@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.
@@ -16,8 +16,8 @@ function getDefaultExportFromCjs (x) {
16
16
  * Authors: Claude 3.7 Sonnet (v1.0.0), Gemini 2.5 Pro (v1.1.0), Gemini 2.5 Flash Thinking (v1.2.0)
17
17
  */
18
18
 
19
- const fs$7 = require$$0;
20
- const path$5 = require$$1;
19
+ const fs$8 = require$$0;
20
+ const path$6 = require$$1;
21
21
  const ANALYZE_MESSAGE_REGEXP = /^# Analyze - `([^`]+)`\n/;
22
22
 
23
23
  /**
@@ -51,12 +51,12 @@ function unescapeCodeBlocks(content) {
51
51
  * @returns {Array} An array of message objects with role and content properties
52
52
  */
53
53
  function getChatTemplateMessages$1(dirname, messageType) {
54
- const messagesDir = path$5.join(dirname, messageType);
54
+ const messagesDir = path$6.join(dirname, messageType);
55
55
  const messages = [];
56
56
 
57
57
  try {
58
58
  // Read all files in the directory
59
- const files = fs$7.readdirSync(messagesDir);
59
+ const files = fs$8.readdirSync(messagesDir);
60
60
 
61
61
  // Sort files numerically (1.md, 2.md, etc.)
62
62
  const sortedFiles = files.sort((a, b) => {
@@ -67,9 +67,9 @@ function getChatTemplateMessages$1(dirname, messageType) {
67
67
 
68
68
  // Process each file
69
69
  for (const file of sortedFiles) {
70
- if (path$5.extname(file) === '.md') {
71
- const filePath = path$5.join(messagesDir, file);
72
- const fileContent = fs$7.readFileSync(filePath, 'utf8');
70
+ if (path$6.extname(file) === '.md') {
71
+ const filePath = path$6.join(messagesDir, file);
72
+ const fileContent = fs$8.readFileSync(filePath, 'utf8');
73
73
 
74
74
  // Split by triple newline to separate metadata from content
75
75
  const parts = fileContent.split('\n\n\n');
@@ -10453,26 +10453,108 @@ var CodeBlockUtils$4 = {
10453
10453
  removeLineNumbers: removeLineNumbers$1,
10454
10454
  };
10455
10455
 
10456
- /**
10456
+ /*
10457
10457
  * Component: ContextUtils
10458
10458
  * Block-UUID: c199efe3-003c-4226-af3c-d460392a6569
10459
10459
  * Parent-UUID: N/A
10460
- * Version: 1.0.0
10461
- * Description: Provides utility functions for parsing context message sections to extract file details and code blocks.
10460
+ * Version: 1.1.0
10461
+ * Description: Provides utility functions for parsing context message sections to extract file details and code blocks, and for formatting content for LLM context.
10462
10462
  * Language: JavaScript
10463
10463
  * Created-at: 2025-05-09T01:36:20.107Z
10464
- * Authors: Gemini 2.5 Flash Thinking (v1.0.0)
10464
+ * Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash (v1.1.0)
10465
10465
  */
10466
10466
 
10467
10467
  const CodeBlockUtils$3 = CodeBlockUtils$4;
10468
10468
  const MessageUtils$2 = MessageUtils$3;
10469
10469
 
10470
+ /**
10471
+ * Formats bytes into human-readable string (KB, MB, GB)
10472
+ * @param {number} bytes - Number of bytes
10473
+ * @returns {string} Formatted size string
10474
+ */
10475
+ function _formatBytes(bytes) {
10476
+ if (typeof bytes !== 'number' || isNaN(bytes)) return '0 bytes';
10477
+ if (bytes === 0) return '0 bytes';
10478
+
10479
+ const k = 1024;
10480
+ const sizes = ['bytes', 'KB', 'MB', 'GB'];
10481
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
10482
+
10483
+ // Special case for bytes (no decimal)
10484
+ if (i === 0) return `${bytes} ${sizes[i]}`;
10485
+
10486
+ const value = bytes / Math.pow(k, i);
10487
+ // Show no decimal if whole number
10488
+ const decimalPlaces = value % 1 === 0 ? 0 : 1;
10489
+ return `${value.toFixed(decimalPlaces)} ${sizes[i]}`;
10490
+ }
10491
+
10492
+ /**
10493
+ * Creates a summary of items for human readers
10494
+ * @param {Array} items - Array of loaded items
10495
+ * @param {string} contentType - Content type
10496
+ * @returns {string} Human-readable summary
10497
+ */
10498
+ function _createContextSummary(items, contentType) {
10499
+ if (items.length === 0) return '';
10500
+
10501
+ // Group by files and trees
10502
+ const files = items.filter(item => item.metadata?.type === 'git-blob');
10503
+ const trees = items.filter(item => item.metadata?.type === 'git-tree' || item.metadata?.type === 'git-ref');
10504
+
10505
+ // Calculate total size and tokens
10506
+ const totalSize = items.reduce((sum, item) => sum + (item.size || 0), 0);
10507
+ const totalTokens = items.reduce((sum, item) => sum + (item.tokenCount || 0), 0);
10508
+
10509
+ let summary = contentType === 'file content'
10510
+ ? `\n**Summary:** ${items.length} file${items.length === 1 ? '' : 's'} (${_formatBytes(totalSize)}, ${totalTokens.toLocaleString()} tokens)\n\n`
10511
+ : `\n**Summary:** ${files.length} file${files.length === 1 ? '' : 's'} - ${trees.length} tree${trees.length === 1 ? '' : 's'}\n\n`;
10512
+
10513
+ // Add brief description of first X files
10514
+ const maxFiles = 10;
10515
+ const displayItems = items.slice(0, maxFiles);
10516
+ if (displayItems.length > 0) {
10517
+ displayItems.forEach(item => {
10518
+ if (item.tokenCount) {
10519
+ summary += `- ${item.name} - ${_formatBytes(item.size)}, ${item.tokenCount.toLocaleString()} tokens\n`;
10520
+ } else {
10521
+ summary += `- ${item.name} - Not analyzed\n`;
10522
+ }
10523
+ });
10524
+
10525
+ // Add note if there are more files
10526
+ if (items.length > maxFiles) {
10527
+ summary += `- ... and ${items.length - maxFiles} more\n`;
10528
+ }
10529
+ }
10530
+
10531
+ return summary + "\n";
10532
+ }
10533
+
10534
+ /**
10535
+ * Escapes backticks in code blocks to prevent premature termination of LLM-generated code blocks.
10536
+ * @param {string} content - The content string to escape.
10537
+ * @returns {{escapedContent: string, escapedLineNums: Array<number>}} Object with escaped content and line numbers of escaped lines.
10538
+ */
10539
+ function _escapeCodeBlocks(content) {
10540
+ const escapedLineNums = [];
10541
+ const escapedLines = content.replace(/\n$/, '').split('\n').map((line, i) => {
10542
+ if (line.trimStart().startsWith('```')) {
10543
+ line = '\\' + line.trimStart();
10544
+ escapedLineNums.push(i + 1);
10545
+ }
10546
+ return line;
10547
+ });
10548
+ return { escapedContent: escapedLines.join('\n'), escapedLineNums };
10549
+ }
10550
+
10551
+
10470
10552
  /**
10471
10553
  * Parses context details from a context message section.
10472
10554
  * @param {string} sectionText - The text content of a single context section (starting from the file header).
10473
10555
  * @returns {Object|null} An object with file details (name, path, meta, content) or null if parsing fails.
10474
10556
  */
10475
- function parseContextSection(sectionText) {
10557
+ function parseContextSection$1(sectionText) {
10476
10558
  const contextSection = {
10477
10559
  name: 'Unknown File',
10478
10560
  content: null,
@@ -10548,7 +10630,7 @@ function parseContextSection(sectionText) {
10548
10630
  * @returns {Array<Object>} An array of parsed context section objects.
10549
10631
  * @throws {Error} If the message content is not a valid context message.
10550
10632
  */
10551
- function extractContextSections(messageContent) {
10633
+ function extractContextSections$1(messageContent) {
10552
10634
  // Use the utility function to validate the message type
10553
10635
  if (!MessageUtils$2.isContextMessage(messageContent)) {
10554
10636
  throw new Error("Invalid message type: Content is not a context message.");
@@ -10562,7 +10644,7 @@ function extractContextSections(messageContent) {
10562
10644
 
10563
10645
  // Process sections starting from the first potential path delimiter.
10564
10646
  for (let i = 0; i < sections.length; i++) {
10565
- const contextSection = parseContextSection(sections[i]);
10647
+ const contextSection = parseContextSection$1(sections[i]);
10566
10648
 
10567
10649
  if (contextSection) {
10568
10650
  contextSections.push(contextSection);
@@ -10577,7 +10659,7 @@ function extractContextSections(messageContent) {
10577
10659
  return contextSections;
10578
10660
  }
10579
10661
 
10580
- function extractContextItemsOverviewTableRows(messageContent) {
10662
+ function extractContextItemsOverviewTableRows$1(messageContent) {
10581
10663
  const lines = messageContent.trim().split('\n');
10582
10664
  const startIndex = lines.findIndex(line => line.startsWith('---Start of Overview Items---')) + 4;
10583
10665
 
@@ -10627,10 +10709,85 @@ function extractContextItemsOverviewTableRows(messageContent) {
10627
10709
  return rows;
10628
10710
  }
10629
10711
 
10712
+ /**
10713
+ * Formats content for context based on content type.
10714
+ * This function is adapted from the original `formatContentForContext` in `formatterUtils.js`.
10715
+ *
10716
+ * @param {Array<Object>} items - Array of loaded items, each with `chatId`, `name`, `content`, `meta`, `repo` (from chatsApi.getBlobDetailsByChatIds).
10717
+ * @param {string} contentType - Type of content ('file content' or 'overview'). For batch analysis, always 'file content'.
10718
+ * @param {string} contentOption - Option for the content type. For batch analysis, always 'imported'.
10719
+ * @returns {string} Formatted text for context.
10720
+ */
10721
+ function formatContextContent$1(items, contentType, contentOption) {
10722
+ if (items.length === 0) {
10723
+ return 'No content loaded';
10724
+ }
10725
+
10726
+ let result = '';
10727
+
10728
+ // Header based on content type
10729
+ if (contentType === 'overview') {
10730
+ result += `## OVERVIEW - ${contentOption.toUpperCase()}\n`;
10731
+ } else {
10732
+ result += `## FILE CONTENT - ${contentOption.toUpperCase()}\n`;
10733
+ }
10734
+
10735
+ // Summary of items
10736
+ result += _createContextSummary(items, contentType);
10737
+ result += "\n---Start of Context---\n\n";
10738
+
10739
+ items.forEach((item, index) => {
10740
+ // Ensure item has necessary properties, especially meta and repo
10741
+ const itemMeta = item.meta || {};
10742
+ const itemRepo = item.repo || {};
10743
+
10744
+ result += "#### `"+item.name+"`\n";
10745
+
10746
+ const { escapedContent, escapedLineNums } = _escapeCodeBlocks(item.content);
10747
+
10748
+ // Always include metadata for batch analysis context
10749
+ result +=
10750
+ `- Repo: ${itemRepo.fullName || 'N/A'}\n`+
10751
+ `- Path: ${itemMeta.path || 'N/A'}\n`;
10752
+
10753
+ // Size and Tokens are specific to 'file content'
10754
+ if (contentType === 'file content') {
10755
+ result += `- Size: ${_formatBytes(itemMeta.size)}\n`;
10756
+ result += `- Tokens: ${itemMeta.tokens?.content?.estimate || 'N/A'}\n`;
10757
+ } else {
10758
+ const type = itemMeta.type || 'unknown';
10759
+ result += `- Type: ${type === 'git-blob' ? 'file' : type === 'git-tree' || type === 'git-ref' ? 'directory' : type }\n`;
10760
+ result += `- Tokens: ${itemMeta.tokens?.analysis?.[contentOption.toLowerCase()]?.estimate || 'N/A'}\n`;
10761
+ }
10762
+
10763
+ result += `- Chat ID: ${item.chatId}\n`;
10764
+
10765
+ if (escapedLineNums.length) {
10766
+ result += `- Escaped Lines: ${escapedLineNums.join(',')}\n`;
10767
+ }
10768
+
10769
+ result += '\n';
10770
+
10771
+ // The original formatterUtils had a special summary handling.
10772
+ // For batch analysis, we want the full file content.
10773
+ // The `if (!escapedContent.includes('Component: New Analyzer Chat') && escapedContent.match(summary))`
10774
+ // logic is specific to the frontend's overview builder and should not be applied here.
10775
+ result += "```"+(itemMeta.highlight || '')+"\n"+escapedContent+"\n```";
10776
+
10777
+ if (index !== items.length - 1) {
10778
+ result += '\n---End of Item---\n';
10779
+ }
10780
+ });
10781
+
10782
+ return result;
10783
+ }
10784
+
10785
+
10630
10786
  var ContextUtils$2 = {
10631
- parseContextSection,
10632
- extractContextSections,
10633
- extractContextItemsOverviewTableRows
10787
+ parseContextSection: parseContextSection$1,
10788
+ extractContextSections: extractContextSections$1,
10789
+ extractContextItemsOverviewTableRows: extractContextItemsOverviewTableRows$1,
10790
+ formatContextContent: formatContextContent$1, // Export the new method
10634
10791
  };
10635
10792
 
10636
10793
  /*
@@ -10923,8 +11080,8 @@ var dataValidator = {
10923
11080
  * Authors: Gemini 2.5 Flash (v1.0.0)
10924
11081
  */
10925
11082
 
10926
- const fs$6 = require$$0.promises;
10927
- const path$4 = require$$1;
11083
+ const fs$7 = require$$0.promises;
11084
+ const path$5 = require$$1;
10928
11085
 
10929
11086
  /**
10930
11087
  * Reads and parses the config.json file in a directory.
@@ -10933,9 +11090,9 @@ const path$4 = require$$1;
10933
11090
  * or null if the file doesn't exist or is invalid.
10934
11091
  */
10935
11092
  async function readConfig$1(dirPath) {
10936
- const configPath = path$4.join(dirPath, 'config.json');
11093
+ const configPath = path$5.join(dirPath, 'config.json');
10937
11094
  try {
10938
- const fileContent = await fs$6.readFile(configPath, 'utf8');
11095
+ const fileContent = await fs$7.readFile(configPath, 'utf8');
10939
11096
  return JSON.parse(fileContent);
10940
11097
  } catch (error) {
10941
11098
  if (error.code !== 'ENOENT') {
@@ -10972,41 +11129,41 @@ async function getAnalyzers$2(analyzeMessagesBasePath) {
10972
11129
  const analyzers = [];
10973
11130
 
10974
11131
  try {
10975
- const analyzerEntries = await fs$6.readdir(analyzeMessagesBasePath, { withFileTypes: true });
11132
+ const analyzerEntries = await fs$7.readdir(analyzeMessagesBasePath, { withFileTypes: true });
10976
11133
 
10977
11134
  for (const analyzerEntry of analyzerEntries) {
10978
11135
  if (analyzerEntry.isDirectory() && isValidDirName(analyzerEntry.name)) {
10979
11136
  const analyzerName = analyzerEntry.name;
10980
- const analyzerPath = path$4.join(analyzeMessagesBasePath, analyzerName);
11137
+ const analyzerPath = path$5.join(analyzeMessagesBasePath, analyzerName);
10981
11138
  const analyzerConfig = await readConfig$1(analyzerPath);
10982
11139
  const analyzerLabel = analyzerConfig?.label || analyzerName;
10983
11140
 
10984
- const contentEntries = await fs$6.readdir(analyzerPath, { withFileTypes: true });
11141
+ const contentEntries = await fs$7.readdir(analyzerPath, { withFileTypes: true });
10985
11142
 
10986
11143
  for (const contentEntry of contentEntries) {
10987
11144
  if (contentEntry.isDirectory() && isValidDirName(contentEntry.name)) {
10988
11145
  const contentType = contentEntry.name;
10989
- const contentPath = path$4.join(analyzerPath, contentType);
11146
+ const contentPath = path$5.join(analyzerPath, contentType);
10990
11147
  const contentConfig = await readConfig$1(contentPath);
10991
11148
  const contentLabel = contentConfig?.label || contentType;
10992
11149
 
10993
- const instructionsEntries = await fs$6.readdir(contentPath, { withFileTypes: true });
11150
+ const instructionsEntries = await fs$7.readdir(contentPath, { withFileTypes: true });
10994
11151
 
10995
11152
  for (const instructionsEntry of instructionsEntries) {
10996
11153
  if (instructionsEntry.isDirectory() && isValidDirName(instructionsEntry.name)) {
10997
11154
  const instructionsType = instructionsEntry.name;
10998
- const instructionsPath = path$4.join(contentPath, instructionsType);
11155
+ const instructionsPath = path$5.join(contentPath, instructionsType);
10999
11156
  const instructionsConfig = await readConfig$1(instructionsPath);
11000
11157
  const instructionsLabel = instructionsConfig?.label || instructionsType;
11001
11158
 
11002
11159
  // Check for the existence of 1.md to confirm a valid analyzer configuration
11003
- const instructionsFilePath = path$4.join(instructionsPath, '1.md');
11160
+ const instructionsFilePath = path$5.join(instructionsPath, '1.md');
11004
11161
  try {
11005
- await fs$6.access(instructionsFilePath); // Check if file exists and is accessible
11162
+ await fs$7.access(instructionsFilePath); // Check if file exists and is accessible
11006
11163
 
11007
11164
  // If analyzerName starts with 'tutorial-', check its last modified time.
11008
11165
  if (analyzerName.startsWith('tutorial-')) {
11009
- const stats = await fs$6.stat(instructionsFilePath);
11166
+ const stats = await fs$7.stat(instructionsFilePath);
11010
11167
  const lastModified = stats.mtime.getTime(); // Get timestamp in milliseconds
11011
11168
  const sixtyMinutesAgo = Date.now() - (60 * 60 * 1000); // Current time - 60 minutes in ms
11012
11169
 
@@ -11060,8 +11217,8 @@ var discovery = {
11060
11217
  * Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash Thinking (v1.1.0)
11061
11218
  */
11062
11219
 
11063
- const fs$5 = require$$0.promises;
11064
- const path$3 = require$$1;
11220
+ const fs$6 = require$$0.promises;
11221
+ const path$4 = require$$1;
11065
11222
 
11066
11223
  /**
11067
11224
  * Saves or updates an analyzer configuration.
@@ -11116,18 +11273,18 @@ async function saveConfiguration$1(analyzeMessagesBasePath, analyzerId, instruct
11116
11273
  }
11117
11274
 
11118
11275
  // 3. Construct directory paths
11119
- const analyzerDir = path$3.join(analyzeMessagesBasePath, analyzerName);
11120
- const contentDir = path$3.join(analyzerDir, contentType);
11121
- const instructionsDir = path$3.join(contentDir, instructionsType);
11122
- const instructionsFilePath = path$3.join(instructionsDir, '1.md');
11276
+ const analyzerDir = path$4.join(analyzeMessagesBasePath, analyzerName);
11277
+ const contentDir = path$4.join(analyzerDir, contentType);
11278
+ const instructionsDir = path$4.join(contentDir, instructionsType);
11279
+ const instructionsFilePath = path$4.join(instructionsDir, '1.md');
11123
11280
 
11124
11281
  try {
11125
11282
  // 4. Create directories recursively
11126
- await fs$5.mkdir(instructionsDir, { recursive: true });
11283
+ await fs$6.mkdir(instructionsDir, { recursive: true });
11127
11284
 
11128
11285
  // 5. Save instructions content to 1.md
11129
11286
  const finalContent = `; role: assistant\n\n\n${instructionsContent}`;
11130
- await fs$5.writeFile(instructionsFilePath, finalContent, 'utf8');
11287
+ await fs$6.writeFile(instructionsFilePath, finalContent, 'utf8');
11131
11288
 
11132
11289
  // 6. Optionally create/Update config.json files
11133
11290
  if (ensureConfigs) {
@@ -11153,11 +11310,11 @@ async function saveConfiguration$1(analyzeMessagesBasePath, analyzerId, instruct
11153
11310
  * @param {string} label - The label to ensure is in the config.json.
11154
11311
  */
11155
11312
  async function ensureConfigJson(dirPath, label) {
11156
- const configPath = path$3.join(dirPath, 'config.json');
11313
+ const configPath = path$4.join(dirPath, 'config.json');
11157
11314
  let config = {};
11158
11315
 
11159
11316
  try {
11160
- const fileContent = await fs$5.readFile(configPath, 'utf8');
11317
+ const fileContent = await fs$6.readFile(configPath, 'utf8');
11161
11318
  config = JSON.parse(fileContent);
11162
11319
  } catch (error) {
11163
11320
  // If file doesn't exist or parsing fails, start with an empty config
@@ -11174,7 +11331,7 @@ async function ensureConfigJson(dirPath, label) {
11174
11331
  }
11175
11332
 
11176
11333
  // Write the updated config back to the file
11177
- await fs$5.writeFile(configPath, JSON.stringify(config, null, 4), 'utf8');
11334
+ await fs$6.writeFile(configPath, JSON.stringify(config, null, 4), 'utf8');
11178
11335
  }
11179
11336
 
11180
11337
 
@@ -11193,8 +11350,8 @@ var saver = {
11193
11350
  * Authors: Gemini 2.5 Flash (v1.0.0)
11194
11351
  */
11195
11352
 
11196
- const fs$4 = require$$0.promises;
11197
- const path$2 = require$$1;
11353
+ const fs$5 = require$$0.promises;
11354
+ const path$3 = require$$1;
11198
11355
  const CodeBlockUtils$1 = CodeBlockUtils$4;
11199
11356
 
11200
11357
  /**
@@ -11280,10 +11437,10 @@ async function getAnalyzerSchema$2(analyzeMessagesBasePath, analyzerId) {
11280
11437
  }
11281
11438
  const [analyzerName, contentType, instructionsType] = parts;
11282
11439
 
11283
- const instructionsFilePath = path$2.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11440
+ const instructionsFilePath = path$3.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11284
11441
 
11285
11442
  try {
11286
- const fileContent = await fs$4.readFile(instructionsFilePath, 'utf8');
11443
+ const fileContent = await fs$5.readFile(instructionsFilePath, 'utf8');
11287
11444
  const { blocks } = CodeBlockUtils$1.extractCodeBlocks(fileContent, { silent: true });
11288
11445
  const jsonBlocks = blocks.filter(block => block.type === 'code' && block.language === 'json');
11289
11446
 
@@ -11354,8 +11511,8 @@ var schemaLoader = {
11354
11511
  * Authors: Gemini 2.5 Flash (v1.0.0)
11355
11512
  */
11356
11513
 
11357
- const fs$3 = require$$0.promises;
11358
- const path$1 = require$$1;
11514
+ const fs$4 = require$$0.promises;
11515
+ const path$2 = require$$1;
11359
11516
  const { readConfig } = discovery; // Import helper from discovery
11360
11517
 
11361
11518
  /**
@@ -11365,7 +11522,7 @@ const { readConfig } = discovery; // Import helper from discovery
11365
11522
  */
11366
11523
  async function isDirectoryEmpty(dirPath) {
11367
11524
  try {
11368
- const files = await fs$3.readdir(dirPath);
11525
+ const files = await fs$4.readdir(dirPath);
11369
11526
  return files.length === 0 || (files.length === 1 && files[0] === 'config.json');
11370
11527
  } catch (error) {
11371
11528
  if (error.code === 'ENOENT') {
@@ -11396,10 +11553,10 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11396
11553
  }
11397
11554
  const [analyzerName, contentType, instructionsType] = parts;
11398
11555
 
11399
- const analyzerDir = path$1.join(analyzeMessagesBasePath, analyzerName);
11400
- const contentDir = path$1.join(analyzerDir, contentType);
11401
- const instructionsDir = path$1.join(contentDir, instructionsType);
11402
- const instructionsFilePath = path$1.join(instructionsDir, '1.md');
11556
+ const analyzerDir = path$2.join(analyzeMessagesBasePath, analyzerName);
11557
+ const contentDir = path$2.join(analyzerDir, contentType);
11558
+ const instructionsDir = path$2.join(contentDir, instructionsType);
11559
+ const instructionsFilePath = path$2.join(instructionsDir, '1.md');
11403
11560
 
11404
11561
  try {
11405
11562
  // 1. Check for protection at all levels
@@ -11420,7 +11577,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11420
11577
 
11421
11578
  // 2. Delete the 1.md file
11422
11579
  try {
11423
- await fs$3.unlink(instructionsFilePath);
11580
+ await fs$4.unlink(instructionsFilePath);
11424
11581
  } catch (error) {
11425
11582
  if (error.code === 'ENOENT') {
11426
11583
  return { success: false, message: `Analyzer instructions file not found: ${instructionsFilePath}. It may have already been deleted.` };
@@ -11434,7 +11591,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11434
11591
  // Check and delete instructions directory
11435
11592
  if (await isDirectoryEmpty(instructionsDir)) {
11436
11593
  try {
11437
- await fs$3.rmdir(instructionsDir);
11594
+ await fs$4.rmdir(instructionsDir);
11438
11595
  deletedDirs.push(instructionsDir);
11439
11596
  } catch (error) {
11440
11597
  console.warn(`Warning: Could not remove empty instructions directory ${instructionsDir}: ${error.message}`);
@@ -11444,7 +11601,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11444
11601
  // Check and delete content directory
11445
11602
  if (await isDirectoryEmpty(contentDir)) {
11446
11603
  try {
11447
- await fs$3.rmdir(contentDir);
11604
+ await fs$4.rmdir(contentDir);
11448
11605
  deletedDirs.push(contentDir);
11449
11606
  } catch (error) {
11450
11607
  console.warn(`Warning: Could not remove empty content directory ${contentDir}: ${error.message}`);
@@ -11454,7 +11611,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11454
11611
  // Check and delete analyzer directory
11455
11612
  if (await isDirectoryEmpty(analyzerDir)) {
11456
11613
  try {
11457
- await fs$3.rmdir(analyzerDir);
11614
+ await fs$4.rmdir(analyzerDir);
11458
11615
  deletedDirs.push(analyzerDir);
11459
11616
  } catch (error) {
11460
11617
  console.warn(`Warning: Could not remove empty analyzer directory ${analyzerDir}: ${error.message}`);
@@ -11483,8 +11640,8 @@ var management = {
11483
11640
  * Authors: Gemini 2.5 Flash (v1.0.0)
11484
11641
  */
11485
11642
 
11486
- const fs$2 = require$$0.promises;
11487
- const path = require$$1;
11643
+ const fs$3 = require$$0.promises;
11644
+ const path$1 = require$$1;
11488
11645
 
11489
11646
  /**
11490
11647
  * Retrieves the raw Markdown content of the analyzer's '1.md' instruction file.
@@ -11510,10 +11667,10 @@ async function getAnalyzerInstructionsContent$2(analyzeMessagesBasePath, analyze
11510
11667
  }
11511
11668
  const [analyzerName, contentType, instructionsType] = parts;
11512
11669
 
11513
- const instructionsFilePath = path.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11670
+ const instructionsFilePath = path$1.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11514
11671
 
11515
11672
  try {
11516
- const fileContent = await fs$2.readFile(instructionsFilePath, 'utf8');
11673
+ const fileContent = await fs$3.readFile(instructionsFilePath, 'utf8');
11517
11674
  return fileContent;
11518
11675
  } catch (error) {
11519
11676
  if (error.code === 'ENOENT') {
@@ -11530,15 +11687,90 @@ var instructionLoader = {
11530
11687
  getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$2
11531
11688
  };
11532
11689
 
11690
+ /*
11691
+ * Component: AnalyzerUtils Default Prompt Loader
11692
+ * Block-UUID: 0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5f
11693
+ * Parent-UUID: N/A
11694
+ * Version: 1.0.0
11695
+ * Description: Provides utility functions for loading shared, default prompt components (system and start messages).
11696
+ * Language: JavaScript
11697
+ * Created-at: 2025-08-29T03:30:28.771Z
11698
+ * Authors: Gemini 2.5 Flash (v1.0.0)
11699
+ */
11700
+
11701
+ const fs$2 = require$$0.promises;
11702
+ const path = require$$1;
11703
+
11704
+ /**
11705
+ * Retrieves the raw Markdown content of the shared system message ('_shared/system/1.md').
11706
+ *
11707
+ * @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing analyzer message files (e.g., 'messages/analyze').
11708
+ * @returns {Promise<string|null>} A promise that resolves with the full Markdown content, or null if not found/invalid.
11709
+ */
11710
+ async function getSystemMessageContent$2(analyzeMessagesBasePath) {
11711
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
11712
+ console.error('Error: analyzeMessagesBasePath is required for getSystemMessageContent.');
11713
+ return null;
11714
+ }
11715
+
11716
+ const systemMessageFilePath = path.join(analyzeMessagesBasePath, '_shared', 'system', '1.md');
11717
+
11718
+ try {
11719
+ const fileContent = await fs$2.readFile(systemMessageFilePath, 'utf8');
11720
+ return fileContent;
11721
+ } catch (error) {
11722
+ if (error.code === 'ENOENT') {
11723
+ console.warn(`Default system message file not found: ${systemMessageFilePath}.`);
11724
+ return null;
11725
+ } else {
11726
+ console.error(`Error reading default system message file ${systemMessageFilePath}: ${error.message}`);
11727
+ throw error;
11728
+ }
11729
+ }
11730
+ }
11731
+
11732
+ /**
11733
+ * Retrieves the raw Markdown content of the shared start message ('_shared/start/1.md').
11734
+ *
11735
+ * @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing analyzer message files (e.g., 'messages/analyze').
11736
+ * @returns {Promise<string|null>} A promise that resolves with the full Markdown content, or null if not found/invalid.
11737
+ */
11738
+ async function getStartMessageContent$2(analyzeMessagesBasePath) {
11739
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
11740
+ console.error('Error: analyzeMessagesBasePath is required for getStartMessageContent.');
11741
+ return null;
11742
+ }
11743
+
11744
+ const startMessageFilePath = path.join(analyzeMessagesBasePath, '_shared', 'start', '1.md');
11745
+
11746
+ try {
11747
+ const fileContent = await fs$2.readFile(startMessageFilePath, 'utf8');
11748
+ return fileContent;
11749
+ } catch (error) {
11750
+ if (error.code === 'ENOENT') {
11751
+ console.warn(`Default start message file not found: ${startMessageFilePath}.`);
11752
+ return null;
11753
+ } else {
11754
+ console.error(`Error reading default start message file ${startMessageFilePath}: ${error.message}`);
11755
+ throw error;
11756
+ }
11757
+ }
11758
+ }
11759
+
11760
+ var defaultPromptLoader = {
11761
+ getSystemMessageContent: getSystemMessageContent$2,
11762
+ getStartMessageContent: getStartMessageContent$2
11763
+ };
11764
+
11533
11765
  /*
11534
11766
  * Component: AnalyzerUtils Index
11535
11767
  * Block-UUID: b403b6a1-230b-4247-8cd6-2a3d068f4bbf
11536
11768
  * Parent-UUID: N/A
11537
- * Version: 1.1.0
11769
+ * Version: 1.2.0
11538
11770
  * Description: Aggregates and exports all utility functions from the AnalyzerUtils module.
11539
11771
  * Language: JavaScript
11540
11772
  * Created-at: 2025-08-28T15:56:40.319Z
11541
- * Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0)
11773
+ * Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0), Gemini 2.5 Flash (v1.2.0)
11542
11774
  */
11543
11775
 
11544
11776
  const { buildChatIdToPathMap: buildChatIdToPathMap$1 } = contextMapper;
@@ -11549,6 +11781,7 @@ const { saveConfiguration } = saver;
11549
11781
  const { getAnalyzerSchema: getAnalyzerSchema$1 } = schemaLoader;
11550
11782
  const { deleteAnalyzer: deleteAnalyzer$1 } = management;
11551
11783
  const { getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1 } = instructionLoader;
11784
+ const { getSystemMessageContent: getSystemMessageContent$1, getStartMessageContent: getStartMessageContent$1 } = defaultPromptLoader; // NEW: Import default prompt loaders
11552
11785
 
11553
11786
  var AnalyzerUtils$1 = {
11554
11787
  buildChatIdToPathMap: buildChatIdToPathMap$1,
@@ -11559,6 +11792,8 @@ var AnalyzerUtils$1 = {
11559
11792
  deleteAnalyzer: deleteAnalyzer$1,
11560
11793
  getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1,
11561
11794
  saveConfiguration,
11795
+ getSystemMessageContent: getSystemMessageContent$1,
11796
+ getStartMessageContent: getStartMessageContent$1
11562
11797
  };
11563
11798
 
11564
11799
  /**
@@ -11769,11 +12004,11 @@ var EnvUtils$1 = {
11769
12004
  * Component: GitSenseChatUtils
11770
12005
  * Block-UUID: 5e8d1a9c-0b3f-4e1a-8c7d-9f0b2e1d3a4b
11771
12006
  * Parent-UUID: 7a9b1c8e-f1a4-4b2d-9e8f-6f7a0b1c2d3f
11772
- * Version: 2.1.3
12007
+ * Version: 2.1.4
11773
12008
  * 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.
11774
12009
  * Language: JavaScript
11775
12010
  * Created-at: 2025-04-15T16:04:26.780Z
11776
- * 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)
12011
+ * 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)
11777
12012
  */
11778
12013
 
11779
12014
  const ChatUtils = ChatUtils$1;
@@ -11829,6 +12064,8 @@ const {
11829
12064
  getAnalyzerSchema,
11830
12065
  deleteAnalyzer,
11831
12066
  getAnalyzerInstructionsContent,
12067
+ getSystemMessageContent,
12068
+ getStartMessageContent,
11832
12069
  saveAnalyzerConfiguration,
11833
12070
  } = AnalyzerUtils;
11834
12071
 
@@ -11888,6 +12125,13 @@ const {
11888
12125
  getApiKey
11889
12126
  } = EnvUtils;
11890
12127
 
12128
+ const {
12129
+ parseContextSection,
12130
+ extractContextSections,
12131
+ extractContextItemsOverviewTableRows,
12132
+ formatContextContent,
12133
+ } = ContextUtils;
12134
+
11891
12135
 
11892
12136
  /**
11893
12137
  * GitSenseChatUtils class provides a unified interface to code block and patch utilities.
@@ -12164,6 +12408,8 @@ var GitSenseChatUtils_1 = {
12164
12408
  getAnalyzerSchema,
12165
12409
  deleteAnalyzer,
12166
12410
  getAnalyzerInstructionsContent,
12411
+ getSystemMessageContent,
12412
+ getStartMessageContent,
12167
12413
 
12168
12414
  // ChatUtils
12169
12415
  getChatMessages,
@@ -12196,8 +12442,11 @@ var GitSenseChatUtils_1 = {
12196
12442
  loadEnv,
12197
12443
  getApiKey,
12198
12444
 
12199
- // Note: Internal helpers like findAllCodeFences, matchFencesAndExtractBlocks are
12200
- // typically not exported directly from the facade but are available via CodeBlockUtils object.
12445
+ // Context Utils
12446
+ parseContextSection,
12447
+ extractContextSections,
12448
+ extractContextItemsOverviewTableRows,
12449
+ formatContextContent,
12201
12450
  };
12202
12451
 
12203
12452
  var GitSenseChatUtils$1 = /*@__PURE__*/getDefaultExportFromCjs(GitSenseChatUtils_1);