@ophan/core 0.0.1

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.
Files changed (47) hide show
  1. package/README.md +107 -0
  2. package/dist/index.d.ts +115 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +715 -0
  5. package/dist/index.test.d.ts +2 -0
  6. package/dist/index.test.d.ts.map +1 -0
  7. package/dist/index.test.js +492 -0
  8. package/dist/parsers/__fixtures__/arrow-functions.d.ts +5 -0
  9. package/dist/parsers/__fixtures__/arrow-functions.d.ts.map +1 -0
  10. package/dist/parsers/__fixtures__/arrow-functions.js +16 -0
  11. package/dist/parsers/__fixtures__/class-methods.d.ts +6 -0
  12. package/dist/parsers/__fixtures__/class-methods.d.ts.map +1 -0
  13. package/dist/parsers/__fixtures__/class-methods.js +12 -0
  14. package/dist/parsers/__fixtures__/no-functions.d.ts +9 -0
  15. package/dist/parsers/__fixtures__/no-functions.d.ts.map +1 -0
  16. package/dist/parsers/__fixtures__/no-functions.js +4 -0
  17. package/dist/parsers/index.d.ts +3 -0
  18. package/dist/parsers/index.d.ts.map +1 -0
  19. package/dist/parsers/index.js +18 -0
  20. package/dist/parsers/python.d.ts +8 -0
  21. package/dist/parsers/python.d.ts.map +1 -0
  22. package/dist/parsers/python.js +137 -0
  23. package/dist/parsers/python.test.d.ts +2 -0
  24. package/dist/parsers/python.test.d.ts.map +1 -0
  25. package/dist/parsers/python.test.js +96 -0
  26. package/dist/parsers/registry.d.ts +8 -0
  27. package/dist/parsers/registry.d.ts.map +1 -0
  28. package/dist/parsers/registry.js +68 -0
  29. package/dist/parsers/types.d.ts +10 -0
  30. package/dist/parsers/types.d.ts.map +1 -0
  31. package/dist/parsers/types.js +18 -0
  32. package/dist/parsers/typescript.d.ts +8 -0
  33. package/dist/parsers/typescript.d.ts.map +1 -0
  34. package/dist/parsers/typescript.js +110 -0
  35. package/dist/parsers/typescript.test.d.ts +2 -0
  36. package/dist/parsers/typescript.test.d.ts.map +1 -0
  37. package/dist/parsers/typescript.test.js +106 -0
  38. package/dist/schemas.d.ts +100 -0
  39. package/dist/schemas.d.ts.map +1 -0
  40. package/dist/schemas.js +128 -0
  41. package/dist/shared.d.ts +12 -0
  42. package/dist/shared.d.ts.map +1 -0
  43. package/dist/shared.js +10 -0
  44. package/dist/test-utils.d.ts +46 -0
  45. package/dist/test-utils.d.ts.map +1 -0
  46. package/dist/test-utils.js +141 -0
  47. package/package.json +37 -0
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # @ophan/core
2
+
3
+ Multi-language analysis engine combining language-native AST parsing with Claude-powered security analysis and documentation.
4
+
5
+ ## Capabilities
6
+
7
+ ### Static Analysis
8
+ - Function extraction via pluggable language parsers (`src/parsers/`)
9
+ - TypeScript/JavaScript: TypeScript compiler API
10
+ - Python: Python's own `ast` module via subprocess (zero npm deps)
11
+ - Content hashing (SHA256) for change detection and content-addressed storage
12
+ - AST traversal for control flow understanding
13
+
14
+ ### Content-Addressed Storage
15
+ Analysis is keyed by SHA256 of function source code:
16
+ - Same function on any branch = same hash = same analysis entry
17
+ - Skip analysis entirely when hash already exists in DB
18
+ - Insert-only sync — no conflict resolution needed
19
+ - Orphaned hashes accumulate harmlessly until manual `ophan gc` (30-day grace period, safe for branch switching)
20
+
21
+ ### Two-Table Schema
22
+ - `function_analysis` — `content_hash → analysis JSON, model_version, created_at, language, entity_type` (synced to cloud)
23
+ - `file_functions` — `file_path + function_name → content_hash, file_mtime, language, entity_type` (local only). No line numbers — resolved at runtime via LSP/parser.
24
+
25
+ ### Incremental Scanning
26
+ 1. Check `file_mtime` against stored value — skip unchanged files entirely (no parse)
27
+ 2. Re-parse changed files, extract functions, compute hashes
28
+ 3. Look up hash in `function_analysis` — skip if exists
29
+ 4. Only call Claude API for functions with new/unknown hashes
30
+ 5. Update `file_functions` with file path, function name, content_hash, mtime
31
+
32
+ ### AI Analysis
33
+ Leverages Claude to provide:
34
+ - Natural language function descriptions
35
+ - Parameter and return type documentation
36
+ - Security vulnerability identification
37
+ - Data flow classification
38
+
39
+ ### Security Detection
40
+ Identifies common vulnerabilities:
41
+ - SQL injection risks
42
+ - Cross-site scripting (XSS) potential
43
+ - Hardcoded secrets and credentials
44
+ - Unsanitized user input
45
+ - Path traversal vulnerabilities
46
+
47
+ ### Data Flow Tagging
48
+ Classifies functions by data they handle:
49
+ - `user_input` — Processes user-provided data
50
+ - `pii` — Handles personally identifiable information
51
+ - `credentials` — Works with authentication data
52
+ - `database` — Database read/write operations
53
+ - `external_api` — Makes external HTTP requests
54
+ - `file_system` — File I/O operations
55
+ - `config` — Configuration management
56
+ - `internal` — Internal system operations
57
+
58
+ ## Storage
59
+
60
+ SQLite database at `.ophan/index.db` (gitignored, per-repo). Designed for:
61
+ - Fast querying by content hash, file path, and line number
62
+ - Incremental updates (only new hashes trigger analysis)
63
+ - JSON storage for structured analysis results
64
+ - Branch-agnostic analysis with branch-specific location mappings
65
+
66
+ ## Multi-Language Architecture
67
+
68
+ ### Parser Interface (`src/parsers/`)
69
+
70
+ Function extraction is handled by pluggable, language-specific parsers. Each implements the `LanguageParser` interface:
71
+
72
+ ```typescript
73
+ interface LanguageParser {
74
+ language: string; // e.g. "typescript", "python"
75
+ extensions: string[]; // e.g. [".ts", ".tsx"]
76
+ extractFunctions(filePath: string): FunctionInfo[];
77
+ }
78
+ ```
79
+
80
+ **Current parsers:**
81
+ - **TypeScript/JavaScript** (`parsers/typescript.ts`): Uses the TypeScript compiler API. Handles `.ts`, `.tsx`, `.js`, `.jsx`.
82
+ - **Python** (`parsers/python.ts`): Shells out to `python3` with an inline `ast` module script. Handles `.py`. Gracefully skips if `python3` not installed.
83
+
84
+ **To add a new language** (e.g. Go, Java):
85
+ 1. Create `parsers/go.ts` implementing `LanguageParser`
86
+ 2. Register it in `parsers/index.ts`
87
+ 3. That's it — the glob pattern, analysis pipeline, DB storage, and sync all pick it up automatically
88
+
89
+ **Why no tree-sitter?** Each language uses its own native tooling (TS compiler, Python's ast, go/parser, etc.) rather than a universal parser framework. This avoids native C dependencies, grammar management, and adds zero npm packages per language.
90
+
91
+ ### Schema Fields
92
+
93
+ Both tables carry `language` and `entity_type` fields set at parse time:
94
+ - **`language`**: Derived from file extension (`.ts` → `"typescript"`, `.py` → `"python"`). Drives prompt template selection and language-specific security flags.
95
+ - **`entity_type`**: Derived from AST node kind (`isMethodDeclaration` → `"method"`, `FunctionDef` inside `ClassDef` → `"method"`). Enables class-level vs function-level analysis.
96
+
97
+ ### Migration Safety
98
+
99
+ Both tables use `DEFAULT 'typescript'` and `DEFAULT 'function'` for the new columns. Existing databases are migrated via `ALTER TABLE ADD COLUMN` on init — safe, no data loss.
100
+
101
+ ## Extensibility
102
+
103
+ Designed to support:
104
+ - Additional programming languages via parser interface (Go, Java, Rust planned)
105
+ - Alternative AI models (Bedrock for enterprise)
106
+ - Custom security rules
107
+ - Supabase sync for cloud features
@@ -0,0 +1,115 @@
1
+ import Database from "better-sqlite3";
2
+ export { FunctionInfo, computeHash } from "./shared";
3
+ export { getSupportedExtensions } from "./parsers";
4
+ export * from "./schemas";
5
+ import type { FunctionInfo } from "./shared";
6
+ /**
7
+ * Ensure .ophan/ is in .gitignore. Only acts in git repos.
8
+ * Creates .gitignore if the repo has .git/ but no .gitignore.
9
+ */
10
+ export declare function ensureGitignore(rootPath: string): void;
11
+ /**
12
+ * Discover source files using git (respects .gitignore) with glob fallback.
13
+ * Returns absolute paths filtered to supported extensions.
14
+ */
15
+ export declare function discoverFiles(rootPath: string): Promise<string[]>;
16
+ export interface AnalyzedFunction extends FunctionInfo {
17
+ description: string;
18
+ params: {
19
+ name: string;
20
+ type: string;
21
+ description: string;
22
+ }[];
23
+ returns: {
24
+ type: string;
25
+ description: string;
26
+ };
27
+ dataTags: string[];
28
+ securityFlags: string[];
29
+ }
30
+ export interface FunctionAnalysis {
31
+ description: string;
32
+ params: {
33
+ name: string;
34
+ type: string;
35
+ description: string;
36
+ }[];
37
+ returns: {
38
+ type: string;
39
+ description: string;
40
+ };
41
+ dataTags: string[];
42
+ securityFlags: string[];
43
+ }
44
+ export interface FileAnalysisEntry {
45
+ functionName: string;
46
+ contentHash: string;
47
+ analysis: FunctionAnalysis;
48
+ language: string;
49
+ entityType: string;
50
+ }
51
+ export declare function initDb(dbPath: string): Database.Database;
52
+ /**
53
+ * Migrate from single-blob function_analysis to split analysis types.
54
+ * Creates v2 table, splits each existing row into 'documentation' + 'security' rows,
55
+ * drops old table, renames. Sets synced_at = NULL to force full re-sync.
56
+ */
57
+ export declare function migrateToAnalysisTypes(db: Database.Database): void;
58
+ export declare function analyzeFunctions(functions: FunctionInfo[]): Promise<AnalyzedFunction[]>;
59
+ export interface AnalyzeFilesOptions {
60
+ pullFn?: (hashes: string[]) => Promise<void>;
61
+ onProgress?: (current: number, total: number, file: string) => void;
62
+ }
63
+ export interface AnalyzeFilesResult {
64
+ analyzed: number;
65
+ skipped: number;
66
+ pulled: number;
67
+ skippedSize: number;
68
+ }
69
+ /**
70
+ * Analyze a specific set of files: parse → hash → pull → Claude → store.
71
+ * Used by `analyzeRepository()` for full scans and `ophan watch` for incremental.
72
+ * The caller is responsible for DB lifecycle (open/close).
73
+ */
74
+ export declare function analyzeFiles(db: Database.Database, rootPath: string, files: string[], options?: AnalyzeFilesOptions): Promise<AnalyzeFilesResult>;
75
+ export declare function analyzeRepository(rootPath: string, onProgress?: (current: number, total: number, file: string) => void, pullFn?: (hashes: string[]) => Promise<void>): Promise<{
76
+ analyzed: number;
77
+ skipped: number;
78
+ pulled: number;
79
+ skippedSize: number;
80
+ files: number;
81
+ }>;
82
+ /**
83
+ * Merge documentation + security analysis rows for a content_hash into
84
+ * the unified FunctionAnalysis shape that consumers expect.
85
+ */
86
+ export declare function mergeAnalysisRows(rows: {
87
+ analysis_type: string;
88
+ analysis: string;
89
+ }[]): FunctionAnalysis;
90
+ export declare function getAnalysisForFile(dbPath: string, filePath: string): FileAnalysisEntry[];
91
+ export declare function getAnalysisByHash(dbPath: string, hash: string): FunctionAnalysis | null;
92
+ export declare function gcAnalysis(dbPath: string, maxAgeDays?: number): {
93
+ deleted: number;
94
+ };
95
+ export declare function refreshFileIndex(rootPath: string, onProgress?: (current: number, total: number, file: string) => void): Promise<void>;
96
+ /**
97
+ * Find content hashes that are referenced in file_functions but have no
98
+ * analysis in function_analysis. Used by CLI to know what to pull from Supabase
99
+ * before running expensive Claude analysis.
100
+ */
101
+ export declare function findMissingHashes(dbPath: string): string[];
102
+ /**
103
+ * Import analysis rows pulled from Supabase into the local SQLite database.
104
+ * Used by CLI pull sync to cache remote analysis locally.
105
+ */
106
+ export declare function importAnalysis(dbPath: string, rows: {
107
+ content_hash: string;
108
+ analysis_type: string;
109
+ analysis: string;
110
+ model_version: string;
111
+ schema_version: number;
112
+ language: string;
113
+ entity_type: string;
114
+ }[]): number;
115
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}