@gitsense/gsc-utils 0.2.25 → 0.2.28
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 +2290 -326
- package/dist/gsc-utils.esm.js +2290 -326
- 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 +102 -14
- package/src/FormatterUtils.js +1 -1
- package/src/GSToolBlockUtils.js +66 -1
- package/src/GitSenseChatUtils.js +58 -5
- package/src/LLMUtils.js +1 -1
- 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/PatchUtils/patchVerifier/detectAndFixRedundantChanges.js +1 -1
- package/src/PatchUtils/patchVerifier/verifyAndCorrectHunkHeaders.js +1 -1
- package/src/SVGUtils.js +137 -2
- package/src/SharedUtils/stringUtils.js +303 -0
- package/src/CodeBlockUtils/blockProcessor.js.rej +0 -8
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component: ReferenceMessageUtils
|
|
3
|
+
* Block-UUID: 2870551a-4311-4d64-9491-c9cc62f276e8
|
|
4
|
+
* Parent-UUID: N/A
|
|
5
|
+
* Description: Utility for parsing reference messages in the compact message workflow, extracting session data, metadata, and message sections.
|
|
6
|
+
* Language: JavaScript
|
|
7
|
+
* Created-at: 2025-12-07T00:08:42.573Z
|
|
8
|
+
* Authors: GLM-4.6 (v1.0.0)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ReferenceMessageUtils {
|
|
13
|
+
/**
|
|
14
|
+
* Extracts all data from a reference message including session data, metadata, and message sections
|
|
15
|
+
* @param {string} referenceMessage - The reference message content to parse
|
|
16
|
+
* @returns {Object} Parsed data with messages to compact and keep, metadata, and session information
|
|
17
|
+
*/
|
|
18
|
+
static extractReferenceMessageData(referenceMessage) {
|
|
19
|
+
if (!referenceMessage) {
|
|
20
|
+
return {
|
|
21
|
+
messagesToCompact: [],
|
|
22
|
+
messagesToKeep: [],
|
|
23
|
+
originalChatUuid: null,
|
|
24
|
+
validationHash: null,
|
|
25
|
+
sessionId: null,
|
|
26
|
+
range: null,
|
|
27
|
+
from: null,
|
|
28
|
+
to: null
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Extract Original Chat UUID
|
|
33
|
+
const originalChatUuidMatch = referenceMessage.match(/Original Chat UUID:\s*([a-f0-9-]+)/i);
|
|
34
|
+
const originalChatUuid = originalChatUuidMatch ? originalChatUuidMatch[1] : null;
|
|
35
|
+
|
|
36
|
+
// Extract Validation Hash
|
|
37
|
+
const validationHashMatch = referenceMessage.match(/Validation Hash:\s*([a-f0-9]+)/i);
|
|
38
|
+
const validationHash = validationHashMatch ? validationHashMatch[1] : null;
|
|
39
|
+
|
|
40
|
+
// Extract Session ID
|
|
41
|
+
const sessionIdMatch = referenceMessage.match(/Session ID:\s*(\d+)/i);
|
|
42
|
+
const sessionId = sessionIdMatch ? sessionIdMatch[1] : null;
|
|
43
|
+
|
|
44
|
+
// Extract Range
|
|
45
|
+
const rangeMatch = referenceMessage.match(/Range:\s*(\d+-\d+)/i);
|
|
46
|
+
const range = rangeMatch ? rangeMatch[1] : null;
|
|
47
|
+
|
|
48
|
+
// Extract From and To values
|
|
49
|
+
const fromMatch = referenceMessage.match(/From:\s*(\d+)/i);
|
|
50
|
+
const from = fromMatch ? parseInt(fromMatch[1], 10) : null;
|
|
51
|
+
|
|
52
|
+
const toMatch = referenceMessage.match(/To:\s*(\d+)/i);
|
|
53
|
+
const to = toMatch ? parseInt(toMatch[1], 10) : null;
|
|
54
|
+
|
|
55
|
+
// If range is not found but from and to are available, construct the range
|
|
56
|
+
if (!range && from !== null && to !== null) {
|
|
57
|
+
range = `${from}-${to}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Extract Messages to Compact section
|
|
61
|
+
const compactSectionMatch = referenceMessage.match(/# Messages to Compact\n([\s\S]*?)(?=\n# |\n$|$)/);
|
|
62
|
+
const compactSection = compactSectionMatch ? compactSectionMatch[1] : '';
|
|
63
|
+
|
|
64
|
+
// Extract Messages to Keep section
|
|
65
|
+
const keepSectionMatch = referenceMessage.match(/# Messages to Keep \(Context\)\n([\s\S]*?)(?=\n# |\n$|$)/);
|
|
66
|
+
const keepSection = keepSectionMatch ? keepSectionMatch[1] : '';
|
|
67
|
+
|
|
68
|
+
// Parse messages from each section
|
|
69
|
+
const messagesToCompact = this.parseMessageSection(compactSection);
|
|
70
|
+
const messagesToKeep = this.parseMessageSection(keepSection);
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
messagesToCompact,
|
|
74
|
+
messagesToKeep,
|
|
75
|
+
originalChatUuid,
|
|
76
|
+
validationHash,
|
|
77
|
+
sessionId,
|
|
78
|
+
range,
|
|
79
|
+
from,
|
|
80
|
+
to
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Parses a message section to extract individual messages
|
|
86
|
+
* @param {string} section - The section content to parse
|
|
87
|
+
* @returns {Array} Array of parsed message objects
|
|
88
|
+
*/
|
|
89
|
+
static parseMessageSection(section) {
|
|
90
|
+
if (!section) return [];
|
|
91
|
+
|
|
92
|
+
const messages = [];
|
|
93
|
+
const messageRegex = /<(\w+) message number (\d+)>\n([\s\S]*?)\n<\/\1 message number \2>/g;
|
|
94
|
+
let match;
|
|
95
|
+
|
|
96
|
+
while ((match = messageRegex.exec(section)) !== null) {
|
|
97
|
+
const [, role, positionStr, content] = match;
|
|
98
|
+
const position = parseInt(positionStr, 10);
|
|
99
|
+
|
|
100
|
+
messages.push({
|
|
101
|
+
role,
|
|
102
|
+
position,
|
|
103
|
+
content: content.trim()
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return messages;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Extracts just the metadata from a reference message without the message sections
|
|
112
|
+
* @param {string} referenceMessage - The reference message content to parse
|
|
113
|
+
* @returns {Object} Metadata object with original chat UUID, validation hash, session ID, and range information
|
|
114
|
+
*/
|
|
115
|
+
static extractReferenceMessageMetadata(referenceMessage) {
|
|
116
|
+
const data = this.extractReferenceMessageData(referenceMessage);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
originalChatUuid: data.originalChatUuid,
|
|
120
|
+
validationHash: data.validationHash,
|
|
121
|
+
sessionId: data.sessionId,
|
|
122
|
+
range: data.range,
|
|
123
|
+
from: data.from,
|
|
124
|
+
to: data.to
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Checks if a message is a reference message
|
|
130
|
+
* @param {string} message - The message content to check
|
|
131
|
+
* @returns {boolean} True if the message is a reference message
|
|
132
|
+
*/
|
|
133
|
+
static isReferenceMessage(message) {
|
|
134
|
+
if (!message) return false;
|
|
135
|
+
|
|
136
|
+
// Check for key indicators of a reference message
|
|
137
|
+
return message.includes('# Compact Messages Reference') &&
|
|
138
|
+
message.includes('Original Chat UUID:') &&
|
|
139
|
+
message.includes('Session ID:');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module.exports = { ReferenceMessageUtils };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component: CompactChatUtils Index
|
|
3
|
+
* Block-UUID: cd0a6091-edb6-4e92-9439-63dd8f6a6796
|
|
4
|
+
* Parent-UUID: 5ffa0338-b4fb-4968-908c-f23a26d4923b
|
|
5
|
+
* Version: 2.0.0
|
|
6
|
+
* Description: Entry point for CompactChatUtils that exports both ReferenceMessageUtils and CompactedMessageUtils methods directly for easier access.
|
|
7
|
+
* Language: JavaScript
|
|
8
|
+
* Created-at: 2025-12-07T00:10:05.123Z
|
|
9
|
+
* Authors: GLM-4.6 (v1.0.0), GLM-4.6 (v2.0.0)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const { ReferenceMessageUtils } = require('./ReferenceMessageUtils');
|
|
14
|
+
const { CompactedMessageUtils } = require('./CompactedMessageUtils');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* CompactChatUtils provides utilities for working with compacted messages in GitSense Chat.
|
|
18
|
+
* It includes functionality for parsing reference messages and formatting/parsing compacted messages.
|
|
19
|
+
*/
|
|
20
|
+
module.exports = {
|
|
21
|
+
// Export the classes for those who want to access them directly
|
|
22
|
+
ReferenceMessageUtils,
|
|
23
|
+
CompactedMessageUtils,
|
|
24
|
+
|
|
25
|
+
// Export all methods from ReferenceMessageUtils directly
|
|
26
|
+
extractReferenceMessageData: ReferenceMessageUtils.extractReferenceMessageData,
|
|
27
|
+
parseMessageSection: ReferenceMessageUtils.parseMessageSection,
|
|
28
|
+
extractReferenceMessageMetadata: ReferenceMessageUtils.extractReferenceMessageMetadata,
|
|
29
|
+
isReferenceMessage: ReferenceMessageUtils.isReferenceMessage,
|
|
30
|
+
|
|
31
|
+
// Export all methods from CompactedMessageUtils directly
|
|
32
|
+
formatCompactedMessage: CompactedMessageUtils.formatCompactedMessage,
|
|
33
|
+
extractCompactedMessageMetadata: CompactedMessageUtils.extractCompactedMessageMetadata,
|
|
34
|
+
extractCompactedMessageContent: CompactedMessageUtils.extractCompactedMessageContent,
|
|
35
|
+
validateCompactedMessageFormat: CompactedMessageUtils.validateCompactedMessageFormat,
|
|
36
|
+
isCompactedMessage: CompactedMessageUtils.isCompactedMessage,
|
|
37
|
+
isValidUUID: CompactedMessageUtils.isValidUUID,
|
|
38
|
+
isValidMessageRange: CompactedMessageUtils.isValidMessageRange,
|
|
39
|
+
isValidISOTimestamp: CompactedMessageUtils.isValidISOTimestamp
|
|
40
|
+
};
|
package/src/ContextUtils.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Component: ContextUtils
|
|
3
|
-
* Block-UUID:
|
|
4
|
-
* Parent-UUID:
|
|
5
|
-
* Version: 1.
|
|
3
|
+
* Block-UUID: 534c348d-a11f-4de6-ad15-f33068d51fb8
|
|
4
|
+
* Parent-UUID: a0b71292-b1cc-401a-8ce2-544a047b0fef
|
|
5
|
+
* Version: 1.4.0
|
|
6
6
|
* Description: Provides utility functions for parsing context message sections to extract file details and code blocks, and for formatting content for LLM context.
|
|
7
7
|
* Language: JavaScript
|
|
8
8
|
* Created-at: 2025-05-09T01:36:20.107Z
|
|
9
|
-
* 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)
|
|
9
|
+
* 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)
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
|
|
@@ -77,6 +77,41 @@ function _createContextSummary(items, contentType) {
|
|
|
77
77
|
return summary + "\n";
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Extracts all context files from a given chat object.
|
|
82
|
+
* Iterates through chat messages, identifies context loader outputs,
|
|
83
|
+
* and parses them into individual file objects.
|
|
84
|
+
*
|
|
85
|
+
* @param {object} chat - The GitSense chat object.
|
|
86
|
+
* @returns {Array<object>} An array of parsed context file objects.
|
|
87
|
+
* Returns an empty array if no context files are found or on error.
|
|
88
|
+
*/
|
|
89
|
+
function getContextFiles(chat) {
|
|
90
|
+
const ChatUtils = require('./ChatUtils');
|
|
91
|
+
const contextFiles = [];
|
|
92
|
+
const messages = ChatUtils.getChatMessages(chat);
|
|
93
|
+
|
|
94
|
+
if (!Array.isArray(messages)) {
|
|
95
|
+
console.warn("getContextFiles: Provided chat object does not contain a valid messages array.");
|
|
96
|
+
return contextFiles;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
messages.forEach(message => {
|
|
100
|
+
// Check if the message content is a context message
|
|
101
|
+
if (MessageUtils.isContextMessage(message.message)) {
|
|
102
|
+
try {
|
|
103
|
+
// Extract all context sections from the message content
|
|
104
|
+
const extractedFiles = extractContextSections(message.message);
|
|
105
|
+
contextFiles.push(...extractedFiles);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.warn(`getContextFiles: Failed to extract context sections from message ID ${message.id}:`, error);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return contextFiles;
|
|
113
|
+
}
|
|
114
|
+
|
|
80
115
|
/**
|
|
81
116
|
* Escapes backticks in code blocks to prevent premature termination of LLM-generated code blocks.
|
|
82
117
|
* @param {string} content - The content string to escape.
|
|
@@ -351,6 +386,7 @@ function formatContextContent(items, contentType, contentOption) {
|
|
|
351
386
|
module.exports = {
|
|
352
387
|
parseContextSection,
|
|
353
388
|
extractContextSections,
|
|
389
|
+
getContextFiles,
|
|
354
390
|
extractContextItemsOverviewTableRows,
|
|
355
391
|
formatContextContent,
|
|
356
392
|
};
|
package/src/DomUtils.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Component: DomUtils Helper Functions
|
|
3
|
-
* Block-UUID:
|
|
4
|
-
* Parent-UUID:
|
|
5
|
-
* Version: 1.1
|
|
3
|
+
* Block-UUID: 9a8e8e8e-8b15-4346-bbfa-740e6a5d2d79
|
|
4
|
+
* Parent-UUID: 8a528728-ce54-4445-946d-1743fb4b16be
|
|
5
|
+
* Version: 1.3.1
|
|
6
6
|
* Description: Provides helper functions for creating and manipulating DOM elements.
|
|
7
7
|
* Language: JavaScript
|
|
8
|
-
* Created-at: 2025-
|
|
9
|
-
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Flash (v1.1.0)
|
|
8
|
+
* Created-at: 2025-12-14T04:18:40.180Z
|
|
9
|
+
* 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), GLM-4.6 (v1.3.1)
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
|
|
@@ -19,6 +19,7 @@ function createElement(type, params) {
|
|
|
19
19
|
let {
|
|
20
20
|
id,
|
|
21
21
|
ariaLabel,
|
|
22
|
+
xmlns,
|
|
22
23
|
role,
|
|
23
24
|
html,
|
|
24
25
|
text,
|
|
@@ -41,11 +42,15 @@ function createElement(type, params) {
|
|
|
41
42
|
"data-message-role": dmr,
|
|
42
43
|
attrs = {},
|
|
43
44
|
dataset,
|
|
45
|
+
rows
|
|
44
46
|
} = params;
|
|
45
47
|
|
|
46
48
|
// Set standard attributes
|
|
47
49
|
if (id != null) elem.id = id;
|
|
48
50
|
if (ariaLabel) elem.setAttribute("aria-label", ariaLabel);
|
|
51
|
+
if (xmlns) elem.setAttribute("xmlns", xmlns);
|
|
52
|
+
if (params.viewBox) elem.setAttribute("viewBox", params.viewBox);
|
|
53
|
+
if (params.fill) elem.setAttribute("fill", params.fill);
|
|
49
54
|
if (role) elem.setAttribute("role", role);
|
|
50
55
|
if (placeholder) elem.setAttribute("placeholder", placeholder);
|
|
51
56
|
if (cls || className) elem.setAttribute("class", cls || className);
|
|
@@ -53,6 +58,9 @@ function createElement(type, params) {
|
|
|
53
58
|
if (title != null) elem.setAttribute("title", title);
|
|
54
59
|
if (inputType) elem.setAttribute("type", inputType);
|
|
55
60
|
if (name != null) elem.setAttribute("name", name);
|
|
61
|
+
if (params.width) elem.setAttribute("width", params.width);
|
|
62
|
+
if (params.height) elem.setAttribute("height", params.height);
|
|
63
|
+
if (params.stroke) elem.setAttribute("stroke", params.stroke);
|
|
56
64
|
if (value != null) elem.value = value;
|
|
57
65
|
if (checked != null && checked) elem.checked = true; // Use property for checked
|
|
58
66
|
if (selected != null && selected) elem.selected = true; // Use property for selected
|
|
@@ -60,13 +68,21 @@ function createElement(type, params) {
|
|
|
60
68
|
if (dmi != null) elem.setAttribute("data-message-id", dmi);
|
|
61
69
|
if (dmr != null) elem.setAttribute("data-message-role", dmr);
|
|
62
70
|
if (_for != null ) elem.setAttribute("for", _for);
|
|
71
|
+
if (params.strokeWidth) elem.setAttribute("stroke-width", params.strokeWidth);
|
|
72
|
+
if (params.strokeLinecap) elem.setAttribute("stroke-linecap", params.strokeLinecap);
|
|
73
|
+
if (params.strokeLinejoin) elem.setAttribute("stroke-linejoin", params.strokeLinejoin);
|
|
63
74
|
if (colSpan != null) elem.colSpan = colSpan;
|
|
75
|
+
if (rows) elem.setAttribute("rows", params.rows);
|
|
64
76
|
|
|
65
77
|
// Set content
|
|
66
78
|
if (html != null) {
|
|
67
79
|
if (typeof html === "object" && html instanceof Node) { // Ensure html is a Node
|
|
68
80
|
elem.appendChild(html);
|
|
69
81
|
} else if (typeof html === "string") {
|
|
82
|
+
// For SVG elements, use innerHTML to support path elements
|
|
83
|
+
if (type === 'svg' && params.innerHTML) {
|
|
84
|
+
elem.innerHTML = params.innerHTML;
|
|
85
|
+
}
|
|
70
86
|
elem.innerHTML = html;
|
|
71
87
|
}
|
|
72
88
|
} else if (text != null) {
|
|
@@ -92,12 +108,12 @@ function createElement(type, params) {
|
|
|
92
108
|
});
|
|
93
109
|
}
|
|
94
110
|
|
|
95
|
-
//
|
|
111
|
+
// Set additional attributes from attrs object
|
|
96
112
|
if (attrs && typeof attrs === 'object') {
|
|
97
113
|
for (const [key, value] of Object.entries(attrs)) {
|
|
98
114
|
if (value !== undefined && value !== null) {
|
|
99
115
|
// Skip if already set by standard properties or handled directly
|
|
100
|
-
if (!['id', 'class', 'role', 'aria-label', 'title', 'style', '
|
|
116
|
+
if (!['id', 'class', 'role', 'aria-label', 'title', 'style', 'selected', 'disabled', 'value', 'name', 'type', 'for'].includes(key) && !key.startsWith('data-')) {
|
|
101
117
|
elem.setAttribute(key, value);
|
|
102
118
|
}
|
|
103
119
|
}
|
|
@@ -210,14 +226,17 @@ const h = {
|
|
|
210
226
|
},
|
|
211
227
|
createLink: (params) => {
|
|
212
228
|
const link = createElement("a", params);
|
|
213
|
-
|
|
214
|
-
if (params?.
|
|
229
|
+
if (params?.href) link.href = params.href;
|
|
230
|
+
if (params?.target) link.target = params.target;
|
|
215
231
|
return link;
|
|
216
232
|
},
|
|
217
233
|
createNav: (params) => {
|
|
218
234
|
return createElement("nav", params);
|
|
219
235
|
},
|
|
220
|
-
|
|
236
|
+
createOl: (params) => {
|
|
237
|
+
return createElement("ol", params);
|
|
238
|
+
},
|
|
239
|
+
createOL: (params) => {
|
|
221
240
|
return createElement("ol", params);
|
|
222
241
|
},
|
|
223
242
|
createOption: (params) => { // Added
|
|
@@ -233,13 +252,49 @@ const h = {
|
|
|
233
252
|
createPre: (params) => {
|
|
234
253
|
return createElement("pre", params);
|
|
235
254
|
},
|
|
236
|
-
createSelect: (params) => {
|
|
237
|
-
//
|
|
238
|
-
|
|
255
|
+
createSelect: (params) => {
|
|
256
|
+
// Extract value before creating the select element
|
|
257
|
+
const { value, ...selectParams } = params || {};
|
|
258
|
+
|
|
259
|
+
// Create select element without the value initially
|
|
260
|
+
const select = createElement("select", selectParams);
|
|
261
|
+
|
|
262
|
+
// Handle options array if provided
|
|
263
|
+
if (params && params.options && Array.isArray(params.options)) {
|
|
264
|
+
params.options.forEach(option => {
|
|
265
|
+
if (option && typeof option === 'object') {
|
|
266
|
+
// Check if this option should be selected based on the value
|
|
267
|
+
const isSelected = (value !== undefined && value !== null) &&
|
|
268
|
+
(option.value === value ||
|
|
269
|
+
(value === '' && option.value === '') ||
|
|
270
|
+
(value === null && option.value === null));
|
|
271
|
+
|
|
272
|
+
const optionElement = createElement("option", {
|
|
273
|
+
value: option.value,
|
|
274
|
+
text: option.text,
|
|
275
|
+
selected: isSelected || option.selected
|
|
276
|
+
});
|
|
277
|
+
select.appendChild(optionElement);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Set the value after options are added to ensure proper selection
|
|
283
|
+
if (value !== undefined && value !== null) {
|
|
284
|
+
select.value = value;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return select;
|
|
239
288
|
},
|
|
240
289
|
createSpan: (params) => {
|
|
241
290
|
return createElement("span", params);
|
|
242
291
|
},
|
|
292
|
+
createSvg: (params) => {
|
|
293
|
+
// Create SVG element with xmlns attribute
|
|
294
|
+
const svgParams = { ...params, xmlns: "http://www.w3.org/2000/svg" };
|
|
295
|
+
const svg = createElement("svg", svgParams);
|
|
296
|
+
return svg;
|
|
297
|
+
},
|
|
243
298
|
createStrong: (params) => { // Added
|
|
244
299
|
return createElement("strong", params);
|
|
245
300
|
},
|
|
@@ -252,6 +307,10 @@ const h = {
|
|
|
252
307
|
createText: (text) => {
|
|
253
308
|
return document.createTextNode(text);
|
|
254
309
|
},
|
|
310
|
+
createTextarea: (params) => {
|
|
311
|
+
const textArea = createElement("textarea", params);
|
|
312
|
+
return textArea;
|
|
313
|
+
},
|
|
255
314
|
createTextArea: (params) => {
|
|
256
315
|
const textArea = createElement("textarea", params);
|
|
257
316
|
return textArea;
|
|
@@ -450,6 +509,35 @@ const h = {
|
|
|
450
509
|
})
|
|
451
510
|
.join('');
|
|
452
511
|
},
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Injects CSS styles into the document head.
|
|
515
|
+
* @param {string} cssString - The CSS string to inject.
|
|
516
|
+
* @param {string} [id] - Optional ID for the style element to prevent duplicates.
|
|
517
|
+
* @returns {HTMLStyleElement} The created or existing style element.
|
|
518
|
+
*/
|
|
519
|
+
injectStyles: (cssString, id) => {
|
|
520
|
+
// If an ID is provided, check if styles with this ID already exist
|
|
521
|
+
if (id) {
|
|
522
|
+
const existingStyle = document.getElementById(id);
|
|
523
|
+
if (existingStyle) {
|
|
524
|
+
// Styles already injected, return the existing element
|
|
525
|
+
return existingStyle;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Create a new style element
|
|
530
|
+
const styleElement = document.createElement('style');
|
|
531
|
+
if (id) {
|
|
532
|
+
styleElement.id = id;
|
|
533
|
+
}
|
|
534
|
+
styleElement.textContent = cssString;
|
|
535
|
+
|
|
536
|
+
// Append to the document head
|
|
537
|
+
document.head.appendChild(styleElement);
|
|
538
|
+
|
|
539
|
+
return styleElement;
|
|
540
|
+
},
|
|
453
541
|
|
|
454
542
|
/**
|
|
455
543
|
* Calculates the distance between an element's edge and the viewport's corresponding edge
|
|
@@ -480,6 +568,6 @@ const h = {
|
|
|
480
568
|
return rect.left;
|
|
481
569
|
}
|
|
482
570
|
}
|
|
483
|
-
}
|
|
571
|
+
};
|
|
484
572
|
|
|
485
573
|
module.exports = { h };
|
package/src/FormatterUtils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Component: Formatter Utilities
|
|
3
|
-
* Block-UUID:
|
|
3
|
+
* Block-UUID: 8512c809-87b0-4f90-af9d-b3dca204c4de
|
|
4
4
|
* Parent-UUID: 9c07d12f-5a05-4402-99d2-85d872d7b2f7
|
|
5
5
|
* Version: 1.0.0
|
|
6
6
|
* Description: Utility functions for formatting content in GitSense Chat
|
package/src/GSToolBlockUtils.js
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
const GS_TOOL_BLOCK_TYPE = 'gs-tool';
|
|
14
|
+
|
|
13
15
|
/**
|
|
14
16
|
* Checks if a given code block content represents a GitSense Chat Tool Block.
|
|
15
17
|
* It verifies if the first non-empty line starts with "# GitSense Chat Tool".
|
|
@@ -28,6 +30,65 @@ function isToolBlock(content) {
|
|
|
28
30
|
return false;
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
|
|
34
|
+
// TODO: Add JSDocs
|
|
35
|
+
function getToolBlocksByTool(content, tool, CodeBlockUtils) {
|
|
36
|
+
const { blocks, warnings } = CodeBlockUtils.extractCodeBlocks(content, { silent: true });
|
|
37
|
+
|
|
38
|
+
return blocks.filter((block, index) => {
|
|
39
|
+
if (block.type !== GS_TOOL_BLOCK_TYPE)
|
|
40
|
+
return;
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const data = parseToolBlock(block.content);
|
|
44
|
+
|
|
45
|
+
if (data.tool === tool) {
|
|
46
|
+
block.index = index;
|
|
47
|
+
return block;
|
|
48
|
+
}
|
|
49
|
+
} catch(error) {
|
|
50
|
+
// FIXME: We need a more elegant way to identify examples.
|
|
51
|
+
if (!content.includes(/Internal INTEGER IDs/)) {
|
|
52
|
+
console.warn(`Invalid tool block JSON: ${error.message}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// TODO: Add JSDocs
|
|
59
|
+
function getToolBlockElemsByTool(dom, tool) {
|
|
60
|
+
const elems = dom.querySelectorAll('pre');
|
|
61
|
+
const toolBockElems = [];
|
|
62
|
+
|
|
63
|
+
for ( let i = 0; i < elems.length; i++ ) {
|
|
64
|
+
const elem = elems[i];
|
|
65
|
+
let content = elem.textContent;
|
|
66
|
+
|
|
67
|
+
// We need to strip out the first two lines since this is not part of the actual code
|
|
68
|
+
// block. These two lines are designed to make it easy to identify the language
|
|
69
|
+
content = content.split('\n').slice(2).join('\n');
|
|
70
|
+
|
|
71
|
+
if (!isToolBlock(content))
|
|
72
|
+
continue;
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const data = parseToolBlock(content, { silent: true });
|
|
76
|
+
|
|
77
|
+
if (data.tool === tool)
|
|
78
|
+
toolBockElems.push(elem);
|
|
79
|
+
} catch(error) {
|
|
80
|
+
// FIXME: We need a more elegant way to identify examples.
|
|
81
|
+
if (!content.match(/Internal INTEGER IDs/)) {
|
|
82
|
+
console.warn("getToolBlockElemsByTool: ",error.message);
|
|
83
|
+
}
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return toolBockElems;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
31
92
|
/**
|
|
32
93
|
* Parses the content of a GitSense Chat Tool Block to extract the JSON payload.
|
|
33
94
|
* It strips the marker line and any subsequent lines starting with '#' (comments)
|
|
@@ -136,7 +197,7 @@ function replaceToolBlock(markdownContent, toolName, newToolData, CodeBlockUtils
|
|
|
136
197
|
// 2. Iterate through the processed blocks to find the target GitSense Chat Tool Block
|
|
137
198
|
for (let i = 0; i < blocks.length; i++) {
|
|
138
199
|
const block = blocks[i];
|
|
139
|
-
if (block.type ===
|
|
200
|
+
if (block.type === GS_TOOL_BLOCK_TYPE && block.toolData && block.toolData.tool === toolName) {
|
|
140
201
|
targetBlockIndex = i;
|
|
141
202
|
break; // Found the first matching tool block
|
|
142
203
|
}
|
|
@@ -270,10 +331,14 @@ function detectAndFormatUnfencedToolBlock(messageContent) {
|
|
|
270
331
|
};
|
|
271
332
|
}
|
|
272
333
|
|
|
334
|
+
|
|
335
|
+
|
|
273
336
|
module.exports = {
|
|
274
337
|
isToolBlock,
|
|
275
338
|
parseToolBlock,
|
|
276
339
|
formatToolBlock,
|
|
277
340
|
replaceToolBlock,
|
|
341
|
+
getToolBlocksByTool,
|
|
342
|
+
getToolBlockElemsByTool,
|
|
278
343
|
detectAndFormatUnfencedToolBlock,
|
|
279
344
|
}
|