@zivis/mcp 0.1.8 → 0.1.10

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 (330) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +19 -0
  3. package/dist/api-client.d.ts +2 -24
  4. package/dist/api-client.js +32 -52
  5. package/dist/auth/index.d.ts +1 -22
  6. package/dist/auth/index.js +17 -38
  7. package/dist/auth/jwt.d.ts +0 -16
  8. package/dist/auth/jwt.js +0 -13
  9. package/dist/auth/keychain.d.ts +6 -32
  10. package/dist/auth/keychain.js +83 -114
  11. package/dist/auth/oauth.d.ts +3 -32
  12. package/dist/auth/oauth.js +67 -61
  13. package/dist/auth/sessions.d.ts +5 -25
  14. package/dist/auth/sessions.js +20 -39
  15. package/dist/auth/token-refresh.d.ts +2 -22
  16. package/dist/auth/token-refresh.js +33 -36
  17. package/dist/cli.d.ts +1 -18
  18. package/dist/cli.js +30 -908
  19. package/dist/index.d.ts +0 -6
  20. package/dist/index.js +0 -7
  21. package/dist/lib/inspect-cache.d.ts +10 -0
  22. package/dist/lib/inspect-cache.js +75 -0
  23. package/dist/lib/next-steps.d.ts +27 -0
  24. package/dist/lib/next-steps.js +21 -0
  25. package/dist/matcher/ast-eval.d.ts +8 -0
  26. package/dist/matcher/ast-eval.js +95 -0
  27. package/dist/matcher/finding.d.ts +55 -0
  28. package/dist/matcher/finding.js +1 -0
  29. package/dist/matcher/index.d.ts +8 -0
  30. package/dist/matcher/index.js +202 -0
  31. package/dist/matcher/inference-candidates.d.ts +26 -0
  32. package/dist/matcher/inference-candidates.js +81 -0
  33. package/dist/matcher/walker.d.ts +7 -0
  34. package/dist/matcher/walker.js +71 -0
  35. package/dist/pattern-pack/index.d.ts +125 -0
  36. package/dist/pattern-pack/index.js +189 -0
  37. package/dist/pattern-packs/zivis-public-0.2.0/capsules/agents/privilege-separation.yaml +224 -0
  38. package/dist/pattern-packs/zivis-public-0.2.0/capsules/prompting/self-consistency-no-isolation.yaml +237 -0
  39. package/dist/pattern-packs/zivis-public-0.2.0/capsules/retrieval/context-injection-no-validator.yaml +348 -0
  40. package/dist/pattern-packs/zivis-public-0.2.0/capsules/security/late-org-filter.yaml +266 -0
  41. package/dist/pattern-packs/zivis-public-0.2.0/controls/external_validator_on_facts.yaml +37 -0
  42. package/dist/pattern-packs/zivis-public-0.2.0/controls/fact_validator_present.yaml +68 -0
  43. package/dist/pattern-packs/zivis-public-0.2.0/controls/human_approval_gate.yaml +44 -0
  44. package/dist/pattern-packs/zivis-public-0.2.0/controls/langgraph_state_machine_with_per_node_tools.yaml +35 -0
  45. package/dist/pattern-packs/zivis-public-0.2.0/controls/per_sample_retrieval_diversification.yaml +38 -0
  46. package/dist/pattern-packs/zivis-public-0.2.0/controls/prisma_extension_or_middleware_attaching_org_filter.yaml +31 -0
  47. package/dist/pattern-packs/zivis-public-0.2.0/controls/row_level_security_policy.yaml +37 -0
  48. package/dist/pattern-packs/zivis-public-0.2.0/controls/source_attribution_present.yaml +58 -0
  49. package/dist/pattern-packs/zivis-public-0.2.0/manifest.json +167 -0
  50. package/dist/pattern-packs/zivis-public-0.2.0/prompts/agents/privilege-separation/identify.md +54 -0
  51. package/dist/pattern-packs/zivis-public-0.2.0/prompts/prompting/self-consistency-no-isolation/identify.md +60 -0
  52. package/dist/pattern-packs/zivis-public-0.2.0/prompts/retrieval/context-injection-no-validator/identify.md +109 -0
  53. package/dist/pattern-packs/zivis-public-0.2.0/prompts/security/late-org-filter/identify.md +78 -0
  54. package/dist/project-binding.d.ts +2 -19
  55. package/dist/project-binding.js +38 -21
  56. package/dist/prompts/audit-dependencies.d.ts +2 -0
  57. package/dist/prompts/audit-dependencies.js +47 -0
  58. package/dist/prompts/getting-started.d.ts +2 -0
  59. package/dist/prompts/getting-started.js +37 -0
  60. package/dist/prompts/index.d.ts +2 -0
  61. package/dist/prompts/index.js +6 -0
  62. package/dist/resolve-application-id.d.ts +0 -4
  63. package/dist/resolve-application-id.js +0 -5
  64. package/dist/sanitize.d.ts +1 -21
  65. package/dist/sanitize.js +7 -41
  66. package/dist/server.d.ts +1 -13
  67. package/dist/server.js +142 -265
  68. package/dist/tools/artifacts.d.ts +76 -0
  69. package/dist/tools/artifacts.js +178 -0
  70. package/dist/tools/check-project.d.ts +5 -18
  71. package/dist/tools/check-project.js +122 -110
  72. package/dist/tools/check-repo-trust.d.ts +4 -19
  73. package/dist/tools/check-repo-trust.js +56 -47
  74. package/dist/tools/create-diagram.d.ts +0 -5
  75. package/dist/tools/create-diagram.js +0 -10
  76. package/dist/tools/create-document.d.ts +0 -5
  77. package/dist/tools/create-document.js +3 -9
  78. package/dist/tools/create-finding.d.ts +85 -0
  79. package/dist/tools/create-finding.js +136 -0
  80. package/dist/tools/delete-finding.d.ts +19 -0
  81. package/dist/tools/delete-finding.js +36 -0
  82. package/dist/tools/devx-run.d.ts +88 -0
  83. package/dist/tools/devx-run.js +175 -0
  84. package/dist/tools/discover-local-infra.d.ts +0 -10
  85. package/dist/tools/discover-local-infra.js +3 -73
  86. package/dist/tools/enterprise/get-org-zat.d.ts +0 -5
  87. package/dist/tools/enterprise/get-org-zat.js +0 -6
  88. package/dist/tools/explain-signal-for-diff.d.ts +34 -0
  89. package/dist/tools/explain-signal-for-diff.js +75 -0
  90. package/dist/tools/generate-diagram.d.ts +0 -6
  91. package/dist/tools/generate-diagram.js +21 -13
  92. package/dist/tools/get-application-overview.d.ts +0 -5
  93. package/dist/tools/get-application-overview.js +0 -6
  94. package/dist/tools/get-application.d.ts +0 -5
  95. package/dist/tools/get-application.js +0 -6
  96. package/dist/tools/get-diagram.d.ts +0 -5
  97. package/dist/tools/get-diagram.js +1 -11
  98. package/dist/tools/get-document.d.ts +0 -5
  99. package/dist/tools/get-document.js +0 -6
  100. package/dist/tools/get-oss-zat.d.ts +0 -5
  101. package/dist/tools/get-oss-zat.js +0 -7
  102. package/dist/tools/get-signal.d.ts +24 -0
  103. package/dist/tools/get-signal.js +75 -0
  104. package/dist/tools/get-started.d.ts +18 -0
  105. package/dist/tools/get-started.js +470 -0
  106. package/dist/tools/get-trust-keys.d.ts +0 -5
  107. package/dist/tools/get-trust-keys.js +0 -6
  108. package/dist/tools/import-openapi-endpoints.d.ts +0 -5
  109. package/dist/tools/import-openapi-endpoints.js +0 -6
  110. package/dist/tools/inspect-zat.d.ts +0 -5
  111. package/dist/tools/inspect-zat.js +0 -19
  112. package/dist/tools/inspect.d.ts +21 -0
  113. package/dist/tools/inspect.js +222 -0
  114. package/dist/tools/list-applications.d.ts +1 -6
  115. package/dist/tools/list-applications.js +0 -6
  116. package/dist/tools/list-diagrams.d.ts +0 -5
  117. package/dist/tools/list-diagrams.js +0 -6
  118. package/dist/tools/list-documents.d.ts +0 -5
  119. package/dist/tools/list-documents.js +0 -6
  120. package/dist/tools/list-endpoints.d.ts +1 -6
  121. package/dist/tools/list-endpoints.js +0 -6
  122. package/dist/tools/list-signals.d.ts +37 -0
  123. package/dist/tools/list-signals.js +83 -0
  124. package/dist/tools/manage-application.d.ts +64 -0
  125. package/dist/tools/manage-application.js +129 -0
  126. package/dist/tools/manage-diagram.d.ts +0 -5
  127. package/dist/tools/manage-diagram.js +0 -16
  128. package/dist/tools/manage-endpoint-lifecycle.d.ts +80 -0
  129. package/dist/tools/manage-endpoint-lifecycle.js +180 -0
  130. package/dist/tools/open-in-ide.d.ts +2 -14
  131. package/dist/tools/open-in-ide.js +0 -13
  132. package/dist/tools/review-change.d.ts +34 -0
  133. package/dist/tools/review-change.js +93 -0
  134. package/dist/tools/security-memory.d.ts +76 -0
  135. package/dist/tools/security-memory.js +202 -0
  136. package/dist/tools/security-review.d.ts +1 -21
  137. package/dist/tools/security-review.js +8 -108
  138. package/dist/tools/threat-get-capsule.d.ts +15 -0
  139. package/dist/tools/threat-get-capsule.js +53 -0
  140. package/dist/tools/threat-get-inference-prompt.d.ts +15 -0
  141. package/dist/tools/threat-get-inference-prompt.js +73 -0
  142. package/dist/tools/threat-list-relevant-capsules.d.ts +17 -0
  143. package/dist/tools/threat-list-relevant-capsules.js +158 -0
  144. package/dist/tools/threat-run-matcher.d.ts +17 -0
  145. package/dist/tools/threat-run-matcher.js +145 -0
  146. package/dist/tools/update-document.d.ts +0 -5
  147. package/dist/tools/update-document.js +3 -9
  148. package/dist/tools/update-endpoint.d.ts +1 -6
  149. package/dist/tools/update-endpoint.js +0 -7
  150. package/dist/tools/update-finding.d.ts +61 -0
  151. package/dist/tools/update-finding.js +80 -0
  152. package/dist/tools/update-mermaid-source.d.ts +0 -13
  153. package/dist/tools/update-mermaid-source.js +0 -14
  154. package/dist/tools/verify-trust-mark.d.ts +0 -5
  155. package/dist/tools/verify-trust-mark.js +0 -6
  156. package/dist/types.d.ts +14 -14
  157. package/dist/types.js +22 -28
  158. package/package.json +38 -15
  159. package/dist/api-client.js.map +0 -1
  160. package/dist/auth/index.js.map +0 -1
  161. package/dist/auth/jwt.js.map +0 -1
  162. package/dist/auth/keychain.js.map +0 -1
  163. package/dist/auth/oauth.js.map +0 -1
  164. package/dist/auth/sessions.js.map +0 -1
  165. package/dist/auth/token-refresh.js.map +0 -1
  166. package/dist/cli.js.map +0 -1
  167. package/dist/index.js.map +0 -1
  168. package/dist/project-binding.js.map +0 -1
  169. package/dist/resolve-application-id.js.map +0 -1
  170. package/dist/sanitize.js.map +0 -1
  171. package/dist/server.js.map +0 -1
  172. package/dist/tools/check-project.js.map +0 -1
  173. package/dist/tools/check-repo-trust.js.map +0 -1
  174. package/dist/tools/create-diagram.js.map +0 -1
  175. package/dist/tools/create-document.js.map +0 -1
  176. package/dist/tools/discover-local-infra.js.map +0 -1
  177. package/dist/tools/enterprise/capture-evidence.d.ts +0 -54
  178. package/dist/tools/enterprise/capture-evidence.js +0 -72
  179. package/dist/tools/enterprise/capture-evidence.js.map +0 -1
  180. package/dist/tools/enterprise/create-report-ticket.d.ts +0 -34
  181. package/dist/tools/enterprise/create-report-ticket.js +0 -44
  182. package/dist/tools/enterprise/create-report-ticket.js.map +0 -1
  183. package/dist/tools/enterprise/end-pentest-session.d.ts +0 -33
  184. package/dist/tools/enterprise/end-pentest-session.js +0 -42
  185. package/dist/tools/enterprise/end-pentest-session.js.map +0 -1
  186. package/dist/tools/enterprise/generate-report.d.ts +0 -55
  187. package/dist/tools/enterprise/generate-report.js +0 -111
  188. package/dist/tools/enterprise/generate-report.js.map +0 -1
  189. package/dist/tools/enterprise/get-org-zat.js.map +0 -1
  190. package/dist/tools/enterprise/get-report-status.d.ts +0 -27
  191. package/dist/tools/enterprise/get-report-status.js +0 -38
  192. package/dist/tools/enterprise/get-report-status.js.map +0 -1
  193. package/dist/tools/enterprise/get-threat-model.d.ts +0 -29
  194. package/dist/tools/enterprise/get-threat-model.js +0 -83
  195. package/dist/tools/enterprise/get-threat-model.js.map +0 -1
  196. package/dist/tools/enterprise/list-agents.d.ts +0 -42
  197. package/dist/tools/enterprise/list-agents.js +0 -95
  198. package/dist/tools/enterprise/list-agents.js.map +0 -1
  199. package/dist/tools/enterprise/list-report-issues.d.ts +0 -36
  200. package/dist/tools/enterprise/list-report-issues.js +0 -50
  201. package/dist/tools/enterprise/list-report-issues.js.map +0 -1
  202. package/dist/tools/enterprise/list-threat-models.d.ts +0 -36
  203. package/dist/tools/enterprise/list-threat-models.js +0 -82
  204. package/dist/tools/enterprise/list-threat-models.js.map +0 -1
  205. package/dist/tools/enterprise/manage-actor.d.ts +0 -58
  206. package/dist/tools/enterprise/manage-actor.js +0 -99
  207. package/dist/tools/enterprise/manage-actor.js.map +0 -1
  208. package/dist/tools/enterprise/manage-attack-scenario.d.ts +0 -70
  209. package/dist/tools/enterprise/manage-attack-scenario.js +0 -89
  210. package/dist/tools/enterprise/manage-attack-scenario.js.map +0 -1
  211. package/dist/tools/enterprise/manage-component.d.ts +0 -58
  212. package/dist/tools/enterprise/manage-component.js +0 -90
  213. package/dist/tools/enterprise/manage-component.js.map +0 -1
  214. package/dist/tools/enterprise/manage-data-asset.d.ts +0 -53
  215. package/dist/tools/enterprise/manage-data-asset.js +0 -90
  216. package/dist/tools/enterprise/manage-data-asset.js.map +0 -1
  217. package/dist/tools/enterprise/manage-data-flow.d.ts +0 -57
  218. package/dist/tools/enterprise/manage-data-flow.js +0 -98
  219. package/dist/tools/enterprise/manage-data-flow.js.map +0 -1
  220. package/dist/tools/enterprise/manage-finding.d.ts +0 -69
  221. package/dist/tools/enterprise/manage-finding.js +0 -106
  222. package/dist/tools/enterprise/manage-finding.js.map +0 -1
  223. package/dist/tools/enterprise/manage-security-control.d.ts +0 -59
  224. package/dist/tools/enterprise/manage-security-control.js +0 -96
  225. package/dist/tools/enterprise/manage-security-control.js.map +0 -1
  226. package/dist/tools/enterprise/manage-test-case.d.ts +0 -88
  227. package/dist/tools/enterprise/manage-test-case.js +0 -119
  228. package/dist/tools/enterprise/manage-test-case.js.map +0 -1
  229. package/dist/tools/enterprise/promote-finding-to-issue.d.ts +0 -36
  230. package/dist/tools/enterprise/promote-finding-to-issue.js +0 -65
  231. package/dist/tools/enterprise/promote-finding-to-issue.js.map +0 -1
  232. package/dist/tools/enterprise/publish-report-version.d.ts +0 -34
  233. package/dist/tools/enterprise/publish-report-version.js +0 -75
  234. package/dist/tools/enterprise/publish-report-version.js.map +0 -1
  235. package/dist/tools/enterprise/publish-test-to-library.d.ts +0 -31
  236. package/dist/tools/enterprise/publish-test-to-library.js +0 -40
  237. package/dist/tools/enterprise/publish-test-to-library.js.map +0 -1
  238. package/dist/tools/enterprise/record-test-result.d.ts +0 -67
  239. package/dist/tools/enterprise/record-test-result.js +0 -75
  240. package/dist/tools/enterprise/record-test-result.js.map +0 -1
  241. package/dist/tools/enterprise/start-pentest-session.d.ts +0 -35
  242. package/dist/tools/enterprise/start-pentest-session.js +0 -50
  243. package/dist/tools/enterprise/start-pentest-session.js.map +0 -1
  244. package/dist/tools/enterprise/sync-report-section.d.ts +0 -41
  245. package/dist/tools/enterprise/sync-report-section.js +0 -79
  246. package/dist/tools/enterprise/sync-report-section.js.map +0 -1
  247. package/dist/tools/enterprise/update-report-issue.d.ts +0 -55
  248. package/dist/tools/enterprise/update-report-issue.js +0 -69
  249. package/dist/tools/enterprise/update-report-issue.js.map +0 -1
  250. package/dist/tools/generate-diagram.js.map +0 -1
  251. package/dist/tools/get-agent-test-results.d.ts +0 -41
  252. package/dist/tools/get-agent-test-results.js +0 -86
  253. package/dist/tools/get-agent-test-results.js.map +0 -1
  254. package/dist/tools/get-application-overview.js.map +0 -1
  255. package/dist/tools/get-application.js.map +0 -1
  256. package/dist/tools/get-artifact-content.d.ts +0 -29
  257. package/dist/tools/get-artifact-content.js +0 -86
  258. package/dist/tools/get-artifact-content.js.map +0 -1
  259. package/dist/tools/get-diagram.js.map +0 -1
  260. package/dist/tools/get-document.js.map +0 -1
  261. package/dist/tools/get-finding-details.d.ts +0 -28
  262. package/dist/tools/get-finding-details.js +0 -43
  263. package/dist/tools/get-finding-details.js.map +0 -1
  264. package/dist/tools/get-findings.d.ts +0 -57
  265. package/dist/tools/get-findings.js +0 -103
  266. package/dist/tools/get-findings.js.map +0 -1
  267. package/dist/tools/get-oss-zat.js.map +0 -1
  268. package/dist/tools/get-recon-scan.d.ts +0 -27
  269. package/dist/tools/get-recon-scan.js +0 -46
  270. package/dist/tools/get-recon-scan.js.map +0 -1
  271. package/dist/tools/get-scan-output.d.ts +0 -27
  272. package/dist/tools/get-scan-output.js +0 -64
  273. package/dist/tools/get-scan-output.js.map +0 -1
  274. package/dist/tools/get-scenario-details.d.ts +0 -27
  275. package/dist/tools/get-scenario-details.js +0 -46
  276. package/dist/tools/get-scenario-details.js.map +0 -1
  277. package/dist/tools/get-test-case-results.d.ts +0 -37
  278. package/dist/tools/get-test-case-results.js +0 -66
  279. package/dist/tools/get-test-case-results.js.map +0 -1
  280. package/dist/tools/get-test-details.d.ts +0 -29
  281. package/dist/tools/get-test-details.js +0 -49
  282. package/dist/tools/get-test-details.js.map +0 -1
  283. package/dist/tools/get-trust-keys.js.map +0 -1
  284. package/dist/tools/import-openapi-endpoints.js.map +0 -1
  285. package/dist/tools/inspect-zat.js.map +0 -1
  286. package/dist/tools/list-agent-test-cases.d.ts +0 -41
  287. package/dist/tools/list-agent-test-cases.js +0 -73
  288. package/dist/tools/list-agent-test-cases.js.map +0 -1
  289. package/dist/tools/list-applications.js.map +0 -1
  290. package/dist/tools/list-diagrams.js.map +0 -1
  291. package/dist/tools/list-documents.js.map +0 -1
  292. package/dist/tools/list-endpoints.js.map +0 -1
  293. package/dist/tools/list-recon-scans.d.ts +0 -36
  294. package/dist/tools/list-recon-scans.js +0 -74
  295. package/dist/tools/list-recon-scans.js.map +0 -1
  296. package/dist/tools/list-scan-artifacts.d.ts +0 -41
  297. package/dist/tools/list-scan-artifacts.js +0 -63
  298. package/dist/tools/list-scan-artifacts.js.map +0 -1
  299. package/dist/tools/list-scans.d.ts +0 -44
  300. package/dist/tools/list-scans.js +0 -91
  301. package/dist/tools/list-scans.js.map +0 -1
  302. package/dist/tools/list-test-library.d.ts +0 -44
  303. package/dist/tools/list-test-library.js +0 -83
  304. package/dist/tools/list-test-library.js.map +0 -1
  305. package/dist/tools/list-test-scenarios.d.ts +0 -31
  306. package/dist/tools/list-test-scenarios.js +0 -66
  307. package/dist/tools/list-test-scenarios.js.map +0 -1
  308. package/dist/tools/local-scan.d.ts +0 -40
  309. package/dist/tools/local-scan.js +0 -261
  310. package/dist/tools/local-scan.js.map +0 -1
  311. package/dist/tools/manage-diagram.js.map +0 -1
  312. package/dist/tools/open-in-ide.js.map +0 -1
  313. package/dist/tools/run-test-scenario.d.ts +0 -37
  314. package/dist/tools/run-test-scenario.js +0 -70
  315. package/dist/tools/run-test-scenario.js.map +0 -1
  316. package/dist/tools/scan-pr.d.ts +0 -27
  317. package/dist/tools/scan-pr.js +0 -51
  318. package/dist/tools/scan-pr.js.map +0 -1
  319. package/dist/tools/security-review.js.map +0 -1
  320. package/dist/tools/setup-red-team-target.d.ts +0 -79
  321. package/dist/tools/setup-red-team-target.js +0 -430
  322. package/dist/tools/setup-red-team-target.js.map +0 -1
  323. package/dist/tools/triage-finding.d.ts +0 -47
  324. package/dist/tools/triage-finding.js +0 -116
  325. package/dist/tools/triage-finding.js.map +0 -1
  326. package/dist/tools/update-document.js.map +0 -1
  327. package/dist/tools/update-endpoint.js.map +0 -1
  328. package/dist/tools/update-mermaid-source.js.map +0 -1
  329. package/dist/tools/verify-trust-mark.js.map +0 -1
  330. package/dist/types.js.map +0 -1
