@zivis/cli 0.1.0-alpha.33 → 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.
Files changed (133) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +31 -0
  3. package/dist/commands/app/index.d.ts +0 -8
  4. package/dist/commands/app/index.js +0 -12
  5. package/dist/commands/auth/bind.d.ts +0 -10
  6. package/dist/commands/auth/bind.js +0 -11
  7. package/dist/commands/auth/index.js +0 -1
  8. package/dist/commands/auth/init.js +12 -13
  9. package/dist/commands/auth/login.d.ts +0 -1
  10. package/dist/commands/auth/login.js +8 -3
  11. package/dist/commands/auth/logout.js +0 -3
  12. package/dist/commands/auth/sessions.js +0 -1
  13. package/dist/commands/auth/status.js +0 -2
  14. package/dist/commands/auth/token.d.ts +0 -13
  15. package/dist/commands/auth/token.js +0 -18
  16. package/dist/commands/check/index.d.ts +2 -0
  17. package/dist/commands/check/index.js +463 -0
  18. package/dist/commands/credits/index.js +0 -1
  19. package/dist/commands/inspect/index.d.ts +0 -15
  20. package/dist/commands/inspect/index.js +0 -23
  21. package/dist/commands/mcp/index.js +0 -9
  22. package/dist/commands/open/index.d.ts +0 -8
  23. package/dist/commands/open/index.js +0 -11
  24. package/dist/commands/scan/index.js +0 -6
  25. package/dist/commands/target/index.js +0 -3
  26. package/dist/commands/tm/index.js +0 -7
  27. package/dist/index.js +11 -1
  28. package/dist/internal/binding-token-mint.d.ts +0 -29
  29. package/dist/internal/binding-token-mint.js +0 -28
  30. package/dist/internal/extractor/adapters/go/index.d.ts +0 -4
  31. package/dist/internal/extractor/adapters/go/index.js +0 -6
  32. package/dist/internal/extractor/adapters/go/manifest.d.ts +0 -17
  33. package/dist/internal/extractor/adapters/go/manifest.js +1 -25
  34. package/dist/internal/extractor/adapters/go/parser.d.ts +0 -4
  35. package/dist/internal/extractor/adapters/go/parser.js +0 -5
  36. package/dist/internal/extractor/adapters/go/scanner.d.ts +0 -20
  37. package/dist/internal/extractor/adapters/go/scanner.js +0 -43
  38. package/dist/internal/extractor/adapters/python/index.d.ts +0 -3
  39. package/dist/internal/extractor/adapters/python/index.js +0 -4
  40. package/dist/internal/extractor/adapters/python/manifest.d.ts +0 -8
  41. package/dist/internal/extractor/adapters/python/manifest.js +3 -18
  42. package/dist/internal/extractor/adapters/python/parser.d.ts +0 -3
  43. package/dist/internal/extractor/adapters/python/parser.js +0 -4
  44. package/dist/internal/extractor/adapters/python/scanner.d.ts +0 -18
  45. package/dist/internal/extractor/adapters/python/scanner.js +1 -54
  46. package/dist/internal/extractor/adapters/typescript/index.d.ts +0 -7
  47. package/dist/internal/extractor/adapters/typescript/index.js +1 -21
  48. package/dist/internal/extractor/adapters/typescript/manifest.d.ts +0 -14
  49. package/dist/internal/extractor/adapters/typescript/manifest.js +1 -20
  50. package/dist/internal/extractor/adapters/typescript/parser.d.ts +0 -8
  51. package/dist/internal/extractor/adapters/typescript/parser.js +0 -9
  52. package/dist/internal/extractor/adapters/typescript/scanner.d.ts +0 -24
  53. package/dist/internal/extractor/adapters/typescript/scanner.js +0 -43
  54. package/dist/internal/extractor/graph-builder.d.ts +0 -25
  55. package/dist/internal/extractor/graph-builder.js +1 -39
  56. package/dist/internal/extractor/graph-types.d.ts +0 -10
  57. package/dist/internal/extractor/graph-types.js +0 -11
  58. package/dist/internal/extractor/index.d.ts +0 -14
  59. package/dist/internal/extractor/index.js +0 -13
  60. package/dist/internal/extractor/types.d.ts +0 -45
  61. package/dist/internal/extractor/types.js +0 -27
  62. package/dist/internal/extractor/walker.d.ts +0 -18
  63. package/dist/internal/extractor/walker.js +0 -18
  64. package/dist/internal/github-linkage-prompt.d.ts +7 -0
  65. package/dist/internal/github-linkage-prompt.js +95 -0
  66. package/dist/internal/ide-setup.d.ts +0 -23
  67. package/dist/internal/ide-setup.js +0 -53
  68. package/dist/internal/orgs.js +0 -1
  69. package/dist/internal/project-binding.d.ts +0 -1
  70. package/dist/internal/project-binding.js +0 -5
  71. package/dist/internal/target-auth/api-config.d.ts +0 -17
  72. package/dist/internal/target-auth/api-config.js +0 -18
  73. package/dist/internal/target-auth/config.d.ts +0 -12
  74. package/dist/internal/target-auth/config.js +0 -13
  75. package/dist/internal/target-auth/index.d.ts +0 -18
  76. package/dist/internal/target-auth/index.js +0 -19
  77. package/dist/internal/target-auth/keychain.d.ts +0 -18
  78. package/dist/internal/target-auth/keychain.js +3 -23
  79. package/dist/internal/target-auth/types.d.ts +0 -26
  80. package/dist/internal/target-auth/types.js +0 -10
  81. package/dist/internal/target-auth/workos.d.ts +0 -15
  82. package/dist/internal/target-auth/workos.js +0 -17
  83. package/package.json +13 -4
  84. package/dist/commands/app/index.js.map +0 -1
  85. package/dist/commands/auth/bind.js.map +0 -1
  86. package/dist/commands/auth/index.js.map +0 -1
  87. package/dist/commands/auth/init.js.map +0 -1
  88. package/dist/commands/auth/login.js.map +0 -1
  89. package/dist/commands/auth/logout.js.map +0 -1
  90. package/dist/commands/auth/sessions.js.map +0 -1
  91. package/dist/commands/auth/status.js.map +0 -1
  92. package/dist/commands/auth/token.js.map +0 -1
  93. package/dist/commands/credits/index.js.map +0 -1
  94. package/dist/commands/inspect/index.js.map +0 -1
  95. package/dist/commands/mcp/index.js.map +0 -1
  96. package/dist/commands/open/index.js.map +0 -1
  97. package/dist/commands/scan/index.js.map +0 -1
  98. package/dist/commands/target/index.js.map +0 -1
  99. package/dist/commands/tm/index.js.map +0 -1
  100. package/dist/index.js.map +0 -1
  101. package/dist/internal/binding-token-mint.js.map +0 -1
  102. package/dist/internal/extractor/adapters/go/index.js.map +0 -1
  103. package/dist/internal/extractor/adapters/go/manifest.js.map +0 -1
  104. package/dist/internal/extractor/adapters/go/parser.js.map +0 -1
  105. package/dist/internal/extractor/adapters/go/scanner.js.map +0 -1
  106. package/dist/internal/extractor/adapters/python/index.js.map +0 -1
  107. package/dist/internal/extractor/adapters/python/manifest.js.map +0 -1
  108. package/dist/internal/extractor/adapters/python/parser.js.map +0 -1
  109. package/dist/internal/extractor/adapters/python/scanner.js.map +0 -1
  110. package/dist/internal/extractor/adapters/typescript/index.js.map +0 -1
  111. package/dist/internal/extractor/adapters/typescript/manifest.js.map +0 -1
  112. package/dist/internal/extractor/adapters/typescript/parser.js.map +0 -1
  113. package/dist/internal/extractor/adapters/typescript/scanner.js.map +0 -1
  114. package/dist/internal/extractor/graph-builder.js.map +0 -1
  115. package/dist/internal/extractor/graph-types.js.map +0 -1
  116. package/dist/internal/extractor/index.js.map +0 -1
  117. package/dist/internal/extractor/types.js.map +0 -1
  118. package/dist/internal/extractor/walker.js.map +0 -1
  119. package/dist/internal/ide-setup.js.map +0 -1
  120. package/dist/internal/orgs.js.map +0 -1
  121. package/dist/internal/pattern-pack/index.d.ts +0 -123
  122. package/dist/internal/pattern-pack/index.js +0 -230
  123. package/dist/internal/pattern-pack/index.js.map +0 -1
  124. package/dist/internal/project-binding.js.map +0 -1
  125. package/dist/internal/target-auth/api-config.js.map +0 -1
  126. package/dist/internal/target-auth/config.js.map +0 -1
  127. package/dist/internal/target-auth/index.js.map +0 -1
  128. package/dist/internal/target-auth/keychain.js.map +0 -1
  129. package/dist/internal/target-auth/types.js.map +0 -1
  130. package/dist/internal/target-auth/workos.js.map +0 -1
  131. package/dist/pattern-packs/zivis-public-0.1.0/capsules/agents/privilege-separation.yaml +0 -228
  132. package/dist/pattern-packs/zivis-public-0.1.0/manifest.json +0 -31
  133. package/dist/pattern-packs/zivis-public-0.1.0/prompts/agents/privilege-separation/identify.md +0 -54
