@gitsense/gsc-utils 0.2.4 → 0.2.5

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$2 = require$$0;
20
- const path = require$$1;
19
+ const fs$6 = require$$0;
20
+ const path$4 = 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.join(dirname, messageType);
54
+ const messagesDir = path$4.join(dirname, messageType);
55
55
  const messages = [];
56
56
 
57
57
  try {
58
58
  // Read all files in the directory
59
- const files = fs$2.readdirSync(messagesDir);
59
+ const files = fs$6.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.extname(file) === '.md') {
71
- const filePath = path.join(messagesDir, file);
72
- const fileContent = fs$2.readFileSync(filePath, 'utf8');
70
+ if (path$4.extname(file) === '.md') {
71
+ const filePath = path$4.join(messagesDir, file);
72
+ const fileContent = fs$6.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');
@@ -10397,7 +10397,7 @@ const { updateCodeBlockByIndex: updateCodeBlockByIndex$1, updateCodeBlockByUUID,
10397
10397
  const { formatWithLineNumbers: formatWithLineNumbers$1, formatBlockWithLineNumbers: formatBlockWithLineNumbers$1, formatBlocksWithLineNumbers: formatBlocksWithLineNumbers$1, removeLineNumbers: removeLineNumbers$1 } = lineNumberFormatter;
10398
10398
 
10399
10399
  // Export all imported items
10400
- var CodeBlockUtils$3 = {
10400
+ var CodeBlockUtils$4 = {
10401
10401
  // Constants
10402
10402
  COMMENT_STYLES: COMMENT_STYLES$1,
10403
10403
 
@@ -10464,7 +10464,7 @@ var CodeBlockUtils$3 = {
10464
10464
  * Authors: Gemini 2.5 Flash Thinking (v1.0.0)
10465
10465
  */
10466
10466
 
10467
- const CodeBlockUtils$2 = CodeBlockUtils$3;
10467
+ const CodeBlockUtils$3 = CodeBlockUtils$4;
10468
10468
  const MessageUtils$2 = MessageUtils$3;
10469
10469
 
10470
10470
  /**
@@ -10521,7 +10521,7 @@ function parseContextSection(sectionText) {
10521
10521
  }
10522
10522
  });
10523
10523
 
10524
- const { blocks, warnings } = CodeBlockUtils$2.extractCodeBlocks(sectionText, { silent: true });
10524
+ const { blocks, warnings } = CodeBlockUtils$3.extractCodeBlocks(sectionText, { silent: true });
10525
10525
  const codeBlocks = blocks.filter(block => block.type === 'code');
10526
10526
 
10527
10527
  if (codeBlocks.length === 0) {
@@ -10654,7 +10654,7 @@ const ContextUtils$1 = ContextUtils$2;
10654
10654
  * @param {Array<Object>} allMessages - An array of all message objects in the chat.
10655
10655
  * @returns {Map<number, string>} A Map where keys are chat IDs (numbers) and values are file paths (strings).
10656
10656
  */
10657
- function buildChatIdToPathMap$1(allMessages) {
10657
+ function buildChatIdToPathMap$2(allMessages) {
10658
10658
  const chatIdToPathMap = new Map();
10659
10659
 
10660
10660
  for (const msg of allMessages) {
@@ -10681,7 +10681,7 @@ function buildChatIdToPathMap$1(allMessages) {
10681
10681
  }
10682
10682
 
10683
10683
  var contextMapper = {
10684
- buildChatIdToPathMap: buildChatIdToPathMap$1
10684
+ buildChatIdToPathMap: buildChatIdToPathMap$2
10685
10685
  };
10686
10686
 
10687
10687
  /*
@@ -10712,7 +10712,7 @@ var constants = {
10712
10712
  * Authors: Gemini 2.5 Flash (v1.0.0)
10713
10713
  */
10714
10714
 
10715
- const CodeBlockUtils$1 = CodeBlockUtils$3;
10715
+ const CodeBlockUtils$2 = CodeBlockUtils$4;
10716
10716
  const GSToolBlockUtils$1 = GSToolBlockUtils$3;
10717
10717
  const JsonUtils$1 = JsonUtils$2;
10718
10718
  const { ANALYZE_HEADER_PREFIX } = constants;
@@ -10727,9 +10727,9 @@ const { ANALYZE_HEADER_PREFIX } = constants;
10727
10727
  * @returns {{analysisBlocks: Array<Object>, analysisMetadataBlocks: Array<Object|null>, error: string|null}}
10728
10728
  * An object containing the extracted blocks and any processing error.
10729
10729
  */
10730
- function processLLMAnalysisResponse$1(messageContent, stoppedStreaming) {
10730
+ function processLLMAnalysisResponse$2(messageContent, stoppedStreaming) {
10731
10731
  const silent = { silent: true };
10732
- const { blocks, warnings } = CodeBlockUtils$1.extractCodeBlocks(messageContent, silent);
10732
+ const { blocks, warnings } = CodeBlockUtils$2.extractCodeBlocks(messageContent, silent);
10733
10733
 
10734
10734
  const analysisBlocks = [];
10735
10735
  const analysisMetadataBlocks = [];
@@ -10828,7 +10828,7 @@ function processLLMAnalysisResponse$1(messageContent, stoppedStreaming) {
10828
10828
  }
10829
10829
 
10830
10830
  var responseProcessor = {
10831
- processLLMAnalysisResponse: processLLMAnalysisResponse$1
10831
+ processLLMAnalysisResponse: processLLMAnalysisResponse$2
10832
10832
  };
10833
10833
 
10834
10834
  /*
@@ -10855,7 +10855,7 @@ const AnalysisBlockUtils$1 = AnalysisBlockUtils$3;
10855
10855
  * @returns {{validAnalysisData: Array<Object>, invalidAnalysisBlocks: Array<string|Object>}}
10856
10856
  * An object containing arrays of valid analysis data and invalid analysis blocks.
10857
10857
  */
10858
- function validateLLMAnalysisData$1(analysisBlocks, analysisMetadataBlocks, chatIdToPathMap) {
10858
+ function validateLLMAnalysisData$2(analysisBlocks, analysisMetadataBlocks, chatIdToPathMap) {
10859
10859
  const validAnalysisData = []; // Store data for the "Save All" button
10860
10860
  const invalidAnalysisBlocks = []; // Store invalid analysis blocks
10861
10861
 
@@ -10909,28 +10909,521 @@ function validateLLMAnalysisData$1(analysisBlocks, analysisMetadataBlocks, chatI
10909
10909
  }
10910
10910
 
10911
10911
  var dataValidator = {
10912
- validateLLMAnalysisData: validateLLMAnalysisData$1
10912
+ validateLLMAnalysisData: validateLLMAnalysisData$2
10913
+ };
10914
+
10915
+ /*
10916
+ * Component: AnalyzerUtils Discovery
10917
+ * Block-UUID: 0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5f
10918
+ * Parent-UUID: N/A
10919
+ * Version: 1.0.0
10920
+ * Description: Provides utility functions for discovering available analyzers.
10921
+ * Language: JavaScript
10922
+ * Created-at: 2025-08-28T23:48:00.000Z
10923
+ * Authors: Gemini 2.5 Flash (v1.0.0)
10924
+ */
10925
+
10926
+ const fs$5 = require$$0.promises;
10927
+ const path$3 = require$$1;
10928
+
10929
+ /**
10930
+ * Reads and parses the config.json file in a directory.
10931
+ * @param {string} dirPath - The path to the directory.
10932
+ * @returns {Promise<object|null>} A promise that resolves to the parsed config object
10933
+ * or null if the file doesn't exist or is invalid.
10934
+ */
10935
+ async function readConfig$1(dirPath) {
10936
+ const configPath = path$3.join(dirPath, 'config.json');
10937
+ try {
10938
+ const fileContent = await fs$5.readFile(configPath, 'utf8');
10939
+ return JSON.parse(fileContent);
10940
+ } catch (error) {
10941
+ if (error.code !== 'ENOENT') {
10942
+ // Log a warning if config.json exists but is malformed
10943
+ console.warn(`Warning: Failed to parse config.json in ${dirPath}: ${error.message}`);
10944
+ }
10945
+ return null; // Return null if file not found or parsing failed
10946
+ }
10947
+ }
10948
+
10949
+ /**
10950
+ * Checks if a directory name is valid based on the rules in messages/analyze/README.md.
10951
+ * Allowed: a-z, A-Z, 0-9, dash (-), underscore (_). Cannot start with underscore or contain dots.
10952
+ * @param {string} name - The directory name to check.
10953
+ * @returns {boolean} True if the name is valid, false otherwise.
10954
+ */
10955
+ function isValidDirName(name) {
10956
+ // Exclude names starting with underscore or containing dots
10957
+ if (name.startsWith('_') || name.includes('.')) {
10958
+ return false;
10959
+ }
10960
+ // Check for allowed characters
10961
+ return /^[a-zA-Z0-9_-]+$/.test(name);
10962
+ }
10963
+
10964
+ /**
10965
+ * Discovers and lists all available analyzers by traversing the directory structure.
10966
+ * An analyzer is considered valid if a '1.md' file exists in the instructions directory.
10967
+ *
10968
+ * @param {string} analyzeMessagesBasePath - The absolute or relative path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
10969
+ * @returns {Promise<Array<{id: string, label: string}>>} A promise that resolves to an array of analyzer objects.
10970
+ */
10971
+ async function getAnalyzers$2(analyzeMessagesBasePath) {
10972
+ const analyzers = [];
10973
+
10974
+ try {
10975
+ const analyzerEntries = await fs$5.readdir(analyzeMessagesBasePath, { withFileTypes: true });
10976
+
10977
+ for (const analyzerEntry of analyzerEntries) {
10978
+ if (analyzerEntry.isDirectory() && isValidDirName(analyzerEntry.name)) {
10979
+ const analyzerName = analyzerEntry.name;
10980
+ const analyzerPath = path$3.join(analyzeMessagesBasePath, analyzerName);
10981
+ const analyzerConfig = await readConfig$1(analyzerPath);
10982
+ const analyzerLabel = analyzerConfig?.label || analyzerName;
10983
+
10984
+ const contentEntries = await fs$5.readdir(analyzerPath, { withFileTypes: true });
10985
+
10986
+ for (const contentEntry of contentEntries) {
10987
+ if (contentEntry.isDirectory() && isValidDirName(contentEntry.name)) {
10988
+ const contentType = contentEntry.name;
10989
+ const contentPath = path$3.join(analyzerPath, contentType);
10990
+ const contentConfig = await readConfig$1(contentPath);
10991
+ const contentLabel = contentConfig?.label || contentType;
10992
+
10993
+ const instructionsEntries = await fs$5.readdir(contentPath, { withFileTypes: true });
10994
+
10995
+ for (const instructionsEntry of instructionsEntries) {
10996
+ if (instructionsEntry.isDirectory() && isValidDirName(instructionsEntry.name)) {
10997
+ const instructionsType = instructionsEntry.name;
10998
+ const instructionsPath = path$3.join(contentPath, instructionsType);
10999
+ const instructionsConfig = await readConfig$1(instructionsPath);
11000
+ const instructionsLabel = instructionsConfig?.label || instructionsType;
11001
+
11002
+ // Check for the existence of 1.md to confirm a valid analyzer configuration
11003
+ const instructionsFilePath = path$3.join(instructionsPath, '1.md');
11004
+ try {
11005
+ await fs$5.access(instructionsFilePath); // Check if file exists and is accessible
11006
+
11007
+ // If analyzerName starts with 'tutorial-', check its last modified time.
11008
+ if (analyzerName.startsWith('tutorial-')) {
11009
+ const stats = await fs$5.stat(instructionsFilePath);
11010
+ const lastModified = stats.mtime.getTime(); // Get timestamp in milliseconds
11011
+ const sixtyMinutesAgo = Date.now() - (60 * 60 * 1000); // Current time - 60 minutes in ms
11012
+
11013
+ if (lastModified < sixtyMinutesAgo) {
11014
+ // This tutorial analyzer has expired, skip it.
11015
+ continue;
11016
+ }
11017
+ }
11018
+ // Construct the analyzer ID and label
11019
+ const analyzerId = `${analyzerName}::${contentType}::${instructionsType}`;
11020
+ const analyzerFullLabel = `${analyzerLabel} (${contentLabel} - ${instructionsLabel})`;
11021
+
11022
+ analyzers.push({
11023
+ id: analyzerId,
11024
+ label: analyzerFullLabel,
11025
+ protected: analyzerConfig?.protected || false
11026
+ });
11027
+ } catch (error) {
11028
+ // If 1.md doesn't exist, this is not a complete analyzer configuration, skip.
11029
+ if (error.code !== 'ENOENT') {
11030
+ console.warn(`Warning: Error accessing 1.md for ${analyzerId}: ${error.message}`);
11031
+ }
11032
+ }
11033
+ }
11034
+ }
11035
+ }
11036
+ }
11037
+ }
11038
+ }
11039
+ } catch (error) {
11040
+ console.error(`Error traversing analyze messages directory ${analyzeMessagesBasePath}: ${error.message}`);
11041
+ // Depending on requirements, you might want to throw the error or return an empty array
11042
+ throw error; // Re-throw to indicate failure
11043
+ }
11044
+
11045
+ return analyzers;
11046
+ }
11047
+
11048
+ var discovery = {
11049
+ getAnalyzers: getAnalyzers$2,
11050
+ readConfig: readConfig$1};
11051
+
11052
+ /*
11053
+ * Component: AnalyzerUtils Schema Loader
11054
+ * Block-UUID: 0c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f
11055
+ * Parent-UUID: N/A
11056
+ * Version: 1.0.0
11057
+ * Description: Provides utility functions for retrieving and deducing JSON schemas for analyzers.
11058
+ * Language: JavaScript
11059
+ * Created-at: 2025-08-28T23:48:00.000Z
11060
+ * Authors: Gemini 2.5 Flash (v1.0.0)
11061
+ */
11062
+
11063
+ const fs$4 = require$$0.promises;
11064
+ const path$2 = require$$1;
11065
+ const CodeBlockUtils$1 = CodeBlockUtils$4;
11066
+
11067
+ /**
11068
+ * Deduces the JSON schema type and format/items from a string value pattern.
11069
+ * Handles patterns like "[string: ...]", "[number: ...]", "[datetime: ...]", "[<string>: ...]",
11070
+ * and boolean instructions. Defaults to 'string' for unknown patterns.
11071
+ *
11072
+ * @param {any} value - The value from the raw JSON (expected to be a string pattern).
11073
+ * @param {string} fieldName - The name of the field (for logging warnings).
11074
+ * @returns {{type: string, format?: string, items?: object}} An object describing the schema type and format/items.
11075
+ */
11076
+ function deduceSchemaType(value, fieldName) {
11077
+ const defaultSchema = { type: 'string' }; // Default fallback
11078
+
11079
+ if (typeof value !== 'string') {
11080
+ const jsType = typeof value;
11081
+ if (jsType === 'object' && value !== null) {
11082
+ console.warn(`Warning: Unexpected non-string, non-null object/array value for field "${fieldName}". Defaulting to type 'string'. Value:`, value);
11083
+ return defaultSchema;
11084
+ }
11085
+ return { type: jsType };
11086
+ }
11087
+
11088
+ const trimmedValue = value.trim();
11089
+
11090
+ if (/^\[string:.*\]$/.test(trimmedValue) || (/^\[[^:]+\]$/.test(trimmedValue) && !/^\[(number|datetime|date|<string>):.*\]$/.test(trimmedValue))) {
11091
+ return { type: 'string' };
11092
+ }
11093
+
11094
+ if (/^\[number:.*\]$/.test(trimmedValue)) {
11095
+ return { type: 'number' };
11096
+ }
11097
+
11098
+ if (/^\[boolean:.*\]$/.test(trimmedValue)) {
11099
+ return { type: 'boolean' };
11100
+ }
11101
+
11102
+ if (/^\[date-*time:.*\]$/.test(trimmedValue)) {
11103
+ return { type: 'string', format: 'date-time' };
11104
+ }
11105
+
11106
+ if (/^\[date:.*\]$/.test(trimmedValue)) {
11107
+ return { type: 'string', format: 'date' };
11108
+ }
11109
+
11110
+ if (/^\[<string>:.*\]$/.test(trimmedValue) || trimmedValue.toLowerCase().includes('array of strings')) {
11111
+ return { type: 'array', items: { type: 'string' } };
11112
+ }
11113
+
11114
+ if (trimmedValue.toLowerCase().includes("output 'true' or 'false'") || trimmedValue.toLowerCase().includes("determine if") && (trimmedValue.toLowerCase().includes("true") || trimmedValue.toLowerCase().includes("false"))) {
11115
+ return { type: 'boolean' };
11116
+ }
11117
+
11118
+ console.warn(`Warning: Unknown metadata value pattern for field "${fieldName}". Defaulting to type 'string'. Value: "${value}"`);
11119
+ return defaultSchema;
11120
+ }
11121
+
11122
+
11123
+ /**
11124
+ * Retrieves the JSON schema for a specific analyzer.
11125
+ * Reads the corresponding '1.md' file, extracts the JSON block,
11126
+ * and deduces schema types from the string values.
11127
+ *
11128
+ * @param {string} analyzeMessagesBasePath - The absolute or relative path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
11129
+ * @param {string} analyzerId - The unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
11130
+ * @returns {Promise<object|null>} A promise that resolves with the JSON schema object or null if the analyzer ID is invalid or the schema cannot be retrieved/parsed.
11131
+ * @throws {Error} If the 1.md file is found but does not contain exactly one JSON code block.
11132
+ */
11133
+ async function getAnalyzerSchema$2(analyzeMessagesBasePath, analyzerId) {
11134
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
11135
+ console.error('Error: analyzeMessagesBasePath is required.');
11136
+ return null;
11137
+ }
11138
+ if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
11139
+ console.error('Error: analyzerId is required.');
11140
+ return null;
11141
+ }
11142
+
11143
+ const parts = analyzerId.split('::');
11144
+ if (parts.length !== 3) {
11145
+ console.error(`Error: Invalid analyzerId format. Expected 'analyzer_name::content_type::instructions_type', but got '${analyzerId}'.`);
11146
+ return null;
11147
+ }
11148
+ const [analyzerName, contentType, instructionsType] = parts;
11149
+
11150
+ const instructionsFilePath = path$2.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11151
+
11152
+ try {
11153
+ const fileContent = await fs$4.readFile(instructionsFilePath, 'utf8');
11154
+ const { blocks } = CodeBlockUtils$1.extractCodeBlocks(fileContent, { silent: true });
11155
+ const jsonBlocks = blocks.filter(block => block.type === 'code' && block.language === 'json');
11156
+
11157
+ if (jsonBlocks.length !== 1) {
11158
+ throw new Error(`Expected exactly one JSON code block in ${instructionsFilePath}, but found ${jsonBlocks.length}.`);
11159
+ }
11160
+
11161
+ const jsonBlockContent = jsonBlocks[0].content;
11162
+ let rawJson = null;
11163
+ try {
11164
+ rawJson = JSON.parse(jsonBlockContent);
11165
+ } catch (parseError) {
11166
+ console.error(`Error parsing JSON content from ${instructionsFilePath}: ${parseError.message}`);
11167
+ return null;
11168
+ }
11169
+
11170
+ const schema = {
11171
+ type: 'object',
11172
+ description: rawJson.description,
11173
+ properties: {},
11174
+ required: []
11175
+ };
11176
+
11177
+ const metadataProperties = rawJson?.extracted_metadata;
11178
+
11179
+ if (metadataProperties && typeof metadataProperties === 'object') {
11180
+ for (const fieldName in metadataProperties) {
11181
+ if (Object.hasOwnProperty.call(metadataProperties, fieldName)) {
11182
+ const rawValue = metadataProperties[fieldName];
11183
+ const fieldSchema = deduceSchemaType(rawValue, fieldName);
11184
+ const description = rawValue.match(/^\[\w+: ([^\]]+)\]/)?.[1] || '';
11185
+
11186
+ schema.properties[fieldName] = {
11187
+ ...fieldSchema,
11188
+ description,
11189
+ title: fieldName.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())
11190
+ };
11191
+ }
11192
+ }
11193
+ } else {
11194
+ console.warn(`Warning: Could not find 'extracted_metadata' object in JSON block from ${instructionsFilePath}. Schema will be empty.`);
11195
+ }
11196
+
11197
+ return schema;
11198
+
11199
+ } catch (error) {
11200
+ if (error.code === 'ENOENT') {
11201
+ console.warn(`Analyzer instructions file not found: ${instructionsFilePath}`);
11202
+ return null;
11203
+ } else {
11204
+ console.error(`Error retrieving or processing schema for analyzer ${analyzerId}: ${error.message}`);
11205
+ throw error;
11206
+ }
11207
+ }
11208
+ }
11209
+
11210
+ var schemaLoader = {
11211
+ getAnalyzerSchema: getAnalyzerSchema$2};
11212
+
11213
+ /*
11214
+ * Component: AnalyzerUtils Management
11215
+ * Block-UUID: 0d1e2f3a-4b5c-6d7e-8f9a-0b1c2d3e4f5a
11216
+ * Parent-UUID: N/A
11217
+ * Version: 1.0.0
11218
+ * Description: Provides utility functions for managing (deleting) analyzer configurations.
11219
+ * Language: JavaScript
11220
+ * Created-at: 2025-08-28T23:48:00.000Z
11221
+ * Authors: Gemini 2.5 Flash (v1.0.0)
11222
+ */
11223
+
11224
+ const fs$3 = require$$0.promises;
11225
+ const path$1 = require$$1;
11226
+ const { readConfig } = discovery; // Import helper from discovery
11227
+
11228
+ /**
11229
+ * Checks if a directory is empty or only contains a config.json.
11230
+ * @param {string} dirPath - The path to the directory.
11231
+ * @returns {Promise<boolean>} True if the directory is empty or only contains config.json, false otherwise.
11232
+ */
11233
+ async function isDirectoryEmpty(dirPath) {
11234
+ try {
11235
+ const files = await fs$3.readdir(dirPath);
11236
+ return files.length === 0 || (files.length === 1 && files[0] === 'config.json');
11237
+ } catch (error) {
11238
+ if (error.code === 'ENOENT') {
11239
+ return true; // Directory doesn't exist, so it's "empty" for our purpose
11240
+ }
11241
+ throw error; // Re-throw other errors
11242
+ }
11243
+ }
11244
+
11245
+ /**
11246
+ * Deletes a specific analyzer configuration and intelligently cleans up empty directories.
11247
+ *
11248
+ * @param {string} analyzeMessagesBasePath - The absolute or relative path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
11249
+ * @param {string} analyzerId - The unique ID of the analyzer to delete (format: 'analyzer_name::content_type::instructions_type').
11250
+ * @returns {Promise<{success: boolean, message: string}>} A promise that resolves with a result object indicating success or failure.
11251
+ */
11252
+ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11253
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
11254
+ return { success: false, message: 'analyzeMessagesBasePath is required.' };
11255
+ }
11256
+ if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
11257
+ return { success: false, message: 'analyzerId is required.' };
11258
+ }
11259
+
11260
+ const parts = analyzerId.split('::');
11261
+ if (parts.length !== 3) {
11262
+ return { success: false, message: `Invalid analyzerId format. Expected 'analyzer_name::content_type::instructions_type', but got '${analyzerId}'.` };
11263
+ }
11264
+ const [analyzerName, contentType, instructionsType] = parts;
11265
+
11266
+ const analyzerDir = path$1.join(analyzeMessagesBasePath, analyzerName);
11267
+ const contentDir = path$1.join(analyzerDir, contentType);
11268
+ const instructionsDir = path$1.join(contentDir, instructionsType);
11269
+ const instructionsFilePath = path$1.join(instructionsDir, '1.md');
11270
+
11271
+ try {
11272
+ // 1. Check for protection at all levels
11273
+ const analyzerConfig = await readConfig(analyzerDir);
11274
+ if (analyzerConfig?.protected) {
11275
+ return { success: false, message: `Analyzer '${analyzerName}' is protected and cannot be deleted.` };
11276
+ }
11277
+
11278
+ const contentConfig = await readConfig(contentDir);
11279
+ if (contentConfig?.protected) {
11280
+ return { success: false, message: `Content type '${contentType}' for analyzer '${analyzerName}' is protected and cannot be deleted.` };
11281
+ }
11282
+
11283
+ const instructionsConfig = await readConfig(instructionsDir);
11284
+ if (instructionsConfig?.protected) {
11285
+ return { success: false, message: `Instructions type '${instructionsType}' for content type '${contentType}' is protected and cannot be deleted.` };
11286
+ }
11287
+
11288
+ // 2. Delete the 1.md file
11289
+ try {
11290
+ await fs$3.unlink(instructionsFilePath);
11291
+ } catch (error) {
11292
+ if (error.code === 'ENOENT') {
11293
+ return { success: false, message: `Analyzer instructions file not found: ${instructionsFilePath}. It may have already been deleted.` };
11294
+ }
11295
+ throw error; // Re-throw other errors
11296
+ }
11297
+
11298
+ // 3. Intelligently delete empty directories, cascading upwards
11299
+ let deletedDirs = [];
11300
+
11301
+ // Check and delete instructions directory
11302
+ if (await isDirectoryEmpty(instructionsDir)) {
11303
+ try {
11304
+ await fs$3.rmdir(instructionsDir);
11305
+ deletedDirs.push(instructionsDir);
11306
+ } catch (error) {
11307
+ console.warn(`Warning: Could not remove empty instructions directory ${instructionsDir}: ${error.message}`);
11308
+ }
11309
+ }
11310
+
11311
+ // Check and delete content directory
11312
+ if (await isDirectoryEmpty(contentDir)) {
11313
+ try {
11314
+ await fs$3.rmdir(contentDir);
11315
+ deletedDirs.push(contentDir);
11316
+ } catch (error) {
11317
+ console.warn(`Warning: Could not remove empty content directory ${contentDir}: ${error.message}`);
11318
+ }
11319
+ }
11320
+
11321
+ // Check and delete analyzer directory
11322
+ if (await isDirectoryEmpty(analyzerDir)) {
11323
+ try {
11324
+ await fs$3.rmdir(analyzerDir);
11325
+ deletedDirs.push(analyzerDir);
11326
+ } catch (error) {
11327
+ console.warn(`Warning: Could not remove empty analyzer directory ${analyzerDir}: ${error.message}`);
11328
+ }
11329
+ }
11330
+
11331
+ return { success: true, message: `Analyzer '${analyzerId}' deleted successfully. Cleaned up directories: ${deletedDirs.join(', ') || 'None'}.` };
11332
+
11333
+ } catch (error) {
11334
+ console.error(`Error deleting analyzer '${analyzerId}': ${error.message}`);
11335
+ return { success: false, message: `Failed to delete analyzer: ${error.message}` };
11336
+ }
11337
+ }
11338
+
11339
+ var management = {
11340
+ deleteAnalyzer: deleteAnalyzer$2};
11341
+
11342
+ /*
11343
+ * Component: AnalyzerUtils Instruction Loader
11344
+ * Block-UUID: 0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5e
11345
+ * Parent-UUID: N/A
11346
+ * Version: 1.0.0
11347
+ * Description: Provides utility functions for loading raw analyzer instruction content.
11348
+ * Language: JavaScript
11349
+ * Created-at: 2025-08-28T23:48:00.000Z
11350
+ * Authors: Gemini 2.5 Flash (v1.0.0)
11351
+ */
11352
+
11353
+ const fs$2 = require$$0.promises;
11354
+ const path = require$$1;
11355
+
11356
+ /**
11357
+ * Retrieves the raw Markdown content of the analyzer's '1.md' instruction file.
11358
+ *
11359
+ * @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
11360
+ * @param {string} analyzerId - The unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
11361
+ * @returns {Promise<string|null>} A promise that resolves with the full Markdown content of the '1.md' file, or null if not found/invalid.
11362
+ */
11363
+ async function getAnalyzerInstructionsContent$2(analyzeMessagesBasePath, analyzerId) {
11364
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
11365
+ console.error('Error: analyzeMessagesBasePath is required.');
11366
+ return null;
11367
+ }
11368
+ if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
11369
+ console.error('Error: analyzerId is required.');
11370
+ return null;
11371
+ }
11372
+
11373
+ const parts = analyzerId.split('::');
11374
+ if (parts.length !== 3) {
11375
+ console.error(`Error: Invalid analyzerId format. Expected 'analyzer_name::content_type::instructions_type', but got '${analyzerId}'.`);
11376
+ return null;
11377
+ }
11378
+ const [analyzerName, contentType, instructionsType] = parts;
11379
+
11380
+ const instructionsFilePath = path.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11381
+
11382
+ try {
11383
+ const fileContent = await fs$2.readFile(instructionsFilePath, 'utf8');
11384
+ return fileContent;
11385
+ } catch (error) {
11386
+ if (error.code === 'ENOENT') {
11387
+ console.warn(`Analyzer instructions file not found: ${instructionsFilePath}`);
11388
+ return null;
11389
+ } else {
11390
+ console.error(`Error reading analyzer instructions file ${instructionsFilePath}: ${error.message}`);
11391
+ throw error;
11392
+ }
11393
+ }
11394
+ }
11395
+
11396
+ var instructionLoader = {
11397
+ getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$2
10913
11398
  };
10914
11399
 
10915
11400
  /*
10916
11401
  * Component: AnalyzerUtils Index
10917
11402
  * Block-UUID: b403b6a1-230b-4247-8cd6-2a3d068f4bbf
10918
11403
  * Parent-UUID: N/A
10919
- * Version: 1.0.0
11404
+ * Version: 1.1.0
10920
11405
  * Description: Aggregates and exports all utility functions from the AnalyzerUtils module.
10921
11406
  * Language: JavaScript
10922
11407
  * Created-at: 2025-08-28T15:56:40.319Z
10923
- * Authors: Gemini 2.5 Flash (v1.0.0)
11408
+ * Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0)
10924
11409
  */
10925
11410
 
10926
- const { buildChatIdToPathMap } = contextMapper;
10927
- const { processLLMAnalysisResponse } = responseProcessor;
10928
- const { validateLLMAnalysisData } = dataValidator;
11411
+ const { buildChatIdToPathMap: buildChatIdToPathMap$1 } = contextMapper;
11412
+ const { processLLMAnalysisResponse: processLLMAnalysisResponse$1 } = responseProcessor;
11413
+ const { validateLLMAnalysisData: validateLLMAnalysisData$1 } = dataValidator;
11414
+ const { getAnalyzers: getAnalyzers$1 } = discovery;
11415
+ const { getAnalyzerSchema: getAnalyzerSchema$1 } = schemaLoader;
11416
+ const { deleteAnalyzer: deleteAnalyzer$1 } = management;
11417
+ const { getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1 } = instructionLoader;
10929
11418
 
10930
11419
  var AnalyzerUtils$1 = {
10931
- buildChatIdToPathMap,
10932
- processLLMAnalysisResponse,
10933
- validateLLMAnalysisData
11420
+ buildChatIdToPathMap: buildChatIdToPathMap$1,
11421
+ processLLMAnalysisResponse: processLLMAnalysisResponse$1,
11422
+ validateLLMAnalysisData: validateLLMAnalysisData$1,
11423
+ getAnalyzers: getAnalyzers$1,
11424
+ getAnalyzerSchema: getAnalyzerSchema$1,
11425
+ deleteAnalyzer: deleteAnalyzer$1,
11426
+ getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1,
10934
11427
  };
10935
11428
 
10936
11429
  /**
@@ -11141,19 +11634,19 @@ var EnvUtils$1 = {
11141
11634
  * Component: GitSenseChatUtils
11142
11635
  * Block-UUID: 5e8d1a9c-0b3f-4e1a-8c7d-9f0b2e1d3a4b
11143
11636
  * Parent-UUID: 7a9b1c8e-f1a4-4b2d-9e8f-6f7a0b1c2d3f
11144
- * Version: 2.1.2
11637
+ * Version: 2.1.3
11145
11638
  * 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.
11146
11639
  * Language: JavaScript
11147
11640
  * Created-at: 2025-04-15T16:04:26.780Z
11148
- * 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)
11641
+ * 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)
11149
11642
  */
11150
11643
 
11151
11644
  const ChatUtils = ChatUtils$1;
11152
- const CodeBlockUtils = CodeBlockUtils$3;
11645
+ const CodeBlockUtils = CodeBlockUtils$4;
11153
11646
  const ContextUtils = ContextUtils$2;
11154
11647
  const MessageUtils = MessageUtils$3;
11155
11648
  const AnalysisBlockUtils = AnalysisBlockUtils$3;
11156
- const AnalyzerUtils = AnalyzerUtils$1;
11649
+ const AnalyzerUtils = AnalyzerUtils$1; // Updated import
11157
11650
  const PatchUtils = PatchUtils$2;
11158
11651
  const GSToolBlockUtils = GSToolBlockUtils$3;
11159
11652
  const LLMUtils = LLMUtils$1;
@@ -11193,6 +11686,16 @@ const {
11193
11686
  validateOverviewMetadata,
11194
11687
  } = AnalysisBlockUtils;
11195
11688
 
11689
+ const { // Updated AnalyzerUtils destructuring
11690
+ buildChatIdToPathMap,
11691
+ processLLMAnalysisResponse,
11692
+ validateLLMAnalysisData,
11693
+ getAnalyzers,
11694
+ getAnalyzerSchema,
11695
+ deleteAnalyzer,
11696
+ getAnalyzerInstructionsContent,
11697
+ } = AnalyzerUtils;
11698
+
11196
11699
  const {
11197
11700
  COMMENT_STYLES,
11198
11701
  generateUUID,
@@ -11518,9 +12021,13 @@ var GitSenseChatUtils_1 = {
11518
12021
  validateOverviewMetadata,
11519
12022
 
11520
12023
  // Analyzer Utilities
11521
- buildChatIdToPathMap: AnalyzerUtils.buildChatIdToPathMap,
11522
- processLLMAnalysisResponse: AnalyzerUtils.processLLMAnalysisResponse,
11523
- validateLLMAnalysisData: AnalyzerUtils.validateLLMAnalysisData,
12024
+ buildChatIdToPathMap,
12025
+ processLLMAnalysisResponse,
12026
+ validateLLMAnalysisData,
12027
+ getAnalyzers,
12028
+ getAnalyzerSchema,
12029
+ deleteAnalyzer,
12030
+ getAnalyzerInstructionsContent,
11524
12031
 
11525
12032
  // ChatUtils
11526
12033
  getChatMessages,