@north-light/crouter 0.3.353 → 0.3.354
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +35 -25
- package/dist/api/client.js +2 -2
- package/dist/api/dto/broker-ops.d.ts +2 -36
- package/dist/api/dto/canvas.d.ts +8 -13
- package/dist/api/dto/config.d.ts +4 -0
- package/dist/api/dto/delivery.d.ts +61 -0
- package/dist/api/dto/docs.d.ts +133 -0
- package/dist/api/dto/docs.js +1 -0
- package/dist/api/dto/health.d.ts +26 -79
- package/dist/api/dto/node-outcomes.d.ts +1 -3
- package/dist/api/dto/nodes.d.ts +5 -26
- package/dist/api/dto/objects.d.ts +167 -0
- package/dist/api/dto/objects.js +1 -0
- package/dist/api/dto/profiles.d.ts +14 -8
- package/dist/api/dto/reports.d.ts +9 -7
- package/dist/api/dto/reviews.d.ts +9 -3
- package/dist/api/dto/worktree.d.ts +1 -1
- package/dist/api/index.d.ts +0 -1
- package/dist/api/index.js +1 -1
- package/dist/api/routes.d.ts +14 -12
- package/dist/api/routes.js +1 -1
- package/dist/build-root.js +1 -1
- package/dist/builtin-memory/00-runtime-base/00-authoring.md +10 -5
- package/dist/builtin-memory/04-orchestration-kernel.md +7 -7
- package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +1 -1
- package/dist/builtin-memory/05-kinds/explore/00-base.md +2 -2
- package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +2 -2
- package/dist/builtin-memory/crouter-concepts/INDEX.md +2 -2
- package/dist/builtin-memory/crouter-concepts/lifecycle-and-wakes.md +1 -1
- package/dist/builtin-memory/crouter-concepts/memory.md +15 -15
- package/dist/builtin-memory/crouter-concepts/nodes-and-the-canvas.md +1 -1
- package/dist/builtin-memory/crouter-concepts/profiles-kinds-and-modes.md +5 -5
- package/dist/builtin-memory/crouter-concepts/scopes-and-trust.md +1 -1
- package/dist/builtin-memory/crouter-concepts/why-a-daemon.md +1 -1
- package/dist/builtin-memory/crouter-sdk/INDEX.md +2 -2
- package/dist/builtin-memory/crouter-sdk/README.md +5 -6
- package/dist/builtin-memory/crouter-sdk/errors.md +0 -13
- package/dist/builtin-memory/crouter-sdk/guides/README.md +0 -1
- package/dist/builtin-memory/crouter-sdk/guides/event-driven-assistant.md +2 -2
- package/dist/builtin-memory/crouter-sdk/nodes.md +0 -2
- package/dist/builtin-memory/crouter-sdk/resources.md +0 -1
- package/dist/builtin-memory/explore/exploration-doc.md +4 -4
- package/dist/builtin-memory/insights/capture.md +6 -6
- package/dist/builtin-memory/insights/init.md +14 -14
- package/dist/builtin-memory/internal/INDEX.md +4 -4
- package/dist/builtin-memory/internal/agent-shaping.md +20 -20
- package/dist/builtin-memory/internal/examples/imessage-assistant.md +2 -2
- package/dist/builtin-memory/internal/marketplaces.md +2 -2
- package/dist/builtin-memory/internal/memory-loading.md +31 -30
- package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
- package/dist/builtin-memory/internal/plugins.md +16 -14
- package/dist/builtin-memory/internal/storage-tiers.md +4 -4
- package/dist/builtin-memory/memory-read-orientation.md +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +32 -40
- package/dist/clients/attach/input/controller.js +1 -1
- package/dist/clients/attach/input/ref-autocomplete.js +1 -1
- package/dist/clients/attach/input/titled-editor.js +1 -1
- package/dist/clients/attach/render/chat-view.js +1 -1
- package/dist/clients/attach/render/crtr-output.d.ts +1 -2
- package/dist/clients/attach/render/crtr-output.js +17 -17
- package/dist/clients/attach/render/group-activity.d.ts +8 -8
- package/dist/clients/attach/render/group-activity.js +2 -2
- package/dist/clients/attach/render/group-recap.js +1 -1
- package/dist/clients/attach/render/tool-calls.d.ts +1 -1
- package/dist/clients/attach/session/profile-files.js +1 -1
- package/dist/clients/attach/slash/dispatch.js +1 -1
- package/dist/clients/attach/viewer.js +806 -1553
- package/dist/commands/api-client.d.ts +2 -0
- package/dist/commands/api-client.js +3 -3
- package/dist/commands/canvas/edges.d.ts +2 -0
- package/dist/commands/canvas/edges.js +2 -0
- package/dist/commands/canvas/list.d.ts +4 -0
- package/dist/commands/canvas/list.js +3 -0
- package/dist/commands/canvas/read.d.ts +8 -0
- package/dist/commands/canvas/read.js +5 -0
- package/dist/commands/canvas/search.d.ts +2 -0
- package/dist/commands/canvas/search.js +3 -0
- package/dist/commands/canvas/unwatch.d.ts +2 -0
- package/dist/commands/canvas/unwatch.js +1 -0
- package/dist/commands/canvas/watch.d.ts +3 -0
- package/dist/commands/canvas/watch.js +1 -0
- package/dist/commands/canvas-analytics.js +1 -1
- package/dist/commands/canvas-history/grep.js +4 -4
- package/dist/commands/canvas-history/read.js +2 -2
- package/dist/commands/canvas-history/search.js +7 -7
- package/dist/commands/canvas-history/shared.d.ts +0 -1
- package/dist/commands/canvas-history/shared.js +1 -1
- package/dist/commands/canvas-history/stats.js +2 -2
- package/dist/commands/canvas-history.js +1 -1
- package/dist/commands/canvas.js +1 -1
- package/dist/commands/doc/delete.d.ts +2 -0
- package/dist/commands/doc/delete.js +1 -0
- package/dist/commands/doc/edit.d.ts +2 -0
- package/dist/commands/doc/edit.js +1 -0
- package/dist/commands/doc/history.d.ts +2 -0
- package/dist/commands/doc/history.js +2 -0
- package/dist/commands/doc/lint.d.ts +2 -0
- package/dist/commands/doc/lint.js +2 -0
- package/dist/commands/doc/list.d.ts +2 -0
- package/dist/commands/doc/list.js +1 -0
- package/dist/commands/doc/move.d.ts +2 -0
- package/dist/commands/doc/move.js +1 -0
- package/dist/commands/doc/read.d.ts +2 -0
- package/dist/commands/doc/read.js +1 -0
- package/dist/commands/doc/shared.d.ts +25 -0
- package/dist/commands/doc/shared.js +2 -0
- package/dist/commands/doc/write.d.ts +2 -0
- package/dist/commands/doc/write.js +1 -0
- package/dist/commands/{memory.d.ts → doc.d.ts} +1 -1
- package/dist/commands/doc.js +1 -0
- package/dist/commands/human/review.js +1 -1
- package/dist/commands/node/bash.js +2 -2
- package/dist/commands/node/create.js +1 -1
- package/dist/commands/node/inspect.js +10 -10
- package/dist/commands/node/lifecycle.js +2 -2
- package/dist/commands/node/outcome.js +1 -1
- package/dist/commands/node/subscription.js +1 -1
- package/dist/commands/node-context.js +2 -2
- package/dist/commands/pkg/browse/catalog.js +1 -1
- package/dist/commands/pkg/browse/doc-view.js +1 -1
- package/dist/commands/pkg/browse/model.d.ts +9 -17
- package/dist/commands/pkg/plugin-inspect.js +1 -1
- package/dist/commands/pkg/plugin-manage.d.ts +4 -8
- package/dist/commands/pkg/plugin-manage.js +15 -17
- package/dist/commands/profile/list.js +1 -1
- package/dist/commands/profile/new.js +1 -1
- package/dist/commands/profile/project.js +1 -1
- package/dist/commands/profile/show.js +1 -1
- package/dist/commands/push.js +3 -3
- package/dist/commands/sys/config.js +1 -1
- package/dist/commands/sys/context/admin/actions.d.ts +18 -43
- package/dist/commands/sys/context/admin/actions.js +1 -2
- package/dist/commands/sys/context/admin/detail-panel.d.ts +17 -25
- package/dist/commands/sys/context/admin/detail-panel.js +2 -1
- package/dist/commands/sys/context/admin/docs-panel.d.ts +7 -6
- package/dist/commands/sys/context/admin/docs-panel.js +1 -1
- package/dist/commands/sys/context/admin/list-view.d.ts +12 -12
- package/dist/commands/sys/context/admin/list-view.js +1 -1
- package/dist/commands/sys/context/admin/model.d.ts +96 -69
- package/dist/commands/sys/context/admin/model.js +1 -1
- package/dist/commands/sys/context/admin/rail-panel.d.ts +7 -5
- package/dist/commands/sys/context/admin/rail-panel.js +1 -1
- package/dist/commands/sys/context/admin/read-view.d.ts +10 -14
- package/dist/commands/sys/context/admin/read-view.js +1 -2
- package/dist/commands/sys/context/admin/shell.d.ts +26 -31
- package/dist/commands/sys/context/admin/shell.js +1 -1
- package/dist/commands/sys/context/admin.js +2 -2
- package/dist/commands/sys/context/doc.js +2 -3
- package/dist/commands/sys/context/expose.js +2 -2
- package/dist/commands/sys/context/prompt-review.js +4 -4
- package/dist/commands/sys/context/resolve.d.ts +92 -65
- package/dist/commands/sys/context/resolve.js +7 -9
- package/dist/commands/sys/context.js +1 -1
- package/dist/commands/sys/doctor.js +1 -1
- package/dist/commands/sys/migrate.js +1 -1
- package/dist/commands/sys/panels/profiles-panel.d.ts +3 -1
- package/dist/commands/sys/panels/profiles-panel.js +1 -1
- package/dist/commands/sys/sync-deps.d.ts +6 -11
- package/dist/commands/sys/sync-deps.js +7 -8
- package/dist/commands/sys/sync-project-guidance.js +5 -4
- package/dist/commands/sys/sync-shared.d.ts +41 -4
- package/dist/commands/sys/sync-shared.js +1 -1
- package/dist/commands/sys/sync-skills.js +2 -2
- package/dist/commands/sys/sync.js +1 -1
- package/dist/core/bash-job-supervisor.d.ts +2 -3
- package/dist/core/bash-job-supervisor.js +3 -3
- package/dist/core/bash-jobs.d.ts +0 -5
- package/dist/core/bash-jobs.js +7 -7
- package/dist/core/bootstrap.js +2 -2
- package/dist/core/canvas/canvas.d.ts +6 -50
- package/dist/core/canvas/canvas.js +16 -21
- package/dist/core/canvas/db.d.ts +4 -1
- package/dist/core/canvas/db.js +2 -2
- package/dist/core/canvas/history.d.ts +11 -39
- package/dist/core/canvas/history.js +9 -20
- package/dist/core/canvas/install-id.d.ts +2 -2
- package/dist/core/canvas/install-id.js +1 -1
- package/dist/core/canvas/memory-reads.d.ts +5 -0
- package/dist/core/canvas/memory-reads.js +1 -1
- package/dist/core/canvas/migrations.js +215 -41
- package/dist/core/canvas/node-agent-paths.js +1 -1
- package/dist/core/canvas/node-tokens.js +1 -1
- package/dist/core/canvas/paths.d.ts +0 -4
- package/dist/core/canvas/paths.js +1 -1
- package/dist/core/canvas/remote-canvas-source.d.ts +0 -1
- package/dist/core/canvas/remote-canvas-source.js +1 -1
- package/dist/core/canvas/render-source.d.ts +9 -6
- package/dist/core/canvas/render-source.js +6 -6
- package/dist/core/canvas/sessions.js +2 -2
- package/dist/core/canvas/source.d.ts +6 -0
- package/dist/core/canvas/tree.d.ts +29 -0
- package/dist/core/canvas/tree.js +12 -0
- package/dist/core/canvas/types.d.ts +0 -20
- package/dist/core/command-plugins/bundle.js +1 -1
- package/dist/core/config.d.ts +1 -1
- package/dist/core/conversation-store/listener.js +4 -2
- package/dist/core/feed/feed.d.ts +9 -7
- package/dist/core/feed/feed.js +3 -7
- package/dist/core/feed/inbox.d.ts +3 -5
- package/dist/core/feed/inbox.js +1 -10
- package/dist/core/feed/messages.d.ts +33 -6
- package/dist/core/feed/messages.js +10 -7
- package/dist/core/feed/reports.d.ts +10 -0
- package/dist/core/feed/reports.js +2 -0
- package/dist/core/grants/remove.js +1 -1
- package/dist/core/graph/access.d.ts +24 -0
- package/dist/core/graph/access.js +8 -0
- package/dist/core/graph/bodies.d.ts +6 -0
- package/dist/core/graph/bodies.js +1 -0
- package/dist/core/graph/deletion.d.ts +9 -0
- package/dist/core/graph/deletion.js +5 -0
- package/dist/core/graph/diff.d.ts +4 -0
- package/dist/core/graph/diff.js +4 -0
- package/dist/core/graph/documents.d.ts +160 -0
- package/dist/core/graph/documents.js +7 -0
- package/dist/core/graph/edges.d.ts +24 -0
- package/dist/core/graph/edges.js +1 -0
- package/dist/core/graph/events.d.ts +26 -0
- package/dist/core/graph/events.js +6 -0
- package/dist/core/graph/exposures.d.ts +53 -0
- package/dist/core/graph/exposures.js +4 -0
- package/dist/core/graph/jobs.d.ts +31 -0
- package/dist/core/graph/jobs.js +2 -0
- package/dist/core/graph/names.d.ts +28 -0
- package/dist/core/graph/names.js +3 -0
- package/dist/core/graph/objects.d.ts +55 -0
- package/dist/core/graph/objects.js +9 -0
- package/dist/core/graph/package-docs.d.ts +31 -0
- package/dist/core/graph/package-docs.js +5 -0
- package/dist/core/graph/package-files.d.ts +20 -0
- package/dist/core/graph/package-files.js +2 -0
- package/dist/core/graph/reader.d.ts +21 -0
- package/dist/core/graph/reader.js +3 -0
- package/dist/core/graph/repo-sync/exchange.d.ts +34 -0
- package/dist/core/graph/repo-sync/exchange.js +2 -0
- package/dist/core/graph/repo-sync/identity.d.ts +30 -0
- package/dist/core/graph/repo-sync/identity.js +1 -0
- package/dist/core/graph/repo-sync/index.d.ts +4 -0
- package/dist/core/graph/repo-sync/index.js +1 -0
- package/dist/core/graph/repo-sync/mirror.d.ts +30 -0
- package/dist/core/graph/repo-sync/mirror.js +6 -0
- package/dist/core/graph/repo-sync/ref-format.d.ts +76 -0
- package/dist/core/graph/repo-sync/ref-format.js +2 -0
- package/dist/core/graph/repo-sync/repos.d.ts +17 -0
- package/dist/core/graph/repo-sync/repos.js +3 -0
- package/dist/core/graph/repo-sync/sync.d.ts +42 -0
- package/dist/core/graph/repo-sync/sync.js +2 -0
- package/dist/core/graph/rules.d.ts +26 -0
- package/dist/core/graph/rules.js +3 -0
- package/dist/core/graph/spaces/app.d.ts +3 -0
- package/dist/core/graph/spaces/app.js +1 -0
- package/dist/core/graph/spaces/index.d.ts +19 -0
- package/dist/core/graph/spaces/index.js +1 -0
- package/dist/core/graph/spaces/person.d.ts +5 -0
- package/dist/core/graph/spaces/person.js +2 -0
- package/dist/core/graph/spaces/repo.d.ts +4 -0
- package/dist/core/graph/spaces/repo.js +1 -0
- package/dist/core/graph/types.d.ts +75 -0
- package/dist/core/graph/types.js +1 -0
- package/dist/core/graph/watches.d.ts +62 -0
- package/dist/core/graph/watches.js +18 -0
- package/dist/core/human/feedback-companion.js +1 -1
- package/dist/core/human/requests.d.ts +3 -1
- package/dist/core/human/requests.js +6 -6
- package/dist/core/inspector/model.js +2 -2
- package/dist/core/io.js +5 -5
- package/dist/core/layout-migrate/index.d.ts +24 -1
- package/dist/core/layout-migrate/index.js +4 -4
- package/dist/core/layout-migrate/paths.d.ts +4 -0
- package/dist/core/layout-migrate/paths.js +1 -1
- package/dist/core/layout-migrate/stored-paths.d.ts +7 -0
- package/dist/core/layout-migrate/stored-paths.js +11 -11
- package/dist/core/layout-migrate/stores.d.ts +19 -6
- package/dist/core/layout-migrate/stores.js +3 -4
- package/dist/core/manifest.d.ts +0 -2
- package/dist/core/manifest.js +1 -1
- package/dist/core/{memory/extensions.d.ts → plugin-extensions.d.ts} +9 -10
- package/dist/core/plugin-extensions.js +1 -0
- package/dist/core/preview-registry.d.ts +1 -1
- package/dist/core/preview-registry.js +3 -2
- package/dist/core/profiles/manifest.d.ts +7 -7
- package/dist/core/profiles/manifest.js +1 -1
- package/dist/core/profiles/select.js +3 -3
- package/dist/core/review/birth.js +1 -1
- package/dist/core/review/companion.js +1 -1
- package/dist/core/review/stage.d.ts +12 -1
- package/dist/core/review/stage.js +1 -1
- package/dist/core/review/store.d.ts +2 -0
- package/dist/core/review/store.js +1 -1
- package/dist/core/review/types.d.ts +7 -1
- package/dist/core/runs/events.js +1 -1
- package/dist/core/runs/operations.js +5 -5
- package/dist/core/runs/questions.js +2 -2
- package/dist/core/runtime/bearings-render.d.ts +13 -7
- package/dist/core/runtime/bearings-render.js +12 -12
- package/dist/core/runtime/bearings.d.ts +8 -18
- package/dist/core/runtime/bearings.js +7 -7
- package/dist/core/runtime/broker/daemon-ops.d.ts +7 -12
- package/dist/core/runtime/broker/daemon-ops.js +1 -1
- package/dist/core/runtime/broker/fault-retry.d.ts +2 -0
- package/dist/core/runtime/broker/fault-retry.js +1 -1
- package/dist/core/runtime/broker/frame-dispatch.d.ts +1 -1
- package/dist/core/runtime/broker/frame-memory-refs.d.ts +7 -2
- package/dist/core/runtime/broker/frame-memory-refs.js +1 -1
- package/dist/core/runtime/broker/inbox.d.ts +1 -4
- package/dist/core/runtime/broker/inbox.js +1 -10
- package/dist/core/runtime/broker/rebind.js +1 -1
- package/dist/core/runtime/broker/retry-card-elision.d.ts +7 -0
- package/dist/core/runtime/broker/retry-card-elision.js +1 -0
- package/dist/core/runtime/broker-extension-render.d.ts +0 -13
- package/dist/core/runtime/broker-extension-render.js +2 -4
- package/dist/core/runtime/broker-persona-guidance.js +3 -3
- package/dist/core/runtime/broker-protocol.d.ts +1 -1
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/close.d.ts +9 -4
- package/dist/core/runtime/close.js +1 -1
- package/dist/core/runtime/deliver-live.js +1 -1
- package/dist/core/runtime/kickoff.js +17 -19
- package/dist/core/runtime/launch-target.d.ts +7 -0
- package/dist/core/runtime/launch-target.js +1 -1
- package/dist/core/runtime/ledger.d.ts +10 -0
- package/dist/core/runtime/ledger.js +3 -0
- package/dist/core/runtime/lifecycle.js +2 -2
- package/dist/core/runtime/nodes.d.ts +10 -2
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/outcome-document.d.ts +2 -2
- package/dist/core/runtime/outcome-document.js +1 -1
- package/dist/core/runtime/persona.js +2 -2
- package/dist/core/runtime/placement.js +1 -1
- package/dist/core/runtime/promote.d.ts +2 -2
- package/dist/core/runtime/promote.js +1 -1
- package/dist/core/runtime/prospective-inventory-cli.js +2 -2
- package/dist/core/runtime/recycle.js +1 -1
- package/dist/core/runtime/reopen.js +1 -1
- package/dist/core/runtime/revive.js +2 -2
- package/dist/core/runtime/roadmap.d.ts +17 -9
- package/dist/core/runtime/roadmap.js +4 -4
- package/dist/core/runtime/spawn-env.js +1 -1
- package/dist/core/runtime/spawn.d.ts +5 -3
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/structured-output.d.ts +3 -1
- package/dist/core/runtime/structured-output.js +4 -4
- package/dist/core/scope.d.ts +1 -32
- package/dist/core/scope.js +1 -1
- package/dist/core/scoped-state/db.js +2 -1
- package/dist/core/scoped-state/migrate.js +2 -2
- package/dist/core/scoped-state/profiles.d.ts +11 -0
- package/dist/core/scoped-state/profiles.js +1 -1
- package/dist/core/scoped-state/schema.d.ts +1 -1
- package/dist/core/scoped-state/schema.js +7 -5
- package/dist/core/spaces/permissions.d.ts +0 -14
- package/dist/core/spaces/permissions.js +1 -1
- package/dist/core/spaces/stop.d.ts +13 -0
- package/dist/core/spaces/stop.js +2 -2
- package/dist/core/storage/tables.d.ts +1 -1
- package/dist/core/substrate/delivery/corpus.d.ts +21 -0
- package/dist/core/substrate/delivery/corpus.js +3 -0
- package/dist/core/substrate/delivery/deliver.d.ts +76 -0
- package/dist/core/substrate/delivery/deliver.js +6 -0
- package/dist/core/substrate/delivery/listings.d.ts +27 -0
- package/dist/core/substrate/delivery/listings.js +4 -0
- package/dist/core/substrate/delivery/match.d.ts +28 -0
- package/dist/core/substrate/delivery/match.js +1 -0
- package/dist/core/substrate/delivery/plan.d.ts +67 -0
- package/dist/core/substrate/delivery/plan.js +3 -0
- package/dist/core/substrate/delivery/render-boot.d.ts +20 -0
- package/dist/core/substrate/delivery/render-boot.js +54 -0
- package/dist/core/substrate/delivery/render-event.d.ts +47 -0
- package/dist/core/substrate/delivery/render-event.js +6 -0
- package/dist/core/substrate/delivery/sub-persona-menu.d.ts +2 -0
- package/dist/core/substrate/delivery/sub-persona-menu.js +6 -0
- package/dist/core/substrate/delivery/types.d.ts +30 -0
- package/dist/core/substrate/delivery/types.js +0 -0
- package/dist/core/substrate/gate-explain.d.ts +0 -13
- package/dist/core/substrate/gate-explain.js +1 -1
- package/dist/core/substrate/schema.d.ts +11 -139
- package/dist/core/substrate/schema.js +1 -1
- package/dist/core/substrate/subject-fields.d.ts +3 -0
- package/dist/core/substrate/subject.d.ts +2 -1
- package/dist/core/substrate/subject.js +1 -1
- package/dist/daemon/api/handlers/app-profiles.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +1 -2
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/canvas.js +5 -5
- package/dist/daemon/api/handlers/daemon.js +1 -1
- package/dist/daemon/api/handlers/delivery.d.ts +2 -0
- package/dist/daemon/api/handlers/delivery.js +1 -0
- package/dist/daemon/api/handlers/{memory.d.ts → docs.d.ts} +1 -1
- package/dist/daemon/api/handlers/docs.js +1 -0
- package/dist/daemon/api/handlers/hook-exec.js +1 -1
- package/dist/daemon/api/handlers/messages.js +2 -2
- package/dist/daemon/api/handlers/node-records.js +2 -2
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/objects.d.ts +2 -0
- package/dist/daemon/api/handlers/objects.js +5 -0
- package/dist/daemon/api/handlers/package-docs.d.ts +2 -0
- package/dist/daemon/api/handlers/package-docs.js +1 -0
- package/dist/daemon/api/handlers/profiles.js +1 -1
- package/dist/daemon/api/handlers/reports.d.ts +2 -2
- package/dist/daemon/api/handlers/reports.js +4 -4
- package/dist/daemon/api/handlers/reviews.js +1 -1
- package/dist/daemon/api/map.d.ts +2 -2
- package/dist/daemon/api/map.js +2 -2
- package/dist/daemon/api/operations.d.ts +1 -1
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/reader.d.ts +17 -0
- package/dist/daemon/api/reader.js +1 -0
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/control.d.ts +2 -3
- package/dist/daemon/crtrd.js +8 -6
- package/dist/daemon/fleet.js +4 -4
- package/dist/daemon/reconcilers/bash-deadline.d.ts +11 -1
- package/dist/daemon/reconcilers/bash-deadline.js +2 -1
- package/dist/daemon/reconcilers/broker-supervision.js +4 -4
- package/dist/daemon/reconcilers/live-obligation.js +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/storage-maintenance.d.ts +1 -0
- package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
- package/dist/daemon/review/deliver.js +2 -2
- package/dist/daemon/review/finish.js +1 -1
- package/dist/hook-authoring.d.ts +0 -1
- package/dist/hook-authoring.js +3 -3
- package/dist/migrations/004-canvas-documents/apply.d.ts +10 -0
- package/dist/migrations/004-canvas-documents/apply.js +1 -0
- package/dist/migrations/004-canvas-documents/fields.d.ts +24 -0
- package/dist/migrations/004-canvas-documents/fields.js +2 -0
- package/dist/migrations/004-canvas-documents/index.d.ts +16 -0
- package/dist/migrations/004-canvas-documents/index.js +2 -0
- package/dist/migrations/004-canvas-documents/legacy/discover.d.ts +16 -0
- package/dist/migrations/004-canvas-documents/legacy/discover.js +1 -0
- package/dist/migrations/004-canvas-documents/legacy/history.d.ts +5 -0
- package/dist/migrations/004-canvas-documents/legacy/history.js +2 -0
- package/dist/migrations/004-canvas-documents/legacy/nested.d.ts +7 -0
- package/dist/migrations/004-canvas-documents/legacy/nested.js +1 -0
- package/dist/migrations/004-canvas-documents/legacy/parse.d.ts +14 -0
- package/dist/migrations/004-canvas-documents/legacy/parse.js +1 -0
- package/dist/migrations/004-canvas-documents/legacy/types.d.ts +91 -0
- package/dist/migrations/004-canvas-documents/legacy/types.js +0 -0
- package/dist/migrations/004-canvas-documents/legacy-edges.d.ts +6 -0
- package/dist/migrations/004-canvas-documents/legacy-edges.js +18 -0
- package/dist/migrations/004-canvas-documents/plan.d.ts +102 -0
- package/dist/migrations/004-canvas-documents/plan.js +3 -0
- package/dist/migrations/004-canvas-documents/pointers.d.ts +23 -0
- package/dist/migrations/004-canvas-documents/pointers.js +4 -0
- package/dist/migrations/activation.d.ts +9 -18
- package/dist/migrations/activation.js +2 -2
- package/dist/pi-extensions/broker-local.d.ts +2 -2
- package/dist/pi-extensions/broker-local.js +2 -2
- package/dist/pi-extensions/canvas-bash-valve.js +5 -4
- package/dist/pi-extensions/canvas-context-intro.js +2 -2
- package/dist/pi-extensions/canvas-doc-substrate.d.ts +0 -1
- package/dist/pi-extensions/canvas-doc-substrate.js +6 -6
- package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
- package/dist/pi-extensions/canvas-passive-context.js +1 -1
- package/dist/pi-extensions/canvas-recap.js +2 -2
- package/dist/pi-extensions/canvas-stophook.d.ts +1 -1
- package/dist/pi-extensions/canvas-stophook.js +1 -1
- package/dist/prompts/review.js +3 -3
- package/dist/shared/env.d.ts +5 -0
- package/dist/shared/env.js +1 -1
- package/dist/shared/generated-context.js +2 -10
- package/dist/shared/inbox-entry-body.d.ts +22 -0
- package/dist/shared/inbox-entry-body.js +10 -0
- package/dist/{core/memory → shared}/inline-ref-guidance.d.ts +2 -2
- package/dist/shared/inline-ref-guidance.js +2 -0
- package/dist/types.d.ts +3 -1
- package/docs/cli/memory-and-preferences.md +12 -14
- package/docs/concepts/README.md +1 -1
- package/docs/concepts/lifecycle-and-wakes.md +1 -1
- package/docs/concepts/memory.md +15 -15
- package/docs/concepts/nodes-and-the-canvas.md +1 -1
- package/docs/concepts/profiles-kinds-and-modes.md +5 -5
- package/docs/concepts/scopes-and-trust.md +1 -1
- package/docs/concepts/why-a-daemon.md +1 -1
- package/docs/sdk/README.md +5 -6
- package/docs/sdk/errors.md +0 -13
- package/docs/sdk/guides/README.md +0 -1
- package/docs/sdk/nodes.md +0 -2
- package/docs/sdk/resources.md +0 -1
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +11 -11
- package/dist/api/dto/memory.d.ts +0 -171
- package/dist/api/dto/memory.js +0 -1
- package/dist/builtin-memory/crouter-sdk/guides/app-memory.md +0 -73
- package/dist/builtin-memory/crouter-sdk/memory.md +0 -87
- package/dist/commands/broker-permissions.d.ts +0 -2
- package/dist/commands/broker-permissions.js +0 -1
- package/dist/commands/memory/client.d.ts +0 -11
- package/dist/commands/memory/client.js +0 -1
- package/dist/commands/memory/delete.d.ts +0 -1
- package/dist/commands/memory/delete.js +0 -1
- package/dist/commands/memory/edit.d.ts +0 -1
- package/dist/commands/memory/edit.js +0 -21
- package/dist/commands/memory/find.d.ts +0 -1
- package/dist/commands/memory/find.js +0 -1
- package/dist/commands/memory/history.d.ts +0 -1
- package/dist/commands/memory/history.js +0 -5
- package/dist/commands/memory/lint.d.ts +0 -1
- package/dist/commands/memory/lint.js +0 -1
- package/dist/commands/memory/list.d.ts +0 -1
- package/dist/commands/memory/list.js +0 -1
- package/dist/commands/memory/move.d.ts +0 -1
- package/dist/commands/memory/move.js +0 -1
- package/dist/commands/memory/origin.d.ts +0 -1
- package/dist/commands/memory/origin.js +0 -1
- package/dist/commands/memory/read.d.ts +0 -1
- package/dist/commands/memory/read.js +0 -6
- package/dist/commands/memory/shared.d.ts +0 -22
- package/dist/commands/memory/shared.js +0 -1
- package/dist/commands/memory/write.d.ts +0 -1
- package/dist/commands/memory/write.js +0 -13
- package/dist/commands/memory.js +0 -1
- package/dist/commands/node-inspect-artifacts.d.ts +0 -1
- package/dist/commands/node-inspect-artifacts.js +0 -8
- package/dist/core/help/memory-extensions.d.ts +0 -3
- package/dist/core/help/memory-extensions.js +0 -2
- package/dist/core/memory/cli-selector.d.ts +0 -13
- package/dist/core/memory/cli-selector.js +0 -1
- package/dist/core/memory/doc-link-grammar.d.ts +0 -20
- package/dist/core/memory/doc-link-grammar.js +0 -2
- package/dist/core/memory/extensions.js +0 -1
- package/dist/core/memory/history.d.ts +0 -87
- package/dist/core/memory/history.js +0 -6
- package/dist/core/memory/identity.d.ts +0 -65
- package/dist/core/memory/identity.js +0 -1
- package/dist/core/memory/inline-ref-guidance.js +0 -2
- package/dist/core/memory/inline-ref-inventory.d.ts +0 -9
- package/dist/core/memory/inline-ref-inventory.js +0 -1
- package/dist/core/memory/lint.d.ts +0 -163
- package/dist/core/memory/lint.js +0 -2
- package/dist/core/memory/mutation-domain.d.ts +0 -113
- package/dist/core/memory/mutation-domain.js +0 -12
- package/dist/core/memory/mutations.d.ts +0 -74
- package/dist/core/memory/mutations.js +0 -1
- package/dist/core/memory/project-namespace.d.ts +0 -31
- package/dist/core/memory/project-namespace.js +0 -2
- package/dist/core/memory/repository-association.d.ts +0 -31
- package/dist/core/memory/repository-association.js +0 -1
- package/dist/core/memory/service.d.ts +0 -145
- package/dist/core/memory/service.js +0 -2
- package/dist/core/memory/tree.d.ts +0 -39
- package/dist/core/memory/tree.js +0 -1
- package/dist/core/memory-resolver.d.ts +0 -280
- package/dist/core/memory-resolver.js +0 -2
- package/dist/core/nested-stores.d.ts +0 -18
- package/dist/core/nested-stores.js +0 -1
- package/dist/core/runtime/memory.d.ts +0 -3
- package/dist/core/runtime/memory.js +0 -1
- package/dist/core/substrate/frontmatter-validation.d.ts +0 -11
- package/dist/core/substrate/frontmatter-validation.js +0 -1
- package/dist/core/substrate/gate.d.ts +0 -16
- package/dist/core/substrate/gate.js +0 -1
- package/dist/core/substrate/index.d.ts +0 -18
- package/dist/core/substrate/index.js +0 -1
- package/dist/core/substrate/injected-store.d.ts +0 -75
- package/dist/core/substrate/injected-store.js +0 -2
- package/dist/core/substrate/listings.d.ts +0 -28
- package/dist/core/substrate/listings.js +0 -1
- package/dist/core/substrate/memory-events.d.ts +0 -6
- package/dist/core/substrate/memory-events.js +0 -1
- package/dist/core/substrate/on-read-node.d.ts +0 -6
- package/dist/core/substrate/on-read-node.js +0 -1
- package/dist/core/substrate/on-read.d.ts +0 -101
- package/dist/core/substrate/on-read.js +0 -9
- package/dist/core/substrate/plan.d.ts +0 -94
- package/dist/core/substrate/plan.js +0 -1
- package/dist/core/substrate/render-node.d.ts +0 -12
- package/dist/core/substrate/render-node.js +0 -1
- package/dist/core/substrate/render.d.ts +0 -41
- package/dist/core/substrate/render.js +0 -65
- package/dist/core/substrate/session-cache.d.ts +0 -27
- package/dist/core/substrate/session-cache.js +0 -1
- package/dist/core/substrate/surface-match.d.ts +0 -73
- package/dist/core/substrate/surface-match.js +0 -1
- package/dist/daemon/api/handlers/memory.js +0 -5
- package/dist/migrations/001-surfaces-frontmatter.d.ts +0 -2
- package/dist/migrations/001-surfaces-frontmatter.js +0 -1
- package/dist/migrations/002-profile-project-memory.d.ts +0 -2
- package/dist/migrations/002-profile-project-memory.js +0 -1
- package/dist/migrations/003-repository-root-memory-identity/front-door.d.ts +0 -26
- package/dist/migrations/003-repository-root-memory-identity/front-door.js +0 -11
- package/dist/migrations/003-repository-root-memory-identity/index.d.ts +0 -2
- package/dist/migrations/003-repository-root-memory-identity/index.js +0 -5
- package/dist/migrations/003-repository-root-memory-identity/references.d.ts +0 -95
- package/dist/migrations/003-repository-root-memory-identity/references.js +0 -5
- package/dist/migrations/003-repository-root-memory-identity/repository-facts.d.ts +0 -39
- package/dist/migrations/003-repository-root-memory-identity/repository-facts.js +0 -3
- package/dist/migrations/convergent.d.ts +0 -43
- package/dist/migrations/convergent.js +0 -2
- package/dist/migrations/corpus.d.ts +0 -75
- package/dist/migrations/corpus.js +0 -3
- package/dist/migrations/frontmatter-splice.d.ts +0 -15
- package/dist/migrations/frontmatter-splice.js +0 -8
- package/dist/migrations/profile-manifests.d.ts +0 -30
- package/dist/migrations/profile-manifests.js +0 -2
- package/dist/migrations/registry.d.ts +0 -7
- package/dist/migrations/registry.js +0 -1
- package/dist/migrations/runner.d.ts +0 -43
- package/dist/migrations/runner.js +0 -1
- package/dist/migrations/types.d.ts +0 -211
- package/dist/shared/birth-announcement.d.ts +0 -12
- package/dist/shared/birth-announcement.js +0 -1
- package/docs/sdk/guides/app-memory.md +0 -22
- package/docs/sdk/memory.md +0 -85
- /package/dist/{migrations/types.js → api/dto/delivery.js} +0 -0
- /package/dist/{core/memory → shared}/inline-ref-grammar.d.ts +0 -0
- /package/dist/{core/memory → shared}/inline-ref-grammar.js +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import type { EventName, Level, ListenDelivery } from '../graph/types.js';
|
|
2
3
|
import { type InboxDisposition, type InboxKind, type InboxTier } from './inbox.js';
|
|
3
4
|
export type { InboxDisposition, InboxKind, InboxTier } from './inbox.js';
|
|
4
5
|
export interface NodeMailInput {
|
|
@@ -12,6 +13,8 @@ export interface NodeMailInput {
|
|
|
12
13
|
urgency: InboxTier;
|
|
13
14
|
wake: 0 | 1;
|
|
14
15
|
operationId?: string;
|
|
16
|
+
/** Caller-chosen message id, so a request can know its id before the insert. */
|
|
17
|
+
messageId?: string;
|
|
15
18
|
/** Optional caller-owned obligation identity, used by cron settlement replay. */
|
|
16
19
|
idempotencyKey?: string;
|
|
17
20
|
/** Runs with the mail insert, before the transaction commits. */
|
|
@@ -39,16 +42,40 @@ export interface EnqueuedExternalAction {
|
|
|
39
42
|
messageId: string;
|
|
40
43
|
deliveryId: string;
|
|
41
44
|
}
|
|
42
|
-
type Subscriber = {
|
|
43
|
-
node_id: string;
|
|
44
|
-
active: boolean;
|
|
45
|
-
};
|
|
46
45
|
/** Insert one immutable message and one node-inbox obligation into the caller's write transaction. */
|
|
47
46
|
export declare function enqueueNodeMail(destinationNodeId: string, input: NodeMailInput): EnqueuedNodeMail;
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
export interface EventMailInput extends Omit<NodeMailInput, 'wake' | 'urgency' | 'idempotencyKey' | 'withinEnqueue'> {
|
|
48
|
+
event: EventName;
|
|
49
|
+
objectId: string;
|
|
50
|
+
level: Level;
|
|
51
|
+
actorId: string | null;
|
|
52
|
+
}
|
|
53
|
+
export interface EventMailDestination {
|
|
54
|
+
nodeId: string;
|
|
55
|
+
urgency: InboxTier;
|
|
56
|
+
wake: 0 | 1;
|
|
57
|
+
}
|
|
58
|
+
/** Contract §1: a listening delivery maps 1:1 onto an inbox tier; only `next-turn` does not wake. */
|
|
59
|
+
export declare function listenDeliveryTier(delivery: ListenDelivery): {
|
|
60
|
+
urgency: InboxTier;
|
|
61
|
+
wake: 0 | 1;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Write one pushed event's `messages` row and a delivery per destination, inside the caller's
|
|
65
|
+
* write transaction. Terminal destinations get deferred/normal raised to urgent only for
|
|
66
|
+
* node reports and notices; each delivery settles a matching controller wait and a waking
|
|
67
|
+
* delivery cancels the destination's wake-cancellable crons.
|
|
68
|
+
*/
|
|
69
|
+
export declare function insertEventMail(db: DatabaseSync, input: EventMailInput, destinations: readonly EventMailDestination[]): Array<EnqueuedNodeMail & {
|
|
50
70
|
destinationNodeId: string;
|
|
51
71
|
}>;
|
|
72
|
+
/** Queue one runtime notice to a node's inbox inside the caller's write transaction (no sender). */
|
|
73
|
+
export declare function queueNodeNotice(db: DatabaseSync, nodeId: string, notice: {
|
|
74
|
+
body: string;
|
|
75
|
+
label?: string;
|
|
76
|
+
tier: InboxTier;
|
|
77
|
+
wake: 0 | 1;
|
|
78
|
+
}): EnqueuedNodeMail;
|
|
52
79
|
/** Insert one frozen external-action obligation. A duplicate idempotency key returns its original identity. */
|
|
53
80
|
export declare function enqueueExternalAction(input: ExternalActionInput): EnqueuedExternalAction;
|
|
54
81
|
/** Retract an obligation without fabricating a terminal receipt. */
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
var
|
|
2
|
-
(message_id, seq, operation_id, created_at, sender_node_id, sender_name, kind, label, body_ref, body_json, disposition
|
|
3
|
-
|
|
1
|
+
var h=Object.defineProperty;var l=(r,e)=>h(r,"name",{value:e,configurable:!0});import{existsSync as O,mkdirSync as T,renameSync as D,writeFileSync as L}from"node:fs";import{randomBytes as x,randomUUID as C}from"node:crypto";import{join as M}from"node:path";import{cancelCronsOnWake as f}from"../canvas/crons.js";import{withCanvasWrite as m}from"../canvas/db.js";import{getRow as W}from"../canvas/canvas.js";import{messagesDir as J}from"../canvas/paths.js";import{syncDirectory as F,syncFile as U}from"../fs-utils.js";import{settleDeadControllerWait as H,settleMatchingControllerWait as N}from"../canvas/waits.js";import{generateOperationId as w,operationIdContext as E,validateOperationId as j}from"../events/operation-id.js";import{clipBody as $}from"../../shared/inbox-entry-body.js";function _(){let r;do r=x(16).toString("hex");while(r==="00000000000000000000000000000000");return r}l(_,"newId");function v(r,e){const n=JSON.stringify(r);if(n===void 0)throw new TypeError(`${e} must be JSON-serializable`);return n}l(v,"stringify");function k(r,e){return e!=="normal"&&e!=="deferred"?e:W(r)?.lifecycle==="terminal"?"urgent":e}l(k,"effectiveTier");function q(r,e,n){const d=J(r);O(d)||T(d,{recursive:!0});const t=e.replace(/[^0-9]/g,""),o=M(d,`${t}-${C().slice(0,6)}.md`),i=`${o}.tmp`;return L(i,n,"utf8"),U(i),D(i,o),F(d),o}l(q,"writeMessageBody");function K(r){if(typeof r!="object"||r===null)return"";const e=r.body;return typeof e=="string"?e.trim():""}l(K,"inlineBody");function u(r,e){const n=e.messageId??_(),d=Number(r.prepare("SELECT COALESCE(MAX(seq), 0) AS seq FROM messages").get().seq)+1;return r.prepare(`INSERT INTO messages
|
|
2
|
+
(message_id, seq, operation_id, created_at, sender_node_id, sender_name, kind, label, body_ref, body_json, disposition,
|
|
3
|
+
event, object_id, level, actor_id)
|
|
4
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(n,d,e.operationId,e.createdAt,e.senderNodeId,e.senderName,e.kind,e.label,e.bodyRef,e.bodyJson===void 0?null:v(e.bodyJson,"message body"),e.disposition,e.event?.event??null,e.event?.objectId??null,e.event?.level??null,e.event?.actorId??null),n}l(u,"insertMessage");function S(r,e,n,d,t,o,i){const a=_();return r.prepare(`INSERT INTO deliveries
|
|
4
5
|
(delivery_id, message_id, destination_kind, destination_id, urgency, wake, state, idempotency_key, created_at, updated_at)
|
|
5
|
-
VALUES (?, ?, 'node_inbox', ?, ?, ?, 'pending', ?, ?, ?)`).run(a,e,d,
|
|
6
|
-
FROM deliveries d JOIN messages m ON m.message_id = d.message_id WHERE d.idempotency_key = ?`).get(e.idempotencyKey);if(
|
|
6
|
+
VALUES (?, ?, 'node_inbox', ?, ?, ?, 'pending', ?, ?, ?)`).run(a,e,n,d,t,i??null,o,o),a}l(S,"insertNodeDelivery");function p(r,e){const n=new Date().toISOString(),d=r.operationId===void 0?E.current()??w():j(r.operationId);let t=r.bodyRef??null,o=r.bodyJson;if(t===null&&r.senderNodeId!=="human"){const i=K(o),a=$(i);a.clipped&&(t=q(e,n,i),o={...o,body:a.text})}return{createdAt:n,operationId:d,bodyRef:t,bodyJson:o}}l(p,"finalizeNodeMail");function P(r,e){const n=p(e,r);return m(d=>{const t=d.prepare("SELECT run_id FROM nodes WHERE node_id = ?").get(r);if(t?.run_id&&d.prepare("SELECT deleting_at FROM nodes WHERE node_id = ?").get(t.run_id)?.deleting_at)throw new Error("run is deleting");if(e.idempotencyKey!==void 0){const c=d.prepare(`SELECT d.delivery_id, d.message_id, d.urgency, m.created_at
|
|
7
|
+
FROM deliveries d JOIN messages m ON m.message_id = d.message_id WHERE d.idempotency_key = ?`).get(e.idempotencyKey);if(c!==void 0)return{messageId:c.message_id,deliveryId:c.delivery_id,urgency:c.urgency,createdAt:c.created_at}}const o=Date.now(),i=k(r,e.urgency),a=u(d,{messageId:e.messageId,operationId:n.operationId,createdAt:n.createdAt,senderNodeId:e.senderNodeId??null,senderName:e.senderName??null,kind:e.kind,label:e.label,bodyRef:n.bodyRef,bodyJson:n.bodyJson,disposition:e.disposition??null}),y=S(d,a,r,i,e.wake,o,e.idempotencyKey);return N(r,e.senderNodeId??null,o,d),e.withinEnqueue?.(d,a),e.wake===1&&i!=="deferred"&&f(r),{messageId:a,deliveryId:y,urgency:i,createdAt:n.createdAt}})}l(P,"enqueueNodeMail");function te(r){switch(r){case"interrupt":return{urgency:"critical",wake:1};case"steer":return{urgency:"urgent",wake:1};case"after-turn":return{urgency:"normal",wake:1};case"next-turn":return{urgency:"deferred",wake:0}}}l(te,"listenDeliveryTier");function oe(r,e,n){if(n.length===0)return[];const d=p({...e,urgency:"normal"},n[0].nodeId),t=Date.now(),o=u(r,{messageId:e.messageId,operationId:d.operationId,createdAt:d.createdAt,senderNodeId:e.senderNodeId??null,senderName:e.senderName??null,kind:e.kind,label:e.label,bodyRef:d.bodyRef,bodyJson:d.bodyJson,disposition:e.disposition??null,event:{event:e.event,objectId:e.objectId,level:e.level,actorId:e.actorId}}),i=e.event.startsWith("report.")||e.event.startsWith("notice."),a=e.senderNodeId??null,y=n.map(s=>s.nodeId),c=`(${y.map(()=>"?").join(",")})`,b=a===null?new Set:new Set(r.prepare(`SELECT DISTINCT node_id FROM waits WHERE kind = 'controller' AND target_id = ? AND satisfied_at IS NULL AND node_id IN ${c}`).all(a,...y).map(s=>s.node_id)),A=new Set(r.prepare(`SELECT DISTINCT anchor_node FROM crons WHERE cancel_on_wake = 1 AND anchor_node IN ${c}`).all(...y).map(s=>s.anchor_node)),R=r.prepare(`INSERT INTO deliveries
|
|
8
|
+
(delivery_id, message_id, destination_kind, destination_id, urgency, wake, state, idempotency_key, created_at, updated_at)
|
|
9
|
+
VALUES (?, ?, 'node_inbox', ?, ?, ?, 'pending', NULL, ?, ?)`);return n.map(s=>{const g=i?k(s.nodeId,s.urgency):s.urgency,I=_();return R.run(I,o,s.nodeId,g,s.wake,t,t),b.has(s.nodeId)&&N(s.nodeId,a,t,r),s.wake===1&&g!=="deferred"&&A.has(s.nodeId)&&f(s.nodeId),{destinationNodeId:s.nodeId,messageId:o,deliveryId:I,urgency:g,createdAt:d.createdAt}})}l(oe,"insertEventMail");function ae(r,e,n){const d={kind:"update",label:n.label??"notice",bodyJson:{body:n.body},urgency:n.tier,wake:n.wake},t=p(d,e),o=Date.now(),i=u(r,{operationId:t.operationId,createdAt:t.createdAt,senderNodeId:null,senderName:null,kind:d.kind,label:d.label,bodyRef:t.bodyRef,bodyJson:t.bodyJson,disposition:null}),a=S(r,i,e,n.tier,n.wake,o);return n.wake===1&&n.tier!=="deferred"&&f(e),{messageId:i,deliveryId:a,urgency:n.tier,createdAt:t.createdAt}}l(ae,"queueNodeNotice");function ie(r){return m(e=>{const n=e.prepare("SELECT delivery_id, message_id FROM deliveries WHERE idempotency_key = ?").get(r.idempotencyKey);if(n!==void 0)return{messageId:n.message_id,deliveryId:n.delivery_id};const d=Date.now(),t=u(e,{operationId:E.current()??w(),createdAt:new Date(d).toISOString(),senderNodeId:null,senderName:null,kind:r.kind??"completed",label:r.label??r.destinationId,bodyRef:null,bodyJson:r.bodyJson,disposition:null}),o=_(),i=e.prepare(`INSERT INTO deliveries
|
|
7
10
|
(delivery_id, message_id, destination_kind, destination_id, urgency, wake, state, next_attempt_at,
|
|
8
11
|
adapter_json, idempotency_key, created_at, updated_at)
|
|
9
12
|
VALUES (?, ?, 'external_action', ?, 'normal', 0, 'pending', ?, ?, ?, ?, ?)
|
|
10
|
-
ON CONFLICT(idempotency_key) WHERE idempotency_key IS NOT NULL DO NOTHING`).run(t,
|
|
11
|
-
WHERE w.node_id = ? AND w.kind = 'controller' AND w.target_id = ? AND w.satisfied_at IS NULL`).get(
|
|
13
|
+
ON CONFLICT(idempotency_key) WHERE idempotency_key IS NOT NULL DO NOTHING`).run(o,t,r.destinationId,d,v(r.adapter,"external action adapter"),r.idempotencyKey,d,d);if(Number(i.changes)===1)return{messageId:t,deliveryId:o};const a=e.prepare("SELECT delivery_id, message_id FROM deliveries WHERE idempotency_key = ?").get(r.idempotencyKey);if(a===void 0)throw new Error(`external action idempotency winner disappeared: ${r.idempotencyKey}`);return{messageId:a.message_id,deliveryId:a.delivery_id}})}l(ie,"enqueueExternalAction");function se(r,e=Date.now()){return m(n=>Number(n.prepare("UPDATE deliveries SET canceled_at = ?, updated_at = ? WHERE delivery_id = ? AND canceled_at IS NULL").run(e,e,r).changes)===1)}l(se,"cancelDelivery");function le(r,e={}){return m(n=>{const d=["d.destination_kind = 'node_inbox'","d.destination_id = ?","d.canceled_at IS NULL","d.state IN ('pending', 'handed_off')"],t=[r];e.senderNodeId!==void 0&&(d.push("m.sender_node_id IS ?"),t.push(e.senderNodeId)),e.kind!==void 0&&(d.push("m.kind = ?"),t.push(e.kind));const o=n.prepare(`SELECT d.delivery_id FROM deliveries d JOIN messages m ON m.message_id = d.message_id WHERE ${d.join(" AND ")}`).all(...t);if(o.length===0)return[];const i=Date.now();return n.prepare(`UPDATE deliveries SET canceled_at = ?, updated_at = ? WHERE delivery_id IN (${o.map(()=>"?").join(",")})`).run(i,i,...o.map(a=>a.delivery_id)),o.map(a=>a.delivery_id)})}l(le,"cancelPendingNodeMail");function ce(r,e){return m(n=>{const d=Date.now(),t=n.prepare(`SELECT target.status AS controller_status FROM waits w LEFT JOIN nodes target ON target.node_id = w.target_id
|
|
14
|
+
WHERE w.node_id = ? AND w.kind = 'controller' AND w.target_id = ? AND w.satisfied_at IS NULL`).get(r,e);if(t===void 0||t.controller_status==="active"||t.controller_status==="idle")return null;const o=P(r,{kind:"urgent",label:"declared controller is no longer live",bodyJson:{body:`Controller ${e} is no longer live; the declared message wait was cleared.`},urgency:"urgent",wake:1});if(!H(r,e,d,n))throw new Error(`controller wait changed while notifying ${r}`);return o})}l(ce,"enqueueControllerDeathNotice");export{se as cancelDelivery,le as cancelPendingNodeMail,ce as enqueueControllerDeathNotice,ie as enqueueExternalAction,P as enqueueNodeMail,oe as insertEventMail,te as listenDeliveryTier,ae as queueNodeNotice};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Whether `nodeId` owns any live report document — proof it already did work. */
|
|
2
|
+
export declare function hasReportDocuments(nodeId: string): boolean;
|
|
3
|
+
/** `<nodeId>/<name>` of `nodeId`'s newest live report document — the name
|
|
4
|
+
* `crtr canvas read` takes — or null when it pushed none. */
|
|
5
|
+
export declare function newestReportName(nodeId: string): string | null;
|
|
6
|
+
/** Body of `nodeId`'s newest live report document, trimmed; '' when it pushed none. */
|
|
7
|
+
export declare function newestReportBody(nodeId: string): string;
|
|
8
|
+
/** Body of the report document a push's `<nodeId>/reports/<name>` ref names;
|
|
9
|
+
* null when the ref is not that shape or the document is gone. */
|
|
10
|
+
export declare function reportBodyByName(ref: string): string | null;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var f=Object.defineProperty;var o=(t,e)=>f(t,"name",{value:e,configurable:!0});import{openDb as d}from"../canvas/db.js";import{get as s}from"../graph/bodies.js";import{heads as p}from"../graph/documents.js";import{getById as u}from"../graph/objects.js";function N(t){const e=d(),n=u(e,t);return n===null||n.type!=="node"?!1:e.prepare("SELECT 1 FROM objects WHERE owner = ? AND type = 'document' AND kind = 'report' AND deleted_at IS NULL LIMIT 1").get(n.rowid)!==void 0}o(N,"hasReportDocuments");function a(t){const e=d(),n=u(e,t);if(!(n===null||n.type!=="node"))return e.prepare(`SELECT * FROM objects WHERE owner = ? AND type = 'document' AND kind = 'report' AND deleted_at IS NULL
|
|
2
|
+
ORDER BY created_at DESC, name DESC LIMIT 1`).get(n.rowid)}o(a,"newestReport");function h(t){const e=a(t);return e===void 0?null:`${t}/${e.name}`}o(h,"newestReportName");function R(t){const e=d(),n=a(t);if(n===void 0)return"";const r=p(e,n)[0];if(r===void 0)return"";try{return s(r.body_hash).trim()}catch{return""}}o(R,"newestReportBody");function L(t){const e=t.indexOf("/");if(e<=0||!t.startsWith("reports/",e+1))return null;const n=d(),r=u(n,t.slice(0,e));if(r===null||r.type!=="node")return null;const c=n.prepare("SELECT * FROM objects WHERE owner = ? AND type = 'document' AND name = ? AND deleted_at IS NULL").get(r.rowid,t.slice(e+1)),i=c===void 0?void 0:p(n,c)[0];if(i===void 0)return null;try{return s(i.body_hash)}catch{return null}}o(L,"reportBodyByName");export{N as hasReportDocuments,R as newestReportBody,h as newestReportName,L as reportBodyByName};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var R=Object.defineProperty;var d=(r,i)=>R(r,"name",{value:i,configurable:!0});import{rmSync as
|
|
1
|
+
var R=Object.defineProperty;var d=(r,i)=>R(r,"name",{value:i,configurable:!0});import{rmSync as w}from"node:fs";import{join as S}from"node:path";import{deleteNodes as h}from"../canvas/canvas.js";import{openDb as f,withCanvasWrite as c}from"../canvas/db.js";import{cancelCron as O}from"../canvas/crons.js";import{emitEvent as m}from"../events/emit.js";import{appSpace as T,appsRoot as E,secretsDir as C}from"../layout.js";import{notifyRunDeleted as D}from"../runs/events.js";import{cancelOpenQuestions as N}from"../runs/questions.js";import{removeTreeBeneath as L}from"../spaces/open-beneath.js";import{markGranteeUploadsDeletePending as W,releaseRunUploads as F,turnSharesOffFor as H}from"../storage/tables.js";import{stopNodeSandboxes as b}from"../spaces/stop.js";import{activeAppUser as p,markAppUserRemoved as M}from"../spaces/users.js";import{launcherRequest as A}from"../../launcher/client.js";import{LaunchRefused as I}from"../../launcher/spec.js";import{allGrants as y}from"./mirror.js";import{launcherPresent as u,listSandboxes as P,stopSandboxPid as U}from"./sandboxes.js";let _=Promise.resolve();function te(r=new Set){const i=_.then(async()=>{const n=y(),o=new Set(n.filter(t=>t.status==="removed").map(t=>t.grantee));for(const t of o)if(!n.some(a=>a.grantee===t&&a.status==="active")&&!(p(t)===null&&!r.has(t)))try{await x(t)}catch(a){m({level:"error",event:"daemon.grants.removal_failed",error:a,fields:{grantee:t}})}});return _=i.catch(()=>{}),i}d(te,"runRemovalCascades");async function x(r){if(r==="app:terminal")throw new Error("app:terminal cannot be removed");const i=T(r),n=p(r);m({level:"info",event:"daemon.grants.removal_started",fields:{grantee:r,uid:n?.uid??null}}),await N({grantee:r},"the app was removed");const o=c(e=>(e.prepare("UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id IN (SELECT node_id FROM node_rows WHERE grantee = ?)").run(new Date().toISOString(),r),e.prepare("SELECT node_id FROM node_rows WHERE grantee = ? ORDER BY created DESC").all(r).map(s=>s.node_id)));for(const{cron_id:e}of f().prepare("SELECT cron_id FROM crons WHERE grantee = ?").all(r))O(e);const a=(await Promise.all(o.map(e=>b(e,"app_removed",{deleting:!0})))).filter(e=>!e.confirmed);if(a.length)throw new Error(`sandbox teardown could not be confirmed for ${a.length} node(s) of ${r}`);if(n&&u())for(const e of await P())e.uid===n.uid&&await U(e.pid);const g=o.filter(e=>f().prepare("SELECT run_id FROM nodes WHERE node_id = ?").get(e)?.run_id===e);c(e=>{if(H(r,e),F(o,e),W(r,e),!o.length)return;const s=o.map(()=>"?").join(","),v=e.prepare(`SELECT message_id FROM messages WHERE sender_node_id IN (${s}) UNION SELECT message_id FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (${s})`).all(...o,...o);e.prepare(`DELETE FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (${s})`).run(...o);for(const{message_id:l}of v)e.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(l,l)}),h(o);for(const e of g)D(e);if(w(S(C(),"env",i.root.slice(E().length+1)),{recursive:!0,force:!0}),L(E(),i.root),n&&u())try{await A({operation:"user.delete",uid:n.uid})}catch(e){if(!(e instanceof I&&e.refusal==="invalid_uid"))throw e}n&&M(n.uid),m({level:"info",event:"daemon.grants.removal_completed",fields:{grantee:r,uid:n?.uid??null,nodes:o.length}})}d(x,"removeApp");export{x as removeApp,te as runRemovalCascades};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import type { ObjectRow, Reader } from './types.js';
|
|
3
|
+
/** The object's owners, nearest first, ending at its space; empty when the object is a space. */
|
|
4
|
+
export declare function ownerChain(db: DatabaseSync, object: ObjectRow): ObjectRow[];
|
|
5
|
+
export declare function spaceOf(db: DatabaseSync, object: ObjectRow): ObjectRow;
|
|
6
|
+
/** A shipped document: one a package reconciler owns, read from its package file
|
|
7
|
+
* (`documents.source_path` is set). Only the reconciler writes it. */
|
|
8
|
+
export declare function isShipped(db: DatabaseSync, object: ObjectRow): boolean;
|
|
9
|
+
/** The apps whose tools a run may use, `crtr` last. On a local runtime (v0) every
|
|
10
|
+
* installed, enabled plugin's tools are usable by every run, and an installed
|
|
11
|
+
* plugin is exactly an app holding live shipped documents. Hosted grants narrow
|
|
12
|
+
* this per reader later; `mayUseTools` is the one question both ask. */
|
|
13
|
+
export declare function toolApps(db: DatabaseSync, reader: Reader): ObjectRow[];
|
|
14
|
+
/** May `reader` use any of `app`'s tool groups? v0: every run may use every installed plugin's tools. */
|
|
15
|
+
export declare function mayUseTools(_db: DatabaseSync, _reader: Reader, app: ObjectRow): boolean;
|
|
16
|
+
/** Callers turn `false` into `not_found`. A person reader reads everything. An app's
|
|
17
|
+
* shipped documents are read by any run that may use that app's tools. */
|
|
18
|
+
export declare function canRead(db: DatabaseSync, reader: Reader, object: ObjectRow): boolean;
|
|
19
|
+
/** `canRead` for many readers of one object: the owner chain is walked once. */
|
|
20
|
+
export declare function readCheck(db: DatabaseSync, object: ObjectRow): (reader: Reader) => boolean;
|
|
21
|
+
/** Always asked of the space, also for a person: a repo never owns a non-public
|
|
22
|
+
* document, whoever asks. A shipped document is changed by nobody, its own app
|
|
23
|
+
* included — only the package reconciler writes it, and it asks no reader. */
|
|
24
|
+
export declare function canChange(db: DatabaseSync, reader: Reader, object: ObjectRow): boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
var u=Object.defineProperty;var o=(t,e)=>u(t,"name",{value:e,configurable:!0});import{SPACES as l}from"./spaces/index.js";function E(t,e){return t.prepare(`WITH RECURSIVE chain(rowid, depth) AS (
|
|
2
|
+
SELECT owner, 1 FROM objects WHERE rowid = ? AND owner IS NOT NULL
|
|
3
|
+
UNION ALL
|
|
4
|
+
SELECT o.owner, c.depth + 1 FROM objects o JOIN chain c ON o.rowid = c.rowid WHERE o.owner IS NOT NULL
|
|
5
|
+
) SELECT o.* FROM chain c JOIN objects o ON o.rowid = c.rowid ORDER BY c.depth`).all(e.rowid)}o(E,"ownerChain");function w(t,e){return c(t,e).space}o(w,"spaceOf");function c(t,e){const r=E(t,e),n=r.length?r[r.length-1]:e,p=l[n.type];if(!p)throw new Error(`${e.type} ${e.id} has no space: its owner chain ends at ${n.type} ${n.id}`);const a=r.length?[...r.slice(0,-1).reverse(),e]:[];return{space:n,path:a,impl:p}}o(c,"locate");function i(t,e){return e.type!=="document"?!1:t.prepare("SELECT source_path FROM documents WHERE object = ?").get(e.rowid)?.source_path!=null}o(i,"isShipped");function f(t,e){return t.prepare(`SELECT a.* FROM objects a WHERE a.type = 'app' AND a.deleted_at IS NULL AND EXISTS (
|
|
6
|
+
SELECT 1 FROM objects o JOIN documents d ON d.object = o.rowid
|
|
7
|
+
WHERE o.owner = a.rowid AND o.type = 'document' AND o.deleted_at IS NULL AND d.source_path IS NOT NULL)
|
|
8
|
+
ORDER BY a.name = 'crtr', a.name`).all().filter(n=>s(t,e,n))}o(f,"toolApps");function s(t,e,r){return r.type==="app"}o(s,"mayUseTools");function O(t,e,r){return d(t,r)(e)}o(O,"canRead");function d(t,e){let r=null,n=null;return p=>p.class==="person"||(r??=c(t,e),r.space.type==="app"&&r.path.length>0&&(n??=i(t,e),n&&s(t,p,r.space)))?!0:r.impl.canRead(t,p,r.space,r.path,e)}o(d,"readCheck");function R(t,e,r){if(i(t,r))return!1;const{space:n,path:p,impl:a}=c(t,r);return a.canChange(t,e,n,p,r)}o(R,"canChange");export{R as canChange,O as canRead,i as isShipped,s as mayUseTools,E as ownerChain,d as readCheck,w as spaceOf,f as toolApps};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Store a body durably (temp + fsync + rename); call before the transaction that references it. */
|
|
2
|
+
export declare function put(body: string): string;
|
|
3
|
+
export declare function get(hash: string): string;
|
|
4
|
+
/** A revision's body: a package document's (one with a `source_path`) is its file's body after
|
|
5
|
+
* the frontmatter; every other document's comes from the body store. */
|
|
6
|
+
export declare function bodyOf(hash: string, sourcePath: string | null): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var m=Object.defineProperty;var o=(r,t)=>m(r,"name",{value:t,configurable:!0});import{createHash as p}from"node:crypto";import{closeSync as y,existsSync as s,fsyncSync as d,mkdirSync as a,openSync as l,readFileSync as c,renameSync as S,writeSync as w}from"node:fs";import{join as f}from"node:path";import{notFound as b}from"../errors.js";import{crtrHome as x}from"../canvas/paths.js";import{parseFrontmatterGeneric as $}from"../frontmatter.js";function u(r){if(!/^[0-9a-f]{64}$/.test(r))throw new Error(`invalid body hash: ${r}`);return f(x(),"bodies",r.slice(0,2),r)}o(u,"bodyPath");function j(r){const t=p("sha256").update(r,"utf8").digest("hex"),n=u(t);if(s(n))return t;a(f(n,".."),{recursive:!0});const i=`${n}.tmp-${process.pid}`,e=l(i,"w");try{w(e,r,null,"utf8"),d(e)}finally{y(e)}return S(i,n),t}o(j,"put");function h(r){try{return c(u(r),"utf8")}catch(t){throw t.code==="ENOENT"?b(`no body ${r}`):t}}o(h,"get");function k(r,t){return t===null?h(r):$(c(t,"utf8")).body}o(k,"bodyOf");export{k as bodyOf,h as get,j as put};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Deleting a node with what it owns (spec §6 "Deletion follows the owner", A9). Rows are kept
|
|
2
|
+
* with `deleted_at` so every pointer resolves to "deleted" with the last preview; a document
|
|
3
|
+
* that a kept document links to passes to the node's owner instead. */
|
|
4
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
5
|
+
import type { ObjectRow } from './types.js';
|
|
6
|
+
/** Mark the node and everything it owns deleted, move kept documents to the node's owner,
|
|
7
|
+
* drop the node's watches (both ends) and its `nodes` row. One savepoint, so it runs as one
|
|
8
|
+
* transaction or inside the caller's. Refuses a node whose managed worktree is unreconciled. */
|
|
9
|
+
export declare function deleteNodeWithOwned(db: DatabaseSync, node: ObjectRow): void;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
var f=Object.defineProperty;var d=(e,o)=>f(e,"name",{value:o,configurable:!0});import{hasUnreconciledWorktree as R}from"../canvas/worktrees.js";import{deleteDocument as O}from"./documents.js";import{levelFor as a,publish as l}from"./events.js";import{getByRowid as w}from"./objects.js";import{setRulesOwner as m}from"./rules.js";let N=0;function I(e,o){if(o.type!=="node")throw new Error(`deleteNodeWithOwned: ${o.id} is a ${o.type}, not a node`);if(R(o.id))throw new Error(`refusing to delete node ${o.id}: its managed worktree is not reconciled`);const r=`graph_delete_${++N}`;e.exec(`SAVEPOINT ${r}`);try{S(e,o),e.exec(`RELEASE ${r}`)}catch(n){throw e.exec(`ROLLBACK TO ${r}`),e.exec(`RELEASE ${r}`),n}}d(I,"deleteNodeWithOwned");function S(e,o){const r=e.prepare(`WITH RECURSIVE sub(rowid) AS (
|
|
2
|
+
SELECT rowid FROM objects WHERE owner = ?
|
|
3
|
+
UNION SELECT o.rowid FROM objects o JOIN sub ON o.owner = sub.rowid)
|
|
4
|
+
SELECT o.* FROM objects o JOIN sub ON sub.rowid = o.rowid WHERE o.deleted_at IS NULL`).all(o.rowid),n=new Set(r.map(t=>t.rowid)),i=e.prepare(`SELECT e.src FROM edges e JOIN objects s ON s.rowid = e.src
|
|
5
|
+
WHERE e.type = 'links-to' AND e.dst = ? AND s.deleted_at IS NULL`),s=[];for(let t=!0;t;){t=!1;for(const E of r)E.type!=="document"||!n.has(E.rowid)||i.all(E.rowid).some(({src:u})=>!n.has(u))&&(n.delete(E.rowid),s.push(E),t=!0)}const p=w(e,o.owner);for(const t of s)h(e,t,p);const c=new Date().toISOString();for(const t of r)if(n.has(t.rowid)){if(t.type==="document"){O(e,null,t);continue}e.prepare("UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(c,t.rowid),l(e,{event:"deleted",object:w(e,t.rowid),actor:null,level:a("deleted",void 0,t.type),attrs:{}}),e.prepare("DELETE FROM watches WHERE object = ? OR watcher = ?").run(t.rowid,t.rowid)}e.prepare("UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(c,o.rowid),l(e,{event:"deleted",object:w(e,o.rowid),actor:null,level:a("deleted",void 0,"node"),attrs:{}}),e.prepare("DELETE FROM watches WHERE object = ? OR watcher = ?").run(o.rowid,o.rowid),e.prepare("DELETE FROM nodes WHERE node_id = ?").run(o.id)}d(S,"deleteInside");function h(e,o,r){const n=e.prepare("SELECT 1 FROM objects WHERE type = 'document' AND owner = ? AND name = ? AND deleted_at IS NULL");let i=o.name;for(let s=2;n.get(r.rowid,i)!==void 0;s++)i=`${o.name}-${s}`;e.prepare("UPDATE objects SET owner = ?, name = ? WHERE rowid = ?").run(r.rowid,i,o.rowid),m(e,w(e,o.rowid))}d(h,"moveToOwner");export{I as deleteNodeWithOwned};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
var b=Object.defineProperty;var m=(n,f)=>b(n,"name",{value:f,configurable:!0});function W(n,f,o=3){const{lines:l,terminated:c}=w(n),{lines:a,terminated:e}=w(f),t=K(M(l,c),M(a,e)),s=[];for(let i=0;i<t.length;i+=1){if(t[i].tag===" ")continue;const p=Math.max(0,i-o),d=Math.min(t.length,i+o+1),u=s[s.length-1];u!==void 0&&p<=u.to?u.to=Math.max(u.to,d):s.push({from:p,to:d})}if(s.length===0)return"";const r=[],N=[];let A=0,E=0;for(const i of t)r.push(A),N.push(E),i.tag!=="+"&&(A+=1),i.tag!=="-"&&(E+=1);const x=[];for(const{from:i,to:p}of s){const d=t.slice(i,p),u=d.filter(h=>h.tag!=="+").length,L=d.filter(h=>h.tag!=="-").length;x.push(`@@ -${u===0?0:r[i]+1},${u} +${L===0?0:N[i]+1},${L} @@`);for(let h=i;h<p;h+=1){const g=t[h];x.push(g.tag+(g.tag==="+"?a[g.index]:l[g.index]));const _=g.tag!=="+"&&!c&&r[h]===l.length-1,$=g.tag!=="-"&&!e&&N[h]===a.length-1;(_||$)&&x.push(j)}}return x.join(`
|
|
2
|
+
`)}m(W,"unifiedDiff");const j="\",y="\0no-newline-at-eof";function M(n,f){return f||n.length===0?n:n.map((o,l)=>l===n.length-1?o+y:o)}m(M,"diffKeys");function w(n){if(n==="")return{lines:[],terminated:!0};const f=n.endsWith(`
|
|
3
|
+
`),o=n.split(`
|
|
4
|
+
`);return f&&o.pop(),{lines:o,terminated:f}}m(w,"toLines");function K(n,f){const o=n.length,l=f.length,c=Array.from({length:o+1},()=>new Array(l+1).fill(0));for(let s=o-1;s>=0;s-=1)for(let r=l-1;r>=0;r-=1)c[s][r]=n[s]===f[r]?c[s+1][r+1]+1:Math.max(c[s+1][r],c[s][r+1]);const a=[];let e=0,t=0;for(;e<o&&t<l;)n[e]===f[t]?(a.push({tag:" ",index:e}),e+=1,t+=1):c[e+1][t]>=c[e][t+1]?(a.push({tag:"-",index:e}),e+=1):(a.push({tag:"+",index:t}),t+=1);for(;e<o;e+=1)a.push({tag:"-",index:e});for(;t<l;t+=1)a.push({tag:"+",index:t});return a}m(K,"diffOps");export{W as unifiedDiff};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/** Documents: write, CAS edit, revisions and heads, links per revision, record fields, move,
|
|
2
|
+
* delete, history, read, and the two import paths (migration, repo sync). Every act records
|
|
3
|
+
* its actor's `acted-on` edge and watch and publishes its event in the caller's transaction. */
|
|
4
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
5
|
+
import type { ReposFn } from './reader.js';
|
|
6
|
+
import type { ObjectRow, Privacy, Reader, Revision, RuleSpec } from './types.js';
|
|
7
|
+
export interface DocumentFields {
|
|
8
|
+
preview?: string;
|
|
9
|
+
summary?: string | null;
|
|
10
|
+
privacy?: Privacy;
|
|
11
|
+
rules?: readonly RuleSpec[];
|
|
12
|
+
whyItExists?: string | null;
|
|
13
|
+
unlisted?: boolean;
|
|
14
|
+
lintIgnore?: readonly string[] | null;
|
|
15
|
+
extensions?: Record<string, Record<string, unknown>> | null;
|
|
16
|
+
}
|
|
17
|
+
export interface WriteSpec extends DocumentFields {
|
|
18
|
+
owner: ObjectRow;
|
|
19
|
+
name: string;
|
|
20
|
+
kind: string;
|
|
21
|
+
preview: string;
|
|
22
|
+
privacy: Privacy;
|
|
23
|
+
}
|
|
24
|
+
export type DocumentChange = {
|
|
25
|
+
body: string;
|
|
26
|
+
verbatim?: boolean;
|
|
27
|
+
} | {
|
|
28
|
+
replace: ReadonlyArray<{
|
|
29
|
+
old: string;
|
|
30
|
+
new: string;
|
|
31
|
+
}>;
|
|
32
|
+
verbatim?: boolean;
|
|
33
|
+
};
|
|
34
|
+
export interface DocumentRecord {
|
|
35
|
+
summary: string | null;
|
|
36
|
+
heads_key: string;
|
|
37
|
+
revision: number;
|
|
38
|
+
why_it_exists: string | null;
|
|
39
|
+
unlisted: boolean;
|
|
40
|
+
lint_ignore: string[] | null;
|
|
41
|
+
extensions: Record<string, Record<string, unknown>> | null;
|
|
42
|
+
source_path: string | null;
|
|
43
|
+
}
|
|
44
|
+
export interface Head extends Revision {
|
|
45
|
+
body: string;
|
|
46
|
+
}
|
|
47
|
+
export interface RenderedLink {
|
|
48
|
+
written_as: string;
|
|
49
|
+
object: ObjectRow;
|
|
50
|
+
deleted: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface DocumentRead {
|
|
53
|
+
object: ObjectRow;
|
|
54
|
+
record: DocumentRecord;
|
|
55
|
+
heads: Head[];
|
|
56
|
+
needsMerge: boolean;
|
|
57
|
+
links: RenderedLink[];
|
|
58
|
+
}
|
|
59
|
+
/** The object a reader acts as: its node, its app, or the person. */
|
|
60
|
+
export declare function actorOf(reader: Reader): ObjectRow;
|
|
61
|
+
/** Head revisions (no child), highest number first. More than one means the document needs a merge. */
|
|
62
|
+
export declare function heads(db: DatabaseSync, doc: ObjectRow): Revision[];
|
|
63
|
+
export declare function documentRecord(db: DatabaseSync, doc: ObjectRow): DocumentRecord;
|
|
64
|
+
/** The `[[name]]` links a body names, in order, each once. */
|
|
65
|
+
export declare function linksIn(body: string): string[];
|
|
66
|
+
/** Derive the document's `links-to` edges from `body`, resolving each name in the writer's
|
|
67
|
+
* view. A name that resolves to nothing or to several objects stays text and is returned;
|
|
68
|
+
* one that may live on another runtime is neither linked nor reported. */
|
|
69
|
+
export declare function setRevisionLinks(db: DatabaseSync, reader: Reader, doc: ObjectRow, body: string): string[];
|
|
70
|
+
/** `body` with each `[[link]]` the document's `links-to` edges resolved shown under its target's
|
|
71
|
+
* current name, so a rename rewrites no stored body yet every read shows the new name (spec §4).
|
|
72
|
+
* A link written as the target's id, or to a deleted target, stays as written. */
|
|
73
|
+
export declare function withCurrentNames(db: DatabaseSync, doc: ObjectRow, body: string): string;
|
|
74
|
+
/** Write the record fields that are present; `null` clears a nullable one. Rules are
|
|
75
|
+
* replaced when given. Does not publish; callers publish the act the fields belong to. */
|
|
76
|
+
export declare function applyDocumentFields(db: DatabaseSync, doc: ObjectRow, fields: DocumentFields): ObjectRow;
|
|
77
|
+
/** Create a document with its first revision. The actor becomes a watcher whose read base is
|
|
78
|
+
* the new revision; `created` is published. Returns the names that stayed text. */
|
|
79
|
+
export declare function writeDocument(db: DatabaseSync, reader: Reader, spec: WriteSpec, body: string, reposFn?: ReposFn): {
|
|
80
|
+
object: ObjectRow;
|
|
81
|
+
revision: number;
|
|
82
|
+
unresolved: string[];
|
|
83
|
+
};
|
|
84
|
+
/** The base of the reader's next edit: the heads it last read or wrote, or null when it never has. */
|
|
85
|
+
export declare function readBase(db: DatabaseSync, reader: Reader, doc: ObjectRow): string | null;
|
|
86
|
+
/** Apply exact-text replacements to one head's body; each `old` must occur exactly once. */
|
|
87
|
+
export declare function applyReplacements(body: string, replace: ReadonlyArray<{
|
|
88
|
+
old: string;
|
|
89
|
+
new: string;
|
|
90
|
+
}>): string;
|
|
91
|
+
/**
|
|
92
|
+
* Commit a new revision made from `base` — the editor's read heads captured when it computed
|
|
93
|
+
* the change. No base → `read_first`. The commit is CAS on `documents.heads_key`: a base that is
|
|
94
|
+
* no longer current returns `{stale}` and writes nothing. The new revision's parents are every
|
|
95
|
+
* head, so an edit from a read that showed several heads merges them. `fields` are record
|
|
96
|
+
* changes applied with the edit.
|
|
97
|
+
*/
|
|
98
|
+
export declare function editDocument(db: DatabaseSync, reader: Reader, doc: ObjectRow, change: DocumentChange, rationale: string, base: string | null, fields?: DocumentFields, reposFn?: ReposFn): {
|
|
99
|
+
revision: number;
|
|
100
|
+
heads_key: string;
|
|
101
|
+
unresolved: string[];
|
|
102
|
+
} | {
|
|
103
|
+
stale: {
|
|
104
|
+
heads_key: string;
|
|
105
|
+
revision: number;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
/** Change record fields (preview, summary, privacy, rules, …) without a new revision. A null
|
|
109
|
+
* reader is repo sync, which carries no reader and checks no access. */
|
|
110
|
+
export declare function setDocumentRecord(db: DatabaseSync, reader: Reader | null, doc: ObjectRow, fields: DocumentFields): ObjectRow;
|
|
111
|
+
/** Record that the reader holds the document's current heads: a `read` watch with that read
|
|
112
|
+
* base, and a `read` push. Delivery's content load calls this without reading the body. */
|
|
113
|
+
export declare function recordRead(db: DatabaseSync, reader: Reader, doc: ObjectRow, reposFn?: ReposFn): void;
|
|
114
|
+
/** The document's record, each head with its body (several = needs merge) and its links under
|
|
115
|
+
* their current names; records the read. */
|
|
116
|
+
export declare function readDocument(db: DatabaseSync, reader: Reader, doc: ObjectRow, reposFn?: ReposFn): DocumentRead;
|
|
117
|
+
/** Every revision, newest first, with authors, rationales and parents. Records nothing. */
|
|
118
|
+
export declare function history(db: DatabaseSync, reader: Reader, doc: ObjectRow): Revision[];
|
|
119
|
+
/** Rename and/or re-own a document. Only `objects` changes: links point at the id, so no body is
|
|
120
|
+
* rewritten. A null actor is repo sync, which carries no reader and checks no access. */
|
|
121
|
+
export declare function moveDocument(db: DatabaseSync, reader: Reader | null, doc: ObjectRow, to: {
|
|
122
|
+
name?: string;
|
|
123
|
+
owner?: ObjectRow;
|
|
124
|
+
}): ObjectRow;
|
|
125
|
+
/** Mark the document deleted; the row stays with its last preview. Publishes `deleted`
|
|
126
|
+
* (level 8), then ends the watches on it and drops its rules. A null actor is repo sync. */
|
|
127
|
+
export declare function deleteDocument(db: DatabaseSync, reader: Reader | null, doc: ObjectRow, reposFn?: ReposFn): ObjectRow;
|
|
128
|
+
export interface ImportedRevision {
|
|
129
|
+
rev_id?: string;
|
|
130
|
+
body_hash: string;
|
|
131
|
+
author: ObjectRow | null;
|
|
132
|
+
rationale: string | null;
|
|
133
|
+
created_at: string;
|
|
134
|
+
verbatim?: boolean;
|
|
135
|
+
}
|
|
136
|
+
export interface ImportSpec extends WriteSpec {
|
|
137
|
+
id?: string;
|
|
138
|
+
revisions: readonly ImportedRevision[];
|
|
139
|
+
}
|
|
140
|
+
/** Migration: a document with its linear history (oldest first; bodies already in the body
|
|
141
|
+
* store). Explicit authors and times; records no edge or watch and publishes nothing — the
|
|
142
|
+
* caller adds links (`setRevisionLinks`), acted-on edges and watches. */
|
|
143
|
+
export declare function importDocument(db: DatabaseSync, spec: ImportSpec): ObjectRow;
|
|
144
|
+
export interface SyncedRevision {
|
|
145
|
+
rev_id: string;
|
|
146
|
+
parents: readonly string[];
|
|
147
|
+
body_hash: string;
|
|
148
|
+
rationale: string | null;
|
|
149
|
+
created_at: string;
|
|
150
|
+
verbatim?: boolean;
|
|
151
|
+
}
|
|
152
|
+
/** Repo sync: add revisions that arrived from another runtime, skipping known `rev_id`s. No
|
|
153
|
+
* CAS, author NULL, publishes nothing; the caller publishes `edited` (with `needs_merge`
|
|
154
|
+
* when `headCount > 1`) and re-derives links from the head it trusts. */
|
|
155
|
+
export declare function insertImportedRevisions(db: DatabaseSync, doc: ObjectRow, revs: readonly SyncedRevision[]): {
|
|
156
|
+
heads_key: string;
|
|
157
|
+
headCount: number;
|
|
158
|
+
};
|
|
159
|
+
/** Look up a live document by id (convenience for handlers and importers). */
|
|
160
|
+
export declare function documentById(db: DatabaseSync, id: string): ObjectRow;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
var Q=Object.defineProperty;var a=(t,n)=>Q(t,"name",{value:n,configurable:!0});import{randomUUID as Z}from"node:crypto";import{CrtrError as j,notFound as y,usage as c}from"../errors.js";import{ExitCode as $}from"../../types.js";import{canChange as A,canRead as U,ownerChain as b}from"./access.js";import{bodyOf as ee,get as te,put as F}from"./bodies.js";import{recordActedOn as R,setLinks as ne}from"./edges.js";import{publish as S}from"./events.js";import{resolveName as re}from"./names.js";import{createObject as oe,getById as ie,getByRowid as f}from"./objects.js";import{replaceRules as B,setRulesOwner as se}from"./rules.js";import{recordWatch as k}from"./watches.js";function E(t){return t.class==="node"?t.node:t.class==="app"?t.app:t.person}a(E,"actorOf");let ae=0;function h(t,n){const e=`graph_doc_${++ae}`;t.exec(`SAVEPOINT ${e}`);try{const r=n();return t.exec(`RELEASE ${e}`),r}catch(r){throw t.exec(`ROLLBACK TO ${e}`),t.exec(`RELEASE ${e}`),r}}a(h,"atomic");function ue(t,n){return new j("conflict",t,$.GENERAL,n)}a(ue,"conflict");function _(t){if(t.type!=="document")throw c(`${t.type} ${t.id} is not a document`)}a(_,"assertDocument");function P(t,n){const e=b(t,n);return(e.length?e[e.length-1]:n).type}a(P,"spaceType");function I(t,n,e){if(e!=="public"&&P(t,n)==="repo")throw c(`a repo owns only public documents; ${n.name} cannot own a ${e} one`,{rule:"repo-public-only",next:"Write it as public, or give it another owner (your own documents can carry `if: {repo: <handle>}`)."})}a(I,"assertPublicInRepo");function J(t,n,e,r){if(e.trim()===""||e!==e.trim())throw c(`invalid document name ${JSON.stringify(e)}`);const o=t.prepare("SELECT id FROM objects WHERE type = 'document' AND owner = ? AND name = ? AND deleted_at IS NULL").get(n.rowid,e);if(o&&o.id!==r?.id)throw ue(`${n.name} already has a document named ${e}`,{name:e,holder:o.id})}a(J,"assertNameFree");function L(t,n,e){if(!U(t,n,e))throw y(`no document ${e.id}`)}a(L,"readable");function N(t,n,e){if(L(t,n,e),!A(t,n,e))throw new j("forbidden",`you cannot change ${e.name}`,$.GENERAL,{id:e.id})}a(N,"changeable");function K(t,n){const e=t.prepare(`SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rowid = rp.parent
|
|
2
|
+
WHERE rp.child = ? ORDER BY p.rev_id`).all(n.rowid);return{rowid:n.rowid,rev_id:n.rev_id,number:n.number,body_hash:n.body_hash,author:n.author===null?null:f(t,n.author)?.id??null,rationale:n.rationale,verbatim:n.verbatim===1,created_at:n.created_at,parents:e.map(r=>r.rev_id)}}a(K,"toRevision");function H(t,n){return t.prepare(`SELECT * FROM revisions r WHERE r.document = ?
|
|
3
|
+
AND NOT EXISTS (SELECT 1 FROM revision_parents p WHERE p.parent = r.rowid) ORDER BY r.number DESC, r.rev_id`).all(n.rowid).map(r=>K(t,r))}a(H,"heads");function ce(t){return t.map(n=>n.rev_id).sort().join(",")}a(ce,"headsKeyOf");function O(t,n){const e=t.prepare("SELECT * FROM documents WHERE object = ?").get(n.rowid);if(!e)throw y(`no document record for ${n.id}`);return{summary:e.summary,heads_key:e.heads_key,revision:e.revision,why_it_exists:e.why_it_exists,unlisted:e.unlisted===1,lint_ignore:e.lint_ignore_json===null?null:JSON.parse(e.lint_ignore_json),extensions:e.extensions_json===null?null:JSON.parse(e.extensions_json),source_path:e.source_path}}a(O,"documentRecord");function D(t,n,e){const r=t.prepare(`INSERT INTO revisions (document, rev_id, number, body_hash, author, rationale, verbatim, created_at)
|
|
4
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`).get(n.rowid,e.rev_id??Z(),e.number,e.body_hash,e.author?.rowid??null,e.rationale,e.verbatim?1:0,e.created_at??new Date().toISOString()),o=t.prepare("INSERT INTO revision_parents (child, parent) VALUES (?, ?)");for(const i of e.parents)o.run(r.rowid,i);return r}a(D,"insertRevision");function pe(t){const n=new Set;for(const e of t.matchAll(/\[\[([^[\]\n]+?)\]\]/g))n.add(e[1].trim());return[...n]}a(pe,"linksIn");function G(t,n,e,r){const o=[],i=[];for(const u of pe(r)){const s=re(t,n,u);"object"in s?o.push({written_as:u,dst:s.object}):"deleted"in s?o.push({written_as:u,dst:s.deleted}):"remote"in s||i.push(u)}return ne(t,e,o),i}a(G,"setRevisionLinks");function le(t,n,e){return n.type==="node"?n.id:t.prepare(`SELECT 1 FROM objects o JOIN objects d ON d.owner = o.rowid
|
|
5
|
+
WHERE o.name = ? AND o.type <> ? AND o.type IN ('person','app','repo','profile')
|
|
6
|
+
AND d.type = 'document' AND d.name = ? AND d.deleted_at IS NULL LIMIT 1`).get(n.name,n.type,e)?`${n.type}:${n.name}`:n.name}a(le,"ownerPrefix");function V(t,n,e){const r=t.prepare(`SELECT e.written_as, o.* FROM edges e JOIN objects o ON o.rowid = e.dst
|
|
7
|
+
WHERE e.type = 'links-to' AND e.src = ? AND e.written_as IS NOT NULL`).all(n.rowid);if(r.length===0)return e;const o=new Map;for(const i of r){if(i.deleted_at||i.written_as===i.id)continue;const u=!i.written_as.includes("/");if(u&&i.name===i.written_as)continue;const s=i.owner===null?null:f(t,i.owner),p=s?`${le(t,s,i.name)}/${i.name}`:i.name,l=u&&i.owner===n.owner?i.name:p;l!==i.written_as&&o.set(i.written_as,l)}return o.size===0?e:e.replace(/\[\[([^[\]\n]+?)\]\]/g,(i,u)=>{const s=o.get(u.trim());return s===void 0?i:`[[${s}]]`})}a(V,"withCurrentNames");function C(t,n,e){if(e.preview!==void 0){if(e.preview.trim()==="")throw c("a document needs a preview",{field:"preview"});t.prepare("UPDATE objects SET preview = ? WHERE rowid = ?").run(e.preview,n.rowid)}e.privacy!==void 0&&(I(t,f(t,n.owner),e.privacy),t.prepare("UPDATE objects SET privacy = ? WHERE rowid = ?").run(e.privacy,n.rowid));const r=a((i,u)=>t.prepare(`UPDATE documents SET ${i} = ? WHERE object = ?`).run(u,n.rowid),"set");e.summary!==void 0&&r("summary",e.summary),e.whyItExists!==void 0&&r("why_it_exists",e.whyItExists),e.unlisted!==void 0&&r("unlisted",e.unlisted?1:0),e.lintIgnore!==void 0&&r("lint_ignore_json",e.lintIgnore===null?null:JSON.stringify(e.lintIgnore)),e.extensions!==void 0&&r("extensions_json",e.extensions===null?null:JSON.stringify(e.extensions));const o=f(t,n.rowid);return e.rules!==void 0&&B(t,o,e.rules),o}a(C,"applyDocumentFields");function Y(t,n){if(n.owner.deleted_at)throw c(`${n.owner.name} is deleted`);if(n.preview.trim()==="")throw c("a document needs a preview",{field:"preview"});I(t,n.owner,n.privacy),J(t,n.owner,n.name);const e=oe(t,{...n.id?{id:n.id}:{},type:"document",kind:n.kind,owner:n.owner.rowid,privacy:n.privacy,name:n.name,preview:n.preview});return t.prepare("INSERT INTO documents (object, heads_key, revision) VALUES (?, '', 0)").run(e.rowid),C(t,e,{...n,preview:void 0,privacy:void 0,rules:n.rules??[]})}a(Y,"createDocument");function W(t,n){const e=H(t,n),r=ce(e),o=Math.max(0,...e.map(i=>i.number));return t.prepare("UPDATE documents SET heads_key = ?, revision = ? WHERE object = ?").run(r,o,n.rowid),{heads_key:r,revision:o,headCount:e.length}}a(W,"setHeads");function Oe(t,n,e,r,o){const i=F(r);return h(t,()=>{const u=E(n),s=Y(t,e),p=D(t,s,{number:1,body_hash:i,author:u,rationale:null,parents:[]}),{heads_key:l}=W(t,s);if(!A(t,n,s))throw y(`no owner ${e.owner.name} you can write to`);const w=G(t,n,s,r);return R(t,u,s),k(t,u,s,"write",{readHeadsKey:l}),S(t,{event:"created",object:s,actor:u,level:4,attrs:{revision:1},pointer:p.rev_id},o),{object:s,revision:1,unresolved:w}})}a(Oe,"writeDocument");function De(t,n,e){return t.prepare("SELECT read_heads_key FROM watches WHERE watcher = ? AND object = ?").get(E(n).rowid,e.rowid)?.read_heads_key??null}a(De,"readBase");function me(t,n){let e=t;for(const{old:r,new:o}of n){if(r==="")throw c("a replacement needs non-empty old text",{field:"replace"});const i=e.indexOf(r);if(i<0)throw c(`old text not found: ${JSON.stringify(r.slice(0,120))}`,{field:"replace",old:r});if(e.indexOf(r,i+1)>=0)throw c(`old text occurs more than once: ${JSON.stringify(r.slice(0,120))}`,{field:"replace",old:r});e=e.slice(0,i)+o+e.slice(i+r.length)}return e}a(me,"applyReplacements");function Te(t,n,e,r,o,i,u={},s){if(_(e),N(t,n,e),e.deleted_at)throw c(`${e.name} is deleted`);if(i===null)throw new j("read_first",`read ${e.name} before editing it`,$.GENERAL,{id:e.id});if(o.trim()==="")throw c("an edit needs a rationale",{field:"rationale"});const p=O(t,e);if(p.heads_key!==i)return{stale:{heads_key:p.heads_key,revision:p.revision}};const l=H(t,e);let w;if("body"in r)w=r.body;else{if(l.length!==1)throw c(`${e.name} has ${l.length} heads and needs a merge; pass the whole merged body`,{heads:l.length});w=me(V(t,e,te(l[0].body_hash)),r.replace)}const m=F(w);try{return h(t,()=>{const d=E(n),g=1+Math.max(0,...l.map(v=>v.number)),M=D(t,e,{number:g,body_hash:m,author:d,rationale:o,verbatim:r.verbatim===!0,parents:l.map(v=>v.rowid)}),T=M.rev_id,X=t.prepare("UPDATE documents SET heads_key = ?, revision = ? WHERE object = ? AND heads_key = ?").run(T,g,e.rowid,i);if(Number(X.changes)===0){const v=O(t,e);throw new z(v.heads_key,v.revision)}const x=C(t,e,u),q=G(t,n,x,w);return R(t,d,x),k(t,d,x,"write",{readHeadsKey:T}),S(t,{event:"edited",object:x,actor:d,level:8,pointer:M.rev_id,attrs:{revision:g,from_revision:p.revision,rationale:o}},s),{revision:g,heads_key:T,unresolved:q}})}catch(d){if(d instanceof z)return{stale:{heads_key:d.heads_key,revision:d.revision}};throw d}}a(Te,"editDocument");class z extends Error{static{a(this,"StaleEdit")}heads_key;revision;constructor(n,e){super("stale"),this.heads_key=n,this.revision=e}}function je(t,n,e,r){return _(e),n&&N(t,n,e),h(t,()=>{const o=C(t,e,r);return n&&R(t,E(n),o),o})}a(je,"setDocumentRecord");function we(t,n,e,r){const o=E(n),{heads_key:i}=O(t,e);k(t,o,e,"read",{readHeadsKey:i}),S(t,{event:"read",object:e,actor:o,level:1,attrs:{}},r)}a(we,"recordRead");function $e(t,n,e,r){return _(e),L(t,n,e),h(t,()=>{const o=O(t,e),i=H(t,e).map(s=>({...s,body:V(t,e,ee(s.body_hash,o.source_path))})),u=t.prepare("SELECT dst, written_as FROM edges WHERE type = 'links-to' AND src = ? ORDER BY written_as").all(e.rowid).map(s=>({written_as:s.written_as??"",object:f(t,s.dst)})).filter(s=>s.object&&U(t,n,s.object)).map(s=>({...s,deleted:s.object.deleted_at!==null}));return e.deleted_at||we(t,n,e,r),{object:e,record:o,heads:i,needsMerge:i.length>1,links:u}})}a($e,"readDocument");function Ae(t,n,e){return _(e),L(t,n,e),t.prepare("SELECT * FROM revisions WHERE document = ? ORDER BY number DESC, created_at DESC, rowid DESC").all(e.rowid).map(o=>K(t,o))}a(Ae,"history");function ke(t,n,e,r){if(_(e),e.deleted_at)throw c(`${e.name} is deleted`);return n&&N(t,n,e),h(t,()=>{const o=r.owner??f(t,e.owner),i=r.name??e.name;J(t,o,i,e),I(t,o,e.privacy),t.prepare("UPDATE objects SET name = ?, owner = ? WHERE rowid = ?").run(i,o.rowid,e.rowid);const u=f(t,e.rowid);if(o.rowid!==e.owner&&(se(t,u),n&&!A(t,n,u)))throw y(`no owner ${o.name} you can move documents to`);return n&&R(t,E(n),u),u})}a(ke,"moveDocument");function Ie(t,n,e,r){return _(e),e.deleted_at?e:(n&&N(t,n,e),h(t,()=>{t.prepare("UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(new Date().toISOString(),e.rowid);const o=f(t,e.rowid),i=n?E(n):null;return i&&R(t,i,o),S(t,{event:"deleted",object:o,actor:i,level:8,attrs:{}},r),t.prepare("DELETE FROM watches WHERE object = ?").run(e.rowid),B(t,o,[]),o}))}a(Ie,"deleteDocument");function Le(t,n){if(n.revisions.length===0)throw c(`import of ${n.name}: no revisions`);return h(t,()=>{const e=Y(t,n);t.prepare("UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.revisions[0].created_at,e.rowid);let r=null;return n.revisions.forEach((o,i)=>{r=D(t,e,{...o,number:i+1,parents:r===null?[]:[r]}).rowid}),W(t,e),f(t,e.rowid)})}a(Le,"importDocument");function He(t,n,e){if(_(n),n.privacy!=="public"&&P(t,n)==="repo")throw c(`a repo owns only public documents; refusing revisions of ${n.name}`);return h(t,()=>{const r=t.prepare("SELECT rowid, number, document FROM revisions WHERE rev_id = ?");let o=e.filter(s=>!r.get(s.rev_id));for(;o.length>0;){const s=[];for(const p of o){const l=p.parents.map(m=>r.get(m));if(l.some(m=>m===void 0)){s.push(p);continue}const w=l;if(w.some(m=>m.document!==n.rowid))throw c(`revision ${p.rev_id} names a parent of another document`);D(t,n,{...p,author:null,number:1+Math.max(0,...w.map(m=>m.number)),parents:w.map(m=>m.rowid)})}if(s.length===o.length)throw c(`revisions of ${n.name} name unknown parents: ${s.map(p=>p.rev_id).join(", ")}`);o=s}const{heads_key:i,headCount:u}=W(t,n);return{heads_key:i,headCount:u}})}a(He,"insertImportedRevisions");function Ce(t,n){const e=ie(t,n);if(!e||e.type!=="document")throw y(`no document ${n}`);return e}a(Ce,"documentById");export{E as actorOf,C as applyDocumentFields,me as applyReplacements,Ie as deleteDocument,Ce as documentById,O as documentRecord,Te as editDocument,H as heads,Ae as history,Le as importDocument,He as insertImportedRevisions,pe as linksIn,ke as moveDocument,De as readBase,$e as readDocument,we as recordRead,je as setDocumentRecord,G as setRevisionLinks,V as withCurrentNames,Oe as writeDocument};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** `acted-on` and `links-to` edges. An edge is visible only to a reader who may read both ends. */
|
|
2
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
3
|
+
import type { ObjectRow, Reader } from './types.js';
|
|
4
|
+
export type EdgeType = 'acted-on' | 'links-to';
|
|
5
|
+
export interface Edge {
|
|
6
|
+
type: EdgeType;
|
|
7
|
+
src: ObjectRow;
|
|
8
|
+
dst: ObjectRow;
|
|
9
|
+
written_as: string | null;
|
|
10
|
+
created_at: string;
|
|
11
|
+
}
|
|
12
|
+
/** One row per actor and object however many times the actor acts. */
|
|
13
|
+
export declare function recordActedOn(db: DatabaseSync, actor: ObjectRow, object: ObjectRow): void;
|
|
14
|
+
/** Replace the document's `links-to` edges with the links of its current revision. */
|
|
15
|
+
export declare function setLinks(db: DatabaseSync, doc: ObjectRow, links: ReadonlyArray<{
|
|
16
|
+
written_as: string;
|
|
17
|
+
dst: ObjectRow;
|
|
18
|
+
}>): void;
|
|
19
|
+
/** Documents whose body links to `object`. */
|
|
20
|
+
export declare function backlinks(db: DatabaseSync, reader: Reader, object: ObjectRow): Edge[];
|
|
21
|
+
export declare function edgesOf(db: DatabaseSync, reader: Reader, object: ObjectRow, opts?: {
|
|
22
|
+
type?: EdgeType;
|
|
23
|
+
direction?: 'out' | 'in' | 'both';
|
|
24
|
+
}): Edge[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var O=Object.defineProperty;var o=(t,n)=>O(t,"name",{value:n,configurable:!0});import{canRead as y}from"./access.js";import{getByRowid as R}from"./objects.js";function k(t,n,e){t.prepare("INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('acted-on', ?, ?, NULL, ?)").run(n.rowid,e.rowid,new Date().toISOString())}o(k,"recordActedOn");function _(t,n,e){t.prepare("DELETE FROM edges WHERE type = 'links-to' AND src = ?").run(n.rowid);const s=t.prepare("INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('links-to', ?, ?, ?, ?)"),i=new Date().toISOString();for(const c of e)s.run(n.rowid,c.dst.rowid,c.written_as,i)}o(_,"setLinks");function I(t,n,e){return S(t,n,e,{type:"links-to",direction:"in"})}o(I,"backlinks");function S(t,n,e,s={}){if(!y(t,n,e))return[];const i=s.direction??"both",c=s.type?[s.type]:["acted-on","links-to"],d=[];for(const r of c)i!=="in"&&d.push(...t.prepare("SELECT * FROM edges WHERE type = ? AND src = ?").all(r,e.rowid)),i!=="out"&&d.push(...t.prepare("SELECT * FROM edges WHERE type = ? AND dst = ?").all(r,e.rowid));const w=new Set,f=[];for(const r of d){const E=`${r.type}|${r.src}|${r.dst}`;if(w.has(E))continue;w.add(E);const a=r.src===e.rowid?e:R(t,r.src),p=r.dst===e.rowid?e:R(t,r.dst);if(!a||!p)continue;const u=a===e?p:a;u!==e&&!y(t,n,u)||f.push({type:r.type,src:a,dst:p,written_as:r.written_as,created_at:r.created_at})}return f}o(S,"edgesOf");export{I as backlinks,S as edgesOf,k as recordActedOn,_ as setLinks};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** The event catalog, subject matching, listening-config resolution and `publish`: the one
|
|
2
|
+
* path by which an event on an object reaches its watchers' inboxes. */
|
|
3
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
4
|
+
import { type ReposFn } from './reader.js';
|
|
5
|
+
import { type Subscription } from './watches.js';
|
|
6
|
+
import { type CanvasEvent, type EventName, type Level, type ListenConfig, type ListenDelivery, type ObjectRow, type ObjectType } from './types.js';
|
|
7
|
+
/** The event's default level, or the caller's. Notices have no default: they carry the caller's tier. */
|
|
8
|
+
export declare function levelFor(event: EventName, override?: Level, objectType?: ObjectType): Level;
|
|
9
|
+
/** NATS-style match over dot-separated event names: `*` is one part, `>` the rest (at least one part). */
|
|
10
|
+
export declare function matchSubject(pattern: string, event: string): boolean;
|
|
11
|
+
/** Per config, the delivery of the highest threshold the level reaches; across configs, the
|
|
12
|
+
* strongest. Null when the level is below every threshold of every config. */
|
|
13
|
+
export declare function resolveDelivery(configs: readonly ListenConfig[], level: Level): ListenDelivery | null;
|
|
14
|
+
/** A subscription's own config, else the watcher node's default, else the global default. */
|
|
15
|
+
export declare function listenConfigFor(db: DatabaseSync, subscription: Pick<Subscription, 'config'>, watcher: ObjectRow): ListenConfig;
|
|
16
|
+
/**
|
|
17
|
+
* Push `ev` to every node watching the object or a space or profile in its owner chain whose
|
|
18
|
+
* subscriptions receive it, inside the caller's write transaction. Document and job events reach
|
|
19
|
+
* only live (active|idle) watchers; node events also reach done ones without waking them. The
|
|
20
|
+
* actor is never pushed its own act, access is re-checked per watcher, and apps, persons and
|
|
21
|
+
* other non-node watchers get nothing. Writes a `messages` row only when a delivery results.
|
|
22
|
+
* `reposFn` resolves a watcher's repos when the object lives in a repo space.
|
|
23
|
+
*/
|
|
24
|
+
export declare function publish(db: DatabaseSync, ev: CanvasEvent, reposFn?: ReposFn): {
|
|
25
|
+
delivered: number;
|
|
26
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
var k=Object.defineProperty;var i=(t,e)=>k(t,"name",{value:e,configurable:!0});import{evalCondition as W}from"../predicate.js";import{insertEventMail as N,listenDeliveryTier as M}from"../feed/messages.js";import{ownerChain as J,readCheck as x}from"./access.js";import{publishLookups as H,readerForNode as $}from"./reader.js";import{configFromJson as g}from"./watches.js";import{DEFAULT_LISTEN as b}from"./types.js";const B={created:4,read:1,watched:1,edited:8,messaged:2,sent:1,configured:1,"report.update":5,"report.final":7,"report.result":5,exited:7,killed:7};function oe(t,e,o){if(e!==void 0)return e;if(t==="deleted")return o==="document"?8:5;if(t.startsWith("notice."))throw new Error(`${t} has no default level; pass the notice's tier as a level`);return B[t]}i(oe,"levelFor");function U(t,e){const o=t.split("."),r=e.split(".");for(let s=0;s<o.length;s++){if(o[s]===">")return s===o.length-1&&r.length>s;if(s>=r.length||o[s]!=="*"&&o[s]!==r[s])return!1}return o.length===r.length}i(U,"matchSubject");const S={"next-turn":1,"after-turn":2,steer:3,interrupt:4};function P(t,e){let o=null;for(const r of t){let s=null;for(const c of r)c.threshold<=e&&(!s||c.threshold>s.threshold)&&(s=c);s&&(!o||S[s.delivery]>S[o])&&(o=s.delivery)}return o}i(P,"resolveDelivery");function re(t,e,o){if(e.config)return e.config;const r=t.prepare("SELECT listen_default_json FROM nodes WHERE node_id = ?").get(o.id);return r?.listen_default_json?g(r.listen_default_json):b}i(re,"listenConfigFor");const V=new Set(["messaged","sent","configured","report.update","report.final","report.result","notice.crash","notice.deadline","notice.close"]),G=new Set(["person","app","repo","profile"]);function K(t){return t.event==="report.final"?"final":t.event==="report.result"?"completed":t.level>=7?"urgent":"update"}i(K,"inboxKind");function X(t,e,o){const r=e.object.owner===null?null:t.prepare("SELECT id FROM objects WHERE rowid = ?").get(e.object.owner).id;return{event:e.event,level:e.level,object:{id:e.object.id,type:e.object.type,kind:e.object.kind,owner:r,name:e.object.name},actor:e.actor?.id??null,attrs:o,...e.pointer===void 0?{}:{pointer:e.pointer}}}i(X,"pushFields");function O(t,e,o){const r=X(t,e,o),s=e.messageBody!==void 0&&(e.event.startsWith("report.")||e.event.startsWith("notice.")),c=s?typeof e.messageBody=="object"&&e.messageBody!==null&&!Array.isArray(e.messageBody)?{...e.messageBody,push:r}:{body:e.messageBody,push:r}:{push:r},a=s&&e.event.startsWith("report.")?e.messageBody:null;return{kind:K(e),label:a?.label??`${e.event} ${e.object.type} ${e.object.name}`,...a?.bodyRef===void 0?{}:{bodyRef:a.bodyRef},...a?.disposition===void 0?{}:{disposition:a.disposition},senderNodeId:e.actor?.type==="node"?e.actor.id:null,senderName:e.actor?.name??null,bodyJson:c,event:e.event,objectId:e.object.id,level:e.level,actorId:e.actor?.id??null}}i(O,"mailInput");function Y(t){const e=t.attrs.revision,o=t.attrs.from_revision??(typeof e=="number"?e-1:null),r=t.attrs.rationale;return{...t.attrs,from_revision:o,revision:e,authors:t.actor?[t.actor.id]:[],rationales:typeof r=="string"?[r]:[]}}i(Y,"editAttrs");function q(t,e){const o=[...t.authors??[],...e.authors.filter(r=>!(t.authors??[]).includes(r))];return{...e,from_revision:t.from_revision??null,authors:o,rationales:[...t.rationales??[],...e.rationales]}}i(q,"mergeEdits");function se(t,e,o=()=>[]){const r=J(t,e.object),s=[e.object.rowid,...r.filter(n=>G.has(n.type)).map(n=>n.rowid)],c=V.has(e.event),a=`w.object IN (${s.map(()=>"?").join(",")}) AND w.watcher != ?`,m="w.watcher, o.id AS watcher_id, n.status, n.listen_default_json, s.pattern, s.filter_json, s.config_json",_=t.prepare(c?`SELECT ${m} FROM watches w JOIN watch_subscriptions s ON s.watch = w.rowid
|
|
2
|
+
JOIN objects o ON o.rowid = w.watcher AND o.type = 'node' JOIN nodes n ON n.node_id = o.id WHERE ${a}`:`SELECT ${m} FROM nodes n CROSS JOIN objects o CROSS JOIN watches w CROSS JOIN watch_subscriptions s
|
|
3
|
+
WHERE n.status IN ('active','idle') AND o.id = n.node_id AND w.watcher = o.rowid AND s.watch = w.rowid AND ${a}`).all(...s,e.actor?.rowid??-1);if(_.length===0)return{delivered:0};const R={event:e.event,level:e.level,id:e.object.id,type:e.object.type,kind:e.object.kind,actor:e.actor?.id??null,...e.attrs},f=new Map;for(const n of _){if(!U(n.pattern,e.event)||n.filter_json!==null&&!W(JSON.parse(n.filter_json),R))continue;const l=n.config_json?g(n.config_json):n.listen_default_json?g(n.listen_default_json):b,d=f.get(n.watcher)??{id:n.watcher_id,status:n.status,configs:[]};d.configs.push(l),f.set(n.watcher,d)}const D=(r.length?r[r.length-1]:e.object).type==="repo",A=i(()=>[],"noRepos"),I=x(t,e.object),T=H(t),u=[];for(const n of f.values()){const l=P(n.configs,e.level);if(l===null||!I($(t,n.id,D?o:A,T)))continue;const d=M(l),p=n.status==="active"||n.status==="idle";u.push({nodeId:n.id,urgency:d.urgency,wake:p?d.wake:0})}if(u.length===0)return{delivered:0};if(e.event!=="edited")return N(t,O(t,e,e.attrs),u),{delivered:u.length};const E=Y(e),L=t.prepare(`SELECT d.delivery_id, d.message_id, m.body_json FROM deliveries d
|
|
4
|
+
JOIN messages m ON m.message_id = d.message_id
|
|
5
|
+
WHERE d.destination_kind = 'node_inbox' AND d.destination_id = ? AND d.state = 'pending' AND d.canceled_at IS NULL
|
|
6
|
+
AND m.event = 'edited' AND m.object_id = ?`),h=new Map,w=new Set,F=t.prepare("DELETE FROM deliveries WHERE delivery_id = ?");for(const n of u){const l=L.all(n.nodeId,e.object.id),d=l.at(-1);for(const j of l)F.run(j.delivery_id),w.add(j.message_id);const p=d?.message_id??null,y=h.get(p)??{prior:d?.body_json?JSON.parse(d.body_json).push?.attrs??null:null,destinations:[]};y.destinations.push(n),h.set(p,y)}for(const n of h.values())N(t,O(t,e,n.prior?q(n.prior,E):E),n.destinations);const C=t.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)");for(const n of w)C.run(n,n);return{delivered:u.length}}i(se,"publish");export{oe as levelFor,re as listenConfigFor,U as matchSubject,se as publish,P as resolveDelivery};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** The exposure ledger: what each node's loaded context already holds, per
|
|
2
|
+
* channel (`system` = rebuilt system prompt, `transcript` = conversation), in
|
|
3
|
+
* `exposures` and `context_sessions`. Rows cascade with the node. Callers
|
|
4
|
+
* load, mutate in memory, and `saveLedger` inside their own transaction. */
|
|
5
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
6
|
+
import type { RuleSpec } from './types.js';
|
|
7
|
+
export type ExposureLevel = RuleSpec['deliver'];
|
|
8
|
+
export type Channel = 'system' | 'transcript';
|
|
9
|
+
export interface Held {
|
|
10
|
+
system?: ExposureLevel;
|
|
11
|
+
transcript?: ExposureLevel;
|
|
12
|
+
headsKey: string | null;
|
|
13
|
+
contentHash: string | null;
|
|
14
|
+
}
|
|
15
|
+
export type Listed = {
|
|
16
|
+
system?: ExposureLevel;
|
|
17
|
+
transcript?: ExposureLevel;
|
|
18
|
+
};
|
|
19
|
+
export interface Ledger {
|
|
20
|
+
node: number;
|
|
21
|
+
preferenceSnapshot: string | null;
|
|
22
|
+
objects: Map<number, Held>;
|
|
23
|
+
/** key = `<owner object id>/<prefix>` */
|
|
24
|
+
listed: Map<string, Listed>;
|
|
25
|
+
}
|
|
26
|
+
export interface Exposed {
|
|
27
|
+
object: number;
|
|
28
|
+
headsKey: string | null;
|
|
29
|
+
contentHash: string | null;
|
|
30
|
+
}
|
|
31
|
+
export declare function loadLedger(db: DatabaseSync, node: number): Ledger;
|
|
32
|
+
/** Write what changed since `loadLedger` (a ledger never loaded is written whole). */
|
|
33
|
+
export declare function saveLedger(db: DatabaseSync, ledger: Ledger): void;
|
|
34
|
+
/** Whether the node has a ledger at all (a context session or any exposure). */
|
|
35
|
+
export declare function hasLedger(db: DatabaseSync, node: number): boolean;
|
|
36
|
+
/** End the node's context session: nothing is held any more. */
|
|
37
|
+
export declare function clearLedger(db: DatabaseSync, node: number): void;
|
|
38
|
+
/** Seed a fork with what the source's transcript holds; the fork builds its own
|
|
39
|
+
* system prompt, so system rows and the preference snapshot are not copied. */
|
|
40
|
+
export declare function forkLedger(db: DatabaseSync, source: number, fork: number): void;
|
|
41
|
+
/** Held at `level` or above: this object, or any held object with the same body
|
|
42
|
+
* (content hash). The object itself counts at content level only for the same revision. */
|
|
43
|
+
export declare function heldAtOrAbove(ledger: Ledger, exposed: Exposed, level: ExposureLevel, channel?: Channel): boolean;
|
|
44
|
+
/** Record that `channel` now holds the object at `level`; never lowers a level of the same revision. */
|
|
45
|
+
export declare function hold(ledger: Ledger, channel: Channel, exposed: Exposed, level: ExposureLevel): void;
|
|
46
|
+
export declare function listedAtOrAbove(ledger: Ledger, key: string, level: ExposureLevel, channel?: Channel): boolean;
|
|
47
|
+
export declare function holdListing(ledger: Ledger, channel: Channel, key: string, level: ExposureLevel): void;
|
|
48
|
+
/** Forget the transcript's copy of the object and of every held object with the
|
|
49
|
+
* same body (compaction dropped it); system holdings stay. */
|
|
50
|
+
export declare function demoteTranscript(ledger: Ledger, object: number): void;
|
|
51
|
+
/** The byte-stable preference block: the first render is kept for the session. */
|
|
52
|
+
export declare function freezePreferences(ledger: Ledger, rendered: string): string;
|
|
53
|
+
export declare function hasTranscript(ledger: Ledger): boolean;
|