@@ -0,0 +1,463 @@
1
+ import * as crypto from "node:crypto";
2
+ import * as readline from "node:readline";
3
+ import * as fs from "node:fs/promises";
4
+ import * as path from "node:path";
5
+ import * as os from "node:os";
6
+ import { exec } from "node:child_process";
7
+ import { promisify } from "node:util";
8
+ import { resolveAuth } from "@zivis/mcp/auth";
9
+ import { detectProjectBinding, resolveConfigFromBinding } from "@zivis/mcp/project-binding";
10
+ import { DEFAULT_CONFIG } from "@zivis/mcp/types";
11
+ import { runMatcher } from "@zivis/mcp/matcher";
12
+ import { runExtractor } from "../../internal/extractor/index.js";
13
+ import { buildRepoGraphArtifact } from "../../internal/extractor/graph-builder.js";
14
+ import { loginCommand } from "../auth/login.js";
15
+ import { buildLinkagePrompt } from "../../internal/github-linkage-prompt.js";
16
+ const execAsync = promisify(exec);
17
+ const LLM_PACKAGE_NAMES = new Set([
18
+ "openai",
19
+ "@anthropic-ai/sdk",
20
+ "anthropic",
21
+ "@anthropic-ai/bedrock-sdk",
22
+ "@anthropic-ai/vertex-sdk",
23
+ "@google/generative-ai",
24
+ "@google-cloud/aiplatform",
25
+ "@google-cloud/vertexai",
26
+ "@aws-sdk/client-bedrock-runtime",
27
+ "@azure/openai",
28
+ "langchain",
29
+ "@langchain/core",
30
+ "@langchain/openai",
31
+ "@langchain/anthropic",
32
+ "llamaindex",
33
+ "ai",
34
+ "ollama",
35
+ "cohere-ai",
36
+ "@cohere-ai/sdk",
37
+ "replicate",
38
+ "mistralai",
39
+ "@mistralai/mistralai",
40
+ "groq-sdk",
41
+ "@groq/groq-sdk",
42
+ ]);
43
+ export function registerCheckCommands(program) {
44
+ program
45
+ .command("check")
46
+ .description("inspect this repo's architecture and post findings to your ZIVIS threat model")
47
+ .option("--cwd <path>", "repo root to inspect (default: cwd)")
48
+ .option("--format <fmt>", "output format: human or json", "human")
49
+ .option("--no-network", "skip server-side promotion; build the graph + run matcher locally only")
50
+ .action(async (opts) => {
51
+ const result = await runCheck(opts);
52
+ process.exit(result.exitCode);
53
+ });
54
+ }
55
+ async function runCheck(opts) {
56
+ const rootDir = opts.cwd ?? process.cwd();
57
+ const format = opts.format === "json" ? "json" : "human";
58
+ const network = opts.network !== false;
59
+ const config = { ...DEFAULT_CONFIG, ...resolveConfigFromBinding(rootDir) };
60
+ const authStatus = await resolveAuth(config);
61
+ if (authStatus.method === "none") {
62
+ const handled = await handleUnauthenticated({ format, config });
63
+ if (handled !== "continue") {
64
+ return { exitCode: handled };
65
+ }
66
+ const recheck = await resolveAuth(config);
67
+ if (recheck.method === "none") {
68
+ printIfHuman(format, "\nAuth did not complete. Run `zivis auth login` and try again.");
69
+ return { exitCode: 1 };
70
+ }
71
+ }
72
+ const creds = await resolveAuth(config);
73
+ const startedAt = Date.now();
74
+ const extractorOutput = await runExtractor({
75
+ rootDir,
76
+ extractorVersion: "check",
77
+ });
78
+ const gitMeta = await readGitMetadata(rootDir);
79
+ const binding = detectProjectBinding(rootDir);
80
+ const applicationId = binding?.binding.applicationId;
81
+ const repoId = deriveRepoId(gitMeta.remoteUrl, rootDir);
82
+ const artifact = buildRepoGraphArtifact(extractorOutput, {
83
+ applicationId,
84
+ repoId,
85
+ commitSha: gitMeta.commitSha,
86
+ branch: gitMeta.branch,
87
+ analysisMode: "local",
88
+ });
89
+ const artifactPath = await writeArtifactToCache(artifact);
90
+ let matcherFindings = [];
91
+ try {
92
+ const matcherResult = await runMatcher({ artifactPath, cwd: rootDir });
93
+ matcherFindings = matcherResult.findings;
94
+ }
95
+ catch (err) {
96
+ const msg = err instanceof Error ? err.message : String(err);
97
+ process.stderr.write(`\n[zivis check] matcher failed (continuing without pattern matches): ${msg}\n`);
98
+ }
99
+ const durationMs = Date.now() - startedAt;
100
+ const summary = summarizeArtifact(artifact, matcherFindings);
101
+ let promotion;
102
+ let promotionError;
103
+ if (network) {
104
+ try {
105
+ promotion = await postCheckArtifact({
106
+ config,
107
+ creds,
108
+ artifact,
109
+ findings: matcherFindings,
110
+ repoName: deriveRepoNameFromGit(gitMeta.remoteUrl, rootDir),
111
+ });
112
+ }
113
+ catch (err) {
114
+ promotionError = err instanceof Error ? err.message : String(err);
115
+ }
116
+ }
117
+ let linkagePrompt = null;
118
+ if (network) {
119
+ try {
120
+ linkagePrompt = await buildLinkagePrompt({
121
+ config,
122
+ applicationId: promotion?.applicationId ?? applicationId,
123
+ });
124
+ }
125
+ catch {
126
+ }
127
+ }
128
+ if (format === "json") {
129
+ process.stdout.write(JSON.stringify(buildJsonOutput(artifact, summary, durationMs, promotion, promotionError, network, linkagePrompt), null, 2) + "\n");
130
+ }
131
+ else {
132
+ renderHumanOutput(artifact, summary, durationMs, promotion, promotionError, network, linkagePrompt);
133
+ }
134
+ return { exitCode: 0 };
135
+ }
136
+ async function handleUnauthenticated(args) {
137
+ const isInteractive = process.stdout.isTTY && process.stdin.isTTY && process.env.CI !== "true";
138
+ if (!isInteractive) {
139
+ printNonTtyAuthInstructions(args.format);
140
+ return 1;
141
+ }
142
+ if (args.format === "json") {
143
+ process.stdout.write(JSON.stringify({
144
+ schema_version: "1",
145
+ error: "not_authenticated",
146
+ message: "zivis check requires authentication; run `zivis auth login` interactively.",
147
+ }, null, 2) + "\n");
148
+ return 1;
149
+ }
150
+ const choice = await promptAuthChoice();
151
+ if (choice === "quit") {
152
+ process.stdout.write("\nCancelled — run `zivis check` again when ready.\n");
153
+ return 1;
154
+ }
155
+ process.stdout.write(`\nOpening your browser to ${choice === "create" ? "sign up" : "sign in"}...\n`);
156
+ try {
157
+ await loginCommand({});
158
+ }
159
+ catch (err) {
160
+ process.stdout.write(`\nAuthentication failed: ${err instanceof Error ? err.message : String(err)}\n`);
161
+ return 1;
162
+ }
163
+ process.stdout.write("\nRunning zivis check ...\n\n");
164
+ return "continue";
165
+ }
166
+ function printNonTtyAuthInstructions(format) {
167
+ if (format === "json") {
168
+ process.stdout.write(JSON.stringify({
169
+ schema_version: "1",
170
+ error: "not_authenticated",
171
+ message: "zivis check requires authentication; set ZIVIS_API_KEY for CI or run interactively.",
172
+ help: {
173
+ sign_up: "https://app.zivis.ai/sign-up?source=cli",
174
+ sign_in: "https://app.zivis.ai/sign-in?source=cli",
175
+ api_keys: "https://app.zivis.ai/settings/api-keys",
176
+ },
177
+ }, null, 2) + "\n");
178
+ return;
179
+ }
180
+ process.stdout.write(`\nZIVIS requires an account to inspect repos.\n\n` +
181
+ ` → Sign up: https://app.zivis.ai/sign-up?source=cli\n` +
182
+ ` → Sign in: https://app.zivis.ai/sign-in?source=cli\n` +
183
+ ` → For CI / headless use: set ZIVIS_API_KEY (issue a service key from\n` +
184
+ ` https://app.zivis.ai/settings/api-keys)\n\n`);
185
+ }
186
+ async function promptAuthChoice() {
187
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
188
+ try {
189
+ process.stdout.write(`\nZIVIS requires an account to inspect repos.\n\n` +
190
+ ` 1) Create account (recommended — first time using ZIVIS)\n` +
191
+ ` 2) Sign in (already have an account)\n` +
192
+ ` q) Quit\n\n`);
193
+ for (;;) {
194
+ const raw = await new Promise((resolve) => rl.question("> ", resolve));
195
+ const choice = raw.trim().toLowerCase();
196
+ if (choice === "" || choice === "1")
197
+ return "create";
198
+ if (choice === "2")
199
+ return "signin";
200
+ if (choice === "q" || choice === "quit")
201
+ return "quit";
202
+ process.stdout.write("Please choose 1, 2, or q.\n");
203
+ }
204
+ }
205
+ finally {
206
+ rl.close();
207
+ }
208
+ }
209
+ async function postCheckArtifact(args) {
210
+ const { config, creds, artifact, findings, repoName } = args;
211
+ const url = `${config.apiBaseUrl}/api/cli/check`;
212
+ const headers = {
213
+ "Content-Type": "application/json",
214
+ "User-Agent": "@zivis/cli",
215
+ };
216
+ if (creds.method === "oauth" && creds.accessToken) {
217
+ headers.Authorization = `Bearer ${creds.accessToken}`;
218
+ }
219
+ else if (creds.method === "apikey" && creds.apiKey) {
220
+ headers["X-API-Key"] = creds.apiKey;
221
+ }
222
+ const body = {
223
+ artifact,
224
+ matches: findings.map((f) => ({
225
+ pattern_id: f.pattern_id,
226
+ lane: f.lane,
227
+ confidence: f.confidence,
228
+ evidence_spans: (f.evidence ?? []).map((e) => ({
229
+ file: e.file,
230
+ line_span: e.end_line ? [e.start_line, e.end_line] : undefined,
231
+ })),
232
+ capsule: {
233
+ safe_summary: f.safe_summary,
234
+ threats: Array.isArray(f.threats) ? f.threats : undefined,
235
+ },
236
+ })),
237
+ repoName,
238
+ };
239
+ const response = await fetch(url, {
240
+ method: "POST",
241
+ headers,
242
+ body: JSON.stringify(body),
243
+ });
244
+ if (!response.ok) {
245
+ const text = await response.text().catch(() => "");
246
+ throw new Error(`HTTP ${response.status} from /api/cli/check: ${text.slice(0, 400)}`);
247
+ }
248
+ return (await response.json());
249
+ }
250
+ function summarizeArtifact(artifact, findings) {
251
+ const services = artifact.nodes.filter((n) => n.type === "service").length;
252
+ const endpoints = artifact.nodes.filter((n) => n.type === "endpoint").length;
253
+ const deps = artifact.nodes.filter((n) => n.type === "external_dependency");
254
+ const llmIntegrations = new Set();
255
+ for (const dep of deps) {
256
+ if (dep.type !== "external_dependency")
257
+ continue;
258
+ const pkg = dep.attributes.package;
259
+ if (!pkg)
260
+ continue;
261
+ if (LLM_PACKAGE_NAMES.has(pkg)) {
262
+ llmIntegrations.add(friendlyLlmName(pkg));
263
+ }
264
+ }
265
+ const trustedMatches = findings.filter((f) => f.lane === "trusted").length;
266
+ const inferredMatches = findings.filter((f) => f.lane === "inferred").length;
267
+ const topPatterns = findings
268
+ .slice()
269
+ .sort((a, b) => b.confidence - a.confidence)
270
+ .slice(0, 3)
271
+ .map((f) => f.pattern_id);
272
+ return {
273
+ serviceCount: services,
274
+ endpointCount: endpoints,
275
+ externalDependencyCount: deps.length,
276
+ llmIntegrations: Array.from(llmIntegrations).sort(),
277
+ languages: artifact.scope.languages ?? [],
278
+ filesScanned: artifact.scope.files_scanned ?? 0,
279
+ trustedMatches,
280
+ inferredMatches,
281
+ topPatterns,
282
+ };
283
+ }
284
+ function friendlyLlmName(pkg) {
285
+ if (pkg === "openai" || pkg === "@azure/openai")
286
+ return "openai";
287
+ if (pkg.startsWith("@anthropic-ai") || pkg === "anthropic")
288
+ return "anthropic";
289
+ if (pkg.startsWith("@google") || pkg.includes("vertexai") || pkg.includes("generative-ai")) {
290
+ return "google";
291
+ }
292
+ if (pkg.includes("bedrock"))
293
+ return "aws-bedrock";
294
+ if (pkg.startsWith("@langchain") || pkg === "langchain")
295
+ return "langchain";
296
+ if (pkg === "llamaindex")
297
+ return "llamaindex";
298
+ if (pkg === "ollama")
299
+ return "ollama";
300
+ if (pkg.includes("cohere"))
301
+ return "cohere";
302
+ if (pkg.includes("mistral"))
303
+ return "mistral";
304
+ if (pkg.includes("groq"))
305
+ return "groq";
306
+ if (pkg === "ai")
307
+ return "vercel-ai";
308
+ return pkg;
309
+ }
310
+ function renderHumanOutput(_artifact, summary, durationMs, promotion, promotionError, network, linkagePrompt) {
311
+ const seconds = (durationMs / 1000).toFixed(1);
312
+ let out = `\nZIVIS read your repo (${seconds}s):\n\n`;
313
+ out += ` Architecture (current snapshot)\n`;
314
+ out += ` ${summary.serviceCount} service${plural(summary.serviceCount)} · ${summary.endpointCount} endpoint${plural(summary.endpointCount)}\n`;
315
+ if (summary.llmIntegrations.length > 0) {
316
+ out += ` ${summary.llmIntegrations.length} LLM integration${plural(summary.llmIntegrations.length)} (${summary.llmIntegrations.join(", ")})\n`;
317
+ }
318
+ if (summary.languages.length > 0) {
319
+ out += ` Languages: ${summary.languages.join(", ")}\n`;
320
+ }
321
+ const totalMatches = summary.trustedMatches + summary.inferredMatches;
322
+ if (totalMatches > 0) {
323
+ out += `\n Patterns matched\n`;
324
+ out += ` ${summary.trustedMatches} trusted · ${summary.inferredMatches} inferred (need IDE review)\n`;
325
+ for (const p of summary.topPatterns) {
326
+ out += ` • ${p}\n`;
327
+ }
328
+ }
329
+ if (promotion) {
330
+ out += `\n ${promotion.isNewApplication ? "Created" : "Updated"} threat model — "${promotion.applicationName}"\n`;
331
+ out += ` Components: +${promotion.componentsAdded}`;
332
+ if (promotion.componentsUnchanged > 0)
333
+ out += ` (${promotion.componentsUnchanged} already present)`;
334
+ out += `\n`;
335
+ out += ` Data flows: +${promotion.dataFlowsAdded}`;
336
+ if (promotion.dataFlowsUnchanged > 0)
337
+ out += ` (${promotion.dataFlowsUnchanged} already present)`;
338
+ out += `\n`;
339
+ out += ` Actors: +${promotion.actorsAttached}\n`;
340
+ out += ` Observations: +${promotion.findingsCreated}\n`;
341
+ out += ` Scenarios: +${promotion.scenariosGenerated}\n`;
342
+ out += `\n View it: ${promotion.webAppUrl}\n`;
343
+ }
344
+ else if (network && promotionError) {
345
+ out += `\n Could not post to your threat model: ${promotionError}\n`;
346
+ out += ` (graph + matches still produced locally; rerun once the API is reachable)\n`;
347
+ }
348
+ else if (!network) {
349
+ out += `\n (--no-network: nothing posted to your threat model)\n`;
350
+ }
351
+ out += `\nContinue:\n`;
352
+ out += ` → In your IDE: zivis mcp install --for claude-code\n`;
353
+ out += ` → Human-reviewed Mini-Threat-Model: zivis teardown ($500)\n`;
354
+ out += ` → Full Deal-Readiness Threat Model: zivis sales ($7.5K–$15K)\n`;
355
+ if (linkagePrompt) {
356
+ out += linkagePrompt + "\n";
357
+ }
358
+ out += "\n";
359
+ process.stdout.write(out);
360
+ }
361
+ function plural(n) {
362
+ return n === 1 ? "" : "s";
363
+ }
364
+ function buildJsonOutput(artifact, summary, durationMs, promotion, promotionError, network, linkagePrompt) {
365
+ let promotionField;
366
+ if (promotion)
367
+ promotionField = { status: "ok", ...promotion };
368
+ else if (!network)
369
+ promotionField = { status: "skipped", reason: "no-network" };
370
+ else if (promotionError)
371
+ promotionField = { status: "error", error: promotionError };
372
+ return {
373
+ schema_version: "1",
374
+ repo_id: artifact.provenance.repo_id ?? "unknown",
375
+ ran_at: artifact.extracted_at,
376
+ duration_ms: durationMs,
377
+ architecture: {
378
+ services: summary.serviceCount,
379
+ endpoints: summary.endpointCount,
380
+ external_dependencies: summary.externalDependencyCount,
381
+ llm_integrations: summary.llmIntegrations,
382
+ languages: summary.languages,
383
+ },
384
+ matches: {
385
+ trusted: summary.trustedMatches,
386
+ inferred: summary.inferredMatches,
387
+ top_patterns: summary.topPatterns,
388
+ },
389
+ promotion: promotionField,
390
+ conversion_links: {
391
+ mcp_install: "zivis mcp install --for <ide>",
392
+ teardown: "zivis teardown",
393
+ sales: "zivis sales",
394
+ },
395
+ linkage_prompt: linkagePrompt,
396
+ };
397
+ }
398
+ function printIfHuman(format, msg) {
399
+ if (format === "human")
400
+ process.stdout.write(msg + "\n");
401
+ }
402
+ async function readGitMetadata(rootDir) {
403
+ return {
404
+ remoteUrl: await tryGit(rootDir, "remote get-url origin"),
405
+ commitSha: await tryGit(rootDir, "rev-parse HEAD"),
406
+ branch: await tryGit(rootDir, "rev-parse --abbrev-ref HEAD"),
407
+ };
408
+ }
409
+ async function tryGit(cwd, args) {
410
+ try {
411
+ const { stdout } = await execAsync(`git ${args}`, { cwd });
412
+ const value = stdout.trim();
413
+ return value || undefined;
414
+ }
415
+ catch {
416
+ return undefined;
417
+ }
418
+ }
419
+ function deriveRepoId(remoteUrl, rootDir) {
420
+ if (remoteUrl) {
421
+ return "remote-" + sha256Short(remoteUrl);
422
+ }
423
+ return "path-" + sha256Short(rootDir);
424
+ }
425
+ function sha256Short(value) {
426
+ return crypto.createHash("sha256").update(value).digest("hex").slice(0, 16);
427
+ }
428
+ function deriveRepoNameFromGit(remoteUrl, rootDir) {
429
+ if (remoteUrl) {
430
+ const m = /[/:]([^/:]+?)\/([^/]+?)(?:\.git)?$/.exec(remoteUrl);
431
+ if (m)
432
+ return m[2];
433
+ }
434
+ const base = path.basename(rootDir);
435
+ return base && base !== "." ? base : undefined;
436
+ }
437
+ function userCacheRoot() {
438
+ const home = os.homedir();
439
+ if (process.platform === "darwin") {
440
+ return path.join(home, "Library", "Caches", "zivis");
441
+ }
442
+ if (process.platform === "win32") {
443
+ const localAppData = process.env.LOCALAPPDATA ?? path.join(home, "AppData", "Local");
444
+ return path.join(localAppData, "zivis", "Cache");
445
+ }
446
+ const xdg = process.env.XDG_CACHE_HOME;
447
+ return path.join(xdg ?? path.join(home, ".cache"), "zivis");
448
+ }
449
+ async function writeArtifactToCache(artifact) {
450
+ const repoId = artifact.provenance.repo_id ?? "unknown";
451
+ const commitSha = artifact.provenance.commit_sha;
452
+ const runId = formatRunId(commitSha, artifact.extracted_at);
453
+ const outPath = path.join(userCacheRoot(), "repos", repoId, "inspect", "runs", `${runId}.json`);
454
+ await fs.mkdir(path.dirname(outPath), { recursive: true });
455
+ await fs.writeFile(outPath, JSON.stringify(artifact, null, 2) + "\n");
456
+ return outPath;
457
+ }
458
+ function formatRunId(commitSha, extractedAt) {
459
+ const compactTs = extractedAt.replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
460
+ if (!commitSha)
461
+ return `nogit-${compactTs}`;
462
+ return `${commitSha.slice(0, 7)}-${compactTs}`;
463
+ }
@@ -48,4 +48,3 @@ export function registerCreditsCommands(program) {
48
48
  }
