mobbdev 1.0.207 → 1.0.209

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.
@@ -28,13 +28,11 @@ var init_env = __esm({
28
28
  });
29
29
 
30
30
  // src/mcp/core/configs.ts
31
- var MCP_DEFAULT_API_URL, MCP_API_KEY_HEADER_NAME, MCP_LOGIN_MAX_WAIT, MCP_LOGIN_CHECK_DELAY, MCP_VUL_REPORT_DIGEST_TIMEOUT_MS, MCP_MAX_FILE_SIZE, MCP_PERIODIC_CHECK_INTERVAL, MCP_REPORT_ID_EXPIRATION_MS, MCP_TOOLS_BROWSER_COOLDOWN_MS, MCP_DEFAULT_LIMIT, isAutoScan, MVS_AUTO_FIX_OVERRIDE, MCP_PERIODIC_TRACK_INTERVAL, MCP_SYSTEM_FIND_TIMEOUT_MS;
31
+ var MCP_LOGIN_MAX_WAIT, MCP_LOGIN_CHECK_DELAY, MCP_VUL_REPORT_DIGEST_TIMEOUT_MS, MCP_MAX_FILE_SIZE, MCP_PERIODIC_CHECK_INTERVAL, MCP_REPORT_ID_EXPIRATION_MS, MCP_TOOLS_BROWSER_COOLDOWN_MS, isAutoScan, MVS_AUTO_FIX_OVERRIDE, MCP_PERIODIC_TRACK_INTERVAL, MCP_SYSTEM_FIND_TIMEOUT_MS;
32
32
  var init_configs = __esm({
33
33
  "src/mcp/core/configs.ts"() {
34
34
  "use strict";
35
35
  init_env();
36
- MCP_DEFAULT_API_URL = "https://api.mobb.ai/v1/graphql";
37
- MCP_API_KEY_HEADER_NAME = "x-mobb-key";
38
36
  MCP_LOGIN_MAX_WAIT = 2 * 60 * 1e3;
39
37
  MCP_LOGIN_CHECK_DELAY = 2 * 1e3;
40
38
  MCP_VUL_REPORT_DIGEST_TIMEOUT_MS = 30 * 60 * 1e3;
@@ -42,7 +40,6 @@ var init_configs = __esm({
42
40
  MCP_PERIODIC_CHECK_INTERVAL = 15 * 60 * 1e3;
43
41
  MCP_REPORT_ID_EXPIRATION_MS = 2 * 60 * 60 * 1e3;
44
42
  MCP_TOOLS_BROWSER_COOLDOWN_MS = 24 * 60 * 60 * 1e3;
45
- MCP_DEFAULT_LIMIT = 3;
46
43
  isAutoScan = process.env["AUTO_SCAN"] !== "false";
47
44
  MVS_AUTO_FIX_OVERRIDE = process.env["MVS_AUTO_FIX"];
48
45
  MCP_PERIODIC_TRACK_INTERVAL = 60 * 60 * 1e3;
@@ -94,21 +91,18 @@ var init_GitService = __esm({
94
91
  // src/args/commands/upload_ai_blame.ts
95
92
  import fsPromises2 from "fs/promises";
96
93
  import path6 from "path";
97
- import chalk2 from "chalk";
94
+ import chalk3 from "chalk";
95
+ import Configstore2 from "configstore";
98
96
  import { withFile } from "tmp-promise";
99
- import z27 from "zod";
97
+ import z26 from "zod";
100
98
 
101
- // src/features/analysis/upload-file.ts
99
+ // src/commands/handleMobbLogin.ts
100
+ import crypto from "crypto";
101
+ import os from "os";
102
+ import chalk2 from "chalk";
103
+ import Configstore from "configstore";
102
104
  import Debug7 from "debug";
103
- import fetch3, { File, fileFrom, FormData } from "node-fetch";
104
-
105
- // src/features/analysis/graphql/gql.ts
106
- import fetchOrig from "cross-fetch";
107
- import Debug6 from "debug";
108
- import { GraphQLClient } from "graphql-request";
109
- import { HttpProxyAgent } from "http-proxy-agent";
110
- import { HttpsProxyAgent as HttpsProxyAgent2 } from "https-proxy-agent";
111
- import { v4 as uuidv4 } from "uuid";
105
+ import open from "open";
112
106
 
113
107
  // src/constants.ts
114
108
  import path2 from "path";
@@ -2151,39 +2145,99 @@ var errorMessages = {
2151
2145
  };
2152
2146
  var VUL_REPORT_DIGEST_TIMEOUT_MS = 1e3 * 60 * 30;
2153
2147
 
2148
+ // src/features/analysis/graphql/gql.ts
2149
+ import fetchOrig from "cross-fetch";
2150
+ import Debug6 from "debug";
2151
+ import { GraphQLClient } from "graphql-request";
2152
+ import { HttpProxyAgent } from "http-proxy-agent";
2153
+ import { HttpsProxyAgent as HttpsProxyAgent2 } from "https-proxy-agent";
2154
+ import { v4 as uuidv4 } from "uuid";
2155
+
2154
2156
  // src/mcp/core/Errors.ts
2155
- var ApiConnectionError = class extends Error {
2156
- constructor(message = "Failed to connect to the API") {
2157
+ var _ReportDigestError = class _ReportDigestError extends Error {
2158
+ constructor(message, failReason) {
2157
2159
  super(message);
2158
- this.name = "ApiConnectionError";
2160
+ this.failReason = failReason;
2161
+ this.name = "ReportDigestError";
2162
+ this.failReason = failReason;
2159
2163
  }
2160
- };
2161
- var CliLoginError = class extends Error {
2162
- constructor(message = "CLI login failed") {
2163
- super(message);
2164
- this.name = "CliLoginError";
2164
+ getDisplayMessage() {
2165
+ if (this.failReason?.trim()) {
2166
+ return `\u{1F575}\uFE0F\u200D\u2642\uFE0F Digesting report failed. ${this.failReason}`;
2167
+ }
2168
+ return _ReportDigestError.defaultMessage;
2165
2169
  }
2166
2170
  };
2167
- var AuthenticationError = class extends Error {
2168
- constructor(message = "Authentication failed") {
2169
- super(message);
2170
- this.name = "AuthenticationError";
2171
- }
2172
- };
2173
- var FailedToGetApiTokenError = class extends Error {
2174
- constructor(message) {
2175
- super(message);
2176
- this.name = "FailedToGetApiTokenError";
2177
- }
2171
+ __publicField(_ReportDigestError, "defaultMessage", "\u{1F575}\uFE0F\u200D\u2642\uFE0F Digesting report failed. Please verify that the file provided is of a valid supported report format.");
2172
+ var ReportDigestError = _ReportDigestError;
2173
+
2174
+ // src/types.ts
2175
+ var ScanContext = {
2176
+ FULL_SCAN: "FULL_SCAN",
2177
+ BACKGROUND_PERIODIC: "BACKGROUND_PERIODIC",
2178
+ BACKGROUND_INITIAL: "BACKGROUND_INITIAL",
2179
+ USER_REQUEST: "USER_REQUEST",
2180
+ BUGSY: "BUGSY"
2178
2181
  };
2179
2182
 
2180
2183
  // src/utils/keypress.ts
2181
2184
  import readline from "readline";
2185
+ async function keypress() {
2186
+ const rl = readline.createInterface({
2187
+ input: process.stdin,
2188
+ output: process.stdout
2189
+ });
2190
+ return new Promise((resolve) => {
2191
+ rl.question("", (answer) => {
2192
+ rl.close();
2193
+ process.stderr.moveCursor(0, -1);
2194
+ process.stderr.clearLine(1);
2195
+ resolve(answer);
2196
+ });
2197
+ });
2198
+ }
2182
2199
 
2183
2200
  // src/utils/spinner.ts
2184
2201
  import {
2185
2202
  createSpinner as _createSpinner
2186
2203
  } from "nanospinner";
2204
+ function printToStdError(opts) {
2205
+ if (opts?.text) console.error(opts.text);
2206
+ }
2207
+ var mockSpinner = {
2208
+ success: (opts) => {
2209
+ printToStdError(opts);
2210
+ return mockSpinner;
2211
+ },
2212
+ error: (opts) => {
2213
+ printToStdError(opts);
2214
+ return mockSpinner;
2215
+ },
2216
+ warn: (opts) => {
2217
+ printToStdError(opts);
2218
+ return mockSpinner;
2219
+ },
2220
+ stop: (opts) => {
2221
+ printToStdError(opts);
2222
+ return mockSpinner;
2223
+ },
2224
+ start: (opts) => {
2225
+ printToStdError(opts);
2226
+ return mockSpinner;
2227
+ },
2228
+ update: (opts) => {
2229
+ printToStdError(opts);
2230
+ return mockSpinner;
2231
+ },
2232
+ reset: () => mockSpinner,
2233
+ clear: () => mockSpinner,
2234
+ spin: () => mockSpinner
2235
+ };
2236
+ function Spinner({ ci = false } = {}) {
2237
+ return {
2238
+ createSpinner: (text, options) => ci ? mockSpinner : _createSpinner(text, options)
2239
+ };
2240
+ }
2187
2241
 
2188
2242
  // src/utils/check_node_version.ts
2189
2243
  import fs2 from "fs";
@@ -2205,6 +2259,8 @@ if (!semver.satisfies(process.version, packageJson.engines.node)) {
2205
2259
 
2206
2260
  // src/utils/index.ts
2207
2261
  var sleep = (ms = 2e3) => new Promise((r) => setTimeout(r, ms));
2262
+ var CliError = class extends Error {
2263
+ };
2208
2264
 
2209
2265
  // src/features/analysis/scm/utils/index.ts
2210
2266
  import { z as z15 } from "zod";
@@ -4268,6 +4324,9 @@ var BitbucketParseResultZ = z20.object({
4268
4324
  import { setTimeout as setTimeout3 } from "timers/promises";
4269
4325
  import { z as z21 } from "zod";
4270
4326
 
4327
+ // src/features/analysis/scm/constants.ts
4328
+ var REPORT_DEFAULT_FILE_NAME = "report.json";
4329
+
4271
4330
  // src/features/analysis/scm/index.ts
4272
4331
  init_env();
4273
4332
 
@@ -4503,458 +4562,38 @@ function getProxyAgent(url) {
4503
4562
  }
4504
4563
  return void 0;
4505
4564
  }
4506
-
4507
- // src/features/analysis/upload-file.ts
4508
- var debug8 = Debug7("mobbdev:upload-file");
4509
- async function uploadFile({
4510
- file,
4511
- url,
4512
- uploadKey,
4513
- uploadFields,
4514
- logger: logger2
4515
- }) {
4516
- const logInfo = logger2 || ((_message, _data) => {
4517
- });
4518
- logInfo(`FileUpload: upload file start ${url}`);
4519
- logInfo(`FileUpload: upload fields`, uploadFields);
4520
- logInfo(`FileUpload: upload key ${uploadKey}`);
4521
- debug8("upload file start %s", url);
4522
- debug8("upload fields %o", uploadFields);
4523
- debug8("upload key %s", uploadKey);
4524
- const form = new FormData();
4525
- Object.entries(uploadFields).forEach(([key, value]) => {
4526
- form.append(key, value);
4527
- });
4528
- if (!form.has("key")) {
4529
- form.append("key", uploadKey);
4530
- }
4531
- if (typeof file === "string") {
4532
- debug8("upload file from path %s", file);
4533
- logInfo(`FileUpload: upload file from path ${file}`);
4534
- form.append("file", await fileFrom(file));
4535
- } else {
4536
- debug8("upload file from buffer");
4537
- logInfo(`FileUpload: upload file from buffer`);
4538
- form.append("file", new File([new Uint8Array(file)], "file"));
4539
- }
4540
- const agent = getProxyAgent(url);
4541
- const response = await fetch3(url, {
4542
- method: "POST",
4543
- body: form,
4544
- agent
4545
- });
4546
- if (!response.ok) {
4547
- debug8("error from S3 %s %s", response.body, response.status);
4548
- logInfo(`FileUpload: error from S3 ${response.body} ${response.status}`);
4549
- throw new Error(`Failed to upload the file: ${response.status}`);
4550
- }
4551
- debug8("upload file done");
4552
- logInfo(`FileUpload: upload file done`);
4553
- }
4554
-
4555
- // src/mcp/services/McpGQLClient.ts
4556
- import crypto2 from "crypto";
4557
- import { GraphQLClient as GraphQLClient2 } from "graphql-request";
4558
- import { v4 as uuidv42 } from "uuid";
4559
- init_configs();
4560
-
4561
- // src/mcp/Logger.ts
4562
- import Configstore from "configstore";
4563
-
4564
- // src/mcp/services/WorkspaceService.ts
4565
- var WorkspaceService = class {
4566
- /**
4567
- * Sets a known workspace path that was discovered through successful validation
4568
- * @param path The validated workspace path to store
4569
- */
4570
- static setKnownWorkspacePath(path7) {
4571
- this.knownWorkspacePath = path7;
4572
- }
4573
- /**
4574
- * Gets the known workspace path that was previously validated
4575
- * @returns The known workspace path or undefined if none stored
4576
- */
4577
- static getKnownWorkspacePath() {
4578
- return this.knownWorkspacePath;
4579
- }
4580
- /**
4581
- * Clears the known workspace path cache
4582
- */
4583
- static clearKnownWorkspacePath() {
4584
- this.knownWorkspacePath = void 0;
4585
- }
4586
- /**
4587
- * Gets the workspace folder path from known path or environment variables
4588
- * @returns The workspace folder path or undefined if none found
4589
- */
4590
- static getWorkspaceFolderPath() {
4591
- if (this.knownWorkspacePath) {
4592
- return this.knownWorkspacePath;
4593
- }
4594
- const workspaceEnvVars = [
4595
- "WORKSPACE_FOLDER_PATHS",
4596
- // Cursor IDE
4597
- "PWD",
4598
- // Claude Code and general shell
4599
- "WORKSPACE_ROOT",
4600
- // Generic workspace root
4601
- "PROJECT_ROOT"
4602
- // Generic project root
4603
- ];
4604
- for (const envVar of workspaceEnvVars) {
4605
- const value = process.env[envVar];
4606
- if (value?.trim()) {
4607
- return value.trim();
4608
- }
4609
- }
4610
- return void 0;
4611
- }
4612
- ///this should be deleted, use instead the host detection from the McpUsageService
4613
- /**
4614
- * Detects the IDE/editor host based on environment variables
4615
- * @returns The detected IDE host
4616
- */
4617
- static getHost() {
4618
- if (process.env["WORKSPACE_FOLDER_PATHS"]) {
4619
- return "CURSOR";
4620
- }
4621
- if (process.env["VSCODE_IPC_HOOK"] || process.env["VSCODE_PID"] || process.env["TERM_PROGRAM"] === "vscode") {
4622
- return "VSCODE";
4623
- }
4624
- if (process.env["WINDSURF_IPC_HOOK"] || process.env["WINDSURF_PID"] || process.env["TERM_PROGRAM"] === "windsurf") {
4625
- return "WINDSURF";
4626
- }
4627
- if (process.env["CLAUDE_DESKTOP"] || process.env["ANTHROPIC_CLAUDE"]) {
4628
- return "CLAUDE";
4629
- }
4630
- if (process.env["WEBSTORM_VM_OPTIONS"] || process.env["IDEA_VM_OPTIONS"] || process.env["JETBRAINS_IDE"]) {
4631
- return "WEBSTORM";
4632
- }
4633
- return "UNKNOWN";
4634
- }
4635
- };
4636
- __publicField(WorkspaceService, "knownWorkspacePath");
4637
-
4638
- // src/mcp/Logger.ts
4639
- var MAX_LOGS_SIZE = 1e3;
4640
- var Logger = class {
4641
- constructor() {
4642
- __publicField(this, "mobbConfigStore");
4643
- __publicField(this, "host");
4644
- __publicField(this, "unknownPathSuffix");
4645
- __publicField(this, "lastKnownPath", null);
4646
- this.host = WorkspaceService.getHost();
4647
- this.unknownPathSuffix = Math.floor(1e3 + Math.random() * 9e3).toString();
4648
- this.mobbConfigStore = new Configstore("mobb-logs", {});
4649
- this.mobbConfigStore.set("version", packageJson.version);
4650
- }
4651
- /**
4652
- * Gets the current log path, fetching workspace path dynamically
4653
- */
4654
- getCurrentLogPath() {
4655
- const workspacePath = WorkspaceService.getWorkspaceFolderPath();
4656
- if (workspacePath) {
4657
- return `${this.host}:${workspacePath}`;
4658
- }
4659
- return `${this.host}:unknown-${this.unknownPathSuffix}`;
4660
- }
4661
- /**
4662
- * Migrates logs from unknown path to known workspace path
4663
- */
4664
- migrateLogs(fromPath, toPath) {
4665
- const existingLogs = this.mobbConfigStore.get(fromPath) ?? [];
4666
- const targetLogs = this.mobbConfigStore.get(toPath) ?? [];
4667
- if (existingLogs.length > 0) {
4668
- const combinedLogs = [...targetLogs, ...existingLogs];
4669
- const finalLogs = combinedLogs.slice(-MAX_LOGS_SIZE);
4670
- this.mobbConfigStore.set(toPath, finalLogs);
4671
- this.mobbConfigStore.delete(fromPath);
4672
- }
4673
- }
4674
- /**
4675
- * Log a message to the console.
4676
- * @param message - The message to log.
4677
- * @param level - The level of the message.
4678
- * @param data - The data to log.
4679
- */
4680
- log(message, level = "info", data) {
4681
- const currentPath = this.getCurrentLogPath();
4682
- const workspacePath = WorkspaceService.getWorkspaceFolderPath();
4683
- if (workspacePath && this.lastKnownPath !== workspacePath) {
4684
- const unknownPath = `${this.host}:unknown-${this.unknownPathSuffix}`;
4685
- const knownPath = `${this.host}:${workspacePath}`;
4686
- if (this.lastKnownPath === null || this.lastKnownPath.includes("unknown-")) {
4687
- this.migrateLogs(unknownPath, knownPath);
4688
- }
4689
- this.lastKnownPath = workspacePath;
4690
- }
4691
- const logMessage = {
4692
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4693
- level,
4694
- message,
4695
- data
4696
- };
4697
- const logs = this.mobbConfigStore.get(currentPath) ?? [];
4698
- if (logs.length >= MAX_LOGS_SIZE) {
4699
- logs.shift();
4700
- }
4701
- this.mobbConfigStore.set(currentPath, [...logs, logMessage]);
4702
- }
4703
- };
4704
- var logger = new Logger();
4705
- var logError = (message, data) => logger.log(message, "error", data);
4706
- var logDebug = (message, data) => logger.log(message, "debug", data);
4707
- var log = logger.log.bind(logger);
4708
-
4709
- // src/mcp/types.ts
4710
- import { z as z26 } from "zod";
4711
- var ScanAndFixVulnerabilitiesToolSchema = z26.object({
4712
- path: z26.string()
4713
- });
4714
- var VulnerabilityReportIssueTagSchema = z26.object({
4715
- vulnerability_report_issue_tag_value: z26.nativeEnum(
4716
- Vulnerability_Report_Issue_Tag_Enum
4717
- )
4718
- });
4719
- var VulnerabilityReportIssueSchema = z26.object({
4720
- category: z26.any().optional().nullable(),
4721
- parsedIssueType: z26.nativeEnum(IssueType_Enum).nullable().optional(),
4722
- parsedSeverity: z26.nativeEnum(Vulnerability_Severity_Enum).nullable().optional(),
4723
- vulnerabilityReportIssueTags: z26.array(VulnerabilityReportIssueTagSchema)
4724
- });
4725
- var SharedStateSchema = z26.object({
4726
- __typename: z26.literal("fix_shared_state").optional(),
4727
- id: z26.any(),
4728
- // GraphQL uses `any` type for UUID
4729
- downloadedBy: z26.array(z26.any().nullable()).optional().nullable()
4730
- });
4731
- var UnstructuredFixExtraContextSchema = z26.object({
4732
- __typename: z26.literal("UnstructuredFixExtraContext").optional(),
4733
- key: z26.string(),
4734
- value: z26.any()
4735
- // GraphQL JSON type
4736
- });
4737
- var FixExtraContextResponseSchema = z26.object({
4738
- __typename: z26.literal("FixExtraContextResponse").optional(),
4739
- extraContext: z26.array(UnstructuredFixExtraContextSchema),
4740
- fixDescription: z26.string()
4741
- });
4742
- var FixDataSchema = z26.object({
4743
- __typename: z26.literal("FixData"),
4744
- patch: z26.string(),
4745
- patchOriginalEncodingBase64: z26.string(),
4746
- extraContext: FixExtraContextResponseSchema
4747
- });
4748
- var GetFixNoFixErrorSchema = z26.object({
4749
- __typename: z26.literal("GetFixNoFixError")
4750
- });
4751
- var PatchAndQuestionsSchema = z26.union([FixDataSchema, GetFixNoFixErrorSchema]);
4752
- var McpFixSchema = z26.object({
4753
- __typename: z26.literal("fix").optional(),
4754
- id: z26.any(),
4755
- // GraphQL uses `any` type for UUID
4756
- confidence: z26.number(),
4757
- safeIssueType: z26.string().nullable(),
4758
- severityText: z26.string().nullable(),
4759
- gitBlameLogin: z26.string().nullable().optional(),
4760
- // Optional in GraphQL
4761
- severityValue: z26.number().nullable(),
4762
- vulnerabilityReportIssues: z26.array(VulnerabilityReportIssueSchema),
4763
- sharedState: SharedStateSchema.nullable().optional(),
4764
- // Optional in GraphQL
4765
- patchAndQuestions: PatchAndQuestionsSchema,
4766
- // Additional field added by the client
4767
- fixUrl: z26.string().optional()
4768
- });
4769
- var FixAggregateSchema = z26.object({
4770
- __typename: z26.literal("fix_aggregate").optional(),
4771
- aggregate: z26.object({
4772
- __typename: z26.literal("fix_aggregate_fields").optional(),
4773
- count: z26.number()
4774
- }).nullable()
4775
- });
4776
- var VulnerabilityReportIssueAggregateSchema = z26.object({
4777
- __typename: z26.literal("vulnerability_report_issue_aggregate").optional(),
4778
- aggregate: z26.object({
4779
- __typename: z26.literal("vulnerability_report_issue_aggregate_fields").optional(),
4780
- count: z26.number()
4781
- }).nullable()
4782
- });
4783
- var RepoSchema = z26.object({
4784
- __typename: z26.literal("repo").optional(),
4785
- originalUrl: z26.string()
4786
- });
4787
- var ProjectSchema = z26.object({
4788
- id: z26.any(),
4789
- // GraphQL uses `any` type for UUID
4790
- organizationId: z26.any()
4791
- // GraphQL uses `any` type for UUID
4792
- });
4793
- var VulnerabilityReportSchema = z26.object({
4794
- scanDate: z26.any().nullable(),
4795
- // GraphQL uses `any` type for timestamp
4796
- vendor: z26.string(),
4797
- // GraphQL generates as string, not enum
4798
- projectId: z26.any().optional(),
4799
- // GraphQL uses `any` type for UUID
4800
- project: ProjectSchema,
4801
- totalVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema,
4802
- notFixableVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema
4803
- });
4804
- var FixReportSummarySchema = z26.object({
4805
- __typename: z26.literal("fixReport").optional(),
4806
- id: z26.any(),
4807
- // GraphQL uses `any` type for UUID
4808
- createdOn: z26.any(),
4809
- // GraphQL uses `any` type for timestamp
4810
- repo: RepoSchema.nullable(),
4811
- issueTypes: z26.any().nullable(),
4812
- // GraphQL uses `any` type for JSON
4813
- CRITICAL: FixAggregateSchema,
4814
- HIGH: FixAggregateSchema,
4815
- MEDIUM: FixAggregateSchema,
4816
- LOW: FixAggregateSchema,
4817
- fixes: z26.array(McpFixSchema),
4818
- userFixes: z26.array(McpFixSchema).optional(),
4819
- // Present in some responses but can be omitted
4820
- filteredFixesCount: FixAggregateSchema,
4821
- totalFixesCount: FixAggregateSchema,
4822
- vulnerabilityReport: VulnerabilityReportSchema
4823
- });
4824
- var ExpiredReportSchema = z26.object({
4825
- __typename: z26.literal("fixReport").optional(),
4826
- id: z26.any(),
4827
- // GraphQL uses `any` type for UUID
4828
- expirationOn: z26.any().nullable()
4829
- // GraphQL uses `any` type for timestamp
4830
- });
4831
- var GetLatestReportByRepoUrlResponseSchema = z26.object({
4832
- __typename: z26.literal("query_root").optional(),
4833
- fixReport: z26.array(FixReportSummarySchema),
4834
- expiredReport: z26.array(ExpiredReportSchema)
4835
- });
4836
-
4837
- // src/mcp/services/ConfigStoreService.ts
4838
- import Configstore2 from "configstore";
4839
- init_configs();
4840
- function createConfigStore(defaultValues = { apiToken: "" }) {
4841
- const API_URL2 = process.env["API_URL"] || MCP_DEFAULT_API_URL;
4842
- let domain = "";
4565
+ var fetchWithProxy = (url, options = {}) => {
4843
4566
  try {
4844
- const url = new URL(API_URL2);
4845
- domain = url.hostname;
4846
- } catch (e) {
4847
- domain = API_URL2.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/:\d+$/, "");
4848
- }
4849
- const sanitizedDomain = domain.replace(/\./g, "_");
4850
- return new Configstore2(
4851
- `${packageJson.name}-${sanitizedDomain}`,
4852
- defaultValues
4853
- );
4854
- }
4855
- function getConfigStore() {
4856
- return createConfigStore();
4857
- }
4858
- var configStore = getConfigStore();
4859
-
4860
- // src/mcp/services/McpAuthService.ts
4861
- import crypto from "crypto";
4862
- import os from "os";
4863
- import open from "open";
4864
- init_configs();
4865
- var McpAuthService = class {
4866
- constructor(client) {
4867
- __publicField(this, "client");
4868
- __publicField(this, "lastBrowserOpenTime", 0);
4869
- this.client = client;
4870
- }
4871
- /**
4872
- * Opens a browser window for authentication
4873
- * @param url URL to open in browser
4874
- * @param isBackgoundCall Whether this is called from tools context
4875
- */
4876
- async openBrowser(url, isBackgoundCall) {
4877
- if (isBackgoundCall) {
4878
- const now = Date.now();
4879
- if (now - this.lastBrowserOpenTime < MCP_TOOLS_BROWSER_COOLDOWN_MS) {
4880
- logDebug(`browser cooldown active, skipping open for ${url}`);
4881
- return;
4882
- }
4883
- }
4884
- logDebug(`opening browser url ${url}`);
4885
- await open(url);
4886
- this.lastBrowserOpenTime = Date.now();
4887
- }
4888
- /**
4889
- * Handles the complete authentication flow
4890
- * @param isBackgoundCall Whether this is called from tools context
4891
- * @returns Authenticated API token
4892
- */
4893
- async authenticate(isBackgoundCall = false) {
4894
- const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
4895
- modulusLength: 2048
4896
- });
4897
- logDebug("creating cli login");
4898
- const loginId = await this.client.createCliLogin({
4899
- publicKey: publicKey.export({ format: "pem", type: "pkcs1" }).toString()
4900
- });
4901
- if (!loginId) {
4902
- throw new CliLoginError("Error: createCliLogin failed");
4903
- }
4904
- logDebug(`cli login created ${loginId}`);
4905
- const webLoginUrl = `${WEB_APP_URL}/mvs-login`;
4906
- const browserUrl = `${webLoginUrl}/${loginId}?hostname=${os.hostname()}`;
4907
- await this.openBrowser(browserUrl, isBackgoundCall);
4908
- logDebug(`waiting for login to complete`);
4909
- let newApiToken = null;
4910
- for (let i = 0; i < MCP_LOGIN_MAX_WAIT / MCP_LOGIN_CHECK_DELAY; i++) {
4911
- const encryptedApiToken = await this.client.getEncryptedApiToken({
4912
- loginId
4567
+ const agent = getProxyAgent(url.toString());
4568
+ if (agent) {
4569
+ return fetchOrig(url, {
4570
+ ...options,
4571
+ // @ts-expect-error Node-fetch doesn't type 'agent', but it's valid
4572
+ agent
4913
4573
  });
4914
- if (encryptedApiToken) {
4915
- logDebug("encrypted API token received");
4916
- newApiToken = crypto.privateDecrypt(privateKey, Buffer.from(encryptedApiToken, "base64")).toString("utf-8");
4917
- logDebug("API token decrypted");
4918
- break;
4919
- }
4920
- await sleep(MCP_LOGIN_CHECK_DELAY);
4921
- }
4922
- if (!newApiToken) {
4923
- throw new FailedToGetApiTokenError(
4924
- "Error: failed to get encrypted api token"
4925
- );
4926
- }
4927
- const verifyClient = new McpGQLClient({
4928
- apiKey: newApiToken,
4929
- type: "apiKey"
4930
- });
4931
- const loginSuccess = await verifyClient.validateUserToken();
4932
- if (!loginSuccess) {
4933
- throw new AuthenticationError("Invalid API token");
4934
4574
  }
4935
- return newApiToken;
4575
+ } catch (err) {
4576
+ debug7(`Skipping proxy for ${url}. Reason: ${err.message}`);
4936
4577
  }
4578
+ return fetchOrig(url, options);
4937
4579
  };
4938
-
4939
- // src/mcp/services/McpGQLClient.ts
4940
- var McpGQLClient = class {
4580
+ var GQLClient = class {
4941
4581
  constructor(args) {
4942
- __publicField(this, "client");
4943
- __publicField(this, "clientSdk");
4582
+ __publicField(this, "_client");
4583
+ __publicField(this, "_clientSdk");
4944
4584
  __publicField(this, "_auth");
4945
- __publicField(this, "currentUser", null);
4946
- __publicField(this, "apiUrl");
4585
+ debug7(`init with ${args}`);
4947
4586
  this._auth = args;
4948
- this.apiUrl = process.env["API_URL"] || MCP_DEFAULT_API_URL;
4949
- logDebug(`[GraphQL] Creating graphql client with api url ${this.apiUrl}`, {
4950
- args
4951
- });
4952
- this.client = new GraphQLClient2(this.apiUrl, {
4953
- headers: args.type === "apiKey" ? { [MCP_API_KEY_HEADER_NAME]: args.apiKey || "" } : {
4587
+ this._client = new GraphQLClient(API_URL, {
4588
+ headers: args.type === "apiKey" ? { [API_KEY_HEADER_NAME]: args.apiKey || "" } : {
4954
4589
  Authorization: `Bearer ${args.token}`
4955
4590
  },
4591
+ fetch: fetchWithProxy,
4956
4592
  requestMiddleware: (request) => {
4957
- const requestId = uuidv42();
4593
+ const requestId = uuidv4();
4594
+ debug7(
4595
+ `sending API request with id: ${requestId} and with request: ${request.body}`
4596
+ );
4958
4597
  return {
4959
4598
  ...request,
4960
4599
  headers: {
@@ -4964,654 +4603,521 @@ var McpGQLClient = class {
4964
4603
  };
4965
4604
  }
4966
4605
  });
4967
- this.clientSdk = getSdk(this.client);
4968
- }
4969
- getErrorContext() {
4970
- return {
4971
- endpoint: this.apiUrl,
4972
- apiKey: this._auth.type === "apiKey" ? this._auth.apiKey : "",
4973
- headers: {
4974
- [MCP_API_KEY_HEADER_NAME]: this._auth.type === "apiKey" ? "[REDACTED]" : "undefined",
4975
- "x-hasura-request-id": "[DYNAMIC]"
4976
- }
4977
- };
4606
+ this._clientSdk = getSdk(this._client);
4978
4607
  }
4979
- async uploadAIBlameInferencesInitRaw(variables) {
4980
- return await this.clientSdk.UploadAIBlameInferencesInit(variables);
4608
+ async getUserInfo() {
4609
+ const { me } = await this._clientSdk.Me();
4610
+ return me;
4981
4611
  }
4982
- async finalizeAIBlameInferencesUploadRaw(variables) {
4983
- return await this.clientSdk.FinalizeAIBlameInferencesUpload(variables);
4612
+ async createCliLogin(variables) {
4613
+ const res = await this._clientSdk.CreateCliLogin(variables, {
4614
+ // We may have outdated API key in the config storage. Avoid using it for the login request.
4615
+ [API_KEY_HEADER_NAME]: ""
4616
+ });
4617
+ return res.insert_cli_login_one?.id || "";
4984
4618
  }
4985
- async isApiEndpointReachable() {
4619
+ async verifyApiConnection() {
4986
4620
  try {
4987
- logDebug("[GraphQL] Calling Me query for API connection verification");
4988
- const result = await this.getUserInfo();
4989
- logDebug("[GraphQL] Me query successful", { result });
4990
- return true;
4621
+ await this.getUserInfo();
4991
4622
  } catch (e) {
4992
- const error = e;
4993
- logDebug(`[GraphQL] API connection verification failed`, { error });
4994
- if (error?.toString().includes("FetchError")) {
4995
- logError("[GraphQL] API connection verification failed", { error });
4623
+ if (e?.toString().startsWith("FetchError")) {
4624
+ debug7("verify connection failed %o", e);
4996
4625
  return false;
4997
4626
  }
4998
4627
  }
4999
4628
  return true;
5000
4629
  }
5001
- /**
5002
- * Verifies both API endpoint reachability and user authentication
5003
- * @returns true if both API is reachable and user is authenticated
5004
- */
5005
- async verifyApiConnection() {
5006
- const isReachable = await this.isApiEndpointReachable();
5007
- if (!isReachable) {
5008
- return false;
5009
- }
4630
+ async validateUserToken() {
4631
+ await this.createCommunityUser();
4632
+ let info;
5010
4633
  try {
5011
- await this.validateUserToken();
5012
- return true;
4634
+ info = await this.getUserInfo();
5013
4635
  } catch (e) {
5014
- logError("User token validation failed", { error: e });
4636
+ debug7("verify token failed %o", e);
5015
4637
  return false;
5016
4638
  }
4639
+ return info?.email || true;
5017
4640
  }
5018
- async uploadS3BucketInfo() {
5019
- try {
5020
- logDebug("[GraphQL] Calling uploadS3BucketInfo mutation");
5021
- const result = await this.clientSdk.uploadS3BucketInfo({
5022
- fileName: "report.json"
5023
- });
5024
- logDebug("[GraphQL] uploadS3BucketInfo successful", { result });
5025
- return result;
5026
- } catch (e) {
5027
- logError("[GraphQL] uploadS3BucketInfo failed", {
5028
- error: e,
5029
- ...this.getErrorContext()
5030
- });
5031
- throw e;
4641
+ async getLastOrgAndNamedProject(params) {
4642
+ const me = await this.getUserInfo();
4643
+ const email = me?.email;
4644
+ if (!email) {
4645
+ throw new Error("User email not found");
5032
4646
  }
5033
- }
5034
- async getAnalysis(analysisId) {
5035
- try {
5036
- logDebug("[GraphQL] Calling getAnalysis query", { analysisId });
5037
- const res = await this.clientSdk.getAnalysis({
5038
- analysisId
5039
- });
5040
- logDebug("[GraphQL] getAnalysis successful", { result: res });
5041
- if (!res.analysis) {
5042
- throw new Error(`Analysis not found: ${analysisId}`);
5043
- }
5044
- return res.analysis;
5045
- } catch (e) {
5046
- logError("[GraphQL] getAnalysis failed", {
5047
- error: e,
5048
- analysisId,
5049
- ...this.getErrorContext()
5050
- });
5051
- throw e;
4647
+ const { projectName, userDefinedOrganizationId } = params;
4648
+ if (!projectName) {
4649
+ throw new Error("Project name is required");
5052
4650
  }
5053
- }
5054
- async submitVulnerabilityReport(variables) {
5055
- try {
5056
- logDebug("[GraphQL] Calling SubmitVulnerabilityReport mutation", {
5057
- variables
5058
- });
5059
- const result = await this.clientSdk.SubmitVulnerabilityReport(variables);
5060
- logDebug("[GraphQL] SubmitVulnerabilityReport successful", { result });
5061
- return result;
5062
- } catch (e) {
5063
- logError("[GraphQL] SubmitVulnerabilityReport failed", {
5064
- error: e,
5065
- variables,
5066
- ...this.getErrorContext()
5067
- });
5068
- throw e;
4651
+ const orgAndProjectRes = await this._clientSdk.getLastOrgAndNamedProject({
4652
+ email,
4653
+ projectName
4654
+ });
4655
+ if (!orgAndProjectRes.user?.[0]?.userOrganizationsAndUserOrganizationRoles?.[0]?.organization?.id) {
4656
+ throw new Error(
4657
+ `The user with email:${email} is not associated with any organization`
4658
+ );
5069
4659
  }
5070
- }
5071
- async subscribeToGetAnalysis(params) {
5072
- const { scanContext } = params;
5073
- try {
5074
- logDebug(`[${scanContext}] GraphQL: Starting GetAnalysis subscription`, {
5075
- params: params.subscribeToAnalysisParams
5076
- });
5077
- const { callbackStates } = params;
5078
- const result = await subscribe(
5079
- GetAnalysisSubscriptionDocument,
5080
- params.subscribeToAnalysisParams,
5081
- async (resolve, reject, data) => {
5082
- logDebug(
5083
- `[${scanContext}] GraphQL: GetAnalysis subscription data received ${data.analysis?.state}`,
5084
- { data }
5085
- );
5086
- if (!data.analysis?.state || data.analysis?.state === "Failed" /* Failed */) {
5087
- const errorMessage = data.analysis?.failReason || `Analysis failed with id: ${data.analysis?.id}`;
5088
- logError(`[${scanContext}] GraphQL: Analysis failed`, {
5089
- analysisId: data.analysis?.id,
5090
- state: data.analysis?.state,
5091
- failReason: data.analysis?.failReason,
5092
- ...this.getErrorContext()
5093
- });
5094
- reject(new Error(errorMessage));
5095
- return;
5096
- }
5097
- if (callbackStates.includes(data.analysis?.state)) {
5098
- logDebug(
5099
- `[${scanContext}] GraphQL: Analysis state matches callback states: ${data.analysis.state}`,
5100
- {
5101
- analysisId: data.analysis.id,
5102
- state: data.analysis.state,
5103
- callbackStates
5104
- }
5105
- );
5106
- await params.callback(data.analysis.id);
5107
- resolve(data);
5108
- }
5109
- },
5110
- this._auth.type === "apiKey" ? {
5111
- apiKey: this._auth.apiKey,
5112
- type: "apiKey",
5113
- timeoutInMs: params.timeoutInMs
5114
- } : {
5115
- token: this._auth.token,
5116
- type: "token",
5117
- timeoutInMs: params.timeoutInMs
5118
- }
4660
+ const organization = orgAndProjectRes.user?.at(0)?.userOrganizationsAndUserOrganizationRoles.map(
4661
+ (org) => org.organization
4662
+ ).filter(
4663
+ (org) => userDefinedOrganizationId ? org.id === userDefinedOrganizationId : true
4664
+ )?.at(0);
4665
+ if (!organization) {
4666
+ throw new Error(
4667
+ `Organization with id:${userDefinedOrganizationId} not found`
5119
4668
  );
5120
- logDebug(`[${scanContext}] GraphQL: GetAnalysis subscription completed`, {
5121
- result
5122
- });
5123
- return result;
5124
- } catch (e) {
5125
- logError(`[${scanContext}] GraphQL: GetAnalysis subscription failed`, {
5126
- error: e,
5127
- params: params.subscribeToAnalysisParams,
5128
- ...this.getErrorContext()
5129
- });
5130
- throw e;
5131
4669
  }
5132
- }
5133
- async getProjectId() {
5134
- try {
5135
- const me = await this.getUserInfo();
5136
- if (!me) {
5137
- throw new Error("User not found");
5138
- }
5139
- const userEmail = me.email;
5140
- if (!userEmail) {
5141
- throw new Error("User email not found");
5142
- }
5143
- const shortEmailHash = crypto2.createHash("sha256").update(userEmail).digest("hex").slice(0, 8).toUpperCase();
5144
- const projectName = `MCP Scans ${shortEmailHash}`;
5145
- logDebug("[GraphQL] Calling getLastOrgAndNamedProject query", {
5146
- projectName
5147
- });
5148
- const orgAndProjectRes = await this.clientSdk.getLastOrgAndNamedProject({
5149
- email: userEmail,
5150
- projectName
5151
- });
5152
- logDebug("[GraphQL] getLastOrgAndNamedProject successful", {
5153
- result: orgAndProjectRes
5154
- });
5155
- if (!orgAndProjectRes.user?.[0]?.userOrganizationsAndUserOrganizationRoles?.[0]?.organization?.id) {
5156
- throw new Error(
5157
- `The user with email:${userEmail} is not associated with any organization`
5158
- );
5159
- }
5160
- const organization = orgAndProjectRes.user?.[0]?.userOrganizationsAndUserOrganizationRoles?.[0]?.organization;
5161
- const projectId = organization?.projects?.[0]?.id;
5162
- if (projectId) {
5163
- logDebug("[GraphQL] Found existing project", {
5164
- projectId,
5165
- projectName
5166
- });
5167
- return projectId;
5168
- }
5169
- logDebug("[GraphQL] Project not found, creating new project", {
4670
+ let projectId = organization?.projects?.[0]?.id;
4671
+ if (!projectId) {
4672
+ const createdProject = await this._clientSdk.CreateProject({
5170
4673
  organizationId: organization.id,
5171
- projectName
5172
- });
5173
- try {
5174
- const createdProject = await this.clientSdk.CreateProject({
5175
- organizationId: organization.id,
5176
- projectName
5177
- });
5178
- logDebug("[GraphQL] CreateProject successful", {
5179
- result: createdProject
5180
- });
5181
- return createdProject.createProject.projectId;
5182
- } catch (createError) {
5183
- const errorMessage = createError instanceof Error ? createError.message : String(createError);
5184
- const isConstraintViolation = errorMessage.includes(
5185
- "duplicate key value violates unique constraint"
5186
- ) && errorMessage.includes("project_name_organization_id_key");
5187
- if (isConstraintViolation) {
5188
- logDebug(
5189
- "[GraphQL] Project creation failed due to constraint violation, retrying fetch",
5190
- {
5191
- organizationId: organization.id,
5192
- projectName,
5193
- error: errorMessage
5194
- }
5195
- );
5196
- const retryOrgAndProjectRes = await this.clientSdk.getLastOrgAndNamedProject({
5197
- email: userEmail,
5198
- projectName
5199
- });
5200
- const retryProjectId = retryOrgAndProjectRes.user?.[0]?.userOrganizationsAndUserOrganizationRoles?.[0]?.organization?.projects?.[0]?.id;
5201
- if (retryProjectId) {
5202
- logDebug(
5203
- "[GraphQL] Successfully found existing project after constraint violation",
5204
- {
5205
- projectId: retryProjectId,
5206
- projectName
5207
- }
5208
- );
5209
- return retryProjectId;
5210
- }
5211
- logError(
5212
- "[GraphQL] Failed to find project even after constraint violation retry",
5213
- {
5214
- organizationId: organization.id,
5215
- projectName,
5216
- retryResult: retryOrgAndProjectRes
5217
- }
5218
- );
5219
- }
5220
- throw createError;
5221
- }
5222
- } catch (e) {
5223
- logError("[GraphQL] getProjectId failed", {
5224
- error: e,
5225
- ...this.getErrorContext()
4674
+ projectName: projectName || "My project"
5226
4675
  });
5227
- throw e;
4676
+ projectId = createdProject.createProject.projectId;
5228
4677
  }
5229
- }
5230
- async getUserInfo() {
5231
- const { me } = await this.clientSdk.Me();
5232
- this.currentUser = me;
5233
- return me;
5234
- }
5235
- getCurrentUser() {
5236
- return this.currentUser;
5237
- }
5238
- async validateUserToken() {
5239
- logDebug("[GraphQL] Validating user token");
5240
- try {
5241
- await this.clientSdk.CreateCommunityUser();
5242
- const info = await this.getUserInfo();
5243
- logDebug("[GraphQL] User token validated successfully");
5244
- return info?.email || true;
5245
- } catch (e) {
5246
- logError("[GraphQL] User token validation failed");
5247
- return false;
5248
- }
5249
- }
5250
- async createCliLogin(variables) {
5251
- try {
5252
- const res = await this.clientSdk.CreateCliLogin(variables, {
5253
- // We may have outdated API key in the config storage. Avoid using it for the login request.
5254
- [MCP_API_KEY_HEADER_NAME]: ""
5255
- });
5256
- const loginId = res.insert_cli_login_one?.id || "";
5257
- if (!loginId) {
5258
- logError("[GraphQL] Create cli login failed - no login ID returned");
5259
- return "";
5260
- }
5261
- return loginId;
5262
- } catch (e) {
5263
- logError("[GraphQL] Create cli login failed", { error: e });
5264
- return "";
4678
+ if (!projectId) {
4679
+ throw new Error("Project not found");
5265
4680
  }
4681
+ return {
4682
+ organizationId: organization.id,
4683
+ projectId
4684
+ };
5266
4685
  }
5267
4686
  async getEncryptedApiToken(variables) {
4687
+ const res = await this._clientSdk.GetEncryptedApiToken(variables, {
4688
+ // We may have outdated API key in the config storage. Avoid using it for the login request.
4689
+ [API_KEY_HEADER_NAME]: ""
4690
+ });
4691
+ return res?.cli_login_by_pk?.encryptedApiToken || null;
4692
+ }
4693
+ async createCommunityUser() {
5268
4694
  try {
5269
- const res = await this.clientSdk.GetEncryptedApiToken(variables, {
5270
- // We may have outdated API key in the config storage. Avoid using it for the login request.
5271
- [MCP_API_KEY_HEADER_NAME]: ""
5272
- });
5273
- return res?.cli_login_by_pk?.encryptedApiToken || null;
4695
+ await this._clientSdk.CreateCommunityUser();
5274
4696
  } catch (e) {
5275
- logError("[GraphQL] Get encrypted api token failed", { error: e });
5276
- return null;
5277
- }
5278
- }
5279
- generateFixUrl({
5280
- fixId,
5281
- organizationId,
5282
- projectId,
5283
- reportId
5284
- }) {
5285
- if (!organizationId || !projectId || !reportId) {
5286
- return void 0;
5287
- }
5288
- const appBaseUrl = this.apiUrl.replace("/v1/graphql", "").replace("api.", "");
5289
- return `${appBaseUrl}/organization/${organizationId}/project/${projectId}/report/${reportId}/fix/${fixId}`;
5290
- }
5291
- mergeUserAndSystemFixes({
5292
- reportData,
5293
- limit
5294
- }) {
5295
- if (!reportData) return [];
5296
- const reportMetadata = {
5297
- id: reportData.id,
5298
- organizationId: reportData.vulnerabilityReport?.project?.organizationId,
5299
- projectId: reportData.vulnerabilityReport?.projectId
5300
- };
5301
- const { userFixes = [], fixes = [] } = reportData;
5302
- const fixMap = /* @__PURE__ */ new Map();
5303
- for (const fix of userFixes) {
5304
- if (fix.id) {
5305
- const fixWithUrl = {
5306
- ...fix,
5307
- fixUrl: this.generateFixUrl({
5308
- fixId: fix.id,
5309
- organizationId: reportMetadata?.organizationId,
5310
- projectId: reportMetadata?.projectId,
5311
- reportId: reportMetadata?.id
5312
- })
5313
- };
5314
- fixMap.set(fix.id, fixWithUrl);
5315
- }
5316
- }
5317
- for (const fix of fixes) {
5318
- if (fix.id && !fixMap.has(fix.id)) {
5319
- const fixWithUrl = {
5320
- ...fix,
5321
- fixUrl: this.generateFixUrl({
5322
- fixId: fix.id,
5323
- organizationId: reportMetadata?.organizationId,
5324
- projectId: reportMetadata?.projectId,
5325
- reportId: reportMetadata?.id
5326
- })
5327
- };
5328
- fixMap.set(fix.id, fixWithUrl);
5329
- }
4697
+ debug7("create community user failed %o", e);
5330
4698
  }
5331
- return Array.from(fixMap.values()).slice(0, limit);
5332
4699
  }
5333
- async updateFixesDownloadStatus(fixIds) {
5334
- if (fixIds.length > 0) {
5335
- const resUpdate = await this.clientSdk.updateDownloadedFixData({
5336
- fixIds,
5337
- source: "MCP" /* Mcp */
5338
- });
5339
- logDebug("[GraphQL] updateFixesDownloadStatus successful", {
5340
- result: resUpdate,
5341
- fixIds
5342
- });
5343
- } else {
5344
- logDebug("[GraphQL] No fixes found to update download status");
5345
- }
5346
- }
5347
- async updateAutoAppliedFixesStatus(fixIds) {
5348
- if (fixIds.length > 0) {
5349
- const resUpdate = await this.clientSdk.updateDownloadedFixData({
5350
- fixIds,
5351
- source: "AUTO_MVS" /* AutoMvs */
5352
- });
5353
- logDebug("[GraphQL] updateAutoAppliedFixesStatus successful", {
5354
- result: resUpdate,
5355
- fixIds,
5356
- note: "Auto-applied via MVS automation"
5357
- });
5358
- } else {
5359
- logDebug("[GraphQL] No auto-applied fixes to update status");
5360
- }
4700
+ async updateScmToken(args) {
4701
+ const { scmType, url, token, org, refreshToken } = args;
4702
+ const updateScmTokenResult = await this._clientSdk.updateScmToken({
4703
+ scmType,
4704
+ url,
4705
+ token,
4706
+ org,
4707
+ refreshToken
4708
+ });
4709
+ return updateScmTokenResult;
5361
4710
  }
5362
- async getMvsAutoFixSettings() {
5363
- try {
5364
- const envOverride = process.env["MVS_AUTO_FIX"];
5365
- if (envOverride !== void 0) {
5366
- const overrideValue = envOverride.toLowerCase() === "true";
5367
- logDebug("[Environment] Using MVS_AUTO_FIX override", {
5368
- envValue: envOverride,
5369
- resolvedValue: overrideValue
5370
- });
5371
- return overrideValue;
5372
- }
5373
- const userInfo = await this.getUserInfo();
5374
- if (!userInfo?.email) {
5375
- throw new Error("User email not found");
5376
- }
5377
- logDebug("[GraphQL] Calling GetUserMvsAutoFix query", {
5378
- userEmail: userInfo.email
5379
- });
5380
- const result = await this.clientSdk.GetUserMvsAutoFix({
5381
- userEmail: userInfo.email
5382
- });
5383
- logDebug("[GraphQL] GetUserMvsAutoFix successful", { result });
5384
- return result.user_email_notification_settings?.[0]?.mvs_auto_fix ?? true;
5385
- } catch (e) {
5386
- logError("[GraphQL] GetUserMvsAutoFix failed", {
5387
- error: e,
5388
- ...this.getErrorContext()
5389
- });
5390
- throw e;
5391
- }
4711
+ async uploadS3BucketInfo() {
4712
+ const uploadS3BucketInfoResult = await this._clientSdk.uploadS3BucketInfo({
4713
+ fileName: REPORT_DEFAULT_FILE_NAME
4714
+ });
4715
+ return uploadS3BucketInfoResult;
5392
4716
  }
5393
- async getLatestReportByRepoUrl({
5394
- repoUrl,
5395
- limit = MCP_DEFAULT_LIMIT,
5396
- offset = 0,
5397
- fileFilter
4717
+ async getVulByNodesMetadata({
4718
+ hunks,
4719
+ vulnerabilityReportId
5398
4720
  }) {
5399
- try {
5400
- logDebug("[GraphQL] Calling GetLatestReportByRepoUrl query", {
5401
- repoUrl,
5402
- limit,
5403
- offset,
5404
- fileFilter
5405
- });
5406
- let currentUserEmail = "%@%";
5407
- try {
5408
- const userInfo = await this.getUserInfo();
5409
- if (userInfo?.email) {
5410
- currentUserEmail = `%${userInfo.email}%`;
5411
- }
5412
- } catch (err) {
5413
- logDebug("[GraphQL] Failed to get user email, using default pattern", {
5414
- error: err
5415
- });
5416
- }
5417
- const filters = {};
5418
- if (fileFilter && fileFilter.length > 0) {
5419
- filters["vulnerabilityReportIssues"] = {
5420
- codeNodes: { path: { _in: fileFilter } }
5421
- };
4721
+ const filters = hunks.map((hunk) => {
4722
+ const filter = {
4723
+ path: { _eq: hunk.path },
4724
+ _or: hunk.ranges.flatMap(({ endLine, startLine }) => {
4725
+ return [
4726
+ { startLine: { _gte: startLine, _lte: endLine } },
4727
+ { endLine: { _gte: startLine, _lte: endLine } }
4728
+ ];
4729
+ })
4730
+ };
4731
+ return filter;
4732
+ });
4733
+ const getVulByNodesMetadataRes = await this._clientSdk.getVulByNodesMetadata({
4734
+ filters: { _or: filters },
4735
+ vulnerabilityReportId
4736
+ });
4737
+ const parsedGetVulByNodesMetadataRes = GetVulByNodesMetadataZ.parse(
4738
+ getVulByNodesMetadataRes
4739
+ );
4740
+ const uniqueVulByNodesMetadata = parsedGetVulByNodesMetadataRes.vulnerabilityReportIssueCodeNodes.reduce((acc, vulnerabilityReportIssueCodeNode) => {
4741
+ if (acc[vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]) {
4742
+ return acc;
5422
4743
  }
5423
- const resp = await this.clientSdk.GetLatestReportByRepoUrl({
5424
- repoUrl,
5425
- limit,
5426
- offset,
5427
- currentUserEmail,
5428
- filters
5429
- });
5430
- logDebug("[GraphQL] GetLatestReportByRepoUrl successful", {
5431
- result: resp,
5432
- reportCount: resp.fixReport?.length || 0
5433
- });
5434
- const latestReport = resp.fixReport?.[0] && FixReportSummarySchema.parse(resp.fixReport?.[0]);
5435
- const fixes = this.mergeUserAndSystemFixes({
5436
- reportData: latestReport,
5437
- limit
5438
- });
5439
4744
  return {
5440
- fixReport: latestReport ? {
5441
- ...latestReport,
5442
- fixes
5443
- } : null,
5444
- expiredReport: resp.expiredReport?.[0] || null
4745
+ ...acc,
4746
+ [vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]: vulnerabilityReportIssueCodeNode
5445
4747
  };
5446
- } catch (e) {
5447
- logError("[GraphQL] GetLatestReportByRepoUrl failed", {
5448
- error: e,
5449
- repoUrl,
5450
- ...this.getErrorContext()
5451
- });
5452
- throw e;
5453
- }
4748
+ }, {});
4749
+ const nonFixablePrVuls = parsedGetVulByNodesMetadataRes.nonFixablePrVuls.aggregate.count;
4750
+ const fixablePrVuls = parsedGetVulByNodesMetadataRes.fixablePrVuls.aggregate.count;
4751
+ const totalScanVulnerabilities = parsedGetVulByNodesMetadataRes.totalScanVulnerabilities.aggregate.count;
4752
+ const vulnerabilitiesOutsidePr = totalScanVulnerabilities - nonFixablePrVuls - fixablePrVuls;
4753
+ const totalPrVulnerabilities = nonFixablePrVuls + fixablePrVuls;
4754
+ const irrelevantVulnerabilityReportIssues = parsedGetVulByNodesMetadataRes.irrelevantVulnerabilityReportIssue?.[0]?.vulnerabilityReportIssues ?? [];
4755
+ return {
4756
+ vulnerabilityReportIssueCodeNodes: Object.values(
4757
+ uniqueVulByNodesMetadata
4758
+ ),
4759
+ nonFixablePrVuls,
4760
+ fixablePrVuls,
4761
+ totalScanVulnerabilities,
4762
+ vulnerabilitiesOutsidePr,
4763
+ totalPrVulnerabilities,
4764
+ irrelevantVulnerabilityReportIssues
4765
+ };
5454
4766
  }
5455
- async getReportFixesPaginated({
5456
- reportId,
5457
- limit = MCP_DEFAULT_LIMIT,
5458
- offset = 0,
5459
- issueType,
5460
- severity,
5461
- fileFilter
4767
+ async digestVulnerabilityReport({
4768
+ fixReportId,
4769
+ projectId,
4770
+ scanSource,
4771
+ repoUrl,
4772
+ reference,
4773
+ sha,
4774
+ shouldScan
5462
4775
  }) {
5463
- const filters = {};
5464
- if (issueType && issueType.length > 0) {
5465
- filters["safeIssueType"] = { _in: issueType };
5466
- }
5467
- if (severity && severity.length > 0) {
5468
- filters["severityText"] = { _in: severity };
4776
+ const res = await this._clientSdk.DigestVulnerabilityReport({
4777
+ fixReportId,
4778
+ vulnerabilityReportFileName: shouldScan ? void 0 : REPORT_DEFAULT_FILE_NAME,
4779
+ projectId,
4780
+ scanSource,
4781
+ repoUrl,
4782
+ reference,
4783
+ sha
4784
+ });
4785
+ if (res.digestVulnerabilityReport.__typename !== "VulnerabilityReport") {
4786
+ throw new Error("Digesting vulnerability report failed");
5469
4787
  }
5470
- if (fileFilter && fileFilter.length > 0) {
5471
- filters["vulnerabilityReportIssues"] = {
5472
- codeNodes: { path: { _in: fileFilter } }
5473
- };
4788
+ return res.digestVulnerabilityReport;
4789
+ }
4790
+ async submitVulnerabilityReport(params) {
4791
+ const {
4792
+ fixReportId,
4793
+ repoUrl,
4794
+ reference,
4795
+ projectId,
4796
+ sha,
4797
+ experimentalEnabled,
4798
+ vulnerabilityReportFileName,
4799
+ pullRequest
4800
+ } = params;
4801
+ return await this._clientSdk.SubmitVulnerabilityReport({
4802
+ fixReportId,
4803
+ repoUrl,
4804
+ reference,
4805
+ vulnerabilityReportFileName,
4806
+ projectId,
4807
+ pullRequest,
4808
+ sha: sha || "",
4809
+ experimentalEnabled: !!experimentalEnabled,
4810
+ scanSource: params.scanSource,
4811
+ scanContext: ScanContext.BUGSY
4812
+ });
4813
+ }
4814
+ async getFixReportState(fixReportId) {
4815
+ const res = await this._clientSdk.FixReportState({ id: fixReportId });
4816
+ return res?.fixReport_by_pk?.state || "Created" /* Created */;
4817
+ }
4818
+ async waitFixReportInit(fixReportId, includeDigested = false) {
4819
+ const FINAL_STATES = [
4820
+ "Finished" /* Finished */,
4821
+ "Failed" /* Failed */
4822
+ ];
4823
+ let lastState = "Created" /* Created */;
4824
+ let attempts = 100;
4825
+ if (includeDigested) {
4826
+ FINAL_STATES.push("Digested" /* Digested */);
5474
4827
  }
5475
- try {
5476
- logDebug("[GraphQL] Calling GetReportFixes query", {
5477
- reportId,
5478
- limit,
5479
- offset,
5480
- filters,
5481
- issueType,
5482
- severity,
5483
- fileFilter
5484
- });
5485
- let currentUserEmail = "%@%";
5486
- try {
5487
- const userInfo = await this.getUserInfo();
5488
- if (userInfo?.email) {
5489
- currentUserEmail = `%${userInfo.email}%`;
4828
+ do {
4829
+ await sleep(REPORT_STATE_CHECK_DELAY);
4830
+ lastState = await this.getFixReportState(fixReportId);
4831
+ } while (!FINAL_STATES.includes(
4832
+ lastState
4833
+ // wait for final the state of the fix report
4834
+ ) && attempts-- > 0);
4835
+ return lastState;
4836
+ }
4837
+ async getVulnerabilityReportPaths(vulnerabilityReportId) {
4838
+ const res = await this._clientSdk.GetVulnerabilityReportPaths({
4839
+ vulnerabilityReportId
4840
+ });
4841
+ return res.vulnerability_report_path.map((p) => p.path);
4842
+ }
4843
+ async subscribeToAnalysis(params) {
4844
+ const { callbackStates } = params;
4845
+ return subscribe(
4846
+ GetAnalysisSubscriptionDocument,
4847
+ params.subscribeToAnalysisParams,
4848
+ async (resolve, reject, data) => {
4849
+ if (!data.analysis?.state || data.analysis?.state === "Failed" /* Failed */) {
4850
+ const errorMessage = data.analysis?.failReason || `Analysis failed with id: ${data.analysis?.id}`;
4851
+ reject(
4852
+ new ReportDigestError(errorMessage, data.analysis?.failReason ?? "")
4853
+ );
4854
+ return;
5490
4855
  }
5491
- } catch (err) {
5492
- logDebug("[GraphQL] Failed to get user email, using default pattern", {
5493
- error: err
5494
- });
5495
- }
5496
- const res = await this.clientSdk.GetReportFixes({
5497
- reportId,
5498
- limit,
5499
- offset,
5500
- filters,
5501
- currentUserEmail
5502
- });
5503
- logDebug("[GraphQL] GetReportFixes successful", {
5504
- result: res,
5505
- fixCount: res.fixReport?.[0]?.fixes?.length || 0,
5506
- totalCount: res.fixReport?.[0]?.filteredFixesCount?.aggregate?.count || 0
5507
- });
5508
- if (res.fixReport.length === 0) {
5509
- return null;
4856
+ if (callbackStates.includes(data.analysis?.state)) {
4857
+ await params.callback(data.analysis.id);
4858
+ resolve(data);
4859
+ }
4860
+ },
4861
+ this._auth.type === "apiKey" ? {
4862
+ apiKey: this._auth.apiKey,
4863
+ type: "apiKey",
4864
+ timeoutInMs: params.timeoutInMs
4865
+ } : {
4866
+ token: this._auth.token,
4867
+ type: "token",
4868
+ timeoutInMs: params.timeoutInMs
5510
4869
  }
5511
- const latestReport = FixReportSummarySchema.parse(res.fixReport?.[0]);
5512
- const fixes = this.mergeUserAndSystemFixes({
5513
- reportData: latestReport,
5514
- limit
5515
- });
5516
- logDebug("[GraphQL] GetReportFixes response parsed", { fixes });
5517
- return {
5518
- fixes,
5519
- totalCount: res.fixReport?.[0]?.filteredFixesCount?.aggregate?.count || 0,
5520
- expiredReport: res.expiredReport?.[0] || null,
5521
- fixReport: res.fixReport?.[0] ? {
5522
- id: res.fixReport[0].id,
5523
- organizationId: res.fixReport[0].vulnerabilityReport?.project?.organizationId,
5524
- projectId: res.fixReport[0].vulnerabilityReport?.projectId
5525
- } : void 0
5526
- };
5527
- } catch (e) {
5528
- logError("[GraphQL] GetReportFixes failed", {
5529
- error: e,
5530
- reportId,
5531
- ...this.getErrorContext()
5532
- });
5533
- throw e;
4870
+ );
4871
+ }
4872
+ async getFixReportsByRepoUrl({ repoUrl }) {
4873
+ const res = await this._clientSdk.GetFixReportsByRepoUrl({
4874
+ repoUrl
4875
+ });
4876
+ return res;
4877
+ }
4878
+ async getAnalysis(analysisId) {
4879
+ const res = await this._clientSdk.getAnalysis({
4880
+ analysisId
4881
+ });
4882
+ if (!res.analysis) {
4883
+ throw new Error(`Analysis not found: ${analysisId}`);
5534
4884
  }
4885
+ return res.analysis;
4886
+ }
4887
+ async autoPrAnalysis({
4888
+ analysisId,
4889
+ commitDirectly,
4890
+ prId,
4891
+ prStrategy
4892
+ }) {
4893
+ return this._clientSdk.autoPrAnalysis({
4894
+ analysisId,
4895
+ commitDirectly,
4896
+ prId,
4897
+ prStrategy
4898
+ });
4899
+ }
4900
+ async getFixes(fixIds) {
4901
+ const res = await this._clientSdk.getFixes({
4902
+ filters: { id: { _in: fixIds } }
4903
+ });
4904
+ return res;
4905
+ }
4906
+ async validateRepoUrl(args) {
4907
+ return this._clientSdk.validateRepoUrl(args);
4908
+ }
4909
+ async getReferenceData(args) {
4910
+ return this._clientSdk.gitReference(args);
4911
+ }
4912
+ async getFalsePositive(args) {
4913
+ return this._clientSdk.getFalsePositive(args);
4914
+ }
4915
+ async uploadAIBlameInferencesInitRaw(variables) {
4916
+ return await this._clientSdk.UploadAIBlameInferencesInit(variables);
4917
+ }
4918
+ async finalizeAIBlameInferencesUploadRaw(variables) {
4919
+ return await this._clientSdk.FinalizeAIBlameInferencesUpload(variables);
5535
4920
  }
5536
4921
  };
5537
- async function createAuthenticatedMcpGQLClient({
5538
- isBackgroundCall = false
5539
- } = {}) {
5540
- logDebug("[GraphQL] Getting config", {
5541
- apiToken: configStore.get("apiToken")
4922
+
4923
+ // src/commands/handleMobbLogin.ts
4924
+ var debug8 = Debug7("mobbdev:commands");
4925
+ var LOGIN_MAX_WAIT = 10 * 60 * 1e3;
4926
+ var LOGIN_CHECK_DELAY = 5 * 1e3;
4927
+ var webLoginUrl = `${WEB_APP_URL}/cli-login`;
4928
+ var MOBB_LOGIN_REQUIRED_MSG = `\u{1F513} Login to Mobb is Required, you will be redirected to our login page, once the authorization is complete return to this prompt, ${chalk2.bgBlue(
4929
+ "press any key to continue"
4930
+ )};`;
4931
+ var config2 = new Configstore(packageJson.name, { apiToken: "" });
4932
+ async function handleMobbLogin({
4933
+ inGqlClient,
4934
+ apiKey,
4935
+ skipPrompts
4936
+ }) {
4937
+ const { createSpinner } = Spinner({ ci: skipPrompts });
4938
+ const isConnected = await inGqlClient.verifyApiConnection();
4939
+ if (!isConnected) {
4940
+ createSpinner().start().error({
4941
+ text: "\u{1F513} Connection to Mobb: failed to connect to the Mobb server"
4942
+ });
4943
+ throw new CliError(
4944
+ "Connection to Mobb: failed to connect to the Mobb server"
4945
+ );
4946
+ }
4947
+ createSpinner().start().success({
4948
+ text: `\u{1F513} Connection to Mobb: succeeded`
5542
4949
  });
5543
- const initialClient = new McpGQLClient({
5544
- apiKey: process.env["MOBB_API_KEY"] || process.env["API_KEY"] || // fallback for backward compatibility
5545
- configStore.get("apiToken") || "",
5546
- type: "apiKey"
4950
+ const userVerify = await inGqlClient.validateUserToken();
4951
+ if (userVerify) {
4952
+ createSpinner().start().success({
4953
+ text: `\u{1F513} Login to Mobb succeeded. ${typeof userVerify === "string" ? `Logged in as ${userVerify}` : ""}`
4954
+ });
4955
+ return inGqlClient;
4956
+ } else if (apiKey) {
4957
+ createSpinner().start().error({
4958
+ text: "\u{1F513} Login to Mobb failed: The provided API key does not match any configured API key on the system"
4959
+ });
4960
+ throw new CliError(
4961
+ "Login to Mobb failed: The provided API key does not match any configured API key on the system"
4962
+ );
4963
+ }
4964
+ const loginSpinner = createSpinner().start();
4965
+ if (!skipPrompts) {
4966
+ loginSpinner.update({ text: MOBB_LOGIN_REQUIRED_MSG });
4967
+ await keypress();
4968
+ }
4969
+ loginSpinner.update({
4970
+ text: "\u{1F513} Waiting for Mobb login..."
4971
+ });
4972
+ const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
4973
+ modulusLength: 2048
4974
+ });
4975
+ const loginId = await inGqlClient.createCliLogin({
4976
+ publicKey: publicKey.export({ format: "pem", type: "pkcs1" }).toString()
5547
4977
  });
5548
- const isApiEndpointReachable = await initialClient.isApiEndpointReachable();
5549
- logDebug("[GraphQL] API connection status", { isApiEndpointReachable });
5550
- if (!isApiEndpointReachable) {
5551
- throw new ApiConnectionError("Error: failed to reach Mobb GraphQL endpoint");
4978
+ const browserUrl = `${webLoginUrl}/${loginId}?hostname=${os.hostname()}`;
4979
+ !skipPrompts && console.log(
4980
+ `If the page does not open automatically, kindly access it through ${browserUrl}.`
4981
+ );
4982
+ await open(browserUrl);
4983
+ let newApiToken = null;
4984
+ for (let i = 0; i < LOGIN_MAX_WAIT / LOGIN_CHECK_DELAY; i++) {
4985
+ const encryptedApiToken = await inGqlClient.getEncryptedApiToken({
4986
+ loginId
4987
+ });
4988
+ loginSpinner.spin();
4989
+ if (encryptedApiToken) {
4990
+ debug8("encrypted API token received %s", encryptedApiToken);
4991
+ newApiToken = crypto.privateDecrypt(privateKey, Buffer.from(encryptedApiToken, "base64")).toString("utf-8");
4992
+ debug8("API token decrypted");
4993
+ break;
4994
+ }
4995
+ await sleep(LOGIN_CHECK_DELAY);
5552
4996
  }
5553
- logDebug("[GraphQL] Validating user token");
5554
- const userVerify = await initialClient.validateUserToken();
5555
- if (userVerify) {
5556
- return initialClient;
4997
+ if (!newApiToken) {
4998
+ loginSpinner.error({
4999
+ text: "Login timeout error"
5000
+ });
5001
+ throw new CliError();
5002
+ }
5003
+ const newGqlClient = new GQLClient({ apiKey: newApiToken, type: "apiKey" });
5004
+ const loginSuccess = await newGqlClient.validateUserToken();
5005
+ if (loginSuccess) {
5006
+ debug8(`set api token ${newApiToken}`);
5007
+ config2.set("apiToken", newApiToken);
5008
+ loginSpinner.success({
5009
+ text: `\u{1F513} Login to Mobb successful! ${typeof loginSpinner === "string" ? `Logged in as ${loginSuccess}` : ""}`
5010
+ });
5011
+ } else {
5012
+ loginSpinner.error({
5013
+ text: "Something went wrong, API token is invalid."
5014
+ });
5015
+ throw new CliError();
5016
+ }
5017
+ return newGqlClient;
5018
+ }
5019
+
5020
+ // src/features/analysis/upload-file.ts
5021
+ import Debug8 from "debug";
5022
+ import fetch3, { File, fileFrom, FormData } from "node-fetch";
5023
+ var debug9 = Debug8("mobbdev:upload-file");
5024
+ async function uploadFile({
5025
+ file,
5026
+ url,
5027
+ uploadKey,
5028
+ uploadFields,
5029
+ logger
5030
+ }) {
5031
+ const logInfo = logger || ((_message, _data) => {
5032
+ });
5033
+ logInfo(`FileUpload: upload file start ${url}`);
5034
+ logInfo(`FileUpload: upload fields`, uploadFields);
5035
+ logInfo(`FileUpload: upload key ${uploadKey}`);
5036
+ debug9("upload file start %s", url);
5037
+ debug9("upload fields %o", uploadFields);
5038
+ debug9("upload key %s", uploadKey);
5039
+ const form = new FormData();
5040
+ Object.entries(uploadFields).forEach(([key, value]) => {
5041
+ form.append(key, value);
5042
+ });
5043
+ if (!form.has("key")) {
5044
+ form.append("key", uploadKey);
5045
+ }
5046
+ if (typeof file === "string") {
5047
+ debug9("upload file from path %s", file);
5048
+ logInfo(`FileUpload: upload file from path ${file}`);
5049
+ form.append("file", await fileFrom(file));
5050
+ } else {
5051
+ debug9("upload file from buffer");
5052
+ logInfo(`FileUpload: upload file from buffer`);
5053
+ form.append("file", new File([new Uint8Array(file)], "file"));
5054
+ }
5055
+ const agent = getProxyAgent(url);
5056
+ const response = await fetch3(url, {
5057
+ method: "POST",
5058
+ body: form,
5059
+ agent
5060
+ });
5061
+ if (!response.ok) {
5062
+ debug9("error from S3 %s %s", response.body, response.status);
5063
+ logInfo(`FileUpload: error from S3 ${response.body} ${response.status}`);
5064
+ throw new Error(`Failed to upload the file: ${response.status}`);
5557
5065
  }
5558
- const authService = new McpAuthService(initialClient);
5559
- const newApiToken = await authService.authenticate(isBackgroundCall);
5560
- configStore.set("apiToken", newApiToken);
5561
- return new McpGQLClient({ apiKey: newApiToken, type: "apiKey" });
5066
+ debug9("upload file done");
5067
+ logInfo(`FileUpload: upload file done`);
5562
5068
  }
5563
5069
 
5564
5070
  // src/args/commands/upload_ai_blame.ts
5565
- var PromptItemZ = z27.object({
5566
- type: z27.enum(["USER_PROMPT", "AI_RESPONSE", "TOOL_EXECUTION", "AI_THINKING"]),
5567
- attachedFiles: z27.array(
5568
- z27.object({
5569
- relativePath: z27.string(),
5570
- startLine: z27.number().optional()
5071
+ var PromptItemZ = z26.object({
5072
+ type: z26.enum(["USER_PROMPT", "AI_RESPONSE", "TOOL_EXECUTION", "AI_THINKING"]),
5073
+ attachedFiles: z26.array(
5074
+ z26.object({
5075
+ relativePath: z26.string(),
5076
+ startLine: z26.number().optional()
5571
5077
  })
5572
5078
  ).optional(),
5573
- tokens: z27.object({
5574
- inputCount: z27.number(),
5575
- outputCount: z27.number()
5079
+ tokens: z26.object({
5080
+ inputCount: z26.number(),
5081
+ outputCount: z26.number()
5576
5082
  }).optional(),
5577
- text: z27.string().optional(),
5578
- date: z27.date().optional(),
5579
- tool: z27.object({
5580
- name: z27.string(),
5581
- parameters: z27.string(),
5582
- result: z27.string(),
5583
- rawArguments: z27.string().optional(),
5584
- accepted: z27.boolean().optional()
5083
+ text: z26.string().optional(),
5084
+ date: z26.date().optional(),
5085
+ tool: z26.object({
5086
+ name: z26.string(),
5087
+ parameters: z26.string(),
5088
+ result: z26.string(),
5089
+ rawArguments: z26.string().optional(),
5090
+ accepted: z26.boolean().optional()
5585
5091
  }).optional()
5586
5092
  });
5587
- var PromptItemArrayZ = z27.array(PromptItemZ);
5093
+ var PromptItemArrayZ = z26.array(PromptItemZ);
5588
5094
  function uploadAiBlameBuilder(args) {
5589
5095
  return args.option("prompt", {
5590
5096
  type: "string",
5591
5097
  array: true,
5592
5098
  demandOption: true,
5593
- describe: chalk2.bold("Path(s) to prompt artifact(s) (one per session)")
5099
+ describe: chalk3.bold("Path(s) to prompt artifact(s) (one per session)")
5594
5100
  }).option("inference", {
5595
5101
  type: "string",
5596
5102
  array: true,
5597
5103
  demandOption: true,
5598
- describe: chalk2.bold(
5104
+ describe: chalk3.bold(
5599
5105
  "Path(s) to inference artifact(s) (one per session)"
5600
5106
  )
5601
5107
  }).option("ai-response-at", {
5602
5108
  type: "string",
5603
5109
  array: true,
5604
- describe: chalk2.bold(
5110
+ describe: chalk3.bold(
5605
5111
  "ISO timestamp(s) for AI response (one per session, defaults to now)"
5606
5112
  )
5607
5113
  }).option("model", {
5608
5114
  type: "string",
5609
5115
  array: true,
5610
- describe: chalk2.bold("AI model name(s) (optional, one per session)")
5116
+ describe: chalk3.bold("AI model name(s) (optional, one per session)")
5611
5117
  }).option("tool-name", {
5612
5118
  type: "string",
5613
5119
  array: true,
5614
- describe: chalk2.bold("Tool/IDE name(s) (optional, one per session)")
5120
+ describe: chalk3.bold("Tool/IDE name(s) (optional, one per session)")
5615
5121
  }).strict();
5616
5122
  }
5617
5123
  async function uploadAiBlameHandlerFromExtension(args) {
@@ -5639,6 +5145,18 @@ async function uploadAiBlameHandlerFromExtension(args) {
5639
5145
  });
5640
5146
  });
5641
5147
  }
5148
+ var config3 = new Configstore2(packageJson.name, { apiToken: "" });
5149
+ async function getAuthenticatedGQLClientForIdeExtension() {
5150
+ let gqlClient = new GQLClient({
5151
+ apiKey: config3.get("apiToken") ?? "",
5152
+ type: "apiKey"
5153
+ });
5154
+ gqlClient = await handleMobbLogin({
5155
+ inGqlClient: gqlClient,
5156
+ skipPrompts: true
5157
+ });
5158
+ return gqlClient;
5159
+ }
5642
5160
  async function uploadAiBlameHandler(args, exitOnError = true) {
5643
5161
  const prompts = args.prompt || [];
5644
5162
  const inferences = args.inference || [];
@@ -5647,7 +5165,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
5647
5165
  const responseTimes = args.aiResponseAt || args["ai-response-at"] || [];
5648
5166
  if (prompts.length !== inferences.length) {
5649
5167
  const errorMsg = "prompt and inference must have the same number of entries";
5650
- console.error(chalk2.red(errorMsg));
5168
+ console.error(chalk3.red(errorMsg));
5651
5169
  if (exitOnError) {
5652
5170
  process.exit(1);
5653
5171
  }
@@ -5665,7 +5183,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
5665
5183
  ]);
5666
5184
  } catch {
5667
5185
  const errorMsg = `File not found for session ${i + 1}`;
5668
- console.error(chalk2.red(errorMsg));
5186
+ console.error(chalk3.red(errorMsg));
5669
5187
  if (exitOnError) {
5670
5188
  process.exit(1);
5671
5189
  }
@@ -5679,12 +5197,14 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
5679
5197
  toolName: tools[i]
5680
5198
  });
5681
5199
  }
5682
- const gqlClient = await createAuthenticatedMcpGQLClient();
5683
- const initRes = await gqlClient.uploadAIBlameInferencesInitRaw({ sessions });
5200
+ const authenticatedClient = await getAuthenticatedGQLClientForIdeExtension();
5201
+ const initRes = await authenticatedClient.uploadAIBlameInferencesInitRaw({
5202
+ sessions
5203
+ });
5684
5204
  const uploadSessions = initRes.uploadAIBlameInferencesInit?.uploadSessions ?? [];
5685
5205
  if (uploadSessions.length !== sessions.length) {
5686
5206
  const errorMsg = "Init failed to return expected number of sessions";
5687
- console.error(chalk2.red(errorMsg));
5207
+ console.error(chalk3.red(errorMsg));
5688
5208
  if (exitOnError) {
5689
5209
  process.exit(1);
5690
5210
  }
@@ -5718,21 +5238,22 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
5718
5238
  toolName: s.toolName
5719
5239
  };
5720
5240
  });
5721
- const finRes = await gqlClient.finalizeAIBlameInferencesUploadRaw({
5241
+ const finRes = await authenticatedClient.finalizeAIBlameInferencesUploadRaw({
5722
5242
  sessions: finalizeSessions
5723
5243
  });
5724
5244
  const status = finRes?.finalizeAIBlameInferencesUpload?.status;
5725
5245
  if (status !== "OK") {
5726
5246
  const errorMsg = finRes?.finalizeAIBlameInferencesUpload?.error || "unknown error";
5727
- console.error(chalk2.red(errorMsg));
5247
+ console.error(chalk3.red(errorMsg));
5728
5248
  if (exitOnError) {
5729
5249
  process.exit(1);
5730
5250
  }
5731
5251
  throw new Error(errorMsg);
5732
5252
  }
5733
- console.log(chalk2.green("AI Blame uploads finalized successfully"));
5253
+ console.log(chalk3.green("AI Blame uploads finalized successfully"));
5734
5254
  }
5735
5255
  export {
5256
+ getAuthenticatedGQLClientForIdeExtension,
5736
5257
  uploadAiBlameBuilder,
5737
5258
  uploadAiBlameHandler,
5738
5259
  uploadAiBlameHandlerFromExtension