@north-light/crouter 0.3.349 → 0.3.350
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/bin/crtr-launcher +4 -0
- package/bin/runtime-generation-manifest.mjs +12 -2
- package/dist/api/client.d.ts +50 -7
- package/dist/api/client.js +2 -2
- package/dist/api/dto/analytics.d.ts +184 -0
- package/dist/api/dto/analytics.js +0 -0
- package/dist/api/dto/broker-ops.d.ts +43 -1
- package/dist/api/dto/config.d.ts +11 -0
- package/dist/api/dto/grants.d.ts +14 -0
- package/dist/api/dto/grants.js +0 -0
- package/dist/api/dto/human-requests.d.ts +14 -0
- package/dist/api/dto/memory.d.ts +6 -0
- package/dist/api/dto/modelauth.d.ts +35 -0
- package/dist/api/dto/node-records.d.ts +35 -0
- package/dist/api/dto/node-records.js +0 -0
- package/dist/api/dto/nodes.d.ts +5 -0
- package/dist/api/dto/profiles.d.ts +38 -3
- package/dist/api/dto/worktree.d.ts +11 -0
- package/dist/api/errors.d.ts +23 -1
- package/dist/api/errors.js +1 -1
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +1 -1
- package/dist/api/node-transport.js +1 -1
- package/dist/api/routes.d.ts +22 -0
- package/dist/api/routes.js +1 -1
- package/dist/build-root.d.ts +6 -1
- package/dist/build-root.js +1 -1
- package/dist/builtin-memory/crouter-sdk/client.md +34 -0
- package/dist/builtin-memory/crouter-sdk/errors.md +2 -0
- package/dist/builtin-memory/crouter-sdk/memory.md +2 -2
- package/dist/builtin-memory/crouter-sdk/streaming.md +21 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +8 -4
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +39 -118
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +6 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +41 -27
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +52 -29
- package/dist/cli.js +9 -8
- package/dist/clients/attach/chrome/inbox-strip.js +1 -1
- package/dist/clients/attach/chrome/roster.js +1 -1
- package/dist/clients/attach/config.js +1 -1
- package/dist/clients/attach/overlays/auth.js +2 -2
- package/dist/clients/attach/overlays/graph.js +1 -1
- package/dist/clients/attach/render/tool-calls.js +3 -3
- package/dist/clients/attach/session/connection.js +1 -1
- package/dist/clients/attach/session/profile-files.js +1 -1
- package/dist/clients/attach/viewer.js +1569 -816
- package/dist/commands/api-client.js +3 -3
- package/dist/commands/broker-permissions.d.ts +2 -0
- package/dist/commands/broker-permissions.js +1 -0
- package/dist/commands/canvas-analytics/chart.d.ts +52 -0
- package/dist/commands/canvas-analytics/chart.js +1 -0
- package/dist/commands/canvas-analytics/drilldown.d.ts +34 -0
- package/dist/commands/canvas-analytics/drilldown.js +1 -0
- package/dist/commands/canvas-analytics/format.d.ts +29 -0
- package/dist/commands/canvas-analytics/format.js +1 -0
- package/dist/commands/canvas-analytics/graph-detail.d.ts +2 -0
- package/dist/commands/canvas-analytics/graph-detail.js +2 -0
- package/dist/commands/canvas-analytics/graphs.d.ts +9 -0
- package/dist/commands/canvas-analytics/graphs.js +1 -0
- package/dist/commands/canvas-analytics/memory.d.ts +2 -0
- package/dist/commands/canvas-analytics/memory.js +1 -0
- package/dist/commands/canvas-analytics/overview.d.ts +2 -0
- package/dist/commands/canvas-analytics/overview.js +1 -0
- package/dist/commands/canvas-analytics/shell.d.ts +60 -0
- package/dist/commands/canvas-analytics/shell.js +2 -0
- package/dist/commands/canvas-analytics/time.d.ts +2 -0
- package/dist/commands/canvas-analytics/time.js +1 -0
- package/dist/commands/canvas-analytics/usage.d.ts +2 -0
- package/dist/commands/canvas-analytics/usage.js +1 -0
- package/dist/commands/canvas-analytics/view.d.ts +85 -0
- package/dist/commands/canvas-analytics/view.js +1 -0
- package/dist/commands/canvas-analytics.d.ts +2 -0
- package/dist/commands/canvas-analytics.js +1 -0
- package/dist/commands/canvas-prune.js +1 -1
- package/dist/commands/canvas.js +1 -1
- package/dist/commands/cron.js +5 -5
- package/dist/commands/human/components.d.ts +2 -0
- package/dist/commands/human/components.js +2 -2
- package/dist/commands/human/prompts.js +1 -1
- package/dist/commands/human/queue.js +1 -1
- package/dist/commands/memory/client.d.ts +11 -0
- package/dist/commands/memory/client.js +1 -0
- package/dist/commands/memory/delete.js +1 -1
- package/dist/commands/memory/edit.js +3 -3
- package/dist/commands/memory/find.js +1 -1
- package/dist/commands/memory/history.js +4 -4
- package/dist/commands/memory/lint.js +1 -1
- package/dist/commands/memory/list.d.ts +0 -2
- package/dist/commands/memory/list.js +1 -1
- package/dist/commands/memory/move.js +1 -1
- package/dist/commands/memory/origin.js +1 -1
- package/dist/commands/memory/read.d.ts +0 -5
- package/dist/commands/memory/read.js +3 -3
- package/dist/commands/memory/shared.d.ts +0 -178
- package/dist/commands/memory/shared.js +1 -12
- package/dist/commands/memory/write.js +5 -5
- package/dist/commands/node/bash.js +5 -5
- package/dist/commands/node/create.d.ts +0 -17
- package/dist/commands/node/create.js +2 -3
- package/dist/commands/node/inspect.js +6 -6
- package/dist/commands/node/lifecycle.js +2 -2
- package/dist/commands/node-context.js +2 -2
- package/dist/commands/node-inspect-artifacts.js +6 -6
- package/dist/commands/pkg/browse/catalog.js +1 -1
- package/dist/commands/pkg/browse/model.d.ts +1 -1
- package/dist/commands/pkg/market-manage.js +1 -1
- package/dist/commands/pkg/plugin-manage.js +10 -10
- package/dist/commands/profile/daemon-profiles.d.ts +13 -0
- package/dist/commands/profile/daemon-profiles.js +4 -0
- package/dist/commands/profile/delete.js +1 -1
- package/dist/commands/profile/env.d.ts +6 -0
- package/dist/commands/profile/env.js +2 -2
- package/dist/commands/profile/kind.js +1 -2
- package/dist/commands/profile/list.js +1 -1
- package/dist/commands/profile/meta.js +1 -1
- package/dist/commands/profile/new.js +1 -1
- package/dist/commands/profile/pause.js +1 -1
- package/dist/commands/profile/project.js +1 -1
- package/dist/commands/profile/rename.js +1 -1
- package/dist/commands/profile/show.js +1 -1
- package/dist/commands/profile.js +1 -1
- package/dist/commands/push.js +3 -3
- package/dist/commands/surface-inspect.js +1 -1
- package/dist/commands/sys/branch.js +1 -1
- package/dist/commands/sys/config.js +1 -1
- package/dist/commands/sys/connect.js +3 -3
- package/dist/commands/sys/context/admin/actions.js +1 -1
- package/dist/commands/sys/context/admin/model.d.ts +1 -0
- package/dist/commands/sys/context/admin/model.js +1 -1
- package/dist/commands/sys/context/admin.js +1 -1
- package/dist/commands/sys/context/expose.js +2 -1
- package/dist/commands/sys/context/prompt-review.js +2 -2
- package/dist/commands/sys/context/resolve.js +7 -7
- package/dist/commands/sys/context/sysprompt.js +1 -1
- package/dist/commands/sys/join.d.ts +1 -0
- package/dist/commands/sys/join.js +1 -0
- package/dist/commands/sys/migrate.js +1 -1
- package/dist/commands/sys/panels/models-panel.js +1 -1
- package/dist/commands/sys/panels/profiles-panel.d.ts +0 -1
- package/dist/commands/sys/panels/profiles-panel.js +1 -1
- package/dist/commands/sys/provider-login.js +6 -6
- package/dist/commands/sys/setup-core.d.ts +1 -1
- package/dist/commands/sys/setup-core.js +6 -6
- package/dist/commands/sys/setup-settings-runner.js +1 -1
- package/dist/commands/sys/setup.js +1 -1
- package/dist/commands/sys/spaces.d.ts +1 -0
- package/dist/commands/sys/spaces.js +2 -0
- package/dist/commands/sys/sync-deps.js +2 -2
- package/dist/commands/sys/sync-project-guidance.js +4 -4
- package/dist/commands/sys/sync-skills.js +2 -2
- package/dist/commands/sys/worktrees.d.ts +1 -0
- package/dist/commands/sys/worktrees.js +1 -1
- package/dist/commands/sys.js +1 -1
- package/dist/core/auth-file.js +2 -2
- package/dist/core/bash-job-supervisor.d.ts +6 -0
- package/dist/core/bash-job-supervisor.js +4 -0
- package/dist/core/bash-jobs.d.ts +13 -6
- package/dist/core/bash-jobs.js +8 -7
- package/dist/core/broker-client/transport-relay.d.ts +6 -3
- package/dist/core/broker-client/transport-relay.js +1 -1
- package/dist/core/broker-client/transport-socket.d.ts +6 -1
- package/dist/core/broker-client/transport-socket.js +1 -1
- package/dist/core/canvas/canvas.d.ts +39 -18
- package/dist/core/canvas/canvas.js +21 -20
- package/dist/core/canvas/context-strip.d.ts +20 -0
- package/dist/core/canvas/context-strip.js +5 -0
- package/dist/core/canvas/crons.d.ts +12 -20
- package/dist/core/canvas/crons.js +15 -13
- package/dist/core/canvas/db.js +2 -2
- package/dist/core/canvas/deliveries.d.ts +4 -1
- package/dist/core/canvas/deliveries.js +1 -1
- package/dist/core/canvas/executions.js +1 -1
- package/dist/core/canvas/history.d.ts +2 -1
- package/dist/core/canvas/history.js +17 -18
- package/dist/core/canvas/memory-reads.d.ts +19 -0
- package/dist/core/canvas/memory-reads.js +1 -0
- package/dist/core/canvas/migrations.d.ts +0 -4
- package/dist/core/canvas/migrations.js +99 -32
- package/dist/core/canvas/nav-render.js +1 -1
- package/dist/core/canvas/node-agent-paths.d.ts +8 -0
- package/dist/core/canvas/node-agent-paths.js +1 -0
- package/dist/core/canvas/node-recap.d.ts +2 -2
- package/dist/core/canvas/node-recap.js +2 -2
- package/dist/core/canvas/node-tokens.d.ts +24 -0
- package/dist/core/canvas/node-tokens.js +5 -0
- package/dist/core/canvas/paths.d.ts +16 -19
- package/dist/core/canvas/paths.js +1 -1
- package/dist/core/canvas/render-source.d.ts +2 -2
- package/dist/core/canvas/render-source.js +6 -9
- package/dist/core/canvas/sessions.d.ts +18 -0
- package/dist/core/canvas/sessions.js +4 -1
- package/dist/core/canvas/types.d.ts +22 -6
- package/dist/core/command-hooks/compose.js +1 -1
- package/dist/core/command-hooks/discovery.d.ts +15 -1
- package/dist/core/command-hooks/discovery.js +1 -1
- package/dist/core/command-hooks/help.d.ts +2 -2
- package/dist/core/command-hooks/lifecycle-create.d.ts +1 -1
- package/dist/core/command-hooks/lifecycle-create.js +1 -1
- package/dist/core/command-hooks/transport/exec-invoke.d.ts +2 -0
- package/dist/core/command-hooks/transport/exec-invoke.js +1 -1
- package/dist/core/command-hooks/transport/exec-lifecycle.d.ts +1 -0
- package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
- package/dist/core/command-hooks/transport/plan.d.ts +3 -0
- package/dist/core/command-hooks/transport/plan.js +1 -0
- package/dist/core/command-plugins/discovery.js +1 -1
- package/dist/core/command.d.ts +6 -2
- package/dist/core/command.js +6 -6
- package/dist/core/config.d.ts +8 -5
- package/dist/core/config.js +1 -1
- package/dist/core/conversation-store/client-worker.d.ts +1 -0
- package/dist/core/conversation-store/client-worker.js +1 -0
- package/dist/core/conversation-store/client.d.ts +2 -0
- package/dist/core/conversation-store/client.js +2 -0
- package/dist/core/conversation-store/file-store.d.ts +37 -0
- package/dist/core/conversation-store/file-store.js +9 -0
- package/dist/core/conversation-store/index.d.ts +50 -0
- package/dist/core/conversation-store/index.js +1 -0
- package/dist/core/conversation-store/listener.d.ts +4 -0
- package/dist/core/conversation-store/listener.js +3 -0
- package/dist/core/conversation-store/patch.d.ts +1 -0
- package/dist/core/conversation-store/patch.js +1 -0
- package/dist/core/directory/join.d.ts +27 -0
- package/dist/core/directory/join.js +1 -0
- package/dist/core/disk-usage.d.ts +4 -0
- package/dist/core/disk-usage.js +1 -0
- package/dist/core/events/emit.d.ts +2 -0
- package/dist/core/events/emit.js +3 -1
- package/dist/core/feed/feed.js +4 -4
- package/dist/core/feed/messages.d.ts +3 -0
- package/dist/core/feed/messages.js +6 -6
- package/dist/core/fs-utils.d.ts +2 -0
- package/dist/core/fs-utils.js +3 -3
- package/dist/core/grants/local.d.ts +4 -0
- package/dist/core/grants/local.js +1 -0
- package/dist/core/grants/mirror.d.ts +44 -0
- package/dist/core/grants/mirror.js +4 -0
- package/dist/core/grants/on-sync.d.ts +22 -0
- package/dist/core/grants/on-sync.js +1 -0
- package/dist/core/grants/remove.d.ts +7 -0
- package/dist/core/grants/remove.js +1 -0
- package/dist/core/grants/sandboxes.d.ts +7 -0
- package/dist/core/grants/sandboxes.js +1 -0
- package/dist/core/grants/sync.d.ts +12 -0
- package/dist/core/grants/sync.js +1 -0
- package/dist/core/help/memory-extensions.d.ts +3 -0
- package/dist/core/help/memory-extensions.js +2 -0
- package/dist/core/help.d.ts +14 -0
- package/dist/core/help.js +7 -7
- package/dist/core/host-exports/builtins.js +3 -3
- package/dist/core/host-exports/export.js +3 -3
- package/dist/core/human/action-binding.d.ts +2 -0
- package/dist/core/human/action-binding.js +1 -1
- package/dist/core/human/feedback-companion.d.ts +0 -1
- package/dist/core/human/feedback-companion.js +1 -1
- package/dist/core/human/page-schema.d.ts +1 -1
- package/dist/core/inspector/core.d.ts +2 -0
- package/dist/core/inspector/core.js +1 -1
- package/dist/core/inspector/tui.js +2 -2
- package/dist/core/installed-plugins.js +1 -1
- package/dist/core/io.js +6 -6
- package/dist/core/keybindings/catalog.d.ts +1 -1
- package/dist/core/keybindings/catalog.js +1 -1
- package/dist/core/layout-migrate/index.d.ts +15 -0
- package/dist/core/layout-migrate/index.js +4 -0
- package/dist/core/layout-migrate/paths.d.ts +26 -0
- package/dist/core/layout-migrate/paths.js +1 -0
- package/dist/core/layout-migrate/stored-paths.d.ts +2 -0
- package/dist/core/layout-migrate/stored-paths.js +11 -0
- package/dist/core/layout-migrate/stores.d.ts +17 -0
- package/dist/core/layout-migrate/stores.js +4 -0
- package/dist/core/layout.d.ts +26 -0
- package/dist/core/layout.js +2 -0
- package/dist/core/llm/run.d.ts +60 -0
- package/dist/core/llm/run.js +4 -0
- package/dist/core/memory/cli-selector.d.ts +13 -0
- package/dist/core/memory/cli-selector.js +1 -0
- package/dist/core/memory/history.d.ts +5 -4
- package/dist/core/memory/history.js +6 -6
- package/dist/core/memory/inline-ref-inventory.d.ts +2 -1
- package/dist/core/memory/inline-ref-inventory.js +1 -1
- package/dist/core/memory/lint.js +2 -2
- package/dist/core/memory/mutation-domain.d.ts +2 -2
- package/dist/core/memory/mutation-domain.js +8 -7
- package/dist/core/memory/mutations.js +1 -1
- package/dist/core/memory/service.d.ts +5 -0
- package/dist/core/memory/service.js +2 -2
- package/dist/core/memory-resolver.d.ts +11 -7
- package/dist/core/memory-resolver.js +2 -2
- package/dist/core/model-auth/daemon-login.d.ts +13 -0
- package/dist/core/model-auth/daemon-login.js +1 -0
- package/dist/core/model-auth/flows.d.ts +45 -0
- package/dist/core/model-auth/flows.js +1 -0
- package/dist/core/model-auth/handoff-jti.d.ts +4 -0
- package/dist/core/model-auth/handoff-jti.js +1 -0
- package/dist/core/model-routes.js +1 -1
- package/dist/core/nested-stores.d.ts +2 -1
- package/dist/core/nested-stores.js +1 -2
- package/dist/core/preview-registry.js +2 -2
- package/dist/core/profiles/env-store.js +2 -2
- package/dist/core/profiles/manifest.d.ts +16 -5
- package/dist/core/profiles/manifest.js +1 -1
- package/dist/core/provider-management.js +1 -1
- package/dist/core/review/birth.js +1 -1
- package/dist/core/review/companion.d.ts +0 -2
- package/dist/core/review/companion.js +1 -1
- package/dist/core/review/fork.js +2 -2
- package/dist/core/review/realize.js +1 -1
- package/dist/core/review/stage.d.ts +1 -1
- package/dist/core/review/stage.js +1 -1
- package/dist/core/review/types.d.ts +1 -1
- package/dist/core/runs/events.d.ts +34 -0
- package/dist/core/runs/events.js +1 -0
- package/dist/core/runs/operations.d.ts +43 -0
- package/dist/core/runs/operations.js +12 -0
- package/dist/core/runtime/bearings-render.d.ts +2 -2
- package/dist/core/runtime/bearings-render.js +11 -11
- package/dist/core/runtime/bearings.js +2 -2
- package/dist/core/runtime/broker/cli-relay.d.ts +5 -0
- package/dist/core/runtime/broker/cli-relay.js +1 -0
- package/dist/core/runtime/broker/client-registry.d.ts +0 -5
- package/dist/core/runtime/broker/client-registry.js +1 -1
- package/dist/core/runtime/broker/daemon-ops.d.ts +28 -1
- package/dist/core/runtime/broker/daemon-ops.js +1 -1
- package/dist/core/runtime/broker/engine-drive.d.ts +0 -2
- package/dist/core/runtime/broker/engine-drive.js +1 -1
- package/dist/core/runtime/broker/fault-retry.d.ts +9 -0
- package/dist/core/runtime/broker/fault-retry.js +1 -1
- package/dist/core/runtime/broker/frame-dispatch.d.ts +5 -9
- package/dist/core/runtime/broker/frame-dispatch.js +1 -1
- package/dist/core/runtime/broker/frame-engine-control.d.ts +3 -2
- package/dist/core/runtime/broker/frame-engine-control.js +1 -1
- package/dist/core/runtime/broker/frame-memory-refs.d.ts +4 -3
- package/dist/core/runtime/broker/frame-memory-refs.js +1 -1
- package/dist/core/runtime/broker/frame-read.js +1 -1
- package/dist/core/runtime/broker/frame-session.js +1 -1
- package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -1
- package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
- package/dist/core/runtime/broker/inbox.d.ts +1 -2
- package/dist/core/runtime/broker/inbox.js +7 -10
- package/dist/core/runtime/broker/model-adapter.d.ts +9 -0
- package/dist/core/runtime/broker/model-adapter.js +2 -0
- package/dist/core/runtime/broker/node-token.d.ts +3 -0
- package/dist/core/runtime/broker/node-token.js +1 -0
- package/dist/core/runtime/broker/read-ops.js +1 -1
- package/dist/core/runtime/broker/rebind.d.ts +2 -0
- package/dist/core/runtime/broker/rebind.js +1 -1
- package/dist/core/runtime/broker/tool-groups.js +1 -1
- package/dist/core/runtime/broker/turn-ignition.d.ts +3 -3
- package/dist/core/runtime/broker/turn-ignition.js +1 -1
- package/dist/core/runtime/broker-cli.js +3 -3
- package/dist/core/runtime/broker-extension-render.d.ts +2 -5
- package/dist/core/runtime/broker-extension-render.js +4 -4
- package/dist/core/runtime/broker-persona-guidance.js +3 -3
- package/dist/core/runtime/broker-protocol.d.ts +7 -8
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/canvas-extensions.d.ts +1 -0
- package/dist/core/runtime/canvas-extensions.js +1 -1
- package/dist/core/runtime/close.d.ts +9 -0
- package/dist/core/runtime/close.js +1 -1
- package/dist/core/runtime/deliver-live.js +1 -1
- package/dist/core/runtime/fleet.d.ts +1 -1
- package/dist/core/runtime/front-door-login.js +1 -1
- package/dist/core/runtime/front-door.js +2 -2
- package/dist/core/runtime/headless-pi.d.ts +1 -1
- package/dist/core/runtime/headless-pi.js +1 -1
- package/dist/core/runtime/host.d.ts +1 -1
- package/dist/core/runtime/host.js +3 -1
- package/dist/core/runtime/invocation.d.ts +3 -0
- package/dist/core/runtime/kickoff.d.ts +1 -0
- package/dist/core/runtime/kickoff.js +16 -16
- package/dist/core/runtime/launch-target.d.ts +1 -1
- package/dist/core/runtime/launch-target.js +1 -1
- package/dist/core/runtime/launch.d.ts +10 -35
- package/dist/core/runtime/launch.js +1 -1
- package/dist/core/runtime/lifecycle.js +2 -2
- package/dist/core/runtime/memory.d.ts +1 -1
- package/dist/core/runtime/memory.js +1 -1
- package/dist/core/runtime/model-registry.js +1 -1
- package/dist/core/runtime/model-swap.d.ts +17 -19
- package/dist/core/runtime/model-swap.js +1 -1
- package/dist/core/runtime/node-read.js +3 -2
- package/dist/core/runtime/nodes.d.ts +7 -0
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/outcome-document.js +1 -1
- package/dist/core/runtime/package-health.js +2 -2
- package/dist/core/runtime/persona.js +2 -2
- package/dist/core/runtime/pi-vendored.js +1 -1
- package/dist/core/runtime/placement-tmux.d.ts +1 -1
- package/dist/core/runtime/placement-tmux.js +1 -1
- package/dist/core/runtime/placement.js +1 -1
- package/dist/core/runtime/promote.js +1 -1
- package/dist/core/runtime/provider-credential-gate.js +2 -2
- package/dist/core/runtime/recovery-hold.d.ts +2 -0
- package/dist/core/runtime/recovery-hold.js +1 -0
- package/dist/core/runtime/recycle.js +1 -1
- package/dist/core/runtime/reopen.js +1 -1
- package/dist/core/runtime/reset.js +1 -1
- package/dist/core/runtime/revive.d.ts +1 -1
- package/dist/core/runtime/revive.js +2 -3
- package/dist/core/runtime/roadmap.js +4 -4
- package/dist/core/runtime/run-command.d.ts +6 -0
- package/dist/core/runtime/run-command.js +1 -1
- package/dist/core/runtime/session-branch.d.ts +2 -8
- package/dist/core/runtime/session-branch.js +1 -1
- package/dist/core/runtime/session-list-cache.d.ts +6 -22
- package/dist/core/runtime/session-list-cache.js +1 -1
- package/dist/core/runtime/situational-context.js +2 -2
- package/dist/core/runtime/spawn-env.d.ts +6 -6
- package/dist/core/runtime/spawn-env.js +1 -1
- package/dist/core/runtime/spawn.d.ts +5 -0
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/stop-guard.js +2 -2
- package/dist/core/runtime/stop-signals.d.ts +2 -2
- package/dist/core/runtime/stop-signals.js +1 -1
- package/dist/core/runtime/structured-output.d.ts +10 -4
- package/dist/core/runtime/structured-output.js +4 -4
- package/dist/core/runtime/tmux-bindings.js +3 -3
- package/dist/core/runtime/tmux-driver.d.ts +4 -0
- package/dist/core/runtime/tmux-driver.js +7 -7
- package/dist/core/runtime/view-socket.d.ts +9 -2
- package/dist/core/runtime/view-socket.js +1 -1
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/scope.d.ts +3 -2
- package/dist/core/scope.js +1 -1
- package/dist/core/scoped-state/db.js +1 -1
- package/dist/core/scoped-state/migrate.js +3 -3
- package/dist/core/scoped-state/profiles.d.ts +2 -1
- package/dist/core/scoped-state/profiles.js +1 -1
- package/dist/core/scoped-state/schema.d.ts +2 -1
- package/dist/core/scoped-state/schema.js +4 -4
- package/dist/core/scopes.d.ts +2 -2
- package/dist/core/scopes.js +1 -1
- package/dist/core/secrets.d.ts +1 -0
- package/dist/core/secrets.js +2 -2
- package/dist/core/spaces/mounts.d.ts +32 -0
- package/dist/core/spaces/mounts.js +1 -0
- package/dist/core/spaces/open-beneath.d.ts +71 -0
- package/dist/core/spaces/open-beneath.js +1 -0
- package/dist/core/spaces/permissions.d.ts +46 -0
- package/dist/core/spaces/permissions.js +1 -0
- package/dist/core/spaces/process.d.ts +27 -0
- package/dist/core/spaces/process.js +1 -0
- package/dist/core/spaces/space.d.ts +8 -0
- package/dist/core/spaces/space.js +2 -0
- package/dist/core/spaces/stop.d.ts +8 -0
- package/dist/core/spaces/stop.js +2 -0
- package/dist/core/spaces/users.d.ts +19 -0
- package/dist/core/spaces/users.js +1 -0
- package/dist/core/subscription-state.d.ts +2 -0
- package/dist/core/subscription-state.js +3 -3
- package/dist/core/substrate/frontmatter-validation.js +1 -1
- package/dist/core/substrate/injected-store.d.ts +28 -3
- package/dist/core/substrate/injected-store.js +2 -1
- package/dist/core/substrate/listings.js +1 -1
- package/dist/core/substrate/memory-events.d.ts +6 -0
- package/dist/core/substrate/memory-events.js +1 -0
- package/dist/core/substrate/on-read-node.js +1 -1
- package/dist/core/substrate/on-read.d.ts +6 -6
- package/dist/core/substrate/on-read.js +5 -5
- package/dist/core/substrate/plan.js +1 -1
- package/dist/core/substrate/render-node.js +1 -1
- package/dist/core/substrate/render.d.ts +4 -3
- package/dist/core/substrate/render.js +38 -38
- package/dist/core/substrate/schema.d.ts +6 -0
- package/dist/core/substrate/schema.js +1 -1
- package/dist/core/tui/panel.js +1 -1
- package/dist/core/user-settings.d.ts +12 -0
- package/dist/core/user-settings.js +1 -1
- package/dist/core/worktree-mutation-async.js +5 -5
- package/dist/core/worktree-quarantine.js +1 -1
- package/dist/core/worktree-remove.d.ts +15 -0
- package/dist/core/worktree-remove.js +1 -0
- package/dist/core/worktree-sweep.js +6 -6
- package/dist/daemon/analytics/compute.d.ts +37 -0
- package/dist/daemon/analytics/compute.js +1 -0
- package/dist/daemon/analytics/scan-worker.d.ts +1 -0
- package/dist/daemon/analytics/scan-worker.js +2 -0
- package/dist/daemon/analytics/scan.d.ts +37 -0
- package/dist/daemon/analytics/scan.js +1 -0
- package/dist/daemon/api/app-listener.d.ts +11 -0
- package/dist/daemon/api/app-listener.js +21 -0
- package/dist/daemon/api/bridge.js +5 -5
- package/dist/daemon/api/handlers/analytics.d.ts +2 -0
- package/dist/daemon/api/handlers/analytics.js +1 -0
- package/dist/daemon/api/handlers/attach.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +2 -2
- package/dist/daemon/api/handlers/bash.js +1 -1
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/canvas.d.ts +1 -1
- package/dist/daemon/api/handlers/canvas.js +6 -6
- package/dist/daemon/api/handlers/crons.js +1 -1
- package/dist/daemon/api/handlers/files.d.ts +1 -1
- package/dist/daemon/api/handlers/files.js +1 -1
- package/dist/daemon/api/handlers/health.js +2 -2
- package/dist/daemon/api/handlers/hook-exec.d.ts +2 -0
- package/dist/daemon/api/handlers/hook-exec.js +1 -0
- package/dist/daemon/api/handlers/human-requests.js +1 -1
- package/dist/daemon/api/handlers/inbox.js +1 -1
- package/dist/daemon/api/handlers/llm.d.ts +2 -0
- package/dist/daemon/api/handlers/llm.js +3 -0
- package/dist/daemon/api/handlers/memory-reads.d.ts +4 -0
- package/dist/daemon/api/handlers/memory-reads.js +1 -0
- package/dist/daemon/api/handlers/memory.js +5 -1
- package/dist/daemon/api/handlers/messages.js +2 -2
- package/dist/daemon/api/handlers/modelauth.js +1 -1
- package/dist/daemon/api/handlers/node-outcomes.js +1 -1
- package/dist/daemon/api/handlers/node-records.d.ts +2 -0
- package/dist/daemon/api/handlers/node-records.js +3 -0
- package/dist/daemon/api/handlers/nodes.d.ts +1 -1
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/profiles.d.ts +4 -1
- package/dist/daemon/api/handlers/profiles.js +1 -1
- package/dist/daemon/api/handlers/reports.js +5 -3
- package/dist/daemon/api/handlers/reviews.d.ts +1 -1
- package/dist/daemon/api/handlers/reviews.js +1 -1
- package/dist/daemon/api/handlers/run-routes.d.ts +2 -0
- package/dist/daemon/api/handlers/run-routes.js +1 -0
- package/dist/daemon/api/handlers/runs.d.ts +9 -0
- package/dist/daemon/api/handlers/runs.js +1 -0
- package/dist/daemon/api/handlers/subscriptions.js +1 -1
- package/dist/daemon/api/handlers/worktree.js +1 -1
- package/dist/daemon/api/map.d.ts +10 -4
- package/dist/daemon/api/map.js +2 -2
- package/dist/daemon/api/operations.d.ts +18 -0
- package/dist/daemon/api/operations.js +1 -0
- package/dist/daemon/api/principal.d.ts +42 -0
- package/dist/daemon/api/principal.js +1 -0
- package/dist/daemon/api/router.d.ts +27 -3
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/api/server.d.ts +4 -0
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/api/vendor-signin.d.ts +7 -0
- package/dist/daemon/api/vendor-signin.js +77 -0
- package/dist/daemon/api/viewer-presence.d.ts +3 -0
- package/dist/daemon/api/viewer-presence.js +1 -0
- package/dist/daemon/cron/armed-context.d.ts +4 -0
- package/dist/daemon/cron/armed-context.js +1 -1
- package/dist/daemon/cron/escalation.js +3 -3
- package/dist/daemon/cron/lease-recovery.js +1 -1
- package/dist/daemon/cron/sinks.js +2 -2
- package/dist/daemon/cron-run.d.ts +5 -5
- package/dist/daemon/cron-run.js +1 -1
- package/dist/daemon/crtrd.js +8 -7
- package/dist/daemon/delivery/run-delivery.d.ts +4 -0
- package/dist/daemon/delivery/run-delivery.js +1 -1
- package/dist/daemon/fleet.d.ts +1 -1
- package/dist/daemon/fleet.js +6 -6
- package/dist/daemon/human/finish.js +7 -7
- package/dist/daemon/joined-owner.d.ts +5 -0
- package/dist/daemon/joined-owner.js +1 -0
- package/dist/daemon/manage.js +2 -2
- package/dist/daemon/messaging/node-message.js +1 -1
- package/dist/daemon/park-activity.js +1 -1
- package/dist/daemon/reconcilers/bash-deadline.js +1 -1
- package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
- package/dist/daemon/reconcilers/broker-supervision.js +4 -4
- package/dist/daemon/reconcilers/delivery-lane.js +1 -1
- package/dist/daemon/reconcilers/live-obligation.d.ts +7 -0
- package/dist/daemon/reconcilers/live-obligation.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +20 -1
- package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
- package/dist/daemon/runs/append-section.d.ts +6 -0
- package/dist/daemon/runs/append-section.js +2 -0
- package/dist/daemon/runs/observer.d.ts +5 -0
- package/dist/daemon/runs/observer.js +4 -0
- package/dist/launcher/bwrap.d.ts +4 -0
- package/dist/launcher/bwrap.js +2 -0
- package/dist/launcher/client.d.ts +2 -0
- package/dist/launcher/client.js +3 -0
- package/dist/launcher/main.d.ts +1 -0
- package/dist/launcher/main.js +3 -0
- package/dist/launcher/netrule.d.ts +1 -0
- package/dist/launcher/netrule.js +1 -0
- package/dist/launcher/seccomp.d.ts +1 -0
- package/dist/launcher/seccomp.js +1 -0
- package/dist/launcher/spec.d.ts +88 -0
- package/dist/launcher/spec.js +1 -0
- package/dist/launcher/users.d.ts +18 -0
- package/dist/launcher/users.js +7 -0
- package/dist/launcher/validate.d.ts +22 -0
- package/dist/launcher/validate.js +1 -0
- package/dist/migrations/corpus.js +3 -3
- package/dist/migrations/runner.js +1 -1
- package/dist/native/linux/addon.node +0 -0
- package/dist/native/linux.d.ts +29 -0
- package/dist/native/linux.js +1 -0
- package/dist/pi-extensions/broker-local.js +2 -2
- package/dist/pi-extensions/canvas-bash-valve.d.ts +1 -3
- package/dist/pi-extensions/canvas-bash-valve.js +4 -7
- package/dist/pi-extensions/canvas-context-intro.d.ts +1 -2
- package/dist/pi-extensions/canvas-context-intro.js +2 -2
- package/dist/pi-extensions/canvas-doc-substrate.js +6 -6
- package/dist/pi-extensions/canvas-inbox-watcher.d.ts +2 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +2 -1
- package/dist/pi-extensions/canvas-passive-context.d.ts +1 -1
- package/dist/pi-extensions/canvas-passive-context.js +11 -11
- package/dist/pi-extensions/canvas-recap.js +6 -6
- package/dist/pi-extensions/canvas-stophook.js +1 -1
- package/dist/pi-extensions/canvas-structured-output.js +4 -4
- package/dist/pi-extensions/canvas-tool-guide.js +1 -1
- package/dist/pi-extensions/system-prompt-entry.d.ts +15 -0
- package/dist/pi-extensions/system-prompt-entry.js +1 -0
- package/dist/shared/env.d.ts +5 -1
- package/dist/shared/env.js +1 -1
- package/dist/shared/strip-cd-prefix.d.ts +1 -0
- package/dist/shared/strip-cd-prefix.js +1 -0
- package/dist/types.d.ts +31 -15
- package/docs/cli/memory-and-preferences.md +3 -1
- package/docs/sdk/client.md +34 -0
- package/docs/sdk/errors.md +2 -0
- package/docs/sdk/memory.md +2 -2
- package/docs/sdk/streaming.md +21 -0
- package/package.json +18 -4
- package/packages/crouter-identity/dist/index.d.ts +54 -0
- package/packages/crouter-identity/dist/index.js +166 -0
- package/packages/crouter-identity/package.json +33 -0
- package/runtime.lock.json +34 -8
- package/scripts/build-native-linux.mjs +16 -0
- package/scripts/install-runtime.mjs +9 -7
- package/scripts/lib/isolation-env.mjs +42 -0
- package/scripts/runtime-smoke.mjs +49 -0
- package/src/native/linux/addon.c +249 -0
- package/dist/core/profiles/state-block.d.ts +0 -4
- package/dist/core/profiles/state-block.js +0 -3
- package/dist/core/runtime/broker/auth-reload.d.ts +0 -41
- package/dist/core/runtime/broker/auth-reload.js +0 -1
- package/dist/core/substrate/cli-context-delivery.d.ts +0 -22
- package/dist/core/substrate/cli-context-delivery.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var j=Object.defineProperty;var a=(t,e)=>j(t,"name",{value:e,configurable:!0});import{createHash as S,generateKeyPairSync as v,randomUUID as _}from"node:crypto";import{mkdirSync as b}from"node:fs";import{join as $}from"node:path";import{InputError as c}from"../io.js";import{network as d}from"../errors.js";import{secretsDir as l}from"../layout.js";import{apiSocketPath as E}from"../canvas/paths.js";import{daemonAnswers as P}from"../layout-migrate/index.js";import{atomicWriteJson as U,readJsonIfExists as w}from"../fs-utils.js";import{updateConfig as J}from"../config.js";import{userScopeRoot as L}from"../scope.js";import{rewriteLocalProfileGrantees as O}from"../scoped-state/profiles.js";function m(){return $(l(),"runtime-client.json")}a(m,"clientPath");function p(t){if(typeof t!="string")return!1;try{const{protocol:e}=new URL(t);return e==="http:"||e==="https:"}catch{return!1}}a(p,"isUrl");function g(t){const e=t??{},{runtime:i,client_id:n,issuer:o,owner:s,url:r}=e;if(typeof i!="string"||!/^runtime:.+/.test(i)||typeof n!="string"||n===""||!p(o)||typeof s!="string"||!/^user:.+/.test(s)||!p(r))throw d("directory registration answer is missing runtime, client_id, issuer, owner, or url");return{runtime:i,client_id:n,issuer:o,owner:s,url:r}}a(g,"registration");async function R(t,e,i){const n=`${t.replace(/\/$/,"")}/v1/runtimes/registration`;let o;try{o=await fetch(n,{method:"PUT",headers:{authorization:`Bearer ${e}`,"content-type":"application/json"},body:JSON.stringify({jwk:i}),signal:AbortSignal.timeout(3e4)})}catch(r){throw d(`directory registration request to ${n} failed: ${r instanceof Error?r.message:String(r)}`)}const s=await o.text();if(!o.ok)throw new c({error:"join_refused",message:`directory refused the registration: ${o.status} ${s.slice(0,500)}`,next:"The enrollment token is single-use and short-lived; provisioning must retry with a fresh token."});try{return g(JSON.parse(s))}catch(r){throw r instanceof SyntaxError?d("directory registration answer is not JSON"):r}}a(R,"register");function y(t){J("user",e=>{e.runtime={...e.runtime,issuer:t.issuer,audience:t.url}}),O(L())}a(y,"commit");function F(){const t=w(m());if(t?.token_sha256===void 0)return null;const{owner:e}=t;if(typeof e!="string"||!/^user:.+/.test(e))throw new Error(`${m()} was written by join but has a missing or invalid owner`);return e}a(F,"joinedOwner");async function M(t,e){if(!p(t))throw new c({error:"invalid_directory",message:"directory must be an http or https URL",received:t,field:"directory",next:"Pass the directory base URL, for example https://directory.example."});if(e==="")throw new c({error:"invalid_token",message:"token is empty",field:"token",next:"Pass the enrollment token provisioning supplied."});const i=E();if(await P(i))throw new c({error:"daemon_running",message:`cannot join while a daemon answers on ${i}`,next:"Join before the daemon starts: stop the daemon that owns this volume, then run `crtr sys join` again."});const n=S("sha256").update(e).digest("hex"),o=w(m());if(o?.token_sha256===n){const h=g(o);return y(h),{...h,registered:!1}}const{privateKey:s,publicKey:r}=v("ec",{namedCurve:"P-256"}),u=_(),k={...s.export({format:"jwk"}),kid:u,alg:"ES256",use:"sig"},f=await R(t,e,{...r.export({format:"jwk"}),kid:u,alg:"ES256",use:"sig"});b(l(),{recursive:!0,mode:448});const x={jwk:k,kid:u,alg:"ES256",...f,token_sha256:n};return U(m(),x,{mode:384}),y(f),{...f,registered:!0}}a(M,"joinDirectory");export{M as joinDirectory,F as joinedOwner};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Disk usage of one directory in bytes, or null when it cannot be measured.
|
|
2
|
+
* `du` is spawned asynchronously: a managed checkout can be tens of gigabytes,
|
|
3
|
+
* and this runs inside the daemon, which must never block its event loop. */
|
|
4
|
+
export declare function directorySizeBytes(path: string): Promise<number | null>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var u=Object.defineProperty;var s=(r,t)=>u(r,"name",{value:t,configurable:!0});import{spawn as l}from"node:child_process";import{existsSync as c}from"node:fs";async function f(r){return c(r)?new Promise(t=>{const n=l("du",["-sk",r]);let e="";n.stdout.on("data",o=>e+=o.toString()),n.stderr.on("data",()=>{}),n.on("error",()=>t(null)),n.on("close",o=>{if(o!==0)return t(null);const i=Number(e.trim().split(/\s+/)[0]);t(Number.isSafeInteger(i)?i*1024:null)})}):null}s(f,"directorySizeBytes");export{f as directorySizeBytes};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { BuildEnvelopeInput } from './types.js';
|
|
2
2
|
export type EmitEventInput = Omit<BuildEnvelopeInput, 'component' | 'stream_id'>;
|
|
3
|
+
/** Resolves after every broker event emitted so far has been appended or written to stderr. */
|
|
4
|
+
export declare function flushBrokerLog(): Promise<void>;
|
|
3
5
|
/** The only canonical write path. The bound source owns the destination component/path/stream; node_id identifies the event target, with a broker source enforcing its bound node. */
|
|
4
6
|
export declare function emitEvent(input: EmitEventInput): boolean;
|
package/dist/core/events/emit.js
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var i=Object.defineProperty;var n=(r,e)=>i(r,"name",{value:e,configurable:!0});import{appendRotatingRecord as s}from"../log.js";import{buildEnvelope as f}from"./envelope.js";import{serializeEventRecord as c}from"./serialize.js";import{eventSource as m}from"./source.js";import{envExecutionId as u}from"../../shared/env.js";import{appendBrokerLog as p}from"../runtime/broker/daemon-ops.js";let d=Promise.resolve();function E(){return d}n(E,"flushBrokerLog");function a(r,e){d=d.then(async()=>{try{const{appended:o}=await p(r,e);o||process.stderr.write(`[broker] log.jsonl refused record: ${e}
|
|
2
|
+
`)}catch(o){process.stderr.write(`[broker] log.jsonl append failed (${o instanceof Error?o.message:String(o)}): ${e}
|
|
3
|
+
`)}})}n(a,"queueBrokerRecord");function R(r){const e=m();if(e===void 0)return!1;if(e.component==="broker"&&e.node_id!==void 0&&r.node_id!==void 0&&r.node_id!==e.node_id)throw new TypeError(`broker event target node_id must match bound node_id; received ${r.node_id}`);if(r.level==="debug"&&process.env.CRTR_LOG!=="debug")return!1;const o=f({...r,component:e.component,...e.node_id===void 0?{}:{node_id:e.node_id},...e.stream_id===void 0?{}:{stream_id:e.stream_id}}),t=c(o);return e.component==="broker"&&e.node_id!==void 0&&u()!==void 0?(a(e.node_id,t),!0):s(e.path,t)}n(R,"emitEvent");export{R as emitEvent,E as flushBrokerLog};
|
package/dist/core/feed/feed.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
var
|
|
1
|
+
var U=Object.defineProperty;var o=(n,e)=>U(n,"name",{value:e,configurable:!0});import{dirname as L,join as E}from"node:path";import{randomUUID as O}from"node:crypto";import{cancelCronsOnWake as x,getNode as p}from"../canvas/index.js";import{nodeAgentDir as M,reportsDir as R}from"../canvas/node-agent-paths.js";import{createFileBeneath as F,fsyncDirBeneath as J,linkBeneath as W,unlinkBeneath as z}from"../spaces/open-beneath.js";import{openDb as A,withCanvasWrite as H}from"../canvas/db.js";import{activateArmedExternalActionDelivery as B,readExternalActionDelivery as Y}from"../canvas/deliveries.js";import{composeNodeOutcomeDocument as K}from"../runtime/outcome-document.js";import{closeNode as j}from"../runtime/close.js";import{enqueueSubscriberMail as q}from"./messages.js";import{operationIdContext as P}from"../events/operation-id.js";class h extends Error{static{o(this,"FinalizationError")}code;reportPath;constructor(e,r){super(e),this.code=e,this.reportPath=r}}function G(n){const e=o((r,i=2)=>String(r).padStart(i,"0"),"pad");return`${n.getUTCFullYear()}${e(n.getUTCMonth()+1)}${e(n.getUTCDate())}T${e(n.getUTCHours())}${e(n.getUTCMinutes())}${e(n.getUTCSeconds())}${e(n.getUTCMilliseconds(),3)}`}o(G,"compactTs");function Q(n,e,r){const i=M(n),c=R(n),u=new Date,s=`${G(u)}-${O().slice(-8)}-${e}.md`,a=E(c,s),d=E(c,`.${s}.${O()}.tmp`),t=u.toISOString();return F(i,d,`---
|
|
2
2
|
node: ${n}
|
|
3
3
|
kind: ${e}
|
|
4
|
-
ts: ${
|
|
4
|
+
ts: ${t}
|
|
5
5
|
---
|
|
6
|
-
${
|
|
7
|
-
`)[0]??"";return
|
|
6
|
+
${r}`),{root:i,finalPath:a,stagedPath:d,basename:s,ts:t}}o(Q,"stageReport");function f(n,e){try{z(n.root,e)}catch(r){if(r.code!=="ENOENT")throw r}}o(f,"remove");function S(n){let e=!1;try{W(n.root,n.stagedPath,n.finalPath),e=!0,f(n,n.stagedPath),J(n.root,L(n.finalPath))}catch(r){throw e&&f(n,n.finalPath),r}}o(S,"install");function V(n,e=80){const r=n.split(`
|
|
7
|
+
`)[0]??"";return r.length>e?`${r.slice(0,e-1)}\u2026`:r}o(V,"firstLine");function X(n,e){return e??(n==="urgent"?"urgent":"normal")}o(X,"tierFor");function Z(n){const e=Y(`node-outcome:${n}`);if(e===null)return null;const r=e.adapter;if(r?.adapter!=="subprocess"||!Array.isArray(r.argv)||!r.argv.every(i=>typeof i=="string")||typeof r.cwd!="string")throw new Error(`outcome delivery ${e.deliveryId} has an invalid subprocess adapter`);return{name:e.destinationId,payload:r.payload??null}}o(Z,"outcomeAction");function y(n,e,r,i,c,u,s,a){return q(n,{kind:i,label:V(s),senderNodeId:e,senderName:r,bodyRef:u,urgency:X(i,c),...a===void 0?{}:{disposition:a}}).map(d=>d.destinationNodeId)}o(y,"enqueueReport");function I(n,e,r,i,c,u,s){const a=A();let d=!1;a.exec("BEGIN IMMEDIATE");try{const t=a.prepare("SELECT status, final_report FROM nodes WHERE node_id = ?").get(n);if(t===void 0)throw new h("unknown_node");if(t.final_report!==null)throw new h("already_finalized",t.final_report);if(t.status==="canceled"||t.status==="dead")throw new h("finalization_forbidden");if(t.status!=="active"&&t.status!=="idle"&&t.status!=="done")throw new h("finalization_forbidden");const l=a.prepare("SELECT e.from_id AS node_id, e.active, e.created FROM edges e JOIN nodes source ON source.node_id = e.to_id JOIN nodes subscriber ON subscriber.node_id = e.from_id WHERE e.type = 'subscribes_to' AND e.to_id = ? AND subscriber.grantee = source.grantee AND (source.run_id IS NULL OR subscriber.run_id = source.run_id) ORDER BY e.created").all(n).map(b=>({node_id:b.node_id,active:b.active===1,created:b.created})),m=p(n),N=m?.kind!=="human",k=(m?.outcome_revision??0)+1,D=s?.kind??"result",_=s?.reason??"finalized",$=s?.detailJson??null,T=m===null?null:Z(n),w=!N||T===null||m===null?null:JSON.stringify(K({node:{...m,status:"done",intent:"done",terminal_reason:_},outcome:{kind:D,reason:_,at:e.ts,revision:k,detailJson:$},action:T,finalReport:e.basename}));S(e),d=!0,N?(a.prepare("UPDATE nodes SET status = 'done', intent = 'done', terminal_reason = ?, final_report = ?, finalized_at = ?, outcome_kind = ?, outcome_reason = ?, outcome_at = ?, outcome_revision = outcome_revision + 1, outcome_detail_json = ? WHERE node_id = ? AND final_report IS NULL").run(_,e.basename,e.ts,D,_,e.ts,$,n),w!==null&&B(a,{idempotencyKey:`node-outcome:${n}`,label:n,bodyJson:w,supersede:!0},Date.now())):a.prepare("UPDATE nodes SET status = 'done', intent = 'done', terminal_reason = 'finalized', final_report = ?, finalized_at = ? WHERE node_id = ? AND final_report IS NULL").run(e.basename,e.ts,n);const g=y(l,i,c,"final",void 0,`${n}:reports/${e.basename}`,r,u);return a.exec("COMMIT"),{deliveredTo:g}}catch(t){throw a.exec("ROLLBACK"),d&&f(e,e.finalPath),t}finally{f(e,e.stagedPath)}}o(I,"commitCanonicalFinal");async function C(n,e){if(!n)throw new Error(`push: empty nodeId (kind=${e.kind}) \u2014 a report must belong to a node`);if(e.kind==="final"&&e.deliveryTier!==void 0)throw new Error("push final does not accept a delivery tier");if(e.kind!=="final"&&e.outcome!==void 0)throw new Error("push outcome is final-only");const r=Q(n,e.kind,e.body),i=e.from??n,c=p(i)?.name;if(e.kind==="final"){const{deliveredTo:s}=I(n,r,e.body,i,c,e.disposition,e.outcome);if(x(n),p(n)?.run_id===n){const d=A().prepare("SELECT node_id FROM nodes WHERE run_id = ? AND node_id != ? ORDER BY created DESC").all(n,n);for(const t of d){const l=p(t.node_id);l&&l.status!=="done"&&l.status!=="canceled"&&l.status!=="dead"&&j(t.node_id,{preserveEmpty:!0})}}return{reportPath:r.finalPath,deliveredTo:s}}let u=!1;try{S(r),u=!0;const s=H(a=>{const d=a.prepare("SELECT e.from_id AS node_id, e.active, e.created FROM edges e JOIN nodes source ON source.node_id = e.to_id JOIN nodes subscriber ON subscriber.node_id = e.from_id WHERE e.type = 'subscribes_to' AND e.to_id = ? AND subscriber.grantee = source.grantee AND (source.run_id IS NULL OR subscriber.run_id = source.run_id) ORDER BY e.created").all(n).map(t=>({node_id:t.node_id,active:t.active===1,created:t.created}));return y(d,i,c,e.kind,e.deliveryTier,`${n}:reports/${r.basename}`,e.body,e.disposition)});return{reportPath:r.finalPath,deliveredTo:s}}catch(s){throw u&&f(r,r.finalPath),s}finally{f(r,r.stagedPath)}}o(C,"pushWithContext");function v(n,e){return P.current()===void 0?P.fresh(()=>C(n,e)):C(n,e)}o(v,"push");async function fe(n,e,r){return v(n,{kind:"update",body:e,...r})}o(fe,"pushUpdate");async function me(n,e,r){return v(n,{kind:"urgent",body:e,...r})}o(me,"pushUrgent");async function pe(n,e,r){return v(n,{kind:"final",body:e,...r})}o(pe,"pushFinal");function _e(n,e,r,i,c){if(r===""||r.includes("/")||r.includes("\\"))throw new Error(`invalid canonical final report basename: ${r}`);const u=y([{node_id:e,active:!0,created:""}],n,p(n)?.name,"final",void 0,`${n}:reports/${r}`,i,c?.disposition);return{reportPath:E(R(n),r),deliveredTo:u}}o(_e,"redeliverFinalReport");export{h as FinalizationError,v as push,pe as pushFinal,fe as pushUpdate,me as pushUrgent,_e as redeliverFinalReport};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
1
2
|
import { type InboxDisposition, type InboxKind, type InboxTier } from './inbox.js';
|
|
2
3
|
export type { InboxDisposition, InboxKind, InboxTier } from './inbox.js';
|
|
3
4
|
export interface NodeMailInput {
|
|
@@ -13,6 +14,8 @@ export interface NodeMailInput {
|
|
|
13
14
|
operationId?: string;
|
|
14
15
|
/** Optional caller-owned obligation identity, used by cron settlement replay. */
|
|
15
16
|
idempotencyKey?: string;
|
|
17
|
+
/** Runs with the mail insert, before the transaction commits. */
|
|
18
|
+
withinEnqueue?: (db: DatabaseSync, messageId: string) => void;
|
|
16
19
|
}
|
|
17
20
|
export interface ExternalActionAdapter {
|
|
18
21
|
adapter: 'subprocess' | 'cron_spawn' | 'cron_human';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
var v=Object.defineProperty;var s=(n,e)=>v(n,"name",{value:e,configurable:!0});import{existsSync as S,mkdirSync as k,renameSync as O,writeFileSync as
|
|
1
|
+
var v=Object.defineProperty;var s=(n,e)=>v(n,"name",{value:e,configurable:!0});import{existsSync as S,mkdirSync as k,renameSync as O,writeFileSync as R}from"node:fs";import{randomBytes as A,randomUUID as h}from"node:crypto";import{join as T}from"node:path";import{cancelCronsOnWake as f}from"../canvas/crons.js";import{withCanvasWrite as c}from"../canvas/db.js";import{getRow as D}from"../canvas/canvas.js";import{messagesDir as L}from"../canvas/paths.js";import{syncDirectory as x,syncFile as C}from"../fs-utils.js";import{settleDeadControllerWait as b,settleMatchingControllerWait as g}from"../canvas/waits.js";import{generateOperationId as p,operationIdContext as u,validateOperationId as M}from"../events/operation-id.js";import{clipBody as J}from"./inbox.js";function y(){let n;do n=A(16).toString("hex");while(n==="00000000000000000000000000000000");return n}s(y,"newId");function E(n,e){const d=JSON.stringify(n);if(d===void 0)throw new TypeError(`${e} must be JSON-serializable`);return d}s(E,"stringify");function I(n,e){return e!=="normal"&&e!=="deferred"?e:D(n)?.lifecycle==="terminal"?"urgent":e}s(I,"effectiveTier");function W(n,e,d){const r=L(n);S(r)||k(r,{recursive:!0});const o=e.replace(/[^0-9]/g,""),t=T(r,`${o}-${h().slice(0,6)}.md`),i=`${t}.tmp`;return R(i,d,"utf8"),C(i),O(i,t),x(r),t}s(W,"writeMessageBody");function F(n){if(typeof n!="object"||n===null)return"";const e=n.body;return typeof e=="string"?e.trim():""}s(F,"inlineBody");function _(n,e){const d=e.messageId??y(),r=Number(n.prepare("SELECT COALESCE(MAX(seq), 0) AS seq FROM messages").get().seq)+1;return n.prepare(`INSERT INTO messages
|
|
2
2
|
(message_id, seq, operation_id, created_at, sender_node_id, sender_name, kind, label, body_ref, body_json, disposition)
|
|
3
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(d,r,e.operationId,e.createdAt,e.senderNodeId,e.senderName,e.kind,e.label,e.bodyRef,e.bodyJson===void 0?null:
|
|
3
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(d,r,e.operationId,e.createdAt,e.senderNodeId,e.senderName,e.kind,e.label,e.bodyRef,e.bodyJson===void 0?null:E(e.bodyJson,"message body"),e.disposition),d}s(_,"insertMessage");function N(n,e,d,r,o,t,i){const a=y();return n.prepare(`INSERT INTO deliveries
|
|
4
4
|
(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,r,o,i??null,t,t),a}s(N,"insertNodeDelivery");function
|
|
6
|
-
FROM deliveries d JOIN messages m ON m.message_id = d.message_id WHERE d.idempotency_key = ?`).get(e.idempotencyKey);if(l!==void 0)return{messageId:l.message_id,deliveryId:l.delivery_id,urgency:l.urgency,createdAt:l.created_at}}const
|
|
5
|
+
VALUES (?, ?, 'node_inbox', ?, ?, ?, 'pending', ?, ?, ?)`).run(a,e,d,r,o,i??null,t,t),a}s(N,"insertNodeDelivery");function w(n,e){const d=new Date().toISOString(),r=n.operationId===void 0?u.current()??p():M(n.operationId);let o=n.bodyRef??null,t=n.bodyJson;if(o===null&&n.senderNodeId!=="human"){const i=F(t),a=J(i);a.clipped&&(o=W(e,d,i),t={...t,body:a.text})}return{createdAt:d,operationId:r,bodyRef:o,bodyJson:t}}s(w,"finalizeNodeMail");function H(n,e){const d=w(e,n);return c(r=>{const o=r.prepare("SELECT run_id FROM nodes WHERE node_id = ?").get(n);if(o?.run_id&&r.prepare("SELECT deleting_at FROM nodes WHERE node_id = ?").get(o.run_id)?.deleting_at)throw new Error("run is deleting");if(e.idempotencyKey!==void 0){const l=r.prepare(`SELECT d.delivery_id, d.message_id, d.urgency, m.created_at
|
|
6
|
+
FROM deliveries d JOIN messages m ON m.message_id = d.message_id WHERE d.idempotency_key = ?`).get(e.idempotencyKey);if(l!==void 0)return{messageId:l.message_id,deliveryId:l.delivery_id,urgency:l.urgency,createdAt:l.created_at}}const t=Date.now(),i=I(n,e.urgency),a=_(r,{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}),m=N(r,a,n,i,e.wake,t,e.idempotencyKey);return g(n,e.senderNodeId??null,t,r),e.withinEnqueue?.(r,a),e.wake===1&&i!=="deferred"&&f(n),{messageId:a,deliveryId:m,urgency:i,createdAt:d.createdAt}})}s(H,"enqueueNodeMail");function Y(n,e){if(n.length===0)return[];const d=w(e,n[0].node_id);return c(r=>{const o=Date.now(),t=_(r,{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});return n.map(i=>{const a=I(i.node_id,e.urgency),m=i.active?1:0,l=N(r,t,i.node_id,a,m,o);return g(i.node_id,e.senderNodeId??null,o,r),m===1&&a!=="deferred"&&f(i.node_id),{destinationNodeId:i.node_id,messageId:t,deliveryId:l,urgency:a,createdAt:d.createdAt}})})}s(Y,"enqueueSubscriberMail");function Z(n){return c(e=>{const d=e.prepare("SELECT delivery_id, message_id FROM deliveries WHERE idempotency_key = ?").get(n.idempotencyKey);if(d!==void 0)return{messageId:d.message_id,deliveryId:d.delivery_id};const r=Date.now(),o=_(e,{operationId:u.current()??p(),createdAt:new Date(r).toISOString(),senderNodeId:null,senderName:null,kind:n.kind??"completed",label:n.label??n.destinationId,bodyRef:null,bodyJson:n.bodyJson,disposition:null}),t=y(),i=e.prepare(`INSERT INTO deliveries
|
|
7
7
|
(delivery_id, message_id, destination_kind, destination_id, urgency, wake, state, next_attempt_at,
|
|
8
8
|
adapter_json, idempotency_key, created_at, updated_at)
|
|
9
9
|
VALUES (?, ?, 'external_action', ?, 'normal', 0, 'pending', ?, ?, ?, ?, ?)
|
|
10
|
-
ON CONFLICT(idempotency_key) WHERE idempotency_key IS NOT NULL DO NOTHING`).run(t,o,n.destinationId,r,
|
|
11
|
-
WHERE w.node_id = ? AND w.kind = 'controller' AND w.target_id = ? AND w.satisfied_at IS NULL`).get(n,e);if(o===void 0||o.controller_status==="active"||o.controller_status==="idle")return null;const t=
|
|
10
|
+
ON CONFLICT(idempotency_key) WHERE idempotency_key IS NOT NULL DO NOTHING`).run(t,o,n.destinationId,r,E(n.adapter,"external action adapter"),n.idempotencyKey,r,r);if(Number(i.changes)===1)return{messageId:o,deliveryId:t};const a=e.prepare("SELECT delivery_id, message_id FROM deliveries WHERE idempotency_key = ?").get(n.idempotencyKey);if(a===void 0)throw new Error(`external action idempotency winner disappeared: ${n.idempotencyKey}`);return{messageId:a.message_id,deliveryId:a.delivery_id}})}s(Z,"enqueueExternalAction");function ee(n,e=Date.now()){return c(d=>Number(d.prepare("UPDATE deliveries SET canceled_at = ?, updated_at = ? WHERE delivery_id = ? AND canceled_at IS NULL").run(e,e,n).changes)===1)}s(ee,"cancelDelivery");function ne(n,e={}){return c(d=>{const r=["d.destination_kind = 'node_inbox'","d.destination_id = ?","d.canceled_at IS NULL","d.state IN ('pending', 'handed_off')"],o=[n];e.senderNodeId!==void 0&&(r.push("m.sender_node_id IS ?"),o.push(e.senderNodeId)),e.kind!==void 0&&(r.push("m.kind = ?"),o.push(e.kind));const t=d.prepare(`SELECT d.delivery_id FROM deliveries d JOIN messages m ON m.message_id = d.message_id WHERE ${r.join(" AND ")}`).all(...o);if(t.length===0)return[];const i=Date.now();return d.prepare(`UPDATE deliveries SET canceled_at = ?, updated_at = ? WHERE delivery_id IN (${t.map(()=>"?").join(",")})`).run(i,i,...t.map(a=>a.delivery_id)),t.map(a=>a.delivery_id)})}s(ne,"cancelPendingNodeMail");function de(n,e){return c(d=>{const r=Date.now(),o=d.prepare(`SELECT target.status AS controller_status FROM waits w LEFT JOIN nodes target ON target.node_id = w.target_id
|
|
11
|
+
WHERE w.node_id = ? AND w.kind = 'controller' AND w.target_id = ? AND w.satisfied_at IS NULL`).get(n,e);if(o===void 0||o.controller_status==="active"||o.controller_status==="idle")return null;const t=H(n,{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(!b(n,e,r,d))throw new Error(`controller wait changed while notifying ${n}`);return t})}s(de,"enqueueControllerDeathNotice");export{ee as cancelDelivery,ne as cancelPendingNodeMail,de as enqueueControllerDeathNotice,Z as enqueueExternalAction,H as enqueueNodeMail,Y as enqueueSubscriberMail};
|
package/dist/core/fs-utils.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export declare function writeJson(path: string, data: unknown): void;
|
|
|
11
11
|
export interface AtomicWriteOptions {
|
|
12
12
|
/** Force this mode regardless of any existing file's mode. Omitted: preserve the existing file's mode, or default a new file to `0o600`. */
|
|
13
13
|
mode?: number;
|
|
14
|
+
/** Require the parent to exist, rather than recreate a removed project root. */
|
|
15
|
+
createParent?: boolean;
|
|
14
16
|
}
|
|
15
17
|
export declare function atomicWriteJson(path: string, data: unknown, opts?: AtomicWriteOptions): void;
|
|
16
18
|
/** Force a file's written bytes to stable storage. */
|
package/dist/core/fs-utils.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
`,"utf8")}n(U,"writeJson");function V(r,t,
|
|
3
|
-
`,
|
|
1
|
+
var v=Object.defineProperty;var n=(r,t)=>v(r,"name",{value:t,configurable:!0});import{existsSync as c,lstatSync as D,mkdirSync as E,readdirSync as y,readFileSync as f,rmSync as S,statSync as d,symlinkSync as W,writeFileSync as a,cpSync as w,readlinkSync as g,renameSync as I,chmodSync as $,realpathSync as b,closeSync as J,fsyncSync as O,openSync as T}from"node:fs";import{dirname as s,join as h,relative as L,sep as j}from"node:path";import{homedir as k,platform as F}from"node:os";function N(r){try{return b(r)}catch{return r}}n(N,"realpathOrSelf");function Q(r,t=k()){return r==="~"?t:r.startsWith("~/")||F()==="win32"&&r.startsWith("~\\")?h(t,r.slice(2)):r}n(Q,"expandTilde");function R(r,t=k()){return r===t?"~":r.startsWith(t+j)?"~"+r.slice(t.length):r}n(R,"tildify");function l(r){E(r,{recursive:!0})}n(l,"ensureDir");function U(r,t){l(s(r)),a(r,JSON.stringify(t,null,2)+`
|
|
2
|
+
`,"utf8")}n(U,"writeJson");function V(r,t,i){C(r,JSON.stringify(t,null,2)+`
|
|
3
|
+
`,i)}n(V,"atomicWriteJson");function X(r){const t=T(r,"r");try{O(t)}finally{J(t)}}n(X,"syncFile");function Y(r){const t=T(r,"r");try{O(t)}finally{J(t)}}n(Y,"syncDirectory");function C(r,t,i){i?.createParent!==!1&&l(s(r));const e=`${r}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`,o=i?.mode??(c(r)?d(r).mode&511:384);try{a(e,t,{mode:o}),$(e,o),I(e,r)}finally{c(e)&&S(e,{force:!0})}}n(C,"atomicWriteText");function M(r){return JSON.parse(f(r,"utf8"))}n(M,"readJson");function Z(r){try{return M(r)}catch(t){if(t.code==="ENOENT")return null;throw t}}n(Z,"readJsonIfExists");function _(r){try{return JSON.parse(f(r,"utf8"))}catch{return null}}n(_,"readJsonOrNull");function P(r){return c(r)?f(r,"utf8"):null}n(P,"readTextIfExists");function rr(r){return f(r,"utf8")}n(rr,"readText");function tr(r,t){l(s(r)),a(r,t,"utf8")}n(tr,"writeText");function q(r){try{return d(r).isDirectory()}catch{return!1}}n(q,"isDir");function z(r){try{return D(r).isSymbolicLink()}catch{return!1}}n(z,"isSymlink");function nr(r){return c(r)}n(nr,"pathExists");function er(r){return c(r)?y(r,{withFileTypes:!0}).filter(t=>t.isDirectory()||t.isSymbolicLink()).map(t=>t.name):[]}n(er,"listDirs");function ir(r){return c(r)?y(r):[]}n(ir,"listEntries");function A(r){!c(r)&&!z(r)||S(r,{recursive:!0,force:!0})}n(A,"removePath");function or(r,t,i={}){l(s(t)),A(t);const e=F()==="win32";if(!i.noSymlink&&!e){const o=L(N(s(t)),N(r));try{return W(o,t,q(r)?"dir":"file"),"symlink"}catch{return w(r,t,{recursive:!0}),"copy"}}return w(r,t,{recursive:!0}),"copy"}n(or,"linkOrCopy");function cr(r){try{return g(r)}catch{return null}}n(cr,"readSymlinkTarget");function ur(r,t=()=>!0,i=()=>!1){const e=[];if(!c(r))return e;const o=[r];for(;o.length;){const x=o.pop();let p;try{p=y(x,{withFileTypes:!0})}catch{continue}for(const u of p){const m=h(x,u.name);u.isDirectory()?i(u.name)||o.push(m):u.isFile()&&t(u.name)&&e.push(m)}}return e}n(ur,"walkFiles");function sr(){return new Date().toISOString()}n(sr,"nowIso");export{V as atomicWriteJson,C as atomicWriteText,l as ensureDir,Q as expandTilde,q as isDir,z as isSymlink,or as linkOrCopy,er as listDirs,ir as listEntries,sr as nowIso,nr as pathExists,M as readJson,Z as readJsonIfExists,_ as readJsonOrNull,cr as readSymlinkTarget,rr as readText,P as readTextIfExists,N as realpathOrSelf,A as removePath,Y as syncDirectory,X as syncFile,R as tildify,ur as walkFiles,U as writeJson,tr as writeText};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** The unjoined runtime's one grant; nodes created before join reference it by id. */
|
|
2
|
+
export declare const LOCAL_TERMINAL_GRANT_ID = "local:terminal";
|
|
3
|
+
/** An unjoined local runtime has exactly one grant, owned by its terminal app. */
|
|
4
|
+
export declare function installLocalTerminalGrant(): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var l=Object.defineProperty;var e=(r,a)=>l(r,"name",{value:a,configurable:!0});import{replaceGrants as s}from"./mirror.js";const t=["crtr:llm","crtr:act","crtr:schedule","crtr:memory:rw:user","crtr:memory:manage:user","crtr:files:rw:user:."].map(r=>({scope:r,mode:"always"})),c="local:terminal";function m(){const r=new Date().toISOString();s([{id:c,runtime:"runtime:local",sub:"user:local",grantee:"app:terminal",rev:1,scopes:t,resolved_scopes:t,spend_cap:null,expires_at:null,status:"active",revoked_at:null,approved_at:r,payer:"user",synced_at:r}],r,"local")}e(m,"installLocalTerminalGrant");export{c as LOCAL_TERMINAL_GRANT_ID,m as installLocalTerminalGrant};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import { type Scope } from '@north-light/crouter-identity';
|
|
3
|
+
export interface GrantScope {
|
|
4
|
+
scope: string;
|
|
5
|
+
mode: 'always' | 'ask';
|
|
6
|
+
}
|
|
7
|
+
export interface GrantRecord {
|
|
8
|
+
id: string;
|
|
9
|
+
runtime: string;
|
|
10
|
+
sub: string;
|
|
11
|
+
grantee: string;
|
|
12
|
+
rev: number;
|
|
13
|
+
scopes: GrantScope[];
|
|
14
|
+
resolved_scopes: GrantScope[];
|
|
15
|
+
spend_cap: number | null;
|
|
16
|
+
expires_at: string | null;
|
|
17
|
+
status: 'active' | 'revoked' | 'removed';
|
|
18
|
+
revoked_at: string | null;
|
|
19
|
+
approved_at: string | null;
|
|
20
|
+
payer: 'user' | 'app' | null;
|
|
21
|
+
synced_at: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ActiveGrant extends GrantRecord {
|
|
24
|
+
resolved: Scope[];
|
|
25
|
+
}
|
|
26
|
+
/** Every mirrored grant, whatever its status. */
|
|
27
|
+
export declare function allGrants(): GrantRecord[];
|
|
28
|
+
/** The active form of a grant record read earlier, or null when it is not active or unparsable. */
|
|
29
|
+
export declare function activeRecord(grant: GrantRecord): ActiveGrant | null;
|
|
30
|
+
export declare function hasGrant(grantId: string): boolean;
|
|
31
|
+
export declare function activeGrant(grantId: string): ActiveGrant | null;
|
|
32
|
+
export declare function grantFor(grantee: string, sub: string): ActiveGrant | null;
|
|
33
|
+
export declare function activeGrantForApp(grantee: string): ActiveGrant | null;
|
|
34
|
+
export declare function terminalGrant(): ActiveGrant | null;
|
|
35
|
+
export declare function hasSyncedGrants(source: string): boolean;
|
|
36
|
+
/** OWN-11 for a joined runtime: the unjoined runtime's local mirror grants
|
|
37
|
+
* `user:local` full local scopes and is not the directory's. Delete it so no
|
|
38
|
+
* grant exists until grant sync installs the directory's mirror. */
|
|
39
|
+
export declare function dropLocalGrantMirror(db: DatabaseSync): number;
|
|
40
|
+
/** The directory response is complete; commit it or keep the prior snapshot intact. */
|
|
41
|
+
export declare function replaceGrants(grants: readonly GrantRecord[], syncedAt: string, source: string): void;
|
|
42
|
+
/** Bumped by every `replaceGrants`. A launch compiled against one generation
|
|
43
|
+
* and started under another may hold mounts the new mirror no longer grants. */
|
|
44
|
+
export declare function grantsGeneration(): number;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
var l=Object.defineProperty;var a=(e,r)=>l(e,"name",{value:r,configurable:!0});import{parseScope as v}from"@north-light/crouter-identity";import{openDb as s,withCanvasWrite as d}from"../canvas/db.js";function i(e){if(!Array.isArray(e))throw new TypeError("grant scopes must be a list");return e.map(r=>{if(!r||typeof r!="object"||typeof r.scope!="string"||!["always","ask"].includes(r.mode))throw new TypeError("invalid grant scope entry");return{scope:r.scope,mode:r.mode}})}a(i,"entries");function c(e){return{id:e.id,runtime:e.runtime,sub:e.sub,grantee:e.grantee,rev:e.rev,scopes:i(JSON.parse(e.scopes_json)),resolved_scopes:i(JSON.parse(e.resolved_scopes_json)),spend_cap:e.spend_cap,expires_at:e.expires_at,status:e.status,revoked_at:e.revoked_at,approved_at:e.approved_at,payer:e.payer,synced_at:e.synced_at}}a(c,"record");function u(e){if(!e||e.status!=="active")return null;try{return f(c(e))}catch(r){if(r instanceof TypeError||r instanceof SyntaxError)return null;throw r}}a(u,"active");function T(){return s().prepare("SELECT * FROM grants").all().flatMap(e=>{try{return[c(e)]}catch(r){if(r instanceof TypeError||r instanceof SyntaxError)return[];throw r}})}a(T,"allGrants");function f(e){if(e.status!=="active")return null;try{const r=e.resolved_scopes.map(({scope:o})=>v(o));return{...e,resolved:e.resolved_scopes.flatMap(({mode:o},p)=>o==="always"?[r[p]]:[])}}catch(r){if(r instanceof TypeError||r instanceof SyntaxError)return null;throw r}}a(f,"activeRecord");function S(e){return!!s().prepare("SELECT 1 FROM grants WHERE id = ?").get(e)}a(S,"hasGrant");function m(e){return u(s().prepare("SELECT * FROM grants WHERE id = ?").get(e))}a(m,"activeGrant");function R(e,r){return u(s().prepare("SELECT * FROM grants WHERE grantee = ? AND sub = ?").get(e,r))}a(R,"grantFor");function O(e){const r=s().prepare("SELECT * FROM grants WHERE grantee = ? AND status = 'active'").all(e);if(r.length>1)throw new Error(`multiple active grants for ${e}`);return u(r[0])}a(O,"activeGrantForApp");function N(){const e=s().prepare("SELECT * FROM grants WHERE grantee = 'app:terminal' AND status = 'active'").all();if(e.length>1)throw new Error("multiple active terminal grants");return u(e[0])}a(N,"terminalGrant");function x(e){return s().prepare("SELECT value FROM runtime_state WHERE key = 'grants_source'").get()?.value===e}a(x,"hasSyncedGrants");function h(e){return e.prepare("SELECT value FROM runtime_state WHERE key = 'grants_source'").get()?.value!=="local"?0:(e.prepare("DELETE FROM runtime_state WHERE key = 'grants_source'").run(),Number(e.prepare("DELETE FROM grants").run().changes))}a(h,"dropLocalGrantMirror");function L(e,r,o){const p=new Set;for(const t of e){if(p.has(t.id)||!t.id||!t.runtime||!t.sub||!t.grantee||!Number.isInteger(t.rev)||!["active","revoked","removed"].includes(t.status))throw new TypeError("invalid grant sync response");p.add(t.id),i(t.scopes),i(t.resolved_scopes)}d(t=>{t.exec("DELETE FROM grants");const E=t.prepare(`INSERT INTO grants
|
|
2
|
+
(id, runtime, sub, grantee, rev, scopes_json, resolved_scopes_json, spend_cap, expires_at,
|
|
3
|
+
status, revoked_at, approved_at, payer, synced_at)
|
|
4
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);for(const n of e)E.run(n.id,n.runtime,n.sub,n.grantee,n.rev,JSON.stringify(n.scopes),JSON.stringify(n.resolved_scopes),n.spend_cap,n.expires_at,n.status,n.revoked_at,n.approved_at,n.payer,n.synced_at);t.prepare("INSERT INTO runtime_state (key, value) VALUES ('grants_source', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(o),t.prepare("INSERT INTO runtime_state (key, value) VALUES ('grants_generation', '1') ON CONFLICT(key) DO UPDATE SET value = CAST(CAST(value AS INTEGER) + 1 AS TEXT)").run()})}a(L,"replaceGrants");function A(){const e=s().prepare("SELECT value FROM runtime_state WHERE key = 'grants_generation'").get();return e?Number(e.value):0}a(A,"grantsGeneration");export{m as activeGrant,O as activeGrantForApp,f as activeRecord,T as allGrants,h as dropLocalGrantMirror,R as grantFor,A as grantsGeneration,S as hasGrant,x as hasSyncedGrants,L as replaceGrants,N as terminalGrant};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SandboxRecord } from '../../launcher/spec.js';
|
|
2
|
+
import { type GrantRecord } from './mirror.js';
|
|
3
|
+
/** Work that outlives the sync that started it; the daemon keeps ownership of it during shutdown. */
|
|
4
|
+
export type Detach = (work: Promise<void>) => void;
|
|
5
|
+
/** Why a sandbox must stop under the current mirror, or null when every
|
|
6
|
+
* granted mount it was launched with is still granted. */
|
|
7
|
+
export declare function exceeds(sandbox: Pick<SandboxRecord, 'uid' | 'nodeId' | 'mounts'>, owners?: ReadonlyMap<number, {
|
|
8
|
+
app: string;
|
|
9
|
+
status: string;
|
|
10
|
+
}>): string | null;
|
|
11
|
+
/** R26 from current state (runtime spec §15 "Ending revoked file access"):
|
|
12
|
+
* compare every live launcher sandbox's launched mounts with what the current
|
|
13
|
+
* mirror grants, and stop each one that holds more. Runs after every sync and
|
|
14
|
+
* once at daemon start, so a stop an earlier daemon never confirmed is retried.
|
|
15
|
+
* Resolves once every stop has been started; `completion` settles when they end. */
|
|
16
|
+
export declare function sweepSandboxes(): Promise<{
|
|
17
|
+
completion: Promise<void>;
|
|
18
|
+
}>;
|
|
19
|
+
/** R26 and R27 after a sync replaced the grant mirror (runtime spec §15).
|
|
20
|
+
* Resolves once streams are closed and the sweep's stops have started; stop
|
|
21
|
+
* completion and removal cascades continue as detached work. */
|
|
22
|
+
export declare function onGrantSync(before: readonly GrantRecord[], detach?: Detach): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var g=Object.defineProperty;var d=(o,r)=>g(o,"name",{value:r,configurable:!0});import{activeBackgroundBashJobs as x,readJobPgid as b}from"../bash-jobs.js";import{getNode as c,recordSettledTurn as w}from"../canvas/index.js";import{transition as S}from"../runtime/lifecycle.js";import{openDb as m}from"../canvas/db.js";import{contextDir as h}from"../canvas/node-agent-paths.js";import{emitEvent as u}from"../events/emit.js";import{closeGrantStreams as y}from"../runs/events.js";import{grantedMounts as E,isGrantedSource as P,mountAllowed as R}from"../spaces/mounts.js";import{permissionsForRun as v}from"../spaces/permissions.js";import{stopNodeSandboxes as k}from"../spaces/stop.js";import{activeGrantForApp as G,allGrants as M}from"./mirror.js";import{runRemovalCascades as A}from"./remove.js";import{launcherPresent as C,listSandboxes as D,stopSandboxPid as N}from"./sandboxes.js";function _(){return new Map(m().prepare("SELECT uid, app, status FROM app_users").all().map(o=>[o.uid,{app:o.app,status:o.status}]))}d(_,"appUserOwners");function O(o,r=_()){const n=r.get(o.uid);if(!n||n.app==="app:terminal")return null;if(n.status!=="active")return"app_removed";const a=c(o.nodeId);try{let t;if(a&&a.grantee===n.app)t=v(n.app,a.sub??"user:local",a.grant_id??null,a.scopes??null);else{const s=G(n.app);if(!s)return"permission_revoked";t=v(n.app,s.sub,s.id,null)}const e=E(t);return o.mounts.every(s=>!P(n.app,s.source)||R(s,e))?null:"permission_revoked"}catch{return"permission_revoked"}}d(O,"exceeds");async function T(o){const r=c(o);if(!r)return;(r.status==="active"||r.status==="idle")&&S(o,"release");const n=new Date().toISOString();w(o,n),r.run_id&&r.run_id!==o&&m().prepare("UPDATE nodes SET last_settled_at = COALESCE(last_settled_at, ?) WHERE node_id = ?").run(n,r.run_id)}d(T,"afterRevocationStop");function F(o){const r=new Set,n=c(o);n?.pi_pid!=null&&r.add(n.pi_pid);try{const a=h(o,n?.grantee);for(const t of x(a,!0)){const e=b(a,t.jobId);e!==void 0&&r.add(e)}}catch{}return r}d(F,"nodePids");async function I(){if(!C())return{completion:Promise.resolve()};const o=await D(),r=_(),n=o.flatMap(e=>{const s=O(e,r);return s?[{sandbox:e,reason:s}]:[]}),a=[],t=new Map;for(const e of n){u({level:"info",event:"daemon.grants.sandbox_stop",fields:{sandbox_node:e.sandbox.nodeId,pid:e.sandbox.pid,grantee:r.get(e.sandbox.uid).app,reason:e.reason}});const s=t.get(e.sandbox.nodeId)??[];s.push(e),t.set(e.sandbox.nodeId,s)}for(const[e,s]of t){const p=c(e),l=p?F(e):new Set,f=p!==null&&s.some(({sandbox:i})=>l.has(i.pid));a.push((async()=>{if(f){const i=await k(e,"permission_revoked",{holdRecovery:!0,after:d(()=>T(e),"after")});if(!i.confirmed)throw i.error??new Error(`stop of ${e} was not confirmed`)}for(const{sandbox:i}of s)(!f||!l.has(i.pid))&&await N(i.pid)})().catch(i=>{u({level:"error",event:"daemon.grants.sandbox_stop_failed",...p?{node_id:e}:{fields:{sandbox_node:e}},error:i})}))}return{completion:Promise.all(a).then(()=>{})}}d(I,"sweepSandboxes");async function Y(o,r=n=>{}){const n=M();for(const t of o){if(t.status!=="active"||n.find(p=>p.id===t.id)?.status==="active")continue;const s=y(t.id);s&&u({level:"info",event:"daemon.grants.streams_closed",fields:{grant:t.id,grantee:t.grantee,streams:s}})}try{const{completion:t}=await I();r(t)}catch(t){u({level:"error",event:"daemon.grants.sweep_failed",error:t})}const a=new Set(n.filter(t=>t.status==="removed"&&o.find(e=>e.id===t.id)?.status!=="removed").map(t=>t.grantee));r(A(a).catch(()=>{}))}d(Y,"onGrantSync");export{O as exceeds,Y as onGrantSync,I as sweepSandboxes};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Run the removal cascade for every `removed` grant whose app still has an
|
|
2
|
+
* active OS-user row, and once for each app in `transitions` (its grant became
|
|
3
|
+
* `removed` at this sync) even with no row. Serialized; each cascade is
|
|
4
|
+
* idempotent and marks the row `removed` last, so an interrupted one resumes. */
|
|
5
|
+
export declare function runRemovalCascades(transitions?: ReadonlySet<string>): Promise<void>;
|
|
6
|
+
/** Runtime spec §15 "On removal" (design flow 10). Audit and usage rows stay. */
|
|
7
|
+
export declare function removeApp(app: string): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var R=Object.defineProperty;var d=(r,i)=>R(r,"name",{value:i,configurable:!0});import{rmSync as S}from"node:fs";import{join as h}from"node:path";import{deleteNodes as w}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{removeTreeBeneath as N}from"../spaces/open-beneath.js";import{stopNodeSandboxes as L}from"../spaces/stop.js";import{activeAppUser as p,markAppUserRemoved as W}from"../spaces/users.js";import{launcherRequest as b}from"../../launcher/client.js";import{LaunchRefused as H}from"../../launcher/spec.js";import{allGrants as x}from"./mirror.js";import{launcherPresent as u,listSandboxes as A,stopSandboxPid as F}from"./sandboxes.js";let g=Promise.resolve();function V(r=new Set){const i=g.then(async()=>{const o=x(),n=new Set(o.filter(t=>t.status==="removed").map(t=>t.grantee));for(const t of n)if(!o.some(a=>a.grantee===t&&a.status==="active")&&!(p(t)===null&&!r.has(t)))try{await M(t)}catch(a){m({level:"error",event:"daemon.grants.removal_failed",error:a,fields:{grantee:t}})}});return g=i.catch(()=>{}),i}d(V,"runRemovalCascades");async function M(r){if(r==="app:terminal")throw new Error("app:terminal cannot be removed");const i=T(r),o=p(r);m({level:"info",event:"daemon.grants.removal_started",fields:{grantee:r,uid:o?.uid??null}});const n=c(e=>(e.prepare("UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE grantee = ?").run(new Date().toISOString(),r),e.prepare("SELECT node_id FROM nodes 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(n.map(e=>L(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(o&&u())for(const e of await A())e.uid===o.uid&&await F(e.pid);const v=n.filter(e=>f().prepare("SELECT run_id FROM nodes WHERE node_id = ?").get(e)?.run_id===e);c(e=>{if(!n.length)return;const s=n.map(()=>"?").join(","),_=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(...n,...n);e.prepare(`DELETE FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (${s})`).run(...n);for(const{message_id:l}of _)e.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(l,l)}),w(n);for(const e of v)D(e);if(S(h(C(),"env",i.root.slice(E().length+1)),{recursive:!0,force:!0}),N(E(),i.root),o&&u())try{await b({operation:"user.delete",uid:o.uid})}catch(e){if(!(e instanceof H&&e.refusal==="invalid_uid"))throw e}o&&W(o.uid),m({level:"info",event:"daemon.grants.removal_completed",fields:{grantee:r,uid:o?.uid??null,nodes:n.length}})}d(M,"removeApp");export{M as removeApp,V as runRemovalCascades};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type SandboxRecord } from '../../launcher/spec.js';
|
|
2
|
+
/** App sandboxes exist only where the root launcher runs (Linux). */
|
|
3
|
+
export declare function launcherPresent(): boolean;
|
|
4
|
+
/** Every live launcher sandbox with the mounts it was launched with. */
|
|
5
|
+
export declare function listSandboxes(): Promise<SandboxRecord[]>;
|
|
6
|
+
/** Kill one launcher sandbox. A pid the launcher no longer knows has already exited. */
|
|
7
|
+
export declare function stopSandboxPid(pid: number): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=Object.defineProperty;var r=(n,o)=>e(n,"name",{value:o,configurable:!0});import{existsSync as s}from"node:fs";import{launcherRequest as t}from"../../launcher/client.js";import{LAUNCHER_SOCKET as i,LaunchRefused as a}from"../../launcher/spec.js";function l(){return process.platform==="linux"&&s(i)}r(l,"launcherPresent");async function d(){const n=await t({operation:"list"});if(!("sandboxes"in n))throw new Error("launcher did not list sandboxes");return n.sandboxes}r(d,"listSandboxes");async function x(n){try{await t({operation:"stop",pid:n,signal:"SIGKILL"})}catch(o){if(!(o instanceof a&&o.refusal==="invalid_spec"))throw o}}r(x,"stopSandboxPid");export{l as launcherPresent,d as listSandboxes,x as stopSandboxPid};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Detach } from './on-sync.js';
|
|
2
|
+
export declare const GRANT_SYNC_INTERVAL_S = 300;
|
|
3
|
+
export type GrantSync = (options?: {
|
|
4
|
+
fresh?: boolean;
|
|
5
|
+
}) => Promise<void>;
|
|
6
|
+
/** Calls share one in-flight pull, including the start, periodic, and
|
|
7
|
+
* unknown-grant triggers. A `fresh` call (a directory sync notice) needs a pull
|
|
8
|
+
* that started after it arrived: while one is in flight it queues exactly one
|
|
9
|
+
* more, which every later fresh call shares. A pull resolves once the mirror is
|
|
10
|
+
* committed and the R26 stops have started; stop completion and removal
|
|
11
|
+
* cascades run as `detach`ed work. */
|
|
12
|
+
export declare function createGrantSync(issuer: string, detach?: Detach): GrantSync;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var w=Object.defineProperty;var s=(t,r)=>w(t,"name",{value:r,configurable:!0});import{createPrivateKey as k,randomUUID as h,sign as v}from"node:crypto";import{readFileSync as S}from"node:fs";import{join as j}from"node:path";import{crtrHome as E}from"../canvas/paths.js";import{emitEvent as u}from"../events/emit.js";import{allGrants as b,replaceGrants as A}from"./mirror.js";import{onGrantSync as $}from"./on-sync.js";const U=300;function T(t,r){const e=Math.floor(Date.now()/1e3),i=Buffer.from(JSON.stringify({alg:"ES256",typ:"JWT",kid:t.kid})).toString("base64url"),a=Buffer.from(JSON.stringify({iss:t.client_id,sub:t.client_id,aud:r,iat:e,exp:e+300,jti:h()})).toString("base64url"),o=`${i}.${a}`,p=v("sha256",Buffer.from(o),{key:k({key:t.jwk,format:"jwk"}),dsaEncoding:"ieee-p1363"});return`${o}.${p.toString("base64url")}`}s(T,"assertion");function N(){const t=JSON.parse(S(j(E(),"secrets","runtime-client.json"),"utf8"));if(!t.jwk||t.alg!=="ES256"||!t.kid||!t.client_id||!t.runtime||t.jwk.kid!==t.kid||t.jwk.kty!=="EC"||t.jwk.crv!=="P-256"||!t.jwk.d)throw new TypeError("invalid runtime client key");return t}s(N,"runtimeClient");function G(t,r){if(!t||typeof t!="object")throw new TypeError("invalid grant sync response");const e=t;if(e.runtime!==(r.runtime.startsWith("runtime:")?r.runtime:`runtime:${r.runtime}`)||typeof e.id!="string"||typeof e.sub!="string"||typeof e.grantee!="string"||!Number.isInteger(e.rev)||!Array.isArray(e.scopes)||!Array.isArray(e.resolved_scopes)||!["active","revoked","removed"].includes(e.status??"")||typeof e.synced_at!="string")throw new TypeError("invalid grant sync response");const a=t.revisions?.find(o=>o.rev===e.rev)?.approved_at;if(typeof a!="string")throw new TypeError("grant revision has no approval time");return{...e,spend_cap:e.spend_cap??null,expires_at:e.expires_at??null,revoked_at:e.revoked_at??null,approved_at:a,payer:"user"}}s(G,"responseGrant");function q(t,r=e=>{}){let e;const i=t.replace(/\/$/,""),a=s(async()=>{const n=N(),d=`${i}/token`,g=new URLSearchParams({grant_type:"client_credentials",client_id:n.client_id,client_assertion_type:"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",client_assertion:T(n,d)}),f=await fetch(d,{method:"POST",body:g,signal:AbortSignal.timeout(1e4)});if(!f.ok)throw new Error(`directory token request failed: ${f.status}`);const m=await f.json();if(typeof m.access_token!="string")throw new TypeError("directory token response has no access_token");const y=await fetch(`${i}/v1/runtime/grants`,{headers:{Authorization:`Bearer ${m.access_token}`},signal:AbortSignal.timeout(1e4)});if(!y.ok)throw new Error(`directory grant sync failed: ${y.status}`);const c=await y.json();if(!Array.isArray(c.grants)||typeof c.synced_at!="string")throw new TypeError("invalid grant sync response");const _=b();A(c.grants.map(l=>G(l,n)),c.synced_at,i),u({level:"info",event:"daemon.grants.synced",fields:{grants:c.grants.length,synced_at:c.synced_at}});try{await $(_,r)}catch(l){u({level:"error",event:"daemon.grants.on_sync_failed",error:l})}},"run");let o;const p=s(()=>{const n=a().catch(d=>{throw u({level:"error",event:"daemon.grants.sync_failed",error:d}),d}).finally(()=>{e===n&&(e=void 0)});return e=n,n},"start");return(n={})=>e?n.fresh?(o??=e.catch(()=>{}).then(()=>(o=void 0,e??p())),o):e:p()}s(q,"createGrantSync");export{U as GRANT_SYNC_INTERVAL_S,q as createGrantSync};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { MemoryExtensionDeclaration } from '../../types.js';
|
|
2
|
+
/** Render the daemon's bounded declaration catalog without opening a memory store in the CLI. */
|
|
3
|
+
export declare function memoryExtensionFieldCatalogHelp(operation: 'write' | 'edit', catalog: Record<string, Record<string, MemoryExtensionDeclaration>>): string | null;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var m=Object.defineProperty;var s=(e,l)=>m(e,"name",{value:l,configurable:!0});import{stateBlock as a}from"../help.js";function c(e){return e.type!=="enum"?e.type:`enum (${e.values.join("|")})`}s(c,"declarationValueDescription");function d(e){return typeof e=="string"?JSON.stringify(e):String(e)}s(d,"extensionHelpValue");function g(e,l){const o=Object.entries(l).flatMap(([n,i])=>Object.entries(i).map(([t,u])=>({namespace:n,field:t,declaration:u}))).sort((n,i)=>`${n.namespace}.${n.field}`.localeCompare(`${i.namespace}.${i.field}`));if(o.length===0)return null;const r=50,f=o.slice(0,r).map(({namespace:n,field:i,declaration:t})=>{const u=t.default===void 0?"":`; default ${d(t.default)}`,p=e==="write"?t.write_help:t.edit_help;return`- \`extensions.${n}.${i}\` \u2014 ${c(t)}${u}. ${p}`});return o.length>r&&f.push(`- ${o.length-r} additional declared fields omitted from help.`),a("memory-extension-fields",{count:o.length},f.join(`
|
|
2
|
+
`))}s(g,"memoryExtensionFieldCatalogHelp");export{g as memoryExtensionFieldCatalogHelp};
|
package/dist/core/help.d.ts
CHANGED
|
@@ -60,6 +60,9 @@ export interface FlagParam {
|
|
|
60
60
|
* deliberately-undiscoverable confirmation gate the agent must be TOLD about
|
|
61
61
|
* in the command's own output (not by reading the schema), never advertised. */
|
|
62
62
|
hidden?: boolean;
|
|
63
|
+
/** The value is a secret. Parse errors for the leaf then withhold every stray
|
|
64
|
+
* argv value, since a mistyped invocation is how a secret lands in one. */
|
|
65
|
+
sensitive?: boolean;
|
|
63
66
|
/** Local-file materialization contract, valid only on a `path` flag — see
|
|
64
67
|
* PositionalParam.encoding. */
|
|
65
68
|
encoding?: FileEncoding;
|
|
@@ -252,6 +255,17 @@ export interface LeafHelp {
|
|
|
252
255
|
export type EffectiveLeafHelp = Readonly<Omit<LeafHelp, 'effects'> & {
|
|
253
256
|
effects: readonly string[];
|
|
254
257
|
}>;
|
|
258
|
+
/** State elements a leaf reads asynchronously (e.g. from the daemon) when its
|
|
259
|
+
* help renders: `leaf` stands in for `dynamicState`, `flags` for a named
|
|
260
|
+
* flag's `focusedHelp.dynamicState`. */
|
|
261
|
+
export interface AsyncHelpState {
|
|
262
|
+
leaf?: () => Promise<string>;
|
|
263
|
+
flags?: Readonly<Record<string, () => Promise<string>>>;
|
|
264
|
+
}
|
|
265
|
+
/** `help` with the async state the render shows read once: the leaf's for
|
|
266
|
+
* ordinary help, only `focusedFlag`'s for focused help. A read that throws
|
|
267
|
+
* renders no element, the same soft failure `evalDynamic` gives a sync one. */
|
|
268
|
+
export declare function withAsyncHelpState(help: LeafHelp, state: AsyncHelpState, focusedFlag?: string): Promise<LeafHelp>;
|
|
255
269
|
/** Build a self-named runtime-state element: `<tag attr="v">body</tag>`. The
|
|
256
270
|
* subtree that owns the state authors it through this, so the tag name and any
|
|
257
271
|
* scalar metadata (e.g. a count) travel with the data and render identically
|
package/dist/core/help.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var g=Object.defineProperty;var i=(e,n)=>g(e,"name",{value:n,configurable:!0});function
|
|
1
|
+
var g=Object.defineProperty;var i=(e,n)=>g(e,"name",{value:n,configurable:!0});async function N(e,n,t){const s=i(async r=>{try{const a=await r();return()=>a}catch{return()=>null}},"read"),o=t===void 0?void 0:n.flags?.[t],u=new Map(o===void 0?[]:[[t,await s(o)]]);return{...e,...t===void 0&&n.leaf!==void 0?{dynamicState:await s(n.leaf)}:{},params:e.params?.map(r=>{const a=r.kind==="flag"?u.get(r.name):void 0;return r.kind==="flag"&&r.focusedHelp!==void 0&&a!==void 0?{...r,focusedHelp:{...r.focusedHelp,dynamicState:a}}:r})}}i(N,"withAsyncHelpState");function C(e,n,t){const s=Object.entries(n).map(([o,u])=>` ${o}="${u}"`).join("");return`<${e}${s}>
|
|
2
2
|
${t}
|
|
3
|
-
</${e}>`}i(
|
|
3
|
+
</${e}>`}i(C,"stateBlock");function l(e){if(e===void 0)return null;try{const n=e();return n!==null&&n!==""?n:null}catch{return null}}i(l,"evalDynamic");function p(e){let n=0;for(const t of e)t.length>n&&(n=t.length);return n}i(p,"maxLen");function m(e,n){return e+" ".repeat(Math.max(0,n-e.length))}i(m,"pad");const b=`I/O contract: flags and positional args on input; stdout is agent-ready markdown/XML you
|
|
4
4
|
act on directly \u2014 read it as a continuation of your prompt, don't parse it as data.
|
|
5
|
-
Exit 0 on success, non-zero on failure. Schemas appear at leaf -h; a leaf may route an uncommon flag to focused --flag -h guidance.`,y="Before running a crtr command that changes state \u2014 creates, mutates, or deletes anything \u2014 whose exact contract (args, flags, effects) you haven't verified this session, run `-h` on it and read the schema first \u2014 a reliable read beats a guess that wastes a turn or triggers an unintended effect. When a leaf routes a flag to focused help, read that focused help before using the flag; the compact row is discovery, not its invocation contract. Same when the user names a capability you don't fully recognize: `-h` it before acting.";function x(e){const n=e.subcommands??[],t=e.otherSubcommandCount??0;if(n.length===0&&t===0)return[];const s=[];if(n.length>0){const
|
|
6
|
-
`)}i(
|
|
7
|
-
`)}i(I,"renderBranch");function
|
|
8
|
-
`)}if(e.guide!==void 0&&(t.push(""),t.push(e.guide)),t.push(""),s.length>0){t.push("Input");const
|
|
9
|
-
`)}i(
|
|
5
|
+
Exit 0 on success, non-zero on failure. Schemas appear at leaf -h; a leaf may route an uncommon flag to focused --flag -h guidance.`,y="Before running a crtr command that changes state \u2014 creates, mutates, or deletes anything \u2014 whose exact contract (args, flags, effects) you haven't verified this session, run `-h` on it and read the schema first \u2014 a reliable read beats a guess that wastes a turn or triggers an unintended effect. When a leaf routes a flag to focused help, read that focused help before using the flag; the compact row is discovery, not its invocation contract. Same when the user names a capability you don't fully recognize: `-h` it before acting.";function x(e){const n=e.subcommands??[],t=e.otherSubcommandCount??0;if(n.length===0&&t===0)return[];const s=[];if(n.length>0){const o=p(n.map(u=>u.path));for(const u of n)s.push(u.desc!==void 0&&u.desc!==""?` ${m(u.path,o)} ${u.desc}`:` ${u.path}`)}if(t>0){const o=n.length>0?"other subcommand":"subcommand";s.push(` [+${t} ${o}${t===1?"":"s"} \u2014 \`crtr ${e.name} -h\`]`)}return s}i(x,"rootSubcommandLines");function H(e){const n=[];n.push(`${e.tagline}`),n.push("");for(const t of e.commands){n.push(`<command name="${t.name}">`),n.push(t.concept),n.push(`use when ${t.useWhen}`);for(const o of x(t))n.push(o);const s=l(t.dynamicState);s!==null&&n.push(s),n.push("</command>"),n.push("")}if(e.globals.length>0){n.push("Globals");const t=p(e.globals.map(s=>s.name));for(const s of e.globals)n.push(` ${m(s.name,t)} ${s.desc}`);n.push("")}return n.push(b),n.push(""),n.push(y),n.join(`
|
|
6
|
+
`)}i(H,"renderRoot");function d(e){return e.replace(/"/g,"'")}i(d,"attr");function I(e){const n=[];n.push(`<command name="${e.name}" description="${d(e.summary)}">`);const t=l(e.dynamicState);t!==null&&n.push(t),e.model!==void 0&&n.push(e.model);for(const s of e.listing??[]){if(s.tier==="hidden")continue;const o=s.plugin===void 0?"":` plugin="${d(s.plugin)}"`,u=s.subCount!==void 0&&s.subCount>0?` subcommands="${s.subCount}"`:"";n.length>1&&n.push(""),n.push(`<subcommand name="${s.name}" description="${d(s.description)}" whenToUse="${d(s.whenToUse)}"${o}${u}/>`)}return e.extensionIssue!==void 0&&n.push(`<extension-issue fragment="${d(e.extensionIssue.fragment)}">This repository's contributed commands were rejected: ${e.extensionIssue.message}. Run \`crtr sys doctor\` for the full report.</extension-issue>`),n.push("</command>"),n.join(`
|
|
7
|
+
`)}i(I,"renderBranch");function w(e){if(e.kind==="positional")return`${e.name.toUpperCase()}${e.repeatable===!0?"...":""}`;if(e.kind==="stdin")return"stdin";if(e.kind==="context-file")return"--context-file PATH";const n=e;return n.type==="bool"?`--${n.name}`:`--${n.name} ${n.name.toUpperCase().replace(/-/g,"_")}`}i(w,"paramLabel");function h(e){return e===void 0?"":e==="base64"?" Local file path: the file is read and its raw bytes are base64-encoded into the request; the path itself is never sent.":" Local file path: the file is read as UTF-8 text and its content is sent as the value; the path itself is never sent."}i(h,"fileEncodingNote");function $(e){return e===void 0?"":` Defaults to $${e} when that is set and non-empty in the environment, and counts as supplied.`}i($,"envDefaultNote");function S(e,n){return e.focusedHelp===void 0?"":` Before using this flag, run \`crtr ${n} --${e.name} -h\` and read its focused guidance.`}i(S,"focusedFlagHelpNote");function v(e,n){const t=e.required?"required":"optional";if(e.kind==="positional"){const c=e.repeatable===!0?" Repeatable \u2014 pass multiple values to accumulate in argv order.":"";return`positional, ${t}.${h(e.encoding)}${$(e.defaultFromEnv)} ${e.constraint}${c}`}if(e.kind==="stdin")return`${t}. ${e.constraint}`;if(e.kind==="context-file"){const c=e.shape!==void 0?` Shape: ${e.shape}`:"";return`${t}. Path to a JSON file.${c} ${e.constraint}`.trim()}const s=e,o=S(s,n);if(s.type==="bool")return`${t} boolean. Presence means true. ${s.constraint}${o}`.trim();const u=s.default!==void 0?` Default: ${String(s.default)}.`:"",r=s.type==="enum"&&s.choices!==void 0?` One of: ${s.choices.join(", ")}.`:"",a=s.repeatable===!0?" Repeatable \u2014 pass multiple times to accumulate.":"";return`${s.type}, ${t}.${r}${u}${h(s.encoding)}${$(s.defaultFromEnv)} ${s.constraint}${a}${o}`.trim()}i(v,"paramDesc");function L(e,n){const t=[`${e.name}: ${e.summary}.`],s=(e.params??[]).filter(a=>!(a.kind==="flag"&&a.hidden===!0)),o=n===void 0?void 0:s.find(a=>a.kind==="flag"&&a.name===n&&a.focusedHelp!==void 0);if(o?.focusedHelp!==void 0){const a=o.focusedHelp;if(t.push(""),t.push(`<parameter name="${o.name}">`),t.push("When to use"),t.push(` ${a.whenToUse}`),t.push(""),t.push("Value"),t.push(` ${a.value}`),(a.effects??[]).length>0){t.push(""),t.push("Effects");for(const f of a.effects??[])t.push(` ${f}`)}const c=l(a.dynamicState);return c!==null&&(t.push(""),t.push(c)),t.push("</parameter>"),t.join(`
|
|
8
|
+
`)}if(e.guide!==void 0&&(t.push(""),t.push(e.guide)),t.push(""),s.length>0){t.push("Input");const a=s.map(w),c=p(a);for(let f=0;f<s.length;f++)t.push(` ${m(a[f],c)} ${v(s[f],e.name)}`)}else t.push(e.inputNote!==void 0?e.inputNote:"No input parameters.");t.push(""),t.push("Output (fields carried in the rendered result)");const u=p(e.output.map(a=>a.name));for(const a of e.output)t.push(` ${m(a.name,u)} ${a.type}. ${a.constraint}`);t.push(""),t.push("Effects");for(const a of e.effects)t.push(` ${a}`);const r=l(e.dynamicState);return r!==null&&(t.push(""),t.push(r)),t.join(`
|
|
9
|
+
`)}i(L,"renderLeafArgv");export{I as renderBranch,L as renderLeafArgv,H as renderRoot,C as stateBlock,N as withAsyncHelpState};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var
|
|
1
|
+
var s=Object.defineProperty;var t=(r,n)=>s(r,"name",{value:n,configurable:!0});import{homedir as e}from"node:os";import{join as o}from"node:path";import{collectSlashSpecs as c}from"../command.js";import{piAgentDir as l}from"../runtime/package-health.js";const u="<!-- crtr-mode-cmd v1 -->",a="<!-- crtr-mode-cmd v";function m(r){const n=r.argumentHint!==void 0?`argument-hint: ${JSON.stringify(r.argumentHint)}
|
|
2
2
|
`:"";return`---
|
|
3
3
|
description: ${r.description}
|
|
4
4
|
${n}---
|
|
5
5
|
|
|
6
|
-
${
|
|
6
|
+
${u}
|
|
7
7
|
|
|
8
8
|
${r.body}
|
|
9
|
-
`}t(
|
|
9
|
+
`}t(m,"renderSlashTemplate");function d(){return o(e(),".claude","skills")}t(d,"claudeSkillsRoot");function p(){return o(l(),"skills")}t(p,"piSkillsRoot");function f(){return o(e(),".claude","commands")}t(f,"claudeCommandsRoot");function R(){return o(l(),"prompts")}t(R,"piPromptsRoot");const S="<!-- crtr-boot-skill v";function A(){return[{id:"@legacy/crtr-skills",name:"crtr-skills",markerPrefix:S,targets:[{host:"claude",dir:d,layout:"bundle"},{host:"pi",dir:p,layout:"bundle"}]}]}t(A,"legacyExportArtifacts");function E(r){const n=[];for(const i of c(r))n.push({id:`@cmd/${i.name}`,name:i.name,markerPrefix:a,render:t(()=>m(i),"render"),targets:[{host:"claude",dir:f,layout:"file"},{host:"pi",dir:R,layout:"file"}]});return n}t(E,"builtinExportPairs");export{a as SLASH_CMD_MARKER_PREFIX,E as builtinExportPairs,A as legacyExportArtifacts};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
`)}}o(
|
|
3
|
-
`)}}o(
|
|
1
|
+
var g=Object.defineProperty;var o=(r,t)=>g(r,"name",{value:t,configurable:!0});import{writeFileSync as x}from"node:fs";import{homedir as l}from"node:os";import{piAgentDir as S}from"../runtime/package-health.js";import{dirname as u,join as s}from"node:path";import{ensureDir as h,pathExists as i,readText as c,removePath as v}from"../fs-utils.js";import{envNoExports as m}from"../../shared/env.js";import{builtinExportPairs as E,legacyExportArtifacts as y}from"./builtins.js";const A=new Set(["help","--help","-h","--version","-v"]);function a(r){const t=r[2];return t!==void 0&&A.has(t)}o(a,"shouldSkipAllForArgv");function P(r){return r[2]===void 0}o(P,"shouldSkipWritesForArgv");function p(r){return r==="claude"?i(s(l(),".claude")):i(S())}o(p,"hostRootExists");function d(r,t){const e=r.dir();return r.layout==="bundle"?s(e,t,"SKILL.md"):s(e,`${t}.md`)}o(d,"targetPath");function w(r,t,e){if(i(r)){const n=c(r);if(!n.includes(e)||n===t)return}h(u(r)),x(r,t,"utf8")}o(w,"writeIfOurs");function b(r,t,e){!i(r)||!c(r).includes(e)||v(t.layout==="bundle"?u(r):r)}o(b,"removeIfOurs");function M(r=process.argv){try{if(m()||a(r))return;for(const t of y())for(const e of t.targets)p(e.host)&&b(d(e,t.name),e,t.markerPrefix)}catch(t){const e=t instanceof Error?t.message:String(t);process.stderr.write(`crtr: exports prune error: ${e}
|
|
2
|
+
`)}}o(M,"pruneLegacyExports");function N(r,t=process.argv){try{if(m()||a(t)||P(t))return;for(const e of E(r)){const n=e.render();for(const f of e.targets)p(f.host)&&w(d(f,e.name),n,e.markerPrefix)}}catch(e){const n=e instanceof Error?e.message:String(e);process.stderr.write(`crtr: exports error: ${n}
|
|
3
|
+
`)}}o(N,"provisionExports");export{N as provisionExports,M as pruneLegacyExports,w as writeIfOurs};
|
|
@@ -13,6 +13,8 @@ export interface TicketActionBinding {
|
|
|
13
13
|
argv: string[];
|
|
14
14
|
/** Fully resolved absolute working directory. */
|
|
15
15
|
cwd: string;
|
|
16
|
+
/** Originating app, retained when its node is later deleted. */
|
|
17
|
+
app?: string;
|
|
16
18
|
}
|
|
17
19
|
/** Publish the binding before the page exists, so a visible request is never
|
|
18
20
|
* unbound. A second write is a caller bug, not a race to tolerate. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=Object.defineProperty;var t=(r,i)=>e(r,"name",{value:i,configurable:!0});import{readFileSync as c}from"node:fs";import{z as n}from"zod";import{actionBindingPath as o,publishJsonExclusive as s}from"./convention.js";const
|
|
1
|
+
var e=Object.defineProperty;var t=(r,i)=>e(r,"name",{value:i,configurable:!0});import{readFileSync as c}from"node:fs";import{z as n}from"zod";import{actionBindingPath as o,publishJsonExclusive as s}from"./convention.js";const p=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,d=n.object({schema:n.literal("crtr.human-action-binding/v1"),name:n.string().regex(p),payload:n.unknown(),creatorCwd:n.string().min(1),configOrigin:n.string().min(1),argv:n.array(n.string().min(1)).min(1),cwd:n.string().min(1),app:n.string().min(1).optional()}).strict();function h(r,i){if(!s(o(r),i))throw new Error(`action binding already exists: ${o(r)}`)}t(h,"publishTicketActionBinding");function A(r){let i;try{i=JSON.parse(c(o(r),"utf8"))}catch(a){if(a.code==="ENOENT")return null;throw a}return{...d.parse(i),payload:i.payload??null}}t(A,"readTicketActionBinding");export{p as HUMAN_ACTION_NAME_PATTERN,h as publishTicketActionBinding,A as readTicketActionBinding};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export declare function feedbackCompanionBranchPath(dir: string): string;
|
|
2
1
|
/** Hex sha256 of the ticket's page document, recorded at first comment so the
|
|
3
2
|
* settle-time completion can say whether the page changed during feedback. */
|
|
4
3
|
export declare function pageDocumentSha256(dir: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var f=Object.defineProperty;var i=(e,o)=>f(e,"name",{value:o,configurable:!0});import{createHash as l}from"node:crypto";import{readFileSync as s}from"node:fs";import{getNode as u}from"../canvas/index.js";import{awaitCompanionBind as w,captureOrigin as h}from"../review/companion.js";import{COMPANION_BIND_DEADLINE_MS as t}from"../review/types.js";import{buildLaunchSpec as _}from"../runtime/launch.js";import{transition as k}from"../runtime/lifecycle.js";import{headlessBrokerHost as N}from"../runtime/host.js";import{spawnNode as b}from"../runtime/nodes.js";import{reviveNode as I}from"../runtime/revive.js";import{materializeSessionBranch as x}from"../runtime/session-branch.js";import{initializeForkContextExposure as F}from"../substrate/injected-store.js";import{pagePath as a}from"./convention.js";import{selectedPageDir as c}from"./tickets.js";function L(e){return l("sha256").update(s(a(c(e),"jsx"))).digest("hex")}i(L,"pageDocumentSha256");function S(e){try{k(e,"cancel",{reason:"retired"}),N.teardown(e)}catch{}}i(S,"discardFeedbackCompanion");async function q(e){const o=u(e.senderNodeId);if(o===null)throw new Error(`page sender was not found: ${e.senderNodeId}`);const d=await h(e.senderNodeId),n=x(d),{launch:m}=_(o.kind,o.mode,{lifecycle:"resident",hasManager:!1,model:d.modelSpec,modelExact:!0,cwd:o.cwd,profileId:o.profile_id??null}),r=await b({kind:o.kind,mode:o.mode,lifecycle:"resident",cwd:o.cwd,profile_id:o.profile_id??null,parent:e.senderNodeId,creator:e.senderNodeId,subscribe:!1,forkFrom:n,forkSourceFile:n,modelOverride:d.modelSpec,reviewBinding:{kind:"page_feedback",review_id:e.ticketId,origin_node_id:e.senderNodeId,branch_file:n,target_file:a(c(e.dir),"jsx")},name:`Feedback \xB7 ${e.title}`,launch:m});try{if(F(r.node_id,e.senderNodeId),await I(r.node_id,{resume:!1,capacity:"refuse"}),!await w(r.node_id,t))throw new Error(`feedback companion did not bind within ${t}ms`)}catch(p){throw S(r.node_id),p}return r.node_id}i(q,"realizeFeedbackCompanion");export{S as discardFeedbackCompanion,L as pageDocumentSha256,q as realizeFeedbackCompanion};
|
|
@@ -186,8 +186,8 @@ export declare const chartDataRowsSchema: z.ZodArray<z.ZodRecord<z.ZodString, z.
|
|
|
186
186
|
export declare const chartConfigSchema: z.ZodObject<{
|
|
187
187
|
kind: z.ZodEnum<{
|
|
188
188
|
line: "line";
|
|
189
|
-
bar: "bar";
|
|
190
189
|
area: "area";
|
|
190
|
+
bar: "bar";
|
|
191
191
|
}>;
|
|
192
192
|
x: z.ZodString;
|
|
193
193
|
y: z.ZodArray<z.ZodObject<{
|
|
@@ -31,6 +31,8 @@ export interface InspectorState {
|
|
|
31
31
|
expanded: boolean;
|
|
32
32
|
pendingCancel: PendingAction | null;
|
|
33
33
|
scroll: Record<InspectorSection, number>;
|
|
34
|
+
/** Opened with `--read-only`: the keymap offers no cron cancel or job stop. */
|
|
35
|
+
readOnly: boolean;
|
|
34
36
|
}
|
|
35
37
|
export declare const inspectorCore: InspectorCore<InspectorState>;
|
|
36
38
|
export declare function selectedJob(state: InspectorState): BashJobRow | undefined;
|