@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,4 +1,4 @@
|
|
|
1
|
-
var
|
|
1
|
+
var p=Object.defineProperty;var r=(i,n)=>p(i,"name",{value:n,configurable:!0});import{openDb as a}from"../canvas/db.js";import{runtimeId as m}from"../grants/sync.js";import{terminalGrant as h}from"../grants/mirror.js";async function E(i){const{caller:n}=i,e=n.sub??(n.class==="person"?(await h())?.sub??null:null),t=n.grantee??e,o=e&&t?[e,t,`runtime:${m()}`]:null;await(await a()).prepare(`INSERT INTO audit_rows
|
|
2
2
|
(request_id, time, grantee, sub, client_id, class, operation, scope_checked,
|
|
3
3
|
outcome, node_id, run_id, resource, initiator_chain, provider, tool, jti, receipt_id, responder, question_id)
|
|
4
|
-
VALUES (?, ?, ?, ?, ?, ?, 'provider.call', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(
|
|
4
|
+
VALUES (?, ?, ?, ?, ?, ?, 'provider.call', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(i.request_id,new Date().toISOString(),t,e,n.client_id,n.class,i.scope_checked??null,i.outcome,n.node_id,n.run_id,`${i.provider} ${i.tool}`,o?JSON.stringify(o):null,i.provider,i.tool,i.jti??null,i.receipt_id??null,i.responder??null,i.question_id??null)}r(E,"writeProviderAudit");async function I(i,n){const e=[],t=[];i!==null&&(e.push("grantee = ?"),t.push(i)),n.after!==void 0&&(e.push("id < ?"),t.push(n.after));for(const u of["operation","outcome","run_id"])n[u]!==void 0&&(e.push(`${u} = ?`),t.push(n[u]));n.since!==void 0&&(e.push("time >= ?"),t.push(n.since)),n.until!==void 0&&(e.push("time <= ?"),t.push(n.until));const o=await(await a()).prepareUncached(`SELECT * FROM audit_rows ${e.length?`WHERE ${e.join(" AND ")}`:""} ORDER BY id DESC LIMIT ?`).all(...t,n.limit+1),s=o.length>n.limit;s&&o.pop();const c=s?String(o.at(-1)?.id):null;return{rows:o.map(({id:u,initiator_chain:d,...l})=>({...l,initiator_chain:typeof d=="string"?JSON.parse(d):null})),next:c}}r(I,"listAudit");export{I as listAudit,E as writeProviderAudit};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var se=Object.defineProperty;var i=(e,n)=>se(e,"name",{value:n,configurable:!0});import{existsSync as
|
|
2
|
-
`),$(u(e,"bundle.tar"),{force:!0}),$(u(e,"etag"),{force:!0})}i(Pe,"retire");function ie(e,n){return new c("provider_version_retired",`provider "${e}" major ${n} is retired`,{param:"version"})}i(ie,"retiredError");async function H(e,n,r){const t=Y(e,n),o=u(t,"bundle.tar"),a=
|
|
1
|
+
var se=Object.defineProperty;var i=(e,n)=>se(e,"name",{value:n,configurable:!0});import{existsSync as g,readdirSync as z,readFileSync as S,rmSync as $,statSync as k}from"node:fs";import{join as u}from"node:path";import{validateCommandManifest as de}from"../../api/command-manifest/manifest.js";import{crtrHome as F}from"../canvas/paths.js";import{withCanvasWrite as G}from"../canvas/db.js";import{bundleVersion as ue,isInstalledGeneration as ce,recordCheckedGeneration as fe}from"../command-plugins/bundle.js";import{readConfig as q,readState as le,updateConfig as pe,updateState as me}from"../config.js";import{emitEvent as m}from"../events/emit.js";import{withExclusiveDirectoryLockAsync as V}from"../exclusive-lock.js";import{atomicWriteText as x,ensureDir as T,pathExists as ve}from"../fs-utils.js";import{reconcilePackages as Z}from"../graph/package-reconcile.js";import{readPluginManifest as C}from"../manifest.js";import{bundleSwapLockPath as L}from"../plugin-swap-lock.js";import{pluginsDir as he,userScopeRoot as J}from"../scope.js";import{listInstalledPlugins as we}from"../resolver.js";import{localGrants as j}from"../grants/mirror.js";import{ProviderError as c}from"./errors.js";const A="[A-Za-z0-9_-]{1,64}",ge=new RegExp(`^(${A}):(${A})$`),K=new RegExp(`^${A}$`),$e=3e4,Q=3e4;function X(e){const n=new Set;for(const r of e)if(r.status==="active")for(const{scope:t}of r.resolved_scopes){const o=ge.exec(t);o&&o[1]!=="crtr"&&n.add(o[1])}return[...n].sort()}i(X,"providerIdsFromGrants");function v(e){return u(he("user"),e)}i(v,"pluginRoot");function R(){return u(F(),"providers")}i(R,"providersRoot");function Y(e,n){return u(R(),e,`v${n}`)}i(Y,"majorDir");function B(e){if(!K.test(e))throw new c("not_found",`"${e}" is not a provider id`,{param:"provider"})}i(B,"assertId");function E(){const e=q("user").runtime?.issuer;if(!e)throw new c("not_found","provider bundles need a directory-connected runtime");return e.replace(/\/+$/,"")}i(E,"directoryBase");async function ee(e,n){const r=`${E()}/providers/${encodeURIComponent(e)}/plugin${n.version!==void 0?`?version=${n.version}`:""}`;let t;try{t=await fetch(r,{headers:{Accept:"application/x-tar",...n.ifNoneMatch!==void 0?{"If-None-Match":n.ifNoneMatch}:{}},signal:AbortSignal.timeout($e)})}catch(s){return{status:"failed",message:`could not reach ${r}: ${s instanceof Error?s.message:String(s)}`}}if(t.status===304)return n.ifNoneMatch===void 0?{status:"failed",message:`HTTP 304 from ${r} without a conditional request`}:{status:304};if(t.status===404||t.status===410)return await t.body?.cancel().catch(()=>{}),{status:t.status===404?404:410,message:`HTTP ${t.status} from ${r}`};if(t.status<200||t.status>=300)return await t.body?.cancel().catch(()=>{}),{status:"failed",message:`HTTP ${t.status} from ${r}`};let o;try{o=new Uint8Array(await t.arrayBuffer())}catch(s){return{status:"failed",message:`reading ${r} failed: ${s instanceof Error?s.message:String(s)}`}}const a=t.headers.get("etag");return{status:200,raw:o,...a!==null?{etag:a}:{}}}i(ee,"fetchProviderBundle");const I=new WeakSet;class M extends Error{static{i(this,"BundleInvalid")}issues;constructor(n,r){super(n),this.issues=r}}function ne(e,n,r){if(r.provider===void 0)return"the archive carries no provider block";if(r.provider.id!==e)return`the archive is provider "${r.provider.id}", not "${e}"`;if(n!==void 0&&r.provider.major!==n)return`the archive is major ${r.provider.major}, not ${n}`;const t=["hooks","kinds","page_components","memory_extensions"].filter(o=>r[o]!==void 0);if(t.length>0)return`a provider bundle may not carry ${t.join(", ")}`}i(ne,"wrongBundle");function D(e,n,r){m({level:"error",event:"daemon.providers.bundle_invalid",fields:{provider:e,...n!==void 0?{major:n}:{},...r instanceof M?{issues:r.issues}:{}},error:r})}i(D,"logInvalid");function re(e,n,r){m({level:"warn",event:"daemon.providers.bundle_fetch_failed",fields:{provider:e,...n!==void 0?{major:n}:{},message:r}})}i(re,"logFailure");async function te(){return import("../../commands/pkg/plugin-manage.js")}i(te,"pluginManage");const y=new Map,b=i(e=>`${F()}\0${e}`,"installKey");function ye(e){const n=e,r=n?.code??n?.cause?.code;return typeof r=="string"&&/^[A-Z][A-Z0-9_]{1,30}$/.test(r)?`${r} on provider install directory`:e instanceof c&&e.message.includes("HTTP 404")?"directory returned HTTP 404":e instanceof c&&e.message.includes("HTTP 410")?"directory returned HTTP 410":"provider bundle could not be installed"}i(ye,"publicInstallCause");function be(e){if(h(e)===void 0)return y.get(b(e))??{status:"installing"}}i(be,"providerInstallState");function _e(e){return new c("provider_unavailable",`provider "${e}" unavailable: ${be(e)?.error??"bundle installation pending"}`)}i(_e,"unavailableProviderError");function h(e){const n=C(v(e));if(!(n?.provider===void 0||n.transport?.kind!=="http"&&n.transport?.kind!=="machine")&&ve(u(v(e),"commands.json"))){try{if(k(u(v(e),"commands.json")).size===0)return}catch{return}return{provider:n.provider,transport:n.transport.kind==="machine"?{kind:"machine"}:{kind:"http",endpoint:n.transport.endpoint}}}}i(h,"installedManifest");async function N(e,n,r=!1){const t=J();h(e)===void 0&&y.set(b(e),{status:"installing"});try{return T(u(t,"tmp")),await V(L(t,e),async()=>{const o=v(e),a=C(o);if(a!==null&&a.provider===void 0)throw new c("provider_unavailable",`plugin "${e}" is installed and is not the directory's provider bundle`);const s=h(e)!==void 0;if(s&&r)return"unchanged";const f=s&&n?le("user").plugins[e]?.etag:void 0,d=await ee(e,f!==void 0?{ifNoneMatch:f}:{});if(d.status===304)return"unchanged";if(d.status===404||d.status===410)throw new c("not_found",`the directory serves no provider "${e}" (${d.message})`,{param:"provider"});if(d.status==="failed")throw new c("provider_unavailable",`provider "${e}" bundle fetch failed: ${d.message}`);const l=ue(d.raw);if(s&&ce(e,"user",o,l))return fe("user",e,d.etag,{swapped:!1}),"unchanged";const{installPluginArchive:w}=await te();try{await w(e,d.raw,{scope:"user",scopeRootPath:t,root:o,version:l,etag:d.etag,enable:!s,bundle:{endpoint:`${E()}/providers/${encodeURIComponent(e)}/plugin`},transport:{kind:"http",endpoint:E()},accept:i(p=>ne(e,void 0,p),"accept")})}catch(p){D(e,void 0,p);const W=new c("not_found",`provider "${e}" served an invalid bundle: ${p instanceof Error?p.message:String(p)}`,{param:"provider"});throw I.add(W),W}try{await G(async p=>await Z(p))}catch(p){m({level:"error",event:"daemon.providers.docs_reconcile_failed",fields:{provider:e},error:p})}return m({level:"info",event:"daemon.providers.bundle_installed",fields:{provider:e,version:l,replaced:s}}),y.delete(b(e)),s?"updated":"installed"},{timeoutMs:Q,timeoutError:i(()=>new c("provider_unavailable",`timed out waiting for another process replacing plugin "${e}"`),"timeoutError")})}catch(o){throw h(e)===void 0&&y.set(b(e),{status:"install_failed",error:ye(o)}),o instanceof c?o:(m({level:"error",event:"daemon.providers.bundle_install_failed",fields:{provider:e},error:o}),_e(e))}}i(N,"refreshInstalled");async function Je(e){B(e),h(e)===void 0&&await N(e,!1,!0)}i(Je,"ensureProviderBundle");async function Ke(e,n){return B(e),n.version!==void 0&&h(e)?.provider.major!==n.version?H(e,n.version,n.conditional):N(e,n.conditional)}i(Ke,"refreshProviderBundle");async function oe(e,n,r){const{validatePluginArchive:t}=await te(),o=await t(r);if(o.bundle===void 0)throw new M(`provider "${e}" major ${n} bundle is invalid: ${o.issues.map(s=>s.message).join("; ")}`,o.issues);const a=ne(e,n,o.bundle);if(a!==void 0)throw new M(`provider "${e}" major ${n} bundle is invalid: ${a}`,[]);if(o.bundle.transport===void 0)throw new M(`provider "${e}" major ${n} bundle declares no transport`,[]);return o.bundle}i(oe,"validateArchive");function Pe(e){T(e),x(u(e,"retired"),`${new Date().toISOString()}
|
|
2
|
+
`),$(u(e,"bundle.tar"),{force:!0}),$(u(e,"etag"),{force:!0})}i(Pe,"retire");function ie(e,n){return new c("provider_version_retired",`provider "${e}" major ${n} is retired`,{param:"version"})}i(ie,"retiredError");async function H(e,n,r){const t=Y(e,n),o=u(t,"bundle.tar"),a=g(o),s=a&&r&&g(u(t,"etag"))?S(u(t,"etag"),"utf8"):void 0,f=await ee(e,{version:n,...s!==void 0?{ifNoneMatch:s}:{}});if(f.status===304)return"unchanged";if(f.status===410)throw Pe(t),m({level:"info",event:"daemon.providers.major_retired",fields:{provider:e,major:n}}),ie(e,n);if(f.status===404)throw new c("not_found",`provider "${e}" never served major ${n}`,{param:"version"});if(f.status==="failed")throw new c("provider_unavailable",`provider "${e}" major ${n} bundle fetch failed: ${f.message}`);try{await oe(e,n,f.raw)}catch(l){D(e,n,l);const w=new c(a?"provider_unavailable":"not_found",l instanceof Error?l.message:String(l),{param:"version"});throw I.add(w),w}T(t),$(u(t,"retired"),{force:!0});const d=a&&Buffer.from(f.raw).equals(S(o));return d||x(o,f.raw),f.etag!==void 0?x(u(t,"etag"),f.etag):$(u(t,"etag"),{force:!0}),d?"unchanged":a?"updated":"installed"}i(H,"refreshPinned");function Se(){const e=[],n=R();if(!g(n))return e;for(const r of z(n)){if(!K.test(r))continue;let t;try{t=z(u(n,r))}catch{continue}for(const o of t){const a=/^v([1-9][0-9]*)$/.exec(o);a&&g(u(n,r,o,"bundle.tar"))&&e.push([r,Number(a[1])])}}return e}i(Se,"cachedMajors");function Ee(e){const n=de(e,{transport:"http",reservedCoreNames:new Set});if(n.manifest===void 0)throw new c("not_found","the provider bundle's commands.json no longer validates");return n.manifest}i(Ee,"readCommands");const _=new Map,O=new Map;function Ie(e,n){const r=k(n),t=`${r.ino}:${r.mtimeMs}:${r.size}`,o=O.get(e);if(o?.stamp===t)return o.commands;const a=Ee(JSON.parse(S(n,"utf8")));return O.set(e,{stamp:t,commands:a}),a}i(Ie,"installedCommands");async function Qe(e,n){B(e);const r=h(e);if(n===void 0||r?.provider.major===n){if(r===void 0)throw new c("not_found",`provider "${e}" has no installed bundle`,{param:"provider"});const l=v(e),w=Ie(e,u(l,"commands.json"));return{id:e,major:r.provider.major,provider:r.provider,commands:w,transport:r.transport,source:"installed",root:l}}if(!Number.isInteger(n)||n<1)throw new c("invalid_request","version must be an integer of at least 1",{param:"version"});const t=Y(e,n);if(g(u(t,"retired")))throw ie(e,n);const o=u(t,"bundle.tar");g(o)||await H(e,n,!1);const a=`${e}/${n}`,s=k(o),f=`${s.mtimeMs}:${s.size}`;let d=_.get(a)?.stamp===f?_.get(a).bundle:void 0;if(d===void 0){try{d=await oe(e,n,new Uint8Array(S(o)))}catch(l){throw D(e,n,l),new c("not_found",`provider "${e}" has no valid bundle for major ${n}`,{param:"version"})}_.set(a,{stamp:f,bundle:d})}return{id:e,major:n,provider:d.provider,commands:d.commands,transport:d.transport.kind==="machine"?{kind:"machine"}:{kind:"http",endpoint:d.transport.endpoint},source:"pinned"}}i(Qe,"resolveProviderBundle");let P=null,U=!1;function Me(e,n){return e?.provider?.id===n&&e.bundle?.endpoint===`${E()}/providers/${encodeURIComponent(n)}/plugin`}i(Me,"isDirectoryBundle");async function ae(e){return X(await j()).includes(e)}i(ae,"grantNames");async function ke(e){await V(L(J(),e),async()=>{if(!(await ae(e)||!Me(C(v(e)),e))){$(v(e),{recursive:!0,force:!0}),pe("user",n=>{delete n.plugins[e]}),me("user",n=>{delete n.plugins[e]}),$(u(R(),e),{recursive:!0,force:!0}),O.delete(e),y.delete(b(e));for(const n of[..._.keys()])n.startsWith(`${e}/`)&&_.delete(n);try{await G(async n=>await Z(n))}catch(n){m({level:"error",event:"daemon.providers.docs_reconcile_failed",fields:{provider:e},error:n})}m({level:"info",event:"daemon.providers.bundle_uninstalled",fields:{provider:e}})}},{timeoutMs:Q,timeoutError:i(()=>new c("provider_unavailable",`timed out waiting for another process replacing plugin "${e}"`),"timeoutError")})}i(ke,"uninstallProvider");async function xe(){if(!(await j()).every(e=>e.status!=="active")){for(const e of we("user"))if(!(e.manifest.provider===void 0||await ae(e.name)))try{await ke(e.name)}catch(n){m({level:"error",event:"daemon.providers.bundle_uninstall_failed",fields:{provider:e.name},error:n})}}}i(xe,"uninstallDisconnected");async function Te(){if(!q("user").runtime?.issuer)return;const e=X(await j());for(const n of e)try{await N(n,!0)}catch(r){r instanceof Object&&I.has(r)||re(n,void 0,r instanceof Error?r.message:String(r))}await xe();for(const[n,r]of Se())try{await H(n,r,!0)}catch(t){if(t instanceof c&&t.code==="provider_version_retired"||t instanceof Object&&I.has(t))continue;re(n,r,t instanceof Error?t.message:String(t))}}i(Te,"syncOnce");function Xe(){return P!==null?(U=!0,P):(P=(async()=>{try{do U=!1,await Te();while(U)}finally{P=null}})(),P)}i(Xe,"syncProviderBundles");export{Je as ensureProviderBundle,X as providerIdsFromGrants,be as providerInstallState,Ke as refreshProviderBundle,Qe as resolveProviderBundle,Xe as syncProviderBundles,_e as unavailableProviderError};
|
|
@@ -64,9 +64,9 @@ export interface ProviderResponseContext {
|
|
|
64
64
|
status: number;
|
|
65
65
|
headers: Record<string, string | string[] | undefined>;
|
|
66
66
|
}
|
|
67
|
-
export declare function onProviderResponse(context: ProviderResponseContext): string | undefined
|
|
67
|
+
export declare function onProviderResponse(context: ProviderResponseContext): Promise<string | undefined>;
|
|
68
68
|
export declare function mapProviderResponse(status: number, body: unknown, headers: Record<string, string | string[] | undefined>, approved?: boolean): ProviderError;
|
|
69
69
|
/** `Crtr-Caller` for a provider HTTP call: the calling node and run, that node's profile, and this machine once the runtime is joined (`ownMachineId`
|
|
70
70
|
* throws on an unjoined runtime). Empty fields are omitted; no field means no header. Never carries a token or scopes. */
|
|
71
|
-
export declare function crtrCallerHeader(caller: ProviderCaller): Record<string, string
|
|
71
|
+
export declare function crtrCallerHeader(caller: ProviderCaller): Promise<Record<string, string>>;
|
|
72
72
|
export declare function callProvider(caller: ProviderCaller, rawInput: ProviderCallInput, request: ProviderRequest): Promise<ProviderCallResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var re=Object.defineProperty;var v=(e,r)=>re(e,"name",{value:r,configurable:!0});import{validateDeclaredResult as I}from"../../api/command-manifest/result.js";import{callerAllows as te,requireGroup as oe}from"../../daemon/api/handlers/providers.js";import{terminalGrant as ne}from"../grants/mirror.js";import{UNCAPPED_GRANTEE as ie}from"../usage/ledger.js";import{listInstalledPlugins as se}from"../resolver.js";import{ProviderError as p}from"./errors.js";import{resolveProviderRef as ae}from"./roots.js";import{providerToolPath as de}from"../plugin-objects-manifest.js";import{ensureProviderBundle as ue,refreshProviderBundle as le,resolveProviderBundle as U,unavailableProviderError as pe}from"./bundles.js";import{prepareFileCall as ce,resignForRetry as G,resolveFileResult as z}from"./files.js";import{consumeApproval as fe,requireProviderApproval as me}from"./approval.js";import{outboundToken as ve}from"./mint.js";import{discardFile as ge}from"./token-cache.js";import{registerProviderCall as he}from"./inflight.js";import{buildRequestPlan as we}from"../command-plugins/transport/http-plan.js";import{sendProviderRequest as be,ProviderTransportError as ye}from"./request.js";import{acceptProviderReceipt as _e}from"./receipts.js";import{writeProviderAudit as Ae}from"./audit.js";import{selectDevice as je,sendDeviceCall as ke,deviceFailure as Pe,deviceUnreachable as Q,DEFAULT_DEVICE_REQUEST_MS as qe}from"./device.js";import{isLibsSearch as V,wantsBundling as Ee,callLibsSearch as $e,bundleExec as Ce,mapLibOutcome as Re,reportLibCalls as Se}from"./device-libs.js";import{directoryIssuer as Ne,ownMachineId as Te}from"../peer/directory.js";import{formatCrtrCaller as K}from"../command-plugins/caller-header.js";import{getNode as De}from"../canvas/canvas.js";import{envelopeForProviderCaller as Fe}from"../peer/envelope.js";function W(e){const r=[],s=v((c,t,o)=>{const a=[...t,c.name],d=o||c.tier==="hidden";if(c.kind==="branch"){for(const m of c.children)s(m,a,d);return}const A=de(e.roots.length,a);r.push({tool:A,leaf:c,hidden:d})},"walk");for(const c of e.roots)s(c,[],!1);return r}v(W,"providerLeaves");function X(e){if(e.kind!=="branch")return null;const r=[];for(const h of e.children)if(h.kind==="branch"){const j=X(h);j&&r.push(j)}else if("group"in h&&h.group){const{kind:j,name:u,description:_,whenToUse:g,tier:w,summary:P,params:n,output:k,effects:i,group:b}=h;r.push({kind:j,name:u,description:_,whenToUse:g,...w===void 0?{}:{tier:w},summary:P,params:n,output:k,effects:i,group:b})}if(r.length===0)return null;const{kind:s,name:c,description:t,whenToUse:o,tier:a,summary:d,model:A,rootEntry:m}=e;return{kind:s,name:c,description:t,whenToUse:o,...a===void 0?{}:{tier:a},summary:d,...A===void 0?{}:{model:A},...m===void 0?{}:{rootEntry:m},children:r}}v(X,"providerHelpBranch");async function mr(e,r){const s=await U(r),c=W(s.commands),t=se("user").find(o=>o.name===r)?.manifest.description??r;return{provider:r,status:"available",major:s.major,display_name:t,transport:s.transport.kind,groups:s.provider.groups.filter(o=>te(e,`${r}:${o.group}`)).map(o=>({group:o.group,leaves:c.filter(({leaf:a,hidden:d})=>!d&&a.group===o.group).map(({tool:a,leaf:d})=>({tool:a,description:d.description,summary:d.summary,params:d.params,output:d.output}))})),commands:s.commands.roots.flatMap(o=>{const a=X(o);return a?[a]:[]})}}v(mr,"providerTools");function Me(e){return _e(e.headers["crtr-receipt"],e)}v(Me,"onProviderResponse");function Oe(e){if(e.class==="person"){const r=ne()?.sub;if(!r)throw new p("grant_revoked","This machine has no active Northlight grant for your terminal. Run `crtr sys join` again from /account/machines.");return{sub:r,grantee:r}}if(!e.sub||!e.grantee)throw new p("grant_revoked","the caller has no active grant");return{sub:e.sub,grantee:e.grantee}}v(Oe,"identity");function Ie(e,r){return[`${e.id}:${r.group}`]}v(Ie,"callScope");function Ue(e,r){const s=W(e.commands).find(c=>c.tool===r);if(!s)throw new p("not_found",`tool "${r}" is not in provider "${e.id}"`,{param:"tool"});if(!s.leaf.group)throw new p("not_found",`tool "${r}" has no group`,{param:"tool"});return s.leaf}v(Ue,"leafFor");function B(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const r=e.error;return!r||typeof r!="object"||Array.isArray(r)?{}:r}v(B,"errorBody");function Be(e){const r=Array.isArray(e)?e[0]:e;if(!r)return;const s=Number(r);if(Number.isFinite(s)&&s>=0)return s;const c=Date.parse(r);return Number.isFinite(c)?Math.max(0,Math.ceil((c-Date.now())/1e3)):void 0}v(Be,"retryAfter");function D(e,r,s,c=!1){const t=B(r),o=typeof t.code=="string"?t.code:void 0,a=typeof t.message=="string"?t.message:`provider answered HTTP ${e}`,d=typeof t.field=="string"?t.field:void 0,m={origin:"provider",details:{code:o??null,message:a,...d?{field:d}:{},...typeof t.next=="string"?{next:t.next}:{},...t.received!==void 0?{received:t.received}:{},status:e},...d?{param:d}:{}};return e===429?new p("provider_rate_limited",a,{...m,retry_after_s:Be(s["retry-after"])}):e===401||e>=500?new p("provider_unavailable",a,m):e===403&&o==="provider_refused"?new p("provider_refused",a,m):e===403&&o==="approval_required"?new p("provider_error",c?"provider asked for approval again":"provider approval question is invalid",{...m,status:e}):new p("provider_error",a,{...m,status:e})}v(D,"mapProviderResponse");function Y(e,r){return JSON.stringify({major:e.major,endpoint:e.transport.kind==="http"?e.transport.endpoint:null,baseUrl:e.commands.baseUrl??null,rest:r.rest,params:r.params,output:r.output})}v(Y,"approvalShape");function Le(e){const r=e.origin!==void 0?K({node:e.origin.node??void 0,run:e.origin.run??void 0,machine:e.origin.machine}):K({node:e.node_id??void 0,run:e.run_id??void 0,profile:e.node_id?De(e.node_id)?.profile_id??void 0:void 0,machine:Ne()!==null?Te():void 0});return r===""?{}:{"Crtr-Caller":r}}v(Le,"crtrCallerHeader");async function vr(e,r,s){const c=ae(r.provider);if(c===null)throw new p("not_found",`provider "${r.provider}" is not available`,{param:"provider"});const t={...r,provider:c},o=new AbortController,a=v(()=>o.abort(s.signal.reason),"abort");s.signal.aborted?a():s.signal.addEventListener("abort",a,{once:!0});let d=s.requestId;const A=he({request_id:d,run_id:e.run_id,node_id:e.node_id,controller:o});let m,h,j,u,_,g,w,P="allowed";try{try{await ue(t.provider)}catch{throw pe(t.provider)}let n=await U(t.provider,t.version),k=!1,i,b,q,L=!1,J=!1,F,H=0;for(;;){const y=Ue(n,t.tool);if(j=`${n.id}:${y.group}`,oe(e,n.id,y.group),n.transport.kind!=="machine"&&t.machine!==void 0)throw new p("invalid_argument",`provider "${n.id}" is not served by a device, so it takes no machine`,{param:"machine"});n.transport.kind==="machine"&&F===void 0&&(F=await je(t.machine,void 0,{newest:V(n.major,t.tool)}),H=Date.now()+(n.commands.timeouts?.requestMs??qe));let M=null;if(t.approval&&!L){const l=fe(e,t,Y(n,y));q=l.option,M=l.prepared,w=t.approval,d=l.requestId,L=!0}const C={params:y.params.filter(l=>"type"in l&&l.type==="file").map(l=>l.name),output:y.output.find(l=>l.type==="file")?.name??null},x=JSON.stringify(C);if(b!==void 0&&b!==x)throw new p("provider_bad_response","the refreshed manifest changed the tool file contract",{origin:"provider",details:{status:409,message:"manifest_stale changed the tool file contract"}});b=x,M&&(i=await G(e,C,t.arguments,M,{signal:o.signal})),i??=await ce(e,C,t.arguments,{signal:o.signal});const{sub:O,grantee:R}=Oe(e);if(n.transport.kind==="machine"){const l=await Je(e,n,t,y,i,{sub:O,requestId:d,deadlineAt:H,signal:o.signal,machine:F});return g=l.responder,m=l.cleanup,{status:200,body:l.result}}const E=await ve({audience:n.transport.endpoint,sub:O,grantee:R,initiating_app:R,scope:Ie(n,y)},{signal:o.signal});u=E.jti;const Z={registration:{name:n.id,endpoint:n.transport.endpoint},...n.commands.baseUrl?{baseUrl:n.commands.baseUrl}:{},...n.commands.timeouts?{timeouts:n.commands.timeouts}:{},params:y.params,rest:y.rest,output:y.output,commandPath:[n.id,...t.tool.split(" ")]},ee=we(Z,i.arguments,void 0,{authorization:`Bearer ${E.access_token}`,requestId:d,fileMode:"pass-through",extraHeaders:{...e.run_id?{"Crtr-Run-Id":e.run_id}:{},...Le(e),...q?{"Crtr-Approval":q}:{},...i.headers}});h??=Date.now()+(n.commands.timeouts?.requestMs??3e4);let f;try{if(f=await be(ee,{connectMs:n.commands.timeouts?.connectMs,requestMs:n.commands.timeouts?.requestMs,deadlineAt:h,signal:o.signal}),o.signal.aborted)throw o.signal.reason??new Error("provider call aborted")}catch(l){throw o.signal.aborted?o.signal.reason??l:l instanceof ye?new p("provider_unavailable",l.message,{origin:"provider",details:{status:null,code:l.kind}}):l}if(_??=Me({provider:n.id,tool:t.tool,request_id:d,run_id:e.run_id,sub:O,grantee:R,payer:E.payer,ledger_grantee:e.class==="person"?ie:R,jti:E.jti,status:f.status,headers:f.headers}),g=f.headers["crtr-responder"],f.status===401&&ge(E.key),f.status>=200&&f.status<300){const l=f.body;if(!l||typeof l!="object"||Array.isArray(l))throw new p("provider_bad_response","provider result is not a JSON object",{origin:"provider",details:{status:f.status,message:"provider result is not a JSON object"}});let N;try{N=await z(e,i,l,{signal:o.signal})}catch($){throw $ instanceof p&&$.code==="provider_error"?new p("provider_bad_response",$.message,{origin:"provider",details:{status:f.status,message:$.message}}):$}m=N.cleanup;const T=I(y.output,N.result);if(T)throw new p("provider_bad_response",`provider result has an invalid output field "${T.field}"`,{origin:"provider",param:T.field,details:{status:f.status,...T}});if(o.signal.aborted)throw o.signal.reason??new Error("provider call aborted");return{status:200,body:N.result}}const S=B(f.body);if(f.status===403&&S.code==="approval_required"&&!q&&!J){J=!0;const l=await me(e,t,d,S.question,o.signal,Y(n,y),i);if(w=l.questionId,q=l.option,i=await G(e,C,t.arguments,i,{signal:o.signal}),h=void 0,o.signal.aborted)throw new p("user_denied","the approval wait was canceled");continue}if(f.status===403&&S.code==="approval_required"&&q)throw D(f.status,f.body,f.headers,!0);if(f.status!==401&&S.manifest_stale===!0&&!k){k=!0,await le(n.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}}),n=await U(n.id,t.version);continue}throw D(f.status,f.body,f.headers,!!q)}}catch(n){throw n instanceof p&&n.question_id&&(w=n.question_id),g===void 0&&n instanceof p&&typeof n.responder=="string"&&(g=n.responder),P=`refused:${n instanceof p?n.code:"server_error"}`,m?.(),n}finally{try{Ae({request_id:d,caller:e,provider:t.provider,tool:t.tool,scope_checked:j,outcome:P,jti:u,receipt_id:_,responder:g,question_id:w})}finally{A()}s.signal.removeEventListener("abort",a)}}v(vr,"callProvider");async function Je(e,r,s,c,t,o){const{machine:a}=o,d=Fe(e,o.sub),A={machine:a,envelope:d,signal:o.signal,deadlineAt:o.deadlineAt,mapFailure:D};if(V(r.major,s.tool)){const i=await $e(A,t.arguments,r.major),b=I(c.output,i);if(b)throw new p("provider_bad_response",`the libraries result has an invalid output field "${b.field}"`,{origin:"provider",param:b.field,details:{status:200,...b}});return{result:i,responder:void 0,cleanup:void 0}}let m=t.arguments,h=null,j="";if(Ee(r.major,s.tool,t.arguments)){const i=await Ce(A,t.arguments,r.major);if(o.deadlineAt-Date.now()<=0)throw Q(a,"timeout","");i!==null&&(m=i.arguments,h=i.services,j=i.release)}const u=await ke(a,{tool:s.tool,arguments:m,version:r.major,requestId:o.requestId,runId:e.run_id,deadlineAt:o.deadlineAt,upload:t.upload===null?null:{id:t.upload.upload_id,link:t.upload.upload_link}},d,o.signal);if(o.signal.aborted)throw o.signal.reason??new Error("provider call aborted");if("unreachable"in u)throw Q(a,u.unreachable.reason,u.unreachable.message);const _=u.headers["crtr-responder"],g=B(u.body);if(u.status<200||u.status>=300){const i=Pe(a,u.status,typeof g.code=="string"?g.code:void 0,typeof g.message=="string"?g.message:void 0,u.body),b=i===null&&u.status>=500&&typeof g.code=="string"?new p("provider_error",typeof g.message=="string"?g.message:`the device answered HTTP ${u.status}`,{origin:"runtime",status:u.status,details:{code:g.code,status:u.status}}):null;throw Object.assign(i??b??D(u.status,u.body,u.headers),{responder:_})}const w=u.body&&typeof u.body=="object"&&!Array.isArray(u.body)?u.body.result:void 0;if(!w||typeof w!="object"||Array.isArray(w))throw Object.assign(new p("provider_bad_response","the device result is not a JSON object",{origin:"provider",details:{status:u.status,message:"the device result is not a JSON object"}}),{responder:_});let P=w;if(h!==null){const i=Re(P,h);if(Se(a,d,j,i.calls),"error"in i)throw Object.assign(i.error,{responder:_});P=i.result}let n;try{n=await z(e,t,P,{signal:o.signal})}catch(i){throw i instanceof p&&i.code==="provider_error"?Object.assign(new p("provider_bad_response",i.message,{origin:"provider",details:{status:u.status,message:i.message}}),{responder:_}):i}const k=I(c.output,n.result);if(k)throw n.cleanup?.(),Object.assign(new p("provider_bad_response",`the device result has an invalid output field "${k.field}"`,{origin:"provider",param:k.field,details:{status:u.status,...k}}),{responder:_});return{result:n.result,responder:_,cleanup:n.cleanup}}v(Je,"callDevice");export{vr as callProvider,Le as crtrCallerHeader,D as mapProviderResponse,Me as onProviderResponse,W as providerLeaves,mr as providerTools};
|
|
1
|
+
var re=Object.defineProperty;var v=(e,r)=>re(e,"name",{value:r,configurable:!0});import{validateDeclaredResult as I}from"../../api/command-manifest/result.js";import{callerAllows as te,requireGroup as oe}from"../../daemon/api/handlers/providers.js";import{terminalGrant as ie}from"../grants/mirror.js";import{UNCAPPED_GRANTEE as ne}from"../usage/ledger.js";import{listInstalledPlugins as se}from"../resolver.js";import{ProviderError as p}from"./errors.js";import{resolveProviderRef as ae}from"./roots.js";import{providerToolPath as de}from"../plugin-objects-manifest.js";import{ensureProviderBundle as ue,refreshProviderBundle as le,resolveProviderBundle as U,unavailableProviderError as pe}from"./bundles.js";import{prepareFileCall as ce,resignForRetry as G,resolveFileResult as z}from"./files.js";import{consumeApproval as fe,requireProviderApproval as me}from"./approval.js";import{outboundToken as ve}from"./mint.js";import{discardFile as ge}from"./token-cache.js";import{registerProviderCall as he}from"./inflight.js";import{buildRequestPlan as we}from"../command-plugins/transport/http-plan.js";import{sendProviderRequest as be,ProviderTransportError as ye}from"./request.js";import{acceptProviderReceipt as _e}from"./receipts.js";import{writeProviderAudit as Ae}from"./audit.js";import{selectDevice as je,sendDeviceCall as ke,deviceFailure as Pe,deviceUnreachable as Q,DEFAULT_DEVICE_REQUEST_MS as qe}from"./device.js";import{isLibsSearch as V,wantsBundling as Ee,callLibsSearch as $e,bundleExec as Ce,mapLibOutcome as Re,reportLibCalls as Se}from"./device-libs.js";import{directoryIssuer as Ne,ownMachineId as Te}from"../peer/directory.js";import{formatCrtrCaller as K}from"../command-plugins/caller-header.js";import{getNode as De}from"../canvas/canvas.js";import{envelopeForProviderCaller as Fe}from"../peer/envelope.js";function W(e){const r=[],s=v((c,t,o)=>{const a=[...t,c.name],d=o||c.tier==="hidden";if(c.kind==="branch"){for(const m of c.children)s(m,a,d);return}const A=de(e.roots.length,a);r.push({tool:A,leaf:c,hidden:d})},"walk");for(const c of e.roots)s(c,[],!1);return r}v(W,"providerLeaves");function X(e){if(e.kind!=="branch")return null;const r=[];for(const h of e.children)if(h.kind==="branch"){const j=X(h);j&&r.push(j)}else if("group"in h&&h.group){const{kind:j,name:u,description:_,whenToUse:g,tier:w,summary:P,params:i,output:k,effects:n,group:b}=h;r.push({kind:j,name:u,description:_,whenToUse:g,...w===void 0?{}:{tier:w},summary:P,params:i,output:k,effects:n,group:b})}if(r.length===0)return null;const{kind:s,name:c,description:t,whenToUse:o,tier:a,summary:d,model:A,rootEntry:m}=e;return{kind:s,name:c,description:t,whenToUse:o,...a===void 0?{}:{tier:a},summary:d,...A===void 0?{}:{model:A},...m===void 0?{}:{rootEntry:m},children:r}}v(X,"providerHelpBranch");async function mr(e,r){const s=await U(r),c=W(s.commands),t=se("user").find(o=>o.name===r)?.manifest.description??r;return{provider:r,status:"available",major:s.major,display_name:t,transport:s.transport.kind,groups:s.provider.groups.filter(o=>te(e,`${r}:${o.group}`)).map(o=>({group:o.group,leaves:c.filter(({leaf:a,hidden:d})=>!d&&a.group===o.group).map(({tool:a,leaf:d})=>({tool:a,description:d.description,summary:d.summary,params:d.params,output:d.output}))})),commands:s.commands.roots.flatMap(o=>{const a=X(o);return a?[a]:[]})}}v(mr,"providerTools");async function Me(e){return await _e(e.headers["crtr-receipt"],e)}v(Me,"onProviderResponse");async function Oe(e){if(e.class==="person"){const r=(await ie())?.sub;if(!r)throw new p("grant_revoked","This machine has no active Northlight grant for your terminal. Run `crtr sys join` again from /account/machines.");return{sub:r,grantee:r}}if(!e.sub||!e.grantee)throw new p("grant_revoked","the caller has no active grant");return{sub:e.sub,grantee:e.grantee}}v(Oe,"identity");function Ie(e,r){return[`${e.id}:${r.group}`]}v(Ie,"callScope");function Ue(e,r){const s=W(e.commands).find(c=>c.tool===r);if(!s)throw new p("not_found",`tool "${r}" is not in provider "${e.id}"`,{param:"tool"});if(!s.leaf.group)throw new p("not_found",`tool "${r}" has no group`,{param:"tool"});return s.leaf}v(Ue,"leafFor");function B(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const r=e.error;return!r||typeof r!="object"||Array.isArray(r)?{}:r}v(B,"errorBody");function Be(e){const r=Array.isArray(e)?e[0]:e;if(!r)return;const s=Number(r);if(Number.isFinite(s)&&s>=0)return s;const c=Date.parse(r);return Number.isFinite(c)?Math.max(0,Math.ceil((c-Date.now())/1e3)):void 0}v(Be,"retryAfter");function D(e,r,s,c=!1){const t=B(r),o=typeof t.code=="string"?t.code:void 0,a=typeof t.message=="string"?t.message:`provider answered HTTP ${e}`,d=typeof t.field=="string"?t.field:void 0,m={origin:"provider",details:{code:o??null,message:a,...d?{field:d}:{},...typeof t.next=="string"?{next:t.next}:{},...t.received!==void 0?{received:t.received}:{},status:e},...d?{param:d}:{}};return e===429?new p("provider_rate_limited",a,{...m,retry_after_s:Be(s["retry-after"])}):e===401||e>=500?new p("provider_unavailable",a,m):e===403&&o==="provider_refused"?new p("provider_refused",a,m):e===403&&o==="approval_required"?new p("provider_error",c?"provider asked for approval again":"provider approval question is invalid",{...m,status:e}):new p("provider_error",a,{...m,status:e})}v(D,"mapProviderResponse");function Y(e,r){return JSON.stringify({major:e.major,endpoint:e.transport.kind==="http"?e.transport.endpoint:null,baseUrl:e.commands.baseUrl??null,rest:r.rest,params:r.params,output:r.output})}v(Y,"approvalShape");async function Le(e){const r=e.origin!==void 0?K({node:e.origin.node??void 0,run:e.origin.run??void 0,machine:e.origin.machine}):K({node:e.node_id??void 0,run:e.run_id??void 0,profile:e.node_id?(await De(e.node_id))?.profile_id??void 0:void 0,machine:Ne()!==null?Te():void 0});return r===""?{}:{"Crtr-Caller":r}}v(Le,"crtrCallerHeader");async function vr(e,r,s){const c=ae(r.provider);if(c===null)throw new p("not_found",`provider "${r.provider}" is not available`,{param:"provider"});const t={...r,provider:c},o=new AbortController,a=v(()=>o.abort(s.signal.reason),"abort");s.signal.aborted?a():s.signal.addEventListener("abort",a,{once:!0});let d=s.requestId;const A=he({request_id:d,run_id:e.run_id,node_id:e.node_id,controller:o});let m,h,j,u,_,g,w,P="allowed";try{try{await ue(t.provider)}catch{throw pe(t.provider)}let i=await U(t.provider,t.version),k=!1,n,b,q,L=!1,J=!1,F,H=0;for(;;){const y=Ue(i,t.tool);if(j=`${i.id}:${y.group}`,oe(e,i.id,y.group),i.transport.kind!=="machine"&&t.machine!==void 0)throw new p("invalid_argument",`provider "${i.id}" is not served by a device, so it takes no machine`,{param:"machine"});i.transport.kind==="machine"&&F===void 0&&(F=await je(t.machine,void 0,{newest:V(i.major,t.tool)}),H=Date.now()+(i.commands.timeouts?.requestMs??qe));let M=null;if(t.approval&&!L){const l=await fe(e,t,Y(i,y));q=l.option,M=l.prepared,w=t.approval,d=l.requestId,L=!0}const C={params:y.params.filter(l=>"type"in l&&l.type==="file").map(l=>l.name),output:y.output.find(l=>l.type==="file")?.name??null},x=JSON.stringify(C);if(b!==void 0&&b!==x)throw new p("provider_bad_response","the refreshed manifest changed the tool file contract",{origin:"provider",details:{status:409,message:"manifest_stale changed the tool file contract"}});b=x,M&&(n=await G(e,C,t.arguments,M,{signal:o.signal})),n??=await ce(e,C,t.arguments,{signal:o.signal});const{sub:O,grantee:R}=await Oe(e);if(i.transport.kind==="machine"){const l=await Je(e,i,t,y,n,{sub:O,requestId:d,deadlineAt:H,signal:o.signal,machine:F});return g=l.responder,m=l.cleanup,{status:200,body:l.result}}const E=await ve({audience:i.transport.endpoint,sub:O,grantee:R,initiating_app:R,scope:Ie(i,y)},{signal:o.signal});u=E.jti;const Z={registration:{name:i.id,endpoint:i.transport.endpoint},...i.commands.baseUrl?{baseUrl:i.commands.baseUrl}:{},...i.commands.timeouts?{timeouts:i.commands.timeouts}:{},params:y.params,rest:y.rest,output:y.output,commandPath:[i.id,...t.tool.split(" ")]},ee=we(Z,n.arguments,void 0,{authorization:`Bearer ${E.access_token}`,requestId:d,fileMode:"pass-through",extraHeaders:{...e.run_id?{"Crtr-Run-Id":e.run_id}:{},...await Le(e),...q?{"Crtr-Approval":q}:{},...n.headers}});h??=Date.now()+(i.commands.timeouts?.requestMs??3e4);let f;try{if(f=await be(ee,{connectMs:i.commands.timeouts?.connectMs,requestMs:i.commands.timeouts?.requestMs,deadlineAt:h,signal:o.signal}),o.signal.aborted)throw o.signal.reason??new Error("provider call aborted")}catch(l){throw o.signal.aborted?o.signal.reason??l:l instanceof ye?new p("provider_unavailable",l.message,{origin:"provider",details:{status:null,code:l.kind}}):l}if(_??=await Me({provider:i.id,tool:t.tool,request_id:d,run_id:e.run_id,sub:O,grantee:R,payer:E.payer,ledger_grantee:e.class==="person"?ne:R,jti:E.jti,status:f.status,headers:f.headers}),g=f.headers["crtr-responder"],f.status===401&&ge(E.key),f.status>=200&&f.status<300){const l=f.body;if(!l||typeof l!="object"||Array.isArray(l))throw new p("provider_bad_response","provider result is not a JSON object",{origin:"provider",details:{status:f.status,message:"provider result is not a JSON object"}});let N;try{N=await z(e,n,l,{signal:o.signal})}catch($){throw $ instanceof p&&$.code==="provider_error"?new p("provider_bad_response",$.message,{origin:"provider",details:{status:f.status,message:$.message}}):$}m=N.cleanup;const T=I(y.output,N.result);if(T)throw new p("provider_bad_response",`provider result has an invalid output field "${T.field}"`,{origin:"provider",param:T.field,details:{status:f.status,...T}});if(o.signal.aborted)throw o.signal.reason??new Error("provider call aborted");return{status:200,body:N.result}}const S=B(f.body);if(f.status===403&&S.code==="approval_required"&&!q&&!J){J=!0;const l=await me(e,t,d,S.question,o.signal,Y(i,y),n);if(w=l.questionId,q=l.option,n=await G(e,C,t.arguments,n,{signal:o.signal}),h=void 0,o.signal.aborted)throw new p("user_denied","the approval wait was canceled");continue}if(f.status===403&&S.code==="approval_required"&&q)throw D(f.status,f.body,f.headers,!0);if(f.status!==401&&S.manifest_stale===!0&&!k){k=!0,await le(i.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}}),i=await U(i.id,t.version);continue}throw D(f.status,f.body,f.headers,!!q)}}catch(i){throw i instanceof p&&i.question_id&&(w=i.question_id),g===void 0&&i instanceof p&&typeof i.responder=="string"&&(g=i.responder),P=`refused:${i instanceof p?i.code:"server_error"}`,await m?.(),i}finally{try{await Ae({request_id:d,caller:e,provider:t.provider,tool:t.tool,scope_checked:j,outcome:P,jti:u,receipt_id:_,responder:g,question_id:w})}finally{A()}s.signal.removeEventListener("abort",a)}}v(vr,"callProvider");async function Je(e,r,s,c,t,o){const{machine:a}=o,d=await Fe(e,o.sub),A={machine:a,envelope:d,signal:o.signal,deadlineAt:o.deadlineAt,mapFailure:D};if(V(r.major,s.tool)){const n=await $e(A,t.arguments,r.major),b=I(c.output,n);if(b)throw new p("provider_bad_response",`the libraries result has an invalid output field "${b.field}"`,{origin:"provider",param:b.field,details:{status:200,...b}});return{result:n,responder:void 0,cleanup:void 0}}let m=t.arguments,h=null,j="";if(Ee(r.major,s.tool,t.arguments)){const n=await Ce(A,t.arguments,r.major);if(o.deadlineAt-Date.now()<=0)throw Q(a,"timeout","");n!==null&&(m=n.arguments,h=n.services,j=n.release)}const u=await ke(a,{tool:s.tool,arguments:m,version:r.major,requestId:o.requestId,runId:e.run_id,deadlineAt:o.deadlineAt,upload:t.upload===null?null:{id:t.upload.upload_id,link:t.upload.upload_link}},d,o.signal);if(o.signal.aborted)throw o.signal.reason??new Error("provider call aborted");if("unreachable"in u)throw Q(a,u.unreachable.reason,u.unreachable.message);const _=u.headers["crtr-responder"],g=B(u.body);if(u.status<200||u.status>=300){const n=Pe(a,u.status,typeof g.code=="string"?g.code:void 0,typeof g.message=="string"?g.message:void 0,u.body),b=n===null&&u.status>=500&&typeof g.code=="string"?new p("provider_error",typeof g.message=="string"?g.message:`the device answered HTTP ${u.status}`,{origin:"runtime",status:u.status,details:{code:g.code,status:u.status}}):null;throw Object.assign(n??b??D(u.status,u.body,u.headers),{responder:_})}const w=u.body&&typeof u.body=="object"&&!Array.isArray(u.body)?u.body.result:void 0;if(!w||typeof w!="object"||Array.isArray(w))throw Object.assign(new p("provider_bad_response","the device result is not a JSON object",{origin:"provider",details:{status:u.status,message:"the device result is not a JSON object"}}),{responder:_});let P=w;if(h!==null){const n=Re(P,h);if(Se(a,d,j,n.calls),"error"in n)throw Object.assign(n.error,{responder:_});P=n.result}let i;try{i=await z(e,t,P,{signal:o.signal})}catch(n){throw n instanceof p&&n.code==="provider_error"?Object.assign(new p("provider_bad_response",n.message,{origin:"provider",details:{status:u.status,message:n.message}}),{responder:_}):n}const k=I(c.output,i.result);if(k)throw await i.cleanup?.(),Object.assign(new p("provider_bad_response",`the device result has an invalid output field "${k.field}"`,{origin:"provider",param:k.field,details:{status:u.status,...k}}),{responder:_});return{result:i.result,responder:_,cleanup:i.cleanup}}v(Je,"callDevice");export{vr as callProvider,Le as crtrCallerHeader,D as mapProviderResponse,Me as onProviderResponse,W as providerLeaves,mr as providerTools};
|
|
@@ -57,7 +57,7 @@ export interface ResolvedFileResult {
|
|
|
57
57
|
upload_id: string;
|
|
58
58
|
} | null;
|
|
59
59
|
/** Remove what this resolve wrote (for a failure after it). Idempotent. */
|
|
60
|
-
cleanup: () => void
|
|
60
|
+
cleanup: () => Promise<void>;
|
|
61
61
|
}
|
|
62
62
|
/** The fetch of a file result is bounded like an attachment fetch. */
|
|
63
63
|
export declare const FILE_RESULT_FETCH_BUDGET_MS = 110000;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var te=Object.defineProperty;var d=(e,t)=>te(e,"name",{value:t,configurable:!0});import{
|
|
1
|
+
var te=Object.defineProperty;var d=(e,t)=>te(e,"name",{value:t,configurable:!0});import{createHash as oe}from"node:crypto";import{closeSync as D,constants as ne,createWriteStream as ie}from"node:fs";import{basename as re,extname as ae,isAbsolute as se,join as F}from"node:path";import{Transform as de}from"node:stream";import{pipeline as ue}from"node:stream/promises";import{appSpace as I}from"../layout.js";import{RunError as T}from"../runs/operations.js";import{createFileBeneath as ce,existsBeneath as M,openBeneath as le,removeTreeBeneath as N,setModeBeneath as fe,unlinkBeneath as pe,withDirBeneath as he}from"../spaces/open-beneath.js";import{ensureAppSpace as we}from"../spaces/space.js";import{invalidStorageName as H,storageClient as B,StorageRefused as U,UPLOAD_MAX_BYTES as C}from"../storage/client.js";import{contentTypeFor as _e,openCallerFile as me}from"../storage/download.js";import{withCanvasWrite as ge}from"../canvas/db.js";import{deleteUploadUse as ye,getUpload as be,insertUpload as $e,insertUploadUses as Se,setUploadSize as ve,uploadUseAt as Ue}from"../storage/tables.js";import{ProviderError as c}from"./errors.js";const ze=11e4,Ee="app:terminal";function P(e){if(e.class==="person")return e.grantee??Ee;if(!e.grantee)throw new c("server_error","provider caller has no grantee");return e.grantee}d(P,"grantee");function Ae(e){return e.class==="person"?null:{app:P(e),resolved:e.resolved??[],launched:e.class==="broker"?e.nodeScopes:null}}d(Ae,"fileCaller");function y(e){return e instanceof c?e:e instanceof U?new c("storage_unavailable",`storage refused: ${e.message}`):e instanceof T&&e.code==="storage_unavailable"?new c("storage_unavailable",e.message):e}d(y,"storageFailure");const b=d(e=>new c("provider_error",e,{origin:"provider"}),"providerError");function Fe(e,t,n){if(typeof n!="string"||!n||!se(n)||n.includes("\0"))throw new c("invalid_request",`${t} must be an absolute runtime path`,{param:t});let r;try{r=me(Ae(e),n)}catch(i){throw i instanceof T?i.code==="scope_missing"?new c("scope_missing",i.message,{param:t,...i.scope?{scope:i.scope}:{}}):i.code==="not_found"||i.code==="invalid_request"?new c("not_found",`no such file: ${n}`,{param:t}):i:i}try{if(r.size>C)throw new c("invalid_request",`${t} exceeds 100 MiB`,{param:t});const i=re(r.path),o=H(i);if(o)throw new c("invalid_request",`${t}: file name cannot be sent: ${o}`,{param:t});return{param:t,file:r,name:i,mediaType:_e(r.path)}}catch(i){throw D(r.fd),i}}d(Fe,"checkFileArgument");async function Te(e,t){try{const n=await e.createOutbound({name:t.name,size:t.file.size,media_type:t.mediaType});await e.putFileBytes(n.upload_link,t.file.fd,t.file.size,t.mediaType);const r=await e.signOutbound(n.object_id);return{param:t.param,path:t.file.path,name:t.name,object_id:n.object_id,url:r.url}}catch(n){throw y(n)}}d(Te,"copyOutbound");async function k(e,t,n,r){const i=[];try{for(const a of t)n[a]===void 0||n[a]===null||i.push(Fe(e,a,n[a]));if(!i.length)return[];let o;try{o=r()}catch(a){throw y(a)}const l=[];for(const a of i)l.push(await Te(o,a));return l}finally{for(const o of i)D(o.file.fd)}}d(k,"copyArguments");function q(e){const t=H(e);if(t)throw new c("server_error",`file output ${e} cannot name an upload: ${t}`)}d(q,"checkOutputField");async function W(e,t,n){q(t);const r=P(e),i="application/octet-stream";let o;try{o=await n().createResultUpload({name:t,media_type:i,max_size:C})}catch(l){throw y(l)}return await $e({upload_id:o.upload_id,grantee:r,name:t,media_type:i,size:C,created_at:new Date().toISOString()}),{field:t,upload_id:o.upload_id,upload_link:o.upload_link,grantee:r}}d(W,"createResultUpload");function X(e){return e?{"Crtr-Upload-Id":e.upload_id,"Crtr-Upload-Link":e.upload_link}:{}}d(X,"uploadHeaders");function Y(e,t){const n={...e};for(const r of t)n[r.param]=r.url;return n}d(Y,"withUrls");async function Ye(e,t,n,r={}){const i=r.storage??B;t.output&&q(t.output);const o=await k(e,t.params,n,i),l=t.output?await W(e,t.output,i):null;return{arguments:Y(n,o),copies:o,upload:l,headers:X(l)}}d(Ye,"prepareFileCall");async function Ge(e,t,n,r,i={}){const o=i.storage??B,l=[];for(const s of r.copies)try{const p=await o().signOutbound(s.object_id);l.push({...s,url:p.url})}catch(p){if(!(p instanceof U))throw y(p);l.push(...await k(e,[s.param],n,o))}let a=r.upload;if(a)try{const s=await o().signUploadLink(a.upload_id);a={...a,upload_link:s.upload_link}}catch(s){if(!(s instanceof U))throw y(s);s.status===404&&(a=await W(e,t.output??a.field,o))}return{arguments:Y(n,l),copies:l,upload:a,headers:X(a)}}d(Ge,"resignForRetry");const Be=/^[0-9a-f]{64}$/i;function Ce(e,t){if(t===1)return e;const n=ae(e);return n&&n!==e?`${e.slice(0,-n.length)}-${t}${n}`:`${e}-${t}`}d(Ce,"candidate");async function Je(e,t,n,r={}){const i={result:n,file:null,cleanup:d(async()=>{},"cleanup")},o=t.upload;if(!o||!n||typeof n!="object"||Array.isArray(n))return i;const l=n,a=l[o.field];if(a==null)return i;if(typeof a!="object"||Array.isArray(a))throw b(`${o.field} must be {upload_id, size, sha256}`);const s=a;if(typeof s.upload_id!="string"||typeof s.size!="number"||!Number.isSafeInteger(s.size)||s.size<0||typeof s.sha256!="string"||!Be.test(s.sha256))throw b(`${o.field} must be {upload_id, size, sha256}`);if(s.upload_id!==o.upload_id)throw b(`${o.field} names an upload other than Crtr-Upload-Id`);const p=s.size,G=s.sha256.toLowerCase(),z=AbortSignal.timeout(r.budgetMs??ze),O=r.signal?AbortSignal.any([z,r.signal]):z;let h;try{h=await(r.storage??B)().fetchUpload(o.upload_id,O)}catch(_){throw _ instanceof U?b(`${o.field} names an upload with nothing stored`):y(_)}if(h.size===null)throw h.body.destroy(),new c("storage_unavailable",`storage did not say how many bytes ${o.field} holds`);if(h.size!==p)throw h.body.destroy(),b(`${o.field} claims ${p} bytes; storage holds ${h.size}`);const E=o.grantee,$=e.node_id!==null,J=await we(E),f=$?I(E).nodes:I(E).files,A=$?F(f,e.node_id):f,S=$?F(A,"attachments"):f,K={uid:process.getuid?.()??0,gid:J.gid},R=$&&!M(f,A),Q=$&&!R&&!M(f,S);let w=null,v=null,x=!1;const L=d(async()=>{if(!x){if(x=!0,v)try{await ye(v)}catch{}if(w)try{pe(f,w)}catch{}try{R?N(f,A):Q&&N(f,S)}catch{}}},"cleanup");try{he(f,S,()=>{},!0);for(let u=1;;u++){const m=F(S,Ce(o.field,u));if(!await Ue(m))try{ce(f,m,Buffer.alloc(0),432),w=m;break}catch(g){if(g.code!=="EEXIST")throw g}}let _=0;const j=oe("sha256"),V=new de({transform(u,m,g){_+=u.length,j.update(u),g(null,u)}}),Z=le(f,w,ne.O_WRONLY);try{await ue(h.body,V,ie("",{fd:Z,autoClose:!0}),{signal:O})}catch(u){throw z.aborted?new c("storage_unavailable","the file result could not be fetched within 110 s"):u instanceof T?y(u):new c("storage_unavailable",`storage stopped sending ${o.field}: ${u instanceof Error?u.message:String(u)}`)}if(_!==p)throw new c("storage_unavailable",`storage sent ${_} of ${p} bytes of ${o.field}`);if(j.digest("hex")!==G)throw b(`${o.field}: the stored bytes do not match sha256`);fe(f,w,432,K);const ee=w;await ge(async u=>{const m=await be(o.upload_id,u);if(!m||m.delete_pending_since)throw new c("not_found",`${o.field}: the upload was deleted while it was fetched`);if(await ve(o.upload_id,p,u),!e.run_id)return;const g=await u.prepare("SELECT deleting_at FROM nodes WHERE node_id = ?").get(e.run_id);if(!g||g.deleting_at)throw new c("not_found",`run ${e.run_id} was deleted while its file result was fetched`);v={upload_id:o.upload_id,run_id:e.run_id,path:ee},await Se([v],u)})}catch(_){throw h.body.destroy(),await L(),_}return{result:{...l,[o.field]:w},file:{path:w,upload_id:o.upload_id},cleanup:L}}d(Je,"resolveFileResult");export{ze as FILE_RESULT_FETCH_BUDGET_MS,Ye as prepareFileCall,Ge as resignForRetry,Je as resolveFileResult};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var T=Object.defineProperty;var a=(r,e)=>T(r,"name",{value:e,configurable:!0});import{createHash as M}from"node:crypto";import{readConfig as E}from"../config.js";import{emitEvent as $}from"../events/emit.js";import{grantSyncStateFor as A}from"../grants/mirror.js";import{assertion as N,machineRevokedMessage as O,requestGrantSync as P,runtimeClient as I}from"../grants/sync.js";import{isUnsandboxedMachine as F}from"../runtime/unsandboxed.js";import{ProviderError as h}from"./errors.js";import{cacheKey as G,cachedToken as L,discardEpoch as U,storeToken as C}from"./token-cache.js";import{discardFile as ce}from"./token-cache.js";const D=1e4;function J(r){const e=r.issuer??E("user").runtime?.issuer;if(!e)throw new h("not_found","provider calls need a directory-connected runtime");return e.replace(/\/$/,"")}a(J,"issuerOf");function f(r,e,t){return new h(r,e,{origin:"directory",details:t})}a(f,"directoryError");function B(r,e,t,i){const n=typeof e.error=="string"?e.error:null,o=typeof e.error_description=="string"?e.error_description:void 0,c={directory_status:r,...n?{directory_error:n}:{},...o?{directory_description:o}:{}},u=o?`: ${o}`:"";switch(n){case"invalid_client":return F()?{error:f("machine_revoked",O(i),c),grantRefusal:!1}:{error:f("server_error",`the directory refused the outbound token request (${n})${u}`,c),grantRefusal:!1};case"invalid_request":return{error:f("server_error",`the directory refused the outbound token request (${n})${u}`,c),grantRefusal:!1};case"invalid_target":return{error:f("not_found",`the directory knows no provider at ${t.audience}${u}`,c),grantRefusal:!1};case"invalid_grant":return{error:f("grant_revoked",`the directory has no active grant for ${t.grantee}${u}`,c),grantRefusal:!0};case"provider_not_connected":return{error:f("provider_not_connected",o??"The user has not connected this provider.",c),grantRefusal:!1};case"invalid_scope":{const s=typeof e.scope=="string"&&e.scope?e.scope:t.scope.length===1?t.scope[0]:void 0,m=s?`missing scope ${s}`:`the grant does not cover ${t.scope.join(" ")}`;return{error:new h("scope_missing",m,{origin:"directory",details:c,...s?{scope:s}:{}}),grantRefusal:!0}}default:return{error:f("server_error",`the directory token endpoint answered ${r}${n?` ${n}`:""}${u}`,c),grantRefusal:!1}}}a(B,"refusal");function H(r){try{return JSON.parse(Buffer.from(r.split(".")[1]??"","base64url").toString("utf8"))}catch{return{}}}a(H,"claims");function K(r){const e=r.grant_rev,t=r.grant_status;return typeof e!="number"||!Number.isInteger(e)||e<0||typeof t!="string"?null:{rev:e,status:t}}a(K,"refusedGrantState");function z(r,e){const t=a(i=>i.status==="active"?0:1,"phase");return r.rev>e.rev||r.rev===e.rev&&t(r)>t(e)}a(z,"newer");function Q(r,e,t){if(!e)return;const i=A(r.grantee,r.sub)??{rev:0,status:"removed"};if(!z(e,i))return;const n=t.syncGrants??P;Promise.resolve().then(()=>n({fresh:!0})).catch(()=>{})}a(Q,"syncIfNewer");async function V(r,e={}){const t=J(e),i=`${t}/token`,n=I(),o=new URLSearchParams({grant_type:"client_credentials",client_id:n.client_id,client_assertion_type:"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",client_assertion:N(n,i),audience:r.audience,sub:r.sub,grantee:r.grantee,scope:[...new Set(r.scope)].sort().join(" "),initiating_app:r.initiating_app}),c=AbortSignal.timeout(D),u=e.signal?AbortSignal.any([e.signal,c]):c;let s,m;try{s=await(e.fetch??fetch)(i,{method:"POST",body:o,signal:u,headers:{Accept:"application/json"}}),m=await s.text()}catch(l){throw e.signal?.aborted?e.signal.reason:new h("server_error",`the directory token endpoint could not be reached: ${l instanceof Error?l.message:String(l)}`,{origin:"directory"})}let p=null;try{p=m?JSON.parse(m):null}catch{p=null}const g=p&&typeof p=="object"&&!Array.isArray(p)?p:{};if(!s.ok){const{error:l,grantRefusal:j}=B(s.status,g,r,t);throw l.code==="machine_revoked"&&$({level:"error",event:"daemon.grants.machine_revoked",fields:{audience:r.audience}}),$({level:"info",event:"daemon.providers.mint_refused",fields:{audience:r.audience,grantee:r.grantee,code:l.code,directory_error:typeof g.error=="string"?g.error:null,status:s.status}}),j&&Q(r,K(g),e),l}const y=g.access_token;if(typeof y!="string"||!y)throw new h("server_error","the directory token response has no access_token",{origin:"directory"});const d=H(y),S=Math.floor((e.now?.()??Date.now())/1e3),_=g.expires_in,v=typeof _=="number"&&Number.isFinite(_)&&_>0?S+Math.floor(_):null,w=typeof d.exp=="number"?d.exp:null,b=v!==null&&w!==null?Math.min(v,w):v??w;if(b===null)throw new h("server_error","the directory token response names no expiry",{origin:"directory"});const x=typeof d.jti=="string"&&d.jti?d.jti:M("sha256").update(y).digest("hex"),R=typeof d.payer=="string"&&d.payer?d.payer:r.sub;return{access_token:y,jti:x,exp:b,payer:R}}a(V,"mintOutboundToken");const k=new Map;async function ie(r,e={}){const t=G(r),i=e.now??Date.now,n=L(t,i());if(n)return{...n,key:t};let o=k.get(t);if(!o){const u=U(t);o=V(r,{...e,signal:void 0}).then(s=>(C(t,s,u),s)).finally(()=>{k.delete(t)}),o.catch(()=>{}),k.set(t,o)}return{...e.signal?await W(o,e.signal):await o,key:t}}a(ie,"outboundToken");function W(r,e){return e.aborted?Promise.reject(e.reason):new Promise((t,i)=>{const n=a(()=>i(e.reason),"onAbort");e.addEventListener("abort",n,{once:!0}),r.then(t,i).finally(()=>e.removeEventListener("abort",n))})}a(W,"abortable");export{D as MINT_TIMEOUT_MS,ce as discardFile,V as mintOutboundToken,ie as outboundToken};
|
|
1
|
+
var T=Object.defineProperty;var a=(r,e)=>T(r,"name",{value:e,configurable:!0});import{createHash as M}from"node:crypto";import{readConfig as E}from"../config.js";import{emitEvent as $}from"../events/emit.js";import{grantSyncStateFor as A}from"../grants/mirror.js";import{assertion as N,machineRevokedMessage as O,requestGrantSync as P,runtimeClient as I}from"../grants/sync.js";import{isUnsandboxedMachine as F}from"../runtime/unsandboxed.js";import{ProviderError as h}from"./errors.js";import{cacheKey as G,cachedToken as L,discardEpoch as U,storeToken as C}from"./token-cache.js";import{discardFile as ce}from"./token-cache.js";const D=1e4;function J(r){const e=r.issuer??E("user").runtime?.issuer;if(!e)throw new h("not_found","provider calls need a directory-connected runtime");return e.replace(/\/$/,"")}a(J,"issuerOf");function f(r,e,t){return new h(r,e,{origin:"directory",details:t})}a(f,"directoryError");function B(r,e,t,i){const n=typeof e.error=="string"?e.error:null,o=typeof e.error_description=="string"?e.error_description:void 0,c={directory_status:r,...n?{directory_error:n}:{},...o?{directory_description:o}:{}},u=o?`: ${o}`:"";switch(n){case"invalid_client":return F()?{error:f("machine_revoked",O(i),c),grantRefusal:!1}:{error:f("server_error",`the directory refused the outbound token request (${n})${u}`,c),grantRefusal:!1};case"invalid_request":return{error:f("server_error",`the directory refused the outbound token request (${n})${u}`,c),grantRefusal:!1};case"invalid_target":return{error:f("not_found",`the directory knows no provider at ${t.audience}${u}`,c),grantRefusal:!1};case"invalid_grant":return{error:f("grant_revoked",`the directory has no active grant for ${t.grantee}${u}`,c),grantRefusal:!0};case"provider_not_connected":return{error:f("provider_not_connected",o??"The user has not connected this provider.",c),grantRefusal:!1};case"invalid_scope":{const s=typeof e.scope=="string"&&e.scope?e.scope:t.scope.length===1?t.scope[0]:void 0,m=s?`missing scope ${s}`:`the grant does not cover ${t.scope.join(" ")}`;return{error:new h("scope_missing",m,{origin:"directory",details:c,...s?{scope:s}:{}}),grantRefusal:!0}}default:return{error:f("server_error",`the directory token endpoint answered ${r}${n?` ${n}`:""}${u}`,c),grantRefusal:!1}}}a(B,"refusal");function H(r){try{return JSON.parse(Buffer.from(r.split(".")[1]??"","base64url").toString("utf8"))}catch{return{}}}a(H,"claims");function K(r){const e=r.grant_rev,t=r.grant_status;return typeof e!="number"||!Number.isInteger(e)||e<0||typeof t!="string"?null:{rev:e,status:t}}a(K,"refusedGrantState");function z(r,e){const t=a(i=>i.status==="active"?0:1,"phase");return r.rev>e.rev||r.rev===e.rev&&t(r)>t(e)}a(z,"newer");async function Q(r,e,t){if(!e)return;const i=await A(r.grantee,r.sub)??{rev:0,status:"removed"};if(!z(e,i))return;const n=t.syncGrants??P;Promise.resolve().then(()=>n({fresh:!0})).catch(()=>{})}a(Q,"syncIfNewer");async function V(r,e={}){const t=J(e),i=`${t}/token`,n=I(),o=new URLSearchParams({grant_type:"client_credentials",client_id:n.client_id,client_assertion_type:"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",client_assertion:N(n,i),audience:r.audience,sub:r.sub,grantee:r.grantee,scope:[...new Set(r.scope)].sort().join(" "),initiating_app:r.initiating_app}),c=AbortSignal.timeout(D),u=e.signal?AbortSignal.any([e.signal,c]):c;let s,m;try{s=await(e.fetch??fetch)(i,{method:"POST",body:o,signal:u,headers:{Accept:"application/json"}}),m=await s.text()}catch(l){throw e.signal?.aborted?e.signal.reason:new h("server_error",`the directory token endpoint could not be reached: ${l instanceof Error?l.message:String(l)}`,{origin:"directory"})}let p=null;try{p=m?JSON.parse(m):null}catch{p=null}const g=p&&typeof p=="object"&&!Array.isArray(p)?p:{};if(!s.ok){const{error:l,grantRefusal:j}=B(s.status,g,r,t);throw l.code==="machine_revoked"&&$({level:"error",event:"daemon.grants.machine_revoked",fields:{audience:r.audience}}),$({level:"info",event:"daemon.providers.mint_refused",fields:{audience:r.audience,grantee:r.grantee,code:l.code,directory_error:typeof g.error=="string"?g.error:null,status:s.status}}),j&&await Q(r,K(g),e),l}const y=g.access_token;if(typeof y!="string"||!y)throw new h("server_error","the directory token response has no access_token",{origin:"directory"});const d=H(y),S=Math.floor((e.now?.()??Date.now())/1e3),_=g.expires_in,v=typeof _=="number"&&Number.isFinite(_)&&_>0?S+Math.floor(_):null,w=typeof d.exp=="number"?d.exp:null,b=v!==null&&w!==null?Math.min(v,w):v??w;if(b===null)throw new h("server_error","the directory token response names no expiry",{origin:"directory"});const x=typeof d.jti=="string"&&d.jti?d.jti:M("sha256").update(y).digest("hex"),R=typeof d.payer=="string"&&d.payer?d.payer:r.sub;return{access_token:y,jti:x,exp:b,payer:R}}a(V,"mintOutboundToken");const k=new Map;async function ie(r,e={}){const t=G(r),i=e.now??Date.now,n=L(t,i());if(n)return{...n,key:t};let o=k.get(t);if(!o){const u=U(t);o=V(r,{...e,signal:void 0}).then(s=>(C(t,s,u),s)).finally(()=>{k.delete(t)}),o.catch(()=>{}),k.set(t,o)}return{...e.signal?await W(o,e.signal):await o,key:t}}a(ie,"outboundToken");function W(r,e){return e.aborted?Promise.reject(e.reason):new Promise((t,i)=>{const n=a(()=>i(e.reason),"onAbort");e.addEventListener("abort",n,{once:!0}),r.then(t,i).finally(()=>e.removeEventListener("abort",n))})}a(W,"abortable");export{D as MINT_TIMEOUT_MS,ce as discardFile,V as mintOutboundToken,ie as outboundToken};
|
|
@@ -16,5 +16,5 @@ type ReceiptCall = {
|
|
|
16
16
|
* own, and one that fails the check is dropped without dropping the others. Returns the first
|
|
17
17
|
* accepted receipt id.
|
|
18
18
|
*/
|
|
19
|
-
export declare function acceptProviderReceipt(value: string | string[] | undefined, call: ReceiptCall): string | undefined
|
|
19
|
+
export declare function acceptProviderReceipt(value: string | string[] | undefined, call: ReceiptCall): Promise<string | undefined>;
|
|
20
20
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
(provider, receipt_id, grantee, run_id, usd_equivalent, received_at) VALUES (?, ?, ?, ?, ?, ?)`).run(r.provider,s.receipt_id,r.grantee,r.run_id,s.usd_equivalent,new Date().toISOString()).changes||(
|
|
1
|
+
var p=Object.defineProperty;var a=(t,r)=>p(t,"name",{value:r,configurable:!0});import{withCanvasWrite as _}from"../canvas/db.js";import{addUsage as f}from"../usage/ledger.js";const g=8,y=65536;function c(t,r){if(!t||typeof t!="object"||Array.isArray(t))return!1;const e=t;return typeof e.receipt_id=="string"&&!!e.receipt_id&&e.receipt_id.length<=256&&e.provider===`app:${r.provider}`&&e.tool===r.tool&&e.request_id===r.request_id&&e.sub===r.sub&&e.grantee===r.grantee&&e.payer===r.payer&&(e.run_id??null)===r.run_id&&typeof e.unit=="string"&&!!e.unit&&typeof e.units=="number"&&Number.isFinite(e.units)&&e.units>=0&&typeof e.time=="string"&&Number.isFinite(Date.parse(e.time))&&typeof e.usd_equivalent=="number"&&Number.isFinite(e.usd_equivalent)&&e.usd_equivalent>=0}a(c,"belongsToCall");async function S(t,r){const e=Array.isArray(t)?t[0]:t;if(!e||e.length>y)return;let n;try{n=JSON.parse(e)}catch{return}if(Array.isArray(n)&&n.length>g)return;const o=(Array.isArray(n)?n:[n]).filter(i=>c(i,r));if(o.length)return await _(async i=>{for(const s of o){if(!(await i.prepare(`INSERT OR IGNORE INTO provider_receipts
|
|
2
|
+
(provider, receipt_id, grantee, run_id, usd_equivalent, received_at) VALUES (?, ?, ?, ?, ?, ?)`).run(r.provider,s.receipt_id,r.grantee,r.run_id,s.usd_equivalent,new Date().toISOString())).changes||(await f(i,{grantee:r.ledger_grantee??r.grantee,payer:r.payer.startsWith("app:")?"app":"user",source:`provider:${r.provider}`,served_model:"",input_tokens:0,output_tokens:0,cached_tokens:0,usd_equivalent:s.usd_equivalent}),!r.run_id))continue;const d=await i.prepare("SELECT usage_json FROM nodes WHERE node_id = ? AND run_id = ?").get(r.run_id,r.run_id);if(!d)continue;const u=d.usage_json?JSON.parse(d.usage_json):{};u.cost_usd=(typeof u.cost_usd=="number"?u.cost_usd:0)+s.usd_equivalent,await i.prepare("UPDATE nodes SET usage_json = ? WHERE node_id = ?").run(JSON.stringify(u),r.run_id)}}),o[0].receipt_id}a(S,"acceptProviderReceipt");export{S as acceptProviderReceipt};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var s=Object.defineProperty;var n=(o,e)=>s(o,"name",{value:e,configurable:!0});import{commitBindingRequest as w}from"../human/requests.js";import{getReview as
|
|
1
|
+
var s=Object.defineProperty;var n=(o,e)=>s(o,"name",{value:e,configurable:!0});import{commitBindingRequest as w}from"../human/requests.js";import{getReview as a}from"./store.js";import{discardStaging as _,stageReview as c}from"./stage.js";import{realizeReview as d}from"./realize.js";async function f(o){const e=await c(o);if(e.existing!==void 0){await d(e.existing.request_id);const r=await a(e.existing.request_id);if(r===null)throw new Error(`realized review disappeared: ${e.existing.request_id}`);return r}let i;try{i=await w({request_id:e.row.review_id,idempotency_key:e.row.idempotency_key,requester_node_id:e.row.origin_node_id,companion_node_id:e.row.companion_node_id,request_dir:e.row.review_dir,file:e.row.file,specification:{origin_kind:e.row.origin_kind,origin_session_file:e.row.origin_session_file,origin_session_id:e.row.origin_session_id,origin_leaf_id:e.row.origin_leaf_id,model_spec:e.row.model_spec,branch_file:e.row.branch_file,baseline_sha256:e.row.baseline_sha256,baseline_bytes:e.row.baseline_bytes,captured_at:e.row.captured_at,output_path:e.row.output_path,document_id:e.row.document_id,document_name:e.row.document_name,document_base:e.row.document_base},anchor_base_sha256:e.row.anchor_base_sha256,anchor_base_bytes:e.row.anchor_base_bytes,created_at:e.row.created,subtitle:e.row.subtitle,...e.row.document_name===null?{}:{title:e.row.document_name},inbox_listed:e.row.origin_kind==="ticket"})}catch(r){throw await _(e.row.review_id,e.row.branch_file),r}i.won||await _(e.row.review_id,e.row.branch_file),await d(i.request_id);const t=await a(i.request_id);if(t===null)throw new Error(`realized review disappeared: ${i.request_id}`);return t}n(f,"createReview");export{f as createReview};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CanvasDb } from '../canvas/db.js';
|
|
2
2
|
import { type CommentAnchor, type CommentAuthorKind, type CommentStatus, type ReviewComment, type ReviewCommentEvent } from './types.js';
|
|
3
3
|
interface Actor {
|
|
4
4
|
kind: CommentAuthorKind;
|
|
@@ -17,53 +17,53 @@ export declare function createComment(args: {
|
|
|
17
17
|
doc_hash: string;
|
|
18
18
|
actor: Actor;
|
|
19
19
|
operation_id: string;
|
|
20
|
-
}): {
|
|
20
|
+
}): Promise<{
|
|
21
21
|
comment: ReviewComment;
|
|
22
22
|
changed: true;
|
|
23
|
-
}
|
|
23
|
+
}>;
|
|
24
24
|
export declare function editComment(commentIdValue: string, args: {
|
|
25
25
|
text: string;
|
|
26
26
|
actor: Actor;
|
|
27
27
|
operation_id: string;
|
|
28
28
|
if_revision?: number;
|
|
29
|
-
}): {
|
|
29
|
+
}): Promise<{
|
|
30
30
|
comment: ReviewComment;
|
|
31
31
|
changed: boolean;
|
|
32
|
-
}
|
|
33
|
-
export declare function resolveComment(commentIdValue: string, args: CommentMutationArgs): {
|
|
32
|
+
}>;
|
|
33
|
+
export declare function resolveComment(commentIdValue: string, args: CommentMutationArgs): Promise<{
|
|
34
34
|
comment: ReviewComment;
|
|
35
35
|
changed: boolean;
|
|
36
|
-
}
|
|
37
|
-
export declare function reopenComment(commentIdValue: string, args: CommentMutationArgs): {
|
|
36
|
+
}>;
|
|
37
|
+
export declare function reopenComment(commentIdValue: string, args: CommentMutationArgs): Promise<{
|
|
38
38
|
comment: ReviewComment;
|
|
39
39
|
changed: boolean;
|
|
40
|
-
}
|
|
41
|
-
export declare function deleteComment(commentIdValue: string, args: CommentMutationArgs): {
|
|
40
|
+
}>;
|
|
41
|
+
export declare function deleteComment(commentIdValue: string, args: CommentMutationArgs): Promise<{
|
|
42
42
|
comment: ReviewComment;
|
|
43
43
|
changed: boolean;
|
|
44
|
-
}
|
|
44
|
+
}>;
|
|
45
45
|
export declare function listComments(reviewId: string, opts?: {
|
|
46
46
|
status?: CommentStatus | 'all';
|
|
47
|
-
}): ReviewComment[]
|
|
48
|
-
export declare function getComment(commentIdValue: string): ReviewComment | null
|
|
49
|
-
export declare function listCommentEvents(commentIdValue: string): ReviewCommentEvent[]
|
|
47
|
+
}): Promise<ReviewComment[]>;
|
|
48
|
+
export declare function getComment(commentIdValue: string): Promise<ReviewComment | null>;
|
|
49
|
+
export declare function listCommentEvents(commentIdValue: string): Promise<ReviewCommentEvent[]>;
|
|
50
50
|
export declare function listReviewEvents(reviewId: string, opts: {
|
|
51
51
|
since_seq?: number;
|
|
52
52
|
limit?: number;
|
|
53
|
-
}): {
|
|
53
|
+
}): Promise<{
|
|
54
54
|
events: ReviewCommentEvent[];
|
|
55
55
|
next_since_seq: number;
|
|
56
|
-
}
|
|
57
|
-
export declare function snapshotCommentsLocked(db:
|
|
56
|
+
}>;
|
|
57
|
+
export declare function snapshotCommentsLocked(db: CanvasDb, reviewId: string): Promise<{
|
|
58
58
|
comments: import('../human/types.js').FeedbackComment[];
|
|
59
59
|
total: number;
|
|
60
60
|
unresolved: number;
|
|
61
|
-
}
|
|
61
|
+
}>;
|
|
62
62
|
export declare function appendDeliveryEvent(args: {
|
|
63
63
|
review_id: string;
|
|
64
64
|
comment_id: string;
|
|
65
65
|
kind: 'notified' | 'notify_failed';
|
|
66
66
|
payload: unknown;
|
|
67
67
|
operation_id: string;
|
|
68
|
-
}): void
|
|
68
|
+
}): Promise<void>;
|
|
69
69
|
export {};
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
var
|
|
1
|
+
var A=Object.defineProperty;var i=(e,t)=>A(e,"name",{value:t,configurable:!0});import{randomBytes as D}from"node:crypto";import{withCanvasWrite as u,openDb as l}from"../canvas/db.js";import{nowIso as h}from"../fs-utils.js";import{signalReviewActivity as v}from"./signal.js";import{COMMENT_EVENTS_PAGE_DEFAULT as F,COMMENT_EVENTS_PAGE_MAX as U,COMMENT_LINE_TEXT_MAX as W,COMMENT_TEXT_MAX as R,LIVE_COMMENTS_MAX as T,ReviewOperationError as m}from"./types.js";function _(e){return{comment_id:e.comment_id,review_id:e.review_id,status:e.status,revision:e.revision,text:e.text,anchor:{line:e.anchor_line,end_line:e.anchor_end_line,...e.anchor_col_start===null?{}:{col_start:e.anchor_col_start},...e.anchor_col_end===null?{}:{col_end:e.anchor_col_end},...e.anchor_quote===null?{}:{quote:e.anchor_quote}},anchor_state:e.anchor_state,anchor_line_text:e.anchor_line_text,anchor_doc_hash:e.anchor_doc_hash,author:{kind:e.author_kind,node_id:e.author_node_id},updated_by:{kind:e.updated_by_kind,node_id:e.updated_by_node_id},created_at:e.created_at,updated_at:e.updated_at,resolved_at:e.resolved_at,deleted_at:e.deleted_at,created_seq:e.created_seq}}i(_,"commentFromRow");function k(e){return{seq:e.seq,review_id:e.review_id,comment_id:e.comment_id,kind:e.kind,state_change:e.state_change===0?0:1,revision_after:e.revision_after,actor:{kind:e.actor_kind,node_id:e.actor_node_id},at:e.at,operation_id:e.operation_id,...e.payload===null?{}:{payload:JSON.parse(e.payload)}}}i(k,"eventFromRow");function N(e){return JSON.stringify(e)}i(N,"json");function q(){let e;do e=D(16).toString("hex");while(/^0+$/.test(e));return e}i(q,"commentId");function C(e){const t=e.trim();if(t==="")throw new Error("comment text must not be empty");const n=Buffer.byteLength(t,"utf8");if(n>R)throw new m("text_too_long","comment text exceeds the maximum length",{limit:R,received:n});return t}i(C,"trimText");function B(e,t){if(Buffer.byteLength(e,"utf8")<=t)return e;const n="\u2026 [truncated]",r=Buffer.byteLength(n,"utf8"),o=Buffer.from(e,"utf8");let a=Math.max(0,t-r);for(;a>0&&(o[a]&192)===128;)a-=1;return`${o.subarray(0,a).toString("utf8")}${n}`}i(B,"truncateUtf8");async function p(e,t){return await e.prepare("SELECT * FROM review_comments WHERE comment_id = ?").get(t)??null}i(p,"getStoredComment");async function E(e,t){const n=await p(e,t);if(n===null)throw new m("unknown_comment","comment was not found",{received:t});return n}i(E,"requireStoredComment");async function L(e,t){if(await e.prepare("SELECT request_id FROM human_requests WHERE request_id = ? AND kind = 'review' AND state = 'open'").get(t)===void 0)throw new m("unknown_review","review was not found",{received:t})}i(L,"assertReviewExists");function S(e,t){if(t!==void 0&&t!==e.revision)throw new m("stale_comment","comment revision is stale",{revision:e.revision,text:e.text})}i(S,"assertRevision");async function w(e,t){const n=await e.prepare(`
|
|
2
2
|
INSERT INTO review_comment_events
|
|
3
3
|
(review_id, comment_id, kind, state_change, revision_after, actor_kind, actor_node_id, at, operation_id, payload)
|
|
4
4
|
VALUES (?, ?, ?, 1, ?, ?, ?, ?, ?, ?)
|
|
5
|
-
`).run(t.row.review_id,t.row.comment_id,t.kind,t.row.revision,t.actor.kind,t.actor.node_id,t.at,t.operation_id,
|
|
5
|
+
`).run(t.row.review_id,t.row.comment_id,t.kind,t.row.revision,t.actor.kind,t.actor.node_id,t.at,t.operation_id,N(t.payload));return Number(n.lastInsertRowid)}i(w,"appendStateEvent");async function M(e,t,n,r,o){const a=t.revision+1;return await e.prepare(`
|
|
6
6
|
UPDATE review_comments
|
|
7
7
|
SET status = ?, revision = ?, text = ?, updated_by_kind = ?, updated_by_node_id = ?,
|
|
8
8
|
updated_at = ?, resolved_at = ?, deleted_at = ?
|
|
9
9
|
WHERE comment_id = ?
|
|
10
|
-
`).run(n.status??t.status,
|
|
10
|
+
`).run(n.status??t.status,a,n.text??t.text,r.kind,r.node_id,o,n.resolved_at===void 0?t.resolved_at:n.resolved_at,n.deleted_at===void 0?t.deleted_at:n.deleted_at,t.comment_id),{...t,...n,revision:a,updated_by_kind:r.kind,updated_by_node_id:r.node_id,updated_at:o}}i(M,"updateComment");function O(e){return e.changed&&v(),e}i(O,"completeMutation");async function P(e){const t=await u(async n=>{await L(n,e.review_id);const r=await n.prepare("SELECT COUNT(*) AS count FROM review_comments WHERE review_id = ? AND status != 'deleted'").get(e.review_id);if(Number(r.count)>=T)throw new m("comment_limit_reached","review comment limit reached",{limit:T,live:Number(r.count)});const o=C(e.text),a=B(e.line_text,W),d=h();let c=q();for(;await p(n,c)!==null;)c=q();if((await n.prepare(`
|
|
11
11
|
INSERT INTO review_comments
|
|
12
12
|
(comment_id, review_id, status, revision, text, anchor_line, anchor_end_line,
|
|
13
13
|
anchor_col_start, anchor_col_end, anchor_quote, anchor_line_text, anchor_doc_hash, anchor_state,
|
|
14
14
|
author_kind, author_node_id, updated_by_kind, updated_by_node_id, created_at,
|
|
15
15
|
updated_at, resolved_at, deleted_at, created_seq)
|
|
16
16
|
VALUES (?, ?, 'open', 1, ?, ?, ?, ?, ?, ?, ?, ?, 'live', ?, ?, ?, ?, ?, ?, NULL, NULL, 0)
|
|
17
|
-
`).run(
|
|
17
|
+
`).run(c,e.review_id,o,e.anchor.line,e.anchor.end_line,e.anchor.col_start??null,e.anchor.col_end??null,e.anchor.quote??null,a,e.doc_hash,e.actor.kind,e.actor.node_id,e.actor.kind,e.actor.node_id,d,d)).changes!==1)throw new Error("failed to insert review comment");const y=await p(n,c),x=await w(n,{row:y,kind:"created",actor:e.actor,operation_id:e.operation_id,at:d,payload:{text:o,anchor:e.anchor,line_text:a,doc_hash:e.doc_hash}});return await n.prepare("UPDATE review_comments SET created_seq = ? WHERE comment_id = ?").run(x,c),{comment:_({...y,created_seq:x}),changed:!0}});return v(),t}i(P,"createComment");async function $(e,t){const n=await u(async r=>{const o=await E(r,e);if(o.status==="deleted")throw new m("comment_deleted","comment is a deleted tombstone",{comment_id:o.comment_id,deleted_at:o.deleted_at});const a=C(t.text);if(o.text===a)return{comment:_(o),changed:!1};S(o,t.if_revision);const d=h(),c=_(o).anchor,s=await M(r,o,{text:a},t.actor,d);return await w(r,{row:s,kind:"edited",actor:t.actor,operation_id:t.operation_id,at:d,payload:{previous_text:o.text,text:a,previous_anchor:c,anchor:_(s).anchor}}),{comment:_(s),changed:!0}});return O(n)}i($,"editComment");async function f(e,t,n,r){const o=await u(async a=>{const d=await E(a,e);if(d.status==="deleted"){if(n==="deleted")return{comment:_(d),changed:!1};throw new m("comment_deleted","comment is a deleted tombstone",{comment_id:d.comment_id,deleted_at:d.deleted_at})}if(d.status===n)return{comment:_(d),changed:!1};S(d,t.if_revision);const c=h(),s=await M(a,d,{status:n,resolved_at:n==="resolved"?c:n==="open"?null:void 0,deleted_at:n==="deleted"?c:void 0},t.actor,c);return await w(a,{row:s,kind:r,actor:t.actor,operation_id:t.operation_id,at:c,payload:{previous_status:d.status,status:n,previous_text:d.text,text:s.text,previous_anchor:_(d).anchor,anchor:_(s).anchor}}),{comment:_(s),changed:!0}});return O(o)}i(f,"transitionComment");async function G(e,t){return await f(e,t,"resolved","resolved")}i(G,"resolveComment");async function J(e,t){return await f(e,t,"open","reopened")}i(J,"reopenComment");async function j(e,t){return await f(e,t,"deleted","deleted")}i(j,"deleteComment");async function z(e,t){const n=await l(),r=t?.status;return(r===void 0?await n.prepare("SELECT * FROM review_comments WHERE review_id = ? AND status != 'deleted' ORDER BY anchor_line, created_seq").all(e):r==="all"?await n.prepare("SELECT * FROM review_comments WHERE review_id = ? ORDER BY anchor_line, created_seq").all(e):await n.prepare("SELECT * FROM review_comments WHERE review_id = ? AND status = ? ORDER BY anchor_line, created_seq").all(e,r)).map(_)}i(z,"listComments");async function K(e){const t=await p(await l(),e);return t===null?null:_(t)}i(K,"getComment");async function Q(e){return(await(await l()).prepare("SELECT * FROM review_comment_events WHERE comment_id = ? ORDER BY seq").all(e)).map(k)}i(Q,"listCommentEvents");async function Z(e,t){const n=t.since_seq??0,r=Math.min(Math.max(t.limit??F,1),U),a=(await(await l()).prepare("SELECT * FROM review_comment_events WHERE review_id = ? AND seq > ? ORDER BY seq LIMIT ?").all(e,n,r)).map(k);return{events:a,next_since_seq:a.length===0?n:a[a.length-1].seq}}i(Z,"listReviewEvents");async function g(e,t){const n=await e.prepare("SELECT * FROM review_comments WHERE review_id = ? AND status != 'deleted' ORDER BY anchor_line, created_seq").all(t);return{comments:n.map(o=>({id:o.comment_id,line:o.anchor_line,endLine:o.anchor_end_line,...o.anchor_quote===null?{}:{quote:o.anchor_quote},...o.anchor_col_start===null?{}:{colStart:o.anchor_col_start},...o.anchor_col_end===null?{}:{colEnd:o.anchor_col_end},lineText:o.anchor_line_text,comment:o.text,createdAt:o.created_at})),total:n.length,unresolved:n.filter(o=>o.status==="open").length}}i(g,"snapshotCommentsLocked");async function ee(e){await u(async t=>{if(await L(t,e.review_id),(await E(t,e.comment_id)).review_id!==e.review_id)throw new m("unknown_comment","comment was not found",{received:e.comment_id});await t.prepare(`
|
|
18
18
|
INSERT INTO review_comment_events
|
|
19
19
|
(review_id, comment_id, kind, state_change, revision_after, actor_kind, actor_node_id, at, operation_id, payload)
|
|
20
20
|
VALUES (?, ?, ?, 0, NULL, 'system', NULL, ?, ?, ?)
|
|
21
|
-
`).run(e.review_id,e.comment_id,e.kind,
|
|
21
|
+
`).run(e.review_id,e.comment_id,e.kind,h(),e.operation_id,N(e.payload))}),v()}i(ee,"appendDeliveryEvent");export{ee as appendDeliveryEvent,P as createComment,j as deleteComment,$ as editComment,K as getComment,Q as listCommentEvents,z as listComments,Z as listReviewEvents,J as reopenComment,G as resolveComment,g as snapshotCommentsLocked};
|
|
@@ -27,7 +27,7 @@ export declare function captureOrigin(originNodeId: string, deps?: {
|
|
|
27
27
|
/** Create the ordinary, promptless companion node. Realization owns its launch. */
|
|
28
28
|
export declare function spawnReviewCompanion(spec: ReviewCompanionSpec): Promise<void>;
|
|
29
29
|
/** A companion is bound only when its session coordinates and visible boundary are durable. */
|
|
30
|
-
export declare function isReviewCompanionBound(nodeId: string): boolean
|
|
30
|
+
export declare function isReviewCompanionBound(nodeId: string): Promise<boolean>;
|
|
31
31
|
/** Wait for the durable companion bind without owning companion liveness. */
|
|
32
32
|
export declare function awaitCompanionBind(nodeId: string, deadlineMs: number): Promise<boolean>;
|
|
33
33
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var S=Object.defineProperty;var d=(e,o)=>S(e,"name",{value:o,configurable:!0});import{randomUUID as v}from"node:crypto";import{conversationIdFromPath as w,conversationStore as u,ConversationNotFoundError as p}from"../conversation-store/index.js";import{basename as F,isAbsolute as c}from"node:path";import{BrokerClient as x}from"../broker-client/index.js";import{deleteNode as M,getNode as g}from"../canvas/index.js";import{expandModelCandidates as C,selectInitialModelRoute as E}from"../model-routes.js";import{buildLaunchSpec as L}from"../runtime/launch.js";import{openModelRegistry as B}from"../runtime/model-registry.js";import{isBrokerLive as O}from"../runtime/model-swap.js";import{spawnNode as R}from"../runtime/nodes.js";import{SessionManager as D}from"../runtime/broker-sdk.js";import{isReviewBoundary as P}from"../runtime/session-visibility.js";import{forkNodeLedger as $}from"../runtime/ledger.js";import{ReviewOperationError as b}from"./types.js";const I=/^[^/\s:]+\/[^/\s:]+:(?:off|minimal|low|medium|high|xhigh|max)$/,q=100;function N(e){return new b("review_origin_missing","review origin was not found",{origin_node_id:e})}d(N,"originMissing");function f(e,o,r={}){return new b("review_origin_unforkable","review origin has no forkable exact session",{origin_node_id:e,reason:o,...r})}d(f,"originUnforkable");async function k(e,o,r){const i=w(o.sourceFile);if(!c(o.sourceFile)||i===null||i!==o.sourceSessionId||o.leafId===null||o.leafId==="")throw f(e,"no_forkable_session");try{await u().header(i)}catch(n){throw n instanceof p?f(e,"no_forkable_session"):n}if(o.modelSpec===null||!I.test(o.modelSpec))throw f(e,"model_unresolvable");const t=E({kind:"exact",spec:o.modelSpec},r??await B(),{cwd:o.cwd,profileId:o.profileId});if(t.selected===void 0)throw f(e,"model_unresolvable",{model_reason:t.rejected[0]?.reason});return{sourceFile:o.sourceFile,sourceSessionId:o.sourceSessionId,leafId:o.leafId,modelSpec:o.modelSpec}}d(k,"validateCapture");function U(e){return new Promise(async(o,r)=>{const i=new x(e);let t=!1;function n(s){t||(t=!0,i.close(),s())}d(n,"finish"),i.on("error",s=>n(()=>r(s))),i.on("close",()=>n(()=>r(new Error("origin broker closed before fork coordinates were read")))),i.on("connect",()=>{i.send({type:"hello",role:"observer",client_id:v()}),i.request({type:"get_human_fork_coordinates"}).then(s=>{if(s.kind!=="human_fork_coordinates"){n(()=>r(new Error("origin broker returned an unexpected fork-coordinate response")));return}n(()=>o(s))}).catch(s=>n(()=>r(s)))}),i.connect()})}d(U,"captureLiveOrigin");async function re(e,o={}){const r=await g(e);if(r===null)throw N(e);if(O(r)){const a=await U(e);return k(e,{...a,cwd:r.cwd,profileId:r.profile_id},o.registry)}const i=typeof r.pi_session_file=="string"?r.pi_session_file:"";let t="",n=null,s=null;const h=w(i);if(c(i)&&h!==null)try{const a=await u().read(h),m=D.inMemory(a.header.cwd,void 0,[a.header,...a.entries]);t=m.getSessionId(),n=m.getLeafId();const _=r.launch?.model,l=typeof _=="string"?C({kind:"exact",spec:_},r.cwd,r.profile_id)[0]:void 0;if(l!==void 0){const y=l.thinkingLevel??(m.buildSessionContext().thinkingLevel||"off");s=`${l.providerId}/${l.modelId}:${y}`}}catch(a){if(!(a instanceof p))throw a}return k(e,{sourceFile:i,sourceSessionId:t,leafId:n,modelSpec:s,cwd:r.cwd,profileId:r.profile_id},o.registry)}d(re,"captureOrigin");async function ie(e){if(!c(e.branchFile)||!c(e.targetFile))throw new Error("review companion requires absolute branch and target paths");if(!I.test(e.modelSpec))throw new Error("review companion requires an exact model spec");const{launch:o}=L("review/companion","base",{lifecycle:"resident",hasManager:!1,model:e.modelSpec,modelExact:!0,cwd:e.cwd,profileId:e.profileId}),r=await R({nodeId:e.nodeId,kind:"review/companion",mode:"base",lifecycle:"resident",cwd:e.cwd,profile_id:e.profileId,parent:e.originNodeId,creator:e.originNodeId,subscribe:!1,forkFrom:e.branchFile,forkSourceFile:e.branchFile,modelOverride:e.modelSpec,reviewBinding:{review_id:e.reviewId,origin_node_id:e.originNodeId,branch_file:e.branchFile,target_file:e.targetFile},name:`review ${F(e.targetFile)}`,launch:o});try{await $(r.node_id,e.originNodeId)}catch(i){throw await M(r.node_id),i}}d(ie,"spawnReviewCompanion");async function A(e){const o=await g(e),r=o?.review_binding,i=o?.pi_session_file,t=typeof i=="string"?w(i):null;if(r==null||o?.pi_session_id==null||t===null)return!1;try{return(await u().read(t)).entries.some(n=>P(n,r.review_id))}catch(n){if(n instanceof p)return!1;throw n}}d(A,"isReviewCompanionBound");async function ne(e,o){const r=Date.now()+Math.max(0,o);for(;;){if(await A(e))return!0;const i=r-Date.now();if(i<=0)return!1;await new Promise(t=>setTimeout(t,Math.min(q,i)))}}d(ne,"awaitCompanionBind");export{ne as awaitCompanionBind,re as captureOrigin,A as isReviewCompanionBound,ie as spawnReviewCompanion};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { DatabaseSync } from 'node:sqlite';
|
|
2
1
|
import type { ReviewRecord } from './types.js';
|
|
3
2
|
import { type CommentAnchor } from './types.js';
|
|
3
|
+
import type { CanvasDb } from '../canvas/db.js';
|
|
4
4
|
type SourcePhase = 'submit' | 'comment';
|
|
5
5
|
/** Read the reviewed document once, preserving the exact bytes used for its digest. */
|
|
6
6
|
export declare function readReviewSource(file: string, phase?: SourcePhase): {
|
|
@@ -15,11 +15,11 @@ export declare function requireCurrentDocument(review: ReviewRecord, expected_do
|
|
|
15
15
|
lines: string[];
|
|
16
16
|
};
|
|
17
17
|
/** Verify a create-time source precondition from the review row held by the caller's canvas write transaction. */
|
|
18
|
-
export declare function requireCurrentDocumentLocked(db:
|
|
18
|
+
export declare function requireCurrentDocumentLocked(db: CanvasDb, review_id: string, expected_doc_hash: string): Promise<{
|
|
19
19
|
bytes: Buffer;
|
|
20
20
|
sha256: string;
|
|
21
21
|
lines: string[];
|
|
22
|
-
}
|
|
22
|
+
}>;
|
|
23
23
|
/** Reject malformed ranges rather than normalizing them into a different anchor. */
|
|
24
24
|
export declare function validateAnchorShape(anchor: CommentAnchor): void;
|
|
25
25
|
/** Capture the full source range used to render an anchor, without silently clamping it. */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var f=Object.defineProperty;var i=(e,t)=>f(e,"name",{value:t,configurable:!0});import{
|
|
2
|
-
`)}i(
|
|
1
|
+
var f=Object.defineProperty;var i=(e,t)=>f(e,"name",{value:t,configurable:!0});import{createHash as m}from"node:crypto";import{readFileSync as g,statSync as b}from"node:fs";import{documentLines as p}from"../document-lines.js";import{COMMENT_QUOTE_MAX as a,ReviewOperationError as u}from"./types.js";const l=2*1024*1024;function o(e,t,n){throw new u("source_unreadable","review source is unreadable",{phase:t,reason:n,file:e})}i(o,"sourceUnreadable");function w(e,t="submit"){let n;try{const s=b(e);if(!s.isFile())return o(e,t,"unreadable");n=s.size}catch(s){return o(e,t,s.code==="ENOENT"?"missing":"unreadable")}if(n>l)return o(e,t,"too_large");let r;try{r=g(e)}catch(s){return o(e,t,s.code==="ENOENT"?"missing":"unreadable")}if(r.length>l)return o(e,t,"too_large");if(r.includes(0))return o(e,t,"binary");let d;try{d=new TextDecoder("utf-8",{fatal:!0}).decode(r)}catch{return o(e,t,"binary")}return{bytes:r,sha256:m("sha256").update(r).digest("hex"),lines:p(d)}}i(w,"readReviewSource");function _(e,t){const n=w(e.file,"comment");if(n.sha256!==t)throw new u("stale_document","review document changed since it was rendered",{reason:"document_changed",expected_sha256:t,actual_sha256:n.sha256});if(n.sha256!==e.anchor_base_sha256)throw new u("stale_document","review comment ranges have not been remapped to the current document",{reason:"anchor_base_stale",expected_sha256:e.anchor_base_sha256,actual_sha256:n.sha256});return n}i(_,"requireDocumentSource");function q(e,t){return _(e,t)}i(q,"requireCurrentDocument");async function y(e,t,n){const r=await e.prepare("SELECT file, anchor_base_sha256 FROM human_requests WHERE request_id = ? AND kind = 'review' AND state = 'open'").get(t);if(r===void 0)throw new u("unknown_review","review was not found",{received:t});return _(r,n)}i(y,"requireCurrentDocumentLocked");function h(e){const t=[],n=e.col_start!==void 0,r=e.col_end!==void 0;if((!Number.isSafeInteger(e.line)||e.line<1)&&t.push("line must be a positive integer"),(!Number.isSafeInteger(e.end_line)||e.end_line<1)&&t.push("end_line must be a positive integer"),Number.isSafeInteger(e.line)&&Number.isSafeInteger(e.end_line)&&e.end_line<e.line&&t.push("end_line must be greater than or equal to line"),n!==r&&t.push("col_start and col_end must be provided together"),n&&(!Number.isSafeInteger(e.col_start)||e.col_start<0)&&t.push("col_start must be a non-negative integer"),r&&(!Number.isSafeInteger(e.col_end)||e.col_end<0)&&t.push("col_end must be a non-negative integer"),n&&r&&e.line===e.end_line&&Number.isSafeInteger(e.col_start)&&Number.isSafeInteger(e.col_end)&&e.col_end<=e.col_start&&t.push("col_end must be greater than col_start for a single-line anchor"),e.quote!==void 0&&typeof e.quote!="string"&&t.push("quote must be a string"),typeof e.quote=="string"&&Buffer.byteLength(e.quote,"utf8")>a&&t.push(`quote exceeds ${a} bytes`),t.length>0)throw new u("invalid_anchor","comment anchor is invalid",{violations:t})}i(h,"validateAnchorShape");function c(e,t){return t===e.length||(e[t]&192)!==128}i(c,"isUtf8Boundary");function I(e,t){if(h(t),t.line>e.length||t.end_line>e.length)throw new u("anchor_out_of_range","comment anchor exceeds the reviewed document",{line_count:e.length,requested:{line:t.line,end_line:t.end_line}});if(t.col_start!==void 0&&t.col_end!==void 0){const n=Buffer.from(e[t.line-1],"utf8"),r=Buffer.from(e[t.end_line-1],"utf8");if(t.col_start>n.length||t.col_end>r.length||!c(n,t.col_start)||!c(r,t.col_end))throw new u("anchor_out_of_range","comment anchor columns exceed the reviewed document",{line_count:e.length,requested:{line:t.line,end_line:t.end_line}})}return e.slice(t.line-1,t.end_line).join(`
|
|
2
|
+
`)}i(I,"captureAnchorText");export{I as captureAnchorText,w as readReviewSource,q as requireCurrentDocument,y as requireCurrentDocumentLocked,h as validateAnchorShape};
|
package/dist/core/review/fork.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
var m=Object.defineProperty;var d=(o,n)=>m(o,"name",{value:n,configurable:!0});import{basename as c}from"node:path";import{getNode as s}from"../canvas/index.js";import{materializeSessionBranch as
|
|
1
|
+
var m=Object.defineProperty;var d=(o,n)=>m(o,"name",{value:n,configurable:!0});import{basename as c}from"node:path";import{getNode as s}from"../canvas/index.js";import{materializeSessionBranch as w}from"../runtime/session-branch.js";import{spawnChildPrepared as p}from"../runtime/spawn.js";import{getComment as l}from"./comments.js";import{captureOrigin as _}from"./companion.js";import{requireVisibleReview as f}from"./store.js";import{ReviewOperationError as a}from"./types.js";function h(o,n){const{line:e,end_line:i}=n.anchor,t=i>e?`lines ${e}-${i}`:`line ${e}`,r=n.anchor_line_text===""?"":`
|
|
2
2
|
> ${n.anchor_line_text}
|
|
3
3
|
`;return[`The person handed you this one comment on \`${o.file}\` so it can be worked in parallel. The review companion you were forked from keeps the rest of the document.`,`${t}:${r}`,n.text,`Address it by editing only the lines this comment is about \u2014 other forks may be editing the same file \u2014 then resolve it with \`crtr human review comment resolve ${n.comment_id}\`, and tell the companion what changed with \`crtr push update\`.`].join(`
|
|
4
4
|
|
|
5
|
-
`)}d(h,"forkTask");async function R(o){const n=l(o);if(n===null)throw new a("unknown_comment","comment was not found",{received:o});if(n.status!=="open")throw new a("comment_deleted","only an open comment can be forked",{comment_id:o,status:n.status});const e=f(n.review_id);if(e.state!=="open")throw new a("review_terminal","review already has a terminal outcome",{state:e.state,requested:"fork",review:e});const i=s(e.companion_node_id);if(i===null)throw new a("review_companion_unbound","review companion is gone",{companion_node_id:e.companion_node_id});const t=await _(e.companion_node_id),r=
|
|
5
|
+
`)}d(h,"forkTask");async function R(o){const n=await l(o);if(n===null)throw new a("unknown_comment","comment was not found",{received:o});if(n.status!=="open")throw new a("comment_deleted","only an open comment can be forked",{comment_id:o,status:n.status});const e=await f(n.review_id);if(e.state!=="open")throw new a("review_terminal","review already has a terminal outcome",{state:e.state,requested:"fork",review:e});const i=await s(e.companion_node_id);if(i===null)throw new a("review_companion_unbound","review companion is gone",{companion_node_id:e.companion_node_id});const t=await _(e.companion_node_id),r=await w(t);return{node_id:(await p({kind:"review/companion",mode:"base",cwd:i.cwd,parent:e.companion_node_id,creator:e.companion_node_id,rootLifecycle:"resident",prompt:h(e,n),forkFrom:r,model:t.modelSpec,name:`comment on ${c(e.file)}`,reviewBinding:{review_id:e.review_id,origin_node_id:e.origin_node_id,branch_file:r,target_file:e.file}})).node.node_id,cwd:i.cwd}}d(R,"forkReviewComment");export{R as forkReviewComment};
|