@gitsense/gsc-utils 0.2.7 → 0.2.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitsense/gsc-utils",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Utilities for GitSense Chat (GSC)",
5
5
  "main": "dist/gsc-utils.cjs.js",
6
6
  "module": "dist/gsc-utils.esm.js",
@@ -0,0 +1,75 @@
1
+ /*
2
+ * Component: AnalyzerUtils Default Prompt Loader
3
+ * Block-UUID: 0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5f
4
+ * Parent-UUID: N/A
5
+ * Version: 1.0.0
6
+ * Description: Provides utility functions for loading shared, default prompt components (system and start messages).
7
+ * Language: JavaScript
8
+ * Created-at: 2025-08-29T03:30:28.771Z
9
+ * Authors: Gemini 2.5 Flash (v1.0.0)
10
+ */
11
+
12
+
13
+ const fs = require('fs').promises;
14
+ const path = require('path');
15
+
16
+ /**
17
+ * Retrieves the raw Markdown content of the shared system message ('_shared/system/1.md').
18
+ *
19
+ * @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing analyzer message files (e.g., 'messages/analyze').
20
+ * @returns {Promise<string|null>} A promise that resolves with the full Markdown content, or null if not found/invalid.
21
+ */
22
+ async function getSystemMessageContent(analyzeMessagesBasePath) {
23
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
24
+ console.error('Error: analyzeMessagesBasePath is required for getSystemMessageContent.');
25
+ return null;
26
+ }
27
+
28
+ const systemMessageFilePath = path.join(analyzeMessagesBasePath, '_shared', 'system', '1.md');
29
+
30
+ try {
31
+ const fileContent = await fs.readFile(systemMessageFilePath, 'utf8');
32
+ return fileContent;
33
+ } catch (error) {
34
+ if (error.code === 'ENOENT') {
35
+ console.warn(`Default system message file not found: ${systemMessageFilePath}.`);
36
+ return null;
37
+ } else {
38
+ console.error(`Error reading default system message file ${systemMessageFilePath}: ${error.message}`);
39
+ throw error;
40
+ }
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Retrieves the raw Markdown content of the shared start message ('_shared/start/1.md').
46
+ *
47
+ * @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing analyzer message files (e.g., 'messages/analyze').
48
+ * @returns {Promise<string|null>} A promise that resolves with the full Markdown content, or null if not found/invalid.
49
+ */
50
+ async function getStartMessageContent(analyzeMessagesBasePath) {
51
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
52
+ console.error('Error: analyzeMessagesBasePath is required for getStartMessageContent.');
53
+ return null;
54
+ }
55
+
56
+ const startMessageFilePath = path.join(analyzeMessagesBasePath, '_shared', 'start', '1.md');
57
+
58
+ try {
59
+ const fileContent = await fs.readFile(startMessageFilePath, 'utf8');
60
+ return fileContent;
61
+ } catch (error) {
62
+ if (error.code === 'ENOENT') {
63
+ console.warn(`Default start message file not found: ${startMessageFilePath}.`);
64
+ return null;
65
+ } else {
66
+ console.error(`Error reading default start message file ${startMessageFilePath}: ${error.message}`);
67
+ throw error;
68
+ }
69
+ }
70
+ }
71
+
72
+ module.exports = {
73
+ getSystemMessageContent,
74
+ getStartMessageContent
75
+ };
@@ -2,11 +2,11 @@
2
2
  * Component: AnalyzerUtils Index
3
3
  * Block-UUID: b403b6a1-230b-4247-8cd6-2a3d068f4bbf
4
4
  * Parent-UUID: N/A
5
- * Version: 1.1.0
5
+ * Version: 1.2.0
6
6
  * Description: Aggregates and exports all utility functions from the AnalyzerUtils module.
7
7
  * Language: JavaScript
8
8
  * Created-at: 2025-08-28T15:56:40.319Z
9
- * Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0)
9
+ * Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0), Gemini 2.5 Flash (v1.2.0)
10
10
  */
