@gitsense/gsc-utils 0.2.25 → 0.2.27
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/README.md +380 -62
- package/dist/gsc-utils.cjs.js +2203 -331
- package/dist/gsc-utils.esm.js +2203 -331
- package/package.json +1 -1
- package/src/AnalyzerUtils/cloner.js +149 -0
- package/src/AnalyzerUtils/constants.js +1 -1
- package/src/AnalyzerUtils/defaultPromptLoader.js +10 -10
- package/src/AnalyzerUtils/discovery.js +48 -39
- package/src/AnalyzerUtils/index.js +13 -7
- package/src/AnalyzerUtils/instructionLoader.js +6 -6
- package/src/AnalyzerUtils/jsonParser.js +35 -0
- package/src/AnalyzerUtils/management.js +6 -6
- package/src/AnalyzerUtils/saver.js +5 -5
- package/src/AnalyzerUtils/schemaLoader.js +194 -26
- package/src/AnalyzerUtils/updater.js +187 -0
- package/src/CodeBlockUtils/blockProcessor.js +14 -32
- package/src/CodeBlockUtils/index.js +7 -6
- package/src/CodeBlockUtils/lineageTracer.js +95 -0
- package/src/CompactChatUtils/CompactedMessageUtils.js +224 -0
- package/src/CompactChatUtils/README.md +321 -0
- package/src/CompactChatUtils/ReferenceMessageUtils.js +143 -0
- package/src/CompactChatUtils/index.js +40 -0
- package/src/ContextUtils.js +40 -4
- package/src/DomUtils.js +86 -12
- package/src/GSToolBlockUtils.js +66 -1
- package/src/GitSenseChatUtils.js +58 -5
- package/src/MarkdownUtils.js +4 -1
- package/src/MessageUtils.js +1 -1
- package/src/MetaRawResultUtils.js +244 -0
- package/src/PatchUtils/constants.js +9 -3
- package/src/PatchUtils/patchParser.js +60 -36
- package/src/PatchUtils/patchVerifier/detectAndFixOverlappingHunks.js +1 -1
- package/src/SVGUtils.js +57 -0
- package/src/SharedUtils/stringUtils.js +303 -0
- package/src/CodeBlockUtils/blockProcessor.js.rej +0 -8
package/dist/gsc-utils.esm.js
CHANGED
|
@@ -43,8 +43,8 @@ function getAugmentedNamespace(n) {
|
|
|
43
43
|
* Authors: Claude 3.7 Sonnet (v1.0.0), Gemini 2.5 Pro (v1.1.0), Gemini 2.5 Flash Thinking (v1.2.0)
|
|
44
44
|
*/
|
|
45
45
|
|
|
46
|
-
const fs$
|
|
47
|
-
const path$
|
|
46
|
+
const fs$9 = require$$0;
|
|
47
|
+
const path$7 = require$$1;
|
|
48
48
|
const ANALYZE_MESSAGE_REGEXP = /^# Analyze - `([^`]+)`\n/;
|
|
49
49
|
|
|
50
50
|
/**
|
|
@@ -78,12 +78,12 @@ function unescapeCodeBlocks(content) {
|
|
|
78
78
|
* @returns {Array} An array of message objects with role and content properties
|
|
79
79
|
*/
|
|
80
80
|
function getChatTemplateMessages$1(dirname, messageType) {
|
|
81
|
-
const messagesDir = messageType ? path$
|
|
81
|
+
const messagesDir = messageType ? path$7.join(dirname, messageType) : dirname;
|
|
82
82
|
const messages = [];
|
|
83
83
|
|
|
84
84
|
try {
|
|
85
85
|
// Read all files in the directory
|
|
86
|
-
const files = fs$
|
|
86
|
+
const files = fs$9.readdirSync(messagesDir);
|
|
87
87
|
|
|
88
88
|
// Sort files numerically (1.md, 2.md, etc.)
|
|
89
89
|
const sortedFiles = files.sort((a, b) => {
|
|
@@ -94,9 +94,9 @@ function getChatTemplateMessages$1(dirname, messageType) {
|
|
|
94
94
|
|
|
95
95
|
// Process each file
|
|
96
96
|
for (const file of sortedFiles) {
|
|
97
|
-
if (path$
|
|
98
|
-
const filePath = path$
|
|
99
|
-
const fileContent = fs$
|
|
97
|
+
if (path$7.extname(file) === '.md') {
|
|
98
|
+
const filePath = path$7.join(messagesDir, file);
|
|
99
|
+
const fileContent = fs$9.readFileSync(filePath, 'utf8');
|
|
100
100
|
|
|
101
101
|
// Split by triple newline to separate metadata from content
|
|
102
102
|
const parts = fileContent.split('\n\n\n');
|
|
@@ -396,7 +396,7 @@ function getMessageContentType$1(messageContent) {
|
|
|
396
396
|
return 'regular'; // Handle non-string input gracefully
|
|
397
397
|
}
|
|
398
398
|
const trimmedContent = messageContent.trimStart(); // Check from the beginning, ignoring leading whitespace
|
|
399
|
-
if (trimmedContent.startsWith('## FILE CONTENT')) {
|
|
399
|
+
if (trimmedContent.startsWith('## FILE CONTENT') || trimmedContent.startsWith('## REFERENCE FILE CONTENT')) {
|
|
400
400
|
return 'file-content-context';
|
|
401
401
|
} else if (trimmedContent.startsWith('## OVERVIEW')) {
|
|
402
402
|
return 'overview-context';
|
|
@@ -617,7 +617,7 @@ function getChatMessages$1(chat, model) {
|
|
|
617
617
|
return getMessagesBeforeId$1(model || chat.main_model, chat.messages[0], null);
|
|
618
618
|
}
|
|
619
619
|
|
|
620
|
-
var ChatUtils$
|
|
620
|
+
var ChatUtils$2 = {
|
|
621
621
|
isAskChat,
|
|
622
622
|
isNewAnalyzerChat,
|
|
623
623
|
isAnalyzeChat,
|
|
@@ -689,7 +689,7 @@ const COMMENT_STYLES$3 = {
|
|
|
689
689
|
'vbscript': { type: 'apostrophe' }
|
|
690
690
|
};
|
|
691
691
|
|
|
692
|
-
var constants$
|
|
692
|
+
var constants$3 = {
|
|
693
693
|
COMMENT_STYLES: COMMENT_STYLES$3
|
|
694
694
|
};
|
|
695
695
|
|
|
@@ -708,7 +708,7 @@ var constants$2 = {
|
|
|
708
708
|
* Generates a valid RFC 4122 UUID v4
|
|
709
709
|
* @returns {string} A valid UUID v4
|
|
710
710
|
*/
|
|
711
|
-
function generateUUID$
|
|
711
|
+
function generateUUID$2() {
|
|
712
712
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
713
713
|
const r = Math.random() * 16 | 0;
|
|
714
714
|
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
@@ -727,7 +727,7 @@ function validateUUID$4(uuid) {
|
|
|
727
727
|
if (!uuidPattern.test(uuid)) {
|
|
728
728
|
return {
|
|
729
729
|
"Block-UUID": "INVALID UUID",
|
|
730
|
-
"Correct Block-UUID": generateUUID$
|
|
730
|
+
"Correct Block-UUID": generateUUID$2()
|
|
731
731
|
};
|
|
732
732
|
}
|
|
733
733
|
|
|
@@ -737,7 +737,7 @@ function validateUUID$4(uuid) {
|
|
|
737
737
|
}
|
|
738
738
|
|
|
739
739
|
var uuidUtils = {
|
|
740
|
-
generateUUID: generateUUID$
|
|
740
|
+
generateUUID: generateUUID$2,
|
|
741
741
|
validateUUID: validateUUID$4
|
|
742
742
|
};
|
|
743
743
|
|
|
@@ -869,7 +869,7 @@ var lineNumberFormatter = {
|
|
|
869
869
|
*/
|
|
870
870
|
|
|
871
871
|
// Dependencies from other modules within CodeBlockUtils
|
|
872
|
-
const { COMMENT_STYLES: COMMENT_STYLES$2 } = constants$
|
|
872
|
+
const { COMMENT_STYLES: COMMENT_STYLES$2 } = constants$3;
|
|
873
873
|
const { removeLineNumbers: removeLineNumbers$9 } = lineNumberFormatter; // Assuming this utility exists
|
|
874
874
|
const { validateUUID: validateUUID$3 } = uuidUtils; // Assuming uuidUtils.js is in the same directory
|
|
875
875
|
|
|
@@ -1538,24 +1538,63 @@ function isValidVersion$1(version) {
|
|
|
1538
1538
|
var versionUtils = {
|
|
1539
1539
|
isValidVersion: isValidVersion$1};
|
|
1540
1540
|
|
|
1541
|
+
/**
|
|
1542
|
+
* Component: PatchUtils Constants
|
|
1543
|
+
* Block-UUID: c6747054-2c8b-461f-910d-0fd725d9a350
|
|
1544
|
+
* Parent-UUID: 32adc00e-7509-4219-8e40-6c1319371db9
|
|
1545
|
+
* Version: 2.1.0
|
|
1546
|
+
* Description: Contains shared constants and regular expressions used by the enhanced patch utilities.
|
|
1547
|
+
* Language: JavaScript
|
|
1548
|
+
* Created-at: 2025-05-14T16:55:00.000Z
|
|
1549
|
+
* Authors: Gemini 2.5 Flash Thinking (v1.0.0), Claude 3.7 Sonnet (v2.0.0), Qwen 3 Coder 480B - Cerebras (v2.1.0)
|
|
1550
|
+
*/
|
|
1551
|
+
|
|
1552
|
+
// Traditional patch markers
|
|
1553
|
+
const PATCH_START_MARKER$1 = '# --- PATCH START MARKER ---';
|
|
1554
|
+
const PATCH_END_MARKER$1 = '# --- PATCH END MARKER ---';
|
|
1555
|
+
|
|
1556
|
+
// Abbreviated patch markers
|
|
1557
|
+
const ABBREVIATED_PATCH_START_MARKER$1 = '# --- ABBREVIATED PATCH START MARKER ---';
|
|
1558
|
+
const ABBREVIATED_PATCH_END_MARKER$1 = '# --- ABBREVIATED PATCH END MARKER ---';
|
|
1559
|
+
|
|
1560
|
+
// Patch metadata header
|
|
1561
|
+
const PATCH_METADATA_HEADER$1 = '# Patch Metadata';
|
|
1562
|
+
|
|
1563
|
+
// Diff file headers
|
|
1564
|
+
const ORIGINAL_FILE_HEADER$1 = '--- Original';
|
|
1565
|
+
const MODIFIED_FILE_HEADER$1 = '+++ Modified';
|
|
1566
|
+
|
|
1567
|
+
var constants$2 = {
|
|
1568
|
+
PATCH_START_MARKER: PATCH_START_MARKER$1,
|
|
1569
|
+
PATCH_END_MARKER: PATCH_END_MARKER$1,
|
|
1570
|
+
ABBREVIATED_PATCH_START_MARKER: ABBREVIATED_PATCH_START_MARKER$1,
|
|
1571
|
+
ABBREVIATED_PATCH_END_MARKER: ABBREVIATED_PATCH_END_MARKER$1,
|
|
1572
|
+
PATCH_METADATA_HEADER: PATCH_METADATA_HEADER$1,
|
|
1573
|
+
ORIGINAL_FILE_HEADER: ORIGINAL_FILE_HEADER$1,
|
|
1574
|
+
MODIFIED_FILE_HEADER: MODIFIED_FILE_HEADER$1
|
|
1575
|
+
};
|
|
1576
|
+
|
|
1541
1577
|
/**
|
|
1542
1578
|
* Component: PatchUtils Parser
|
|
1543
1579
|
* Block-UUID: ce634df9-ff99-482a-a261-56ab34a2546e
|
|
1544
1580
|
* Parent-UUID: fcc85ec1-0146-40bf-a937-6f7928258cbf
|
|
1545
|
-
* Version: 1.
|
|
1546
|
-
* Description: Handles parsing, validation, extraction, and detection of traditional unified diff patches. Extracts metadata and raw diff content.
|
|
1581
|
+
* Version: 1.2.0
|
|
1582
|
+
* Description: Handles parsing, validation, extraction, and detection of traditional unified diff patches and abbreviated patches. Extracts metadata and raw diff content.
|
|
1547
1583
|
* Language: JavaScript
|
|
1548
1584
|
* Created-at: 2025-04-18T02:59:04.322Z
|
|
1549
|
-
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Pro (v1.1.0)
|
|
1585
|
+
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Pro (v1.1.0), Qwen 3 Coder 480B - Cerebras (v1.2.0)
|
|
1550
1586
|
*/
|
|
1551
1587
|
|
|
1552
1588
|
const { isValidVersion } = versionUtils; // Assuming SharedUtils is one level up
|
|
1589
|
+
const { PATCH_START_MARKER, PATCH_END_MARKER, PATCH_METADATA_HEADER,
|
|
1590
|
+
ORIGINAL_FILE_HEADER, MODIFIED_FILE_HEADER, ABBREVIATED_PATCH_START_MARKER,
|
|
1591
|
+
ABBREVIATED_PATCH_END_MARKER } = constants$2;
|
|
1553
1592
|
|
|
1554
1593
|
/**
|
|
1555
1594
|
* Determines the type of patch format used based on markers.
|
|
1556
|
-
*
|
|
1595
|
+
* Looks for traditional unified diff markers or abbreviated patch markers.
|
|
1557
1596
|
* @param {string} patchText - The patch text
|
|
1558
|
-
* @returns {string} 'traditional', or 'unknown'
|
|
1597
|
+
* @returns {string} 'traditional', 'abbreviated', or 'unknown'
|
|
1559
1598
|
*/
|
|
1560
1599
|
function determinePatchFormat$1(patchText) {
|
|
1561
1600
|
if (!patchText || typeof patchText !== 'string') {
|
|
@@ -1563,29 +1602,33 @@ function determinePatchFormat$1(patchText) {
|
|
|
1563
1602
|
}
|
|
1564
1603
|
|
|
1565
1604
|
// Check for required metadata header first
|
|
1566
|
-
if (!patchText.includes(
|
|
1605
|
+
if (!patchText.includes(PATCH_METADATA_HEADER)) {
|
|
1567
1606
|
return 'unknown'; // Must have metadata header
|
|
1568
1607
|
}
|
|
1569
1608
|
|
|
1570
1609
|
// Check for traditional unified diff markers *after* potential metadata and start marker
|
|
1571
1610
|
// Look for ---, +++, @@ after the start marker
|
|
1572
|
-
const
|
|
1573
|
-
if (
|
|
1574
|
-
|
|
1575
|
-
}
|
|
1611
|
+
const traditionalStartMarkerIndex = patchText.indexOf(PATCH_START_MARKER);
|
|
1612
|
+
if (traditionalStartMarkerIndex !== -1) {
|
|
1613
|
+
const contentAfterMarker = patchText.substring(traditionalStartMarkerIndex);
|
|
1576
1614
|
|
|
1577
|
-
|
|
1615
|
+
// Use regex for more reliable detection within the content part
|
|
1616
|
+
const traditionalMarkers = /^\s*--- Original\s*\n\s*\+\+\+ Modified\s*\n\s*@@ -\d+(?:,\d+)? \+\d+(?:,\d+)? @@/m;
|
|
1578
1617
|
|
|
1579
|
-
|
|
1580
|
-
|
|
1618
|
+
if (traditionalMarkers.test(contentAfterMarker)) {
|
|
1619
|
+
return 'traditional';
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1581
1622
|
|
|
1582
|
-
|
|
1583
|
-
|
|
1623
|
+
// Check for abbreviated patch markers
|
|
1624
|
+
const abbreviatedStartMarkerIndex = patchText.indexOf(ABBREVIATED_PATCH_START_MARKER);
|
|
1625
|
+
if (abbreviatedStartMarkerIndex !== -1) {
|
|
1626
|
+
return 'abbreviated';
|
|
1584
1627
|
}
|
|
1585
1628
|
|
|
1586
1629
|
// Removed check for obsolete '@=' context marker
|
|
1587
1630
|
|
|
1588
|
-
return 'unknown'; // Format doesn't match expected
|
|
1631
|
+
return 'unknown'; // Format doesn't match expected structures after markers
|
|
1589
1632
|
}
|
|
1590
1633
|
|
|
1591
1634
|
/**
|
|
@@ -1606,7 +1649,8 @@ function extractPatchMetadata$1(patchText) {
|
|
|
1606
1649
|
const trimmedLine = line.trim();
|
|
1607
1650
|
|
|
1608
1651
|
// Stop processing metadata if we hit content markers or the start marker
|
|
1609
|
-
if (trimmedLine ===
|
|
1652
|
+
if (trimmedLine === PATCH_START_MARKER ||
|
|
1653
|
+
trimmedLine === ABBREVIATED_PATCH_START_MARKER ||
|
|
1610
1654
|
line.startsWith('--- ') || // Standard diff header start
|
|
1611
1655
|
line.startsWith('+++ ') || // Standard diff header start
|
|
1612
1656
|
line.startsWith('@@ ')) // Standard diff hunk header start
|
|
@@ -1628,7 +1672,7 @@ function extractPatchMetadata$1(patchText) {
|
|
|
1628
1672
|
}
|
|
1629
1673
|
}
|
|
1630
1674
|
// Allow lines that are just comments (e.g., # Description continued)
|
|
1631
|
-
} else if (trimmedLine !== '' && !trimmedLine.startsWith(
|
|
1675
|
+
} else if (trimmedLine !== '' && !trimmedLine.startsWith(PATCH_METADATA_HEADER)) {
|
|
1632
1676
|
break;
|
|
1633
1677
|
}
|
|
1634
1678
|
}
|
|
@@ -1669,11 +1713,11 @@ function validatePatchMetadata$1(metadata) {
|
|
|
1669
1713
|
}
|
|
1670
1714
|
|
|
1671
1715
|
// Validate UUIDs are not the template string
|
|
1672
|
-
if (metadata['Source-Block-UUID'] === '
|
|
1673
|
-
errors.push('Source-Block-UUID contains placeholder value "
|
|
1716
|
+
if (metadata['Source-Block-UUID'] === '{{GS-UUID}}') {
|
|
1717
|
+
errors.push('Source-Block-UUID contains placeholder value "{{GS-UUID}}".');
|
|
1674
1718
|
}
|
|
1675
|
-
if (metadata['Target-Block-UUID'] === '
|
|
1676
|
-
errors.push('Target-Block-UUID contains placeholder value "
|
|
1719
|
+
if (metadata['Target-Block-UUID'] === '{{GS-UUID}}') {
|
|
1720
|
+
errors.push('Target-Block-UUID contains placeholder value "{{GS-UUID}}".');
|
|
1677
1721
|
}
|
|
1678
1722
|
|
|
1679
1723
|
return errors;
|
|
@@ -1686,23 +1730,34 @@ function validatePatchMetadata$1(metadata) {
|
|
|
1686
1730
|
* @param {string} format - Expected format (should be 'traditional').
|
|
1687
1731
|
* @returns {string} Raw unified diff content, or empty string if not found/invalid.
|
|
1688
1732
|
*/
|
|
1689
|
-
function extractPatchContent$1(patchText, format) {
|
|
1690
|
-
if (!patchText
|
|
1733
|
+
function extractPatchContent$1(patchText, format = 'traditional') {
|
|
1734
|
+
if (!patchText) {
|
|
1691
1735
|
return "";
|
|
1692
1736
|
}
|
|
1693
1737
|
|
|
1694
1738
|
const lines = patchText.split('\n');
|
|
1695
|
-
|
|
1696
1739
|
let contentLines = [];
|
|
1697
1740
|
let inContentBlock = false;
|
|
1741
|
+
let startMarker, endMarker;
|
|
1742
|
+
|
|
1743
|
+
// Determine which markers to look for based on format
|
|
1744
|
+
if (format === 'traditional') {
|
|
1745
|
+
startMarker = PATCH_START_MARKER;
|
|
1746
|
+
endMarker = PATCH_END_MARKER;
|
|
1747
|
+
} else if (format === 'abbreviated') {
|
|
1748
|
+
startMarker = ABBREVIATED_PATCH_START_MARKER;
|
|
1749
|
+
endMarker = ABBREVIATED_PATCH_END_MARKER;
|
|
1750
|
+
} else {
|
|
1751
|
+
return ""; // Unsupported format
|
|
1752
|
+
}
|
|
1698
1753
|
|
|
1699
1754
|
for (const line of lines) {
|
|
1700
|
-
if (line.trim() ===
|
|
1755
|
+
if (line.trim() === startMarker) {
|
|
1701
1756
|
inContentBlock = true;
|
|
1702
1757
|
continue; // Skip the marker line itself
|
|
1703
1758
|
}
|
|
1704
1759
|
|
|
1705
|
-
if (line.trim() ===
|
|
1760
|
+
if (line.trim() === endMarker) {
|
|
1706
1761
|
inContentBlock = false;
|
|
1707
1762
|
break; // Stop processing once end marker is found
|
|
1708
1763
|
}
|
|
@@ -1741,23 +1796,25 @@ function detectPatch(messageText) {
|
|
|
1741
1796
|
}
|
|
1742
1797
|
|
|
1743
1798
|
// Find the first code block that contains patch metadata
|
|
1744
|
-
// Regex looks for ``` optionally followed by
|
|
1745
|
-
const codeBlockRegex = /```(
|
|
1799
|
+
// Regex looks for ``` optionally followed by language hint
|
|
1800
|
+
const codeBlockRegex = /```([a-zA-Z0-9#+_-]*)?\s*\n([\s\S]*?)```/g;
|
|
1746
1801
|
let match;
|
|
1747
1802
|
while ((match = codeBlockRegex.exec(messageText)) !== null) {
|
|
1748
|
-
const
|
|
1803
|
+
const language = match[1] || '';
|
|
1804
|
+
const blockContent = match[2];
|
|
1749
1805
|
if (isPatchBlock$1(blockContent)) { // Use isPatchBlock for check
|
|
1750
1806
|
const metadata = extractPatchMetadata$1(blockContent); // Use extractPatchMetadata
|
|
1751
1807
|
// Basic validation: Check for essential UUIDs
|
|
1752
1808
|
if (metadata['Source-Block-UUID'] && metadata['Target-Block-UUID'] &&
|
|
1753
|
-
metadata['Source-Block-UUID'] !== '
|
|
1754
|
-
metadata['Target-Block-UUID'] !== '
|
|
1809
|
+
metadata['Source-Block-UUID'] !== '{{GS-UUID}}' && // Check placeholders
|
|
1810
|
+
metadata['Target-Block-UUID'] !== '{{GS-UUID}}')
|
|
1755
1811
|
{
|
|
1756
1812
|
return {
|
|
1757
1813
|
patchText: blockContent, // Return the content inside the fence
|
|
1758
1814
|
metadata,
|
|
1759
1815
|
sourceBlockUUID: metadata['Source-Block-UUID'],
|
|
1760
1816
|
targetBlockUUID: metadata['Target-Block-UUID'],
|
|
1817
|
+
language: language,
|
|
1761
1818
|
startIndex: match.index, // Store block position if needed
|
|
1762
1819
|
endIndex: match.index + match[0].length
|
|
1763
1820
|
};
|
|
@@ -1779,25 +1836,28 @@ function findAllPatches(messageText) {
|
|
|
1779
1836
|
}
|
|
1780
1837
|
|
|
1781
1838
|
const patches = [];
|
|
1782
|
-
|
|
1839
|
+
// Find code blocks with any language identifier
|
|
1840
|
+
const codeBlockRegex = /```([a-zA-Z0-9#+_-]*)?\s*\n([\s\S]*?)```/g;
|
|
1783
1841
|
|
|
1784
1842
|
let match;
|
|
1785
1843
|
while ((match = codeBlockRegex.exec(messageText)) !== null) {
|
|
1786
|
-
const
|
|
1844
|
+
const language = match[1] || '';
|
|
1845
|
+
const blockContent = match[2];
|
|
1787
1846
|
|
|
1788
1847
|
if (isPatchBlock$1(blockContent)) {
|
|
1789
1848
|
const metadata = extractPatchMetadata$1(blockContent);
|
|
1790
1849
|
|
|
1791
1850
|
// Basic validation: Check for essential UUIDs and non-placeholder values
|
|
1792
1851
|
if (metadata['Source-Block-UUID'] && metadata['Target-Block-UUID'] &&
|
|
1793
|
-
metadata['Source-Block-UUID'] !== '
|
|
1794
|
-
metadata['Target-Block-UUID'] !== '
|
|
1852
|
+
metadata['Source-Block-UUID'] !== '{{GS-UUID}}' &&
|
|
1853
|
+
metadata['Target-Block-UUID'] !== '{{GS-UUID}}')
|
|
1795
1854
|
{
|
|
1796
1855
|
patches.push({
|
|
1797
1856
|
patchText: blockContent,
|
|
1798
1857
|
metadata,
|
|
1799
1858
|
sourceBlockUUID: metadata['Source-Block-UUID'],
|
|
1800
1859
|
targetBlockUUID: metadata['Target-Block-UUID'],
|
|
1860
|
+
language: language,
|
|
1801
1861
|
startIndex: match.index,
|
|
1802
1862
|
endIndex: match.index + match[0].length
|
|
1803
1863
|
});
|
|
@@ -2867,7 +2927,7 @@ var detectAndFixRedundantChanges_1 = {
|
|
|
2867
2927
|
|
|
2868
2928
|
/**
|
|
2869
2929
|
* Component: PatchUtils Detect and Fix Overlapping Hunks
|
|
2870
|
-
* Block-UUID:
|
|
2930
|
+
* Block-UUID: 7324dab8-24ae-4a42-9dc3-766e69104ef6
|
|
2871
2931
|
* Parent-UUID: 2308ed72-91ff-48ba-bc80-310c23c01ff1
|
|
2872
2932
|
* Version: 1.0.0
|
|
2873
2933
|
* Description: Detects and optionally fixes overlapping hunks in a patch file by merging them.
|
|
@@ -8744,6 +8804,8 @@ var PatchUtils$2 = {
|
|
|
8744
8804
|
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Flash (v1.1.0)
|
|
8745
8805
|
*/
|
|
8746
8806
|
|
|
8807
|
+
const GS_TOOL_BLOCK_TYPE = 'gs-tool';
|
|
8808
|
+
|
|
8747
8809
|
/**
|
|
8748
8810
|
* Checks if a given code block content represents a GitSense Chat Tool Block.
|
|
8749
8811
|
* It verifies if the first non-empty line starts with "# GitSense Chat Tool".
|
|
@@ -8762,6 +8824,65 @@ function isToolBlock$1(content) {
|
|
|
8762
8824
|
return false;
|
|
8763
8825
|
}
|
|
8764
8826
|
|
|
8827
|
+
|
|
8828
|
+
// TODO: Add JSDocs
|
|
8829
|
+
function getToolBlocksByTool(content, tool, CodeBlockUtils) {
|
|
8830
|
+
const { blocks, warnings } = CodeBlockUtils.extractCodeBlocks(content, { silent: true });
|
|
8831
|
+
|
|
8832
|
+
return blocks.filter((block, index) => {
|
|
8833
|
+
if (block.type !== GS_TOOL_BLOCK_TYPE)
|
|
8834
|
+
return;
|
|
8835
|
+
|
|
8836
|
+
try {
|
|
8837
|
+
const data = parseToolBlock$1(block.content);
|
|
8838
|
+
|
|
8839
|
+
if (data.tool === tool) {
|
|
8840
|
+
block.index = index;
|
|
8841
|
+
return block;
|
|
8842
|
+
}
|
|
8843
|
+
} catch(error) {
|
|
8844
|
+
// FIXME: We need a more elegant way to identify examples.
|
|
8845
|
+
if (!content.includes(/Internal INTEGER IDs/)) {
|
|
8846
|
+
console.warn(`Invalid tool block JSON: ${error.message}`);
|
|
8847
|
+
}
|
|
8848
|
+
}
|
|
8849
|
+
});
|
|
8850
|
+
}
|
|
8851
|
+
|
|
8852
|
+
// TODO: Add JSDocs
|
|
8853
|
+
function getToolBlockElemsByTool(dom, tool) {
|
|
8854
|
+
const elems = dom.querySelectorAll('pre');
|
|
8855
|
+
const toolBockElems = [];
|
|
8856
|
+
|
|
8857
|
+
for ( let i = 0; i < elems.length; i++ ) {
|
|
8858
|
+
const elem = elems[i];
|
|
8859
|
+
let content = elem.textContent;
|
|
8860
|
+
|
|
8861
|
+
// We need to strip out the first two lines since this is not part of the actual code
|
|
8862
|
+
// block. These two lines are designed to make it easy to identify the language
|
|
8863
|
+
content = content.split('\n').slice(2).join('\n');
|
|
8864
|
+
|
|
8865
|
+
if (!isToolBlock$1(content))
|
|
8866
|
+
continue;
|
|
8867
|
+
|
|
8868
|
+
try {
|
|
8869
|
+
const data = parseToolBlock$1(content, { silent: true });
|
|
8870
|
+
|
|
8871
|
+
if (data.tool === tool)
|
|
8872
|
+
toolBockElems.push(elem);
|
|
8873
|
+
} catch(error) {
|
|
8874
|
+
// FIXME: We need a more elegant way to identify examples.
|
|
8875
|
+
if (!content.match(/Internal INTEGER IDs/)) {
|
|
8876
|
+
console.warn("getToolBlockElemsByTool: ",error.message);
|
|
8877
|
+
}
|
|
8878
|
+
continue;
|
|
8879
|
+
}
|
|
8880
|
+
}
|
|
8881
|
+
|
|
8882
|
+
return toolBockElems;
|
|
8883
|
+
}
|
|
8884
|
+
|
|
8885
|
+
|
|
8765
8886
|
/**
|
|
8766
8887
|
* Parses the content of a GitSense Chat Tool Block to extract the JSON payload.
|
|
8767
8888
|
* It strips the marker line and any subsequent lines starting with '#' (comments)
|
|
@@ -8870,7 +8991,7 @@ function replaceToolBlock(markdownContent, toolName, newToolData, CodeBlockUtils
|
|
|
8870
8991
|
// 2. Iterate through the processed blocks to find the target GitSense Chat Tool Block
|
|
8871
8992
|
for (let i = 0; i < blocks.length; i++) {
|
|
8872
8993
|
const block = blocks[i];
|
|
8873
|
-
if (block.type ===
|
|
8994
|
+
if (block.type === GS_TOOL_BLOCK_TYPE && block.toolData && block.toolData.tool === toolName) {
|
|
8874
8995
|
targetBlockIndex = i;
|
|
8875
8996
|
break; // Found the first matching tool block
|
|
8876
8997
|
}
|
|
@@ -9004,11 +9125,15 @@ function detectAndFormatUnfencedToolBlock(messageContent) {
|
|
|
9004
9125
|
};
|
|
9005
9126
|
}
|
|
9006
9127
|
|
|
9128
|
+
|
|
9129
|
+
|
|
9007
9130
|
var GSToolBlockUtils$3 = {
|
|
9008
9131
|
isToolBlock: isToolBlock$1,
|
|
9009
9132
|
parseToolBlock: parseToolBlock$1,
|
|
9010
9133
|
formatToolBlock,
|
|
9011
9134
|
replaceToolBlock,
|
|
9135
|
+
getToolBlocksByTool,
|
|
9136
|
+
getToolBlockElemsByTool,
|
|
9012
9137
|
detectAndFormatUnfencedToolBlock,
|
|
9013
9138
|
};
|
|
9014
9139
|
|
|
@@ -9308,16 +9433,16 @@ var JsonUtils$2 = {
|
|
|
9308
9433
|
* Component: CodeBlockUtils Block Processor
|
|
9309
9434
|
* Block-UUID: 1d8a559b-4f7a-4b0b-9e0a-13786f94a74e
|
|
9310
9435
|
* Parent-UUID: 082abf8b-079f-4c95-8464-0e66c0de45eb
|
|
9311
|
-
* Version: 1.
|
|
9436
|
+
* Version: 1.5.0
|
|
9312
9437
|
* Description: Processes the content of identified code blocks, parsing headers or patch details, and provides utilities like fixing UUIDs within blocks.
|
|
9313
9438
|
* Language: JavaScript
|
|
9314
9439
|
* Created-at: 2025-07-21T00:33:22.312Z
|
|
9315
|
-
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Pro (v1.1.0), Gemini 2.5 Pro (v1.2.0), Gemini 2.5 Flash Thinking (v1.3.0), Gemini 2.5 Flash Thinking (v1.4.0)
|
|
9440
|
+
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Pro (v1.1.0), Gemini 2.5 Pro (v1.2.0), Gemini 2.5 Flash Thinking (v1.3.0), Gemini 2.5 Flash Thinking (v1.4.0), Qwen 3 Coder 480B - Cerebras (v1.5.0)
|
|
9316
9441
|
*/
|
|
9317
9442
|
|
|
9318
9443
|
const { findAllCodeFences: findAllCodeFences$3, matchFencesAndExtractBlocks: matchFencesAndExtractBlocks$3 } = blockExtractor;
|
|
9319
9444
|
const { parseHeader: parseHeader$2 } = headerUtils;
|
|
9320
|
-
const { validateUUID: validateUUID$2
|
|
9445
|
+
const { validateUUID: validateUUID$2 } = uuidUtils;
|
|
9321
9446
|
const AnalysisBlockUtils$2 = AnalysisBlockUtils$3;
|
|
9322
9447
|
const PatchUtils$1 = PatchUtils$2;
|
|
9323
9448
|
const GSToolBlockUtils$2 = GSToolBlockUtils$3;
|
|
@@ -9433,7 +9558,7 @@ function processBlockContent(content, language, position, incomplete, options =
|
|
|
9433
9558
|
if (PatchUtils$1.isPatchBlock(content)) {
|
|
9434
9559
|
const patchFormat = PatchUtils$1.determinePatchFormat(content);
|
|
9435
9560
|
const metadata = PatchUtils$1.extractPatchMetadata(content); // Extract metadata regardless of validation
|
|
9436
|
-
const patchContent = PatchUtils$1.extractPatchContent(content); // Extract raw patch content
|
|
9561
|
+
const patchContent = PatchUtils$1.extractPatchContent(content, patchFormat); // Extract raw patch content
|
|
9437
9562
|
|
|
9438
9563
|
let patchValidationResult = { valid: true, errors: [], patches: null }; // Default valid state
|
|
9439
9564
|
|
|
@@ -9450,36 +9575,16 @@ function processBlockContent(content, language, position, incomplete, options =
|
|
|
9450
9575
|
// For now, just warn, but return the extracted (potentially invalid) metadata.
|
|
9451
9576
|
}
|
|
9452
9577
|
|
|
9453
|
-
//
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
if (!patches || patches.length === 0) {
|
|
9458
|
-
patchValidationResult = { valid: false, errors: ['No valid context patch content found.'], patches: null };
|
|
9459
|
-
warnings.push({
|
|
9460
|
-
position: position,
|
|
9461
|
-
type: 'patch_content_error',
|
|
9462
|
-
message: 'No valid context patch content found.',
|
|
9463
|
-
content: content,
|
|
9464
|
-
});
|
|
9465
|
-
} else {
|
|
9466
|
-
// Basic validation passed (structure was parsable)
|
|
9467
|
-
patchValidationResult = { valid: true, errors: [], patches: patches };
|
|
9468
|
-
}
|
|
9469
|
-
} catch (error) {
|
|
9470
|
-
patchValidationResult = { valid: false, errors: [error.message], patches: null };
|
|
9471
|
-
warnings.push({
|
|
9472
|
-
position: position,
|
|
9473
|
-
type: 'patch_parse_error',
|
|
9474
|
-
message: `Error parsing context patch: ${error.message}`,
|
|
9475
|
-
content: content,
|
|
9476
|
-
});
|
|
9477
|
-
}
|
|
9578
|
+
// Determine the correct language for the block
|
|
9579
|
+
let blockLanguage = language; // Default to the fence language
|
|
9580
|
+
if (patchFormat === 'traditional') {
|
|
9581
|
+
blockLanguage = 'diff'; // Enforce 'diff' for traditional patches
|
|
9478
9582
|
}
|
|
9583
|
+
// For abbreviated patches, keep the original language (e.g., 'javascript', 'python')
|
|
9479
9584
|
|
|
9480
9585
|
return {
|
|
9481
9586
|
type: 'patch',
|
|
9482
|
-
language:
|
|
9587
|
+
language: blockLanguage, // Use determined language
|
|
9483
9588
|
content: content, // Full original content within fences
|
|
9484
9589
|
position: position,
|
|
9485
9590
|
incomplete: incomplete,
|
|
@@ -9673,8 +9778,10 @@ function processBlockContents(text, completeBlocks, incompleteBlocks, options) {
|
|
|
9673
9778
|
* @returns {Object} { blocks: Array, warnings: Array, hasIncompleteBlocks: boolean, lastIncompleteBlock: Object|null }
|
|
9674
9779
|
*/
|
|
9675
9780
|
function processCodeBlocks$5(text, options = { silent: false, validatePatches: false }) {
|
|
9676
|
-
if (typeof text !== "string") {
|
|
9677
|
-
|
|
9781
|
+
if (typeof text !== "string") {
|
|
9782
|
+
if (text != null )
|
|
9783
|
+
console.warn("Warning: Input must be a string.");
|
|
9784
|
+
|
|
9678
9785
|
return {
|
|
9679
9786
|
blocks: [],
|
|
9680
9787
|
warnings: [{ type: 'invalid_input', message: 'Input must be a string.' }],
|
|
@@ -10595,19 +10702,114 @@ var updateCodeBlock_1 = {
|
|
|
10595
10702
|
updateCodeBlockInMessage: updateCodeBlockInMessage$1,
|
|
10596
10703
|
deleteCodeBlockByIndex: deleteCodeBlockByIndex$2};
|
|
10597
10704
|
|
|
10705
|
+
/**
|
|
10706
|
+
* Component: CodeBlockUtils Lineage Tracer
|
|
10707
|
+
* Block-UUID: 13b08cce-6fd1-4ec9-a915-240714ee89b9
|
|
10708
|
+
* Parent-UUID: df1a629b-2cc0-4677-b410-3172ee0e0f9f
|
|
10709
|
+
* Version: 1.1.0
|
|
10710
|
+
* Description: Provides a utility function to trace the full lineage (patch-based and parent-based) of code blocks within a chat, including loop detection.
|
|
10711
|
+
* Language: JavaScript
|
|
10712
|
+
* Created-at: 2025-10-23T01:28:10.456Z
|
|
10713
|
+
* Authors: Qwen 3 Coder 480B - Cerebras (v1.0.0), Qwen 3 Coder 480B - Cerebras (v1.1.0)
|
|
10714
|
+
*/
|
|
10715
|
+
|
|
10716
|
+
/**
|
|
10717
|
+
* Traces the full lineage of a code block or patch identified by a UUID.
|
|
10718
|
+
* The lineage includes the block itself and all its ancestors, tracing backwards
|
|
10719
|
+
* first through patch relationships (Source-Block-UUID -> Target-Block-UUID)
|
|
10720
|
+
* and then through Parent-UUID relationships.
|
|
10721
|
+
* Loop detection is included to prevent infinite tracing.
|
|
10722
|
+
*
|
|
10723
|
+
* @param {string} uuid - The UUID of the target code block or patch.
|
|
10724
|
+
* @param {Map<string, object>} blockMap - A map where keys are UUIDs (for code blocks)
|
|
10725
|
+
* or patch UUIDs (source:target) and values
|
|
10726
|
+
* are the corresponding block objects.
|
|
10727
|
+
* Block objects are expected to have
|
|
10728
|
+
* properties like `isPatch`, `metadata`, and `header`.
|
|
10729
|
+
* @returns {Array<object>} An array of block objects representing the lineage.
|
|
10730
|
+
* The first element is the block for the provided `uuid`.
|
|
10731
|
+
* Subsequent elements are its ancestors.
|
|
10732
|
+
* Returns an empty array if the initial uuid is not found.
|
|
10733
|
+
* If a loop is detected, the last element will have a property `loopDetected: true`.
|
|
10734
|
+
*/
|
|
10735
|
+
function getLineage$2(uuid, blockMap) {
|
|
10736
|
+
if (!uuid || !blockMap) {
|
|
10737
|
+
return [];
|
|
10738
|
+
}
|
|
10739
|
+
|
|
10740
|
+
const lineage = [];
|
|
10741
|
+
const visitedUuids = new Set();
|
|
10742
|
+
let currentUuid = uuid;
|
|
10743
|
+
|
|
10744
|
+
while (currentUuid) {
|
|
10745
|
+
// --- Loop Detection ---
|
|
10746
|
+
if (visitedUuids.has(currentUuid)) {
|
|
10747
|
+
// Add a marker or the block itself to indicate the loop
|
|
10748
|
+
const loopBlock = blockMap.get(currentUuid) || { uuid: currentUuid, loopDetected: true, type: 'loop-marker' };
|
|
10749
|
+
loopBlock.loopDetected = true; // Ensure the property is set
|
|
10750
|
+
lineage.push(loopBlock);
|
|
10751
|
+
break; // Stop the trace
|
|
10752
|
+
}
|
|
10753
|
+
visitedUuids.add(currentUuid);
|
|
10754
|
+
|
|
10755
|
+
// --- 1. Try to find the block directly by its UUID ---
|
|
10756
|
+
let block = blockMap.get(currentUuid);
|
|
10757
|
+
|
|
10758
|
+
// --- 2. If not found directly, search patch keys ---
|
|
10759
|
+
if (!block) {
|
|
10760
|
+
for (const [key, value] of blockMap) {
|
|
10761
|
+
// Check if the map key is a patch key (contains ':') and ends with our target UUID
|
|
10762
|
+
if (key.includes(':') && key.endsWith(`:${currentUuid}`)) {
|
|
10763
|
+
block = value;
|
|
10764
|
+
break;
|
|
10765
|
+
}
|
|
10766
|
+
}
|
|
10767
|
+
}
|
|
10768
|
+
|
|
10769
|
+
// --- 3. If a block was found, add it to the lineage ---
|
|
10770
|
+
if (block) {
|
|
10771
|
+
lineage.push(block);
|
|
10772
|
+
|
|
10773
|
+
let nextUuid = null;
|
|
10774
|
+
|
|
10775
|
+
// --- 3a. If it's a patch, move to its source UUID ---
|
|
10776
|
+
if (block.isPatch && block.metadata && block.metadata['Source-Block-UUID']) {
|
|
10777
|
+
nextUuid = block.metadata['Source-Block-UUID'];
|
|
10778
|
+
}
|
|
10779
|
+
// --- 3b. If it's a code block, move to its Parent-UUID (if valid) ---
|
|
10780
|
+
else if (!block.isPatch && block.header && block.header['Parent-UUID'] && block.header['Parent-UUID'] !== 'N/A') {
|
|
10781
|
+
nextUuid = block.header['Parent-UUID'];
|
|
10782
|
+
}
|
|
10783
|
+
// If it's a code block with Parent-UUID: 0c104865-260a-4942-8cb6-93bebf40c450
|
|
10784
|
+
|
|
10785
|
+
currentUuid = nextUuid;
|
|
10786
|
+
} else {
|
|
10787
|
+
// If no block is found for currentUuid, the lineage is incomplete.
|
|
10788
|
+
// We could add a placeholder here if needed, but for now, we just stop.
|
|
10789
|
+
currentUuid = null;
|
|
10790
|
+
}
|
|
10791
|
+
}
|
|
10792
|
+
|
|
10793
|
+
return lineage;
|
|
10794
|
+
}
|
|
10795
|
+
|
|
10796
|
+
var lineageTracer = {
|
|
10797
|
+
getLineage: getLineage$2
|
|
10798
|
+
};
|
|
10799
|
+
|
|
10598
10800
|
/**
|
|
10599
10801
|
* Component: CodeBlockUtils Index
|
|
10600
|
-
* Block-UUID:
|
|
10601
|
-
* Parent-UUID:
|
|
10602
|
-
* Version: 1.
|
|
10802
|
+
* Block-UUID: 98684aa5-d597-41b6-a7fd-cc16482aafdc
|
|
10803
|
+
* Parent-UUID: 7e9d3f8a-1b2c-4d5e-8f9a-0123456789ab
|
|
10804
|
+
* Version: 1.5.0
|
|
10603
10805
|
* Description: Aggregates and exports all utilities related to code block processing from the CodeBlockUtils module. Serves as the main entry point for this module.
|
|
10604
10806
|
* Language: JavaScript
|
|
10605
10807
|
* Created-at: 2025-04-15T16:02:20.217Z
|
|
10606
|
-
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Pro (v1.1.0), Claude 3.7 Sonnet (v1.2.0), Gemini 2.5 Pro (v1.3.0), Gemini 2.5 Flash Thinking (v1.4.0)
|
|
10808
|
+
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Pro (v1.1.0), Claude 3.7 Sonnet (v1.2.0), Gemini 2.5 Pro (v1.3.0), Gemini 2.5 Flash Thinking (v1.4.0), Qwen 3 Coder 480B - Cerebras (v1.5.0)
|
|
10607
10809
|
*/
|
|
10608
10810
|
|
|
10609
10811
|
// Import from individual utility files
|
|
10610
|
-
const { COMMENT_STYLES: COMMENT_STYLES$1 } = constants$
|
|
10812
|
+
const { COMMENT_STYLES: COMMENT_STYLES$1 } = constants$3;
|
|
10611
10813
|
const { generateUUID: generateUUID$1, validateUUID: validateUUID$1 } = uuidUtils;
|
|
10612
10814
|
const { isValidISOTimestamp: isValidISOTimestamp$1, parseHeader: parseHeader$1, getHeaderLineCount } = headerUtils;
|
|
10613
10815
|
const { findAllCodeFences: findAllCodeFences$1, matchFencesAndExtractBlocks: matchFencesAndExtractBlocks$1, extractCodeBlocksWithUUIDs, findCodeBlockByUUID } = blockExtractor;
|
|
@@ -10619,9 +10821,10 @@ const { parseCodeBlocks: parseCommentDelimitedBlocks$1 } = headerParser;
|
|
|
10619
10821
|
const { removeCodeBlockMarkers: removeCodeBlockMarkers$1 } = markerRemover;
|
|
10620
10822
|
const { updateCodeBlockByIndex: updateCodeBlockByIndex$1, updateCodeBlockByUUID, updateCodeBlock, updateCodeBlockInMessage, deleteCodeBlockByIndex: deleteCodeBlockByIndex$1 } = updateCodeBlock_1;
|
|
10621
10823
|
const { formatWithLineNumbers: formatWithLineNumbers$1, formatBlockWithLineNumbers: formatBlockWithLineNumbers$1, formatBlocksWithLineNumbers: formatBlocksWithLineNumbers$1, removeLineNumbers: removeLineNumbers$1 } = lineNumberFormatter;
|
|
10824
|
+
const { getLineage: getLineage$1 } = lineageTracer;
|
|
10622
10825
|
|
|
10623
10826
|
// Export all imported items
|
|
10624
|
-
var CodeBlockUtils$
|
|
10827
|
+
var CodeBlockUtils$7 = {
|
|
10625
10828
|
// Constants
|
|
10626
10829
|
COMMENT_STYLES: COMMENT_STYLES$1,
|
|
10627
10830
|
|
|
@@ -10673,22 +10876,23 @@ var CodeBlockUtils$5 = {
|
|
|
10673
10876
|
// Line Number Formatting Utilities
|
|
10674
10877
|
formatWithLineNumbers: formatWithLineNumbers$1,
|
|
10675
10878
|
formatBlockWithLineNumbers: formatBlockWithLineNumbers$1,
|
|
10676
|
-
formatBlocksWithLineNumbers: formatBlocksWithLineNumbers$1,
|
|
10879
|
+
formatBlocksWithLineNumbers: formatBlocksWithLineNumbers$1,
|
|
10880
|
+
getLineage: getLineage$1,
|
|
10677
10881
|
removeLineNumbers: removeLineNumbers$1,
|
|
10678
10882
|
};
|
|
10679
10883
|
|
|
10680
10884
|
/*
|
|
10681
10885
|
* Component: ContextUtils
|
|
10682
|
-
* Block-UUID:
|
|
10683
|
-
* Parent-UUID:
|
|
10684
|
-
* Version: 1.
|
|
10886
|
+
* Block-UUID: 534c348d-a11f-4de6-ad15-f33068d51fb8
|
|
10887
|
+
* Parent-UUID: a0b71292-b1cc-401a-8ce2-544a047b0fef
|
|
10888
|
+
* Version: 1.4.0
|
|
10685
10889
|
* Description: Provides utility functions for parsing context message sections to extract file details and code blocks, and for formatting content for LLM context.
|
|
10686
10890
|
* Language: JavaScript
|
|
10687
10891
|
* Created-at: 2025-05-09T01:36:20.107Z
|
|
10688
|
-
* Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash (v1.1.0), Qwen 3 Coder 480B - Cerebras (v1.2.0), Qwen 3 Coder 480B - Cerebras (v1.3.0)
|
|
10892
|
+
* Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash (v1.1.0), Qwen 3 Coder 480B - Cerebras (v1.2.0), Qwen 3 Coder 480B - Cerebras (v1.3.0), Qwen 3 Coder 480B - Cerebras (v1.4.0)
|
|
10689
10893
|
*/
|
|
10690
10894
|
|
|
10691
|
-
const CodeBlockUtils$
|
|
10895
|
+
const CodeBlockUtils$6 = CodeBlockUtils$7;
|
|
10692
10896
|
const MessageUtils$2 = MessageUtils$3;
|
|
10693
10897
|
|
|
10694
10898
|
/**
|
|
@@ -10755,6 +10959,41 @@ function _createContextSummary(items, contentType) {
|
|
|
10755
10959
|
return summary + "\n";
|
|
10756
10960
|
}
|
|
10757
10961
|
|
|
10962
|
+
/**
|
|
10963
|
+
* Extracts all context files from a given chat object.
|
|
10964
|
+
* Iterates through chat messages, identifies context loader outputs,
|
|
10965
|
+
* and parses them into individual file objects.
|
|
10966
|
+
*
|
|
10967
|
+
* @param {object} chat - The GitSense chat object.
|
|
10968
|
+
* @returns {Array<object>} An array of parsed context file objects.
|
|
10969
|
+
* Returns an empty array if no context files are found or on error.
|
|
10970
|
+
*/
|
|
10971
|
+
function getContextFiles$1(chat) {
|
|
10972
|
+
const ChatUtils = ChatUtils$2;
|
|
10973
|
+
const contextFiles = [];
|
|
10974
|
+
const messages = ChatUtils.getChatMessages(chat);
|
|
10975
|
+
|
|
10976
|
+
if (!Array.isArray(messages)) {
|
|
10977
|
+
console.warn("getContextFiles: Provided chat object does not contain a valid messages array.");
|
|
10978
|
+
return contextFiles;
|
|
10979
|
+
}
|
|
10980
|
+
|
|
10981
|
+
messages.forEach(message => {
|
|
10982
|
+
// Check if the message content is a context message
|
|
10983
|
+
if (MessageUtils$2.isContextMessage(message.message)) {
|
|
10984
|
+
try {
|
|
10985
|
+
// Extract all context sections from the message content
|
|
10986
|
+
const extractedFiles = extractContextSections$1(message.message);
|
|
10987
|
+
contextFiles.push(...extractedFiles);
|
|
10988
|
+
} catch (error) {
|
|
10989
|
+
console.warn(`getContextFiles: Failed to extract context sections from message ID ${message.id}:`, error);
|
|
10990
|
+
}
|
|
10991
|
+
}
|
|
10992
|
+
});
|
|
10993
|
+
|
|
10994
|
+
return contextFiles;
|
|
10995
|
+
}
|
|
10996
|
+
|
|
10758
10997
|
/**
|
|
10759
10998
|
* Escapes backticks in code blocks to prevent premature termination of LLM-generated code blocks.
|
|
10760
10999
|
* @param {string} content - The content string to escape.
|
|
@@ -10827,7 +11066,7 @@ function parseContextSection$1(sectionText) {
|
|
|
10827
11066
|
}
|
|
10828
11067
|
});
|
|
10829
11068
|
|
|
10830
|
-
const { blocks, warnings } = CodeBlockUtils$
|
|
11069
|
+
const { blocks, warnings } = CodeBlockUtils$6.extractCodeBlocks(sectionText, { silent: true });
|
|
10831
11070
|
const codeBlocks = blocks.filter(block => block.type === 'code');
|
|
10832
11071
|
|
|
10833
11072
|
if (codeBlocks.length === 0) {
|
|
@@ -11029,6 +11268,7 @@ function formatContextContent$1(items, contentType, contentOption) {
|
|
|
11029
11268
|
var ContextUtils$2 = {
|
|
11030
11269
|
parseContextSection: parseContextSection$1,
|
|
11031
11270
|
extractContextSections: extractContextSections$1,
|
|
11271
|
+
getContextFiles: getContextFiles$1,
|
|
11032
11272
|
extractContextItemsOverviewTableRows: extractContextItemsOverviewTableRows$1,
|
|
11033
11273
|
formatContextContent: formatContextContent$1,
|
|
11034
11274
|
};
|
|
@@ -11086,7 +11326,7 @@ var contextMapper = {
|
|
|
11086
11326
|
|
|
11087
11327
|
/*
|
|
11088
11328
|
* Component: AnalyzerUtils Constants
|
|
11089
|
-
* Block-UUID:
|
|
11329
|
+
* Block-UUID: fec5dcc4-a1d0-4ef7-8828-3e44a75892c4
|
|
11090
11330
|
* Parent-UUID: N/A
|
|
11091
11331
|
* Version: 1.0.0
|
|
11092
11332
|
* Description: Defines constants specific to the AnalyzerUtils module.
|
|
@@ -11112,7 +11352,7 @@ var constants = {
|
|
|
11112
11352
|
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
11113
11353
|
*/
|
|
11114
11354
|
|
|
11115
|
-
const CodeBlockUtils$
|
|
11355
|
+
const CodeBlockUtils$5 = CodeBlockUtils$7;
|
|
11116
11356
|
const GSToolBlockUtils$1 = GSToolBlockUtils$3;
|
|
11117
11357
|
const JsonUtils$1 = JsonUtils$2;
|
|
11118
11358
|
const { ANALYZE_HEADER_PREFIX } = constants;
|
|
@@ -11129,7 +11369,7 @@ const { ANALYZE_HEADER_PREFIX } = constants;
|
|
|
11129
11369
|
*/
|
|
11130
11370
|
function processLLMAnalysisResponse$2(messageContent, stoppedStreaming) {
|
|
11131
11371
|
const silent = { silent: true };
|
|
11132
|
-
const { blocks, warnings } = CodeBlockUtils$
|
|
11372
|
+
const { blocks, warnings } = CodeBlockUtils$5.extractCodeBlocks(messageContent, silent);
|
|
11133
11373
|
|
|
11134
11374
|
const analysisBlocks = [];
|
|
11135
11375
|
const analysisMetadataBlocks = [];
|
|
@@ -11314,7 +11554,7 @@ var dataValidator = {
|
|
|
11314
11554
|
|
|
11315
11555
|
/*
|
|
11316
11556
|
* Component: AnalyzerUtils Instruction Loader
|
|
11317
|
-
* Block-UUID:
|
|
11557
|
+
* Block-UUID: 3ecd422e-1dd8-482d-ae3f-90a5eae3ae44
|
|
11318
11558
|
* Parent-UUID: N/A
|
|
11319
11559
|
* Version: 1.0.0
|
|
11320
11560
|
* Description: Provides utility functions for loading raw analyzer instruction content.
|
|
@@ -11323,19 +11563,19 @@ var dataValidator = {
|
|
|
11323
11563
|
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
11324
11564
|
*/
|
|
11325
11565
|
|
|
11326
|
-
const fs$
|
|
11327
|
-
const path$
|
|
11566
|
+
const fs$8 = require$$0.promises;
|
|
11567
|
+
const path$6 = require$$1;
|
|
11328
11568
|
|
|
11329
11569
|
/**
|
|
11330
11570
|
* Retrieves the raw Markdown content of the analyzer's '1.md' instruction file.
|
|
11331
11571
|
*
|
|
11332
|
-
* @param {string}
|
|
11572
|
+
* @param {string} analyzersBasePath - The absolute path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
|
|
11333
11573
|
* @param {string} analyzerId - The unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
|
|
11334
11574
|
* @returns {Promise<string|null>} A promise that resolves with the full Markdown content of the '1.md' file, or null if not found/invalid.
|
|
11335
11575
|
*/
|
|
11336
|
-
async function getAnalyzerInstructionsContent$3(
|
|
11337
|
-
if (typeof
|
|
11338
|
-
console.error('Error:
|
|
11576
|
+
async function getAnalyzerInstructionsContent$3(analyzersBasePath, analyzerId) {
|
|
11577
|
+
if (typeof analyzersBasePath !== 'string' || analyzersBasePath.trim() === '') {
|
|
11578
|
+
console.error('Error: analyzersBasePath is required.');
|
|
11339
11579
|
return null;
|
|
11340
11580
|
}
|
|
11341
11581
|
if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
|
|
@@ -11350,10 +11590,10 @@ async function getAnalyzerInstructionsContent$3(analyzeMessagesBasePath, analyze
|
|
|
11350
11590
|
}
|
|
11351
11591
|
const [analyzerName, contentType, instructionsType] = parts;
|
|
11352
11592
|
|
|
11353
|
-
const instructionsFilePath = path$
|
|
11593
|
+
const instructionsFilePath = path$6.join(analyzersBasePath, analyzerName, contentType, instructionsType, '1.md');
|
|
11354
11594
|
|
|
11355
11595
|
try {
|
|
11356
|
-
const fileContent = await fs$
|
|
11596
|
+
const fileContent = await fs$8.readFile(instructionsFilePath, 'utf8');
|
|
11357
11597
|
const parts = fileContent.split('\n\n\n');
|
|
11358
11598
|
parts.shift();
|
|
11359
11599
|
return parts.join('\n\n\n');
|
|
@@ -11373,20 +11613,56 @@ var instructionLoader = {
|
|
|
11373
11613
|
};
|
|
11374
11614
|
|
|
11375
11615
|
/*
|
|
11616
|
+
* Component: AnalyzerUtils JSON Parser
|
|
11617
|
+
* Block-UUID: 4dd21efd-3ad3-43e1-adf0-d52d7c560970
|
|
11618
|
+
* Version: 1.0.0
|
|
11619
|
+
* Description: Provides utility functions for pre-processing JSON content from analyzer instructions.
|
|
11620
|
+
* Language: JavaScript
|
|
11621
|
+
* Created-at: 2025-11-23T05:38:15.725Z
|
|
11622
|
+
* Authors: GLM-4.6 (v1.0.0)
|
|
11623
|
+
*/
|
|
11624
|
+
|
|
11625
|
+
/**
|
|
11626
|
+
* Pre-processes JSON content to quote unquoted template strings before parsing.
|
|
11627
|
+
* This handles cases where {{SYSTEM: ...}} and {{ANALYZER: ...}} placeholders
|
|
11628
|
+
* are not properly quoted in the JSON.
|
|
11629
|
+
*
|
|
11630
|
+
* @param {string} jsonString - The raw JSON string content.
|
|
11631
|
+
* @returns {string} The processed JSON string with template strings quoted.
|
|
11632
|
+
*/
|
|
11633
|
+
function preprocessJsonForValidation$5(jsonString) {
|
|
11634
|
+
// Find all unquoted template strings and quote them with proper escaping
|
|
11635
|
+
// This regex looks for template strings that aren't already quoted
|
|
11636
|
+
return jsonString.replace(
|
|
11637
|
+
/(?<!")(\{\{(SYSTEM|ANALYZER):[^}]+\}\})(?!")/g,
|
|
11638
|
+
(match, template) => {
|
|
11639
|
+
// Escape any double quotes within the template string
|
|
11640
|
+
const escapedTemplate = template.replace(/"/g, '\\"');
|
|
11641
|
+
return `"${escapedTemplate}"`;
|
|
11642
|
+
}
|
|
11643
|
+
);
|
|
11644
|
+
}
|
|
11645
|
+
|
|
11646
|
+
var jsonParser = {
|
|
11647
|
+
preprocessJsonForValidation: preprocessJsonForValidation$5
|
|
11648
|
+
};
|
|
11649
|
+
|
|
11650
|
+
/**
|
|
11376
11651
|
* Component: AnalyzerUtils Discovery
|
|
11377
|
-
* Block-UUID:
|
|
11378
|
-
* Parent-UUID:
|
|
11379
|
-
* Version: 1.1
|
|
11380
|
-
* Description: Provides utility functions for discovering available analyzers.
|
|
11652
|
+
* Block-UUID: 26a7df9b-ef29-4dcd-aab2-9cdc3a11133c
|
|
11653
|
+
* Parent-UUID: aa999515-84fb-43f6-91a7-cf79248d7286
|
|
11654
|
+
* Version: 1.3.1
|
|
11655
|
+
* Description: Provides utility functions for discovering available analyzers. Updated to include version and tags in analyzer objects.
|
|
11381
11656
|
* Language: JavaScript
|
|
11382
|
-
* Created-at: 2025-
|
|
11383
|
-
* Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0)
|
|
11657
|
+
* Created-at: 2025-11-27T14:45:30.978Z
|
|
11658
|
+
* Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0), Qwen 3 Coder 480B - Cerebras (v1.2.0), GLM-4.6 (v1.2.1), GLM-4.6 (v1.3.0), GLM-4.6 (v1.3.1)
|
|
11384
11659
|
*/
|
|
11385
11660
|
|
|
11386
|
-
const fs$
|
|
11387
|
-
const path$
|
|
11661
|
+
const fs$7 = require$$0.promises;
|
|
11662
|
+
const path$5 = require$$1;
|
|
11388
11663
|
const { getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$2 } = instructionLoader;
|
|
11389
|
-
const
|
|
11664
|
+
const { preprocessJsonForValidation: preprocessJsonForValidation$4 } = jsonParser;
|
|
11665
|
+
const CodeBlockUtils$4 = CodeBlockUtils$7;
|
|
11390
11666
|
|
|
11391
11667
|
/**
|
|
11392
11668
|
* Reads and parses the config.json file in a directory.
|
|
@@ -11394,10 +11670,10 @@ const CodeBlockUtils$2 = CodeBlockUtils$5;
|
|
|
11394
11670
|
* @returns {Promise<object|null>} A promise that resolves to the parsed config object
|
|
11395
11671
|
* or null if the file doesn't exist or is invalid.
|
|
11396
11672
|
*/
|
|
11397
|
-
async function readConfig$
|
|
11398
|
-
const configPath = path$
|
|
11673
|
+
async function readConfig$2(dirPath) {
|
|
11674
|
+
const configPath = path$5.join(dirPath, 'config.json');
|
|
11399
11675
|
try {
|
|
11400
|
-
const fileContent = await fs$
|
|
11676
|
+
const fileContent = await fs$7.readFile(configPath, 'utf8');
|
|
11401
11677
|
return JSON.parse(fileContent);
|
|
11402
11678
|
} catch (error) {
|
|
11403
11679
|
if (error.code !== 'ENOENT') {
|
|
@@ -11409,12 +11685,12 @@ async function readConfig$1(dirPath) {
|
|
|
11409
11685
|
}
|
|
11410
11686
|
|
|
11411
11687
|
/**
|
|
11412
|
-
* Checks if a directory name is valid
|
|
11688
|
+
* Checks if a directory name is valid
|
|
11413
11689
|
* Allowed: a-z, A-Z, 0-9, dash (-), underscore (_). Cannot start with underscore or contain dots.
|
|
11414
11690
|
* @param {string} name - The directory name to check.
|
|
11415
11691
|
* @returns {boolean} True if the name is valid, false otherwise.
|
|
11416
11692
|
*/
|
|
11417
|
-
function isValidDirName(name) {
|
|
11693
|
+
function isValidDirName$2(name) {
|
|
11418
11694
|
// Exclude names starting with underscore or containing dots
|
|
11419
11695
|
if (name.startsWith('_') || name.includes('.')) {
|
|
11420
11696
|
return false;
|
|
@@ -11427,51 +11703,53 @@ function isValidDirName(name) {
|
|
|
11427
11703
|
* Discovers and lists all available analyzers by traversing the directory structure.
|
|
11428
11704
|
* An analyzer is considered valid if a '1.md' file exists in the instructions directory.
|
|
11429
11705
|
*
|
|
11430
|
-
* @param {string}
|
|
11706
|
+
* @param {string} analyzersBasePath - The absolute path to the base directory containing the analyzers (e.g., 'analyzers/analyzer-1').
|
|
11431
11707
|
* @param {object} [options={}] - Optional configuration.
|
|
11432
|
-
* @
|
|
11433
|
-
* @returns {Promise<Array<{id: string, label: string, name: string, protected: boolean, description?: string}>>} A promise that resolves to an array of analyzer objects.
|
|
11708
|
+
* @returns {Promise<Array<{id: string, label: string, name: string, protected: boolean, description?: string, version?: string, tags?: Array<string>}>>} A promise that resolves to an array of analyzer objects.
|
|
11434
11709
|
*/
|
|
11435
|
-
async function getAnalyzers$
|
|
11436
|
-
const { includeDescription = false } = options;
|
|
11710
|
+
async function getAnalyzers$3(analyzersBasePath, options = {}) {
|
|
11437
11711
|
const analyzers = [];
|
|
11712
|
+
const demoAnalyzerPattern = /^demo-.+-\w{6}$/;
|
|
11438
11713
|
|
|
11439
11714
|
try {
|
|
11440
|
-
const analyzerEntries = await fs$
|
|
11715
|
+
const analyzerEntries = await fs$7.readdir(analyzersBasePath, { withFileTypes: true });
|
|
11441
11716
|
|
|
11442
11717
|
for (const analyzerEntry of analyzerEntries) {
|
|
11443
|
-
if (analyzerEntry.isDirectory() && isValidDirName(analyzerEntry.name)) {
|
|
11718
|
+
if (analyzerEntry.isDirectory() && isValidDirName$2(analyzerEntry.name)) {
|
|
11444
11719
|
const analyzerName = analyzerEntry.name;
|
|
11445
|
-
const analyzerPath = path$
|
|
11446
|
-
const analyzerConfig = await readConfig$
|
|
11720
|
+
const analyzerPath = path$5.join(analyzersBasePath, analyzerName);
|
|
11721
|
+
const analyzerConfig = await readConfig$2(analyzerPath);
|
|
11447
11722
|
const analyzerLabel = analyzerConfig?.label || analyzerName;
|
|
11448
11723
|
|
|
11449
|
-
const contentEntries = await fs$
|
|
11724
|
+
const contentEntries = await fs$7.readdir(analyzerPath, { withFileTypes: true });
|
|
11450
11725
|
|
|
11451
11726
|
for (const contentEntry of contentEntries) {
|
|
11452
|
-
if (contentEntry.isDirectory() && isValidDirName(contentEntry.name)) {
|
|
11727
|
+
if (contentEntry.isDirectory() && isValidDirName$2(contentEntry.name)) {
|
|
11453
11728
|
const contentType = contentEntry.name;
|
|
11454
|
-
const contentPath = path$
|
|
11455
|
-
const contentConfig = await readConfig$
|
|
11729
|
+
const contentPath = path$5.join(analyzerPath, contentType);
|
|
11730
|
+
const contentConfig = await readConfig$2(contentPath);
|
|
11456
11731
|
const contentLabel = contentConfig?.label || contentType;
|
|
11457
11732
|
|
|
11458
|
-
const instructionsEntries = await fs$
|
|
11733
|
+
const instructionsEntries = await fs$7.readdir(contentPath, { withFileTypes: true });
|
|
11459
11734
|
|
|
11460
11735
|
for (const instructionsEntry of instructionsEntries) {
|
|
11461
|
-
if (instructionsEntry.isDirectory() && isValidDirName(instructionsEntry.name)) {
|
|
11736
|
+
if (instructionsEntry.isDirectory() && isValidDirName$2(instructionsEntry.name)) {
|
|
11462
11737
|
const instructionsType = instructionsEntry.name;
|
|
11463
|
-
const instructionsPath = path$
|
|
11464
|
-
const instructionsConfig = await readConfig$
|
|
11738
|
+
const instructionsPath = path$5.join(contentPath, instructionsType);
|
|
11739
|
+
const instructionsConfig = await readConfig$2(instructionsPath);
|
|
11465
11740
|
const instructionsLabel = instructionsConfig?.label || instructionsType;
|
|
11466
11741
|
|
|
11742
|
+
// Construct the analyzer ID and label
|
|
11743
|
+
const analyzerId = `${analyzerName}::${contentType}::${instructionsType}`;
|
|
11744
|
+
|
|
11467
11745
|
// Check for the existence of 1.md to confirm a valid analyzer configuration
|
|
11468
|
-
const instructionsFilePath = path$
|
|
11746
|
+
const instructionsFilePath = path$5.join(instructionsPath, '1.md');
|
|
11469
11747
|
try {
|
|
11470
|
-
await fs$
|
|
11748
|
+
await fs$7.access(instructionsFilePath); // Check if file exists and is accessible
|
|
11471
11749
|
|
|
11472
11750
|
// If analyzerName starts with 'tutorial-', check its last modified time.
|
|
11473
|
-
if (analyzerName.startsWith('tutorial-')) {
|
|
11474
|
-
const stats = await fs$
|
|
11751
|
+
if (analyzerName.startsWith('tutorial-') || demoAnalyzerPattern.test(analyzerName)) {
|
|
11752
|
+
const stats = await fs$7.stat(instructionsFilePath);
|
|
11475
11753
|
const lastModified = stats.mtime.getTime(); // Get timestamp in milliseconds
|
|
11476
11754
|
const sixtyMinutesAgo = Date.now() - (60 * 60 * 1000); // Current time - 60 minutes in ms
|
|
11477
11755
|
|
|
@@ -11480,37 +11758,43 @@ async function getAnalyzers$2(analyzeMessagesBasePath, options = {}) {
|
|
|
11480
11758
|
continue;
|
|
11481
11759
|
}
|
|
11482
11760
|
}
|
|
11483
|
-
//
|
|
11484
|
-
const
|
|
11485
|
-
const analyzerFullLabel = `${analyzerLabel} (${contentLabel} - ${instructionsLabel})`;
|
|
11761
|
+
// TODO: Decide if we should show the contentLabel and instructionsLabel. For now we will ignore them.
|
|
11762
|
+
const analyzerFullLabel = `${analyzerLabel}`; // (${contentLabel} - ${instructionsLabel})`;
|
|
11486
11763
|
|
|
11764
|
+
// Extract description, version, and tags from the JSON block in 1.md
|
|
11487
11765
|
let description = null;
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
|
|
11492
|
-
|
|
11493
|
-
|
|
11494
|
-
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
|
|
11504
|
-
|
|
11766
|
+
let version = null;
|
|
11767
|
+
let tags = [];
|
|
11768
|
+
let label = null;
|
|
11769
|
+
let requires_reference_files = null;
|
|
11770
|
+
|
|
11771
|
+
try {
|
|
11772
|
+
const content = await getAnalyzerInstructionsContent$2(analyzersBasePath, analyzerId);
|
|
11773
|
+
const { blocks, warnings } = CodeBlockUtils$4.extractCodeBlocks(content, { silent: true });
|
|
11774
|
+
const jsonBlock = blocks.find(block => block.language === 'json');
|
|
11775
|
+
|
|
11776
|
+
if (jsonBlock && jsonBlock.content) {
|
|
11777
|
+
const preprocessedContent = preprocessJsonForValidation$4(jsonBlock.content);
|
|
11778
|
+
const json = JSON.parse(preprocessedContent);
|
|
11779
|
+
description = json.description || null;
|
|
11780
|
+
label = json.label || null;
|
|
11781
|
+
requires_reference_files = json.requires_reference_files || false;
|
|
11782
|
+
version = json.version || null;
|
|
11783
|
+
tags = Array.isArray(json.tags) ? json.tags : [];
|
|
11505
11784
|
}
|
|
11785
|
+
} catch (descError) {
|
|
11786
|
+
console.warn(`Warning: Could not load metadata for ${analyzerId}: ${descError.message}`);
|
|
11506
11787
|
}
|
|
11507
11788
|
|
|
11508
11789
|
analyzers.push({
|
|
11509
11790
|
id: analyzerId,
|
|
11510
|
-
label: analyzerFullLabel,
|
|
11511
11791
|
name: analyzerName,
|
|
11792
|
+
description,
|
|
11793
|
+
label: label || analyzerFullLabel,
|
|
11794
|
+
requires_reference_files,
|
|
11512
11795
|
protected: analyzerConfig?.protected || false,
|
|
11513
|
-
|
|
11796
|
+
version,
|
|
11797
|
+
tags
|
|
11514
11798
|
});
|
|
11515
11799
|
} catch (error) {
|
|
11516
11800
|
// If 1.md doesn't exist, this is not a complete analyzer configuration, skip.
|
|
@@ -11525,7 +11809,7 @@ async function getAnalyzers$2(analyzeMessagesBasePath, options = {}) {
|
|
|
11525
11809
|
}
|
|
11526
11810
|
}
|
|
11527
11811
|
} catch (error) {
|
|
11528
|
-
console.error(`Error traversing
|
|
11812
|
+
console.error(`Error traversing analyzers directory ${analyzersBasePath}: ${error.message}`);
|
|
11529
11813
|
// Depending on requirements, you might want to throw the error or return an empty array
|
|
11530
11814
|
throw error; // Re-throw to indicate failure
|
|
11531
11815
|
}
|
|
@@ -11534,8 +11818,10 @@ async function getAnalyzers$2(analyzeMessagesBasePath, options = {}) {
|
|
|
11534
11818
|
}
|
|
11535
11819
|
|
|
11536
11820
|
var discovery = {
|
|
11537
|
-
getAnalyzers: getAnalyzers$
|
|
11538
|
-
readConfig: readConfig$
|
|
11821
|
+
getAnalyzers: getAnalyzers$3,
|
|
11822
|
+
readConfig: readConfig$2,
|
|
11823
|
+
isValidDirName: isValidDirName$2,
|
|
11824
|
+
};
|
|
11539
11825
|
|
|
11540
11826
|
/**
|
|
11541
11827
|
* Component: Analyzer Saver Utility
|
|
@@ -11548,8 +11834,8 @@ var discovery = {
|
|
|
11548
11834
|
* Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash Thinking (v1.1.0)
|
|
11549
11835
|
*/
|
|
11550
11836
|
|
|
11551
|
-
const fs$
|
|
11552
|
-
const path$
|
|
11837
|
+
const fs$6 = require$$0.promises;
|
|
11838
|
+
const path$4 = require$$1;
|
|
11553
11839
|
|
|
11554
11840
|
/**
|
|
11555
11841
|
* Saves or updates an analyzer configuration.
|
|
@@ -11559,19 +11845,19 @@ const path$3 = require$$1;
|
|
|
11559
11845
|
* if necessary, saves the instructions to '1.md'. Optionally, it can
|
|
11560
11846
|
* ensure config.json files exist with labels derived from directory names.
|
|
11561
11847
|
*
|
|
11562
|
-
* @param {string}
|
|
11848
|
+
* @param {string} analyzersBasePath - The absolute path to the base directory containing the analyzers (e.g., 'analyzers/analyzer-1').
|
|
11563
11849
|
* @param {string} analyzerId - The unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
|
|
11564
11850
|
* @param {string} instructionsContent - The full content of the analyzer instructions message to be saved in '1.md'.
|
|
11565
11851
|
* @param {object} [options={}] - Optional configuration options.
|
|
11566
11852
|
* @param {boolean} [options.ensureConfigs=false] - If true, ensures config.json files exist in the analyzer, content, and instructions directories. Defaults to false.
|
|
11567
11853
|
* @returns {Promise<{success: boolean, message?: string}>} A promise that resolves with a result object.
|
|
11568
11854
|
*/
|
|
11569
|
-
async function saveConfiguration$
|
|
11855
|
+
async function saveConfiguration$2(analyzersBasePath, analyzerId, instructionsContent, options = {}) {
|
|
11570
11856
|
const { ensureConfigs = false } = options;
|
|
11571
11857
|
|
|
11572
11858
|
// 1. Validate inputs
|
|
11573
|
-
if (typeof
|
|
11574
|
-
return { success: false, message: '
|
|
11859
|
+
if (typeof analyzersBasePath !== 'string' || analyzersBasePath.trim() === '') {
|
|
11860
|
+
return { success: false, message: 'analyzersBasePath is required.' };
|
|
11575
11861
|
}
|
|
11576
11862
|
if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
|
|
11577
11863
|
return { success: false, message: 'analyzerId is required.' };
|
|
@@ -11604,18 +11890,18 @@ async function saveConfiguration$1(analyzeMessagesBasePath, analyzerId, instruct
|
|
|
11604
11890
|
}
|
|
11605
11891
|
|
|
11606
11892
|
// 3. Construct directory paths
|
|
11607
|
-
const analyzerDir = path$
|
|
11608
|
-
const contentDir = path$
|
|
11609
|
-
const instructionsDir = path$
|
|
11610
|
-
const instructionsFilePath = path$
|
|
11893
|
+
const analyzerDir = path$4.join(analyzersBasePath, analyzerName);
|
|
11894
|
+
const contentDir = path$4.join(analyzerDir, contentType);
|
|
11895
|
+
const instructionsDir = path$4.join(contentDir, instructionsType);
|
|
11896
|
+
const instructionsFilePath = path$4.join(instructionsDir, '1.md');
|
|
11611
11897
|
|
|
11612
11898
|
try {
|
|
11613
11899
|
// 4. Create directories recursively
|
|
11614
|
-
await fs$
|
|
11900
|
+
await fs$6.mkdir(instructionsDir, { recursive: true });
|
|
11615
11901
|
|
|
11616
11902
|
// 5. Save instructions content to 1.md
|
|
11617
11903
|
const finalContent = `; role: assistant\n\n\n${instructionsContent}`;
|
|
11618
|
-
await fs$
|
|
11904
|
+
await fs$6.writeFile(instructionsFilePath, finalContent, 'utf8');
|
|
11619
11905
|
|
|
11620
11906
|
// 6. Optionally create/Update config.json files
|
|
11621
11907
|
if (ensureConfigs) {
|
|
@@ -11641,11 +11927,11 @@ async function saveConfiguration$1(analyzeMessagesBasePath, analyzerId, instruct
|
|
|
11641
11927
|
* @param {string} label - The label to ensure is in the config.json.
|
|
11642
11928
|
*/
|
|
11643
11929
|
async function ensureConfigJson(dirPath, label) {
|
|
11644
|
-
const configPath = path$
|
|
11930
|
+
const configPath = path$4.join(dirPath, 'config.json');
|
|
11645
11931
|
let config = {};
|
|
11646
11932
|
|
|
11647
11933
|
try {
|
|
11648
|
-
const fileContent = await fs$
|
|
11934
|
+
const fileContent = await fs$6.readFile(configPath, 'utf8');
|
|
11649
11935
|
config = JSON.parse(fileContent);
|
|
11650
11936
|
} catch (error) {
|
|
11651
11937
|
// If file doesn't exist or parsing fails, start with an empty config
|
|
@@ -11662,28 +11948,103 @@ async function ensureConfigJson(dirPath, label) {
|
|
|
11662
11948
|
}
|
|
11663
11949
|
|
|
11664
11950
|
// Write the updated config back to the file
|
|
11665
|
-
await fs$
|
|
11951
|
+
await fs$6.writeFile(configPath, JSON.stringify(config, null, 4), 'utf8');
|
|
11666
11952
|
}
|
|
11667
11953
|
|
|
11668
11954
|
|
|
11669
11955
|
var saver = {
|
|
11670
|
-
saveConfiguration: saveConfiguration$
|
|
11956
|
+
saveConfiguration: saveConfiguration$2,
|
|
11671
11957
|
};
|
|
11672
11958
|
|
|
11673
|
-
|
|
11959
|
+
/**
|
|
11674
11960
|
* Component: AnalyzerUtils Schema Loader
|
|
11675
|
-
* Block-UUID:
|
|
11676
|
-
* Parent-UUID:
|
|
11677
|
-
* Version: 1.
|
|
11961
|
+
* Block-UUID: bf25c501-f9e1-4e5b-ad22-9ed24ba50787
|
|
11962
|
+
* Parent-UUID: 66208fdc-2c80-4264-8500-06d5f4db103a
|
|
11963
|
+
* Version: 1.4.1
|
|
11678
11964
|
* Description: Provides utility functions for retrieving and deducing JSON schemas for analyzers.
|
|
11679
11965
|
* Language: JavaScript
|
|
11680
|
-
* Created-at: 2025-
|
|
11681
|
-
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
11966
|
+
* Created-at: 2025-11-23T05:40:43.016Z
|
|
11967
|
+
* Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Pro (v1.1.0), Claude Haiku 4.5 (v1.2.0), Claude Haiku 4.5 (v1.3.0), Qwen 3 Coder 480B - Cerebras (v1.4.0), GLM-4.6 (v1.4.1)
|
|
11682
11968
|
*/
|
|
11683
11969
|
|
|
11684
|
-
|
|
11685
|
-
|
|
11686
|
-
|
|
11970
|
+
/**
|
|
11971
|
+
* Parses the 'Custom Metadata Definitions' block from the markdown content.
|
|
11972
|
+
* Handles both formats:
|
|
11973
|
+
* - With backticks: * `fieldName` (type): description
|
|
11974
|
+
* - Without backticks: * fieldName (type): description
|
|
11975
|
+
*
|
|
11976
|
+
* @param {string} markdownContent - The full content of the 1.md file.
|
|
11977
|
+
* @returns {Map<string, {type: string, description: string}>} A map from field name to its type and description.
|
|
11978
|
+
*/
|
|
11979
|
+
function parseMetadataDefinitions(markdownContent) {
|
|
11980
|
+
const definitions = new Map();
|
|
11981
|
+
|
|
11982
|
+
// Match the "### Custom Metadata Definitions" section until the next code block or section
|
|
11983
|
+
const sectionRegex = /### Custom Metadata Definitions\s*([\s\S]*?)(?=```|\n##|\n---)/;
|
|
11984
|
+
const match = markdownContent.match(sectionRegex);
|
|
11985
|
+
|
|
11986
|
+
if (!match || !match[1]) {
|
|
11987
|
+
return definitions;
|
|
11988
|
+
}
|
|
11989
|
+
|
|
11990
|
+
const definitionBlock = match[1];
|
|
11991
|
+
|
|
11992
|
+
// Regex to match both formats:
|
|
11993
|
+
// Format 1: * `fieldName` (type): description
|
|
11994
|
+
// Format 2: * fieldName (type): description
|
|
11995
|
+
// Capture groups:
|
|
11996
|
+
// Group 1: backtick-wrapped field name (if present)
|
|
11997
|
+
// Group 2: non-backtick field name (if present)
|
|
11998
|
+
// Group 3: field type
|
|
11999
|
+
// Group 4: description
|
|
12000
|
+
const lineRegex = /^\s*\*\s+(?:`([^`]+)`|([a-zA-Z0-9_-]+))\s+\(([^)]+)\):\s*(.+)/gm;
|
|
12001
|
+
|
|
12002
|
+
let lineMatch;
|
|
12003
|
+
while ((lineMatch = lineRegex.exec(definitionBlock)) !== null) {
|
|
12004
|
+
// Extract field name from either group 1 (backtick-wrapped) or group 2 (plain)
|
|
12005
|
+
const fieldName = (lineMatch[1] || lineMatch[2]).trim();
|
|
12006
|
+
const fieldType = lineMatch[3].trim();
|
|
12007
|
+
const description = lineMatch[4].trim();
|
|
12008
|
+
|
|
12009
|
+
if (fieldName && fieldType && description) {
|
|
12010
|
+
definitions.set(fieldName, { type: fieldType, description });
|
|
12011
|
+
}
|
|
12012
|
+
}
|
|
12013
|
+
|
|
12014
|
+
return definitions;
|
|
12015
|
+
}
|
|
12016
|
+
|
|
12017
|
+
const fs$5 = require$$0.promises;
|
|
12018
|
+
const path$3 = require$$1;
|
|
12019
|
+
const CodeBlockUtils$3 = CodeBlockUtils$7;
|
|
12020
|
+
const { preprocessJsonForValidation: preprocessJsonForValidation$3 } = jsonParser;
|
|
12021
|
+
|
|
12022
|
+
/**
|
|
12023
|
+
* Maps a simple type string (from the definitions block) to a JSON schema type object.
|
|
12024
|
+
* @param {string} simpleType - The type string (e.g., "number", "array of strings").
|
|
12025
|
+
* @returns {object} A JSON schema type definition.
|
|
12026
|
+
*/
|
|
12027
|
+
function mapSimpleTypeToSchema(simpleType) {
|
|
12028
|
+
const lowerType = simpleType.toLowerCase().trim();
|
|
12029
|
+
switch (lowerType) {
|
|
12030
|
+
case 'string':
|
|
12031
|
+
return { type: 'string' };
|
|
12032
|
+
case 'number':
|
|
12033
|
+
case 'integer':
|
|
12034
|
+
return { type: 'number' };
|
|
12035
|
+
case 'boolean':
|
|
12036
|
+
return { type: 'boolean' };
|
|
12037
|
+
case 'array of strings':
|
|
12038
|
+
return { type: 'array', items: { type: 'string' } };
|
|
12039
|
+
case 'date':
|
|
12040
|
+
return { type: 'string', format: 'date' };
|
|
12041
|
+
case 'datetime':
|
|
12042
|
+
case 'iso 8601 timestamp':
|
|
12043
|
+
return { type: 'string', format: 'date-time' };
|
|
12044
|
+
default:
|
|
12045
|
+
return { type: 'string' }; // Default to string for unknown types
|
|
12046
|
+
}
|
|
12047
|
+
}
|
|
11687
12048
|
|
|
11688
12049
|
/**
|
|
11689
12050
|
* Deduces the JSON schema type and format/items from a string value pattern.
|
|
@@ -11696,6 +12057,15 @@ const CodeBlockUtils$1 = CodeBlockUtils$5;
|
|
|
11696
12057
|
*/
|
|
11697
12058
|
function deduceSchemaType(value, fieldName) {
|
|
11698
12059
|
const defaultSchema = { type: 'string' }; // Default fallback
|
|
12060
|
+
|
|
12061
|
+
// Handle new placeholder format {{SYSTEM: ...}} and {{ANALYZER: ...}}
|
|
12062
|
+
// These are valid placeholders and should not generate warnings
|
|
12063
|
+
if (typeof value === 'string') {
|
|
12064
|
+
const trimmedValue = value.trim();
|
|
12065
|
+
if (trimmedValue.startsWith('{{SYSTEM:') || trimmedValue.startsWith('{{ANALYZER:')) {
|
|
12066
|
+
return defaultSchema; // Return default string schema for system/analyzer placeholders
|
|
12067
|
+
}
|
|
12068
|
+
}
|
|
11699
12069
|
|
|
11700
12070
|
if (typeof value !== 'string') {
|
|
11701
12071
|
const jsType = typeof value;
|
|
@@ -11707,35 +12077,35 @@ function deduceSchemaType(value, fieldName) {
|
|
|
11707
12077
|
}
|
|
11708
12078
|
|
|
11709
12079
|
const trimmedValue = value.trim();
|
|
11710
|
-
|
|
12080
|
+
|
|
11711
12081
|
if (/^\[string:.*\]$/.test(trimmedValue) || (/^\[[^:]+\]$/.test(trimmedValue) && !/^\[(number|datetime|date|<string>):.*\]$/.test(trimmedValue))) {
|
|
11712
12082
|
return { type: 'string' };
|
|
11713
12083
|
}
|
|
11714
|
-
|
|
12084
|
+
|
|
11715
12085
|
if (/^\[number:.*\]$/.test(trimmedValue)) {
|
|
11716
12086
|
return { type: 'number' };
|
|
11717
12087
|
}
|
|
11718
|
-
|
|
12088
|
+
|
|
11719
12089
|
if (/^\[boolean:.*\]$/.test(trimmedValue)) {
|
|
11720
12090
|
return { type: 'boolean' };
|
|
11721
12091
|
}
|
|
11722
|
-
|
|
12092
|
+
|
|
11723
12093
|
if (/^\[date-*time:.*\]$/.test(trimmedValue)) {
|
|
11724
12094
|
return { type: 'string', format: 'date-time' };
|
|
11725
12095
|
}
|
|
11726
|
-
|
|
12096
|
+
|
|
11727
12097
|
if (/^\[date:.*\]$/.test(trimmedValue)) {
|
|
11728
12098
|
return { type: 'string', format: 'date' };
|
|
11729
12099
|
}
|
|
11730
|
-
|
|
12100
|
+
|
|
11731
12101
|
if (/^\[<string>:.*\]$/.test(trimmedValue) || trimmedValue.toLowerCase().includes('array of strings')) {
|
|
11732
12102
|
return { type: 'array', items: { type: 'string' } };
|
|
11733
12103
|
}
|
|
11734
|
-
|
|
12104
|
+
|
|
11735
12105
|
if (trimmedValue.toLowerCase().includes("output 'true' or 'false'") || trimmedValue.toLowerCase().includes("determine if") && (trimmedValue.toLowerCase().includes("true") || trimmedValue.toLowerCase().includes("false"))) {
|
|
11736
12106
|
return { type: 'boolean' };
|
|
11737
12107
|
}
|
|
11738
|
-
|
|
12108
|
+
|
|
11739
12109
|
console.warn(`Warning: Unknown metadata value pattern for field "${fieldName}". Defaulting to type 'string'. Value: "${value}"`);
|
|
11740
12110
|
return defaultSchema;
|
|
11741
12111
|
}
|
|
@@ -11746,14 +12116,14 @@ function deduceSchemaType(value, fieldName) {
|
|
|
11746
12116
|
* Reads the corresponding '1.md' file, extracts the JSON block,
|
|
11747
12117
|
* and deduces schema types from the string values.
|
|
11748
12118
|
*
|
|
11749
|
-
* @param {string}
|
|
12119
|
+
* @param {string} analyzersBasePath - The absolute or relative path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
|
|
11750
12120
|
* @param {string} analyzerId - The unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
|
|
11751
12121
|
* @returns {Promise<object|null>} A promise that resolves with the JSON schema object or null if the analyzer ID is invalid or the schema cannot be retrieved/parsed.
|
|
11752
12122
|
* @throws {Error} If the 1.md file is found but does not contain exactly one JSON code block.
|
|
11753
12123
|
*/
|
|
11754
|
-
async function getAnalyzerSchema$2(
|
|
11755
|
-
if (typeof
|
|
11756
|
-
console.error('Error:
|
|
12124
|
+
async function getAnalyzerSchema$2(analyzersBasePath, analyzerId) {
|
|
12125
|
+
if (typeof analyzersBasePath !== 'string' || analyzersBasePath.trim() === '') {
|
|
12126
|
+
console.error('Error: analyzersBasePath is required.');
|
|
11757
12127
|
return null;
|
|
11758
12128
|
}
|
|
11759
12129
|
if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
|
|
@@ -11768,11 +12138,14 @@ async function getAnalyzerSchema$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11768
12138
|
}
|
|
11769
12139
|
const [analyzerName, contentType, instructionsType] = parts;
|
|
11770
12140
|
|
|
11771
|
-
const instructionsFilePath = path$
|
|
12141
|
+
const instructionsFilePath = path$3.join(analyzersBasePath, analyzerName, contentType, instructionsType, '1.md');
|
|
11772
12142
|
|
|
11773
12143
|
try {
|
|
11774
|
-
const fileContent = await fs$
|
|
11775
|
-
|
|
12144
|
+
const fileContent = await fs$5.readFile(instructionsFilePath, 'utf8');
|
|
12145
|
+
// New: Parse the structured definitions block first
|
|
12146
|
+
const definedFields = parseMetadataDefinitions(fileContent);
|
|
12147
|
+
|
|
12148
|
+
const { blocks } = CodeBlockUtils$3.extractCodeBlocks(fileContent, { silent: true });
|
|
11776
12149
|
const jsonBlocks = blocks.filter(block => block.type === 'code' && block.language === 'json');
|
|
11777
12150
|
|
|
11778
12151
|
if (jsonBlocks.length !== 1) {
|
|
@@ -11780,19 +12153,24 @@ async function getAnalyzerSchema$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11780
12153
|
}
|
|
11781
12154
|
|
|
11782
12155
|
const jsonBlockContent = jsonBlocks[0].content;
|
|
12156
|
+
const preprocessedContent = preprocessJsonForValidation$3(jsonBlockContent);
|
|
11783
12157
|
let rawJson = null;
|
|
11784
12158
|
try {
|
|
11785
|
-
rawJson = JSON.parse(
|
|
12159
|
+
rawJson = JSON.parse(preprocessedContent);
|
|
11786
12160
|
} catch (parseError) {
|
|
11787
12161
|
console.error(`Error parsing JSON content from ${instructionsFilePath}: ${parseError.message}`);
|
|
11788
12162
|
return null;
|
|
11789
12163
|
}
|
|
11790
12164
|
|
|
12165
|
+
const startOfInstructions = fileContent.indexOf('# Analyze ');
|
|
12166
|
+
|
|
11791
12167
|
const schema = {
|
|
11792
12168
|
type: 'object',
|
|
11793
12169
|
description: rawJson.description,
|
|
12170
|
+
version: rawJson.version,
|
|
11794
12171
|
properties: {},
|
|
11795
|
-
required: []
|
|
12172
|
+
required: [],
|
|
12173
|
+
instructions: fileContent.slice(startOfInstructions),
|
|
11796
12174
|
};
|
|
11797
12175
|
|
|
11798
12176
|
const metadataProperties = rawJson?.extracted_metadata;
|
|
@@ -11800,9 +12178,20 @@ async function getAnalyzerSchema$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11800
12178
|
if (metadataProperties && typeof metadataProperties === 'object') {
|
|
11801
12179
|
for (const fieldName in metadataProperties) {
|
|
11802
12180
|
if (Object.hasOwnProperty.call(metadataProperties, fieldName)) {
|
|
11803
|
-
|
|
11804
|
-
|
|
11805
|
-
|
|
12181
|
+
let fieldSchema;
|
|
12182
|
+
let description;
|
|
12183
|
+
|
|
12184
|
+
if (definedFields.has(fieldName)) {
|
|
12185
|
+
// Priority 1: Use the explicit definition
|
|
12186
|
+
const definition = definedFields.get(fieldName);
|
|
12187
|
+
fieldSchema = mapSimpleTypeToSchema(definition.type);
|
|
12188
|
+
description = definition.description;
|
|
12189
|
+
} else {
|
|
12190
|
+
// Priority 2: Fallback for system fields or backward compatibility
|
|
12191
|
+
const rawValue = metadataProperties[fieldName];
|
|
12192
|
+
fieldSchema = deduceSchemaType(rawValue, fieldName);
|
|
12193
|
+
description = rawValue.match(/^\[\w+: ([^\]]+)\]/)?.[1] || '';
|
|
12194
|
+
}
|
|
11806
12195
|
|
|
11807
12196
|
schema.properties[fieldName] = {
|
|
11808
12197
|
...fieldSchema,
|
|
@@ -11816,7 +12205,6 @@ async function getAnalyzerSchema$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11816
12205
|
}
|
|
11817
12206
|
|
|
11818
12207
|
return schema;
|
|
11819
|
-
|
|
11820
12208
|
} catch (error) {
|
|
11821
12209
|
if (error.code === 'ENOENT') {
|
|
11822
12210
|
console.warn(`Analyzer instructions file not found: ${instructionsFilePath}`);
|
|
@@ -11833,7 +12221,7 @@ var schemaLoader = {
|
|
|
11833
12221
|
|
|
11834
12222
|
/*
|
|
11835
12223
|
* Component: AnalyzerUtils Management
|
|
11836
|
-
* Block-UUID:
|
|
12224
|
+
* Block-UUID: 6241f381-512b-48a7-b70e-6b45683831fe
|
|
11837
12225
|
* Parent-UUID: N/A
|
|
11838
12226
|
* Version: 1.0.0
|
|
11839
12227
|
* Description: Provides utility functions for managing (deleting) analyzer configurations.
|
|
@@ -11842,9 +12230,9 @@ var schemaLoader = {
|
|
|
11842
12230
|
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
11843
12231
|
*/
|
|
11844
12232
|
|
|
11845
|
-
const fs$
|
|
11846
|
-
const path$
|
|
11847
|
-
const { readConfig } = discovery; // Import helper from discovery
|
|
12233
|
+
const fs$4 = require$$0.promises;
|
|
12234
|
+
const path$2 = require$$1;
|
|
12235
|
+
const { readConfig: readConfig$1 } = discovery; // Import helper from discovery
|
|
11848
12236
|
|
|
11849
12237
|
/**
|
|
11850
12238
|
* Checks if a directory is empty or only contains a config.json.
|
|
@@ -11853,7 +12241,7 @@ const { readConfig } = discovery; // Import helper from discovery
|
|
|
11853
12241
|
*/
|
|
11854
12242
|
async function isDirectoryEmpty(dirPath) {
|
|
11855
12243
|
try {
|
|
11856
|
-
const files = await fs$
|
|
12244
|
+
const files = await fs$4.readdir(dirPath);
|
|
11857
12245
|
return files.length === 0 || (files.length === 1 && files[0] === 'config.json');
|
|
11858
12246
|
} catch (error) {
|
|
11859
12247
|
if (error.code === 'ENOENT') {
|
|
@@ -11866,13 +12254,13 @@ async function isDirectoryEmpty(dirPath) {
|
|
|
11866
12254
|
/**
|
|
11867
12255
|
* Deletes a specific analyzer configuration and intelligently cleans up empty directories.
|
|
11868
12256
|
*
|
|
11869
|
-
* @param {string}
|
|
12257
|
+
* @param {string} analyzersBasePath - The absolute path to the base directory containing the analyzers (e.g., 'analyzers/analyzer-1').
|
|
11870
12258
|
* @param {string} analyzerId - The unique ID of the analyzer to delete (format: 'analyzer_name::content_type::instructions_type').
|
|
11871
12259
|
* @returns {Promise<{success: boolean, message: string}>} A promise that resolves with a result object indicating success or failure.
|
|
11872
12260
|
*/
|
|
11873
|
-
async function deleteAnalyzer$2(
|
|
11874
|
-
if (typeof
|
|
11875
|
-
return { success: false, message: '
|
|
12261
|
+
async function deleteAnalyzer$2(analyzersBasePath, analyzerId) {
|
|
12262
|
+
if (typeof analyzersBasePath !== 'string' || analyzersBasePath.trim() === '') {
|
|
12263
|
+
return { success: false, message: 'analyzersBasePath is required.' };
|
|
11876
12264
|
}
|
|
11877
12265
|
if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
|
|
11878
12266
|
return { success: false, message: 'analyzerId is required.' };
|
|
@@ -11884,31 +12272,31 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11884
12272
|
}
|
|
11885
12273
|
const [analyzerName, contentType, instructionsType] = parts;
|
|
11886
12274
|
|
|
11887
|
-
const analyzerDir = path$
|
|
11888
|
-
const contentDir = path$
|
|
11889
|
-
const instructionsDir = path$
|
|
11890
|
-
const instructionsFilePath = path$
|
|
12275
|
+
const analyzerDir = path$2.join(analyzersBasePath, analyzerName);
|
|
12276
|
+
const contentDir = path$2.join(analyzerDir, contentType);
|
|
12277
|
+
const instructionsDir = path$2.join(contentDir, instructionsType);
|
|
12278
|
+
const instructionsFilePath = path$2.join(instructionsDir, '1.md');
|
|
11891
12279
|
|
|
11892
12280
|
try {
|
|
11893
12281
|
// 1. Check for protection at all levels
|
|
11894
|
-
const analyzerConfig = await readConfig(analyzerDir);
|
|
12282
|
+
const analyzerConfig = await readConfig$1(analyzerDir);
|
|
11895
12283
|
if (analyzerConfig?.protected) {
|
|
11896
12284
|
return { success: false, message: `Analyzer '${analyzerName}' is protected and cannot be deleted.` };
|
|
11897
12285
|
}
|
|
11898
12286
|
|
|
11899
|
-
const contentConfig = await readConfig(contentDir);
|
|
12287
|
+
const contentConfig = await readConfig$1(contentDir);
|
|
11900
12288
|
if (contentConfig?.protected) {
|
|
11901
12289
|
return { success: false, message: `Content type '${contentType}' for analyzer '${analyzerName}' is protected and cannot be deleted.` };
|
|
11902
12290
|
}
|
|
11903
12291
|
|
|
11904
|
-
const instructionsConfig = await readConfig(instructionsDir);
|
|
12292
|
+
const instructionsConfig = await readConfig$1(instructionsDir);
|
|
11905
12293
|
if (instructionsConfig?.protected) {
|
|
11906
12294
|
return { success: false, message: `Instructions type '${instructionsType}' for content type '${contentType}' is protected and cannot be deleted.` };
|
|
11907
12295
|
}
|
|
11908
12296
|
|
|
11909
12297
|
// 2. Delete the 1.md file
|
|
11910
12298
|
try {
|
|
11911
|
-
await fs$
|
|
12299
|
+
await fs$4.unlink(instructionsFilePath);
|
|
11912
12300
|
} catch (error) {
|
|
11913
12301
|
if (error.code === 'ENOENT') {
|
|
11914
12302
|
return { success: false, message: `Analyzer instructions file not found: ${instructionsFilePath}. It may have already been deleted.` };
|
|
@@ -11922,7 +12310,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11922
12310
|
// Check and delete instructions directory
|
|
11923
12311
|
if (await isDirectoryEmpty(instructionsDir)) {
|
|
11924
12312
|
try {
|
|
11925
|
-
await fs$
|
|
12313
|
+
await fs$4.rmdir(instructionsDir);
|
|
11926
12314
|
deletedDirs.push(instructionsDir);
|
|
11927
12315
|
} catch (error) {
|
|
11928
12316
|
console.warn(`Warning: Could not remove empty instructions directory ${instructionsDir}: ${error.message}`);
|
|
@@ -11932,7 +12320,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11932
12320
|
// Check and delete content directory
|
|
11933
12321
|
if (await isDirectoryEmpty(contentDir)) {
|
|
11934
12322
|
try {
|
|
11935
|
-
await fs$
|
|
12323
|
+
await fs$4.rmdir(contentDir);
|
|
11936
12324
|
deletedDirs.push(contentDir);
|
|
11937
12325
|
} catch (error) {
|
|
11938
12326
|
console.warn(`Warning: Could not remove empty content directory ${contentDir}: ${error.message}`);
|
|
@@ -11942,7 +12330,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11942
12330
|
// Check and delete analyzer directory
|
|
11943
12331
|
if (await isDirectoryEmpty(analyzerDir)) {
|
|
11944
12332
|
try {
|
|
11945
|
-
await fs$
|
|
12333
|
+
await fs$4.rmdir(analyzerDir);
|
|
11946
12334
|
deletedDirs.push(analyzerDir);
|
|
11947
12335
|
} catch (error) {
|
|
11948
12336
|
console.warn(`Warning: Could not remove empty analyzer directory ${analyzerDir}: ${error.message}`);
|
|
@@ -11958,7 +12346,9 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11958
12346
|
}
|
|
11959
12347
|
|
|
11960
12348
|
var management = {
|
|
11961
|
-
deleteAnalyzer: deleteAnalyzer$2
|
|
12349
|
+
deleteAnalyzer: deleteAnalyzer$2,
|
|
12350
|
+
isDirectoryEmpty,
|
|
12351
|
+
};
|
|
11962
12352
|
|
|
11963
12353
|
/*
|
|
11964
12354
|
* Component: AnalyzerUtils Default Prompt Loader
|
|
@@ -11971,25 +12361,25 @@ var management = {
|
|
|
11971
12361
|
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
11972
12362
|
*/
|
|
11973
12363
|
|
|
11974
|
-
const fs$
|
|
11975
|
-
const path = require$$1;
|
|
12364
|
+
const fs$3 = require$$0.promises;
|
|
12365
|
+
const path$1 = require$$1;
|
|
11976
12366
|
|
|
11977
12367
|
/**
|
|
11978
12368
|
* Retrieves the raw Markdown content of the shared system message ('_shared/system/1.md').
|
|
11979
12369
|
*
|
|
11980
|
-
* @param {string}
|
|
12370
|
+
* @param {string} analyzersBasePath - The absolute path to the base directory containing the analyzers (e.g., 'analyzers/analyzer-1').
|
|
11981
12371
|
* @returns {Promise<string|null>} A promise that resolves with the full Markdown content, or null if not found/invalid.
|
|
11982
12372
|
*/
|
|
11983
|
-
async function getSystemMessageContent$2(
|
|
11984
|
-
if (typeof
|
|
11985
|
-
console.error('Error:
|
|
12373
|
+
async function getSystemMessageContent$2(analyzersBasePath) {
|
|
12374
|
+
if (typeof analyzersBasePath !== 'string' || analyzersBasePath.trim() === '') {
|
|
12375
|
+
console.error('Error: analyzersBasePath is required for getSystemMessageContent.');
|
|
11986
12376
|
return null;
|
|
11987
12377
|
}
|
|
11988
12378
|
|
|
11989
|
-
const systemMessageFilePath = path.join(
|
|
12379
|
+
const systemMessageFilePath = path$1.join(analyzersBasePath, '_shared', 'system', '1.md');
|
|
11990
12380
|
|
|
11991
12381
|
try {
|
|
11992
|
-
const fileContent = await fs$
|
|
12382
|
+
const fileContent = await fs$3.readFile(systemMessageFilePath, 'utf8');
|
|
11993
12383
|
const parts = fileContent.split('\n\n\n');
|
|
11994
12384
|
parts.shift();
|
|
11995
12385
|
return parts.join('\n\n\n');
|
|
@@ -12007,19 +12397,19 @@ async function getSystemMessageContent$2(analyzeMessagesBasePath) {
|
|
|
12007
12397
|
/**
|
|
12008
12398
|
* Retrieves the raw Markdown content of the shared start message ('_shared/start/1.md').
|
|
12009
12399
|
*
|
|
12010
|
-
* @param {string}
|
|
12400
|
+
* @param {string} analyzersBasePath - The absolute path to the base directory containing the analyzers (e.g., 'analyzers/analyzer-1').
|
|
12011
12401
|
* @returns {Promise<string|null>} A promise that resolves with the full Markdown content, or null if not found/invalid.
|
|
12012
12402
|
*/
|
|
12013
|
-
async function getStartMessageContent$2(
|
|
12014
|
-
if (typeof
|
|
12015
|
-
console.error('Error:
|
|
12403
|
+
async function getStartMessageContent$2(analyzersBasePath) {
|
|
12404
|
+
if (typeof analyzersBasePath !== 'string' || analyzersBasePath.trim() === '') {
|
|
12405
|
+
console.error('Error: analyzersBasePath is required for getStartMessageContent.');
|
|
12016
12406
|
return null;
|
|
12017
12407
|
}
|
|
12018
12408
|
|
|
12019
|
-
const startMessageFilePath = path.join(
|
|
12409
|
+
const startMessageFilePath = path$1.join(analyzersBasePath, '_shared', 'start', '1.md');
|
|
12020
12410
|
|
|
12021
12411
|
try {
|
|
12022
|
-
const fileContent = await fs$
|
|
12412
|
+
const fileContent = await fs$3.readFile(startMessageFilePath, 'utf8');
|
|
12023
12413
|
const parts = fileContent.split('\n\n\n');
|
|
12024
12414
|
parts.shift();
|
|
12025
12415
|
return parts.join('\n\n\n');
|
|
@@ -12040,59 +12430,400 @@ var defaultPromptLoader = {
|
|
|
12040
12430
|
};
|
|
12041
12431
|
|
|
12042
12432
|
/*
|
|
12043
|
-
* Component: AnalyzerUtils
|
|
12044
|
-
* Block-UUID:
|
|
12045
|
-
* Parent-UUID: N/A
|
|
12046
|
-
* Version: 1.2.0
|
|
12047
|
-
* Description: Aggregates and exports all utility functions from the AnalyzerUtils module.
|
|
12048
|
-
* Language: JavaScript
|
|
12049
|
-
* Created-at: 2025-08-28T15:56:40.319Z
|
|
12050
|
-
* Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0), Gemini 2.5 Flash (v1.2.0)
|
|
12051
|
-
*/
|
|
12052
|
-
|
|
12053
|
-
const { buildChatIdToPathMap: buildChatIdToPathMap$1 } = contextMapper;
|
|
12054
|
-
const { processLLMAnalysisResponse: processLLMAnalysisResponse$1 } = responseProcessor;
|
|
12055
|
-
const { validateLLMAnalysisData: validateLLMAnalysisData$1 } = dataValidator;
|
|
12056
|
-
const { getAnalyzers: getAnalyzers$1 } = discovery;
|
|
12057
|
-
const { saveConfiguration } = saver;
|
|
12058
|
-
const { getAnalyzerSchema: getAnalyzerSchema$1 } = schemaLoader;
|
|
12059
|
-
const { deleteAnalyzer: deleteAnalyzer$1 } = management;
|
|
12060
|
-
const { getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1 } = instructionLoader;
|
|
12061
|
-
const { getSystemMessageContent: getSystemMessageContent$1, getStartMessageContent: getStartMessageContent$1 } = defaultPromptLoader; // NEW: Import default prompt loaders
|
|
12062
|
-
|
|
12063
|
-
var AnalyzerUtils$1 = {
|
|
12064
|
-
buildChatIdToPathMap: buildChatIdToPathMap$1,
|
|
12065
|
-
processLLMAnalysisResponse: processLLMAnalysisResponse$1,
|
|
12066
|
-
validateLLMAnalysisData: validateLLMAnalysisData$1,
|
|
12067
|
-
getAnalyzers: getAnalyzers$1,
|
|
12068
|
-
getAnalyzerSchema: getAnalyzerSchema$1,
|
|
12069
|
-
deleteAnalyzer: deleteAnalyzer$1,
|
|
12070
|
-
getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1,
|
|
12071
|
-
saveConfiguration,
|
|
12072
|
-
getSystemMessageContent: getSystemMessageContent$1,
|
|
12073
|
-
getStartMessageContent: getStartMessageContent$1
|
|
12074
|
-
};
|
|
12075
|
-
|
|
12076
|
-
/**
|
|
12077
|
-
* Component: LLMUtils
|
|
12078
|
-
* Block-UUID: a3106054-42f1-474f-96f3-182d66eb19a0
|
|
12433
|
+
* Component: AnalyzerUtils Updater
|
|
12434
|
+
* Block-UUID: 8a7b6c5d-4e3f-2a1b-9c8d-7e6f5a4b3c2d
|
|
12079
12435
|
* Parent-UUID: N/A
|
|
12080
12436
|
* Version: 1.0.0
|
|
12081
|
-
* Description: Provides utility functions
|
|
12437
|
+
* Description: Provides utility functions for updating analyzer configurations, including renaming and metadata updates.
|
|
12082
12438
|
* Language: JavaScript
|
|
12083
|
-
* Created-at: 2025-
|
|
12084
|
-
* Authors:
|
|
12439
|
+
* Created-at: 2025-12-25T19:55:00.000Z
|
|
12440
|
+
* Authors: GLM-4.6 (v1.0.0)
|
|
12085
12441
|
*/
|
|
12086
12442
|
|
|
12443
|
+
const fs$2 = require$$0.promises;
|
|
12444
|
+
const path = require$$1;
|
|
12445
|
+
const CodeBlockUtils$2 = CodeBlockUtils$7;
|
|
12446
|
+
const { preprocessJsonForValidation: preprocessJsonForValidation$2 } = jsonParser;
|
|
12447
|
+
const { isValidDirName: isValidDirName$1 } = discovery;
|
|
12448
|
+
const { readConfig } = discovery;
|
|
12449
|
+
|
|
12087
12450
|
/**
|
|
12088
|
-
*
|
|
12089
|
-
* This is a basic estimation using the common heuristic of ~4 characters per token.
|
|
12090
|
-
* Actual token count can vary significantly based on the specific tokenizer used by an LLM.
|
|
12451
|
+
* Updates an analyzer configuration, including renaming the analyzer if needed.
|
|
12091
12452
|
*
|
|
12092
|
-
* @param {string}
|
|
12093
|
-
* @
|
|
12453
|
+
* @param {string} analyzersBasePath - The absolute path to the base directory containing the analyzers.
|
|
12454
|
+
* @param {string} analyzerId - The current unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
|
|
12455
|
+
* @param {object} updates - The updates to apply to the analyzer.
|
|
12456
|
+
* @param {string} [updates.name] - The new analyzer name (for renaming the directory).
|
|
12457
|
+
* @param {string} [updates.label] - The new label for the analyzer.
|
|
12458
|
+
* @param {string} [updates.description] - The new description for the analyzer.
|
|
12459
|
+
* @param {string} [updates.version] - The new version for the analyzer.
|
|
12460
|
+
* @param {Array<string>} [updates.tags] - The new tags for the analyzer.
|
|
12461
|
+
* @returns {Promise<{success: boolean, message: string, newAnalyzerId?: string}>} A promise that resolves with a result object.
|
|
12094
12462
|
*/
|
|
12095
|
-
function
|
|
12463
|
+
async function updateAnalyzer$1(analyzersBasePath, analyzerId, updates) {
|
|
12464
|
+
// 1. Validate inputs
|
|
12465
|
+
if (typeof analyzersBasePath !== 'string' || analyzersBasePath.trim() === '') {
|
|
12466
|
+
return { success: false, message: 'analyzersBasePath is required.' };
|
|
12467
|
+
}
|
|
12468
|
+
if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
|
|
12469
|
+
return { success: false, message: 'analyzerId is required.' };
|
|
12470
|
+
}
|
|
12471
|
+
if (!updates || typeof updates !== 'object') {
|
|
12472
|
+
return { success: false, message: 'updates object is required.' };
|
|
12473
|
+
}
|
|
12474
|
+
|
|
12475
|
+
// 2.0 Parse current analyzerId
|
|
12476
|
+
const parts = analyzerId.split('::');
|
|
12477
|
+
if (parts.length !== 3) {
|
|
12478
|
+
return { success: false, message: `Invalid analyzerId format. Expected 'analyzer_name::content_type::instructions_type', but got '${analyzerId}'.` };
|
|
12479
|
+
}
|
|
12480
|
+
const [analyzerName, contentType, instructionsType] = parts;
|
|
12481
|
+
|
|
12482
|
+
// 2.1 Unset name if it has been provided but is the same as the analyzerName
|
|
12483
|
+
if (updates.name && analyzerName === updates.name) {
|
|
12484
|
+
delete updates.name;
|
|
12485
|
+
}
|
|
12486
|
+
|
|
12487
|
+
// 3. Validate new name if provided
|
|
12488
|
+
if (updates.name && !isValidDirName$1(updates.name)) {
|
|
12489
|
+
return { success: false, message: `Invalid analyzer name '${updates.name}'. Names must be alphanumeric, dash, or underscore, cannot start with underscore, and cannot contain dots.` };
|
|
12490
|
+
}
|
|
12491
|
+
|
|
12492
|
+
// 4. Check if analyzer is protected
|
|
12493
|
+
const analyzerDir = path.join(analyzersBasePath, analyzerName);
|
|
12494
|
+
const analyzerConfig = await readConfig(analyzerDir);
|
|
12495
|
+
if (analyzerConfig?.protected) {
|
|
12496
|
+
return { success: false, message: `Analyzer '${analyzerName}' is protected and cannot be updated.` };
|
|
12497
|
+
}
|
|
12498
|
+
|
|
12499
|
+
// 5. Get current instructions content
|
|
12500
|
+
const instructionsFilePath = path.join(analyzerDir, contentType, instructionsType, '1.md');
|
|
12501
|
+
let instructionsContent;
|
|
12502
|
+
try {
|
|
12503
|
+
instructionsContent = await fs$2.readFile(instructionsFilePath, 'utf8');
|
|
12504
|
+
} catch (error) {
|
|
12505
|
+
return { success: false, message: `Failed to read analyzer instructions: ${error.message}` };
|
|
12506
|
+
}
|
|
12507
|
+
|
|
12508
|
+
// 6. Extract and update JSON block
|
|
12509
|
+
const { blocks } = CodeBlockUtils$2.extractCodeBlocks(instructionsContent, { silent: true });
|
|
12510
|
+
const jsonBlock = blocks.find(block => block.language === 'json');
|
|
12511
|
+
|
|
12512
|
+
if (!jsonBlock) {
|
|
12513
|
+
return { success: false, message: 'No JSON block found in analyzer instructions.' };
|
|
12514
|
+
}
|
|
12515
|
+
|
|
12516
|
+
let jsonData;
|
|
12517
|
+
try {
|
|
12518
|
+
const preprocessedContent = preprocessJsonForValidation$2(jsonBlock.content);
|
|
12519
|
+
jsonData = JSON.parse(preprocessedContent);
|
|
12520
|
+
} catch (error) {
|
|
12521
|
+
return { success: false, message: `Failed to parse JSON block: ${error.message}` };
|
|
12522
|
+
}
|
|
12523
|
+
|
|
12524
|
+
// 7. Update JSON data with provided values
|
|
12525
|
+
if (updates.label !== undefined) jsonData.label = updates.label;
|
|
12526
|
+
if (updates.description !== undefined) jsonData.description = updates.description;
|
|
12527
|
+
if (updates.version !== undefined) jsonData.version = updates.version;
|
|
12528
|
+
if (updates.tags !== undefined) jsonData.tags = updates.tags;
|
|
12529
|
+
|
|
12530
|
+
// 8. Rebuild the instructions content with updated JSON
|
|
12531
|
+
const updatedJsonContent = JSON.stringify(jsonData, null, 2);
|
|
12532
|
+
const updatedInstructionsContent = instructionsContent.replace(
|
|
12533
|
+
jsonBlock.content,
|
|
12534
|
+
updatedJsonContent
|
|
12535
|
+
);
|
|
12536
|
+
|
|
12537
|
+
// 9. Handle directory renaming if needed
|
|
12538
|
+
let newAnalyzerId = analyzerId;
|
|
12539
|
+
if (updates.name && updates.name !== analyzerName) {
|
|
12540
|
+
// Create new directory structure
|
|
12541
|
+
const newAnalyzerDir = path.join(analyzersBasePath, updates.name);
|
|
12542
|
+
const newContentDir = path.join(newAnalyzerDir, contentType);
|
|
12543
|
+
const newInstructionsDir = path.join(newContentDir, instructionsType);
|
|
12544
|
+
const newInstructionsFilePath = path.join(newInstructionsDir, '1.md');
|
|
12545
|
+
|
|
12546
|
+
try {
|
|
12547
|
+
// Create new directories
|
|
12548
|
+
await fs$2.mkdir(newInstructionsDir, { recursive: true });
|
|
12549
|
+
|
|
12550
|
+
// Copy config.json if it exists
|
|
12551
|
+
const configPath = path.join(analyzerDir, 'config.json');
|
|
12552
|
+
const newConfigPath = path.join(newAnalyzerDir, 'config.json');
|
|
12553
|
+
try {
|
|
12554
|
+
const configContent = await fs$2.readFile(configPath, 'utf8');
|
|
12555
|
+
await fs$2.writeFile(newConfigPath, configContent, 'utf8');
|
|
12556
|
+
} catch (error) {
|
|
12557
|
+
// Config file might not exist, that's okay
|
|
12558
|
+
}
|
|
12559
|
+
|
|
12560
|
+
// Copy content config.json if it exists
|
|
12561
|
+
const contentConfigPath = path.join(analyzerDir, contentType, 'config.json');
|
|
12562
|
+
const newContentConfigPath = path.join(newContentDir, 'config.json');
|
|
12563
|
+
try {
|
|
12564
|
+
const contentConfigContent = await fs$2.readFile(contentConfigPath, 'utf8');
|
|
12565
|
+
await fs$2.writeFile(newContentConfigPath, contentConfigContent, 'utf8');
|
|
12566
|
+
} catch (error) {
|
|
12567
|
+
// Config file might not exist, that's okay
|
|
12568
|
+
}
|
|
12569
|
+
|
|
12570
|
+
// Copy instructions config.json if it exists
|
|
12571
|
+
const instructionsConfigPath = path.join(analyzerDir, contentType, instructionsType, 'config.json');
|
|
12572
|
+
const newInstructionsConfigPath = path.join(newInstructionsDir, 'config.json');
|
|
12573
|
+
try {
|
|
12574
|
+
const instructionsConfigContent = await fs$2.readFile(instructionsConfigPath, 'utf8');
|
|
12575
|
+
await fs$2.writeFile(newInstructionsConfigPath, instructionsConfigContent, 'utf8');
|
|
12576
|
+
} catch (error) {
|
|
12577
|
+
// Config file might not exist, that's okay
|
|
12578
|
+
}
|
|
12579
|
+
|
|
12580
|
+
// Write updated instructions to new location
|
|
12581
|
+
const finalContent = `; role: assistant\n\n\n${updatedInstructionsContent}`;
|
|
12582
|
+
await fs$2.writeFile(newInstructionsFilePath, finalContent, 'utf8');
|
|
12583
|
+
|
|
12584
|
+
// Update the analyzer ID
|
|
12585
|
+
newAnalyzerId = `${updates.name}::${contentType}::${instructionsType}`;
|
|
12586
|
+
|
|
12587
|
+
// Delete old analyzer directory (will be done after successful save)
|
|
12588
|
+
} catch (error) {
|
|
12589
|
+
return { success: false, message: `Failed to create new analyzer directory: ${error.message}` };
|
|
12590
|
+
}
|
|
12591
|
+
} else {
|
|
12592
|
+
// Just update the existing file
|
|
12593
|
+
const finalContent = `; role: assistant\n\n\n${updatedInstructionsContent}`;
|
|
12594
|
+
await fs$2.writeFile(instructionsFilePath, finalContent, 'utf8');
|
|
12595
|
+
}
|
|
12596
|
+
|
|
12597
|
+
// 10. Clean up old directory if renamed
|
|
12598
|
+
if (updates.name && updates.name !== analyzerName) {
|
|
12599
|
+
try {
|
|
12600
|
+
// Use the deleteAnalyzer function to clean up the old directory
|
|
12601
|
+
const { deleteAnalyzer } = management;
|
|
12602
|
+
await deleteAnalyzer(analyzersBasePath, analyzerId);
|
|
12603
|
+
} catch (error) {
|
|
12604
|
+
console.warn(`Warning: Could not clean up old analyzer directory: ${error.message}`);
|
|
12605
|
+
}
|
|
12606
|
+
}
|
|
12607
|
+
|
|
12608
|
+
return {
|
|
12609
|
+
success: true,
|
|
12610
|
+
message: `Analyzer '${analyzerId}' updated successfully.`,
|
|
12611
|
+
newAnalyzerId
|
|
12612
|
+
};
|
|
12613
|
+
}
|
|
12614
|
+
|
|
12615
|
+
var updater = {
|
|
12616
|
+
updateAnalyzer: updateAnalyzer$1
|
|
12617
|
+
};
|
|
12618
|
+
|
|
12619
|
+
/*
|
|
12620
|
+
* Component: AnalyzerUtils Cloner
|
|
12621
|
+
* Block-UUID: 56b8c9f4-97ce-406c-a598-22a838ebefda
|
|
12622
|
+
* Parent-UUID: N/A
|
|
12623
|
+
* Version: 1.0.0
|
|
12624
|
+
* Description: Provides utility functions for cloning analyzer configurations.
|
|
12625
|
+
* Language: JavaScript
|
|
12626
|
+
* Created-at: 2025-12-26T16:59:39.782Z
|
|
12627
|
+
* Authors: GLM-4.6 (v1.0.0)
|
|
12628
|
+
*/
|
|
12629
|
+
|
|
12630
|
+
require$$0.promises;
|
|
12631
|
+
const CodeBlockUtils$1 = CodeBlockUtils$7;
|
|
12632
|
+
const { preprocessJsonForValidation: preprocessJsonForValidation$1 } = jsonParser;
|
|
12633
|
+
const { isValidDirName } = discovery;
|
|
12634
|
+
const { saveConfiguration: saveConfiguration$1 } = saver;
|
|
12635
|
+
const { getAnalyzers: getAnalyzers$2 } = discovery;
|
|
12636
|
+
|
|
12637
|
+
/**
|
|
12638
|
+
* Clones an existing analyzer with a new name.
|
|
12639
|
+
*
|
|
12640
|
+
* @param {string} analyzersBasePath - The absolute path to the base directory containing the analyzers.
|
|
12641
|
+
* @param {string} originalAnalyzerId - The ID of the analyzer to clone (format: 'analyzer_name::content_type::instructions_type').
|
|
12642
|
+
* @param {string} newAnalyzerName - The new name for the cloned analyzer.
|
|
12643
|
+
* @param {object} [options={}] - Optional configuration options.
|
|
12644
|
+
* @param {string} [options.label] - The new label for the cloned analyzer (optional, defaults to newAnalyzerName).
|
|
12645
|
+
* @param {string} [options.description] - The new description for the cloned analyzer (optional, keeps original if not provided).
|
|
12646
|
+
* @returns {Promise<{success: boolean, message: string, newAnalyzerId?: string}>} A promise that resolves with a result object.
|
|
12647
|
+
*/
|
|
12648
|
+
async function cloneAnalyzer$1(analyzersBasePath, originalAnalyzerId, newAnalyzerName, options = {}) {
|
|
12649
|
+
// 1. Validate inputs
|
|
12650
|
+
if (typeof analyzersBasePath !== 'string' || analyzersBasePath.trim() === '') {
|
|
12651
|
+
return { success: false, message: 'analyzersBasePath is required.' };
|
|
12652
|
+
}
|
|
12653
|
+
if (typeof originalAnalyzerId !== 'string' || originalAnalyzerId.trim() === '') {
|
|
12654
|
+
return { success: false, message: 'originalAnalyzerId is required.' };
|
|
12655
|
+
}
|
|
12656
|
+
if (typeof newAnalyzerName !== 'string' || newAnalyzerName.trim() === '') {
|
|
12657
|
+
return { success: false, message: 'newAnalyzerName is required.' };
|
|
12658
|
+
}
|
|
12659
|
+
|
|
12660
|
+
// 2. Parse original analyzerId
|
|
12661
|
+
const parts = originalAnalyzerId.split('::');
|
|
12662
|
+
if (parts.length !== 3) {
|
|
12663
|
+
return { success: false, message: `Invalid originalAnalyzerId format. Expected 'analyzer_name::content_type::instructions_type', but got '${originalAnalyzerId}'.` };
|
|
12664
|
+
}
|
|
12665
|
+
const [originalAnalyzerName, contentType, instructionsType] = parts;
|
|
12666
|
+
|
|
12667
|
+
// 3. Validate new analyzer name
|
|
12668
|
+
if (!isValidDirName(newAnalyzerName)) {
|
|
12669
|
+
return { success: false, message: `Invalid analyzer name '${newAnalyzerName}'. Names must be alphanumeric, dash, or underscore, cannot start with underscore, and cannot contain dots.` };
|
|
12670
|
+
}
|
|
12671
|
+
|
|
12672
|
+
// 4. Check if new analyzer name already exists
|
|
12673
|
+
try {
|
|
12674
|
+
const existingAnalyzers = await getAnalyzers$2(analyzersBasePath);
|
|
12675
|
+
const nameExists = existingAnalyzers.some(analyzer => analyzer.name === newAnalyzerName);
|
|
12676
|
+
if (nameExists) {
|
|
12677
|
+
return { success: false, message: `An analyzer with name '${newAnalyzerName}' already exists. Please choose a different name.` };
|
|
12678
|
+
}
|
|
12679
|
+
} catch (error) {
|
|
12680
|
+
return { success: false, message: `Failed to check for existing analyzers: ${error.message}` };
|
|
12681
|
+
}
|
|
12682
|
+
|
|
12683
|
+
// 5. Get original analyzer's instructions content
|
|
12684
|
+
const { getAnalyzerInstructionsContent } = instructionLoader;
|
|
12685
|
+
let instructionsContent;
|
|
12686
|
+
try {
|
|
12687
|
+
instructionsContent = await getAnalyzerInstructionsContent(analyzersBasePath, originalAnalyzerId);
|
|
12688
|
+
if (!instructionsContent) {
|
|
12689
|
+
return { success: false, message: `Could not find original analyzer '${originalAnalyzerId}'.` };
|
|
12690
|
+
}
|
|
12691
|
+
} catch (error) {
|
|
12692
|
+
return { success: false, message: `Failed to read original analyzer instructions: ${error.message}` };
|
|
12693
|
+
}
|
|
12694
|
+
|
|
12695
|
+
// 6. Extract and update JSON block
|
|
12696
|
+
const { blocks } = CodeBlockUtils$1.extractCodeBlocks(instructionsContent, { silent: true });
|
|
12697
|
+
const jsonBlocks = blocks.filter((block, index) => {
|
|
12698
|
+
if (block.language === 'json') {
|
|
12699
|
+
block.index = index;
|
|
12700
|
+
return block;
|
|
12701
|
+
}
|
|
12702
|
+
});
|
|
12703
|
+
const jsonBlock = jsonBlocks[jsonBlocks.length - 1];
|
|
12704
|
+
|
|
12705
|
+
if (!jsonBlock) {
|
|
12706
|
+
return { success: false, message: 'No JSON block found in original analyzer instructions.' };
|
|
12707
|
+
}
|
|
12708
|
+
|
|
12709
|
+
let jsonData;
|
|
12710
|
+
try {
|
|
12711
|
+
const preprocessedContent = preprocessJsonForValidation$1(jsonBlock.content);
|
|
12712
|
+
jsonData = JSON.parse(preprocessedContent);
|
|
12713
|
+
} catch (error) {
|
|
12714
|
+
return { success: false, message: `Failed to parse JSON block: ${error.message}` };
|
|
12715
|
+
}
|
|
12716
|
+
|
|
12717
|
+
// 7. Update JSON data with new values
|
|
12718
|
+
if (options.label !== undefined) {
|
|
12719
|
+
jsonData.label = options.label;
|
|
12720
|
+
}
|
|
12721
|
+
if (options.description !== undefined) {
|
|
12722
|
+
jsonData.description = options.description;
|
|
12723
|
+
}
|
|
12724
|
+
// Reset version for cloned analyzer
|
|
12725
|
+
jsonData.version = '1.0.0';
|
|
12726
|
+
|
|
12727
|
+
// 8. Rebuild the instructions content with updated JSON
|
|
12728
|
+
let updatedInstructionsContent = CodeBlockUtils$1.updateCodeBlockByIndex(
|
|
12729
|
+
instructionsContent,
|
|
12730
|
+
jsonBlock.index,
|
|
12731
|
+
JSON.stringify(jsonData, null, 2),
|
|
12732
|
+
'json'
|
|
12733
|
+
);
|
|
12734
|
+
|
|
12735
|
+
// 9. Create the new analyzer ID
|
|
12736
|
+
const newAnalyzerId = `${newAnalyzerName}::${contentType}::${instructionsType}`;
|
|
12737
|
+
|
|
12738
|
+
// 10. Update the analyzer id in the instructions
|
|
12739
|
+
updatedInstructionsContent = updatedInstructionsContent.replaceAll(originalAnalyzerId, newAnalyzerId);
|
|
12740
|
+
|
|
12741
|
+
// 11. Save the new analyzer
|
|
12742
|
+
try {
|
|
12743
|
+
const saveResult = await saveConfiguration$1(
|
|
12744
|
+
analyzersBasePath,
|
|
12745
|
+
newAnalyzerId,
|
|
12746
|
+
updatedInstructionsContent
|
|
12747
|
+
);
|
|
12748
|
+
|
|
12749
|
+
if (saveResult.success) {
|
|
12750
|
+
return {
|
|
12751
|
+
success: true,
|
|
12752
|
+
message: `Analyzer '${originalAnalyzerName}' cloned successfully as '${newAnalyzerName}'.`,
|
|
12753
|
+
newAnalyzerId
|
|
12754
|
+
};
|
|
12755
|
+
} else {
|
|
12756
|
+
return { success: false, error: saveResult.message };
|
|
12757
|
+
}
|
|
12758
|
+
} catch (error) {
|
|
12759
|
+
return { success: false, message: `Failed to save cloned analyzer: ${error.message}` };
|
|
12760
|
+
}
|
|
12761
|
+
}
|
|
12762
|
+
|
|
12763
|
+
var cloner = {
|
|
12764
|
+
cloneAnalyzer: cloneAnalyzer$1
|
|
12765
|
+
};
|
|
12766
|
+
|
|
12767
|
+
/*
|
|
12768
|
+
* Component: AnalyzerUtils Index
|
|
12769
|
+
* Block-UUID: 780e17b0-0c1e-4d77-bf6e-302951b341bf
|
|
12770
|
+
* Parent-UUID: b403b6a1-230b-4247-8cd6-2a3d068f4bbf
|
|
12771
|
+
* Version: 1.5.0
|
|
12772
|
+
* Description: Aggregates and exports all utility functions from the AnalyzerUtils module. Added cloneAnalyzer method.
|
|
12773
|
+
* Language: JavaScript
|
|
12774
|
+
* Created-at: 2025-08-28T15:56:40.319Z
|
|
12775
|
+
* Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0), Gemini 2.5 Flash (v1.2.0), GLM-4.6 (v1.3.0), GLM-4.6 (v1.4.0), GLM-4.6 (v1.5.0)
|
|
12776
|
+
*/
|
|
12777
|
+
|
|
12778
|
+
const { buildChatIdToPathMap: buildChatIdToPathMap$1 } = contextMapper;
|
|
12779
|
+
const { processLLMAnalysisResponse: processLLMAnalysisResponse$1 } = responseProcessor;
|
|
12780
|
+
const { validateLLMAnalysisData: validateLLMAnalysisData$1 } = dataValidator;
|
|
12781
|
+
const { getAnalyzers: getAnalyzers$1 } = discovery;
|
|
12782
|
+
const { saveConfiguration } = saver;
|
|
12783
|
+
const { getAnalyzerSchema: getAnalyzerSchema$1 } = schemaLoader;
|
|
12784
|
+
const { deleteAnalyzer: deleteAnalyzer$1 } = management;
|
|
12785
|
+
const { getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1 } = instructionLoader;
|
|
12786
|
+
const { getSystemMessageContent: getSystemMessageContent$1, getStartMessageContent: getStartMessageContent$1 } = defaultPromptLoader;
|
|
12787
|
+
const { preprocessJsonForValidation } = jsonParser;
|
|
12788
|
+
const { updateAnalyzer } = updater;
|
|
12789
|
+
const { cloneAnalyzer } = cloner;
|
|
12790
|
+
|
|
12791
|
+
var AnalyzerUtils$1 = {
|
|
12792
|
+
buildChatIdToPathMap: buildChatIdToPathMap$1,
|
|
12793
|
+
processLLMAnalysisResponse: processLLMAnalysisResponse$1,
|
|
12794
|
+
validateLLMAnalysisData: validateLLMAnalysisData$1,
|
|
12795
|
+
getAnalyzers: getAnalyzers$1,
|
|
12796
|
+
getAnalyzerSchema: getAnalyzerSchema$1,
|
|
12797
|
+
deleteAnalyzer: deleteAnalyzer$1,
|
|
12798
|
+
getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1,
|
|
12799
|
+
saveConfiguration,
|
|
12800
|
+
getSystemMessageContent: getSystemMessageContent$1,
|
|
12801
|
+
getStartMessageContent: getStartMessageContent$1,
|
|
12802
|
+
preprocessJsonForValidation,
|
|
12803
|
+
updateAnalyzer,
|
|
12804
|
+
cloneAnalyzer
|
|
12805
|
+
};
|
|
12806
|
+
|
|
12807
|
+
/**
|
|
12808
|
+
* Component: LLMUtils
|
|
12809
|
+
* Block-UUID: a3106054-42f1-474f-96f3-182d66eb19a0
|
|
12810
|
+
* Parent-UUID: N/A
|
|
12811
|
+
* Version: 1.0.0
|
|
12812
|
+
* Description: Provides utility functions related to Large Language Model interactions, such as token estimation.
|
|
12813
|
+
* Language: JavaScript
|
|
12814
|
+
* Created-at: 2025-04-22T17:16:00.590Z
|
|
12815
|
+
* Authors: Gemini 2.5 Pro (v1.0.0)
|
|
12816
|
+
*/
|
|
12817
|
+
|
|
12818
|
+
/**
|
|
12819
|
+
* Estimates the number of tokens in a given text string.
|
|
12820
|
+
* This is a basic estimation using the common heuristic of ~4 characters per token.
|
|
12821
|
+
* Actual token count can vary significantly based on the specific tokenizer used by an LLM.
|
|
12822
|
+
*
|
|
12823
|
+
* @param {string} text - The text to estimate tokens for.
|
|
12824
|
+
* @returns {number} An estimated token count. Returns 0 if input is not a non-empty string.
|
|
12825
|
+
*/
|
|
12826
|
+
function estimateTokens$1(text) {
|
|
12096
12827
|
if (typeof text !== 'string' || text.length === 0) {
|
|
12097
12828
|
return 0;
|
|
12098
12829
|
}
|
|
@@ -12274,13 +13005,13 @@ var FormatterUtils$1 = {
|
|
|
12274
13005
|
|
|
12275
13006
|
/**
|
|
12276
13007
|
* Component: DomUtils Helper Functions
|
|
12277
|
-
* Block-UUID:
|
|
12278
|
-
* Parent-UUID:
|
|
12279
|
-
* Version: 1.
|
|
13008
|
+
* Block-UUID: 9a8e8e8e-8b15-4346-bbfa-740e6a5d2d79
|
|
13009
|
+
* Parent-UUID: 8a528728-ce54-4445-946d-1743fb4b16be
|
|
13010
|
+
* Version: 1.3.0
|
|
12280
13011
|
* Description: Provides helper functions for creating and manipulating DOM elements.
|
|
12281
13012
|
* Language: JavaScript
|
|
12282
|
-
* Created-at: 2025-
|
|
12283
|
-
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Flash (v1.1.0)
|
|
13013
|
+
* Created-at: 2025-12-14T04:18:40.180Z
|
|
13014
|
+
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Flash (v1.1.0), Qwen 3 Coder 480B - Cerebras (v1.2.0), GLM-4.6 (v1.2.1), GLM-4.6 (v1.3.0)
|
|
12284
13015
|
*/
|
|
12285
13016
|
|
|
12286
13017
|
function createElement(type, params) {
|
|
@@ -12292,6 +13023,7 @@ function createElement(type, params) {
|
|
|
12292
13023
|
let {
|
|
12293
13024
|
id,
|
|
12294
13025
|
ariaLabel,
|
|
13026
|
+
xmlns,
|
|
12295
13027
|
role,
|
|
12296
13028
|
html,
|
|
12297
13029
|
text,
|
|
@@ -12314,11 +13046,15 @@ function createElement(type, params) {
|
|
|
12314
13046
|
"data-message-role": dmr,
|
|
12315
13047
|
attrs = {},
|
|
12316
13048
|
dataset,
|
|
13049
|
+
rows
|
|
12317
13050
|
} = params;
|
|
12318
13051
|
|
|
12319
13052
|
// Set standard attributes
|
|
12320
13053
|
if (id != null) elem.id = id;
|
|
12321
13054
|
if (ariaLabel) elem.setAttribute("aria-label", ariaLabel);
|
|
13055
|
+
if (xmlns) elem.setAttribute("xmlns", xmlns);
|
|
13056
|
+
if (params.viewBox) elem.setAttribute("viewBox", params.viewBox);
|
|
13057
|
+
if (params.fill) elem.setAttribute("fill", params.fill);
|
|
12322
13058
|
if (role) elem.setAttribute("role", role);
|
|
12323
13059
|
if (placeholder) elem.setAttribute("placeholder", placeholder);
|
|
12324
13060
|
if (cls || className) elem.setAttribute("class", cls || className);
|
|
@@ -12326,6 +13062,9 @@ function createElement(type, params) {
|
|
|
12326
13062
|
if (title != null) elem.setAttribute("title", title);
|
|
12327
13063
|
if (inputType) elem.setAttribute("type", inputType);
|
|
12328
13064
|
if (name != null) elem.setAttribute("name", name);
|
|
13065
|
+
if (params.width) elem.setAttribute("width", params.width);
|
|
13066
|
+
if (params.height) elem.setAttribute("height", params.height);
|
|
13067
|
+
if (params.stroke) elem.setAttribute("stroke", params.stroke);
|
|
12329
13068
|
if (value != null) elem.value = value;
|
|
12330
13069
|
if (checked != null && checked) elem.checked = true; // Use property for checked
|
|
12331
13070
|
if (selected != null && selected) elem.selected = true; // Use property for selected
|
|
@@ -12333,13 +13072,21 @@ function createElement(type, params) {
|
|
|
12333
13072
|
if (dmi != null) elem.setAttribute("data-message-id", dmi);
|
|
12334
13073
|
if (dmr != null) elem.setAttribute("data-message-role", dmr);
|
|
12335
13074
|
if (_for != null ) elem.setAttribute("for", _for);
|
|
13075
|
+
if (params.strokeWidth) elem.setAttribute("stroke-width", params.strokeWidth);
|
|
13076
|
+
if (params.strokeLinecap) elem.setAttribute("stroke-linecap", params.strokeLinecap);
|
|
13077
|
+
if (params.strokeLinejoin) elem.setAttribute("stroke-linejoin", params.strokeLinejoin);
|
|
12336
13078
|
if (colSpan != null) elem.colSpan = colSpan;
|
|
13079
|
+
if (rows) elem.setAttribute("rows", params.rows);
|
|
12337
13080
|
|
|
12338
13081
|
// Set content
|
|
12339
13082
|
if (html != null) {
|
|
12340
13083
|
if (typeof html === "object" && html instanceof Node) { // Ensure html is a Node
|
|
12341
13084
|
elem.appendChild(html);
|
|
12342
13085
|
} else if (typeof html === "string") {
|
|
13086
|
+
// For SVG elements, use innerHTML to support path elements
|
|
13087
|
+
if (type === 'svg' && params.innerHTML) {
|
|
13088
|
+
elem.innerHTML = params.innerHTML;
|
|
13089
|
+
}
|
|
12343
13090
|
elem.innerHTML = html;
|
|
12344
13091
|
}
|
|
12345
13092
|
} else if (text != null) {
|
|
@@ -12365,12 +13112,12 @@ function createElement(type, params) {
|
|
|
12365
13112
|
});
|
|
12366
13113
|
}
|
|
12367
13114
|
|
|
12368
|
-
//
|
|
13115
|
+
// Set additional attributes from attrs object
|
|
12369
13116
|
if (attrs && typeof attrs === 'object') {
|
|
12370
13117
|
for (const [key, value] of Object.entries(attrs)) {
|
|
12371
13118
|
if (value !== undefined && value !== null) {
|
|
12372
13119
|
// Skip if already set by standard properties or handled directly
|
|
12373
|
-
if (!['id', 'class', 'role', 'aria-label', 'title', 'style', '
|
|
13120
|
+
if (!['id', 'class', 'role', 'aria-label', 'title', 'style', 'selected', 'disabled', 'value', 'name', 'type', 'for'].includes(key) && !key.startsWith('data-')) {
|
|
12374
13121
|
elem.setAttribute(key, value);
|
|
12375
13122
|
}
|
|
12376
13123
|
}
|
|
@@ -12483,14 +13230,17 @@ const h$1 = {
|
|
|
12483
13230
|
},
|
|
12484
13231
|
createLink: (params) => {
|
|
12485
13232
|
const link = createElement("a", params);
|
|
12486
|
-
|
|
12487
|
-
if (params?.
|
|
13233
|
+
if (params?.href) link.href = params.href;
|
|
13234
|
+
if (params?.target) link.target = params.target;
|
|
12488
13235
|
return link;
|
|
12489
13236
|
},
|
|
12490
13237
|
createNav: (params) => {
|
|
12491
13238
|
return createElement("nav", params);
|
|
12492
13239
|
},
|
|
12493
|
-
|
|
13240
|
+
createOl: (params) => {
|
|
13241
|
+
return createElement("ol", params);
|
|
13242
|
+
},
|
|
13243
|
+
createOL: (params) => {
|
|
12494
13244
|
return createElement("ol", params);
|
|
12495
13245
|
},
|
|
12496
13246
|
createOption: (params) => { // Added
|
|
@@ -12508,11 +13258,33 @@ const h$1 = {
|
|
|
12508
13258
|
},
|
|
12509
13259
|
createSelect: (params) => { // Added
|
|
12510
13260
|
// name, disabled etc handled by createElement
|
|
12511
|
-
|
|
13261
|
+
const select = createElement("select", params);
|
|
13262
|
+
|
|
13263
|
+
// Handle options array if provided
|
|
13264
|
+
if (params && params.options && Array.isArray(params.options)) {
|
|
13265
|
+
params.options.forEach(option => {
|
|
13266
|
+
if (option && typeof option === 'object') {
|
|
13267
|
+
const optionElement = createElement("option", {
|
|
13268
|
+
value: option.value,
|
|
13269
|
+
text: option.text,
|
|
13270
|
+
selected: option.selected
|
|
13271
|
+
});
|
|
13272
|
+
select.appendChild(optionElement);
|
|
13273
|
+
}
|
|
13274
|
+
});
|
|
13275
|
+
}
|
|
13276
|
+
|
|
13277
|
+
return select;
|
|
12512
13278
|
},
|
|
12513
13279
|
createSpan: (params) => {
|
|
12514
13280
|
return createElement("span", params);
|
|
12515
13281
|
},
|
|
13282
|
+
createSvg: (params) => {
|
|
13283
|
+
// Create SVG element with xmlns attribute
|
|
13284
|
+
const svgParams = { ...params, xmlns: "http://www.w3.org/2000/svg" };
|
|
13285
|
+
const svg = createElement("svg", svgParams);
|
|
13286
|
+
return svg;
|
|
13287
|
+
},
|
|
12516
13288
|
createStrong: (params) => { // Added
|
|
12517
13289
|
return createElement("strong", params);
|
|
12518
13290
|
},
|
|
@@ -12525,6 +13297,10 @@ const h$1 = {
|
|
|
12525
13297
|
createText: (text) => {
|
|
12526
13298
|
return document.createTextNode(text);
|
|
12527
13299
|
},
|
|
13300
|
+
createTextarea: (params) => {
|
|
13301
|
+
const textArea = createElement("textarea", params);
|
|
13302
|
+
return textArea;
|
|
13303
|
+
},
|
|
12528
13304
|
createTextArea: (params) => {
|
|
12529
13305
|
const textArea = createElement("textarea", params);
|
|
12530
13306
|
return textArea;
|
|
@@ -12723,6 +13499,35 @@ const h$1 = {
|
|
|
12723
13499
|
})
|
|
12724
13500
|
.join('');
|
|
12725
13501
|
},
|
|
13502
|
+
|
|
13503
|
+
/**
|
|
13504
|
+
* Injects CSS styles into the document head.
|
|
13505
|
+
* @param {string} cssString - The CSS string to inject.
|
|
13506
|
+
* @param {string} [id] - Optional ID for the style element to prevent duplicates.
|
|
13507
|
+
* @returns {HTMLStyleElement} The created or existing style element.
|
|
13508
|
+
*/
|
|
13509
|
+
injectStyles: (cssString, id) => {
|
|
13510
|
+
// If an ID is provided, check if styles with this ID already exist
|
|
13511
|
+
if (id) {
|
|
13512
|
+
const existingStyle = document.getElementById(id);
|
|
13513
|
+
if (existingStyle) {
|
|
13514
|
+
// Styles already injected, return the existing element
|
|
13515
|
+
return existingStyle;
|
|
13516
|
+
}
|
|
13517
|
+
}
|
|
13518
|
+
|
|
13519
|
+
// Create a new style element
|
|
13520
|
+
const styleElement = document.createElement('style');
|
|
13521
|
+
if (id) {
|
|
13522
|
+
styleElement.id = id;
|
|
13523
|
+
}
|
|
13524
|
+
styleElement.textContent = cssString;
|
|
13525
|
+
|
|
13526
|
+
// Append to the document head
|
|
13527
|
+
document.head.appendChild(styleElement);
|
|
13528
|
+
|
|
13529
|
+
return styleElement;
|
|
13530
|
+
},
|
|
12726
13531
|
|
|
12727
13532
|
/**
|
|
12728
13533
|
* Calculates the distance between an element's edge and the viewport's corresponding edge
|
|
@@ -22355,7 +23160,10 @@ function createMarkdownRenderer$1(hljs, hstyle = {}, nhstyle = {}) {
|
|
|
22355
23160
|
// Create the inner code element with the highlighted content
|
|
22356
23161
|
// and the language label prepended.
|
|
22357
23162
|
const codeElement = h.createCode({
|
|
22358
|
-
html: `<span class='gs-chat-lang'>${lang}</span>\n\n${highlightedCode}
|
|
23163
|
+
html: `<span class='gs-chat-lang'>${lang}</span>\n\n${highlightedCode}`,
|
|
23164
|
+
style: {
|
|
23165
|
+
fontSize: '13px'
|
|
23166
|
+
}
|
|
22359
23167
|
});
|
|
22360
23168
|
|
|
22361
23169
|
// Wrap the code element in a pre tag with styling
|
|
@@ -23163,6 +23971,18 @@ let SVGUtils$1 = class SVGUtils {
|
|
|
23163
23971
|
return this.create(xml, params);
|
|
23164
23972
|
}
|
|
23165
23973
|
|
|
23974
|
+
/**
|
|
23975
|
+
* Generate dropZone SVG icon
|
|
23976
|
+
* @param {Object} params - Configuration parameters
|
|
23977
|
+
* @returns {Element} SVG element
|
|
23978
|
+
*/
|
|
23979
|
+
static dropZone(params) {
|
|
23980
|
+
const xml = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='64' height='64'><path d="M7 18C4.23858 18 2 15.7614 2 13C2 10.2386 4.23858 8 7 8C7.55228 8 8 8.44772 8 9C8 9.55228 7.55228 10 7 10C5.34315 10 4 11.3431 4 13C4 14.6569 5.34315 16 7 16H17C18.6569 16 20 14.6569 20 13C20 11.3431 18.6569 10 17 10C16.4477 10 16 9.55228 16 9C16 8.44772 16.4477 8 17 8C19.7614 8 22 10.2386 22 13C22 15.7614 19.7614 18 17 18H7Z" fill="currentColor"/><path d="M12 2L12 14M12 14L9 11M12 14L15 11" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
23981
|
+
return this.create(xml, params);
|
|
23982
|
+
}
|
|
23983
|
+
|
|
23984
|
+
|
|
23985
|
+
|
|
23166
23986
|
/**
|
|
23167
23987
|
* Generate dot SVG icon
|
|
23168
23988
|
* @param {Object} params - Configuration parameters
|
|
@@ -23203,6 +24023,26 @@ let SVGUtils$1 = class SVGUtils {
|
|
|
23203
24023
|
return this.create(xml, params);
|
|
23204
24024
|
}
|
|
23205
24025
|
|
|
24026
|
+
/**
|
|
24027
|
+
* Generate eye SVG icon
|
|
24028
|
+
* @param {Object} params - Configuration parameters
|
|
24029
|
+
* @returns {Element} SVG element
|
|
24030
|
+
*/
|
|
24031
|
+
static eye(params) {
|
|
24032
|
+
const xml = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M8 2c1.981 0 3.671.992 4.933 2.078 1.27 1.091 2.187 2.345 2.637 3.023a1.62 1.62 0 0 1 0 1.798c-.45.678-1.367 1.932-2.637 3.023C11.67 13.008 9.981 14 8 14c-1.981 0-3.671-.992-4.933-2.078C1.797 10.83.88 9.576.43 8.898a1.62 1.62 0 0 1 0-1.798c.45-.677 1.367-1.931 2.637-3.022C4.33 2.992 6.019 2 8 2ZM1.679 7.932a.12.12 0 0 0 0 .136c.411.622 1.241 1.75 2.366 2.717C5.176 11.758 6.527 12.5 8 12.5c1.473 0 2.825-.742 3.955-1.715 1.124-.967 1.954-2.096 2.366-2.717a.12.12 0 0 0 0-.136c-.412-.621-1.242-1.75-2.366-2.717C10.824 4.242 9.473 3.5 8 3.5c-1.473 0-2.825.742-3.955 1.715-1.124.967-1.954 2.096-2.366 2.717ZM8 10a2 2 0 1 1-.001-3.999A2 2 0 0 1 8 10Z"></path></svg>`;
|
|
24033
|
+
return this.create(xml, params);
|
|
24034
|
+
}
|
|
24035
|
+
|
|
24036
|
+
/**
|
|
24037
|
+
* Generate eye closed SVG icon
|
|
24038
|
+
* @param {Object} params - Configuration parameters
|
|
24039
|
+
* @returns {Element} SVG element
|
|
24040
|
+
*/
|
|
24041
|
+
static eyeClosed(params) {
|
|
24042
|
+
const xml = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M.143 2.31a.75.75 0 0 1 1.047-.167l14.5 10.5a.75.75 0 1 1-.88 1.214l-2.248-1.628C11.346 13.19 9.792 14 8 14c-1.981 0-3.67-.992-4.933-2.078C1.797 10.832.88 9.577.43 8.9a1.619 1.619 0 0 1 0-1.797c.353-.533.995-1.42 1.868-2.305L.31 3.357A.75.75 0 0 1 .143 2.31Zm1.536 5.622A.12.12 0 0 0 1.657 8c0 .021.006.045.022.068.412.621 1.242 1.75 2.366 2.717C5.175 11.758 6.527 12.5 8 12.5c1.195 0 2.31-.488 3.29-1.191L9.063 9.695A2 2 0 0 1 6.058 7.52L3.529 5.688a14.207 14.207 0 0 0-1.85 2.244ZM8 3.5c-.516 0-1.017.09-1.499.251a.75.75 0 1 1-.473-1.423A6.207 6.207 0 0 1 8 2c1.981 0 3.67.992 4.933 2.078 1.27 1.091 2.187 2.345 2.637 3.023a1.62 1.62 0 0 1 0 1.798c-.11.166-.248.365-.41.587a.75.75 0 1 1-1.21-.887c.148-.201.272-.382.371-.53a.119.119 0 0 0 0-.137c-.412-.621-1.242-1.75-2.366-2.717C10.825 4.242 9.473 3.5 8 3.5Z"></path></svg>`;
|
|
24043
|
+
return this.create(xml, params);
|
|
24044
|
+
}
|
|
24045
|
+
|
|
23206
24046
|
/**
|
|
23207
24047
|
* Generate file SVG icon
|
|
23208
24048
|
* @param {Object} params - Configuration parameters
|
|
@@ -23759,6 +24599,16 @@ let SVGUtils$1 = class SVGUtils {
|
|
|
23759
24599
|
return this.create(xml, params);
|
|
23760
24600
|
}
|
|
23761
24601
|
|
|
24602
|
+
/**
|
|
24603
|
+
* Generate squarCircle SVG icon
|
|
24604
|
+
* @param {Object} params - Configuration parameters
|
|
24605
|
+
* @returns {Element} SVG element
|
|
24606
|
+
*/
|
|
24607
|
+
static squareCircle(params) {
|
|
24608
|
+
const xml = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm0-1.5a6.5 6.5 0 1 0 0-13 6.5 6.5 0 0 0 0 13Z"></path><path d="M5 5.75A.75.75 0 0 1 5.75 5h4.5a.75.75 0 0 1 .75.75v4.5a.75.75 0 0 1-.75.75h-4.5a.75.75 0 0 1-.75-.75Z"></path></svg>`;
|
|
24609
|
+
return this.create(xml, params);
|
|
24610
|
+
}
|
|
24611
|
+
|
|
23762
24612
|
/**
|
|
23763
24613
|
* Generate stack SVG icon
|
|
23764
24614
|
* @param {Object} params - Configuration parameters
|
|
@@ -24049,6 +24899,16 @@ let SVGUtils$1 = class SVGUtils {
|
|
|
24049
24899
|
return this.create(xml, params);
|
|
24050
24900
|
}
|
|
24051
24901
|
|
|
24902
|
+
/**
|
|
24903
|
+
* Generate verticalEllipsis SVG icon
|
|
24904
|
+
* @param {Object} params - Configuration parameters
|
|
24905
|
+
* @returns {Element} SVG element
|
|
24906
|
+
*/
|
|
24907
|
+
static verticalEllipsis(params) {
|
|
24908
|
+
const xml = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16' transform='rotate(90)'><path d='M8 9a1.5 1.5 0 100-3 1.5 1.5 0 000 3zM1.5 9a1.5 1.5 0 100-3 1.5 1.5 0 000 3zm13 0a1.5 1.5 0 100-3 1.5 1.5 0 000 3z'></path></svg>`;
|
|
24909
|
+
return this.create(xml, params);
|
|
24910
|
+
}
|
|
24911
|
+
|
|
24052
24912
|
/**
|
|
24053
24913
|
* Generate x SVG icon
|
|
24054
24914
|
* @param {Object} params - Configuration parameters
|
|
@@ -24078,35 +24938,343 @@ let SVGUtils$1 = class SVGUtils {
|
|
|
24078
24938
|
const xml = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'><path fill-rule='evenodd' d='M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z'></path></svg>`;
|
|
24079
24939
|
return this.create(xml, params);
|
|
24080
24940
|
}
|
|
24941
|
+
|
|
24942
|
+
static zai(params) {
|
|
24943
|
+
const xml = `<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em"><title>Z.ai</title><path d="M12.105 2L9.927 4.953H.653L2.83 2h9.276zM23.254 19.048L21.078 22h-9.242l2.174-2.952h9.244zM24 2L9.264 22H0L14.736 2H24z"/></svg>`;
|
|
24944
|
+
return this.create(xml, params);
|
|
24945
|
+
}
|
|
24081
24946
|
};
|
|
24082
24947
|
|
|
24083
24948
|
var SVGUtils_1 = SVGUtils$1;
|
|
24084
24949
|
|
|
24085
24950
|
/*
|
|
24086
|
-
* Component:
|
|
24087
|
-
* Block-UUID:
|
|
24088
|
-
* Parent-UUID: N/A
|
|
24951
|
+
* Component: StringUtils
|
|
24952
|
+
* Block-UUID: 7069f2b4-f0b3-4dcd-9eae-5cecaddcdd66
|
|
24089
24953
|
* Version: 1.0.0
|
|
24090
|
-
* Description:
|
|
24954
|
+
* Description: A collection of utility functions for common string manipulation and processing tasks within GitSense Chat.
|
|
24091
24955
|
* Language: JavaScript
|
|
24092
|
-
* Created-at: 2025-10-
|
|
24956
|
+
* Created-at: 2025-10-30T22:06:47.000Z
|
|
24093
24957
|
* Authors: Qwen 3 Coder 480B - Cerebras (v1.0.0)
|
|
24094
24958
|
*/
|
|
24095
24959
|
|
|
24096
24960
|
/**
|
|
24097
|
-
*
|
|
24961
|
+
* Splits a string into an array of substrings based on a delimiter, up to a specified limit.
|
|
24962
|
+
* This mimics behavior similar to Python's `str.split(sep, maxsplit)` or Java's `String.split(regex, limit)`.
|
|
24963
|
+
*
|
|
24964
|
+
* @param {string} text - The string to split.
|
|
24965
|
+
* @param {string|RegExp} delimiter - The delimiter to split the string by.
|
|
24966
|
+
* @param {number} [limit=Infinity] - The maximum number of parts to return. The final part will contain the remainder of the string.
|
|
24967
|
+
* @returns {string[]} An array of substrings.
|
|
24098
24968
|
*/
|
|
24099
|
-
|
|
24100
|
-
|
|
24101
|
-
|
|
24102
|
-
|
|
24103
|
-
|
|
24104
|
-
|
|
24105
|
-
|
|
24106
|
-
|
|
24107
|
-
|
|
24108
|
-
|
|
24109
|
-
|
|
24969
|
+
function splitWithLimit$1(text, delimiter, limit = Infinity) {
|
|
24970
|
+
if (limit === 0) {
|
|
24971
|
+
return [];
|
|
24972
|
+
}
|
|
24973
|
+
if (limit === 1) {
|
|
24974
|
+
return [text];
|
|
24975
|
+
}
|
|
24976
|
+
|
|
24977
|
+
const parts = [];
|
|
24978
|
+
let remainingText = text;
|
|
24979
|
+
let count = 0;
|
|
24980
|
+
|
|
24981
|
+
// Handle RegExp delimiter
|
|
24982
|
+
if (delimiter instanceof RegExp) {
|
|
24983
|
+
// For RegExp, we need to manually find matches and slice the string
|
|
24984
|
+
// This is a simplified approach and might not cover all edge cases of global regex matching
|
|
24985
|
+
// especially with capture groups or zero-width matches.
|
|
24986
|
+
const flags = delimiter.flags.includes('g') ? delimiter.flags : delimiter.flags + 'g';
|
|
24987
|
+
const globalDelimiter = new RegExp(delimiter.source, flags);
|
|
24988
|
+
let match;
|
|
24989
|
+
let lastIndex = 0;
|
|
24990
|
+
let matchCount = 0;
|
|
24991
|
+
|
|
24992
|
+
// We need (limit - 1) matches to create `limit` parts
|
|
24993
|
+
while ((match = globalDelimiter.exec(remainingText)) !== null && matchCount < limit - 1) {
|
|
24994
|
+
// Add the part before the match
|
|
24995
|
+
parts.push(remainingText.substring(lastIndex, match.index));
|
|
24996
|
+
// Add the matched delimiter part itself if it's non-empty (important for zero-width matches)
|
|
24997
|
+
// This part is tricky; typically, the delimiter itself is not part of the returned array.
|
|
24998
|
+
// The logic below follows the standard split behavior where the delimiter is not included.
|
|
24999
|
+
lastIndex = match.index + match[0].length;
|
|
25000
|
+
matchCount++;
|
|
25001
|
+
// Avoid infinite loop for zero-length matches
|
|
25002
|
+
if (match.index === globalDelimiter.lastIndex) {
|
|
25003
|
+
globalDelimiter.lastIndex++;
|
|
25004
|
+
}
|
|
25005
|
+
}
|
|
25006
|
+
// Add the final part
|
|
25007
|
+
parts.push(remainingText.substring(lastIndex));
|
|
25008
|
+
} else {
|
|
25009
|
+
// Handle string delimiter
|
|
25010
|
+
const delimLength = delimiter.length;
|
|
25011
|
+
if (delimLength === 0) {
|
|
25012
|
+
// If delimiter is an empty string, split by characters
|
|
25013
|
+
// This is consistent with JS String.split('')
|
|
25014
|
+
return text.split('').slice(0, limit);
|
|
25015
|
+
}
|
|
25016
|
+
let index;
|
|
25017
|
+
while (count < limit - 1 && (index = remainingText.indexOf(delimiter)) !== -1) {
|
|
25018
|
+
parts.push(remainingText.substring(0, index));
|
|
25019
|
+
remainingText = remainingText.substring(index + delimLength);
|
|
25020
|
+
count++;
|
|
25021
|
+
}
|
|
25022
|
+
// Add the final part (the rest of the string)
|
|
25023
|
+
parts.push(remainingText);
|
|
25024
|
+
}
|
|
25025
|
+
|
|
25026
|
+
return parts;
|
|
25027
|
+
}
|
|
25028
|
+
|
|
25029
|
+
/**
|
|
25030
|
+
* Capitalizes the first character of a string.
|
|
25031
|
+
*
|
|
25032
|
+
* @param {string} text - The string to capitalize.
|
|
25033
|
+
* @returns {string} The string with its first character capitalized.
|
|
25034
|
+
*/
|
|
25035
|
+
function capitalize$1(text) {
|
|
25036
|
+
if (!text || typeof text !== 'string') {
|
|
25037
|
+
return text;
|
|
25038
|
+
}
|
|
25039
|
+
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
25040
|
+
}
|
|
25041
|
+
|
|
25042
|
+
/**
|
|
25043
|
+
* Converts a string to title case (capitalizing the first letter of each word).
|
|
25044
|
+
* Words are sequences of characters separated by space, tab, or newline.
|
|
25045
|
+
*
|
|
25046
|
+
* @param {string} text - The string to convert.
|
|
25047
|
+
* @returns {string} The string in title case.
|
|
25048
|
+
*/
|
|
25049
|
+
function titleCase$1(text) {
|
|
25050
|
+
if (!text || typeof text !== 'string') {
|
|
25051
|
+
return text;
|
|
25052
|
+
}
|
|
25053
|
+
// Split by one or more whitespace characters
|
|
25054
|
+
return text.split(/\s+/).map(word => capitalize$1(word)).join(' ');
|
|
25055
|
+
}
|
|
25056
|
+
|
|
25057
|
+
/**
|
|
25058
|
+
* Converts a string to camelCase.
|
|
25059
|
+
*
|
|
25060
|
+
* @param {string} text - The string to convert.
|
|
25061
|
+
* @returns {string} The string in camelCase.
|
|
25062
|
+
*/
|
|
25063
|
+
function camelCase$1(text) {
|
|
25064
|
+
if (!text || typeof text !== 'string') {
|
|
25065
|
+
return text;
|
|
25066
|
+
}
|
|
25067
|
+
return text
|
|
25068
|
+
.split(/\W+/) // Split on non-word characters
|
|
25069
|
+
.map((word, index) => {
|
|
25070
|
+
if (index === 0) {
|
|
25071
|
+
// First word is lowercase
|
|
25072
|
+
return word.toLowerCase();
|
|
25073
|
+
}
|
|
25074
|
+
// Subsequent words have their first letter capitalized
|
|
25075
|
+
return capitalize$1(word.toLowerCase());
|
|
25076
|
+
})
|
|
25077
|
+
.join('');
|
|
25078
|
+
}
|
|
25079
|
+
|
|
25080
|
+
/**
|
|
25081
|
+
* Converts a string to PascalCase.
|
|
25082
|
+
*
|
|
25083
|
+
* @param {string} text - The string to convert.
|
|
25084
|
+
* @returns {string} The string in PascalCase.
|
|
25085
|
+
*/
|
|
25086
|
+
function pascalCase$1(text) {
|
|
25087
|
+
if (!text || typeof text !== 'string') {
|
|
25088
|
+
return text;
|
|
25089
|
+
}
|
|
25090
|
+
return text
|
|
25091
|
+
.split(/\W+/) // Split on non-word characters
|
|
25092
|
+
.map(word => capitalize$1(word.toLowerCase()))
|
|
25093
|
+
.join('');
|
|
25094
|
+
}
|
|
25095
|
+
|
|
25096
|
+
/**
|
|
25097
|
+
* Converts a string to kebab-case.
|
|
25098
|
+
*
|
|
25099
|
+
* @param {string} text - The string to convert.
|
|
25100
|
+
* @returns {string} The string in kebab-case.
|
|
25101
|
+
*/
|
|
25102
|
+
function kebabCase$1(text) {
|
|
25103
|
+
if (!text || typeof text !== 'string') {
|
|
25104
|
+
return text;
|
|
25105
|
+
}
|
|
25106
|
+
return text
|
|
25107
|
+
.split(/\W+/) // Split on non-word characters
|
|
25108
|
+
.map(word => word.toLowerCase())
|
|
25109
|
+
.filter(word => word.length > 0) // Remove empty strings from split
|
|
25110
|
+
.join('-');
|
|
25111
|
+
}
|
|
25112
|
+
|
|
25113
|
+
/**
|
|
25114
|
+
* Converts a string to snake_case.
|
|
25115
|
+
*
|
|
25116
|
+
* @param {string} text - The string to convert.
|
|
25117
|
+
* @returns {string} The string in snake_case.
|
|
25118
|
+
*/
|
|
25119
|
+
function snakeCase$1(text) {
|
|
25120
|
+
if (!text || typeof text !== 'string') {
|
|
25121
|
+
return text;
|
|
25122
|
+
}
|
|
25123
|
+
return text
|
|
25124
|
+
.split(/\W+/) // Split on non-word characters
|
|
25125
|
+
.map(word => word.toLowerCase())
|
|
25126
|
+
.filter(word => word.length > 0) // Remove empty strings from split
|
|
25127
|
+
.join('_');
|
|
25128
|
+
}
|
|
25129
|
+
|
|
25130
|
+
/**
|
|
25131
|
+
* Converts a string to CONSTANT_CASE.
|
|
25132
|
+
*
|
|
25133
|
+
* @param {string} text - The string to convert.
|
|
25134
|
+
* @returns {string} The string in CONSTANT_CASE.
|
|
25135
|
+
*/
|
|
25136
|
+
function constantCase$1(text) {
|
|
25137
|
+
if (!text || typeof text !== 'string') {
|
|
25138
|
+
return text;
|
|
25139
|
+
}
|
|
25140
|
+
return text
|
|
25141
|
+
.split(/\W+/) // Split on non-word characters
|
|
25142
|
+
.map(word => word.toUpperCase())
|
|
25143
|
+
.filter(word => word.length > 0) // Remove empty strings from split
|
|
25144
|
+
.join('_');
|
|
25145
|
+
}
|
|
25146
|
+
|
|
25147
|
+
/**
|
|
25148
|
+
* Trims leading and trailing whitespace and normalizes internal whitespace
|
|
25149
|
+
* (replacing sequences of whitespace characters with a single space).
|
|
25150
|
+
*
|
|
25151
|
+
* @param {string} text - The string to trim and normalize.
|
|
25152
|
+
* @returns {string} The trimmed and normalized string.
|
|
25153
|
+
*/
|
|
25154
|
+
function trimWhitespace$1(text) {
|
|
25155
|
+
if (!text || typeof text !== 'string') {
|
|
25156
|
+
return text;
|
|
25157
|
+
}
|
|
25158
|
+
return text.trim().replace(/\s+/g, ' ');
|
|
25159
|
+
}
|
|
25160
|
+
|
|
25161
|
+
/**
|
|
25162
|
+
* Truncates a string to a specified maximum length and appends a suffix if truncated.
|
|
25163
|
+
*
|
|
25164
|
+
* @param {string} text - The string to truncate.
|
|
25165
|
+
* @param {number} maxLength - The maximum length of the string.
|
|
25166
|
+
* @param {string} [suffix='...'] - The suffix to append if the string is truncated.
|
|
25167
|
+
* @returns {string} The truncated string with suffix, or the original string if not truncated.
|
|
25168
|
+
*/
|
|
25169
|
+
function truncate$1(text, maxLength, suffix = '...') {
|
|
25170
|
+
if (!text || typeof text !== 'string' || maxLength <= 0) {
|
|
25171
|
+
return '';
|
|
25172
|
+
}
|
|
25173
|
+
if (text.length <= maxLength) {
|
|
25174
|
+
return text;
|
|
25175
|
+
}
|
|
25176
|
+
// Ensure we don't cut the suffix itself if maxLength is very small
|
|
25177
|
+
const suffixLength = suffix.length;
|
|
25178
|
+
if (maxLength <= suffixLength) {
|
|
25179
|
+
// If max length is less than or equal to suffix, return a truncated suffix
|
|
25180
|
+
// This is a bit of an edge case, but handles it gracefully.
|
|
25181
|
+
return suffix.substring(0, maxLength);
|
|
25182
|
+
}
|
|
25183
|
+
return text.substring(0, maxLength - suffixLength) + suffix;
|
|
25184
|
+
}
|
|
25185
|
+
|
|
25186
|
+
/**
|
|
25187
|
+
* Escapes HTML characters in a string to prevent them from being interpreted as HTML.
|
|
25188
|
+
*
|
|
25189
|
+
* @param {string} text - The string to escape.
|
|
25190
|
+
* @returns {string} The escaped string.
|
|
25191
|
+
*/
|
|
25192
|
+
function escapeHtml(text) {
|
|
25193
|
+
if (!text || typeof text !== 'string') {
|
|
25194
|
+
return text;
|
|
25195
|
+
}
|
|
25196
|
+
const htmlEscapes = {
|
|
25197
|
+
'&': '&',
|
|
25198
|
+
'<': '<',
|
|
25199
|
+
'>': '>',
|
|
25200
|
+
'"': '"',
|
|
25201
|
+
"'": ''',
|
|
25202
|
+
};
|
|
25203
|
+
return text.replace(/[&<>"']/g, match => htmlEscapes[match]);
|
|
25204
|
+
}
|
|
25205
|
+
|
|
25206
|
+
/**
|
|
25207
|
+
* Removes HTML tags from a string.
|
|
25208
|
+
*
|
|
25209
|
+
* @param {string} text - The string to strip tags from.
|
|
25210
|
+
* @returns {string} The string without HTML tags.
|
|
25211
|
+
*/
|
|
25212
|
+
function stripHtml(text) {
|
|
25213
|
+
if (!text || typeof text !== 'string') {
|
|
25214
|
+
return text;
|
|
25215
|
+
}
|
|
25216
|
+
return text.replace(/<[^>]*>/g, '');
|
|
25217
|
+
}
|
|
25218
|
+
|
|
25219
|
+
/**
|
|
25220
|
+
* Performs a basic check to see if a string looks like a valid email address.
|
|
25221
|
+
* This is a simple validation and should not be used for robust security checks.
|
|
25222
|
+
*
|
|
25223
|
+
* @param {string} email - The email string to validate.
|
|
25224
|
+
* @returns {boolean} True if the string looks like a valid email, false otherwise.
|
|
25225
|
+
*/
|
|
25226
|
+
function isValidEmail(email) {
|
|
25227
|
+
if (!email || typeof email !== 'string') {
|
|
25228
|
+
return false;
|
|
25229
|
+
}
|
|
25230
|
+
// A basic regex for email validation. Note: Fully validating email addresses
|
|
25231
|
+
// is extremely complex. This covers common cases.
|
|
25232
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
25233
|
+
return emailRegex.test(email);
|
|
25234
|
+
}
|
|
25235
|
+
|
|
25236
|
+
|
|
25237
|
+
var stringUtils = {
|
|
25238
|
+
splitWithLimit: splitWithLimit$1,
|
|
25239
|
+
capitalize: capitalize$1,
|
|
25240
|
+
titleCase: titleCase$1,
|
|
25241
|
+
camelCase: camelCase$1,
|
|
25242
|
+
kebabCase: kebabCase$1,
|
|
25243
|
+
snakeCase: snakeCase$1,
|
|
25244
|
+
constantCase: constantCase$1,
|
|
25245
|
+
pascalCase: pascalCase$1,
|
|
25246
|
+
trimWhitespace: trimWhitespace$1,
|
|
25247
|
+
truncate: truncate$1,
|
|
25248
|
+
escapeHtml,
|
|
25249
|
+
stripHtml,
|
|
25250
|
+
isValidEmail,
|
|
25251
|
+
};
|
|
25252
|
+
|
|
25253
|
+
/*
|
|
25254
|
+
* Component: Language Name Utils
|
|
25255
|
+
* Block-UUID: 313abeab-2bb3-49d1-8693-e9e88aa97113
|
|
25256
|
+
* Parent-UUID: N/A
|
|
25257
|
+
* Version: 1.0.0
|
|
25258
|
+
* Description: Utility for converting common lowercase language names and aliases to their proper capitalization
|
|
25259
|
+
* Language: JavaScript
|
|
25260
|
+
* Created-at: 2025-10-19T23:25:09.231Z
|
|
25261
|
+
* Authors: Qwen 3 Coder 480B - Cerebras (v1.0.0)
|
|
25262
|
+
*/
|
|
25263
|
+
|
|
25264
|
+
/**
|
|
25265
|
+
* A mapping of language aliases to their properly capitalized names
|
|
25266
|
+
*/
|
|
25267
|
+
const LANGUAGE_NAME_MAP = {
|
|
25268
|
+
// Core Programming Languages
|
|
25269
|
+
'javascript': 'JavaScript',
|
|
25270
|
+
'js': 'JavaScript',
|
|
25271
|
+
'typescript': 'TypeScript',
|
|
25272
|
+
'ts': 'TypeScript',
|
|
25273
|
+
'python': 'Python',
|
|
25274
|
+
'py': 'Python',
|
|
25275
|
+
'java': 'Java',
|
|
25276
|
+
'c': 'C',
|
|
25277
|
+
'c++': 'C++',
|
|
24110
25278
|
'cpp': 'C++',
|
|
24111
25279
|
'c#': 'C#',
|
|
24112
25280
|
'csharp': 'C#',
|
|
@@ -24253,19 +25421,670 @@ var LanguageNameUtils$1 = {
|
|
|
24253
25421
|
getLanguageNameMap
|
|
24254
25422
|
};
|
|
24255
25423
|
|
|
25424
|
+
/**
|
|
25425
|
+
* Component: MetaRawResultUtils
|
|
25426
|
+
* Block-UUID: 8a4d235b-a9d3-44b8-9c08-47b3678ba1c0
|
|
25427
|
+
* Parent-UUID: N/A
|
|
25428
|
+
* Version: 1.0.0
|
|
25429
|
+
* Description: Utility for parsing and extracting mappings from meta-raw-result messages
|
|
25430
|
+
* Language: JavaScript
|
|
25431
|
+
* Created-at: 2025-11-15T19:15:00.000Z
|
|
25432
|
+
* Authors: GLM-4.6 (v1.0.0)
|
|
25433
|
+
*/
|
|
25434
|
+
|
|
25435
|
+
const ChatUtils$1 = ChatUtils$2;
|
|
25436
|
+
|
|
25437
|
+
/**
|
|
25438
|
+
* Extracts and parses all meta-raw-result messages from a chat
|
|
25439
|
+
* @param {Object} chat - The chat object containing messages
|
|
25440
|
+
* @param {string} model - The model name (optional, for message filtering)
|
|
25441
|
+
* @returns {Map<number, Object>} Map of chatId to file metadata
|
|
25442
|
+
*/
|
|
25443
|
+
function extractMetaRawResultMappings$1(chat, model = null) {
|
|
25444
|
+
const mappings = new Map();
|
|
25445
|
+
|
|
25446
|
+
try {
|
|
25447
|
+
// Get all messages from the chat
|
|
25448
|
+
const allMessages = ChatUtils$1.getChatMessages(chat, model);
|
|
25449
|
+
|
|
25450
|
+
// Filter for meta-raw-result messages
|
|
25451
|
+
const metaRawMessages = allMessages.filter(msg => isMetaRawResultMessage$1(msg));
|
|
25452
|
+
|
|
25453
|
+
// Parse each meta-raw-result message
|
|
25454
|
+
for (const message of metaRawMessages) {
|
|
25455
|
+
const messageMappings = parseMetaRawResultContent$1(message.message);
|
|
25456
|
+
|
|
25457
|
+
// Merge mappings into the main map
|
|
25458
|
+
for (const [chatId, fileInfo] of messageMappings) {
|
|
25459
|
+
mappings.set(chatId, fileInfo);
|
|
25460
|
+
}
|
|
25461
|
+
}
|
|
25462
|
+
|
|
25463
|
+
return mappings;
|
|
25464
|
+
} catch (error) {
|
|
25465
|
+
console.error('Error extracting meta-raw-result mappings:', error);
|
|
25466
|
+
return mappings;
|
|
25467
|
+
}
|
|
25468
|
+
}
|
|
25469
|
+
|
|
25470
|
+
/**
|
|
25471
|
+
* Validates if a message is a meta-raw-result message
|
|
25472
|
+
* @param {Object} message - The message object to validate
|
|
25473
|
+
* @returns {boolean} True if message is meta-raw-result type
|
|
25474
|
+
*/
|
|
25475
|
+
function isMetaRawResultMessage$1(message) {
|
|
25476
|
+
if (!message || !message.message) {
|
|
25477
|
+
return false;
|
|
25478
|
+
}
|
|
25479
|
+
|
|
25480
|
+
// Check if message type is meta-raw-result
|
|
25481
|
+
if (message.type === 'meta-raw-result') {
|
|
25482
|
+
return true;
|
|
25483
|
+
}
|
|
25484
|
+
|
|
25485
|
+
return false;
|
|
25486
|
+
}
|
|
25487
|
+
|
|
25488
|
+
/**
|
|
25489
|
+
* Parses a single meta-raw-result message content
|
|
25490
|
+
* @param {string} messageContent - The message content to parse
|
|
25491
|
+
* @returns {Map<number, Object>} Map of chatId to file metadata
|
|
25492
|
+
*/
|
|
25493
|
+
function parseMetaRawResultContent$1(messageContent) {
|
|
25494
|
+
const mappings = new Map();
|
|
25495
|
+
|
|
25496
|
+
try {
|
|
25497
|
+
// Split content into lines
|
|
25498
|
+
const lines = messageContent.split('\n');
|
|
25499
|
+
|
|
25500
|
+
// Find the data section
|
|
25501
|
+
let dataSectionStart = -1;
|
|
25502
|
+
for (let i = 0; i < lines.length; i++) {
|
|
25503
|
+
if (lines[i].trimStart().startsWith('## Data ')) {
|
|
25504
|
+
dataSectionStart = i;
|
|
25505
|
+
break;
|
|
25506
|
+
}
|
|
25507
|
+
}
|
|
25508
|
+
|
|
25509
|
+
if (dataSectionStart === -1) {
|
|
25510
|
+
return mappings; // No data section found
|
|
25511
|
+
}
|
|
25512
|
+
|
|
25513
|
+
// Find the table header (line with |)
|
|
25514
|
+
let headerLine = -1;
|
|
25515
|
+
for (let i = dataSectionStart; i < lines.length; i++) {
|
|
25516
|
+
if (lines[i].includes('|') && lines[i].includes('Chat ID')) {
|
|
25517
|
+
headerLine = i;
|
|
25518
|
+
break;
|
|
25519
|
+
}
|
|
25520
|
+
}
|
|
25521
|
+
|
|
25522
|
+
if (headerLine === -1) {
|
|
25523
|
+
return mappings; // No table header found
|
|
25524
|
+
}
|
|
25525
|
+
|
|
25526
|
+
// Find the separator line (|---|---|...)
|
|
25527
|
+
let separatorLine = -1;
|
|
25528
|
+
for (let i = headerLine + 1; i < lines.length; i++) {
|
|
25529
|
+
if (lines[i].match(/^\|[\s\-\|]*\|$/)) {
|
|
25530
|
+
separatorLine = i;
|
|
25531
|
+
break;
|
|
25532
|
+
}
|
|
25533
|
+
}
|
|
25534
|
+
|
|
25535
|
+
if (separatorLine === -1) {
|
|
25536
|
+
return mappings; // No separator found
|
|
25537
|
+
}
|
|
25538
|
+
|
|
25539
|
+
// Parse data rows (everything after the separator)
|
|
25540
|
+
for (let i = separatorLine + 1; i < lines.length; i++) {
|
|
25541
|
+
const line = lines[i].trim();
|
|
25542
|
+
|
|
25543
|
+
// Skip empty lines or separator lines
|
|
25544
|
+
if (!line || line.match(/^\|[\s\-\|]*\|$/) || !line.includes('|')) {
|
|
25545
|
+
continue;
|
|
25546
|
+
}
|
|
25547
|
+
|
|
25548
|
+
// Parse the table row
|
|
25549
|
+
const fileInfo = parseTableRow$1(line);
|
|
25550
|
+
if (fileInfo && fileInfo.id) {
|
|
25551
|
+
mappings.set(fileInfo.id, fileInfo);
|
|
25552
|
+
}
|
|
25553
|
+
}
|
|
25554
|
+
|
|
25555
|
+
return mappings;
|
|
25556
|
+
} catch (error) {
|
|
25557
|
+
console.error('Error parsing meta-raw-result content:', error);
|
|
25558
|
+
return mappings;
|
|
25559
|
+
}
|
|
25560
|
+
}
|
|
25561
|
+
|
|
25562
|
+
/**
|
|
25563
|
+
* Parses a single table row from meta-raw-result content
|
|
25564
|
+
* @param {string} rowLine - The table row line to parse
|
|
25565
|
+
* @returns {Object|null} Parsed file information object or null if parsing failed
|
|
25566
|
+
*/
|
|
25567
|
+
function parseTableRow$1(rowLine) {
|
|
25568
|
+
try {
|
|
25569
|
+
// Split the row by | and clean up
|
|
25570
|
+
const cells = rowLine.split('|').map(cell => cell.trim()).filter(cell => cell);
|
|
25571
|
+
|
|
25572
|
+
if (cells.length < 6) {
|
|
25573
|
+
return null; // Not enough columns
|
|
25574
|
+
}
|
|
25575
|
+
|
|
25576
|
+
// Extract basic information from the table cells
|
|
25577
|
+
const repo = cells[0];
|
|
25578
|
+
const branch = cells[1];
|
|
25579
|
+
const filePath = cells[2];
|
|
25580
|
+
const language = cells[3];
|
|
25581
|
+
const chatId = parseInt(cells[4], 10);
|
|
25582
|
+
|
|
25583
|
+
// Parse file path to extract name and path
|
|
25584
|
+
const pathParts = filePath.split('/');
|
|
25585
|
+
const name = pathParts[pathParts.length - 1];
|
|
25586
|
+
const path = filePath;
|
|
25587
|
+
|
|
25588
|
+
// Create full path
|
|
25589
|
+
const fullPath = `${repo}/${path}`;
|
|
25590
|
+
|
|
25591
|
+
return {
|
|
25592
|
+
id: chatId,
|
|
25593
|
+
name: name,
|
|
25594
|
+
path: path,
|
|
25595
|
+
repo: repo,
|
|
25596
|
+
branch: branch,
|
|
25597
|
+
language: language,
|
|
25598
|
+
fullPath: fullPath
|
|
25599
|
+
};
|
|
25600
|
+
} catch (error) {
|
|
25601
|
+
console.error('Error parsing table row:', error);
|
|
25602
|
+
return null;
|
|
25603
|
+
}
|
|
25604
|
+
}
|
|
25605
|
+
|
|
25606
|
+
/**
|
|
25607
|
+
* Parses size string to bytes
|
|
25608
|
+
* @param {string} sizeStr - Size string (e.g., "1.2 KB", "500 B")
|
|
25609
|
+
* @returns {number} Size in bytes
|
|
25610
|
+
*/
|
|
25611
|
+
function parseSize$1(sizeStr) {
|
|
25612
|
+
if (!sizeStr || sizeStr === 'N/A') {
|
|
25613
|
+
return 0;
|
|
25614
|
+
}
|
|
25615
|
+
|
|
25616
|
+
const match = sizeStr.match(/^([\d.]+)\s*(B|KB|MB|GB)?$/i);
|
|
25617
|
+
if (!match) {
|
|
25618
|
+
return 0;
|
|
25619
|
+
}
|
|
25620
|
+
|
|
25621
|
+
const value = parseFloat(match[1]);
|
|
25622
|
+
const unit = (match[2] || 'B').toUpperCase();
|
|
25623
|
+
|
|
25624
|
+
switch (unit) {
|
|
25625
|
+
case 'B': return Math.round(value);
|
|
25626
|
+
case 'KB': return Math.round(value * 1024);
|
|
25627
|
+
case 'MB': return Math.round(value * 1024 * 1024);
|
|
25628
|
+
case 'GB': return Math.round(value * 1024 * 1024 * 1024);
|
|
25629
|
+
default: return 0;
|
|
25630
|
+
}
|
|
25631
|
+
}
|
|
25632
|
+
|
|
25633
|
+
/**
|
|
25634
|
+
* Parses tokens string to number
|
|
25635
|
+
* @param {string} tokensStr - Tokens string (e.g., "1.2k", "500")
|
|
25636
|
+
* @returns {number} Token count
|
|
25637
|
+
*/
|
|
25638
|
+
function parseTokens$1(tokensStr) {
|
|
25639
|
+
if (!tokensStr || tokensStr === 'N/A') {
|
|
25640
|
+
return 0;
|
|
25641
|
+
}
|
|
25642
|
+
|
|
25643
|
+
const match = tokensStr.match(/^([\d.]+)(k|m|b)?$/i);
|
|
25644
|
+
if (!match) {
|
|
25645
|
+
return 0;
|
|
25646
|
+
}
|
|
25647
|
+
|
|
25648
|
+
const value = parseFloat(match[1]);
|
|
25649
|
+
const suffix = (match[2] || '').toLowerCase();
|
|
25650
|
+
|
|
25651
|
+
switch (suffix) {
|
|
25652
|
+
case 'k': return Math.round(value * 1000);
|
|
25653
|
+
case 'm': return Math.round(value * 1000000);
|
|
25654
|
+
case 'b': return Math.round(value * 1000000000);
|
|
25655
|
+
default: return Math.round(value);
|
|
25656
|
+
}
|
|
25657
|
+
}
|
|
25658
|
+
|
|
25659
|
+
var MetaRawResultUtils$1 = {
|
|
25660
|
+
extractMetaRawResultMappings: extractMetaRawResultMappings$1,
|
|
25661
|
+
isMetaRawResultMessage: isMetaRawResultMessage$1,
|
|
25662
|
+
parseMetaRawResultContent: parseMetaRawResultContent$1,
|
|
25663
|
+
parseTableRow: parseTableRow$1,
|
|
25664
|
+
parseSize: parseSize$1,
|
|
25665
|
+
parseTokens: parseTokens$1
|
|
25666
|
+
};
|
|
25667
|
+
|
|
25668
|
+
/**
|
|
25669
|
+
* Component: ReferenceMessageUtils
|
|
25670
|
+
* Block-UUID: 2870551a-4311-4d64-9491-c9cc62f276e8
|
|
25671
|
+
* Parent-UUID: N/A
|
|
25672
|
+
* Description: Utility for parsing reference messages in the compact message workflow, extracting session data, metadata, and message sections.
|
|
25673
|
+
* Language: JavaScript
|
|
25674
|
+
* Created-at: 2025-12-07T00:08:42.573Z
|
|
25675
|
+
* Authors: GLM-4.6 (v1.0.0)
|
|
25676
|
+
*/
|
|
25677
|
+
|
|
25678
|
+
let ReferenceMessageUtils$1 = class ReferenceMessageUtils {
|
|
25679
|
+
/**
|
|
25680
|
+
* Extracts all data from a reference message including session data, metadata, and message sections
|
|
25681
|
+
* @param {string} referenceMessage - The reference message content to parse
|
|
25682
|
+
* @returns {Object} Parsed data with messages to compact and keep, metadata, and session information
|
|
25683
|
+
*/
|
|
25684
|
+
static extractReferenceMessageData(referenceMessage) {
|
|
25685
|
+
if (!referenceMessage) {
|
|
25686
|
+
return {
|
|
25687
|
+
messagesToCompact: [],
|
|
25688
|
+
messagesToKeep: [],
|
|
25689
|
+
originalChatUuid: null,
|
|
25690
|
+
validationHash: null,
|
|
25691
|
+
sessionId: null,
|
|
25692
|
+
range: null,
|
|
25693
|
+
from: null,
|
|
25694
|
+
to: null
|
|
25695
|
+
};
|
|
25696
|
+
}
|
|
25697
|
+
|
|
25698
|
+
// Extract Original Chat UUID
|
|
25699
|
+
const originalChatUuidMatch = referenceMessage.match(/Original Chat UUID:\s*([a-f0-9-]+)/i);
|
|
25700
|
+
const originalChatUuid = originalChatUuidMatch ? originalChatUuidMatch[1] : null;
|
|
25701
|
+
|
|
25702
|
+
// Extract Validation Hash
|
|
25703
|
+
const validationHashMatch = referenceMessage.match(/Validation Hash:\s*([a-f0-9]+)/i);
|
|
25704
|
+
const validationHash = validationHashMatch ? validationHashMatch[1] : null;
|
|
25705
|
+
|
|
25706
|
+
// Extract Session ID
|
|
25707
|
+
const sessionIdMatch = referenceMessage.match(/Session ID:\s*(\d+)/i);
|
|
25708
|
+
const sessionId = sessionIdMatch ? sessionIdMatch[1] : null;
|
|
25709
|
+
|
|
25710
|
+
// Extract Range
|
|
25711
|
+
const rangeMatch = referenceMessage.match(/Range:\s*(\d+-\d+)/i);
|
|
25712
|
+
const range = rangeMatch ? rangeMatch[1] : null;
|
|
25713
|
+
|
|
25714
|
+
// Extract From and To values
|
|
25715
|
+
const fromMatch = referenceMessage.match(/From:\s*(\d+)/i);
|
|
25716
|
+
const from = fromMatch ? parseInt(fromMatch[1], 10) : null;
|
|
25717
|
+
|
|
25718
|
+
const toMatch = referenceMessage.match(/To:\s*(\d+)/i);
|
|
25719
|
+
const to = toMatch ? parseInt(toMatch[1], 10) : null;
|
|
25720
|
+
|
|
25721
|
+
// If range is not found but from and to are available, construct the range
|
|
25722
|
+
if (!range && from !== null && to !== null) {
|
|
25723
|
+
range = `${from}-${to}`;
|
|
25724
|
+
}
|
|
25725
|
+
|
|
25726
|
+
// Extract Messages to Compact section
|
|
25727
|
+
const compactSectionMatch = referenceMessage.match(/# Messages to Compact\n([\s\S]*?)(?=\n# |\n$|$)/);
|
|
25728
|
+
const compactSection = compactSectionMatch ? compactSectionMatch[1] : '';
|
|
25729
|
+
|
|
25730
|
+
// Extract Messages to Keep section
|
|
25731
|
+
const keepSectionMatch = referenceMessage.match(/# Messages to Keep \(Context\)\n([\s\S]*?)(?=\n# |\n$|$)/);
|
|
25732
|
+
const keepSection = keepSectionMatch ? keepSectionMatch[1] : '';
|
|
25733
|
+
|
|
25734
|
+
// Parse messages from each section
|
|
25735
|
+
const messagesToCompact = this.parseMessageSection(compactSection);
|
|
25736
|
+
const messagesToKeep = this.parseMessageSection(keepSection);
|
|
25737
|
+
|
|
25738
|
+
return {
|
|
25739
|
+
messagesToCompact,
|
|
25740
|
+
messagesToKeep,
|
|
25741
|
+
originalChatUuid,
|
|
25742
|
+
validationHash,
|
|
25743
|
+
sessionId,
|
|
25744
|
+
range,
|
|
25745
|
+
from,
|
|
25746
|
+
to
|
|
25747
|
+
};
|
|
25748
|
+
}
|
|
25749
|
+
|
|
25750
|
+
/**
|
|
25751
|
+
* Parses a message section to extract individual messages
|
|
25752
|
+
* @param {string} section - The section content to parse
|
|
25753
|
+
* @returns {Array} Array of parsed message objects
|
|
25754
|
+
*/
|
|
25755
|
+
static parseMessageSection(section) {
|
|
25756
|
+
if (!section) return [];
|
|
25757
|
+
|
|
25758
|
+
const messages = [];
|
|
25759
|
+
const messageRegex = /<(\w+) message number (\d+)>\n([\s\S]*?)\n<\/\1 message number \2>/g;
|
|
25760
|
+
let match;
|
|
25761
|
+
|
|
25762
|
+
while ((match = messageRegex.exec(section)) !== null) {
|
|
25763
|
+
const [, role, positionStr, content] = match;
|
|
25764
|
+
const position = parseInt(positionStr, 10);
|
|
25765
|
+
|
|
25766
|
+
messages.push({
|
|
25767
|
+
role,
|
|
25768
|
+
position,
|
|
25769
|
+
content: content.trim()
|
|
25770
|
+
});
|
|
25771
|
+
}
|
|
25772
|
+
|
|
25773
|
+
return messages;
|
|
25774
|
+
}
|
|
25775
|
+
|
|
25776
|
+
/**
|
|
25777
|
+
* Extracts just the metadata from a reference message without the message sections
|
|
25778
|
+
* @param {string} referenceMessage - The reference message content to parse
|
|
25779
|
+
* @returns {Object} Metadata object with original chat UUID, validation hash, session ID, and range information
|
|
25780
|
+
*/
|
|
25781
|
+
static extractReferenceMessageMetadata(referenceMessage) {
|
|
25782
|
+
const data = this.extractReferenceMessageData(referenceMessage);
|
|
25783
|
+
|
|
25784
|
+
return {
|
|
25785
|
+
originalChatUuid: data.originalChatUuid,
|
|
25786
|
+
validationHash: data.validationHash,
|
|
25787
|
+
sessionId: data.sessionId,
|
|
25788
|
+
range: data.range,
|
|
25789
|
+
from: data.from,
|
|
25790
|
+
to: data.to
|
|
25791
|
+
};
|
|
25792
|
+
}
|
|
25793
|
+
|
|
25794
|
+
/**
|
|
25795
|
+
* Checks if a message is a reference message
|
|
25796
|
+
* @param {string} message - The message content to check
|
|
25797
|
+
* @returns {boolean} True if the message is a reference message
|
|
25798
|
+
*/
|
|
25799
|
+
static isReferenceMessage(message) {
|
|
25800
|
+
if (!message) return false;
|
|
25801
|
+
|
|
25802
|
+
// Check for key indicators of a reference message
|
|
25803
|
+
return message.includes('# Compact Messages Reference') &&
|
|
25804
|
+
message.includes('Original Chat UUID:') &&
|
|
25805
|
+
message.includes('Session ID:');
|
|
25806
|
+
}
|
|
25807
|
+
};
|
|
25808
|
+
|
|
25809
|
+
var ReferenceMessageUtils_1 = { ReferenceMessageUtils: ReferenceMessageUtils$1 };
|
|
25810
|
+
|
|
25811
|
+
/**
|
|
25812
|
+
* Component: CompactedMessageUtils
|
|
25813
|
+
* Block-UUID: b4111118-ec11-49d6-9a6e-402ca0b6df5b
|
|
25814
|
+
* Parent-UUID: N/A
|
|
25815
|
+
* Version: 1.0.1
|
|
25816
|
+
* Description: Utility for formatting, parsing, and validating compacted messages with standardized metadata headers.
|
|
25817
|
+
* Language: JavaScript
|
|
25818
|
+
* Created-at: 2025-12-07T00:09:15.842Z
|
|
25819
|
+
* Authors: GLM-4.6 (v1.0.0), GLM-4.6 (v1.0.1)
|
|
25820
|
+
*/
|
|
25821
|
+
|
|
25822
|
+
let CompactedMessageUtils$1 = class CompactedMessageUtils {
|
|
25823
|
+
/**
|
|
25824
|
+
* Formats a compacted message with standardized metadata headers
|
|
25825
|
+
* @param {string} content - The compacted message content
|
|
25826
|
+
* @param {string} originalChatUuid - UUID of the original chat
|
|
25827
|
+
* @param {string} messageRange - Message range that was compacted (e.g., "3-6")
|
|
25828
|
+
* @param {Object} options - Additional options
|
|
25829
|
+
* @param {Date} options.compactedAt - Custom timestamp for when the message was compacted
|
|
25830
|
+
* @returns {string} Formatted compacted message with metadata
|
|
25831
|
+
*/
|
|
25832
|
+
static formatCompactedMessage(content, originalChatUuid, messageRange, options = {}) {
|
|
25833
|
+
if (!content) {
|
|
25834
|
+
throw new Error('Content is required for formatting a compacted message');
|
|
25835
|
+
}
|
|
25836
|
+
|
|
25837
|
+
if (!originalChatUuid) {
|
|
25838
|
+
throw new Error('Original chat UUID is required for formatting a compacted message');
|
|
25839
|
+
}
|
|
25840
|
+
|
|
25841
|
+
if (!messageRange) {
|
|
25842
|
+
throw new Error('Message range is required for formatting a compacted message');
|
|
25843
|
+
}
|
|
25844
|
+
|
|
25845
|
+
// Use provided timestamp or generate current one
|
|
25846
|
+
const compactedAt = options.compactedAt || new Date().toISOString();
|
|
25847
|
+
|
|
25848
|
+
return `## Compacted Message
|
|
25849
|
+
|
|
25850
|
+
- **Original Chat:** [${originalChatUuid}](/?chat=${originalChatUuid})
|
|
25851
|
+
- **Message Range:** ${messageRange}
|
|
25852
|
+
- **Compacted At:** ${compactedAt}
|
|
25853
|
+
|
|
25854
|
+
${content}`;
|
|
25855
|
+
}
|
|
25856
|
+
|
|
25857
|
+
/**
|
|
25858
|
+
* Extracts metadata from a compacted message
|
|
25859
|
+
* @param {string} compactedMessage - The compacted message to parse
|
|
25860
|
+
* @returns {Object|null} Metadata object or null if format is invalid
|
|
25861
|
+
*/
|
|
25862
|
+
static extractCompactedMessageMetadata(compactedMessage) {
|
|
25863
|
+
if (!this.isCompactedMessage(compactedMessage)) {
|
|
25864
|
+
return null;
|
|
25865
|
+
}
|
|
25866
|
+
|
|
25867
|
+
// Extract Original Chat UUID
|
|
25868
|
+
const originalChatMatch = compactedMessage.match(/\*\*Original Chat:\*\*\s*([a-f0-9-]+)/i);
|
|
25869
|
+
const originalChatUuid = originalChatMatch ? originalChatMatch[1] : null;
|
|
25870
|
+
|
|
25871
|
+
// Extract Message Range
|
|
25872
|
+
const rangeMatch = compactedMessage.match(/\*\*Message Range:\*\*\s*(\d+-\d+)/i);
|
|
25873
|
+
const messageRange = rangeMatch ? rangeMatch[1] : null;
|
|
25874
|
+
|
|
25875
|
+
// Extract Compacted At timestamp
|
|
25876
|
+
const compactedAtMatch = compactedMessage.match(/\*\*Compacted At:\*\*\s*([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z)/i);
|
|
25877
|
+
const compactedAt = compactedAtMatch ? compactedAtMatch[1] : null;
|
|
25878
|
+
|
|
25879
|
+
return {
|
|
25880
|
+
originalChatUuid,
|
|
25881
|
+
messageRange,
|
|
25882
|
+
compactedAt
|
|
25883
|
+
};
|
|
25884
|
+
}
|
|
25885
|
+
|
|
25886
|
+
/**
|
|
25887
|
+
* Extracts just the content portion from a compacted message (without metadata)
|
|
25888
|
+
* @param {string} compactedMessage - The compacted message to parse
|
|
25889
|
+
* @returns {string|null} Content portion or null if format is invalid
|
|
25890
|
+
*/
|
|
25891
|
+
static extractCompactedMessageContent(compactedMessage) {
|
|
25892
|
+
if (!this.isCompactedMessage(compactedMessage)) {
|
|
25893
|
+
return null;
|
|
25894
|
+
}
|
|
25895
|
+
|
|
25896
|
+
// Find the start and end boundaries
|
|
25897
|
+
const startMarker = "## Compacted Message";
|
|
25898
|
+
const endMarker = "## End Compacted Message";
|
|
25899
|
+
|
|
25900
|
+
const startIndex = compactedMessage.indexOf(startMarker);
|
|
25901
|
+
const endIndex = compactedMessage.indexOf(endMarker);
|
|
25902
|
+
|
|
25903
|
+
// If start marker is not found, return null
|
|
25904
|
+
if (startIndex === -1) {
|
|
25905
|
+
return null;
|
|
25906
|
+
}
|
|
25907
|
+
|
|
25908
|
+
// If end marker is not found, extract everything after start marker
|
|
25909
|
+
if (endIndex === -1) {
|
|
25910
|
+
return compactedMessage.substring(startIndex + startMarker.length).trim();
|
|
25911
|
+
}
|
|
25912
|
+
|
|
25913
|
+
// Extract content between the markers
|
|
25914
|
+
const contentStart = startIndex + startMarker.length;
|
|
25915
|
+
return compactedMessage.substring(contentStart, endIndex).trim();
|
|
25916
|
+
}
|
|
25917
|
+
|
|
25918
|
+
/**
|
|
25919
|
+
* Validates that a compacted message follows the expected format
|
|
25920
|
+
* @param {string} compactedMessage - The compacted message to validate
|
|
25921
|
+
* @returns {Object} Validation result with isValid flag and any errors/warnings
|
|
25922
|
+
*/
|
|
25923
|
+
static validateCompactedMessageFormat(compactedMessage) {
|
|
25924
|
+
const result = {
|
|
25925
|
+
isValid: true,
|
|
25926
|
+
errors: [],
|
|
25927
|
+
warnings: []
|
|
25928
|
+
};
|
|
25929
|
+
|
|
25930
|
+
if (!compactedMessage) {
|
|
25931
|
+
result.isValid = false;
|
|
25932
|
+
result.errors.push('Compacted message is empty or null');
|
|
25933
|
+
return result;
|
|
25934
|
+
}
|
|
25935
|
+
|
|
25936
|
+
// Check for required header
|
|
25937
|
+
if (!compactedMessage.includes('## Compacted Message')) {
|
|
25938
|
+
result.isValid = false;
|
|
25939
|
+
result.errors.push('Missing required "## Compacted Message" header');
|
|
25940
|
+
}
|
|
25941
|
+
|
|
25942
|
+
// Check for required metadata fields
|
|
25943
|
+
const metadata = this.extractCompactedMessageMetadata(compactedMessage);
|
|
25944
|
+
|
|
25945
|
+
if (!metadata) {
|
|
25946
|
+
result.isValid = false;
|
|
25947
|
+
result.errors.push('Could not extract metadata from compacted message');
|
|
25948
|
+
return result;
|
|
25949
|
+
}
|
|
25950
|
+
|
|
25951
|
+
if (!metadata.originalChatUuid) {
|
|
25952
|
+
result.isValid = false;
|
|
25953
|
+
result.errors.push('Missing or invalid Original Chat UUID');
|
|
25954
|
+
}
|
|
25955
|
+
|
|
25956
|
+
if (!metadata.messageRange) {
|
|
25957
|
+
result.isValid = false;
|
|
25958
|
+
result.errors.push('Missing or invalid Message Range');
|
|
25959
|
+
}
|
|
25960
|
+
|
|
25961
|
+
if (!metadata.compactedAt) {
|
|
25962
|
+
result.warnings.push('Missing or invalid Compacted At timestamp');
|
|
25963
|
+
}
|
|
25964
|
+
|
|
25965
|
+
// Validate UUID format
|
|
25966
|
+
if (metadata.originalChatUuid && !this.isValidUUID(metadata.originalChatUuid)) {
|
|
25967
|
+
result.isValid = false;
|
|
25968
|
+
result.errors.push('Original Chat UUID is not in valid UUID format');
|
|
25969
|
+
}
|
|
25970
|
+
|
|
25971
|
+
// Validate message range format
|
|
25972
|
+
if (metadata.messageRange && !this.isValidMessageRange(metadata.messageRange)) {
|
|
25973
|
+
result.isValid = false;
|
|
25974
|
+
result.errors.push('Message Range is not in valid format (expected "X-Y")');
|
|
25975
|
+
}
|
|
25976
|
+
|
|
25977
|
+
// Validate timestamp format
|
|
25978
|
+
if (metadata.compactedAt && !this.isValidISOTimestamp(metadata.compactedAt)) {
|
|
25979
|
+
result.warnings.push('Compacted At timestamp is not in valid ISO 8601 format');
|
|
25980
|
+
}
|
|
25981
|
+
|
|
25982
|
+
return result;
|
|
25983
|
+
}
|
|
25984
|
+
|
|
25985
|
+
/**
|
|
25986
|
+
* Checks if a message is a compacted message
|
|
25987
|
+
* @param {string} message - The message content to check
|
|
25988
|
+
* @returns {boolean} True if the message is a compacted message
|
|
25989
|
+
*/
|
|
25990
|
+
static isCompactedMessage(message) {
|
|
25991
|
+
if (!message) return false;
|
|
25992
|
+
|
|
25993
|
+
// Check for the compacted message header
|
|
25994
|
+
return message.includes('## Compacted Message');
|
|
25995
|
+
}
|
|
25996
|
+
|
|
25997
|
+
/**
|
|
25998
|
+
* Validates if a string is a valid UUID v4
|
|
25999
|
+
* @param {string} uuid - The UUID string to validate
|
|
26000
|
+
* @returns {boolean} True if valid UUID v4
|
|
26001
|
+
*/
|
|
26002
|
+
static isValidUUID(uuid) {
|
|
26003
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
26004
|
+
return uuidRegex.test(uuid);
|
|
26005
|
+
}
|
|
26006
|
+
|
|
26007
|
+
/**
|
|
26008
|
+
* Validates if a string is a valid message range (e.g., "3-6")
|
|
26009
|
+
* @param {string} range - The range string to validate
|
|
26010
|
+
* @returns {boolean} True if valid range format
|
|
26011
|
+
*/
|
|
26012
|
+
static isValidMessageRange(range) {
|
|
26013
|
+
const rangeRegex = /^\d+-\d+$/;
|
|
26014
|
+
if (!rangeRegex.test(range)) return false;
|
|
26015
|
+
|
|
26016
|
+
const [from, to] = range.split('-').map(Number);
|
|
26017
|
+
return !isNaN(from) && !isNaN(to) && from <= to;
|
|
26018
|
+
}
|
|
26019
|
+
|
|
26020
|
+
/**
|
|
26021
|
+
* Validates if a string is a valid ISO 8601 timestamp
|
|
26022
|
+
* @param {string} timestamp - The timestamp string to validate
|
|
26023
|
+
* @returns {boolean} True if valid ISO 8601 timestamp
|
|
26024
|
+
*/
|
|
26025
|
+
static isValidISOTimestamp(timestamp) {
|
|
26026
|
+
if (!timestamp) return false;
|
|
26027
|
+
|
|
26028
|
+
const date = new Date(timestamp);
|
|
26029
|
+
return !isNaN(date.getTime()) && timestamp === date.toISOString();
|
|
26030
|
+
}
|
|
26031
|
+
};
|
|
26032
|
+
|
|
26033
|
+
var CompactedMessageUtils_1 = { CompactedMessageUtils: CompactedMessageUtils$1 };
|
|
26034
|
+
|
|
26035
|
+
/**
|
|
26036
|
+
* Component: CompactChatUtils Index
|
|
26037
|
+
* Block-UUID: cd0a6091-edb6-4e92-9439-63dd8f6a6796
|
|
26038
|
+
* Parent-UUID: 5ffa0338-b4fb-4968-908c-f23a26d4923b
|
|
26039
|
+
* Version: 2.0.0
|
|
26040
|
+
* Description: Entry point for CompactChatUtils that exports both ReferenceMessageUtils and CompactedMessageUtils methods directly for easier access.
|
|
26041
|
+
* Language: JavaScript
|
|
26042
|
+
* Created-at: 2025-12-07T00:10:05.123Z
|
|
26043
|
+
* Authors: GLM-4.6 (v1.0.0), GLM-4.6 (v2.0.0)
|
|
26044
|
+
*/
|
|
26045
|
+
|
|
26046
|
+
const { ReferenceMessageUtils } = ReferenceMessageUtils_1;
|
|
26047
|
+
const { CompactedMessageUtils } = CompactedMessageUtils_1;
|
|
26048
|
+
|
|
26049
|
+
/**
|
|
26050
|
+
* CompactChatUtils provides utilities for working with compacted messages in GitSense Chat.
|
|
26051
|
+
* It includes functionality for parsing reference messages and formatting/parsing compacted messages.
|
|
26052
|
+
*/
|
|
26053
|
+
var CompactChatUtils$1 = {
|
|
26054
|
+
// Export the classes for those who want to access them directly
|
|
26055
|
+
ReferenceMessageUtils,
|
|
26056
|
+
CompactedMessageUtils,
|
|
26057
|
+
|
|
26058
|
+
// Export all methods from ReferenceMessageUtils directly
|
|
26059
|
+
extractReferenceMessageData: ReferenceMessageUtils.extractReferenceMessageData,
|
|
26060
|
+
parseMessageSection: ReferenceMessageUtils.parseMessageSection,
|
|
26061
|
+
extractReferenceMessageMetadata: ReferenceMessageUtils.extractReferenceMessageMetadata,
|
|
26062
|
+
isReferenceMessage: ReferenceMessageUtils.isReferenceMessage,
|
|
26063
|
+
|
|
26064
|
+
// Export all methods from CompactedMessageUtils directly
|
|
26065
|
+
formatCompactedMessage: CompactedMessageUtils.formatCompactedMessage,
|
|
26066
|
+
extractCompactedMessageMetadata: CompactedMessageUtils.extractCompactedMessageMetadata,
|
|
26067
|
+
extractCompactedMessageContent: CompactedMessageUtils.extractCompactedMessageContent,
|
|
26068
|
+
validateCompactedMessageFormat: CompactedMessageUtils.validateCompactedMessageFormat,
|
|
26069
|
+
isCompactedMessage: CompactedMessageUtils.isCompactedMessage,
|
|
26070
|
+
isValidUUID: CompactedMessageUtils.isValidUUID,
|
|
26071
|
+
isValidMessageRange: CompactedMessageUtils.isValidMessageRange,
|
|
26072
|
+
isValidISOTimestamp: CompactedMessageUtils.isValidISOTimestamp
|
|
26073
|
+
};
|
|
26074
|
+
|
|
24256
26075
|
/*
|
|
24257
26076
|
* Component: GitSenseChatUtils
|
|
24258
|
-
* Block-UUID:
|
|
24259
|
-
* Parent-UUID:
|
|
24260
|
-
* Version: 2.
|
|
24261
|
-
* Description: Interface class for GitSense Chat utilities providing a unified API for code block parsing (markdown), extraction, and patch operations. Integrates functionalities from CodeBlockUtils and PatchUtils modules, and now includes ConfigUtils, EnvUtils, and
|
|
26077
|
+
* Block-UUID: c1b6c4d3-7959-4eb6-8022-6cd7aa59240d
|
|
26078
|
+
* Parent-UUID: 1793b3a8-4881-4306-bfdf-673eef503679
|
|
26079
|
+
* Version: 2.7.0
|
|
26080
|
+
* Description: Interface class for GitSense Chat utilities providing a unified API for code block parsing (markdown), extraction, and patch operations. Integrates functionalities from CodeBlockUtils and PatchUtils modules, and now includes ConfigUtils, EnvUtils, ObjectUtils, MetaRawResultUtils, and CompactChatUtils.
|
|
24262
26081
|
* Language: JavaScript
|
|
24263
26082
|
* Created-at: 2025-10-17T17:13:04.663Z
|
|
24264
|
-
* Authors: Claude 3.7 Sonnet (v1.0.0), Gemini 2.5 Pro (v2.0.0), Gemini 2.5 Pro (v2.1.0), Gemini 2.5 Pro (v2.1.1), Gemini 2.5 Flash (v2.1.2), Gemini 2.5 Flash (v2.1.3), Gemini 2.5 Flash (v2.1.4), Qwen 3 Coder 480B - Cerebras (v2.1.5), Qwen 3 Coder 480B - Cerebras (v2.2.0), Qwen 3 Coder 480B - Cerebras (v2.2.1), Claude Haiku 4.5 (v2.3.0), Qwen 3 Coder 480B - Cerebras (v2.4.0)
|
|
26083
|
+
* Authors: Claude 3.7 Sonnet (v1.0.0), Gemini 2.5 Pro (v2.0.0), Gemini 2.5 Pro (v2.1.0), Gemini 2.5 Pro (v2.1.1), Gemini 2.5 Flash (v2.1.2), Gemini 2.5 Flash (v2.1.3), Gemini 2.5 Flash (v2.1.4), Qwen 3 Coder 480B - Cerebras (v2.1.5), Qwen 3 Coder 480B - Cerebras (v2.2.0), Qwen 3 Coder 480B - Cerebras (v2.2.1), Claude Haiku 4.5 (v2.3.0), Qwen 3 Coder 480B - Cerebras (v2.4.0), Qwen 3 Coder 480B - Cerebras (v2.5.0), GLM-4.6 (v2.6.0), GLM-4.6 (v2.7.0)
|
|
24265
26084
|
*/
|
|
24266
26085
|
|
|
24267
|
-
const ChatUtils = ChatUtils$
|
|
24268
|
-
const CodeBlockUtils = CodeBlockUtils$
|
|
26086
|
+
const ChatUtils = ChatUtils$2;
|
|
26087
|
+
const CodeBlockUtils = CodeBlockUtils$7;
|
|
24269
26088
|
const ContextUtils = ContextUtils$2;
|
|
24270
26089
|
const MessageUtils = MessageUtils$3;
|
|
24271
26090
|
const AnalysisBlockUtils = AnalysisBlockUtils$3;
|
|
@@ -24282,7 +26101,10 @@ const EnvUtils = EnvUtils$1;
|
|
|
24282
26101
|
const DomUtils = DomUtils$1;
|
|
24283
26102
|
const ObjectUtils = ObjectUtils$1;
|
|
24284
26103
|
const SVGUtils = SVGUtils_1;
|
|
26104
|
+
const StringUtils = stringUtils;
|
|
24285
26105
|
const LanguageNameUtils = LanguageNameUtils$1;
|
|
26106
|
+
const MetaRawResultUtils = MetaRawResultUtils$1;
|
|
26107
|
+
const CompactChatUtils = CompactChatUtils$1;
|
|
24286
26108
|
|
|
24287
26109
|
const {
|
|
24288
26110
|
normalizeLanguageName,
|
|
@@ -24368,6 +26190,7 @@ const {
|
|
|
24368
26190
|
removeCodeBlockMarkers,
|
|
24369
26191
|
updateCodeBlockByIndex,
|
|
24370
26192
|
deleteCodeBlockByIndex,
|
|
26193
|
+
getLineage,
|
|
24371
26194
|
} = CodeBlockUtils;
|
|
24372
26195
|
|
|
24373
26196
|
const {
|
|
@@ -24413,6 +26236,7 @@ const {
|
|
|
24413
26236
|
parseContextSection,
|
|
24414
26237
|
extractContextSections,
|
|
24415
26238
|
extractContextItemsOverviewTableRows,
|
|
26239
|
+
getContextFiles,
|
|
24416
26240
|
formatContextContent,
|
|
24417
26241
|
} = ContextUtils;
|
|
24418
26242
|
|
|
@@ -24420,6 +26244,28 @@ const {
|
|
|
24420
26244
|
trimObjectStrings
|
|
24421
26245
|
} = ObjectUtils;
|
|
24422
26246
|
|
|
26247
|
+
const {
|
|
26248
|
+
splitWithLimit,
|
|
26249
|
+
capitalize,
|
|
26250
|
+
titleCase,
|
|
26251
|
+
camelCase,
|
|
26252
|
+
kebabCase,
|
|
26253
|
+
snakeCase,
|
|
26254
|
+
constantCase,
|
|
26255
|
+
pascalCase,
|
|
26256
|
+
trimWhitespace,
|
|
26257
|
+
truncate,
|
|
26258
|
+
} = StringUtils;
|
|
26259
|
+
|
|
26260
|
+
const {
|
|
26261
|
+
extractMetaRawResultMappings,
|
|
26262
|
+
isMetaRawResultMessage,
|
|
26263
|
+
parseMetaRawResultContent,
|
|
26264
|
+
parseTableRow,
|
|
26265
|
+
parseSize,
|
|
26266
|
+
parseTokens
|
|
26267
|
+
} = MetaRawResultUtils;
|
|
26268
|
+
|
|
24423
26269
|
|
|
24424
26270
|
/**
|
|
24425
26271
|
* GitSenseChatUtils class provides a unified interface to code block and patch utilities.
|
|
@@ -24660,7 +26506,12 @@ var GitSenseChatUtils_1 = {
|
|
|
24660
26506
|
EnvUtils,
|
|
24661
26507
|
DomUtils,
|
|
24662
26508
|
ObjectUtils,
|
|
26509
|
+
StringUtils,
|
|
24663
26510
|
SVGUtils,
|
|
26511
|
+
MetaRawResultUtils,
|
|
26512
|
+
CompactChatUtils,
|
|
26513
|
+
ReferenceMessageUtils: CompactChatUtils.ReferenceMessageUtils,
|
|
26514
|
+
CompactedMessageUtils: CompactChatUtils.CompactedMessageUtils,
|
|
24664
26515
|
|
|
24665
26516
|
// --- Individual Function Exports (sourced correctly) ---
|
|
24666
26517
|
|
|
@@ -24753,6 +26604,18 @@ var GitSenseChatUtils_1 = {
|
|
|
24753
26604
|
// Object Utils
|
|
24754
26605
|
trimObjectStrings,
|
|
24755
26606
|
|
|
26607
|
+
// String Utils
|
|
26608
|
+
splitWithLimit,
|
|
26609
|
+
capitalize,
|
|
26610
|
+
titleCase,
|
|
26611
|
+
camelCase,
|
|
26612
|
+
kebabCase,
|
|
26613
|
+
snakeCase,
|
|
26614
|
+
constantCase,
|
|
26615
|
+
pascalCase,
|
|
26616
|
+
trimWhitespace,
|
|
26617
|
+
truncate,
|
|
26618
|
+
|
|
24756
26619
|
// Markdown Utils
|
|
24757
26620
|
createMarkdownRenderer,
|
|
24758
26621
|
removeSignature,
|
|
@@ -24772,10 +26635,19 @@ var GitSenseChatUtils_1 = {
|
|
|
24772
26635
|
getApiKey,
|
|
24773
26636
|
|
|
24774
26637
|
// Context Utils
|
|
26638
|
+
getContextFiles,
|
|
24775
26639
|
parseContextSection,
|
|
24776
26640
|
extractContextSections,
|
|
24777
26641
|
extractContextItemsOverviewTableRows,
|
|
24778
26642
|
formatContextContent,
|
|
26643
|
+
|
|
26644
|
+
// MetaRawResult Utils
|
|
26645
|
+
extractMetaRawResultMappings,
|
|
26646
|
+
isMetaRawResultMessage,
|
|
26647
|
+
parseMetaRawResultContent,
|
|
26648
|
+
parseTableRow,
|
|
26649
|
+
parseSize,
|
|
26650
|
+
parseTokens,
|
|
24779
26651
|
};
|
|
24780
26652
|
|
|
24781
26653
|
var GitSenseChatUtils$1 = /*@__PURE__*/getDefaultExportFromCjs(GitSenseChatUtils_1);
|