mobbdev 1.2.33 → 1.2.34

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.
@@ -206,6 +206,20 @@ declare const PromptItemArrayZ: z.ZodArray<z.ZodObject<{
206
206
  } | undefined;
207
207
  }>, "many">;
208
208
  type PromptItemArray = z.infer<typeof PromptItemArrayZ>;
209
+ /**
210
+ * Gets the normalized GitHub repository URL from the current working directory.
211
+ * Returns null if not in a git repository or if not a GitHub repository.
212
+ */
213
+ declare function getRepositoryUrl(): Promise<string | null>;
214
+ /**
215
+ * Get system information for tracking inference source.
216
+ * Works cross-platform (Windows, macOS, Linux).
217
+ * Handles errors gracefully for containerized environments where user info may not be available.
218
+ */
219
+ declare function getSystemInfo(): {
220
+ computerName: string;
221
+ userName: string | undefined;
222
+ };
209
223
  type UploadAiBlameOptions = {
210
224
  prompt: string[];
211
225
  inference: string[];
@@ -249,4 +263,4 @@ type UploadAiBlameHandlerOptions = {
249
263
  declare function uploadAiBlameHandler(options: UploadAiBlameHandlerOptions): Promise<void>;
250
264
  declare function uploadAiBlameCommandHandler(args: UploadAiBlameOptions): Promise<void>;
251
265
 
252
- export { type PromptItem, type PromptItemArray, type UploadAiBlameOptions, type UploadAiBlameResult, uploadAiBlameBuilder, uploadAiBlameCommandHandler, uploadAiBlameHandler, uploadAiBlameHandlerFromExtension };
266
+ export { type PromptItem, type PromptItemArray, type UploadAiBlameOptions, type UploadAiBlameResult, getRepositoryUrl, getSystemInfo, uploadAiBlameBuilder, uploadAiBlameCommandHandler, uploadAiBlameHandler, uploadAiBlameHandlerFromExtension };
@@ -73,6 +73,12 @@ function getSdk(client, withWrapper = defaultWrapper) {
73
73
  FinalizeAIBlameInferencesUpload(variables, requestHeaders, signal) {
74
74
  return withWrapper((wrappedRequestHeaders) => client.request({ document: FinalizeAiBlameInferencesUploadDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "FinalizeAIBlameInferencesUpload", "mutation", variables);
75
75
  },
76
+ UploadTracyRecords(variables, requestHeaders, signal) {
77
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: UploadTracyRecordsDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "UploadTracyRecords", "mutation", variables);
78
+ },
79
+ GetTracyRawDataUploadUrls(variables, requestHeaders, signal) {
80
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetTracyRawDataUploadUrlsDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetTracyRawDataUploadUrls", "mutation", variables);
81
+ },
76
82
  DigestVulnerabilityReport(variables, requestHeaders, signal) {
77
83
  return withWrapper((wrappedRequestHeaders) => client.request({ document: DigestVulnerabilityReportDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "DigestVulnerabilityReport", "mutation", variables);
78
84
  },
@@ -126,7 +132,7 @@ function getSdk(client, withWrapper = defaultWrapper) {
126
132
  }
127
133
  };
128
134
  }
129
- var AiBlameInferenceType, FixQuestionInputType, Language, ManifestAction, Effort_To_Apply_Fix_Enum, Fix_Rating_Tag_Enum, Fix_Report_State_Enum, Fix_State_Enum, IssueLanguage_Enum, IssueType_Enum, Pr_Status_Enum, Project_Role_Type_Enum, Vulnerability_Report_Issue_Category_Enum, Vulnerability_Report_Issue_State_Enum, Vulnerability_Report_Issue_Tag_Enum, Vulnerability_Report_Vendor_Enum, Vulnerability_Severity_Enum, FixDetailsFragmentDoc, FixReportSummaryFieldsFragmentDoc, MeDocument, GetLastOrgAndNamedProjectDocument, GetLastOrgDocument, GetEncryptedApiTokenDocument, FixReportStateDocument, GetVulnerabilityReportPathsDocument, GetAnalysisSubscriptionDocument, GetAnalysisDocument, GetFixesDocument, GetVulByNodesMetadataDocument, GetFalsePositiveDocument, UpdateScmTokenDocument, UploadS3BucketInfoDocument, GetTracyDiffUploadUrlDocument, AnalyzeCommitForExtensionAiBlameDocument, GetAiBlameInferenceDocument, GetAiBlameAttributionPromptDocument, GetPromptSummaryDocument, UploadAiBlameInferencesInitDocument, FinalizeAiBlameInferencesUploadDocument, DigestVulnerabilityReportDocument, SubmitVulnerabilityReportDocument, CreateCommunityUserDocument, CreateCliLoginDocument, PerformCliLoginDocument, CreateProjectDocument, ValidateRepoUrlDocument, GitReferenceDocument, AutoPrAnalysisDocument, GetFixReportsByRepoUrlDocument, GetReportFixesDocument, GetLatestReportByRepoUrlDocument, UpdateDownloadedFixDataDocument, GetUserMvsAutoFixDocument, StreamBlameAiAnalysisRequestsDocument, StreamCommitBlameRequestsDocument, ScanSkillDocument, defaultWrapper;
135
+ var AiBlameInferenceType, FixQuestionInputType, Language, ManifestAction, Effort_To_Apply_Fix_Enum, Fix_Rating_Tag_Enum, Fix_Report_State_Enum, Fix_State_Enum, IssueLanguage_Enum, IssueType_Enum, Pr_Status_Enum, Project_Role_Type_Enum, Vulnerability_Report_Issue_Category_Enum, Vulnerability_Report_Issue_State_Enum, Vulnerability_Report_Issue_Tag_Enum, Vulnerability_Report_Vendor_Enum, Vulnerability_Severity_Enum, FixDetailsFragmentDoc, FixReportSummaryFieldsFragmentDoc, MeDocument, GetLastOrgAndNamedProjectDocument, GetLastOrgDocument, GetEncryptedApiTokenDocument, FixReportStateDocument, GetVulnerabilityReportPathsDocument, GetAnalysisSubscriptionDocument, GetAnalysisDocument, GetFixesDocument, GetVulByNodesMetadataDocument, GetFalsePositiveDocument, UpdateScmTokenDocument, UploadS3BucketInfoDocument, GetTracyDiffUploadUrlDocument, AnalyzeCommitForExtensionAiBlameDocument, GetAiBlameInferenceDocument, GetAiBlameAttributionPromptDocument, GetPromptSummaryDocument, UploadAiBlameInferencesInitDocument, FinalizeAiBlameInferencesUploadDocument, UploadTracyRecordsDocument, GetTracyRawDataUploadUrlsDocument, DigestVulnerabilityReportDocument, SubmitVulnerabilityReportDocument, CreateCommunityUserDocument, CreateCliLoginDocument, PerformCliLoginDocument, CreateProjectDocument, ValidateRepoUrlDocument, GitReferenceDocument, AutoPrAnalysisDocument, GetFixReportsByRepoUrlDocument, GetReportFixesDocument, GetLatestReportByRepoUrlDocument, UpdateDownloadedFixDataDocument, GetUserMvsAutoFixDocument, StreamBlameAiAnalysisRequestsDocument, StreamCommitBlameRequestsDocument, ScanSkillDocument, defaultWrapper;
130
136
  var init_client_generates = __esm({
131
137
  "src/features/analysis/scm/generates/client_generates.ts"() {
132
138
  "use strict";
@@ -962,6 +968,28 @@ var init_client_generates = __esm({
962
968
  status
963
969
  error
964
970
  }
971
+ }
972
+ `;
973
+ UploadTracyRecordsDocument = `
974
+ mutation UploadTracyRecords($records: [TracyRecordInput!]!) {
975
+ uploadTracyRecords(records: $records) {
976
+ status
977
+ error
978
+ }
979
+ }
980
+ `;
981
+ GetTracyRawDataUploadUrlsDocument = `
982
+ mutation GetTracyRawDataUploadUrls($recordIds: [String!]!) {
983
+ getTracyRawDataUploadUrls(recordIds: $recordIds) {
984
+ status
985
+ error
986
+ uploads {
987
+ recordId
988
+ url
989
+ uploadFieldsJSON
990
+ uploadKey
991
+ }
992
+ }
965
993
  }
966
994
  `;
967
995
  DigestVulnerabilityReportDocument = `
@@ -4082,7 +4110,7 @@ import z27 from "zod";
4082
4110
 
4083
4111
  // src/commands/handleMobbLogin.ts
4084
4112
  import chalk2 from "chalk";
4085
- import Debug7 from "debug";
4113
+ import Debug10 from "debug";
4086
4114
 
4087
4115
  // src/utils/dirname.ts
4088
4116
  import fs from "fs";
@@ -4211,6 +4239,7 @@ var CliError = class extends Error {
4211
4239
  // src/commands/AuthManager.ts
4212
4240
  import crypto from "crypto";
4213
4241
  import os from "os";
4242
+ import Debug9 from "debug";
4214
4243
  import open from "open";
4215
4244
 
4216
4245
  // src/constants.ts
@@ -4374,8 +4403,7 @@ function getProxyAgent(url) {
4374
4403
  const isHttps = parsedUrl.protocol === "https:";
4375
4404
  const proxy = isHttps ? getHttpProxy() : isHttp ? getHttpProxyOnly() : null;
4376
4405
  if (proxy) {
4377
- debug2("Using proxy %s", proxy);
4378
- debug2("Proxy agent %o", proxy);
4406
+ debug2("Using proxy %s for %s", proxy, url);
4379
4407
  return new HttpsProxyAgent(proxy);
4380
4408
  }
4381
4409
  } catch (err) {
@@ -7094,6 +7122,12 @@ var GQLClient = class {
7094
7122
  async finalizeAIBlameInferencesUploadRaw(variables) {
7095
7123
  return await this._clientSdk.FinalizeAIBlameInferencesUpload(variables);
7096
7124
  }
7125
+ async uploadTracyRecords(variables) {
7126
+ return await this._clientSdk.UploadTracyRecords(variables);
7127
+ }
7128
+ async getTracyRawDataUploadUrls(variables) {
7129
+ return await this._clientSdk.GetTracyRawDataUploadUrls(variables);
7130
+ }
7097
7131
  async analyzeCommitForExtensionAIBlame(variables) {
7098
7132
  return await this._clientSdk.AnalyzeCommitForExtensionAIBlame(variables);
7099
7133
  }
@@ -7111,6 +7145,209 @@ var GQLClient = class {
7111
7145
  }
7112
7146
  };
7113
7147
 
7148
+ // src/features/analysis/graphql/tracy-batch-upload.ts
7149
+ import { promisify } from "util";
7150
+ import { gzip } from "zlib";
7151
+ import Debug8 from "debug";
7152
+
7153
+ // src/utils/sanitize-sensitive-data.ts
7154
+ import { OpenRedaction } from "@openredaction/openredaction";
7155
+ var openRedaction = new OpenRedaction({
7156
+ patterns: [
7157
+ // Core Personal Data
7158
+ // Removed EMAIL - causes false positives in code/test snippets (e.g. --author="Eve Author <eve@example.com>")
7159
+ // Prefer false negatives over false positives for this use case.
7160
+ "SSN",
7161
+ "NATIONAL_INSURANCE_UK",
7162
+ "DATE_OF_BIRTH",
7163
+ // Identity Documents
7164
+ "PASSPORT_UK",
7165
+ "PASSPORT_US",
7166
+ "PASSPORT_MRZ_TD1",
7167
+ "PASSPORT_MRZ_TD3",
7168
+ "DRIVING_LICENSE_UK",
7169
+ "DRIVING_LICENSE_US",
7170
+ "VISA_NUMBER",
7171
+ "VISA_MRZ",
7172
+ "TAX_ID",
7173
+ // Financial Data (removed SWIFT_BIC, CARD_AUTH_CODE - too broad, causing false positives with authentication words)
7174
+ // Removed CREDIT_CARD - causes false positives on zero-filled UUIDs (e.g. '00000000-0000-0000-0000-000000000000')
7175
+ // Prefer false negatives over false positives for this use case.
7176
+ "IBAN",
7177
+ "BANK_ACCOUNT_UK",
7178
+ "ROUTING_NUMBER_US",
7179
+ "CARD_TRACK1_DATA",
7180
+ "CARD_TRACK2_DATA",
7181
+ "CARD_EXPIRY",
7182
+ // Cryptocurrency (removed BITCOIN_ADDRESS - too broad, matches hash-like strings)
7183
+ "ETHEREUM_ADDRESS",
7184
+ "LITECOIN_ADDRESS",
7185
+ "CARDANO_ADDRESS",
7186
+ "SOLANA_ADDRESS",
7187
+ "MONERO_ADDRESS",
7188
+ "RIPPLE_ADDRESS",
7189
+ // Medical Data (removed PRESCRIPTION_NUMBER - too broad, matches words containing "ription")
7190
+ // Removed MEDICAL_RECORD_NUMBER - too broad, "MR" prefix matches "Merge Request" in SCM contexts (e.g. "MR branches" → "MR br****es")
7191
+ "NHS_NUMBER",
7192
+ "AUSTRALIAN_MEDICARE",
7193
+ "HEALTH_PLAN_NUMBER",
7194
+ "PATIENT_ID",
7195
+ // Communications (removed EMERGENCY_CONTACT, ADDRESS_PO_BOX, ZIP_CODE_US, PHONE_US, PHONE_INTERNATIONAL - too broad, causing false positives)
7196
+ "PHONE_UK",
7197
+ "PHONE_UK_MOBILE",
7198
+ "PHONE_LINE_NUMBER",
7199
+ "ADDRESS_STREET",
7200
+ "POSTCODE_UK",
7201
+ // Network & Technical
7202
+ "IPV4",
7203
+ "IPV6",
7204
+ "MAC_ADDRESS",
7205
+ "URL_WITH_AUTH",
7206
+ // Security Keys & Tokens
7207
+ "PRIVATE_KEY",
7208
+ "SSH_PRIVATE_KEY",
7209
+ "AWS_SECRET_KEY",
7210
+ "AWS_ACCESS_KEY",
7211
+ "AZURE_STORAGE_KEY",
7212
+ "GCP_SERVICE_ACCOUNT",
7213
+ "JWT_TOKEN",
7214
+ "OAUTH_TOKEN",
7215
+ "OAUTH_CLIENT_SECRET",
7216
+ "BEARER_TOKEN",
7217
+ "PAYMENT_TOKEN",
7218
+ "GENERIC_SECRET",
7219
+ "GENERIC_API_KEY",
7220
+ // Platform-Specific API Keys
7221
+ "GITHUB_TOKEN",
7222
+ "SLACK_TOKEN",
7223
+ "STRIPE_API_KEY",
7224
+ "GOOGLE_API_KEY",
7225
+ "FIREBASE_API_KEY",
7226
+ "HEROKU_API_KEY",
7227
+ "MAILGUN_API_KEY",
7228
+ "SENDGRID_API_KEY",
7229
+ "TWILIO_API_KEY",
7230
+ "NPM_TOKEN",
7231
+ "PYPI_TOKEN",
7232
+ "DOCKER_AUTH",
7233
+ "KUBERNETES_SECRET",
7234
+ // Government & Legal
7235
+ // Removed CLIENT_ID - too broad, "client" is ubiquitous in code (npm packages like @scope/client-*, class names like ClientSdkOptions)
7236
+ "POLICE_REPORT_NUMBER",
7237
+ "IMMIGRATION_NUMBER",
7238
+ "COURT_REPORTER_LICENSE"
7239
+ ]
7240
+ });
7241
+ function maskString(str, showStart = 2, showEnd = 2) {
7242
+ if (str.length <= showStart + showEnd) {
7243
+ return "*".repeat(str.length);
7244
+ }
7245
+ return str.slice(0, showStart) + "*".repeat(str.length - showStart - showEnd) + str.slice(-showEnd);
7246
+ }
7247
+ async function sanitizeDataWithCounts(obj) {
7248
+ const counts = {
7249
+ detections: { total: 0, high: 0, medium: 0, low: 0 }
7250
+ };
7251
+ const sanitizeString = async (str) => {
7252
+ let result = str;
7253
+ const piiDetections = openRedaction.scan(str);
7254
+ if (piiDetections && piiDetections.total > 0) {
7255
+ const allDetections = [
7256
+ ...piiDetections.high,
7257
+ ...piiDetections.medium,
7258
+ ...piiDetections.low
7259
+ ];
7260
+ for (const detection of allDetections) {
7261
+ counts.detections.total++;
7262
+ if (detection.severity === "high") counts.detections.high++;
7263
+ else if (detection.severity === "medium") counts.detections.medium++;
7264
+ else if (detection.severity === "low") counts.detections.low++;
7265
+ const masked = maskString(detection.value);
7266
+ result = result.replaceAll(detection.value, masked);
7267
+ }
7268
+ }
7269
+ return result;
7270
+ };
7271
+ const sanitizeRecursive = async (data) => {
7272
+ if (typeof data === "string") {
7273
+ return sanitizeString(data);
7274
+ } else if (Array.isArray(data)) {
7275
+ return Promise.all(data.map((item) => sanitizeRecursive(item)));
7276
+ } else if (data instanceof Error) {
7277
+ return data;
7278
+ } else if (data instanceof Date) {
7279
+ return data;
7280
+ } else if (typeof data === "object" && data !== null) {
7281
+ const sanitized = {};
7282
+ const record = data;
7283
+ for (const key in record) {
7284
+ if (Object.prototype.hasOwnProperty.call(record, key)) {
7285
+ sanitized[key] = await sanitizeRecursive(record[key]);
7286
+ }
7287
+ }
7288
+ return sanitized;
7289
+ }
7290
+ return data;
7291
+ };
7292
+ const sanitizedData = await sanitizeRecursive(obj);
7293
+ return { sanitizedData, counts };
7294
+ }
7295
+
7296
+ // src/features/analysis/upload-file.ts
7297
+ import Debug7 from "debug";
7298
+ import fetch3, { File, fileFrom, FormData } from "node-fetch";
7299
+ var debug8 = Debug7("mobbdev:upload-file");
7300
+ async function uploadFile({
7301
+ file,
7302
+ url,
7303
+ uploadKey,
7304
+ uploadFields,
7305
+ logger
7306
+ }) {
7307
+ const logInfo = logger || ((_message, _data) => {
7308
+ });
7309
+ logInfo(`FileUpload: upload file start ${url}`);
7310
+ logInfo(`FileUpload: upload fields`, uploadFields);
7311
+ logInfo(`FileUpload: upload key ${uploadKey}`);
7312
+ debug8("upload file start %s", url);
7313
+ debug8("upload fields %o", uploadFields);
7314
+ debug8("upload key %s", uploadKey);
7315
+ const form = new FormData();
7316
+ Object.entries(uploadFields).forEach(([key, value]) => {
7317
+ form.append(key, value);
7318
+ });
7319
+ if (!form.has("key")) {
7320
+ form.append("key", uploadKey);
7321
+ }
7322
+ if (typeof file === "string") {
7323
+ debug8("upload file from path %s", file);
7324
+ logInfo(`FileUpload: upload file from path ${file}`);
7325
+ form.append("file", await fileFrom(file));
7326
+ } else {
7327
+ debug8("upload file from buffer");
7328
+ logInfo(`FileUpload: upload file from buffer`);
7329
+ form.append("file", new File([new Uint8Array(file)], "file"));
7330
+ }
7331
+ const agent = getProxyAgent(url);
7332
+ const response = await fetch3(url, {
7333
+ method: "POST",
7334
+ body: form,
7335
+ agent
7336
+ });
7337
+ if (!response.ok) {
7338
+ debug8("error from S3 %s %s", response.body, response.status);
7339
+ logInfo(`FileUpload: error from S3 ${response.body} ${response.status}`);
7340
+ throw new Error(`Failed to upload the file: ${response.status}`);
7341
+ }
7342
+ debug8("upload file done");
7343
+ logInfo(`FileUpload: upload file done`);
7344
+ }
7345
+
7346
+ // src/features/analysis/graphql/tracy-batch-upload.ts
7347
+ var gzipAsync = promisify(gzip);
7348
+ var debug9 = Debug8("mobbdev:tracy-batch-upload");
7349
+ var MAX_BATCH_PAYLOAD_BYTES = 3 * 1024 * 1024;
7350
+
7114
7351
  // src/mcp/services/types.ts
7115
7352
  function buildLoginUrl(baseUrl, loginId, hostname, context) {
7116
7353
  const url = new URL(`${baseUrl}/${loginId}`);
@@ -7143,9 +7380,10 @@ function getConfigStore() {
7143
7380
  var configStore = getConfigStore();
7144
7381
 
7145
7382
  // src/commands/AuthManager.ts
7383
+ var debug10 = Debug9("mobbdev:auth");
7146
7384
  var LOGIN_MAX_WAIT = 10 * 60 * 1e3;
7147
7385
  var LOGIN_CHECK_DELAY = 5 * 1e3;
7148
- var AuthManager = class {
7386
+ var _AuthManager = class _AuthManager {
7149
7387
  constructor(webAppUrl, apiUrl) {
7150
7388
  __publicField(this, "publicKey");
7151
7389
  __publicField(this, "privateKey");
@@ -7167,7 +7405,7 @@ var AuthManager = class {
7167
7405
  }
7168
7406
  async waitForAuthentication() {
7169
7407
  let newApiToken = null;
7170
- for (let i = 0; i < LOGIN_MAX_WAIT / LOGIN_CHECK_DELAY; i++) {
7408
+ for (let i = 0; i < _AuthManager.loginMaxWait / LOGIN_CHECK_DELAY; i++) {
7171
7409
  newApiToken = await this.getApiToken();
7172
7410
  if (newApiToken) {
7173
7411
  break;
@@ -7197,6 +7435,9 @@ var AuthManager = class {
7197
7435
  if (this.authenticated === null) {
7198
7436
  const result = await this.checkAuthentication();
7199
7437
  this.authenticated = result.isAuthenticated;
7438
+ if (!result.isAuthenticated) {
7439
+ debug10("isAuthenticated: false \u2014 %s", result.message);
7440
+ }
7200
7441
  }
7201
7442
  return this.authenticated;
7202
7443
  }
@@ -7273,6 +7514,14 @@ var AuthManager = class {
7273
7514
  }
7274
7515
  return null;
7275
7516
  }
7517
+ /**
7518
+ * Returns true if a non-empty API token is stored in the configStore.
7519
+ * Used for diagnostics — does NOT validate the token.
7520
+ */
7521
+ hasStoredToken() {
7522
+ const token = configStore.get("apiToken");
7523
+ return typeof token === "string" && token.length > 0;
7524
+ }
7276
7525
  /**
7277
7526
  * Gets the current GQL client (if authenticated)
7278
7527
  */
@@ -7305,9 +7554,12 @@ var AuthManager = class {
7305
7554
  this.currentBrowserUrl = null;
7306
7555
  }
7307
7556
  };
7557
+ /** Maximum time (ms) to wait for login authentication. Override in tests for faster failures. */
7558
+ __publicField(_AuthManager, "loginMaxWait", LOGIN_MAX_WAIT);
7559
+ var AuthManager = _AuthManager;
7308
7560
 
7309
7561
  // src/commands/handleMobbLogin.ts
7310
- var debug8 = Debug7("mobbdev:commands");
7562
+ var debug11 = Debug10("mobbdev:commands");
7311
7563
  var LOGIN_MAX_WAIT2 = 10 * 60 * 1e3;
7312
7564
  var LOGIN_CHECK_DELAY2 = 5 * 1e3;
7313
7565
  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(
@@ -7319,7 +7571,7 @@ async function getAuthenticatedGQLClient({
7319
7571
  apiUrl,
7320
7572
  webAppUrl
7321
7573
  }) {
7322
- debug8(
7574
+ debug11(
7323
7575
  "getAuthenticatedGQLClient called with: apiUrl=%s, webAppUrl=%s",
7324
7576
  apiUrl || "undefined",
7325
7577
  webAppUrl || "undefined"
@@ -7342,7 +7594,7 @@ async function handleMobbLogin({
7342
7594
  webAppUrl,
7343
7595
  loginContext
7344
7596
  }) {
7345
- debug8(
7597
+ debug11(
7346
7598
  "handleMobbLogin: resolved URLs - apiUrl=%s (from param: %s), webAppUrl=%s (from param: %s)",
7347
7599
  apiUrl || "fallback",
7348
7600
  apiUrl || "fallback",
@@ -7361,7 +7613,7 @@ async function handleMobbLogin({
7361
7613
  return authManager.getGQLClient();
7362
7614
  }
7363
7615
  } catch (error) {
7364
- debug8("Authentication check failed:", error);
7616
+ debug11("Authentication check failed:", error);
7365
7617
  }
7366
7618
  if (apiKey) {
7367
7619
  createSpinner().start().error({
@@ -7412,56 +7664,6 @@ init_client_generates();
7412
7664
  init_GitService();
7413
7665
  init_urlParser2();
7414
7666
 
7415
- // src/features/analysis/upload-file.ts
7416
- import Debug8 from "debug";
7417
- import fetch3, { File, fileFrom, FormData } from "node-fetch";
7418
- var debug9 = Debug8("mobbdev:upload-file");
7419
- async function uploadFile({
7420
- file,
7421
- url,
7422
- uploadKey,
7423
- uploadFields,
7424
- logger
7425
- }) {
7426
- const logInfo = logger || ((_message, _data) => {
7427
- });
7428
- logInfo(`FileUpload: upload file start ${url}`);
7429
- logInfo(`FileUpload: upload fields`, uploadFields);
7430
- logInfo(`FileUpload: upload key ${uploadKey}`);
7431
- debug9("upload file start %s", url);
7432
- debug9("upload fields %o", uploadFields);
7433
- debug9("upload key %s", uploadKey);
7434
- const form = new FormData();
7435
- Object.entries(uploadFields).forEach(([key, value]) => {
7436
- form.append(key, value);
7437
- });
7438
- if (!form.has("key")) {
7439
- form.append("key", uploadKey);
7440
- }
7441
- if (typeof file === "string") {
7442
- debug9("upload file from path %s", file);
7443
- logInfo(`FileUpload: upload file from path ${file}`);
7444
- form.append("file", await fileFrom(file));
7445
- } else {
7446
- debug9("upload file from buffer");
7447
- logInfo(`FileUpload: upload file from buffer`);
7448
- form.append("file", new File([new Uint8Array(file)], "file"));
7449
- }
7450
- const agent = getProxyAgent(url);
7451
- const response = await fetch3(url, {
7452
- method: "POST",
7453
- body: form,
7454
- agent
7455
- });
7456
- if (!response.ok) {
7457
- debug9("error from S3 %s %s", response.body, response.status);
7458
- logInfo(`FileUpload: error from S3 ${response.body} ${response.status}`);
7459
- throw new Error(`Failed to upload the file: ${response.status}`);
7460
- }
7461
- debug9("upload file done");
7462
- logInfo(`FileUpload: upload file done`);
7463
- }
7464
-
7465
7667
  // src/utils/computerName.ts
7466
7668
  import { execSync } from "child_process";
7467
7669
  import os2 from "os";
@@ -7551,149 +7753,6 @@ function getStableComputerName() {
7551
7753
  return currentName;
7552
7754
  }
7553
7755
 
7554
- // src/utils/sanitize-sensitive-data.ts
7555
- import { OpenRedaction } from "@openredaction/openredaction";
7556
- var openRedaction = new OpenRedaction({
7557
- patterns: [
7558
- // Core Personal Data
7559
- // Removed EMAIL - causes false positives in code/test snippets (e.g. --author="Eve Author <eve@example.com>")
7560
- // Prefer false negatives over false positives for this use case.
7561
- "SSN",
7562
- "NATIONAL_INSURANCE_UK",
7563
- "DATE_OF_BIRTH",
7564
- // Identity Documents
7565
- "PASSPORT_UK",
7566
- "PASSPORT_US",
7567
- "PASSPORT_MRZ_TD1",
7568
- "PASSPORT_MRZ_TD3",
7569
- "DRIVING_LICENSE_UK",
7570
- "DRIVING_LICENSE_US",
7571
- "VISA_NUMBER",
7572
- "VISA_MRZ",
7573
- "TAX_ID",
7574
- // Financial Data (removed SWIFT_BIC, CARD_AUTH_CODE - too broad, causing false positives with authentication words)
7575
- // Removed CREDIT_CARD - causes false positives on zero-filled UUIDs (e.g. '00000000-0000-0000-0000-000000000000')
7576
- // Prefer false negatives over false positives for this use case.
7577
- "IBAN",
7578
- "BANK_ACCOUNT_UK",
7579
- "ROUTING_NUMBER_US",
7580
- "CARD_TRACK1_DATA",
7581
- "CARD_TRACK2_DATA",
7582
- "CARD_EXPIRY",
7583
- // Cryptocurrency (removed BITCOIN_ADDRESS - too broad, matches hash-like strings)
7584
- "ETHEREUM_ADDRESS",
7585
- "LITECOIN_ADDRESS",
7586
- "CARDANO_ADDRESS",
7587
- "SOLANA_ADDRESS",
7588
- "MONERO_ADDRESS",
7589
- "RIPPLE_ADDRESS",
7590
- // Medical Data (removed PRESCRIPTION_NUMBER - too broad, matches words containing "ription")
7591
- // Removed MEDICAL_RECORD_NUMBER - too broad, "MR" prefix matches "Merge Request" in SCM contexts (e.g. "MR branches" → "MR br****es")
7592
- "NHS_NUMBER",
7593
- "AUSTRALIAN_MEDICARE",
7594
- "HEALTH_PLAN_NUMBER",
7595
- "PATIENT_ID",
7596
- // Communications (removed EMERGENCY_CONTACT, ADDRESS_PO_BOX, ZIP_CODE_US, PHONE_US, PHONE_INTERNATIONAL - too broad, causing false positives)
7597
- "PHONE_UK",
7598
- "PHONE_UK_MOBILE",
7599
- "PHONE_LINE_NUMBER",
7600
- "ADDRESS_STREET",
7601
- "POSTCODE_UK",
7602
- // Network & Technical
7603
- "IPV4",
7604
- "IPV6",
7605
- "MAC_ADDRESS",
7606
- "URL_WITH_AUTH",
7607
- // Security Keys & Tokens
7608
- "PRIVATE_KEY",
7609
- "SSH_PRIVATE_KEY",
7610
- "AWS_SECRET_KEY",
7611
- "AWS_ACCESS_KEY",
7612
- "AZURE_STORAGE_KEY",
7613
- "GCP_SERVICE_ACCOUNT",
7614
- "JWT_TOKEN",
7615
- "OAUTH_TOKEN",
7616
- "OAUTH_CLIENT_SECRET",
7617
- "BEARER_TOKEN",
7618
- "PAYMENT_TOKEN",
7619
- "GENERIC_SECRET",
7620
- "GENERIC_API_KEY",
7621
- // Platform-Specific API Keys
7622
- "GITHUB_TOKEN",
7623
- "SLACK_TOKEN",
7624
- "STRIPE_API_KEY",
7625
- "GOOGLE_API_KEY",
7626
- "FIREBASE_API_KEY",
7627
- "HEROKU_API_KEY",
7628
- "MAILGUN_API_KEY",
7629
- "SENDGRID_API_KEY",
7630
- "TWILIO_API_KEY",
7631
- "NPM_TOKEN",
7632
- "PYPI_TOKEN",
7633
- "DOCKER_AUTH",
7634
- "KUBERNETES_SECRET",
7635
- // Government & Legal
7636
- // Removed CLIENT_ID - too broad, "client" is ubiquitous in code (npm packages like @scope/client-*, class names like ClientSdkOptions)
7637
- "POLICE_REPORT_NUMBER",
7638
- "IMMIGRATION_NUMBER",
7639
- "COURT_REPORTER_LICENSE"
7640
- ]
7641
- });
7642
- function maskString(str, showStart = 2, showEnd = 2) {
7643
- if (str.length <= showStart + showEnd) {
7644
- return "*".repeat(str.length);
7645
- }
7646
- return str.slice(0, showStart) + "*".repeat(str.length - showStart - showEnd) + str.slice(-showEnd);
7647
- }
7648
- async function sanitizeDataWithCounts(obj) {
7649
- const counts = {
7650
- detections: { total: 0, high: 0, medium: 0, low: 0 }
7651
- };
7652
- const sanitizeString = async (str) => {
7653
- let result = str;
7654
- const piiDetections = openRedaction.scan(str);
7655
- if (piiDetections && piiDetections.total > 0) {
7656
- const allDetections = [
7657
- ...piiDetections.high,
7658
- ...piiDetections.medium,
7659
- ...piiDetections.low
7660
- ];
7661
- for (const detection of allDetections) {
7662
- counts.detections.total++;
7663
- if (detection.severity === "high") counts.detections.high++;
7664
- else if (detection.severity === "medium") counts.detections.medium++;
7665
- else if (detection.severity === "low") counts.detections.low++;
7666
- const masked = maskString(detection.value);
7667
- result = result.replaceAll(detection.value, masked);
7668
- }
7669
- }
7670
- return result;
7671
- };
7672
- const sanitizeRecursive = async (data) => {
7673
- if (typeof data === "string") {
7674
- return sanitizeString(data);
7675
- } else if (Array.isArray(data)) {
7676
- return Promise.all(data.map((item) => sanitizeRecursive(item)));
7677
- } else if (data instanceof Error) {
7678
- return data;
7679
- } else if (data instanceof Date) {
7680
- return data;
7681
- } else if (typeof data === "object" && data !== null) {
7682
- const sanitized = {};
7683
- const record = data;
7684
- for (const key in record) {
7685
- if (Object.prototype.hasOwnProperty.call(record, key)) {
7686
- sanitized[key] = await sanitizeRecursive(record[key]);
7687
- }
7688
- }
7689
- return sanitized;
7690
- }
7691
- return data;
7692
- };
7693
- const sanitizedData = await sanitizeRecursive(obj);
7694
- return { sanitizedData, counts };
7695
- }
7696
-
7697
7756
  // src/args/commands/upload_ai_blame.ts
7698
7757
  var defaultLogger = {
7699
7758
  info: (msg, data) => {
@@ -8014,6 +8073,8 @@ async function uploadAiBlameCommandHandler(args) {
8014
8073
  await uploadAiBlameHandler({ args });
8015
8074
  }
8016
8075
  export {
8076
+ getRepositoryUrl,
8077
+ getSystemInfo,
8017
8078
  uploadAiBlameBuilder,
8018
8079
  uploadAiBlameCommandHandler,
8019
8080
  uploadAiBlameHandler,