@ophan/core 0.0.2 → 0.0.4

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 (76) hide show
  1. package/dist/community-detectors/index.d.ts +20 -0
  2. package/dist/community-detectors/index.d.ts.map +1 -0
  3. package/dist/community-detectors/index.js +45 -0
  4. package/dist/community-detectors/label-prop.d.ts +20 -0
  5. package/dist/community-detectors/label-prop.d.ts.map +1 -0
  6. package/dist/community-detectors/label-prop.js +77 -0
  7. package/dist/community-detectors/leiden.d.ts +22 -0
  8. package/dist/community-detectors/leiden.d.ts.map +1 -0
  9. package/dist/community-detectors/leiden.js +312 -0
  10. package/dist/community-detectors/louvain.d.ts +13 -0
  11. package/dist/community-detectors/louvain.d.ts.map +1 -0
  12. package/dist/community-detectors/louvain.js +29 -0
  13. package/dist/community-detectors/types.d.ts +36 -0
  14. package/dist/community-detectors/types.d.ts.map +1 -0
  15. package/dist/{parsers/__fixtures__/no-functions.js → community-detectors/types.js} +0 -2
  16. package/dist/edge-resolvers/call.d.ts +13 -0
  17. package/dist/edge-resolvers/call.d.ts.map +1 -0
  18. package/dist/edge-resolvers/call.js +40 -0
  19. package/dist/edge-resolvers/co-location.d.ts +16 -0
  20. package/dist/edge-resolvers/co-location.d.ts.map +1 -0
  21. package/dist/edge-resolvers/co-location.js +129 -0
  22. package/dist/edge-resolvers/import.d.ts +16 -0
  23. package/dist/edge-resolvers/import.d.ts.map +1 -0
  24. package/dist/edge-resolvers/import.js +118 -0
  25. package/dist/edge-resolvers/index.d.ts +9 -0
  26. package/dist/edge-resolvers/index.d.ts.map +1 -0
  27. package/dist/edge-resolvers/index.js +29 -0
  28. package/dist/edge-resolvers/jsx-ref.d.ts +13 -0
  29. package/dist/edge-resolvers/jsx-ref.d.ts.map +1 -0
  30. package/dist/edge-resolvers/jsx-ref.js +40 -0
  31. package/dist/edge-resolvers/types.d.ts +40 -0
  32. package/dist/edge-resolvers/types.d.ts.map +1 -0
  33. package/dist/edge-resolvers/types.js +2 -0
  34. package/dist/graph.d.ts +293 -0
  35. package/dist/graph.d.ts.map +1 -0
  36. package/dist/graph.js +1295 -0
  37. package/dist/index.d.ts +37 -8
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +385 -183
  40. package/dist/migrations.d.ts +25 -0
  41. package/dist/migrations.d.ts.map +1 -0
  42. package/dist/migrations.js +323 -0
  43. package/dist/module-resolvers/index.d.ts +11 -0
  44. package/dist/module-resolvers/index.d.ts.map +1 -0
  45. package/dist/module-resolvers/index.js +67 -0
  46. package/dist/module-resolvers/javascript.d.ts +18 -0
  47. package/dist/module-resolvers/javascript.d.ts.map +1 -0
  48. package/dist/module-resolvers/javascript.js +130 -0
  49. package/dist/module-resolvers/types.d.ts +18 -0
  50. package/dist/module-resolvers/types.d.ts.map +1 -0
  51. package/dist/module-resolvers/types.js +2 -0
  52. package/dist/parsers/python.d.ts.map +1 -1
  53. package/dist/parsers/python.js +38 -4
  54. package/dist/parsers/typescript.d.ts.map +1 -1
  55. package/dist/parsers/typescript.js +133 -0
  56. package/dist/practices.d.ts +28 -0
  57. package/dist/practices.d.ts.map +1 -0
  58. package/dist/practices.js +95 -0
  59. package/dist/schemas.d.ts +251 -3
  60. package/dist/schemas.d.ts.map +1 -1
  61. package/dist/schemas.js +121 -6
  62. package/dist/shared.d.ts +8 -0
  63. package/dist/shared.d.ts.map +1 -1
  64. package/dist/summarize.d.ts +165 -0
  65. package/dist/summarize.d.ts.map +1 -0
  66. package/dist/summarize.js +1067 -0
  67. package/ophan_logo.png +0 -0
  68. package/package.json +9 -2
  69. package/dist/parsers/__fixtures__/arrow-functions.d.ts +0 -5
  70. package/dist/parsers/__fixtures__/arrow-functions.d.ts.map +0 -1
  71. package/dist/parsers/__fixtures__/arrow-functions.js +0 -16
  72. package/dist/parsers/__fixtures__/class-methods.d.ts +0 -6
  73. package/dist/parsers/__fixtures__/class-methods.d.ts.map +0 -1
  74. package/dist/parsers/__fixtures__/class-methods.js +0 -12
  75. package/dist/parsers/__fixtures__/no-functions.d.ts +0 -9
  76. package/dist/parsers/__fixtures__/no-functions.d.ts.map +0 -1
