@zivis/cli 0.1.0-alpha.34 → 0.1.0-alpha.35
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/LICENSE +201 -0
- package/README.md +31 -0
- package/dist/commands/app/index.d.ts +0 -8
- package/dist/commands/app/index.js +0 -12
- package/dist/commands/auth/bind.d.ts +0 -10
- package/dist/commands/auth/bind.js +0 -11
- package/dist/commands/auth/index.js +0 -1
- package/dist/commands/auth/init.js +0 -19
- package/dist/commands/auth/login.d.ts +0 -1
- package/dist/commands/auth/login.js +0 -6
- package/dist/commands/auth/logout.js +0 -3
- package/dist/commands/auth/sessions.js +0 -1
- package/dist/commands/auth/status.js +0 -2
- package/dist/commands/auth/token.d.ts +0 -13
- package/dist/commands/auth/token.js +0 -18
- package/dist/commands/check/index.d.ts +0 -18
- package/dist/commands/check/index.js +1 -37
- package/dist/commands/credits/index.js +0 -1
- package/dist/commands/inspect/index.d.ts +0 -15
- package/dist/commands/inspect/index.js +0 -23
- package/dist/commands/mcp/index.js +0 -9
- package/dist/commands/open/index.d.ts +0 -8
- package/dist/commands/open/index.js +0 -11
- package/dist/commands/scan/index.js +0 -6
- package/dist/commands/target/index.js +0 -3
- package/dist/commands/tm/index.js +0 -7
- package/dist/index.js +9 -1
- package/dist/internal/binding-token-mint.d.ts +0 -29
- package/dist/internal/binding-token-mint.js +0 -28
- package/dist/internal/extractor/adapters/go/index.d.ts +0 -4
- package/dist/internal/extractor/adapters/go/index.js +0 -6
- package/dist/internal/extractor/adapters/go/manifest.d.ts +0 -17
- package/dist/internal/extractor/adapters/go/manifest.js +1 -25
- package/dist/internal/extractor/adapters/go/parser.d.ts +0 -4
- package/dist/internal/extractor/adapters/go/parser.js +0 -5
- package/dist/internal/extractor/adapters/go/scanner.d.ts +0 -20
- package/dist/internal/extractor/adapters/go/scanner.js +0 -43
- package/dist/internal/extractor/adapters/python/index.d.ts +0 -3
- package/dist/internal/extractor/adapters/python/index.js +0 -4
- package/dist/internal/extractor/adapters/python/manifest.d.ts +0 -8
- package/dist/internal/extractor/adapters/python/manifest.js +3 -18
- package/dist/internal/extractor/adapters/python/parser.d.ts +0 -3
- package/dist/internal/extractor/adapters/python/parser.js +0 -4
- package/dist/internal/extractor/adapters/python/scanner.d.ts +0 -18
- package/dist/internal/extractor/adapters/python/scanner.js +1 -54
- package/dist/internal/extractor/adapters/typescript/index.d.ts +0 -7
- package/dist/internal/extractor/adapters/typescript/index.js +1 -21
- package/dist/internal/extractor/adapters/typescript/manifest.d.ts +0 -14
- package/dist/internal/extractor/adapters/typescript/manifest.js +1 -20
- package/dist/internal/extractor/adapters/typescript/parser.d.ts +0 -8
- package/dist/internal/extractor/adapters/typescript/parser.js +0 -9
- package/dist/internal/extractor/adapters/typescript/scanner.d.ts +0 -24
- package/dist/internal/extractor/adapters/typescript/scanner.js +0 -43
- package/dist/internal/extractor/graph-builder.d.ts +0 -25
- package/dist/internal/extractor/graph-builder.js +1 -39
- package/dist/internal/extractor/graph-types.d.ts +0 -10
- package/dist/internal/extractor/graph-types.js +0 -11
- package/dist/internal/extractor/index.d.ts +0 -14
- package/dist/internal/extractor/index.js +0 -13
- package/dist/internal/extractor/types.d.ts +0 -45
- package/dist/internal/extractor/types.js +0 -27
- package/dist/internal/extractor/walker.d.ts +0 -18
- package/dist/internal/extractor/walker.js +0 -18
- package/dist/internal/github-linkage-prompt.d.ts +0 -19
- package/dist/internal/github-linkage-prompt.js +1 -27
- package/dist/internal/ide-setup.d.ts +0 -23
- package/dist/internal/ide-setup.js +0 -53
- package/dist/internal/orgs.js +0 -1
- package/dist/internal/project-binding.d.ts +0 -1
- package/dist/internal/project-binding.js +0 -5
- package/dist/internal/target-auth/api-config.d.ts +0 -17
- package/dist/internal/target-auth/api-config.js +0 -18
- package/dist/internal/target-auth/config.d.ts +0 -12
- package/dist/internal/target-auth/config.js +0 -13
- package/dist/internal/target-auth/index.d.ts +0 -18
- package/dist/internal/target-auth/index.js +0 -19
- package/dist/internal/target-auth/keychain.d.ts +0 -18
- package/dist/internal/target-auth/keychain.js +3 -23
- package/dist/internal/target-auth/types.d.ts +0 -26
- package/dist/internal/target-auth/types.js +0 -10
- package/dist/internal/target-auth/workos.d.ts +0 -15
- package/dist/internal/target-auth/workos.js +0 -17
- package/package.json +22 -13
- package/dist/commands/app/index.js.map +0 -1
- package/dist/commands/auth/bind.js.map +0 -1
- package/dist/commands/auth/index.js.map +0 -1
- package/dist/commands/auth/init.js.map +0 -1
- package/dist/commands/auth/login.js.map +0 -1
- package/dist/commands/auth/logout.js.map +0 -1
- package/dist/commands/auth/sessions.js.map +0 -1
- package/dist/commands/auth/status.js.map +0 -1
- package/dist/commands/auth/token.js.map +0 -1
- package/dist/commands/check/index.js.map +0 -1
- package/dist/commands/credits/index.js.map +0 -1
- package/dist/commands/inspect/index.js.map +0 -1
- package/dist/commands/mcp/index.js.map +0 -1
- package/dist/commands/open/index.js.map +0 -1
- package/dist/commands/scan/index.js.map +0 -1
- package/dist/commands/target/index.js.map +0 -1
- package/dist/commands/tm/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/internal/binding-token-mint.js.map +0 -1
- package/dist/internal/extractor/adapters/go/index.js.map +0 -1
- package/dist/internal/extractor/adapters/go/manifest.js.map +0 -1
- package/dist/internal/extractor/adapters/go/parser.js.map +0 -1
- package/dist/internal/extractor/adapters/go/scanner.js.map +0 -1
- package/dist/internal/extractor/adapters/python/index.js.map +0 -1
- package/dist/internal/extractor/adapters/python/manifest.js.map +0 -1
- package/dist/internal/extractor/adapters/python/parser.js.map +0 -1
- package/dist/internal/extractor/adapters/python/scanner.js.map +0 -1
- package/dist/internal/extractor/adapters/typescript/index.js.map +0 -1
- package/dist/internal/extractor/adapters/typescript/manifest.js.map +0 -1
- package/dist/internal/extractor/adapters/typescript/parser.js.map +0 -1
- package/dist/internal/extractor/adapters/typescript/scanner.js.map +0 -1
- package/dist/internal/extractor/graph-builder.js.map +0 -1
- package/dist/internal/extractor/graph-types.js.map +0 -1
- package/dist/internal/extractor/index.js.map +0 -1
- package/dist/internal/extractor/types.js.map +0 -1
- package/dist/internal/extractor/walker.js.map +0 -1
- package/dist/internal/github-linkage-prompt.js.map +0 -1
- package/dist/internal/ide-setup.js.map +0 -1
- package/dist/internal/orgs.js.map +0 -1
- package/dist/internal/pattern-pack/index.d.ts +0 -123
- package/dist/internal/pattern-pack/index.js +0 -230
- package/dist/internal/pattern-pack/index.js.map +0 -1
- package/dist/internal/project-binding.js.map +0 -1
- package/dist/internal/target-auth/api-config.js.map +0 -1
- package/dist/internal/target-auth/config.js.map +0 -1
- package/dist/internal/target-auth/index.js.map +0 -1
- package/dist/internal/target-auth/keychain.js.map +0 -1
- package/dist/internal/target-auth/types.js.map +0 -1
- package/dist/internal/target-auth/workos.js.map +0 -1
- package/dist/pattern-packs/zivis-public-0.1.0/capsules/agents/privilege-separation.yaml +0 -228
- package/dist/pattern-packs/zivis-public-0.1.0/manifest.json +0 -31
- package/dist/pattern-packs/zivis-public-0.1.0/prompts/agents/privilege-separation/identify.md +0 -54
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Python manifest analysis.
|
|
3
|
-
*
|
|
4
|
-
* Reads pyproject.toml (PEP 621 + Poetry sections) and requirements.txt.
|
|
5
|
-
* Other formats (Pipfile, setup.py) deferred — they're either rare in
|
|
6
|
-
* modern projects (setup.py) or layer on top of these two.
|
|
7
|
-
*/
|
|
8
1
|
import type { ExtractedExternalService, ExtractedDataStore, ManifestSummary } from "../../types.js";
|
|
9
2
|
export declare const WEB_FRAMEWORK_PACKAGES: Record<string, string>;
|
|
10
3
|
export declare const DATA_STORE_PACKAGES: Record<string, {
|
|
@@ -15,7 +8,6 @@ export declare const AI_SDK_PACKAGES: Record<string, string>;
|
|
|
15
8
|
export interface ParsedPyManifest {
|
|
16
9
|
filePath: string;
|
|
17
10
|
format: "pyproject.toml" | "requirements.txt";
|
|
18
|
-
/** package name → version specifier (verbatim, e.g. "^0.30.0", ">=2.0,<3"). */
|
|
19
11
|
deps: Record<string, string>;
|
|
20
12
|
}
|
|
21
13
|
export declare function readManifests(rootDir: string, manifestFiles: string[]): Promise<ParsedPyManifest[]>;
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Python manifest analysis.
|
|
3
|
-
*
|
|
4
|
-
* Reads pyproject.toml (PEP 621 + Poetry sections) and requirements.txt.
|
|
5
|
-
* Other formats (Pipfile, setup.py) deferred — they're either rare in
|
|
6
|
-
* modern projects (setup.py) or layer on top of these two.
|
|
7
|
-
*/
|
|
8
1
|
import * as fs from "node:fs/promises";
|
|
9
2
|
import * as path from "node:path";
|
|
10
3
|
import TOML from "@iarna/toml";
|
|
@@ -20,7 +13,7 @@ export const WEB_FRAMEWORK_PACKAGES = {
|
|
|
20
13
|
quart: "quart",
|
|
21
14
|
};
|
|
22
15
|
export const DATA_STORE_PACKAGES = {
|
|
23
|
-
sqlalchemy: { kind: "postgres", client: "sqlalchemy" },
|
|
16
|
+
sqlalchemy: { kind: "postgres", client: "sqlalchemy" },
|
|
24
17
|
asyncpg: { kind: "postgres", client: "asyncpg" },
|
|
25
18
|
psycopg: { kind: "postgres", client: "psycopg" },
|
|
26
19
|
psycopg2: { kind: "postgres", client: "psycopg2" },
|
|
@@ -45,7 +38,7 @@ export const AI_SDK_PACKAGES = {
|
|
|
45
38
|
vertexai: "Vertex AI",
|
|
46
39
|
"google-generativeai": "Google Generative AI",
|
|
47
40
|
cohere: "Cohere",
|
|
48
|
-
"boto3": "AWS (boto3)",
|
|
41
|
+
"boto3": "AWS (boto3)",
|
|
49
42
|
};
|
|
50
43
|
export async function readManifests(rootDir, manifestFiles) {
|
|
51
44
|
const out = [];
|
|
@@ -61,7 +54,6 @@ export async function readManifests(rootDir, manifestFiles) {
|
|
|
61
54
|
}
|
|
62
55
|
}
|
|
63
56
|
catch {
|
|
64
|
-
// skip unreadable / unparsable
|
|
65
57
|
}
|
|
66
58
|
}
|
|
67
59
|
return out;
|
|
@@ -79,7 +71,6 @@ function parsePyproject(filePath, rootDir, raw) {
|
|
|
79
71
|
catch {
|
|
80
72
|
return result;
|
|
81
73
|
}
|
|
82
|
-
// PEP 621: project.dependencies = ["fastapi >=0.100", ...]
|
|
83
74
|
const projectDeps = parsed?.project?.dependencies;
|
|
84
75
|
if (Array.isArray(projectDeps)) {
|
|
85
76
|
for (const spec of projectDeps) {
|
|
@@ -90,7 +81,6 @@ function parsePyproject(filePath, rootDir, raw) {
|
|
|
90
81
|
result.deps[name] = version;
|
|
91
82
|
}
|
|
92
83
|
}
|
|
93
|
-
// PEP 621: optional-dependencies = { test = [...], dev = [...] }
|
|
94
84
|
const opt = parsed?.project?.["optional-dependencies"];
|
|
95
85
|
if (opt && typeof opt === "object") {
|
|
96
86
|
for (const groupSpec of Object.values(opt)) {
|
|
@@ -105,7 +95,6 @@ function parsePyproject(filePath, rootDir, raw) {
|
|
|
105
95
|
}
|
|
106
96
|
}
|
|
107
97
|
}
|
|
108
|
-
// Poetry: tool.poetry.dependencies = { fastapi = "^0.100" } (also dev-dependencies)
|
|
109
98
|
const poetryDeps = parsed?.tool?.poetry?.dependencies;
|
|
110
99
|
if (poetryDeps && typeof poetryDeps === "object") {
|
|
111
100
|
for (const [name, value] of Object.entries(poetryDeps)) {
|
|
@@ -137,8 +126,7 @@ function parseRequirementsTxt(filePath, rootDir, raw) {
|
|
|
137
126
|
if (!line || line.startsWith("#"))
|
|
138
127
|
continue;
|
|
139
128
|
if (line.startsWith("-"))
|
|
140
|
-
continue;
|
|
141
|
-
// strip inline comments
|
|
129
|
+
continue;
|
|
142
130
|
const hashAt = line.indexOf(" #");
|
|
143
131
|
if (hashAt > 0)
|
|
144
132
|
line = line.slice(0, hashAt).trim();
|
|
@@ -148,9 +136,7 @@ function parseRequirementsTxt(filePath, rootDir, raw) {
|
|
|
148
136
|
}
|
|
149
137
|
return result;
|
|
150
138
|
}
|
|
151
|
-
/** "fastapi>=0.100,<0.110" → ["fastapi", ">=0.100,<0.110"] */
|
|
152
139
|
function splitPep508(spec) {
|
|
153
|
-
// strip extras like fastapi[all]
|
|
154
140
|
const cleaned = spec.replace(/\[[^\]]*\]/g, "").trim();
|
|
155
141
|
const m = cleaned.match(/^([A-Za-z0-9_.\-]+)\s*(.*)$/);
|
|
156
142
|
if (!m)
|
|
@@ -251,4 +237,3 @@ function relPosix(rootDir, abs) {
|
|
|
251
237
|
const rel = path.relative(rootDir, abs);
|
|
252
238
|
return rel.split(path.sep).join("/");
|
|
253
239
|
}
|
|
254
|
-
//# sourceMappingURL=manifest.js.map
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* tree-sitter-python loader.
|
|
3
|
-
*/
|
|
4
1
|
import { createRequire } from "node:module";
|
|
5
2
|
import * as path from "node:path";
|
|
6
3
|
import { Parser, Language } from "web-tree-sitter";
|
|
@@ -19,4 +16,3 @@ export function getPythonParser() {
|
|
|
19
16
|
}
|
|
20
17
|
return parserPromise;
|
|
21
18
|
}
|
|
22
|
-
//# sourceMappingURL=parser.js.map
|
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AST scanner for Python source files.
|
|
3
|
-
*
|
|
4
|
-
* Patterns covered:
|
|
5
|
-
* 1. import_statement / import_from_statement → tracked-package imports
|
|
6
|
-
* (AI SDKs, web frameworks, DB clients).
|
|
7
|
-
* 2. Decorator-based routes (FastAPI, Flask):
|
|
8
|
-
* @app.get("/path") → method=GET
|
|
9
|
-
* @app.post("/path") → method=POST
|
|
10
|
-
* @app.route("/path", …) → method=ALL (Flask default; verbs in `methods=` kw not parsed yet)
|
|
11
|
-
* @router.get("/x", …) → method=GET (FastAPI APIRouter convention)
|
|
12
|
-
* 3. Django urls.py-style call: path("/route", view, …) / re_path(…) → method=ALL
|
|
13
|
-
* 4. aiohttp: app.router.add_get("/path", h) / add_post(…) / etc.
|
|
14
|
-
*
|
|
15
|
-
* Privacy invariant: identifier names + dotted attribute names + string
|
|
16
|
-
* literals on routes only. Function bodies and decorator args beyond the
|
|
17
|
-
* route path are never inspected.
|
|
18
|
-
*/
|
|
19
1
|
import type { EvidenceLocation, Evidence, HttpRouteEvidence, ImportEvidence } from "../../types.js";
|
|
20
2
|
export interface FileScanResult {
|
|
21
3
|
file: string;
|
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AST scanner for Python source files.
|
|
3
|
-
*
|
|
4
|
-
* Patterns covered:
|
|
5
|
-
* 1. import_statement / import_from_statement → tracked-package imports
|
|
6
|
-
* (AI SDKs, web frameworks, DB clients).
|
|
7
|
-
* 2. Decorator-based routes (FastAPI, Flask):
|
|
8
|
-
* @app.get("/path") → method=GET
|
|
9
|
-
* @app.post("/path") → method=POST
|
|
10
|
-
* @app.route("/path", …) → method=ALL (Flask default; verbs in `methods=` kw not parsed yet)
|
|
11
|
-
* @router.get("/x", …) → method=GET (FastAPI APIRouter convention)
|
|
12
|
-
* 3. Django urls.py-style call: path("/route", view, …) / re_path(…) → method=ALL
|
|
13
|
-
* 4. aiohttp: app.router.add_get("/path", h) / add_post(…) / etc.
|
|
14
|
-
*
|
|
15
|
-
* Privacy invariant: identifier names + dotted attribute names + string
|
|
16
|
-
* literals on routes only. Function bodies and decorator args beyond the
|
|
17
|
-
* route path are never inspected.
|
|
18
|
-
*/
|
|
19
1
|
import * as fs from "node:fs/promises";
|
|
20
2
|
import { getPythonParser } from "./parser.js";
|
|
21
3
|
import { AI_SDK_PACKAGES, DATA_STORE_PACKAGES, WEB_FRAMEWORK_PACKAGES, } from "./manifest.js";
|
|
@@ -87,22 +69,9 @@ function walk(node, visit) {
|
|
|
87
69
|
walk(child, visit);
|
|
88
70
|
}
|
|
89
71
|
}
|
|
90
|
-
/**
|
|
91
|
-
* Pull the top-level package(s) out of an import statement.
|
|
92
|
-
*
|
|
93
|
-
* - `import anthropic` → ["anthropic"]
|
|
94
|
-
* - `import langchain.chat_models` → ["langchain"] (we track the root)
|
|
95
|
-
* - `from fastapi import FastAPI` → ["fastapi"]
|
|
96
|
-
* - `from langchain.schema import HumanMessage` → ["langchain"]
|
|
97
|
-
*
|
|
98
|
-
* Sub-modules collapse to the root because the manifest table is keyed
|
|
99
|
-
* by distribution name, which is also the import root for the packages
|
|
100
|
-
* we care about.
|
|
101
|
-
*/
|
|
102
72
|
function extractImportPackages(node) {
|
|
103
73
|
const out = [];
|
|
104
74
|
if (node.type === "import_from_statement") {
|
|
105
|
-
// import_from_statement → module_name as the "module" field
|
|
106
75
|
const moduleField = node.childForFieldName("module_name");
|
|
107
76
|
if (moduleField) {
|
|
108
77
|
const root = topLevelImportName(moduleField);
|
|
@@ -111,7 +80,6 @@ function extractImportPackages(node) {
|
|
|
111
80
|
}
|
|
112
81
|
return out;
|
|
113
82
|
}
|
|
114
|
-
// import_statement: one or more dotted_name (or aliased_import wrapping it)
|
|
115
83
|
for (const child of node.namedChildren) {
|
|
116
84
|
if (!child)
|
|
117
85
|
continue;
|
|
@@ -141,13 +109,7 @@ function topLevelImportName(node) {
|
|
|
141
109
|
function trackedPackageMatch(pkg) {
|
|
142
110
|
return TRACKED_PACKAGES.has(pkg) ? pkg : null;
|
|
143
111
|
}
|
|
144
|
-
/**
|
|
145
|
-
* Match @app.get("/path"), @router.post(…), @app.route("/x", …).
|
|
146
|
-
* Returns the route + method, or null if it isn't a known shape.
|
|
147
|
-
*/
|
|
148
112
|
function extractDecoratorRoute(node) {
|
|
149
|
-
// decorator → `@` + (call | attribute | identifier)
|
|
150
|
-
// We only care about call shapes: @app.get("/path", …)
|
|
151
113
|
const callNode = node.namedChildren.find((c) => c?.type === "call");
|
|
152
114
|
if (!callNode)
|
|
153
115
|
return null;
|
|
@@ -163,37 +125,28 @@ function extractDecoratorRoute(node) {
|
|
|
163
125
|
return null;
|
|
164
126
|
const objectName = objectNode.text.toLowerCase();
|
|
165
127
|
const attrName = attrNode.text.toLowerCase();
|
|
166
|
-
// Object must be a router-y identifier — keep the false-positive surface
|
|
167
|
-
// tight even though we'd lose decorators on uncommon names like `myapi`.
|
|
168
128
|
if (!ROUTER_IDENTIFIERS.has(objectName))
|
|
169
129
|
return null;
|
|
170
130
|
let method = null;
|
|
171
131
|
if (HTTP_METHODS.has(attrName))
|
|
172
132
|
method = attrName.toUpperCase();
|
|
173
133
|
else if (attrName === "route")
|
|
174
|
-
method = "ALL";
|
|
134
|
+
method = "ALL";
|
|
175
135
|
if (!method)
|
|
176
136
|
return null;
|
|
177
137
|
return readRoutePath(args, method);
|
|
178
138
|
}
|
|
179
|
-
/**
|
|
180
|
-
* Match Django path("/route", view, …) / re_path(…) and aiohttp
|
|
181
|
-
* app.router.add_get("/path", h) / add_post(…) etc.
|
|
182
|
-
*/
|
|
183
139
|
function extractCallRoute(node) {
|
|
184
140
|
const fn = node.childForFieldName("function");
|
|
185
141
|
const args = node.childForFieldName("arguments");
|
|
186
142
|
if (!fn || !args)
|
|
187
143
|
return null;
|
|
188
|
-
// Django: bare identifier function, e.g. `path("/route", view)`.
|
|
189
144
|
if (fn.type === "identifier") {
|
|
190
145
|
const name = fn.text;
|
|
191
146
|
if (!DJANGO_PATH_FNS.has(name))
|
|
192
147
|
return null;
|
|
193
148
|
return readRoutePath(args, "ALL");
|
|
194
149
|
}
|
|
195
|
-
// aiohttp: app.router.add_get("/path", h) — attribute call where the
|
|
196
|
-
// method name is encoded into the attribute (add_get, add_post, …).
|
|
197
150
|
if (fn.type === "attribute") {
|
|
198
151
|
const attrNode = fn.childForFieldName("attribute");
|
|
199
152
|
if (!attrNode)
|
|
@@ -205,20 +158,16 @@ function extractCallRoute(node) {
|
|
|
205
158
|
}
|
|
206
159
|
return null;
|
|
207
160
|
}
|
|
208
|
-
/** Pull the first positional string-literal argument as the route path. */
|
|
209
161
|
function readRoutePath(argsNode, method) {
|
|
210
162
|
for (const arg of argsNode.namedChildren) {
|
|
211
163
|
if (!arg)
|
|
212
164
|
continue;
|
|
213
|
-
// Skip kwargs (we only want the first positional).
|
|
214
165
|
if (arg.type === "keyword_argument")
|
|
215
166
|
continue;
|
|
216
167
|
if (arg.type !== "string")
|
|
217
168
|
return null;
|
|
218
|
-
// string → string_start, string_content, string_end
|
|
219
169
|
const content = arg.namedChildren.find((c) => c?.type === "string_content");
|
|
220
170
|
if (!content) {
|
|
221
|
-
// fall back: strip leading/trailing quote chars from raw text
|
|
222
171
|
const text = arg.text;
|
|
223
172
|
if (text.length >= 2 && (text.startsWith('"') || text.startsWith("'"))) {
|
|
224
173
|
return { method, path: text.slice(1, -1) };
|
|
@@ -265,7 +214,6 @@ export function aggregate(scans) {
|
|
|
265
214
|
}
|
|
266
215
|
function deriveComponentName(filePath) {
|
|
267
216
|
const segs = filePath.split("/");
|
|
268
|
-
// Skip common project-layout prefixes.
|
|
269
217
|
const skipPrefixes = new Set(["src", "app", "apps", "backend", "api"]);
|
|
270
218
|
const start = skipPrefixes.has(segs[0]) ? 1 : 0;
|
|
271
219
|
if (segs.length - start >= 2)
|
|
@@ -281,4 +229,3 @@ function detectFrameworkFromImports(imports) {
|
|
|
281
229
|
}
|
|
282
230
|
return undefined;
|
|
283
231
|
}
|
|
284
|
-
//# sourceMappingURL=scanner.js.map
|
|
@@ -1,9 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeScript / JavaScript language adapter.
|
|
3
|
-
*
|
|
4
|
-
* Handles .ts/.tsx/.js/.jsx + package.json. Combines manifest analysis
|
|
5
|
-
* (cheap, runs against package.json) with AST scanning (per source file)
|
|
6
|
-
* to produce components, external services, and data stores.
|
|
7
|
-
*/
|
|
8
1
|
import type { LanguageAdapter } from "../../types.js";
|
|
9
2
|
export declare const typescriptAdapter: LanguageAdapter;
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeScript / JavaScript language adapter.
|
|
3
|
-
*
|
|
4
|
-
* Handles .ts/.tsx/.js/.jsx + package.json. Combines manifest analysis
|
|
5
|
-
* (cheap, runs against package.json) with AST scanning (per source file)
|
|
6
|
-
* to produce components, external services, and data stores.
|
|
7
|
-
*/
|
|
8
1
|
import * as path from "node:path";
|
|
9
2
|
import { readManifests, summarizeManifests, findExternalServices, findDataStores, detectFrameworkFromManifest, } from "./manifest.js";
|
|
10
3
|
import { scanFile, aggregate } from "./scanner.js";
|
|
@@ -15,13 +8,10 @@ export const typescriptAdapter = {
|
|
|
15
8
|
manifests: ["package.json"],
|
|
16
9
|
async extract(input) {
|
|
17
10
|
const { rootDir, sourceFiles, manifestFiles } = input;
|
|
18
|
-
// Manifest pass — fast, runs entirely on package.json contents.
|
|
19
11
|
const parsedManifests = await readManifests(rootDir, manifestFiles);
|
|
20
12
|
const manifestSummaries = summarizeManifests(parsedManifests);
|
|
21
13
|
const manifestExternalServices = findExternalServices(parsedManifests);
|
|
22
14
|
const manifestDataStores = findDataStores(parsedManifests);
|
|
23
|
-
// AST pass — only on source files. Cap at MAX_SOURCE_FILES per run
|
|
24
|
-
// for the Phase J <60s budget on a 100k-LOC monorepo.
|
|
25
15
|
const MAX_SOURCE_FILES = 5_000;
|
|
26
16
|
const filesToScan = sourceFiles.slice(0, MAX_SOURCE_FILES);
|
|
27
17
|
const scans = await Promise.all(filesToScan.map(async (abs) => {
|
|
@@ -33,10 +23,7 @@ export const typescriptAdapter = {
|
|
|
33
23
|
}
|
|
34
24
|
}));
|
|
35
25
|
const agg = aggregate(scans);
|
|
36
|
-
// Map scanner output → ExtractedComponent shape.
|
|
37
26
|
const components = agg.components.map((c) => {
|
|
38
|
-
// Best-effort framework inference: scanner picks up imports; manifest
|
|
39
|
-
// picks up the dep. Either signal counts.
|
|
40
27
|
const framework = c.framework ?? frameworkFromOwningManifest(c.sourceFile, parsedManifests);
|
|
41
28
|
return {
|
|
42
29
|
name: c.name,
|
|
@@ -47,13 +34,11 @@ export const typescriptAdapter = {
|
|
|
47
34
|
evidence: [...c.routes, ...c.imports],
|
|
48
35
|
};
|
|
49
36
|
});
|
|
50
|
-
// Augment manifest-derived ExternalServices with AST call sites.
|
|
51
37
|
for (const svc of manifestExternalServices) {
|
|
52
38
|
const sites = agg.aiSdkCallSites.get(svc.package);
|
|
53
39
|
if (sites)
|
|
54
40
|
svc.callSites.push(...sites);
|
|
55
41
|
}
|
|
56
|
-
// Augment manifest-derived DataStores with import-evidence from source.
|
|
57
42
|
for (const store of manifestDataStores) {
|
|
58
43
|
if (!store.client)
|
|
59
44
|
continue;
|
|
@@ -69,16 +54,11 @@ export const typescriptAdapter = {
|
|
|
69
54
|
};
|
|
70
55
|
},
|
|
71
56
|
};
|
|
72
|
-
/**
|
|
73
|
-
* Walk up from a source file's path to find the closest package.json
|
|
74
|
-
* we parsed; return the framework hint from that manifest.
|
|
75
|
-
*/
|
|
76
57
|
function frameworkFromOwningManifest(sourceFile, manifests) {
|
|
77
58
|
const sourceDir = path.posix.dirname(sourceFile);
|
|
78
59
|
const candidates = manifests
|
|
79
60
|
.map((m) => ({ m, dir: path.posix.dirname(m.filePath) }))
|
|
80
61
|
.filter(({ dir }) => sourceDir === dir || sourceDir.startsWith(dir + "/"))
|
|
81
|
-
.sort((a, b) => b.dir.length - a.dir.length);
|
|
62
|
+
.sort((a, b) => b.dir.length - a.dir.length);
|
|
82
63
|
return candidates[0] ? detectFrameworkFromManifest(candidates[0].m) : undefined;
|
|
83
64
|
}
|
|
84
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeScript / JavaScript manifest analysis.
|
|
3
|
-
*
|
|
4
|
-
* Reads package.json files (root + workspaces) to classify dependencies
|
|
5
|
-
* into the categories the threat-model graph cares about. Used both for
|
|
6
|
-
* the manifests block of the output and as a hint for which AST queries
|
|
7
|
-
* are worth running on which files.
|
|
8
|
-
*/
|
|
9
1
|
import type { ExtractedExternalService, ExtractedDataStore, ManifestSummary } from "../../types.js";
|
|
10
2
|
export interface PackageJson {
|
|
11
3
|
name?: string;
|
|
@@ -28,14 +20,8 @@ export interface ParsedManifest {
|
|
|
28
20
|
packageName?: string;
|
|
29
21
|
deps: Record<string, string>;
|
|
30
22
|
}
|
|
31
|
-
/**
|
|
32
|
-
* Read every package.json, return per-file dependency maps. Combines
|
|
33
|
-
* dependencies + devDependencies (we want both — devDeps include things
|
|
34
|
-
* like @types that signal use, plus dev-only auth packages).
|
|
35
|
-
*/
|
|
36
23
|
export declare function readManifests(rootDir: string, manifestFiles: string[]): Promise<ParsedManifest[]>;
|
|
37
24
|
export declare function summarizeManifests(parsed: ParsedManifest[]): ManifestSummary[];
|
|
38
25
|
export declare function findExternalServices(parsed: ParsedManifest[]): ExtractedExternalService[];
|
|
39
26
|
export declare function findDataStores(parsed: ParsedManifest[]): ExtractedDataStore[];
|
|
40
|
-
/** Pick the most likely web framework for a manifest's owning package. */
|
|
41
27
|
export declare function detectFrameworkFromManifest(m: ParsedManifest): string | undefined;
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeScript / JavaScript manifest analysis.
|
|
3
|
-
*
|
|
4
|
-
* Reads package.json files (root + workspaces) to classify dependencies
|
|
5
|
-
* into the categories the threat-model graph cares about. Used both for
|
|
6
|
-
* the manifests block of the output and as a hint for which AST queries
|
|
7
|
-
* are worth running on which files.
|
|
8
|
-
*/
|
|
9
1
|
import * as fs from "node:fs/promises";
|
|
10
2
|
import * as path from "node:path";
|
|
11
3
|
export const WEB_FRAMEWORK_PACKAGES = {
|
|
@@ -22,7 +14,7 @@ export const WEB_FRAMEWORK_PACKAGES = {
|
|
|
22
14
|
"apollo-server-express": "express",
|
|
23
15
|
};
|
|
24
16
|
export const DATA_STORE_PACKAGES = {
|
|
25
|
-
"@prisma/client": { kind: "postgres", client: "@prisma/client" },
|
|
17
|
+
"@prisma/client": { kind: "postgres", client: "@prisma/client" },
|
|
26
18
|
pg: { kind: "postgres", client: "pg" },
|
|
27
19
|
postgres: { kind: "postgres", client: "postgres" },
|
|
28
20
|
mongoose: { kind: "mongo", client: "mongoose" },
|
|
@@ -43,11 +35,6 @@ export const AI_SDK_PACKAGES = {
|
|
|
43
35
|
"@langchain/core": "LangChain",
|
|
44
36
|
llamaindex: "LlamaIndex",
|
|
45
37
|
};
|
|
46
|
-
/**
|
|
47
|
-
* Read every package.json, return per-file dependency maps. Combines
|
|
48
|
-
* dependencies + devDependencies (we want both — devDeps include things
|
|
49
|
-
* like @types that signal use, plus dev-only auth packages).
|
|
50
|
-
*/
|
|
51
38
|
export async function readManifests(rootDir, manifestFiles) {
|
|
52
39
|
const out = [];
|
|
53
40
|
for (const file of manifestFiles) {
|
|
@@ -68,7 +55,6 @@ export async function readManifests(rootDir, manifestFiles) {
|
|
|
68
55
|
});
|
|
69
56
|
}
|
|
70
57
|
catch {
|
|
71
|
-
// Skip broken JSON; not our job to validate the customer's manifests.
|
|
72
58
|
}
|
|
73
59
|
}
|
|
74
60
|
return out;
|
|
@@ -103,9 +89,6 @@ export function findExternalServices(parsed) {
|
|
|
103
89
|
callSites: [{ file: m.filePath, line: 1 }],
|
|
104
90
|
});
|
|
105
91
|
}
|
|
106
|
-
// Web frameworks — surface as external_dependency nodes so capsules with
|
|
107
|
-
// dependency-shaped relevance_filters (e.g. security.late-org-filter
|
|
108
|
-
// gating on express/fastify/etc.) can fire.
|
|
109
92
|
for (const [pkg, vendor] of Object.entries(WEB_FRAMEWORK_PACKAGES)) {
|
|
110
93
|
const ver = m.deps[pkg];
|
|
111
94
|
if (!ver)
|
|
@@ -153,7 +136,6 @@ export function findDataStores(parsed) {
|
|
|
153
136
|
}
|
|
154
137
|
return [...seen.values()];
|
|
155
138
|
}
|
|
156
|
-
/** Pick the most likely web framework for a manifest's owning package. */
|
|
157
139
|
export function detectFrameworkFromManifest(m) {
|
|
158
140
|
for (const [pkg, framework] of Object.entries(WEB_FRAMEWORK_PACKAGES)) {
|
|
159
141
|
if (m.deps[pkg])
|
|
@@ -181,4 +163,3 @@ function relPosix(rootDir, abs) {
|
|
|
181
163
|
const rel = path.relative(rootDir, abs);
|
|
182
164
|
return rel.split(path.sep).join("/");
|
|
183
165
|
}
|
|
184
|
-
//# sourceMappingURL=manifest.js.map
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* tree-sitter-typescript loader. Initializes the WASM grammar lazily and
|
|
3
|
-
* caches the parser+language for the rest of the run.
|
|
4
|
-
*
|
|
5
|
-
* @vscode/tree-sitter-wasm bundles the prebuilt .wasm files so we don't
|
|
6
|
-
* need a build step on the user's machine. Loading a .wasm grammar is
|
|
7
|
-
* O(50ms); parsing a TS file is O(low ms) per file.
|
|
8
|
-
*/
|
|
9
1
|
import { Parser } from "web-tree-sitter";
|
|
10
2
|
export declare function getParsers(): Promise<{
|
|
11
3
|
parser: Parser;
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* tree-sitter-typescript loader. Initializes the WASM grammar lazily and
|
|
3
|
-
* caches the parser+language for the rest of the run.
|
|
4
|
-
*
|
|
5
|
-
* @vscode/tree-sitter-wasm bundles the prebuilt .wasm files so we don't
|
|
6
|
-
* need a build step on the user's machine. Loading a .wasm grammar is
|
|
7
|
-
* O(50ms); parsing a TS file is O(low ms) per file.
|
|
8
|
-
*/
|
|
9
1
|
import { createRequire } from "node:module";
|
|
10
2
|
import * as path from "node:path";
|
|
11
3
|
import { Parser, Language } from "web-tree-sitter";
|
|
@@ -30,4 +22,3 @@ export function getParsers() {
|
|
|
30
22
|
export function pickParserForFile(file, parser, tsx) {
|
|
31
23
|
return file.endsWith(".tsx") || file.endsWith(".jsx") ? tsx : parser;
|
|
32
24
|
}
|
|
33
|
-
//# sourceMappingURL=parser.js.map
|
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AST scanner for TypeScript / JavaScript source files.
|
|
3
|
-
*
|
|
4
|
-
* For each file: parses with tree-sitter-typescript, walks the tree
|
|
5
|
-
* looking for:
|
|
6
|
-
*
|
|
7
|
-
* 1. `import` / `require` statements naming any tracked package
|
|
8
|
-
* (AI SDKs, web frameworks, DB clients) → import-evidence + extra
|
|
9
|
-
* ExternalService call sites
|
|
10
|
-
* 2. Express-style route declarations:
|
|
11
|
-
* app.METHOD("/path", ...)
|
|
12
|
-
* router.METHOD("/path", ...)
|
|
13
|
-
* server.METHOD("/path", ...)
|
|
14
|
-
* where METHOD is one of GET/POST/PUT/DELETE/PATCH/ALL/USE
|
|
15
|
-
* → HTTP-route-evidence on a component derived from the file
|
|
16
|
-
*
|
|
17
|
-
* Privacy invariant: we only ever emit identifier names, file paths,
|
|
18
|
-
* line numbers, dependency identifiers, and HTTP method/path strings.
|
|
19
|
-
* Function bodies and inline values are never read past the first arg
|
|
20
|
-
* of a route call.
|
|
21
|
-
*/
|
|
22
1
|
import type { EvidenceLocation, Evidence, HttpRouteEvidence, ImportEvidence } from "../../types.js";
|
|
23
2
|
export interface FileScanResult {
|
|
24
3
|
file: string;
|
|
@@ -27,7 +6,6 @@ export interface FileScanResult {
|
|
|
27
6
|
}
|
|
28
7
|
export declare function scanFile(absPath: string, repoRel: string): Promise<FileScanResult>;
|
|
29
8
|
export interface ScannedAggregates {
|
|
30
|
-
/** Per-component findings (one per source file with relevant evidence). */
|
|
31
9
|
components: Array<{
|
|
32
10
|
name: string;
|
|
33
11
|
sourceFile: string;
|
|
@@ -35,9 +13,7 @@ export interface ScannedAggregates {
|
|
|
35
13
|
routes: HttpRouteEvidence[];
|
|
36
14
|
imports: ImportEvidence[];
|
|
37
15
|
}>;
|
|
38
|
-
/** Extra ExternalService call-site evidence beyond what the manifests gave. */
|
|
39
16
|
aiSdkCallSites: Map<string, EvidenceLocation[]>;
|
|
40
|
-
/** Extra data-store evidence (when AST shows usage of e.g. `new Pool()` etc.; v1 just imports). */
|
|
41
17
|
dataStoreEvidence: Map<string, Evidence[]>;
|
|
42
18
|
}
|
|
43
19
|
export declare function aggregate(scans: FileScanResult[]): ScannedAggregates;
|
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AST scanner for TypeScript / JavaScript source files.
|
|
3
|
-
*
|
|
4
|
-
* For each file: parses with tree-sitter-typescript, walks the tree
|
|
5
|
-
* looking for:
|
|
6
|
-
*
|
|
7
|
-
* 1. `import` / `require` statements naming any tracked package
|
|
8
|
-
* (AI SDKs, web frameworks, DB clients) → import-evidence + extra
|
|
9
|
-
* ExternalService call sites
|
|
10
|
-
* 2. Express-style route declarations:
|
|
11
|
-
* app.METHOD("/path", ...)
|
|
12
|
-
* router.METHOD("/path", ...)
|
|
13
|
-
* server.METHOD("/path", ...)
|
|
14
|
-
* where METHOD is one of GET/POST/PUT/DELETE/PATCH/ALL/USE
|
|
15
|
-
* → HTTP-route-evidence on a component derived from the file
|
|
16
|
-
*
|
|
17
|
-
* Privacy invariant: we only ever emit identifier names, file paths,
|
|
18
|
-
* line numbers, dependency identifiers, and HTTP method/path strings.
|
|
19
|
-
* Function bodies and inline values are never read past the first arg
|
|
20
|
-
* of a route call.
|
|
21
|
-
*/
|
|
22
1
|
import * as fs from "node:fs/promises";
|
|
23
2
|
import { getParsers, pickParserForFile } from "./parser.js";
|
|
24
3
|
import { AI_SDK_PACKAGES, DATA_STORE_PACKAGES, WEB_FRAMEWORK_PACKAGES, } from "./manifest.js";
|
|
@@ -75,35 +54,22 @@ function walk(node, visit) {
|
|
|
75
54
|
walk(child, visit);
|
|
76
55
|
}
|
|
77
56
|
}
|
|
78
|
-
/** Pull the string literal from `import … from "<here>"`. */
|
|
79
57
|
function extractImportSource(node) {
|
|
80
|
-
// import_statement → ... → (string (string_fragment))
|
|
81
58
|
const stringNode = node.children.find((c) => c?.type === "string");
|
|
82
59
|
if (!stringNode)
|
|
83
60
|
return null;
|
|
84
61
|
const frag = stringNode.namedChildren.find((c) => c?.type === "string_fragment");
|
|
85
62
|
return frag?.text ?? null;
|
|
86
63
|
}
|
|
87
|
-
/** Map a package import to a tracked-package identifier, allowing for sub-paths. */
|
|
88
64
|
function trackedPackageMatch(pkg) {
|
|
89
65
|
if (TRACKED_PACKAGES.has(pkg))
|
|
90
66
|
return pkg;
|
|
91
|
-
// sub-paths: "@anthropic-ai/sdk/foo" → "@anthropic-ai/sdk"
|
|
92
67
|
for (const tracked of TRACKED_PACKAGES) {
|
|
93
68
|
if (pkg.startsWith(tracked + "/"))
|
|
94
69
|
return tracked;
|
|
95
70
|
}
|
|
96
71
|
return null;
|
|
97
72
|
}
|
|
98
|
-
/**
|
|
99
|
-
* Identify Express-style route calls. Only inspects the AST shape; never
|
|
100
|
-
* reads the handler-function body.
|
|
101
|
-
*
|
|
102
|
-
* Matches:
|
|
103
|
-
* <ROUTER_IDENT>.<METHOD>("/path", ...)
|
|
104
|
-
*
|
|
105
|
-
* Where the second-and-onward args are deliberately ignored.
|
|
106
|
-
*/
|
|
107
73
|
function extractRouteCall(node) {
|
|
108
74
|
const fn = node.namedChildren.find((c) => c?.type === "member_expression");
|
|
109
75
|
const args = node.namedChildren.find((c) => c?.type === "arguments");
|
|
@@ -119,7 +85,6 @@ function extractRouteCall(node) {
|
|
|
119
85
|
return null;
|
|
120
86
|
if (!HTTP_METHODS.has(methodName))
|
|
121
87
|
return null;
|
|
122
|
-
// First arg should be a string literal — the route path.
|
|
123
88
|
const firstArg = args.namedChildren[0];
|
|
124
89
|
if (!firstArg || firstArg.type !== "string")
|
|
125
90
|
return null;
|
|
@@ -135,8 +100,6 @@ export function aggregate(scans) {
|
|
|
135
100
|
for (const s of scans) {
|
|
136
101
|
if (s.routes.length === 0 && s.imports.length === 0)
|
|
137
102
|
continue;
|
|
138
|
-
// Tag SDK call sites. Each tracked import of an AI SDK package
|
|
139
|
-
// counts as a call site for that vendor, on top of the manifest hit.
|
|
140
103
|
for (const imp of s.imports) {
|
|
141
104
|
if (AI_SDK_PACKAGES[imp.package]) {
|
|
142
105
|
const arr = aiSdkCallSites.get(imp.package) ?? [];
|
|
@@ -152,8 +115,6 @@ export function aggregate(scans) {
|
|
|
152
115
|
}
|
|
153
116
|
if (s.routes.length === 0)
|
|
154
117
|
continue;
|
|
155
|
-
// Derive a friendly component name from the file path (the deepest
|
|
156
|
-
// meaningful directory). e.g. src/auth/login.ts → "auth".
|
|
157
118
|
const name = deriveComponentName(s.file);
|
|
158
119
|
const framework = detectFrameworkFromImports(s.imports);
|
|
159
120
|
components.push({
|
|
@@ -168,10 +129,7 @@ export function aggregate(scans) {
|
|
|
168
129
|
}
|
|
169
130
|
function deriveComponentName(filePath) {
|
|
170
131
|
const segs = filePath.split("/");
|
|
171
|
-
// Drop "src" / "lib" / "app" prefixes so the name is meaningful.
|
|
172
132
|
const start = ["src", "lib", "app"].includes(segs[0]) ? 1 : 0;
|
|
173
|
-
// Use the parent directory as the component (e.g. "auth"), or the
|
|
174
|
-
// filename root if the file lives at the top level.
|
|
175
133
|
if (segs.length - start >= 2)
|
|
176
134
|
return segs[start];
|
|
177
135
|
const last = segs[segs.length - 1];
|
|
@@ -185,4 +143,3 @@ function detectFrameworkFromImports(imports) {
|
|
|
185
143
|
}
|
|
186
144
|
return undefined;
|
|
187
145
|
}
|
|
188
|
-
//# sourceMappingURL=scanner.js.map
|
|
@@ -1,35 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Build a RepoGraphArtifactV1 from an ExtractionResult.
|
|
3
|
-
*
|
|
4
|
-
* The existing extractor emits an entity-list shape (components,
|
|
5
|
-
* externalServices, dataStores, manifests). This builder is the canonical
|
|
6
|
-
* translator from that internal intermediate into the graph artifact that
|
|
7
|
-
* downstream pattern matching, threat modeling, and evidence storage all
|
|
8
|
-
* consume.
|
|
9
|
-
*
|
|
10
|
-
* Plan: docs/plans/LOCAL-REPO-GRAPH-IMPLEMENTATION.md (Phase 1)
|
|
11
|
-
* Schema: schemas/repo-graph-artifact.schema.json
|
|
12
|
-
*
|
|
13
|
-
* v1 scope (locked): three node types (service, endpoint, external_dependency)
|
|
14
|
-
* and two edge types (exposes, depends_on). Datastores and the corresponding
|
|
15
|
-
* reads/writes edges are deferred to Phase 1.5.
|
|
16
|
-
*
|
|
17
|
-
* Lane assignment for v1: every node and edge produced by deterministic
|
|
18
|
-
* adapter output is `trusted`. Inferred-lane nodes are introduced later by
|
|
19
|
-
* the matching engine (Phase 3), not by extraction.
|
|
20
|
-
*/
|
|
21
1
|
import type { ExtractionResult } from "./types.js";
|
|
22
2
|
import type { RepoGraphArtifactV1, AnalysisMode } from "./graph-types.js";
|
|
23
3
|
export interface BuildOptions {
|
|
24
|
-
/** Resolved Application ID (optional at extraction time; required before persistence). */
|
|
25
4
|
applicationId?: string;
|
|
26
|
-
/** Canonical repo identifier — typically a hash of the git remote URL. */
|
|
27
5
|
repoId?: string;
|
|
28
|
-
/** Git commit SHA. */
|
|
29
6
|
commitSha?: string;
|
|
30
|
-
/** Git branch / ref. */
|
|
31
7
|
branch?: string;
|
|
32
|
-
/** Whether this artifact was produced locally (default) or via cloud clone fallback. */
|
|
33
8
|
analysisMode?: AnalysisMode;
|
|
34
9
|
}
|
|
35
10
|
export declare function buildRepoGraphArtifact(result: ExtractionResult, opts?: BuildOptions): RepoGraphArtifactV1;
|