@zivis/cli 0.1.0-alpha.4 → 0.1.0-alpha.40
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 +4 -16
- package/dist/commands/auth/bind.d.ts +4 -0
- package/dist/commands/auth/bind.js +97 -0
- package/dist/commands/auth/index.js +20 -2
- package/dist/commands/auth/init.d.ts +1 -0
- package/dist/commands/auth/init.js +245 -73
- package/dist/commands/auth/login.d.ts +2 -0
- package/dist/commands/auth/login.js +136 -18
- package/dist/commands/auth/logout.js +19 -7
- package/dist/commands/auth/sessions.js +7 -4
- package/dist/commands/auth/status.js +33 -12
- package/dist/commands/auth/token.d.ts +4 -0
- package/dist/commands/auth/token.js +73 -0
- package/dist/commands/check/index.d.ts +2 -0
- package/dist/commands/check/index.js +463 -0
- package/dist/commands/credits/index.js +2 -3
- package/dist/commands/inspect/index.d.ts +2 -0
- package/dist/commands/inspect/index.js +136 -0
- package/dist/commands/mcp/index.js +81 -14
- package/dist/commands/open/index.d.ts +0 -8
- package/dist/commands/open/index.js +0 -11
- package/dist/commands/scan/index.js +3 -8
- package/dist/commands/target/index.js +0 -3
- package/dist/commands/tm/index.js +3 -10
- package/dist/index.js +13 -1
- package/dist/internal/binding-token-mint.d.ts +33 -0
- package/dist/internal/binding-token-mint.js +174 -0
- 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 +19 -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 +21 -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 +26 -17
- 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 +10 -0
- package/dist/internal/extractor/graph-builder.js +245 -0
- package/dist/internal/extractor/graph-types.d.ts +89 -0
- package/dist/internal/extractor/graph-types.js +1 -0
- 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 +7 -0
- package/dist/internal/github-linkage-prompt.js +95 -0
- package/dist/internal/ide-setup.d.ts +16 -7
- package/dist/internal/ide-setup.js +320 -46
- package/dist/internal/org-picker.d.ts +11 -0
- package/dist/internal/org-picker.js +34 -0
- package/dist/internal/orgs.js +0 -1
- package/dist/internal/project-binding.d.ts +1 -0
- package/dist/internal/project-binding.js +14 -9
- 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 +9 -18
- package/package.json +19 -5
- package/dist/commands/app/index.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/credits/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/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/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/ide-setup.js.map +0 -1
- package/dist/internal/orgs.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
|
@@ -1,16 +1,290 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
function getServerName(pkg) {
|
|
4
|
+
return pkg === "builder" ? "zivis-builder" : "zivis";
|
|
5
|
+
}
|
|
6
|
+
function appendBlock(filePath, blockKey, content) {
|
|
7
|
+
const begin = `<!-- BEGIN ZIVIS:${blockKey} -->`;
|
|
8
|
+
const end = `<!-- END ZIVIS:${blockKey} -->`;
|
|
9
|
+
let existing = fs.existsSync(filePath)
|
|
10
|
+
? fs.readFileSync(filePath, "utf-8")
|
|
11
|
+
: "";
|
|
12
|
+
const blockRegex = new RegExp(`${escapeRegex(begin)}[\\s\\S]*?${escapeRegex(end)}`, "g");
|
|
13
|
+
const newBlock = `${begin}\n${content}\n${end}`;
|
|
14
|
+
if (blockRegex.test(existing)) {
|
|
15
|
+
existing = existing.replace(blockRegex, newBlock);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
if (existing && !existing.endsWith("\n"))
|
|
19
|
+
existing += "\n";
|
|
20
|
+
existing += `\n${newBlock}\n`;
|
|
21
|
+
}
|
|
22
|
+
const dir = path.dirname(filePath);
|
|
23
|
+
if (!fs.existsSync(dir))
|
|
24
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
25
|
+
fs.writeFileSync(filePath, existing);
|
|
26
|
+
}
|
|
27
|
+
function escapeRegex(s) {
|
|
28
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
29
|
+
}
|
|
30
|
+
function cursorRuleContent() {
|
|
31
|
+
return `---
|
|
32
|
+
description: ZIVIS security guidance — quietly suggest security checks at the right moments
|
|
33
|
+
globs:
|
|
34
|
+
- "**/*.{ts,tsx,js,jsx,py,go,rb,java}"
|
|
35
|
+
- "**/package.json"
|
|
36
|
+
- "**/requirements.txt"
|
|
37
|
+
- "**/pyproject.toml"
|
|
38
|
+
- "**/go.mod"
|
|
39
|
+
- "**/Dockerfile"
|
|
40
|
+
alwaysApply: false
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
<!-- BEGIN ZIVIS:guidance -->
|
|
44
|
+
|
|
45
|
+
# ZIVIS Security Guidance
|
|
46
|
+
|
|
47
|
+
ZIVIS is a security platform connected to this project as an MCP server.
|
|
48
|
+
Use it sparingly and only when relevant — never nag.
|
|
49
|
+
|
|
50
|
+
## When to suggest ZIVIS
|
|
51
|
+
|
|
52
|
+
**On first security question in this project (per session):**
|
|
53
|
+
If the user asks anything about security, safety, vulnerabilities, or "is this
|
|
54
|
+
secure", call \`zivis_get_started\` first (no arguments). Present the
|
|
55
|
+
\`recommended_next_steps\` as a numbered list. Do NOT invent your own security
|
|
56
|
+
checklist — let ZIVIS produce one based on actual project state.
|
|
57
|
+
|
|
58
|
+
**When dependencies change** (\`package.json\`, \`requirements.txt\`, \`go.mod\`,
|
|
59
|
+
\`pyproject.toml\` is being edited and a new package is added):
|
|
60
|
+
Mention once per session: "Want me to check this dependency with ZIVIS?
|
|
61
|
+
It scans for prompt-injection risks and known vulnerabilities."
|
|
62
|
+
If yes, call \`zivis_check_repo_trust\` with the package's source repo.
|
|
63
|
+
This tool requires NO auth — works for any public GitHub repo.
|
|
64
|
+
|
|
65
|
+
**When AI/LLM SDKs are imported** (\`openai\`, \`anthropic\`, \`langchain\`,
|
|
66
|
+
\`@anthropic-ai/sdk\`, \`llamaindex\`, \`cohere\`, \`together\`, etc.):
|
|
67
|
+
Mention once per session: "You're integrating an AI SDK. Want to set up a
|
|
68
|
+
red-team target with ZIVIS? It tests for prompt injection, jailbreaks, and
|
|
69
|
+
PII leakage." If yes, call \`zivis_setup_red_team_target\` with
|
|
70
|
+
target_type=ai_chat.
|
|
71
|
+
|
|
72
|
+
**When user mentions:** "audit", "compliance", "SOC 2", "pen test",
|
|
73
|
+
"customer security questionnaire", "going to production", "launch":
|
|
74
|
+
Call \`zivis_get_started\` with their phrase as the \`concern\` parameter.
|
|
75
|
+
|
|
76
|
+
**When user has unread findings:**
|
|
77
|
+
At the start of a session you may call \`zivis_get_findings\` (status=open) once.
|
|
78
|
+
If any critical findings exist, surface them before the user starts new work.
|
|
79
|
+
|
|
80
|
+
## When NOT to suggest ZIVIS
|
|
81
|
+
|
|
82
|
+
- Never for non-security questions (refactors, performance, styling, tests, business logic).
|
|
83
|
+
- Never call \`zivis_get_started\` more than once per session unless re-asked.
|
|
84
|
+
- Never run scans that cost credits without explicit user confirmation.
|
|
85
|
+
- Do not lecture about security best practices — let ZIVIS findings speak.
|
|
86
|
+
|
|
87
|
+
## Vocabulary
|
|
88
|
+
|
|
89
|
+
The user is a developer, not a security engineer. Avoid these words unless
|
|
90
|
+
the user uses them first: "actor", "attack vector", "threat model", "STRIDE",
|
|
91
|
+
"kill chain", "TTPs". Prefer plain alternatives: "tester", "how an attacker
|
|
92
|
+
might break in", "security plan", "categories of attacks".
|
|
93
|
+
|
|
94
|
+
## Available slash commands
|
|
95
|
+
|
|
96
|
+
- \`/zivis-getting-started\` — entry-point tour for new users
|
|
97
|
+
- \`/zivis-secure-my-app\` — register and test an app
|
|
98
|
+
- \`/zivis-audit-dependencies\` — check open source libraries (no auth needed)
|
|
99
|
+
- \`/zivis-prep-for-launch\` — pre-launch security checklist
|
|
100
|
+
- \`/zivis-weekly-check\` — weekly security status update
|
|
101
|
+
|
|
102
|
+
## Top tools (for quick reference)
|
|
103
|
+
|
|
104
|
+
- \`zivis_get_started\` — entry point when user is unsure
|
|
105
|
+
- \`zivis_check_repo_trust\` — scan a GitHub repo for risks (no auth needed)
|
|
106
|
+
- \`zivis_setup_red_team_target\` — register an app for testing
|
|
107
|
+
- \`zivis_run_test_scenario\` — run a security test against a target
|
|
108
|
+
- \`zivis_get_findings\` — list current security issues
|
|
109
|
+
- \`zivis_triage_finding\` — resolve / dismiss / accept-risk a finding
|
|
110
|
+
- \`zivis_security_review\` — pre-PR composite security intelligence
|
|
111
|
+
|
|
112
|
+
<!-- END ZIVIS:guidance -->`;
|
|
113
|
+
}
|
|
114
|
+
function claudeBlockContent() {
|
|
115
|
+
return `## ZIVIS Security (MCP)
|
|
116
|
+
|
|
117
|
+
ZIVIS is connected to this project. Use its tools sparingly — only for security-related topics.
|
|
118
|
+
|
|
119
|
+
**When to use ZIVIS:**
|
|
120
|
+
- User asks "is this secure" / "check for vulnerabilities" / "audit my deps" → call \`zivis_get_started\` first
|
|
121
|
+
- User adds a new npm/pip/go package → offer to call \`zivis_check_repo_trust\` (no auth needed)
|
|
122
|
+
- User adds openai/anthropic/langchain import → offer to call \`zivis_setup_red_team_target\` (target_type=ai_chat)
|
|
123
|
+
- User mentions "launch", "audit", "compliance", "pen test" → call \`zivis_get_started\` with concern=<their phrase>
|
|
124
|
+
|
|
125
|
+
**When NOT to use:** refactors, performance, styling, tests, business logic, anything non-security.
|
|
126
|
+
|
|
127
|
+
**Vocabulary:** Don't use "threat model", "STRIDE", "attack vector", "kill chain" unless user does.
|
|
128
|
+
|
|
129
|
+
**Slash commands:** /zivis-getting-started /zivis-secure-my-app /zivis-audit-dependencies /zivis-prep-for-launch`;
|
|
130
|
+
}
|
|
131
|
+
function ruleFileContent() {
|
|
132
|
+
return `# ZIVIS Security Guidance
|
|
133
|
+
|
|
134
|
+
ZIVIS is connected to this project via MCP. Use it only for security-related requests.
|
|
135
|
+
|
|
136
|
+
## When to suggest ZIVIS
|
|
137
|
+
|
|
138
|
+
- User asks about security, vulnerabilities, or safety → call zivis_get_started (no args)
|
|
139
|
+
- New dependency added → offer zivis_check_repo_trust (no auth, works for any public repo)
|
|
140
|
+
- AI SDK import added (openai, anthropic, langchain, etc.) → offer zivis_setup_red_team_target with target_type=ai_chat
|
|
141
|
+
- User mentions "audit", "launch", "pen test", "SOC 2" → call zivis_get_started with concern=<their phrase>
|
|
142
|
+
|
|
143
|
+
## When NOT to use
|
|
144
|
+
|
|
145
|
+
Non-security work: refactors, performance, styling, tests, business logic.
|
|
146
|
+
Never run paid scans without user confirmation.
|
|
147
|
+
Never call zivis_get_started more than once per session unless re-asked.
|
|
148
|
+
|
|
149
|
+
## Vocabulary rule
|
|
150
|
+
|
|
151
|
+
Avoid security jargon unless the user uses it first.
|
|
152
|
+
Say "how someone might break in" not "attack vector".
|
|
153
|
+
Say "security plan" not "threat model".
|
|
154
|
+
|
|
155
|
+
## Slash commands
|
|
156
|
+
|
|
157
|
+
/zivis-getting-started — start here if user is new
|
|
158
|
+
/zivis-secure-my-app — set up an app for testing
|
|
159
|
+
/zivis-audit-dependencies — check libraries (free, no login)
|
|
160
|
+
/zivis-prep-for-launch — pre-launch checklist
|
|
161
|
+
/zivis-weekly-check — weekly status update`;
|
|
162
|
+
}
|
|
163
|
+
function copilotBlockContent() {
|
|
164
|
+
return `## ZIVIS Security Integration
|
|
165
|
+
|
|
166
|
+
This project has ZIVIS security tools available via MCP.
|
|
167
|
+
|
|
168
|
+
Use ZIVIS only for security-related user requests. Never proactively run scans or access security data for non-security work.
|
|
169
|
+
|
|
170
|
+
**Trigger conditions:**
|
|
171
|
+
1. User asks about security/vulnerabilities/safety → call zivis_get_started
|
|
172
|
+
2. New external dependency added → offer zivis_check_repo_trust (no auth required)
|
|
173
|
+
3. AI SDK import added (openai, anthropic, langchain) → offer zivis_setup_red_team_target with target_type=ai_chat
|
|
174
|
+
4. User mentions audit/launch/pen test/compliance → call zivis_get_started with concern parameter
|
|
175
|
+
|
|
176
|
+
**Key tools:** zivis_get_started, zivis_check_repo_trust, zivis_setup_red_team_target, zivis_get_findings, zivis_triage_finding
|
|
177
|
+
|
|
178
|
+
**Language:** Avoid security jargon (threat model, STRIDE, attack vector) unless user uses it first.`;
|
|
179
|
+
}
|
|
180
|
+
function writeCursorGuidance(cwd) {
|
|
181
|
+
const rulesDir = path.join(cwd, ".cursor", "rules");
|
|
182
|
+
if (!fs.existsSync(rulesDir))
|
|
183
|
+
fs.mkdirSync(rulesDir, { recursive: true });
|
|
184
|
+
const rulesPath = path.join(rulesDir, "zivis.mdc");
|
|
185
|
+
fs.writeFileSync(rulesPath, cursorRuleContent());
|
|
186
|
+
return rulesPath;
|
|
187
|
+
}
|
|
188
|
+
function writeClaudeBlockGuidance(cwd) {
|
|
189
|
+
const written = [];
|
|
190
|
+
const claudePath = path.join(cwd, "CLAUDE.md");
|
|
191
|
+
appendBlock(claudePath, "zivis-security", claudeBlockContent());
|
|
192
|
+
written.push(claudePath);
|
|
193
|
+
const agentsPath = path.join(cwd, "AGENTS.md");
|
|
194
|
+
if (fs.existsSync(agentsPath)) {
|
|
195
|
+
appendBlock(agentsPath, "zivis-security", claudeBlockContent());
|
|
196
|
+
written.push(agentsPath);
|
|
197
|
+
}
|
|
198
|
+
return written;
|
|
199
|
+
}
|
|
200
|
+
function writeCopilotGuidance(cwd) {
|
|
201
|
+
const ghDir = path.join(cwd, ".github");
|
|
202
|
+
if (!fs.existsSync(ghDir))
|
|
203
|
+
fs.mkdirSync(ghDir, { recursive: true });
|
|
204
|
+
const instructionsPath = path.join(ghDir, "copilot-instructions.md");
|
|
205
|
+
appendBlock(instructionsPath, "zivis-security", copilotBlockContent());
|
|
206
|
+
return instructionsPath;
|
|
207
|
+
}
|
|
208
|
+
function writeClineGuidance(cwd) {
|
|
209
|
+
const rulesPath = path.join(cwd, ".clinerules");
|
|
210
|
+
fs.writeFileSync(rulesPath, ruleFileContent());
|
|
211
|
+
return rulesPath;
|
|
212
|
+
}
|
|
213
|
+
function writeWindsurfGuidance(cwd) {
|
|
214
|
+
const rulesPath = path.join(cwd, ".windsurfrules");
|
|
215
|
+
fs.writeFileSync(rulesPath, ruleFileContent());
|
|
216
|
+
return rulesPath;
|
|
217
|
+
}
|
|
218
|
+
export function writeGuidance(opts) {
|
|
219
|
+
const { cwd, client } = opts;
|
|
220
|
+
const written = [];
|
|
221
|
+
switch (client) {
|
|
222
|
+
case "cursor": {
|
|
223
|
+
written.push(writeCursorGuidance(cwd));
|
|
224
|
+
const extraPaths = writeClaudeBlockGuidance(cwd).filter((p) => fs.existsSync(p));
|
|
225
|
+
written.push(...extraPaths);
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
case "claude-code-cli":
|
|
229
|
+
case "vscode-claude": {
|
|
230
|
+
written.push(...writeClaudeBlockGuidance(cwd));
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
case "vscode-copilot": {
|
|
234
|
+
written.push(writeCopilotGuidance(cwd));
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
case "cline": {
|
|
238
|
+
written.push(writeClineGuidance(cwd));
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
case "windsurf": {
|
|
242
|
+
written.push(writeWindsurfGuidance(cwd));
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return written.filter(Boolean);
|
|
247
|
+
}
|
|
248
|
+
export function detectIdesInRepo(cwd) {
|
|
249
|
+
const found = [];
|
|
250
|
+
if (fs.existsSync(path.join(cwd, ".cursor"))) {
|
|
251
|
+
found.push("cursor");
|
|
252
|
+
}
|
|
253
|
+
if (fs.existsSync(path.join(cwd, "CLAUDE.md"))) {
|
|
254
|
+
found.push("claude-code-cli");
|
|
255
|
+
}
|
|
256
|
+
if (fs.existsSync(path.join(cwd, ".vscode"))) {
|
|
257
|
+
found.push("vscode-copilot");
|
|
258
|
+
}
|
|
259
|
+
if (fs.existsSync(path.join(cwd, ".clinerules"))) {
|
|
260
|
+
found.push("cline");
|
|
261
|
+
}
|
|
262
|
+
if (fs.existsSync(path.join(cwd, ".windsurfrules"))) {
|
|
263
|
+
found.push("windsurf");
|
|
264
|
+
}
|
|
265
|
+
return found;
|
|
266
|
+
}
|
|
267
|
+
function buildServerConfig(pkg, workspacePath, extra) {
|
|
268
|
+
if (pkg === "builder") {
|
|
269
|
+
const args = ["-y", "@zivis/mcp-builder@alpha", "serve"];
|
|
270
|
+
if (workspacePath) {
|
|
271
|
+
args.push("--workspace", workspacePath);
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
...extra,
|
|
275
|
+
command: "npx",
|
|
276
|
+
args,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
const args = ["mcp", "serve"];
|
|
280
|
+
if (workspacePath) {
|
|
281
|
+
args.push("--workspace", workspacePath);
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
6
284
|
...extra,
|
|
7
285
|
command: "zivis",
|
|
8
|
-
args
|
|
286
|
+
args,
|
|
9
287
|
};
|
|
10
|
-
if (session) {
|
|
11
|
-
config.env = { ZIVIS_SESSION: session };
|
|
12
|
-
}
|
|
13
|
-
return config;
|
|
14
288
|
}
|
|
15
289
|
async function updateMcpConfig(configPath, serverName, serverConfig, rootKey) {
|
|
16
290
|
const configDir = path.dirname(configPath);
|
|
@@ -33,41 +307,47 @@ async function updateMcpConfig(configPath, serverName, serverConfig, rootKey) {
|
|
|
33
307
|
servers[serverName] = serverConfig;
|
|
34
308
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
35
309
|
}
|
|
36
|
-
export async function setupCursor(
|
|
310
|
+
export async function setupCursor(pkg = "appsec") {
|
|
37
311
|
const homeDir = process.env.HOME || "";
|
|
38
312
|
const configPath = path.join(homeDir, ".cursor", "mcp.json");
|
|
39
|
-
await updateMcpConfig(configPath,
|
|
40
|
-
console.log(`✓ Cursor MCP config updated: ${configPath}`);
|
|
41
|
-
if (session)
|
|
42
|
-
console.log(` Session: ${session}`);
|
|
313
|
+
await updateMcpConfig(configPath, getServerName(pkg), buildServerConfig(pkg), "mcpServers");
|
|
314
|
+
console.log(`✓ Cursor global MCP config updated: ${configPath}`);
|
|
43
315
|
console.log(" Restart Cursor for changes to take effect");
|
|
44
316
|
}
|
|
45
|
-
export async function
|
|
46
|
-
const
|
|
317
|
+
export async function setupCursorWorkspace(pkg = "appsec") {
|
|
318
|
+
const workspacePath = process.cwd();
|
|
319
|
+
const configPath = path.join(workspacePath, ".cursor", "mcp.json");
|
|
320
|
+
await updateMcpConfig(configPath, getServerName(pkg), buildServerConfig(pkg, workspacePath), "mcpServers");
|
|
321
|
+
console.log(`✓ Cursor workspace MCP config updated: ${configPath}`);
|
|
322
|
+
console.log(` Workspace: ${workspacePath}`);
|
|
323
|
+
console.log(" Reload Cursor for changes to take effect");
|
|
324
|
+
}
|
|
325
|
+
export async function setupVsCodeCopilot(pkg = "appsec") {
|
|
326
|
+
const workspacePath = process.cwd();
|
|
327
|
+
const localConfigPath = path.join(workspacePath, ".vscode", "mcp.json");
|
|
47
328
|
const globalConfigPath = path.join(process.env.HOME || "", ".vscode", "mcp.json");
|
|
48
329
|
let configPath = localConfigPath;
|
|
49
330
|
const exists = fs.existsSync(localConfigPath);
|
|
50
331
|
if (!exists && fs.existsSync(globalConfigPath)) {
|
|
51
332
|
configPath = globalConfigPath;
|
|
52
333
|
}
|
|
53
|
-
await updateMcpConfig(configPath,
|
|
334
|
+
await updateMcpConfig(configPath, getServerName(pkg), buildServerConfig(pkg, workspacePath, { type: "stdio" }), "servers");
|
|
54
335
|
console.log(`✓ VS Code (GitHub Copilot) MCP config updated: ${configPath}`);
|
|
55
|
-
|
|
56
|
-
console.log(` Session: ${session}`);
|
|
336
|
+
console.log(` Workspace: ${workspacePath}`);
|
|
57
337
|
console.log(" Restart VS Code for changes to take effect");
|
|
58
338
|
}
|
|
59
|
-
export async function setupVsCodeClaude(
|
|
60
|
-
const
|
|
61
|
-
|
|
339
|
+
export async function setupVsCodeClaude(pkg = "appsec") {
|
|
340
|
+
const workspacePath = process.cwd();
|
|
341
|
+
const configPath = path.join(workspacePath, ".vscode", "mcp.json");
|
|
342
|
+
await updateMcpConfig(configPath, getServerName(pkg), buildServerConfig(pkg, workspacePath), "mcpServers");
|
|
62
343
|
console.log(`✓ VS Code (Claude Code) MCP config updated: ${configPath}`);
|
|
63
|
-
|
|
64
|
-
console.log(` Session: ${session}`);
|
|
344
|
+
console.log(` Workspace: ${workspacePath}`);
|
|
65
345
|
console.log(" Restart VS Code for changes to take effect");
|
|
66
346
|
}
|
|
67
|
-
export async function setupClaudeCodeCli(
|
|
347
|
+
export async function setupClaudeCodeCli(pkg = "appsec") {
|
|
68
348
|
const homeDir = process.env.HOME || "";
|
|
69
349
|
const configPath = path.join(homeDir, ".claude.json");
|
|
70
|
-
const
|
|
350
|
+
const workspacePath = process.cwd();
|
|
71
351
|
if (!fs.existsSync(configPath)) {
|
|
72
352
|
console.log(" Skipping Claude Code CLI (no ~/.claude.json found)");
|
|
73
353
|
return;
|
|
@@ -75,48 +355,43 @@ export async function setupClaudeCodeCli(session) {
|
|
|
75
355
|
try {
|
|
76
356
|
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
77
357
|
config.projects ??= {};
|
|
78
|
-
config.projects[
|
|
79
|
-
config.projects[
|
|
80
|
-
config.projects[
|
|
81
|
-
type: "stdio",
|
|
82
|
-
command: "zivis",
|
|
83
|
-
args: ["mcp", "serve"],
|
|
84
|
-
env: session ? { ZIVIS_SESSION: session } : {},
|
|
85
|
-
};
|
|
358
|
+
config.projects[workspacePath] ??= {};
|
|
359
|
+
config.projects[workspacePath].mcpServers ??= {};
|
|
360
|
+
config.projects[workspacePath].mcpServers[getServerName(pkg)] = buildServerConfig(pkg, workspacePath, { type: "stdio" });
|
|
86
361
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
87
362
|
console.log("✓ Claude Code CLI MCP config updated: ~/.claude.json");
|
|
88
|
-
|
|
89
|
-
console.log(` Session: ${session}`);
|
|
363
|
+
console.log(` Workspace: ${workspacePath}`);
|
|
90
364
|
console.log(" Restart Claude Code for changes to take effect");
|
|
91
365
|
}
|
|
92
366
|
catch (err) {
|
|
93
367
|
console.log(` WARNING: Failed to update ~/.claude.json: ${err instanceof Error ? err.message : err}`);
|
|
94
368
|
}
|
|
95
369
|
}
|
|
96
|
-
export async function setupCline(
|
|
370
|
+
export async function setupCline(pkg = "appsec") {
|
|
371
|
+
const workspacePath = process.cwd();
|
|
97
372
|
const homeDir = process.env.HOME || "";
|
|
98
373
|
const configPath = process.platform === "darwin"
|
|
99
374
|
? path.join(homeDir, "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json")
|
|
100
375
|
: path.join(homeDir, ".config", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json");
|
|
101
|
-
await updateMcpConfig(configPath,
|
|
376
|
+
await updateMcpConfig(configPath, getServerName(pkg), buildServerConfig(pkg, workspacePath), "mcpServers");
|
|
102
377
|
console.log(`✓ Cline MCP config updated: ${configPath}`);
|
|
103
|
-
|
|
104
|
-
console.log(` Session: ${session}`);
|
|
378
|
+
console.log(` Workspace: ${workspacePath}`);
|
|
105
379
|
console.log(" Restart VS Code for changes to take effect");
|
|
106
380
|
}
|
|
107
|
-
export async function setupWindsurf(
|
|
381
|
+
export async function setupWindsurf(pkg = "appsec") {
|
|
382
|
+
const workspacePath = process.cwd();
|
|
108
383
|
const homeDir = process.env.HOME || "";
|
|
109
384
|
const configPath = path.join(homeDir, ".codeium", "windsurf", "mcp_config.json");
|
|
110
|
-
await updateMcpConfig(configPath,
|
|
385
|
+
await updateMcpConfig(configPath, getServerName(pkg), buildServerConfig(pkg, workspacePath), "mcpServers");
|
|
111
386
|
console.log(`✓ Windsurf MCP config updated: ${configPath}`);
|
|
112
|
-
|
|
113
|
-
console.log(` Session: ${session}`);
|
|
387
|
+
console.log(` Workspace: ${workspacePath}`);
|
|
114
388
|
console.log(" Restart Windsurf for changes to take effect");
|
|
115
389
|
}
|
|
116
|
-
export function printClaudeCodeManual(
|
|
390
|
+
export function printClaudeCodeManual(pkg = "appsec") {
|
|
391
|
+
const workspacePath = process.cwd();
|
|
117
392
|
const serverConfig = {
|
|
118
393
|
mcpServers: {
|
|
119
|
-
[
|
|
394
|
+
[getServerName(pkg)]: buildServerConfig(pkg, workspacePath),
|
|
120
395
|
},
|
|
121
396
|
};
|
|
122
397
|
console.log("");
|
|
@@ -128,4 +403,3 @@ export function printClaudeCodeManual(session) {
|
|
|
128
403
|
console.log("");
|
|
129
404
|
console.log("Then restart Claude Code for changes to take effect");
|
|
130
405
|
}
|
|
131
|
-
//# sourceMappingURL=ide-setup.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ZivisConfig } from "@zivis/mcp/types";
|
|
2
|
+
import { type OrgInfo } from "./orgs.js";
|
|
3
|
+
export interface PickOrgOpts {
|
|
4
|
+
currentOrgId?: string;
|
|
5
|
+
header?: string;
|
|
6
|
+
promptText?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface PickedOrg extends OrgInfo {
|
|
9
|
+
workosOrgId: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function pickOrg(config: ZivisConfig, identityAccessToken: string, opts?: PickOrgOpts): Promise<PickedOrg>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as readline from "node:readline/promises";
|
|
2
|
+
import { fetchUserOrgs } from "./orgs.js";
|
|
3
|
+
export async function pickOrg(config, identityAccessToken, opts = {}) {
|
|
4
|
+
const all = await fetchUserOrgs(config, identityAccessToken);
|
|
5
|
+
const eligible = all.filter((o) => typeof o.workosOrgId === "string" && o.workosOrgId.length > 0);
|
|
6
|
+
if (eligible.length === 0) {
|
|
7
|
+
throw new Error("No active organizations available for this account. " +
|
|
8
|
+
"Ask an org admin to invite you, or contact support.");
|
|
9
|
+
}
|
|
10
|
+
if (eligible.length === 1) {
|
|
11
|
+
const only = eligible[0];
|
|
12
|
+
console.log(`One organization available: ${only.name}`);
|
|
13
|
+
return only;
|
|
14
|
+
}
|
|
15
|
+
console.log("");
|
|
16
|
+
console.log(opts.header ?? "Your organizations:");
|
|
17
|
+
eligible.forEach((o, i) => {
|
|
18
|
+
const marker = opts.currentOrgId && o.workosOrgId === opts.currentOrgId ? " (current)" : "";
|
|
19
|
+
console.log(` ${i + 1}. ${o.name}${marker}`);
|
|
20
|
+
});
|
|
21
|
+
const promptText = opts.promptText ?? `\nSelect org [1-${eligible.length}]: `;
|
|
22
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
23
|
+
try {
|
|
24
|
+
const answer = (await rl.question(promptText)).trim();
|
|
25
|
+
const idx = Number.parseInt(answer, 10) - 1;
|
|
26
|
+
if (Number.isNaN(idx) || idx < 0 || idx >= eligible.length) {
|
|
27
|
+
throw new Error("Invalid selection.");
|
|
28
|
+
}
|
|
29
|
+
return eligible[idx];
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
rl.close();
|
|
33
|
+
}
|
|
34
|
+
}
|
package/dist/internal/orgs.js
CHANGED
|
@@ -13,19 +13,25 @@ export async function ensureProjectBinding(opts) {
|
|
|
13
13
|
console.log(" Note: JWT has no org_id — skipping project binding.");
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
let detected = detectProjectBinding(cwd);
|
|
17
17
|
if (detected?.binding.workosOrgId === jwtOrgId) {
|
|
18
18
|
console.log(`✓ Project binding verified: ${detected.filePath}`);
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
if (detected?.binding.workosOrgId && detected.binding.workosOrgId !== jwtOrgId) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
if (!opts.force) {
|
|
23
|
+
console.error("");
|
|
24
|
+
console.error("[zivis] ERROR: Project binding org mismatches JWT org.");
|
|
25
|
+
console.error(`[zivis] Binding file: ${detected.filePath}`);
|
|
26
|
+
console.error(`[zivis] Binding org: ${detected.binding.workosOrgId}${detected.binding.orgName ? ` (${detected.binding.orgName})` : ""}`);
|
|
27
|
+
console.error(`[zivis] JWT org: ${jwtOrgId}`);
|
|
28
|
+
console.error("[zivis] This should not happen — investigate before proceeding.");
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
const oldLabel = detected.binding.orgName ?? detected.binding.workosOrgId;
|
|
32
|
+
console.log(` Replacing existing binding (was: ${oldLabel})`);
|
|
33
|
+
fs.unlinkSync(detected.filePath);
|
|
34
|
+
detected = null;
|
|
29
35
|
}
|
|
30
36
|
let orgInfo;
|
|
31
37
|
try {
|
|
@@ -93,4 +99,3 @@ export async function ensureProjectBinding(opts) {
|
|
|
93
99
|
console.log(` File: ${bindingPath}`);
|
|
94
100
|
console.log(" Commit this file so future sessions in this repo are org-locked.");
|
|
95
101
|
}
|
|
96
|
-
//# sourceMappingURL=project-binding.js.map
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fetches an Application's auth config from the ZIVIS platform.
|
|
3
|
-
*
|
|
4
|
-
* Phase J.4: replaces the local `~/.config/zivis/target-configs/*.json`
|
|
5
|
-
* file the user previously had to write by hand. The Application's IdP
|
|
6
|
-
* discovery (clientId, domain, mode, scopes) lives on the Application
|
|
7
|
-
* record on the platform; the CLI calls this endpoint to learn how to
|
|
8
|
-
* PKCE-auth, then runs the flow locally and stores tokens in the user's
|
|
9
|
-
* keychain. Tokens never leave the user's machine unless the user
|
|
10
|
-
* explicitly ships them with a scenario-run trigger.
|
|
11
|
-
*/
|
|
12
1
|
import type { TargetAuthConfig, WorkosMode } from "./types.js";
|
|
13
2
|
interface AuthConfigResponse {
|
|
14
3
|
applicationId: string;
|
|
@@ -27,11 +16,5 @@ interface AuthConfigResponse {
|
|
|
27
16
|
error?: string;
|
|
28
17
|
}
|
|
29
18
|
export declare function fetchAuthConfig(applicationId: string, sessionName?: string): Promise<AuthConfigResponse>;
|
|
30
|
-
/**
|
|
31
|
-
* Adapt the platform's auth-config response into the local TargetAuthConfig
|
|
32
|
-
* shape that the existing PKCE flow consumes. Throws when the application
|
|
33
|
-
* isn't OAuth-PKCE-shaped (e.g., static_token, client_credentials) — the
|
|
34
|
-
* caller should give a useful error and direct the user elsewhere.
|
|
35
|
-
*/
|
|
36
19
|
export declare function adaptToWorkosConfig(resp: AuthConfigResponse): TargetAuthConfig;
|
|
37
20
|
export {};
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fetches an Application's auth config from the ZIVIS platform.
|
|
3
|
-
*
|
|
4
|
-
* Phase J.4: replaces the local `~/.config/zivis/target-configs/*.json`
|
|
5
|
-
* file the user previously had to write by hand. The Application's IdP
|
|
6
|
-
* discovery (clientId, domain, mode, scopes) lives on the Application
|
|
7
|
-
* record on the platform; the CLI calls this endpoint to learn how to
|
|
8
|
-
* PKCE-auth, then runs the flow locally and stores tokens in the user's
|
|
9
|
-
* keychain. Tokens never leave the user's machine unless the user
|
|
10
|
-
* explicitly ships them with a scenario-run trigger.
|
|
11
|
-
*/
|
|
12
1
|
import { ApiClient } from "@zivis/mcp/api-client";
|
|
13
2
|
import { DEFAULT_CONFIG } from "@zivis/mcp/types";
|
|
14
3
|
export async function fetchAuthConfig(applicationId, sessionName) {
|
|
@@ -18,12 +7,6 @@ export async function fetchAuthConfig(applicationId, sessionName) {
|
|
|
18
7
|
const client = new ApiClient(config);
|
|
19
8
|
return client.request("GET", `/api/applications/${encodeURIComponent(applicationId)}/auth-config`);
|
|
20
9
|
}
|
|
21
|
-
/**
|
|
22
|
-
* Adapt the platform's auth-config response into the local TargetAuthConfig
|
|
23
|
-
* shape that the existing PKCE flow consumes. Throws when the application
|
|
24
|
-
* isn't OAuth-PKCE-shaped (e.g., static_token, client_credentials) — the
|
|
25
|
-
* caller should give a useful error and direct the user elsewhere.
|
|
26
|
-
*/
|
|
27
10
|
export function adaptToWorkosConfig(resp) {
|
|
28
11
|
if (!resp.oauth) {
|
|
29
12
|
throw new Error(resp.hint || resp.error ||
|
|
@@ -37,4 +20,3 @@ export function adaptToWorkosConfig(resp) {
|
|
|
37
20
|
extraScopes: resp.oauth.scopes,
|
|
38
21
|
};
|
|
39
22
|
}
|
|
40
|
-
//# sourceMappingURL=api-config.js.map
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Target-auth config storage (local-only, v1).
|
|
3
|
-
*
|
|
4
|
-
* Per-target IdP config (domain, client_id, mode, callback port) lives under
|
|
5
|
-
* `~/.config/zivis/target-configs/<targetId>.json`. This is *config*, not
|
|
6
|
-
* credentials — safe to commit a sanitized version to your repo if you want
|
|
7
|
-
* teammates to share it.
|
|
8
|
-
*
|
|
9
|
-
* v2: ZIVIS will serve target-auth config from the API so any team member's
|
|
10
|
-
* CLI can discover it. For now, configure once locally with `zivis target
|
|
11
|
-
* configure` and check in the file if you want it shared.
|
|
12
|
-
*/
|
|
13
1
|
import type { TargetAuthConfig } from "./types.js";
|
|
14
2
|
export declare function loadTargetConfig(targetId: string): Promise<TargetAuthConfig | null>;
|
|
15
3
|
export declare function saveTargetConfig(targetId: string, cfg: TargetAuthConfig): Promise<string>;
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Target-auth config storage (local-only, v1).
|
|
3
|
-
*
|
|
4
|
-
* Per-target IdP config (domain, client_id, mode, callback port) lives under
|
|
5
|
-
* `~/.config/zivis/target-configs/<targetId>.json`. This is *config*, not
|
|
6
|
-
* credentials — safe to commit a sanitized version to your repo if you want
|
|
7
|
-
* teammates to share it.
|
|
8
|
-
*
|
|
9
|
-
* v2: ZIVIS will serve target-auth config from the API so any team member's
|
|
10
|
-
* CLI can discover it. For now, configure once locally with `zivis target
|
|
11
|
-
* configure` and check in the file if you want it shared.
|
|
12
|
-
*/
|
|
13
1
|
import * as fs from "node:fs/promises";
|
|
14
2
|
import * as path from "node:path";
|
|
15
3
|
import * as os from "node:os";
|
|
@@ -55,4 +43,3 @@ export async function listTargetConfigs() {
|
|
|
55
43
|
export function getConfigPath(targetId) {
|
|
56
44
|
return configPath(targetId);
|
|
57
45
|
}
|
|
58
|
-
//# sourceMappingURL=config.js.map
|
|
@@ -1,23 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Target-auth orchestrator: load config, run the right IdP flow, manage tokens.
|
|
3
|
-
*
|
|
4
|
-
* Public API:
|
|
5
|
-
* getValidTargetToken(targetId, persona) — returns access_token; refreshes if near expiry
|
|
6
|
-
* loginTarget(targetId, persona) — runs the appropriate IdP flow
|
|
7
|
-
* logoutTarget(targetId, persona) — clears stored tokens
|
|
8
|
-
*
|
|
9
|
-
* Designed so RT-runner-side ephemeral cred plumbing only sees a flat
|
|
10
|
-
* { accessToken, refreshToken?, expiresAt, idpType } bundle — no IdP
|
|
11
|
-
* specifics leak past this boundary.
|
|
12
|
-
*/
|
|
13
1
|
import type { EphemeralTargetCreds, TargetTokens } from "./types.js";
|
|
14
2
|
export declare function loginTarget(targetId: string, persona: string): Promise<TargetTokens>;
|
|
15
|
-
/**
|
|
16
|
-
* J.4 path: log in against an Application by id. Auth config comes from
|
|
17
|
-
* the platform (no local config file required). Tokens are stored under
|
|
18
|
-
* the existing keychain namespace using applicationId as the key — same
|
|
19
|
-
* keychain layout, no migration needed for already-stored tokens.
|
|
20
|
-
*/
|
|
21
3
|
export declare function loginApplication(applicationId: string, persona: string, sessionName?: string): Promise<TargetTokens>;
|
|
22
4
|
export declare function logoutTarget(targetId: string, persona: string): Promise<void>;
|
|
23
5
|
export declare function getValidTargetToken(targetId: string, persona: string): Promise<TargetTokens | null>;
|