@unerr-ai/unerr 0.2.0 → 0.2.2
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/README.md +6 -0
- package/dist/cli.js +37236 -35793
- package/package.json +6 -1
- package/dist/behaviors/agent-llm-bridge.js +0 -166
- package/dist/behaviors/architecture-guard.js +0 -256
- package/dist/behaviors/auto-doc.js +0 -247
- package/dist/behaviors/cascade-guard.js +0 -289
- package/dist/behaviors/change-narrative.js +0 -270
- package/dist/behaviors/convention-drift.js +0 -290
- package/dist/behaviors/framework.js +0 -235
- package/dist/behaviors/guard-formatter.js +0 -44
- package/dist/behaviors/incomplete-work.js +0 -270
- package/dist/behaviors/loop-breaker.js +0 -300
- package/dist/behaviors/session-continuity.js +0 -208
- package/dist/commands/branches.js +0 -97
- package/dist/commands/check-commit.js +0 -225
- package/dist/commands/compress-output.js +0 -64
- package/dist/commands/config-verify.js +0 -243
- package/dist/commands/daemon.js +0 -905
- package/dist/commands/dashboard.js +0 -52
- package/dist/commands/debug.js +0 -200
- package/dist/commands/enrich.js +0 -184
- package/dist/commands/exec.js +0 -233
- package/dist/commands/gain.js +0 -156
- package/dist/commands/hook.js +0 -88
- package/dist/commands/index.js +0 -88
- package/dist/commands/init.js +0 -74
- package/dist/commands/install.js +0 -505
- package/dist/commands/learn.js +0 -116
- package/dist/commands/manifest.js +0 -193
- package/dist/commands/rewind.js +0 -103
- package/dist/commands/serve.js +0 -19
- package/dist/commands/setup-wizard.js +0 -414
- package/dist/commands/skills.js +0 -64
- package/dist/commands/stats.js +0 -20
- package/dist/commands/status.js +0 -654
- package/dist/commands/timeline.js +0 -139
- package/dist/commands/uninstall.js +0 -230
- package/dist/components/App.js +0 -109
- package/dist/components/Banner.js +0 -12
- package/dist/components/ConfirmPrompt.js +0 -25
- package/dist/components/DriftSummary.js +0 -23
- package/dist/components/GradeBadge.js +0 -15
- package/dist/components/HealthCard.js +0 -18
- package/dist/components/InkSpinner.js +0 -22
- package/dist/components/InputBox.js +0 -17
- package/dist/components/KeyValue.js +0 -13
- package/dist/components/MessageList.js +0 -14
- package/dist/components/ProgressBar.js +0 -26
- package/dist/components/Section.js +0 -16
- package/dist/components/SessionSummaryCard.js +0 -73
- package/dist/components/StartupDisplay.js +0 -24
- package/dist/components/StatusDashboard.js +0 -57
- package/dist/components/StatusLine.js +0 -8
- package/dist/components/StepLine.js +0 -22
- package/dist/components/Theme.js +0 -20
- package/dist/components/ToolProgress.js +0 -8
- package/dist/components/ViolationList.js +0 -21
- package/dist/components/render.js +0 -13
- package/dist/config/agent-registry.js +0 -237
- package/dist/config/claude-settings-hooks.js +0 -304
- package/dist/config/hook-installer.js +0 -65
- package/dist/config/instruction-writer.js +0 -388
- package/dist/config/mcp-config-writer.js +0 -266
- package/dist/config/settings.js +0 -174
- package/dist/config/tool-detector.js +0 -42
- package/dist/config/value-surfacing.js +0 -119
- package/dist/core/context-assembly.js +0 -108
- package/dist/core/conversation.js +0 -33
- package/dist/core/local-chat-provider.js +0 -475
- package/dist/core/provider-factory.js +0 -55
- package/dist/core/providers.js +0 -90
- package/dist/core/query-engine.js +0 -174
- package/dist/daemon/api.js +0 -312
- package/dist/daemon/autostart.js +0 -119
- package/dist/daemon/bootstrap.js +0 -39
- package/dist/daemon/client.js +0 -164
- package/dist/daemon/detect-ci.js +0 -81
- package/dist/daemon/platform-linux.js +0 -146
- package/dist/daemon/platform-macos.js +0 -134
- package/dist/daemon/platform-windows.js +0 -116
- package/dist/daemon/process-manager.js +0 -299
- package/dist/daemon/protocol.js +0 -23
- package/dist/daemon/registry.js +0 -270
- package/dist/daemon/settings-schema.js +0 -72
- package/dist/daemon/system-health.js +0 -134
- package/dist/daemon/version-checker.js +0 -262
- package/dist/daemon/warm-start.js +0 -223
- package/dist/entrypoints/cli.js +0 -1043
- package/dist/entrypoints/daemon.js +0 -380
- package/dist/entrypoints/repl.js +0 -147
- package/dist/hooks/adapters/claude-code.js +0 -90
- package/dist/hooks/adapters/cline.js +0 -100
- package/dist/hooks/adapters/cursor.js +0 -98
- package/dist/hooks/hook-dedup.js +0 -79
- package/dist/hooks/hook-runner.js +0 -113
- package/dist/hooks/navigation-hooks.js +0 -175
- package/dist/hooks/prompt-hooks.js +0 -63
- package/dist/hooks/shell-hooks.js +0 -47
- package/dist/ignore.js +0 -111
- package/dist/intelligence/approach-suggester.js +0 -61
- package/dist/intelligence/ast-extractor.js +0 -2615
- package/dist/intelligence/ast-worker.js +0 -34
- package/dist/intelligence/background-indexer.js +0 -121
- package/dist/intelligence/blast-radius.js +0 -200
- package/dist/intelligence/community-detection.js +0 -691
- package/dist/intelligence/community-detector.js +0 -184
- package/dist/intelligence/computation-scheduler.js +0 -75
- package/dist/intelligence/confidence-propagation.js +0 -47
- package/dist/intelligence/convention-detector.js +0 -242
- package/dist/intelligence/convention-learner.js +0 -205
- package/dist/intelligence/convention-matcher.js +0 -205
- package/dist/intelligence/cozo-schema.js +0 -376
- package/dist/intelligence/decision-point-detector.js +0 -90
- package/dist/intelligence/deep-dive-tools.js +0 -586
- package/dist/intelligence/durability-scorer.js +0 -84
- package/dist/intelligence/exploration-cost.js +0 -204
- package/dist/intelligence/exploration-pattern-tracker.js +0 -61
- package/dist/intelligence/fact-generator.js +0 -322
- package/dist/intelligence/facts-schema.js +0 -90
- package/dist/intelligence/file-intelligence.js +0 -59
- package/dist/intelligence/graph-holder.js +0 -220
- package/dist/intelligence/graph-temporal-joiner.js +0 -238
- package/dist/intelligence/health-grade.js +0 -423
- package/dist/intelligence/health-grader.js +0 -200
- package/dist/intelligence/health-map-data.js +0 -259
- package/dist/intelligence/import-symbols.js +0 -136
- package/dist/intelligence/incremental-indexer.js +0 -658
- package/dist/intelligence/indexer/centrality.js +0 -62
- package/dist/intelligence/indexer/cfg-context.js +0 -95
- package/dist/intelligence/indexer/confidence.js +0 -34
- package/dist/intelligence/indexer/cross-file-resolver.js +0 -104
- package/dist/intelligence/indexer/edge-repair.js +0 -89
- package/dist/intelligence/indexer/entity-key.js +0 -17
- package/dist/intelligence/indexer/export-map.js +0 -132
- package/dist/intelligence/indexer/git-cochange.js +0 -128
- package/dist/intelligence/indexer/graph-patch.js +0 -147
- package/dist/intelligence/indexer/incremental.js +0 -78
- package/dist/intelligence/indexer/ingest.js +0 -160
- package/dist/intelligence/indexer/language-detect.js +0 -226
- package/dist/intelligence/indexer/metadata.js +0 -63
- package/dist/intelligence/indexer/mutation-tracker.js +0 -79
- package/dist/intelligence/indexer/orchestrator.js +0 -155
- package/dist/intelligence/indexer/plugin-interface.js +0 -31
- package/dist/intelligence/indexer/plugins/csharp.js +0 -440
- package/dist/intelligence/indexer/plugins/go.js +0 -335
- package/dist/intelligence/indexer/plugins/java.js +0 -370
- package/dist/intelligence/indexer/plugins/python.js +0 -358
- package/dist/intelligence/indexer/plugins/regex-fallback.js +0 -82
- package/dist/intelligence/indexer/plugins/ruby.js +0 -290
- package/dist/intelligence/indexer/plugins/rust.js +0 -484
- package/dist/intelligence/indexer/plugins/tier2-generic.js +0 -310
- package/dist/intelligence/indexer/plugins/typescript.js +0 -456
- package/dist/intelligence/indexer/resource-monitor.js +0 -93
- package/dist/intelligence/indexer/scip/decoder.js +0 -253
- package/dist/intelligence/indexer/scip/detector.js +0 -232
- package/dist/intelligence/indexer/scip/downloader.js +0 -427
- package/dist/intelligence/indexer/scip/fallback.js +0 -34
- package/dist/intelligence/indexer/scip/merger.js +0 -109
- package/dist/intelligence/indexer/scip/orchestrator.js +0 -433
- package/dist/intelligence/indexer/scip/runner.js +0 -98
- package/dist/intelligence/indexer/snapshot.js +0 -66
- package/dist/intelligence/indexer/test-detector.js +0 -196
- package/dist/intelligence/indexer/watch-integration.js +0 -61
- package/dist/intelligence/indexer/worker.js +0 -85
- package/dist/intelligence/local-convention-detector.js +0 -437
- package/dist/intelligence/local-embeddings.js +0 -190
- package/dist/intelligence/local-graph.js +0 -1946
- package/dist/intelligence/local-indexer.js +0 -1575
- package/dist/intelligence/local-llm.js +0 -163
- package/dist/intelligence/local-rule-generator.js +0 -154
- package/dist/intelligence/local-snapshot.js +0 -213
- package/dist/intelligence/negative-knowledge.js +0 -103
- package/dist/intelligence/persistent-db.js +0 -85
- package/dist/intelligence/query-router.js +0 -2556
- package/dist/intelligence/risk-classifier.js +0 -116
- package/dist/intelligence/rule-evaluator.js +0 -380
- package/dist/intelligence/rule-generator.js +0 -49
- package/dist/intelligence/search-index.js +0 -173
- package/dist/intelligence/semantic/docstring-extractor.js +0 -67
- package/dist/intelligence/semantic/embedding-store.js +0 -52
- package/dist/intelligence/semantic/enrichment-orchestrator.js +0 -48
- package/dist/intelligence/semantic/git-message-miner.js +0 -114
- package/dist/intelligence/semantic/identifier-tokenizer.js +0 -51
- package/dist/intelligence/semantic/node2vec-embeddings.js +0 -71
- package/dist/intelligence/semantic/node2vec-walks.js +0 -103
- package/dist/intelligence/semantic/path-domain-inference.js +0 -112
- package/dist/intelligence/semantic/similarity-engine.js +0 -60
- package/dist/intelligence/semantic/tfidf-vectors.js +0 -88
- package/dist/intelligence/session-brief-builder.js +0 -159
- package/dist/intelligence/session-context.js +0 -221
- package/dist/intelligence/session-health-monitor.js +0 -211
- package/dist/intelligence/session-narrative.js +0 -197
- package/dist/intelligence/session-pattern-analyzer.js +0 -218
- package/dist/intelligence/signal-scorer.js +0 -390
- package/dist/intelligence/signal-show-store.js +0 -182
- package/dist/intelligence/smart-truncate.js +0 -158
- package/dist/intelligence/subgraph-cache.js +0 -88
- package/dist/intelligence/temporal-facts.js +0 -494
- package/dist/intelligence/token-estimator.js +0 -100
- package/dist/intelligence/tool-injector.js +0 -87
- package/dist/intelligence/tree-sitter-loader.js +0 -71
- package/dist/intelligence/worker-pool.js +0 -116
- package/dist/proxy/arg-validator.js +0 -79
- package/dist/proxy/auto-bootstrap.js +0 -167
- package/dist/proxy/bridge.js +0 -147
- package/dist/proxy/budget-enforcer.js +0 -70
- package/dist/proxy/compression-quality-monitor.js +0 -160
- package/dist/proxy/compression-stats.js +0 -51
- package/dist/proxy/context-rot-detector.js +0 -137
- package/dist/proxy/drift-detector.js +0 -139
- package/dist/proxy/efficiency-tracker.js +0 -79
- package/dist/proxy/fact-ranking.js +0 -154
- package/dist/proxy/format-encoder.js +0 -266
- package/dist/proxy/http-transport.js +0 -90
- package/dist/proxy/lifecycle-actor.js +0 -55
- package/dist/proxy/lifecycle-machine.js +0 -187
- package/dist/proxy/log-tailer.js +0 -265
- package/dist/proxy/model-pricing.js +0 -98
- package/dist/proxy/network-firewall.js +0 -141
- package/dist/proxy/nudge-state.js +0 -93
- package/dist/proxy/output-compressor.js +0 -185
- package/dist/proxy/pid-lock.js +0 -291
- package/dist/proxy/proxy-context.js +0 -11
- package/dist/proxy/proxy.js +0 -2633
- package/dist/proxy/response-enrichment.js +0 -32
- package/dist/proxy/response-envelope.js +0 -313
- package/dist/proxy/session-dedup.js +0 -82
- package/dist/proxy/session-legend.js +0 -30
- package/dist/proxy/session-persistence.js +0 -210
- package/dist/proxy/session-resume.js +0 -94
- package/dist/proxy/session-stats.js +0 -513
- package/dist/proxy/shell-classifier.js +0 -1346
- package/dist/proxy/shell-compression-log.js +0 -93
- package/dist/proxy/shell-compressor.js +0 -390
- package/dist/proxy/shell-graph-boost.js +0 -202
- package/dist/proxy/shell-monitor-map.js +0 -18
- package/dist/proxy/shell-stats.js +0 -54
- package/dist/proxy/shell-strategies/cloud.js +0 -215
- package/dist/proxy/shell-strategies/diff.js +0 -159
- package/dist/proxy/shell-strategies/error-diagnostic.js +0 -796
- package/dist/proxy/shell-strategies/filter-dsl.js +0 -358
- package/dist/proxy/shell-strategies/git-status.js +0 -177
- package/dist/proxy/shell-strategies/key-value.js +0 -193
- package/dist/proxy/shell-strategies/log-text.js +0 -154
- package/dist/proxy/shell-strategies/omni.js +0 -188
- package/dist/proxy/shell-strategies/progress.js +0 -55
- package/dist/proxy/shell-strategies/redact.js +0 -76
- package/dist/proxy/shell-strategies/structured.js +0 -241
- package/dist/proxy/shell-strategies/tabular.js +0 -243
- package/dist/proxy/shell-strategies/test-results-types.js +0 -13
- package/dist/proxy/shell-strategies/test-results.js +0 -784
- package/dist/proxy/shell-strategies/tree-paths.js +0 -144
- package/dist/proxy/shell-strategies/yaml.js +0 -182
- package/dist/proxy/shell-tee.js +0 -111
- package/dist/proxy/signal-dedup.js +0 -171
- package/dist/proxy/startup-renderer.js +0 -158
- package/dist/proxy/task-token-display.js +0 -38
- package/dist/proxy/token-counter.js +0 -61
- package/dist/proxy/tool-clusters.js +0 -273
- package/dist/proxy/tool-definitions.js +0 -525
- package/dist/proxy/transport-mux.js +0 -229
- package/dist/proxy/wire-cap.js +0 -268
- package/dist/rules/developer.mozilla.org.json +0 -9
- package/dist/rules/github.com.json +0 -21
- package/dist/schemas/api/skills.js +0 -19
- package/dist/schemas/common/errors.js +0 -7
- package/dist/schemas/common/headers.js +0 -5
- package/dist/schemas/entities/edge.js +0 -25
- package/dist/schemas/entities/entity.js +0 -22
- package/dist/schemas/entities/rule.js +0 -18
- package/dist/schemas/index.js +0 -14
- package/dist/server/event-bus.js +0 -59
- package/dist/server/http.js +0 -156
- package/dist/server/middleware.js +0 -70
- package/dist/server/routes/drift.js +0 -97
- package/dist/server/routes/intelligence.js +0 -1217
- package/dist/server/routes/reasoning-quality.js +0 -444
- package/dist/server/routes/session.js +0 -86
- package/dist/server/routes/stream.js +0 -120
- package/dist/server/routes/system.js +0 -73
- package/dist/server/routes/temporal.js +0 -170
- package/dist/server/routes/timeline.js +0 -232
- package/dist/server/routes/token-flow.js +0 -403
- package/dist/skills/effectiveness-tracker.js +0 -93
- package/dist/skills/local-pack.js +0 -380
- package/dist/skills/resolver.js +0 -495
- package/dist/state-detector.js +0 -83
- package/dist/timeline/intent-detector.js +0 -263
- package/dist/timeline/loop-miner.js +0 -140
- package/dist/timeline/open-threads.js +0 -49
- package/dist/timeline/signal-reinforcer.js +0 -62
- package/dist/timeline/timeline-bootstrap.js +0 -151
- package/dist/timeline/timeline-store.js +0 -618
- package/dist/tools/coding/bash.js +0 -49
- package/dist/tools/coding/file-edit.js +0 -72
- package/dist/tools/coding/file-outline.js +0 -227
- package/dist/tools/coding/file-read-protocol.js +0 -425
- package/dist/tools/coding/file-read.js +0 -35
- package/dist/tools/coding/file-write.js +0 -43
- package/dist/tools/coding/glob-tool.js +0 -109
- package/dist/tools/coding/grep.js +0 -162
- package/dist/tools/coding/index.js +0 -27
- package/dist/tools/intelligence/index.js +0 -269
- package/dist/tools/intelligence/record-fact.js +0 -48
- package/dist/tools/intelligence/timeline-markers.js +0 -130
- package/dist/tools/registry.js +0 -47
- package/dist/tools/types.js +0 -8
- package/dist/tracking/auto-snapshot-triggers.js +0 -246
- package/dist/tracking/branch-context.js +0 -115
- package/dist/tracking/branch-snapshot.js +0 -217
- package/dist/tracking/causal-bridge.js +0 -317
- package/dist/tracking/circuit-breaker.js +0 -147
- package/dist/tracking/commit-watcher.js +0 -114
- package/dist/tracking/context-ledger.js +0 -119
- package/dist/tracking/correction-detector.js +0 -324
- package/dist/tracking/drift-tracker.js +0 -874
- package/dist/tracking/durability-tracker.js +0 -94
- package/dist/tracking/entity-rewind.js +0 -200
- package/dist/tracking/file-hash-state.js +0 -114
- package/dist/tracking/git-attribution.js +0 -132
- package/dist/tracking/git-trailers.js +0 -171
- package/dist/tracking/intelligence-counter.js +0 -46
- package/dist/tracking/intent-correlator.js +0 -202
- package/dist/tracking/intent-encoder.js +0 -52
- package/dist/tracking/intent-token-tracker.js +0 -159
- package/dist/tracking/ledger-archiver.js +0 -94
- package/dist/tracking/ledger-chains.js +0 -245
- package/dist/tracking/metrics-store.js +0 -361
- package/dist/tracking/native-watcher.js +0 -131
- package/dist/tracking/offline-rewind.js +0 -295
- package/dist/tracking/pending-violations.js +0 -74
- package/dist/tracking/persistence-effectiveness.js +0 -167
- package/dist/tracking/prompt-durability.js +0 -202
- package/dist/tracking/quality-signals.js +0 -213
- package/dist/tracking/redactor.js +0 -73
- package/dist/tracking/rewind-engine.js +0 -161
- package/dist/tracking/session-history.js +0 -128
- package/dist/tracking/session-receipt.js +0 -88
- package/dist/tracking/session-summary-writer.js +0 -157
- package/dist/tracking/shadow-ledger.js +0 -321
- package/dist/tracking/stash-manager.js +0 -258
- package/dist/tracking/timeline-fork.js +0 -213
- package/dist/tracking/timeline.js +0 -69
- package/dist/tracking/token-flow.js +0 -276
- package/dist/tracking/turn-segmenter.js +0 -122
- package/dist/tracking/weekly-accumulator.js +0 -179
- package/dist/tracking/working-snapshots.js +0 -188
- package/dist/tracking/workspace-manifest.js +0 -176
- package/dist/transport/http.js +0 -102
- package/dist/utils/counterfactual.js +0 -65
- package/dist/utils/deep-link.js +0 -34
- package/dist/utils/detect.js +0 -193
- package/dist/utils/exec.js +0 -73
- package/dist/utils/file-logger.js +0 -87
- package/dist/utils/format-error.js +0 -29
- package/dist/utils/git.js +0 -181
- package/dist/utils/log.js +0 -57
- package/dist/utils/logger.js +0 -35
- package/dist/utils/mcp-content-json.js +0 -8
- package/dist/utils/session-logger.js +0 -154
- package/dist/utils/startup-log.js +0 -512
- package/dist/utils/ui.js +0 -56
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Path-Based Domain Inference — infers domain labels from file paths.
|
|
3
|
-
*
|
|
4
|
-
* Uses directory naming conventions to assign domain labels:
|
|
5
|
-
* src/auth/ → "authentication"
|
|
6
|
-
* src/payments/ → "payments"
|
|
7
|
-
* src/api/routes/ → "api"
|
|
8
|
-
* tests/ → "testing"
|
|
9
|
-
*/
|
|
10
|
-
const PATH_PATTERNS = [
|
|
11
|
-
{ pattern: /\bauth\b/i, domain: "authentication", confidence: 0.9 },
|
|
12
|
-
{
|
|
13
|
-
pattern: /\bpayment|billing|stripe|checkout\b/i,
|
|
14
|
-
domain: "payments",
|
|
15
|
-
confidence: 0.9,
|
|
16
|
-
},
|
|
17
|
-
{ pattern: /\bapi\b/i, domain: "api", confidence: 0.8 },
|
|
18
|
-
{
|
|
19
|
-
pattern: /\broute|router|middleware\b/i,
|
|
20
|
-
domain: "routing",
|
|
21
|
-
confidence: 0.8,
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
pattern: /\bdb|database|model|schema|migration\b/i,
|
|
25
|
-
domain: "database",
|
|
26
|
-
confidence: 0.85,
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
pattern: /\btest|spec|__tests__|__test__\b/i,
|
|
30
|
-
domain: "testing",
|
|
31
|
-
confidence: 0.95,
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
pattern: /\bconfig|settings|env\b/i,
|
|
35
|
-
domain: "configuration",
|
|
36
|
-
confidence: 0.8,
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
pattern: /\blog|logger|telemetry|monitor\b/i,
|
|
40
|
-
domain: "observability",
|
|
41
|
-
confidence: 0.8,
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
pattern: /\butil|helper|lib|common|shared\b/i,
|
|
45
|
-
domain: "utilities",
|
|
46
|
-
confidence: 0.7,
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
pattern: /\bui|component|view|page|layout\b/i,
|
|
50
|
-
domain: "frontend",
|
|
51
|
-
confidence: 0.85,
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
pattern: /\bstyle|css|theme|design\b/i,
|
|
55
|
-
domain: "styling",
|
|
56
|
-
confidence: 0.85,
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
pattern: /\bsecurity|crypto|encrypt|token\b/i,
|
|
60
|
-
domain: "security",
|
|
61
|
-
confidence: 0.9,
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
pattern: /\bemail|notification|message|queue\b/i,
|
|
65
|
-
domain: "messaging",
|
|
66
|
-
confidence: 0.8,
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
pattern: /\bstorage|upload|file|asset|media\b/i,
|
|
70
|
-
domain: "storage",
|
|
71
|
-
confidence: 0.8,
|
|
72
|
-
},
|
|
73
|
-
{ pattern: /\bcache|redis|memcache\b/i, domain: "caching", confidence: 0.9 },
|
|
74
|
-
{ pattern: /\bsearch|index|elastic\b/i, domain: "search", confidence: 0.85 },
|
|
75
|
-
{
|
|
76
|
-
pattern: /\bgraph|intelligence|semantic|embedding\b/i,
|
|
77
|
-
domain: "intelligence",
|
|
78
|
-
confidence: 0.9,
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
pattern: /\bproxy|transport|protocol|mcp\b/i,
|
|
82
|
-
domain: "infrastructure",
|
|
83
|
-
confidence: 0.8,
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
pattern: /\btracking|analytics|metric\b/i,
|
|
87
|
-
domain: "tracking",
|
|
88
|
-
confidence: 0.85,
|
|
89
|
-
},
|
|
90
|
-
];
|
|
91
|
-
/**
|
|
92
|
-
* Infer domain labels for a file path.
|
|
93
|
-
* Returns all matching domains sorted by confidence.
|
|
94
|
-
*/
|
|
95
|
-
export function inferDomain(filePath) {
|
|
96
|
-
const labels = [];
|
|
97
|
-
for (const { pattern, domain, confidence } of PATH_PATTERNS) {
|
|
98
|
-
if (pattern.test(filePath)) {
|
|
99
|
-
labels.push({ domain, confidence, source: "path-pattern" });
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
labels.sort((a, b) => b.confidence - a.confidence);
|
|
103
|
-
return labels;
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Get the primary domain for a file path.
|
|
107
|
-
* Returns null if no domain pattern matches.
|
|
108
|
-
*/
|
|
109
|
-
export function getPrimaryDomain(filePath) {
|
|
110
|
-
const labels = inferDomain(filePath);
|
|
111
|
-
return labels[0]?.domain ?? null;
|
|
112
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Combined Similarity Engine — weighted cosine across lexical + structural + metadata.
|
|
3
|
-
*
|
|
4
|
-
* Weights: 0.5 lexical (TF-IDF) + 0.3 structural (Node2Vec) + 0.2 metadata (domain + git)
|
|
5
|
-
*/
|
|
6
|
-
import { cosineSimilarity } from "./embedding-store.js";
|
|
7
|
-
const DEFAULT_WEIGHTS = {
|
|
8
|
-
lexical: 0.5,
|
|
9
|
-
structural: 0.3,
|
|
10
|
-
metadata: 0.2,
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Compute combined similarity between two entities.
|
|
14
|
-
*/
|
|
15
|
-
export function computeSimilarity(a, b, weights = DEFAULT_WEIGHTS) {
|
|
16
|
-
const lexicalSim = cosineSimilarity(a.lexical, b.lexical);
|
|
17
|
-
const structuralSim = cosineSimilarity(a.structural, b.structural);
|
|
18
|
-
const metadataSim = computeMetadataSimilarity(a, b);
|
|
19
|
-
return (weights.lexical * lexicalSim +
|
|
20
|
-
weights.structural * structuralSim +
|
|
21
|
-
weights.metadata * metadataSim);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Find the top-K most similar entities using the combined metric.
|
|
25
|
-
*/
|
|
26
|
-
export function findMostSimilar(queryKey, queryEmbeddings, allEmbeddings, topK = 10, weights = DEFAULT_WEIGHTS) {
|
|
27
|
-
const results = [];
|
|
28
|
-
for (const [key, embeddings] of allEmbeddings) {
|
|
29
|
-
if (key === queryKey)
|
|
30
|
-
continue;
|
|
31
|
-
const lexicalScore = cosineSimilarity(queryEmbeddings.lexical, embeddings.lexical);
|
|
32
|
-
const structuralScore = cosineSimilarity(queryEmbeddings.structural, embeddings.structural);
|
|
33
|
-
const metadataScore = computeMetadataSimilarity(queryEmbeddings, embeddings);
|
|
34
|
-
const score = weights.lexical * lexicalScore +
|
|
35
|
-
weights.structural * structuralScore +
|
|
36
|
-
weights.metadata * metadataScore;
|
|
37
|
-
results.push({
|
|
38
|
-
entityKey: key,
|
|
39
|
-
score,
|
|
40
|
-
lexicalScore,
|
|
41
|
-
structuralScore,
|
|
42
|
-
metadataScore,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
results.sort((a, b) => b.score - a.score);
|
|
46
|
-
return results.slice(0, topK);
|
|
47
|
-
}
|
|
48
|
-
function computeMetadataSimilarity(a, b) {
|
|
49
|
-
let score = 0;
|
|
50
|
-
if (a.domain && b.domain && a.domain === b.domain) {
|
|
51
|
-
score += 0.5;
|
|
52
|
-
}
|
|
53
|
-
if (a.keywords.length > 0 && b.keywords.length > 0) {
|
|
54
|
-
const aSet = new Set(a.keywords);
|
|
55
|
-
const overlap = b.keywords.filter((k) => aSet.has(k)).length;
|
|
56
|
-
const maxPossible = Math.max(a.keywords.length, b.keywords.length);
|
|
57
|
-
score += 0.5 * (overlap / maxPossible);
|
|
58
|
-
}
|
|
59
|
-
return Math.min(1, score);
|
|
60
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TF-IDF Vector Builder — produces 64-dimensional lexical embeddings.
|
|
3
|
-
*
|
|
4
|
-
* Corpus: all entity identifiers in the project.
|
|
5
|
-
* Method: standard TF-IDF with dimensionality reduction via hashing trick.
|
|
6
|
-
*
|
|
7
|
-
* Output: Float32Array[64] per entity, normalized to unit length.
|
|
8
|
-
* Performance: <500ms for 1K entities.
|
|
9
|
-
*/
|
|
10
|
-
import { tokenizeIdentifier } from "./identifier-tokenizer.js";
|
|
11
|
-
/**
|
|
12
|
-
* Build a TF-IDF corpus from entity identifiers.
|
|
13
|
-
*/
|
|
14
|
-
export function buildCorpus(identifiers) {
|
|
15
|
-
const documentFrequency = new Map();
|
|
16
|
-
const vocabulary = new Map();
|
|
17
|
-
let vocabIndex = 0;
|
|
18
|
-
for (const id of identifiers) {
|
|
19
|
-
const tokens = new Set(tokenizeIdentifier(id));
|
|
20
|
-
for (const token of tokens) {
|
|
21
|
-
documentFrequency.set(token, (documentFrequency.get(token) ?? 0) + 1);
|
|
22
|
-
if (!vocabulary.has(token)) {
|
|
23
|
-
vocabulary.set(token, vocabIndex++);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
const idf = new Map();
|
|
28
|
-
const N = identifiers.length;
|
|
29
|
-
for (const [token, df] of documentFrequency) {
|
|
30
|
-
idf.set(token, Math.log((N + 1) / (df + 1)) + 1);
|
|
31
|
-
}
|
|
32
|
-
return { vocabulary, idf, documentCount: N };
|
|
33
|
-
}
|
|
34
|
-
const VECTOR_DIM = 64;
|
|
35
|
-
/**
|
|
36
|
-
* Compute a 64-dim TF-IDF vector for a single identifier.
|
|
37
|
-
* Uses hashing trick for dimensionality reduction.
|
|
38
|
-
*/
|
|
39
|
-
export function computeTfIdfVector(identifier, corpus) {
|
|
40
|
-
const vector = new Float32Array(VECTOR_DIM);
|
|
41
|
-
const tokens = tokenizeIdentifier(identifier);
|
|
42
|
-
if (tokens.length === 0)
|
|
43
|
-
return vector;
|
|
44
|
-
const tokenCounts = new Map();
|
|
45
|
-
for (const token of tokens) {
|
|
46
|
-
tokenCounts.set(token, (tokenCounts.get(token) ?? 0) + 1);
|
|
47
|
-
}
|
|
48
|
-
for (const [token, count] of tokenCounts) {
|
|
49
|
-
const tf = count / tokens.length;
|
|
50
|
-
const idfVal = corpus.idf.get(token) ?? 1;
|
|
51
|
-
const tfidf = tf * idfVal;
|
|
52
|
-
const hashIdx = hashToken(token) % VECTOR_DIM;
|
|
53
|
-
vector[hashIdx] += tfidf;
|
|
54
|
-
}
|
|
55
|
-
normalize(vector);
|
|
56
|
-
return vector;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Build TF-IDF vectors for all entities at once.
|
|
60
|
-
*/
|
|
61
|
-
export function buildTfIdfVectors(identifiers) {
|
|
62
|
-
const corpus = buildCorpus(identifiers);
|
|
63
|
-
const vectors = new Map();
|
|
64
|
-
for (const id of identifiers) {
|
|
65
|
-
vectors.set(id, computeTfIdfVector(id, corpus));
|
|
66
|
-
}
|
|
67
|
-
return vectors;
|
|
68
|
-
}
|
|
69
|
-
function hashToken(token) {
|
|
70
|
-
let hash = 0;
|
|
71
|
-
for (let i = 0; i < token.length; i++) {
|
|
72
|
-
hash = ((hash << 5) - hash + token.charCodeAt(i)) | 0;
|
|
73
|
-
}
|
|
74
|
-
return Math.abs(hash);
|
|
75
|
-
}
|
|
76
|
-
function normalize(vector) {
|
|
77
|
-
let norm = 0;
|
|
78
|
-
for (let i = 0; i < vector.length; i++) {
|
|
79
|
-
norm += vector[i] * vector[i];
|
|
80
|
-
}
|
|
81
|
-
norm = Math.sqrt(norm);
|
|
82
|
-
if (norm > 0) {
|
|
83
|
-
for (let i = 0; i < vector.length; i++) {
|
|
84
|
-
vector[i] /= norm;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
export { VECTOR_DIM };
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SessionBriefBuilder — constructs a structured intelligence brief
|
|
3
|
-
* for the first tool call of a session.
|
|
4
|
-
*
|
|
5
|
-
* Replaces flat session_greeting + session_resume with a structured
|
|
6
|
-
* SessionBrief that includes inter-session changes, unfinished work,
|
|
7
|
-
* key facts, convention summary, and intelligence health.
|
|
8
|
-
*
|
|
9
|
-
* Part of Layer B of the Three-Layer Experience System.
|
|
10
|
-
*/
|
|
11
|
-
export class SessionBriefBuilder {
|
|
12
|
-
localGraph;
|
|
13
|
-
factStore;
|
|
14
|
-
graphStats;
|
|
15
|
-
healthGrade;
|
|
16
|
-
constructor(localGraph, factStore, graphStats, healthGrade) {
|
|
17
|
-
this.localGraph = localGraph;
|
|
18
|
-
this.factStore = factStore;
|
|
19
|
-
this.graphStats = graphStats;
|
|
20
|
-
this.healthGrade = healthGrade;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Build a structured session brief.
|
|
24
|
-
* Gathers intelligence from graph, fact store, and resume context.
|
|
25
|
-
*/
|
|
26
|
-
async build(resumeContext) {
|
|
27
|
-
const brief = {
|
|
28
|
-
greeting: this.buildGreeting(),
|
|
29
|
-
};
|
|
30
|
-
// Inter-session changes from resume context
|
|
31
|
-
if (resumeContext?.filesModified &&
|
|
32
|
-
resumeContext.filesModified.length > 0) {
|
|
33
|
-
brief.inter_session_changes = resumeContext.filesModified.slice(0, 10);
|
|
34
|
-
}
|
|
35
|
-
// Unfinished work from resume context
|
|
36
|
-
if (resumeContext?.incompleteEntities &&
|
|
37
|
-
resumeContext.incompleteEntities.length > 0) {
|
|
38
|
-
brief.unfinished_work = resumeContext.incompleteEntities.slice(0, 5);
|
|
39
|
-
}
|
|
40
|
-
// Gather async data in parallel
|
|
41
|
-
const [keyFacts, conventionSummary] = await Promise.all([
|
|
42
|
-
this.getKeyFacts(),
|
|
43
|
-
this.getConventionSummary(),
|
|
44
|
-
]);
|
|
45
|
-
if (keyFacts.length > 0) {
|
|
46
|
-
brief.key_facts = keyFacts;
|
|
47
|
-
}
|
|
48
|
-
if (conventionSummary) {
|
|
49
|
-
brief.convention_summary = conventionSummary;
|
|
50
|
-
}
|
|
51
|
-
// Intelligence health from graph stats + fact count
|
|
52
|
-
const health = await this.getIntelligenceHealth();
|
|
53
|
-
if (health) {
|
|
54
|
-
brief.intelligence_health = health;
|
|
55
|
-
}
|
|
56
|
-
return brief;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Build the greeting line based on codebase health grade.
|
|
60
|
-
*/
|
|
61
|
-
buildGreeting() {
|
|
62
|
-
if (!this.healthGrade || !this.graphStats) {
|
|
63
|
-
return "unerr proxy ready. Graph intelligence active.";
|
|
64
|
-
}
|
|
65
|
-
const { entities, edges, rules } = this.graphStats;
|
|
66
|
-
const grade = this.healthGrade;
|
|
67
|
-
if (grade === "A" || grade === "A+") {
|
|
68
|
-
return `Codebase scores ${grade} — ${entities} entities, ${edges} edges, ${rules} rules. Architecture is healthy.`;
|
|
69
|
-
}
|
|
70
|
-
if (grade === "B" || grade === "B+") {
|
|
71
|
-
return `Codebase health: ${grade}. Tracking ${entities} entities, ${edges} edges, ${rules} rules. Some areas could improve.`;
|
|
72
|
-
}
|
|
73
|
-
if (grade.startsWith("C")) {
|
|
74
|
-
return `Codebase health: ${grade}. ${entities} entities tracked, ${rules} rules active. Structural issues affect maintainability.`;
|
|
75
|
-
}
|
|
76
|
-
return `Warning: codebase health is ${grade}. Significant structural issues across ${entities} entities.`;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Get top 3 most relevant project-scope facts.
|
|
80
|
-
*/
|
|
81
|
-
async getKeyFacts() {
|
|
82
|
-
if (!this.factStore)
|
|
83
|
-
return [];
|
|
84
|
-
try {
|
|
85
|
-
const facts = await this.factStore.recallByScope("project", 0.4);
|
|
86
|
-
return facts
|
|
87
|
-
.sort((a, b) => b.effective_confidence - a.effective_confidence)
|
|
88
|
-
.slice(0, 3)
|
|
89
|
-
.map((f) => f.content);
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
92
|
-
return [];
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Get convention summary from graph store.
|
|
97
|
-
*/
|
|
98
|
-
async getConventionSummary() {
|
|
99
|
-
if (!this.localGraph)
|
|
100
|
-
return null;
|
|
101
|
-
try {
|
|
102
|
-
const conventions = await this.localGraph.getConventions();
|
|
103
|
-
if (!conventions || conventions.length === 0)
|
|
104
|
-
return null;
|
|
105
|
-
const avgAdherence = Math.round(conventions.reduce((sum, c) => sum + c.adherence_rate, 0) /
|
|
106
|
-
conventions.length);
|
|
107
|
-
return `${conventions.length} conventions detected, ${avgAdherence}% avg adherence`;
|
|
108
|
-
}
|
|
109
|
-
catch {
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Get intelligence health summary.
|
|
115
|
-
*/
|
|
116
|
-
async getIntelligenceHealth() {
|
|
117
|
-
const parts = [];
|
|
118
|
-
if (this.graphStats) {
|
|
119
|
-
parts.push(`${this.graphStats.entities} entities`);
|
|
120
|
-
}
|
|
121
|
-
if (this.factStore) {
|
|
122
|
-
try {
|
|
123
|
-
const facts = await this.factStore.recallByScope("project", 0.0);
|
|
124
|
-
if (facts.length > 0) {
|
|
125
|
-
parts.push(`${facts.length} facts`);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
catch {
|
|
129
|
-
// Non-critical
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
if (this.localGraph) {
|
|
133
|
-
try {
|
|
134
|
-
const conventions = await this.localGraph.getConventions();
|
|
135
|
-
if (conventions && conventions.length > 0) {
|
|
136
|
-
parts.push(`${conventions.length} conventions`);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
// Non-critical
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return parts.length > 0 ? parts.join(", ") : null;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
let instance = null;
|
|
147
|
-
/**
|
|
148
|
-
* Get or create the SessionBriefBuilder singleton.
|
|
149
|
-
* Must be re-created if graph/facts change (call resetSessionBriefBuilder).
|
|
150
|
-
*/
|
|
151
|
-
export function getSessionBriefBuilder(localGraph, factStore, graphStats, healthGrade) {
|
|
152
|
-
if (!instance) {
|
|
153
|
-
instance = new SessionBriefBuilder(localGraph, factStore, graphStats, healthGrade);
|
|
154
|
-
}
|
|
155
|
-
return instance;
|
|
156
|
-
}
|
|
157
|
-
export function resetSessionBriefBuilder() {
|
|
158
|
-
instance = null;
|
|
159
|
-
}
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session Context — tracks per-session state for intelligent context injection.
|
|
3
|
-
*
|
|
4
|
-
* Used by QueryRouter to decide when to inject blast radius, conventions,
|
|
5
|
-
* corrections, and risk information into tool responses.
|
|
6
|
-
*/
|
|
7
|
-
export class SessionContext {
|
|
8
|
-
toolCallCount = 0;
|
|
9
|
-
greeted = false;
|
|
10
|
-
injectedBlastRadius = new Set();
|
|
11
|
-
/**
|
|
12
|
-
* Convention / fact reinforcement windows: track WHEN each key was last
|
|
13
|
-
* shown (tool-call index + wall-clock ms) so we can re-surface after a
|
|
14
|
-
* stale window instead of going silent for the rest of the session.
|
|
15
|
-
*
|
|
16
|
-
* Stale = 10+ unrelated tool calls since last show, OR 30+ min wall-clock.
|
|
17
|
-
* Tunable via STALE_CALL_GAP / STALE_TIME_MS constants below.
|
|
18
|
-
*/
|
|
19
|
-
injectedConventions = new Map();
|
|
20
|
-
injectedRisk = new Set();
|
|
21
|
-
injectedCorrections = new Set();
|
|
22
|
-
injectedFacts = new Map();
|
|
23
|
-
STALE_CALL_GAP = 10;
|
|
24
|
-
STALE_TIME_MS = 30 * 60 * 1000;
|
|
25
|
-
entityHistory = new Map();
|
|
26
|
-
lastFiredThreshold = 0;
|
|
27
|
-
/**
|
|
28
|
-
* Tier-3 rotational signal decay: how many times each unique signal has
|
|
29
|
-
* been emitted in the body prefix this session. Used by signal-scorer.rank()
|
|
30
|
-
* to deprioritize already-shown signals (`adjusted_score = base / (1 + shows * 0.5)`),
|
|
31
|
-
* so anti-pattern facts surface fresh information instead of repeating.
|
|
32
|
-
* Key: stable signal id (sha256(content).slice(0,16) or fact_id).
|
|
33
|
-
*
|
|
34
|
-
* In-memory fallback used when no SignalShowStore has been attached
|
|
35
|
-
* (tests, --mcp during facts.db boot). When the store is present its
|
|
36
|
-
* effective count is preferred so rotation survives restarts and is
|
|
37
|
-
* coordinated across parallel sessions in the same repo.
|
|
38
|
-
*/
|
|
39
|
-
signalShowCount = new Map();
|
|
40
|
-
showStore = null;
|
|
41
|
-
recordToolCall() {
|
|
42
|
-
this.toolCallCount++;
|
|
43
|
-
}
|
|
44
|
-
getToolCallCount() {
|
|
45
|
-
return this.toolCallCount;
|
|
46
|
-
}
|
|
47
|
-
isFirstCall() {
|
|
48
|
-
return !this.greeted && this.toolCallCount <= 1;
|
|
49
|
-
}
|
|
50
|
-
markGreeted() {
|
|
51
|
-
this.greeted = true;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Attach the persistent rotation store. Once attached, getSignalShowCount
|
|
55
|
-
* returns the time-decayed cross-session count and recordSignalShown writes
|
|
56
|
-
* through to facts.db on the next flush tick.
|
|
57
|
-
*/
|
|
58
|
-
setSignalShowStore(store) {
|
|
59
|
-
this.showStore = store;
|
|
60
|
-
}
|
|
61
|
-
// ── Tier-3 rotational signal decay ────────────────────────────────────
|
|
62
|
-
/** Record that a signal was emitted in a prefix line (called by ranker). */
|
|
63
|
-
recordSignalShown(signalId, scope = "") {
|
|
64
|
-
if (!signalId)
|
|
65
|
-
return;
|
|
66
|
-
this.signalShowCount.set(signalId, (this.signalShowCount.get(signalId) ?? 0) + 1);
|
|
67
|
-
this.showStore?.recordShown(signalId, scope);
|
|
68
|
-
}
|
|
69
|
-
/** How many times this signal has been emitted this session (or effective decayed count if persisted). */
|
|
70
|
-
getSignalShowCount(signalId) {
|
|
71
|
-
if (!signalId)
|
|
72
|
-
return 0;
|
|
73
|
-
if (this.showStore)
|
|
74
|
-
return this.showStore.getEffectiveShowCount(signalId);
|
|
75
|
-
return this.signalShowCount.get(signalId) ?? 0;
|
|
76
|
-
}
|
|
77
|
-
/** Last-shown timestamp (ms since epoch) across all sessions; 0 if never shown. */
|
|
78
|
-
getSignalLastShownMs(signalId) {
|
|
79
|
-
if (!signalId)
|
|
80
|
-
return 0;
|
|
81
|
-
return this.showStore?.getLastShownMs(signalId) ?? 0;
|
|
82
|
-
}
|
|
83
|
-
/** Reset rotation state — useful for tests or explicit "fresh start" intents. */
|
|
84
|
-
resetSignalRotation() {
|
|
85
|
-
this.signalShowCount.clear();
|
|
86
|
-
}
|
|
87
|
-
hasHistory(entityKey) {
|
|
88
|
-
return this.entityHistory.has(entityKey);
|
|
89
|
-
}
|
|
90
|
-
getHistory(entityKey) {
|
|
91
|
-
return this.entityHistory.get(entityKey);
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Entity keys recently queried this session (Map insertion order — newest
|
|
95
|
-
* last). Returns the trailing slice up to `max` so the recall_facts ranker
|
|
96
|
-
* can give a small boost to facts whose subject matches active context.
|
|
97
|
-
*/
|
|
98
|
-
getRecentSubjects(max = 10) {
|
|
99
|
-
const keys = Array.from(this.entityHistory.keys());
|
|
100
|
-
return new Set(keys.slice(-max));
|
|
101
|
-
}
|
|
102
|
-
recordEntityHistory(entityKey, blastRadius, risk) {
|
|
103
|
-
// Only record on first call — do not overwrite
|
|
104
|
-
if (this.entityHistory.has(entityKey))
|
|
105
|
-
return;
|
|
106
|
-
this.entityHistory.set(entityKey, {
|
|
107
|
-
blast_radius: blastRadius,
|
|
108
|
-
risk,
|
|
109
|
-
queriedAt: Date.now(),
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
shouldInjectBlastRadius(entityKey) {
|
|
113
|
-
if (this.injectedBlastRadius.has(entityKey))
|
|
114
|
-
return false;
|
|
115
|
-
this.injectedBlastRadius.add(entityKey);
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
shouldInjectCorrection(entityKey, _errorType) {
|
|
119
|
-
if (this.injectedCorrections.has(entityKey))
|
|
120
|
-
return false;
|
|
121
|
-
this.injectedCorrections.add(entityKey);
|
|
122
|
-
return true;
|
|
123
|
-
}
|
|
124
|
-
shouldInjectConvention(entityKey) {
|
|
125
|
-
const key = Array.isArray(entityKey) ? entityKey.join(",") : entityKey;
|
|
126
|
-
return this.isStale(this.injectedConventions.get(key));
|
|
127
|
-
}
|
|
128
|
-
recordConventions(conventions) {
|
|
129
|
-
// Set-once semantics: stamp on FIRST show only. Refreshing on every
|
|
130
|
-
// re-show defeats the stale-window predicate (the gap can never
|
|
131
|
-
// accumulate when each show resets atCall to current). Once a key
|
|
132
|
-
// becomes stale, isStale returns true, the caller surfaces it again,
|
|
133
|
-
// and only then does recordConventions overwrite the stamp.
|
|
134
|
-
const items = Array.isArray(conventions) ? conventions : [conventions];
|
|
135
|
-
const stamp = { atCall: this.toolCallCount, atMs: Date.now() };
|
|
136
|
-
for (const item of items) {
|
|
137
|
-
const existing = this.injectedConventions.get(item);
|
|
138
|
-
if (!existing || this.isStale(existing)) {
|
|
139
|
-
this.injectedConventions.set(item, stamp);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
shouldInjectFact(factId) {
|
|
144
|
-
return this.isStale(this.injectedFacts.get(factId));
|
|
145
|
-
}
|
|
146
|
-
recordFacts(factIds) {
|
|
147
|
-
// Set-once semantics — same reasoning as recordConventions above.
|
|
148
|
-
const stamp = { atCall: this.toolCallCount, atMs: Date.now() };
|
|
149
|
-
for (const id of factIds) {
|
|
150
|
-
const existing = this.injectedFacts.get(id);
|
|
151
|
-
if (!existing || this.isStale(existing)) {
|
|
152
|
-
this.injectedFacts.set(id, stamp);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* "Should re-surface" predicate: true when never shown, or when the gap
|
|
158
|
-
* since last show exceeds either threshold (call-count or wall-clock).
|
|
159
|
-
* Both thresholds matter — pure call-count misses long idle gaps, pure
|
|
160
|
-
* time misses rapid-fire sessions.
|
|
161
|
-
*/
|
|
162
|
-
isStale(last) {
|
|
163
|
-
if (!last)
|
|
164
|
-
return true;
|
|
165
|
-
if (this.toolCallCount - last.atCall >= this.STALE_CALL_GAP)
|
|
166
|
-
return true;
|
|
167
|
-
if (Date.now() - last.atMs >= this.STALE_TIME_MS)
|
|
168
|
-
return true;
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
shouldInjectRisk(entityKey) {
|
|
172
|
-
if (this.injectedRisk.has(entityKey))
|
|
173
|
-
return false;
|
|
174
|
-
return true;
|
|
175
|
-
}
|
|
176
|
-
recordRisk(entityKey) {
|
|
177
|
-
this.injectedRisk.add(entityKey);
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Value counter — surfaces "unerr has caught N issues this session" every 3rd caught event.
|
|
181
|
-
* Conditions: toolCallCount > 10, caught > 0, caught % 3 === 0, fires once per threshold.
|
|
182
|
-
*/
|
|
183
|
-
getValueCounter(events) {
|
|
184
|
-
if (this.toolCallCount <= 10)
|
|
185
|
-
return undefined;
|
|
186
|
-
const caught = events.conventionViolationsCaught +
|
|
187
|
-
events.chokepointWarningsIssued +
|
|
188
|
-
events.circularDepsDetected;
|
|
189
|
-
if (caught === 0)
|
|
190
|
-
return undefined;
|
|
191
|
-
if (caught % 3 !== 0)
|
|
192
|
-
return undefined;
|
|
193
|
-
if (caught === this.lastFiredThreshold)
|
|
194
|
-
return undefined;
|
|
195
|
-
this.lastFiredThreshold = caught;
|
|
196
|
-
return `(unerr has caught ${caught} issues this session)`;
|
|
197
|
-
}
|
|
198
|
-
recordQuery(entityKey) {
|
|
199
|
-
// Mark as having had blast radius injected (dedup future calls)
|
|
200
|
-
this.injectedBlastRadius.add(entityKey);
|
|
201
|
-
}
|
|
202
|
-
get entitiesQueried() {
|
|
203
|
-
return this.injectedBlastRadius.size;
|
|
204
|
-
}
|
|
205
|
-
get conventionsSurfaced() {
|
|
206
|
-
return this.injectedConventions.size;
|
|
207
|
-
}
|
|
208
|
-
get risksSurfaced() {
|
|
209
|
-
return this.injectedRisk.size;
|
|
210
|
-
}
|
|
211
|
-
reset() {
|
|
212
|
-
this.toolCallCount = 0;
|
|
213
|
-
this.greeted = false;
|
|
214
|
-
this.injectedBlastRadius.clear();
|
|
215
|
-
this.injectedConventions.clear();
|
|
216
|
-
this.injectedRisk.clear();
|
|
217
|
-
this.injectedCorrections.clear();
|
|
218
|
-
this.entityHistory.clear();
|
|
219
|
-
this.lastFiredThreshold = 0;
|
|
220
|
-
}
|
|
221
|
-
}
|