@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,4 +1,4 @@
|
|
|
1
|
-
var m=Object.defineProperty;var a=(
|
|
2
|
-
`).filter(c=>c.trim()!=="").slice(-
|
|
1
|
+
var m=Object.defineProperty;var a=(s,t)=>m(s,"name",{value:t,configurable:!0});import{closeSync as p,fstatSync as w,openSync as _,readSync as b}from"node:fs";import{join as C}from"node:path";import{ApiError as u}from"../api/index.js";import{localClient as l}from"../api/node-transport.js";import{apiErrorToCliError as g}from"../core/io.js";import{autostartDisabled as S,ensureDaemon as y}from"../daemon/manage.js";import{DAEMON_STARTUP_WINDOW_MS as v}from"../daemon/startup-policy.js";import{readState as N}from"../core/config.js";import{resolveRemoteCanvasTarget as T}from"../core/remote-canvas-target.js";import{RemoteCanvasSource as A}from"../core/canvas/remote-canvas-source.js";import{crtrHome as M}from"../core/canvas/paths.js";function f(s){return{...s,fault:s.fault??null}}a(f,"withRowFault");function I(s,t){throw s instanceof u?g(s,t):s}a(I,"rethrowAsCliError");async function U(s){try{return await h().getNode(s)}catch(t){if(t instanceof u&&t.status===404)return null;I(t)}}a(U,"getNodeOrNull");const O=4096,R=20;function D(){let s;try{s=_(C(M(),"crtrd.log"),"r");const{size:t}=w(s),e=Math.max(0,t-O),i=t-e;if(i<=0)return;const n=Buffer.alloc(i);b(s,n,0,i,e);const o=n.toString("utf8").split(`
|
|
2
|
+
`).filter(c=>c.trim()!=="").slice(-R).join(`
|
|
3
3
|
`).trim();return o===""?void 0:`crtrd.log (tail):
|
|
4
|
-
${o}`}catch{return}finally{if(
|
|
4
|
+
${o}`}catch{return}finally{if(s!==void 0)try{p(s)}catch{}}}a(D,"readColdStartDiagnostic");function h(s){return process.env.CRTR_API_SOCKET?l({autostart:!1,...s?.timeoutMs!==void 0?{timeoutMs:s.timeoutMs}:{}}):S()?l({autostart:!1,...s?.timeoutMs!==void 0?{timeoutMs:s.timeoutMs}:{}}):l({...s?.timeoutMs!==void 0?{timeoutMs:s.timeoutMs}:{},onColdSocket:a(async()=>{y()},"onColdSocket"),coldStartDiagnostic:D,coldStartPollWindowMs:v})}a(h,"cliClient");const E=2e3;class x{static{a(this,"ApiCanvasSource")}client;rosterCache=null;rosterInFlight=null;constructor(t=h()){this.client=t}async roster(){const t=Date.now();return this.rosterCache!==null&&t-this.rosterCache.at<E?this.rosterCache.index:this.rosterInFlight!==null?this.rosterInFlight:(this.rosterInFlight=this.client.canvasRoster().then(e=>{const i={subscriptions:new Map,subscribers:new Map};for(const n of e.edges){const r={node_id:n.to_id,active:n.active,created:n.created},o={node_id:n.from_id,active:n.active,created:n.created},c=i.subscriptions.get(n.from_id);c===void 0?i.subscriptions.set(n.from_id,[r]):c.push(r);const d=i.subscribers.get(n.to_id);d===void 0?i.subscribers.set(n.to_id,[o]):d.push(o)}return this.rosterCache={at:Date.now(),index:i},i}).finally(()=>{this.rosterInFlight=null}),this.rosterInFlight)}async orNull(t){try{return await t()}catch(e){if(e instanceof u&&e.status===404)return null;throw e}}async getNode(t){const e=await this.orNull(()=>this.client.getNode(t));return e===null?null:f(e)}async getRow(t){const e=await this.orNull(()=>this.client.getNode(t));return e===null?null:f(e)}async listNodes(t){const e=t?.status;let i;if(Array.isArray(e)){const n=new Set(e);i=(await this.client.listNodes()).filter(o=>n.has(o.status))}else e!==void 0?i=await this.client.listNodes({status:e}):i=await this.client.listNodes();return i.map(n=>f(n))}async subscriptionsOf(t){return this.roster().then(e=>e.subscriptions.get(t)??[])}async subscribersOf(t){return this.roster().then(e=>e.subscribers.get(t)??[])}async view(t){const e=new Set([t]),i=[],n=(await this.subscriptionsOf(t)).map(r=>r.node_id);for(;n.length>0;){const r=n.shift();if(!e.has(r)){e.add(r),i.push(r);for(const o of await this.subscriptionsOf(r))e.has(o.node_id)||n.push(o.node_id)}}return i}async ticketCountsForNodes(t){return(await this.client.attentionCounts([...t])).counts}async ticketCountsForView(t){return this.ticketCountsForNodes([t,...await this.view(t)])}async hasActiveLiveSubscription(t){const e=(await this.subscriptionsOf(t)).filter(i=>i.active);for(const i of e){const n=await this.getRow(i.node_id);if(n&&(n.status==="active"||n.status==="idle"))return!0}return!1}}function V(s){const t=s?.scope??"user",e=s?.canvasName??N(t).activeCanvas??null;if(!e)return new x;const{previewEndpoint:i,relayToken:n}=T(e,t);return new A(i,n)}a(V,"cliCanvasSource");export{x as ApiCanvasSource,O as COLD_START_DIAGNOSTIC_TAIL_BYTES,V as cliCanvasSource,h as cliClient,U as getNodeOrNull,D as readColdStartDiagnostic,I as rethrowAsCliError};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var o=Object.defineProperty;var r=(e,n)=>o(e,"name",{value:n,configurable:!0});import{InputError as i}from"../core/io.js";function m(){if(process.env.CRTR_API_SOCKET!==void 0)throw new i({error:"permission_error",message:"this command is not available to a node",next:"Run this command from the person's terminal."})}r(m,"requirePersonCli");export{m as requirePersonCli};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Horizontal bar at eighth-cell resolution, `value` scaled against `max` over
|
|
2
|
+
* `cells` columns, padded to exactly `cells`. A non-zero value shows at least
|
|
3
|
+
* one eighth, so it never reads as zero. */
|
|
4
|
+
export declare function hbar(value: number, max: number, cells: number): string;
|
|
5
|
+
/** The fills a stacked bar uses, in order. The last one is for "other". */
|
|
6
|
+
export declare const STACK_FILLS: readonly ["█", "▓", "▒", "░"];
|
|
7
|
+
export declare const OTHER_FILL = "\u259A";
|
|
8
|
+
/** One fill per part: the first four parts take `STACK_FILLS`, any later part
|
|
9
|
+
* takes `OTHER_FILL`. Callers put "other" last. */
|
|
10
|
+
export declare function stackFill(index: number): string;
|
|
11
|
+
/** A bar of exactly `cells` whole cells split by share of the parts' total.
|
|
12
|
+
* Each non-zero part gets at least one cell while cells allow, so a part that
|
|
13
|
+
* exists never disappears from the bar. `fills[i]` defaults to `stackFill(i)`. */
|
|
14
|
+
export declare function stackedBar(parts: readonly number[], cells: number, fills?: readonly string[]): string;
|
|
15
|
+
/** The legend for a stacked bar: "█ opus ▓ sonnet ▒ codex ░ gemini ▚ other". */
|
|
16
|
+
export declare function stackLegend(labels: readonly string[], fills?: readonly string[]): string;
|
|
17
|
+
/** A column chart `rows` high, top row first. Each value is one column of
|
|
18
|
+
* `columnWidth` cells, columns separated by `gap` spaces, scaled to the
|
|
19
|
+
* largest value at eighth-cell resolution. A non-zero value shows at least ▁. */
|
|
20
|
+
export declare function columnChart(values: readonly number[], rows: number, columnWidth?: number, gap?: number): string[];
|
|
21
|
+
/** A log-scale axis from `minMs` to `maxMs` over `cells` columns. */
|
|
22
|
+
export interface LogAxis {
|
|
23
|
+
minMs: number;
|
|
24
|
+
maxMs: number;
|
|
25
|
+
cells: number;
|
|
26
|
+
}
|
|
27
|
+
/** The column (0 … cells−1) for `ms` on a log axis; values outside the axis
|
|
28
|
+
* sit at its end. */
|
|
29
|
+
export declare function logPosition(ms: number, axis: LogAxis): number;
|
|
30
|
+
/** A percentile line on a log axis: `─` from p10 to p90 and `●` at the
|
|
31
|
+
* median, padded to exactly `axis.cells`. One sample (p10 = p90) is one `●`. */
|
|
32
|
+
export declare function percentileLine(stats: {
|
|
33
|
+
p10_ms: number;
|
|
34
|
+
median_ms: number;
|
|
35
|
+
p90_ms: number;
|
|
36
|
+
}, axis: LogAxis): string;
|
|
37
|
+
/** Tick labels placed at their log positions over `axis.cells` columns, each
|
|
38
|
+
* label starting at its tick; a label that would overlap the previous one is
|
|
39
|
+
* dropped. */
|
|
40
|
+
export declare function logAxisLabels(ticks: ReadonlyArray<{
|
|
41
|
+
ms: number;
|
|
42
|
+
label: string;
|
|
43
|
+
}>, axis: LogAxis): string;
|
|
44
|
+
/** A ranked list folded to its first `keep` rows plus the rest as one sum, for
|
|
45
|
+
* "<n> more …" rows. The rest is undefined when nothing is folded. */
|
|
46
|
+
export declare function foldRanked<T>(rows: readonly T[], keep: number, value: (row: T) => number): {
|
|
47
|
+
top: T[];
|
|
48
|
+
rest: {
|
|
49
|
+
count: number;
|
|
50
|
+
sum: number;
|
|
51
|
+
} | undefined;
|
|
52
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var p=Object.defineProperty;var l=(n,t)=>p(n,"name",{value:t,configurable:!0});const M=["","\u258F","\u258E","\u258D","\u258C","\u258B","\u258A","\u2589"],b="\u2588";function k(n,t,e){if(e<=0)return"";if(t<=0||n<=0)return" ".repeat(e);const o=Math.max(1,Math.round(Math.min(n,t)/t*e*8)),i=Math.floor(o/8);return"\u2588".repeat(i)+M[o%8]+" ".repeat(e-i-(o%8===0?0:1))}l(k,"hbar");const d=["\u2588","\u2593","\u2592","\u2591"],g="\u259A";function s(n){return d[n]??g}l(s,"stackFill");function _(n,t,e){const o=n.reduce((r,a)=>r+Math.max(0,a),0);if(t<=0)return"";if(o<=0)return" ".repeat(t);const i=n.map(r=>Math.max(0,r)/o*t),c=i.map(Math.floor);let h=t-c.reduce((r,a)=>r+a,0);const f=i.map((r,a)=>({i:a,r:r-Math.floor(r)})).sort((r,a)=>a.r-r.r);for(const{i:r}of f){if(h===0)break;c[r]+=1,h-=1}for(let r=0;r<n.length;r+=1){if(n[r]<=0||c[r]>0)continue;let a=0;for(let u=1;u<c.length;u+=1)c[u]>c[a]&&(a=u);if(c[a]<=1)break;c[a]-=1,c[r]=1}return c.map((r,a)=>(e?.[a]??s(a)).repeat(r)).join("")}l(_,"stackedBar");function j(n,t){return n.map((e,o)=>`${t?.[o]??s(o)} ${e}`).join(" ")}l(j,"stackLegend");const L=[" ","\u2581","\u2582","\u2583","\u2584","\u2585","\u2586","\u2587","\u2588"];function E(n,t,e=2,o=1){const i=Math.max(0,...n),c=n.map(f=>f<=0||i<=0?0:Math.max(1,Math.round(f/i*t*8))),h=[];for(let f=t-1;f>=0;f-=1){const r=c.map(a=>{const u=Math.max(0,Math.min(8,a-f*8));return L[u].repeat(e)});h.push(r.join(" ".repeat(o)))}return h}l(E,"columnChart");function m(n,t){if(t.cells<=1)return 0;const e=Math.min(t.maxMs,Math.max(t.minMs,n)),o=Math.log(e/t.minMs)/Math.log(t.maxMs/t.minMs);return Math.round(o*(t.cells-1))}l(m,"logPosition");function F(n,t){const e=Array.from({length:t.cells},()=>" "),o=m(n.p10_ms,t),i=m(n.p90_ms,t);for(let c=o;c<=i;c+=1)e[c]="\u2500";return e[m(n.median_ms,t)]="\u25CF",e.join("")}l(F,"percentileLine");function H(n,t){let e="";for(const o of n){const i=Math.min(m(o.ms,t),Math.max(0,t.cells-o.label.length));i<e.length+(e===""?0:1)||(e=e.padEnd(i)+o.label)}return e.padEnd(t.cells).slice(0,t.cells)}l(H,"logAxisLabels");function I(n,t,e){if(n.length<=t)return{top:[...n],rest:void 0};const o=n.slice(0,Math.max(0,t)),i=n.slice(o.length);return{top:o,rest:{count:i.length,sum:i.reduce((c,h)=>c+e(h),0)}}}l(I,"foldRanked");export{g as OTHER_FILL,d as STACK_FILLS,E as columnChart,I as foldRanked,k as hbar,H as logAxisLabels,m as logPosition,F as percentileLine,s as stackFill,j as stackLegend,_ as stackedBar};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AnalyticsDTO } from '../../api/dto/analytics.js';
|
|
2
|
+
import { type AnalyticsNav } from './view.js';
|
|
3
|
+
/** A text column shares the free width with the other text columns (at most
|
|
4
|
+
* `max` cells); a number column is as wide as its widest value, right-aligned. */
|
|
5
|
+
export interface DrillColumn {
|
|
6
|
+
header: string;
|
|
7
|
+
kind: 'text' | 'number';
|
|
8
|
+
max?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface DrillRow {
|
|
11
|
+
node_id: string;
|
|
12
|
+
graph_id: string;
|
|
13
|
+
cells: string[];
|
|
14
|
+
}
|
|
15
|
+
export declare class AgentDrilldown {
|
|
16
|
+
private readonly title;
|
|
17
|
+
private readonly columns;
|
|
18
|
+
private readonly rows;
|
|
19
|
+
private readonly nav;
|
|
20
|
+
private cursor;
|
|
21
|
+
constructor(title: string, columns: readonly DrillColumn[], rows: readonly DrillRow[], nav: AnalyticsNav);
|
|
22
|
+
render(width: number, height: number): string[];
|
|
23
|
+
/** 'close' on Esc: the owning view pops this list. */
|
|
24
|
+
handleKey(key: string): 'handled' | 'close' | 'unhandled';
|
|
25
|
+
keyLine(narrow: boolean): string;
|
|
26
|
+
private line;
|
|
27
|
+
private widths;
|
|
28
|
+
/** The selected row's text cells in full, when any of them was cut. */
|
|
29
|
+
private fullText;
|
|
30
|
+
}
|
|
31
|
+
/** A graph's display name: its graph row (root title, else root name), else
|
|
32
|
+
* the root agent's name, else the id. A graph with no active agent in the
|
|
33
|
+
* window has no graph row. */
|
|
34
|
+
export declare function graphName(data: AnalyticsDTO, graphId: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var p=Object.defineProperty;var a=(u,e)=>p(u,"name",{value:e,configurable:!0});import{matchesKey as l,visibleWidth as c}from"@earendil-works/pi-tui";import{theme as d}from"../../core/tui/panel.js";import{padLeft as g,padRight as w,truncate as m}from"./format.js";import{listWindow as x,markRow as M,moreRow as _}from"./view.js";const f=" ";class R{static{a(this,"AgentDrilldown")}title;columns;rows;nav;cursor=0;constructor(e,t,n,i){this.title=e,this.columns=t,this.rows=n,this.nav=i}render(e,t){const n=[d.bold(m(this.title,e))];if(this.rows.length===0)return[...n,"None in this window."];const i=this.widths(e);n.push(d.fg("dim",` ${this.line(this.columns.map(o=>o.header),i)}`));const h=this.fullText(i),s=Math.max(1,t-n.length-(h===void 0?0:1)),r=x(this.rows.length,this.cursor,s);for(let o=r.start;o<r.end;o+=1)n.push(M(this.line(this.rows[o].cells,i),o===this.cursor));return r.more>0&&n.push(_(r.more,"agents")),h!==void 0&&n.push(d.fg("dim",m(` ${h}`,e))),n}handleKey(e){if(l(e,"escape"))return"close";if(l(e,"down")||l(e,"j"))this.cursor=Math.min(this.rows.length-1,this.cursor+1);else if(l(e,"up")||l(e,"k"))this.cursor=Math.max(0,this.cursor-1);else if(l(e,"enter")){const t=this.rows[this.cursor];t!==void 0&&this.nav.openGraphDetail(t.graph_id,t.node_id)}else return"unhandled";return this.cursor=Math.max(0,this.cursor),"handled"}keyLine(e){return this.rows.length===0?"":e?"\u2191\u2193 Enter":"\u2191\u2193 agent \xB7 Enter: its graph, agent selected"}line(e,t){return e.map((n,i)=>this.columns[i].kind==="number"?g(n,t[i]):w(n,t[i])).join(f)}widths(e){const t=this.columns.map((s,r)=>Math.min(s.max??1/0,Math.max(c(s.header),...this.rows.map(o=>c(o.cells[r]??""))))),n=this.columns.flatMap((s,r)=>s.kind==="text"?[r]:[]),i=t.reduce((s,r,o)=>s+(this.columns[o].kind==="number"?r:0),0);let h=e-2-i-f.length*(this.columns.length-1);return n.sort((s,r)=>t[s]-t[r]),n.forEach((s,r)=>{t[s]=Math.max(4,Math.min(t[s],Math.floor(h/(n.length-r)))),h-=t[s]}),t}fullText(e){const t=this.rows[this.cursor];if(t===void 0)return;const n=t.cells.filter((h,s)=>this.columns[s].kind==="text");return t.cells.some((h,s)=>this.columns[s].kind==="text"&&c(h)>e[s])?n.join(" \xB7 "):void 0}}function $(u,e){const t=u.graphs.ok?u.graphs.value.graphs.find(n=>n.graph_id===e):void 0;return t!==void 0?t.root_deleted?`${t.name} (root deleted)`:t.name:u.agents.find(n=>n.node_id===e)?.name??e}a($,"graphName");export{R as AgentDrilldown,$ as graphName};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** API-price estimate: "<$1" under one dollar, whole dollars otherwise ("$4",
|
|
2
|
+
* "$1,236"). Exactly zero reads "$0": "<$1" would claim a non-zero amount. */
|
|
3
|
+
export declare function formatPrice(dollars: number): string;
|
|
4
|
+
/** Tokens with 2–3 significant figures and k/M/B ("950", "9.8M", "121M"). */
|
|
5
|
+
export declare function formatTokens(tokens: number): string;
|
|
6
|
+
/** Durations: "<1m", "14m", "1h 30m", "1h", "1d 4h", "2d". Rounded down. */
|
|
7
|
+
export declare function formatDuration(ms: number): string;
|
|
8
|
+
/** Counts with thousands separators ("1,376"). */
|
|
9
|
+
export declare function formatCount(n: number): string;
|
|
10
|
+
/** A 0–1 ratio as a whole percentage ("90%"). */
|
|
11
|
+
export declare function formatShare(ratio: number): string;
|
|
12
|
+
/** "1 graph" / "14 graphs", count formatted. */
|
|
13
|
+
export declare function plural(n: number, one: string, many: string): string;
|
|
14
|
+
/** A failed measure, in place of its numbers. */
|
|
15
|
+
export declare function unavailable(reason: string): string;
|
|
16
|
+
/** Cut to `width` columns, ending in "…" when cut. */
|
|
17
|
+
export declare function truncate(text: string, width: number): string;
|
|
18
|
+
/** Cut or pad to exactly `width` columns, left-aligned. */
|
|
19
|
+
export declare function padRight(text: string, width: number): string;
|
|
20
|
+
/** Cut or pad to exactly `width` columns, right-aligned (numbers). */
|
|
21
|
+
export declare function padLeft(text: string, width: number): string;
|
|
22
|
+
/** Local weekday and time, "Thu 18:00". Arithmetic stays UTC; only labels are local. */
|
|
23
|
+
export declare function formatClock(at: string | number | Date): string;
|
|
24
|
+
/** Local time of day, "18:00". */
|
|
25
|
+
export declare function formatTimeOfDay(at: string | number | Date): string;
|
|
26
|
+
/** Local date and time, "Sep 3 18:00". */
|
|
27
|
+
export declare function formatDateTime(at: string | number | Date): string;
|
|
28
|
+
/** The local timezone abbreviation, "PDT". */
|
|
29
|
+
export declare function formatTimezone(at: string | number | Date): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var x=Object.defineProperty;var o=(t,n)=>x(t,"name",{value:n,configurable:!0});import{truncateToWidth as d,visibleWidth as s}from"@earendil-works/pi-tui";function D(t){return t===0?"$0":t<1?"<$1":`$${m(Math.round(t))}`}o(D,"formatPrice");const l=[[1e9,"B"],[1e6,"M"],[1e3,"k"]];function S(t){const n=Math.round(t);if(n<1e3)return String(n);for(const[r,a]of l){if(n<r)continue;const e=n/r,p=e<10?e.toFixed(1).replace(/\.0$/,""):String(Math.round(e));return p==="1000"&&a!=="B"?S(r*1e3):`${p}${a}`}return String(n)}o(S,"formatTokens");const i=6e4,u=60*i,f=24*u;function T(t){if(t<i)return"<1m";if(t<u)return`${Math.floor(t/i)}m`;if(t<f){const a=Math.floor(t/u),e=Math.floor(t%u/i);return e===0?`${a}h`:`${a}h ${e}m`}const n=Math.floor(t/f),r=Math.floor(t%f/u);return r===0?`${n}d`:`${n}d ${r}h`}o(T,"formatDuration");function m(t){return t.toLocaleString("en-US")}o(m,"formatCount");function y(t){return`${Math.round(t*100)}%`}o(y,"formatShare");function U(t,n,r){return`${m(t)} ${t===1?n:r}`}o(U,"plural");function k(t){return`unavailable: ${t}`}o(k,"unavailable");function $(t,n){return d(t,Math.max(0,n),"\u2026")}o($,"truncate");function v(t,n){const r=$(t,n);return r+" ".repeat(Math.max(0,n-s(r)))}o(v,"padRight");function N(t,n){const r=$(t,n);return" ".repeat(Math.max(0,n-s(r)))+r}o(N,"padLeft");const c=o(t=>t instanceof Date?t:new Date(t),"toDate");function L(t){const n=c(t);return`${n.toLocaleDateString("en-US",{weekday:"short"})} ${h(n)}`}o(L,"formatClock");function h(t){const n=c(t);return`${String(n.getHours()).padStart(2,"0")}:${String(n.getMinutes()).padStart(2,"0")}`}o(h,"formatTimeOfDay");function b(t){const n=c(t);return`${n.toLocaleDateString("en-US",{month:"short",day:"numeric"})} ${h(n)}`}o(b,"formatDateTime");function w(t){return new Intl.DateTimeFormat("en-US",{timeZoneName:"short"}).formatToParts(c(t)).find(r=>r.type==="timeZoneName")?.value??"local time"}o(w,"formatTimezone");export{L as formatClock,m as formatCount,b as formatDateTime,T as formatDuration,D as formatPrice,y as formatShare,h as formatTimeOfDay,w as formatTimezone,S as formatTokens,N as padLeft,v as padRight,U as plural,$ as truncate,k as unavailable};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var q=Object.defineProperty;var p=(r,t)=>q(r,"name",{value:t,configurable:!0});import{matchesKey as u,visibleWidth as K}from"@earendil-works/pi-tui";import{rule as V,theme as g,wrapText as C}from"../../core/tui/panel.js";import{formatClock as b,formatDuration as U,formatPrice as y,formatTimeOfDay as E,formatTokens as H,padLeft as x,padRight as T,plural as W,unavailable as J}from"./format.js";import{fullNameLine as Q,graphLabel as X}from"./graphs.js";import{isNarrow as Y,listWindow as Z,markRow as I}from"./view.js";const w=6e4,A=[1,2,5,7.5,10,15,30,60,120,180,240],B=[15,30,60,120,180,360,720,1440,2880];function ee(r){const t=new Set(r.map(e=>e.node_id)),o=[...r].sort((e,i)=>Date.parse(e.created)-Date.parse(i.created)||e.node_id.localeCompare(i.node_id)),n=new Map,s=[];for(const e of o)if(e.parent!==null&&t.has(e.parent)){const i=n.get(e.parent)??[];i.push(e),n.set(e.parent,i)}else s.push(e);const a=[],d=p((e,i,l)=>{a.push({agent:e,guide:i+l});const h=n.get(e.node_id)??[],_=l===""?i:i+(l==="\u251C "?"\u2502 ":" ");h.forEach((v,D)=>d(v,_,D===h.length-1?"\u2514 ":"\u251C "))},"walk");for(const e of s)d(e,"","");return a}p(ee,"treeRows");function R(r){return`${r.guide}${r.agent.kind} ${r.agent.name}`}p(R,"rowLabel");function te(r){return r<60?`${r}-min`:`${r/60}-hour`}p(te,"slotLabel");function F(r,t,o){const n=-new Date(r).getTimezoneOffset()*w;let s;for(const a of A){const d=a*w,e=Math.floor((r+n)/d)*d-n,i=Math.floor((t-e)/d)+1;if(s={start:e,slotMs:d,slots:i,offset:n},i<=o)break}return s}p(F,"timelineFor");function ne(r,t){const o=r.slotMs/w,n=r.slots*r.slotMs>1440*w,s=n?9:5,d=(B.find(i=>i>=o&&i%o===0&&i/o>=s+2)??B.at(-1))*w;let e="";for(let i=0;i<r.slots&&i<t;i+=1){const l=r.start+i*r.slotMs;if((l+r.offset)%d!==0||i<e.length+(e===""?0:1))continue;const h=n?b(l):E(l);if(i+h.length>t)break;e=e.padEnd(i)+h}return e.padEnd(t).slice(0,t)}p(ne,"axisLine");function se(r,t,o){const n=Date.parse(r.created),s=r.finalized_at===null?void 0:Date.parse(r.finalized_at),a=new Set(r.response_times_ms.map(e=>Math.floor((e-t.start)/t.slotMs)));let d="";for(let e=0;e<Math.min(t.slots,o);e+=1){const i=t.start+e*t.slotMs,l=i+t.slotMs;s!==void 0&&s>=i&&s<l?d+="\u25C6":a.has(e)?d+="\u2588":n<l&&(s===void 0||s>=l)?d+="\u2500":d+=" "}return d.padEnd(o)}p(se,"timelineCells");function oe(r){return r.agent_time_ms!==null?U(r.agent_time_ms):r.lifecycle==="resident"?"resident":"open"}p(oe,"createdToFinal");class re{static{p(this,"GraphDetailView")}ctx;rows;graph;rootName;root;unlisted;cursor=0;report;constructor(t,o,n){this.ctx=t;const s=t.data;this.graph=s.graphs.ok?s.graphs.value.graphs.find(e=>e.graph_id===o):void 0;const a=new Map(s.agents.map(e=>[e.node_id,e])),d=new Map(s.agents.filter(e=>e.graph_id===o&&e.in_graph_detail).map(e=>[e.node_id,e]));for(let e=n===void 0?void 0:a.get(n);e!==void 0&&!d.has(e.node_id);e=e.parent===null?void 0:a.get(e.parent))d.set(e.node_id,e);this.rows=ee([...d.values()]),this.cursor=Math.max(0,this.rows.findIndex(e=>e.agent.node_id===n)),this.unlisted=n!==void 0&&!a.has(n)?this.readerNamed(n):void 0,this.root=s.agents.find(e=>e.graph_id===o&&e.parent===null),this.rootName=this.graph!==void 0?X(this.graph):this.root?.name??o}readerNamed(t){const o=this.ctx.data.memory;return o.ok?[...o.value.read.rows,...o.value.loaded.rows].flatMap(s=>s.readers).find(s=>s.node_id===t):void 0}get selected(){return this.rows[this.cursor]?.agent}handleKey(t){if(this.report!==void 0){if(u(t,"escape")||u(t,"r"))this.report=void 0;else if(u(t,"down")||u(t,"j"))this.report.scroll+=1;else if(u(t,"up")||u(t,"k"))this.report.scroll=Math.max(0,this.report.scroll-1);else return"unhandled";return"handled"}if(u(t,"escape"))return"back";const o=this.selected;if(u(t,"up")||u(t,"k"))this.cursor=Math.max(0,this.cursor-1);else if(u(t,"down")||u(t,"j"))this.cursor=Math.min(this.rows.length-1,this.cursor+1);else{if(o===void 0)return"unhandled";if(u(t,"enter"))this.ctx.nav.openInspector(o.node_id);else if(u(t,"o"))this.ctx.nav.openConversation(o.node_id);else if(u(t,"r")){if(o.final_report_ref===null)return"handled";this.openReport(o.final_report_ref,`${o.kind} ${o.name}`)}else return"unhandled"}return"handled"}openReport(t,o){const n={ref:t,name:o,scroll:0,text:void 0,error:void 0};this.report=n,this.ctx.nav.readFinalReport(t).then(s=>{n.text=s,this.ctx.nav.requestRender()},s=>{n.error=s instanceof Error?s.message:String(s),this.ctx.nav.requestRender()})}keyLine(t){if(this.report!==void 0)return t?"\u2191\u2193":"\u2191\u2193 scroll";if(this.rows.length===0)return"";const o=this.selected?.final_report_ref!==null;return t?["\u2191\u2193 Enter",...o?["r"]:[],"o open, may wake it"].join(" "):["\u2191\u2193 agent \xB7 Enter inspect, read-only",...o?["r final report"]:[],"o open, may wake it"].join(" \xB7 ")}escapeLabel(){return this.report!==void 0?"close report":void 0}render(t,o,n){const s=this.header(t,n),a=this.report!==void 0?this.reportBody(t,o-s.length,this.report):this.treeBody(t,o-s.length);return[...s,...a]}header(t,o){const n=[g.bold(`< Graphs / ${this.rootName}`)],s=this.graph,a=p((d,e,i)=>`Root: ${d} \xB7 ${e==="resident"?"resident conversation":"terminal"} \xB7 created ${b(i)}`,"rootLine");return o.graphs.ok?s===void 0?(this.root!==void 0&&n.push(a(this.root.kind,this.root.lifecycle,this.root.created)),n.push("No agent in this graph had a model response in this window.")):(n.push(a(s.root_kind,s.root_lifecycle,s.root_created)),n.push(`${W(s.active_agents,"agent","agents")} \xB7 depth ${s.depth} \xB7 ${H(s.tokens)} tokens \xB7 ${y(s.api_price_estimate)} API-price est.`)):n.push(J(o.graphs.reason)),n.push(V(t)),n}treeBody(t,o){if(!this.ctx.data.graphs.ok||this.rows.length===0)return[];const n=Y(t),s=15,a=9,d=Math.max(0,...this.rows.map(f=>K(R(f))));let e=n?t-2-s-a:Math.max(20,Math.min(d,Math.floor(t*.4)));const i=p(f=>n?0:Math.max(10,t-2-f-1-s-a),"cellsFor");let l=i(e);const h=[],_=this.rows.flatMap(f=>f.agent.response_times_ms),v=Math.min(..._),D=Math.max(..._);let c=!n&&_.length>0?F(v,D,l):void 0;if(c!==void 0&&c.slots>l&&(e=Math.max(20,e-(c.slots-l)),l=i(e),c=F(v,D,l)),!n)if(c===void 0)h.push("Timeline: no model responses in this window.");else{const f=c.start+Math.min(c.slots,l)*c.slotMs,m=new Date(c.start).toDateString()===new Date(f-1).toDateString()?`${E(c.start)}\u2013${E(f)}`:`${b(c.start)}\u2013${b(f)}`;h.push(`Timeline: ${m}, the part of the window with activity`)}const j=c===void 0?" ".repeat(l):ne(c,l);h.push(g.fg("dim",` ${T("Agent",e)}${n?"":` ${j}`}${x("created\u2192final",s)}${x("est.",a)}`));const S=c===void 0?[]:["",g.fg("dim",`\u2588 ${te(c.slotMs/w)} slot with a model response \u2500 alive, no response \u25C6 final report`)],z=this.rows[this.cursor],L=Q(R(z),e),k=this.unlisted!==void 0?g.fg("dim",` ${this.unlisted.kind} ${this.unlisted.name} had no model response, spawn, or final report in this window, so it has no row here.`):void 0,G=S.length+(L!==void 0?1:0)+(k!==void 0?1:0),M=Z(this.rows.length,this.cursor,Math.max(1,o-h.length-G));for(let f=M.start;f<M.end;f+=1){const $=this.rows[f],m=$.agent,N=T(R($),e),O=n?"":` ${c===void 0?" ".repeat(l):se(m,c,l)}`,P=m.active?y(m.api_price_estimate):"\u2014";h.push(I(`${N}${O}${x(oe(m),s)}${x(P,a)}`,f===this.cursor))}if(M.more>0){const f=this.rows.slice(M.end).reduce((m,N)=>m+N.agent.api_price_estimate,0),$=` ${W(M.more,"more agent","more agents")} \u2193`;h.push(`${T($,t-a)}${x(y(f),a)}`)}return L!==void 0&&h.push(L),k!==void 0&&h.push(k),h.push(...S),h}reportBody(t,o,n){const s=g.bold(`Final report \xB7 ${n.name}`);if(n.error!==void 0)return[s,"",...C(`Could not read the final report: ${n.error}`,t)];if(n.text===void 0)return[s,"","Loading the final report\u2026"];const a=n.text.split(`
|
|
2
|
+
`).flatMap(h=>h.trim()===""?[""]:C(h,t)),d=Math.max(1,o-2);n.scroll=Math.min(n.scroll,Math.max(0,a.length-d));const e=a.slice(n.scroll,n.scroll+d),i=a.length-n.scroll-e.length,l=i>0?g.fg("dim",` \xB7 ${i} more lines \u2193`):"";return[`${s}${l}`,"",...e]}}const fe=p((r,t,o)=>new re(r,t,o),"createGraphDetailView");export{fe as createGraphDetailView};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GraphRowDTO } from '../../api/dto/analytics.js';
|
|
2
|
+
import { type AnalyticsViewFactory } from './view.js';
|
|
3
|
+
/** A graph's name as its rows show it: "(root deleted)" when the root's parent row is gone. */
|
|
4
|
+
export declare function graphLabel(graph: GraphRowDTO): string;
|
|
5
|
+
/** Graphs by API-price estimate, largest first; ties by name so the order is stable. */
|
|
6
|
+
export declare function byEstimate(a: GraphRowDTO, b: GraphRowDTO): number;
|
|
7
|
+
/** The line under a list that shows the selected row's whole name, when its row cut it. */
|
|
8
|
+
export declare function fullNameLine(label: string, shownWidth: number): string | undefined;
|
|
9
|
+
export declare const createGraphsView: AnalyticsViewFactory;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var F=Object.defineProperty;var l=(s,t)=>F(s,"name",{value:t,configurable:!0});import{matchesKey as c,visibleWidth as g}from"@earendil-works/pi-tui";import{rule as E,theme as C,wrapText as K}from"../../core/tui/panel.js";import{foldRanked as B,hbar as A}from"./chart.js";import{formatCount as b,formatPrice as D,formatTokens as Y,padLeft as f,padRight as k,plural as O,unavailable as Z}from"./format.js";import{NARROW_BAR_CELLS as S,isNarrow as q,listWindow as H,markRow as v,moreRow as J,textWidth as Q}from"./view.js";function N(s){return s.root_deleted?`${s.name} (root deleted)`:s.name}l(N,"graphLabel");function U(s,t){return t.api_price_estimate-s.api_price_estimate||s.name.localeCompare(t.name)}l(U,"byEstimate");function T(s,t,e,i){return g(s)<e?`${k(s,e)}${f(t,i)}`:s}l(T,"chartTitle");function X(s,t){return g(s)>t?C.fg("dim",` ${s}`):void 0}l(X,"fullNameLine");const M=[{key:"estimate",label:"API est.",value:l(s=>s.api_price_estimate,"value")},{key:"agents",label:"agents",value:l(s=>s.active_agents,"value")},{key:"depth",label:"depth",value:l(s=>s.depth,"value")},{key:"tokens",label:"tokens",value:l(s=>s.tokens,"value")}],tt={1:[1,1],"2\u20135":[2,5],"6\u201310":[6,10],"11\u201320":[11,20],"21+":[21,Number.POSITIVE_INFINITY]};function et(s){const t=s.spawned_by_kind,e=t.length>5?B(t,4,n=>n.agents):{top:t,rest:void 0},i=e.top.map(n=>({label:n.kind,agents:n.agents,kinds:[n.kind]}));return e.rest!==void 0&&i.push({label:`${b(e.rest.count)} more kinds`,agents:e.rest.sum,kinds:t.slice(4).map(n=>n.kind)}),i}l(et,"kindRows");const G=l(s=>s==="1"?"1 agent":`${s} agents`,"sizeLabel");class st{static{l(this,"GraphsView")}ctx;zone="list";lastChart="size";sizeIndex=0;kindIndex=0;listIndex=0;sort=0;filter;secondOpen=!1;narrow=!1;constructor(t){this.ctx=t}get graphs(){return this.ctx.data.graphs.ok?this.ctx.data.graphs.value:void 0}get kinds(){return this.graphs===void 0?[]:et(this.graphs)}listed(){const t=this.graphs?.graphs??[],e=M[this.sort],i=this.filter;return t.filter(n=>i===void 0||i.match(n)).sort((n,r)=>e.value(r)-e.value(n)||U(n,r))}get buckets(){const t=this.graphs?.size_buckets??[];return t.some(e=>e.graphs>0)?t:[]}sizeRowCount(){return this.buckets.length+(this.narrow?1:0)}land(t){t.tab==="graphs"&&(this.filter=void 0,this.listIndex=0,t.at==="size-chart"?(this.zone="size",this.lastChart="size",this.sizeIndex=0,this.secondOpen=!1):t.at==="kind-chart"?(this.zone="kind",this.lastChart="kind",this.kindIndex=0,this.secondOpen=!0):(this.zone="list",this.sort=0))}handleKey(t){return this.graphs===void 0?c(t,"escape")?"back":"unhandled":c(t,"escape")?this.narrow&&this.secondOpen?(this.secondOpen=!1,this.zone==="kind"&&(this.zone="size",this.sizeIndex=this.sizeRowCount()-1),this.lastChart="size","handled"):this.filter!==void 0?(this.filter=void 0,this.listIndex=0,"handled"):"back":c(t,"c")?(this.sort=(this.sort+1)%M.length,this.listIndex=0,"handled"):c(t,"up")||c(t,"k")?this.move(-1):c(t,"down")||c(t,"j")?this.move(1):c(t,"left")||c(t,"h")?this.side("size"):c(t,"right")||c(t,"l")?this.side("kind"):c(t,"enter")?this.enter():"unhandled"}visibleChart(){return this.narrow?this.secondOpen?"kind":"size":this.lastChart}move(t){const e=this.listed().length;if(this.zone==="list"){if(t===-1&&this.listIndex===0){const h=this.visibleChart(),o=h==="size"?this.sizeRowCount():this.kinds.length;o>0&&(this.zone=h,h==="size"?this.sizeIndex=o-1:this.kindIndex=o-1)}else this.listIndex=Math.max(0,Math.min(e-1,this.listIndex+t));return"handled"}const i=this.zone==="size"?this.sizeRowCount():this.kinds.length,r=(this.zone==="size"?this.sizeIndex:this.kindIndex)+t;return r>=i?e>0&&(this.lastChart=this.zone,this.zone="list",this.listIndex=0):r>=0&&(this.zone==="size"?this.sizeIndex=r:this.kindIndex=r),"handled"}side(t){if(this.narrow||this.zone==="list"||this.zone===t)return"unhandled";const e=t==="size"?this.sizeRowCount():this.kinds.length;if(e===0)return"handled";const i=this.zone==="size"?this.sizeIndex:this.kindIndex;return this.zone=t,this.lastChart=t,t==="size"?this.sizeIndex=Math.min(i,e-1):this.kindIndex=Math.min(i,e-1),"handled"}enter(){if(this.zone==="list"){const t=this.listed()[this.listIndex];return t!==void 0&&this.ctx.nav.openGraphDetail(t.graph_id),"handled"}if(this.zone==="size"){const t=this.buckets[this.sizeIndex];if(t===void 0)return this.secondOpen=!0,this.zone="kind",this.lastChart="kind",this.kindIndex=0,this.kinds.length===0&&(this.zone="size"),"handled";const[e,i]=tt[t.label];this.filter={label:`graphs with ${G(t.label)}`,match:l(n=>n.active_agents>=e&&n.active_agents<=i,"match")}}else{const t=this.kinds[this.kindIndex];if(t===void 0)return"handled";const e=new Set(t.kinds),i=t.kinds.length===1?`graphs that spawned ${nt(t.label)} in this window`:`graphs that spawned one of the ${t.label} in this window`;this.filter={label:i,match:l(n=>n.spawned_kinds.some(r=>e.has(r)),"match")}}return this.listIndex=0,"handled"}keyLine(t){return this.graphs===void 0?"":t?"\u2190\u2192\u2191\u2193 \xB7 Enter \xB7 c sort":`\u2190\u2192\u2191\u2193 select \xB7 ${this.zone==="list"?"Enter open graph":this.zone==="size"&&this.buckets[this.sizeIndex]===void 0?"Enter open chart":"Enter filter the list"} \xB7 c sort`}escapeLabel(){if(this.narrow&&this.secondOpen)return"close chart";if(this.filter!==void 0)return"clear filter"}render(t,e,i){if(this.narrow=q(t),!i.graphs.ok)return[Z(i.graphs.reason)];const n=i.graphs.value;this.narrow&&this.zone==="kind"&&!this.secondOpen&&(this.zone="size"),this.sizeIndex=Math.min(this.sizeIndex,Math.max(0,this.sizeRowCount()-1));const r=this.narrow?this.narrowCharts(t):this.wideCharts(t),h=this.listLines(t,Math.max(3,e-r.length),n);return[...r,...h]}sizeChart(t){const n=this.narrow?S:Math.max(4,t-2-12-1-6-1),r=T("Agents per graph","graphs",15+n,6),h=this.buckets;if(h.length===0)return[r," None in this window."];const o=Math.max(...h.map(a=>a.graphs)),d=h.map((a,z)=>{const x=`${k(G(a.label),12)} ${A(a.graphs,o,n)}${f(b(a.graphs),6)}`;return v(x,this.zone==="size"&&this.sizeIndex===z)});return[r,...d]}kindChart(t){const e=this.kinds,i=Math.max(14,Math.min(this.narrow?14:24,Math.max(0,...e.map(a=>g(a.label))))),n=6,r=this.narrow?S:Math.max(4,t-2-i-1-n-1),h=T("Agents spawned in window, by kind","agents",2+i+1+r,n);if(e.length===0)return[h," None in this window."];const o=Math.max(...e.map(a=>a.agents)),d=e.map((a,z)=>{const x=`${k(a.label,i)} ${A(a.agents,o,r)}${f(b(a.agents),n)}`;return v(x,this.zone==="kind"&&this.kindIndex===z)});return[h,...d]}wideCharts(t){const e=Math.floor((t-3)/2),i=t-e-3,n=this.sizeChart(e),r=this.kindChart(i),h=Math.max(n.length,r.length),o=[];for(let d=0;d<h;d+=1)o.push(`${k(n[d]??"",e)} \u2502 ${r[d]??""}`);return o.push(C.fg("border",`${"\u2500".repeat(e+1)}\u2534${"\u2500".repeat(Math.max(0,t-e-2))}`)),o}narrowCharts(t){if(this.secondOpen)return[...this.kindChart(t),E(t)];const e=v("Agents spawned in window, by kind \u2192",this.zone==="size"&&this.sizeIndex===this.buckets.length);return[...this.sizeChart(t),e,E(t)]}listLines(t,e,i){const n=this.narrow,r=M[this.sort],h=`${O(i.count,"graph","graphs")} \xB7 deepest ${O(i.deepest,"level","levels")} below root`,o=n?`sort: ${r.label}`:`sort: ${M.map(u=>u===r?`[${u.label}]`:u.label).join(" ")}`,d=this.listed(),[a,z,x,_]=n?[7,6,9,7]:[9,8,12,9],w=a+z+x+_,P=Math.max(0,...d.map(u=>g(N(u)))),I=n?Math.max(8,Math.min(t,t-2-w)):Math.max(8,Math.min(t-2-w,Q(t-2-w,P,44))),V=n?t:Math.max(2+I+w,g(h)+g(o)+2),L=Math.min(t,V)-g(h)-g(o),p=[L>=2?`${h}${" ".repeat(L)}${o}`:`${h} \xB7 ${o}`];if(this.filter!==void 0){const u=`Filter: ${this.filter.label} \xB7 ${O(d.length,"graph","graphs")} \xB7 Esc clears`;p.push(...K(u,t).map(m=>C.fg("accent",m)))}if(p.push(C.fg("dim",` ${k("Graph",I)}${f("agents",a)}${f("depth",z)}${f("est.",x)}${f("tokens",_)}`)),d.length===0)return p.push(this.filter!==void 0?" No graphs match this filter.":" None in this window."),p;this.listIndex=Math.min(this.listIndex,d.length-1);const W=this.zone==="list"?d[this.listIndex]:void 0,R=W===void 0?void 0:X(N(W),I),j=Math.max(1,e-p.length-(R!==void 0?1:0)),$=H(d.length,this.zone==="list"?this.listIndex:0,j);for(let u=$.start;u<$.end;u+=1){const m=d[u],y=`${k(N(m),I)}${f(b(m.active_agents),a)}${f(b(m.depth),z)}${f(D(m.api_price_estimate),x)}${f(Y(m.tokens),_)}`;p.push(v(y,m===W))}return $.more>0&&p.push(J($.more,"graphs")),R!==void 0&&p.push(R),p}}function nt(s){return/^[aeiou]/i.test(s)?`an ${s}`:`a ${s}`}l(nt,"article");const lt=l(s=>new st(s),"createGraphsView");export{U as byEstimate,lt as createGraphsView,X as fullNameLine,N as graphLabel};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var N=Object.defineProperty;var M=(b,t)=>N(b,"name",{value:t,configurable:!0});import{matchesKey as m,visibleWidth as O}from"@earendil-works/pi-tui";import{columns as S,theme as g,wrapText as v}from"../../core/tui/panel.js";import{foldRanked as j,hbar as B}from"./chart.js";import{AgentDrilldown as K,graphName as T}from"./drilldown.js";import{formatCount as w,formatDateTime as W,padLeft as u,padRight as x,plural as _,truncate as E,unavailable as H}from"./format.js";import{NARROW_BAR_CELLS as V,isNarrow as F,listWindow as U,markRow as C,moreRow as q,textWidth as z}from"./view.js";const L={read:"Read on purpose",loaded:"Loaded automatically"},$={read:{one:"read",many:"reads",verb:"read",first:"first read"},loaded:{one:"load",many:"loads",verb:"loaded",first:"first loaded"}},G="A read does not show whether the document changed the work.",h=7;class I{static{M(this,"MemoryView")}ctx;show="read";cursor=0;doc=0;layers=[];narrow=!1;constructor(t){this.ctx=t}get view(){return this.ctx.data.memory.ok?this.ctx.data.memory.value[this.show]:void 0}count(){const t=this.view?.rows.length??0;return t===0?0:t+(this.narrow?1:0)}render(t,s,e){if(!e.memory.ok)return[`Memory: ${H(e.memory.reason)}`];const o=e.memory.value[this.show],n=F(t);this.narrow=n,n||(this.layers=this.layers.filter(p=>p.kind!=="readers")),this.cursor=Math.min(this.cursor,Math.max(0,this.count()-1));const r=[this.switchLine(),...v(this.summary(o,e),t)],d=v(G,t).map(p=>g.fg("dim",p)),c=this.layers.at(-1);if(c?.kind==="drill")return[...r,"",...c.list.render(t,s-r.length-1)];const a=this.labels(o);if(c?.kind==="readers")return[...r,"",...this.readersChart(o.rows[this.doc],a[this.doc],t,s-r.length-1)];if(o.rows.length===0)return[...r,"",`No documents ${L[this.show].toLowerCase()} in this window.`,"",...d];const l=Math.max(3,s-r.length-1-d.length-1);if(n){const p=this.documents(o,a,t,l-1),A=C(E(`Who ${$[this.show].verb} ${a[this.doc]} \u2192`,t-2),this.cursor===o.rows.length);return[...r,"",...p,A,"",...d]}const f=t-3-2-3*h,k=Math.max(8,...a.map(p=>O(p))),y=2+z(f,k,24)+3*h,i=t-y-3,D=this.documents(o,a,y,l),R=this.readersChart(o.rows[this.doc],a[this.doc],i,l);return R.push("",g.fg("dim",E("Enter: agents and graphs",i))),[...r,"",...S(D,y,R.slice(0,l),i),"",...d]}switchLine(){const t=this.show==="read"?"loaded":"read",s=g.bold(`[${L[this.show]}]`),e=` ${L[t]} `;return`Show: ${this.show==="read"?`${s} ${e}`:`${e} ${s}`}`}summary(t,s){const e=$[this.show],o=`${_(t.entries,e.one,e.many)} of ${_(t.documents,"document","documents")} \xB7 ${w(t.agents_with_entry)} of ${_(t.active_agents,"agent","agents")} ${e.verb} at least one`,n=s.memory_log_started_at;return n!==null&&Date.parse(s.window_start)<Date.parse(n)?`${o} \xB7 recorded since ${W(n)}`:o}labels(t){const s=new Map;for(const e of t.rows)s.set(e.name,(s.get(e.name)??0)+1);return t.rows.map(e=>s.get(e.name)>1?`${e.name} \xB7 ${e.scope}`:e.name)}documents(t,s,e,o){const n=Math.max(8,e-2-3*h),r=$[this.show],d=[g.fg("dim",` ${x("Document",n)}${u(r.many,h)}${u("agents",h)}${u("graphs",h)}`)],c=U(t.rows.length,Math.min(this.cursor,t.rows.length-1),Math.max(1,o-1));for(let a=c.start;a<c.end;a+=1){const l=t.rows[a],f=`${x(s[a],n)}${u(w(l.reads),h)}${u(w(l.agents),h)}${u(w(l.graphs),h)}`;d.push(C(f,a===this.cursor))}return c.more>0&&d.push(q(c.more,"documents")),d}readersChart(t,s,e,o){const n=$[this.show],r=v(`${s} \xB7 who ${n.verb} it`,e).slice(0,2).map(i=>g.bold(i));r.push(g.fg("dim",`${x(`scope: ${t.scope}`,e-h)}${u("agents",h)}`));const d=14,c=this.narrow?V:Math.max(4,e-2-d-1-h),a=Math.max(2,o-r.length-2),{top:l,rest:f}=j(t.readers_by_kind,t.readers_by_kind.length>a?a-1:a,i=>i.agents),k=[...l.map(i=>({label:i.kind,agents:i.agents})),...f!==void 0?[{label:`${_(f.count,"more kind","more kinds")}`,agents:f.sum}]:[]],y=Math.max(0,...k.map(i=>i.agents));for(const i of k)r.push(` ${x(i.label,d)}${B(i.agents,y,c)} ${u(w(i.agents),h-1)}`);return r}handleKey(t){if(m(t,"t")&&this.ctx.data.memory.ok)return this.show=this.show==="read"?"loaded":"read",this.cursor=0,this.doc=0,this.layers=[],"handled";const s=this.layers.at(-1);if(s?.kind==="drill")return s.list.handleKey(t)==="close"&&this.layers.pop(),"handled";if(s?.kind==="readers")return m(t,"escape")?(this.layers.pop(),"handled"):"unhandled";if(m(t,"escape"))return"back";const e=this.view;if(e===void 0||e.rows.length===0)return"unhandled";if(m(t,"down")||m(t,"j"))this.cursor=Math.min(this.count()-1,this.cursor+1);else if(m(t,"up")||m(t,"k"))this.cursor=Math.max(0,this.cursor-1);else return m(t,"enter")?(this.cursor<e.rows.length?this.layers.push({kind:"drill",list:this.drill(e,this.cursor)}):this.layers.push({kind:"readers"}),"handled"):"unhandled";return this.cursor<e.rows.length&&(this.doc=this.cursor),"handled"}drill(t,s){const e=this.ctx.data,o=t.rows[s],n=$[this.show];return new K(`${this.labels(t)[s]} \xB7 agents that ${n.verb} it`,[{header:"kind",kind:"text",max:18},{header:"agent",kind:"text"},{header:"graph",kind:"text"},{header:n.many,kind:"number"},{header:n.first,kind:"number"}],o.readers.map(r=>({node_id:r.node_id,graph_id:r.graph_id,cells:[r.kind,r.name,T(e,r.graph_id),w(r.reads),W(r.first_at)]})),this.ctx.nav)}keyLine(t){const s=this.layers.at(-1),e=t?"t":`t ${this.show==="read"?"loaded automatically":"read on purpose"}`;return s?.kind==="drill"?[s.list.keyLine(t),e].filter(o=>o!=="").join(" \xB7 "):s?.kind==="readers"||(this.view?.rows.length??0)===0?e:[t?"\u2191\u2193 Enter":`\u2191\u2193 document \xB7 Enter: agents that ${$[this.show].verb} it`,e].join(" \xB7 ")}escapeLabel(){const t=this.layers.at(-1);if(t?.kind==="drill")return"back to documents";if(t?.kind==="readers")return"back"}land(){this.show="read",this.layers=[],this.cursor=0,this.doc=0}}const et=M(b=>new I(b),"createMemoryView");export{et as createMemoryView};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var C=Object.defineProperty;var m=(t,e)=>C(t,"name",{value:e,configurable:!0});import{matchesKey as l,visibleWidth as W}from"@earendil-works/pi-tui";import{theme as f,wrapText as D}from"../../core/tui/panel.js";import{hbar as G}from"./chart.js";import{formatCount as x,formatDuration as H,formatPrice as P,formatTokens as L,padLeft as g,padRight as w,unavailable as T}from"./format.js";import{byEstimate as O,fullNameLine as j,graphLabel as $}from"./graphs.js";import{NARROW_BAR_CELLS as K,isNarrow as V,markRow as S,moreRow as Y,textWidth as B}from"./view.js";const q=10;function b(t,e){return t.ok?e(t.value):"unavailable"}m(b,"measured");function R(t){return[{label:"GRAPHS",short:"GRAPHS",value:b(t.graphs,e=>x(e.count)),landing:{tab:"graphs",at:"size-chart"}},{label:"AGENTS SPAWNED",short:"SPAWNED",value:b(t.graphs,e=>x(e.spawned)),landing:{tab:"graphs",at:"kind-chart"}},{label:"MEDIAN AGENT TIME",short:"MEDIAN TIME",value:b(t.time,e=>e.all===null?"none finished":H(e.all.median_ms)),landing:{tab:"time",at:"all-agents"}},{label:"API-PRICE EST.",short:"API-PRICE EST.",value:b(t.usage,e=>P(e.api_price_estimate)),landing:{tab:"usage",at:"top-model"}},{label:"MEMORY READS",short:"MEMORY READS",value:b(t.memory,e=>x(e.read.entries)),landing:{tab:"memory",at:"top-read-document"}}]}m(R,"headlines");function y(t){const e=[t.graphs,t.time,t.usage,t.memory].flatMap(n=>n.ok?[]:[n.reason]);return[...new Set(e)]}m(y,"failures");class F{static{m(this,"OverviewView")}ctx;zone="headline";headline=0;row=0;shown=0;constructor(e){this.ctx=e}ranked(){const e=this.ctx.data.graphs;return e.ok?[...e.value.graphs].sort(O):[]}rowCount(){const e=this.ranked().length;return this.shown+(e>this.shown?1:0)}handleKey(e){if(l(e,"escape"))return"back";if(l(e,"left")||l(e,"h"))return this.zone==="headline"&&(this.headline=Math.max(0,this.headline-1)),"handled";if(l(e,"right")||l(e,"l"))return this.zone==="headline"&&(this.headline=Math.min(4,this.headline+1)),"handled";if(l(e,"down")||l(e,"j"))return this.zone==="headline"?this.rowCount()>0&&(this.zone="list",this.row=0):this.row=Math.min(this.rowCount()-1,this.row+1),"handled";if(l(e,"up")||l(e,"k"))return this.zone==="list"&&(this.row===0?this.zone="headline":this.row-=1),"handled";if(l(e,"enter")){if(this.zone==="headline")return this.ctx.nav.openTab(R(this.ctx.data)[this.headline].landing),"handled";const n=this.row<this.shown?this.ranked()[this.row]:void 0;return n!==void 0?this.ctx.nav.openGraphDetail(n.graph_id):this.ctx.nav.openTab({tab:"graphs",at:"list-by-estimate"}),"handled"}return"unhandled"}keyLine(e){return e?"\u2190\u2192\u2191\u2193 \xB7 Enter":"\u2190\u2192\u2191\u2193 select \xB7 Enter open"}render(e,n,a){const s=V(e),i=s?this.narrowHeadlines(e,a):this.wideHeadlines(e,a);for(const o of y(a))i.push(...D(T(o),e).map(h=>f.fg("warning",h)));return i.push(""),i.push(...this.topGraphs(e,Math.max(3,n-i.length),a,s)),i}mark(e){const n=this.zone==="headline"&&this.headline===e;return{selected:n,prefix:n?"> ":" "}}wideHeadlines(e,n){const a=Math.floor(e/5);let s="",i="";return R(n).forEach((o,h)=>{const{selected:r,prefix:c}=this.mark(h),d=w(`${c}${o.label}`,a);s+=r?f.bold(d):f.fg("dim",d);const E=w(` ${o.value}`,a);i+=r?f.bold(E):E}),[s,i]}narrowHeadlines(e,n){const a=R(n).map((s,i)=>{const{selected:o,prefix:h}=this.mark(i),r=`${h}${s.short} ${s.value}`;return o?f.bold(r):r});return[a.slice(0,3).join(" "),a.slice(3).join(" ")].map(s=>w(s,e))}topGraphs(e,n,a,s){const[i,o,h]=s?[7,9,7]:[7,9,8],r=a.graphs.ok?this.ranked():[];let c,d;if(s)c=K,d=Math.max(8,e-2-i-1-c-o-h-1);else{const u=e-2-i-1-o-h-3,p=Math.max(0,...r.map(A=>W($(A))));d=B(u,p,30),c=Math.max(10,u-d)}const M=`${w(s?"Top graphs, API est.":"Top graphs, by API-price estimate",2+d)}${g("agents",i)} ${" ".repeat(c)}${g("est.",o)}${g("tokens",h)}`;if(!a.graphs.ok)return[M,` ${T(a.graphs.reason)}`];if(r.length===0)return this.shown=0,[M," None in this window."];const I=Math.max(1,n-3);this.shown=Math.min(s?q:r.length,r.length,I),this.zone==="list"&&(this.row=Math.min(this.row,this.rowCount()-1));const N=r[0].api_price_estimate,v=[f.fg("dim",M)];for(let u=0;u<this.shown;u+=1){const p=r[u],A=`${w($(p),d)}${g(x(p.active_agents),i)} ${G(p.api_price_estimate,N,c)}${g(P(p.api_price_estimate),o)}${g(L(p.tokens),h)}`;v.push(S(A,this.zone==="list"&&this.row===u))}const z=r.length-this.shown;if(z>0){const u=Y(z,"graphs").slice(2);v.push(S(u,this.zone==="list"&&this.row===this.shown))}const _=this.zone==="list"?r[this.row]:void 0,k=_!==void 0&&this.row<this.shown?j($(_),d):void 0;return k!==void 0&&v.push(k),v}}const ne=m(t=>new F(t),"createOverviewView");export{ne as createOverviewView};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type Component, type Focusable, type TUI } from '@earendil-works/pi-tui';
|
|
2
|
+
import { type TuiPageControl } from '../../core/tui/page-host.js';
|
|
3
|
+
type PageResult = {
|
|
4
|
+
open: string;
|
|
5
|
+
};
|
|
6
|
+
export declare class AnalyticsShell implements Component, Focusable {
|
|
7
|
+
private readonly tui;
|
|
8
|
+
private readonly rows;
|
|
9
|
+
private readonly suspendForChild;
|
|
10
|
+
private readonly control;
|
|
11
|
+
focused: boolean;
|
|
12
|
+
private readonly client;
|
|
13
|
+
private asOf;
|
|
14
|
+
private window;
|
|
15
|
+
private project;
|
|
16
|
+
private tab;
|
|
17
|
+
/** Detail views opened over the current tab, innermost last. */
|
|
18
|
+
private stack;
|
|
19
|
+
private load;
|
|
20
|
+
private overlay;
|
|
21
|
+
/** Identifies the newest request; an answer carrying an older number is dropped. */
|
|
22
|
+
private seq;
|
|
23
|
+
/** Picker choices from the newest successful answer. */
|
|
24
|
+
private projects;
|
|
25
|
+
constructor(tui: TUI, rows: () => number, suspendForChild: () => () => void, control: TuiPageControl<PageResult>);
|
|
26
|
+
/** Issue a request for the current T, window, and scope. */
|
|
27
|
+
request(): void;
|
|
28
|
+
private ready;
|
|
29
|
+
private nav;
|
|
30
|
+
/** Nothing is cached: every render draws from state. */
|
|
31
|
+
invalidate(): void;
|
|
32
|
+
dispose(): void;
|
|
33
|
+
private get shownTab();
|
|
34
|
+
private get topView();
|
|
35
|
+
handleInput(data: string): void;
|
|
36
|
+
private handleKey;
|
|
37
|
+
private cycleTab;
|
|
38
|
+
private pickerKey;
|
|
39
|
+
private sourcesKey;
|
|
40
|
+
render(width: number): string[];
|
|
41
|
+
private renderPage;
|
|
42
|
+
private fit;
|
|
43
|
+
private scopeLabel;
|
|
44
|
+
private controlsRow;
|
|
45
|
+
private tabRow;
|
|
46
|
+
private coverageLine;
|
|
47
|
+
private keyParts;
|
|
48
|
+
/** The longest spelling that fits: wide keys with the wide tail, then with the
|
|
49
|
+
* short tail, then the narrow keys. */
|
|
50
|
+
private keyLine;
|
|
51
|
+
private body;
|
|
52
|
+
private pickerBody;
|
|
53
|
+
private sourcesBody;
|
|
54
|
+
/** The transcript scan's failure reason, which every scan-based measure carries. */
|
|
55
|
+
private scanFailure;
|
|
56
|
+
}
|
|
57
|
+
/** `pane` is the tmux pane the page was opened from (the prefix menu passes it);
|
|
58
|
+
* without it, `o` opens beside this process's own pane. */
|
|
59
|
+
export declare function runAnalytics(pane: string | undefined): Promise<void>;
|
|
60
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var C=Object.defineProperty;var l=(c,e)=>C(c,"name",{value:e,configurable:!0});import{spawnSync as O}from"node:child_process";import{basename as R}from"node:path";import{matchesKey as o,truncateToWidth as D,visibleWidth as b}from"@earendil-works/pi-tui";import{localClient as W}from"../../api/node-transport.js";import{runShellInBackground as N}from"../../core/runtime/placement-tmux.js";import{runTuiPage as V}from"../../core/tui/page-host.js";import{rule as _,theme as d,wrapText as k}from"../../core/tui/panel.js";import{shellQuote as q}from"../../shared/shell-quote.js";import{ExitCode as B}from"../../types.js";import{formatClock as F,formatCount as f,formatDateTime as y,formatPrice as G,formatTimezone as H,padRight as v,unavailable as x}from"./format.js";import{createGraphDetailView as K}from"./graph-detail.js";import{createGraphsView as U}from"./graphs.js";import{createMemoryView as z}from"./memory.js";import{createOverviewView as X}from"./overview.js";import{createTimeView as Y}from"./time.js";import{createUsageView as Q}from"./usage.js";import{MAX_PAGE_WIDTH as J,TABS as m,isNarrow as Z,listWindow as ee,moreRow as te}from"./view.js";const $=50,j=20,A=36e5,se={"24h":24*A,"7d":168*A},T={"24h":"Last 24h","7d":"Last 7d"},L=16;function E(c){return c.graphs.ok&&c.memory.ok&&c.agents.length===0&&c.memory.value.read.entries===0&&c.memory.value.loaded.entries===0}l(E,"isEmpty");function re(c){return(c instanceof Error?c.message:String(c)).trim().replace(/\.$/,"")||"unknown error"}l(re,"errorReason");class ne{static{l(this,"AnalyticsShell")}tui;rows;suspendForChild;control;focused=!1;client=W({autostart:!1});asOf=new Date;window="24h";project=null;tab="overview";stack=[];load={kind:"loading"};overlay;seq=0;projects=[];constructor(e,t,s,n){this.tui=e,this.rows=t,this.suspendForChild=s,this.control=n}request(){const e=++this.seq;this.load={kind:"loading"},this.stack=[];const t={as_of:this.asOf.toISOString(),window:this.window,...this.project!==null?{project:this.project}:{}};this.client.analytics(t).then(s=>{e===this.seq&&(this.projects=s.projects,this.load=this.ready(s),this.tui.requestRender())},s=>{e===this.seq&&(this.load={kind:"error",reason:re(s)},this.tui.requestRender())}),this.tui.requestRender()}ready(e){const t={data:e,nav:this.nav()};return{kind:"ready",data:e,ctx:t,views:{overview:X(t),graphs:U(t),time:Y(t),memory:z(t),usage:Q(t)}}}nav(){return{openTab:l(e=>{this.load.kind==="ready"&&(this.stack=[],this.tab=e.tab,this.load.views[e.tab].land?.(e),this.tui.requestRender())},"openTab"),openGraphDetail:l((e,t)=>{this.load.kind==="ready"&&(this.stack.push({view:K(this.load.ctx,e,t),tab:"graphs"}),this.tui.requestRender())},"openGraphDetail"),openInspector:l(e=>{const t=this.suspendForChild();try{O("crtr",["surface","inspect",e,"--read-only"],{stdio:"inherit"})}finally{t()}},"openInspector"),openConversation:l(e=>this.control.submit({open:e}),"openConversation"),readFinalReport:l(async e=>(await this.client.historyRead({ref:e})).content,"readFinalReport"),requestRender:l(()=>this.tui.requestRender(),"requestRender")}}invalidate(){}dispose(){this.seq+=1}get shownTab(){return this.stack.at(-1)?.tab??this.tab}get topView(){if(!(this.load.kind!=="ready"||E(this.load.data)))return this.stack.at(-1)?.view??this.load.views[this.tab]}handleInput(e){this.handleKey(e),this.tui.requestRender()}handleKey(e){if(o(e,"ctrl+c")||o(e,"q"))return this.control.cancel();if(this.rows()<j||this.tui.terminal.columns<$){o(e,"escape")&&this.control.cancel();return}if(this.overlay?.kind==="picker")return this.pickerKey(e,this.overlay);if(this.overlay?.kind==="sources")return this.sourcesKey(e,this.overlay);if(o(e,"shift+tab"))return this.cycleTab(-1);if(o(e,"tab"))return this.cycleTab(1);if(o(e,"w"))return this.window=this.window==="24h"?"7d":"24h",this.request();if(o(e,"shift+r"))return this.asOf=new Date,this.request();if(o(e,"p")){const n=this.projects.findIndex(r=>r.cwd===this.project);this.overlay={kind:"picker",cursor:n+1};return}if(o(e,"s")){this.overlay={kind:"sources",scroll:0};return}const t=this.topView,s=t===void 0?"unhandled":t.handleKey(e);(s==="back"||s==="unhandled"&&o(e,"escape"))&&(this.stack.length>0?this.stack.pop():this.control.cancel())}cycleTab(e){const t=m.findIndex(s=>s.id===this.shownTab);this.tab=m[(t+e+m.length)%m.length].id,this.stack=[]}pickerKey(e,t){const s=this.projects.length+1;if(o(e,"escape")||o(e,"p"))this.overlay=void 0;else if(o(e,"down")||o(e,"j"))t.cursor=Math.min(s-1,t.cursor+1);else if(o(e,"up")||o(e,"k"))t.cursor=Math.max(0,t.cursor-1);else if(o(e,"enter")){this.overlay=void 0;const n=t.cursor===0?null:this.projects[t.cursor-1].cwd;n!==this.project&&(this.project=n,this.request())}}sourcesKey(e,t){o(e,"escape")||o(e,"s")?this.overlay=void 0:o(e,"down")||o(e,"j")?t.scroll+=1:(o(e,"up")||o(e,"k"))&&(t.scroll=Math.max(0,t.scroll-1))}render(e){const t=this.rows();if(e<$||t<j){const r=k(`Analytics needs at least ${$} \xD7 ${j}; this window is ${e} \xD7 ${t}.`,e);return this.fit(r,t,e)}const s=Math.min(e,J);if(s===e)return this.renderPage(e,t);const n=" ".repeat(Math.floor((e-s)/2));return this.renderPage(s,t).map(r=>r===""?"":`${n}${r}`)}renderPage(e,t){const s=Z(e),n=[this.controlsRow(e,s),this.tabRow(s),_(e)],r=this.coverageLine(),i=[...r!==void 0?[r]:[],_(e),this.keyLine(e,s)],a=Math.max(1,t-n.length-i.length);return this.fit([...n,...this.fit(this.body(e,a),a,e),...i],t,e)}fit(e,t,s){const n=e.slice(0,t).map(r=>D(r,s,"\u2026"));for(;n.length<t;)n.push("");return n}scopeLabel(){return this.project===null?"All projects":R(this.project)||this.project}controlsRow(e,t){const s=`${this.scopeLabel()} \u25BE`,n=`as of ${F(this.asOf)}`,r=this.window==="24h",i=t?`${r?"[24h] 7d":"24h [7d]"} \xB7 ${s}`:`${v(s,34)}${r?"[ Last 24h ] Last 7d ":" Last 24h [ Last 7d ]"}`,a=e-b(i)-b(n)-(t?0:3);return a>=2?`${i}${" ".repeat(a)}${d.fg("dim",n)}`:`${i} ${d.fg("dim",n)}`}tabRow(e){const t=this.shownTab;return m.map(({id:s,label:n})=>{const r=s===t?`[${n}]`:e?n:` ${n}`,i=e?r:v(r,12);return s===t?d.fg("accent",d.bold(i)):i}).join(e?" ":"")}coverageLine(){if(this.load.kind!=="ready")return;const e=this.load.data.transcripts;if(!(e===null||e.unreadable.length===0))return d.fg("warning",`Sources: ${f(e.unreadable.length)} of ${f(e.total)} transcripts unreadable (s)`)}keyParts(e){if(this.overlay?.kind==="picker")return[e?"\u2191\u2193 Enter":"\u2191\u2193 project \xB7 Enter choose",e?"Esc":"Esc close picker"];if(this.overlay?.kind==="sources")return[e?"\u2191\u2193":"\u2191\u2193 scroll",e?"Esc":"Esc close sources"];const t=this.topView,s=t?.keyLine(e)??"",n=t?.escapeLabel?.()??(this.stack.length>0?"back":"close");return[...s!==""?[s]:[],e?"Esc":`Esc ${n}`]}keyLine(e,t){const s="Tab tab \xB7 w 24h/7d \xB7 p project \xB7 R refresh \xB7 s sources \xB7 q close",n="Tab w p R s q",r=[...this.keyParts(!0),n].join(" \xB7 "),a=(t?[]:[[...this.keyParts(!1),s].join(" \xB7 "),[...this.keyParts(!1),n].join(" \xB7 ")]).find(h=>b(h)<=e)??r;return d.fg("dim",a)}body(e,t){if(this.overlay?.kind==="sources")return this.sourcesBody(e,t,this.overlay);if(this.overlay?.kind==="picker")return this.pickerBody(t,this.overlay);switch(this.load.kind){case"loading":return["Computing\u2026"];case"error":return k(`Could not load analytics: ${this.load.reason}. R retries.`,e);case"ready":return E(this.load.data)?[`No recorded activity in ${this.scopeLabel()}, ${T[this.window]}.`]:this.topView.render(e,t,this.load.data)}}pickerBody(e,t){const s=[{label:"All projects",detail:"",path:""},...this.projects.map(a=>({label:R(a.cwd)||a.cwd,detail:G(a.api_price_estimate),path:a.cwd}))],n=[d.bold("Project"),d.fg("dim","Projects with at least one active agent in the window, by API-price estimate."),""],r=ee(s.length,t.cursor,Math.max(1,e-n.length)),i=[...n];for(let a=r.start;a<r.end;a+=1){const h=s[a],w=a===t.cursor,u=(a===0?null:h.path)===this.project?" (current)":"",p=`${v(h.label,32)} ${h.detail.padStart(6)}${u}${w&&h.path!==""?` ${h.path}`:""}`;i.push(w?d.bold(`> ${p}`):` ${p}`)}return r.more>0&&i.push(te(r.more,"projects")),i}sourcesBody(e,t,s){const n=this.load,r=n.kind==="ready"?n.data:void 0,i=n.kind==="loading"?"Computing\u2026":"Could not load analytics.",a=r!==void 0?new Date(r.window_start):new Date(this.asOf.getTime()-se[this.window]),h=[["Window",`${T[this.window]}, rolling: ${y(a)} \u2192 ${y(this.asOf)} ${H(this.asOf)}, frozen until R.`],["Scope",this.project===null?"All projects.":this.project],["Graph","A root agent and every agent whose parent chain leads to it. Every agent is in exactly one graph, so graph rows add up to page totals. An agent whose parent was deleted joins the graph of its topmost surviving ancestor, marked (root deleted)."],["Graph view","The canvas graph view follows report subscriptions and can group agents differently."],["Active","An agent with at least one model response inside the window."],["Spawned","A non-root agent created inside the window."],["Finished","An agent whose final report landed inside the window. Its agent time is created \u2192 final report, full length, not clipped to the window."],["Model response","An assistant message in any transcript bound to the agent whose stop reason is not error, at its recorded time. Responses copied into a forked agent count once, for the agent that produced them; one provider response id counts once."],["Model","The provider and model recorded on each response, not the current setting."],["Tokens","Per response: input + output + cache read + cache write."],["Context size","Per response: input + cache read + cache write."],["API-price est.","The price pi recorded for each response at published API rates when it was made; never recomputed. It is not what your subscriptions charged."],["Transcripts",r===void 0?i:r.transcripts===null?x(this.scanFailure(r)):`${f(r.transcripts.read)} of ${f(r.transcripts.total)} transcripts read.`],["Unknown",r===void 0?i:r.unknown_responses===null?x(this.scanFailure(r)):`${f(r.unknown_responses)} responses with no model or usage recorded.`],["Memory reads",`Read on purpose: an agent ran crtr memory read and got the document back. Loaded automatically: a document's full body entered an agent's context another way \u2014 at launch, by memory routing, as a companion of a read, or by a memory slash command. ${r===void 0?i:r.memory_log_started_at===null?"No recording start time is stored.":`Recorded since ${y(r.memory_log_started_at)}.`} Reads made while crtrd was unreachable are not recorded.`],["Time split","Running and waiting time are not recorded."],["History",`${r===void 0?i:r.oldest_agent_created===null?"No surviving agents.":`Oldest surviving agent created ${y(r.oldest_agent_created)}.`} Deleted agents and their transcripts are not counted.`]],w=Math.max(10,e-L-2),u=[d.bold(`Sources \xB7 ${T[this.window]} \xB7 ${this.scopeLabel()}`),""];for(const[g,I]of h)k(I,w).forEach((P,S)=>{u.push(`${v(S===0?g:"",L)} ${P}`)});const p=r?.transcripts?.unreadable??[];if(p.length>0){u.push("","Unreadable transcripts:");for(const g of p)u.push(` ${g.node_id} (${g.reason})`)}const M=Math.max(0,u.length-t);return s.scroll=Math.min(s.scroll,M),u.slice(s.scroll,s.scroll+t)}scanFailure(e){return e.graphs.ok?"the transcript scan failed":e.graphs.reason}}async function je(c){if(!process.stdin.isTTY||!process.stdout.isTTY){process.stderr.write(`crtr canvas analytics needs an interactive terminal; open it from the prefix menu (shift+a) or run it in a terminal.
|
|
2
|
+
`),process.exitCode=B.GENERAL;return}const e=await V(({tui:t,terminal:s,suspendForChild:n},r)=>{const i=new ne(t,()=>s.rows,n,r);return i.request(),i});if(e!==void 0){const t=c??process.env.TMUX_PANE,s=t!==void 0&&t!==""?` --pane ${q(t)}`:"";N(`crtr surface node focus ${q(e.open)}${s} >/dev/null 2>&1`)}process.exit(0)}l(je,"runAnalytics");export{ne as AnalyticsShell,je as runAnalytics};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var H=Object.defineProperty;var T=(w,t)=>H(w,"name",{value:t,configurable:!0});import{matchesKey as y}from"@earendil-works/pi-tui";import{theme as _,wrapText as V}from"../../core/tui/panel.js";import{columnChart as j,logAxisLabels as G,percentileLine as q}from"./chart.js";import{AgentDrilldown as z,graphName as B}from"./drilldown.js";import{formatCount as D,formatDuration as $,formatTimeOfDay as F,padLeft as M,padRight as A,plural as J,truncate as I,unavailable as P}from"./format.js";import{MAX_COLUMN_CHART_ROWS as S,isNarrow as K,listWindow as Q,markRow as E,moreRow as Y}from"./view.js";const v=6e4,b=60*v,Z=v,tt=4*b,nt=[{ms:v,label:"1m"},{ms:5*v,label:"5m"},{ms:15*v,label:"15m"},{ms:b,label:"1h"},{ms:4*b,label:"4h"}],O="Created \u2192 final report, by kind",U="\u2500\u2500 10th\u201390th percentile \u25CF median";class et{static{T(this,"TimeView")}ctx;cursor=0;layers=[];narrow=!1;constructor(t){this.ctx=t}get time(){return this.ctx.data.time.ok?this.ctx.data.time.value:void 0}items(t){const n=this.time;if(n===void 0)return[];const a=n.all===null?[]:[{kind:"all",stats:n.all},...n.by_kind.map(e=>({kind:"kind",name:e.kind,stats:e}))];return t?[...a,{kind:"activity"}]:a}render(t,n,a){if(!a.time.ok)return[`Time: ${P(a.time.reason)}`];const e=a.time.value,s=K(t);this.narrow=s,s||(this.layers=this.layers.filter(r=>r.kind!=="activity"));const o=this.items(s);this.cursor=Math.min(this.cursor,Math.max(0,o.length-1));const i=V(this.summary(e),t),l=this.layers.at(-1);if(l?.kind==="drill")return[...i,"",...l.list.render(t,n-i.length-1)];if(l?.kind==="activity")return[...i,"",...this.activity(e,t,Math.max(2,Math.min(8,n-i.length-4)))];const u=[...i,"",...s?[O,_.fg("dim",U)]:[`${A(O,38)}${_.fg("dim",U)}`]];if(e.all===null){const r=[...u,"None in this window."];return s?[...r,"",E(I(`${this.activityTitle(e)} \u2192`,t-2),!0)]:[...r,"",...this.activity(e,t,Math.max(4,Math.min(S,n-r.length-4)))]}const h=this.layout(t,s),f=o.filter(r=>r.kind==="kind"),c=[...u,_.fg("dim",`${" ".repeat(2+h.label+h.count+2)}${G(nt,h.axis)}${M("median",h.num)}${M("p90",h.num)}`)];c.push(this.row(o[0],h,this.cursor===0),"");const m=T(r=>s?2:r+3,"tail"),g=n-c.length;let k=Math.max(4,Math.min(S,g-f.length-m(0)));!s&&g-m(k)<Math.min(f.length,3)&&(k=2);const p=Q(f.length,this.cursor-1,Math.max(1,g-m(k)));for(let r=p.start;r<p.end;r+=1)c.push(this.row(f[r],h,this.cursor===r+1));return p.more>0&&c.push(Y(p.more,"kinds")),c.push(""),s?c.push(E(I(`${this.activityTitle(e)} \u2192`,t-2),this.cursor===o.length-1)):c.push(...this.activity(e,t,k)),c}summary(t){const n=t.all;return n===null?"No agents finished in this window.":`${J(n.count,"agent","agents")} finished \xB7 median ${$(n.median_ms)} \xB7 p90 ${$(n.p90_ms)} \xB7 longest ${$(n.max_ms)}`}layout(t,n){const a=n?12:14,e=n?4:5,s=n?7:8,o=t-2-a-e-2-2*s-1,i=Math.max(10,n?Math.min(60,o):o);return{label:a,count:e,num:s,axis:{minMs:Z,maxMs:tt,cells:i}}}row(t,n,a){if(t.kind==="activity")return"";const e=t.kind==="all"?"all agents":t.name,{stats:s}=t,o=`${A(e,n.label)}${M(D(s.count),n.count)} ${q(s,n.axis)}${M($(s.median_ms),n.num)}${M($(s.p90_ms),n.num)}`;return E(o,a)}activityTitle(t){return`Agents with at least one model response, per ${t.activity.bucket_ms>=24*b?"day":"hour"}`}activity(t,n,a){const{buckets:e,max:s,bucket_ms:o}=t.activity,i=o>=24*b,l=this.activityTitle(t);if(s===0||e.length===0)return[l,"None in this window."];const u=`most in one ${i?"day":"hour"}: ${D(s)}`,h=n-2-4,f=K(n),c=Math.floor((h+1)/e.length),m=!f&&c>=6?2:1,g=Math.max(1,f?Math.min(i?6:2,c-1):c-m),k=2+e.length*(g+m)-m,p=f?Math.min(n-u.length,60):k-u.length,r=n-2>=l.length+u.length+4&&p>=l.length+2?[`${A(l,p)}${_.fg("dim",u)}`]:[l,_.fg("dim",u)],X=j(e.map(x=>x.agents),a,g,m).map(x=>` ${x}`),L=g+m;let d="";e.forEach((x,C)=>{if(!i&&C%6!==0)return;const R=C*L,W=i?new Date(x.start).toLocaleDateString("en-US",{weekday:"short"}):F(x.start);R<d.length+(d===""?0:1)||(d=d.padEnd(R)+W)});const N=e.length*L-m;return d=N>=d.length+1?`${d.padEnd(N)}now`:d,[...r,...X,_.fg("dim",` ${d}`)]}handleKey(t){const n=this.layers.at(-1);if(n?.kind==="drill")return n.list.handleKey(t)==="close"&&this.layers.pop(),"handled";if(n?.kind==="activity")return y(t,"escape")?(this.layers.pop(),"handled"):"unhandled";if(y(t,"escape"))return"back";if(!this.ctx.data.time.ok)return"unhandled";const a=this.items(this.narrow);if(y(t,"down")||y(t,"j"))this.cursor=Math.min(a.length-1,this.cursor+1);else if(y(t,"up")||y(t,"k"))this.cursor=Math.max(0,this.cursor-1);else if(y(t,"enter")){const e=a[this.cursor];e?.kind==="activity"?this.layers.push({kind:"activity"}):e!==void 0&&this.layers.push({kind:"drill",list:this.drill(e.kind==="kind"?e.name:void 0)})}else return"unhandled";return"handled"}drill(t){const n=this.ctx.data,a=n.agents.filter(i=>i.finished_in_window&&i.agent_time_ms!==null&&(t===void 0||i.kind===t)).sort((i,l)=>l.agent_time_ms-i.agent_time_ms||i.name.localeCompare(l.name)),e=[...t===void 0?[{header:"kind",kind:"text",max:18}]:[],{header:"agent",kind:"text"},{header:"graph",kind:"text"},{header:"created\u2192final",kind:"number"}],s=a.map(i=>({node_id:i.node_id,graph_id:i.graph_id,cells:[...t===void 0?[i.kind]:[],i.name,B(n,i.graph_id),$(i.agent_time_ms)]})),o=t===void 0?"All finished agents, longest first":`${t} \xB7 finished agents, longest first`;return new z(o,e,s,this.ctx.nav)}keyLine(t){const n=this.layers.at(-1);return n?.kind==="drill"?n.list.keyLine(t):n?.kind==="activity"||this.items(t).length===0?"":t?"\u2191\u2193 Enter":"\u2191\u2193 kind \xB7 Enter: that kind's agents, longest first"}escapeLabel(){const t=this.layers.at(-1);if(t?.kind==="drill")return"back to kinds";if(t?.kind==="activity")return"back"}land(){this.layers=[],this.cursor=0}}const mt=T(w=>new et(w),"createTimeView");export{mt as createTimeView};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var V=Object.defineProperty;var R=(b,e)=>V(b,"name",{value:e,configurable:!0});import{matchesKey as y,visibleWidth as z}from"@earendil-works/pi-tui";import{columns as H,rule as S,theme as M,wrapText as P}from"../../core/tui/panel.js";import{OTHER_FILL as X,STACK_FILLS as q,hbar as N,stackLegend as G,stackedBar as J}from"./chart.js";import{AgentDrilldown as Q,graphName as Y}from"./drilldown.js";import{formatCount as Z,formatPrice as E,formatShare as ee,formatTokens as f,padLeft as h,padRight as x,plural as te,truncate as K,unavailable as ne}from"./format.js";import{NARROW_BAR_CELLS as T,isNarrow as se,listWindow as W,markRow as B,moreRow as U,textWidth as F}from"./view.js";const oe="API-price est. = the price pi recorded for each response at published API rates. It is not what your subscriptions charged.",O="Which models each kind used",re=["< 50k","50\u2013100k","100\u2013150k","150\u2013200k","200k+"],v=R(b=>`${b.provider}/${b.model}`,"key");class ie{static{R(this,"UsageView")}ctx;cursor=0;layers=[];narrow=!1;labels=new Map;constructor(e){if(this.ctx=e,!e.data.usage.ok)return;const{models:t,legend:s}=e.data.usage.value,o=new Map([...t,...s].map(r=>[v(r),r])),i=new Map;for(const r of o.values())i.set(r.model,(i.get(r.model)??0)+1);for(const[r,n]of o)this.labels.set(r,i.get(n.model)>1?r:n.model)}label(e){return this.labels.get(v(e))??e.model}get usage(){return this.ctx.data.usage.ok?this.ctx.data.usage.value:void 0}count(){const e=this.usage;return e===void 0?0:this.layers.at(-1)?.kind==="detail"?e.models.length:e.models.length+(this.narrow?e.kinds.length>0?1:0:e.kinds.length)}render(e,t,s){if(!s.usage.ok)return[`Usage: ${ne(s.usage.reason)}`];const o=s.usage.value,i=se(e);this.narrow=i,i||(this.layers=this.layers.filter(_=>_.kind!=="kinds")),this.cursor=Math.min(this.cursor,Math.max(0,this.count()-1));const r=P(this.summary(o),e),n=P(oe,e).map(_=>M.fg("dim",_)),a=this.layers.at(-1);if(a?.kind==="drill")return[...r,"",...a.list.render(e,t-r.length-1)];if(a?.kind==="kinds")return[...r,"",...this.kindsChart(o,e,t-r.length-1-n.length-1,a.cursor),"",...n];if(i&&a?.kind==="detail")return[...r,"",...this.detail(o.models[a.model],e,i)];const k=s.unknown_responses!==null&&s.unknown_responses>0?s.unknown_responses:0,d=[...r,""];if(o.models.length===0)return[...d,"By model","None in this window.",...k>0?[this.unknownRow(k,e,12)]:[],"",...n];const m=this.widths(o,e,i),u=i?2:a?.kind==="detail"?12:4+Math.min(o.kinds.length,8),l=Math.max(1,t-d.length-1-(k>0?1:0)-u-n.length),p=this.modelsChart(o,m,e,Math.min(o.models.length+1,l),i),g=[...d,...p,...k>0?[this.unknownRow(k,e,m.label)]:[]];if(i){const _=o.kinds.length>0?[B(K(`${O} \u2192`,e-2),this.cursor===o.models.length)]:[];return[...g,"",..._,"",...n]}return g.push(S(e)),a?.kind==="detail"?g.push(...this.detail(o.models[a.model],e,!1)):g.push(...this.kindsChart(o,e,t-g.length-n.length-1,this.cursor-o.models.length)),[...g,S(e),...n]}summary(e){const t=[`${E(e.api_price_estimate)} API-price estimate`,`${f(e.tokens)} tokens`];return e.median_context!==null&&t.push(`median context ${f(e.median_context)} per response`),t.join(" \xB7 ")}widths(e,t,s){const o=Math.max(7,...e.models.map(n=>this.label(n).length));if(s)return{label:Math.max(8,Math.min(o,t-2-1-T-8-7-8)),bar:T,est:8,tokens:7,context:8};const i=t-2-2-15-9-16,r=F(i,o,7);return{label:r,bar:Math.max(6,i-r),est:15,tokens:9,context:16}}modelsChart(e,t,s,o,i){const r=2+t.label+(i?1:2)+t.bar,n=i?`${x("By model",r)}${h("est.",t.est)}${h("tokens",t.tokens)}${h("context",t.context)}`:`${x("By model",r)}${h("API-price est.",t.est)}${h("tokens",t.tokens)}${h("median context",t.context)}`,a=[M.fg("dim",K(n,s))],k=Math.max(0,...e.models.map(u=>u.api_price_estimate)),d=this.cursor<e.models.length?this.cursor:-1,m=W(e.models.length,Math.max(0,d),Math.max(1,o-1));for(let u=m.start;u<m.end;u+=1){const l=e.models[u],p=`${x(this.label(l),t.label)}${i?" ":" "}${N(l.api_price_estimate,k,t.bar)}${h(E(l.api_price_estimate),t.est)}${h(f(l.tokens),t.tokens)}${h(f(l.context.median),t.context)}`;a.push(B(p,u===d))}return m.more>0&&a.push(U(m.more,"models")),a}unknownRow(e,t,s){return M.fg("dim",K(` ${x("unknown",s)} ${te(e,"response","responses")} with no model or usage recorded`,t))}kindsChart(e,t,s,o){const i=e.legend.map(v),r=[...e.legend.map((c,$)=>q[$]),X],n=e.kinds.map(c=>{const $=i.map(C=>c.responses_by_model.find(I=>v(I)===C)?.responses??0),w=c.responses_by_model.reduce((C,I)=>C+I.responses,0);return[...$,w-$.reduce((C,I)=>C+I,0)]}),a=n.some(c=>c.at(-1)>0),k=[...e.legend.map(c=>this.label(c)),...a?["other"]:[]],d=this.narrow,m=d?8:15,u=d?7:9,l=Math.max(...e.kinds.map(c=>c.kind.length),4),p=t-2-2-m-u,g=d?Math.max(6,Math.min(12,l)):F(p,l,6),_=d?T:Math.max(6,p-g),j=2+g+2+_,D=d?"":`${O} \xB7 share of its responses`,L=[...d?[O]:[],M.fg("dim",K(`${x(D,j)}${h(d?"est.":"API-price est.",m)}${h("tokens",u)}`,t)),...this.legendLines(G(k,r),t-2).map(c=>` ${c}`)];if(e.kinds.length===0)return[...L,"None in this window."];const A=W(e.kinds.length,Math.max(0,o),Math.max(1,s-L.length));for(let c=A.start;c<A.end;c+=1){const $=e.kinds[c],w=`${x($.kind,g)} ${J(n[c],_,r)}${h(E($.api_price_estimate),m)}${h(f($.tokens),u)}`;L.push(B(w,c===o))}return A.more>0&&L.push(U(A.more,"kinds")),L}legendLines(e,t){return z(e)<=t?[e]:P(e,t)}detail(e,t,s){const o=s?t:Math.floor((t-3)/2),i=s?t:t-3-o,r=8,n=R((l,p)=>s?T:Math.max(4,l-2-p-r),"cells"),a=[["cache read",e.tokens_by_type.cache_read],["cache write",e.tokens_by_type.cache_write],["input, not cached",e.tokens_by_type.input],["output",e.tokens_by_type.output]],k=Math.max(0,...a.map(([,l])=>l)),d=[M.bold(`${x(`${this.label(e)} \xB7 tokens by type`,o-r)}${h(f(e.tokens),r)}`),...a.map(([l,p])=>` ${x(l,18)}${N(p,k,n(o,18))}${h(f(p),r)}`),"",` Cache reads were ${ee(e.cache_read_share)} of input tokens`],m=Math.max(0,...e.context.buckets),u=[M.bold(`${x("Context size per response",i-10)}${h("responses",10)}`),...e.context.buckets.map((l,p)=>` ${x(re[p],10)}${N(l,m,n(i,10))}${h(Z(l),r)}`),"",` median ${f(e.context.median)} \xB7 p90 ${f(e.context.p90)} \xB7 max ${f(e.context.max)}`];return s?[...d,"",...u]:H(d,o,u,i)}handleKey(e){const t=this.usage,s=this.layers.at(-1);if(s?.kind==="drill")return s.list.handleKey(e)==="close"&&this.layers.pop(),"handled";if(y(e,"escape"))return s===void 0?"back":(this.layers.pop(),"handled");if(t===void 0)return"unhandled";const o=y(e,"down")||y(e,"j"),i=y(e,"up")||y(e,"k"),r=y(e,"enter");if(s?.kind==="kinds"){if(o)s.cursor=Math.min(t.kinds.length-1,s.cursor+1);else if(i)s.cursor=Math.max(0,s.cursor-1);else if(r)this.openKind(t,s.cursor);else return"unhandled";return"handled"}if(s?.kind==="detail")return this.narrow||!(o||i)?"unhandled":(this.cursor=o?Math.min(t.models.length-1,this.cursor+1):Math.max(0,this.cursor-1),s.model=this.cursor,"handled");if(o)this.cursor=Math.min(this.count()-1,this.cursor+1);else if(i)this.cursor=Math.max(0,this.cursor-1);else if(r){const n=t.models.length;this.cursor<n?this.layers.push({kind:"detail",model:this.cursor}):this.narrow?this.layers.push({kind:"kinds",cursor:0}):this.openKind(t,this.cursor-n)}else return"unhandled";return"handled"}openKind(e,t){const s=e.kinds[t];if(s===void 0)return;const o=this.ctx.data,i=o.agents.filter(n=>n.kind===s.kind&&n.active).sort((n,a)=>a.api_price_estimate-n.api_price_estimate||a.tokens-n.tokens||n.name.localeCompare(a.name)),r=new Q(`${s.kind} \xB7 agents by API-price estimate`,[{header:"agent",kind:"text"},{header:"graph",kind:"text"},{header:"API-price est.",kind:"number"},{header:"tokens",kind:"number"}],i.map(n=>({node_id:n.node_id,graph_id:n.graph_id,cells:[n.name,Y(o,n.graph_id),E(n.api_price_estimate),f(n.tokens)]})),this.ctx.nav);this.layers.push({kind:"drill",list:r})}keyLine(e){const t=this.layers.at(-1);return t?.kind==="drill"?t.list.keyLine(e):t?.kind==="detail"?e?"":"\u2191\u2193 model":t?.kind==="kinds"?e?"\u2191\u2193 Enter":"\u2191\u2193 kind \xB7 Enter: its agents":this.count()===0?"":e?"\u2191\u2193 Enter":"\u2191\u2193 row \xB7 Enter: model \u2192 token and context detail, kind \u2192 its agents"}escapeLabel(){const e=this.layers.at(-1);if(e?.kind==="drill")return"back to kinds";if(e?.kind==="detail")return this.narrow?"back to models":"back to models by kind";if(e?.kind==="kinds")return"back to models"}land(){this.layers=[],this.cursor=0}}const pe=R(b=>new ie(b),"createUsageView");export{pe as createUsageView};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { AnalyticsDTO } from '../../api/dto/analytics.js';
|
|
2
|
+
export type TabId = 'overview' | 'graphs' | 'time' | 'memory' | 'usage';
|
|
3
|
+
export declare const TABS: ReadonlyArray<{
|
|
4
|
+
id: TabId;
|
|
5
|
+
label: string;
|
|
6
|
+
}>;
|
|
7
|
+
/** Where `Enter` on an Overview headline (or its "<n> more graphs" row) lands. */
|
|
8
|
+
export type TabLanding = {
|
|
9
|
+
tab: 'overview';
|
|
10
|
+
} | {
|
|
11
|
+
tab: 'graphs';
|
|
12
|
+
at: 'size-chart' | 'kind-chart' | 'list-by-estimate';
|
|
13
|
+
} | {
|
|
14
|
+
tab: 'time';
|
|
15
|
+
at: 'all-agents';
|
|
16
|
+
} | {
|
|
17
|
+
tab: 'memory';
|
|
18
|
+
at: 'top-read-document';
|
|
19
|
+
} | {
|
|
20
|
+
tab: 'usage';
|
|
21
|
+
at: 'top-model';
|
|
22
|
+
};
|
|
23
|
+
export interface AnalyticsNav {
|
|
24
|
+
openTab(landing: TabLanding): void;
|
|
25
|
+
openGraphDetail(graphId: string, selectAgentId?: string): void;
|
|
26
|
+
openInspector(nodeId: string): void;
|
|
27
|
+
openConversation(nodeId: string): void;
|
|
28
|
+
readFinalReport(ref: string): Promise<string>;
|
|
29
|
+
requestRender(): void;
|
|
30
|
+
}
|
|
31
|
+
export interface AnalyticsViewContext {
|
|
32
|
+
/** The model this view was built for; the same object `render` receives. */
|
|
33
|
+
data: AnalyticsDTO;
|
|
34
|
+
nav: AnalyticsNav;
|
|
35
|
+
}
|
|
36
|
+
export interface AnalyticsTabView {
|
|
37
|
+
/** Exactly `height` rows (the shell pads or cuts), each at most `width`
|
|
38
|
+
* columns. `isNarrow(width)` picks the 50–95 column layout. */
|
|
39
|
+
render(width: number, height: number, data: AnalyticsDTO): string[];
|
|
40
|
+
/** `key` is raw terminal input; match it with pi-tui's `matchesKey`. The
|
|
41
|
+
* shell takes Tab, Shift+Tab, q, w, R, p, s, and Ctrl+C before the view.
|
|
42
|
+
* Return 'back' on Esc when the view has nothing of its own to close; the
|
|
43
|
+
* shell then closes this detail view, or the page at a tab's top level.
|
|
44
|
+
* An 'unhandled' Esc is treated the same as 'back'. */
|
|
45
|
+
handleKey(key: string): 'handled' | 'back' | 'unhandled';
|
|
46
|
+
/** The view's own keys for the bottom row ("↑↓ agent · r final report · …").
|
|
47
|
+
* Narrow: key characters only. The shell appends Esc and the page keys. */
|
|
48
|
+
keyLine(narrow: boolean): string;
|
|
49
|
+
/** What Esc does inside the view right now ("clear filter", "close report"),
|
|
50
|
+
* or undefined when Esc would return 'back' — the shell then labels it. */
|
|
51
|
+
escapeLabel?(): string | undefined;
|
|
52
|
+
/** Move the cursor to an Overview landing target on this tab. */
|
|
53
|
+
land?(landing: TabLanding): void;
|
|
54
|
+
}
|
|
55
|
+
export type AnalyticsViewFactory = (ctx: AnalyticsViewContext) => AnalyticsTabView;
|
|
56
|
+
export type GraphDetailViewFactory = (ctx: AnalyticsViewContext, graphId: string, selectAgentId?: string) => AnalyticsTabView;
|
|
57
|
+
/** Content width at or above which the wide (v3) layout applies. */
|
|
58
|
+
export declare const WIDE_MIN_WIDTH = 96;
|
|
59
|
+
export declare const isNarrow: (width: number) => boolean;
|
|
60
|
+
/** Bar cells in the narrow layout. */
|
|
61
|
+
export declare const NARROW_BAR_CELLS = 6;
|
|
62
|
+
/** Widest the page draws; a wider window centers it. */
|
|
63
|
+
export declare const MAX_PAGE_WIDTH = 160;
|
|
64
|
+
/** Tallest a column chart grows in a tall window. */
|
|
65
|
+
export declare const MAX_COLUMN_CHART_ROWS = 16;
|
|
66
|
+
/** A text column's width in the wide layout: its natural width, at least
|
|
67
|
+
* `min` and at most half of `free` (the columns left once number columns are
|
|
68
|
+
* placed). The chart element beside it gets `free − textWidth`. */
|
|
69
|
+
export declare function textWidth(free: number, natural: number, min: number): number;
|
|
70
|
+
/** Row prefix: "> " on the cursor row, two spaces elsewhere. */
|
|
71
|
+
export declare function cursorPrefix(selected: boolean): string;
|
|
72
|
+
/** A row on the cursor, marked by the "> " prefix and, where color exists, bold. */
|
|
73
|
+
export declare function markRow(text: string, selected: boolean): string;
|
|
74
|
+
/** Which rows of a `count`-long list fit in `capacity` rows with the cursor
|
|
75
|
+
* visible. When the list does not fit, the last visible row is spent on a
|
|
76
|
+
* "<n> more <things> ↓" line (`more` is the count below the window). */
|
|
77
|
+
export declare function listWindow(count: number, cursor: number, capacity: number): {
|
|
78
|
+
start: number;
|
|
79
|
+
end: number;
|
|
80
|
+
more: number;
|
|
81
|
+
};
|
|
82
|
+
/** The "<n> more <things> ↓" row. */
|
|
83
|
+
export declare function moreRow(more: number, things: string): string;
|
|
84
|
+
/** A view that only names its tab — what each tab shows until its task builds it. */
|
|
85
|
+
export declare function placeholderView(title: string): AnalyticsTabView;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var a=Object.defineProperty;var e=(r,t)=>a(r,"name",{value:t,configurable:!0});import{theme as m}from"../../core/tui/panel.js";import{formatCount as s}from"./format.js";const u=[{id:"overview",label:"Overview"},{id:"graphs",label:"Graphs"},{id:"time",label:"Time"},{id:"memory",label:"Memory"},{id:"usage",label:"Usage"}],l=96,f=e(r=>r<l,"isNarrow"),h=6,M=160,_=16;function w(r,t,o){return Math.max(o,Math.min(t,Math.floor(r/2)))}e(w,"textWidth");function b(r){return r?"> ":" "}e(b,"cursorPrefix");function c(r,t){return t?m.bold(`> ${r}`):` ${r}`}e(c,"markRow");function A(r,t,o){if(r<=o)return{start:0,end:r,more:0};const n=Math.max(1,o-1),i=Math.max(0,t-n+1);return i+n>=r?{start:Math.max(0,r-o),end:r,more:0}:{start:i,end:i+n,more:r-i-n}}e(A,"listWindow");function R(r,t){return` ${s(r)} more ${t} \u2193`}e(R,"moreRow");function W(r){return{render:e(()=>[`${r}: not built yet.`],"render"),handleKey:e(()=>"unhandled","handleKey"),keyLine:e(()=>"","keyLine")}}e(W,"placeholderView");export{_ as MAX_COLUMN_CHART_ROWS,M as MAX_PAGE_WIDTH,h as NARROW_BAR_CELLS,u as TABS,l as WIDE_MIN_WIDTH,b as cursorPrefix,f as isNarrow,A as listWindow,c as markRow,R as moreRow,W as placeholderView,w as textWidth};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var n=Object.defineProperty;var a=(e,t)=>n(e,"name",{value:t,configurable:!0});import{defineLeaf as s}from"../core/command.js";const o=s({name:"analytics",description:"open the interactive Analytics page",whenToUse:"the user wants to see how agents worked in the last 24 hours or 7 days \u2014 graph sizes and spawned kinds, created \u2192 final report times, memory documents read, and where the API-price estimate and tokens went. It is a person-facing page for the tmux popup (prefix menu, shift+a); it has no non-interactive output for agents",help:{name:"canvas analytics",summary:"open the read-only Analytics page \u2014 Overview, Graphs, Time, Memory, and Usage tabs over the last 24h or 7d",params:[{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane id that `o` opens a conversation beside (the prefix menu passes the pane it was opened from). Default: $TMUX_PANE."}],output:[],outputKind:"object",effects:["Opens a pi-tui page; crtrd computes every number (`GET /v1/canvas/analytics`, person only). The page opens no database or transcript file.","Read-only. The one exception is `o` in graph detail, which closes the page and opens that agent\u2019s conversation and may wake it.","Does not start crtrd: with the daemon unreachable the page shows the error and `R` retries.","Requires an interactive terminal. Without one it prints one line to stderr and exits 1."]},run:a(async e=>{await(await import("./canvas-analytics/shell.js")).runAnalytics(e.pane)},"run"),render:a(()=>"","render")});export{o as analyticsLeaf};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var u=Object.defineProperty;var
|
|
1
|
+
var u=Object.defineProperty;var o=(e,a)=>u(e,"name",{value:a,configurable:!0});import{defineLeaf as p}from"../core/command.js";import{cliClient as h,rethrowAsCliError as m}from"./api-client.js";const r=14,v=p({name:"prune",description:"remove terminal nodes (dead/done/canceled) last active more than a TTL ago",whenToUse:"you want to bound the canvas\u2019s on-disk growth \u2014 sweep away nodes that are finished (done), crashed (dead), or closed (canceled) and last active more than a retention window ago, reclaiming their rows, edges (cascade-deleted by the schema), and `nodes/<id>/` dirs. crtrd already runs the default 14-day sweep of terminal nodes every 5 minutes, so run this by hand for a shorter window, a count cap, --include-stale, or --empty; live nodes (active/idle) and nodes with an open managed worktree are never touched, and you can preview the sweep before it deletes anything",help:{name:"canvas prune",summary:"delete terminal nodes last active more than a TTL ago (edges cascade, dirs removed); --max N for a count cap; --dry-run to preview",params:[{kind:"flag",name:"max",type:"int",required:!1,constraint:"COUNT mode (instead of the TTL sweep): keep every protected node, plus the most recently active terminal nodes up to N in total, deleting the rest. Active/idle nodes regardless of process state and every node listed under effects as kept are NEVER deleted, so the real floor is max(N, protectedCount). Recency = the latest lifecycle timestamp or telemetry.json mtime. Combine with --dry-run to preview."},{kind:"flag",name:"ttl",type:"int",required:!1,default:r,constraint:`Retention window in days: only dead/done/canceled nodes last active more than this many days ago are pruned (last active = the latest lifecycle timestamp or telemetry.json mtime), except the nodes listed under effects as kept. Default: ${r}.`},{kind:"flag",name:"include-stale",type:"bool",required:!1,default:!1,constraint:"ALSO prune stale active/idle nodes last active before the TTL whose process is gone (pi_pid null or dead) \u2014 reaps abandoned roots the daemon never reconciled. Skipped: a live pi_pid, a node sleeping until it is woken, a node with unseen wake mail, a frozen node, a node in respawn backoff, and every node listed under effects as kept."},{kind:"flag",name:"empty",type:"bool",required:!1,default:!1,constraint:"Instead of the TTL sweep, reap EMPTY nodes \u2014 nodes (of any age or status) whose engine never produced an assistant message, the useless shells that just take up graph + disk space. A node mid-first-turn, the caller, and a node with an open managed worktree are spared. Combine with --dry-run to preview."},{kind:"flag",name:"dry-run",type:"bool",required:!1,default:!1,constraint:"Report what WOULD be pruned without deleting anything."}],output:[{name:"pruned",type:"integer",required:!0,constraint:"How many nodes were pruned (0 under --dry-run since nothing is deleted; the candidate count is in `nodes`)."},{name:"dryRun",type:"boolean",required:!0,constraint:"True when nothing was deleted (preview only)."},{name:"ttlDays",type:"integer",required:!0,constraint:"The retention window used."},{name:"nodes",type:"object[]",required:!0,constraint:"One per pruned (or, under --dry-run, prunable) node: {node_id,status,created}."}],outputKind:"object",effects:["With --max N: COUNT mode \u2014 keep every protected node plus the most recently active terminal nodes up to N in total, deleting the rest; active/idle nodes regardless of process state are never deleted. Takes precedence over the TTL/--empty sweeps.","Deletes matching `nodes` rows; their edges cascade-delete via the FK; each node\u2019s `nodes/<id>/` dir is removed.","Always kept, in every mode except --empty: the caller, a node with a live or launching engine, a node with durable work that must wake it (subscription, message wait, cron wake, open ticket, output request), a node a person is viewing, a frozen node, an app run (deleted only through the runs API), and a node with an open managed worktree.","No-op on live nodes (active/idle) and terminal nodes active within the TTL. With --include-stale: also deletes active/idle nodes last active before the TTL whose process is gone and that nothing will wake.","crtrd runs the default sweep (terminal nodes, 14 days, no --include-stale) automatically every 5 minutes.","Under --dry-run: read-only, deletes nothing."]},run:o(async e=>{const a=e.ttl??r,i=e.dryRun??!1,l=e.includeStale??!1,c=e.empty??!1,s=e.max,n={dry_run:i,ttl_days:a};s!==void 0?n.limit=s:c?n.empty=!0:n.include_stale=l;try{const t=await h().prune(n);return{pruned:t.dry_run?0:t.pruned.length,dryRun:t.dry_run,ttlDays:t.ttl_days,nodes:t.pruned.map(d=>({node_id:d.node_id,status:d.status,created:d.created}))}}catch(t){m(t)}},"run")});export{v as canvasPruneLeaf};
|
package/dist/commands/canvas.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var o=Object.defineProperty;var e=(a,t)=>o(a,"name",{value:t,configurable:!0});import{defineBranch as r}from"../core/command.js";import{dashboardLeaf as n}from"./dashboard.js";import{canvasSnapshotLeaf as s}from"./canvas-snapshot.js";import{canvasRosterLeaf as i}from"./canvas-roster.js";import{browseLeaf as c}from"./canvas-browse.js";import{reviveLeaf as d}from"./revive.js";import{attentionBranch as
|
|
1
|
+
var o=Object.defineProperty;var e=(a,t)=>o(a,"name",{value:t,configurable:!0});import{defineBranch as r}from"../core/command.js";import{dashboardLeaf as n}from"./dashboard.js";import{canvasSnapshotLeaf as s}from"./canvas-snapshot.js";import{canvasRosterLeaf as i}from"./canvas-roster.js";import{browseLeaf as c}from"./canvas-browse.js";import{reviveLeaf as d}from"./revive.js";import{attentionBranch as p}from"./attention.js";import{chordLeaf as h}from"./chord.js";import{canvasPruneLeaf as m}from"./canvas-prune.js";import{historyBranch as u}from"./canvas-history.js";import{issueNewLeaf as f}from"./canvas-issue.js";import{canvasConfigBranch as l}from"./canvas-config.js";import{canvasUseLeaf as g}from"./canvas-use.js";import{analyticsLeaf as v}from"./canvas-analytics.js";const b=r({name:"issue",description:"capture a quick todo/idea/bug into a GitHub issue (or a .todos/ note)",whenToUse:"the alt+c \u2192 i chord uses this; capture a passing thought without leaving your pane",tier:"hidden",help:{name:"canvas issue",summary:"capture a quick todo/idea/bug into a GitHub issue",model:"Quick brain-dump capture, bound to the alt+c \u2192 i \u2192 (idea|bug) prefix chord. `new` reads a free-text note, auto-generates the title via a headless pi call, and files it with `gh issue create --label <type>` when the pane\u2019s cwd is a GitHub repo, else writes `<git-root>/.todos/<slug>.md`. Meant for the chord/popup, not hand-running."},children:[f]});function U(){return r({name:"canvas",rootEntry:{concept:"the whole agent graph at a glance \u2014 render it, see who is blocked, mass-revive disconnected nodes, and find or re-read prior node reports/context artifacts",desc:"bird's-eye view, supervision, and report/artifact history for the entire canvas",useWhen:"surveying the full graph, finding blocked agents, mass-reviving every disconnected node, or finding/re-reading prior reports/artifacts; run `crtr canvas -h`"},help:{name:"canvas",summary:"observe and supervise the whole agent graph",model:"Canvas-wide operations, distinct from per-node work (`node`) and a node's own spine write verb (`push`). `dashboard` renders the subscription forest as a tree; `browse` opens an interactive full-screen navigator (tabs/tree/search) over the whole canvas and resumes the chosen node; `attention` aggregates pending replies from the user across the graph; `revive --all` mass-reconnects every disconnected node (bringing back ONE named node is `node lifecycle revive <id>` instead); `history` searches and recalls the content record (reports + context docs) of past work in a cwd; `prune` bounds growth by deleting terminal nodes past a TTL; `analytics` opens the read-only Analytics page (graph sizes, agent time, memory reads, API-price estimate) for a person. `config` registers/lists remote canvas targets (preview endpoint + relay token); `use` switches remote-capable read commands such as `node inspect` onto a configured target or back to local."},children:[n,s,i,c,p,d,u,h,b,m,l,g,v]})}e(U,"registerCanvas");export{b as issueBranch,U as registerCanvas};
|