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