@@ -1,15 +1,3 @@
1
- /**
2
- * OS Keychain credential storage
3
- *
4
- * Uses native OS CLI commands to store/retrieve credentials securely.
5
- * No native npm dependencies (no keytar).
6
- *
7
- * - macOS: Keychain Services via `security` CLI
8
- * - Linux: Secret Service API via `secret-tool` CLI
9
- * - Windows: DPAPI via PowerShell
10
- *
11
- * Falls back to encrypted file if keychain CLI is unavailable.
12
- */
13
1
  import { execFile } from "node:child_process";
14
2
  import { promisify } from "node:util";
15
3
  import * as fs from "node:fs/promises";
@@ -18,48 +6,49 @@ import * as os from "node:os";
18
6
  import * as crypto from "node:crypto";
19
7
  import { ENV_CONFIG } from "../types.js";
20
8
  const execFileAsync = promisify(execFile);
21
- // Use environment-aware prefix so staging and production credentials are isolated
22
- const SERVICE_PREFIX = ENV_CONFIG.keychainPrefix;
23
- /**
24
- * Returns the keychain account key for a given session.
25
- * - No session or undefined → "oauth" (backward compatible)
26
- * - Named session → "oauth.{session}"
27
- */
9
+ function resolvedStorage(storage) {
10
+ return (storage ?? {
11
+ keychainPrefix: ENV_CONFIG.keychainPrefix,
12
+ configDir: ENV_CONFIG.configDir,
13
+ });
14
+ }
28
15
  export function getSessionAccount(session) {
29
16
  return session ? `oauth.${session}` : "oauth";
30
17
  }
