claude-flow-novice 2.18.16 → 2.18.17
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/.claude/agents/cfn-dev-team/analysts/analyst.md +9 -0
- package/.claude/agents/cfn-dev-team/analysts/root-cause-analyst.md +9 -0
- package/.claude/agents/cfn-dev-team/architecture/api-designer-persona.md +10 -1
- package/.claude/agents/cfn-dev-team/architecture/base-template-generator.md +9 -0
- package/.claude/agents/cfn-dev-team/architecture/goal-planner.md +10 -1
- package/.claude/agents/cfn-dev-team/architecture/planner.md +9 -0
- package/.claude/agents/cfn-dev-team/architecture/system-architect.md +9 -0
- package/.claude/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +9 -0
- package/.claude/agents/cfn-dev-team/coordinators/consensus-builder.md +10 -1
- package/.claude/agents/cfn-dev-team/coordinators/handoff-coordinator.md +9 -0
- package/.claude/agents/cfn-dev-team/coordinators/multi-sprint-coordinator.md +9 -0
- package/.claude/agents/cfn-dev-team/dev-ops/devops-engineer.md +9 -0
- package/.claude/agents/cfn-dev-team/dev-ops/docker-specialist.md +9 -0
- package/.claude/agents/cfn-dev-team/dev-ops/github-commit-agent.md +9 -0
- package/.claude/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +9 -0
- package/.claude/agents/cfn-dev-team/developers/api-gateway-specialist.md +9 -0
- package/.claude/agents/cfn-dev-team/developers/data/data-engineer.md +9 -0
- package/.claude/agents/cfn-dev-team/developers/database/database-architect.md +9 -0
- package/.claude/agents/cfn-dev-team/developers/database/supabase-specialist.md +9 -0
- package/.claude/agents/cfn-dev-team/developers/frontend/mobile-dev.md +10 -1
- package/.claude/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +10 -1
- package/.claude/agents/cfn-dev-team/developers/frontend/ui-designer.md +10 -1
- package/.claude/agents/cfn-dev-team/developers/graphql-specialist.md +9 -0
- package/.claude/agents/cfn-dev-team/developers/rust-developer.md +10 -1
- package/.claude/agents/cfn-dev-team/documentation/agent-type-guidelines.md +9 -0
- package/.claude/agents/cfn-dev-team/documentation/api-documentation.md +10 -1
- package/.claude/agents/cfn-dev-team/documentation/pseudocode.md +10 -1
- package/.claude/agents/cfn-dev-team/documentation/specification-agent.md +10 -1
- package/.claude/agents/cfn-dev-team/product-owners/accessibility-advocate-persona.md +10 -1
- package/.claude/agents/cfn-dev-team/product-owners/cto-agent.md +9 -0
- package/.claude/agents/cfn-dev-team/product-owners/power-user-persona.md +10 -1
- package/.claude/agents/cfn-dev-team/product-owners/product-owner.md +9 -0
- package/.claude/agents/cfn-dev-team/reviewers/quality/code-quality-validator.md +9 -0
- package/.claude/agents/cfn-dev-team/reviewers/quality/cyclomatic-complexity-reducer.md +9 -0
- package/.claude/agents/cfn-dev-team/reviewers/quality/perf-analyzer.md +9 -0
- package/.claude/agents/cfn-dev-team/reviewers/quality/performance-benchmarker.md +10 -1
- package/.claude/agents/cfn-dev-team/reviewers/quality/quality-metrics.md +9 -0
- package/.claude/agents/cfn-dev-team/testers/api-testing-specialist.md +9 -0
- package/.claude/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +9 -0
- package/.claude/agents/cfn-dev-team/testers/contract-tester.md +9 -0
- package/.claude/agents/cfn-dev-team/testers/e2e/playwright-tester.md +9 -0
- package/.claude/agents/cfn-dev-team/testers/integration-tester.md +9 -0
- package/.claude/agents/cfn-dev-team/testers/interaction-tester.md +9 -0
- package/.claude/agents/cfn-dev-team/testers/load-testing-specialist.md +9 -0
- package/.claude/agents/cfn-dev-team/testers/mutation-testing-specialist.md +9 -0
- package/.claude/agents/cfn-dev-team/testers/playwright-tester.md +10 -1
- package/.claude/agents/cfn-dev-team/testers/unit/tdd-london-unit-swarm.md +10 -1
- package/.claude/agents/cfn-dev-team/testers/validation/validation-production-validator.md +10 -1
- package/.claude/agents/cfn-dev-team/testing/test-validation-agent.md +9 -0
- package/.claude/agents/cfn-dev-team/utility/agent-builder.md +10 -1
- package/.claude/agents/cfn-dev-team/utility/context-curator.md +9 -0
- package/.claude/agents/cfn-dev-team/utility/memory-leak-specialist.md +9 -0
- package/.claude/agents/cfn-dev-team/utility/researcher.md +9 -0
- package/.claude/agents/cfn-dev-team/utility/z-ai-specialist.md +9 -0
- package/.claude/hooks/SessionStart-cfn-build-ruvector.sh +12 -0
- package/.claude/hooks/SessionStart:cfn-build-ruvector.sh +28 -0
- package/.claude/skills/bulk-add-ruvector-instructions.sh +34 -46
- package/.claude/skills/cfn-local-ruvector-accelerator/.claude/hooks/SessionStart-cfn-build-ruvector.sh +12 -0
- package/.claude/skills/cfn-local-ruvector-accelerator/SKILL.md +89 -6
- package/.claude/skills/cfn-local-ruvector-accelerator/src/cli/index.rs +36 -10
- package/.claude/skills/cfn-local-ruvector-accelerator/src/cli/index_ast.rs +4 -1
- package/.claude/skills/cfn-local-ruvector-accelerator/src/extractors/mod.rs +1 -1
- package/.claude/skills/cfn-local-ruvector-accelerator/src/migration_v2.rs +7 -7
- package/.claude/skills/cfn-local-ruvector-accelerator/src/query_api.rs +6 -3
- package/.claude/skills/cfn-local-ruvector-accelerator/src/schema_v2.rs +16 -1
- package/.claude/skills/cfn-local-ruvector-accelerator/src/store_v2.rs +7 -3
- package/.claude/skills/cfn-local-ruvector-accelerator/src/store_v2_tx.rs +5 -3
- package/.claude/skills/cfn-local-ruvector-accelerator/src/transaction_tests.rs +8 -2
- package/CLAUDE.md +2 -1
- package/package.json +1 -1
|
@@ -1,8 +1,91 @@
|
|
|
1
|
-
#
|
|
2
|
-
./target/release/local-ruvector init
|
|
1
|
+
# RuVector Local Semantic Code Search
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
./target/release/local-ruvector index --path /path/to/project --types rs
|
|
3
|
+
## WHEN TO USE THIS SKILL
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
**USE RuVector V2 SQL for ALL indexed projects (400x FASTER than grep):**
|
|
6
|
+
```bash
|
|
7
|
+
# Exact name lookup - 0.002s vs grep's 0.8s
|
|
8
|
+
sqlite3 ~/.local/share/ruvector/index_v2.db "SELECT file_path, line_number FROM entities WHERE name = 'MyFunction';"
|
|
9
|
+
|
|
10
|
+
# Fuzzy search - 0.004s
|
|
11
|
+
sqlite3 ~/.local/share/ruvector/index_v2.db "SELECT file_path, line_number FROM entities WHERE name LIKE '%Store%' LIMIT 10;"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**USE grep/rg ONLY when:**
|
|
15
|
+
- Project is NOT indexed yet
|
|
16
|
+
- Searching for strings that aren't code entities (error messages, comments, config values)
|
|
17
|
+
- Quick one-off search in small directory
|
|
18
|
+
|
|
19
|
+
**USE RuVector semantic search when:**
|
|
20
|
+
- "Where is authentication implemented?" (conceptual search)
|
|
21
|
+
- Finding similar patterns you can't name exactly
|
|
22
|
+
- Discovering how a feature is built
|
|
23
|
+
|
|
24
|
+
## Quick Commands
|
|
25
|
+
|
|
26
|
+
### Semantic Search (V1 - Embeddings)
|
|
27
|
+
```bash
|
|
28
|
+
# Natural language search
|
|
29
|
+
/codebase-search "authentication middleware pattern"
|
|
30
|
+
/cfn-ruvector-search "error handling in API routes"
|
|
31
|
+
|
|
32
|
+
# CLI direct
|
|
33
|
+
./.claude/skills/cfn-local-ruvector-accelerator/target/release/local-ruvector query --pattern "user login flow"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Structural Search (V2 - SQL on AST)
|
|
37
|
+
```bash
|
|
38
|
+
# Find all callers of a function
|
|
39
|
+
sqlite3 ~/.local/share/ruvector/index_v2.db \
|
|
40
|
+
"SELECT * FROM refs WHERE target_name = 'MyFunction';"
|
|
41
|
+
|
|
42
|
+
# Find all functions in a file
|
|
43
|
+
sqlite3 ~/.local/share/ruvector/index_v2.db \
|
|
44
|
+
"SELECT name, line_number FROM entities WHERE file_path LIKE '%myfile.rs' AND kind = 'function';"
|
|
45
|
+
|
|
46
|
+
# Find entities by project (multi-project isolation)
|
|
47
|
+
sqlite3 ~/.local/share/ruvector/index_v2.db \
|
|
48
|
+
"SELECT COUNT(*) FROM entities WHERE project_root = '/path/to/project';"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Index Management
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Index a project (first time or full rebuild)
|
|
55
|
+
./target/release/local-ruvector index --path /path/to/project --types rs,ts,py
|
|
56
|
+
|
|
57
|
+
# Incremental update (after code changes)
|
|
58
|
+
/codebase-reindex
|
|
59
|
+
|
|
60
|
+
# Check index stats
|
|
61
|
+
sqlite3 ~/.local/share/ruvector/index_v2.db "SELECT project_root, COUNT(*) FROM entities GROUP BY project_root;"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Key Features
|
|
65
|
+
|
|
66
|
+
- **Multi-project isolation**: Index multiple projects in single database without data collision
|
|
67
|
+
- **Non-destructive**: Indexing one project never deletes data from other projects
|
|
68
|
+
- **Centralized storage**: `~/.local/share/ruvector/index_v2.db`
|
|
69
|
+
- **Dual search**: V1 semantic (embeddings) + V2 structural (SQL on AST)
|
|
70
|
+
- **Fast**: Rust binary with SQLite backend
|
|
71
|
+
|
|
72
|
+
## Database Location
|
|
73
|
+
```
|
|
74
|
+
~/.local/share/ruvector/index_v2.db
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## For Agents
|
|
78
|
+
|
|
79
|
+
Before implementing changes, ALWAYS query RuVector first:
|
|
80
|
+
```bash
|
|
81
|
+
# Find similar patterns
|
|
82
|
+
/codebase-search "relevant search terms" --top 5
|
|
83
|
+
|
|
84
|
+
# Query past errors
|
|
85
|
+
./.claude/skills/cfn-ruvector-codebase-index/query-error-patterns.sh --task-description "description"
|
|
86
|
+
|
|
87
|
+
# Query learnings
|
|
88
|
+
./.claude/skills/cfn-ruvector-codebase-index/query-learnings.sh --task-description "description" --category PATTERN
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
This prevents duplicated work and leverages existing solutions.
|
|
@@ -432,14 +432,21 @@ impl IndexCommand {
|
|
|
432
432
|
) -> Result<()> {
|
|
433
433
|
let file_hash = self.calculate_file_hash(file_path)?;
|
|
434
434
|
|
|
435
|
+
// Check if file is already indexed with same hash (incremental indexing)
|
|
435
436
|
if !self.force && self.is_file_indexed(file_path, &file_hash)? {
|
|
436
|
-
debug!("Skipping already indexed file: {}", file_path.display());
|
|
437
|
+
debug!("Skipping already indexed file (unchanged): {}", file_path.display());
|
|
437
438
|
return Ok(());
|
|
438
439
|
}
|
|
439
440
|
|
|
440
|
-
//
|
|
441
|
+
// Non-destructive update: Only delete entities for THIS specific file
|
|
442
|
+
// The delete_file_entities already scopes to project_root for multi-project safety
|
|
441
443
|
let file_path_str = file_path.to_string_lossy();
|
|
442
|
-
|
|
444
|
+
|
|
445
|
+
// Only clean up if the file was previously indexed (avoid unnecessary DB operations)
|
|
446
|
+
if self.is_file_in_index(file_path)? {
|
|
447
|
+
debug!("Updating existing file entries: {}", file_path.display());
|
|
448
|
+
self.store_v2.delete_file_entities(&file_path_str, &self.project_dir)?;
|
|
449
|
+
}
|
|
443
450
|
|
|
444
451
|
let content = fs::read_to_string(file_path)
|
|
445
452
|
.with_context(|| format!("Failed to read file: {}", file_path.display()))?;
|
|
@@ -470,7 +477,7 @@ impl IndexCommand {
|
|
|
470
477
|
s.embeddings_generated += embeddings.len();
|
|
471
478
|
}
|
|
472
479
|
|
|
473
|
-
self.mark_file_indexed(file_path, &file_hash)?;
|
|
480
|
+
self.mark_file_indexed(file_path, &file_hash, extraction_result.entities.len())?;
|
|
474
481
|
|
|
475
482
|
Ok(())
|
|
476
483
|
}
|
|
@@ -539,6 +546,7 @@ impl IndexCommand {
|
|
|
539
546
|
doc_comment: None,
|
|
540
547
|
attributes: None,
|
|
541
548
|
metadata: Some(serde_json::to_string(&entity.metadata)?),
|
|
549
|
+
project_root: project_root_str.to_string(),
|
|
542
550
|
created_at: chrono::Utc::now(),
|
|
543
551
|
updated_at: chrono::Utc::now(),
|
|
544
552
|
};
|
|
@@ -654,15 +662,33 @@ impl IndexCommand {
|
|
|
654
662
|
Ok(count > 0)
|
|
655
663
|
}
|
|
656
664
|
|
|
657
|
-
|
|
665
|
+
/// Check if file exists in the index (regardless of hash)
|
|
666
|
+
fn is_file_in_index(&self, file_path: &Path) -> Result<bool> {
|
|
667
|
+
let query = "SELECT COUNT(*) FROM file_hashes WHERE file_path = ?";
|
|
668
|
+
let mut stmt = self.store_v2.conn.prepare(query)?;
|
|
669
|
+
let count: i64 = stmt.query_row(
|
|
670
|
+
params![file_path.to_string_lossy()],
|
|
671
|
+
|row| row.get(0)
|
|
672
|
+
)?;
|
|
673
|
+
Ok(count > 0)
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
fn mark_file_indexed(&self, file_path: &Path, file_hash: &str, patterns_count: usize) -> Result<()> {
|
|
677
|
+
let timestamp = chrono::Utc::now().timestamp();
|
|
678
|
+
let file_path_str = file_path.to_string_lossy().to_string();
|
|
679
|
+
|
|
680
|
+
// Update file_hashes table (for incremental indexing)
|
|
658
681
|
self.store_v2.conn.execute(
|
|
659
682
|
"INSERT OR REPLACE INTO file_hashes (file_path, file_hash, indexed_at) VALUES (?1, ?2, ?3)",
|
|
660
|
-
params![
|
|
661
|
-
file_path.to_string_lossy(),
|
|
662
|
-
file_hash,
|
|
663
|
-
chrono::Utc::now().timestamp()
|
|
664
|
-
]
|
|
683
|
+
params![&file_path_str, file_hash, timestamp]
|
|
665
684
|
)?;
|
|
685
|
+
|
|
686
|
+
// Also update the files table (for legacy compatibility and stats)
|
|
687
|
+
self.store_v2.conn.execute(
|
|
688
|
+
"INSERT OR REPLACE INTO files (path, hash, last_indexed, patterns_count) VALUES (?1, ?2, ?3, ?4)",
|
|
689
|
+
params![&file_path_str, file_hash, timestamp, patterns_count as i64]
|
|
690
|
+
)?;
|
|
691
|
+
|
|
666
692
|
Ok(())
|
|
667
693
|
}
|
|
668
694
|
|
|
@@ -299,6 +299,7 @@ impl AstIndexCommand {
|
|
|
299
299
|
let mut entity_map = HashMap::new();
|
|
300
300
|
let mut type_usages = Vec::new();
|
|
301
301
|
|
|
302
|
+
let project_root_str = self.project_dir.to_string_lossy().to_string();
|
|
302
303
|
for (idx, entity) in extraction_result.entities.iter().enumerate() {
|
|
303
304
|
let store_entity = StoreEntity {
|
|
304
305
|
id: 0,
|
|
@@ -313,6 +314,7 @@ impl AstIndexCommand {
|
|
|
313
314
|
doc_comment: None, // TODO: Extract doc comments
|
|
314
315
|
attributes: None, // TODO: Extract attributes
|
|
315
316
|
metadata: Some(serde_json::to_string(&entity.metadata)?),
|
|
317
|
+
project_root: project_root_str.clone(),
|
|
316
318
|
created_at: chrono::Utc::now(),
|
|
317
319
|
updated_at: chrono::Utc::now(),
|
|
318
320
|
};
|
|
@@ -613,6 +615,7 @@ impl AstIndexCommand {
|
|
|
613
615
|
Ok(entity.id)
|
|
614
616
|
} else {
|
|
615
617
|
// Create a placeholder entity for unknown references
|
|
618
|
+
let project_root_str = self.project_dir.to_string_lossy().to_string();
|
|
616
619
|
let placeholder = StoreEntity {
|
|
617
620
|
id: 0,
|
|
618
621
|
kind: EntityKind::Function,
|
|
@@ -626,11 +629,11 @@ impl AstIndexCommand {
|
|
|
626
629
|
doc_comment: None,
|
|
627
630
|
attributes: None,
|
|
628
631
|
metadata: None,
|
|
632
|
+
project_root: project_root_str.clone(),
|
|
629
633
|
created_at: chrono::Utc::now(),
|
|
630
634
|
updated_at: chrono::Utc::now(),
|
|
631
635
|
};
|
|
632
636
|
|
|
633
|
-
let project_root_str = self.project_dir.to_string_lossy();
|
|
634
637
|
Ok(self.store_v2.insert_entity(&placeholder, &project_root_str)?)
|
|
635
638
|
}
|
|
636
639
|
}
|
|
@@ -28,7 +28,7 @@ pub fn create_text_fallback_extractor() -> Result<text_fallback::TextFallbackExt
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/// Common entity kinds across languages
|
|
31
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
31
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
32
32
|
pub enum EntityKind {
|
|
33
33
|
// Functions
|
|
34
34
|
Function,
|
|
@@ -359,21 +359,21 @@ mod tests {
|
|
|
359
359
|
|
|
360
360
|
SchemaV2::initialize(&conn)?;
|
|
361
361
|
|
|
362
|
-
// Insert test entities with
|
|
362
|
+
// Insert test entities with project_root set (schema now requires it)
|
|
363
363
|
conn.execute(
|
|
364
|
-
"INSERT INTO entities (kind, name, file_path, line_number) VALUES (?, ?, ?, ?)",
|
|
365
|
-
params!["struct", "Test1", "/home/user/project/src/main.rs", 10]
|
|
364
|
+
"INSERT INTO entities (kind, name, file_path, line_number, project_root) VALUES (?, ?, ?, ?, ?)",
|
|
365
|
+
params!["struct", "Test1", "/home/user/project/src/main.rs", 10, "/home/user/project"]
|
|
366
366
|
)?;
|
|
367
367
|
|
|
368
368
|
conn.execute(
|
|
369
|
-
"INSERT INTO entities (kind, name, file_path, line_number) VALUES (?, ?, ?, ?)",
|
|
370
|
-
params!["function", "Test2", "/var/app/lib/utils.rs", 20]
|
|
369
|
+
"INSERT INTO entities (kind, name, file_path, line_number, project_root) VALUES (?, ?, ?, ?, ?)",
|
|
370
|
+
params!["function", "Test2", "/var/app/lib/utils.rs", 20, "/var/app"]
|
|
371
371
|
)?;
|
|
372
372
|
|
|
373
|
-
// Run migration
|
|
373
|
+
// Run migration (will be skipped since schema already has project_root)
|
|
374
374
|
MigrationV2::run_v2_migration(&mut conn)?;
|
|
375
375
|
|
|
376
|
-
// Verify project_root
|
|
376
|
+
// Verify project_root values
|
|
377
377
|
let project1: String = conn.query_row(
|
|
378
378
|
"SELECT project_root FROM entities WHERE name = ?",
|
|
379
379
|
params!["Test1"],
|
|
@@ -310,14 +310,15 @@ impl QueryApi {
|
|
|
310
310
|
row.get::<_, Option<String>>(9)?, // doc_comment
|
|
311
311
|
row.get::<_, Option<String>>(10)?, // attributes
|
|
312
312
|
row.get::<_, Option<String>>(11)?, // metadata
|
|
313
|
-
row.get::<_,
|
|
314
|
-
row.get::<_, i64>(13)?, //
|
|
313
|
+
row.get::<_, String>(12)?, // project_root
|
|
314
|
+
row.get::<_, i64>(13)?, // created_at
|
|
315
|
+
row.get::<_, i64>(14)?, // updated_at
|
|
315
316
|
))
|
|
316
317
|
})?;
|
|
317
318
|
|
|
318
319
|
for row in rows {
|
|
319
320
|
let row = row?;
|
|
320
|
-
let (id, kind_str, name, signature, visibility_str, parent_id, file_path, line_number, column_number, doc_comment, attributes, metadata, created_at, updated_at) = row;
|
|
321
|
+
let (id, kind_str, name, signature, visibility_str, parent_id, file_path, line_number, column_number, doc_comment, attributes, metadata, project_root, created_at, updated_at) = row;
|
|
321
322
|
// For now, just create a simple entity - the full parsing can be done later
|
|
322
323
|
// This is just to get the IDs for reference finding
|
|
323
324
|
matching_entities.push(crate::store_v2::Entity {
|
|
@@ -333,6 +334,7 @@ impl QueryApi {
|
|
|
333
334
|
doc_comment,
|
|
334
335
|
attributes,
|
|
335
336
|
metadata,
|
|
337
|
+
project_root,
|
|
336
338
|
created_at: chrono::DateTime::from_timestamp(created_at, 0).unwrap_or_default(),
|
|
337
339
|
updated_at: chrono::DateTime::from_timestamp(updated_at, 0).unwrap_or_default(),
|
|
338
340
|
});
|
|
@@ -366,6 +368,7 @@ impl QueryApi {
|
|
|
366
368
|
doc_comment: None,
|
|
367
369
|
attributes: None,
|
|
368
370
|
metadata: None,
|
|
371
|
+
project_root: "".to_string(),
|
|
369
372
|
created_at: chrono::DateTime::from_timestamp(0, 0).unwrap_or_default(),
|
|
370
373
|
updated_at: chrono::DateTime::from_timestamp(0, 0).unwrap_or_default(),
|
|
371
374
|
};
|
|
@@ -226,9 +226,10 @@ impl SchemaV2 {
|
|
|
226
226
|
doc_comment TEXT,
|
|
227
227
|
attributes TEXT,
|
|
228
228
|
metadata TEXT,
|
|
229
|
+
project_root TEXT NOT NULL DEFAULT '',
|
|
229
230
|
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
|
|
230
231
|
updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
|
|
231
|
-
|
|
232
|
+
|
|
232
233
|
FOREIGN KEY (parent_id) REFERENCES entities(id) ON DELETE RESTRICT
|
|
233
234
|
);
|
|
234
235
|
|
|
@@ -282,6 +283,14 @@ impl SchemaV2 {
|
|
|
282
283
|
|
|
283
284
|
FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE RESTRICT
|
|
284
285
|
);
|
|
286
|
+
|
|
287
|
+
-- Create files table for tracking indexed files (stats and legacy compatibility)
|
|
288
|
+
CREATE TABLE IF NOT EXISTS files (
|
|
289
|
+
path TEXT PRIMARY KEY,
|
|
290
|
+
hash TEXT NOT NULL,
|
|
291
|
+
last_indexed INTEGER NOT NULL,
|
|
292
|
+
patterns_count INTEGER NOT NULL DEFAULT 0
|
|
293
|
+
);
|
|
285
294
|
"#
|
|
286
295
|
)?;
|
|
287
296
|
|
|
@@ -311,6 +320,8 @@ impl SchemaV2 {
|
|
|
311
320
|
CREATE INDEX IF NOT EXISTS idx_entities_kind_name ON entities(kind, name);
|
|
312
321
|
CREATE INDEX IF NOT EXISTS idx_entities_file_kind ON entities(file_path, kind);
|
|
313
322
|
CREATE INDEX IF NOT EXISTS idx_entities_parent_kind ON entities(parent_id, kind);
|
|
323
|
+
CREATE INDEX IF NOT EXISTS idx_entities_project_root ON entities(project_root);
|
|
324
|
+
CREATE INDEX IF NOT EXISTS idx_entities_project_file ON entities(project_root, file_path);
|
|
314
325
|
|
|
315
326
|
-- Reference indexes
|
|
316
327
|
CREATE INDEX IF NOT EXISTS idx_refs_source ON refs(source_entity_id);
|
|
@@ -338,6 +349,10 @@ impl SchemaV2 {
|
|
|
338
349
|
|
|
339
350
|
-- Entity-module relationship index (via file path)
|
|
340
351
|
CREATE INDEX IF NOT EXISTS idx_entities_module_lookup ON entities(file_path);
|
|
352
|
+
|
|
353
|
+
-- Files table indexes
|
|
354
|
+
CREATE INDEX IF NOT EXISTS idx_files_hash ON files(hash);
|
|
355
|
+
CREATE INDEX IF NOT EXISTS idx_files_last_indexed ON files(last_indexed);
|
|
341
356
|
"#
|
|
342
357
|
)?;
|
|
343
358
|
|
|
@@ -23,6 +23,7 @@ pub struct Entity {
|
|
|
23
23
|
pub doc_comment: Option<String>,
|
|
24
24
|
pub attributes: Option<String>,
|
|
25
25
|
pub metadata: Option<String>,
|
|
26
|
+
pub project_root: String,
|
|
26
27
|
pub created_at: DateTime<Utc>,
|
|
27
28
|
pub updated_at: DateTime<Utc>,
|
|
28
29
|
}
|
|
@@ -558,8 +559,9 @@ impl StoreV2 {
|
|
|
558
559
|
|
|
559
560
|
// Helper methods to convert rows to structs
|
|
560
561
|
pub(crate) fn row_to_entity(&self, row: &Row) -> rusqlite::Result<Entity> {
|
|
561
|
-
let
|
|
562
|
-
let
|
|
562
|
+
let project_root: String = row.get(12)?;
|
|
563
|
+
let created_timestamp: i64 = row.get(13)?;
|
|
564
|
+
let updated_timestamp: i64 = row.get(14)?;
|
|
563
565
|
|
|
564
566
|
let kind_str = row.get::<_, String>(1)?;
|
|
565
567
|
let kind = EntityKind::from_str(&kind_str)
|
|
@@ -582,6 +584,7 @@ impl StoreV2 {
|
|
|
582
584
|
doc_comment: row.get(9)?,
|
|
583
585
|
attributes: row.get(10)?,
|
|
584
586
|
metadata: row.get(11)?,
|
|
587
|
+
project_root,
|
|
585
588
|
created_at: DateTime::from_timestamp(created_timestamp, 0).unwrap_or_default(),
|
|
586
589
|
updated_at: DateTime::from_timestamp(updated_timestamp, 0).unwrap_or_default(),
|
|
587
590
|
})
|
|
@@ -664,11 +667,12 @@ mod tests {
|
|
|
664
667
|
doc_comment: Some("Test function".to_string()),
|
|
665
668
|
attributes: None,
|
|
666
669
|
metadata: None,
|
|
670
|
+
project_root: "/test/project".to_string(),
|
|
667
671
|
created_at: Utc::now(),
|
|
668
672
|
updated_at: Utc::now(),
|
|
669
673
|
};
|
|
670
674
|
|
|
671
|
-
let entity_id = store.insert_entity(&entity)?;
|
|
675
|
+
let entity_id = store.insert_entity(&entity, "/test/project")?;
|
|
672
676
|
assert!(entity_id > 0);
|
|
673
677
|
|
|
674
678
|
// Retrieve entity
|
|
@@ -225,10 +225,11 @@ impl StoreV2WithTx {
|
|
|
225
225
|
// Execute the callback
|
|
226
226
|
f(&tx)?;
|
|
227
227
|
|
|
228
|
-
// Record file hash
|
|
228
|
+
// Record file hash with current timestamp
|
|
229
|
+
let current_time = chrono::Utc::now().timestamp();
|
|
229
230
|
tx.execute(
|
|
230
|
-
"INSERT INTO file_hashes (file_path, file_hash) VALUES (?, ?)",
|
|
231
|
-
params![file_path, file_hash],
|
|
231
|
+
"INSERT INTO file_hashes (file_path, file_hash, indexed_at) VALUES (?, ?, ?)",
|
|
232
|
+
params![file_path, file_hash, current_time],
|
|
232
233
|
)?;
|
|
233
234
|
|
|
234
235
|
tx.commit()
|
|
@@ -308,6 +309,7 @@ mod tests {
|
|
|
308
309
|
doc_comment: None,
|
|
309
310
|
attributes: None,
|
|
310
311
|
metadata: None,
|
|
312
|
+
project_root: "/test/project".to_string(),
|
|
311
313
|
created_at: Utc::now(),
|
|
312
314
|
updated_at: Utc::now(),
|
|
313
315
|
}).collect();
|
|
@@ -44,6 +44,7 @@ fn test_atomic_file_indexing_with_rollback() -> Result<()> {
|
|
|
44
44
|
doc_comment: None,
|
|
45
45
|
attributes: None,
|
|
46
46
|
metadata: None,
|
|
47
|
+
project_root: "/test/project".to_string(),
|
|
47
48
|
created_at: chrono::Utc::now(),
|
|
48
49
|
updated_at: chrono::Utc::now(),
|
|
49
50
|
};
|
|
@@ -67,6 +68,7 @@ fn test_atomic_file_indexing_with_rollback() -> Result<()> {
|
|
|
67
68
|
doc_comment: None,
|
|
68
69
|
attributes: None,
|
|
69
70
|
metadata: None,
|
|
71
|
+
project_root: "/test/project".to_string(),
|
|
70
72
|
created_at: chrono::Utc::now(),
|
|
71
73
|
updated_at: chrono::Utc::now(),
|
|
72
74
|
};
|
|
@@ -84,6 +86,7 @@ fn test_atomic_file_indexing_with_rollback() -> Result<()> {
|
|
|
84
86
|
doc_comment: None,
|
|
85
87
|
attributes: None,
|
|
86
88
|
metadata: None,
|
|
89
|
+
project_root: "/test/project".to_string(),
|
|
87
90
|
created_at: chrono::Utc::now(),
|
|
88
91
|
updated_at: chrono::Utc::now(),
|
|
89
92
|
};
|
|
@@ -92,8 +95,8 @@ fn test_atomic_file_indexing_with_rollback() -> Result<()> {
|
|
|
92
95
|
r#"
|
|
93
96
|
INSERT INTO entities (
|
|
94
97
|
kind, name, signature, visibility, parent_id, file_path,
|
|
95
|
-
line_number, column_number, doc_comment, attributes, metadata
|
|
96
|
-
) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)
|
|
98
|
+
line_number, column_number, doc_comment, attributes, metadata, project_root
|
|
99
|
+
) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)
|
|
97
100
|
"#
|
|
98
101
|
)?;
|
|
99
102
|
|
|
@@ -109,6 +112,7 @@ fn test_atomic_file_indexing_with_rollback() -> Result<()> {
|
|
|
109
112
|
entity1.doc_comment,
|
|
110
113
|
entity1.attributes,
|
|
111
114
|
entity1.metadata,
|
|
115
|
+
entity1.project_root,
|
|
112
116
|
])?;
|
|
113
117
|
|
|
114
118
|
stmt.execute(params![
|
|
@@ -123,6 +127,7 @@ fn test_atomic_file_indexing_with_rollback() -> Result<()> {
|
|
|
123
127
|
entity2.doc_comment,
|
|
124
128
|
entity2.attributes,
|
|
125
129
|
entity2.metadata,
|
|
130
|
+
entity2.project_root,
|
|
126
131
|
])?;
|
|
127
132
|
|
|
128
133
|
Ok(())
|
|
@@ -220,6 +225,7 @@ fn test_batch_insert_rollback() -> Result<()> {
|
|
|
220
225
|
doc_comment: None,
|
|
221
226
|
attributes: None,
|
|
222
227
|
metadata: None,
|
|
228
|
+
project_root: "/test/project".to_string(),
|
|
223
229
|
created_at: chrono::Utc::now(),
|
|
224
230
|
updated_at: chrono::Utc::now(),
|
|
225
231
|
});
|
package/CLAUDE.md
CHANGED
|
@@ -24,7 +24,8 @@ Purpose: concise reference for CFN agents. Focus on persona, mandatory rules, ed
|
|
|
24
24
|
- Do not run tests inside agents; run once via coordinator/main chat, agents read results.
|
|
25
25
|
- Never save to project root; use appropriate subdirectories.
|
|
26
26
|
- Never hardcode secrets; always redact as `[REDACTED]`.
|
|
27
|
-
-
|
|
27
|
+
- Use RuVector SQL for indexed projects (400x faster than grep); use grep only for non-indexed projects or non-code strings.
|
|
28
|
+
- When monitoring, sleep-check-sleep loops.
|
|
28
29
|
- All agent communication must use coordination protocols; no ad-hoc file coordination.
|
|
29
30
|
|
|
30
31
|
## 3) Cerebras MCP & Context Discovery Protocols
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow-novice",
|
|
3
|
-
"version": "2.18.
|
|
3
|
+
"version": "2.18.17",
|
|
4
4
|
"description": "Claude Flow Novice - Advanced orchestration platform for multi-agent AI workflows with CFN Loop architecture\n\nIncludes Local RuVector Accelerator and all CFN skills for complete functionality.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|