mobbdev 1.4.2 → 1.4.7
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 +91 -11
- package/dist/index.mjs +713 -310
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -94,6 +94,9 @@ function getSdk(client, withWrapper = defaultWrapper) {
|
|
|
94
94
|
performCliLogin(variables, requestHeaders, signal) {
|
|
95
95
|
return withWrapper((wrappedRequestHeaders) => client.request({ document: PerformCliLoginDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "performCliLogin", "mutation", variables);
|
|
96
96
|
},
|
|
97
|
+
SetQuarantineEnabled(variables, requestHeaders, signal) {
|
|
98
|
+
return withWrapper((wrappedRequestHeaders) => client.request({ document: SetQuarantineEnabledDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "SetQuarantineEnabled", "mutation", variables);
|
|
99
|
+
},
|
|
97
100
|
CreateProject(variables, requestHeaders, signal) {
|
|
98
101
|
return withWrapper((wrappedRequestHeaders) => client.request({ document: CreateProjectDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "CreateProject", "mutation", variables);
|
|
99
102
|
},
|
|
@@ -135,7 +138,7 @@ function getSdk(client, withWrapper = defaultWrapper) {
|
|
|
135
138
|
}
|
|
136
139
|
};
|
|
137
140
|
}
|
|
138
|
-
var AiBlameInferenceType, FixQuestionInputType, Language, ManifestAction, Effort_To_Apply_Fix_Enum, Fix_Rating_Tag_Enum, Fix_Report_State_Enum, Fix_State_Enum, IssueLanguage_Enum, IssueType_Enum, Pr_Status_Enum, Project_Role_Type_Enum, Vulnerability_Report_Issue_Category_Enum, Vulnerability_Report_Issue_State_Enum, Vulnerability_Report_Issue_Tag_Enum, Vulnerability_Report_Vendor_Enum, Vulnerability_Severity_Enum, FixDetailsFragmentDoc, FixReportSummaryFieldsFragmentDoc, MeDocument, GetLastOrgAndNamedProjectDocument, GetLastOrgDocument, GetEncryptedApiTokenDocument, FixReportStateDocument, GetVulnerabilityReportPathsDocument, GetAnalysisSubscriptionDocument, GetAnalysisDocument, GetFixesDocument, GetVulByNodesMetadataDocument, GetFalsePositiveDocument, UpdateScmTokenDocument, UploadS3BucketInfoDocument, GetTracyDiffUploadUrlDocument, AnalyzeCommitForExtensionAiBlameDocument, GetAiBlameInferenceDocument, GetAiBlameAttributionPromptDocument, GetPromptSummaryDocument, UploadAiBlameInferencesInitDocument, FinalizeAiBlameInferencesUploadDocument, UploadTracyRecordsDocument, GetTracyRawDataUploadUrlDocument, DigestVulnerabilityReportDocument, SubmitVulnerabilityReportDocument, CreateCommunityUserDocument, CreateCliLoginDocument, PerformCliLoginDocument, CreateProjectDocument, ValidateRepoUrlDocument, GitReferenceDocument, AutoPrAnalysisDocument, GetFixReportsByRepoUrlDocument, GetReportFixesDocument, GetLatestReportByRepoUrlDocument, UpdateDownloadedFixDataDocument, GetUserMvsAutoFixDocument, StreamBlameAiAnalysisRequestsDocument, StreamCommitBlameRequestsDocument, ScanSkillDocument, SkillVerdictsByMd5Document, defaultWrapper;
|
|
141
|
+
var AiBlameInferenceType, FixQuestionInputType, Language, ManifestAction, Effort_To_Apply_Fix_Enum, Fix_Rating_Tag_Enum, Fix_Report_State_Enum, Fix_State_Enum, IssueLanguage_Enum, IssueType_Enum, Pr_Status_Enum, Project_Role_Type_Enum, Vulnerability_Report_Issue_Category_Enum, Vulnerability_Report_Issue_State_Enum, Vulnerability_Report_Issue_Tag_Enum, Vulnerability_Report_Vendor_Enum, Vulnerability_Severity_Enum, FixDetailsFragmentDoc, FixReportSummaryFieldsFragmentDoc, MeDocument, GetLastOrgAndNamedProjectDocument, GetLastOrgDocument, GetEncryptedApiTokenDocument, FixReportStateDocument, GetVulnerabilityReportPathsDocument, GetAnalysisSubscriptionDocument, GetAnalysisDocument, GetFixesDocument, GetVulByNodesMetadataDocument, GetFalsePositiveDocument, UpdateScmTokenDocument, UploadS3BucketInfoDocument, GetTracyDiffUploadUrlDocument, AnalyzeCommitForExtensionAiBlameDocument, GetAiBlameInferenceDocument, GetAiBlameAttributionPromptDocument, GetPromptSummaryDocument, UploadAiBlameInferencesInitDocument, FinalizeAiBlameInferencesUploadDocument, UploadTracyRecordsDocument, GetTracyRawDataUploadUrlDocument, DigestVulnerabilityReportDocument, SubmitVulnerabilityReportDocument, CreateCommunityUserDocument, CreateCliLoginDocument, PerformCliLoginDocument, SetQuarantineEnabledDocument, CreateProjectDocument, ValidateRepoUrlDocument, GitReferenceDocument, AutoPrAnalysisDocument, GetFixReportsByRepoUrlDocument, GetReportFixesDocument, GetLatestReportByRepoUrlDocument, UpdateDownloadedFixDataDocument, GetUserMvsAutoFixDocument, StreamBlameAiAnalysisRequestsDocument, StreamCommitBlameRequestsDocument, ScanSkillDocument, SkillVerdictsByMd5Document, defaultWrapper;
|
|
139
142
|
var init_client_generates = __esm({
|
|
140
143
|
"src/features/analysis/scm/generates/client_generates.ts"() {
|
|
141
144
|
"use strict";
|
|
@@ -260,6 +263,7 @@ var init_client_generates = __esm({
|
|
|
260
263
|
IssueType_Enum2["HttpParameterPollution"] = "HTTP_PARAMETER_POLLUTION";
|
|
261
264
|
IssueType_Enum2["HttpResponseSplitting"] = "HTTP_RESPONSE_SPLITTING";
|
|
262
265
|
IssueType_Enum2["IframeWithoutSandbox"] = "IFRAME_WITHOUT_SANDBOX";
|
|
266
|
+
IssueType_Enum2["ImproperCertificateValidation"] = "IMPROPER_CERTIFICATE_VALIDATION";
|
|
263
267
|
IssueType_Enum2["ImproperExceptionHandling"] = "IMPROPER_EXCEPTION_HANDLING";
|
|
264
268
|
IssueType_Enum2["ImproperResourceShutdownOrRelease"] = "IMPROPER_RESOURCE_SHUTDOWN_OR_RELEASE";
|
|
265
269
|
IssueType_Enum2["ImproperStringFormatting"] = "IMPROPER_STRING_FORMATTING";
|
|
@@ -278,6 +282,7 @@ var init_client_generates = __esm({
|
|
|
278
282
|
IssueType_Enum2["InsecureTmpFile"] = "INSECURE_TMP_FILE";
|
|
279
283
|
IssueType_Enum2["InsecureUuidVersion"] = "INSECURE_UUID_VERSION";
|
|
280
284
|
IssueType_Enum2["InsufficientLogging"] = "INSUFFICIENT_LOGGING";
|
|
285
|
+
IssueType_Enum2["J2EeGetConnection"] = "J2EE_GET_CONNECTION";
|
|
281
286
|
IssueType_Enum2["JqueryDeprecatedSymbols"] = "JQUERY_DEPRECATED_SYMBOLS";
|
|
282
287
|
IssueType_Enum2["LeftoverDebugCode"] = "LEFTOVER_DEBUG_CODE";
|
|
283
288
|
IssueType_Enum2["LocaleDependentComparison"] = "LOCALE_DEPENDENT_COMPARISON";
|
|
@@ -941,6 +946,12 @@ var init_client_generates = __esm({
|
|
|
941
946
|
level
|
|
942
947
|
justification
|
|
943
948
|
}
|
|
949
|
+
appliedSkills
|
|
950
|
+
mcpCalls {
|
|
951
|
+
mcpServer
|
|
952
|
+
mcpTool
|
|
953
|
+
callCount
|
|
954
|
+
}
|
|
944
955
|
}
|
|
945
956
|
}
|
|
946
957
|
... on PromptSummaryProcessing {
|
|
@@ -1092,6 +1103,13 @@ var init_client_generates = __esm({
|
|
|
1092
1103
|
performCliLogin(loginId: $loginId) {
|
|
1093
1104
|
status
|
|
1094
1105
|
}
|
|
1106
|
+
}
|
|
1107
|
+
`;
|
|
1108
|
+
SetQuarantineEnabledDocument = `
|
|
1109
|
+
mutation SetQuarantineEnabled($enabled: Boolean!) {
|
|
1110
|
+
update_organization(where: {}, _set: {quarantineEnabled: $enabled}) {
|
|
1111
|
+
affected_rows
|
|
1112
|
+
}
|
|
1095
1113
|
}
|
|
1096
1114
|
`;
|
|
1097
1115
|
CreateProjectDocument = `
|
|
@@ -1277,12 +1295,15 @@ var init_client_generates = __esm({
|
|
|
1277
1295
|
SkillVerdictsByMd5Document = `
|
|
1278
1296
|
query SkillVerdictsByMd5($md5s: [String!]!) {
|
|
1279
1297
|
skillVerdictsByMd5(md5s: $md5s) {
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1298
|
+
quarantineEnabled
|
|
1299
|
+
verdicts {
|
|
1300
|
+
md5
|
|
1301
|
+
verdict
|
|
1302
|
+
summary
|
|
1303
|
+
scannerName
|
|
1304
|
+
scannerVersion
|
|
1305
|
+
scannedAt
|
|
1306
|
+
}
|
|
1286
1307
|
}
|
|
1287
1308
|
}
|
|
1288
1309
|
`;
|
|
@@ -1400,6 +1421,7 @@ var init_getIssueType = __esm({
|
|
|
1400
1421
|
["NO_EQUIVALENCE_METHOD" /* NoEquivalenceMethod */]: "Class Does Not Implement Equivalence Method",
|
|
1401
1422
|
["INFORMATION_EXPOSURE_VIA_HEADERS" /* InformationExposureViaHeaders */]: "Information Exposure via Headers",
|
|
1402
1423
|
["DEBUG_ENABLED" /* DebugEnabled */]: "Debug Enabled",
|
|
1424
|
+
["J2EE_GET_CONNECTION" /* J2EeGetConnection */]: "J2EE Bad Practices: getConnection()",
|
|
1403
1425
|
["LEFTOVER_DEBUG_CODE" /* LeftoverDebugCode */]: "Leftover Debug Code",
|
|
1404
1426
|
["POOR_ERROR_HANDLING_EMPTY_CATCH_BLOCK" /* PoorErrorHandlingEmptyCatchBlock */]: "Poor Error Handling: Empty Catch Block",
|
|
1405
1427
|
["ERRONEOUS_STRING_COMPARE" /* ErroneousStringCompare */]: "Erroneous String Compare",
|
|
@@ -1474,7 +1496,8 @@ var init_getIssueType = __esm({
|
|
|
1474
1496
|
["TAINTED_NUMERIC_CAST" /* TaintedNumericCast */]: "Tainted Numeric Cast",
|
|
1475
1497
|
["MISSING_X_FRAME_OPTIONS" /* MissingXFrameOptions */]: "Missing X-Frame-Options Header",
|
|
1476
1498
|
["IMPROPER_VALIDATION_OF_ARRAY_INDEX" /* ImproperValidationOfArrayIndex */]: "Improper Validation of Array Index",
|
|
1477
|
-
["INCORRECT_INTEGER_CONVERSION" /* IncorrectIntegerConversion */]: "Incorrect Integer Conversion"
|
|
1499
|
+
["INCORRECT_INTEGER_CONVERSION" /* IncorrectIntegerConversion */]: "Incorrect Integer Conversion",
|
|
1500
|
+
["IMPROPER_CERTIFICATE_VALIDATION" /* ImproperCertificateValidation */]: "Improper Certificate Validation"
|
|
1478
1501
|
};
|
|
1479
1502
|
issueTypeZ = z.nativeEnum(IssueType_Enum);
|
|
1480
1503
|
getIssueTypeFriendlyString = (issueType) => {
|
|
@@ -3601,8 +3624,8 @@ var init_FileUtils = __esm({
|
|
|
3601
3624
|
const fullPath = path.join(dir, item);
|
|
3602
3625
|
try {
|
|
3603
3626
|
await fsPromises.access(fullPath, fs.constants.R_OK);
|
|
3604
|
-
const
|
|
3605
|
-
if (
|
|
3627
|
+
const stat5 = await fsPromises.stat(fullPath);
|
|
3628
|
+
if (stat5.isDirectory()) {
|
|
3606
3629
|
if (isRootLevel && excludedRootDirectories.includes(item)) {
|
|
3607
3630
|
continue;
|
|
3608
3631
|
}
|
|
@@ -3614,7 +3637,7 @@ var init_FileUtils = __esm({
|
|
|
3614
3637
|
name: item,
|
|
3615
3638
|
fullPath,
|
|
3616
3639
|
relativePath: path.relative(rootDir, fullPath),
|
|
3617
|
-
time:
|
|
3640
|
+
time: stat5.mtime.getTime(),
|
|
3618
3641
|
isFile: true
|
|
3619
3642
|
});
|
|
3620
3643
|
}
|
|
@@ -4568,6 +4591,7 @@ var fixDetailsData = {
|
|
|
4568
4591
|
issueDescription: "A data member and a function have the same name which can be confusing to the developer.",
|
|
4569
4592
|
fixInstructions: "Rename the data member to avoid confusion."
|
|
4570
4593
|
},
|
|
4594
|
+
["J2EE_GET_CONNECTION" /* J2EeGetConnection */]: void 0,
|
|
4571
4595
|
["LEFTOVER_DEBUG_CODE" /* LeftoverDebugCode */]: void 0,
|
|
4572
4596
|
["UNVALIDATED_PUBLIC_METHOD_ARGUMENT" /* UnvalidatedPublicMethodArgument */]: void 0,
|
|
4573
4597
|
["ERRONEOUS_STRING_COMPARE" /* ErroneousStringCompare */]: void 0,
|
|
@@ -4670,7 +4694,8 @@ var fixDetailsData = {
|
|
|
4670
4694
|
["TAINTED_NUMERIC_CAST" /* TaintedNumericCast */]: void 0,
|
|
4671
4695
|
["MISSING_X_FRAME_OPTIONS" /* MissingXFrameOptions */]: void 0,
|
|
4672
4696
|
["IMPROPER_VALIDATION_OF_ARRAY_INDEX" /* ImproperValidationOfArrayIndex */]: void 0,
|
|
4673
|
-
["INCORRECT_INTEGER_CONVERSION" /* IncorrectIntegerConversion */]: void 0
|
|
4697
|
+
["INCORRECT_INTEGER_CONVERSION" /* IncorrectIntegerConversion */]: void 0,
|
|
4698
|
+
["IMPROPER_CERTIFICATE_VALIDATION" /* ImproperCertificateValidation */]: void 0
|
|
4674
4699
|
};
|
|
4675
4700
|
|
|
4676
4701
|
// src/features/analysis/scm/shared/src/commitDescriptionMarkup.ts
|
|
@@ -4834,6 +4859,31 @@ var go_default = vulnerabilities3;
|
|
|
4834
4859
|
// src/features/analysis/scm/shared/src/storedFixData/java/index.ts
|
|
4835
4860
|
init_client_generates();
|
|
4836
4861
|
|
|
4862
|
+
// src/features/analysis/scm/shared/src/storedFixData/java/j2eeGetConnection.ts
|
|
4863
|
+
var j2eeGetConnection = {
|
|
4864
|
+
guidance: () => `This fix replaces direct \`DriverManager.getConnection(...)\` calls with a container-managed JNDI \`DataSource\` lookup. The new code expects the app server (Tomcat / WildFly / WebSphere / etc.) to expose a configured connection pool under the JNDI name you specified.
|
|
4865
|
+
|
|
4866
|
+
|
|
4867
|
+
|
|
4868
|
+
|
|
4869
|
+
***Make sure the resource pool exists before merging.*** The patched code will throw a \`NamingException\` at runtime if the JNDI name does not resolve. Configure it in your container's resource definition:
|
|
4870
|
+
|
|
4871
|
+
- **Tomcat**: declare a \`<Resource>\` element in \`context.xml\` (or per-app \`META-INF/context.xml\`) with the same JNDI name, plus \`url\`, \`username\`, \`password\`, \`driverClassName\`, and any pool sizing.
|
|
4872
|
+
- **Spring Boot (embedded Tomcat)**: configure via \`spring.datasource.jndi-name\` and matching \`<Resource>\`, or use \`@ConfigurationProperties\` to bind a \`DataSource\` bean.
|
|
4873
|
+
- **WildFly / JBoss EAP**: declare a \`<datasource>\` in the standalone/domain XML and reference its JNDI binding.
|
|
4874
|
+
- **WebSphere / WebLogic**: define the JDBC provider and data source through the admin console; bind it to the JNDI name.
|
|
4875
|
+
|
|
4876
|
+
|
|
4877
|
+
|
|
4878
|
+
|
|
4879
|
+
Also add a matching \`<resource-ref>\` (or \`<data-source>\`) in your \`WEB-INF/web.xml\` if you use one. The original connection details (URL, user, password) move from the call site into the resource definition \u2014 remove them from any constants / properties files where they were duplicated.
|
|
4880
|
+
|
|
4881
|
+
|
|
4882
|
+
|
|
4883
|
+
|
|
4884
|
+
This fix is mandated by the J2EE / Jakarta EE specification (CWE-245) \u2014 direct driver management bypasses the container's pooling, retry, and failover policies.`
|
|
4885
|
+
};
|
|
4886
|
+
|
|
4837
4887
|
// src/features/analysis/scm/shared/src/storedFixData/java/sqlInjection.ts
|
|
4838
4888
|
var sqlInjection = {
|
|
4839
4889
|
guidance: ({
|
|
@@ -4861,6 +4911,7 @@ var systemInformationLeak = {
|
|
|
4861
4911
|
// src/features/analysis/scm/shared/src/storedFixData/java/index.ts
|
|
4862
4912
|
var vulnerabilities4 = {
|
|
4863
4913
|
["PASSWORD_IN_COMMENT" /* PasswordInComment */]: passwordInComment,
|
|
4914
|
+
["J2EE_GET_CONNECTION" /* J2EeGetConnection */]: j2eeGetConnection,
|
|
4864
4915
|
["SQL_Injection" /* SqlInjection */]: sqlInjection,
|
|
4865
4916
|
["SYSTEM_INFORMATION_LEAK" /* SystemInformationLeak */]: systemInformationLeak
|
|
4866
4917
|
};
|
|
@@ -4945,10 +4996,24 @@ See more information [here](https://jinja.palletsprojects.com/en/3.1.x/templates
|
|
|
4945
4996
|
***Note: make sure that none of the data you're marking as safe is coming from user input, as this can lead to XSS vulnerabilities!***`
|
|
4946
4997
|
};
|
|
4947
4998
|
|
|
4999
|
+
// src/features/analysis/scm/shared/src/storedFixData/python/improperCertificateValidation.ts
|
|
5000
|
+
var improperCertificateValidation = {
|
|
5001
|
+
guidance: () => `This fix re-enables TLS certificate validation by changing \`verify=False\` to \`verify=True\` on the HTTP request. Any call that was deliberately reaching a server with a self-signed, expired, or otherwise untrusted certificate will start raising \`ssl.SSLError\` / \`requests.exceptions.SSLError\` after this change.
|
|
5002
|
+
|
|
5003
|
+
|
|
5004
|
+
|
|
5005
|
+
***Before merging, confirm that every endpoint reached by this call presents a certificate signed by a trusted CA.*** If the call must talk to an internal service that uses a private CA, prefer pointing \`verify\` at the CA bundle (\`verify="/path/to/ca.pem"\`) over disabling validation. If the certificate cannot be trusted at all, the safe fix is to terminate that connection at a properly configured proxy, not to keep it unvalidated.
|
|
5006
|
+
|
|
5007
|
+
|
|
5008
|
+
|
|
5009
|
+
See the [\`requests\` SSL verification docs](https://requests.readthedocs.io/en/latest/user/advanced/#ssl-cert-verification) for the supported \`verify\` values.`
|
|
5010
|
+
};
|
|
5011
|
+
|
|
4948
5012
|
// src/features/analysis/scm/shared/src/storedFixData/python/index.ts
|
|
4949
5013
|
var vulnerabilities7 = {
|
|
4950
5014
|
["AUTO_ESCAPE_FALSE" /* AutoEscapeFalse */]: autoEscapeFalse,
|
|
4951
|
-
["CSRF" /* Csrf */]: csrf
|
|
5015
|
+
["CSRF" /* Csrf */]: csrf,
|
|
5016
|
+
["IMPROPER_CERTIFICATE_VALIDATION" /* ImproperCertificateValidation */]: improperCertificateValidation
|
|
4952
5017
|
};
|
|
4953
5018
|
var python_default = vulnerabilities7;
|
|
4954
5019
|
|
|
@@ -5484,6 +5549,15 @@ var insecureCookie2 = {
|
|
|
5484
5549
|
}
|
|
5485
5550
|
};
|
|
5486
5551
|
|
|
5552
|
+
// src/features/analysis/scm/shared/src/storedQuestionData/java/j2eeGetConnection.ts
|
|
5553
|
+
var j2eeGetConnection2 = {
|
|
5554
|
+
jndiResourceName: {
|
|
5555
|
+
content: () => "What JNDI name is the database connection pool registered under?",
|
|
5556
|
+
description: () => 'We need the JNDI name your app server uses to expose its container-managed `DataSource`. The fix performs `new InitialContext().lookup(<jndi-name>)` to retrieve the pool, so this value must exactly match the resource definition (e.g. `<Resource name="...">` in Tomcat `context.xml`, or the binding declared in WildFly / WebSphere / WebLogic). The default `java:comp/env/jdbc/myDataSource` is the canonical Tomcat / Spring convention; replace it with whatever your environment uses.',
|
|
5557
|
+
guidance: () => ""
|
|
5558
|
+
}
|
|
5559
|
+
};
|
|
5560
|
+
|
|
5487
5561
|
// src/features/analysis/scm/shared/src/storedQuestionData/java/leftoverDebugCode.ts
|
|
5488
5562
|
var leftoverDebugCode = {
|
|
5489
5563
|
isCodeUsed: {
|
|
@@ -5812,6 +5886,7 @@ var vulnerabilities12 = {
|
|
|
5812
5886
|
["UNCHECKED_LOOP_CONDITION" /* UncheckedLoopCondition */]: uncheckedLoopCondition,
|
|
5813
5887
|
["INSECURE_COOKIE" /* InsecureCookie */]: insecureCookie2,
|
|
5814
5888
|
["TRUST_BOUNDARY_VIOLATION" /* TrustBoundaryViolation */]: trustBoundaryViolation2,
|
|
5889
|
+
["J2EE_GET_CONNECTION" /* J2EeGetConnection */]: j2eeGetConnection2,
|
|
5815
5890
|
["LEFTOVER_DEBUG_CODE" /* LeftoverDebugCode */]: leftoverDebugCode,
|
|
5816
5891
|
["ERRONEOUS_STRING_COMPARE" /* ErroneousStringCompare */]: erroneousStringCompare,
|
|
5817
5892
|
["DUPLICATED_STRINGS" /* DuplicatedStrings */]: duplicatedStrings
|
|
@@ -7178,7 +7253,7 @@ async function getAdoSdk(params) {
|
|
|
7178
7253
|
const url = new URL(repoUrl);
|
|
7179
7254
|
const origin = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
|
|
7180
7255
|
const params2 = `path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
|
|
7181
|
-
const
|
|
7256
|
+
const path37 = [
|
|
7182
7257
|
prefixPath,
|
|
7183
7258
|
owner,
|
|
7184
7259
|
projectName,
|
|
@@ -7189,7 +7264,7 @@ async function getAdoSdk(params) {
|
|
|
7189
7264
|
"items",
|
|
7190
7265
|
"items"
|
|
7191
7266
|
].filter(Boolean).join("/");
|
|
7192
|
-
return new URL(`${
|
|
7267
|
+
return new URL(`${path37}?${params2}`, origin).toString();
|
|
7193
7268
|
},
|
|
7194
7269
|
async getAdoBranchList({ repoUrl }) {
|
|
7195
7270
|
try {
|
|
@@ -7278,8 +7353,8 @@ async function getAdoSdk(params) {
|
|
|
7278
7353
|
const changeType = entry.changeType;
|
|
7279
7354
|
return changeType !== 16 && entry.item?.path;
|
|
7280
7355
|
}).map((entry) => {
|
|
7281
|
-
const
|
|
7282
|
-
return
|
|
7356
|
+
const path37 = entry.item.path;
|
|
7357
|
+
return path37.startsWith("/") ? path37.slice(1) : path37;
|
|
7283
7358
|
});
|
|
7284
7359
|
},
|
|
7285
7360
|
async searchAdoPullRequests({
|
|
@@ -13646,6 +13721,7 @@ var GQLClient = class {
|
|
|
13646
13721
|
return await this._clientSdk.ScanSkill(variables);
|
|
13647
13722
|
}
|
|
13648
13723
|
// T-467 — batched verdict lookup for the client-side quarantine check.
|
|
13724
|
+
// T-493 — response is the envelope `{ quarantineEnabled, verdicts }`.
|
|
13649
13725
|
async skillVerdictsByMd5(md5s) {
|
|
13650
13726
|
return await this._clientSdk.SkillVerdictsByMd5({ md5s });
|
|
13651
13727
|
}
|
|
@@ -14068,7 +14144,11 @@ async function sanitizeDataWithCounts(obj, options) {
|
|
|
14068
14144
|
if (typeof data === "string") {
|
|
14069
14145
|
return sanitizeString(data);
|
|
14070
14146
|
} else if (Array.isArray(data)) {
|
|
14071
|
-
|
|
14147
|
+
const results = [];
|
|
14148
|
+
for (const item of data) {
|
|
14149
|
+
results.push(await sanitizeRecursive(item));
|
|
14150
|
+
}
|
|
14151
|
+
return results;
|
|
14072
14152
|
} else if (data instanceof Error) {
|
|
14073
14153
|
return data;
|
|
14074
14154
|
} else if (data instanceof Date) {
|
|
@@ -14499,22 +14579,25 @@ async function prepareAndSendTracyRecords(client, rawRecords, workingDir, option
|
|
|
14499
14579
|
const serializedRawDataByIndex = /* @__PURE__ */ new Map();
|
|
14500
14580
|
const records = await timedStep(
|
|
14501
14581
|
`${shouldSanitize ? "sanitize" : "serialize"} ${rawRecords.length} records`,
|
|
14502
|
-
() =>
|
|
14503
|
-
|
|
14582
|
+
async () => {
|
|
14583
|
+
const results = [];
|
|
14584
|
+
for (let index = 0; index < rawRecords.length; index++) {
|
|
14585
|
+
const record = rawRecords[index];
|
|
14504
14586
|
if (record.rawData != null && record.rawDataS3Key == null) {
|
|
14505
14587
|
const serialized = shouldSanitize ? await sanitizeRawData(record.rawData) : JSON.stringify(record.rawData);
|
|
14506
14588
|
serializedRawDataByIndex.set(index, serialized);
|
|
14507
14589
|
}
|
|
14508
14590
|
const { rawData: _rawData, ...rest } = record;
|
|
14509
|
-
|
|
14591
|
+
results.push({
|
|
14510
14592
|
...rest,
|
|
14511
14593
|
repositoryUrl: record.repositoryUrl ?? defaultRepoUrl,
|
|
14512
14594
|
computerName,
|
|
14513
14595
|
userName,
|
|
14514
14596
|
clientVersion: record.clientVersion ?? defaultClientVersion
|
|
14515
|
-
};
|
|
14516
|
-
}
|
|
14517
|
-
|
|
14597
|
+
});
|
|
14598
|
+
}
|
|
14599
|
+
return results;
|
|
14600
|
+
}
|
|
14518
14601
|
);
|
|
14519
14602
|
const recordsWithRawData = rawRecords.map((r, i) => ({ recordId: r.recordId, index: i })).filter((entry) => serializedRawDataByIndex.has(entry.index));
|
|
14520
14603
|
if (recordsWithRawData.length > 0) {
|
|
@@ -14555,32 +14638,39 @@ async function prepareAndSendTracyRecords(client, rawRecords, workingDir, option
|
|
|
14555
14638
|
errors: ["[step:s3-url] Malformed uploadFieldsJSON from server"]
|
|
14556
14639
|
};
|
|
14557
14640
|
}
|
|
14641
|
+
const MAX_CONCURRENT_S3_UPLOADS = 5;
|
|
14558
14642
|
debug10(
|
|
14559
|
-
"[step:s3-upload] Uploading %d files to S3",
|
|
14560
|
-
recordsWithRawData.length
|
|
14643
|
+
"[step:s3-upload] Uploading %d files to S3 (concurrency=%d)",
|
|
14644
|
+
recordsWithRawData.length,
|
|
14645
|
+
MAX_CONCURRENT_S3_UPLOADS
|
|
14561
14646
|
);
|
|
14562
14647
|
const s3Start = Date.now();
|
|
14563
|
-
const uploadResults =
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
|
|
14569
|
-
|
|
14570
|
-
|
|
14571
|
-
|
|
14572
|
-
|
|
14573
|
-
|
|
14574
|
-
|
|
14575
|
-
|
|
14576
|
-
|
|
14577
|
-
|
|
14578
|
-
|
|
14579
|
-
|
|
14580
|
-
|
|
14581
|
-
|
|
14582
|
-
|
|
14583
|
-
|
|
14648
|
+
const uploadResults = [];
|
|
14649
|
+
for (let i = 0; i < recordsWithRawData.length; i += MAX_CONCURRENT_S3_UPLOADS) {
|
|
14650
|
+
const chunk = recordsWithRawData.slice(i, i + MAX_CONCURRENT_S3_UPLOADS);
|
|
14651
|
+
const chunkResults = await Promise.allSettled(
|
|
14652
|
+
chunk.map(async (entry) => {
|
|
14653
|
+
const rawDataJson = serializedRawDataByIndex.get(entry.index);
|
|
14654
|
+
if (!rawDataJson) {
|
|
14655
|
+
debug10("No serialized rawData for recordId=%s", entry.recordId);
|
|
14656
|
+
return;
|
|
14657
|
+
}
|
|
14658
|
+
const uploadKey = `${keyPrefix}${entry.recordId}.json`;
|
|
14659
|
+
await withTimeout(
|
|
14660
|
+
uploadFile({
|
|
14661
|
+
file: Buffer.from(rawDataJson, "utf-8"),
|
|
14662
|
+
url,
|
|
14663
|
+
uploadKey,
|
|
14664
|
+
uploadFields
|
|
14665
|
+
}),
|
|
14666
|
+
BATCH_TIMEOUT_MS,
|
|
14667
|
+
`[step:s3-upload] uploadFile ${entry.recordId}`
|
|
14668
|
+
);
|
|
14669
|
+
records[entry.index].rawDataS3Key = uploadKey;
|
|
14670
|
+
})
|
|
14671
|
+
);
|
|
14672
|
+
uploadResults.push(...chunkResults);
|
|
14673
|
+
}
|
|
14584
14674
|
debug10(
|
|
14585
14675
|
"[perf] s3-upload %d files: %dms",
|
|
14586
14676
|
recordsWithRawData.length,
|
|
@@ -15172,7 +15262,7 @@ async function postIssueComment(params) {
|
|
|
15172
15262
|
fpDescription
|
|
15173
15263
|
} = params;
|
|
15174
15264
|
const {
|
|
15175
|
-
path:
|
|
15265
|
+
path: path37,
|
|
15176
15266
|
startLine,
|
|
15177
15267
|
vulnerabilityReportIssue: {
|
|
15178
15268
|
vulnerabilityReportIssueTags,
|
|
@@ -15187,7 +15277,7 @@ async function postIssueComment(params) {
|
|
|
15187
15277
|
Refresh the page in order to see the changes.`,
|
|
15188
15278
|
pull_number: pullRequest,
|
|
15189
15279
|
commit_id: commitSha,
|
|
15190
|
-
path:
|
|
15280
|
+
path: path37,
|
|
15191
15281
|
line: startLine
|
|
15192
15282
|
});
|
|
15193
15283
|
const commentId = commentRes.data.id;
|
|
@@ -15221,7 +15311,7 @@ async function postFixComment(params) {
|
|
|
15221
15311
|
scanner
|
|
15222
15312
|
} = params;
|
|
15223
15313
|
const {
|
|
15224
|
-
path:
|
|
15314
|
+
path: path37,
|
|
15225
15315
|
startLine,
|
|
15226
15316
|
vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
|
|
15227
15317
|
vulnerabilityReportIssueId
|
|
@@ -15239,7 +15329,7 @@ async function postFixComment(params) {
|
|
|
15239
15329
|
Refresh the page in order to see the changes.`,
|
|
15240
15330
|
pull_number: pullRequest,
|
|
15241
15331
|
commit_id: commitSha,
|
|
15242
|
-
path:
|
|
15332
|
+
path: path37,
|
|
15243
15333
|
line: startLine
|
|
15244
15334
|
});
|
|
15245
15335
|
const commentId = commentRes.data.id;
|
|
@@ -15843,8 +15933,8 @@ if (typeof __filename !== "undefined") {
|
|
|
15843
15933
|
}
|
|
15844
15934
|
var costumeRequire = createRequire(moduleUrl);
|
|
15845
15935
|
var getCheckmarxPath = () => {
|
|
15846
|
-
const
|
|
15847
|
-
const cxFileName =
|
|
15936
|
+
const os17 = type();
|
|
15937
|
+
const cxFileName = os17 === "Windows_NT" ? "cx.exe" : "cx";
|
|
15848
15938
|
try {
|
|
15849
15939
|
return costumeRequire.resolve(`.bin/${cxFileName}`);
|
|
15850
15940
|
} catch (e) {
|
|
@@ -16761,8 +16851,8 @@ async function resolveSkillScanInput(skillInput) {
|
|
|
16761
16851
|
if (!fs11.existsSync(resolvedPath)) {
|
|
16762
16852
|
return skillInput;
|
|
16763
16853
|
}
|
|
16764
|
-
const
|
|
16765
|
-
if (!
|
|
16854
|
+
const stat5 = fs11.statSync(resolvedPath);
|
|
16855
|
+
if (!stat5.isDirectory()) {
|
|
16766
16856
|
throw new CliError(
|
|
16767
16857
|
"Local skill input must be a directory containing SKILL.md"
|
|
16768
16858
|
);
|
|
@@ -17161,10 +17251,16 @@ import { spawn } from "child_process";
|
|
|
17161
17251
|
|
|
17162
17252
|
// src/features/claude_code/daemon.ts
|
|
17163
17253
|
import { readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
17164
|
-
import
|
|
17254
|
+
import * as os8 from "os";
|
|
17255
|
+
import path24 from "path";
|
|
17165
17256
|
import { setTimeout as sleep2 } from "timers/promises";
|
|
17166
17257
|
import Configstore3 from "configstore";
|
|
17167
17258
|
|
|
17259
|
+
// src/features/analysis/skill_quarantine/runQuarantineCheck.ts
|
|
17260
|
+
import { stat as stat3 } from "fs/promises";
|
|
17261
|
+
import { homedir as homedir4 } from "os";
|
|
17262
|
+
import path19 from "path";
|
|
17263
|
+
|
|
17168
17264
|
// src/features/analysis/skill_quarantine/constants.ts
|
|
17169
17265
|
var HEARTBEAT_DEBOUNCE_MS = (() => {
|
|
17170
17266
|
const raw = Number(process.env["MOBB_TRACY_SKILL_QUARANTINE_DEBOUNCE_MS"]);
|
|
@@ -17240,51 +17336,86 @@ import { globby as globby2 } from "globby";
|
|
|
17240
17336
|
import { parse as parseJsoncLib } from "jsonc-parser";
|
|
17241
17337
|
|
|
17242
17338
|
// src/features/analysis/context_file_scan_paths.ts
|
|
17243
|
-
var
|
|
17339
|
+
var CATEGORY = {
|
|
17340
|
+
RULE: "rule",
|
|
17341
|
+
MEMORY: "memory",
|
|
17342
|
+
SKILL: "skill",
|
|
17343
|
+
COMMAND: "command",
|
|
17344
|
+
PROMPT: "prompt",
|
|
17345
|
+
AGENT_CONFIG: "agent-config",
|
|
17346
|
+
CONFIG: "config",
|
|
17347
|
+
MCP_CONFIG: "mcp-config",
|
|
17348
|
+
IGNORE: "ignore"
|
|
17349
|
+
};
|
|
17350
|
+
var SKILL_CATEGORY = CATEGORY.SKILL;
|
|
17244
17351
|
var SCAN_PATHS = {
|
|
17245
17352
|
"claude-code": [
|
|
17246
|
-
{ glob: "CLAUDE.md", category:
|
|
17247
|
-
{ glob: "CLAUDE.local.md", category:
|
|
17248
|
-
{ glob: "INSIGHTS.md", category:
|
|
17249
|
-
{ glob: "AGENTS.md", category:
|
|
17250
|
-
{
|
|
17251
|
-
|
|
17252
|
-
|
|
17253
|
-
|
|
17353
|
+
{ glob: "CLAUDE.md", category: CATEGORY.RULE, root: "workspace" },
|
|
17354
|
+
{ glob: "CLAUDE.local.md", category: CATEGORY.RULE, root: "workspace" },
|
|
17355
|
+
{ glob: "INSIGHTS.md", category: CATEGORY.RULE, root: "workspace" },
|
|
17356
|
+
{ glob: "AGENTS.md", category: CATEGORY.RULE, root: "workspace" },
|
|
17357
|
+
{
|
|
17358
|
+
glob: ".claude/rules/**/*.md",
|
|
17359
|
+
category: CATEGORY.RULE,
|
|
17360
|
+
root: "workspace"
|
|
17361
|
+
},
|
|
17362
|
+
{ glob: ".claude/CLAUDE.md", category: CATEGORY.RULE, root: "home" },
|
|
17363
|
+
{ glob: ".claude/INSIGHTS.md", category: CATEGORY.RULE, root: "home" },
|
|
17364
|
+
{ glob: ".claude/rules/**/*.md", category: CATEGORY.RULE, root: "home" },
|
|
17254
17365
|
{
|
|
17255
17366
|
glob: ".claude/projects/*/memory/*.md",
|
|
17256
|
-
category:
|
|
17367
|
+
category: CATEGORY.MEMORY,
|
|
17257
17368
|
root: "home"
|
|
17258
17369
|
},
|
|
17259
17370
|
{ kind: "skill-bundle", skillsRoot: ".claude/skills", root: "workspace" },
|
|
17260
|
-
{
|
|
17371
|
+
{
|
|
17372
|
+
glob: ".claude/commands/*.md",
|
|
17373
|
+
category: CATEGORY.COMMAND,
|
|
17374
|
+
root: "workspace"
|
|
17375
|
+
},
|
|
17261
17376
|
{
|
|
17262
17377
|
glob: ".claude/agents/*.md",
|
|
17263
|
-
category:
|
|
17378
|
+
category: CATEGORY.SKILL,
|
|
17264
17379
|
root: "workspace"
|
|
17265
17380
|
},
|
|
17266
17381
|
{ kind: "skill-bundle", skillsRoot: ".claude/skills", root: "home" },
|
|
17267
|
-
{ glob: ".claude/commands/*.md", category:
|
|
17268
|
-
{ glob: ".claude/agents/*.md", category:
|
|
17269
|
-
{
|
|
17382
|
+
{ glob: ".claude/commands/*.md", category: CATEGORY.COMMAND, root: "home" },
|
|
17383
|
+
{ glob: ".claude/agents/*.md", category: CATEGORY.SKILL, root: "home" },
|
|
17384
|
+
{
|
|
17385
|
+
glob: ".claude/settings.json",
|
|
17386
|
+
category: CATEGORY.CONFIG,
|
|
17387
|
+
root: "workspace"
|
|
17388
|
+
},
|
|
17270
17389
|
{
|
|
17271
17390
|
glob: ".claude/settings.local.json",
|
|
17272
|
-
category:
|
|
17391
|
+
category: CATEGORY.CONFIG,
|
|
17273
17392
|
root: "workspace"
|
|
17274
17393
|
},
|
|
17275
|
-
{ glob: ".mcp.json", category:
|
|
17276
|
-
{
|
|
17277
|
-
|
|
17278
|
-
|
|
17394
|
+
{ glob: ".mcp.json", category: CATEGORY.MCP_CONFIG, root: "workspace" },
|
|
17395
|
+
{
|
|
17396
|
+
glob: ".claude/.mcp.json",
|
|
17397
|
+
category: CATEGORY.MCP_CONFIG,
|
|
17398
|
+
root: "workspace"
|
|
17399
|
+
},
|
|
17400
|
+
{ glob: ".claude/settings.json", category: CATEGORY.CONFIG, root: "home" },
|
|
17401
|
+
{ glob: ".claudeignore", category: CATEGORY.IGNORE, root: "workspace" }
|
|
17279
17402
|
],
|
|
17280
17403
|
cursor: [
|
|
17281
17404
|
// Legacy single-file rules
|
|
17282
|
-
{ glob: ".cursorrules", category:
|
|
17405
|
+
{ glob: ".cursorrules", category: CATEGORY.RULE, root: "workspace" },
|
|
17283
17406
|
// Project Rules — docs support both `.mdc` and `.md` inside .cursor/rules/
|
|
17284
|
-
{
|
|
17285
|
-
|
|
17407
|
+
{
|
|
17408
|
+
glob: ".cursor/rules/**/*.mdc",
|
|
17409
|
+
category: CATEGORY.RULE,
|
|
17410
|
+
root: "workspace"
|
|
17411
|
+
},
|
|
17412
|
+
{
|
|
17413
|
+
glob: ".cursor/rules/**/*.md",
|
|
17414
|
+
category: CATEGORY.RULE,
|
|
17415
|
+
root: "workspace"
|
|
17416
|
+
},
|
|
17286
17417
|
// AGENTS.md — Cursor's documented alternative to .cursor/rules/
|
|
17287
|
-
{ glob: "AGENTS.md", category:
|
|
17418
|
+
{ glob: "AGENTS.md", category: CATEGORY.RULE, root: "workspace" },
|
|
17288
17419
|
// Agent skills — Cursor auto-loads from these dirs plus compat with
|
|
17289
17420
|
// Claude / Codex / generic .agents/ per Cursor docs.
|
|
17290
17421
|
{ kind: "skill-bundle", skillsRoot: ".cursor/skills", root: "workspace" },
|
|
@@ -17292,15 +17423,19 @@ var SCAN_PATHS = {
|
|
|
17292
17423
|
{ kind: "skill-bundle", skillsRoot: ".claude/skills", root: "workspace" },
|
|
17293
17424
|
{ kind: "skill-bundle", skillsRoot: ".codex/skills", root: "workspace" },
|
|
17294
17425
|
// MCP — project + global
|
|
17295
|
-
{
|
|
17296
|
-
|
|
17426
|
+
{
|
|
17427
|
+
glob: ".cursor/mcp.json",
|
|
17428
|
+
category: CATEGORY.MCP_CONFIG,
|
|
17429
|
+
root: "workspace"
|
|
17430
|
+
},
|
|
17431
|
+
{ glob: ".cursor/mcp.json", category: CATEGORY.MCP_CONFIG, root: "home" },
|
|
17297
17432
|
// Home skills (user-level cross-project skills)
|
|
17298
17433
|
{ kind: "skill-bundle", skillsRoot: ".cursor/skills", root: "home" },
|
|
17299
17434
|
{ kind: "skill-bundle", skillsRoot: ".agents/skills", root: "home" },
|
|
17300
17435
|
{ kind: "skill-bundle", skillsRoot: ".claude/skills", root: "home" },
|
|
17301
17436
|
{ kind: "skill-bundle", skillsRoot: ".codex/skills", root: "home" },
|
|
17302
17437
|
// Exclusion
|
|
17303
|
-
{ glob: ".cursorignore", category:
|
|
17438
|
+
{ glob: ".cursorignore", category: CATEGORY.IGNORE, root: "workspace" }
|
|
17304
17439
|
// Note: Cursor's global "Rules for AI" from Settings UI is stored in
|
|
17305
17440
|
// Cursor's internal settings DB. The tracer_ext reads it via VS Code API
|
|
17306
17441
|
// (vscode.workspace.getConfiguration) and includes it as a synthetic entry.
|
|
@@ -17309,42 +17444,46 @@ var SCAN_PATHS = {
|
|
|
17309
17444
|
// Instructions — workspace
|
|
17310
17445
|
{
|
|
17311
17446
|
glob: ".github/copilot-instructions.md",
|
|
17312
|
-
category:
|
|
17447
|
+
category: CATEGORY.RULE,
|
|
17313
17448
|
root: "workspace"
|
|
17314
17449
|
},
|
|
17315
17450
|
{
|
|
17316
17451
|
glob: ".github/instructions/**/*.instructions.md",
|
|
17317
|
-
category:
|
|
17452
|
+
category: CATEGORY.RULE,
|
|
17318
17453
|
root: "workspace"
|
|
17319
17454
|
},
|
|
17320
17455
|
// AGENTS.md / CLAUDE.md family (Copilot reads these via chat.useAgentsMdFile,
|
|
17321
17456
|
// chat.useClaudeMdFile for cross-compat with Claude Code / other agents).
|
|
17322
|
-
{ glob: "AGENTS.md", category:
|
|
17323
|
-
{ glob: "CLAUDE.md", category:
|
|
17324
|
-
{ glob: "CLAUDE.local.md", category:
|
|
17325
|
-
{ glob: ".claude/CLAUDE.md", category:
|
|
17326
|
-
{
|
|
17457
|
+
{ glob: "AGENTS.md", category: CATEGORY.RULE, root: "workspace" },
|
|
17458
|
+
{ glob: "CLAUDE.md", category: CATEGORY.RULE, root: "workspace" },
|
|
17459
|
+
{ glob: "CLAUDE.local.md", category: CATEGORY.RULE, root: "workspace" },
|
|
17460
|
+
{ glob: ".claude/CLAUDE.md", category: CATEGORY.RULE, root: "workspace" },
|
|
17461
|
+
{
|
|
17462
|
+
glob: ".claude/rules/**/*.md",
|
|
17463
|
+
category: CATEGORY.RULE,
|
|
17464
|
+
root: "workspace"
|
|
17465
|
+
},
|
|
17327
17466
|
// Prompts — workspace
|
|
17328
17467
|
{
|
|
17329
17468
|
glob: ".github/prompts/*.prompt.md",
|
|
17330
|
-
category:
|
|
17469
|
+
category: CATEGORY.PROMPT,
|
|
17331
17470
|
root: "workspace"
|
|
17332
17471
|
},
|
|
17333
17472
|
// Custom agents — `.agent.md` is the current format; `.chatmode.md` is the
|
|
17334
17473
|
// legacy naming docs recommend renaming. We scan both for transition.
|
|
17335
17474
|
{
|
|
17336
17475
|
glob: ".github/agents/*.agent.md",
|
|
17337
|
-
category:
|
|
17476
|
+
category: CATEGORY.AGENT_CONFIG,
|
|
17338
17477
|
root: "workspace"
|
|
17339
17478
|
},
|
|
17340
17479
|
{
|
|
17341
17480
|
glob: ".github/chatmodes/*.chatmode.md",
|
|
17342
|
-
category:
|
|
17481
|
+
category: CATEGORY.AGENT_CONFIG,
|
|
17343
17482
|
root: "workspace"
|
|
17344
17483
|
},
|
|
17345
17484
|
{
|
|
17346
17485
|
glob: ".claude/agents/*.md",
|
|
17347
|
-
category:
|
|
17486
|
+
category: CATEGORY.SKILL,
|
|
17348
17487
|
root: "workspace"
|
|
17349
17488
|
},
|
|
17350
17489
|
// Agent skills — Copilot discovers skills in all three roots (VS Code docs:
|
|
@@ -17353,30 +17492,38 @@ var SCAN_PATHS = {
|
|
|
17353
17492
|
{ kind: "skill-bundle", skillsRoot: ".claude/skills", root: "workspace" },
|
|
17354
17493
|
{ kind: "skill-bundle", skillsRoot: ".agents/skills", root: "workspace" },
|
|
17355
17494
|
// MCP — VS Code Copilot reads MCP servers from .vscode/mcp.json
|
|
17356
|
-
{
|
|
17495
|
+
{
|
|
17496
|
+
glob: ".vscode/mcp.json",
|
|
17497
|
+
category: CATEGORY.MCP_CONFIG,
|
|
17498
|
+
root: "workspace"
|
|
17499
|
+
},
|
|
17357
17500
|
// Global — home (JetBrains stores global instructions here)
|
|
17358
17501
|
{
|
|
17359
17502
|
glob: ".config/github-copilot/global-copilot-instructions.md",
|
|
17360
|
-
category:
|
|
17503
|
+
category: CATEGORY.RULE,
|
|
17361
17504
|
root: "home"
|
|
17362
17505
|
},
|
|
17363
17506
|
// User-level Copilot customizations (~/.copilot/)
|
|
17364
17507
|
{
|
|
17365
17508
|
glob: ".copilot/instructions/**/*.instructions.md",
|
|
17366
|
-
category:
|
|
17509
|
+
category: CATEGORY.RULE,
|
|
17510
|
+
root: "home"
|
|
17511
|
+
},
|
|
17512
|
+
{
|
|
17513
|
+
glob: ".copilot/prompts/*.prompt.md",
|
|
17514
|
+
category: CATEGORY.PROMPT,
|
|
17367
17515
|
root: "home"
|
|
17368
17516
|
},
|
|
17369
|
-
{ glob: ".copilot/prompts/*.prompt.md", category: "skill", root: "home" },
|
|
17370
17517
|
{
|
|
17371
17518
|
glob: ".copilot/agents/*.agent.md",
|
|
17372
|
-
category:
|
|
17519
|
+
category: CATEGORY.AGENT_CONFIG,
|
|
17373
17520
|
root: "home"
|
|
17374
17521
|
},
|
|
17375
17522
|
{ kind: "skill-bundle", skillsRoot: ".copilot/skills", root: "home" },
|
|
17376
17523
|
// Cross-compat home paths (Copilot reads Claude / generic agent dirs too)
|
|
17377
|
-
{ glob: ".claude/CLAUDE.md", category:
|
|
17378
|
-
{ glob: ".claude/rules/**/*.md", category:
|
|
17379
|
-
{ glob: ".claude/agents/*.md", category:
|
|
17524
|
+
{ glob: ".claude/CLAUDE.md", category: CATEGORY.RULE, root: "home" },
|
|
17525
|
+
{ glob: ".claude/rules/**/*.md", category: CATEGORY.RULE, root: "home" },
|
|
17526
|
+
{ glob: ".claude/agents/*.md", category: CATEGORY.SKILL, root: "home" },
|
|
17380
17527
|
{ kind: "skill-bundle", skillsRoot: ".claude/skills", root: "home" },
|
|
17381
17528
|
{ kind: "skill-bundle", skillsRoot: ".agents/skills", root: "home" }
|
|
17382
17529
|
]
|
|
@@ -17416,7 +17563,7 @@ var COPILOT_CUSTOM_LOCATION_SETTINGS = [
|
|
|
17416
17563
|
{
|
|
17417
17564
|
key: "chat.promptFilesLocations",
|
|
17418
17565
|
kind: "glob",
|
|
17419
|
-
category: "
|
|
17566
|
+
category: "prompt",
|
|
17420
17567
|
glob: "**/*.prompt.md"
|
|
17421
17568
|
},
|
|
17422
17569
|
{
|
|
@@ -17547,11 +17694,11 @@ async function readJsoncSettings(settingsPath) {
|
|
|
17547
17694
|
putSettingsCache(settingsPath, { mtimeMs, parsed: payload });
|
|
17548
17695
|
return payload;
|
|
17549
17696
|
}
|
|
17550
|
-
function putSettingsCache(
|
|
17551
|
-
if (!settingsCache.has(
|
|
17697
|
+
function putSettingsCache(path37, entry) {
|
|
17698
|
+
if (!settingsCache.has(path37) && settingsCache.size >= MAX_SETTINGS_CACHE_SIZE) {
|
|
17552
17699
|
settingsCache.delete(settingsCache.keys().next().value);
|
|
17553
17700
|
}
|
|
17554
|
-
settingsCache.set(
|
|
17701
|
+
settingsCache.set(path37, entry);
|
|
17555
17702
|
}
|
|
17556
17703
|
async function readCopilotCustomLocations(workspaceRoot) {
|
|
17557
17704
|
const parsed = await readJsoncSettings(
|
|
@@ -17801,7 +17948,7 @@ async function enumerateGlob(pattern, cwd, category, isDynamic) {
|
|
|
17801
17948
|
} catch {
|
|
17802
17949
|
return [];
|
|
17803
17950
|
}
|
|
17804
|
-
return files.map((
|
|
17951
|
+
return files.map((path37) => ({ path: path37, category }));
|
|
17805
17952
|
}
|
|
17806
17953
|
async function enumerateSkillBundle(baseDir, skillsRoot) {
|
|
17807
17954
|
const skillsDir = path14.resolve(baseDir, skillsRoot);
|
|
@@ -17965,6 +18112,12 @@ var Metric = {
|
|
|
17965
18112
|
CHECK_TRIGGERED: "skill_quarantine.check_triggered",
|
|
17966
18113
|
/** The env-var kill switch skipped the run. */
|
|
17967
18114
|
CHECK_DISABLED_ENV: "skill_quarantine.check_disabled_env",
|
|
18115
|
+
/**
|
|
18116
|
+
* T-493 — the per-org opt-in toggle was off for every org the caller
|
|
18117
|
+
* belongs to. Verdict query still ran (useful server-side telemetry);
|
|
18118
|
+
* on-disk enforcement was skipped.
|
|
18119
|
+
*/
|
|
18120
|
+
CHECK_DISABLED_ORG: "skill_quarantine.check_disabled_org",
|
|
17968
18121
|
/** Verdict-query call failed. Fail-open. */
|
|
17969
18122
|
QUERY_ERROR: "skill_quarantine.query_error",
|
|
17970
18123
|
/** Count of skills enumerated in this run. */
|
|
@@ -17986,7 +18139,18 @@ var Metric = {
|
|
|
17986
18139
|
/** Stale partial zip swept (older than grace window). */
|
|
17987
18140
|
SWEPT_PARTIAL: "skill_quarantine.swept_partial",
|
|
17988
18141
|
/** Total run duration including I/O. */
|
|
17989
|
-
DURATION_MS: "skill_quarantine.duration_ms"
|
|
18142
|
+
DURATION_MS: "skill_quarantine.duration_ms",
|
|
18143
|
+
/**
|
|
18144
|
+
* T-492 — Stub-md5 sentinel published successfully. The next heartbeat's
|
|
18145
|
+
* presence check will short-circuit re-quarantining our own stub.
|
|
18146
|
+
*/
|
|
18147
|
+
STUB_PREREGISTERED: "skill_quarantine.stub_preregistered",
|
|
18148
|
+
/**
|
|
18149
|
+
* T-492 — Stub-md5 sentinel write failed. Layer 1 (the scanner LLM
|
|
18150
|
+
* recognising stubs) still protects against the loop; this layer is
|
|
18151
|
+
* defense in depth.
|
|
18152
|
+
*/
|
|
18153
|
+
STUB_PREREGISTER_ERROR: "skill_quarantine.stub_preregister_error"
|
|
17990
18154
|
};
|
|
17991
18155
|
|
|
17992
18156
|
// src/features/analysis/skill_quarantine/quarantineSkill.ts
|
|
@@ -18120,6 +18284,12 @@ async function quarantineSkill(params) {
|
|
|
18120
18284
|
);
|
|
18121
18285
|
return { status: "publish_error", err };
|
|
18122
18286
|
}
|
|
18287
|
+
await preregisterStubMd5(params).catch((err) => {
|
|
18288
|
+
log2.warn(
|
|
18289
|
+
{ err, md5, metric: Metric.STUB_PREREGISTER_ERROR },
|
|
18290
|
+
"skill_quarantine: stub-md5 pre-registration failed; LLM-side recognition remains"
|
|
18291
|
+
);
|
|
18292
|
+
});
|
|
18123
18293
|
log2.info(
|
|
18124
18294
|
{
|
|
18125
18295
|
md5,
|
|
@@ -18133,6 +18303,53 @@ async function quarantineSkill(params) {
|
|
|
18133
18303
|
);
|
|
18134
18304
|
return { status: "quarantined" };
|
|
18135
18305
|
}
|
|
18306
|
+
async function preregisterStubMd5(params) {
|
|
18307
|
+
const { skillPath, isFolder, origName, log: log2 } = params;
|
|
18308
|
+
const stubFilePath = isFolder ? path18.join(skillPath, "SKILL.md") : skillPath;
|
|
18309
|
+
const stubEntryName = isFolder ? `${origName}/SKILL.md` : origName;
|
|
18310
|
+
const content = await readFile2(stubFilePath, "utf-8");
|
|
18311
|
+
const fileStat = await stat2(stubFilePath);
|
|
18312
|
+
const stubFile = {
|
|
18313
|
+
name: stubEntryName,
|
|
18314
|
+
path: stubFilePath,
|
|
18315
|
+
content,
|
|
18316
|
+
sizeBytes: fileStat.size,
|
|
18317
|
+
category: "skill",
|
|
18318
|
+
mtimeMs: fileStat.mtimeMs
|
|
18319
|
+
};
|
|
18320
|
+
const stubGroup = {
|
|
18321
|
+
name: isFolder ? origName : path18.basename(skillPath, path18.extname(skillPath)),
|
|
18322
|
+
root: "workspace",
|
|
18323
|
+
// unused by md5 computation
|
|
18324
|
+
skillPath,
|
|
18325
|
+
files: [stubFile],
|
|
18326
|
+
isFolder,
|
|
18327
|
+
maxMtimeMs: stubFile.mtimeMs,
|
|
18328
|
+
sessionKey: `stub-preregister:${skillPath}`
|
|
18329
|
+
};
|
|
18330
|
+
const { skills } = await processContextFiles([], [stubGroup]);
|
|
18331
|
+
const processed = skills[0];
|
|
18332
|
+
if (!processed) {
|
|
18333
|
+
return;
|
|
18334
|
+
}
|
|
18335
|
+
const { md5: stubMd5, zipBuffer } = processed;
|
|
18336
|
+
const sentinelPath = getQuarantineZipPath(stubMd5);
|
|
18337
|
+
if (await exists(sentinelPath)) {
|
|
18338
|
+
return;
|
|
18339
|
+
}
|
|
18340
|
+
const tmpSentinel = getTmpZipPath(stubMd5, randomUUID());
|
|
18341
|
+
try {
|
|
18342
|
+
await writeFile(tmpSentinel, zipBuffer);
|
|
18343
|
+
await rename(tmpSentinel, sentinelPath);
|
|
18344
|
+
} catch (err) {
|
|
18345
|
+
await unlink(tmpSentinel).catch(ignoreErr);
|
|
18346
|
+
throw err;
|
|
18347
|
+
}
|
|
18348
|
+
log2.info(
|
|
18349
|
+
{ stubMd5, metric: Metric.STUB_PREREGISTERED },
|
|
18350
|
+
"skill_quarantine: stub md5 pre-registered"
|
|
18351
|
+
);
|
|
18352
|
+
}
|
|
18136
18353
|
async function writeStub(params) {
|
|
18137
18354
|
const { skillPath, isFolder, md5, verdict } = params;
|
|
18138
18355
|
const stubContent = renderStub({
|
|
@@ -18242,12 +18459,13 @@ async function addFolderAsync(zip, root, prefix) {
|
|
|
18242
18459
|
// src/features/analysis/skill_quarantine/queryVerdicts.ts
|
|
18243
18460
|
async function queryVerdicts(gqlClient, md5s, log2) {
|
|
18244
18461
|
if (md5s.length === 0) {
|
|
18245
|
-
return /* @__PURE__ */ new Map();
|
|
18462
|
+
return { verdicts: /* @__PURE__ */ new Map(), quarantineEnabled: false };
|
|
18246
18463
|
}
|
|
18247
18464
|
try {
|
|
18248
18465
|
const res = await gqlClient.skillVerdictsByMd5(md5s);
|
|
18466
|
+
const envelope = res.skillVerdictsByMd5;
|
|
18249
18467
|
const out = /* @__PURE__ */ new Map();
|
|
18250
|
-
for (const row of
|
|
18468
|
+
for (const row of envelope.verdicts) {
|
|
18251
18469
|
out.set(row.md5, {
|
|
18252
18470
|
md5: row.md5,
|
|
18253
18471
|
verdict: row.verdict,
|
|
@@ -18257,18 +18475,41 @@ async function queryVerdicts(gqlClient, md5s, log2) {
|
|
|
18257
18475
|
scannedAt: row.scannedAt
|
|
18258
18476
|
});
|
|
18259
18477
|
}
|
|
18260
|
-
return out;
|
|
18478
|
+
return { verdicts: out, quarantineEnabled: envelope.quarantineEnabled };
|
|
18261
18479
|
} catch (err) {
|
|
18262
18480
|
log2.warn(
|
|
18263
18481
|
{ err, md5_count: md5s.length, metric: "skill_quarantine.query_error" },
|
|
18264
18482
|
"skill_quarantine: verdict query failed, failing open"
|
|
18265
18483
|
);
|
|
18266
|
-
return /* @__PURE__ */ new Map();
|
|
18484
|
+
return { verdicts: /* @__PURE__ */ new Map(), quarantineEnabled: false };
|
|
18267
18485
|
}
|
|
18268
18486
|
}
|
|
18269
18487
|
|
|
18270
18488
|
// src/features/analysis/skill_quarantine/runQuarantineCheck.ts
|
|
18489
|
+
var SKILL_PARENT_DIRS = [
|
|
18490
|
+
".claude/skills",
|
|
18491
|
+
".claude/commands",
|
|
18492
|
+
".claude/agents"
|
|
18493
|
+
];
|
|
18494
|
+
async function getSkillDirsMtimeMs(cwd) {
|
|
18495
|
+
const home = homedir4();
|
|
18496
|
+
const dirs = SKILL_PARENT_DIRS.flatMap((d) => [
|
|
18497
|
+
path19.join(cwd, d),
|
|
18498
|
+
path19.join(home, d)
|
|
18499
|
+
]);
|
|
18500
|
+
let max = 0;
|
|
18501
|
+
for (const dir of dirs) {
|
|
18502
|
+
try {
|
|
18503
|
+
const s = await stat3(dir);
|
|
18504
|
+
if (s.mtimeMs > max) max = s.mtimeMs;
|
|
18505
|
+
} catch {
|
|
18506
|
+
}
|
|
18507
|
+
}
|
|
18508
|
+
return max;
|
|
18509
|
+
}
|
|
18271
18510
|
var lastRunAt = /* @__PURE__ */ new Map();
|
|
18511
|
+
var lastDirsMtimeMs = /* @__PURE__ */ new Map();
|
|
18512
|
+
var seenSkillMd5s = /* @__PURE__ */ new Set();
|
|
18272
18513
|
var killSwitchLogged = false;
|
|
18273
18514
|
async function runQuarantineCheckIfNeeded(opts) {
|
|
18274
18515
|
const { sessionId, cwd, gqlClient, log: log2 } = opts;
|
|
@@ -18284,18 +18525,25 @@ async function runQuarantineCheckIfNeeded(opts) {
|
|
|
18284
18525
|
}
|
|
18285
18526
|
const now = Date.now();
|
|
18286
18527
|
const prev = lastRunAt.get(sessionId);
|
|
18287
|
-
|
|
18528
|
+
const withinDebounce = prev !== void 0 && now - prev < HEARTBEAT_DEBOUNCE_MS;
|
|
18529
|
+
lastRunAt.set(sessionId, now);
|
|
18530
|
+
const dirsMtime = await getSkillDirsMtimeMs(cwd);
|
|
18531
|
+
if (withinDebounce && dirsMtime <= (lastDirsMtimeMs.get(sessionId) ?? 0)) {
|
|
18288
18532
|
return;
|
|
18289
18533
|
}
|
|
18290
|
-
|
|
18534
|
+
const installed = await enumerateInstalledSkills(cwd);
|
|
18535
|
+
const hasNewSkills = installed.some((s) => !seenSkillMd5s.has(s.md5));
|
|
18536
|
+
if (!hasNewSkills && withinDebounce) {
|
|
18537
|
+
return;
|
|
18538
|
+
}
|
|
18539
|
+
lastDirsMtimeMs.set(sessionId, dirsMtime);
|
|
18291
18540
|
log2.info(
|
|
18292
|
-
{ sessionId, metric: Metric.CHECK_TRIGGERED },
|
|
18541
|
+
{ sessionId, metric: Metric.CHECK_TRIGGERED, hasNewSkills },
|
|
18293
18542
|
"skill_quarantine: check start"
|
|
18294
18543
|
);
|
|
18295
18544
|
const t0 = Date.now();
|
|
18296
18545
|
try {
|
|
18297
18546
|
await reconcileAndSweep(log2);
|
|
18298
|
-
const installed = await enumerateInstalledSkills(cwd);
|
|
18299
18547
|
log2.info(
|
|
18300
18548
|
{ sessionId, count: installed.length, metric: Metric.SKILLS_CHECKED },
|
|
18301
18549
|
"skill_quarantine: skills enumerated"
|
|
@@ -18303,11 +18551,25 @@ async function runQuarantineCheckIfNeeded(opts) {
|
|
|
18303
18551
|
if (installed.length === 0) {
|
|
18304
18552
|
return;
|
|
18305
18553
|
}
|
|
18306
|
-
const
|
|
18554
|
+
const currentMd5s = new Set(installed.map((s) => s.md5));
|
|
18555
|
+
for (const md5 of seenSkillMd5s) {
|
|
18556
|
+
if (!currentMd5s.has(md5)) seenSkillMd5s.delete(md5);
|
|
18557
|
+
}
|
|
18558
|
+
for (const skill of installed) {
|
|
18559
|
+
seenSkillMd5s.add(skill.md5);
|
|
18560
|
+
}
|
|
18561
|
+
const { verdicts, quarantineEnabled } = await queryVerdicts(
|
|
18307
18562
|
gqlClient,
|
|
18308
18563
|
installed.map((s) => s.md5),
|
|
18309
18564
|
log2
|
|
18310
18565
|
);
|
|
18566
|
+
if (!quarantineEnabled) {
|
|
18567
|
+
log2.info(
|
|
18568
|
+
{ sessionId, metric: Metric.CHECK_DISABLED_ORG },
|
|
18569
|
+
"skill_quarantine: opt-in not enabled for any org of caller; skipping enforcement"
|
|
18570
|
+
);
|
|
18571
|
+
return;
|
|
18572
|
+
}
|
|
18311
18573
|
for (const skill of installed) {
|
|
18312
18574
|
const verdict = verdicts.get(skill.md5);
|
|
18313
18575
|
if (!verdict || verdict.verdict !== MALICIOUS_VERDICT) {
|
|
@@ -18344,7 +18606,7 @@ async function runQuarantineCheckIfNeeded(opts) {
|
|
|
18344
18606
|
// src/features/claude_code/daemon_pid_file.ts
|
|
18345
18607
|
import fs13 from "fs";
|
|
18346
18608
|
import os4 from "os";
|
|
18347
|
-
import
|
|
18609
|
+
import path20 from "path";
|
|
18348
18610
|
|
|
18349
18611
|
// src/features/claude_code/data_collector_constants.ts
|
|
18350
18612
|
var CC_VERSION_CACHE_KEY = "claudeCode.detectedCCVersion";
|
|
@@ -18365,17 +18627,17 @@ var CONTEXT_SCAN_INTERVAL_MS = 5e3;
|
|
|
18365
18627
|
|
|
18366
18628
|
// src/features/claude_code/daemon_pid_file.ts
|
|
18367
18629
|
function getMobbdevDir() {
|
|
18368
|
-
return
|
|
18630
|
+
return path20.join(os4.homedir(), ".mobbdev");
|
|
18369
18631
|
}
|
|
18370
18632
|
function getDaemonCheckScriptPath() {
|
|
18371
|
-
return
|
|
18633
|
+
return path20.join(getMobbdevDir(), "daemon-check.js");
|
|
18372
18634
|
}
|
|
18373
18635
|
var DaemonPidFile = class {
|
|
18374
18636
|
constructor() {
|
|
18375
18637
|
__publicField(this, "data", null);
|
|
18376
18638
|
}
|
|
18377
18639
|
get filePath() {
|
|
18378
|
-
return
|
|
18640
|
+
return path20.join(getMobbdevDir(), "daemon.pid");
|
|
18379
18641
|
}
|
|
18380
18642
|
/** Ensure ~/.mobbdev/ directory exists. */
|
|
18381
18643
|
ensureDir() {
|
|
@@ -18438,7 +18700,7 @@ var DaemonPidFile = class {
|
|
|
18438
18700
|
import { execFile } from "child_process";
|
|
18439
18701
|
import { createHash as createHash3 } from "crypto";
|
|
18440
18702
|
import { access as access2, open as open4, readdir as readdir3, readFile as readFile3, unlink as unlink2 } from "fs/promises";
|
|
18441
|
-
import
|
|
18703
|
+
import path21 from "path";
|
|
18442
18704
|
import { promisify } from "util";
|
|
18443
18705
|
|
|
18444
18706
|
// src/features/analysis/context_file_uploader.ts
|
|
@@ -18703,8 +18965,8 @@ function createConfigstoreStream(store, opts) {
|
|
|
18703
18965
|
heartbeatBuffer.length = 0;
|
|
18704
18966
|
}
|
|
18705
18967
|
}
|
|
18706
|
-
function setScopePath(
|
|
18707
|
-
scopePath =
|
|
18968
|
+
function setScopePath(path37) {
|
|
18969
|
+
scopePath = path37;
|
|
18708
18970
|
}
|
|
18709
18971
|
return { writable, flush, setScopePath };
|
|
18710
18972
|
}
|
|
@@ -18928,18 +19190,24 @@ function createLogger(config2) {
|
|
|
18928
19190
|
|
|
18929
19191
|
// src/features/claude_code/hook_logger.ts
|
|
18930
19192
|
var DD_RUM_TOKEN = true ? "pubf59c0182545bfb4c299175119f1abf9b" : "";
|
|
18931
|
-
var CLI_VERSION = true ? "1.4.
|
|
19193
|
+
var CLI_VERSION = true ? "1.4.7" : "unknown";
|
|
18932
19194
|
var NAMESPACE = "mobbdev-claude-code-hook-logs";
|
|
18933
19195
|
var claudeCodeVersion;
|
|
18934
19196
|
function buildDdTags() {
|
|
18935
|
-
const tags = [
|
|
19197
|
+
const tags = [
|
|
19198
|
+
`version:${CLI_VERSION}`,
|
|
19199
|
+
`platform:claude_code`,
|
|
19200
|
+
`os:${process.platform}`,
|
|
19201
|
+
`arch:${process.arch}`
|
|
19202
|
+
];
|
|
18936
19203
|
if (claudeCodeVersion) {
|
|
18937
19204
|
tags.push(`cc_version:${claudeCodeVersion}`);
|
|
18938
19205
|
}
|
|
18939
19206
|
return tags.join(",");
|
|
18940
19207
|
}
|
|
19208
|
+
var handlingDdError = false;
|
|
18941
19209
|
function createHookLogger(opts) {
|
|
18942
|
-
|
|
19210
|
+
const created = createLogger({
|
|
18943
19211
|
namespace: NAMESPACE,
|
|
18944
19212
|
scopePath: opts?.scopePath,
|
|
18945
19213
|
enableConfigstore: opts?.enableConfigstore,
|
|
@@ -18949,9 +19217,26 @@ function createHookLogger(opts) {
|
|
|
18949
19217
|
service: "mobbdev-cli-hook",
|
|
18950
19218
|
ddtags: buildDdTags(),
|
|
18951
19219
|
hostnameMode: "hashed",
|
|
18952
|
-
unrefTimer: true
|
|
19220
|
+
unrefTimer: true,
|
|
19221
|
+
onError: (error) => {
|
|
19222
|
+
if (handlingDdError) {
|
|
19223
|
+
process.stderr.write(`dd-ship-error: ${String(error)}
|
|
19224
|
+
`);
|
|
19225
|
+
return;
|
|
19226
|
+
}
|
|
19227
|
+
handlingDdError = true;
|
|
19228
|
+
try {
|
|
19229
|
+
created.warn(
|
|
19230
|
+
{ err: String(error), source: "dd-log-shipping" },
|
|
19231
|
+
"Datadog log shipping failed"
|
|
19232
|
+
);
|
|
19233
|
+
} finally {
|
|
19234
|
+
handlingDdError = false;
|
|
19235
|
+
}
|
|
19236
|
+
}
|
|
18953
19237
|
}
|
|
18954
19238
|
});
|
|
19239
|
+
return created;
|
|
18955
19240
|
}
|
|
18956
19241
|
var logger = createHookLogger();
|
|
18957
19242
|
var activeScopedLoggers = [];
|
|
@@ -18981,6 +19266,9 @@ function createScopedHookLog(scopePath, opts) {
|
|
|
18981
19266
|
activeScopedLoggers.push(scoped);
|
|
18982
19267
|
return scoped;
|
|
18983
19268
|
}
|
|
19269
|
+
function getScopedLoggerCount() {
|
|
19270
|
+
return scopedLoggerCache.size;
|
|
19271
|
+
}
|
|
18984
19272
|
|
|
18985
19273
|
// src/features/claude_code/data_collector.ts
|
|
18986
19274
|
var execFileAsync = promisify(execFile);
|
|
@@ -19019,12 +19307,12 @@ async function resolveTranscriptPath(transcriptPath, sessionId) {
|
|
|
19019
19307
|
return transcriptPath;
|
|
19020
19308
|
} catch {
|
|
19021
19309
|
}
|
|
19022
|
-
const filename =
|
|
19023
|
-
const dirName =
|
|
19024
|
-
const projectsDir =
|
|
19310
|
+
const filename = path21.basename(transcriptPath);
|
|
19311
|
+
const dirName = path21.basename(path21.dirname(transcriptPath));
|
|
19312
|
+
const projectsDir = path21.dirname(path21.dirname(transcriptPath));
|
|
19025
19313
|
const baseDirName = dirName.replace(/[-.]claude-worktrees-.+$/, "");
|
|
19026
19314
|
if (baseDirName !== dirName) {
|
|
19027
|
-
const candidate =
|
|
19315
|
+
const candidate = path21.join(projectsDir, baseDirName, filename);
|
|
19028
19316
|
try {
|
|
19029
19317
|
await access2(candidate);
|
|
19030
19318
|
hookLog.info(
|
|
@@ -19046,7 +19334,7 @@ async function resolveTranscriptPath(transcriptPath, sessionId) {
|
|
|
19046
19334
|
const dirs = await readdir3(projectsDir);
|
|
19047
19335
|
for (const dir of dirs) {
|
|
19048
19336
|
if (dir === dirName) continue;
|
|
19049
|
-
const candidate =
|
|
19337
|
+
const candidate = path21.join(projectsDir, dir, filename);
|
|
19050
19338
|
try {
|
|
19051
19339
|
await access2(candidate);
|
|
19052
19340
|
hookLog.info(
|
|
@@ -19075,21 +19363,33 @@ async function readNewTranscriptEntries(transcriptPath, sessionId, sessionStore,
|
|
|
19075
19363
|
let fileSize;
|
|
19076
19364
|
let lineIndexOffset;
|
|
19077
19365
|
if (cursor?.byteOffset) {
|
|
19366
|
+
const MAX_TRANSCRIPT_READ_BYTES = 10 * 1024 * 1024;
|
|
19078
19367
|
const fh = await open4(transcriptPath, "r");
|
|
19079
19368
|
try {
|
|
19080
|
-
const
|
|
19081
|
-
fileSize =
|
|
19082
|
-
if (cursor.byteOffset >=
|
|
19369
|
+
const stat5 = await fh.stat();
|
|
19370
|
+
fileSize = stat5.size;
|
|
19371
|
+
if (cursor.byteOffset >= stat5.size) {
|
|
19083
19372
|
hookLog.info({ data: { sessionId } }, "No new data in transcript file");
|
|
19084
19373
|
return {
|
|
19085
19374
|
entries: [],
|
|
19086
19375
|
endByteOffset: fileSize,
|
|
19087
|
-
resolvedTranscriptPath: transcriptPath
|
|
19376
|
+
resolvedTranscriptPath: transcriptPath,
|
|
19377
|
+
transcriptBytesRead: 0
|
|
19088
19378
|
};
|
|
19089
19379
|
}
|
|
19090
|
-
const
|
|
19091
|
-
|
|
19380
|
+
const bytesToRead = Math.min(
|
|
19381
|
+
stat5.size - cursor.byteOffset,
|
|
19382
|
+
MAX_TRANSCRIPT_READ_BYTES
|
|
19383
|
+
);
|
|
19384
|
+
const buf = Buffer.alloc(bytesToRead);
|
|
19385
|
+
await fh.read(buf, 0, bytesToRead, cursor.byteOffset);
|
|
19092
19386
|
content = buf.toString("utf-8");
|
|
19387
|
+
if (bytesToRead < stat5.size - cursor.byteOffset && !content.endsWith("\n")) {
|
|
19388
|
+
const lastNewline = content.lastIndexOf("\n");
|
|
19389
|
+
if (lastNewline > 0) {
|
|
19390
|
+
content = content.substring(0, lastNewline + 1);
|
|
19391
|
+
}
|
|
19392
|
+
}
|
|
19093
19393
|
} finally {
|
|
19094
19394
|
await fh.close();
|
|
19095
19395
|
}
|
|
@@ -19105,12 +19405,34 @@ async function readNewTranscriptEntries(transcriptPath, sessionId, sessionStore,
|
|
|
19105
19405
|
"Read transcript file from offset"
|
|
19106
19406
|
);
|
|
19107
19407
|
} else {
|
|
19108
|
-
|
|
19109
|
-
|
|
19408
|
+
const MAX_CWD_READ_BYTES = 2 * 1024 * 1024;
|
|
19409
|
+
const fh = await open4(transcriptPath, "r");
|
|
19410
|
+
try {
|
|
19411
|
+
const stat5 = await fh.stat();
|
|
19412
|
+
fileSize = stat5.size;
|
|
19413
|
+
const bytesToRead = Math.min(stat5.size, MAX_CWD_READ_BYTES);
|
|
19414
|
+
const buf = Buffer.alloc(bytesToRead);
|
|
19415
|
+
await fh.read(buf, 0, bytesToRead, 0);
|
|
19416
|
+
content = buf.toString("utf-8");
|
|
19417
|
+
if (bytesToRead < stat5.size && !content.endsWith("\n")) {
|
|
19418
|
+
const lastNewline = content.lastIndexOf("\n");
|
|
19419
|
+
if (lastNewline > 0) {
|
|
19420
|
+
content = content.substring(0, lastNewline + 1);
|
|
19421
|
+
}
|
|
19422
|
+
}
|
|
19423
|
+
} finally {
|
|
19424
|
+
await fh.close();
|
|
19425
|
+
}
|
|
19110
19426
|
lineIndexOffset = 0;
|
|
19111
19427
|
hookLog.debug(
|
|
19112
|
-
{
|
|
19113
|
-
|
|
19428
|
+
{
|
|
19429
|
+
data: {
|
|
19430
|
+
transcriptPath,
|
|
19431
|
+
totalBytes: fileSize,
|
|
19432
|
+
cappedBytes: content.length
|
|
19433
|
+
}
|
|
19434
|
+
},
|
|
19435
|
+
"Read transcript file (first run)"
|
|
19114
19436
|
);
|
|
19115
19437
|
}
|
|
19116
19438
|
const startOffset = cursor?.byteOffset ?? 0;
|
|
@@ -19175,7 +19497,8 @@ async function readNewTranscriptEntries(transcriptPath, sessionId, sessionStore,
|
|
|
19175
19497
|
return {
|
|
19176
19498
|
entries: parsed,
|
|
19177
19499
|
endByteOffset,
|
|
19178
|
-
resolvedTranscriptPath: transcriptPath
|
|
19500
|
+
resolvedTranscriptPath: transcriptPath,
|
|
19501
|
+
transcriptBytesRead: content.length
|
|
19179
19502
|
};
|
|
19180
19503
|
}
|
|
19181
19504
|
var FILTERED_PROGRESS_SUBTYPES = /* @__PURE__ */ new Set([
|
|
@@ -19224,14 +19547,16 @@ async function cleanupStaleSessions(configDir) {
|
|
|
19224
19547
|
if (lastCleanup && Date.now() - lastCleanup < CLEANUP_INTERVAL_MS) {
|
|
19225
19548
|
return;
|
|
19226
19549
|
}
|
|
19227
|
-
const
|
|
19550
|
+
const cleanupStart = Date.now();
|
|
19228
19551
|
const prefix = getSessionFilePrefix();
|
|
19229
19552
|
try {
|
|
19230
19553
|
const files = await readdir3(configDir);
|
|
19554
|
+
const sessionFiles = files.filter(
|
|
19555
|
+
(f) => f.startsWith(prefix) && f.endsWith(".json")
|
|
19556
|
+
);
|
|
19231
19557
|
let deletedCount = 0;
|
|
19232
|
-
for (const file of
|
|
19233
|
-
|
|
19234
|
-
const filePath = path20.join(configDir, file);
|
|
19558
|
+
for (const file of sessionFiles) {
|
|
19559
|
+
const filePath = path21.join(configDir, file);
|
|
19235
19560
|
try {
|
|
19236
19561
|
const content = JSON.parse(await readFile3(filePath, "utf-8"));
|
|
19237
19562
|
let newest = 0;
|
|
@@ -19242,25 +19567,34 @@ async function cleanupStaleSessions(configDir) {
|
|
|
19242
19567
|
if (c?.updatedAt && c.updatedAt > newest) newest = c.updatedAt;
|
|
19243
19568
|
}
|
|
19244
19569
|
}
|
|
19245
|
-
if (newest > 0 &&
|
|
19570
|
+
if (newest > 0 && cleanupStart - newest > STALE_KEY_MAX_AGE_MS) {
|
|
19246
19571
|
await unlink2(filePath);
|
|
19247
19572
|
deletedCount++;
|
|
19248
19573
|
}
|
|
19249
19574
|
} catch {
|
|
19250
19575
|
}
|
|
19251
19576
|
}
|
|
19252
|
-
|
|
19253
|
-
|
|
19254
|
-
|
|
19577
|
+
hookLog.info(
|
|
19578
|
+
{
|
|
19579
|
+
heartbeat: true,
|
|
19580
|
+
data: {
|
|
19581
|
+
sessionFileCount: sessionFiles.length,
|
|
19582
|
+
deletedCount,
|
|
19583
|
+
cleanupDurationMs: Date.now() - cleanupStart
|
|
19584
|
+
}
|
|
19585
|
+
},
|
|
19586
|
+
"Session cleanup"
|
|
19587
|
+
);
|
|
19255
19588
|
} catch {
|
|
19256
19589
|
}
|
|
19257
|
-
configStore.set("claudeCode.lastCleanupAt",
|
|
19590
|
+
configStore.set("claudeCode.lastCleanupAt", cleanupStart);
|
|
19258
19591
|
}
|
|
19259
19592
|
async function processTranscript(input, sessionStore, log2, maxEntries = DAEMON_CHUNK_SIZE, gqlClientOverride) {
|
|
19260
19593
|
const {
|
|
19261
19594
|
entries: rawEntries,
|
|
19262
19595
|
endByteOffset,
|
|
19263
|
-
resolvedTranscriptPath
|
|
19596
|
+
resolvedTranscriptPath,
|
|
19597
|
+
transcriptBytesRead
|
|
19264
19598
|
} = await log2.timed(
|
|
19265
19599
|
"Read transcript",
|
|
19266
19600
|
() => readNewTranscriptEntries(
|
|
@@ -19347,15 +19681,21 @@ async function processTranscript(input, sessionStore, log2, maxEntries = DAEMON_
|
|
|
19347
19681
|
rawData: rawEntry
|
|
19348
19682
|
};
|
|
19349
19683
|
});
|
|
19350
|
-
|
|
19351
|
-
|
|
19352
|
-
|
|
19684
|
+
let totalRawDataBytes = 0;
|
|
19685
|
+
let maxRecordBytes = 0;
|
|
19686
|
+
for (const r of records) {
|
|
19687
|
+
const size = r.rawData ? JSON.stringify(r.rawData).length : 0;
|
|
19688
|
+
totalRawDataBytes += size;
|
|
19689
|
+
if (size > maxRecordBytes) maxRecordBytes = size;
|
|
19690
|
+
}
|
|
19353
19691
|
log2.info(
|
|
19354
19692
|
{
|
|
19355
19693
|
data: {
|
|
19356
19694
|
count: records.length,
|
|
19357
19695
|
skipped: filteredOut,
|
|
19696
|
+
transcriptBytesRead,
|
|
19358
19697
|
rawDataBytes: totalRawDataBytes,
|
|
19698
|
+
maxRecordBytes,
|
|
19359
19699
|
firstRecordId: records[0]?.recordId,
|
|
19360
19700
|
lastRecordId: records[records.length - 1]?.recordId
|
|
19361
19701
|
}
|
|
@@ -19469,14 +19809,14 @@ async function uploadContextFilesIfNeeded(sessionId, cwd, gqlClient, log2) {
|
|
|
19469
19809
|
import fs14 from "fs";
|
|
19470
19810
|
import fsPromises4 from "fs/promises";
|
|
19471
19811
|
import os6 from "os";
|
|
19472
|
-
import
|
|
19812
|
+
import path22 from "path";
|
|
19473
19813
|
import chalk11 from "chalk";
|
|
19474
19814
|
|
|
19475
19815
|
// src/features/claude_code/daemon-check-shim.tmpl.js
|
|
19476
19816
|
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";
|
|
19477
19817
|
|
|
19478
19818
|
// src/features/claude_code/install_hook.ts
|
|
19479
|
-
var CLAUDE_SETTINGS_PATH =
|
|
19819
|
+
var CLAUDE_SETTINGS_PATH = path22.join(os6.homedir(), ".claude", "settings.json");
|
|
19480
19820
|
var RECOMMENDED_MATCHER = "*";
|
|
19481
19821
|
async function claudeSettingsExists() {
|
|
19482
19822
|
try {
|
|
@@ -19622,18 +19962,18 @@ async function installMobbHooks(options = {}) {
|
|
|
19622
19962
|
}
|
|
19623
19963
|
|
|
19624
19964
|
// src/features/claude_code/transcript_scanner.ts
|
|
19625
|
-
import { open as open5, readdir as readdir4, stat as
|
|
19965
|
+
import { open as open5, readdir as readdir4, stat as stat4 } from "fs/promises";
|
|
19626
19966
|
import os7 from "os";
|
|
19627
|
-
import
|
|
19967
|
+
import path23 from "path";
|
|
19628
19968
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
19629
19969
|
function getClaudeProjectsDirs() {
|
|
19630
19970
|
const dirs = [];
|
|
19631
19971
|
const configDir = process.env["CLAUDE_CONFIG_DIR"];
|
|
19632
19972
|
if (configDir) {
|
|
19633
|
-
dirs.push(
|
|
19973
|
+
dirs.push(path23.join(configDir, "projects"));
|
|
19634
19974
|
}
|
|
19635
|
-
dirs.push(
|
|
19636
|
-
dirs.push(
|
|
19975
|
+
dirs.push(path23.join(os7.homedir(), ".config", "claude", "projects"));
|
|
19976
|
+
dirs.push(path23.join(os7.homedir(), ".claude", "projects"));
|
|
19637
19977
|
return dirs;
|
|
19638
19978
|
}
|
|
19639
19979
|
async function collectJsonlFiles(files, dir, projectDir, seen, now, results) {
|
|
@@ -19641,12 +19981,12 @@ async function collectJsonlFiles(files, dir, projectDir, seen, now, results) {
|
|
|
19641
19981
|
if (!file.endsWith(".jsonl")) continue;
|
|
19642
19982
|
const sessionId = file.replace(".jsonl", "");
|
|
19643
19983
|
if (!UUID_RE.test(sessionId)) continue;
|
|
19644
|
-
const filePath =
|
|
19984
|
+
const filePath = path23.join(dir, file);
|
|
19645
19985
|
if (seen.has(filePath)) continue;
|
|
19646
19986
|
seen.add(filePath);
|
|
19647
19987
|
let fileStat;
|
|
19648
19988
|
try {
|
|
19649
|
-
fileStat = await
|
|
19989
|
+
fileStat = await stat4(filePath);
|
|
19650
19990
|
} catch {
|
|
19651
19991
|
continue;
|
|
19652
19992
|
}
|
|
@@ -19672,10 +20012,10 @@ async function scanForTranscripts(projectsDirs = getClaudeProjectsDirs()) {
|
|
|
19672
20012
|
continue;
|
|
19673
20013
|
}
|
|
19674
20014
|
for (const projName of projectDirs) {
|
|
19675
|
-
const projPath =
|
|
20015
|
+
const projPath = path23.join(projectsDir, projName);
|
|
19676
20016
|
let projStat;
|
|
19677
20017
|
try {
|
|
19678
|
-
projStat = await
|
|
20018
|
+
projStat = await stat4(projPath);
|
|
19679
20019
|
} catch {
|
|
19680
20020
|
continue;
|
|
19681
20021
|
}
|
|
@@ -19689,9 +20029,9 @@ async function scanForTranscripts(projectsDirs = getClaudeProjectsDirs()) {
|
|
|
19689
20029
|
await collectJsonlFiles(files, projPath, projPath, seen, now, results);
|
|
19690
20030
|
for (const entry of files) {
|
|
19691
20031
|
if (!UUID_RE.test(entry)) continue;
|
|
19692
|
-
const subagentsDir =
|
|
20032
|
+
const subagentsDir = path23.join(projPath, entry, "subagents");
|
|
19693
20033
|
try {
|
|
19694
|
-
const s = await
|
|
20034
|
+
const s = await stat4(subagentsDir);
|
|
19695
20035
|
if (!s.isDirectory()) continue;
|
|
19696
20036
|
const subFiles = await readdir4(subagentsDir);
|
|
19697
20037
|
await collectJsonlFiles(
|
|
@@ -19739,6 +20079,9 @@ async function extractCwdFromTranscript(filePath) {
|
|
|
19739
20079
|
}
|
|
19740
20080
|
return void 0;
|
|
19741
20081
|
}
|
|
20082
|
+
function getCwdCacheSize() {
|
|
20083
|
+
return cwdCache.size;
|
|
20084
|
+
}
|
|
19742
20085
|
|
|
19743
20086
|
// src/features/claude_code/daemon.ts
|
|
19744
20087
|
async function startDaemon() {
|
|
@@ -19779,6 +20122,11 @@ async function startDaemon() {
|
|
|
19779
20122
|
let cleanupConfigDir;
|
|
19780
20123
|
const sessionCwdCache = /* @__PURE__ */ new Map();
|
|
19781
20124
|
let lastContextScanMs = 0;
|
|
20125
|
+
const machineContext = {
|
|
20126
|
+
cpuCount: os8.cpus().length,
|
|
20127
|
+
totalMemGB: Math.round(os8.totalmem() / 1024 ** 3),
|
|
20128
|
+
nodeVersion: process.version
|
|
20129
|
+
};
|
|
19782
20130
|
while (true) {
|
|
19783
20131
|
if (shuttingDown) {
|
|
19784
20132
|
await gracefulExit(0, "signal");
|
|
@@ -19787,19 +20135,44 @@ async function startDaemon() {
|
|
|
19787
20135
|
await gracefulExit(0, "TTL reached");
|
|
19788
20136
|
}
|
|
19789
20137
|
pidFile.updateHeartbeat();
|
|
20138
|
+
const cpuBefore = process.cpuUsage();
|
|
20139
|
+
const heapBefore = process.memoryUsage().heapUsed;
|
|
20140
|
+
const cycleStart = Date.now();
|
|
20141
|
+
let changedCount = 0;
|
|
20142
|
+
let totalUploaded = 0;
|
|
20143
|
+
let totalErrors = 0;
|
|
19790
20144
|
try {
|
|
19791
20145
|
const changed = await detectChangedTranscripts(lastSeen);
|
|
20146
|
+
changedCount = changed.length;
|
|
19792
20147
|
for (const transcript of changed) {
|
|
19793
20148
|
const sessionStore = createSessionConfigStore(transcript.sessionId);
|
|
19794
20149
|
if (!cleanupConfigDir) {
|
|
19795
|
-
cleanupConfigDir =
|
|
20150
|
+
cleanupConfigDir = path24.dirname(sessionStore.path);
|
|
19796
20151
|
}
|
|
19797
|
-
|
|
20152
|
+
pidFile.updateHeartbeat();
|
|
20153
|
+
const drainStart = Date.now();
|
|
20154
|
+
const result = await drainTranscript(
|
|
19798
20155
|
transcript,
|
|
19799
20156
|
sessionStore,
|
|
19800
20157
|
gqlClient,
|
|
19801
20158
|
sessionCwdCache
|
|
19802
20159
|
);
|
|
20160
|
+
totalUploaded += result.uploaded;
|
|
20161
|
+
totalErrors += result.errors;
|
|
20162
|
+
if (result.uploaded > 0 || result.errors > 0) {
|
|
20163
|
+
hookLog.info(
|
|
20164
|
+
{
|
|
20165
|
+
data: {
|
|
20166
|
+
sessionId: transcript.sessionId,
|
|
20167
|
+
drainDurationMs: Date.now() - drainStart,
|
|
20168
|
+
chunksProcessed: result.chunks,
|
|
20169
|
+
entriesUploaded: result.uploaded,
|
|
20170
|
+
errors: result.errors
|
|
20171
|
+
}
|
|
20172
|
+
},
|
|
20173
|
+
"Transcript drained"
|
|
20174
|
+
);
|
|
20175
|
+
}
|
|
19803
20176
|
}
|
|
19804
20177
|
if (lastSeen.size > 0) {
|
|
19805
20178
|
for (const filePath of sessionCwdCache.keys()) {
|
|
@@ -19822,6 +20195,29 @@ async function startDaemon() {
|
|
|
19822
20195
|
} catch (err) {
|
|
19823
20196
|
hookLog.warn({ err }, "Unexpected error in daemon cycle");
|
|
19824
20197
|
}
|
|
20198
|
+
const cpuDelta = process.cpuUsage(cpuBefore);
|
|
20199
|
+
const heapAfter = process.memoryUsage().heapUsed;
|
|
20200
|
+
hookLog.info(
|
|
20201
|
+
{
|
|
20202
|
+
heartbeat: true,
|
|
20203
|
+
data: {
|
|
20204
|
+
cycleDurationMs: Date.now() - cycleStart,
|
|
20205
|
+
cpuUserUs: cpuDelta.user,
|
|
20206
|
+
cpuSystemUs: cpuDelta.system,
|
|
20207
|
+
heapDeltaBytes: heapAfter - heapBefore,
|
|
20208
|
+
heapUsedBytes: heapAfter,
|
|
20209
|
+
daemonUptimeMs: Date.now() - startedAt,
|
|
20210
|
+
changedTranscripts: changedCount,
|
|
20211
|
+
activeTranscripts: lastSeen.size,
|
|
20212
|
+
entriesUploaded: totalUploaded,
|
|
20213
|
+
errors: totalErrors,
|
|
20214
|
+
cwdCacheSize: getCwdCacheSize(),
|
|
20215
|
+
scopedLoggerCount: getScopedLoggerCount(),
|
|
20216
|
+
...machineContext
|
|
20217
|
+
}
|
|
20218
|
+
},
|
|
20219
|
+
"daemon poll cycle"
|
|
20220
|
+
);
|
|
19825
20221
|
await sleep2(DAEMON_POLL_INTERVAL_MS);
|
|
19826
20222
|
}
|
|
19827
20223
|
}
|
|
@@ -19860,6 +20256,9 @@ async function drainTranscript(transcript, sessionStore, gqlClient, sessionCwdCa
|
|
|
19860
20256
|
const log2 = createScopedHookLog(cwd ?? transcript.projectDir, {
|
|
19861
20257
|
daemonMode: true
|
|
19862
20258
|
});
|
|
20259
|
+
let totalUploaded = 0;
|
|
20260
|
+
let totalErrors = 0;
|
|
20261
|
+
let chunks = 0;
|
|
19863
20262
|
if (cwd) {
|
|
19864
20263
|
sessionCwdCache.set(transcript.filePath, {
|
|
19865
20264
|
sessionId: transcript.sessionId,
|
|
@@ -19869,6 +20268,7 @@ async function drainTranscript(transcript, sessionStore, gqlClient, sessionCwdCa
|
|
|
19869
20268
|
try {
|
|
19870
20269
|
let hasMore = true;
|
|
19871
20270
|
while (hasMore) {
|
|
20271
|
+
chunks++;
|
|
19872
20272
|
const result = await processTranscript(
|
|
19873
20273
|
{
|
|
19874
20274
|
session_id: transcript.sessionId,
|
|
@@ -19880,8 +20280,10 @@ async function drainTranscript(transcript, sessionStore, gqlClient, sessionCwdCa
|
|
|
19880
20280
|
DAEMON_CHUNK_SIZE,
|
|
19881
20281
|
gqlClient
|
|
19882
20282
|
);
|
|
20283
|
+
totalUploaded += result.entriesUploaded;
|
|
19883
20284
|
hasMore = result.entriesUploaded + result.entriesSkipped >= DAEMON_CHUNK_SIZE;
|
|
19884
20285
|
if (result.errors > 0) {
|
|
20286
|
+
totalErrors += result.errors;
|
|
19885
20287
|
hookLog.warn(
|
|
19886
20288
|
{
|
|
19887
20289
|
data: {
|
|
@@ -19913,6 +20315,7 @@ async function drainTranscript(transcript, sessionStore, gqlClient, sessionCwdCa
|
|
|
19913
20315
|
);
|
|
19914
20316
|
});
|
|
19915
20317
|
}
|
|
20318
|
+
return { uploaded: totalUploaded, errors: totalErrors, chunks };
|
|
19916
20319
|
}
|
|
19917
20320
|
async function detectChangedTranscripts(lastSeen) {
|
|
19918
20321
|
const transcripts = await scanForTranscripts();
|
|
@@ -20089,8 +20492,8 @@ var WorkspaceService = class {
|
|
|
20089
20492
|
* Sets a known workspace path that was discovered through successful validation
|
|
20090
20493
|
* @param path The validated workspace path to store
|
|
20091
20494
|
*/
|
|
20092
|
-
static setKnownWorkspacePath(
|
|
20093
|
-
this.knownWorkspacePath =
|
|
20495
|
+
static setKnownWorkspacePath(path37) {
|
|
20496
|
+
this.knownWorkspacePath = path37;
|
|
20094
20497
|
}
|
|
20095
20498
|
/**
|
|
20096
20499
|
* Gets the known workspace path that was previously validated
|
|
@@ -20950,8 +21353,8 @@ async function createAuthenticatedMcpGQLClient({
|
|
|
20950
21353
|
// src/mcp/services/McpUsageService/host.ts
|
|
20951
21354
|
import { execSync as execSync2 } from "child_process";
|
|
20952
21355
|
import fs15 from "fs";
|
|
20953
|
-
import
|
|
20954
|
-
import
|
|
21356
|
+
import os9 from "os";
|
|
21357
|
+
import path25 from "path";
|
|
20955
21358
|
var IDEs = ["cursor", "windsurf", "webstorm", "vscode", "claude"];
|
|
20956
21359
|
var runCommand = (cmd) => {
|
|
20957
21360
|
try {
|
|
@@ -20965,8 +21368,8 @@ var gitInfo = {
|
|
|
20965
21368
|
email: runCommand("git config user.email")
|
|
20966
21369
|
};
|
|
20967
21370
|
var getClaudeWorkspacePaths = () => {
|
|
20968
|
-
const home =
|
|
20969
|
-
const claudeIdePath =
|
|
21371
|
+
const home = os9.homedir();
|
|
21372
|
+
const claudeIdePath = path25.join(home, ".claude", "ide");
|
|
20970
21373
|
const workspacePaths = [];
|
|
20971
21374
|
if (!fs15.existsSync(claudeIdePath)) {
|
|
20972
21375
|
return workspacePaths;
|
|
@@ -20974,7 +21377,7 @@ var getClaudeWorkspacePaths = () => {
|
|
|
20974
21377
|
try {
|
|
20975
21378
|
const lockFiles = fs15.readdirSync(claudeIdePath).filter((file) => file.endsWith(".lock"));
|
|
20976
21379
|
for (const lockFile of lockFiles) {
|
|
20977
|
-
const lockFilePath =
|
|
21380
|
+
const lockFilePath = path25.join(claudeIdePath, lockFile);
|
|
20978
21381
|
try {
|
|
20979
21382
|
const lockContent = JSON.parse(fs15.readFileSync(lockFilePath, "utf8"));
|
|
20980
21383
|
if (lockContent.workspaceFolders && Array.isArray(lockContent.workspaceFolders)) {
|
|
@@ -20994,29 +21397,29 @@ var getClaudeWorkspacePaths = () => {
|
|
|
20994
21397
|
return workspacePaths;
|
|
20995
21398
|
};
|
|
20996
21399
|
var getMCPConfigPaths = (hostName) => {
|
|
20997
|
-
const home =
|
|
21400
|
+
const home = os9.homedir();
|
|
20998
21401
|
const currentDir = process.env["WORKSPACE_FOLDER_PATHS"] || process.env["PWD"] || process.cwd();
|
|
20999
21402
|
switch (hostName.toLowerCase()) {
|
|
21000
21403
|
case "cursor":
|
|
21001
21404
|
return [
|
|
21002
|
-
|
|
21405
|
+
path25.join(currentDir, ".cursor", "mcp.json"),
|
|
21003
21406
|
// local first
|
|
21004
|
-
|
|
21407
|
+
path25.join(home, ".cursor", "mcp.json")
|
|
21005
21408
|
];
|
|
21006
21409
|
case "windsurf":
|
|
21007
21410
|
return [
|
|
21008
|
-
|
|
21411
|
+
path25.join(currentDir, ".codeium", "mcp_config.json"),
|
|
21009
21412
|
// local first
|
|
21010
|
-
|
|
21413
|
+
path25.join(home, ".codeium", "windsurf", "mcp_config.json")
|
|
21011
21414
|
];
|
|
21012
21415
|
case "webstorm":
|
|
21013
21416
|
return [];
|
|
21014
21417
|
case "visualstudiocode":
|
|
21015
21418
|
case "vscode":
|
|
21016
21419
|
return [
|
|
21017
|
-
|
|
21420
|
+
path25.join(currentDir, ".vscode", "mcp.json"),
|
|
21018
21421
|
// local first
|
|
21019
|
-
process.platform === "win32" ?
|
|
21422
|
+
process.platform === "win32" ? path25.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path25.join(
|
|
21020
21423
|
home,
|
|
21021
21424
|
"Library",
|
|
21022
21425
|
"Application Support",
|
|
@@ -21027,13 +21430,13 @@ var getMCPConfigPaths = (hostName) => {
|
|
|
21027
21430
|
];
|
|
21028
21431
|
case "claude": {
|
|
21029
21432
|
const claudePaths = [
|
|
21030
|
-
|
|
21433
|
+
path25.join(currentDir, ".claude.json"),
|
|
21031
21434
|
// local first
|
|
21032
|
-
|
|
21435
|
+
path25.join(home, ".claude.json")
|
|
21033
21436
|
];
|
|
21034
21437
|
const workspacePaths = getClaudeWorkspacePaths();
|
|
21035
21438
|
for (const workspacePath of workspacePaths) {
|
|
21036
|
-
claudePaths.push(
|
|
21439
|
+
claudePaths.push(path25.join(workspacePath, ".mcp.json"));
|
|
21037
21440
|
}
|
|
21038
21441
|
return claudePaths;
|
|
21039
21442
|
}
|
|
@@ -21084,7 +21487,7 @@ var readMCPConfig = (hostName) => {
|
|
|
21084
21487
|
};
|
|
21085
21488
|
var getRunningProcesses = () => {
|
|
21086
21489
|
try {
|
|
21087
|
-
return
|
|
21490
|
+
return os9.platform() === "win32" ? execSync2("tasklist", { encoding: "utf8" }) : execSync2("ps aux", { encoding: "utf8" });
|
|
21088
21491
|
} catch {
|
|
21089
21492
|
return "";
|
|
21090
21493
|
}
|
|
@@ -21159,7 +21562,7 @@ var versionCommands = {
|
|
|
21159
21562
|
}
|
|
21160
21563
|
};
|
|
21161
21564
|
var getProcessInfo = (pid) => {
|
|
21162
|
-
const platform2 =
|
|
21565
|
+
const platform2 = os9.platform();
|
|
21163
21566
|
try {
|
|
21164
21567
|
if (platform2 === "linux" || platform2 === "darwin") {
|
|
21165
21568
|
const output = execSync2(`ps -o pid=,ppid=,comm= -p ${pid}`, {
|
|
@@ -21194,10 +21597,10 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
21194
21597
|
const ideConfigPaths = /* @__PURE__ */ new Set();
|
|
21195
21598
|
for (const ide of IDEs) {
|
|
21196
21599
|
const configPaths = getMCPConfigPaths(ide);
|
|
21197
|
-
configPaths.forEach((
|
|
21600
|
+
configPaths.forEach((path37) => ideConfigPaths.add(path37));
|
|
21198
21601
|
}
|
|
21199
21602
|
const uniqueAdditionalPaths = additionalMcpList.filter(
|
|
21200
|
-
(
|
|
21603
|
+
(path37) => !ideConfigPaths.has(path37)
|
|
21201
21604
|
);
|
|
21202
21605
|
for (const ide of IDEs) {
|
|
21203
21606
|
const cfg = readMCPConfig(ide);
|
|
@@ -21278,7 +21681,7 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
21278
21681
|
const config2 = allConfigs[ide] || null;
|
|
21279
21682
|
const ideName = ide.charAt(0).toUpperCase() + ide.slice(1) || "Unknown";
|
|
21280
21683
|
let ideVersion = "Unknown";
|
|
21281
|
-
const platform2 =
|
|
21684
|
+
const platform2 = os9.platform();
|
|
21282
21685
|
const cmds = versionCommands[ideName]?.[platform2] ?? [];
|
|
21283
21686
|
for (const cmd of cmds) {
|
|
21284
21687
|
try {
|
|
@@ -21311,15 +21714,15 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
21311
21714
|
|
|
21312
21715
|
// src/mcp/services/McpUsageService/McpUsageService.ts
|
|
21313
21716
|
import fetch6 from "node-fetch";
|
|
21314
|
-
import
|
|
21717
|
+
import os11 from "os";
|
|
21315
21718
|
import { v4 as uuidv42, v5 as uuidv5 } from "uuid";
|
|
21316
21719
|
init_configs();
|
|
21317
21720
|
|
|
21318
21721
|
// src/mcp/services/McpUsageService/system.ts
|
|
21319
21722
|
init_configs();
|
|
21320
21723
|
import fs16 from "fs";
|
|
21321
|
-
import
|
|
21322
|
-
import
|
|
21724
|
+
import os10 from "os";
|
|
21725
|
+
import path26 from "path";
|
|
21323
21726
|
var MAX_DEPTH = 2;
|
|
21324
21727
|
var patterns = ["mcp", "claude"];
|
|
21325
21728
|
var isFileMatch = (fileName) => {
|
|
@@ -21339,7 +21742,7 @@ var searchDir = async (dir, depth = 0) => {
|
|
|
21339
21742
|
if (depth > MAX_DEPTH) return results;
|
|
21340
21743
|
const entries = await fs16.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
21341
21744
|
for (const entry of entries) {
|
|
21342
|
-
const fullPath =
|
|
21745
|
+
const fullPath = path26.join(dir, entry.name);
|
|
21343
21746
|
if (entry.isFile() && isFileMatch(entry.name)) {
|
|
21344
21747
|
results.push(fullPath);
|
|
21345
21748
|
} else if (entry.isDirectory()) {
|
|
@@ -21353,17 +21756,17 @@ var searchDir = async (dir, depth = 0) => {
|
|
|
21353
21756
|
};
|
|
21354
21757
|
var findSystemMCPConfigs = async () => {
|
|
21355
21758
|
try {
|
|
21356
|
-
const home =
|
|
21357
|
-
const platform2 =
|
|
21759
|
+
const home = os10.homedir();
|
|
21760
|
+
const platform2 = os10.platform();
|
|
21358
21761
|
const knownDirs = platform2 === "win32" ? [
|
|
21359
|
-
|
|
21360
|
-
|
|
21361
|
-
|
|
21762
|
+
path26.join(home, ".cursor"),
|
|
21763
|
+
path26.join(home, "Documents"),
|
|
21764
|
+
path26.join(home, "Downloads")
|
|
21362
21765
|
] : [
|
|
21363
|
-
|
|
21364
|
-
process.env["XDG_CONFIG_HOME"] ||
|
|
21365
|
-
|
|
21366
|
-
|
|
21766
|
+
path26.join(home, ".cursor"),
|
|
21767
|
+
process.env["XDG_CONFIG_HOME"] || path26.join(home, ".config"),
|
|
21768
|
+
path26.join(home, "Documents"),
|
|
21769
|
+
path26.join(home, "Downloads")
|
|
21367
21770
|
];
|
|
21368
21771
|
const timeoutPromise = new Promise(
|
|
21369
21772
|
(resolve) => setTimeout(() => {
|
|
@@ -21426,7 +21829,7 @@ var McpUsageService = class {
|
|
|
21426
21829
|
generateHostId() {
|
|
21427
21830
|
const stored = configStore.get(this.configKey);
|
|
21428
21831
|
if (stored?.mcpHostId) return stored.mcpHostId;
|
|
21429
|
-
const interfaces =
|
|
21832
|
+
const interfaces = os11.networkInterfaces();
|
|
21430
21833
|
const macs = [];
|
|
21431
21834
|
for (const iface of Object.values(interfaces)) {
|
|
21432
21835
|
if (!iface) continue;
|
|
@@ -21434,7 +21837,7 @@ var McpUsageService = class {
|
|
|
21434
21837
|
if (net.mac && net.mac !== "00:00:00:00:00:00") macs.push(net.mac);
|
|
21435
21838
|
}
|
|
21436
21839
|
}
|
|
21437
|
-
const macString = macs.length ? macs.sort().join(",") : `${
|
|
21840
|
+
const macString = macs.length ? macs.sort().join(",") : `${os11.hostname()}-${uuidv42()}`;
|
|
21438
21841
|
const hostId = uuidv5(macString, uuidv5.DNS);
|
|
21439
21842
|
logDebug("[UsageService] Generated new host ID", { hostId });
|
|
21440
21843
|
return hostId;
|
|
@@ -21457,7 +21860,7 @@ var McpUsageService = class {
|
|
|
21457
21860
|
mcpHostId,
|
|
21458
21861
|
organizationId,
|
|
21459
21862
|
mcpVersion: packageJson.version,
|
|
21460
|
-
mcpOsName:
|
|
21863
|
+
mcpOsName: os11.platform(),
|
|
21461
21864
|
mcps: JSON.stringify(mcps),
|
|
21462
21865
|
status,
|
|
21463
21866
|
userName: user.name,
|
|
@@ -23778,30 +24181,30 @@ For a complete security audit workflow, use the \`full-security-audit\` prompt.
|
|
|
23778
24181
|
|
|
23779
24182
|
// src/mcp/services/McpDetectionService/CursorMcpDetectionService.ts
|
|
23780
24183
|
import * as fs19 from "fs";
|
|
23781
|
-
import * as
|
|
23782
|
-
import * as
|
|
24184
|
+
import * as os13 from "os";
|
|
24185
|
+
import * as path28 from "path";
|
|
23783
24186
|
|
|
23784
24187
|
// src/mcp/services/McpDetectionService/BaseMcpDetectionService.ts
|
|
23785
24188
|
init_configs();
|
|
23786
24189
|
import * as fs18 from "fs";
|
|
23787
24190
|
import fetch7 from "node-fetch";
|
|
23788
|
-
import * as
|
|
24191
|
+
import * as path27 from "path";
|
|
23789
24192
|
|
|
23790
24193
|
// src/mcp/services/McpDetectionService/McpDetectionServiceUtils.ts
|
|
23791
24194
|
import * as fs17 from "fs";
|
|
23792
|
-
import * as
|
|
24195
|
+
import * as os12 from "os";
|
|
23793
24196
|
|
|
23794
24197
|
// src/mcp/services/McpDetectionService/VscodeMcpDetectionService.ts
|
|
23795
24198
|
import * as fs20 from "fs";
|
|
23796
|
-
import * as
|
|
23797
|
-
import * as
|
|
24199
|
+
import * as os14 from "os";
|
|
24200
|
+
import * as path29 from "path";
|
|
23798
24201
|
|
|
23799
24202
|
// src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesTool.ts
|
|
23800
24203
|
import { z as z42 } from "zod";
|
|
23801
24204
|
|
|
23802
24205
|
// src/mcp/services/PathValidation.ts
|
|
23803
24206
|
import fs21 from "fs";
|
|
23804
|
-
import
|
|
24207
|
+
import path30 from "path";
|
|
23805
24208
|
async function validatePath(inputPath) {
|
|
23806
24209
|
logDebug("Validating MCP path", { inputPath });
|
|
23807
24210
|
if (/^\/[a-zA-Z]:\//.test(inputPath)) {
|
|
@@ -23833,7 +24236,7 @@ async function validatePath(inputPath) {
|
|
|
23833
24236
|
logError(error);
|
|
23834
24237
|
return { isValid: false, error, path: inputPath };
|
|
23835
24238
|
}
|
|
23836
|
-
const normalizedPath =
|
|
24239
|
+
const normalizedPath = path30.normalize(inputPath);
|
|
23837
24240
|
if (normalizedPath.includes("..")) {
|
|
23838
24241
|
const error = `Normalized path contains path traversal patterns: ${inputPath}`;
|
|
23839
24242
|
logError(error);
|
|
@@ -24485,7 +24888,7 @@ init_configs();
|
|
|
24485
24888
|
import fs22 from "fs/promises";
|
|
24486
24889
|
import nodePath from "path";
|
|
24487
24890
|
var getLocalFiles = async ({
|
|
24488
|
-
path:
|
|
24891
|
+
path: path37,
|
|
24489
24892
|
maxFileSize = MCP_MAX_FILE_SIZE,
|
|
24490
24893
|
maxFiles,
|
|
24491
24894
|
isAllFilesScan,
|
|
@@ -24493,17 +24896,17 @@ var getLocalFiles = async ({
|
|
|
24493
24896
|
scanRecentlyChangedFiles
|
|
24494
24897
|
}) => {
|
|
24495
24898
|
logDebug(`[${scanContext}] Starting getLocalFiles`, {
|
|
24496
|
-
path:
|
|
24899
|
+
path: path37,
|
|
24497
24900
|
maxFileSize,
|
|
24498
24901
|
maxFiles,
|
|
24499
24902
|
isAllFilesScan,
|
|
24500
24903
|
scanRecentlyChangedFiles
|
|
24501
24904
|
});
|
|
24502
24905
|
try {
|
|
24503
|
-
const resolvedRepoPath = await fs22.realpath(
|
|
24906
|
+
const resolvedRepoPath = await fs22.realpath(path37);
|
|
24504
24907
|
logDebug(`[${scanContext}] Resolved repository path`, {
|
|
24505
24908
|
resolvedRepoPath,
|
|
24506
|
-
originalPath:
|
|
24909
|
+
originalPath: path37
|
|
24507
24910
|
});
|
|
24508
24911
|
const gitService = new GitService(resolvedRepoPath, log);
|
|
24509
24912
|
const gitValidation = await gitService.validateRepository();
|
|
@@ -24516,7 +24919,7 @@ var getLocalFiles = async ({
|
|
|
24516
24919
|
if (!gitValidation.isValid || isAllFilesScan) {
|
|
24517
24920
|
try {
|
|
24518
24921
|
files = await FileUtils.getLastChangedFiles({
|
|
24519
|
-
dir:
|
|
24922
|
+
dir: path37,
|
|
24520
24923
|
maxFileSize,
|
|
24521
24924
|
maxFiles,
|
|
24522
24925
|
isAllFilesScan
|
|
@@ -24608,7 +25011,7 @@ var getLocalFiles = async ({
|
|
|
24608
25011
|
logError(`${scanContext}Unexpected error in getLocalFiles`, {
|
|
24609
25012
|
error: error instanceof Error ? error.message : String(error),
|
|
24610
25013
|
stack: error instanceof Error ? error.stack : void 0,
|
|
24611
|
-
path:
|
|
25014
|
+
path: path37
|
|
24612
25015
|
});
|
|
24613
25016
|
throw error;
|
|
24614
25017
|
}
|
|
@@ -24618,7 +25021,7 @@ var getLocalFiles = async ({
|
|
|
24618
25021
|
init_client_generates();
|
|
24619
25022
|
init_GitService();
|
|
24620
25023
|
import fs23 from "fs";
|
|
24621
|
-
import
|
|
25024
|
+
import path31 from "path";
|
|
24622
25025
|
import { z as z41 } from "zod";
|
|
24623
25026
|
function extractPathFromPatch(patch) {
|
|
24624
25027
|
const match = patch?.match(/diff --git a\/([^\s]+) b\//);
|
|
@@ -24704,7 +25107,7 @@ var LocalMobbFolderService = class {
|
|
|
24704
25107
|
"[LocalMobbFolderService] Non-git repository detected, skipping .gitignore operations"
|
|
24705
25108
|
);
|
|
24706
25109
|
}
|
|
24707
|
-
const mobbFolderPath =
|
|
25110
|
+
const mobbFolderPath = path31.join(
|
|
24708
25111
|
this.repoPath,
|
|
24709
25112
|
this.defaultMobbFolderName
|
|
24710
25113
|
);
|
|
@@ -24876,7 +25279,7 @@ var LocalMobbFolderService = class {
|
|
|
24876
25279
|
mobbFolderPath,
|
|
24877
25280
|
baseFileName
|
|
24878
25281
|
);
|
|
24879
|
-
const filePath =
|
|
25282
|
+
const filePath = path31.join(mobbFolderPath, uniqueFileName);
|
|
24880
25283
|
await fs23.promises.writeFile(filePath, patch, "utf8");
|
|
24881
25284
|
logInfo("[LocalMobbFolderService] Patch saved successfully", {
|
|
24882
25285
|
filePath,
|
|
@@ -24934,11 +25337,11 @@ var LocalMobbFolderService = class {
|
|
|
24934
25337
|
* @returns Unique filename that doesn't conflict with existing files
|
|
24935
25338
|
*/
|
|
24936
25339
|
getUniqueFileName(folderPath, baseFileName) {
|
|
24937
|
-
const baseName =
|
|
24938
|
-
const extension =
|
|
25340
|
+
const baseName = path31.parse(baseFileName).name;
|
|
25341
|
+
const extension = path31.parse(baseFileName).ext;
|
|
24939
25342
|
let uniqueFileName = baseFileName;
|
|
24940
25343
|
let index = 1;
|
|
24941
|
-
while (fs23.existsSync(
|
|
25344
|
+
while (fs23.existsSync(path31.join(folderPath, uniqueFileName))) {
|
|
24942
25345
|
uniqueFileName = `${baseName}-${index}${extension}`;
|
|
24943
25346
|
index++;
|
|
24944
25347
|
if (index > 1e3) {
|
|
@@ -24969,7 +25372,7 @@ var LocalMobbFolderService = class {
|
|
|
24969
25372
|
logDebug("[LocalMobbFolderService] Logging patch info", { fixId: fix.id });
|
|
24970
25373
|
try {
|
|
24971
25374
|
const mobbFolderPath = await this.getFolder();
|
|
24972
|
-
const patchInfoPath =
|
|
25375
|
+
const patchInfoPath = path31.join(mobbFolderPath, "patchInfo.md");
|
|
24973
25376
|
const markdownContent = this.generateFixMarkdown(fix, savedPatchFileName);
|
|
24974
25377
|
let existingContent = "";
|
|
24975
25378
|
if (fs23.existsSync(patchInfoPath)) {
|
|
@@ -25011,7 +25414,7 @@ var LocalMobbFolderService = class {
|
|
|
25011
25414
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
25012
25415
|
const patch = this.extractPatchFromFix(fix);
|
|
25013
25416
|
const relativePatchedFilePath = patch ? extractPathFromPatch(patch) : null;
|
|
25014
|
-
const patchedFilePath = relativePatchedFilePath ?
|
|
25417
|
+
const patchedFilePath = relativePatchedFilePath ? path31.resolve(this.repoPath, relativePatchedFilePath) : null;
|
|
25015
25418
|
const fixIdentifier = savedPatchFileName ? savedPatchFileName.replace(".patch", "") : fix.id;
|
|
25016
25419
|
let markdown = `# Fix ${fixIdentifier}
|
|
25017
25420
|
|
|
@@ -25355,14 +25758,14 @@ import {
|
|
|
25355
25758
|
} from "fs";
|
|
25356
25759
|
import fs24 from "fs/promises";
|
|
25357
25760
|
import parseDiff2 from "parse-diff";
|
|
25358
|
-
import
|
|
25761
|
+
import path32 from "path";
|
|
25359
25762
|
var PatchApplicationService = class {
|
|
25360
25763
|
/**
|
|
25361
25764
|
* Gets the appropriate comment syntax for a file based on its extension
|
|
25362
25765
|
*/
|
|
25363
25766
|
static getCommentSyntax(filePath) {
|
|
25364
|
-
const ext =
|
|
25365
|
-
const basename2 =
|
|
25767
|
+
const ext = path32.extname(filePath).toLowerCase();
|
|
25768
|
+
const basename2 = path32.basename(filePath);
|
|
25366
25769
|
const commentMap = {
|
|
25367
25770
|
// C-style languages (single line comments)
|
|
25368
25771
|
".js": "//",
|
|
@@ -25570,7 +25973,7 @@ var PatchApplicationService = class {
|
|
|
25570
25973
|
}
|
|
25571
25974
|
);
|
|
25572
25975
|
}
|
|
25573
|
-
const dirPath =
|
|
25976
|
+
const dirPath = path32.dirname(normalizedFilePath);
|
|
25574
25977
|
mkdirSync(dirPath, { recursive: true });
|
|
25575
25978
|
writeFileSync3(normalizedFilePath, finalContent, "utf8");
|
|
25576
25979
|
return normalizedFilePath;
|
|
@@ -25579,9 +25982,9 @@ var PatchApplicationService = class {
|
|
|
25579
25982
|
repositoryPath,
|
|
25580
25983
|
targetPath
|
|
25581
25984
|
}) {
|
|
25582
|
-
const repoRoot =
|
|
25583
|
-
const normalizedPath =
|
|
25584
|
-
const repoRootWithSep = repoRoot.endsWith(
|
|
25985
|
+
const repoRoot = path32.resolve(repositoryPath);
|
|
25986
|
+
const normalizedPath = path32.resolve(repoRoot, targetPath);
|
|
25987
|
+
const repoRootWithSep = repoRoot.endsWith(path32.sep) ? repoRoot : `${repoRoot}${path32.sep}`;
|
|
25585
25988
|
if (normalizedPath !== repoRoot && !normalizedPath.startsWith(repoRootWithSep)) {
|
|
25586
25989
|
throw new Error(
|
|
25587
25990
|
`Security violation: target path ${targetPath} resolves outside repository`
|
|
@@ -25590,7 +25993,7 @@ var PatchApplicationService = class {
|
|
|
25590
25993
|
return {
|
|
25591
25994
|
repoRoot,
|
|
25592
25995
|
normalizedPath,
|
|
25593
|
-
relativePath:
|
|
25996
|
+
relativePath: path32.relative(repoRoot, normalizedPath)
|
|
25594
25997
|
};
|
|
25595
25998
|
}
|
|
25596
25999
|
/**
|
|
@@ -25872,7 +26275,7 @@ var PatchApplicationService = class {
|
|
|
25872
26275
|
continue;
|
|
25873
26276
|
}
|
|
25874
26277
|
try {
|
|
25875
|
-
const absolutePath =
|
|
26278
|
+
const absolutePath = path32.resolve(repositoryPath, targetFile);
|
|
25876
26279
|
if (existsSync6(absolutePath)) {
|
|
25877
26280
|
const stats = await fs24.stat(absolutePath);
|
|
25878
26281
|
const fileModTime = stats.mtime.getTime();
|
|
@@ -26098,7 +26501,7 @@ var PatchApplicationService = class {
|
|
|
26098
26501
|
fix,
|
|
26099
26502
|
scanContext
|
|
26100
26503
|
});
|
|
26101
|
-
appliedFiles.push(
|
|
26504
|
+
appliedFiles.push(path32.relative(repositoryPath, actualPath));
|
|
26102
26505
|
logDebug(`[${scanContext}] Created new file: ${relativePath}`);
|
|
26103
26506
|
}
|
|
26104
26507
|
/**
|
|
@@ -26147,7 +26550,7 @@ var PatchApplicationService = class {
|
|
|
26147
26550
|
fix,
|
|
26148
26551
|
scanContext
|
|
26149
26552
|
});
|
|
26150
|
-
appliedFiles.push(
|
|
26553
|
+
appliedFiles.push(path32.relative(repositoryPath, actualPath));
|
|
26151
26554
|
logDebug(`[${scanContext}] Modified file: ${relativePath}`);
|
|
26152
26555
|
}
|
|
26153
26556
|
}
|
|
@@ -26344,7 +26747,7 @@ init_configs();
|
|
|
26344
26747
|
// src/mcp/services/FileOperations.ts
|
|
26345
26748
|
init_FileUtils();
|
|
26346
26749
|
import fs25 from "fs";
|
|
26347
|
-
import
|
|
26750
|
+
import path33 from "path";
|
|
26348
26751
|
import AdmZip5 from "adm-zip";
|
|
26349
26752
|
var FileOperations = class {
|
|
26350
26753
|
/**
|
|
@@ -26364,10 +26767,10 @@ var FileOperations = class {
|
|
|
26364
26767
|
let packedFilesCount = 0;
|
|
26365
26768
|
const packedFiles = [];
|
|
26366
26769
|
const excludedFiles = [];
|
|
26367
|
-
const resolvedRepoPath =
|
|
26770
|
+
const resolvedRepoPath = path33.resolve(repositoryPath);
|
|
26368
26771
|
for (const filepath of fileList) {
|
|
26369
|
-
const absoluteFilepath =
|
|
26370
|
-
const resolvedFilePath =
|
|
26772
|
+
const absoluteFilepath = path33.join(repositoryPath, filepath);
|
|
26773
|
+
const resolvedFilePath = path33.resolve(absoluteFilepath);
|
|
26371
26774
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
26372
26775
|
const reason = "potential path traversal security risk";
|
|
26373
26776
|
logDebug(`[FileOperations] Skipping ${filepath} due to ${reason}`);
|
|
@@ -26414,11 +26817,11 @@ var FileOperations = class {
|
|
|
26414
26817
|
fileList,
|
|
26415
26818
|
repositoryPath
|
|
26416
26819
|
}) {
|
|
26417
|
-
const resolvedRepoPath =
|
|
26820
|
+
const resolvedRepoPath = path33.resolve(repositoryPath);
|
|
26418
26821
|
const validatedPaths = [];
|
|
26419
26822
|
for (const filepath of fileList) {
|
|
26420
|
-
const absoluteFilepath =
|
|
26421
|
-
const resolvedFilePath =
|
|
26823
|
+
const absoluteFilepath = path33.join(repositoryPath, filepath);
|
|
26824
|
+
const resolvedFilePath = path33.resolve(absoluteFilepath);
|
|
26422
26825
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
26423
26826
|
logDebug(
|
|
26424
26827
|
`[FileOperations] Rejecting ${filepath} - path traversal attempt detected`
|
|
@@ -26446,7 +26849,7 @@ var FileOperations = class {
|
|
|
26446
26849
|
for (const absolutePath of filePaths) {
|
|
26447
26850
|
try {
|
|
26448
26851
|
const content = await fs25.promises.readFile(absolutePath);
|
|
26449
|
-
const relativePath =
|
|
26852
|
+
const relativePath = path33.basename(absolutePath);
|
|
26450
26853
|
fileDataArray.push({
|
|
26451
26854
|
relativePath,
|
|
26452
26855
|
absolutePath,
|
|
@@ -26758,14 +27161,14 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
26758
27161
|
* since the last scan.
|
|
26759
27162
|
*/
|
|
26760
27163
|
async scanForSecurityVulnerabilities({
|
|
26761
|
-
path:
|
|
27164
|
+
path: path37,
|
|
26762
27165
|
isAllDetectionRulesScan,
|
|
26763
27166
|
isAllFilesScan,
|
|
26764
27167
|
scanContext
|
|
26765
27168
|
}) {
|
|
26766
27169
|
this.hasAuthenticationFailed = false;
|
|
26767
27170
|
logDebug(`[${scanContext}] Scanning for new security vulnerabilities`, {
|
|
26768
|
-
path:
|
|
27171
|
+
path: path37
|
|
26769
27172
|
});
|
|
26770
27173
|
if (!this.gqlClient) {
|
|
26771
27174
|
logInfo(`[${scanContext}] No GQL client found, skipping scan`);
|
|
@@ -26781,11 +27184,11 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
26781
27184
|
}
|
|
26782
27185
|
logDebug(
|
|
26783
27186
|
`[${scanContext}] Connected to the API, assembling list of files to scan`,
|
|
26784
|
-
{ path:
|
|
27187
|
+
{ path: path37 }
|
|
26785
27188
|
);
|
|
26786
27189
|
const isBackgroundScan = scanContext === ScanContext.BACKGROUND_INITIAL || scanContext === ScanContext.BACKGROUND_PERIODIC;
|
|
26787
27190
|
const files = await getLocalFiles({
|
|
26788
|
-
path:
|
|
27191
|
+
path: path37,
|
|
26789
27192
|
isAllFilesScan,
|
|
26790
27193
|
scanContext,
|
|
26791
27194
|
scanRecentlyChangedFiles: !isBackgroundScan
|
|
@@ -26811,13 +27214,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
26811
27214
|
});
|
|
26812
27215
|
const { fixReportId, projectId } = await scanFiles({
|
|
26813
27216
|
fileList: filesToScan.map((file) => file.relativePath),
|
|
26814
|
-
repositoryPath:
|
|
27217
|
+
repositoryPath: path37,
|
|
26815
27218
|
gqlClient: this.gqlClient,
|
|
26816
27219
|
isAllDetectionRulesScan,
|
|
26817
27220
|
scanContext
|
|
26818
27221
|
});
|
|
26819
27222
|
logInfo(
|
|
26820
|
-
`[${scanContext}] Security scan completed for ${
|
|
27223
|
+
`[${scanContext}] Security scan completed for ${path37} reportId: ${fixReportId} projectId: ${projectId}`
|
|
26821
27224
|
);
|
|
26822
27225
|
if (isAllFilesScan) {
|
|
26823
27226
|
return;
|
|
@@ -27111,13 +27514,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
27111
27514
|
});
|
|
27112
27515
|
return scannedFiles.some((file) => file.relativePath === fixFile);
|
|
27113
27516
|
}
|
|
27114
|
-
async getFreshFixes({ path:
|
|
27517
|
+
async getFreshFixes({ path: path37 }) {
|
|
27115
27518
|
const scanContext = ScanContext.USER_REQUEST;
|
|
27116
|
-
logDebug(`[${scanContext}] Getting fresh fixes`, { path:
|
|
27117
|
-
if (this.path !==
|
|
27118
|
-
this.path =
|
|
27519
|
+
logDebug(`[${scanContext}] Getting fresh fixes`, { path: path37 });
|
|
27520
|
+
if (this.path !== path37) {
|
|
27521
|
+
this.path = path37;
|
|
27119
27522
|
this.reset();
|
|
27120
|
-
logInfo(`[${scanContext}] Reset service state for new path`, { path:
|
|
27523
|
+
logInfo(`[${scanContext}] Reset service state for new path`, { path: path37 });
|
|
27121
27524
|
}
|
|
27122
27525
|
try {
|
|
27123
27526
|
const loginContext = createMcpLoginContext("check_new_fixes");
|
|
@@ -27136,7 +27539,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
27136
27539
|
}
|
|
27137
27540
|
throw error;
|
|
27138
27541
|
}
|
|
27139
|
-
this.triggerScan({ path:
|
|
27542
|
+
this.triggerScan({ path: path37, gqlClient: this.gqlClient });
|
|
27140
27543
|
let isMvsAutoFixEnabled = null;
|
|
27141
27544
|
try {
|
|
27142
27545
|
isMvsAutoFixEnabled = await this.gqlClient.getMvsAutoFixSettings();
|
|
@@ -27170,33 +27573,33 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
27170
27573
|
return noFreshFixesPrompt;
|
|
27171
27574
|
}
|
|
27172
27575
|
triggerScan({
|
|
27173
|
-
path:
|
|
27576
|
+
path: path37,
|
|
27174
27577
|
gqlClient
|
|
27175
27578
|
}) {
|
|
27176
|
-
if (this.path !==
|
|
27177
|
-
this.path =
|
|
27579
|
+
if (this.path !== path37) {
|
|
27580
|
+
this.path = path37;
|
|
27178
27581
|
this.reset();
|
|
27179
|
-
logInfo(`Reset service state for new path in triggerScan`, { path:
|
|
27582
|
+
logInfo(`Reset service state for new path in triggerScan`, { path: path37 });
|
|
27180
27583
|
}
|
|
27181
27584
|
this.gqlClient = gqlClient;
|
|
27182
27585
|
if (!this.intervalId) {
|
|
27183
|
-
this.startPeriodicScanning(
|
|
27184
|
-
this.executeInitialScan(
|
|
27185
|
-
void this.executeInitialFullScan(
|
|
27586
|
+
this.startPeriodicScanning(path37);
|
|
27587
|
+
this.executeInitialScan(path37);
|
|
27588
|
+
void this.executeInitialFullScan(path37);
|
|
27186
27589
|
}
|
|
27187
27590
|
}
|
|
27188
|
-
startPeriodicScanning(
|
|
27591
|
+
startPeriodicScanning(path37) {
|
|
27189
27592
|
const scanContext = ScanContext.BACKGROUND_PERIODIC;
|
|
27190
27593
|
logDebug(
|
|
27191
27594
|
`[${scanContext}] Starting periodic scan for new security vulnerabilities`,
|
|
27192
27595
|
{
|
|
27193
|
-
path:
|
|
27596
|
+
path: path37
|
|
27194
27597
|
}
|
|
27195
27598
|
);
|
|
27196
27599
|
this.intervalId = setInterval(() => {
|
|
27197
|
-
logDebug(`[${scanContext}] Triggering periodic security scan`, { path:
|
|
27600
|
+
logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path37 });
|
|
27198
27601
|
this.scanForSecurityVulnerabilities({
|
|
27199
|
-
path:
|
|
27602
|
+
path: path37,
|
|
27200
27603
|
scanContext
|
|
27201
27604
|
}).catch((error) => {
|
|
27202
27605
|
logError(`[${scanContext}] Error during periodic security scan`, {
|
|
@@ -27205,45 +27608,45 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
27205
27608
|
});
|
|
27206
27609
|
}, MCP_PERIODIC_CHECK_INTERVAL);
|
|
27207
27610
|
}
|
|
27208
|
-
async executeInitialFullScan(
|
|
27611
|
+
async executeInitialFullScan(path37) {
|
|
27209
27612
|
const scanContext = ScanContext.FULL_SCAN;
|
|
27210
|
-
logDebug(`[${scanContext}] Triggering initial full security scan`, { path:
|
|
27613
|
+
logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path37 });
|
|
27211
27614
|
logDebug(`[${scanContext}] Full scan paths scanned`, {
|
|
27212
27615
|
fullScanPathsScanned: this.fullScanPathsScanned
|
|
27213
27616
|
});
|
|
27214
|
-
if (this.fullScanPathsScanned.includes(
|
|
27617
|
+
if (this.fullScanPathsScanned.includes(path37)) {
|
|
27215
27618
|
logDebug(`[${scanContext}] Full scan already executed for this path`, {
|
|
27216
|
-
path:
|
|
27619
|
+
path: path37
|
|
27217
27620
|
});
|
|
27218
27621
|
return;
|
|
27219
27622
|
}
|
|
27220
27623
|
configStore.set("fullScanPathsScanned", [
|
|
27221
27624
|
...this.fullScanPathsScanned,
|
|
27222
|
-
|
|
27625
|
+
path37
|
|
27223
27626
|
]);
|
|
27224
27627
|
try {
|
|
27225
27628
|
await this.scanForSecurityVulnerabilities({
|
|
27226
|
-
path:
|
|
27629
|
+
path: path37,
|
|
27227
27630
|
isAllFilesScan: true,
|
|
27228
27631
|
isAllDetectionRulesScan: true,
|
|
27229
27632
|
scanContext: ScanContext.FULL_SCAN
|
|
27230
27633
|
});
|
|
27231
|
-
if (!this.fullScanPathsScanned.includes(
|
|
27232
|
-
this.fullScanPathsScanned.push(
|
|
27634
|
+
if (!this.fullScanPathsScanned.includes(path37)) {
|
|
27635
|
+
this.fullScanPathsScanned.push(path37);
|
|
27233
27636
|
configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
|
|
27234
27637
|
}
|
|
27235
|
-
logInfo(`[${scanContext}] Full scan completed`, { path:
|
|
27638
|
+
logInfo(`[${scanContext}] Full scan completed`, { path: path37 });
|
|
27236
27639
|
} catch (error) {
|
|
27237
27640
|
logError(`[${scanContext}] Error during initial full security scan`, {
|
|
27238
27641
|
error
|
|
27239
27642
|
});
|
|
27240
27643
|
}
|
|
27241
27644
|
}
|
|
27242
|
-
executeInitialScan(
|
|
27645
|
+
executeInitialScan(path37) {
|
|
27243
27646
|
const scanContext = ScanContext.BACKGROUND_INITIAL;
|
|
27244
|
-
logDebug(`[${scanContext}] Triggering initial security scan`, { path:
|
|
27647
|
+
logDebug(`[${scanContext}] Triggering initial security scan`, { path: path37 });
|
|
27245
27648
|
this.scanForSecurityVulnerabilities({
|
|
27246
|
-
path:
|
|
27649
|
+
path: path37,
|
|
27247
27650
|
scanContext: ScanContext.BACKGROUND_INITIAL
|
|
27248
27651
|
}).catch((error) => {
|
|
27249
27652
|
logError(`[${scanContext}] Error during initial security scan`, { error });
|
|
@@ -27340,9 +27743,9 @@ Example payload:
|
|
|
27340
27743
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
27341
27744
|
);
|
|
27342
27745
|
}
|
|
27343
|
-
const
|
|
27746
|
+
const path37 = pathValidationResult.path;
|
|
27344
27747
|
const resultText = await this.newFixesService.getFreshFixes({
|
|
27345
|
-
path:
|
|
27748
|
+
path: path37
|
|
27346
27749
|
});
|
|
27347
27750
|
logInfo("CheckForNewAvailableFixesTool execution completed", {
|
|
27348
27751
|
resultText
|
|
@@ -27520,8 +27923,8 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
27520
27923
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
27521
27924
|
);
|
|
27522
27925
|
}
|
|
27523
|
-
const
|
|
27524
|
-
const gitService = new GitService(
|
|
27926
|
+
const path37 = pathValidationResult.path;
|
|
27927
|
+
const gitService = new GitService(path37, log);
|
|
27525
27928
|
const gitValidation = await gitService.validateRepository();
|
|
27526
27929
|
if (!gitValidation.isValid) {
|
|
27527
27930
|
throw new Error(`Invalid git repository: ${gitValidation.error}`);
|
|
@@ -27906,9 +28309,9 @@ Example payload:
|
|
|
27906
28309
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
27907
28310
|
);
|
|
27908
28311
|
}
|
|
27909
|
-
const
|
|
28312
|
+
const path37 = pathValidationResult.path;
|
|
27910
28313
|
const files = await getLocalFiles({
|
|
27911
|
-
path:
|
|
28314
|
+
path: path37,
|
|
27912
28315
|
maxFileSize: MCP_MAX_FILE_SIZE,
|
|
27913
28316
|
maxFiles: args.maxFiles,
|
|
27914
28317
|
scanContext: ScanContext.USER_REQUEST,
|
|
@@ -27928,7 +28331,7 @@ Example payload:
|
|
|
27928
28331
|
try {
|
|
27929
28332
|
const fixResult = await this.vulnerabilityFixService.processVulnerabilities({
|
|
27930
28333
|
fileList: files.map((file) => file.relativePath),
|
|
27931
|
-
repositoryPath:
|
|
28334
|
+
repositoryPath: path37,
|
|
27932
28335
|
offset: args.offset,
|
|
27933
28336
|
limit: args.limit,
|
|
27934
28337
|
isRescan: args.rescan || !!args.maxFiles
|
|
@@ -28229,10 +28632,10 @@ init_client_generates();
|
|
|
28229
28632
|
init_urlParser2();
|
|
28230
28633
|
|
|
28231
28634
|
// src/features/codeium_intellij/codeium_language_server_grpc_client.ts
|
|
28232
|
-
import
|
|
28635
|
+
import path34 from "path";
|
|
28233
28636
|
import * as grpc from "@grpc/grpc-js";
|
|
28234
28637
|
import * as protoLoader from "@grpc/proto-loader";
|
|
28235
|
-
var PROTO_PATH =
|
|
28638
|
+
var PROTO_PATH = path34.join(
|
|
28236
28639
|
getModuleRootDir(),
|
|
28237
28640
|
"src/features/codeium_intellij/proto/exa/language_server_pb/language_server.proto"
|
|
28238
28641
|
);
|
|
@@ -28244,7 +28647,7 @@ function loadProto() {
|
|
|
28244
28647
|
defaults: true,
|
|
28245
28648
|
oneofs: true,
|
|
28246
28649
|
includeDirs: [
|
|
28247
|
-
|
|
28650
|
+
path34.join(getModuleRootDir(), "src/features/codeium_intellij/proto")
|
|
28248
28651
|
]
|
|
28249
28652
|
});
|
|
28250
28653
|
return grpc.loadPackageDefinition(
|
|
@@ -28299,29 +28702,29 @@ async function getGrpcClient(port, csrf3) {
|
|
|
28299
28702
|
|
|
28300
28703
|
// src/features/codeium_intellij/parse_intellij_logs.ts
|
|
28301
28704
|
import fs27 from "fs";
|
|
28302
|
-
import
|
|
28303
|
-
import
|
|
28705
|
+
import os15 from "os";
|
|
28706
|
+
import path35 from "path";
|
|
28304
28707
|
function getLogsDir() {
|
|
28305
28708
|
if (process.platform === "darwin") {
|
|
28306
|
-
return
|
|
28709
|
+
return path35.join(os15.homedir(), "Library/Logs/JetBrains");
|
|
28307
28710
|
} else if (process.platform === "win32") {
|
|
28308
|
-
return
|
|
28309
|
-
process.env["LOCALAPPDATA"] ||
|
|
28711
|
+
return path35.join(
|
|
28712
|
+
process.env["LOCALAPPDATA"] || path35.join(os15.homedir(), "AppData/Local"),
|
|
28310
28713
|
"JetBrains"
|
|
28311
28714
|
);
|
|
28312
28715
|
} else {
|
|
28313
|
-
return
|
|
28716
|
+
return path35.join(os15.homedir(), ".cache/JetBrains");
|
|
28314
28717
|
}
|
|
28315
28718
|
}
|
|
28316
28719
|
function parseIdeLogDir(ideLogDir) {
|
|
28317
28720
|
const logFiles = fs27.readdirSync(ideLogDir).filter((f) => /^idea(\.\d+)?\.log$/.test(f)).map((f) => ({
|
|
28318
28721
|
name: f,
|
|
28319
|
-
mtime: fs27.statSync(
|
|
28722
|
+
mtime: fs27.statSync(path35.join(ideLogDir, f)).mtimeMs
|
|
28320
28723
|
})).sort((a, b) => a.mtime - b.mtime).map((f) => f.name);
|
|
28321
28724
|
let latestCsrf = null;
|
|
28322
28725
|
let latestPort = null;
|
|
28323
28726
|
for (const logFile of logFiles) {
|
|
28324
|
-
const lines = fs27.readFileSync(
|
|
28727
|
+
const lines = fs27.readFileSync(path35.join(ideLogDir, logFile), "utf-8").split("\n");
|
|
28325
28728
|
for (const line of lines) {
|
|
28326
28729
|
if (!line.includes(
|
|
28327
28730
|
"com.codeium.intellij.language_server.LanguageServerProcessHandler"
|
|
@@ -28349,9 +28752,9 @@ function findRunningCodeiumLanguageServers() {
|
|
|
28349
28752
|
const logsDir = getLogsDir();
|
|
28350
28753
|
if (!fs27.existsSync(logsDir)) return results;
|
|
28351
28754
|
for (const ide of fs27.readdirSync(logsDir)) {
|
|
28352
|
-
let ideLogDir =
|
|
28755
|
+
let ideLogDir = path35.join(logsDir, ide);
|
|
28353
28756
|
if (process.platform !== "darwin") {
|
|
28354
|
-
ideLogDir =
|
|
28757
|
+
ideLogDir = path35.join(ideLogDir, "log");
|
|
28355
28758
|
}
|
|
28356
28759
|
if (!fs27.existsSync(ideLogDir) || !fs27.statSync(ideLogDir).isDirectory()) {
|
|
28357
28760
|
continue;
|
|
@@ -28533,11 +28936,11 @@ function processChatStepCodeAction(step) {
|
|
|
28533
28936
|
|
|
28534
28937
|
// src/features/codeium_intellij/install_hook.ts
|
|
28535
28938
|
import fsPromises5 from "fs/promises";
|
|
28536
|
-
import
|
|
28537
|
-
import
|
|
28939
|
+
import os16 from "os";
|
|
28940
|
+
import path36 from "path";
|
|
28538
28941
|
import chalk14 from "chalk";
|
|
28539
28942
|
function getCodeiumHooksPath() {
|
|
28540
|
-
return
|
|
28943
|
+
return path36.join(os16.homedir(), ".codeium", "hooks.json");
|
|
28541
28944
|
}
|
|
28542
28945
|
async function readCodeiumHooks() {
|
|
28543
28946
|
const hooksPath = getCodeiumHooksPath();
|
|
@@ -28550,7 +28953,7 @@ async function readCodeiumHooks() {
|
|
|
28550
28953
|
}
|
|
28551
28954
|
async function writeCodeiumHooks(config2) {
|
|
28552
28955
|
const hooksPath = getCodeiumHooksPath();
|
|
28553
|
-
const dir =
|
|
28956
|
+
const dir = path36.dirname(hooksPath);
|
|
28554
28957
|
await fsPromises5.mkdir(dir, { recursive: true });
|
|
28555
28958
|
await fsPromises5.writeFile(
|
|
28556
28959
|
hooksPath,
|