@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.
- package/README.md +107 -0
- package/dist/index.d.ts +115 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +715 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +492 -0
- package/dist/parsers/__fixtures__/arrow-functions.d.ts +5 -0
- package/dist/parsers/__fixtures__/arrow-functions.d.ts.map +1 -0
- package/dist/parsers/__fixtures__/arrow-functions.js +16 -0
- package/dist/parsers/__fixtures__/class-methods.d.ts +6 -0
- package/dist/parsers/__fixtures__/class-methods.d.ts.map +1 -0
- package/dist/parsers/__fixtures__/class-methods.js +12 -0
- package/dist/parsers/__fixtures__/no-functions.d.ts +9 -0
- package/dist/parsers/__fixtures__/no-functions.d.ts.map +1 -0
- package/dist/parsers/__fixtures__/no-functions.js +4 -0
- package/dist/parsers/index.d.ts +3 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +18 -0
- package/dist/parsers/python.d.ts +8 -0
- package/dist/parsers/python.d.ts.map +1 -0
- package/dist/parsers/python.js +137 -0
- package/dist/parsers/python.test.d.ts +2 -0
- package/dist/parsers/python.test.d.ts.map +1 -0
- package/dist/parsers/python.test.js +96 -0
- package/dist/parsers/registry.d.ts +8 -0
- package/dist/parsers/registry.d.ts.map +1 -0
- package/dist/parsers/registry.js +68 -0
- package/dist/parsers/types.d.ts +10 -0
- package/dist/parsers/types.d.ts.map +1 -0
- package/dist/parsers/types.js +18 -0
- package/dist/parsers/typescript.d.ts +8 -0
- package/dist/parsers/typescript.d.ts.map +1 -0
- package/dist/parsers/typescript.js +110 -0
- package/dist/parsers/typescript.test.d.ts +2 -0
- package/dist/parsers/typescript.test.d.ts.map +1 -0
- package/dist/parsers/typescript.test.js +106 -0
- package/dist/schemas.d.ts +100 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +128 -0
- package/dist/shared.d.ts +12 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +10 -0
- package/dist/test-utils.d.ts +46 -0
- package/dist/test-utils.d.ts.map +1 -0
- package/dist/test-utils.js +141 -0
- 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
|
package/dist/index.d.ts
ADDED
|
@@ -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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"}
|