mobbdev 1.1.32 → 1.1.35
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.
- package/dist/args/commands/upload_ai_blame.d.mts +30 -28
- package/dist/args/commands/upload_ai_blame.mjs +1303 -8
- package/dist/index.mjs +98 -117
- package/package.json +2 -1
|
@@ -4,6 +4,10 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
4
4
|
var __esm = (fn, res) => function __init() {
|
|
5
5
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
6
|
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
7
11
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
8
12
|
|
|
9
13
|
// src/features/analysis/scm/env.ts
|
|
@@ -28,7 +32,7 @@ var init_env = __esm({
|
|
|
28
32
|
});
|
|
29
33
|
|
|
30
34
|
// src/mcp/core/configs.ts
|
|
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;
|
|
35
|
+
var MCP_LOGIN_MAX_WAIT, MCP_LOGIN_CHECK_DELAY, MCP_VUL_REPORT_DIGEST_TIMEOUT_MS, MCP_MAX_FILE_SIZE, MCP_PERIODIC_CHECK_INTERVAL, MCP_DEFAULT_MAX_FILES_TO_SCAN, 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
36
|
var init_configs = __esm({
|
|
33
37
|
"src/mcp/core/configs.ts"() {
|
|
34
38
|
"use strict";
|
|
@@ -38,6 +42,7 @@ var init_configs = __esm({
|
|
|
38
42
|
MCP_VUL_REPORT_DIGEST_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
39
43
|
MCP_MAX_FILE_SIZE = MAX_UPLOAD_FILE_SIZE_MB * 1024 * 1024;
|
|
40
44
|
MCP_PERIODIC_CHECK_INTERVAL = 15 * 60 * 1e3;
|
|
45
|
+
MCP_DEFAULT_MAX_FILES_TO_SCAN = 10;
|
|
41
46
|
MCP_REPORT_ID_EXPIRATION_MS = 2 * 60 * 60 * 1e3;
|
|
42
47
|
MCP_TOOLS_BROWSER_COOLDOWN_MS = 24 * 60 * 60 * 1e3;
|
|
43
48
|
isAutoScan = process.env["AUTO_SCAN"] !== "false";
|
|
@@ -48,16 +53,513 @@ var init_configs = __esm({
|
|
|
48
53
|
});
|
|
49
54
|
|
|
50
55
|
// src/features/analysis/scm/services/ExcludedDirs.ts
|
|
56
|
+
var EXCLUDED_DIRS;
|
|
51
57
|
var init_ExcludedDirs = __esm({
|
|
52
58
|
"src/features/analysis/scm/services/ExcludedDirs.ts"() {
|
|
53
59
|
"use strict";
|
|
60
|
+
EXCLUDED_DIRS = [
|
|
61
|
+
"$RECYCLE.BIN",
|
|
62
|
+
".7z",
|
|
63
|
+
".AppleDouble",
|
|
64
|
+
".DS_Store",
|
|
65
|
+
".Rproj.user",
|
|
66
|
+
".Spotlight-V100",
|
|
67
|
+
".Trashes",
|
|
68
|
+
".adoc",
|
|
69
|
+
".android",
|
|
70
|
+
".angular",
|
|
71
|
+
".atom",
|
|
72
|
+
".aws-sam",
|
|
73
|
+
".azure",
|
|
74
|
+
".azure-pipelines",
|
|
75
|
+
".babelrc",
|
|
76
|
+
".babelrc.js",
|
|
77
|
+
".bmp",
|
|
78
|
+
".brackets.json",
|
|
79
|
+
".browserslistrc",
|
|
80
|
+
".build",
|
|
81
|
+
".bundle",
|
|
82
|
+
".bundle.js",
|
|
83
|
+
".bzr",
|
|
84
|
+
".c8rc",
|
|
85
|
+
".c9",
|
|
86
|
+
".cabal",
|
|
87
|
+
".cabal-sandbox",
|
|
88
|
+
".cache",
|
|
89
|
+
".cache-loader",
|
|
90
|
+
".cargo",
|
|
91
|
+
".chunk.js",
|
|
92
|
+
".circleci",
|
|
93
|
+
".class",
|
|
94
|
+
".classpath",
|
|
95
|
+
".composer",
|
|
96
|
+
".conf",
|
|
97
|
+
".config",
|
|
98
|
+
".cpanm",
|
|
99
|
+
".crt",
|
|
100
|
+
".cvs",
|
|
101
|
+
".d.ts",
|
|
102
|
+
".dart_tool",
|
|
103
|
+
".db",
|
|
104
|
+
".devcontainer",
|
|
105
|
+
".dll",
|
|
106
|
+
".docker",
|
|
107
|
+
".dockerignore",
|
|
108
|
+
".docusaurus",
|
|
109
|
+
".dylib",
|
|
110
|
+
".ebextensions",
|
|
111
|
+
".eclipse",
|
|
112
|
+
".editorconfig",
|
|
113
|
+
".eggs",
|
|
114
|
+
".ember-cli",
|
|
115
|
+
".ensime_cache",
|
|
116
|
+
".env",
|
|
117
|
+
".env.vault",
|
|
118
|
+
".eot",
|
|
119
|
+
".eslintcache",
|
|
120
|
+
".eslintrc",
|
|
121
|
+
".eslintrc.js",
|
|
122
|
+
".exe",
|
|
123
|
+
".expo",
|
|
124
|
+
".expo-shared",
|
|
125
|
+
".flutter-plugins",
|
|
126
|
+
".fseventsd",
|
|
127
|
+
".gem",
|
|
128
|
+
".gif",
|
|
129
|
+
".git",
|
|
130
|
+
".gitattributes",
|
|
131
|
+
".github",
|
|
132
|
+
".gitignore",
|
|
133
|
+
".gitkeep",
|
|
134
|
+
".gitlab",
|
|
135
|
+
".gitlab-ci",
|
|
136
|
+
".gitlab-ci.yml",
|
|
137
|
+
".gitmodules",
|
|
138
|
+
".gradle",
|
|
139
|
+
".gvmrc",
|
|
140
|
+
".gz",
|
|
141
|
+
".hbuilder",
|
|
142
|
+
".helm",
|
|
143
|
+
".hg",
|
|
144
|
+
".hgignore",
|
|
145
|
+
".history",
|
|
146
|
+
".htaccess",
|
|
147
|
+
".husky",
|
|
148
|
+
".ico",
|
|
149
|
+
".idea",
|
|
150
|
+
".ini",
|
|
151
|
+
".ionic",
|
|
152
|
+
".ipynb_checkpoints",
|
|
153
|
+
".ivy2",
|
|
154
|
+
".jekyll-cache",
|
|
155
|
+
".jest-cache",
|
|
156
|
+
".jpeg",
|
|
157
|
+
".jpg",
|
|
158
|
+
".jscsrc",
|
|
159
|
+
".jshintrc",
|
|
160
|
+
".json",
|
|
161
|
+
".k8s",
|
|
162
|
+
".keep",
|
|
163
|
+
".key",
|
|
164
|
+
".kubernetes",
|
|
165
|
+
".lcov",
|
|
166
|
+
".lock",
|
|
167
|
+
".log",
|
|
168
|
+
".logs",
|
|
169
|
+
".m2",
|
|
170
|
+
".mailmap",
|
|
171
|
+
".md",
|
|
172
|
+
".metadata",
|
|
173
|
+
".metals",
|
|
174
|
+
".min.css",
|
|
175
|
+
".min.html",
|
|
176
|
+
".min.js",
|
|
177
|
+
".mvn",
|
|
178
|
+
".mypy_cache",
|
|
179
|
+
".nbproject",
|
|
180
|
+
".netbeans",
|
|
181
|
+
".netlify",
|
|
182
|
+
".next",
|
|
183
|
+
".node-version",
|
|
184
|
+
".node_modules",
|
|
185
|
+
".npmrc",
|
|
186
|
+
".nuget",
|
|
187
|
+
".nunit",
|
|
188
|
+
".nuxt",
|
|
189
|
+
".nvm",
|
|
190
|
+
".nvmrc",
|
|
191
|
+
".nx",
|
|
192
|
+
".nyc_output",
|
|
193
|
+
".nycrc",
|
|
194
|
+
".o",
|
|
195
|
+
".obj",
|
|
196
|
+
".otf",
|
|
197
|
+
".output",
|
|
198
|
+
".p12",
|
|
199
|
+
".parcel-cache",
|
|
200
|
+
".pem",
|
|
201
|
+
".pfx",
|
|
202
|
+
".phpunit.result.cache",
|
|
203
|
+
".png",
|
|
204
|
+
".pnp",
|
|
205
|
+
".pnp.cjs",
|
|
206
|
+
".pnp.js",
|
|
207
|
+
".pnpm",
|
|
208
|
+
".pnpm-state",
|
|
209
|
+
".pnpm-store",
|
|
210
|
+
".pnpmfile.cjs",
|
|
211
|
+
".prettierrc",
|
|
212
|
+
".prettierrc.js",
|
|
213
|
+
".project",
|
|
214
|
+
".project.vim",
|
|
215
|
+
".pub-cache",
|
|
216
|
+
".pulumi",
|
|
217
|
+
".pyc",
|
|
218
|
+
".pyenv",
|
|
219
|
+
".pyo",
|
|
220
|
+
".pytest_cache",
|
|
221
|
+
".python-version",
|
|
222
|
+
".pythonrc",
|
|
223
|
+
".quasar",
|
|
224
|
+
".rar",
|
|
225
|
+
".rbenv-version",
|
|
226
|
+
".react-native",
|
|
227
|
+
".rebar3",
|
|
228
|
+
".rollup.cache",
|
|
229
|
+
".rst",
|
|
230
|
+
".ruby-version",
|
|
231
|
+
".ruff_cache",
|
|
232
|
+
".rush",
|
|
233
|
+
".rvm",
|
|
234
|
+
".rvmrc",
|
|
235
|
+
".sass-cache",
|
|
236
|
+
".sbt",
|
|
237
|
+
".serverless",
|
|
238
|
+
".settings",
|
|
239
|
+
".snap",
|
|
240
|
+
".so",
|
|
241
|
+
".spec.js",
|
|
242
|
+
".spec.jsx",
|
|
243
|
+
".spec.ts",
|
|
244
|
+
".spec.tsx",
|
|
245
|
+
".sql",
|
|
246
|
+
".sqlite",
|
|
247
|
+
".stack-work",
|
|
248
|
+
".storybook",
|
|
249
|
+
".stylelintcache",
|
|
250
|
+
".stylelintrc",
|
|
251
|
+
".stylelintrc.js",
|
|
252
|
+
".sublime-project",
|
|
253
|
+
".sublime-workspace",
|
|
254
|
+
".svelte-kit",
|
|
255
|
+
".svg",
|
|
256
|
+
".svn",
|
|
257
|
+
".swcrc",
|
|
258
|
+
".tar",
|
|
259
|
+
".temp",
|
|
260
|
+
".terraform",
|
|
261
|
+
".test.js",
|
|
262
|
+
".test.jsx",
|
|
263
|
+
".test.ts",
|
|
264
|
+
".test.tsx",
|
|
265
|
+
".tiff",
|
|
266
|
+
".tmp",
|
|
267
|
+
".toml",
|
|
268
|
+
".tox",
|
|
269
|
+
".travis",
|
|
270
|
+
".travis.yml",
|
|
271
|
+
".ttf",
|
|
272
|
+
".turbo",
|
|
273
|
+
".txt",
|
|
274
|
+
".vagrant",
|
|
275
|
+
".venv",
|
|
276
|
+
".vite",
|
|
277
|
+
".vs",
|
|
278
|
+
".vscode",
|
|
279
|
+
".webp",
|
|
280
|
+
".webpack",
|
|
281
|
+
".woff",
|
|
282
|
+
".woff2",
|
|
283
|
+
".wrangler",
|
|
284
|
+
".xml",
|
|
285
|
+
".yaml",
|
|
286
|
+
".yarn",
|
|
287
|
+
".yarnrc",
|
|
288
|
+
".yml",
|
|
289
|
+
".zip",
|
|
290
|
+
"Carthage",
|
|
291
|
+
"Debug",
|
|
292
|
+
"DerivedData",
|
|
293
|
+
"Godeps",
|
|
294
|
+
"Release",
|
|
295
|
+
"TestResults",
|
|
296
|
+
"__pycache__",
|
|
297
|
+
"_build",
|
|
298
|
+
"allure-results",
|
|
299
|
+
"bazel",
|
|
300
|
+
"benchmark",
|
|
301
|
+
"benchmarks",
|
|
302
|
+
"bin",
|
|
303
|
+
"bower_components",
|
|
304
|
+
"buck-out",
|
|
305
|
+
"build",
|
|
306
|
+
"build-cache",
|
|
307
|
+
"build_tools",
|
|
308
|
+
"builds",
|
|
309
|
+
"cache",
|
|
310
|
+
"changelog",
|
|
311
|
+
"changelogs",
|
|
312
|
+
"compiled",
|
|
313
|
+
"copyright",
|
|
314
|
+
"coverage",
|
|
315
|
+
"debug",
|
|
316
|
+
"deploy",
|
|
317
|
+
"deployment",
|
|
318
|
+
"dist",
|
|
319
|
+
"dist-newstyle",
|
|
320
|
+
"dist-packages",
|
|
321
|
+
"docker",
|
|
322
|
+
"dockerfile",
|
|
323
|
+
"egg-info",
|
|
324
|
+
"elm-stuff",
|
|
325
|
+
"fonts",
|
|
326
|
+
"gemfile",
|
|
327
|
+
"generated",
|
|
328
|
+
"go.mod",
|
|
329
|
+
"go.sum",
|
|
330
|
+
"jars",
|
|
331
|
+
"jenkinsfile",
|
|
332
|
+
"jspm_packages",
|
|
333
|
+
"junit-reports",
|
|
334
|
+
"makefile",
|
|
335
|
+
"mock_data",
|
|
336
|
+
"nbproject",
|
|
337
|
+
"node_modules",
|
|
338
|
+
"notice",
|
|
339
|
+
"obj",
|
|
340
|
+
"out",
|
|
341
|
+
"out-tsc",
|
|
342
|
+
"output",
|
|
343
|
+
"packrat",
|
|
344
|
+
"pipfile",
|
|
345
|
+
"pycache",
|
|
346
|
+
"readme",
|
|
347
|
+
"sdist",
|
|
348
|
+
"snapshots",
|
|
349
|
+
"target",
|
|
350
|
+
"debug",
|
|
351
|
+
"temp",
|
|
352
|
+
"tempfiles",
|
|
353
|
+
"test-reports",
|
|
354
|
+
"test-results",
|
|
355
|
+
"test_output",
|
|
356
|
+
"third-party",
|
|
357
|
+
"third_party",
|
|
358
|
+
"thirdparty",
|
|
359
|
+
"tmp",
|
|
360
|
+
"vendor",
|
|
361
|
+
"bundle",
|
|
362
|
+
"venv",
|
|
363
|
+
"virtualenv",
|
|
364
|
+
"webpack-cache",
|
|
365
|
+
"www",
|
|
366
|
+
"wwwroot",
|
|
367
|
+
"xunit"
|
|
368
|
+
];
|
|
54
369
|
}
|
|
55
370
|
});
|
|
56
371
|
|
|
57
372
|
// src/features/analysis/scm/services/FilePatterns.ts
|
|
373
|
+
var EXCLUDED_FILE_PATTERNS, SUPPORTED_EXTENSIONS, IMPORTANT_PROJECT_FILES;
|
|
58
374
|
var init_FilePatterns = __esm({
|
|
59
375
|
"src/features/analysis/scm/services/FilePatterns.ts"() {
|
|
60
376
|
"use strict";
|
|
377
|
+
EXCLUDED_FILE_PATTERNS = [
|
|
378
|
+
// Minified and bundled files (have supported extensions but should be excluded)
|
|
379
|
+
".min.js",
|
|
380
|
+
".min.html",
|
|
381
|
+
".bundle.js",
|
|
382
|
+
".chunk.js",
|
|
383
|
+
// Test files (have supported extensions but should be excluded)
|
|
384
|
+
".test.js",
|
|
385
|
+
".test.ts",
|
|
386
|
+
".test.jsx",
|
|
387
|
+
".test.tsx",
|
|
388
|
+
".spec.js",
|
|
389
|
+
".spec.ts",
|
|
390
|
+
".spec.jsx",
|
|
391
|
+
".spec.tsx",
|
|
392
|
+
// TypeScript declaration files
|
|
393
|
+
".d.ts",
|
|
394
|
+
// Runtime version files that have supported extensions
|
|
395
|
+
".pnpmfile.cjs",
|
|
396
|
+
// Language-specific files with supported extensions that should be excluded
|
|
397
|
+
"go.sum",
|
|
398
|
+
"project.clj",
|
|
399
|
+
"setup.py",
|
|
400
|
+
"setup.cfg",
|
|
401
|
+
"manifest.in",
|
|
402
|
+
// Build tool configuration files (have supported extensions but should be excluded)
|
|
403
|
+
"gulpfile.js",
|
|
404
|
+
"gruntfile.js",
|
|
405
|
+
"webpack.config.js",
|
|
406
|
+
"webpack.config.ts",
|
|
407
|
+
"rollup.config.js",
|
|
408
|
+
"vite.config.js",
|
|
409
|
+
"vite.config.ts",
|
|
410
|
+
"next.config.js",
|
|
411
|
+
"nuxt.config.js",
|
|
412
|
+
"tailwind.config.js",
|
|
413
|
+
"postcss.config.js",
|
|
414
|
+
// Linter and formatter config files (with supported extensions)
|
|
415
|
+
".babelrc.js",
|
|
416
|
+
".eslintrc.js",
|
|
417
|
+
".prettierrc.js",
|
|
418
|
+
".stylelintrc.js",
|
|
419
|
+
// Test framework config files (with supported extensions)
|
|
420
|
+
"jest.config.js",
|
|
421
|
+
"jest.config.ts",
|
|
422
|
+
"vitest.config.js",
|
|
423
|
+
"karma.conf.js",
|
|
424
|
+
"protractor.conf.js",
|
|
425
|
+
"cypress.config.js",
|
|
426
|
+
"playwright.config.js"
|
|
427
|
+
];
|
|
428
|
+
SUPPORTED_EXTENSIONS = [
|
|
429
|
+
// Apex
|
|
430
|
+
".cls",
|
|
431
|
+
// Bash
|
|
432
|
+
".bash",
|
|
433
|
+
".sh",
|
|
434
|
+
// C
|
|
435
|
+
".c",
|
|
436
|
+
".h",
|
|
437
|
+
// Cairo
|
|
438
|
+
".cairo",
|
|
439
|
+
// Circom
|
|
440
|
+
".circom",
|
|
441
|
+
// Clojure
|
|
442
|
+
".clj",
|
|
443
|
+
".cljs",
|
|
444
|
+
".cljc",
|
|
445
|
+
".edn",
|
|
446
|
+
// C++
|
|
447
|
+
".cc",
|
|
448
|
+
".cpp",
|
|
449
|
+
".cxx",
|
|
450
|
+
".c++",
|
|
451
|
+
".pcc",
|
|
452
|
+
".tpp",
|
|
453
|
+
".C",
|
|
454
|
+
".hh",
|
|
455
|
+
".hpp",
|
|
456
|
+
".hxx",
|
|
457
|
+
".inl",
|
|
458
|
+
".ipp",
|
|
459
|
+
// C#
|
|
460
|
+
".cs",
|
|
461
|
+
// Dart
|
|
462
|
+
".dart",
|
|
463
|
+
// Dockerfile
|
|
464
|
+
".dockerfile",
|
|
465
|
+
".Dockerfile",
|
|
466
|
+
"Dockerfile",
|
|
467
|
+
"dockerfile",
|
|
468
|
+
// Elixir
|
|
469
|
+
".ex",
|
|
470
|
+
".exs",
|
|
471
|
+
// Go
|
|
472
|
+
".go",
|
|
473
|
+
// Hack
|
|
474
|
+
".hack",
|
|
475
|
+
".hck",
|
|
476
|
+
".hh",
|
|
477
|
+
// HTML
|
|
478
|
+
".htm",
|
|
479
|
+
".html",
|
|
480
|
+
// Java
|
|
481
|
+
".java",
|
|
482
|
+
// JavaScript
|
|
483
|
+
".cjs",
|
|
484
|
+
".js",
|
|
485
|
+
".jsx",
|
|
486
|
+
".mjs",
|
|
487
|
+
// JSON
|
|
488
|
+
".json",
|
|
489
|
+
".ipynb",
|
|
490
|
+
// Jsonnet
|
|
491
|
+
".jsonnet",
|
|
492
|
+
".libsonnet",
|
|
493
|
+
// Julia
|
|
494
|
+
".jl",
|
|
495
|
+
// Kotlin
|
|
496
|
+
".kt",
|
|
497
|
+
".kts",
|
|
498
|
+
".ktm",
|
|
499
|
+
// Lisp
|
|
500
|
+
".lisp",
|
|
501
|
+
".cl",
|
|
502
|
+
".el",
|
|
503
|
+
// Lua
|
|
504
|
+
".lua",
|
|
505
|
+
// Move (both Sui and Aptos)
|
|
506
|
+
".move",
|
|
507
|
+
// OCaml
|
|
508
|
+
".ml",
|
|
509
|
+
".mli",
|
|
510
|
+
// PHP
|
|
511
|
+
".php",
|
|
512
|
+
".tpl",
|
|
513
|
+
".phtml",
|
|
514
|
+
// PromQL
|
|
515
|
+
".promql",
|
|
516
|
+
// Protocol Buffers
|
|
517
|
+
".proto",
|
|
518
|
+
// Python
|
|
519
|
+
".py",
|
|
520
|
+
".pyi",
|
|
521
|
+
// QL
|
|
522
|
+
".ql",
|
|
523
|
+
".qll",
|
|
524
|
+
// R
|
|
525
|
+
".r",
|
|
526
|
+
".R",
|
|
527
|
+
// Ruby
|
|
528
|
+
".rb",
|
|
529
|
+
// Rust
|
|
530
|
+
".rs",
|
|
531
|
+
// Scala
|
|
532
|
+
".scala",
|
|
533
|
+
// Scheme
|
|
534
|
+
".scm",
|
|
535
|
+
".ss",
|
|
536
|
+
// Solidity
|
|
537
|
+
".sol",
|
|
538
|
+
// Swift
|
|
539
|
+
".swift",
|
|
540
|
+
// Terraform
|
|
541
|
+
".tf",
|
|
542
|
+
".hcl",
|
|
543
|
+
".tfvars",
|
|
544
|
+
// TypeScript
|
|
545
|
+
".ts",
|
|
546
|
+
".tsx",
|
|
547
|
+
// Vue
|
|
548
|
+
".vue",
|
|
549
|
+
// XML
|
|
550
|
+
".xml",
|
|
551
|
+
".plist",
|
|
552
|
+
// YAML
|
|
553
|
+
".yml",
|
|
554
|
+
".yaml"
|
|
555
|
+
];
|
|
556
|
+
IMPORTANT_PROJECT_FILES = [
|
|
557
|
+
"package.json",
|
|
558
|
+
"package-lock.json",
|
|
559
|
+
"pnpm-lock.yaml",
|
|
560
|
+
"yarn.lock",
|
|
561
|
+
"pom.xml"
|
|
562
|
+
];
|
|
61
563
|
}
|
|
62
564
|
});
|
|
63
565
|
|
|
@@ -66,27 +568,795 @@ import fs4 from "fs";
|
|
|
66
568
|
import { promises as fsPromises } from "fs";
|
|
67
569
|
import { isBinary } from "istextorbinary";
|
|
68
570
|
import path4 from "path";
|
|
571
|
+
var FileUtils;
|
|
69
572
|
var init_FileUtils = __esm({
|
|
70
573
|
"src/features/analysis/scm/services/FileUtils.ts"() {
|
|
71
574
|
"use strict";
|
|
72
575
|
init_configs();
|
|
73
576
|
init_ExcludedDirs();
|
|
74
577
|
init_FilePatterns();
|
|
578
|
+
FileUtils = class {
|
|
579
|
+
// Important project configuration files that should always be included
|
|
580
|
+
static isExcludedFileType(filepath) {
|
|
581
|
+
const basename2 = path4.basename(filepath).toLowerCase();
|
|
582
|
+
if (IMPORTANT_PROJECT_FILES.includes(basename2)) {
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
const ext = path4.extname(filepath).toLowerCase();
|
|
586
|
+
const isSupported = SUPPORTED_EXTENSIONS.includes(ext) || SUPPORTED_EXTENSIONS.includes(basename2);
|
|
587
|
+
if (!isSupported) {
|
|
588
|
+
return true;
|
|
589
|
+
}
|
|
590
|
+
if (EXCLUDED_FILE_PATTERNS.some((pattern) => basename2.endsWith(pattern))) {
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
static shouldPackFile(filepath, maxFileSize = MCP_MAX_FILE_SIZE) {
|
|
596
|
+
const absoluteFilepath = path4.resolve(filepath);
|
|
597
|
+
if (this.isExcludedFileType(filepath)) {
|
|
598
|
+
return false;
|
|
599
|
+
}
|
|
600
|
+
try {
|
|
601
|
+
const stats = fs4.statSync(absoluteFilepath);
|
|
602
|
+
if (stats.size > maxFileSize) {
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
const data = fs4.readFileSync(absoluteFilepath);
|
|
606
|
+
if (isBinary(null, data)) {
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
return true;
|
|
610
|
+
} catch {
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
// Process directory at repository root level with special handling for excluded root directories
|
|
615
|
+
static async processRootDirectory(dir, excludedRootDirectories) {
|
|
616
|
+
const visitedDirs = /* @__PURE__ */ new Set();
|
|
617
|
+
return this.processDirectory(
|
|
618
|
+
dir,
|
|
619
|
+
dir,
|
|
620
|
+
excludedRootDirectories,
|
|
621
|
+
0,
|
|
622
|
+
visitedDirs,
|
|
623
|
+
true
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
// Process directories with tracking to prevent circular symlink recursion
|
|
627
|
+
static async processDirectory(dir, rootDir, excludedRootDirectories = [], depth = 0, visitedDirs = /* @__PURE__ */ new Set(), isRootLevel = false) {
|
|
628
|
+
if (depth > 20) {
|
|
629
|
+
return [];
|
|
630
|
+
}
|
|
631
|
+
let canonicalPath;
|
|
632
|
+
try {
|
|
633
|
+
canonicalPath = await fsPromises.realpath(dir);
|
|
634
|
+
if (visitedDirs.has(canonicalPath)) {
|
|
635
|
+
return [];
|
|
636
|
+
}
|
|
637
|
+
visitedDirs.add(canonicalPath);
|
|
638
|
+
} catch {
|
|
639
|
+
return [];
|
|
640
|
+
}
|
|
641
|
+
try {
|
|
642
|
+
await fsPromises.access(dir, fs4.constants.R_OK);
|
|
643
|
+
} catch {
|
|
644
|
+
return [];
|
|
645
|
+
}
|
|
646
|
+
const items = await fsPromises.readdir(dir);
|
|
647
|
+
const results = [];
|
|
648
|
+
const filePromises = [];
|
|
649
|
+
for (const item of items) {
|
|
650
|
+
const fullPath = path4.join(dir, item);
|
|
651
|
+
try {
|
|
652
|
+
await fsPromises.access(fullPath, fs4.constants.R_OK);
|
|
653
|
+
const stat = await fsPromises.stat(fullPath);
|
|
654
|
+
if (stat.isDirectory()) {
|
|
655
|
+
if (isRootLevel && excludedRootDirectories.includes(item)) {
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
filePromises.push(
|
|
659
|
+
this.processDirectory(fullPath, rootDir, [], depth + 1, visitedDirs)
|
|
660
|
+
);
|
|
661
|
+
} else {
|
|
662
|
+
results.push({
|
|
663
|
+
name: item,
|
|
664
|
+
fullPath,
|
|
665
|
+
relativePath: path4.relative(rootDir, fullPath),
|
|
666
|
+
time: stat.mtime.getTime(),
|
|
667
|
+
isFile: true
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
} catch {
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
const subdirResults = await Promise.all(filePromises);
|
|
675
|
+
for (const subdirResult of subdirResults) {
|
|
676
|
+
results.push(...subdirResult);
|
|
677
|
+
}
|
|
678
|
+
return results;
|
|
679
|
+
}
|
|
680
|
+
static async getLastChangedFiles({
|
|
681
|
+
dir,
|
|
682
|
+
maxFileSize,
|
|
683
|
+
maxFiles = MCP_DEFAULT_MAX_FILES_TO_SCAN,
|
|
684
|
+
isAllFilesScan
|
|
685
|
+
}) {
|
|
686
|
+
try {
|
|
687
|
+
const stats = fs4.statSync(dir);
|
|
688
|
+
if (!stats.isDirectory()) return [];
|
|
689
|
+
} catch {
|
|
690
|
+
return [];
|
|
691
|
+
}
|
|
692
|
+
let gitMatcher = null;
|
|
693
|
+
try {
|
|
694
|
+
const { GitService: GitService2 } = await Promise.resolve().then(() => (init_GitService(), GitService_exports));
|
|
695
|
+
const gitService = new GitService2(dir);
|
|
696
|
+
gitMatcher = await gitService.getGitignoreMatcher();
|
|
697
|
+
} catch (e) {
|
|
698
|
+
}
|
|
699
|
+
const allFiles = await this.processRootDirectory(dir, EXCLUDED_DIRS);
|
|
700
|
+
const filteredFiles = allFiles.filter(
|
|
701
|
+
(file) => this.shouldPackFile(file.fullPath, maxFileSize) && !gitMatcher?.ignores(file.relativePath)
|
|
702
|
+
).sort((a, b) => b.time - a.time).map((file) => file.relativePath);
|
|
703
|
+
if (isAllFilesScan) {
|
|
704
|
+
return filteredFiles;
|
|
705
|
+
} else {
|
|
706
|
+
return filteredFiles.slice(0, maxFiles);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
};
|
|
75
710
|
}
|
|
76
711
|
});
|
|
77
712
|
|
|
78
713
|
// src/features/analysis/scm/services/GitService.ts
|
|
714
|
+
var GitService_exports = {};
|
|
715
|
+
__export(GitService_exports, {
|
|
716
|
+
GitService: () => GitService,
|
|
717
|
+
isGitHubUrl: () => isGitHubUrl,
|
|
718
|
+
normalizeGitUrl: () => normalizeGitUrl
|
|
719
|
+
});
|
|
79
720
|
import fs5 from "fs";
|
|
80
721
|
import ignore from "ignore";
|
|
81
722
|
import * as path5 from "path";
|
|
82
723
|
import { simpleGit as simpleGit2 } from "simple-git";
|
|
83
|
-
|
|
724
|
+
function normalizeGitUrl(url) {
|
|
725
|
+
let normalizedUrl = url;
|
|
726
|
+
if (normalizedUrl.endsWith(".git")) {
|
|
727
|
+
normalizedUrl = normalizedUrl.slice(0, -".git".length);
|
|
728
|
+
}
|
|
729
|
+
const sshToHttpsMappings = [
|
|
730
|
+
// GitHub
|
|
731
|
+
{ pattern: "git@github.com:", replacement: "https://github.com/" },
|
|
732
|
+
// GitLab
|
|
733
|
+
{ pattern: "git@gitlab.com:", replacement: "https://gitlab.com/" },
|
|
734
|
+
// Bitbucket
|
|
735
|
+
{ pattern: "git@bitbucket.org:", replacement: "https://bitbucket.org/" },
|
|
736
|
+
// Azure DevOps (SSH format)
|
|
737
|
+
{
|
|
738
|
+
pattern: "git@ssh.dev.azure.com:",
|
|
739
|
+
replacement: "https://dev.azure.com/"
|
|
740
|
+
},
|
|
741
|
+
// Azure DevOps (alternative SSH format)
|
|
742
|
+
{
|
|
743
|
+
pattern: /git@([^:]+):v3\/([^/]+)\/([^/]+)\/([^/]+)/,
|
|
744
|
+
replacement: "https://$1/$2/_git/$4"
|
|
745
|
+
}
|
|
746
|
+
];
|
|
747
|
+
for (const mapping of sshToHttpsMappings) {
|
|
748
|
+
if (typeof mapping.pattern === "string") {
|
|
749
|
+
if (normalizedUrl.startsWith(mapping.pattern)) {
|
|
750
|
+
normalizedUrl = normalizedUrl.replace(
|
|
751
|
+
mapping.pattern,
|
|
752
|
+
mapping.replacement
|
|
753
|
+
);
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
} else {
|
|
757
|
+
const match = normalizedUrl.match(mapping.pattern);
|
|
758
|
+
if (match) {
|
|
759
|
+
normalizedUrl = normalizedUrl.replace(
|
|
760
|
+
mapping.pattern,
|
|
761
|
+
mapping.replacement
|
|
762
|
+
);
|
|
763
|
+
break;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
if (normalizedUrl.startsWith("https://") || normalizedUrl.startsWith("http://")) {
|
|
768
|
+
normalizedUrl = normalizedUrl.replace(/^(https?:\/\/)([^@/]+@)/, "$1");
|
|
769
|
+
}
|
|
770
|
+
return normalizedUrl;
|
|
771
|
+
}
|
|
772
|
+
function isGitHubUrl(normalizedUrl) {
|
|
773
|
+
try {
|
|
774
|
+
const url = new URL(normalizedUrl);
|
|
775
|
+
const host = url.host.toLowerCase();
|
|
776
|
+
return host === "github.com" || host.endsWith(".github.com");
|
|
777
|
+
} catch {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
var MAX_COMMIT_DIFF_SIZE_BYTES, GitService;
|
|
84
782
|
var init_GitService = __esm({
|
|
85
783
|
"src/features/analysis/scm/services/GitService.ts"() {
|
|
86
784
|
"use strict";
|
|
87
785
|
init_configs();
|
|
88
786
|
init_FileUtils();
|
|
89
787
|
MAX_COMMIT_DIFF_SIZE_BYTES = 3 * 1024 * 1024;
|
|
788
|
+
GitService = class {
|
|
789
|
+
constructor(repositoryPath, log) {
|
|
790
|
+
__publicField(this, "git");
|
|
791
|
+
__publicField(this, "repositoryPath");
|
|
792
|
+
__publicField(this, "log");
|
|
793
|
+
const noopLog = (_message, _level, _data) => {
|
|
794
|
+
};
|
|
795
|
+
this.log = log || noopLog;
|
|
796
|
+
this.git = simpleGit2(repositoryPath, { binary: "git" });
|
|
797
|
+
this.repositoryPath = repositoryPath;
|
|
798
|
+
this.log("[GitService] Git service initialized", "debug", {
|
|
799
|
+
repositoryPath
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Checks if the current path is within a git repository
|
|
804
|
+
* @returns Promise<boolean> True if it's a git repository, false otherwise
|
|
805
|
+
*/
|
|
806
|
+
async isGitRepository() {
|
|
807
|
+
try {
|
|
808
|
+
const isRepo = await this.git.checkIsRepo();
|
|
809
|
+
if (!isRepo) {
|
|
810
|
+
this.log("[GitService] Not a git repository", "debug");
|
|
811
|
+
return false;
|
|
812
|
+
}
|
|
813
|
+
await this.git.revparse(["--show-toplevel"]);
|
|
814
|
+
return true;
|
|
815
|
+
} catch (error) {
|
|
816
|
+
this.log("[GitService] Not a git repository", "debug", {
|
|
817
|
+
error: String(error)
|
|
818
|
+
});
|
|
819
|
+
return false;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Validates that the path is a valid git repository
|
|
824
|
+
*/
|
|
825
|
+
async validateRepository() {
|
|
826
|
+
this.log("[GitService] Validating git repository", "debug");
|
|
827
|
+
try {
|
|
828
|
+
const isRepo = await this.git.checkIsRepo();
|
|
829
|
+
if (!isRepo) {
|
|
830
|
+
const error = "[GitService] Path is not a valid git repository";
|
|
831
|
+
this.log(error, "error");
|
|
832
|
+
return { isValid: false, error };
|
|
833
|
+
}
|
|
834
|
+
this.log("[GitService] Git repository validation successful", "debug");
|
|
835
|
+
return { isValid: true };
|
|
836
|
+
} catch (error) {
|
|
837
|
+
const errorMessage = `Failed to verify git repository: ${error.message}`;
|
|
838
|
+
this.log(`[GitService] ${errorMessage}`, "error", { error });
|
|
839
|
+
return { isValid: false, error: errorMessage };
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Gets the current git status and returns changed files
|
|
844
|
+
*/
|
|
845
|
+
async getChangedFiles() {
|
|
846
|
+
this.log("[GitService] Getting git status", "debug");
|
|
847
|
+
try {
|
|
848
|
+
const status = await this.git.status();
|
|
849
|
+
const gitRoot = await this.git.revparse(["--show-toplevel"]);
|
|
850
|
+
const relativePathFromGitRoot = path5.relative(
|
|
851
|
+
gitRoot,
|
|
852
|
+
this.repositoryPath
|
|
853
|
+
);
|
|
854
|
+
const deletedFiles = status.files.filter((file) => file.index === "D" || file.working_dir === "D").map((file) => file.path);
|
|
855
|
+
const files = status.files.filter((file) => {
|
|
856
|
+
return !(file.index === "D" || file.working_dir === "D");
|
|
857
|
+
}).map((file) => {
|
|
858
|
+
const gitRelativePath = file.path;
|
|
859
|
+
if (relativePathFromGitRoot === "") {
|
|
860
|
+
return gitRelativePath;
|
|
861
|
+
}
|
|
862
|
+
if (gitRelativePath.startsWith(relativePathFromGitRoot + "/")) {
|
|
863
|
+
return gitRelativePath.substring(relativePathFromGitRoot.length + 1);
|
|
864
|
+
}
|
|
865
|
+
const safeInput = path5.basename(
|
|
866
|
+
String(gitRelativePath || "").replace("\0", "").replace(/^(\.\.(\/|\\$))+/, "")
|
|
867
|
+
);
|
|
868
|
+
return path5.relative(
|
|
869
|
+
this.repositoryPath,
|
|
870
|
+
path5.join(gitRoot, safeInput)
|
|
871
|
+
);
|
|
872
|
+
});
|
|
873
|
+
this.log("[GitService] Git status retrieved", "info", {
|
|
874
|
+
fileCount: files.length,
|
|
875
|
+
files: files.slice(0, 10),
|
|
876
|
+
// Log first 10 files to avoid spam
|
|
877
|
+
deletedFileCount: deletedFiles.length,
|
|
878
|
+
deletedFiles: deletedFiles.slice(0, 10),
|
|
879
|
+
gitRoot,
|
|
880
|
+
workingDir: this.repositoryPath,
|
|
881
|
+
relativePathFromGitRoot
|
|
882
|
+
});
|
|
883
|
+
return { files, deletedFiles, status };
|
|
884
|
+
} catch (error) {
|
|
885
|
+
const errorMessage = `Failed to get git status: ${error.message}`;
|
|
886
|
+
this.log(`[GitService] ${errorMessage}`, "error", { error });
|
|
887
|
+
throw new Error(errorMessage);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Gets git repository information including remote URL, current commit hash, and branch name
|
|
892
|
+
*/
|
|
893
|
+
async getGitInfo() {
|
|
894
|
+
this.log("[GitService] Getting git repository information", "debug");
|
|
895
|
+
try {
|
|
896
|
+
const [repoUrl, hash, reference] = await Promise.all([
|
|
897
|
+
this.git.getConfig("remote.origin.url"),
|
|
898
|
+
this.git.revparse(["HEAD"]),
|
|
899
|
+
this.git.revparse(["--abbrev-ref", "HEAD"])
|
|
900
|
+
]);
|
|
901
|
+
const normalizedRepoUrl = repoUrl.value ? normalizeGitUrl(repoUrl.value) : "";
|
|
902
|
+
this.log("[GitService] Git repository information retrieved", "debug", {
|
|
903
|
+
repoUrl: normalizedRepoUrl,
|
|
904
|
+
hash,
|
|
905
|
+
reference
|
|
906
|
+
});
|
|
907
|
+
return {
|
|
908
|
+
repoUrl: normalizedRepoUrl,
|
|
909
|
+
hash,
|
|
910
|
+
reference
|
|
911
|
+
};
|
|
912
|
+
} catch (error) {
|
|
913
|
+
const errorMessage = `Failed to get git repository information: ${error.message}`;
|
|
914
|
+
this.log(`[GitService] ${errorMessage}`, "error", { error });
|
|
915
|
+
throw new Error(errorMessage);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Validates if a branch name is valid according to git's rules
|
|
920
|
+
*/
|
|
921
|
+
async isValidBranchName(branchName) {
|
|
922
|
+
this.log("[GitService] Validating branch name", "debug", { branchName });
|
|
923
|
+
try {
|
|
924
|
+
const result = await this.git.raw([
|
|
925
|
+
"check-ref-format",
|
|
926
|
+
"--branch",
|
|
927
|
+
branchName
|
|
928
|
+
]);
|
|
929
|
+
const isValid = Boolean(result);
|
|
930
|
+
this.log("[GitService] Branch name validation result", "debug", {
|
|
931
|
+
branchName,
|
|
932
|
+
isValid
|
|
933
|
+
});
|
|
934
|
+
return isValid;
|
|
935
|
+
} catch (error) {
|
|
936
|
+
this.log("[GitService] Branch name validation failed", "debug", {
|
|
937
|
+
branchName,
|
|
938
|
+
error
|
|
939
|
+
});
|
|
940
|
+
return false;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Gets the current branch name
|
|
945
|
+
*/
|
|
946
|
+
async getCurrentBranch() {
|
|
947
|
+
this.log("[GitService] Getting current branch name", "debug");
|
|
948
|
+
try {
|
|
949
|
+
const branch = await this.git.revparse(["--abbrev-ref", "HEAD"]);
|
|
950
|
+
this.log("[GitService] Current branch retrieved", "debug", { branch });
|
|
951
|
+
return branch;
|
|
952
|
+
} catch (error) {
|
|
953
|
+
const errorMessage = `Failed to get current branch: ${error.message}`;
|
|
954
|
+
this.log(`[GitService] ${errorMessage}`, "error", { error });
|
|
955
|
+
throw new Error(errorMessage);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Gets the current commit hash
|
|
960
|
+
*/
|
|
961
|
+
async getCurrentCommitHash() {
|
|
962
|
+
this.log("[GitService] Getting current commit hash", "debug");
|
|
963
|
+
try {
|
|
964
|
+
const hash = await this.git.revparse(["HEAD"]);
|
|
965
|
+
this.log("[GitService] Current commit hash retrieved", "debug", { hash });
|
|
966
|
+
return hash;
|
|
967
|
+
} catch (error) {
|
|
968
|
+
const errorMessage = `Failed to get current commit hash: ${error.message}`;
|
|
969
|
+
this.log(`[GitService] ${errorMessage}`, "error", { error });
|
|
970
|
+
throw new Error(errorMessage);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Gets both the current commit hash and current branch name
|
|
975
|
+
*/
|
|
976
|
+
async getCurrentCommitAndBranch() {
|
|
977
|
+
this.log("[GitService] Getting current commit hash and branch", "debug");
|
|
978
|
+
try {
|
|
979
|
+
const [hash, branch] = await Promise.all([
|
|
980
|
+
this.git.revparse(["HEAD"]),
|
|
981
|
+
this.git.revparse(["--abbrev-ref", "HEAD"])
|
|
982
|
+
]);
|
|
983
|
+
this.log(
|
|
984
|
+
"[GitService] Current commit hash and branch retrieved",
|
|
985
|
+
"debug",
|
|
986
|
+
{
|
|
987
|
+
hash,
|
|
988
|
+
branch
|
|
989
|
+
}
|
|
990
|
+
);
|
|
991
|
+
return { hash, branch };
|
|
992
|
+
} catch (error) {
|
|
993
|
+
const errorMessage = `Failed to get current commit hash and branch: ${error.message}`;
|
|
994
|
+
this.log(`[GitService] ${errorMessage}`, "error", { error });
|
|
995
|
+
return { hash: "", branch: "" };
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* Gets the remote repository URL (origin)
|
|
1000
|
+
*/
|
|
1001
|
+
async getRemoteUrl() {
|
|
1002
|
+
this.log("[GitService] Getting remote repository URL", "debug");
|
|
1003
|
+
try {
|
|
1004
|
+
const remoteUrl = await this.git.getConfig("remote.origin.url");
|
|
1005
|
+
const url = remoteUrl.value || "";
|
|
1006
|
+
const normalizedUrl = normalizeGitUrl(url);
|
|
1007
|
+
this.log("[GitService] Remote repository URL retrieved", "debug", {
|
|
1008
|
+
url: normalizedUrl
|
|
1009
|
+
});
|
|
1010
|
+
return normalizedUrl;
|
|
1011
|
+
} catch (error) {
|
|
1012
|
+
const errorMessage = `Failed to get remote repository URL: ${error.message}`;
|
|
1013
|
+
this.log(`[GitService] ${errorMessage}`, "error", { error });
|
|
1014
|
+
throw new Error(errorMessage);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Gets the maxFiles most recently changed files, starting with current changes and then from commit history
|
|
1019
|
+
*/
|
|
1020
|
+
async getRecentlyChangedFiles({
|
|
1021
|
+
maxFiles = MCP_DEFAULT_MAX_FILES_TO_SCAN
|
|
1022
|
+
}) {
|
|
1023
|
+
this.log(
|
|
1024
|
+
`[GitService] Getting the ${maxFiles} most recently changed files, starting with current changes`,
|
|
1025
|
+
"debug"
|
|
1026
|
+
);
|
|
1027
|
+
try {
|
|
1028
|
+
const currentChanges = await this.getChangedFiles();
|
|
1029
|
+
const gitRoot = await this.git.revparse(["--show-toplevel"]);
|
|
1030
|
+
const relativePathFromGitRoot = path5.relative(
|
|
1031
|
+
gitRoot,
|
|
1032
|
+
this.repositoryPath
|
|
1033
|
+
);
|
|
1034
|
+
const fileSet = /* @__PURE__ */ new Set();
|
|
1035
|
+
let commitsProcessed = 0;
|
|
1036
|
+
const consideredFiles = [];
|
|
1037
|
+
for (const file of currentChanges.files) {
|
|
1038
|
+
if (fileSet.size >= maxFiles) {
|
|
1039
|
+
break;
|
|
1040
|
+
}
|
|
1041
|
+
const fullPath = path5.join(this.repositoryPath, file);
|
|
1042
|
+
if (await FileUtils.shouldPackFile(fullPath) && !file.startsWith("..")) {
|
|
1043
|
+
fileSet.add(file);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
this.log(
|
|
1047
|
+
`[GitService] Added ${fileSet.size} files from current changes`,
|
|
1048
|
+
"debug",
|
|
1049
|
+
{
|
|
1050
|
+
filesFromCurrentChanges: fileSet.size,
|
|
1051
|
+
currentChangesTotal: currentChanges.files.length
|
|
1052
|
+
}
|
|
1053
|
+
);
|
|
1054
|
+
const logResult = await this.git.log({
|
|
1055
|
+
maxCount: maxFiles * 5,
|
|
1056
|
+
// 5 times the max files to scan to ensure we find enough files
|
|
1057
|
+
format: {
|
|
1058
|
+
hash: "%H",
|
|
1059
|
+
date: "%ai",
|
|
1060
|
+
message: "%s",
|
|
1061
|
+
//the field name author_name can't follow the naming convention as we are using the git log command
|
|
1062
|
+
author_name: "%an"
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
for (const commit of logResult.all) {
|
|
1066
|
+
if (fileSet.size >= maxFiles) {
|
|
1067
|
+
break;
|
|
1068
|
+
}
|
|
1069
|
+
commitsProcessed++;
|
|
1070
|
+
try {
|
|
1071
|
+
const filesOutput = await this.git.show([
|
|
1072
|
+
"--name-only",
|
|
1073
|
+
"--pretty=format:",
|
|
1074
|
+
commit.hash
|
|
1075
|
+
]);
|
|
1076
|
+
const commitFiles = filesOutput.split("\n").filter((file) => file.trim() !== "");
|
|
1077
|
+
for (const file of commitFiles) {
|
|
1078
|
+
if (fileSet.size >= maxFiles) {
|
|
1079
|
+
break;
|
|
1080
|
+
}
|
|
1081
|
+
const gitRelativePath = file.trim();
|
|
1082
|
+
let adjustedPath;
|
|
1083
|
+
if (relativePathFromGitRoot === "") {
|
|
1084
|
+
adjustedPath = gitRelativePath;
|
|
1085
|
+
} else if (gitRelativePath.startsWith(relativePathFromGitRoot + "/")) {
|
|
1086
|
+
adjustedPath = gitRelativePath.substring(
|
|
1087
|
+
relativePathFromGitRoot.length + 1
|
|
1088
|
+
);
|
|
1089
|
+
} else {
|
|
1090
|
+
adjustedPath = path5.relative(
|
|
1091
|
+
this.repositoryPath,
|
|
1092
|
+
path5.join(gitRoot, gitRelativePath)
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
consideredFiles.push(adjustedPath);
|
|
1096
|
+
if (!fileSet.has(adjustedPath) && await FileUtils.shouldPackFile(
|
|
1097
|
+
path5.join(gitRoot, gitRelativePath)
|
|
1098
|
+
) && !adjustedPath.startsWith("..")) {
|
|
1099
|
+
fileSet.add(adjustedPath);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
} catch (showError) {
|
|
1103
|
+
this.log(
|
|
1104
|
+
`[GitService] Could not get files for commit ${commit.hash}`,
|
|
1105
|
+
"debug",
|
|
1106
|
+
{
|
|
1107
|
+
error: showError
|
|
1108
|
+
}
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
const files = Array.from(fileSet);
|
|
1113
|
+
if (consideredFiles.length > 0) {
|
|
1114
|
+
this.log(
|
|
1115
|
+
`[GitService] Considered ${consideredFiles.length} files during recent file search`,
|
|
1116
|
+
"debug",
|
|
1117
|
+
{ consideredFiles }
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
this.log("[GitService] Recently changed files retrieved", "info", {
|
|
1121
|
+
fileCount: files.length,
|
|
1122
|
+
commitsProcessed,
|
|
1123
|
+
totalCommitsAvailable: logResult.all.length,
|
|
1124
|
+
files: files.slice(0, maxFiles),
|
|
1125
|
+
// Log the files (should be all of them since we limit to maxFiles)
|
|
1126
|
+
gitRoot,
|
|
1127
|
+
workingDir: this.repositoryPath,
|
|
1128
|
+
relativePathFromGitRoot
|
|
1129
|
+
});
|
|
1130
|
+
return {
|
|
1131
|
+
files,
|
|
1132
|
+
commitCount: commitsProcessed
|
|
1133
|
+
};
|
|
1134
|
+
} catch (error) {
|
|
1135
|
+
const errorMessage = `Failed to get recently changed files: ${error.message}`;
|
|
1136
|
+
this.log(`[GitService] ${errorMessage}`, "error", { error });
|
|
1137
|
+
throw new Error(errorMessage);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Fetches the contents of the .gitignore file from the repository
|
|
1142
|
+
* @returns The contents of the .gitignore file as a string, or null if the file doesn't exist
|
|
1143
|
+
*/
|
|
1144
|
+
async getGitignoreContent() {
|
|
1145
|
+
this.log("[GitService] Getting .gitignore contents", "debug");
|
|
1146
|
+
try {
|
|
1147
|
+
let combinedContent = "";
|
|
1148
|
+
const localGitignorePath = path5.join(this.repositoryPath, ".gitignore");
|
|
1149
|
+
if (fs5.existsSync(localGitignorePath)) {
|
|
1150
|
+
const localContent = fs5.readFileSync(localGitignorePath, "utf8");
|
|
1151
|
+
combinedContent += `${localContent}
|
|
1152
|
+
`;
|
|
1153
|
+
}
|
|
1154
|
+
try {
|
|
1155
|
+
const gitRoot = await this.git.revparse(["--show-toplevel"]);
|
|
1156
|
+
const rootGitignorePath = path5.join(gitRoot, ".gitignore");
|
|
1157
|
+
if (fs5.existsSync(rootGitignorePath)) {
|
|
1158
|
+
const rootContent = fs5.readFileSync(rootGitignorePath, "utf8");
|
|
1159
|
+
if (rootContent.trim() !== combinedContent.trim()) {
|
|
1160
|
+
combinedContent += `
|
|
1161
|
+
${rootContent}`;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
} catch (rootErr) {
|
|
1165
|
+
this.log(
|
|
1166
|
+
"[GitService] Unable to resolve git root while reading .gitignore",
|
|
1167
|
+
"debug",
|
|
1168
|
+
{ error: rootErr }
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
if (combinedContent.trim() === "") {
|
|
1172
|
+
this.log("[GitService] .gitignore file not found", "debug");
|
|
1173
|
+
return null;
|
|
1174
|
+
}
|
|
1175
|
+
this.log(
|
|
1176
|
+
"[GitService] .gitignore contents retrieved successfully",
|
|
1177
|
+
"debug"
|
|
1178
|
+
);
|
|
1179
|
+
return combinedContent.trimEnd();
|
|
1180
|
+
} catch (error) {
|
|
1181
|
+
const errorMessage = `Failed to get .gitignore contents: ${error.message}`;
|
|
1182
|
+
this.log(`[GitService] ${errorMessage}`, "error", { error });
|
|
1183
|
+
return null;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
async getGitignoreMatcher() {
|
|
1187
|
+
const content = await this.getGitignoreContent();
|
|
1188
|
+
if (!content) return null;
|
|
1189
|
+
return ignore().add(content);
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Gets the git repository root directory path
|
|
1193
|
+
* @returns Absolute path to the git repository root
|
|
1194
|
+
*/
|
|
1195
|
+
async getGitRoot() {
|
|
1196
|
+
this.log("[GitService] Getting git repository root", "debug");
|
|
1197
|
+
try {
|
|
1198
|
+
const gitRoot = await this.git.revparse(["--show-toplevel"]);
|
|
1199
|
+
this.log("[GitService] Git root retrieved", "debug", { gitRoot });
|
|
1200
|
+
return gitRoot;
|
|
1201
|
+
} catch (error) {
|
|
1202
|
+
const errorMessage = `Failed to get git repository root: ${error.message}`;
|
|
1203
|
+
this.log(`[GitService] ${errorMessage}`, "error", { error });
|
|
1204
|
+
throw new Error(errorMessage);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
/**
|
|
1208
|
+
* Ensures that a specific entry exists in the .gitignore file
|
|
1209
|
+
* Creates .gitignore if it doesn't exist, adds the entry if not present
|
|
1210
|
+
* @param entry The entry to add to .gitignore (e.g., '.mobb', 'node_modules')
|
|
1211
|
+
* @returns True if entry was added, false if it already existed
|
|
1212
|
+
*/
|
|
1213
|
+
async ensureGitignoreEntry(entry) {
|
|
1214
|
+
this.log("[GitService] Ensuring .gitignore entry", "debug", { entry });
|
|
1215
|
+
try {
|
|
1216
|
+
const gitRoot = await this.getGitRoot();
|
|
1217
|
+
const gitignorePath = path5.join(gitRoot, ".gitignore");
|
|
1218
|
+
let gitignoreContent = "";
|
|
1219
|
+
if (fs5.existsSync(gitignorePath)) {
|
|
1220
|
+
gitignoreContent = fs5.readFileSync(gitignorePath, "utf8");
|
|
1221
|
+
this.log("[GitService] .gitignore file exists", "debug");
|
|
1222
|
+
} else {
|
|
1223
|
+
this.log("[GitService] Creating .gitignore file", "info", {
|
|
1224
|
+
gitignorePath
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
if (gitignoreContent.includes(entry)) {
|
|
1228
|
+
this.log("[GitService] Entry already exists in .gitignore", "debug", {
|
|
1229
|
+
entry
|
|
1230
|
+
});
|
|
1231
|
+
return false;
|
|
1232
|
+
}
|
|
1233
|
+
this.log("[GitService] Adding entry to .gitignore", "info", { entry });
|
|
1234
|
+
const newLine = gitignoreContent.endsWith("\n") || gitignoreContent === "" ? "" : "\n";
|
|
1235
|
+
const updatedContent = `${gitignoreContent}${newLine}${entry}
|
|
1236
|
+
`;
|
|
1237
|
+
fs5.writeFileSync(gitignorePath, updatedContent, "utf8");
|
|
1238
|
+
this.log("[GitService] .gitignore updated successfully", "debug", {
|
|
1239
|
+
entry
|
|
1240
|
+
});
|
|
1241
|
+
return true;
|
|
1242
|
+
} catch (error) {
|
|
1243
|
+
const errorMessage = `Failed to ensure .gitignore entry: ${error.message}`;
|
|
1244
|
+
this.log(`[GitService] ${errorMessage}`, "error", { error, entry });
|
|
1245
|
+
throw new Error(errorMessage);
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
/**
|
|
1249
|
+
* Checks if the .gitignore file exists in the repository root
|
|
1250
|
+
* @returns True if .gitignore exists, false otherwise
|
|
1251
|
+
*/
|
|
1252
|
+
async gitignoreExists() {
|
|
1253
|
+
this.log("[GitService] Checking if .gitignore exists", "debug");
|
|
1254
|
+
try {
|
|
1255
|
+
const gitRoot = await this.getGitRoot();
|
|
1256
|
+
const gitignorePath = path5.join(gitRoot, ".gitignore");
|
|
1257
|
+
const exists = fs5.existsSync(gitignorePath);
|
|
1258
|
+
this.log("[GitService] .gitignore existence check complete", "debug", {
|
|
1259
|
+
exists
|
|
1260
|
+
});
|
|
1261
|
+
return exists;
|
|
1262
|
+
} catch (error) {
|
|
1263
|
+
const errorMessage = `Failed to check .gitignore existence: ${error.message}`;
|
|
1264
|
+
this.log(`[GitService] ${errorMessage}`, "error", { error });
|
|
1265
|
+
throw new Error(errorMessage);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Gets timestamps for parent commits in a single git call.
|
|
1270
|
+
* @param parentShas Array of parent commit SHAs
|
|
1271
|
+
* @returns Array of parent commits with timestamps, or undefined if unavailable
|
|
1272
|
+
*/
|
|
1273
|
+
async getParentCommitTimestamps(parentShas) {
|
|
1274
|
+
if (parentShas.length === 0) {
|
|
1275
|
+
return void 0;
|
|
1276
|
+
}
|
|
1277
|
+
try {
|
|
1278
|
+
const output = await this.git.raw([
|
|
1279
|
+
"log",
|
|
1280
|
+
"--format=%H %cI",
|
|
1281
|
+
"--no-walk",
|
|
1282
|
+
...parentShas
|
|
1283
|
+
]);
|
|
1284
|
+
const parentCommits = output.trim().split("\n").filter(Boolean).map((line) => {
|
|
1285
|
+
const [sha, ts] = line.split(" ");
|
|
1286
|
+
return { sha: sha ?? "", timestamp: new Date(ts ?? "") };
|
|
1287
|
+
}).filter((p) => p.sha !== "");
|
|
1288
|
+
return parentCommits.length > 0 ? parentCommits : void 0;
|
|
1289
|
+
} catch {
|
|
1290
|
+
this.log("[GitService] Could not get parent commit timestamps", "debug", {
|
|
1291
|
+
parentShas
|
|
1292
|
+
});
|
|
1293
|
+
return void 0;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
/**
|
|
1297
|
+
* Gets local commit data including diff, timestamp, and parent commits.
|
|
1298
|
+
* Used by Tracy extension to send commit data directly without requiring SCM token.
|
|
1299
|
+
* @param commitSha The commit SHA to get data for
|
|
1300
|
+
* @param maxDiffSizeBytes Maximum diff size in bytes (default 3MB). Returns null if exceeded.
|
|
1301
|
+
* @returns Commit data or null if unavailable/too large
|
|
1302
|
+
*/
|
|
1303
|
+
async getLocalCommitData(commitSha, maxDiffSizeBytes = MAX_COMMIT_DIFF_SIZE_BYTES) {
|
|
1304
|
+
this.log("[GitService] Getting local commit data", "debug", { commitSha });
|
|
1305
|
+
try {
|
|
1306
|
+
const DIFF_DELIMITER = "---MOBB_DIFF_START---";
|
|
1307
|
+
const output = await this.git.show([
|
|
1308
|
+
commitSha,
|
|
1309
|
+
`--format=%cI%n%P%n${DIFF_DELIMITER}`,
|
|
1310
|
+
"--patch"
|
|
1311
|
+
]);
|
|
1312
|
+
const delimiterIndex = output.indexOf(DIFF_DELIMITER);
|
|
1313
|
+
if (delimiterIndex === -1) {
|
|
1314
|
+
this.log("[GitService] Could not parse git show output", "warning", {
|
|
1315
|
+
commitSha
|
|
1316
|
+
});
|
|
1317
|
+
return null;
|
|
1318
|
+
}
|
|
1319
|
+
const metadataOutput = output.substring(0, delimiterIndex);
|
|
1320
|
+
const diff = output.substring(delimiterIndex + DIFF_DELIMITER.length + 1);
|
|
1321
|
+
const diffSizeBytes = Buffer.byteLength(diff, "utf8");
|
|
1322
|
+
if (diffSizeBytes > maxDiffSizeBytes) {
|
|
1323
|
+
this.log("[GitService] Commit diff exceeds size limit", "warning", {
|
|
1324
|
+
commitSha,
|
|
1325
|
+
diffSizeBytes,
|
|
1326
|
+
maxDiffSizeBytes
|
|
1327
|
+
});
|
|
1328
|
+
return null;
|
|
1329
|
+
}
|
|
1330
|
+
const metadataLines = metadataOutput.trim().split("\n");
|
|
1331
|
+
if (metadataLines.length < 1 || !metadataLines[0]) {
|
|
1332
|
+
this.log("[GitService] Unexpected metadata format", "warning", {
|
|
1333
|
+
commitSha,
|
|
1334
|
+
metadataLines
|
|
1335
|
+
});
|
|
1336
|
+
return null;
|
|
1337
|
+
}
|
|
1338
|
+
const timestampStr = metadataLines[0];
|
|
1339
|
+
const timestamp = new Date(timestampStr);
|
|
1340
|
+
const parentShas = (metadataLines[1] ?? "").trim().split(/\s+/).filter(Boolean);
|
|
1341
|
+
const parentCommits = await this.getParentCommitTimestamps(parentShas);
|
|
1342
|
+
this.log("[GitService] Local commit data retrieved", "debug", {
|
|
1343
|
+
commitSha,
|
|
1344
|
+
diffSizeBytes,
|
|
1345
|
+
timestamp: timestamp.toISOString(),
|
|
1346
|
+
parentCommitCount: parentCommits?.length ?? 0
|
|
1347
|
+
});
|
|
1348
|
+
return {
|
|
1349
|
+
diff,
|
|
1350
|
+
timestamp,
|
|
1351
|
+
parentCommits
|
|
1352
|
+
};
|
|
1353
|
+
} catch (error) {
|
|
1354
|
+
const errorMessage = `Failed to get local commit data: ${error.message}`;
|
|
1355
|
+
this.log(`[GitService] ${errorMessage}`, "debug", { error, commitSha });
|
|
1356
|
+
return null;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
};
|
|
90
1360
|
}
|
|
91
1361
|
});
|
|
92
1362
|
|
|
@@ -895,9 +2165,10 @@ var GetPromptSummaryDocument = `
|
|
|
895
2165
|
goal
|
|
896
2166
|
developersPlan
|
|
897
2167
|
aiImplementationDetails
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
2168
|
+
developersPushbacks
|
|
2169
|
+
importantInstructionsAndDecisions
|
|
2170
|
+
backAndForthLevel {
|
|
2171
|
+
level
|
|
901
2172
|
justification
|
|
902
2173
|
}
|
|
903
2174
|
}
|
|
@@ -4644,6 +5915,7 @@ var REPORT_DEFAULT_FILE_NAME = "report.json";
|
|
|
4644
5915
|
init_env();
|
|
4645
5916
|
|
|
4646
5917
|
// src/features/analysis/scm/github/GithubSCMLib.ts
|
|
5918
|
+
import pLimit from "p-limit";
|
|
4647
5919
|
import { z as z22 } from "zod";
|
|
4648
5920
|
|
|
4649
5921
|
// src/features/analysis/scm/github/github.ts
|
|
@@ -4656,6 +5928,9 @@ import sodium from "libsodium-wrappers";
|
|
|
4656
5928
|
import { Octokit } from "octokit";
|
|
4657
5929
|
import { fetch as fetch2, ProxyAgent } from "undici";
|
|
4658
5930
|
|
|
5931
|
+
// src/features/analysis/scm/github/GithubSCMLib.ts
|
|
5932
|
+
var GITHUB_COMMIT_FETCH_CONCURRENCY = parseInt(process.env["GITHUB_COMMIT_CONCURRENCY"] || "10", 10) || 10;
|
|
5933
|
+
|
|
4659
5934
|
// src/features/analysis/scm/gitlab/gitlab.ts
|
|
4660
5935
|
import querystring3 from "querystring";
|
|
4661
5936
|
import {
|
|
@@ -5355,6 +6630,9 @@ async function handleMobbLogin({
|
|
|
5355
6630
|
return newGqlClient;
|
|
5356
6631
|
}
|
|
5357
6632
|
|
|
6633
|
+
// src/args/commands/upload_ai_blame.ts
|
|
6634
|
+
init_GitService();
|
|
6635
|
+
|
|
5358
6636
|
// src/features/analysis/upload-file.ts
|
|
5359
6637
|
import Debug7 from "debug";
|
|
5360
6638
|
import fetch3, { File, fileFrom, FormData } from "node-fetch";
|
|
@@ -5675,6 +6953,19 @@ var PromptItemZ = z26.object({
|
|
|
5675
6953
|
}).optional()
|
|
5676
6954
|
});
|
|
5677
6955
|
var PromptItemArrayZ = z26.array(PromptItemZ);
|
|
6956
|
+
async function getRepositoryUrl() {
|
|
6957
|
+
try {
|
|
6958
|
+
const gitService = new GitService(process.cwd());
|
|
6959
|
+
const isRepo = await gitService.isGitRepository();
|
|
6960
|
+
if (!isRepo) {
|
|
6961
|
+
return null;
|
|
6962
|
+
}
|
|
6963
|
+
const remoteUrl = await gitService.getRemoteUrl();
|
|
6964
|
+
return isGitHubUrl(remoteUrl) ? remoteUrl : null;
|
|
6965
|
+
} catch {
|
|
6966
|
+
return null;
|
|
6967
|
+
}
|
|
6968
|
+
}
|
|
5678
6969
|
function getSystemInfo() {
|
|
5679
6970
|
let userName;
|
|
5680
6971
|
try {
|
|
@@ -5771,7 +7062,8 @@ async function uploadAiBlameHandlerFromExtension(args) {
|
|
|
5771
7062
|
args: uploadArgs,
|
|
5772
7063
|
exitOnError: false,
|
|
5773
7064
|
apiUrl: args.apiUrl,
|
|
5774
|
-
webAppUrl: args.webAppUrl
|
|
7065
|
+
webAppUrl: args.webAppUrl,
|
|
7066
|
+
repositoryUrl: args.repositoryUrl
|
|
5775
7067
|
});
|
|
5776
7068
|
});
|
|
5777
7069
|
});
|
|
@@ -5807,6 +7099,7 @@ async function uploadAiBlameHandler(options) {
|
|
|
5807
7099
|
}
|
|
5808
7100
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
5809
7101
|
const { computerName, userName } = getSystemInfo();
|
|
7102
|
+
const repositoryUrl = options.repositoryUrl !== void 0 ? options.repositoryUrl : await getRepositoryUrl();
|
|
5810
7103
|
const sessions = [];
|
|
5811
7104
|
for (let i = 0; i < prompts.length; i++) {
|
|
5812
7105
|
const promptPath = String(prompts[i]);
|
|
@@ -5833,7 +7126,8 @@ async function uploadAiBlameHandler(options) {
|
|
|
5833
7126
|
blameType: blameTypes[i] || "CHAT" /* Chat */,
|
|
5834
7127
|
computerName,
|
|
5835
7128
|
userName,
|
|
5836
|
-
sessionId: sessionIds[i]
|
|
7129
|
+
sessionId: sessionIds[i],
|
|
7130
|
+
repositoryUrl
|
|
5837
7131
|
});
|
|
5838
7132
|
}
|
|
5839
7133
|
const authenticatedClient = await getAuthenticatedGQLClient({
|
|
@@ -5889,7 +7183,8 @@ async function uploadAiBlameHandler(options) {
|
|
|
5889
7183
|
blameType: s.blameType,
|
|
5890
7184
|
computerName: s.computerName,
|
|
5891
7185
|
userName: s.userName,
|
|
5892
|
-
sessionId: s.sessionId
|
|
7186
|
+
sessionId: s.sessionId,
|
|
7187
|
+
repositoryUrl: s.repositoryUrl
|
|
5893
7188
|
};
|
|
5894
7189
|
});
|
|
5895
7190
|
try {
|