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":"dashboard-graph.js","names":[],"sources":["../../routes/dashboard-graph.ts"],"sourcesContent":["/**\n * Memory graph API + explorer page (Issue #788).\n */\n\nimport type { FactsDB } from \"../backends/facts-db.js\";\nimport type { GraphConnectedStats } from \"../backends/facts-db/links.js\";\nimport { expandGraph, resolveGraphHubDegreeCap, type GraphExpansionStats } from \"../services/graph-retrieval.js\";\n\ninterface MemoryGraphNode {\n id: string;\n label: string;\n category: string;\n importance: number;\n decayClass: string;\n provenance?: unknown;\n}\n\nfunction parseProvenance(raw: string | null): unknown | undefined {\n if (!raw) return undefined;\n try {\n return JSON.parse(raw);\n } catch {\n return undefined;\n }\n}\n\ninterface MemoryGraphEdge {\n source: string;\n target: string;\n linkType: string;\n strength: number;\n}\n\ninterface GraphPayload {\n generatedAt: string;\n nodes: MemoryGraphNode[];\n edges: MemoryGraphEdge[];\n}\n\ninterface GraphRecallPayload extends GraphPayload {\n activated: string[];\n /** Hub-guard observability for recall graph (Issue #1192). */\n graphHubGuard?: {\n configuredCap: number | null | undefined;\n effectiveCap: number | null;\n connected: GraphConnectedStats;\n expansion: GraphExpansionStats;\n };\n}\n\nexport function collectGraphPayload(factsDb: FactsDB, days: number, maxNodes: number): GraphPayload {\n const nowSec = Math.floor(Date.now() / 1000);\n const cutoff = nowSec - days * 86400;\n const capped = Math.min(2000, Math.max(20, maxNodes));\n const db = factsDb.getRawDb();\n const rows = db\n .prepare(\n \"SELECT id, text, category, importance, decay_class, provenance_json FROM facts WHERE superseded_at IS NULL AND (expires_at IS NULL OR expires_at > ?) AND created_at >= ? ORDER BY created_at DESC LIMIT ?\",\n )\n .all(nowSec, cutoff, capped) as Array<{\n id: string;\n text: string;\n category: string;\n importance: number;\n decay_class: string | null;\n provenance_json: string | null;\n }>;\n const idSet = new Set(rows.map((r) => r.id));\n const allEdges = factsDb.getAllEdges(12000);\n const edges = allEdges.filter((e) => idSet.has(e.source) && idSet.has(e.target)).slice(0, 2000);\n const nodes: MemoryGraphNode[] = rows.map((r) => ({\n id: r.id,\n label: r.text.length > 120 ? `${r.text.slice(0, 120)}…` : r.text,\n category: r.category,\n importance: r.importance,\n decayClass: r.decay_class ?? \"stable\",\n provenance: parseProvenance(r.provenance_json),\n }));\n return {\n generatedAt: new Date().toISOString(),\n nodes,\n edges: edges.map((e) => ({\n source: e.source,\n target: e.target,\n linkType: e.linkType,\n strength: e.strength,\n })),\n };\n}\n\nfunction collectDashboardConnectedIds(\n factsDb: FactsDB,\n seeds: string[],\n maxDepth: number,\n hubDegreeCap: number | null | undefined,\n stats?: GraphConnectedStats,\n): string[] {\n if (seeds.length === 0) return [];\n const cap = hubDegreeCap === undefined ? 500 : hubDegreeCap;\n return factsDb.getConnectedFactIds(seeds, maxDepth, { hubDegreeCap: cap, stats });\n}\n\nexport function collectGraphRecallPayload(\n factsDb: FactsDB,\n query: string,\n hubDegreeCap?: number | null,\n): GraphRecallPayload {\n const q = query.trim();\n if (!q) {\n return { generatedAt: new Date().toISOString(), nodes: [], edges: [], activated: [] };\n }\n const results = factsDb.search(q, 12, {\n includeSuperseded: false,\n reinforcementBoost: 0.1,\n diversityWeight: 1,\n });\n const seeds = results.map((r) => r.entry.id);\n const connected: GraphConnectedStats = { nodesConsidered: 0, nodesSkipped: 0, hubsSkipped: 0 };\n const ids = collectDashboardConnectedIds(factsDb, seeds, 3, hubDegreeCap, connected).slice(0, 2000);\n const seedInputs = results.map((r) => ({ factId: r.entry.id, score: r.score, entry: r.entry }));\n const { stats: expansion } = expandGraph(factsDb, seedInputs, {\n maxDepth: 3,\n maxExpandedResults: 20,\n hubDegreeCap,\n });\n const entryMap = factsDb.getByIds(ids);\n const nodes: MemoryGraphNode[] = [];\n for (const id of ids) {\n const f = entryMap.get(id);\n if (!f) continue;\n nodes.push({\n id: f.id,\n label: f.text.length > 120 ? `${f.text.slice(0, 120)}…` : f.text,\n category: f.category,\n importance: f.importance,\n decayClass: f.decayClass ?? \"stable\",\n provenance: parseProvenance(f.provenanceJson ?? null),\n });\n }\n const nodeIdSet = new Set(nodes.map((n) => n.id));\n const allEdges = factsDb.getAllEdges(10000);\n const edges = allEdges.filter((e) => nodeIdSet.has(e.source) && nodeIdSet.has(e.target)).slice(0, 2000);\n return {\n generatedAt: new Date().toISOString(),\n nodes,\n edges: edges.map((e) => ({\n source: e.source,\n target: e.target,\n linkType: e.linkType,\n strength: e.strength,\n })),\n activated: seeds,\n graphHubGuard: {\n configuredCap: hubDegreeCap,\n effectiveCap: resolveGraphHubDegreeCap(hubDegreeCap),\n connected,\n expansion,\n },\n };\n}\n\nexport function getGraphExplorerHtml(): 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>Memory Graph</title>\n<script src=\"https://cdn.jsdelivr.net/npm/d3@7\"></script>\n<style>\n :root { --bg:#0f1117; --surface:#1a1d27; --border:#2a2d3a; --text:#e2e8f0; --muted:#8892a4; }\n body { margin:0; background:var(--bg); color:var(--text); font-family:system-ui,sans-serif; font-size:13px; }\n header { padding:12px 16px; border-bottom:1px solid var(--border); display:flex; flex-wrap:wrap; gap:8px; align-items:center; }\n h1 { margin:0; font-size:16px; color:#3b82f6; }\n #graph { width:100%; height:calc(100vh - 56px); }\n .panel { background:var(--surface); border:1px solid var(--border); border-radius:6px; padding:8px; max-width:420px; font-size:12px; max-height:160px; overflow:auto; }\n input[type=\"search\"] { background:#0b0d12; border:1px solid var(--border); color:var(--text); padding:6px 10px; border-radius:6px; min-width:200px; }\n button { background:#2563eb; color:#fff; border:none; padding:6px 12px; border-radius:6px; cursor:pointer; }\n button:hover { filter:brightness(1.1); }\n .legend { font-size:11px; color:var(--muted); }\n</style>\n</head>\n<body>\n<header>\n <h1>Memory graph</h1>\n <input type=\"search\" id=\"q\" placeholder=\"Recall subgraph (FTS search)…\" />\n <button type=\"button\" id=\"go\">Highlight recall</button>\n <span class=\"legend\">SUPERSEDES · RELATED_TO · PART_OF · CAUSED_BY · DEPENDS_ON · edges colored · drag nodes</span>\n</header>\n<div id=\"detail\" class=\"panel\" style=\"margin:8px;display:none\"></div>\n<svg id=\"graph\"></svg>\n<script>\nconst LINK_COLORS = { SUPERSEDES:'#ef4444', RELATED_TO:'#6b7280', PART_OF:'#3b82f6', CAUSED_BY:'#a855f7', DEPENDS_ON:'#f97316', INSTANCE_OF:'#22c55e', CONTRADICTS:'#f43f5e' };\nconst CAT_COLORS = { fact:'#3b82f6', preference:'#22c55e', decision:'#eab308', entity:'#a855f7', episode:'#c084fc', procedure:'#f97316', pattern:'#14b8a6', rule:'#f59e0b', other:'#64748b' };\n\nlet sim, svg, link, node, pulse;\n\nasync function loadBase() {\n const res = await fetch('/api/graph?days=30&maxNodes=400');\n if (!res.ok) {\n throw new Error(\\`Failed to load graph: \\${res.status} \\${res.statusText}\\`);\n }\n return res.json();\n}\n\nasync function loadRecall(q) {\n const res = await fetch('/api/graph/recall?' + new URLSearchParams({ query: q }));\n if (!res.ok) {\n throw new Error(\\`Failed to load recall graph: \\${res.status} \\${res.statusText}\\`);\n }\n return res.json();\n}\n\nfunction buildGraph(data) {\n if (sim) sim.stop();\n const width = window.innerWidth;\n const height = window.innerHeight - 56;\n d3.select('#graph').selectAll('*').remove();\n svg = d3.select('#graph').attr('width', width).attr('height', height);\n const g = svg.append('g');\n const zoom = d3.zoom().scaleExtent([0.2, 4]).on('zoom', (e) => g.attr('transform', e.transform));\n svg.call(zoom);\n\n const nodes = data.nodes.map(d => ({...d}));\n const nodeById = new Map(nodes.map(n => [n.id, n]));\n const links = data.edges.map(d => ({\n source: nodeById.get(d.source),\n target: nodeById.get(d.target),\n linkType: d.linkType,\n strength: d.strength\n })).filter(l => l.source && l.target);\n\n sim = d3.forceSimulation(nodes)\n .force('link', d3.forceLink(links).id(d => d.id).distance(45).strength(0.35))\n .force('charge', d3.forceManyBody().strength(-120))\n .force('center', d3.forceCenter(width/2, height/2))\n .force('collide', d3.forceCollide().radius(d => 6 + (d.importance || 0.5) * 10));\n\n link = g.append('g').attr('stroke', '#555').selectAll('line')\n .data(links).join('line')\n .attr('stroke-width', d => 0.5 + (d.strength || 0.5))\n .attr('stroke', d => LINK_COLORS[d.linkType] || '#6b7280');\n\n node = g.append('g').selectAll('circle')\n .data(nodes).join('circle')\n .attr('r', d => 5 + (d.importance || 0.5) * 8)\n .attr('fill', d => CAT_COLORS[d.category] || CAT_COLORS.other)\n .attr('opacity', d => {\n const dc = (d.decayClass || '').toLowerCase();\n if (dc.includes('ephemeral') || dc.includes('short')) return 0.55;\n return 0.92;\n })\n .call(d3.drag()\n .on('start', (e, d) => { if (!e.active) sim.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; })\n .on('drag', (e, d) => { d.fx = e.x; d.fy = e.y; })\n .on('end', (e, d) => { if (!e.active) sim.alphaTarget(0); d.fx = null; d.fy = null; }))\n .on('click', (e, d) => {\n const el = document.getElementById('detail');\n el.style.display = 'block';\n el.textContent = d.provenance ? d.label + '\\n\\nProvenance: ' + JSON.stringify(d.provenance, null, 2) : d.label;\n });\n\n pulse = new Set((data.activated || []).filter(Boolean));\n if (pulse.size) {\n node.attr('stroke', d => pulse.has(d.id) ? '#fff' : 'none').attr('stroke-width', d => pulse.has(d.id) ? 2 : 0);\n }\n\n sim.on('tick', () => {\n link\n .attr('x1', d => d.source.x).attr('y1', d => d.source.y)\n .attr('x2', d => d.target.x).attr('y2', d => d.target.y);\n node.attr('cx', d => d.x).attr('cy', d => d.y);\n });\n}\n\n(async () => {\n try {\n const data = await loadBase();\n buildGraph(data);\n document.getElementById('go').onclick = async () => {\n const q = document.getElementById('q').value.trim();\n try {\n if (!q) {\n buildGraph(await loadBase());\n return;\n }\n buildGraph(await loadRecall(q));\n } catch (err) {\n const el = document.getElementById('detail');\n el.style.display = 'block';\n el.style.color = '#ef4444';\n el.textContent = 'Error: ' + (err.message || String(err));\n }\n };\n } catch (err) {\n const el = document.getElementById('detail');\n el.style.display = 'block';\n el.style.color = '#ef4444';\n el.textContent = 'Error loading graph: ' + (err.message || String(err));\n }\n})();\n</script>\n</body>\n</html>`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dashboard-graph.js","names":[],"sources":["../../routes/dashboard-graph.ts"],"sourcesContent":["/**\n * Memory graph API + explorer page (Issue #788).\n */\n\nimport type { FactsDB } from \"../backends/facts-db.js\";\nimport type { GraphConnectedStats } from \"../backends/facts-db/links.js\";\nimport { expandGraph, resolveGraphHubDegreeCap, type GraphExpansionStats } from \"../services/graph-retrieval.js\";\n\ninterface MemoryGraphNode {\n id: string;\n label: string;\n category: string;\n importance: number;\n decayClass: string;\n provenance?: unknown;\n}\n\nfunction parseProvenance(raw: string | null): unknown | undefined {\n if (!raw) return undefined;\n try {\n return JSON.parse(raw);\n } catch {\n return undefined;\n }\n}\n\ninterface MemoryGraphEdge {\n source: string;\n target: string;\n linkType: string;\n strength: number;\n}\n\ninterface GraphPayload {\n generatedAt: string;\n nodes: MemoryGraphNode[];\n edges: MemoryGraphEdge[];\n}\n\ninterface GraphRecallPayload extends GraphPayload {\n activated: string[];\n /** Hub-guard observability for recall graph (Issue #1192). */\n graphHubGuard?: {\n configuredCap: number | null | undefined;\n effectiveCap: number | null;\n connected: GraphConnectedStats;\n expansion: GraphExpansionStats;\n };\n}\n\nexport function collectGraphPayload(factsDb: FactsDB, days: number, maxNodes: number): GraphPayload {\n const nowSec = Math.floor(Date.now() / 1000);\n const cutoff = nowSec - days * 86400;\n const capped = Math.min(2000, Math.max(20, maxNodes));\n const db = factsDb.getRawDb();\n const rows = db\n .prepare(\n \"SELECT id, text, category, importance, decay_class, provenance_json FROM facts WHERE superseded_at IS NULL AND (expires_at IS NULL OR expires_at > ?) AND created_at >= ? ORDER BY created_at DESC LIMIT ?\",\n )\n .all(nowSec, cutoff, capped) as Array<{\n id: string;\n text: string;\n category: string;\n importance: number;\n decay_class: string | null;\n provenance_json: string | null;\n }>;\n const idSet = new Set(rows.map((r) => r.id));\n const allEdges = factsDb.getAllEdges(12000);\n const edges = allEdges.filter((e) => idSet.has(e.source) && idSet.has(e.target)).slice(0, 2000);\n const nodes: MemoryGraphNode[] = rows.map((r) => ({\n id: r.id,\n label: r.text.length > 120 ? `${r.text.slice(0, 120)}…` : r.text,\n category: r.category,\n importance: r.importance,\n decayClass: r.decay_class ?? \"stable\",\n provenance: parseProvenance(r.provenance_json),\n }));\n return {\n generatedAt: new Date().toISOString(),\n nodes,\n edges: edges.map((e) => ({\n source: e.source,\n target: e.target,\n linkType: e.linkType,\n strength: e.strength,\n })),\n };\n}\n\nfunction collectDashboardConnectedIds(\n factsDb: FactsDB,\n seeds: string[],\n maxDepth: number,\n hubDegreeCap: number | null | undefined,\n stats?: GraphConnectedStats,\n): string[] {\n if (seeds.length === 0) return [];\n const cap = hubDegreeCap === undefined ? 500 : hubDegreeCap;\n return factsDb.getConnectedFactIds(seeds, maxDepth, { hubDegreeCap: cap, stats });\n}\n\nexport function collectGraphRecallPayload(\n factsDb: FactsDB,\n query: string,\n hubDegreeCap?: number | null,\n): GraphRecallPayload {\n const q = query.trim();\n if (!q) {\n return { generatedAt: new Date().toISOString(), nodes: [], edges: [], activated: [] };\n }\n const results = factsDb.search(q, 12, {\n includeSuperseded: false,\n reinforcementBoost: 0.1,\n diversityWeight: 1,\n });\n const seeds = results.map((r) => r.entry.id);\n const connected: GraphConnectedStats = { nodesConsidered: 0, nodesSkipped: 0, hubsSkipped: 0 };\n const ids = collectDashboardConnectedIds(factsDb, seeds, 3, hubDegreeCap, connected).slice(0, 2000);\n const seedInputs = results.map((r) => ({ factId: r.entry.id, score: r.score, entry: r.entry }));\n const { stats: expansion } = expandGraph(factsDb, seedInputs, {\n maxDepth: 3,\n maxExpandedResults: 20,\n hubDegreeCap,\n });\n const entryMap = factsDb.getByIds(ids);\n const nodes: MemoryGraphNode[] = [];\n for (const id of ids) {\n const f = entryMap.get(id);\n if (!f) continue;\n nodes.push({\n id: f.id,\n label: f.text.length > 120 ? `${f.text.slice(0, 120)}…` : f.text,\n category: f.category,\n importance: f.importance,\n decayClass: f.decayClass ?? \"stable\",\n provenance: parseProvenance(f.provenanceJson ?? null),\n });\n }\n const nodeIdSet = new Set(nodes.map((n) => n.id));\n const allEdges = factsDb.getAllEdges(10000);\n const edges = allEdges.filter((e) => nodeIdSet.has(e.source) && nodeIdSet.has(e.target)).slice(0, 2000);\n return {\n generatedAt: new Date().toISOString(),\n nodes,\n edges: edges.map((e) => ({\n source: e.source,\n target: e.target,\n linkType: e.linkType,\n strength: e.strength,\n })),\n activated: seeds,\n graphHubGuard: {\n configuredCap: hubDegreeCap,\n effectiveCap: resolveGraphHubDegreeCap(hubDegreeCap),\n connected,\n expansion,\n },\n };\n}\n\nexport function getGraphExplorerHtml(): 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>Memory Graph</title>\n<script src=\"https://cdn.jsdelivr.net/npm/d3@7\"></script>\n<style>\n :root { --bg:#0f1117; --surface:#1a1d27; --border:#2a2d3a; --text:#e2e8f0; --muted:#8892a4; }\n body { margin:0; background:var(--bg); color:var(--text); font-family:system-ui,sans-serif; font-size:13px; }\n header { padding:12px 16px; border-bottom:1px solid var(--border); display:flex; flex-wrap:wrap; gap:8px; align-items:center; }\n h1 { margin:0; font-size:16px; color:#3b82f6; }\n #graph { width:100%; height:calc(100vh - 56px); }\n .panel { background:var(--surface); border:1px solid var(--border); border-radius:6px; padding:8px; max-width:420px; font-size:12px; max-height:160px; overflow:auto; }\n input[type=\"search\"] { background:#0b0d12; border:1px solid var(--border); color:var(--text); padding:6px 10px; border-radius:6px; min-width:200px; }\n button { background:#2563eb; color:#fff; border:none; padding:6px 12px; border-radius:6px; cursor:pointer; }\n button:hover { filter:brightness(1.1); }\n .legend { font-size:11px; color:var(--muted); }\n</style>\n</head>\n<body>\n<header>\n <h1>Memory graph</h1>\n <input type=\"search\" id=\"q\" placeholder=\"Recall subgraph (FTS search)…\" />\n <button type=\"button\" id=\"go\">Highlight recall</button>\n <span class=\"legend\">SUPERSEDES · RELATED_TO · PART_OF · CAUSED_BY · DEPENDS_ON · edges colored · drag nodes</span>\n</header>\n<div id=\"detail\" class=\"panel\" style=\"margin:8px;display:none\"></div>\n<svg id=\"graph\"></svg>\n<script>\nconst LINK_COLORS = { SUPERSEDES:'#ef4444', RELATED_TO:'#6b7280', PART_OF:'#3b82f6', CAUSED_BY:'#a855f7', DEPENDS_ON:'#f97316', INSTANCE_OF:'#22c55e', CONTRADICTS:'#f43f5e' };\nconst CAT_COLORS = { fact:'#3b82f6', preference:'#22c55e', decision:'#eab308', entity:'#a855f7', episode:'#c084fc', procedure:'#f97316', pattern:'#14b8a6', rule:'#f59e0b', other:'#64748b' };\n\nlet sim, svg, link, node, pulse;\n\nasync function loadBase() {\n const res = await fetch('/api/graph?days=30&maxNodes=400');\n if (!res.ok) {\n throw new Error(\\`Failed to load graph: \\${res.status} \\${res.statusText}\\`);\n }\n return res.json();\n}\n\nasync function loadRecall(q) {\n const res = await fetch('/api/graph/recall?' + new URLSearchParams({ query: q }));\n if (!res.ok) {\n throw new Error(\\`Failed to load recall graph: \\${res.status} \\${res.statusText}\\`);\n }\n return res.json();\n}\n\nfunction buildGraph(data) {\n if (sim) sim.stop();\n const width = window.innerWidth;\n const height = window.innerHeight - 56;\n d3.select('#graph').selectAll('*').remove();\n svg = d3.select('#graph').attr('width', width).attr('height', height);\n const g = svg.append('g');\n const zoom = d3.zoom().scaleExtent([0.2, 4]).on('zoom', (e) => g.attr('transform', e.transform));\n svg.call(zoom);\n\n const nodes = data.nodes.map(d => ({...d}));\n const nodeById = new Map(nodes.map(n => [n.id, n]));\n const links = data.edges.map(d => ({\n source: nodeById.get(d.source),\n target: nodeById.get(d.target),\n linkType: d.linkType,\n strength: d.strength\n })).filter(l => l.source && l.target);\n\n sim = d3.forceSimulation(nodes)\n .force('link', d3.forceLink(links).id(d => d.id).distance(45).strength(0.35))\n .force('charge', d3.forceManyBody().strength(-120))\n .force('center', d3.forceCenter(width/2, height/2))\n .force('collide', d3.forceCollide().radius(d => 6 + (d.importance || 0.5) * 10));\n\n link = g.append('g').attr('stroke', '#555').selectAll('line')\n .data(links).join('line')\n .attr('stroke-width', d => 0.5 + (d.strength || 0.5))\n .attr('stroke', d => LINK_COLORS[d.linkType] || '#6b7280');\n\n node = g.append('g').selectAll('circle')\n .data(nodes).join('circle')\n .attr('r', d => 5 + (d.importance || 0.5) * 8)\n .attr('fill', d => CAT_COLORS[d.category] || CAT_COLORS.other)\n .attr('opacity', d => {\n const dc = (d.decayClass || '').toLowerCase();\n if (dc.includes('ephemeral') || dc.includes('short')) return 0.55;\n return 0.92;\n })\n .call(d3.drag()\n .on('start', (e, d) => { if (!e.active) sim.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; })\n .on('drag', (e, d) => { d.fx = e.x; d.fy = e.y; })\n .on('end', (e, d) => { if (!e.active) sim.alphaTarget(0); d.fx = null; d.fy = null; }))\n .on('click', (e, d) => {\n const el = document.getElementById('detail');\n el.style.display = 'block';\n el.textContent = d.provenance ? d.label + '\\n\\nProvenance: ' + JSON.stringify(d.provenance, null, 2) : d.label;\n });\n\n pulse = new Set((data.activated || []).filter(Boolean));\n if (pulse.size) {\n node.attr('stroke', d => pulse.has(d.id) ? '#fff' : 'none').attr('stroke-width', d => pulse.has(d.id) ? 2 : 0);\n }\n\n sim.on('tick', () => {\n link\n .attr('x1', d => d.source.x).attr('y1', d => d.source.y)\n .attr('x2', d => d.target.x).attr('y2', d => d.target.y);\n node.attr('cx', d => d.x).attr('cy', d => d.y);\n });\n}\n\n(async () => {\n try {\n const data = await loadBase();\n buildGraph(data);\n document.getElementById('go').onclick = async () => {\n const q = document.getElementById('q').value.trim();\n try {\n if (!q) {\n buildGraph(await loadBase());\n return;\n }\n buildGraph(await loadRecall(q));\n } catch (err) {\n const el = document.getElementById('detail');\n el.style.display = 'block';\n el.style.color = '#ef4444';\n el.textContent = 'Error: ' + (err.message || String(err));\n }\n };\n } catch (err) {\n const el = document.getElementById('detail');\n el.style.display = 'block';\n el.style.color = '#ef4444';\n el.textContent = 'Error loading graph: ' + (err.message || String(err));\n }\n})();\n</script>\n</body>\n</html>`;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql-resolvers.js","names":[],"sources":["../../routes/graphql-resolvers.ts"],"sourcesContent":["// GraphQL resolver map for the dashboard API.\n// Keep this module conservative: it must compile against the real FactsDB API and\n// return safe placeholders for schema areas that are not implemented yet.\n\nimport type { FactsDB } from \"../backends/facts-db.js\";\nimport { isPreStoreGuardBlocked } from \"../backends/facts-db/crud.js\";\nimport type { VectorDB } from \"../backends/vector-db.js\";\nimport { DECAY_CLASSES, type DecayClass } from \"../config.js\";\nimport type { MemoryLinkType } from \"../backends/facts-db/types.js\";\nimport type { MemoryEntry } from \"../types/memory.js\";\nimport { cleanupEvictedVector } from \"../services/vector-maintenance.js\";\nimport { pluginLogger } from \"../utils/logger.js\";\n\nexport type GraphQLContext = {\n factsDb: FactsDB;\n vectorDb?: VectorDB;\n pluginContext: Record<string, unknown>;\n};\n\ntype ResolverFn = (parent: unknown, args: unknown, context: GraphQLContext) => unknown;\ntype ResolverGroup = Record<string, ResolverFn>;\n\ntype GraphQLResolvers = {\n Query: ResolverGroup;\n Mutation: ResolverGroup;\n Fact: ResolverGroup;\n Link: ResolverGroup;\n Episode: ResolverGroup;\n};\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction asStringArray(value: unknown): string[] | undefined {\n return Array.isArray(value) ? value.filter((item): item is string => typeof item === \"string\") : undefined;\n}\n\nfunction allFacts(factsDb: FactsDB, includeSuperseded = false): MemoryEntry[] {\n return factsDb.getAll({ includeSuperseded });\n}\n\nfunction isActiveFact(fact: MemoryEntry, nowSec = Math.floor(Date.now() / 1000)): boolean {\n const notSuperseded = (fact.supersededAt == null || fact.supersededAt <= 0) && fact.supersededBy == null;\n const notExpired = fact.expiresAt == null || fact.expiresAt <= 0 || fact.expiresAt > nowSec;\n return notSuperseded && notExpired;\n}\n\nfunction scoreFact(fact: MemoryEntry, query: string): number {\n const q = query.toLowerCase();\n const haystack = [fact.text, fact.entity, fact.key, fact.value, fact.category, ...(fact.tags ?? [])]\n .filter(Boolean)\n .join(\"\\n\")\n .toLowerCase();\n if (!q) return 0;\n if (haystack.includes(q)) return 1;\n const terms = q.split(/\\s+/).filter(Boolean);\n if (terms.length === 0) return 0;\n return terms.filter((term) => haystack.includes(term)).length / terms.length;\n}\n\nfunction searchFacts(\n context: GraphQLContext,\n input: Record<string, unknown>,\n): Array<{\n fact: MemoryEntry;\n score: number;\n matchType: string;\n snippet: string;\n}> {\n const query = asString(input.query) ?? \"\";\n const limit = Math.max(1, Math.min(100, asNumber(input.limit) ?? 20));\n const offset = Math.max(0, asNumber(input.offset) ?? 0);\n const categories = asStringArray(input.categories);\n const tags = asStringArray(input.tags);\n const minImportance = asNumber(input.minImportance);\n const minConfidence = asNumber(input.minConfidence);\n const includeSuperseded = input.includeSuperseded === true;\n const includeExpired = input.includeExpired === true;\n const now = Date.now();\n\n let facts = allFacts(context.factsDb, includeSuperseded);\n if (!includeExpired) facts = facts.filter((fact) => fact.expiresAt == null || fact.expiresAt > now);\n if (categories?.length) facts = facts.filter((fact) => categories.includes(fact.category));\n if (tags?.length) facts = facts.filter((fact) => tags.some((tag) => fact.tags?.includes(tag)));\n if (minImportance !== undefined) facts = facts.filter((fact) => fact.importance >= minImportance);\n if (minConfidence !== undefined) facts = facts.filter((fact) => fact.confidence >= minConfidence);\n\n return facts\n .map((fact) => ({ fact, score: scoreFact(fact, query) }))\n .filter((result) => query.length === 0 || result.score > 0)\n .sort((a, b) => b.score - a.score || b.fact.createdAt - a.fact.createdAt)\n .slice(offset, offset + limit)\n .map(({ fact, score }) => ({\n fact,\n score,\n matchType: \"fts\",\n snippet: fact.text.slice(0, 200),\n }));\n}\n\ntype GraphQLLink = {\n id: string;\n sourceId: string;\n targetId: string;\n linkType: string;\n weight: number;\n createdAt: number;\n};\n\nfunction normalizeLink(row: Record<string, unknown>): GraphQLLink {\n return {\n id: String(row.id ?? \"\"),\n sourceId: String(row.source_fact_id ?? row.sourceFactId ?? \"\"),\n targetId: String(row.target_fact_id ?? row.targetFactId ?? \"\"),\n linkType: String(row.link_type ?? row.linkType ?? \"RELATED_TO\"),\n weight: Number(row.strength ?? row.weight ?? 1),\n createdAt: Number(row.created_at ?? row.createdAt ?? 0),\n };\n}\n\nfunction getAllLinks(factsDb: FactsDB): GraphQLLink[] {\n const rows = factsDb\n .getRawDb()\n .prepare(\n \"SELECT id, source_fact_id, target_fact_id, link_type, strength, created_at FROM memory_links ORDER BY created_at DESC\",\n )\n .all() as Array<Record<string, unknown>>;\n return rows.map(normalizeLink);\n}\n\nfunction isMemoryLinkType(value: string): value is MemoryLinkType {\n return [\"SUPERSEDES\", \"CAUSED_BY\", \"PART_OF\", \"RELATED_TO\", \"DEPENDS_ON\", \"CONTRADICTS\", \"INSTANCE_OF\"].includes(\n value,\n );\n}\n\nfunction asDecayClass(value: unknown): DecayClass {\n return typeof value === \"string\" && (DECAY_CLASSES as readonly string[]).includes(value)\n ? (value as DecayClass)\n : \"normal\";\n}\n\nfunction createStoreInput(input: Record<string, unknown>) {\n return {\n text: asString(input.text) ?? \"\",\n category: asString(input.category) ?? \"other\",\n importance: asNumber(input.importance) ?? 0.5,\n confidence: asNumber(input.confidence) ?? 1,\n decayClass: asDecayClass(input.decayClass),\n source: asString(input.source) ?? \"graphql\",\n tags: asStringArray(input.tags) ?? [],\n entity: asString(input.entity) ?? null,\n key: asString(input.key) ?? null,\n value: asString(input.value) ?? null,\n scope: asString(input.scope) as MemoryEntry[\"scope\"] | undefined,\n scopeTarget: asString(input.scopeTarget) ?? null,\n expiresAt: asNumber(input.expiresAt) ?? null,\n };\n}\n\nasync function cleanupGraphqlEviction(context: GraphQLContext, evictedFactId: string | null | undefined) {\n if (!context.vectorDb || !evictedFactId) return;\n await cleanupEvictedVector({\n vectorDb: context.vectorDb,\n evictedFactId,\n logger: pluginLogger,\n context: \"graphql-mutation\",\n });\n}\n\nexport const resolvers: GraphQLResolvers = {\n Query: {\n fact: (_parent, args, context) => {\n const id = asString(asRecord(args).id);\n return id ? context.factsDb.getById(id) : null;\n },\n\n facts: (_parent, args, context) => {\n const input = asRecord(args);\n const limit = Math.max(1, Math.min(500, asNumber(input.limit) ?? 100));\n const offset = Math.max(0, asNumber(input.offset) ?? 0);\n const category = asString(input.category);\n const decayClass = asString(input.decayClass);\n const tags = asStringArray(input.tags);\n const scope = asString(input.scope);\n const includeSuperseded = input.includeSuperseded === true;\n const includeExpired = input.includeExpired === true;\n const now = Date.now();\n\n let facts = allFacts(context.factsDb, includeSuperseded);\n if (category) facts = facts.filter((fact) => fact.category === category);\n if (decayClass) facts = facts.filter((fact) => fact.decayClass === decayClass);\n if (tags?.length) facts = facts.filter((fact) => tags.some((tag) => fact.tags?.includes(tag)));\n if (scope) facts = facts.filter((fact) => fact.scope === scope);\n if (!includeExpired) facts = facts.filter((fact) => fact.expiresAt == null || fact.expiresAt > now);\n return facts.sort((a, b) => b.createdAt - a.createdAt).slice(offset, offset + limit);\n },\n\n search: (_parent, args, context) => searchFacts(context, asRecord(asRecord(args).input)),\n\n semanticSearch: (_parent, args, context) => {\n const input = asRecord(args);\n return searchFacts(context, { query: input.query, limit: input.limit, scope: input.scope });\n },\n\n episode: () => null,\n episodes: () => [],\n link: (_parent, args, context) => {\n const id = asString(asRecord(args).id);\n if (!id) return null;\n return getAllLinks(context.factsDb).find((link) => link.id === id) ?? null;\n },\n links: (_parent, args, context) => {\n const input = asRecord(args);\n const sourceId = asString(input.sourceId);\n const targetId = asString(input.targetId);\n const linkType = asString(input.linkType);\n return getAllLinks(context.factsDb).filter(\n (link) =>\n (!sourceId || link.sourceId === sourceId) &&\n (!targetId || link.targetId === targetId) &&\n (!linkType || link.linkType === linkType),\n );\n },\n relatedFacts: (_parent, args, context) => {\n const input = asRecord(args);\n const factId = asString(input.factId);\n if (!factId) return [];\n const maxDepth = Math.max(1, Math.min(5, asNumber(input.maxDepth) ?? 1));\n return context.factsDb\n .getConnectedFactIds([factId], maxDepth)\n .filter((id) => id !== factId)\n .map((id) => context.factsDb.getById(id))\n .filter((fact): fact is MemoryEntry => fact !== null);\n },\n\n entityFacts: (_parent, args, context) => {\n const input = asRecord(args);\n const entity = asString(input.entity);\n const key = asString(input.key);\n if (!entity) return [];\n return allFacts(context.factsDb).filter((fact) => fact.entity === entity && (!key || fact.key === key));\n },\n\n graph: (_parent, args, context) => {\n const filter = asRecord(asRecord(args).filter);\n const categories = asStringArray(filter.categories);\n const decayClasses = asStringArray(filter.decayClasses);\n const minImportance = asNumber(filter.minImportance);\n const scope = asString(filter.scope);\n let facts = allFacts(context.factsDb).filter((fact) => isActiveFact(fact));\n if (categories?.length) facts = facts.filter((fact) => categories.includes(fact.category));\n if (decayClasses?.length) facts = facts.filter((fact) => decayClasses.includes(fact.decayClass));\n if (minImportance !== undefined) facts = facts.filter((fact) => fact.importance >= minImportance);\n if (scope) facts = facts.filter((fact) => fact.scope === scope);\n return {\n nodes: facts.map((fact) => ({\n id: fact.id,\n label: fact.text.slice(0, 50) + (fact.text.length > 50 ? \"...\" : \"\"),\n category: fact.category,\n importance: fact.importance,\n confidence: fact.confidence,\n decayClass: fact.decayClass,\n factCount: 1,\n })),\n edges: facts\n .filter((fact) => fact.supersededBy)\n .map((fact) => ({\n source: fact.id,\n target: fact.supersededBy as string,\n linkType: \"superseded_by\",\n weight: 1,\n })),\n };\n },\n\n stats: (_parent, _args, context) => {\n const facts = allFacts(context.factsDb, true);\n const nowSec = Math.floor(Date.now() / 1000);\n const active = facts.filter((fact) => isActiveFact(fact, nowSec));\n const expired = facts.filter((fact) => fact.expiresAt != null && fact.expiresAt > 0 && fact.expiresAt <= nowSec);\n const superseded = facts.filter(\n (fact) => (fact.supersededAt != null && fact.supersededAt > 0) || fact.supersededBy != null,\n );\n const byCategory = new Map<string, number>();\n const byDecay = new Map<string, number>();\n for (const fact of active) {\n byCategory.set(fact.category, (byCategory.get(fact.category) ?? 0) + 1);\n byDecay.set(fact.decayClass, (byDecay.get(fact.decayClass) ?? 0) + 1);\n }\n return {\n totalFacts: facts.length,\n activeFactsCount: active.length,\n expiredFactsCount: expired.length,\n supersededFactsCount: superseded.length,\n factsByCategory: [...byCategory].map(([category, count]) => ({ category, count })),\n factsByDecayClass: [...byDecay].map(([decayClass, count]) => ({ decayClass, count })),\n totalEpisodes: 0,\n totalLinks: 0,\n databaseSizeBytes: 0,\n oldestFactDate: facts.length ? Math.min(...facts.map((fact) => fact.createdAt)) : null,\n newestFactDate: facts.length ? Math.max(...facts.map((fact) => fact.createdAt)) : null,\n };\n },\n },\n\n Mutation: {\n createFact: async (_parent, args, context) => {\n const input = asRecord(asRecord(args).input);\n const result = context.factsDb.storeWithResult(createStoreInput(input));\n if (result.entry.id === \"\") {\n throw new Error(\"Fact rejected: artifact or reasoning trace text cannot be stored\");\n }\n await cleanupGraphqlEviction(context, result.evictedFactId);\n return result.entry;\n },\n\n updateFact: async (_parent, args, context) => {\n const input = asRecord(asRecord(args).input);\n const id = asString(input.id);\n if (!id) throw new Error(\"Missing fact id\");\n const existing = context.factsDb.getById(id);\n if (!existing) throw new Error(`Fact not found: ${id}`);\n const updatedText = asString(input.text) ?? existing.text;\n const result = context.factsDb.storeWithResult(\n {\n text: updatedText,\n category: asString(input.category) ?? existing.category,\n importance: asNumber(input.importance) ?? existing.importance,\n confidence: asNumber(input.confidence) ?? existing.confidence,\n decayClass: existing.decayClass,\n source: existing.source,\n tags: asStringArray(input.tags) ?? existing.tags ?? [],\n entity: existing.entity,\n key: existing.key,\n value: existing.value,\n scope: existing.scope,\n scopeTarget: existing.scopeTarget ?? null,\n expiresAt: asNumber(input.expiresAt) ?? existing.expiresAt ?? null,\n },\n { allowPreStoreGuardBypass: true },\n );\n // Skip supersede if store was rejected (artifact text)\n if (result.entry.id !== \"\") {\n context.factsDb.supersede(existing.id, result.entry.id);\n }\n await cleanupGraphqlEviction(context, result.evictedFactId);\n return result.entry;\n },\n\n deleteFact: (_parent, args, context) => {\n const id = asString(asRecord(args).id);\n return id ? context.factsDb.delete(id) : false;\n },\n\n supersedeFact: (_parent, args, context) => {\n const input = asRecord(args);\n const oldFactId = asString(input.oldFactId);\n const newFactId = asString(input.newFactId);\n if (!oldFactId || !newFactId) throw new Error(\"Missing fact id\");\n const oldFact = context.factsDb.getById(oldFactId);\n if (!oldFact) throw new Error(`Fact not found: ${oldFactId}`);\n const newFact = context.factsDb.getById(newFactId);\n if (!newFact) throw new Error(`Fact not found: ${newFactId}`);\n const applied = context.factsDb.supersede(oldFactId, newFactId);\n if (!applied) throw new Error(`Fact supersede did not apply: ${oldFactId}`);\n return newFact;\n },\n\n createLink: (_parent, args, context) => {\n const input = asRecord(args);\n const sourceId = asString(input.sourceId);\n const targetId = asString(input.targetId);\n const linkType = asString(input.linkType) ?? \"RELATED_TO\";\n const weight = asNumber(input.weight) ?? 1;\n if (!sourceId || !targetId) throw new Error(\"Missing link endpoint\");\n if (!isMemoryLinkType(linkType)) throw new Error(`Unsupported link type: ${linkType}`);\n const id = context.factsDb.createLink(sourceId, targetId, linkType, weight);\n return getAllLinks(context.factsDb).find((link) => link.id === id);\n },\n deleteLink: (_parent, args, context) => {\n const id = asString(asRecord(args).id);\n if (!id) return false;\n const result = context.factsDb.getRawDb().prepare(\"DELETE FROM memory_links WHERE id = ?\").run(id);\n return result.changes > 0;\n },\n\n importFacts: async (_parent, args, context) => {\n const facts = Array.isArray(asRecord(args).facts) ? (asRecord(args).facts as unknown[]) : [];\n const inputs = facts.map((raw) => createStoreInput(asRecord(raw)));\n // Pre-validate all facts before storing any\n for (const input of inputs) {\n if (isPreStoreGuardBlocked(input)) {\n throw new Error(\n `Fact blocked by pre-store guard: category=${input.category ?? \"\"}, source=${input.source ?? \"\"}`,\n );\n }\n }\n const stored: MemoryEntry[] = [];\n for (const input of inputs) {\n const result = context.factsDb.storeWithResult(input);\n if (result.entry.id !== \"\") {\n stored.push(result.entry);\n }\n await cleanupGraphqlEviction(context, result.evictedFactId);\n }\n return stored;\n },\n\n pruneFacts: (_parent, args, context) => {\n const input = asRecord(args);\n const olderThan = asNumber(input.olderThan);\n const category = asString(input.category);\n const toDelete = allFacts(context.factsDb).filter(\n (fact) => (olderThan === undefined || fact.createdAt < olderThan) && (!category || fact.category === category),\n );\n let deleted = 0;\n for (const fact of toDelete) {\n if (context.factsDb.delete(fact.id)) deleted++;\n }\n return deleted;\n },\n\n consolidateFacts: () => null,\n recomputeEmbeddings: () => null,\n },\n\n Fact: {\n links: (parent, _args, context) => {\n const fact = asRecord(parent) as Partial<MemoryEntry>;\n return fact.id ? getAllLinks(context.factsDb).filter((link) => link.sourceId === fact.id) : [];\n },\n linkedFrom: (parent, _args, context) => {\n const fact = asRecord(parent) as Partial<MemoryEntry>;\n return fact.id ? getAllLinks(context.factsDb).filter((link) => link.targetId === fact.id) : [];\n },\n supersedes: (parent, _args, context) => {\n const fact = asRecord(parent) as Partial<MemoryEntry>;\n return fact.supersedesId ? context.factsDb.getById(fact.supersedesId) : null;\n },\n supersededByFact: (parent, _args, context) => {\n const fact = asRecord(parent) as Partial<MemoryEntry>;\n return fact.supersededBy ? context.factsDb.getById(fact.supersededBy) : null;\n },\n },\n\n Link: {\n source: (parent, _args, context) => {\n const sourceId = asString(asRecord(parent).sourceId);\n return sourceId ? context.factsDb.getById(sourceId) : null;\n },\n target: (parent, _args, context) => {\n const targetId = asString(asRecord(parent).targetId);\n return targetId ? context.factsDb.getById(targetId) : null;\n },\n },\n\n Episode: {\n facts: () => [],\n },\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"graphql-resolvers.js","names":[],"sources":["../../routes/graphql-resolvers.ts"],"sourcesContent":["// GraphQL resolver map for the dashboard API.\n// Keep this module conservative: it must compile against the real FactsDB API and\n// return safe placeholders for schema areas that are not implemented yet.\n\nimport type { FactsDB } from \"../backends/facts-db.js\";\nimport { isPreStoreGuardBlocked } from \"../backends/facts-db/crud.js\";\nimport type { VectorDB } from \"../backends/vector-db.js\";\nimport { DECAY_CLASSES, type DecayClass } from \"../config.js\";\nimport type { MemoryLinkType } from \"../backends/facts-db/types.js\";\nimport type { MemoryEntry } from \"../types/memory.js\";\nimport { cleanupEvictedVector } from \"../services/vector-maintenance.js\";\nimport { pluginLogger } from \"../utils/logger.js\";\n\nexport type GraphQLContext = {\n factsDb: FactsDB;\n vectorDb?: VectorDB;\n pluginContext: Record<string, unknown>;\n};\n\ntype ResolverFn = (parent: unknown, args: unknown, context: GraphQLContext) => unknown;\ntype ResolverGroup = Record<string, ResolverFn>;\n\ntype GraphQLResolvers = {\n Query: ResolverGroup;\n Mutation: ResolverGroup;\n Fact: ResolverGroup;\n Link: ResolverGroup;\n Episode: ResolverGroup;\n};\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction asStringArray(value: unknown): string[] | undefined {\n return Array.isArray(value) ? value.filter((item): item is string => typeof item === \"string\") : undefined;\n}\n\nfunction allFacts(factsDb: FactsDB, includeSuperseded = false): MemoryEntry[] {\n return factsDb.getAll({ includeSuperseded });\n}\n\nfunction isActiveFact(fact: MemoryEntry, nowSec = Math.floor(Date.now() / 1000)): boolean {\n const notSuperseded = (fact.supersededAt == null || fact.supersededAt <= 0) && fact.supersededBy == null;\n const notExpired = fact.expiresAt == null || fact.expiresAt <= 0 || fact.expiresAt > nowSec;\n return notSuperseded && notExpired;\n}\n\nfunction scoreFact(fact: MemoryEntry, query: string): number {\n const q = query.toLowerCase();\n const haystack = [fact.text, fact.entity, fact.key, fact.value, fact.category, ...(fact.tags ?? [])]\n .filter(Boolean)\n .join(\"\\n\")\n .toLowerCase();\n if (!q) return 0;\n if (haystack.includes(q)) return 1;\n const terms = q.split(/\\s+/).filter(Boolean);\n if (terms.length === 0) return 0;\n return terms.filter((term) => haystack.includes(term)).length / terms.length;\n}\n\nfunction searchFacts(\n context: GraphQLContext,\n input: Record<string, unknown>,\n): Array<{\n fact: MemoryEntry;\n score: number;\n matchType: string;\n snippet: string;\n}> {\n const query = asString(input.query) ?? \"\";\n const limit = Math.max(1, Math.min(100, asNumber(input.limit) ?? 20));\n const offset = Math.max(0, asNumber(input.offset) ?? 0);\n const categories = asStringArray(input.categories);\n const tags = asStringArray(input.tags);\n const minImportance = asNumber(input.minImportance);\n const minConfidence = asNumber(input.minConfidence);\n const includeSuperseded = input.includeSuperseded === true;\n const includeExpired = input.includeExpired === true;\n const now = Date.now();\n\n let facts = allFacts(context.factsDb, includeSuperseded);\n if (!includeExpired) facts = facts.filter((fact) => fact.expiresAt == null || fact.expiresAt > now);\n if (categories?.length) facts = facts.filter((fact) => categories.includes(fact.category));\n if (tags?.length) facts = facts.filter((fact) => tags.some((tag) => fact.tags?.includes(tag)));\n if (minImportance !== undefined) facts = facts.filter((fact) => fact.importance >= minImportance);\n if (minConfidence !== undefined) facts = facts.filter((fact) => fact.confidence >= minConfidence);\n\n return facts\n .map((fact) => ({ fact, score: scoreFact(fact, query) }))\n .filter((result) => query.length === 0 || result.score > 0)\n .sort((a, b) => b.score - a.score || b.fact.createdAt - a.fact.createdAt)\n .slice(offset, offset + limit)\n .map(({ fact, score }) => ({\n fact,\n score,\n matchType: \"fts\",\n snippet: fact.text.slice(0, 200),\n }));\n}\n\ntype GraphQLLink = {\n id: string;\n sourceId: string;\n targetId: string;\n linkType: string;\n weight: number;\n createdAt: number;\n};\n\nfunction normalizeLink(row: Record<string, unknown>): GraphQLLink {\n return {\n id: String(row.id ?? \"\"),\n sourceId: String(row.source_fact_id ?? row.sourceFactId ?? \"\"),\n targetId: String(row.target_fact_id ?? row.targetFactId ?? \"\"),\n linkType: String(row.link_type ?? row.linkType ?? \"RELATED_TO\"),\n weight: Number(row.strength ?? row.weight ?? 1),\n createdAt: Number(row.created_at ?? row.createdAt ?? 0),\n };\n}\n\nfunction getAllLinks(factsDb: FactsDB): GraphQLLink[] {\n const rows = factsDb\n .getRawDb()\n .prepare(\n \"SELECT id, source_fact_id, target_fact_id, link_type, strength, created_at FROM memory_links ORDER BY created_at DESC\",\n )\n .all() as Array<Record<string, unknown>>;\n return rows.map(normalizeLink);\n}\n\nfunction isMemoryLinkType(value: string): value is MemoryLinkType {\n return [\"SUPERSEDES\", \"CAUSED_BY\", \"PART_OF\", \"RELATED_TO\", \"DEPENDS_ON\", \"CONTRADICTS\", \"INSTANCE_OF\"].includes(\n value,\n );\n}\n\nfunction asDecayClass(value: unknown): DecayClass {\n return typeof value === \"string\" && (DECAY_CLASSES as readonly string[]).includes(value)\n ? (value as DecayClass)\n : \"normal\";\n}\n\nfunction createStoreInput(input: Record<string, unknown>) {\n return {\n text: asString(input.text) ?? \"\",\n category: asString(input.category) ?? \"other\",\n importance: asNumber(input.importance) ?? 0.5,\n confidence: asNumber(input.confidence) ?? 1,\n decayClass: asDecayClass(input.decayClass),\n source: asString(input.source) ?? \"graphql\",\n tags: asStringArray(input.tags) ?? [],\n entity: asString(input.entity) ?? null,\n key: asString(input.key) ?? null,\n value: asString(input.value) ?? null,\n scope: asString(input.scope) as MemoryEntry[\"scope\"] | undefined,\n scopeTarget: asString(input.scopeTarget) ?? null,\n expiresAt: asNumber(input.expiresAt) ?? null,\n };\n}\n\nasync function cleanupGraphqlEviction(context: GraphQLContext, evictedFactId: string | null | undefined) {\n if (!context.vectorDb || !evictedFactId) return;\n await cleanupEvictedVector({\n vectorDb: context.vectorDb,\n evictedFactId,\n logger: pluginLogger,\n context: \"graphql-mutation\",\n });\n}\n\nexport const resolvers: GraphQLResolvers = {\n Query: {\n fact: (_parent, args, context) => {\n const id = asString(asRecord(args).id);\n return id ? context.factsDb.getById(id) : null;\n },\n\n facts: (_parent, args, context) => {\n const input = asRecord(args);\n const limit = Math.max(1, Math.min(500, asNumber(input.limit) ?? 100));\n const offset = Math.max(0, asNumber(input.offset) ?? 0);\n const category = asString(input.category);\n const decayClass = asString(input.decayClass);\n const tags = asStringArray(input.tags);\n const scope = asString(input.scope);\n const includeSuperseded = input.includeSuperseded === true;\n const includeExpired = input.includeExpired === true;\n const now = Date.now();\n\n let facts = allFacts(context.factsDb, includeSuperseded);\n if (category) facts = facts.filter((fact) => fact.category === category);\n if (decayClass) facts = facts.filter((fact) => fact.decayClass === decayClass);\n if (tags?.length) facts = facts.filter((fact) => tags.some((tag) => fact.tags?.includes(tag)));\n if (scope) facts = facts.filter((fact) => fact.scope === scope);\n if (!includeExpired) facts = facts.filter((fact) => fact.expiresAt == null || fact.expiresAt > now);\n return facts.sort((a, b) => b.createdAt - a.createdAt).slice(offset, offset + limit);\n },\n\n search: (_parent, args, context) => searchFacts(context, asRecord(asRecord(args).input)),\n\n semanticSearch: (_parent, args, context) => {\n const input = asRecord(args);\n return searchFacts(context, { query: input.query, limit: input.limit, scope: input.scope });\n },\n\n episode: () => null,\n episodes: () => [],\n link: (_parent, args, context) => {\n const id = asString(asRecord(args).id);\n if (!id) return null;\n return getAllLinks(context.factsDb).find((link) => link.id === id) ?? null;\n },\n links: (_parent, args, context) => {\n const input = asRecord(args);\n const sourceId = asString(input.sourceId);\n const targetId = asString(input.targetId);\n const linkType = asString(input.linkType);\n return getAllLinks(context.factsDb).filter(\n (link) =>\n (!sourceId || link.sourceId === sourceId) &&\n (!targetId || link.targetId === targetId) &&\n (!linkType || link.linkType === linkType),\n );\n },\n relatedFacts: (_parent, args, context) => {\n const input = asRecord(args);\n const factId = asString(input.factId);\n if (!factId) return [];\n const maxDepth = Math.max(1, Math.min(5, asNumber(input.maxDepth) ?? 1));\n return context.factsDb\n .getConnectedFactIds([factId], maxDepth)\n .filter((id) => id !== factId)\n .map((id) => context.factsDb.getById(id))\n .filter((fact): fact is MemoryEntry => fact !== null);\n },\n\n entityFacts: (_parent, args, context) => {\n const input = asRecord(args);\n const entity = asString(input.entity);\n const key = asString(input.key);\n if (!entity) return [];\n return allFacts(context.factsDb).filter((fact) => fact.entity === entity && (!key || fact.key === key));\n },\n\n graph: (_parent, args, context) => {\n const filter = asRecord(asRecord(args).filter);\n const categories = asStringArray(filter.categories);\n const decayClasses = asStringArray(filter.decayClasses);\n const minImportance = asNumber(filter.minImportance);\n const scope = asString(filter.scope);\n let facts = allFacts(context.factsDb).filter((fact) => isActiveFact(fact));\n if (categories?.length) facts = facts.filter((fact) => categories.includes(fact.category));\n if (decayClasses?.length) facts = facts.filter((fact) => decayClasses.includes(fact.decayClass));\n if (minImportance !== undefined) facts = facts.filter((fact) => fact.importance >= minImportance);\n if (scope) facts = facts.filter((fact) => fact.scope === scope);\n return {\n nodes: facts.map((fact) => ({\n id: fact.id,\n label: fact.text.slice(0, 50) + (fact.text.length > 50 ? \"...\" : \"\"),\n category: fact.category,\n importance: fact.importance,\n confidence: fact.confidence,\n decayClass: fact.decayClass,\n factCount: 1,\n })),\n edges: facts\n .filter((fact) => fact.supersededBy)\n .map((fact) => ({\n source: fact.id,\n target: fact.supersededBy as string,\n linkType: \"superseded_by\",\n weight: 1,\n })),\n };\n },\n\n stats: (_parent, _args, context) => {\n const facts = allFacts(context.factsDb, true);\n const nowSec = Math.floor(Date.now() / 1000);\n const active = facts.filter((fact) => isActiveFact(fact, nowSec));\n const expired = facts.filter((fact) => fact.expiresAt != null && fact.expiresAt > 0 && fact.expiresAt <= nowSec);\n const superseded = facts.filter(\n (fact) => (fact.supersededAt != null && fact.supersededAt > 0) || fact.supersededBy != null,\n );\n const byCategory = new Map<string, number>();\n const byDecay = new Map<string, number>();\n for (const fact of active) {\n byCategory.set(fact.category, (byCategory.get(fact.category) ?? 0) + 1);\n byDecay.set(fact.decayClass, (byDecay.get(fact.decayClass) ?? 0) + 1);\n }\n return {\n totalFacts: facts.length,\n activeFactsCount: active.length,\n expiredFactsCount: expired.length,\n supersededFactsCount: superseded.length,\n factsByCategory: [...byCategory].map(([category, count]) => ({ category, count })),\n factsByDecayClass: [...byDecay].map(([decayClass, count]) => ({ decayClass, count })),\n totalEpisodes: 0,\n totalLinks: 0,\n databaseSizeBytes: 0,\n oldestFactDate: facts.length ? Math.min(...facts.map((fact) => fact.createdAt)) : null,\n newestFactDate: facts.length ? Math.max(...facts.map((fact) => fact.createdAt)) : null,\n };\n },\n },\n\n Mutation: {\n createFact: async (_parent, args, context) => {\n const input = asRecord(asRecord(args).input);\n const result = context.factsDb.storeWithResult(createStoreInput(input));\n if (result.entry.id === \"\") {\n throw new Error(\"Fact rejected: artifact or reasoning trace text cannot be stored\");\n }\n await cleanupGraphqlEviction(context, result.evictedFactId);\n return result.entry;\n },\n\n updateFact: async (_parent, args, context) => {\n const input = asRecord(asRecord(args).input);\n const id = asString(input.id);\n if (!id) throw new Error(\"Missing fact id\");\n const existing = context.factsDb.getById(id);\n if (!existing) throw new Error(`Fact not found: ${id}`);\n const updatedText = asString(input.text) ?? existing.text;\n const result = context.factsDb.storeWithResult(\n {\n text: updatedText,\n category: asString(input.category) ?? existing.category,\n importance: asNumber(input.importance) ?? existing.importance,\n confidence: asNumber(input.confidence) ?? existing.confidence,\n decayClass: existing.decayClass,\n source: existing.source,\n tags: asStringArray(input.tags) ?? existing.tags ?? [],\n entity: existing.entity,\n key: existing.key,\n value: existing.value,\n scope: existing.scope,\n scopeTarget: existing.scopeTarget ?? null,\n expiresAt: asNumber(input.expiresAt) ?? existing.expiresAt ?? null,\n },\n { allowPreStoreGuardBypass: true },\n );\n // Skip supersede if store was rejected (artifact text)\n if (result.entry.id !== \"\") {\n context.factsDb.supersede(existing.id, result.entry.id);\n }\n await cleanupGraphqlEviction(context, result.evictedFactId);\n return result.entry;\n },\n\n deleteFact: (_parent, args, context) => {\n const id = asString(asRecord(args).id);\n return id ? context.factsDb.delete(id) : false;\n },\n\n supersedeFact: (_parent, args, context) => {\n const input = asRecord(args);\n const oldFactId = asString(input.oldFactId);\n const newFactId = asString(input.newFactId);\n if (!oldFactId || !newFactId) throw new Error(\"Missing fact id\");\n const oldFact = context.factsDb.getById(oldFactId);\n if (!oldFact) throw new Error(`Fact not found: ${oldFactId}`);\n const newFact = context.factsDb.getById(newFactId);\n if (!newFact) throw new Error(`Fact not found: ${newFactId}`);\n const applied = context.factsDb.supersede(oldFactId, newFactId);\n if (!applied) throw new Error(`Fact supersede did not apply: ${oldFactId}`);\n return newFact;\n },\n\n createLink: (_parent, args, context) => {\n const input = asRecord(args);\n const sourceId = asString(input.sourceId);\n const targetId = asString(input.targetId);\n const linkType = asString(input.linkType) ?? \"RELATED_TO\";\n const weight = asNumber(input.weight) ?? 1;\n if (!sourceId || !targetId) throw new Error(\"Missing link endpoint\");\n if (!isMemoryLinkType(linkType)) throw new Error(`Unsupported link type: ${linkType}`);\n const id = context.factsDb.createLink(sourceId, targetId, linkType, weight);\n return getAllLinks(context.factsDb).find((link) => link.id === id);\n },\n deleteLink: (_parent, args, context) => {\n const id = asString(asRecord(args).id);\n if (!id) return false;\n const result = context.factsDb.getRawDb().prepare(\"DELETE FROM memory_links WHERE id = ?\").run(id);\n return result.changes > 0;\n },\n\n importFacts: async (_parent, args, context) => {\n const facts = Array.isArray(asRecord(args).facts) ? (asRecord(args).facts as unknown[]) : [];\n const inputs = facts.map((raw) => createStoreInput(asRecord(raw)));\n // Pre-validate all facts before storing any\n for (const input of inputs) {\n if (isPreStoreGuardBlocked(input)) {\n throw new Error(\n `Fact blocked by pre-store guard: category=${input.category ?? \"\"}, source=${input.source ?? \"\"}`,\n );\n }\n }\n const stored: MemoryEntry[] = [];\n for (const input of inputs) {\n const result = context.factsDb.storeWithResult(input);\n if (result.entry.id !== \"\") {\n stored.push(result.entry);\n }\n await cleanupGraphqlEviction(context, result.evictedFactId);\n }\n return stored;\n },\n\n pruneFacts: (_parent, args, context) => {\n const input = asRecord(args);\n const olderThan = asNumber(input.olderThan);\n const category = asString(input.category);\n const toDelete = allFacts(context.factsDb).filter(\n (fact) => (olderThan === undefined || fact.createdAt < olderThan) && (!category || fact.category === category),\n );\n let deleted = 0;\n for (const fact of toDelete) {\n if (context.factsDb.delete(fact.id)) deleted++;\n }\n return deleted;\n },\n\n consolidateFacts: () => null,\n recomputeEmbeddings: () => null,\n },\n\n Fact: {\n links: (parent, _args, context) => {\n const fact = asRecord(parent) as Partial<MemoryEntry>;\n return fact.id ? getAllLinks(context.factsDb).filter((link) => link.sourceId === fact.id) : [];\n },\n linkedFrom: (parent, _args, context) => {\n const fact = asRecord(parent) as Partial<MemoryEntry>;\n return fact.id ? getAllLinks(context.factsDb).filter((link) => link.targetId === fact.id) : [];\n },\n supersedes: (parent, _args, context) => {\n const fact = asRecord(parent) as Partial<MemoryEntry>;\n return fact.supersedesId ? context.factsDb.getById(fact.supersedesId) : null;\n },\n supersededByFact: (parent, _args, context) => {\n const fact = asRecord(parent) as Partial<MemoryEntry>;\n return fact.supersededBy ? context.factsDb.getById(fact.supersededBy) : null;\n },\n },\n\n Link: {\n source: (parent, _args, context) => {\n const sourceId = asString(asRecord(parent).sourceId);\n return sourceId ? context.factsDb.getById(sourceId) : null;\n },\n target: (parent, _args, context) => {\n const targetId = asString(asRecord(parent).targetId);\n return targetId ? context.factsDb.getById(targetId) : null;\n },\n },\n\n Episode: {\n facts: () => [],\n },\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphql-server.js","names":[],"sources":["../../routes/graphql-server.ts"],"sourcesContent":["/**\n * GraphQL Server for OpenClaw Hybrid Memory\n * Provides GraphQL API endpoint with subscriptions support\n */\n\ninterface MemoryPluginContext {\n config?: unknown;\n [key: string]: unknown;\n}\n\nimport { createSchema, createYoga, createPubSub } from \"graphql-yoga\";\nimport type { FactsDB } from \"../backends/facts-db.js\";\nimport type { VectorDB } from \"../backends/vector-db.js\";\nimport { graphqlSchema } from \"./graphql-schema.js\";\nimport { pluginLogger } from \"../utils/logger.js\";\nimport { resolvers, type GraphQLContext } from \"./graphql-resolvers.js\";\n\ntype FactSubscriptionPayload = { fact: unknown; category?: string; scope?: string };\ntype FactUpdatedPayload = { fact: unknown; factId?: string; category?: string };\ntype FactDeletedPayload = { id: string; category?: string };\ntype LinkCreatedPayload = { link: unknown; sourceId?: string; targetId?: string };\ntype StatsUpdatedPayload = { stats: unknown };\n\n// PubSub for subscriptions\nconst pubSub = createPubSub<{\n factCreated: [FactSubscriptionPayload];\n factUpdated: [FactUpdatedPayload];\n factDeleted: [FactDeletedPayload];\n linkCreated: [LinkCreatedPayload];\n statsUpdated: [StatsUpdatedPayload];\n}>();\n\nfunction recordValue(value: unknown, key: string): unknown {\n return value && typeof value === \"object\" ? (value as Record<string, unknown>)[key] : undefined;\n}\n\nfunction optionalMatches(expected: unknown, actual: unknown): boolean {\n return expected == null || expected === \"\" || actual === expected;\n}\n\nfunction factCategory(fact: unknown, fallback?: string): string | undefined {\n return typeof recordValue(fact, \"category\") === \"string\" ? (recordValue(fact, \"category\") as string) : fallback;\n}\n\nfunction factScope(fact: unknown, fallback?: string): string | undefined {\n return typeof recordValue(fact, \"scope\") === \"string\" ? (recordValue(fact, \"scope\") as string) : fallback;\n}\n\nfunction factId(fact: unknown): string | undefined {\n return typeof recordValue(fact, \"id\") === \"string\" ? (recordValue(fact, \"id\") as string) : undefined;\n}\n\nfunction linkEndpoint(link: unknown, key: \"sourceId\" | \"targetId\", fallback?: string): string | undefined {\n const direct = recordValue(link, key);\n return typeof direct === \"string\" ? direct : fallback;\n}\n\nexport function matchesFactCreatedSubscription(\n payload: FactSubscriptionPayload,\n args: { category?: string; scope?: string },\n): boolean {\n return (\n optionalMatches(args.category, factCategory(payload.fact, payload.category)) &&\n optionalMatches(args.scope, factScope(payload.fact, payload.scope))\n );\n}\n\nexport function matchesFactUpdatedSubscription(\n payload: FactUpdatedPayload,\n args: { factId?: string; category?: string },\n): boolean {\n return (\n optionalMatches(args.factId, payload.factId ?? factId(payload.fact)) &&\n optionalMatches(args.category, factCategory(payload.fact, payload.category))\n );\n}\n\nexport function matchesFactDeletedSubscription(payload: FactDeletedPayload, args: { category?: string }): boolean {\n return optionalMatches(args.category, payload.category);\n}\n\nexport function matchesLinkCreatedSubscription(\n payload: LinkCreatedPayload,\n args: { sourceId?: string; targetId?: string },\n): boolean {\n return (\n optionalMatches(args.sourceId, linkEndpoint(payload.link, \"sourceId\", payload.sourceId)) &&\n optionalMatches(args.targetId, linkEndpoint(payload.link, \"targetId\", payload.targetId))\n );\n}\n\nasync function* filterAsyncIterator<T>(source: AsyncIterable<T>, predicate: (payload: T) => boolean): AsyncIterable<T> {\n for await (const payload of source) {\n if (predicate(payload)) yield payload;\n }\n}\n\n/**\n * Create GraphQL Yoga server instance\n */\nexport function createGraphQLServer(\n factsDb: FactsDB,\n vectorDb: VectorDB | undefined,\n pluginContext: MemoryPluginContext,\n) {\n const yoga = createYoga<GraphQLContext>({\n schema: createSchema({\n typeDefs: graphqlSchema,\n resolvers: {\n ...resolvers,\n Subscription: {\n factCreated: {\n subscribe: (_parent: unknown, args: { category?: string; scope?: string }) =>\n filterAsyncIterator(pubSub.subscribe(\"factCreated\"), (payload) =>\n matchesFactCreatedSubscription(payload, args),\n ),\n resolve: (payload: FactSubscriptionPayload) => payload.fact,\n },\n factUpdated: {\n subscribe: (_parent: unknown, args: { factId?: string; category?: string }) =>\n filterAsyncIterator(pubSub.subscribe(\"factUpdated\"), (payload) =>\n matchesFactUpdatedSubscription(payload, args),\n ),\n resolve: (payload: FactUpdatedPayload) => payload.fact,\n },\n factDeleted: {\n subscribe: (_parent: unknown, args: { category?: string }) =>\n filterAsyncIterator(pubSub.subscribe(\"factDeleted\"), (payload) =>\n matchesFactDeletedSubscription(payload, args),\n ),\n resolve: (payload: FactDeletedPayload) => payload.id,\n },\n linkCreated: {\n subscribe: (_parent: unknown, args: { sourceId?: string; targetId?: string }) =>\n filterAsyncIterator(pubSub.subscribe(\"linkCreated\"), (payload) =>\n matchesLinkCreatedSubscription(payload, args),\n ),\n resolve: (payload: LinkCreatedPayload) => payload.link,\n },\n statsUpdated: {\n subscribe: () => pubSub.subscribe(\"statsUpdated\"),\n resolve: (payload: StatsUpdatedPayload) => payload.stats,\n },\n },\n },\n }),\n context: (): GraphQLContext => ({\n factsDb,\n vectorDb,\n pluginContext,\n }),\n graphiql: {\n title: \"OpenClaw Hybrid Memory GraphQL API\",\n defaultQuery: `# Welcome to OpenClaw Hybrid Memory GraphQL API\n#\n# Example queries:\n\n# Get all facts with pagination\nquery GetFacts {\n facts(limit: 10, offset: 0) {\n id\n text\n category\n importance\n confidence\n createdAt\n tags\n }\n}\n\n# Search for memories\nquery SearchMemories {\n search(input: {\n query: \"user preferences\"\n limit: 5\n }) {\n fact {\n id\n text\n category\n }\n score\n matchType\n }\n}\n\n# Get memory statistics\nquery GetStats {\n stats {\n totalFacts\n activeFactsCount\n factsByCategory {\n category\n count\n }\n }\n}\n\n# Visualize memory graph\nquery GetGraph {\n graph(filter: {\n minImportance: 0.5\n categories: [\"preference\", \"decision\"]\n }) {\n nodes {\n id\n label\n category\n importance\n }\n edges {\n source\n target\n linkType\n }\n }\n}\n\n# Create a new fact\nmutation CreateFact {\n createFact(input: {\n text: \"User prefers dark mode\"\n category: \"preference\"\n importance: 0.8\n tags: [\"ui\", \"preference\"]\n }) {\n id\n text\n createdAt\n }\n}\n\n# Subscribe to new facts (WebSocket)\nsubscription WatchNewFacts {\n factCreated(category: \"preference\") {\n id\n text\n category\n }\n}\n`,\n },\n cors: {\n origin: \"*\",\n credentials: false,\n methods: [\"GET\", \"POST\", \"OPTIONS\"],\n },\n logging: {\n debug: (...args) => pluginLogger.debug(args.map(String).join(\" \")),\n info: (...args) => pluginLogger.info(args.map(String).join(\" \")),\n warn: (...args) => pluginLogger.warn(args.map(String).join(\" \")),\n error: (...args) => pluginLogger.error(args.map(String).join(\" \")),\n },\n });\n\n return { yoga, pubSub };\n}\n\n/**\n * Publish fact created event\n */\nexport function publishFactCreated(\n pubSub: ReturnType<typeof createPubSub>,\n fact: unknown,\n category?: string,\n scope?: string,\n) {\n pubSub.publish(\"factCreated\", { fact, category, scope });\n}\n\n/**\n * Publish fact updated event\n */\nexport function publishFactUpdated(pubSub: ReturnType<typeof createPubSub>, fact: unknown) {\n pubSub.publish(\"factUpdated\", { fact, factId: factId(fact), category: factCategory(fact) });\n}\n\n/**\n * Publish fact deleted event\n */\nexport function publishFactDeleted(pubSub: ReturnType<typeof createPubSub>, id: string, category?: string) {\n pubSub.publish(\"factDeleted\", { id, category });\n}\n\n/**\n * Publish stats updated event\n */\nexport function publishLinkCreated(pubSub: ReturnType<typeof createPubSub>, link: unknown) {\n pubSub.publish(\"linkCreated\", {\n link,\n sourceId: linkEndpoint(link, \"sourceId\"),\n targetId: linkEndpoint(link, \"targetId\"),\n });\n}\n\nexport function publishStatsUpdated(pubSub: ReturnType<typeof createPubSub>, stats: unknown) {\n pubSub.publish(\"statsUpdated\", { stats });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"graphql-server.js","names":[],"sources":["../../routes/graphql-server.ts"],"sourcesContent":["/**\n * GraphQL Server for OpenClaw Hybrid Memory\n * Provides GraphQL API endpoint with subscriptions support\n */\n\ninterface MemoryPluginContext {\n config?: unknown;\n [key: string]: unknown;\n}\n\nimport { createSchema, createYoga, createPubSub } from \"graphql-yoga\";\nimport type { FactsDB } from \"../backends/facts-db.js\";\nimport type { VectorDB } from \"../backends/vector-db.js\";\nimport { graphqlSchema } from \"./graphql-schema.js\";\nimport { pluginLogger } from \"../utils/logger.js\";\nimport { resolvers, type GraphQLContext } from \"./graphql-resolvers.js\";\n\ntype FactSubscriptionPayload = { fact: unknown; category?: string; scope?: string };\ntype FactUpdatedPayload = { fact: unknown; factId?: string; category?: string };\ntype FactDeletedPayload = { id: string; category?: string };\ntype LinkCreatedPayload = { link: unknown; sourceId?: string; targetId?: string };\ntype StatsUpdatedPayload = { stats: unknown };\n\n// PubSub for subscriptions\nconst pubSub = createPubSub<{\n factCreated: [FactSubscriptionPayload];\n factUpdated: [FactUpdatedPayload];\n factDeleted: [FactDeletedPayload];\n linkCreated: [LinkCreatedPayload];\n statsUpdated: [StatsUpdatedPayload];\n}>();\n\nfunction recordValue(value: unknown, key: string): unknown {\n return value && typeof value === \"object\" ? (value as Record<string, unknown>)[key] : undefined;\n}\n\nfunction optionalMatches(expected: unknown, actual: unknown): boolean {\n return expected == null || expected === \"\" || actual === expected;\n}\n\nfunction factCategory(fact: unknown, fallback?: string): string | undefined {\n return typeof recordValue(fact, \"category\") === \"string\" ? (recordValue(fact, \"category\") as string) : fallback;\n}\n\nfunction factScope(fact: unknown, fallback?: string): string | undefined {\n return typeof recordValue(fact, \"scope\") === \"string\" ? (recordValue(fact, \"scope\") as string) : fallback;\n}\n\nfunction factId(fact: unknown): string | undefined {\n return typeof recordValue(fact, \"id\") === \"string\" ? (recordValue(fact, \"id\") as string) : undefined;\n}\n\nfunction linkEndpoint(link: unknown, key: \"sourceId\" | \"targetId\", fallback?: string): string | undefined {\n const direct = recordValue(link, key);\n return typeof direct === \"string\" ? direct : fallback;\n}\n\nexport function matchesFactCreatedSubscription(\n payload: FactSubscriptionPayload,\n args: { category?: string; scope?: string },\n): boolean {\n return (\n optionalMatches(args.category, factCategory(payload.fact, payload.category)) &&\n optionalMatches(args.scope, factScope(payload.fact, payload.scope))\n );\n}\n\nexport function matchesFactUpdatedSubscription(\n payload: FactUpdatedPayload,\n args: { factId?: string; category?: string },\n): boolean {\n return (\n optionalMatches(args.factId, payload.factId ?? factId(payload.fact)) &&\n optionalMatches(args.category, factCategory(payload.fact, payload.category))\n );\n}\n\nexport function matchesFactDeletedSubscription(payload: FactDeletedPayload, args: { category?: string }): boolean {\n return optionalMatches(args.category, payload.category);\n}\n\nexport function matchesLinkCreatedSubscription(\n payload: LinkCreatedPayload,\n args: { sourceId?: string; targetId?: string },\n): boolean {\n return (\n optionalMatches(args.sourceId, linkEndpoint(payload.link, \"sourceId\", payload.sourceId)) &&\n optionalMatches(args.targetId, linkEndpoint(payload.link, \"targetId\", payload.targetId))\n );\n}\n\nasync function* filterAsyncIterator<T>(source: AsyncIterable<T>, predicate: (payload: T) => boolean): AsyncIterable<T> {\n for await (const payload of source) {\n if (predicate(payload)) yield payload;\n }\n}\n\n/**\n * Create GraphQL Yoga server instance\n */\nexport function createGraphQLServer(\n factsDb: FactsDB,\n vectorDb: VectorDB | undefined,\n pluginContext: MemoryPluginContext,\n) {\n const yoga = createYoga<GraphQLContext>({\n schema: createSchema({\n typeDefs: graphqlSchema,\n resolvers: {\n ...resolvers,\n Subscription: {\n factCreated: {\n subscribe: (_parent: unknown, args: { category?: string; scope?: string }) =>\n filterAsyncIterator(pubSub.subscribe(\"factCreated\"), (payload) =>\n matchesFactCreatedSubscription(payload, args),\n ),\n resolve: (payload: FactSubscriptionPayload) => payload.fact,\n },\n factUpdated: {\n subscribe: (_parent: unknown, args: { factId?: string; category?: string }) =>\n filterAsyncIterator(pubSub.subscribe(\"factUpdated\"), (payload) =>\n matchesFactUpdatedSubscription(payload, args),\n ),\n resolve: (payload: FactUpdatedPayload) => payload.fact,\n },\n factDeleted: {\n subscribe: (_parent: unknown, args: { category?: string }) =>\n filterAsyncIterator(pubSub.subscribe(\"factDeleted\"), (payload) =>\n matchesFactDeletedSubscription(payload, args),\n ),\n resolve: (payload: FactDeletedPayload) => payload.id,\n },\n linkCreated: {\n subscribe: (_parent: unknown, args: { sourceId?: string; targetId?: string }) =>\n filterAsyncIterator(pubSub.subscribe(\"linkCreated\"), (payload) =>\n matchesLinkCreatedSubscription(payload, args),\n ),\n resolve: (payload: LinkCreatedPayload) => payload.link,\n },\n statsUpdated: {\n subscribe: () => pubSub.subscribe(\"statsUpdated\"),\n resolve: (payload: StatsUpdatedPayload) => payload.stats,\n },\n },\n },\n }),\n context: (): GraphQLContext => ({\n factsDb,\n vectorDb,\n pluginContext,\n }),\n graphiql: {\n title: \"OpenClaw Hybrid Memory GraphQL API\",\n defaultQuery: `# Welcome to OpenClaw Hybrid Memory GraphQL API\n#\n# Example queries:\n\n# Get all facts with pagination\nquery GetFacts {\n facts(limit: 10, offset: 0) {\n id\n text\n category\n importance\n confidence\n createdAt\n tags\n }\n}\n\n# Search for memories\nquery SearchMemories {\n search(input: {\n query: \"user preferences\"\n limit: 5\n }) {\n fact {\n id\n text\n category\n }\n score\n matchType\n }\n}\n\n# Get memory statistics\nquery GetStats {\n stats {\n totalFacts\n activeFactsCount\n factsByCategory {\n category\n count\n }\n }\n}\n\n# Visualize memory graph\nquery GetGraph {\n graph(filter: {\n minImportance: 0.5\n categories: [\"preference\", \"decision\"]\n }) {\n nodes {\n id\n label\n category\n importance\n }\n edges {\n source\n target\n linkType\n }\n }\n}\n\n# Create a new fact\nmutation CreateFact {\n createFact(input: {\n text: \"User prefers dark mode\"\n category: \"preference\"\n importance: 0.8\n tags: [\"ui\", \"preference\"]\n }) {\n id\n text\n createdAt\n }\n}\n\n# Subscribe to new facts (WebSocket)\nsubscription WatchNewFacts {\n factCreated(category: \"preference\") {\n id\n text\n category\n }\n}\n`,\n },\n cors: {\n origin: \"*\",\n credentials: false,\n methods: [\"GET\", \"POST\", \"OPTIONS\"],\n },\n logging: {\n debug: (...args) => pluginLogger.debug(args.map(String).join(\" \")),\n info: (...args) => pluginLogger.info(args.map(String).join(\" \")),\n warn: (...args) => pluginLogger.warn(args.map(String).join(\" \")),\n error: (...args) => pluginLogger.error(args.map(String).join(\" \")),\n },\n });\n\n return { yoga, pubSub };\n}\n\n/**\n * Publish fact created event\n */\nexport function publishFactCreated(\n pubSub: ReturnType<typeof createPubSub>,\n fact: unknown,\n category?: string,\n scope?: string,\n) {\n pubSub.publish(\"factCreated\", { fact, category, scope });\n}\n\n/**\n * Publish fact updated event\n */\nexport function publishFactUpdated(pubSub: ReturnType<typeof createPubSub>, fact: unknown) {\n pubSub.publish(\"factUpdated\", { fact, factId: factId(fact), category: factCategory(fact) });\n}\n\n/**\n * Publish fact deleted event\n */\nexport function publishFactDeleted(pubSub: ReturnType<typeof createPubSub>, id: string, category?: string) {\n pubSub.publish(\"factDeleted\", { id, category });\n}\n\n/**\n * Publish stats updated event\n */\nexport function publishLinkCreated(pubSub: ReturnType<typeof createPubSub>, link: unknown) {\n pubSub.publish(\"linkCreated\", {\n link,\n sourceId: linkEndpoint(link, \"sourceId\"),\n targetId: linkEndpoint(link, \"targetId\"),\n });\n}\n\nexport function publishStatsUpdated(pubSub: ReturnType<typeof createPubSub>, stats: unknown) {\n pubSub.publish(\"statsUpdated\", { stats });\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"active-task-checkpoint.js","names":["mkdirAsync","e","statAsync","rmAsync"],"sources":["../../services/active-task-checkpoint.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { mkdir as mkdirAsync, rm as rmAsync, stat as statAsync } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { isAbsolute, join } from \"node:path\";\nimport type { FactsDB } from \"../backends/facts-db.js\";\nimport type { VectorDB } from \"../backends/vector-db.js\";\nimport { type HybridMemoryConfig, getCronModelConfig, getDefaultCronModel, getLLMModelPreference } from \"../config.js\";\nimport type { EpisodeOutcome, MemoryEntry, ScopeFilter } from \"../types/memory.js\";\nimport { parseDuration } from \"../utils/duration.js\";\nimport { getEnv } from \"../utils/env-manager.js\";\nimport { renderActiveTaskMarkdownFile, taskEntityKey, upsertProjectTaskKey } from \"./task-ledger-facts.js\";\nimport { buildGuardPrefix } from \"./cron-guard.js\";\nimport type { EmbeddingProvider } from \"./embeddings.js\";\n\nconst ACTIVE_TASK_WAKE_JOB_PREFIX = \"hybrid-mem:active-task-wake:\";\nconst ACTIVE_TASK_WAKE_GUARD_YEARS = 10;\nconst CRON_JOBS_LOCK_RETRY_MS = 25;\nconst CRON_JOBS_LOCK_MAX_RETRIES = 200;\nconst CRON_JOBS_LOCK_STALE_MS = 2 * 60 * 1000;\n\nexport interface ActiveTaskCheckpointInput {\n entity?: string;\n status?: string;\n owner?: string;\n next?: string;\n relatedSession?: string;\n title?: string;\n resumeAt?: string;\n state?: Record<string, unknown>;\n scheduleWake?: boolean;\n refreshProjection?: boolean;\n recordEpisode?: boolean;\n}\n\nexport interface ActiveTaskCheckpointDeps {\n factsDb: FactsDB;\n vectorDb: VectorDB;\n embeddings: EmbeddingProvider;\n cfg: HybridMemoryConfig;\n logger?: { warn?: (msg: string) => void; info?: (msg: string) => void };\n openclawDir?: string;\n workspaceRoot?: string;\n now?: () => Date;\n episodeScopeFilter?: ScopeFilter | null;\n scheduleWakeFn?: (args: ActiveTaskWakeScheduleInput) => Promise<ActiveTaskWakeScheduleResult>;\n refreshProjectionFn?: (args: ActiveTaskProjectionRefreshInput) => Promise<ActiveTaskProjectionRefreshResult>;\n}\n\ninterface NormalizedCheckpointInput {\n entity: string;\n status?: string;\n owner?: string;\n next?: string;\n relatedSession?: string;\n title?: string;\n resumeAtIso?: string;\n resumeAtDate?: Date;\n state?: Record<string, unknown>;\n scheduleWake: boolean;\n refreshProjection: boolean;\n recordEpisode: boolean;\n}\n\nexport type ActiveTaskCheckpointStep = \"validation\" | \"facts\" | \"episode\" | \"schedule\" | \"projection\";\n\nexport interface ActiveTaskCheckpointError {\n step: ActiveTaskCheckpointStep;\n message: string;\n}\n\nexport interface ActiveTaskWakeScheduleInput {\n cfg: HybridMemoryConfig;\n entity: string;\n status: string;\n owner?: string;\n next?: string;\n relatedSession?: string;\n title?: string;\n resumeAt: Date;\n state?: Record<string, unknown>;\n openclawDir?: string;\n}\n\nexport interface ActiveTaskWakeScheduleResult {\n scheduled: boolean;\n jobId: string;\n scheduleKind: \"at\";\n scheduleAt: string;\n jobsPath: string;\n disabledPreviousJobs: number;\n}\n\nexport interface ActiveTaskProjectionRefreshInput {\n cfg: HybridMemoryConfig;\n factsDb: FactsDB;\n workspaceRoot?: string;\n}\n\nexport interface ActiveTaskProjectionRefreshResult {\n attempted: boolean;\n refreshed: boolean;\n path?: string;\n reason?: string;\n}\n\nexport interface ActiveTaskCheckpointResult {\n ok: boolean;\n partial: boolean;\n message: string;\n checkpoint?: {\n entity: string;\n status: string;\n owner: string;\n next: string;\n relatedSession: string;\n title?: string;\n resumeAt?: string;\n taskUpdated: string;\n state?: Record<string, unknown>;\n };\n steps: {\n facts: {\n ok: boolean;\n updatedKeys: string[];\n failedKeys: string[];\n titleSource?: \"provided\" | \"existing\" | \"defaulted\";\n };\n episode: {\n attempted: boolean;\n ok: boolean;\n episodeId?: string;\n skippedReason?: string;\n };\n schedule: {\n attempted: boolean;\n scheduled: boolean;\n jobId?: string;\n scheduleKind?: \"at\";\n scheduleAt?: string;\n jobsPath?: string;\n disabledPreviousJobs?: number;\n skippedReason?: string;\n };\n projection: ActiveTaskProjectionRefreshResult;\n };\n errors: ActiveTaskCheckpointError[];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction trimToString(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction normalizeStatus(raw?: string): string | undefined {\n if (raw === undefined) return undefined;\n if (!raw.trim()) return \"in_progress\";\n const value = raw.trim().toLowerCase();\n if (value === \"open\" || value === \"in_progress\" || value === \"in progress\" || value === \"working\") {\n return \"in_progress\";\n }\n if (value === \"blocked\" || value === \"stalled\") return \"blocked\";\n if (value === \"waiting\" || value === \"on_hold\" || value === \"on hold\") return \"waiting\";\n if (value === \"done\" || value === \"completed\" || value === \"closed\") {\n return \"done\";\n }\n if (value === \"cancelled\" || value === \"canceled\" || value === \"abandoned\") {\n return \"cancelled\";\n }\n if (value === \"failed\" || value === \"error\") return \"failed\";\n return undefined;\n}\n\nfunction normalizeExistingStatus(raw?: string): string | undefined {\n const value = trimToString(raw);\n if (value === undefined) return undefined;\n const lower = value.toLowerCase();\n if (lower === \"abandoned\" || lower === \"superseded\") return lower;\n const normalized = normalizeStatus(value);\n if (normalized) return normalized;\n return lower;\n}\n\nconst TERMINAL_CHECKPOINT_STATUSES = new Set([\"done\", \"failed\", \"cancelled\", \"abandoned\", \"superseded\"]);\n\nfunction isTerminalCheckpointStatus(status: string): boolean {\n return TERMINAL_CHECKPOINT_STATUSES.has(status);\n}\n\nfunction normalizeCheckpointInput(\n input: ActiveTaskCheckpointInput,\n _now: Date,\n): {\n normalized?: NormalizedCheckpointInput;\n errors: ActiveTaskCheckpointError[];\n} {\n const errors: ActiveTaskCheckpointError[] = [];\n\n const entity = trimToString(input.entity);\n if (!entity) {\n errors.push({ step: \"validation\", message: \"entity is required\" });\n }\n\n const status = normalizeStatus(input.status);\n if (input.status !== undefined && !status) {\n errors.push({\n step: \"validation\",\n message:\n \"status must be one of: open, in_progress, blocked, waiting, done/completed/closed, cancelled/canceled/abandoned, failed\",\n });\n }\n\n const title = trimToString(input.title);\n const owner = input.owner !== undefined ? (trimToString(input.owner) ?? \"\") : undefined;\n const next = input.next !== undefined ? (trimToString(input.next) ?? \"\") : undefined;\n const relatedSession = input.relatedSession !== undefined ? (trimToString(input.relatedSession) ?? \"\") : undefined;\n\n let resumeAtIso: string | undefined;\n let resumeAtDate: Date | undefined;\n if (input.resumeAt !== undefined) {\n const rawResumeAt = trimToString(input.resumeAt);\n if (!rawResumeAt) {\n errors.push({ step: \"validation\", message: \"resumeAt must be a non-empty ISO timestamp\" });\n } else {\n const parsed = new Date(rawResumeAt);\n if (Number.isNaN(parsed.getTime())) {\n errors.push({ step: \"validation\", message: \"resumeAt must be a valid ISO timestamp\" });\n } else {\n // Accept past timestamps so missed reminders can be caught up by the cron scanner.\n resumeAtDate = parsed;\n resumeAtIso = parsed.toISOString();\n }\n }\n }\n\n if (input.state !== undefined && !isRecord(input.state)) {\n errors.push({ step: \"validation\", message: \"state must be an object when provided\" });\n }\n\n if (errors.length > 0 || !entity) {\n return { errors };\n }\n\n return {\n normalized: {\n entity,\n status,\n owner,\n next,\n relatedSession,\n title,\n resumeAtIso,\n resumeAtDate,\n state: input.state,\n scheduleWake: input.scheduleWake !== false,\n refreshProjection: input.refreshProjection === true,\n recordEpisode: input.recordEpisode !== false,\n },\n errors,\n };\n}\n\nfunction slugify(input: string): string {\n return input\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 64);\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction extractProjectValueFromText(text: string, key: string): string | undefined {\n const trimmedText = text.trim();\n if (!trimmedText) return undefined;\n const keyPattern = escapeRegExp(key);\n const match = trimmedText.match(new RegExp(`^Task \\\\[[^\\\\]]+\\\\] ${keyPattern}:\\\\s*(.*)$`));\n if (match) {\n return (match[1] ?? \"\").trim();\n }\n return trimToString(trimmedText);\n}\n\nfunction primeLatestProjectFactCacheForEntityKeys(\n factsDb: FactsDB,\n cache: Map<string, MemoryEntry>,\n entity: string,\n keys: readonly string[],\n): void {\n const normalizedEntity = entity.trim().toLowerCase();\n for (const key of keys) {\n const normalizedKey = key.trim();\n if (!normalizedKey) continue;\n const cacheKey = taskEntityKey(normalizedEntity, normalizedKey);\n if (cache.has(cacheKey)) continue;\n const hit = factsDb.lookup(entity, normalizedKey, undefined, { includeSuperseded: false, limit: 1 })[0]?.entry;\n if (!hit) continue;\n if ((hit.category ?? \"\").trim() !== \"project\") continue;\n cache.set(cacheKey, hit);\n }\n}\n\nfunction getLatestProjectValue(cache: Map<string, MemoryEntry>, entity: string, key: string): string | undefined {\n const normalizedEntity = entity.trim().toLowerCase();\n const row = cache.get(taskEntityKey(normalizedEntity, key));\n if (!row) return undefined;\n if (typeof row.value === \"string\") return row.value.trim();\n if (typeof row.text === \"string\") {\n return extractProjectValueFromText(row.text, key);\n }\n return trimToString(row.value) ?? undefined;\n}\n\nfunction wakeEntityKey(entity: string): string {\n const slug = slugify(entity).slice(0, 40) || \"task\";\n const digest = createHash(\"sha1\").update(entity).digest(\"hex\").slice(0, 12);\n return `${slug}-${digest}`;\n}\n\nfunction disableActiveTaskWakeJobs(\n jobs: Array<Record<string, unknown>>,\n entity: string,\n opts?: { excludeJobId?: string },\n): number {\n const entityPrefix = `${ACTIVE_TASK_WAKE_JOB_PREFIX}${wakeEntityKey(entity)}:`;\n let disabled = 0;\n for (const row of jobs) {\n const pluginJobId = typeof row.pluginJobId === \"string\" ? row.pluginJobId : \"\";\n const id = typeof row.id === \"string\" ? row.id : \"\";\n const rowId = pluginJobId || id;\n if (!rowId) continue;\n if (opts?.excludeJobId && (pluginJobId === opts.excludeJobId || id === opts.excludeJobId)) continue;\n if (!rowId.startsWith(entityPrefix)) continue;\n if (row.enabled !== false) {\n row.enabled = false;\n disabled += 1;\n }\n }\n return disabled;\n}\n\nasync function acquireCronJobsLock(openclawDir: string): Promise<string> {\n const lockPath = join(openclawDir, \"cron\", \".jobs-write-lock\");\n for (let attempt = 0; attempt < CRON_JOBS_LOCK_MAX_RETRIES; attempt++) {\n try {\n await mkdirAsync(lockPath, { recursive: false });\n return lockPath;\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n if (e.code !== \"EEXIST\") throw err;\n try {\n const lockStat = await statAsync(lockPath);\n if (Date.now() - lockStat.mtimeMs > CRON_JOBS_LOCK_STALE_MS) {\n await rmAsync(lockPath, { recursive: true, force: true }).catch(() => {});\n continue;\n }\n } catch {\n // Lock may be replaced/removed by another process; continue retrying.\n }\n await new Promise((resolve) => setTimeout(resolve, CRON_JOBS_LOCK_RETRY_MS));\n }\n }\n throw new Error(\"timed out waiting for cron jobs lock\");\n}\n\nasync function withCronJobsLock<T>(openclawDir: string, fn: () => T | Promise<T>): Promise<T> {\n await mkdirAsync(join(openclawDir, \"cron\"), { recursive: true });\n const lockPath = await acquireCronJobsLock(openclawDir);\n try {\n return await fn();\n } finally {\n await rmAsync(lockPath, { recursive: true, force: true }).catch(() => {});\n }\n}\n\nasync function disableActiveTaskWakeJobsForEntity(\n entity: string,\n openclawDirOverride?: string,\n): Promise<{ jobsPath: string; disabled: number }> {\n const openclawDir = resolveOpenclawDir(openclawDirOverride);\n return withCronJobsLock(openclawDir, () => {\n const cronDir = join(openclawDir, \"cron\");\n const jobsPath = join(cronDir, \"jobs.json\");\n if (!existsSync(jobsPath)) {\n return { jobsPath, disabled: 0 };\n }\n\n let store: { jobs?: unknown[] };\n try {\n store = JSON.parse(readFileSync(jobsPath, \"utf-8\")) as { jobs?: unknown[] };\n } catch (err) {\n throw new Error(`failed to parse ${jobsPath}: ${String(err)}`);\n }\n\n if (!Array.isArray(store.jobs)) {\n return { jobsPath, disabled: 0 };\n }\n\n const jobs = store.jobs as Array<Record<string, unknown>>;\n const disabled = disableActiveTaskWakeJobs(jobs, entity);\n if (disabled <= 0) {\n return { jobsPath, disabled: 0 };\n }\n\n const payload = JSON.stringify(store, null, 2);\n const tmpPath = `${jobsPath}.${process.pid}.${Date.now()}.tmp`;\n writeFileSync(tmpPath, payload, \"utf-8\");\n renameSync(tmpPath, jobsPath);\n return { jobsPath, disabled };\n });\n}\n\nfunction resolveOpenclawDir(override?: string): string {\n if (override?.trim()) return override.trim();\n const env = getEnv(\"OPENCLAW_HOME\")?.trim();\n if (env) return env;\n return join(homedir(), \".openclaw\");\n}\n\nfunction resolveWorkspaceRoot(override?: string): string {\n if (override?.trim()) return override.trim();\n const env = getEnv(\"OPENCLAW_WORKSPACE\")?.trim();\n if (env) return env;\n return join(resolveOpenclawDir(), \"workspace\");\n}\n\nfunction resolveCronModel(cfg: HybridMemoryConfig): string {\n const cronCfg = getCronModelConfig(cfg);\n const pref = getLLMModelPreference(cronCfg, \"nano\");\n return pref[0] ?? getDefaultCronModel(cronCfg, \"nano\");\n}\n\nfunction safeJson(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return '{\"error\":\"unserializable\"}';\n }\n}\n\nfunction buildWakeMessage(args: {\n entity: string;\n status: string;\n owner?: string;\n next?: string;\n relatedSession?: string;\n title?: string;\n resumeAtIso: string;\n state?: Record<string, unknown>;\n guardYears: number;\n}): string {\n const lines: string[] = [\n `Active-task wake reminder for \"${args.entity}\".`,\n `Scheduled resume time (UTC): ${args.resumeAtIso}`,\n `Status: ${args.status}`,\n ];\n\n if (args.title) lines.push(`Title: ${args.title}`);\n if (args.owner) lines.push(`Owner: ${args.owner}`);\n if (args.relatedSession) lines.push(`Related session: ${args.relatedSession}`);\n if (args.next) lines.push(`Next: ${args.next}`);\n if (args.state) {\n const json = safeJson(args.state);\n lines.push(`Checkpoint state JSON: ${json.length > 1500 ? `${json.slice(0, 1500)}...` : json}`);\n }\n\n lines.push(\n `This reminder is guarded to avoid duplicate reruns for approximately ${args.guardYears} year(s).`,\n \"If work is still relevant, continue execution and update task state with active_task_checkpoint.\",\n );\n\n return lines.join(\"\\n\");\n}\n\nasync function scheduleActiveTaskWakeReminder(\n input: ActiveTaskWakeScheduleInput,\n): Promise<ActiveTaskWakeScheduleResult> {\n const openclawDir = resolveOpenclawDir(input.openclawDir);\n return withCronJobsLock(openclawDir, () => {\n const cronDir = join(openclawDir, \"cron\");\n const jobsPath = join(cronDir, \"jobs.json\");\n\n let store: { jobs?: unknown[] } = {};\n if (existsSync(jobsPath)) {\n try {\n store = JSON.parse(readFileSync(jobsPath, \"utf-8\")) as { jobs?: unknown[] };\n } catch (err) {\n throw new Error(`failed to parse ${jobsPath}: ${String(err)}`);\n }\n }\n\n if (!Array.isArray(store.jobs)) {\n store.jobs = [];\n }\n\n const jobs = store.jobs as Array<Record<string, unknown>>;\n const entitySlug = slugify(input.entity) || \"task\";\n const entityKey = wakeEntityKey(input.entity);\n const resumeAtIso = input.resumeAt.toISOString();\n const resumeEpochSec = Math.floor(input.resumeAt.getTime() / 1000);\n const jobId = `${ACTIVE_TASK_WAKE_JOB_PREFIX}${entityKey}:${resumeEpochSec}`;\n\n const disabledPreviousJobs = disableActiveTaskWakeJobs(jobs, input.entity, { excludeJobId: jobId });\n\n const model = resolveCronModel(input.cfg);\n const minIntervalMs = ACTIVE_TASK_WAKE_GUARD_YEARS * 365 * 24 * 60 * 60 * 1000;\n const guardJobName = `active-task-wake-${entityKey}-${resumeEpochSec}`;\n const guardPrefix = buildGuardPrefix(guardJobName, minIntervalMs, openclawDir);\n\n const job: Record<string, unknown> = {\n id: jobId,\n pluginJobId: jobId,\n name: `active-task-wake-${entitySlug}`,\n sessionTarget: \"isolated\",\n schedule: { kind: \"at\", at: resumeAtIso },\n deleteAfterRun: true,\n payload: {\n kind: \"agentTurn\",\n message:\n guardPrefix +\n buildWakeMessage({\n entity: input.entity,\n status: input.status,\n owner: input.owner,\n next: input.next,\n relatedSession: input.relatedSession,\n title: input.title,\n resumeAtIso,\n state: input.state,\n guardYears: ACTIVE_TASK_WAKE_GUARD_YEARS,\n }),\n model,\n },\n delivery: { mode: \"announce\" },\n enabled: true,\n metadata: {\n source: \"active_task_checkpoint\",\n entity: input.entity,\n resumeAt: resumeAtIso,\n createdAt: new Date().toISOString(),\n },\n };\n\n const existingIdx = jobs.findIndex((row) => {\n const pluginJobId = typeof row.pluginJobId === \"string\" ? row.pluginJobId : \"\";\n const id = typeof row.id === \"string\" ? row.id : \"\";\n return pluginJobId === jobId || id === jobId;\n });\n\n if (existingIdx >= 0) {\n jobs[existingIdx] = { ...(jobs[existingIdx] ?? {}), ...job };\n } else {\n jobs.push(job);\n }\n\n const payload = JSON.stringify(store, null, 2);\n const tmpPath = `${jobsPath}.${process.pid}.${Date.now()}.tmp`;\n writeFileSync(tmpPath, payload, \"utf-8\");\n renameSync(tmpPath, jobsPath);\n\n return {\n scheduled: true,\n jobId,\n scheduleKind: \"at\" as const,\n scheduleAt: resumeAtIso,\n jobsPath,\n disabledPreviousJobs,\n };\n });\n}\n\nasync function refreshActiveTaskProjectionFromFacts(\n input: ActiveTaskProjectionRefreshInput,\n): Promise<ActiveTaskProjectionRefreshResult> {\n if (!input.cfg.activeTask.enabled) {\n return { attempted: true, refreshed: false, reason: \"active_task_disabled\" };\n }\n if (input.cfg.activeTask.ledger !== \"facts\") {\n return { attempted: true, refreshed: false, reason: \"active_task_ledger_not_facts\" };\n }\n\n const workspaceRoot = resolveWorkspaceRoot(input.workspaceRoot);\n const activeTaskPath = isAbsolute(input.cfg.activeTask.filePath)\n ? input.cfg.activeTask.filePath\n : join(workspaceRoot, input.cfg.activeTask.filePath);\n const staleMinutes = parseDuration(input.cfg.activeTask.staleThreshold);\n\n await renderActiveTaskMarkdownFile(input.factsDb, staleMinutes, activeTaskPath, input.cfg.activeTask.projection);\n return { attempted: true, refreshed: true, path: activeTaskPath };\n}\n\nfunction stepError(step: ActiveTaskCheckpointStep, err: unknown): ActiveTaskCheckpointError {\n return { step, message: err instanceof Error ? err.message : String(err) };\n}\n\nfunction outcomeFromStatus(status: string): EpisodeOutcome {\n if (status === \"done\") return \"success\";\n if (status === \"failed\") return \"failure\";\n if (status === \"cancelled\" || status === \"abandoned\" || status === \"superseded\") return \"partial\";\n if (status === \"blocked\" || status === \"waiting\") return \"partial\";\n return \"unknown\";\n}\n\nfunction scopeFromFilter(filter?: ScopeFilter | null): {\n scope: \"global\" | \"user\" | \"agent\" | \"session\";\n scopeTarget: string | null;\n agentId?: string;\n userId?: string;\n sessionId?: string;\n} {\n if (filter?.sessionId?.trim()) {\n return {\n scope: \"session\",\n scopeTarget: filter.sessionId,\n agentId: filter.agentId ?? undefined,\n userId: filter.userId ?? undefined,\n sessionId: filter.sessionId,\n };\n }\n if (filter?.userId?.trim()) {\n return {\n scope: \"user\",\n scopeTarget: filter.userId,\n agentId: filter.agentId ?? undefined,\n userId: filter.userId,\n sessionId: filter.sessionId ?? undefined,\n };\n }\n if (filter?.agentId?.trim()) {\n return {\n scope: \"agent\",\n scopeTarget: filter.agentId,\n agentId: filter.agentId,\n userId: filter.userId ?? undefined,\n sessionId: filter.sessionId ?? undefined,\n };\n }\n return {\n scope: \"global\",\n scopeTarget: null,\n agentId: filter?.agentId ?? undefined,\n userId: filter?.userId ?? undefined,\n sessionId: filter?.sessionId ?? undefined,\n };\n}\n\nexport async function runActiveTaskCheckpoint(\n deps: ActiveTaskCheckpointDeps,\n input: ActiveTaskCheckpointInput,\n): Promise<ActiveTaskCheckpointResult> {\n const now = deps.now?.() ?? new Date();\n const validation = normalizeCheckpointInput(input, now);\n if (!validation.normalized) {\n return {\n ok: false,\n partial: false,\n message: `active_task_checkpoint validation failed: ${validation.errors.map((e) => e.message).join(\"; \")}`,\n steps: {\n facts: { ok: false, updatedKeys: [], failedKeys: [] },\n episode: { attempted: false, ok: false, skippedReason: \"validation_failed\" },\n schedule: { attempted: false, scheduled: false, skippedReason: \"validation_failed\" },\n projection: { attempted: false, refreshed: false, reason: \"validation_failed\" },\n },\n errors: validation.errors,\n };\n }\n\n const checkpoint = validation.normalized;\n const latestProjectFacts = new Map<string, MemoryEntry>();\n primeLatestProjectFactCacheForEntityKeys(deps.factsDb, latestProjectFacts, checkpoint.entity, [\n \"status\",\n \"owner\",\n \"next\",\n \"related_session\",\n \"title\",\n \"resume_at\",\n ]);\n const existingStatus = getLatestProjectValue(latestProjectFacts, checkpoint.entity, \"status\");\n const resolvedStatus = checkpoint.status ?? normalizeExistingStatus(existingStatus) ?? \"in_progress\";\n const resolvedOwner = checkpoint.owner ?? getLatestProjectValue(latestProjectFacts, checkpoint.entity, \"owner\") ?? \"\";\n const resolvedNext = checkpoint.next ?? getLatestProjectValue(latestProjectFacts, checkpoint.entity, \"next\") ?? \"\";\n const resolvedRelatedSession =\n checkpoint.relatedSession ?? getLatestProjectValue(latestProjectFacts, checkpoint.entity, \"related_session\") ?? \"\";\n const existingResumeAt = getLatestProjectValue(latestProjectFacts, checkpoint.entity, \"resume_at\");\n const terminalStatus = isTerminalCheckpointStatus(resolvedStatus);\n const taskUpdated = now.toISOString();\n const errors: ActiveTaskCheckpointError[] = [];\n const updatedKeys: string[] = [];\n const failedKeys: string[] = [];\n\n let titleSource: \"provided\" | \"existing\" | \"defaulted\" | undefined;\n let effectiveTitle = checkpoint.title;\n\n try {\n if (effectiveTitle) {\n titleSource = \"provided\";\n } else {\n const existingTitle = getLatestProjectValue(latestProjectFacts, checkpoint.entity, \"title\");\n if (existingTitle) {\n effectiveTitle = existingTitle;\n titleSource = \"existing\";\n } else {\n effectiveTitle = \"Project task\";\n titleSource = \"defaulted\";\n }\n }\n } catch (err) {\n deps.logger?.warn?.(`memory-hybrid: active-task checkpoint title lookup failed: ${String(err)}`);\n effectiveTitle = checkpoint.title ?? \"Project task\";\n titleSource = checkpoint.title ? \"provided\" : \"defaulted\";\n }\n\n const updates: Array<{ key: string; value: string }> = [\n { key: \"status\", value: resolvedStatus },\n { key: \"next\", value: resolvedNext },\n { key: \"owner\", value: resolvedOwner },\n { key: \"related_session\", value: resolvedRelatedSession },\n { key: \"task_updated\", value: taskUpdated },\n ];\n\n if (effectiveTitle) {\n updates.push({ key: \"title\", value: effectiveTitle });\n }\n\n if (checkpoint.state) {\n updates.push({ key: \"checkpoint_state\", value: safeJson(checkpoint.state) });\n }\n\n const shouldPersistResumeAt = !terminalStatus && !!checkpoint.resumeAtIso;\n const shouldClearResumeAt = !checkpoint.resumeAtIso || terminalStatus;\n if (shouldPersistResumeAt) {\n updates.push({ key: \"resume_at\", value: checkpoint.resumeAtIso as string });\n } else if (shouldClearResumeAt && existingResumeAt !== undefined) {\n updates.push({ key: \"resume_at\", value: \"\" });\n }\n\n primeLatestProjectFactCacheForEntityKeys(\n deps.factsDb,\n latestProjectFacts,\n checkpoint.entity,\n updates.map((u) => u.key),\n );\n\n for (const update of updates) {\n try {\n await upsertProjectTaskKey(\n deps.factsDb,\n deps.vectorDb,\n deps.embeddings,\n checkpoint.entity,\n update.key,\n update.value,\n deps.logger,\n { latestByEntityKey: latestProjectFacts },\n );\n updatedKeys.push(update.key);\n } catch (err) {\n failedKeys.push(update.key);\n errors.push(stepError(\"facts\", new Error(`${update.key}: ${String(err)}`)));\n }\n }\n\n let episodeId: string | undefined;\n let episodeAttempted = false;\n let episodeOk = false;\n let episodeSkippedReason: string | undefined;\n\n if (checkpoint.recordEpisode) {\n episodeAttempted = true;\n try {\n const scope = scopeFromFilter(deps.episodeScopeFilter);\n const contextLines: string[] = [\n `entity=${checkpoint.entity}`,\n `status=${resolvedStatus}`,\n `owner=${resolvedOwner || \"n/a\"}`,\n `next=${resolvedNext || \"n/a\"}`,\n `relatedSession=${resolvedRelatedSession || \"n/a\"}`,\n `taskUpdated=${taskUpdated}`,\n ];\n if (checkpoint.resumeAtIso) contextLines.push(`resumeAt=${checkpoint.resumeAtIso}`);\n if (checkpoint.state) contextLines.push(`state=${safeJson(checkpoint.state)}`);\n\n const ep = deps.factsDb.recordEpisode({\n event: `Active task checkpoint: ${checkpoint.entity}`,\n outcome: outcomeFromStatus(resolvedStatus),\n context: contextLines.join(\"\\n\"),\n importance: resolvedStatus === \"failed\" ? 0.8 : 0.6,\n tags: [\"active-task\", \"checkpoint\", slugify(checkpoint.entity)],\n scope: scope.scope,\n scopeTarget: scope.scopeTarget,\n agentId: scope.agentId,\n userId: scope.userId,\n sessionId: scope.sessionId,\n });\n episodeId = ep.id;\n episodeOk = true;\n } catch (err) {\n errors.push(stepError(\"episode\", err));\n }\n } else {\n episodeSkippedReason = \"record_episode_disabled\";\n }\n\n let wakeAttempted = false;\n let wakeScheduled = false;\n let wakeSkippedReason: string | undefined;\n let wakeResult: ActiveTaskWakeScheduleResult | undefined;\n let wakeJobsPath: string | undefined;\n let wakeDisabledPreviousJobs: number | undefined;\n\n if (failedKeys.length > 0) {\n wakeSkippedReason = \"facts_write_failed\";\n } else if (checkpoint.resumeAtIso && checkpoint.resumeAtDate && checkpoint.scheduleWake && !terminalStatus) {\n wakeAttempted = true;\n try {\n const scheduleWake = deps.scheduleWakeFn ?? scheduleActiveTaskWakeReminder;\n wakeResult = await scheduleWake({\n cfg: deps.cfg,\n entity: checkpoint.entity,\n status: resolvedStatus,\n owner: resolvedOwner || undefined,\n next: resolvedNext || undefined,\n relatedSession: resolvedRelatedSession || undefined,\n title: effectiveTitle,\n resumeAt: checkpoint.resumeAtDate,\n state: checkpoint.state,\n openclawDir: deps.openclawDir,\n });\n wakeScheduled = wakeResult.scheduled;\n wakeJobsPath = wakeResult.jobsPath;\n wakeDisabledPreviousJobs = wakeResult.disabledPreviousJobs;\n } catch (err) {\n errors.push(stepError(\"schedule\", err));\n }\n } else {\n wakeSkippedReason = terminalStatus\n ? \"terminal_status_no_wake\"\n : checkpoint.resumeAtIso\n ? \"schedule_wake_disabled\"\n : \"resumeAt_not_provided\";\n try {\n const cleanup = await disableActiveTaskWakeJobsForEntity(checkpoint.entity, deps.openclawDir);\n wakeJobsPath = cleanup.jobsPath;\n wakeDisabledPreviousJobs = cleanup.disabled;\n } catch (err) {\n errors.push(stepError(\"schedule\", err));\n }\n }\n\n let projection = {\n attempted: false,\n refreshed: false,\n reason: \"refresh_not_requested\",\n } as ActiveTaskProjectionRefreshResult;\n if (checkpoint.refreshProjection) {\n try {\n const refreshFn = deps.refreshProjectionFn ?? refreshActiveTaskProjectionFromFacts;\n projection = await refreshFn({\n cfg: deps.cfg,\n factsDb: deps.factsDb,\n workspaceRoot: deps.workspaceRoot,\n });\n } catch (err) {\n projection = { attempted: true, refreshed: false, reason: String(err) };\n errors.push(stepError(\"projection\", err));\n }\n }\n\n const ok = errors.length === 0;\n const partial = !ok && updatedKeys.length > 0;\n\n const summaryBits: string[] = [\n `entity=${checkpoint.entity}`,\n `status=${resolvedStatus}`,\n `facts=${updatedKeys.length}/${updates.length}`,\n checkpoint.recordEpisode ? `episode=${episodeOk ? \"recorded\" : \"failed\"}` : \"episode=skipped\",\n ];\n if (wakeAttempted) {\n summaryBits.push(`wake=${wakeScheduled ? \"scheduled\" : \"failed\"}`);\n } else if (wakeSkippedReason) {\n summaryBits.push(`wake=skipped(${wakeSkippedReason})`);\n }\n if (checkpoint.refreshProjection) {\n summaryBits.push(`projection=${projection.refreshed ? \"refreshed\" : \"not_refreshed\"}`);\n }\n\n const message = ok\n ? `active_task_checkpoint completed (${summaryBits.join(\", \")}).`\n : partial\n ? `active_task_checkpoint completed with partial failures (${summaryBits.join(\", \")}).`\n : `active_task_checkpoint failed (${summaryBits.join(\", \")}).`;\n\n return {\n ok,\n partial,\n message,\n checkpoint: {\n entity: checkpoint.entity,\n status: resolvedStatus,\n owner: resolvedOwner,\n next: resolvedNext,\n relatedSession: resolvedRelatedSession,\n title: effectiveTitle,\n resumeAt: checkpoint.resumeAtIso,\n taskUpdated,\n state: checkpoint.state,\n },\n steps: {\n facts: {\n ok: failedKeys.length === 0,\n updatedKeys,\n failedKeys,\n titleSource,\n },\n episode: {\n attempted: episodeAttempted,\n ok: episodeOk,\n episodeId,\n skippedReason: episodeSkippedReason,\n },\n schedule: {\n attempted: wakeAttempted,\n scheduled: wakeScheduled,\n jobId: wakeResult?.jobId,\n scheduleKind: wakeResult?.scheduleKind,\n scheduleAt: wakeResult?.scheduleAt,\n jobsPath: wakeJobsPath,\n disabledPreviousJobs: wakeDisabledPreviousJobs,\n skippedReason: wakeSkippedReason,\n },\n projection,\n },\n errors,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"active-task-checkpoint.js","names":["mkdirAsync","e","statAsync","rmAsync"],"sources":["../../services/active-task-checkpoint.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { mkdir as mkdirAsync, rm as rmAsync, stat as statAsync } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { isAbsolute, join } from \"node:path\";\nimport type { FactsDB } from \"../backends/facts-db.js\";\nimport type { VectorDB } from \"../backends/vector-db.js\";\nimport { type HybridMemoryConfig, getCronModelConfig, getDefaultCronModel, getLLMModelPreference } from \"../config.js\";\nimport type { EpisodeOutcome, MemoryEntry, ScopeFilter } from \"../types/memory.js\";\nimport { parseDuration } from \"../utils/duration.js\";\nimport { getEnv } from \"../utils/env-manager.js\";\nimport { renderActiveTaskMarkdownFile, taskEntityKey, upsertProjectTaskKey } from \"./task-ledger-facts.js\";\nimport { buildGuardPrefix } from \"./cron-guard.js\";\nimport type { EmbeddingProvider } from \"./embeddings.js\";\n\nconst ACTIVE_TASK_WAKE_JOB_PREFIX = \"hybrid-mem:active-task-wake:\";\nconst ACTIVE_TASK_WAKE_GUARD_YEARS = 10;\nconst CRON_JOBS_LOCK_RETRY_MS = 25;\nconst CRON_JOBS_LOCK_MAX_RETRIES = 200;\nconst CRON_JOBS_LOCK_STALE_MS = 2 * 60 * 1000;\n\nexport interface ActiveTaskCheckpointInput {\n entity?: string;\n status?: string;\n owner?: string;\n next?: string;\n relatedSession?: string;\n title?: string;\n resumeAt?: string;\n state?: Record<string, unknown>;\n scheduleWake?: boolean;\n refreshProjection?: boolean;\n recordEpisode?: boolean;\n}\n\nexport interface ActiveTaskCheckpointDeps {\n factsDb: FactsDB;\n vectorDb: VectorDB;\n embeddings: EmbeddingProvider;\n cfg: HybridMemoryConfig;\n logger?: { warn?: (msg: string) => void; info?: (msg: string) => void };\n openclawDir?: string;\n workspaceRoot?: string;\n now?: () => Date;\n episodeScopeFilter?: ScopeFilter | null;\n scheduleWakeFn?: (args: ActiveTaskWakeScheduleInput) => Promise<ActiveTaskWakeScheduleResult>;\n refreshProjectionFn?: (args: ActiveTaskProjectionRefreshInput) => Promise<ActiveTaskProjectionRefreshResult>;\n}\n\ninterface NormalizedCheckpointInput {\n entity: string;\n status?: string;\n owner?: string;\n next?: string;\n relatedSession?: string;\n title?: string;\n resumeAtIso?: string;\n resumeAtDate?: Date;\n state?: Record<string, unknown>;\n scheduleWake: boolean;\n refreshProjection: boolean;\n recordEpisode: boolean;\n}\n\nexport type ActiveTaskCheckpointStep = \"validation\" | \"facts\" | \"episode\" | \"schedule\" | \"projection\";\n\nexport interface ActiveTaskCheckpointError {\n step: ActiveTaskCheckpointStep;\n message: string;\n}\n\nexport interface ActiveTaskWakeScheduleInput {\n cfg: HybridMemoryConfig;\n entity: string;\n status: string;\n owner?: string;\n next?: string;\n relatedSession?: string;\n title?: string;\n resumeAt: Date;\n state?: Record<string, unknown>;\n openclawDir?: string;\n}\n\nexport interface ActiveTaskWakeScheduleResult {\n scheduled: boolean;\n jobId: string;\n scheduleKind: \"at\";\n scheduleAt: string;\n jobsPath: string;\n disabledPreviousJobs: number;\n}\n\nexport interface ActiveTaskProjectionRefreshInput {\n cfg: HybridMemoryConfig;\n factsDb: FactsDB;\n workspaceRoot?: string;\n}\n\nexport interface ActiveTaskProjectionRefreshResult {\n attempted: boolean;\n refreshed: boolean;\n path?: string;\n reason?: string;\n}\n\nexport interface ActiveTaskCheckpointResult {\n ok: boolean;\n partial: boolean;\n message: string;\n checkpoint?: {\n entity: string;\n status: string;\n owner: string;\n next: string;\n relatedSession: string;\n title?: string;\n resumeAt?: string;\n taskUpdated: string;\n state?: Record<string, unknown>;\n };\n steps: {\n facts: {\n ok: boolean;\n updatedKeys: string[];\n failedKeys: string[];\n titleSource?: \"provided\" | \"existing\" | \"defaulted\";\n };\n episode: {\n attempted: boolean;\n ok: boolean;\n episodeId?: string;\n skippedReason?: string;\n };\n schedule: {\n attempted: boolean;\n scheduled: boolean;\n jobId?: string;\n scheduleKind?: \"at\";\n scheduleAt?: string;\n jobsPath?: string;\n disabledPreviousJobs?: number;\n skippedReason?: string;\n };\n projection: ActiveTaskProjectionRefreshResult;\n };\n errors: ActiveTaskCheckpointError[];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction trimToString(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction normalizeStatus(raw?: string): string | undefined {\n if (raw === undefined) return undefined;\n if (!raw.trim()) return \"in_progress\";\n const value = raw.trim().toLowerCase();\n if (value === \"open\" || value === \"in_progress\" || value === \"in progress\" || value === \"working\") {\n return \"in_progress\";\n }\n if (value === \"blocked\" || value === \"stalled\") return \"blocked\";\n if (value === \"waiting\" || value === \"on_hold\" || value === \"on hold\") return \"waiting\";\n if (value === \"done\" || value === \"completed\" || value === \"closed\") {\n return \"done\";\n }\n if (value === \"cancelled\" || value === \"canceled\" || value === \"abandoned\") {\n return \"cancelled\";\n }\n if (value === \"failed\" || value === \"error\") return \"failed\";\n return undefined;\n}\n\nfunction normalizeExistingStatus(raw?: string): string | undefined {\n const value = trimToString(raw);\n if (value === undefined) return undefined;\n const lower = value.toLowerCase();\n if (lower === \"abandoned\" || lower === \"superseded\") return lower;\n const normalized = normalizeStatus(value);\n if (normalized) return normalized;\n return lower;\n}\n\nconst TERMINAL_CHECKPOINT_STATUSES = new Set([\"done\", \"failed\", \"cancelled\", \"abandoned\", \"superseded\"]);\n\nfunction isTerminalCheckpointStatus(status: string): boolean {\n return TERMINAL_CHECKPOINT_STATUSES.has(status);\n}\n\nfunction normalizeCheckpointInput(\n input: ActiveTaskCheckpointInput,\n _now: Date,\n): {\n normalized?: NormalizedCheckpointInput;\n errors: ActiveTaskCheckpointError[];\n} {\n const errors: ActiveTaskCheckpointError[] = [];\n\n const entity = trimToString(input.entity);\n if (!entity) {\n errors.push({ step: \"validation\", message: \"entity is required\" });\n }\n\n const status = normalizeStatus(input.status);\n if (input.status !== undefined && !status) {\n errors.push({\n step: \"validation\",\n message:\n \"status must be one of: open, in_progress, blocked, waiting, done/completed/closed, cancelled/canceled/abandoned, failed\",\n });\n }\n\n const title = trimToString(input.title);\n const owner = input.owner !== undefined ? (trimToString(input.owner) ?? \"\") : undefined;\n const next = input.next !== undefined ? (trimToString(input.next) ?? \"\") : undefined;\n const relatedSession = input.relatedSession !== undefined ? (trimToString(input.relatedSession) ?? \"\") : undefined;\n\n let resumeAtIso: string | undefined;\n let resumeAtDate: Date | undefined;\n if (input.resumeAt !== undefined) {\n const rawResumeAt = trimToString(input.resumeAt);\n if (!rawResumeAt) {\n errors.push({ step: \"validation\", message: \"resumeAt must be a non-empty ISO timestamp\" });\n } else {\n const parsed = new Date(rawResumeAt);\n if (Number.isNaN(parsed.getTime())) {\n errors.push({ step: \"validation\", message: \"resumeAt must be a valid ISO timestamp\" });\n } else {\n // Accept past timestamps so missed reminders can be caught up by the cron scanner.\n resumeAtDate = parsed;\n resumeAtIso = parsed.toISOString();\n }\n }\n }\n\n if (input.state !== undefined && !isRecord(input.state)) {\n errors.push({ step: \"validation\", message: \"state must be an object when provided\" });\n }\n\n if (errors.length > 0 || !entity) {\n return { errors };\n }\n\n return {\n normalized: {\n entity,\n status,\n owner,\n next,\n relatedSession,\n title,\n resumeAtIso,\n resumeAtDate,\n state: input.state,\n scheduleWake: input.scheduleWake !== false,\n refreshProjection: input.refreshProjection === true,\n recordEpisode: input.recordEpisode !== false,\n },\n errors,\n };\n}\n\nfunction slugify(input: string): string {\n return input\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 64);\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction extractProjectValueFromText(text: string, key: string): string | undefined {\n const trimmedText = text.trim();\n if (!trimmedText) return undefined;\n const keyPattern = escapeRegExp(key);\n const match = trimmedText.match(new RegExp(`^Task \\\\[[^\\\\]]+\\\\] ${keyPattern}:\\\\s*(.*)$`));\n if (match) {\n return (match[1] ?? \"\").trim();\n }\n return trimToString(trimmedText);\n}\n\nfunction primeLatestProjectFactCacheForEntityKeys(\n factsDb: FactsDB,\n cache: Map<string, MemoryEntry>,\n entity: string,\n keys: readonly string[],\n): void {\n const normalizedEntity = entity.trim().toLowerCase();\n for (const key of keys) {\n const normalizedKey = key.trim();\n if (!normalizedKey) continue;\n const cacheKey = taskEntityKey(normalizedEntity, normalizedKey);\n if (cache.has(cacheKey)) continue;\n const hit = factsDb.lookup(entity, normalizedKey, undefined, { includeSuperseded: false, limit: 1 })[0]?.entry;\n if (!hit) continue;\n if ((hit.category ?? \"\").trim() !== \"project\") continue;\n cache.set(cacheKey, hit);\n }\n}\n\nfunction getLatestProjectValue(cache: Map<string, MemoryEntry>, entity: string, key: string): string | undefined {\n const normalizedEntity = entity.trim().toLowerCase();\n const row = cache.get(taskEntityKey(normalizedEntity, key));\n if (!row) return undefined;\n if (typeof row.value === \"string\") return row.value.trim();\n if (typeof row.text === \"string\") {\n return extractProjectValueFromText(row.text, key);\n }\n return trimToString(row.value) ?? undefined;\n}\n\nfunction wakeEntityKey(entity: string): string {\n const slug = slugify(entity).slice(0, 40) || \"task\";\n const digest = createHash(\"sha1\").update(entity).digest(\"hex\").slice(0, 12);\n return `${slug}-${digest}`;\n}\n\nfunction disableActiveTaskWakeJobs(\n jobs: Array<Record<string, unknown>>,\n entity: string,\n opts?: { excludeJobId?: string },\n): number {\n const entityPrefix = `${ACTIVE_TASK_WAKE_JOB_PREFIX}${wakeEntityKey(entity)}:`;\n let disabled = 0;\n for (const row of jobs) {\n const pluginJobId = typeof row.pluginJobId === \"string\" ? row.pluginJobId : \"\";\n const id = typeof row.id === \"string\" ? row.id : \"\";\n const rowId = pluginJobId || id;\n if (!rowId) continue;\n if (opts?.excludeJobId && (pluginJobId === opts.excludeJobId || id === opts.excludeJobId)) continue;\n if (!rowId.startsWith(entityPrefix)) continue;\n if (row.enabled !== false) {\n row.enabled = false;\n disabled += 1;\n }\n }\n return disabled;\n}\n\nasync function acquireCronJobsLock(openclawDir: string): Promise<string> {\n const lockPath = join(openclawDir, \"cron\", \".jobs-write-lock\");\n for (let attempt = 0; attempt < CRON_JOBS_LOCK_MAX_RETRIES; attempt++) {\n try {\n await mkdirAsync(lockPath, { recursive: false });\n return lockPath;\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n if (e.code !== \"EEXIST\") throw err;\n try {\n const lockStat = await statAsync(lockPath);\n if (Date.now() - lockStat.mtimeMs > CRON_JOBS_LOCK_STALE_MS) {\n await rmAsync(lockPath, { recursive: true, force: true }).catch(() => {});\n continue;\n }\n } catch {\n // Lock may be replaced/removed by another process; continue retrying.\n }\n await new Promise((resolve) => setTimeout(resolve, CRON_JOBS_LOCK_RETRY_MS));\n }\n }\n throw new Error(\"timed out waiting for cron jobs lock\");\n}\n\nasync function withCronJobsLock<T>(openclawDir: string, fn: () => T | Promise<T>): Promise<T> {\n await mkdirAsync(join(openclawDir, \"cron\"), { recursive: true });\n const lockPath = await acquireCronJobsLock(openclawDir);\n try {\n return await fn();\n } finally {\n await rmAsync(lockPath, { recursive: true, force: true }).catch(() => {});\n }\n}\n\nasync function disableActiveTaskWakeJobsForEntity(\n entity: string,\n openclawDirOverride?: string,\n): Promise<{ jobsPath: string; disabled: number }> {\n const openclawDir = resolveOpenclawDir(openclawDirOverride);\n return withCronJobsLock(openclawDir, () => {\n const cronDir = join(openclawDir, \"cron\");\n const jobsPath = join(cronDir, \"jobs.json\");\n if (!existsSync(jobsPath)) {\n return { jobsPath, disabled: 0 };\n }\n\n let store: { jobs?: unknown[] };\n try {\n store = JSON.parse(readFileSync(jobsPath, \"utf-8\")) as { jobs?: unknown[] };\n } catch (err) {\n throw new Error(`failed to parse ${jobsPath}: ${String(err)}`);\n }\n\n if (!Array.isArray(store.jobs)) {\n return { jobsPath, disabled: 0 };\n }\n\n const jobs = store.jobs as Array<Record<string, unknown>>;\n const disabled = disableActiveTaskWakeJobs(jobs, entity);\n if (disabled <= 0) {\n return { jobsPath, disabled: 0 };\n }\n\n const payload = JSON.stringify(store, null, 2);\n const tmpPath = `${jobsPath}.${process.pid}.${Date.now()}.tmp`;\n writeFileSync(tmpPath, payload, \"utf-8\");\n renameSync(tmpPath, jobsPath);\n return { jobsPath, disabled };\n });\n}\n\nfunction resolveOpenclawDir(override?: string): string {\n if (override?.trim()) return override.trim();\n const env = getEnv(\"OPENCLAW_HOME\")?.trim();\n if (env) return env;\n return join(homedir(), \".openclaw\");\n}\n\nfunction resolveWorkspaceRoot(override?: string): string {\n if (override?.trim()) return override.trim();\n const env = getEnv(\"OPENCLAW_WORKSPACE\")?.trim();\n if (env) return env;\n return join(resolveOpenclawDir(), \"workspace\");\n}\n\nfunction resolveCronModel(cfg: HybridMemoryConfig): string {\n const cronCfg = getCronModelConfig(cfg);\n const pref = getLLMModelPreference(cronCfg, \"nano\");\n return pref[0] ?? getDefaultCronModel(cronCfg, \"nano\");\n}\n\nfunction safeJson(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return '{\"error\":\"unserializable\"}';\n }\n}\n\nfunction buildWakeMessage(args: {\n entity: string;\n status: string;\n owner?: string;\n next?: string;\n relatedSession?: string;\n title?: string;\n resumeAtIso: string;\n state?: Record<string, unknown>;\n guardYears: number;\n}): string {\n const lines: string[] = [\n `Active-task wake reminder for \"${args.entity}\".`,\n `Scheduled resume time (UTC): ${args.resumeAtIso}`,\n `Status: ${args.status}`,\n ];\n\n if (args.title) lines.push(`Title: ${args.title}`);\n if (args.owner) lines.push(`Owner: ${args.owner}`);\n if (args.relatedSession) lines.push(`Related session: ${args.relatedSession}`);\n if (args.next) lines.push(`Next: ${args.next}`);\n if (args.state) {\n const json = safeJson(args.state);\n lines.push(`Checkpoint state JSON: ${json.length > 1500 ? `${json.slice(0, 1500)}...` : json}`);\n }\n\n lines.push(\n `This reminder is guarded to avoid duplicate reruns for approximately ${args.guardYears} year(s).`,\n \"If work is still relevant, continue execution and update task state with active_task_checkpoint.\",\n );\n\n return lines.join(\"\\n\");\n}\n\nasync function scheduleActiveTaskWakeReminder(\n input: ActiveTaskWakeScheduleInput,\n): Promise<ActiveTaskWakeScheduleResult> {\n const openclawDir = resolveOpenclawDir(input.openclawDir);\n return withCronJobsLock(openclawDir, () => {\n const cronDir = join(openclawDir, \"cron\");\n const jobsPath = join(cronDir, \"jobs.json\");\n\n let store: { jobs?: unknown[] } = {};\n if (existsSync(jobsPath)) {\n try {\n store = JSON.parse(readFileSync(jobsPath, \"utf-8\")) as { jobs?: unknown[] };\n } catch (err) {\n throw new Error(`failed to parse ${jobsPath}: ${String(err)}`);\n }\n }\n\n if (!Array.isArray(store.jobs)) {\n store.jobs = [];\n }\n\n const jobs = store.jobs as Array<Record<string, unknown>>;\n const entitySlug = slugify(input.entity) || \"task\";\n const entityKey = wakeEntityKey(input.entity);\n const resumeAtIso = input.resumeAt.toISOString();\n const resumeEpochSec = Math.floor(input.resumeAt.getTime() / 1000);\n const jobId = `${ACTIVE_TASK_WAKE_JOB_PREFIX}${entityKey}:${resumeEpochSec}`;\n\n const disabledPreviousJobs = disableActiveTaskWakeJobs(jobs, input.entity, { excludeJobId: jobId });\n\n const model = resolveCronModel(input.cfg);\n const minIntervalMs = ACTIVE_TASK_WAKE_GUARD_YEARS * 365 * 24 * 60 * 60 * 1000;\n const guardJobName = `active-task-wake-${entityKey}-${resumeEpochSec}`;\n const guardPrefix = buildGuardPrefix(guardJobName, minIntervalMs, openclawDir);\n\n const job: Record<string, unknown> = {\n id: jobId,\n pluginJobId: jobId,\n name: `active-task-wake-${entitySlug}`,\n sessionTarget: \"isolated\",\n schedule: { kind: \"at\", at: resumeAtIso },\n deleteAfterRun: true,\n payload: {\n kind: \"agentTurn\",\n message:\n guardPrefix +\n buildWakeMessage({\n entity: input.entity,\n status: input.status,\n owner: input.owner,\n next: input.next,\n relatedSession: input.relatedSession,\n title: input.title,\n resumeAtIso,\n state: input.state,\n guardYears: ACTIVE_TASK_WAKE_GUARD_YEARS,\n }),\n model,\n },\n delivery: { mode: \"announce\" },\n enabled: true,\n metadata: {\n source: \"active_task_checkpoint\",\n entity: input.entity,\n resumeAt: resumeAtIso,\n createdAt: new Date().toISOString(),\n },\n };\n\n const existingIdx = jobs.findIndex((row) => {\n const pluginJobId = typeof row.pluginJobId === \"string\" ? row.pluginJobId : \"\";\n const id = typeof row.id === \"string\" ? row.id : \"\";\n return pluginJobId === jobId || id === jobId;\n });\n\n if (existingIdx >= 0) {\n jobs[existingIdx] = { ...(jobs[existingIdx] ?? {}), ...job };\n } else {\n jobs.push(job);\n }\n\n const payload = JSON.stringify(store, null, 2);\n const tmpPath = `${jobsPath}.${process.pid}.${Date.now()}.tmp`;\n writeFileSync(tmpPath, payload, \"utf-8\");\n renameSync(tmpPath, jobsPath);\n\n return {\n scheduled: true,\n jobId,\n scheduleKind: \"at\" as const,\n scheduleAt: resumeAtIso,\n jobsPath,\n disabledPreviousJobs,\n };\n });\n}\n\nasync function refreshActiveTaskProjectionFromFacts(\n input: ActiveTaskProjectionRefreshInput,\n): Promise<ActiveTaskProjectionRefreshResult> {\n if (!input.cfg.activeTask.enabled) {\n return { attempted: true, refreshed: false, reason: \"active_task_disabled\" };\n }\n if (input.cfg.activeTask.ledger !== \"facts\") {\n return { attempted: true, refreshed: false, reason: \"active_task_ledger_not_facts\" };\n }\n\n const workspaceRoot = resolveWorkspaceRoot(input.workspaceRoot);\n const activeTaskPath = isAbsolute(input.cfg.activeTask.filePath)\n ? input.cfg.activeTask.filePath\n : join(workspaceRoot, input.cfg.activeTask.filePath);\n const staleMinutes = parseDuration(input.cfg.activeTask.staleThreshold);\n\n await renderActiveTaskMarkdownFile(input.factsDb, staleMinutes, activeTaskPath, input.cfg.activeTask.projection);\n return { attempted: true, refreshed: true, path: activeTaskPath };\n}\n\nfunction stepError(step: ActiveTaskCheckpointStep, err: unknown): ActiveTaskCheckpointError {\n return { step, message: err instanceof Error ? err.message : String(err) };\n}\n\nfunction outcomeFromStatus(status: string): EpisodeOutcome {\n if (status === \"done\") return \"success\";\n if (status === \"failed\") return \"failure\";\n if (status === \"cancelled\" || status === \"abandoned\" || status === \"superseded\") return \"partial\";\n if (status === \"blocked\" || status === \"waiting\") return \"partial\";\n return \"unknown\";\n}\n\nfunction scopeFromFilter(filter?: ScopeFilter | null): {\n scope: \"global\" | \"user\" | \"agent\" | \"session\";\n scopeTarget: string | null;\n agentId?: string;\n userId?: string;\n sessionId?: string;\n} {\n if (filter?.sessionId?.trim()) {\n return {\n scope: \"session\",\n scopeTarget: filter.sessionId,\n agentId: filter.agentId ?? undefined,\n userId: filter.userId ?? undefined,\n sessionId: filter.sessionId,\n };\n }\n if (filter?.userId?.trim()) {\n return {\n scope: \"user\",\n scopeTarget: filter.userId,\n agentId: filter.agentId ?? undefined,\n userId: filter.userId,\n sessionId: filter.sessionId ?? undefined,\n };\n }\n if (filter?.agentId?.trim()) {\n return {\n scope: \"agent\",\n scopeTarget: filter.agentId,\n agentId: filter.agentId,\n userId: filter.userId ?? undefined,\n sessionId: filter.sessionId ?? undefined,\n };\n }\n return {\n scope: \"global\",\n scopeTarget: null,\n agentId: filter?.agentId ?? undefined,\n userId: filter?.userId ?? undefined,\n sessionId: filter?.sessionId ?? undefined,\n };\n}\n\nexport async function runActiveTaskCheckpoint(\n deps: ActiveTaskCheckpointDeps,\n input: ActiveTaskCheckpointInput,\n): Promise<ActiveTaskCheckpointResult> {\n const now = deps.now?.() ?? new Date();\n const validation = normalizeCheckpointInput(input, now);\n if (!validation.normalized) {\n return {\n ok: false,\n partial: false,\n message: `active_task_checkpoint validation failed: ${validation.errors.map((e) => e.message).join(\"; \")}`,\n steps: {\n facts: { ok: false, updatedKeys: [], failedKeys: [] },\n episode: { attempted: false, ok: false, skippedReason: \"validation_failed\" },\n schedule: { attempted: false, scheduled: false, skippedReason: \"validation_failed\" },\n projection: { attempted: false, refreshed: false, reason: \"validation_failed\" },\n },\n errors: validation.errors,\n };\n }\n\n const checkpoint = validation.normalized;\n const latestProjectFacts = new Map<string, MemoryEntry>();\n primeLatestProjectFactCacheForEntityKeys(deps.factsDb, latestProjectFacts, checkpoint.entity, [\n \"status\",\n \"owner\",\n \"next\",\n \"related_session\",\n \"title\",\n \"resume_at\",\n ]);\n const existingStatus = getLatestProjectValue(latestProjectFacts, checkpoint.entity, \"status\");\n const resolvedStatus = checkpoint.status ?? normalizeExistingStatus(existingStatus) ?? \"in_progress\";\n const resolvedOwner = checkpoint.owner ?? getLatestProjectValue(latestProjectFacts, checkpoint.entity, \"owner\") ?? \"\";\n const resolvedNext = checkpoint.next ?? getLatestProjectValue(latestProjectFacts, checkpoint.entity, \"next\") ?? \"\";\n const resolvedRelatedSession =\n checkpoint.relatedSession ?? getLatestProjectValue(latestProjectFacts, checkpoint.entity, \"related_session\") ?? \"\";\n const existingResumeAt = getLatestProjectValue(latestProjectFacts, checkpoint.entity, \"resume_at\");\n const terminalStatus = isTerminalCheckpointStatus(resolvedStatus);\n const taskUpdated = now.toISOString();\n const errors: ActiveTaskCheckpointError[] = [];\n const updatedKeys: string[] = [];\n const failedKeys: string[] = [];\n\n let titleSource: \"provided\" | \"existing\" | \"defaulted\" | undefined;\n let effectiveTitle = checkpoint.title;\n\n try {\n if (effectiveTitle) {\n titleSource = \"provided\";\n } else {\n const existingTitle = getLatestProjectValue(latestProjectFacts, checkpoint.entity, \"title\");\n if (existingTitle) {\n effectiveTitle = existingTitle;\n titleSource = \"existing\";\n } else {\n effectiveTitle = \"Project task\";\n titleSource = \"defaulted\";\n }\n }\n } catch (err) {\n deps.logger?.warn?.(`memory-hybrid: active-task checkpoint title lookup failed: ${String(err)}`);\n effectiveTitle = checkpoint.title ?? \"Project task\";\n titleSource = checkpoint.title ? \"provided\" : \"defaulted\";\n }\n\n const updates: Array<{ key: string; value: string }> = [\n { key: \"status\", value: resolvedStatus },\n { key: \"next\", value: resolvedNext },\n { key: \"owner\", value: resolvedOwner },\n { key: \"related_session\", value: resolvedRelatedSession },\n { key: \"task_updated\", value: taskUpdated },\n ];\n\n if (effectiveTitle) {\n updates.push({ key: \"title\", value: effectiveTitle });\n }\n\n if (checkpoint.state) {\n updates.push({ key: \"checkpoint_state\", value: safeJson(checkpoint.state) });\n }\n\n const shouldPersistResumeAt = !terminalStatus && !!checkpoint.resumeAtIso;\n const shouldClearResumeAt = !checkpoint.resumeAtIso || terminalStatus;\n if (shouldPersistResumeAt) {\n updates.push({ key: \"resume_at\", value: checkpoint.resumeAtIso as string });\n } else if (shouldClearResumeAt && existingResumeAt !== undefined) {\n updates.push({ key: \"resume_at\", value: \"\" });\n }\n\n primeLatestProjectFactCacheForEntityKeys(\n deps.factsDb,\n latestProjectFacts,\n checkpoint.entity,\n updates.map((u) => u.key),\n );\n\n for (const update of updates) {\n try {\n await upsertProjectTaskKey(\n deps.factsDb,\n deps.vectorDb,\n deps.embeddings,\n checkpoint.entity,\n update.key,\n update.value,\n deps.logger,\n { latestByEntityKey: latestProjectFacts },\n );\n updatedKeys.push(update.key);\n } catch (err) {\n failedKeys.push(update.key);\n errors.push(stepError(\"facts\", new Error(`${update.key}: ${String(err)}`)));\n }\n }\n\n let episodeId: string | undefined;\n let episodeAttempted = false;\n let episodeOk = false;\n let episodeSkippedReason: string | undefined;\n\n if (checkpoint.recordEpisode) {\n episodeAttempted = true;\n try {\n const scope = scopeFromFilter(deps.episodeScopeFilter);\n const contextLines: string[] = [\n `entity=${checkpoint.entity}`,\n `status=${resolvedStatus}`,\n `owner=${resolvedOwner || \"n/a\"}`,\n `next=${resolvedNext || \"n/a\"}`,\n `relatedSession=${resolvedRelatedSession || \"n/a\"}`,\n `taskUpdated=${taskUpdated}`,\n ];\n if (checkpoint.resumeAtIso) contextLines.push(`resumeAt=${checkpoint.resumeAtIso}`);\n if (checkpoint.state) contextLines.push(`state=${safeJson(checkpoint.state)}`);\n\n const ep = deps.factsDb.recordEpisode({\n event: `Active task checkpoint: ${checkpoint.entity}`,\n outcome: outcomeFromStatus(resolvedStatus),\n context: contextLines.join(\"\\n\"),\n importance: resolvedStatus === \"failed\" ? 0.8 : 0.6,\n tags: [\"active-task\", \"checkpoint\", slugify(checkpoint.entity)],\n scope: scope.scope,\n scopeTarget: scope.scopeTarget,\n agentId: scope.agentId,\n userId: scope.userId,\n sessionId: scope.sessionId,\n });\n episodeId = ep.id;\n episodeOk = true;\n } catch (err) {\n errors.push(stepError(\"episode\", err));\n }\n } else {\n episodeSkippedReason = \"record_episode_disabled\";\n }\n\n let wakeAttempted = false;\n let wakeScheduled = false;\n let wakeSkippedReason: string | undefined;\n let wakeResult: ActiveTaskWakeScheduleResult | undefined;\n let wakeJobsPath: string | undefined;\n let wakeDisabledPreviousJobs: number | undefined;\n\n if (failedKeys.length > 0) {\n wakeSkippedReason = \"facts_write_failed\";\n } else if (checkpoint.resumeAtIso && checkpoint.resumeAtDate && checkpoint.scheduleWake && !terminalStatus) {\n wakeAttempted = true;\n try {\n const scheduleWake = deps.scheduleWakeFn ?? scheduleActiveTaskWakeReminder;\n wakeResult = await scheduleWake({\n cfg: deps.cfg,\n entity: checkpoint.entity,\n status: resolvedStatus,\n owner: resolvedOwner || undefined,\n next: resolvedNext || undefined,\n relatedSession: resolvedRelatedSession || undefined,\n title: effectiveTitle,\n resumeAt: checkpoint.resumeAtDate,\n state: checkpoint.state,\n openclawDir: deps.openclawDir,\n });\n wakeScheduled = wakeResult.scheduled;\n wakeJobsPath = wakeResult.jobsPath;\n wakeDisabledPreviousJobs = wakeResult.disabledPreviousJobs;\n } catch (err) {\n errors.push(stepError(\"schedule\", err));\n }\n } else {\n wakeSkippedReason = terminalStatus\n ? \"terminal_status_no_wake\"\n : checkpoint.resumeAtIso\n ? \"schedule_wake_disabled\"\n : \"resumeAt_not_provided\";\n try {\n const cleanup = await disableActiveTaskWakeJobsForEntity(checkpoint.entity, deps.openclawDir);\n wakeJobsPath = cleanup.jobsPath;\n wakeDisabledPreviousJobs = cleanup.disabled;\n } catch (err) {\n errors.push(stepError(\"schedule\", err));\n }\n }\n\n let projection = {\n attempted: false,\n refreshed: false,\n reason: \"refresh_not_requested\",\n } as ActiveTaskProjectionRefreshResult;\n if (checkpoint.refreshProjection) {\n try {\n const refreshFn = deps.refreshProjectionFn ?? refreshActiveTaskProjectionFromFacts;\n projection = await refreshFn({\n cfg: deps.cfg,\n factsDb: deps.factsDb,\n workspaceRoot: deps.workspaceRoot,\n });\n } catch (err) {\n projection = { attempted: true, refreshed: false, reason: String(err) };\n errors.push(stepError(\"projection\", err));\n }\n }\n\n const ok = errors.length === 0;\n const partial = !ok && updatedKeys.length > 0;\n\n const summaryBits: string[] = [\n `entity=${checkpoint.entity}`,\n `status=${resolvedStatus}`,\n `facts=${updatedKeys.length}/${updates.length}`,\n checkpoint.recordEpisode ? `episode=${episodeOk ? \"recorded\" : \"failed\"}` : \"episode=skipped\",\n ];\n if (wakeAttempted) {\n summaryBits.push(`wake=${wakeScheduled ? \"scheduled\" : \"failed\"}`);\n } else if (wakeSkippedReason) {\n summaryBits.push(`wake=skipped(${wakeSkippedReason})`);\n }\n if (checkpoint.refreshProjection) {\n summaryBits.push(`projection=${projection.refreshed ? \"refreshed\" : \"not_refreshed\"}`);\n }\n\n const message = ok\n ? `active_task_checkpoint completed (${summaryBits.join(\", \")}).`\n : partial\n ? `active_task_checkpoint completed with partial failures (${summaryBits.join(\", \")}).`\n : `active_task_checkpoint failed (${summaryBits.join(\", \")}).`;\n\n return {\n ok,\n partial,\n message,\n checkpoint: {\n entity: checkpoint.entity,\n status: resolvedStatus,\n owner: resolvedOwner,\n next: resolvedNext,\n relatedSession: resolvedRelatedSession,\n title: effectiveTitle,\n resumeAt: checkpoint.resumeAtIso,\n taskUpdated,\n state: checkpoint.state,\n },\n steps: {\n facts: {\n ok: failedKeys.length === 0,\n updatedKeys,\n failedKeys,\n titleSource,\n },\n episode: {\n attempted: episodeAttempted,\n ok: episodeOk,\n episodeId,\n skippedReason: episodeSkippedReason,\n },\n schedule: {\n attempted: wakeAttempted,\n scheduled: wakeScheduled,\n jobId: wakeResult?.jobId,\n scheduleKind: wakeResult?.scheduleKind,\n scheduleAt: wakeResult?.scheduleAt,\n jobsPath: wakeJobsPath,\n disabledPreviousJobs: wakeDisabledPreviousJobs,\n skippedReason: wakeSkippedReason,\n },\n projection,\n },\n errors,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"active-task-injection.js","names":[],"sources":["../../services/active-task-injection.ts"],"sourcesContent":["/**\n * Active-task prompt injection: projection filters, relevance ordering, unified char budget.\n */\n\nimport type { ActiveTaskProjectionConfig } from \"../config.js\";\nimport { estimateTokens } from \"../utils/text.js\";\nimport type { ActiveTaskEntry, ActiveTaskStatus } from \"./active-task.js\";\nimport {\n type ActiveTaskInjectionBuildResult,\n buildActiveTaskInjection,\n buildStaleWarningInjection,\n} from \"./active-task.js\";\nimport { buildHeartbeatTaskHygieneBlock } from \"./task-hygiene.js\";\nimport { applyActiveTaskProjectionFilters } from \"./task-ledger-facts.js\";\n\nconst ACTIVE_STATUSES = new Set<ActiveTaskStatus>([\"In progress\", \"Waiting\", \"Stalled\", \"Failed\"]);\nconst LABEL_LIST_CAP = 15;\n\nfunction parseUpdatedMs(updated: string): number {\n if (!updated || updated === \"Unknown\") return 0;\n const ms = Date.parse(updated);\n return Number.isNaN(ms) ? 0 : ms;\n}\n\nfunction taskRelevanceScore(task: ActiveTaskEntry, userText?: string, sessionKey?: string): number {\n let score = 0;\n const sk = sessionKey?.trim();\n if (sk && task.subagent?.includes(sk)) score += 4;\n const ut = userText?.trim().toLowerCase();\n if (ut) {\n const label = task.label.trim().toLowerCase();\n const desc = task.description.trim().toLowerCase();\n if (label && ut.includes(label)) score += 3;\n if (desc.length >= 8 && ut.includes(desc.slice(0, Math.min(desc.length, 48)))) score += 2;\n for (const token of label.split(/[-_]+/)) {\n if (token.length >= 4 && ut.includes(token)) score += 1;\n }\n }\n return score;\n}\n\nfunction compareTasksForInjection(\n a: ActiveTaskEntry,\n b: ActiveTaskEntry,\n userText?: string,\n sessionKey?: string,\n): number {\n const rel = taskRelevanceScore(b, userText, sessionKey) - taskRelevanceScore(a, userText, sessionKey);\n if (rel !== 0) return rel;\n return parseUpdatedMs(b.updated) - parseUpdatedMs(a.updated);\n}\n\n/** Cap comma-separated task labels for heartbeat hygiene lines. */\nexport function formatCappedTaskLabelList(labels: string[], maxShown = LABEL_LIST_CAP): string {\n if (labels.length <= maxShown) {\n return labels.map((l) => `[${l}]`).join(\", \");\n }\n const shown = labels\n .slice(0, maxShown)\n .map((l) => `[${l}]`)\n .join(\", \");\n return `${shown}, …and ${labels.length - maxShown} more`;\n}\n\n/**\n * Filter, dedupe (projection), sort for injection, and apply optional row caps.\n */\nexport function prepareActiveTasksForInjection(\n ledgerTasks: ActiveTaskEntry[],\n opts: {\n projection: ActiveTaskProjectionConfig;\n injectionMaxTasks?: number;\n userText?: string;\n sessionKey?: string;\n },\n): { prepared: ActiveTaskEntry[]; ledgerActiveCount: number; filteredActiveCount: number } {\n const ledgerActiveCount = ledgerTasks.filter((t) => ACTIVE_STATUSES.has(t.status)).length;\n let prepared = ledgerTasks.filter((t) => ACTIVE_STATUSES.has(t.status) && !t.stale);\n prepared = applyActiveTaskProjectionFilters(prepared, opts.projection);\n prepared.sort((a, b) => compareTasksForInjection(a, b, opts.userText, opts.sessionKey));\n\n const filteredActiveCount = prepared.length;\n const rowCap = opts.injectionMaxTasks ?? opts.projection.maxRowsPerSection;\n if (typeof rowCap === \"number\" && rowCap > 0 && prepared.length > rowCap) {\n prepared = prepared.slice(0, rowCap);\n }\n\n return { prepared, ledgerActiveCount, filteredActiveCount };\n}\n\nexport type ActiveTaskContextBundleResult = {\n parts: string[];\n ledgerActiveCount: number;\n filteredActiveCount: number;\n injectedTaskCount: number;\n injectedTokens: number;\n activeTaskTokens: number;\n staleWarningTokens: number;\n heartbeatHygieneTokens: number;\n goalEscalationTokens: number;\n};\n\nexport type ActiveTaskContextBundleInput = {\n ledgerTasks: ActiveTaskEntry[];\n injectionBudgetTokens: number;\n staleMinutes: number;\n staleWarningEnabled: boolean;\n projection: ActiveTaskProjectionConfig;\n injectionMaxTasks?: number;\n userText?: string;\n sessionKey?: string;\n heartbeatHygiene?: { maxChars: number; suggestGoalAfterTaskAgeDays: number };\n goalEscalationBlock?: string;\n};\n\n/**\n * Build all budgeted active-task prepend blocks from one shared char pool (`injectionBudget * 4`).\n */\nexport function buildActiveTaskContextBundle(input: ActiveTaskContextBundleInput): ActiveTaskContextBundleResult {\n const { prepared, ledgerActiveCount, filteredActiveCount } = prepareActiveTasksForInjection(input.ledgerTasks, {\n projection: input.projection,\n injectionMaxTasks: input.injectionMaxTasks,\n userText: input.userText,\n sessionKey: input.sessionKey,\n });\n\n const parts: string[] = [];\n let injectedTaskCount = 0;\n let activeTaskTokens = 0;\n let staleWarningTokens = 0;\n let heartbeatHygieneTokens = 0;\n let goalEscalationTokens = 0;\n const totalChars = Math.max(0, input.injectionBudgetTokens * 4);\n const hygieneReserve =\n input.heartbeatHygiene != null\n ? Math.min(input.heartbeatHygiene.maxChars, Math.max(200, Math.floor(totalChars * 0.25)))\n : 0;\n let remainingChars = Math.max(0, totalChars - hygieneReserve);\n\n if (prepared.length > 0 && remainingChars > 80) {\n const main: ActiveTaskInjectionBuildResult = buildActiveTaskInjection(prepared, input.injectionBudgetTokens, {\n maxChars: remainingChars,\n });\n if (main.text) {\n parts.push(main.text);\n injectedTaskCount = main.injectedCount;\n activeTaskTokens = estimateTokens(main.text);\n remainingChars = Math.max(0, remainingChars - main.text.length - 2);\n }\n }\n\n if (input.staleWarningEnabled && remainingChars > 40) {\n const staleResult = buildStaleWarningInjection(input.ledgerTasks, input.staleMinutes, remainingChars);\n if (staleResult.text) {\n parts.push(staleResult.text);\n staleWarningTokens = estimateTokens(staleResult.text);\n remainingChars = Math.max(0, remainingChars - staleResult.text.length - 2);\n }\n }\n\n if (input.heartbeatHygiene) {\n const hygieneCap = Math.min(input.heartbeatHygiene.maxChars, hygieneReserve + remainingChars);\n if (hygieneCap > 60) {\n const hygiene = buildHeartbeatTaskHygieneBlock(input.ledgerTasks, {\n maxChars: hygieneCap,\n suggestGoalAfterTaskAgeDays: input.heartbeatHygiene.suggestGoalAfterTaskAgeDays,\n formatLabelList: formatCappedTaskLabelList,\n });\n if (hygiene) {\n parts.push(hygiene);\n heartbeatHygieneTokens = estimateTokens(hygiene);\n }\n }\n }\n\n const usedChars = parts.reduce((sum, p) => sum + p.length + 2, 0);\n const leftAfterBlocks = Math.max(0, totalChars - usedChars);\n if (input.goalEscalationBlock && leftAfterBlocks > 40) {\n const block =\n input.goalEscalationBlock.length <= leftAfterBlocks\n ? input.goalEscalationBlock\n : `${input.goalEscalationBlock.slice(0, Math.max(0, leftAfterBlocks - 24))}\\n…(truncated)\\n`;\n if (block.trim()) {\n parts.push(block);\n goalEscalationTokens = estimateTokens(block);\n }\n }\n\n const combined = parts.filter(Boolean).join(\"\\n\\n\");\n return {\n parts,\n ledgerActiveCount,\n filteredActiveCount,\n injectedTaskCount,\n injectedTokens: combined ? estimateTokens(combined) : 0,\n activeTaskTokens,\n staleWarningTokens,\n heartbeatHygieneTokens,\n goalEscalationTokens,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"active-task-injection.js","names":[],"sources":["../../services/active-task-injection.ts"],"sourcesContent":["/**\n * Active-task prompt injection: projection filters, relevance ordering, unified char budget.\n */\n\nimport type { ActiveTaskProjectionConfig } from \"../config.js\";\nimport { estimateTokens } from \"../utils/text.js\";\nimport type { ActiveTaskEntry, ActiveTaskStatus } from \"./active-task.js\";\nimport {\n type ActiveTaskInjectionBuildResult,\n buildActiveTaskInjection,\n buildStaleWarningInjection,\n} from \"./active-task.js\";\nimport { buildHeartbeatTaskHygieneBlock } from \"./task-hygiene.js\";\nimport { applyActiveTaskProjectionFilters } from \"./task-ledger-facts.js\";\n\nconst ACTIVE_STATUSES = new Set<ActiveTaskStatus>([\"In progress\", \"Waiting\", \"Stalled\", \"Failed\"]);\nconst LABEL_LIST_CAP = 15;\n\nfunction parseUpdatedMs(updated: string): number {\n if (!updated || updated === \"Unknown\") return 0;\n const ms = Date.parse(updated);\n return Number.isNaN(ms) ? 0 : ms;\n}\n\nfunction taskRelevanceScore(task: ActiveTaskEntry, userText?: string, sessionKey?: string): number {\n let score = 0;\n const sk = sessionKey?.trim();\n if (sk && task.subagent?.includes(sk)) score += 4;\n const ut = userText?.trim().toLowerCase();\n if (ut) {\n const label = task.label.trim().toLowerCase();\n const desc = task.description.trim().toLowerCase();\n if (label && ut.includes(label)) score += 3;\n if (desc.length >= 8 && ut.includes(desc.slice(0, Math.min(desc.length, 48)))) score += 2;\n for (const token of label.split(/[-_]+/)) {\n if (token.length >= 4 && ut.includes(token)) score += 1;\n }\n }\n return score;\n}\n\nfunction compareTasksForInjection(\n a: ActiveTaskEntry,\n b: ActiveTaskEntry,\n userText?: string,\n sessionKey?: string,\n): number {\n const rel = taskRelevanceScore(b, userText, sessionKey) - taskRelevanceScore(a, userText, sessionKey);\n if (rel !== 0) return rel;\n return parseUpdatedMs(b.updated) - parseUpdatedMs(a.updated);\n}\n\n/** Cap comma-separated task labels for heartbeat hygiene lines. */\nexport function formatCappedTaskLabelList(labels: string[], maxShown = LABEL_LIST_CAP): string {\n if (labels.length <= maxShown) {\n return labels.map((l) => `[${l}]`).join(\", \");\n }\n const shown = labels\n .slice(0, maxShown)\n .map((l) => `[${l}]`)\n .join(\", \");\n return `${shown}, …and ${labels.length - maxShown} more`;\n}\n\n/**\n * Filter, dedupe (projection), sort for injection, and apply optional row caps.\n */\nexport function prepareActiveTasksForInjection(\n ledgerTasks: ActiveTaskEntry[],\n opts: {\n projection: ActiveTaskProjectionConfig;\n injectionMaxTasks?: number;\n userText?: string;\n sessionKey?: string;\n },\n): { prepared: ActiveTaskEntry[]; ledgerActiveCount: number; filteredActiveCount: number } {\n const ledgerActiveCount = ledgerTasks.filter((t) => ACTIVE_STATUSES.has(t.status)).length;\n let prepared = ledgerTasks.filter((t) => ACTIVE_STATUSES.has(t.status) && !t.stale);\n prepared = applyActiveTaskProjectionFilters(prepared, opts.projection);\n prepared.sort((a, b) => compareTasksForInjection(a, b, opts.userText, opts.sessionKey));\n\n const filteredActiveCount = prepared.length;\n const rowCap = opts.injectionMaxTasks ?? opts.projection.maxRowsPerSection;\n if (typeof rowCap === \"number\" && rowCap > 0 && prepared.length > rowCap) {\n prepared = prepared.slice(0, rowCap);\n }\n\n return { prepared, ledgerActiveCount, filteredActiveCount };\n}\n\nexport type ActiveTaskContextBundleResult = {\n parts: string[];\n ledgerActiveCount: number;\n filteredActiveCount: number;\n injectedTaskCount: number;\n injectedTokens: number;\n activeTaskTokens: number;\n staleWarningTokens: number;\n heartbeatHygieneTokens: number;\n goalEscalationTokens: number;\n};\n\nexport type ActiveTaskContextBundleInput = {\n ledgerTasks: ActiveTaskEntry[];\n injectionBudgetTokens: number;\n staleMinutes: number;\n staleWarningEnabled: boolean;\n projection: ActiveTaskProjectionConfig;\n injectionMaxTasks?: number;\n userText?: string;\n sessionKey?: string;\n heartbeatHygiene?: { maxChars: number; suggestGoalAfterTaskAgeDays: number };\n goalEscalationBlock?: string;\n};\n\n/**\n * Build all budgeted active-task prepend blocks from one shared char pool (`injectionBudget * 4`).\n */\nexport function buildActiveTaskContextBundle(input: ActiveTaskContextBundleInput): ActiveTaskContextBundleResult {\n const { prepared, ledgerActiveCount, filteredActiveCount } = prepareActiveTasksForInjection(input.ledgerTasks, {\n projection: input.projection,\n injectionMaxTasks: input.injectionMaxTasks,\n userText: input.userText,\n sessionKey: input.sessionKey,\n });\n\n const parts: string[] = [];\n let injectedTaskCount = 0;\n let activeTaskTokens = 0;\n let staleWarningTokens = 0;\n let heartbeatHygieneTokens = 0;\n let goalEscalationTokens = 0;\n const totalChars = Math.max(0, input.injectionBudgetTokens * 4);\n const hygieneReserve =\n input.heartbeatHygiene != null\n ? Math.min(input.heartbeatHygiene.maxChars, Math.max(200, Math.floor(totalChars * 0.25)))\n : 0;\n let remainingChars = Math.max(0, totalChars - hygieneReserve);\n\n if (prepared.length > 0 && remainingChars > 80) {\n const main: ActiveTaskInjectionBuildResult = buildActiveTaskInjection(prepared, input.injectionBudgetTokens, {\n maxChars: remainingChars,\n });\n if (main.text) {\n parts.push(main.text);\n injectedTaskCount = main.injectedCount;\n activeTaskTokens = estimateTokens(main.text);\n remainingChars = Math.max(0, remainingChars - main.text.length - 2);\n }\n }\n\n if (input.staleWarningEnabled && remainingChars > 40) {\n const staleResult = buildStaleWarningInjection(input.ledgerTasks, input.staleMinutes, remainingChars);\n if (staleResult.text) {\n parts.push(staleResult.text);\n staleWarningTokens = estimateTokens(staleResult.text);\n remainingChars = Math.max(0, remainingChars - staleResult.text.length - 2);\n }\n }\n\n if (input.heartbeatHygiene) {\n const hygieneCap = Math.min(input.heartbeatHygiene.maxChars, hygieneReserve + remainingChars);\n if (hygieneCap > 60) {\n const hygiene = buildHeartbeatTaskHygieneBlock(input.ledgerTasks, {\n maxChars: hygieneCap,\n suggestGoalAfterTaskAgeDays: input.heartbeatHygiene.suggestGoalAfterTaskAgeDays,\n formatLabelList: formatCappedTaskLabelList,\n });\n if (hygiene) {\n parts.push(hygiene);\n heartbeatHygieneTokens = estimateTokens(hygiene);\n }\n }\n }\n\n const usedChars = parts.reduce((sum, p) => sum + p.length + 2, 0);\n const leftAfterBlocks = Math.max(0, totalChars - usedChars);\n if (input.goalEscalationBlock && leftAfterBlocks > 40) {\n const block =\n input.goalEscalationBlock.length <= leftAfterBlocks\n ? input.goalEscalationBlock\n : `${input.goalEscalationBlock.slice(0, Math.max(0, leftAfterBlocks - 24))}\\n…(truncated)\\n`;\n if (block.trim()) {\n parts.push(block);\n goalEscalationTokens = estimateTokens(block);\n }\n }\n\n const combined = parts.filter(Boolean).join(\"\\n\\n\");\n return {\n parts,\n ledgerActiveCount,\n filteredActiveCount,\n injectedTaskCount,\n injectedTokens: combined ? estimateTokens(combined) : 0,\n activeTaskTokens,\n staleWarningTokens,\n heartbeatHygieneTokens,\n goalEscalationTokens,\n };\n}\n"],"mappings":"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"}
|