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":"pending-review-digest.js","names":[],"sources":["../../services/pending-review-digest.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { DatabaseSync } from \"node:sqlite\";\n\nimport { CrystallizationStore } from \"../backends/crystallization-store.js\";\nimport { ProposalsDB } from \"../backends/proposals-db.js\";\nimport { ToolProposalStore } from \"../backends/tool-proposal-store.js\";\nimport type { HybridMemoryConfig } from \"../config.js\";\nimport { pluginLogger } from \"../utils/logger.js\";\nimport { summarizeSkillProposalValidation } from \"./generated-skill-validation.js\";\n\ntype FactsDbForPendingDigest = {\n proceduresCount(): number;\n proceduresValidatedCount(): number;\n proceduresPromotedCount(): number;\n countVerifiedFacts(): number;\n /**\n * Optional: count procedures whose `validated_at` falls within `[sinceSec, nowSec)` (#1197).\n * Used by `procedures.newThisWeek` in the digest. When unsupported, the digest reports 0.\n */\n proceduresValidatedSince?(sinceSec: number): number;\n /**\n * Optional: return the raw SQLite handle so the digest can resolve persona-proposal evidence\n * (#1197 — `evidence: { topFactIds, facts }`). Falls back to empty evidence when unsupported.\n */\n getRawDb?(): DatabaseSync | undefined | null;\n};\n\nexport type PendingReviewCounts = {\n persona: number;\n procedures: number;\n tools: number;\n crystallization: number;\n verified: number;\n};\n\nexport type PendingReviewDigestReport = {\n schemaVersion: 1;\n generatedAt: string;\n sinceDays: number;\n pendingReview: PendingReviewCounts;\n procedures: {\n total: number;\n validated: number;\n promoted: number;\n validatedNotPromoted: number;\n /** #1197: procedures whose `validated_at` is within `sinceDays`. */\n newThisWeek: number;\n };\n personaProposals: {\n enabled: boolean;\n pending: number;\n approved: number;\n rejected: number;\n expired: number;\n /**\n * #1742: count of pending entries omitted from `pendingEntries` (by time-window filter or\n * the per-digest cap). When > 0, the digest renders an explicit truncation marker.\n */\n truncated: number;\n pendingEntries: Array<{\n id: string;\n title: string;\n targetFile: string;\n confidence: number;\n createdAt: number;\n approveCommand: string;\n declineCommand: string;\n deferCommand: string;\n /**\n * #1197: top supporting facts derived from the proposal's `evidenceSessions`. Capped at\n * `topFactIds.length <= 5`; `facts` is the total count of supporting facts found across\n * those sessions (not just the truncated head).\n */\n evidence: { topFactIds: string[]; facts: number };\n }>;\n };\n toolProposals: {\n proposed: number;\n approved: number;\n rejected: number;\n proposedEntries: Array<{\n id: string;\n name: string;\n description: string;\n approveCommand: string;\n declineCommand: string;\n }>;\n };\n crystallization: {\n pending: number;\n approved: number;\n rejected: number;\n pendingEntries: Array<{\n id: string;\n skillName: string;\n approveCommand: string;\n declineCommand: string;\n validation: string;\n }>;\n };\n verifiedFacts: { pendingReview: number; reviewCommand: string };\n};\n\nexport function parsePendingDigestSinceDays(value?: string): number {\n if (!value) return 7;\n const m = value.trim().match(/^(\\d+)([dhw])?$/i);\n if (!m) return 7;\n const n = Number.parseInt(m[1], 10);\n const unit = (m[2] ?? \"d\").toLowerCase();\n if (unit === \"h\") return Math.max(1, Math.ceil(n / 24));\n if (unit === \"w\") return n * 7;\n return Math.max(1, n);\n}\n\nexport function pendingStorePaths(sqlitePath: string): {\n proposals: string;\n toolProposals: string;\n crystallization: string;\n} {\n const base = dirname(sqlitePath);\n return {\n proposals: join(base, \"proposals.db\"),\n toolProposals: join(base, \"tool-proposals.db\"),\n crystallization: join(base, \"crystallization-proposals.db\"),\n };\n}\n\nfunction withStore<TStore extends { close?: () => void }, T>(\n factory: () => TStore,\n fn: (store: TStore) => T,\n fallback: T,\n): T {\n let store: TStore | null = null;\n try {\n store = factory();\n return fn(store);\n } catch {\n return fallback;\n } finally {\n try {\n store?.close?.();\n } catch {\n // ignore close errors in operator digest helpers\n }\n }\n}\n\nexport function countPendingReviewBacklogs(\n cfg: HybridMemoryConfig,\n factsDb: FactsDbForPendingDigest,\n): PendingReviewCounts {\n const paths = pendingStorePaths(cfg.sqlitePath);\n const persona = cfg.personaProposals.enabled\n ? withStore(\n () => new ProposalsDB(paths.proposals),\n (store: ProposalsDB) => store.list({ status: \"pending\" }).length,\n 0,\n )\n : 0;\n const tools = withStore(\n () => new ToolProposalStore(paths.toolProposals),\n (store: ToolProposalStore) => store.count(\"proposed\"),\n 0,\n );\n const crystallization = withStore(\n () => new CrystallizationStore(paths.crystallization),\n (store: CrystallizationStore) => store.count(\"pending\"),\n 0,\n );\n return {\n persona,\n procedures: Math.max(0, factsDb.proceduresValidatedCount() - factsDb.proceduresPromotedCount()),\n tools,\n crystallization,\n verified: factsDb.countVerifiedFacts(),\n };\n}\n\nfunction relativeTime(epochSec: number, nowSec = Math.floor(Date.now() / 1000)): string {\n const diffSec = Math.max(0, nowSec - epochSec);\n if (diffSec < 60) return \"just now\";\n const mins = Math.floor(diffSec / 60);\n if (mins < 60) return `${mins}m ago`;\n const hours = Math.floor(mins / 60);\n if (hours < 24) return `${hours}h ago`;\n const days = Math.floor(hours / 24);\n if (days < 30) return `${days}d ago`;\n return `${Math.floor(days / 30)}mo ago`;\n}\n\nexport function buildPendingReviewDigestReport(opts: {\n cfg: HybridMemoryConfig;\n factsDb: FactsDbForPendingDigest;\n since?: string;\n now?: Date;\n}): PendingReviewDigestReport {\n const cfg = opts.cfg;\n const factsDb = opts.factsDb;\n const sinceDays = parsePendingDigestSinceDays(opts.since);\n const now = opts.now ?? new Date();\n const sinceSec = Math.floor(now.getTime() / 1000) - sinceDays * 24 * 3600;\n const paths = pendingStorePaths(cfg.sqlitePath);\n\n const personaAll = cfg.personaProposals.enabled\n ? withStore(\n () => new ProposalsDB(paths.proposals),\n (store: ProposalsDB) => store.list(),\n [],\n )\n : [];\n const personaPending = personaAll.filter((p) => p.status === \"pending\");\n const personaRecentPending = personaPending.filter((p) => p.createdAt >= sinceSec);\n\n const toolAll = withStore(\n () => new ToolProposalStore(paths.toolProposals),\n (store: ToolProposalStore) => store.list(),\n [],\n );\n const crystalAll = withStore(\n () => new CrystallizationStore(paths.crystallization),\n (store: CrystallizationStore) => store.list(),\n [],\n );\n\n const proceduresTotal = factsDb.proceduresCount();\n const proceduresValidated = factsDb.proceduresValidatedCount();\n const proceduresPromoted = factsDb.proceduresPromotedCount();\n const validatedNotPromoted = Math.max(0, proceduresValidated - proceduresPromoted);\n const proceduresNewThisWeek = factsDb.proceduresValidatedSince\n ? Math.max(0, factsDb.proceduresValidatedSince(sinceSec))\n : 0;\n const toolProposed = toolAll.filter((p) => p.status === \"proposed\");\n const crystalPending = crystalAll.filter((p) => p.status === \"drafted\" || p.status === \"validated\");\n const pendingReview = {\n persona: personaPending.length,\n procedures: validatedNotPromoted,\n tools: toolProposed.length,\n crystallization: crystalPending.length,\n verified: factsDb.countVerifiedFacts(),\n };\n\n // #1197: resolve persona-proposal evidence by joining `evidenceSessions` against\n // `facts.provenance_session`. Best-effort — empty when the FactsDB does not expose a raw db.\n const rawDb = factsDb.getRawDb?.();\n function evidenceForProposal(sessions: string[]): { topFactIds: string[]; facts: number } {\n if (!rawDb || sessions.length === 0) return { topFactIds: [], facts: 0 };\n try {\n const placeholders = sessions.map(() => \"?\").join(\",\");\n const rows = rawDb\n .prepare(\n `SELECT id FROM facts\n WHERE superseded_at IS NULL\n AND provenance_session IS NOT NULL\n AND provenance_session IN (${placeholders})\n ORDER BY COALESCE(importance, 0) DESC, created_at DESC\n LIMIT 50`,\n )\n .all(...sessions) as Array<{ id: string }>;\n return {\n topFactIds: rows.slice(0, 5).map((r) => r.id),\n facts: rows.length,\n };\n } catch {\n return { topFactIds: [], facts: 0 };\n }\n }\n\n return {\n schemaVersion: 1,\n generatedAt: now.toISOString(),\n sinceDays,\n pendingReview,\n procedures: {\n total: proceduresTotal,\n validated: proceduresValidated,\n promoted: proceduresPromoted,\n validatedNotPromoted,\n newThisWeek: proceduresNewThisWeek,\n },\n personaProposals: {\n enabled: cfg.personaProposals.enabled,\n pending: personaPending.length,\n approved: personaAll.filter((p) => p.status === \"approved\").length,\n rejected: personaAll.filter((p) => p.status === \"rejected\").length,\n expired: personaAll.filter((p) => p.status === \"expired\").length,\n // #1742: track omitted entries so callers can surface a truncation marker.\n truncated: personaPending.length - personaRecentPending.slice(0, 10).length,\n pendingEntries: personaRecentPending.slice(0, 10).map((p) => ({\n id: p.id,\n title: p.title,\n targetFile: p.targetFile,\n confidence: p.confidence,\n createdAt: p.createdAt,\n approveCommand: `openclaw hybrid-mem proposals approve ${p.id}`,\n declineCommand: `openclaw hybrid-mem proposals reject ${p.id}`,\n deferCommand: \"openclaw hybrid-mem proposals list --status pending\",\n evidence: evidenceForProposal(p.evidenceSessions ?? []),\n })),\n },\n toolProposals: {\n proposed: toolProposed.length,\n approved: toolAll.filter((p) => p.status === \"approved\").length,\n rejected: toolAll.filter((p) => p.status === \"rejected\").length,\n proposedEntries: toolProposed.slice(0, 10).map((p) => ({\n id: p.id,\n name: p.name,\n description: p.description,\n approveCommand: `memory_tool_approve id=${p.id}`,\n declineCommand: `memory_tool_reject id=${p.id}`,\n })),\n },\n crystallization: {\n pending: crystalPending.length,\n approved: crystalAll.filter((p) => p.status === \"approved\").length,\n rejected: crystalAll.filter((p) => p.status === \"rejected\").length,\n pendingEntries: crystalPending.slice(0, 10).map((p) => ({\n id: p.id,\n skillName: p.skillName,\n approveCommand: `memory_crystallize_approve id=${p.id}`,\n declineCommand: `memory_crystallize_reject id=${p.id}`,\n validation: summarizeSkillProposalValidation(p.validationResult),\n })),\n },\n verifiedFacts: {\n pendingReview: pendingReview.verified,\n reviewCommand: \"openclaw hybrid-mem verified list\",\n },\n };\n}\n\nexport function renderPendingReviewDigestMarkdown(report: PendingReviewDigestReport): string {\n const generated = report.generatedAt.slice(0, 10);\n const lines = [\n `# Hybrid-memory pending digest (${generated}, last ${report.sinceDays}d)`,\n \"\",\n `Pending review (proposals/procedures/tools/crystal/verified): ${report.pendingReview.persona}/${report.pendingReview.procedures}/${report.pendingReview.tools}/${report.pendingReview.crystallization}/${report.pendingReview.verified}`,\n \"\",\n `## Persona proposals (${report.personaProposals.pending})`,\n ];\n if (report.personaProposals.pendingEntries.length === 0)\n lines.push(\"No recent pending persona proposals in this window.\");\n report.personaProposals.pendingEntries.forEach((p, i) => {\n lines.push(\n `${i + 1}. [proposed ${relativeTime(p.createdAt)}] ${p.title} (${p.targetFile}, confidence ${p.confidence.toFixed(2)})`,\n );\n lines.push(` - Approve: ${p.approveCommand}`);\n lines.push(` - Decline: ${p.declineCommand}`);\n lines.push(` - Defer: ${p.deferCommand}`);\n if (p.evidence.facts > 0) {\n const sample = p.evidence.topFactIds.length > 0 ? ` (sample: ${p.evidence.topFactIds.join(\", \")})` : \"\";\n lines.push(` - Evidence: ${p.evidence.facts} fact(s)${sample}`);\n }\n });\n // #1742: when entries were omitted (time-window or cap), surface an explicit marker so\n // operators know the list is incomplete and how to see the full backlog.\n if (report.personaProposals.truncated > 0) {\n const shown = report.personaProposals.pendingEntries.length;\n const total = report.personaProposals.pending;\n lines.push(\n `_(Showing ${shown} of ${total} pending persona proposals; ${report.personaProposals.truncated} omitted — run \\`openclaw hybrid-mem proposals list --status pending\\` to list all.)_`,\n );\n }\n lines.push(\n \"\",\n `## Procedure promotions (${report.procedures.validatedNotPromoted} backlog, ${report.procedures.newThisWeek} new this week)`,\n \"- Review: openclaw hybrid-mem procedures triage --not-promoted\",\n \"- Approve/promote: openclaw hybrid-mem generate-auto-skills\",\n \"- Defer: leave validated procedures unpromoted\",\n \"\",\n );\n lines.push(`## Tool proposals (${report.toolProposals.proposed})`);\n if (report.toolProposals.proposedEntries.length === 0) lines.push(\"No pending tool proposals.\");\n report.toolProposals.proposedEntries.forEach((p, i) => {\n lines.push(`${i + 1}. ${p.name} — ${p.description}`);\n lines.push(` - Approve: ${p.approveCommand}`);\n lines.push(` - Decline: ${p.declineCommand}`);\n lines.push(\" - Defer: leave as proposed\");\n });\n lines.push(\"\", `## Crystallization proposals (${report.crystallization.pending})`);\n if (report.crystallization.pendingEntries.length === 0) lines.push(\"No pending crystallization proposals.\");\n report.crystallization.pendingEntries.forEach((p, i) => {\n lines.push(`${i + 1}. ${p.skillName}`);\n lines.push(` - Validation: ${p.validation}`);\n lines.push(` - Approve: ${p.approveCommand}`);\n lines.push(` - Decline: ${p.declineCommand}`);\n lines.push(\" - Defer: leave pending\");\n });\n lines.push(\n \"\",\n `## Verified-fact reviews (${report.verifiedFacts.pendingReview})`,\n `- Review: ${report.verifiedFacts.reviewCommand}`,\n );\n return lines.join(\"\\n\");\n}\n\nexport function writePendingReviewDigestOutput(opts: {\n report: PendingReviewDigestReport;\n format: \"md\" | \"json\";\n outPath: string;\n}): void {\n const output =\n opts.format === \"json\" ? JSON.stringify(opts.report, null, 2) : renderPendingReviewDigestMarkdown(opts.report);\n if (opts.outPath === \"-\") {\n process.stdout.write(`${output}\\n`);\n return;\n }\n mkdirSync(dirname(opts.outPath), { recursive: true });\n writeFileSync(opts.outPath, output, \"utf-8\");\n pluginLogger.info(`Written: ${opts.outPath}`);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pending-review-digest.js","names":[],"sources":["../../services/pending-review-digest.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { DatabaseSync } from \"node:sqlite\";\n\nimport { CrystallizationStore } from \"../backends/crystallization-store.js\";\nimport { ProposalsDB } from \"../backends/proposals-db.js\";\nimport { ToolProposalStore } from \"../backends/tool-proposal-store.js\";\nimport type { HybridMemoryConfig } from \"../config.js\";\nimport { pluginLogger } from \"../utils/logger.js\";\nimport { summarizeSkillProposalValidation } from \"./generated-skill-validation.js\";\n\ntype FactsDbForPendingDigest = {\n proceduresCount(): number;\n proceduresValidatedCount(): number;\n proceduresPromotedCount(): number;\n countVerifiedFacts(): number;\n /**\n * Optional: count procedures whose `validated_at` falls within `[sinceSec, nowSec)` (#1197).\n * Used by `procedures.newThisWeek` in the digest. When unsupported, the digest reports 0.\n */\n proceduresValidatedSince?(sinceSec: number): number;\n /**\n * Optional: return the raw SQLite handle so the digest can resolve persona-proposal evidence\n * (#1197 — `evidence: { topFactIds, facts }`). Falls back to empty evidence when unsupported.\n */\n getRawDb?(): DatabaseSync | undefined | null;\n};\n\nexport type PendingReviewCounts = {\n persona: number;\n procedures: number;\n tools: number;\n crystallization: number;\n verified: number;\n};\n\nexport type PendingReviewDigestReport = {\n schemaVersion: 1;\n generatedAt: string;\n sinceDays: number;\n pendingReview: PendingReviewCounts;\n procedures: {\n total: number;\n validated: number;\n promoted: number;\n validatedNotPromoted: number;\n /** #1197: procedures whose `validated_at` is within `sinceDays`. */\n newThisWeek: number;\n };\n personaProposals: {\n enabled: boolean;\n pending: number;\n approved: number;\n rejected: number;\n expired: number;\n /**\n * #1742: count of pending entries omitted from `pendingEntries` (by time-window filter or\n * the per-digest cap). When > 0, the digest renders an explicit truncation marker.\n */\n truncated: number;\n pendingEntries: Array<{\n id: string;\n title: string;\n targetFile: string;\n confidence: number;\n createdAt: number;\n approveCommand: string;\n declineCommand: string;\n deferCommand: string;\n /**\n * #1197: top supporting facts derived from the proposal's `evidenceSessions`. Capped at\n * `topFactIds.length <= 5`; `facts` is the total count of supporting facts found across\n * those sessions (not just the truncated head).\n */\n evidence: { topFactIds: string[]; facts: number };\n }>;\n };\n toolProposals: {\n proposed: number;\n approved: number;\n rejected: number;\n proposedEntries: Array<{\n id: string;\n name: string;\n description: string;\n approveCommand: string;\n declineCommand: string;\n }>;\n };\n crystallization: {\n pending: number;\n approved: number;\n rejected: number;\n pendingEntries: Array<{\n id: string;\n skillName: string;\n approveCommand: string;\n declineCommand: string;\n validation: string;\n }>;\n };\n verifiedFacts: { pendingReview: number; reviewCommand: string };\n};\n\nexport function parsePendingDigestSinceDays(value?: string): number {\n if (!value) return 7;\n const m = value.trim().match(/^(\\d+)([dhw])?$/i);\n if (!m) return 7;\n const n = Number.parseInt(m[1], 10);\n const unit = (m[2] ?? \"d\").toLowerCase();\n if (unit === \"h\") return Math.max(1, Math.ceil(n / 24));\n if (unit === \"w\") return n * 7;\n return Math.max(1, n);\n}\n\nexport function pendingStorePaths(sqlitePath: string): {\n proposals: string;\n toolProposals: string;\n crystallization: string;\n} {\n const base = dirname(sqlitePath);\n return {\n proposals: join(base, \"proposals.db\"),\n toolProposals: join(base, \"tool-proposals.db\"),\n crystallization: join(base, \"crystallization-proposals.db\"),\n };\n}\n\nfunction withStore<TStore extends { close?: () => void }, T>(\n factory: () => TStore,\n fn: (store: TStore) => T,\n fallback: T,\n): T {\n let store: TStore | null = null;\n try {\n store = factory();\n return fn(store);\n } catch {\n return fallback;\n } finally {\n try {\n store?.close?.();\n } catch {\n // ignore close errors in operator digest helpers\n }\n }\n}\n\nexport function countPendingReviewBacklogs(\n cfg: HybridMemoryConfig,\n factsDb: FactsDbForPendingDigest,\n): PendingReviewCounts {\n const paths = pendingStorePaths(cfg.sqlitePath);\n const persona = cfg.personaProposals.enabled\n ? withStore(\n () => new ProposalsDB(paths.proposals),\n (store: ProposalsDB) => store.list({ status: \"pending\" }).length,\n 0,\n )\n : 0;\n const tools = withStore(\n () => new ToolProposalStore(paths.toolProposals),\n (store: ToolProposalStore) => store.count(\"proposed\"),\n 0,\n );\n const crystallization = withStore(\n () => new CrystallizationStore(paths.crystallization),\n (store: CrystallizationStore) => store.count(\"pending\"),\n 0,\n );\n return {\n persona,\n procedures: Math.max(0, factsDb.proceduresValidatedCount() - factsDb.proceduresPromotedCount()),\n tools,\n crystallization,\n verified: factsDb.countVerifiedFacts(),\n };\n}\n\nfunction relativeTime(epochSec: number, nowSec = Math.floor(Date.now() / 1000)): string {\n const diffSec = Math.max(0, nowSec - epochSec);\n if (diffSec < 60) return \"just now\";\n const mins = Math.floor(diffSec / 60);\n if (mins < 60) return `${mins}m ago`;\n const hours = Math.floor(mins / 60);\n if (hours < 24) return `${hours}h ago`;\n const days = Math.floor(hours / 24);\n if (days < 30) return `${days}d ago`;\n return `${Math.floor(days / 30)}mo ago`;\n}\n\nexport function buildPendingReviewDigestReport(opts: {\n cfg: HybridMemoryConfig;\n factsDb: FactsDbForPendingDigest;\n since?: string;\n now?: Date;\n}): PendingReviewDigestReport {\n const cfg = opts.cfg;\n const factsDb = opts.factsDb;\n const sinceDays = parsePendingDigestSinceDays(opts.since);\n const now = opts.now ?? new Date();\n const sinceSec = Math.floor(now.getTime() / 1000) - sinceDays * 24 * 3600;\n const paths = pendingStorePaths(cfg.sqlitePath);\n\n const personaAll = cfg.personaProposals.enabled\n ? withStore(\n () => new ProposalsDB(paths.proposals),\n (store: ProposalsDB) => store.list(),\n [],\n )\n : [];\n const personaPending = personaAll.filter((p) => p.status === \"pending\");\n const personaRecentPending = personaPending.filter((p) => p.createdAt >= sinceSec);\n\n const toolAll = withStore(\n () => new ToolProposalStore(paths.toolProposals),\n (store: ToolProposalStore) => store.list(),\n [],\n );\n const crystalAll = withStore(\n () => new CrystallizationStore(paths.crystallization),\n (store: CrystallizationStore) => store.list(),\n [],\n );\n\n const proceduresTotal = factsDb.proceduresCount();\n const proceduresValidated = factsDb.proceduresValidatedCount();\n const proceduresPromoted = factsDb.proceduresPromotedCount();\n const validatedNotPromoted = Math.max(0, proceduresValidated - proceduresPromoted);\n const proceduresNewThisWeek = factsDb.proceduresValidatedSince\n ? Math.max(0, factsDb.proceduresValidatedSince(sinceSec))\n : 0;\n const toolProposed = toolAll.filter((p) => p.status === \"proposed\");\n const crystalPending = crystalAll.filter((p) => p.status === \"drafted\" || p.status === \"validated\");\n const pendingReview = {\n persona: personaPending.length,\n procedures: validatedNotPromoted,\n tools: toolProposed.length,\n crystallization: crystalPending.length,\n verified: factsDb.countVerifiedFacts(),\n };\n\n // #1197: resolve persona-proposal evidence by joining `evidenceSessions` against\n // `facts.provenance_session`. Best-effort — empty when the FactsDB does not expose a raw db.\n const rawDb = factsDb.getRawDb?.();\n function evidenceForProposal(sessions: string[]): { topFactIds: string[]; facts: number } {\n if (!rawDb || sessions.length === 0) return { topFactIds: [], facts: 0 };\n try {\n const placeholders = sessions.map(() => \"?\").join(\",\");\n const rows = rawDb\n .prepare(\n `SELECT id FROM facts\n WHERE superseded_at IS NULL\n AND provenance_session IS NOT NULL\n AND provenance_session IN (${placeholders})\n ORDER BY COALESCE(importance, 0) DESC, created_at DESC\n LIMIT 50`,\n )\n .all(...sessions) as Array<{ id: string }>;\n return {\n topFactIds: rows.slice(0, 5).map((r) => r.id),\n facts: rows.length,\n };\n } catch {\n return { topFactIds: [], facts: 0 };\n }\n }\n\n return {\n schemaVersion: 1,\n generatedAt: now.toISOString(),\n sinceDays,\n pendingReview,\n procedures: {\n total: proceduresTotal,\n validated: proceduresValidated,\n promoted: proceduresPromoted,\n validatedNotPromoted,\n newThisWeek: proceduresNewThisWeek,\n },\n personaProposals: {\n enabled: cfg.personaProposals.enabled,\n pending: personaPending.length,\n approved: personaAll.filter((p) => p.status === \"approved\").length,\n rejected: personaAll.filter((p) => p.status === \"rejected\").length,\n expired: personaAll.filter((p) => p.status === \"expired\").length,\n // #1742: track omitted entries so callers can surface a truncation marker.\n truncated: personaPending.length - personaRecentPending.slice(0, 10).length,\n pendingEntries: personaRecentPending.slice(0, 10).map((p) => ({\n id: p.id,\n title: p.title,\n targetFile: p.targetFile,\n confidence: p.confidence,\n createdAt: p.createdAt,\n approveCommand: `openclaw hybrid-mem proposals approve ${p.id}`,\n declineCommand: `openclaw hybrid-mem proposals reject ${p.id}`,\n deferCommand: \"openclaw hybrid-mem proposals list --status pending\",\n evidence: evidenceForProposal(p.evidenceSessions ?? []),\n })),\n },\n toolProposals: {\n proposed: toolProposed.length,\n approved: toolAll.filter((p) => p.status === \"approved\").length,\n rejected: toolAll.filter((p) => p.status === \"rejected\").length,\n proposedEntries: toolProposed.slice(0, 10).map((p) => ({\n id: p.id,\n name: p.name,\n description: p.description,\n approveCommand: `memory_tool_approve id=${p.id}`,\n declineCommand: `memory_tool_reject id=${p.id}`,\n })),\n },\n crystallization: {\n pending: crystalPending.length,\n approved: crystalAll.filter((p) => p.status === \"approved\").length,\n rejected: crystalAll.filter((p) => p.status === \"rejected\").length,\n pendingEntries: crystalPending.slice(0, 10).map((p) => ({\n id: p.id,\n skillName: p.skillName,\n approveCommand: `memory_crystallize_approve id=${p.id}`,\n declineCommand: `memory_crystallize_reject id=${p.id}`,\n validation: summarizeSkillProposalValidation(p.validationResult),\n })),\n },\n verifiedFacts: {\n pendingReview: pendingReview.verified,\n reviewCommand: \"openclaw hybrid-mem verified list\",\n },\n };\n}\n\nexport function renderPendingReviewDigestMarkdown(report: PendingReviewDigestReport): string {\n const generated = report.generatedAt.slice(0, 10);\n const lines = [\n `# Hybrid-memory pending digest (${generated}, last ${report.sinceDays}d)`,\n \"\",\n `Pending review (proposals/procedures/tools/crystal/verified): ${report.pendingReview.persona}/${report.pendingReview.procedures}/${report.pendingReview.tools}/${report.pendingReview.crystallization}/${report.pendingReview.verified}`,\n \"\",\n `## Persona proposals (${report.personaProposals.pending})`,\n ];\n if (report.personaProposals.pendingEntries.length === 0)\n lines.push(\"No recent pending persona proposals in this window.\");\n report.personaProposals.pendingEntries.forEach((p, i) => {\n lines.push(\n `${i + 1}. [proposed ${relativeTime(p.createdAt)}] ${p.title} (${p.targetFile}, confidence ${p.confidence.toFixed(2)})`,\n );\n lines.push(` - Approve: ${p.approveCommand}`);\n lines.push(` - Decline: ${p.declineCommand}`);\n lines.push(` - Defer: ${p.deferCommand}`);\n if (p.evidence.facts > 0) {\n const sample = p.evidence.topFactIds.length > 0 ? ` (sample: ${p.evidence.topFactIds.join(\", \")})` : \"\";\n lines.push(` - Evidence: ${p.evidence.facts} fact(s)${sample}`);\n }\n });\n // #1742: when entries were omitted (time-window or cap), surface an explicit marker so\n // operators know the list is incomplete and how to see the full backlog.\n if (report.personaProposals.truncated > 0) {\n const shown = report.personaProposals.pendingEntries.length;\n const total = report.personaProposals.pending;\n lines.push(\n `_(Showing ${shown} of ${total} pending persona proposals; ${report.personaProposals.truncated} omitted — run \\`openclaw hybrid-mem proposals list --status pending\\` to list all.)_`,\n );\n }\n lines.push(\n \"\",\n `## Procedure promotions (${report.procedures.validatedNotPromoted} backlog, ${report.procedures.newThisWeek} new this week)`,\n \"- Review: openclaw hybrid-mem procedures triage --not-promoted\",\n \"- Approve/promote: openclaw hybrid-mem generate-auto-skills\",\n \"- Defer: leave validated procedures unpromoted\",\n \"\",\n );\n lines.push(`## Tool proposals (${report.toolProposals.proposed})`);\n if (report.toolProposals.proposedEntries.length === 0) lines.push(\"No pending tool proposals.\");\n report.toolProposals.proposedEntries.forEach((p, i) => {\n lines.push(`${i + 1}. ${p.name} — ${p.description}`);\n lines.push(` - Approve: ${p.approveCommand}`);\n lines.push(` - Decline: ${p.declineCommand}`);\n lines.push(\" - Defer: leave as proposed\");\n });\n lines.push(\"\", `## Crystallization proposals (${report.crystallization.pending})`);\n if (report.crystallization.pendingEntries.length === 0) lines.push(\"No pending crystallization proposals.\");\n report.crystallization.pendingEntries.forEach((p, i) => {\n lines.push(`${i + 1}. ${p.skillName}`);\n lines.push(` - Validation: ${p.validation}`);\n lines.push(` - Approve: ${p.approveCommand}`);\n lines.push(` - Decline: ${p.declineCommand}`);\n lines.push(\" - Defer: leave pending\");\n });\n lines.push(\n \"\",\n `## Verified-fact reviews (${report.verifiedFacts.pendingReview})`,\n `- Review: ${report.verifiedFacts.reviewCommand}`,\n );\n return lines.join(\"\\n\");\n}\n\nexport function writePendingReviewDigestOutput(opts: {\n report: PendingReviewDigestReport;\n format: \"md\" | \"json\";\n outPath: string;\n}): void {\n const output =\n opts.format === \"json\" ? JSON.stringify(opts.report, null, 2) : renderPendingReviewDigestMarkdown(opts.report);\n if (opts.outPath === \"-\") {\n process.stdout.write(`${output}\\n`);\n return;\n }\n mkdirSync(dirname(opts.outPath), { recursive: true });\n writeFileSync(opts.outPath, output, \"utf-8\");\n pluginLogger.info(`Written: ${opts.outPath}`);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persona-proposal-triage.js","names":[],"sources":["../../services/persona-proposal-triage.ts"],"sourcesContent":["/**\n * Cautious persona-proposal triage adapter (#1327).\n *\n * This module owns persona-specific policy while preserving the shared\n * pending-autopilot #1334 decision, reason, redaction, dry-run, lock/CAS, and\n * audit envelope. Proposal text is treated as untrusted input: it is never used\n * as instructions and raw proposal bodies are not persisted in output/audit.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, lstatSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\nimport type { ProposalEntry, ProposalsDB } from \"../backends/proposals-db.js\";\nimport { buildAppliedContent, buildUnifiedDiff, parseSuggestedChange } from \"../cli/proposals.js\";\nimport type { HybridMemoryConfig } from \"../config.js\";\nimport { getEnv } from \"../utils/env-manager.js\";\nimport { getFileSnapshot } from \"../utils/file-snapshot.js\";\nimport {\n type AutopilotMode,\n type PendingAutopilotCursor,\n type PendingDecision,\n type PendingDecisionActorContext,\n type PendingDecisionContext,\n type PendingItem,\n type PendingQueueAdapter,\n PendingAutopilotStore,\n canonicalJson,\n computePendingInputHash,\n createPendingAutopilotRunId,\n createStableRunSummary,\n redactAutopilotValue,\n shouldAdvancePendingCursor,\n} from \"./pending-autopilot/index.js\";\n\nexport const PERSONA_PROPOSAL_TRIAGE_POLICY_VERSION = \"persona-proposal-triage-v1\";\nexport const PERSONA_APPLY_CONFIDENCE_THRESHOLD = 0.95;\nexport const PERSONA_REJECT_CONFIDENCE_THRESHOLD = 0.7;\n\nexport type PersonaProposalTriagePolicy = \"report-only\" | \"cautious\" | \"apply-safe\";\nexport type PersonaProposalRisk = \"low\" | \"medium\" | \"high\" | \"critical\";\nexport const PERSONA_PROPOSAL_SENSITIVE_TARGET_FILES = [\"SOUL.md\", \"USER.md\", \"IDENTITY.md\", \"AGENTS.md\"] as const;\nexport const PERSONA_PROPOSAL_CRITICAL_TARGET_FILES = [...PERSONA_PROPOSAL_SENSITIVE_TARGET_FILES, \"TOOLS.md\"] as const;\nexport type PersonaProposalTargetFile = (typeof PERSONA_PROPOSAL_CRITICAL_TARGET_FILES)[number];\n\nexport interface PersonaProposalTriageOptions {\n proposalsDb: ProposalsDB;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n stateDbPath?: string;\n workspace?: string;\n mode?: AutopilotMode;\n policy?: PersonaProposalTriagePolicy;\n max?: number;\n proposalId?: string;\n runId?: string;\n jobId?: string;\n actor?: PendingDecisionActorContext;\n now?: Date;\n runLifecycle?: \"standalone\" | \"embedded\";\n store?: PendingAutopilotStore;\n}\n\nexport interface PersonaProposalTriageResult {\n schemaVersion: 1;\n runId: string;\n mode: AutopilotMode;\n policy: PersonaProposalTriagePolicy;\n policyVersion: string;\n counts: {\n inspected: number;\n classified: number;\n grouped: number;\n autoRejected: number;\n autoApplied: number;\n deferredForHuman: number;\n failedValidation: number;\n skippedByPolicy: number;\n };\n decisions: PersonaProposalDecisionView[];\n bundles: PersonaProposalReviewBundle[];\n humanSummary: string;\n}\n\nexport interface PersonaProposalDecisionView {\n proposalId: string;\n targetFile: string;\n risk: PersonaProposalRisk;\n action: PendingDecision[\"action\"];\n reason: PendingDecision[\"reasonCode\"];\n capability: PendingDecision[\"capabilityClass\"];\n confidence: number;\n humanReviewRequired: boolean;\n evidence: PendingDecision[\"evidence\"];\n diffSummary: string;\n inputHash: string;\n targetHash: string | null;\n}\n\nexport interface PersonaProposalReviewBundle {\n id: string;\n targetFile: string;\n risk: PersonaProposalRisk;\n recommendation: \"reject\" | \"defer\";\n proposalIds: string[];\n reasons: string[];\n rationale: string;\n commands: string[];\n evidence: PendingDecision[\"evidence\"];\n diffPreview: string;\n}\n\ntype PersonaProposalPayload = {\n proposalId: string;\n targetFile: string;\n title: string;\n confidence: number;\n evidenceSessions: string[];\n createdAt: number;\n targetHash: string | null;\n proposalHash: string;\n};\n\nexport type PersonaProposalPendingItem = PendingItem<PersonaProposalPayload> & {\n proposal: ProposalEntry;\n targetPath: string;\n targetValid: boolean;\n targetHash: string | null;\n workspace: string;\n};\n\ntype Analysis = {\n risk: PersonaProposalRisk;\n action: PendingDecision[\"action\"];\n reasonCode: PendingDecision[\"reasonCode\"];\n actionClass: PendingDecision[\"actionClass\"];\n capabilityClass: PendingDecision[\"capabilityClass\"];\n confidence: number;\n humanReviewRequired: boolean;\n diffSummary: string;\n evidence: PendingDecision[\"evidence\"];\n applyAllowed: boolean;\n};\n\nconst SENSITIVE_PERSONA_FILES = new Set<string>(PERSONA_PROPOSAL_SENSITIVE_TARGET_FILES);\nconst CRITICAL_TARGETS = new Set<string>(PERSONA_PROPOSAL_CRITICAL_TARGET_FILES);\nconst LOW_RISK_DRIFT_THRESHOLD = 2;\nconst SENSITIVE_TOOLS_RE = /^TOOLS\\.md$/i;\n\nfunction normalizePersonaProposalTriageMax(max: number | undefined): number {\n if (max === undefined) return 20;\n if (!Number.isFinite(max) || !Number.isInteger(max) || max < 0) {\n throw new Error(`persona proposal triage max must be a non-negative finite integer. Got: ${max}`);\n }\n return max;\n}\n\nexport function createPersonaProposalTriageAdapter(input: {\n proposalsDb: ProposalsDB;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n workspace?: string;\n allProposals?: ProposalEntry[];\n proposalId?: string;\n}): PendingQueueAdapter<PersonaProposalPendingItem> & {\n proposalsDb: ProposalsDB;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n workspace: string;\n} {\n return {\n queue: \"persona\",\n listPending: (cursor) => listPersonaProposalItems(input, cursor),\n decide: (item, context) => decidePersonaProposal(item, context, input),\n apply: () => {\n throw new Error(\"Use runPersonaProposalTriage for lock/CAS guarded apply semantics.\");\n },\n proposalsDb: input.proposalsDb,\n cfg: input.cfg,\n workspace: input.workspace ?? defaultWorkspace(),\n };\n}\n\nexport async function runPersonaProposalTriage(\n opts: PersonaProposalTriageOptions,\n): Promise<PersonaProposalTriageResult> {\n const mode = opts.mode ?? \"dry-run\";\n const policy = opts.policy ?? \"report-only\";\n validatePersonaPolicy(policy);\n if (mode !== \"dry-run\" && mode !== \"apply\") throw new Error(`Unsupported mode: ${mode}`);\n const max = normalizePersonaProposalTriageMax(opts.max);\n const runId = opts.runId ?? createPendingAutopilotRunId();\n const actor = opts.actor ?? ({ type: \"agent\", id: \"persona-proposal-triage\" } as const);\n const workspace = opts.workspace ?? defaultWorkspace();\n const stateDbPath = opts.stateDbPath ?? join(workspace, \"memory\", \"pending-autopilot.db\");\n const manageRunLifecycle = opts.runLifecycle !== \"embedded\";\n let store: PendingAutopilotStore | null = null;\n const allProposals = opts.proposalsDb.list();\n const adapter = createPersonaProposalTriageAdapter({\n proposalsDb: opts.proposalsDb,\n cfg: opts.cfg,\n workspace,\n allProposals,\n proposalId: opts.proposalId,\n });\n const decisions: PendingDecision[] = [];\n const views: PersonaProposalDecisionView[] = [];\n const startedAt = Math.floor((opts.now ?? new Date()).getTime() / 1000);\n const runInputHash = computePendingInputHash({ command: \"proposals triage\", mode, policy, max, startedAt: 0 });\n let cursorAdvanceCandidate: { decision: PendingDecision; cursor: string } | null = null;\n let cursorAdvanceBlocked = false;\n const ownStore = !opts.store;\n\n try {\n store =\n opts.store ?? (mode === \"apply\" && policy !== \"report-only\" ? new PendingAutopilotStore(stateDbPath) : null);\n if (manageRunLifecycle) {\n store?.createRun({\n runId,\n mode,\n policy,\n policyVersion: PERSONA_PROPOSAL_TRIAGE_POLICY_VERSION,\n inputHash: runInputHash,\n queues: [\"persona\"],\n startedAt,\n });\n }\n\n const cursor = store?.getCursor(\"persona\", policy) ?? null;\n const listed = await adapter.listPending(cursor);\n const pending = listed.slice(0, max);\n for (const item of pending) {\n const context: PendingDecisionContext = {\n runId,\n jobId: opts.jobId,\n mode,\n policy,\n policyVersion: PERSONA_PROPOSAL_TRIAGE_POLICY_VERSION,\n inputHash: item.inputHash,\n actor,\n };\n const freshProposals = mode === \"apply\" ? opts.proposalsDb.list() : allProposals;\n const freshAdapter =\n mode === \"apply\"\n ? createPersonaProposalTriageAdapter({\n proposalsDb: opts.proposalsDb,\n cfg: opts.cfg,\n workspace,\n allProposals: freshProposals,\n proposalId: opts.proposalId,\n })\n : adapter;\n let decision = await freshAdapter.decide(item, context);\n if (mode === \"apply\" && policy !== \"report-only\" && isMutationDecision(decision)) {\n if (!store) throw new Error(\"apply mode requires pending-autopilot store\");\n decision = applyPersonaDecisionWithLock({\n store,\n proposalsDb: opts.proposalsDb,\n item,\n decision,\n workspace,\n cfg: opts.cfg,\n });\n if (decision.action === \"failed-validation\") {\n store.recordDecision(decision);\n } else {\n // Successful mutation decisions are already recorded inside mutateWithLockAndAudit\n }\n } else if (policy !== \"report-only\") {\n store?.recordDecision(decision);\n }\n const itemCursor = item.visibleAfterCursor ?? item.id;\n if (shouldAdvancePendingCursor(decision)) {\n if (!cursorAdvanceBlocked) {\n cursorAdvanceCandidate = { decision, cursor: itemCursor };\n }\n } else {\n cursorAdvanceBlocked = true;\n }\n decisions.push(decision);\n views.push(decisionToView(item, decision));\n }\n if (\n policy !== \"report-only\" &&\n opts.proposalId === undefined &&\n cursorAdvanceCandidate !== null &&\n pending.length > 0\n ) {\n store?.advanceCursorIfSafe(cursorAdvanceCandidate.decision, cursorAdvanceCandidate.cursor);\n }\n\n const summary = createStableRunSummary({\n runId,\n mode,\n policy,\n policyVersion: PERSONA_PROPOSAL_TRIAGE_POLICY_VERSION,\n queues: [\"persona\"],\n startedAt,\n finishedAt: Math.floor((opts.now ?? new Date()).getTime() / 1000),\n decisions,\n });\n if (manageRunLifecycle) {\n store?.finishRun(runId, summary);\n }\n const result: PersonaProposalTriageResult = {\n schemaVersion: 1,\n runId,\n mode,\n policy,\n policyVersion: PERSONA_PROPOSAL_TRIAGE_POLICY_VERSION,\n counts: countPersonaDecisions(decisions),\n decisions: views,\n bundles: buildPersonaReviewBundles(views),\n humanSummary: \"\",\n };\n result.humanSummary = renderPersonaProposalTriageHumanSummary(result);\n return result;\n } finally {\n if (ownStore) {\n store?.close();\n }\n }\n}\n\nexport function stablePersonaProposalTriageJson(result: PersonaProposalTriageResult): string {\n return `${canonicalJson(redactAutopilotValue(result))}\\n`;\n}\n\nexport function renderPersonaProposalTriageHumanSummary(result: PersonaProposalTriageResult): string {\n const lines = [\n `Persona proposal triage ${result.runId} (${result.mode}, policy=${result.policy})`,\n `Inspected ${result.counts.inspected}; auto-rejected ${result.counts.autoRejected}; auto-applied ${result.counts.autoApplied}; deferred ${result.counts.deferredForHuman}; failed ${result.counts.failedValidation}.`,\n ];\n if (result.bundles.length > 0) {\n lines.push(\"Review bundles:\");\n for (const bundle of result.bundles) {\n lines.push(\n `- ${bundle.id}: ${bundle.proposalIds.length} proposal(s), target=${bundle.targetFile}, risk=${bundle.risk}, recommendation=${bundle.recommendation}, reasons=${bundle.reasons.join(\",\")}`,\n );\n }\n } else {\n lines.push(\"Review bundles: none.\");\n }\n lines.push(\n result.mode === \"dry-run\"\n ? \"Dry-run wrote no proposal state, target files, or durable pending-autopilot state.\"\n : \"Apply mode used shared pending-autopilot lock/CAS decision recording before any proposal/file mutation.\",\n );\n return lines.join(\"\\n\");\n}\n\nexport function decidePersonaProposal(\n item: PersonaProposalPendingItem,\n context: PendingDecisionContext,\n input: {\n proposalsDb: ProposalsDB;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n workspace?: string;\n allProposals?: ProposalEntry[];\n },\n): PendingDecision {\n const all = input.allProposals ?? input.proposalsDb.list();\n const analysis = analyzePersonaProposal(item, context.policy as PersonaProposalTriagePolicy, all);\n const reportOnly = context.policy === \"report-only\";\n const readOnlyCapability = context.mode === \"dry-run\" ? \"dry-run\" : \"read-only\";\n const action = reportOnly ? \"reported\" : analysis.action;\n const actionClass = reportOnly ? \"observe\" : analysis.actionClass;\n const capabilityClass = reportOnly ? readOnlyCapability : analysis.capabilityClass;\n const isSecurityCritical =\n analysis.reasonCode === \"security-boundary-change\" ||\n analysis.reasonCode === \"secret-or-private-data-risk\" ||\n analysis.reasonCode === \"privacy-boundary-change\";\n const humanReviewRequired = reportOnly\n ? isSecurityCritical\n ? analysis.humanReviewRequired\n : false\n : analysis.humanReviewRequired;\n\n return {\n queue: \"persona\",\n itemId: item.id,\n inputHash: item.inputHash,\n policy: context.policy,\n policyVersion: context.policyVersion,\n mode: context.mode,\n action,\n reasonCode: analysis.reasonCode,\n actionClass,\n capabilityClass,\n confidence: analysis.confidence,\n humanReviewRequired,\n evidence: analysis.evidence,\n actor: context.actor,\n runId: context.runId,\n jobId: context.jobId,\n summary: {\n title: item.proposal.title,\n body: analysis.diffSummary,\n metadata: {\n targetFile: item.proposal.targetFile,\n risk: analysis.risk,\n targetHash: item.targetHash,\n proposalHash: item.payload.proposalHash,\n },\n },\n audit: {\n queue: \"persona\",\n itemId: item.id,\n inputHash: item.inputHash,\n policy: context.policy,\n policyVersion: context.policyVersion,\n action,\n reasonCode: analysis.reasonCode,\n capabilityClass,\n humanReviewRequired,\n evidence: analysis.evidence,\n actor: context.actor,\n runId: context.runId,\n jobId: context.jobId,\n summary: {\n title: item.proposal.title,\n body: analysis.diffSummary,\n metadata: {\n targetFile: item.proposal.targetFile,\n proposalHash: item.payload.proposalHash,\n targetHash: item.targetHash,\n risk: analysis.risk,\n },\n },\n },\n };\n}\n\nfunction listPersonaProposalItems(\n input: {\n proposalsDb: ProposalsDB;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n workspace?: string;\n proposalId?: string;\n },\n cursor?: PendingAutopilotCursor | null,\n): PersonaProposalPendingItem[] {\n if (!input.cfg.personaProposals.enabled) return [];\n const pending = input.proposalsDb.list({ status: \"pending\" });\n const workspace = input.workspace ?? defaultWorkspace();\n return pending\n .sort(comparePersonaProposalNewestFirst)\n .filter((proposal) => input.proposalId === undefined || proposal.id === input.proposalId)\n .filter((proposal) => isVisibleAfterPersonaCursor(proposal, cursor))\n .map((proposal) => proposalToPendingItem(proposal, workspace, input.cfg));\n}\n\nfunction isVisibleAfterPersonaCursor(proposal: ProposalEntry, cursor?: PendingAutopilotCursor | null): boolean {\n if (!cursor?.cursor) return true;\n if (proposal.createdAt >= cursor.updatedAt) return true;\n // Persona proposals are listed newest-first by ProposalsDB. A durable cursor\n // therefore means \"the newest processed boundary\" for the already-seen backlog,\n // and subsequent pages must move toward older proposals without hiding proposals\n // created after the cursor was advanced.\n return comparePersonaCursor(proposalCursor(proposal), cursor.cursor) < 0;\n}\n\nfunction proposalCursor(proposal: Pick<ProposalEntry, \"createdAt\" | \"id\">): string {\n return `${proposal.createdAt.toString().padStart(12, \"0\")}:${proposal.id}`;\n}\n\nfunction comparePersonaCursor(a: string, b: string): number {\n return a.localeCompare(b);\n}\n\nfunction comparePersonaProposalNewestFirst(a: ProposalEntry, b: ProposalEntry): number {\n return comparePersonaCursor(proposalCursor(b), proposalCursor(a));\n}\n\nfunction proposalToPendingItem(\n proposal: ProposalEntry,\n workspace: string,\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">,\n policyVersion = PERSONA_PROPOSAL_TRIAGE_POLICY_VERSION,\n): PersonaProposalPendingItem {\n const target = resolveAllowedPersonaTarget(workspace, proposal.targetFile, cfg.personaProposals.allowedFiles);\n let targetHash: string | null = null;\n if (target.ok) {\n try {\n targetHash = existsSync(target.path) ? fileHash(target.path) : null;\n } catch {\n targetHash = null;\n }\n }\n const proposalHash = computePendingInputHash({\n id: proposal.id,\n targetFile: proposal.targetFile,\n title: proposal.title,\n observation: proposal.observation,\n suggestedChange: proposal.suggestedChange,\n confidence: proposal.confidence,\n evidenceSessions: proposal.evidenceSessions,\n targetHash: proposal.targetHash ?? null,\n targetMtimeMs: proposal.targetMtimeMs ?? null,\n });\n const payload: PersonaProposalPayload = {\n proposalId: proposal.id,\n targetFile: proposal.targetFile,\n title: proposal.title,\n confidence: proposal.confidence,\n evidenceSessions: proposal.evidenceSessions,\n createdAt: proposal.createdAt,\n targetHash: proposal.targetHash ?? null,\n proposalHash,\n };\n return {\n queue: \"persona\",\n id: proposal.id,\n inputHash: computePendingInputHash({\n queue: \"persona\",\n id: proposal.id,\n payload,\n policyVersion,\n }),\n policyVersion,\n capabilityClasses: [\"read-only\", \"safe-state-transition\", \"apply-low-risk-change\"],\n payload,\n visibleAfterCursor: proposalCursor(proposal),\n requiresHumanReview: true,\n proposal,\n targetPath: target.path,\n targetValid: target.ok,\n targetHash,\n workspace,\n };\n}\n\nfunction analyzePersonaProposal(\n item: PersonaProposalPendingItem,\n policy: PersonaProposalTriagePolicy,\n allProposals: ProposalEntry[],\n): Analysis {\n const p = item.proposal;\n const text = `${p.title}\\n${p.observation}\\n${p.suggestedChange}`;\n const evidence = buildEvidence(p);\n if (!item.targetValid) {\n return failed(\"critical\", \"validation-failed\", `Target path rejected for ${p.targetFile}`, evidence, 0.1);\n }\n if (containsSecretOrPrivateData(text)) {\n return rejectOrDefer(\n policy,\n \"critical\",\n \"secret-or-private-data-risk\",\n \"Secret/private-data risk detected; [REDACTED] raw content.\",\n evidence,\n 1,\n );\n }\n if (containsPromptInjection(text)) {\n return defer(\n \"critical\",\n \"security-boundary-change\",\n \"Prompt-injection language is untrusted and cannot affect policy gates.\",\n evidence,\n 1,\n );\n }\n if (p.confidence < PERSONA_REJECT_CONFIDENCE_THRESHOLD) {\n return rejectOrDefer(\n policy,\n \"low\",\n \"low-confidence\",\n `Confidence ${p.confidence.toFixed(2)} below ${PERSONA_REJECT_CONFIDENCE_THRESHOLD}.`,\n evidence,\n 1,\n );\n }\n if (isNonActionable(p.suggestedChange)) {\n return rejectOrDefer(\n policy,\n \"low\",\n \"non-actionable\",\n \"Proposal lacks an actionable localized change.\",\n evidence,\n 0.95,\n );\n }\n const duplicate = findDuplicate(p, allProposals);\n if (duplicate?.status === \"applied\") {\n return rejectOrDefer(\n policy,\n \"low\",\n \"duplicate-applied-proposal\",\n `Duplicates already-applied proposal ${duplicate.id}.`,\n evidence,\n 1,\n );\n }\n if (duplicate?.status === \"pending\") {\n return rejectOrDefer(\n policy,\n \"low\",\n \"duplicate-pending-proposal\",\n `Duplicates pending proposal ${duplicate.id}.`,\n evidence,\n 1,\n );\n }\n if (isStaleTarget(item)) {\n return rejectOrDefer(\n policy,\n \"low\",\n \"stale-target-context\",\n \"Target snapshot changed since proposal creation; safe rebase unavailable.\",\n evidence,\n 1,\n );\n }\n const risk = classifyRisk(p, item);\n const diffSummary = summarizeDiff(p, item);\n if (policy === \"report-only\") return report(risk, \"policy-report-only\", diffSummary, evidence, p.confidence);\n if (risk === \"high\" || risk === \"critical\") {\n return defer(risk, highRiskReason(p), diffSummary, evidence, p.confidence);\n }\n if (risk === \"medium\") {\n return defer(\"medium\", \"policy-requires-human\", diffSummary, evidence, p.confidence);\n }\n if (!hasEvidence(p)) return defer(\"low\", \"missing-evidence\", diffSummary, evidence, p.confidence);\n if (policy !== \"apply-safe\") return defer(\"low\", \"policy-requires-human\", diffSummary, evidence, p.confidence);\n if (!hasReliableTargetSnapshot(p)) {\n return defer(\n \"low\",\n \"stale-target-context\",\n \"Auto-apply requires target hash or mtime snapshot.\",\n evidence,\n p.confidence,\n );\n }\n if (p.confidence < PERSONA_APPLY_CONFIDENCE_THRESHOLD) {\n return defer(\"low\", \"low-confidence\", diffSummary, evidence, p.confidence);\n }\n const drift = lowRiskDriftGuard(p, allProposals);\n if (drift.blocked) {\n return defer(\"low\", \"policy-requires-human\", `${diffSummary}; ${drift.summary}`, evidence, p.confidence);\n }\n return {\n risk: \"low\",\n action: \"applied\",\n reasonCode: \"safe-low-risk-localized-change\",\n actionClass: \"low-risk-apply\",\n capabilityClass: \"apply-low-risk-change\",\n confidence: p.confidence,\n humanReviewRequired: false,\n diffSummary,\n evidence,\n applyAllowed: true,\n };\n}\n\nfunction applyPersonaDecisionWithLock(input: {\n store: PendingAutopilotStore;\n proposalsDb: ProposalsDB;\n item: PersonaProposalPendingItem;\n decision: PendingDecision;\n workspace: string;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n}): PendingDecision {\n const owner = `${input.decision.runId}:persona-triage`;\n const locked = input.store.acquireLock({\n queue: \"persona\",\n itemId: input.item.id,\n inputHash: input.item.inputHash,\n owner,\n ttlSeconds: 120,\n mode: input.decision.mode,\n });\n if (!locked) return validationFailure(input.decision, \"lock-conflict\", \"Could not acquire persona proposal lock.\");\n try {\n const current = input.proposalsDb.get(input.item.id);\n if (!current || current.status !== \"pending\") {\n return validationFailure(input.decision, \"already-processed\", \"Proposal was already processed before apply.\");\n }\n const actualHash = proposalToPendingItem(current, input.workspace, input.cfg).inputHash;\n if (actualHash !== input.decision.inputHash) {\n return validationFailure(\n input.decision,\n \"input-hash-mismatch\",\n \"Proposal changed between classification and apply.\",\n );\n }\n let preparedApply:\n | {\n targetPath: string;\n backupPath: string;\n original: string;\n appliedContent: string;\n preHash: string;\n postHash: string;\n auditDiff: string;\n }\n | undefined;\n if (input.decision.action === \"applied\") {\n const currentTarget = resolveAllowedPersonaTarget(\n input.workspace,\n current.targetFile,\n input.cfg.personaProposals.allowedFiles,\n );\n if (!currentTarget.ok || !existsSync(currentTarget.path)) {\n return validationFailure(\n input.decision,\n \"stale-target-context\",\n \"Target file unavailable during apply revalidation.\",\n );\n }\n const currentSnapshot = getFileSnapshot(currentTarget.path);\n if (!currentSnapshot) {\n return validationFailure(\n input.decision,\n \"stale-target-context\",\n \"Target file unreadable during apply revalidation.\",\n );\n }\n if (!hasReliableTargetSnapshot(current)) {\n return validationFailure(\n input.decision,\n \"stale-target-context\",\n \"Auto-apply requires target hash or mtime snapshot.\",\n );\n }\n if (current.targetHash && current.targetHash !== currentSnapshot.hash) {\n return validationFailure(input.decision, \"input-hash-mismatch\", \"Target file changed before apply.\");\n }\n if (!current.targetHash && current.targetMtimeMs != null && current.targetMtimeMs !== currentSnapshot.mtimeMs) {\n return validationFailure(input.decision, \"input-hash-mismatch\", \"Target mtime changed before apply.\");\n }\n const original = readFileSync(currentTarget.path, \"utf-8\");\n const applied = buildAppliedContent(original, current, new Date().toISOString());\n if (!applied.content.trim()) {\n return validationFailure(\n input.decision,\n \"validation-failed\",\n `Proposal ${input.item.id} does not contain replacement content to apply.`,\n );\n }\n if (!isAllowedSensitivePersonaApply(current.targetFile, original, applied.content, current.suggestedChange)) {\n return validationFailure(\n input.decision,\n \"identity-boundary-change\",\n \"Sensitive persona files require mechanically verified formatting-only diffs for apply-safe auto-apply.\",\n );\n }\n const auditDiff = redactedAuditDiff(original, applied.content, current.targetFile);\n preparedApply = {\n targetPath: currentTarget.path,\n backupPath: `${currentTarget.path}.backup-${Date.now()}`,\n original,\n appliedContent: applied.content,\n preHash: currentSnapshot.hash,\n postHash: hashText(applied.content),\n auditDiff,\n };\n }\n\n const decisionForMutation = preparedApply ? withPersonaApplyAudit(input.decision, preparedApply) : input.decision;\n const ok = input.store.mutateWithLockAndAudit({\n decision: decisionForMutation,\n owner,\n actualInputHash: actualHash,\n audit: () => {},\n mutate: () => {\n if (decisionForMutation.action === \"rejected\") {\n input.proposalsDb.updateStatus(input.item.id, \"rejected\", \"persona-triage\", decisionForMutation.reasonCode);\n } else if (decisionForMutation.action === \"applied\" && preparedApply) {\n applyPreparedPersonaChange(preparedApply, () => input.proposalsDb.markApplied(input.item.id));\n }\n },\n });\n if (!ok) return validationFailure(input.decision, \"input-hash-mismatch\", \"Lock/CAS/audit mutation rejected.\");\n return decisionForMutation;\n } finally {\n input.store.releaseLock({\n queue: \"persona\",\n itemId: input.item.id,\n inputHash: input.item.inputHash,\n owner,\n mode: input.decision.mode,\n });\n }\n}\n\nfunction validationFailure(\n decision: PendingDecision,\n reasonCode: PendingDecision[\"reasonCode\"],\n body: string,\n): PendingDecision {\n const capabilityClass = decision.mode === \"dry-run\" ? \"dry-run\" : \"read-only\";\n return {\n ...decision,\n action: \"failed-validation\",\n reasonCode,\n actionClass: \"observe\",\n capabilityClass,\n confidence: 0,\n humanReviewRequired: true,\n summary: { ...(decision.summary ?? {}), body },\n audit: decision.audit\n ? {\n ...decision.audit,\n action: \"failed-validation\",\n reasonCode,\n capabilityClass,\n humanReviewRequired: true,\n }\n : undefined,\n };\n}\n\nfunction decisionToView(item: PersonaProposalPendingItem, decision: PendingDecision): PersonaProposalDecisionView {\n const metadata = decision.summary?.metadata ?? {};\n return {\n proposalId: item.id,\n targetFile: item.proposal.targetFile,\n risk: (metadata.risk as PersonaProposalRisk | undefined) ?? \"medium\",\n action: decision.action,\n reason: decision.reasonCode,\n capability: decision.capabilityClass,\n confidence: decision.confidence,\n humanReviewRequired: decision.humanReviewRequired,\n evidence: decision.evidence,\n diffSummary: String(decision.summary?.body ?? \"\"),\n inputHash: decision.inputHash,\n targetHash: item.targetHash,\n };\n}\n\nfunction buildPersonaReviewBundles(views: PersonaProposalDecisionView[]): PersonaProposalReviewBundle[] {\n const reviewable = views.filter(\n (v) => v.humanReviewRequired || v.action === \"reported\" || v.action === \"deferred-for-human\",\n );\n const groups = new Map<string, PersonaProposalDecisionView[]>();\n for (const view of reviewable) {\n const semanticTopic = topicKey(\n view.evidence\n .map((entry) => entry.summary)\n .filter(Boolean)\n .join(\"\\n\"),\n );\n const key = `${view.targetFile}:${view.risk}:${view.reason}:${semanticTopic}`;\n groups.set(key, [...(groups.get(key) ?? []), view]);\n }\n return [...groups.values()].map((items, idx) => {\n const risk = maxRisk(items.map((i) => i.risk));\n const targetFile = items[0]?.targetFile ?? \"unknown\";\n const reasons = [...new Set(items.map((i) => i.reason))];\n const proposalIds = items.map((i) => i.proposalId);\n return {\n id: `persona-bundle-${idx + 1}`,\n targetFile,\n risk,\n recommendation:\n risk === \"low\" && reasons.every((r) => r.startsWith(\"duplicate\") || r === \"non-actionable\")\n ? \"reject\"\n : \"defer\",\n proposalIds,\n reasons,\n rationale: `Grouped by target=${targetFile}, risk=${risk}, and shared topic. Review each proposal independently before approval.`,\n commands: proposalIds.flatMap((id) => [\n `openclaw hybrid-mem proposals show ${id} --diff`,\n `openclaw hybrid-mem proposals reject ${id} --reason <reason>`,\n ]),\n evidence: items.flatMap((i) => i.evidence),\n diffPreview: items.map((i) => `[${i.proposalId}] ${i.diffSummary}`).join(\"\\n\"),\n };\n });\n}\n\nfunction countPersonaDecisions(decisions: PendingDecision[]): PersonaProposalTriageResult[\"counts\"] {\n return {\n inspected: decisions.length,\n classified: decisions.filter((d) => d.action === \"classified\" || d.action === \"reported\").length,\n grouped: decisions.filter(\n (d) => d.humanReviewRequired || d.action === \"reported\" || d.action === \"deferred-for-human\",\n ).length,\n autoRejected: decisions.filter((d) => d.action === \"rejected\").length,\n autoApplied: decisions.filter((d) => d.action === \"applied\").length,\n deferredForHuman: decisions.filter((d) => d.action === \"deferred-for-human\").length,\n failedValidation: decisions.filter((d) => d.action === \"failed-validation\").length,\n skippedByPolicy: decisions.filter((d) => d.action === \"skipped-by-policy\").length,\n };\n}\n\nfunction rejectOrDefer(\n policy: PersonaProposalTriagePolicy,\n risk: PersonaProposalRisk,\n reasonCode: PendingDecision[\"reasonCode\"],\n diffSummary: string,\n evidence: PendingDecision[\"evidence\"],\n confidence: number,\n): Analysis {\n if (policy === \"cautious\" || policy === \"apply-safe\") {\n return {\n risk,\n action: \"rejected\",\n reasonCode,\n actionClass: \"state-transition\",\n capabilityClass: \"safe-state-transition\",\n confidence,\n humanReviewRequired: false,\n diffSummary,\n evidence,\n applyAllowed: false,\n };\n }\n return report(risk, reasonCode, diffSummary, evidence, confidence);\n}\n\nfunction defer(\n risk: PersonaProposalRisk,\n reasonCode: PendingDecision[\"reasonCode\"],\n diffSummary: string,\n evidence: PendingDecision[\"evidence\"],\n confidence: number,\n): Analysis {\n return {\n risk,\n action: \"deferred-for-human\",\n reasonCode,\n actionClass: \"record-review\",\n capabilityClass: \"record-review-metadata\",\n confidence,\n humanReviewRequired: true,\n diffSummary,\n evidence,\n applyAllowed: false,\n };\n}\n\nfunction report(\n risk: PersonaProposalRisk,\n reasonCode: PendingDecision[\"reasonCode\"],\n diffSummary: string,\n evidence: PendingDecision[\"evidence\"],\n confidence: number,\n): Analysis {\n return {\n risk,\n action: \"reported\",\n reasonCode,\n actionClass: \"observe\",\n capabilityClass: \"read-only\",\n confidence,\n humanReviewRequired: false,\n diffSummary,\n evidence,\n applyAllowed: false,\n };\n}\n\nfunction failed(\n risk: PersonaProposalRisk,\n reasonCode: PendingDecision[\"reasonCode\"],\n diffSummary: string,\n evidence: PendingDecision[\"evidence\"],\n confidence: number,\n): Analysis {\n return {\n risk,\n action: \"failed-validation\",\n reasonCode,\n actionClass: \"observe\",\n capabilityClass: \"read-only\",\n confidence,\n humanReviewRequired: true,\n diffSummary,\n evidence,\n applyAllowed: false,\n };\n}\n\nfunction classifyRisk(p: ProposalEntry, item: PersonaProposalPendingItem): PersonaProposalRisk {\n const text = `${p.title}\n${p.observation}\n${p.suggestedChange}`.toLowerCase();\n if (/\\b(destructive|credential)\\b|approval boundary|bypass approval|disable safeguard/.test(text)) return \"critical\";\n if (isCriticalTarget(p.targetFile)) {\n if (SENSITIVE_PERSONA_FILES.has(p.targetFile)) {\n if (!isMechanicallyVerifiedSensitiveFormatting(item, p.suggestedChange)) return \"high\";\n return \"low\";\n }\n if (!isCriticalTargetFormattingOnly(p.suggestedChange)) return \"high\";\n if (/\\b(privacy|security|approval|credential|destructive|safeguard)\\b/.test(text)) return \"high\";\n if (item.targetHash && normalizeText(p.suggestedChange).length < 240) return \"low\";\n return \"medium\";\n }\n if (\n /\\b(identit(?:y|ies)|personalit(?:y|ies)|voice|tone|privacy|security|external|group chat|user preferences?|profile|personal facts?|memory rules?)\\b/.test(\n text,\n )\n ) {\n return \"high\";\n }\n if (/\\b(preference|workflow|routing|project context|communication)\\b/.test(text)) return \"medium\";\n if (isLargeOrBroadDiff(p)) return \"medium\";\n if (item.targetHash && normalizeText(p.suggestedChange).length < 240) return \"low\";\n return \"medium\";\n}\n\nfunction isCriticalTargetFormattingOnly(suggestedChange: string): boolean {\n const parsed = parseSuggestedChange(suggestedChange);\n if (parsed.changeType !== \"replace\") return false;\n const hasFormattingKeywords = /\\b(formatting|typo|whitespace|punctuation)\\b/i.test(suggestedChange);\n if (!hasFormattingKeywords) return false;\n const containsSemanticKeywords =\n /\\b(personalit(?:y|ies)|voice|tone|behaviou?r(?:al)?|instructions?|responses?|reply|replies|always|never|must|should|redirect|defer|escalate|refer|contact|route|forward|delegate|friendlier|friendly|warmer|casual|greeting)\\b/i.test(\n suggestedChange,\n );\n return !containsSemanticKeywords;\n}\n\nfunction isMechanicallyVerifiedSensitiveFormatting(item: PersonaProposalPendingItem, suggestedChange: string): boolean {\n const parsed = parseSuggestedChange(suggestedChange);\n if (parsed.changeType !== \"replace\" || !item.targetHash || !item.targetValid || !existsSync(item.targetPath))\n return false;\n try {\n const original = readFileSync(item.targetPath, \"utf-8\");\n return stripWhitespaceAndPunctuation(original) === stripWhitespaceAndPunctuation(parsed.content);\n } catch {\n return false;\n }\n}\n\nfunction lowRiskDriftGuard(\n proposal: ProposalEntry,\n allProposals: ProposalEntry[],\n): { blocked: boolean; summary: string } {\n const target = proposal.targetFile;\n const topic = topicKey(`${proposal.title}\\n${proposal.observation}\\n${proposal.suggestedChange}`);\n const previous = allProposals.filter(\n (candidate) =>\n candidate.id !== proposal.id &&\n candidate.status === \"applied\" &&\n candidate.targetFile === target &&\n normalizeText(candidate.suggestedChange).length < 240 &&\n topicKey(`${candidate.title}\\n${candidate.observation}\\n${candidate.suggestedChange}`) === topic,\n );\n if (previous.length >= LOW_RISK_DRIFT_THRESHOLD) {\n return {\n blocked: true,\n summary: `cumulative low-risk drift guard: ${previous.length} previous auto-applied edit(s) for ${target}/${topic}`,\n };\n }\n return { blocked: false, summary: \"\" };\n}\n\nfunction isAllowedSensitivePersonaApply(\n targetFile: string,\n original: string,\n applied: string,\n suggestedChange: string,\n): boolean {\n if (!isCriticalTarget(targetFile)) return true;\n const parsed = parseSuggestedChange(suggestedChange);\n if (parsed.changeType !== \"replace\") return false;\n return stripWhitespaceAndPunctuation(original) === stripWhitespaceAndPunctuation(applied);\n}\n\nfunction stripWhitespaceAndPunctuation(input: string): string {\n return input.replace(/[\\s\\p{P}]+/gu, \"\").toLowerCase();\n}\n\nfunction withPersonaApplyAudit(\n decision: PendingDecision,\n preparedApply: { preHash: string; postHash: string; auditDiff: string },\n): PendingDecision {\n const metadata = {\n ...(decision.summary?.metadata ?? {}),\n targetPreHash: preparedApply.preHash,\n targetPostHash: preparedApply.postHash,\n };\n const summary = {\n ...(decision.summary ?? {}),\n metadata: {\n ...metadata,\n redactedBeforeAfterDiff: preparedApply.auditDiff,\n },\n };\n return {\n ...decision,\n summary,\n audit: decision.audit\n ? {\n ...decision.audit,\n summary: {\n ...(decision.audit.summary ?? {}),\n metadata: {\n ...(decision.audit.summary?.metadata ?? {}),\n ...metadata,\n redactedBeforeAfterDiff: preparedApply.auditDiff,\n },\n },\n }\n : undefined,\n };\n}\n\nfunction redactedAuditDiff(original: string, applied: string, targetFile: string): string {\n let diff: string;\n try {\n diff = buildUnifiedDiff(original, applied, targetFile);\n } catch {\n diff = `--- ${targetFile} (before)\n+++ ${targetFile} (after)\n@@ before\n${original}\n@@ after\n${applied}`;\n }\n const redacted = String(redactAutopilotValue(diff));\n return redacted.length > 8000\n ? `${redacted.slice(0, 8000)}\n... [diff truncated]`\n : redacted;\n}\n\nfunction highRiskReason(p: ProposalEntry): PendingDecision[\"reasonCode\"] {\n const text = `${p.title}\\n${p.observation}\\n${p.suggestedChange}`.toLowerCase();\n if (/privacy/.test(text)) return \"privacy-boundary-change\";\n if (/security|credential|approval|destructive|safeguard/.test(text)) return \"security-boundary-change\";\n if (/preference|profile|personal fact|user preference/.test(text)) return \"user-preference-change-requires-approval\";\n return \"identity-boundary-change\";\n}\n\nfunction isCriticalTarget(targetFile: string): boolean {\n return CRITICAL_TARGETS.has(targetFile) || SENSITIVE_TOOLS_RE.test(targetFile);\n}\n\nfunction isMutationDecision(decision: PendingDecision): boolean {\n return decision.mode === \"apply\" && (decision.action === \"rejected\" || decision.action === \"applied\");\n}\n\nfunction isStaleTarget(item: PersonaProposalPendingItem): boolean {\n return Boolean(item.proposal.targetHash && item.targetHash && item.proposal.targetHash !== item.targetHash);\n}\n\nfunction hasReliableTargetSnapshot(proposal: Pick<ProposalEntry, \"targetHash\" | \"targetMtimeMs\">): boolean {\n return Boolean(proposal.targetHash || proposal.targetMtimeMs != null);\n}\n\nfunction findDuplicate(proposal: ProposalEntry, all: ProposalEntry[]): ProposalEntry | null {\n const normalized = normalizeText(proposal.suggestedChange);\n if (!normalized) return null;\n const candidates = all.filter(\n (c) =>\n c.id !== proposal.id &&\n c.targetFile === proposal.targetFile &&\n (c.status === \"applied\" || c.status === \"pending\") &&\n normalizeText(c.suggestedChange) === normalized,\n );\n if (candidates.length === 0) return null;\n\n const appliedDuplicate = candidates\n .filter((c) => c.status === \"applied\")\n .sort((a, b) => a.createdAt - b.createdAt)[0];\n if (appliedDuplicate) return appliedDuplicate;\n\n const earlierPending = candidates\n .filter((c) => c.status === \"pending\" && compareProposalCreationOrder(c, proposal) < 0)\n .sort(compareProposalCreationOrder)[0];\n return earlierPending ?? null;\n}\n\nfunction compareProposalCreationOrder(\n a: Pick<ProposalEntry, \"createdAt\" | \"id\">,\n b: Pick<ProposalEntry, \"createdAt\" | \"id\">,\n): number {\n const createdAtDelta = a.createdAt - b.createdAt;\n if (createdAtDelta !== 0) return createdAtDelta;\n return a.id.localeCompare(b.id);\n}\n\nconst NON_ACTIONABLE_PHRASES = new Set([\n \"be better\",\n \"improve\",\n \"do better\",\n \"fix this\",\n \"update\",\n \"change\",\n \"misc\",\n \"note\",\n]);\n\nfunction isNonActionable(change: string): boolean {\n const normalized = normalizeText(change);\n if (normalized.length === 0) return true;\n if (NON_ACTIONABLE_PHRASES.has(normalized)) return true;\n\n const directiveVerbs =\n /\\b(add|append|record|capture|document|replace|remove|delete|update|clarify|format|fix|rewrite|rename|prefer|avoid|use|mention|store|include)\\b/i;\n const hasTargetOrLocation =\n /\\b(soul\\.md|user\\.md|identity\\.md|agents\\.md|tools\\.md|section|heading|paragraph|line|bullet|preference|guidance|instruction|file|document)\\b/i.test(\n change,\n );\n\n return normalized.length < 12 && !directiveVerbs.test(change) && !hasTargetOrLocation;\n}\n\nfunction isLargeOrBroadDiff(p: ProposalEntry): boolean {\n const lines = p.suggestedChange.split(/\\r?\\n/).filter((line) => line.trim());\n return lines.length > 12 || p.suggestedChange.length > 1200 || /^\\s*replace\\b/i.test(p.suggestedChange);\n}\n\nfunction hasEvidence(p: ProposalEntry): boolean {\n return Array.isArray(p.evidenceSessions) && p.evidenceSessions.length > 0;\n}\n\nfunction summarizeDiff(p: ProposalEntry, item: PersonaProposalPendingItem): string {\n const change = redactAutopilotValue(p.suggestedChange) as string;\n const lines = String(change)\n .split(/\\r?\\n/)\n .filter((line) => line.trim());\n return `${safeActionVerb(p)} ${lines.length} non-empty line(s) in ${p.targetFile}; targetHash=${item.targetHash ?? \"missing\"}; proposalHash=${item.payload.proposalHash.slice(0, 12)}`;\n}\n\nfunction safeActionVerb(p: ProposalEntry): string {\n return /^\\s*replace\\b/i.test(p.suggestedChange) ? \"Would replace\" : \"Would append/update\";\n}\n\nfunction buildEvidence(p: ProposalEntry): PendingDecision[\"evidence\"] {\n const sessions = (p.evidenceSessions ?? [])\n .slice(0, 5)\n .map((id) => ({ type: \"session\", id, summary: \"proposal evidence session\" }));\n return [\n { type: \"proposal\", id: p.id, summary: redactedOneLine(p.title) },\n ...sessions,\n {\n type: \"proposal-hash\",\n id: shortHash(`${p.title}\\n${p.observation}\\n${p.suggestedChange}`),\n summary: \"redacted proposal content hash\",\n },\n ];\n}\n\nfunction containsPromptInjection(text: string): boolean {\n return /ignore (all )?(previous|above|system|developer)(?:\\s+\\w+){0,3}\\s+instructions|reveal (the )?(system prompt|secrets)|bypass (policy|approval|safety)|you are now|act as an unrestricted/i.test(\n text,\n );\n}\n\nfunction containsSecretOrPrivateData(text: string): boolean {\n return /-----BEGIN [A-Z ]*PRIVATE KEY-----|\\b(?:api[_-]?key|token|password|secret)\\s*[:=]|\\bghp_[A-Za-z0-9_]{20,}|\\bgithub_pat_[A-Za-z0-9_]{20,}|\\bsk-[A-Za-z0-9]{20,}|Bearer\\s+[A-Za-z0-9._~+/-]{16,}/i.test(\n text,\n );\n}\n\nfunction resolveAllowedPersonaTarget(\n workspace: string,\n targetFile: string,\n allowedFiles: readonly string[],\n): { ok: true; path: string } | { ok: false; path: string; error: string } {\n if (!allowedFiles.includes(targetFile)) return { ok: false, path: targetFile, error: \"target not allowlisted\" };\n if (targetFile.includes(\"..\") || targetFile.includes(\"/\") || targetFile.includes(\"\\\\\") || isAbsolute(targetFile)) {\n return { ok: false, path: targetFile, error: \"path traversal\" };\n }\n const workspaceReal = existsSync(workspace) ? realpathSync(workspace) : resolve(workspace);\n const targetPath = resolve(workspaceReal, targetFile);\n const rel = relative(workspaceReal, targetPath);\n if (rel.startsWith(\"..\") || isAbsolute(rel))\n return { ok: false, path: targetPath, error: \"target escapes workspace\" };\n try {\n const stat = lstatSync(targetPath);\n if (stat.isSymbolicLink()) {\n try {\n const real = realpathSync(targetPath);\n const realRel = relative(workspaceReal, real);\n if (realRel.startsWith(\"..\") || isAbsolute(realRel))\n return { ok: false, path: targetPath, error: \"symlink escapes workspace\" };\n } catch {\n return { ok: false, path: targetPath, error: \"dangling symlink\" };\n }\n }\n } catch (err: unknown) {\n if ((err as { code?: string }).code !== \"ENOENT\") {\n return { ok: false, path: targetPath, error: \"target stat failed\" };\n }\n }\n return { ok: true, path: targetPath };\n}\n\nexport function applyPreparedPersonaChange(\n preparedApply: { targetPath: string; backupPath: string; original: string; appliedContent: string },\n markApplied: () => void,\n io: {\n writeBackup?: (path: string, content: string) => void;\n writeTargetAtomic?: (path: string, content: string) => void;\n removeBackup?: (path: string) => void;\n } = {},\n): void {\n let backupWritten = false;\n let targetWritten = false;\n let targetRestored = false;\n let appliedMarked = false;\n try {\n (io.writeBackup ?? ((path, content) => writeFileSync(path, content, \"utf-8\")))(\n preparedApply.backupPath,\n preparedApply.original,\n );\n backupWritten = true;\n (io.writeTargetAtomic ?? writeFileAtomic)(preparedApply.targetPath, preparedApply.appliedContent);\n targetWritten = true;\n markApplied();\n appliedMarked = true;\n try {\n (io.removeBackup ?? ((path) => rmSync(path, { force: true })))(preparedApply.backupPath);\n } catch {\n // Bookkeeping has already succeeded and the target file contains the\n // applied content. Backup cleanup is best-effort at this point; do not\n // roll back a successful apply or surface it as an apply failure.\n }\n } catch (err) {\n if (targetWritten && !appliedMarked) {\n try {\n (io.writeTargetAtomic ?? writeFileAtomic)(preparedApply.targetPath, preparedApply.original);\n targetRestored = true;\n } catch {\n // Preserve original error; restore failed and the backup remains the recovery artifact.\n }\n }\n if (backupWritten && !appliedMarked && (!targetWritten || targetRestored)) {\n try {\n (io.removeBackup ?? ((path) => rmSync(path, { force: true })))(preparedApply.backupPath);\n } catch {\n // Preserve original error; backup cleanup failed but original error is more important.\n }\n }\n throw err;\n }\n}\n\nfunction writeFileAtomic(path: string, content: string): void {\n const tempPath = `${path}.tmp-${process.pid}-${Date.now()}`;\n try {\n writeFileSync(tempPath, content, \"utf-8\");\n renameSync(tempPath, path);\n } finally {\n try {\n if (existsSync(tempPath)) rmSync(tempPath, { force: true });\n } catch {\n // Suppress cleanup errors to preserve original error if any\n }\n }\n}\n\nfunction fileHash(path: string): string {\n return createHash(\"sha256\").update(readFileSync(path)).digest(\"hex\");\n}\n\nfunction hashText(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction shortHash(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\").slice(0, 16);\n}\n\nfunction normalizeText(input: string): string {\n return input.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\n\nfunction redactedOneLine(input: string): string {\n return String(redactAutopilotValue(input)).replace(/\\s+/g, \" \").slice(0, 160);\n}\n\nfunction topicKey(input: string): string {\n const text = input.toLowerCase();\n if (/security|privacy|credential|approval/.test(text)) return \"security\";\n if (/identity|voice|tone/.test(text)) return \"identity\";\n if (/preference|workflow|profile|user.?prefer|pr review|branch naming/.test(text)) return \"preference\";\n return \"general\";\n}\n\nfunction maxRisk(risks: PersonaProposalRisk[]): PersonaProposalRisk {\n const order: PersonaProposalRisk[] = [\"low\", \"medium\", \"high\", \"critical\"];\n return [...risks].sort((a, b) => order.indexOf(b) - order.indexOf(a))[0] ?? \"medium\";\n}\n\nexport function validatePersonaPolicy(policy: string): asserts policy is PersonaProposalTriagePolicy {\n if (policy !== \"report-only\" && policy !== \"cautious\" && policy !== \"apply-safe\") {\n throw new Error(`Unsupported persona proposal triage policy: ${policy}`);\n }\n}\n\nfunction defaultWorkspace(): string {\n return getEnv(\"OPENCLAW_WORKSPACE\") ?? join(homedir(), \".openclaw\", \"workspace\");\n}\n\nexport function createPersonaParentExecutionPath(\n adapter: PendingQueueAdapter<PersonaProposalPendingItem> & {\n proposalsDb: ProposalsDB;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n workspace: string;\n },\n) {\n return async (item: PersonaProposalPendingItem, context: PendingDecisionContext): Promise<PendingDecision> => {\n const listed = await adapter.listPending(null);\n const listedItem = listed.find((i) => i.id === item.id);\n if (!listedItem) {\n throw new Error(`Parent execution path: item ${item.id} not found in adapter.listPending()`);\n }\n return adapter.decide(listedItem, context);\n };\n}\n\nexport function createPersonaStandaloneExecutionPath(adapter: PendingQueueAdapter<PersonaProposalPendingItem>) {\n return (\n item: PersonaProposalPendingItem,\n context: PendingDecisionContext,\n ): Promise<PendingDecision> | PendingDecision => adapter.decide(item, context);\n}\n\nexport function createPersonaProposalFixtureItem(input: {\n proposal: ProposalEntry;\n workspace: string;\n allowedFiles: PersonaProposalTargetFile[];\n policyVersion?: string;\n}): PersonaProposalPendingItem {\n const item = proposalToPendingItem(\n input.proposal,\n input.workspace,\n {\n personaProposals: { allowedFiles: input.allowedFiles },\n } as Pick<HybridMemoryConfig, \"personaProposals\">,\n input.policyVersion,\n );\n return item;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"persona-proposal-triage.js","names":[],"sources":["../../services/persona-proposal-triage.ts"],"sourcesContent":["/**\n * Cautious persona-proposal triage adapter (#1327).\n *\n * This module owns persona-specific policy while preserving the shared\n * pending-autopilot #1334 decision, reason, redaction, dry-run, lock/CAS, and\n * audit envelope. Proposal text is treated as untrusted input: it is never used\n * as instructions and raw proposal bodies are not persisted in output/audit.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, lstatSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\nimport type { ProposalEntry, ProposalsDB } from \"../backends/proposals-db.js\";\nimport { buildAppliedContent, buildUnifiedDiff, parseSuggestedChange } from \"../cli/proposals.js\";\nimport type { HybridMemoryConfig } from \"../config.js\";\nimport { getEnv } from \"../utils/env-manager.js\";\nimport { getFileSnapshot } from \"../utils/file-snapshot.js\";\nimport {\n type AutopilotMode,\n type PendingAutopilotCursor,\n type PendingDecision,\n type PendingDecisionActorContext,\n type PendingDecisionContext,\n type PendingItem,\n type PendingQueueAdapter,\n PendingAutopilotStore,\n canonicalJson,\n computePendingInputHash,\n createPendingAutopilotRunId,\n createStableRunSummary,\n redactAutopilotValue,\n shouldAdvancePendingCursor,\n} from \"./pending-autopilot/index.js\";\n\nexport const PERSONA_PROPOSAL_TRIAGE_POLICY_VERSION = \"persona-proposal-triage-v1\";\nexport const PERSONA_APPLY_CONFIDENCE_THRESHOLD = 0.95;\nexport const PERSONA_REJECT_CONFIDENCE_THRESHOLD = 0.7;\n\nexport type PersonaProposalTriagePolicy = \"report-only\" | \"cautious\" | \"apply-safe\";\nexport type PersonaProposalRisk = \"low\" | \"medium\" | \"high\" | \"critical\";\nexport const PERSONA_PROPOSAL_SENSITIVE_TARGET_FILES = [\"SOUL.md\", \"USER.md\", \"IDENTITY.md\", \"AGENTS.md\"] as const;\nexport const PERSONA_PROPOSAL_CRITICAL_TARGET_FILES = [...PERSONA_PROPOSAL_SENSITIVE_TARGET_FILES, \"TOOLS.md\"] as const;\nexport type PersonaProposalTargetFile = (typeof PERSONA_PROPOSAL_CRITICAL_TARGET_FILES)[number];\n\nexport interface PersonaProposalTriageOptions {\n proposalsDb: ProposalsDB;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n stateDbPath?: string;\n workspace?: string;\n mode?: AutopilotMode;\n policy?: PersonaProposalTriagePolicy;\n max?: number;\n proposalId?: string;\n runId?: string;\n jobId?: string;\n actor?: PendingDecisionActorContext;\n now?: Date;\n runLifecycle?: \"standalone\" | \"embedded\";\n store?: PendingAutopilotStore;\n}\n\nexport interface PersonaProposalTriageResult {\n schemaVersion: 1;\n runId: string;\n mode: AutopilotMode;\n policy: PersonaProposalTriagePolicy;\n policyVersion: string;\n counts: {\n inspected: number;\n classified: number;\n grouped: number;\n autoRejected: number;\n autoApplied: number;\n deferredForHuman: number;\n failedValidation: number;\n skippedByPolicy: number;\n };\n decisions: PersonaProposalDecisionView[];\n bundles: PersonaProposalReviewBundle[];\n humanSummary: string;\n}\n\nexport interface PersonaProposalDecisionView {\n proposalId: string;\n targetFile: string;\n risk: PersonaProposalRisk;\n action: PendingDecision[\"action\"];\n reason: PendingDecision[\"reasonCode\"];\n capability: PendingDecision[\"capabilityClass\"];\n confidence: number;\n humanReviewRequired: boolean;\n evidence: PendingDecision[\"evidence\"];\n diffSummary: string;\n inputHash: string;\n targetHash: string | null;\n}\n\nexport interface PersonaProposalReviewBundle {\n id: string;\n targetFile: string;\n risk: PersonaProposalRisk;\n recommendation: \"reject\" | \"defer\";\n proposalIds: string[];\n reasons: string[];\n rationale: string;\n commands: string[];\n evidence: PendingDecision[\"evidence\"];\n diffPreview: string;\n}\n\ntype PersonaProposalPayload = {\n proposalId: string;\n targetFile: string;\n title: string;\n confidence: number;\n evidenceSessions: string[];\n createdAt: number;\n targetHash: string | null;\n proposalHash: string;\n};\n\nexport type PersonaProposalPendingItem = PendingItem<PersonaProposalPayload> & {\n proposal: ProposalEntry;\n targetPath: string;\n targetValid: boolean;\n targetHash: string | null;\n workspace: string;\n};\n\ntype Analysis = {\n risk: PersonaProposalRisk;\n action: PendingDecision[\"action\"];\n reasonCode: PendingDecision[\"reasonCode\"];\n actionClass: PendingDecision[\"actionClass\"];\n capabilityClass: PendingDecision[\"capabilityClass\"];\n confidence: number;\n humanReviewRequired: boolean;\n diffSummary: string;\n evidence: PendingDecision[\"evidence\"];\n applyAllowed: boolean;\n};\n\nconst SENSITIVE_PERSONA_FILES = new Set<string>(PERSONA_PROPOSAL_SENSITIVE_TARGET_FILES);\nconst CRITICAL_TARGETS = new Set<string>(PERSONA_PROPOSAL_CRITICAL_TARGET_FILES);\nconst LOW_RISK_DRIFT_THRESHOLD = 2;\nconst SENSITIVE_TOOLS_RE = /^TOOLS\\.md$/i;\n\nfunction normalizePersonaProposalTriageMax(max: number | undefined): number {\n if (max === undefined) return 20;\n if (!Number.isFinite(max) || !Number.isInteger(max) || max < 0) {\n throw new Error(`persona proposal triage max must be a non-negative finite integer. Got: ${max}`);\n }\n return max;\n}\n\nexport function createPersonaProposalTriageAdapter(input: {\n proposalsDb: ProposalsDB;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n workspace?: string;\n allProposals?: ProposalEntry[];\n proposalId?: string;\n}): PendingQueueAdapter<PersonaProposalPendingItem> & {\n proposalsDb: ProposalsDB;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n workspace: string;\n} {\n return {\n queue: \"persona\",\n listPending: (cursor) => listPersonaProposalItems(input, cursor),\n decide: (item, context) => decidePersonaProposal(item, context, input),\n apply: () => {\n throw new Error(\"Use runPersonaProposalTriage for lock/CAS guarded apply semantics.\");\n },\n proposalsDb: input.proposalsDb,\n cfg: input.cfg,\n workspace: input.workspace ?? defaultWorkspace(),\n };\n}\n\nexport async function runPersonaProposalTriage(\n opts: PersonaProposalTriageOptions,\n): Promise<PersonaProposalTriageResult> {\n const mode = opts.mode ?? \"dry-run\";\n const policy = opts.policy ?? \"report-only\";\n validatePersonaPolicy(policy);\n if (mode !== \"dry-run\" && mode !== \"apply\") throw new Error(`Unsupported mode: ${mode}`);\n const max = normalizePersonaProposalTriageMax(opts.max);\n const runId = opts.runId ?? createPendingAutopilotRunId();\n const actor = opts.actor ?? ({ type: \"agent\", id: \"persona-proposal-triage\" } as const);\n const workspace = opts.workspace ?? defaultWorkspace();\n const stateDbPath = opts.stateDbPath ?? join(workspace, \"memory\", \"pending-autopilot.db\");\n const manageRunLifecycle = opts.runLifecycle !== \"embedded\";\n let store: PendingAutopilotStore | null = null;\n const allProposals = opts.proposalsDb.list();\n const adapter = createPersonaProposalTriageAdapter({\n proposalsDb: opts.proposalsDb,\n cfg: opts.cfg,\n workspace,\n allProposals,\n proposalId: opts.proposalId,\n });\n const decisions: PendingDecision[] = [];\n const views: PersonaProposalDecisionView[] = [];\n const startedAt = Math.floor((opts.now ?? new Date()).getTime() / 1000);\n const runInputHash = computePendingInputHash({ command: \"proposals triage\", mode, policy, max, startedAt: 0 });\n let cursorAdvanceCandidate: { decision: PendingDecision; cursor: string } | null = null;\n let cursorAdvanceBlocked = false;\n const ownStore = !opts.store;\n\n try {\n store =\n opts.store ?? (mode === \"apply\" && policy !== \"report-only\" ? new PendingAutopilotStore(stateDbPath) : null);\n if (manageRunLifecycle) {\n store?.createRun({\n runId,\n mode,\n policy,\n policyVersion: PERSONA_PROPOSAL_TRIAGE_POLICY_VERSION,\n inputHash: runInputHash,\n queues: [\"persona\"],\n startedAt,\n });\n }\n\n const cursor = store?.getCursor(\"persona\", policy) ?? null;\n const listed = await adapter.listPending(cursor);\n const pending = listed.slice(0, max);\n for (const item of pending) {\n const context: PendingDecisionContext = {\n runId,\n jobId: opts.jobId,\n mode,\n policy,\n policyVersion: PERSONA_PROPOSAL_TRIAGE_POLICY_VERSION,\n inputHash: item.inputHash,\n actor,\n };\n const freshProposals = mode === \"apply\" ? opts.proposalsDb.list() : allProposals;\n const freshAdapter =\n mode === \"apply\"\n ? createPersonaProposalTriageAdapter({\n proposalsDb: opts.proposalsDb,\n cfg: opts.cfg,\n workspace,\n allProposals: freshProposals,\n proposalId: opts.proposalId,\n })\n : adapter;\n let decision = await freshAdapter.decide(item, context);\n if (mode === \"apply\" && policy !== \"report-only\" && isMutationDecision(decision)) {\n if (!store) throw new Error(\"apply mode requires pending-autopilot store\");\n decision = applyPersonaDecisionWithLock({\n store,\n proposalsDb: opts.proposalsDb,\n item,\n decision,\n workspace,\n cfg: opts.cfg,\n });\n if (decision.action === \"failed-validation\") {\n store.recordDecision(decision);\n } else {\n // Successful mutation decisions are already recorded inside mutateWithLockAndAudit\n }\n } else if (policy !== \"report-only\") {\n store?.recordDecision(decision);\n }\n const itemCursor = item.visibleAfterCursor ?? item.id;\n if (shouldAdvancePendingCursor(decision)) {\n if (!cursorAdvanceBlocked) {\n cursorAdvanceCandidate = { decision, cursor: itemCursor };\n }\n } else {\n cursorAdvanceBlocked = true;\n }\n decisions.push(decision);\n views.push(decisionToView(item, decision));\n }\n if (\n policy !== \"report-only\" &&\n opts.proposalId === undefined &&\n cursorAdvanceCandidate !== null &&\n pending.length > 0\n ) {\n store?.advanceCursorIfSafe(cursorAdvanceCandidate.decision, cursorAdvanceCandidate.cursor);\n }\n\n const summary = createStableRunSummary({\n runId,\n mode,\n policy,\n policyVersion: PERSONA_PROPOSAL_TRIAGE_POLICY_VERSION,\n queues: [\"persona\"],\n startedAt,\n finishedAt: Math.floor((opts.now ?? new Date()).getTime() / 1000),\n decisions,\n });\n if (manageRunLifecycle) {\n store?.finishRun(runId, summary);\n }\n const result: PersonaProposalTriageResult = {\n schemaVersion: 1,\n runId,\n mode,\n policy,\n policyVersion: PERSONA_PROPOSAL_TRIAGE_POLICY_VERSION,\n counts: countPersonaDecisions(decisions),\n decisions: views,\n bundles: buildPersonaReviewBundles(views),\n humanSummary: \"\",\n };\n result.humanSummary = renderPersonaProposalTriageHumanSummary(result);\n return result;\n } finally {\n if (ownStore) {\n store?.close();\n }\n }\n}\n\nexport function stablePersonaProposalTriageJson(result: PersonaProposalTriageResult): string {\n return `${canonicalJson(redactAutopilotValue(result))}\\n`;\n}\n\nexport function renderPersonaProposalTriageHumanSummary(result: PersonaProposalTriageResult): string {\n const lines = [\n `Persona proposal triage ${result.runId} (${result.mode}, policy=${result.policy})`,\n `Inspected ${result.counts.inspected}; auto-rejected ${result.counts.autoRejected}; auto-applied ${result.counts.autoApplied}; deferred ${result.counts.deferredForHuman}; failed ${result.counts.failedValidation}.`,\n ];\n if (result.bundles.length > 0) {\n lines.push(\"Review bundles:\");\n for (const bundle of result.bundles) {\n lines.push(\n `- ${bundle.id}: ${bundle.proposalIds.length} proposal(s), target=${bundle.targetFile}, risk=${bundle.risk}, recommendation=${bundle.recommendation}, reasons=${bundle.reasons.join(\",\")}`,\n );\n }\n } else {\n lines.push(\"Review bundles: none.\");\n }\n lines.push(\n result.mode === \"dry-run\"\n ? \"Dry-run wrote no proposal state, target files, or durable pending-autopilot state.\"\n : \"Apply mode used shared pending-autopilot lock/CAS decision recording before any proposal/file mutation.\",\n );\n return lines.join(\"\\n\");\n}\n\nexport function decidePersonaProposal(\n item: PersonaProposalPendingItem,\n context: PendingDecisionContext,\n input: {\n proposalsDb: ProposalsDB;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n workspace?: string;\n allProposals?: ProposalEntry[];\n },\n): PendingDecision {\n const all = input.allProposals ?? input.proposalsDb.list();\n const analysis = analyzePersonaProposal(item, context.policy as PersonaProposalTriagePolicy, all);\n const reportOnly = context.policy === \"report-only\";\n const readOnlyCapability = context.mode === \"dry-run\" ? \"dry-run\" : \"read-only\";\n const action = reportOnly ? \"reported\" : analysis.action;\n const actionClass = reportOnly ? \"observe\" : analysis.actionClass;\n const capabilityClass = reportOnly ? readOnlyCapability : analysis.capabilityClass;\n const isSecurityCritical =\n analysis.reasonCode === \"security-boundary-change\" ||\n analysis.reasonCode === \"secret-or-private-data-risk\" ||\n analysis.reasonCode === \"privacy-boundary-change\";\n const humanReviewRequired = reportOnly\n ? isSecurityCritical\n ? analysis.humanReviewRequired\n : false\n : analysis.humanReviewRequired;\n\n return {\n queue: \"persona\",\n itemId: item.id,\n inputHash: item.inputHash,\n policy: context.policy,\n policyVersion: context.policyVersion,\n mode: context.mode,\n action,\n reasonCode: analysis.reasonCode,\n actionClass,\n capabilityClass,\n confidence: analysis.confidence,\n humanReviewRequired,\n evidence: analysis.evidence,\n actor: context.actor,\n runId: context.runId,\n jobId: context.jobId,\n summary: {\n title: item.proposal.title,\n body: analysis.diffSummary,\n metadata: {\n targetFile: item.proposal.targetFile,\n risk: analysis.risk,\n targetHash: item.targetHash,\n proposalHash: item.payload.proposalHash,\n },\n },\n audit: {\n queue: \"persona\",\n itemId: item.id,\n inputHash: item.inputHash,\n policy: context.policy,\n policyVersion: context.policyVersion,\n action,\n reasonCode: analysis.reasonCode,\n capabilityClass,\n humanReviewRequired,\n evidence: analysis.evidence,\n actor: context.actor,\n runId: context.runId,\n jobId: context.jobId,\n summary: {\n title: item.proposal.title,\n body: analysis.diffSummary,\n metadata: {\n targetFile: item.proposal.targetFile,\n proposalHash: item.payload.proposalHash,\n targetHash: item.targetHash,\n risk: analysis.risk,\n },\n },\n },\n };\n}\n\nfunction listPersonaProposalItems(\n input: {\n proposalsDb: ProposalsDB;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n workspace?: string;\n proposalId?: string;\n },\n cursor?: PendingAutopilotCursor | null,\n): PersonaProposalPendingItem[] {\n if (!input.cfg.personaProposals.enabled) return [];\n const pending = input.proposalsDb.list({ status: \"pending\" });\n const workspace = input.workspace ?? defaultWorkspace();\n return pending\n .sort(comparePersonaProposalNewestFirst)\n .filter((proposal) => input.proposalId === undefined || proposal.id === input.proposalId)\n .filter((proposal) => isVisibleAfterPersonaCursor(proposal, cursor))\n .map((proposal) => proposalToPendingItem(proposal, workspace, input.cfg));\n}\n\nfunction isVisibleAfterPersonaCursor(proposal: ProposalEntry, cursor?: PendingAutopilotCursor | null): boolean {\n if (!cursor?.cursor) return true;\n if (proposal.createdAt >= cursor.updatedAt) return true;\n // Persona proposals are listed newest-first by ProposalsDB. A durable cursor\n // therefore means \"the newest processed boundary\" for the already-seen backlog,\n // and subsequent pages must move toward older proposals without hiding proposals\n // created after the cursor was advanced.\n return comparePersonaCursor(proposalCursor(proposal), cursor.cursor) < 0;\n}\n\nfunction proposalCursor(proposal: Pick<ProposalEntry, \"createdAt\" | \"id\">): string {\n return `${proposal.createdAt.toString().padStart(12, \"0\")}:${proposal.id}`;\n}\n\nfunction comparePersonaCursor(a: string, b: string): number {\n return a.localeCompare(b);\n}\n\nfunction comparePersonaProposalNewestFirst(a: ProposalEntry, b: ProposalEntry): number {\n return comparePersonaCursor(proposalCursor(b), proposalCursor(a));\n}\n\nfunction proposalToPendingItem(\n proposal: ProposalEntry,\n workspace: string,\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">,\n policyVersion = PERSONA_PROPOSAL_TRIAGE_POLICY_VERSION,\n): PersonaProposalPendingItem {\n const target = resolveAllowedPersonaTarget(workspace, proposal.targetFile, cfg.personaProposals.allowedFiles);\n let targetHash: string | null = null;\n if (target.ok) {\n try {\n targetHash = existsSync(target.path) ? fileHash(target.path) : null;\n } catch {\n targetHash = null;\n }\n }\n const proposalHash = computePendingInputHash({\n id: proposal.id,\n targetFile: proposal.targetFile,\n title: proposal.title,\n observation: proposal.observation,\n suggestedChange: proposal.suggestedChange,\n confidence: proposal.confidence,\n evidenceSessions: proposal.evidenceSessions,\n targetHash: proposal.targetHash ?? null,\n targetMtimeMs: proposal.targetMtimeMs ?? null,\n });\n const payload: PersonaProposalPayload = {\n proposalId: proposal.id,\n targetFile: proposal.targetFile,\n title: proposal.title,\n confidence: proposal.confidence,\n evidenceSessions: proposal.evidenceSessions,\n createdAt: proposal.createdAt,\n targetHash: proposal.targetHash ?? null,\n proposalHash,\n };\n return {\n queue: \"persona\",\n id: proposal.id,\n inputHash: computePendingInputHash({\n queue: \"persona\",\n id: proposal.id,\n payload,\n policyVersion,\n }),\n policyVersion,\n capabilityClasses: [\"read-only\", \"safe-state-transition\", \"apply-low-risk-change\"],\n payload,\n visibleAfterCursor: proposalCursor(proposal),\n requiresHumanReview: true,\n proposal,\n targetPath: target.path,\n targetValid: target.ok,\n targetHash,\n workspace,\n };\n}\n\nfunction analyzePersonaProposal(\n item: PersonaProposalPendingItem,\n policy: PersonaProposalTriagePolicy,\n allProposals: ProposalEntry[],\n): Analysis {\n const p = item.proposal;\n const text = `${p.title}\\n${p.observation}\\n${p.suggestedChange}`;\n const evidence = buildEvidence(p);\n if (!item.targetValid) {\n return failed(\"critical\", \"validation-failed\", `Target path rejected for ${p.targetFile}`, evidence, 0.1);\n }\n if (containsSecretOrPrivateData(text)) {\n return rejectOrDefer(\n policy,\n \"critical\",\n \"secret-or-private-data-risk\",\n \"Secret/private-data risk detected; [REDACTED] raw content.\",\n evidence,\n 1,\n );\n }\n if (containsPromptInjection(text)) {\n return defer(\n \"critical\",\n \"security-boundary-change\",\n \"Prompt-injection language is untrusted and cannot affect policy gates.\",\n evidence,\n 1,\n );\n }\n if (p.confidence < PERSONA_REJECT_CONFIDENCE_THRESHOLD) {\n return rejectOrDefer(\n policy,\n \"low\",\n \"low-confidence\",\n `Confidence ${p.confidence.toFixed(2)} below ${PERSONA_REJECT_CONFIDENCE_THRESHOLD}.`,\n evidence,\n 1,\n );\n }\n if (isNonActionable(p.suggestedChange)) {\n return rejectOrDefer(\n policy,\n \"low\",\n \"non-actionable\",\n \"Proposal lacks an actionable localized change.\",\n evidence,\n 0.95,\n );\n }\n const duplicate = findDuplicate(p, allProposals);\n if (duplicate?.status === \"applied\") {\n return rejectOrDefer(\n policy,\n \"low\",\n \"duplicate-applied-proposal\",\n `Duplicates already-applied proposal ${duplicate.id}.`,\n evidence,\n 1,\n );\n }\n if (duplicate?.status === \"pending\") {\n return rejectOrDefer(\n policy,\n \"low\",\n \"duplicate-pending-proposal\",\n `Duplicates pending proposal ${duplicate.id}.`,\n evidence,\n 1,\n );\n }\n if (isStaleTarget(item)) {\n return rejectOrDefer(\n policy,\n \"low\",\n \"stale-target-context\",\n \"Target snapshot changed since proposal creation; safe rebase unavailable.\",\n evidence,\n 1,\n );\n }\n const risk = classifyRisk(p, item);\n const diffSummary = summarizeDiff(p, item);\n if (policy === \"report-only\") return report(risk, \"policy-report-only\", diffSummary, evidence, p.confidence);\n if (risk === \"high\" || risk === \"critical\") {\n return defer(risk, highRiskReason(p), diffSummary, evidence, p.confidence);\n }\n if (risk === \"medium\") {\n return defer(\"medium\", \"policy-requires-human\", diffSummary, evidence, p.confidence);\n }\n if (!hasEvidence(p)) return defer(\"low\", \"missing-evidence\", diffSummary, evidence, p.confidence);\n if (policy !== \"apply-safe\") return defer(\"low\", \"policy-requires-human\", diffSummary, evidence, p.confidence);\n if (!hasReliableTargetSnapshot(p)) {\n return defer(\n \"low\",\n \"stale-target-context\",\n \"Auto-apply requires target hash or mtime snapshot.\",\n evidence,\n p.confidence,\n );\n }\n if (p.confidence < PERSONA_APPLY_CONFIDENCE_THRESHOLD) {\n return defer(\"low\", \"low-confidence\", diffSummary, evidence, p.confidence);\n }\n const drift = lowRiskDriftGuard(p, allProposals);\n if (drift.blocked) {\n return defer(\"low\", \"policy-requires-human\", `${diffSummary}; ${drift.summary}`, evidence, p.confidence);\n }\n return {\n risk: \"low\",\n action: \"applied\",\n reasonCode: \"safe-low-risk-localized-change\",\n actionClass: \"low-risk-apply\",\n capabilityClass: \"apply-low-risk-change\",\n confidence: p.confidence,\n humanReviewRequired: false,\n diffSummary,\n evidence,\n applyAllowed: true,\n };\n}\n\nfunction applyPersonaDecisionWithLock(input: {\n store: PendingAutopilotStore;\n proposalsDb: ProposalsDB;\n item: PersonaProposalPendingItem;\n decision: PendingDecision;\n workspace: string;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n}): PendingDecision {\n const owner = `${input.decision.runId}:persona-triage`;\n const locked = input.store.acquireLock({\n queue: \"persona\",\n itemId: input.item.id,\n inputHash: input.item.inputHash,\n owner,\n ttlSeconds: 120,\n mode: input.decision.mode,\n });\n if (!locked) return validationFailure(input.decision, \"lock-conflict\", \"Could not acquire persona proposal lock.\");\n try {\n const current = input.proposalsDb.get(input.item.id);\n if (!current || current.status !== \"pending\") {\n return validationFailure(input.decision, \"already-processed\", \"Proposal was already processed before apply.\");\n }\n const actualHash = proposalToPendingItem(current, input.workspace, input.cfg).inputHash;\n if (actualHash !== input.decision.inputHash) {\n return validationFailure(\n input.decision,\n \"input-hash-mismatch\",\n \"Proposal changed between classification and apply.\",\n );\n }\n let preparedApply:\n | {\n targetPath: string;\n backupPath: string;\n original: string;\n appliedContent: string;\n preHash: string;\n postHash: string;\n auditDiff: string;\n }\n | undefined;\n if (input.decision.action === \"applied\") {\n const currentTarget = resolveAllowedPersonaTarget(\n input.workspace,\n current.targetFile,\n input.cfg.personaProposals.allowedFiles,\n );\n if (!currentTarget.ok || !existsSync(currentTarget.path)) {\n return validationFailure(\n input.decision,\n \"stale-target-context\",\n \"Target file unavailable during apply revalidation.\",\n );\n }\n const currentSnapshot = getFileSnapshot(currentTarget.path);\n if (!currentSnapshot) {\n return validationFailure(\n input.decision,\n \"stale-target-context\",\n \"Target file unreadable during apply revalidation.\",\n );\n }\n if (!hasReliableTargetSnapshot(current)) {\n return validationFailure(\n input.decision,\n \"stale-target-context\",\n \"Auto-apply requires target hash or mtime snapshot.\",\n );\n }\n if (current.targetHash && current.targetHash !== currentSnapshot.hash) {\n return validationFailure(input.decision, \"input-hash-mismatch\", \"Target file changed before apply.\");\n }\n if (!current.targetHash && current.targetMtimeMs != null && current.targetMtimeMs !== currentSnapshot.mtimeMs) {\n return validationFailure(input.decision, \"input-hash-mismatch\", \"Target mtime changed before apply.\");\n }\n const original = readFileSync(currentTarget.path, \"utf-8\");\n const applied = buildAppliedContent(original, current, new Date().toISOString());\n if (!applied.content.trim()) {\n return validationFailure(\n input.decision,\n \"validation-failed\",\n `Proposal ${input.item.id} does not contain replacement content to apply.`,\n );\n }\n if (!isAllowedSensitivePersonaApply(current.targetFile, original, applied.content, current.suggestedChange)) {\n return validationFailure(\n input.decision,\n \"identity-boundary-change\",\n \"Sensitive persona files require mechanically verified formatting-only diffs for apply-safe auto-apply.\",\n );\n }\n const auditDiff = redactedAuditDiff(original, applied.content, current.targetFile);\n preparedApply = {\n targetPath: currentTarget.path,\n backupPath: `${currentTarget.path}.backup-${Date.now()}`,\n original,\n appliedContent: applied.content,\n preHash: currentSnapshot.hash,\n postHash: hashText(applied.content),\n auditDiff,\n };\n }\n\n const decisionForMutation = preparedApply ? withPersonaApplyAudit(input.decision, preparedApply) : input.decision;\n const ok = input.store.mutateWithLockAndAudit({\n decision: decisionForMutation,\n owner,\n actualInputHash: actualHash,\n audit: () => {},\n mutate: () => {\n if (decisionForMutation.action === \"rejected\") {\n input.proposalsDb.updateStatus(input.item.id, \"rejected\", \"persona-triage\", decisionForMutation.reasonCode);\n } else if (decisionForMutation.action === \"applied\" && preparedApply) {\n applyPreparedPersonaChange(preparedApply, () => input.proposalsDb.markApplied(input.item.id));\n }\n },\n });\n if (!ok) return validationFailure(input.decision, \"input-hash-mismatch\", \"Lock/CAS/audit mutation rejected.\");\n return decisionForMutation;\n } finally {\n input.store.releaseLock({\n queue: \"persona\",\n itemId: input.item.id,\n inputHash: input.item.inputHash,\n owner,\n mode: input.decision.mode,\n });\n }\n}\n\nfunction validationFailure(\n decision: PendingDecision,\n reasonCode: PendingDecision[\"reasonCode\"],\n body: string,\n): PendingDecision {\n const capabilityClass = decision.mode === \"dry-run\" ? \"dry-run\" : \"read-only\";\n return {\n ...decision,\n action: \"failed-validation\",\n reasonCode,\n actionClass: \"observe\",\n capabilityClass,\n confidence: 0,\n humanReviewRequired: true,\n summary: { ...(decision.summary ?? {}), body },\n audit: decision.audit\n ? {\n ...decision.audit,\n action: \"failed-validation\",\n reasonCode,\n capabilityClass,\n humanReviewRequired: true,\n }\n : undefined,\n };\n}\n\nfunction decisionToView(item: PersonaProposalPendingItem, decision: PendingDecision): PersonaProposalDecisionView {\n const metadata = decision.summary?.metadata ?? {};\n return {\n proposalId: item.id,\n targetFile: item.proposal.targetFile,\n risk: (metadata.risk as PersonaProposalRisk | undefined) ?? \"medium\",\n action: decision.action,\n reason: decision.reasonCode,\n capability: decision.capabilityClass,\n confidence: decision.confidence,\n humanReviewRequired: decision.humanReviewRequired,\n evidence: decision.evidence,\n diffSummary: String(decision.summary?.body ?? \"\"),\n inputHash: decision.inputHash,\n targetHash: item.targetHash,\n };\n}\n\nfunction buildPersonaReviewBundles(views: PersonaProposalDecisionView[]): PersonaProposalReviewBundle[] {\n const reviewable = views.filter(\n (v) => v.humanReviewRequired || v.action === \"reported\" || v.action === \"deferred-for-human\",\n );\n const groups = new Map<string, PersonaProposalDecisionView[]>();\n for (const view of reviewable) {\n const semanticTopic = topicKey(\n view.evidence\n .map((entry) => entry.summary)\n .filter(Boolean)\n .join(\"\\n\"),\n );\n const key = `${view.targetFile}:${view.risk}:${view.reason}:${semanticTopic}`;\n groups.set(key, [...(groups.get(key) ?? []), view]);\n }\n return [...groups.values()].map((items, idx) => {\n const risk = maxRisk(items.map((i) => i.risk));\n const targetFile = items[0]?.targetFile ?? \"unknown\";\n const reasons = [...new Set(items.map((i) => i.reason))];\n const proposalIds = items.map((i) => i.proposalId);\n return {\n id: `persona-bundle-${idx + 1}`,\n targetFile,\n risk,\n recommendation:\n risk === \"low\" && reasons.every((r) => r.startsWith(\"duplicate\") || r === \"non-actionable\")\n ? \"reject\"\n : \"defer\",\n proposalIds,\n reasons,\n rationale: `Grouped by target=${targetFile}, risk=${risk}, and shared topic. Review each proposal independently before approval.`,\n commands: proposalIds.flatMap((id) => [\n `openclaw hybrid-mem proposals show ${id} --diff`,\n `openclaw hybrid-mem proposals reject ${id} --reason <reason>`,\n ]),\n evidence: items.flatMap((i) => i.evidence),\n diffPreview: items.map((i) => `[${i.proposalId}] ${i.diffSummary}`).join(\"\\n\"),\n };\n });\n}\n\nfunction countPersonaDecisions(decisions: PendingDecision[]): PersonaProposalTriageResult[\"counts\"] {\n return {\n inspected: decisions.length,\n classified: decisions.filter((d) => d.action === \"classified\" || d.action === \"reported\").length,\n grouped: decisions.filter(\n (d) => d.humanReviewRequired || d.action === \"reported\" || d.action === \"deferred-for-human\",\n ).length,\n autoRejected: decisions.filter((d) => d.action === \"rejected\").length,\n autoApplied: decisions.filter((d) => d.action === \"applied\").length,\n deferredForHuman: decisions.filter((d) => d.action === \"deferred-for-human\").length,\n failedValidation: decisions.filter((d) => d.action === \"failed-validation\").length,\n skippedByPolicy: decisions.filter((d) => d.action === \"skipped-by-policy\").length,\n };\n}\n\nfunction rejectOrDefer(\n policy: PersonaProposalTriagePolicy,\n risk: PersonaProposalRisk,\n reasonCode: PendingDecision[\"reasonCode\"],\n diffSummary: string,\n evidence: PendingDecision[\"evidence\"],\n confidence: number,\n): Analysis {\n if (policy === \"cautious\" || policy === \"apply-safe\") {\n return {\n risk,\n action: \"rejected\",\n reasonCode,\n actionClass: \"state-transition\",\n capabilityClass: \"safe-state-transition\",\n confidence,\n humanReviewRequired: false,\n diffSummary,\n evidence,\n applyAllowed: false,\n };\n }\n return report(risk, reasonCode, diffSummary, evidence, confidence);\n}\n\nfunction defer(\n risk: PersonaProposalRisk,\n reasonCode: PendingDecision[\"reasonCode\"],\n diffSummary: string,\n evidence: PendingDecision[\"evidence\"],\n confidence: number,\n): Analysis {\n return {\n risk,\n action: \"deferred-for-human\",\n reasonCode,\n actionClass: \"record-review\",\n capabilityClass: \"record-review-metadata\",\n confidence,\n humanReviewRequired: true,\n diffSummary,\n evidence,\n applyAllowed: false,\n };\n}\n\nfunction report(\n risk: PersonaProposalRisk,\n reasonCode: PendingDecision[\"reasonCode\"],\n diffSummary: string,\n evidence: PendingDecision[\"evidence\"],\n confidence: number,\n): Analysis {\n return {\n risk,\n action: \"reported\",\n reasonCode,\n actionClass: \"observe\",\n capabilityClass: \"read-only\",\n confidence,\n humanReviewRequired: false,\n diffSummary,\n evidence,\n applyAllowed: false,\n };\n}\n\nfunction failed(\n risk: PersonaProposalRisk,\n reasonCode: PendingDecision[\"reasonCode\"],\n diffSummary: string,\n evidence: PendingDecision[\"evidence\"],\n confidence: number,\n): Analysis {\n return {\n risk,\n action: \"failed-validation\",\n reasonCode,\n actionClass: \"observe\",\n capabilityClass: \"read-only\",\n confidence,\n humanReviewRequired: true,\n diffSummary,\n evidence,\n applyAllowed: false,\n };\n}\n\nfunction classifyRisk(p: ProposalEntry, item: PersonaProposalPendingItem): PersonaProposalRisk {\n const text = `${p.title}\n${p.observation}\n${p.suggestedChange}`.toLowerCase();\n if (/\\b(destructive|credential)\\b|approval boundary|bypass approval|disable safeguard/.test(text)) return \"critical\";\n if (isCriticalTarget(p.targetFile)) {\n if (SENSITIVE_PERSONA_FILES.has(p.targetFile)) {\n if (!isMechanicallyVerifiedSensitiveFormatting(item, p.suggestedChange)) return \"high\";\n return \"low\";\n }\n if (!isCriticalTargetFormattingOnly(p.suggestedChange)) return \"high\";\n if (/\\b(privacy|security|approval|credential|destructive|safeguard)\\b/.test(text)) return \"high\";\n if (item.targetHash && normalizeText(p.suggestedChange).length < 240) return \"low\";\n return \"medium\";\n }\n if (\n /\\b(identit(?:y|ies)|personalit(?:y|ies)|voice|tone|privacy|security|external|group chat|user preferences?|profile|personal facts?|memory rules?)\\b/.test(\n text,\n )\n ) {\n return \"high\";\n }\n if (/\\b(preference|workflow|routing|project context|communication)\\b/.test(text)) return \"medium\";\n if (isLargeOrBroadDiff(p)) return \"medium\";\n if (item.targetHash && normalizeText(p.suggestedChange).length < 240) return \"low\";\n return \"medium\";\n}\n\nfunction isCriticalTargetFormattingOnly(suggestedChange: string): boolean {\n const parsed = parseSuggestedChange(suggestedChange);\n if (parsed.changeType !== \"replace\") return false;\n const hasFormattingKeywords = /\\b(formatting|typo|whitespace|punctuation)\\b/i.test(suggestedChange);\n if (!hasFormattingKeywords) return false;\n const containsSemanticKeywords =\n /\\b(personalit(?:y|ies)|voice|tone|behaviou?r(?:al)?|instructions?|responses?|reply|replies|always|never|must|should|redirect|defer|escalate|refer|contact|route|forward|delegate|friendlier|friendly|warmer|casual|greeting)\\b/i.test(\n suggestedChange,\n );\n return !containsSemanticKeywords;\n}\n\nfunction isMechanicallyVerifiedSensitiveFormatting(item: PersonaProposalPendingItem, suggestedChange: string): boolean {\n const parsed = parseSuggestedChange(suggestedChange);\n if (parsed.changeType !== \"replace\" || !item.targetHash || !item.targetValid || !existsSync(item.targetPath))\n return false;\n try {\n const original = readFileSync(item.targetPath, \"utf-8\");\n return stripWhitespaceAndPunctuation(original) === stripWhitespaceAndPunctuation(parsed.content);\n } catch {\n return false;\n }\n}\n\nfunction lowRiskDriftGuard(\n proposal: ProposalEntry,\n allProposals: ProposalEntry[],\n): { blocked: boolean; summary: string } {\n const target = proposal.targetFile;\n const topic = topicKey(`${proposal.title}\\n${proposal.observation}\\n${proposal.suggestedChange}`);\n const previous = allProposals.filter(\n (candidate) =>\n candidate.id !== proposal.id &&\n candidate.status === \"applied\" &&\n candidate.targetFile === target &&\n normalizeText(candidate.suggestedChange).length < 240 &&\n topicKey(`${candidate.title}\\n${candidate.observation}\\n${candidate.suggestedChange}`) === topic,\n );\n if (previous.length >= LOW_RISK_DRIFT_THRESHOLD) {\n return {\n blocked: true,\n summary: `cumulative low-risk drift guard: ${previous.length} previous auto-applied edit(s) for ${target}/${topic}`,\n };\n }\n return { blocked: false, summary: \"\" };\n}\n\nfunction isAllowedSensitivePersonaApply(\n targetFile: string,\n original: string,\n applied: string,\n suggestedChange: string,\n): boolean {\n if (!isCriticalTarget(targetFile)) return true;\n const parsed = parseSuggestedChange(suggestedChange);\n if (parsed.changeType !== \"replace\") return false;\n return stripWhitespaceAndPunctuation(original) === stripWhitespaceAndPunctuation(applied);\n}\n\nfunction stripWhitespaceAndPunctuation(input: string): string {\n return input.replace(/[\\s\\p{P}]+/gu, \"\").toLowerCase();\n}\n\nfunction withPersonaApplyAudit(\n decision: PendingDecision,\n preparedApply: { preHash: string; postHash: string; auditDiff: string },\n): PendingDecision {\n const metadata = {\n ...(decision.summary?.metadata ?? {}),\n targetPreHash: preparedApply.preHash,\n targetPostHash: preparedApply.postHash,\n };\n const summary = {\n ...(decision.summary ?? {}),\n metadata: {\n ...metadata,\n redactedBeforeAfterDiff: preparedApply.auditDiff,\n },\n };\n return {\n ...decision,\n summary,\n audit: decision.audit\n ? {\n ...decision.audit,\n summary: {\n ...(decision.audit.summary ?? {}),\n metadata: {\n ...(decision.audit.summary?.metadata ?? {}),\n ...metadata,\n redactedBeforeAfterDiff: preparedApply.auditDiff,\n },\n },\n }\n : undefined,\n };\n}\n\nfunction redactedAuditDiff(original: string, applied: string, targetFile: string): string {\n let diff: string;\n try {\n diff = buildUnifiedDiff(original, applied, targetFile);\n } catch {\n diff = `--- ${targetFile} (before)\n+++ ${targetFile} (after)\n@@ before\n${original}\n@@ after\n${applied}`;\n }\n const redacted = String(redactAutopilotValue(diff));\n return redacted.length > 8000\n ? `${redacted.slice(0, 8000)}\n... [diff truncated]`\n : redacted;\n}\n\nfunction highRiskReason(p: ProposalEntry): PendingDecision[\"reasonCode\"] {\n const text = `${p.title}\\n${p.observation}\\n${p.suggestedChange}`.toLowerCase();\n if (/privacy/.test(text)) return \"privacy-boundary-change\";\n if (/security|credential|approval|destructive|safeguard/.test(text)) return \"security-boundary-change\";\n if (/preference|profile|personal fact|user preference/.test(text)) return \"user-preference-change-requires-approval\";\n return \"identity-boundary-change\";\n}\n\nfunction isCriticalTarget(targetFile: string): boolean {\n return CRITICAL_TARGETS.has(targetFile) || SENSITIVE_TOOLS_RE.test(targetFile);\n}\n\nfunction isMutationDecision(decision: PendingDecision): boolean {\n return decision.mode === \"apply\" && (decision.action === \"rejected\" || decision.action === \"applied\");\n}\n\nfunction isStaleTarget(item: PersonaProposalPendingItem): boolean {\n return Boolean(item.proposal.targetHash && item.targetHash && item.proposal.targetHash !== item.targetHash);\n}\n\nfunction hasReliableTargetSnapshot(proposal: Pick<ProposalEntry, \"targetHash\" | \"targetMtimeMs\">): boolean {\n return Boolean(proposal.targetHash || proposal.targetMtimeMs != null);\n}\n\nfunction findDuplicate(proposal: ProposalEntry, all: ProposalEntry[]): ProposalEntry | null {\n const normalized = normalizeText(proposal.suggestedChange);\n if (!normalized) return null;\n const candidates = all.filter(\n (c) =>\n c.id !== proposal.id &&\n c.targetFile === proposal.targetFile &&\n (c.status === \"applied\" || c.status === \"pending\") &&\n normalizeText(c.suggestedChange) === normalized,\n );\n if (candidates.length === 0) return null;\n\n const appliedDuplicate = candidates\n .filter((c) => c.status === \"applied\")\n .sort((a, b) => a.createdAt - b.createdAt)[0];\n if (appliedDuplicate) return appliedDuplicate;\n\n const earlierPending = candidates\n .filter((c) => c.status === \"pending\" && compareProposalCreationOrder(c, proposal) < 0)\n .sort(compareProposalCreationOrder)[0];\n return earlierPending ?? null;\n}\n\nfunction compareProposalCreationOrder(\n a: Pick<ProposalEntry, \"createdAt\" | \"id\">,\n b: Pick<ProposalEntry, \"createdAt\" | \"id\">,\n): number {\n const createdAtDelta = a.createdAt - b.createdAt;\n if (createdAtDelta !== 0) return createdAtDelta;\n return a.id.localeCompare(b.id);\n}\n\nconst NON_ACTIONABLE_PHRASES = new Set([\n \"be better\",\n \"improve\",\n \"do better\",\n \"fix this\",\n \"update\",\n \"change\",\n \"misc\",\n \"note\",\n]);\n\nfunction isNonActionable(change: string): boolean {\n const normalized = normalizeText(change);\n if (normalized.length === 0) return true;\n if (NON_ACTIONABLE_PHRASES.has(normalized)) return true;\n\n const directiveVerbs =\n /\\b(add|append|record|capture|document|replace|remove|delete|update|clarify|format|fix|rewrite|rename|prefer|avoid|use|mention|store|include)\\b/i;\n const hasTargetOrLocation =\n /\\b(soul\\.md|user\\.md|identity\\.md|agents\\.md|tools\\.md|section|heading|paragraph|line|bullet|preference|guidance|instruction|file|document)\\b/i.test(\n change,\n );\n\n return normalized.length < 12 && !directiveVerbs.test(change) && !hasTargetOrLocation;\n}\n\nfunction isLargeOrBroadDiff(p: ProposalEntry): boolean {\n const lines = p.suggestedChange.split(/\\r?\\n/).filter((line) => line.trim());\n return lines.length > 12 || p.suggestedChange.length > 1200 || /^\\s*replace\\b/i.test(p.suggestedChange);\n}\n\nfunction hasEvidence(p: ProposalEntry): boolean {\n return Array.isArray(p.evidenceSessions) && p.evidenceSessions.length > 0;\n}\n\nfunction summarizeDiff(p: ProposalEntry, item: PersonaProposalPendingItem): string {\n const change = redactAutopilotValue(p.suggestedChange) as string;\n const lines = String(change)\n .split(/\\r?\\n/)\n .filter((line) => line.trim());\n return `${safeActionVerb(p)} ${lines.length} non-empty line(s) in ${p.targetFile}; targetHash=${item.targetHash ?? \"missing\"}; proposalHash=${item.payload.proposalHash.slice(0, 12)}`;\n}\n\nfunction safeActionVerb(p: ProposalEntry): string {\n return /^\\s*replace\\b/i.test(p.suggestedChange) ? \"Would replace\" : \"Would append/update\";\n}\n\nfunction buildEvidence(p: ProposalEntry): PendingDecision[\"evidence\"] {\n const sessions = (p.evidenceSessions ?? [])\n .slice(0, 5)\n .map((id) => ({ type: \"session\", id, summary: \"proposal evidence session\" }));\n return [\n { type: \"proposal\", id: p.id, summary: redactedOneLine(p.title) },\n ...sessions,\n {\n type: \"proposal-hash\",\n id: shortHash(`${p.title}\\n${p.observation}\\n${p.suggestedChange}`),\n summary: \"redacted proposal content hash\",\n },\n ];\n}\n\nfunction containsPromptInjection(text: string): boolean {\n return /ignore (all )?(previous|above|system|developer)(?:\\s+\\w+){0,3}\\s+instructions|reveal (the )?(system prompt|secrets)|bypass (policy|approval|safety)|you are now|act as an unrestricted/i.test(\n text,\n );\n}\n\nfunction containsSecretOrPrivateData(text: string): boolean {\n return /-----BEGIN [A-Z ]*PRIVATE KEY-----|\\b(?:api[_-]?key|token|password|secret)\\s*[:=]|\\bghp_[A-Za-z0-9_]{20,}|\\bgithub_pat_[A-Za-z0-9_]{20,}|\\bsk-[A-Za-z0-9]{20,}|Bearer\\s+[A-Za-z0-9._~+/-]{16,}/i.test(\n text,\n );\n}\n\nfunction resolveAllowedPersonaTarget(\n workspace: string,\n targetFile: string,\n allowedFiles: readonly string[],\n): { ok: true; path: string } | { ok: false; path: string; error: string } {\n if (!allowedFiles.includes(targetFile)) return { ok: false, path: targetFile, error: \"target not allowlisted\" };\n if (targetFile.includes(\"..\") || targetFile.includes(\"/\") || targetFile.includes(\"\\\\\") || isAbsolute(targetFile)) {\n return { ok: false, path: targetFile, error: \"path traversal\" };\n }\n const workspaceReal = existsSync(workspace) ? realpathSync(workspace) : resolve(workspace);\n const targetPath = resolve(workspaceReal, targetFile);\n const rel = relative(workspaceReal, targetPath);\n if (rel.startsWith(\"..\") || isAbsolute(rel))\n return { ok: false, path: targetPath, error: \"target escapes workspace\" };\n try {\n const stat = lstatSync(targetPath);\n if (stat.isSymbolicLink()) {\n try {\n const real = realpathSync(targetPath);\n const realRel = relative(workspaceReal, real);\n if (realRel.startsWith(\"..\") || isAbsolute(realRel))\n return { ok: false, path: targetPath, error: \"symlink escapes workspace\" };\n } catch {\n return { ok: false, path: targetPath, error: \"dangling symlink\" };\n }\n }\n } catch (err: unknown) {\n if ((err as { code?: string }).code !== \"ENOENT\") {\n return { ok: false, path: targetPath, error: \"target stat failed\" };\n }\n }\n return { ok: true, path: targetPath };\n}\n\nexport function applyPreparedPersonaChange(\n preparedApply: { targetPath: string; backupPath: string; original: string; appliedContent: string },\n markApplied: () => void,\n io: {\n writeBackup?: (path: string, content: string) => void;\n writeTargetAtomic?: (path: string, content: string) => void;\n removeBackup?: (path: string) => void;\n } = {},\n): void {\n let backupWritten = false;\n let targetWritten = false;\n let targetRestored = false;\n let appliedMarked = false;\n try {\n (io.writeBackup ?? ((path, content) => writeFileSync(path, content, \"utf-8\")))(\n preparedApply.backupPath,\n preparedApply.original,\n );\n backupWritten = true;\n (io.writeTargetAtomic ?? writeFileAtomic)(preparedApply.targetPath, preparedApply.appliedContent);\n targetWritten = true;\n markApplied();\n appliedMarked = true;\n try {\n (io.removeBackup ?? ((path) => rmSync(path, { force: true })))(preparedApply.backupPath);\n } catch {\n // Bookkeeping has already succeeded and the target file contains the\n // applied content. Backup cleanup is best-effort at this point; do not\n // roll back a successful apply or surface it as an apply failure.\n }\n } catch (err) {\n if (targetWritten && !appliedMarked) {\n try {\n (io.writeTargetAtomic ?? writeFileAtomic)(preparedApply.targetPath, preparedApply.original);\n targetRestored = true;\n } catch {\n // Preserve original error; restore failed and the backup remains the recovery artifact.\n }\n }\n if (backupWritten && !appliedMarked && (!targetWritten || targetRestored)) {\n try {\n (io.removeBackup ?? ((path) => rmSync(path, { force: true })))(preparedApply.backupPath);\n } catch {\n // Preserve original error; backup cleanup failed but original error is more important.\n }\n }\n throw err;\n }\n}\n\nfunction writeFileAtomic(path: string, content: string): void {\n const tempPath = `${path}.tmp-${process.pid}-${Date.now()}`;\n try {\n writeFileSync(tempPath, content, \"utf-8\");\n renameSync(tempPath, path);\n } finally {\n try {\n if (existsSync(tempPath)) rmSync(tempPath, { force: true });\n } catch {\n // Suppress cleanup errors to preserve original error if any\n }\n }\n}\n\nfunction fileHash(path: string): string {\n return createHash(\"sha256\").update(readFileSync(path)).digest(\"hex\");\n}\n\nfunction hashText(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction shortHash(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\").slice(0, 16);\n}\n\nfunction normalizeText(input: string): string {\n return input.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\n\nfunction redactedOneLine(input: string): string {\n return String(redactAutopilotValue(input)).replace(/\\s+/g, \" \").slice(0, 160);\n}\n\nfunction topicKey(input: string): string {\n const text = input.toLowerCase();\n if (/security|privacy|credential|approval/.test(text)) return \"security\";\n if (/identity|voice|tone/.test(text)) return \"identity\";\n if (/preference|workflow|profile|user.?prefer|pr review|branch naming/.test(text)) return \"preference\";\n return \"general\";\n}\n\nfunction maxRisk(risks: PersonaProposalRisk[]): PersonaProposalRisk {\n const order: PersonaProposalRisk[] = [\"low\", \"medium\", \"high\", \"critical\"];\n return [...risks].sort((a, b) => order.indexOf(b) - order.indexOf(a))[0] ?? \"medium\";\n}\n\nexport function validatePersonaPolicy(policy: string): asserts policy is PersonaProposalTriagePolicy {\n if (policy !== \"report-only\" && policy !== \"cautious\" && policy !== \"apply-safe\") {\n throw new Error(`Unsupported persona proposal triage policy: ${policy}`);\n }\n}\n\nfunction defaultWorkspace(): string {\n return getEnv(\"OPENCLAW_WORKSPACE\") ?? join(homedir(), \".openclaw\", \"workspace\");\n}\n\nexport function createPersonaParentExecutionPath(\n adapter: PendingQueueAdapter<PersonaProposalPendingItem> & {\n proposalsDb: ProposalsDB;\n cfg: Pick<HybridMemoryConfig, \"personaProposals\">;\n workspace: string;\n },\n) {\n return async (item: PersonaProposalPendingItem, context: PendingDecisionContext): Promise<PendingDecision> => {\n const listed = await adapter.listPending(null);\n const listedItem = listed.find((i) => i.id === item.id);\n if (!listedItem) {\n throw new Error(`Parent execution path: item ${item.id} not found in adapter.listPending()`);\n }\n return adapter.decide(listedItem, context);\n };\n}\n\nexport function createPersonaStandaloneExecutionPath(adapter: PendingQueueAdapter<PersonaProposalPendingItem>) {\n return (\n item: PersonaProposalPendingItem,\n context: PendingDecisionContext,\n ): Promise<PendingDecision> | PendingDecision => adapter.decide(item, context);\n}\n\nexport function createPersonaProposalFixtureItem(input: {\n proposal: ProposalEntry;\n workspace: string;\n allowedFiles: PersonaProposalTargetFile[];\n policyVersion?: string;\n}): PersonaProposalPendingItem {\n const item = proposalToPendingItem(\n input.proposal,\n input.workspace,\n {\n personaProposals: { allowedFiles: input.allowedFiles },\n } as Pick<HybridMemoryConfig, \"personaProposals\">,\n input.policyVersion,\n );\n return item;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persona-state-promotion.js","names":[],"sources":["../../services/persona-state-promotion.ts"],"sourcesContent":["import type { IdentityReflectionEntry, IdentityReflectionStore } from \"../backends/identity-reflection-store.js\";\nimport type { PersonaStateEntry, PersonaStateStore } from \"../backends/persona-state-store.js\";\nimport { hasAnyScopeFilter, normalizeScopeValue } from \"../backends/scope-filter-sql.js\";\nimport type { IdentityFileType } from \"../config/types/agents.js\";\nimport type { IdentityPromotionConfig } from \"../config/types/capture.js\";\nimport type { ScopeFilter } from \"../types/memory.js\";\nimport { uniqueStrings } from \"../utils/text.js\";\n\nconst INSIGHT_STOPWORDS = new Set([\n \"a\",\n \"an\",\n \"and\",\n \"are\",\n \"as\",\n \"at\",\n \"be\",\n \"by\",\n \"for\",\n \"from\",\n \"i\",\n \"in\",\n \"is\",\n \"it\",\n \"of\",\n \"on\",\n \"or\",\n \"that\",\n \"the\",\n \"to\",\n \"when\",\n \"with\",\n]);\n\ninterface PersonaPromotionCandidate {\n stateKey: string;\n questionKey: string;\n targetFile: IdentityFileType;\n insight: string;\n normalizedInsight: string;\n averageConfidence: number;\n durableCount: number;\n evidence: string[];\n sourceReflectionIds: string[];\n firstSeenAt: number;\n lastSeenAt: number;\n}\n\ninterface PersonaPromotionResult {\n reflectionsReviewed: number;\n durableReflections: number;\n candidatesFound: number;\n promoted: number;\n updated: number;\n unchanged: number;\n entries: PersonaStateEntry[];\n}\n\nfunction normalizePersonaInsight(text: string): string {\n return text\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9\\s]/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction tokenizeInsight(text: string): string[] {\n return normalizePersonaInsight(text)\n .split(\" \")\n .map((token) => token.trim())\n .filter((token) => token.length >= 3 && !INSIGHT_STOPWORDS.has(token));\n}\n\nfunction buildCharacterBigrams(text: string): string[] {\n const normalized = ` ${normalizePersonaInsight(text)} `;\n const bigrams: string[] = [];\n for (let index = 0; index < normalized.length - 1; index++) {\n bigrams.push(normalized.slice(index, index + 2));\n }\n return bigrams;\n}\n\nfunction diceCoefficient(left: string[], right: string[]): number {\n if (left.length === 0 || right.length === 0) return 0;\n const rightCounts = new Map<string, number>();\n for (const token of right) {\n rightCounts.set(token, (rightCounts.get(token) ?? 0) + 1);\n }\n let intersection = 0;\n for (const token of left) {\n const remaining = rightCounts.get(token) ?? 0;\n if (remaining <= 0) continue;\n intersection++;\n rightCounts.set(token, remaining - 1);\n }\n return (2 * intersection) / (left.length + right.length);\n}\n\nexport function calculatePersonaInsightSimilarity(left: string, right: string): number {\n const leftTokens = new Set(tokenizeInsight(left));\n const rightTokens = new Set(tokenizeInsight(right));\n if (leftTokens.size === 0 || rightTokens.size === 0) {\n return normalizePersonaInsight(left) === normalizePersonaInsight(right) ? 1 : 0;\n }\n let intersection = 0;\n for (const token of leftTokens) {\n if (rightTokens.has(token)) intersection++;\n }\n const tokenSimilarity = (2 * intersection) / (leftTokens.size + rightTokens.size);\n const bigramSimilarity = diceCoefficient(buildCharacterBigrams(left), buildCharacterBigrams(right));\n return Math.max(tokenSimilarity, bigramSimilarity);\n}\n\nfunction inferPersonaTargetFile(questionKey: string, insight: string): IdentityFileType {\n const combined = `${questionKey} ${insight}`.toLowerCase();\n if (/\\b(name|identity|avatar|creature|role|vibe|species|origin)\\b/.test(combined)) {\n return \"IDENTITY.md\";\n }\n return \"SOUL.md\";\n}\n\nfunction buildStateKey(questionKey: string, insight: string): string {\n const tokenSignature = uniqueStrings(tokenizeInsight(insight)).sort().slice(0, 12).join(\"-\");\n const stablePart = tokenSignature || normalizePersonaInsight(insight).slice(0, 160);\n return `${questionKey}::${stablePart}`;\n}\n\nexport function collectPersonaPromotionCandidates(\n reflections: IdentityReflectionEntry[],\n config: IdentityPromotionConfig,\n): PersonaPromotionCandidate[] {\n const lookbackCutoff = Math.floor(Date.now() / 1000) - config.lookbackDays * 24 * 3600;\n const durable = reflections\n .filter((entry) => entry.durability === \"durable\" && entry.createdAt >= lookbackCutoff)\n .sort((left, right) => left.createdAt - right.createdAt);\n\n const clusters: Array<{\n stateKey: string;\n questionKey: string;\n canonicalInsight: string;\n normalizedInsight: string;\n targetFile: IdentityFileType;\n confidenceSum: number;\n durableCount: number;\n evidence: string[];\n sourceReflectionIds: string[];\n firstSeenAt: number;\n lastSeenAt: number;\n }> = [];\n\n for (const reflection of durable) {\n const match = clusters.find(\n (cluster) =>\n cluster.questionKey === reflection.questionKey &&\n calculatePersonaInsightSimilarity(cluster.canonicalInsight, reflection.insight) >= config.similarityThreshold,\n );\n if (!match) {\n clusters.push({\n stateKey: buildStateKey(reflection.questionKey, reflection.insight),\n questionKey: reflection.questionKey,\n canonicalInsight: reflection.insight,\n normalizedInsight: normalizePersonaInsight(reflection.insight),\n targetFile: inferPersonaTargetFile(reflection.questionKey, reflection.insight),\n confidenceSum: reflection.confidence,\n durableCount: 1,\n evidence: [...reflection.evidence],\n sourceReflectionIds: [reflection.id],\n firstSeenAt: reflection.createdAt,\n lastSeenAt: reflection.createdAt,\n });\n continue;\n }\n\n match.confidenceSum += reflection.confidence;\n match.durableCount += 1;\n match.evidence.push(...reflection.evidence);\n match.sourceReflectionIds.push(reflection.id);\n match.lastSeenAt = Math.max(match.lastSeenAt, reflection.createdAt);\n if (\n reflection.confidence > match.confidenceSum / match.durableCount ||\n reflection.insight.length > match.canonicalInsight.length\n ) {\n match.canonicalInsight = reflection.insight;\n match.normalizedInsight = normalizePersonaInsight(reflection.insight);\n match.targetFile = inferPersonaTargetFile(reflection.questionKey, reflection.insight);\n }\n }\n\n return clusters\n .map((cluster) => ({\n stateKey: buildStateKey(cluster.questionKey, cluster.canonicalInsight),\n questionKey: cluster.questionKey,\n targetFile: cluster.targetFile,\n insight: cluster.canonicalInsight,\n normalizedInsight: cluster.normalizedInsight,\n averageConfidence: cluster.confidenceSum / Math.max(1, cluster.durableCount),\n durableCount: cluster.durableCount,\n evidence: uniqueStrings(cluster.evidence).slice(0, 8),\n sourceReflectionIds: uniqueStrings(cluster.sourceReflectionIds),\n firstSeenAt: cluster.firstSeenAt,\n lastSeenAt: cluster.lastSeenAt,\n }))\n .filter(\n (candidate) =>\n candidate.durableCount >= config.minDurableReflections && candidate.averageConfidence >= config.minConfidence,\n )\n .sort((left, right) => right.durableCount - left.durableCount || right.averageConfidence - left.averageConfidence)\n .slice(0, config.maxPromotionsPerRun);\n}\n\nexport function buildPersonaStateInsightsBlock(entries: PersonaStateEntry[]): string {\n if (entries.length === 0) return \"\";\n return entries\n .map(\n (entry) =>\n `- [${entry.targetFile}] ${entry.insight} (question=${entry.questionKey}; durable_count=${entry.durableCount}; confidence=${entry.confidence.toFixed(2)})`,\n )\n .join(\"\\n\");\n}\n\nexport function promotePersonaStateFromReflections(\n reflectionStore: IdentityReflectionStore,\n personaStateStore: PersonaStateStore,\n config: IdentityPromotionConfig,\n opts?: { dryRun?: boolean; limit?: number; scopeFilter?: ScopeFilter },\n): PersonaPromotionResult {\n if (!config.enabled) {\n return {\n reflectionsReviewed: 0,\n durableReflections: 0,\n candidatesFound: 0,\n promoted: 0,\n updated: 0,\n unchanged: 0,\n entries: [],\n };\n }\n\n const scopeFilter = opts?.scopeFilter;\n const reflections = reflectionStore.listRecent(opts?.limit ?? 250, { scopeFilter });\n const durableReflections = reflections.filter((entry) => entry.durability === \"durable\");\n const candidates = collectPersonaPromotionCandidates(reflections, config);\n const entries: PersonaStateEntry[] = [];\n let promoted = 0;\n let updated = 0;\n let unchanged = 0;\n\n const existingEntries = personaStateStore.listRecent(100, { scopeFilter });\n\n for (const candidate of candidates) {\n let stateKey = withScopePrefix(candidate.stateKey, scopeFilter);\n const matchingEntry = existingEntries.find(\n (entry) =>\n entry.questionKey === candidate.questionKey &&\n calculatePersonaInsightSimilarity(entry.insight, candidate.insight) >= config.similarityThreshold,\n );\n if (matchingEntry) {\n stateKey = matchingEntry.stateKey;\n }\n\n if (opts?.dryRun) {\n entries.push({\n id: stateKey,\n stateKey,\n questionKey: candidate.questionKey,\n targetFile: candidate.targetFile,\n insight: candidate.insight,\n normalizedInsight: candidate.normalizedInsight,\n confidence: candidate.averageConfidence,\n durableCount: candidate.durableCount,\n evidence: candidate.evidence,\n sourceReflectionIds: candidate.sourceReflectionIds,\n firstSeenAt: candidate.firstSeenAt,\n lastSeenAt: candidate.lastSeenAt,\n promotedAt: candidate.lastSeenAt,\n updatedAt: candidate.lastSeenAt,\n });\n if (matchingEntry) {\n updated++;\n } else {\n promoted++;\n }\n continue;\n }\n\n const result = personaStateStore.upsert({\n stateKey,\n questionKey: candidate.questionKey,\n targetFile: candidate.targetFile,\n insight: candidate.insight,\n normalizedInsight: candidate.normalizedInsight,\n confidence: candidate.averageConfidence,\n durableCount: candidate.durableCount,\n evidence: candidate.evidence,\n sourceReflectionIds: candidate.sourceReflectionIds,\n firstSeenAt: candidate.firstSeenAt,\n lastSeenAt: candidate.lastSeenAt,\n scopeFilter,\n });\n if (result.action === \"created\") promoted++;\n else if (result.action === \"updated\") updated++;\n else unchanged++;\n entries.push(result.entry);\n }\n\n return {\n reflectionsReviewed: reflections.length,\n durableReflections: durableReflections.length,\n candidatesFound: candidates.length,\n promoted,\n updated,\n unchanged,\n entries,\n };\n}\n\nfunction withScopePrefix(stateKey: string, scopeFilter?: ScopeFilter): string {\n if (!hasAnyScopeFilter(scopeFilter)) return stateKey;\n const scopeParts: string[] = [];\n const userId = normalizeScopeValue(scopeFilter?.userId);\n if (userId) scopeParts.push(`u=${userId}`);\n const agentId = normalizeScopeValue(scopeFilter?.agentId);\n if (agentId) scopeParts.push(`a=${agentId}`);\n const sessionId = normalizeScopeValue(scopeFilter?.sessionId);\n if (sessionId) scopeParts.push(`s=${sessionId}`);\n return `scope[${scopeParts.join(\"|\")}]::${stateKey}`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"persona-state-promotion.js","names":[],"sources":["../../services/persona-state-promotion.ts"],"sourcesContent":["import type { IdentityReflectionEntry, IdentityReflectionStore } from \"../backends/identity-reflection-store.js\";\nimport type { PersonaStateEntry, PersonaStateStore } from \"../backends/persona-state-store.js\";\nimport { hasAnyScopeFilter, normalizeScopeValue } from \"../backends/scope-filter-sql.js\";\nimport type { IdentityFileType } from \"../config/types/agents.js\";\nimport type { IdentityPromotionConfig } from \"../config/types/capture.js\";\nimport type { ScopeFilter } from \"../types/memory.js\";\nimport { uniqueStrings } from \"../utils/text.js\";\n\nconst INSIGHT_STOPWORDS = new Set([\n \"a\",\n \"an\",\n \"and\",\n \"are\",\n \"as\",\n \"at\",\n \"be\",\n \"by\",\n \"for\",\n \"from\",\n \"i\",\n \"in\",\n \"is\",\n \"it\",\n \"of\",\n \"on\",\n \"or\",\n \"that\",\n \"the\",\n \"to\",\n \"when\",\n \"with\",\n]);\n\ninterface PersonaPromotionCandidate {\n stateKey: string;\n questionKey: string;\n targetFile: IdentityFileType;\n insight: string;\n normalizedInsight: string;\n averageConfidence: number;\n durableCount: number;\n evidence: string[];\n sourceReflectionIds: string[];\n firstSeenAt: number;\n lastSeenAt: number;\n}\n\ninterface PersonaPromotionResult {\n reflectionsReviewed: number;\n durableReflections: number;\n candidatesFound: number;\n promoted: number;\n updated: number;\n unchanged: number;\n entries: PersonaStateEntry[];\n}\n\nfunction normalizePersonaInsight(text: string): string {\n return text\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9\\s]/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction tokenizeInsight(text: string): string[] {\n return normalizePersonaInsight(text)\n .split(\" \")\n .map((token) => token.trim())\n .filter((token) => token.length >= 3 && !INSIGHT_STOPWORDS.has(token));\n}\n\nfunction buildCharacterBigrams(text: string): string[] {\n const normalized = ` ${normalizePersonaInsight(text)} `;\n const bigrams: string[] = [];\n for (let index = 0; index < normalized.length - 1; index++) {\n bigrams.push(normalized.slice(index, index + 2));\n }\n return bigrams;\n}\n\nfunction diceCoefficient(left: string[], right: string[]): number {\n if (left.length === 0 || right.length === 0) return 0;\n const rightCounts = new Map<string, number>();\n for (const token of right) {\n rightCounts.set(token, (rightCounts.get(token) ?? 0) + 1);\n }\n let intersection = 0;\n for (const token of left) {\n const remaining = rightCounts.get(token) ?? 0;\n if (remaining <= 0) continue;\n intersection++;\n rightCounts.set(token, remaining - 1);\n }\n return (2 * intersection) / (left.length + right.length);\n}\n\nexport function calculatePersonaInsightSimilarity(left: string, right: string): number {\n const leftTokens = new Set(tokenizeInsight(left));\n const rightTokens = new Set(tokenizeInsight(right));\n if (leftTokens.size === 0 || rightTokens.size === 0) {\n return normalizePersonaInsight(left) === normalizePersonaInsight(right) ? 1 : 0;\n }\n let intersection = 0;\n for (const token of leftTokens) {\n if (rightTokens.has(token)) intersection++;\n }\n const tokenSimilarity = (2 * intersection) / (leftTokens.size + rightTokens.size);\n const bigramSimilarity = diceCoefficient(buildCharacterBigrams(left), buildCharacterBigrams(right));\n return Math.max(tokenSimilarity, bigramSimilarity);\n}\n\nfunction inferPersonaTargetFile(questionKey: string, insight: string): IdentityFileType {\n const combined = `${questionKey} ${insight}`.toLowerCase();\n if (/\\b(name|identity|avatar|creature|role|vibe|species|origin)\\b/.test(combined)) {\n return \"IDENTITY.md\";\n }\n return \"SOUL.md\";\n}\n\nfunction buildStateKey(questionKey: string, insight: string): string {\n const tokenSignature = uniqueStrings(tokenizeInsight(insight)).sort().slice(0, 12).join(\"-\");\n const stablePart = tokenSignature || normalizePersonaInsight(insight).slice(0, 160);\n return `${questionKey}::${stablePart}`;\n}\n\nexport function collectPersonaPromotionCandidates(\n reflections: IdentityReflectionEntry[],\n config: IdentityPromotionConfig,\n): PersonaPromotionCandidate[] {\n const lookbackCutoff = Math.floor(Date.now() / 1000) - config.lookbackDays * 24 * 3600;\n const durable = reflections\n .filter((entry) => entry.durability === \"durable\" && entry.createdAt >= lookbackCutoff)\n .sort((left, right) => left.createdAt - right.createdAt);\n\n const clusters: Array<{\n stateKey: string;\n questionKey: string;\n canonicalInsight: string;\n normalizedInsight: string;\n targetFile: IdentityFileType;\n confidenceSum: number;\n durableCount: number;\n evidence: string[];\n sourceReflectionIds: string[];\n firstSeenAt: number;\n lastSeenAt: number;\n }> = [];\n\n for (const reflection of durable) {\n const match = clusters.find(\n (cluster) =>\n cluster.questionKey === reflection.questionKey &&\n calculatePersonaInsightSimilarity(cluster.canonicalInsight, reflection.insight) >= config.similarityThreshold,\n );\n if (!match) {\n clusters.push({\n stateKey: buildStateKey(reflection.questionKey, reflection.insight),\n questionKey: reflection.questionKey,\n canonicalInsight: reflection.insight,\n normalizedInsight: normalizePersonaInsight(reflection.insight),\n targetFile: inferPersonaTargetFile(reflection.questionKey, reflection.insight),\n confidenceSum: reflection.confidence,\n durableCount: 1,\n evidence: [...reflection.evidence],\n sourceReflectionIds: [reflection.id],\n firstSeenAt: reflection.createdAt,\n lastSeenAt: reflection.createdAt,\n });\n continue;\n }\n\n match.confidenceSum += reflection.confidence;\n match.durableCount += 1;\n match.evidence.push(...reflection.evidence);\n match.sourceReflectionIds.push(reflection.id);\n match.lastSeenAt = Math.max(match.lastSeenAt, reflection.createdAt);\n if (\n reflection.confidence > match.confidenceSum / match.durableCount ||\n reflection.insight.length > match.canonicalInsight.length\n ) {\n match.canonicalInsight = reflection.insight;\n match.normalizedInsight = normalizePersonaInsight(reflection.insight);\n match.targetFile = inferPersonaTargetFile(reflection.questionKey, reflection.insight);\n }\n }\n\n return clusters\n .map((cluster) => ({\n stateKey: buildStateKey(cluster.questionKey, cluster.canonicalInsight),\n questionKey: cluster.questionKey,\n targetFile: cluster.targetFile,\n insight: cluster.canonicalInsight,\n normalizedInsight: cluster.normalizedInsight,\n averageConfidence: cluster.confidenceSum / Math.max(1, cluster.durableCount),\n durableCount: cluster.durableCount,\n evidence: uniqueStrings(cluster.evidence).slice(0, 8),\n sourceReflectionIds: uniqueStrings(cluster.sourceReflectionIds),\n firstSeenAt: cluster.firstSeenAt,\n lastSeenAt: cluster.lastSeenAt,\n }))\n .filter(\n (candidate) =>\n candidate.durableCount >= config.minDurableReflections && candidate.averageConfidence >= config.minConfidence,\n )\n .sort((left, right) => right.durableCount - left.durableCount || right.averageConfidence - left.averageConfidence)\n .slice(0, config.maxPromotionsPerRun);\n}\n\nexport function buildPersonaStateInsightsBlock(entries: PersonaStateEntry[]): string {\n if (entries.length === 0) return \"\";\n return entries\n .map(\n (entry) =>\n `- [${entry.targetFile}] ${entry.insight} (question=${entry.questionKey}; durable_count=${entry.durableCount}; confidence=${entry.confidence.toFixed(2)})`,\n )\n .join(\"\\n\");\n}\n\nexport function promotePersonaStateFromReflections(\n reflectionStore: IdentityReflectionStore,\n personaStateStore: PersonaStateStore,\n config: IdentityPromotionConfig,\n opts?: { dryRun?: boolean; limit?: number; scopeFilter?: ScopeFilter },\n): PersonaPromotionResult {\n if (!config.enabled) {\n return {\n reflectionsReviewed: 0,\n durableReflections: 0,\n candidatesFound: 0,\n promoted: 0,\n updated: 0,\n unchanged: 0,\n entries: [],\n };\n }\n\n const scopeFilter = opts?.scopeFilter;\n const reflections = reflectionStore.listRecent(opts?.limit ?? 250, { scopeFilter });\n const durableReflections = reflections.filter((entry) => entry.durability === \"durable\");\n const candidates = collectPersonaPromotionCandidates(reflections, config);\n const entries: PersonaStateEntry[] = [];\n let promoted = 0;\n let updated = 0;\n let unchanged = 0;\n\n const existingEntries = personaStateStore.listRecent(100, { scopeFilter });\n\n for (const candidate of candidates) {\n let stateKey = withScopePrefix(candidate.stateKey, scopeFilter);\n const matchingEntry = existingEntries.find(\n (entry) =>\n entry.questionKey === candidate.questionKey &&\n calculatePersonaInsightSimilarity(entry.insight, candidate.insight) >= config.similarityThreshold,\n );\n if (matchingEntry) {\n stateKey = matchingEntry.stateKey;\n }\n\n if (opts?.dryRun) {\n entries.push({\n id: stateKey,\n stateKey,\n questionKey: candidate.questionKey,\n targetFile: candidate.targetFile,\n insight: candidate.insight,\n normalizedInsight: candidate.normalizedInsight,\n confidence: candidate.averageConfidence,\n durableCount: candidate.durableCount,\n evidence: candidate.evidence,\n sourceReflectionIds: candidate.sourceReflectionIds,\n firstSeenAt: candidate.firstSeenAt,\n lastSeenAt: candidate.lastSeenAt,\n promotedAt: candidate.lastSeenAt,\n updatedAt: candidate.lastSeenAt,\n });\n if (matchingEntry) {\n updated++;\n } else {\n promoted++;\n }\n continue;\n }\n\n const result = personaStateStore.upsert({\n stateKey,\n questionKey: candidate.questionKey,\n targetFile: candidate.targetFile,\n insight: candidate.insight,\n normalizedInsight: candidate.normalizedInsight,\n confidence: candidate.averageConfidence,\n durableCount: candidate.durableCount,\n evidence: candidate.evidence,\n sourceReflectionIds: candidate.sourceReflectionIds,\n firstSeenAt: candidate.firstSeenAt,\n lastSeenAt: candidate.lastSeenAt,\n scopeFilter,\n });\n if (result.action === \"created\") promoted++;\n else if (result.action === \"updated\") updated++;\n else unchanged++;\n entries.push(result.entry);\n }\n\n return {\n reflectionsReviewed: reflections.length,\n durableReflections: durableReflections.length,\n candidatesFound: candidates.length,\n promoted,\n updated,\n unchanged,\n entries,\n };\n}\n\nfunction withScopePrefix(stateKey: string, scopeFilter?: ScopeFilter): string {\n if (!hasAnyScopeFilter(scopeFilter)) return stateKey;\n const scopeParts: string[] = [];\n const userId = normalizeScopeValue(scopeFilter?.userId);\n if (userId) scopeParts.push(`u=${userId}`);\n const agentId = normalizeScopeValue(scopeFilter?.agentId);\n if (agentId) scopeParts.push(`a=${agentId}`);\n const sessionId = normalizeScopeValue(scopeFilter?.sessionId);\n if (sessionId) scopeParts.push(`s=${sessionId}`);\n return `scope[${scopeParts.join(\"|\")}]::${stateKey}`;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"post-compaction-recall.js","names":[],"sources":["../../services/post-compaction-recall.ts"],"sourcesContent":["/**\n * Re-run a lightweight recall pipeline after OpenClaw context compaction (#957).\n * Uses the last user prompt captured during before_agent_start auto-recall.\n */\n\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport type { LifecycleContext } from \"../lifecycle/types.js\";\nimport type { ScopeFilter } from \"../types/memory.js\";\nimport { withTimeout } from \"../utils/timeout.js\";\nimport { capturePluginError } from \"./error-reporter.js\";\nimport { type RecallPipelineDeps, runRecallPipelineQuery } from \"./recall-pipeline.js\";\nimport { DEFAULT_INTERACTIVE_RECALL_POLICY } from \"./retrieval-mode-policy.js\";\n\nconst POST_COMPACTION_RECALL_TIMEOUT_MS = 120_000;\n\nfunction buildScopeFilter(ctx: LifecycleContext): ScopeFilter | undefined {\n const { currentAgentIdRef } = ctx;\n if (currentAgentIdRef.value && currentAgentIdRef.value !== ctx.cfg.multiAgent.orchestratorId) {\n return {\n userId: ctx.cfg.autoRecall.scopeFilter?.userId ?? null,\n agentId: currentAgentIdRef.value,\n sessionId: ctx.cfg.autoRecall.scopeFilter?.sessionId ?? null,\n };\n }\n if (\n ctx.cfg.autoRecall.scopeFilter &&\n (ctx.cfg.autoRecall.scopeFilter.userId ||\n ctx.cfg.autoRecall.scopeFilter.agentId ||\n ctx.cfg.autoRecall.scopeFilter.sessionId)\n ) {\n return {\n userId: ctx.cfg.autoRecall.scopeFilter.userId ?? null,\n agentId: ctx.cfg.autoRecall.scopeFilter.agentId ?? null,\n sessionId: ctx.cfg.autoRecall.scopeFilter.sessionId ?? null,\n };\n }\n return undefined;\n}\n\n/**\n * Returns a `<recalled-context>` block for prependContext after compaction, or null if skipped/failed.\n */\nexport async function buildPostCompactionRecallSnippet(\n ctx: LifecycleContext,\n api: ClawdbotPluginApi,\n prompt: string,\n): Promise<string | null> {\n const trimmed = prompt.trim();\n if (trimmed.length < 5) return null;\n\n return withTimeout(\n POST_COMPACTION_RECALL_TIMEOUT_MS,\n async () => {\n const scopeFilter = buildScopeFilter(ctx);\n const tierFilter: \"warm\" | \"all\" = ctx.cfg.memoryTiering.enabled ? \"warm\" : \"all\";\n const recallOpts = {\n tierFilter,\n scopeFilter,\n reinforcementBoost: ctx.cfg.distill?.reinforcementBoost ?? 0.1,\n diversityWeight: ctx.cfg.reinforcement?.diversityWeight ?? 1.0,\n interactiveFtsFastPath: true,\n };\n const limit = Math.min(ctx.cfg.autoRecall.limit ?? 10, 15);\n const minScore = ctx.cfg.autoRecall.minScore ?? 0.3;\n const hydeUsedRef = { value: false };\n const pipelineDeps: RecallPipelineDeps = {\n factsDb: ctx.factsDb,\n vectorDb: ctx.vectorDb,\n embeddings: ctx.embeddings,\n openai: ctx.openai,\n cfg: {\n queryExpansion: ctx.cfg.queryExpansion,\n retrievalStrategies: ctx.cfg.retrieval.strategies,\n memoryTieringEnabled: ctx.cfg.memoryTiering.enabled,\n recallTiming: ctx.cfg.autoRecall.recallTiming,\n rawCfg: ctx.cfg,\n },\n recallOpts,\n minScore,\n pendingLLMWarnings: ctx.pendingLLMWarnings,\n logger: api.logger,\n };\n\n let candidates;\n try {\n candidates = await runRecallPipelineQuery(trimmed, limit, pipelineDeps, hydeUsedRef, {\n errorPrefix: \"post-compaction-\",\n policy: DEFAULT_INTERACTIVE_RECALL_POLICY,\n timingSpan: \"post-compaction\",\n timingOp: \"post-compaction-recall\",\n });\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"auto-recall\",\n operation: \"post-compaction-recall\",\n });\n return null;\n }\n\n if (candidates.length === 0) return null;\n\n const lines = candidates.slice(0, limit).map((r) => {\n const text = (r.entry.summary || r.entry.text).replace(/\\s+/g, \" \").trim();\n const preview = text.length > 220 ? `${text.slice(0, 220)}…` : text;\n return `- [${r.entry.category}] ${preview}`;\n });\n\n return [\n \"<!-- memory-hybrid: post-compaction recall (re-matched to last user prompt; issue #957) -->\",\n \"<recalled-context>\",\n \"Recalled after context compaction (same query as your last turn):\",\n ...lines,\n \"</recalled-context>\",\n ].join(\"\\n\");\n },\n null,\n );\n}\n"],"mappings":";;;;;AAaA,MAAM,oCAAoC;AAE1C,SAAS,iBAAiB,KAAgD;CACxE,MAAM,EAAE,sBAAsB;CAC9B,IAAI,kBAAkB,SAAS,kBAAkB,UAAU,IAAI,IAAI,WAAW,gBAC5E,OAAO;EACL,QAAQ,IAAI,IAAI,WAAW,aAAa,UAAU;EAClD,SAAS,kBAAkB;EAC3B,WAAW,IAAI,IAAI,WAAW,aAAa,aAAa;
|
|
1
|
+
{"version":3,"file":"post-compaction-recall.js","names":[],"sources":["../../services/post-compaction-recall.ts"],"sourcesContent":["/**\n * Re-run a lightweight recall pipeline after OpenClaw context compaction (#957).\n * Uses the last user prompt captured during before_agent_start auto-recall.\n */\n\nimport type { ClawdbotPluginApi } from \"openclaw/plugin-sdk/core\";\nimport type { LifecycleContext } from \"../lifecycle/types.js\";\nimport type { ScopeFilter } from \"../types/memory.js\";\nimport { withTimeout } from \"../utils/timeout.js\";\nimport { capturePluginError } from \"./error-reporter.js\";\nimport { type RecallPipelineDeps, runRecallPipelineQuery } from \"./recall-pipeline.js\";\nimport { DEFAULT_INTERACTIVE_RECALL_POLICY } from \"./retrieval-mode-policy.js\";\n\nconst POST_COMPACTION_RECALL_TIMEOUT_MS = 120_000;\n\nfunction buildScopeFilter(ctx: LifecycleContext): ScopeFilter | undefined {\n const { currentAgentIdRef } = ctx;\n if (currentAgentIdRef.value && currentAgentIdRef.value !== ctx.cfg.multiAgent.orchestratorId) {\n return {\n userId: ctx.cfg.autoRecall.scopeFilter?.userId ?? null,\n agentId: currentAgentIdRef.value,\n sessionId: ctx.cfg.autoRecall.scopeFilter?.sessionId ?? null,\n };\n }\n if (\n ctx.cfg.autoRecall.scopeFilter &&\n (ctx.cfg.autoRecall.scopeFilter.userId ||\n ctx.cfg.autoRecall.scopeFilter.agentId ||\n ctx.cfg.autoRecall.scopeFilter.sessionId)\n ) {\n return {\n userId: ctx.cfg.autoRecall.scopeFilter.userId ?? null,\n agentId: ctx.cfg.autoRecall.scopeFilter.agentId ?? null,\n sessionId: ctx.cfg.autoRecall.scopeFilter.sessionId ?? null,\n };\n }\n return undefined;\n}\n\n/**\n * Returns a `<recalled-context>` block for prependContext after compaction, or null if skipped/failed.\n */\nexport async function buildPostCompactionRecallSnippet(\n ctx: LifecycleContext,\n api: ClawdbotPluginApi,\n prompt: string,\n): Promise<string | null> {\n const trimmed = prompt.trim();\n if (trimmed.length < 5) return null;\n\n return withTimeout(\n POST_COMPACTION_RECALL_TIMEOUT_MS,\n async () => {\n const scopeFilter = buildScopeFilter(ctx);\n const tierFilter: \"warm\" | \"all\" = ctx.cfg.memoryTiering.enabled ? \"warm\" : \"all\";\n const recallOpts = {\n tierFilter,\n scopeFilter,\n reinforcementBoost: ctx.cfg.distill?.reinforcementBoost ?? 0.1,\n diversityWeight: ctx.cfg.reinforcement?.diversityWeight ?? 1.0,\n interactiveFtsFastPath: true,\n };\n const limit = Math.min(ctx.cfg.autoRecall.limit ?? 10, 15);\n const minScore = ctx.cfg.autoRecall.minScore ?? 0.3;\n const hydeUsedRef = { value: false };\n const pipelineDeps: RecallPipelineDeps = {\n factsDb: ctx.factsDb,\n vectorDb: ctx.vectorDb,\n embeddings: ctx.embeddings,\n openai: ctx.openai,\n cfg: {\n queryExpansion: ctx.cfg.queryExpansion,\n retrievalStrategies: ctx.cfg.retrieval.strategies,\n memoryTieringEnabled: ctx.cfg.memoryTiering.enabled,\n recallTiming: ctx.cfg.autoRecall.recallTiming,\n rawCfg: ctx.cfg,\n },\n recallOpts,\n minScore,\n pendingLLMWarnings: ctx.pendingLLMWarnings,\n logger: api.logger,\n };\n\n let candidates;\n try {\n candidates = await runRecallPipelineQuery(trimmed, limit, pipelineDeps, hydeUsedRef, {\n errorPrefix: \"post-compaction-\",\n policy: DEFAULT_INTERACTIVE_RECALL_POLICY,\n timingSpan: \"post-compaction\",\n timingOp: \"post-compaction-recall\",\n });\n } catch (err) {\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"auto-recall\",\n operation: \"post-compaction-recall\",\n });\n return null;\n }\n\n if (candidates.length === 0) return null;\n\n const lines = candidates.slice(0, limit).map((r) => {\n const text = (r.entry.summary || r.entry.text).replace(/\\s+/g, \" \").trim();\n const preview = text.length > 220 ? `${text.slice(0, 220)}…` : text;\n return `- [${r.entry.category}] ${preview}`;\n });\n\n return [\n \"<!-- memory-hybrid: post-compaction recall (re-matched to last user prompt; issue #957) -->\",\n \"<recalled-context>\",\n \"Recalled after context compaction (same query as your last turn):\",\n ...lines,\n \"</recalled-context>\",\n ].join(\"\\n\");\n },\n null,\n );\n}\n"],"mappings":";;;;;AAaA,MAAM,oCAAoC;AAE1C,SAAS,iBAAiB,KAAgD;CACxE,MAAM,EAAE,sBAAsB;CAC9B,IAAI,kBAAkB,SAAS,kBAAkB,UAAU,IAAI,IAAI,WAAW,gBAC5E,OAAO;EACL,QAAQ,IAAI,IAAI,WAAW,aAAa,UAAU;EAClD,SAAS,kBAAkB;EAC3B,WAAW,IAAI,IAAI,WAAW,aAAa,aAAa;CAC1D;CAEF,IACE,IAAI,IAAI,WAAW,gBAClB,IAAI,IAAI,WAAW,YAAY,UAC9B,IAAI,IAAI,WAAW,YAAY,WAC/B,IAAI,IAAI,WAAW,YAAY,YAEjC,OAAO;EACL,QAAQ,IAAI,IAAI,WAAW,YAAY,UAAU;EACjD,SAAS,IAAI,IAAI,WAAW,YAAY,WAAW;EACnD,WAAW,IAAI,IAAI,WAAW,YAAY,aAAa;CACzD;AAGJ;;;;AAKA,eAAsB,iCACpB,KACA,KACA,QACwB;CACxB,MAAM,UAAU,OAAO,KAAK;CAC5B,IAAI,QAAQ,SAAS,GAAG,OAAO;CAE/B,OAAO,YACL,mCACA,YAAY;EACV,MAAM,cAAc,iBAAiB,GAAG;EAExC,MAAM,aAAa;GACjB,YAFiC,IAAI,IAAI,cAAc,UAAU,SAAS;GAG1E;GACA,oBAAoB,IAAI,IAAI,SAAS,sBAAsB;GAC3D,iBAAiB,IAAI,IAAI,eAAe,mBAAmB;GAC3D,wBAAwB;EAC1B;EACA,MAAM,QAAQ,KAAK,IAAI,IAAI,IAAI,WAAW,SAAS,IAAI,EAAE;EACzD,MAAM,WAAW,IAAI,IAAI,WAAW,YAAY;EAChD,MAAM,cAAc,EAAE,OAAO,MAAM;EACnC,MAAM,eAAmC;GACvC,SAAS,IAAI;GACb,UAAU,IAAI;GACd,YAAY,IAAI;GAChB,QAAQ,IAAI;GACZ,KAAK;IACH,gBAAgB,IAAI,IAAI;IACxB,qBAAqB,IAAI,IAAI,UAAU;IACvC,sBAAsB,IAAI,IAAI,cAAc;IAC5C,cAAc,IAAI,IAAI,WAAW;IACjC,QAAQ,IAAI;GACd;GACA;GACA;GACA,oBAAoB,IAAI;GACxB,QAAQ,IAAI;EACd;EAEA,IAAI;EACJ,IAAI;GACF,aAAa,MAAM,uBAAuB,SAAS,OAAO,cAAc,aAAa;IACnF,aAAa;IACb,QAAQ;IACR,YAAY;IACZ,UAAU;GACZ,CAAC;EACH,SAAS,KAAK;GACZ,mBAAmB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG;IACtE,WAAW;IACX,WAAW;GACb,CAAC;GACD,OAAO;EACT;EAEA,IAAI,WAAW,WAAW,GAAG,OAAO;EAQpC,OAAO;GACL;GACA;GACA;GACA,GAVY,WAAW,MAAM,GAAG,KAAK,EAAE,KAAK,MAAM;IAClD,MAAM,QAAQ,EAAE,MAAM,WAAW,EAAE,MAAM,MAAM,QAAQ,QAAQ,GAAG,EAAE,KAAK;IACzE,MAAM,UAAU,KAAK,SAAS,MAAM,GAAG,KAAK,MAAM,GAAG,GAAG,EAAE,KAAK;IAC/D,OAAO,MAAM,EAAE,MAAM,SAAS,IAAI;GACpC,CAMS;GACP;EACF,EAAE,KAAK,IAAI;CACb,GACA,IACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pre-consolidation-flush.js","names":[],"sources":["../../services/pre-consolidation-flush.ts"],"sourcesContent":["import type { FactsDB } from \"../backends/facts-db.js\";\nimport type { VectorDB } from \"../backends/vector-db.js\";\nimport type { WriteAheadLog } from \"../backends/wal.js\";\nimport { replayWalEntries } from \"../utils/wal-replay.js\";\nimport type { EmbeddingProvider } from \"./embeddings.js\";\nimport { capturePluginError } from \"./error-reporter.js\";\n\ninterface PreConsolidationFlushDeps {\n wal: WriteAheadLog | null;\n factsDb: FactsDB;\n vectorDb: VectorDB;\n embeddings: EmbeddingProvider;\n}\n\nexport async function runPreConsolidationFlush(\n deps: PreConsolidationFlushDeps,\n logger: { info?: (msg: string) => void; warn?: (msg: string) => void },\n phase: string,\n): Promise<{ committed: number; skipped: number }> {\n if (!deps.wal) return { committed: 0, skipped: 0 };\n\n try {\n const result = await replayWalEntries(deps.wal, deps.factsDb, deps.vectorDb, deps.embeddings);\n if (result.committed > 0 || result.skipped > 0) {\n logger.info?.(`memory-hybrid: ${phase} — WAL replay: ${result.committed} committed, ${result.skipped} skipped`);\n }\n return result;\n } catch (err) {\n logger.warn?.(`memory-hybrid: ${phase} — WAL replay failed (non-fatal): ${String(err)}`);\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"lifecycle\",\n operation: `${phase}-wal-replay`,\n });\n return { committed: 0, skipped: 0 };\n }\n}\n"],"mappings":";;;AAcA,eAAsB,yBACpB,MACA,QACA,OACiD;CACjD,IAAI,CAAC,KAAK,KAAK,OAAO;EAAE,WAAW;EAAG,SAAS;
|
|
1
|
+
{"version":3,"file":"pre-consolidation-flush.js","names":[],"sources":["../../services/pre-consolidation-flush.ts"],"sourcesContent":["import type { FactsDB } from \"../backends/facts-db.js\";\nimport type { VectorDB } from \"../backends/vector-db.js\";\nimport type { WriteAheadLog } from \"../backends/wal.js\";\nimport { replayWalEntries } from \"../utils/wal-replay.js\";\nimport type { EmbeddingProvider } from \"./embeddings.js\";\nimport { capturePluginError } from \"./error-reporter.js\";\n\ninterface PreConsolidationFlushDeps {\n wal: WriteAheadLog | null;\n factsDb: FactsDB;\n vectorDb: VectorDB;\n embeddings: EmbeddingProvider;\n}\n\nexport async function runPreConsolidationFlush(\n deps: PreConsolidationFlushDeps,\n logger: { info?: (msg: string) => void; warn?: (msg: string) => void },\n phase: string,\n): Promise<{ committed: number; skipped: number }> {\n if (!deps.wal) return { committed: 0, skipped: 0 };\n\n try {\n const result = await replayWalEntries(deps.wal, deps.factsDb, deps.vectorDb, deps.embeddings);\n if (result.committed > 0 || result.skipped > 0) {\n logger.info?.(`memory-hybrid: ${phase} — WAL replay: ${result.committed} committed, ${result.skipped} skipped`);\n }\n return result;\n } catch (err) {\n logger.warn?.(`memory-hybrid: ${phase} — WAL replay failed (non-fatal): ${String(err)}`);\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"lifecycle\",\n operation: `${phase}-wal-replay`,\n });\n return { committed: 0, skipped: 0 };\n }\n}\n"],"mappings":";;;AAcA,eAAsB,yBACpB,MACA,QACA,OACiD;CACjD,IAAI,CAAC,KAAK,KAAK,OAAO;EAAE,WAAW;EAAG,SAAS;CAAE;CAEjD,IAAI;EACF,MAAM,SAAS,MAAM,iBAAiB,KAAK,KAAK,KAAK,SAAS,KAAK,UAAU,KAAK,UAAU;EAC5F,IAAI,OAAO,YAAY,KAAK,OAAO,UAAU,GAC3C,OAAO,OAAO,kBAAkB,MAAM,iBAAiB,OAAO,UAAU,cAAc,OAAO,QAAQ,SAAS;EAEhH,OAAO;CACT,SAAS,KAAK;EACZ,OAAO,OAAO,kBAAkB,MAAM,oCAAoC,OAAO,GAAG,GAAG;EACvF,mBAAmB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,GAAG;GACtE,WAAW;GACX,WAAW,GAAG,MAAM;EACtB,CAAC;EACD,OAAO;GAAE,WAAW;GAAG,SAAS;EAAE;CACpC;AACF"}
|