scai
Version:
> **AI-powered CLI for local code analysis, commit message suggestions, and natural-language queries.** 100% local, private, GDPR-friendly, made in Denmark/EU with ❤️.
161 lines (160 loc) • 4.85 kB
JavaScript
// --- Files ---
// Upsert file metadata into `files`
export const upsertFileTemplate = `
INSERT INTO files (path, filename, summary, type, last_modified, indexed_at)
VALUES (:path, :filename, :summary, :type, :lastModified, :indexedAt)
ON CONFLICT(path) DO UPDATE SET
filename = excluded.filename,
summary = CASE
WHEN excluded.summary IS NOT NULL AND excluded.summary != files.summary
THEN excluded.summary
ELSE files.summary
END,
type = excluded.type,
last_modified = excluded.last_modified,
indexed_at = excluded.indexed_at
`;
// Insert or replace into FTS
export const upsertFileFtsTemplate = `
INSERT OR REPLACE INTO files_fts (rowid, filename, summary, path, content_text)
VALUES ((SELECT id FROM files WHERE path = :path), :filename, :summary, :path, :contentText)
`;
// Simple file query (no scoring)
export const queryFilesTemplate = `
SELECT f.id, f.path, f.filename, f.summary, f.type, f.last_modified, f.indexed_at
FROM files f
JOIN files_fts fts ON f.id = fts.rowid
WHERE fts.files_fts MATCH ?
LIMIT ?
`;
// FTS search with bm25 scoring
export const searchFilesTemplate = `
SELECT fts.rowid AS id, f.path, f.filename, f.summary, f.type,
bm25(files_fts) AS bm25Score
FROM files f
JOIN files_fts fts ON f.id = fts.rowid
WHERE fts.files_fts MATCH ?
ORDER BY bm25Score ASC
LIMIT ?
`;
// --- Functions ---
export const insertFunctionTemplate = `
INSERT INTO functions (file_id, name, start_line, end_line, content, lang, unique_id)
VALUES (:file_id, :name, :start_line, :end_line, :content, :lang, :unique_id)
`;
// --- Graph ---
export const insertGraphClassTemplate = `
INSERT INTO graph_classes (file_id, name, start_line, end_line, content, lang)
VALUES (:file_id, :name, :start_line, :end_line, :content, :lang)
`;
export const insertEdgeTemplate = `
INSERT INTO graph_edges (
source_type,
source_unique_id,
target_type,
target_unique_id,
relation
)
VALUES (
:source_type,
:source_unique_id,
:target_type,
:target_unique_id,
:relation
)
`;
// --- New graph tag templates ---
export const insertGraphTagTemplate = `
INSERT OR IGNORE INTO graph_tags_master (name) VALUES (:name)
`;
export const selectGraphTagIdTemplate = `
SELECT id FROM graph_tags_master WHERE name = :name
`;
export const insertGraphEntityTagTemplate = `
INSERT INTO graph_entity_tags (
entity_type,
entity_unique_id,
tag_id
)
VALUES (
:entity_type,
:entity_unique_id,
:tag_id
)
ON CONFLICT(entity_type, entity_unique_id, tag_id) DO NOTHING
`;
// --- File Processing Status ---
/* processing_status values:
"unprocessed" → newly discovered, not yet indexed
"indexed" → content read and inserted into FTS
"capsuled" → folder capsule created
"extracted" → functions/classes extracted for knowledge graph
"kg_done" → knowledge graph updated
"skipped" → ignored (invalid, missing, or binary)
"failed" → could not be processed due to error
*/
export const markFileAsProcessedByPath = `
UPDATE files
SET processing_status = 'processed'
WHERE path = @path
`;
export const markFileAsIndexed = `
UPDATE files
SET processing_status = 'indexed',
indexed_at = datetime('now')
WHERE path = @path
`;
export const markFileAsCapsuled = `
UPDATE files
SET processing_status = 'capsulized'
WHERE path LIKE ?
`;
export const markFileAsKgDone = `
UPDATE files
SET processing_status = 'kg_done'
WHERE path = @path
`;
export const markFileAsExtractedTemplate = `
UPDATE files
SET processing_status = 'extracted',
functions_extracted_at = CURRENT_TIMESTAMP
WHERE id = :id
`;
export const markFileAsSkippedTemplate = `
UPDATE files
SET processing_status = 'skipped',
functions_extracted_at = NULL
WHERE id = :id
`;
export const markFileAsFailedTemplate = `
UPDATE files
SET processing_status = 'failed',
functions_extracted_at = NULL
WHERE id = :id
`;
export const selectUnprocessedFiles = `
SELECT id, path, type, content_text, indexed_at, last_modified, processing_status
FROM files
WHERE processing_status = 'unprocessed'
ORDER BY last_modified DESC
LIMIT ?
`;
export const markFileAsSkippedByPath = `
UPDATE files
SET processing_status = 'skipped',
functions_extracted_at = NULL
WHERE path = @path
`;
export const updateFileWithSummary = `
UPDATE files
SET summary = @summary,
content_text = @contentText,
indexed_at = datetime('now')
WHERE path = @path
`;
// --- File Processing Status Checks ---
export const countUnprocessedFiles = `
SELECT COUNT(*) as count
FROM files
WHERE processing_status = 'unprocessed'
`;