@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
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
var r=Object.defineProperty;var T=(E
|
|
1
|
+
var r=Object.defineProperty;var T=(e,E)=>r(e,"name",{value:E,configurable:!0});const n=3,a=1,_=`
|
|
2
2
|
CREATE TABLE scope_owners (owner_key TEXT PRIMARY KEY, kind TEXT NOT NULL CHECK(kind IN ('user','profile','project')), root TEXT NOT NULL UNIQUE, profile_id TEXT UNIQUE);
|
|
3
|
-
CREATE TABLE profiles (id TEXT PRIMARY KEY, name TEXT NOT NULL, created_at TEXT NOT NULL, last_used_at TEXT, paused_at TEXT,
|
|
3
|
+
CREATE TABLE profiles (id TEXT PRIMARY KEY, name TEXT NOT NULL, created_at TEXT NOT NULL, last_used_at TEXT, paused_at TEXT, default_kind TEXT, grantee TEXT, metadata_json TEXT NOT NULL CHECK(json_valid(metadata_json)));
|
|
4
4
|
CREATE TABLE profile_projects (profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE, path TEXT NOT NULL, position INTEGER NOT NULL, memory TEXT NOT NULL CHECK(memory IN ('none','name','preview','content')), PRIMARY KEY(profile_id,path), UNIQUE(profile_id,position));
|
|
5
5
|
CREATE TABLE profile_defaults (directory TEXT PRIMARY KEY, profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE);
|
|
6
6
|
CREATE TABLE scope_settings (owner_key TEXT PRIMARY KEY REFERENCES scope_owners(owner_key), raw_json TEXT NOT NULL CHECK(json_valid(raw_json)));
|
|
7
7
|
CREATE TABLE scope_bookkeeping (owner_key TEXT PRIMARY KEY REFERENCES scope_owners(owner_key), last_self_check TEXT, active_canvas TEXT);
|
|
8
8
|
CREATE TABLE scope_marketplaces (owner_key TEXT NOT NULL REFERENCES scope_owners(owner_key), name TEXT NOT NULL, last_updated TEXT, PRIMARY KEY(owner_key,name));
|
|
9
|
-
CREATE TABLE scope_plugins (owner_key TEXT NOT NULL REFERENCES scope_owners(owner_key), name TEXT NOT NULL, last_updated TEXT, etag TEXT, checked_at TEXT, PRIMARY KEY(owner_key,name));`,
|
|
9
|
+
CREATE TABLE scope_plugins (owner_key TEXT NOT NULL REFERENCES scope_owners(owner_key), name TEXT NOT NULL, last_updated TEXT, etag TEXT, checked_at TEXT, PRIMARY KEY(owner_key,name));`,N=`
|
|
10
10
|
CREATE TABLE managed_accounts (provider_id TEXT NOT NULL, id TEXT NOT NULL, label TEXT NOT NULL, label_key TEXT NOT NULL, position INTEGER NOT NULL, last_attempt_at INTEGER NOT NULL, last_rate_limited_at INTEGER NOT NULL, rate_limited_until INTEGER NOT NULL, auth_failure TEXT CHECK(auth_failure IS NULL OR auth_failure='invalid_grant'), PRIMARY KEY(provider_id,id), UNIQUE(provider_id,label_key));
|
|
11
11
|
CREATE INDEX managed_accounts_order ON managed_accounts(provider_id,position);
|
|
12
12
|
CREATE TABLE rotation_settings (singleton INTEGER PRIMARY KEY CHECK(singleton=1), default_fallback_strength TEXT, revert_when_available INTEGER CHECK(revert_when_available IN (0,1)));
|
|
13
|
-
CREATE TABLE provider_revision (singleton INTEGER PRIMARY KEY CHECK(singleton=1), revision INTEGER NOT NULL);`;function
|
|
13
|
+
CREATE TABLE provider_revision (singleton INTEGER PRIMARY KEY CHECK(singleton=1), revision INTEGER NOT NULL);`;function t(e,E){if(e.exec(E==="provider"?N:_),E!=="provider"){const o=E==="user"?"user":"project";e.prepare("INSERT INTO scope_owners(owner_key, kind, root, profile_id) VALUES (?, ?, ?, NULL)").run(o,E,"")}else e.prepare("INSERT INTO provider_revision(singleton, revision) VALUES (1, 0)").run();e.exec(`PRAGMA user_version = ${E==="provider"?1:3}`)}T(t,"createScopedSchema");export{a as PROVIDER_SCHEMA_VERSION,n as SCOPED_SCHEMA_VERSION,t as createScopedSchema};
|
package/dist/core/scopes.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { scopeAllowed } from '../shared/env.js';
|
|
2
2
|
export { scopeAllowed };
|
|
3
|
-
/** The scopes
|
|
4
|
-
export declare const SCOPE_VOCABULARY: readonly ["
|
|
3
|
+
/** The scopes an unrestricted local terminal run presents to the document substrate. */
|
|
4
|
+
export declare const SCOPE_VOCABULARY: readonly ["crtr:llm", "crtr:act", "crtr:schedule", "crtr:memory:rw:user", "crtr:memory:manage:user", "crtr:files:rw:user:."];
|
|
5
5
|
/** Reject unknown scope strings before they can silently change an allow-list. */
|
|
6
6
|
export declare function validateScopes(value: unknown): string[];
|
|
7
7
|
export declare function assertScope(meta: {
|
package/dist/core/scopes.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var c=Object.defineProperty;var o=(e,r)=>c(e,"name",{value:r,configurable:!0});import{parseScope as i}from"@north-light/crouter-identity";import{scopeAllowed as t}from"../shared/env.js";import{InputError as n}from"./io.js";const w=["crtr:llm","crtr:act","crtr:schedule","crtr:memory:rw:user","crtr:memory:manage:user","crtr:files:rw:user:."];function h(e){if(!Array.isArray(e))throw new n({error:"unknown_scope",message:"scopes must be a list",received:e,field:"scopes",next:"Pass identity scope strings."});for(const r of e)try{if(typeof r!="string")throw new TypeError("scope is not a string");i(r)}catch{throw new n({error:"unknown_scope",message:`unknown scope: ${String(r)}`,received:r,field:"scopes",next:"Pass identity scope strings."})}return[...e]}o(h,"validateScopes");function u(e,r){if(!t(e.scopes,r))throw new p(`node ${e.node_id}`,r)}o(u,"assertScope");class p extends Error{static{o(this,"ScopeDeniedError")}holder;scope;constructor(r,s){super(`${r} does not hold the ${s} scope`),this.holder=r,this.scope=s,this.name="ScopeDeniedError"}}export{w as SCOPE_VOCABULARY,p as ScopeDeniedError,u as assertScope,t as scopeAllowed,h as validateScopes};
|
package/dist/core/secrets.d.ts
CHANGED
package/dist/core/secrets.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
`,{mode:384}),
|
|
1
|
+
var f=Object.defineProperty;var t=(e,o)=>f(e,"name",{value:o,configurable:!0});import{createHash as u}from"node:crypto";import{existsSync as y,readFileSync as d,writeFileSync as l,chmodSync as A}from"node:fs";import{join as m}from"node:path";import{scopeRoot as S,requireScopeRoot as g,userScopeRoot as a}from"./scope.js";import{secretsDir as k}from"./layout.js";import{ensureDir as x}from"./fs-utils.js";const h="secrets.json";function T(e){return m(e===a()?k():e,h)}t(T,"secretsPathFor");function s(e){const o=S(e);if(!o)return{relayTokens:{}};const n=T(o);if(!y(n))return{relayTokens:{}};try{const r=JSON.parse(d(n,"utf8")),c=Array.isArray(r.scopedApiTokens)?r.scopedApiTokens.filter(i=>typeof i?.token=="string"&&i.token!==""&&typeof i.grantee=="string"&&/^app:[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(i.grantee)&&Array.isArray(i.scopes)&&typeof i.created=="string"):[];return{relayTokens:r.relayTokens??{},...typeof r.apiToken=="string"&&r.apiToken!==""?{apiToken:r.apiToken}:{},...c.length>0?{scopedApiTokens:c}:{}}}catch{return{relayTokens:{}}}}t(s,"readSecrets");function p(e,o){const n=g(e),r=T(n);x(n===a()?k():n),l(r,JSON.stringify(o,null,2)+`
|
|
2
|
+
`,{mode:384}),A(r,384)}t(p,"writeSecrets");function J(e,o){return s(o).relayTokens[e]}t(J,"getRelayToken");function N(e,o,n){const r=s(n);r.relayTokens[e]=o,p(n,r)}t(N,"setRelayToken");function O(e,o){const n=s(o);delete n.relayTokens[e],p(o,n)}t(O,"deleteRelayToken");function Z(e){return s(e).apiToken}t(Z,"getApiToken");function _(e,o){const n=s(o);n.apiToken=e,p(o,n)}t(_,"setApiToken");function q(e){return s(e).scopedApiTokens??[]}t(q,"listScopedApiTokens");function C(e,o){const n=s(o);n.scopedApiTokens=[...n.scopedApiTokens??[],e],p(o,n)}t(C,"addScopedApiToken");function H(e){return u("sha256").update(e).digest("hex").slice(0,12)}t(H,"fingerprint");export{C as addScopedApiToken,O as deleteRelayToken,H as fingerprint,Z as getApiToken,J as getRelayToken,q as listScopedApiTokens,s as readSecrets,_ as setApiToken,N as setRelayToken,p as writeSecrets};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type RunPermissions } from './permissions.js';
|
|
2
|
+
import type { LaunchSpec } from '../../launcher/spec.js';
|
|
3
|
+
export interface LaunchNode {
|
|
4
|
+
nodeId: string;
|
|
5
|
+
app: string;
|
|
6
|
+
sub: string;
|
|
7
|
+
grantId: string | null;
|
|
8
|
+
scopes: string[] | null;
|
|
9
|
+
command: string[];
|
|
10
|
+
env: Record<string, string>;
|
|
11
|
+
/** No node exists for this app process (e.g. an unanchored cron). */
|
|
12
|
+
withoutNode?: boolean;
|
|
13
|
+
cwd?: string;
|
|
14
|
+
/** Hook code alone may be mounted from the installed plugin root, read-only. */
|
|
15
|
+
pluginRoot?: string;
|
|
16
|
+
/** Missing granted directories are omitted and reported to the daemon. */
|
|
17
|
+
auditMissing: (source: string) => void;
|
|
18
|
+
}
|
|
19
|
+
/** The mounts a run's grant adds beyond its own app space (other apps' files
|
|
20
|
+
* and nodes, and the person's files). */
|
|
21
|
+
export declare function grantedMounts(permissions: RunPermissions): LaunchSpec['mounts'];
|
|
22
|
+
/** Whether a launched mount came from a grant: it lies under the person's files
|
|
23
|
+
* or under another app's space. Own-space and system mounts never do. */
|
|
24
|
+
export declare function isGrantedSource(app: string, source: string): boolean;
|
|
25
|
+
/** A launched mount the current permissions still give: the same or a broader
|
|
26
|
+
* granted directory, writable if the mount is. */
|
|
27
|
+
export declare function mountAllowed(mount: LaunchSpec['mounts'][number], allowed: LaunchSpec['mounts']): boolean;
|
|
28
|
+
/** Whether a spec compiled earlier is still within the node's current
|
|
29
|
+
* permissions. A launch whose grant generation moved while the launcher was
|
|
30
|
+
* starting it checks this before registering the sandbox (runtime spec §15). */
|
|
31
|
+
export declare function launchStillGranted(node: Pick<LaunchNode, 'app' | 'sub' | 'grantId' | 'scopes'>, spec: Pick<LaunchSpec, 'mounts'>): boolean;
|
|
32
|
+
export declare function compileLaunch(node: LaunchNode): LaunchSpec;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var W=Object.defineProperty;var p=(t,r)=>W(t,"name",{value:r,configurable:!0});import{lstatSync as y}from"node:fs";import{join as u,relative as a,sep as c}from"node:path";import{appSpace as m,appsRoot as D,runtimeRoot as f,socketDir as h,userFilesRoot as b}from"../layout.js";import{nodeAgentDir as F,nodeRunDir as R}from"../canvas/paths.js";import{uidForApp as S}from"./users.js";import{permissionsForRun as I}from"./permissions.js";function k(t){const r=[];for(const e of t.otherFiles){const i=e.holder==="user"?b():m(e.holder).files;r.push({source:e.path==="."?i:u(i,e.path),writable:e.writable})}for(const e of t.otherNodes)r.push({source:m(e).nodes,writable:!1});return r}p(k,"grantedMounts");function w(t,r){const e=a(t,r);return e===""||e!==".."&&!e.startsWith(`..${c}`)&&!e.startsWith(c)}p(w,"beneath");function A(t,r){return w(b(),r)||w(D(),r)&&!w(m(t).root,r)}p(A,"isGrantedSource");function M(t,r){return r.some(e=>w(e.source,t.source)&&(e.writable||!t.writable))}p(M,"mountAllowed");function q(t,r){try{const e=k(I(t.app,t.sub,t.grantId,t.scopes));return r.mounts.every(i=>!A(t.app,i.source)||M(i,e))}catch{return!1}}p(q,"launchStillGranted");function z(t){const r=m(t.app),e=I(t.app,t.sub,t.grantId,t.scopes),i=new Map,s=p((o,n,l=!1,E=!1)=>{if(l)try{y(o)}catch(d){if(d.code!=="ENOENT")throw d;E&&t.auditMissing(o);return}i.set(o,n||(i.get(o)??!1))},"add");for(const o of["/usr","/bin","/lib","/lib64","/opt/crouter","/etc/passwd","/etc/group","/etc/resolv.conf","/etc/hosts","/etc/ssl","/etc/ca-certificates"])s(o,!1,!0);t.withoutNode||s(F(t.nodeId,t.app),!0),s(r.home,!0),s(r.files,!0),t.withoutNode||s(R(t.nodeId),!0),s(u(h(),"api.sock"),!0),s(u(h(),"store.sock"),!0),e.ownNodes&&s(r.nodes,!0);for(const o of k(e))s(o.source,o.writable,!0,!0);if(t.pluginRoot!==void 0){const o=p(l=>t.pluginRoot===l||a(l,t.pluginRoot)!==".."&&!a(l,t.pluginRoot).startsWith(`..${c}`),"within"),n=u(f(),"plugins");if([...i].some(([l])=>o(l))){if(i.get(t.pluginRoot)===!0)throw new Error("hook root cannot also be writable");s(t.pluginRoot,!1)}else if(o(n)&&t.pluginRoot!==n)s(t.pluginRoot,!1);else if(o("/opt/crouter"))s(t.pluginRoot,!1);else throw new Error("hook root is not readable with this app\u2019s mounts")}const x=t.cwd??r.files,g=[...i].sort(([o],[n])=>o.split(c).length-n.split(c).length||o.localeCompare(n)),N=u(f(),"nodes",t.nodeId,"job","broker.log"),v=process.platform!=="linux"?[R(t.nodeId),u(h(),"api.sock"),u(h(),"store.sock")]:[];if(g.some(([o])=>o!==t.pluginRoot&&!v.includes(o)&&(o===f()||!a(f(),o).startsWith("..")&&!a(f(),o).startsWith(c))))throw new Error("runtime records cannot be mounted");return{nodeId:t.nodeId,uid:S(t.app),mounts:g.map(([o,n])=>({source:o,writable:n})),cwd:x,env:t.env,command:t.command,log:N}}p(z,"compileLaunch");export{z as compileLaunch,k as grantedMounts,A as isGrantedSource,q as launchStillGranted,M as mountAllowed};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type Dirent, type Stats } from 'node:fs';
|
|
2
|
+
export declare function isBeneathRefusal(error: unknown): boolean;
|
|
3
|
+
/** Whether a beneath read failed because nothing usable is there: absent, not a
|
|
4
|
+
* directory, unreadable, or refused (see `BeneathRefusal`). */
|
|
5
|
+
export declare function isAbsentOrRefused(error: unknown): boolean;
|
|
6
|
+
/** An fd for `path` opened with `flags`, resolved beneath `root`. Never creates:
|
|
7
|
+
* `openat2` takes no mode, so a file it created would be mode 0000. On Linux
|
|
8
|
+
* the fd is a regular file or a directory, except with O_PATH, which opens
|
|
9
|
+
* nothing and is only stat'd. */
|
|
10
|
+
export declare function openBeneath(root: string, path: string, flags: number): number;
|
|
11
|
+
export declare function readFileBeneath(root: string, path: string): Buffer;
|
|
12
|
+
/** The file's text, or null when it is missing or refused. */
|
|
13
|
+
export declare function readTextBeneathIfExists(root: string, path: string): string | null;
|
|
14
|
+
export declare function statBeneath(root: string, path: string): Stats;
|
|
15
|
+
export declare function existsBeneath(root: string, path: string): boolean;
|
|
16
|
+
/** Run `fn` with `at(name)`, a pathname that reaches one entry of `dir` after
|
|
17
|
+
* `dir` itself resolved beneath `root` (`at()` is the directory). With
|
|
18
|
+
* `create`, missing directories on the way are made. */
|
|
19
|
+
export declare function withDirBeneath<T>(root: string, dir: string, fn: (at: (name?: string) => string) => T, create?: boolean): T;
|
|
20
|
+
/** Write `data` to `path` beneath `root`, making missing parents. `atomic`
|
|
21
|
+
* writes a temporary file and renames it over the target, so on Linux a
|
|
22
|
+
* symlink at the target is replaced, never followed. A Mac writes through a
|
|
23
|
+
* symlink to its target, as it always has (a dangling one fails ENOENT). */
|
|
24
|
+
export declare function writeFileBeneath(root: string, path: string, data: Buffer | string, options?: {
|
|
25
|
+
mode?: number;
|
|
26
|
+
atomic?: boolean;
|
|
27
|
+
}): void;
|
|
28
|
+
/** Create `path` beneath `root` only if absent (`wx`), making missing parents. */
|
|
29
|
+
export declare function createFileBeneath(root: string, path: string, data: Buffer | string, mode?: number): void;
|
|
30
|
+
export declare function appendFileBeneath(root: string, path: string, data: string): void;
|
|
31
|
+
export declare function unlinkBeneath(root: string, path: string): void;
|
|
32
|
+
export declare function rmdirBeneath(root: string, path: string): void;
|
|
33
|
+
export declare function renameBeneath(root: string, from: string, to: string): void;
|
|
34
|
+
/** link(2) without replacement: fails if `to` exists. */
|
|
35
|
+
export declare function linkBeneath(root: string, from: string, to: string): void;
|
|
36
|
+
export declare function fsyncDirBeneath(root: string, dir: string): void;
|
|
37
|
+
/** Directory entries typed by the directory itself (a symlink stays a symlink). */
|
|
38
|
+
export declare function readdirBeneath(root: string, dir: string): Dirent[];
|
|
39
|
+
/** The first `limit` entries by name, each with its own (unfollowed on Linux)
|
|
40
|
+
* stat; an entry removed before its stat is left out. */
|
|
41
|
+
export declare function listBeneath(root: string, dir: string, limit: number): Array<{
|
|
42
|
+
name: string;
|
|
43
|
+
stat: Stats;
|
|
44
|
+
}>;
|
|
45
|
+
/** Regular files under `dir` matching `predicate`, never descending a symlink. */
|
|
46
|
+
export declare function walkFilesBeneath(root: string, dir: string, predicate?: (name: string) => boolean, skipDir?: (name: string) => boolean): string[];
|
|
47
|
+
/** Copy the entries of `from` (beneath `fromRoot`) into `to` (beneath
|
|
48
|
+
* `toRoot`): directories and regular files with their permission bits, and
|
|
49
|
+
* symlinks as links, never followed. Any other entry, any entry removed or
|
|
50
|
+
* refused after the directory was read, and any top-level name in `skip`, is
|
|
51
|
+
* left out. A name `to` already holds is overwritten, except by a symlink. */
|
|
52
|
+
export declare function copyTreeBeneath(fromRoot: string, from: string, toRoot: string, to: string, skip?: ReadonlySet<string>): void;
|
|
53
|
+
/** Set the mode (and, with `owner`, the owner) of the file or directory at
|
|
54
|
+
* `path` beneath `root` through an fd opened without following a symlink. A
|
|
55
|
+
* Mac sets them by pathname, as it always has. */
|
|
56
|
+
export declare function setModeBeneath(root: string, path: string, mode: number, owner?: {
|
|
57
|
+
uid: number;
|
|
58
|
+
gid: number;
|
|
59
|
+
}): void;
|
|
60
|
+
/** Remove the tree at `path` beneath `root`, never descending a symlink: a
|
|
61
|
+
* symlink at `path` or inside it is unlinked itself. Absent is not an error.
|
|
62
|
+
* On Linux the walk holds one directory fd per level and opens each child
|
|
63
|
+
* relative to its parent, so a deep tree costs one open per entry. */
|
|
64
|
+
export declare function removeTreeBeneath(root: string, path: string): void;
|
|
65
|
+
/** A pathname that connects to the unix socket at `path` beneath `root`
|
|
66
|
+
* without following a symlink, and `release`, to call once the connect has
|
|
67
|
+
* settled. On Linux it is the magic link of an O_PATH fd held until release. */
|
|
68
|
+
export declare function socketBeneath(root: string, path: string): {
|
|
69
|
+
path: string;
|
|
70
|
+
release: () => void;
|
|
71
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var ie=Object.defineProperty;var f=(t,e)=>ie(t,"name",{value:e,configurable:!0});import{chmodSync as V,chownSync as oe,closeSync as y,constants as d,fchmodSync as K,fchownSync as ce,fstatSync as $,fsyncSync as A,linkSync as fe,lstatSync as X,mkdirSync as M,openSync as w,readdirSync as C,readFileSync as se,readlinkSync as le,readSync as H,realpathSync as ue,renameSync as j,rmdirSync as G,rmSync as ae,statSync as q,symlinkSync as ye,unlinkSync as R,writeSync as he}from"node:fs";import{randomUUID as de}from"node:crypto";import{basename as p,dirname as N,join as _,relative as g,resolve as k,sep as v}from"node:path";import{loadLinuxNative as Oe,O_CLOEXEC as I,O_PATH as D,RESOLVE_BENEATH as Ee,RESOLVE_NO_SYMLINKS as pe}from"../../native/linux.js";const Ne=Ee|pe,B=D|d.O_DIRECTORY|I;let b=null;function m(){return b===null&&(b=Oe()),b}f(m,"native");function E(t){return t.code}f(E,"code");class S extends Error{static{f(this,"BeneathRefusal")}}function z(t){return t instanceof S}f(z,"isBeneathRefusal");function J(t,e){switch(E(t)){case"ELOOP":case"EXDEV":return new S(`path meets a symlink: ${e}`);case"ENXIO":return new S(`path is not a regular file: ${e}`);case"EAGAIN":return new S(`path is held by a lease: ${e}`);default:return t}}f(J,"refused");function x(t,e,r,i,n){try{return t.openat2(e,r,i,Ne)}catch(c){throw J(c,n)}}f(x,"openat2");function Q(t,e,r){let i;try{i=$(t)}catch(n){throw y(t),n}if(i.isFile()||r&&i.isDirectory())return t;throw y(t),new S(`path is not a regular file: ${e}`)}f(Q,"regular");const Y=new Set(["ENOENT","ENOTDIR","EACCES"]);function W(t){return Y.has(E(t)??"")||z(t)}f(W,"isAbsentOrRefused");function Z(t,e){const r=g(k(t),k(e));if(r===".."||r.startsWith(`..${v}`)||r.startsWith(v))throw new Error(`${e} is outside ${t}`);return r}f(Z,"inside");function ee(t){if(t===""||t===".."||t.includes("/"))throw new Error(`not one path component: ${t}`);return t}f(ee,"entry");function L(t,e,r){if(r&d.O_CREAT)throw new Error("openBeneath never creates; use writeFileBeneath or createFileBeneath");const i=Z(t,e),n=m();if(!n)return w(e,r);const c=w("/",B);let o;try{o=x(n,c,g("/",k(t))||".",B,t)}finally{y(c)}try{return r&D?x(n,o,i||".",r|I,e):Q(x(n,o,i||".",r|I|d.O_NONBLOCK,e),e,!0)}finally{y(o)}}f(L,"openBeneath");function we(t,e){const r=L(t,e,d.O_RDONLY);try{return se(r)}finally{y(r)}}f(we,"readFileBeneath");function Le(t,e){try{return we(t,e).toString("utf8")}catch(r){if(E(r)==="ENOENT"||z(r))return null;throw r}}f(Le,"readTextBeneathIfExists");function te(t,e){if(!m())return q(e);const r=L(t,e,D);try{return $(r)}finally{y(r)}}f(te,"statBeneath");function Fe(t,e){try{return te(t,e),!0}catch(r){if(Y.has(E(r)??""))return!1;throw r}}f(Fe,"existsBeneath");function O(t,e,r,i=!1){Z(t,e);const n=m();if(!n)return i&&M(e,{recursive:!0}),r(o=>o===void 0?e:_(e,ee(o)));let c=w("/",B);try{for(const s of g("/",k(e)).split(v).filter(Boolean)){let a;try{a=x(n,c,s,B,e)}catch(u){if(!i||E(u)!=="ENOENT")throw u;try{M(`/proc/self/fd/${c}/${s}`)}catch(l){if(E(l)!=="EEXIST")throw l}a=x(n,c,s,B,e)}y(c),c=a}const o=`/proc/self/fd/${c}`;return r(s=>s===void 0?o:`${o}/${ee(s)}`)}finally{y(c)}}f(O,"withDirBeneath");function P(t,e,r,i){if(!m())return w(t,e,r);let n;try{n=w(t,e|d.O_NOFOLLOW|d.O_NONBLOCK,r)}catch(c){throw J(c,i)}return Q(n,i,!1)}f(P,"openForWrite");function F(t,e){let r=0;for(;r<e.length;)r+=he(t,e,r,e.length-r)}f(F,"writeAll");function ke(t,e,r,i={}){const n=typeof r=="string"?Buffer.from(r,"utf8"):r,c=i.mode??438;let o=N(e),s=p(e),a=t;if(i.atomic&&!m()){let u=!1;try{u=X(e).isSymbolicLink()}catch(l){if(E(l)!=="ENOENT")throw l}if(u){const l=ue(e);o=N(l),s=p(l),a="/"}}O(a,o,u=>{if(!i.atomic){const T=P(u(s),d.O_WRONLY|d.O_CREAT|d.O_TRUNC,c,e);try{F(T,n)}finally{y(T)}return}const l=u(`.${s}.${de()}.tmp`);let h=w(l,"wx",c);try{F(h,n),A(h),y(h),h=void 0,j(l,u(s))}finally{h!==void 0&&y(h);try{R(l)}catch(T){if(E(T)!=="ENOENT")throw T}}},!0)}f(ke,"writeFileBeneath");function De(t,e,r,i=438){const n=typeof r=="string"?Buffer.from(r,"utf8"):r;O(t,N(e),c=>{const o=w(c(p(e)),"wx",i);try{F(o,n),A(o)}finally{y(o)}},!0)}f(De,"createFileBeneath");function Ae(t,e,r){O(t,N(e),i=>{const n=P(i(p(e)),d.O_WRONLY|d.O_CREAT|d.O_APPEND,438,e);try{F(n,Buffer.from(r,"utf8"))}finally{y(n)}},!0)}f(Ae,"appendFileBeneath");function Ce(t,e){O(t,N(e),r=>R(r(p(e))))}f(Ce,"unlinkBeneath");function Re(t,e){O(t,N(e),r=>G(r(p(e))))}f(Re,"rmdirBeneath");function ge(t,e,r){O(t,N(e),i=>O(t,N(r),n=>j(i(p(e)),n(p(r))),!0))}f(ge,"renameBeneath");function ve(t,e,r){O(t,N(e),i=>O(t,N(r),n=>fe(i(p(e)),n(p(r)))))}f(ve,"linkBeneath");function Ie(t,e){O(t,e,r=>{const i=w(r(),d.O_RDONLY);try{A(i)}finally{y(i)}})}f(Ie,"fsyncDirBeneath");function U(t,e){return O(t,e,r=>C(r(),{withFileTypes:!0}))}f(U,"readdirBeneath");function be(t,e,r){return O(t,e,i=>C(i()).sort((n,c)=>n.localeCompare(c)).slice(0,r).flatMap(n=>{try{return[{name:n,stat:m()?X(i(n)):q(i(n))}]}catch(c){if(E(c)==="ENOENT")return[];throw c}}))}f(be,"listBeneath");function Ye(t,e,r=()=>!0,i=()=>!1){const n=[],c=[e];for(;c.length;){const o=c.pop();let s;try{s=U(t,o)}catch(a){if(o===e&&!Y.has(E(a)??""))throw a;continue}for(const a of s){const u=_(o,a.name);a.isDirectory()?i(a.name)||c.push(u):a.isFile()&&r(a.name)&&n.push(u)}}return n}f(Ye,"walkFilesBeneath");function We(t,e,r,i,n=new Set){re(t,e,U(t,e),r,i,n)}f(We,"copyTreeBeneath");function re(t,e,r,i,n,c){O(i,n,()=>{},!0);for(const o of r){if(c.has(o.name))continue;const s=_(e,o.name),a=_(n,o.name);if(o.isDirectory()){let u,l;try{u=te(t,s).mode&511,l=U(t,s)}catch(h){if(W(h))continue;throw h}re(t,s,l,i,a,new Set),O(i,n,h=>V(h(o.name),u))}else if(o.isSymbolicLink()){let u;try{u=O(t,e,l=>le(l(o.name)))}catch(l){if(E(l)==="EINVAL"||W(l))continue;throw l}O(i,n,l=>ye(u,l(o.name)))}else if(o.isFile()){let u;try{u=L(t,s,d.O_RDONLY)}catch(l){if(W(l))continue;throw l}try{me(u,i,a)}finally{y(u)}}}}f(re,"copyEntries");function me(t,e,r){const i=$(t).mode&511;O(e,N(r),n=>{const c=P(n(p(r)),d.O_WRONLY|d.O_CREAT|d.O_TRUNC,i,r);try{K(c,i);const o=Buffer.allocUnsafe(1<<20);for(let s=H(t,o);s>0;s=H(t,o))F(c,o.subarray(0,s))}finally{y(c)}},!0)}f(me,"copyFileFd");function Pe(t,e,r,i){if(!m()){i&&oe(e,i.uid,i.gid),V(e,r);return}const n=L(t,e,d.O_RDONLY|d.O_NONBLOCK);try{const c=$(n);if(!c.isFile()&&!c.isDirectory())throw new S(`path is not a regular file or directory: ${e}`);i&&ce(n,i.uid,i.gid),K(n,r)}finally{y(n)}}f(Pe,"setModeBeneath");function ne(t){try{R(t)}catch(e){if(E(e)!=="ENOENT")throw e}}f(ne,"unlinkIfPresent");function Ue(t,e){const r=m();if(!r){ae(e,{recursive:!0,force:!0});return}try{O(t,N(e),i=>{const n=w(i(),B);try{Se(r,n,p(e),e)}finally{y(n)}})}catch(i){if(E(i)!=="ENOENT")throw i}}f(Ue,"removeTreeBeneath");function Se(t,e,r,i){const n=[],c=f((o,s,a)=>{let u;try{u=x(t,o,s,B,a)}catch(h){if(E(h)==="ENOENT")return;if(E(h)!=="ENOTDIR"&&!(h instanceof S))throw h;ne(`/proc/self/fd/${o}/${s}`);return}n.push({fd:u,parentFd:o,name:s,shown:a,dirs:[]});const l=n[n.length-1];for(const h of C(`/proc/self/fd/${u}`,{withFileTypes:!0}))h.isDirectory()?l.dirs.push(h.name):ne(`/proc/self/fd/${u}/${h.name}`)},"enter");try{for(c(e,r,i);n.length>0;){const o=n[n.length-1],s=o.dirs.pop();if(s!==void 0){c(o.fd,s,_(o.shown,s));continue}n.pop(),y(o.fd);try{G(`/proc/self/fd/${o.parentFd}/${o.name}`)}catch(a){if(E(a)!=="ENOENT")throw a}}}finally{for(const o of n)y(o.fd)}}f(Se,"removeTreeAt");function Ve(t,e){if(!m())return{path:e,release:f(()=>{},"release")};const r=L(t,e,D);let i;try{i=$(r)}catch(c){throw y(r),c}if(!i.isSocket())throw y(r),new S(`path is not a socket: ${e}`);let n=!0;return{path:`/proc/self/fd/${r}`,release:f(()=>{n&&(n=!1,y(r))},"release")}}f(Ve,"socketBeneath");export{Ae as appendFileBeneath,We as copyTreeBeneath,De as createFileBeneath,Fe as existsBeneath,Ie as fsyncDirBeneath,W as isAbsentOrRefused,z as isBeneathRefusal,ve as linkBeneath,be as listBeneath,L as openBeneath,we as readFileBeneath,Le as readTextBeneathIfExists,U as readdirBeneath,Ue as removeTreeBeneath,ge as renameBeneath,Re as rmdirBeneath,Pe as setModeBeneath,Ve as socketBeneath,te as statBeneath,Ce as unlinkBeneath,Ye as walkFilesBeneath,O as withDirBeneath,ke as writeFileBeneath};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type ActiveGrant } from '../grants/mirror.js';
|
|
2
|
+
import type { MemoryStoreDescriptor, MemoryTarget } from '../memory-resolver.js';
|
|
3
|
+
export interface RunPermissions {
|
|
4
|
+
app: string;
|
|
5
|
+
ownNodes: boolean;
|
|
6
|
+
otherFiles: Array<{
|
|
7
|
+
holder: string;
|
|
8
|
+
path: string;
|
|
9
|
+
writable: boolean;
|
|
10
|
+
}>;
|
|
11
|
+
otherNodes: string[];
|
|
12
|
+
}
|
|
13
|
+
/** Only the active mirror and the launched scope list determine a run's mounts. */
|
|
14
|
+
export declare function permissionsForRun(app: string, sub: string, grantId: string | null, launched: string[] | null): RunPermissions;
|
|
15
|
+
/** The same computation over a given grant record, e.g. the mirror before a sync replaced it. */
|
|
16
|
+
export declare function permissionsForGrant(app: string, sub: string, grant: ActiveGrant | null, launched: string[] | null): RunPermissions;
|
|
17
|
+
/** The grant is current on every call; an explicit run scope list narrows it. */
|
|
18
|
+
export declare function memoryPermission(app: string, resolved: readonly string[], launched: readonly string[] | null, store: MemoryStoreDescriptor, access: 'read' | 'rw', name?: string, wholeStore?: boolean): boolean;
|
|
19
|
+
export declare function automaticallyLoadsUserMemory(resolved: readonly string[], launched: readonly string[] | null): boolean;
|
|
20
|
+
/** A project is available only through an actual file mount, never a symlink or an ancestor of it. */
|
|
21
|
+
export declare function readableProject(repository: string, roots: readonly string[]): boolean;
|
|
22
|
+
export declare function readableProjectForScopes(repository: string, app: string, resolved: readonly string[], launched: readonly string[] | null): boolean;
|
|
23
|
+
export interface FileCaller {
|
|
24
|
+
app: string;
|
|
25
|
+
resolved: readonly string[];
|
|
26
|
+
launched: readonly string[] | null;
|
|
27
|
+
}
|
|
28
|
+
/** The directory a caller's permission names for `path`: the daemon opens
|
|
29
|
+
* `path` beneath it. `missing` is the scope the caller lacks (null when no
|
|
30
|
+
* scope names the path). The person (`null`) and a Mac terminal node keep a
|
|
31
|
+
* Mac's whole filesystem; on Linux the person reaches /user and /apps. */
|
|
32
|
+
export declare function fileRoot(caller: FileCaller | null, target: string, access: 'read' | 'rw'): {
|
|
33
|
+
root: string;
|
|
34
|
+
} | {
|
|
35
|
+
missing: string | null;
|
|
36
|
+
};
|
|
37
|
+
/** Daemon-only automatic corpus; never deliver a store merely because it is explicitly readable. */
|
|
38
|
+
export declare function automaticMemoryTarget(node: {
|
|
39
|
+
node_id: string;
|
|
40
|
+
cwd: string;
|
|
41
|
+
profile_id?: string | null;
|
|
42
|
+
grantee: string;
|
|
43
|
+
sub?: string | null;
|
|
44
|
+
grant_id?: string | null;
|
|
45
|
+
scopes?: string[] | null;
|
|
46
|
+
}): MemoryTarget;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var I=Object.defineProperty;var u=(r,t)=>I(r,"name",{value:t,configurable:!0});import{covers as g,parseScope as C}from"@north-light/crouter-identity";import{activeGrant as P,grantFor as W}from"../grants/mirror.js";import{appSpace as v,appsRoot as _,userFilesRoot as b,userRoot as L}from"../layout.js";import{relative as R,join as S,sep as E,resolve as A}from"node:path";import{lstatSync as M,realpathSync as Z}from"node:fs";import{readConfig as k}from"../config.js";import{SCOPE_VOCABULARY as G}from"../scopes.js";function X(r,t,o,e){return N(r,t,o?P(o):W(r,t),e)}u(X,"permissionsForRun");function N(r,t,o,e){if(!o||o.grantee!==r||o.sub!==t)throw new Error(`no active grant for ${r}`);if(e!==null&&!Array.isArray(e))throw new Error("invalid launched scopes");const s=[],i=[];let n=e===null;const f=e??o.resolved;for(const c of f){if(typeof c!="string")throw new Error("invalid launched scope");C(c);const w=c===`crtr:memory:read:${r}`||c===`crtr:memory:rw:${r}`||c.startsWith(`crtr:memory:read:${r}:`)||c.startsWith(`crtr:memory:rw:${r}:`);if(e!==null&&!w&&!o.resolved.some(p=>g(p,c)))throw new Error(`launched scope not in grant: ${c}`);const m=/^crtr:files:(read|rw):(user|app:[A-Za-z0-9_-]{1,64}):(.+)$/.exec(c);if(m){const[,p,l,$]=m;if(l===r)throw new Error(`own-app files cannot narrow a run: ${c}`);s.push({holder:l,path:$,writable:p==="rw"})}const a=/^crtr:objects:read:(app:[A-Za-z0-9_-]{1,64})$/.exec(c);a&&a[1]!==r&&i.push(a[1])}return{app:r,ownNodes:n,otherFiles:s,otherNodes:i}}u(N,"permissionsForGrant");function O(r,t,o,e,s,i,n=!1){if(e.scope==="builtin")return s==="read";if(e.scope==="project")return!0;const f=e.scope==="user"?"user":e.ownerApp??(e.scope==="profile"?"app:terminal":r),c=e.scope==="profile"&&!e.profileId&&i?.match(/^profiles\/([A-Za-z0-9_-]{1,64})(?:\/(.+))?$/),w=e.scope==="profile"&&e.profileId?`:profile:${e.profileId}`:c?`:profile:${c[1]}`:"",m=c?c[2]:f==="user"||e.profileId?i:void 0,a=`crtr:memory:${s}:${f}${w}${m?`:${m}`:""}`,p=u(l=>g(l,a)||!n&&i===void 0&&l.startsWith(`${a}:`),"permits");return(f===r||t.some(p))&&(o===null||o.some(p))}u(O,"memoryPermission");function U(r,t){return r.includes("crtr:memory:manage:user")&&(t===null||t.includes("crtr:memory:manage:user"))}u(U,"automaticallyLoadsUserMemory");function h(r,t){const o=R(r,t);return o===""||o!==".."&&!o.startsWith(`..${E}`)&&!o.startsWith(E)}u(h,"contains");function q(r,t){const o=A(r);for(const e of t){const s=A(e);if(h(s,o))try{if(Z(o)!==o||Z(s)!==s)continue;let i=o;for(;h(s,i)&&!M(i).isSymbolicLink();){if(i===s)return!0;i=A(i,"..")}}catch{}}return!1}u(q,"readableProject");function B(r,t,o,e){const s=[v(t).files];for(const i of e??o){if(e!==null&&!o.some(f=>g(f,i)))continue;const n=/^crtr:files:(?:read|rw):(user|app:[A-Za-z0-9_-]{1,64}):(.+)$/.exec(i);n&&s.push(S(n[1]==="user"?b():v(n[1]).files,n[2]==="."?"":n[2]))}return q(r,s)}u(B,"readableProjectForScopes");function rr(r,t,o){const e=A(t);if(r===null||process.platform!=="linux"&&r.app==="app:terminal"){if(process.platform!=="linux")return{root:"/"};const p=[L(),_()].find(l=>h(l,e));return p?{root:p}:{missing:null}}const s=v(r.app);for(const p of[s.files,s.nodes])if(h(p,e))return{root:p};const i=u(p=>r.resolved.some(l=>g(l,p))&&(r.launched===null||r.launched.some(l=>g(l,p))),"held"),n=u((p,l)=>{const $=R(l,e)||".",z=u(y=>y.flatMap(x=>{const d=/^crtr:files:(read|rw):(user|app:[A-Za-z0-9_-]{1,64}):(.+)$/.exec(x);return!d||d[2]!==p||o==="rw"&&d[1]!=="rw"?[]:d[3]==="."||d[3]===$||$.startsWith(`${d[3]}/`)?[S(l,d[3]==="."?"":d[3])]:[]}),"dirs"),j=z(r.resolved),F=r.launched===null?j:z(r.launched);return!j.length||!F.length?{missing:`crtr:files:${o}:${p}:${$}`}:{root:[...j,...F].reduce((y,x)=>x.length>y.length?x:y)}},"files");if(h(b(),e))return n("user",b());const[f,c,w,m]=R(_(),e).split(E);if(!h(_(),e)||!f||!/^[A-Za-z0-9_-]{1,64}$/.test(f))return{missing:null};const a=v(`app:${f}`);return c==="files"?n(`app:${f}`,a.files):c!=="nodes"||o!=="read"?{missing:null}:i(`crtr:objects:read:app:${f}`)?{root:a.nodes}:w&&(m==="attachments"||m==="reports")&&i(`crtr:conversations:read:app:${f}`)?{root:S(a.nodes,w,m)}:{missing:`crtr:objects:read:app:${f}`}}u(rr,"fileRoot");function er(r){const t=r.grantee,e=(r.grant_id?P(r.grant_id):W(t,r.sub??""))?.resolved??(t==="app:terminal"&&!k("user").runtime?.issuer?G:null);if(e===null)throw new Error(`no active memory grant for ${t}`);const s=r.scopes??null,i=u(n=>process.platform!=="linux"&&t==="app:terminal"||B(n,t,e,s),"projectReadable");return{cwd:r.cwd,profileId:r.profile_id??null,nodeId:r.node_id,grantee:t,allowsProject:i,allowsStore:u(n=>n.scope==="project"?i(n.repositoryRoot??n.ownerDir??n.storeRoot):n.scope==="user"?U(e,s):n.scope==="node"?n.ownerApp===t:n.scope==="profile"?O(t,e,s,n,"read",void 0,!0):!0,"allowsStore")}}u(er,"automaticMemoryTarget");export{er as automaticMemoryTarget,U as automaticallyLoadsUserMemory,rr as fileRoot,O as memoryPermission,N as permissionsForGrant,X as permissionsForRun,q as readableProject,B as readableProjectForScopes};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type CapturedExit } from '../../launcher/spec.js';
|
|
2
|
+
export interface AppProcess {
|
|
3
|
+
pid: number;
|
|
4
|
+
completion: Promise<CapturedExit>;
|
|
5
|
+
stop(signal?: 'SIGTERM' | 'SIGKILL'): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export interface AppProcessOptions {
|
|
8
|
+
nodeId?: string;
|
|
9
|
+
app?: string;
|
|
10
|
+
command: string[];
|
|
11
|
+
cwd: string;
|
|
12
|
+
env: NodeJS.ProcessEnv;
|
|
13
|
+
stdin?: string;
|
|
14
|
+
stdoutBytes?: number;
|
|
15
|
+
stderrBytes?: number;
|
|
16
|
+
stderrTail?: boolean;
|
|
17
|
+
pluginRoot?: string;
|
|
18
|
+
/** A file-backed job writes its own log and needs no launcher output capture. */
|
|
19
|
+
capture?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** The same mount compiler and launcher request used by broker launches. A node
|
|
22
|
+
* keeps its launched scope list; a process without a node uses the app's whole
|
|
23
|
+
* current grant. Linux never falls back to direct execution when configured
|
|
24
|
+
* with a launcher whose socket is missing. */
|
|
25
|
+
export declare function appProcessSandboxed(): boolean;
|
|
26
|
+
export declare function stopAppProcess(pid: number, signal?: 'SIGTERM' | 'SIGKILL', nodeId?: string): Promise<void>;
|
|
27
|
+
export declare function launchAppProcess(options: AppProcessOptions): Promise<AppProcess>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var v=Object.defineProperty;var d=(e,r)=>v(e,"name",{value:r,configurable:!0});import{existsSync as _}from"node:fs";import{randomUUID as b}from"node:crypto";import{join as h}from"node:path";import{getNode as S}from"../canvas/canvas.js";import{nodeRunDir as y}from"../canvas/paths.js";import{appSpace as G}from"../layout.js";import{activeGrant as L,activeGrantForApp as T,grantFor as x,grantsGeneration as g}from"../grants/mirror.js";import{emitEvent as I}from"../events/emit.js";import{ensureAppSpace as A}from"./space.js";import{compileLaunch as N,launchStillGranted as O}from"./mounts.js";import{launcherRequest as s}from"../../launcher/client.js";import{LAUNCHER_SOCKET as C}from"../../launcher/spec.js";function z(){if(process.platform!=="linux")return!1;if(_(C))return!0;throw new Error("root launcher socket is unavailable; refusing an unsandboxed app process")}d(z,"appProcessSandboxed");async function E(e,r="SIGKILL",t){if(!("ok"in await s({operation:"stop",pid:e,signal:r,...t===void 0?{}:{nodeId:t}})))throw new Error("launcher did not stop process")}d(E,"stopAppProcess");async function J(e){const r=e.nodeId===void 0?null:S(e.nodeId);if(e.nodeId!==void 0&&!r)throw new Error(`missing node ${e.nodeId}`);const t=r?.grantee??e.app??"app:terminal";if(e.app!==void 0&&e.app!==t)throw new Error("app does not match node");const o=r?null:T(t);if(!r&&!o)throw new Error(`no active grant for ${t}`);if(r&&t!=="app:terminal"&&!(r.grant_id?L(r.grant_id):x(t,r.sub??"user:local")))throw new Error(`no active grant for ${t}`);await A(t);const p=e.nodeId??`proc-${b()}`,l=G(t),f=Object.fromEntries(Object.entries({...e.env,HOME:l.home,PI_CODING_AGENT_DIR:h(l.home,".pi","agent"),PWD:e.cwd,...e.nodeId===void 0?{}:{CRTR_API_SOCKET:h(y(p),"cli.sock")}}).filter(n=>n[1]!==void 0));delete f.CRTR_RUNTIME_HOME;const m={nodeId:p,app:t,sub:r?r.sub??"user:local":o.sub,grantId:r?r.grant_id??null:o.id,scopes:r?.scopes??null},R=d(()=>{const n=N({...m,command:e.command,env:f,...e.nodeId===void 0?{withoutNode:!0}:{},cwd:e.cwd,...e.pluginRoot===void 0?{}:{pluginRoot:e.pluginRoot},auditMissing:d(c=>I({level:"warn",event:"process.mount.missing",...e.nodeId===void 0?{}:{node_id:e.nodeId},fields:{source:c}}),"auditMissing")});if(e.pluginRoot!==void 0&&(n.pluginRoot=e.pluginRoot),e.capture===!1){if(e.nodeId===void 0||e.stdin!==void 0)throw new Error("uncaptured process requires a node and no stdin")}else n.capture={stdoutBytes:e.stdoutBytes??256*1024,stderrBytes:e.stderrBytes??256*1024,...e.stderrTail?{stderrTail:!0}:{},...e.stdin===void 0?{}:{stdin:e.stdin}};return n},"compile");let i;for(let n=0;n<2&&i===void 0;n++){const c=g(),w=R(),a=await s({operation:"launch",spec:w});if(!("pid"in a))throw new Error("launcher did not return a process id");if(g()===c||O(m,w)){i=a.pid;break}I({level:"info",event:"process.launch.regranted",...e.nodeId===void 0?{}:{node_id:e.nodeId},fields:{pid:a.pid}}),await E(a.pid,"SIGKILL").catch(()=>{})}if(i===void 0)throw new Error("grant changed during every launch attempt");const u=i;return{pid:u,get completion(){return s({operation:"wait",pid:u}).then(n=>{if(!("result"in n))throw new Error("launcher did not return process completion");return n.result})},stop:d((n="SIGKILL")=>E(u,n,e.nodeId),"stop")}}d(J,"launchAppProcess");export{z as appProcessSandboxed,J as launchAppProcess,E as stopAppProcess};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** App sandboxes bind the person's files through nl-data group access. */
|
|
2
|
+
export declare function ensureUserFiles(): void;
|
|
3
|
+
/** On macOS no launcher or nl-data group exists; directories stay owned by the Mac user. */
|
|
4
|
+
export declare function ensureAppSpace(app: string): Promise<{
|
|
5
|
+
uid: number;
|
|
6
|
+
gid: number;
|
|
7
|
+
root: string;
|
|
8
|
+
}>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var f=Object.defineProperty;var n=(o,r)=>f(o,"name",{value:r,configurable:!0});import{chownSync as d,chmodSync as a,existsSync as m,mkdirSync as u,readFileSync as l,statSync as h}from"node:fs";import{appSpace as g,appsRoot as w,userFilesRoot as y}from"../layout.js";import{launcherRequest as S}from"../../launcher/client.js";import{LAUNCHER_SOCKET as x}from"../../launcher/spec.js";import{allocateAppUser as E,uidForApp as v}from"./users.js";function p(){const o=l("/etc/group","utf8").split(`
|
|
2
|
+
`).find(e=>e.startsWith("nl-data:"));if(!o)throw new Error("nl-data group is required on sandboxed Linux");const r=Number(o.split(":")[2]);if(!Number.isInteger(r))throw new Error("invalid nl-data group id");return r}n(p,"dataGroup");function L(){const o=y(),r=p();u(o,{recursive:!0,mode:1528});const e=h(o),t=e.mode&4095;if(!e.isDirectory()||e.gid!==r||t!==1528){if(!e.isDirectory()||e.uid!==process.getuid())throw new Error(`${o} has owner ${e.uid}, group ${e.gid}, mode ${t.toString(8).padStart(4,"0")}; requires an nl-data (${r}) directory with mode 2770; only its owner can repair it`);e.gid!==r&&d(o,e.uid,r),t!==1528&&a(o,1528)}}n(L,"ensureUserFiles");async function N(o){const r=g(o);if(!(process.platform==="linux"&&m(x))){if(process.platform==="linux")throw new Error("app space requires the root launcher on Linux");for(const i of[r.root,r.memory,r.conversations,r.nodes,r.files,r.home])u(i,{recursive:!0});return{uid:v(o),gid:process.getgid(),root:r.root}}const t=p(),s=E(o),c=await S({operation:"user.create",app:r.root.slice(w().length+1),uid:s.uid});if(!("uid"in c)||c.uid!==s.uid)throw new Error(`launcher did not create OS user for ${o}`);for(const i of[r.root,r.memory,r.conversations,r.nodes,r.files,r.home])u(i,{recursive:!0,mode:1528}),d(i,process.getuid(),t),a(i,1528);return{uid:s.uid,gid:t,root:r.root}}n(N,"ensureAppSpace");export{N as ensureAppSpace,L as ensureUserFiles};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type TeardownResult } from '../runtime/host.js';
|
|
2
|
+
/** Stop the broker first so it cannot start another job during the job scan. */
|
|
3
|
+
export declare function stopNodeSandboxes(nodeId: string, reason: string, options?: {
|
|
4
|
+
excludePid?: number;
|
|
5
|
+
after?: () => Promise<void>;
|
|
6
|
+
deleting?: boolean;
|
|
7
|
+
holdRecovery?: boolean;
|
|
8
|
+
}): Promise<TeardownResult>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var v=Object.defineProperty;var f=(e,n)=>v(e,"name",{value:n,configurable:!0});import{randomUUID as h}from"node:crypto";import{activeBackgroundBashJobs as R,bashJobPaths as _,stopBackgroundBashJob as D}from"../bash-jobs.js";import{getNode as T}from"../canvas/index.js";import{openDb as $}from"../canvas/db.js";import{readLiveSession as B}from"../canvas/sessions.js";import{contextDir as N}from"../canvas/node-agent-paths.js";import{conversationStore as x}from"../conversation-store/index.js";import{enqueueNodeMail as J}from"../feed/messages.js";import{requestBrokerTeardown as L}from"../runtime/host.js";import{holdRecovery as M}from"../runtime/recovery-hold.js";const d=new Map;function Y(e,n,r={}){const b=d.get(e);if(b)return b;const u=T(e);if(!u)return Promise.resolve({confirmed:!1,error:new Error(`missing node ${e}`)});const m=B(e)?.sessionId,g=f(()=>$().prepare(`SELECT type, body_json FROM run_events WHERE node_id = ?
|
|
2
|
+
AND type IN ('node.turn.started', 'node.turn.completed') ORDER BY sequence_number DESC LIMIT 1`).get(e),"latestTurn"),w=u.run_id!==null&&u.pi_pid!==null&&g()?.type==="node.turn.started",j=r.holdRecovery?M(e):()=>{},k=L(e,{excludePid:r.excludePid}),i=(async()=>{const c=await k;if(!c.confirmed)return c;try{const o=N(e);for(const t of R(o,!0)){const s=await D(o,t.jobId,!0,e,n);if(s.kind==="not-stoppable")throw new Error(`background bash job ${t.jobId} could not be stopped`);if(s.kind!=="stopped"||r.deleting)continue;const p=_(o,t.jobId),a=`Background bash job ${t.jobId} stopped: ${n}. Log: ${p.jobLog} Command: ${p.cmdSh}`;J(e,{senderNodeId:null,urgency:"urgent",wake:0,kind:"message",label:a.slice(0,120),bodyJson:{body:a},idempotencyKey:`bash-stopped:${e}:${t.jobId}`})}if(w&&m&&!r.deleting){const t=g(),s=t?.type==="node.turn.started",p=t?.type==="node.turn.completed"&&JSON.parse(t.body_json).stop_reason==="aborted";if(!s&&!p)return await r.after?.(),c;const a=x(),{entries:E}=a.read(m),S=E.at(-1),y=new Date().toISOString(),l={type:"message",id:h(),parentId:S?.id??null,timestamp:y,message:{role:"assistant",content:[],api:"openai-completions",provider:"crouter",model:"",usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"error",errorMessage:n,timestamp:Date.now()}};a.append(m,s?[l,{type:"custom",id:h(),parentId:l.id,timestamp:y,customType:"crtr-turn-end",data:{stop_reason:"error"}}]:[l])}return await r.after?.(),c}catch(o){return{confirmed:!1,error:o instanceof Error?o:new Error(String(o))}}})();return d.set(e,i),i.finally(()=>{j(),d.get(e)===i&&d.delete(e)}),i}f(Y,"stopNodeSandboxes");export{Y as stopNodeSandboxes};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface AppUser {
|
|
2
|
+
app: string;
|
|
3
|
+
uid: number;
|
|
4
|
+
created: string;
|
|
5
|
+
status: 'active' | 'removed';
|
|
6
|
+
}
|
|
7
|
+
/** The launcher is absent on macOS; there is no app uid on that host. */
|
|
8
|
+
export declare function uidForApp(app: string): number;
|
|
9
|
+
/** An app has at most one active row. A removed app that reconnects gets a new
|
|
10
|
+
* row above every uid ever allocated, so a uid is never reused. */
|
|
11
|
+
export declare function allocateAppUser(app: string): AppUser;
|
|
12
|
+
export declare function activeAppUsers(): Array<{
|
|
13
|
+
app: string;
|
|
14
|
+
uid: number;
|
|
15
|
+
}>;
|
|
16
|
+
/** The app's OS-user row not yet marked removed, if any. */
|
|
17
|
+
export declare function activeAppUser(app: string): AppUser | null;
|
|
18
|
+
/** The removal cascade's last write (runtime spec, "On removal"). */
|
|
19
|
+
export declare function markAppUserRemoved(uid: number): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var c=Object.defineProperty;var r=(e,t)=>c(e,"name",{value:t,configurable:!0});import{existsSync as E}from"node:fs";import{openDb as u,withCanvasWrite as i}from"../canvas/db.js";import{APP_UID_MAX as d,APP_UID_MIN as n,LAUNCHER_SOCKET as A}from"../../launcher/spec.js";function v(e){return process.platform!=="linux"||!E(A)?process.getuid?.()??0:S(e).uid}r(v,"uidForApp");function S(e){if(process.platform!=="linux")throw new Error("app OS users exist only on Linux");return i(t=>{const a=t.prepare("SELECT app, uid, created, status FROM app_users WHERE app = ? AND status = 'active'").get(e);if(a)return a;const o=t.prepare("SELECT MAX(uid) AS uid FROM app_users").get().uid,p=Math.max(n,(o??n-1)+1);if(p>d)throw new Error("app OS user range exhausted");const s=new Date().toISOString();return t.prepare("INSERT INTO app_users (app, uid, created, status) VALUES (?, ?, ?, ?)").run(e,p,s,"active"),{app:e,uid:p,created:s,status:"active"}})}r(S,"allocateAppUser");function _(){return u().prepare("SELECT app, uid FROM app_users WHERE status = 'active'").all().map(t=>({app:t.app.startsWith("app:")?t.app.slice(4):t.app,uid:t.uid}))}r(_,"activeAppUsers");function R(e){return u().prepare("SELECT app, uid, created, status FROM app_users WHERE app = ? AND status = 'active'").get(e)??null}r(R,"activeAppUser");function O(e){i(t=>{t.prepare("UPDATE app_users SET status = 'removed', removed_at = ? WHERE uid = ? AND status = 'active'").run(new Date().toISOString(),e)})}r(O,"markAppUserRemoved");export{R as activeAppUser,_ as activeAppUsers,S as allocateAppUser,O as markAppUserRemoved,v as uidForApp};
|
|
@@ -90,6 +90,8 @@ export declare function commitManagedLogin(provider: ManagedProviderId, label: s
|
|
|
90
90
|
autoLabel?: boolean;
|
|
91
91
|
}): Promise<SubscriptionCredential[]>;
|
|
92
92
|
export declare function parseRetryAfterHeader(value: string | undefined, now?: number): number | undefined;
|
|
93
|
+
export declare function retryAfterMsFromHeaders(headers: Headers | Record<string, string> | undefined): number | undefined;
|
|
94
|
+
export declare function retryAfterMsFromError(error: unknown): number | undefined;
|
|
93
95
|
export declare function readRotationConfig(): RotationConfig;
|
|
94
96
|
export declare function writeRotationConfig(next: RotationConfig): RotationConfig;
|
|
95
97
|
export declare function formatStatusLine(provider: ManagedProviderId, now?: number): string;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var B=Object.defineProperty;var s=(t,n)=>B(t,"name",{value:n,configurable:!0});import{createHash as z,randomUUID as
|
|
2
|
-
`)}s(q,"managedCredentialFile");function
|
|
3
|
-
`))}})}s(x,"locked");function S(t,n,e){t.prepare("INSERT INTO managed_accounts(provider_id,id,label,label_key,position,last_attempt_at,last_rate_limited_at,rate_limited_until,auth_failure) VALUES(?,?,?,?,?,?,?,?,?)").run(n,e.id,e.label,e.labelKey,e.position,e.lastAttemptAt,e.lastRateLimitedAt,e.rateLimitedUntil,e.authFailure??null)}s(S,"insert");function I(t,n){t.prepare("UPDATE managed_accounts SET label=?,label_key=?,position=?,last_attempt_at=?,last_rate_limited_at=?,rate_limited_until=?,auth_failure=? WHERE provider_id=? AND id=?").run(n.label,n.labelKey,n.position,n.lastAttemptAt,n.lastRateLimitedAt,n.rateLimitedUntil,n.authFailure??null,n.providerId,n.id)}s(I,"update");function L(t,n){return N(t,n).map(({entry:e})=>e)}s(L,"publicPool");function w(t,n){try{n()}catch(e){throw new Error(`managed ${h(t)} credential file was published, but its SQL membership update failed; SQL membership remains authoritative: ${e instanceof Error?e.message:String(e)}`,{cause:e})}}s(w,"writeMembershipAfterCredentialPublish");async function Lt(t,n){return x(t,async(e,a,r)=>{const i=n.map(d=>$(t,d)),o=i.map((d,u)=>({entry:d,id:a[u]?.row.id??F()})),c={};for(const{entry:d,id:u}of o)c[u]={refresh:d.refresh,access:d.access,expires:d.expires,...d.accountId?{accountId:d.accountId}:{}};return r({version:1,accounts:c}),w(t,()=>A(b(),d=>{d.prepare("DELETE FROM managed_accounts WHERE provider_id=?").run(t),o.forEach(({entry:u,id:m},l)=>S(d,t,{providerId:t,id:m,label:u.label,labelKey:f(u.label),position:l,lastAttemptAt:u.lastAttemptAt,lastRateLimitedAt:u.lastRateLimitedAt,rateLimitedUntil:u.rateLimitedUntil,...u.authFailure?{authFailure:u.authFailure}:{}}))})),i})}s(Lt,"writeSubscriptionPool");function U(t,n){const e=n.trim().toLowerCase(),a=Number.parseInt(e,10);return Number.isFinite(a)&&String(a)===e&&a>=1&&a<=t.length?a-1:t.findIndex(({entry:r})=>f(r.label)===e)}s(U,"resolve");async function it(t,n){const e=$(t,n);return x(t,async(a,r,i)=>{if(r.some(({entry:u})=>f(u.label)===f(e.label)))throw new E(`${h(t)} subscription already exists: ${e.label}`);const o=y(e),c=r.find(({entry:u})=>y(u)===o);if(o&&c)throw new E(`This ${h(t)} account is already added as \u201C${c.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);const d=F();return a.accounts[d]={refresh:e.refresh,access:e.access,expires:e.expires,...e.accountId?{accountId:e.accountId}:{}},i(a),w(t,()=>A(b(),u=>S(u,t,{providerId:t,id:d,label:e.label,labelKey:f(e.label),position:r.length,lastAttemptAt:e.lastAttemptAt,lastRateLimitedAt:e.lastRateLimitedAt,rateLimitedUntil:e.rateLimitedUntil,...e.authFailure?{authFailure:e.authFailure}:{}}))),L(t,a)})}s(it,"addSubscription");async function _t(t,n){const e=$(t,n);return D(t).find(r=>f(r.label)===f(e.label))?st(t,e):it(t,e)}s(_t,"upsertSubscription");async function st(t,n){const e=$(t,n);return x(t,async(a,r,i)=>{const o=r.findIndex(({entry:l})=>f(l.label)===f(e.label)),c=r[o],d=r.find(({entry:l},g)=>g!==o&&y(l)===y(e));if(y(e)&&d)throw new E(`This ${h(t)} account is already added as \u201C${d.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);if(!c){const l=F();return a.accounts[l]={refresh:e.refresh,access:e.access,expires:e.expires,...e.accountId?{accountId:e.accountId}:{}},i(a),w(t,()=>A(b(),g=>S(g,t,{providerId:t,id:l,label:e.label,labelKey:f(e.label),position:r.length,lastAttemptAt:e.lastAttemptAt,lastRateLimitedAt:e.lastRateLimitedAt,rateLimitedUntil:e.rateLimitedUntil}))),L(t,a)}const u=c.row,m=e.lastRateLimitedAt>=u.lastRateLimitedAt;return a.accounts[u.id]={refresh:e.refresh,access:e.access,expires:e.expires,...e.accountId?{accountId:e.accountId}:{}},i(a),w(t,()=>A(b(),l=>I(l,{...u,label:e.label,labelKey:f(e.label),lastAttemptAt:Math.max(u.lastAttemptAt,e.lastAttemptAt),lastRateLimitedAt:m?e.lastRateLimitedAt:u.lastRateLimitedAt,rateLimitedUntil:m?e.rateLimitedUntil:u.rateLimitedUntil}))),L(t,a)})}s(st,"upsertSubscriptionWithUniqueAccount");async function Et(t,n,e){return x(t,async(a,r)=>{const i=U(r,n);if(i<0)throw new Error(`Unknown ${h(t)} subscription: ${n}`);const o=e.trim();if(!o)throw new Error(`${h(t)} subscription label cannot be empty`);if(r.some((c,d)=>d!==i&&f(c.entry.label)===f(o)))throw new E(`${h(t)} subscription already exists: ${o}`);return A(b(),c=>I(c,{...r[i].row,label:o,labelKey:f(o)})),L(t,a)})}s(Et,"renameSubscription");async function M(t,n){return x(t,async(e,a,r)=>{const i=U(a,n);if(i<0)throw new Error(`Unknown ${h(t)} subscription: ${n}`);const o=a[i].row;return A(b(),c=>c.prepare("DELETE FROM managed_accounts WHERE provider_id=? AND id=?").run(t,o.id)),delete e.accounts[o.id],r(e),L(t,e)})}s(M,"remove");async function It(t,n){return M(t,n)}s(It,"removeManagedAccount");async function wt(t,n){return M(t,n)}s(wt,"removeSubscription");async function ct(t){return x(t,async(n,e,a)=>{A(b(),r=>r.prepare("DELETE FROM managed_accounts WHERE provider_id=?").run(t));for(const{row:r}of e)delete n.accounts[r.id];return a(n),e.length})}s(ct,"removeAllManagedAccounts");async function Rt(t,n){return n===void 0?(await ct(t),[]):M(t,n)}s(Rt,"removeManagedProvider");async function $t(t,n){return x(t,async(e,a)=>{const r=U(a,n);if(r<0)throw new Error(`Unknown ${h(t)} subscription: ${n}`);return A(b(),i=>{[a[r],...a.filter((c,d)=>d!==r)].forEach((c,d)=>I(i,{...c.row,position:d}))}),L(t,e)})}s($t,"promoteSubscription");async function T(t,n,e){return A(b(),a=>{const r=Z(a,t,n);if(!r)throw new Error(`Unknown ${h(t)} subscription: ${n}`);const i=e(r);i&&I(a,i)}),D(t)}s(T,"mutateHealth");async function Ft(t,n,e=Date.now()){return T(t,n,a=>({...a,lastAttemptAt:Math.max(a.lastAttemptAt,e)}))}s(Ft,"markSubscriptionAttempt");async function St(t,n,e,a,r=Date.now()){return x(t,async(i,o)=>{const c=o.find(({entry:d})=>f(d.label)===f(n));if(!c)throw new Error(`Unknown ${h(t)} subscription: ${n}`);return c.entry.refresh!==e.refresh||c.entry.access!==e.access||A(b(),d=>I(d,{...c.row,authFailure:"invalid_grant",lastAttemptAt:Math.max(c.row.lastAttemptAt,r),rateLimitedUntil:Math.max(c.row.rateLimitedUntil,r+Math.max(0,a))})),L(t,i)})}s(St,"markSubscriptionAuthenticationFailed");async function Ut(t,n,e,a=Date.now(),r=Date.now()){return T(t,n,i=>r<i.lastRateLimitedAt?null:{...i,lastAttemptAt:Math.max(i.lastAttemptAt,a),lastRateLimitedAt:r,rateLimitedUntil:r+Math.max(0,e)})}s(Ut,"markSubscriptionRateLimited");async function kt(t,n,e=Date.now()){return T(t,n,a=>e<a.lastRateLimitedAt?null:{...a,authFailure:void 0,lastAttemptAt:Math.max(a.lastAttemptAt,e),rateLimitedUntil:0})}s(kt,"markSubscriptionSuccess");async function Nt(t,n,e){return x(t,async(a,r,i)=>{const o=U(r,n);if(o<0)throw new Error(`${h(t)} subscription "${n}" no longer exists`);const c=r[o];if(c.entry.expires>Date.now())return c.entry;const d=V(t,c.entry.label,await e(c.entry.refresh));return a.accounts[c.row.id]={...a.accounts[c.row.id],...d},i(a),{...c.entry,...d}})}s(Nt,"refreshSubscriptionCredential");function ot(t){const n=t,e=[n?.errorMessage,n?.message,t instanceof Error?t.message:""].filter(r=>typeof r=="string").join(" ");return(typeof n?.status=="number"?n.status:Number(e.match(/\bstatus[=:]\s*(\d+)/i)?.[1]))===400&&/invalid_grant|refresh token .*invalid|refresh token .*not found/i.test(e)}s(ot,"isInvalidRefreshTokenError");async function Dt(t,n,e){return x(t,async(a,r,i)=>{const o=new Set;let c;for(;o.size<r.length;){const d=n(r.filter(({entry:m})=>!o.has(m.label)).map(({entry:m})=>m));if(!d)break;const u=r.find(({entry:m})=>m.label===d.label);o.add(u.entry.label);try{const m=await e(u.entry);if(m){const l=V(t,u.entry.label,m);return a.accounts[u.row.id]={...a.accounts[u.row.id],...l},i(a),{...u.entry,...l}}return u.entry}catch(m){if(!ot(m))throw m;c=m;const l=Date.now();A(b(),g=>I(g,{...u.row,authFailure:"invalid_grant",lastAttemptAt:Math.max(u.row.lastAttemptAt,l),rateLimitedUntil:Math.max(u.row.rateLimitedUntil,l+et)}))}}if(c)throw c})}s(Dt,"modifyElectedSubscription");async function lt(t,n){const e=n.accountId?.trim();if(t!==P)return e?{accountId:e}:{};try{const a=await fetch("https://api.anthropic.com/api/oauth/profile",{headers:{Authorization:`Bearer ${n.access}`,Accept:"application/json"},signal:AbortSignal.timeout(3e3)});if(!a.ok)return e?{accountId:e}:{};const r=await a.json(),i=typeof r.account?.uuid=="string"&&r.account.uuid.trim()?r.account.uuid.trim():void 0,o=typeof r.account?.email=="string"&&r.account.email.trim()?r.account.email.trim():void 0;return{...i?{accountId:i}:{},...o?{email:o}:{}}}catch{return e?{accountId:e}:{}}}s(lt,"enrichManagedLoginIdentity");async function Mt(t,n,e){const a=await lt(t,e);return x(t,async(r,i,o)=>{const c=e.autoLabel?void 0:n?.trim(),d=y({refresh:e.refresh,accountId:a.accountId}),u=(c?i.find(({entry:p})=>f(p.label)===f(c)):void 0)??i.find(({entry:p})=>y(p)===d);let m=u?.entry.label??c;if(!m&&e.autoLabel){const p=a.email||n?.trim()||`Account ${i.length+1}`;m=p;for(let R=2;i.some(({entry:_})=>f(_.label)===f(m));R++)m=`${p} (${R})`}if(!m)throw new Error(`${h(t)} subscription label cannot be empty`);const l=$(t,{label:m,refresh:e.refresh,access:e.access,expires:e.expires,...a.accountId?{accountId:a.accountId}:{},rateLimitedUntil:0,lastAttemptAt:Date.now(),lastRateLimitedAt:e.lastRateLimitedAt});if(!u){if(i.some(({entry:_})=>f(_.label)===f(l.label)))throw new E(`${h(t)} subscription already exists: ${l.label}`);const p=i.find(({entry:_})=>y(_)===y(l));if(y(l)&&p)throw new E(`This ${h(t)} account is already added as \u201C${p.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);const R=F();return r.accounts[R]={refresh:l.refresh,access:l.access,expires:l.expires,...l.accountId?{accountId:l.accountId}:{}},o(r),w(t,()=>A(b(),_=>S(_,t,{providerId:t,id:R,label:l.label,labelKey:f(l.label),position:i.length,lastAttemptAt:l.lastAttemptAt,lastRateLimitedAt:l.lastRateLimitedAt,rateLimitedUntil:l.rateLimitedUntil}))),L(t,r)}const g=u.row,O=i.find(({entry:p})=>p.label!==u.entry.label&&y(p)===y(l));if(y(l)&&O)throw new E(`This ${h(t)} account is already added as \u201C${O.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);r.accounts[g.id]={refresh:l.refresh,access:l.access,expires:l.expires,...l.accountId?{accountId:l.accountId}:{}},o(r);const C=l.lastRateLimitedAt>=g.lastRateLimitedAt;return w(t,()=>A(b(),p=>I(p,{...g,authFailure:void 0,lastAttemptAt:Math.max(g.lastAttemptAt,l.lastAttemptAt),lastRateLimitedAt:C?l.lastRateLimitedAt:g.lastRateLimitedAt,rateLimitedUntil:C?0:g.rateLimitedUntil}))),L(t,r)})}s(Mt,"commitManagedLogin");function Tt(t,n=Date.now()){if(!t?.trim())return;const e=Number(t.trim());if(Number.isFinite(e))return Math.max(0,Math.round(e*1e3));const a=Date.parse(t);return Number.isFinite(a)?Math.max(0,a-n):void 0}s(Tt,"parseRetryAfterHeader");function ut(){const t=X(Y(b())).prepare("SELECT default_fallback_strength,revert_when_available FROM rotation_settings WHERE singleton=1").get();return{defaultFallbackStrength:K(t?.default_fallback_strength)??W,revertWhenAvailable:t?.revert_when_available===void 0||t.revert_when_available===null?!0:!!t.revert_when_available}}s(ut,"readRotationConfig");function Ot(t){const n=ut(),e={defaultFallbackStrength:K(t.defaultFallbackStrength)??n.defaultFallbackStrength??W,revertWhenAvailable:t.revertWhenAvailable??n.revertWhenAvailable??!0};return A(b(),a=>a.prepare("INSERT INTO rotation_settings(singleton,default_fallback_strength,revert_when_available) VALUES(1,?,?) ON CONFLICT(singleton) DO UPDATE SET default_fallback_strength=excluded.default_fallback_strength,revert_when_available=excluded.revert_when_available").run(e.defaultFallbackStrength,e.revertWhenAvailable?1:0)),e}s(Ot,"writeRotationConfig");function Ct(t,n=Date.now()){const e=D(t),a=e.filter(i=>i.authFailure===void 0&&i.rateLimitedUntil<=n),r=h(t);return a.length===0?`${r} pool exhausted`:`${r} ${a[0]?.label??t} (${a.length}/${e.length} ready)`}s(Ct,"formatStatusLine");export{P as ANTHROPIC_PROVIDER_ID,E as DuplicateSubscriptionError,et as INVALID_REFRESH_TOKEN_BACKOFF_MS,tt as OPENAI_CODEX_PROVIDER_ID,it as addSubscription,Mt as commitManagedLogin,lt as enrichManagedLoginIdentity,Ct as formatStatusLine,h as getProviderLabel,ot as isInvalidRefreshTokenError,gt as isManagedProvider,Ft as markSubscriptionAttempt,St as markSubscriptionAuthenticationFailed,Ut as markSubscriptionRateLimited,kt as markSubscriptionSuccess,Dt as modifyElectedSubscription,Tt as parseRetryAfterHeader,$t as promoteSubscription,ut as readRotationConfig,D as readSubscriptionPool,Nt as refreshSubscriptionCredential,ct as removeAllManagedAccounts,It as removeManagedAccount,Rt as removeManagedProvider,wt as removeSubscription,Et as renameSubscription,xt as resolveProviderCandidates,_t as upsertSubscription,st as upsertSubscriptionWithUniqueAccount,Ot as writeRotationConfig,Lt as writeSubscriptionPool};
|
|
1
|
+
var B=Object.defineProperty;var s=(t,n)=>B(t,"name",{value:n,configurable:!0});import{createHash as z,randomUUID as $}from"node:crypto";import{join as J}from"node:path";import{brokerConfigSnapshot as Q}from"./config.js";import{LockedJsonFile as G}from"./locked-file.js";import{secretsDir as X}from"./layout.js";import{openScopedStore as Y}from"./scoped-state/db.js";import{providerStore as Z}from"./scoped-state/paths.js";import{providerRowByReference as v,providerRows as tt,providerWrite as A}from"./scoped-state/providers.js";const P="anthropic",et="openai-codex",nt=720*60*60*1e3,H="strong",W={anthropic:{label:"Claude",credentials:"anthropic-credentials.json"},"openai-codex":{label:"OpenAI Codex",credentials:"openai-codex-credentials.json"}};function b(){return X()}s(b,"agentDir");function k(t){return J(b(),W[t].credentials)}s(k,"credentialFile");function j(t){return t==="ultra"||t==="strong"||t==="medium"||t==="light"?t:void 0}s(j,"normalizeStrength");function f(t){return t.toLowerCase()}s(f,"key");function at(t){const n=typeof t.label=="string"?t.label.trim():"",e=typeof t.refresh=="string"?t.refresh.trim():"",a=typeof t.access=="string"?t.access.trim():"",r=Number(t.expires);if(!n||!e||!a||!Number.isFinite(r))return;const i=typeof t.accountId=="string"&&t.accountId.trim()?t.accountId.trim():void 0;return{label:n,refresh:e,access:a,expires:r,rateLimitedUntil:Number.isFinite(Number(t.rateLimitedUntil))?Number(t.rateLimitedUntil):0,lastAttemptAt:Number.isFinite(Number(t.lastAttemptAt))?Number(t.lastAttemptAt):0,lastRateLimitedAt:Number.isFinite(Number(t.lastRateLimitedAt))?Number(t.lastRateLimitedAt):0,...t.authFailure==="invalid_grant"?{authFailure:"invalid_grant"}:{},...i?{accountId:i}:{}}}s(at,"credential");function F(t,n){if(!n.label?.trim())throw new Error(`${h(t)} subscription label cannot be empty`);const e=at(n);if(!e)throw new Error(`Refusing to persist incomplete ${h(t)} subscription "${n.label.trim()}"; pool rows require both OAuth tokens.`);return e}s(F,"assertCredential");function K(t,n){if(!n||n.trim()==="")return{version:1,accounts:{}};let e;try{e=JSON.parse(n)}catch(a){throw new Error(`managed credential file ${t} is corrupt: ${a instanceof Error?a.message:String(a)}`)}if(typeof e!="object"||e===null||Array.isArray(e)||e.version!==1||typeof e.accounts!="object"||e.accounts===null||Array.isArray(e.accounts))throw new Error(`managed credential file ${t} is corrupt`);return e}s(K,"parseCredentials");function rt(t,n){const e=n.accounts[t.id];if(!e||typeof e.refresh!="string"||typeof e.access!="string"||!Number.isFinite(e.expires))throw new Error(`managed ${t.providerId} account ${t.id} has no credential record`);return{label:t.label,refresh:e.refresh,access:e.access,expires:e.expires,rateLimitedUntil:t.rateLimitedUntil,lastAttemptAt:t.lastAttemptAt,lastRateLimitedAt:t.lastRateLimitedAt,...t.authFailure?{authFailure:t.authFailure}:{},...e.accountId?{accountId:e.accountId}:{}}}s(rt,"toPublic");function N(t,n){return tt(b(),t).map(e=>({row:e,entry:rt(e,n)}))}s(N,"rowsWithCredentials");function q(t){return new G(k(t),!0,`{"version":1,"accounts":{}}
|
|
2
|
+
`)}s(q,"managedCredentialFile");function it(t){return K(k(t),q(t).readUnlocked())}s(it,"readFile");function y(t){return t.accountId?.trim()||(t.refresh.trim()?`refresh:${z("sha256").update(t.refresh.trim()).digest("hex")}`:void 0)}s(y,"identity");function V(t,n,e){const a=e.refresh?.trim()??"",r=e.access?.trim()??"",i=Number(e.expires);if(!a||!r||!Number.isFinite(i))throw new Error(`${h(t)} subscription "${n}" returned an incomplete credential; the stored credential was left unchanged.`);return{refresh:a,access:r,expires:i}}s(V,"assertTokens");function Et(t){return t===P||t===et}s(Et,"isManagedProvider");function h(t){return W[t].label}s(h,"getProviderLabel");function It(t,n=Date.now(),e={}){const a=[],r=[];for(let i=0;i<t.length;i++){const o=t[i],c=o.registered?o.automaticFallback===!1?"non-managed-fallback":o.authenticated?(o.coolingUntil??0)>n?"cooling":void 0:"unauthenticated":"unregistered";if(!c)a.push(o);else if(r.push({candidate:o,reason:c}),e.pinnedToFirst&&i===0&&c!=="cooling")break}return{candidates:a,rejected:r}}s(It,"resolveProviderCandidates");class E extends Error{static{s(this,"DuplicateSubscriptionError")}constructor(n){super(n),this.name="DuplicateSubscriptionError"}}function D(t){return N(t,it(t)).map(({entry:n})=>n)}s(D,"readSubscriptionPool");async function x(t,n){const e=k(t);return q(t).withLockAsync(async(a,r,i)=>{const o=K(e,a);return{result:await n(o,N(t,o),c=>i(`${JSON.stringify(c)}
|
|
3
|
+
`))}})}s(x,"locked");function S(t,n,e){t.prepare("INSERT INTO managed_accounts(provider_id,id,label,label_key,position,last_attempt_at,last_rate_limited_at,rate_limited_until,auth_failure) VALUES(?,?,?,?,?,?,?,?,?)").run(n,e.id,e.label,e.labelKey,e.position,e.lastAttemptAt,e.lastRateLimitedAt,e.rateLimitedUntil,e.authFailure??null)}s(S,"insert");function I(t,n){t.prepare("UPDATE managed_accounts SET label=?,label_key=?,position=?,last_attempt_at=?,last_rate_limited_at=?,rate_limited_until=?,auth_failure=? WHERE provider_id=? AND id=?").run(n.label,n.labelKey,n.position,n.lastAttemptAt,n.lastRateLimitedAt,n.rateLimitedUntil,n.authFailure??null,n.providerId,n.id)}s(I,"update");function L(t,n){return N(t,n).map(({entry:e})=>e)}s(L,"publicPool");function w(t,n){try{n()}catch(e){throw new Error(`managed ${h(t)} credential file was published, but its SQL membership update failed; SQL membership remains authoritative: ${e instanceof Error?e.message:String(e)}`,{cause:e})}}s(w,"writeMembershipAfterCredentialPublish");async function wt(t,n){return x(t,async(e,a,r)=>{const i=n.map(d=>F(t,d)),o=i.map((d,u)=>({entry:d,id:a[u]?.row.id??$()})),c={};for(const{entry:d,id:u}of o)c[u]={refresh:d.refresh,access:d.access,expires:d.expires,...d.accountId?{accountId:d.accountId}:{}};return r({version:1,accounts:c}),w(t,()=>A(b(),d=>{d.prepare("DELETE FROM managed_accounts WHERE provider_id=?").run(t),o.forEach(({entry:u,id:m},l)=>S(d,t,{providerId:t,id:m,label:u.label,labelKey:f(u.label),position:l,lastAttemptAt:u.lastAttemptAt,lastRateLimitedAt:u.lastRateLimitedAt,rateLimitedUntil:u.rateLimitedUntil,...u.authFailure?{authFailure:u.authFailure}:{}}))})),i})}s(wt,"writeSubscriptionPool");function U(t,n){const e=n.trim().toLowerCase(),a=Number.parseInt(e,10);return Number.isFinite(a)&&String(a)===e&&a>=1&&a<=t.length?a-1:t.findIndex(({entry:r})=>f(r.label)===e)}s(U,"resolve");async function st(t,n){const e=F(t,n);return x(t,async(a,r,i)=>{if(r.some(({entry:u})=>f(u.label)===f(e.label)))throw new E(`${h(t)} subscription already exists: ${e.label}`);const o=y(e),c=r.find(({entry:u})=>y(u)===o);if(o&&c)throw new E(`This ${h(t)} account is already added as \u201C${c.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);const d=$();return a.accounts[d]={refresh:e.refresh,access:e.access,expires:e.expires,...e.accountId?{accountId:e.accountId}:{}},i(a),w(t,()=>A(b(),u=>S(u,t,{providerId:t,id:d,label:e.label,labelKey:f(e.label),position:r.length,lastAttemptAt:e.lastAttemptAt,lastRateLimitedAt:e.lastRateLimitedAt,rateLimitedUntil:e.rateLimitedUntil,...e.authFailure?{authFailure:e.authFailure}:{}}))),L(t,a)})}s(st,"addSubscription");async function Rt(t,n){const e=F(t,n);return D(t).find(r=>f(r.label)===f(e.label))?ct(t,e):st(t,e)}s(Rt,"upsertSubscription");async function ct(t,n){const e=F(t,n);return x(t,async(a,r,i)=>{const o=r.findIndex(({entry:l})=>f(l.label)===f(e.label)),c=r[o],d=r.find(({entry:l},g)=>g!==o&&y(l)===y(e));if(y(e)&&d)throw new E(`This ${h(t)} account is already added as \u201C${d.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);if(!c){const l=$();return a.accounts[l]={refresh:e.refresh,access:e.access,expires:e.expires,...e.accountId?{accountId:e.accountId}:{}},i(a),w(t,()=>A(b(),g=>S(g,t,{providerId:t,id:l,label:e.label,labelKey:f(e.label),position:r.length,lastAttemptAt:e.lastAttemptAt,lastRateLimitedAt:e.lastRateLimitedAt,rateLimitedUntil:e.rateLimitedUntil}))),L(t,a)}const u=c.row,m=e.lastRateLimitedAt>=u.lastRateLimitedAt;return a.accounts[u.id]={refresh:e.refresh,access:e.access,expires:e.expires,...e.accountId?{accountId:e.accountId}:{}},i(a),w(t,()=>A(b(),l=>I(l,{...u,label:e.label,labelKey:f(e.label),lastAttemptAt:Math.max(u.lastAttemptAt,e.lastAttemptAt),lastRateLimitedAt:m?e.lastRateLimitedAt:u.lastRateLimitedAt,rateLimitedUntil:m?e.rateLimitedUntil:u.rateLimitedUntil}))),L(t,a)})}s(ct,"upsertSubscriptionWithUniqueAccount");async function Ft(t,n,e){return x(t,async(a,r)=>{const i=U(r,n);if(i<0)throw new Error(`Unknown ${h(t)} subscription: ${n}`);const o=e.trim();if(!o)throw new Error(`${h(t)} subscription label cannot be empty`);if(r.some((c,d)=>d!==i&&f(c.entry.label)===f(o)))throw new E(`${h(t)} subscription already exists: ${o}`);return A(b(),c=>I(c,{...r[i].row,label:o,labelKey:f(o)})),L(t,a)})}s(Ft,"renameSubscription");async function M(t,n){return x(t,async(e,a,r)=>{const i=U(a,n);if(i<0)throw new Error(`Unknown ${h(t)} subscription: ${n}`);const o=a[i].row;return A(b(),c=>c.prepare("DELETE FROM managed_accounts WHERE provider_id=? AND id=?").run(t,o.id)),delete e.accounts[o.id],r(e),L(t,e)})}s(M,"remove");async function $t(t,n){return M(t,n)}s($t,"removeManagedAccount");async function St(t,n){return M(t,n)}s(St,"removeSubscription");async function ot(t){return x(t,async(n,e,a)=>{A(b(),r=>r.prepare("DELETE FROM managed_accounts WHERE provider_id=?").run(t));for(const{row:r}of e)delete n.accounts[r.id];return a(n),e.length})}s(ot,"removeAllManagedAccounts");async function Ut(t,n){return n===void 0?(await ot(t),[]):M(t,n)}s(Ut,"removeManagedProvider");async function kt(t,n){return x(t,async(e,a)=>{const r=U(a,n);if(r<0)throw new Error(`Unknown ${h(t)} subscription: ${n}`);return A(b(),i=>{[a[r],...a.filter((c,d)=>d!==r)].forEach((c,d)=>I(i,{...c.row,position:d}))}),L(t,e)})}s(kt,"promoteSubscription");async function T(t,n,e){return A(b(),a=>{const r=v(a,t,n);if(!r)throw new Error(`Unknown ${h(t)} subscription: ${n}`);const i=e(r);i&&I(a,i)}),D(t)}s(T,"mutateHealth");async function Nt(t,n,e=Date.now()){return T(t,n,a=>({...a,lastAttemptAt:Math.max(a.lastAttemptAt,e)}))}s(Nt,"markSubscriptionAttempt");async function Dt(t,n,e,a,r=Date.now()){return x(t,async(i,o)=>{const c=o.find(({entry:d})=>f(d.label)===f(n));if(!c)throw new Error(`Unknown ${h(t)} subscription: ${n}`);return c.entry.refresh!==e.refresh||c.entry.access!==e.access||A(b(),d=>I(d,{...c.row,authFailure:"invalid_grant",lastAttemptAt:Math.max(c.row.lastAttemptAt,r),rateLimitedUntil:Math.max(c.row.rateLimitedUntil,r+Math.max(0,a))})),L(t,i)})}s(Dt,"markSubscriptionAuthenticationFailed");async function Mt(t,n,e,a=Date.now(),r=Date.now()){return T(t,n,i=>r<i.lastRateLimitedAt?null:{...i,lastAttemptAt:Math.max(i.lastAttemptAt,a),lastRateLimitedAt:r,rateLimitedUntil:r+Math.max(0,e)})}s(Mt,"markSubscriptionRateLimited");async function Tt(t,n,e=Date.now()){return T(t,n,a=>e<a.lastRateLimitedAt?null:{...a,authFailure:void 0,lastAttemptAt:Math.max(a.lastAttemptAt,e),rateLimitedUntil:0})}s(Tt,"markSubscriptionSuccess");async function Ct(t,n,e){return x(t,async(a,r,i)=>{const o=U(r,n);if(o<0)throw new Error(`${h(t)} subscription "${n}" no longer exists`);const c=r[o];if(c.entry.expires>Date.now())return c.entry;const d=V(t,c.entry.label,await e(c.entry.refresh));return a.accounts[c.row.id]={...a.accounts[c.row.id],...d},i(a),{...c.entry,...d}})}s(Ct,"refreshSubscriptionCredential");function lt(t){const n=t,e=[n?.errorMessage,n?.message,t instanceof Error?t.message:""].filter(r=>typeof r=="string").join(" ");return(typeof n?.status=="number"?n.status:Number(e.match(/\bstatus[=:]\s*(\d+)/i)?.[1]))===400&&/invalid_grant|refresh token .*invalid|refresh token .*not found/i.test(e)}s(lt,"isInvalidRefreshTokenError");async function Ot(t,n,e){return x(t,async(a,r,i)=>{const o=new Set;let c;for(;o.size<r.length;){const d=n(r.filter(({entry:m})=>!o.has(m.label)).map(({entry:m})=>m));if(!d)break;const u=r.find(({entry:m})=>m.label===d.label);o.add(u.entry.label);try{const m=await e(u.entry);if(m){const l=V(t,u.entry.label,m);return a.accounts[u.row.id]={...a.accounts[u.row.id],...l},i(a),{...u.entry,...l}}return u.entry}catch(m){if(!lt(m))throw m;c=m;const l=Date.now();A(b(),g=>I(g,{...u.row,authFailure:"invalid_grant",lastAttemptAt:Math.max(u.row.lastAttemptAt,l),rateLimitedUntil:Math.max(u.row.rateLimitedUntil,l+nt)}))}}if(c)throw c})}s(Ot,"modifyElectedSubscription");async function ut(t,n){const e=n.accountId?.trim();if(t!==P)return e?{accountId:e}:{};try{const a=await fetch("https://api.anthropic.com/api/oauth/profile",{headers:{Authorization:`Bearer ${n.access}`,Accept:"application/json"},signal:AbortSignal.timeout(3e3)});if(!a.ok)return e?{accountId:e}:{};const r=await a.json(),i=typeof r.account?.uuid=="string"&&r.account.uuid.trim()?r.account.uuid.trim():void 0,o=typeof r.account?.email=="string"&&r.account.email.trim()?r.account.email.trim():void 0;return{...i?{accountId:i}:{},...o?{email:o}:{}}}catch{return e?{accountId:e}:{}}}s(ut,"enrichManagedLoginIdentity");async function Pt(t,n,e){const a=await ut(t,e);return x(t,async(r,i,o)=>{const c=e.autoLabel?void 0:n?.trim(),d=y({refresh:e.refresh,accountId:a.accountId}),u=(c?i.find(({entry:p})=>f(p.label)===f(c)):void 0)??i.find(({entry:p})=>y(p)===d);let m=u?.entry.label??c;if(!m&&e.autoLabel){const p=a.email||n?.trim()||`Account ${i.length+1}`;m=p;for(let R=2;i.some(({entry:_})=>f(_.label)===f(m));R++)m=`${p} (${R})`}if(!m)throw new Error(`${h(t)} subscription label cannot be empty`);const l=F(t,{label:m,refresh:e.refresh,access:e.access,expires:e.expires,...a.accountId?{accountId:a.accountId}:{},rateLimitedUntil:0,lastAttemptAt:Date.now(),lastRateLimitedAt:e.lastRateLimitedAt});if(!u){if(i.some(({entry:_})=>f(_.label)===f(l.label)))throw new E(`${h(t)} subscription already exists: ${l.label}`);const p=i.find(({entry:_})=>y(_)===y(l));if(y(l)&&p)throw new E(`This ${h(t)} account is already added as \u201C${p.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);const R=$();return r.accounts[R]={refresh:l.refresh,access:l.access,expires:l.expires,...l.accountId?{accountId:l.accountId}:{}},o(r),w(t,()=>A(b(),_=>S(_,t,{providerId:t,id:R,label:l.label,labelKey:f(l.label),position:i.length,lastAttemptAt:l.lastAttemptAt,lastRateLimitedAt:l.lastRateLimitedAt,rateLimitedUntil:l.rateLimitedUntil}))),L(t,r)}const g=u.row,C=i.find(({entry:p})=>p.label!==u.entry.label&&y(p)===y(l));if(y(l)&&C)throw new E(`This ${h(t)} account is already added as \u201C${C.entry.label}\u201D \u2014 it shares the same quota, so a second slot adds no redundancy.`);r.accounts[g.id]={refresh:l.refresh,access:l.access,expires:l.expires,...l.accountId?{accountId:l.accountId}:{}},o(r);const O=l.lastRateLimitedAt>=g.lastRateLimitedAt;return w(t,()=>A(b(),p=>I(p,{...g,authFailure:void 0,lastAttemptAt:Math.max(g.lastAttemptAt,l.lastAttemptAt),lastRateLimitedAt:O?l.lastRateLimitedAt:g.lastRateLimitedAt,rateLimitedUntil:O?0:g.rateLimitedUntil}))),L(t,r)})}s(Pt,"commitManagedLogin");function dt(t,n=Date.now()){if(!t?.trim())return;const e=Number(t.trim());if(Number.isFinite(e))return Math.max(0,Math.round(e*1e3));const a=Date.parse(t);return Number.isFinite(a)?Math.max(0,a-n):void 0}s(dt,"parseRetryAfterHeader");function mt(t){if(!t)return;const n=s(a=>t instanceof Headers?t.get(a)??void 0:Object.entries(t).find(([r])=>r.toLowerCase()===a)?.[1],"get"),e=n("retry-after-ms");return e!==void 0&&e.trim()!==""&&Number.isFinite(Number(e))?Math.max(0,Number(e)):dt(n("retry-after"))}s(mt,"retryAfterMsFromHeaders");function Ht(t){if(!t||typeof t!="object"||!("headers"in t))return;const n=t.headers;if(!(!(n instanceof Headers)&&(!n||typeof n!="object"||Array.isArray(n))))return mt(n)}s(Ht,"retryAfterMsFromError");function ft(){const t=Q();if(t)return t.rotation;const n=Y(Z(b())).prepare("SELECT default_fallback_strength,revert_when_available FROM rotation_settings WHERE singleton=1").get();return{defaultFallbackStrength:j(n?.default_fallback_strength)??H,revertWhenAvailable:n?.revert_when_available===void 0||n.revert_when_available===null?!0:!!n.revert_when_available}}s(ft,"readRotationConfig");function Wt(t){const n=ft(),e={defaultFallbackStrength:j(t.defaultFallbackStrength)??n.defaultFallbackStrength??H,revertWhenAvailable:t.revertWhenAvailable??n.revertWhenAvailable??!0};return A(b(),a=>a.prepare("INSERT INTO rotation_settings(singleton,default_fallback_strength,revert_when_available) VALUES(1,?,?) ON CONFLICT(singleton) DO UPDATE SET default_fallback_strength=excluded.default_fallback_strength,revert_when_available=excluded.revert_when_available").run(e.defaultFallbackStrength,e.revertWhenAvailable?1:0)),e}s(Wt,"writeRotationConfig");function jt(t,n=Date.now()){const e=D(t),a=e.filter(i=>i.authFailure===void 0&&i.rateLimitedUntil<=n),r=h(t);return a.length===0?`${r} pool exhausted`:`${r} ${a[0]?.label??t} (${a.length}/${e.length} ready)`}s(jt,"formatStatusLine");export{P as ANTHROPIC_PROVIDER_ID,E as DuplicateSubscriptionError,nt as INVALID_REFRESH_TOKEN_BACKOFF_MS,et as OPENAI_CODEX_PROVIDER_ID,st as addSubscription,Pt as commitManagedLogin,ut as enrichManagedLoginIdentity,jt as formatStatusLine,h as getProviderLabel,lt as isInvalidRefreshTokenError,Et as isManagedProvider,Nt as markSubscriptionAttempt,Dt as markSubscriptionAuthenticationFailed,Mt as markSubscriptionRateLimited,Tt as markSubscriptionSuccess,Ot as modifyElectedSubscription,dt as parseRetryAfterHeader,kt as promoteSubscription,ft as readRotationConfig,D as readSubscriptionPool,Ct as refreshSubscriptionCredential,ot as removeAllManagedAccounts,$t as removeManagedAccount,Ut as removeManagedProvider,St as removeSubscription,Ft as renameSubscription,It as resolveProviderCandidates,Ht as retryAfterMsFromError,mt as retryAfterMsFromHeaders,Rt as upsertSubscription,ct as upsertSubscriptionWithUniqueAccount,Wt as writeRotationConfig,wt as writeSubscriptionPool};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var g=Object.defineProperty;var s=(e,n)=>g(e,"name",{value:n,configurable:!0});import{isDocKind as
|
|
1
|
+
var g=Object.defineProperty;var s=(e,n)=>g(e,"name",{value:n,configurable:!0});import{isDocKind as m,parseSubstrateFrontmatter as b,PRIVACY_LEVELS as y,SURFACE_EVENTS as f,SURFACE_RUNGS as h}from"./schema.js";const S=["system-prompt-visibility","file-read-visibility","applies-to","read-when"],v=["on","match","match-frontmatter","gate","at"],p=["length","broad-memory-read","orphan"];function $(e){if(e===void 0)return null;if(!Array.isArray(e))return`invalid surfaces: ${JSON.stringify(e)} (expected a list of {on, at, match?, match-frontmatter?, gate?} entries)`;for(const n of e){if(n===null||typeof n!="object"||Array.isArray(n))return`invalid surfaces entry: ${JSON.stringify(n)} (expected an {on, at, match?, match-frontmatter?, gate?} object)`;const r=n;for(const i of Object.keys(r))if(!v.includes(i))return`invalid surfaces entry: unknown key \`${i}\` (an entry carries only on, match, match-frontmatter, gate, at)`;const t=r.on;if(typeof t!="string"||!f.includes(t))return`invalid surfaces entry \`on\`: ${JSON.stringify(t)} (expected ${f.join("|")})`;const c=r.at;if(typeof c!="string"||!h.includes(c))return`invalid surfaces entry \`at\`: ${JSON.stringify(c)} (expected ${h.join("|")})`;let u=!1;if(r.match!==void 0){if(t==="boot"||t==="workspace-open")return`invalid surfaces entry: \`match\` is meaningless on \`${t}\` \u2014 the entry's presence is the match; drop it`;const i=r.match,d=typeof i=="string"?[i]:Array.isArray(i)&&i.every(l=>typeof l=="string")?i:null;if(d===null||d.length===0||d.some(l=>l.trim()===""))return`invalid surfaces entry \`match\`: ${JSON.stringify(i)} (expected a non-empty glob or non-empty glob list)`;u=!0}const a=r["match-frontmatter"];if(a!==void 0){if(t!=="read")return"invalid surfaces entry: `match-frontmatter` is a `read`-event predicate only";if(a===null||typeof a!="object"||Array.isArray(a))return`invalid surfaces entry \`match-frontmatter\`: ${JSON.stringify(a)} (expected a field\u2192matcher object)`}if((t==="read"||t==="memory-read"||t==="command"||t==="pre-command")&&!u&&a===void 0)return`invalid surfaces entry: a \`${t}\` entry requires \`match\`${t==="read"?" or `match-frontmatter`":""}`;const o=r.gate;if(o!==void 0&&(o===null||typeof o!="object"||Array.isArray(o)))return`invalid surfaces entry \`gate\`: ${JSON.stringify(o)} (expected a field\u2192matcher object)`}return null}s($,"lintSubstrateSurfaces");function w(e){if(e===null)return"missing frontmatter: a memory store doc requires `kind: knowledge|preference`";if(!m(e.kind))return`invalid kind: ${JSON.stringify(e.kind)} (expected knowledge|preference)`;if("when"in e||"why"in e)return'retired `when`/`why` keys: merge them into one `when-and-why-to-read` line \u2014 "When <circumstance>, this <kind> should be read because <broader downstream payoff>." WHY is the benefit unlocked by reading, not the document summary, rule, or obedience rationale.';if(typeof e["when-and-why-to-read"]!="string"||e["when-and-why-to-read"].trim()==="")return'missing `when-and-why-to-read`: one routing line \u2014 "When <circumstance>, this <kind> should be read because <broader downstream payoff>." WHY is the benefit unlocked by reading, not the document summary, rule, or obedience rationale.';for(const r of S)if(r in e)return`retired \`${r}\` key: the visibility axes were replaced by \`surfaces\` event routing \u2014 run \`crtr sys migrate\` to convert old-format docs, or author \`surfaces\` entries by hand (\`crtr memory write -h\`)`;if("privacy"in e&&!y.includes(e.privacy))return`invalid privacy: ${JSON.stringify(e.privacy)} (expected ${y.join("|")})`;if(e.unlisted!==void 0&&typeof e.unlisted!="boolean")return`invalid unlisted: ${JSON.stringify(e.unlisted)} (expected a boolean)`;const n=$(e.surfaces);if(n!==null)return n;if(e.gate!==void 0&&(e.gate===null||typeof e.gate!="object"||Array.isArray(e.gate)))return`invalid gate: ${JSON.stringify(e.gate)} (expected a field\u2192matcher object)`;if(e.slash!==void 0&&typeof e.slash!="boolean")return`invalid slash: ${JSON.stringify(e.slash)} (expected a boolean)`;if(e.rationale!==void 0&&typeof e.rationale!="string")return`invalid rationale: ${JSON.stringify(e.rationale)} (expected a string)`;if(e["lint-ignore"]!==void 0){const r=Array.isArray(e["lint-ignore"])?e["lint-ignore"]:[e["lint-ignore"]];if(r.length===0||!r.every(t=>typeof t=="string"&&p.includes(t)))return`invalid lint-ignore: ${JSON.stringify(e["lint-ignore"])} (suppressible rules: ${p.map(t=>`\`${t}\``).join(", ")})`}return null}s(w,"lintSubstrateFrontmatter");const k=w;function N(e){return b(e)?.surfaces??[]}s(N,"parsedSubstrateSurfaces");export{p as SUPPRESSIBLE_RULES,w as lintSubstrateFrontmatter,k as lintSubstrateSchema,$ as lintSubstrateSurfaces,N as parsedSubstrateSurfaces};
|
|
@@ -11,19 +11,44 @@ export interface ContextExposureState {
|
|
|
11
11
|
/** Canonical identity → ranks loaded from the system and transcript snapshots. */
|
|
12
12
|
exposures: Map<string, ExposureRanks>;
|
|
13
13
|
}
|
|
14
|
+
/** One full document body that entered a context — the analytics memory log's
|
|
15
|
+
* `loaded` event, before it is timestamped and sent. */
|
|
16
|
+
export interface MemoryLoad {
|
|
17
|
+
name: string;
|
|
18
|
+
scope: string;
|
|
19
|
+
}
|
|
14
20
|
export interface ExposureTarget {
|
|
15
21
|
state: ContextExposureState;
|
|
16
22
|
source: ExposureSource;
|
|
23
|
+
/** Present only at real delivery sites; diagnostic renders pass none. */
|
|
24
|
+
loads?: MemoryLoad[];
|
|
25
|
+
}
|
|
26
|
+
/** JSON form exchanged with the daemon after Pi has materialized a baseline. */
|
|
27
|
+
export interface ContextExposureSnapshot {
|
|
28
|
+
preferenceSnapshot: string | null;
|
|
29
|
+
exposures: Record<string, {
|
|
30
|
+
system?: number;
|
|
31
|
+
transcript?: number;
|
|
32
|
+
}>;
|
|
17
33
|
}
|
|
34
|
+
export declare function snapshotContextExposure(state: ContextExposureState): ContextExposureSnapshot;
|
|
35
|
+
export declare function restoreContextExposure(value: ContextExposureSnapshot): ContextExposureState;
|
|
18
36
|
export declare function emptyContextExposureState(): ContextExposureState;
|
|
19
|
-
export declare function exposureTarget(state: ContextExposureState, source: ExposureSource): ExposureTarget;
|
|
37
|
+
export declare function exposureTarget(state: ContextExposureState, source: ExposureSource, loads?: MemoryLoad[]): ExposureTarget;
|
|
20
38
|
export declare function exposedAtOrAbove(state: ContextExposureState, identity: string, rung: Rung): boolean;
|
|
21
39
|
/** The sole delivery mutation: max-fold one loaded identity into its source rank. */
|
|
22
40
|
export declare function registerExposure(target: ExposureTarget, identity: string, rung: Rung): void;
|
|
23
41
|
export declare function contentExposureIdentity(body: string): string | null;
|
|
24
42
|
export declare function documentExposedAtOrAbove(state: ContextExposureState, path: string, body: string, rung: Rung): boolean;
|
|
25
|
-
/** Register both the physical document and its non-empty content alias.
|
|
26
|
-
|
|
43
|
+
/** Register both the physical document and its non-empty content alias. A
|
|
44
|
+
* `content` registration of a body the context did not already hold is a full
|
|
45
|
+
* body entering the context, so it lands in the target's collector. */
|
|
46
|
+
export declare function registerDocumentExposure(target: ExposureTarget, doc: {
|
|
47
|
+
path: string;
|
|
48
|
+
body: string;
|
|
49
|
+
name: string;
|
|
50
|
+
scope: string;
|
|
51
|
+
}, rung: Rung): void;
|
|
27
52
|
/** Forget that a document was delivered into the TRANSCRIPT — both its physical
|
|
28
53
|
* identity and its content alias — while leaving any `system` rank intact,
|
|
29
54
|
* because the system prompt is rebuilt on every agent run and survives
|