49
49
  });
50
50
  }
51
- //# sourceMappingURL=index.js.map
@@ -1,17 +1,2 @@
1
- /**
2
- * `zivis inspect` — local repo graph extraction.
3
- *
4
- * Walks the repo with the existing extractor, converts the result into a
5
- * RepoGraphArtifactV1 (the canonical contract), and writes it to the
6
- * user-level cache. This is the user-facing entrypoint for Phase 1 of the
7
- * local repo graph + pattern library work.
8
- *
9
- * Plan: docs/plans/LOCAL-REPO-GRAPH-IMPLEMENTATION.md
10
- * Schema: schemas/repo-graph-artifact.schema.json
11
- *
12
- * The command is local-only and never makes network calls. Persistence to
13
- * the platform happens in a separate step (Phase 4 — `/inspect` upload),
14
- * gated on Application mapping resolution per plan §Repo->Application Mapping.
15
- */
16
1
  import type { Command } from "commander";
17
2
  export declare function registerInspectCommands(program: Command): void;
@@ -1,18 +1,3 @@
1
- /**
2
- * `zivis inspect` — local repo graph extraction.
3
- *
4
- * Walks the repo with the existing extractor, converts the result into a
5
- * RepoGraphArtifactV1 (the canonical contract), and writes it to the
6
- * user-level cache. This is the user-facing entrypoint for Phase 1 of the
7
- * local repo graph + pattern library work.
8
- *
9
- * Plan: docs/plans/LOCAL-REPO-GRAPH-IMPLEMENTATION.md
10
- * Schema: schemas/repo-graph-artifact.schema.json
11
- *
12
- * The command is local-only and never makes network calls. Persistence to
13
- * the platform happens in a separate step (Phase 4 — `/inspect` upload),
14
- * gated on Application mapping resolution per plan §Repo->Application Mapping.
15
- */
16
1
  import * as crypto from "node:crypto";
