@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,6 +1,6 @@
|
|
|
1
|
-
var
|
|
2
|
-
`);if(e.length>0){const c=
|
|
3
|
-
`).forEach((u,g)=>{
|
|
1
|
+
var X=Object.defineProperty;var l=(t,e)=>X(t,"name",{value:e,configurable:!0});import{gzipSync as Z}from"node:zlib";import{browseNodes as F,graphNodes as ee,listNodes as G,pruneNodes as te,pruneToLimit as ne,rosterEdges as S,rosterNodes as se}from"../../../core/canvas/canvas.js";import{liveObjectWaitsNamed as oe,readControllerWait as re}from"../../../core/canvas/waits.js";import{activeBackgroundBashJobs as ae}from"../../../core/bash-jobs.js";import{contextDir as ie}from"../../../core/canvas/node-agent-paths.js";import{nowIso as I}from"../../../core/fs-utils.js";import{isPidPresent as de}from"../../../core/canvas/pid.js";import{dashboardRowsAllFromSource as le,enrichRowsFromSource as ce}from"../../../core/canvas/render-source.js";import{localCanvasSource as D}from"../../../core/canvas/source.js";import{ticketCountsForNodes as q,ticketsAcrossCanvas as ue}from"../../../core/canvas/attention.js";import{buildCorpus as fe,groupCorpus as pe,resolveRef as me}from"../../../core/canvas/history.js";import{listFocuses as H,reapEmptyNodes as _e}from"../../../core/runtime/placement.js";import{boundFleet as ye}from"../../../core/runtime/fleet.js";import{retentionHold as he}from"../../reconcilers/live-obligation.js";import{notFound as be,usage as _}from"../../../core/errors.js";import{openDb as ge}from"../../../core/canvas/db.js";import{view as ve}from"../../../core/canvas/tree.js";import{isLiveStatus as we}from"../../../core/canvas/node-order.js";import{readNodeRecap as ke}from"../../../core/canvas/node-recap.js";import{readGoal as Se}from"../../../core/runtime/kickoff.js";import{faultSummary as Ne}from"../../../core/canvas/status-glyph.js";import{listPendingAsks as Re}from"../../../core/human/requests.js";import{toGraphNodeDTO as Ce}from"../map.js";import{actsAsPerson as je,canReadNode as A,canReadRun as Ie}from"../router.js";import{ApiError as T}from"../../../api/errors.js";import{filterAsync as $,mapAsync as x}from"../../../core/async-array.js";async function N(t){return t.principal.class==="person"?null:new Set((await $(await G(),async e=>await A(t.principal,e.grantee??"app:terminal",e.node_id))).map(e=>e.node_id))}l(N,"visibleNodes");async function z(t){return t.principal.class==="person"?null:new Set((await $(await G(),async e=>e.run_id?await Ie(t.principal,e.grantee??"app:terminal",e.node_id):await A(t.principal,e.grantee??"app:terminal",e.node_id))).map(e=>e.node_id))}l(z,"visibleHistoryNodes");async function Me(t){const e=await N(t);return{status:200,body:{items:(await ue()).filter(n=>e===null||e.has(n.node_id)).map(n=>({node_id:n.node_id,name:n.name,cwd:n.cwd,count:n.count,subjects:n.subjects}))}}}l(Me,"handleAttention");async function Le(t){const e=t.body;if(e===null||typeof e!="object"||!Array.isArray(e.node_ids))throw _("attention count request requires node_ids: string[]");const r=e.node_ids;if(!r.every(o=>typeof o=="string"))throw _("attention count request node_ids must contain only strings");const n=await N(t);return{status:200,body:{counts:await q(r.filter(o=>n===null||n.has(o)))}}}l(Le,"handleAttentionCounts");function J(t){return Buffer.from(String(t),"utf8").toString("base64")}l(J,"encodeCursor");function K(t){const e=Number(Buffer.from(t,"base64").toString("utf8"));if(!Number.isInteger(e)||e<0)throw _(`invalid cursor: ${t}`);return e}l(K,"decodeCursor");function Oe(t,e,r){const i=t.loadBody().split(`
|
|
2
|
+
`);if(e.length>0){const c=i.findIndex(p=>{const f=p.toLowerCase();return e.some(y=>f.includes(y))});if(c!==-1)return i.slice(c,c+r).map(p=>p.trim()).filter(p=>p!=="").join(" \u23CE ")}const o=i.map(c=>c.trim()).filter(c=>c!=="").slice(0,r).join(" \u23CE ");return o!==""?o:t.title}l(Oe,"snippet");function Ee(t,e,r){const n=[...t];return e==="relevance"&&r!==void 0?n.sort((i,o)=>(r.get(o.ref)??0)-(r.get(i.ref)??0)||o.tsMs-i.tsMs||i.ref.localeCompare(o.ref)):e==="oldest"?n.sort((i,o)=>i.tsMs-o.tsMs||i.ref.localeCompare(o.ref)):n.sort((i,o)=>o.tsMs-i.tsMs||i.ref.localeCompare(o.ref)),n}l(Ee,"sortArtifacts");function Ae(t){if(t==null)return{};if(typeof t!="object")throw _("history search body must be a JSON object");return t}l(Ae,"parseSearchBody");function Te(t){if(t===null||typeof t!="object")throw _("history grep body must be a JSON object");const e=t;if(typeof e.pattern!="string"||e.pattern==="")throw _("history grep body requires a non-empty pattern");return e}l(Te,"parseGrepBody");async function B(t,e){const r={cwd:t.cwd,allCwds:t.all_cwds===!0,under:t.under,nodes:t.nodes},n={types:t.types,kinds:t.kinds,statuses:t.statuses,sinceMs:t.since_ms,untilMs:t.until_ms,origins:t.origins,roles:t.roles,from:t.from},i=await z(e);return(await fe(r,n)).filter(o=>i===null||i.has(o.nodeId))}l(B,"buildCorpusFromQuery");function $e(t){if(t==null)return{};if(typeof t!="object")throw _("history stats body must be a JSON object");return t}l($e,"parseStatsBody");const W=["origin","node","kind","day","type","role"];async function Be(t){const e=$e(t.body),r=e.group_by??"type";if(!W.includes(r))throw _(`--group-by must be one of: ${W.join(", ")}; received: ${String(e.group_by)}`);const n=await B(e,t),i=pe(n,r);return{status:200,body:{group_by:r,groups:i,total:i.reduce((c,p)=>c+p.count,0),scanned:n.length}}}l(Be,"handleHistoryStats");async function Pe(t){const e=Te(t.body),r=Math.min(100,Math.max(1,e.limit??20)),n=await B(e,t),i=e.cursor!==void 0?K(e.cursor):0;let o;try{o=new RegExp(e.pattern,"i")}catch{throw _(`invalid regex pattern: ${e.pattern}`)}const c=[];for(const a of n)a.loadBody().split(`
|
|
3
|
+
`).forEach((u,g)=>{o.test(u)&&c.push({ref:a.ref,node:`${a.nodeName} (${a.nodeId})`,ts:a.ts,line:g+1,text:u.trim()})});c.sort((a,s)=>a.ref.localeCompare(s.ref)||a.line-s.line);const p=c.slice(i,i+r),f=i+r<c.length?J(i+r):null;return{status:200,body:{hits:p,next_cursor:f,total:c.length}}}l(Pe,"handleHistoryGrep");async function Fe(t){const e=Ae(t.body),r=(e.query??"").trim(),n=e.weigh_body===!0,i=e.full===!0,o=Math.max(1,e.snippet_lines??1),c=Math.min(100,Math.max(1,e.limit??20)),p=e.per_node===!0;if(p&&(e.nodes===void 0||e.nodes.length===0))throw new T(400,"invalid_request","`per_node` requires a non-empty `nodes` list",{param:"nodes"});const f=await B(e,t),y=e.cursor!==void 0?K(e.cursor):0,a=r.toLowerCase().split(/\s+/).filter(d=>d.length>0);let s=f,u;const g=e.sort??(a.length>0?"relevance":"recency");if(a.length>0&&g==="relevance"){u=new Map;const d=[];for(const m of f){const E=m.title.toLowerCase(),Y=m.nodeName.toLowerCase(),V=m.nodeDesc.toLowerCase(),P=n?m.loadBody().toLowerCase():null;let k=0;for(const j of a)E.includes(j)&&(k+=10),Y.includes(j)&&(k+=5),V.includes(j)&&(k+=3),P!==null&&P.includes(j)&&(k+=1);k>0&&(u.set(m.ref,k),d.push(m))}s=d}else a.length>0&&(s=f.filter(d=>{const m=`${d.title}
|
|
4
4
|
${d.nodeName}
|
|
5
5
|
${d.nodeDesc}${n?`
|
|
6
|
-
`+d.loadBody():""}`.toLowerCase();return
|
|
6
|
+
`+d.loadBody():""}`.toLowerCase();return a.some(E=>m.includes(E))}));let b=Ee(s,g,u);if(p){const d=new Set;b=b.filter(m=>!d.has(m.nodeId)&&d.add(m.nodeId))}const v=p?b:b.slice(y,y+c),h=!p&&y+c<b.length?J(y+c):null;return{status:200,body:{hits:v.map(d=>{const m={ref:d.ref,node:`${d.nodeName} (${d.nodeId})`,kind:d.nodeKind,source:d.source,ts:d.ts,...p?{node_id:d.nodeId}:{}};return g==="relevance"&&u!==void 0&&(m.score=u.get(d.ref)??0),i?m.body=d.loadBody():m.snippet=Oe(d,a,o),m}),next_cursor:h,total:b.length}}}l(Fe,"handleHistorySearch");async function Ge(t){const e=(t.query.get("ref")??"").trim();if(!e.includes(":"))throw _(`ref must be <node-id>:inbox/<n>, <node-id>:session, or <node-id>:session/<n>; received: ${e}`,{received:e,next:"Get a valid ref from `crtr canvas history search`. Reports and documents are `crtr canvas read <name>`."});const r=await me(e);if(r===null)throw be(`no inbox entry or message for ref: ${e}`,{ref:e,next:"Re-run `crtr canvas history search` for a current ref. Reports and documents are `crtr canvas read <name>`."});if((await z(t))?.has(r.nodeId)===!1)throw new T(404,"not_found","artifact not found");const n=r.source,o=t.query.get("format")==="raw"&&r.raw!==null?r.raw:r.body;return{status:200,body:{ref:e,node:`${r.nodeName} (${r.nodeId})`,source:n,ts:r.ts,content:o}}}l(Ge,"handleHistoryRead");function De(t){for(const[n]of t.query)if(n!=="live")throw _(`unknown snapshot query parameter: ${n}`);const e=t.query.getAll("live");if(e.length>1)throw _("live must appear at most once");const r=e[0];if(r===void 0||r==="false"||r==="0")return!1;if(r==="true"||r==="1")return!0;throw _("live must be true or false")}l(De,"snapshotLiveOnly");async function qe(t){const e=new Set((await H()).map(a=>a.node_id)),r=await N(t),n=(await le(D,e,De(t))).filter(a=>r===null||r.has(a.node_id)),i=await q(n.map(a=>a.node_id));await ce(D,n,i);const o=await x(n,async a=>{const s=a.srcRow,u=s?.host_kind??"tmux";return{node_id:a.node_id,name:a.name,title:a.handle??a.name,description:a.description??null,kind:a.kind,mode:a.mode,lifecycle:a.lifecycle??s?.lifecycle,status:a.status,cwd:a.cwd,profile_id:a.profile_id??null,parent:s?.parent??null,created:a.created,host_kind:u,enterable:u==="broker",attention_count:a.asks,...s?.cycles!=null?{cycles:s.cycles}:{},...a.mtimeMs!==void 0?{last_activity:new Date(a.mtimeMs).toISOString()}:{},ctx_tokens:a.ctx_tokens,streaming:a.streaming??!1,jobs_active:s!==void 0&&de(s.pi_pid)?ae(await ie(a.node_id)).length:0,waiting_for:(await re(a.node_id))?.controllerId??null,hanging:a.hanging??null,viewed:a.viewed??!1,final_report:s?.final_report??null,finalized_at:s?.finalized_at??null}}),c=new Map;for(const a of await S()){const s=c.get(a.from_id);s===void 0?c.set(a.from_id,[a.to_id]):s.push(a.to_id)}const p=new Set(n.map(a=>a.node_id)),f=Object.fromEntries(n.map(a=>[a.node_id,(c.get(a.node_id)??[]).filter(s=>p.has(s))]));return{status:200,body:{generated_at:I(),nodes:o,subscriptions:f}}}l(qe,"handleSnapshot");async function U(){const t=(await se()).map(n=>{const i=n.host_kind??"tmux";return{node_id:n.node_id,name:n.name,kind:n.kind,mode:n.mode,lifecycle:n.lifecycle,status:n.status,cwd:n.cwd,host_kind:i,enterable:i==="broker",parent:n.parent,created:n.created}}),e=(await S()).map(n=>({from_id:n.from_id,to_id:n.to_id,active:n.active,created:n.created})),r=(await oe()).map(n=>({node_id:n.nodeId,object_id:n.objectId,object_type:n.objectType,object_name:n.objectName,created:new Date(n.createdAt).toISOString()}));return{generated_at:I(),nodes:t,edges:e,object_waits:r}}l(U,"buildRoster");let R=null,M=null;function He(){return R===null?(R=Promise.resolve().then(async()=>await U()).finally(()=>{R=null}),R):(M===null&&(M=R.then(async()=>await U()).finally(()=>{M=null})),M)}l(He,"rosterCoalesced");async function xe(t){const e=await He(),r=await N(t);return r===null?{status:200,body:e}:{status:200,body:{...e,nodes:e.nodes.filter(n=>r.has(n.node_id)),edges:e.edges.filter(n=>r.has(n.from_id)&&r.has(n.to_id)),object_waits:(e.object_waits??[]).filter(n=>r.has(n.node_id))}}}l(xe,"handleRoster");function Q(t){if(t.name!==""&&t.name!==t.kind)return t.name;const e=(t.description??"").trim();return e!==""?e:t.name}l(Q,"liveRootName");const ze=1440*6e4;async function Je(){const t=await F(),e=new Map(t.map(s=>[s.node_id,s])),r=new Map((await(await ge()).prepare("SELECT node_id, reply_at, read_at, intent FROM nodes WHERE parent IS NULL").all()).map(s=>[s.node_id,s])),n=await Re(),i=new Map;for(const s of n)i.set(s.requester_node_id,(i.get(s.requester_node_id)??0)+1);const o=new Date(Date.now()-ze).toISOString(),c=l(s=>{const u=r.get(s.node_id);return u?.reply_at!=null&&(u.read_at==null||u.reply_at>u.read_at)||(i.get(s.node_id)??0)>0?!0:s.status!=="done"||u?.intent!=="parked"?!1:[s.created,s.telemetry_updated_at,u.reply_at].reduce((v,h)=>h!=null&&h>v?h:v,"")>=o},"keepFinished"),p=t.filter(s=>s.parent===null&&s.kind!=="human"&&(we(s.status)||c(s))),f=new Map;for(const s of await S())f.set(s.from_id,[...f.get(s.from_id)??[],s.to_id]);const y=l(s=>{const u=e.get(s)?.fault;return u&&u.link!=="broker\u2194crtrd"?Ne(u):null},"faultOf"),a=await x(p,async s=>{const u=[s.node_id,...await ve(s.node_id)].filter(d=>e.get(d)?.kind!=="human"&&e.has(d)),g=new Set(u),b=n.filter(d=>g.has(d.requester_node_id)),v=r.get(s.node_id),h=v?.reply_at??null,O=v?.read_at??null;let w=s.created;for(const d of u){const m=e.get(d).telemetry_updated_at;m!=null&&m>w&&(w=m)}return h!==null&&h>w&&(w=h),{node_id:s.node_id,name:Q(s),cwd:s.cwd,profile_id:s.profile_id,status:s.status,state_line:(()=>{const d=ke(s.node_id)?.state.trim();return d||null})(),goal:(await Se(s.node_id))?.trim()||null,asks:b.length,first_ask_ticket_id:b[0]?.inbox_ticket_id??null,fault:u.map(y).find(d=>d!==null)??null,running_count:u.filter(d=>e.get(d).streaming===!0).length,unread:h!==null&&(O===null||h>O),last_activity:w,children:(f.get(s.node_id)??[]).filter(d=>e.has(d)&&e.get(d).kind!=="human").map(d=>{const m=e.get(d);return{node_id:d,name:Q(m),status:m.status,streaming:m.streaming===!0,asks:i.get(d)??0,fault:y(d)}})}});return{generated_at:I(),rows:a}}l(Je,"buildLiveRoots");let C=null,L=null;function Ke(){const t=l(()=>Promise.resolve().then(Je),"run");return C===null?(C=t().finally(()=>{C=null}),C):(L===null&&(L=C.then(t).finally(()=>{L=null})),L)}l(Ke,"liveRootsCoalesced");async function We(t){if(!je(t.principal))throw new T(403,"permission_error","only the person reads the dashboard");const e=await Ke(),r=t.query.get("profile");return{status:200,body:r===null?e:{...e,rows:e.rows.filter(n=>n.profile_id===r)}}}l(We,"handleLiveRoots");async function Ue(t){const e=(await $(await F(),async o=>t.principal.class==="person"||await A(t.principal,o.grantee??"app:terminal",o.node_id))).map(o=>({node_id:o.node_id,name:o.name,description:o.description,kind:o.kind,mode:o.mode,lifecycle:o.lifecycle,status:o.status,cwd:o.cwd,profile_id:o.profile_id,grantee:o.grantee??"app:terminal",parent:o.parent,created:o.created,frozen_at:o.frozen_at??null,terminal_reason:o.terminal_reason??null,final_report:o.final_report??null,telemetry_tokens_in:o.telemetry_tokens_in??null,telemetry_updated_at:o.telemetry_updated_at??null,fault:o.fault&&o.fault.link!=="broker\u2194crtrd"?{...o.fault,link:o.fault.link}:null,streaming:o.streaming??!1})),r=new Set(e.map(o=>o.node_id)),n=(await S()).filter(o=>r.has(o.from_id)&&r.has(o.to_id));return{status:200,rawBody:Z(JSON.stringify({nodes:e,edges:n}),{level:1}),headers:{"content-type":"application/gzip"}}}l(Ue,"handleBrowse");async function Qe(t){const e=await N(t);return{status:200,body:{generated_at:I(),nodes:(await ee()).filter(n=>e===null||e.has(n.node_id)).map(Ce),edges:(await S()).filter(n=>e===null||e.has(n.from_id)&&e.has(n.to_id)).map(n=>({from_id:n.from_id,to_id:n.to_id,active:n.active,created:n.created})),focused_node_ids:(await H()).map(n=>n.node_id).filter(n=>e===null||e.has(n))}}}l(Qe,"handleGraph");function Ye(t){if(t==null)return{};if(typeof t!="object")throw _("prune body must be a JSON object");const e=t,r=l(a=>{const s=e[a];if(s!==void 0){if(typeof s!="number"||!Number.isFinite(s))throw _(`${a} must be a number`);return s}},"num"),n=l(a=>{const s=e[a];if(s!==void 0){if(typeof s!="boolean")throw _(`${a} must be a boolean`);return s}},"bool"),i={},o=r("limit");o!==void 0&&(i.limit=o);const c=r("ttl_days");c!==void 0&&(i.ttl_days=c);const p=n("include_stale");p!==void 0&&(i.include_stale=p);const f=n("empty");f!==void 0&&(i.empty=f);const y=n("dry_run");return y!==void 0&&(i.dry_run=y),i}l(Ye,"parsePruneBody");async function Ve(t){const e=Ye(t.body),r=e.ttl_days??14,n=e.dry_run??!1,i=await he(ye());let o;return e.limit!==void 0?o=(await ne({maxNodes:e.limit,held:i,dryRun:n})).pruned.map(f=>({node_id:f.node_id,status:f.status,created:f.created})):e.empty===!0?o=(await _e({dryRun:n})).map(f=>({node_id:f,status:"empty",created:""})):o=(await te({ttlDays:r,held:i,dryRun:n,includeStale:e.include_stale??!1})).pruned.map(f=>({node_id:f.node_id,status:f.status,created:f.created})),{status:200,body:{pruned:o,dry_run:n,ttl_days:r}}}l(Ve,"handlePrune");const Rt=[{method:"GET",pattern:"/v1/canvas/attention",handler:Me},{method:"POST",pattern:"/v1/canvas/attention/counts",handler:Le},{method:"POST",pattern:"/v1/canvas/history/search",handler:Fe},{method:"POST",pattern:"/v1/canvas/history/grep",handler:Pe},{method:"GET",pattern:"/v1/canvas/history/read",handler:Ge},{method:"POST",pattern:"/v1/canvas/history/stats",handler:Be},{method:"GET",pattern:"/v1/canvas/snapshot",handler:qe},{method:"GET",pattern:"/v1/canvas/roster",handler:xe},{method:"GET",pattern:"/v1/canvas/live-roots",handler:We},{method:"GET",pattern:"/v1/canvas/browse",handler:Ue},{method:"GET",pattern:"/v1/canvas/graph",handler:Qe},{method:"POST",pattern:"/v1/canvas/prune",ownerOnly:!0,handler:Ve}];export{Rt as canvasRoutes,Ue as handleBrowse};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var n=Object.defineProperty;var e=(t,o)=>n(t,"name",{value:o,configurable:!0});import{getNode as r}from"../../../core/canvas/canvas.js";import{isSafeNodeId as d}from"../../../core/canvas/paths.js";import{notFound as i,usage as a}from"../../../core/errors.js";import{readChatInventory as m}from"../../../core/runtime/broker-inventory.js";async function s(t){const o=t.params.id;if(!d(o))throw a(`invalid node id: ${o}`,{received:o});if(r(o)===null)throw i(`unknown node: ${o}`,{received:o});return{status:200,body:await m(o)}}e(s,"handleGet");const v=[{method:"GET",pattern:"/v1/nodes/:id/chat-inventory",handler:s}];export{v as chatInventoryRoutes};
|
|
1
|
+
var n=Object.defineProperty;var e=(t,o)=>n(t,"name",{value:o,configurable:!0});import{getNode as r}from"../../../core/canvas/canvas.js";import{isSafeNodeId as d}from"../../../core/canvas/paths.js";import{notFound as i,usage as a}from"../../../core/errors.js";import{readChatInventory as m}from"../../../core/runtime/broker-inventory.js";async function s(t){const o=t.params.id;if(!d(o))throw a(`invalid node id: ${o}`,{received:o});if(await r(o)===null)throw i(`unknown node: ${o}`,{received:o});return{status:200,body:await m(o)}}e(s,"handleGet");const v=[{method:"GET",pattern:"/v1/nodes/:id/chat-inventory",handler:s}];export{v as chatInventoryRoutes};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var X=Object.defineProperty;var t=(e,n)=>X(e,"name",{value:n,configurable:!0});import{randomUUID as nn}from"node:crypto";import{relative as en,resolve as B,sep as G}from"node:path";import{ApiError as c}from"../../../api/errors.js";import{armCron as rn,parseCronSink as on,getCron as y,listCrons as T,listCronRuns as F,pokeHeldCrons as tn,setCronState as L}from"../../../core/canvas/crons.js";import{getNode as h}from"../../../core/canvas/canvas.js";import{appSpace as sn,cronFolder as an}from"../../../core/layout.js";import{appProcessesSandboxed as cn,cwdIsMounted as ln}from"../../../core/spaces/process.js";import{activeGrant as dn,activeGrantForApp as un,grantFor as pn,terminalGrant as fn}from"../../../core/grants/mirror.js";import{readConfig as _n}from"../../../core/config.js";import{assertScope as Z}from"../../../core/scopes.js";import{InputError as i}from"../../../core/io.js";import{nextSlotAfter as hn}from"../../../core/wake.js";import{executeCron as mn,markSelfCanceledCronRun as gn}from"../../cron-run.js";import{toCronDTO as k,toCronRunDTO as H}from"../map.js";import{appOf as A,assertCeiling as wn,canReadNode as bn}from"../router.js";import{checkCronBirth as vn,checkCronFire as yn}from"../../cron/authority.js";import{endCron as kn}from"../../cron/ended.js";import{requireUsableProfile as Sn}from"./profiles.js";function E(e,n){const r=e[n];if(typeof r!="string"||r.trim()==="")throw new i({error:"missing_field",message:`cron arm request requires a non-empty "${n}"`,field:n,next:`Send a non-empty string "${n}".`});return r}t(E,"requireString");function C(e,n,r,o){if(e==null)return o;if(typeof e=="string"&&r.includes(e))return e;throw new i({error:`bad_${n}`,message:`"${String(e)}" is not a valid ${n}`,field:n,next:`Use one of: ${r.join(", ")}.`})}t(C,"requireEnum");function $n(e){if(e==="human")return JSON.stringify({human:!0});if(e.startsWith("node:")){const n=e.slice(5).trim();if(n==="")throw new i({error:"bad_sink",message:"node sink requires a node id",field:"sink",next:'Use sink "node:<node-id>".'});if(h(n)===null)throw new i({error:"sink_node_not_found",message:`sink node ${n} does not exist on the canvas`,field:"sink",next:"Name a live node id, or use spawn:<kind> for a delivery that outlives any one node."});return JSON.stringify({node:n})}if(e.startsWith("spawn:")){const n=e.slice(6).trim();if(n==="")throw new i({error:"bad_sink",message:"spawn sink requires a node kind",field:"sink",next:'Use sink "spawn:<kind>" (e.g. spawn:general).'});return JSON.stringify({spawn:n})}throw new i({error:"bad_sink",message:`"${e}" is not a valid sink`,field:"sink",next:"Use node:<node-id>, spawn:<kind>, or human."})}t($n,"parseSinkSpec");const Cn=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;function M(e,n){if(!Cn.test(e)||Number.isNaN(Date.parse(e)))throw new i({error:`bad_${n}`,message:`"${e}" is not a UTC ISO instant`,field:n,next:'Send a resolved UTC instant like "2026-06-07T09:00:00.000Z" (the client resolves the time grammar).'});return e}t(M,"requireUtcIso");function On(e){try{hn(e,new Date)}catch(n){throw new i({error:"bad_recur",message:`recur is not advanceable: ${n instanceof Error?n.message:String(n)}`,field:"recur",next:'Send recur JSON the daemon can advance: {"every":"6h"} or {"cron":"0 9 * * *","tz":"America/New_York"}.'})}return e}t(On,"requireRecur");function In(e){let n;try{n=JSON.parse(e)}catch{throw new i({error:"bad_env_json",message:"env_json is not valid JSON",field:"env_json",next:'Send a JSON object of string values, e.g. {"API_BASE":"https://x"}.'})}if(typeof n!="object"||n===null||Array.isArray(n))throw new i({error:"bad_env_json",message:"env_json must be a JSON object",field:"env_json",next:'Send a JSON object of string values, e.g. {"API_BASE":"https://x"}.'});for(const[r,o]of Object.entries(n))if(typeof o!="string")throw new i({error:"bad_env_json",message:`env_json value for "${r}" is not a string`,field:"env_json",next:"Every env value must be a string."});return e}t(In,"requireEnvJson");function U(e){const n=e.query.get("profile");return n!==null&&n.trim()!==""?n.trim():null}t(U,"callerProfile");function Y(e,n){return n===null||e.scope==="global"||e.profile===n}t(Y,"inScope");function K(e){return e.principal.class==="person"?null:A(e.principal)}t(K,"callerApp");function J(e,n){return bn(e.principal,n.grantee,n.created_by??void 0)}t(J,"visibleTo");function Nn(e){return typeof e.anchor_node=="string"&&e.anchor_node!==""?e.anchor_node:null}t(Nn,"anchorNodeOf");function qn(e,n,r,o,a,u){const l=typeof e.cwd=="string"&&e.cwd.trim()!==""?B(e.cwd):null;if(!cn()){if(l===null)throw new i({error:"missing_field",message:'cron arm request requires a non-empty "cwd"',field:"cwd",next:'Send a non-empty string "cwd".'});return l}const p=o!==null&&h(o)!==null?o:void 0,d=t(N=>ln(n,N,p,a,void 0,u),"reaches");if(l!==null&&d(l))return l;const s=sn(n).files;if(l!==null&&e.cwd_is_default!==!0)throw new c(400,"invalid_request",`cwd ${l} is not inside a directory this app's cron runs can see, so every run would fail to start; use a directory under ${s}`,{cwd:l,default:s},void 0,{param:"cwd"});const m=r===null?null:h(r)?.cwd??null;return m!==null&&d(m)?m:s}t(qn,"resolveArmedCwd");function jn(e,n,r){const o=e.principal;if(o.class==="person"){const s=fn();return{sub:s?.sub??"user:local",grant_id:s?.id??null,scopes:null,origin_run_id:null}}if(o.class==="app"){const s=un(n);if(s===null)throw new c(401,"grant_revoked",`no active grant for ${n}`);const m=e.ceiling??o.scopes;return{sub:s.sub,grant_id:s.id,scopes:[...m??s.resolved],origin_run_id:null}}if(o.class==="cron"){const s=yn({grantee:o.app,sub:o.sub,grant_id:o.grant,scopes:o.scopes});if(!s.allowed)throw new c(s.reason==="scope_missing"?403:401,s.reason==="scope_missing"?"scope_missing":"grant_revoked",s.message);return{sub:o.sub,grant_id:o.grant,scopes:o.scopes===null?[...s.effectiveScopes]:[...o.scopes],origin_run_id:o.origin_run}}if(o.class!=="broker")throw new c(401,"unauthorized","this caller cannot arm a cron");const a=r??h(o.node),u=a?.grant_id??o.grant,l=a?.sub??o.sub,p=u!=null?dn(u):pn(n,l);if(p===null){if(n==="app:terminal"&&!_n("user").runtime?.issuer)return{sub:l,grant_id:u??null,scopes:a?.scopes??o.scopes,origin_run_id:a?.run_id??o.run};throw new c(401,"grant_revoked","the node grant is not active")}const d=a?.scopes??o.scopes;return{sub:p.sub,grant_id:p.id,scopes:d===null?[...p.resolved]:[...d],origin_run_id:a?.run_id??o.run}}t(jn,"armPrincipal");function Pn(e){const n=e.body??{},r=E(n,"name"),o=E(n,"command"),a=M(E(n,"fire_at"),"fire_at"),u=typeof n.recur=="string"&&n.recur!==""?On(n.recur):null,l=typeof n.expires_at=="string"&&n.expires_at!==""?M(n.expires_at,"expires_at"):null,p=typeof n.env_json=="string"&&n.env_json!==""?In(n.env_json):null,d=typeof n.sink=="string"&&n.sink.trim()!==""?n.sink.trim():null,s=C(n.on_output,"on_output",["silent","on-failure","always","on-change"],d?.startsWith("node:")?"on-change":"on-failure"),m=C(n.overlap,"overlap",["skip","queue","replace"],"skip"),N=C(n.tier,"tier",["normal","urgent","critical"],"normal"),D=s==="always"||s==="on-change";if(D&&d===null)throw new i({error:"sink_required",message:`on_output "${s}" delivers stdout every qualifying run \u2014 it needs a sink`,field:"sink",next:"Pass sink node:<node-id> (a living node's inbox), spawn:<kind> (birth a fresh node per delivery), or human (the humanloop inbox)."});if(!D&&d!==null)throw new i({error:"sink_unused",message:`on_output "${s}" never delivers stdout \u2014 a sink would be dead config`,field:"sink",next:'Drop the sink, or use on_output "always"/"on-change" if delivery is the point.'});const Q=d!==null?$n(d):"{}";if(d?.startsWith("spawn:")&&(wn(e.ceiling,"crtr:act"),e.principal.class==="cron")){const _=vn({grantee:e.principal.app,sub:e.principal.sub,grant_id:e.principal.grant,scopes:e.principal.scopes});if(!_.allowed)throw new c(_.reason==="scope_missing"?403:401,_.reason==="scope_missing"?"scope_missing":"grant_revoked",_.message)}const b=A(e.principal)??"app:terminal",v=e.principal.class==="broker"?e.principal.node:e.principal.class==="cron"?null:typeof n.created_by=="string"&&n.created_by!==""?n.created_by:null;if(e.principal.class==="broker"&&n.created_by!=null&&n.created_by!==v)throw new c(403,"permission_error","a broker may only arm a cron as its own node");const g=v===null?null:h(v);if(g!==null){if(g.grantee!==b)throw new i({error:"creator_app_mismatch",message:"creator node belongs to another app",field:"created_by",next:"Use a node of the calling app."});Z(g,"crtr:schedule"),d?.startsWith("spawn:")&&Z(g,"crtr:act")}if(n.isolated!==void 0&&typeof n.isolated!="boolean")throw new c(400,"invalid_request","isolated must be a boolean");if(g?.isolated&&n.isolated===!1)throw new c(403,"isolated_run","a cron created by an isolated node cannot escape isolation");const W=g?.isolated===!0||e.principal.class==="cron"&&e.principal.isolated;if(W&&n.isolated===!1)throw new c(403,"isolated_run","a cron created by an isolated caller cannot escape isolation");const q=W||n.isolated===!0,w=jn(e,b,g),j=nn(),S=q?an(b,j):null;if(S!==null&&n.cwd_is_default!==!0){const _=en(S,typeof n.cwd=="string"&&n.cwd.trim()!==""?B(n.cwd):S);if(_===".."||_.startsWith(`..${G}`)||_.startsWith(G))throw new c(400,"invalid_request","an isolated cron must run in its own cron folder",{param:"cwd"})}const V=S??qn(n,b,v,Nn(n),q,{sub:w.sub,grantId:w.grant_id,scopes:w.scopes}),f=typeof n.anchor_node=="string"&&n.anchor_node!==""?n.anchor_node:null;if(f!==null&&h(f)!==null&&h(f).grantee!==b)throw new i({error:"anchor_app_mismatch",message:"anchor node belongs to another app",field:"anchor_node",next:"Use an anchor of the calling app."});if(f!==null&&h(f)===null)throw new i({error:"anchor_not_found",message:`anchor node ${f} does not exist on the canvas`,field:"anchor_node",next:"Name a live node id, or drop the anchor \u2014 an unanchored cron outlives every node."});const x=n.cancel_on_wake===!0;if(x&&f===null)throw new i({error:"cancel_on_wake_needs_anchor",message:"cancel_on_wake couples the cron to a node's dormancy \u2014 it requires an anchor node",field:"anchor_node",next:"Pass anchor_node with the node whose wake should cancel this cron."});const $=n.run_timeout_s??300;if(typeof $!="number"||!Number.isInteger($)||$<=0)throw new i({error:"bad_run_timeout",message:`run_timeout_s must be a positive integer (got ${String(n.run_timeout_s)})`,field:"run_timeout_s",next:"Send the timeout in whole seconds, e.g. 300."});const P=typeof n.profile=="string"&&n.profile!==""?Sn(e,n.profile).profileId:null,z=C(n.scope,"scope",["profile","global"],P!==null?"profile":"global");if(z==="profile"&&P===null)throw new i({error:"scope_needs_profile",message:'scope "profile" names the profile the cron lists and cancels within \u2014 it requires a profile',field:"profile",next:'Send a profile, or use scope "global" for a canvas-home-wide cron.'});return rn({cron_id:j,name:r,created_by:v,grantee:b,sub:w.sub,grant_id:w.grant_id,scopes:w.scopes,origin_run_id:w.origin_run_id,isolated:q,command:o,fire_at:a,recur:u,tz:typeof n.tz=="string"?n.tz:null,expires_at:l,anchor_node:f,cancel_on_wake:x,cwd:V,env_json:p,profile:P,scope:z,run_timeout_s:$,overlap:m,on_output:s,sink:Q,tier:N}),{status:201,body:k(y(j),null)}}t(Pn,"handleArm");function Tn(e){const n=U(e);return{status:200,body:(n===null?T({all:!0}):[...T({profile:n}),...T({global:!0})].sort((o,a)=>o.fire_at<a.fire_at?-1:o.fire_at>a.fire_at?1:0)).filter(o=>J(e,o)).map(o=>k(o,R(o)))}}t(Tn,"handleList");function R(e){return F(e.cron_id)[0]??null}t(R,"lastRunOf");function O(e){const n=e.params.cronId,r=y(n);if(r===null||!J(e,r))throw new c(404,"cron_not_found",`no cron ${n}`);if(!Y(r,U(e)))throw new c(404,"cron_not_found",`no cron ${n} in this profile \u2014 it is scoped to another profile`);return r}t(O,"requireCron");function I(e,n){const r=K(e);if(r!==null&&n.grantee!==r)throw new c(403,"other_app_run",`cron ${n.cron_id} belongs to another app`);return n}t(I,"requireOwnCron");function An(e){const n=O(e),r=F(n.cron_id);return{status:200,body:{cron:k(n,r[0]??null),runs:r.map(H)}}}t(An,"handleShow");function En(e){const n=I(e,O(e));L(n.cron_id,"paused");const r=y(n.cron_id);return{status:200,body:k(r,R(r))}}t(En,"handlePause");function Un(e){const n=I(e,O(e));L(n.cron_id,"active");const r=y(n.cron_id);return{status:200,body:k(r,R(r))}}t(Un,"handleResume");async function Jn(e){const n=I(e,O(e));if(n.run_state==="running")throw new c(409,"cron_running",`cron ${n.cron_id} has a run in flight \u2014 wait for it to settle`);const r=await mn(n,{outOfBand:!0});if(r===null)throw new c(409,"cron_running",`cron ${n.cron_id} was claimed by a concurrent run \u2014 check \`cron show\` for its result`);return{status:200,body:H(r)}}t(Jn,"handleRun");function Rn(e){const n=new Date().toISOString();return{status:200,body:{unparked:tn(n,K(e)),at:n}}}t(Rn,"handlePoke");function Dn(e,n){const r=e.principal;if(r.class==="cron")return r.cron===n.cron_id?null:{kind:"canceled",by:`cron ${r.cron}`};if(r.class==="broker"){const a=on(n.sink);return a?.kind==="node"&&a.node===r.node?null:{kind:"canceled",by:`node ${r.node}`}}const o=A(r);return{kind:"canceled",by:o===null||o==="app:terminal"?"the person":o}}t(Dn,"cancelNotice");function Wn(e){const n=e.params.cronId,r=y(n);if(r!==null&&!J(e,r))throw new c(404,"cron_not_found",`no cron ${n}`);if(r!==null&&!Y(r,U(e)))throw new c(404,"cron_not_found",`no cron ${n} in this profile \u2014 it is scoped to another profile`);r!==null&&I(e,r);const o=e.query.get("run_id"),a=e.principal.class==="cron"?o===e.principal.execution&&n===e.principal.cron:!0,u=o!==null&&a&&gn(n,o);return r!==null&&kn(r,u?null:Dn(e,r),{preserveRunningProcess:u}),{status:204}}t(Wn,"handleCancel");const se=[{method:"POST",pattern:"/v1/crons",scope:"crtr:schedule",handler:Pn},{method:"GET",pattern:"/v1/crons",handler:Tn},{method:"GET",pattern:"/v1/crons/:cronId",handler:An},{method:"POST",pattern:"/v1/crons/:cronId/pause",scope:"crtr:schedule",handler:En},{method:"POST",pattern:"/v1/crons/:cronId/resume",scope:"crtr:schedule",handler:Un},{method:"POST",pattern:"/v1/crons/poke",scope:"crtr:schedule",handler:Rn},{method:"POST",pattern:"/v1/crons/:cronId/run",scope:"crtr:schedule",handler:Jn},{method:"DELETE",pattern:"/v1/crons/:cronId",scope:"crtr:schedule",handler:Wn}];export{se as cronRoutes};
|
|
1
|
+
var X=Object.defineProperty;var t=(e,n)=>X(e,"name",{value:n,configurable:!0});import{randomUUID as nn}from"node:crypto";import{relative as en,resolve as B,sep as G}from"node:path";import{ApiError as c}from"../../../api/errors.js";import{armCron as rn,parseCronSink as on,getCron as v,listCrons as P,listCronRuns as F,pokeHeldCrons as tn,setCronState as L}from"../../../core/canvas/crons.js";import{getNode as _}from"../../../core/canvas/canvas.js";import{appSpace as sn,cronFolder as an}from"../../../core/layout.js";import{appProcessesSandboxed as cn,cwdIsMounted as ln}from"../../../core/spaces/process.js";import{activeGrant as dn,activeGrantForApp as un,grantFor as pn,terminalGrant as fn}from"../../../core/grants/mirror.js";import{readConfig as wn}from"../../../core/config.js";import{assertScope as Z}from"../../../core/scopes.js";import{InputError as s}from"../../../core/io.js";import{nextSlotAfter as _n}from"../../../core/wake.js";import{executeCron as hn,markSelfCanceledCronRun as mn}from"../../cron-run.js";import{toCronDTO as k,toCronRunDTO as H}from"../map.js";import{appOf as T,assertCeiling as gn,canReadNode as yn}from"../router.js";import{checkCronBirth as bn,checkCronFire as vn}from"../../cron/authority.js";import{endCron as kn}from"../../cron/ended.js";import{requireUsableProfile as Sn}from"./profiles.js";import{filterAsync as $n,mapAsync as Cn}from"../../../core/async-array.js";function E(e,n){const r=e[n];if(typeof r!="string"||r.trim()==="")throw new s({error:"missing_field",message:`cron arm request requires a non-empty "${n}"`,field:n,next:`Send a non-empty string "${n}".`});return r}t(E,"requireString");function C(e,n,r,o){if(e==null)return o;if(typeof e=="string"&&r.includes(e))return e;throw new s({error:`bad_${n}`,message:`"${String(e)}" is not a valid ${n}`,field:n,next:`Use one of: ${r.join(", ")}.`})}t(C,"requireEnum");async function On(e){if(e==="human")return JSON.stringify({human:!0});if(e.startsWith("node:")){const n=e.slice(5).trim();if(n==="")throw new s({error:"bad_sink",message:"node sink requires a node id",field:"sink",next:'Use sink "node:<node-id>".'});if(await _(n)===null)throw new s({error:"sink_node_not_found",message:`sink node ${n} does not exist on the canvas`,field:"sink",next:"Name a live node id, or use spawn:<kind> for a delivery that outlives any one node."});return JSON.stringify({node:n})}if(e.startsWith("spawn:")){const n=e.slice(6).trim();if(n==="")throw new s({error:"bad_sink",message:"spawn sink requires a node kind",field:"sink",next:'Use sink "spawn:<kind>" (e.g. spawn:general).'});return JSON.stringify({spawn:n})}throw new s({error:"bad_sink",message:`"${e}" is not a valid sink`,field:"sink",next:"Use node:<node-id>, spawn:<kind>, or human."})}t(On,"parseSinkSpec");const In=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;function M(e,n){if(!In.test(e)||Number.isNaN(Date.parse(e)))throw new s({error:`bad_${n}`,message:`"${e}" is not a UTC ISO instant`,field:n,next:'Send a resolved UTC instant like "2026-06-07T09:00:00.000Z" (the client resolves the time grammar).'});return e}t(M,"requireUtcIso");function Nn(e){try{_n(e,new Date)}catch(n){throw new s({error:"bad_recur",message:`recur is not advanceable: ${n instanceof Error?n.message:String(n)}`,field:"recur",next:'Send recur JSON the daemon can advance: {"every":"6h"} or {"cron":"0 9 * * *","tz":"America/New_York"}.'})}return e}t(Nn,"requireRecur");function qn(e){let n;try{n=JSON.parse(e)}catch{throw new s({error:"bad_env_json",message:"env_json is not valid JSON",field:"env_json",next:'Send a JSON object of string values, e.g. {"API_BASE":"https://x"}.'})}if(typeof n!="object"||n===null||Array.isArray(n))throw new s({error:"bad_env_json",message:"env_json must be a JSON object",field:"env_json",next:'Send a JSON object of string values, e.g. {"API_BASE":"https://x"}.'});for(const[r,o]of Object.entries(n))if(typeof o!="string")throw new s({error:"bad_env_json",message:`env_json value for "${r}" is not a string`,field:"env_json",next:"Every env value must be a string."});return e}t(qn,"requireEnvJson");function U(e){const n=e.query.get("profile");return n!==null&&n.trim()!==""?n.trim():null}t(U,"callerProfile");function Y(e,n){return n===null||e.scope==="global"||e.profile===n}t(Y,"inScope");function K(e){return e.principal.class==="person"?null:T(e.principal)}t(K,"callerApp");async function J(e,n){return await yn(e.principal,n.grantee,n.created_by??void 0)}t(J,"visibleTo");function jn(e){return typeof e.anchor_node=="string"&&e.anchor_node!==""?e.anchor_node:null}t(jn,"anchorNodeOf");async function An(e,n,r,o,a,u){const l=typeof e.cwd=="string"&&e.cwd.trim()!==""?B(e.cwd):null;if(!cn()){if(l===null)throw new s({error:"missing_field",message:'cron arm request requires a non-empty "cwd"',field:"cwd",next:'Send a non-empty string "cwd".'});return l}const p=o!==null&&await _(o)!==null?o:void 0,d=t(async N=>await ln(n,N,p,a,void 0,u),"reaches");if(l!==null&&await d(l))return l;const i=sn(n).files;if(l!==null&&e.cwd_is_default!==!0)throw new c(400,"invalid_request",`cwd ${l} is not inside a directory this app's cron runs can see, so every run would fail to start; use a directory under ${i}`,{cwd:l,default:i},void 0,{param:"cwd"});const h=r===null?null:(await _(r))?.cwd??null;return h!==null&&await d(h)?h:i}t(An,"resolveArmedCwd");async function Pn(e,n,r){const o=e.principal;if(o.class==="person"){const i=await fn();return{sub:i?.sub??"user:local",grant_id:i?.id??null,scopes:null,origin_run_id:null}}if(o.class==="app"){const i=await un(n);if(i===null)throw new c(401,"grant_revoked",`no active grant for ${n}`);const h=e.ceiling??o.scopes;return{sub:i.sub,grant_id:i.id,scopes:[...h??i.resolved],origin_run_id:null}}if(o.class==="cron"){const i=await vn({grantee:o.app,sub:o.sub,grant_id:o.grant,scopes:o.scopes});if(!i.allowed)throw new c(i.reason==="scope_missing"?403:401,i.reason==="scope_missing"?"scope_missing":"grant_revoked",i.message);return{sub:o.sub,grant_id:o.grant,scopes:o.scopes===null?[...i.effectiveScopes]:[...o.scopes],origin_run_id:o.origin_run}}if(o.class!=="broker")throw new c(401,"unauthorized","this caller cannot arm a cron");const a=r??await _(o.node),u=a?.grant_id??o.grant,l=a?.sub??o.sub,p=u!=null?await dn(u):await pn(n,l);if(p===null){if(n==="app:terminal"&&!wn("user").runtime?.issuer)return{sub:l,grant_id:u??null,scopes:a?.scopes??o.scopes,origin_run_id:a?.run_id??o.run};throw new c(401,"grant_revoked","the node grant is not active")}const d=a?.scopes??o.scopes;return{sub:p.sub,grant_id:p.id,scopes:d===null?[...p.resolved]:[...d],origin_run_id:a?.run_id??o.run}}t(Pn,"armPrincipal");async function Tn(e){const n=e.body??{},r=E(n,"name"),o=E(n,"command"),a=M(E(n,"fire_at"),"fire_at"),u=typeof n.recur=="string"&&n.recur!==""?Nn(n.recur):null,l=typeof n.expires_at=="string"&&n.expires_at!==""?M(n.expires_at,"expires_at"):null,p=typeof n.env_json=="string"&&n.env_json!==""?qn(n.env_json):null,d=typeof n.sink=="string"&&n.sink.trim()!==""?n.sink.trim():null,i=C(n.on_output,"on_output",["silent","on-failure","always","on-change"],d?.startsWith("node:")?"on-change":"on-failure"),h=C(n.overlap,"overlap",["skip","queue","replace"],"skip"),N=C(n.tier,"tier",["normal","urgent","critical"],"normal"),D=i==="always"||i==="on-change";if(D&&d===null)throw new s({error:"sink_required",message:`on_output "${i}" delivers stdout every qualifying run \u2014 it needs a sink`,field:"sink",next:"Pass sink node:<node-id> (a living node's inbox), spawn:<kind> (birth a fresh node per delivery), or human (the humanloop inbox)."});if(!D&&d!==null)throw new s({error:"sink_unused",message:`on_output "${i}" never delivers stdout \u2014 a sink would be dead config`,field:"sink",next:'Drop the sink, or use on_output "always"/"on-change" if delivery is the point.'});const Q=d!==null?await On(d):"{}";if(d?.startsWith("spawn:")&&(gn(e.ceiling,"crtr:act"),e.principal.class==="cron")){const w=await bn({grantee:e.principal.app,sub:e.principal.sub,grant_id:e.principal.grant,scopes:e.principal.scopes});if(!w.allowed)throw new c(w.reason==="scope_missing"?403:401,w.reason==="scope_missing"?"scope_missing":"grant_revoked",w.message)}const y=T(e.principal)??"app:terminal",b=e.principal.class==="broker"?e.principal.node:e.principal.class==="cron"?null:typeof n.created_by=="string"&&n.created_by!==""?n.created_by:null;if(e.principal.class==="broker"&&n.created_by!=null&&n.created_by!==b)throw new c(403,"permission_error","a broker may only arm a cron as its own node");const m=b===null?null:await _(b);if(m!==null){if(m.grantee!==y)throw new s({error:"creator_app_mismatch",message:"creator node belongs to another app",field:"created_by",next:"Use a node of the calling app."});Z(m,"crtr:schedule"),d?.startsWith("spawn:")&&Z(m,"crtr:act")}if(n.isolated!==void 0&&typeof n.isolated!="boolean")throw new c(400,"invalid_request","isolated must be a boolean");if(m?.isolated&&n.isolated===!1)throw new c(403,"isolated_run","a cron created by an isolated node cannot escape isolation");const W=m?.isolated===!0||e.principal.class==="cron"&&e.principal.isolated;if(W&&n.isolated===!1)throw new c(403,"isolated_run","a cron created by an isolated caller cannot escape isolation");const q=W||n.isolated===!0,g=await Pn(e,y,m),j=nn(),S=q?an(y,j):null;if(S!==null&&n.cwd_is_default!==!0){const w=en(S,typeof n.cwd=="string"&&n.cwd.trim()!==""?B(n.cwd):S);if(w===".."||w.startsWith(`..${G}`)||w.startsWith(G))throw new c(400,"invalid_request","an isolated cron must run in its own cron folder",{param:"cwd"})}const V=S??await An(n,y,b,jn(n),q,{sub:g.sub,grantId:g.grant_id,scopes:g.scopes}),f=typeof n.anchor_node=="string"&&n.anchor_node!==""?n.anchor_node:null;if(f!==null&&await _(f)!==null&&(await _(f)).grantee!==y)throw new s({error:"anchor_app_mismatch",message:"anchor node belongs to another app",field:"anchor_node",next:"Use an anchor of the calling app."});if(f!==null&&await _(f)===null)throw new s({error:"anchor_not_found",message:`anchor node ${f} does not exist on the canvas`,field:"anchor_node",next:"Name a live node id, or drop the anchor \u2014 an unanchored cron outlives every node."});const x=n.cancel_on_wake===!0;if(x&&f===null)throw new s({error:"cancel_on_wake_needs_anchor",message:"cancel_on_wake couples the cron to a node's dormancy \u2014 it requires an anchor node",field:"anchor_node",next:"Pass anchor_node with the node whose wake should cancel this cron."});const $=n.run_timeout_s??300;if(typeof $!="number"||!Number.isInteger($)||$<=0)throw new s({error:"bad_run_timeout",message:`run_timeout_s must be a positive integer (got ${String(n.run_timeout_s)})`,field:"run_timeout_s",next:"Send the timeout in whole seconds, e.g. 300."});const A=typeof n.profile=="string"&&n.profile!==""?(await Sn(e,n.profile)).profileId:null,z=C(n.scope,"scope",["profile","global"],A!==null?"profile":"global");if(z==="profile"&&A===null)throw new s({error:"scope_needs_profile",message:'scope "profile" names the profile the cron lists and cancels within \u2014 it requires a profile',field:"profile",next:'Send a profile, or use scope "global" for a canvas-home-wide cron.'});return await rn({cron_id:j,name:r,created_by:b,grantee:y,sub:g.sub,grant_id:g.grant_id,scopes:g.scopes,origin_run_id:g.origin_run_id,isolated:q,command:o,fire_at:a,recur:u,tz:typeof n.tz=="string"?n.tz:null,expires_at:l,anchor_node:f,cancel_on_wake:x,cwd:V,env_json:p,profile:A,scope:z,run_timeout_s:$,overlap:h,on_output:i,sink:Q,tier:N}),{status:201,body:k(await v(j),null)}}t(Tn,"handleArm");async function En(e){const n=U(e),r=await $n(n===null?await P({all:!0}):[...await P({profile:n}),...await P({global:!0})].sort((o,a)=>o.fire_at<a.fire_at?-1:o.fire_at>a.fire_at?1:0),async o=>await J(e,o));return{status:200,body:await Cn(r,async o=>k(o,await R(o)))}}t(En,"handleList");async function R(e){return(await F(e.cron_id))[0]??null}t(R,"lastRunOf");async function O(e){const n=e.params.cronId,r=await v(n);if(r===null||!await J(e,r))throw new c(404,"cron_not_found",`no cron ${n}`);if(!Y(r,U(e)))throw new c(404,"cron_not_found",`no cron ${n} in this profile \u2014 it is scoped to another profile`);return r}t(O,"requireCron");function I(e,n){const r=K(e);if(r!==null&&n.grantee!==r)throw new c(403,"other_app_run",`cron ${n.cron_id} belongs to another app`);return n}t(I,"requireOwnCron");async function Un(e){const n=await O(e),r=await F(n.cron_id);return{status:200,body:{cron:k(n,r[0]??null),runs:r.map(H)}}}t(Un,"handleShow");async function Jn(e){const n=I(e,await O(e));await L(n.cron_id,"paused");const r=await v(n.cron_id);return{status:200,body:k(r,await R(r))}}t(Jn,"handlePause");async function Rn(e){const n=I(e,await O(e));await L(n.cron_id,"active");const r=await v(n.cron_id);return{status:200,body:k(r,await R(r))}}t(Rn,"handleResume");async function Dn(e){const n=I(e,await O(e));if(n.run_state==="running")throw new c(409,"cron_running",`cron ${n.cron_id} has a run in flight \u2014 wait for it to settle`);const r=await hn(n,{outOfBand:!0});if(r===null)throw new c(409,"cron_running",`cron ${n.cron_id} was claimed by a concurrent run \u2014 check \`cron show\` for its result`);return{status:200,body:H(r)}}t(Dn,"handleRun");async function Wn(e){const n=new Date().toISOString();return{status:200,body:{unparked:await tn(n,K(e)),at:n}}}t(Wn,"handlePoke");function xn(e,n){const r=e.principal;if(r.class==="cron")return r.cron===n.cron_id?null:{kind:"canceled",by:`cron ${r.cron}`};if(r.class==="broker"){const a=on(n.sink);return a?.kind==="node"&&a.node===r.node?null:{kind:"canceled",by:`node ${r.node}`}}const o=T(r);return{kind:"canceled",by:o===null||o==="app:terminal"?"the person":o}}t(xn,"cancelNotice");async function zn(e){const n=e.params.cronId,r=await v(n);if(r!==null&&!await J(e,r))throw new c(404,"cron_not_found",`no cron ${n}`);if(r!==null&&!Y(r,U(e)))throw new c(404,"cron_not_found",`no cron ${n} in this profile \u2014 it is scoped to another profile`);r!==null&&I(e,r);const o=e.query.get("run_id"),a=e.principal.class==="cron"?o===e.principal.execution&&n===e.principal.cron:!0,u=o!==null&&a&&mn(n,o);return r!==null&&await kn(r,u?null:xn(e,r),{preserveRunningProcess:u}),{status:204}}t(zn,"handleCancel");const ce=[{method:"POST",pattern:"/v1/crons",scope:"crtr:schedule",handler:Tn},{method:"GET",pattern:"/v1/crons",handler:En},{method:"GET",pattern:"/v1/crons/:cronId",handler:Un},{method:"POST",pattern:"/v1/crons/:cronId/pause",scope:"crtr:schedule",handler:Jn},{method:"POST",pattern:"/v1/crons/:cronId/resume",scope:"crtr:schedule",handler:Rn},{method:"POST",pattern:"/v1/crons/poke",scope:"crtr:schedule",handler:Wn},{method:"POST",pattern:"/v1/crons/:cronId/run",scope:"crtr:schedule",handler:Dn},{method:"DELETE",pattern:"/v1/crons/:cronId",scope:"crtr:schedule",handler:zn}];export{ce as cronRoutes};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CanvasDb } from '../../../core/canvas/db.js';
|
|
2
2
|
import type { ObjectRow } from '../../../core/graph/types.js';
|
|
3
3
|
import type { RequestContext, RouteTable } from '../router.js';
|
|
4
4
|
/** A token cannot read the graph. Resolve only identity here; authorization follows before any response. */
|
|
5
|
-
export declare function customObjectRef(db:
|
|
5
|
+
export declare function customObjectRef(db: CanvasDb, raw: string): Promise<ObjectRow>;
|
|
6
6
|
/** An argv object runs host commands: only a person or node principal may change it or what it watches — never an app or publish token. */
|
|
7
|
-
export declare function fenceArgv(db:
|
|
7
|
+
export declare function fenceArgv(db: CanvasDb, ctx: RequestContext, object: ObjectRow): Promise<void>;
|
|
8
8
|
/** A valid object bearer grants only this object; an ordinary principal must act as its owner. */
|
|
9
|
-
export declare function authorizeCustom(db:
|
|
9
|
+
export declare function authorizeCustom(db: CanvasDb, ctx: RequestContext, object: ObjectRow, concealed?: boolean): Promise<ObjectRow | null>;
|
|
10
10
|
export declare const customObjectRoutes: RouteTable;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var A=Object.defineProperty;var
|
|
2
|
-
`),s
|
|
3
|
-
`)},15e3),C=
|
|
1
|
+
var A=Object.defineProperty;var a=(r,e)=>A(r,"name",{value:e,configurable:!0});import{ApiError as c}from"../../../api/errors.js";import{emitEvent as F}from"../../../core/events/emit.js";import{withCanvasWrite as f,openDb as $}from"../../../core/canvas/db.js";import{registerCustomObject as L,publishCustom as P,unregisterCustomObject as H,pendingFor as I,acknowledge as W,verifyPublishToken as j,mayActAs as h,onQueueSignal as M,customReachable as k}from"../../../core/graph/custom.js";import{getById as E,getByRowid as b}from"../../../core/graph/objects.js";import{readerFor as N}from"../../../core/graph/reader.js";import{resolveName as D}from"../../../core/graph/names.js";import{stubOf as z}from"../../../core/peer/stubs.js";import{PRIVACY_LEVELS_DTO as B}from"../../../api/dto/objects.js";import{receiverForObject as Q}from"../../../core/graph/receivers.js";import{readerFor as w,resolveRef as V}from"../reader.js";import{isRecord as d}from"./validate.js";import{receiverEndpoint as G,resolveReceiverAddress as J}from"../../../core/graph/receiver-url.js";const l=a(r=>{throw new c(400,"invalid_request",`invalid ${r}`)},"bad"),p=a(()=>{throw new c(404,"not_found","custom object not found")},"missing");async function m(r,e){const n=await E(r,e)??await(async()=>{const i=await N(r,{class:"person"},async()=>[]),o=await D(r,i,e);return"object"in o?o.object:null})();return!n||!n.type.includes(".")||n.deleted_at!==null?p():n}a(m,"customObjectRef");async function U(r,e,t){if(await Q(r,t)==="argv"&&(e.publishToken||e.principal.class!=="person"&&e.principal.class!=="broker"))throw new c(403,"argv_forbidden","argv object requires a person or node principal")}a(U,"fenceArgv");async function y(r,e,t,n=!1){if(e.publishToken){if(await j(r,t,e.publishToken))return t;if(n)return p();throw new c(401,"invalid_publish_token","invalid publish token")}if(e.principal.class==="anonymous")return p();const i=await w(r,e),o=t.owner===null?null:await b(r,t.owner);return!o||!await h(r,i,o)||!await k(r,i,t)?p():i.class==="person"?i.person:i.class==="app"?i.app:i.class==="node"?i.node:i.object}a(y,"authorizeCustom");async function Y(r){const e=r.body;if((!d(e)||typeof e.kind!="string"||typeof e.name!="string"||typeof e.description!="string"||e.events!==void 0&&!d(e.events)||e.owner!==void 0&&typeof e.owner!="string"||e.rotate_token!==void 0&&typeof e.rotate_token!="boolean"||e.privacy!==void 0&&!B.includes(e.privacy))&&l("register request"),d(e.receiver)&&"url"in e.receiver&&typeof e.receiver.url=="string")try{await J(G(e.receiver.url))}catch(t){throw new c(400,"invalid_receiver",`invalid receiver URL: ${String(t)}`)}return await f(async t=>{const n=await w(t,r),i=e.owner===void 0?n.class==="person"?n.person:n.app:await(async()=>{const u=await V(t,n,e.owner);return"deleted"in u||"remote"in u?p():u})();["person","app","repo","profile"].includes(i.type)||l("owner");const o=await L(t,n,{kind:e.kind,name:e.name,owner:i,description:e.description,...e.events===void 0?{}:{events:e.events},...e.receiver===void 0?{}:{receiver:e.receiver},rotateToken:e.rotate_token,...e.privacy===void 0?{}:{privacy:e.privacy}});return{id:o.object.id,name:o.object.name,...o.token?{token:o.token}:{}}})}a(Y,"register");async function K(r,e,t){const n=await r.prepare("SELECT owner, source, declared FROM object_kinds WHERE name = ?").get(t.type);if(!n||n.source==="register")return;if(n.source==="manifest"&&n.declared===0)throw new c(409,"kind_inert",`${t.type} is no longer declared by an installed plugin`);if(e.publishToken)return;const i=await b(r,n.owner);if(!i||!await h(r,await w(r,e),i))throw new c(403,"forbidden",`only ${i?.name??"the kind owner"} may publish ${t.type}`)}a(K,"requirePublisher");async function X(r){const e=r.body;return(!d(e)||typeof e.event!="string"||typeof e.summary!="string"||e.cause!==void 0&&typeof e.cause!="string")&&l("publish request"),await f(async t=>{const n=await m(t,r.params.ref),i=await z(t,n);if(i!==null)throw new c(404,"not_here",`${n.id} is not homed on this machine (it is a stub of ${i.home_machine})`,{id:n.id,home_machine:i.home_machine});const o=await y(t,r,n);return await K(t,r,n),await P(t,n,o,e)})}a(X,"publish");async function Z(r){await f(async e=>{const t=await m(e,r.params.ref),n=await y(e,r,t);await U(e,r,t),await H(e,t,n)})}a(Z,"unregister");async function x(r){const e=r.body;return(!d(e)||!Array.isArray(e.delivery_ids)||e.delivery_ids.some(t=>typeof t!="string"))&&l("delivery_ids"),await f(async t=>{const n=await m(t,r.params.ref);return await y(t,r,n,!0),await R(t,n),await W(t,n,e.delivery_ids)})}a(x,"ack");async function R(r,e){if((await r.prepare("SELECT receiver_json FROM custom_objects WHERE object = ?").get(e.rowid))?.receiver_json!=='"queue"')throw new c(409,"not_a_queue","object does not have a queue receiver")}a(R,"requireQueue");async function ee(r){const e=r.query.get("after");e!==null&&(!/^\d+$/.test(e)||!Number.isSafeInteger(Number(e)))&&l("after");const t=await $(),n=await m(t,r.params.ref);await y(t,r,n,!0),await R(t,n);const i=r.res;i.writeHead(200,{"content-type":"application/x-ndjson; charset=utf-8","cache-control":"no-cache","x-accel-buffering":"no"});let o=-1;const u=a(async()=>{const s=await E(t,n.id);if(!s||s.deleted_at!==null)return!1;if(r.publishToken)return await j(t,s,r.publishToken)&&(await t.prepare("SELECT receiver_json FROM custom_objects WHERE object = ?").get(s.rowid))?.receiver_json==='"queue"';if(r.principal.class==="anonymous")return!1;const _=s.owner===null?null:await b(t,s.owner),g=await w(t,r);return _!==null&&await h(t,g,_)&&await k(t,g,s)&&(await t.prepare("SELECT receiver_json FROM custom_objects WHERE object = ?").get(s.rowid))?.receiver_json==='"queue"'},"authorized"),v=a(async()=>{if(!(i.destroyed||i.writableEnded)){if(!await u()){i.end();return}for(const s of await I(t,n,o))i.write(`${JSON.stringify(s)}
|
|
2
|
+
`),o=s.seq}},"flush"),O=await M(n.id,v),q=a(async()=>{await v(),!i.destroyed&&!i.writableEnded&&i.write(`
|
|
3
|
+
`)},"beat"),S=setInterval(()=>{q().catch(s=>F({level:"error",event:"api.custom_objects.heartbeat_failed",node_id:n.id,error:s}))},15e3),C=a(()=>{clearInterval(S),O()},"close");return i.once("close",C),await v(),{status:200}}a(ee,"stream");const T=a(r=>async e=>({status:200,body:await r(e)}),"ok"),me=[{method:"POST",pattern:"/v1/custom-objects",handler:a(async r=>({status:200,body:await Y(r)}),"handler")},{method:"POST",pattern:"/v1/custom-objects/:ref/events",handler:T(X)},{method:"DELETE",pattern:"/v1/custom-objects/:ref",handler:a(async r=>(await Z(r),{status:204}),"handler")},{method:"GET",pattern:"/v1/custom-objects/:ref/deliveries",handler:ee},{method:"POST",pattern:"/v1/custom-objects/:ref/deliveries/ack",handler:T(x)}];export{y as authorizeCustom,m as customObjectRef,me as customObjectRoutes,U as fenceArgv};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var d=Object.defineProperty;var t=(r,e)=>d(r,"name",{value:e,configurable:!0});import{ApiError as i}from"../../../api/errors.js";import{retryFailedDaemonAction as o}from"../../../core/canvas/daemon-actions.js";import{retryFailedDelivery as
|
|
1
|
+
var d=Object.defineProperty;var t=(r,e)=>d(r,"name",{value:e,configurable:!0});import{ApiError as i}from"../../../api/errors.js";import{retryFailedDaemonAction as o}from"../../../core/canvas/daemon-actions.js";import{retryFailedDelivery as a}from"../../../core/canvas/deliveries.js";const n=/^[0-9a-f]{32}$/;async function l(r){const e=r.params.delivery_id??"";if(!n.test(e))throw new i(400,"invalid_request","delivery_id must be the 32-character id of a delivery");if(!await a(e)&&!await o(e))throw new i(404,"delivery_not_failed",`no failed delivery ${e} to retry (it does not exist, is not permanently failed, or was canceled)`);return{status:200,body:{delivery_id:e,state:"pending"}}}t(l,"handleRetry");const m=[{method:"POST",pattern:"/v1/deliveries/:delivery_id/retry",handler:l}];export{m as deliveryRetryRoutes};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var _=Object.defineProperty;var c=(e,n)=>_(e,"name",{value:n,configurable:!0});import{ApiError as r}from"../../../api/errors.js";import{withCanvasWrite as f}from"../../../core/canvas/db.js";import{readerForNode as l}from"../../../core/graph/reader.js";import{noteNodeBooting as j}from"../../../core/graph/repo-sync/index.js";import{checkoutsForCwd as h,warmCheckoutIdentities as k}from"../../../core/graph/repo-sync/repos.js";import{getNode as N}from"../../../core/canvas/canvas.js";import{DRY_RUN_ONLY as q,deliver as A,hypotheticalFrom as C,hypotheticalReader as I,inspect as p}from"../../../core/substrate/delivery/deliver.js";import{requireCurrentExecution as w}from"./broker-recovery.js";const O=["boot","system-prompt","compact","persona","file-read","command","pre-command","slash-command","names",...q];function m(e){if(typeof e!="object"||e===null||Array.isArray(e))throw new r(400,"usage","delivery requires a JSON body");const n=e;if(!O.includes(n.activity))throw new r(400,"usage",`invalid delivery activity: ${String(n.activity)}`);if(n.subject!==void 0&&typeof n.subject!="string")throw new r(400,"usage","delivery subject must be a string");return n}c(m,"parse");function b(e){if(e.principal.class!=="person"&&e.principal.class!=="broker")throw new r(403,"permission_error","a delivery dry run is available to a person or a node only")}c(b,"requirePerson");function R(e){if(typeof e!="object"||e===null||Array.isArray(e))throw new r(400,"usage","hypothetical must be an object");const n=c((o,s)=>{if(o!==void 0){if(typeof o!="string"||o==="")throw new r(400,"usage",`hypothetical.${s} must be a non-empty string`);return o}},"str"),t=n(e.cwd,"cwd");if(t!==void 0&&!t.startsWith("/"))throw new r(400,"usage","hypothetical.cwd must be an absolute path");if(e.mode!==void 0&&e.mode!=="base"&&e.mode!=="orchestrator")throw new r(400,"usage","hypothetical.mode must be base or orchestrator");if(e.lifecycle!==void 0&&e.lifecycle!=="terminal"&&e.lifecycle!=="resident")throw new r(400,"usage","hypothetical.lifecycle must be terminal or resident");if(e.has_manager!==void 0&&typeof e.has_manager!="boolean")throw new r(400,"usage","hypothetical.has_manager must be a boolean");if(e.depth!==void 0&&(!Number.isInteger(e.depth)||e.depth<0))throw new r(400,"usage","hypothetical.depth must be a non-negative integer");const i={};t!==void 0&&(i.cwd=t),e.profile!==void 0&&(i.profile=e.profile===null?null:n(e.profile,"profile"));const d=n(e.grantee,"grantee");d!==void 0&&(i.grantee=d);const a=n(e.kind,"kind");return a!==void 0&&(i.kind=a),e.mode!==void 0&&(i.mode=e.mode),e.lifecycle!==void 0&&(i.lifecycle=e.lifecycle),e.has_manager!==void 0&&(i.hasManager=e.has_manager),e.depth!==void 0&&(i.depth=e.depth),i}c(R,"hypotheticalOf");async function y(e,n){const t=e===void 0?void 0:await N(e);for(const i of[t?.cwd,n])i&&k(i)}c(y,"warmDeliveryCwds");async function S(e){b(e);const n=m(e.body);if(n.node!==void 0&&typeof n.node!="string")throw new r(400,"usage","node must be a node id");const t={activity:n.activity,...n.subject!==void 0?{subject:n.subject}:{}};await y(n.node,n.hypothetical?.cwd);const{result:i,plan:d}=await f(async a=>{if(n.hypothetical===void 0){if(n.node===void 0)throw new r(400,"usage","a delivery dry run names a node, a hypothetical node, or both");return await p(a,await l(a,n.node,async v=>await h(a,v)),t,n.subject_override)}const o=R(n.hypothetical),s=n.node!==void 0?await C(n.node,o):{...o,cwd:o.cwd??""};if(s.cwd==="")throw new r(400,"usage","a hypothetical node needs a cwd");const{reader:u,subject:g}=await I(a,s);return await p(a,u,t,n.subject_override,g)},{rollback:!0});return{status:200,body:{...i,plan:d}}}c(S,"handleDryRun");async function D(e){const n=e.params.id,t=m(e.body),i={activity:t.activity,...t.subject!==void 0?{subject:t.subject}:{},...t.inherited===!0?{inherited:!0}:{}};if(t.dry_run===!0){b(e),await y(n);const{result:a,plan:o}=await f(async s=>await p(s,await l(s,n,async u=>await h(s,u)),i,t.subject_override),{rollback:!0});return{status:200,body:{...a,plan:o}}}if(e.principal.class==="broker"&&e.principal.node!==n)throw new r(403,"permission_error","delivery is performed by the node's own broker");return await w(n,t.expected_execution_id),t.activity==="boot"&&(await j(n),await w(n,t.expected_execution_id)),await y(n),{status:200,body:await f(async a=>await A(a,await l(a,n,async o=>await h(a,o)),i))}}c(D,"handleDelivery");const L=[{method:"POST",pattern:"/v1/nodes/:id/delivery",handler:D},{method:"POST",pattern:"/v1/delivery/dry-run",handler:S}];export{L as deliveryRoutes};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CanvasDb } from '../../../core/canvas/db.js';
|
|
2
2
|
import type { ObjectRow, Reader } from '../../../core/graph/types.js';
|
|
3
3
|
import type { RouteTable } from '../router.js';
|
|
4
|
-
export declare function canonicalName(db:
|
|
4
|
+
export declare function canonicalName(db: CanvasDb, o: ObjectRow): Promise<string>;
|
|
5
5
|
/** A committed change to a repo-owned document starts that repo's sync. */
|
|
6
6
|
export interface RepoChange {
|
|
7
7
|
repos: ObjectRow[];
|
|
@@ -10,7 +10,7 @@ export interface RepoChange {
|
|
|
10
10
|
/** The repos among `owners` and the directories that may hold a checkout of them (the caller's cwd,
|
|
11
11
|
* a node's own else the request's, and the checkouts its view reaches), captured inside the write
|
|
12
12
|
* transaction and acted on after it commits. */
|
|
13
|
-
export declare function repoChange(db:
|
|
13
|
+
export declare function repoChange(db: CanvasDb, reader: Reader, owners: ObjectRow[], requestCwd?: string): Promise<RepoChange>;
|
|
14
14
|
/** The change is committed; a sync that cannot start is reported as an event, never as a failed write. */
|
|
15
|
-
export declare function syncChanged(change: RepoChange): void
|
|
15
|
+
export declare function syncChanged(change: RepoChange): Promise<void>;
|
|
16
16
|
export declare const docRoutes: RouteTable;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var re=Object.defineProperty;var u=(t,e)=>re(t,"name",{value:e,configurable:!0});import{prepared as P}from"../../../core/sqlite-statements.js";import{ApiError as _}from"../../../api/errors.js";import{DOC_KINDS as q,DOC_UNSET_FIELDS as H}from"../../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as U}from"../../../api/dto/objects.js";import{withCanvasWrite as k}from"../../../core/canvas/db.js";import{CrtrError as ie}from"../../../core/errors.js";import{emitEvent as se}from"../../../core/events/emit.js";import{canChange as V,spaceOf as ae}from"../../../core/graph/access.js";import{get as A}from"../../../core/graph/bodies.js";import{deleteDocument as ce,documentRecord as I,editDocument as de,heads as x,history as ue,linksIn as K,moveDocument as fe,readBase as me,setDocumentRecord as le,withCurrentNames as pe,writeDocument as he}from"../../../core/graph/documents.js";import{resolveName as X}from"../../../core/graph/names.js";import{getByRowid as L}from"../../../core/graph/objects.js";import{noteRepoDocumentsChanged as we}from"../../../core/graph/repo-sync/index.js";import{checkoutsForCwd as ye}from"../../../core/graph/repo-sync/repos.js";import{lintRules as ve,rulesOf as ge}from"../../../core/graph/rules.js";import{unifiedDiff as _e}from"../../../core/graph/diff.js";import{ownerFromFlag as M,readerFor as E,resolveRef as z}from"../reader.js";function v(t,e,n,o,i={}){return new _(t,e,n,{...i,error:e,message:n,next:o})}u(v,"refuse");const b=u((t,e)=>new _(400,"invalid_request",t,e),"invalid");function R(t){const e=t.body;if(e===void 0)return{};if(typeof e!="object"||e===null||Array.isArray(e))throw b("the request body must be a JSON object");return e}u(R,"bodyOf");const S=u(t=>e=>ye(t,e),"reposFnFor");function C(t,e){if(t instanceof ie){const n=t.details;if(t.code==="read_first")throw v(409,"read_first",t.message,`Read it first with \`crtr canvas read ${e?.id??"<ref>"}\`, then rerun the edit.`,n??{});if(t.code==="conflict")throw new _(409,"name_taken",t.message,n);if(t.code==="forbidden")throw new _(403,"forbidden",t.message,n);if(t.code==="scope_missing")throw v(403,"scope_missing",t.message,`Launch the run with \`${String(n?.scope)}\` in its scopes list.`,n??{});if(n?.rule==="repo-public-only")throw v(422,"repo_documents_are_public",t.message,'Own it as `user` and add a rule with `if: {"repo": "<handle>"}` so it loads only in that repo.')}throw t}u(C,"mapGraphError");function W(t,e,n){const o=z(t,e,decodeURIComponent(n));if("remote"in o)throw v(404,"not_found",G(o.remote),"Check the name with `crtr canvas search`.");if("deleted"in o)throw new _(404,"not_found",`${o.deleted.name} is deleted`,{id:o.deleted.id,deleted:!0});if(o.type!=="document")throw b(`${n} is a ${o.type}, not a document`);return o}u(W,"refDocument");function G(t){return`no object named ${t} on this runtime; it may be on another runtime, or the name may be misspelled`}u(G,"remoteMessage");function be(t,e){const n=e.owner===null?null:L(t,e.owner);return n?n.type==="node"?n.id:n.name:""}u(be,"ownerHandle");function j(t,e){const n=be(t,e);return n?`${n}/${e.name}`:e.name}u(j,"canonicalName");function ke(t,e){const n=e.owner===null?null:L(t,e.owner),o=n?{id:n.id,type:n.type,handle:n.type==="node"?n.id:n.name}:null;return{id:e.id,type:e.type,kind:e.kind,owner:o,privacy:e.privacy,name:e.name,preview:e.preview??"",created_at:e.created_at,deleted_at:e.deleted_at}}u(ke,"objectDTO");function Ee(t,e){const n=e.owner===null?null:L(t,e.owner);return n?.type==="repo"?n:null}u(Ee,"repoOwner");function N(t,e,n,o){const i=[...new Map(n.flatMap(f=>{const s=Ee(t,f);return s?[[s.id,s]]:[]})).values()],a=e.class==="node"?e.cwd:o,r=e.class==="node"?[...e.checkouts,...e.projectCheckouts].map(f=>f.root):[];return{repos:i,dirs:[...new Set([...a!==void 0?[a]:[],...r])]}}u(N,"repoChange");function T(t){for(const e of t.repos)try{we(e,t.dirs)}catch(n){se({level:"warn",event:"repo_sync.failed",outcome:"failed",error:n,fields:{repo:e.name,step:"export",reason:n instanceof Error?n.message:String(n)}})}}u(T,"syncChanged");const Y=/^[A-Za-z0-9_-]+(\/[A-Za-z0-9_-]+)*$/;function $e(t,e){if(t===void 0)return;if(!Array.isArray(t)){e.push("`rules` must be a list");return}const n=t.map(i=>{if(typeof i!="object"||i===null||Array.isArray(i))return i;const{match_frontmatter:a,...r}=i;return"matchFrontmatter"in r?{...r,match_frontmatter:r.matchFrontmatter}:a===void 0?r:{...r,matchFrontmatter:a}}),o=ve(n);if(o){e.push(o.replaceAll("matchFrontmatter","match_frontmatter"));return}return n}u($e,"rulesFromDTO");function Z(t,e){const n={},o=u(s=>{const c=t[s];if(c!==void 0){if(typeof c!="string"){e.push(`\`${s}\` must be a string`);return}return c}},"str"),i=o("preview");i!==void 0&&(i.trim()===""||/[\r\n]/.test(i)?e.push("`preview` must be one non-empty line"):n.preview=i);const a=o("summary");a!==void 0&&(n.summary=a);const r=o("why_it_exists");if(r!==void 0&&(n.whyItExists=r),t.privacy!==void 0&&(U.includes(t.privacy)?n.privacy=t.privacy:e.push(`\`privacy\` must be one of ${U.join(", ")}`)),t.unlisted!==void 0&&(typeof t.unlisted!="boolean"?e.push("`unlisted` must be a boolean"):n.unlisted=t.unlisted),t.lint_ignore!==void 0){const s=t.lint_ignore;!Array.isArray(s)||s.some(c=>typeof c!="string")?e.push("`lint_ignore` must be a list of strings"):n.lintIgnore=s}if(t.extensions!==void 0){const s=t.extensions;typeof s!="object"||s===null||Array.isArray(s)||Object.values(s).some(c=>typeof c!="object"||c===null||Array.isArray(c))?e.push("`extensions` must map each plugin to an object of fields"):n.extensions=s}const f=$e(t.rules,e);return f!==void 0&&(n.rules=f),n}u(Z,"fieldsFrom");function J(t){if(t.length>0)throw b(t.join("; "),{errors:t})}u(J,"failOn");function Q(t,e,n,o){const i=K(n).filter(a=>"remote"in X(t,e,a));return{...o.length>0?{unresolved_links:o}:{},...i.length>0?{remote_links:i}:{}}}u(Q,"linkReport");function Oe(t){const e=R(t),n=[],o=e.name;(typeof o!="string"||!Y.test(o))&&n.push("`name` must be segments of letters, digits, `_` or `-` joined by `/`"),typeof e.body!="string"&&n.push("`body` must be a string"),typeof e.preview!="string"&&n.push("`preview` is required");const i=e.kind??"knowledge";q.includes(i)||n.push(i==="report"?"reports are written only by `crtr push`":`\`kind\` must be one of ${q.join(", ")}`);const a=Z(e,n);e.cwd!==void 0&&typeof e.cwd!="string"&&n.push("`cwd` must be a string"),J(n);const r=e,{dto:f,change:s}=k(c=>{const h=E(c,t),d=M(c,h,r.owner,r.cwd);if(!V(c,h,d))throw new _(404,"not_found",`no owner ${d.name} you can write to`);try{const{object:p,unresolved:m}=he(c,h,{...a,owner:d,name:r.name,kind:i,preview:a.preview,privacy:a.privacy??"public"},r.body,S(c));return{dto:{id:p.id,name:j(c,p),...Q(c,h,r.body,m)},change:N(c,h,[p],r.cwd)}}catch(p){C(p)}});return T(s),f}u(Oe,"write");function Ae(t,e){let n=t;e.forEach(({old:o,new:i},a)=>{const r=o===""?-1:n.indexOf(o);if(r<0)throw v(422,"replace_no_match",`replace[${a}]: old text not found in the revision you read`,"Copy the old text exactly from your last read and rerun.",{index:a});if(n.indexOf(o,r+1)>=0)throw v(422,"replace_ambiguous",`replace[${a}]: old text occurs more than once`,"Include more surrounding text so the old text matches once, and rerun.",{index:a});n=n.slice(0,r)+i+n.slice(r+o.length)})}u(Ae,"checkReplacements");function je(t){const e=R(t),n=[],o=e.body!==void 0,i=e.replace!==void 0;o&&i&&n.push("give `body` or `replace`, not both"),o&&typeof e.body!="string"&&n.push("`body` must be a string");const a=e.replace;i&&(!Array.isArray(a)||a.length===0||a.some(d=>typeof d!="object"||d===null||typeof d.old!="string"||typeof d.new!="string"))&&n.push("`replace` must be a non-empty list of {old, new} strings"),(typeof e.rationale!="string"||e.rationale.trim()==="")&&n.push("`rationale` is required"),e.verbatim!==void 0&&typeof e.verbatim!="boolean"&&n.push("`verbatim` must be a boolean"),e.base!==void 0&&(typeof e.base!="string"||e.base==="")&&n.push("`base` must be a non-empty heads key"),e.base!==void 0&&!o&&!i&&n.push("`base` applies only to a `body` or `replace` edit");const r=Z(e,n),f=e.unset??[];if(!Array.isArray(f)||f.some(d=>!H.includes(d)))n.push(`\`unset\` takes only ${H.join(", ")}`);else for(const d of f)d==="summary"&&(r.summary=null),d==="why_it_exists"&&(r.whyItExists=null),d==="unlisted"&&(r.unlisted=!1),d==="lint_ignore"&&(r.lintIgnore=null),d==="extensions"&&(r.extensions=null),d==="rules"&&(r.rules=[]);n.length===0&&!o&&!i&&Object.keys(r).length===0&&n.push("nothing to change: give `body`, `replace`, or a field"),J(n);const s=e,{dto:c,synced:h}=k(d=>{const p=E(d,t),m=W(d,p,t.params.ref),g=j(d,m),O=N(d,p,[m]);try{if(!o&&!i)return le(d,p,m,r),{dto:{id:m.id,name:g,revision:I(d,m).revision},synced:O};const y=s.base??me(d,p,m);if(i&&y!==null){const oe=I(d,m),B=x(d,m);oe.heads_key===y&&B.length===1&&Ae(pe(d,m,A(B[0].body_hash)),s.replace)}const D=s.verbatim===!0,l=o?{body:s.body,verbatim:D}:{replace:s.replace,verbatim:D},w=de(d,p,m,l,s.rationale,y,r,S(d));if("stale"in w)throw v(409,"stale_revision",`${g} changed after your read; it is now at revision ${w.stale.revision}`,`Read it again with \`crtr canvas read ${g}\`, then redo your change on the current text.`,{stale:w.stale});const F=A(x(d,m)[0].body_hash);return{dto:{id:m.id,name:g,revision:w.revision,...Q(d,p,F,w.unresolved)},synced:O}}catch(y){C(y,m)}});return T(h),c}u(je,"edit");function De(t){const e=R(t);if(e.new_name===void 0&&e.owner===void 0)throw b("give a new name, an owner, or both");if(e.new_name!==void 0&&(typeof e.new_name!="string"||!Y.test(e.new_name)))throw b("`new_name` must be segments of letters, digits, `_` or `-` joined by `/`");const{dto:n,change:o}=k(i=>{const a=E(i,t),r=W(i,a,t.params.ref),f=e.owner===void 0?void 0:M(i,a,e.owner,e.cwd);try{const s=fe(i,a,r,{...e.new_name!==void 0?{name:e.new_name}:{},...f?{owner:f}:{}},S(i));return{dto:{id:s.id,name:j(i,s)},change:N(i,a,[r,s],e.cwd)}}catch(s){C(s,r)}});return T(o),n}u(De,"move");function Re(t){const{dto:e,change:n}=k(o=>{const i=E(o,t),a=W(o,i,t.params.ref),r=j(o,a),f=N(o,i,[a]);try{ce(o,i,a,S(o))}catch(s){C(s,a)}return{dto:{id:a.id,name:r},change:f}});return T(n),e}u(Re,"remove");function Se(t){const e=t.query.get("diff"),n=e===null?void 0:Number(e);if(n!==void 0&&!(Number.isInteger(n)&&n>0))throw b("`diff` must be a revision number");return k(o=>{const i=E(o,t),a=z(o,i,decodeURIComponent(t.params.ref));if("remote"in a)throw v(404,"not_found",G(a.remote),"Check the name with `crtr canvas search`.");const r="deleted"in a?a.deleted:a;if(r.type!=="document")throw b(`${r.name} is a ${r.type}, not a document`);const f=ue(o,i,r),s={object:ke(o,r),revisions:f.map(c=>({rev_id:c.rev_id,number:c.number,author_id:c.author,rationale:c.rationale,verbatim:c.verbatim,created_at:c.created_at,parents:c.parents}))};if(n!==void 0){const c=f.find(d=>d.number===n);if(!c)throw new _(404,"not_found",`${r.name} has no revision ${n}`);const h=c.parents[0]===void 0?void 0:f.find(d=>d.rev_id===c.parents[0]);s.diff=_e(h?A(h.body_hash):"",A(c.body_hash))}return s})}u(Se,"revisionHistory");const ee=1e3,ne=1e3,te=3e3,Ce=/^When\b.+\bbecause\b.+/,Ne=u(t=>{const e=t.trim();return e===""?0:e.split(/\s+/).length},"words");function Te(t,e){if(t.some(o=>o.on==="boot"&&o.deliver==="content")&&e>ee)return`body is ${e} words, over the ${ee}-word cap for a boot rule at content (the whole body enters every node's context). Keep the core here and move separate subjects into [[linked]] documents.`;const n=[...new Set(t.filter(o=>o.on!=="boot"&&o.deliver==="content").map(o=>o.on))];return n.length>0&&e>ne?`body is ${e} words, over the ${ne}-word cap for a content rule on ${n.join("/")}. Keep the core here and move separate subjects into [[linked]] documents.`:t.some(o=>o.on==="boot"&&o.deliver==="preview")&&e>te?`body is ${e} words, over the ${te}-word cap for a boot rule at preview. Keep the core here and move separate subjects into [[linked]] documents.`:null}u(Te,"lengthFinding");function Fe(t){const e=R(t);return k(n=>{const o=E(n,t),i=e.owner===void 0?null:M(n,o,e.owner,e.cwd),a=P(n,"SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL AND home_machine IS NULL AND kind != 'report' ORDER BY name").all(),r=[],f=new Map;for(const s of a){if(i&&s.owner!==i.rowid||!V(n,o,s))continue;const c=I(n,s),h=new Set(c.lint_ignore??[]),d=j(n,s),p=u((l,w,F)=>{h.has(l)||r.push({name:d,severity:w,rule:l,message:F})},"add"),m=ge(n,s),g=x(n,s)[0],O=g?A(g.body_hash):"",y=Te(m,Ne(O));y&&p("length","error",y),m.some(l=>l.deliver==="preview")&&!Ce.test(s.preview??"")&&p("preview-shape","error",`a rule delivers this document at preview, so the preview must read "When <situation in the reader's work>, read this because <what the reader gains>"`);const D=new Set(P(n,"SELECT written_as FROM edges WHERE type = 'links-to' AND src = ?").all(s.rowid).map(l=>l.written_as));for(const l of K(O)){if(D.has(l))continue;const w=X(n,o,l);"remote"in w||"object"in w||"deleted"in w||p("links","warning",`[[${l}]] names no object in your view`)}if(m.some(l=>l.on==="workspace-open"&&l.deliver==="content")){const l=ae(n,s);l.type==="repo"&&!h.has("workspace-open")&&f.set(l.name,[...f.get(l.name)??[],d])}}for(const[s,c]of f)if(!(c.length<2))for(const h of c)r.push({name:h,severity:"warning",rule:"workspace-open",message:`repo ${s} has ${c.length} documents delivered at content on workspace-open (${c.join(", ")}); keep one and link the rest from it`});return{findings:r}})}u(Fe,"lint");const $=u((t,e=200)=>n=>({status:e,body:t(n)}),"ok"),Qe=[{method:"POST",pattern:"/v1/docs",handler:$(Oe,201)},{method:"PATCH",pattern:"/v1/docs/:ref",handler:$(je)},{method:"POST",pattern:"/v1/docs/:ref/move",handler:$(De)},{method:"DELETE",pattern:"/v1/docs/:ref",handler:$(Re)},{method:"GET",pattern:"/v1/docs/:ref/history",handler:$(Se)},{method:"POST",pattern:"/v1/docs/lint",handler:$(Fe)}];export{j as canonicalName,Qe as docRoutes,N as repoChange,T as syncChanged};
|
|
1
|
+
var oe=Object.defineProperty;var u=(n,e)=>oe(n,"name",{value:e,configurable:!0});import{ApiError as _}from"../../../api/errors.js";import{DOC_KINDS as P,DOC_UNSET_FIELDS as q}from"../../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as H}from"../../../api/dto/objects.js";import{withCanvasWrite as k}from"../../../core/canvas/db.js";import{CrtrError as re}from"../../../core/errors.js";import{emitEvent as ie}from"../../../core/events/emit.js";import{canChange as U,spaceOf as ae}from"../../../core/graph/access.js";import{get as O}from"../../../core/graph/bodies.js";import{deleteDocument as se,documentRecord as I,editDocument as ce,heads as x,history as de,linksIn as V,moveDocument as ue,readBase as fe,setDocumentRecord as le,withCurrentNames as me,writeDocument as pe}from"../../../core/graph/documents.js";import{resolveName as K}from"../../../core/graph/names.js";import{getByRowid as L}from"../../../core/graph/objects.js";import{noteRepoDocumentsChanged as we}from"../../../core/graph/repo-sync/index.js";import{checkoutsForCwd as he}from"../../../core/graph/repo-sync/repos.js";import{lintRules as ye,rulesOf as ve}from"../../../core/graph/rules.js";import{unifiedDiff as ge}from"../../../core/graph/diff.js";import{ownerFromFlag as M,readerFor as E,resolveRef as X}from"../reader.js";import{filterAsync as _e,flatMapAsync as be}from"../../../core/async-array.js";function v(n,e,t,o,i={}){return new _(n,e,t,{...i,error:e,message:t,next:o})}u(v,"refuse");const b=u((n,e)=>new _(400,"invalid_request",n,e),"invalid");function R(n){const e=n.body;if(e===void 0)return{};if(typeof e!="object"||e===null||Array.isArray(e))throw b("the request body must be a JSON object");return e}u(R,"bodyOf");const C=u(async n=>async e=>await he(n,e),"reposFnFor");function S(n,e){if(n instanceof re){const t=n.details;if(n.code==="read_first")throw v(409,"read_first",n.message,`Read it first with \`crtr canvas read ${e?.id??"<ref>"}\`, then rerun the edit.`,t??{});if(n.code==="conflict")throw new _(409,"name_taken",n.message,t);if(n.code==="forbidden")throw new _(403,"forbidden",n.message,t);if(n.code==="scope_missing")throw v(403,"scope_missing",n.message,`Launch the run with \`${String(t?.scope)}\` in its scopes list.`,t??{});if(t?.rule==="repo-public-only")throw v(422,"repo_documents_are_public",n.message,'Own it as `user` and add a rule with `if: {"repo": "<handle>"}` so it loads only in that repo.')}throw n}u(S,"mapGraphError");async function W(n,e,t){const o=await X(n,e,decodeURIComponent(t));if("remote"in o)throw v(404,"not_found",z(o.remote),"Check the name with `crtr canvas search`.");if("deleted"in o)throw new _(404,"not_found",`${o.deleted.name} is deleted`,{id:o.deleted.id,deleted:!0});if(o.type!=="document")throw b(`${t} is a ${o.type}, not a document`);return o}u(W,"refDocument");function z(n){return`no object named ${n} on this runtime; it may be on another runtime, or the name may be misspelled`}u(z,"remoteMessage");async function ke(n,e){const t=e.owner===null?null:await L(n,e.owner);return t?t.type==="node"?t.id:t.name:""}u(ke,"ownerHandle");async function j(n,e){const t=await ke(n,e);return t?`${t}/${e.name}`:e.name}u(j,"canonicalName");async function Ee(n,e){const t=e.owner===null?null:await L(n,e.owner),o=t?{id:t.id,type:t.type,handle:t.type==="node"?t.id:t.name}:null;return{id:e.id,type:e.type,kind:e.kind,owner:o,privacy:e.privacy,name:e.name,preview:e.preview??"",created_at:e.created_at,deleted_at:e.deleted_at}}u(Ee,"objectDTO");async function $e(n,e){const t=e.owner===null?null:await L(n,e.owner);return t?.type==="repo"?t:null}u($e,"repoOwner");async function N(n,e,t,o){const i=[...new Map(await be(t,async f=>{const a=await $e(n,f);return a?[[a.id,a]]:[]})).values()],s=e.class==="node"?e.cwd:o,r=e.class==="node"?[...e.checkouts,...e.projectCheckouts].map(f=>f.root):[];return{repos:i,dirs:[...new Set([...s!==void 0?[s]:[],...r])]}}u(N,"repoChange");async function T(n){for(const e of n.repos)try{await we(e,n.dirs)}catch(t){ie({level:"warn",event:"repo_sync.failed",outcome:"failed",error:t,fields:{repo:e.name,step:"export",reason:t instanceof Error?t.message:String(t)}})}}u(T,"syncChanged");const G=/^[A-Za-z0-9_-]+(\/[A-Za-z0-9_-]+)*$/;function Ae(n,e){if(n===void 0)return;if(!Array.isArray(n)){e.push("`rules` must be a list");return}const t=n.map(i=>{if(typeof i!="object"||i===null||Array.isArray(i))return i;const{match_frontmatter:s,...r}=i;return"matchFrontmatter"in r?{...r,match_frontmatter:r.matchFrontmatter}:s===void 0?r:{...r,matchFrontmatter:s}}),o=ye(t);if(o){e.push(o.replaceAll("matchFrontmatter","match_frontmatter"));return}return t}u(Ae,"rulesFromDTO");function Y(n,e){const t={},o=u(a=>{const c=n[a];if(c!==void 0){if(typeof c!="string"){e.push(`\`${a}\` must be a string`);return}return c}},"str"),i=o("preview");i!==void 0&&(i.trim()===""||/[\r\n]/.test(i)?e.push("`preview` must be one non-empty line"):t.preview=i);const s=o("summary");s!==void 0&&(t.summary=s);const r=o("why_it_exists");if(r!==void 0&&(t.whyItExists=r),n.privacy!==void 0&&(H.includes(n.privacy)?t.privacy=n.privacy:e.push(`\`privacy\` must be one of ${H.join(", ")}`)),n.unlisted!==void 0&&(typeof n.unlisted!="boolean"?e.push("`unlisted` must be a boolean"):t.unlisted=n.unlisted),n.lint_ignore!==void 0){const a=n.lint_ignore;!Array.isArray(a)||a.some(c=>typeof c!="string")?e.push("`lint_ignore` must be a list of strings"):t.lintIgnore=a}if(n.extensions!==void 0){const a=n.extensions;typeof a!="object"||a===null||Array.isArray(a)||Object.values(a).some(c=>typeof c!="object"||c===null||Array.isArray(c))?e.push("`extensions` must map each plugin to an object of fields"):t.extensions=a}const f=Ae(n.rules,e);return f!==void 0&&(t.rules=f),t}u(Y,"fieldsFrom");function Z(n){if(n.length>0)throw b(n.join("; "),{errors:n})}u(Z,"failOn");async function J(n,e,t,o){const i=await _e(V(t),async s=>"remote"in await K(n,e,s));return{...o.length>0?{unresolved_links:o}:{},...i.length>0?{remote_links:i}:{}}}u(J,"linkReport");async function Oe(n){const e=R(n),t=[],o=e.name;(typeof o!="string"||!G.test(o))&&t.push("`name` must be segments of letters, digits, `_` or `-` joined by `/`"),typeof e.body!="string"&&t.push("`body` must be a string"),typeof e.preview!="string"&&t.push("`preview` is required");const i=e.kind??"knowledge";P.includes(i)||t.push(i==="report"?"reports are written only by `crtr push`":`\`kind\` must be one of ${P.join(", ")}`);const s=Y(e,t);e.cwd!==void 0&&typeof e.cwd!="string"&&t.push("`cwd` must be a string"),Z(t);const r=e,{dto:f,change:a}=await k(async c=>{const w=await E(c,n),d=await M(c,w,r.owner,r.cwd);if(!await U(c,w,d))throw new _(404,"not_found",`no owner ${d.name} you can write to`);try{const{object:p,unresolved:l}=await pe(c,w,{...s,owner:d,name:r.name,kind:i,preview:s.preview,privacy:s.privacy??"public"},r.body,await C(c));return{dto:{id:p.id,name:await j(c,p),...await J(c,w,r.body,l)},change:await N(c,w,[p],r.cwd)}}catch(p){S(p)}});return await T(a),f}u(Oe,"write");function je(n,e){let t=n;e.forEach(({old:o,new:i},s)=>{const r=o===""?-1:t.indexOf(o);if(r<0)throw v(422,"replace_no_match",`replace[${s}]: old text not found in the revision you read`,"Copy the old text exactly from your last read and rerun.",{index:s});if(t.indexOf(o,r+1)>=0)throw v(422,"replace_ambiguous",`replace[${s}]: old text occurs more than once`,"Include more surrounding text so the old text matches once, and rerun.",{index:s});t=t.slice(0,r)+i+t.slice(r+o.length)})}u(je,"checkReplacements");async function De(n){const e=R(n),t=[],o=e.body!==void 0,i=e.replace!==void 0;o&&i&&t.push("give `body` or `replace`, not both"),o&&typeof e.body!="string"&&t.push("`body` must be a string");const s=e.replace;i&&(!Array.isArray(s)||s.length===0||s.some(d=>typeof d!="object"||d===null||typeof d.old!="string"||typeof d.new!="string"))&&t.push("`replace` must be a non-empty list of {old, new} strings"),(typeof e.rationale!="string"||e.rationale.trim()==="")&&t.push("`rationale` is required"),e.verbatim!==void 0&&typeof e.verbatim!="boolean"&&t.push("`verbatim` must be a boolean"),e.base!==void 0&&(typeof e.base!="string"||e.base==="")&&t.push("`base` must be a non-empty heads key"),e.base!==void 0&&!o&&!i&&t.push("`base` applies only to a `body` or `replace` edit");const r=Y(e,t),f=e.unset??[];if(!Array.isArray(f)||f.some(d=>!q.includes(d)))t.push(`\`unset\` takes only ${q.join(", ")}`);else for(const d of f)d==="summary"&&(r.summary=null),d==="why_it_exists"&&(r.whyItExists=null),d==="unlisted"&&(r.unlisted=!1),d==="lint_ignore"&&(r.lintIgnore=null),d==="extensions"&&(r.extensions=null),d==="rules"&&(r.rules=[]);t.length===0&&!o&&!i&&Object.keys(r).length===0&&t.push("nothing to change: give `body`, `replace`, or a field"),Z(t);const a=e,{dto:c,synced:w}=await k(async d=>{const p=await E(d,n),l=await W(d,p,n.params.ref),g=await j(d,l),A=await N(d,p,[l]);try{if(!o&&!i)return await le(d,p,l,r),{dto:{id:l.id,name:g,revision:(await I(d,l)).revision},synced:A};const y=a.base??await fe(d,p,l);if(i&&y!==null){const ne=await I(d,l),B=await x(d,l);ne.heads_key===y&&B.length===1&&je(await me(d,l,O(B[0].body_hash)),a.replace)}const D=a.verbatim===!0,m=o?{body:a.body,verbatim:D}:{replace:a.replace,verbatim:D},h=await ce(d,p,l,m,a.rationale,y,r,await C(d));if("stale"in h)throw v(409,"stale_revision",`${g} changed after your read; it is now at revision ${h.stale.revision}`,`Read it again with \`crtr canvas read ${g}\`, then redo your change on the current text.`,{stale:h.stale});const F=O((await x(d,l))[0].body_hash);return{dto:{id:l.id,name:g,revision:h.revision,...await J(d,p,F,h.unresolved)},synced:A}}catch(y){S(y,l)}});return await T(w),c}u(De,"edit");async function Re(n){const e=R(n);if(e.new_name===void 0&&e.owner===void 0)throw b("give a new name, an owner, or both");if(e.new_name!==void 0&&(typeof e.new_name!="string"||!G.test(e.new_name)))throw b("`new_name` must be segments of letters, digits, `_` or `-` joined by `/`");const{dto:t,change:o}=await k(async i=>{const s=await E(i,n),r=await W(i,s,n.params.ref),f=e.owner===void 0?void 0:await M(i,s,e.owner,e.cwd);try{const a=await ue(i,s,r,{...e.new_name!==void 0?{name:e.new_name}:{},...f?{owner:f}:{}},await C(i));return{dto:{id:a.id,name:await j(i,a)},change:await N(i,s,[r,a],e.cwd)}}catch(a){S(a,r)}});return await T(o),t}u(Re,"move");async function Ce(n){const{dto:e,change:t}=await k(async o=>{const i=await E(o,n),s=await W(o,i,n.params.ref),r=await j(o,s),f=await N(o,i,[s]);try{await se(o,i,s,await C(o))}catch(a){S(a,s)}return{dto:{id:s.id,name:r},change:f}});return await T(t),e}u(Ce,"remove");async function Se(n){const e=n.query.get("diff"),t=e===null?void 0:Number(e);if(t!==void 0&&!(Number.isInteger(t)&&t>0))throw b("`diff` must be a revision number");return await k(async o=>{const i=await E(o,n),s=await X(o,i,decodeURIComponent(n.params.ref));if("remote"in s)throw v(404,"not_found",z(s.remote),"Check the name with `crtr canvas search`.");const r="deleted"in s?s.deleted:s;if(r.type!=="document")throw b(`${r.name} is a ${r.type}, not a document`);const f=await de(o,i,r),a={object:await Ee(o,r),revisions:f.map(c=>({rev_id:c.rev_id,number:c.number,author_id:c.author,rationale:c.rationale,verbatim:c.verbatim,created_at:c.created_at,parents:c.parents}))};if(t!==void 0){const c=f.find(d=>d.number===t);if(!c)throw new _(404,"not_found",`${r.name} has no revision ${t}`);const w=c.parents[0]===void 0?void 0:f.find(d=>d.rev_id===c.parents[0]);a.diff=ge(w?O(w.body_hash):"",O(c.body_hash))}return a})}u(Se,"revisionHistory");const Q=1e3,ee=1e3,te=3e3,Ne=/^When\b.+\bbecause\b.+/,Te=u(n=>{const e=n.trim();return e===""?0:e.split(/\s+/).length},"words");function Fe(n,e){if(n.some(o=>o.on==="boot"&&o.deliver==="content")&&e>Q)return`body is ${e} words, over the ${Q}-word cap for a boot rule at content (the whole body enters every node's context). Keep the core here and move separate subjects into [[linked]] documents.`;const t=[...new Set(n.filter(o=>o.on!=="boot"&&o.deliver==="content").map(o=>o.on))];return t.length>0&&e>ee?`body is ${e} words, over the ${ee}-word cap for a content rule on ${t.join("/")}. Keep the core here and move separate subjects into [[linked]] documents.`:n.some(o=>o.on==="boot"&&o.deliver==="preview")&&e>te?`body is ${e} words, over the ${te}-word cap for a boot rule at preview. Keep the core here and move separate subjects into [[linked]] documents.`:null}u(Fe,"lengthFinding");async function Ie(n){const e=R(n);return await k(async t=>{const o=await E(t,n),i=e.owner===void 0?null:await M(t,o,e.owner,e.cwd),s=await t.prepare("SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL AND home_machine IS NULL AND kind != 'report' ORDER BY name").all(),r=[],f=new Map;for(const a of s){if(i&&a.owner!==i.rowid||!await U(t,o,a))continue;const c=await I(t,a),w=new Set(c.lint_ignore??[]),d=await j(t,a),p=u((m,h,F)=>{w.has(m)||r.push({name:d,severity:h,rule:m,message:F})},"add"),l=await ve(t,a),g=(await x(t,a))[0],A=g?O(g.body_hash):"",y=Fe(l,Te(A));y&&p("length","error",y),l.some(m=>m.deliver==="preview")&&!Ne.test(a.preview??"")&&p("preview-shape","error",`a rule delivers this document at preview, so the preview must read "When <situation in the reader's work>, read this because <what the reader gains>"`);const D=new Set((await t.prepare("SELECT written_as FROM edges WHERE type = 'links-to' AND src = ?").all(a.rowid)).map(m=>m.written_as));for(const m of V(A)){if(D.has(m))continue;const h=await K(t,o,m);"remote"in h||"object"in h||"deleted"in h||p("links","warning",`[[${m}]] names no object in your view`)}if(l.some(m=>m.on==="workspace-open"&&m.deliver==="content")){const m=await ae(t,a);m.type==="repo"&&!w.has("workspace-open")&&f.set(m.name,[...f.get(m.name)??[],d])}}for(const[a,c]of f)if(!(c.length<2))for(const w of c)r.push({name:w,severity:"warning",rule:"workspace-open",message:`repo ${a} has ${c.length} documents delivered at content on workspace-open (${c.join(", ")}); keep one and link the rest from it`});return{findings:r}})}u(Ie,"lint");const $=u((n,e=200)=>async t=>({status:e,body:await n(t)}),"ok"),et=[{method:"POST",pattern:"/v1/docs",handler:$(Oe,201)},{method:"PATCH",pattern:"/v1/docs/:ref",handler:$(De)},{method:"POST",pattern:"/v1/docs/:ref/move",handler:$(Re)},{method:"DELETE",pattern:"/v1/docs/:ref",handler:$(Ce)},{method:"GET",pattern:"/v1/docs/:ref/history",handler:$(Se)},{method:"POST",pattern:"/v1/docs/lint",handler:$(Ie)}];export{j as canonicalName,et as docRoutes,N as repoChange,T as syncChanged};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var g=Object.defineProperty;var c=(
|
|
2
|
-
`).map(e=>`> ${e}`),"",
|
|
3
|
-
`)}c($,"renderCommentTurn");async function z(
|
|
1
|
+
var g=Object.defineProperty;var c=(n,t)=>g(n,"name",{value:t,configurable:!0});import{basename as y}from"node:path";import{ApiError as a}from"../../../api/index.js";import{createPageFeedbackComment as I,readPageFeedback as u,resolvePageFeedbackComment as q,PageFeedbackCommentAlreadyResolvedError as C,PageTicketTerminalError as k,UnknownPageFeedbackCommentError as T}from"../../../core/human/feedback.js";import{discardFeedbackCompanion as w,pageDocumentSha256 as P,realizeFeedbackCompanion as N}from"../../../core/human/feedback-companion.js";import{parsePage as S}from"../../../core/human/page.js";import{pageTicketState as F,selectedPageDir as E}from"../../../core/human/tickets.js";import{deliverNodeMessage as x}from"../../messaging/node-message.js";import{requireTicketId as D,resolveTicket as O}from"./inbox.js";import{invalidRequest as b,objectBody as p,optionalString as R,requiredString as l}from"./validate.js";import{toPageFeedbackDTO as h,toPageFeedbackCommentDTO as v}from"../map.js";const M=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;async function _(n){const t=D(n.params),e=await O(t);if(e===null)throw new a(404,"ticket_not_found","no matching ticket");if(e.kind==="review")throw new a(409,"ticket_kind_unsupported","review tickets have no feedback comments");const o=await F(e.dir);if(o==="resolved"||o==="canceled")throw new a(409,"ticket_terminal","ticket already has a terminal outcome");return e}c(_,"requireMutablePageTicket");function j(n){const t=n.comment_id;if(t===void 0||!M.test(t))throw new a(400,"invalid_request","invalid feedback comment id");return t}c(j,"requireCommentId");function $(n){return[...n.quote.split(`
|
|
2
|
+
`).map(e=>`> ${e}`),"",n.note].join(`
|
|
3
|
+
`)}c($,"renderCommentTurn");async function z(n){const t=n.mutation.feedback.companionNodeId;if(t===void 0)throw new a(500,"internal","feedback has comments but no companion conversation");try{const e=await x({node_id:t,body:$(n.mutation.comment),label:n.title,from:"human",mode:"interactive",data:{page_id:y(n.dir),comment_id:n.mutation.comment.id,verb:"create"}});return{target_node_id:t,status:"delivered",via:e.via,woke:e.revived,...e.reason===void 0?{}:{reason:e.reason}}}catch(e){return{target_node_id:t,status:"failed",woke:!1,error:e instanceof Error?e.message:String(e)}}}c(z,"deliverCommentTurn");function A(n){const t=[],e=p(n.body,["quote","context","note"],t),o=l(e,"quote",t),i=R(e,"context",t),d=l(e,"note",t);return(t.length>0||o===void 0||d===void 0)&&b("page feedback comment request",t),{quote:o,...i===void 0?{}:{context:i},note:d}}c(A,"parseCreate");async function B(n){const t=A(n),e=await _(n),o=S(await E(e.dir));if(o.dialect!=="jsx")throw new a(409,"page_dialect_unsupported","feedback comments exist only on TSX pages");let i=(await u(e.dir)).companionNodeId,d,s=!1;if(i===void 0){const m=o.source?.nodeId;if(m===void 0)throw new a(409,"ticket_has_no_sender","this page carries no sending node to deliver feedback to");d=await P(e.dir);try{i=await N({ticketId:e.ticketId,dir:e.dir,senderNodeId:m,title:o.title})}catch(f){throw new a(409,"fork_failed",`the sending node could not be forked: ${f instanceof Error?f.message:String(f)}`)}s=!0}let r;try{r=await I(e.dir,{...t,companionNodeId:i,firstCommentedSha256:d})}catch(m){throw s&&await w(i),m instanceof k?new a(409,"ticket_terminal","ticket already has a terminal outcome"):m}return s&&r.feedback.companionNodeId!==i&&await w(i),{status:200,body:{comment:v(r.comment),feedback:h(r.feedback),delivery:await z({dir:e.dir,title:o.title,mutation:r})}}}c(B,"handleCreate");function U(n){const t=[],e=p(n.body,["node_id"],t),o=l(e,"node_id",t);return(t.length>0||o===void 0)&&b("feedback resolve request",t),o}c(U,"parseResolve");async function X(n){const t=await _(n),e=j(n.params),o=U(n),i=(await u(t.dir)).companionNodeId;if(i===void 0||o!==i)throw new a(403,"not_companion","only the ticket's bound feedback companion resolves its comments");let d;try{d=await q(t.dir,e)}catch(r){throw r instanceof T?new a(404,"unknown_comment",r.message):r instanceof C?new a(409,"comment_already_resolved",r.message):r instanceof k?new a(409,"ticket_terminal","ticket already has a terminal outcome"):r}return{status:200,body:{comment:v(d.comment),feedback:h(d.feedback)}}}c(X,"handleResolve");const ne=[{method:"POST",pattern:"/v1/human/inbox/:ticket_id/feedback-comments",handler:B},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/feedback-comments/:comment_id/resolve",handler:X}];export{ne as feedbackCommentRoutes};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var q=Object.defineProperty;var o=(e,t)=>q(e,"name",{value:t,configurable:!0});import{closeSync as B,constants as T,fstatSync as v,readSync as R}from"node:fs";import{isAbsolute as I,relative as L,resolve as b,sep as F}from"node:path";import{filterAsync as M}from"../../../core/async-array.js";import{appSpace as g}from"../../../core/layout.js";import{ApiError as d}from"../../../api/index.js";import{notFound as E,usage as a}from"../../../core/errors.js";import{InputError as k}from"../../../core/io.js";import{RunError as p}from"../../../core/runs/operations.js";import{isBeneathRefusal as z,listBeneath as N,openBeneath as P,writeFileBeneath as O}from"../../../core/spaces/open-beneath.js";import{fileRoot as C}from"../../../core/spaces/permissions.js";import{nodeMayReach as D,runNodeIds as W,runPlace as Y}from"../../../core/runs/confinement.js";import{resolvedScopes as $}from"../router.js";const h=512*1024,S=1024*1024,Z=1e3;function y(e,t){if(e===null||e==="")throw a(`a file ${t} requires a \`path\` ${t==="write"?"body field":"query param"}`);if(!I(e))throw a(`file ${t} path must be absolute`,{received:e});return e}o(y,"requireAbsolutePath");function A(e){if(e==null)return"utf8";if(e==="utf8"||e==="base64")return e;throw a("encoding must be `utf8` or `base64`",{received:e})}o(A,"parseEncoding");function m(e,t,r){if(e instanceof d||e instanceof k||e instanceof p)throw e;if(z(e))throw new p(400,"invalid_request",`${t} meets a symlink, leaves its permitted root, or is not a regular file`,"path");const n=e.code;throw n==="ENOENT"?E(`no such file: ${t}`,{received:t}):n==="EACCES"||n==="EPERM"?new d(403,"forbidden",`permission denied ${r} ${t}`):new d(500,"internal",`cannot ${r} ${t}: ${e instanceof Error?e.message:String(e)}`)}o(m,"mapFilesystemError");async function _(e,t){const r=await Y(e);if(r?.isolated){const n=new Set(await W(r.run));return{isolated:!0,reaches:o(async i=>n.has(i),"reaches")}}return{isolated:!1,reaches:o(async n=>await D(e,t,n,t),"reaches")}}o(_,"runConfinement");async function j(e,t,r){const{isolated:n,reaches:i}=await _(e,t),[s,c]=L(g(t).root,b(r)).split(F),u=s==="nodes"&&c?await i(c):!1;return{isolated:n,reaches:o(()=>u,"reaches")}}o(j,"runConfinementFor");async function w(e,t,r){const n=e.principal;if(n.class==="forwarded"||n.class==="machine")throw new d(403,"permission_error","this operation is not available to the caller");const i=n.class==="person"?null:n.class==="app"?{app:n.app,resolved:n.scopes,launched:null}:n.class==="cron"?{app:n.app,resolved:await $(n),launched:n.scopes}:{app:n.app,resolved:await $(n),launched:n.scopes,run:await j(n.node,n.app,t)},s=C(i,t,r);if("root"in s)return s.root;throw"hidden"in s?E(`no such file: ${t}`,{received:t}):new p(403,"scope_missing",s.missing?`missing scope ${s.missing}`:`no permission names ${t}`,void 0,void 0,s.missing??void 0)}o(w,"rootFor");function G(e,t,r){let n;try{n=P(e,t,T.O_RDONLY)}catch(i){return m(i,t,"reading")}try{const i=v(n);if(i.isDirectory())throw a(`file peek path is a directory: ${t}`,{received:t});const s=Buffer.allocUnsafe(Math.min(i.size,h)+1),c=R(n,s,0,s.length,0),u=c>h,l=s.subarray(0,Math.min(c,h)).toString(r);return{path:t,content:l,truncated:u}}catch(i){return m(i,t,"reading")}finally{B(n)}}o(G,"readHead");async function U(e){const t=y(e.query.get("path"),"peek");return{status:200,body:G(await w(e,t,"read"),t,A(e.query.get("encoding")))}}o(U,"handlePeek");function X(e){return e.length%4===0&&/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(e)}o(X,"isBase64");function H(e){if(typeof e!="object"||e===null||Array.isArray(e))throw a("file write requires an object body");const t=e,r=y(typeof t.path=="string"?t.path:null,"write");if(typeof t.content!="string")throw a("file write requires a string `content` body field");const n=A(t.encoding);if(n==="base64"&&!X(t.content))throw a("base64 file content must be valid base64");return{path:r,content:t.content,encoding:n}}o(H,"parseWriteBody");function K(e,t,r){if(r.byteLength>S)throw new d(413,"file_too_large",`file content exceeds the ${S} byte limit`);try{return O(e,t,r,{mode:process.platform==="linux"?432:384,atomic:!0}),{path:t,bytes_written:r.byteLength}}catch(n){return m(n,t,"writing")}}o(K,"writeAtomically");async function J(e){const{path:t,content:r,encoding:n}=H(e.body);return{status:200,body:K(await w(e,t,"rw"),t,Buffer.from(r,n))}}o(J,"handleWrite");function Q(e){if(e===null)return Z;const t=Number(e);if(!Number.isInteger(t)||t<1)throw a("file list limit must be a positive integer",{received:e});return t}o(Q,"parseLimit");async function V(e){const t=y(e.query.get("path"),"list"),r=Q(e.query.get("limit")),n=await w(e,t,"read");let i;try{i=N(n,t,r+1)}catch(l){return m(l,t,"listing")}const s=e.principal;if(s.class==="broker"&&b(t)===g(s.app).nodes){const l=await _(s.node,s.app);i=await M(i,async({name:f})=>await l.reaches(f))}const c=i.slice(0,r).map(({name:l,stat:f})=>({name:l,type:f.isFile()?"file":f.isDirectory()?"dir":"other",size:f.size,modified:f.mtime.toISOString()}));return{status:200,body:{path:t,entries:c,truncated:i.length>r}}}o(V,"handleList");const ue=[{method:"GET",pattern:"/v1/files/peek",scope:"crtr:act",handler:U},{method:"POST",pattern:"/v1/files/write",scope:"crtr:act",handler:J},{method:"GET",pattern:"/v1/files/list",scope:"crtr:act",handler:V}];export{ue as fileRoutes};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var u=Object.defineProperty;var s=(n,e)=>u(n,"name",{value:e,configurable:!0});import{focusByPane as r,focusOf as a,listFocuses as d,registerViewerFocus as c}from"../../../core/runtime/placement.js";import{closeFocusRow as f,setFocusPane as p}from"../../../core/canvas/focuses.js";import{usage as o}from"../../../core/errors.js";import{ownerOnly as l}from"../router.js";function i(n){return n===null?null:{focus_id:n.focus_id,pane:n.pane,session:n.session,node_id:n.node_id}}s(i,"toFocusDTO");async function y(){return{status:200,body:(await d()).map(e=>i(e))}}s(y,"handleListFocuses");async function h(n){const e=n.query.get("node_id");if(e===null||e==="")throw o("focuses/by-node requires a node_id query param");return{status:200,body:i(await a(e))}}s(h,"handleFocusByNode");async function w(n){const e=n.query.get("pane");if(e===null||e==="")throw o("focuses/by-pane requires a pane query param");return{status:200,body:i(await r(e))}}s(w,"handleFocusByPane");function m(n){if(typeof n!="object"||n===null)throw o("register-focus body must be a JSON object");const e=n;if(typeof e.node_id!="string"||e.node_id==="")throw o("node_id is required");if(typeof e.pane!="string"||e.pane==="")throw o("pane is required");return{node_id:e.node_id,pane:e.pane,session:typeof e.session=="string"?e.session:null,window:typeof e.window=="string"?e.window:null}}s(m,"parseRegisterBody");async function _(n){const e=m(n.body),t=await c(e.node_id,e.pane,e.session,e.window);return{status:200,body:i(t)}}s(_,"handleRegisterFocus");function b(n){if(typeof n!="object"||n===null)throw o("set-focus-pane body must be a JSON object");const e=n;return{pane:typeof e.pane=="string"?e.pane:null,session:typeof e.session=="string"?e.session:null}}s(b,"parseSetPaneBody");async function g(n){const e=n.params.focus_id;if(e===void 0||e==="")throw o("focus_id is required");const t=b(n.body);return await p(e,t.pane,t.session),{status:204}}s(g,"handleSetFocusPane");async function q(n){const e=n.params.focus_id;if(e===void 0||e==="")throw o("focus_id is required");return await f(e),{status:204}}s(q,"handleCloseFocus");const O=l([{method:"GET",pattern:"/v1/focuses",handler:y},{method:"POST",pattern:"/v1/focuses",handler:_},{method:"GET",pattern:"/v1/focuses/by-node",handler:h},{method:"GET",pattern:"/v1/focuses/by-pane",handler:w},{method:"PATCH",pattern:"/v1/focuses/:focus_id",handler:g},{method:"DELETE",pattern:"/v1/focuses/:focus_id",handler:q}]);export{O as focusRoutes};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var
|
|
1
|
+
var i=Object.defineProperty;var e=(a,t)=>i(a,"name",{value:t,configurable:!0});import{openDb as n}from"../../../core/canvas/db.js";import{apiSocketPath as c}from"../../../core/canvas/paths.js";import{currentVersion as u}from"../../../core/self-update.js";import{API_VERSION as d}from"../../../api/index.js";import{DEFAULT_INTERVAL_MS as p}from"../../supervise-cadence.js";import{isPidPresent as l}from"../../../core/canvas/pid.js";import{boundDaemonControl as r}from"../../control.js";import{dueReport as _}from"../../due.js";import{runtimeReadiness as m}from"../../readiness.js";import{processGeneration as h}from"../../../commands/sys/shared.js";const w=p;async function s(){try{return await(await n()).prepare("SELECT 1 FROM nodes LIMIT 1").get(),!0}catch{return!1}}e(s,"canvasAccessible");async function f(){const a={},t=await(await n()).prepare(`
|
|
2
2
|
SELECT status, COUNT(*) AS count
|
|
3
3
|
FROM node_rows
|
|
4
4
|
WHERE node_id NOT IN (SELECT node_id FROM warm_pool)
|
|
5
5
|
GROUP BY status
|
|
6
|
-
`).all();for(const
|
|
6
|
+
`).all();for(const o of t)a[o.status]=o.count;return a}e(f,"nodeCounts");async function y(){return(await(await n()).prepare(`
|
|
7
7
|
SELECT pi_pid
|
|
8
8
|
FROM node_rows
|
|
9
9
|
WHERE node_id NOT IN (SELECT node_id FROM warm_pool)
|
|
@@ -11,4 +11,4 @@ var u=Object.defineProperty;var o=(e,t)=>u(e,"name",{value:t,configurable:!0});i
|
|
|
11
11
|
AND pi_pid IS NOT NULL
|
|
12
12
|
AND turn_open_at IS NOT NULL
|
|
13
13
|
AND turn_closed_at IS NULL
|
|
14
|
-
`).all().filter(t=>
|
|
14
|
+
`).all()).filter(t=>l(t.pi_pid)).length}e(y,"busyNodeCount");async function E(){const a=await s(),t=r()?.startupBlock()??null,o={ok:a&&t===null,daemon_up:!0,store_accessible:a,brokers_reconciled:t===null,startup_phase:t?.phase??"ready",...t===null?{}:{startup_blocked:t.message}};return{status:o.ok?200:503,body:o}}e(E,"handleHealthz");async function T(){const a=await m();return{status:a.ready?200:503,body:a}}e(T,"handleReady");async function b(a){if(!await s())throw{status:503,code:"store_unavailable",message:"canvas store is inaccessible"};return{status:200,body:{daemon_pid:process.pid,tick_interval_ms:w,node_counts:await f(),busy_node_count:await y(),listeners:{socket_path:c(),tcp:a()},runtime_version:u(),generation_id:h()?.id??null,api_version:d,startup_phase:r()?.startupBlock()?.phase??"ready"}}}e(b,"handleStatus");async function N(){if(!await s())throw{status:503,code:"store_unavailable",message:"canvas store is inaccessible"};return{status:200,body:await _()}}e(N,"handleDue");function g(a){return[{method:"GET",pattern:"/healthz",handler:e(async t=>await E(),"handler")},{method:"GET",pattern:"/v1/ready",handler:e(async t=>await T(),"handler")},{method:"GET",pattern:"/v1/status",handler:e(async t=>await b(a),"handler")},{method:"GET",pattern:"/v1/due",handler:e(async t=>await N(),"handler")}]}e(g,"healthRoutes");export{g as healthRoutes};
|