mobbdev 1.1.27 → 1.1.29

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.
@@ -16,6 +16,10 @@ type SanitizationCounts = {
16
16
  };
17
17
  };
18
18
 
19
+ type Logger = {
20
+ info: (msg: string, data?: unknown) => void;
21
+ error: (msg: string, data?: unknown) => void;
22
+ };
19
23
  declare const PromptItemZ: z.ZodObject<{
20
24
  type: z.ZodEnum<["USER_PROMPT", "AI_RESPONSE", "TOOL_EXECUTION", "AI_THINKING"]>;
21
25
  attachedFiles: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -210,7 +214,17 @@ declare function uploadAiBlameHandlerFromExtension(args: {
210
214
  responseTime: string;
211
215
  blameType?: AiBlameInferenceType;
212
216
  sessionId?: string;
217
+ apiUrl?: string;
218
+ webAppUrl?: string;
213
219
  }): Promise<UploadAiBlameResult>;
214
- declare function uploadAiBlameHandler(args: UploadAiBlameOptions, exitOnError?: boolean): Promise<void>;
220
+ type UploadAiBlameHandlerOptions = {
221
+ args: UploadAiBlameOptions;
222
+ exitOnError?: boolean;
223
+ apiUrl?: string;
224
+ webAppUrl?: string;
225
+ logger?: Logger;
226
+ };
227
+ declare function uploadAiBlameHandler(options: UploadAiBlameHandlerOptions): Promise<void>;
228
+ declare function uploadAiBlameCommandHandler(args: UploadAiBlameOptions): Promise<void>;
215
229
 
216
- export { type PromptItem, type PromptItemArray, type UploadAiBlameOptions, type UploadAiBlameResult, uploadAiBlameBuilder, uploadAiBlameHandler, uploadAiBlameHandlerFromExtension };
230
+ export { type PromptItem, type PromptItemArray, type UploadAiBlameOptions, type UploadAiBlameResult, uploadAiBlameBuilder, uploadAiBlameCommandHandler, uploadAiBlameHandler, uploadAiBlameHandlerFromExtension };
@@ -80,11 +80,13 @@ import fs4 from "fs";
80
80
  import ignore from "ignore";
81
81
  import * as path5 from "path";
82
82
  import { simpleGit as simpleGit2 } from "simple-git";
83
+ var MAX_COMMIT_DIFF_SIZE_BYTES;
83
84
  var init_GitService = __esm({
84
85
  "src/features/analysis/scm/services/GitService.ts"() {
85
86
  "use strict";
86
87
  init_configs();
87
88
  init_FileUtils();
89
+ MAX_COMMIT_DIFF_SIZE_BYTES = 3 * 1024 * 1024;
88
90
  }
89
91
  });
90
92
 
@@ -817,11 +819,14 @@ var UploadS3BucketInfoDocument = `
817
819
  }
818
820
  `;
819
821
  var AnalyzeCommitForExtensionAiBlameDocument = `
820
- mutation AnalyzeCommitForExtensionAIBlame($repositoryURL: String!, $commitSha: String!, $organizationId: String!) {
822
+ mutation AnalyzeCommitForExtensionAIBlame($repositoryURL: String!, $commitSha: String!, $organizationId: String!, $commitDiff: String, $commitTimestamp: Timestamp, $parentCommits: [ParentCommitInput!]) {
821
823
  analyzeCommitForAIBlame(
822
824
  repositoryURL: $repositoryURL
823
825
  commitSha: $commitSha
824
826
  organizationId: $organizationId
827
+ commitDiff: $commitDiff
828
+ commitTimestamp: $commitTimestamp
829
+ parentCommits: $parentCommits
825
830
  ) {
826
831
  __typename
827
832
  ... on ProcessAIBlameFinalResult {
@@ -867,6 +872,30 @@ var GetAiBlameAttributionPromptDocument = `
867
872
  }
868
873
  }