17
2
  import * as fs from "node:fs/promises";
18
3
  import * as os from "node:os";
@@ -115,12 +100,6 @@ function deriveRepoId(remoteUrl, rootDir) {
115
100
  function sha256Short(value) {
116
101
  return crypto.createHash("sha256").update(value).digest("hex").slice(0, 16);
117
102
  }
118
- /**
119
- * XDG-compliant user cache root. Layout follows the plan §2A:
120
- * macOS: ~/Library/Caches/zivis
121
- * Linux: $XDG_CACHE_HOME/zivis (or ~/.cache/zivis)
122
- * Windows: %LOCALAPPDATA%\zivis\Cache
123
- */
124
103
  function userCacheRoot() {
125
104
  const home = os.homedir();
126
105
  if (process.platform === "darwin") {
@@ -138,7 +117,6 @@ function defaultCacheOutPath(repoId, commitSha, extractedAt) {
138
117
  return path.join(userCacheRoot(), "repos", repoId, "inspect", "runs", `${runId}.json`);
139
118
  }
140
119
  function formatRunId(commitSha, extractedAt) {
141
- // <short-commit>-<compact-iso> e.g. abc1234-20260505T201600Z
142
120
  const compactTs = extractedAt.replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
143
121
  if (!commitSha)
144
122
  return `nogit-${compactTs}`;
@@ -156,4 +134,3 @@ function printSummary(artifact, suffix) {
156
134
  ` ${artifact.edges.length} edges (${exposes} exposes, ${dependsOn} depends_on)\n` +
157
135
  (suffix ? ` ${suffix}\n` : ""));
158
136
  }
159
- //# sourceMappingURL=index.js.map
@@ -12,10 +12,6 @@ const KNOWN_CLIENTS = [
12
12
  "vscode-copilot",
13
13
  "vscode-claude",
14
14
  ];
15
- /**
16
- * Map the CLI --client value to the GuidanceClient type used by writeGuidance().
17
- * "claude-code" (manual) has no guidance files — skip it.
18
- */
19
15
  function toGuidanceClient(client) {
20
16
  switch (client) {
21
17
  case "cursor": return "cursor";
@@ -97,23 +93,19 @@ export function registerMcpCommands(program) {
97
93
  console.error("Install failed:", err instanceof Error ? err.message : err);
98
94
  process.exit(1);
99
95
  }
100
- // "claude-code" is manual — no guidance files to write
101
96
  if (client === "claude-code")
102
97
  return;
103
98
  const guidanceClient = toGuidanceClient(client);
104
99
  if (!guidanceClient)
105
100
  return;
106
- // Determine whether to write guidance files
107
101
  let shouldWrite;
108
102
  if (opts.withGuidance) {
109
103
  shouldWrite = true;
110
104
  }
111
105
  else if (opts.guidance === false) {
112
- // Commander sets opts.guidance = false when --no-guidance is passed
113
106
  shouldWrite = false;
114
107
  }
115
108
  else {
116
- // Interactive default
117
109
  console.log("");
118
110
  shouldWrite = await promptYesNo("Write ZIVIS guidance files so your IDE knows when to suggest security checks?\n" +
119
111
  "(Adds a rule/instruction file to the project. You can edit or remove it anytime.) [Y/n] ");
@@ -133,4 +125,3 @@ export function registerMcpCommands(program) {
133
125
  }
134
126
  });
135
127
  }
136
- //# sourceMappingURL=index.js.map
@@ -1,10 +1,2 @@
1
- /**
2
- * `zivis open` — Build and (by default) launch a vscode:// or cursor:// deep link
3
- * that opens a ZIVIS artifact in the ZIVIS Code IDE extension. Use `--ide cursor`
4
- * for Cursor. With --print, emit the URI to stdout for piping/sharing.
5
- *
6
- * Mirrors the URI shape emitted by the `zivis_open_in_ide` MCP tool and the
7
- * web app's buildIdeLink() helper. See docs/platform/integrations/IDE-DEEP-LINKS.md.
8
- */
9
1
  import type { Command } from "commander";
10
2
  export declare function registerOpenCommands(program: Command): void;
@@ -1,11 +1,3 @@
1
- /**
2
- * `zivis open` — Build and (by default) launch a vscode:// or cursor:// deep link
3
- * that opens a ZIVIS artifact in the ZIVIS Code IDE extension. Use `--ide cursor`
4
- * for Cursor. With --print, emit the URI to stdout for piping/sharing.
5
- *
6
- * Mirrors the URI shape emitted by the `zivis_open_in_ide` MCP tool and the
7
- * web app's buildIdeLink() helper. See docs/platform/integrations/IDE-DEEP-LINKS.md.
8
- */
9
1
  const KINDS = ["diagram", "document", "threat-model"];
10
2
  export function registerOpenCommands(program) {
11
3
  program
@@ -47,11 +39,8 @@ export function registerOpenCommands(program) {
47
39
  console.log(uri);
48
40
  return;
49
41
  }
50
- // Lazy-import `open` so --print stays dependency-free in environments
51
- // (e.g. headless CI) where launching a URL handler would fail or hang.
52
42
  const { default: open } = await import("open");
53
43
  await open(uri);
54
44
  console.log(uri);
55
45
  });
56
46
  }
57
- //# sourceMappingURL=index.js.map
@@ -118,11 +118,6 @@ export function registerScanCommands(program) {
118
118
  }
119
119
  });
