principles-disciple 1.126.0 → 1.128.0
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/dist/commands/archive-impl.d.ts +18 -0
- package/dist/commands/archive-impl.js +105 -0
- package/dist/commands/capabilities.d.ts +3 -0
- package/dist/commands/capabilities.js +76 -0
- package/dist/commands/context.d.ts +5 -0
- package/{src/commands/context.ts → dist/commands/context.js} +34 -83
- package/dist/commands/disable-impl.d.ts +22 -0
- package/dist/commands/disable-impl.js +118 -0
- package/dist/commands/evolution-status.d.ts +4 -0
- package/dist/commands/evolution-status.js +187 -0
- package/dist/commands/export.d.ts +2 -0
- package/dist/commands/export.js +53 -0
- package/dist/commands/focus.d.ts +14 -0
- package/dist/commands/focus.js +443 -0
- package/dist/commands/pain.d.ts +6 -0
- package/{src/commands/pain.ts → dist/commands/pain.js} +137 -188
- package/dist/commands/principle-rollback.d.ts +4 -0
- package/dist/commands/principle-rollback.js +26 -0
- package/dist/commands/promote-impl.d.ts +22 -0
- package/dist/commands/promote-impl.js +194 -0
- package/dist/commands/rollback-impl.d.ts +32 -0
- package/dist/commands/rollback-impl.js +180 -0
- package/dist/commands/rollback.d.ts +19 -0
- package/{src/commands/rollback.ts → dist/commands/rollback.js} +10 -53
- package/dist/commands/samples.d.ts +2 -0
- package/dist/commands/samples.js +58 -0
- package/dist/commands/strategy.d.ts +2 -0
- package/dist/commands/strategy.js +16 -0
- package/dist/commands/thinking-os.d.ts +2 -0
- package/{src/commands/thinking-os.ts → dist/commands/thinking-os.js} +35 -58
- package/dist/commands/workflow-debug.d.ts +6 -0
- package/{src/commands/workflow-debug.ts → dist/commands/workflow-debug.js} +13 -33
- package/dist/config/defaults/runtime.d.ts +58 -0
- package/{src/config/defaults/runtime.ts → dist/config/defaults/runtime.js} +4 -41
- package/dist/config/errors.d.ts +86 -0
- package/dist/config/errors.js +107 -0
- package/{src/config/index.ts → dist/config/index.d.ts} +1 -2
- package/dist/config/index.js +7 -0
- package/dist/constants/diagnostician.d.ts +12 -0
- package/{src/constants/diagnostician.ts → dist/constants/diagnostician.js} +0 -1
- package/dist/constants/tools.d.ts +17 -0
- package/dist/constants/tools.js +53 -0
- package/dist/core/__tests__/focus-history.test.d.ts +1 -0
- package/dist/core/__tests__/focus-history.test.js +160 -0
- package/dist/core/bootstrap-rules.d.ts +50 -0
- package/dist/core/bootstrap-rules.js +187 -0
- package/dist/core/code-implementation-storage.d.ts +71 -0
- package/dist/core/code-implementation-storage.js +139 -0
- package/dist/core/config-health.d.ts +27 -0
- package/dist/core/config-health.js +60 -0
- package/dist/core/config-service.d.ts +15 -0
- package/{src/core/config-service.ts → dist/core/config-service.js} +4 -7
- package/dist/core/config.d.ts +111 -0
- package/{src/core/config.ts → dist/core/config.js} +46 -146
- package/dist/core/control-ui-db.d.ts +106 -0
- package/dist/core/control-ui-db.js +309 -0
- package/dist/core/correction-cue-learner.d.ts +33 -0
- package/dist/core/correction-cue-learner.js +184 -0
- package/dist/core/correction-types.d.ts +3 -0
- package/dist/core/correction-types.js +1 -0
- package/dist/core/detection-funnel.d.ts +33 -0
- package/{src/core/detection-funnel.ts → dist/core/detection-funnel.js} +17 -37
- package/dist/core/detection-service.d.ts +15 -0
- package/{src/core/detection-service.ts → dist/core/detection-service.js} +4 -7
- package/dist/core/dictionary-service.d.ts +15 -0
- package/{src/core/dictionary-service.ts → dist/core/dictionary-service.js} +4 -7
- package/dist/core/dictionary.d.ts +38 -0
- package/{src/core/dictionary.ts → dist/core/dictionary.js} +33 -59
- package/dist/core/empathy-keyword-matcher.d.ts +5 -0
- package/dist/core/empathy-keyword-matcher.js +40 -0
- package/dist/core/empathy-types.d.ts +2 -0
- package/dist/core/empathy-types.js +1 -0
- package/dist/core/event-log.d.ts +90 -0
- package/dist/core/event-log.js +702 -0
- package/dist/core/evolution-engine.d.ts +119 -0
- package/dist/core/evolution-engine.js +460 -0
- package/dist/core/evolution-logger.d.ts +137 -0
- package/dist/core/evolution-logger.js +261 -0
- package/dist/core/evolution-migration.d.ts +5 -0
- package/dist/core/evolution-migration.js +65 -0
- package/dist/core/evolution-reducer.d.ts +124 -0
- package/dist/core/evolution-reducer.js +730 -0
- package/dist/core/evolution-types.d.ts +50 -0
- package/dist/core/evolution-types.js +11 -0
- package/dist/core/external-training-contract.d.ts +276 -0
- package/dist/core/external-training-contract.js +269 -0
- package/dist/core/file-store.d.ts +41 -0
- package/dist/core/file-store.js +46 -0
- package/dist/core/focus-history.d.ts +50 -0
- package/dist/core/focus-history.js +574 -0
- package/dist/core/hygiene/tracker.d.ts +22 -0
- package/dist/core/hygiene/tracker.js +110 -0
- package/dist/core/init.d.ts +30 -0
- package/{src/core/init.ts → dist/core/init.js} +87 -118
- package/dist/core/local-worker-routing.d.ts +124 -0
- package/dist/core/local-worker-routing.js +216 -0
- package/dist/core/migration.d.ts +6 -0
- package/{src/core/migration.ts → dist/core/migration.js} +10 -18
- package/dist/core/model-deployment-registry.d.ts +218 -0
- package/dist/core/model-deployment-registry.js +502 -0
- package/dist/core/model-training-registry.d.ts +295 -0
- package/dist/core/model-training-registry.js +474 -0
- package/dist/core/observability.d.ts +40 -0
- package/dist/core/observability.js +164 -0
- package/dist/core/pain-diagnostic-gate.d.ts +36 -0
- package/dist/core/pain-diagnostic-gate.js +105 -0
- package/dist/core/pain.d.ts +87 -0
- package/dist/core/pain.js +223 -0
- package/dist/core/path-resolver.d.ts +60 -0
- package/{src/core/path-resolver.ts → dist/core/path-resolver.js} +41 -131
- package/dist/core/paths.d.ts +60 -0
- package/{src/core/paths.ts → dist/core/paths.js} +4 -13
- package/dist/core/pd-config-loader.d.ts +96 -0
- package/dist/core/pd-config-loader.js +307 -0
- package/dist/core/pd-task-reconciler.d.ts +89 -0
- package/dist/core/pd-task-reconciler.js +262 -0
- package/dist/core/pd-task-service.d.ts +2 -0
- package/dist/core/pd-task-service.js +32 -0
- package/dist/core/pd-task-store.d.ts +5 -0
- package/dist/core/pd-task-store.js +62 -0
- package/dist/core/pd-task-types.d.ts +8 -0
- package/dist/core/pd-task-types.js +2 -0
- package/dist/core/principle-compiler/__tests__/compiler-replay-gate.test.d.ts +1 -0
- package/dist/core/principle-compiler/__tests__/compiler-replay-gate.test.js +132 -0
- package/dist/core/principle-compiler/code-validator.d.ts +14 -0
- package/dist/core/principle-compiler/code-validator.js +86 -0
- package/dist/core/principle-compiler/compiler.d.ts +45 -0
- package/dist/core/principle-compiler/compiler.js +287 -0
- package/{src/core/principle-compiler/index.ts → dist/core/principle-compiler/index.d.ts} +0 -1
- package/dist/core/principle-compiler/index.js +10 -0
- package/dist/core/principle-compiler/ledger-registrar.d.ts +28 -0
- package/dist/core/principle-compiler/ledger-registrar.js +95 -0
- package/{src/core/principle-compiler/template-generator.ts → dist/core/principle-compiler/template-generator.d.ts} +0 -1
- package/dist/core/principle-compiler/template-generator.js +7 -0
- package/{src/core/principle-injection.ts → dist/core/principle-injection.d.ts} +1 -7
- package/dist/core/principle-injection.js +10 -0
- package/dist/core/principle-internalization/filesystem-lifecycle-datasource.d.ts +15 -0
- package/dist/core/principle-internalization/filesystem-lifecycle-datasource.js +34 -0
- package/dist/core/principle-internalization/lifecycle-read-model.d.ts +17 -0
- package/{src/core/principle-internalization/lifecycle-read-model.ts → dist/core/principle-internalization/lifecycle-read-model.js} +2 -21
- package/dist/core/principle-internalization/lifecycle-refresh.d.ts +2 -0
- package/dist/core/principle-internalization/lifecycle-refresh.js +4 -0
- package/dist/core/principle-internalization/principle-lifecycle-service.d.ts +28 -0
- package/dist/core/principle-internalization/principle-lifecycle-service.js +89 -0
- package/dist/core/principle-training-state.d.ts +47 -0
- package/dist/core/principle-training-state.js +113 -0
- package/dist/core/principle-tree-ledger-adapter.d.ts +32 -0
- package/dist/core/principle-tree-ledger-adapter.js +125 -0
- package/dist/core/principle-tree-ledger.d.ts +82 -0
- package/dist/core/principle-tree-ledger.js +527 -0
- package/dist/core/profile.d.ts +62 -0
- package/dist/core/profile.js +211 -0
- package/dist/core/promotion-gate.d.ts +243 -0
- package/dist/core/promotion-gate.js +554 -0
- package/dist/core/reflection/reflection-context.d.ts +31 -0
- package/dist/core/reflection/reflection-context.js +91 -0
- package/dist/core/replay-engine.d.ts +12 -0
- package/dist/core/replay-engine.js +82 -0
- package/dist/core/risk-calculator.d.ts +22 -0
- package/{src/core/risk-calculator.ts → dist/core/risk-calculator.js} +19 -49
- package/{src/core/rule-host-helpers.ts → dist/core/rule-host-helpers.d.ts} +0 -1
- package/dist/core/rule-host-helpers.js +7 -0
- package/{src/core/rule-host-types.ts → dist/core/rule-host-types.d.ts} +1 -8
- package/dist/core/rule-host-types.js +7 -0
- package/dist/core/rule-host.d.ts +86 -0
- package/dist/core/rule-host.js +311 -0
- package/dist/core/rule-implementation-runtime.d.ts +18 -0
- package/dist/core/rule-implementation-runtime.js +112 -0
- package/dist/core/runtime-v2-prompt-activation-reader.d.ts +22 -0
- package/dist/core/runtime-v2-prompt-activation-reader.js +99 -0
- package/{src/core/schema/db-types.ts → dist/core/schema/db-types.d.ts} +4 -9
- package/dist/core/schema/db-types.js +5 -0
- package/{src/core/schema/index.ts → dist/core/schema/index.d.ts} +1 -10
- package/dist/core/schema/index.js +15 -0
- package/dist/core/schema/migration-runner.d.ts +53 -0
- package/dist/core/schema/migration-runner.js +170 -0
- package/dist/core/schema/migrations/001-init-trajectory.d.ts +6 -0
- package/{src/core/schema/migrations/001-init-trajectory.ts → dist/core/schema/migrations/001-init-trajectory.js} +38 -56
- package/dist/core/schema/migrations/002-init-central.d.ts +5 -0
- package/{src/core/schema/migrations/002-init-central.ts → dist/core/schema/migrations/002-init-central.js} +27 -41
- package/dist/core/schema/migrations/003-init-workflow.d.ts +5 -0
- package/{src/core/schema/migrations/003-init-workflow.ts → dist/core/schema/migrations/003-init-workflow.js} +16 -21
- package/dist/core/schema/migrations/004-add-thinking-and-gfi.d.ts +8 -0
- package/{src/core/schema/migrations/004-add-thinking-and-gfi.ts → dist/core/schema/migrations/004-add-thinking-and-gfi.js} +19 -27
- package/{src/core/schema/migrations/index.ts → dist/core/schema/migrations/index.d.ts} +1 -16
- package/dist/core/schema/migrations/index.js +27 -0
- package/dist/core/schema/schema-definitions.d.ts +46 -0
- package/{src/core/schema/schema-definitions.ts → dist/core/schema/schema-definitions.js} +242 -291
- package/dist/core/session-tracker.d.ts +119 -0
- package/{src/core/session-tracker.ts → dist/core/session-tracker.js} +96 -239
- package/dist/core/shadow-observation-registry.d.ts +217 -0
- package/dist/core/shadow-observation-registry.js +280 -0
- package/dist/core/surface-guard.d.ts +31 -0
- package/dist/core/surface-guard.js +131 -0
- package/dist/core/system-logger.d.ts +8 -0
- package/{src/core/system-logger.ts → dist/core/system-logger.js} +20 -34
- package/dist/core/thinking-models.d.ts +70 -0
- package/dist/core/thinking-models.js +300 -0
- package/dist/core/thinking-os-parser.d.ts +35 -0
- package/dist/core/thinking-os-parser.js +123 -0
- package/dist/core/trajectory-types.d.ts +220 -0
- package/dist/core/trajectory-types.js +8 -0
- package/dist/core/trajectory.d.ts +242 -0
- package/dist/core/trajectory.js +1500 -0
- package/dist/core/workflow-funnel-loader.d.ts +72 -0
- package/dist/core/workflow-funnel-loader.js +135 -0
- package/dist/core/workspace-context.d.ts +111 -0
- package/{src/core/workspace-context.ts → dist/core/workspace-context.js} +50 -105
- package/dist/core/workspace-dir-validation.d.ts +11 -0
- package/dist/core/workspace-dir-validation.js +37 -0
- package/dist/core/workspace-guidance-migrator.d.ts +12 -0
- package/{src/core/workspace-guidance-migrator.ts → dist/core/workspace-guidance-migrator.js} +21 -59
- package/dist/hooks/after-tool-call-helpers.d.ts +89 -0
- package/dist/hooks/after-tool-call-helpers.js +475 -0
- package/dist/hooks/after-tool-call-types.d.ts +86 -0
- package/dist/hooks/after-tool-call-types.js +13 -0
- package/dist/hooks/gate-block-helper.d.ts +44 -0
- package/dist/hooks/gate-block-helper.js +209 -0
- package/dist/hooks/gate.d.ts +16 -0
- package/dist/hooks/gate.js +381 -0
- package/dist/hooks/lifecycle.d.ts +5 -0
- package/dist/hooks/lifecycle.js +287 -0
- package/dist/hooks/llm.d.ts +13 -0
- package/{src/hooks/llm.ts → dist/hooks/llm.js} +63 -117
- package/dist/hooks/message-sanitize.d.ts +24 -0
- package/dist/hooks/message-sanitize.js +77 -0
- package/dist/hooks/pain.d.ts +33 -0
- package/dist/hooks/pain.js +294 -0
- package/dist/hooks/prompt.d.ts +52 -0
- package/dist/hooks/prompt.js +930 -0
- package/dist/hooks/raw-observation-adapter.d.ts +57 -0
- package/dist/hooks/raw-observation-adapter.js +170 -0
- package/dist/hooks/raw-observation-types.d.ts +62 -0
- package/dist/hooks/raw-observation-types.js +15 -0
- package/dist/hooks/subagent.d.ts +9 -0
- package/{src/hooks/subagent.ts → dist/hooks/subagent.js} +20 -60
- package/dist/hooks/trajectory-collector.d.ts +25 -0
- package/dist/hooks/trajectory-collector.js +225 -0
- package/dist/hooks/trajectory-evidence.d.ts +11 -0
- package/dist/hooks/trajectory-evidence.js +88 -0
- package/dist/hooks/triage-adapter.d.ts +58 -0
- package/{src/hooks/triage-adapter.ts → dist/hooks/triage-adapter.js} +36 -68
- package/dist/hooks/trigger-cooldown-tracker.d.ts +30 -0
- package/dist/hooks/trigger-cooldown-tracker.js +55 -0
- package/dist/i18n/commands.d.ts +26 -0
- package/dist/i18n/commands.js +96 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +829 -0
- package/dist/openclaw-sdk.d.ts +293 -0
- package/dist/openclaw-sdk.js +4 -0
- package/dist/service/central-database.d.ts +138 -0
- package/dist/service/central-database.js +731 -0
- package/dist/service/central-sync-service.d.ts +8 -0
- package/dist/service/central-sync-service.js +71 -0
- package/dist/service/correction-observer-service.d.ts +19 -0
- package/{src/service/correction-observer-service.ts → dist/service/correction-observer-service.js} +36 -76
- package/dist/service/evolution-dedup.d.ts +27 -0
- package/{src/service/evolution-dedup.ts → dist/service/evolution-dedup.js} +11 -31
- package/{src/service/evolution-queue-migration.ts → dist/service/evolution-queue-migration.d.ts} +15 -62
- package/dist/service/evolution-queue-migration.js +53 -0
- package/dist/service/evolution-worker.d.ts +103 -0
- package/{src/service/evolution-worker.ts → dist/service/evolution-worker.js} +169 -331
- package/dist/service/internalization-auto-consumer-service.d.ts +8 -0
- package/dist/service/internalization-auto-consumer-service.js +322 -0
- package/dist/service/keyword-optimization-service.d.ts +44 -0
- package/dist/service/keyword-optimization-service.js +137 -0
- package/dist/service/phase3-input-filter.d.ts +73 -0
- package/dist/service/phase3-input-filter.js +172 -0
- package/dist/service/queue-io.d.ts +30 -0
- package/dist/service/queue-io.js +79 -0
- package/{src/service/queue-migration.ts → dist/service/queue-migration.d.ts} +6 -45
- package/dist/service/queue-migration.js +56 -0
- package/dist/service/runtime-summary-service.d.ts +158 -0
- package/dist/service/runtime-summary-service.js +636 -0
- package/dist/service/subagent-workflow/subagent-error-utils.d.ts +8 -0
- package/{src/service/subagent-workflow/subagent-error-utils.ts → dist/service/subagent-workflow/subagent-error-utils.js} +3 -6
- package/{src/service/subagent-workflow/types.ts → dist/service/subagent-workflow/types.d.ts} +17 -80
- package/dist/service/subagent-workflow/types.js +11 -0
- package/dist/service/subagent-workflow/workflow-store.d.ts +30 -0
- package/{src/service/subagent-workflow/workflow-store.ts → dist/service/subagent-workflow/workflow-store.js} +43 -108
- package/dist/service/trajectory-service.d.ts +2 -0
- package/dist/service/trajectory-service.js +16 -0
- package/dist/service/workflow-watchdog.d.ts +23 -0
- package/dist/service/workflow-watchdog.js +103 -0
- package/dist/types/event-types.d.ts +2 -0
- package/dist/types/event-types.js +1 -0
- package/dist/types/hygiene-types.d.ts +2 -0
- package/dist/types/hygiene-types.js +1 -0
- package/{src/types/principle-tree-schema.ts → dist/types/principle-tree-schema.d.ts} +2 -25
- package/dist/types/principle-tree-schema.js +24 -0
- package/dist/types/queue.d.ts +2 -0
- package/dist/types/queue.js +1 -0
- package/dist/types/runtime-summary.d.ts +1 -0
- package/dist/types/runtime-summary.js +1 -0
- package/dist/types.d.ts +33 -0
- package/dist/types.js +16 -0
- package/dist/utils/file-lock.d.ts +68 -0
- package/dist/utils/file-lock.js +310 -0
- package/dist/utils/hashing.d.ts +9 -0
- package/{src/utils/hashing.ts → dist/utils/hashing.js} +4 -6
- package/dist/utils/io.d.ts +11 -0
- package/dist/utils/io.js +174 -0
- package/dist/utils/node-vm-polyfill.d.ts +9 -0
- package/{src/utils/node-vm-polyfill.ts → dist/utils/node-vm-polyfill.js} +0 -2
- package/dist/utils/retry.d.ts +210 -0
- package/dist/utils/retry.js +375 -0
- package/dist/utils/session-key.d.ts +10 -0
- package/{src/utils/session-key.ts → dist/utils/session-key.js} +5 -4
- package/dist/utils/shadow-fingerprint.d.ts +16 -0
- package/dist/utils/shadow-fingerprint.js +34 -0
- package/dist/utils/workspace-resolver.d.ts +82 -0
- package/dist/utils/workspace-resolver.js +288 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +8 -2
- package/templates/workspace/.principles/DECISION_POLICY.json +44 -0
- package/templates/workspace/.principles/PRINCIPLES.md +20 -0
- package/templates/workspace/.principles/PROFILE.json +54 -0
- package/templates/workspace/.principles/PROFILE.schema.json +56 -0
- package/templates/workspace/.principles/THINKING_OS.md +65 -0
- package/templates/workspace/.principles/THINKING_OS_ARCHIVE.md +7 -0
- package/templates/workspace/.principles/THINKING_OS_CANDIDATES.md +9 -0
- package/templates/workspace/.principles/models/_INDEX.md +27 -0
- package/templates/workspace/.principles/models/first_principles.md +62 -0
- package/templates/workspace/.principles/models/marketing_4p.md +52 -0
- package/templates/workspace/.principles/models/porter_five.md +63 -0
- package/templates/workspace/.principles/models/swot.md +60 -0
- package/templates/workspace/.principles/models/user_story_map.md +63 -0
- package/templates/workspace/.state/WORKBOARD.json +4 -0
- package/.dependency-cruiser.json +0 -19
- package/ADVANCED_CONFIG_ZH.md +0 -93
- package/AGENT_INSTALL.md +0 -173
- package/AGENT_INSTALL_EN.md +0 -173
- package/CHANGELOG.md +0 -26
- package/INSTALL.md +0 -254
- package/SKILL.md +0 -63
- package/esbuild.config.js +0 -104
- package/src/commands/archive-impl.ts +0 -147
- package/src/commands/capabilities.ts +0 -89
- package/src/commands/disable-impl.ts +0 -159
- package/src/commands/evolution-status.ts +0 -247
- package/src/commands/export.ts +0 -59
- package/src/commands/focus.ts +0 -523
- package/src/commands/principle-rollback.ts +0 -32
- package/src/commands/promote-impl.ts +0 -254
- package/src/commands/rollback-impl.ts +0 -246
- package/src/commands/samples.ts +0 -65
- package/src/commands/strategy.ts +0 -21
- package/src/config/errors.ts +0 -180
- package/src/constants/tools.ts +0 -62
- package/src/core/AGENTS.md +0 -34
- package/src/core/__tests__/focus-history.test.ts +0 -210
- package/src/core/bootstrap-rules.ts +0 -216
- package/src/core/code-implementation-storage.ts +0 -213
- package/src/core/config-health.ts +0 -72
- package/src/core/control-ui-db.ts +0 -454
- package/src/core/correction-cue-learner.ts +0 -239
- package/src/core/correction-types.ts +0 -16
- package/src/core/empathy-keyword-matcher.ts +0 -64
- package/src/core/empathy-types.ts +0 -18
- package/src/core/event-log.ts +0 -787
- package/src/core/evolution-engine.ts +0 -613
- package/src/core/evolution-logger.ts +0 -357
- package/src/core/evolution-migration.ts +0 -77
- package/src/core/evolution-reducer.ts +0 -891
- package/src/core/evolution-types.ts +0 -110
- package/src/core/external-training-contract.ts +0 -530
- package/src/core/file-store.ts +0 -80
- package/src/core/focus-history.ts +0 -763
- package/src/core/hygiene/tracker.ts +0 -122
- package/src/core/local-worker-routing.ts +0 -337
- package/src/core/model-deployment-registry.ts +0 -724
- package/src/core/model-training-registry.ts +0 -815
- package/src/core/observability.ts +0 -242
- package/src/core/pain-diagnostic-gate.ts +0 -169
- package/src/core/pain.ts +0 -309
- package/src/core/pd-config-loader.ts +0 -400
- package/src/core/pd-task-reconciler.ts +0 -380
- package/src/core/pd-task-service.ts +0 -43
- package/src/core/pd-task-store.ts +0 -78
- package/src/core/pd-task-types.ts +0 -24
- package/src/core/principle-compiler/__tests__/compiler-replay-gate.test.ts +0 -174
- package/src/core/principle-compiler/code-validator.ts +0 -93
- package/src/core/principle-compiler/compiler.ts +0 -327
- package/src/core/principle-compiler/ledger-registrar.ts +0 -116
- package/src/core/principle-internalization/filesystem-lifecycle-datasource.ts +0 -42
- package/src/core/principle-internalization/lifecycle-refresh.ts +0 -11
- package/src/core/principle-internalization/principle-lifecycle-service.ts +0 -170
- package/src/core/principle-training-state.ts +0 -177
- package/src/core/principle-tree-ledger-adapter.ts +0 -145
- package/src/core/principle-tree-ledger.ts +0 -725
- package/src/core/profile.ts +0 -228
- package/src/core/promotion-gate.ts +0 -854
- package/src/core/reflection/reflection-context.ts +0 -133
- package/src/core/replay-engine.ts +0 -106
- package/src/core/rule-host.ts +0 -386
- package/src/core/rule-implementation-runtime.ts +0 -145
- package/src/core/runtime-v2-prompt-activation-reader.ts +0 -114
- package/src/core/schema/migration-runner.ts +0 -207
- package/src/core/shadow-observation-registry.ts +0 -508
- package/src/core/surface-guard.ts +0 -188
- package/src/core/thinking-models.ts +0 -377
- package/src/core/thinking-os-parser.ts +0 -165
- package/src/core/trajectory-types.ts +0 -247
- package/src/core/trajectory.ts +0 -1831
- package/src/core/workflow-funnel-loader.ts +0 -195
- package/src/core/workspace-dir-validation.ts +0 -52
- package/src/hooks/AGENTS.md +0 -31
- package/src/hooks/after-tool-call-helpers.ts +0 -601
- package/src/hooks/after-tool-call-types.ts +0 -99
- package/src/hooks/gate-block-helper.ts +0 -265
- package/src/hooks/gate.ts +0 -394
- package/src/hooks/lifecycle.ts +0 -334
- package/src/hooks/message-sanitize.ts +0 -102
- package/src/hooks/pain.ts +0 -358
- package/src/hooks/prompt.ts +0 -1102
- package/src/hooks/raw-observation-adapter.ts +0 -215
- package/src/hooks/raw-observation-types.ts +0 -77
- package/src/hooks/trajectory-collector.ts +0 -253
- package/src/hooks/trajectory-evidence.ts +0 -97
- package/src/hooks/trigger-cooldown-tracker.ts +0 -82
- package/src/i18n/commands.ts +0 -101
- package/src/index.ts +0 -939
- package/src/openclaw-sdk.ts +0 -312
- package/src/service/central-database.ts +0 -936
- package/src/service/central-sync-service.ts +0 -85
- package/src/service/internalization-auto-consumer-service.ts +0 -397
- package/src/service/keyword-optimization-service.ts +0 -169
- package/src/service/phase3-input-filter.ts +0 -237
- package/src/service/queue-io.ts +0 -108
- package/src/service/runtime-summary-service.ts +0 -990
- package/src/service/trajectory-service.ts +0 -16
- package/src/service/workflow-watchdog.ts +0 -125
- package/src/types/event-types.ts +0 -39
- package/src/types/hygiene-types.ts +0 -8
- package/src/types/queue.ts +0 -15
- package/src/types/runtime-summary.ts +0 -5
- package/src/types.ts +0 -53
- package/src/utils/file-lock.ts +0 -394
- package/src/utils/io.ts +0 -176
- package/src/utils/retry.ts +0 -573
- package/src/utils/shadow-fingerprint.ts +0 -42
- package/src/utils/workspace-resolver.ts +0 -393
- package/tests/README.md +0 -120
- package/tests/build-artifacts.test.ts +0 -55
- package/tests/commands/evolution-status.test.ts +0 -511
- package/tests/commands/export.test.ts +0 -78
- package/tests/commands/pain.test.ts +0 -287
- package/tests/commands/samples.test.ts +0 -65
- package/tests/commands/strategy.test.ts +0 -19
- package/tests/commands/thinking-os.test.ts +0 -88
- package/tests/core/bootstrap-rules.test.ts +0 -596
- package/tests/core/code-implementation-storage.test.ts +0 -300
- package/tests/core/code-validator.test.ts +0 -197
- package/tests/core/config-service.test.ts +0 -89
- package/tests/core/config.test.ts +0 -90
- package/tests/core/control-ui-db.test.ts +0 -75
- package/tests/core/core-principle-registry-drift.test.ts +0 -39
- package/tests/core/core-template-guidance.test.ts +0 -21
- package/tests/core/correction-cue-learner.test.ts +0 -345
- package/tests/core/detection-service.test.ts +0 -50
- package/tests/core/dictionary-service.test.ts +0 -116
- package/tests/core/dictionary.test.ts +0 -171
- package/tests/core/empathy-keyword-matcher.test.ts +0 -209
- package/tests/core/event-log.test.ts +0 -484
- package/tests/core/evolution-engine.test.ts +0 -610
- package/tests/core/evolution-logger.test.ts +0 -148
- package/tests/core/evolution-migration.test.ts +0 -374
- package/tests/core/evolution-paths.test.ts +0 -21
- package/tests/core/evolution-reducer.compilation-retry.test.ts +0 -189
- package/tests/core/evolution-reducer.detector-metadata.test.ts +0 -602
- package/tests/core/evolution-types-loop.test.ts +0 -48
- package/tests/core/external-training-contract.test.ts +0 -463
- package/tests/core/file-store.test.ts +0 -102
- package/tests/core/focus-history.test.ts +0 -874
- package/tests/core/init-flatten.test.ts +0 -69
- package/tests/core/init-refactor.test.ts +0 -87
- package/tests/core/init-v1.3.test.ts +0 -46
- package/tests/core/init.test.ts +0 -190
- package/tests/core/ledger-registrar.test.ts +0 -235
- package/tests/core/migration.test.ts +0 -84
- package/tests/core/model-deployment-registry.test.ts +0 -858
- package/tests/core/model-training-registry.test.ts +0 -908
- package/tests/core/observability.test.ts +0 -382
- package/tests/core/pain-diagnostic-gate.test.ts +0 -614
- package/tests/core/pain-score.property.test.ts +0 -19
- package/tests/core/pain.test.ts +0 -132
- package/tests/core/path-resolver.test.ts +0 -57
- package/tests/core/paths-refactor.test.ts +0 -20
- package/tests/core/pd-config-loader.test.ts +0 -407
- package/tests/core/pd-task-store.test.ts +0 -126
- package/tests/core/phase7-rollout-integration.test.ts +0 -477
- package/tests/core/principle-compiler.test.ts +0 -350
- package/tests/core/principle-injection.test.ts +0 -223
- package/tests/core/principle-internalization/deprecated-readiness.test.ts +0 -193
- package/tests/core/principle-internalization/lifecycle-metrics.test.ts +0 -350
- package/tests/core/principle-internalization/lifecycle-routing-policy.test.ts +0 -212
- package/tests/core/principle-internalization/lineage-source-retired.test.ts +0 -56
- package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +0 -189
- package/tests/core/principle-training-state.test.ts +0 -939
- package/tests/core/principle-tree-ledger-adapter.test.ts +0 -253
- package/tests/core/principle-tree-ledger.test.ts +0 -423
- package/tests/core/profile.test.ts +0 -56
- package/tests/core/promotion-gate.test.ts +0 -561
- package/tests/core/queue-purge.test.ts +0 -337
- package/tests/core/reflection-context.test.ts +0 -342
- package/tests/core/regression-v1-9-1.test.ts +0 -266
- package/tests/core/replay-engine.test.ts +0 -165
- package/tests/core/risk-calculator.test.ts +0 -168
- package/tests/core/rule-host-adversarial-output.test.ts +0 -242
- package/tests/core/rule-host-autocorrect-vm.test.ts +0 -163
- package/tests/core/rule-host-helpers.test.ts +0 -120
- package/tests/core/rule-host-resource-bounds.test.ts +0 -231
- package/tests/core/rule-host-sqlite-source.test.ts +0 -720
- package/tests/core/rule-host-unhealthy-visibility.test.ts +0 -261
- package/tests/core/rule-host-validation.test.ts +0 -315
- package/tests/core/rule-implementation-runtime.test.ts +0 -49
- package/tests/core/session-tracker.test.ts +0 -191
- package/tests/core/surface-guard.test.ts +0 -338
- package/tests/core/template-generator.test.ts +0 -101
- package/tests/core/trajectory.test.ts +0 -427
- package/tests/core/workflow-funnel-loader.test.ts +0 -1028
- package/tests/core/workspace-context-factory.test.ts +0 -18
- package/tests/core/workspace-context.test.ts +0 -187
- package/tests/core/workspace-guidance-migrator.test.ts +0 -248
- package/tests/core-anti-growth.test.ts +0 -182
- package/tests/evolution-worker-quarantine.test.ts +0 -400
- package/tests/evolution-worker-slimming.test.ts +0 -380
- package/tests/fixtures/legacy-queue-v1.json +0 -74
- package/tests/fixtures/production-compatibility.test.ts +0 -147
- package/tests/fixtures/production-mock-generator.ts +0 -282
- package/tests/globalSetup.ts +0 -38
- package/tests/hook-workspace-nextaction-contract.test.ts +0 -50
- package/tests/hooks/confirm-first-removal.test.ts +0 -188
- package/tests/hooks/gate-auto-correct-shadow.test.ts +0 -309
- package/tests/hooks/gate-auto-correct.test.ts +0 -664
- package/tests/hooks/gate-block-helper-profile.test.ts +0 -186
- package/tests/hooks/gate-no-path-write-tool.test.ts +0 -171
- package/tests/hooks/gate-rule-host-pipeline.test.ts +0 -230
- package/tests/hooks/gate-rule-host-real-pipeline.test.ts +0 -190
- package/tests/hooks/lifecycle.test.ts +0 -248
- package/tests/hooks/message-sanitize.test.ts +0 -244
- package/tests/hooks/pain-emission-characterization.test.ts +0 -420
- package/tests/hooks/pain.test.ts +0 -795
- package/tests/hooks/prompt-characterization.test.ts +0 -476
- package/tests/hooks/prompt-diet.test.ts +0 -335
- package/tests/hooks/prompt-size-guard.test.ts +0 -319
- package/tests/hooks/raw-observation-adapter.test.ts +0 -312
- package/tests/hooks/runtime-v2-prompt-activation.test.ts +0 -895
- package/tests/hooks/single-gate-pain-admission.test.ts +0 -258
- package/tests/hooks/subagent.test.ts +0 -469
- package/tests/hooks/trajectory-collector.test.ts +0 -269
- package/tests/hooks/trajectory-evidence.test.ts +0 -280
- package/tests/hooks/triage-adapter.test.ts +0 -331
- package/tests/hygiene-tracker.test.ts +0 -77
- package/tests/index.test.ts +0 -142
- package/tests/integration/auto-entry-gate.test.ts +0 -256
- package/tests/integration/gate-real-io.e2e.test.ts +0 -248
- package/tests/integration/m8-legacy-paths.test.ts +0 -63
- package/tests/integration/mvp-surface-registry-guard.test.ts +0 -536
- package/tests/integration/pain-id-chain-e2e.test.ts +0 -313
- package/tests/integration/principle-compiler-e2e.test.ts +0 -403
- package/tests/integration/principle-lifecycle.e2e.test.ts +0 -198
- package/tests/integration/runtime-v2-pain-guard.test.ts +0 -125
- package/tests/integration/trajectory-lifecycle.e2e.test.ts +0 -523
- package/tests/internalization-auto-consumer-gate.test.ts +0 -158
- package/tests/internalization-auto-consumer-service.test.ts +0 -219
- package/tests/plugin-config-resolution-cutover.test.ts +0 -359
- package/tests/queue/async-lock.test.ts +0 -200
- package/tests/runtime-v2-discovery-guard.test.ts +0 -153
- package/tests/scripts/validate-live-path.test.ts +0 -286
- package/tests/service/central-database.test.ts +0 -457
- package/tests/service/correction-observer-service.test.ts +0 -505
- package/tests/service/evolution-worker.compilation-backfill.test.ts +0 -203
- package/tests/service/evolution-worker.correction-observer.test.ts +0 -50
- package/tests/service/evolution-worker.queue.test.ts +0 -296
- package/tests/service/evolution-worker.timeout.test.ts +0 -233
- package/tests/service/keyword-optimization-service.test.ts +0 -121
- package/tests/service/phase3-input-filter.test.ts +0 -289
- package/tests/service/queue-io.test.ts +0 -168
- package/tests/service/queue-migration.test.ts +0 -147
- package/tests/service/runtime-summary-service.test.ts +0 -1100
- package/tests/service/workflow-watchdog.test.ts +0 -281
- package/tests/task-compliance.test.ts +0 -166
- package/tests/test-utils.ts +0 -48
- package/tests/utils/file-lock.test.ts +0 -409
- package/tests/utils/hashing.test.ts +0 -32
- package/tests/utils/hook-workspace-resolver.test.ts +0 -524
- package/tests/utils/io.test.ts +0 -39
- package/tests/utils/retry.test.ts +0 -327
- package/tests/utils/session-key.test.ts +0 -52
- package/tsconfig.json +0 -16
- package/vitest.config.ts +0 -61
- package/vitest.unit.config.ts +0 -12
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PRI-437 Slice 2: Valid decisions work through public before-tool-call hook
|
|
3
|
-
*
|
|
4
|
-
* PURPOSE: Verify that valid RuleHost decisions (block/allow) flow correctly
|
|
5
|
-
* through the real handleBeforeToolCall public hook with real SQLite activations.
|
|
6
|
-
*
|
|
7
|
-
* This test exercises the FULL public path:
|
|
8
|
-
* real SQLite activation → real RuleHost.evaluate() → validateRuleHostResult()
|
|
9
|
-
* → real handleBeforeToolCall() → block/allow result
|
|
10
|
-
*
|
|
11
|
-
* No mocking of RuleHost, SQLite, or gate internals.
|
|
12
|
-
*
|
|
13
|
-
* ERR risk mitigation:
|
|
14
|
-
* - ERR-024: validator is wired into the production path (verified end-to-end)
|
|
15
|
-
* - ERR-048: activation write (SQLite) connects to read (RuleHost) connects to enforcement (gate)
|
|
16
|
-
* - ERR-002: valid decisions must NOT be silently degraded
|
|
17
|
-
*/
|
|
18
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
19
|
-
import * as fs from 'fs';
|
|
20
|
-
import * as os from 'os';
|
|
21
|
-
import * as path from 'path';
|
|
22
|
-
import { SqliteConnection, SqliteActivationStateStore } from '@principles/core/runtime-v2';
|
|
23
|
-
import { handleBeforeToolCall } from '../../src/hooks/gate.js';
|
|
24
|
-
import type { PluginHookBeforeToolCallEvent, PluginHookToolContext } from '../../src/openclaw-sdk.js';
|
|
25
|
-
import { WorkspaceContext } from '../../src/core/workspace-context.js';
|
|
26
|
-
|
|
27
|
-
// ── Test helpers ───────────────────────────────────────────────────────────
|
|
28
|
-
|
|
29
|
-
const RULE_ID = 'R_TEST_GATE_002';
|
|
30
|
-
const ARTIFACT_ID = 'art-gate-002';
|
|
31
|
-
const ACTIVATION_ID = `act_code_${RULE_ID}`;
|
|
32
|
-
|
|
33
|
-
const BLOCK_CODE = `
|
|
34
|
-
function evaluate(input, helpers) {
|
|
35
|
-
var p = input.action.normalizedPath || '';
|
|
36
|
-
if (p.indexOf('/etc/') === 0 || p === '/etc') {
|
|
37
|
-
return { decision: 'block', matched: true, reason: 'GATE_BLOCK_002: system directory' };
|
|
38
|
-
}
|
|
39
|
-
return { decision: 'allow', matched: false, reason: 'Not matched' };
|
|
40
|
-
}
|
|
41
|
-
var meta = { name: 'gate-test-rule', version: '1', ruleId: '${RULE_ID}', coversCondition: 'all' };
|
|
42
|
-
`;
|
|
43
|
-
|
|
44
|
-
let tempWorkspaceDir: string;
|
|
45
|
-
let tempStateDir: string;
|
|
46
|
-
let sqliteConn: SqliteConnection;
|
|
47
|
-
|
|
48
|
-
function setupTempDirs(): void {
|
|
49
|
-
const baseTmp = os.tmpdir();
|
|
50
|
-
tempWorkspaceDir = fs.mkdtempSync(path.join(baseTmp, 'pd-gate-real-'));
|
|
51
|
-
tempStateDir = path.join(tempWorkspaceDir, '.principles');
|
|
52
|
-
fs.mkdirSync(tempStateDir, { recursive: true });
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function insertRuleArtifact(): void {
|
|
56
|
-
const db = sqliteConn.getDb();
|
|
57
|
-
const now = new Date().toISOString();
|
|
58
|
-
const contentJson = JSON.stringify({
|
|
59
|
-
principleId: 'P_TEST_GATE_002',
|
|
60
|
-
ruleId: RULE_ID,
|
|
61
|
-
implementationCode: BLOCK_CODE,
|
|
62
|
-
goldenTrace: {
|
|
63
|
-
traceId: 'trace-gate-002',
|
|
64
|
-
cases: [],
|
|
65
|
-
createdAt: now,
|
|
66
|
-
version: 1,
|
|
67
|
-
},
|
|
68
|
-
ruleHostGateDecision: 'accepted_shadow',
|
|
69
|
-
affectedTools: ['write_file'],
|
|
70
|
-
painReasonSummary: 'Test: block /etc writes via gate',
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
db.prepare(`
|
|
74
|
-
INSERT INTO pi_artifacts (artifact_id, artifact_kind, source_task_id, source_principle_id, source_rule_id, lineage_artifact_ids, validation_status, content_json, created_at, updated_at)
|
|
75
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
76
|
-
`).run(
|
|
77
|
-
ARTIFACT_ID,
|
|
78
|
-
'rule',
|
|
79
|
-
'task-gate-002',
|
|
80
|
-
'P_TEST_GATE_002',
|
|
81
|
-
RULE_ID,
|
|
82
|
-
'[]',
|
|
83
|
-
'validated',
|
|
84
|
-
contentJson,
|
|
85
|
-
now,
|
|
86
|
-
now,
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async function insertActivation(): Promise<void> {
|
|
91
|
-
const store = new SqliteActivationStateStore(sqliteConn);
|
|
92
|
-
const now = new Date().toISOString();
|
|
93
|
-
await store.recordActivation({
|
|
94
|
-
activationId: ACTIVATION_ID,
|
|
95
|
-
idempotencyKey: `${ARTIFACT_ID}::code_tool_hook`,
|
|
96
|
-
artifactId: ARTIFACT_ID,
|
|
97
|
-
channel: 'code_tool_hook',
|
|
98
|
-
action: 'code_tool_hook_shadow_activate',
|
|
99
|
-
targetRef: `impl://${RULE_ID}`,
|
|
100
|
-
activatedAt: now,
|
|
101
|
-
deactivatedAt: null,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// ── Setup / Teardown ───────────────────────────────────────────────────────
|
|
106
|
-
|
|
107
|
-
beforeEach(() => {
|
|
108
|
-
setupTempDirs();
|
|
109
|
-
WorkspaceContext.clearCache();
|
|
110
|
-
sqliteConn = new SqliteConnection(tempWorkspaceDir);
|
|
111
|
-
sqliteConn.getDb();
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
afterEach(() => {
|
|
115
|
-
WorkspaceContext.clearCache();
|
|
116
|
-
try { sqliteConn?.close(); } catch { /* best-effort */ }
|
|
117
|
-
try { fs.rmSync(tempWorkspaceDir, { recursive: true, force: true }); } catch { /* Windows */ }
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// ── Slice 2: Valid decisions through public hook ───────────────────────────
|
|
121
|
-
|
|
122
|
-
describe('PRI-437 Slice 2: Valid decisions work through public before-tool-call hook', () => {
|
|
123
|
-
it('valid block decision from SQLite activation → handleBeforeToolCall returns block result', async () => {
|
|
124
|
-
// Setup: real SQLite activation with valid blocking code
|
|
125
|
-
insertRuleArtifact();
|
|
126
|
-
await insertActivation();
|
|
127
|
-
|
|
128
|
-
// Exercise the PUBLIC hook with a real event targeting /etc/passwd
|
|
129
|
-
const event: PluginHookBeforeToolCallEvent = {
|
|
130
|
-
toolName: 'write_file',
|
|
131
|
-
params: { file_path: '/etc/passwd', content: 'malicious' },
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const ctx: PluginHookToolContext = {
|
|
135
|
-
workspaceDir: tempWorkspaceDir,
|
|
136
|
-
sessionId: 'test-session-gate-002',
|
|
137
|
-
logger: { warn: () => {}, error: () => {}, info: () => {} },
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const result = handleBeforeToolCall(event, ctx);
|
|
141
|
-
|
|
142
|
-
// Verify: block decision is enforced through the public hook
|
|
143
|
-
expect(result).toBeDefined();
|
|
144
|
-
expect(result?.block).toBe(true);
|
|
145
|
-
expect(result?.blockReason).toContain('GATE_BLOCK_002: system directory');
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('valid allow (no match) from SQLite activation → handleBeforeToolCall returns undefined', async () => {
|
|
149
|
-
insertRuleArtifact();
|
|
150
|
-
await insertActivation();
|
|
151
|
-
|
|
152
|
-
// Exercise the PUBLIC hook with a safe path that does NOT match the block rule
|
|
153
|
-
const event: PluginHookBeforeToolCallEvent = {
|
|
154
|
-
toolName: 'write_file',
|
|
155
|
-
params: { file_path: '/safe/project/file.txt', content: 'safe content' },
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
const ctx: PluginHookToolContext = {
|
|
159
|
-
workspaceDir: tempWorkspaceDir,
|
|
160
|
-
sessionId: 'test-session-gate-002',
|
|
161
|
-
logger: { warn: () => {}, error: () => {}, info: () => {} },
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
const result = handleBeforeToolCall(event, ctx);
|
|
165
|
-
|
|
166
|
-
// Verify: no block (allow passes through)
|
|
167
|
-
expect(result).toBeUndefined();
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('no SQLite activation → handleBeforeToolCall returns undefined (no opinion)', async () => {
|
|
171
|
-
// Artifact exists but no activation
|
|
172
|
-
insertRuleArtifact();
|
|
173
|
-
|
|
174
|
-
const event: PluginHookBeforeToolCallEvent = {
|
|
175
|
-
toolName: 'write_file',
|
|
176
|
-
params: { file_path: '/etc/passwd', content: 'malicious' },
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const ctx: PluginHookToolContext = {
|
|
180
|
-
workspaceDir: tempWorkspaceDir,
|
|
181
|
-
sessionId: 'test-session-gate-002',
|
|
182
|
-
logger: { warn: () => {}, error: () => {}, info: () => {} },
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
const result = handleBeforeToolCall(event, ctx);
|
|
186
|
-
|
|
187
|
-
// No activation → RuleHost returns undefined → gate allows
|
|
188
|
-
expect(result).toBeUndefined();
|
|
189
|
-
});
|
|
190
|
-
});
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { handleBeforeReset, handleBeforeCompaction, extractPainFromSessionFile } from '../../src/hooks/lifecycle';
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
import * as os from 'os';
|
|
6
|
-
import { Readable } from 'stream';
|
|
7
|
-
|
|
8
|
-
vi.mock('fs');
|
|
9
|
-
|
|
10
|
-
describe('Lifecycle Hooks', () => {
|
|
11
|
-
const workspaceDir = '/mock/workspace';
|
|
12
|
-
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
vi.clearAllMocks();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
afterEach(() => {
|
|
18
|
-
vi.clearAllMocks();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
describe('handleBeforeReset', () => {
|
|
22
|
-
it('should append summary to MEMORY.md if pain points exist', async () => {
|
|
23
|
-
const mockEvent = {
|
|
24
|
-
messages: [
|
|
25
|
-
{ role: 'user', content: 'hello' },
|
|
26
|
-
{ role: 'assistant', content: 'error: something went wrong' }
|
|
27
|
-
],
|
|
28
|
-
reason: 'Manual reset'
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
await handleBeforeReset(mockEvent, { workspaceDir });
|
|
32
|
-
|
|
33
|
-
expect(fs.appendFileSync).toHaveBeenCalled();
|
|
34
|
-
const callArgs = vi.mocked(fs.appendFileSync).mock.calls[0];
|
|
35
|
-
expect(callArgs[0]).toContain('MEMORY.md');
|
|
36
|
-
expect(callArgs[1]).toContain('Session Reset Summary');
|
|
37
|
-
expect(callArgs[1]).toContain('1 potential pain point(s)');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('should not write if no pain points are found', async () => {
|
|
41
|
-
const mockEvent = {
|
|
42
|
-
messages: [{ role: 'assistant', content: 'all good' }]
|
|
43
|
-
};
|
|
44
|
-
await handleBeforeReset(mockEvent, { workspaceDir });
|
|
45
|
-
expect(fs.appendFileSync).not.toHaveBeenCalled();
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe('handleBeforeCompaction', () => {
|
|
50
|
-
it('should write checkpoint to CHECKPOINT.md', async () => {
|
|
51
|
-
const mockEvent = { messageCount: 50 };
|
|
52
|
-
await handleBeforeCompaction(mockEvent, { workspaceDir });
|
|
53
|
-
expect(fs.appendFileSync).toHaveBeenCalled();
|
|
54
|
-
const callArgs = vi.mocked(fs.appendFileSync).mock.calls[0];
|
|
55
|
-
expect(callArgs[0]).toContain(path.join('memory'));
|
|
56
|
-
expect(callArgs[1]).toContain('Pre-Compaction Checkpoint');
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
describe('extractPainFromSessionFile', () => {
|
|
61
|
-
const tempSessionFile = path.join(os.tmpdir(), 'test_session.jsonl');
|
|
62
|
-
|
|
63
|
-
beforeEach(() => {
|
|
64
|
-
// Create memory directories so our test can write to them without erroring
|
|
65
|
-
const dailyLogDir = path.join(workspaceDir, 'memory');
|
|
66
|
-
const painLogDir = path.join(dailyLogDir, 'pain');
|
|
67
|
-
fs.mkdirSync(painLogDir, { recursive: true });
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
afterEach(() => {
|
|
71
|
-
// Clean up the temp jsonl
|
|
72
|
-
if (fs.existsSync(tempSessionFile)) fs.unlinkSync(tempSessionFile);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should extract FATAL INTERCEPT from openclawAbort', async () => {
|
|
76
|
-
const loggerMock = { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
|
77
|
-
|
|
78
|
-
const jsonlContent = [
|
|
79
|
-
JSON.stringify({ role: 'user', content: 'Do something' }),
|
|
80
|
-
JSON.stringify({
|
|
81
|
-
role: 'assistant',
|
|
82
|
-
content: 'I will modify the file directly',
|
|
83
|
-
openclawAbort: { aborted: true, origin: 'rpc', runId: 'test-run-123' }
|
|
84
|
-
})
|
|
85
|
-
].join('\n') + '\n';
|
|
86
|
-
|
|
87
|
-
// Temporarily mock fs.existsSync true strictly for our file, and unmock createReadStream
|
|
88
|
-
vi.mocked(fs.existsSync).mockImplementation((p: any) => p === tempSessionFile || String(p).includes('memory'));
|
|
89
|
-
vi.spyOn(fs, 'createReadStream').mockImplementation((...args: any[]) => {
|
|
90
|
-
// We use actual fs for reading our temp file which we write actually unmocked below
|
|
91
|
-
return Readable.from([jsonlContent]) as any;
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
await extractPainFromSessionFile(tempSessionFile, { workspaceDir, logger: loggerMock });
|
|
95
|
-
|
|
96
|
-
expect(loggerMock.info).toHaveBeenCalledWith(expect.stringContaining('Detected hard-abort snapshot (runId: test-run-123)'));
|
|
97
|
-
expect(fs.appendFileSync).toHaveBeenCalled();
|
|
98
|
-
|
|
99
|
-
// Check that what was appended to MEMORY contains FATAL INTERCEPT
|
|
100
|
-
const calls = vi.mocked(fs.appendFileSync).mock.calls;
|
|
101
|
-
const memoryWrite = calls.find((call: any) => String(call[0]).endsWith('.md') && !String(call[0]).includes('confusion_samples'));
|
|
102
|
-
expect(memoryWrite).toBeDefined();
|
|
103
|
-
expect(memoryWrite![1]).toContain('[FATAL INTERCEPT]');
|
|
104
|
-
expect(memoryWrite![1]).toContain('I will modify the file directly');
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('should extract COGNITIVE OVERLOAD from oversized placeholder', async () => {
|
|
108
|
-
const loggerMock = { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
|
109
|
-
|
|
110
|
-
const jsonlContent = [
|
|
111
|
-
JSON.stringify({
|
|
112
|
-
role: 'assistant',
|
|
113
|
-
content: 'Reading massive file',
|
|
114
|
-
__openclaw: { truncated: true, reason: 'oversized' }
|
|
115
|
-
})
|
|
116
|
-
].join('\n') + '\n';
|
|
117
|
-
|
|
118
|
-
vi.mocked(fs.existsSync).mockImplementation((p: any) => p === tempSessionFile || String(p).includes('memory'));
|
|
119
|
-
vi.spyOn(fs, 'createReadStream').mockImplementation((...args: any[]) => {
|
|
120
|
-
return Readable.from([jsonlContent]) as any;
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
await extractPainFromSessionFile(tempSessionFile, { workspaceDir, logger: loggerMock });
|
|
124
|
-
|
|
125
|
-
expect(loggerMock.info).toHaveBeenCalledWith(expect.stringContaining('Detected oversized data truncation placeholder'));
|
|
126
|
-
|
|
127
|
-
const calls = vi.mocked(fs.appendFileSync).mock.calls;
|
|
128
|
-
const memoryWrite = calls.find((call: any) => String(call[0]).endsWith('.md') && !String(call[0]).includes('confusion_samples'));
|
|
129
|
-
expect(memoryWrite).toBeDefined();
|
|
130
|
-
expect(memoryWrite![1]).toContain('[COGNITIVE OVERLOAD]');
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('should fallback to semantic guessing for i am sorry', async () => {
|
|
134
|
-
const loggerMock = { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
|
135
|
-
|
|
136
|
-
const jsonlContent = [
|
|
137
|
-
JSON.stringify({
|
|
138
|
-
role: 'assistant',
|
|
139
|
-
content: 'I\'m sorry, but I\'m still getting an error.'
|
|
140
|
-
})
|
|
141
|
-
].join('\n') + '\n';
|
|
142
|
-
|
|
143
|
-
vi.mocked(fs.existsSync).mockImplementation((p: any) => p === tempSessionFile || String(p).includes('memory'));
|
|
144
|
-
vi.spyOn(fs, 'createReadStream').mockImplementation((...args: any[]) => {
|
|
145
|
-
return Readable.from([jsonlContent]) as any;
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
await extractPainFromSessionFile(tempSessionFile, { workspaceDir, logger: loggerMock });
|
|
149
|
-
|
|
150
|
-
expect(loggerMock.debug).toHaveBeenCalledWith(expect.stringContaining('Detected semantic confusion string'));
|
|
151
|
-
|
|
152
|
-
const calls = vi.mocked(fs.appendFileSync).mock.calls;
|
|
153
|
-
const memoryWrite = calls.find((call: any) => String(call[0]).endsWith('.md') && !String(call[0]).includes('confusion_samples'));
|
|
154
|
-
expect(memoryWrite).toBeDefined();
|
|
155
|
-
expect(memoryWrite![1]).toContain('I\'m sorry, but I\'m still getting');
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('should ignore openclawAbort when aborted is false', async () => {
|
|
159
|
-
const loggerMock = { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
|
160
|
-
const jsonlContent = [
|
|
161
|
-
JSON.stringify({
|
|
162
|
-
role: 'assistant',
|
|
163
|
-
content: 'Normal message',
|
|
164
|
-
openclawAbort: { aborted: false, origin: 'rpc', runId: 'test-run-456' }
|
|
165
|
-
})
|
|
166
|
-
].join('\n') + '\n';
|
|
167
|
-
|
|
168
|
-
vi.mocked(fs.existsSync).mockImplementation((p: any) => p === tempSessionFile || String(p).includes('memory'));
|
|
169
|
-
vi.spyOn(fs, 'createReadStream').mockImplementation((...args: any[]) => {
|
|
170
|
-
return Readable.from([jsonlContent]) as any;
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
await extractPainFromSessionFile(tempSessionFile, { workspaceDir, logger: loggerMock } as any);
|
|
174
|
-
|
|
175
|
-
const calls = vi.mocked(fs.appendFileSync).mock.calls;
|
|
176
|
-
const memoryWrite = calls.find((call: any) => String(call[0]).endsWith('.md') && !String(call[0]).includes('confusion_samples'));
|
|
177
|
-
expect(memoryWrite).toBeUndefined();
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('should ignore __openclaw when truncated is false or reason is not oversized', async () => {
|
|
181
|
-
const loggerMock = { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
|
182
|
-
const jsonlContent = [
|
|
183
|
-
JSON.stringify({
|
|
184
|
-
role: 'assistant',
|
|
185
|
-
content: 'Normal message',
|
|
186
|
-
__openclaw: { truncated: false, reason: 'oversized' }
|
|
187
|
-
}),
|
|
188
|
-
JSON.stringify({
|
|
189
|
-
role: 'assistant',
|
|
190
|
-
content: 'Normal message 2',
|
|
191
|
-
__openclaw: { truncated: true, reason: 'other_reason' }
|
|
192
|
-
})
|
|
193
|
-
].join('\n') + '\n';
|
|
194
|
-
|
|
195
|
-
vi.mocked(fs.existsSync).mockImplementation((p: any) => p === tempSessionFile || String(p).includes('memory'));
|
|
196
|
-
vi.spyOn(fs, 'createReadStream').mockImplementation((...args: any[]) => {
|
|
197
|
-
return Readable.from([jsonlContent]) as any;
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
await extractPainFromSessionFile(tempSessionFile, { workspaceDir, logger: loggerMock } as any);
|
|
201
|
-
|
|
202
|
-
const calls = vi.mocked(fs.appendFileSync).mock.calls;
|
|
203
|
-
const memoryWrite = calls.find((call: any) => String(call[0]).endsWith('.md') && !String(call[0]).includes('confusion_samples'));
|
|
204
|
-
expect(memoryWrite).toBeUndefined();
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
it('should return early if workspaceDir is not available', async () => {
|
|
208
|
-
const loggerMock = { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
|
209
|
-
vi.spyOn(fs, 'createReadStream');
|
|
210
|
-
|
|
211
|
-
await extractPainFromSessionFile(tempSessionFile, { logger: loggerMock } as any);
|
|
212
|
-
|
|
213
|
-
expect(fs.createReadStream).not.toHaveBeenCalled();
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('should log debug and return early if sessionFile does not exist', async () => {
|
|
217
|
-
const loggerMock = { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
|
218
|
-
vi.mocked(fs.existsSync).mockReturnValue(false);
|
|
219
|
-
vi.spyOn(fs, 'createReadStream');
|
|
220
|
-
|
|
221
|
-
await extractPainFromSessionFile('fake_file.jsonl', { workspaceDir, logger: loggerMock } as any);
|
|
222
|
-
|
|
223
|
-
expect(loggerMock.debug).toHaveBeenCalledWith(expect.stringContaining('Session file not found: fake_file.jsonl'));
|
|
224
|
-
expect(fs.createReadStream).not.toHaveBeenCalled();
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it('should handle corrupted jsonl lines gracefully without throwing', async () => {
|
|
228
|
-
const loggerMock = { info: vi.fn(), debug: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
|
229
|
-
const jsonlContent = [
|
|
230
|
-
'{ invalid json ',
|
|
231
|
-
JSON.stringify({ role: 'user', content: 'Normal' }),
|
|
232
|
-
'also invalid json'
|
|
233
|
-
].join('\n') + '\n';
|
|
234
|
-
|
|
235
|
-
vi.mocked(fs.existsSync).mockImplementation((p: any) => p === tempSessionFile || String(p).includes('memory'));
|
|
236
|
-
vi.spyOn(fs, 'createReadStream').mockImplementation((...args: any[]) => {
|
|
237
|
-
return Readable.from([jsonlContent]) as any;
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
// Execute without throwing
|
|
241
|
-
await extractPainFromSessionFile(tempSessionFile, { workspaceDir, logger: loggerMock } as any);
|
|
242
|
-
|
|
243
|
-
const calls = vi.mocked(fs.appendFileSync).mock.calls;
|
|
244
|
-
const memoryWrite = calls.find((call: any) => String(call[0]).endsWith('.md') && !String(call[0]).includes('confusion_samples'));
|
|
245
|
-
expect(memoryWrite).toBeUndefined();
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
});
|
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
handleBeforeMessageWrite,
|
|
4
|
-
sanitizeAssistantText,
|
|
5
|
-
sanitizeForEvidence,
|
|
6
|
-
sanitizeToolParamsForEvidence,
|
|
7
|
-
sanitizeValueForEvidence,
|
|
8
|
-
MAX_EVIDENCE_VALUE_CHARS,
|
|
9
|
-
} from '../../src/hooks/message-sanitize';
|
|
10
|
-
|
|
11
|
-
describe('message-sanitize hook', () => {
|
|
12
|
-
it('removes empathy control tags from assistant text', () => {
|
|
13
|
-
const text = '抱歉 [EMOTIONAL_DAMAGE_DETECTED:moderate]\n<empathy signal="damage" severity="moderate"/>\n继续处理';
|
|
14
|
-
expect(sanitizeAssistantText(text)).toBe('抱歉\n\n继续处理');
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('returns modified message for assistant role', () => {
|
|
18
|
-
const result = handleBeforeMessageWrite({
|
|
19
|
-
message: { role: 'assistant', content: 'hello [EMOTIONAL_DAMAGE_DETECTED] world' }
|
|
20
|
-
} as any);
|
|
21
|
-
expect(result).toEqual({
|
|
22
|
-
message: { role: 'assistant', content: 'hello world' }
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('ignores non-assistant messages', () => {
|
|
27
|
-
const result = handleBeforeMessageWrite({
|
|
28
|
-
message: { role: 'user', content: '[EMOTIONAL_DAMAGE_DETECTED]' }
|
|
29
|
-
} as any);
|
|
30
|
-
expect(result).toBeUndefined();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// ── sanitizeForEvidence ──
|
|
34
|
-
|
|
35
|
-
it('binds long string values to MAX_EVIDENCE_VALUE_CHARS', () => {
|
|
36
|
-
const segment = ' data ';
|
|
37
|
-
const long = segment.repeat(100);
|
|
38
|
-
const result = sanitizeForEvidence(long);
|
|
39
|
-
expect(result).toMatch(/___TRUNCATED___$/);
|
|
40
|
-
expect(result.length).toBeLessThanOrEqual(MAX_EVIDENCE_VALUE_CHARS + 20);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('redacts OpenAI-style secret keys (sk-*)', () => {
|
|
44
|
-
const token = 'sk-proj-' + 'a'.repeat(30);
|
|
45
|
-
const result = sanitizeForEvidence(`token is ${token}`);
|
|
46
|
-
expect(result).toContain('___REDACTED___');
|
|
47
|
-
expect(result).not.toContain(token);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('redacts JWT-like patterns (eyJ*)', () => {
|
|
51
|
-
const jwt = 'eyJ' + 'a'.repeat(30) + '.bc';
|
|
52
|
-
const result = sanitizeForEvidence(`Bearer ${jwt}`);
|
|
53
|
-
expect(result).toContain('___REDACTED___');
|
|
54
|
-
expect(result).not.toContain(jwt);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('redacts long base64-like strings', () => {
|
|
58
|
-
const token = 'A'.repeat(50);
|
|
59
|
-
const result = sanitizeForEvidence(`hash: ${token}`);
|
|
60
|
-
expect(result).toContain('___REDACTED___');
|
|
61
|
-
expect(result).not.toContain(token);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('redacts GitHub PATs (ghp_*)', () => {
|
|
65
|
-
const token = 'ghp_' + 'a'.repeat(40);
|
|
66
|
-
const result = sanitizeForEvidence(token);
|
|
67
|
-
expect(result).toContain('___REDACTED___');
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('strips internal PD tags from evidence', () => {
|
|
71
|
-
const result = sanitizeForEvidence('[EMOTIONAL_DAMAGE_DETECTED:severe] something went wrong');
|
|
72
|
-
expect(result).not.toContain('EMOTIONAL_DAMAGE_DETECTED');
|
|
73
|
-
expect(result).toContain('something went wrong');
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('returns safe string for non-string values', () => {
|
|
77
|
-
expect(sanitizeForEvidence(42)).toBe('42');
|
|
78
|
-
expect(sanitizeForEvidence(null)).toBe('');
|
|
79
|
-
expect(sanitizeForEvidence(undefined)).toBe('');
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('converges absolute paths to basename when no workspaceDir', () => {
|
|
83
|
-
const result = sanitizeForEvidence('/home/user/secrets/token.json');
|
|
84
|
-
expect(result).toBe('<path:token.json>');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('converges absolute paths to repo-relative when workspaceDir matches', () => {
|
|
88
|
-
const result = sanitizeForEvidence('/workspace/my-repo/src/index.ts', '/workspace/my-repo');
|
|
89
|
-
expect(result).toBe('src/index.ts');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
// ── Path substring sanitization ──
|
|
93
|
-
|
|
94
|
-
it('replaces Windows absolute path in command with basename', () => {
|
|
95
|
-
const result = sanitizeForEvidence('cd D:\\Code\\principles && git status');
|
|
96
|
-
expect(result).not.toContain('D:\\Code\\principles');
|
|
97
|
-
expect(result).toContain('principles');
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('replaces Windows absolute path in reason with basename', () => {
|
|
101
|
-
const result = sanitizeForEvidence('error in C:\\Users\\Administrator\\secret.txt');
|
|
102
|
-
expect(result).not.toContain('C:\\Users\\Administrator');
|
|
103
|
-
expect(result).not.toContain('Administrator');
|
|
104
|
-
expect(result).toContain('secret.txt');
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('replaces POSIX absolute path in string', () => {
|
|
108
|
-
const result = sanitizeForEvidence('failed to read /home/user/project/src/config.ts');
|
|
109
|
-
expect(result).not.toContain('/home/user/project');
|
|
110
|
-
expect(result).toContain('config.ts');
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('converges workspace-internal path in string to repo-relative', () => {
|
|
114
|
-
const result = sanitizeForEvidence(
|
|
115
|
-
'edit failed on D:\\Code\\principles\\src\\index.ts',
|
|
116
|
-
'D:\\Code\\principles',
|
|
117
|
-
);
|
|
118
|
-
expect(result).not.toContain('D:\\Code\\principles');
|
|
119
|
-
expect(result).toContain('src\\index.ts');
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// ── sanitizeToolParamsForEvidence ──
|
|
123
|
-
|
|
124
|
-
it('redacts long content/text/input/new_string fields', () => {
|
|
125
|
-
const params = {
|
|
126
|
-
file_path: 'src/file.ts',
|
|
127
|
-
content: ' data chunk '.repeat(60),
|
|
128
|
-
text: ' report line '.repeat(60),
|
|
129
|
-
};
|
|
130
|
-
const result = sanitizeToolParamsForEvidence(params);
|
|
131
|
-
expect(result.file_path).toBe('src/file.ts');
|
|
132
|
-
expect(result.content).toMatch(/___TRUNCATED___$/);
|
|
133
|
-
expect(result.text).toMatch(/___TRUNCATED___$/);
|
|
134
|
-
expect(result.content.length).toBeLessThan(500);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('keeps short normal fields intact', () => {
|
|
138
|
-
const params = { file_path: 'src/index.ts', content: 'short-content', query: 'SELECT * FROM users' };
|
|
139
|
-
const result = sanitizeToolParamsForEvidence(params);
|
|
140
|
-
expect(result.file_path).toBe('src/index.ts');
|
|
141
|
-
expect(result.content).toBe('short-content');
|
|
142
|
-
expect(result.query).toBe('SELECT * FROM users');
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('redacts token-like strings inside content/text fields', () => {
|
|
146
|
-
const token = 'sk-proj-' + 'a'.repeat(30);
|
|
147
|
-
const params = { content: `key is ${token}` };
|
|
148
|
-
const result = sanitizeToolParamsForEvidence(params);
|
|
149
|
-
expect(result.content).toContain('___REDACTED___');
|
|
150
|
-
expect(result.content).not.toContain(token);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
// ── edit params: nested edits array ──
|
|
154
|
-
|
|
155
|
-
it('sanitizes edit params with nested edits[].oldText/newText', () => {
|
|
156
|
-
const secretToken = 'sk-proj-' + 'a'.repeat(30);
|
|
157
|
-
const params = {
|
|
158
|
-
file_path: '/repo/src/config.ts',
|
|
159
|
-
edits: [
|
|
160
|
-
{ oldText: secretToken, newText: 'safe-value' },
|
|
161
|
-
{ oldText: 'const x = 1;', newText: ' data '.repeat(200) },
|
|
162
|
-
],
|
|
163
|
-
};
|
|
164
|
-
const result = sanitizeToolParamsForEvidence(params, '/repo') as Record<string, unknown>;
|
|
165
|
-
const edits = result.edits as Array<Record<string, unknown>>;
|
|
166
|
-
// Token in oldText redacted
|
|
167
|
-
expect(edits[0].oldText).toContain('___REDACTED___');
|
|
168
|
-
expect(edits[0].oldText).not.toContain(secretToken);
|
|
169
|
-
// Short value preserved
|
|
170
|
-
expect(edits[0].newText).toBe('safe-value');
|
|
171
|
-
// Long newText truncated
|
|
172
|
-
expect(edits[1].newText).toMatch(/___TRUNCATED___$/);
|
|
173
|
-
// file_path converged to relative (workspaceDir provided)
|
|
174
|
-
expect(result.file_path).toBe('src/config.ts');
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
// ── command/query: token redaction ──
|
|
178
|
-
|
|
179
|
-
it('redacts tokens in command and query fields', () => {
|
|
180
|
-
const jwt = 'eyJ' + 'a'.repeat(30) + '.bc';
|
|
181
|
-
const skToken = 'sk-proj-' + 'a'.repeat(30);
|
|
182
|
-
const params = {
|
|
183
|
-
command: `curl -H "Authorization: Bearer ${jwt}" https://api.example.com`,
|
|
184
|
-
query: `SELECT * FROM users WHERE api_key = "${skToken}"`,
|
|
185
|
-
};
|
|
186
|
-
const result = sanitizeToolParamsForEvidence(params);
|
|
187
|
-
expect(result.command).toContain('___REDACTED___');
|
|
188
|
-
expect(result.command).not.toContain(jwt);
|
|
189
|
-
expect(result.query).toContain('___REDACTED___');
|
|
190
|
-
expect(result.query).not.toContain(skToken);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
// ── null/array/string input: no throw ──
|
|
194
|
-
|
|
195
|
-
it('handles null input without throwing', () => {
|
|
196
|
-
expect(() => sanitizeToolParamsForEvidence(null)).not.toThrow();
|
|
197
|
-
expect(sanitizeToolParamsForEvidence(null)).toEqual({});
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it('handles array input without throwing', () => {
|
|
201
|
-
const result = sanitizeToolParamsForEvidence(['a', 'b', 'c']);
|
|
202
|
-
expect(result['<array-input>']).toBeDefined();
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it('handles string input without throwing', () => {
|
|
206
|
-
const result = sanitizeToolParamsForEvidence('raw string input');
|
|
207
|
-
expect(result['<string-input>']).toBeDefined();
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it('handles undefined input without throwing', () => {
|
|
211
|
-
expect(sanitizeToolParamsForEvidence(undefined)).toEqual({});
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it('handles number input without throwing', () => {
|
|
215
|
-
expect(sanitizeToolParamsForEvidence(42)).toEqual({});
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
// ── sanitizeValueForEvidence: recursive ──
|
|
219
|
-
|
|
220
|
-
it('recursively sanitizes nested objects', () => {
|
|
221
|
-
const token = 'sk-proj-' + 'a'.repeat(30);
|
|
222
|
-
const input = { a: { b: { c: token } } };
|
|
223
|
-
const result = sanitizeValueForEvidence(input) as Record<string, unknown>;
|
|
224
|
-
const nested = (result.a as Record<string, unknown>).b as Record<string, unknown>;
|
|
225
|
-
expect(nested.c).toContain('___REDACTED___');
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
it('respects max array items limit', () => {
|
|
229
|
-
const input = { items: Array.from({ length: 100 }, (_, i) => `item-${i}`) };
|
|
230
|
-
const result = sanitizeValueForEvidence(input) as Record<string, unknown>;
|
|
231
|
-
const items = result.items as unknown[];
|
|
232
|
-
expect(items.length).toBeLessThanOrEqual(22);
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
it('respects max depth limit', () => {
|
|
236
|
-
const deep: any = { a: { b: { c: { d: { e: 'too deep' } } } } };
|
|
237
|
-
const result = sanitizeValueForEvidence(deep, 0) as Record<string, unknown>;
|
|
238
|
-
const a = result.a as Record<string, unknown>;
|
|
239
|
-
const b = a.b as Record<string, unknown>;
|
|
240
|
-
const c = b.c as Record<string, unknown>;
|
|
241
|
-
const d = c.d as Record<string, unknown>;
|
|
242
|
-
expect(d.e).toBe('<max-depth>');
|
|
243
|
-
});
|
|
244
|
-
});
|