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":"cmd-selfcorrection.js","names":[],"sources":["../../cli/cmd-selfcorrection.ts"],"sourcesContent":["import { getEnv } from \"../utils/env-manager.js\";\n/**\n * Self-Correction CLI Handlers\n *\n * Implements the self-correction commands:\n * - self-correction extract — scan recent sessions for correction incidents\n * - self-correction run — analyse incidents with LLM and apply remediations\n *\n * The two constants below are self-correction-specific and live here rather than\n * in the shared constants module because they are only consumed by these handlers.\n */\n\nimport { existsSync, lstatSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { getCronModelConfig, getDefaultCronModel, resolveReflectionModelAndFallbacks } from \"../config.js\";\nimport { chatCompleteWithAdaptiveMaintenanceRetry } from \"../services/adaptive-maintenance-llm.js\";\nimport { distillMaxOutputTokens } from \"../services/chat.js\";\nimport { CostFeature } from \"../services/cost-feature-labels.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { type CorrectionIncident, runSelfCorrectionExtract } from \"../services/self-correction-extract.js\";\nimport { preFilterSessions } from \"../services/session-pre-filter.js\";\nimport { insertRulesUnderSection } from \"../services/tools-md-section.js\";\nimport { cleanupEvictedVector } from \"../services/vector-maintenance.js\";\nimport { atomicWriteFile } from \"../utils/atomic-write.js\";\nimport { CLI_STORE_IMPORTANCE } from \"../utils/constants.js\";\nimport { getCorrectionSignalRegex } from \"../utils/language-keywords.js\";\nimport { stripThinkingWrapperBlocks, tryParseFirstJsonArray } from \"../utils/llm-json-array.js\";\nimport { resolveTierPreferenceWithSources } from \"../utils/llm-selection.js\";\nimport { fillPrompt, loadPrompt } from \"../utils/prompt-loader.js\";\nimport { gatherSessionFiles } from \"./cmd-distill.js\";\nimport { buildPreFilterConfig } from \"./cmd-install.js\";\nimport { inferTargetFile } from \"./cmd-store.js\";\nimport type { HandlerContext } from \"./handlers.js\";\nimport { acquireScanSlot, clearScanLock } from \"./shared.js\";\nimport type { SelfCorrectionExtractResult, SelfCorrectionRunResult } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Module-level constants (self-correction-specific)\n// ---------------------------------------------------------------------------\n\n/** Maximum number of remediation items to auto-apply per run. */\nconst SELF_CORRECTION_CAP = 5;\n\n/** Default self-correction configuration values. */\nconst DEFAULT_SELF_CORRECTION = {\n semanticDedup: true,\n semanticDedupThreshold: 0.92,\n toolsSection: \"Self-correction rules\",\n applyToolsByDefault: true,\n autoRewriteTools: false,\n analyzeViaSpawn: false,\n spawnThreshold: 15,\n spawnModel: \"\",\n} as const;\n\nfunction sanitizeLlmResponseExcerpt(content: string): string {\n return content\n .trim()\n .slice(0, 200)\n .replace(/\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}\\b/gi, \"[redacted-email]\")\n .replace(/\\b(?:sk|gh[pousr]|xox[baprs])-[A-Za-z0-9_=-]{8,}\\b/g, \"[redacted-token]\")\n .replace(/\\b(api[_-]?key|password|secret|token)\\s*[:=]\\s*\\S+/gi, \"$1=[redacted]\")\n .replace(/\\s+/g, \" \");\n}\n\n// ---------------------------------------------------------------------------\n// Self-correction LLM response parser\n// ---------------------------------------------------------------------------\n\n/**\n * Parse the JSON array of remediation items from a self-correction LLM response.\n *\n * The model is instructed to return a bare JSON array, but in practice it may:\n * - wrap the array in a markdown code fence (```json ... ```)\n * - add prose before or after the array\n * - emit thinking/reasoning tokens before the JSON (e.g. MiniMax M2.7-highspeed, #1718)\n * - emit placeholder tokens instead of JSON\n * - return invalid/truncated JSON\n *\n * This function handles all of those cases robustly by first stripping thinking\n * wrapper blocks, then scanning balanced `[...]` spans and only accepting arrays\n * that match expected remediation object shape.\n * Returns `null` when no valid array can be extracted (callers treat this as\n * `failed_parse` — no remediations are applied and the error is reported).\n *\n * Scenarios and expected behaviour:\n * - **strict JSON**: `[{\"remediationType\":\"MEMORY_STORE\",...}]` → parsed directly\n * - **fenced JSON**: `` ```json\\n[...]\\n``` `` → fence stripped, array parsed\n * - **trailing text**: `[...]\\n\\nHere is my explanation` → array extracted, text ignored\n * - **thinking prefix**: `<thinking>...</thinking>\\n[...]` → thinking stripped, array parsed\n * - **invalid JSON**: `[not valid]` / truncated → null returned, caller handles error\n */\nexport function parseSelfCorrectionLLMResponse(content: string): unknown[] | null {\n let emptyArrayCandidate: unknown[] | null = null;\n const normalized = stripThinkingWrapperBlocks(content);\n\n const result = tryParseFirstJsonArray(normalized, (parsed) => {\n if (parsed.length === 0) {\n emptyArrayCandidate = parsed;\n return null;\n }\n return isSelfCorrectionRemediationArray(parsed) ? parsed : null;\n });\n\n return result ?? emptyArrayCandidate;\n}\n\nfunction isSelfCorrectionRemediationArray(items: unknown[]): boolean {\n return items.every((item) => isSelfCorrectionRemediationItem(item));\n}\n\nfunction isSelfCorrectionRemediationItem(item: unknown): boolean {\n if (typeof item !== \"object\" || item === null) return false;\n const candidate = item as Record<string, unknown>;\n const remediationType = candidate.remediationType;\n if (typeof remediationType !== \"string\" || remediationType.trim().length === 0) return false;\n\n const isNoAction = remediationType.trim().toUpperCase() === \"NO_ACTION\";\n if (\"remediationContent\" in candidate) {\n const remediationContent = candidate.remediationContent;\n if (\n !(\n typeof remediationContent === \"string\" ||\n (typeof remediationContent === \"object\" && remediationContent !== null)\n )\n ) {\n return false;\n }\n } else if (!isNoAction) {\n return false;\n }\n\n if (\"category\" in candidate && typeof candidate.category !== \"string\") return false;\n if (\"severity\" in candidate && typeof candidate.severity !== \"string\") return false;\n if (\"repeated\" in candidate && typeof candidate.repeated !== \"boolean\") return false;\n\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// self-correction extract\n// ---------------------------------------------------------------------------\n\n/**\n * Extract self-correction incidents from sessions.\n */\nexport function runSelfCorrectionExtractForCli(\n ctx: HandlerContext,\n opts: {\n days?: number;\n outputPath?: string;\n verbose?: boolean;\n /** Pre-filtered session file paths. When provided, skips gatherSessionFiles(). */\n filePaths?: string[];\n },\n): SelfCorrectionExtractResult {\n const filePaths =\n opts.filePaths ?? gatherSessionFiles({ days: opts.days ?? 3 }).map((f: { path: string; mtime: number }) => f.path);\n if (filePaths.length === 0) {\n return { incidents: [], sessionsScanned: 0 };\n }\n if (opts.verbose) {\n ctx.logger.info?.(`memory-hybrid: self-correction-extract — scanning ${filePaths.length} session file(s)`);\n const cap = 40;\n for (let i = 0; i < Math.min(filePaths.length, cap); i++) {\n ctx.logger.info?.(` ${filePaths[i]}`);\n }\n if (filePaths.length > cap) {\n ctx.logger.info?.(` ... and ${filePaths.length - cap} more`);\n }\n }\n try {\n const result = runSelfCorrectionExtract({\n filePaths,\n correctionRegex: getCorrectionSignalRegex(),\n });\n if (opts.outputPath && result.incidents.length > 0) {\n try {\n const outputJson = JSON.stringify(result.incidents, null, 2);\n // Follow symlinks so shared extract targets are updated, not replaced.\n if (existsSync(opts.outputPath) && lstatSync(opts.outputPath).isSymbolicLink()) {\n writeFileSync(opts.outputPath, outputJson, \"utf-8\");\n } else {\n atomicWriteFile(opts.outputPath, outputJson);\n }\n } catch (e) {\n capturePluginError(e as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionExtractForCli:write-output\" });\n }\n }\n return result;\n } catch (err) {\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionExtractForCli\" });\n throw err;\n }\n}\n\n// ---------------------------------------------------------------------------\n// self-correction run\n// ---------------------------------------------------------------------------\n\n/**\n * Run self-correction analysis and remediation.\n */\nexport async function runSelfCorrectionRunForCli(\n ctx: HandlerContext,\n opts: {\n extractPath?: string;\n incidents?: CorrectionIncident[];\n workspace?: string;\n dryRun?: boolean;\n model?: string;\n approve?: boolean;\n applyTools?: boolean;\n full?: boolean;\n verbose?: boolean;\n },\n): Promise<SelfCorrectionRunResult> {\n const { factsDb, vectorDb, embeddings, openai, cfg, logger, proposalsDb } = ctx;\n const SCAN_TYPE = \"self-correction-run\";\n\n // Startup guard + concurrency lock (skip if already ran within 23h and not forced)\n // Only apply when no explicit incidents/extractPath provided (i.e. fresh scan)\n if (!opts.full && !opts.dryRun && !opts.incidents && !opts.extractPath) {\n const cursor = factsDb.getScanCursor(SCAN_TYPE);\n const skip = acquireScanSlot(SCAN_TYPE, cursor?.lastRunAt, logger);\n if (skip) {\n const isConcurrency = skip.includes(\"already running\");\n return {\n incidentsFound: 0,\n analysed: 0,\n autoFixed: 0,\n proposals: [],\n reportPath: null,\n skipped: true,\n status: isConcurrency ? \"skipped_concurrency\" : \"skipped_cooldown\",\n };\n }\n }\n\n try {\n const workspaceRoot = opts.workspace ?? getEnv(\"OPENCLAW_WORKSPACE\") ?? join(homedir(), \".openclaw\", \"workspace\");\n const scCfg = cfg.selfCorrection ?? DEFAULT_SELF_CORRECTION;\n const reportDir = join(workspaceRoot, \"memory\", \"reports\");\n const today = new Date().toISOString().slice(0, 10);\n const reportPath = join(reportDir, `self-correction-${today}.md`);\n let incidents: CorrectionIncident[];\n if (opts.incidents !== undefined) {\n incidents = opts.incidents;\n } else if (opts.extractPath) {\n try {\n const raw = readFileSync(opts.extractPath, \"utf-8\");\n incidents = JSON.parse(raw) as CorrectionIncident[];\n } catch (e) {\n capturePluginError(e as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:read-extract\" });\n return { incidentsFound: 0, analysed: 0, autoFixed: 0, proposals: [], reportPath: null, error: String(e) };\n }\n } else {\n // Two-tier pre-filter: use local Ollama to triage sessions before extraction (Issue #290).\n let scFilePaths: string[] | undefined;\n const pfCfgSC = buildPreFilterConfig(cfg);\n if (pfCfgSC.enabled) {\n const sessionFiles = gatherSessionFiles({ days: 3 });\n const allPaths = sessionFiles.map((f: { path: string; mtime: number }) => f.path);\n if (allPaths.length > 0) {\n const pfResult = await preFilterSessions(allPaths, pfCfgSC);\n if (!pfResult.ollamaUnavailable) {\n logger.info?.(\n `memory-hybrid: ${SCAN_TYPE} pre-filter: ${pfResult.kept.length}/${allPaths.length} sessions flagged as interesting`,\n );\n scFilePaths = pfResult.kept;\n } else {\n logger.info?.(`memory-hybrid: ${SCAN_TYPE} pre-filter: Ollama unavailable — scanning all sessions`);\n scFilePaths = allPaths; // avoid redundant gatherSessionFiles inside runSelfCorrectionExtractForCli\n }\n }\n }\n const extractResult = runSelfCorrectionExtractForCli(ctx, {\n days: 3,\n filePaths: scFilePaths,\n verbose: opts.verbose,\n });\n incidents = extractResult.incidents;\n }\n if (incidents.length === 0) {\n const emptyReport = `# Self-Correction Analysis (${today})\\n\\nScanned sessions: 3 days.\\nIncidents found: 0.\\n`;\n try {\n atomicWriteFile(reportPath, emptyReport);\n } catch (err) {\n capturePluginError(err as Error, {\n subsystem: \"cli\",\n operation: \"runSelfCorrectionRunForCli:write-empty-report\",\n });\n }\n if (!opts.dryRun && !opts.incidents && !opts.extractPath) {\n factsDb.updateScanCursor(SCAN_TYPE, 0, 0);\n clearScanLock(SCAN_TYPE);\n }\n return {\n incidentsFound: 0,\n analysed: 0,\n autoFixed: 0,\n proposals: [],\n reportPath,\n status: \"success_no_incidents\",\n };\n }\n if (opts.verbose) {\n logger.info?.(`memory-hybrid: ${SCAN_TYPE} — ${incidents.length} incident(s); building LLM prompt…`);\n }\n const prompt = fillPrompt(loadPrompt(\"self-correction-analyze\"), {\n incidents_json: JSON.stringify(incidents),\n });\n const heavyResolved = resolveReflectionModelAndFallbacks(cfg, \"heavy\");\n const heavyPrefWithSources = resolveTierPreferenceWithSources(cfg, \"heavy\");\n const model = opts.model ?? heavyResolved.defaultModel ?? getDefaultCronModel(getCronModelConfig(cfg), \"heavy\");\n const modelSource = opts.model\n ? \"--model\"\n : heavyPrefWithSources.models[0] === model\n ? (heavyPrefWithSources.sources[0] ?? \"built-in\")\n : \"built-in\";\n const scFallbackCandidates = opts.model\n ? [heavyResolved.defaultModel, ...(heavyResolved.fallbackModels ?? [])]\n : (heavyResolved.fallbackModels ?? []);\n const scFallbackModels = [...new Set(scFallbackCandidates.filter((m) => m !== model))];\n let analysed: Array<{\n category: string;\n severity: string;\n remediationType: string;\n remediationContent: string | { text?: string; entity?: string; key?: string; tags?: string[] };\n repeated?: boolean;\n }> = [];\n const useSpawn = scCfg.analyzeViaSpawn && incidents.length > scCfg.spawnThreshold;\n try {\n const attemptAnalysisJsonRepair = async (rawContent: string): Promise<typeof analysed | null> => {\n const repairPrompt = [\n \"Convert the following model output into a valid JSON array.\",\n \"Return ONLY JSON (no markdown, no prose).\",\n \"If no valid remediation items can be recovered, return [].\",\n \"\",\n \"MODEL_OUTPUT_START\",\n rawContent,\n \"MODEL_OUTPUT_END\",\n ].join(\"\\n\");\n const adaptiveEnabled = (getEnv(\"OPENCLAW_HYBRID_MEM_ADAPTIVE_DISTILL\") ?? \"\").trim() !== \"0\";\n const detail = await chatCompleteWithAdaptiveMaintenanceRetry({\n model,\n modelSource,\n content: repairPrompt,\n temperature: 0,\n maxTokens: distillMaxOutputTokens(model),\n openai,\n fallbackModels: scFallbackModels,\n label: \"memory-hybrid: self-correction analyze-repair\",\n feature: CostFeature.selfCorrectionAnalyze,\n logger,\n adaptiveStatePath:\n ctx.resolvedSqlitePath && ctx.resolvedSqlitePath.length > 0\n ? join(dirname(ctx.resolvedSqlitePath), \".adaptive-llm-limits.json\")\n : undefined,\n enabled: adaptiveEnabled,\n });\n const repaired = parseSelfCorrectionLLMResponse(detail.content);\n return repaired === null ? null : (repaired as typeof analysed);\n };\n\n let content: string;\n if (useSpawn) {\n const { spawnSync } = await import(\"node:child_process\");\n const { tmpdir: osTmp } = await import(\"node:os\");\n const promptPath = join(osTmp(), `self-correction-prompt-${Date.now()}.txt`);\n writeFileSync(promptPath, prompt, \"utf-8\");\n const spawnModel = scCfg.spawnModel?.trim() || getDefaultCronModel(getCronModelConfig(cfg), \"default\");\n const r = spawnSync(\n \"openclaw\",\n [\n \"sessions\",\n \"spawn\",\n \"--model\",\n spawnModel,\n \"--message\",\n \"Analyze the attached incidents and output ONLY a JSON array (no markdown, no code fences). Use the instructions in the attached file.\",\n \"--attach\",\n promptPath,\n ],\n { encoding: \"utf-8\", maxBuffer: 2 * 1024 * 1024 },\n );\n try {\n if (existsSync(promptPath)) rmSync(promptPath, { force: true });\n } catch (err) {\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:cleanup-tmp\" });\n }\n content = (r.stdout ?? \"\") + (r.stderr ?? \"\");\n if (r.status !== 0) throw new Error(`sessions spawn exited ${r.status}: ${content.slice(0, 500)}`);\n } else {\n logger.info?.(\"memory-hybrid: self-correction-run model tier = heavy\");\n logger.info?.(`memory-hybrid: self-correction-run starting with model ${model} (source=${modelSource})`);\n logger.info?.(\n `memory-hybrid: self-correction-run fallback chain = [${scFallbackModels.length > 0 ? scFallbackModels.join(\", \") : \"\"}]`,\n );\n const adaptiveEnabled = (getEnv(\"OPENCLAW_HYBRID_MEM_ADAPTIVE_DISTILL\") ?? \"\").trim() !== \"0\";\n const detail = await chatCompleteWithAdaptiveMaintenanceRetry({\n model,\n modelSource,\n content: prompt,\n temperature: 0.2,\n maxTokens: distillMaxOutputTokens(model),\n openai,\n fallbackModels: scFallbackModels,\n label: \"memory-hybrid: self-correction analyze\",\n feature: CostFeature.selfCorrectionAnalyze,\n logger,\n adaptiveStatePath:\n ctx.resolvedSqlitePath && ctx.resolvedSqlitePath.length > 0\n ? join(dirname(ctx.resolvedSqlitePath), \".adaptive-llm-limits.json\")\n : undefined,\n enabled: adaptiveEnabled,\n });\n if (detail.modelUsed !== model) {\n logger.info?.(`memory-hybrid: self-correction-run analysis used fallback model ${detail.modelUsed}`);\n }\n content = detail.content;\n }\n const parsedRemediations = parseSelfCorrectionLLMResponse(content);\n if (parsedRemediations !== null) {\n analysed = parsedRemediations as typeof analysed;\n } else if (content.trim().length > 0) {\n // Log a sanitized excerpt (no private session data) so operators can diagnose.\n const excerpt = sanitizeLlmResponseExcerpt(content);\n logger.warn?.(\n `memory-hybrid: self-correction-run — initial JSON parse failed; attempting repair pass. excerpt: \"${excerpt}\"`,\n );\n let repaired: typeof analysed | null = null;\n try {\n repaired = await attemptAnalysisJsonRepair(content);\n } catch (repairErr) {\n capturePluginError(repairErr as Error, {\n subsystem: \"cli\",\n operation: \"runSelfCorrectionRunForCli:llm-analysis-repair\",\n });\n }\n if (repaired !== null) {\n analysed = repaired;\n logger.info?.(`memory-hybrid: self-correction-run — repair pass recovered ${analysed.length} item(s)`);\n } else {\n const parseError = new Error(\n `Self-correction analysis: LLM response could not be parsed as a JSON array (repair failed). excerpt=\"${excerpt}\"`,\n );\n (parseError as any).isParseFailure = true;\n throw parseError;\n }\n } else {\n analysed = [];\n }\n if (opts.verbose && analysed.length > 0) {\n logger.info?.(\n `memory-hybrid: ${SCAN_TYPE} — LLM returned ${analysed.length} remediation item(s) (before cap/filter)`,\n );\n }\n } catch (e) {\n capturePluginError(e as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:llm-analysis\" });\n const isParseFailure = (e as any).isParseFailure === true;\n return {\n incidentsFound: incidents.length,\n analysed: 0,\n autoFixed: 0,\n proposals: [],\n reportPath: null,\n error: String(e),\n status: isParseFailure ? \"failed_parse\" : undefined,\n };\n }\n const proposals: string[] = [];\n const toolsSuggestions: string[] = [];\n let autoFixed = 0;\n let toolsApplied = 0;\n const toApply = analysed\n .filter((a) => a.remediationType !== \"NO_ACTION\" && !a.repeated)\n .slice(0, SELF_CORRECTION_CAP);\n const toolsPath = join(workspaceRoot, \"TOOLS.md\");\n const toolsSection = scCfg.toolsSection;\n const semanticThreshold = scCfg.semanticDedupThreshold ?? 0.92;\n\n for (const a of toApply) {\n if (a.remediationType === \"MEMORY_STORE\") {\n const c = a.remediationContent;\n const obj =\n typeof c === \"object\" && c && \"text\" in c ? c : { text: String(c), entity: \"Fact\", tags: [] as string[] };\n const text = (obj.text ?? \"\").trim();\n if (!text || factsDb.hasDuplicate(text, \"self-correction\")) continue;\n let vector: number[] | null = null;\n if (scCfg.semanticDedup || !opts.dryRun) {\n try {\n vector = await embeddings.embed(text);\n if (scCfg.semanticDedup && (await vectorDb.hasDuplicate(vector, semanticThreshold))) continue;\n } catch (err) {\n logger.warn?.(`memory-hybrid: self-correction embed/semantic dedup failed: ${err}`);\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:embed-dedup\" });\n continue;\n }\n }\n if (opts.dryRun) continue;\n try {\n const storeResult = factsDb.storeWithResult({\n text,\n category: \"technical\",\n importance: CLI_STORE_IMPORTANCE,\n entity: obj.entity ?? null,\n key: typeof obj.key === \"string\" ? obj.key : null,\n value: text.slice(0, 200),\n source: \"self-correction\",\n tags: Array.isArray(obj.tags) ? obj.tags : [],\n });\n if (storeResult.skipped) {\n continue;\n }\n const entry = storeResult.entry;\n // CRITICAL FIX (#2): Delete vector for evicted fact to prevent orphaned vectors\n await cleanupEvictedVector({\n vectorDb: vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: logger,\n context: \"self-correction\",\n });\n if (vector) {\n await vectorDb.store({\n text,\n vector,\n importance: CLI_STORE_IMPORTANCE,\n category: \"technical\",\n id: entry.id,\n });\n factsDb.setEmbeddingModel(entry.id, embeddings.modelName);\n }\n autoFixed++;\n } catch (err) {\n logger.warn?.(`memory-hybrid: self-correction MEMORY_STORE failed: ${err}`);\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:memory-store\" });\n }\n } else if (a.remediationType === \"TOOLS_RULE\") {\n const line =\n typeof a.remediationContent === \"string\"\n ? a.remediationContent\n : ((a.remediationContent as { text?: string })?.text ?? \"\");\n if (line.trim()) toolsSuggestions.push(line.trim());\n } else if (a.remediationType === \"AGENTS_RULE\" || a.remediationType === \"SKILL_UPDATE\") {\n const line =\n typeof a.remediationContent === \"string\"\n ? a.remediationContent\n : ((a.remediationContent as { text?: string })?.text ?? \"\");\n if (line.trim()) {\n proposals.push(`[${a.remediationType}] ${line.trim()}`);\n // Wire AGENTS_RULE into proposals DB (#260) — closes the dead end\n if (\n a.remediationType === \"AGENTS_RULE\" &&\n proposalsDb &&\n (scCfg as { agentsRuleToProposals?: boolean }).agentsRuleToProposals !== false &&\n !opts.dryRun\n ) {\n try {\n const targetFile = inferTargetFile(line);\n const incidentContext =\n incidents.length > 0\n ? `Correction incident: \"${incidents[0].userMessage.slice(0, 200)}\"`\n : \"Self-correction analysis\";\n proposalsDb.create({\n targetFile,\n title: `Self-correction: ${a.category ?? \"behavior\"}`,\n observation: incidentContext,\n suggestedChange: line.trim(),\n confidence: 0.7,\n evidenceSessions: incidents\n .map((inc) => inc.sessionFile)\n .filter((v, idx, arr) => arr.indexOf(v) === idx),\n });\n } catch (err) {\n capturePluginError(err as Error, {\n subsystem: \"cli\",\n operation: \"runSelfCorrectionRunForCli:agents-rule-proposal\",\n });\n }\n }\n }\n }\n }\n\n const noApplyTools = opts.applyTools === false;\n const shouldApplyTools = !opts.dryRun && (scCfg.applyToolsByDefault !== false || opts.approve) && !noApplyTools;\n if (toolsSuggestions.length > 0 && !opts.dryRun) {\n if (scCfg.autoRewriteTools && shouldApplyTools && existsSync(toolsPath)) {\n try {\n const currentTools = readFileSync(toolsPath, \"utf-8\");\n const rewritePrompt = fillPrompt(loadPrompt(\"self-correction-rewrite-tools\"), {\n current_tools: currentTools,\n new_rules: toolsSuggestions.join(\"\\n\"),\n });\n logger.info?.(\n `memory-hybrid: self-correction-run rewrite-tools starting with model ${model} (source=${modelSource})`,\n );\n const adaptiveEnabled = (getEnv(\"OPENCLAW_HYBRID_MEM_ADAPTIVE_DISTILL\") ?? \"\").trim() !== \"0\";\n const detail = await chatCompleteWithAdaptiveMaintenanceRetry({\n model,\n modelSource,\n content: rewritePrompt,\n temperature: 0.2,\n maxTokens: 16000,\n openai,\n fallbackModels: scFallbackModels,\n label: \"memory-hybrid: self-correction rewrite-tools\",\n feature: CostFeature.selfCorrectionRewriteTools,\n logger,\n adaptiveStatePath:\n ctx.resolvedSqlitePath && ctx.resolvedSqlitePath.length > 0\n ? join(dirname(ctx.resolvedSqlitePath), \".adaptive-llm-limits.json\")\n : undefined,\n enabled: adaptiveEnabled,\n });\n if (detail.modelUsed !== model) {\n logger.info?.(`memory-hybrid: self-correction-run rewrite-tools used fallback model ${detail.modelUsed}`);\n }\n const cleaned = detail.content\n .trim()\n .replace(/^```\\w*\\n?|```\\s*$/g, \"\")\n .trim();\n if (cleaned.length > 50) {\n // Follow symlinks so shared TOOLS.md targets are updated, not replaced.\n if (existsSync(toolsPath) && lstatSync(toolsPath).isSymbolicLink()) {\n writeFileSync(toolsPath, cleaned, \"utf-8\");\n } else {\n atomicWriteFile(toolsPath, cleaned);\n }\n toolsApplied = toolsSuggestions.length;\n autoFixed += toolsApplied;\n }\n } catch (err) {\n logger.warn?.(`memory-hybrid: self-correction TOOLS rewrite failed: ${err}`);\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:tools-rewrite\" });\n }\n } else if (shouldApplyTools && existsSync(toolsPath)) {\n try {\n const { inserted } = insertRulesUnderSection(toolsPath, toolsSection, toolsSuggestions);\n toolsApplied = inserted;\n autoFixed += inserted;\n } catch (err) {\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:insert-tools\" });\n }\n }\n }\n\n const reportLines = [\n `# Self-Correction Analysis (${today})`,\n \"\",\n `Scanned: last 3 days. Incidents found: ${incidents.length}.`,\n `Analysed: ${analysed.length}. Auto-fixed: ${autoFixed}. Needs review: ${proposals.length}.`,\n \"\",\n ...(autoFixed > 0 ? [\"## Auto-applied\", \"\", `- ${autoFixed} memory store(s) and/or TOOLS.md rule(s).`, \"\"] : []),\n ...(toolsSuggestions.length > 0 && toolsApplied === 0 && !scCfg.autoRewriteTools\n ? [\n \"## Suggested TOOLS.md rules (not applied this run). To apply: config applyToolsByDefault is true by default, or use --approve. To skip applying: --no-apply-tools.\",\n \"\",\n ...toolsSuggestions.map((s) => `- ${s}`),\n \"\",\n ]\n : []),\n ...(toolsApplied > 0\n ? [\"## TOOLS.md updated\", \"\", `- ${toolsApplied} rule(s) inserted under section \"${toolsSection}\".`, \"\"]\n : []),\n ...(proposals.length > 0\n ? [\"## Proposed (review before applying)\", \"\", ...proposals.map((p) => `- ${p}`), \"\"]\n : []),\n ];\n try {\n atomicWriteFile(reportPath, reportLines.join(\"\\n\"));\n } catch (e) {\n logger.warn?.(`memory-hybrid: could not write report: ${e}`);\n capturePluginError(e as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:write-report\" });\n }\n // Record savings: each auto-fixed incident avoided ~2 manual LLM round-trips\n if (autoFixed > 0 && ctx.costTracker && !opts?.dryRun) {\n ctx.costTracker.recordSavings({\n feature: \"self-correction\",\n action: \"auto-fixed incident\",\n countAvoided: autoFixed,\n estimatedSavingUsd: autoFixed * 0.002,\n note: `${autoFixed} incident(s) auto-remediated`,\n });\n }\n\n if (!opts.dryRun && !opts.incidents && !opts.extractPath) {\n factsDb.updateScanCursor(SCAN_TYPE, Date.now(), incidents.length);\n }\n\n return {\n incidentsFound: incidents.length,\n analysed: analysed.length,\n autoFixed,\n proposals,\n reportPath,\n toolsSuggestions: toolsSuggestions.length > 0 ? toolsSuggestions : undefined,\n toolsApplied: toolsApplied > 0 ? toolsApplied : undefined,\n status: \"success_analyzed\",\n };\n } finally {\n if (!opts.full && !opts.dryRun && !opts.incidents && !opts.extractPath) clearScanLock(SCAN_TYPE);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cmd-selfcorrection.js","names":[],"sources":["../../cli/cmd-selfcorrection.ts"],"sourcesContent":["import { getEnv } from \"../utils/env-manager.js\";\n/**\n * Self-Correction CLI Handlers\n *\n * Implements the self-correction commands:\n * - self-correction extract — scan recent sessions for correction incidents\n * - self-correction run — analyse incidents with LLM and apply remediations\n *\n * The two constants below are self-correction-specific and live here rather than\n * in the shared constants module because they are only consumed by these handlers.\n */\n\nimport { existsSync, lstatSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { getCronModelConfig, getDefaultCronModel, resolveReflectionModelAndFallbacks } from \"../config.js\";\nimport { chatCompleteWithAdaptiveMaintenanceRetry } from \"../services/adaptive-maintenance-llm.js\";\nimport { distillMaxOutputTokens } from \"../services/chat.js\";\nimport { CostFeature } from \"../services/cost-feature-labels.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { type CorrectionIncident, runSelfCorrectionExtract } from \"../services/self-correction-extract.js\";\nimport { preFilterSessions } from \"../services/session-pre-filter.js\";\nimport { insertRulesUnderSection } from \"../services/tools-md-section.js\";\nimport { cleanupEvictedVector } from \"../services/vector-maintenance.js\";\nimport { atomicWriteFile } from \"../utils/atomic-write.js\";\nimport { CLI_STORE_IMPORTANCE } from \"../utils/constants.js\";\nimport { getCorrectionSignalRegex } from \"../utils/language-keywords.js\";\nimport { stripThinkingWrapperBlocks, tryParseFirstJsonArray } from \"../utils/llm-json-array.js\";\nimport { resolveTierPreferenceWithSources } from \"../utils/llm-selection.js\";\nimport { fillPrompt, loadPrompt } from \"../utils/prompt-loader.js\";\nimport { gatherSessionFiles } from \"./cmd-distill.js\";\nimport { buildPreFilterConfig } from \"./cmd-install.js\";\nimport { inferTargetFile } from \"./cmd-store.js\";\nimport type { HandlerContext } from \"./handlers.js\";\nimport { acquireScanSlot, clearScanLock } from \"./shared.js\";\nimport type { SelfCorrectionExtractResult, SelfCorrectionRunResult } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Module-level constants (self-correction-specific)\n// ---------------------------------------------------------------------------\n\n/** Maximum number of remediation items to auto-apply per run. */\nconst SELF_CORRECTION_CAP = 5;\n\n/** Default self-correction configuration values. */\nconst DEFAULT_SELF_CORRECTION = {\n semanticDedup: true,\n semanticDedupThreshold: 0.92,\n toolsSection: \"Self-correction rules\",\n applyToolsByDefault: true,\n autoRewriteTools: false,\n analyzeViaSpawn: false,\n spawnThreshold: 15,\n spawnModel: \"\",\n} as const;\n\nfunction sanitizeLlmResponseExcerpt(content: string): string {\n return content\n .trim()\n .slice(0, 200)\n .replace(/\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}\\b/gi, \"[redacted-email]\")\n .replace(/\\b(?:sk|gh[pousr]|xox[baprs])-[A-Za-z0-9_=-]{8,}\\b/g, \"[redacted-token]\")\n .replace(/\\b(api[_-]?key|password|secret|token)\\s*[:=]\\s*\\S+/gi, \"$1=[redacted]\")\n .replace(/\\s+/g, \" \");\n}\n\n// ---------------------------------------------------------------------------\n// Self-correction LLM response parser\n// ---------------------------------------------------------------------------\n\n/**\n * Parse the JSON array of remediation items from a self-correction LLM response.\n *\n * The model is instructed to return a bare JSON array, but in practice it may:\n * - wrap the array in a markdown code fence (```json ... ```)\n * - add prose before or after the array\n * - emit thinking/reasoning tokens before the JSON (e.g. MiniMax M2.7-highspeed, #1718)\n * - emit placeholder tokens instead of JSON\n * - return invalid/truncated JSON\n *\n * This function handles all of those cases robustly by first stripping thinking\n * wrapper blocks, then scanning balanced `[...]` spans and only accepting arrays\n * that match expected remediation object shape.\n * Returns `null` when no valid array can be extracted (callers treat this as\n * `failed_parse` — no remediations are applied and the error is reported).\n *\n * Scenarios and expected behaviour:\n * - **strict JSON**: `[{\"remediationType\":\"MEMORY_STORE\",...}]` → parsed directly\n * - **fenced JSON**: `` ```json\\n[...]\\n``` `` → fence stripped, array parsed\n * - **trailing text**: `[...]\\n\\nHere is my explanation` → array extracted, text ignored\n * - **thinking prefix**: `<thinking>...</thinking>\\n[...]` → thinking stripped, array parsed\n * - **invalid JSON**: `[not valid]` / truncated → null returned, caller handles error\n */\nexport function parseSelfCorrectionLLMResponse(content: string): unknown[] | null {\n let emptyArrayCandidate: unknown[] | null = null;\n const normalized = stripThinkingWrapperBlocks(content);\n\n const result = tryParseFirstJsonArray(normalized, (parsed) => {\n if (parsed.length === 0) {\n emptyArrayCandidate = parsed;\n return null;\n }\n return isSelfCorrectionRemediationArray(parsed) ? parsed : null;\n });\n\n return result ?? emptyArrayCandidate;\n}\n\nfunction isSelfCorrectionRemediationArray(items: unknown[]): boolean {\n return items.every((item) => isSelfCorrectionRemediationItem(item));\n}\n\nfunction isSelfCorrectionRemediationItem(item: unknown): boolean {\n if (typeof item !== \"object\" || item === null) return false;\n const candidate = item as Record<string, unknown>;\n const remediationType = candidate.remediationType;\n if (typeof remediationType !== \"string\" || remediationType.trim().length === 0) return false;\n\n const isNoAction = remediationType.trim().toUpperCase() === \"NO_ACTION\";\n if (\"remediationContent\" in candidate) {\n const remediationContent = candidate.remediationContent;\n if (\n !(\n typeof remediationContent === \"string\" ||\n (typeof remediationContent === \"object\" && remediationContent !== null)\n )\n ) {\n return false;\n }\n } else if (!isNoAction) {\n return false;\n }\n\n if (\"category\" in candidate && typeof candidate.category !== \"string\") return false;\n if (\"severity\" in candidate && typeof candidate.severity !== \"string\") return false;\n if (\"repeated\" in candidate && typeof candidate.repeated !== \"boolean\") return false;\n\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// self-correction extract\n// ---------------------------------------------------------------------------\n\n/**\n * Extract self-correction incidents from sessions.\n */\nexport function runSelfCorrectionExtractForCli(\n ctx: HandlerContext,\n opts: {\n days?: number;\n outputPath?: string;\n verbose?: boolean;\n /** Pre-filtered session file paths. When provided, skips gatherSessionFiles(). */\n filePaths?: string[];\n },\n): SelfCorrectionExtractResult {\n const filePaths =\n opts.filePaths ?? gatherSessionFiles({ days: opts.days ?? 3 }).map((f: { path: string; mtime: number }) => f.path);\n if (filePaths.length === 0) {\n return { incidents: [], sessionsScanned: 0 };\n }\n if (opts.verbose) {\n ctx.logger.info?.(`memory-hybrid: self-correction-extract — scanning ${filePaths.length} session file(s)`);\n const cap = 40;\n for (let i = 0; i < Math.min(filePaths.length, cap); i++) {\n ctx.logger.info?.(` ${filePaths[i]}`);\n }\n if (filePaths.length > cap) {\n ctx.logger.info?.(` ... and ${filePaths.length - cap} more`);\n }\n }\n try {\n const result = runSelfCorrectionExtract({\n filePaths,\n correctionRegex: getCorrectionSignalRegex(),\n });\n if (opts.outputPath && result.incidents.length > 0) {\n try {\n const outputJson = JSON.stringify(result.incidents, null, 2);\n // Follow symlinks so shared extract targets are updated, not replaced.\n if (existsSync(opts.outputPath) && lstatSync(opts.outputPath).isSymbolicLink()) {\n writeFileSync(opts.outputPath, outputJson, \"utf-8\");\n } else {\n atomicWriteFile(opts.outputPath, outputJson);\n }\n } catch (e) {\n capturePluginError(e as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionExtractForCli:write-output\" });\n }\n }\n return result;\n } catch (err) {\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionExtractForCli\" });\n throw err;\n }\n}\n\n// ---------------------------------------------------------------------------\n// self-correction run\n// ---------------------------------------------------------------------------\n\n/**\n * Run self-correction analysis and remediation.\n */\nexport async function runSelfCorrectionRunForCli(\n ctx: HandlerContext,\n opts: {\n extractPath?: string;\n incidents?: CorrectionIncident[];\n workspace?: string;\n dryRun?: boolean;\n model?: string;\n approve?: boolean;\n applyTools?: boolean;\n full?: boolean;\n verbose?: boolean;\n },\n): Promise<SelfCorrectionRunResult> {\n const { factsDb, vectorDb, embeddings, openai, cfg, logger, proposalsDb } = ctx;\n const SCAN_TYPE = \"self-correction-run\";\n\n // Startup guard + concurrency lock (skip if already ran within 23h and not forced)\n // Only apply when no explicit incidents/extractPath provided (i.e. fresh scan)\n if (!opts.full && !opts.dryRun && !opts.incidents && !opts.extractPath) {\n const cursor = factsDb.getScanCursor(SCAN_TYPE);\n const skip = acquireScanSlot(SCAN_TYPE, cursor?.lastRunAt, logger);\n if (skip) {\n const isConcurrency = skip.includes(\"already running\");\n return {\n incidentsFound: 0,\n analysed: 0,\n autoFixed: 0,\n proposals: [],\n reportPath: null,\n skipped: true,\n status: isConcurrency ? \"skipped_concurrency\" : \"skipped_cooldown\",\n };\n }\n }\n\n try {\n const workspaceRoot = opts.workspace ?? getEnv(\"OPENCLAW_WORKSPACE\") ?? join(homedir(), \".openclaw\", \"workspace\");\n const scCfg = cfg.selfCorrection ?? DEFAULT_SELF_CORRECTION;\n const reportDir = join(workspaceRoot, \"memory\", \"reports\");\n const today = new Date().toISOString().slice(0, 10);\n const reportPath = join(reportDir, `self-correction-${today}.md`);\n let incidents: CorrectionIncident[];\n if (opts.incidents !== undefined) {\n incidents = opts.incidents;\n } else if (opts.extractPath) {\n try {\n const raw = readFileSync(opts.extractPath, \"utf-8\");\n incidents = JSON.parse(raw) as CorrectionIncident[];\n } catch (e) {\n capturePluginError(e as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:read-extract\" });\n return { incidentsFound: 0, analysed: 0, autoFixed: 0, proposals: [], reportPath: null, error: String(e) };\n }\n } else {\n // Two-tier pre-filter: use local Ollama to triage sessions before extraction (Issue #290).\n let scFilePaths: string[] | undefined;\n const pfCfgSC = buildPreFilterConfig(cfg);\n if (pfCfgSC.enabled) {\n const sessionFiles = gatherSessionFiles({ days: 3 });\n const allPaths = sessionFiles.map((f: { path: string; mtime: number }) => f.path);\n if (allPaths.length > 0) {\n const pfResult = await preFilterSessions(allPaths, pfCfgSC);\n if (!pfResult.ollamaUnavailable) {\n logger.info?.(\n `memory-hybrid: ${SCAN_TYPE} pre-filter: ${pfResult.kept.length}/${allPaths.length} sessions flagged as interesting`,\n );\n scFilePaths = pfResult.kept;\n } else {\n logger.info?.(`memory-hybrid: ${SCAN_TYPE} pre-filter: Ollama unavailable — scanning all sessions`);\n scFilePaths = allPaths; // avoid redundant gatherSessionFiles inside runSelfCorrectionExtractForCli\n }\n }\n }\n const extractResult = runSelfCorrectionExtractForCli(ctx, {\n days: 3,\n filePaths: scFilePaths,\n verbose: opts.verbose,\n });\n incidents = extractResult.incidents;\n }\n if (incidents.length === 0) {\n const emptyReport = `# Self-Correction Analysis (${today})\\n\\nScanned sessions: 3 days.\\nIncidents found: 0.\\n`;\n try {\n atomicWriteFile(reportPath, emptyReport);\n } catch (err) {\n capturePluginError(err as Error, {\n subsystem: \"cli\",\n operation: \"runSelfCorrectionRunForCli:write-empty-report\",\n });\n }\n if (!opts.dryRun && !opts.incidents && !opts.extractPath) {\n factsDb.updateScanCursor(SCAN_TYPE, 0, 0);\n clearScanLock(SCAN_TYPE);\n }\n return {\n incidentsFound: 0,\n analysed: 0,\n autoFixed: 0,\n proposals: [],\n reportPath,\n status: \"success_no_incidents\",\n };\n }\n if (opts.verbose) {\n logger.info?.(`memory-hybrid: ${SCAN_TYPE} — ${incidents.length} incident(s); building LLM prompt…`);\n }\n const prompt = fillPrompt(loadPrompt(\"self-correction-analyze\"), {\n incidents_json: JSON.stringify(incidents),\n });\n const heavyResolved = resolveReflectionModelAndFallbacks(cfg, \"heavy\");\n const heavyPrefWithSources = resolveTierPreferenceWithSources(cfg, \"heavy\");\n const model = opts.model ?? heavyResolved.defaultModel ?? getDefaultCronModel(getCronModelConfig(cfg), \"heavy\");\n const modelSource = opts.model\n ? \"--model\"\n : heavyPrefWithSources.models[0] === model\n ? (heavyPrefWithSources.sources[0] ?? \"built-in\")\n : \"built-in\";\n const scFallbackCandidates = opts.model\n ? [heavyResolved.defaultModel, ...(heavyResolved.fallbackModels ?? [])]\n : (heavyResolved.fallbackModels ?? []);\n const scFallbackModels = [...new Set(scFallbackCandidates.filter((m) => m !== model))];\n let analysed: Array<{\n category: string;\n severity: string;\n remediationType: string;\n remediationContent: string | { text?: string; entity?: string; key?: string; tags?: string[] };\n repeated?: boolean;\n }> = [];\n const useSpawn = scCfg.analyzeViaSpawn && incidents.length > scCfg.spawnThreshold;\n try {\n const attemptAnalysisJsonRepair = async (rawContent: string): Promise<typeof analysed | null> => {\n const repairPrompt = [\n \"Convert the following model output into a valid JSON array.\",\n \"Return ONLY JSON (no markdown, no prose).\",\n \"If no valid remediation items can be recovered, return [].\",\n \"\",\n \"MODEL_OUTPUT_START\",\n rawContent,\n \"MODEL_OUTPUT_END\",\n ].join(\"\\n\");\n const adaptiveEnabled = (getEnv(\"OPENCLAW_HYBRID_MEM_ADAPTIVE_DISTILL\") ?? \"\").trim() !== \"0\";\n const detail = await chatCompleteWithAdaptiveMaintenanceRetry({\n model,\n modelSource,\n content: repairPrompt,\n temperature: 0,\n maxTokens: distillMaxOutputTokens(model),\n openai,\n fallbackModels: scFallbackModels,\n label: \"memory-hybrid: self-correction analyze-repair\",\n feature: CostFeature.selfCorrectionAnalyze,\n logger,\n adaptiveStatePath:\n ctx.resolvedSqlitePath && ctx.resolvedSqlitePath.length > 0\n ? join(dirname(ctx.resolvedSqlitePath), \".adaptive-llm-limits.json\")\n : undefined,\n enabled: adaptiveEnabled,\n });\n const repaired = parseSelfCorrectionLLMResponse(detail.content);\n return repaired === null ? null : (repaired as typeof analysed);\n };\n\n let content: string;\n if (useSpawn) {\n const { spawnSync } = await import(\"node:child_process\");\n const { tmpdir: osTmp } = await import(\"node:os\");\n const promptPath = join(osTmp(), `self-correction-prompt-${Date.now()}.txt`);\n writeFileSync(promptPath, prompt, \"utf-8\");\n const spawnModel = scCfg.spawnModel?.trim() || getDefaultCronModel(getCronModelConfig(cfg), \"default\");\n const r = spawnSync(\n \"openclaw\",\n [\n \"sessions\",\n \"spawn\",\n \"--model\",\n spawnModel,\n \"--message\",\n \"Analyze the attached incidents and output ONLY a JSON array (no markdown, no code fences). Use the instructions in the attached file.\",\n \"--attach\",\n promptPath,\n ],\n { encoding: \"utf-8\", maxBuffer: 2 * 1024 * 1024 },\n );\n try {\n if (existsSync(promptPath)) rmSync(promptPath, { force: true });\n } catch (err) {\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:cleanup-tmp\" });\n }\n content = (r.stdout ?? \"\") + (r.stderr ?? \"\");\n if (r.status !== 0) throw new Error(`sessions spawn exited ${r.status}: ${content.slice(0, 500)}`);\n } else {\n logger.info?.(\"memory-hybrid: self-correction-run model tier = heavy\");\n logger.info?.(`memory-hybrid: self-correction-run starting with model ${model} (source=${modelSource})`);\n logger.info?.(\n `memory-hybrid: self-correction-run fallback chain = [${scFallbackModels.length > 0 ? scFallbackModels.join(\", \") : \"\"}]`,\n );\n const adaptiveEnabled = (getEnv(\"OPENCLAW_HYBRID_MEM_ADAPTIVE_DISTILL\") ?? \"\").trim() !== \"0\";\n const detail = await chatCompleteWithAdaptiveMaintenanceRetry({\n model,\n modelSource,\n content: prompt,\n temperature: 0.2,\n maxTokens: distillMaxOutputTokens(model),\n openai,\n fallbackModels: scFallbackModels,\n label: \"memory-hybrid: self-correction analyze\",\n feature: CostFeature.selfCorrectionAnalyze,\n logger,\n adaptiveStatePath:\n ctx.resolvedSqlitePath && ctx.resolvedSqlitePath.length > 0\n ? join(dirname(ctx.resolvedSqlitePath), \".adaptive-llm-limits.json\")\n : undefined,\n enabled: adaptiveEnabled,\n });\n if (detail.modelUsed !== model) {\n logger.info?.(`memory-hybrid: self-correction-run analysis used fallback model ${detail.modelUsed}`);\n }\n content = detail.content;\n }\n const parsedRemediations = parseSelfCorrectionLLMResponse(content);\n if (parsedRemediations !== null) {\n analysed = parsedRemediations as typeof analysed;\n } else if (content.trim().length > 0) {\n // Log a sanitized excerpt (no private session data) so operators can diagnose.\n const excerpt = sanitizeLlmResponseExcerpt(content);\n logger.warn?.(\n `memory-hybrid: self-correction-run — initial JSON parse failed; attempting repair pass. excerpt: \"${excerpt}\"`,\n );\n let repaired: typeof analysed | null = null;\n try {\n repaired = await attemptAnalysisJsonRepair(content);\n } catch (repairErr) {\n capturePluginError(repairErr as Error, {\n subsystem: \"cli\",\n operation: \"runSelfCorrectionRunForCli:llm-analysis-repair\",\n });\n }\n if (repaired !== null) {\n analysed = repaired;\n logger.info?.(`memory-hybrid: self-correction-run — repair pass recovered ${analysed.length} item(s)`);\n } else {\n const parseError = new Error(\n `Self-correction analysis: LLM response could not be parsed as a JSON array (repair failed). excerpt=\"${excerpt}\"`,\n );\n (parseError as any).isParseFailure = true;\n throw parseError;\n }\n } else {\n analysed = [];\n }\n if (opts.verbose && analysed.length > 0) {\n logger.info?.(\n `memory-hybrid: ${SCAN_TYPE} — LLM returned ${analysed.length} remediation item(s) (before cap/filter)`,\n );\n }\n } catch (e) {\n capturePluginError(e as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:llm-analysis\" });\n const isParseFailure = (e as any).isParseFailure === true;\n return {\n incidentsFound: incidents.length,\n analysed: 0,\n autoFixed: 0,\n proposals: [],\n reportPath: null,\n error: String(e),\n status: isParseFailure ? \"failed_parse\" : undefined,\n };\n }\n const proposals: string[] = [];\n const toolsSuggestions: string[] = [];\n let autoFixed = 0;\n let toolsApplied = 0;\n const toApply = analysed\n .filter((a) => a.remediationType !== \"NO_ACTION\" && !a.repeated)\n .slice(0, SELF_CORRECTION_CAP);\n const toolsPath = join(workspaceRoot, \"TOOLS.md\");\n const toolsSection = scCfg.toolsSection;\n const semanticThreshold = scCfg.semanticDedupThreshold ?? 0.92;\n\n for (const a of toApply) {\n if (a.remediationType === \"MEMORY_STORE\") {\n const c = a.remediationContent;\n const obj =\n typeof c === \"object\" && c && \"text\" in c ? c : { text: String(c), entity: \"Fact\", tags: [] as string[] };\n const text = (obj.text ?? \"\").trim();\n if (!text || factsDb.hasDuplicate(text, \"self-correction\")) continue;\n let vector: number[] | null = null;\n if (scCfg.semanticDedup || !opts.dryRun) {\n try {\n vector = await embeddings.embed(text);\n if (scCfg.semanticDedup && (await vectorDb.hasDuplicate(vector, semanticThreshold))) continue;\n } catch (err) {\n logger.warn?.(`memory-hybrid: self-correction embed/semantic dedup failed: ${err}`);\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:embed-dedup\" });\n continue;\n }\n }\n if (opts.dryRun) continue;\n try {\n const storeResult = factsDb.storeWithResult({\n text,\n category: \"technical\",\n importance: CLI_STORE_IMPORTANCE,\n entity: obj.entity ?? null,\n key: typeof obj.key === \"string\" ? obj.key : null,\n value: text.slice(0, 200),\n source: \"self-correction\",\n tags: Array.isArray(obj.tags) ? obj.tags : [],\n });\n if (storeResult.skipped) {\n continue;\n }\n const entry = storeResult.entry;\n // CRITICAL FIX (#2): Delete vector for evicted fact to prevent orphaned vectors\n await cleanupEvictedVector({\n vectorDb: vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: logger,\n context: \"self-correction\",\n });\n if (vector) {\n await vectorDb.store({\n text,\n vector,\n importance: CLI_STORE_IMPORTANCE,\n category: \"technical\",\n id: entry.id,\n });\n factsDb.setEmbeddingModel(entry.id, embeddings.modelName);\n }\n autoFixed++;\n } catch (err) {\n logger.warn?.(`memory-hybrid: self-correction MEMORY_STORE failed: ${err}`);\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:memory-store\" });\n }\n } else if (a.remediationType === \"TOOLS_RULE\") {\n const line =\n typeof a.remediationContent === \"string\"\n ? a.remediationContent\n : ((a.remediationContent as { text?: string })?.text ?? \"\");\n if (line.trim()) toolsSuggestions.push(line.trim());\n } else if (a.remediationType === \"AGENTS_RULE\" || a.remediationType === \"SKILL_UPDATE\") {\n const line =\n typeof a.remediationContent === \"string\"\n ? a.remediationContent\n : ((a.remediationContent as { text?: string })?.text ?? \"\");\n if (line.trim()) {\n proposals.push(`[${a.remediationType}] ${line.trim()}`);\n // Wire AGENTS_RULE into proposals DB (#260) — closes the dead end\n if (\n a.remediationType === \"AGENTS_RULE\" &&\n proposalsDb &&\n (scCfg as { agentsRuleToProposals?: boolean }).agentsRuleToProposals !== false &&\n !opts.dryRun\n ) {\n try {\n const targetFile = inferTargetFile(line);\n const incidentContext =\n incidents.length > 0\n ? `Correction incident: \"${incidents[0].userMessage.slice(0, 200)}\"`\n : \"Self-correction analysis\";\n proposalsDb.create({\n targetFile,\n title: `Self-correction: ${a.category ?? \"behavior\"}`,\n observation: incidentContext,\n suggestedChange: line.trim(),\n confidence: 0.7,\n evidenceSessions: incidents\n .map((inc) => inc.sessionFile)\n .filter((v, idx, arr) => arr.indexOf(v) === idx),\n });\n } catch (err) {\n capturePluginError(err as Error, {\n subsystem: \"cli\",\n operation: \"runSelfCorrectionRunForCli:agents-rule-proposal\",\n });\n }\n }\n }\n }\n }\n\n const noApplyTools = opts.applyTools === false;\n const shouldApplyTools = !opts.dryRun && (scCfg.applyToolsByDefault !== false || opts.approve) && !noApplyTools;\n if (toolsSuggestions.length > 0 && !opts.dryRun) {\n if (scCfg.autoRewriteTools && shouldApplyTools && existsSync(toolsPath)) {\n try {\n const currentTools = readFileSync(toolsPath, \"utf-8\");\n const rewritePrompt = fillPrompt(loadPrompt(\"self-correction-rewrite-tools\"), {\n current_tools: currentTools,\n new_rules: toolsSuggestions.join(\"\\n\"),\n });\n logger.info?.(\n `memory-hybrid: self-correction-run rewrite-tools starting with model ${model} (source=${modelSource})`,\n );\n const adaptiveEnabled = (getEnv(\"OPENCLAW_HYBRID_MEM_ADAPTIVE_DISTILL\") ?? \"\").trim() !== \"0\";\n const detail = await chatCompleteWithAdaptiveMaintenanceRetry({\n model,\n modelSource,\n content: rewritePrompt,\n temperature: 0.2,\n maxTokens: 16000,\n openai,\n fallbackModels: scFallbackModels,\n label: \"memory-hybrid: self-correction rewrite-tools\",\n feature: CostFeature.selfCorrectionRewriteTools,\n logger,\n adaptiveStatePath:\n ctx.resolvedSqlitePath && ctx.resolvedSqlitePath.length > 0\n ? join(dirname(ctx.resolvedSqlitePath), \".adaptive-llm-limits.json\")\n : undefined,\n enabled: adaptiveEnabled,\n });\n if (detail.modelUsed !== model) {\n logger.info?.(`memory-hybrid: self-correction-run rewrite-tools used fallback model ${detail.modelUsed}`);\n }\n const cleaned = detail.content\n .trim()\n .replace(/^```\\w*\\n?|```\\s*$/g, \"\")\n .trim();\n if (cleaned.length > 50) {\n // Follow symlinks so shared TOOLS.md targets are updated, not replaced.\n if (existsSync(toolsPath) && lstatSync(toolsPath).isSymbolicLink()) {\n writeFileSync(toolsPath, cleaned, \"utf-8\");\n } else {\n atomicWriteFile(toolsPath, cleaned);\n }\n toolsApplied = toolsSuggestions.length;\n autoFixed += toolsApplied;\n }\n } catch (err) {\n logger.warn?.(`memory-hybrid: self-correction TOOLS rewrite failed: ${err}`);\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:tools-rewrite\" });\n }\n } else if (shouldApplyTools && existsSync(toolsPath)) {\n try {\n const { inserted } = insertRulesUnderSection(toolsPath, toolsSection, toolsSuggestions);\n toolsApplied = inserted;\n autoFixed += inserted;\n } catch (err) {\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:insert-tools\" });\n }\n }\n }\n\n const reportLines = [\n `# Self-Correction Analysis (${today})`,\n \"\",\n `Scanned: last 3 days. Incidents found: ${incidents.length}.`,\n `Analysed: ${analysed.length}. Auto-fixed: ${autoFixed}. Needs review: ${proposals.length}.`,\n \"\",\n ...(autoFixed > 0 ? [\"## Auto-applied\", \"\", `- ${autoFixed} memory store(s) and/or TOOLS.md rule(s).`, \"\"] : []),\n ...(toolsSuggestions.length > 0 && toolsApplied === 0 && !scCfg.autoRewriteTools\n ? [\n \"## Suggested TOOLS.md rules (not applied this run). To apply: config applyToolsByDefault is true by default, or use --approve. To skip applying: --no-apply-tools.\",\n \"\",\n ...toolsSuggestions.map((s) => `- ${s}`),\n \"\",\n ]\n : []),\n ...(toolsApplied > 0\n ? [\"## TOOLS.md updated\", \"\", `- ${toolsApplied} rule(s) inserted under section \"${toolsSection}\".`, \"\"]\n : []),\n ...(proposals.length > 0\n ? [\"## Proposed (review before applying)\", \"\", ...proposals.map((p) => `- ${p}`), \"\"]\n : []),\n ];\n try {\n atomicWriteFile(reportPath, reportLines.join(\"\\n\"));\n } catch (e) {\n logger.warn?.(`memory-hybrid: could not write report: ${e}`);\n capturePluginError(e as Error, { subsystem: \"cli\", operation: \"runSelfCorrectionRunForCli:write-report\" });\n }\n // Record savings: each auto-fixed incident avoided ~2 manual LLM round-trips\n if (autoFixed > 0 && ctx.costTracker && !opts?.dryRun) {\n ctx.costTracker.recordSavings({\n feature: \"self-correction\",\n action: \"auto-fixed incident\",\n countAvoided: autoFixed,\n estimatedSavingUsd: autoFixed * 0.002,\n note: `${autoFixed} incident(s) auto-remediated`,\n });\n }\n\n if (!opts.dryRun && !opts.incidents && !opts.extractPath) {\n factsDb.updateScanCursor(SCAN_TYPE, Date.now(), incidents.length);\n }\n\n return {\n incidentsFound: incidents.length,\n analysed: analysed.length,\n autoFixed,\n proposals,\n reportPath,\n toolsSuggestions: toolsSuggestions.length > 0 ? toolsSuggestions : undefined,\n toolsApplied: toolsApplied > 0 ? toolsApplied : undefined,\n status: \"success_analyzed\",\n };\n } finally {\n if (!opts.full && !opts.dryRun && !opts.incidents && !opts.extractPath) clearScanLock(SCAN_TYPE);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cmd-setup.js","names":[],"sources":["../../cli/cmd-setup.ts"],"sourcesContent":["/**\n * Interactive setup wizard for first-time configuration\n */\n\nimport type { Chainable } from \"./shared.js\";\nimport type { HybridMemoryConfig } from \"../config.js\";\nimport { detectAvailableProviders, recommendProvider } from \"../utils/provider-detection.js\";\nimport { ProgressSpinner } from \"../utils/progress-indicators.js\";\n\n// Simple readline alternative for getting user input\nasync function prompt(question: string): Promise<string> {\n const readline = await import(\"node:readline\");\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\ntype HiddenReadline = {\n question(question: string, callback: (answer: string) => void): void;\n close(): void;\n on(event: \"close\", callback: () => void): unknown;\n};\n\ntype HiddenReadlineFactory = (options: { input: NodeJS.ReadStream; output: NodeJS.WriteStream }) => HiddenReadline;\n\nexport async function promptHidden(question: string): Promise<string> {\n const readline = await import(\"node:readline\");\n return promptHiddenWithInterface(question, readline.createInterface as HiddenReadlineFactory);\n}\n\nexport async function promptHiddenWithInterface(\n question: string,\n createInterface: HiddenReadlineFactory,\n): Promise<string> {\n const mutableOutput = process.stdout as NodeJS.WriteStream & { muted?: boolean };\n const rl = createInterface({ input: process.stdin, output: mutableOutput });\n const originalWrite = mutableOutput.write.bind(mutableOutput);\n mutableOutput.muted = false;\n mutableOutput.write = ((chunk: unknown, encoding?: BufferEncoding, cb?: (err?: Error | null) => void) => {\n if (!mutableOutput.muted) return originalWrite(chunk as string | Uint8Array, encoding, cb);\n if (typeof cb === \"function\") cb();\n return true;\n }) as typeof mutableOutput.write;\n\n const restore = () => {\n mutableOutput.muted = false;\n mutableOutput.write = originalWrite as typeof mutableOutput.write;\n };\n\n return new Promise((resolve) => {\n rl.on(\"close\", () => {\n restore();\n resolve(\"\");\n });\n rl.question(question, (answer) => {\n restore();\n process.stdout.write(\"\\n\");\n resolve(answer.trim());\n rl.close();\n });\n mutableOutput.muted = true;\n });\n}\n\nexport function registerSetupCommand(\n program: Chainable,\n cfg: HybridMemoryConfig,\n runConfigSet?: (\n key: string,\n value: string,\n ) => { ok: boolean; error?: string } | Promise<{ ok: boolean; error?: string }>,\n): void {\n program\n .command(\"setup\")\n .description(\"Interactive setup wizard for first-time configuration\")\n .option(\"--interactive\", \"Run in interactive mode (ask questions)\")\n .action(async (opts: { interactive?: boolean }) => {\n console.log(\"\\n🚀 Hybrid Memory Setup Wizard\\n\");\n console.log(\"This wizard will help you configure the hybrid memory system.\\n\");\n\n // Step 1: Detect available providers\n console.log(\"Step 1: Detecting available embedding providers...\\n\");\n const spinner = new ProgressSpinner(\"Checking providers\");\n spinner.start();\n\n const providers = await detectAvailableProviders(cfg.embedding?.apiKey, cfg.embedding?.googleApiKey);\n spinner.success(\"Provider detection complete\");\n\n console.log(\"\\nAvailable providers:\\n\");\n for (const provider of providers) {\n const icon = provider.available ? \"✓\" : \"✗\";\n const badge = provider.localOnly ? \"[Local]\" : \"[Cloud]\";\n console.log(` ${icon} ${provider.provider.toUpperCase()} ${badge}`);\n console.log(` ${provider.recommendation}\\n`);\n }\n\n // Step 2: Choose provider\n let selectedProvider: string;\n\n if (opts.interactive) {\n const recommended = await recommendProvider(cfg.embedding?.apiKey, cfg.embedding?.googleApiKey);\n console.log(`\\nRecommended provider: ${recommended.toUpperCase()}\\n`);\n\n const answer = await prompt(`Choose provider (ollama/onnx/openai/google) [${recommended}]: `);\n selectedProvider = answer || recommended;\n } else {\n selectedProvider = await recommendProvider(cfg.embedding?.apiKey, cfg.embedding?.googleApiKey);\n console.log(`\\nUsing recommended provider: ${selectedProvider}\\n`);\n }\n\n // Step 3: Configure provider\n const configUpdates: Record<string, string> = {\n \"embedding.provider\": selectedProvider,\n };\n\n if (selectedProvider === \"openai\") {\n console.log(\"\\n⚠️ OpenAI requires an API key and incurs costs.\\n\");\n\n if (opts.interactive) {\n const apiKey = await promptHidden(\"Enter your OpenAI API key (input hidden): \");\n if (apiKey) {\n configUpdates[\"embedding.apiKey\"] = apiKey;\n }\n } else {\n console.log(\"Set your API key with: openclaw hybrid-mem config-set embedding.apiKey YOUR_KEY\\n\");\n }\n\n // Set default model\n configUpdates[\"embedding.model\"] = \"text-embedding-3-small\";\n } else if (selectedProvider === \"ollama\") {\n configUpdates[\"embedding.model\"] = \"nomic-embed-text\";\n console.log(\"\\n💡 Make sure Ollama is running: ollama serve\");\n console.log(\" And pull the model: ollama pull nomic-embed-text\\n\");\n } else if (selectedProvider === \"onnx\") {\n configUpdates[\"embedding.model\"] = \"all-MiniLM-L6-v2\";\n } else if (selectedProvider === \"google\") {\n configUpdates[\"embedding.model\"] = \"text-embedding-004\";\n if (opts.interactive) {\n const apiKey = await promptHidden(\"Enter your Google API key (input hidden): \");\n if (apiKey) configUpdates[\"embedding.googleApiKey\"] = apiKey;\n } else {\n console.log(\"Set your API key with: openclaw hybrid-mem config-set embedding.googleApiKey YOUR_KEY\\n\");\n }\n }\n\n // Step 4: Apply configuration\n console.log(\"\\nApplying configuration...\\n\");\n\n if (!runConfigSet) {\n throw new Error(\"setup cannot persist configuration: config writer is unavailable in this CLI context\");\n }\n\n for (const [key, value] of Object.entries(configUpdates)) {\n const displayValue = key.toLowerCase().includes(\"key\") ? \"[hidden]\" : value;\n console.log(` Setting ${key} = ${displayValue}`);\n const result = await runConfigSet(key, value);\n if (!result.ok) throw new Error(result.error || `Failed to set ${key}`);\n }\n\n // Step 5: Run verification\n console.log(\"\\n✓ Configuration complete!\\n\");\n console.log(\"Next steps:\\n\");\n console.log(\" 1. Verify setup: openclaw hybrid-mem verify\");\n console.log(\" 2. Try the demo: openclaw hybrid-mem demo\");\n console.log(\" 3. Store your first fact: openclaw hybrid-mem store 'your text here'\\n\");\n\n // Show onboarding checklist\n console.log(\"📋 Onboarding Checklist:\\n\");\n console.log(\" ✓ Configure embedding provider\");\n console.log(\" ⃞ Run verification (openclaw hybrid-mem verify)\");\n console.log(\" ⃞ Store your first memory\");\n console.log(\" ⃞ Try a semantic search\");\n console.log(\" ⃞ Set up backup automation\\n\");\n\n console.log(\"💡 For more help: openclaw hybrid-mem examples basics\\n\");\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cmd-setup.js","names":[],"sources":["../../cli/cmd-setup.ts"],"sourcesContent":["/**\n * Interactive setup wizard for first-time configuration\n */\n\nimport type { Chainable } from \"./shared.js\";\nimport type { HybridMemoryConfig } from \"../config.js\";\nimport { detectAvailableProviders, recommendProvider } from \"../utils/provider-detection.js\";\nimport { ProgressSpinner } from \"../utils/progress-indicators.js\";\n\n// Simple readline alternative for getting user input\nasync function prompt(question: string): Promise<string> {\n const readline = await import(\"node:readline\");\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\ntype HiddenReadline = {\n question(question: string, callback: (answer: string) => void): void;\n close(): void;\n on(event: \"close\", callback: () => void): unknown;\n};\n\ntype HiddenReadlineFactory = (options: { input: NodeJS.ReadStream; output: NodeJS.WriteStream }) => HiddenReadline;\n\nexport async function promptHidden(question: string): Promise<string> {\n const readline = await import(\"node:readline\");\n return promptHiddenWithInterface(question, readline.createInterface as HiddenReadlineFactory);\n}\n\nexport async function promptHiddenWithInterface(\n question: string,\n createInterface: HiddenReadlineFactory,\n): Promise<string> {\n const mutableOutput = process.stdout as NodeJS.WriteStream & { muted?: boolean };\n const rl = createInterface({ input: process.stdin, output: mutableOutput });\n const originalWrite = mutableOutput.write.bind(mutableOutput);\n mutableOutput.muted = false;\n mutableOutput.write = ((chunk: unknown, encoding?: BufferEncoding, cb?: (err?: Error | null) => void) => {\n if (!mutableOutput.muted) return originalWrite(chunk as string | Uint8Array, encoding, cb);\n if (typeof cb === \"function\") cb();\n return true;\n }) as typeof mutableOutput.write;\n\n const restore = () => {\n mutableOutput.muted = false;\n mutableOutput.write = originalWrite as typeof mutableOutput.write;\n };\n\n return new Promise((resolve) => {\n rl.on(\"close\", () => {\n restore();\n resolve(\"\");\n });\n rl.question(question, (answer) => {\n restore();\n process.stdout.write(\"\\n\");\n resolve(answer.trim());\n rl.close();\n });\n mutableOutput.muted = true;\n });\n}\n\nexport function registerSetupCommand(\n program: Chainable,\n cfg: HybridMemoryConfig,\n runConfigSet?: (\n key: string,\n value: string,\n ) => { ok: boolean; error?: string } | Promise<{ ok: boolean; error?: string }>,\n): void {\n program\n .command(\"setup\")\n .description(\"Interactive setup wizard for first-time configuration\")\n .option(\"--interactive\", \"Run in interactive mode (ask questions)\")\n .action(async (opts: { interactive?: boolean }) => {\n console.log(\"\\n🚀 Hybrid Memory Setup Wizard\\n\");\n console.log(\"This wizard will help you configure the hybrid memory system.\\n\");\n\n // Step 1: Detect available providers\n console.log(\"Step 1: Detecting available embedding providers...\\n\");\n const spinner = new ProgressSpinner(\"Checking providers\");\n spinner.start();\n\n const providers = await detectAvailableProviders(cfg.embedding?.apiKey, cfg.embedding?.googleApiKey);\n spinner.success(\"Provider detection complete\");\n\n console.log(\"\\nAvailable providers:\\n\");\n for (const provider of providers) {\n const icon = provider.available ? \"✓\" : \"✗\";\n const badge = provider.localOnly ? \"[Local]\" : \"[Cloud]\";\n console.log(` ${icon} ${provider.provider.toUpperCase()} ${badge}`);\n console.log(` ${provider.recommendation}\\n`);\n }\n\n // Step 2: Choose provider\n let selectedProvider: string;\n\n if (opts.interactive) {\n const recommended = await recommendProvider(cfg.embedding?.apiKey, cfg.embedding?.googleApiKey);\n console.log(`\\nRecommended provider: ${recommended.toUpperCase()}\\n`);\n\n const answer = await prompt(`Choose provider (ollama/onnx/openai/google) [${recommended}]: `);\n selectedProvider = answer || recommended;\n } else {\n selectedProvider = await recommendProvider(cfg.embedding?.apiKey, cfg.embedding?.googleApiKey);\n console.log(`\\nUsing recommended provider: ${selectedProvider}\\n`);\n }\n\n // Step 3: Configure provider\n const configUpdates: Record<string, string> = {\n \"embedding.provider\": selectedProvider,\n };\n\n if (selectedProvider === \"openai\") {\n console.log(\"\\n⚠️ OpenAI requires an API key and incurs costs.\\n\");\n\n if (opts.interactive) {\n const apiKey = await promptHidden(\"Enter your OpenAI API key (input hidden): \");\n if (apiKey) {\n configUpdates[\"embedding.apiKey\"] = apiKey;\n }\n } else {\n console.log(\"Set your API key with: openclaw hybrid-mem config-set embedding.apiKey YOUR_KEY\\n\");\n }\n\n // Set default model\n configUpdates[\"embedding.model\"] = \"text-embedding-3-small\";\n } else if (selectedProvider === \"ollama\") {\n configUpdates[\"embedding.model\"] = \"nomic-embed-text\";\n console.log(\"\\n💡 Make sure Ollama is running: ollama serve\");\n console.log(\" And pull the model: ollama pull nomic-embed-text\\n\");\n } else if (selectedProvider === \"onnx\") {\n configUpdates[\"embedding.model\"] = \"all-MiniLM-L6-v2\";\n } else if (selectedProvider === \"google\") {\n configUpdates[\"embedding.model\"] = \"text-embedding-004\";\n if (opts.interactive) {\n const apiKey = await promptHidden(\"Enter your Google API key (input hidden): \");\n if (apiKey) configUpdates[\"embedding.googleApiKey\"] = apiKey;\n } else {\n console.log(\"Set your API key with: openclaw hybrid-mem config-set embedding.googleApiKey YOUR_KEY\\n\");\n }\n }\n\n // Step 4: Apply configuration\n console.log(\"\\nApplying configuration...\\n\");\n\n if (!runConfigSet) {\n throw new Error(\"setup cannot persist configuration: config writer is unavailable in this CLI context\");\n }\n\n for (const [key, value] of Object.entries(configUpdates)) {\n const displayValue = key.toLowerCase().includes(\"key\") ? \"[hidden]\" : value;\n console.log(` Setting ${key} = ${displayValue}`);\n const result = await runConfigSet(key, value);\n if (!result.ok) throw new Error(result.error || `Failed to set ${key}`);\n }\n\n // Step 5: Run verification\n console.log(\"\\n✓ Configuration complete!\\n\");\n console.log(\"Next steps:\\n\");\n console.log(\" 1. Verify setup: openclaw hybrid-mem verify\");\n console.log(\" 2. Try the demo: openclaw hybrid-mem demo\");\n console.log(\" 3. Store your first fact: openclaw hybrid-mem store 'your text here'\\n\");\n\n // Show onboarding checklist\n console.log(\"📋 Onboarding Checklist:\\n\");\n console.log(\" ✓ Configure embedding provider\");\n console.log(\" ⃞ Run verification (openclaw hybrid-mem verify)\");\n console.log(\" ⃞ Store your first memory\");\n console.log(\" ⃞ Try a semantic search\");\n console.log(\" ⃞ Set up backup automation\\n\");\n\n console.log(\"💡 For more help: openclaw hybrid-mem examples basics\\n\");\n });\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cmd-status.js","names":[],"sources":["../../cli/cmd-status.ts"],"sourcesContent":["import { capturePluginError } from \"../services/error-reporter.js\";\nimport { collectStatus } from \"../routes/dashboard-server.js\";\nimport { getDashboardUrl } from \"./cmd-install.js\";\nimport { type Chainable, withExit } from \"./shared.js\";\n\nexport type StatusContext = {\n factsDb: import(\"../backends/facts-db.js\").FactsDB;\n vectorDb: import(\"../backends/vector-db.js\").VectorDB;\n resolvedSqlitePath: string;\n resolvedLancePath: string;\n pluginId: string;\n cfg: Record<string, unknown>;\n logger?: { info?: (m: string) => void; warn?: (m: string) => void; error?: (m: string) => void };\n costTracker?: import(\"../backends/cost-tracker.js\").CostTracker | null;\n auditStore?: import(\"../backends/audit-store.js\").AuditStore | null;\n agentHealthStore?: import(\"../backends/agent-health-store.js\").AgentHealthStore | null;\n};\n\nexport async function runStatusForCli(ctx: StatusContext, opts?: { format?: \"text\" | \"json\" }): Promise<void> {\n const status = await collectStatus({\n factsDb: ctx.factsDb,\n vectorDb: ctx.vectorDb,\n resolvedSqlitePath: ctx.resolvedSqlitePath,\n resolvedLancePath: ctx.resolvedLancePath,\n costTracker: ctx.costTracker ?? null,\n auditStore: ctx.auditStore ?? null,\n agentHealthStore: ctx.agentHealthStore ?? null,\n logger: ctx.logger,\n });\n const dashboardUrl = getDashboardUrl({\n plugins: {\n entries: {\n [ctx.pluginId]: {\n config: ctx.cfg,\n },\n },\n },\n });\n\n if (opts?.format === \"json\") {\n console.log(JSON.stringify({ dashboardUrl, status }, null, 2));\n return;\n }\n\n const needsAttention = status.cronJobs.filter(\n (job) => job.enabled && (job.consecutiveErrors > 0 || job.lastRunAt == null),\n );\n const auditFailureCount = status.audit.recentFailures.length;\n const agentAlerts = status.agentHealth.alerts.length;\n const activeTask = status.taskQueue.current;\n\n console.log(\"Hybrid Memory status\");\n console.log(`Dashboard: ${dashboardUrl}`);\n console.log(\"\");\n console.log(\"Memory\");\n console.log(` Active facts: ${status.memory.activeFacts.toLocaleString()}`);\n console.log(` Expired facts: ${status.memory.expiredFacts.toLocaleString()}`);\n console.log(` Vectors: ${status.memory.vectorCount.toLocaleString()}`);\n console.log(` Total size: ${status.memory.totalSizeBytes.toLocaleString()} bytes`);\n console.log(\"\");\n console.log(\"Health home\");\n console.log(` Cron jobs: ${status.cronJobs.length} total, ${needsAttention.length} needing attention`);\n console.log(` Audit failures (24h): ${auditFailureCount}`);\n console.log(` Agent alerts: ${agentAlerts}`);\n console.log(` Current task: ${activeTask?.title ?? activeTask?.details ?? \"none\"}`);\n console.log(\"\");\n console.log(\"What to do next\");\n if (needsAttention.length > 0) {\n console.log(` - Run \\`openclaw hybrid-mem verify\\`: ${needsAttention[0].name} still needs attention.`);\n }\n if (auditFailureCount > 0) {\n console.log(\" - Open Mission Control to inspect the audit timeline.\");\n }\n if (agentAlerts > 0) {\n console.log(\" - Open Mission Control to inspect stale or degraded agents.\");\n }\n if (needsAttention.length === 0 && auditFailureCount === 0 && agentAlerts === 0) {\n console.log(\" - Everything looks healthy. Open Mission Control for deeper inspection.\");\n }\n}\n\nexport function registerStatusCommands(mem: Chainable, ctx: StatusContext): void {\n const command = mem.command(\"status\").description(\"Unified health home: memory, jobs, audit, and dashboard link\");\n if (command.alias) command.alias(\"home\");\n command.option(\"--json\", \"Output the full status payload as JSON\").action(\n withExit(async (opts?: { json?: boolean }) => {\n try {\n await runStatusForCli(ctx, { format: opts?.json ? \"json\" : \"text\" });\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"cli\",\n operation: \"status\",\n });\n throw err;\n }\n }),\n );\n\n const dashboard = mem.command(\"dashboard\").description(\"Print the Mission Control dashboard URL\");\n if (dashboard.alias) dashboard.alias(\"mission-control\");\n dashboard.action(\n withExit(async () => {\n const url = getDashboardUrl({\n plugins: { entries: { [ctx.pluginId]: { config: ctx.cfg } } },\n });\n console.log(`Mission Control: ${url}`);\n console.log(\"The dashboard is served by the plugin when the OpenClaw gateway is running.\");\n console.log(\"Tip: run `openclaw hybrid-mem status` for a quick health summary.\");\n }),\n );\n}\n"],"mappings":";;;;;;;AAkBA,eAAsB,gBAAgB,KAAoB,MAAoD;CAC5G,MAAM,SAAS,MAAM,cAAc;EACjC,SAAS,IAAI;EACb,UAAU,IAAI;EACd,oBAAoB,IAAI;EACxB,mBAAmB,IAAI;EACvB,aAAa,IAAI,eAAe;EAChC,YAAY,IAAI,cAAc;EAC9B,kBAAkB,IAAI,oBAAoB;EAC1C,QAAQ,IAAI;
|
|
1
|
+
{"version":3,"file":"cmd-status.js","names":[],"sources":["../../cli/cmd-status.ts"],"sourcesContent":["import { capturePluginError } from \"../services/error-reporter.js\";\nimport { collectStatus } from \"../routes/dashboard-server.js\";\nimport { getDashboardUrl } from \"./cmd-install.js\";\nimport { type Chainable, withExit } from \"./shared.js\";\n\nexport type StatusContext = {\n factsDb: import(\"../backends/facts-db.js\").FactsDB;\n vectorDb: import(\"../backends/vector-db.js\").VectorDB;\n resolvedSqlitePath: string;\n resolvedLancePath: string;\n pluginId: string;\n cfg: Record<string, unknown>;\n logger?: { info?: (m: string) => void; warn?: (m: string) => void; error?: (m: string) => void };\n costTracker?: import(\"../backends/cost-tracker.js\").CostTracker | null;\n auditStore?: import(\"../backends/audit-store.js\").AuditStore | null;\n agentHealthStore?: import(\"../backends/agent-health-store.js\").AgentHealthStore | null;\n};\n\nexport async function runStatusForCli(ctx: StatusContext, opts?: { format?: \"text\" | \"json\" }): Promise<void> {\n const status = await collectStatus({\n factsDb: ctx.factsDb,\n vectorDb: ctx.vectorDb,\n resolvedSqlitePath: ctx.resolvedSqlitePath,\n resolvedLancePath: ctx.resolvedLancePath,\n costTracker: ctx.costTracker ?? null,\n auditStore: ctx.auditStore ?? null,\n agentHealthStore: ctx.agentHealthStore ?? null,\n logger: ctx.logger,\n });\n const dashboardUrl = getDashboardUrl({\n plugins: {\n entries: {\n [ctx.pluginId]: {\n config: ctx.cfg,\n },\n },\n },\n });\n\n if (opts?.format === \"json\") {\n console.log(JSON.stringify({ dashboardUrl, status }, null, 2));\n return;\n }\n\n const needsAttention = status.cronJobs.filter(\n (job) => job.enabled && (job.consecutiveErrors > 0 || job.lastRunAt == null),\n );\n const auditFailureCount = status.audit.recentFailures.length;\n const agentAlerts = status.agentHealth.alerts.length;\n const activeTask = status.taskQueue.current;\n\n console.log(\"Hybrid Memory status\");\n console.log(`Dashboard: ${dashboardUrl}`);\n console.log(\"\");\n console.log(\"Memory\");\n console.log(` Active facts: ${status.memory.activeFacts.toLocaleString()}`);\n console.log(` Expired facts: ${status.memory.expiredFacts.toLocaleString()}`);\n console.log(` Vectors: ${status.memory.vectorCount.toLocaleString()}`);\n console.log(` Total size: ${status.memory.totalSizeBytes.toLocaleString()} bytes`);\n console.log(\"\");\n console.log(\"Health home\");\n console.log(` Cron jobs: ${status.cronJobs.length} total, ${needsAttention.length} needing attention`);\n console.log(` Audit failures (24h): ${auditFailureCount}`);\n console.log(` Agent alerts: ${agentAlerts}`);\n console.log(` Current task: ${activeTask?.title ?? activeTask?.details ?? \"none\"}`);\n console.log(\"\");\n console.log(\"What to do next\");\n if (needsAttention.length > 0) {\n console.log(` - Run \\`openclaw hybrid-mem verify\\`: ${needsAttention[0].name} still needs attention.`);\n }\n if (auditFailureCount > 0) {\n console.log(\" - Open Mission Control to inspect the audit timeline.\");\n }\n if (agentAlerts > 0) {\n console.log(\" - Open Mission Control to inspect stale or degraded agents.\");\n }\n if (needsAttention.length === 0 && auditFailureCount === 0 && agentAlerts === 0) {\n console.log(\" - Everything looks healthy. Open Mission Control for deeper inspection.\");\n }\n}\n\nexport function registerStatusCommands(mem: Chainable, ctx: StatusContext): void {\n const command = mem.command(\"status\").description(\"Unified health home: memory, jobs, audit, and dashboard link\");\n if (command.alias) command.alias(\"home\");\n command.option(\"--json\", \"Output the full status payload as JSON\").action(\n withExit(async (opts?: { json?: boolean }) => {\n try {\n await runStatusForCli(ctx, { format: opts?.json ? \"json\" : \"text\" });\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"cli\",\n operation: \"status\",\n });\n throw err;\n }\n }),\n );\n\n const dashboard = mem.command(\"dashboard\").description(\"Print the Mission Control dashboard URL\");\n if (dashboard.alias) dashboard.alias(\"mission-control\");\n dashboard.action(\n withExit(async () => {\n const url = getDashboardUrl({\n plugins: { entries: { [ctx.pluginId]: { config: ctx.cfg } } },\n });\n console.log(`Mission Control: ${url}`);\n console.log(\"The dashboard is served by the plugin when the OpenClaw gateway is running.\");\n console.log(\"Tip: run `openclaw hybrid-mem status` for a quick health summary.\");\n }),\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cmd-store.js","names":[],"sources":["../../cli/cmd-store.ts"],"sourcesContent":["/**\n * CLI Store Command Handlers\n *\n * Contains inferTargetFile and runStoreForCli — the core memory-store\n * CLI implementation extracted from handlers.ts.\n */\n\nimport type { MemoryCategory } from \"../config.js\";\nimport { getCronModelConfig, getDefaultCronModel } from \"../config.js\";\nimport { isCredentialLike, tryParseCredentialForVault, VAULT_POINTER_PREFIX } from \"../services/auto-capture.js\";\nimport { classifyMemoryOperation } from \"../services/classification.js\";\nimport { validateScopedClassificationTarget } from \"../services/classification-scope.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { extractStructuredFields } from \"../services/fact-extraction.js\";\nimport { cleanupEvictedVector, deleteVectorForFactId } from \"../services/vector-maintenance.js\";\nimport { findSimilarByEmbedding } from \"../services/vector-search.js\";\nimport { CLI_STORE_IMPORTANCE } from \"../utils/constants.js\";\nimport { parseSourceDate } from \"../utils/dates.js\";\nimport { persistCanonicalFactEmbedding } from \"../utils/fact-embeddings.js\";\nimport { extractTags } from \"../utils/tags.js\";\nimport type { HandlerContext } from \"./handlers.js\";\nimport type { StoreCliOpts, StoreCliResult } from \"./types.js\";\n\n/**\n * Infer which identity file a rule or suggestion should target (#260).\n */\nexport function inferTargetFile(content: string): string {\n const lower = content.toLowerCase();\n if (/\\b(identity|creature|persona)\\b/.test(lower)) return \"IDENTITY.md\";\n if (/\\b(my (name|role)|agent (name|role|identity)|who (i am|you are))\\b/.test(lower)) return \"IDENTITY.md\";\n if (/\\b(preference|style|workflow|working|setup|tooling)\\b/.test(lower)) return \"USER.md\";\n return \"SOUL.md\";\n}\n\n/**\n * Store a memory via CLI\n */\nexport async function runStoreForCli(\n ctx: HandlerContext,\n opts: StoreCliOpts,\n log: { warn: (m: string) => void },\n): Promise<StoreCliResult> {\n const { factsDb, vectorDb, embeddings, openai, cfg, credentialsDb, aliasDb } = ctx;\n const text = opts.text;\n const sourceDate = opts.sourceDate ? parseSourceDate(opts.sourceDate) : null;\n const extracted = extractStructuredFields(text, (opts.category ?? \"other\") as MemoryCategory);\n const entity = opts.entity ?? extracted.entity ?? null;\n const key = opts.key ?? extracted.key ?? null;\n const value = opts.value ?? extracted.value ?? null;\n if (isCredentialLike(text, entity, key, value)) {\n if (cfg.credentials.enabled && credentialsDb) {\n const parsed = tryParseCredentialForVault(text, entity, key, value, {\n requirePatternMatch: cfg.credentials.autoCapture?.requirePatternMatch === true,\n });\n if (parsed) {\n // Step 1: Write to vault (use storeIfNew to avoid overwriting user-managed credentials)\n try {\n const stored = credentialsDb.storeIfNew({\n service: parsed.service,\n type: parsed.type,\n value: parsed.secretValue,\n url: parsed.url,\n notes: parsed.notes,\n });\n if (!stored) {\n return { outcome: \"credential_skipped_duplicate\", service: parsed.service, type: parsed.type };\n }\n } catch (err) {\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runStoreForCli:credential-vault-store\" });\n return { outcome: \"credential_vault_error\" };\n }\n\n // Step 2: Write pointer to factsDb\n let pointerEntry: any;\n try {\n const pointerText = `Credential for ${parsed.service} (${parsed.type}) — stored in secure vault. Use credential_get(service=\"${parsed.service}\", type=\"${parsed.type}\") to retrieve.`;\n const pointerValue = `${VAULT_POINTER_PREFIX}${parsed.service}:${parsed.type}`;\n const storeResult = factsDb.storeWithResult({\n text: pointerText,\n category: \"technical\" as MemoryCategory,\n importance: CLI_STORE_IMPORTANCE,\n entity: \"Credentials\",\n key: parsed.service,\n value: pointerValue,\n source: \"cli\",\n sourceDate,\n tags: [\"auth\", ...extractTags(pointerText, \"Credentials\")],\n });\n pointerEntry = storeResult.entry;\n // CRITICAL FIX (#2): Delete vector for evicted fact to prevent orphaned vectors\n await cleanupEvictedVector({\n vectorDb: vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: log,\n context: \"cli-store\",\n });\n try {\n const vector = await embeddings.embed(pointerText);\n factsDb.setEmbeddingModel(pointerEntry.id, embeddings.modelName);\n if (!(await vectorDb.hasDuplicate(vector))) {\n await vectorDb.store({\n text: pointerText,\n vector,\n importance: CLI_STORE_IMPORTANCE,\n category: \"technical\",\n id: pointerEntry.id,\n });\n }\n persistCanonicalFactEmbedding(\n factsDb,\n pointerEntry.id,\n embeddings.modelName,\n vector,\n \"runStoreForCli:pointer-fact-embeddings\",\n \"cli\",\n log.warn,\n );\n } catch (err) {\n log.warn(`memory-hybrid: vector store failed: ${err}`);\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runStoreForCli:vector-store\" });\n }\n } catch (err) {\n // Compensating delete: vault write succeeded but pointer write failed\n try {\n credentialsDb.delete(parsed.service, parsed.type);\n } catch (cleanupErr) {\n log.warn(`memory-hybrid: Failed to clean up orphaned credential for ${parsed.service}: ${cleanupErr}`);\n capturePluginError(cleanupErr as Error, {\n subsystem: \"cli\",\n operation: \"runStoreForCli:credential-compensating-delete\",\n });\n }\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runStoreForCli:credential-db-store\" });\n return { outcome: \"credential_db_error\" };\n }\n return { outcome: \"credential\", id: pointerEntry.id, service: parsed.service, type: parsed.type };\n }\n return { outcome: \"credential_parse_error\" };\n }\n return { outcome: \"credential_blocked_no_vault\" };\n }\n\n const tags = opts.tags\n ? opts.tags\n .split(\",\")\n .map((t) => t.trim().toLowerCase())\n .filter(Boolean)\n : undefined;\n const category = (opts.category ?? \"other\") as MemoryCategory;\n const dedupeProfile = cfg.store.sourceProfiles?.cli ?? cfg.store.defaultProfile;\n const cliDuplicatesCanMutateExistingFact =\n dedupeProfile?.onDuplicate === \"merge\" || dedupeProfile?.onDuplicate === \"boost\";\n if (\n !cliDuplicatesCanMutateExistingFact &&\n factsDb.hasDuplicate(text, \"cli\", {\n category,\n entity,\n key,\n value,\n })\n ) {\n return { outcome: \"duplicate\" };\n }\n\n // FR-006: Compute scope early so it's available for classify-before-write UPDATE path\n const scope = opts.scope ?? \"global\";\n const scopeTarget = scope === \"global\" ? null : (opts.scopeTarget?.trim() ?? null);\n\n if (cfg.store.classifyBeforeWrite) {\n let vector: number[] | undefined;\n try {\n vector = await embeddings.embed(text);\n } catch (err) {\n log.warn(`memory-hybrid: CLI store embedding failed: ${err}`);\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runStoreForCli:embed\" });\n }\n if (vector) {\n let similarFacts = await findSimilarByEmbedding(vectorDb, factsDb, vector, 5, 0.3, { scope, scopeTarget });\n if (similarFacts.length === 0) {\n similarFacts = factsDb.findSimilarForClassification(text, entity, key, 5, scope, scopeTarget);\n }\n if (similarFacts.length > 0) {\n try {\n const classification = await classifyMemoryOperation(\n text,\n entity,\n key,\n similarFacts,\n openai,\n cfg.store.classifyModel ?? getDefaultCronModel(getCronModelConfig(cfg), \"nano\"),\n log,\n );\n if (classification.action === \"NOOP\") return { outcome: \"noop\", reason: classification.reason ?? \"\" };\n if (classification.action === \"DELETE\" && classification.targetId) {\n const target = validateScopedClassificationTarget({\n targetId: classification.targetId,\n candidates: similarFacts,\n getById: (id) => factsDb.getById(id),\n scope,\n scopeTarget,\n warn: (message) => log.warn(message),\n warnMessage: `memory-hybrid: blocked cross-scope or unknown classification DELETE target ${classification.targetId}`,\n });\n if (target) {\n factsDb.supersede(classification.targetId, null);\n aliasDb?.deleteByFactId(classification.targetId);\n await deleteVectorForFactId({\n vectorDb: vectorDb,\n factId: classification.targetId,\n logger: log,\n context: \"cli-store-delete-action\",\n });\n return { outcome: \"retracted\", targetId: classification.targetId, reason: classification.reason ?? \"\" };\n }\n return {\n outcome: \"noop\",\n reason: `blocked delete target ${classification.targetId} due to scope/candidate validation`,\n };\n }\n if (classification.action === \"UPDATE\" && classification.targetId) {\n const oldFact = validateScopedClassificationTarget({\n targetId: classification.targetId,\n candidates: similarFacts,\n getById: (id) => factsDb.getById(id),\n scope,\n scopeTarget,\n warn: (message) => log.warn(message),\n warnMessage: `memory-hybrid: blocked cross-scope classification UPDATE target ${classification.targetId}`,\n });\n if (oldFact) {\n const nowSec = Math.floor(Date.now() / 1000);\n const storeResult = factsDb.storeWithResult({\n text,\n category,\n importance: CLI_STORE_IMPORTANCE,\n entity: entity ?? oldFact.entity,\n key: opts.key ?? extracted.key ?? oldFact.key ?? null,\n value: opts.value ?? extracted.value ?? oldFact.value ?? null,\n source: \"cli\",\n sourceDate,\n tags: tags ?? extractTags(text, entity),\n validFrom: sourceDate ?? nowSec,\n supersedesId: classification.targetId,\n scope,\n scopeTarget,\n });\n if (storeResult.skipped) {\n return { outcome: \"noop\", reason: \"artifact text rejected by pre-store guard\" };\n }\n const newEntry = storeResult.entry;\n // CRITICAL FIX (#2): Delete vector for evicted fact to prevent orphaned vectors\n await cleanupEvictedVector({\n vectorDb: vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: log,\n context: \"cli-store\",\n });\n factsDb.supersede(classification.targetId, newEntry.id);\n aliasDb?.deleteByFactId(classification.targetId);\n await deleteVectorForFactId({\n vectorDb: vectorDb,\n factId: classification.targetId,\n logger: log,\n context: \"cli-store-update-superseded\",\n });\n try {\n if (storeResult.embeddingStale) {\n const mergedVector = await embeddings.embed(newEntry.text);\n factsDb.setEmbeddingModel(newEntry.id, embeddings.modelName);\n await vectorDb.store({\n text: newEntry.text,\n vector: mergedVector,\n importance: CLI_STORE_IMPORTANCE,\n category,\n id: newEntry.id,\n });\n persistCanonicalFactEmbedding(\n factsDb,\n newEntry.id,\n embeddings.modelName,\n mergedVector,\n \"runStoreForCli:update-fact-embeddings\",\n \"cli\",\n log.warn,\n );\n } else {\n const canonicalText = newEntry.text;\n const canonicalVector = canonicalText === text ? vector : await embeddings.embed(canonicalText);\n factsDb.setEmbeddingModel(newEntry.id, embeddings.modelName);\n if (!(await vectorDb.hasDuplicate(canonicalVector))) {\n await vectorDb.store({\n text: canonicalText,\n vector: canonicalVector,\n importance: CLI_STORE_IMPORTANCE,\n category,\n id: newEntry.id,\n });\n }\n persistCanonicalFactEmbedding(\n factsDb,\n newEntry.id,\n embeddings.modelName,\n canonicalVector,\n \"runStoreForCli:update-fact-embeddings\",\n \"cli\",\n log.warn,\n );\n }\n } catch (err) {\n log.warn(\n storeResult.embeddingStale\n ? `memory-hybrid: stale vector re-embed failed for merged fact ${newEntry.id.slice(0, 8)} — nightly re-index will repair: ${err}`\n : `memory-hybrid: vector store failed: ${err}`,\n );\n capturePluginError(err as Error, {\n subsystem: \"cli\",\n operation: storeResult.embeddingStale\n ? \"runStoreForCli:vector-store-update-stale\"\n : \"runStoreForCli:vector-store-update\",\n });\n }\n return {\n outcome: \"updated\",\n id: newEntry.id,\n supersededId: classification.targetId,\n reason: classification.reason ?? \"\",\n };\n }\n return {\n outcome: \"noop\",\n reason: `blocked update target ${classification.targetId} due to scope/candidate validation`,\n };\n }\n } catch (err) {\n log.warn(`memory-hybrid: CLI store classification failed: ${err}`);\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runStoreForCli:classify\" });\n }\n }\n }\n }\n\n // FR-006: scope already computed above\n const supersedesId = opts.supersedes?.trim();\n const nowSec = supersedesId ? Math.floor(Date.now() / 1000) : undefined;\n try {\n const storeResult = factsDb.storeWithResult({\n text,\n category,\n importance: CLI_STORE_IMPORTANCE,\n entity,\n key: opts.key ?? extracted.key ?? null,\n value: opts.value ?? extracted.value ?? null,\n source: \"cli\",\n sourceDate,\n tags: tags ?? extractTags(text, entity),\n scope,\n scopeTarget,\n ...(supersedesId ? { validFrom: nowSec, supersedesId } : {}),\n });\n if (storeResult.skipped) {\n return { outcome: \"noop\", reason: \"artifact text rejected by pre-store guard\" };\n }\n const entry = storeResult.entry;\n // CRITICAL FIX (#2): Delete vector for evicted fact to prevent orphaned vectors\n await cleanupEvictedVector({\n vectorDb: vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: log,\n context: \"cli-store\",\n });\n if (supersedesId) {\n factsDb.supersede(supersedesId, entry.id);\n aliasDb?.deleteByFactId(supersedesId);\n }\n try {\n if (storeResult.embeddingStale) {\n // Merge case: the existing fact's text was updated in-place.\n // Re-embed the merged text and force-replace the stale LanceDB vector.\n // If embed fails, the vector encodes stale pre-merge text; nightly re-index will repair.\n const mergedVector = await embeddings.embed(entry.text);\n factsDb.setEmbeddingModel(entry.id, embeddings.modelName);\n await vectorDb.store({\n text: entry.text,\n vector: mergedVector,\n importance: CLI_STORE_IMPORTANCE,\n category: opts.category ?? \"other\",\n id: entry.id,\n });\n persistCanonicalFactEmbedding(\n factsDb,\n entry.id,\n embeddings.modelName,\n mergedVector,\n \"runStoreForCli:final-fact-embeddings\",\n \"cli\",\n log.warn,\n );\n } else {\n const canonicalText = entry.text;\n const vector = await embeddings.embed(text);\n const canonicalVector = canonicalText === text ? vector : await embeddings.embed(canonicalText);\n factsDb.setEmbeddingModel(entry.id, embeddings.modelName);\n if (!(await vectorDb.hasDuplicate(canonicalVector))) {\n await vectorDb.store({\n text: canonicalText,\n vector: canonicalVector,\n importance: CLI_STORE_IMPORTANCE,\n category: opts.category ?? \"other\",\n id: entry.id,\n });\n }\n persistCanonicalFactEmbedding(\n factsDb,\n entry.id,\n embeddings.modelName,\n canonicalVector,\n \"runStoreForCli:final-fact-embeddings\",\n \"cli\",\n log.warn,\n );\n }\n } catch (err) {\n log.warn(\n storeResult.embeddingStale\n ? `memory-hybrid: stale vector re-embed failed for merged fact ${entry.id.slice(0, 8)} — nightly re-index will repair: ${err}`\n : `memory-hybrid: vector store failed: ${err}`,\n );\n capturePluginError(err as Error, {\n subsystem: \"cli\",\n operation: storeResult.embeddingStale\n ? \"runStoreForCli:vector-store-final-stale\"\n : \"runStoreForCli:vector-store-final\",\n });\n }\n return {\n outcome: \"stored\",\n id: entry.id,\n textPreview: text.slice(0, 80) + (text.length > 80 ? \"...\" : \"\"),\n ...(supersedesId ? { supersededId: supersedesId } : {}),\n };\n } catch (err) {\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runStoreForCli:store\" });\n throw err;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cmd-store.js","names":[],"sources":["../../cli/cmd-store.ts"],"sourcesContent":["/**\n * CLI Store Command Handlers\n *\n * Contains inferTargetFile and runStoreForCli — the core memory-store\n * CLI implementation extracted from handlers.ts.\n */\n\nimport type { MemoryCategory } from \"../config.js\";\nimport { getCronModelConfig, getDefaultCronModel } from \"../config.js\";\nimport { isCredentialLike, tryParseCredentialForVault, VAULT_POINTER_PREFIX } from \"../services/auto-capture.js\";\nimport { classifyMemoryOperation } from \"../services/classification.js\";\nimport { validateScopedClassificationTarget } from \"../services/classification-scope.js\";\nimport { capturePluginError } from \"../services/error-reporter.js\";\nimport { extractStructuredFields } from \"../services/fact-extraction.js\";\nimport { cleanupEvictedVector, deleteVectorForFactId } from \"../services/vector-maintenance.js\";\nimport { findSimilarByEmbedding } from \"../services/vector-search.js\";\nimport { CLI_STORE_IMPORTANCE } from \"../utils/constants.js\";\nimport { parseSourceDate } from \"../utils/dates.js\";\nimport { persistCanonicalFactEmbedding } from \"../utils/fact-embeddings.js\";\nimport { extractTags } from \"../utils/tags.js\";\nimport type { HandlerContext } from \"./handlers.js\";\nimport type { StoreCliOpts, StoreCliResult } from \"./types.js\";\n\n/**\n * Infer which identity file a rule or suggestion should target (#260).\n */\nexport function inferTargetFile(content: string): string {\n const lower = content.toLowerCase();\n if (/\\b(identity|creature|persona)\\b/.test(lower)) return \"IDENTITY.md\";\n if (/\\b(my (name|role)|agent (name|role|identity)|who (i am|you are))\\b/.test(lower)) return \"IDENTITY.md\";\n if (/\\b(preference|style|workflow|working|setup|tooling)\\b/.test(lower)) return \"USER.md\";\n return \"SOUL.md\";\n}\n\n/**\n * Store a memory via CLI\n */\nexport async function runStoreForCli(\n ctx: HandlerContext,\n opts: StoreCliOpts,\n log: { warn: (m: string) => void },\n): Promise<StoreCliResult> {\n const { factsDb, vectorDb, embeddings, openai, cfg, credentialsDb, aliasDb } = ctx;\n const text = opts.text;\n const sourceDate = opts.sourceDate ? parseSourceDate(opts.sourceDate) : null;\n const extracted = extractStructuredFields(text, (opts.category ?? \"other\") as MemoryCategory);\n const entity = opts.entity ?? extracted.entity ?? null;\n const key = opts.key ?? extracted.key ?? null;\n const value = opts.value ?? extracted.value ?? null;\n if (isCredentialLike(text, entity, key, value)) {\n if (cfg.credentials.enabled && credentialsDb) {\n const parsed = tryParseCredentialForVault(text, entity, key, value, {\n requirePatternMatch: cfg.credentials.autoCapture?.requirePatternMatch === true,\n });\n if (parsed) {\n // Step 1: Write to vault (use storeIfNew to avoid overwriting user-managed credentials)\n try {\n const stored = credentialsDb.storeIfNew({\n service: parsed.service,\n type: parsed.type,\n value: parsed.secretValue,\n url: parsed.url,\n notes: parsed.notes,\n });\n if (!stored) {\n return { outcome: \"credential_skipped_duplicate\", service: parsed.service, type: parsed.type };\n }\n } catch (err) {\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runStoreForCli:credential-vault-store\" });\n return { outcome: \"credential_vault_error\" };\n }\n\n // Step 2: Write pointer to factsDb\n let pointerEntry: any;\n try {\n const pointerText = `Credential for ${parsed.service} (${parsed.type}) — stored in secure vault. Use credential_get(service=\"${parsed.service}\", type=\"${parsed.type}\") to retrieve.`;\n const pointerValue = `${VAULT_POINTER_PREFIX}${parsed.service}:${parsed.type}`;\n const storeResult = factsDb.storeWithResult({\n text: pointerText,\n category: \"technical\" as MemoryCategory,\n importance: CLI_STORE_IMPORTANCE,\n entity: \"Credentials\",\n key: parsed.service,\n value: pointerValue,\n source: \"cli\",\n sourceDate,\n tags: [\"auth\", ...extractTags(pointerText, \"Credentials\")],\n });\n pointerEntry = storeResult.entry;\n // CRITICAL FIX (#2): Delete vector for evicted fact to prevent orphaned vectors\n await cleanupEvictedVector({\n vectorDb: vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: log,\n context: \"cli-store\",\n });\n try {\n const vector = await embeddings.embed(pointerText);\n factsDb.setEmbeddingModel(pointerEntry.id, embeddings.modelName);\n if (!(await vectorDb.hasDuplicate(vector))) {\n await vectorDb.store({\n text: pointerText,\n vector,\n importance: CLI_STORE_IMPORTANCE,\n category: \"technical\",\n id: pointerEntry.id,\n });\n }\n persistCanonicalFactEmbedding(\n factsDb,\n pointerEntry.id,\n embeddings.modelName,\n vector,\n \"runStoreForCli:pointer-fact-embeddings\",\n \"cli\",\n log.warn,\n );\n } catch (err) {\n log.warn(`memory-hybrid: vector store failed: ${err}`);\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runStoreForCli:vector-store\" });\n }\n } catch (err) {\n // Compensating delete: vault write succeeded but pointer write failed\n try {\n credentialsDb.delete(parsed.service, parsed.type);\n } catch (cleanupErr) {\n log.warn(`memory-hybrid: Failed to clean up orphaned credential for ${parsed.service}: ${cleanupErr}`);\n capturePluginError(cleanupErr as Error, {\n subsystem: \"cli\",\n operation: \"runStoreForCli:credential-compensating-delete\",\n });\n }\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runStoreForCli:credential-db-store\" });\n return { outcome: \"credential_db_error\" };\n }\n return { outcome: \"credential\", id: pointerEntry.id, service: parsed.service, type: parsed.type };\n }\n return { outcome: \"credential_parse_error\" };\n }\n return { outcome: \"credential_blocked_no_vault\" };\n }\n\n const tags = opts.tags\n ? opts.tags\n .split(\",\")\n .map((t) => t.trim().toLowerCase())\n .filter(Boolean)\n : undefined;\n const category = (opts.category ?? \"other\") as MemoryCategory;\n const dedupeProfile = cfg.store.sourceProfiles?.cli ?? cfg.store.defaultProfile;\n const cliDuplicatesCanMutateExistingFact =\n dedupeProfile?.onDuplicate === \"merge\" || dedupeProfile?.onDuplicate === \"boost\";\n if (\n !cliDuplicatesCanMutateExistingFact &&\n factsDb.hasDuplicate(text, \"cli\", {\n category,\n entity,\n key,\n value,\n })\n ) {\n return { outcome: \"duplicate\" };\n }\n\n // FR-006: Compute scope early so it's available for classify-before-write UPDATE path\n const scope = opts.scope ?? \"global\";\n const scopeTarget = scope === \"global\" ? null : (opts.scopeTarget?.trim() ?? null);\n\n if (cfg.store.classifyBeforeWrite) {\n let vector: number[] | undefined;\n try {\n vector = await embeddings.embed(text);\n } catch (err) {\n log.warn(`memory-hybrid: CLI store embedding failed: ${err}`);\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runStoreForCli:embed\" });\n }\n if (vector) {\n let similarFacts = await findSimilarByEmbedding(vectorDb, factsDb, vector, 5, 0.3, { scope, scopeTarget });\n if (similarFacts.length === 0) {\n similarFacts = factsDb.findSimilarForClassification(text, entity, key, 5, scope, scopeTarget);\n }\n if (similarFacts.length > 0) {\n try {\n const classification = await classifyMemoryOperation(\n text,\n entity,\n key,\n similarFacts,\n openai,\n cfg.store.classifyModel ?? getDefaultCronModel(getCronModelConfig(cfg), \"nano\"),\n log,\n );\n if (classification.action === \"NOOP\") return { outcome: \"noop\", reason: classification.reason ?? \"\" };\n if (classification.action === \"DELETE\" && classification.targetId) {\n const target = validateScopedClassificationTarget({\n targetId: classification.targetId,\n candidates: similarFacts,\n getById: (id) => factsDb.getById(id),\n scope,\n scopeTarget,\n warn: (message) => log.warn(message),\n warnMessage: `memory-hybrid: blocked cross-scope or unknown classification DELETE target ${classification.targetId}`,\n });\n if (target) {\n factsDb.supersede(classification.targetId, null);\n aliasDb?.deleteByFactId(classification.targetId);\n await deleteVectorForFactId({\n vectorDb: vectorDb,\n factId: classification.targetId,\n logger: log,\n context: \"cli-store-delete-action\",\n });\n return { outcome: \"retracted\", targetId: classification.targetId, reason: classification.reason ?? \"\" };\n }\n return {\n outcome: \"noop\",\n reason: `blocked delete target ${classification.targetId} due to scope/candidate validation`,\n };\n }\n if (classification.action === \"UPDATE\" && classification.targetId) {\n const oldFact = validateScopedClassificationTarget({\n targetId: classification.targetId,\n candidates: similarFacts,\n getById: (id) => factsDb.getById(id),\n scope,\n scopeTarget,\n warn: (message) => log.warn(message),\n warnMessage: `memory-hybrid: blocked cross-scope classification UPDATE target ${classification.targetId}`,\n });\n if (oldFact) {\n const nowSec = Math.floor(Date.now() / 1000);\n const storeResult = factsDb.storeWithResult({\n text,\n category,\n importance: CLI_STORE_IMPORTANCE,\n entity: entity ?? oldFact.entity,\n key: opts.key ?? extracted.key ?? oldFact.key ?? null,\n value: opts.value ?? extracted.value ?? oldFact.value ?? null,\n source: \"cli\",\n sourceDate,\n tags: tags ?? extractTags(text, entity),\n validFrom: sourceDate ?? nowSec,\n supersedesId: classification.targetId,\n scope,\n scopeTarget,\n });\n if (storeResult.skipped) {\n return { outcome: \"noop\", reason: \"artifact text rejected by pre-store guard\" };\n }\n const newEntry = storeResult.entry;\n // CRITICAL FIX (#2): Delete vector for evicted fact to prevent orphaned vectors\n await cleanupEvictedVector({\n vectorDb: vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: log,\n context: \"cli-store\",\n });\n factsDb.supersede(classification.targetId, newEntry.id);\n aliasDb?.deleteByFactId(classification.targetId);\n await deleteVectorForFactId({\n vectorDb: vectorDb,\n factId: classification.targetId,\n logger: log,\n context: \"cli-store-update-superseded\",\n });\n try {\n if (storeResult.embeddingStale) {\n const mergedVector = await embeddings.embed(newEntry.text);\n factsDb.setEmbeddingModel(newEntry.id, embeddings.modelName);\n await vectorDb.store({\n text: newEntry.text,\n vector: mergedVector,\n importance: CLI_STORE_IMPORTANCE,\n category,\n id: newEntry.id,\n });\n persistCanonicalFactEmbedding(\n factsDb,\n newEntry.id,\n embeddings.modelName,\n mergedVector,\n \"runStoreForCli:update-fact-embeddings\",\n \"cli\",\n log.warn,\n );\n } else {\n const canonicalText = newEntry.text;\n const canonicalVector = canonicalText === text ? vector : await embeddings.embed(canonicalText);\n factsDb.setEmbeddingModel(newEntry.id, embeddings.modelName);\n if (!(await vectorDb.hasDuplicate(canonicalVector))) {\n await vectorDb.store({\n text: canonicalText,\n vector: canonicalVector,\n importance: CLI_STORE_IMPORTANCE,\n category,\n id: newEntry.id,\n });\n }\n persistCanonicalFactEmbedding(\n factsDb,\n newEntry.id,\n embeddings.modelName,\n canonicalVector,\n \"runStoreForCli:update-fact-embeddings\",\n \"cli\",\n log.warn,\n );\n }\n } catch (err) {\n log.warn(\n storeResult.embeddingStale\n ? `memory-hybrid: stale vector re-embed failed for merged fact ${newEntry.id.slice(0, 8)} — nightly re-index will repair: ${err}`\n : `memory-hybrid: vector store failed: ${err}`,\n );\n capturePluginError(err as Error, {\n subsystem: \"cli\",\n operation: storeResult.embeddingStale\n ? \"runStoreForCli:vector-store-update-stale\"\n : \"runStoreForCli:vector-store-update\",\n });\n }\n return {\n outcome: \"updated\",\n id: newEntry.id,\n supersededId: classification.targetId,\n reason: classification.reason ?? \"\",\n };\n }\n return {\n outcome: \"noop\",\n reason: `blocked update target ${classification.targetId} due to scope/candidate validation`,\n };\n }\n } catch (err) {\n log.warn(`memory-hybrid: CLI store classification failed: ${err}`);\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runStoreForCli:classify\" });\n }\n }\n }\n }\n\n // FR-006: scope already computed above\n const supersedesId = opts.supersedes?.trim();\n const nowSec = supersedesId ? Math.floor(Date.now() / 1000) : undefined;\n try {\n const storeResult = factsDb.storeWithResult({\n text,\n category,\n importance: CLI_STORE_IMPORTANCE,\n entity,\n key: opts.key ?? extracted.key ?? null,\n value: opts.value ?? extracted.value ?? null,\n source: \"cli\",\n sourceDate,\n tags: tags ?? extractTags(text, entity),\n scope,\n scopeTarget,\n ...(supersedesId ? { validFrom: nowSec, supersedesId } : {}),\n });\n if (storeResult.skipped) {\n return { outcome: \"noop\", reason: \"artifact text rejected by pre-store guard\" };\n }\n const entry = storeResult.entry;\n // CRITICAL FIX (#2): Delete vector for evicted fact to prevent orphaned vectors\n await cleanupEvictedVector({\n vectorDb: vectorDb,\n evictedFactId: storeResult.evictedFactId,\n logger: log,\n context: \"cli-store\",\n });\n if (supersedesId) {\n factsDb.supersede(supersedesId, entry.id);\n aliasDb?.deleteByFactId(supersedesId);\n }\n try {\n if (storeResult.embeddingStale) {\n // Merge case: the existing fact's text was updated in-place.\n // Re-embed the merged text and force-replace the stale LanceDB vector.\n // If embed fails, the vector encodes stale pre-merge text; nightly re-index will repair.\n const mergedVector = await embeddings.embed(entry.text);\n factsDb.setEmbeddingModel(entry.id, embeddings.modelName);\n await vectorDb.store({\n text: entry.text,\n vector: mergedVector,\n importance: CLI_STORE_IMPORTANCE,\n category: opts.category ?? \"other\",\n id: entry.id,\n });\n persistCanonicalFactEmbedding(\n factsDb,\n entry.id,\n embeddings.modelName,\n mergedVector,\n \"runStoreForCli:final-fact-embeddings\",\n \"cli\",\n log.warn,\n );\n } else {\n const canonicalText = entry.text;\n const vector = await embeddings.embed(text);\n const canonicalVector = canonicalText === text ? vector : await embeddings.embed(canonicalText);\n factsDb.setEmbeddingModel(entry.id, embeddings.modelName);\n if (!(await vectorDb.hasDuplicate(canonicalVector))) {\n await vectorDb.store({\n text: canonicalText,\n vector: canonicalVector,\n importance: CLI_STORE_IMPORTANCE,\n category: opts.category ?? \"other\",\n id: entry.id,\n });\n }\n persistCanonicalFactEmbedding(\n factsDb,\n entry.id,\n embeddings.modelName,\n canonicalVector,\n \"runStoreForCli:final-fact-embeddings\",\n \"cli\",\n log.warn,\n );\n }\n } catch (err) {\n log.warn(\n storeResult.embeddingStale\n ? `memory-hybrid: stale vector re-embed failed for merged fact ${entry.id.slice(0, 8)} — nightly re-index will repair: ${err}`\n : `memory-hybrid: vector store failed: ${err}`,\n );\n capturePluginError(err as Error, {\n subsystem: \"cli\",\n operation: storeResult.embeddingStale\n ? \"runStoreForCli:vector-store-final-stale\"\n : \"runStoreForCli:vector-store-final\",\n });\n }\n return {\n outcome: \"stored\",\n id: entry.id,\n textPreview: text.slice(0, 80) + (text.length > 80 ? \"...\" : \"\"),\n ...(supersedesId ? { supersededId: supersedesId } : {}),\n };\n } catch (err) {\n capturePluginError(err as Error, { subsystem: \"cli\", operation: \"runStoreForCli:store\" });\n throw err;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cmd-user-friendly.js","names":[],"sources":["../../cli/cmd-user-friendly.ts"],"sourcesContent":["/**\n * Register user-friendly commands (setup, demo, providers, health, doctor, examples)\n */\n\nimport type { Chainable } from \"./shared.js\";\nimport type { FactsDB } from \"../backends/facts-db.js\";\nimport type { VectorDB } from \"../backends/vector-db.js\";\nimport type { WriteAheadLog } from \"../backends/wal.js\";\nimport type { HybridMemoryConfig } from \"../config.js\";\nimport type { EmbeddingProvider } from \"../services/embeddings.js\";\nimport { registerDemoCommand } from \"./cmd-demo.js\";\nimport { registerDoctorCommand } from \"./cmd-doctor.js\";\nimport { registerExamplesCommand } from \"./cmd-examples.js\";\nimport { registerHealthCommand } from \"./cmd-health.js\";\nimport { registerProvidersCommand } from \"./cmd-providers.js\";\nimport { registerSetupCommand } from \"./cmd-setup.js\";\n\nexport interface UserFriendlyContext {\n cfg: HybridMemoryConfig;\n factsDb: FactsDB;\n vectorDb: VectorDB;\n wal?: WriteAheadLog | null;\n embeddings: EmbeddingProvider;\n runConfigSet?: (\n key: string,\n value: string,\n ) => { ok: boolean; error?: string } | Promise<{ ok: boolean; error?: string }>;\n}\n\nfunction hasCommand(mem: Chainable, name: string): boolean {\n const maybeCommands = (\n mem as {\n commands?: Array<{\n name?: string | (() => string);\n _name?: string;\n aliases?: () => string[];\n _aliases?: string[];\n }>;\n }\n ).commands;\n return Array.isArray(maybeCommands)\n ? maybeCommands.some((command) => {\n const commandName = typeof command.name === \"function\" ? command.name() : command.name;\n const aliases = typeof command.aliases === \"function\" ? command.aliases() : (command._aliases ?? []);\n return command._name === name || commandName === name || aliases.includes(name);\n })\n : false;\n}\n\nfunction registerIfMissing(mem: Chainable, name: string, register: () => void): void {\n if (hasCommand(mem, name)) return;\n register();\n}\n\nexport function registerUserFriendlyCommands(mem: Chainable, ctx: UserFriendlyContext): void {\n registerIfMissing(mem, \"setup\", () => registerSetupCommand(mem, ctx.cfg, ctx.runConfigSet));\n registerIfMissing(mem, \"providers\", () => registerProvidersCommand(mem, ctx.cfg));\n registerIfMissing(mem, \"doctor\", () =>\n registerDoctorCommand(mem, ctx.cfg, ctx.factsDb, ctx.vectorDb, ctx.wal ?? null),\n );\n registerIfMissing(mem, \"health\", () =>\n registerHealthCommand(mem, ctx.cfg, ctx.factsDb, ctx.vectorDb, ctx.wal ?? null),\n );\n registerIfMissing(mem, \"demo\", () => registerDemoCommand(mem, ctx.factsDb, ctx.vectorDb, ctx.embeddings));\n registerIfMissing(mem, \"examples\", () => registerExamplesCommand(mem));\n}\n"],"mappings":";;;;;;;AA6BA,SAAS,WAAW,KAAgB,MAAuB;CACzD,MAAM,gBACJ,IAQA;CACF,OAAO,MAAM,QAAQ,
|
|
1
|
+
{"version":3,"file":"cmd-user-friendly.js","names":[],"sources":["../../cli/cmd-user-friendly.ts"],"sourcesContent":["/**\n * Register user-friendly commands (setup, demo, providers, health, doctor, examples)\n */\n\nimport type { Chainable } from \"./shared.js\";\nimport type { FactsDB } from \"../backends/facts-db.js\";\nimport type { VectorDB } from \"../backends/vector-db.js\";\nimport type { WriteAheadLog } from \"../backends/wal.js\";\nimport type { HybridMemoryConfig } from \"../config.js\";\nimport type { EmbeddingProvider } from \"../services/embeddings.js\";\nimport { registerDemoCommand } from \"./cmd-demo.js\";\nimport { registerDoctorCommand } from \"./cmd-doctor.js\";\nimport { registerExamplesCommand } from \"./cmd-examples.js\";\nimport { registerHealthCommand } from \"./cmd-health.js\";\nimport { registerProvidersCommand } from \"./cmd-providers.js\";\nimport { registerSetupCommand } from \"./cmd-setup.js\";\n\nexport interface UserFriendlyContext {\n cfg: HybridMemoryConfig;\n factsDb: FactsDB;\n vectorDb: VectorDB;\n wal?: WriteAheadLog | null;\n embeddings: EmbeddingProvider;\n runConfigSet?: (\n key: string,\n value: string,\n ) => { ok: boolean; error?: string } | Promise<{ ok: boolean; error?: string }>;\n}\n\nfunction hasCommand(mem: Chainable, name: string): boolean {\n const maybeCommands = (\n mem as {\n commands?: Array<{\n name?: string | (() => string);\n _name?: string;\n aliases?: () => string[];\n _aliases?: string[];\n }>;\n }\n ).commands;\n return Array.isArray(maybeCommands)\n ? maybeCommands.some((command) => {\n const commandName = typeof command.name === \"function\" ? command.name() : command.name;\n const aliases = typeof command.aliases === \"function\" ? command.aliases() : (command._aliases ?? []);\n return command._name === name || commandName === name || aliases.includes(name);\n })\n : false;\n}\n\nfunction registerIfMissing(mem: Chainable, name: string, register: () => void): void {\n if (hasCommand(mem, name)) return;\n register();\n}\n\nexport function registerUserFriendlyCommands(mem: Chainable, ctx: UserFriendlyContext): void {\n registerIfMissing(mem, \"setup\", () => registerSetupCommand(mem, ctx.cfg, ctx.runConfigSet));\n registerIfMissing(mem, \"providers\", () => registerProvidersCommand(mem, ctx.cfg));\n registerIfMissing(mem, \"doctor\", () =>\n registerDoctorCommand(mem, ctx.cfg, ctx.factsDb, ctx.vectorDb, ctx.wal ?? null),\n );\n registerIfMissing(mem, \"health\", () =>\n registerHealthCommand(mem, ctx.cfg, ctx.factsDb, ctx.vectorDb, ctx.wal ?? null),\n );\n registerIfMissing(mem, \"demo\", () => registerDemoCommand(mem, ctx.factsDb, ctx.vectorDb, ctx.embeddings));\n registerIfMissing(mem, \"examples\", () => registerExamplesCommand(mem));\n}\n"],"mappings":";;;;;;;AA6BA,SAAS,WAAW,KAAgB,MAAuB;CACzD,MAAM,gBACJ,IAQA;CACF,OAAO,MAAM,QAAQ,aAAa,IAC9B,cAAc,MAAM,YAAY;EAC9B,MAAM,cAAc,OAAO,QAAQ,SAAS,aAAa,QAAQ,KAAK,IAAI,QAAQ;EAClF,MAAM,UAAU,OAAO,QAAQ,YAAY,aAAa,QAAQ,QAAQ,IAAK,QAAQ,YAAY,CAAC;EAClG,OAAO,QAAQ,UAAU,QAAQ,gBAAgB,QAAQ,QAAQ,SAAS,IAAI;CAChF,CAAC,IACD;AACN;AAEA,SAAS,kBAAkB,KAAgB,MAAc,UAA4B;CACnF,IAAI,WAAW,KAAK,IAAI,GAAG;CAC3B,SAAS;AACX;AAEA,SAAgB,6BAA6B,KAAgB,KAAgC;CAC3F,kBAAkB,KAAK,eAAe,qBAAqB,KAAK,IAAI,KAAK,IAAI,YAAY,CAAC;CAC1F,kBAAkB,KAAK,mBAAmB,yBAAyB,KAAK,IAAI,GAAG,CAAC;CAChF,kBAAkB,KAAK,gBACrB,sBAAsB,KAAK,IAAI,KAAK,IAAI,SAAS,IAAI,UAAU,IAAI,OAAO,IAAI,CAChF;CACA,kBAAkB,KAAK,gBACrB,sBAAsB,KAAK,IAAI,KAAK,IAAI,SAAS,IAAI,UAAU,IAAI,OAAO,IAAI,CAChF;CACA,kBAAkB,KAAK,cAAc,oBAAoB,KAAK,IAAI,SAAS,IAAI,UAAU,IAAI,UAAU,CAAC;CACxG,kBAAkB,KAAK,kBAAkB,wBAAwB,GAAG,CAAC;AACvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cmd-verify.js","names":[],"sources":["../../cli/cmd-verify.ts"],"sourcesContent":["import { getCachedFactCount, readApproxFactsRowCount, resetVerifyFactCountCacheForTests } from \"./verify/fact-count.js\";\nimport { computeVectorSqliteOrphans } from \"./verify/orphans.js\";\n\nexport { computeVectorSqliteOrphans, getCachedFactCount, readApproxFactsRowCount, resetVerifyFactCountCacheForTests };\nimport { createVerifyRunState, type VerifyRunOpts } from \"./verify/verify-run-state.js\";\nimport { runVerifyInfrastructureSection } from \"./verify/sections/infrastructure.js\";\nimport { runVerifyEmbeddingsSection } from \"./verify/sections/embeddings.js\";\nimport { runVerifyLlmModelsSection } from \"./verify/sections/llm-models.js\";\nimport { runVerifyConfigCronSection } from \"./verify/sections/config-cron.js\";\nimport { runVerifyReconcileSection } from \"./verify/sections/reconcile.js\";\n\nexport async function runVerifyForCli(\n ctx: import(\"./handlers.js\").HandlerContext,\n opts: VerifyRunOpts,\n sink: import(\"./types.js\").VerifyCliSink,\n): Promise<void> {\n const state = createVerifyRunState(ctx, opts, sink);\n await runVerifyInfrastructureSection(state);\n await runVerifyEmbeddingsSection(state);\n await runVerifyLlmModelsSection(state);\n await runVerifyConfigCronSection(state);\n await runVerifyReconcileSection(state);\n}\n"],"mappings":";;;;;;;;AAWA,eAAsB,gBACpB,KACA,MACA,MACe;CACf,MAAM,QAAQ,qBAAqB,KAAK,MAAM,
|
|
1
|
+
{"version":3,"file":"cmd-verify.js","names":[],"sources":["../../cli/cmd-verify.ts"],"sourcesContent":["import { getCachedFactCount, readApproxFactsRowCount, resetVerifyFactCountCacheForTests } from \"./verify/fact-count.js\";\nimport { computeVectorSqliteOrphans } from \"./verify/orphans.js\";\n\nexport { computeVectorSqliteOrphans, getCachedFactCount, readApproxFactsRowCount, resetVerifyFactCountCacheForTests };\nimport { createVerifyRunState, type VerifyRunOpts } from \"./verify/verify-run-state.js\";\nimport { runVerifyInfrastructureSection } from \"./verify/sections/infrastructure.js\";\nimport { runVerifyEmbeddingsSection } from \"./verify/sections/embeddings.js\";\nimport { runVerifyLlmModelsSection } from \"./verify/sections/llm-models.js\";\nimport { runVerifyConfigCronSection } from \"./verify/sections/config-cron.js\";\nimport { runVerifyReconcileSection } from \"./verify/sections/reconcile.js\";\n\nexport async function runVerifyForCli(\n ctx: import(\"./handlers.js\").HandlerContext,\n opts: VerifyRunOpts,\n sink: import(\"./types.js\").VerifyCliSink,\n): Promise<void> {\n const state = createVerifyRunState(ctx, opts, sink);\n await runVerifyInfrastructureSection(state);\n await runVerifyEmbeddingsSection(state);\n await runVerifyLlmModelsSection(state);\n await runVerifyConfigCronSection(state);\n await runVerifyReconcileSection(state);\n}\n"],"mappings":";;;;;;;;AAWA,eAAsB,gBACpB,KACA,MACA,MACe;CACf,MAAM,QAAQ,qBAAqB,KAAK,MAAM,IAAI;CAClD,MAAM,+BAA+B,KAAK;CAC1C,MAAM,2BAA2B,KAAK;CACtC,MAAM,0BAA0B,KAAK;CACrC,MAAM,2BAA2B,KAAK;CACtC,MAAM,0BAA0B,KAAK;AACvC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bindings.js","names":[],"sources":["../../../../cli/commands/manage/bindings.ts"],"sourcesContent":["// biome-ignore lint/style/useImportType: mergeResults kept as value import so typeof mergeResults resolves at the type level without confusion\nimport { mergeResults } from \"../../../services/merge-results.js\";\nimport type { ManageContext } from \"../../context.js\";\n\n/**\n * Shared flattened context for manage command modules (Issue #955).\n * Includes `merge` as an alias for `mergeResults` and `ctx` for sparse `ctx.*` access.\n */\nexport type ManageBindings = ManageContext & {\n ctx: ManageContext;\n merge: typeof mergeResults;\n BACKFILL_DECAY_MARKER: string;\n};\n\nexport function buildManageBindings(ctx: ManageContext): ManageBindings {\n return {\n ...ctx,\n ctx,\n merge: ctx.mergeResults,\n BACKFILL_DECAY_MARKER: \".backfill-decay-done\",\n };\n}\n"],"mappings":";AAcA,SAAgB,oBAAoB,KAAoC;CACtE,OAAO;EACL,GAAG;EACH;EACA,OAAO,IAAI;EACX,uBAAuB;
|
|
1
|
+
{"version":3,"file":"bindings.js","names":[],"sources":["../../../../cli/commands/manage/bindings.ts"],"sourcesContent":["// biome-ignore lint/style/useImportType: mergeResults kept as value import so typeof mergeResults resolves at the type level without confusion\nimport { mergeResults } from \"../../../services/merge-results.js\";\nimport type { ManageContext } from \"../../context.js\";\n\n/**\n * Shared flattened context for manage command modules (Issue #955).\n * Includes `merge` as an alias for `mergeResults` and `ctx` for sparse `ctx.*` access.\n */\nexport type ManageBindings = ManageContext & {\n ctx: ManageContext;\n merge: typeof mergeResults;\n BACKFILL_DECAY_MARKER: string;\n};\n\nexport function buildManageBindings(ctx: ManageContext): ManageBindings {\n return {\n ...ctx,\n ctx,\n merge: ctx.mergeResults,\n BACKFILL_DECAY_MARKER: \".backfill-decay-done\",\n };\n}\n"],"mappings":";AAcA,SAAgB,oBAAoB,KAAoC;CACtE,OAAO;EACL,GAAG;EACH;EACA,OAAO,IAAI;EACX,uBAAuB;CACzB;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dream-cycle-followup.js","names":[],"sources":["../../../../cli/commands/manage/dream-cycle-followup.ts"],"sourcesContent":["/** Dream-cycle follow-up progress formatting and verbose stage runner. */\n\nimport type { ExtractImplicitFeedbackProgressSnapshot } from \"../../cmd-feedback.js\";\nimport type { VerificationCycleResult } from \"../../../services/continuous-verifier.js\";\nimport { runMaintenanceHeartbeat } from \"./maintenance-heartbeat.js\";\n\nexport type FollowUpProgressSupplier = () => string | undefined;\n\nexport interface RunVerboseFollowUpOptions {\n progressSupplier?: FollowUpProgressSupplier;\n heartbeatIntervalMs?: number;\n stageIndex?: number;\n stageTotal?: number;\n}\n\nexport interface ContinuousVerificationAssessment {\n status: \"healthy\" | \"degraded\";\n reason: \"healthy\" | \"errors_present\" | \"all_uncertain\";\n shouldFailPipeline: boolean;\n summary?: string;\n}\n\nexport function formatExtractImplicitFeedbackProgress(\n snapshot: ExtractImplicitFeedbackProgressSnapshot | undefined,\n): string | undefined {\n if (!snapshot) return undefined;\n const parts: string[] = [`stage=${snapshot.stage}`];\n\n if (snapshot.stage === \"scan-sessions\") {\n parts.push(`sessions=${snapshot.sessionsVisited}/${snapshot.sessionsDiscovered}`);\n if (snapshot.sessionsProcessed !== snapshot.sessionsVisited) {\n parts.push(`processed=${snapshot.sessionsProcessed}`);\n }\n const skipped = snapshot.sessionsReadErrors + snapshot.sessionsTooShort;\n if (skipped > 0) parts.push(`skipped=${skipped}`);\n if (snapshot.currentSession) parts.push(`current=${snapshot.currentSession}`);\n parts.push(`signals=${snapshot.signalsExtracted} (${snapshot.positiveCount}+/${snapshot.negativeCount}-)`);\n if (snapshot.trajectoriesBuilt > 0) parts.push(`traj=${snapshot.trajectoriesBuilt}`);\n } else if (snapshot.stage === \"cleanup-duplicates\") {\n parts.push(`collapsed=${snapshot.cleanupCollapsed}`);\n if (snapshot.cleanupScanned > 0) parts.push(`scanned=${snapshot.cleanupScanned}`);\n if (snapshot.cleanupBatches > 0) parts.push(`batches=${snapshot.cleanupBatches}`);\n } else if (snapshot.stage === \"closed-loop\") {\n parts.push(`signals=${snapshot.signalsExtracted} (${snapshot.positiveCount}+/${snapshot.negativeCount}-)`);\n if (snapshot.trajectoriesBuilt > 0) parts.push(`traj=${snapshot.trajectoriesBuilt}`);\n }\n\n if (snapshot.partial) {\n parts.push(`partial=${snapshot.partialReason ?? \"capped\"}`);\n if ((snapshot.sessionsDeferred ?? 0) > 0) parts.push(`deferred=${snapshot.sessionsDeferred}`);\n if ((snapshot.backlogSignalsEstimate ?? 0) > 0 || (snapshot.backlogTrajectoriesEstimate ?? 0) > 0) {\n parts.push(`backlog≈${snapshot.backlogSignalsEstimate ?? 0}s/${snapshot.backlogTrajectoriesEstimate ?? 0}t`);\n }\n }\n\n return parts.join(\"; \");\n}\n\nexport function assessContinuousVerificationResult(result: VerificationCycleResult): ContinuousVerificationAssessment {\n if (result.errors > 0) {\n const summary =\n result.checked === 0\n ? `infrastructure error prevented verification (${result.errors} error(s))`\n : `${result.errors}/${result.checked} verification check(s) errored`;\n return {\n status: \"degraded\",\n reason: \"errors_present\",\n shouldFailPipeline: true,\n summary,\n };\n }\n if (result.checked > 0 && result.confirmed === 0 && result.stale === 0) {\n return {\n status: \"degraded\",\n reason: \"all_uncertain\",\n shouldFailPipeline: true,\n summary: `all ${result.checked} verification check(s) were uncertain`,\n };\n }\n return { status: \"healthy\", reason: \"healthy\", shouldFailPipeline: false };\n}\n\nexport function formatContinuousVerificationAssessmentLine(\n result: VerificationCycleResult,\n assessment: ContinuousVerificationAssessment,\n): string {\n return [\n `status=${assessment.status}`,\n `reason=${assessment.reason}`,\n `checked=${result.checked}`,\n `confirmed=${result.confirmed}`,\n `stale=${result.stale}`,\n `uncertain=${result.uncertain}`,\n `errors=${result.errors}`,\n ].join(\" \");\n}\n\nexport async function runVerboseFollowUp<T>(\n label: string,\n verbose: boolean,\n fn: () => Promise<T> | T,\n opts: RunVerboseFollowUpOptions = {},\n): Promise<T> {\n const stagePrefix =\n opts.stageIndex && opts.stageTotal && opts.stageTotal > 0 ? `stage ${opts.stageIndex}/${opts.stageTotal} ` : \"\";\n const stageLabel = `${stagePrefix}${label}`.trim();\n return runMaintenanceHeartbeat(stageLabel, verbose, fn, {\n progressSupplier: opts.progressSupplier,\n heartbeatIntervalMs: opts.heartbeatIntervalMs,\n jsonMode: false,\n logPrefix: \"[dream-cycle]\",\n progressSeparator: \" — \",\n });\n}\n"],"mappings":";;AAsBA,SAAgB,sCACd,UACoB;CACpB,IAAI,CAAC,UAAU,OAAO,KAAA;CACtB,MAAM,QAAkB,CAAC,SAAS,SAAS,
|
|
1
|
+
{"version":3,"file":"dream-cycle-followup.js","names":[],"sources":["../../../../cli/commands/manage/dream-cycle-followup.ts"],"sourcesContent":["/** Dream-cycle follow-up progress formatting and verbose stage runner. */\n\nimport type { ExtractImplicitFeedbackProgressSnapshot } from \"../../cmd-feedback.js\";\nimport type { VerificationCycleResult } from \"../../../services/continuous-verifier.js\";\nimport { runMaintenanceHeartbeat } from \"./maintenance-heartbeat.js\";\n\nexport type FollowUpProgressSupplier = () => string | undefined;\n\nexport interface RunVerboseFollowUpOptions {\n progressSupplier?: FollowUpProgressSupplier;\n heartbeatIntervalMs?: number;\n stageIndex?: number;\n stageTotal?: number;\n}\n\nexport interface ContinuousVerificationAssessment {\n status: \"healthy\" | \"degraded\";\n reason: \"healthy\" | \"errors_present\" | \"all_uncertain\";\n shouldFailPipeline: boolean;\n summary?: string;\n}\n\nexport function formatExtractImplicitFeedbackProgress(\n snapshot: ExtractImplicitFeedbackProgressSnapshot | undefined,\n): string | undefined {\n if (!snapshot) return undefined;\n const parts: string[] = [`stage=${snapshot.stage}`];\n\n if (snapshot.stage === \"scan-sessions\") {\n parts.push(`sessions=${snapshot.sessionsVisited}/${snapshot.sessionsDiscovered}`);\n if (snapshot.sessionsProcessed !== snapshot.sessionsVisited) {\n parts.push(`processed=${snapshot.sessionsProcessed}`);\n }\n const skipped = snapshot.sessionsReadErrors + snapshot.sessionsTooShort;\n if (skipped > 0) parts.push(`skipped=${skipped}`);\n if (snapshot.currentSession) parts.push(`current=${snapshot.currentSession}`);\n parts.push(`signals=${snapshot.signalsExtracted} (${snapshot.positiveCount}+/${snapshot.negativeCount}-)`);\n if (snapshot.trajectoriesBuilt > 0) parts.push(`traj=${snapshot.trajectoriesBuilt}`);\n } else if (snapshot.stage === \"cleanup-duplicates\") {\n parts.push(`collapsed=${snapshot.cleanupCollapsed}`);\n if (snapshot.cleanupScanned > 0) parts.push(`scanned=${snapshot.cleanupScanned}`);\n if (snapshot.cleanupBatches > 0) parts.push(`batches=${snapshot.cleanupBatches}`);\n } else if (snapshot.stage === \"closed-loop\") {\n parts.push(`signals=${snapshot.signalsExtracted} (${snapshot.positiveCount}+/${snapshot.negativeCount}-)`);\n if (snapshot.trajectoriesBuilt > 0) parts.push(`traj=${snapshot.trajectoriesBuilt}`);\n }\n\n if (snapshot.partial) {\n parts.push(`partial=${snapshot.partialReason ?? \"capped\"}`);\n if ((snapshot.sessionsDeferred ?? 0) > 0) parts.push(`deferred=${snapshot.sessionsDeferred}`);\n if ((snapshot.backlogSignalsEstimate ?? 0) > 0 || (snapshot.backlogTrajectoriesEstimate ?? 0) > 0) {\n parts.push(`backlog≈${snapshot.backlogSignalsEstimate ?? 0}s/${snapshot.backlogTrajectoriesEstimate ?? 0}t`);\n }\n }\n\n return parts.join(\"; \");\n}\n\nexport function assessContinuousVerificationResult(result: VerificationCycleResult): ContinuousVerificationAssessment {\n if (result.errors > 0) {\n const summary =\n result.checked === 0\n ? `infrastructure error prevented verification (${result.errors} error(s))`\n : `${result.errors}/${result.checked} verification check(s) errored`;\n return {\n status: \"degraded\",\n reason: \"errors_present\",\n shouldFailPipeline: true,\n summary,\n };\n }\n if (result.checked > 0 && result.confirmed === 0 && result.stale === 0) {\n return {\n status: \"degraded\",\n reason: \"all_uncertain\",\n shouldFailPipeline: true,\n summary: `all ${result.checked} verification check(s) were uncertain`,\n };\n }\n return { status: \"healthy\", reason: \"healthy\", shouldFailPipeline: false };\n}\n\nexport function formatContinuousVerificationAssessmentLine(\n result: VerificationCycleResult,\n assessment: ContinuousVerificationAssessment,\n): string {\n return [\n `status=${assessment.status}`,\n `reason=${assessment.reason}`,\n `checked=${result.checked}`,\n `confirmed=${result.confirmed}`,\n `stale=${result.stale}`,\n `uncertain=${result.uncertain}`,\n `errors=${result.errors}`,\n ].join(\" \");\n}\n\nexport async function runVerboseFollowUp<T>(\n label: string,\n verbose: boolean,\n fn: () => Promise<T> | T,\n opts: RunVerboseFollowUpOptions = {},\n): Promise<T> {\n const stagePrefix =\n opts.stageIndex && opts.stageTotal && opts.stageTotal > 0 ? `stage ${opts.stageIndex}/${opts.stageTotal} ` : \"\";\n const stageLabel = `${stagePrefix}${label}`.trim();\n return runMaintenanceHeartbeat(stageLabel, verbose, fn, {\n progressSupplier: opts.progressSupplier,\n heartbeatIntervalMs: opts.heartbeatIntervalMs,\n jsonMode: false,\n logPrefix: \"[dream-cycle]\",\n progressSeparator: \" — \",\n });\n}\n"],"mappings":";;AAsBA,SAAgB,sCACd,UACoB;CACpB,IAAI,CAAC,UAAU,OAAO,KAAA;CACtB,MAAM,QAAkB,CAAC,SAAS,SAAS,OAAO;CAElD,IAAI,SAAS,UAAU,iBAAiB;EACtC,MAAM,KAAK,YAAY,SAAS,gBAAgB,GAAG,SAAS,oBAAoB;EAChF,IAAI,SAAS,sBAAsB,SAAS,iBAC1C,MAAM,KAAK,aAAa,SAAS,mBAAmB;EAEtD,MAAM,UAAU,SAAS,qBAAqB,SAAS;EACvD,IAAI,UAAU,GAAG,MAAM,KAAK,WAAW,SAAS;EAChD,IAAI,SAAS,gBAAgB,MAAM,KAAK,WAAW,SAAS,gBAAgB;EAC5E,MAAM,KAAK,WAAW,SAAS,iBAAiB,IAAI,SAAS,cAAc,IAAI,SAAS,cAAc,GAAG;EACzG,IAAI,SAAS,oBAAoB,GAAG,MAAM,KAAK,QAAQ,SAAS,mBAAmB;CACrF,OAAO,IAAI,SAAS,UAAU,sBAAsB;EAClD,MAAM,KAAK,aAAa,SAAS,kBAAkB;EACnD,IAAI,SAAS,iBAAiB,GAAG,MAAM,KAAK,WAAW,SAAS,gBAAgB;EAChF,IAAI,SAAS,iBAAiB,GAAG,MAAM,KAAK,WAAW,SAAS,gBAAgB;CAClF,OAAO,IAAI,SAAS,UAAU,eAAe;EAC3C,MAAM,KAAK,WAAW,SAAS,iBAAiB,IAAI,SAAS,cAAc,IAAI,SAAS,cAAc,GAAG;EACzG,IAAI,SAAS,oBAAoB,GAAG,MAAM,KAAK,QAAQ,SAAS,mBAAmB;CACrF;CAEA,IAAI,SAAS,SAAS;EACpB,MAAM,KAAK,WAAW,SAAS,iBAAiB,UAAU;EAC1D,KAAK,SAAS,oBAAoB,KAAK,GAAG,MAAM,KAAK,YAAY,SAAS,kBAAkB;EAC5F,KAAK,SAAS,0BAA0B,KAAK,MAAM,SAAS,+BAA+B,KAAK,GAC9F,MAAM,KAAK,WAAW,SAAS,0BAA0B,EAAE,IAAI,SAAS,+BAA+B,EAAE,EAAE;CAE/G;CAEA,OAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAgB,mCAAmC,QAAmE;CACpH,IAAI,OAAO,SAAS,GAKlB,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,oBAAoB;EACpB,SAPA,OAAO,YAAY,IACf,gDAAgD,OAAO,OAAO,cAC9D,GAAG,OAAO,OAAO,GAAG,OAAO,QAAQ;CAMzC;CAEF,IAAI,OAAO,UAAU,KAAK,OAAO,cAAc,KAAK,OAAO,UAAU,GACnE,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,oBAAoB;EACpB,SAAS,OAAO,OAAO,QAAQ;CACjC;CAEF,OAAO;EAAE,QAAQ;EAAW,QAAQ;EAAW,oBAAoB;CAAM;AAC3E;AAEA,SAAgB,2CACd,QACA,YACQ;CACR,OAAO;EACL,UAAU,WAAW;EACrB,UAAU,WAAW;EACrB,WAAW,OAAO;EAClB,aAAa,OAAO;EACpB,SAAS,OAAO;EAChB,aAAa,OAAO;EACpB,UAAU,OAAO;CACnB,EAAE,KAAK,GAAG;AACZ;AAEA,eAAsB,mBACpB,OACA,SACA,IACA,OAAkC,CAAC,GACvB;CAIZ,OAAO,wBADY,GADjB,KAAK,cAAc,KAAK,cAAc,KAAK,aAAa,IAAI,SAAS,KAAK,WAAW,GAAG,KAAK,WAAW,KAAK,KAC3E,QAAQ,KACJ,GAAG,SAAS,IAAI;EACtD,kBAAkB,KAAK;EACvB,qBAAqB,KAAK;EAC1B,UAAU;EACV,WAAW;EACX,mBAAmB;CACrB,CAAC;AACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maintenance-heartbeat.js","names":[],"sources":["../../../../cli/commands/manage/maintenance-heartbeat.ts"],"sourcesContent":["function formatError(err: unknown): string {\n return err instanceof Error ? (err.stack ?? err.message) : String(err);\n}\n\nexport type ProgressSupplier = () => string | undefined;\n\nexport interface MaintenanceHeartbeatController {\n heartbeat: () => void;\n}\n\nexport interface RunMaintenanceHeartbeatOptions {\n progressSupplier?: ProgressSupplier;\n heartbeatIntervalMs?: number;\n forceHeartbeat?: boolean;\n jsonMode?: boolean;\n logPrefix?: string;\n progressSeparator?: string;\n}\n\nexport async function runMaintenanceHeartbeat<T>(\n label: string,\n verbose: boolean,\n fn: (heartbeat: MaintenanceHeartbeatController) => Promise<T> | T,\n opts: RunMaintenanceHeartbeatOptions = {},\n): Promise<T> {\n const emit = verbose || opts.forceHeartbeat === true;\n const logStream = opts.jsonMode ? console.error : console.log;\n const prefix = opts.logPrefix ?? \"memory-hybrid:\";\n const progressSep = opts.progressSeparator ?? \"; \";\n const intervalMs = Math.max(1, opts.heartbeatIntervalMs ?? 60_000);\n const started = Date.now();\n let lastHeartbeatAt = started;\n let heartbeat: ReturnType<typeof setInterval> | undefined;\n const emitStillRunning = () => {\n if (!emit) return;\n const now = Date.now();\n if (now - lastHeartbeatAt < intervalMs) return;\n const elapsedSec = Math.floor((now - started) / 1000);\n let progressSuffix = \"\";\n if (opts.progressSupplier) {\n try {\n const progress = opts.progressSupplier();\n if (progress) progressSuffix = `${progressSep}${progress}`;\n } catch {\n // Heartbeat logging must never fail the command.\n }\n }\n logStream(`${prefix} ${label} — still running after ${elapsedSec}s${progressSuffix}`);\n lastHeartbeatAt = now;\n };\n const heartbeatController: MaintenanceHeartbeatController = {\n heartbeat: emitStillRunning,\n };\n if (emit) {\n logStream(`${prefix} ${label} — start`);\n heartbeat = setInterval(emitStillRunning, intervalMs);\n heartbeat.unref?.();\n }\n try {\n const result = await fn(heartbeatController);\n if (emit) {\n const elapsedSec = Math.floor((Date.now() - started) / 1000);\n logStream(`${prefix} ${label} — complete in ${elapsedSec}s`);\n }\n return result;\n } catch (err) {\n if (emit) {\n const elapsedSec = Math.floor((Date.now() - started) / 1000);\n console.error(`${prefix} ${label} — failed after ${elapsedSec}s: ${formatError(err)}`);\n }\n throw err;\n } finally {\n if (heartbeat) clearInterval(heartbeat);\n }\n}\n"],"mappings":";AAAA,SAAS,YAAY,KAAsB;CACzC,OAAO,eAAe,QAAS,IAAI,SAAS,IAAI,UAAW,OAAO,
|
|
1
|
+
{"version":3,"file":"maintenance-heartbeat.js","names":[],"sources":["../../../../cli/commands/manage/maintenance-heartbeat.ts"],"sourcesContent":["function formatError(err: unknown): string {\n return err instanceof Error ? (err.stack ?? err.message) : String(err);\n}\n\nexport type ProgressSupplier = () => string | undefined;\n\nexport interface MaintenanceHeartbeatController {\n heartbeat: () => void;\n}\n\nexport interface RunMaintenanceHeartbeatOptions {\n progressSupplier?: ProgressSupplier;\n heartbeatIntervalMs?: number;\n forceHeartbeat?: boolean;\n jsonMode?: boolean;\n logPrefix?: string;\n progressSeparator?: string;\n}\n\nexport async function runMaintenanceHeartbeat<T>(\n label: string,\n verbose: boolean,\n fn: (heartbeat: MaintenanceHeartbeatController) => Promise<T> | T,\n opts: RunMaintenanceHeartbeatOptions = {},\n): Promise<T> {\n const emit = verbose || opts.forceHeartbeat === true;\n const logStream = opts.jsonMode ? console.error : console.log;\n const prefix = opts.logPrefix ?? \"memory-hybrid:\";\n const progressSep = opts.progressSeparator ?? \"; \";\n const intervalMs = Math.max(1, opts.heartbeatIntervalMs ?? 60_000);\n const started = Date.now();\n let lastHeartbeatAt = started;\n let heartbeat: ReturnType<typeof setInterval> | undefined;\n const emitStillRunning = () => {\n if (!emit) return;\n const now = Date.now();\n if (now - lastHeartbeatAt < intervalMs) return;\n const elapsedSec = Math.floor((now - started) / 1000);\n let progressSuffix = \"\";\n if (opts.progressSupplier) {\n try {\n const progress = opts.progressSupplier();\n if (progress) progressSuffix = `${progressSep}${progress}`;\n } catch {\n // Heartbeat logging must never fail the command.\n }\n }\n logStream(`${prefix} ${label} — still running after ${elapsedSec}s${progressSuffix}`);\n lastHeartbeatAt = now;\n };\n const heartbeatController: MaintenanceHeartbeatController = {\n heartbeat: emitStillRunning,\n };\n if (emit) {\n logStream(`${prefix} ${label} — start`);\n heartbeat = setInterval(emitStillRunning, intervalMs);\n heartbeat.unref?.();\n }\n try {\n const result = await fn(heartbeatController);\n if (emit) {\n const elapsedSec = Math.floor((Date.now() - started) / 1000);\n logStream(`${prefix} ${label} — complete in ${elapsedSec}s`);\n }\n return result;\n } catch (err) {\n if (emit) {\n const elapsedSec = Math.floor((Date.now() - started) / 1000);\n console.error(`${prefix} ${label} — failed after ${elapsedSec}s: ${formatError(err)}`);\n }\n throw err;\n } finally {\n if (heartbeat) clearInterval(heartbeat);\n }\n}\n"],"mappings":";AAAA,SAAS,YAAY,KAAsB;CACzC,OAAO,eAAe,QAAS,IAAI,SAAS,IAAI,UAAW,OAAO,GAAG;AACvE;AAiBA,eAAsB,wBACpB,OACA,SACA,IACA,OAAuC,CAAC,GAC5B;CACZ,MAAM,OAAO,WAAW,KAAK,mBAAmB;CAChD,MAAM,YAAY,KAAK,WAAW,QAAQ,QAAQ,QAAQ;CAC1D,MAAM,SAAS,KAAK,aAAa;CACjC,MAAM,cAAc,KAAK,qBAAqB;CAC9C,MAAM,aAAa,KAAK,IAAI,GAAG,KAAK,uBAAuB,GAAM;CACjE,MAAM,UAAU,KAAK,IAAI;CACzB,IAAI,kBAAkB;CACtB,IAAI;CACJ,MAAM,yBAAyB;EAC7B,IAAI,CAAC,MAAM;EACX,MAAM,MAAM,KAAK,IAAI;EACrB,IAAI,MAAM,kBAAkB,YAAY;EACxC,MAAM,aAAa,KAAK,OAAO,MAAM,WAAW,GAAI;EACpD,IAAI,iBAAiB;EACrB,IAAI,KAAK,kBACP,IAAI;GACF,MAAM,WAAW,KAAK,iBAAiB;GACvC,IAAI,UAAU,iBAAiB,GAAG,cAAc;EAClD,QAAQ,CAER;EAEF,UAAU,GAAG,OAAO,GAAG,MAAM,yBAAyB,WAAW,GAAG,gBAAgB;EACpF,kBAAkB;CACpB;CACA,MAAM,sBAAsD,EAC1D,WAAW,iBACb;CACA,IAAI,MAAM;EACR,UAAU,GAAG,OAAO,GAAG,MAAM,SAAS;EACtC,YAAY,YAAY,kBAAkB,UAAU;EACpD,UAAU,QAAQ;CACpB;CACA,IAAI;EACF,MAAM,SAAS,MAAM,GAAG,mBAAmB;EAC3C,IAAI,MAEF,UAAU,GAAG,OAAO,GAAG,MAAM,iBADV,KAAK,OAAO,KAAK,IAAI,IAAI,WAAW,GACA,EAAE,EAAE;EAE7D,OAAO;CACT,SAAS,KAAK;EACZ,IAAI,MAAM;GACR,MAAM,aAAa,KAAK,OAAO,KAAK,IAAI,IAAI,WAAW,GAAI;GAC3D,QAAQ,MAAM,GAAG,OAAO,GAAG,MAAM,kBAAkB,WAAW,KAAK,YAAY,GAAG,GAAG;EACvF;EACA,MAAM;CACR,UAAU;EACR,IAAI,WAAW,cAAc,SAAS;CACxC;AACF"}
|