869
874
  `;
875
+ var GetPromptSummaryDocument = `
876
+ query GetPromptSummary($aiBlameAttributionId: String!) {
877
+ getPromptSummary(aiBlameAttributionId: $aiBlameAttributionId) {
878
+ __typename
879
+ ... on PromptSummarySuccess {
880
+ status
881
+ summary {
882
+ goal
883
+ developersPlan
884
+ aiImplementationDetails
885
+ importantInstructionsAndPushbacks
886
+ frictionScore {
887
+ score
888
+ justification
889
+ }
890
+ }
891
+ }
892
+ ... on PromptSummaryError {
893
+ status
894
+ error
895
+ }
896
+ }
897
+ }
898
+ `;
870
899
  var UploadAiBlameInferencesInitDocument = `
871
900
  mutation UploadAIBlameInferencesInit($sessions: [AIBlameInferenceInitInput!]!) {
872
901
  uploadAIBlameInferencesInit(sessions: $sessions) {
@@ -1194,6 +1223,9 @@ function getSdk(client, withWrapper = defaultWrapper) {
1194
1223
  GetAIBlameAttributionPrompt(variables, requestHeaders, signal) {
1195
1224
  return withWrapper((wrappedRequestHeaders) => client.request({ document: GetAiBlameAttributionPromptDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetAIBlameAttributionPrompt", "query", variables);
1196
1225
  },
1226
+ GetPromptSummary(variables, requestHeaders, signal) {
1227
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetPromptSummaryDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetPromptSummary", "query", variables);
1228
+ },
1197
1229
  UploadAIBlameInferencesInit(variables, requestHeaders, signal) {
1198
1230
  return withWrapper((wrappedRequestHeaders) => client.request({ document: UploadAiBlameInferencesInitDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "UploadAIBlameInferencesInit", "mutation", variables);
1199
1231
  },
@@ -4734,6 +4766,11 @@ var GQLClient = class {
4734
4766
  debug6(`init with ${args}`);
4735
4767
  this._auth = args;
4736
4768
  this._apiUrl = args.apiUrl || API_URL;
4769
+ debug6(
4770
+ "GQLClient constructor: resolved apiUrl=%s (from param: %s)",
4771
+ this._apiUrl,
4772
+ args.apiUrl || "fallback to API_URL constant"
4773
+ );
4737
4774
  this._client = new GraphQLClient(this._apiUrl, {
4738
4775
  headers: args.type === "apiKey" ? { [API_KEY_HEADER_NAME]: args.apiKey || "" } : {
4739
4776
  Authorization: `Bearer ${args.token}`
@@ -5098,6 +5135,9 @@ var GQLClient = class {
5098
5135
  async getAIBlameAttributionPrompt(variables) {
5099
5136
  return await this._clientSdk.GetAIBlameAttributionPrompt(variables);
5100
5137
  }
5138
+ async getAIBlameAttributionPromptSummary(variables) {
5139
+ return await this._clientSdk.GetPromptSummary(variables);
5140
+ }
5101
5141
  };
5102
5142
 
5103
5143
  // src/mcp/services/types.ts
@@ -5144,6 +5184,11 @@ async function getAuthenticatedGQLClient({
5144
5184
  apiUrl,
5145
5185
  webAppUrl
5146
5186
  }) {
5187
+ debug7(
5188
+ "getAuthenticatedGQLClient called with: apiUrl=%s, webAppUrl=%s",
5189
+ apiUrl || "undefined",
5190
+ webAppUrl || "undefined"
5191
+ );
5147
5192
  let gqlClient = new GQLClient({
5148
5193
  apiKey: inputApiKey || configStore.get("apiToken") || "",
5149
5194
  type: "apiKey",
@@ -5167,6 +5212,13 @@ async function handleMobbLogin({
5167
5212
  }) {
5168
5213
  const resolvedWebAppUrl = webAppUrl || WEB_APP_URL;
5169
5214
  const resolvedApiUrl = apiUrl || API_URL;
5215
+ debug7(
5216
+ "handleMobbLogin: resolved URLs - apiUrl=%s (from param: %s), webAppUrl=%s (from param: %s)",
5217
+ resolvedApiUrl,
5218
+ apiUrl || "fallback",
5219
+ resolvedWebAppUrl,
5220
+ webAppUrl || "fallback"
5221
+ );
5170
5222
  const { createSpinner } = Spinner({ ci: skipPrompts });
5171
5223
  const isConnected = await inGqlClient.verifyApiConnection();
5172
5224
  if (!isConnected) {
@@ -5447,6 +5499,22 @@ async function sanitizeDataWithCounts(obj) {
5447
5499
  }
5448
5500
 
5449
5501
  // src/args/commands/upload_ai_blame.ts
5502
+ var defaultLogger = {
5503
+ info: (msg, data) => {
5504
+ if (data !== void 0) {
5505
+ console.log(msg, data);
5506
+ } else {
5507
+ console.log(msg);
5508
+ }
5509
+ },
5510
+ error: (msg, data) => {
5511
+ if (data !== void 0) {
5512
+ console.error(msg, data);
5513
+ } else {
5514
+ console.error(msg);
5515
+ }
5516
+ }
5517
+ };
5450
5518
  var PromptItemZ = z26.object({
5451
5519
  type: z26.enum(["USER_PROMPT", "AI_RESPONSE", "TOOL_EXECUTION", "AI_THINKING"]),
5452
5520
  attachedFiles: z26.array(
@@ -5562,7 +5630,12 @@ async function uploadAiBlameHandlerFromExtension(args) {
5562
5630
  if (args.sessionId) {
5563
5631
  uploadArgs.sessionId.push(args.sessionId);
5564
5632
  }
5565
- await uploadAiBlameHandler(uploadArgs, false);
5633
+ await uploadAiBlameHandler({
5634
+ args: uploadArgs,
5635
+ exitOnError: false,
5636
+ apiUrl: args.apiUrl,
5637
+ webAppUrl: args.webAppUrl
5638
+ });
5566
5639
  });
5567
5640
  });
5568
5641
  return {
@@ -5572,7 +5645,14 @@ async function uploadAiBlameHandlerFromExtension(args) {
5572
5645
  inferenceUUID
5573
5646
  };
5574
5647
  }
5575
- async function uploadAiBlameHandler(args, exitOnError = true) {
5648
+ async function uploadAiBlameHandler(options) {
5649
+ const {
5650
+ args,
5651
+ exitOnError = true,
5652
+ apiUrl,
5653
+ webAppUrl,
5654
+ logger = defaultLogger
5655
+ } = options;
5576
5656
  const prompts = args.prompt || [];
5577
5657
  const inferences = args.inference || [];
5578
5658
  const models = args.model || [];
@@ -5582,7 +5662,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
5582
5662
  const sessionIds = args.sessionId || args["session-id"] || [];
5583
5663
  if (prompts.length !== inferences.length) {
5584
5664
  const errorMsg = "prompt and inference must have the same number of entries";
5585
- console.error(chalk3.red(errorMsg));
5665
+ logger.error(chalk3.red(errorMsg));
5586
5666
  if (exitOnError) {
5587
5667
  process.exit(1);
5588
5668
  }
@@ -5601,7 +5681,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
5601
5681
  ]);
5602
5682
  } catch {
5603
5683
  const errorMsg = `File not found for session ${i + 1}`;
5604
- console.error(chalk3.red(errorMsg));
5684
+ logger.error(chalk3.red(errorMsg));
5605
5685
  if (exitOnError) {
5606
5686
  process.exit(1);
5607
5687
  }
@@ -5620,7 +5700,9 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
5620
5700
  });
5621
5701
  }
5622
5702
  const authenticatedClient = await getAuthenticatedGQLClient({
5623
- isSkipPrompts: true
5703
+ isSkipPrompts: true,
5704
+ apiUrl,
5705
+ webAppUrl
5624
5706
  });
5625
5707
  const initSessions = sessions.map(
5626
5708
  ({ sessionId: _sessionId, ...rest }) => rest
@@ -5631,7 +5713,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
5631
5713
  const uploadSessions = initRes.uploadAIBlameInferencesInit?.uploadSessions ?? [];
5632
5714
  if (uploadSessions.length !== sessions.length) {
5633
5715
  const errorMsg = "Init failed to return expected number of sessions";
5634
- console.error(chalk3.red(errorMsg));
5716
+ logger.error(chalk3.red(errorMsg));
5635
5717
  if (exitOnError) {
5636
5718
  process.exit(1);
5637
5719
  }
@@ -5673,22 +5755,41 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
5673
5755
  sessionId: s.sessionId
5674
5756
  };
5675
5757
  });
5676
- const finRes = await authenticatedClient.finalizeAIBlameInferencesUploadRaw({
5677
- sessions: finalizeSessions
5678
- });
5679
- const status = finRes?.finalizeAIBlameInferencesUpload?.status;
5680
- if (status !== "OK") {
5681
- const errorMsg = finRes?.finalizeAIBlameInferencesUpload?.error || "unknown error";
5682
- console.error(chalk3.red(errorMsg));
5683
- if (exitOnError) {
5684
- process.exit(1);
5758
+ try {
5759
+ logger.info(
5760
+ `[UPLOAD] Calling finalizeAIBlameInferencesUploadRaw with ${finalizeSessions.length} sessions`
5761
+ );
5762
+ const finRes = await authenticatedClient.finalizeAIBlameInferencesUploadRaw(
5763
+ {
5764
+ sessions: finalizeSessions
5765
+ }
5766
+ );
5767
+ logger.info("[UPLOAD] Finalize response:", JSON.stringify(finRes, null, 2));
5768
+ const status = finRes?.finalizeAIBlameInferencesUpload?.status;
5769
+ if (status !== "OK") {
5770
+ const errorMsg = finRes?.finalizeAIBlameInferencesUpload?.error || "unknown error";
5771
+ logger.error(
5772
+ chalk3.red(
5773
+ `[UPLOAD] Finalize failed with status: ${status}, error: ${errorMsg}`
5774
+ )
5775
+ );
5776
+ if (exitOnError) {
5777
+ process.exit(1);
5778
+ }
5779
+ throw new Error(errorMsg);
5685
5780
  }
5686
- throw new Error(errorMsg);
5781
+ logger.info(chalk3.green("[UPLOAD] AI Blame uploads finalized successfully"));
5782
+ } catch (error) {
5783
+ logger.error("[UPLOAD] Finalize threw error:", error);
5784
+ throw error;
5687
5785
  }
5688
- console.log(chalk3.green("AI Blame uploads finalized successfully"));
5786
+ }
5787
+ async function uploadAiBlameCommandHandler(args) {
5788
+ await uploadAiBlameHandler({ args });
5689
5789
  }
5690
5790
  export {
5691
5791
  uploadAiBlameBuilder,
5792
+ uploadAiBlameCommandHandler,
5692
5793
  uploadAiBlameHandler,
5693
5794
  uploadAiBlameHandlerFromExtension
5694
5795
  };
package/dist/index.mjs CHANGED
@@ -723,12 +723,13 @@ import fs2 from "fs";
723
723
  import ignore from "ignore";
724
724
  import * as path2 from "path";
725
725
  import { simpleGit } from "simple-git";
726
- var GitService;
726
+ var MAX_COMMIT_DIFF_SIZE_BYTES, GitService;
727
727
  var init_GitService = __esm({
728
728
  "src/features/analysis/scm/services/GitService.ts"() {
729
729
  "use strict";
730
730
  init_configs();
731
731
  init_FileUtils();
732
+ MAX_COMMIT_DIFF_SIZE_BYTES = 3 * 1024 * 1024;
732
733
  GitService = class {
733
734
  constructor(repositoryPath, log2) {
734
735
  __publicField(this, "git");
@@ -1307,6 +1308,97 @@ ${rootContent}`;
1307
1308
  throw new Error(errorMessage);
1308
1309
  }
1309
1310
  }
1311
+ /**
1312
+ * Gets timestamps for parent commits in a single git call.
1313
+ * @param parentShas Array of parent commit SHAs
1314
+ * @returns Array of parent commits with timestamps, or undefined if unavailable
1315
+ */
1316
+ async getParentCommitTimestamps(parentShas) {
1317
+ if (parentShas.length === 0) {
1318
+ return void 0;
1319
+ }
1320
+ try {
1321
+ const output = await this.git.raw([
1322
+ "log",
1323
+ "--format=%H %cI",
1324
+ "--no-walk",
1325
+ ...parentShas
1326
+ ]);
1327
+ const parentCommits = output.trim().split("\n").filter(Boolean).map((line) => {
1328
+ const [sha, ts] = line.split(" ");
1329
+ return { sha: sha ?? "", timestamp: new Date(ts ?? "") };
1330
+ }).filter((p) => p.sha !== "");
1331
+ return parentCommits.length > 0 ? parentCommits : void 0;
1332
+ } catch {
1333
+ this.log("[GitService] Could not get parent commit timestamps", "debug", {
1334
+ parentShas
1335
+ });
1336
+ return void 0;
1337
+ }
1338
+ }
1339
+ /**
1340
+ * Gets local commit data including diff, timestamp, and parent commits.
1341
+ * Used by Tracy extension to send commit data directly without requiring SCM token.
1342
+ * @param commitSha The commit SHA to get data for
1343
+ * @param maxDiffSizeBytes Maximum diff size in bytes (default 3MB). Returns null if exceeded.
1344
+ * @returns Commit data or null if unavailable/too large
1345
+ */
1346
+ async getLocalCommitData(commitSha, maxDiffSizeBytes = MAX_COMMIT_DIFF_SIZE_BYTES) {
1347
+ this.log("[GitService] Getting local commit data", "debug", { commitSha });
1348
+ try {
1349
+ const DIFF_DELIMITER = "---MOBB_DIFF_START---";
1350
+ const output = await this.git.show([
1351
+ commitSha,
1352
+ `--format=%cI%n%P%n${DIFF_DELIMITER}`,
1353
+ "--patch"
1354
+ ]);
1355
+ const delimiterIndex = output.indexOf(DIFF_DELIMITER);
1356
+ if (delimiterIndex === -1) {
1357
+ this.log("[GitService] Could not parse git show output", "warning", {
1358
+ commitSha
1359
+ });
1360
+ return null;
1361
+ }
1362
+ const metadataOutput = output.substring(0, delimiterIndex);
1363
+ const diff = output.substring(delimiterIndex + DIFF_DELIMITER.length + 1);
1364
+ const diffSizeBytes = Buffer.byteLength(diff, "utf8");
1365
+ if (diffSizeBytes > maxDiffSizeBytes) {
1366
+ this.log("[GitService] Commit diff exceeds size limit", "warning", {
1367
+ commitSha,
1368
+ diffSizeBytes,
1369
+ maxDiffSizeBytes
1370
+ });
1371
+ return null;
1372
+ }
1373
+ const metadataLines = metadataOutput.trim().split("\n");
1374
+ if (metadataLines.length < 1 || !metadataLines[0]) {
1375
+ this.log("[GitService] Unexpected metadata format", "warning", {
1376
+ commitSha,
1377
+ metadataLines
1378
+ });
1379
+ return null;
1380
+ }
1381
+ const timestampStr = metadataLines[0];
1382
+ const timestamp = new Date(timestampStr);
1383
+ const parentShas = (metadataLines[1] ?? "").trim().split(/\s+/).filter(Boolean);
1384
+ const parentCommits = await this.getParentCommitTimestamps(parentShas);
1385
+ this.log("[GitService] Local commit data retrieved", "debug", {
1386
+ commitSha,
1387
+ diffSizeBytes,
1388
+ timestamp: timestamp.toISOString(),
1389
+ parentCommitCount: parentCommits?.length ?? 0
1390
+ });
1391
+ return {
1392
+ diff,
1393
+ timestamp,
1394
+ parentCommits
1395
+ };
1396
+ } catch (error) {
1397
+ const errorMessage = `Failed to get local commit data: ${error.message}`;
1398
+ this.log(`[GitService] ${errorMessage}`, "debug", { error, commitSha });
1399
+ return null;
1400
+ }
1401
+ }
1310
1402
  };
1311
1403
  }
1312
1404
  });
@@ -2070,11 +2162,14 @@ var UploadS3BucketInfoDocument = `
2070
2162
  }
2071
2163
  `;
2072
2164
  var AnalyzeCommitForExtensionAiBlameDocument = `
2073
- mutation AnalyzeCommitForExtensionAIBlame($repositoryURL: String!, $commitSha: String!, $organizationId: String!) {
2165
+ mutation AnalyzeCommitForExtensionAIBlame($repositoryURL: String!, $commitSha: String!, $organizationId: String!, $commitDiff: String, $commitTimestamp: Timestamp, $parentCommits: [ParentCommitInput!]) {
2074
2166
  analyzeCommitForAIBlame(
2075
2167
  repositoryURL: $repositoryURL
2076
2168
  commitSha: $commitSha
2077
2169
  organizationId: $organizationId
2170
+ commitDiff: $commitDiff
2171
+ commitTimestamp: $commitTimestamp
2172
+ parentCommits: $parentCommits
2078
2173
  ) {
2079
2174
  __typename
2080
2175
  ... on ProcessAIBlameFinalResult {
@@ -2120,6 +2215,30 @@ var GetAiBlameAttributionPromptDocument = `
2120
2215
  }
2121
2216
  }
2122
2217
  `;
2218
+ var GetPromptSummaryDocument = `
2219
+ query GetPromptSummary($aiBlameAttributionId: String!) {
2220
+ getPromptSummary(aiBlameAttributionId: $aiBlameAttributionId) {
2221
+ __typename
2222
+ ... on PromptSummarySuccess {
2223
+ status
2224
+ summary {
2225
+ goal
2226
+ developersPlan
2227
+ aiImplementationDetails
2228
+ importantInstructionsAndPushbacks
2229
+ frictionScore {
2230
+ score
2231
+ justification
2232
+ }
2233
+ }
2234
+ }
2235
+ ... on PromptSummaryError {
2236
+ status
2237
+ error
2238
+ }
2239
+ }
2240
+ }
2241
+ `;
2123
2242
  var UploadAiBlameInferencesInitDocument = `
2124
2243
  mutation UploadAIBlameInferencesInit($sessions: [AIBlameInferenceInitInput!]!) {
2125
2244
  uploadAIBlameInferencesInit(sessions: $sessions) {
@@ -2447,6 +2566,9 @@ function getSdk(client, withWrapper = defaultWrapper) {
2447
2566
  GetAIBlameAttributionPrompt(variables, requestHeaders, signal) {
2448
2567
  return withWrapper((wrappedRequestHeaders) => client.request({ document: GetAiBlameAttributionPromptDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetAIBlameAttributionPrompt", "query", variables);
2449
2568
  },
2569
+ GetPromptSummary(variables, requestHeaders, signal) {
2570
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetPromptSummaryDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetPromptSummary", "query", variables);
2571
+ },
2450
2572
  UploadAIBlameInferencesInit(variables, requestHeaders, signal) {
2451
2573
  return withWrapper((wrappedRequestHeaders) => client.request({ document: UploadAiBlameInferencesInitDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "UploadAIBlameInferencesInit", "mutation", variables);
2452
2574
  },
@@ -11034,6 +11156,11 @@ var GQLClient = class {
11034
11156
  debug6(`init with ${args}`);
11035
11157
  this._auth = args;
11036
11158
  this._apiUrl = args.apiUrl || API_URL;
11159
+ debug6(
11160
+ "GQLClient constructor: resolved apiUrl=%s (from param: %s)",
11161
+ this._apiUrl,
11162
+ args.apiUrl || "fallback to API_URL constant"
11163
+ );
11037
11164
  this._client = new GraphQLClient(this._apiUrl, {
11038
11165
  headers: args.type === "apiKey" ? { [API_KEY_HEADER_NAME]: args.apiKey || "" } : {
11039
11166
  Authorization: `Bearer ${args.token}`
@@ -11398,6 +11525,9 @@ var GQLClient = class {
11398
11525
  async getAIBlameAttributionPrompt(variables) {
11399
11526
  return await this._clientSdk.GetAIBlameAttributionPrompt(variables);
11400
11527
  }
11528
+ async getAIBlameAttributionPromptSummary(variables) {
11529
+ return await this._clientSdk.GetPromptSummary(variables);
11530
+ }
11401
11531
  };
11402
11532
 
11403
11533
  // src/mcp/services/types.ts
@@ -11464,6 +11594,11 @@ async function getAuthenticatedGQLClient({
11464
11594
  apiUrl,
11465
11595
  webAppUrl
11466
11596
  }) {
11597
+ debug7(
11598
+ "getAuthenticatedGQLClient called with: apiUrl=%s, webAppUrl=%s",
11599
+ apiUrl || "undefined",
11600
+ webAppUrl || "undefined"
11601
+ );
11467
11602
  let gqlClient = new GQLClient({
11468
11603
  apiKey: inputApiKey || configStore.get("apiToken") || "",
11469
11604
  type: "apiKey",
@@ -11487,6 +11622,13 @@ async function handleMobbLogin({
11487
11622
  }) {
11488
11623
  const resolvedWebAppUrl = webAppUrl || WEB_APP_URL;
11489
11624
  const resolvedApiUrl = apiUrl || API_URL;
11625
+ debug7(
11626
+ "handleMobbLogin: resolved URLs - apiUrl=%s (from param: %s), webAppUrl=%s (from param: %s)",
11627
+ resolvedApiUrl,
11628
+ apiUrl || "fallback",
11629
+ resolvedWebAppUrl,
11630
+ webAppUrl || "fallback"
11631
+ );
11490
11632
  const { createSpinner: createSpinner5 } = Spinner({ ci: skipPrompts });
11491
11633
  const isConnected = await inGqlClient.verifyApiConnection();
11492
11634
  if (!isConnected) {
@@ -13801,6 +13943,22 @@ async function sanitizeDataWithCounts(obj) {
13801
13943
  }
13802
13944
 
13803
13945
  // src/args/commands/upload_ai_blame.ts
13946
+ var defaultLogger2 = {
13947
+ info: (msg, data) => {
13948
+ if (data !== void 0) {
13949
+ console.log(msg, data);
13950
+ } else {
13951
+ console.log(msg);
13952
+ }
13953
+ },
13954
+ error: (msg, data) => {
13955
+ if (data !== void 0) {
13956
+ console.error(msg, data);
13957
+ } else {
13958
+ console.error(msg);
13959
+ }
13960
+ }
13961
+ };
13804
13962
  var PromptItemZ = z31.object({
13805
13963
  type: z31.enum(["USER_PROMPT", "AI_RESPONSE", "TOOL_EXECUTION", "AI_THINKING"]),
13806
13964
  attachedFiles: z31.array(
@@ -13916,7 +14074,12 @@ async function uploadAiBlameHandlerFromExtension(args) {
13916
14074
  if (args.sessionId) {
13917
14075
  uploadArgs.sessionId.push(args.sessionId);
13918
14076
  }
13919
- await uploadAiBlameHandler(uploadArgs, false);
14077
+ await uploadAiBlameHandler({
14078
+ args: uploadArgs,
14079
+ exitOnError: false,
14080
+ apiUrl: args.apiUrl,
14081
+ webAppUrl: args.webAppUrl
14082
+ });
13920
14083
  });
13921
14084
  });
13922
14085
  return {
@@ -13926,7 +14089,14 @@ async function uploadAiBlameHandlerFromExtension(args) {
13926
14089
  inferenceUUID
13927
14090
  };
13928
14091
  }
13929
- async function uploadAiBlameHandler(args, exitOnError = true) {
14092
+ async function uploadAiBlameHandler(options) {
14093
+ const {
14094
+ args,
14095
+ exitOnError = true,
14096
+ apiUrl,
14097
+ webAppUrl,
14098
+ logger: logger2 = defaultLogger2
14099
+ } = options;
13930
14100
  const prompts = args.prompt || [];
13931
14101
  const inferences = args.inference || [];
13932
14102
  const models = args.model || [];
@@ -13936,7 +14106,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
13936
14106
  const sessionIds = args.sessionId || args["session-id"] || [];
13937
14107
  if (prompts.length !== inferences.length) {
13938
14108
  const errorMsg = "prompt and inference must have the same number of entries";
13939
- console.error(chalk9.red(errorMsg));
14109
+ logger2.error(chalk9.red(errorMsg));
13940
14110
  if (exitOnError) {
13941
14111
  process.exit(1);
13942
14112
  }
@@ -13955,7 +14125,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
13955
14125
  ]);
13956
14126
  } catch {
13957
14127
  const errorMsg = `File not found for session ${i + 1}`;
13958
- console.error(chalk9.red(errorMsg));
14128
+ logger2.error(chalk9.red(errorMsg));
13959
14129
  if (exitOnError) {
13960
14130
  process.exit(1);
13961
14131
  }
@@ -13974,7 +14144,9 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
13974
14144
  });
13975
14145
  }
13976
14146
  const authenticatedClient = await getAuthenticatedGQLClient({
13977
- isSkipPrompts: true
14147
+ isSkipPrompts: true,
14148
+ apiUrl,
14149
+ webAppUrl
13978
14150
  });
13979
14151
  const initSessions = sessions.map(
13980
14152
  ({ sessionId: _sessionId, ...rest }) => rest
@@ -13985,7 +14157,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
13985
14157
  const uploadSessions = initRes.uploadAIBlameInferencesInit?.uploadSessions ?? [];
13986
14158
  if (uploadSessions.length !== sessions.length) {
13987
14159
  const errorMsg = "Init failed to return expected number of sessions";
13988
- console.error(chalk9.red(errorMsg));
14160
+ logger2.error(chalk9.red(errorMsg));
13989
14161
  if (exitOnError) {
13990
14162
  process.exit(1);
13991
14163
  }
@@ -14027,19 +14199,37 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
14027
14199
  sessionId: s.sessionId
14028
14200
  };
14029
14201
  });
14030
- const finRes = await authenticatedClient.finalizeAIBlameInferencesUploadRaw({
14031
- sessions: finalizeSessions
14032
- });
14033
- const status = finRes?.finalizeAIBlameInferencesUpload?.status;
14034
- if (status !== "OK") {
14035
- const errorMsg = finRes?.finalizeAIBlameInferencesUpload?.error || "unknown error";
14036
- console.error(chalk9.red(errorMsg));
14037
- if (exitOnError) {
14038
- process.exit(1);
14202
+ try {
14203
+ logger2.info(
14204
+ `[UPLOAD] Calling finalizeAIBlameInferencesUploadRaw with ${finalizeSessions.length} sessions`
14205
+ );
14206
+ const finRes = await authenticatedClient.finalizeAIBlameInferencesUploadRaw(
14207
+ {
14208
+ sessions: finalizeSessions
14209
+ }
14210
+ );
14211
+ logger2.info("[UPLOAD] Finalize response:", JSON.stringify(finRes, null, 2));
14212
+ const status = finRes?.finalizeAIBlameInferencesUpload?.status;
14213
+ if (status !== "OK") {
14214
+ const errorMsg = finRes?.finalizeAIBlameInferencesUpload?.error || "unknown error";
14215
+ logger2.error(
14216
+ chalk9.red(
14217
+ `[UPLOAD] Finalize failed with status: ${status}, error: ${errorMsg}`
14218
+ )
14219
+ );
14220
+ if (exitOnError) {
14221
+ process.exit(1);
14222
+ }
14223
+ throw new Error(errorMsg);
14039
14224
  }
14040
- throw new Error(errorMsg);
14225
+ logger2.info(chalk9.green("[UPLOAD] AI Blame uploads finalized successfully"));
14226
+ } catch (error) {
14227
+ logger2.error("[UPLOAD] Finalize threw error:", error);
14228
+ throw error;
14041
14229
  }
14042
- console.log(chalk9.green("AI Blame uploads finalized successfully"));
14230
+ }
14231
+ async function uploadAiBlameCommandHandler(args) {
14232
+ await uploadAiBlameHandler({ args });
14043
14233
  }
14044
14234
 
14045
14235
  // src/features/claude_code/transcript_parser.ts
@@ -22792,7 +22982,7 @@ var parseArgs = async (args) => {
22792
22982
  "Upload AI Blame inference artifacts (prompt + inference) and finalize them."
22793
22983
  ),
22794
22984
  uploadAiBlameBuilder,
22795
- uploadAiBlameHandler
22985
+ uploadAiBlameCommandHandler
22796
22986
  ).command(
22797
22987
  mobbCliCommand.claudeCodeInstallHook,
22798
22988
  chalk12.bold("Install Claude Code hooks for data collection."),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "1.1.27",
3
+ "version": "1.1.29",
4
4
  "description": "Automated secure code remediation tool",
5
5
  "repository": "git+https://github.com/mobb-dev/bugsy.git",
6
6
  "main": "dist/index.mjs",