@@ -65,6 +65,28 @@ for node in ast.walk(tree):
65
65
  for child in ast.iter_child_nodes(node):
66
66
  child._parent = node
67
67
 
68
+ # Extract file-level imports
69
+ file_imports = []
70
+ for node in ast.iter_child_nodes(tree):
71
+ if isinstance(node, ast.Import):
72
+ for alias in node.names:
73
+ file_imports.append({"module": alias.name, "names": [alias.asname or alias.name]})
74
+ elif isinstance(node, ast.ImportFrom):
75
+ module = node.module or ""
76
+ names = [alias.name for alias in node.names]
77
+ file_imports.append({"module": module, "names": names})
78
+
79
+ # Extract call names from a function body
80
+ # Only direct function calls (ast.Name), not method calls (ast.Attribute)
81
+ # Method calls like obj.method() produce false matches against library APIs
82
+ def get_calls(func_node):
83
+ calls = set()
84
+ for node in ast.walk(func_node):
85
+ if isinstance(node, ast.Call):
86
+ if isinstance(node.func, ast.Name):
87
+ calls.add(node.func.id)
88
+ return sorted(calls)
89
+
68
90
  functions = []
69
91
  lines = source.split('\\n')
70
92
 
@@ -76,15 +98,20 @@ for node in ast.walk(tree):
76
98
  parent = getattr(node, '_parent', None)
77
99
  entity_type = "method" if isinstance(parent, ast.ClassDef) else "function"
78
100
 
101
+ # Module-level functions (not nested in class or other function) are "exported"
102
+ exported = isinstance(parent, ast.Module)
103
+
79
104
  functions.append({
80
105
  "name": node.name,
81
106
  "startLine": node.lineno,
82
107
  "endLine": end_line,
83
108
  "sourceCode": source_code,
84
- "entityType": entity_type
109
+ "entityType": entity_type,
110
+ "calls": get_calls(node),
111
+ "exported": exported
85
112
  })
86
113
 
