feed-the-machine 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +170 -170
- package/bin/generate-manifest.mjs +463 -463
- package/bin/install.mjs +491 -491
- package/docs/HOOKS.md +243 -243
- package/docs/INBOX.md +233 -233
- package/ftm/SKILL.md +122 -122
- package/ftm-audit/SKILL.md +623 -541
- package/ftm-audit/references/protocols/PROJECT-PATTERNS.md +91 -91
- package/ftm-audit/references/protocols/RUNTIME-WIRING.md +66 -66
- package/ftm-audit/references/protocols/WIRING-CONTRACTS.md +135 -135
- package/ftm-audit/references/strategies/AUTO-FIX-STRATEGIES.md +69 -69
- package/ftm-audit/references/templates/REPORT-FORMAT.md +96 -96
- package/ftm-audit/scripts/run-knip.sh +23 -23
- package/ftm-audit.yml +2 -2
- package/ftm-brainstorm/SKILL.md +498 -498
- package/ftm-brainstorm/evals/evals.json +100 -100
- package/ftm-brainstorm/evals/promptfoo.yaml +109 -109
- package/ftm-brainstorm/references/agent-prompts.md +224 -224
- package/ftm-brainstorm/references/plan-template.md +121 -121
- package/ftm-brainstorm.yml +2 -2
- package/ftm-browse/SKILL.md +454 -454
- package/ftm-browse/daemon/browser-manager.ts +206 -206
- package/ftm-browse/daemon/bun.lock +30 -30
- package/ftm-browse/daemon/cli.ts +347 -347
- package/ftm-browse/daemon/commands.ts +410 -410
- package/ftm-browse/daemon/main.ts +357 -357
- package/ftm-browse/daemon/package.json +17 -17
- package/ftm-browse/daemon/server.ts +189 -189
- package/ftm-browse/daemon/snapshot.ts +519 -519
- package/ftm-browse/daemon/tsconfig.json +22 -22
- package/ftm-browse.yml +4 -4
- package/ftm-capture/SKILL.md +370 -370
- package/ftm-capture.yml +4 -4
- package/ftm-codex-gate/SKILL.md +361 -361
- package/ftm-codex-gate.yml +2 -2
- package/ftm-config/SKILL.md +345 -345
- package/ftm-config.default.yml +82 -80
- package/ftm-config.yml +2 -2
- package/ftm-council/SKILL.md +416 -416
- package/ftm-council/references/prompts/CLAUDE-INVESTIGATION.md +60 -60
- package/ftm-council/references/prompts/CODEX-INVESTIGATION.md +58 -58
- package/ftm-council/references/prompts/GEMINI-INVESTIGATION.md +58 -58
- package/ftm-council/references/prompts/REBUTTAL-TEMPLATE.md +57 -57
- package/ftm-council/references/protocols/PREREQUISITES.md +47 -47
- package/ftm-council/references/protocols/STEP-0-FRAMING.md +46 -46
- package/ftm-council.yml +2 -2
- package/ftm-dashboard/SKILL.md +163 -163
- package/ftm-dashboard.yml +4 -4
- package/ftm-debug/SKILL.md +1037 -1037
- package/ftm-debug/references/phases/PHASE-0-INTAKE.md +58 -58
- package/ftm-debug/references/phases/PHASE-1-TRIAGE.md +46 -46
- package/ftm-debug/references/phases/PHASE-2-WAR-ROOM-AGENTS.md +279 -279
- package/ftm-debug/references/phases/PHASE-3-TO-6-EXECUTION.md +436 -436
- package/ftm-debug/references/protocols/BLACKBOARD.md +86 -86
- package/ftm-debug/references/protocols/EDGE-CASES.md +103 -103
- package/ftm-debug.yml +2 -2
- package/ftm-diagram/SKILL.md +277 -277
- package/ftm-diagram.yml +2 -2
- package/ftm-executor/SKILL.md +777 -767
- package/ftm-executor/references/STYLE-TEMPLATE.md +73 -73
- package/ftm-executor/references/phases/PHASE-0-VERIFICATION.md +62 -62
- package/ftm-executor/references/phases/PHASE-2-AGENT-ASSEMBLY.md +34 -34
- package/ftm-executor/references/phases/PHASE-3-WORKTREES.md +38 -38
- package/ftm-executor/references/phases/PHASE-4-5-AUDIT.md +72 -72
- package/ftm-executor/references/phases/PHASE-4-DISPATCH.md +66 -66
- package/ftm-executor/references/phases/PHASE-5-5-CODEX-GATE.md +73 -73
- package/ftm-executor/references/protocols/DOCUMENTATION-BOOTSTRAP.md +36 -36
- package/ftm-executor/references/protocols/MODEL-PROFILE.md +59 -44
- package/ftm-executor/references/protocols/PROGRESS-TRACKING.md +66 -66
- package/ftm-executor/runtime/ftm-runtime.mjs +252 -252
- package/ftm-executor/runtime/package.json +8 -8
- package/ftm-executor.yml +2 -2
- package/ftm-git/SKILL.md +441 -441
- package/ftm-git/evals/evals.json +26 -26
- package/ftm-git/evals/promptfoo.yaml +75 -75
- package/ftm-git/hooks/post-commit-experience.sh +92 -92
- package/ftm-git/references/patterns/SECRET-PATTERNS.md +104 -104
- package/ftm-git/references/protocols/REMEDIATION.md +139 -139
- package/ftm-git/scripts/pre-commit-secrets.sh +110 -110
- package/ftm-git.yml +2 -2
- package/ftm-inbox/backend/adapters/_retry.py +64 -64
- package/ftm-inbox/backend/adapters/base.py +230 -230
- package/ftm-inbox/backend/adapters/freshservice.py +104 -104
- package/ftm-inbox/backend/adapters/gmail.py +125 -125
- package/ftm-inbox/backend/adapters/jira.py +136 -136
- package/ftm-inbox/backend/adapters/registry.py +192 -192
- package/ftm-inbox/backend/adapters/slack.py +110 -110
- package/ftm-inbox/backend/db/connection.py +54 -54
- package/ftm-inbox/backend/db/schema.py +78 -78
- package/ftm-inbox/backend/executor/__init__.py +7 -7
- package/ftm-inbox/backend/executor/engine.py +149 -149
- package/ftm-inbox/backend/executor/step_runner.py +98 -98
- package/ftm-inbox/backend/main.py +103 -103
- package/ftm-inbox/backend/models/__init__.py +1 -1
- package/ftm-inbox/backend/models/unified_task.py +36 -36
- package/ftm-inbox/backend/planner/__init__.py +6 -6
- package/ftm-inbox/backend/planner/generator.py +127 -127
- package/ftm-inbox/backend/planner/schema.py +34 -34
- package/ftm-inbox/backend/requirements.txt +5 -5
- package/ftm-inbox/backend/routes/execute.py +186 -186
- package/ftm-inbox/backend/routes/health.py +52 -52
- package/ftm-inbox/backend/routes/inbox.py +68 -68
- package/ftm-inbox/backend/routes/plan.py +271 -271
- package/ftm-inbox/bin/launchagent.mjs +91 -91
- package/ftm-inbox/bin/setup.mjs +188 -188
- package/ftm-inbox/bin/start.sh +10 -10
- package/ftm-inbox/bin/status.sh +17 -17
- package/ftm-inbox/bin/stop.sh +8 -8
- package/ftm-inbox/config.example.yml +55 -55
- package/ftm-inbox/package-lock.json +2898 -2898
- package/ftm-inbox/package.json +26 -26
- package/ftm-inbox/postcss.config.js +6 -6
- package/ftm-inbox/src/app.css +199 -199
- package/ftm-inbox/src/app.html +18 -18
- package/ftm-inbox/src/lib/api.ts +166 -166
- package/ftm-inbox/src/lib/components/ExecutionLog.svelte +81 -81
- package/ftm-inbox/src/lib/components/InboxFeed.svelte +143 -143
- package/ftm-inbox/src/lib/components/PlanStep.svelte +271 -271
- package/ftm-inbox/src/lib/components/PlanView.svelte +206 -206
- package/ftm-inbox/src/lib/components/StreamPanel.svelte +99 -99
- package/ftm-inbox/src/lib/components/TaskCard.svelte +190 -190
- package/ftm-inbox/src/lib/components/ui/EmptyState.svelte +63 -63
- package/ftm-inbox/src/lib/components/ui/KawaiiCard.svelte +86 -86
- package/ftm-inbox/src/lib/components/ui/PillButton.svelte +106 -106
- package/ftm-inbox/src/lib/components/ui/StatusBadge.svelte +67 -67
- package/ftm-inbox/src/lib/components/ui/StreamDrawer.svelte +149 -149
- package/ftm-inbox/src/lib/components/ui/ThemeToggle.svelte +80 -80
- package/ftm-inbox/src/lib/theme.ts +47 -47
- package/ftm-inbox/src/routes/+layout.svelte +76 -76
- package/ftm-inbox/src/routes/+page.svelte +401 -401
- package/ftm-inbox/svelte.config.js +12 -12
- package/ftm-inbox/tailwind.config.ts +63 -63
- package/ftm-inbox/tsconfig.json +13 -13
- package/ftm-inbox/vite.config.ts +6 -6
- package/ftm-intent/SKILL.md +241 -241
- package/ftm-intent.yml +2 -2
- package/ftm-manifest.json +3794 -3794
- package/ftm-map/SKILL.md +291 -291
- package/ftm-map/scripts/db.py +712 -712
- package/ftm-map/scripts/index.py +415 -415
- package/ftm-map/scripts/parser.py +224 -224
- package/ftm-map/scripts/queries/go-tags.scm +20 -20
- package/ftm-map/scripts/queries/javascript-tags.scm +35 -35
- package/ftm-map/scripts/queries/python-tags.scm +31 -31
- package/ftm-map/scripts/queries/ruby-tags.scm +19 -19
- package/ftm-map/scripts/queries/rust-tags.scm +37 -37
- package/ftm-map/scripts/queries/typescript-tags.scm +41 -41
- package/ftm-map/scripts/query.py +301 -301
- package/ftm-map/scripts/ranker.py +377 -377
- package/ftm-map/scripts/requirements.txt +5 -5
- package/ftm-map/scripts/setup-hooks.sh +27 -27
- package/ftm-map/scripts/setup.sh +56 -56
- package/ftm-map/scripts/test_db.py +364 -364
- package/ftm-map/scripts/test_parser.py +174 -174
- package/ftm-map/scripts/test_query.py +183 -183
- package/ftm-map/scripts/test_ranker.py +199 -199
- package/ftm-map/scripts/views.py +591 -591
- package/ftm-map.yml +2 -2
- package/ftm-mind/SKILL.md +1943 -1943
- package/ftm-mind/evals/promptfoo.yaml +142 -142
- package/ftm-mind/references/blackboard-schema.md +328 -328
- package/ftm-mind/references/complexity-guide.md +110 -110
- package/ftm-mind/references/event-registry.md +319 -319
- package/ftm-mind/references/mcp-inventory.md +296 -296
- package/ftm-mind/references/protocols/COMPLEXITY-SIZING.md +72 -72
- package/ftm-mind/references/protocols/MCP-HEURISTICS.md +32 -32
- package/ftm-mind/references/protocols/PLAN-APPROVAL.md +80 -80
- package/ftm-mind/references/reflexion-protocol.md +249 -249
- package/ftm-mind/references/routing/SCENARIOS.md +22 -22
- package/ftm-mind/references/routing-scenarios.md +35 -35
- package/ftm-mind.yml +2 -2
- package/ftm-pause/SKILL.md +395 -395
- package/ftm-pause/references/protocols/SKILL-RESTORE-PROTOCOLS.md +186 -186
- package/ftm-pause/references/protocols/VALIDATION.md +80 -80
- package/ftm-pause.yml +2 -2
- package/ftm-researcher/SKILL.md +275 -275
- package/ftm-researcher/evals/agent-diversity.yaml +17 -17
- package/ftm-researcher/evals/synthesis-quality.yaml +12 -12
- package/ftm-researcher/evals/trigger-accuracy.yaml +39 -39
- package/ftm-researcher/references/adaptive-search.md +116 -116
- package/ftm-researcher/references/agent-prompts.md +193 -193
- package/ftm-researcher/references/council-integration.md +193 -193
- package/ftm-researcher/references/output-format.md +203 -203
- package/ftm-researcher/references/synthesis-pipeline.md +165 -165
- package/ftm-researcher/scripts/score_credibility.py +234 -234
- package/ftm-researcher/scripts/validate_research.py +92 -92
- package/ftm-researcher.yml +2 -2
- package/ftm-resume/SKILL.md +518 -518
- package/ftm-resume/references/protocols/VALIDATION.md +172 -172
- package/ftm-resume.yml +2 -2
- package/ftm-retro/SKILL.md +380 -380
- package/ftm-retro/references/protocols/SCORING-RUBRICS.md +89 -89
- package/ftm-retro/references/templates/REPORT-FORMAT.md +109 -109
- package/ftm-retro.yml +2 -2
- package/ftm-routine/SKILL.md +170 -170
- package/ftm-routine.yml +4 -4
- package/ftm-state/blackboard/capabilities.json +5 -5
- package/ftm-state/blackboard/capabilities.schema.json +27 -27
- package/ftm-state/blackboard/context.json +23 -23
- package/ftm-state/blackboard/experiences/index.json +9 -9
- package/ftm-state/blackboard/patterns.json +6 -6
- package/ftm-state/schemas/context.schema.json +130 -130
- package/ftm-state/schemas/experience-index.schema.json +77 -77
- package/ftm-state/schemas/experience.schema.json +78 -78
- package/ftm-state/schemas/patterns.schema.json +44 -44
- package/ftm-upgrade/SKILL.md +194 -194
- package/ftm-upgrade/scripts/check-version.sh +76 -76
- package/ftm-upgrade/scripts/upgrade.sh +143 -143
- package/ftm-upgrade.yml +2 -2
- package/ftm-verify.yml +2 -2
- package/ftm.yml +2 -2
- package/hooks/ftm-blackboard-enforcer.sh +93 -93
- package/hooks/ftm-discovery-reminder.sh +90 -90
- package/hooks/ftm-drafts-gate.sh +61 -61
- package/hooks/ftm-event-logger.mjs +107 -107
- package/hooks/ftm-map-autodetect.sh +79 -79
- package/hooks/ftm-pending-sync-check.sh +22 -22
- package/hooks/ftm-plan-gate.sh +92 -92
- package/hooks/ftm-post-commit-trigger.sh +57 -57
- package/hooks/settings-template.json +81 -81
- package/install.sh +363 -363
- package/package.json +84 -84
- package/uninstall.sh +25 -25
|
@@ -1,183 +1,183 @@
|
|
|
1
|
-
"""Tests for query.py -- all query modes with new schema."""
|
|
2
|
-
import os
|
|
3
|
-
import sys
|
|
4
|
-
import tempfile
|
|
5
|
-
import pytest
|
|
6
|
-
|
|
7
|
-
sys.path.insert(0, os.path.dirname(__file__))
|
|
8
|
-
from db import get_connection, add_file, add_symbol, add_reference, rebuild_file_edges, rebuild_symbol_edges
|
|
9
|
-
from query import blast_radius, dependency_chain, search, symbol_info, context, stats
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@pytest.fixture
|
|
13
|
-
def indexed_conn():
|
|
14
|
-
"""Connection with a fully indexed mini-project."""
|
|
15
|
-
with tempfile.TemporaryDirectory() as tmp:
|
|
16
|
-
conn = get_connection(tmp)
|
|
17
|
-
|
|
18
|
-
f1 = add_file(conn, "src/auth.py", "python", 1.0, line_count=50)
|
|
19
|
-
f2 = add_file(conn, "src/api.py", "python", 1.0, line_count=100)
|
|
20
|
-
f3 = add_file(conn, "src/utils.py", "python", 1.0, line_count=30)
|
|
21
|
-
|
|
22
|
-
add_symbol(conn, f1, "authenticate", "function", 1, 20, signature="def authenticate(req)")
|
|
23
|
-
add_symbol(conn, f1, "verify_token", "function", 25, 40)
|
|
24
|
-
add_symbol(conn, f2, "handle_request", "function", 1, 50)
|
|
25
|
-
add_symbol(conn, f3, "format_date", "function", 1, 10)
|
|
26
|
-
add_symbol(conn, f3, "parse_config", "function", 15, 25)
|
|
27
|
-
|
|
28
|
-
add_reference(conn, f2, "authenticate", 10)
|
|
29
|
-
add_reference(conn, f2, "format_date", 20)
|
|
30
|
-
add_reference(conn, f1, "format_date", 30)
|
|
31
|
-
|
|
32
|
-
rebuild_file_edges(conn)
|
|
33
|
-
rebuild_symbol_edges(conn)
|
|
34
|
-
conn.commit()
|
|
35
|
-
|
|
36
|
-
yield conn
|
|
37
|
-
conn.close()
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class TestBlastRadius:
|
|
41
|
-
def test_finds_affected(self, indexed_conn):
|
|
42
|
-
result = blast_radius(indexed_conn, "authenticate")
|
|
43
|
-
assert result["affected_count"] >= 1
|
|
44
|
-
|
|
45
|
-
def test_returns_symbol_name(self, indexed_conn):
|
|
46
|
-
result = blast_radius(indexed_conn, "authenticate")
|
|
47
|
-
assert result["symbol"] == "authenticate"
|
|
48
|
-
|
|
49
|
-
def test_results_have_file_path(self, indexed_conn):
|
|
50
|
-
result = blast_radius(indexed_conn, "authenticate")
|
|
51
|
-
if result["results"]:
|
|
52
|
-
assert "file_path" in result["results"][0]
|
|
53
|
-
|
|
54
|
-
def test_results_have_depth(self, indexed_conn):
|
|
55
|
-
result = blast_radius(indexed_conn, "authenticate")
|
|
56
|
-
if result["results"]:
|
|
57
|
-
assert "depth" in result["results"][0]
|
|
58
|
-
|
|
59
|
-
def test_not_found(self, indexed_conn):
|
|
60
|
-
result = blast_radius(indexed_conn, "nonexistent")
|
|
61
|
-
assert "error" in result
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class TestDependencyChain:
|
|
65
|
-
def test_finds_deps(self, indexed_conn):
|
|
66
|
-
result = dependency_chain(indexed_conn, "handle_request")
|
|
67
|
-
assert result["dependency_count"] >= 1
|
|
68
|
-
|
|
69
|
-
def test_returns_symbol_name(self, indexed_conn):
|
|
70
|
-
result = dependency_chain(indexed_conn, "handle_request")
|
|
71
|
-
assert result["symbol"] == "handle_request"
|
|
72
|
-
|
|
73
|
-
def test_not_found(self, indexed_conn):
|
|
74
|
-
result = dependency_chain(indexed_conn, "nonexistent")
|
|
75
|
-
assert "error" in result
|
|
76
|
-
|
|
77
|
-
def test_leaf_has_no_deps(self, indexed_conn):
|
|
78
|
-
result = dependency_chain(indexed_conn, "verify_token")
|
|
79
|
-
# verify_token has no references to other symbols in its scope
|
|
80
|
-
assert result["dependency_count"] == 0 or "error" not in result
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
class TestSearch:
|
|
84
|
-
def test_finds_by_name(self, indexed_conn):
|
|
85
|
-
result = search(indexed_conn, "authenticate")
|
|
86
|
-
assert result["result_count"] >= 1
|
|
87
|
-
|
|
88
|
-
def test_returns_query(self, indexed_conn):
|
|
89
|
-
result = search(indexed_conn, "authenticate")
|
|
90
|
-
assert result["query"] == "authenticate"
|
|
91
|
-
|
|
92
|
-
def test_results_have_file_path(self, indexed_conn):
|
|
93
|
-
result = search(indexed_conn, "authenticate")
|
|
94
|
-
if result["results"]:
|
|
95
|
-
assert "file_path" in result["results"][0]
|
|
96
|
-
|
|
97
|
-
def test_results_have_rank(self, indexed_conn):
|
|
98
|
-
result = search(indexed_conn, "authenticate")
|
|
99
|
-
if result["results"]:
|
|
100
|
-
assert "rank" in result["results"][0]
|
|
101
|
-
|
|
102
|
-
def test_empty_results(self, indexed_conn):
|
|
103
|
-
result = search(indexed_conn, "zzzznonexistent")
|
|
104
|
-
assert result["result_count"] == 0
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
class TestSymbolInfo:
|
|
108
|
-
def test_returns_name(self, indexed_conn):
|
|
109
|
-
result = symbol_info(indexed_conn, "authenticate")
|
|
110
|
-
assert result["name"] == "authenticate"
|
|
111
|
-
|
|
112
|
-
def test_returns_kind(self, indexed_conn):
|
|
113
|
-
result = symbol_info(indexed_conn, "authenticate")
|
|
114
|
-
assert "kind" in result
|
|
115
|
-
|
|
116
|
-
def test_returns_reference_count(self, indexed_conn):
|
|
117
|
-
result = symbol_info(indexed_conn, "authenticate")
|
|
118
|
-
assert "reference_count" in result
|
|
119
|
-
assert result["reference_count"] >= 1 # api.py references it
|
|
120
|
-
|
|
121
|
-
def test_returns_callers_callees(self, indexed_conn):
|
|
122
|
-
result = symbol_info(indexed_conn, "authenticate")
|
|
123
|
-
assert "callers" in result
|
|
124
|
-
assert "callees" in result
|
|
125
|
-
|
|
126
|
-
def test_returns_blast_radius_count(self, indexed_conn):
|
|
127
|
-
result = symbol_info(indexed_conn, "authenticate")
|
|
128
|
-
assert "blast_radius_count" in result
|
|
129
|
-
|
|
130
|
-
def test_returns_file(self, indexed_conn):
|
|
131
|
-
result = symbol_info(indexed_conn, "authenticate")
|
|
132
|
-
assert result["file"] == "src/auth.py"
|
|
133
|
-
|
|
134
|
-
def test_not_found(self, indexed_conn):
|
|
135
|
-
result = symbol_info(indexed_conn, "nonexistent")
|
|
136
|
-
assert "error" in result
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
class TestContext:
|
|
140
|
-
def test_returns_files(self, indexed_conn):
|
|
141
|
-
result = context(indexed_conn, seed_symbols=["authenticate"])
|
|
142
|
-
assert "files" in result
|
|
143
|
-
assert len(result["files"]) > 0
|
|
144
|
-
|
|
145
|
-
def test_files_have_path(self, indexed_conn):
|
|
146
|
-
result = context(indexed_conn, seed_symbols=["authenticate"])
|
|
147
|
-
if result["files"]:
|
|
148
|
-
assert "path" in result["files"][0]
|
|
149
|
-
|
|
150
|
-
def test_files_have_score(self, indexed_conn):
|
|
151
|
-
result = context(indexed_conn, seed_symbols=["authenticate"])
|
|
152
|
-
if result["files"]:
|
|
153
|
-
assert "score" in result["files"][0]
|
|
154
|
-
|
|
155
|
-
def test_respects_budget(self, indexed_conn):
|
|
156
|
-
result = context(indexed_conn, token_budget=50)
|
|
157
|
-
if result.get("total_tokens"):
|
|
158
|
-
assert result["total_tokens"] <= 50 * 1.15
|
|
159
|
-
|
|
160
|
-
def test_no_budget_returns_all(self, indexed_conn):
|
|
161
|
-
result = context(indexed_conn, token_budget=None)
|
|
162
|
-
assert "files" in result
|
|
163
|
-
|
|
164
|
-
def test_seed_files(self, indexed_conn):
|
|
165
|
-
result = context(indexed_conn, seed_files=["src/auth.py"])
|
|
166
|
-
assert "files" in result
|
|
167
|
-
assert len(result["files"]) > 0
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class TestStats:
|
|
171
|
-
def test_returns_counts(self, indexed_conn):
|
|
172
|
-
result = stats(indexed_conn)
|
|
173
|
-
assert result["file_count"] == 3
|
|
174
|
-
assert result["symbol_count"] == 5
|
|
175
|
-
|
|
176
|
-
def test_returns_edge_counts(self, indexed_conn):
|
|
177
|
-
result = stats(indexed_conn)
|
|
178
|
-
assert "edge_count" in result
|
|
179
|
-
assert "file_edge_count" in result
|
|
180
|
-
|
|
181
|
-
def test_returns_reference_count(self, indexed_conn):
|
|
182
|
-
result = stats(indexed_conn)
|
|
183
|
-
assert result["reference_count"] == 3
|
|
1
|
+
"""Tests for query.py -- all query modes with new schema."""
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import tempfile
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
sys.path.insert(0, os.path.dirname(__file__))
|
|
8
|
+
from db import get_connection, add_file, add_symbol, add_reference, rebuild_file_edges, rebuild_symbol_edges
|
|
9
|
+
from query import blast_radius, dependency_chain, search, symbol_info, context, stats
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.fixture
|
|
13
|
+
def indexed_conn():
|
|
14
|
+
"""Connection with a fully indexed mini-project."""
|
|
15
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
16
|
+
conn = get_connection(tmp)
|
|
17
|
+
|
|
18
|
+
f1 = add_file(conn, "src/auth.py", "python", 1.0, line_count=50)
|
|
19
|
+
f2 = add_file(conn, "src/api.py", "python", 1.0, line_count=100)
|
|
20
|
+
f3 = add_file(conn, "src/utils.py", "python", 1.0, line_count=30)
|
|
21
|
+
|
|
22
|
+
add_symbol(conn, f1, "authenticate", "function", 1, 20, signature="def authenticate(req)")
|
|
23
|
+
add_symbol(conn, f1, "verify_token", "function", 25, 40)
|
|
24
|
+
add_symbol(conn, f2, "handle_request", "function", 1, 50)
|
|
25
|
+
add_symbol(conn, f3, "format_date", "function", 1, 10)
|
|
26
|
+
add_symbol(conn, f3, "parse_config", "function", 15, 25)
|
|
27
|
+
|
|
28
|
+
add_reference(conn, f2, "authenticate", 10)
|
|
29
|
+
add_reference(conn, f2, "format_date", 20)
|
|
30
|
+
add_reference(conn, f1, "format_date", 30)
|
|
31
|
+
|
|
32
|
+
rebuild_file_edges(conn)
|
|
33
|
+
rebuild_symbol_edges(conn)
|
|
34
|
+
conn.commit()
|
|
35
|
+
|
|
36
|
+
yield conn
|
|
37
|
+
conn.close()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TestBlastRadius:
|
|
41
|
+
def test_finds_affected(self, indexed_conn):
|
|
42
|
+
result = blast_radius(indexed_conn, "authenticate")
|
|
43
|
+
assert result["affected_count"] >= 1
|
|
44
|
+
|
|
45
|
+
def test_returns_symbol_name(self, indexed_conn):
|
|
46
|
+
result = blast_radius(indexed_conn, "authenticate")
|
|
47
|
+
assert result["symbol"] == "authenticate"
|
|
48
|
+
|
|
49
|
+
def test_results_have_file_path(self, indexed_conn):
|
|
50
|
+
result = blast_radius(indexed_conn, "authenticate")
|
|
51
|
+
if result["results"]:
|
|
52
|
+
assert "file_path" in result["results"][0]
|
|
53
|
+
|
|
54
|
+
def test_results_have_depth(self, indexed_conn):
|
|
55
|
+
result = blast_radius(indexed_conn, "authenticate")
|
|
56
|
+
if result["results"]:
|
|
57
|
+
assert "depth" in result["results"][0]
|
|
58
|
+
|
|
59
|
+
def test_not_found(self, indexed_conn):
|
|
60
|
+
result = blast_radius(indexed_conn, "nonexistent")
|
|
61
|
+
assert "error" in result
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class TestDependencyChain:
|
|
65
|
+
def test_finds_deps(self, indexed_conn):
|
|
66
|
+
result = dependency_chain(indexed_conn, "handle_request")
|
|
67
|
+
assert result["dependency_count"] >= 1
|
|
68
|
+
|
|
69
|
+
def test_returns_symbol_name(self, indexed_conn):
|
|
70
|
+
result = dependency_chain(indexed_conn, "handle_request")
|
|
71
|
+
assert result["symbol"] == "handle_request"
|
|
72
|
+
|
|
73
|
+
def test_not_found(self, indexed_conn):
|
|
74
|
+
result = dependency_chain(indexed_conn, "nonexistent")
|
|
75
|
+
assert "error" in result
|
|
76
|
+
|
|
77
|
+
def test_leaf_has_no_deps(self, indexed_conn):
|
|
78
|
+
result = dependency_chain(indexed_conn, "verify_token")
|
|
79
|
+
# verify_token has no references to other symbols in its scope
|
|
80
|
+
assert result["dependency_count"] == 0 or "error" not in result
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class TestSearch:
|
|
84
|
+
def test_finds_by_name(self, indexed_conn):
|
|
85
|
+
result = search(indexed_conn, "authenticate")
|
|
86
|
+
assert result["result_count"] >= 1
|
|
87
|
+
|
|
88
|
+
def test_returns_query(self, indexed_conn):
|
|
89
|
+
result = search(indexed_conn, "authenticate")
|
|
90
|
+
assert result["query"] == "authenticate"
|
|
91
|
+
|
|
92
|
+
def test_results_have_file_path(self, indexed_conn):
|
|
93
|
+
result = search(indexed_conn, "authenticate")
|
|
94
|
+
if result["results"]:
|
|
95
|
+
assert "file_path" in result["results"][0]
|
|
96
|
+
|
|
97
|
+
def test_results_have_rank(self, indexed_conn):
|
|
98
|
+
result = search(indexed_conn, "authenticate")
|
|
99
|
+
if result["results"]:
|
|
100
|
+
assert "rank" in result["results"][0]
|
|
101
|
+
|
|
102
|
+
def test_empty_results(self, indexed_conn):
|
|
103
|
+
result = search(indexed_conn, "zzzznonexistent")
|
|
104
|
+
assert result["result_count"] == 0
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class TestSymbolInfo:
|
|
108
|
+
def test_returns_name(self, indexed_conn):
|
|
109
|
+
result = symbol_info(indexed_conn, "authenticate")
|
|
110
|
+
assert result["name"] == "authenticate"
|
|
111
|
+
|
|
112
|
+
def test_returns_kind(self, indexed_conn):
|
|
113
|
+
result = symbol_info(indexed_conn, "authenticate")
|
|
114
|
+
assert "kind" in result
|
|
115
|
+
|
|
116
|
+
def test_returns_reference_count(self, indexed_conn):
|
|
117
|
+
result = symbol_info(indexed_conn, "authenticate")
|
|
118
|
+
assert "reference_count" in result
|
|
119
|
+
assert result["reference_count"] >= 1 # api.py references it
|
|
120
|
+
|
|
121
|
+
def test_returns_callers_callees(self, indexed_conn):
|
|
122
|
+
result = symbol_info(indexed_conn, "authenticate")
|
|
123
|
+
assert "callers" in result
|
|
124
|
+
assert "callees" in result
|
|
125
|
+
|
|
126
|
+
def test_returns_blast_radius_count(self, indexed_conn):
|
|
127
|
+
result = symbol_info(indexed_conn, "authenticate")
|
|
128
|
+
assert "blast_radius_count" in result
|
|
129
|
+
|
|
130
|
+
def test_returns_file(self, indexed_conn):
|
|
131
|
+
result = symbol_info(indexed_conn, "authenticate")
|
|
132
|
+
assert result["file"] == "src/auth.py"
|
|
133
|
+
|
|
134
|
+
def test_not_found(self, indexed_conn):
|
|
135
|
+
result = symbol_info(indexed_conn, "nonexistent")
|
|
136
|
+
assert "error" in result
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class TestContext:
|
|
140
|
+
def test_returns_files(self, indexed_conn):
|
|
141
|
+
result = context(indexed_conn, seed_symbols=["authenticate"])
|
|
142
|
+
assert "files" in result
|
|
143
|
+
assert len(result["files"]) > 0
|
|
144
|
+
|
|
145
|
+
def test_files_have_path(self, indexed_conn):
|
|
146
|
+
result = context(indexed_conn, seed_symbols=["authenticate"])
|
|
147
|
+
if result["files"]:
|
|
148
|
+
assert "path" in result["files"][0]
|
|
149
|
+
|
|
150
|
+
def test_files_have_score(self, indexed_conn):
|
|
151
|
+
result = context(indexed_conn, seed_symbols=["authenticate"])
|
|
152
|
+
if result["files"]:
|
|
153
|
+
assert "score" in result["files"][0]
|
|
154
|
+
|
|
155
|
+
def test_respects_budget(self, indexed_conn):
|
|
156
|
+
result = context(indexed_conn, token_budget=50)
|
|
157
|
+
if result.get("total_tokens"):
|
|
158
|
+
assert result["total_tokens"] <= 50 * 1.15
|
|
159
|
+
|
|
160
|
+
def test_no_budget_returns_all(self, indexed_conn):
|
|
161
|
+
result = context(indexed_conn, token_budget=None)
|
|
162
|
+
assert "files" in result
|
|
163
|
+
|
|
164
|
+
def test_seed_files(self, indexed_conn):
|
|
165
|
+
result = context(indexed_conn, seed_files=["src/auth.py"])
|
|
166
|
+
assert "files" in result
|
|
167
|
+
assert len(result["files"]) > 0
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class TestStats:
|
|
171
|
+
def test_returns_counts(self, indexed_conn):
|
|
172
|
+
result = stats(indexed_conn)
|
|
173
|
+
assert result["file_count"] == 3
|
|
174
|
+
assert result["symbol_count"] == 5
|
|
175
|
+
|
|
176
|
+
def test_returns_edge_counts(self, indexed_conn):
|
|
177
|
+
result = stats(indexed_conn)
|
|
178
|
+
assert "edge_count" in result
|
|
179
|
+
assert "file_edge_count" in result
|
|
180
|
+
|
|
181
|
+
def test_returns_reference_count(self, indexed_conn):
|
|
182
|
+
result = stats(indexed_conn)
|
|
183
|
+
assert result["reference_count"] == 3
|