120
120
  }
121
- /**
122
- * Map customer-facing ApplicationType to the RT scan's targetType enum.
123
- * The two enums differ historically: ApplicationType is product-shape,
124
- * targetType is what the RT runner needs to know about the wire format.
125
- */
126
121
  function appTypeToTargetType(appType) {
127
122
  switch (appType) {
128
123
  case "agent":
@@ -137,4 +132,3 @@ function appTypeToTargetType(appType) {
137
132
  return undefined;
138
133
  }
139
134
  }
140
- //# sourceMappingURL=index.js.map
@@ -4,8 +4,6 @@ import { getStorageName } from "../../internal/target-auth/keychain.js";
4
4
  import { decodeJwtPayload } from "../../internal/target-auth/workos.js";
5
5
  const DEFAULT_PERSONA = "default";
6
6
  function warnDeprecated() {
7
- // stderr so it doesn't pollute stdout (CLI scripts pipe `zivis target token`
8
- // straight into curl). One line, no color codes — keeps grep-friendly.
9
7
  console.error("[zivis] WARNING: 'zivis target' is deprecated; use 'zivis app' instead.");
10
8
  }
11
9
  export function registerTargetCommands(program) {
@@ -143,4 +141,3 @@ export function registerTargetCommands(program) {
143
141
  console.log(`✓ Cleared tokens for target ${targetId} (persona: ${opts.persona})`);
144
142
  });
145
143
  }
