@zivis/cli 0.1.0-alpha.39 → 0.1.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist/commands/app/index.d.ts +8 -0
  2. package/dist/commands/app/index.js +14 -2
  3. package/dist/commands/app/index.js.map +1 -0
  4. package/dist/commands/auth/index.js +2 -19
  5. package/dist/commands/auth/index.js.map +1 -0
  6. package/dist/commands/auth/init.d.ts +0 -1
  7. package/dist/commands/auth/init.js +73 -245
  8. package/dist/commands/auth/init.js.map +1 -0
  9. package/dist/commands/auth/login.d.ts +0 -1
  10. package/dist/commands/auth/login.js +9 -34
  11. package/dist/commands/auth/login.js.map +1 -0
  12. package/dist/commands/auth/logout.js +7 -19
  13. package/dist/commands/auth/logout.js.map +1 -0
  14. package/dist/commands/auth/sessions.js +4 -7
  15. package/dist/commands/auth/sessions.js.map +1 -0
  16. package/dist/commands/auth/status.js +12 -33
  17. package/dist/commands/auth/status.js.map +1 -0
  18. package/dist/commands/credits/index.js +3 -2
  19. package/dist/commands/credits/index.js.map +1 -0
  20. package/dist/commands/mcp/index.js +14 -81
  21. package/dist/commands/mcp/index.js.map +1 -0
  22. package/dist/commands/open/index.d.ts +8 -0
  23. package/dist/commands/open/index.js +11 -0
  24. package/dist/commands/open/index.js.map +1 -0
  25. package/dist/commands/scan/index.js +8 -2
  26. package/dist/commands/scan/index.js.map +1 -0
  27. package/dist/commands/target/index.js +3 -0
  28. package/dist/commands/target/index.js.map +1 -0
  29. package/dist/commands/tm/index.js +10 -3
  30. package/dist/commands/tm/index.js.map +1 -0
  31. package/dist/index.js +1 -13
  32. package/dist/index.js.map +1 -0
  33. package/dist/internal/extractor/adapters/go/index.d.ts +4 -0
  34. package/dist/internal/extractor/adapters/go/index.js +6 -0
  35. package/dist/internal/extractor/adapters/go/index.js.map +1 -0
  36. package/dist/internal/extractor/adapters/go/manifest.d.ts +17 -0
  37. package/dist/internal/extractor/adapters/go/manifest.js +25 -19
  38. package/dist/internal/extractor/adapters/go/manifest.js.map +1 -0
  39. package/dist/internal/extractor/adapters/go/parser.d.ts +4 -0
  40. package/dist/internal/extractor/adapters/go/parser.js +5 -0
  41. package/dist/internal/extractor/adapters/go/parser.js.map +1 -0
  42. package/dist/internal/extractor/adapters/go/scanner.d.ts +20 -0
  43. package/dist/internal/extractor/adapters/go/scanner.js +43 -0
  44. package/dist/internal/extractor/adapters/go/scanner.js.map +1 -0
  45. package/dist/internal/extractor/adapters/python/index.d.ts +3 -0
  46. package/dist/internal/extractor/adapters/python/index.js +4 -0
  47. package/dist/internal/extractor/adapters/python/index.js.map +1 -0
  48. package/dist/internal/extractor/adapters/python/manifest.d.ts +8 -0
  49. package/dist/internal/extractor/adapters/python/manifest.js +18 -21
  50. package/dist/internal/extractor/adapters/python/manifest.js.map +1 -0
  51. package/dist/internal/extractor/adapters/python/parser.d.ts +3 -0
  52. package/dist/internal/extractor/adapters/python/parser.js +4 -0
  53. package/dist/internal/extractor/adapters/python/parser.js.map +1 -0
  54. package/dist/internal/extractor/adapters/python/scanner.d.ts +18 -0
  55. package/dist/internal/extractor/adapters/python/scanner.js +54 -1
  56. package/dist/internal/extractor/adapters/python/scanner.js.map +1 -0
  57. package/dist/internal/extractor/adapters/typescript/index.d.ts +7 -0
  58. package/dist/internal/extractor/adapters/typescript/index.js +21 -1
  59. package/dist/internal/extractor/adapters/typescript/index.js.map +1 -0
  60. package/dist/internal/extractor/adapters/typescript/manifest.d.ts +14 -0
  61. package/dist/internal/extractor/adapters/typescript/manifest.js +17 -26
  62. package/dist/internal/extractor/adapters/typescript/manifest.js.map +1 -0
  63. package/dist/internal/extractor/adapters/typescript/parser.d.ts +8 -0
  64. package/dist/internal/extractor/adapters/typescript/parser.js +9 -0
  65. package/dist/internal/extractor/adapters/typescript/parser.js.map +1 -0
  66. package/dist/internal/extractor/adapters/typescript/scanner.d.ts +24 -0
  67. package/dist/internal/extractor/adapters/typescript/scanner.js +43 -0
  68. package/dist/internal/extractor/adapters/typescript/scanner.js.map +1 -0
  69. package/dist/internal/extractor/index.d.ts +14 -0
  70. package/dist/internal/extractor/index.js +13 -0
  71. package/dist/internal/extractor/index.js.map +1 -0
  72. package/dist/internal/extractor/types.d.ts +45 -0
  73. package/dist/internal/extractor/types.js +27 -0
  74. package/dist/internal/extractor/types.js.map +1 -0
  75. package/dist/internal/extractor/walker.d.ts +18 -0
  76. package/dist/internal/extractor/walker.js +18 -0
  77. package/dist/internal/extractor/walker.js.map +1 -0
  78. package/dist/internal/ide-setup.d.ts +7 -16
  79. package/dist/internal/ide-setup.js +46 -320
  80. package/dist/internal/ide-setup.js.map +1 -0
  81. package/dist/internal/orgs.js +1 -0
  82. package/dist/internal/orgs.js.map +1 -0
  83. package/dist/internal/project-binding.d.ts +0 -1
  84. package/dist/internal/project-binding.js +9 -14
  85. package/dist/internal/project-binding.js.map +1 -0
  86. package/dist/internal/target-auth/api-config.d.ts +17 -0
  87. package/dist/internal/target-auth/api-config.js +18 -0
  88. package/dist/internal/target-auth/api-config.js.map +1 -0
  89. package/dist/internal/target-auth/config.d.ts +12 -0
  90. package/dist/internal/target-auth/config.js +13 -0
  91. package/dist/internal/target-auth/config.js.map +1 -0
  92. package/dist/internal/target-auth/index.d.ts +18 -0
  93. package/dist/internal/target-auth/index.js +19 -0
  94. package/dist/internal/target-auth/index.js.map +1 -0
  95. package/dist/internal/target-auth/keychain.d.ts +18 -0
  96. package/dist/internal/target-auth/keychain.js +23 -3
  97. package/dist/internal/target-auth/keychain.js.map +1 -0
  98. package/dist/internal/target-auth/types.d.ts +26 -0
  99. package/dist/internal/target-auth/types.js +10 -0
  100. package/dist/internal/target-auth/types.js.map +1 -0
  101. package/dist/internal/target-auth/workos.d.ts +15 -0
  102. package/dist/internal/target-auth/workos.js +17 -0
  103. package/dist/internal/target-auth/workos.js.map +1 -0
  104. package/package.json +4 -18
  105. package/LICENSE +0 -201
  106. package/README.md +0 -31
  107. package/dist/commands/auth/bind.d.ts +0 -4
  108. package/dist/commands/auth/bind.js +0 -97
  109. package/dist/commands/auth/token.d.ts +0 -4
  110. package/dist/commands/auth/token.js +0 -73
  111. package/dist/commands/check/index.d.ts +0 -2
  112. package/dist/commands/check/index.js +0 -463
  113. package/dist/commands/inspect/index.d.ts +0 -2
  114. package/dist/commands/inspect/index.js +0 -136
  115. package/dist/internal/binding-token-mint.d.ts +0 -33
  116. package/dist/internal/binding-token-mint.js +0 -174
  117. package/dist/internal/extractor/graph-builder.d.ts +0 -10
  118. package/dist/internal/extractor/graph-builder.js +0 -245
  119. package/dist/internal/extractor/graph-types.d.ts +0 -89
  120. package/dist/internal/extractor/graph-types.js +0 -1
  121. package/dist/internal/github-linkage-prompt.d.ts +0 -7
  122. package/dist/internal/github-linkage-prompt.js +0 -95
