@zivis/cli 0.1.0-alpha.43 → 0.1.0-alpha.44

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.
@@ -9,7 +9,7 @@ import { discardOauthAfterLogin, tryAutoMintBindingTokenAfterLogin, } from "../.
9
9
  import { decodeJwtPayload } from "@zivis/mcp/auth/jwt";
10
10
  import { detectIdesInRepo, writeGuidance } from "../../internal/ide-setup.js";
11
11
  import { buildLinkagePrompt } from "../../internal/github-linkage-prompt.js";
12
- import { resolveExistingSessionTokens } from "../../internal/resolve-init-session.js";
12
+ import { resolveExistingSessionAuth } from "../../internal/resolve-init-session.js";
13
13
  async function maybePromptGitHubLinkage(config) {
14
14
  try {
15
15
  const msg = await buildLinkagePrompt({ config });
@@ -74,11 +74,15 @@ export async function initCommand(opts) {
74
74
  console.log(`Environment: ${envLabel} (${config.apiBaseUrl})`);
75
75
  console.log("");
76
76
  let tokens;
77
- const existing = await resolveExistingSessionTokens(config, session);
77
+ let existingOrgId;
78
+ let existingEmail;
79
+ const existing = await resolveExistingSessionAuth(config, session, process.cwd());
78
80
  if (existing) {
79
81
  console.log("Existing session found — reusing stored credentials.");
80
82
  console.log("(Run `zivis auth logout` first to switch accounts.)\n");
81
- tokens = existing;
83
+ tokens = { access_token: existing.accessToken, id_token: existing.idToken };
84
+ existingOrgId = existing.organizationId;
85
+ existingEmail = existing.email;
82
86
  }
83
87
  else {
84
88
  console.log("Opening browser for authentication...");
@@ -91,9 +95,9 @@ export async function initCommand(opts) {
91
95
  process.exit(1);
92
96
  }
93
97
  }
94
- const email = extractEmail(tokens.id_token);
98
+ const email = existingEmail ?? extractEmail(tokens.id_token);
95
99
  const claims = decodeJwtPayload(tokens.access_token);
96
- const jwtOrgId = claims?.org_id;
100
+ const jwtOrgId = existingOrgId ?? claims?.org_id;
97
101
  if (jwtOrgId) {
98
102
  let orgName;
99
103
  try {
@@ -45,17 +45,39 @@ export function registerRunCommands(program) {
45
45
  contractVersion: DEVX_RUN_CONTRACT_VERSION,
46
46
  result,
47
47
  });
48
+ const reconciliation = response.reconciliation;
48
49
  const output = jsonEnvelope("run complete", {
49
50
  run_id: runId,
50
51
  outcome: response.outcome,
51
52
  status: response.run.status,
52
53
  completed_at: response.run.completedAt,
54
+ ...(reconciliation
55
+ ? {
56
+ finding_ids: reconciliation.findings.map((f) => ({ id: f.id, action: f.action })),
57
+ retest_results: reconciliation.retests,
58
+ evidence_ids: reconciliation.evidence.map((e) => ({ id: e.id, action: e.action })),
59
+ coverage: reconciliation.coverage,
60
+ }
61
+ : {}),
53
62
  });
54
63
  if (json) {
55
64
  printJson(output);
56
65
  }
57
66
  else {
58
67
  console.log(`zivis run complete: ${response.outcome} (run ${runId} is now ${response.run.status})`);
68
+ if (reconciliation) {
69
+ const created = reconciliation.findings.filter((f) => f.action === "created").length;
70
+ const updated = reconciliation.findings.filter((f) => f.action === "updated").length;
71
+ const retested = reconciliation.retests.filter((r) => r.action === "disposition_updated").length;
72
+ if (created)
73
+ console.log(` + ${created} new finding${created === 1 ? "" : "s"}`);
74
+ if (updated)
75
+ console.log(` ~ ${updated} finding${updated === 1 ? "" : "s"} updated`);
76
+ if (retested)
77
+ console.log(` ✓ ${retested} retest${retested === 1 ? "" : "s"} recorded`);
78
+ if (reconciliation.evidence.length)
79
+ console.log(` ${reconciliation.evidence.length} artifact(s) persisted`);
80
+ }
59
81
  }
60
82
  process.exit(EXIT.OK);
61
83
  }
@@ -31,9 +31,30 @@ export interface DevXRunWire {
31
31
  cancelledAt: string | null;
32
32
  cancelReason: string | null;
33
33
  }
34
+ export interface DevXRunReconciliationSummary {
35
+ findings: Array<{
36
+ id: string;
37
+ action: "created" | "updated" | "unchanged";
38
+ fingerprint: string;
39
+ }>;
40
+ retests: Array<{
41
+ findingId: string;
42
+ outcome: "resolved" | "still_present";
43
+ action: "disposition_updated" | "no_change";
44
+ }>;
45
+ evidence: Array<{
46
+ id: string;
47
+ action: "created" | "existing";
48
+ }>;
49
+ coverage: Array<{
50
+ scopeId: string;
51
+ applicability: string;
52
+ }>;
53
+ }
34
54
  export interface DevXRunOutcome {
35
55
  outcome: "completed" | "cancelled" | "idempotent-replay";
36
56
  run: DevXRunWire;
57
+ reconciliation?: DevXRunReconciliationSummary;
37
58
  }
38
59
  export declare function isRetryableDevXRunError(err: unknown): boolean;
39
60
  export declare function completeDevXRunRemote(client: DevXRunApi, params: {
@@ -7,10 +7,10 @@ import { fetchUserOrgs } from "./orgs.js";
7
7
  export async function ensureProjectBinding(opts) {
8
8
  const { config, session, accessToken, cwd, autoBind, skipBind } = opts;
9
9
  const claims = decodeJwtPayload(accessToken);
10
- const jwtOrgId = claims?.org_id;
10
+ const jwtOrgId = claims?.org_id ?? opts.organizationId;
11
11
  if (!jwtOrgId) {
12
12
  console.log("");
13
- console.log(" Note: JWT has no org_id — skipping project binding.");
13
+ console.log(" Note: no org_id available (JWT has none, and no organizationId was supplied) — skipping project binding.");
14
14
  return;
15
15
  }
16
16
  let detected = detectProjectBinding(cwd);
@@ -1,6 +1,8 @@
1
1
  import { type ZivisConfig } from "@zivis/mcp/types";
2
- export interface ExistingSessionTokens {
3
- access_token: string;
4
- id_token?: string;
2
+ export interface ExistingSessionAuth {
3
+ accessToken: string;
4
+ idToken?: string;
5
+ organizationId?: string;
6
+ email?: string;
5
7
  }
6
- export declare function resolveExistingSessionTokens(config: ZivisConfig, session: string): Promise<ExistingSessionTokens | null>;
8
+ export declare function resolveExistingSessionAuth(config: ZivisConfig, session: string, cwd: string): Promise<ExistingSessionAuth | null>;
@@ -1,10 +1,36 @@
1
- import { loadTokens } from "@zivis/mcp/auth";
1
+ import { loadTokens, loadSessionIndex, resolveAuth } from "@zivis/mcp/auth";
2
2
  import { getValidAccessToken } from "@zivis/mcp/auth/token-refresh";
3
3
  import { credentialStorageFromConfig } from "@zivis/mcp/types";
4
- export async function resolveExistingSessionTokens(config, session) {
5
- const accessToken = await getValidAccessToken({ ...config, session });
6
- if (!accessToken)
4
+ import { detectProjectBinding } from "@zivis/mcp/project-binding";
5
+ import { fetchUserOrgs } from "./orgs.js";
6
+ export async function resolveExistingSessionAuth(config, session, cwd) {
7
+ const sessionConfig = { ...config, session };
8
+ const oauthAccessToken = await getValidAccessToken(sessionConfig);
9
+ if (oauthAccessToken) {
10
+ const stored = await loadTokens(session, credentialStorageFromConfig(config));
11
+ return { accessToken: oauthAccessToken, idToken: stored?.id_token };
12
+ }
13
+ const creds = await resolveAuth(sessionConfig, "apikey");
14
+ if (creds.method !== "apikey" || !creds.apiKey)
7
15
  return null;
8
- const stored = await loadTokens(session, credentialStorageFromConfig(config));
9
- return { access_token: accessToken, id_token: stored?.id_token };
16
+ const binding = detectProjectBinding(cwd);
17
+ const workosOrgId = binding?.binding.workosOrgId;
18
+ if (!workosOrgId)
19
+ return null;
20
+ let orgs;
21
+ try {
22
+ orgs = await fetchUserOrgs(config, creds.apiKey);
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ if (!orgs.some((o) => o.workosOrgId === workosOrgId)) {
28
+ return null;
29
+ }
30
+ const index = await loadSessionIndex(credentialStorageFromConfig(config));
31
+ return {
32
+ accessToken: creds.apiKey,
33
+ organizationId: workosOrgId,
34
+ email: index[session]?.email,
35
+ };
10
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zivis/cli",
3
- "version": "0.1.0-alpha.43",
3
+ "version": "0.1.0-alpha.44",
4
4
  "description": "ZIVIS CLI — threat modeling, scans, and MCP server for IDE integration",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://zivis.ai",