146
- //# sourceMappingURL=index.js.map
@@ -14,7 +14,6 @@ function collect(value, previous) {
14
14
  return previous.concat([value]);
15
15
  }
16
16
  function defaultOutPath(extractedAt) {
17
- // .zivis/extracted/<iso-no-colons>.json — matches the doc's example.
18
17
  const ts = extractedAt.replace(/[:.]/g, "-");
19
18
  return `.zivis/extracted/${ts}.json`;
20
19
  }
@@ -80,9 +79,6 @@ export function registerTmCommands(program) {
80
79
  process.exit(1);
81
80
  });
82
81
  const parsed = JSON.parse(raw);
83
- // Only fields the PATCH endpoint accepts. tm pull dumps the full
84
- // record; tm push only sends the editable subset, so a round-trip
85
- // edit cycle Just Works.
86
82
  const payload = {};
87
83
  for (const k of ["name", "description", "status", "campaignId"]) {
88
84
  if (parsed[k] !== undefined)
@@ -123,8 +119,6 @@ export function registerTmCommands(program) {
123
119
  extractorVersion: cliPkg.version,
124
120
  });
125
121
  if (opts.privacyAudit) {
126
- // Prints the entire object that WOULD be sent to ZIVIS via --apply.
127
- // Never makes a network call; the extractor itself is local-only.
128
122
  process.stdout.write(JSON.stringify(result, null, 2) + "\n");
129
123
  process.stderr.write(`\n[zivis] Privacy audit: ${result.scope.filesScanned} files scanned, ` +
130
124
  `${result.components.length} component(s), ${result.externalServices.length} external service(s), ` +
@@ -263,4 +257,3 @@ export function registerTmCommands(program) {
263
257
  }
264
258
  });
265
259
  }
266
- //# sourceMappingURL=index.js.map