@@ -1,97 +0,0 @@
1
- import { login } from "@zivis/mcp/auth";
2
- import { keychainClearSession } from "@zivis/mcp/auth";
3
- import { detectProjectBinding, resolveConfigFromBinding } from "@zivis/mcp/project-binding";
4
- import { DEFAULT_CONFIG, credentialStorageFromConfig } from "@zivis/mcp/types";
5
- import { extractEmail } from "../../internal/orgs.js";
6
- import { ensureProjectBinding } from "../../internal/project-binding.js";
7
- import { mintLocalProjectBindingToken } from "../../internal/binding-token-mint.js";
8
- import { setupCursorWorkspace, setupVsCodeClaude, setupVsCodeCopilot, setupClaudeCodeCli, } from "../../internal/ide-setup.js";
9
- export async function bindCommand(opts) {
10
- const cwd = process.cwd();
11
- const config = { ...DEFAULT_CONFIG, ...resolveConfigFromBinding(cwd) };
12
- const detected = detectProjectBinding(cwd);
13
- if (!detected?.binding.workosOrgId) {
14
- console.error("");
15
- console.error("[zivis] ERROR: No project binding found.");
16
- console.error("[zivis] Run zivis auth login (or auth init) in this repo first,");
17
- console.error("[zivis] then run zivis auth bind if MCP still needs an API key.");
18
- console.error("");
19
- process.exit(1);
20
- }
21
- const { workosOrgId, session: bindingSession, orgName } = detected.binding;
22
- const session = bindingSession;
23
- console.log("");
24
- console.log(`Minting MCP API key for ${orgName ?? workosOrgId} (session: "${session}")`);
25
- console.log("");
26
- let tokens;
27
- try {
28
- tokens = await login(config, `__bind_temp_${session}`, workosOrgId, {
29
- orgName,
30
- sessionLabel: session,
31
- skipConfirm: opts.yes === true,
32
- });
33
- }
34
- catch (err) {
35
- console.error("[zivis] Authentication failed:", err instanceof Error ? err.message : err);
36
- process.exit(1);
37
- }
38
- const email = extractEmail(tokens.id_token);
39
- console.log(`✓ Authenticated as ${email}`);
40
- const credentialStorage = credentialStorageFromConfig(config);
41
- let mint;
42
- try {
43
- mint = await mintLocalProjectBindingToken({
44
- config,
45
- session,
46
- accessToken: tokens.access_token,
47
- cwd,
48
- });
49
- }
50
- finally {
51
- await keychainClearSession(`__bind_temp_${session}`, credentialStorage).catch(() => { });
52
- }
53
- if (!mint.ok) {
54
- console.error(`[zivis] Bind failed: ${mint.error}`);
55
- process.exit(1);
56
- }
57
- const maskedKey = `${mint.key.slice(0, 10)}...${mint.key.slice(-4)}`;
58
- console.log(`✓ Local Project Binding Token stored (${maskedKey})`);
59
- console.log(` Org: ${mint.orgName} (${mint.workosOrgId})`);
60
- console.log(` Key name: ${mint.keyName}`);
61
- try {
62
- await setupCursorWorkspace();
63
- }
64
- catch (err) {
65
- console.log(` WARNING: Failed to update .cursor/mcp.json: ${err instanceof Error ? err.message : err}`);
66
- }
67
- try {
68
- await setupVsCodeClaude();
69
- await setupVsCodeCopilot();
70
- }
71
- catch (err) {
72
- console.log(` WARNING: Failed to update .vscode/mcp.json: ${err instanceof Error ? err.message : err}`);
73
- }
74
- try {
75
- await setupClaudeCodeCli();
76
- }
77
- catch (err) {
78
- console.log(` WARNING: Failed to update Claude Code CLI config: ${err instanceof Error ? err.message : err}`);
79
- }
80
- await ensureProjectBinding({
81
- config,
82
- session,
83
- accessToken: tokens.access_token,
84
- organizationId: workosOrgId,
85
- cwd,
86
- autoBind: true,
87
- skipBind: false,
88
- force: false,
89
- });
90
- console.log("");
91
- console.log("✓ Bind complete. Reload your IDE to activate the MCP server.");
92
- console.log("");
93
- console.log(" To verify: zivis auth status");
94
- console.log(" To revoke: zivis auth logout (or Settings → API Tokens in the UI)");
95
- console.log("");
96
- process.exit(0);
97
- }
@@ -1,4 +0,0 @@
1
- export interface TokenCmdOpts {
2
- session?: string;
3
- }
4
- export declare function tokenCommand(apiKey: string, opts: TokenCmdOpts): Promise<void>;
@@ -1,73 +0,0 @@
1
- import { keychainStore, getStorageName } from "@zivis/mcp/auth";
2
- import { detectProjectBinding, resolveConfigFromBinding } from "@zivis/mcp/project-binding";
3
- import { DEFAULT_CONFIG, credentialStorageFromConfig } from "@zivis/mcp/types";
4
- const API_KEY_PREFIX = "sk_";
5
- const API_KEY_REGEX = /^sk_[a-z0-9_]{10,}$/i;
6
- function getApiKeyAccount(session) {
7
- return session ? `apikey.${session}` : "apikey";
8
- }
9
- function validateKeyFormat(key) {
10
- return API_KEY_REGEX.test(key);
11
- }
12
- export async function tokenCommand(apiKey, opts) {
13
- if (!validateKeyFormat(apiKey)) {
14
- console.error(`Invalid API token format. Expected: ${API_KEY_PREFIX}<token value>`);
15
- console.error(`Got: ${apiKey.substring(0, 20)}...`);
16
- console.error(`\nGenerate a token at: Settings → API Tokens in the ZIVIS platform.`);
17
- process.exit(1);
18
- }
19
- const cwd = process.cwd();
20
- const detected = detectProjectBinding(cwd);
21
- const session = opts.session ?? detected?.binding.session;
22
- const config = { ...DEFAULT_CONFIG, ...resolveConfigFromBinding(cwd) };
23
- const account = getApiKeyAccount(session);
24
- const sessionLabel = session ? `session "${session}"` : "default session";
25
- const storageName = getStorageName();
26
- try {
27
- await keychainStore(account, apiKey, credentialStorageFromConfig(config));
28
- }
29
- catch (err) {
30
- console.error(`Failed to store token: ${err instanceof Error ? err.message : err}`);
31
- process.exit(1);
32
- }
33
- const maskedKey = `${apiKey.substring(0, 12)}...${apiKey.slice(-4)}`;
34
- console.log(`✓ API token stored for ${sessionLabel}`);
35
- console.log(` Key: ${maskedKey}`);
36
- console.log(` Storage: ${storageName} (account: ${account})`);
37
- if (session) {
38
- console.log(`\nThe MCP server will use this token automatically for projects bound to session "${session}".`);
39
- }
40
- else {
41
- console.log(`\nThe MCP server will use this token for the default session.`);
42
- console.log(`Tip: Use --session <name> to scope this token to a specific org.`);
43
- }
44
- if (detected) {
45
- const orgLabel = detected.binding.orgName
46
- ? ` (${detected.binding.orgName})`
47
- : "";
48
- console.log(`\nProject binding detected: this repo is bound to session "${detected.binding.session}"${orgLabel}.`);
49
- if (!session) {
50
- console.log(` Tip: Run with --session ${detected.binding.session} to scope this token to that org.`);
51
- }
52
- }
53
- try {
54
- const response = await fetch(`${config.apiBaseUrl}/api/mcp/session`, {
55
- headers: { "X-API-Key": apiKey, "User-Agent": "@zivis/cli" },
56
- });
57
- if (response.ok) {
58
- const data = (await response.json());
59
- const orgName = data.org?.name ?? "unknown org";
60
- const email = data.user?.email ?? "unknown user";
61
- console.log(`\n✓ Token verified — authenticated as ${email} in ${orgName}`);
62
- }
63
- else {
64
- const body = await response.json().catch(() => ({}));
65
- console.log(`\n Warning: Could not verify token against API (HTTP ${response.status}): ${body.message ?? body.error ?? "unknown error"}`);
66
- console.log(` Token was stored but may be invalid or lack the 'mcp' scope.`);
67
- }
68
- }
69
- catch {
70
- console.log(`\n Note: Could not reach the ZIVIS API to verify the token (stored anyway).`);
71
- }
72
- process.exit(0);
73
- }
@@ -1,2 +0,0 @@
1
- import type { Command } from "commander";
2
- export declare function registerCheckCommands(program: Command): void;
@@ -1,463 +0,0 @@
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
- }
@@ -1,2 +0,0 @@
1
- import type { Command } from "commander";
2
- export declare function registerInspectCommands(program: Command): void;