@unerr-ai/unerr 0.1.6 → 0.1.8
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 +79 -196
- package/dist/cli.js +19821 -16589
- package/package.json +17 -3
- package/dist/__tests__/architecture-guard.test.js +0 -122
- package/dist/__tests__/arg-validator.test.js +0 -205
- package/dist/__tests__/ast-extractor.test.js +0 -203
- package/dist/__tests__/auto-bootstrap.test.js +0 -280
- package/dist/__tests__/background-indexer.test.js +0 -228
- package/dist/__tests__/blast-radius-engine.test.js +0 -200
- package/dist/__tests__/bridge-isolation.test.js +0 -37
- package/dist/__tests__/budget-enforcer.test.js +0 -53
- package/dist/__tests__/cfg-test-detection-perf.test.js +0 -82
- package/dist/__tests__/change-narrative.test.js +0 -190
- package/dist/__tests__/check-commit.test.js +0 -258
- package/dist/__tests__/checksum.test.js +0 -34
- package/dist/__tests__/commit-watcher.test.js +0 -154
- package/dist/__tests__/community-detection.test.js +0 -179
- package/dist/__tests__/community-tools.test.js +0 -299
- package/dist/__tests__/components.test.js +0 -449
- package/dist/__tests__/compression-log.test.js +0 -174
- package/dist/__tests__/compression-quality-monitor.test.js +0 -40
- package/dist/__tests__/config-healer.test.js +0 -165
- package/dist/__tests__/context-ledger.test.js +0 -58
- package/dist/__tests__/convention-detector.test.js +0 -99
- package/dist/__tests__/convention-learner.test.js +0 -86
- package/dist/__tests__/correction-detector.test.js +0 -330
- package/dist/__tests__/daemon-autostart-install.test.js +0 -283
- package/dist/__tests__/daemon-bridge.test.js +0 -222
- package/dist/__tests__/daemon-dashboard.test.js +0 -202
- package/dist/__tests__/daemon-registry.test.js +0 -240
- package/dist/__tests__/daemon-supervisor.test.js +0 -318
- package/dist/__tests__/daemon-version-check.test.js +0 -275
- package/dist/__tests__/decision-point-detector.test.js +0 -98
- package/dist/__tests__/deep-link.test.js +0 -143
- package/dist/__tests__/disallowed-tools.test.js +0 -115
- package/dist/__tests__/drift-tracker.test.js +0 -582
- package/dist/__tests__/durability-scorer.test.js +0 -152
- package/dist/__tests__/efficiency-tracker.test.js +0 -65
- package/dist/__tests__/enrich.test.js +0 -144
- package/dist/__tests__/entity-rewind.test.js +0 -248
- package/dist/__tests__/ephemeral.test.js +0 -111
- package/dist/__tests__/exploration-cost.test.js +0 -93
- package/dist/__tests__/fact-generator.test.js +0 -197
- package/dist/__tests__/file-l0-graph.test.js +0 -244
- package/dist/__tests__/file-logger.test.js +0 -82
- package/dist/__tests__/file-outline.test.js +0 -141
- package/dist/__tests__/file-read-protocol.test.js +0 -188
- package/dist/__tests__/format-encoder.test.js +0 -233
- package/dist/__tests__/git-attribution.test.js +0 -259
- package/dist/__tests__/graph-temporal-joiner.test.js +0 -219
- package/dist/__tests__/health-grade-enhanced.test.js +0 -138
- package/dist/__tests__/health-map-data.test.js +0 -173
- package/dist/__tests__/helpers/mcp-harness.js +0 -45
- package/dist/__tests__/helpers/mcp-harness.test.js +0 -68
- package/dist/__tests__/hook-dedup.test.js +0 -112
- package/dist/__tests__/hook-runner.test.js +0 -253
- package/dist/__tests__/indexer-cfg.test.js +0 -185
- package/dist/__tests__/indexer-cross-file.test.js +0 -172
- package/dist/__tests__/indexer-extraction.test.js +0 -245
- package/dist/__tests__/indexer-incremental.test.js +0 -232
- package/dist/__tests__/indexer-language-expansion.test.js +0 -165
- package/dist/__tests__/init-push.test.js +0 -131
- package/dist/__tests__/instruction-writer.test.js +0 -179
- package/dist/__tests__/intelligence-integration.test.js +0 -217
- package/dist/__tests__/intent-correlator.test.js +0 -175
- package/dist/__tests__/intent-detector.test.js +0 -235
- package/dist/__tests__/intent-encoder.test.js +0 -167
- package/dist/__tests__/java-build-tool-detection.test.js +0 -174
- package/dist/__tests__/layer3-sprint-q.test.js +0 -160
- package/dist/__tests__/layer3-sprint-r.test.js +0 -91
- package/dist/__tests__/layer3-sprint-s.test.js +0 -183
- package/dist/__tests__/layer3-sprint-t.test.js +0 -201
- package/dist/__tests__/layer3-sprint-u.test.js +0 -174
- package/dist/__tests__/layer4-sprint-ba2.test.js +0 -354
- package/dist/__tests__/layer4-sprint-ba4.test.js +0 -84
- package/dist/__tests__/layer4-sprint-vs.test.js +0 -105
- package/dist/__tests__/ledger-chains.test.js +0 -162
- package/dist/__tests__/lifecycle-machine.test.js +0 -226
- package/dist/__tests__/local-chat-provider.test.js +0 -170
- package/dist/__tests__/local-convention-detector.test.js +0 -308
- package/dist/__tests__/local-embeddings.test.js +0 -422
- package/dist/__tests__/local-graph.test.js +0 -540
- package/dist/__tests__/local-indexer.test.js +0 -228
- package/dist/__tests__/local-intelligence-l3.test.js +0 -332
- package/dist/__tests__/local-llm.test.js +0 -253
- package/dist/__tests__/local-mode-offline.test.js +0 -187
- package/dist/__tests__/local-mode-stats.test.js +0 -273
- package/dist/__tests__/local-mode-tui.test.js +0 -343
- package/dist/__tests__/local-parse.test.js +0 -199
- package/dist/__tests__/log-tailer.test.js +0 -208
- package/dist/__tests__/loop-breaker.test.js +0 -276
- package/dist/__tests__/loop-miner.test.js +0 -226
- package/dist/__tests__/mcp-config.test.js +0 -126
- package/dist/__tests__/mcp-content-json.test.js +0 -10
- package/dist/__tests__/mcp-envelope.test.js +0 -124
- package/dist/__tests__/metrics-store.test.js +0 -223
- package/dist/__tests__/native-watcher.test.js +0 -191
- package/dist/__tests__/navigation-hooks-agent-aware.test.js +0 -145
- package/dist/__tests__/negative-knowledge.test.js +0 -116
- package/dist/__tests__/network-boundary.test.js +0 -190
- package/dist/__tests__/network-firewall.test.js +0 -112
- package/dist/__tests__/nudge-invariants.test.js +0 -160
- package/dist/__tests__/nudge-v2.test.js +0 -225
- package/dist/__tests__/offline-rewind.test.js +0 -251
- package/dist/__tests__/open-threads.test.js +0 -89
- package/dist/__tests__/output-compressor.test.js +0 -93
- package/dist/__tests__/pending-violations.test.js +0 -112
- package/dist/__tests__/persistence-effectiveness.test.js +0 -143
- package/dist/__tests__/provider-factory.test.js +0 -42
- package/dist/__tests__/providers.test.js +0 -24
- package/dist/__tests__/proxy.test.js +0 -314
- package/dist/__tests__/query-router.test.js +0 -1018
- package/dist/__tests__/reasoning-quality-route.test.js +0 -138
- package/dist/__tests__/redactor.test.js +0 -120
- package/dist/__tests__/resource-monitor.test.js +0 -57
- package/dist/__tests__/response-envelope.test.js +0 -100
- package/dist/__tests__/risk-classifier.test.js +0 -101
- package/dist/__tests__/risk-signal-scope.test.js +0 -75
- package/dist/__tests__/rule-evaluator.test.js +0 -280
- package/dist/__tests__/scip-decoder.test.js +0 -49
- package/dist/__tests__/scip-downloader.test.js +0 -201
- package/dist/__tests__/scip-merger.test.js +0 -103
- package/dist/__tests__/search-index.test.js +0 -422
- package/dist/__tests__/semantic-enrichment.test.js +0 -360
- package/dist/__tests__/session-brief-builder.test.js +0 -187
- package/dist/__tests__/session-context.test.js +0 -221
- package/dist/__tests__/session-continuity.test.js +0 -144
- package/dist/__tests__/session-dedup.test.js +0 -74
- package/dist/__tests__/session-event-wiring.test.js +0 -206
- package/dist/__tests__/session-events.test.js +0 -149
- package/dist/__tests__/session-legend.test.js +0 -20
- package/dist/__tests__/session-persistence.test.js +0 -131
- package/dist/__tests__/session-resume-block.test.js +0 -107
- package/dist/__tests__/session-resume.test.js +0 -97
- package/dist/__tests__/session-summary-writer.test.js +0 -134
- package/dist/__tests__/shadow-ledger.test.js +0 -203
- package/dist/__tests__/shell-classifier.test.js +0 -151
- package/dist/__tests__/shell-compression-floor.test.js +0 -189
- package/dist/__tests__/shell-compression-v2.test.js +0 -339
- package/dist/__tests__/shell-compressor.test.js +0 -35
- package/dist/__tests__/shell-hooks.test.js +0 -128
- package/dist/__tests__/shell-strategies.test.js +0 -644
- package/dist/__tests__/shell-tee.test.js +0 -133
- package/dist/__tests__/signal-dedup.test.js +0 -158
- package/dist/__tests__/signal-reinforcer.test.js +0 -77
- package/dist/__tests__/signal-scorer.test.js +0 -251
- package/dist/__tests__/signal-show-store.test.js +0 -108
- package/dist/__tests__/smart-truncate.test.js +0 -215
- package/dist/__tests__/snapshot-v2.test.js +0 -113
- package/dist/__tests__/sprint-l1-local-mode.test.js +0 -130
- package/dist/__tests__/sprint-l10-boot.test.js +0 -220
- package/dist/__tests__/sprint-l9-offline-commands.test.js +0 -189
- package/dist/__tests__/sprint-q-persistent-context.test.js +0 -198
- package/dist/__tests__/sprint-s1-wiring.test.js +0 -215
- package/dist/__tests__/sprint-s2-wiring.test.js +0 -256
- package/dist/__tests__/sprint-s3-wiring.test.js +0 -195
- package/dist/__tests__/sprint-s4-wiring.test.js +0 -213
- package/dist/__tests__/sprint-s6-hooks.test.js +0 -222
- package/dist/__tests__/sprint-s7-persistent.test.js +0 -263
- package/dist/__tests__/sprint-s8-value.test.js +0 -167
- package/dist/__tests__/sprint-s9-behavioral.test.js +0 -179
- package/dist/__tests__/sprint3-intelligence.test.js +0 -297
- package/dist/__tests__/sprint5-mcp-server.test.js +0 -136
- package/dist/__tests__/startup-display.test.js +0 -302
- package/dist/__tests__/startup-log-file.test.js +0 -97
- package/dist/__tests__/stash-manager.test.js +0 -229
- package/dist/__tests__/state-detector.test.js +0 -92
- package/dist/__tests__/status-dashboard.test.js +0 -142
- package/dist/__tests__/temporal-facts.test.js +0 -292
- package/dist/__tests__/temporal-routes.test.js +0 -142
- package/dist/__tests__/test-detector.test.js +0 -174
- package/dist/__tests__/theme.test.js +0 -72
- package/dist/__tests__/timeline-agents.test.js +0 -122
- package/dist/__tests__/timeline-bootstrap.test.js +0 -176
- package/dist/__tests__/timeline-filters.test.js +0 -193
- package/dist/__tests__/timeline-markers.test.js +0 -151
- package/dist/__tests__/timeline-routes.test.js +0 -156
- package/dist/__tests__/timeline-store.test.js +0 -171
- package/dist/__tests__/token-counter.test.js +0 -86
- package/dist/__tests__/token-estimator.test.js +0 -96
- package/dist/__tests__/token-flow-api.test.js +0 -239
- package/dist/__tests__/token-flow-instrumentation.test.js +0 -437
- package/dist/__tests__/token-flow-persistence.test.js +0 -356
- package/dist/__tests__/token-flow-routes.test.js +0 -199
- package/dist/__tests__/token-flow.test.js +0 -695
- package/dist/__tests__/tool-clusters.test.js +0 -177
- package/dist/__tests__/transport-mux.test.js +0 -283
- package/dist/__tests__/turn-segmenter.test.js +0 -166
- package/dist/__tests__/uninstall.test.js +0 -141
- package/dist/__tests__/warm-start-policy.test.js +0 -271
- package/dist/__tests__/wire-cap-nudge.test.js +0 -77
- package/dist/__tests__/worker-pool.test.js +0 -101
- package/dist/ui/assets/index-7gl3mIuY.css +0 -1
- package/dist/ui/assets/index-CX4FCWGT.js +0 -10
- package/dist/ui/assets/rolldown-runtime-S-ySWqyJ.js +0 -1
- package/dist/ui/assets/vis-network-NIJHUFI3.js +0 -908
- package/dist/ui/fonts/jetbrains-mono-latin-400-normal.woff +0 -0
- package/dist/ui/icon-wordmark.png +0 -0
- package/dist/ui/icon-wordmark.svg +0 -30
- package/dist/ui/icon.png +0 -0
- package/dist/ui/icon.svg +0 -25
- package/dist/ui/index.html +0 -15
- package/dist/ui/prototype-sandbox/index.html +0 -257
- package/dist/ui/screenshots/activity.png +0 -0
- package/dist/ui/screenshots/code-base-intelligence.png +0 -0
- package/dist/ui/screenshots/dashboard.png +0 -0
- package/dist/ui/screenshots/project-memory.png +0 -0
- package/dist/ui/screenshots/reasoning-quality.png +0 -0
- package/dist/ui/screenshots/reasoning-session.png +0 -0
- package/dist/ui/screenshots/token-session.png +0 -0
- package/dist/ui/screenshots/token-trace-main.png +0 -0
- package/dist/ui/screenshots/token-turn.png +0 -0
- package/dist/ui/unerr-wordmark.png +0 -0
- package/dist/ui/unerr-wordmark.svg +0 -9
- package/dist/ui/unerr.png +0 -0
- package/dist/ui/unerr.svg +0 -25
- package/dist/ui/web-app-manifest-192x192.png +0 -0
- package/dist/ui/web-app-manifest-512x512.png +0 -0
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for auto-bootstrap and PARSE mode (Task 8.4).
|
|
3
|
-
*/
|
|
4
|
-
import { describe, expect, it } from "vitest";
|
|
5
|
-
import { ParseModeIndex, extractEntitiesFromSource, } from "../proxy/auto-bootstrap.js";
|
|
6
|
-
describe("extractEntitiesFromSource", () => {
|
|
7
|
-
it("extracts exported functions", () => {
|
|
8
|
-
const code = `export function handlePayment(amount: number): boolean {
|
|
9
|
-
return amount > 0
|
|
10
|
-
}`;
|
|
11
|
-
const entities = extractEntitiesFromSource("src/billing.ts", code);
|
|
12
|
-
expect(entities).toHaveLength(1);
|
|
13
|
-
expect(entities[0]?.name).toBe("handlePayment");
|
|
14
|
-
expect(entities[0]?.kind).toBe("function");
|
|
15
|
-
expect(entities[0]?.key).toBe("src/billing.ts::handlePayment");
|
|
16
|
-
expect(entities[0]?.line_start).toBe(1);
|
|
17
|
-
expect(entities[0]?.signature).toBe("handlePayment(amount: number)");
|
|
18
|
-
});
|
|
19
|
-
it("extracts async functions", () => {
|
|
20
|
-
const code = `export async function fetchUser(id: string) {
|
|
21
|
-
return db.get(id)
|
|
22
|
-
}`;
|
|
23
|
-
const entities = extractEntitiesFromSource("src/api.ts", code);
|
|
24
|
-
expect(entities).toHaveLength(1);
|
|
25
|
-
expect(entities[0]?.kind).toBe("function");
|
|
26
|
-
expect(entities[0]?.name).toBe("fetchUser");
|
|
27
|
-
});
|
|
28
|
-
it("extracts arrow functions", () => {
|
|
29
|
-
const code = `export const validate = (input: string): boolean => {
|
|
30
|
-
return input.length > 0
|
|
31
|
-
}`;
|
|
32
|
-
const entities = extractEntitiesFromSource("src/utils.ts", code);
|
|
33
|
-
expect(entities).toHaveLength(1);
|
|
34
|
-
expect(entities[0]?.kind).toBe("function");
|
|
35
|
-
expect(entities[0]?.name).toBe("validate");
|
|
36
|
-
});
|
|
37
|
-
it("extracts classes", () => {
|
|
38
|
-
const code = `export class PaymentService {
|
|
39
|
-
process(amount: number) {
|
|
40
|
-
return amount
|
|
41
|
-
}
|
|
42
|
-
}`;
|
|
43
|
-
const entities = extractEntitiesFromSource("src/service.ts", code);
|
|
44
|
-
expect(entities.length).toBeGreaterThanOrEqual(1);
|
|
45
|
-
const cls = entities.find((e) => e.kind === "class");
|
|
46
|
-
expect(cls).toBeDefined();
|
|
47
|
-
expect(cls?.name).toBe("PaymentService");
|
|
48
|
-
});
|
|
49
|
-
it("extracts interfaces", () => {
|
|
50
|
-
const code = `export interface UserConfig {
|
|
51
|
-
name: string
|
|
52
|
-
email: string
|
|
53
|
-
}`;
|
|
54
|
-
const entities = extractEntitiesFromSource("src/types.ts", code);
|
|
55
|
-
expect(entities).toHaveLength(1);
|
|
56
|
-
expect(entities[0]?.kind).toBe("interface");
|
|
57
|
-
expect(entities[0]?.name).toBe("UserConfig");
|
|
58
|
-
});
|
|
59
|
-
it("extracts type aliases", () => {
|
|
60
|
-
const code = `export type Status = "active" | "inactive"`;
|
|
61
|
-
const entities = extractEntitiesFromSource("src/types.ts", code);
|
|
62
|
-
expect(entities).toHaveLength(1);
|
|
63
|
-
expect(entities[0]?.kind).toBe("type");
|
|
64
|
-
expect(entities[0]?.name).toBe("Status");
|
|
65
|
-
});
|
|
66
|
-
it("extracts methods inside classes", () => {
|
|
67
|
-
const code = `export class Router {
|
|
68
|
-
async execute(name: string) {
|
|
69
|
-
return name
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private validate(input: string) {
|
|
73
|
-
return true
|
|
74
|
-
}
|
|
75
|
-
}`;
|
|
76
|
-
const entities = extractEntitiesFromSource("src/router.ts", code);
|
|
77
|
-
const methods = entities.filter((e) => e.kind === "method");
|
|
78
|
-
expect(methods.length).toBeGreaterThanOrEqual(2);
|
|
79
|
-
expect(methods.find((m) => m.name === "Router.execute")).toBeDefined();
|
|
80
|
-
expect(methods.find((m) => m.name === "Router.validate")).toBeDefined();
|
|
81
|
-
});
|
|
82
|
-
it("handles multiple entity types in one file", () => {
|
|
83
|
-
const code = `export interface Config {
|
|
84
|
-
key: string
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export type Mode = "a" | "b"
|
|
88
|
-
|
|
89
|
-
export class Service {
|
|
90
|
-
run() {
|
|
91
|
-
return true
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function helper() {
|
|
96
|
-
return 1
|
|
97
|
-
}`;
|
|
98
|
-
const entities = extractEntitiesFromSource("src/mixed.ts", code);
|
|
99
|
-
const kinds = new Set(entities.map((e) => e.kind));
|
|
100
|
-
expect(kinds.has("interface")).toBe(true);
|
|
101
|
-
expect(kinds.has("type")).toBe(true);
|
|
102
|
-
expect(kinds.has("class")).toBe(true);
|
|
103
|
-
expect(kinds.has("function")).toBe(true);
|
|
104
|
-
});
|
|
105
|
-
it("returns empty for empty file", () => {
|
|
106
|
-
const entities = extractEntitiesFromSource("src/empty.ts", "");
|
|
107
|
-
expect(entities).toHaveLength(0);
|
|
108
|
-
});
|
|
109
|
-
it("does not extract control flow as methods", () => {
|
|
110
|
-
const code = `export class Foo {
|
|
111
|
-
bar() {
|
|
112
|
-
if (true) {
|
|
113
|
-
for (const x of []) {
|
|
114
|
-
while (false) {
|
|
115
|
-
switch (x) {
|
|
116
|
-
default: break
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}`;
|
|
123
|
-
const entities = extractEntitiesFromSource("src/foo.ts", code);
|
|
124
|
-
const methods = entities.filter((e) => e.kind === "method");
|
|
125
|
-
// Should only have 'bar', not 'if', 'for', 'while', 'switch'
|
|
126
|
-
expect(methods).toHaveLength(1);
|
|
127
|
-
expect(methods[0]?.name).toBe("Foo.bar");
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
describe("ParseModeIndex", () => {
|
|
131
|
-
it("indexes and retrieves entities by key", () => {
|
|
132
|
-
const index = new ParseModeIndex();
|
|
133
|
-
index.addEntities([
|
|
134
|
-
{
|
|
135
|
-
key: "src/a.ts::foo",
|
|
136
|
-
name: "foo",
|
|
137
|
-
kind: "function",
|
|
138
|
-
file_path: "src/a.ts",
|
|
139
|
-
line_start: 1,
|
|
140
|
-
signature: "foo()",
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
key: "src/b.ts::Bar",
|
|
144
|
-
name: "Bar",
|
|
145
|
-
kind: "class",
|
|
146
|
-
file_path: "src/b.ts",
|
|
147
|
-
line_start: 5,
|
|
148
|
-
signature: "Bar",
|
|
149
|
-
},
|
|
150
|
-
]);
|
|
151
|
-
expect(index.getEntity("src/a.ts::foo")).toBeDefined();
|
|
152
|
-
expect(index.getEntity("src/a.ts::foo")?.name).toBe("foo");
|
|
153
|
-
expect(index.getEntity("nonexistent")).toBeNull();
|
|
154
|
-
});
|
|
155
|
-
it("retrieves entities by file", () => {
|
|
156
|
-
const index = new ParseModeIndex();
|
|
157
|
-
index.addEntities([
|
|
158
|
-
{
|
|
159
|
-
key: "src/a.ts::foo",
|
|
160
|
-
name: "foo",
|
|
161
|
-
kind: "function",
|
|
162
|
-
file_path: "src/a.ts",
|
|
163
|
-
line_start: 1,
|
|
164
|
-
signature: "foo()",
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
key: "src/a.ts::bar",
|
|
168
|
-
name: "bar",
|
|
169
|
-
kind: "function",
|
|
170
|
-
file_path: "src/a.ts",
|
|
171
|
-
line_start: 10,
|
|
172
|
-
signature: "bar()",
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
key: "src/b.ts::Baz",
|
|
176
|
-
name: "Baz",
|
|
177
|
-
kind: "class",
|
|
178
|
-
file_path: "src/b.ts",
|
|
179
|
-
line_start: 1,
|
|
180
|
-
signature: "Baz",
|
|
181
|
-
},
|
|
182
|
-
]);
|
|
183
|
-
expect(index.getEntitiesByFile("src/a.ts")).toHaveLength(2);
|
|
184
|
-
expect(index.getEntitiesByFile("src/b.ts")).toHaveLength(1);
|
|
185
|
-
expect(index.getEntitiesByFile("src/c.ts")).toHaveLength(0);
|
|
186
|
-
});
|
|
187
|
-
it("searches by name substring", () => {
|
|
188
|
-
const index = new ParseModeIndex();
|
|
189
|
-
index.addEntities([
|
|
190
|
-
{
|
|
191
|
-
key: "src/a.ts::handlePayment",
|
|
192
|
-
name: "handlePayment",
|
|
193
|
-
kind: "function",
|
|
194
|
-
file_path: "src/a.ts",
|
|
195
|
-
line_start: 1,
|
|
196
|
-
signature: "handlePayment()",
|
|
197
|
-
},
|
|
198
|
-
{
|
|
199
|
-
key: "src/b.ts::processPayment",
|
|
200
|
-
name: "processPayment",
|
|
201
|
-
kind: "function",
|
|
202
|
-
file_path: "src/b.ts",
|
|
203
|
-
line_start: 1,
|
|
204
|
-
signature: "processPayment()",
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
key: "src/c.ts::getUserName",
|
|
208
|
-
name: "getUserName",
|
|
209
|
-
kind: "function",
|
|
210
|
-
file_path: "src/c.ts",
|
|
211
|
-
line_start: 1,
|
|
212
|
-
signature: "getUserName()",
|
|
213
|
-
},
|
|
214
|
-
]);
|
|
215
|
-
const results = index.search("payment");
|
|
216
|
-
expect(results).toHaveLength(2);
|
|
217
|
-
});
|
|
218
|
-
it("respects search limit", () => {
|
|
219
|
-
const index = new ParseModeIndex();
|
|
220
|
-
const entities = Array.from({ length: 20 }, (_, i) => ({
|
|
221
|
-
key: `src/a.ts::fn${i}`,
|
|
222
|
-
name: `fn${i}`,
|
|
223
|
-
kind: "function",
|
|
224
|
-
file_path: "src/a.ts",
|
|
225
|
-
line_start: i + 1,
|
|
226
|
-
signature: `fn${i}()`,
|
|
227
|
-
}));
|
|
228
|
-
index.addEntities(entities);
|
|
229
|
-
expect(index.search("fn", 5)).toHaveLength(5);
|
|
230
|
-
});
|
|
231
|
-
it("reports accurate stats", () => {
|
|
232
|
-
const index = new ParseModeIndex();
|
|
233
|
-
index.addEntities([
|
|
234
|
-
{
|
|
235
|
-
key: "src/a.ts::foo",
|
|
236
|
-
name: "foo",
|
|
237
|
-
kind: "function",
|
|
238
|
-
file_path: "src/a.ts",
|
|
239
|
-
line_start: 1,
|
|
240
|
-
signature: "foo()",
|
|
241
|
-
},
|
|
242
|
-
{
|
|
243
|
-
key: "src/a.ts::bar",
|
|
244
|
-
name: "bar",
|
|
245
|
-
kind: "function",
|
|
246
|
-
file_path: "src/a.ts",
|
|
247
|
-
line_start: 5,
|
|
248
|
-
signature: "bar()",
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
key: "src/b.ts::Baz",
|
|
252
|
-
name: "Baz",
|
|
253
|
-
kind: "class",
|
|
254
|
-
file_path: "src/b.ts",
|
|
255
|
-
line_start: 1,
|
|
256
|
-
signature: "Baz",
|
|
257
|
-
},
|
|
258
|
-
]);
|
|
259
|
-
const stats = index.getStats();
|
|
260
|
-
expect(stats.entityCount).toBe(3);
|
|
261
|
-
expect(stats.fileCount).toBe(2);
|
|
262
|
-
});
|
|
263
|
-
it("clears all entities", () => {
|
|
264
|
-
const index = new ParseModeIndex();
|
|
265
|
-
index.addEntities([
|
|
266
|
-
{
|
|
267
|
-
key: "src/a.ts::foo",
|
|
268
|
-
name: "foo",
|
|
269
|
-
kind: "function",
|
|
270
|
-
file_path: "src/a.ts",
|
|
271
|
-
line_start: 1,
|
|
272
|
-
signature: "foo()",
|
|
273
|
-
},
|
|
274
|
-
]);
|
|
275
|
-
expect(index.getStats().entityCount).toBe(1);
|
|
276
|
-
index.clear();
|
|
277
|
-
expect(index.getStats().entityCount).toBe(0);
|
|
278
|
-
expect(index.getEntity("src/a.ts::foo")).toBeNull();
|
|
279
|
-
});
|
|
280
|
-
});
|
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sprint L11 Tests: Background indexing, partial graph serving, deferred DriftTracker.
|
|
3
|
-
*/
|
|
4
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
|
-
// ── BackgroundIndexer Tests ─────────────────────────────────────
|
|
6
|
-
// Mock indexLocalProject so we don't need real CozoDB or tree-sitter
|
|
7
|
-
vi.mock("../intelligence/local-indexer.js", () => ({
|
|
8
|
-
indexLocalProject: vi.fn(async (_projectRoot, _graphStore, _repoId, opts) => {
|
|
9
|
-
const phases = [
|
|
10
|
-
"discovering",
|
|
11
|
-
"extracting",
|
|
12
|
-
"resolving",
|
|
13
|
-
"populating",
|
|
14
|
-
"communities",
|
|
15
|
-
"search",
|
|
16
|
-
"snapshot",
|
|
17
|
-
];
|
|
18
|
-
for (let i = 0; i < phases.length; i++) {
|
|
19
|
-
opts?.onProgress?.({
|
|
20
|
-
processed: i + 1,
|
|
21
|
-
total: phases.length,
|
|
22
|
-
phase: phases[i],
|
|
23
|
-
currentFile: i === 1 ? "src/index.ts" : null,
|
|
24
|
-
});
|
|
25
|
-
// Yield to event loop between phases
|
|
26
|
-
await new Promise((r) => setTimeout(r, 5));
|
|
27
|
-
}
|
|
28
|
-
return {
|
|
29
|
-
fileCount: 2,
|
|
30
|
-
entityCount: 5,
|
|
31
|
-
edgeCount: 3,
|
|
32
|
-
elapsedMs: 42,
|
|
33
|
-
communityCount: 1,
|
|
34
|
-
patternCount: 3,
|
|
35
|
-
ruleCount: 2,
|
|
36
|
-
};
|
|
37
|
-
}),
|
|
38
|
-
}));
|
|
39
|
-
describe("BackgroundIndexer", () => {
|
|
40
|
-
beforeEach(() => {
|
|
41
|
-
vi.clearAllMocks();
|
|
42
|
-
});
|
|
43
|
-
it("starts in idle state", async () => {
|
|
44
|
-
const { BackgroundIndexer } = await import("../intelligence/background-indexer.js");
|
|
45
|
-
const indexer = new BackgroundIndexer();
|
|
46
|
-
expect(indexer.getStatus()).toBe("idle");
|
|
47
|
-
expect(indexer.isIndexing()).toBe(false);
|
|
48
|
-
expect(indexer.isComplete()).toBe(false);
|
|
49
|
-
expect(indexer.getResult()).toBeNull();
|
|
50
|
-
expect(indexer.getError()).toBeNull();
|
|
51
|
-
});
|
|
52
|
-
it("transitions to indexing state immediately after start()", async () => {
|
|
53
|
-
const { BackgroundIndexer } = await import("../intelligence/background-indexer.js");
|
|
54
|
-
const indexer = new BackgroundIndexer();
|
|
55
|
-
const mockGraphStore = {};
|
|
56
|
-
indexer.start("/tmp/test-project", mockGraphStore, "test-repo", () => { }, () => { });
|
|
57
|
-
expect(indexer.getStatus()).toBe("indexing");
|
|
58
|
-
expect(indexer.isIndexing()).toBe(true);
|
|
59
|
-
// Wait for completion
|
|
60
|
-
await vi.waitFor(() => {
|
|
61
|
-
expect(indexer.isComplete()).toBe(true);
|
|
62
|
-
}, { timeout: 5000 });
|
|
63
|
-
});
|
|
64
|
-
it("reports progress during indexing", async () => {
|
|
65
|
-
const { BackgroundIndexer } = await import("../intelligence/background-indexer.js");
|
|
66
|
-
const indexer = new BackgroundIndexer();
|
|
67
|
-
const mockGraphStore = {};
|
|
68
|
-
const progressSnapshots = [];
|
|
69
|
-
indexer.start("/tmp/test-project", mockGraphStore, "test-repo", () => { }, () => { });
|
|
70
|
-
// Poll progress a few times
|
|
71
|
-
const pollInterval = setInterval(() => {
|
|
72
|
-
const p = indexer.getProgress();
|
|
73
|
-
progressSnapshots.push({
|
|
74
|
-
processed: p.processed,
|
|
75
|
-
total: p.total,
|
|
76
|
-
phase: p.phase,
|
|
77
|
-
});
|
|
78
|
-
}, 2);
|
|
79
|
-
await vi.waitFor(() => {
|
|
80
|
-
expect(indexer.isComplete()).toBe(true);
|
|
81
|
-
}, { timeout: 5000 });
|
|
82
|
-
clearInterval(pollInterval);
|
|
83
|
-
// Should have captured at least one progress snapshot
|
|
84
|
-
expect(progressSnapshots.length).toBeGreaterThan(0);
|
|
85
|
-
});
|
|
86
|
-
it("calls onComplete with IndexResult on success", async () => {
|
|
87
|
-
const { BackgroundIndexer } = await import("../intelligence/background-indexer.js");
|
|
88
|
-
const indexer = new BackgroundIndexer();
|
|
89
|
-
const mockGraphStore = {};
|
|
90
|
-
let completedResult = null;
|
|
91
|
-
indexer.start("/tmp/test-project", mockGraphStore, "test-repo", (result) => {
|
|
92
|
-
completedResult = result;
|
|
93
|
-
}, () => { });
|
|
94
|
-
await vi.waitFor(() => {
|
|
95
|
-
expect(indexer.isComplete()).toBe(true);
|
|
96
|
-
}, { timeout: 5000 });
|
|
97
|
-
expect(completedResult).not.toBeNull();
|
|
98
|
-
expect(completedResult.fileCount).toBe(2);
|
|
99
|
-
expect(completedResult.entityCount).toBe(5);
|
|
100
|
-
expect(completedResult.elapsedMs).toBe(42);
|
|
101
|
-
// Result should also be accessible via getter
|
|
102
|
-
const storedResult = indexer.getResult();
|
|
103
|
-
expect(storedResult).toEqual(completedResult);
|
|
104
|
-
});
|
|
105
|
-
it("does not start twice if already indexing", async () => {
|
|
106
|
-
const { BackgroundIndexer } = await import("../intelligence/background-indexer.js");
|
|
107
|
-
const indexer = new BackgroundIndexer();
|
|
108
|
-
const mockGraphStore = {};
|
|
109
|
-
let callCount = 0;
|
|
110
|
-
indexer.start("/tmp/test-project", mockGraphStore, "test-repo", () => {
|
|
111
|
-
callCount++;
|
|
112
|
-
}, () => { });
|
|
113
|
-
// Second start should be a no-op
|
|
114
|
-
indexer.start("/tmp/test-project", mockGraphStore, "test-repo", () => {
|
|
115
|
-
callCount++;
|
|
116
|
-
}, () => { });
|
|
117
|
-
await vi.waitFor(() => {
|
|
118
|
-
expect(indexer.isComplete()).toBe(true);
|
|
119
|
-
}, { timeout: 5000 });
|
|
120
|
-
// onComplete should have been called exactly once
|
|
121
|
-
expect(callCount).toBe(1);
|
|
122
|
-
});
|
|
123
|
-
it("getElapsedMs returns positive value after completion", async () => {
|
|
124
|
-
const { BackgroundIndexer } = await import("../intelligence/background-indexer.js");
|
|
125
|
-
const indexer = new BackgroundIndexer();
|
|
126
|
-
const mockGraphStore = {};
|
|
127
|
-
indexer.start("/tmp/test-project", mockGraphStore, "test-repo", () => { }, () => { });
|
|
128
|
-
await vi.waitFor(() => {
|
|
129
|
-
expect(indexer.isComplete()).toBe(true);
|
|
130
|
-
}, { timeout: 5000 });
|
|
131
|
-
expect(indexer.getElapsedMs()).toBeGreaterThan(0);
|
|
132
|
-
});
|
|
133
|
-
it("getState returns full snapshot", async () => {
|
|
134
|
-
const { BackgroundIndexer } = await import("../intelligence/background-indexer.js");
|
|
135
|
-
const indexer = new BackgroundIndexer();
|
|
136
|
-
const state = indexer.getState();
|
|
137
|
-
expect(state.status).toBe("idle");
|
|
138
|
-
expect(state.progress.processed).toBe(0);
|
|
139
|
-
expect(state.progress.total).toBe(0);
|
|
140
|
-
expect(state.progress.pct).toBe(0);
|
|
141
|
-
expect(state.result).toBeNull();
|
|
142
|
-
expect(state.error).toBeNull();
|
|
143
|
-
expect(state.startedAt).toBeNull();
|
|
144
|
-
expect(state.completedAt).toBeNull();
|
|
145
|
-
});
|
|
146
|
-
it("handles indexing errors gracefully", async () => {
|
|
147
|
-
// Override mock to throw
|
|
148
|
-
const { indexLocalProject } = await import("../intelligence/local-indexer.js");
|
|
149
|
-
vi.mocked(indexLocalProject).mockRejectedValueOnce(new Error("tree-sitter init failed"));
|
|
150
|
-
const { BackgroundIndexer } = await import("../intelligence/background-indexer.js");
|
|
151
|
-
const indexer = new BackgroundIndexer();
|
|
152
|
-
const mockGraphStore = {};
|
|
153
|
-
let errorCaught = null;
|
|
154
|
-
indexer.start("/tmp/test-project", mockGraphStore, "test-repo", () => { }, (err) => {
|
|
155
|
-
errorCaught = err;
|
|
156
|
-
});
|
|
157
|
-
await vi.waitFor(() => {
|
|
158
|
-
expect(indexer.getStatus()).toBe("error");
|
|
159
|
-
}, { timeout: 5000 });
|
|
160
|
-
expect(errorCaught).not.toBeNull();
|
|
161
|
-
expect(errorCaught.message).toBe("tree-sitter init failed");
|
|
162
|
-
expect(indexer.getError()?.message).toBe("tree-sitter init failed");
|
|
163
|
-
expect(indexer.isComplete()).toBe(false);
|
|
164
|
-
expect(indexer.isIndexing()).toBe(false);
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
// ── Partial Graph Query Tests ───────────────────────────────────
|
|
168
|
-
describe("QueryRouter partial graph handling", () => {
|
|
169
|
-
it("returns indexing metadata when backgroundIndexer is active", async () => {
|
|
170
|
-
const { BackgroundIndexer } = await import("../intelligence/background-indexer.js");
|
|
171
|
-
// Create a mock indexer that stays in "indexing" state
|
|
172
|
-
const mockIndexer = new BackgroundIndexer();
|
|
173
|
-
// Manually set state to "indexing" via Object.assign on private fields
|
|
174
|
-
Object.assign(mockIndexer, {
|
|
175
|
-
_status: "indexing",
|
|
176
|
-
_processed: 150,
|
|
177
|
-
_total: 500,
|
|
178
|
-
_phase: "extracting",
|
|
179
|
-
_currentFile: "src/service.ts",
|
|
180
|
-
_startedAt: Date.now(),
|
|
181
|
-
});
|
|
182
|
-
expect(mockIndexer.isIndexing()).toBe(true);
|
|
183
|
-
const progress = mockIndexer.getProgress();
|
|
184
|
-
expect(progress.processed).toBe(150);
|
|
185
|
-
expect(progress.total).toBe(500);
|
|
186
|
-
expect(progress.pct).toBe(30);
|
|
187
|
-
expect(progress.phase).toBe("extracting");
|
|
188
|
-
expect(progress.currentFile).toBe("src/service.ts");
|
|
189
|
-
});
|
|
190
|
-
});
|
|
191
|
-
// ── IndexProgressEvent Tests ────────────────────────────────────
|
|
192
|
-
describe("indexLocalProject onProgress callback", () => {
|
|
193
|
-
it("calls onProgress with phase transitions via mock", async () => {
|
|
194
|
-
const { indexLocalProject } = await import("../intelligence/local-indexer.js");
|
|
195
|
-
const phases = [];
|
|
196
|
-
await indexLocalProject("/tmp/test", {}, "test-repo", {
|
|
197
|
-
onProgress: (event) => {
|
|
198
|
-
if (!phases.includes(event.phase)) {
|
|
199
|
-
phases.push(event.phase);
|
|
200
|
-
}
|
|
201
|
-
},
|
|
202
|
-
});
|
|
203
|
-
// Should have gone through all phases (via our mock)
|
|
204
|
-
expect(phases).toContain("discovering");
|
|
205
|
-
expect(phases).toContain("extracting");
|
|
206
|
-
expect(phases).toContain("resolving");
|
|
207
|
-
expect(phases).toContain("populating");
|
|
208
|
-
expect(phases).toContain("communities");
|
|
209
|
-
expect(phases).toContain("search");
|
|
210
|
-
expect(phases).toContain("snapshot");
|
|
211
|
-
});
|
|
212
|
-
it("reports file count in extracting phase", async () => {
|
|
213
|
-
const { indexLocalProject } = await import("../intelligence/local-indexer.js");
|
|
214
|
-
let maxProcessed = 0;
|
|
215
|
-
let totalReported = 0;
|
|
216
|
-
await indexLocalProject("/tmp/test", {}, "test-repo", {
|
|
217
|
-
onProgress: (event) => {
|
|
218
|
-
if (event.phase === "extracting") {
|
|
219
|
-
maxProcessed = Math.max(maxProcessed, event.processed);
|
|
220
|
-
totalReported = event.total;
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
});
|
|
224
|
-
// Should have processed and reported totals
|
|
225
|
-
expect(totalReported).toBeGreaterThan(0);
|
|
226
|
-
expect(maxProcessed).toBeGreaterThan(0);
|
|
227
|
-
});
|
|
228
|
-
});
|