@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,11 +1,11 @@
|
|
|
1
|
-
var
|
|
2
|
-
VALUES (?, ?, 'controller', ?, ?, ?, NULL)`).run(
|
|
1
|
+
var w=Object.defineProperty;var n=(t,e)=>w(t,"name",{value:e,configurable:!0});import{randomBytes as c}from"node:crypto";import{withCanvasWrite as E,openDb as d}from"./db.js";function s(t){if(t.kind!=="controller")throw new Error(`wait ${t.wait_id} is not a controller wait`);return{waitId:t.wait_id,nodeId:t.node_id,controllerId:t.target_id,generation:t.generation,createdAt:t.created_at,satisfiedAt:t.satisfied_at}}n(s,"waitFrom");function _(){let t;do t=c(16).toString("hex");while(t==="00000000000000000000000000000000");return t}n(_,"newWaitId");async function f(t,e,i=Date.now()){return await E(async a=>{await a.prepare("UPDATE waits SET satisfied_at = ? WHERE node_id = ? AND kind = 'controller' AND satisfied_at IS NULL").run(i,t);const r=Number((await a.prepare("SELECT COALESCE(MAX(generation), 0) AS generation FROM waits WHERE node_id = ? AND kind = 'controller'").get(t)).generation)+1,o={wait_id:_(),node_id:t,kind:"controller",target_id:e,generation:r,created_at:i,satisfied_at:null};return await a.prepare(`INSERT INTO waits (wait_id, node_id, kind, target_id, generation, created_at, satisfied_at)
|
|
2
|
+
VALUES (?, ?, 'controller', ?, ?, ?, NULL)`).run(o.wait_id,o.node_id,o.target_id,o.generation,o.created_at),s(o)})}n(f,"armControllerWait");async function p(t){const e=await(await d()).prepare("SELECT * FROM waits WHERE node_id = ? AND kind = 'controller' AND satisfied_at IS NULL").get(t);return e===void 0?null:s(e)}n(p,"readControllerWait");async function L(t,e,i,a){if(a??=await d(),e===null)return!1;const r=await a.prepare("SELECT wait_id, generation FROM waits WHERE node_id = ? AND kind = 'controller' AND target_id = ? AND satisfied_at IS NULL").get(t,e);return r===void 0?!1:Number((await a.prepare("UPDATE waits SET satisfied_at = ? WHERE wait_id = ? AND generation = ? AND satisfied_at IS NULL").run(i,r.wait_id,r.generation)).changes)===1}n(L,"settleMatchingControllerWait");async function g(t,e,i,a){a??=await d();const r=await a.prepare(`SELECT w.wait_id, w.generation, target.status AS controller_status
|
|
3
3
|
FROM waits w LEFT JOIN nodes target ON target.node_id = w.target_id
|
|
4
|
-
WHERE w.node_id = ? AND w.kind = 'controller' AND w.target_id = ? AND w.satisfied_at IS NULL`).get(t,e);return
|
|
4
|
+
WHERE w.node_id = ? AND w.kind = 'controller' AND w.target_id = ? AND w.satisfied_at IS NULL`).get(t,e);return r===void 0||r.controller_status==="active"||r.controller_status==="idle"?!1:Number((await a.prepare("UPDATE waits SET satisfied_at = ? WHERE wait_id = ? AND generation = ? AND satisfied_at IS NULL").run(i,r.wait_id,r.generation)).changes)===1}n(g,"settleDeadControllerWait");async function A(){return(await(await d()).prepare("SELECT * FROM waits WHERE kind = 'controller' AND satisfied_at IS NULL").all()).map(s)}n(A,"liveControllerWaits");async function D(t,e,i,a=Date.now()){await t.prepare(`INSERT INTO waits (wait_id, node_id, kind, target_id, generation, created_at, satisfied_at)
|
|
5
5
|
SELECT ?, ?, 'object', ?, 1, ?, NULL
|
|
6
|
-
WHERE NOT EXISTS (SELECT 1 FROM waits WHERE node_id = ? AND kind = 'object' AND target_id = ? AND satisfied_at IS NULL)`).run(
|
|
6
|
+
WHERE NOT EXISTS (SELECT 1 FROM waits WHERE node_id = ? AND kind = 'object' AND target_id = ? AND satisfied_at IS NULL)`).run(_(),e,i,a,e,i)}n(D,"armObjectWait");async function S(t,e,i=null,a=Date.now()){return Number(i===null?(await t.prepare("UPDATE waits SET satisfied_at = ? WHERE kind = 'object' AND target_id = ? AND satisfied_at IS NULL").run(a,e)).changes:(await t.prepare("UPDATE waits SET satisfied_at = ? WHERE kind = 'object' AND target_id = ? AND node_id = ? AND satisfied_at IS NULL").run(a,e,i)).changes)}n(S,"settleObjectWaits");async function T(t,e,i=Date.now()){return Number((await t.prepare("UPDATE waits SET satisfied_at = ? WHERE kind = 'object' AND node_id = ? AND satisfied_at IS NULL").run(i,e)).changes)}n(T,"settleNodeObjectWaits");async function R(t){return t??=await d(),(await t.prepare(`SELECT w.wait_id, w.node_id, w.target_id, w.created_at, o.type AS object_type, o.name AS object_name
|
|
7
7
|
FROM waits w JOIN objects o ON o.id = w.target_id
|
|
8
8
|
WHERE w.kind = 'object' AND w.satisfied_at IS NULL AND o.deleted_at IS NULL
|
|
9
|
-
ORDER BY w.node_id, w.created_at, w.rowid`).all().map(e=>({waitId:e.wait_id,nodeId:e.node_id,objectId:e.target_id,createdAt:e.created_at,objectType:e.object_type,objectName:e.object_name}))}
|
|
9
|
+
ORDER BY w.node_id, w.created_at, w.rowid`).all()).map(e=>({waitId:e.wait_id,nodeId:e.node_id,objectId:e.target_id,createdAt:e.created_at,objectType:e.object_type,objectName:e.object_name}))}n(R,"liveObjectWaitsNamed");async function W(t){return await(await d()).prepare("SELECT 1 FROM waits WHERE node_id = ? AND kind = 'object' AND satisfied_at IS NULL LIMIT 1").get(t)!==void 0}n(W,"hasLiveObjectWait");async function I(t){return await(await d()).prepare(`SELECT 1 FROM waits w JOIN nodes target ON target.node_id = w.target_id
|
|
10
10
|
WHERE w.node_id = ? AND w.kind = 'controller' AND w.satisfied_at IS NULL
|
|
11
|
-
AND target.status IN ('active', 'idle') LIMIT 1`).get(t)!==void 0}
|
|
11
|
+
AND target.status IN ('active', 'idle') LIMIT 1`).get(t)!==void 0}n(I,"hasLiveControllerWait");export{f as armControllerWait,D as armObjectWait,I as hasLiveControllerWait,W as hasLiveObjectWait,A as liveControllerWaits,R as liveObjectWaitsNamed,p as readControllerWait,g as settleDeadControllerWait,L as settleMatchingControllerWait,T as settleNodeObjectWaits,S as settleObjectWaits};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type CanvasDb } from './db.js';
|
|
2
2
|
import type { ManagedWorktree, ManagedWorktreeObservation } from './types.js';
|
|
3
3
|
export declare function worktreeFromRow(row: Record<string, unknown> | undefined): ManagedWorktree | null;
|
|
4
|
-
export declare function readWorktree(nodeId: string): ManagedWorktree | null
|
|
5
|
-
export declare function openWorktree(nodeId: string, worktree: ManagedWorktree, db?:
|
|
4
|
+
export declare function readWorktree(nodeId: string): Promise<ManagedWorktree | null>;
|
|
5
|
+
export declare function openWorktree(nodeId: string, worktree: ManagedWorktree, db?: CanvasDb): Promise<void>;
|
|
6
6
|
export declare function closeWorktree(nodeId: string, input: {
|
|
7
7
|
cleanup: 'pending' | 'complete';
|
|
8
8
|
closedAt: string;
|
|
9
|
-
}): void
|
|
9
|
+
}): Promise<void>;
|
|
10
10
|
/** Complete a worktree close and repoint the node in the same SQL transaction.
|
|
11
11
|
* A close invalidates the active transcript because Pi remains in the old
|
|
12
12
|
* checkout; the next launch starts from the durable base checkout. */
|
|
@@ -15,14 +15,14 @@ export declare function closeWorktreeAndRepoint(nodeId: string, input: {
|
|
|
15
15
|
cleanup: 'pending' | 'complete';
|
|
16
16
|
closedAt: string;
|
|
17
17
|
unbindSession: boolean;
|
|
18
|
-
}): void
|
|
19
|
-
export declare function abandonWorktree(nodeId: string, abandoned: NonNullable<ManagedWorktree['abandoned']>): void
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
export declare function abandonWorktree(nodeId: string, abandoned: NonNullable<ManagedWorktree['abandoned']>): Promise<void>;
|
|
20
20
|
export declare function abandonWorktreeAndRepoint(nodeId: string, input: {
|
|
21
21
|
cwd: string;
|
|
22
22
|
abandoned: NonNullable<ManagedWorktree['abandoned']>;
|
|
23
|
-
}): void
|
|
24
|
-
export declare function recordLandIntent(nodeId: string, intent: NonNullable<ManagedWorktree['land_intent']>): void
|
|
25
|
-
export declare function recordDisposalGrant(nodeId: string, disposal: NonNullable<ManagedWorktree['disposal']>): void
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
export declare function recordLandIntent(nodeId: string, intent: NonNullable<ManagedWorktree['land_intent']>): Promise<void>;
|
|
25
|
+
export declare function recordDisposalGrant(nodeId: string, disposal: NonNullable<ManagedWorktree['disposal']>): Promise<void>;
|
|
26
26
|
export declare function recordSweepAttempt(nodeId: string, input: {
|
|
27
27
|
reason: string;
|
|
28
28
|
detail?: string;
|
|
@@ -31,11 +31,11 @@ export declare function recordSweepAttempt(nodeId: string, input: {
|
|
|
31
31
|
lastAttemptAt: string;
|
|
32
32
|
nextAttemptAt: string;
|
|
33
33
|
quarantined: boolean;
|
|
34
|
-
}): void
|
|
35
|
-
export declare function completeCleanup(nodeId: string): void
|
|
36
|
-
export declare function hasUnreconciledWorktree(nodeId: string): boolean
|
|
37
|
-
export declare function sweepCandidates(now: string): string[]
|
|
38
|
-
export declare function quarantinedWorktrees(): Array<{
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
export declare function completeCleanup(nodeId: string): Promise<void>;
|
|
36
|
+
export declare function hasUnreconciledWorktree(nodeId: string): Promise<boolean>;
|
|
37
|
+
export declare function sweepCandidates(now: string): Promise<string[]>;
|
|
38
|
+
export declare function quarantinedWorktrees(): Promise<Array<{
|
|
39
39
|
nodeId: string;
|
|
40
40
|
worktree: ManagedWorktree;
|
|
41
|
-
}
|
|
41
|
+
}>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var p=Object.defineProperty;var a=(e,t)=>p(e,"name",{value:t,configurable:!0});import{openDb as s,withCanvasWrite as _}from"./db.js";import{flatMapAsync as i}from"../async-array.js";function d(e){const t=JSON.stringify(e);if(t===void 0)throw new TypeError("worktree value must be JSON-serializable");return t}a(d,"json");function o(e){if(typeof e=="string")return JSON.parse(e)}a(o,"parse");function l(e){if(e===void 0)return null;const t=o(e.sweep_observed_json),n=e.attempts,r=t===void 0?void 0:{reason:e.sweep_reason,...e.sweep_detail===null?{}:{detail:e.sweep_detail},observed:t,attempts:n,last_attempt:e.sweep_last_at,next_attempt:e.next_attempt_at,...e.quarantined===1?{quarantined:!0}:{}};return{state:e.state,...e.cleanup_state===null?{}:{cleanup:e.cleanup_state},path:e.path,branch:e.branch,repo_root:e.repo_root,base_ref:e.base_ref,base_sha:e.base_sha,created:e.created_at,...e.closed_at===null?{}:{closed:e.closed_at},...o(e.abandoned_json)===void 0?{}:{abandoned:o(e.abandoned_json)},...o(e.land_intent_json)===void 0?{}:{land_intent:o(e.land_intent_json)},...r===void 0?{}:{sweep:r},...o(e.disposal_json)===void 0?{}:{disposal:o(e.disposal_json)}}}a(l,"worktreeFromRow");async function c(e){return l(await(await s()).prepare("SELECT * FROM worktrees WHERE node_id = ?").get(e))}a(c,"readWorktree");async function w(e,t,n){n??=await s(),await n.prepare("INSERT INTO worktrees (node_id, state, cleanup_state, path, branch, repo_root, base_ref, base_sha, created_at, closed_at, next_attempt_at, attempts, quarantined, sweep_reason, sweep_detail, sweep_last_at, sweep_observed_json, abandoned_json, land_intent_json, disposal_json) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL)").run(e,t.state,t.cleanup??null,t.path,t.branch,t.repo_root,t.base_ref,t.base_sha,t.created,t.closed??null)}a(w,"openWorktree");async function N(e,t){await(await s()).prepare("UPDATE worktrees SET state = 'closed', cleanup_state = ?, closed_at = ?, land_intent_json = NULL, sweep_reason = NULL, sweep_detail = NULL, sweep_last_at = NULL, sweep_observed_json = NULL, next_attempt_at = NULL, attempts = 0, quarantined = 0 WHERE node_id = ?").run(t.cleanup,t.closedAt,e)}a(N,"closeWorktree");async function U(e,t){await _(async n=>{await n.prepare("UPDATE nodes SET cwd = ? WHERE node_id = ?").run(t.cwd,e),t.unbindSession&&await n.prepare("UPDATE sessions SET unbound_at = ? WHERE node_id = ? AND unbound_at IS NULL").run(t.closedAt,e),await n.prepare("UPDATE worktrees SET state = 'closed', cleanup_state = ?, closed_at = ?, land_intent_json = NULL, sweep_reason = NULL, sweep_detail = NULL, sweep_last_at = NULL, sweep_observed_json = NULL, next_attempt_at = NULL, attempts = 0, quarantined = 0 WHERE node_id = ?").run(t.cleanup,t.closedAt,e)})}a(U,"closeWorktreeAndRepoint");async function f(e,t){await(await s()).prepare("UPDATE worktrees SET state = 'abandoned', abandoned_json = ? WHERE node_id = ? AND abandoned_json IS NULL").run(d(t),e)}a(f,"abandonWorktree");async function b(e,t){await _(async n=>{await n.prepare("UPDATE nodes SET cwd = ? WHERE node_id = ?").run(t.cwd,e),await n.prepare("UPDATE worktrees SET state = 'abandoned', abandoned_json = ? WHERE node_id = ? AND abandoned_json IS NULL").run(d(t.abandoned),e)})}a(b,"abandonWorktreeAndRepoint");async function A(e,t){await(await s()).prepare("UPDATE worktrees SET land_intent_json = ? WHERE node_id = ? AND land_intent_json IS NULL").run(d(t),e)}a(A,"recordLandIntent");async function m(e,t){await(await s()).prepare("UPDATE worktrees SET disposal_json = ? WHERE node_id = ? AND disposal_json IS NULL").run(d(t),e)}a(m,"recordDisposalGrant");async function R(e,t){await(await s()).prepare("UPDATE worktrees SET sweep_reason = ?, sweep_detail = ?, sweep_observed_json = ?, attempts = ?, sweep_last_at = ?, next_attempt_at = ?, quarantined = ? WHERE node_id = ?").run(t.reason,t.detail??null,d(t.observed),t.attempts,t.lastAttemptAt,t.nextAttemptAt,t.quarantined?1:0,e)}a(R,"recordSweepAttempt");async function S(e){await(await s()).prepare("UPDATE worktrees SET state = 'closed', cleanup_state = 'complete', sweep_reason = NULL, sweep_detail = NULL, sweep_last_at = NULL, sweep_observed_json = NULL, next_attempt_at = NULL, attempts = 0, quarantined = 0 WHERE node_id = ?").run(e)}a(S,"completeCleanup");async function T(e){return await(await s()).prepare("SELECT 1 FROM worktrees WHERE node_id = ? AND state != 'abandoned' AND (state = 'open' OR cleanup_state IS NULL OR cleanup_state != 'complete')").get(e)!==void 0}a(T,"hasUnreconciledWorktree");async function D(e){return(await(await s()).prepare("SELECT w.node_id FROM worktrees w JOIN nodes n ON n.node_id = w.node_id WHERE n.status IN ('done', 'dead', 'canceled') AND n.frozen_at IS NULL AND w.state IN ('open', 'closed') AND (w.state = 'open' OR w.cleanup_state IS NULL OR w.cleanup_state != 'complete') AND (w.state = 'closed' OR (n.status = 'done' AND n.final_report IS NOT NULL)) AND (w.next_attempt_at IS NULL OR w.next_attempt_at <= ?) ORDER BY w.next_attempt_at, w.node_id").all(e)).map(({node_id:t})=>t)}a(D,"sweepCandidates");async function j(){return await i(await(await s()).prepare("SELECT node_id FROM worktrees WHERE quarantined = 1 ORDER BY sweep_last_at").all(),async({node_id:e})=>{const t=await c(e);return t===null?[]:[{nodeId:e,worktree:t}]})}a(j,"quarantinedWorktrees");export{f as abandonWorktree,b as abandonWorktreeAndRepoint,N as closeWorktree,U as closeWorktreeAndRepoint,S as completeCleanup,T as hasUnreconciledWorktree,w as openWorktree,j as quarantinedWorktrees,c as readWorktree,m as recordDisposalGrant,A as recordLandIntent,R as recordSweepAttempt,D as sweepCandidates,l as worktreeFromRow};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export declare const LIFECYCLE_CATALOG: {
|
|
2
2
|
readonly 'node:create': {
|
|
3
3
|
readonly phase: "before";
|
|
4
|
-
readonly hookTimeoutMs:
|
|
5
|
-
readonly eventBudgetMs:
|
|
4
|
+
readonly hookTimeoutMs: 15000;
|
|
5
|
+
readonly eventBudgetMs: 30000;
|
|
6
6
|
};
|
|
7
7
|
readonly 'node:start': {
|
|
8
8
|
readonly phase: "on";
|
|
9
|
-
readonly hookTimeoutMs:
|
|
10
|
-
readonly eventBudgetMs:
|
|
9
|
+
readonly hookTimeoutMs: 15000;
|
|
10
|
+
readonly eventBudgetMs: 30000;
|
|
11
11
|
};
|
|
12
12
|
readonly 'node:close': {
|
|
13
13
|
readonly phase: "on";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var n=Object.defineProperty;var t=(e,s)=>n(e,"name",{value:s,configurable:!0});const o={"node:create":{phase:"before",hookTimeoutMs:
|
|
1
|
+
var n=Object.defineProperty;var t=(e,s)=>n(e,"name",{value:s,configurable:!0});const o={"node:create":{phase:"before",hookTimeoutMs:15e3,eventBudgetMs:3e4},"node:start":{phase:"on",hookTimeoutMs:15e3,eventBudgetMs:3e4},"node:close":{phase:"on",hookTimeoutMs:12e4,eventBudgetMs:18e4}},r=Object.freeze(Object.keys(o));function u(e){return Object.hasOwn(o,e)}t(u,"isLifecycleEvent");export{o as LIFECYCLE_CATALOG,r as LIFECYCLE_EVENTS,u as isLifecycleEvent};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var M=Object.defineProperty;var c=(e,t)=>M(e,"name",{value:t,configurable:!0});import{randomBytes as k}from"node:crypto";import{spawn as _}from"node:child_process";import{PROCESS_GROUP_KILL_GRACE_MS as S,posixProcessGroupSpawnOptions as R,terminateProcessGroup as V}from"../../../hook-process.js";import{isRecord as L}from"../../../shared/predicates.js";import{diag as x}from"../../io.js";import{LIFECYCLE_CATALOG as O}from"../lifecycle-catalog.js";import{getNode as A}from"../../canvas/canvas.js";import{buildAppProcessEnv as C}from"../../runtime/spawn-env.js";import{appProcessSandboxed as D,launchAppProcess as G}from"../../spaces/process.js";const P=10*1024*1024;async function H(e,t,n){try{const r=await B(e,t,n);r.ok||x(`crtr: ${g(e)} failed: ${r.error.code}: ${r.error.message}`)}catch(r){x(`crtr: ${g(e)} failed: ${w(r)}`)}}c(H,"invokeLifecycleHook");async function te(e,t){if(e.length===0)return;const{hookTimeoutMs:n,eventBudgetMs:r}=O[e[0].event],s=Date.now()+r;for(const o of e){const a=s-Date.now(),u=Math.min(n,a-S);if(u<=0){x(`crtr: lifecycle hook event ${o.event} exceeded its ${r}ms aggregate budget; skipped ${g(o)}`);return}await H(o,t,u)}}c(te,"invokeLifecycleHooks");async function re(e,t){if(e.length===0)return null;const{hookTimeoutMs:n,eventBudgetMs:r}=O["node:create"],s=Date.now()+r;for(const o of e){const a=s-Date.now(),u=Math.min(n,a-S);if(u<=0)return T(o,`lifecycle hook event node:create exceeded its ${r}ms aggregate budget`);try{const i=await B(o,t,u);if(!i.ok)return{hook:o,message:i.error.message,next:i.error.next??E(o)}}catch(i){return T(o,w(i))}}return null}c(re,"invokeBlockingLifecycleHooks");function T(e,t){return{hook:e,message:`${g(e)} failed: ${t}`,next:E(e)}}c(T,"refusal");function ne(e){return E(e)}c(ne,"lifecycleHookAttribution");async function B(e,t,n){const r=e.event==="node:create"?N(e,t):I(e,t),s=D()?await J(e,t,JSON.stringify(r),n):await q(e,JSON.stringify(r),n);if(s.signal!==null)throw new Error(`executable was killed by signal ${s.signal}`);const o=K(s.stdout);return o.ok&&s.status!==0&&x(`crtr: ${g(e)} returned ok:true but exited ${s.status} (honoring the envelope)`),o}c(B,"executeLifecycleHook");function I(e,t){return{protocolVersion:1,op:e.op,event:e.event,phase:e.phase,operationId:k(16).toString("hex"),node:t.node,runtime:t.runtime,context:{cwd:t.node.cwd}}}c(I,"nodeRequest");function N(e,t){return{protocolVersion:1,op:e.op,event:"node:create",phase:"before",operationId:k(16).toString("hex"),create:t.create,runtime:t.runtime,context:{cwd:t.create.cwd}}}c(N,"createRequest");async function J(e,t,n,r){const s=e.event==="node:create",o=s?t.create.cwd:t.node.cwd,a=s?void 0:t.node.id,u=s?t.app:A(a)?.grantee;if(!u)throw new Error(`missing app for lifecycle hook ${e.event}`);const i=C(o,t.runtime.profile,u),m=await G({...s?{app:u}:{nodeId:a},command:[e.executable,"--crtr-hook-protocol","1"],cwd:e.plugin.root,pluginRoot:e.plugin.root,env:i,stdin:n,stdoutBytes:P,stderrBytes:64*1024});let l;try{const p=await Promise.race([m.completion,new Promise((b,f)=>{l=setTimeout(()=>{m.stop().then(()=>f(new Error(`executable timed out after ${r}ms`)),f)},r)})]);if(p.stdoutTruncated)throw new Error("stdout exceeded the 10 MiB cap");return{stdout:p.stdout,status:p.exitCode,signal:p.signal}}finally{l&&clearTimeout(l)}}c(J,"runSandboxedLifecycleProcess");async function q(e,t,n){let r;try{r=_(e.executable,["--crtr-hook-protocol","1"],{cwd:e.plugin.root,env:process.env,stdio:["pipe","pipe","inherit"],...R()})}catch(s){throw new Error(`executable could not be run (${w(s)})`)}return new Promise((s,o)=>{let a=0;const u=[];let i,m=!1,l=!1,p=null,b=null,f;const y=c(()=>{if(!(!m||i!==void 0&&!l)){if(f!==void 0&&clearTimeout(f),i?.kind==="timeout")return o(new Error(`executable timed out after ${n}ms`));if(i?.kind==="output_limit")return o(new Error("stdout exceeded the 10 MiB cap"));if(i?.kind==="spawn")return o(new Error(`executable could not be run (${w(i.error)})`));if(i?.kind==="cleanup")return o(new Error(`executable cleanup failed (${w(i.error)})`));s({stdout:Buffer.concat(u).toString("utf8"),status:p,signal:b})}},"finish"),$=c(d=>{i===void 0&&(i=d,f!==void 0&&clearTimeout(f),V(r).then(()=>{l=!0,y()},h=>{i={kind:"cleanup",error:h},l=!0,y()}))},"terminate");r.stdout.on("data",d=>{if(a+=d.byteLength,a>P)return $({kind:"output_limit"});u.push(d)}),r.once("error",d=>{if(r.pid===void 0){i={kind:"spawn",error:d},m=!0,l=!0,y();return}$({kind:"spawn",error:d})}),r.once("close",(d,h)=>{p=d,b=h,m=!0,y()}),f=setTimeout(()=>$({kind:"timeout"}),n),r.stdin.end(t)})}c(q,"runLifecycleProcess");function K(e){let t;try{t=JSON.parse(e.trim())}catch{throw new Error("stdout was not a single JSON envelope")}if(!L(t)||t.protocolVersion!==1)throw new Error("stdout was not a protocolVersion: 1 envelope");if(t.ok===!0&&v(t,["protocolVersion","ok"]))return{protocolVersion:1,ok:!0};if(t.ok!==!1||!v(t,["protocolVersion","ok","error"]))throw new Error("response envelope had missing or extra fields");const n=t.error;if(!L(n)||!v(n,["code","message"],["next"])||typeof n.code!="string"||n.code===""||typeof n.message!="string"||n.message===""||n.next!==void 0&&typeof n.next!="string")throw new Error("failure envelope had invalid error fields");return{protocolVersion:1,ok:!1,error:{code:n.code,message:n.message,...n.next===void 0?{}:{next:n.next}}}}c(K,"parseEnvelope");function v(e,t,n=[]){return t.every(r=>Object.hasOwn(e,r))&&Object.keys(e).every(r=>t.includes(r)||n.includes(r))}c(v,"exactKeys");function g(e){return`plugin "${e.plugin.name}" lifecycle hook "${e.op}" for ${e.event}`}c(g,"label");function E(e){return`Refused by plugin ${e.plugin.name}, op ${e.op}.`}c(E,"attribution");function w(e){return e instanceof Error?e.message:String(e)}c(w,"describeError");export{re as invokeBlockingLifecycleHooks,H as invokeLifecycleHook,te as invokeLifecycleHooks,ne as lifecycleHookAttribution};
|
|
1
|
+
var M=Object.defineProperty;var c=(e,t)=>M(e,"name",{value:t,configurable:!0});import{randomBytes as k}from"node:crypto";import{spawn as _}from"node:child_process";import{PROCESS_GROUP_KILL_GRACE_MS as S,posixProcessGroupSpawnOptions as R,terminateProcessGroup as V}from"../../../hook-process.js";import{isRecord as L}from"../../../shared/predicates.js";import{diag as x}from"../../io.js";import{LIFECYCLE_CATALOG as O}from"../lifecycle-catalog.js";import{getNode as A}from"../../canvas/canvas.js";import{buildAppProcessEnv as C}from"../../runtime/spawn-env.js";import{appProcessSandboxed as D,launchAppProcess as G}from"../../spaces/process.js";const P=10*1024*1024;async function H(e,t,n){try{const r=await B(e,t,n);r.ok||x(`crtr: ${g(e)} failed: ${r.error.code}: ${r.error.message}`)}catch(r){x(`crtr: ${g(e)} failed: ${w(r)}`)}}c(H,"invokeLifecycleHook");async function te(e,t){if(e.length===0)return;const{hookTimeoutMs:n,eventBudgetMs:r}=O[e[0].event],s=Date.now()+r;for(const o of e){const a=s-Date.now(),u=Math.min(n,a-S);if(u<=0){x(`crtr: lifecycle hook event ${o.event} exceeded its ${r}ms aggregate budget; skipped ${g(o)}`);return}await H(o,t,u)}}c(te,"invokeLifecycleHooks");async function re(e,t){if(e.length===0)return null;const{hookTimeoutMs:n,eventBudgetMs:r}=O["node:create"],s=Date.now()+r;for(const o of e){const a=s-Date.now(),u=Math.min(n,a-S);if(u<=0)return T(o,`lifecycle hook event node:create exceeded its ${r}ms aggregate budget`);try{const i=await B(o,t,u);if(!i.ok)return{hook:o,message:i.error.message,next:i.error.next??E(o)}}catch(i){return T(o,w(i))}}return null}c(re,"invokeBlockingLifecycleHooks");function T(e,t){return{hook:e,message:`${g(e)} failed: ${t}`,next:E(e)}}c(T,"refusal");function ne(e){return E(e)}c(ne,"lifecycleHookAttribution");async function B(e,t,n){const r=e.event==="node:create"?N(e,t):I(e,t),s=D()?await J(e,t,JSON.stringify(r),n):await q(e,JSON.stringify(r),n);if(s.signal!==null)throw new Error(`executable was killed by signal ${s.signal}`);const o=K(s.stdout);return o.ok&&s.status!==0&&x(`crtr: ${g(e)} returned ok:true but exited ${s.status} (honoring the envelope)`),o}c(B,"executeLifecycleHook");function I(e,t){return{protocolVersion:1,op:e.op,event:e.event,phase:e.phase,operationId:k(16).toString("hex"),node:t.node,runtime:t.runtime,context:{cwd:t.node.cwd}}}c(I,"nodeRequest");function N(e,t){return{protocolVersion:1,op:e.op,event:"node:create",phase:"before",operationId:k(16).toString("hex"),create:t.create,runtime:t.runtime,context:{cwd:t.create.cwd}}}c(N,"createRequest");async function J(e,t,n,r){const s=e.event==="node:create",o=s?t.create.cwd:t.node.cwd,a=s?void 0:t.node.id,u=s?t.app:(await A(a))?.grantee;if(!u)throw new Error(`missing app for lifecycle hook ${e.event}`);const i=C(o,t.runtime.profile,u),m=await G({...s?{app:u}:{nodeId:a},command:[e.executable,"--crtr-hook-protocol","1"],cwd:e.plugin.root,pluginRoot:e.plugin.root,env:i,stdin:n,stdoutBytes:P,stderrBytes:64*1024});let l;try{const p=await Promise.race([m.completion,new Promise((b,f)=>{l=setTimeout(()=>{m.stop().then(()=>f(new Error(`executable timed out after ${r}ms`)),f)},r)})]);if(p.stdoutTruncated)throw new Error("stdout exceeded the 10 MiB cap");return{stdout:p.stdout,status:p.exitCode,signal:p.signal}}finally{l&&clearTimeout(l)}}c(J,"runSandboxedLifecycleProcess");async function q(e,t,n){let r;try{r=_(e.executable,["--crtr-hook-protocol","1"],{cwd:e.plugin.root,env:process.env,stdio:["pipe","pipe","inherit"],...R()})}catch(s){throw new Error(`executable could not be run (${w(s)})`)}return new Promise((s,o)=>{let a=0;const u=[];let i,m=!1,l=!1,p=null,b=null,f;const y=c(()=>{if(!(!m||i!==void 0&&!l)){if(f!==void 0&&clearTimeout(f),i?.kind==="timeout")return o(new Error(`executable timed out after ${n}ms`));if(i?.kind==="output_limit")return o(new Error("stdout exceeded the 10 MiB cap"));if(i?.kind==="spawn")return o(new Error(`executable could not be run (${w(i.error)})`));if(i?.kind==="cleanup")return o(new Error(`executable cleanup failed (${w(i.error)})`));s({stdout:Buffer.concat(u).toString("utf8"),status:p,signal:b})}},"finish"),$=c(d=>{i===void 0&&(i=d,f!==void 0&&clearTimeout(f),V(r).then(()=>{l=!0,y()},h=>{i={kind:"cleanup",error:h},l=!0,y()}))},"terminate");r.stdout.on("data",d=>{if(a+=d.byteLength,a>P)return $({kind:"output_limit"});u.push(d)}),r.once("error",d=>{if(r.pid===void 0){i={kind:"spawn",error:d},m=!0,l=!0,y();return}$({kind:"spawn",error:d})}),r.once("close",(d,h)=>{p=d,b=h,m=!0,y()}),f=setTimeout(()=>$({kind:"timeout"}),n),r.stdin.end(t)})}c(q,"runLifecycleProcess");function K(e){let t;try{t=JSON.parse(e.trim())}catch{throw new Error("stdout was not a single JSON envelope")}if(!L(t)||t.protocolVersion!==1)throw new Error("stdout was not a protocolVersion: 1 envelope");if(t.ok===!0&&v(t,["protocolVersion","ok"]))return{protocolVersion:1,ok:!0};if(t.ok!==!1||!v(t,["protocolVersion","ok","error"]))throw new Error("response envelope had missing or extra fields");const n=t.error;if(!L(n)||!v(n,["code","message"],["next"])||typeof n.code!="string"||n.code===""||typeof n.message!="string"||n.message===""||n.next!==void 0&&typeof n.next!="string")throw new Error("failure envelope had invalid error fields");return{protocolVersion:1,ok:!1,error:{code:n.code,message:n.message,...n.next===void 0?{}:{next:n.next}}}}c(K,"parseEnvelope");function v(e,t,n=[]){return t.every(r=>Object.hasOwn(e,r))&&Object.keys(e).every(r=>t.includes(r)||n.includes(r))}c(v,"exactKeys");function g(e){return`plugin "${e.plugin.name}" lifecycle hook "${e.op}" for ${e.event}`}c(g,"label");function E(e){return`Refused by plugin ${e.plugin.name}, op ${e.op}.`}c(E,"attribution");function w(e){return e instanceof Error?e.message:String(e)}c(w,"describeError");export{re as invokeBlockingLifecycleHooks,H as invokeLifecycleHook,te as invokeLifecycleHooks,ne as lifecycleHookAttribution};
|
|
@@ -2,7 +2,7 @@ import { type ValidatedCommandManifest } from '../../api/command-manifest/manife
|
|
|
2
2
|
import type { KindConfig, MemoryExtensionDeclarations, ObjectKindDeclaration, PageComponentRegistration, PluginBundle, PluginManifest, Scope } from '../../types.js';
|
|
3
3
|
import { type BundleTransport } from './endpoint.js';
|
|
4
4
|
/** Who may call a capability provider's tool group (contract 3). */
|
|
5
|
-
export type ProviderGroupWho = 'own' | 'user' | 'allowlist' | 'any'
|
|
5
|
+
export type ProviderGroupWho = 'own' | 'user' | 'allowlist' | 'any' | `team:${string}`;
|
|
6
6
|
/** One tool group a capability provider declares in `bundle.json`. */
|
|
7
7
|
export interface ProviderGroupDeclaration {
|
|
8
8
|
group: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var P=Object.defineProperty;var c=(e,o)=>P(e,"name",{value:o,configurable:!0});import{Parser as J}from"tar";import{createHash as I}from"node:crypto";import{chmodSync as W,renameSync as k}from"node:fs";import{dirname as $,join as w,resolve as B,sep as V}from"node:path";import{validateCommandManifest as z}from"../../api/command-manifest/manifest.js";import{ensureScopeInitialized as R,invalidPluginKindsReasons as F,readConfig as M,updateConfig as D,updateState as C}from"../config.js";import{general as x}from"../errors.js";import{atomicWriteJson as T,atomicWriteText as q,ensureDir as j,nowIso as E,pathExists as _,removePath as S,syncDirectory as U,syncTree as H}from"../fs-utils.js";import{invalidPageComponentsReasons as K,normalizePageComponents as G}from"../human/page-catalog.js";import{validateMemoryExtensionDeclarations as X}from"../plugin-extensions.js";import{objectBlocksShapeReasons as Z}from"../plugin-objects-manifest.js";import{validateBundleTransport as L}from"./endpoint.js";const O=/^[A-Za-z0-9_-]{1,64}$/,Y=new Set(["id","major","groups"]),Q=new Set(["group","consent_line","rate","who","allowlist"]),ee=new Set(["own","user","allowlist","any"]),ne=new Set(["bundleVersion","kinds","page_components","memory_extensions","version","transport","provider","object_kinds","scopes","groups"]);function oe(e,o,n,r,s,a){return{code:e,message:o,received:n,expected:r,next:s,...a!==void 0?{path:a}:{}}}c(oe,"issue");function u(e,o,n,r,s){return oe("plugin_bundle_invalid",e,o,n,r,s)}c(u,"bundleInvalid");function re(e){if(e[0]===31&&e[1]===139)return u("bundle archive must be uncompressed tar data","gzip-compressed archive","an uncompressed tar archive","Serve the archive without compression.");if(e.length===0||e.length%512!==0)return u("bundle archive must be a non-empty whole number of 512-byte tar blocks",`${e.length} bytes`,"a non-empty tar stream with a 512-byte block length","Serve one complete uncompressed tar archive.");if(e.length<1024||!e.subarray(-1024).every(o=>o===0))return u("bundle archive is missing the required two zero-block terminator","archive tail is not 1024 zero bytes","a complete tar stream ending in two 512-byte zero blocks","Serve the complete uncompressed tar archive.")}c(re,"archiveEnvelopeIssue");function se(e,o){if(e.length===0||e.includes("\0")||e.includes("\\")||e.startsWith("/")||/^[A-Za-z]:($|\/)/.test(e))return u("bundle member path must be a safe relative POSIX path",e,"a relative path without absolute, drive-letter, backslash, or NUL forms","Use a safe relative POSIX member path.",e);if(o==="file"&&e.endsWith("/"))return u("only directory members may have a trailing slash",e,"a regular-file path without a trailing slash","Emit this member as a regular file path.",e);if((o==="directory"&&e.endsWith("/")?e.slice(0,-1):e).split("/").some(r=>r===""||r==="."||r===".."))return u("bundle member path contains an unsafe segment",e,"non-empty segments other than . or ..","Use a safe relative POSIX member path.",e)}c(se,"validateMemberName");function te(e,o){if(o==="file")return e==="bundle.json"||e==="commands.json"||e==="hooks.json"||e.startsWith("memory/")&&e.endsWith(".md")||e.startsWith("hooks/")?void 0:u("bundle contains an unsupported file member",e,"bundle.json, commands.json, hooks.json, memory/**/*.md, or hooks/**","Remove unsupported members from the archive.",e);if(!(e==="memory"||e.startsWith("memory/")||e==="hooks"||e.startsWith("hooks/")))return u("bundle contains an unsupported directory member",e,"memory or hooks, or a directory below either subtree","Remove unsupported directory members from the archive.",e)}c(te,"validateMemberShape");function ie(e){return e.type==="directory"&&e.path.endsWith("/")?e.path.slice(0,-1):e.path}c(ie,"materializedPath");function de(e){const o=new Map;for(const n of e){const r=ie(n),s=o.get(r);if(s!==void 0)return u(s===n.type?"bundle contains a duplicate member":"bundle claims one path as both a file and a directory",`${r} (${s} and ${n.type})`,"each materialized path exactly once, with one type","Emit each archive path once, as a single member type.",r);o.set(r,n.type)}for(const[n,r]of o)if(r==="file"){for(const s of o.keys())if(s.startsWith(`${n}/`))return u("bundle nests a member beneath a regular-file path",`${s} beneath file ${n}`,"members nested only beneath directory paths","Emit the parent path as a directory or remove the nested member.",s)}}c(de,"validateMemberTree");async function ae(e){const o=[],n=new Set;let r;return await new Promise((s,a)=>{const p=new J({strict:!0,maxMetaEntrySize:Number.MAX_SAFE_INTEGER,gzip:!1,brotli:!1,zstd:!1,onReadEntry:c(t=>{const d=t.path,f=t.type==="File"||t.type==="OldFile"?"file":t.type==="Directory"?"directory":void 0;if(f===void 0||t.unsupported||t.ignore||t.linkpath!==void 0){r??=u("bundle member must be a regular file or directory without a link target",`${d} (${t.type})`,"a regular file or directory member without link metadata","Remove links and unsupported member types from the archive.",d),t.resume();return}r??=se(d,f),r??=te(d,f),n.has(d)&&(r??=u("bundle contains a duplicate member",d,"each member path exactly once","Emit each archive member only once.",d)),n.add(d);const i=[];t.on("data",b=>i.push(b)),t.on("end",()=>{r===void 0&&o.push({path:d,type:f,bytes:new Uint8Array(Buffer.concat(i))})})},"onReadEntry")});p.on("ignoredEntry",t=>{const d=t.path;r??=u("bundle contains an ignored or unsupported archive member",`${d} (${t.type})`,"only supported regular file or directory members","Remove ignored or unsupported members from the archive.",d),t.resume()}),p.once("error",a),p.once("end",s);try{p.end(Buffer.from(e))}catch(t){a(t)}}).catch(s=>{r??=u("bundle archive could not be parsed",s instanceof Error?s.message:String(s),"a valid complete uncompressed tar archive","Fix the archive format and serve it again.")}),r===void 0?{members:o}:{issue:r}}c(ae,"parseArchive");function N(e){return typeof e=="number"&&Number.isInteger(e)&&e>=1}c(N,"isPositiveInt");function ue(e){const o=c((t,d,f,i)=>({issue:u(t,d,f,"Fix the provider block in bundle.json.",`bundle.json.${i}`)}),"bad");if(typeof e!="object"||e===null||Array.isArray(e))return o("bundle.json provider must be an object",JSON.stringify(e),"{ id, major, groups }","provider");const n=e,r=Object.keys(n).filter(t=>!Y.has(t));if(r.length>0)return o("bundle.json provider has unknown keys",r.join(", "),"only: id, major, groups","provider");if(typeof n.id!="string"||!O.test(n.id))return o("provider id must match [A-Za-z0-9_-]{1,64}",JSON.stringify(n.id),'a provider id of 1-64 letters, digits, "_" or "-"',"provider.id");if(!N(n.major))return o("provider major must be an integer of at least 1",JSON.stringify(n.major),"the served major as an integer >= 1","provider.major");const s=n.groups;if(!Array.isArray(s)||s.length===0)return o("provider groups must be a non-empty array",JSON.stringify(s),"at least one { group, consent_line, rate?, who, allowlist }","provider.groups");const a=[],p=new Set;for(let t=0;t<s.length;t++){const d=`provider.groups[${t}]`,f=s[t];if(typeof f!="object"||f===null||Array.isArray(f))return o("provider group must be an object",JSON.stringify(f),"{ group, consent_line, rate?, who, allowlist }",d);const i=f,b=Object.keys(i).filter(v=>!Q.has(v));if(b.length>0)return o("provider group has unknown keys",b.join(", "),"only: group, consent_line, rate, who, allowlist",d);if(typeof i.group!="string"||!O.test(i.group))return o("provider group id must match [A-Za-z0-9_-]{1,64}",JSON.stringify(i.group),'a group id of 1-64 letters, digits, "_" or "-"',`${d}.group`);if(p.has(i.group))return o("provider group ids must be unique",i.group,"each group declared once",`${d}.group`);if(p.add(i.group),typeof i.consent_line!="string"||i.consent_line.trim().length===0)return o("provider group consent_line must be a non-empty string",JSON.stringify(i.consent_line),"the consent line shown for this group",`${d}.consent_line`);const h=i.rate;if(h!=null&&(typeof h!="number"||!Number.isFinite(h)||h<0))return o("provider group rate must be a non-negative number or null",JSON.stringify(h),"a finite number >= 0, null, or omitted",`${d}.rate`);if(typeof i.who!="string"||!ee.has(i.who))return o("provider group who must be own|user|allowlist|any",JSON.stringify(i.who),"own | user | allowlist | any",`${d}.who`);const m=i.allowlist;if(!Array.isArray(m)||!m.every(v=>typeof v=="string"&&v.length>0))return o("provider group allowlist must be an array of non-empty strings",JSON.stringify(m),"an array of app principals ([] unless who is allowlist)",`${d}.allowlist`);if(m.length>0&&i.who!=="allowlist")return o("provider group allowlist must be empty unless who is allowlist",`who ${i.who}`,'who: "allowlist", or allowlist: []',`${d}.allowlist`);a.push({group:i.group,consent_line:i.consent_line,...h!==void 0?{rate:h}:{},who:i.who,allowlist:m})}return{provider:{id:n.id,major:n.major,groups:a}}}c(ue,"parseProviderBlock");function le(e){const o=[],n=c((r,s)=>{const a=[...s,r.name];if(r.kind==="leaf")o.push({path:a.join(" "),leaf:r});else for(const p of r.children)n(p,a)},"walk");for(const r of e.roots)n(r,[]);for(const r of e.coreMounts)n(r.node,r.parent);return o}c(le,"collectLeaves");function pe(e,o){const n=e.provider;if(n===void 0)return;if(e.transport===void 0)return u("a provider bundle must declare its transport","(missing)",'transport { kind: "http", endpoint } in bundle.json',"Add the provider endpoint as bundle.json transport.","bundle.json.transport");if(e.transport.kind==="http"&&e.transport.authEnv!==void 0)return u("a provider bundle must not declare authEnv",e.transport.authEnv,"no authEnv: the runtime presents its own outbound token","Remove transport.authEnv from bundle.json.","bundle.json.transport.authEnv");const r=new Set(n.groups.map(s=>s.group));for(const{path:s,leaf:a}of le(o)){const p="group"in a?a.group:void 0;if(p===void 0)return u(`provider leaf "${s}" has no group`,s,"a group on every leaf of a provider bundle",`Add a group to leaf "${s}".`,`commands.json:${s}.group`);if(!r.has(p))return u(`provider leaf "${s}" names undeclared group "${p}"`,p,`one of: ${[...r].join(", ")}`,`Declare group "${p}" in the provider block, or move leaf "${s}" to a declared group.`,`commands.json:${s}.group`);if("rest"in a&&a.rest.streaming===!0)return u(`provider leaf "${s}" streams`,"rest.streaming: true","no streaming leaves in a provider bundle",`Make leaf "${s}" return one response.`,`commands.json:${s}.rest.streaming`)}}c(pe,"providerBundleIssue");function ce(e){let o;try{o=JSON.parse(Buffer.from(e).toString("utf8"))}catch{return{issue:u("bundle.json is not valid JSON","invalid JSON",'{"bundleVersion":1}',"Write valid bundle metadata.","bundle.json")}}if(typeof o!="object"||o===null||Array.isArray(o))return{issue:u("bundle.json must be a JSON object",JSON.stringify(o),"an object with bundleVersion set to 1 and optionally kinds",'Set bundle.json to {"bundleVersion":1}.',"bundle.json")};const n=o,r=Object.keys(n).filter(d=>!ne.has(d));if(n.bundleVersion!==1||r.length>0)return{issue:u("bundle.json must contain bundleVersion 1 and at most version, transport, provider, kinds, page_components, memory_extensions, object_kinds, scopes, and groups",JSON.stringify(o),"an object with bundleVersion set to 1 and optional version, transport, provider, kinds, page_components, memory_extensions, object_kinds, scopes, and groups",'Set bundle.json to {"bundleVersion":1} plus optional contribution blocks.',"bundle.json")};if(n.kinds!==void 0){const d=F(n.kinds);if(d.length>0)return{issue:u("bundle.json kinds block is invalid",d.join("; "),"each entry a full KindConfig (whenToUse required) or a sparse patch of launch fields","Fix the kinds entries in bundle.json.","bundle.json")}}if(n.page_components!==void 0){const d=K(n.page_components);if(d.length>0)return{issue:u("bundle.json page_components block is invalid",d.join("; "),"an array of page component registrations, each a kind string or {kind, description?, useWhen?, doc?, display?}","Fix the page_components entries in bundle.json.","bundle.json")}}const s=Z(n);if(n.provider!==void 0&&n.scopes!==void 0&&s.push("scopes is for local plugins; a provider gets its scopes from directory consent"),s.length>0)return{issue:u("bundle.json object_kinds or scopes block is invalid",s.join("; "),"object_kinds keyed by kind name with description, events and optional read.command; scopes an array of crtr:objects:<verb>:<target> strings (local plugins only)","Fix the object_kinds and scopes blocks in bundle.json.","bundle.json")};let a;if(n.memory_extensions!==void 0)try{a=X(n.memory_extensions)}catch(d){return{issue:u("bundle.json memory_extensions block is invalid",d instanceof Error?d.message:String(d),"a valid memory_extensions declaration object","Fix the memory_extensions declarations in bundle.json.","bundle.json")}}if(n.version!==void 0&&!N(n.version))return{issue:u("bundle.json version must be an integer of at least 1",JSON.stringify(n.version),"the plugin major as an integer >= 1, or omitted","Fix version in bundle.json.","bundle.json.version")};let p;if(n.transport!==void 0){const d=L(n.transport);if(d.transport===void 0)return{issue:u("bundle.json transport is invalid",d.errors.join("; "),'{ kind: "http", endpoint, authEnv? } or { kind: "machine" }',"Fix transport in bundle.json.","bundle.json.transport")};p=d.transport}let t;if(n.provider!==void 0){const d=ue(n.provider);if(d.issue!==void 0)return{issue:d.issue};if(t=d.provider,n.version!==void 0&&n.version!==t.major)return{issue:u("bundle.json provider major must equal version",`version ${String(n.version)}, major ${t.major}`,"one major","Set provider.major and version to the same integer.","bundle.json.provider.major")}}return{...n.version!==void 0?{version:n.version}:{},...p!==void 0?{transport:p}:{},...t!==void 0?{provider:t}:{},...n.kinds!==void 0?{kinds:n.kinds}:{},...n.page_components!==void 0?{page_components:G(n.page_components)}:{},...a!==void 0?{memory_extensions:a}:{},...n.object_kinds!==void 0?{object_kinds:n.object_kinds}:{},...n.scopes!==void 0?{scopes:n.scopes}:{}}}c(ce,"parseBundleMetadata");function me(e,o,n,r=new Set){let s;try{s=JSON.parse(Buffer.from(e).toString("utf8"))}catch{return{issues:[u("commands.json is not valid JSON","invalid JSON","a valid command-manifest JSON object","Regenerate commands.json.","commands.json")]}}const a=z(s,{transport:"http",reservedCoreNames:o,extensibleCoreBranches:r,...n!==void 0?{coreCommandPaths:n}:{}});return{...a.manifest!==void 0?{commands:a.manifest}:{},issues:a.issues}}c(me,"parseCommands");async function fe(e,o){const n=re(e);if(n!==void 0)return{issues:[n]};const r=await ae(e);if(r.issue!==void 0||r.members===void 0)return{issues:[r.issue]};const s=de(r.members);if(s!==void 0)return{issues:[s]};const a=r.members.find(l=>l.path==="bundle.json"&&l.type==="file"),p=r.members.find(l=>l.path==="commands.json"&&l.type==="file");if(a===void 0||p===void 0)return{issues:[u("bundle must contain exactly one bundle.json and one commands.json regular file",`bundle.json=${a!==void 0}, commands.json=${p!==void 0}`,"one regular bundle.json and one regular commands.json member","Add the required metadata members to the archive.")]};const t=r.members.find(l=>l.path==="hooks.json"&&l.type==="file"),d=r.members.filter(l=>l.type==="file"&&l.path.startsWith("hooks/"));if((t!==void 0||r.members.some(l=>l.path==="hooks"||l.path.startsWith("hooks/")))&&(t===void 0||!d.some(l=>l.path==="hooks/dispatch")))return{issues:[u("bundle hook payload must contain both hooks.json and hooks/dispatch regular files",`hooks.json=${t!==void 0}, hooks/dispatch=${d.some(l=>l.path==="hooks/dispatch")}`,"both hooks.json and hooks/dispatch regular files","Add both required hook members or remove the hook payload.")]};const i=ce(a.bytes);if(i.issue!==void 0)return{issues:[i.issue]};const b=me(p.bytes,o.reservedCoreNames,o.coreCommandPaths,o.extensibleCoreBranches);if(b.commands===void 0)return{issues:b.issues};const h=b.commands.version;if(i.version!==void 0&&h!==void 0&&i.version!==h)return{issues:[u("bundle.json version and commands.json version differ",`bundle.json ${i.version}, commands.json ${h}`,"one plugin major","Emit the same version in bundle.json and commands.json.","bundle.json.version")]};const m=i.version??h;if(i.provider!==void 0&&m===void 0)return{issues:[u("a provider bundle requires a plugin version","no version in bundle.json or commands.json",`version ${i.provider.major}, the provider major`,"Emit the provider major as the plugin version.","bundle.json.version")]};if(i.provider!==void 0&&m!==i.provider.major)return{issues:[u("bundle provider major must equal the plugin version",`version ${m}, major ${i.provider.major}`,"one major","Emit the provider major as the plugin version.","bundle.json.provider.major")]};const v=pe(i,b.commands);return v!==void 0?{issues:[v]}:{bundle:{bundleVersion:1,...m!==void 0?{version:m}:{},...i.transport!==void 0?{transport:i.transport}:{},...i.provider!==void 0?{provider:i.provider}:{},...i.kinds!==void 0?{kinds:i.kinds}:{},...i.page_components!==void 0?{page_components:i.page_components}:{},...i.memory_extensions!==void 0?{memory_extensions:i.memory_extensions}:{},...i.object_kinds!==void 0?{object_kinds:i.object_kinds}:{},...i.scopes!==void 0?{scopes:i.scopes}:{},commands:b.commands,commandsBytes:p.bytes,directories:r.members.filter(l=>l.type==="directory").map(l=>({path:l.path})),memory:r.members.filter(l=>l.type==="file"&&l.path.startsWith("memory/")).map(l=>({path:l.path,bytes:l.bytes})),...t!==void 0?{hooks:{manifest:t.bytes,files:d.map(l=>({path:l.path,bytes:l.bytes}))}}:{}},issues:[]}}c(fe,"validatePluginBundle");function he(e){return I("sha256").update(e).digest("hex").slice(0,12)}c(he,"bundleVersion");function Pe(e,o,n,r){return M(o).plugins[e]?.version!==r?!1:_(w(n,"commands.json"))}c(Pe,"isInstalledGeneration");function be(e,o,n,r){C(e,s=>{s.plugins[o]===void 0&&(s.plugins[o]={}),r.swapped&&(s.plugins[o].last_updated=E()),s.plugins[o].checked_at=E(),n===void 0?delete s.plugins[o].etag:s.plugins[o].etag=n})}c(be,"recordCheckedGeneration");function g(e,o){const n=B(e,o);if(n===e||!n.startsWith(e+V))throw x(`bundle member path escapes the staging directory: ${o}`);return n}c(g,"stagedPath");function ve(e,o,n){const r=c((s,a,p=420)=>q(s,a,{mode:p,durable:!0}),"write");T(g(e,".crouter-plugin/plugin.json"),o,{durable:!0});for(const s of n.directories)j(g(e,s.path));r(g(e,"commands.json"),n.commandsBytes);for(const s of n.memory)r(g(e,s.path),s.bytes);if(n.hooks!==void 0){r(g(e,"hooks.json"),n.hooks.manifest);for(const s of n.hooks.files)r(g(e,s.path),s.bytes);W(g(e,"hooks/dispatch"),493)}H(e)}c(ve,"writeStagedBundle");async function Je(e,o,n){const{scope:r,scopeRootPath:s,root:a}=n,p=await fe(o,n.validation);if(p.bundle===void 0)throw n.invalid(`HTTP plugin bundle for "${e}" is invalid`,p.issues);const t=p.bundle,d=n.accept?.(t);if(d!==void 0)throw n.invalid(`HTTP plugin bundle for "${e}" is invalid`,[u(d,e,"the bundle this install asked for","Serve the requested bundle.")]);const f=n.version??he(o),i=t.provider!==void 0&&t.transport!==void 0?t.transport:n.transport,b={name:e,version:f,commands:"commands.json",transport:i,bundle:n.bundle,...t.kinds!==void 0?{kinds:t.kinds}:{},...t.page_components!==void 0?{page_components:t.page_components}:{},...t.memory_extensions!==void 0?{memory_extensions:t.memory_extensions}:{},...t.object_kinds!==void 0?{object_kinds:t.object_kinds}:{},...t.scopes!==void 0?{scopes:t.scopes}:{},...t.hooks!==void 0?{hooks:"hooks.json",hookExecutable:"hooks/dispatch"}:{},...t.provider!==void 0?{provider:t.provider}:{}},h=w(s,"tmp"),m=w(h,`${e}.${process.pid}`),v=`${m}.prev`;if(_(v))throw x(`cannot replace plugin "${e}": prior interrupted replacement remains at ${v}`);j(h),j($(a)),S(m);let l;try{j(m),ve(m,b,t),l=await n.validateStaged(m,b);let y=!1;_(a)&&(k(a,v),y=!0);try{k(m,a)}catch(A){throw y&&k(v,a),A}U($(a)),y&&S(v)}finally{S(m)}return R(r,s),D(r,y=>{y.plugins[e]={enabled:n.enable?!0:y.plugins[e]?.enabled??!0,version:f}}),be(r,e,n.etag,{swapped:!0}),{manifest:b,validated:t,version:f,root:a,staged:l}}c(Je,"installBundleArchive");export{he as bundleVersion,Je as installBundleArchive,Pe as isInstalledGeneration,be as recordCheckedGeneration,fe as validatePluginBundle,ve as writeStagedBundle};
|
|
1
|
+
var P=Object.defineProperty;var c=(e,o)=>P(e,"name",{value:o,configurable:!0});import{Parser as J}from"tar";import{createHash as I}from"node:crypto";import{chmodSync as W,renameSync as k}from"node:fs";import{dirname as $,join as w,resolve as V,sep as z}from"node:path";import{validateCommandManifest as B}from"../../api/command-manifest/manifest.js";import{ensureScopeInitialized as R,invalidPluginKindsReasons as F,readConfig as M,updateConfig as D,updateState as T}from"../config.js";import{general as x}from"../errors.js";import{atomicWriteJson as C,atomicWriteText as q,ensureDir as j,nowIso as E,pathExists as _,removePath as S,syncDirectory as H,syncTree as U}from"../fs-utils.js";import{invalidPageComponentsReasons as K,normalizePageComponents as G}from"../human/page-catalog.js";import{validateMemoryExtensionDeclarations as X}from"../plugin-extensions.js";import{objectBlocksShapeReasons as Z}from"../plugin-objects-manifest.js";import{validateBundleTransport as L}from"./endpoint.js";const O=/^[A-Za-z0-9_-]{1,64}$/,Y=new Set(["id","major","groups"]),Q=new Set(["group","consent_line","rate","who","allowlist"]),ee=new Set(["own","user","allowlist","any"]),ne=/^team:[a-z0-9]+$/,oe=new Set(["bundleVersion","kinds","page_components","memory_extensions","version","transport","provider","object_kinds","scopes","groups"]);function re(e,o,n,r,s,a){return{code:e,message:o,received:n,expected:r,next:s,...a!==void 0?{path:a}:{}}}c(re,"issue");function u(e,o,n,r,s){return re("plugin_bundle_invalid",e,o,n,r,s)}c(u,"bundleInvalid");function se(e){if(e[0]===31&&e[1]===139)return u("bundle archive must be uncompressed tar data","gzip-compressed archive","an uncompressed tar archive","Serve the archive without compression.");if(e.length===0||e.length%512!==0)return u("bundle archive must be a non-empty whole number of 512-byte tar blocks",`${e.length} bytes`,"a non-empty tar stream with a 512-byte block length","Serve one complete uncompressed tar archive.");if(e.length<1024||!e.subarray(-1024).every(o=>o===0))return u("bundle archive is missing the required two zero-block terminator","archive tail is not 1024 zero bytes","a complete tar stream ending in two 512-byte zero blocks","Serve the complete uncompressed tar archive.")}c(se,"archiveEnvelopeIssue");function te(e,o){if(e.length===0||e.includes("\0")||e.includes("\\")||e.startsWith("/")||/^[A-Za-z]:($|\/)/.test(e))return u("bundle member path must be a safe relative POSIX path",e,"a relative path without absolute, drive-letter, backslash, or NUL forms","Use a safe relative POSIX member path.",e);if(o==="file"&&e.endsWith("/"))return u("only directory members may have a trailing slash",e,"a regular-file path without a trailing slash","Emit this member as a regular file path.",e);if((o==="directory"&&e.endsWith("/")?e.slice(0,-1):e).split("/").some(r=>r===""||r==="."||r===".."))return u("bundle member path contains an unsafe segment",e,"non-empty segments other than . or ..","Use a safe relative POSIX member path.",e)}c(te,"validateMemberName");function ie(e,o){if(o==="file")return e==="bundle.json"||e==="commands.json"||e==="hooks.json"||e.startsWith("memory/")&&e.endsWith(".md")||e.startsWith("hooks/")?void 0:u("bundle contains an unsupported file member",e,"bundle.json, commands.json, hooks.json, memory/**/*.md, or hooks/**","Remove unsupported members from the archive.",e);if(!(e==="memory"||e.startsWith("memory/")||e==="hooks"||e.startsWith("hooks/")))return u("bundle contains an unsupported directory member",e,"memory or hooks, or a directory below either subtree","Remove unsupported directory members from the archive.",e)}c(ie,"validateMemberShape");function de(e){return e.type==="directory"&&e.path.endsWith("/")?e.path.slice(0,-1):e.path}c(de,"materializedPath");function ae(e){const o=new Map;for(const n of e){const r=de(n),s=o.get(r);if(s!==void 0)return u(s===n.type?"bundle contains a duplicate member":"bundle claims one path as both a file and a directory",`${r} (${s} and ${n.type})`,"each materialized path exactly once, with one type","Emit each archive path once, as a single member type.",r);o.set(r,n.type)}for(const[n,r]of o)if(r==="file"){for(const s of o.keys())if(s.startsWith(`${n}/`))return u("bundle nests a member beneath a regular-file path",`${s} beneath file ${n}`,"members nested only beneath directory paths","Emit the parent path as a directory or remove the nested member.",s)}}c(ae,"validateMemberTree");async function ue(e){const o=[],n=new Set;let r;return await new Promise((s,a)=>{const p=new J({strict:!0,maxMetaEntrySize:Number.MAX_SAFE_INTEGER,gzip:!1,brotli:!1,zstd:!1,onReadEntry:c(t=>{const d=t.path,f=t.type==="File"||t.type==="OldFile"?"file":t.type==="Directory"?"directory":void 0;if(f===void 0||t.unsupported||t.ignore||t.linkpath!==void 0){r??=u("bundle member must be a regular file or directory without a link target",`${d} (${t.type})`,"a regular file or directory member without link metadata","Remove links and unsupported member types from the archive.",d),t.resume();return}r??=te(d,f),r??=ie(d,f),n.has(d)&&(r??=u("bundle contains a duplicate member",d,"each member path exactly once","Emit each archive member only once.",d)),n.add(d);const i=[];t.on("data",b=>i.push(b)),t.on("end",()=>{r===void 0&&o.push({path:d,type:f,bytes:new Uint8Array(Buffer.concat(i))})})},"onReadEntry")});p.on("ignoredEntry",t=>{const d=t.path;r??=u("bundle contains an ignored or unsupported archive member",`${d} (${t.type})`,"only supported regular file or directory members","Remove ignored or unsupported members from the archive.",d),t.resume()}),p.once("error",a),p.once("end",s);try{p.end(Buffer.from(e))}catch(t){a(t)}}).catch(s=>{r??=u("bundle archive could not be parsed",s instanceof Error?s.message:String(s),"a valid complete uncompressed tar archive","Fix the archive format and serve it again.")}),r===void 0?{members:o}:{issue:r}}c(ue,"parseArchive");function N(e){return typeof e=="number"&&Number.isInteger(e)&&e>=1}c(N,"isPositiveInt");function le(e){const o=c((t,d,f,i)=>({issue:u(t,d,f,"Fix the provider block in bundle.json.",`bundle.json.${i}`)}),"bad");if(typeof e!="object"||e===null||Array.isArray(e))return o("bundle.json provider must be an object",JSON.stringify(e),"{ id, major, groups }","provider");const n=e,r=Object.keys(n).filter(t=>!Y.has(t));if(r.length>0)return o("bundle.json provider has unknown keys",r.join(", "),"only: id, major, groups","provider");if(typeof n.id!="string"||!O.test(n.id))return o("provider id must match [A-Za-z0-9_-]{1,64}",JSON.stringify(n.id),'a provider id of 1-64 letters, digits, "_" or "-"',"provider.id");if(!N(n.major))return o("provider major must be an integer of at least 1",JSON.stringify(n.major),"the served major as an integer >= 1","provider.major");const s=n.groups;if(!Array.isArray(s)||s.length===0)return o("provider groups must be a non-empty array",JSON.stringify(s),"at least one { group, consent_line, rate?, who, allowlist }","provider.groups");const a=[],p=new Set;for(let t=0;t<s.length;t++){const d=`provider.groups[${t}]`,f=s[t];if(typeof f!="object"||f===null||Array.isArray(f))return o("provider group must be an object",JSON.stringify(f),"{ group, consent_line, rate?, who, allowlist }",d);const i=f,b=Object.keys(i).filter(v=>!Q.has(v));if(b.length>0)return o("provider group has unknown keys",b.join(", "),"only: group, consent_line, rate, who, allowlist",d);if(typeof i.group!="string"||!O.test(i.group))return o("provider group id must match [A-Za-z0-9_-]{1,64}",JSON.stringify(i.group),'a group id of 1-64 letters, digits, "_" or "-"',`${d}.group`);if(p.has(i.group))return o("provider group ids must be unique",i.group,"each group declared once",`${d}.group`);if(p.add(i.group),typeof i.consent_line!="string"||i.consent_line.trim().length===0)return o("provider group consent_line must be a non-empty string",JSON.stringify(i.consent_line),"the consent line shown for this group",`${d}.consent_line`);const h=i.rate;if(h!=null&&(typeof h!="number"||!Number.isFinite(h)||h<0))return o("provider group rate must be a non-negative number or null",JSON.stringify(h),"a finite number >= 0, null, or omitted",`${d}.rate`);if(typeof i.who!="string"||!(ee.has(i.who)||ne.test(i.who)))return o("provider group who must be own|user|allowlist|any|team:<id>",JSON.stringify(i.who),"own | user | allowlist | any | team:<id> (id of lowercase letters and digits)",`${d}.who`);const m=i.allowlist;if(!Array.isArray(m)||!m.every(v=>typeof v=="string"&&v.length>0))return o("provider group allowlist must be an array of non-empty strings",JSON.stringify(m),"an array of app principals ([] unless who is allowlist)",`${d}.allowlist`);if(m.length>0&&i.who!=="allowlist")return o("provider group allowlist must be empty unless who is allowlist",`who ${i.who}`,'who: "allowlist", or allowlist: []',`${d}.allowlist`);a.push({group:i.group,consent_line:i.consent_line,...h!==void 0?{rate:h}:{},who:i.who,allowlist:m})}return{provider:{id:n.id,major:n.major,groups:a}}}c(le,"parseProviderBlock");function pe(e){const o=[],n=c((r,s)=>{const a=[...s,r.name];if(r.kind==="leaf")o.push({path:a.join(" "),leaf:r});else for(const p of r.children)n(p,a)},"walk");for(const r of e.roots)n(r,[]);for(const r of e.coreMounts)n(r.node,r.parent);return o}c(pe,"collectLeaves");function ce(e,o){const n=e.provider;if(n===void 0)return;if(e.transport===void 0)return u("a provider bundle must declare its transport","(missing)",'transport { kind: "http", endpoint } in bundle.json',"Add the provider endpoint as bundle.json transport.","bundle.json.transport");if(e.transport.kind==="http"&&e.transport.authEnv!==void 0)return u("a provider bundle must not declare authEnv",e.transport.authEnv,"no authEnv: the runtime presents its own outbound token","Remove transport.authEnv from bundle.json.","bundle.json.transport.authEnv");const r=new Set(n.groups.map(s=>s.group));for(const{path:s,leaf:a}of pe(o)){const p="group"in a?a.group:void 0;if(p===void 0)return u(`provider leaf "${s}" has no group`,s,"a group on every leaf of a provider bundle",`Add a group to leaf "${s}".`,`commands.json:${s}.group`);if(!r.has(p))return u(`provider leaf "${s}" names undeclared group "${p}"`,p,`one of: ${[...r].join(", ")}`,`Declare group "${p}" in the provider block, or move leaf "${s}" to a declared group.`,`commands.json:${s}.group`);if("rest"in a&&a.rest.streaming===!0)return u(`provider leaf "${s}" streams`,"rest.streaming: true","no streaming leaves in a provider bundle",`Make leaf "${s}" return one response.`,`commands.json:${s}.rest.streaming`)}}c(ce,"providerBundleIssue");function me(e){let o;try{o=JSON.parse(Buffer.from(e).toString("utf8"))}catch{return{issue:u("bundle.json is not valid JSON","invalid JSON",'{"bundleVersion":1}',"Write valid bundle metadata.","bundle.json")}}if(typeof o!="object"||o===null||Array.isArray(o))return{issue:u("bundle.json must be a JSON object",JSON.stringify(o),"an object with bundleVersion set to 1 and optionally kinds",'Set bundle.json to {"bundleVersion":1}.',"bundle.json")};const n=o,r=Object.keys(n).filter(d=>!oe.has(d));if(n.bundleVersion!==1||r.length>0)return{issue:u("bundle.json must contain bundleVersion 1 and at most version, transport, provider, kinds, page_components, memory_extensions, object_kinds, scopes, and groups",JSON.stringify(o),"an object with bundleVersion set to 1 and optional version, transport, provider, kinds, page_components, memory_extensions, object_kinds, scopes, and groups",'Set bundle.json to {"bundleVersion":1} plus optional contribution blocks.',"bundle.json")};if(n.kinds!==void 0){const d=F(n.kinds);if(d.length>0)return{issue:u("bundle.json kinds block is invalid",d.join("; "),"each entry a full KindConfig (whenToUse required) or a sparse patch of launch fields","Fix the kinds entries in bundle.json.","bundle.json")}}if(n.page_components!==void 0){const d=K(n.page_components);if(d.length>0)return{issue:u("bundle.json page_components block is invalid",d.join("; "),"an array of page component registrations, each a kind string or {kind, description?, useWhen?, doc?, display?}","Fix the page_components entries in bundle.json.","bundle.json")}}const s=Z(n);if(n.provider!==void 0&&n.scopes!==void 0&&s.push("scopes is for local plugins; a provider gets its scopes from directory consent"),s.length>0)return{issue:u("bundle.json object_kinds or scopes block is invalid",s.join("; "),"object_kinds keyed by kind name with description, events and optional read.command; scopes an array of crtr:objects:<verb>:<target> strings (local plugins only)","Fix the object_kinds and scopes blocks in bundle.json.","bundle.json")};let a;if(n.memory_extensions!==void 0)try{a=X(n.memory_extensions)}catch(d){return{issue:u("bundle.json memory_extensions block is invalid",d instanceof Error?d.message:String(d),"a valid memory_extensions declaration object","Fix the memory_extensions declarations in bundle.json.","bundle.json")}}if(n.version!==void 0&&!N(n.version))return{issue:u("bundle.json version must be an integer of at least 1",JSON.stringify(n.version),"the plugin major as an integer >= 1, or omitted","Fix version in bundle.json.","bundle.json.version")};let p;if(n.transport!==void 0){const d=L(n.transport);if(d.transport===void 0)return{issue:u("bundle.json transport is invalid",d.errors.join("; "),'{ kind: "http", endpoint, authEnv? } or { kind: "machine" }',"Fix transport in bundle.json.","bundle.json.transport")};p=d.transport}let t;if(n.provider!==void 0){const d=le(n.provider);if(d.issue!==void 0)return{issue:d.issue};if(t=d.provider,n.version!==void 0&&n.version!==t.major)return{issue:u("bundle.json provider major must equal version",`version ${String(n.version)}, major ${t.major}`,"one major","Set provider.major and version to the same integer.","bundle.json.provider.major")}}return{...n.version!==void 0?{version:n.version}:{},...p!==void 0?{transport:p}:{},...t!==void 0?{provider:t}:{},...n.kinds!==void 0?{kinds:n.kinds}:{},...n.page_components!==void 0?{page_components:G(n.page_components)}:{},...a!==void 0?{memory_extensions:a}:{},...n.object_kinds!==void 0?{object_kinds:n.object_kinds}:{},...n.scopes!==void 0?{scopes:n.scopes}:{}}}c(me,"parseBundleMetadata");function fe(e,o,n,r=new Set){let s;try{s=JSON.parse(Buffer.from(e).toString("utf8"))}catch{return{issues:[u("commands.json is not valid JSON","invalid JSON","a valid command-manifest JSON object","Regenerate commands.json.","commands.json")]}}const a=B(s,{transport:"http",reservedCoreNames:o,extensibleCoreBranches:r,...n!==void 0?{coreCommandPaths:n}:{}});return{...a.manifest!==void 0?{commands:a.manifest}:{},issues:a.issues}}c(fe,"parseCommands");async function he(e,o){const n=se(e);if(n!==void 0)return{issues:[n]};const r=await ue(e);if(r.issue!==void 0||r.members===void 0)return{issues:[r.issue]};const s=ae(r.members);if(s!==void 0)return{issues:[s]};const a=r.members.find(l=>l.path==="bundle.json"&&l.type==="file"),p=r.members.find(l=>l.path==="commands.json"&&l.type==="file");if(a===void 0||p===void 0)return{issues:[u("bundle must contain exactly one bundle.json and one commands.json regular file",`bundle.json=${a!==void 0}, commands.json=${p!==void 0}`,"one regular bundle.json and one regular commands.json member","Add the required metadata members to the archive.")]};const t=r.members.find(l=>l.path==="hooks.json"&&l.type==="file"),d=r.members.filter(l=>l.type==="file"&&l.path.startsWith("hooks/"));if((t!==void 0||r.members.some(l=>l.path==="hooks"||l.path.startsWith("hooks/")))&&(t===void 0||!d.some(l=>l.path==="hooks/dispatch")))return{issues:[u("bundle hook payload must contain both hooks.json and hooks/dispatch regular files",`hooks.json=${t!==void 0}, hooks/dispatch=${d.some(l=>l.path==="hooks/dispatch")}`,"both hooks.json and hooks/dispatch regular files","Add both required hook members or remove the hook payload.")]};const i=me(a.bytes);if(i.issue!==void 0)return{issues:[i.issue]};const b=fe(p.bytes,o.reservedCoreNames,o.coreCommandPaths,o.extensibleCoreBranches);if(b.commands===void 0)return{issues:b.issues};const h=b.commands.version;if(i.version!==void 0&&h!==void 0&&i.version!==h)return{issues:[u("bundle.json version and commands.json version differ",`bundle.json ${i.version}, commands.json ${h}`,"one plugin major","Emit the same version in bundle.json and commands.json.","bundle.json.version")]};const m=i.version??h;if(i.provider!==void 0&&m===void 0)return{issues:[u("a provider bundle requires a plugin version","no version in bundle.json or commands.json",`version ${i.provider.major}, the provider major`,"Emit the provider major as the plugin version.","bundle.json.version")]};if(i.provider!==void 0&&m!==i.provider.major)return{issues:[u("bundle provider major must equal the plugin version",`version ${m}, major ${i.provider.major}`,"one major","Emit the provider major as the plugin version.","bundle.json.provider.major")]};const v=ce(i,b.commands);return v!==void 0?{issues:[v]}:{bundle:{bundleVersion:1,...m!==void 0?{version:m}:{},...i.transport!==void 0?{transport:i.transport}:{},...i.provider!==void 0?{provider:i.provider}:{},...i.kinds!==void 0?{kinds:i.kinds}:{},...i.page_components!==void 0?{page_components:i.page_components}:{},...i.memory_extensions!==void 0?{memory_extensions:i.memory_extensions}:{},...i.object_kinds!==void 0?{object_kinds:i.object_kinds}:{},...i.scopes!==void 0?{scopes:i.scopes}:{},commands:b.commands,commandsBytes:p.bytes,directories:r.members.filter(l=>l.type==="directory").map(l=>({path:l.path})),memory:r.members.filter(l=>l.type==="file"&&l.path.startsWith("memory/")).map(l=>({path:l.path,bytes:l.bytes})),...t!==void 0?{hooks:{manifest:t.bytes,files:d.map(l=>({path:l.path,bytes:l.bytes}))}}:{}},issues:[]}}c(he,"validatePluginBundle");function be(e){return I("sha256").update(e).digest("hex").slice(0,12)}c(be,"bundleVersion");function Je(e,o,n,r){return M(o).plugins[e]?.version!==r?!1:_(w(n,"commands.json"))}c(Je,"isInstalledGeneration");function ve(e,o,n,r){T(e,s=>{s.plugins[o]===void 0&&(s.plugins[o]={}),r.swapped&&(s.plugins[o].last_updated=E()),s.plugins[o].checked_at=E(),n===void 0?delete s.plugins[o].etag:s.plugins[o].etag=n})}c(ve,"recordCheckedGeneration");function g(e,o){const n=V(e,o);if(n===e||!n.startsWith(e+z))throw x(`bundle member path escapes the staging directory: ${o}`);return n}c(g,"stagedPath");function ge(e,o,n){const r=c((s,a,p=420)=>q(s,a,{mode:p,durable:!0}),"write");C(g(e,".crouter-plugin/plugin.json"),o,{durable:!0});for(const s of n.directories)j(g(e,s.path));r(g(e,"commands.json"),n.commandsBytes);for(const s of n.memory)r(g(e,s.path),s.bytes);if(n.hooks!==void 0){r(g(e,"hooks.json"),n.hooks.manifest);for(const s of n.hooks.files)r(g(e,s.path),s.bytes);W(g(e,"hooks/dispatch"),493)}U(e)}c(ge,"writeStagedBundle");async function Ie(e,o,n){const{scope:r,scopeRootPath:s,root:a}=n,p=await he(o,n.validation);if(p.bundle===void 0)throw n.invalid(`HTTP plugin bundle for "${e}" is invalid`,p.issues);const t=p.bundle,d=n.accept?.(t);if(d!==void 0)throw n.invalid(`HTTP plugin bundle for "${e}" is invalid`,[u(d,e,"the bundle this install asked for","Serve the requested bundle.")]);const f=n.version??be(o),i=t.provider!==void 0&&t.transport!==void 0?t.transport:n.transport,b={name:e,version:f,commands:"commands.json",transport:i,bundle:n.bundle,...t.kinds!==void 0?{kinds:t.kinds}:{},...t.page_components!==void 0?{page_components:t.page_components}:{},...t.memory_extensions!==void 0?{memory_extensions:t.memory_extensions}:{},...t.object_kinds!==void 0?{object_kinds:t.object_kinds}:{},...t.scopes!==void 0?{scopes:t.scopes}:{},...t.hooks!==void 0?{hooks:"hooks.json",hookExecutable:"hooks/dispatch"}:{},...t.provider!==void 0?{provider:t.provider}:{}},h=w(s,"tmp"),m=w(h,`${e}.${process.pid}`),v=`${m}.prev`;if(_(v))throw x(`cannot replace plugin "${e}": prior interrupted replacement remains at ${v}`);j(h),j($(a)),S(m);let l;try{j(m),ge(m,b,t),l=await n.validateStaged(m,b);let y=!1;_(a)&&(k(a,v),y=!0);try{k(m,a)}catch(A){throw y&&k(v,a),A}H($(a)),y&&S(v)}finally{S(m)}return R(r,s),D(r,y=>{y.plugins[e]={enabled:n.enable?!0:y.plugins[e]?.enabled??!0,version:f}}),ve(r,e,n.etag,{swapped:!0}),{manifest:b,validated:t,version:f,root:a,staged:l}}c(Ie,"installBundleArchive");export{be as bundleVersion,Ie as installBundleArchive,Je as isInstalledGeneration,ve as recordCheckedGeneration,he as validatePluginBundle,ge as writeStagedBundle};
|
|
@@ -15,16 +15,16 @@ export type ConversationWrite = {
|
|
|
15
15
|
kind: 'replace';
|
|
16
16
|
};
|
|
17
17
|
/** One coherent write: the canvas step, `write()` (returns the new file size), then commit. */
|
|
18
|
-
export type AppendSection = (conversationId: string, change: ConversationWrite, write: () => number) => void
|
|
18
|
+
export type AppendSection = (conversationId: string, change: ConversationWrite, write: () => number) => Promise<void>;
|
|
19
19
|
/** The canvas side of the store: the write section, and each conversation's current owner. */
|
|
20
20
|
export interface ConversationCanvas {
|
|
21
21
|
appendSection: AppendSection;
|
|
22
|
-
owners(): Map<string, string
|
|
23
|
-
createPath?(nodeId: string, header: SessionHeader): string
|
|
24
|
-
pathFor?(id: string): string | undefined
|
|
25
|
-
repair?(id: string, path: string): void
|
|
26
|
-
abortCreate?(id: string): void
|
|
27
|
-
delete?(id: string): void
|
|
22
|
+
owners(): Promise<Map<string, string>>;
|
|
23
|
+
createPath?(nodeId: string, header: SessionHeader): Promise<string>;
|
|
24
|
+
pathFor?(id: string): Promise<string | undefined>;
|
|
25
|
+
repair?(id: string, path: string): Promise<void>;
|
|
26
|
+
abortCreate?(id: string): Promise<void>;
|
|
27
|
+
delete?(id: string): Promise<void>;
|
|
28
28
|
}
|
|
29
29
|
export declare function sessionDirectory(root: string, cwd: string): string;
|
|
30
30
|
export declare function createFileStore(root: string, canvas: ConversationCanvas): ConversationStore & {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var G=Object.defineProperty;var u=(l,
|
|
2
|
-
`))if(
|
|
3
|
-
`);for(;
|
|
4
|
-
`)}}}finally{v(
|
|
5
|
-
`).join("")}u(C,"lines");function W(l,
|
|
6
|
-
`)},"slice"),s=
|
|
7
|
-
`));return g[0]?.type==="session"&&g.shift(),{header:r,entries:g,tail:E(
|
|
8
|
-
`)),path:n}}finally{v(i)}}u(H,"readWindow");function D(e,t,r,n,
|
|
9
|
-
`).join("")),k(i),S(n).size}finally{v(i)}})}catch(i){throw
|
|
1
|
+
var G=Object.defineProperty;var u=(l,o)=>G(l,"name",{value:o,configurable:!0});import{randomUUID as J}from"node:crypto";import{closeSync as v,createReadStream as K,existsSync as $,fsyncSync as k,mkdirSync as L,openSync as z,readFileSync as P,readSync as M,renameSync as Q,statSync as S,unlinkSync as O,writeFileSync as j}from"node:fs";import{createInterface as T}from"node:readline";import{dirname as V,join as F,relative as X,resolve as b}from"node:path";import{SessionManager as Y}from"@earendil-works/pi-coding-agent";import{ConversationNotFoundError as Z}from"./index.js";function E(l){const o=[];for(const w of l.split(`
|
|
2
|
+
`))if(w.trim())try{o.push(JSON.parse(w))}catch{}return o}u(E,"parseLines");function I(l){const o=z(l,"r");try{const w=Buffer.allocUnsafe(4096);let f="";for(;;){const h=M(o,w,0,w.length,null);f+=w.toString("utf8",0,h);let y=f.indexOf(`
|
|
3
|
+
`);for(;y!==-1||h===0;){const m=y===-1?f:f.slice(0,y),[d]=E(m);if(d!==void 0)return d;if(y===-1)return;f=f.slice(y+1),y=f.indexOf(`
|
|
4
|
+
`)}}}finally{v(o)}}u(I,"firstLine");function ee(l,o){const w=z(l,"r");try{const f=Buffer.alloc(1);return M(w,f,0,1,o-1),f[0]}finally{v(w)}}u(ee,"lastByte");function C(l,o){return[l,...o].map(w=>`${JSON.stringify(w)}
|
|
5
|
+
`).join("")}u(C,"lines");function W(l,o){const w=`--${b(o).replace(/^[/\\]/,"").replace(/[/\\:]/g,"-")}--`;return F(l,w)}u(W,"sessionDirectory");function A(l){return`${l.timestamp.replace(/[:.]/g,"-")}_${l.id}.jsonl`}u(A,"fileName");function ce(l,o){const{appendSection:w}=o,f=new Map,h=new Map;L(l,{recursive:!0,mode:448});const y=new Set;async function m(e){if(y.has(e))return;const t=await d(e);if(await o.repair?.(e,t),!$(t)){f.delete(e),h.delete(e);return}y.add(e)}u(m,"repair");async function d(e){const t=f.get(e)??await o.pathFor?.(e);if(!t)throw new Z(e);return f.set(e,t),t}u(d,"pathFor");async function x(e){await m(e);const t=await d(e),r=E(P(t,"utf8")),n=r.shift();if(n?.type!=="session"||n.id!==e)throw new Error(`invalid conversation: ${e}`);return{header:n,entries:r,path:t}}u(x,"read");function B(e,t){const r=I(t);return r?.type==="session"&&r.id===e?r:void 0}u(B,"validHeader");async function N(e){const t=await d(e),r=B(e,t);if(!r)throw new Error(`invalid conversation: ${e}`);return{header:r,path:t}}u(N,"headerOf");async function H(e,t){await m(e);const{header:r,path:n}=await N(e),c=S(n).size;if(c<=t.head+t.tail)return await x(e);const i=z(n,"r");try{const a=u((R,_)=>{if(_<=0)return[];const U=Buffer.allocUnsafe(_),q=M(i,U,0,_,R);return U.subarray(0,q).toString("utf8").split(`
|
|
6
|
+
`)},"slice"),s=a(0,t.head),p=a(c-t.tail,t.tail);s.pop(),p.shift();const g=E(s.join(`
|
|
7
|
+
`));return g[0]?.type==="session"&&g.shift(),{header:r,entries:g,tail:E(p.join(`
|
|
8
|
+
`)),path:n}}finally{v(i)}}u(H,"readWindow");async function D(e,t,r,n,c){if(f.has(t.id))throw new Error(`conversation already exists: ${t.id}`);const i=X(l,n);if(i.startsWith("..")||i===""||b(n)===b(l))throw new Error("conversation path outside store root");if(L(V(n),{recursive:!0,mode:448}),$(n))throw new Error(`conversation file already exists: ${n}`);let a=!1;try{const s=u(()=>{const p=z(n,"wx",384);a=!0;try{return j(p,C(t,r)),k(p),a=!1,S(n).size}finally{v(p)}},"write");return e===void 0?s():await w(t.id,{kind:"create",nodeId:e,path:n,entries:r,...c?{sourceId:c}:{}},s),f.set(t.id,n),t.id}catch(s){throw a||!$(n)?($(n)&&O(n),await o.abortCreate?.(t.id)):f.set(t.id,n),s}}return u(D,"createAt"),{recover(e){for(const t of e){if(!t.transcript_path)continue;const r=f.get(t.session_id);if(r&&r!==t.transcript_path)throw new Error(`conflicting conversation paths: ${t.session_id}`);f.set(t.session_id,t.transcript_path)}},repair:m,async readLines(e){await m(e);const t=await d(e),r=T({input:K(t),crlfDelay:1/0});return{path:t,lines:r}},async create(e,t,r,n){return await D(e,t,r,await o.createPath?.(e,t)??n??F(W(l,t.cwd),A(t)))},async append(e,t,r){if(t.length===0)return;await m(e);const n=await d(e);if(r?.dedupe){const i=new Set((await x(e)).entries.map(a=>a.id));if(t=t.filter(a=>!i.has(a.id)),t.length===0)return}const c=S(n).size;if(c>0&&ee(n,c)!==10)throw new Error(`incomplete conversation tail: ${e}`);try{await w(e,{kind:"append",entries:t},()=>{const i=z(n,"a");try{return j(i,t.map(a=>`${JSON.stringify(a)}
|
|
9
|
+
`).join("")),k(i),S(n).size}finally{v(i)}})}catch(i){throw y.delete(e),i}},async replace(e,t,r){await m(e);const n=await d(e);if(t.id!==e)throw new Error("replacement header id differs from conversation id");const c=P(n),i=u(s=>{const p=`${n}.${J()}.tmp`;try{j(p,s,{flag:"wx",mode:384});const g=z(p,"r");try{k(g)}finally{v(g)}Q(p,n)}finally{$(p)&&O(p)}},"swap");let a=!1;try{await w(e,{kind:"replace"},()=>(i(C(t,r)),a=!0,S(n).size))}catch(s){throw a&&i(c),s}finally{h.delete(e)}},async read(e,t){return t?await H(e,t):await x(e)},async header(e){await m(e);const{header:t,path:r}=await N(e),n=S(r);return{header:t,path:r,mtime:n.mtimeMs,size:n.size}},async fork(e,t,r,n){const c=await x(e);let i=c.entries;if(r!==void 0){const p=Y.inMemory(c.header.cwd,void 0,[c.header,...i]);p.createBranchedSession(r),i=p.getEntries()}const a=new Date().toISOString(),s={...c.header,id:J(),timestamp:a,cwd:n??c.header.cwd,parentSession:c.path};return await D(t,s,i,t&&o.createPath?await o.createPath(t,s):F(W(l,s.cwd),A(s)),e)},async list(e){const t=[],r=await o.owners();for(const n of new Set([...f.keys(),...r.keys()])){const c=r.get(n);if(e!==void 0&&c!==e||(await m(n),!f.has(n)))continue;const i=await d(n),a=S(i);let s=h.get(n);(!s||s.mtime!==a.mtimeMs||s.size!==a.size)&&(s={mtime:a.mtimeMs,size:a.size,header:B(n,i)},h.set(n,s)),s.header&&t.push({conversation_id:n,...c?{node_id:c}:{},header:s.header,mtime:a.mtimeMs,size:a.size,path:i})}return t.sort((n,c)=>c.mtime-n.mtime)},async delete(e){O(await d(e)),await o.delete?.(e),f.delete(e),y.delete(e),h.delete(e)}}}u(ce,"createFileStore");export{ce as createFileStore,W as sessionDirectory};
|
|
@@ -54,41 +54,43 @@ export interface ConversationStoreClient {
|
|
|
54
54
|
}
|
|
55
55
|
/** The daemon's file store (`createFileStore`, installed by `sessions.ts`). */
|
|
56
56
|
export interface ConversationStore {
|
|
57
|
-
create(nodeId: string, header: SessionHeader, entries: SessionEntry[], path?: string): string
|
|
57
|
+
create(nodeId: string, header: SessionHeader, entries: SessionEntry[], path?: string): Promise<string>;
|
|
58
58
|
append(id: string, entries: SessionEntry[], options?: {
|
|
59
59
|
dedupe?: boolean;
|
|
60
|
-
}): void
|
|
61
|
-
replace(id: string, header: SessionHeader, entries: SessionEntry[]): void
|
|
62
|
-
read(id: string, window?: ConversationWindow): {
|
|
60
|
+
}): Promise<void>;
|
|
61
|
+
replace(id: string, header: SessionHeader, entries: SessionEntry[]): Promise<void>;
|
|
62
|
+
read(id: string, window?: ConversationWindow): Promise<{
|
|
63
63
|
header: SessionHeader;
|
|
64
64
|
entries: SessionEntry[];
|
|
65
65
|
tail?: SessionEntry[];
|
|
66
66
|
path: string;
|
|
67
|
-
}
|
|
67
|
+
}>;
|
|
68
68
|
/** Stream a complete conversation without blocking the daemon on a full-file read. */
|
|
69
|
-
readLines?(id: string): {
|
|
69
|
+
readLines?(id: string): Promise<{
|
|
70
70
|
path: string;
|
|
71
71
|
lines: AsyncIterable<string>;
|
|
72
|
-
}
|
|
73
|
-
header(id: string): {
|
|
72
|
+
}>;
|
|
73
|
+
header(id: string): Promise<{
|
|
74
74
|
header: SessionHeader;
|
|
75
75
|
mtime: number;
|
|
76
76
|
size: number;
|
|
77
77
|
path: string;
|
|
78
|
-
}
|
|
79
|
-
fork(id: string, nodeId?: string, leafId?: string, cwd?: string): string
|
|
80
|
-
list(nodeId?: string): ConversationInfo[]
|
|
81
|
-
delete(id: string): void
|
|
78
|
+
}>;
|
|
79
|
+
fork(id: string, nodeId?: string, leafId?: string, cwd?: string): Promise<string>;
|
|
80
|
+
list(nodeId?: string): Promise<ConversationInfo[]>;
|
|
81
|
+
delete(id: string): Promise<void>;
|
|
82
82
|
}
|
|
83
83
|
export declare function conversationIdFromPath(path: string): string | null;
|
|
84
84
|
export declare function defaultConversationRoot(): string;
|
|
85
85
|
export declare function storeAddress(): string;
|
|
86
86
|
export declare function installConversationStore(store: ConversationStore | undefined): void;
|
|
87
|
+
/** The installed store, else the client over the store socket with each call awaited. */
|
|
87
88
|
export declare function conversationStore(): ConversationStore;
|
|
88
|
-
/** The synchronous store pi's `SessionManager` statics call:
|
|
89
|
+
/** The synchronous store pi's `SessionManager` statics call: always the client over the store socket (the installed
|
|
90
|
+
* store is async, so it cannot serve a synchronous caller). */
|
|
89
91
|
export declare function conversationClient(): ConversationStoreClient;
|
|
90
92
|
/** Read a conversation without parking the event loop on the store worker. */
|
|
91
|
-
export declare function readConversationAsync(id: string, window?: ConversationWindow): Promise<ReturnType<ConversationStore['read']
|
|
93
|
+
export declare function readConversationAsync(id: string, window?: ConversationWindow): Promise<Awaited<ReturnType<ConversationStore['read']>>>;
|
|
92
94
|
export { createFileStore, sessionDirectory, type AppendSection, type ConversationCanvas, type ConversationWrite } from './file-store.js';
|
|
93
95
|
export { installSessionManagerStorePatch } from './patch.js';
|
|
94
96
|
export { findOrphanedParents, relinkOrphanedParents, repairConversationFile, type FileRepair, type OrphanRelink } from './repair.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var c=Object.defineProperty;var o=(e,r)=>c(e,"name",{value:r,configurable:!0});import{appsRoot as i,socketDir as p}from"../layout.js";import{join as d}from"node:path";import{createStoreClient as f}from"./client.js";import{currentNodeToken as u}from"../runtime/broker/node-token.js";class l extends Error{static{o(this,"ConversationNotFoundError")}code="not_found";constructor(r){super(`conversation not found: ${r}`)}}function h(e){return e instanceof l}o(h,"isConversationNotFound");function k(e){return/(?:^|\/)[^/]+_([0-9a-f-]{36})\.jsonl$/i.exec(e)?.[1]??null}o(k,"conversationIdFromPath");function R(){return i()}o(R,"defaultConversationRoot");function m(){return process.env.CRTR_STORE_ADDRESS||d(p(),"store.sock")}o(m,"storeAddress");let t,s;function A(e){t=e}o(A,"installConversationStore");function F(){if(t)return t;const e=a();return{create:o(async(...r)=>e.create(...r),"create"),append:o(async(...r)=>e.append(...r),"append"),replace:o(async(...r)=>e.replace(...r),"replace"),read:o(async(...r)=>e.read(...r),"read"),header:o(async(...r)=>e.header(...r),"header"),fork:o(async(...r)=>e.fork(...r),"fork"),list:o(async(...r)=>e.list(...r),"list"),delete:o(async(...r)=>e.delete(...r),"delete")}}o(F,"conversationStore");function a(){const e=m();return s?.address!==e&&(s={address:e,store:f(e,u())}),s.store}o(a,"conversationClient");async function D(e,r){if(t)return t.read(e,r);const n=a();return n.readAsync?n.readAsync(e,r):n.read(e,r)}o(D,"readConversationAsync");import{createFileStore as _,sessionDirectory as N}from"./file-store.js";import{installSessionManagerStorePatch as T}from"./patch.js";import{findOrphanedParents as $,relinkOrphanedParents as g,repairConversationFile as I}from"./repair.js";export{l as ConversationNotFoundError,a as conversationClient,k as conversationIdFromPath,F as conversationStore,_ as createFileStore,R as defaultConversationRoot,$ as findOrphanedParents,A as installConversationStore,T as installSessionManagerStorePatch,h as isConversationNotFound,D as readConversationAsync,g as relinkOrphanedParents,I as repairConversationFile,N as sessionDirectory,m as storeAddress};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var O=Object.defineProperty;var v=(
|
|
1
|
+
var O=Object.defineProperty;var v=(o,n)=>O(o,"name",{value:n,configurable:!0});import{createServer as _}from"node:http";import{chmodSync as k,existsSync as N,unlinkSync as T}from"node:fs";import{isConversationNotFound as b}from"./index.js";import{resolveNodeToken as j}from"../canvas/node-tokens.js";import{conversationOwner as H}from"../canvas/sessions.js";import{peerUid as J}from"../../native/linux.js";async function x(o){const n=[];for await(const s of o)n.push(Buffer.from(s));return JSON.parse(Buffer.concat(n).toString("utf8"))}v(x,"body");function l(o,n,s){o.writeHead(n,{"content-type":"application/json"}),o.end(JSON.stringify(s))}v(l,"json");async function P(o,n,s){if(!n.readLines){const f=await n.read(s);o.writeHead(200,{"content-type":"application/x-ndjson","x-conversation-path":f.path}),o.end([f.header,...f.entries].map(d=>JSON.stringify(d)).join(`
|
|
2
2
|
`)+`
|
|
3
|
-
`);return}const{path:
|
|
4
|
-
`;c+=Buffer.byteLength(S),c>=256*1024?(c=0,await new Promise((p,u)=>
|
|
3
|
+
`);return}const{path:a,lines:e}=await n.readLines(s);let r=!1,c=0;for await(const f of e){if(!f.trim())continue;let d;try{d=JSON.parse(f)}catch{continue}if(!r){if(d.type!=="session"||d.id!==s)throw new Error(`invalid conversation: ${s}`);o.writeHead(200,{"content-type":"application/x-ndjson","x-conversation-path":a}),r=!0}const S=JSON.stringify(d)+`
|
|
4
|
+
`;c+=Buffer.byteLength(S),c>=256*1024?(c=0,await new Promise((p,u)=>o.write(S,w=>w?u(w):p()))):o.write(S)}if(!r)throw new Error(`invalid conversation: ${s}`);o.end()}v(P,"fullRead");async function C(o,n){const s=_(async(a,e)=>{try{const r=a.headers.authorization,c=typeof r=="string"&&r.startsWith("Bearer ")?await j(r.slice(7)):null,f=new URL(a.url??"/","http://store"),d=f.pathname.split("/").filter(Boolean);if(r===void 0&&process.platform!=="linux"&&a.method==="GET"&&d[0]==="conversations"&&(d.length===1||d.length===2||d.length===3&&d[2]==="header")){const t=d[1];if(!t)l(e,200,{conversations:await n.list(f.searchParams.get("node_id")??void 0)});else if(d[2]==="header")l(e,200,await n.header(t));else{const y=f.searchParams.get("head"),h=f.searchParams.get("tail");if(y===null||h===null)await P(e,n,t);else{const g=await n.read(t,{head:Number(y),tail:Number(h)});e.writeHead(200,{"content-type":"application/x-ndjson","x-conversation-path":g.path,...g.tail?{"x-conversation-tail":String(1+g.entries.length)}:{}}),e.end([g.header,...g.entries,...g.tail??[]].map(E=>JSON.stringify(E)).join(`
|
|
5
5
|
`)+`
|
|
6
|
-
`)}}return}if(!c){l(e,401,{error:"unauthorized"});return}if(process.platform==="linux"){let
|
|
6
|
+
`)}}return}if(!c){l(e,401,{error:"unauthorized"});return}if(process.platform==="linux"){let t;try{t=J(a.socket)}catch{l(e,401,{error:"unauthorized"});return}if(t!==c.uid){l(e,401,{error:"unauthorized"});return}}const p=v(async t=>await H(t)===c.node,"owns"),u=v(()=>l(e,404,{error:"not_found"}),"notFound"),w=new URL(a.url??"/","http://store"),m=w.pathname.split("/").filter(Boolean);if(m[0]!=="conversations"){l(e,404,{error:"not_found"});return}const i=m[1];if(!i&&a.method==="POST"){const t=await x(a);if(t.node_id!==c.node){u();return}l(e,201,{conversation_id:await n.create(t.node_id,t.header,t.entries,t.path)})}else if(!i&&a.method==="GET"){if(w.searchParams.has("node_id")&&w.searchParams.get("node_id")!==c.node){u();return}l(e,200,{conversations:await n.list(c.node)})}else if(i&&m[2]==="entries"&&a.method==="POST"){if(!await p(i)){u();return}const t=await x(a);await n.append(i,t.entries,t.dedupe===!0?{dedupe:!0}:void 0),e.writeHead(204).end()}else if(i&&m[2]==="header"&&a.method==="GET"){if(!await p(i)){u();return}l(e,200,await n.header(i))}else if(i&&m[2]==="fork"&&a.method==="POST"){if(!await p(i)){u();return}const t=await x(a);if(t.node_id!==c.node){u();return}l(e,201,{conversation_id:await n.fork(i,c.node,t.leaf_id,t.cwd)})}else if(i&&m.length===2&&a.method==="GET"){if(!await p(i)){u();return}const t=w.searchParams.get("head"),y=w.searchParams.get("tail");if(t===null||y===null)await P(e,n,i);else{const h=await n.read(i,{head:Number(t),tail:Number(y)});e.writeHead(200,{"content-type":"application/x-ndjson","x-conversation-path":h.path,...h.tail?{"x-conversation-tail":String(1+h.entries.length)}:{}}),e.end([h.header,...h.entries,...h.tail??[]].map(g=>JSON.stringify(g)).join(`
|
|
7
7
|
`)+`
|
|
8
|
-
`)}}else if(
|
|
8
|
+
`)}}else if(i&&m.length===2&&a.method==="PUT"){if(!await p(i)){u();return}const t=await x(a);await n.replace(i,t.header,t.entries),e.writeHead(204).end()}else if(i&&m.length===2&&a.method==="DELETE"){if(!await p(i)){u();return}await n.delete(i),e.writeHead(204).end()}else l(e,404,{error:"not_found"})}catch(r){const c=r instanceof Error?r.message:String(r);e.headersSent?e.destroy(r instanceof Error?r:new Error(c)):l(e,b(r)?404:500,{error:c})}});if(N(o)&&T(o),await new Promise((a,e)=>{s.once("error",e),s.listen(o,()=>{s.off("error",e),a()})}),typeof s.address()!="string")throw s.close(),new Error(`store listener must bind a unix socket: ${JSON.stringify(s.address())}`);return k(o,process.platform==="linux"&&N("/run/crtr/launcher.sock")?438:384),{close:v(()=>new Promise((a,e)=>s.close(r=>r?e(r):a())),"close")}}v(C,"listenConversationStore");export{C as listenConversationStore};
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
import { type ConversationStoreClient } from './index.js';
|
|
2
|
+
/** `store` is the synchronous client pi's `SessionManager` needs: the broker's client over the store socket unless a caller supplies one. */
|
|
3
|
+
export declare function installSessionManagerStorePatch(nodeId: string, store?: ConversationStoreClient): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var P=Object.defineProperty;var
|
|
1
|
+
var P=Object.defineProperty;var c=(a,r)=>P(a,"name",{value:r,configurable:!0});import{dirname as E,resolve as A}from"node:path";import{SessionManager as w}from"@earendil-works/pi-coding-agent";import{conversationClient as R,conversationIdFromPath as O}from"./index.js";import{findOrphanedParents as T}from"./repair.js";import{emitEvent as I}from"../events/emit.js";const f=new WeakMap;function k(a){a>0&&Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,a)}c(k,"sleep");function C(){const a=Number(process.env.CRTR_CONVERSATION_APPEND_RETRY_MS);return Number.isFinite(a)&&a>=0?a:500}c(C,"retryDelayMs");let x=!1;function z(a,r=R()){if(x)return;const l=w.prototype,h=w;for(const e of["_setSessionFile","_rewriteFile","_persist","createBranchedSession","newSession"])if(typeof l[e]!="function")throw new Error(`pi SessionManager.${e} changed; store patch cannot start`);for(const e of["create","open","continueRecent","forkFrom","findById","list","listAll"])if(typeof h[e]!="function")throw new Error(`pi SessionManager.${e} changed; store patch cannot start`);const M=l.createBranchedSession,y=l.newSession;function N(e,s){const t=T(s);t.length!==0&&I({level:"error",event:"conversation.orphaned_parent",fields:{conversation_id:e,orphan_count:t.length,orphans:t.slice(0,20).map(i=>({entry_id:i.entryId,missing_parent_id:i.missingParentId}))}})}c(N,"reportOrphans");function _(e,s){const{header:t,entries:i,path:o}=r.read(e);N(t.id,i);const n=w.inMemory(s??t.cwd);n.sessionFile=o,n.sessionDir=E(o),n._loadEntries([t,...i]),n.persist=!0,n.flushed=!0;const u=n.fileEntries[0];return u?.type==="session"&&u.version!==t.version&&n._rewriteFile(),n}c(_,"fromStore");function m(e){const[s,...t]=e.fileEntries;if(!s||s.type!=="session")throw new Error("conversation has no session header");r.create(a,s,t),e.sessionFile=r.header(s.id).path,e.sessionDir=E(e.sessionFile),e.flushed=!0,f.delete(e)}c(m,"persistNew");function B(e,s){const t=f.get(e)??{entries:[],ambiguous:!1};t.entries.push(s),f.set(e,t);let i;for(let o=0;o<2;o++){o>0&&k(C());try{r.append(e.sessionId,t.entries,t.ambiguous?{dedupe:!0}:void 0),f.delete(e);return}catch(n){i=n,t.ambiguous=!0}}throw I({level:"error",event:"conversation.append_failed",error:i,fields:{conversation_id:e.sessionId,pending_entries:t.entries.length}}),i}c(B,"appendInOrder");function g(e){const s=O(e);if(!s)throw new Error(`invalid conversation path: ${e}`);return s}c(g,"idOf"),l._setSessionFile=function(e){const{header:s,entries:t}=r.read(g(e));this.sessionFile=r.header(s.id).path,this.sessionDir=E(this.sessionFile),N(s.id,t),this._loadEntries([s,...t]),this.flushed=!0,f.delete(this)},l._rewriteFile=function(){if(!this.persist||!this.sessionFile)return;const[e,...s]=this.fileEntries;if(!e||e.type!=="session")throw new Error("conversation has no session header");r.replace(e.id,e,s),f.delete(this)},l._persist=function(e){!this.persist||!this.sessionFile||(this.flushed?B(this,e):m(this))},l.newSession=function(e){if(!this.persist)return y.call(this,e);const s=this.flushed&&this.fileEntries.length===1&&this.sessionFile!==void 0?this.sessionId:void 0;if(s!==void 0&&(e?.id===void 0||e.id===s)){const t=this.sessionFile;y.call(this,{...e,id:s});const i=this.fileEntries[0];if(!i||i.type!=="session")throw new Error("conversation has no session header");return r.replace(s,i,[]),this.sessionFile=t,this.flushed=!0,t}return y.call(this,e),m(this),this.sessionFile},l.createBranchedSession=function(e){if(!this.persist)return M.call(this,e);const s=this.sessionFile;this.persist=!1;try{M.call(this,e)}finally{this.persist=!0}const t=this.fileEntries[0];if(!t||t.type!=="session")throw new Error("branch has no header");return this.fileEntries[0]={...t,parentSession:s},m(this),this.sessionFile},h.create=(e,s,t)=>{const i=w.inMemory(e,t);return i.persist=!0,m(i),i},h.open=(e,s,t)=>_(g(e),t),h.continueRecent=e=>{const s=r.list().find(t=>t.header.cwd===A(e));return s?_(s.conversation_id,e):h.create(e)},h.forkFrom=(e,s)=>_(r.fork(g(e),a,void 0,s)),h.findById=(e,s)=>r.list().find(t=>t.conversation_id===s&&t.header.cwd===A(e))?.path;function b(e){return r.list().filter(s=>e===void 0||s.header.cwd===A(e)).map(s=>{let t,i=0,o="",n;const u=[];for(const p of r.read(s.conversation_id).entries){if(p.type==="session_info"&&(t=p.name?.trim()||void 0),p.type!=="message")continue;i++;const d=p.message;if(d.role!=="user"&&d.role!=="assistant")continue;const D=typeof d.timestamp=="number"?d.timestamp:Date.parse(p.timestamp);Number.isNaN(D)||(n=Math.max(n??0,D));const F=typeof d.content=="string"?d.content:Array.isArray(d.content)?d.content.filter(S=>S.type==="text").map(S=>S.text??"").join(" "):"";F&&(u.push(F),!o&&d.role==="user"&&(o=F))}const v=new Date(s.header.timestamp);return{path:s.path,id:s.conversation_id,cwd:s.header.cwd,...t?{name:t}:{},...s.header.parentSession?{parentSessionPath:s.header.parentSession}:{},created:v,modified:n&&n>0?new Date(n):Number.isNaN(v.getTime())?new Date(s.mtime):v,messageCount:i,firstMessage:o||"(no messages)",allMessagesText:u.join(" ")}})}c(b,"sessionInfos"),h.list=async(e,s,t,i)=>{i?.throwIfAborted();const o=b(e);return t?.(o.length,o.length,o),o},h.listAll=async(...e)=>(e.find(t=>t instanceof AbortSignal)?.throwIfAborted(),b()),x=!0}c(z,"installSessionManagerStorePatch");export{z as installSessionManagerStorePatch};
|
|
@@ -42,7 +42,7 @@ export interface JoinDaemonControl {
|
|
|
42
42
|
export declare function installedPluginIds(): string[];
|
|
43
43
|
/** The owner a successful join recorded, or null when `crtr sys join` never
|
|
44
44
|
* wrote the client file (no file, or one provisioned without join, which has
|
|
45
|
-
* no `token_sha256`). The daemon applies OWN-11 to canvas.db from it at
|
|
45
|
+
* no `token_sha256`). The daemon applies OWN-11 to canvas.db from it at the first start under each owner. */
|
|
46
46
|
export declare function joinedOwner(): string | null;
|
|
47
47
|
/** Join this runtime to a directory.
|
|
48
48
|
*
|