@zivis/cli 0.1.0-alpha.32 → 0.1.0-alpha.33

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.
@@ -0,0 +1,283 @@
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
+ const TRUSTED_LANE = "trusted";
22
+ const TRUSTED_SOURCE = "inspect.trusted";
23
+ export function buildRepoGraphArtifact(result, opts = {}) {
24
+ const nodes = [];
25
+ const edges = [];
26
+ // Service nodes — every component that isn't an external service or pure datastore.
27
+ // The existing extractor models datastores via `dataStores` and external SDKs via
28
+ // `externalServices`; `components` covers code-defined services and frontends.
29
+ // Skip components that arrive with empty evidence — schema requires minItems: 1.
30
+ const serviceById = new Map();
31
+ for (const component of result.components) {
32
+ if (component.kind === "external_service" || component.kind === "data_store") {
33
+ continue;
34
+ }
35
+ if (component.evidence.length === 0)
36
+ continue;
37
+ const node = buildServiceNode(component);
38
+ serviceById.set(node.id, node);
39
+ nodes.push(node);
40
+ }
41
+ // Endpoint nodes + exposes edges — derived from each service's http_route evidence.
42
+ // Non-canonical methods (e.g. Express `app.use()` mounts emitted by the TS adapter)
43
+ // are dropped here — they're middleware mounts, not endpoints. Fixing them belongs
44
+ // upstream in the adapter; the graph-builder enforces the contract.
45
+ for (const component of result.components) {
46
+ const owningServiceId = serviceIdFor(component);
47
+ if (!serviceById.has(owningServiceId))
48
+ continue;
49
+ const seenEndpoints = new Set();
50
+ for (const ev of component.evidence) {
51
+ if (ev.kind !== "http_route")
52
+ continue;
53
+ const method = canonicalMethod(ev.method);
54
+ if (!method)
55
+ continue;
56
+ const endpointNode = buildEndpointNode(owningServiceId, component.language, ev, method);
57
+ if (seenEndpoints.has(endpointNode.id))
58
+ continue;
59
+ seenEndpoints.add(endpointNode.id);
60
+ nodes.push(endpointNode);
61
+ edges.push(buildExposesEdge(owningServiceId, endpointNode.id, ev));
62
+ }
63
+ }
64
+ // External dependency nodes — one per (registry, package) tuple.
65
+ // Manifest-only deps (no callSites) fall back to manifest evidence so they still
66
+ // satisfy the schema's evidence: minItems: 1 invariant.
67
+ const manifestEvidenceByPackage = indexManifestsByPackage(result);
68
+ const depById = new Map();
69
+ for (const ext of result.externalServices) {
70
+ const node = buildExternalDependencyNode(ext, manifestEvidenceByPackage.get(ext.package) ?? []);
71
+ if (depById.has(node.id))
72
+ continue;
73
+ if (node.evidence.length === 0)
74
+ continue; // truly orphaned — skip
75
+ depById.set(node.id, node);
76
+ nodes.push(node);
77
+ }
78
+ // File-to-service index for resolving callSites into depends_on edges.
79
+ const fileToServiceId = buildFileToServiceIndex(result.components, serviceById);
80
+ for (const ext of result.externalServices) {
81
+ const depId = externalDepId(ext);
82
+ const seenServiceIds = new Set();
83
+ const evidenceByService = new Map();
84
+ for (const callSite of ext.callSites) {
85
+ const serviceId = fileToServiceId.get(callSite.file);
86
+ if (!serviceId)
87
+ continue;
88
+ seenServiceIds.add(serviceId);
89
+ const list = evidenceByService.get(serviceId) ?? [];
90
+ list.push(toImportEvidence(callSite, ext.package));
91
+ evidenceByService.set(serviceId, list);
92
+ }
93
+ for (const serviceId of seenServiceIds) {
94
+ edges.push(buildDependsOnEdge(serviceId, depId, evidenceByService.get(serviceId) ?? []));
95
+ }
96
+ }
97
+ const provenance = {
98
+ root_dir: result.scope.rootDir,
99
+ analysis_mode: opts.analysisMode ?? "local",
100
+ ...(opts.repoId ? { repo_id: opts.repoId } : {}),
101
+ ...(opts.commitSha ? { commit_sha: opts.commitSha } : {}),
102
+ ...(opts.branch ? { branch: opts.branch } : {}),
103
+ ...(opts.applicationId ? { application_id: opts.applicationId } : {}),
104
+ };
105
+ const languagesFromManifests = new Set(result.manifests.map((m) => normalizeLanguage(m.language)).filter(Boolean));
106
+ return {
107
+ version: "1.0.0",
108
+ kind: "repo_graph_artifact",
109
+ extracted_at: result.extractedAt,
110
+ extractor: result.extractor,
111
+ provenance,
112
+ scope: {
113
+ files_scanned: result.scope.filesScanned,
114
+ files_skipped: result.scope.filesSkipped,
115
+ duration_ms: result.scope.durationMs,
116
+ languages: [...languagesFromManifests],
117
+ },
118
+ nodes,
119
+ edges,
120
+ };
121
+ }
122
+ // ── Node builders ──
123
+ function buildServiceNode(component) {
124
+ const id = serviceIdFor(component);
125
+ return {
126
+ id,
127
+ type: "service",
128
+ name: component.name,
129
+ lane: TRUSTED_LANE,
130
+ source: TRUSTED_SOURCE,
131
+ confidence: 1,
132
+ language: normalizeLanguage(component.language),
133
+ evidence: component.evidence.map(toEvidenceSpan),
134
+ attributes: {
135
+ ...(component.framework ? { framework: component.framework } : {}),
136
+ source_files: component.sourceFiles,
137
+ },
138
+ };
139
+ }
140
+ function buildEndpointNode(serviceId, language, ev, method) {
141
+ const id = `endpoint::${stripPrefix(serviceId, "service::")}::${method}::${ev.path}`;
142
+ return {
143
+ id,
144
+ type: "endpoint",
145
+ name: `${method} ${ev.path}`,
146
+ lane: TRUSTED_LANE,
147
+ source: TRUSTED_SOURCE,
148
+ confidence: 1,
149
+ language: normalizeLanguage(language),
150
+ evidence: [toEvidenceSpan(ev)],
151
+ attributes: { method, path: ev.path },
152
+ };
153
+ }
154
+ function buildExternalDependencyNode(ext, manifestFallback) {
155
+ const registry = registryFor(ext);
156
+ const evidence = ext.callSites.length > 0
157
+ ? ext.callSites.map((cs) => toImportEvidence(cs, ext.package))
158
+ : manifestFallback;
159
+ return {
160
+ id: externalDepId(ext),
161
+ type: "external_dependency",
162
+ name: ext.name,
163
+ lane: TRUSTED_LANE,
164
+ source: TRUSTED_SOURCE,
165
+ confidence: 1,
166
+ evidence,
167
+ attributes: {
168
+ package: ext.package,
169
+ registry,
170
+ ...(ext.version ? { version: ext.version } : {}),
171
+ ...(ext.kind ? { kind: ext.kind } : {}),
172
+ },
173
+ };
174
+ }
175
+ function indexManifestsByPackage(result) {
176
+ const idx = new Map();
177
+ for (const m of result.manifests) {
178
+ for (const pkg of Object.keys(m.dependencies)) {
179
+ const span = { file: m.file, kind: "manifest", detail: { package: pkg } };
180
+ const list = idx.get(pkg) ?? [];
181
+ list.push(span);
182
+ idx.set(pkg, list);
183
+ }
184
+ }
185
+ return idx;
186
+ }
187
+ function buildExposesEdge(serviceId, endpointId, ev) {
188
+ return {
189
+ id: `exposes::${serviceId}::${endpointId}`,
190
+ type: "exposes",
191
+ source_id: serviceId,
192
+ target_id: endpointId,
193
+ lane: TRUSTED_LANE,
194
+ source: TRUSTED_SOURCE,
195
+ confidence: 1,
196
+ evidence: [toEvidenceSpan(ev)],
197
+ };
198
+ }
199
+ function buildDependsOnEdge(serviceId, depId, evidence) {
200
+ return {
201
+ id: `depends_on::${serviceId}::${depId}`,
202
+ type: "depends_on",
203
+ source_id: serviceId,
204
+ target_id: depId,
205
+ lane: TRUSTED_LANE,
206
+ source: TRUSTED_SOURCE,
207
+ confidence: 1,
208
+ evidence,
209
+ };
210
+ }
211
+ // ── Helpers ──
212
+ function serviceIdFor(component) {
213
+ return `service::${component.language}::${component.name}`;
214
+ }
215
+ function externalDepId(ext) {
216
+ const registry = registryFor(ext);
217
+ return `external_dependency::${registry}::${ext.package}`;
218
+ }
219
+ function registryFor(ext) {
220
+ // Heuristic — the existing extractor doesn't tag registry, so derive from package shape.
221
+ if (ext.package.startsWith("github.com/"))
222
+ return "go";
223
+ if (ext.package.startsWith("@") || /^[a-z0-9-]+$/.test(ext.package)) {
224
+ // npm + pypi share many shapes; lean npm by default since most ai_sdks live there.
225
+ // PyPI-only packages can be retagged once adapters expose registry directly.
226
+ return "npm";
227
+ }
228
+ return "npm";
229
+ }
230
+ const CANONICAL_METHODS = new Set([
231
+ "GET",
232
+ "POST",
233
+ "PUT",
234
+ "PATCH",
235
+ "DELETE",
236
+ "HEAD",
237
+ "OPTIONS",
238
+ "WS",
239
+ "SSE",
240
+ "RPC",
241
+ ]);
242
+ function canonicalMethod(method) {
243
+ const upper = method.toUpperCase();
244
+ return CANONICAL_METHODS.has(upper) ? upper : undefined;
245
+ }
246
+ function normalizeLanguage(lang) {
247
+ return lang;
248
+ }
249
+ function buildFileToServiceIndex(components, servicesById) {
250
+ const idx = new Map();
251
+ for (const component of components) {
252
+ const id = serviceIdFor(component);
253
+ if (!servicesById.has(id))
254
+ continue;
255
+ for (const file of component.sourceFiles) {
256
+ if (!idx.has(file))
257
+ idx.set(file, id);
258
+ }
259
+ }
260
+ return idx;
261
+ }
262
+ function toEvidenceSpan(ev) {
263
+ const base = { file: ev.file, start_line: ev.line, kind: ev.kind };
264
+ if (ev.kind === "http_route") {
265
+ return { ...base, detail: { method: ev.method, path: ev.path } };
266
+ }
267
+ if (ev.kind === "import") {
268
+ return { ...base, detail: { package: ev.package } };
269
+ }
270
+ return base;
271
+ }
272
+ function toImportEvidence(loc, pkg) {
273
+ return {
274
+ file: loc.file,
275
+ start_line: loc.line,
276
+ kind: "import",
277
+ detail: { package: pkg },
278
+ };
279
+ }
280
+ function stripPrefix(value, prefix) {
281
+ return value.startsWith(prefix) ? value.slice(prefix.length) : value;
282
+ }
283
+ //# sourceMappingURL=graph-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-builder.js","sourceRoot":"","sources":["../../../src/internal/extractor/graph-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * TypeScript interfaces for RepoGraphArtifactV1.
3
+ *
4
+ * Canonical source: schemas/repo-graph-artifact.schema.json
5
+ * Plan: docs/plans/LOCAL-REPO-GRAPH-IMPLEMENTATION.md (Phase 1)
6
+ *
7
+ * The JSON schema is authoritative — these types must stay in sync. A
8
+ * repo-level test (planned) validates extractor output against the schema
9
+ * to catch drift.
10
+ */
11
+ export type Lane = "trusted" | "inferred";
12
+ export type Source = "inspect.trusted" | "inspect.inferred";
13
+ export type GraphLanguage = "typescript" | "javascript" | "python" | "go";
14
+ export type AnalysisMode = "local" | "cloud";
15
+ export type EvidenceKind = "import" | "http_route" | "config" | "manifest" | "decorator" | "annotation";
16
+ export type NodeType = "service" | "endpoint" | "external_dependency";
17
+ export type EdgeType = "exposes" | "depends_on";
18
+ export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS" | "WS" | "SSE" | "RPC";
19
+ export type DependencyRegistry = "npm" | "pypi" | "go";
20
+ export interface EvidenceSpan {
21
+ file: string;
22
+ start_line?: number;
23
+ end_line?: number;
24
+ kind: EvidenceKind;
25
+ detail?: Record<string, unknown>;
26
+ }
27
+ export interface ServiceAttributes {
28
+ framework?: string;
29
+ source_files?: string[];
30
+ }
31
+ export interface EndpointAttributes {
32
+ method: HttpMethod;
33
+ path: string;
34
+ }
35
+ export interface ExternalDependencyAttributes {
36
+ package: string;
37
+ version?: string;
38
+ registry: DependencyRegistry;
39
+ kind?: string;
40
+ }
41
+ export type NodeAttributes = ServiceAttributes | EndpointAttributes | ExternalDependencyAttributes;
42
+ interface BaseNode {
43
+ id: string;
44
+ name: string;
45
+ lane: Lane;
46
+ source: Source;
47
+ confidence?: number;
48
+ language?: GraphLanguage;
49
+ evidence: EvidenceSpan[];
50
+ }
51
+ export interface ServiceNode extends BaseNode {
52
+ type: "service";
53
+ attributes?: ServiceAttributes;
54
+ }
55
+ export interface EndpointNode extends BaseNode {
56
+ type: "endpoint";
57
+ attributes: EndpointAttributes;
58
+ }
59
+ export interface ExternalDependencyNode extends BaseNode {
60
+ type: "external_dependency";
61
+ attributes: ExternalDependencyAttributes;
62
+ }
63
+ export type GraphNode = ServiceNode | EndpointNode | ExternalDependencyNode;
64
+ export interface GraphEdge {
65
+ id: string;
66
+ type: EdgeType;
67
+ source_id: string;
68
+ target_id: string;
69
+ lane: Lane;
70
+ source: Source;
71
+ confidence?: number;
72
+ evidence?: EvidenceSpan[];
73
+ attributes?: Record<string, unknown>;
74
+ }
75
+ export interface GraphProvenance {
76
+ root_dir: string;
77
+ repo_id?: string;
78
+ commit_sha?: string;
79
+ branch?: string;
80
+ application_id?: string;
81
+ analysis_mode: AnalysisMode;
82
+ }
83
+ export interface GraphScope {
84
+ files_scanned: number;
85
+ files_skipped: number;
86
+ duration_ms: number;
87
+ languages?: GraphLanguage[];
88
+ }
89
+ export interface RepoGraphArtifactV1 {
90
+ version: "1.0.0";
91
+ kind: "repo_graph_artifact";
92
+ extracted_at: string;
93
+ extractor: string;
94
+ provenance: GraphProvenance;
95
+ scope: GraphScope;
96
+ nodes: GraphNode[];
97
+ edges: GraphEdge[];
98
+ }
99
+ export {};
@@ -0,0 +1,12 @@
1
+ /**
2
+ * TypeScript interfaces for RepoGraphArtifactV1.
3
+ *
4
+ * Canonical source: schemas/repo-graph-artifact.schema.json
5
+ * Plan: docs/plans/LOCAL-REPO-GRAPH-IMPLEMENTATION.md (Phase 1)
6
+ *
7
+ * The JSON schema is authoritative — these types must stay in sync. A
8
+ * repo-level test (planned) validates extractor output against the schema
9
+ * to catch drift.
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=graph-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-types.js","sourceRoot":"","sources":["../../../src/internal/extractor/graph-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Local pattern pack reader.
3
+ *
4
+ * The pack ships bundled inside the @zivis/cli npm package at
5
+ * `dist/pattern-packs/<pack-id>-<version>/`. On first use we copy it to
6
+ * `~/Library/Caches/zivis/pattern-packs/<pack-id>-<version>/` so future
7
+ * runs read from the user cache directly.
8
+ *
9
+ * The reader serves both:
10
+ * - `zivis inspect` matcher (Phase 3) — deterministic + inference
11
+ * candidates evaluated against the local repo graph artifact.
12
+ * - MCP tools that surface relevant capsules mid-IDE-conversation.
13
+ *
14
+ * Plan: docs/plans/LOCAL-REPO-GRAPH-IMPLEMENTATION.md (Phase 2A)
15
+ * Schemas:
16
+ * - schemas/pattern-pack-manifest.schema.json (manifest.json)
17
+ * - schemas/pattern-detection-card.schema.json (capsule yaml)
18
+ */
19
+ import type { RepoGraphArtifactV1, GraphLanguage } from "../extractor/graph-types.js";
20
+ export interface PackManifest {
21
+ schema_version: "1.0.0";
22
+ pack_id: string;
23
+ pack_name: string;
24
+ version: string;
25
+ built_at: string;
26
+ tier: "public_teaser" | "public" | "customer_safe";
27
+ description?: string;
28
+ capsules: ManifestCapsuleEntry[];
29
+ prompts: ManifestPromptEntry[];
30
+ }
31
+ export interface ManifestCapsuleEntry {
32
+ id: string;
33
+ version: string;
34
+ path: string;
35
+ sha256: string;
36
+ category?: string;
37
+ lifecycle?: string;
38
+ applicable_languages?: string[];
39
+ }
40
+ export interface ManifestPromptEntry {
41
+ path: string;
42
+ sha256: string;
43
+ capsule_id?: string;
44
+ }
45
+ export interface RelevanceTerm {
46
+ dependency?: string;
47
+ direct_only?: boolean;
48
+ language?: string;
49
+ framework?: string;
50
+ evidence?: string;
51
+ }
52
+ export interface RelevanceFilter {
53
+ any_of?: RelevanceTerm[];
54
+ all_of?: RelevanceTerm[];
55
+ none_of?: RelevanceTerm[];
56
+ }
57
+ export interface Capsule {
58
+ id: string;
59
+ slug: string;
60
+ version: string;
61
+ category: string;
62
+ title?: string;
63
+ headline?: string;
64
+ description?: string;
65
+ detection_tier: "public" | "proprietary";
66
+ scoring_tier: "public" | "proprietary";
67
+ applicable_languages: string[];
68
+ relevance_filter?: RelevanceFilter;
69
+ strategies: unknown[];
70
+ required_evidence_count: number;
71
+ threats?: unknown[];
72
+ lifecycle: "draft" | "active" | "deprecated";
73
+ sensitivity_level?: "public_teaser" | "customer_safe" | "zivis_confidential";
74
+ safe_summary?: string;
75
+ detect_when?: string;
76
+ risk_hints?: string[];
77
+ architectural_signals?: string[];
78
+ model_task_prompt_ref?: string;
79
+ expected_output_schema?: unknown;
80
+ minimum_context_required?: {
81
+ lines?: number;
82
+ symbols?: string[];
83
+ };
84
+ related_patterns?: string[];
85
+ repair_contract?: {
86
+ allowed?: string[];
87
+ forbidden?: string[];
88
+ };
89
+ validation_contract?: {
90
+ requires_tests_pass?: boolean;
91
+ requires_static_rules?: string[];
92
+ };
93
+ }
94
+ export interface PackHandle {
95
+ manifest: PackManifest;
96
+ rootDir: string;
97
+ }
98
+ /**
99
+ * Locate the active pack and ensure it's available in the user cache.
100
+ *
101
+ * Resolution order:
102
+ * 1. ZIVIS_PACK_DIR env var (override for tests / enterprise air-gap imports)
103
+ * 2. User cache, if present
104
+ * 3. Bundled pack inside @zivis/cli (copied to user cache on first use)
105
+ */
106
+ export declare function loadActivePack(packId?: string): Promise<PackHandle>;
107
+ export declare function getCapsule(handle: PackHandle, capsuleId: string): Promise<Capsule>;
108
+ export declare function getInferencePrompt(handle: PackHandle, ref: string): Promise<string>;
109
+ export declare function listCapsuleIds(handle: PackHandle): Promise<string[]>;
110
+ /**
111
+ * Evaluate each capsule's relevance_filter against the repo graph artifact
112
+ * and return the subset whose filter passes. Used by:
113
+ * - chat-session surface: "what patterns might apply to this codebase?"
114
+ * - matcher pre-filter: skip capsules that can't fire on this graph
115
+ */
116
+ export declare function findRelevantCapsules(handle: PackHandle, artifact: RepoGraphArtifactV1): Promise<Capsule[]>;
117
+ interface EvalContext {
118
+ packageNames: Set<string>;
119
+ languages: Set<GraphLanguage>;
120
+ evidenceKinds: Set<string>;
121
+ }
122
+ export declare function matchesRelevance(cap: Capsule, ctx: EvalContext): boolean;
123
+ export {};