@unerr-ai/unerr 0.2.1 → 0.2.3
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 +36 -45
- package/dist/cli.js +37443 -36022
- package/package.json +2 -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,205 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Convention Learning — detects developer correction patterns from
|
|
3
|
-
* sequential shadow ledger entries and generates convention rules.
|
|
4
|
-
*
|
|
5
|
-
* Patterns detected:
|
|
6
|
-
* 1. Rename: getData → fetchData → convention "use fetch prefix for data operations"
|
|
7
|
-
* 2. Import reorganization: scattered → grouped → convention "group imports by type"
|
|
8
|
-
* 3. Repeated structural changes → convention candidates
|
|
9
|
-
*
|
|
10
|
-
* Runs at session end or via `unerr learn` — never during active MCP serving.
|
|
11
|
-
*
|
|
12
|
-
* Temporal intelligence note: conventions are procedural memory (Section 13.2)
|
|
13
|
-
* that mature through stages: tentative → emerging → established → stale.
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
|
-
* Analyze ledger entries for convention patterns.
|
|
17
|
-
* Returns newly detected conventions.
|
|
18
|
-
*/
|
|
19
|
-
export function learnConventions(entries) {
|
|
20
|
-
const conventions = [];
|
|
21
|
-
const renameConventions = detectRenamePatterns(entries);
|
|
22
|
-
conventions.push(...renameConventions);
|
|
23
|
-
const structuralConventions = detectStructuralPatterns(entries);
|
|
24
|
-
conventions.push(...structuralConventions);
|
|
25
|
-
return conventions;
|
|
26
|
-
}
|
|
27
|
-
function detectRenamePatterns(entries) {
|
|
28
|
-
const syncEntries = entries.filter((e) => e.tool === "sync_local_diff");
|
|
29
|
-
if (syncEntries.length < 2)
|
|
30
|
-
return [];
|
|
31
|
-
const renameGroups = new Map();
|
|
32
|
-
for (let i = 1; i < syncEntries.length; i++) {
|
|
33
|
-
const prev = syncEntries[i - 1];
|
|
34
|
-
const curr = syncEntries[i];
|
|
35
|
-
const prevFiles = extractFiles(prev.args_summary);
|
|
36
|
-
const currFiles = extractFiles(curr.args_summary);
|
|
37
|
-
const sameFiles = prevFiles.filter((f) => currFiles.includes(f));
|
|
38
|
-
for (const file of sameFiles) {
|
|
39
|
-
const prevContent = extractContent(prev.args_summary, file);
|
|
40
|
-
const currContent = extractContent(curr.args_summary, file);
|
|
41
|
-
if (!prevContent || !currContent)
|
|
42
|
-
continue;
|
|
43
|
-
const renames = detectNameChanges(prevContent, currContent);
|
|
44
|
-
for (const rename of renames) {
|
|
45
|
-
const pattern = extractNamingPattern(rename.fromName, rename.toName);
|
|
46
|
-
if (pattern) {
|
|
47
|
-
const key = pattern;
|
|
48
|
-
const group = renameGroups.get(key) ?? [];
|
|
49
|
-
group.push({ ...rename, file, ts: curr.ts });
|
|
50
|
-
renameGroups.set(key, group);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
const conventions = [];
|
|
56
|
-
for (const [pattern, observations] of renameGroups) {
|
|
57
|
-
if (observations.length >= 2) {
|
|
58
|
-
conventions.push({
|
|
59
|
-
id: `rename:${pattern}:${Date.now()}`,
|
|
60
|
-
name: `Naming: ${pattern}`,
|
|
61
|
-
pattern,
|
|
62
|
-
evidence: observations.map((o) => `${o.fromName} → ${o.toName} in ${o.file}`),
|
|
63
|
-
confidence: Math.min(0.9, 0.5 + observations.length * 0.1),
|
|
64
|
-
detectedAt: new Date().toISOString(),
|
|
65
|
-
observationCount: observations.length,
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return conventions;
|
|
70
|
-
}
|
|
71
|
-
function detectStructuralPatterns(entries) {
|
|
72
|
-
const fileModCounts = new Map();
|
|
73
|
-
for (const entry of entries) {
|
|
74
|
-
if (entry.tool !== "sync_local_diff")
|
|
75
|
-
continue;
|
|
76
|
-
const files = extractFiles(entry.args_summary);
|
|
77
|
-
for (const f of files) {
|
|
78
|
-
fileModCounts.set(f, (fileModCounts.get(f) ?? 0) + 1);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
const conventions = [];
|
|
82
|
-
const coChangeGroups = detectCoChanges(entries);
|
|
83
|
-
for (const [key, files] of coChangeGroups) {
|
|
84
|
-
if (files.count >= 3) {
|
|
85
|
-
conventions.push({
|
|
86
|
-
id: `cochange:${key}:${Date.now()}`,
|
|
87
|
-
name: `Co-change: ${files.files.slice(0, 2).join(" + ")}`,
|
|
88
|
-
pattern: "co-change",
|
|
89
|
-
evidence: files.files,
|
|
90
|
-
confidence: Math.min(0.8, 0.4 + files.count * 0.1),
|
|
91
|
-
detectedAt: new Date().toISOString(),
|
|
92
|
-
observationCount: files.count,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return conventions;
|
|
97
|
-
}
|
|
98
|
-
function detectCoChanges(entries) {
|
|
99
|
-
const groups = new Map();
|
|
100
|
-
const syncEntries = entries.filter((e) => e.tool === "sync_local_diff");
|
|
101
|
-
for (const entry of syncEntries) {
|
|
102
|
-
const files = extractFiles(entry.args_summary).sort();
|
|
103
|
-
if (files.length < 2)
|
|
104
|
-
continue;
|
|
105
|
-
for (let i = 0; i < files.length - 1; i++) {
|
|
106
|
-
for (let j = i + 1; j < files.length && j < i + 4; j++) {
|
|
107
|
-
const key = `${files[i]}+${files[j]}`;
|
|
108
|
-
const existing = groups.get(key) ?? {
|
|
109
|
-
files: [files[i], files[j]],
|
|
110
|
-
count: 0,
|
|
111
|
-
};
|
|
112
|
-
existing.count++;
|
|
113
|
-
groups.set(key, existing);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return groups;
|
|
118
|
-
}
|
|
119
|
-
function extractFiles(args) {
|
|
120
|
-
const files = args.files;
|
|
121
|
-
if (!Array.isArray(files))
|
|
122
|
-
return [];
|
|
123
|
-
return files
|
|
124
|
-
.map((f) => typeof f === "string" ? f : (f?.path ?? ""))
|
|
125
|
-
.filter(Boolean);
|
|
126
|
-
}
|
|
127
|
-
function extractContent(args, filePath) {
|
|
128
|
-
const files = args.files;
|
|
129
|
-
if (!Array.isArray(files))
|
|
130
|
-
return null;
|
|
131
|
-
for (const f of files) {
|
|
132
|
-
if (typeof f === "object" && f !== null) {
|
|
133
|
-
const obj = f;
|
|
134
|
-
if (obj.path === filePath && obj.content)
|
|
135
|
-
return obj.content;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
function detectNameChanges(prevContent, currContent) {
|
|
141
|
-
const prevNames = extractIdentifiers(prevContent);
|
|
142
|
-
const currNames = extractIdentifiers(currContent);
|
|
143
|
-
const removed = prevNames.filter((n) => !currNames.includes(n));
|
|
144
|
-
const added = currNames.filter((n) => !prevNames.includes(n));
|
|
145
|
-
const renames = [];
|
|
146
|
-
for (const from of removed) {
|
|
147
|
-
for (const to of added) {
|
|
148
|
-
if (similarity(from, to) > 0.5) {
|
|
149
|
-
renames.push({ fromName: from, toName: to });
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return renames;
|
|
155
|
-
}
|
|
156
|
-
function extractIdentifiers(content) {
|
|
157
|
-
const matches = content.match(/\b[a-zA-Z_$][a-zA-Z0-9_$]*\b/g) ?? [];
|
|
158
|
-
return [...new Set(matches)].filter((n) => n.length > 2);
|
|
159
|
-
}
|
|
160
|
-
function similarity(a, b) {
|
|
161
|
-
if (a === b)
|
|
162
|
-
return 1;
|
|
163
|
-
const maxLen = Math.max(a.length, b.length);
|
|
164
|
-
if (maxLen === 0)
|
|
165
|
-
return 1;
|
|
166
|
-
let common = 0;
|
|
167
|
-
const shorter = a.length <= b.length ? a : b;
|
|
168
|
-
const longer = a.length > b.length ? a : b;
|
|
169
|
-
for (const char of shorter) {
|
|
170
|
-
if (longer.includes(char))
|
|
171
|
-
common++;
|
|
172
|
-
}
|
|
173
|
-
return common / maxLen;
|
|
174
|
-
}
|
|
175
|
-
function extractNamingPattern(from, to) {
|
|
176
|
-
const prefixes = [
|
|
177
|
-
"get",
|
|
178
|
-
"set",
|
|
179
|
-
"fetch",
|
|
180
|
-
"load",
|
|
181
|
-
"create",
|
|
182
|
-
"update",
|
|
183
|
-
"delete",
|
|
184
|
-
"remove",
|
|
185
|
-
"handle",
|
|
186
|
-
"on",
|
|
187
|
-
];
|
|
188
|
-
for (const prefix of prefixes) {
|
|
189
|
-
if (from.startsWith(prefix) && !to.startsWith(prefix)) {
|
|
190
|
-
const toPrefix = prefixes.find((p) => to.startsWith(p));
|
|
191
|
-
if (toPrefix)
|
|
192
|
-
return `use ${toPrefix} prefix instead of ${prefix}`;
|
|
193
|
-
}
|
|
194
|
-
if (!from.startsWith(prefix) && to.startsWith(prefix)) {
|
|
195
|
-
return `use ${prefix} prefix for ${from.slice(0, 1).toLowerCase() + from.slice(1)} operations`;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
if (from.includes("_") && !to.includes("_") && to.match(/[A-Z]/)) {
|
|
199
|
-
return "use camelCase instead of snake_case";
|
|
200
|
-
}
|
|
201
|
-
if (!from.includes("_") && to.includes("_")) {
|
|
202
|
-
return "use snake_case instead of camelCase";
|
|
203
|
-
}
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sprint 3.2: Local Convention Pattern Matching — structural checks without LLM.
|
|
3
|
-
*
|
|
4
|
-
* Three convention types evaluated locally:
|
|
5
|
-
* 1. Naming conventions — regex patterns from CozoDB `patterns` table
|
|
6
|
-
* 2. File structure conventions — expected sibling files (e.g., *.test.ts)
|
|
7
|
-
* 3. Import direction conventions — forbidden dependency directions
|
|
8
|
-
*
|
|
9
|
-
* All checks complete in <5ms per file.
|
|
10
|
-
*
|
|
11
|
-
* Design authority: PHASE_CLI_ENHANCEMENT §3.2
|
|
12
|
-
*/
|
|
13
|
-
/** Default naming conventions derived from common TypeScript patterns. */
|
|
14
|
-
const DEFAULT_NAMING_CONVENTIONS = [
|
|
15
|
-
{
|
|
16
|
-
kind: "class",
|
|
17
|
-
pattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
18
|
-
name: "PascalCase classes",
|
|
19
|
-
message: "Class names must be PascalCase",
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
kind: "function",
|
|
23
|
-
pattern: /^[a-z_][a-zA-Z0-9]*$/,
|
|
24
|
-
name: "camelCase functions",
|
|
25
|
-
message: "Function names must be camelCase or snake_case",
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
kind: "interface",
|
|
29
|
-
pattern: /^[A-Z][a-zA-Z0-9]*$/,
|
|
30
|
-
name: "PascalCase interfaces",
|
|
31
|
-
message: "Interface names must be PascalCase",
|
|
32
|
-
},
|
|
33
|
-
];
|
|
34
|
-
/** Default file structure conventions. */
|
|
35
|
-
const DEFAULT_FILE_STRUCTURE_CONVENTIONS = [
|
|
36
|
-
{
|
|
37
|
-
sourceGlob: "src/**/*.ts",
|
|
38
|
-
siblingSuffix: ".test.ts",
|
|
39
|
-
name: "Test file sibling",
|
|
40
|
-
message: "Source files should have a corresponding .test.ts file",
|
|
41
|
-
},
|
|
42
|
-
];
|
|
43
|
-
/** Default import direction conventions. */
|
|
44
|
-
const DEFAULT_IMPORT_DIRECTION_CONVENTIONS = [
|
|
45
|
-
{
|
|
46
|
-
fromLayer: "/services/",
|
|
47
|
-
toLayer: "/controllers/",
|
|
48
|
-
name: "Services cannot import controllers",
|
|
49
|
-
message: "Service layer should not depend on controller layer",
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
fromLayer: "/utils/",
|
|
53
|
-
toLayer: "/services/",
|
|
54
|
-
name: "Utils cannot import services",
|
|
55
|
-
message: "Utility layer should not depend on service layer",
|
|
56
|
-
},
|
|
57
|
-
];
|
|
58
|
-
/**
|
|
59
|
-
* Check naming conventions against entities in a file.
|
|
60
|
-
*/
|
|
61
|
-
export function checkNamingConventions(entities, conventions) {
|
|
62
|
-
const rules = conventions ?? DEFAULT_NAMING_CONVENTIONS;
|
|
63
|
-
const violations = [];
|
|
64
|
-
for (const entity of entities) {
|
|
65
|
-
for (const rule of rules) {
|
|
66
|
-
if (entity.kind === rule.kind && !rule.pattern.test(entity.name)) {
|
|
67
|
-
violations.push({
|
|
68
|
-
type: "naming",
|
|
69
|
-
severity: "warn",
|
|
70
|
-
entity: entity.key,
|
|
71
|
-
file: entity.file_path,
|
|
72
|
-
message: `${rule.message}: "${entity.name}"`,
|
|
73
|
-
suggestion: `Rename to match ${rule.pattern.source}`,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return violations;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Check file structure conventions (sibling file existence).
|
|
82
|
-
* Uses the graph's file index to check for expected sibling files.
|
|
83
|
-
*/
|
|
84
|
-
export async function checkFileStructure(filePath, graph, conventions) {
|
|
85
|
-
const rules = conventions ?? DEFAULT_FILE_STRUCTURE_CONVENTIONS;
|
|
86
|
-
const violations = [];
|
|
87
|
-
for (const rule of rules) {
|
|
88
|
-
// Check if file matches source glob (simple suffix check for performance)
|
|
89
|
-
const sourceExt = rule.sourceGlob.split("*").pop() ?? "";
|
|
90
|
-
if (!filePath.endsWith(sourceExt))
|
|
91
|
-
continue;
|
|
92
|
-
// Skip if this IS a test/sibling file
|
|
93
|
-
if (filePath.endsWith(rule.siblingSuffix))
|
|
94
|
-
continue;
|
|
95
|
-
// Check for expected sibling
|
|
96
|
-
const basePath = filePath.slice(0, -sourceExt.length);
|
|
97
|
-
const expectedSibling = basePath + rule.siblingSuffix;
|
|
98
|
-
const siblingEntities = await graph.getEntitiesByFile(expectedSibling);
|
|
99
|
-
if (siblingEntities.length === 0) {
|
|
100
|
-
violations.push({
|
|
101
|
-
type: "file_structure",
|
|
102
|
-
severity: "warn",
|
|
103
|
-
file: filePath,
|
|
104
|
-
message: `${rule.message}: missing ${expectedSibling}`,
|
|
105
|
-
suggestion: `Create ${expectedSibling}`,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return violations;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Check import direction conventions.
|
|
113
|
-
* Uses the graph's import data to detect forbidden dependency directions.
|
|
114
|
-
*/
|
|
115
|
-
export async function checkImportDirection(filePath, graph, conventions) {
|
|
116
|
-
const rules = conventions ?? DEFAULT_IMPORT_DIRECTION_CONVENTIONS;
|
|
117
|
-
const violations = [];
|
|
118
|
-
for (const rule of rules) {
|
|
119
|
-
// Only check files in the source layer
|
|
120
|
-
if (!filePath.includes(rule.fromLayer))
|
|
121
|
-
continue;
|
|
122
|
-
// Get imports for this file
|
|
123
|
-
const imports = await graph.getImports(filePath);
|
|
124
|
-
for (const imp of imports) {
|
|
125
|
-
const importPath = imp.imported_file;
|
|
126
|
-
if (importPath?.includes(rule.toLayer)) {
|
|
127
|
-
violations.push({
|
|
128
|
-
type: "import_direction",
|
|
129
|
-
severity: "error",
|
|
130
|
-
file: filePath,
|
|
131
|
-
message: `${rule.message}: ${filePath} imports from ${importPath}`,
|
|
132
|
-
suggestion: "Move shared logic to a common layer or invert the dependency",
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return violations;
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Run all convention checks for a file. <5ms per file.
|
|
141
|
-
*/
|
|
142
|
-
export async function matchConventions(filePath, graph, options) {
|
|
143
|
-
const entities = await graph.getEntitiesByFile(filePath);
|
|
144
|
-
const violations = [];
|
|
145
|
-
violations.push(...checkNamingConventions(entities, options?.namingConventions));
|
|
146
|
-
violations.push(...(await checkFileStructure(filePath, graph, options?.fileStructureConventions)));
|
|
147
|
-
violations.push(...(await checkImportDirection(filePath, graph, options?.importDirectionConventions)));
|
|
148
|
-
return violations;
|
|
149
|
-
}
|
|
150
|
-
/** Map naming style keywords to regex patterns. */
|
|
151
|
-
const NAMING_STYLE_REGEX = {
|
|
152
|
-
camelcase: /^[a-z][a-zA-Z0-9]*$/,
|
|
153
|
-
pascalcase: /^[A-Z][a-zA-Z0-9]*$/,
|
|
154
|
-
snake_case: /^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/,
|
|
155
|
-
screaming_snake: /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$/,
|
|
156
|
-
kebab: /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/,
|
|
157
|
-
};
|
|
158
|
-
/** Resolve regex from a pattern name like "camelCase functions" or "PascalCase classes". */
|
|
159
|
-
function resolveNamingRegex(patternName) {
|
|
160
|
-
const lower = patternName.toLowerCase();
|
|
161
|
-
for (const [key, regex] of Object.entries(NAMING_STYLE_REGEX)) {
|
|
162
|
-
if (lower.includes(key))
|
|
163
|
-
return regex;
|
|
164
|
-
}
|
|
165
|
-
// Try partial matches: "pascal" → PascalCase, "camel" → camelCase
|
|
166
|
-
if (lower.includes("pascal"))
|
|
167
|
-
return NAMING_STYLE_REGEX.pascalcase ?? null;
|
|
168
|
-
if (lower.includes("camel"))
|
|
169
|
-
return NAMING_STYLE_REGEX.camelcase ?? null;
|
|
170
|
-
if (lower.includes("snake") && lower.includes("scream"))
|
|
171
|
-
return NAMING_STYLE_REGEX.screaming_snake ?? null;
|
|
172
|
-
if (lower.includes("snake"))
|
|
173
|
-
return NAMING_STYLE_REGEX.snake_case ?? null;
|
|
174
|
-
if (lower.includes("kebab"))
|
|
175
|
-
return NAMING_STYLE_REGEX.kebab ?? null;
|
|
176
|
-
return null;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Derive naming conventions from CozoDB patterns table.
|
|
180
|
-
* Converts pattern entries with kind="naming" into regex-based naming checks,
|
|
181
|
-
* mapping pattern names to the correct regex (camelCase, PascalCase, snake_case, etc.).
|
|
182
|
-
*/
|
|
183
|
-
export async function deriveNamingConventionsFromPatterns(graph) {
|
|
184
|
-
const patterns = await graph.getPatterns();
|
|
185
|
-
const conventions = [];
|
|
186
|
-
for (const p of patterns) {
|
|
187
|
-
if (p.kind === "naming" && p.confidence >= 0.7) {
|
|
188
|
-
// Extract entity kind (class, function, interface, etc.)
|
|
189
|
-
const kindMatch = p.name.match(/\b(class|function|interface|method|variable|type|enum|constant)\b/i);
|
|
190
|
-
if (!kindMatch)
|
|
191
|
-
continue;
|
|
192
|
-
// Resolve the correct regex from the pattern name
|
|
193
|
-
const regex = resolveNamingRegex(p.name);
|
|
194
|
-
if (!regex)
|
|
195
|
-
continue;
|
|
196
|
-
conventions.push({
|
|
197
|
-
kind: kindMatch[1].toLowerCase(),
|
|
198
|
-
pattern: regex,
|
|
199
|
-
name: p.name,
|
|
200
|
-
message: `Convention: ${p.name} (${Math.round(p.confidence * 100)}% confidence, ${p.frequency} occurrences)`,
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
return conventions.length > 0 ? conventions : DEFAULT_NAMING_CONVENTIONS;
|
|
205
|
-
}
|