31
- function getServiceName(account) {
32
- return `${SERVICE_PREFIX}.${account}`;
18
+ function getServiceName(account, keychainPrefix) {
19
+ return `${keychainPrefix}.${account}`;
33
20
  }
34
- function getFallbackDir() {
35
- // Use environment-aware config dir so staging and production are isolated
36
- const configDir = ENV_CONFIG.configDir;
21
+ function getFallbackDir(configDir) {
37
22
  if (process.platform === "win32") {
38
23
  return path.join(process.env.APPDATA || os.homedir(), configDir);
39
24
  }
40
25
  return path.join(os.homedir(), ".config", configDir);
41
26
  }
42
- function getFallbackPath(account) {
43
- return path.join(getFallbackDir(), `${account}.enc`);
44
- }
45
- // ── macOS Keychain ──
46
- async function macosStore(account, value) {
47
- const service = getServiceName(account);
48
- // Delete existing entry first (ignore errors if not found)
49
- try {
50
- await execFileAsync("security", [
51
- "delete-generic-password",
52
- "-a",
53
- "zivis-mcp",
54
- "-s",
55
- service,
56
- ]);
57
- }
58
- catch {
59
- // Entry didn't exist, that's fine
27
+ function getFallbackPath(account, storage) {
28
+ return path.join(getFallbackDir(storage.configDir), `${account}.enc`);
29
+ }
30
+ async function macosDeleteAll(service) {
31
+ for (let i = 0; i < 100; i++) {
32
+ try {
33
+ await execFileAsync("security", [
34
+ "delete-generic-password",
35
+ "-a",
36
+ "zivis-mcp",
37
+ "-s",
38
+ service,
39
+ ]);
40
+ }
41
+ catch {
42
+ return;
43
+ }
60
44
  }
45
+ }
46
+ async function macosStore(account, value, keychainPrefix) {
47
+ const service = getServiceName(account, keychainPrefix);
48
+ await macosDeleteAll(service);
61
49
  await execFileAsync("security", [
62
50
  "add-generic-password",
51
+ "-U",
63
52
  "-a",
64
53
  "zivis-mcp",
65
54
  "-s",
@@ -68,8 +57,8 @@ async function macosStore(account, value) {
68
57
  value,
69
58
  ]);
70
59
  }
71
- async function macosRead(account) {
72
- const service = getServiceName(account);
60
+ async function macosRead(account, keychainPrefix) {
61
+ const service = getServiceName(account, keychainPrefix);
73
62
  try {
74
63
  const { stdout } = await execFileAsync("security", [
75
64
  "find-generic-password",
@@ -85,43 +74,29 @@ async function macosRead(account) {
85
74
  return null;
86
75
  }
87
76
  }
88
- async function macosDelete(account) {
89
- const service = getServiceName(account);
90
- try {
91
- await execFileAsync("security", [
92
- "delete-generic-password",
93
- "-a",
94
- "zivis-mcp",
95
- "-s",
96
- service,
97
- ]);
98
- }
99
- catch {
100
- // Entry didn't exist
101
- }
77
+ async function macosDelete(account, keychainPrefix) {
78
+ await macosDeleteAll(getServiceName(account, keychainPrefix));
102
79
  }
103
- // ── Linux Secret Service ──
104
- async function linuxStore(account, value) {
80
+ async function linuxStore(account, value, keychainPrefix) {
105
81
  const child = execFileAsync("secret-tool", [
106
82
  "store",
107
83
  "--label",
108
84
  `ZIVIS MCP ${account}`,
109
85
  "service",
110
- SERVICE_PREFIX,
86
+ keychainPrefix,
111
87
  "account",
112
88
  account,
113
89
  ]);
114
- // secret-tool reads value from stdin
115
90
  child.child.stdin?.write(value);
116
91
  child.child.stdin?.end();
117
92
  await child;
118
93
  }
119
- async function linuxRead(account) {
94
+ async function linuxRead(account, keychainPrefix) {
120
95
  try {
121
96
  const { stdout } = await execFileAsync("secret-tool", [
122
97
  "lookup",
123
98
  "service",
124
- SERVICE_PREFIX,
99
+ keychainPrefix,
125
100
  "account",
126
101
  account,
127
102
  ]);
@@ -131,44 +106,39 @@ async function linuxRead(account) {
131
106
  return null;
132
107
  }
133
108
  }
134
- async function linuxDelete(account) {
109
+ async function linuxDelete(account, keychainPrefix) {
135
110
  try {
136
111
  await execFileAsync("secret-tool", [
137
112
  "clear",
138
113
  "service",
139
- SERVICE_PREFIX,
114
+ keychainPrefix,
140
115
  "account",
141
116
  account,
142
117
  ]);
143
118
  }
144
119
  catch {
145
- // Entry didn't exist
146
120
  }
147
121
  }
148
- // ── Encrypted File Fallback (Windows + fallback for all platforms) ──
149
122
  function deriveKey() {
150
- // Use machine-specific data as encryption key seed
151
123
  const seed = `zivis-mcp:${os.hostname()}:${os.userInfo().username}`;
152
124
  return crypto.createHash("sha256").update(seed).digest();
153
125
  }
154
- async function fileStore(account, value) {
126
+ async function fileStore(account, value, storage) {
155
127
  const key = deriveKey();
156
128
  const iv = crypto.randomBytes(16);
157
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
158
129
  const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
159
130
  let encrypted = cipher.update(value, "utf8", "hex");
160
131
  encrypted += cipher.final("hex");
161
132
  const data = JSON.stringify({ iv: iv.toString("hex"), data: encrypted });
162
- const dir = getFallbackDir();
133
+ const dir = getFallbackDir(storage.configDir);
163
134
  await fs.mkdir(dir, { recursive: true });
164
- await fs.writeFile(getFallbackPath(account), data, { mode: 0o600 });
135
+ await fs.writeFile(getFallbackPath(account, storage), data, { mode: 0o600 });
165
136
  }
166
- async function fileRead(account) {
137
+ async function fileRead(account, storage) {
167
138
  try {
168
- const raw = await fs.readFile(getFallbackPath(account), "utf8");
139
+ const raw = await fs.readFile(getFallbackPath(account, storage), "utf8");
169
140
  const { iv, data } = JSON.parse(raw);
170
141
  const key = deriveKey();
171
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
172
142
  const decipher = crypto.createDecipheriv("aes-256-cbc", key, Buffer.from(iv, "hex"));
173
143
  let decrypted = decipher.update(data, "hex", "utf8");
174
144
  decrypted += decipher.final("utf8");
@@ -178,15 +148,13 @@ async function fileRead(account) {
178
148
  return null;
179
149
  }
180
150
  }
181
- async function fileDelete(account) {
151
+ async function fileDelete(account, storage) {
182
152
  try {
183
- await fs.unlink(getFallbackPath(account));
153
+ await fs.unlink(getFallbackPath(account, storage));
184
154
  }
185
155
  catch {
186
- // File didn't exist
187
156
  }
188
157
  }
189
- // ── Platform Detection & Dispatch ──
190
158
  async function isKeychainAvailable() {
191
159
  try {
192
160
  if (process.platform === "darwin") {
@@ -210,56 +178,58 @@ async function useKeychain() {
210
178
  }
211
179
  return keychainAvailable;
212
180
  }
213
- // ── Public API ──
214
- export async function keychainStore(account, value) {
215
- // Always store to encrypted file as fallback (for environments where keychain CLI
216
- // may not be available, e.g., MCP servers spawned by IDEs with different $PATH)
217
- await fileStore(account, value);
218
- // Also store to native keychain if available
181
+ export async function keychainStore(account, value, storage) {
182
+ const st = resolvedStorage(storage);
183
+ await fileStore(account, value, st);
219
184
  if (await useKeychain()) {
220
185
  if (process.platform === "darwin") {
221
- await macosStore(account, value);
186
+ await macosStore(account, value, st.keychainPrefix);
222
187
  }
223
188
  else if (process.platform === "linux") {
224
- await linuxStore(account, value);
189
+ await linuxStore(account, value, st.keychainPrefix);
225
190
  }
226
191
  }
227
192
  }
228
- export async function keychainRead(account) {
193
+ const LEGACY_KEYCHAIN_PREFIX = "io.zivis.mcp";
194
+ async function readFromBucket(account, storage) {
229
195
  if (await useKeychain()) {
230
196
  if (process.platform === "darwin")
231
- return macosRead(account);
197
+ return macosRead(account, storage.keychainPrefix);
232
198
  if (process.platform === "linux")
233
- return linuxRead(account);
234
- }
235
- return fileRead(account);
236
- }
237
- export async function keychainDelete(account) {
199
+ return linuxRead(account, storage.keychainPrefix);
200
+ }
201
+ return fileRead(account, storage);
202
+ }
203
+ export async function keychainRead(account, storage) {
204
+ const st = resolvedStorage(storage);
205
+ const primary = await readFromBucket(account, st);
206
+ if (primary !== null)
207
+ return primary;
208
+ if (st.keychainPrefix !== LEGACY_KEYCHAIN_PREFIX) {
209
+ return await readFromBucket(account, {
210
+ ...st,
211
+ keychainPrefix: LEGACY_KEYCHAIN_PREFIX,
212
+ });
213
+ }
214
+ return null;
215
+ }
216
+ export async function keychainDelete(account, storage) {
217
+ const st = resolvedStorage(storage);
218
+ await fileDelete(account, st);
238
219
  if (await useKeychain()) {
239
220
  if (process.platform === "darwin")
240
- return macosDelete(account);
221
+ return macosDelete(account, st.keychainPrefix);
241
222
  if (process.platform === "linux")
242
- return linuxDelete(account);
223
+ return linuxDelete(account, st.keychainPrefix);
243
224
  }
244
- return fileDelete(account);
245
225
  }
246
- /**
247
- * Delete credentials for a specific session
248
- */
249
- export async function keychainClearSession(session) {
250
- await keychainDelete(getSessionAccount(session));
226
+ export async function keychainClearSession(session, storage) {
227
+ await keychainDelete(getSessionAccount(session), storage);
251
228
  }
252
- /**
253
- * Delete all stored credentials (default OAuth + API key).
254
- * Does NOT clear named sessions — use keychainClearSession() for those.
255
- */
256
- export async function keychainClearAll() {
257
- await keychainDelete("oauth");
258
- await keychainDelete("apikey");
229
+ export async function keychainClearAll(storage) {
230
+ await keychainDelete("oauth", storage);
231
+ await keychainDelete("apikey", storage);
259
232
  }
260
- /**
261
- * Returns the storage mechanism name for display purposes
262
- */
263
233
  export function getStorageName() {
264
234
  if (process.platform === "darwin")
265
235
  return "macOS Keychain";
@@ -269,4 +239,3 @@ export function getStorageName() {
269
239
  return "encrypted file";
270
240
  return "encrypted file";
271
241
  }
272
- //# sourceMappingURL=keychain.js.map
@@ -1,38 +1,9 @@
1
- /**
2
- * OAuth PKCE Authentication Flow
3
- *
4
- * Authorization Code Flow with Proof Key for Code Exchange (PKCE)
5
- * for native/CLI applications. Uses WorkOS as the identity provider.
6
- *
7
- * Flow:
8
- * 1. Generate PKCE code_verifier + code_challenge
9
- * 2. Start localhost callback server
10
- * 3. Open browser to WorkOS authorization URL
11
- * 4. Receive authorization code via callback
12
- * 5. Exchange code + verifier for tokens
13
- * 6. Store tokens in OS keychain
14
- */
15
1
  import type { OAuthTokens, ZivisConfig } from "../types.js";
16
- /**
17
- * Run the full OAuth PKCE login flow.
18
- *
19
- * 1. Generate PKCE pair + state
20
- * 2. Start localhost callback server
21
- * 3. Open browser to WorkOS
22
- * 4. Wait for callback
23
- * 5. Exchange code for tokens
24
- * 6. Store tokens in keychain (under session-qualified key)
25
- *
26
- * @param config - Server configuration
27
- * @param session - Optional named session for multi-tenant isolation
28
- * @param organizationId - Optional WorkOS org ID to scope the login to a specific org
29
- * @param opts - Display and confirmation options
30
- * @returns The OAuth tokens
31
- */
32
2
  export interface LoginOptions {
33
- /** Human-readable org name, shown in the pre-browser confirmation prompt. */
34
3
  orgName?: string;
35
- /** Skip the pre-browser confirmation prompt (for scripted/interactive-wizard callers). */
4
+ sessionLabel?: string;
36
5
  skipConfirm?: boolean;
6
+ printUrlOnly?: boolean;
7
+ incognito?: boolean;
37
8
  }
38
9
  export declare function login(config?: ZivisConfig, session?: string, organizationId?: string, opts?: LoginOptions): Promise<OAuthTokens>;
@@ -1,17 +1,3 @@
1
- /**
2
- * OAuth PKCE Authentication Flow
3
- *
4
- * Authorization Code Flow with Proof Key for Code Exchange (PKCE)
5
- * for native/CLI applications. Uses WorkOS as the identity provider.
6
- *
7
- * Flow:
8
- * 1. Generate PKCE code_verifier + code_challenge
9
- * 2. Start localhost callback server
10
- * 3. Open browser to WorkOS authorization URL
11
- * 4. Receive authorization code via callback
12
- * 5. Exchange code + verifier for tokens
13
- * 6. Store tokens in OS keychain
14
- */
15
1
  import * as crypto from "node:crypto";
16
2
  import * as http from "node:http";
17
3
  import * as readline from "node:readline/promises";
@@ -19,8 +5,8 @@ import { URL } from "node:url";
19
5
  import open from "open";
20
6
  import { keychainStore, getSessionAccount } from "./keychain.js";
21
7
  import { decodeJwtPayload } from "./jwt.js";
22
- import { DEFAULT_CONFIG } from "../types.js";
23
- const LOGIN_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
8
+ import { DEFAULT_CONFIG, credentialStorageFromConfig } from "../types.js";
9
+ const LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
24
10
  function generatePKCE() {
25
11
  const verifier = crypto.randomBytes(32).toString("base64url");
26
12
  const challenge = crypto
@@ -42,29 +28,15 @@ function buildAuthUrl(config, codeChallenge, state, organizationId) {
42
28
  state,
43
29
  scope: "openid profile email offline_access",
44
30
  });
45
- // Scope the OAuth session to a specific org so the JWT has the correct org_id
46
31
  if (organizationId) {
47
32
  params.set("organization_id", organizationId);
48
33
  }
49
- // Force the WorkOS login screen even when an active session exists.
50
- // Why: users in multiple orgs must visually confirm which identity/org they're using —
51
- // silent SSO could let them accidentally bind the wrong org to a project.
52
34
  params.set("prompt", "login");
53
- // Handle both WorkOS (auth.workos.com -> /authorize) and custom AuthKit (authkit.app -> /oauth2/authorize)
54
- const isAuthKit = config.oauthApiUrl.includes("authkit.app");
35
+ const isAuthKit = !config.oauthApiUrl.includes("workos.com");
55
36
  const authPath = isAuthKit ? "/oauth2/authorize" : "/authorize";
56
37
  const authUrl = `${config.oauthApiUrl}${authPath}?${params.toString()}`;
57
- // We used to chain custom AuthKit hosts through /logout?return_to=... so
58
- // browser cookies did not override organization_id. AuthKit OIDC metadata
59
- // does not advertise end_session_endpoint, and *.authkit.app/logout returns
60
- // 404 — so that redirect is unusable. Rely on prompt=login plus
61
- // organization_id for org-scoped flows instead.
62
38
  return authUrl;
63
39
  }
64
- /**
65
- * Start a localhost HTTP server to receive the OAuth callback.
66
- * Returns the authorization code on success.
67
- */
68
40
  function startCallbackServer(port, expectedState) {
69
41
  return new Promise((resolve, reject) => {
70
42
  const server = http.createServer((req, res) => {
@@ -74,6 +46,11 @@ function startCallbackServer(port, expectedState) {
74
46
  const state = parsedUrl.searchParams.get("state");
75
47
  const error = parsedUrl.searchParams.get("error");
76
48
  const errorDesc = parsedUrl.searchParams.get("error_description");
49
+ if (state !== expectedState) {
50
+ res.writeHead(200, { "Content-Type": "text/html" });
51
+ res.end(callbackHtml(false, "This is a stale authentication tab. You can close it — your login is continuing in the original window."));
52
+ return;
53
+ }
77
54
  res.writeHead(200, { "Content-Type": "text/html" });
78
55
  if (error) {
79
56
  res.end(callbackHtml(false, errorDesc || error));
@@ -81,12 +58,6 @@ function startCallbackServer(port, expectedState) {
81
58
  reject(new Error(errorDesc || error));
82
59
  return;
83
60
  }
84
- if (state !== expectedState) {
85
- res.end(callbackHtml(false, "State mismatch — possible CSRF attack"));
86
- server.close();
87
- reject(new Error("State mismatch"));
88
- return;
89
- }
90
61
  if (!code) {
91
62
  res.end(callbackHtml(false, "No authorization code received"));
92
63
  server.close();
@@ -98,14 +69,13 @@ function startCallbackServer(port, expectedState) {
98
69
  resolve(code);
99
70
  }
100
71
  else {
101
- // 404 for any other path
102
72
  res.writeHead(404, { "Content-Type": "text/html" });
103
73
  res.end(`<!DOCTYPE html>
104
74
  <html>
105
75
  <head><title>Not Found</title></head>
106
76
  <body style="font-family:system-ui;text-align:center;padding:50px;background:#0f0f1a;color:#fff;">
107
77
  <h1>404 - Not Found</h1>
108
- <p>Expected callback at /callback, got ${parsedUrl.pathname}</p>
78
+ <p>Expected callback at /callback, got ${escapeHtml(parsedUrl.pathname)}</p>
109
79
  </body>
110
80
  </html>`);
111
81
  }
@@ -114,13 +84,20 @@ function startCallbackServer(port, expectedState) {
114
84
  reject(new Error(`Failed to start callback server on port ${port}: ${err.message}`));
115
85
  });
116
86
  server.listen(port, "127.0.0.1");
117
- // Timeout
118
87
  setTimeout(() => {
119
88
  server.close();
120
89
  reject(new Error("Authentication timed out after 5 minutes"));
121
90
  }, LOGIN_TIMEOUT_MS);
122
91
  });
123
92
  }
93
+ function escapeHtml(s) {
94
+ return s
95
+ .replace(/&/g, "&amp;")
96
+ .replace(/</g, "&lt;")
97
+ .replace(/>/g, "&gt;")
98
+ .replace(/"/g, "&quot;")
99
+ .replace(/'/g, "&#39;");
100
+ }
124
101
  function callbackHtml(success, errorMessage) {
125
102
  if (success) {
126
103
  return `<!DOCTYPE html>
@@ -138,17 +115,13 @@ function callbackHtml(success, errorMessage) {
138
115
  <head><title>Authentication Failed</title></head>
139
116
  <body style="font-family:system-ui;text-align:center;padding:50px;background:#0f0f1a;color:#fff;">
140
117
  <h1 style="color:#ff5252;">Authentication Failed</h1>
141
- <p>${errorMessage || "Unknown error"}</p>
118
+ <p>${escapeHtml(errorMessage || "Unknown error")}</p>
142
119
  <p>You can close this window.</p>
143
120
  </body>
144
121
  </html>`;
145
122
  }
146
- /**
147
- * Exchange authorization code for tokens via WorkOS token endpoint
148
- */
149
123
  async function exchangeCodeForTokens(config, code, codeVerifier) {
150
- // Handle both WorkOS (auth.workos.com -> /oauth/token) and custom AuthKit (authkit.app -> /oauth2/token)
151
- const tokenPath = config.oauthApiUrl.includes("authkit.app") ? "/oauth2/token" : "/oauth/token";
124
+ const tokenPath = config.oauthApiUrl.includes("workos.com") ? "/oauth/token" : "/oauth2/token";
152
125
  const tokenUrl = `${config.oauthApiUrl}${tokenPath}`;
153
126
  const response = await fetch(tokenUrl, {
154
127
  method: "POST",
@@ -169,6 +142,14 @@ async function exchangeCodeForTokens(config, code, codeVerifier) {
169
142
  throw new Error(errorMsg);
170
143
  }
171
144
  const data = (await response.json());
145
+ if (!data.refresh_token) {
146
+ console.error("[zivis] WARNING: WorkOS did not return a refresh_token. " +
147
+ "Verify the OAuth client has Refresh Tokens / offline_access enabled in the WorkOS dashboard. " +
148
+ "Without this, sessions will expire and require manual re-login.");
149
+ }
150
+ else {
151
+ console.error("[zivis] Token exchange complete — refresh_token received, session will auto-renew.");
152
+ }
172
153
  return {
173
154
  access_token: data.access_token,
174
155
  refresh_token: data.refresh_token,
@@ -183,13 +164,12 @@ export async function login(config = DEFAULT_CONFIG, session, organizationId, op
183
164
  const { verifier, challenge } = generatePKCE();
184
165
  const state = generateState();
185
166
  const authUrl = buildAuthUrl(config, challenge, state, organizationId);
186
- // Pre-browser confirmation: only when an org is scoped AND the terminal is interactive.
187
- // Protects users in multiple orgs from accidentally authenticating to the wrong tenant.
188
167
  if (organizationId && !opts.skipConfirm && process.stderr.isTTY && process.stdin.isTTY) {
189
168
  const orgLabel = opts.orgName
190
169
  ? `${opts.orgName} (${organizationId})`
191
170
  : organizationId;
192
- const sessionLabel = session ? ` as session "${session}"` : "";
171
+ const displaySession = opts.sessionLabel ?? session;
172
+ const sessionLabel = displaySession ? ` as session "${displaySession}"` : "";
193
173
  console.error("");
194
174
  console.error(`[zivis] About to authenticate to org: ${orgLabel}${sessionLabel}`);
195
175
  const rl = readline.createInterface({
@@ -209,18 +189,46 @@ export async function login(config = DEFAULT_CONFIG, session, organizationId, op
209
189
  else if (organizationId) {
210
190
  console.error(`[zivis] Login scoped to organization: ${organizationId}`);
211
191
  }
212
- // Start callback server before opening browser
213
192
  const codePromise = startCallbackServer(config.callbackPort, state);
214
- console.error("[zivis] Opening browser for authentication...");
215
- await open(authUrl);
216
- console.error("[zivis] Waiting for login...");
217
- // Wait for the authorization code
193
+ if (opts.printUrlOnly) {
194
+ console.error("[zivis] Open this URL in a private/incognito browser window:");
195
+ console.error("");
196
+ console.error(` ${authUrl}`);
197
+ console.error("");
198
+ console.error("[zivis] Waiting for login...");
199
+ }
200
+ else if (opts.incognito) {
201
+ let opened = false;
202
+ for (const app of [
203
+ { name: "google chrome", args: ["--incognito"] },
204
+ { name: "chromium", args: ["--incognito"] },
205
+ { name: "firefox", args: ["-private-window"] },
206
+ ]) {
207
+ try {
208
+ await open(authUrl, { app: { name: app.name, arguments: [authUrl, ...app.args] } });
209
+ console.error(`[zivis] Opened private window in ${app.name} — waiting for login...`);
210
+ opened = true;
211
+ break;
212
+ }
213
+ catch {
214
+ }
215
+ }
216
+ if (!opened) {
217
+ console.error("[zivis] Could not open an incognito window automatically.");
218
+ console.error("[zivis] Paste this URL into a private/incognito browser window:");
219
+ console.error("");
220
+ console.error(` ${authUrl}`);
221
+ console.error("");
222
+ console.error("[zivis] Waiting for login...");
223
+ }
224
+ }
225
+ else {
226
+ console.error("[zivis] Opening browser for authentication...");
227
+ await open(authUrl);
228
+ console.error("[zivis] Waiting for login...");
229
+ }
218
230
  const code = await codePromise;
219
- // Exchange code for tokens
220
231
  const tokens = await exchangeCodeForTokens(config, code, verifier);
221
- // Hard verification: if we requested a specific org, the returned JWT
222
- // MUST be scoped to that org. Refuse to store mismatched tokens — this is
223
- // the last-ditch guard against silently binding the wrong tenant.
224
232
  if (organizationId) {
225
233
  const claims = decodeJwtPayload(tokens.access_token);
226
234
  const jwtOrgId = claims?.org_id;
@@ -234,8 +242,6 @@ export async function login(config = DEFAULT_CONFIG, session, organizationId, op
234
242
  }
235
243
  console.error(`[zivis] \u2713 JWT org_id verified: ${jwtOrgId}`);
236
244
  }
237
- // Store in keychain (session-qualified key for multi-tenant isolation)
238
- await keychainStore(getSessionAccount(session), JSON.stringify(tokens));
245
+ await keychainStore(getSessionAccount(session), JSON.stringify(tokens), credentialStorageFromConfig(config));
239
246
  return tokens;
240
247
  }
241
- //# sourceMappingURL=oauth.js.map
@@ -1,28 +1,8 @@
1
- /**
2
- * Session Index Management
3
- *
4
- * Tracks named OAuth sessions in a JSON file so users can list
5
- * and manage multiple tenant sessions without enumerating keychain entries.
6
- *
7
- * Session index file: ~/.config/{configDir}/sessions.json
8
- */
9
1
  import type { SessionIndex, SessionInfo } from "../types.js";
10
- /**
11
- * Load the session index from disk.
12
- * Returns an empty object if the file doesn't exist.
13
- */
14
- export declare function loadSessionIndex(): Promise<SessionIndex>;
15
- /**
16
- * Add or update a session entry in the index.
17
- */
18
- export declare function saveSessionEntry(name: string, email: string): Promise<void>;
19
- /**
20
- * Remove a session entry from the index.
21
- */
22
- export declare function removeSessionEntry(name: string): Promise<void>;
23
- /**
24
- * List all sessions with their metadata.
25
- */
26
- export declare function listSessions(): Promise<Array<{
2
+ import { type CredentialStorage } from "../types.js";
3
+ export declare function loadSessionIndex(storage?: CredentialStorage): Promise<SessionIndex>;
4
+ export declare function saveSessionEntry(name: string, email: string, storage?: CredentialStorage): Promise<void>;
5
+ export declare function removeSessionEntry(name: string, storage?: CredentialStorage): Promise<void>;
6
+ export declare function listSessions(storage?: CredentialStorage): Promise<Array<{
27
7
  name: string;
28
8
  } & SessionInfo>>;