mobbdev 1.4.48 → 1.4.49
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.mjs +4 -1
- package/dist/index.mjs +467 -336
- package/package.json +7 -3
package/dist/index.mjs
CHANGED
|
@@ -5227,7 +5227,7 @@ async function getAdoSdk(params) {
|
|
|
5227
5227
|
const url = new URL(repoUrl);
|
|
5228
5228
|
const origin = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
|
|
5229
5229
|
const params2 = `path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
|
|
5230
|
-
const
|
|
5230
|
+
const path38 = [
|
|
5231
5231
|
prefixPath,
|
|
5232
5232
|
owner,
|
|
5233
5233
|
projectName,
|
|
@@ -5238,7 +5238,7 @@ async function getAdoSdk(params) {
|
|
|
5238
5238
|
"items",
|
|
5239
5239
|
"items"
|
|
5240
5240
|
].filter(Boolean).join("/");
|
|
5241
|
-
return new URL(`${
|
|
5241
|
+
return new URL(`${path38}?${params2}`, origin).toString();
|
|
5242
5242
|
},
|
|
5243
5243
|
async getAdoBranchList({ repoUrl }) {
|
|
5244
5244
|
try {
|
|
@@ -5327,8 +5327,8 @@ async function getAdoSdk(params) {
|
|
|
5327
5327
|
const changeType = entry.changeType;
|
|
5328
5328
|
return changeType !== 16 && entry.item?.path;
|
|
5329
5329
|
}).map((entry) => {
|
|
5330
|
-
const
|
|
5331
|
-
return
|
|
5330
|
+
const path38 = entry.item.path;
|
|
5331
|
+
return path38.startsWith("/") ? path38.slice(1) : path38;
|
|
5332
5332
|
});
|
|
5333
5333
|
},
|
|
5334
5334
|
async searchAdoPullRequests({
|
|
@@ -6265,7 +6265,6 @@ var AdoSCMLib = class extends SCMLib {
|
|
|
6265
6265
|
// src/features/analysis/scm/bitbucket/bitbucket.ts
|
|
6266
6266
|
import querystring2 from "querystring";
|
|
6267
6267
|
import * as bitbucketPkgNode from "bitbucket";
|
|
6268
|
-
import bitbucketPkg from "bitbucket";
|
|
6269
6268
|
import Debug2 from "debug";
|
|
6270
6269
|
import { z as z16 } from "zod";
|
|
6271
6270
|
|
|
@@ -6278,6 +6277,7 @@ var BitbucketAuthResultZ = z15.object({
|
|
|
6278
6277
|
});
|
|
6279
6278
|
|
|
6280
6279
|
// src/features/analysis/scm/bitbucket/bitbucket.ts
|
|
6280
|
+
var bitbucketPkg = bitbucketPkgNode.default;
|
|
6281
6281
|
var debug3 = Debug2("scm:bitbucket");
|
|
6282
6282
|
function isBitbucketPermissionDenied(e) {
|
|
6283
6283
|
const status = e?.status;
|
|
@@ -10417,6 +10417,7 @@ __export(utils_exports, {
|
|
|
10417
10417
|
getDirName: () => getDirName,
|
|
10418
10418
|
getModuleRootDir: () => getModuleRootDir,
|
|
10419
10419
|
getTopLevelDirName: () => getTopLevelDirName,
|
|
10420
|
+
isStandaloneBinary: () => isStandaloneBinary,
|
|
10420
10421
|
keypress: () => keypress,
|
|
10421
10422
|
packageJson: () => packageJson,
|
|
10422
10423
|
sleep: () => sleep
|
|
@@ -10427,6 +10428,10 @@ import fs3 from "fs";
|
|
|
10427
10428
|
import path3 from "path";
|
|
10428
10429
|
import { fileURLToPath } from "url";
|
|
10429
10430
|
function getModuleRootDir() {
|
|
10431
|
+
const seaRoot = process.env["MOBBDEV_MODULE_ROOT"];
|
|
10432
|
+
if (seaRoot) {
|
|
10433
|
+
return seaRoot;
|
|
10434
|
+
}
|
|
10430
10435
|
let manifestDir = getDirName();
|
|
10431
10436
|
for (let i = 0; i < 10; i++) {
|
|
10432
10437
|
const manifestPath = path3.join(manifestDir, "package.json");
|
|
@@ -10523,6 +10528,16 @@ function Spinner({ ci = false } = {}) {
|
|
|
10523
10528
|
};
|
|
10524
10529
|
}
|
|
10525
10530
|
|
|
10531
|
+
// src/utils/standalone_binary.ts
|
|
10532
|
+
function isStandaloneBinary() {
|
|
10533
|
+
try {
|
|
10534
|
+
const getBuiltin = process.getBuiltinModule;
|
|
10535
|
+
return Boolean(getBuiltin?.("node:sea")?.isSea());
|
|
10536
|
+
} catch {
|
|
10537
|
+
return false;
|
|
10538
|
+
}
|
|
10539
|
+
}
|
|
10540
|
+
|
|
10526
10541
|
// src/utils/check_node_version.ts
|
|
10527
10542
|
import fs4 from "fs";
|
|
10528
10543
|
import path4 from "path";
|
|
@@ -11306,7 +11321,7 @@ var ScanContext = {
|
|
|
11306
11321
|
};
|
|
11307
11322
|
|
|
11308
11323
|
// src/args/commands/analyze.ts
|
|
11309
|
-
import
|
|
11324
|
+
import fs13 from "fs";
|
|
11310
11325
|
import chalk10 from "chalk";
|
|
11311
11326
|
|
|
11312
11327
|
// src/commands/index.ts
|
|
@@ -11314,11 +11329,11 @@ import chalk8 from "chalk";
|
|
|
11314
11329
|
import chalkAnimation from "chalk-animation";
|
|
11315
11330
|
|
|
11316
11331
|
// src/features/analysis/index.ts
|
|
11317
|
-
import
|
|
11332
|
+
import fs11 from "fs";
|
|
11318
11333
|
import fsPromises3 from "fs/promises";
|
|
11319
|
-
import
|
|
11334
|
+
import path11 from "path";
|
|
11320
11335
|
import { env as env2 } from "process";
|
|
11321
|
-
import { pipeline } from "stream/promises";
|
|
11336
|
+
import { pipeline as pipeline2 } from "stream/promises";
|
|
11322
11337
|
import chalk7 from "chalk";
|
|
11323
11338
|
import Debug22 from "debug";
|
|
11324
11339
|
import extract from "extract-zip";
|
|
@@ -14019,7 +14034,7 @@ async function postIssueComment(params) {
|
|
|
14019
14034
|
fpDescription
|
|
14020
14035
|
} = params;
|
|
14021
14036
|
const {
|
|
14022
|
-
path:
|
|
14037
|
+
path: path38,
|
|
14023
14038
|
startLine,
|
|
14024
14039
|
vulnerabilityReportIssue: {
|
|
14025
14040
|
vulnerabilityReportIssueTags,
|
|
@@ -14034,7 +14049,7 @@ async function postIssueComment(params) {
|
|
|
14034
14049
|
Refresh the page in order to see the changes.`,
|
|
14035
14050
|
pull_number: pullRequest,
|
|
14036
14051
|
commit_id: commitSha,
|
|
14037
|
-
path:
|
|
14052
|
+
path: path38,
|
|
14038
14053
|
line: startLine
|
|
14039
14054
|
});
|
|
14040
14055
|
const commentId = commentRes.data.id;
|
|
@@ -14068,7 +14083,7 @@ async function postFixComment(params) {
|
|
|
14068
14083
|
scanner
|
|
14069
14084
|
} = params;
|
|
14070
14085
|
const {
|
|
14071
|
-
path:
|
|
14086
|
+
path: path38,
|
|
14072
14087
|
startLine,
|
|
14073
14088
|
vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
|
|
14074
14089
|
vulnerabilityReportIssueId
|
|
@@ -14086,7 +14101,7 @@ async function postFixComment(params) {
|
|
|
14086
14101
|
Refresh the page in order to see the changes.`,
|
|
14087
14102
|
pull_number: pullRequest,
|
|
14088
14103
|
commit_id: commitSha,
|
|
14089
|
-
path:
|
|
14104
|
+
path: path38,
|
|
14090
14105
|
line: startLine
|
|
14091
14106
|
});
|
|
14092
14107
|
const commentId = commentRes.data.id;
|
|
@@ -14636,7 +14651,7 @@ function createFork({ args, processPath, name }, options) {
|
|
|
14636
14651
|
}
|
|
14637
14652
|
function createSpawn({ args, processPath, name, cwd, env: env3 }, options) {
|
|
14638
14653
|
const child = cp.spawn(processPath, args, {
|
|
14639
|
-
stdio: ["inherit", "pipe", "pipe"
|
|
14654
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
14640
14655
|
env: { ...process2.env, ...env3 },
|
|
14641
14656
|
cwd
|
|
14642
14657
|
});
|
|
@@ -14694,11 +14709,16 @@ if (typeof __filename !== "undefined") {
|
|
|
14694
14709
|
}
|
|
14695
14710
|
var costumeRequire = createRequire(moduleUrl);
|
|
14696
14711
|
var getCheckmarxPath = () => {
|
|
14697
|
-
const
|
|
14698
|
-
const cxFileName =
|
|
14712
|
+
const os20 = type();
|
|
14713
|
+
const cxFileName = os20 === "Windows_NT" ? "cx.exe" : "cx";
|
|
14699
14714
|
try {
|
|
14700
14715
|
return costumeRequire.resolve(`.bin/${cxFileName}`);
|
|
14701
14716
|
} catch (e) {
|
|
14717
|
+
if (isStandaloneBinary()) {
|
|
14718
|
+
throw new CliError(
|
|
14719
|
+
"The Checkmarx scanner is not available in the standalone mobbdev binary yet. Use the npm package instead: npx mobbdev@latest"
|
|
14720
|
+
);
|
|
14721
|
+
}
|
|
14702
14722
|
throw new CliError(cxOperatingSystemSupportMessage);
|
|
14703
14723
|
}
|
|
14704
14724
|
};
|
|
@@ -14805,7 +14825,13 @@ async function validateCheckamxCredentials() {
|
|
|
14805
14825
|
}
|
|
14806
14826
|
|
|
14807
14827
|
// src/features/analysis/scanners/snyk.ts
|
|
14828
|
+
import crypto2 from "crypto";
|
|
14829
|
+
import fs10 from "fs";
|
|
14808
14830
|
import { createRequire as createRequire2 } from "module";
|
|
14831
|
+
import os4 from "os";
|
|
14832
|
+
import path10 from "path";
|
|
14833
|
+
import { Readable } from "stream";
|
|
14834
|
+
import { pipeline } from "stream/promises";
|
|
14809
14835
|
import chalk6 from "chalk";
|
|
14810
14836
|
import Debug21 from "debug";
|
|
14811
14837
|
import { createSpinner as createSpinner3 } from "nanospinner";
|
|
@@ -14830,31 +14856,130 @@ if (typeof __filename !== "undefined") {
|
|
|
14830
14856
|
}
|
|
14831
14857
|
}
|
|
14832
14858
|
var costumeRequire2 = createRequire2(moduleUrl2);
|
|
14833
|
-
var SNYK_PATH = costumeRequire2.resolve("snyk/bin/snyk");
|
|
14834
14859
|
var SNYK_ARTICLE_URL = "https://docs.snyk.io/scan-using-snyk/snyk-code/configure-snyk-code#enable-snyk-code";
|
|
14835
|
-
|
|
14860
|
+
var SNYK_VERSION = packageJson.dependencies.snyk;
|
|
14861
|
+
var SNYK_DOWNLOAD_BASE = process.env["MOBB_SNYK_DOWNLOAD_BASE"] || "https://downloads.snyk.io/cli";
|
|
14862
|
+
var SNYK_BINARY_ASSETS = {
|
|
14863
|
+
"darwin-x64": "snyk-macos",
|
|
14864
|
+
"darwin-arm64": "snyk-macos-arm64",
|
|
14865
|
+
"linux-x64": "snyk-linux",
|
|
14866
|
+
"linux-arm64": "snyk-linux-arm64",
|
|
14867
|
+
"win32-x64": "snyk-win.exe"
|
|
14868
|
+
};
|
|
14869
|
+
async function downloadSnykBinary(asset, dest) {
|
|
14870
|
+
if (!/^\d+\.\d+\.\d+$/.test(SNYK_VERSION)) {
|
|
14871
|
+
throw new CliError(
|
|
14872
|
+
`Cannot build the Snyk CLI download URL: expected an exact version in the "snyk" dependency of package.json, got "${SNYK_VERSION}".`
|
|
14873
|
+
);
|
|
14874
|
+
}
|
|
14875
|
+
const url = `${SNYK_DOWNLOAD_BASE}/v${SNYK_VERSION}/${asset}`;
|
|
14876
|
+
const tmpPath = `${dest}.download.${process.pid}`;
|
|
14877
|
+
const spinner = createSpinner3(
|
|
14878
|
+
`\u2B07\uFE0F Downloading Snyk CLI v${SNYK_VERSION}`
|
|
14879
|
+
).start();
|
|
14880
|
+
try {
|
|
14881
|
+
fs10.mkdirSync(path10.dirname(dest), { recursive: true });
|
|
14882
|
+
const timeout = () => AbortSignal.timeout(10 * 60 * 1e3);
|
|
14883
|
+
const [binRes, shaRes] = await Promise.all([
|
|
14884
|
+
fetchWithProxy(url, { signal: timeout() }),
|
|
14885
|
+
fetchWithProxy(`${url}.sha256`, { signal: timeout() })
|
|
14886
|
+
]);
|
|
14887
|
+
if (!binRes.ok || !shaRes.ok || !binRes.body) {
|
|
14888
|
+
throw new CliError(
|
|
14889
|
+
`Snyk CLI download failed with HTTP ${binRes.ok ? shaRes.status : binRes.status}: ${url}
|
|
14890
|
+
If downloads.snyk.io is unreachable from this network, point MOBB_SNYK_DOWNLOAD_BASE at a mirror.`
|
|
14891
|
+
);
|
|
14892
|
+
}
|
|
14893
|
+
const hash = crypto2.createHash("sha256");
|
|
14894
|
+
await pipeline(
|
|
14895
|
+
Readable.fromWeb(binRes.body),
|
|
14896
|
+
async function* (source) {
|
|
14897
|
+
for await (const chunk of source) {
|
|
14898
|
+
hash.update(chunk);
|
|
14899
|
+
yield chunk;
|
|
14900
|
+
}
|
|
14901
|
+
},
|
|
14902
|
+
fs10.createWriteStream(tmpPath, { mode: 493 })
|
|
14903
|
+
);
|
|
14904
|
+
const expected = (await shaRes.text()).trim().split(/\s+/)[0];
|
|
14905
|
+
const actual = hash.digest("hex");
|
|
14906
|
+
if (actual !== expected) {
|
|
14907
|
+
throw new CliError(
|
|
14908
|
+
`Snyk CLI download checksum mismatch (expected ${expected}, got ${actual}) \u2014 refusing to install it. Please try again.`
|
|
14909
|
+
);
|
|
14910
|
+
}
|
|
14911
|
+
fs10.renameSync(tmpPath, dest);
|
|
14912
|
+
spinner.success({ text: `\u2B07\uFE0F Snyk CLI v${SNYK_VERSION} installed` });
|
|
14913
|
+
} catch (e) {
|
|
14914
|
+
fs10.rmSync(tmpPath, { force: true });
|
|
14915
|
+
spinner.error({ text: "\u2B07\uFE0F Snyk CLI download failed" });
|
|
14916
|
+
throw e;
|
|
14917
|
+
}
|
|
14918
|
+
}
|
|
14919
|
+
async function getSnykExecutable() {
|
|
14920
|
+
try {
|
|
14921
|
+
return {
|
|
14922
|
+
processPath: costumeRequire2.resolve("snyk/bin/snyk"),
|
|
14923
|
+
isNodeScript: true
|
|
14924
|
+
};
|
|
14925
|
+
} catch (e) {
|
|
14926
|
+
if (!isStandaloneBinary()) {
|
|
14927
|
+
throw e;
|
|
14928
|
+
}
|
|
14929
|
+
debug21("running as standalone binary, using standalone snyk binary");
|
|
14930
|
+
}
|
|
14931
|
+
const asset = SNYK_BINARY_ASSETS[`${process.platform}-${process.arch}`];
|
|
14932
|
+
if (!asset) {
|
|
14933
|
+
throw new CliError(
|
|
14934
|
+
`Snyk scan is not supported on this platform (${process.platform}-${process.arch}) when running the standalone mobbdev binary. Use the npm package instead: npx mobbdev@latest`
|
|
14935
|
+
);
|
|
14936
|
+
}
|
|
14937
|
+
const dest = path10.join(
|
|
14938
|
+
os4.homedir(),
|
|
14939
|
+
".mobb",
|
|
14940
|
+
"tools",
|
|
14941
|
+
"snyk",
|
|
14942
|
+
`v${SNYK_VERSION}`,
|
|
14943
|
+
asset
|
|
14944
|
+
);
|
|
14945
|
+
if (!fs10.existsSync(dest)) {
|
|
14946
|
+
await downloadSnykBinary(asset, dest);
|
|
14947
|
+
}
|
|
14948
|
+
return { processPath: dest, isNodeScript: false };
|
|
14949
|
+
}
|
|
14836
14950
|
async function forkSnyk(args, { display }) {
|
|
14837
14951
|
debug21("fork snyk with args %o %s", args, display);
|
|
14838
|
-
|
|
14952
|
+
const { processPath, isNodeScript } = await getSnykExecutable();
|
|
14953
|
+
const create = isNodeScript ? createFork : createSpawn;
|
|
14954
|
+
return create({ args, processPath, name: "snyk" }, { display });
|
|
14839
14955
|
}
|
|
14840
14956
|
async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
14841
14957
|
debug21("get snyk report start %s %s", reportPath, repoRoot);
|
|
14842
14958
|
const config2 = await forkSnyk(["config"], { display: false });
|
|
14843
14959
|
const { message: configMessage } = config2;
|
|
14844
|
-
|
|
14845
|
-
|
|
14846
|
-
|
|
14960
|
+
const hasStoredCredential = configMessage.includes("api: ") || configMessage.includes("INTERNAL_OAUTH_TOKEN_STORAGE");
|
|
14961
|
+
if (!hasStoredCredential) {
|
|
14962
|
+
const hasSnykToken = !!process.env["SNYK_TOKEN"];
|
|
14963
|
+
if (skipPrompts) {
|
|
14964
|
+
if (!hasSnykToken) {
|
|
14965
|
+
throw new CliError(
|
|
14966
|
+
"Snyk authentication is required. In CI / non-interactive mode, set the SNYK_TOKEN environment variable (Snyk API token). Interactive `snyk auth` (browser) is not available with --ci."
|
|
14967
|
+
);
|
|
14968
|
+
}
|
|
14969
|
+
debug21("skipPrompts: using SNYK_TOKEN for snyk authentication");
|
|
14970
|
+
} else {
|
|
14971
|
+
const snykLoginSpinner = createSpinner3().start();
|
|
14847
14972
|
snykLoginSpinner.update({
|
|
14848
14973
|
text: "\u{1F513} Login to Snyk is required, press any key to continue"
|
|
14849
14974
|
});
|
|
14850
14975
|
await keypress();
|
|
14976
|
+
snykLoginSpinner.update({
|
|
14977
|
+
text: "\u{1F513} Waiting for Snyk login to complete"
|
|
14978
|
+
});
|
|
14979
|
+
debug21("no token in the config %s", config2);
|
|
14980
|
+
await forkSnyk(["auth"], { display: true });
|
|
14981
|
+
snykLoginSpinner.success({ text: "\u{1F513} Login to Snyk Successful" });
|
|
14851
14982
|
}
|
|
14852
|
-
snykLoginSpinner.update({
|
|
14853
|
-
text: "\u{1F513} Waiting for Snyk login to complete"
|
|
14854
|
-
});
|
|
14855
|
-
debug21("no token in the config %s", config2);
|
|
14856
|
-
await forkSnyk(["auth"], { display: true });
|
|
14857
|
-
snykLoginSpinner.success({ text: "\u{1F513} Login to Snyk Successful" });
|
|
14858
14983
|
}
|
|
14859
14984
|
const snykSpinner = createSpinner3("\u{1F50D} Scanning your repo with Snyk ").start();
|
|
14860
14985
|
const { message: scanOutput } = await forkSnyk(
|
|
@@ -14916,7 +15041,7 @@ async function downloadRepo({
|
|
|
14916
15041
|
const { createSpinner: createSpinner5 } = Spinner2({ ci });
|
|
14917
15042
|
const repoSpinner = createSpinner5("\u{1F4BE} Downloading Repo").start();
|
|
14918
15043
|
debug22("download repo %s %s %s", repoUrl, dirname);
|
|
14919
|
-
const zipFilePath =
|
|
15044
|
+
const zipFilePath = path11.join(dirname, "repo.zip");
|
|
14920
15045
|
debug22("download URL: %s auth headers: %o", downloadUrl, authHeaders);
|
|
14921
15046
|
const response = await fetch4(downloadUrl, {
|
|
14922
15047
|
method: "GET",
|
|
@@ -14929,19 +15054,19 @@ async function downloadRepo({
|
|
|
14929
15054
|
repoSpinner.error({ text: "\u{1F4BE} Repo download failed" });
|
|
14930
15055
|
throw new Error(`Can't access ${chalk7.bold(repoUrl)}`);
|
|
14931
15056
|
}
|
|
14932
|
-
const fileWriterStream =
|
|
15057
|
+
const fileWriterStream = fs11.createWriteStream(zipFilePath);
|
|
14933
15058
|
if (!response.body) {
|
|
14934
15059
|
throw new Error("Response body is empty");
|
|
14935
15060
|
}
|
|
14936
|
-
await
|
|
15061
|
+
await pipeline2(response.body, fileWriterStream);
|
|
14937
15062
|
await extract(zipFilePath, { dir: dirname });
|
|
14938
|
-
const repoRoot =
|
|
15063
|
+
const repoRoot = fs11.readdirSync(dirname, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name)[0];
|
|
14939
15064
|
if (!repoRoot) {
|
|
14940
15065
|
throw new Error("Repo root not found");
|
|
14941
15066
|
}
|
|
14942
15067
|
debug22("repo root %s", repoRoot);
|
|
14943
15068
|
repoSpinner.success({ text: "\u{1F4BE} Repo downloaded successfully" });
|
|
14944
|
-
return
|
|
15069
|
+
return path11.join(dirname, repoRoot);
|
|
14945
15070
|
}
|
|
14946
15071
|
var getReportUrl = ({
|
|
14947
15072
|
organizationId,
|
|
@@ -15049,7 +15174,7 @@ async function getReport(params, { skipPrompts }) {
|
|
|
15049
15174
|
authHeaders: scm.getAuthHeaders(),
|
|
15050
15175
|
downloadUrl
|
|
15051
15176
|
});
|
|
15052
|
-
const reportPath =
|
|
15177
|
+
const reportPath = path11.join(dirname, REPORT_DEFAULT_FILE_NAME);
|
|
15053
15178
|
switch (scanner) {
|
|
15054
15179
|
case "snyk":
|
|
15055
15180
|
await getSnykReport(reportPath, repositoryRoot, { skipPrompts });
|
|
@@ -15461,7 +15586,7 @@ async function _zipAndUploadRepo({
|
|
|
15461
15586
|
const zippingSpinner = createSpinner4("\u{1F4E6} Zipping repo").start();
|
|
15462
15587
|
let zipBuffer;
|
|
15463
15588
|
let gitInfo2 = { success: false };
|
|
15464
|
-
if (srcFileStatus.isFile() &&
|
|
15589
|
+
if (srcFileStatus.isFile() && path11.extname(srcPath).toLowerCase() === ".fpr") {
|
|
15465
15590
|
zipBuffer = await repackFpr(srcPath);
|
|
15466
15591
|
} else {
|
|
15467
15592
|
gitInfo2 = await getGitInfo(srcPath);
|
|
@@ -15634,17 +15759,17 @@ async function waitForAnaysisAndReviewPr({
|
|
|
15634
15759
|
}
|
|
15635
15760
|
|
|
15636
15761
|
// src/commands/scan_skill_input.ts
|
|
15637
|
-
import
|
|
15638
|
-
import
|
|
15762
|
+
import fs12 from "fs";
|
|
15763
|
+
import path12 from "path";
|
|
15639
15764
|
import AdmZip2 from "adm-zip";
|
|
15640
15765
|
var LOCAL_SKILL_ZIP_DATA_URL_PREFIX = "data:application/zip;base64,";
|
|
15641
15766
|
var MAX_LOCAL_SKILL_ARCHIVE_BYTES = 2 * 1024 * 1024;
|
|
15642
15767
|
async function resolveSkillScanInput(skillInput) {
|
|
15643
|
-
const resolvedPath =
|
|
15644
|
-
if (!
|
|
15768
|
+
const resolvedPath = path12.resolve(skillInput);
|
|
15769
|
+
if (!fs12.existsSync(resolvedPath)) {
|
|
15645
15770
|
return skillInput;
|
|
15646
15771
|
}
|
|
15647
|
-
const stat5 =
|
|
15772
|
+
const stat5 = fs12.statSync(resolvedPath);
|
|
15648
15773
|
if (!stat5.isDirectory()) {
|
|
15649
15774
|
throw new CliError(
|
|
15650
15775
|
"Local skill input must be a directory containing SKILL.md"
|
|
@@ -15654,18 +15779,18 @@ async function resolveSkillScanInput(skillInput) {
|
|
|
15654
15779
|
}
|
|
15655
15780
|
function packageLocalSkillDirectory(directoryPath) {
|
|
15656
15781
|
const zip = new AdmZip2();
|
|
15657
|
-
const rootPath =
|
|
15782
|
+
const rootPath = path12.resolve(directoryPath);
|
|
15658
15783
|
const filePaths = listDirectoryFiles(rootPath);
|
|
15659
15784
|
let hasSkillMd = false;
|
|
15660
15785
|
for (const relativePath of filePaths) {
|
|
15661
|
-
const fullPath =
|
|
15662
|
-
const normalizedFullPath =
|
|
15663
|
-
if (normalizedFullPath !== rootPath && !normalizedFullPath.startsWith(rootPath +
|
|
15786
|
+
const fullPath = path12.join(rootPath, relativePath);
|
|
15787
|
+
const normalizedFullPath = path12.resolve(fullPath);
|
|
15788
|
+
if (normalizedFullPath !== rootPath && !normalizedFullPath.startsWith(rootPath + path12.sep)) {
|
|
15664
15789
|
continue;
|
|
15665
15790
|
}
|
|
15666
|
-
const fileContent =
|
|
15791
|
+
const fileContent = fs12.readFileSync(normalizedFullPath);
|
|
15667
15792
|
zip.addFile(relativePath, fileContent);
|
|
15668
|
-
if (
|
|
15793
|
+
if (path12.basename(relativePath).toLowerCase() === "skill.md") {
|
|
15669
15794
|
hasSkillMd = true;
|
|
15670
15795
|
}
|
|
15671
15796
|
}
|
|
@@ -15683,17 +15808,17 @@ function packageLocalSkillDirectory(directoryPath) {
|
|
|
15683
15808
|
function listDirectoryFiles(rootPath) {
|
|
15684
15809
|
const files = [];
|
|
15685
15810
|
function walk(relativeDir) {
|
|
15686
|
-
const absoluteDir =
|
|
15687
|
-
const entries =
|
|
15811
|
+
const absoluteDir = path12.join(rootPath, relativeDir);
|
|
15812
|
+
const entries = fs12.readdirSync(absoluteDir, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
|
|
15688
15813
|
for (const entry of entries) {
|
|
15689
|
-
const safeEntryName =
|
|
15814
|
+
const safeEntryName = path12.basename(entry.name).replace(/\0/g, "");
|
|
15690
15815
|
if (!safeEntryName) {
|
|
15691
15816
|
continue;
|
|
15692
15817
|
}
|
|
15693
|
-
const relativePath = relativeDir ?
|
|
15694
|
-
const absolutePath =
|
|
15695
|
-
const normalizedAbsolutePath =
|
|
15696
|
-
if (normalizedAbsolutePath !== rootPath && !normalizedAbsolutePath.startsWith(rootPath +
|
|
15818
|
+
const relativePath = relativeDir ? path12.posix.join(relativeDir, safeEntryName) : safeEntryName;
|
|
15819
|
+
const absolutePath = path12.join(rootPath, relativePath);
|
|
15820
|
+
const normalizedAbsolutePath = path12.resolve(absolutePath);
|
|
15821
|
+
if (normalizedAbsolutePath !== rootPath && !normalizedAbsolutePath.startsWith(rootPath + path12.sep)) {
|
|
15697
15822
|
continue;
|
|
15698
15823
|
}
|
|
15699
15824
|
if (entry.isSymbolicLink()) {
|
|
@@ -15914,7 +16039,7 @@ async function scanSkill(options) {
|
|
|
15914
16039
|
|
|
15915
16040
|
// src/args/validation.ts
|
|
15916
16041
|
import chalk9 from "chalk";
|
|
15917
|
-
import
|
|
16042
|
+
import path13 from "path";
|
|
15918
16043
|
import { z as z28 } from "zod";
|
|
15919
16044
|
function throwRepoUrlErrorMessage({
|
|
15920
16045
|
error,
|
|
@@ -15958,7 +16083,7 @@ function validateRepoUrl(args) {
|
|
|
15958
16083
|
}
|
|
15959
16084
|
var supportExtensions = [".json", ".xml", ".fpr", ".sarif", ".zip"];
|
|
15960
16085
|
function validateReportFileFormat(reportFile) {
|
|
15961
|
-
if (!supportExtensions.includes(
|
|
16086
|
+
if (!supportExtensions.includes(path13.extname(reportFile))) {
|
|
15962
16087
|
throw new CliError(
|
|
15963
16088
|
`
|
|
15964
16089
|
${chalk9.bold(
|
|
@@ -16006,7 +16131,7 @@ function analyzeBuilder(yargs2) {
|
|
|
16006
16131
|
).help();
|
|
16007
16132
|
}
|
|
16008
16133
|
function validateAnalyzeOptions(argv) {
|
|
16009
|
-
if (argv.f && !
|
|
16134
|
+
if (argv.f && !fs13.existsSync(argv.f)) {
|
|
16010
16135
|
throw new CliError(`
|
|
16011
16136
|
Can't access ${chalk10.bold(argv.f)}`);
|
|
16012
16137
|
}
|
|
@@ -16054,8 +16179,8 @@ import { spawn } from "child_process";
|
|
|
16054
16179
|
|
|
16055
16180
|
// src/features/claude_code/daemon.ts
|
|
16056
16181
|
import { readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
16057
|
-
import * as
|
|
16058
|
-
import
|
|
16182
|
+
import * as os9 from "os";
|
|
16183
|
+
import path25 from "path";
|
|
16059
16184
|
import { setTimeout as sleep4 } from "timers/promises";
|
|
16060
16185
|
import Configstore4 from "configstore";
|
|
16061
16186
|
|
|
@@ -16234,7 +16359,7 @@ function loadBreaker(store) {
|
|
|
16234
16359
|
// src/features/analysis/skill_quarantine/runQuarantineCheck.ts
|
|
16235
16360
|
import { stat as stat3 } from "fs/promises";
|
|
16236
16361
|
import { homedir as homedir4 } from "os";
|
|
16237
|
-
import
|
|
16362
|
+
import path20 from "path";
|
|
16238
16363
|
|
|
16239
16364
|
// src/features/analysis/skill_quarantine/constants.ts
|
|
16240
16365
|
var HEARTBEAT_DEBOUNCE_MS = (() => {
|
|
@@ -16249,11 +16374,11 @@ var STUB_MARKER = "\u26D4 QUARANTINED BY TRACY";
|
|
|
16249
16374
|
|
|
16250
16375
|
// src/features/analysis/skill_quarantine/enumerateInstalledSkills.ts
|
|
16251
16376
|
import { homedir as homedir2 } from "os";
|
|
16252
|
-
import
|
|
16377
|
+
import path16 from "path";
|
|
16253
16378
|
|
|
16254
16379
|
// src/features/analysis/context_file_processor.ts
|
|
16255
16380
|
import { createHash } from "crypto";
|
|
16256
|
-
import
|
|
16381
|
+
import path14 from "path";
|
|
16257
16382
|
import AdmZip3 from "adm-zip";
|
|
16258
16383
|
import pLimit5 from "p-limit";
|
|
16259
16384
|
var SANITIZE_CONCURRENCY = 5;
|
|
@@ -16287,7 +16412,7 @@ async function processContextFiles(regularFiles, skillGroups) {
|
|
|
16287
16412
|
);
|
|
16288
16413
|
for (const file of sortedFiles) {
|
|
16289
16414
|
const sanitizedContent = await sanitizeFileContent(file.content);
|
|
16290
|
-
const zipEntryName = group.isFolder ?
|
|
16415
|
+
const zipEntryName = group.isFolder ? path14.relative(group.skillPath, file.path).replace(/\\/g, "/") : path14.basename(file.path);
|
|
16291
16416
|
zip.addFile(zipEntryName, Buffer.from(sanitizedContent, "utf-8"));
|
|
16292
16417
|
const entry = zip.getEntry(zipEntryName);
|
|
16293
16418
|
if (entry) {
|
|
@@ -16306,7 +16431,7 @@ async function processContextFiles(regularFiles, skillGroups) {
|
|
|
16306
16431
|
// src/features/analysis/context_file_scanner.ts
|
|
16307
16432
|
import { lstat, readdir, readFile, realpath, stat } from "fs/promises";
|
|
16308
16433
|
import { homedir } from "os";
|
|
16309
|
-
import
|
|
16434
|
+
import path15 from "path";
|
|
16310
16435
|
import { globby as globby2 } from "globby";
|
|
16311
16436
|
import { parse as parseJsoncLib } from "jsonc-parser";
|
|
16312
16437
|
|
|
@@ -16638,25 +16763,25 @@ function resolveCustomLocationPath(raw, workspaceRoot, home) {
|
|
|
16638
16763
|
return null;
|
|
16639
16764
|
}
|
|
16640
16765
|
if (s.startsWith("~/") || s === "~") {
|
|
16641
|
-
s =
|
|
16766
|
+
s = path15.join(home, s.slice(1));
|
|
16642
16767
|
}
|
|
16643
|
-
if (!
|
|
16644
|
-
s =
|
|
16768
|
+
if (!path15.isAbsolute(s)) {
|
|
16769
|
+
s = path15.resolve(workspaceRoot, s);
|
|
16645
16770
|
}
|
|
16646
|
-
const resolved =
|
|
16771
|
+
const resolved = path15.normalize(s);
|
|
16647
16772
|
if (resolved === "/" || resolved === home) {
|
|
16648
16773
|
return null;
|
|
16649
16774
|
}
|
|
16650
16775
|
for (const sub of SENSITIVE_HOME_SUBDIRS) {
|
|
16651
|
-
const sensitive =
|
|
16652
|
-
if (resolved === sensitive || resolved.startsWith(`${sensitive}${
|
|
16776
|
+
const sensitive = path15.join(home, sub);
|
|
16777
|
+
if (resolved === sensitive || resolved.startsWith(`${sensitive}${path15.sep}`)) {
|
|
16653
16778
|
return null;
|
|
16654
16779
|
}
|
|
16655
16780
|
}
|
|
16656
|
-
const relWorkspace =
|
|
16657
|
-
const relHome =
|
|
16658
|
-
const escapesWorkspace = relWorkspace.startsWith("..") ||
|
|
16659
|
-
const escapesHome = relHome.startsWith("..") ||
|
|
16781
|
+
const relWorkspace = path15.relative(workspaceRoot, resolved);
|
|
16782
|
+
const relHome = path15.relative(home, resolved);
|
|
16783
|
+
const escapesWorkspace = relWorkspace.startsWith("..") || path15.isAbsolute(relWorkspace);
|
|
16784
|
+
const escapesHome = relHome.startsWith("..") || path15.isAbsolute(relHome);
|
|
16660
16785
|
if (escapesWorkspace && escapesHome) {
|
|
16661
16786
|
return null;
|
|
16662
16787
|
}
|
|
@@ -16707,15 +16832,15 @@ async function readJsoncSettings(settingsPath) {
|
|
|
16707
16832
|
putSettingsCache(settingsPath, { mtimeMs, parsed: payload });
|
|
16708
16833
|
return payload;
|
|
16709
16834
|
}
|
|
16710
|
-
function putSettingsCache(
|
|
16711
|
-
if (!settingsCache.has(
|
|
16835
|
+
function putSettingsCache(path38, entry) {
|
|
16836
|
+
if (!settingsCache.has(path38) && settingsCache.size >= MAX_SETTINGS_CACHE_SIZE) {
|
|
16712
16837
|
settingsCache.delete(settingsCache.keys().next().value);
|
|
16713
16838
|
}
|
|
16714
|
-
settingsCache.set(
|
|
16839
|
+
settingsCache.set(path38, entry);
|
|
16715
16840
|
}
|
|
16716
16841
|
async function readCopilotCustomLocations(workspaceRoot) {
|
|
16717
16842
|
const parsed = await readJsoncSettings(
|
|
16718
|
-
|
|
16843
|
+
path15.join(workspaceRoot, ".vscode", "settings.json")
|
|
16719
16844
|
);
|
|
16720
16845
|
if (!parsed) {
|
|
16721
16846
|
return [];
|
|
@@ -16762,7 +16887,7 @@ async function readCopilotCustomLocations(workspaceRoot) {
|
|
|
16762
16887
|
async function readClaudeCodeCustomLocations() {
|
|
16763
16888
|
const home = homedir();
|
|
16764
16889
|
const parsed = await readJsoncSettings(
|
|
16765
|
-
|
|
16890
|
+
path15.join(home, ".claude", "settings.json")
|
|
16766
16891
|
);
|
|
16767
16892
|
if (!parsed) {
|
|
16768
16893
|
return [];
|
|
@@ -16804,7 +16929,7 @@ function groupSkills(files, root, baseDir) {
|
|
|
16804
16929
|
const folderMap = /* @__PURE__ */ new Map();
|
|
16805
16930
|
const standalone = [];
|
|
16806
16931
|
for (const f of skillFiles) {
|
|
16807
|
-
const rel =
|
|
16932
|
+
const rel = path15.relative(baseDir, f.path).replace(/\\/g, "/");
|
|
16808
16933
|
const skillsMarker = "skills/";
|
|
16809
16934
|
const skillsIdx = rel.indexOf(skillsMarker);
|
|
16810
16935
|
if (skillsIdx === -1) {
|
|
@@ -16831,8 +16956,8 @@ function groupSkills(files, root, baseDir) {
|
|
|
16831
16956
|
}
|
|
16832
16957
|
const groups = [];
|
|
16833
16958
|
for (const f of standalone) {
|
|
16834
|
-
const name =
|
|
16835
|
-
const standaloneRel =
|
|
16959
|
+
const name = path15.basename(f.path, path15.extname(f.path));
|
|
16960
|
+
const standaloneRel = path15.relative(baseDir, f.path).replace(/\\/g, "/");
|
|
16836
16961
|
const sessionKey = `skill:${root}:${standaloneRel}`;
|
|
16837
16962
|
groups.push({
|
|
16838
16963
|
name,
|
|
@@ -16846,7 +16971,7 @@ function groupSkills(files, root, baseDir) {
|
|
|
16846
16971
|
}
|
|
16847
16972
|
for (const [folderKey, { folderName, files: folderFiles }] of folderMap) {
|
|
16848
16973
|
const maxMtimeMs = Math.max(...folderFiles.map((f) => f.mtimeMs));
|
|
16849
|
-
const skillPath =
|
|
16974
|
+
const skillPath = path15.join(baseDir, folderKey);
|
|
16850
16975
|
const sessionKey = `skill:${root}:${folderKey}`;
|
|
16851
16976
|
groups.push({
|
|
16852
16977
|
name: folderName,
|
|
@@ -16967,10 +17092,10 @@ async function enumerateGlob(pattern, cwd, category, isDynamic) {
|
|
|
16967
17092
|
} catch {
|
|
16968
17093
|
return [];
|
|
16969
17094
|
}
|
|
16970
|
-
return files.map((
|
|
17095
|
+
return files.map((path38) => ({ path: path38, category }));
|
|
16971
17096
|
}
|
|
16972
17097
|
async function enumerateSkillBundle(baseDir, skillsRoot) {
|
|
16973
|
-
const skillsDir =
|
|
17098
|
+
const skillsDir = path15.resolve(baseDir, skillsRoot);
|
|
16974
17099
|
let manifests;
|
|
16975
17100
|
try {
|
|
16976
17101
|
manifests = await globby2("*/SKILL.md", {
|
|
@@ -16986,7 +17111,7 @@ async function enumerateSkillBundle(baseDir, skillsRoot) {
|
|
|
16986
17111
|
}
|
|
16987
17112
|
const perSkillResults = await Promise.all(
|
|
16988
17113
|
manifests.map(async (manifest) => {
|
|
16989
|
-
const skillDir =
|
|
17114
|
+
const skillDir = path15.dirname(manifest);
|
|
16990
17115
|
try {
|
|
16991
17116
|
return await globby2("**/*", {
|
|
16992
17117
|
cwd: skillDir,
|
|
@@ -17035,11 +17160,11 @@ async function enumerateSymlinkedSkills(skillsDir) {
|
|
|
17035
17160
|
const results = [];
|
|
17036
17161
|
for (const entry of dirEntries) {
|
|
17037
17162
|
if (!entry.isSymbolicLink()) continue;
|
|
17038
|
-
const entryPath =
|
|
17163
|
+
const entryPath = path15.join(skillsDir, entry.name);
|
|
17039
17164
|
try {
|
|
17040
17165
|
const st = await stat(entryPath);
|
|
17041
17166
|
if (st.isDirectory()) {
|
|
17042
|
-
const hasManifest = await stat(
|
|
17167
|
+
const hasManifest = await stat(path15.join(entryPath, "SKILL.md")).then(() => true).catch(() => false);
|
|
17043
17168
|
if (!hasManifest) continue;
|
|
17044
17169
|
const realDir = await realpath(entryPath);
|
|
17045
17170
|
const realFiles = await globby2("**/*", {
|
|
@@ -17052,7 +17177,7 @@ async function enumerateSymlinkedSkills(skillsDir) {
|
|
|
17052
17177
|
}).catch(() => []);
|
|
17053
17178
|
for (const f of realFiles) {
|
|
17054
17179
|
results.push({
|
|
17055
|
-
path:
|
|
17180
|
+
path: path15.join(entryPath, path15.relative(realDir, f)),
|
|
17056
17181
|
category: "skill"
|
|
17057
17182
|
});
|
|
17058
17183
|
}
|
|
@@ -17084,11 +17209,11 @@ function scopeForRoot(root) {
|
|
|
17084
17209
|
return void 0;
|
|
17085
17210
|
}
|
|
17086
17211
|
function deriveIdentifier(filePath, baseDir) {
|
|
17087
|
-
const relative2 =
|
|
17212
|
+
const relative2 = path15.relative(baseDir, filePath);
|
|
17088
17213
|
if (!relative2.startsWith("..")) {
|
|
17089
17214
|
return relative2.replace(/\\/g, "/");
|
|
17090
17215
|
}
|
|
17091
|
-
return
|
|
17216
|
+
return path15.basename(filePath);
|
|
17092
17217
|
}
|
|
17093
17218
|
|
|
17094
17219
|
// src/features/analysis/skill_quarantine/enumerateInstalledSkills.ts
|
|
@@ -17100,8 +17225,8 @@ async function enumerateInstalledSkills(workspaceRoot) {
|
|
|
17100
17225
|
);
|
|
17101
17226
|
const home = homedir2();
|
|
17102
17227
|
const agentGroups = regularFiles.filter((f) => f.category === "agent-config").map((f) => ({
|
|
17103
|
-
name:
|
|
17104
|
-
root: f.path.startsWith(home +
|
|
17228
|
+
name: path16.basename(f.path, path16.extname(f.path)),
|
|
17229
|
+
root: f.path.startsWith(home + path16.sep) ? "home" : "workspace",
|
|
17105
17230
|
skillPath: f.path,
|
|
17106
17231
|
files: [f],
|
|
17107
17232
|
isFolder: false,
|
|
@@ -17185,32 +17310,32 @@ import {
|
|
|
17185
17310
|
unlink,
|
|
17186
17311
|
writeFile
|
|
17187
17312
|
} from "fs/promises";
|
|
17188
|
-
import
|
|
17313
|
+
import path19 from "path";
|
|
17189
17314
|
import AdmZip4 from "adm-zip";
|
|
17190
17315
|
|
|
17191
17316
|
// src/features/analysis/skill_quarantine/paths.ts
|
|
17192
17317
|
import { homedir as homedir3 } from "os";
|
|
17193
|
-
import
|
|
17318
|
+
import path17 from "path";
|
|
17194
17319
|
function getQuarantineRoot() {
|
|
17195
|
-
return
|
|
17320
|
+
return path17.join(homedir3(), ".tracy", "quarantine", "claude", "skills");
|
|
17196
17321
|
}
|
|
17197
17322
|
function getQuarantineZipPath(md5) {
|
|
17198
|
-
return
|
|
17323
|
+
return path17.join(getQuarantineRoot(), `${md5}.zip`);
|
|
17199
17324
|
}
|
|
17200
17325
|
function getTmpZipPath(md5, uuid) {
|
|
17201
|
-
return
|
|
17326
|
+
return path17.join(getQuarantineRoot(), `${md5}_tmp_${uuid}.zip`);
|
|
17202
17327
|
}
|
|
17203
17328
|
var TMP_ZIP_REGEX = /^([0-9a-f]{32})_tmp_[0-9a-f-]+\.zip$/;
|
|
17204
17329
|
var COMMITTED_ZIP_REGEX = /^([0-9a-f]{32})\.zip$/;
|
|
17205
17330
|
|
|
17206
17331
|
// src/features/analysis/skill_quarantine/stubTemplate.ts
|
|
17207
|
-
import
|
|
17332
|
+
import path18 from "path";
|
|
17208
17333
|
import { quote } from "shell-quote";
|
|
17209
17334
|
var LEGACY_SUMMARY_FALLBACK = "not available (scan predates current schema)";
|
|
17210
17335
|
function renderStub(params) {
|
|
17211
17336
|
const folderOrFile = params.isFolder ? "skill folder" : "skill file";
|
|
17212
17337
|
const reason = params.summary ?? LEGACY_SUMMARY_FALLBACK;
|
|
17213
|
-
const extractParent =
|
|
17338
|
+
const extractParent = path18.dirname(params.origPath);
|
|
17214
17339
|
const recoverCommand = `rm -rf ${quote([params.origPath])} && unzip -o ${quote([params.quarantinedZipPath])} -d ${quote([extractParent])}`;
|
|
17215
17340
|
return `# ${STUB_MARKER}
|
|
17216
17341
|
|
|
@@ -17324,7 +17449,7 @@ async function quarantineSkill(params) {
|
|
|
17324
17449
|
}
|
|
17325
17450
|
async function preregisterStubMd5(params) {
|
|
17326
17451
|
const { skillPath, isFolder, origName, log: log2 } = params;
|
|
17327
|
-
const stubFilePath = isFolder ?
|
|
17452
|
+
const stubFilePath = isFolder ? path19.join(skillPath, "SKILL.md") : skillPath;
|
|
17328
17453
|
const stubEntryName = isFolder ? `${origName}/SKILL.md` : origName;
|
|
17329
17454
|
const content = await readFile2(stubFilePath, "utf-8");
|
|
17330
17455
|
const fileStat = await stat2(stubFilePath);
|
|
@@ -17337,7 +17462,7 @@ async function preregisterStubMd5(params) {
|
|
|
17337
17462
|
mtimeMs: fileStat.mtimeMs
|
|
17338
17463
|
};
|
|
17339
17464
|
const stubGroup = {
|
|
17340
|
-
name: isFolder ? origName :
|
|
17465
|
+
name: isFolder ? origName : path19.basename(skillPath, path19.extname(skillPath)),
|
|
17341
17466
|
root: "workspace",
|
|
17342
17467
|
// unused by md5 computation
|
|
17343
17468
|
skillPath,
|
|
@@ -17384,7 +17509,7 @@ async function writeStub(params) {
|
|
|
17384
17509
|
if (isFolder) {
|
|
17385
17510
|
await rm(skillPath, { recursive: true, force: true });
|
|
17386
17511
|
await mkdir(skillPath, { recursive: true });
|
|
17387
|
-
await writeFile(
|
|
17512
|
+
await writeFile(path19.join(skillPath, "SKILL.md"), stubContent, "utf8");
|
|
17388
17513
|
} else {
|
|
17389
17514
|
await writeFile(skillPath, stubContent, "utf8");
|
|
17390
17515
|
}
|
|
@@ -17406,7 +17531,7 @@ async function reconcileAndSweep(log2) {
|
|
|
17406
17531
|
for (const entry of entries) {
|
|
17407
17532
|
const md5 = TMP_ZIP_REGEX.exec(entry)?.[1];
|
|
17408
17533
|
if (md5 === void 0) continue;
|
|
17409
|
-
const full =
|
|
17534
|
+
const full = path19.join(root, entry);
|
|
17410
17535
|
if (committed.has(md5)) {
|
|
17411
17536
|
await unlink(full).catch(
|
|
17412
17537
|
(err) => log2.warn(
|
|
@@ -17466,8 +17591,8 @@ async function addFolderAsync(zip, root, prefix) {
|
|
|
17466
17591
|
async function walk(dir, relPrefix) {
|
|
17467
17592
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
17468
17593
|
for (const e of entries) {
|
|
17469
|
-
const full =
|
|
17470
|
-
const rel =
|
|
17594
|
+
const full = path19.join(dir, e.name);
|
|
17595
|
+
const rel = path19.posix.join(relPrefix, e.name);
|
|
17471
17596
|
if (e.isDirectory()) await walk(full, rel);
|
|
17472
17597
|
else if (e.isFile()) zip.addFile(rel, await readFile2(full));
|
|
17473
17598
|
}
|
|
@@ -17513,8 +17638,8 @@ var SKILL_PARENT_DIRS = [
|
|
|
17513
17638
|
async function getSkillDirsMtimeMs(cwd) {
|
|
17514
17639
|
const home = homedir4();
|
|
17515
17640
|
const dirs = SKILL_PARENT_DIRS.flatMap((d) => [
|
|
17516
|
-
|
|
17517
|
-
|
|
17641
|
+
path20.join(cwd, d),
|
|
17642
|
+
path20.join(home, d)
|
|
17518
17643
|
]);
|
|
17519
17644
|
let max = 0;
|
|
17520
17645
|
for (const dir of dirs) {
|
|
@@ -17627,9 +17752,9 @@ async function runQuarantineCheckIfNeeded(opts) {
|
|
|
17627
17752
|
}
|
|
17628
17753
|
|
|
17629
17754
|
// src/features/claude_code/daemon_pid_file.ts
|
|
17630
|
-
import
|
|
17631
|
-
import
|
|
17632
|
-
import
|
|
17755
|
+
import fs14 from "fs";
|
|
17756
|
+
import os5 from "os";
|
|
17757
|
+
import path21 from "path";
|
|
17633
17758
|
|
|
17634
17759
|
// src/features/claude_code/data_collector_constants.ts
|
|
17635
17760
|
var CC_VERSION_CACHE_KEY = "claudeCode.detectedCCVersion";
|
|
@@ -17655,26 +17780,26 @@ var DAEMON_SHUTDOWN_DRAIN_MS = 6e3;
|
|
|
17655
17780
|
|
|
17656
17781
|
// src/features/claude_code/daemon_pid_file.ts
|
|
17657
17782
|
function getMobbdevDir() {
|
|
17658
|
-
return
|
|
17783
|
+
return path21.join(os5.homedir(), ".mobbdev");
|
|
17659
17784
|
}
|
|
17660
17785
|
function getDaemonCheckScriptPath() {
|
|
17661
|
-
return
|
|
17786
|
+
return path21.join(getMobbdevDir(), "daemon-check.js");
|
|
17662
17787
|
}
|
|
17663
17788
|
var DaemonPidFile = class {
|
|
17664
17789
|
constructor() {
|
|
17665
17790
|
__publicField(this, "data", null);
|
|
17666
17791
|
}
|
|
17667
17792
|
get filePath() {
|
|
17668
|
-
return
|
|
17793
|
+
return path21.join(getMobbdevDir(), "daemon.pid");
|
|
17669
17794
|
}
|
|
17670
17795
|
/** Ensure ~/.mobbdev/ directory exists. */
|
|
17671
17796
|
ensureDir() {
|
|
17672
|
-
|
|
17797
|
+
fs14.mkdirSync(getMobbdevDir(), { recursive: true });
|
|
17673
17798
|
}
|
|
17674
17799
|
/** Read the PID file from disk. Returns the parsed data or null. */
|
|
17675
17800
|
read() {
|
|
17676
17801
|
try {
|
|
17677
|
-
const raw =
|
|
17802
|
+
const raw = fs14.readFileSync(this.filePath, "utf8");
|
|
17678
17803
|
const parsed = JSON.parse(raw);
|
|
17679
17804
|
if (typeof parsed.pid !== "number" || typeof parsed.startedAt !== "number" || typeof parsed.heartbeat !== "number") {
|
|
17680
17805
|
this.data = null;
|
|
@@ -17694,14 +17819,14 @@ var DaemonPidFile = class {
|
|
|
17694
17819
|
heartbeat: Date.now(),
|
|
17695
17820
|
version
|
|
17696
17821
|
};
|
|
17697
|
-
|
|
17822
|
+
fs14.writeFileSync(this.filePath, JSON.stringify(this.data), "utf8");
|
|
17698
17823
|
}
|
|
17699
17824
|
/** Update the heartbeat timestamp of the current PID file. */
|
|
17700
17825
|
updateHeartbeat() {
|
|
17701
17826
|
if (!this.data) this.read();
|
|
17702
17827
|
if (!this.data) return;
|
|
17703
17828
|
this.data.heartbeat = Date.now();
|
|
17704
|
-
|
|
17829
|
+
fs14.writeFileSync(this.filePath, JSON.stringify(this.data), "utf8");
|
|
17705
17830
|
}
|
|
17706
17831
|
/** Check whether the previously read PID data represents a live daemon. */
|
|
17707
17832
|
isAlive() {
|
|
@@ -17718,7 +17843,7 @@ var DaemonPidFile = class {
|
|
|
17718
17843
|
remove() {
|
|
17719
17844
|
this.data = null;
|
|
17720
17845
|
try {
|
|
17721
|
-
|
|
17846
|
+
fs14.unlinkSync(this.filePath);
|
|
17722
17847
|
} catch {
|
|
17723
17848
|
}
|
|
17724
17849
|
}
|
|
@@ -17728,7 +17853,7 @@ var DaemonPidFile = class {
|
|
|
17728
17853
|
import { execFile } from "child_process";
|
|
17729
17854
|
import { createHash as createHash3 } from "crypto";
|
|
17730
17855
|
import { access as access2, open as open4, readdir as readdir3, readFile as readFile3, unlink as unlink2 } from "fs/promises";
|
|
17731
|
-
import
|
|
17856
|
+
import path22 from "path";
|
|
17732
17857
|
import { promisify } from "util";
|
|
17733
17858
|
|
|
17734
17859
|
// src/features/analysis/context_file_uploader.ts
|
|
@@ -18092,8 +18217,8 @@ function createConfigstoreStream(store, opts) {
|
|
|
18092
18217
|
heartbeatBuffer.length = 0;
|
|
18093
18218
|
}
|
|
18094
18219
|
}
|
|
18095
|
-
function setScopePath(
|
|
18096
|
-
scopePath =
|
|
18220
|
+
function setScopePath(path38) {
|
|
18221
|
+
scopePath = path38;
|
|
18097
18222
|
}
|
|
18098
18223
|
return { writable, flush, setScopePath };
|
|
18099
18224
|
}
|
|
@@ -18175,22 +18300,22 @@ function createDdBatch(config2) {
|
|
|
18175
18300
|
|
|
18176
18301
|
// src/utils/shared-logger/hostname.ts
|
|
18177
18302
|
import { createHash as createHash2 } from "crypto";
|
|
18178
|
-
import
|
|
18303
|
+
import os6 from "os";
|
|
18179
18304
|
function hashString(input) {
|
|
18180
18305
|
return createHash2("sha256").update(input).digest("hex").slice(0, 16);
|
|
18181
18306
|
}
|
|
18182
18307
|
function getPlainHostname() {
|
|
18183
18308
|
try {
|
|
18184
|
-
return `${
|
|
18309
|
+
return `${os6.userInfo().username}@${os6.hostname()}`;
|
|
18185
18310
|
} catch {
|
|
18186
|
-
return `unknown@${
|
|
18311
|
+
return `unknown@${os6.hostname()}`;
|
|
18187
18312
|
}
|
|
18188
18313
|
}
|
|
18189
18314
|
function getHashedHostname() {
|
|
18190
18315
|
try {
|
|
18191
|
-
return `${hashString(
|
|
18316
|
+
return `${hashString(os6.userInfo().username)}@${hashString(os6.hostname())}`;
|
|
18192
18317
|
} catch {
|
|
18193
|
-
return `unknown@${hashString(
|
|
18318
|
+
return `unknown@${hashString(os6.hostname())}`;
|
|
18194
18319
|
}
|
|
18195
18320
|
}
|
|
18196
18321
|
|
|
@@ -18317,7 +18442,7 @@ function createLogger(config2) {
|
|
|
18317
18442
|
|
|
18318
18443
|
// src/features/claude_code/hook_logger.ts
|
|
18319
18444
|
var DD_RUM_TOKEN = true ? "pubf59c0182545bfb4c299175119f1abf9b" : "";
|
|
18320
|
-
var CLI_VERSION = true ? "1.4.
|
|
18445
|
+
var CLI_VERSION = true ? "1.4.49" : "unknown";
|
|
18321
18446
|
var NAMESPACE = "mobbdev-claude-code-hook-logs";
|
|
18322
18447
|
var claudeCodeVersion;
|
|
18323
18448
|
function buildDdTags() {
|
|
@@ -18434,12 +18559,12 @@ async function resolveTranscriptPath(transcriptPath, sessionId) {
|
|
|
18434
18559
|
return transcriptPath;
|
|
18435
18560
|
} catch {
|
|
18436
18561
|
}
|
|
18437
|
-
const filename =
|
|
18438
|
-
const dirName =
|
|
18439
|
-
const projectsDir =
|
|
18562
|
+
const filename = path22.basename(transcriptPath);
|
|
18563
|
+
const dirName = path22.basename(path22.dirname(transcriptPath));
|
|
18564
|
+
const projectsDir = path22.dirname(path22.dirname(transcriptPath));
|
|
18440
18565
|
const baseDirName = dirName.replace(/[-.]claude-worktrees-.+$/, "");
|
|
18441
18566
|
if (baseDirName !== dirName) {
|
|
18442
|
-
const candidate =
|
|
18567
|
+
const candidate = path22.join(projectsDir, baseDirName, filename);
|
|
18443
18568
|
try {
|
|
18444
18569
|
await access2(candidate);
|
|
18445
18570
|
hookLog.info(
|
|
@@ -18461,7 +18586,7 @@ async function resolveTranscriptPath(transcriptPath, sessionId) {
|
|
|
18461
18586
|
const dirs = await readdir3(projectsDir);
|
|
18462
18587
|
for (const dir of dirs) {
|
|
18463
18588
|
if (dir === dirName) continue;
|
|
18464
|
-
const candidate =
|
|
18589
|
+
const candidate = path22.join(projectsDir, dir, filename);
|
|
18465
18590
|
try {
|
|
18466
18591
|
await access2(candidate);
|
|
18467
18592
|
hookLog.info(
|
|
@@ -18683,7 +18808,7 @@ async function cleanupStaleSessions(configDir) {
|
|
|
18683
18808
|
);
|
|
18684
18809
|
let deletedCount = 0;
|
|
18685
18810
|
for (const file of sessionFiles) {
|
|
18686
|
-
const filePath =
|
|
18811
|
+
const filePath = path22.join(configDir, file);
|
|
18687
18812
|
try {
|
|
18688
18813
|
const content = JSON.parse(await readFile3(filePath, "utf-8"));
|
|
18689
18814
|
let newest = 0;
|
|
@@ -18980,17 +19105,17 @@ function summarizeUploadErrTypes(errs) {
|
|
|
18980
19105
|
}
|
|
18981
19106
|
|
|
18982
19107
|
// src/features/claude_code/install_hook.ts
|
|
18983
|
-
import
|
|
19108
|
+
import fs15 from "fs";
|
|
18984
19109
|
import fsPromises4 from "fs/promises";
|
|
18985
|
-
import
|
|
18986
|
-
import
|
|
19110
|
+
import os7 from "os";
|
|
19111
|
+
import path23 from "path";
|
|
18987
19112
|
import chalk11 from "chalk";
|
|
18988
19113
|
|
|
18989
19114
|
// src/features/claude_code/daemon-check-shim.tmpl.js
|
|
18990
19115
|
var daemon_check_shim_tmpl_default = "// Mobb daemon shim \u2014 checks if daemon is alive, spawns if dead.\n// Auto-generated by mobbdev CLI. Do not edit.\nvar fs = require('fs')\nvar spawn = require('child_process').spawn\nvar path = require('path')\nvar os = require('os')\n\nvar pidFile = path.join(os.homedir(), '.mobbdev', 'daemon.pid')\nvar HEARTBEAT_STALE_MS = __HEARTBEAT_STALE_MS__\n\ntry {\n var data = JSON.parse(fs.readFileSync(pidFile, 'utf8'))\n if (Date.now() - data.heartbeat > HEARTBEAT_STALE_MS) throw new Error('stale')\n process.kill(data.pid, 0) // throws ESRCH if the process is gone\n} catch (e) {\n var localCli = process.env.MOBBDEV_LOCAL_CLI\n var child = localCli\n ? spawn('node', [localCli, 'claude-code-daemon'], { detached: true, stdio: 'ignore', windowsHide: true })\n : spawn('npx', ['--yes', 'mobbdev@latest', 'claude-code-daemon'], { detached: true, stdio: 'ignore', shell: true, windowsHide: true })\n child.unref()\n}\n";
|
|
18991
19116
|
|
|
18992
19117
|
// src/features/claude_code/install_hook.ts
|
|
18993
|
-
var CLAUDE_SETTINGS_PATH =
|
|
19118
|
+
var CLAUDE_SETTINGS_PATH = path23.join(os7.homedir(), ".claude", "settings.json");
|
|
18994
19119
|
var RECOMMENDED_MATCHER = "*";
|
|
18995
19120
|
async function claudeSettingsExists() {
|
|
18996
19121
|
try {
|
|
@@ -19025,8 +19150,8 @@ function getDaemonCheckScript() {
|
|
|
19025
19150
|
);
|
|
19026
19151
|
}
|
|
19027
19152
|
function writeDaemonCheckScript() {
|
|
19028
|
-
|
|
19029
|
-
|
|
19153
|
+
fs15.mkdirSync(getMobbdevDir(), { recursive: true });
|
|
19154
|
+
fs15.writeFileSync(getDaemonCheckScriptPath(), getDaemonCheckScript(), "utf8");
|
|
19030
19155
|
}
|
|
19031
19156
|
function buildHookCommand(envPrefix) {
|
|
19032
19157
|
const nodeBin = process.execPath || "node";
|
|
@@ -19137,17 +19262,17 @@ async function installMobbHooks(options = {}) {
|
|
|
19137
19262
|
|
|
19138
19263
|
// src/features/claude_code/transcript_scanner.ts
|
|
19139
19264
|
import { lstat as lstat2, open as open5, readdir as readdir4, stat as stat4 } from "fs/promises";
|
|
19140
|
-
import
|
|
19141
|
-
import
|
|
19265
|
+
import os8 from "os";
|
|
19266
|
+
import path24 from "path";
|
|
19142
19267
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
19143
19268
|
function getClaudeProjectsDirs() {
|
|
19144
19269
|
const dirs = [];
|
|
19145
19270
|
const configDir = process.env["CLAUDE_CONFIG_DIR"];
|
|
19146
19271
|
if (configDir) {
|
|
19147
|
-
dirs.push(
|
|
19272
|
+
dirs.push(path24.join(configDir, "projects"));
|
|
19148
19273
|
}
|
|
19149
|
-
dirs.push(
|
|
19150
|
-
dirs.push(
|
|
19274
|
+
dirs.push(path24.join(os8.homedir(), ".config", "claude", "projects"));
|
|
19275
|
+
dirs.push(path24.join(os8.homedir(), ".claude", "projects"));
|
|
19151
19276
|
return dirs;
|
|
19152
19277
|
}
|
|
19153
19278
|
var META_MAX_BYTES = 4096;
|
|
@@ -19203,7 +19328,7 @@ async function collectJsonlFiles(files, dir, projectDir, seen, now, results, ove
|
|
|
19203
19328
|
sessionId = basename2;
|
|
19204
19329
|
isSubagent = false;
|
|
19205
19330
|
}
|
|
19206
|
-
const filePath =
|
|
19331
|
+
const filePath = path24.join(dir, file);
|
|
19207
19332
|
if (seen.has(filePath)) continue;
|
|
19208
19333
|
seen.add(filePath);
|
|
19209
19334
|
let fileStat;
|
|
@@ -19237,7 +19362,7 @@ async function scanForTranscripts(projectsDirs = getClaudeProjectsDirs()) {
|
|
|
19237
19362
|
continue;
|
|
19238
19363
|
}
|
|
19239
19364
|
for (const projName of projectDirs) {
|
|
19240
|
-
const projPath =
|
|
19365
|
+
const projPath = path24.join(projectsDir, projName);
|
|
19241
19366
|
let projStat;
|
|
19242
19367
|
try {
|
|
19243
19368
|
projStat = await stat4(projPath);
|
|
@@ -19254,7 +19379,7 @@ async function scanForTranscripts(projectsDirs = getClaudeProjectsDirs()) {
|
|
|
19254
19379
|
await collectJsonlFiles(files, projPath, projPath, seen, now, results);
|
|
19255
19380
|
for (const entry of files) {
|
|
19256
19381
|
if (!UUID_RE.test(entry)) continue;
|
|
19257
|
-
const subagentsDir =
|
|
19382
|
+
const subagentsDir = path24.join(projPath, entry, "subagents");
|
|
19258
19383
|
if (knownAbsentSubagentDirs.has(subagentsDir)) continue;
|
|
19259
19384
|
try {
|
|
19260
19385
|
const s = await stat4(subagentsDir);
|
|
@@ -19360,8 +19485,8 @@ async function startDaemon() {
|
|
|
19360
19485
|
const sessionCwdCache = /* @__PURE__ */ new Map();
|
|
19361
19486
|
let lastContextScanMs = 0;
|
|
19362
19487
|
const machineContext = {
|
|
19363
|
-
cpuCount:
|
|
19364
|
-
totalMemGB: Math.round(
|
|
19488
|
+
cpuCount: os9.cpus().length,
|
|
19489
|
+
totalMemGB: Math.round(os9.totalmem() / 1024 ** 3),
|
|
19365
19490
|
nodeVersion: process.version
|
|
19366
19491
|
};
|
|
19367
19492
|
while (true) {
|
|
@@ -19384,7 +19509,7 @@ async function startDaemon() {
|
|
|
19384
19509
|
for (const transcript of changed) {
|
|
19385
19510
|
const sessionStore = createSessionConfigStore(transcript.sessionId);
|
|
19386
19511
|
if (!cleanupConfigDir) {
|
|
19387
|
-
cleanupConfigDir =
|
|
19512
|
+
cleanupConfigDir = path25.dirname(sessionStore.path);
|
|
19388
19513
|
}
|
|
19389
19514
|
pidFile.updateHeartbeat();
|
|
19390
19515
|
const drainStart = Date.now();
|
|
@@ -19672,6 +19797,12 @@ var claudeCodeDaemonBuilder = (yargs2) => {
|
|
|
19672
19797
|
).strict();
|
|
19673
19798
|
};
|
|
19674
19799
|
var claudeCodeInstallHookHandler = async (argv) => {
|
|
19800
|
+
if (isStandaloneBinary()) {
|
|
19801
|
+
console.error(
|
|
19802
|
+
"Claude Code hooks are not available in the standalone mobbdev binary (they need a Node.js runtime). Install them with the npm package instead: npx mobbdev@latest claude-code-install-hook"
|
|
19803
|
+
);
|
|
19804
|
+
process.exit(1);
|
|
19805
|
+
}
|
|
19675
19806
|
try {
|
|
19676
19807
|
await getAuthenticatedGQLClient({ isSkipPrompts: false });
|
|
19677
19808
|
await installMobbHooks({ saveEnv: argv["save-env"] });
|
|
@@ -19740,8 +19871,8 @@ var WorkspaceService = class {
|
|
|
19740
19871
|
* Sets a known workspace path that was discovered through successful validation
|
|
19741
19872
|
* @param path The validated workspace path to store
|
|
19742
19873
|
*/
|
|
19743
|
-
static setKnownWorkspacePath(
|
|
19744
|
-
this.knownWorkspacePath =
|
|
19874
|
+
static setKnownWorkspacePath(path38) {
|
|
19875
|
+
this.knownWorkspacePath = path38;
|
|
19745
19876
|
}
|
|
19746
19877
|
/**
|
|
19747
19878
|
* Gets the known workspace path that was previously validated
|
|
@@ -19882,7 +20013,7 @@ var logDebug = (message, data) => logger2.log(message, "debug", data);
|
|
|
19882
20013
|
var log = logger2.log.bind(logger2);
|
|
19883
20014
|
|
|
19884
20015
|
// src/mcp/services/McpGQLClient.ts
|
|
19885
|
-
import
|
|
20016
|
+
import os10 from "os";
|
|
19886
20017
|
init_client_generates();
|
|
19887
20018
|
init_configs();
|
|
19888
20019
|
|
|
@@ -20393,7 +20524,7 @@ var McpGQLClient = class extends GQLClient {
|
|
|
20393
20524
|
projectId: params.projectId ?? null,
|
|
20394
20525
|
repoUrl: params.repoUrl ?? null,
|
|
20395
20526
|
riskCount: params.riskCount ?? null,
|
|
20396
|
-
computerName:
|
|
20527
|
+
computerName: os10.hostname(),
|
|
20397
20528
|
computerUser: getComputerUser() ?? null,
|
|
20398
20529
|
clientVersion: packageJson.version
|
|
20399
20530
|
});
|
|
@@ -20676,9 +20807,9 @@ async function createAuthenticatedMcpGQLClient({
|
|
|
20676
20807
|
|
|
20677
20808
|
// src/mcp/services/McpUsageService/host.ts
|
|
20678
20809
|
import { execSync as execSync2 } from "child_process";
|
|
20679
|
-
import
|
|
20680
|
-
import
|
|
20681
|
-
import
|
|
20810
|
+
import fs16 from "fs";
|
|
20811
|
+
import os11 from "os";
|
|
20812
|
+
import path26 from "path";
|
|
20682
20813
|
var IDEs = ["cursor", "windsurf", "webstorm", "vscode", "claude"];
|
|
20683
20814
|
var runCommand = (cmd) => {
|
|
20684
20815
|
try {
|
|
@@ -20692,18 +20823,18 @@ var gitInfo = {
|
|
|
20692
20823
|
email: runCommand("git config user.email")
|
|
20693
20824
|
};
|
|
20694
20825
|
var getClaudeWorkspacePaths = () => {
|
|
20695
|
-
const home =
|
|
20696
|
-
const claudeIdePath =
|
|
20826
|
+
const home = os11.homedir();
|
|
20827
|
+
const claudeIdePath = path26.join(home, ".claude", "ide");
|
|
20697
20828
|
const workspacePaths = [];
|
|
20698
|
-
if (!
|
|
20829
|
+
if (!fs16.existsSync(claudeIdePath)) {
|
|
20699
20830
|
return workspacePaths;
|
|
20700
20831
|
}
|
|
20701
20832
|
try {
|
|
20702
|
-
const lockFiles =
|
|
20833
|
+
const lockFiles = fs16.readdirSync(claudeIdePath).filter((file) => file.endsWith(".lock"));
|
|
20703
20834
|
for (const lockFile of lockFiles) {
|
|
20704
|
-
const lockFilePath =
|
|
20835
|
+
const lockFilePath = path26.join(claudeIdePath, lockFile);
|
|
20705
20836
|
try {
|
|
20706
|
-
const lockContent = JSON.parse(
|
|
20837
|
+
const lockContent = JSON.parse(fs16.readFileSync(lockFilePath, "utf8"));
|
|
20707
20838
|
if (lockContent.workspaceFolders && Array.isArray(lockContent.workspaceFolders)) {
|
|
20708
20839
|
workspacePaths.push(...lockContent.workspaceFolders);
|
|
20709
20840
|
}
|
|
@@ -20721,29 +20852,29 @@ var getClaudeWorkspacePaths = () => {
|
|
|
20721
20852
|
return workspacePaths;
|
|
20722
20853
|
};
|
|
20723
20854
|
var getMCPConfigPaths = (hostName) => {
|
|
20724
|
-
const home =
|
|
20855
|
+
const home = os11.homedir();
|
|
20725
20856
|
const currentDir = process.env["WORKSPACE_FOLDER_PATHS"] || process.env["PWD"] || process.cwd();
|
|
20726
20857
|
switch (hostName.toLowerCase()) {
|
|
20727
20858
|
case "cursor":
|
|
20728
20859
|
return [
|
|
20729
|
-
|
|
20860
|
+
path26.join(currentDir, ".cursor", "mcp.json"),
|
|
20730
20861
|
// local first
|
|
20731
|
-
|
|
20862
|
+
path26.join(home, ".cursor", "mcp.json")
|
|
20732
20863
|
];
|
|
20733
20864
|
case "windsurf":
|
|
20734
20865
|
return [
|
|
20735
|
-
|
|
20866
|
+
path26.join(currentDir, ".codeium", "mcp_config.json"),
|
|
20736
20867
|
// local first
|
|
20737
|
-
|
|
20868
|
+
path26.join(home, ".codeium", "windsurf", "mcp_config.json")
|
|
20738
20869
|
];
|
|
20739
20870
|
case "webstorm":
|
|
20740
20871
|
return [];
|
|
20741
20872
|
case "visualstudiocode":
|
|
20742
20873
|
case "vscode":
|
|
20743
20874
|
return [
|
|
20744
|
-
|
|
20875
|
+
path26.join(currentDir, ".vscode", "mcp.json"),
|
|
20745
20876
|
// local first
|
|
20746
|
-
process.platform === "win32" ?
|
|
20877
|
+
process.platform === "win32" ? path26.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path26.join(
|
|
20747
20878
|
home,
|
|
20748
20879
|
"Library",
|
|
20749
20880
|
"Application Support",
|
|
@@ -20754,13 +20885,13 @@ var getMCPConfigPaths = (hostName) => {
|
|
|
20754
20885
|
];
|
|
20755
20886
|
case "claude": {
|
|
20756
20887
|
const claudePaths = [
|
|
20757
|
-
|
|
20888
|
+
path26.join(currentDir, ".claude.json"),
|
|
20758
20889
|
// local first
|
|
20759
|
-
|
|
20890
|
+
path26.join(home, ".claude.json")
|
|
20760
20891
|
];
|
|
20761
20892
|
const workspacePaths = getClaudeWorkspacePaths();
|
|
20762
20893
|
for (const workspacePath of workspacePaths) {
|
|
20763
|
-
claudePaths.push(
|
|
20894
|
+
claudePaths.push(path26.join(workspacePath, ".mcp.json"));
|
|
20764
20895
|
}
|
|
20765
20896
|
return claudePaths;
|
|
20766
20897
|
}
|
|
@@ -20769,9 +20900,9 @@ var getMCPConfigPaths = (hostName) => {
|
|
|
20769
20900
|
}
|
|
20770
20901
|
};
|
|
20771
20902
|
var readConfigFile = (filePath) => {
|
|
20772
|
-
if (!
|
|
20903
|
+
if (!fs16.existsSync(filePath)) return null;
|
|
20773
20904
|
try {
|
|
20774
|
-
return JSON.parse(
|
|
20905
|
+
return JSON.parse(fs16.readFileSync(filePath, "utf8"));
|
|
20775
20906
|
} catch (error) {
|
|
20776
20907
|
logWarn(`[UsageService] Failed to read MCP config: ${filePath}`);
|
|
20777
20908
|
return null;
|
|
@@ -20811,7 +20942,7 @@ var readMCPConfig = (hostName) => {
|
|
|
20811
20942
|
};
|
|
20812
20943
|
var getRunningProcesses = () => {
|
|
20813
20944
|
try {
|
|
20814
|
-
return
|
|
20945
|
+
return os11.platform() === "win32" ? execSync2("tasklist", { encoding: "utf8" }) : execSync2("ps aux", { encoding: "utf8" });
|
|
20815
20946
|
} catch {
|
|
20816
20947
|
return "";
|
|
20817
20948
|
}
|
|
@@ -20886,7 +21017,7 @@ var versionCommands = {
|
|
|
20886
21017
|
}
|
|
20887
21018
|
};
|
|
20888
21019
|
var getProcessInfo = (pid) => {
|
|
20889
|
-
const platform2 =
|
|
21020
|
+
const platform2 = os11.platform();
|
|
20890
21021
|
try {
|
|
20891
21022
|
if (platform2 === "linux" || platform2 === "darwin") {
|
|
20892
21023
|
const output = execSync2(`ps -o pid=,ppid=,comm= -p ${pid}`, {
|
|
@@ -20921,10 +21052,10 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
20921
21052
|
const ideConfigPaths = /* @__PURE__ */ new Set();
|
|
20922
21053
|
for (const ide of IDEs) {
|
|
20923
21054
|
const configPaths = getMCPConfigPaths(ide);
|
|
20924
|
-
configPaths.forEach((
|
|
21055
|
+
configPaths.forEach((path38) => ideConfigPaths.add(path38));
|
|
20925
21056
|
}
|
|
20926
21057
|
const uniqueAdditionalPaths = additionalMcpList.filter(
|
|
20927
|
-
(
|
|
21058
|
+
(path38) => !ideConfigPaths.has(path38)
|
|
20928
21059
|
);
|
|
20929
21060
|
for (const ide of IDEs) {
|
|
20930
21061
|
const cfg = readMCPConfig(ide);
|
|
@@ -21005,7 +21136,7 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
21005
21136
|
const config2 = allConfigs[ide] || null;
|
|
21006
21137
|
const ideName = ide.charAt(0).toUpperCase() + ide.slice(1) || "Unknown";
|
|
21007
21138
|
let ideVersion = "Unknown";
|
|
21008
|
-
const platform2 =
|
|
21139
|
+
const platform2 = os11.platform();
|
|
21009
21140
|
const cmds = versionCommands[ideName]?.[platform2] ?? [];
|
|
21010
21141
|
for (const cmd of cmds) {
|
|
21011
21142
|
try {
|
|
@@ -21038,15 +21169,15 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
21038
21169
|
|
|
21039
21170
|
// src/mcp/services/McpUsageService/McpUsageService.ts
|
|
21040
21171
|
import fetch6 from "node-fetch";
|
|
21041
|
-
import
|
|
21172
|
+
import os13 from "os";
|
|
21042
21173
|
import { v4 as uuidv42, v5 as uuidv5 } from "uuid";
|
|
21043
21174
|
init_configs();
|
|
21044
21175
|
|
|
21045
21176
|
// src/mcp/services/McpUsageService/system.ts
|
|
21046
21177
|
init_configs();
|
|
21047
|
-
import
|
|
21048
|
-
import
|
|
21049
|
-
import
|
|
21178
|
+
import fs17 from "fs";
|
|
21179
|
+
import os12 from "os";
|
|
21180
|
+
import path27 from "path";
|
|
21050
21181
|
var MAX_DEPTH = 2;
|
|
21051
21182
|
var patterns = ["mcp", "claude"];
|
|
21052
21183
|
var isFileMatch = (fileName) => {
|
|
@@ -21055,7 +21186,7 @@ var isFileMatch = (fileName) => {
|
|
|
21055
21186
|
};
|
|
21056
21187
|
var safeAccess = async (filePath) => {
|
|
21057
21188
|
try {
|
|
21058
|
-
await
|
|
21189
|
+
await fs17.promises.access(filePath, fs17.constants.R_OK);
|
|
21059
21190
|
return true;
|
|
21060
21191
|
} catch {
|
|
21061
21192
|
return false;
|
|
@@ -21064,9 +21195,9 @@ var safeAccess = async (filePath) => {
|
|
|
21064
21195
|
var searchDir = async (dir, depth = 0) => {
|
|
21065
21196
|
const results = [];
|
|
21066
21197
|
if (depth > MAX_DEPTH) return results;
|
|
21067
|
-
const entries = await
|
|
21198
|
+
const entries = await fs17.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
21068
21199
|
for (const entry of entries) {
|
|
21069
|
-
const fullPath =
|
|
21200
|
+
const fullPath = path27.join(dir, entry.name);
|
|
21070
21201
|
if (entry.isFile() && isFileMatch(entry.name)) {
|
|
21071
21202
|
results.push(fullPath);
|
|
21072
21203
|
} else if (entry.isDirectory()) {
|
|
@@ -21080,17 +21211,17 @@ var searchDir = async (dir, depth = 0) => {
|
|
|
21080
21211
|
};
|
|
21081
21212
|
var findSystemMCPConfigs = async () => {
|
|
21082
21213
|
try {
|
|
21083
|
-
const home =
|
|
21084
|
-
const platform2 =
|
|
21214
|
+
const home = os12.homedir();
|
|
21215
|
+
const platform2 = os12.platform();
|
|
21085
21216
|
const knownDirs = platform2 === "win32" ? [
|
|
21086
|
-
|
|
21087
|
-
|
|
21088
|
-
|
|
21217
|
+
path27.join(home, ".cursor"),
|
|
21218
|
+
path27.join(home, "Documents"),
|
|
21219
|
+
path27.join(home, "Downloads")
|
|
21089
21220
|
] : [
|
|
21090
|
-
|
|
21091
|
-
process.env["XDG_CONFIG_HOME"] ||
|
|
21092
|
-
|
|
21093
|
-
|
|
21221
|
+
path27.join(home, ".cursor"),
|
|
21222
|
+
process.env["XDG_CONFIG_HOME"] || path27.join(home, ".config"),
|
|
21223
|
+
path27.join(home, "Documents"),
|
|
21224
|
+
path27.join(home, "Downloads")
|
|
21094
21225
|
];
|
|
21095
21226
|
const timeoutPromise = new Promise(
|
|
21096
21227
|
(resolve) => setTimeout(() => {
|
|
@@ -21102,7 +21233,7 @@ var findSystemMCPConfigs = async () => {
|
|
|
21102
21233
|
);
|
|
21103
21234
|
const searchPromise = Promise.all(
|
|
21104
21235
|
knownDirs.map(
|
|
21105
|
-
(dir) =>
|
|
21236
|
+
(dir) => fs17.existsSync(dir) ? searchDir(dir) : Promise.resolve([])
|
|
21106
21237
|
)
|
|
21107
21238
|
).then((results) => results.flat());
|
|
21108
21239
|
return await Promise.race([timeoutPromise, searchPromise]);
|
|
@@ -21153,7 +21284,7 @@ var McpUsageService = class {
|
|
|
21153
21284
|
generateHostId() {
|
|
21154
21285
|
const stored = configStore.get(this.configKey);
|
|
21155
21286
|
if (stored?.mcpHostId) return stored.mcpHostId;
|
|
21156
|
-
const interfaces =
|
|
21287
|
+
const interfaces = os13.networkInterfaces();
|
|
21157
21288
|
const macs = [];
|
|
21158
21289
|
for (const iface of Object.values(interfaces)) {
|
|
21159
21290
|
if (!iface) continue;
|
|
@@ -21161,7 +21292,7 @@ var McpUsageService = class {
|
|
|
21161
21292
|
if (net.mac && net.mac !== "00:00:00:00:00:00") macs.push(net.mac);
|
|
21162
21293
|
}
|
|
21163
21294
|
}
|
|
21164
|
-
const macString = macs.length ? macs.sort().join(",") : `${
|
|
21295
|
+
const macString = macs.length ? macs.sort().join(",") : `${os13.hostname()}-${uuidv42()}`;
|
|
21165
21296
|
const hostId = uuidv5(macString, uuidv5.DNS);
|
|
21166
21297
|
logDebug("[UsageService] Generated new host ID", { hostId });
|
|
21167
21298
|
return hostId;
|
|
@@ -21184,7 +21315,7 @@ var McpUsageService = class {
|
|
|
21184
21315
|
mcpHostId,
|
|
21185
21316
|
organizationId,
|
|
21186
21317
|
mcpVersion: packageJson.version,
|
|
21187
|
-
mcpOsName:
|
|
21318
|
+
mcpOsName: os13.platform(),
|
|
21188
21319
|
mcps: JSON.stringify(mcps),
|
|
21189
21320
|
status,
|
|
21190
21321
|
userName: user.name,
|
|
@@ -23505,31 +23636,31 @@ For a complete security audit workflow, use the \`full-security-audit\` prompt.
|
|
|
23505
23636
|
};
|
|
23506
23637
|
|
|
23507
23638
|
// src/mcp/services/McpDetectionService/CursorMcpDetectionService.ts
|
|
23508
|
-
import * as
|
|
23509
|
-
import * as
|
|
23510
|
-
import * as
|
|
23639
|
+
import * as fs20 from "fs";
|
|
23640
|
+
import * as os15 from "os";
|
|
23641
|
+
import * as path29 from "path";
|
|
23511
23642
|
|
|
23512
23643
|
// src/mcp/services/McpDetectionService/BaseMcpDetectionService.ts
|
|
23513
23644
|
init_configs();
|
|
23514
|
-
import * as
|
|
23645
|
+
import * as fs19 from "fs";
|
|
23515
23646
|
import fetch7 from "node-fetch";
|
|
23516
|
-
import * as
|
|
23647
|
+
import * as path28 from "path";
|
|
23517
23648
|
|
|
23518
23649
|
// src/mcp/services/McpDetectionService/McpDetectionServiceUtils.ts
|
|
23519
|
-
import * as
|
|
23520
|
-
import * as
|
|
23650
|
+
import * as fs18 from "fs";
|
|
23651
|
+
import * as os14 from "os";
|
|
23521
23652
|
|
|
23522
23653
|
// src/mcp/services/McpDetectionService/VscodeMcpDetectionService.ts
|
|
23523
|
-
import * as
|
|
23524
|
-
import * as
|
|
23525
|
-
import * as
|
|
23654
|
+
import * as fs21 from "fs";
|
|
23655
|
+
import * as os16 from "os";
|
|
23656
|
+
import * as path30 from "path";
|
|
23526
23657
|
|
|
23527
23658
|
// src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesTool.ts
|
|
23528
23659
|
import { z as z37 } from "zod";
|
|
23529
23660
|
|
|
23530
23661
|
// src/mcp/services/PathValidation.ts
|
|
23531
|
-
import
|
|
23532
|
-
import
|
|
23662
|
+
import fs22 from "fs";
|
|
23663
|
+
import path31 from "path";
|
|
23533
23664
|
async function validatePath(inputPath) {
|
|
23534
23665
|
logDebug("Validating MCP path", { inputPath });
|
|
23535
23666
|
if (/^\/[a-zA-Z]:\//.test(inputPath)) {
|
|
@@ -23561,7 +23692,7 @@ async function validatePath(inputPath) {
|
|
|
23561
23692
|
logError(error);
|
|
23562
23693
|
return { isValid: false, error, path: inputPath };
|
|
23563
23694
|
}
|
|
23564
|
-
const normalizedPath =
|
|
23695
|
+
const normalizedPath = path31.normalize(inputPath);
|
|
23565
23696
|
if (normalizedPath.includes("..")) {
|
|
23566
23697
|
const error = `Normalized path contains path traversal patterns: ${inputPath}`;
|
|
23567
23698
|
logError(error);
|
|
@@ -23588,7 +23719,7 @@ async function validatePath(inputPath) {
|
|
|
23588
23719
|
logDebug("Path validation successful", { inputPath });
|
|
23589
23720
|
logDebug("Checking path existence", { inputPath });
|
|
23590
23721
|
try {
|
|
23591
|
-
await
|
|
23722
|
+
await fs22.promises.access(inputPath);
|
|
23592
23723
|
logDebug("Path exists and is accessible", { inputPath });
|
|
23593
23724
|
WorkspaceService.setKnownWorkspacePath(inputPath);
|
|
23594
23725
|
logDebug("Stored validated path in WorkspaceService", { inputPath });
|
|
@@ -24342,10 +24473,10 @@ If you wish to scan files that were recently changed in your git history call th
|
|
|
24342
24473
|
init_FileUtils();
|
|
24343
24474
|
init_GitService();
|
|
24344
24475
|
init_configs();
|
|
24345
|
-
import
|
|
24476
|
+
import fs23 from "fs/promises";
|
|
24346
24477
|
import nodePath from "path";
|
|
24347
24478
|
var getLocalFiles = async ({
|
|
24348
|
-
path:
|
|
24479
|
+
path: path38,
|
|
24349
24480
|
maxFileSize = MCP_MAX_FILE_SIZE,
|
|
24350
24481
|
maxFiles,
|
|
24351
24482
|
isAllFilesScan,
|
|
@@ -24353,17 +24484,17 @@ var getLocalFiles = async ({
|
|
|
24353
24484
|
scanRecentlyChangedFiles
|
|
24354
24485
|
}) => {
|
|
24355
24486
|
logDebug(`[${scanContext}] Starting getLocalFiles`, {
|
|
24356
|
-
path:
|
|
24487
|
+
path: path38,
|
|
24357
24488
|
maxFileSize,
|
|
24358
24489
|
maxFiles,
|
|
24359
24490
|
isAllFilesScan,
|
|
24360
24491
|
scanRecentlyChangedFiles
|
|
24361
24492
|
});
|
|
24362
24493
|
try {
|
|
24363
|
-
const resolvedRepoPath = await
|
|
24494
|
+
const resolvedRepoPath = await fs23.realpath(path38);
|
|
24364
24495
|
logDebug(`[${scanContext}] Resolved repository path`, {
|
|
24365
24496
|
resolvedRepoPath,
|
|
24366
|
-
originalPath:
|
|
24497
|
+
originalPath: path38
|
|
24367
24498
|
});
|
|
24368
24499
|
const gitService = new GitService(resolvedRepoPath, log);
|
|
24369
24500
|
const gitValidation = await gitService.validateRepository();
|
|
@@ -24376,7 +24507,7 @@ var getLocalFiles = async ({
|
|
|
24376
24507
|
if (!gitValidation.isValid || isAllFilesScan) {
|
|
24377
24508
|
try {
|
|
24378
24509
|
files = await FileUtils.getLastChangedFiles({
|
|
24379
|
-
dir:
|
|
24510
|
+
dir: path38,
|
|
24380
24511
|
maxFileSize,
|
|
24381
24512
|
maxFiles,
|
|
24382
24513
|
isAllFilesScan
|
|
@@ -24440,7 +24571,7 @@ var getLocalFiles = async ({
|
|
|
24440
24571
|
absoluteFilePath
|
|
24441
24572
|
);
|
|
24442
24573
|
try {
|
|
24443
|
-
const fileStat = await
|
|
24574
|
+
const fileStat = await fs23.stat(absoluteFilePath);
|
|
24444
24575
|
return {
|
|
24445
24576
|
filename: nodePath.basename(absoluteFilePath),
|
|
24446
24577
|
relativePath,
|
|
@@ -24468,7 +24599,7 @@ var getLocalFiles = async ({
|
|
|
24468
24599
|
logError(`${scanContext}Unexpected error in getLocalFiles`, {
|
|
24469
24600
|
error: error instanceof Error ? error.message : String(error),
|
|
24470
24601
|
stack: error instanceof Error ? error.stack : void 0,
|
|
24471
|
-
path:
|
|
24602
|
+
path: path38
|
|
24472
24603
|
});
|
|
24473
24604
|
throw error;
|
|
24474
24605
|
}
|
|
@@ -24477,8 +24608,8 @@ var getLocalFiles = async ({
|
|
|
24477
24608
|
// src/mcp/services/LocalMobbFolderService.ts
|
|
24478
24609
|
init_GitService();
|
|
24479
24610
|
init_issueTypeCatalog();
|
|
24480
|
-
import
|
|
24481
|
-
import
|
|
24611
|
+
import fs24 from "fs";
|
|
24612
|
+
import path32 from "path";
|
|
24482
24613
|
function extractPathFromPatch(patch) {
|
|
24483
24614
|
const match = patch?.match(/diff --git a\/([^\s]+) b\//);
|
|
24484
24615
|
return match?.[1] ?? null;
|
|
@@ -24560,19 +24691,19 @@ var LocalMobbFolderService = class {
|
|
|
24560
24691
|
"[LocalMobbFolderService] Non-git repository detected, skipping .gitignore operations"
|
|
24561
24692
|
);
|
|
24562
24693
|
}
|
|
24563
|
-
const mobbFolderPath =
|
|
24694
|
+
const mobbFolderPath = path32.join(
|
|
24564
24695
|
this.repoPath,
|
|
24565
24696
|
this.defaultMobbFolderName
|
|
24566
24697
|
);
|
|
24567
|
-
if (!
|
|
24698
|
+
if (!fs24.existsSync(mobbFolderPath)) {
|
|
24568
24699
|
logInfo("[LocalMobbFolderService] Creating .mobb folder", {
|
|
24569
24700
|
mobbFolderPath
|
|
24570
24701
|
});
|
|
24571
|
-
|
|
24702
|
+
fs24.mkdirSync(mobbFolderPath, { recursive: true });
|
|
24572
24703
|
} else {
|
|
24573
24704
|
logDebug("[LocalMobbFolderService] .mobb folder already exists");
|
|
24574
24705
|
}
|
|
24575
|
-
const stats =
|
|
24706
|
+
const stats = fs24.statSync(mobbFolderPath);
|
|
24576
24707
|
if (!stats.isDirectory()) {
|
|
24577
24708
|
throw new Error(`Path exists but is not a directory: ${mobbFolderPath}`);
|
|
24578
24709
|
}
|
|
@@ -24613,13 +24744,13 @@ var LocalMobbFolderService = class {
|
|
|
24613
24744
|
logDebug("[LocalMobbFolderService] Git repository validated successfully");
|
|
24614
24745
|
} else {
|
|
24615
24746
|
try {
|
|
24616
|
-
const stats =
|
|
24747
|
+
const stats = fs24.statSync(this.repoPath);
|
|
24617
24748
|
if (!stats.isDirectory()) {
|
|
24618
24749
|
throw new Error(
|
|
24619
24750
|
`Path exists but is not a directory: ${this.repoPath}`
|
|
24620
24751
|
);
|
|
24621
24752
|
}
|
|
24622
|
-
|
|
24753
|
+
fs24.accessSync(this.repoPath, fs24.constants.R_OK | fs24.constants.W_OK);
|
|
24623
24754
|
logDebug(
|
|
24624
24755
|
"[LocalMobbFolderService] Non-git directory validated successfully"
|
|
24625
24756
|
);
|
|
@@ -24732,8 +24863,8 @@ var LocalMobbFolderService = class {
|
|
|
24732
24863
|
mobbFolderPath,
|
|
24733
24864
|
baseFileName
|
|
24734
24865
|
);
|
|
24735
|
-
const filePath =
|
|
24736
|
-
await
|
|
24866
|
+
const filePath = path32.join(mobbFolderPath, uniqueFileName);
|
|
24867
|
+
await fs24.promises.writeFile(filePath, patch, "utf8");
|
|
24737
24868
|
logInfo("[LocalMobbFolderService] Patch saved successfully", {
|
|
24738
24869
|
filePath,
|
|
24739
24870
|
fileName: uniqueFileName,
|
|
@@ -24790,11 +24921,11 @@ var LocalMobbFolderService = class {
|
|
|
24790
24921
|
* @returns Unique filename that doesn't conflict with existing files
|
|
24791
24922
|
*/
|
|
24792
24923
|
getUniqueFileName(folderPath, baseFileName) {
|
|
24793
|
-
const baseName =
|
|
24794
|
-
const extension =
|
|
24924
|
+
const baseName = path32.parse(baseFileName).name;
|
|
24925
|
+
const extension = path32.parse(baseFileName).ext;
|
|
24795
24926
|
let uniqueFileName = baseFileName;
|
|
24796
24927
|
let index = 1;
|
|
24797
|
-
while (
|
|
24928
|
+
while (fs24.existsSync(path32.join(folderPath, uniqueFileName))) {
|
|
24798
24929
|
uniqueFileName = `${baseName}-${index}${extension}`;
|
|
24799
24930
|
index++;
|
|
24800
24931
|
if (index > 1e3) {
|
|
@@ -24825,18 +24956,18 @@ var LocalMobbFolderService = class {
|
|
|
24825
24956
|
logDebug("[LocalMobbFolderService] Logging patch info", { fixId: fix.id });
|
|
24826
24957
|
try {
|
|
24827
24958
|
const mobbFolderPath = await this.getFolder();
|
|
24828
|
-
const patchInfoPath =
|
|
24959
|
+
const patchInfoPath = path32.join(mobbFolderPath, "patchInfo.md");
|
|
24829
24960
|
const markdownContent = this.generateFixMarkdown(fix, savedPatchFileName);
|
|
24830
24961
|
let existingContent = "";
|
|
24831
|
-
if (
|
|
24832
|
-
existingContent = await
|
|
24962
|
+
if (fs24.existsSync(patchInfoPath)) {
|
|
24963
|
+
existingContent = await fs24.promises.readFile(patchInfoPath, "utf8");
|
|
24833
24964
|
logDebug("[LocalMobbFolderService] Existing patchInfo.md found");
|
|
24834
24965
|
} else {
|
|
24835
24966
|
logDebug("[LocalMobbFolderService] Creating new patchInfo.md file");
|
|
24836
24967
|
}
|
|
24837
24968
|
const separator = existingContent ? "\n\n================================================================================\n\n" : "";
|
|
24838
24969
|
const updatedContent = `${markdownContent}${separator}${existingContent}`;
|
|
24839
|
-
await
|
|
24970
|
+
await fs24.promises.writeFile(patchInfoPath, updatedContent, "utf8");
|
|
24840
24971
|
logInfo("[LocalMobbFolderService] Patch info logged successfully", {
|
|
24841
24972
|
patchInfoPath,
|
|
24842
24973
|
fixId: fix.id,
|
|
@@ -24867,7 +24998,7 @@ var LocalMobbFolderService = class {
|
|
|
24867
24998
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
24868
24999
|
const patch = this.extractPatchFromFix(fix);
|
|
24869
25000
|
const relativePatchedFilePath = patch ? extractPathFromPatch(patch) : null;
|
|
24870
|
-
const patchedFilePath = relativePatchedFilePath ?
|
|
25001
|
+
const patchedFilePath = relativePatchedFilePath ? path32.resolve(this.repoPath, relativePatchedFilePath) : null;
|
|
24871
25002
|
const fixIdentifier = savedPatchFileName ? savedPatchFileName.replace(".patch", "") : fix.id;
|
|
24872
25003
|
let markdown = `# Fix ${fixIdentifier}
|
|
24873
25004
|
|
|
@@ -25209,16 +25340,16 @@ import {
|
|
|
25209
25340
|
unlinkSync,
|
|
25210
25341
|
writeFileSync as writeFileSync3
|
|
25211
25342
|
} from "fs";
|
|
25212
|
-
import
|
|
25343
|
+
import fs25 from "fs/promises";
|
|
25213
25344
|
import parseDiff2 from "parse-diff";
|
|
25214
|
-
import
|
|
25345
|
+
import path33 from "path";
|
|
25215
25346
|
var PatchApplicationService = class {
|
|
25216
25347
|
/**
|
|
25217
25348
|
* Gets the appropriate comment syntax for a file based on its extension
|
|
25218
25349
|
*/
|
|
25219
25350
|
static getCommentSyntax(filePath) {
|
|
25220
|
-
const ext =
|
|
25221
|
-
const basename2 =
|
|
25351
|
+
const ext = path33.extname(filePath).toLowerCase();
|
|
25352
|
+
const basename2 = path33.basename(filePath);
|
|
25222
25353
|
const commentMap = {
|
|
25223
25354
|
// C-style languages (single line comments)
|
|
25224
25355
|
".js": "//",
|
|
@@ -25426,7 +25557,7 @@ var PatchApplicationService = class {
|
|
|
25426
25557
|
}
|
|
25427
25558
|
);
|
|
25428
25559
|
}
|
|
25429
|
-
const dirPath =
|
|
25560
|
+
const dirPath = path33.dirname(normalizedFilePath);
|
|
25430
25561
|
mkdirSync(dirPath, { recursive: true });
|
|
25431
25562
|
writeFileSync3(normalizedFilePath, finalContent, "utf8");
|
|
25432
25563
|
return normalizedFilePath;
|
|
@@ -25435,9 +25566,9 @@ var PatchApplicationService = class {
|
|
|
25435
25566
|
repositoryPath,
|
|
25436
25567
|
targetPath
|
|
25437
25568
|
}) {
|
|
25438
|
-
const repoRoot =
|
|
25439
|
-
const normalizedPath =
|
|
25440
|
-
const repoRootWithSep = repoRoot.endsWith(
|
|
25569
|
+
const repoRoot = path33.resolve(repositoryPath);
|
|
25570
|
+
const normalizedPath = path33.resolve(repoRoot, targetPath);
|
|
25571
|
+
const repoRootWithSep = repoRoot.endsWith(path33.sep) ? repoRoot : `${repoRoot}${path33.sep}`;
|
|
25441
25572
|
if (normalizedPath !== repoRoot && !normalizedPath.startsWith(repoRootWithSep)) {
|
|
25442
25573
|
throw new Error(
|
|
25443
25574
|
`Security violation: target path ${targetPath} resolves outside repository`
|
|
@@ -25446,7 +25577,7 @@ var PatchApplicationService = class {
|
|
|
25446
25577
|
return {
|
|
25447
25578
|
repoRoot,
|
|
25448
25579
|
normalizedPath,
|
|
25449
|
-
relativePath:
|
|
25580
|
+
relativePath: path33.relative(repoRoot, normalizedPath)
|
|
25450
25581
|
};
|
|
25451
25582
|
}
|
|
25452
25583
|
/**
|
|
@@ -25728,9 +25859,9 @@ var PatchApplicationService = class {
|
|
|
25728
25859
|
continue;
|
|
25729
25860
|
}
|
|
25730
25861
|
try {
|
|
25731
|
-
const absolutePath =
|
|
25862
|
+
const absolutePath = path33.resolve(repositoryPath, targetFile);
|
|
25732
25863
|
if (existsSync6(absolutePath)) {
|
|
25733
|
-
const stats = await
|
|
25864
|
+
const stats = await fs25.stat(absolutePath);
|
|
25734
25865
|
const fileModTime = stats.mtime.getTime();
|
|
25735
25866
|
if (fileModTime > scanStartTime) {
|
|
25736
25867
|
logError(
|
|
@@ -25772,7 +25903,7 @@ var PatchApplicationService = class {
|
|
|
25772
25903
|
const appliedFixes = [];
|
|
25773
25904
|
const failedFixes = [];
|
|
25774
25905
|
const skippedFixes = [];
|
|
25775
|
-
const resolvedRepoPath = await
|
|
25906
|
+
const resolvedRepoPath = await fs25.realpath(repositoryPath);
|
|
25776
25907
|
logInfo(
|
|
25777
25908
|
`[${scanContext}] Starting patch application for ${fixes.length} fixes`,
|
|
25778
25909
|
{
|
|
@@ -25961,7 +26092,7 @@ var PatchApplicationService = class {
|
|
|
25961
26092
|
fix,
|
|
25962
26093
|
scanContext
|
|
25963
26094
|
});
|
|
25964
|
-
appliedFiles.push(
|
|
26095
|
+
appliedFiles.push(path33.relative(repositoryPath, actualPath));
|
|
25965
26096
|
logDebug(`[${scanContext}] Created new file: ${relativePath}`);
|
|
25966
26097
|
}
|
|
25967
26098
|
/**
|
|
@@ -26010,7 +26141,7 @@ var PatchApplicationService = class {
|
|
|
26010
26141
|
fix,
|
|
26011
26142
|
scanContext
|
|
26012
26143
|
});
|
|
26013
|
-
appliedFiles.push(
|
|
26144
|
+
appliedFiles.push(path33.relative(repositoryPath, actualPath));
|
|
26014
26145
|
logDebug(`[${scanContext}] Modified file: ${relativePath}`);
|
|
26015
26146
|
}
|
|
26016
26147
|
}
|
|
@@ -26202,13 +26333,13 @@ var PatchApplicationService = class {
|
|
|
26202
26333
|
// src/mcp/services/ScanFiles.ts
|
|
26203
26334
|
init_client_generates();
|
|
26204
26335
|
init_GitService();
|
|
26205
|
-
import
|
|
26336
|
+
import os17 from "os";
|
|
26206
26337
|
init_configs();
|
|
26207
26338
|
|
|
26208
26339
|
// src/mcp/services/FileOperations.ts
|
|
26209
26340
|
init_FileUtils();
|
|
26210
|
-
import
|
|
26211
|
-
import
|
|
26341
|
+
import fs26 from "fs";
|
|
26342
|
+
import path34 from "path";
|
|
26212
26343
|
import AdmZip5 from "adm-zip";
|
|
26213
26344
|
var FileOperations = class {
|
|
26214
26345
|
/**
|
|
@@ -26228,10 +26359,10 @@ var FileOperations = class {
|
|
|
26228
26359
|
let packedFilesCount = 0;
|
|
26229
26360
|
const packedFiles = [];
|
|
26230
26361
|
const excludedFiles = [];
|
|
26231
|
-
const resolvedRepoPath =
|
|
26362
|
+
const resolvedRepoPath = path34.resolve(repositoryPath);
|
|
26232
26363
|
for (const filepath of fileList) {
|
|
26233
|
-
const absoluteFilepath =
|
|
26234
|
-
const resolvedFilePath =
|
|
26364
|
+
const absoluteFilepath = path34.join(repositoryPath, filepath);
|
|
26365
|
+
const resolvedFilePath = path34.resolve(absoluteFilepath);
|
|
26235
26366
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
26236
26367
|
const reason = "potential path traversal security risk";
|
|
26237
26368
|
logDebug(`[FileOperations] Skipping ${filepath} due to ${reason}`);
|
|
@@ -26278,11 +26409,11 @@ var FileOperations = class {
|
|
|
26278
26409
|
fileList,
|
|
26279
26410
|
repositoryPath
|
|
26280
26411
|
}) {
|
|
26281
|
-
const resolvedRepoPath =
|
|
26412
|
+
const resolvedRepoPath = path34.resolve(repositoryPath);
|
|
26282
26413
|
const validatedPaths = [];
|
|
26283
26414
|
for (const filepath of fileList) {
|
|
26284
|
-
const absoluteFilepath =
|
|
26285
|
-
const resolvedFilePath =
|
|
26415
|
+
const absoluteFilepath = path34.join(repositoryPath, filepath);
|
|
26416
|
+
const resolvedFilePath = path34.resolve(absoluteFilepath);
|
|
26286
26417
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
26287
26418
|
logDebug(
|
|
26288
26419
|
`[FileOperations] Rejecting ${filepath} - path traversal attempt detected`
|
|
@@ -26290,7 +26421,7 @@ var FileOperations = class {
|
|
|
26290
26421
|
continue;
|
|
26291
26422
|
}
|
|
26292
26423
|
try {
|
|
26293
|
-
await
|
|
26424
|
+
await fs26.promises.access(absoluteFilepath, fs26.constants.R_OK);
|
|
26294
26425
|
validatedPaths.push(filepath);
|
|
26295
26426
|
} catch (error) {
|
|
26296
26427
|
logDebug(
|
|
@@ -26309,8 +26440,8 @@ var FileOperations = class {
|
|
|
26309
26440
|
const fileDataArray = [];
|
|
26310
26441
|
for (const absolutePath of filePaths) {
|
|
26311
26442
|
try {
|
|
26312
|
-
const content = await
|
|
26313
|
-
const relativePath =
|
|
26443
|
+
const content = await fs26.promises.readFile(absolutePath);
|
|
26444
|
+
const relativePath = path34.basename(absolutePath);
|
|
26314
26445
|
fileDataArray.push({
|
|
26315
26446
|
relativePath,
|
|
26316
26447
|
absolutePath,
|
|
@@ -26335,7 +26466,7 @@ var FileOperations = class {
|
|
|
26335
26466
|
relativeFilepath
|
|
26336
26467
|
}) {
|
|
26337
26468
|
try {
|
|
26338
|
-
return await
|
|
26469
|
+
return await fs26.promises.readFile(absoluteFilepath);
|
|
26339
26470
|
} catch (fsError) {
|
|
26340
26471
|
logError(
|
|
26341
26472
|
`[FileOperations] Failed to read ${relativeFilepath} from filesystem: ${fsError}`
|
|
@@ -26479,7 +26610,7 @@ var executeSecurityScan = async ({
|
|
|
26479
26610
|
fileCount,
|
|
26480
26611
|
// MVS device attribution: a developer appears in the MVS Developers grid
|
|
26481
26612
|
// from scanning alone (no fresh login needed).
|
|
26482
|
-
computerName:
|
|
26613
|
+
computerName: os17.hostname(),
|
|
26483
26614
|
computerUser: getComputerUser(),
|
|
26484
26615
|
clientVersion: packageJson.version
|
|
26485
26616
|
};
|
|
@@ -26629,14 +26760,14 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
26629
26760
|
* since the last scan.
|
|
26630
26761
|
*/
|
|
26631
26762
|
async scanForSecurityVulnerabilities({
|
|
26632
|
-
path:
|
|
26763
|
+
path: path38,
|
|
26633
26764
|
isAllDetectionRulesScan,
|
|
26634
26765
|
isAllFilesScan,
|
|
26635
26766
|
scanContext
|
|
26636
26767
|
}) {
|
|
26637
26768
|
this.hasAuthenticationFailed = false;
|
|
26638
26769
|
logDebug(`[${scanContext}] Scanning for new security vulnerabilities`, {
|
|
26639
|
-
path:
|
|
26770
|
+
path: path38
|
|
26640
26771
|
});
|
|
26641
26772
|
if (!this.gqlClient) {
|
|
26642
26773
|
logInfo(`[${scanContext}] No GQL client found, skipping scan`);
|
|
@@ -26652,11 +26783,11 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
26652
26783
|
}
|
|
26653
26784
|
logDebug(
|
|
26654
26785
|
`[${scanContext}] Connected to the API, assembling list of files to scan`,
|
|
26655
|
-
{ path:
|
|
26786
|
+
{ path: path38 }
|
|
26656
26787
|
);
|
|
26657
26788
|
const isBackgroundScan = scanContext === ScanContext.BACKGROUND_INITIAL || scanContext === ScanContext.BACKGROUND_PERIODIC;
|
|
26658
26789
|
const files = await getLocalFiles({
|
|
26659
|
-
path:
|
|
26790
|
+
path: path38,
|
|
26660
26791
|
isAllFilesScan,
|
|
26661
26792
|
scanContext,
|
|
26662
26793
|
scanRecentlyChangedFiles: !isBackgroundScan
|
|
@@ -26682,13 +26813,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
26682
26813
|
});
|
|
26683
26814
|
const { fixReportId, projectId } = await scanFiles({
|
|
26684
26815
|
fileList: filesToScan.map((file) => file.relativePath),
|
|
26685
|
-
repositoryPath:
|
|
26816
|
+
repositoryPath: path38,
|
|
26686
26817
|
gqlClient: this.gqlClient,
|
|
26687
26818
|
isAllDetectionRulesScan,
|
|
26688
26819
|
scanContext
|
|
26689
26820
|
});
|
|
26690
26821
|
logInfo(
|
|
26691
|
-
`[${scanContext}] Security scan completed for ${
|
|
26822
|
+
`[${scanContext}] Security scan completed for ${path38} reportId: ${fixReportId} projectId: ${projectId}`
|
|
26692
26823
|
);
|
|
26693
26824
|
if (isAllFilesScan) {
|
|
26694
26825
|
return;
|
|
@@ -26992,13 +27123,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
26992
27123
|
});
|
|
26993
27124
|
return scannedFiles.some((file) => file.relativePath === fixFile);
|
|
26994
27125
|
}
|
|
26995
|
-
async getFreshFixes({ path:
|
|
27126
|
+
async getFreshFixes({ path: path38 }) {
|
|
26996
27127
|
const scanContext = ScanContext.USER_REQUEST;
|
|
26997
|
-
logDebug(`[${scanContext}] Getting fresh fixes`, { path:
|
|
26998
|
-
if (this.path !==
|
|
26999
|
-
this.path =
|
|
27128
|
+
logDebug(`[${scanContext}] Getting fresh fixes`, { path: path38 });
|
|
27129
|
+
if (this.path !== path38) {
|
|
27130
|
+
this.path = path38;
|
|
27000
27131
|
this.reset();
|
|
27001
|
-
logInfo(`[${scanContext}] Reset service state for new path`, { path:
|
|
27132
|
+
logInfo(`[${scanContext}] Reset service state for new path`, { path: path38 });
|
|
27002
27133
|
}
|
|
27003
27134
|
try {
|
|
27004
27135
|
const loginContext = createMcpLoginContext("check_new_fixes");
|
|
@@ -27017,7 +27148,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
27017
27148
|
}
|
|
27018
27149
|
throw error;
|
|
27019
27150
|
}
|
|
27020
|
-
this.triggerScan({ path:
|
|
27151
|
+
this.triggerScan({ path: path38, gqlClient: this.gqlClient });
|
|
27021
27152
|
let isMvsAutoFixEnabled = null;
|
|
27022
27153
|
try {
|
|
27023
27154
|
isMvsAutoFixEnabled = await this.gqlClient.getMvsAutoFixSettings();
|
|
@@ -27051,33 +27182,33 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
27051
27182
|
return noFreshFixesPrompt;
|
|
27052
27183
|
}
|
|
27053
27184
|
triggerScan({
|
|
27054
|
-
path:
|
|
27185
|
+
path: path38,
|
|
27055
27186
|
gqlClient
|
|
27056
27187
|
}) {
|
|
27057
|
-
if (this.path !==
|
|
27058
|
-
this.path =
|
|
27188
|
+
if (this.path !== path38) {
|
|
27189
|
+
this.path = path38;
|
|
27059
27190
|
this.reset();
|
|
27060
|
-
logInfo(`Reset service state for new path in triggerScan`, { path:
|
|
27191
|
+
logInfo(`Reset service state for new path in triggerScan`, { path: path38 });
|
|
27061
27192
|
}
|
|
27062
27193
|
this.gqlClient = gqlClient;
|
|
27063
27194
|
if (!this.intervalId) {
|
|
27064
|
-
this.startPeriodicScanning(
|
|
27065
|
-
this.executeInitialScan(
|
|
27066
|
-
void this.executeInitialFullScan(
|
|
27195
|
+
this.startPeriodicScanning(path38);
|
|
27196
|
+
this.executeInitialScan(path38);
|
|
27197
|
+
void this.executeInitialFullScan(path38);
|
|
27067
27198
|
}
|
|
27068
27199
|
}
|
|
27069
|
-
startPeriodicScanning(
|
|
27200
|
+
startPeriodicScanning(path38) {
|
|
27070
27201
|
const scanContext = ScanContext.BACKGROUND_PERIODIC;
|
|
27071
27202
|
logDebug(
|
|
27072
27203
|
`[${scanContext}] Starting periodic scan for new security vulnerabilities`,
|
|
27073
27204
|
{
|
|
27074
|
-
path:
|
|
27205
|
+
path: path38
|
|
27075
27206
|
}
|
|
27076
27207
|
);
|
|
27077
27208
|
this.intervalId = setInterval(() => {
|
|
27078
|
-
logDebug(`[${scanContext}] Triggering periodic security scan`, { path:
|
|
27209
|
+
logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path38 });
|
|
27079
27210
|
this.scanForSecurityVulnerabilities({
|
|
27080
|
-
path:
|
|
27211
|
+
path: path38,
|
|
27081
27212
|
scanContext
|
|
27082
27213
|
}).catch((error) => {
|
|
27083
27214
|
logError(`[${scanContext}] Error during periodic security scan`, {
|
|
@@ -27086,45 +27217,45 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
27086
27217
|
});
|
|
27087
27218
|
}, MCP_PERIODIC_CHECK_INTERVAL);
|
|
27088
27219
|
}
|
|
27089
|
-
async executeInitialFullScan(
|
|
27220
|
+
async executeInitialFullScan(path38) {
|
|
27090
27221
|
const scanContext = ScanContext.FULL_SCAN;
|
|
27091
|
-
logDebug(`[${scanContext}] Triggering initial full security scan`, { path:
|
|
27222
|
+
logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path38 });
|
|
27092
27223
|
logDebug(`[${scanContext}] Full scan paths scanned`, {
|
|
27093
27224
|
fullScanPathsScanned: this.fullScanPathsScanned
|
|
27094
27225
|
});
|
|
27095
|
-
if (this.fullScanPathsScanned.includes(
|
|
27226
|
+
if (this.fullScanPathsScanned.includes(path38)) {
|
|
27096
27227
|
logDebug(`[${scanContext}] Full scan already executed for this path`, {
|
|
27097
|
-
path:
|
|
27228
|
+
path: path38
|
|
27098
27229
|
});
|
|
27099
27230
|
return;
|
|
27100
27231
|
}
|
|
27101
27232
|
configStore.set("fullScanPathsScanned", [
|
|
27102
27233
|
...this.fullScanPathsScanned,
|
|
27103
|
-
|
|
27234
|
+
path38
|
|
27104
27235
|
]);
|
|
27105
27236
|
try {
|
|
27106
27237
|
await this.scanForSecurityVulnerabilities({
|
|
27107
|
-
path:
|
|
27238
|
+
path: path38,
|
|
27108
27239
|
isAllFilesScan: true,
|
|
27109
27240
|
isAllDetectionRulesScan: true,
|
|
27110
27241
|
scanContext: ScanContext.FULL_SCAN
|
|
27111
27242
|
});
|
|
27112
|
-
if (!this.fullScanPathsScanned.includes(
|
|
27113
|
-
this.fullScanPathsScanned.push(
|
|
27243
|
+
if (!this.fullScanPathsScanned.includes(path38)) {
|
|
27244
|
+
this.fullScanPathsScanned.push(path38);
|
|
27114
27245
|
configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
|
|
27115
27246
|
}
|
|
27116
|
-
logInfo(`[${scanContext}] Full scan completed`, { path:
|
|
27247
|
+
logInfo(`[${scanContext}] Full scan completed`, { path: path38 });
|
|
27117
27248
|
} catch (error) {
|
|
27118
27249
|
logError(`[${scanContext}] Error during initial full security scan`, {
|
|
27119
27250
|
error
|
|
27120
27251
|
});
|
|
27121
27252
|
}
|
|
27122
27253
|
}
|
|
27123
|
-
executeInitialScan(
|
|
27254
|
+
executeInitialScan(path38) {
|
|
27124
27255
|
const scanContext = ScanContext.BACKGROUND_INITIAL;
|
|
27125
|
-
logDebug(`[${scanContext}] Triggering initial security scan`, { path:
|
|
27256
|
+
logDebug(`[${scanContext}] Triggering initial security scan`, { path: path38 });
|
|
27126
27257
|
this.scanForSecurityVulnerabilities({
|
|
27127
|
-
path:
|
|
27258
|
+
path: path38,
|
|
27128
27259
|
scanContext: ScanContext.BACKGROUND_INITIAL
|
|
27129
27260
|
}).catch((error) => {
|
|
27130
27261
|
logError(`[${scanContext}] Error during initial security scan`, { error });
|
|
@@ -27225,9 +27356,9 @@ Example payload:
|
|
|
27225
27356
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
27226
27357
|
);
|
|
27227
27358
|
}
|
|
27228
|
-
const
|
|
27359
|
+
const path38 = pathValidationResult.path;
|
|
27229
27360
|
const resultText = await this.newFixesService.getFreshFixes({
|
|
27230
|
-
path:
|
|
27361
|
+
path: path38
|
|
27231
27362
|
});
|
|
27232
27363
|
logInfo("CheckForNewAvailableFixesTool execution completed", {
|
|
27233
27364
|
resultText
|
|
@@ -27408,8 +27539,8 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
27408
27539
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
27409
27540
|
);
|
|
27410
27541
|
}
|
|
27411
|
-
const
|
|
27412
|
-
const gitService = new GitService(
|
|
27542
|
+
const path38 = pathValidationResult.path;
|
|
27543
|
+
const gitService = new GitService(path38, log);
|
|
27413
27544
|
const gitValidation = await gitService.validateRepository();
|
|
27414
27545
|
if (!gitValidation.isValid) {
|
|
27415
27546
|
throw new Error(`Invalid git repository: ${gitValidation.error}`);
|
|
@@ -27446,7 +27577,7 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
27446
27577
|
}
|
|
27447
27578
|
const fixResult = await this.availableFixesService.checkForAvailableFixes({
|
|
27448
27579
|
repoUrl: originUrl,
|
|
27449
|
-
repositoryPath:
|
|
27580
|
+
repositoryPath: path38,
|
|
27450
27581
|
limit: args.limit,
|
|
27451
27582
|
offset: args.offset,
|
|
27452
27583
|
fileFilter: actualFileFilter
|
|
@@ -28031,7 +28162,7 @@ Example payload (Mode B \u2014 abstain from every interactive fix, no rescan):
|
|
|
28031
28162
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
28032
28163
|
);
|
|
28033
28164
|
}
|
|
28034
|
-
const
|
|
28165
|
+
const path38 = pathValidationResult.path;
|
|
28035
28166
|
if (args.interactiveAnswers !== void 0) {
|
|
28036
28167
|
if (args.interactiveAnswers.length === 0) {
|
|
28037
28168
|
return this.createSuccessResponse(
|
|
@@ -28041,7 +28172,7 @@ Example payload (Mode B \u2014 abstain from every interactive fix, no rescan):
|
|
|
28041
28172
|
try {
|
|
28042
28173
|
const result = await this.vulnerabilityFixService.applyInteractiveAnswers({
|
|
28043
28174
|
interactiveAnswers: args.interactiveAnswers,
|
|
28044
|
-
repositoryPath:
|
|
28175
|
+
repositoryPath: path38
|
|
28045
28176
|
});
|
|
28046
28177
|
return this.createSuccessResponse(result);
|
|
28047
28178
|
} catch (error) {
|
|
@@ -28053,7 +28184,7 @@ Example payload (Mode B \u2014 abstain from every interactive fix, no rescan):
|
|
|
28053
28184
|
}
|
|
28054
28185
|
}
|
|
28055
28186
|
const files = await getLocalFiles({
|
|
28056
|
-
path:
|
|
28187
|
+
path: path38,
|
|
28057
28188
|
maxFileSize: MCP_MAX_FILE_SIZE,
|
|
28058
28189
|
maxFiles: args.maxFiles,
|
|
28059
28190
|
scanContext: ScanContext.USER_REQUEST,
|
|
@@ -28073,7 +28204,7 @@ Example payload (Mode B \u2014 abstain from every interactive fix, no rescan):
|
|
|
28073
28204
|
try {
|
|
28074
28205
|
const fixResult = await this.vulnerabilityFixService.processVulnerabilities({
|
|
28075
28206
|
fileList: files.map((file) => file.relativePath),
|
|
28076
|
-
repositoryPath:
|
|
28207
|
+
repositoryPath: path38,
|
|
28077
28208
|
offset: args.offset,
|
|
28078
28209
|
limit: args.limit,
|
|
28079
28210
|
isRescan: args.rescan || !!args.maxFiles
|
|
@@ -28177,7 +28308,7 @@ var mcpHandler = async (_args) => {
|
|
|
28177
28308
|
};
|
|
28178
28309
|
|
|
28179
28310
|
// src/args/commands/review.ts
|
|
28180
|
-
import
|
|
28311
|
+
import fs27 from "fs";
|
|
28181
28312
|
import chalk12 from "chalk";
|
|
28182
28313
|
function reviewBuilder(yargs2) {
|
|
28183
28314
|
return yargs2.option("f", {
|
|
@@ -28214,7 +28345,7 @@ function reviewBuilder(yargs2) {
|
|
|
28214
28345
|
).help();
|
|
28215
28346
|
}
|
|
28216
28347
|
function validateReviewOptions(argv) {
|
|
28217
|
-
if (!
|
|
28348
|
+
if (!fs27.existsSync(argv.f)) {
|
|
28218
28349
|
throw new CliError(`
|
|
28219
28350
|
Can't access ${chalk12.bold(argv.f)}`);
|
|
28220
28351
|
}
|
|
@@ -28374,10 +28505,10 @@ init_client_generates();
|
|
|
28374
28505
|
init_urlParser2();
|
|
28375
28506
|
|
|
28376
28507
|
// src/features/codeium_intellij/codeium_language_server_grpc_client.ts
|
|
28377
|
-
import
|
|
28508
|
+
import path35 from "path";
|
|
28378
28509
|
import * as grpc from "@grpc/grpc-js";
|
|
28379
28510
|
import * as protoLoader from "@grpc/proto-loader";
|
|
28380
|
-
var PROTO_PATH =
|
|
28511
|
+
var PROTO_PATH = path35.join(
|
|
28381
28512
|
getModuleRootDir(),
|
|
28382
28513
|
"src/features/codeium_intellij/proto/exa/language_server_pb/language_server.proto"
|
|
28383
28514
|
);
|
|
@@ -28389,7 +28520,7 @@ function loadProto() {
|
|
|
28389
28520
|
defaults: true,
|
|
28390
28521
|
oneofs: true,
|
|
28391
28522
|
includeDirs: [
|
|
28392
|
-
|
|
28523
|
+
path35.join(getModuleRootDir(), "src/features/codeium_intellij/proto")
|
|
28393
28524
|
]
|
|
28394
28525
|
});
|
|
28395
28526
|
return grpc.loadPackageDefinition(
|
|
@@ -28443,30 +28574,30 @@ async function getGrpcClient(port, csrf) {
|
|
|
28443
28574
|
}
|
|
28444
28575
|
|
|
28445
28576
|
// src/features/codeium_intellij/parse_intellij_logs.ts
|
|
28446
|
-
import
|
|
28447
|
-
import
|
|
28448
|
-
import
|
|
28577
|
+
import fs28 from "fs";
|
|
28578
|
+
import os18 from "os";
|
|
28579
|
+
import path36 from "path";
|
|
28449
28580
|
function getLogsDir() {
|
|
28450
28581
|
if (process.platform === "darwin") {
|
|
28451
|
-
return
|
|
28582
|
+
return path36.join(os18.homedir(), "Library/Logs/JetBrains");
|
|
28452
28583
|
} else if (process.platform === "win32") {
|
|
28453
|
-
return
|
|
28454
|
-
process.env["LOCALAPPDATA"] ||
|
|
28584
|
+
return path36.join(
|
|
28585
|
+
process.env["LOCALAPPDATA"] || path36.join(os18.homedir(), "AppData/Local"),
|
|
28455
28586
|
"JetBrains"
|
|
28456
28587
|
);
|
|
28457
28588
|
} else {
|
|
28458
|
-
return
|
|
28589
|
+
return path36.join(os18.homedir(), ".cache/JetBrains");
|
|
28459
28590
|
}
|
|
28460
28591
|
}
|
|
28461
28592
|
function parseIdeLogDir(ideLogDir) {
|
|
28462
|
-
const logFiles =
|
|
28593
|
+
const logFiles = fs28.readdirSync(ideLogDir).filter((f) => /^idea(\.\d+)?\.log$/.test(f)).map((f) => ({
|
|
28463
28594
|
name: f,
|
|
28464
|
-
mtime:
|
|
28595
|
+
mtime: fs28.statSync(path36.join(ideLogDir, f)).mtimeMs
|
|
28465
28596
|
})).sort((a, b) => a.mtime - b.mtime).map((f) => f.name);
|
|
28466
28597
|
let latestCsrf = null;
|
|
28467
28598
|
let latestPort = null;
|
|
28468
28599
|
for (const logFile of logFiles) {
|
|
28469
|
-
const lines =
|
|
28600
|
+
const lines = fs28.readFileSync(path36.join(ideLogDir, logFile), "utf-8").split("\n");
|
|
28470
28601
|
for (const line of lines) {
|
|
28471
28602
|
if (!line.includes(
|
|
28472
28603
|
"com.codeium.intellij.language_server.LanguageServerProcessHandler"
|
|
@@ -28492,13 +28623,13 @@ function parseIdeLogDir(ideLogDir) {
|
|
|
28492
28623
|
function findRunningCodeiumLanguageServers() {
|
|
28493
28624
|
const results = [];
|
|
28494
28625
|
const logsDir = getLogsDir();
|
|
28495
|
-
if (!
|
|
28496
|
-
for (const ide of
|
|
28497
|
-
let ideLogDir =
|
|
28626
|
+
if (!fs28.existsSync(logsDir)) return results;
|
|
28627
|
+
for (const ide of fs28.readdirSync(logsDir)) {
|
|
28628
|
+
let ideLogDir = path36.join(logsDir, ide);
|
|
28498
28629
|
if (process.platform !== "darwin") {
|
|
28499
|
-
ideLogDir =
|
|
28630
|
+
ideLogDir = path36.join(ideLogDir, "log");
|
|
28500
28631
|
}
|
|
28501
|
-
if (!
|
|
28632
|
+
if (!fs28.existsSync(ideLogDir) || !fs28.statSync(ideLogDir).isDirectory()) {
|
|
28502
28633
|
continue;
|
|
28503
28634
|
}
|
|
28504
28635
|
const result = parseIdeLogDir(ideLogDir);
|
|
@@ -28678,11 +28809,11 @@ function processChatStepCodeAction(step) {
|
|
|
28678
28809
|
|
|
28679
28810
|
// src/features/codeium_intellij/install_hook.ts
|
|
28680
28811
|
import fsPromises5 from "fs/promises";
|
|
28681
|
-
import
|
|
28682
|
-
import
|
|
28812
|
+
import os19 from "os";
|
|
28813
|
+
import path37 from "path";
|
|
28683
28814
|
import chalk14 from "chalk";
|
|
28684
28815
|
function getCodeiumHooksPath() {
|
|
28685
|
-
return
|
|
28816
|
+
return path37.join(os19.homedir(), ".codeium", "hooks.json");
|
|
28686
28817
|
}
|
|
28687
28818
|
async function readCodeiumHooks() {
|
|
28688
28819
|
const hooksPath = getCodeiumHooksPath();
|
|
@@ -28695,7 +28826,7 @@ async function readCodeiumHooks() {
|
|
|
28695
28826
|
}
|
|
28696
28827
|
async function writeCodeiumHooks(config2) {
|
|
28697
28828
|
const hooksPath = getCodeiumHooksPath();
|
|
28698
|
-
const dir =
|
|
28829
|
+
const dir = path37.dirname(hooksPath);
|
|
28699
28830
|
await fsPromises5.mkdir(dir, { recursive: true });
|
|
28700
28831
|
await fsPromises5.writeFile(
|
|
28701
28832
|
hooksPath,
|