11
11
 
12
12
 
@@ -18,6 +18,7 @@ const { saveConfiguration } = require('./saver');
18
18
  const { getAnalyzerSchema } = require('./schemaLoader');
19
19
  const { deleteAnalyzer } = require('./management');
20
20
  const { getAnalyzerInstructionsContent } = require('./instructionLoader');
21
+ const { getSystemMessageContent, getStartMessageContent } = require('./defaultPromptLoader'); // NEW: Import default prompt loaders
21
22
 
22
23
  module.exports = {
23
24
  buildChatIdToPathMap,
@@ -28,4 +29,6 @@ module.exports = {
28
29
  deleteAnalyzer,
29
30
  getAnalyzerInstructionsContent,
30
31
  saveConfiguration,
32
+ getSystemMessageContent,
33
+ getStartMessageContent
31
34
  };
@@ -1,18 +1,100 @@
1
- /**
1
+ /*
2
2
  * Component: ContextUtils
3
3
  * Block-UUID: c199efe3-003c-4226-af3c-d460392a6569
4
4
  * Parent-UUID: N/A
5
- * Version: 1.0.0
6
- * Description: Provides utility functions for parsing context message sections to extract file details and code blocks.
5
+ * Version: 1.1.0
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)
9
+ * Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash (v1.1.0)
10
10
  */
11
11
 
12
12
 
13
13
  const CodeBlockUtils = require('./CodeBlockUtils');
14
14
  const MessageUtils = require('./MessageUtils');
15
15
 
16
+ /**
17
+ * Formats bytes into human-readable string (KB, MB, GB)
18
+ * @param {number} bytes - Number of bytes
19
+ * @returns {string} Formatted size string
20
+ */
21
+ function _formatBytes(bytes) {
22
+ if (typeof bytes !== 'number' || isNaN(bytes)) return '0 bytes';
23
+ if (bytes === 0) return '0 bytes';
24
+
25
+ const k = 1024;
26
+ const sizes = ['bytes', 'KB', 'MB', 'GB'];
27
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
28
+
29
+ // Special case for bytes (no decimal)
30
+ if (i === 0) return `${bytes} ${sizes[i]}`;
31
+
32
+ const value = bytes / Math.pow(k, i);
33
+ // Show no decimal if whole number
34
+ const decimalPlaces = value % 1 === 0 ? 0 : 1;
35
+ return `${value.toFixed(decimalPlaces)} ${sizes[i]}`;
36
+ }
37
+
38
+ /**
39
+ * Creates a summary of items for human readers
40
+ * @param {Array} items - Array of loaded items
41
+ * @param {string} contentType - Content type
42
+ * @returns {string} Human-readable summary
43
+ */
44
+ function _createContextSummary(items, contentType) {
45
+ if (items.length === 0) return '';
46
+
47
+ // Group by files and trees
48
+ const files = items.filter(item => item.metadata?.type === 'git-blob');
49
+ const trees = items.filter(item => item.metadata?.type === 'git-tree' || item.metadata?.type === 'git-ref');
50
+
51
+ // Calculate total size and tokens
52
+ const totalSize = items.reduce((sum, item) => sum + (item.size || 0), 0);
53
+ const totalTokens = items.reduce((sum, item) => sum + (item.tokenCount || 0), 0);
54
+
55
+ let summary = contentType === 'file content'
56
+ ? `\n**Summary:** ${items.length} file${items.length === 1 ? '' : 's'} (${_formatBytes(totalSize)}, ${totalTokens.toLocaleString()} tokens)\n\n`
57
+ : `\n**Summary:** ${files.length} file${files.length === 1 ? '' : 's'} - ${trees.length} tree${trees.length === 1 ? '' : 's'}\n\n`;
58
+
59
+ // Add brief description of first X files
60
+ const maxFiles = 10;
61
+ const displayItems = items.slice(0, maxFiles);
62
+ if (displayItems.length > 0) {
63
+ displayItems.forEach(item => {
64
+ if (item.tokenCount) {
65
+ summary += `- ${item.name} - ${_formatBytes(item.size)}, ${item.tokenCount.toLocaleString()} tokens\n`;
66
+ } else {
67
+ summary += `- ${item.name} - Not analyzed\n`;
68
+ }
69
+ });
70
+
71
+ // Add note if there are more files
72
+ if (items.length > maxFiles) {
73
+ summary += `- ... and ${items.length - maxFiles} more\n`;
74
+ }
75
+ }
76
+
77
+ return summary + "\n";
78
+ }
79
+
80
+ /**
81
+ * Escapes backticks in code blocks to prevent premature termination of LLM-generated code blocks.
82
+ * @param {string} content - The content string to escape.
83
+ * @returns {{escapedContent: string, escapedLineNums: Array<number>}} Object with escaped content and line numbers of escaped lines.
84
+ */
85
+ function _escapeCodeBlocks(content) {
86
+ const escapedLineNums = [];
87
+ const escapedLines = content.replace(/\n$/, '').split('\n').map((line, i) => {
88
+ if (line.trimStart().startsWith('```')) {
89
+ line = '\\' + line.trimStart();
90
+ escapedLineNums.push(i + 1);
91
+ }
92
+ return line;
93
+ });
94
+ return { escapedContent: escapedLines.join('\n'), escapedLineNums };
95
+ }
96
+
97
+
16
98
  /**
17
99
  * Parses context details from a context message section.
18
100
  * @param {string} sectionText - The text content of a single context section (starting from the file header).
@@ -173,8 +255,84 @@ function extractContextItemsOverviewTableRows(messageContent) {
173
255
  return rows;
174
256
  }
175
257
 
258
+ /**
259
+ * Formats content for context based on content type.
260
+ * This function is adapted from the original `formatContentForContext` in `formatterUtils.js`.
261
+ *
262
+ * @param {Array<Object>} items - Array of loaded items, each with `chatId`, `name`, `content`, `meta`, `repo` (from chatsApi.getBlobDetailsByChatIds).
263
+ * @param {string} contentType - Type of content ('file content' or 'overview'). For batch analysis, always 'file content'.
264
+ * @param {string} contentOption - Option for the content type. For batch analysis, always 'imported'.
265
+ * @returns {string} Formatted text for context.
266
+ */
267
+ function formatContextContent(items, contentType, contentOption) {
268
+ if (items.length === 0) {
269
+ return 'No content loaded';
270
+ }
271
+
272
+ let result = '';
273
+
274
+ // Header based on content type
275
+ if (contentType === 'overview') {
276
+ const label = contentOption === "long" ? "comprehensive" : "short";
277
+ result += `## OVERVIEW - ${contentOption.toUpperCase()}\n`;
278
+ } else {
279
+ result += `## FILE CONTENT - ${contentOption.toUpperCase()}\n`;
280
+ }
281
+
282
+ // Summary of items
283
+ result += _createContextSummary(items, contentType);
284
+ result += "\n---Start of Context---\n\n";
285
+
286
+ items.forEach((item, index) => {
287
+ // Ensure item has necessary properties, especially meta and repo
288
+ const itemMeta = item.meta || {};
289
+ const itemRepo = item.repo || {};
290
+
291
+ result += "#### `"+item.name+"`\n";
292
+
293
+ const { escapedContent, escapedLineNums } = _escapeCodeBlocks(item.content);
294
+
295
+ // Always include metadata for batch analysis context
296
+ result +=
297
+ `- Repo: ${itemRepo.fullName || 'N/A'}\n`+
298
+ `- Path: ${itemMeta.path || 'N/A'}\n`;
299
+
300
+ // Size and Tokens are specific to 'file content'
301
+ if (contentType === 'file content') {
302
+ result += `- Size: ${_formatBytes(itemMeta.size)}\n`;
303
+ result += `- Tokens: ${itemMeta.tokens?.content?.estimate || 'N/A'}\n`;
304
+ } else {
305
+ const type = itemMeta.type || 'unknown';
306
+ result += `- Type: ${type === 'git-blob' ? 'file' : type === 'git-tree' || type === 'git-ref' ? 'directory' : type }\n`;
307
+ result += `- Tokens: ${itemMeta.tokens?.analysis?.[contentOption.toLowerCase()]?.estimate || 'N/A'}\n`;
308
+ }
309
+
310
+ result += `- Chat ID: ${item.chatId}\n`;
311
+
312
+ if (escapedLineNums.length) {
313
+ result += `- Escaped Lines: ${escapedLineNums.join(',')}\n`;
314
+ }
315
+
316
+ result += '\n';
317
+
318
+ // The original formatterUtils had a special summary handling.
319
+ // For batch analysis, we want the full file content.
320
+ // The `if (!escapedContent.includes('Component: New Analyzer Chat') && escapedContent.match(summary))`
321
+ // logic is specific to the frontend's overview builder and should not be applied here.
322
+ result += "```"+(itemMeta.highlight || '')+"\n"+escapedContent+"\n```";
323
+
324
+ if (index !== items.length - 1) {
325
+ result += '\n---End of Item---\n';
326
+ }
327
+ });
328
+
329
+ return result;
330
+ }
331
+
332
+
176
333
  module.exports = {
177
334
  parseContextSection,
178
335
  extractContextSections,
179
- extractContextItemsOverviewTableRows
336
+ extractContextItemsOverviewTableRows,
337
+ formatContextContent, // Export the new method
180
338
  };
@@ -2,11 +2,11 @@
2
2
  * Component: GitSenseChatUtils
3
3
  * Block-UUID: 5e8d1a9c-0b3f-4e1a-8c7d-9f0b2e1d3a4b
4
4
  * Parent-UUID: 7a9b1c8e-f1a4-4b2d-9e8f-6f7a0b1c2d3f
5
- * Version: 2.1.3
5
+ * Version: 2.1.4
6
6
  * 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 and EnvUtils.
7
7
  * Language: JavaScript
8
8
  * Created-at: 2025-04-15T16:04:26.780Z
9
- * 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)
9
+ * 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)
10
10
  */
