openclaw-hybrid-memory 2026.5.310 → 2026.6.10
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/api/plugin-runtime.ts +2 -0
- package/backends/facts-db/contradictions.ts +1 -1
- package/cli/cmd-extract-directives.ts +225 -11
- package/cli/cmd-extract-proposals.ts +5 -6
- package/cli/cmd-extract-reinforcement.ts +71 -0
- package/cli/cmd-feedback.ts +15 -9
- package/cli/commands/manage/register-reflection-pipeline.ts +247 -13
- package/cli/commands/manage/register-storage-maintenance.ts +224 -15
- package/cli/commands/manage/storage-stats-helpers.ts +13 -2
- package/cli/context.ts +9 -19
- package/cli/distill.ts +31 -1
- package/cli/register.ts +28 -38
- package/dist/api/plugin-runtime.js.map +1 -1
- package/dist/backends/agent-health-store.js.map +1 -1
- package/dist/backends/apitap-store.js.map +1 -1
- package/dist/backends/audit-store.js.map +1 -1
- package/dist/backends/base-sqlite-store.js.map +1 -1
- package/dist/backends/cost-tracker.js.map +1 -1
- package/dist/backends/credentials-db.js +2 -3
- package/dist/backends/credentials-db.js.map +1 -1
- package/dist/backends/crystallization-store.js.map +1 -1
- package/dist/backends/edict-store.js.map +1 -1
- package/dist/backends/event-bus.js.map +1 -1
- package/dist/backends/event-log.js.map +1 -1
- package/dist/backends/facts-db/cache-manager.js.map +1 -1
- package/dist/backends/facts-db/clusters.js.map +1 -1
- package/dist/backends/facts-db/contradictions.js +1 -1
- package/dist/backends/facts-db/contradictions.js.map +1 -1
- package/dist/backends/facts-db/crud.js.map +1 -1
- package/dist/backends/facts-db/db-connection.js.map +1 -1
- package/dist/backends/facts-db/entity-autolink.js.map +1 -1
- package/dist/backends/facts-db/entity-layer.js.map +1 -1
- package/dist/backends/facts-db/episodes.js.map +1 -1
- package/dist/backends/facts-db/fact-queries.js.map +1 -1
- package/dist/backends/facts-db/fact-read-queries.js.map +1 -1
- package/dist/backends/facts-db/facts-db-layer1.js.map +1 -1
- package/dist/backends/facts-db/facts-db-layer2.js.map +1 -1
- package/dist/backends/facts-db/facts-db-layer3.js.map +1 -1
- package/dist/backends/facts-db/fts-text.js.map +1 -1
- package/dist/backends/facts-db/generated-skills/policy.js.map +1 -1
- package/dist/backends/facts-db/generated-skills.js.map +1 -1
- package/dist/backends/facts-db/housekeeping.js.map +1 -1
- package/dist/backends/facts-db/links.js.map +1 -1
- package/dist/backends/facts-db/maintenance.js.map +1 -1
- package/dist/backends/facts-db/procedures/crud.js.map +1 -1
- package/dist/backends/facts-db/procedures/internal.js.map +1 -1
- package/dist/backends/facts-db/procedures/promotion.js.map +1 -1
- package/dist/backends/facts-db/procedures/search.js.map +1 -1
- package/dist/backends/facts-db/procedures/stats.js.map +1 -1
- package/dist/backends/facts-db/reinforcement.js.map +1 -1
- package/dist/backends/facts-db/row-mapper.js.map +1 -1
- package/dist/backends/facts-db/scan-cursors.js.map +1 -1
- package/dist/backends/facts-db/schema-bootstrap.js.map +1 -1
- package/dist/backends/facts-db/scope-sql.js.map +1 -1
- package/dist/backends/facts-db/search.js.map +1 -1
- package/dist/backends/facts-db/stats.js.map +1 -1
- package/dist/backends/facts-db/types.js.map +1 -1
- package/dist/backends/facts-db/variants.js.map +1 -1
- package/dist/backends/identity-reflection-store.js.map +1 -1
- package/dist/backends/issue-store.js.map +1 -1
- package/dist/backends/learnings-db.js.map +1 -1
- package/dist/backends/migrations/facts-migrations.js.map +1 -1
- package/dist/backends/migrations/procedures.js.map +1 -1
- package/dist/backends/narratives-db.js.map +1 -1
- package/dist/backends/persona-state-store.js.map +1 -1
- package/dist/backends/proposals-db.js.map +1 -1
- package/dist/backends/scope-filter-sql.js.map +1 -1
- package/dist/backends/sqlite-schema-meta.js.map +1 -1
- package/dist/backends/tool-proposal-store.js.map +1 -1
- package/dist/backends/vector-db/constants.js.map +1 -1
- package/dist/backends/vector-db/path-utils.js.map +1 -1
- package/dist/backends/vector-db/runtime-locks.js.map +1 -1
- package/dist/backends/vector-db/vector-db-class.js.map +1 -1
- package/dist/backends/wal.js.map +1 -1
- package/dist/backends/workflow-store.js.map +1 -1
- package/dist/benchmark/shadow-eval.js.map +1 -1
- package/dist/cli/active-tasks.js.map +1 -1
- package/dist/cli/backup.js.map +1 -1
- package/dist/cli/benchmark.js.map +1 -1
- package/dist/cli/cmd-backfill.js.map +1 -1
- package/dist/cli/cmd-config.js.map +1 -1
- package/dist/cli/cmd-credentials.js.map +1 -1
- package/dist/cli/cmd-demo.js.map +1 -1
- package/dist/cli/cmd-distill.js.map +1 -1
- package/dist/cli/cmd-doctor.js.map +1 -1
- package/dist/cli/cmd-examples.js.map +1 -1
- package/dist/cli/cmd-extract-daily.js.map +1 -1
- package/dist/cli/cmd-extract-directives.js +141 -10
- package/dist/cli/cmd-extract-directives.js.map +1 -1
- package/dist/cli/cmd-extract-procedures.js.map +1 -1
- package/dist/cli/cmd-extract-proposals.js +3 -2
- package/dist/cli/cmd-extract-proposals.js.map +1 -1
- package/dist/cli/cmd-extract-reinforcement.js +39 -0
- package/dist/cli/cmd-extract-reinforcement.js.map +1 -1
- package/dist/cli/cmd-extract-sessions.js.map +1 -1
- package/dist/cli/cmd-feedback.js +9 -4
- package/dist/cli/cmd-feedback.js.map +1 -1
- package/dist/cli/cmd-health.js.map +1 -1
- package/dist/cli/cmd-providers.js.map +1 -1
- package/dist/cli/cmd-selfcorrection.js.map +1 -1
- package/dist/cli/cmd-setup.js.map +1 -1
- package/dist/cli/cmd-status.js.map +1 -1
- package/dist/cli/cmd-store.js.map +1 -1
- package/dist/cli/cmd-user-friendly.js.map +1 -1
- package/dist/cli/cmd-verify.js.map +1 -1
- package/dist/cli/commands/manage/bindings.js.map +1 -1
- package/dist/cli/commands/manage/dream-cycle-followup.js.map +1 -1
- package/dist/cli/commands/manage/maintenance-heartbeat.js.map +1 -1
- package/dist/cli/commands/manage/register-agents-audit-runall.js.map +1 -1
- package/dist/cli/commands/manage/register-analyze-maintenance-logs.js.map +1 -1
- package/dist/cli/commands/manage/register-budget-proposals.js.map +1 -1
- package/dist/cli/commands/manage/register-config-cli.js.map +1 -1
- package/dist/cli/commands/manage/register-corrections-and-pipeline.js.map +1 -1
- package/dist/cli/commands/manage/register-corrections.js.map +1 -1
- package/dist/cli/commands/manage/register-council.js.map +1 -1
- package/dist/cli/commands/manage/register-credentials-scope.js.map +1 -1
- package/dist/cli/commands/manage/register-digest.js.map +1 -1
- package/dist/cli/commands/manage/register-lifecycle.js.map +1 -1
- package/dist/cli/commands/manage/register-procedure-lifecycle.js.map +1 -1
- package/dist/cli/commands/manage/register-reconcile-cron-ledgers.js.map +1 -1
- package/dist/cli/commands/manage/register-reflection-pipeline.js +144 -7
- package/dist/cli/commands/manage/register-reflection-pipeline.js.map +1 -1
- package/dist/cli/commands/manage/register-self-correction-feedback.js.map +1 -1
- package/dist/cli/commands/manage/register-storage-and-stats.js.map +1 -1
- package/dist/cli/commands/manage/register-storage-entities-decay.js.map +1 -1
- package/dist/cli/commands/manage/register-storage-graph-audit.js.map +1 -1
- package/dist/cli/commands/manage/register-storage-maintenance.js +152 -9
- package/dist/cli/commands/manage/register-storage-maintenance.js.map +1 -1
- package/dist/cli/commands/manage/register-validate-cron-exit.js.map +1 -1
- package/dist/cli/commands/manage/storage-stats-helpers.js +10 -3
- package/dist/cli/commands/manage/storage-stats-helpers.js.map +1 -1
- package/dist/cli/commands/register-manage-commands.js.map +1 -1
- package/dist/cli/config-feature-summaries.js.map +1 -1
- package/dist/cli/config-output-sink.js.map +1 -1
- package/dist/cli/distill-session-jsonl.js.map +1 -1
- package/dist/cli/distill.js +10 -1
- package/dist/cli/distill.js.map +1 -1
- package/dist/cli/global-verbose.js.map +1 -1
- package/dist/cli/goals.js.map +1 -1
- package/dist/cli/hybrid-mem-commander-utils.js.map +1 -1
- package/dist/cli/install/config-merge.js.map +1 -1
- package/dist/cli/install/cron-jobs.js.map +1 -1
- package/dist/cli/install/embedding-detect.js.map +1 -1
- package/dist/cli/install/run-install.js.map +1 -1
- package/dist/cli/install/workspace.js.map +1 -1
- package/dist/cli/proposals.js.map +1 -1
- package/dist/cli/register.js.map +1 -1
- package/dist/cli/shared.js.map +1 -1
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/task-queue-status.js.map +1 -1
- package/dist/cli/verified.js.map +1 -1
- package/dist/cli/verify/fact-count.js.map +1 -1
- package/dist/cli/verify/openclaw-config.js.map +1 -1
- package/dist/cli/verify/plugin-config-credentials.js.map +1 -1
- package/dist/cli/verify/sections/config-cron.js.map +1 -1
- package/dist/cli/verify/sections/embeddings.js.map +1 -1
- package/dist/cli/verify/sections/infrastructure.js.map +1 -1
- package/dist/cli/verify/sections/llm-models.js.map +1 -1
- package/dist/cli/verify/sections/reconcile.js.map +1 -1
- package/dist/cli/verify/verify-run-state.js.map +1 -1
- package/dist/cli/verify-llm-azure-auth.js.map +1 -1
- package/dist/cli/verify.js.map +1 -1
- package/dist/config/hybrid-schema.js.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/maintenance-fallback-policy.js.map +1 -1
- package/dist/config/parsers/capture.js.map +1 -1
- package/dist/config/parsers/core.js.map +1 -1
- package/dist/config/parsers/features.js.map +1 -1
- package/dist/config/parsers/index.js.map +1 -1
- package/dist/config/parsers/maintenance.js.map +1 -1
- package/dist/config/parsers/retrieval.js.map +1 -1
- package/dist/config/parsers/sensors.js.map +1 -1
- package/dist/config/skill-sections.js.map +1 -1
- package/dist/config/skill-size-limits.js.map +1 -1
- package/dist/config/types/agents.js.map +1 -1
- package/dist/config/types/bootstrap.js.map +1 -1
- package/dist/config/types/core.js.map +1 -1
- package/dist/config/types/index.js.map +1 -1
- package/dist/config/utils.js.map +1 -1
- package/dist/index-help.js.map +1 -1
- package/dist/index-testing-exports.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/lifecycle/hook-resolution-api.js.map +1 -1
- package/dist/lifecycle/hooks.js +0 -1
- package/dist/lifecycle/hooks.js.map +1 -1
- package/dist/lifecycle/resolve-agent-id.js.map +1 -1
- package/dist/lifecycle/session-state.js.map +1 -1
- package/dist/lifecycle/stage-active-task.js.map +1 -1
- package/dist/lifecycle/stage-auth-failure.js.map +1 -1
- package/dist/lifecycle/stage-capture/run-capture.js.map +1 -1
- package/dist/lifecycle/stage-capture.js.map +1 -1
- package/dist/lifecycle/stage-cleanup.js.map +1 -1
- package/dist/lifecycle/stage-credential-hint.js.map +1 -1
- package/dist/lifecycle/stage-frustration.js.map +1 -1
- package/dist/lifecycle/stage-goal-stewardship.js.map +1 -1
- package/dist/lifecycle/stage-goal-subagent.js.map +1 -1
- package/dist/lifecycle/stage-injection.js +1 -1
- package/dist/lifecycle/stage-injection.js.map +1 -1
- package/dist/lifecycle/stage-recall/run-recall.js.map +1 -1
- package/dist/lifecycle/stage-recall.js.map +1 -1
- package/dist/lifecycle/stage-setup.js.map +1 -1
- package/dist/routes/dashboard/collectors.js.map +1 -1
- package/dist/routes/dashboard/html.js.map +1 -1
- package/dist/routes/dashboard/server.js.map +1 -1
- package/dist/routes/dashboard-graph.js.map +1 -1
- package/dist/routes/graphql-resolvers.js.map +1 -1
- package/dist/routes/graphql-server.js.map +1 -1
- package/dist/services/active-task-checkpoint.js.map +1 -1
- package/dist/services/active-task-injection.js.map +1 -1
- package/dist/services/active-task.js.map +1 -1
- package/dist/services/adaptive-catch-up-pacing.js +25 -0
- package/dist/services/adaptive-catch-up-pacing.js.map +1 -0
- package/dist/services/adaptive-maintenance-llm.js.map +1 -1
- package/dist/services/adaptive-model-limits.js.map +1 -1
- package/dist/services/ambient-retrieval.js.map +1 -1
- package/dist/services/apitap-service.js.map +1 -1
- package/dist/services/audit-health-exit-info.js.map +1 -1
- package/dist/services/audit-health-json.js.map +1 -1
- package/dist/services/auth-failure-detect.js.map +1 -1
- package/dist/services/auto-capture.js.map +1 -1
- package/dist/services/auto-classifier.js.map +1 -1
- package/dist/services/auto-skills-audit.js.map +1 -1
- package/dist/services/bootstrap-optional.js.map +1 -1
- package/dist/services/bootstrap-priority.js.map +1 -1
- package/dist/services/bootstrap.js.map +1 -1
- package/dist/services/capture-provenance.js.map +1 -1
- package/dist/services/capture-utils.js.map +1 -1
- package/dist/services/chat.js +22 -3
- package/dist/services/chat.js.map +1 -1
- package/dist/services/classification-scope.js.map +1 -1
- package/dist/services/classification.js.map +1 -1
- package/dist/services/cli-sql-dump.js.map +1 -1
- package/dist/services/consolidation.js.map +1 -1
- package/dist/services/context-audit.js +1 -1
- package/dist/services/context-audit.js.map +1 -1
- package/dist/services/context-budget.js.map +1 -1
- package/dist/services/context-engine.js.map +1 -1
- package/dist/services/contextual-variants.js.map +1 -1
- package/dist/services/continuous-verifier.js.map +1 -1
- package/dist/services/contradiction-adjudicator.js.map +1 -1
- package/dist/services/cost-context.js.map +1 -1
- package/dist/services/cost-feature-labels.js.map +1 -1
- package/dist/services/credential-migration.js.map +1 -1
- package/dist/services/credential-scanner.js.map +1 -1
- package/dist/services/credential-validation.js.map +1 -1
- package/dist/services/cron-exit-validator.js.map +1 -1
- package/dist/services/cron-guard.js.map +1 -1
- package/dist/services/cron-job-bash-harness.js +52 -5
- package/dist/services/cron-job-bash-harness.js.map +1 -1
- package/dist/services/cron-maintenance-reconciler.js +1 -3
- package/dist/services/cron-maintenance-reconciler.js.map +1 -1
- package/dist/services/cross-agent-learning.js.map +1 -1
- package/dist/services/crystallization-proposer.js.map +1 -1
- package/dist/services/dedupe-policy.js.map +1 -1
- package/dist/services/deprecated-cron-commands.js.map +1 -1
- package/dist/services/directive-extract.js.map +1 -1
- package/dist/services/document-chunker.js.map +1 -1
- package/dist/services/document-grader.js.map +1 -1
- package/dist/services/dream-cycle.js.map +1 -1
- package/dist/services/embedding-migration.js.map +1 -1
- package/dist/services/embedding-registry.js.map +1 -1
- package/dist/services/embeddings/chain-provider.js.map +1 -1
- package/dist/services/embeddings/factory.js.map +1 -1
- package/dist/services/embeddings/fallback-provider.js.map +1 -1
- package/dist/services/embeddings/ollama-provider.js.map +1 -1
- package/dist/services/embeddings/onnx-provider.js.map +1 -1
- package/dist/services/embeddings/openai-provider.js.map +1 -1
- package/dist/services/embeddings/shared.js +3 -3
- package/dist/services/embeddings/shared.js.map +1 -1
- package/dist/services/embeddings/types.js.map +1 -1
- package/dist/services/entity-enrichment-adaptive.js +128 -0
- package/dist/services/entity-enrichment-adaptive.js.map +1 -0
- package/dist/services/entity-enrichment-cli.js +389 -42
- package/dist/services/entity-enrichment-cli.js.map +1 -1
- package/dist/services/entity-enrichment.js +31 -5
- package/dist/services/entity-enrichment.js.map +1 -1
- package/dist/services/error-reporter/noisy-errors.js.map +1 -1
- package/dist/services/error-reporter/sanitize.js.map +1 -1
- package/dist/services/error-reporter.js.map +1 -1
- package/dist/services/event-hub-repair.js.map +1 -1
- package/dist/services/export-memory.js.map +1 -1
- package/dist/services/fact-extraction.js.map +1 -1
- package/dist/services/feedback-effectiveness.js.map +1 -1
- package/dist/services/find-duplicates.js.map +1 -1
- package/dist/services/frustration-detector.js.map +1 -1
- package/dist/services/fts-search.js.map +1 -1
- package/dist/services/gap-detector.js.map +1 -1
- package/dist/services/generated-skill-lifecycle.js.map +1 -1
- package/dist/services/generated-skill-validation.js.map +1 -1
- package/dist/services/goal-active-task-mirror.js.map +1 -1
- package/dist/services/goal-circuit-breaker.js.map +1 -1
- package/dist/services/goal-health.js.map +1 -1
- package/dist/services/goal-registry.js.map +1 -1
- package/dist/services/goal-stewardship-heartbeat.js.map +1 -1
- package/dist/services/goal-stewardship-llm-triage.js.map +1 -1
- package/dist/services/goal-stewardship-verify-cron.js.map +1 -1
- package/dist/services/goal-stewardship.js.map +1 -1
- package/dist/services/goal-subagent.js.map +1 -1
- package/dist/services/graph-retrieval.js.map +1 -1
- package/dist/services/humanizer-score.js.map +1 -1
- package/dist/services/hybrid-mem-cron-default-job-steps.js.map +1 -1
- package/dist/services/hyde-helper.js.map +1 -1
- package/dist/services/identity-reflection.js.map +1 -1
- package/dist/services/implicit-feedback-extract.js.map +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/ingest-utils.js.map +1 -1
- package/dist/services/intent-template.js.map +1 -1
- package/dist/services/json-array-parser.js.map +1 -1
- package/dist/services/knowledge-gaps.js.map +1 -1
- package/dist/services/language-keywords-build.js.map +1 -1
- package/dist/services/lifecycle/github-adapter.js.map +1 -1
- package/dist/services/llm-rate-limit-headers.js +1 -2
- package/dist/services/llm-rate-limit-headers.js.map +1 -1
- package/dist/services/maintenance-auto-fix.js.map +1 -1
- package/dist/services/maintenance-log-analyzer.js +7 -1
- package/dist/services/maintenance-log-analyzer.js.map +1 -1
- package/dist/services/maintenance-timestamp.js.map +1 -1
- package/dist/services/memory-diagnostics.js.map +1 -1
- package/dist/services/memory-index.js.map +1 -1
- package/dist/services/merge-results.js.map +1 -1
- package/dist/services/model-capabilities.js.map +1 -1
- package/dist/services/model-pricing.js.map +1 -1
- package/dist/services/narrative-recall.js.map +1 -1
- package/dist/services/openclaw-session-artifact.js.map +1 -1
- package/dist/services/passive-observer.js.map +1 -1
- package/dist/services/pattern-detector-hash.js.map +1 -1
- package/dist/services/pattern-detector.js.map +1 -1
- package/dist/services/pending-autopilot/foundation.js.map +1 -1
- package/dist/services/pending-autopilot/redaction.js.map +1 -1
- package/dist/services/pending-autopilot/store.js.map +1 -1
- package/dist/services/pending-autopilot/types.js.map +1 -1
- package/dist/services/pending-digest-autopilot-cron.js.map +1 -1
- package/dist/services/pending-digest-autopilot.js.map +1 -1
- package/dist/services/pending-review-digest.js.map +1 -1
- package/dist/services/persona-proposal-triage.js.map +1 -1
- package/dist/services/persona-state-promotion.js.map +1 -1
- package/dist/services/post-compaction-recall.js.map +1 -1
- package/dist/services/pre-consolidation-flush.js.map +1 -1
- package/dist/services/pre-finalization-guard.js.map +1 -1
- package/dist/services/procedure-cluster.js.map +1 -1
- package/dist/services/procedure-extractor.js.map +1 -1
- package/dist/services/procedure-promotion/duplicate-skill-cache.js.map +1 -1
- package/dist/services/procedure-promotion-policy.js.map +1 -1
- package/dist/services/procedure-selection-metrics.js.map +1 -1
- package/dist/services/procedure-skill-eval.js.map +1 -1
- package/dist/services/procedure-skill-generator.js.map +1 -1
- package/dist/services/procedure-skill-recipe.js.map +1 -1
- package/dist/services/procedure-skill-shrink.js.map +1 -1
- package/dist/services/procedure-skill-workflow.js.map +1 -1
- package/dist/services/provenance.js.map +1 -1
- package/dist/services/public-export-bundle.js.map +1 -1
- package/dist/services/python-bridge.js.map +1 -1
- package/dist/services/query-expander.js.map +1 -1
- package/dist/services/query-validator.js.map +1 -1
- package/dist/services/recall-pipeline.js.map +1 -1
- package/dist/services/recall-timing.js.map +1 -1
- package/dist/services/recent-http-attempts.js.map +1 -1
- package/dist/services/reflection/shared.js.map +1 -1
- package/dist/services/reflection.js.map +1 -1
- package/dist/services/reinforcement-extract.js.map +1 -1
- package/dist/services/reranker.js.map +1 -1
- package/dist/services/responses-adapter.js.map +1 -1
- package/dist/services/retrieval-aliases.js.map +1 -1
- package/dist/services/retrieval-mode-policy.js.map +1 -1
- package/dist/services/retrieval-orchestrator/packing.js.map +1 -1
- package/dist/services/retrieval-orchestrator.d.ts +2 -3
- package/dist/services/retrieval-orchestrator.js.map +1 -1
- package/dist/services/rrf-fusion.js.map +1 -1
- package/dist/services/self-correction-extract.js.map +1 -1
- package/dist/services/session-observability.js.map +1 -1
- package/dist/services/session-pre-filter.js.map +1 -1
- package/dist/services/shortest-path.js.map +1 -1
- package/dist/services/skill-allowed-tools.js.map +1 -1
- package/dist/services/skill-creator-validator.js.map +1 -1
- package/dist/services/skill-crystallizer-helpers.js.map +1 -1
- package/dist/services/skill-crystallizer.js.map +1 -1
- package/dist/services/skill-description-builder.js.map +1 -1
- package/dist/services/skill-eval-synthesizer.js.map +1 -1
- package/dist/services/skill-examples-builder.js.map +1 -1
- package/dist/services/skill-frontmatter.js.map +1 -1
- package/dist/services/skill-name-validator.js.map +1 -1
- package/dist/services/skill-prompt-injection.js.map +1 -1
- package/dist/services/skill-reference-sidecar.js.map +1 -1
- package/dist/services/skill-script-bundler.js.map +1 -1
- package/dist/services/skill-validator.js.map +1 -1
- package/dist/services/startup-memory-attribution.js.map +1 -1
- package/dist/services/task-hygiene.js.map +1 -1
- package/dist/services/task-ledger/canonical.js.map +1 -1
- package/dist/services/task-ledger-facts.js.map +1 -1
- package/dist/services/task-queue-leases.js.map +1 -1
- package/dist/services/task-queue-watchdog.js.map +1 -1
- package/dist/services/tool-effectiveness.js.map +1 -1
- package/dist/services/tool-proposer.js.map +1 -1
- package/dist/services/tools-md-section.js.map +1 -1
- package/dist/services/topic-clusters.js.map +1 -1
- package/dist/services/trajectory-tracker.js.map +1 -1
- package/dist/services/vector-backend-observability.js.map +1 -1
- package/dist/services/vector-lifecycle-audit.js.map +1 -1
- package/dist/services/vector-maintenance.js.map +1 -1
- package/dist/services/vector-search.js.map +1 -1
- package/dist/services/verification-store.js.map +1 -1
- package/dist/services/verified-fact-triage.js.map +1 -1
- package/dist/services/wal-helpers.js.map +1 -1
- package/dist/services/workflow-tracker.js.map +1 -1
- package/dist/setup/bootstrap-databases.js.map +1 -1
- package/dist/setup/cli-context/cli-services.js.map +1 -1
- package/dist/setup/cli-context/help-text.js.map +1 -1
- package/dist/setup/cli-context/metadata.js.map +1 -1
- package/dist/setup/cli-context/register-cli-with-help.js.map +1 -1
- package/dist/setup/cli-context/register-full.js.map +1 -1
- package/dist/setup/cli-context/register-help.js.map +1 -1
- package/dist/setup/cost-instrumentation.js.map +1 -1
- package/dist/setup/hybrid-memory-generation-state.js.map +1 -1
- package/dist/setup/hybrid-memory-reload-coordinator.js +13 -13
- package/dist/setup/hybrid-memory-reload-coordinator.js.map +1 -1
- package/dist/setup/plugin-service.js.map +1 -1
- package/dist/setup/provider-router.js.map +1 -1
- package/dist/setup/register-context-engine.js.map +1 -1
- package/dist/setup/register-hooks.js.map +1 -1
- package/dist/setup/register-plugin.js +25 -21
- package/dist/setup/register-plugin.js.map +1 -1
- package/dist/setup/register-tools.js.map +1 -1
- package/dist/setup/reregister-policy.js +2 -2
- package/dist/setup/reregister-policy.js.map +1 -1
- package/dist/setup/tool-installers.js.map +1 -1
- package/dist/setup/workspace-bootstrap.js.map +1 -1
- package/dist/src/worker/narratives.js.map +1 -1
- package/dist/tools/apitap-tools.js.map +1 -1
- package/dist/tools/credential-tools.js.map +1 -1
- package/dist/tools/crystallization-tools.js.map +1 -1
- package/dist/tools/dashboard-routes.js.map +1 -1
- package/dist/tools/document-tools.js.map +1 -1
- package/dist/tools/goal-tools.js.map +1 -1
- package/dist/tools/graph-tools.js.map +1 -1
- package/dist/tools/issue-tools.js.map +1 -1
- package/dist/tools/memory/build-runtime.js.map +1 -1
- package/dist/tools/memory/helpers.js.map +1 -1
- package/dist/tools/memory/register-checkpoint-tools.js.map +1 -1
- package/dist/tools/memory/register-directory-tools.js.map +1 -1
- package/dist/tools/memory/register-edict-tools.js.map +1 -1
- package/dist/tools/memory/register-episode-tools.js.map +1 -1
- package/dist/tools/memory/register-recall-tools.js.map +1 -1
- package/dist/tools/memory/register-store-tools.js.map +1 -1
- package/dist/tools/memory-tools.js.map +1 -1
- package/dist/tools/persona-tools.js.map +1 -1
- package/dist/tools/provenance-tools.js.map +1 -1
- package/dist/tools/public-api-routes.js.map +1 -1
- package/dist/tools/safe-register-http-route.js.map +1 -1
- package/dist/tools/self-extension-tools.js.map +1 -1
- package/dist/tools/task-hygiene-tools.js.map +1 -1
- package/dist/tools/utility-tools.js.map +1 -1
- package/dist/tools/verification-tools.js.map +1 -1
- package/dist/tools/workflow-tools.js.map +1 -1
- package/dist/types/issue-types.js.map +1 -1
- package/dist/types/learnings-types.js.map +1 -1
- package/dist/types/memory.js.map +1 -1
- package/dist/utils/apim-gateway-fetch.js.map +1 -1
- package/dist/utils/atomic-write.js.map +1 -1
- package/dist/utils/auth-failover.js.map +1 -1
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/compaction-model-watchdog.js.map +1 -1
- package/dist/utils/consolidation-controls.js.map +1 -1
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/date-detector.js.map +1 -1
- package/dist/utils/dates.js.map +1 -1
- package/dist/utils/decay.js.map +1 -1
- package/dist/utils/duration.js.map +1 -1
- package/dist/utils/embed-call.js.map +1 -1
- package/dist/utils/entity-lookup-resolve.js.map +1 -1
- package/dist/utils/entity-mention-quality.js.map +1 -1
- package/dist/utils/entity-stopwords.js.map +1 -1
- package/dist/utils/env-manager.js.map +1 -1
- package/dist/utils/error-tracking.js.map +1 -1
- package/dist/utils/event-loop-yield.js.map +1 -1
- package/dist/utils/extract-last-user-message.js.map +1 -1
- package/dist/utils/extraction-from-template.js.map +1 -1
- package/dist/utils/fact-embeddings.js.map +1 -1
- package/dist/utils/file-snapshot.js.map +1 -1
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/fs.js.map +1 -1
- package/dist/utils/gh-repo-arg.js.map +1 -1
- package/dist/utils/hybrid-mem-json-cli.js.map +1 -1
- package/dist/utils/language-keywords.js.map +1 -1
- package/dist/utils/lifecycle-generation.js.map +1 -1
- package/dist/utils/llm-json-array.js.map +1 -1
- package/dist/utils/llm-selection.js.map +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/model-provider-family.js.map +1 -1
- package/dist/utils/model-tier.js.map +1 -1
- package/dist/utils/openclaw-agent-defaults.js.map +1 -1
- package/dist/utils/path.js.map +1 -1
- package/dist/utils/plugin-root.js.map +1 -1
- package/dist/utils/plugin-update-check.js.map +1 -1
- package/dist/utils/procedure-risk.js.map +1 -1
- package/dist/utils/progress-indicators.js.map +1 -1
- package/dist/utils/prompt-loader.js.map +1 -1
- package/dist/utils/provenance.js.map +1 -1
- package/dist/utils/provider-detection.js.map +1 -1
- package/dist/utils/registration-superseded.js.map +1 -1
- package/dist/utils/salience.js.map +1 -1
- package/dist/utils/sanitize-messages.js.map +1 -1
- package/dist/utils/scope-filter.js.map +1 -1
- package/dist/utils/skill-discovery.js.map +1 -1
- package/dist/utils/sqlite-file-perms.js.map +1 -1
- package/dist/utils/sqlite-outcome-compat.js.map +1 -1
- package/dist/utils/sqlite-transaction.js.map +1 -1
- package/dist/utils/stable-stringify.js.map +1 -1
- package/dist/utils/subagent-ended-utils.js.map +1 -1
- package/dist/utils/tags.js.map +1 -1
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/timeout.js.map +1 -1
- package/dist/utils/typebox.js.map +1 -1
- package/dist/utils/version-check.js.map +1 -1
- package/dist/utils/wal-replay.js.map +1 -1
- package/dist/versionInfo.js.map +1 -1
- package/index.ts +2 -2
- package/lifecycle/hooks.ts +0 -1
- package/npm-shrinkwrap.json +487 -186
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -2
- package/services/adaptive-catch-up-pacing.ts +28 -0
- package/services/chat.ts +34 -1
- package/services/cron-job-bash-harness.ts +52 -5
- package/services/embeddings/shared.ts +5 -2
- package/services/entity-enrichment-adaptive.ts +245 -0
- package/services/entity-enrichment-cli.ts +553 -47
- package/services/entity-enrichment.ts +43 -2
- package/services/llm-rate-limit-headers.ts +1 -4
- package/services/maintenance-log-analyzer.ts +13 -9
- package/services/reinforcement-extract.ts +19 -0
- package/setup/hybrid-memory-reload-coordinator.ts +26 -0
- package/setup/register-plugin.ts +62 -32
- package/setup/reregister-policy.ts +10 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collectors.js","names":["execFileCb"],"sources":["../../../routes/dashboard/collectors.ts"],"sourcesContent":["/**\n * Mission Control Dashboard — Issue #309\n *\n * Serves a web dashboard via a small HTTP server registered as a plugin service.\n * Routes:\n * GET / — HTML dashboard (vanilla JS/CSS, no framework)\n * GET /api/status — JSON data for all dashboard sections\n */\n\nimport { existsSync } from \"node:fs\";\nimport { readdir, stat } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { type AgentHealthView, mergeAgentHealthDashboard } from \"../../backends/agent-health-store.js\";\nimport type { AuditStore } from \"../../backends/audit-store.js\";\nimport type { EdictStore } from \"../../backends/edict-store.js\";\nimport type { FactsDB } from \"../../backends/facts-db.js\";\nimport type { IssueStore } from \"../../backends/issue-store.js\";\nimport type { NarrativesDB } from \"../../backends/narratives-db.js\";\nimport type { VectorDB } from \"../../backends/vector-db.js\";\nimport type { WorkflowStore } from \"../../backends/workflow-store.js\";\nimport type { ProvenanceService } from \"../../services/provenance.js\";\nimport type { VerificationStore } from \"../../services/verification-store.js\";\nimport { getDirSize, getFileSizeAsync, readJsonFile } from \"../../utils/fs.js\";\nimport { pluginLogger } from \"../../utils/logger.js\";\nimport { isValidGhRepoArg } from \"../../utils/gh-repo-arg.js\";\nimport { execFile as execFileCb } from \"../../utils/process-runner.js\";\n\nconst execFile = promisify(execFileCb);\nconst require = createRequire(import.meta.url);\n\nconst _MAX_DASHBOARD_JSON_BODY_BYTES = 64 * 1024;\nconst VERIFIED_FACT_SET_TTL_MS = 5000;\nconst verifiedFactIdCacheByStore = new WeakMap<VerificationStore, { at: number; ids: Set<string> }>();\n\nfunction clearVerifiedFactIdCache(ctx: DashboardContext): void {\n const store = ctx.verificationStore;\n if (!store) return;\n verifiedFactIdCacheByStore.delete(store);\n}\n\nexport function getVerifiedFactIdSet(ctx: DashboardContext): Set<string> {\n const store = ctx.verificationStore;\n if (!store) return new Set();\n const now = Date.now();\n const cached = verifiedFactIdCacheByStore.get(store);\n if (cached && now - cached.at < VERIFIED_FACT_SET_TTL_MS) {\n return cached.ids;\n }\n try {\n const ids = new Set<string>();\n for (const v of store.listLatestVerified()) {\n ids.add(v.factId);\n }\n verifiedFactIdCacheByStore.set(store, { at: now, ids });\n return ids;\n } catch {\n return new Set();\n }\n}\n\nexport function parseUrlPathSegment(input: string): string | null {\n try {\n const trimmed = input.trim();\n if (!trimmed) return null;\n return decodeURIComponent(trimmed);\n } catch {\n return null;\n }\n}\n\nexport function readJsonBody(\n req: import(\"node:http\").IncomingMessage,\n maxBytes: number,\n): Promise<Record<string, unknown>> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let sizeBytes = 0;\n let settled = false;\n\n const cleanup = () => {\n req.off(\"data\", onData);\n req.off(\"end\", onEnd);\n req.off(\"error\", onError);\n };\n\n const resolveOnce = (value: Record<string, unknown>) => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(value);\n };\n\n const rejectOnce = (err: unknown) => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(err);\n };\n\n const onData = (chunk: Buffer | string) => {\n const chunkBytes = Buffer.isBuffer(chunk) ? chunk.byteLength : Buffer.byteLength(chunk, \"utf-8\");\n if (sizeBytes + chunkBytes > maxBytes) {\n rejectOnce(new Error(\"Request body too large\"));\n try {\n req.resume();\n } catch {\n /* ignore */\n }\n return;\n }\n sizeBytes += chunkBytes;\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, \"utf-8\"));\n };\n\n const onEnd = () => {\n if (chunks.length === 0) return resolveOnce({});\n try {\n const parsed = JSON.parse(Buffer.concat(chunks).toString(\"utf-8\"));\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return resolveOnce({});\n resolveOnce(parsed as Record<string, unknown>);\n } catch (err) {\n rejectOnce(err);\n }\n };\n\n const onError = (err: unknown) => {\n rejectOnce(err);\n };\n\n req.on(\"data\", onData);\n req.on(\"end\", onEnd);\n req.on(\"error\", onError);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface DashboardContext {\n factsDb: FactsDB;\n vectorDb: VectorDB;\n resolvedSqlitePath: string;\n resolvedLancePath: string;\n /** Optional owner/repo for GitHub queries (e.g. \"markus-lassfolk/openclaw-hybrid-memory\") */\n gitRepo?: string;\n /** Optional plugin config exposed to GraphQL context. */\n cfg?: unknown;\n /** Optional embedding service exposed to GraphQL context. */\n embeddings?: unknown;\n /** Optional embedding registry exposed to GraphQL context. */\n embeddingRegistry?: unknown;\n /** Optional CostTracker instance — delegates cost stats to the established abstraction. */\n costTracker?: import(\"../../backends/cost-tracker.js\").CostTracker | null;\n /** Optional logger for structured logging of server errors */\n logger?: { error?: (msg: string) => void };\n /** Cross-agent audit trail (Issue #790). */\n auditStore?: AuditStore | null;\n /** Per-agent health store (Issue #789). */\n agentHealthStore?: import(\"../../backends/agent-health-store.js\").AgentHealthStore | null;\n /** Edict store for verified ground-truth facts. */\n edictStore?: EdictStore | null;\n /** Verification store for critical facts. */\n verificationStore?: VerificationStore | null;\n /** Issue store for tracked problems. */\n issueStore?: IssueStore | null;\n /** Workflow store for tool-sequence patterns. */\n workflowStore?: WorkflowStore | null;\n /** Narratives store for session summaries. */\n narrativesDb?: NarrativesDB | null;\n /** Provenance service for fact-to-source tracing. */\n provenanceService?: ProvenanceService | null;\n /** Mirrors `graph.hubDegreeCap` for dashboard graph recall (Issue #1192). */\n graphHubDegreeCap?: number | null;\n /** Mirrors `graph.hubScorePenalty` for dashboard graph recall (#1192). */\n graphHubScorePenalty?: number | null;\n}\n\ninterface MemoryStats {\n activeFacts: number;\n expiredFacts: number;\n vectorCount: number;\n sqliteSizeBytes: number;\n lanceSizeBytes: number;\n totalSizeBytes: number;\n}\n\ninterface CronJobStatus {\n id: string;\n name: string;\n schedule: string;\n enabled: boolean;\n lastRunAt: string | null;\n nextRunAt: string | null;\n lastStatus: string | null;\n lastError: string | null;\n consecutiveErrors: number;\n agentId: string;\n model?: string;\n}\n\ninterface TaskQueueItem {\n issue?: number;\n title?: string;\n branch?: string;\n pid?: number;\n started?: string;\n status?: string;\n completed?: string;\n exit_code?: number;\n details?: string;\n}\n\ninterface ForgeTaskItem {\n agent?: string;\n task: string;\n workdir?: string;\n pid?: number;\n started_at?: string;\n status?: string;\n}\n\ninterface GitActivity {\n prs: Array<{\n number: number;\n title: string;\n state: string;\n url: string;\n createdAt: string;\n }>;\n issues: Array<{\n number: number;\n title: string;\n state: string;\n url: string;\n createdAt: string;\n }>;\n gitError?: string;\n}\n\ninterface CostRow {\n feature: string;\n calls: number;\n inputTokens: number;\n outputTokens: number;\n estimatedCostUsd: number;\n}\n\ninterface CostStats {\n features: CostRow[];\n totalCalls: number;\n totalInputTokens: number;\n totalOutputTokens: number;\n totalEstimatedCostUsd: number;\n days: number;\n enabled: boolean;\n}\n\ninterface AgentHealthPayload {\n enabled: boolean;\n agents: AgentHealthView[];\n alerts: string[];\n}\n\ninterface AuditSummaryPayload {\n enabled: boolean;\n total24h: number;\n byOutcome: { success: number; partial: number; failed: number };\n byAgent: Record<string, number>;\n recentFailures: Array<{\n timestamp: number;\n agentId: string;\n action: string;\n target: string | null;\n error: string | null;\n }>;\n}\n\ninterface DashboardStatus {\n generatedAt: string;\n memory: MemoryStats;\n cronJobs: CronJobStatus[];\n taskQueue: {\n current: TaskQueueItem | null;\n history: TaskQueueItem[];\n };\n forge: ForgeTaskItem[];\n git: GitActivity;\n costs: CostStats;\n audit: AuditSummaryPayload;\n agentHealth: AgentHealthPayload;\n}\n\n// ---------------------------------------------------------------------------\n// Memory Viewer types (Issue #1023)\n// ---------------------------------------------------------------------------\n\ninterface MemoryViewerStats {\n totalFacts: number;\n totalExpired: number;\n totalSuperseded: number;\n totalVerified: number;\n totalEdicts: number;\n totalIssues: number;\n totalProcedures: number;\n totalEpisodes: number;\n totalLinks: number;\n vectorCount: number;\n byCategory: Record<string, number>;\n byTier: Record<string, number>;\n byDecayClass: Record<string, number>;\n bySource: Record<string, number>;\n entityCount: number;\n}\n\ninterface MemoryViewerEpisode {\n id: string;\n event: string;\n outcome: string;\n timestamp: number;\n duration?: number;\n context?: string;\n agentId?: string;\n sessionId?: string;\n importance: number;\n tags: string[];\n}\n\nexport interface MemoryViewerFact {\n id: string;\n text: string;\n why?: string | null;\n category: string;\n importance: number;\n entity: string | null;\n key: string | null;\n value: string | null;\n source: string;\n createdAt: number;\n decayClass: string;\n expiresAt: number | null;\n confidence: number;\n summary?: string | null;\n tags: string[];\n supersededAt?: number | null;\n supersededBy?: string | null;\n verified?: boolean;\n edict?: boolean;\n scope?: string;\n provenanceSession?: string | null;\n reinforcedCount?: number;\n}\n\ninterface MemoryViewerEntity {\n entity: string;\n factCount: number;\n categories: string[];\n tags: string[];\n lastUpdated: number;\n}\n\ninterface MemoryViewerEdict {\n id: string;\n text: string;\n source?: string | null;\n tags: string[];\n verifiedAt: number | null;\n expiresAt: string | null;\n ttl: string;\n createdAt: number;\n}\n\ninterface MemoryViewerIssue {\n id: string;\n title: string;\n status: string;\n severity: string;\n symptoms: string[];\n rootCause?: string | null;\n fix?: string | null;\n tags: string[];\n detectedAt: string;\n resolvedAt?: string | null;\n verifiedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface MemoryViewerWorkflow {\n id: string;\n goal: string;\n toolSequence: string[];\n outcome: string;\n toolCount: number;\n durationMs: number;\n successRate: number;\n sessionId: string;\n createdAt: string;\n}\n\ninterface MemoryViewerNarrative {\n id: string;\n sessionId: string;\n periodStart: number;\n periodEnd: number;\n tag: string;\n narrativeText: string;\n createdAt: number;\n}\n\ninterface MemoryViewerVerification {\n factId: string;\n canonicalText: string;\n verifiedAt: string;\n verifiedBy: string;\n nextVerification: string | null;\n version: number;\n}\n\ninterface MemoryViewerProvenance {\n factId: string;\n text: string;\n confidence: number;\n provenanceSession?: string | null;\n sourceTurn?: number | null;\n edges: Array<{\n edgeType: string;\n sourceType: string;\n sourceId: string;\n sourceText?: string | null;\n createdAt: string;\n }>;\n}\n\ninterface MemoryViewerLinks {\n from: string;\n to: string;\n type: string;\n strength: number;\n}\n\n// ---------------------------------------------------------------------------\n// Data collection helpers\n// ---------------------------------------------------------------------------\n\n/** Cached LanceDB dir size keyed by resolved path to avoid repeated traversal on every poll */\nconst _lanceSizeCache = new Map<string, { size: number; ts: number }>();\nconst _lanceInFlight = new Map<string, Promise<number>>();\nconst LANCE_CACHE_TTL_MS = 300_000; // 5 minutes\n\nasync function collectMemoryStats(ctx: DashboardContext): Promise<MemoryStats> {\n const activeFacts = ctx.factsDb.count();\n const expiredFacts = ctx.factsDb.countExpired();\n let vectorCount = 0;\n try {\n vectorCount = await ctx.vectorDb.count();\n } catch {\n /* non-fatal */\n }\n const sqliteSize = await getFileSizeAsync(ctx.resolvedSqlitePath);\n const sqliteWalSize = await getFileSizeAsync(`${ctx.resolvedSqlitePath}-wal`);\n const sqliteShmSize = await getFileSizeAsync(`${ctx.resolvedSqlitePath}-shm`);\n const sqliteSizeBytes = sqliteSize + sqliteWalSize + sqliteShmSize;\n\n // Use cached LanceDB size to avoid blocking on large directory traversals.\n // TOCTOU guard: write to cache inside .then() — before .finally() clears the\n // in-flight entry — so any concurrent caller that sees no in-flight promise\n // will always find the cache already populated.\n const cachedEntry = _lanceSizeCache.get(ctx.resolvedLancePath);\n const now = Date.now();\n if (!cachedEntry || now - cachedEntry.ts > LANCE_CACHE_TTL_MS) {\n let inFlightPromise = _lanceInFlight.get(ctx.resolvedLancePath);\n if (!inFlightPromise) {\n inFlightPromise = getDirSize(ctx.resolvedLancePath)\n .then((size) => {\n _lanceSizeCache.set(ctx.resolvedLancePath, { size, ts: Date.now() });\n return size;\n })\n .finally(() => {\n _lanceInFlight.delete(ctx.resolvedLancePath);\n });\n _lanceInFlight.set(ctx.resolvedLancePath, inFlightPromise);\n }\n try {\n await inFlightPromise;\n } catch (err) {\n pluginLogger.error(\n `[dashboard-server] lance size traversal failed for ${ctx.resolvedLancePath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n const lanceSizeBytes = _lanceSizeCache.get(ctx.resolvedLancePath)?.size ?? 0;\n\n return {\n activeFacts,\n expiredFacts,\n vectorCount,\n sqliteSizeBytes,\n lanceSizeBytes,\n totalSizeBytes: sqliteSizeBytes + lanceSizeBytes,\n };\n}\n\nasync function collectCronJobs(): Promise<CronJobStatus[]> {\n const openclawDir = join(homedir(), \".openclaw\");\n const cronStorePath = join(openclawDir, \"cron\", \"jobs.json\");\n if (!existsSync(cronStorePath)) return [];\n try {\n const store = await readJsonFile<{ jobs?: unknown[] }>(cronStorePath);\n if (!store || !Array.isArray(store.jobs)) return [];\n return store.jobs\n .filter((j): j is Record<string, unknown> => typeof j === \"object\" && j !== null)\n .map((job) => {\n const state = (typeof job.state === \"object\" && job.state !== null ? job.state : {}) as Record<string, unknown>;\n const schedule = job.schedule as Record<string, unknown> | undefined;\n const payload = job.payload as Record<string, unknown> | undefined;\n return {\n id: String(job.id ?? \"\"),\n name: String(job.name ?? \"\"),\n schedule: typeof schedule?.expr === \"string\" ? schedule.expr : \"\",\n enabled: job.enabled !== false,\n lastRunAt: typeof state.lastRunAtMs === \"number\" ? new Date(state.lastRunAtMs).toISOString() : null,\n nextRunAt: typeof state.nextRunAtMs === \"number\" ? new Date(state.nextRunAtMs).toISOString() : null,\n lastStatus:\n typeof state.lastStatus === \"string\"\n ? state.lastStatus\n : typeof state.lastRunStatus === \"string\"\n ? state.lastRunStatus\n : null,\n lastError: typeof state.lastError === \"string\" ? state.lastError : null,\n consecutiveErrors: typeof state.consecutiveErrors === \"number\" ? state.consecutiveErrors : 0,\n agentId: String(job.agentId ?? \"\"),\n model: typeof payload?.model === \"string\" ? payload.model : undefined,\n };\n });\n } catch {\n return [];\n }\n}\n\nasync function collectTaskQueue(): Promise<{\n current: TaskQueueItem | null;\n history: TaskQueueItem[];\n}> {\n const stateDir = join(homedir(), \".openclaw\", \"workspace\", \"state\", \"task-queue\");\n const currentPath = join(stateDir, \"current.json\");\n const historyDir = join(stateDir, \"history\");\n\n const current = await readJsonFile<TaskQueueItem>(currentPath);\n\n let history: TaskQueueItem[] = [];\n if (existsSync(historyDir)) {\n try {\n const files = (await readdir(historyDir))\n .filter((f) => f.endsWith(\".json\"))\n .sort()\n .reverse()\n .slice(0, 10);\n history = (await Promise.all(files.map((f) => readJsonFile<TaskQueueItem>(join(historyDir, f))))).filter(\n (item): item is TaskQueueItem => item !== null,\n );\n } catch {\n /* non-fatal */\n }\n }\n\n return { current, history };\n}\n\nexport async function collectForgeState(): Promise<ForgeTaskItem[]> {\n const forgeDir = join(homedir(), \".openclaw\", \"workspace\", \"state\", \"forge\");\n if (!existsSync(forgeDir)) return [];\n try {\n const files = (await readdir(forgeDir))\n .filter((f) => f.endsWith(\".json\"))\n .sort()\n .reverse()\n .slice(0, 50);\n const withMtime = (\n await Promise.all(\n files.map(async (f) => {\n const fullPath = join(forgeDir, f);\n try {\n return { name: f, mtime: (await stat(fullPath)).mtimeMs };\n } catch {\n return null;\n }\n }),\n )\n ).filter((e): e is { name: string; mtime: number } => e !== null);\n withMtime.sort((a, b) => b.mtime - a.mtime);\n return (\n await Promise.all(\n withMtime.slice(0, 20).map(async (e) => {\n const item = await readJsonFile<ForgeTaskItem>(join(forgeDir, e.name));\n if (item) {\n item.agent = e.name.replace(/\\.json$/, \"\");\n }\n return item;\n }),\n )\n ).filter((item): item is ForgeTaskItem => item !== null);\n } catch {\n return [];\n }\n}\n\nasync function collectGitActivity(repo?: string): Promise<GitActivity> {\n try {\n const safeRepo = repo && isValidGhRepoArg(repo) ? repo : undefined;\n const repoArgs = safeRepo ? [\"--repo\", safeRepo] : [];\n const [prResult, issueResult] = await Promise.all([\n execFile(\"gh\", [\"pr\", \"list\", \"--limit\", \"10\", \"--json\", \"number,title,state,url,createdAt\", ...repoArgs], {\n timeout: 8000,\n encoding: \"utf-8\",\n }),\n execFile(\"gh\", [\"issue\", \"list\", \"--limit\", \"10\", \"--json\", \"number,title,state,url,createdAt\", ...repoArgs], {\n timeout: 8000,\n encoding: \"utf-8\",\n }),\n ]);\n type GitItem = {\n number: number;\n title: string;\n state: string;\n url: string;\n createdAt: string;\n };\n const prJson = prResult.stdout.trim();\n const issueJson = issueResult.stdout.trim();\n return {\n prs: prJson ? (JSON.parse(prJson) as GitItem[]) : [],\n issues: issueJson ? (JSON.parse(issueJson) as GitItem[]) : [],\n };\n } catch (err) {\n return { prs: [], issues: [], gitError: String(err) };\n }\n}\n\nfunction collectCostStats(ctx: DashboardContext): CostStats {\n const days = 7;\n const empty: CostStats = {\n features: [],\n totalCalls: 0,\n totalInputTokens: 0,\n totalOutputTokens: 0,\n totalEstimatedCostUsd: 0,\n days,\n enabled: false,\n };\n\n // Prefer the established CostTracker abstraction when available to avoid duplicating SQL.\n if (ctx.costTracker) {\n try {\n const report = ctx.costTracker.getReport({ days });\n return {\n features: report.features.slice(0, 20),\n totalCalls: report.total.calls,\n totalInputTokens: report.total.inputTokens,\n totalOutputTokens: report.total.outputTokens,\n totalEstimatedCostUsd: report.total.estimatedCostUsd,\n days,\n enabled: true,\n };\n } catch {\n return empty;\n }\n }\n\n // Fallback: query the DB directly (e.g. in tests where CostTracker is not injected).\n try {\n const db = ctx.factsDb.getRawDb();\n const cutoff = Math.floor(Date.now() / 1000) - days * 86400;\n\n const tableExists = db.prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name='llm_cost_log'\").get() as\n | { name: string }\n | undefined;\n\n if (!tableExists) return empty;\n\n const rows = db\n .prepare(\n `SELECT feature,\n COUNT(*) AS calls,\n COALESCE(SUM(input_tokens), 0) AS inputTokens,\n COALESCE(SUM(output_tokens), 0) AS outputTokens,\n COALESCE(SUM(estimated_cost_usd), 0) AS estimatedCostUsd\n FROM llm_cost_log\n WHERE timestamp >= ?\n GROUP BY feature\n ORDER BY estimatedCostUsd DESC`,\n )\n .all(cutoff) as Array<{\n feature: string;\n calls: number;\n inputTokens: number;\n outputTokens: number;\n estimatedCostUsd: number;\n }>;\n\n const allFeatures: CostRow[] = rows.map((r) => ({\n feature: r.feature,\n calls: Number(r.calls),\n inputTokens: Number(r.inputTokens),\n outputTokens: Number(r.outputTokens),\n estimatedCostUsd: Number(r.estimatedCostUsd),\n }));\n\n return {\n features: allFeatures.slice(0, 20),\n totalCalls: allFeatures.reduce((s, r) => s + r.calls, 0),\n totalInputTokens: allFeatures.reduce((s, r) => s + r.inputTokens, 0),\n totalOutputTokens: allFeatures.reduce((s, r) => s + r.outputTokens, 0),\n totalEstimatedCostUsd: allFeatures.reduce((s, r) => s + r.estimatedCostUsd, 0),\n days,\n enabled: true,\n };\n } catch {\n return empty;\n }\n}\n\nexport async function collectAgentHealth(\n ctx: DashboardContext,\n forgeState?: ForgeTaskItem[],\n): Promise<AgentHealthPayload> {\n if (!ctx.agentHealthStore) {\n return { enabled: false, agents: [], alerts: [] };\n }\n try {\n const forge = forgeState ?? (await collectForgeState());\n const db = ctx.agentHealthStore.listAll();\n const agents = mergeAgentHealthDashboard(forge, db);\n const alerts: string[] = [];\n for (const a of agents) {\n if (a.status === \"stale\") alerts.push(`${a.agentId}: no activity > 4h — check dispatch`);\n if (a.status === \"degraded\") alerts.push(`${a.agentId}: score ${a.score.toFixed(0)} (degraded)`);\n }\n return { enabled: true, agents, alerts };\n } catch {\n return { enabled: false, agents: [], alerts: [] };\n }\n}\n\nexport function collectAuditSummary(ctx: DashboardContext): AuditSummaryPayload {\n if (!ctx.auditStore) {\n return {\n enabled: false,\n total24h: 0,\n byOutcome: { success: 0, partial: 0, failed: 0 },\n byAgent: {},\n recentFailures: [],\n };\n }\n try {\n const s = ctx.auditStore.summary24h();\n const failed = ctx.auditStore.query({ sinceMs: Date.now() - 24 * 3600 * 1000, outcome: \"failed\", limit: 8 });\n return {\n enabled: true,\n total24h: s.total,\n byOutcome: s.byOutcome,\n byAgent: s.byAgent,\n recentFailures: failed.map((r) => ({\n timestamp: r.timestamp,\n agentId: r.agentId,\n action: r.action,\n target: r.target,\n error: r.error,\n })),\n };\n } catch {\n return {\n enabled: false,\n total24h: 0,\n byOutcome: { success: 0, partial: 0, failed: 0 },\n byAgent: {},\n recentFailures: [],\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Memory Viewer collectors (Issue #1023)\n// ---------------------------------------------------------------------------\n\n/** Open a read-only handle to the facts DB for internal dashboard use. */\nfunction openFactsDbReadonly(path: string): import(\"node:sqlite\").DatabaseSync | null {\n try {\n const { DatabaseSync: DBSync } = require(\"node:sqlite\") as typeof import(\"node:sqlite\");\n const db = new DBSync(path, { readOnly: true });\n return db;\n } catch {\n return null;\n }\n}\n\n/** Collect Memory Viewer overview stats. */\nexport async function collectMemoryViewerStats(ctx: DashboardContext): Promise<MemoryViewerStats> {\n const factsDb = ctx.factsDb;\n const totalFacts = factsDb.count();\n const totalExpired = factsDb.countExpired();\n\n // Use a read-only connection to the facts DB for counts not exposed by the public API\n const roDb = openFactsDbReadonly(ctx.resolvedSqlitePath);\n let totalSuperseded = 0;\n let totalVerified = 0;\n let totalEdicts = 0;\n let totalEpisodes = 0;\n if (roDb) {\n try {\n const sr = roDb.prepare(\"SELECT COUNT(*) as cnt FROM facts WHERE superseded_at IS NOT NULL\").get() as\n | { cnt: number }\n | undefined;\n totalSuperseded = sr?.cnt ?? 0;\n } catch {\n /* non-fatal */\n }\n try {\n const vr = roDb.prepare(\"SELECT COUNT(*) as cnt FROM verified_facts\").get() as { cnt: number } | undefined;\n totalVerified = vr?.cnt ?? 0;\n } catch {\n /* non-fatal */\n }\n try {\n const er = roDb.prepare(\"SELECT COUNT(*) as cnt FROM edicts\").get() as { cnt: number } | undefined;\n totalEdicts = er?.cnt ?? 0;\n } catch {\n /* non-fatal */\n }\n try {\n const ar = roDb.prepare(\"SELECT COUNT(*) as cnt FROM episodes\").get() as { cnt: number } | undefined;\n totalEpisodes = ar?.cnt ?? 0;\n } catch {\n /* non-fatal */\n }\n try {\n roDb.close();\n } catch {\n /* ignore */\n }\n }\n\n const totalIssues = (() => {\n try {\n if (!ctx.issueStore) return 0;\n return ctx.issueStore.list({}).length;\n } catch {\n return 0;\n }\n })();\n const totalProcedures = (() => {\n try {\n return factsDb.proceduresCount();\n } catch {\n return 0;\n }\n })();\n const totalLinks = (() => {\n try {\n return factsDb.linksCount();\n } catch {\n return 0;\n }\n })();\n let vectorCount = 0;\n try {\n vectorCount = await ctx.vectorDb.count();\n } catch {\n /* non-fatal */\n }\n\n return {\n totalFacts,\n totalExpired,\n totalSuperseded,\n totalVerified,\n totalEdicts,\n totalIssues,\n totalProcedures,\n totalEpisodes,\n totalLinks,\n vectorCount,\n byCategory: factsDb.statsBreakdownByCategory(),\n byTier: factsDb.statsBreakdownByTier(),\n byDecayClass: factsDb.statsBreakdownByDecayClass(),\n bySource: factsDb.statsBreakdownBySource(),\n entityCount: factsDb.entityCount(),\n };\n}\n\n/** Collect recent episodes — reads from the episodes table within the facts DB. */\nexport function collectMemoryViewerEpisodes(ctx: DashboardContext, limit = 50): MemoryViewerEpisode[] {\n try {\n const roDb = openFactsDbReadonly(ctx.resolvedSqlitePath);\n if (!roDb) return [];\n try {\n const rows = roDb.prepare(\"SELECT * FROM episodes ORDER BY timestamp DESC LIMIT ?\").all(limit) as Array<\n Record<string, unknown>\n >;\n return rows.map((r) => ({\n id: String(r.id ?? \"\"),\n event: String(r.event ?? \"\"),\n outcome: String(r.outcome ?? \"\"),\n timestamp: Number(r.timestamp ?? 0),\n duration: r.duration != null ? Number(r.duration) : undefined,\n context: r.context != null ? String(r.context) : undefined,\n agentId: r.agent_id != null ? String(r.agent_id) : undefined,\n sessionId: r.session_id != null ? String(r.session_id) : undefined,\n importance: Number(r.importance ?? 0.5),\n tags: (() => {\n try {\n return JSON.parse(String(r.tags ?? \"[]\"));\n } catch {\n return [];\n }\n })(),\n }));\n } finally {\n try {\n roDb.close();\n } catch {\n /* ignore */\n }\n }\n } catch {\n return [];\n }\n}\n\n/** Collect recent narratives. */\nexport function collectMemoryViewerNarratives(ctx: DashboardContext, limit = 20): MemoryViewerNarrative[] {\n try {\n if (!ctx.narrativesDb) return [];\n return ctx.narrativesDb.listRecent(limit, \"all\").map((n) => ({\n id: n.id,\n sessionId: n.sessionId,\n periodStart: n.periodStart,\n periodEnd: n.periodEnd,\n tag: n.tag,\n narrativeText: n.narrativeText,\n createdAt: n.createdAt,\n }));\n } catch {\n return [];\n }\n}\n\n/** Collect recent issues. */\nexport function collectMemoryViewerIssues(ctx: DashboardContext): MemoryViewerIssue[] {\n try {\n if (!ctx.issueStore) return [];\n return ctx.issueStore.list({}).map((issue) => ({\n id: issue.id,\n title: issue.title,\n status: issue.status,\n severity: issue.severity,\n symptoms: issue.symptoms,\n rootCause: issue.rootCause,\n fix: issue.fix,\n tags: issue.tags,\n detectedAt: issue.detectedAt,\n resolvedAt: issue.resolvedAt,\n verifiedAt: issue.verifiedAt,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n }));\n } catch {\n return [];\n }\n}\n\n/** Collect workflow patterns / recent traces. */\nexport function collectMemoryViewerWorkflows(ctx: DashboardContext, limit = 100): MemoryViewerWorkflow[] {\n try {\n if (!ctx.workflowStore) return [];\n const traces = ctx.workflowStore.list({ limit });\n const patterns = ctx.workflowStore.getPatterns({ limit: 20 });\n const result: MemoryViewerWorkflow[] = traces.map((t) => ({\n id: t.id,\n goal: t.goal,\n toolSequence: t.toolSequence,\n outcome: t.outcome,\n toolCount: t.toolCount,\n durationMs: t.durationMs,\n successRate:\n patterns.find((p) => JSON.stringify(p.toolSequence) === JSON.stringify(t.toolSequence))?.successRate ?? 0,\n sessionId: t.sessionId,\n createdAt: t.createdAt,\n }));\n return result;\n } catch {\n return [];\n }\n}\n\n/** Collect recent edicts. */\nexport function collectMemoryViewerEdicts(ctx: DashboardContext): MemoryViewerEdict[] {\n try {\n if (!ctx.edictStore) return [];\n return ctx.edictStore.list({}).map((e) => ({\n id: e.id,\n text: e.text,\n source: e.source,\n tags: e.tags,\n verifiedAt: e.verifiedAt,\n expiresAt: e.expiresAt,\n ttl: String(e.ttl),\n createdAt: e.createdAt,\n }));\n } catch {\n return [];\n }\n}\n\n/** Collect verified facts using the public listLatestVerified API. */\nexport function collectMemoryViewerVerified(ctx: DashboardContext, limit = 100): MemoryViewerVerification[] {\n try {\n if (!ctx.verificationStore) return [];\n const verified = ctx.verificationStore.listLatestVerified().slice(0, Math.max(1, Math.min(500, Math.floor(limit))));\n return verified.map((v) => ({\n factId: v.factId,\n canonicalText: v.canonicalText,\n verifiedAt: v.verifiedAt ?? \"\",\n verifiedBy: v.verifiedBy ?? \"\",\n nextVerification: v.nextVerification ?? null,\n version: v.version,\n }));\n } catch {\n return [];\n }\n}\n\n/** Collect top entities. */\nexport function collectMemoryViewerEntities(ctx: DashboardContext, limit = 50): MemoryViewerEntity[] {\n try {\n const raw = ctx.factsDb.getRawDb();\n const rows = raw\n .prepare(\n `SELECT entity, COUNT(*) as cnt, GROUP_CONCAT(DISTINCT category) as cats, GROUP_CONCAT(DISTINCT tags) as tgs, MAX(created_at) as last_updated\n FROM facts WHERE entity IS NOT NULL AND entity != '' AND superseded_at IS NULL\n GROUP BY entity ORDER BY cnt DESC LIMIT ?`,\n )\n .all(limit) as Array<Record<string, unknown>>;\n return rows.map((r) => {\n let cats: string[] = [];\n try {\n cats = [...new Set(String(r.cats ?? \"\").split(\",\"))];\n } catch {}\n let tgs: string[] = [];\n try {\n const allTags = String(r.tgs ?? \"\").split(\",\");\n tgs = [...new Set(allTags.filter(Boolean))];\n } catch {}\n return {\n entity: String(r.entity ?? \"\"),\n factCount: Number(r.cnt ?? 0),\n categories: cats,\n tags: tgs,\n lastUpdated: Number(r.last_updated ?? 0),\n };\n });\n } catch {\n return [];\n }\n}\n\n/** Collect provenance edges for a fact. */\nexport function collectMemoryViewerProvenance(ctx: DashboardContext, factId: string): MemoryViewerProvenance | null {\n try {\n if (!ctx.provenanceService) return null;\n // Note: getProvenance accepts an optional factsDb param for fact text enrichment.\n // We pass the open FactsDB instance directly for this read-only access.\n const chain = ctx.provenanceService.getProvenance(factId);\n return {\n factId: chain.fact.id,\n text: chain.fact.text,\n confidence: chain.fact.confidence,\n provenanceSession: chain.source.sessionId,\n sourceTurn: chain.source.turn,\n edges: chain.edges.map((e) => ({\n edgeType: e.edgeType,\n sourceType: e.sourceType,\n sourceId: e.sourceId,\n sourceText: e.sourceText,\n createdAt: e.createdAt,\n })),\n };\n } catch {\n return null;\n }\n}\n\n/** Collect fact links from the memory_links table. */\nexport function collectMemoryViewerLinks(ctx: DashboardContext, limit = 5000): MemoryViewerLinks[] {\n try {\n const roDb = openFactsDbReadonly(ctx.resolvedSqlitePath);\n if (!roDb) return [];\n try {\n const rows = roDb.prepare(\"SELECT * FROM memory_links LIMIT ?\").all(limit) as Array<Record<string, unknown>>;\n return rows.map((r) => ({\n from: String(r.source_fact_id ?? \"\"),\n to: String(r.target_fact_id ?? \"\"),\n type: String(r.link_type ?? \"\"),\n strength: Number(r.strength ?? 1),\n }));\n } finally {\n try {\n roDb.close();\n } catch {\n /* ignore */\n }\n }\n } catch {\n return [];\n }\n}\n\n/** Perform a fact action (verify / forget) and return result. */\nexport function performFactAction(\n ctx: DashboardContext,\n action: \"verify\" | \"forget\",\n factId: string,\n body: Record<string, unknown>,\n): { ok: boolean; message: string } {\n try {\n const factsDb = ctx.factsDb;\n const fact = factsDb.getById(factId);\n if (!fact) return { ok: false, message: `Fact not found: ${factId}` };\n\n if (action === \"verify\") {\n if (!ctx.verificationStore) return { ok: false, message: \"Verification store not available\" };\n const verifiedBy = (body.verifiedBy as \"agent\" | \"user\" | \"system\") ?? \"agent\";\n ctx.verificationStore.verify(factId, fact.text, verifiedBy);\n clearVerifiedFactIdCache(ctx);\n return { ok: true, message: `Fact ${factId} verified as ${verifiedBy}` };\n }\n // forget: supersede with null to mark the fact as superseded (soft-delete).\n // superseded_at IS NOT NULL filters it out of all recall paths.\n try {\n const ok = factsDb.supersede(factId, null);\n if (!ok) return { ok: false, message: `Could not supersede fact ${factId}` };\n } catch {\n return { ok: false, message: `Could not forget fact ${factId}` };\n }\n clearVerifiedFactIdCache(ctx);\n return { ok: true, message: `Fact ${factId} forgotten` };\n } catch {\n return { ok: false, message: \"Fact action failed\" };\n }\n}\n\nexport async function collectStatus(ctx: DashboardContext): Promise<DashboardStatus> {\n const [memory, cronJobs, taskQueue, forge, git] = await Promise.all([\n collectMemoryStats(ctx),\n collectCronJobs(),\n collectTaskQueue(),\n collectForgeState(),\n collectGitActivity(ctx.gitRepo),\n ]);\n const agentHealth = await collectAgentHealth(ctx, forge);\n return {\n generatedAt: new Date().toISOString(),\n memory,\n cronJobs,\n taskQueue,\n forge,\n git,\n costs: collectCostStats(ctx),\n audit: collectAuditSummary(ctx),\n agentHealth,\n };\n}\n\n// ---------------------------------------------------------------------------\n// HTML dashboard\n// ---------------------------------------------------------------------------\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA8BA,MAAM,WAAW,UAAUA,WAAW;AACtC,MAAM,UAAU,cAAc,OAAO,KAAK,IAAI;AAG9C,MAAM,2BAA2B;AACjC,MAAM,6CAA6B,IAAI,SAA8D;AAErG,SAAS,yBAAyB,KAA6B;CAC7D,MAAM,QAAQ,IAAI;CAClB,IAAI,CAAC,OAAO;CACZ,2BAA2B,OAAO,MAAM;;AAG1C,SAAgB,qBAAqB,KAAoC;CACvE,MAAM,QAAQ,IAAI;CAClB,IAAI,CAAC,OAAO,uBAAO,IAAI,KAAK;CAC5B,MAAM,MAAM,KAAK,KAAK;CACtB,MAAM,SAAS,2BAA2B,IAAI,MAAM;CACpD,IAAI,UAAU,MAAM,OAAO,KAAK,0BAC9B,OAAO,OAAO;CAEhB,IAAI;EACF,MAAM,sBAAM,IAAI,KAAa;EAC7B,KAAK,MAAM,KAAK,MAAM,oBAAoB,EACxC,IAAI,IAAI,EAAE,OAAO;EAEnB,2BAA2B,IAAI,OAAO;GAAE,IAAI;GAAK;GAAK,CAAC;EACvD,OAAO;SACD;EACN,uBAAO,IAAI,KAAK;;;AAIpB,SAAgB,oBAAoB,OAA8B;CAChE,IAAI;EACF,MAAM,UAAU,MAAM,MAAM;EAC5B,IAAI,CAAC,SAAS,OAAO;EACrB,OAAO,mBAAmB,QAAQ;SAC5B;EACN,OAAO;;;AAIX,SAAgB,aACd,KACA,UACkC;CAClC,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,SAAmB,EAAE;EAC3B,IAAI,YAAY;EAChB,IAAI,UAAU;EAEd,MAAM,gBAAgB;GACpB,IAAI,IAAI,QAAQ,OAAO;GACvB,IAAI,IAAI,OAAO,MAAM;GACrB,IAAI,IAAI,SAAS,QAAQ;;EAG3B,MAAM,eAAe,UAAmC;GACtD,IAAI,SAAS;GACb,UAAU;GACV,SAAS;GACT,QAAQ,MAAM;;EAGhB,MAAM,cAAc,QAAiB;GACnC,IAAI,SAAS;GACb,UAAU;GACV,SAAS;GACT,OAAO,IAAI;;EAGb,MAAM,UAAU,UAA2B;GACzC,MAAM,aAAa,OAAO,SAAS,MAAM,GAAG,MAAM,aAAa,OAAO,WAAW,OAAO,QAAQ;GAChG,IAAI,YAAY,aAAa,UAAU;IACrC,2BAAW,IAAI,MAAM,yBAAyB,CAAC;IAC/C,IAAI;KACF,IAAI,QAAQ;YACN;IAGR;;GAEF,aAAa;GACb,OAAO,KAAK,OAAO,SAAS,MAAM,GAAG,QAAQ,OAAO,KAAK,OAAO,QAAQ,CAAC;;EAG3E,MAAM,cAAc;GAClB,IAAI,OAAO,WAAW,GAAG,OAAO,YAAY,EAAE,CAAC;GAC/C,IAAI;IACF,MAAM,SAAS,KAAK,MAAM,OAAO,OAAO,OAAO,CAAC,SAAS,QAAQ,CAAC;IAClE,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,EAAE,OAAO,YAAY,EAAE,CAAC;IAC1F,YAAY,OAAkC;YACvC,KAAK;IACZ,WAAW,IAAI;;;EAInB,MAAM,WAAW,QAAiB;GAChC,WAAW,IAAI;;EAGjB,IAAI,GAAG,QAAQ,OAAO;EACtB,IAAI,GAAG,OAAO,MAAM;EACpB,IAAI,GAAG,SAAS,QAAQ;GACxB;;;AA0TJ,MAAM,kCAAkB,IAAI,KAA2C;AACvE,MAAM,iCAAiB,IAAI,KAA8B;AACzD,MAAM,qBAAqB;AAE3B,eAAe,mBAAmB,KAA6C;CAC7E,MAAM,cAAc,IAAI,QAAQ,OAAO;CACvC,MAAM,eAAe,IAAI,QAAQ,cAAc;CAC/C,IAAI,cAAc;CAClB,IAAI;EACF,cAAc,MAAM,IAAI,SAAS,OAAO;SAClC;CAGR,MAAM,aAAa,MAAM,iBAAiB,IAAI,mBAAmB;CACjE,MAAM,gBAAgB,MAAM,iBAAiB,GAAG,IAAI,mBAAmB,MAAM;CAC7E,MAAM,gBAAgB,MAAM,iBAAiB,GAAG,IAAI,mBAAmB,MAAM;CAC7E,MAAM,kBAAkB,aAAa,gBAAgB;CAMrD,MAAM,cAAc,gBAAgB,IAAI,IAAI,kBAAkB;CAE9D,IAAI,CAAC,eADO,KAAK,KACM,GAAG,YAAY,KAAK,oBAAoB;EAC7D,IAAI,kBAAkB,eAAe,IAAI,IAAI,kBAAkB;EAC/D,IAAI,CAAC,iBAAiB;GACpB,kBAAkB,WAAW,IAAI,kBAAkB,CAChD,MAAM,SAAS;IACd,gBAAgB,IAAI,IAAI,mBAAmB;KAAE;KAAM,IAAI,KAAK,KAAK;KAAE,CAAC;IACpE,OAAO;KACP,CACD,cAAc;IACb,eAAe,OAAO,IAAI,kBAAkB;KAC5C;GACJ,eAAe,IAAI,IAAI,mBAAmB,gBAAgB;;EAE5D,IAAI;GACF,MAAM;WACC,KAAK;GACZ,aAAa,MACX,sDAAsD,IAAI,kBAAkB,IAAI,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GACjI;;;CAGL,MAAM,iBAAiB,gBAAgB,IAAI,IAAI,kBAAkB,EAAE,QAAQ;CAE3E,OAAO;EACL;EACA;EACA;EACA;EACA;EACA,gBAAgB,kBAAkB;EACnC;;AAGH,eAAe,kBAA4C;CAEzD,MAAM,gBAAgB,KADF,KAAK,SAAS,EAAE,YACE,EAAE,QAAQ,YAAY;CAC5D,IAAI,CAAC,WAAW,cAAc,EAAE,OAAO,EAAE;CACzC,IAAI;EACF,MAAM,QAAQ,MAAM,aAAmC,cAAc;EACrE,IAAI,CAAC,SAAS,CAAC,MAAM,QAAQ,MAAM,KAAK,EAAE,OAAO,EAAE;EACnD,OAAO,MAAM,KACV,QAAQ,MAAoC,OAAO,MAAM,YAAY,MAAM,KAAK,CAChF,KAAK,QAAQ;GACZ,MAAM,QAAS,OAAO,IAAI,UAAU,YAAY,IAAI,UAAU,OAAO,IAAI,QAAQ,EAAE;GACnF,MAAM,WAAW,IAAI;GACrB,MAAM,UAAU,IAAI;GACpB,OAAO;IACL,IAAI,OAAO,IAAI,MAAM,GAAG;IACxB,MAAM,OAAO,IAAI,QAAQ,GAAG;IAC5B,UAAU,OAAO,UAAU,SAAS,WAAW,SAAS,OAAO;IAC/D,SAAS,IAAI,YAAY;IACzB,WAAW,OAAO,MAAM,gBAAgB,WAAW,IAAI,KAAK,MAAM,YAAY,CAAC,aAAa,GAAG;IAC/F,WAAW,OAAO,MAAM,gBAAgB,WAAW,IAAI,KAAK,MAAM,YAAY,CAAC,aAAa,GAAG;IAC/F,YACE,OAAO,MAAM,eAAe,WACxB,MAAM,aACN,OAAO,MAAM,kBAAkB,WAC7B,MAAM,gBACN;IACR,WAAW,OAAO,MAAM,cAAc,WAAW,MAAM,YAAY;IACnE,mBAAmB,OAAO,MAAM,sBAAsB,WAAW,MAAM,oBAAoB;IAC3F,SAAS,OAAO,IAAI,WAAW,GAAG;IAClC,OAAO,OAAO,SAAS,UAAU,WAAW,QAAQ,QAAQ,KAAA;IAC7D;IACD;SACE;EACN,OAAO,EAAE;;;AAIb,eAAe,mBAGZ;CACD,MAAM,WAAW,KAAK,SAAS,EAAE,aAAa,aAAa,SAAS,aAAa;CACjF,MAAM,cAAc,KAAK,UAAU,eAAe;CAClD,MAAM,aAAa,KAAK,UAAU,UAAU;CAE5C,MAAM,UAAU,MAAM,aAA4B,YAAY;CAE9D,IAAI,UAA2B,EAAE;CACjC,IAAI,WAAW,WAAW,EACxB,IAAI;EACF,MAAM,SAAS,MAAM,QAAQ,WAAW,EACrC,QAAQ,MAAM,EAAE,SAAS,QAAQ,CAAC,CAClC,MAAM,CACN,SAAS,CACT,MAAM,GAAG,GAAG;EACf,WAAW,MAAM,QAAQ,IAAI,MAAM,KAAK,MAAM,aAA4B,KAAK,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,QAC/F,SAAgC,SAAS,KAC3C;SACK;CAKV,OAAO;EAAE;EAAS;EAAS;;AAG7B,eAAsB,oBAA8C;CAClE,MAAM,WAAW,KAAK,SAAS,EAAE,aAAa,aAAa,SAAS,QAAQ;CAC5E,IAAI,CAAC,WAAW,SAAS,EAAE,OAAO,EAAE;CACpC,IAAI;EACF,MAAM,SAAS,MAAM,QAAQ,SAAS,EACnC,QAAQ,MAAM,EAAE,SAAS,QAAQ,CAAC,CAClC,MAAM,CACN,SAAS,CACT,MAAM,GAAG,GAAG;EACf,MAAM,aACJ,MAAM,QAAQ,IACZ,MAAM,IAAI,OAAO,MAAM;GACrB,MAAM,WAAW,KAAK,UAAU,EAAE;GAClC,IAAI;IACF,OAAO;KAAE,MAAM;KAAG,QAAQ,MAAM,KAAK,SAAS,EAAE;KAAS;WACnD;IACN,OAAO;;IAET,CACH,EACD,QAAQ,MAA4C,MAAM,KAAK;EACjE,UAAU,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;EAC3C,QACE,MAAM,QAAQ,IACZ,UAAU,MAAM,GAAG,GAAG,CAAC,IAAI,OAAO,MAAM;GACtC,MAAM,OAAO,MAAM,aAA4B,KAAK,UAAU,EAAE,KAAK,CAAC;GACtE,IAAI,MACF,KAAK,QAAQ,EAAE,KAAK,QAAQ,WAAW,GAAG;GAE5C,OAAO;IACP,CACH,EACD,QAAQ,SAAgC,SAAS,KAAK;SAClD;EACN,OAAO,EAAE;;;AAIb,eAAe,mBAAmB,MAAqC;CACrE,IAAI;EACF,MAAM,WAAW,QAAQ,iBAAiB,KAAK,GAAG,OAAO,KAAA;EACzD,MAAM,WAAW,WAAW,CAAC,UAAU,SAAS,GAAG,EAAE;EACrD,MAAM,CAAC,UAAU,eAAe,MAAM,QAAQ,IAAI,CAChD,SAAS,MAAM;GAAC;GAAM;GAAQ;GAAW;GAAM;GAAU;GAAoC,GAAG;GAAS,EAAE;GACzG,SAAS;GACT,UAAU;GACX,CAAC,EACF,SAAS,MAAM;GAAC;GAAS;GAAQ;GAAW;GAAM;GAAU;GAAoC,GAAG;GAAS,EAAE;GAC5G,SAAS;GACT,UAAU;GACX,CAAC,CACH,CAAC;EAQF,MAAM,SAAS,SAAS,OAAO,MAAM;EACrC,MAAM,YAAY,YAAY,OAAO,MAAM;EAC3C,OAAO;GACL,KAAK,SAAU,KAAK,MAAM,OAAO,GAAiB,EAAE;GACpD,QAAQ,YAAa,KAAK,MAAM,UAAU,GAAiB,EAAE;GAC9D;UACM,KAAK;EACZ,OAAO;GAAE,KAAK,EAAE;GAAE,QAAQ,EAAE;GAAE,UAAU,OAAO,IAAI;GAAE;;;AAIzD,SAAS,iBAAiB,KAAkC;CAC1D,MAAM,OAAO;CACb,MAAM,QAAmB;EACvB,UAAU,EAAE;EACZ,YAAY;EACZ,kBAAkB;EAClB,mBAAmB;EACnB,uBAAuB;EACvB;EACA,SAAS;EACV;CAGD,IAAI,IAAI,aACN,IAAI;EACF,MAAM,SAAS,IAAI,YAAY,UAAU,EAAE,MAAM,CAAC;EAClD,OAAO;GACL,UAAU,OAAO,SAAS,MAAM,GAAG,GAAG;GACtC,YAAY,OAAO,MAAM;GACzB,kBAAkB,OAAO,MAAM;GAC/B,mBAAmB,OAAO,MAAM;GAChC,uBAAuB,OAAO,MAAM;GACpC;GACA,SAAS;GACV;SACK;EACN,OAAO;;CAKX,IAAI;EACF,MAAM,KAAK,IAAI,QAAQ,UAAU;EACjC,MAAM,SAAS,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK,GAAG,OAAO;EAMtD,IAAI,CAJgB,GAAG,QAAQ,4EAA4E,CAAC,KAI5F,EAAE,OAAO;EAsBzB,MAAM,cApBO,GACV,QACC;;;;;;;;yCASD,CACA,IAAI,OAQ4B,CAAC,KAAK,OAAO;GAC9C,SAAS,EAAE;GACX,OAAO,OAAO,EAAE,MAAM;GACtB,aAAa,OAAO,EAAE,YAAY;GAClC,cAAc,OAAO,EAAE,aAAa;GACpC,kBAAkB,OAAO,EAAE,iBAAiB;GAC7C,EAAE;EAEH,OAAO;GACL,UAAU,YAAY,MAAM,GAAG,GAAG;GAClC,YAAY,YAAY,QAAQ,GAAG,MAAM,IAAI,EAAE,OAAO,EAAE;GACxD,kBAAkB,YAAY,QAAQ,GAAG,MAAM,IAAI,EAAE,aAAa,EAAE;GACpE,mBAAmB,YAAY,QAAQ,GAAG,MAAM,IAAI,EAAE,cAAc,EAAE;GACtE,uBAAuB,YAAY,QAAQ,GAAG,MAAM,IAAI,EAAE,kBAAkB,EAAE;GAC9E;GACA,SAAS;GACV;SACK;EACN,OAAO;;;AAIX,eAAsB,mBACpB,KACA,YAC6B;CAC7B,IAAI,CAAC,IAAI,kBACP,OAAO;EAAE,SAAS;EAAO,QAAQ,EAAE;EAAE,QAAQ,EAAE;EAAE;CAEnD,IAAI;EAGF,MAAM,SAAS,0BAFD,cAAe,MAAM,mBAAmB,EAC3C,IAAI,iBAAiB,SACkB,CAAC;EACnD,MAAM,SAAmB,EAAE;EAC3B,KAAK,MAAM,KAAK,QAAQ;GACtB,IAAI,EAAE,WAAW,SAAS,OAAO,KAAK,GAAG,EAAE,QAAQ,qCAAqC;GACxF,IAAI,EAAE,WAAW,YAAY,OAAO,KAAK,GAAG,EAAE,QAAQ,UAAU,EAAE,MAAM,QAAQ,EAAE,CAAC,aAAa;;EAElG,OAAO;GAAE,SAAS;GAAM;GAAQ;GAAQ;SAClC;EACN,OAAO;GAAE,SAAS;GAAO,QAAQ,EAAE;GAAE,QAAQ,EAAE;GAAE;;;AAIrD,SAAgB,oBAAoB,KAA4C;CAC9E,IAAI,CAAC,IAAI,YACP,OAAO;EACL,SAAS;EACT,UAAU;EACV,WAAW;GAAE,SAAS;GAAG,SAAS;GAAG,QAAQ;GAAG;EAChD,SAAS,EAAE;EACX,gBAAgB,EAAE;EACnB;CAEH,IAAI;EACF,MAAM,IAAI,IAAI,WAAW,YAAY;EACrC,MAAM,SAAS,IAAI,WAAW,MAAM;GAAE,SAAS,KAAK,KAAK,GAAG,KAAK,OAAO;GAAM,SAAS;GAAU,OAAO;GAAG,CAAC;EAC5G,OAAO;GACL,SAAS;GACT,UAAU,EAAE;GACZ,WAAW,EAAE;GACb,SAAS,EAAE;GACX,gBAAgB,OAAO,KAAK,OAAO;IACjC,WAAW,EAAE;IACb,SAAS,EAAE;IACX,QAAQ,EAAE;IACV,QAAQ,EAAE;IACV,OAAO,EAAE;IACV,EAAE;GACJ;SACK;EACN,OAAO;GACL,SAAS;GACT,UAAU;GACV,WAAW;IAAE,SAAS;IAAG,SAAS;IAAG,QAAQ;IAAG;GAChD,SAAS,EAAE;GACX,gBAAgB,EAAE;GACnB;;;;AASL,SAAS,oBAAoB,MAAyD;CACpF,IAAI;EACF,MAAM,EAAE,cAAc,WAAW,QAAQ,cAAc;EAEvD,OAAO,IADQ,OAAO,MAAM,EAAE,UAAU,MAAM,CACrC;SACH;EACN,OAAO;;;;AAKX,eAAsB,yBAAyB,KAAmD;CAChG,MAAM,UAAU,IAAI;CACpB,MAAM,aAAa,QAAQ,OAAO;CAClC,MAAM,eAAe,QAAQ,cAAc;CAG3C,MAAM,OAAO,oBAAoB,IAAI,mBAAmB;CACxD,IAAI,kBAAkB;CACtB,IAAI,gBAAgB;CACpB,IAAI,cAAc;CAClB,IAAI,gBAAgB;CACpB,IAAI,MAAM;EACR,IAAI;GAIF,kBAHW,KAAK,QAAQ,oEAAoE,CAAC,KAGzE,EAAE,OAAO;UACvB;EAGR,IAAI;GAEF,gBADW,KAAK,QAAQ,6CAA6C,CAAC,KACpD,EAAE,OAAO;UACrB;EAGR,IAAI;GAEF,cADW,KAAK,QAAQ,qCAAqC,CAAC,KAC9C,EAAE,OAAO;UACnB;EAGR,IAAI;GAEF,gBADW,KAAK,QAAQ,uCAAuC,CAAC,KAC9C,EAAE,OAAO;UACrB;EAGR,IAAI;GACF,KAAK,OAAO;UACN;;CAKV,MAAM,qBAAqB;EACzB,IAAI;GACF,IAAI,CAAC,IAAI,YAAY,OAAO;GAC5B,OAAO,IAAI,WAAW,KAAK,EAAE,CAAC,CAAC;UACzB;GACN,OAAO;;KAEP;CACJ,MAAM,yBAAyB;EAC7B,IAAI;GACF,OAAO,QAAQ,iBAAiB;UAC1B;GACN,OAAO;;KAEP;CACJ,MAAM,oBAAoB;EACxB,IAAI;GACF,OAAO,QAAQ,YAAY;UACrB;GACN,OAAO;;KAEP;CACJ,IAAI,cAAc;CAClB,IAAI;EACF,cAAc,MAAM,IAAI,SAAS,OAAO;SAClC;CAIR,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YAAY,QAAQ,0BAA0B;EAC9C,QAAQ,QAAQ,sBAAsB;EACtC,cAAc,QAAQ,4BAA4B;EAClD,UAAU,QAAQ,wBAAwB;EAC1C,aAAa,QAAQ,aAAa;EACnC;;;AAIH,SAAgB,4BAA4B,KAAuB,QAAQ,IAA2B;CACpG,IAAI;EACF,MAAM,OAAO,oBAAoB,IAAI,mBAAmB;EACxD,IAAI,CAAC,MAAM,OAAO,EAAE;EACpB,IAAI;GAIF,OAHa,KAAK,QAAQ,yDAAyD,CAAC,IAAI,MAG7E,CAAC,KAAK,OAAO;IACtB,IAAI,OAAO,EAAE,MAAM,GAAG;IACtB,OAAO,OAAO,EAAE,SAAS,GAAG;IAC5B,SAAS,OAAO,EAAE,WAAW,GAAG;IAChC,WAAW,OAAO,EAAE,aAAa,EAAE;IACnC,UAAU,EAAE,YAAY,OAAO,OAAO,EAAE,SAAS,GAAG,KAAA;IACpD,SAAS,EAAE,WAAW,OAAO,OAAO,EAAE,QAAQ,GAAG,KAAA;IACjD,SAAS,EAAE,YAAY,OAAO,OAAO,EAAE,SAAS,GAAG,KAAA;IACnD,WAAW,EAAE,cAAc,OAAO,OAAO,EAAE,WAAW,GAAG,KAAA;IACzD,YAAY,OAAO,EAAE,cAAc,GAAI;IACvC,aAAa;KACX,IAAI;MACF,OAAO,KAAK,MAAM,OAAO,EAAE,QAAQ,KAAK,CAAC;aACnC;MACN,OAAO,EAAE;;QAET;IACL,EAAE;YACK;GACR,IAAI;IACF,KAAK,OAAO;WACN;;SAIJ;EACN,OAAO,EAAE;;;;AAKb,SAAgB,8BAA8B,KAAuB,QAAQ,IAA6B;CACxG,IAAI;EACF,IAAI,CAAC,IAAI,cAAc,OAAO,EAAE;EAChC,OAAO,IAAI,aAAa,WAAW,OAAO,MAAM,CAAC,KAAK,OAAO;GAC3D,IAAI,EAAE;GACN,WAAW,EAAE;GACb,aAAa,EAAE;GACf,WAAW,EAAE;GACb,KAAK,EAAE;GACP,eAAe,EAAE;GACjB,WAAW,EAAE;GACd,EAAE;SACG;EACN,OAAO,EAAE;;;;AAKb,SAAgB,0BAA0B,KAA4C;CACpF,IAAI;EACF,IAAI,CAAC,IAAI,YAAY,OAAO,EAAE;EAC9B,OAAO,IAAI,WAAW,KAAK,EAAE,CAAC,CAAC,KAAK,WAAW;GAC7C,IAAI,MAAM;GACV,OAAO,MAAM;GACb,QAAQ,MAAM;GACd,UAAU,MAAM;GAChB,UAAU,MAAM;GAChB,WAAW,MAAM;GACjB,KAAK,MAAM;GACX,MAAM,MAAM;GACZ,YAAY,MAAM;GAClB,YAAY,MAAM;GAClB,YAAY,MAAM;GAClB,WAAW,MAAM;GACjB,WAAW,MAAM;GAClB,EAAE;SACG;EACN,OAAO,EAAE;;;;AAKb,SAAgB,6BAA6B,KAAuB,QAAQ,KAA6B;CACvG,IAAI;EACF,IAAI,CAAC,IAAI,eAAe,OAAO,EAAE;EACjC,MAAM,SAAS,IAAI,cAAc,KAAK,EAAE,OAAO,CAAC;EAChD,MAAM,WAAW,IAAI,cAAc,YAAY,EAAE,OAAO,IAAI,CAAC;EAa7D,OAZuC,OAAO,KAAK,OAAO;GACxD,IAAI,EAAE;GACN,MAAM,EAAE;GACR,cAAc,EAAE;GAChB,SAAS,EAAE;GACX,WAAW,EAAE;GACb,YAAY,EAAE;GACd,aACE,SAAS,MAAM,MAAM,KAAK,UAAU,EAAE,aAAa,KAAK,KAAK,UAAU,EAAE,aAAa,CAAC,EAAE,eAAe;GAC1G,WAAW,EAAE;GACb,WAAW,EAAE;GACd,EACY;SACP;EACN,OAAO,EAAE;;;;AAKb,SAAgB,0BAA0B,KAA4C;CACpF,IAAI;EACF,IAAI,CAAC,IAAI,YAAY,OAAO,EAAE;EAC9B,OAAO,IAAI,WAAW,KAAK,EAAE,CAAC,CAAC,KAAK,OAAO;GACzC,IAAI,EAAE;GACN,MAAM,EAAE;GACR,QAAQ,EAAE;GACV,MAAM,EAAE;GACR,YAAY,EAAE;GACd,WAAW,EAAE;GACb,KAAK,OAAO,EAAE,IAAI;GAClB,WAAW,EAAE;GACd,EAAE;SACG;EACN,OAAO,EAAE;;;;AAKb,SAAgB,4BAA4B,KAAuB,QAAQ,KAAiC;CAC1G,IAAI;EACF,IAAI,CAAC,IAAI,mBAAmB,OAAO,EAAE;EAErC,OADiB,IAAI,kBAAkB,oBAAoB,CAAC,MAAM,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,MAAM,CAAC,CAAC,CACnG,CAAC,KAAK,OAAO;GAC1B,QAAQ,EAAE;GACV,eAAe,EAAE;GACjB,YAAY,EAAE,cAAc;GAC5B,YAAY,EAAE,cAAc;GAC5B,kBAAkB,EAAE,oBAAoB;GACxC,SAAS,EAAE;GACZ,EAAE;SACG;EACN,OAAO,EAAE;;;;AAKb,SAAgB,4BAA4B,KAAuB,QAAQ,IAA0B;CACnG,IAAI;EASF,OARY,IAAI,QAAQ,UACR,CACb,QACC;;oDAGD,CACA,IAAI,MACI,CAAC,KAAK,MAAM;GACrB,IAAI,OAAiB,EAAE;GACvB,IAAI;IACF,OAAO,CAAC,GAAG,IAAI,IAAI,OAAO,EAAE,QAAQ,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;WAC9C;GACR,IAAI,MAAgB,EAAE;GACtB,IAAI;IACF,MAAM,UAAU,OAAO,EAAE,OAAO,GAAG,CAAC,MAAM,IAAI;IAC9C,MAAM,CAAC,GAAG,IAAI,IAAI,QAAQ,OAAO,QAAQ,CAAC,CAAC;WACrC;GACR,OAAO;IACL,QAAQ,OAAO,EAAE,UAAU,GAAG;IAC9B,WAAW,OAAO,EAAE,OAAO,EAAE;IAC7B,YAAY;IACZ,MAAM;IACN,aAAa,OAAO,EAAE,gBAAgB,EAAE;IACzC;IACD;SACI;EACN,OAAO,EAAE;;;;AAKb,SAAgB,8BAA8B,KAAuB,QAA+C;CAClH,IAAI;EACF,IAAI,CAAC,IAAI,mBAAmB,OAAO;EAGnC,MAAM,QAAQ,IAAI,kBAAkB,cAAc,OAAO;EACzD,OAAO;GACL,QAAQ,MAAM,KAAK;GACnB,MAAM,MAAM,KAAK;GACjB,YAAY,MAAM,KAAK;GACvB,mBAAmB,MAAM,OAAO;GAChC,YAAY,MAAM,OAAO;GACzB,OAAO,MAAM,MAAM,KAAK,OAAO;IAC7B,UAAU,EAAE;IACZ,YAAY,EAAE;IACd,UAAU,EAAE;IACZ,YAAY,EAAE;IACd,WAAW,EAAE;IACd,EAAE;GACJ;SACK;EACN,OAAO;;;;AAKX,SAAgB,yBAAyB,KAAuB,QAAQ,KAA2B;CACjG,IAAI;EACF,MAAM,OAAO,oBAAoB,IAAI,mBAAmB;EACxD,IAAI,CAAC,MAAM,OAAO,EAAE;EACpB,IAAI;GAEF,OADa,KAAK,QAAQ,qCAAqC,CAAC,IAAI,MACzD,CAAC,KAAK,OAAO;IACtB,MAAM,OAAO,EAAE,kBAAkB,GAAG;IACpC,IAAI,OAAO,EAAE,kBAAkB,GAAG;IAClC,MAAM,OAAO,EAAE,aAAa,GAAG;IAC/B,UAAU,OAAO,EAAE,YAAY,EAAE;IAClC,EAAE;YACK;GACR,IAAI;IACF,KAAK,OAAO;WACN;;SAIJ;EACN,OAAO,EAAE;;;;AAKb,SAAgB,kBACd,KACA,QACA,QACA,MACkC;CAClC,IAAI;EACF,MAAM,UAAU,IAAI;EACpB,MAAM,OAAO,QAAQ,QAAQ,OAAO;EACpC,IAAI,CAAC,MAAM,OAAO;GAAE,IAAI;GAAO,SAAS,mBAAmB;GAAU;EAErE,IAAI,WAAW,UAAU;GACvB,IAAI,CAAC,IAAI,mBAAmB,OAAO;IAAE,IAAI;IAAO,SAAS;IAAoC;GAC7F,MAAM,aAAc,KAAK,cAA8C;GACvE,IAAI,kBAAkB,OAAO,QAAQ,KAAK,MAAM,WAAW;GAC3D,yBAAyB,IAAI;GAC7B,OAAO;IAAE,IAAI;IAAM,SAAS,QAAQ,OAAO,eAAe;IAAc;;EAI1E,IAAI;GAEF,IAAI,CADO,QAAQ,UAAU,QAAQ,KAC9B,EAAE,OAAO;IAAE,IAAI;IAAO,SAAS,4BAA4B;IAAU;UACtE;GACN,OAAO;IAAE,IAAI;IAAO,SAAS,yBAAyB;IAAU;;EAElE,yBAAyB,IAAI;EAC7B,OAAO;GAAE,IAAI;GAAM,SAAS,QAAQ,OAAO;GAAa;SAClD;EACN,OAAO;GAAE,IAAI;GAAO,SAAS;GAAsB;;;AAIvD,eAAsB,cAAc,KAAiD;CACnF,MAAM,CAAC,QAAQ,UAAU,WAAW,OAAO,OAAO,MAAM,QAAQ,IAAI;EAClE,mBAAmB,IAAI;EACvB,iBAAiB;EACjB,kBAAkB;EAClB,mBAAmB;EACnB,mBAAmB,IAAI,QAAQ;EAChC,CAAC;CACF,MAAM,cAAc,MAAM,mBAAmB,KAAK,MAAM;CACxD,OAAO;EACL,8BAAa,IAAI,MAAM,EAAC,aAAa;EACrC;EACA;EACA;EACA;EACA;EACA,OAAO,iBAAiB,IAAI;EAC5B,OAAO,oBAAoB,IAAI;EAC/B;EACD"}
|
|
1
|
+
{"version":3,"file":"collectors.js","names":["execFileCb"],"sources":["../../../routes/dashboard/collectors.ts"],"sourcesContent":["/**\n * Mission Control Dashboard — Issue #309\n *\n * Serves a web dashboard via a small HTTP server registered as a plugin service.\n * Routes:\n * GET / — HTML dashboard (vanilla JS/CSS, no framework)\n * GET /api/status — JSON data for all dashboard sections\n */\n\nimport { existsSync } from \"node:fs\";\nimport { readdir, stat } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { type AgentHealthView, mergeAgentHealthDashboard } from \"../../backends/agent-health-store.js\";\nimport type { AuditStore } from \"../../backends/audit-store.js\";\nimport type { EdictStore } from \"../../backends/edict-store.js\";\nimport type { FactsDB } from \"../../backends/facts-db.js\";\nimport type { IssueStore } from \"../../backends/issue-store.js\";\nimport type { NarrativesDB } from \"../../backends/narratives-db.js\";\nimport type { VectorDB } from \"../../backends/vector-db.js\";\nimport type { WorkflowStore } from \"../../backends/workflow-store.js\";\nimport type { ProvenanceService } from \"../../services/provenance.js\";\nimport type { VerificationStore } from \"../../services/verification-store.js\";\nimport { getDirSize, getFileSizeAsync, readJsonFile } from \"../../utils/fs.js\";\nimport { pluginLogger } from \"../../utils/logger.js\";\nimport { isValidGhRepoArg } from \"../../utils/gh-repo-arg.js\";\nimport { execFile as execFileCb } from \"../../utils/process-runner.js\";\n\nconst execFile = promisify(execFileCb);\nconst require = createRequire(import.meta.url);\n\nconst _MAX_DASHBOARD_JSON_BODY_BYTES = 64 * 1024;\nconst VERIFIED_FACT_SET_TTL_MS = 5000;\nconst verifiedFactIdCacheByStore = new WeakMap<VerificationStore, { at: number; ids: Set<string> }>();\n\nfunction clearVerifiedFactIdCache(ctx: DashboardContext): void {\n const store = ctx.verificationStore;\n if (!store) return;\n verifiedFactIdCacheByStore.delete(store);\n}\n\nexport function getVerifiedFactIdSet(ctx: DashboardContext): Set<string> {\n const store = ctx.verificationStore;\n if (!store) return new Set();\n const now = Date.now();\n const cached = verifiedFactIdCacheByStore.get(store);\n if (cached && now - cached.at < VERIFIED_FACT_SET_TTL_MS) {\n return cached.ids;\n }\n try {\n const ids = new Set<string>();\n for (const v of store.listLatestVerified()) {\n ids.add(v.factId);\n }\n verifiedFactIdCacheByStore.set(store, { at: now, ids });\n return ids;\n } catch {\n return new Set();\n }\n}\n\nexport function parseUrlPathSegment(input: string): string | null {\n try {\n const trimmed = input.trim();\n if (!trimmed) return null;\n return decodeURIComponent(trimmed);\n } catch {\n return null;\n }\n}\n\nexport function readJsonBody(\n req: import(\"node:http\").IncomingMessage,\n maxBytes: number,\n): Promise<Record<string, unknown>> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let sizeBytes = 0;\n let settled = false;\n\n const cleanup = () => {\n req.off(\"data\", onData);\n req.off(\"end\", onEnd);\n req.off(\"error\", onError);\n };\n\n const resolveOnce = (value: Record<string, unknown>) => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(value);\n };\n\n const rejectOnce = (err: unknown) => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(err);\n };\n\n const onData = (chunk: Buffer | string) => {\n const chunkBytes = Buffer.isBuffer(chunk) ? chunk.byteLength : Buffer.byteLength(chunk, \"utf-8\");\n if (sizeBytes + chunkBytes > maxBytes) {\n rejectOnce(new Error(\"Request body too large\"));\n try {\n req.resume();\n } catch {\n /* ignore */\n }\n return;\n }\n sizeBytes += chunkBytes;\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, \"utf-8\"));\n };\n\n const onEnd = () => {\n if (chunks.length === 0) return resolveOnce({});\n try {\n const parsed = JSON.parse(Buffer.concat(chunks).toString(\"utf-8\"));\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return resolveOnce({});\n resolveOnce(parsed as Record<string, unknown>);\n } catch (err) {\n rejectOnce(err);\n }\n };\n\n const onError = (err: unknown) => {\n rejectOnce(err);\n };\n\n req.on(\"data\", onData);\n req.on(\"end\", onEnd);\n req.on(\"error\", onError);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface DashboardContext {\n factsDb: FactsDB;\n vectorDb: VectorDB;\n resolvedSqlitePath: string;\n resolvedLancePath: string;\n /** Optional owner/repo for GitHub queries (e.g. \"markus-lassfolk/openclaw-hybrid-memory\") */\n gitRepo?: string;\n /** Optional plugin config exposed to GraphQL context. */\n cfg?: unknown;\n /** Optional embedding service exposed to GraphQL context. */\n embeddings?: unknown;\n /** Optional embedding registry exposed to GraphQL context. */\n embeddingRegistry?: unknown;\n /** Optional CostTracker instance — delegates cost stats to the established abstraction. */\n costTracker?: import(\"../../backends/cost-tracker.js\").CostTracker | null;\n /** Optional logger for structured logging of server errors */\n logger?: { error?: (msg: string) => void };\n /** Cross-agent audit trail (Issue #790). */\n auditStore?: AuditStore | null;\n /** Per-agent health store (Issue #789). */\n agentHealthStore?: import(\"../../backends/agent-health-store.js\").AgentHealthStore | null;\n /** Edict store for verified ground-truth facts. */\n edictStore?: EdictStore | null;\n /** Verification store for critical facts. */\n verificationStore?: VerificationStore | null;\n /** Issue store for tracked problems. */\n issueStore?: IssueStore | null;\n /** Workflow store for tool-sequence patterns. */\n workflowStore?: WorkflowStore | null;\n /** Narratives store for session summaries. */\n narrativesDb?: NarrativesDB | null;\n /** Provenance service for fact-to-source tracing. */\n provenanceService?: ProvenanceService | null;\n /** Mirrors `graph.hubDegreeCap` for dashboard graph recall (Issue #1192). */\n graphHubDegreeCap?: number | null;\n /** Mirrors `graph.hubScorePenalty` for dashboard graph recall (#1192). */\n graphHubScorePenalty?: number | null;\n}\n\ninterface MemoryStats {\n activeFacts: number;\n expiredFacts: number;\n vectorCount: number;\n sqliteSizeBytes: number;\n lanceSizeBytes: number;\n totalSizeBytes: number;\n}\n\ninterface CronJobStatus {\n id: string;\n name: string;\n schedule: string;\n enabled: boolean;\n lastRunAt: string | null;\n nextRunAt: string | null;\n lastStatus: string | null;\n lastError: string | null;\n consecutiveErrors: number;\n agentId: string;\n model?: string;\n}\n\ninterface TaskQueueItem {\n issue?: number;\n title?: string;\n branch?: string;\n pid?: number;\n started?: string;\n status?: string;\n completed?: string;\n exit_code?: number;\n details?: string;\n}\n\ninterface ForgeTaskItem {\n agent?: string;\n task: string;\n workdir?: string;\n pid?: number;\n started_at?: string;\n status?: string;\n}\n\ninterface GitActivity {\n prs: Array<{\n number: number;\n title: string;\n state: string;\n url: string;\n createdAt: string;\n }>;\n issues: Array<{\n number: number;\n title: string;\n state: string;\n url: string;\n createdAt: string;\n }>;\n gitError?: string;\n}\n\ninterface CostRow {\n feature: string;\n calls: number;\n inputTokens: number;\n outputTokens: number;\n estimatedCostUsd: number;\n}\n\ninterface CostStats {\n features: CostRow[];\n totalCalls: number;\n totalInputTokens: number;\n totalOutputTokens: number;\n totalEstimatedCostUsd: number;\n days: number;\n enabled: boolean;\n}\n\ninterface AgentHealthPayload {\n enabled: boolean;\n agents: AgentHealthView[];\n alerts: string[];\n}\n\ninterface AuditSummaryPayload {\n enabled: boolean;\n total24h: number;\n byOutcome: { success: number; partial: number; failed: number };\n byAgent: Record<string, number>;\n recentFailures: Array<{\n timestamp: number;\n agentId: string;\n action: string;\n target: string | null;\n error: string | null;\n }>;\n}\n\ninterface DashboardStatus {\n generatedAt: string;\n memory: MemoryStats;\n cronJobs: CronJobStatus[];\n taskQueue: {\n current: TaskQueueItem | null;\n history: TaskQueueItem[];\n };\n forge: ForgeTaskItem[];\n git: GitActivity;\n costs: CostStats;\n audit: AuditSummaryPayload;\n agentHealth: AgentHealthPayload;\n}\n\n// ---------------------------------------------------------------------------\n// Memory Viewer types (Issue #1023)\n// ---------------------------------------------------------------------------\n\ninterface MemoryViewerStats {\n totalFacts: number;\n totalExpired: number;\n totalSuperseded: number;\n totalVerified: number;\n totalEdicts: number;\n totalIssues: number;\n totalProcedures: number;\n totalEpisodes: number;\n totalLinks: number;\n vectorCount: number;\n byCategory: Record<string, number>;\n byTier: Record<string, number>;\n byDecayClass: Record<string, number>;\n bySource: Record<string, number>;\n entityCount: number;\n}\n\ninterface MemoryViewerEpisode {\n id: string;\n event: string;\n outcome: string;\n timestamp: number;\n duration?: number;\n context?: string;\n agentId?: string;\n sessionId?: string;\n importance: number;\n tags: string[];\n}\n\nexport interface MemoryViewerFact {\n id: string;\n text: string;\n why?: string | null;\n category: string;\n importance: number;\n entity: string | null;\n key: string | null;\n value: string | null;\n source: string;\n createdAt: number;\n decayClass: string;\n expiresAt: number | null;\n confidence: number;\n summary?: string | null;\n tags: string[];\n supersededAt?: number | null;\n supersededBy?: string | null;\n verified?: boolean;\n edict?: boolean;\n scope?: string;\n provenanceSession?: string | null;\n reinforcedCount?: number;\n}\n\ninterface MemoryViewerEntity {\n entity: string;\n factCount: number;\n categories: string[];\n tags: string[];\n lastUpdated: number;\n}\n\ninterface MemoryViewerEdict {\n id: string;\n text: string;\n source?: string | null;\n tags: string[];\n verifiedAt: number | null;\n expiresAt: string | null;\n ttl: string;\n createdAt: number;\n}\n\ninterface MemoryViewerIssue {\n id: string;\n title: string;\n status: string;\n severity: string;\n symptoms: string[];\n rootCause?: string | null;\n fix?: string | null;\n tags: string[];\n detectedAt: string;\n resolvedAt?: string | null;\n verifiedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface MemoryViewerWorkflow {\n id: string;\n goal: string;\n toolSequence: string[];\n outcome: string;\n toolCount: number;\n durationMs: number;\n successRate: number;\n sessionId: string;\n createdAt: string;\n}\n\ninterface MemoryViewerNarrative {\n id: string;\n sessionId: string;\n periodStart: number;\n periodEnd: number;\n tag: string;\n narrativeText: string;\n createdAt: number;\n}\n\ninterface MemoryViewerVerification {\n factId: string;\n canonicalText: string;\n verifiedAt: string;\n verifiedBy: string;\n nextVerification: string | null;\n version: number;\n}\n\ninterface MemoryViewerProvenance {\n factId: string;\n text: string;\n confidence: number;\n provenanceSession?: string | null;\n sourceTurn?: number | null;\n edges: Array<{\n edgeType: string;\n sourceType: string;\n sourceId: string;\n sourceText?: string | null;\n createdAt: string;\n }>;\n}\n\ninterface MemoryViewerLinks {\n from: string;\n to: string;\n type: string;\n strength: number;\n}\n\n// ---------------------------------------------------------------------------\n// Data collection helpers\n// ---------------------------------------------------------------------------\n\n/** Cached LanceDB dir size keyed by resolved path to avoid repeated traversal on every poll */\nconst _lanceSizeCache = new Map<string, { size: number; ts: number }>();\nconst _lanceInFlight = new Map<string, Promise<number>>();\nconst LANCE_CACHE_TTL_MS = 300_000; // 5 minutes\n\nasync function collectMemoryStats(ctx: DashboardContext): Promise<MemoryStats> {\n const activeFacts = ctx.factsDb.count();\n const expiredFacts = ctx.factsDb.countExpired();\n let vectorCount = 0;\n try {\n vectorCount = await ctx.vectorDb.count();\n } catch {\n /* non-fatal */\n }\n const sqliteSize = await getFileSizeAsync(ctx.resolvedSqlitePath);\n const sqliteWalSize = await getFileSizeAsync(`${ctx.resolvedSqlitePath}-wal`);\n const sqliteShmSize = await getFileSizeAsync(`${ctx.resolvedSqlitePath}-shm`);\n const sqliteSizeBytes = sqliteSize + sqliteWalSize + sqliteShmSize;\n\n // Use cached LanceDB size to avoid blocking on large directory traversals.\n // TOCTOU guard: write to cache inside .then() — before .finally() clears the\n // in-flight entry — so any concurrent caller that sees no in-flight promise\n // will always find the cache already populated.\n const cachedEntry = _lanceSizeCache.get(ctx.resolvedLancePath);\n const now = Date.now();\n if (!cachedEntry || now - cachedEntry.ts > LANCE_CACHE_TTL_MS) {\n let inFlightPromise = _lanceInFlight.get(ctx.resolvedLancePath);\n if (!inFlightPromise) {\n inFlightPromise = getDirSize(ctx.resolvedLancePath)\n .then((size) => {\n _lanceSizeCache.set(ctx.resolvedLancePath, { size, ts: Date.now() });\n return size;\n })\n .finally(() => {\n _lanceInFlight.delete(ctx.resolvedLancePath);\n });\n _lanceInFlight.set(ctx.resolvedLancePath, inFlightPromise);\n }\n try {\n await inFlightPromise;\n } catch (err) {\n pluginLogger.error(\n `[dashboard-server] lance size traversal failed for ${ctx.resolvedLancePath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n const lanceSizeBytes = _lanceSizeCache.get(ctx.resolvedLancePath)?.size ?? 0;\n\n return {\n activeFacts,\n expiredFacts,\n vectorCount,\n sqliteSizeBytes,\n lanceSizeBytes,\n totalSizeBytes: sqliteSizeBytes + lanceSizeBytes,\n };\n}\n\nasync function collectCronJobs(): Promise<CronJobStatus[]> {\n const openclawDir = join(homedir(), \".openclaw\");\n const cronStorePath = join(openclawDir, \"cron\", \"jobs.json\");\n if (!existsSync(cronStorePath)) return [];\n try {\n const store = await readJsonFile<{ jobs?: unknown[] }>(cronStorePath);\n if (!store || !Array.isArray(store.jobs)) return [];\n return store.jobs\n .filter((j): j is Record<string, unknown> => typeof j === \"object\" && j !== null)\n .map((job) => {\n const state = (typeof job.state === \"object\" && job.state !== null ? job.state : {}) as Record<string, unknown>;\n const schedule = job.schedule as Record<string, unknown> | undefined;\n const payload = job.payload as Record<string, unknown> | undefined;\n return {\n id: String(job.id ?? \"\"),\n name: String(job.name ?? \"\"),\n schedule: typeof schedule?.expr === \"string\" ? schedule.expr : \"\",\n enabled: job.enabled !== false,\n lastRunAt: typeof state.lastRunAtMs === \"number\" ? new Date(state.lastRunAtMs).toISOString() : null,\n nextRunAt: typeof state.nextRunAtMs === \"number\" ? new Date(state.nextRunAtMs).toISOString() : null,\n lastStatus:\n typeof state.lastStatus === \"string\"\n ? state.lastStatus\n : typeof state.lastRunStatus === \"string\"\n ? state.lastRunStatus\n : null,\n lastError: typeof state.lastError === \"string\" ? state.lastError : null,\n consecutiveErrors: typeof state.consecutiveErrors === \"number\" ? state.consecutiveErrors : 0,\n agentId: String(job.agentId ?? \"\"),\n model: typeof payload?.model === \"string\" ? payload.model : undefined,\n };\n });\n } catch {\n return [];\n }\n}\n\nasync function collectTaskQueue(): Promise<{\n current: TaskQueueItem | null;\n history: TaskQueueItem[];\n}> {\n const stateDir = join(homedir(), \".openclaw\", \"workspace\", \"state\", \"task-queue\");\n const currentPath = join(stateDir, \"current.json\");\n const historyDir = join(stateDir, \"history\");\n\n const current = await readJsonFile<TaskQueueItem>(currentPath);\n\n let history: TaskQueueItem[] = [];\n if (existsSync(historyDir)) {\n try {\n const files = (await readdir(historyDir))\n .filter((f) => f.endsWith(\".json\"))\n .sort()\n .reverse()\n .slice(0, 10);\n history = (await Promise.all(files.map((f) => readJsonFile<TaskQueueItem>(join(historyDir, f))))).filter(\n (item): item is TaskQueueItem => item !== null,\n );\n } catch {\n /* non-fatal */\n }\n }\n\n return { current, history };\n}\n\nexport async function collectForgeState(): Promise<ForgeTaskItem[]> {\n const forgeDir = join(homedir(), \".openclaw\", \"workspace\", \"state\", \"forge\");\n if (!existsSync(forgeDir)) return [];\n try {\n const files = (await readdir(forgeDir))\n .filter((f) => f.endsWith(\".json\"))\n .sort()\n .reverse()\n .slice(0, 50);\n const withMtime = (\n await Promise.all(\n files.map(async (f) => {\n const fullPath = join(forgeDir, f);\n try {\n return { name: f, mtime: (await stat(fullPath)).mtimeMs };\n } catch {\n return null;\n }\n }),\n )\n ).filter((e): e is { name: string; mtime: number } => e !== null);\n withMtime.sort((a, b) => b.mtime - a.mtime);\n return (\n await Promise.all(\n withMtime.slice(0, 20).map(async (e) => {\n const item = await readJsonFile<ForgeTaskItem>(join(forgeDir, e.name));\n if (item) {\n item.agent = e.name.replace(/\\.json$/, \"\");\n }\n return item;\n }),\n )\n ).filter((item): item is ForgeTaskItem => item !== null);\n } catch {\n return [];\n }\n}\n\nasync function collectGitActivity(repo?: string): Promise<GitActivity> {\n try {\n const safeRepo = repo && isValidGhRepoArg(repo) ? repo : undefined;\n const repoArgs = safeRepo ? [\"--repo\", safeRepo] : [];\n const [prResult, issueResult] = await Promise.all([\n execFile(\"gh\", [\"pr\", \"list\", \"--limit\", \"10\", \"--json\", \"number,title,state,url,createdAt\", ...repoArgs], {\n timeout: 8000,\n encoding: \"utf-8\",\n }),\n execFile(\"gh\", [\"issue\", \"list\", \"--limit\", \"10\", \"--json\", \"number,title,state,url,createdAt\", ...repoArgs], {\n timeout: 8000,\n encoding: \"utf-8\",\n }),\n ]);\n type GitItem = {\n number: number;\n title: string;\n state: string;\n url: string;\n createdAt: string;\n };\n const prJson = prResult.stdout.trim();\n const issueJson = issueResult.stdout.trim();\n return {\n prs: prJson ? (JSON.parse(prJson) as GitItem[]) : [],\n issues: issueJson ? (JSON.parse(issueJson) as GitItem[]) : [],\n };\n } catch (err) {\n return { prs: [], issues: [], gitError: String(err) };\n }\n}\n\nfunction collectCostStats(ctx: DashboardContext): CostStats {\n const days = 7;\n const empty: CostStats = {\n features: [],\n totalCalls: 0,\n totalInputTokens: 0,\n totalOutputTokens: 0,\n totalEstimatedCostUsd: 0,\n days,\n enabled: false,\n };\n\n // Prefer the established CostTracker abstraction when available to avoid duplicating SQL.\n if (ctx.costTracker) {\n try {\n const report = ctx.costTracker.getReport({ days });\n return {\n features: report.features.slice(0, 20),\n totalCalls: report.total.calls,\n totalInputTokens: report.total.inputTokens,\n totalOutputTokens: report.total.outputTokens,\n totalEstimatedCostUsd: report.total.estimatedCostUsd,\n days,\n enabled: true,\n };\n } catch {\n return empty;\n }\n }\n\n // Fallback: query the DB directly (e.g. in tests where CostTracker is not injected).\n try {\n const db = ctx.factsDb.getRawDb();\n const cutoff = Math.floor(Date.now() / 1000) - days * 86400;\n\n const tableExists = db.prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name='llm_cost_log'\").get() as\n | { name: string }\n | undefined;\n\n if (!tableExists) return empty;\n\n const rows = db\n .prepare(\n `SELECT feature,\n COUNT(*) AS calls,\n COALESCE(SUM(input_tokens), 0) AS inputTokens,\n COALESCE(SUM(output_tokens), 0) AS outputTokens,\n COALESCE(SUM(estimated_cost_usd), 0) AS estimatedCostUsd\n FROM llm_cost_log\n WHERE timestamp >= ?\n GROUP BY feature\n ORDER BY estimatedCostUsd DESC`,\n )\n .all(cutoff) as Array<{\n feature: string;\n calls: number;\n inputTokens: number;\n outputTokens: number;\n estimatedCostUsd: number;\n }>;\n\n const allFeatures: CostRow[] = rows.map((r) => ({\n feature: r.feature,\n calls: Number(r.calls),\n inputTokens: Number(r.inputTokens),\n outputTokens: Number(r.outputTokens),\n estimatedCostUsd: Number(r.estimatedCostUsd),\n }));\n\n return {\n features: allFeatures.slice(0, 20),\n totalCalls: allFeatures.reduce((s, r) => s + r.calls, 0),\n totalInputTokens: allFeatures.reduce((s, r) => s + r.inputTokens, 0),\n totalOutputTokens: allFeatures.reduce((s, r) => s + r.outputTokens, 0),\n totalEstimatedCostUsd: allFeatures.reduce((s, r) => s + r.estimatedCostUsd, 0),\n days,\n enabled: true,\n };\n } catch {\n return empty;\n }\n}\n\nexport async function collectAgentHealth(\n ctx: DashboardContext,\n forgeState?: ForgeTaskItem[],\n): Promise<AgentHealthPayload> {\n if (!ctx.agentHealthStore) {\n return { enabled: false, agents: [], alerts: [] };\n }\n try {\n const forge = forgeState ?? (await collectForgeState());\n const db = ctx.agentHealthStore.listAll();\n const agents = mergeAgentHealthDashboard(forge, db);\n const alerts: string[] = [];\n for (const a of agents) {\n if (a.status === \"stale\") alerts.push(`${a.agentId}: no activity > 4h — check dispatch`);\n if (a.status === \"degraded\") alerts.push(`${a.agentId}: score ${a.score.toFixed(0)} (degraded)`);\n }\n return { enabled: true, agents, alerts };\n } catch {\n return { enabled: false, agents: [], alerts: [] };\n }\n}\n\nexport function collectAuditSummary(ctx: DashboardContext): AuditSummaryPayload {\n if (!ctx.auditStore) {\n return {\n enabled: false,\n total24h: 0,\n byOutcome: { success: 0, partial: 0, failed: 0 },\n byAgent: {},\n recentFailures: [],\n };\n }\n try {\n const s = ctx.auditStore.summary24h();\n const failed = ctx.auditStore.query({ sinceMs: Date.now() - 24 * 3600 * 1000, outcome: \"failed\", limit: 8 });\n return {\n enabled: true,\n total24h: s.total,\n byOutcome: s.byOutcome,\n byAgent: s.byAgent,\n recentFailures: failed.map((r) => ({\n timestamp: r.timestamp,\n agentId: r.agentId,\n action: r.action,\n target: r.target,\n error: r.error,\n })),\n };\n } catch {\n return {\n enabled: false,\n total24h: 0,\n byOutcome: { success: 0, partial: 0, failed: 0 },\n byAgent: {},\n recentFailures: [],\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Memory Viewer collectors (Issue #1023)\n// ---------------------------------------------------------------------------\n\n/** Open a read-only handle to the facts DB for internal dashboard use. */\nfunction openFactsDbReadonly(path: string): import(\"node:sqlite\").DatabaseSync | null {\n try {\n const { DatabaseSync: DBSync } = require(\"node:sqlite\") as typeof import(\"node:sqlite\");\n const db = new DBSync(path, { readOnly: true });\n return db;\n } catch {\n return null;\n }\n}\n\n/** Collect Memory Viewer overview stats. */\nexport async function collectMemoryViewerStats(ctx: DashboardContext): Promise<MemoryViewerStats> {\n const factsDb = ctx.factsDb;\n const totalFacts = factsDb.count();\n const totalExpired = factsDb.countExpired();\n\n // Use a read-only connection to the facts DB for counts not exposed by the public API\n const roDb = openFactsDbReadonly(ctx.resolvedSqlitePath);\n let totalSuperseded = 0;\n let totalVerified = 0;\n let totalEdicts = 0;\n let totalEpisodes = 0;\n if (roDb) {\n try {\n const sr = roDb.prepare(\"SELECT COUNT(*) as cnt FROM facts WHERE superseded_at IS NOT NULL\").get() as\n | { cnt: number }\n | undefined;\n totalSuperseded = sr?.cnt ?? 0;\n } catch {\n /* non-fatal */\n }\n try {\n const vr = roDb.prepare(\"SELECT COUNT(*) as cnt FROM verified_facts\").get() as { cnt: number } | undefined;\n totalVerified = vr?.cnt ?? 0;\n } catch {\n /* non-fatal */\n }\n try {\n const er = roDb.prepare(\"SELECT COUNT(*) as cnt FROM edicts\").get() as { cnt: number } | undefined;\n totalEdicts = er?.cnt ?? 0;\n } catch {\n /* non-fatal */\n }\n try {\n const ar = roDb.prepare(\"SELECT COUNT(*) as cnt FROM episodes\").get() as { cnt: number } | undefined;\n totalEpisodes = ar?.cnt ?? 0;\n } catch {\n /* non-fatal */\n }\n try {\n roDb.close();\n } catch {\n /* ignore */\n }\n }\n\n const totalIssues = (() => {\n try {\n if (!ctx.issueStore) return 0;\n return ctx.issueStore.list({}).length;\n } catch {\n return 0;\n }\n })();\n const totalProcedures = (() => {\n try {\n return factsDb.proceduresCount();\n } catch {\n return 0;\n }\n })();\n const totalLinks = (() => {\n try {\n return factsDb.linksCount();\n } catch {\n return 0;\n }\n })();\n let vectorCount = 0;\n try {\n vectorCount = await ctx.vectorDb.count();\n } catch {\n /* non-fatal */\n }\n\n return {\n totalFacts,\n totalExpired,\n totalSuperseded,\n totalVerified,\n totalEdicts,\n totalIssues,\n totalProcedures,\n totalEpisodes,\n totalLinks,\n vectorCount,\n byCategory: factsDb.statsBreakdownByCategory(),\n byTier: factsDb.statsBreakdownByTier(),\n byDecayClass: factsDb.statsBreakdownByDecayClass(),\n bySource: factsDb.statsBreakdownBySource(),\n entityCount: factsDb.entityCount(),\n };\n}\n\n/** Collect recent episodes — reads from the episodes table within the facts DB. */\nexport function collectMemoryViewerEpisodes(ctx: DashboardContext, limit = 50): MemoryViewerEpisode[] {\n try {\n const roDb = openFactsDbReadonly(ctx.resolvedSqlitePath);\n if (!roDb) return [];\n try {\n const rows = roDb.prepare(\"SELECT * FROM episodes ORDER BY timestamp DESC LIMIT ?\").all(limit) as Array<\n Record<string, unknown>\n >;\n return rows.map((r) => ({\n id: String(r.id ?? \"\"),\n event: String(r.event ?? \"\"),\n outcome: String(r.outcome ?? \"\"),\n timestamp: Number(r.timestamp ?? 0),\n duration: r.duration != null ? Number(r.duration) : undefined,\n context: r.context != null ? String(r.context) : undefined,\n agentId: r.agent_id != null ? String(r.agent_id) : undefined,\n sessionId: r.session_id != null ? String(r.session_id) : undefined,\n importance: Number(r.importance ?? 0.5),\n tags: (() => {\n try {\n return JSON.parse(String(r.tags ?? \"[]\"));\n } catch {\n return [];\n }\n })(),\n }));\n } finally {\n try {\n roDb.close();\n } catch {\n /* ignore */\n }\n }\n } catch {\n return [];\n }\n}\n\n/** Collect recent narratives. */\nexport function collectMemoryViewerNarratives(ctx: DashboardContext, limit = 20): MemoryViewerNarrative[] {\n try {\n if (!ctx.narrativesDb) return [];\n return ctx.narrativesDb.listRecent(limit, \"all\").map((n) => ({\n id: n.id,\n sessionId: n.sessionId,\n periodStart: n.periodStart,\n periodEnd: n.periodEnd,\n tag: n.tag,\n narrativeText: n.narrativeText,\n createdAt: n.createdAt,\n }));\n } catch {\n return [];\n }\n}\n\n/** Collect recent issues. */\nexport function collectMemoryViewerIssues(ctx: DashboardContext): MemoryViewerIssue[] {\n try {\n if (!ctx.issueStore) return [];\n return ctx.issueStore.list({}).map((issue) => ({\n id: issue.id,\n title: issue.title,\n status: issue.status,\n severity: issue.severity,\n symptoms: issue.symptoms,\n rootCause: issue.rootCause,\n fix: issue.fix,\n tags: issue.tags,\n detectedAt: issue.detectedAt,\n resolvedAt: issue.resolvedAt,\n verifiedAt: issue.verifiedAt,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n }));\n } catch {\n return [];\n }\n}\n\n/** Collect workflow patterns / recent traces. */\nexport function collectMemoryViewerWorkflows(ctx: DashboardContext, limit = 100): MemoryViewerWorkflow[] {\n try {\n if (!ctx.workflowStore) return [];\n const traces = ctx.workflowStore.list({ limit });\n const patterns = ctx.workflowStore.getPatterns({ limit: 20 });\n const result: MemoryViewerWorkflow[] = traces.map((t) => ({\n id: t.id,\n goal: t.goal,\n toolSequence: t.toolSequence,\n outcome: t.outcome,\n toolCount: t.toolCount,\n durationMs: t.durationMs,\n successRate:\n patterns.find((p) => JSON.stringify(p.toolSequence) === JSON.stringify(t.toolSequence))?.successRate ?? 0,\n sessionId: t.sessionId,\n createdAt: t.createdAt,\n }));\n return result;\n } catch {\n return [];\n }\n}\n\n/** Collect recent edicts. */\nexport function collectMemoryViewerEdicts(ctx: DashboardContext): MemoryViewerEdict[] {\n try {\n if (!ctx.edictStore) return [];\n return ctx.edictStore.list({}).map((e) => ({\n id: e.id,\n text: e.text,\n source: e.source,\n tags: e.tags,\n verifiedAt: e.verifiedAt,\n expiresAt: e.expiresAt,\n ttl: String(e.ttl),\n createdAt: e.createdAt,\n }));\n } catch {\n return [];\n }\n}\n\n/** Collect verified facts using the public listLatestVerified API. */\nexport function collectMemoryViewerVerified(ctx: DashboardContext, limit = 100): MemoryViewerVerification[] {\n try {\n if (!ctx.verificationStore) return [];\n const verified = ctx.verificationStore.listLatestVerified().slice(0, Math.max(1, Math.min(500, Math.floor(limit))));\n return verified.map((v) => ({\n factId: v.factId,\n canonicalText: v.canonicalText,\n verifiedAt: v.verifiedAt ?? \"\",\n verifiedBy: v.verifiedBy ?? \"\",\n nextVerification: v.nextVerification ?? null,\n version: v.version,\n }));\n } catch {\n return [];\n }\n}\n\n/** Collect top entities. */\nexport function collectMemoryViewerEntities(ctx: DashboardContext, limit = 50): MemoryViewerEntity[] {\n try {\n const raw = ctx.factsDb.getRawDb();\n const rows = raw\n .prepare(\n `SELECT entity, COUNT(*) as cnt, GROUP_CONCAT(DISTINCT category) as cats, GROUP_CONCAT(DISTINCT tags) as tgs, MAX(created_at) as last_updated\n FROM facts WHERE entity IS NOT NULL AND entity != '' AND superseded_at IS NULL\n GROUP BY entity ORDER BY cnt DESC LIMIT ?`,\n )\n .all(limit) as Array<Record<string, unknown>>;\n return rows.map((r) => {\n let cats: string[] = [];\n try {\n cats = [...new Set(String(r.cats ?? \"\").split(\",\"))];\n } catch {}\n let tgs: string[] = [];\n try {\n const allTags = String(r.tgs ?? \"\").split(\",\");\n tgs = [...new Set(allTags.filter(Boolean))];\n } catch {}\n return {\n entity: String(r.entity ?? \"\"),\n factCount: Number(r.cnt ?? 0),\n categories: cats,\n tags: tgs,\n lastUpdated: Number(r.last_updated ?? 0),\n };\n });\n } catch {\n return [];\n }\n}\n\n/** Collect provenance edges for a fact. */\nexport function collectMemoryViewerProvenance(ctx: DashboardContext, factId: string): MemoryViewerProvenance | null {\n try {\n if (!ctx.provenanceService) return null;\n // Note: getProvenance accepts an optional factsDb param for fact text enrichment.\n // We pass the open FactsDB instance directly for this read-only access.\n const chain = ctx.provenanceService.getProvenance(factId);\n return {\n factId: chain.fact.id,\n text: chain.fact.text,\n confidence: chain.fact.confidence,\n provenanceSession: chain.source.sessionId,\n sourceTurn: chain.source.turn,\n edges: chain.edges.map((e) => ({\n edgeType: e.edgeType,\n sourceType: e.sourceType,\n sourceId: e.sourceId,\n sourceText: e.sourceText,\n createdAt: e.createdAt,\n })),\n };\n } catch {\n return null;\n }\n}\n\n/** Collect fact links from the memory_links table. */\nexport function collectMemoryViewerLinks(ctx: DashboardContext, limit = 5000): MemoryViewerLinks[] {\n try {\n const roDb = openFactsDbReadonly(ctx.resolvedSqlitePath);\n if (!roDb) return [];\n try {\n const rows = roDb.prepare(\"SELECT * FROM memory_links LIMIT ?\").all(limit) as Array<Record<string, unknown>>;\n return rows.map((r) => ({\n from: String(r.source_fact_id ?? \"\"),\n to: String(r.target_fact_id ?? \"\"),\n type: String(r.link_type ?? \"\"),\n strength: Number(r.strength ?? 1),\n }));\n } finally {\n try {\n roDb.close();\n } catch {\n /* ignore */\n }\n }\n } catch {\n return [];\n }\n}\n\n/** Perform a fact action (verify / forget) and return result. */\nexport function performFactAction(\n ctx: DashboardContext,\n action: \"verify\" | \"forget\",\n factId: string,\n body: Record<string, unknown>,\n): { ok: boolean; message: string } {\n try {\n const factsDb = ctx.factsDb;\n const fact = factsDb.getById(factId);\n if (!fact) return { ok: false, message: `Fact not found: ${factId}` };\n\n if (action === \"verify\") {\n if (!ctx.verificationStore) return { ok: false, message: \"Verification store not available\" };\n const verifiedBy = (body.verifiedBy as \"agent\" | \"user\" | \"system\") ?? \"agent\";\n ctx.verificationStore.verify(factId, fact.text, verifiedBy);\n clearVerifiedFactIdCache(ctx);\n return { ok: true, message: `Fact ${factId} verified as ${verifiedBy}` };\n }\n // forget: supersede with null to mark the fact as superseded (soft-delete).\n // superseded_at IS NOT NULL filters it out of all recall paths.\n try {\n const ok = factsDb.supersede(factId, null);\n if (!ok) return { ok: false, message: `Could not supersede fact ${factId}` };\n } catch {\n return { ok: false, message: `Could not forget fact ${factId}` };\n }\n clearVerifiedFactIdCache(ctx);\n return { ok: true, message: `Fact ${factId} forgotten` };\n } catch {\n return { ok: false, message: \"Fact action failed\" };\n }\n}\n\nexport async function collectStatus(ctx: DashboardContext): Promise<DashboardStatus> {\n const [memory, cronJobs, taskQueue, forge, git] = await Promise.all([\n collectMemoryStats(ctx),\n collectCronJobs(),\n collectTaskQueue(),\n collectForgeState(),\n collectGitActivity(ctx.gitRepo),\n ]);\n const agentHealth = await collectAgentHealth(ctx, forge);\n return {\n generatedAt: new Date().toISOString(),\n memory,\n cronJobs,\n taskQueue,\n forge,\n git,\n costs: collectCostStats(ctx),\n audit: collectAuditSummary(ctx),\n agentHealth,\n };\n}\n\n// ---------------------------------------------------------------------------\n// HTML dashboard\n// ---------------------------------------------------------------------------\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.js","names":["execFileCb"],"sources":["../../../routes/dashboard/html.ts"],"sourcesContent":["/**\n * Mission Control Dashboard — Issue #309\n *\n * Serves a web dashboard via a small HTTP server registered as a plugin service.\n * Routes:\n * GET / — HTML dashboard (vanilla JS/CSS, no framework)\n * GET /api/status — JSON data for all dashboard sections\n */\n\nimport { createRequire } from \"node:module\";\nimport { promisify } from \"node:util\";\nimport type { VerificationStore } from \"../../services/verification-store.js\";\nimport { execFile as execFileCb } from \"../../utils/process-runner.js\";\n\nconst _execFile = promisify(execFileCb);\nconst _require = createRequire(import.meta.url);\n\nconst _MAX_DASHBOARD_JSON_BODY_BYTES = 64 * 1024;\nconst _VERIFIED_FACT_SET_TTL_MS = 5000;\nconst _verifiedFactIdCacheByStore = new WeakMap<VerificationStore, { at: number; ids: Set<string> }>();\n\nexport function getDashboardHtml(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Mission Control</title>\n<style>\n :root {\n --bg: #0f1117;\n --surface: #1a1d27;\n --border: #2a2d3a;\n --text: #e2e8f0;\n --muted: #8892a4;\n --green: #22c55e;\n --yellow: #eab308;\n --red: #ef4444;\n --blue: #3b82f6;\n --purple: #a855f7;\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body { background: var(--bg); color: var(--text); font-family: 'Segoe UI', system-ui, sans-serif; font-size: 14px; min-height: 100vh; }\n header { background: var(--surface); border-bottom: 1px solid var(--border); padding: 12px 20px; display: flex; align-items: center; justify-content: space-between; position: sticky; top: 0; z-index: 10; }\n header h1 { font-size: 18px; font-weight: 700; letter-spacing: 0.05em; color: var(--blue); }\n #last-updated { font-size: 12px; color: var(--muted); }\n main { padding: 16px; max-width: 1400px; margin: 0 auto; }\n .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 16px; }\n .card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 16px; }\n .card-title { font-size: 13px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); margin-bottom: 12px; display: flex; align-items: center; gap: 6px; }\n .card-title .icon { font-size: 16px; }\n .stat-row { display: flex; justify-content: space-between; align-items: center; padding: 4px 0; border-bottom: 1px solid var(--border); }\n .stat-row:last-child { border-bottom: none; }\n .stat-label { color: var(--muted); }\n .stat-value { font-weight: 600; font-variant-numeric: tabular-nums; }\n .badge { display: inline-block; padding: 2px 8px; border-radius: 12px; font-size: 11px; font-weight: 600; }\n .badge-green { background: rgba(34,197,94,0.15); color: var(--green); }\n .badge-yellow { background: rgba(234,179,8,0.15); color: var(--yellow); }\n .badge-red { background: rgba(239,68,68,0.15); color: var(--red); }\n .badge-blue { background: rgba(59,130,246,0.15); color: var(--blue); }\n .badge-muted { background: rgba(136,146,164,0.15); color: var(--muted); }\n .job-row { padding: 6px 0; border-bottom: 1px solid var(--border); display: grid; grid-template-columns: 1fr auto; gap: 8px; align-items: start; }\n .job-row:last-child { border-bottom: none; }\n .job-name { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .job-meta { font-size: 11px; color: var(--muted); margin-top: 2px; }\n .task-row { padding: 6px 0; border-bottom: 1px solid var(--border); }\n .task-row:last-child { border-bottom: none; }\n .task-title { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .task-meta { font-size: 11px; color: var(--muted); margin-top: 2px; }\n .pr-row { padding: 6px 0; border-bottom: 1px solid var(--border); }\n .pr-row:last-child { border-bottom: none; }\n .pr-title { font-size: 13px; font-weight: 500; }\n .pr-title a { color: var(--text); text-decoration: none; }\n .pr-title a:hover { color: var(--blue); }\n .pr-meta { font-size: 11px; color: var(--muted); margin-top: 2px; }\n .cost-row { display: grid; grid-template-columns: 1fr auto auto; gap: 8px; align-items: center; padding: 4px 0; border-bottom: 1px solid var(--border); }\n .cost-row:last-child { border-bottom: none; }\n .cost-feature { font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .cost-calls { font-size: 12px; color: var(--muted); }\n .cost-usd { font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--green); }\n .empty { color: var(--muted); font-size: 13px; text-align: center; padding: 16px 0; }\n .agent-row { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid var(--border); }\n .agent-row:last-child { border-bottom: none; }\n .agent-avatar { font-size: 18px; flex-shrink: 0; }\n .agent-info { flex: 1; min-width: 0; }\n .agent-name { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .agent-task { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .section-full { grid-column: 1 / -1; }\n @media (max-width: 600px) { .grid { grid-template-columns: 1fr; } main { padding: 8px; } }\n</style>\n</head>\n<body>\n<header>\n <h1>⚡ Mission Control</h1>\n <div style=\"display:flex;align-items:center;gap:14px\">\n <a href=\"/graph\" style=\"color:var(--muted);text-decoration:none;font-size:12px\">Memory graph →</a>\n <span id=\"last-updated\">Loading…</span>\n </div>\n</header>\n<main>\n <div class=\"grid\" id=\"grid\">\n <div class=\"card\"><div class=\"empty\">Loading…</div></div>\n </div>\n</main>\n<script>\nconst AGENT_AVATARS = { Forge: '⚒️', Scholar: '📚', Hearth: '🏠', Warden: '🛡️', Reaver: '🔧' };\nconst STATUS_BADGE = {\n running: '<span class=\"badge badge-green\">running</span>',\n active: '<span class=\"badge badge-green\">active</span>',\n idle: '<span class=\"badge badge-muted\">idle</span>',\n done: '<span class=\"badge badge-blue\">done</span>',\n completed: '<span class=\"badge badge-blue\">done</span>',\n partial: '<span class=\"badge badge-yellow\">partial</span>',\n failed: '<span class=\"badge badge-red\">failed</span>',\n error: '<span class=\"badge badge-red\">error</span>',\n success: '<span class=\"badge badge-green\">ok</span>',\n ok: '<span class=\"badge badge-green\">ok</span>',\n};\n\nfunction badge(status) {\n const s = String(status ?? '').toLowerCase();\n return Object.hasOwn(STATUS_BADGE, s) ? STATUS_BADGE[s] : \\`<span class=\"badge badge-muted\">\\${escHtml(status || 'unknown')}</span>\\`;\n}\n\nfunction escHtml(s) {\n return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"');\n}\n\nfunction fmtBytes(b) {\n if (b < 1024) return b + ' B';\n if (b < 1048576) return (b/1024).toFixed(1) + ' KB';\n return (b/1048576).toFixed(1) + ' MB';\n}\n\nfunction fmtDate(iso) {\n if (!iso) return '—';\n const d = new Date(iso);\n const now = new Date();\n const diffMs = now - d;\n const diffH = diffMs / 3600000;\n if (diffH < 1) return Math.round(diffMs/60000) + 'm ago';\n if (diffH < 24) return diffH.toFixed(0) + 'h ago';\n if (diffH < 168) return Math.round(diffH/24) + 'd ago';\n return d.toLocaleDateString();\n}\n\nfunction getAvatar(name) {\n for (const [k, v] of Object.entries(AGENT_AVATARS)) {\n if (name && name.toLowerCase().includes(k.toLowerCase())) return v;\n }\n return '🤖';\n}\n\nfunction renderMemory(m) {\n return \\`<div class=\"card\">\n <div class=\"card-title\"><span class=\"icon\">🧠</span> Memory Stats</div>\n <div class=\"stat-row\"><span class=\"stat-label\">Active facts</span><span class=\"stat-value\">\\${m.activeFacts.toLocaleString()}</span></div>\n <div class=\"stat-row\"><span class=\"stat-label\">Expired facts</span><span class=\"stat-value\">\\${m.expiredFacts.toLocaleString()}</span></div>\n <div class=\"stat-row\"><span class=\"stat-label\">Vector index</span><span class=\"stat-value\">\\${m.vectorCount.toLocaleString()}</span></div>\n <div class=\"stat-row\"><span class=\"stat-label\">SQLite size</span><span class=\"stat-value\">\\${fmtBytes(m.sqliteSizeBytes)}</span></div>\n <div class=\"stat-row\"><span class=\"stat-label\">LanceDB size</span><span class=\"stat-value\">\\${fmtBytes(m.lanceSizeBytes)}</span></div>\n <div class=\"stat-row\"><span class=\"stat-label\">Total storage</span><span class=\"stat-value\">\\${fmtBytes(m.totalSizeBytes)}</span></div>\n</div>\\`;\n}\n\nfunction renderTaskQueue(tq) {\n let html = '<div class=\"card\"><div class=\"card-title\"><span class=\"icon\">📋</span> Task Queue</div>';\n if (tq.current) {\n const c = tq.current;\n html += \\`<div class=\"task-row\">\n <div style=\"display:flex;justify-content:space-between;align-items:center\">\n <div class=\"task-title\">\\${escHtml(c.title || (c.issue != null ? '#' + c.issue : 'Current Task'))}</div>\n \\${badge(c.status)}\n </div>\n <div class=\"task-meta\">\\${c.branch ? '#' + escHtml(c.branch) + ' · ' : ''}\\${fmtDate(c.started)}</div>\n </div>\\`;\n } else {\n html += '<div class=\"stat-row\"><span class=\"stat-label\">Current</span><span class=\"badge badge-muted\">idle</span></div>';\n }\n if (tq.history && tq.history.length > 0) {\n html += '<div style=\"margin-top:8px;font-size:11px;color:var(--muted);margin-bottom:4px\">Recent</div>';\n tq.history.slice(0, 5).forEach(h => {\n html += \\`<div class=\"task-row\">\n <div style=\"display:flex;justify-content:space-between;align-items:center\">\n <div class=\"task-title\" style=\"font-size:12px\">\\${escHtml(h.title || (h.issue != null ? '#' + h.issue : '?'))}</div>\n \\${badge(h.status)}\n </div>\n <div class=\"task-meta\">\\${fmtDate(h.completed || h.started)}</div>\n </div>\\`;\n });\n }\n html += '</div>';\n return html;\n}\n\nfunction renderForge(forge) {\n let html = '<div class=\"card\"><div class=\"card-title\"><span class=\"icon\">⚒️</span> Agent Status</div>';\n if (!forge || forge.length === 0) {\n html += '<div class=\"empty\">No active agents</div>';\n } else {\n forge.forEach(f => {\n const name = f.agent || 'unknown';\n html += \\`<div class=\"agent-row\">\n <div class=\"agent-avatar\">\\${getAvatar(name)}</div>\n <div class=\"agent-info\">\n <div class=\"agent-name\">\\${escHtml(name)}</div>\n <div class=\"agent-task\">\\${escHtml(f.task || f.workdir || '')}</div>\n </div>\n <div>\\${badge(f.status)}</div>\n </div>\\`;\n });\n }\n html += '</div>';\n return html;\n}\n\nfunction renderCronJobs(jobs) {\n let html = '<div class=\"card\"><div class=\"card-title\"><span class=\"icon\">⏰</span> Cron Jobs</div>';\n if (!jobs || jobs.length === 0) {\n html += '<div class=\"empty\">No cron jobs</div>';\n } else {\n jobs.forEach(j => {\n const status = j.consecutiveErrors > 0 ? 'error' : (j.lastStatus || (j.enabled ? 'ok' : 'disabled'));\n html += \\`<div class=\"job-row\">\n <div>\n <div class=\"job-name\">\\${escHtml(j.name)}</div>\n <div class=\"job-meta\">\\${escHtml(j.schedule)} · last: \\${fmtDate(j.lastRunAt)}</div>\n \\${j.lastError ? '<div class=\"job-meta\" style=\"color:var(--red);\">' + escHtml(j.lastError.slice(0,80)) + '</div>' : ''}\n </div>\n <div>\\${badge(status)}</div>\n </div>\\`;\n });\n }\n html += '</div>';\n return html;\n}\n\nfunction renderGit(git) {\n let html = '<div class=\"card\"><div class=\"card-title\"><span class=\"icon\">🔀</span> Git Activity</div>';\n if (git.gitError) {\n html += \\`<div class=\"empty\">gh CLI unavailable</div>\\`;\n } else {\n const items = [...(git.prs || []).map(p => ({...p, kind:'PR'})), ...(git.issues || []).map(i => ({...i, kind:'Issue'}))];\n items.sort((a,b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\n if (items.length === 0) {\n html += '<div class=\"empty\">No recent activity</div>';\n } else {\n items.slice(0, 8).forEach(item => {\n const statColor = item.state === 'OPEN' ? 'green' : (item.state === 'MERGED' ? 'blue' : 'muted');\n html += \\`<div class=\"pr-row\">\n <div class=\"pr-title\"><a href=\"\\${escHtml(item.url || '#')}\" target=\"_blank\" rel=\"noopener noreferrer\">#\\${escHtml(String(item.number))} \\${escHtml(item.title)}</a></div>\n <div class=\"pr-meta\"><span class=\"badge badge-\\${statColor}\" style=\"font-size:10px\">\\${escHtml(item.state)}</span> \\${escHtml(item.kind)} · \\${fmtDate(item.createdAt)}</div>\n </div>\\`;\n });\n }\n }\n html += '</div>';\n return html;\n}\n\nfunction renderCosts(c) {\n let html = '<div class=\"card\"><div class=\"card-title\"><span class=\"icon\">💰</span> Cost Tracking (7d)</div>';\n if (!c.enabled) {\n html += '<div class=\"empty\">Cost tracking disabled</div>';\n } else if (c.features.length === 0) {\n html += '<div class=\"empty\">No LLM calls in last 7 days</div>';\n } else {\n html += \\`<div class=\"stat-row\"><span class=\"stat-label\">Total calls</span><span class=\"stat-value\">\\${c.totalCalls.toLocaleString()}</span></div>\\`;\n html += \\`<div class=\"stat-row\"><span class=\"stat-label\">Tokens in/out</span><span class=\"stat-value\">\\${c.totalInputTokens.toLocaleString()} / \\${c.totalOutputTokens.toLocaleString()}</span></div>\\`;\n html += \\`<div class=\"stat-row\" style=\"margin-bottom:8px\"><span class=\"stat-label\">Est. cost</span><span class=\"stat-value\" style=\"color:var(--green)\">$\\${c.totalEstimatedCostUsd.toFixed(4)}</span></div>\\`;\n c.features.slice(0, 6).forEach(f => {\n html += \\`<div class=\"cost-row\">\n <div class=\"cost-feature\">\\${escHtml(f.feature)}</div>\n <div class=\"cost-calls\">\\${f.calls} calls</div>\n <div class=\"cost-usd\">$\\${f.estimatedCostUsd.toFixed(4)}</div>\n </div>\\`;\n });\n }\n html += '</div>';\n return html;\n}\n\nfunction renderAgentHealth(ah) {\n let html = '<div class=\"card section-full\"><div class=\"card-title\"><span class=\"icon\">🩺</span> Agent Health</div>';\n if (!ah || !ah.enabled) {\n html += '<div class=\"empty\">Agent health store unavailable</div></div>';\n return html;\n }\n html += '<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:8px\">';\n (ah.agents || []).slice(0, 12).forEach(function (a) {\n const st = String(a.status || 'unknown');\n const badge = st === 'healthy' ? 'badge-green' : st === 'idle' ? 'badge-muted' : st === 'stale' ? 'badge-yellow' : st === 'degraded' ? 'badge-red' : 'badge-muted';\n html += '<div class=\"agent-row\" style=\"flex-direction:column;align-items:flex-start;border:1px solid var(--border);border-radius:6px;padding:8px\">';\n html += '<div style=\"display:flex;justify-content:space-between;width:100%;align-items:center\"><span class=\"agent-name\">' + escHtml(a.agentId) + '</span><span class=\"badge ' + badge + '\">' + escHtml(st) + '</span></div>';\n html += '<div class=\"task-meta\">score ' + (typeof a.score === 'number' ? a.score.toFixed(1) : '—') + ' · ' + fmtDate(new Date(a.lastSeen).toISOString()) + '</div>';\n html += '<div class=\"agent-task\">' + escHtml((a.lastTask || '').slice(0, 120)) + '</div></div>';\n });\n html += '</div>';\n if (ah.alerts && ah.alerts.length > 0) {\n html += '<div style=\"margin-top:10px;font-size:12px;color:var(--yellow)\">';\n ah.alerts.slice(0, 4).forEach(function (m) { html += '<div>⚠ ' + escHtml(m) + '</div>'; });\n html += '</div>';\n }\n html += '</div>';\n return html;\n}\n\nfunction renderAudit(a) {\n let html = '<div class=\"card section-full\"><div class=\"card-title\"><span class=\"icon\">📜</span> Audit Trail (24h)</div>';\n if (!a || !a.enabled) {\n html += '<div class=\"empty\">Audit log unavailable</div></div>';\n return html;\n }\n html += \\`<div class=\"stat-row\"><span class=\"stat-label\">Total events</span><span class=\"stat-value\">\\${a.total24h.toLocaleString()}</span></div>\\`;\n html += \\`<div class=\"stat-row\"><span class=\"stat-label\">Outcomes</span><span class=\"stat-value\">ok \\${a.byOutcome.success} · partial \\${a.byOutcome.partial} · failed \\${a.byOutcome.failed}</span></div>\\`;\n const agents = Object.entries(a.byAgent || {}).sort((x,y) => y[1] - x[1]).slice(0, 8);\n if (agents.length > 0) {\n html += '<div style=\"margin-top:8px;font-size:11px;color:var(--muted)\">By agent</div>';\n agents.forEach(([name, cnt]) => {\n html += \\`<div class=\"stat-row\"><span class=\"stat-label\">\\${escHtml(name)}</span><span class=\"stat-value\">\\${cnt}</span></div>\\`;\n });\n }\n if (a.recentFailures && a.recentFailures.length > 0) {\n html += '<div style=\"margin-top:8px;font-size:11px;color:var(--red)\">Recent failures</div>';\n a.recentFailures.slice(0, 5).forEach(f => {\n html += \\`<div class=\"task-row\"><div class=\"task-title\" style=\"font-size:12px\">\\${escHtml(f.agentId)} / \\${escHtml(f.action)}</div><div class=\"task-meta\">\\${escHtml(f.target || '')} \\${f.error ? escHtml(f.error.slice(0,120)) : ''}</div></div>\\`;\n });\n }\n html += '</div>';\n return html;\n}\n\nasync function refresh() {\n try {\n const res = await fetch('/api/status');\n const data = await res.json();\n if (!res.ok) {\n throw new Error(data.error || 'Server error');\n }\n const grid = document.getElementById('grid');\n grid.innerHTML = [\n renderMemory(data.memory),\n renderTaskQueue(data.taskQueue),\n renderForge(data.forge),\n renderCronJobs(data.cronJobs),\n renderGit(data.git),\n renderCosts(data.costs),\n renderAgentHealth(data.agentHealth),\n renderAudit(data.audit),\n ].join('');\n document.getElementById('last-updated').textContent = 'Updated ' + new Date(data.generatedAt).toLocaleTimeString();\n } catch (err) {\n document.getElementById('last-updated').textContent = 'Error: ' + err.message;\n }\n}\n\nrefresh();\nsetInterval(refresh, 60000);\n</script>\n</body>\n</html>`;\n}\n"],"mappings":";;;;;;;;;;;;AAckB,UAAUA,SAAW;AACtB,cAAc,OAAO,KAAK,IAAI;AAM/C,SAAgB,mBAA2B;CACzC,OAAO"}
|
|
1
|
+
{"version":3,"file":"html.js","names":["execFileCb"],"sources":["../../../routes/dashboard/html.ts"],"sourcesContent":["/**\n * Mission Control Dashboard — Issue #309\n *\n * Serves a web dashboard via a small HTTP server registered as a plugin service.\n * Routes:\n * GET / — HTML dashboard (vanilla JS/CSS, no framework)\n * GET /api/status — JSON data for all dashboard sections\n */\n\nimport { createRequire } from \"node:module\";\nimport { promisify } from \"node:util\";\nimport type { VerificationStore } from \"../../services/verification-store.js\";\nimport { execFile as execFileCb } from \"../../utils/process-runner.js\";\n\nconst _execFile = promisify(execFileCb);\nconst _require = createRequire(import.meta.url);\n\nconst _MAX_DASHBOARD_JSON_BODY_BYTES = 64 * 1024;\nconst _VERIFIED_FACT_SET_TTL_MS = 5000;\nconst _verifiedFactIdCacheByStore = new WeakMap<VerificationStore, { at: number; ids: Set<string> }>();\n\nexport function getDashboardHtml(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Mission Control</title>\n<style>\n :root {\n --bg: #0f1117;\n --surface: #1a1d27;\n --border: #2a2d3a;\n --text: #e2e8f0;\n --muted: #8892a4;\n --green: #22c55e;\n --yellow: #eab308;\n --red: #ef4444;\n --blue: #3b82f6;\n --purple: #a855f7;\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body { background: var(--bg); color: var(--text); font-family: 'Segoe UI', system-ui, sans-serif; font-size: 14px; min-height: 100vh; }\n header { background: var(--surface); border-bottom: 1px solid var(--border); padding: 12px 20px; display: flex; align-items: center; justify-content: space-between; position: sticky; top: 0; z-index: 10; }\n header h1 { font-size: 18px; font-weight: 700; letter-spacing: 0.05em; color: var(--blue); }\n #last-updated { font-size: 12px; color: var(--muted); }\n main { padding: 16px; max-width: 1400px; margin: 0 auto; }\n .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 16px; }\n .card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 16px; }\n .card-title { font-size: 13px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); margin-bottom: 12px; display: flex; align-items: center; gap: 6px; }\n .card-title .icon { font-size: 16px; }\n .stat-row { display: flex; justify-content: space-between; align-items: center; padding: 4px 0; border-bottom: 1px solid var(--border); }\n .stat-row:last-child { border-bottom: none; }\n .stat-label { color: var(--muted); }\n .stat-value { font-weight: 600; font-variant-numeric: tabular-nums; }\n .badge { display: inline-block; padding: 2px 8px; border-radius: 12px; font-size: 11px; font-weight: 600; }\n .badge-green { background: rgba(34,197,94,0.15); color: var(--green); }\n .badge-yellow { background: rgba(234,179,8,0.15); color: var(--yellow); }\n .badge-red { background: rgba(239,68,68,0.15); color: var(--red); }\n .badge-blue { background: rgba(59,130,246,0.15); color: var(--blue); }\n .badge-muted { background: rgba(136,146,164,0.15); color: var(--muted); }\n .job-row { padding: 6px 0; border-bottom: 1px solid var(--border); display: grid; grid-template-columns: 1fr auto; gap: 8px; align-items: start; }\n .job-row:last-child { border-bottom: none; }\n .job-name { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .job-meta { font-size: 11px; color: var(--muted); margin-top: 2px; }\n .task-row { padding: 6px 0; border-bottom: 1px solid var(--border); }\n .task-row:last-child { border-bottom: none; }\n .task-title { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .task-meta { font-size: 11px; color: var(--muted); margin-top: 2px; }\n .pr-row { padding: 6px 0; border-bottom: 1px solid var(--border); }\n .pr-row:last-child { border-bottom: none; }\n .pr-title { font-size: 13px; font-weight: 500; }\n .pr-title a { color: var(--text); text-decoration: none; }\n .pr-title a:hover { color: var(--blue); }\n .pr-meta { font-size: 11px; color: var(--muted); margin-top: 2px; }\n .cost-row { display: grid; grid-template-columns: 1fr auto auto; gap: 8px; align-items: center; padding: 4px 0; border-bottom: 1px solid var(--border); }\n .cost-row:last-child { border-bottom: none; }\n .cost-feature { font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .cost-calls { font-size: 12px; color: var(--muted); }\n .cost-usd { font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--green); }\n .empty { color: var(--muted); font-size: 13px; text-align: center; padding: 16px 0; }\n .agent-row { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid var(--border); }\n .agent-row:last-child { border-bottom: none; }\n .agent-avatar { font-size: 18px; flex-shrink: 0; }\n .agent-info { flex: 1; min-width: 0; }\n .agent-name { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .agent-task { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .section-full { grid-column: 1 / -1; }\n @media (max-width: 600px) { .grid { grid-template-columns: 1fr; } main { padding: 8px; } }\n</style>\n</head>\n<body>\n<header>\n <h1>⚡ Mission Control</h1>\n <div style=\"display:flex;align-items:center;gap:14px\">\n <a href=\"/graph\" style=\"color:var(--muted);text-decoration:none;font-size:12px\">Memory graph →</a>\n <span id=\"last-updated\">Loading…</span>\n </div>\n</header>\n<main>\n <div class=\"grid\" id=\"grid\">\n <div class=\"card\"><div class=\"empty\">Loading…</div></div>\n </div>\n</main>\n<script>\nconst AGENT_AVATARS = { Forge: '⚒️', Scholar: '📚', Hearth: '🏠', Warden: '🛡️', Reaver: '🔧' };\nconst STATUS_BADGE = {\n running: '<span class=\"badge badge-green\">running</span>',\n active: '<span class=\"badge badge-green\">active</span>',\n idle: '<span class=\"badge badge-muted\">idle</span>',\n done: '<span class=\"badge badge-blue\">done</span>',\n completed: '<span class=\"badge badge-blue\">done</span>',\n partial: '<span class=\"badge badge-yellow\">partial</span>',\n failed: '<span class=\"badge badge-red\">failed</span>',\n error: '<span class=\"badge badge-red\">error</span>',\n success: '<span class=\"badge badge-green\">ok</span>',\n ok: '<span class=\"badge badge-green\">ok</span>',\n};\n\nfunction badge(status) {\n const s = String(status ?? '').toLowerCase();\n return Object.hasOwn(STATUS_BADGE, s) ? STATUS_BADGE[s] : \\`<span class=\"badge badge-muted\">\\${escHtml(status || 'unknown')}</span>\\`;\n}\n\nfunction escHtml(s) {\n return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"');\n}\n\nfunction fmtBytes(b) {\n if (b < 1024) return b + ' B';\n if (b < 1048576) return (b/1024).toFixed(1) + ' KB';\n return (b/1048576).toFixed(1) + ' MB';\n}\n\nfunction fmtDate(iso) {\n if (!iso) return '—';\n const d = new Date(iso);\n const now = new Date();\n const diffMs = now - d;\n const diffH = diffMs / 3600000;\n if (diffH < 1) return Math.round(diffMs/60000) + 'm ago';\n if (diffH < 24) return diffH.toFixed(0) + 'h ago';\n if (diffH < 168) return Math.round(diffH/24) + 'd ago';\n return d.toLocaleDateString();\n}\n\nfunction getAvatar(name) {\n for (const [k, v] of Object.entries(AGENT_AVATARS)) {\n if (name && name.toLowerCase().includes(k.toLowerCase())) return v;\n }\n return '🤖';\n}\n\nfunction renderMemory(m) {\n return \\`<div class=\"card\">\n <div class=\"card-title\"><span class=\"icon\">🧠</span> Memory Stats</div>\n <div class=\"stat-row\"><span class=\"stat-label\">Active facts</span><span class=\"stat-value\">\\${m.activeFacts.toLocaleString()}</span></div>\n <div class=\"stat-row\"><span class=\"stat-label\">Expired facts</span><span class=\"stat-value\">\\${m.expiredFacts.toLocaleString()}</span></div>\n <div class=\"stat-row\"><span class=\"stat-label\">Vector index</span><span class=\"stat-value\">\\${m.vectorCount.toLocaleString()}</span></div>\n <div class=\"stat-row\"><span class=\"stat-label\">SQLite size</span><span class=\"stat-value\">\\${fmtBytes(m.sqliteSizeBytes)}</span></div>\n <div class=\"stat-row\"><span class=\"stat-label\">LanceDB size</span><span class=\"stat-value\">\\${fmtBytes(m.lanceSizeBytes)}</span></div>\n <div class=\"stat-row\"><span class=\"stat-label\">Total storage</span><span class=\"stat-value\">\\${fmtBytes(m.totalSizeBytes)}</span></div>\n</div>\\`;\n}\n\nfunction renderTaskQueue(tq) {\n let html = '<div class=\"card\"><div class=\"card-title\"><span class=\"icon\">📋</span> Task Queue</div>';\n if (tq.current) {\n const c = tq.current;\n html += \\`<div class=\"task-row\">\n <div style=\"display:flex;justify-content:space-between;align-items:center\">\n <div class=\"task-title\">\\${escHtml(c.title || (c.issue != null ? '#' + c.issue : 'Current Task'))}</div>\n \\${badge(c.status)}\n </div>\n <div class=\"task-meta\">\\${c.branch ? '#' + escHtml(c.branch) + ' · ' : ''}\\${fmtDate(c.started)}</div>\n </div>\\`;\n } else {\n html += '<div class=\"stat-row\"><span class=\"stat-label\">Current</span><span class=\"badge badge-muted\">idle</span></div>';\n }\n if (tq.history && tq.history.length > 0) {\n html += '<div style=\"margin-top:8px;font-size:11px;color:var(--muted);margin-bottom:4px\">Recent</div>';\n tq.history.slice(0, 5).forEach(h => {\n html += \\`<div class=\"task-row\">\n <div style=\"display:flex;justify-content:space-between;align-items:center\">\n <div class=\"task-title\" style=\"font-size:12px\">\\${escHtml(h.title || (h.issue != null ? '#' + h.issue : '?'))}</div>\n \\${badge(h.status)}\n </div>\n <div class=\"task-meta\">\\${fmtDate(h.completed || h.started)}</div>\n </div>\\`;\n });\n }\n html += '</div>';\n return html;\n}\n\nfunction renderForge(forge) {\n let html = '<div class=\"card\"><div class=\"card-title\"><span class=\"icon\">⚒️</span> Agent Status</div>';\n if (!forge || forge.length === 0) {\n html += '<div class=\"empty\">No active agents</div>';\n } else {\n forge.forEach(f => {\n const name = f.agent || 'unknown';\n html += \\`<div class=\"agent-row\">\n <div class=\"agent-avatar\">\\${getAvatar(name)}</div>\n <div class=\"agent-info\">\n <div class=\"agent-name\">\\${escHtml(name)}</div>\n <div class=\"agent-task\">\\${escHtml(f.task || f.workdir || '')}</div>\n </div>\n <div>\\${badge(f.status)}</div>\n </div>\\`;\n });\n }\n html += '</div>';\n return html;\n}\n\nfunction renderCronJobs(jobs) {\n let html = '<div class=\"card\"><div class=\"card-title\"><span class=\"icon\">⏰</span> Cron Jobs</div>';\n if (!jobs || jobs.length === 0) {\n html += '<div class=\"empty\">No cron jobs</div>';\n } else {\n jobs.forEach(j => {\n const status = j.consecutiveErrors > 0 ? 'error' : (j.lastStatus || (j.enabled ? 'ok' : 'disabled'));\n html += \\`<div class=\"job-row\">\n <div>\n <div class=\"job-name\">\\${escHtml(j.name)}</div>\n <div class=\"job-meta\">\\${escHtml(j.schedule)} · last: \\${fmtDate(j.lastRunAt)}</div>\n \\${j.lastError ? '<div class=\"job-meta\" style=\"color:var(--red);\">' + escHtml(j.lastError.slice(0,80)) + '</div>' : ''}\n </div>\n <div>\\${badge(status)}</div>\n </div>\\`;\n });\n }\n html += '</div>';\n return html;\n}\n\nfunction renderGit(git) {\n let html = '<div class=\"card\"><div class=\"card-title\"><span class=\"icon\">🔀</span> Git Activity</div>';\n if (git.gitError) {\n html += \\`<div class=\"empty\">gh CLI unavailable</div>\\`;\n } else {\n const items = [...(git.prs || []).map(p => ({...p, kind:'PR'})), ...(git.issues || []).map(i => ({...i, kind:'Issue'}))];\n items.sort((a,b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\n if (items.length === 0) {\n html += '<div class=\"empty\">No recent activity</div>';\n } else {\n items.slice(0, 8).forEach(item => {\n const statColor = item.state === 'OPEN' ? 'green' : (item.state === 'MERGED' ? 'blue' : 'muted');\n html += \\`<div class=\"pr-row\">\n <div class=\"pr-title\"><a href=\"\\${escHtml(item.url || '#')}\" target=\"_blank\" rel=\"noopener noreferrer\">#\\${escHtml(String(item.number))} \\${escHtml(item.title)}</a></div>\n <div class=\"pr-meta\"><span class=\"badge badge-\\${statColor}\" style=\"font-size:10px\">\\${escHtml(item.state)}</span> \\${escHtml(item.kind)} · \\${fmtDate(item.createdAt)}</div>\n </div>\\`;\n });\n }\n }\n html += '</div>';\n return html;\n}\n\nfunction renderCosts(c) {\n let html = '<div class=\"card\"><div class=\"card-title\"><span class=\"icon\">💰</span> Cost Tracking (7d)</div>';\n if (!c.enabled) {\n html += '<div class=\"empty\">Cost tracking disabled</div>';\n } else if (c.features.length === 0) {\n html += '<div class=\"empty\">No LLM calls in last 7 days</div>';\n } else {\n html += \\`<div class=\"stat-row\"><span class=\"stat-label\">Total calls</span><span class=\"stat-value\">\\${c.totalCalls.toLocaleString()}</span></div>\\`;\n html += \\`<div class=\"stat-row\"><span class=\"stat-label\">Tokens in/out</span><span class=\"stat-value\">\\${c.totalInputTokens.toLocaleString()} / \\${c.totalOutputTokens.toLocaleString()}</span></div>\\`;\n html += \\`<div class=\"stat-row\" style=\"margin-bottom:8px\"><span class=\"stat-label\">Est. cost</span><span class=\"stat-value\" style=\"color:var(--green)\">$\\${c.totalEstimatedCostUsd.toFixed(4)}</span></div>\\`;\n c.features.slice(0, 6).forEach(f => {\n html += \\`<div class=\"cost-row\">\n <div class=\"cost-feature\">\\${escHtml(f.feature)}</div>\n <div class=\"cost-calls\">\\${f.calls} calls</div>\n <div class=\"cost-usd\">$\\${f.estimatedCostUsd.toFixed(4)}</div>\n </div>\\`;\n });\n }\n html += '</div>';\n return html;\n}\n\nfunction renderAgentHealth(ah) {\n let html = '<div class=\"card section-full\"><div class=\"card-title\"><span class=\"icon\">🩺</span> Agent Health</div>';\n if (!ah || !ah.enabled) {\n html += '<div class=\"empty\">Agent health store unavailable</div></div>';\n return html;\n }\n html += '<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:8px\">';\n (ah.agents || []).slice(0, 12).forEach(function (a) {\n const st = String(a.status || 'unknown');\n const badge = st === 'healthy' ? 'badge-green' : st === 'idle' ? 'badge-muted' : st === 'stale' ? 'badge-yellow' : st === 'degraded' ? 'badge-red' : 'badge-muted';\n html += '<div class=\"agent-row\" style=\"flex-direction:column;align-items:flex-start;border:1px solid var(--border);border-radius:6px;padding:8px\">';\n html += '<div style=\"display:flex;justify-content:space-between;width:100%;align-items:center\"><span class=\"agent-name\">' + escHtml(a.agentId) + '</span><span class=\"badge ' + badge + '\">' + escHtml(st) + '</span></div>';\n html += '<div class=\"task-meta\">score ' + (typeof a.score === 'number' ? a.score.toFixed(1) : '—') + ' · ' + fmtDate(new Date(a.lastSeen).toISOString()) + '</div>';\n html += '<div class=\"agent-task\">' + escHtml((a.lastTask || '').slice(0, 120)) + '</div></div>';\n });\n html += '</div>';\n if (ah.alerts && ah.alerts.length > 0) {\n html += '<div style=\"margin-top:10px;font-size:12px;color:var(--yellow)\">';\n ah.alerts.slice(0, 4).forEach(function (m) { html += '<div>⚠ ' + escHtml(m) + '</div>'; });\n html += '</div>';\n }\n html += '</div>';\n return html;\n}\n\nfunction renderAudit(a) {\n let html = '<div class=\"card section-full\"><div class=\"card-title\"><span class=\"icon\">📜</span> Audit Trail (24h)</div>';\n if (!a || !a.enabled) {\n html += '<div class=\"empty\">Audit log unavailable</div></div>';\n return html;\n }\n html += \\`<div class=\"stat-row\"><span class=\"stat-label\">Total events</span><span class=\"stat-value\">\\${a.total24h.toLocaleString()}</span></div>\\`;\n html += \\`<div class=\"stat-row\"><span class=\"stat-label\">Outcomes</span><span class=\"stat-value\">ok \\${a.byOutcome.success} · partial \\${a.byOutcome.partial} · failed \\${a.byOutcome.failed}</span></div>\\`;\n const agents = Object.entries(a.byAgent || {}).sort((x,y) => y[1] - x[1]).slice(0, 8);\n if (agents.length > 0) {\n html += '<div style=\"margin-top:8px;font-size:11px;color:var(--muted)\">By agent</div>';\n agents.forEach(([name, cnt]) => {\n html += \\`<div class=\"stat-row\"><span class=\"stat-label\">\\${escHtml(name)}</span><span class=\"stat-value\">\\${cnt}</span></div>\\`;\n });\n }\n if (a.recentFailures && a.recentFailures.length > 0) {\n html += '<div style=\"margin-top:8px;font-size:11px;color:var(--red)\">Recent failures</div>';\n a.recentFailures.slice(0, 5).forEach(f => {\n html += \\`<div class=\"task-row\"><div class=\"task-title\" style=\"font-size:12px\">\\${escHtml(f.agentId)} / \\${escHtml(f.action)}</div><div class=\"task-meta\">\\${escHtml(f.target || '')} \\${f.error ? escHtml(f.error.slice(0,120)) : ''}</div></div>\\`;\n });\n }\n html += '</div>';\n return html;\n}\n\nasync function refresh() {\n try {\n const res = await fetch('/api/status');\n const data = await res.json();\n if (!res.ok) {\n throw new Error(data.error || 'Server error');\n }\n const grid = document.getElementById('grid');\n grid.innerHTML = [\n renderMemory(data.memory),\n renderTaskQueue(data.taskQueue),\n renderForge(data.forge),\n renderCronJobs(data.cronJobs),\n renderGit(data.git),\n renderCosts(data.costs),\n renderAgentHealth(data.agentHealth),\n renderAudit(data.audit),\n ].join('');\n document.getElementById('last-updated').textContent = 'Updated ' + new Date(data.generatedAt).toLocaleTimeString();\n } catch (err) {\n document.getElementById('last-updated').textContent = 'Error: ' + err.message;\n }\n}\n\nrefresh();\nsetInterval(refresh, 60000);\n</script>\n</body>\n</html>`;\n}\n"],"mappings":";;;;;;;;;;;;AAckB,UAAUA,QAAU;AACrB,cAAc,OAAO,KAAK,GAAG;AAM9C,SAAgB,mBAA2B;CACzC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmVT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":["execFileCb"],"sources":["../../../routes/dashboard/server.ts"],"sourcesContent":["/**\n * Mission Control Dashboard — Issue #309\n *\n * Serves a web dashboard via a small HTTP server registered as a plugin service.\n * Routes:\n * GET / — HTML dashboard (vanilla JS/CSS, no framework)\n * GET /api/status — JSON data for all dashboard sections\n */\n\nimport { createServer } from \"node:http\";\nimport type { Server } from \"node:http\";\nimport { createRequire } from \"node:module\";\nimport { promisify } from \"node:util\";\nimport type { VerificationStore } from \"../../services/verification-store.js\";\nimport { pluginLogger } from \"../../utils/logger.js\";\nimport { execFile as execFileCb } from \"../../utils/process-runner.js\";\nimport { parseTags } from \"../../utils/tags.js\";\nimport { collectGraphPayload, collectGraphRecallPayload, getGraphExplorerHtml } from \"../dashboard-graph.js\";\n\nconst _execFile = promisify(execFileCb);\nconst _require = createRequire(import.meta.url);\n\nconst MAX_DASHBOARD_JSON_BODY_BYTES = 64 * 1024;\nconst _VERIFIED_FACT_SET_TTL_MS = 5000;\nconst _verifiedFactIdCacheByStore = new WeakMap<VerificationStore, { at: number; ids: Set<string> }>();\n\nimport {\n collectAgentHealth,\n collectAuditSummary,\n collectMemoryViewerEdicts,\n collectMemoryViewerEntities,\n collectMemoryViewerEpisodes,\n collectMemoryViewerIssues,\n collectMemoryViewerLinks,\n collectMemoryViewerNarratives,\n collectMemoryViewerProvenance,\n collectMemoryViewerStats,\n collectMemoryViewerVerified,\n collectMemoryViewerWorkflows,\n collectStatus,\n getVerifiedFactIdSet,\n type MemoryViewerFact,\n parseUrlPathSegment,\n performFactAction,\n readJsonBody,\n type DashboardContext,\n} from \"./collectors.js\";\nimport { getDashboardHtml } from \"./html.js\";\n\nexport interface DashboardServer {\n server: Server;\n port: number;\n close(): void;\n}\n\nexport async function createDashboardServer(ctx: DashboardContext, port: number): Promise<DashboardServer> {\n const html = getDashboardHtml();\n const { createGraphQLServer } = await import(\"../graphql-server.js\");\n const { yoga } = createGraphQLServer(ctx.factsDb, ctx.vectorDb, {\n config: ctx.cfg,\n factsDb: ctx.factsDb,\n vectorDb: ctx.vectorDb,\n embeddings: ctx.embeddings,\n embeddingRegistry: ctx.embeddingRegistry,\n });\n\n const server = createServer(async (req, res) => {\n const url = req.url ?? \"/\";\n let pathname: string;\n let searchParams: URLSearchParams;\n try {\n const parsed = new URL(url, \"http://127.0.0.1\");\n pathname = parsed.pathname;\n searchParams = parsed.searchParams;\n } catch {\n res.writeHead(400, { \"Content-Type\": \"text/plain\" });\n res.end(\"Bad Request\");\n return;\n }\n\n if (pathname === \"/graph\" || pathname === \"/graph.html\") {\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\", \"Cache-Control\": \"no-cache\" });\n res.end(getGraphExplorerHtml());\n return;\n }\n\n if (pathname === \"/api/graph\") {\n try {\n const days = Math.min(365, Math.max(1, Number.parseInt(searchParams.get(\"days\") ?? \"30\", 10) || 30));\n const maxNodes = Math.min(\n 2000,\n Math.max(20, Number.parseInt(searchParams.get(\"maxNodes\") ?? \"400\", 10) || 400),\n );\n const body = JSON.stringify(collectGraphPayload(ctx.factsDb, days, maxNodes));\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(body);\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n pluginLogger.error(`[dashboard-server] /api/graph: ${err instanceof Error ? err.message : String(err)}`);\n res.end(JSON.stringify({ error: \"InternalServerError\" }));\n }\n return;\n }\n\n if (pathname === \"/api/graph/recall\") {\n try {\n const q = searchParams.get(\"query\") ?? searchParams.get(\"q\") ?? \"\";\n const body = JSON.stringify(collectGraphRecallPayload(ctx.factsDb, q, ctx.graphHubDegreeCap));\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(body);\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n pluginLogger.error(`[dashboard-server] /api/graph/recall: ${err instanceof Error ? err.message : String(err)}`);\n res.end(JSON.stringify({ error: \"InternalServerError\" }));\n }\n return;\n }\n\n if (pathname === \"/api/agents/health\") {\n collectAgentHealth(ctx)\n .then((payload) => {\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(payload));\n })\n .catch((_err: unknown) => {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"InternalServerError\" }));\n });\n return;\n }\n\n if (pathname === \"/api/audit/summary\") {\n try {\n const body = JSON.stringify(collectAuditSummary(ctx));\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(body);\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n pluginLogger.error(\n `[dashboard-server] /api/audit/summary: ${err instanceof Error ? err.message : String(err)}`,\n );\n res.end(JSON.stringify({ error: \"InternalServerError\" }));\n }\n return;\n }\n\n if (pathname === \"/api/audit/events\") {\n if (!ctx.auditStore) {\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"audit store unavailable\" }));\n return;\n }\n try {\n const hours = Math.min(720, Math.max(1, Number.parseInt(searchParams.get(\"hours\") ?? \"24\", 10) || 24));\n const sinceMs = Date.now() - hours * 3600 * 1000;\n const agentId = searchParams.get(\"agent\") ?? undefined;\n const outcome = searchParams.get(\"outcome\") as \"success\" | \"partial\" | \"failed\" | null;\n const targetContains = searchParams.get(\"targetContains\") ?? searchParams.get(\"target\") ?? undefined;\n const rows = ctx.auditStore.query({\n sinceMs,\n agentId,\n outcome: outcome === \"success\" || outcome === \"partial\" || outcome === \"failed\" ? outcome : undefined,\n targetContains,\n limit: 2000,\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify({ events: rows }));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n pluginLogger.error(`[dashboard-server] /api/audit/events: ${err instanceof Error ? err.message : String(err)}`);\n res.end(JSON.stringify({ error: \"InternalServerError\" }));\n }\n return;\n }\n\n // Memory Viewer routes (Issue #1023)\n // GET /api/viewer/stats\n if (pathname === \"/api/viewer/stats\") {\n collectMemoryViewerStats(ctx)\n .then((stats) => {\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(stats));\n })\n .catch((err: unknown) => {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n });\n return;\n }\n\n // GET /api/viewer/facts?limit=50&offset=0&category=&tier=&entity=&search=\n if (pathname === \"/api/viewer/facts\") {\n try {\n const limit = Math.min(500, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"50\", 10)));\n const offset = Math.max(0, Number.parseInt(searchParams.get(\"offset\") ?? \"0\", 10) || 0);\n const categoryFilter = searchParams.get(\"category\") || undefined;\n const entityFilter = searchParams.get(\"entity\") || undefined;\n // #1187: honor `?tier=hot|warm|cold|structural` so operators can drill into a single tier\n // from the dashboard. Invalid tiers are dropped server-side by `listForDashboard`.\n const tierFilter = searchParams.get(\"tier\") || undefined;\n const search = searchParams.get(\"search\") || searchParams.get(\"q\") || undefined;\n\n const { facts: pageFacts, total } = ctx.factsDb.listForDashboard({\n limit,\n offset,\n category: categoryFilter,\n tier: tierFilter,\n entity: entityFilter,\n search,\n });\n const verifiedFactIds = getVerifiedFactIdSet(ctx);\n const facts: MemoryViewerFact[] = pageFacts.map((record) => {\n const id = String(record.id ?? \"\");\n return {\n id,\n text: String(record.text ?? \"\"),\n why: (record.why as string | null) ?? null,\n category: String(record.category ?? \"\"),\n importance: Number(record.importance ?? 0.5),\n entity: (record.entity as string | null) ?? null,\n key: (record.key as string | null) ?? null,\n value: (record.value as string | null) ?? null,\n source: String(record.source ?? \"\"),\n createdAt: Number(record.created_at ?? 0),\n decayClass: String(record.decay_class ?? \"\"),\n expiresAt: record.expires_at != null ? Number(record.expires_at) : null,\n confidence: Number(record.confidence ?? 0.5),\n summary: (record.summary as string | null) ?? null,\n tags: parseTags(typeof record.tags === \"string\" ? record.tags : null),\n supersededAt: record.superseded_at != null ? Number(record.superseded_at) : null,\n supersededBy: (record.superseded_by as string | null) ?? null,\n verified: verifiedFactIds.has(id),\n scope: record.scope as string | undefined,\n provenanceSession: (record.provenance_session as string | null) ?? null,\n reinforcedCount: record.reinforced_count != null ? Number(record.reinforced_count) : undefined,\n };\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify({ facts, total }));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/facts/:id\n if (req.method === \"GET\" && pathname.startsWith(\"/api/viewer/facts/\") && !pathname.endsWith(\"/provenance\")) {\n const factIdRaw = pathname.slice(\"/api/viewer/facts/\".length);\n const factId = parseUrlPathSegment(factIdRaw);\n if (!factId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing fact id\" }));\n return;\n }\n try {\n const fact = ctx.factsDb.getById(factId);\n if (!fact) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Fact not found\" }));\n return;\n }\n const verifiedFactIds = getVerifiedFactIdSet(ctx);\n const f: MemoryViewerFact = {\n id: fact.id,\n text: fact.text,\n why: fact.why,\n category: fact.category,\n importance: fact.importance,\n entity: fact.entity,\n key: fact.key,\n value: fact.value,\n source: fact.source,\n createdAt: fact.createdAt,\n decayClass: fact.decayClass,\n expiresAt: fact.expiresAt,\n confidence: fact.confidence,\n summary: fact.summary ?? null,\n tags: fact.tags ?? [],\n supersededAt: fact.supersededAt ?? null,\n supersededBy: fact.supersededBy ?? null,\n verified: verifiedFactIds.has(fact.id),\n scope: fact.scope,\n provenanceSession: fact.provenanceSession ?? null,\n reinforcedCount: fact.reinforcedCount,\n };\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(f));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/facts/:id/provenance — #1195: resolve `provenance_json.sourceEventIds`\n // into a structured panel payload (id, eventType, occurredAt, text snippet) instead of\n // dumping the JSON blob into the dashboard. Falls back to raw JSON when the event log is\n // unavailable so the UI can still render *something*.\n if (req.method === \"GET\" && /^\\/api\\/viewer\\/facts\\/[^/]+\\/provenance$/.test(pathname)) {\n const factIdRaw = pathname.replace(/^\\/api\\/viewer\\/facts\\/([^/]+)\\/provenance$/, \"$1\");\n const factId = parseUrlPathSegment(factIdRaw);\n if (!factId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing fact id\" }));\n return;\n }\n try {\n const fact = ctx.factsDb.getById(factId);\n if (!fact) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Fact not found\" }));\n return;\n }\n const raw = fact.provenanceJson ?? null;\n let parsed: {\n method?: string;\n consolidatedAt?: number;\n sourceEventIds?: string[];\n sourceEvents?: unknown[];\n } | null = null;\n if (raw) {\n try {\n parsed = JSON.parse(raw);\n } catch {\n parsed = null;\n }\n }\n const events: Array<{\n id: string;\n eventType?: string | null;\n occurredAt?: number | null;\n textPreview?: string | null;\n }> = [];\n if (parsed && Array.isArray(parsed.sourceEvents)) {\n for (const ev of parsed.sourceEvents) {\n if (!ev || typeof ev !== \"object\") continue;\n const e = ev as Record<string, unknown>;\n const id = typeof e.id === \"string\" ? e.id : null;\n if (!id) continue;\n events.push({\n id,\n eventType: typeof e.eventType === \"string\" ? e.eventType : null,\n occurredAt: typeof e.timestamp === \"number\" ? e.timestamp : null,\n textPreview: typeof e.text === \"string\" ? e.text.slice(0, 200) : null,\n });\n }\n } else if (parsed && Array.isArray(parsed.sourceEventIds)) {\n for (const id of parsed.sourceEventIds) {\n if (typeof id !== \"string\") continue;\n events.push({ id, eventType: null, occurredAt: null, textPreview: null });\n }\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(\n JSON.stringify({\n factId: fact.id,\n method: parsed?.method ?? null,\n consolidatedAt: parsed?.consolidatedAt ?? null,\n events,\n raw: parsed ?? null,\n }),\n );\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/entities\n if (pathname === \"/api/viewer/entities\") {\n try {\n const limit = Math.min(200, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"50\", 10)));\n const entities = collectMemoryViewerEntities(ctx, limit);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(entities));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/episodes\n if (pathname === \"/api/viewer/episodes\") {\n try {\n const limit = Math.min(500, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"50\", 10)));\n const episodes = collectMemoryViewerEpisodes(ctx, limit);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(episodes));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/narratives\n if (pathname === \"/api/viewer/narratives\") {\n try {\n const limit = Math.min(100, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"20\", 10)));\n const narratives = collectMemoryViewerNarratives(ctx, limit);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(narratives));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/issues\n if (pathname === \"/api/viewer/issues\") {\n try {\n const issues = collectMemoryViewerIssues(ctx);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(issues));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/workflows\n if (pathname === \"/api/viewer/workflows\") {\n try {\n const limit = Math.min(500, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"100\", 10)));\n const workflows = collectMemoryViewerWorkflows(ctx, limit);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(workflows));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/edicts\n if (pathname === \"/api/viewer/edicts\") {\n try {\n const edicts = collectMemoryViewerEdicts(ctx);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(edicts));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/verified\n if (pathname === \"/api/viewer/verified\") {\n try {\n const limit = Math.min(500, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"100\", 10)));\n const verified = collectMemoryViewerVerified(ctx, limit);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(verified));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/links\n if (pathname === \"/api/viewer/links\") {\n try {\n const limit = Math.min(10000, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"5000\", 10)));\n const links = collectMemoryViewerLinks(ctx, limit);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(links));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/provenance/:factId\n if (pathname.startsWith(\"/api/viewer/provenance/\")) {\n const factId = pathname.replace(\"/api/viewer/provenance/\", \"\");\n try {\n const prov = collectMemoryViewerProvenance(ctx, factId);\n if (!prov) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Provenance not available\" }));\n return;\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(prov));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // POST /api/viewer/facts/:id/verify\n if (req.method === \"POST\" && pathname.match(/^\\/api\\/viewer\\/facts\\/[^/]+\\/verify$/)) {\n const factIdRaw = pathname.split(\"/\")[4];\n const factId = parseUrlPathSegment(factIdRaw ?? \"\");\n if (!factId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing fact id\" }));\n return;\n }\n\n readJsonBody(req, MAX_DASHBOARD_JSON_BODY_BYTES)\n .then((parsed) => {\n const result = performFactAction(ctx, \"verify\", factId, parsed);\n res.writeHead(result.ok ? 200 : 400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n })\n .catch((err: unknown) => {\n if (err instanceof Error && err.message === \"Request body too large\") {\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"PayloadTooLarge\" }));\n return;\n }\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid JSON\" }));\n });\n return;\n }\n\n // POST /api/viewer/facts/:id/forget\n if (req.method === \"POST\" && pathname.match(/^\\/api\\/viewer\\/facts\\/[^/]+\\/forget$/)) {\n const factIdRaw = pathname.split(\"/\")[4];\n const factId = parseUrlPathSegment(factIdRaw ?? \"\");\n if (!factId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing fact id\" }));\n return;\n }\n\n // Drain any body (defensive) and enforce size.\n readJsonBody(req, MAX_DASHBOARD_JSON_BODY_BYTES)\n .then(() => {\n const result = performFactAction(ctx, \"forget\", factId, {});\n res.writeHead(result.ok ? 200 : 400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n })\n .catch((err: unknown) => {\n if (err instanceof Error && err.message === \"Request body too large\") {\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"PayloadTooLarge\" }));\n return;\n }\n // Body content is ignored for forget; malformed JSON should not block the action.\n const result = performFactAction(ctx, \"forget\", factId, {});\n res.writeHead(result.ok ? 200 : 400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n });\n return;\n }\n\n if (pathname === \"/api/status\") {\n collectStatus(ctx)\n .then((status) => {\n const body = JSON.stringify(status);\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": \"no-cache\",\n });\n res.end(body);\n })\n .catch((_err: unknown) => {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"InternalServerError\" }));\n });\n } else if (pathname === \"/\" || pathname === \"/index.html\") {\n res.writeHead(200, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-cache\",\n });\n res.end(html);\n } else if (pathname === \"/graph\") {\n // Serve the graph explorer visualization\n const { graphExplorerHTML } = await import(\"../graph-explorer.js\");\n res.writeHead(200, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-cache\",\n });\n res.end(graphExplorerHTML);\n } else if (pathname === \"/graphql\" && req.method === \"POST\") {\n // Handle GraphQL API requests using the shared Yoga server created at dashboard startup.\n try {\n const graphQlBody = await readJsonBody(req, MAX_DASHBOARD_JSON_BODY_BYTES);\n const headers = new Headers();\n for (const [name, value] of Object.entries(req.headers)) {\n if (typeof value === \"string\") headers.set(name, value);\n else if (Array.isArray(value)) headers.set(name, value.join(\", \"));\n }\n const response = await yoga.fetch(req.url || \"\", {\n method: req.method || \"POST\",\n headers,\n body: JSON.stringify(graphQlBody),\n });\n\n res.writeHead(response.status, Object.fromEntries(response.headers));\n res.end(await response.text());\n } catch (err) {\n if (err instanceof Error && err.message === \"Request body too large\") {\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"PayloadTooLarge\" }));\n return;\n }\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"InvalidGraphQLRequest\" }));\n }\n } else {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"Not found\");\n }\n });\n\n /** Attempt to bind `server` to the given port; resolves with the bound port. */\n function tryListen(targetPort: number): Promise<number> {\n return new Promise((resolve, reject) => {\n function onStartupError(err: NodeJS.ErrnoException) {\n reject(err);\n }\n server.once(\"error\", onStartupError);\n\n server.listen(targetPort, \"127.0.0.1\", () => {\n const addr = server.address();\n const boundPort = typeof addr === \"object\" && addr ? addr.port : targetPort;\n server.removeAllListeners(\"error\");\n resolve(boundPort);\n });\n });\n }\n\n let boundPort: number;\n try {\n boundPort = await tryListen(port);\n } catch (err: unknown) {\n const isAddrInUse = err instanceof Error && \"code\" in err && (err as NodeJS.ErrnoException).code === \"EADDRINUSE\";\n if (!isAddrInUse) throw err;\n\n // Port is occupied (likely a previous instance that didn't shut down\n // cleanly). Fall back to an OS-assigned ephemeral port so the dashboard\n // remains available rather than failing entirely.\n const log = ctx.logger?.error ? (m: string) => ctx.logger?.error?.(m) : (m: string) => pluginLogger.warn(m);\n log(`[dashboard-server] Port ${port} in use (EADDRINUSE), falling back to OS-assigned port`);\n server.removeAllListeners(\"listening\");\n boundPort = await tryListen(0);\n }\n\n // Install permanent error handler now that the server is bound.\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n const errMsg = err instanceof Error ? err.message : String(err);\n if (ctx.logger?.error) {\n ctx.logger.error(`[dashboard-server] Server error: ${errMsg}`);\n } else {\n pluginLogger.error(`[dashboard-server] Server error: ${errMsg}`);\n }\n });\n\n return {\n server,\n port: boundPort,\n close() {\n server.close();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","names":["execFileCb"],"sources":["../../../routes/dashboard/server.ts"],"sourcesContent":["/**\n * Mission Control Dashboard — Issue #309\n *\n * Serves a web dashboard via a small HTTP server registered as a plugin service.\n * Routes:\n * GET / — HTML dashboard (vanilla JS/CSS, no framework)\n * GET /api/status — JSON data for all dashboard sections\n */\n\nimport { createServer } from \"node:http\";\nimport type { Server } from \"node:http\";\nimport { createRequire } from \"node:module\";\nimport { promisify } from \"node:util\";\nimport type { VerificationStore } from \"../../services/verification-store.js\";\nimport { pluginLogger } from \"../../utils/logger.js\";\nimport { execFile as execFileCb } from \"../../utils/process-runner.js\";\nimport { parseTags } from \"../../utils/tags.js\";\nimport { collectGraphPayload, collectGraphRecallPayload, getGraphExplorerHtml } from \"../dashboard-graph.js\";\n\nconst _execFile = promisify(execFileCb);\nconst _require = createRequire(import.meta.url);\n\nconst MAX_DASHBOARD_JSON_BODY_BYTES = 64 * 1024;\nconst _VERIFIED_FACT_SET_TTL_MS = 5000;\nconst _verifiedFactIdCacheByStore = new WeakMap<VerificationStore, { at: number; ids: Set<string> }>();\n\nimport {\n collectAgentHealth,\n collectAuditSummary,\n collectMemoryViewerEdicts,\n collectMemoryViewerEntities,\n collectMemoryViewerEpisodes,\n collectMemoryViewerIssues,\n collectMemoryViewerLinks,\n collectMemoryViewerNarratives,\n collectMemoryViewerProvenance,\n collectMemoryViewerStats,\n collectMemoryViewerVerified,\n collectMemoryViewerWorkflows,\n collectStatus,\n getVerifiedFactIdSet,\n type MemoryViewerFact,\n parseUrlPathSegment,\n performFactAction,\n readJsonBody,\n type DashboardContext,\n} from \"./collectors.js\";\nimport { getDashboardHtml } from \"./html.js\";\n\nexport interface DashboardServer {\n server: Server;\n port: number;\n close(): void;\n}\n\nexport async function createDashboardServer(ctx: DashboardContext, port: number): Promise<DashboardServer> {\n const html = getDashboardHtml();\n const { createGraphQLServer } = await import(\"../graphql-server.js\");\n const { yoga } = createGraphQLServer(ctx.factsDb, ctx.vectorDb, {\n config: ctx.cfg,\n factsDb: ctx.factsDb,\n vectorDb: ctx.vectorDb,\n embeddings: ctx.embeddings,\n embeddingRegistry: ctx.embeddingRegistry,\n });\n\n const server = createServer(async (req, res) => {\n const url = req.url ?? \"/\";\n let pathname: string;\n let searchParams: URLSearchParams;\n try {\n const parsed = new URL(url, \"http://127.0.0.1\");\n pathname = parsed.pathname;\n searchParams = parsed.searchParams;\n } catch {\n res.writeHead(400, { \"Content-Type\": \"text/plain\" });\n res.end(\"Bad Request\");\n return;\n }\n\n if (pathname === \"/graph\" || pathname === \"/graph.html\") {\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\", \"Cache-Control\": \"no-cache\" });\n res.end(getGraphExplorerHtml());\n return;\n }\n\n if (pathname === \"/api/graph\") {\n try {\n const days = Math.min(365, Math.max(1, Number.parseInt(searchParams.get(\"days\") ?? \"30\", 10) || 30));\n const maxNodes = Math.min(\n 2000,\n Math.max(20, Number.parseInt(searchParams.get(\"maxNodes\") ?? \"400\", 10) || 400),\n );\n const body = JSON.stringify(collectGraphPayload(ctx.factsDb, days, maxNodes));\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(body);\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n pluginLogger.error(`[dashboard-server] /api/graph: ${err instanceof Error ? err.message : String(err)}`);\n res.end(JSON.stringify({ error: \"InternalServerError\" }));\n }\n return;\n }\n\n if (pathname === \"/api/graph/recall\") {\n try {\n const q = searchParams.get(\"query\") ?? searchParams.get(\"q\") ?? \"\";\n const body = JSON.stringify(collectGraphRecallPayload(ctx.factsDb, q, ctx.graphHubDegreeCap));\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(body);\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n pluginLogger.error(`[dashboard-server] /api/graph/recall: ${err instanceof Error ? err.message : String(err)}`);\n res.end(JSON.stringify({ error: \"InternalServerError\" }));\n }\n return;\n }\n\n if (pathname === \"/api/agents/health\") {\n collectAgentHealth(ctx)\n .then((payload) => {\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(payload));\n })\n .catch((_err: unknown) => {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"InternalServerError\" }));\n });\n return;\n }\n\n if (pathname === \"/api/audit/summary\") {\n try {\n const body = JSON.stringify(collectAuditSummary(ctx));\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(body);\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n pluginLogger.error(\n `[dashboard-server] /api/audit/summary: ${err instanceof Error ? err.message : String(err)}`,\n );\n res.end(JSON.stringify({ error: \"InternalServerError\" }));\n }\n return;\n }\n\n if (pathname === \"/api/audit/events\") {\n if (!ctx.auditStore) {\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"audit store unavailable\" }));\n return;\n }\n try {\n const hours = Math.min(720, Math.max(1, Number.parseInt(searchParams.get(\"hours\") ?? \"24\", 10) || 24));\n const sinceMs = Date.now() - hours * 3600 * 1000;\n const agentId = searchParams.get(\"agent\") ?? undefined;\n const outcome = searchParams.get(\"outcome\") as \"success\" | \"partial\" | \"failed\" | null;\n const targetContains = searchParams.get(\"targetContains\") ?? searchParams.get(\"target\") ?? undefined;\n const rows = ctx.auditStore.query({\n sinceMs,\n agentId,\n outcome: outcome === \"success\" || outcome === \"partial\" || outcome === \"failed\" ? outcome : undefined,\n targetContains,\n limit: 2000,\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify({ events: rows }));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n pluginLogger.error(`[dashboard-server] /api/audit/events: ${err instanceof Error ? err.message : String(err)}`);\n res.end(JSON.stringify({ error: \"InternalServerError\" }));\n }\n return;\n }\n\n // Memory Viewer routes (Issue #1023)\n // GET /api/viewer/stats\n if (pathname === \"/api/viewer/stats\") {\n collectMemoryViewerStats(ctx)\n .then((stats) => {\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(stats));\n })\n .catch((err: unknown) => {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n });\n return;\n }\n\n // GET /api/viewer/facts?limit=50&offset=0&category=&tier=&entity=&search=\n if (pathname === \"/api/viewer/facts\") {\n try {\n const limit = Math.min(500, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"50\", 10)));\n const offset = Math.max(0, Number.parseInt(searchParams.get(\"offset\") ?? \"0\", 10) || 0);\n const categoryFilter = searchParams.get(\"category\") || undefined;\n const entityFilter = searchParams.get(\"entity\") || undefined;\n // #1187: honor `?tier=hot|warm|cold|structural` so operators can drill into a single tier\n // from the dashboard. Invalid tiers are dropped server-side by `listForDashboard`.\n const tierFilter = searchParams.get(\"tier\") || undefined;\n const search = searchParams.get(\"search\") || searchParams.get(\"q\") || undefined;\n\n const { facts: pageFacts, total } = ctx.factsDb.listForDashboard({\n limit,\n offset,\n category: categoryFilter,\n tier: tierFilter,\n entity: entityFilter,\n search,\n });\n const verifiedFactIds = getVerifiedFactIdSet(ctx);\n const facts: MemoryViewerFact[] = pageFacts.map((record) => {\n const id = String(record.id ?? \"\");\n return {\n id,\n text: String(record.text ?? \"\"),\n why: (record.why as string | null) ?? null,\n category: String(record.category ?? \"\"),\n importance: Number(record.importance ?? 0.5),\n entity: (record.entity as string | null) ?? null,\n key: (record.key as string | null) ?? null,\n value: (record.value as string | null) ?? null,\n source: String(record.source ?? \"\"),\n createdAt: Number(record.created_at ?? 0),\n decayClass: String(record.decay_class ?? \"\"),\n expiresAt: record.expires_at != null ? Number(record.expires_at) : null,\n confidence: Number(record.confidence ?? 0.5),\n summary: (record.summary as string | null) ?? null,\n tags: parseTags(typeof record.tags === \"string\" ? record.tags : null),\n supersededAt: record.superseded_at != null ? Number(record.superseded_at) : null,\n supersededBy: (record.superseded_by as string | null) ?? null,\n verified: verifiedFactIds.has(id),\n scope: record.scope as string | undefined,\n provenanceSession: (record.provenance_session as string | null) ?? null,\n reinforcedCount: record.reinforced_count != null ? Number(record.reinforced_count) : undefined,\n };\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify({ facts, total }));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/facts/:id\n if (req.method === \"GET\" && pathname.startsWith(\"/api/viewer/facts/\") && !pathname.endsWith(\"/provenance\")) {\n const factIdRaw = pathname.slice(\"/api/viewer/facts/\".length);\n const factId = parseUrlPathSegment(factIdRaw);\n if (!factId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing fact id\" }));\n return;\n }\n try {\n const fact = ctx.factsDb.getById(factId);\n if (!fact) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Fact not found\" }));\n return;\n }\n const verifiedFactIds = getVerifiedFactIdSet(ctx);\n const f: MemoryViewerFact = {\n id: fact.id,\n text: fact.text,\n why: fact.why,\n category: fact.category,\n importance: fact.importance,\n entity: fact.entity,\n key: fact.key,\n value: fact.value,\n source: fact.source,\n createdAt: fact.createdAt,\n decayClass: fact.decayClass,\n expiresAt: fact.expiresAt,\n confidence: fact.confidence,\n summary: fact.summary ?? null,\n tags: fact.tags ?? [],\n supersededAt: fact.supersededAt ?? null,\n supersededBy: fact.supersededBy ?? null,\n verified: verifiedFactIds.has(fact.id),\n scope: fact.scope,\n provenanceSession: fact.provenanceSession ?? null,\n reinforcedCount: fact.reinforcedCount,\n };\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(f));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/facts/:id/provenance — #1195: resolve `provenance_json.sourceEventIds`\n // into a structured panel payload (id, eventType, occurredAt, text snippet) instead of\n // dumping the JSON blob into the dashboard. Falls back to raw JSON when the event log is\n // unavailable so the UI can still render *something*.\n if (req.method === \"GET\" && /^\\/api\\/viewer\\/facts\\/[^/]+\\/provenance$/.test(pathname)) {\n const factIdRaw = pathname.replace(/^\\/api\\/viewer\\/facts\\/([^/]+)\\/provenance$/, \"$1\");\n const factId = parseUrlPathSegment(factIdRaw);\n if (!factId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing fact id\" }));\n return;\n }\n try {\n const fact = ctx.factsDb.getById(factId);\n if (!fact) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Fact not found\" }));\n return;\n }\n const raw = fact.provenanceJson ?? null;\n let parsed: {\n method?: string;\n consolidatedAt?: number;\n sourceEventIds?: string[];\n sourceEvents?: unknown[];\n } | null = null;\n if (raw) {\n try {\n parsed = JSON.parse(raw);\n } catch {\n parsed = null;\n }\n }\n const events: Array<{\n id: string;\n eventType?: string | null;\n occurredAt?: number | null;\n textPreview?: string | null;\n }> = [];\n if (parsed && Array.isArray(parsed.sourceEvents)) {\n for (const ev of parsed.sourceEvents) {\n if (!ev || typeof ev !== \"object\") continue;\n const e = ev as Record<string, unknown>;\n const id = typeof e.id === \"string\" ? e.id : null;\n if (!id) continue;\n events.push({\n id,\n eventType: typeof e.eventType === \"string\" ? e.eventType : null,\n occurredAt: typeof e.timestamp === \"number\" ? e.timestamp : null,\n textPreview: typeof e.text === \"string\" ? e.text.slice(0, 200) : null,\n });\n }\n } else if (parsed && Array.isArray(parsed.sourceEventIds)) {\n for (const id of parsed.sourceEventIds) {\n if (typeof id !== \"string\") continue;\n events.push({ id, eventType: null, occurredAt: null, textPreview: null });\n }\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(\n JSON.stringify({\n factId: fact.id,\n method: parsed?.method ?? null,\n consolidatedAt: parsed?.consolidatedAt ?? null,\n events,\n raw: parsed ?? null,\n }),\n );\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/entities\n if (pathname === \"/api/viewer/entities\") {\n try {\n const limit = Math.min(200, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"50\", 10)));\n const entities = collectMemoryViewerEntities(ctx, limit);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(entities));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/episodes\n if (pathname === \"/api/viewer/episodes\") {\n try {\n const limit = Math.min(500, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"50\", 10)));\n const episodes = collectMemoryViewerEpisodes(ctx, limit);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(episodes));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/narratives\n if (pathname === \"/api/viewer/narratives\") {\n try {\n const limit = Math.min(100, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"20\", 10)));\n const narratives = collectMemoryViewerNarratives(ctx, limit);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(narratives));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/issues\n if (pathname === \"/api/viewer/issues\") {\n try {\n const issues = collectMemoryViewerIssues(ctx);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(issues));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/workflows\n if (pathname === \"/api/viewer/workflows\") {\n try {\n const limit = Math.min(500, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"100\", 10)));\n const workflows = collectMemoryViewerWorkflows(ctx, limit);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(workflows));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/edicts\n if (pathname === \"/api/viewer/edicts\") {\n try {\n const edicts = collectMemoryViewerEdicts(ctx);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(edicts));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/verified\n if (pathname === \"/api/viewer/verified\") {\n try {\n const limit = Math.min(500, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"100\", 10)));\n const verified = collectMemoryViewerVerified(ctx, limit);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(verified));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/links\n if (pathname === \"/api/viewer/links\") {\n try {\n const limit = Math.min(10000, Math.max(1, Number.parseInt(searchParams.get(\"limit\") ?? \"5000\", 10)));\n const links = collectMemoryViewerLinks(ctx, limit);\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(links));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // GET /api/viewer/provenance/:factId\n if (pathname.startsWith(\"/api/viewer/provenance/\")) {\n const factId = pathname.replace(\"/api/viewer/provenance/\", \"\");\n try {\n const prov = collectMemoryViewerProvenance(ctx, factId);\n if (!prov) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Provenance not available\" }));\n return;\n }\n res.writeHead(200, { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-cache\" });\n res.end(JSON.stringify(prov));\n } catch (err: unknown) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(err) }));\n }\n return;\n }\n\n // POST /api/viewer/facts/:id/verify\n if (req.method === \"POST\" && pathname.match(/^\\/api\\/viewer\\/facts\\/[^/]+\\/verify$/)) {\n const factIdRaw = pathname.split(\"/\")[4];\n const factId = parseUrlPathSegment(factIdRaw ?? \"\");\n if (!factId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing fact id\" }));\n return;\n }\n\n readJsonBody(req, MAX_DASHBOARD_JSON_BODY_BYTES)\n .then((parsed) => {\n const result = performFactAction(ctx, \"verify\", factId, parsed);\n res.writeHead(result.ok ? 200 : 400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n })\n .catch((err: unknown) => {\n if (err instanceof Error && err.message === \"Request body too large\") {\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"PayloadTooLarge\" }));\n return;\n }\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid JSON\" }));\n });\n return;\n }\n\n // POST /api/viewer/facts/:id/forget\n if (req.method === \"POST\" && pathname.match(/^\\/api\\/viewer\\/facts\\/[^/]+\\/forget$/)) {\n const factIdRaw = pathname.split(\"/\")[4];\n const factId = parseUrlPathSegment(factIdRaw ?? \"\");\n if (!factId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Missing fact id\" }));\n return;\n }\n\n // Drain any body (defensive) and enforce size.\n readJsonBody(req, MAX_DASHBOARD_JSON_BODY_BYTES)\n .then(() => {\n const result = performFactAction(ctx, \"forget\", factId, {});\n res.writeHead(result.ok ? 200 : 400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n })\n .catch((err: unknown) => {\n if (err instanceof Error && err.message === \"Request body too large\") {\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"PayloadTooLarge\" }));\n return;\n }\n // Body content is ignored for forget; malformed JSON should not block the action.\n const result = performFactAction(ctx, \"forget\", factId, {});\n res.writeHead(result.ok ? 200 : 400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n });\n return;\n }\n\n if (pathname === \"/api/status\") {\n collectStatus(ctx)\n .then((status) => {\n const body = JSON.stringify(status);\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": \"no-cache\",\n });\n res.end(body);\n })\n .catch((_err: unknown) => {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"InternalServerError\" }));\n });\n } else if (pathname === \"/\" || pathname === \"/index.html\") {\n res.writeHead(200, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-cache\",\n });\n res.end(html);\n } else if (pathname === \"/graph\") {\n // Serve the graph explorer visualization\n const { graphExplorerHTML } = await import(\"../graph-explorer.js\");\n res.writeHead(200, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-cache\",\n });\n res.end(graphExplorerHTML);\n } else if (pathname === \"/graphql\" && req.method === \"POST\") {\n // Handle GraphQL API requests using the shared Yoga server created at dashboard startup.\n try {\n const graphQlBody = await readJsonBody(req, MAX_DASHBOARD_JSON_BODY_BYTES);\n const headers = new Headers();\n for (const [name, value] of Object.entries(req.headers)) {\n if (typeof value === \"string\") headers.set(name, value);\n else if (Array.isArray(value)) headers.set(name, value.join(\", \"));\n }\n const response = await yoga.fetch(req.url || \"\", {\n method: req.method || \"POST\",\n headers,\n body: JSON.stringify(graphQlBody),\n });\n\n res.writeHead(response.status, Object.fromEntries(response.headers));\n res.end(await response.text());\n } catch (err) {\n if (err instanceof Error && err.message === \"Request body too large\") {\n res.writeHead(413, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"PayloadTooLarge\" }));\n return;\n }\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"InvalidGraphQLRequest\" }));\n }\n } else {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"Not found\");\n }\n });\n\n /** Attempt to bind `server` to the given port; resolves with the bound port. */\n function tryListen(targetPort: number): Promise<number> {\n return new Promise((resolve, reject) => {\n function onStartupError(err: NodeJS.ErrnoException) {\n reject(err);\n }\n server.once(\"error\", onStartupError);\n\n server.listen(targetPort, \"127.0.0.1\", () => {\n const addr = server.address();\n const boundPort = typeof addr === \"object\" && addr ? addr.port : targetPort;\n server.removeAllListeners(\"error\");\n resolve(boundPort);\n });\n });\n }\n\n let boundPort: number;\n try {\n boundPort = await tryListen(port);\n } catch (err: unknown) {\n const isAddrInUse = err instanceof Error && \"code\" in err && (err as NodeJS.ErrnoException).code === \"EADDRINUSE\";\n if (!isAddrInUse) throw err;\n\n // Port is occupied (likely a previous instance that didn't shut down\n // cleanly). Fall back to an OS-assigned ephemeral port so the dashboard\n // remains available rather than failing entirely.\n const log = ctx.logger?.error ? (m: string) => ctx.logger?.error?.(m) : (m: string) => pluginLogger.warn(m);\n log(`[dashboard-server] Port ${port} in use (EADDRINUSE), falling back to OS-assigned port`);\n server.removeAllListeners(\"listening\");\n boundPort = await tryListen(0);\n }\n\n // Install permanent error handler now that the server is bound.\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n const errMsg = err instanceof Error ? err.message : String(err);\n if (ctx.logger?.error) {\n ctx.logger.error(`[dashboard-server] Server error: ${errMsg}`);\n } else {\n pluginLogger.error(`[dashboard-server] Server error: ${errMsg}`);\n }\n });\n\n return {\n server,\n port: boundPort,\n close() {\n server.close();\n },\n };\n}\n"],"mappings":"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"}
|