87
- json.dump(functions, sys.stdout)
114
+ json.dump({"functions": functions, "imports": file_imports}, sys.stdout)
88
115
  `;
89
116
  let pythonAvailable = null;
90
117
  function isPythonAvailable() {
@@ -116,8 +143,12 @@ class PythonParser {
116
143
  encoding: "utf-8",
117
144
  timeout: 10000, // 10s timeout per file
118
145
  });
119
- const raw = JSON.parse(output);
120
- return raw.map((fn) => ({
146
+ const result = JSON.parse(output);
147
+ const fileImports = result.imports.map((imp) => ({
148
+ module: imp.module,
149
+ names: imp.names,
150
+ }));
151
+ return result.functions.map((fn) => ({
121
152
  name: fn.name,
122
153
  filePath,
123
154
  startLine: fn.startLine,
@@ -126,6 +157,9 @@ class PythonParser {
126
157
  contentHash: (0, shared_1.computeHash)(fn.sourceCode),
127
158
  language: "python",
128
159
  entityType: fn.entityType,
160
+ calls: fn.calls,
161
+ imports: fileImports,
162
+ exported: fn.exported,
129
163
  }));
130
164
  }
131
165
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"typescript.d.ts","sourceRoot":"","sources":["../../src/parsers/typescript.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAa9C,qBAAa,gBAAiB,YAAW,cAAc;IACrD,QAAQ,CAAC,QAAQ,gBAAgB;IACjC,QAAQ,CAAC,UAAU,WAAkC;IAErD,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE;CAyDnD"}
1
+ {"version":3,"file":"typescript.d.ts","sourceRoot":"","sources":["../../src/parsers/typescript.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAa,MAAM,WAAW,CAAC;AAEzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAa9C,qBAAa,gBAAiB,YAAW,cAAc;IACrD,QAAQ,CAAC,QAAQ,gBAAgB;IACjC,QAAQ,CAAC,UAAU,WAAkC;IAErD,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE;CAiEnD"}
@@ -67,6 +67,8 @@ class TypeScriptParser {
67
67
  const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
68
68
  const language = detectLanguage(filePath);
69
69
  const functions = [];
70
+ // Collect file-level imports (shared across all functions in this file)
71
+ const fileImports = extractImports(sourceFile);
70
72
  function visit(node) {
71
73
  if (ts.isFunctionDeclaration(node) ||
72
74
  ts.isMethodDeclaration(node) ||
@@ -78,6 +80,7 @@ class TypeScriptParser {
78
80
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
79
81
  const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
80
82
  const sourceCode = node.getText(sourceFile);
83
+ const { calls, jsxRefs } = extractCallExpressions(node, sourceFile);
81
84
  functions.push({
82
85
  name,
83
86
  filePath,
@@ -87,6 +90,10 @@ class TypeScriptParser {
87
90
  contentHash: (0, shared_1.computeHash)(sourceCode),
88
91
  language,
89
92
  entityType: detectEntityType(node),
93
+ calls,
94
+ jsxRefs: jsxRefs.length > 0 ? jsxRefs : undefined,
95
+ imports: fileImports,
96
+ exported: isExported(node),
90
97
  });
91
98
  }
92
99
  ts.forEachChild(node, visit);
@@ -108,3 +115,129 @@ class TypeScriptParser {
108
115
  }
109
116
  }
110
117
  exports.TypeScriptParser = TypeScriptParser;
118
+ // ============ RELATIONSHIP EXTRACTION ============
119
+ /**
120
+ * Extract call expression names and JSX component references from inside a function body.
121
+ * Returns separate arrays: `calls` for direct function calls (strong signal) and
122
+ * `jsxRefs` for JSX component references (weaker signal — UI composition, not domain logic).
123
+ */
124
+ function extractCallExpressions(node, sourceFile) {
125
+ const calls = new Set();
126
+ const jsxRefs = new Set();
127
+ function walkCalls(n) {
128
+ if (ts.isCallExpression(n)) {
129
+ const name = getCallName(n.expression, sourceFile);
130
+ if (name)
131
+ calls.add(name);
132
+ }
133
+ // JSX elements: <Foo /> treated as a component reference (separate from calls)
134
+ if (ts.isJsxOpeningElement(n) || ts.isJsxSelfClosingElement(n)) {
135
+ const tagName = n.tagName;
136
+ if (ts.isIdentifier(tagName)) {
137
+ const name = tagName.getText(sourceFile);
138
+ // Only PascalCase (React components), not HTML elements (div, span)
139
+ if (name[0] === name[0].toUpperCase() && name[0] !== name[0].toLowerCase()) {
140
+ jsxRefs.add(name);
141
+ }
142
+ }
143
+ }
144
+ ts.forEachChild(n, walkCalls);
145
+ }
146
+ // Walk the function body (not the signature)
147
+ const body = getFunctionBody(node);
148
+ if (body)
149
+ walkCalls(body);
150
+ return { calls: [...calls], jsxRefs: [...jsxRefs] };
151
+ }
152
+ function getCallName(expr, sourceFile) {
153
+ // Direct call: foo()
154
+ if (ts.isIdentifier(expr)) {
155
+ return expr.getText(sourceFile);
156
+ }
157
+ // Method calls (obj.method()) are excluded — they typically reference
158
+ // library APIs (db.prepare, res.json, arr.map) and produce false matches.
159
+ // Intra-project method calls are captured by co-location and import edges instead.
160
+ return null;
161
+ }
162
+ function getFunctionBody(node) {
163
+ if (ts.isFunctionDeclaration(node) ||
164
+ ts.isMethodDeclaration(node) ||
165
+ ts.isFunctionExpression(node)) {
166
+ return node.body || null;
167
+ }
168
+ if (ts.isArrowFunction(node)) {
169
+ return node.body;
170
+ }
171
+ return null;
172
+ }
173
+ /**
174
+ * Extract import declarations from the top level of a source file.
175
+ */
176
+ function extractImports(sourceFile) {
177
+ const imports = [];
178
+ for (const stmt of sourceFile.statements) {
179
+ if (!ts.isImportDeclaration(stmt))
180
+ continue;
181
+ const moduleSpec = stmt.moduleSpecifier;
182
+ if (!ts.isStringLiteral(moduleSpec))
183
+ continue;
184
+ const module = moduleSpec.text;
185
+ const names = [];
186
+ const clause = stmt.importClause;
187
+ if (clause) {
188
+ // Skip entire type-only imports: import type { X } from "..."
189
+ if (clause.isTypeOnly)
190
+ continue;
191
+ // Default import: import Foo from "..."
192
+ if (clause.name) {
193
+ names.push(clause.name.getText(sourceFile));
194
+ }
195
+ // Named imports: import { a, b } from "..."
196
+ if (clause.namedBindings) {
197
+ if (ts.isNamedImports(clause.namedBindings)) {
198
+ for (const el of clause.namedBindings.elements) {
199
+ // Skip individual type-only specifiers: import { type X, Y } from "..."
200
+ if (el.isTypeOnly)
201
+ continue;
202
+ names.push(el.name.getText(sourceFile));
203
+ }
204
+ }
205
+ // Namespace import: import * as ns from "..."
206
+ if (ts.isNamespaceImport(clause.namedBindings)) {
207
+ names.push(clause.namedBindings.name.getText(sourceFile));
208
+ }
209
+ }
210
+ }
211
+ imports.push({ module, names });
212
+ }
213
+ return imports;
214
+ }
215
+ /**
216
+ * Check if a function/variable declaration has the `export` modifier.
217
+ */
218
+ function isExported(node) {
219
+ // Function declarations: check modifiers directly
220
+ if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
221
+ return hasExportModifier(node);
222
+ }
223
+ // Arrow functions / function expressions: check parent variable statement
224
+ if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
225
+ const parent = node.parent; // VariableDeclaration
226
+ if (parent && ts.isVariableDeclaration(parent)) {
227
+ const declList = parent.parent; // VariableDeclarationList
228
+ if (declList && ts.isVariableDeclarationList(declList)) {
229
+ const varStmt = declList.parent; // VariableStatement
230
+ if (varStmt && ts.isVariableStatement(varStmt)) {
231
+ return hasExportModifier(varStmt);
232
+ }
233
+ }
234
+ }
235
+ }
236
+ return false;
237
+ }
238
+ function hasExportModifier(node) {
239
+ const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
240
+ if (!modifiers)
241
+ return false;
242
+ return modifiers.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
243
+ }
@@ -0,0 +1,28 @@
1
+ import type Database from "better-sqlite3";
2
+ import { MAX_PRACTICES, MAX_RULE_LENGTH } from "./schemas";
3
+ export interface Practice {
4
+ id: string;
5
+ rule: string;
6
+ severity: "error" | "warning" | "info";
7
+ }
8
+ export { MAX_PRACTICES, MAX_RULE_LENGTH };
9
+ /**
10
+ * Load practices from the local SQLite practices table.
11
+ * Returns [] if table is empty or doesn't exist.
12
+ */
13
+ export declare function loadPracticesFromDb(db: Database.Database): Practice[];
14
+ /**
15
+ * Import practices from Supabase into the local SQLite practices table.
16
+ * Replaces all existing practices (full sync).
17
+ */
18
+ export declare function importPractices(db: Database.Database, practices: Practice[]): void;
19
+ /**
20
+ * Validate practices array. Enforces limits and format.
21
+ * Returns the validated (possibly truncated) array.
22
+ */
23
+ export declare function validatePractices(practices: Practice[]): Practice[];
24
+ /**
25
+ * Build the prompt section for practices. Returns empty string if no practices.
26
+ */
27
+ export declare function buildPracticesPrompt(practices: Practice[]): string;
28
+ //# sourceMappingURL=practices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"practices.d.ts","sourceRoot":"","sources":["../src/practices.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE3D,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;CACxC;AAED,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,CAAC;AAI1C;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,QAAQ,EAAE,CAcrE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,QAAQ,EAAE,GACpB,IAAI,CAWN;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,CA2BnE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAoBlE"}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_RULE_LENGTH = exports.MAX_PRACTICES = void 0;
4
+ exports.loadPracticesFromDb = loadPracticesFromDb;
5
+ exports.importPractices = importPractices;
6
+ exports.validatePractices = validatePractices;
7
+ exports.buildPracticesPrompt = buildPracticesPrompt;
8
+ const schemas_1 = require("./schemas");
9
+ Object.defineProperty(exports, "MAX_PRACTICES", { enumerable: true, get: function () { return schemas_1.MAX_PRACTICES; } });
10
+ Object.defineProperty(exports, "MAX_RULE_LENGTH", { enumerable: true, get: function () { return schemas_1.MAX_RULE_LENGTH; } });
11
+ const ID_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
12
+ /**
13
+ * Load practices from the local SQLite practices table.
14
+ * Returns [] if table is empty or doesn't exist.
15
+ */
16
+ function loadPracticesFromDb(db) {
17
+ try {
18
+ const rows = db
19
+ .prepare("SELECT practice_id, rule, severity FROM practices")
20
+ .all();
21
+ return rows.map((r) => ({
22
+ id: r.practice_id,
23
+ rule: r.rule,
24
+ severity: r.severity,
25
+ }));
26
+ }
27
+ catch {
28
+ // Table doesn't exist yet (old DB without initDb migration)
29
+ return [];
30
+ }
31
+ }
32
+ /**
33
+ * Import practices from Supabase into the local SQLite practices table.
34
+ * Replaces all existing practices (full sync).
35
+ */
36
+ function importPractices(db, practices) {
37
+ const validated = validatePractices(practices);
38
+ db.transaction(() => {
39
+ db.prepare("DELETE FROM practices").run();
40
+ const insert = db.prepare("INSERT INTO practices (practice_id, rule, severity) VALUES (?, ?, ?)");
41
+ for (const p of validated) {
42
+ insert.run(p.id, p.rule, p.severity);
43
+ }
44
+ })();
45
+ }
46
+ /**
47
+ * Validate practices array. Enforces limits and format.
48
+ * Returns the validated (possibly truncated) array.
49
+ */
50
+ function validatePractices(practices) {
51
+ if (!Array.isArray(practices))
52
+ return [];
53
+ const capped = practices.slice(0, schemas_1.MAX_PRACTICES);
54
+ return capped.map((p, i) => {
55
+ if (!p.id || typeof p.id !== "string") {
56
+ throw new Error(`Practice at index ${i} has invalid id: ${JSON.stringify(p.id)}`);
57
+ }
58
+ if (!ID_PATTERN.test(p.id)) {
59
+ throw new Error(`Practice id "${p.id}" must be kebab-case (lowercase letters, numbers, hyphens)`);
60
+ }
61
+ if (!p.rule || typeof p.rule !== "string") {
62
+ throw new Error(`Practice "${p.id}" has invalid rule`);
63
+ }
64
+ const severity = p.severity ?? "warning";
65
+ if (!["error", "warning", "info"].includes(severity)) {
66
+ throw new Error(`Practice "${p.id}" has invalid severity: ${severity}`);
67
+ }
68
+ return {
69
+ id: p.id,
70
+ rule: p.rule.slice(0, schemas_1.MAX_RULE_LENGTH),
71
+ severity: severity,
72
+ };
73
+ });
74
+ }
75
+ /**
76
+ * Build the prompt section for practices. Returns empty string if no practices.
77
+ */
78
+ function buildPracticesPrompt(practices) {
79
+ if (practices.length === 0)
80
+ return "";
81
+ const lines = practices.map((p) => `- ${p.id} [${p.severity}]: ${p.rule}`);
82
+ return `
83
+ Also check for violations of these coding practices:
84
+ ${lines.join("\n")}
85
+
86
+ For each violation found, add an entry to practiceViolations (empty array if none), each with:
87
+ - flag: the practice id from the list above
88
+ - title: short one-line title
89
+ - description: what's wrong (1-2 sentences)
90
+ - explanation: how to fix (2-4 sentences)
91
+ - line: the line number (read the label, don't count)
92
+ - startText: first ~30 characters of the problematic code on that line
93
+ - endText: last ~20 characters of the problematic code on that line
94
+ - severity: use the severity shown in brackets above`;
95
+ }
package/dist/schemas.d.ts CHANGED
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  export declare const AnalysisType: z.ZodEnum<{
3
3
  documentation: "documentation";
4
4
  security: "security";
5
+ practices: "practices";
5
6
  }>;
6
7
  export type AnalysisType = z.infer<typeof AnalysisType>;
7
8
  export declare const KNOWN_DATA_TAGS: readonly ["user_input", "pii", "credentials", "database", "external_api", "file_system", "config", "internal"];
@@ -34,15 +35,87 @@ export declare const DocumentationAnalysis: z.ZodObject<{
34
35
  }, z.core.$strip>;
35
36
  export type DocumentationAnalysis = z.infer<typeof DocumentationAnalysis>;
36
37
  /**
37
- * Security analysis: data flow tags and security vulnerability flags.
38
- * Both fields use z.string() arrays (not enums) open with known values.
39
- * Unknown values from Claude are preserved, not rejected.
38
+ * A rich security or practice issue with location, description, and fix guidance.
39
+ * Every field uses .catch() so malformed Claude responses degrade gracefully.
40
+ * The `line` field is 1-indexed within the function (from line-numbered prompt context).
41
+ * `startText`/`endText` are anchor snippets for character-level precision.
42
+ */
43
+ export declare const DetailedIssue: z.ZodObject<{
44
+ flag: z.ZodString;
45
+ title: z.ZodCatch<z.ZodString>;
46
+ description: z.ZodCatch<z.ZodString>;
47
+ explanation: z.ZodCatch<z.ZodString>;
48
+ line: z.ZodCatch<z.ZodNumber>;
49
+ startText: z.ZodCatch<z.ZodString>;
50
+ endText: z.ZodCatch<z.ZodString>;
51
+ severity: z.ZodCatch<z.ZodEnum<{
52
+ error: "error";
53
+ warning: "warning";
54
+ info: "info";
55
+ }>>;
56
+ confidence: z.ZodCatch<z.ZodEnum<{
57
+ high: "high";
58
+ medium: "medium";
59
+ low: "low";
60
+ }>>;
61
+ lineText: z.ZodCatch<z.ZodString>;
62
+ }, z.core.$strip>;
63
+ export type DetailedIssue = z.infer<typeof DetailedIssue>;
64
+ /**
65
+ * Security analysis: data flow tags, vulnerability flags, and detailed issues.
66
+ * `securityFlags` is kept as a lightweight summary (for CodeLens icons, filtering, badge counts).
67
+ * `issues` provides rich details (title, description, explanation, line location).
68
+ * `issues` uses .catch([]) so v1 rows (without issues) parse successfully.
40
69
  */
41
70
  export declare const SecurityAnalysis: z.ZodObject<{
42
71
  dataTags: z.ZodArray<z.ZodString>;
43
72
  securityFlags: z.ZodArray<z.ZodString>;
73
+ issues: z.ZodCatch<z.ZodArray<z.ZodObject<{
74
+ flag: z.ZodString;
75
+ title: z.ZodCatch<z.ZodString>;
76
+ description: z.ZodCatch<z.ZodString>;
77
+ explanation: z.ZodCatch<z.ZodString>;
78
+ line: z.ZodCatch<z.ZodNumber>;
79
+ startText: z.ZodCatch<z.ZodString>;
80
+ endText: z.ZodCatch<z.ZodString>;
81
+ severity: z.ZodCatch<z.ZodEnum<{
82
+ error: "error";
83
+ warning: "warning";
84
+ info: "info";
85
+ }>>;
86
+ confidence: z.ZodCatch<z.ZodEnum<{
87
+ high: "high";
88
+ medium: "medium";
89
+ low: "low";
90
+ }>>;
91
+ lineText: z.ZodCatch<z.ZodString>;
92
+ }, z.core.$strip>>>;
44
93
  }, z.core.$strip>;
45
94
  export type SecurityAnalysis = z.infer<typeof SecurityAnalysis>;
95
+ /** Practices analysis: violations of team-defined coding practices. */
96
+ export declare const PracticesAnalysis: z.ZodObject<{
97
+ violations: z.ZodCatch<z.ZodArray<z.ZodObject<{
98
+ flag: z.ZodString;
99
+ title: z.ZodCatch<z.ZodString>;
100
+ description: z.ZodCatch<z.ZodString>;
101
+ explanation: z.ZodCatch<z.ZodString>;
102
+ line: z.ZodCatch<z.ZodNumber>;
103
+ startText: z.ZodCatch<z.ZodString>;
104
+ endText: z.ZodCatch<z.ZodString>;
105
+ severity: z.ZodCatch<z.ZodEnum<{
106
+ error: "error";
107
+ warning: "warning";
108
+ info: "info";
109
+ }>>;
110
+ confidence: z.ZodCatch<z.ZodEnum<{
111
+ high: "high";
112
+ medium: "medium";
113
+ low: "low";
114
+ }>>;
115
+ lineText: z.ZodCatch<z.ZodString>;
116
+ }, z.core.$strip>>>;
117
+ }, z.core.$strip>;
118
+ export type PracticesAnalysis = z.infer<typeof PracticesAnalysis>;
46
119
  export declare const TypedAnalysis: z.ZodDiscriminatedUnion<[z.ZodObject<{
47
120
  analysisType: z.ZodLiteral<"documentation">;
48
121
  data: z.ZodObject<{
@@ -62,6 +135,50 @@ export declare const TypedAnalysis: z.ZodDiscriminatedUnion<[z.ZodObject<{
62
135
  data: z.ZodObject<{
63
136
  dataTags: z.ZodArray<z.ZodString>;
64
137
  securityFlags: z.ZodArray<z.ZodString>;
138
+ issues: z.ZodCatch<z.ZodArray<z.ZodObject<{
139
+ flag: z.ZodString;
140
+ title: z.ZodCatch<z.ZodString>;
141
+ description: z.ZodCatch<z.ZodString>;
142
+ explanation: z.ZodCatch<z.ZodString>;
143
+ line: z.ZodCatch<z.ZodNumber>;
144
+ startText: z.ZodCatch<z.ZodString>;
145
+ endText: z.ZodCatch<z.ZodString>;
146
+ severity: z.ZodCatch<z.ZodEnum<{
147
+ error: "error";
148
+ warning: "warning";
149
+ info: "info";
150
+ }>>;
151
+ confidence: z.ZodCatch<z.ZodEnum<{
152
+ high: "high";
153
+ medium: "medium";
154
+ low: "low";
155
+ }>>;
156
+ lineText: z.ZodCatch<z.ZodString>;
157
+ }, z.core.$strip>>>;
158
+ }, z.core.$strip>;
159
+ }, z.core.$strip>, z.ZodObject<{
160
+ analysisType: z.ZodLiteral<"practices">;
161
+ data: z.ZodObject<{
162
+ violations: z.ZodCatch<z.ZodArray<z.ZodObject<{
163
+ flag: z.ZodString;
164
+ title: z.ZodCatch<z.ZodString>;
165
+ description: z.ZodCatch<z.ZodString>;
166
+ explanation: z.ZodCatch<z.ZodString>;
167
+ line: z.ZodCatch<z.ZodNumber>;
168
+ startText: z.ZodCatch<z.ZodString>;
169
+ endText: z.ZodCatch<z.ZodString>;
170
+ severity: z.ZodCatch<z.ZodEnum<{
171
+ error: "error";
172
+ warning: "warning";
173
+ info: "info";
174
+ }>>;
175
+ confidence: z.ZodCatch<z.ZodEnum<{
176
+ high: "high";
177
+ medium: "medium";
178
+ low: "low";
179
+ }>>;
180
+ lineText: z.ZodCatch<z.ZodString>;
181
+ }, z.core.$strip>>>;
65
182
  }, z.core.$strip>;
66
183
  }, z.core.$strip>], "analysisType">;
67
184
  export type TypedAnalysis = z.infer<typeof TypedAnalysis>;
@@ -87,14 +204,145 @@ export declare const ClaudeAnalysisResponse: z.ZodObject<{
87
204
  }, z.core.$strip>>;
88
205
  dataTags: z.ZodCatch<z.ZodArray<z.ZodString>>;
89
206
  securityFlags: z.ZodCatch<z.ZodArray<z.ZodString>>;
207
+ issues: z.ZodCatch<z.ZodArray<z.ZodObject<{
208
+ flag: z.ZodString;
209
+ title: z.ZodCatch<z.ZodString>;
210
+ description: z.ZodCatch<z.ZodString>;
211
+ explanation: z.ZodCatch<z.ZodString>;
212
+ line: z.ZodCatch<z.ZodNumber>;
213
+ startText: z.ZodCatch<z.ZodString>;
214
+ endText: z.ZodCatch<z.ZodString>;
215
+ severity: z.ZodCatch<z.ZodEnum<{
216
+ error: "error";
217
+ warning: "warning";
218
+ info: "info";
219
+ }>>;
220
+ confidence: z.ZodCatch<z.ZodEnum<{
221
+ high: "high";
222
+ medium: "medium";
223
+ low: "low";
224
+ }>>;
225
+ lineText: z.ZodCatch<z.ZodString>;
226
+ }, z.core.$strip>>>;
227
+ practiceViolations: z.ZodCatch<z.ZodArray<z.ZodObject<{
228
+ flag: z.ZodString;
229
+ title: z.ZodCatch<z.ZodString>;
230
+ description: z.ZodCatch<z.ZodString>;
231
+ explanation: z.ZodCatch<z.ZodString>;
232
+ line: z.ZodCatch<z.ZodNumber>;
233
+ startText: z.ZodCatch<z.ZodString>;
234
+ endText: z.ZodCatch<z.ZodString>;
235
+ severity: z.ZodCatch<z.ZodEnum<{
236
+ error: "error";
237
+ warning: "warning";
238
+ info: "info";
239
+ }>>;
240
+ confidence: z.ZodCatch<z.ZodEnum<{
241
+ high: "high";
242
+ medium: "medium";
243
+ low: "low";
244
+ }>>;
245
+ lineText: z.ZodCatch<z.ZodString>;
246
+ }, z.core.$strip>>>;
90
247
  }, z.core.$strip>;
91
248
  export type ClaudeAnalysisResponse = z.infer<typeof ClaudeAnalysisResponse>;
249
+ export declare const SummaryMeta: z.ZodObject<{
250
+ securityPosture: z.ZodCatch<z.ZodString>;
251
+ dataClassification: z.ZodCatch<z.ZodArray<z.ZodString>>;
252
+ boundaries: z.ZodCatch<z.ZodArray<z.ZodString>>;
253
+ keyFunctions: z.ZodCatch<z.ZodArray<z.ZodString>>;
254
+ complexity: z.ZodCatch<z.ZodEnum<{
255
+ high: "high";
256
+ medium: "medium";
257
+ low: "low";
258
+ }>>;
259
+ }, z.core.$strip>;
260
+ export type SummaryMeta = z.infer<typeof SummaryMeta>;
261
+ /** L1 subsystem summary: docs for a group of closely-related functions */
262
+ export declare const L1Summary: z.ZodObject<{
263
+ title: z.ZodCatch<z.ZodString>;
264
+ documentation: z.ZodCatch<z.ZodString>;
265
+ meta: z.ZodCatch<z.ZodObject<{
266
+ securityPosture: z.ZodCatch<z.ZodString>;
267
+ dataClassification: z.ZodCatch<z.ZodArray<z.ZodString>>;
268
+ boundaries: z.ZodCatch<z.ZodArray<z.ZodString>>;
269
+ keyFunctions: z.ZodCatch<z.ZodArray<z.ZodString>>;
270
+ complexity: z.ZodCatch<z.ZodEnum<{
271
+ high: "high";
272
+ medium: "medium";
273
+ low: "low";
274
+ }>>;
275
+ }, z.core.$strip>>;
276
+ }, z.core.$strip>;
277
+ export type L1Summary = z.infer<typeof L1Summary>;
278
+ /** L2 system summary: docs for a group of L1 subsystems */
279
+ export declare const L2Summary: z.ZodObject<{
280
+ title: z.ZodCatch<z.ZodString>;
281
+ documentation: z.ZodCatch<z.ZodString>;
282
+ meta: z.ZodCatch<z.ZodObject<{
283
+ securityPosture: z.ZodCatch<z.ZodString>;
284
+ dataClassification: z.ZodCatch<z.ZodArray<z.ZodString>>;
285
+ boundaries: z.ZodCatch<z.ZodArray<z.ZodString>>;
286
+ keyFunctions: z.ZodCatch<z.ZodArray<z.ZodString>>;
287
+ complexity: z.ZodCatch<z.ZodEnum<{
288
+ high: "high";
289
+ medium: "medium";
290
+ low: "low";
291
+ }>>;
292
+ }, z.core.$strip>>;
293
+ }, z.core.$strip>;
294
+ export type L2Summary = z.infer<typeof L2Summary>;
295
+ /** L3 architecture overview: top-level docs from L2 summaries */
296
+ export declare const L3Summary: z.ZodObject<{
297
+ title: z.ZodCatch<z.ZodString>;
298
+ documentation: z.ZodCatch<z.ZodString>;
299
+ meta: z.ZodCatch<z.ZodObject<{
300
+ securityPosture: z.ZodCatch<z.ZodString>;
301
+ dataClassification: z.ZodCatch<z.ZodArray<z.ZodString>>;
302
+ boundaries: z.ZodCatch<z.ZodArray<z.ZodString>>;
303
+ keyFunctions: z.ZodCatch<z.ZodArray<z.ZodString>>;
304
+ complexity: z.ZodCatch<z.ZodEnum<{
305
+ high: "high";
306
+ medium: "medium";
307
+ low: "low";
308
+ }>>;
309
+ }, z.core.$strip>>;
310
+ }, z.core.$strip>;
311
+ export type L3Summary = z.infer<typeof L3Summary>;
312
+ /** Cross-cutting concern summary: docs for a data flow or security pattern spanning communities */
313
+ export declare const CrossCuttingConcernSummary: z.ZodObject<{
314
+ title: z.ZodCatch<z.ZodString>;
315
+ concernType: z.ZodCatch<z.ZodString>;
316
+ tag: z.ZodCatch<z.ZodString>;
317
+ documentation: z.ZodCatch<z.ZodString>;
318
+ bridgeFunctions: z.ZodCatch<z.ZodArray<z.ZodObject<{
319
+ functionName: z.ZodString;
320
+ contentHash: z.ZodString;
321
+ communityId: z.ZodString;
322
+ centrality: z.ZodNumber;
323
+ }, z.core.$strip>>>;
324
+ affectedCommunities: z.ZodCatch<z.ZodArray<z.ZodObject<{
325
+ communityId: z.ZodString;
326
+ communityTitle: z.ZodString;
327
+ }, z.core.$strip>>>;
328
+ severity: z.ZodCatch<z.ZodString>;
329
+ }, z.core.$strip>;
330
+ export type CrossCuttingConcernSummary = z.infer<typeof CrossCuttingConcernSummary>;
92
331
  /**
93
332
  * Each analysis type has an independent schema version.
94
333
  * Bump when the JSON shape changes. Old rows remain readable.
95
334
  * Stored alongside each row for forward-compatibility.
96
335
  */
97
336
  export declare const SCHEMA_VERSIONS: Record<AnalysisType, number>;
337
+ export declare const MAX_PRACTICES = 10;
338
+ export declare const MAX_RULE_LENGTH = 200;
98
339
  export declare const SECURITY_FLAG_LABELS: Record<string, string>;
340
+ export interface SecurityFlagMeta {
341
+ tier: 1 | 2 | 3 | 4;
342
+ cwe: string;
343
+ owasp: string;
344
+ }
345
+ export declare const SECURITY_FLAG_META: Record<string, SecurityFlagMeta>;
346
+ export declare const SECURITY_TIER_LABELS: Record<number, string>;
99
347
  export declare const DATA_TAG_LABELS: Record<string, string>;
100
348
  //# sourceMappingURL=schemas.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,YAAY;;;EAAwC,CAAC;AAClE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAaxD,eAAO,MAAM,eAAe,gHASlB,CAAC;AACX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,eAAO,MAAM,oBAAoB,wMAWvB,CAAC;AACX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAItE,eAAO,MAAM,WAAW;;;;iBAItB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD,eAAO,MAAM,aAAa;;;iBAGxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,mEAAmE;AACnE,eAAO,MAAM,qBAAqB;;;;;;;;;;;iBAIhC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE1E;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;iBAG3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAIhE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;mCASxB,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAI1D;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;iBAOjC,CAAC;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAI5E;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAGxD,CAAC;AAQF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAWvD,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CASlD,CAAC"}
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}