11
11
 
12
12
 
@@ -63,6 +63,8 @@ const {
63
63
  getAnalyzerSchema,
64
64
  deleteAnalyzer,
65
65
  getAnalyzerInstructionsContent,
66
+ getSystemMessageContent,
67
+ getStartMessageContent,
66
68
  saveAnalyzerConfiguration,
67
69
  } = AnalyzerUtils;
68
70
 
@@ -122,6 +124,13 @@ const {
122
124
  getApiKey
123
125
  } = EnvUtils;
124
126
 
127
+ const {
128
+ parseContextSection,
129
+ extractContextSections,
130
+ extractContextItemsOverviewTableRows,
131
+ formatContextContent,
132
+ } = ContextUtils;
133
+
125
134
 
126
135
  /**
127
136
  * GitSenseChatUtils class provides a unified interface to code block and patch utilities.
@@ -398,6 +407,8 @@ module.exports = {
398
407
  getAnalyzerSchema,
399
408
  deleteAnalyzer,
400
409
  getAnalyzerInstructionsContent,
410
+ getSystemMessageContent,
411
+ getStartMessageContent,
401
412
 
402
413
  // ChatUtils
403
414
  getChatMessages,
@@ -430,6 +441,9 @@ module.exports = {
430
441
  loadEnv,
431
442
  getApiKey,
432
443
 
433
- // Note: Internal helpers like findAllCodeFences, matchFencesAndExtractBlocks are
434
- // typically not exported directly from the facade but are available via CodeBlockUtils object.
444
+ // Context Utils
445
+ parseContextSection,
446
+ extractContextSections,
447
+ extractContextItemsOverviewTableRows,
448
+ formatContextContent,
435
449
  };