@gitsense/gsc-utils 0.2.6 → 0.2.8

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$6 = require$$0;
22
- const path$4 = 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$4.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$6.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$4.extname(file) === '.md') {
73
- const filePath = path$4.join(messagesDir, file);
74
- const fileContent = fs$6.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');
@@ -10925,8 +10925,8 @@ var dataValidator = {
10925
10925
  * Authors: Gemini 2.5 Flash (v1.0.0)
10926
10926
  */
10927
10927
 
10928
- const fs$5 = require$$0.promises;
10929
- const path$3 = require$$1;
10928
+ const fs$7 = require$$0.promises;
10929
+ const path$5 = require$$1;
10930
10930
 
10931
10931
  /**
10932
10932
  * Reads and parses the config.json file in a directory.
@@ -10935,9 +10935,9 @@ const path$3 = require$$1;
10935
10935
  * or null if the file doesn't exist or is invalid.
10936
10936
  */
10937
10937
  async function readConfig$1(dirPath) {
10938
- const configPath = path$3.join(dirPath, 'config.json');
10938
+ const configPath = path$5.join(dirPath, 'config.json');
10939
10939
  try {
10940
- const fileContent = await fs$5.readFile(configPath, 'utf8');
10940
+ const fileContent = await fs$7.readFile(configPath, 'utf8');
10941
10941
  return JSON.parse(fileContent);
10942
10942
  } catch (error) {
10943
10943
  if (error.code !== 'ENOENT') {
@@ -10974,41 +10974,41 @@ async function getAnalyzers$2(analyzeMessagesBasePath) {
10974
10974
  const analyzers = [];
10975
10975
 
10976
10976
  try {
10977
- const analyzerEntries = await fs$5.readdir(analyzeMessagesBasePath, { withFileTypes: true });
10977
+ const analyzerEntries = await fs$7.readdir(analyzeMessagesBasePath, { withFileTypes: true });
10978
10978
 
10979
10979
  for (const analyzerEntry of analyzerEntries) {
10980
10980
  if (analyzerEntry.isDirectory() && isValidDirName(analyzerEntry.name)) {
10981
10981
  const analyzerName = analyzerEntry.name;
10982
- const analyzerPath = path$3.join(analyzeMessagesBasePath, analyzerName);
10982
+ const analyzerPath = path$5.join(analyzeMessagesBasePath, analyzerName);
10983
10983
  const analyzerConfig = await readConfig$1(analyzerPath);
10984
10984
  const analyzerLabel = analyzerConfig?.label || analyzerName;
10985
10985
 
10986
- const contentEntries = await fs$5.readdir(analyzerPath, { withFileTypes: true });
10986
+ const contentEntries = await fs$7.readdir(analyzerPath, { withFileTypes: true });
10987
10987
 
10988
10988
  for (const contentEntry of contentEntries) {
10989
10989
  if (contentEntry.isDirectory() && isValidDirName(contentEntry.name)) {
10990
10990
  const contentType = contentEntry.name;
10991
- const contentPath = path$3.join(analyzerPath, contentType);
10991
+ const contentPath = path$5.join(analyzerPath, contentType);
10992
10992
  const contentConfig = await readConfig$1(contentPath);
10993
10993
  const contentLabel = contentConfig?.label || contentType;
10994
10994
 
10995
- const instructionsEntries = await fs$5.readdir(contentPath, { withFileTypes: true });
10995
+ const instructionsEntries = await fs$7.readdir(contentPath, { withFileTypes: true });
10996
10996
 
10997
10997
  for (const instructionsEntry of instructionsEntries) {
10998
10998
  if (instructionsEntry.isDirectory() && isValidDirName(instructionsEntry.name)) {
10999
10999
  const instructionsType = instructionsEntry.name;
11000
- const instructionsPath = path$3.join(contentPath, instructionsType);
11000
+ const instructionsPath = path$5.join(contentPath, instructionsType);
11001
11001
  const instructionsConfig = await readConfig$1(instructionsPath);
11002
11002
  const instructionsLabel = instructionsConfig?.label || instructionsType;
11003
11003
 
11004
11004
  // Check for the existence of 1.md to confirm a valid analyzer configuration
11005
- const instructionsFilePath = path$3.join(instructionsPath, '1.md');
11005
+ const instructionsFilePath = path$5.join(instructionsPath, '1.md');
11006
11006
  try {
11007
- await fs$5.access(instructionsFilePath); // Check if file exists and is accessible
11007
+ await fs$7.access(instructionsFilePath); // Check if file exists and is accessible
11008
11008
 
11009
11009
  // If analyzerName starts with 'tutorial-', check its last modified time.
11010
11010
  if (analyzerName.startsWith('tutorial-')) {
11011
- const stats = await fs$5.stat(instructionsFilePath);
11011
+ const stats = await fs$7.stat(instructionsFilePath);
11012
11012
  const lastModified = stats.mtime.getTime(); // Get timestamp in milliseconds
11013
11013
  const sixtyMinutesAgo = Date.now() - (60 * 60 * 1000); // Current time - 60 minutes in ms
11014
11014
 
@@ -11062,12 +11062,128 @@ var discovery = {
11062
11062
  * Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash Thinking (v1.1.0)
11063
11063
  */
11064
11064
 
11065
- require$$0.promises;
11065
+ const fs$6 = require$$0.promises;
11066
+ const path$4 = require$$1;
11066
11067
 
11068
+ /**
11069
+ * Saves or updates an analyzer configuration.
11070
+ *
11071
+ * This function takes the analyzer ID and its full instructions content,
11072
+ * parses the ID to determine the directory structure, creates directories
11073
+ * if necessary, saves the instructions to '1.md'. Optionally, it can
11074
+ * ensure config.json files exist with labels derived from directory names.
11075
+ *
11076
+ * @param {string} analyzeMessagesBasePath - The absolute or relative path to the 'messages/analyze' directory.
11077
+ * @param {string} analyzerId - The unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
11078
+ * @param {string} instructionsContent - The full content of the analyzer instructions message to be saved in '1.md'.
11079
+ * @param {object} [options={}] - Optional configuration options.
11080
+ * @param {boolean} [options.ensureConfigs=false] - If true, ensures config.json files exist in the analyzer, content, and instructions directories. Defaults to false.
11081
+ * @returns {Promise<{success: boolean, message?: string}>} A promise that resolves with a result object.
11082
+ */
11083
+ async function saveConfiguration$1(analyzeMessagesBasePath, analyzerId, instructionsContent, options = {}) {
11084
+ const { ensureConfigs = false } = options;
11067
11085
 
11068
- var saver = {
11086
+ // 1. Validate inputs
11087
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
11088
+ return { success: false, message: 'analyzeMessagesBasePath is required.' };
11089
+ }
11090
+ if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
11091
+ return { success: false, message: 'analyzerId is required.' };
11092
+ }
11093
+ if (typeof instructionsContent !== 'string' || instructionsContent.trim() === '') {
11094
+ return { success: false, message: 'instructionsContent is required.' };
11095
+ }
11096
+
11097
+ // 2. Parse analyzerId
11098
+ const parts = analyzerId.split('::');
11099
+ if (parts.length !== 3) {
11100
+ return { success: false, message: `Invalid analyzerId format. Expected 'analyzer_name::content_type::instructions_type', but got '${analyzerId}'.` };
11101
+ }
11102
+ const [analyzerName, contentType, instructionsType] = parts;
11103
+
11104
+ // Helper to validate directory names based on README.md rules
11105
+ const isValidDirName = (name) => {
11106
+ // Cannot start with underscore, cannot contain dots, must be alphanumeric, dash, or underscore
11107
+ return /^[a-zA-Z0-9_-]+$/.test(name) && !name.startsWith('_') && !name.includes('.');
11069
11108
  };
11070
11109
 
11110
+ if (!isValidDirName(analyzerName)) {
11111
+ return { success: false, message: `Invalid analyzer name '${analyzerName}'. Names must be alphanumeric, dash, or underscore, cannot start with underscore, and cannot contain dots.` };
11112
+ }
11113
+ if (!isValidDirName(contentType)) {
11114
+ return { success: false, message: `Invalid content type name '${contentType}'. Names must be alphanumeric, dash, or underscore, cannot start with underscore, and cannot contain dots.` };
11115
+ }
11116
+ if (!isValidDirName(instructionsType)) {
11117
+ return { success: false, message: `Invalid instructions type name '${instructionsType}'. Names must be alphanumeric, dash, or underscore, cannot start with underscore, and cannot contain dots.` };
11118
+ }
11119
+
11120
+ // 3. Construct directory paths
11121
+ const analyzerDir = path$4.join(analyzeMessagesBasePath, analyzerName);
11122
+ const contentDir = path$4.join(analyzerDir, contentType);
11123
+ const instructionsDir = path$4.join(contentDir, instructionsType);
11124
+ const instructionsFilePath = path$4.join(instructionsDir, '1.md');
11125
+
11126
+ try {
11127
+ // 4. Create directories recursively
11128
+ await fs$6.mkdir(instructionsDir, { recursive: true });
11129
+
11130
+ // 5. Save instructions content to 1.md
11131
+ const finalContent = `; role: assistant\n\n\n${instructionsContent}`;
11132
+ await fs$6.writeFile(instructionsFilePath, finalContent, 'utf8');
11133
+
11134
+ // 6. Optionally create/Update config.json files
11135
+ if (ensureConfigs) {
11136
+ await ensureConfigJson(analyzerDir, analyzerName);
11137
+ await ensureConfigJson(contentDir, contentType);
11138
+ await ensureConfigJson(instructionsDir, instructionsType);
11139
+ }
11140
+
11141
+ return { success: true, message: `Analyzer configuration '${analyzerId}' saved successfully.` };
11142
+
11143
+ } catch (error) {
11144
+ console.error(`Error saving analyzer configuration '${analyzerId}':`, error);
11145
+ return { success: false, message: `Failed to save analyzer configuration: ${error.message}` };
11146
+ }
11147
+ }
11148
+
11149
+ /**
11150
+ * Ensures a config.json file exists in the given directory with a label.
11151
+ * If the file exists, it reads it and adds the label if missing.
11152
+ * If the file doesn't exist, it creates it with the label.
11153
+ *
11154
+ * @param {string} dirPath - The path to the directory.
11155
+ * @param {string} label - The label to ensure is in the config.json.
11156
+ */
11157
+ async function ensureConfigJson(dirPath, label) {
11158
+ const configPath = path$4.join(dirPath, 'config.json');
11159
+ let config = {};
11160
+
11161
+ try {
11162
+ const fileContent = await fs$6.readFile(configPath, 'utf8');
11163
+ config = JSON.parse(fileContent);
11164
+ } catch (error) {
11165
+ // If file doesn't exist or parsing fails, start with an empty config
11166
+ if (error.code !== 'ENOENT') {
11167
+ console.warn(`Failed to read or parse existing config.json in ${dirPath}: ${error.message}`);
11168
+ }
11169
+ config = {}; // Ensure config is an object even on error
11170
+ }
11171
+
11172
+ // Add or update the label if it's missing or empty
11173
+ if (!config.label || typeof config.label !== 'string' || config.label.trim() === '') {
11174
+ // Capitalize the first letter for the label
11175
+ config.label = label.charAt(0).toUpperCase() + label.slice(1);
11176
+ }
11177
+
11178
+ // Write the updated config back to the file
11179
+ await fs$6.writeFile(configPath, JSON.stringify(config, null, 4), 'utf8');
11180
+ }
11181
+
11182
+
11183
+ var saver = {
11184
+ saveConfiguration: saveConfiguration$1,
11185
+ };
11186
+
11071
11187
  /*
11072
11188
  * Component: AnalyzerUtils Schema Loader
11073
11189
  * Block-UUID: 0c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f
@@ -11079,8 +11195,8 @@ var saver = {
11079
11195
  * Authors: Gemini 2.5 Flash (v1.0.0)
11080
11196
  */
11081
11197
 
11082
- const fs$4 = require$$0.promises;
11083
- const path$2 = require$$1;
11198
+ const fs$5 = require$$0.promises;
11199
+ const path$3 = require$$1;
11084
11200
  const CodeBlockUtils$1 = CodeBlockUtils$4;
11085
11201
 
11086
11202
  /**
@@ -11166,10 +11282,10 @@ async function getAnalyzerSchema$2(analyzeMessagesBasePath, analyzerId) {
11166
11282
  }
11167
11283
  const [analyzerName, contentType, instructionsType] = parts;
11168
11284
 
11169
- const instructionsFilePath = path$2.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11285
+ const instructionsFilePath = path$3.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11170
11286
 
11171
11287
  try {
11172
- const fileContent = await fs$4.readFile(instructionsFilePath, 'utf8');
11288
+ const fileContent = await fs$5.readFile(instructionsFilePath, 'utf8');
11173
11289
  const { blocks } = CodeBlockUtils$1.extractCodeBlocks(fileContent, { silent: true });
11174
11290
  const jsonBlocks = blocks.filter(block => block.type === 'code' && block.language === 'json');
11175
11291
 
@@ -11240,8 +11356,8 @@ var schemaLoader = {
11240
11356
  * Authors: Gemini 2.5 Flash (v1.0.0)
11241
11357
  */
11242
11358
 
11243
- const fs$3 = require$$0.promises;
11244
- const path$1 = require$$1;
11359
+ const fs$4 = require$$0.promises;
11360
+ const path$2 = require$$1;
11245
11361
  const { readConfig } = discovery; // Import helper from discovery
11246
11362
 
11247
11363
  /**
@@ -11251,7 +11367,7 @@ const { readConfig } = discovery; // Import helper from discovery
11251
11367
  */
11252
11368
  async function isDirectoryEmpty(dirPath) {
11253
11369
  try {
11254
- const files = await fs$3.readdir(dirPath);
11370
+ const files = await fs$4.readdir(dirPath);
11255
11371
  return files.length === 0 || (files.length === 1 && files[0] === 'config.json');
11256
11372
  } catch (error) {
11257
11373
  if (error.code === 'ENOENT') {
@@ -11282,10 +11398,10 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11282
11398
  }
11283
11399
  const [analyzerName, contentType, instructionsType] = parts;
11284
11400
 
11285
- const analyzerDir = path$1.join(analyzeMessagesBasePath, analyzerName);
11286
- const contentDir = path$1.join(analyzerDir, contentType);
11287
- const instructionsDir = path$1.join(contentDir, instructionsType);
11288
- const instructionsFilePath = path$1.join(instructionsDir, '1.md');
11401
+ const analyzerDir = path$2.join(analyzeMessagesBasePath, analyzerName);
11402
+ const contentDir = path$2.join(analyzerDir, contentType);
11403
+ const instructionsDir = path$2.join(contentDir, instructionsType);
11404
+ const instructionsFilePath = path$2.join(instructionsDir, '1.md');
11289
11405
 
11290
11406
  try {
11291
11407
  // 1. Check for protection at all levels
@@ -11306,7 +11422,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11306
11422
 
11307
11423
  // 2. Delete the 1.md file
11308
11424
  try {
11309
- await fs$3.unlink(instructionsFilePath);
11425
+ await fs$4.unlink(instructionsFilePath);
11310
11426
  } catch (error) {
11311
11427
  if (error.code === 'ENOENT') {
11312
11428
  return { success: false, message: `Analyzer instructions file not found: ${instructionsFilePath}. It may have already been deleted.` };
@@ -11320,7 +11436,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11320
11436
  // Check and delete instructions directory
11321
11437
  if (await isDirectoryEmpty(instructionsDir)) {
11322
11438
  try {
11323
- await fs$3.rmdir(instructionsDir);
11439
+ await fs$4.rmdir(instructionsDir);
11324
11440
  deletedDirs.push(instructionsDir);
11325
11441
  } catch (error) {
11326
11442
  console.warn(`Warning: Could not remove empty instructions directory ${instructionsDir}: ${error.message}`);
@@ -11330,7 +11446,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11330
11446
  // Check and delete content directory
11331
11447
  if (await isDirectoryEmpty(contentDir)) {
11332
11448
  try {
11333
- await fs$3.rmdir(contentDir);
11449
+ await fs$4.rmdir(contentDir);
11334
11450
  deletedDirs.push(contentDir);
11335
11451
  } catch (error) {
11336
11452
  console.warn(`Warning: Could not remove empty content directory ${contentDir}: ${error.message}`);
@@ -11340,7 +11456,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11340
11456
  // Check and delete analyzer directory
11341
11457
  if (await isDirectoryEmpty(analyzerDir)) {
11342
11458
  try {
11343
- await fs$3.rmdir(analyzerDir);
11459
+ await fs$4.rmdir(analyzerDir);
11344
11460
  deletedDirs.push(analyzerDir);
11345
11461
  } catch (error) {
11346
11462
  console.warn(`Warning: Could not remove empty analyzer directory ${analyzerDir}: ${error.message}`);
@@ -11369,8 +11485,8 @@ var management = {
11369
11485
  * Authors: Gemini 2.5 Flash (v1.0.0)
11370
11486
  */
11371
11487
 
11372
- const fs$2 = require$$0.promises;
11373
- const path = require$$1;
11488
+ const fs$3 = require$$0.promises;
11489
+ const path$1 = require$$1;
11374
11490
 
11375
11491
  /**
11376
11492
  * Retrieves the raw Markdown content of the analyzer's '1.md' instruction file.
@@ -11396,10 +11512,10 @@ async function getAnalyzerInstructionsContent$2(analyzeMessagesBasePath, analyze
11396
11512
  }
11397
11513
  const [analyzerName, contentType, instructionsType] = parts;
11398
11514
 
11399
- const instructionsFilePath = path.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11515
+ const instructionsFilePath = path$1.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11400
11516
 
11401
11517
  try {
11402
- const fileContent = await fs$2.readFile(instructionsFilePath, 'utf8');
11518
+ const fileContent = await fs$3.readFile(instructionsFilePath, 'utf8');
11403
11519
  return fileContent;
11404
11520
  } catch (error) {
11405
11521
  if (error.code === 'ENOENT') {
@@ -11416,15 +11532,90 @@ var instructionLoader = {
11416
11532
  getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$2
11417
11533
  };
11418
11534
 
11535
+ /*
11536
+ * Component: AnalyzerUtils Default Prompt Loader
11537
+ * Block-UUID: 0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5f
11538
+ * Parent-UUID: N/A
11539
+ * Version: 1.0.0
11540
+ * Description: Provides utility functions for loading shared, default prompt components (system and start messages).
11541
+ * Language: JavaScript
11542
+ * Created-at: 2025-08-29T03:30:28.771Z
11543
+ * Authors: Gemini 2.5 Flash (v1.0.0)
11544
+ */
11545
+
11546
+ const fs$2 = require$$0.promises;
11547
+ const path = require$$1;
11548
+
11549
+ /**
11550
+ * Retrieves the raw Markdown content of the shared system message ('_shared/system/1.md').
11551
+ *
11552
+ * @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing analyzer message files (e.g., 'messages/analyze').
11553
+ * @returns {Promise<string|null>} A promise that resolves with the full Markdown content, or null if not found/invalid.
11554
+ */
11555
+ async function getSystemMessageContent$2(analyzeMessagesBasePath) {
11556
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
11557
+ console.error('Error: analyzeMessagesBasePath is required for getSystemMessageContent.');
11558
+ return null;
11559
+ }
11560
+
11561
+ const systemMessageFilePath = path.join(analyzeMessagesBasePath, '_shared', 'system', '1.md');
11562
+
11563
+ try {
11564
+ const fileContent = await fs$2.readFile(systemMessageFilePath, 'utf8');
11565
+ return fileContent;
11566
+ } catch (error) {
11567
+ if (error.code === 'ENOENT') {
11568
+ console.warn(`Default system message file not found: ${systemMessageFilePath}.`);
11569
+ return null;
11570
+ } else {
11571
+ console.error(`Error reading default system message file ${systemMessageFilePath}: ${error.message}`);
11572
+ throw error;
11573
+ }
11574
+ }
11575
+ }
11576
+
11577
+ /**
11578
+ * Retrieves the raw Markdown content of the shared start message ('_shared/start/1.md').
11579
+ *
11580
+ * @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing analyzer message files (e.g., 'messages/analyze').
11581
+ * @returns {Promise<string|null>} A promise that resolves with the full Markdown content, or null if not found/invalid.
11582
+ */
11583
+ async function getStartMessageContent$2(analyzeMessagesBasePath) {
11584
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
11585
+ console.error('Error: analyzeMessagesBasePath is required for getStartMessageContent.');
11586
+ return null;
11587
+ }
11588
+
11589
+ const startMessageFilePath = path.join(analyzeMessagesBasePath, '_shared', 'start', '1.md');
11590
+
11591
+ try {
11592
+ const fileContent = await fs$2.readFile(startMessageFilePath, 'utf8');
11593
+ return fileContent;
11594
+ } catch (error) {
11595
+ if (error.code === 'ENOENT') {
11596
+ console.warn(`Default start message file not found: ${startMessageFilePath}.`);
11597
+ return null;
11598
+ } else {
11599
+ console.error(`Error reading default start message file ${startMessageFilePath}: ${error.message}`);
11600
+ throw error;
11601
+ }
11602
+ }
11603
+ }
11604
+
11605
+ var defaultPromptLoader = {
11606
+ getSystemMessageContent: getSystemMessageContent$2,
11607
+ getStartMessageContent: getStartMessageContent$2
11608
+ };
11609
+
11419
11610
  /*
11420
11611
  * Component: AnalyzerUtils Index
11421
11612
  * Block-UUID: b403b6a1-230b-4247-8cd6-2a3d068f4bbf
11422
11613
  * Parent-UUID: N/A
11423
- * Version: 1.1.0
11614
+ * Version: 1.2.0
11424
11615
  * Description: Aggregates and exports all utility functions from the AnalyzerUtils module.
11425
11616
  * Language: JavaScript
11426
11617
  * Created-at: 2025-08-28T15:56:40.319Z
11427
- * Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0)
11618
+ * Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0), Gemini 2.5 Flash (v1.2.0)
11428
11619
  */
11429
11620
 
11430
11621
  const { buildChatIdToPathMap: buildChatIdToPathMap$1 } = contextMapper;
@@ -11435,6 +11626,7 @@ const { saveConfiguration } = saver;
11435
11626
  const { getAnalyzerSchema: getAnalyzerSchema$1 } = schemaLoader;
11436
11627
  const { deleteAnalyzer: deleteAnalyzer$1 } = management;
11437
11628
  const { getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1 } = instructionLoader;
11629
+ const { getSystemMessageContent: getSystemMessageContent$1, getStartMessageContent: getStartMessageContent$1 } = defaultPromptLoader; // NEW: Import default prompt loaders
11438
11630
 
11439
11631
  var AnalyzerUtils$1 = {
11440
11632
  buildChatIdToPathMap: buildChatIdToPathMap$1,
@@ -11445,6 +11637,8 @@ var AnalyzerUtils$1 = {
11445
11637
  deleteAnalyzer: deleteAnalyzer$1,
11446
11638
  getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1,
11447
11639
  saveConfiguration,
11640
+ getSystemMessageContent: getSystemMessageContent$1,
11641
+ getStartMessageContent: getStartMessageContent$1
11448
11642
  };
11449
11643
 
11450
11644
  /**
@@ -11715,6 +11909,8 @@ const {
11715
11909
  getAnalyzerSchema,
11716
11910
  deleteAnalyzer,
11717
11911
  getAnalyzerInstructionsContent,
11912
+ getSystemMessageContent,
11913
+ getStartMessageContent,
11718
11914
  saveAnalyzerConfiguration,
11719
11915
  } = AnalyzerUtils;
11720
11916
 
@@ -12050,6 +12246,8 @@ var GitSenseChatUtils_1 = {
12050
12246
  getAnalyzerSchema,
12051
12247
  deleteAnalyzer,
12052
12248
  getAnalyzerInstructionsContent,
12249
+ getSystemMessageContent,
12250
+ getStartMessageContent,
12053
12251
 
12054
12252
  // ChatUtils
12055
12253
  getChatMessages,
@@ -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$6 = require$$0;
20
- const path$4 = 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$4.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$6.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$4.extname(file) === '.md') {
71
- const filePath = path$4.join(messagesDir, file);
72
- const fileContent = fs$6.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');
@@ -10923,8 +10923,8 @@ var dataValidator = {
10923
10923
  * Authors: Gemini 2.5 Flash (v1.0.0)
10924
10924
  */
10925
10925
 
10926
- const fs$5 = require$$0.promises;
10927
- const path$3 = require$$1;
10926
+ const fs$7 = require$$0.promises;
10927
+ const path$5 = require$$1;
10928
10928
 
10929
10929
  /**
10930
10930
  * Reads and parses the config.json file in a directory.
@@ -10933,9 +10933,9 @@ const path$3 = require$$1;
10933
10933
  * or null if the file doesn't exist or is invalid.
10934
10934
  */
10935
10935
  async function readConfig$1(dirPath) {
10936
- const configPath = path$3.join(dirPath, 'config.json');
10936
+ const configPath = path$5.join(dirPath, 'config.json');
10937
10937
  try {
10938
- const fileContent = await fs$5.readFile(configPath, 'utf8');
10938
+ const fileContent = await fs$7.readFile(configPath, 'utf8');
10939
10939
  return JSON.parse(fileContent);
10940
10940
  } catch (error) {
10941
10941
  if (error.code !== 'ENOENT') {
@@ -10972,41 +10972,41 @@ async function getAnalyzers$2(analyzeMessagesBasePath) {
10972
10972
  const analyzers = [];
10973
10973
 
10974
10974
  try {
10975
- const analyzerEntries = await fs$5.readdir(analyzeMessagesBasePath, { withFileTypes: true });
10975
+ const analyzerEntries = await fs$7.readdir(analyzeMessagesBasePath, { withFileTypes: true });
10976
10976
 
10977
10977
  for (const analyzerEntry of analyzerEntries) {
10978
10978
  if (analyzerEntry.isDirectory() && isValidDirName(analyzerEntry.name)) {
10979
10979
  const analyzerName = analyzerEntry.name;
10980
- const analyzerPath = path$3.join(analyzeMessagesBasePath, analyzerName);
10980
+ const analyzerPath = path$5.join(analyzeMessagesBasePath, analyzerName);
10981
10981
  const analyzerConfig = await readConfig$1(analyzerPath);
10982
10982
  const analyzerLabel = analyzerConfig?.label || analyzerName;
10983
10983
 
10984
- const contentEntries = await fs$5.readdir(analyzerPath, { withFileTypes: true });
10984
+ const contentEntries = await fs$7.readdir(analyzerPath, { withFileTypes: true });
10985
10985
 
10986
10986
  for (const contentEntry of contentEntries) {
10987
10987
  if (contentEntry.isDirectory() && isValidDirName(contentEntry.name)) {
10988
10988
  const contentType = contentEntry.name;
10989
- const contentPath = path$3.join(analyzerPath, contentType);
10989
+ const contentPath = path$5.join(analyzerPath, contentType);
10990
10990
  const contentConfig = await readConfig$1(contentPath);
10991
10991
  const contentLabel = contentConfig?.label || contentType;
10992
10992
 
10993
- const instructionsEntries = await fs$5.readdir(contentPath, { withFileTypes: true });
10993
+ const instructionsEntries = await fs$7.readdir(contentPath, { withFileTypes: true });
10994
10994
 
10995
10995
  for (const instructionsEntry of instructionsEntries) {
10996
10996
  if (instructionsEntry.isDirectory() && isValidDirName(instructionsEntry.name)) {
10997
10997
  const instructionsType = instructionsEntry.name;
10998
- const instructionsPath = path$3.join(contentPath, instructionsType);
10998
+ const instructionsPath = path$5.join(contentPath, instructionsType);
10999
10999
  const instructionsConfig = await readConfig$1(instructionsPath);
11000
11000
  const instructionsLabel = instructionsConfig?.label || instructionsType;
11001
11001
 
11002
11002
  // Check for the existence of 1.md to confirm a valid analyzer configuration
11003
- const instructionsFilePath = path$3.join(instructionsPath, '1.md');
11003
+ const instructionsFilePath = path$5.join(instructionsPath, '1.md');
11004
11004
  try {
11005
- await fs$5.access(instructionsFilePath); // Check if file exists and is accessible
11005
+ await fs$7.access(instructionsFilePath); // Check if file exists and is accessible
11006
11006
 
11007
11007
  // If analyzerName starts with 'tutorial-', check its last modified time.
11008
11008
  if (analyzerName.startsWith('tutorial-')) {
11009
- const stats = await fs$5.stat(instructionsFilePath);
11009
+ const stats = await fs$7.stat(instructionsFilePath);
11010
11010
  const lastModified = stats.mtime.getTime(); // Get timestamp in milliseconds
11011
11011
  const sixtyMinutesAgo = Date.now() - (60 * 60 * 1000); // Current time - 60 minutes in ms
11012
11012
 
@@ -11060,12 +11060,128 @@ var discovery = {
11060
11060
  * Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash Thinking (v1.1.0)
11061
11061
  */
11062
11062
 
11063
- require$$0.promises;
11063
+ const fs$6 = require$$0.promises;
11064
+ const path$4 = require$$1;
11064
11065
 
11066
+ /**
11067
+ * Saves or updates an analyzer configuration.
11068
+ *
11069
+ * This function takes the analyzer ID and its full instructions content,
11070
+ * parses the ID to determine the directory structure, creates directories
11071
+ * if necessary, saves the instructions to '1.md'. Optionally, it can
11072
+ * ensure config.json files exist with labels derived from directory names.
11073
+ *
11074
+ * @param {string} analyzeMessagesBasePath - The absolute or relative path to the 'messages/analyze' directory.
11075
+ * @param {string} analyzerId - The unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
11076
+ * @param {string} instructionsContent - The full content of the analyzer instructions message to be saved in '1.md'.
11077
+ * @param {object} [options={}] - Optional configuration options.
11078
+ * @param {boolean} [options.ensureConfigs=false] - If true, ensures config.json files exist in the analyzer, content, and instructions directories. Defaults to false.
11079
+ * @returns {Promise<{success: boolean, message?: string}>} A promise that resolves with a result object.
11080
+ */
11081
+ async function saveConfiguration$1(analyzeMessagesBasePath, analyzerId, instructionsContent, options = {}) {
11082
+ const { ensureConfigs = false } = options;
11065
11083
 
11066
- var saver = {
11084
+ // 1. Validate inputs
11085
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
11086
+ return { success: false, message: 'analyzeMessagesBasePath is required.' };
11087
+ }
11088
+ if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
11089
+ return { success: false, message: 'analyzerId is required.' };
11090
+ }
11091
+ if (typeof instructionsContent !== 'string' || instructionsContent.trim() === '') {
11092
+ return { success: false, message: 'instructionsContent is required.' };
11093
+ }
11094
+
11095
+ // 2. Parse analyzerId
11096
+ const parts = analyzerId.split('::');
11097
+ if (parts.length !== 3) {
11098
+ return { success: false, message: `Invalid analyzerId format. Expected 'analyzer_name::content_type::instructions_type', but got '${analyzerId}'.` };
11099
+ }
11100
+ const [analyzerName, contentType, instructionsType] = parts;
11101
+
11102
+ // Helper to validate directory names based on README.md rules
11103
+ const isValidDirName = (name) => {
11104
+ // Cannot start with underscore, cannot contain dots, must be alphanumeric, dash, or underscore
11105
+ return /^[a-zA-Z0-9_-]+$/.test(name) && !name.startsWith('_') && !name.includes('.');
11067
11106
  };
11068
11107
 
11108
+ if (!isValidDirName(analyzerName)) {
11109
+ return { success: false, message: `Invalid analyzer name '${analyzerName}'. Names must be alphanumeric, dash, or underscore, cannot start with underscore, and cannot contain dots.` };
11110
+ }
11111
+ if (!isValidDirName(contentType)) {
11112
+ return { success: false, message: `Invalid content type name '${contentType}'. Names must be alphanumeric, dash, or underscore, cannot start with underscore, and cannot contain dots.` };
11113
+ }
11114
+ if (!isValidDirName(instructionsType)) {
11115
+ return { success: false, message: `Invalid instructions type name '${instructionsType}'. Names must be alphanumeric, dash, or underscore, cannot start with underscore, and cannot contain dots.` };
11116
+ }
11117
+
11118
+ // 3. Construct directory paths
11119
+ const analyzerDir = path$4.join(analyzeMessagesBasePath, analyzerName);
11120
+ const contentDir = path$4.join(analyzerDir, contentType);
11121
+ const instructionsDir = path$4.join(contentDir, instructionsType);
11122
+ const instructionsFilePath = path$4.join(instructionsDir, '1.md');
11123
+
11124
+ try {
11125
+ // 4. Create directories recursively
11126
+ await fs$6.mkdir(instructionsDir, { recursive: true });
11127
+
11128
+ // 5. Save instructions content to 1.md
11129
+ const finalContent = `; role: assistant\n\n\n${instructionsContent}`;
11130
+ await fs$6.writeFile(instructionsFilePath, finalContent, 'utf8');
11131
+
11132
+ // 6. Optionally create/Update config.json files
11133
+ if (ensureConfigs) {
11134
+ await ensureConfigJson(analyzerDir, analyzerName);
11135
+ await ensureConfigJson(contentDir, contentType);
11136
+ await ensureConfigJson(instructionsDir, instructionsType);
11137
+ }
11138
+
11139
+ return { success: true, message: `Analyzer configuration '${analyzerId}' saved successfully.` };
11140
+
11141
+ } catch (error) {
11142
+ console.error(`Error saving analyzer configuration '${analyzerId}':`, error);
11143
+ return { success: false, message: `Failed to save analyzer configuration: ${error.message}` };
11144
+ }
11145
+ }
11146
+
11147
+ /**
11148
+ * Ensures a config.json file exists in the given directory with a label.
11149
+ * If the file exists, it reads it and adds the label if missing.
11150
+ * If the file doesn't exist, it creates it with the label.
11151
+ *
11152
+ * @param {string} dirPath - The path to the directory.
11153
+ * @param {string} label - The label to ensure is in the config.json.
11154
+ */
11155
+ async function ensureConfigJson(dirPath, label) {
11156
+ const configPath = path$4.join(dirPath, 'config.json');
11157
+ let config = {};
11158
+
11159
+ try {
11160
+ const fileContent = await fs$6.readFile(configPath, 'utf8');
11161
+ config = JSON.parse(fileContent);
11162
+ } catch (error) {
11163
+ // If file doesn't exist or parsing fails, start with an empty config
11164
+ if (error.code !== 'ENOENT') {
11165
+ console.warn(`Failed to read or parse existing config.json in ${dirPath}: ${error.message}`);
11166
+ }
11167
+ config = {}; // Ensure config is an object even on error
11168
+ }
11169
+
11170
+ // Add or update the label if it's missing or empty
11171
+ if (!config.label || typeof config.label !== 'string' || config.label.trim() === '') {
11172
+ // Capitalize the first letter for the label
11173
+ config.label = label.charAt(0).toUpperCase() + label.slice(1);
11174
+ }
11175
+
11176
+ // Write the updated config back to the file
11177
+ await fs$6.writeFile(configPath, JSON.stringify(config, null, 4), 'utf8');
11178
+ }
11179
+
11180
+
11181
+ var saver = {
11182
+ saveConfiguration: saveConfiguration$1,
11183
+ };
11184
+
11069
11185
  /*
11070
11186
  * Component: AnalyzerUtils Schema Loader
11071
11187
  * Block-UUID: 0c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f
@@ -11077,8 +11193,8 @@ var saver = {
11077
11193
  * Authors: Gemini 2.5 Flash (v1.0.0)
11078
11194
  */
11079
11195
 
11080
- const fs$4 = require$$0.promises;
11081
- const path$2 = require$$1;
11196
+ const fs$5 = require$$0.promises;
11197
+ const path$3 = require$$1;
11082
11198
  const CodeBlockUtils$1 = CodeBlockUtils$4;
11083
11199
 
11084
11200
  /**
@@ -11164,10 +11280,10 @@ async function getAnalyzerSchema$2(analyzeMessagesBasePath, analyzerId) {
11164
11280
  }
11165
11281
  const [analyzerName, contentType, instructionsType] = parts;
11166
11282
 
11167
- const instructionsFilePath = path$2.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11283
+ const instructionsFilePath = path$3.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11168
11284
 
11169
11285
  try {
11170
- const fileContent = await fs$4.readFile(instructionsFilePath, 'utf8');
11286
+ const fileContent = await fs$5.readFile(instructionsFilePath, 'utf8');
11171
11287
  const { blocks } = CodeBlockUtils$1.extractCodeBlocks(fileContent, { silent: true });
11172
11288
  const jsonBlocks = blocks.filter(block => block.type === 'code' && block.language === 'json');
11173
11289
 
@@ -11238,8 +11354,8 @@ var schemaLoader = {
11238
11354
  * Authors: Gemini 2.5 Flash (v1.0.0)
11239
11355
  */
11240
11356
 
11241
- const fs$3 = require$$0.promises;
11242
- const path$1 = require$$1;
11357
+ const fs$4 = require$$0.promises;
11358
+ const path$2 = require$$1;
11243
11359
  const { readConfig } = discovery; // Import helper from discovery
11244
11360
 
11245
11361
  /**
@@ -11249,7 +11365,7 @@ const { readConfig } = discovery; // Import helper from discovery
11249
11365
  */
11250
11366
  async function isDirectoryEmpty(dirPath) {
11251
11367
  try {
11252
- const files = await fs$3.readdir(dirPath);
11368
+ const files = await fs$4.readdir(dirPath);
11253
11369
  return files.length === 0 || (files.length === 1 && files[0] === 'config.json');
11254
11370
  } catch (error) {
11255
11371
  if (error.code === 'ENOENT') {
@@ -11280,10 +11396,10 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11280
11396
  }
11281
11397
  const [analyzerName, contentType, instructionsType] = parts;
11282
11398
 
11283
- const analyzerDir = path$1.join(analyzeMessagesBasePath, analyzerName);
11284
- const contentDir = path$1.join(analyzerDir, contentType);
11285
- const instructionsDir = path$1.join(contentDir, instructionsType);
11286
- const instructionsFilePath = path$1.join(instructionsDir, '1.md');
11399
+ const analyzerDir = path$2.join(analyzeMessagesBasePath, analyzerName);
11400
+ const contentDir = path$2.join(analyzerDir, contentType);
11401
+ const instructionsDir = path$2.join(contentDir, instructionsType);
11402
+ const instructionsFilePath = path$2.join(instructionsDir, '1.md');
11287
11403
 
11288
11404
  try {
11289
11405
  // 1. Check for protection at all levels
@@ -11304,7 +11420,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11304
11420
 
11305
11421
  // 2. Delete the 1.md file
11306
11422
  try {
11307
- await fs$3.unlink(instructionsFilePath);
11423
+ await fs$4.unlink(instructionsFilePath);
11308
11424
  } catch (error) {
11309
11425
  if (error.code === 'ENOENT') {
11310
11426
  return { success: false, message: `Analyzer instructions file not found: ${instructionsFilePath}. It may have already been deleted.` };
@@ -11318,7 +11434,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11318
11434
  // Check and delete instructions directory
11319
11435
  if (await isDirectoryEmpty(instructionsDir)) {
11320
11436
  try {
11321
- await fs$3.rmdir(instructionsDir);
11437
+ await fs$4.rmdir(instructionsDir);
11322
11438
  deletedDirs.push(instructionsDir);
11323
11439
  } catch (error) {
11324
11440
  console.warn(`Warning: Could not remove empty instructions directory ${instructionsDir}: ${error.message}`);
@@ -11328,7 +11444,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11328
11444
  // Check and delete content directory
11329
11445
  if (await isDirectoryEmpty(contentDir)) {
11330
11446
  try {
11331
- await fs$3.rmdir(contentDir);
11447
+ await fs$4.rmdir(contentDir);
11332
11448
  deletedDirs.push(contentDir);
11333
11449
  } catch (error) {
11334
11450
  console.warn(`Warning: Could not remove empty content directory ${contentDir}: ${error.message}`);
@@ -11338,7 +11454,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
11338
11454
  // Check and delete analyzer directory
11339
11455
  if (await isDirectoryEmpty(analyzerDir)) {
11340
11456
  try {
11341
- await fs$3.rmdir(analyzerDir);
11457
+ await fs$4.rmdir(analyzerDir);
11342
11458
  deletedDirs.push(analyzerDir);
11343
11459
  } catch (error) {
11344
11460
  console.warn(`Warning: Could not remove empty analyzer directory ${analyzerDir}: ${error.message}`);
@@ -11367,8 +11483,8 @@ var management = {
11367
11483
  * Authors: Gemini 2.5 Flash (v1.0.0)
11368
11484
  */
11369
11485
 
11370
- const fs$2 = require$$0.promises;
11371
- const path = require$$1;
11486
+ const fs$3 = require$$0.promises;
11487
+ const path$1 = require$$1;
11372
11488
 
11373
11489
  /**
11374
11490
  * Retrieves the raw Markdown content of the analyzer's '1.md' instruction file.
@@ -11394,10 +11510,10 @@ async function getAnalyzerInstructionsContent$2(analyzeMessagesBasePath, analyze
11394
11510
  }
11395
11511
  const [analyzerName, contentType, instructionsType] = parts;
11396
11512
 
11397
- const instructionsFilePath = path.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11513
+ const instructionsFilePath = path$1.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
11398
11514
 
11399
11515
  try {
11400
- const fileContent = await fs$2.readFile(instructionsFilePath, 'utf8');
11516
+ const fileContent = await fs$3.readFile(instructionsFilePath, 'utf8');
11401
11517
  return fileContent;
11402
11518
  } catch (error) {
11403
11519
  if (error.code === 'ENOENT') {
@@ -11414,15 +11530,90 @@ var instructionLoader = {
11414
11530
  getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$2
11415
11531
  };
11416
11532
 
11533
+ /*
11534
+ * Component: AnalyzerUtils Default Prompt Loader
11535
+ * Block-UUID: 0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5f
11536
+ * Parent-UUID: N/A
11537
+ * Version: 1.0.0
11538
+ * Description: Provides utility functions for loading shared, default prompt components (system and start messages).
11539
+ * Language: JavaScript
11540
+ * Created-at: 2025-08-29T03:30:28.771Z
11541
+ * Authors: Gemini 2.5 Flash (v1.0.0)
11542
+ */
11543
+
11544
+ const fs$2 = require$$0.promises;
11545
+ const path = require$$1;
11546
+
11547
+ /**
11548
+ * Retrieves the raw Markdown content of the shared system message ('_shared/system/1.md').
11549
+ *
11550
+ * @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing analyzer message files (e.g., 'messages/analyze').
11551
+ * @returns {Promise<string|null>} A promise that resolves with the full Markdown content, or null if not found/invalid.
11552
+ */
11553
+ async function getSystemMessageContent$2(analyzeMessagesBasePath) {
11554
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
11555
+ console.error('Error: analyzeMessagesBasePath is required for getSystemMessageContent.');
11556
+ return null;
11557
+ }
11558
+
11559
+ const systemMessageFilePath = path.join(analyzeMessagesBasePath, '_shared', 'system', '1.md');
11560
+
11561
+ try {
11562
+ const fileContent = await fs$2.readFile(systemMessageFilePath, 'utf8');
11563
+ return fileContent;
11564
+ } catch (error) {
11565
+ if (error.code === 'ENOENT') {
11566
+ console.warn(`Default system message file not found: ${systemMessageFilePath}.`);
11567
+ return null;
11568
+ } else {
11569
+ console.error(`Error reading default system message file ${systemMessageFilePath}: ${error.message}`);
11570
+ throw error;
11571
+ }
11572
+ }
11573
+ }
11574
+
11575
+ /**
11576
+ * Retrieves the raw Markdown content of the shared start message ('_shared/start/1.md').
11577
+ *
11578
+ * @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing analyzer message files (e.g., 'messages/analyze').
11579
+ * @returns {Promise<string|null>} A promise that resolves with the full Markdown content, or null if not found/invalid.
11580
+ */
11581
+ async function getStartMessageContent$2(analyzeMessagesBasePath) {
11582
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
11583
+ console.error('Error: analyzeMessagesBasePath is required for getStartMessageContent.');
11584
+ return null;
11585
+ }
11586
+
11587
+ const startMessageFilePath = path.join(analyzeMessagesBasePath, '_shared', 'start', '1.md');
11588
+
11589
+ try {
11590
+ const fileContent = await fs$2.readFile(startMessageFilePath, 'utf8');
11591
+ return fileContent;
11592
+ } catch (error) {
11593
+ if (error.code === 'ENOENT') {
11594
+ console.warn(`Default start message file not found: ${startMessageFilePath}.`);
11595
+ return null;
11596
+ } else {
11597
+ console.error(`Error reading default start message file ${startMessageFilePath}: ${error.message}`);
11598
+ throw error;
11599
+ }
11600
+ }
11601
+ }
11602
+
11603
+ var defaultPromptLoader = {
11604
+ getSystemMessageContent: getSystemMessageContent$2,
11605
+ getStartMessageContent: getStartMessageContent$2
11606
+ };
11607
+
11417
11608
  /*
11418
11609
  * Component: AnalyzerUtils Index
11419
11610
  * Block-UUID: b403b6a1-230b-4247-8cd6-2a3d068f4bbf
11420
11611
  * Parent-UUID: N/A
11421
- * Version: 1.1.0
11612
+ * Version: 1.2.0
11422
11613
  * Description: Aggregates and exports all utility functions from the AnalyzerUtils module.
11423
11614
  * Language: JavaScript
11424
11615
  * Created-at: 2025-08-28T15:56:40.319Z
11425
- * Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0)
11616
+ * Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0), Gemini 2.5 Flash (v1.2.0)
11426
11617
  */
11427
11618
 
11428
11619
  const { buildChatIdToPathMap: buildChatIdToPathMap$1 } = contextMapper;
@@ -11433,6 +11624,7 @@ const { saveConfiguration } = saver;
11433
11624
  const { getAnalyzerSchema: getAnalyzerSchema$1 } = schemaLoader;
11434
11625
  const { deleteAnalyzer: deleteAnalyzer$1 } = management;
11435
11626
  const { getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1 } = instructionLoader;
11627
+ const { getSystemMessageContent: getSystemMessageContent$1, getStartMessageContent: getStartMessageContent$1 } = defaultPromptLoader; // NEW: Import default prompt loaders
11436
11628
 
11437
11629
  var AnalyzerUtils$1 = {
11438
11630
  buildChatIdToPathMap: buildChatIdToPathMap$1,
@@ -11443,6 +11635,8 @@ var AnalyzerUtils$1 = {
11443
11635
  deleteAnalyzer: deleteAnalyzer$1,
11444
11636
  getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1,
11445
11637
  saveConfiguration,
11638
+ getSystemMessageContent: getSystemMessageContent$1,
11639
+ getStartMessageContent: getStartMessageContent$1
11446
11640
  };
11447
11641
 
11448
11642
  /**
@@ -11713,6 +11907,8 @@ const {
11713
11907
  getAnalyzerSchema,
11714
11908
  deleteAnalyzer,
11715
11909
  getAnalyzerInstructionsContent,
11910
+ getSystemMessageContent,
11911
+ getStartMessageContent,
11716
11912
  saveAnalyzerConfiguration,
11717
11913
  } = AnalyzerUtils;
11718
11914
 
@@ -12048,6 +12244,8 @@ var GitSenseChatUtils_1 = {
12048
12244
  getAnalyzerSchema,
12049
12245
  deleteAnalyzer,
12050
12246
  getAnalyzerInstructionsContent,
12247
+ getSystemMessageContent,
12248
+ getStartMessageContent,
12051
12249
 
12052
12250
  // ChatUtils
12053
12251
  getChatMessages,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitsense/gsc-utils",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Utilities for GitSense Chat (GSC)",
5
5
  "main": "dist/gsc-utils.cjs.js",
6
6
  "module": "dist/gsc-utils.esm.js",
@@ -0,0 +1,75 @@
1
+ /*
2
+ * Component: AnalyzerUtils Default Prompt Loader
3
+ * Block-UUID: 0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5f
4
+ * Parent-UUID: N/A
5
+ * Version: 1.0.0
6
+ * Description: Provides utility functions for loading shared, default prompt components (system and start messages).
7
+ * Language: JavaScript
8
+ * Created-at: 2025-08-29T03:30:28.771Z
9
+ * Authors: Gemini 2.5 Flash (v1.0.0)
10
+ */
11
+
12
+
13
+ const fs = require('fs').promises;
14
+ const path = require('path');
15
+
16
+ /**
17
+ * Retrieves the raw Markdown content of the shared system message ('_shared/system/1.md').
18
+ *
19
+ * @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing analyzer message files (e.g., 'messages/analyze').
20
+ * @returns {Promise<string|null>} A promise that resolves with the full Markdown content, or null if not found/invalid.
21
+ */
22
+ async function getSystemMessageContent(analyzeMessagesBasePath) {
23
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
24
+ console.error('Error: analyzeMessagesBasePath is required for getSystemMessageContent.');
25
+ return null;
26
+ }
27
+
28
+ const systemMessageFilePath = path.join(analyzeMessagesBasePath, '_shared', 'system', '1.md');
29
+
30
+ try {
31
+ const fileContent = await fs.readFile(systemMessageFilePath, 'utf8');
32
+ return fileContent;
33
+ } catch (error) {
34
+ if (error.code === 'ENOENT') {
35
+ console.warn(`Default system message file not found: ${systemMessageFilePath}.`);
36
+ return null;
37
+ } else {
38
+ console.error(`Error reading default system message file ${systemMessageFilePath}: ${error.message}`);
39
+ throw error;
40
+ }
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Retrieves the raw Markdown content of the shared start message ('_shared/start/1.md').
46
+ *
47
+ * @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing analyzer message files (e.g., 'messages/analyze').
48
+ * @returns {Promise<string|null>} A promise that resolves with the full Markdown content, or null if not found/invalid.
49
+ */
50
+ async function getStartMessageContent(analyzeMessagesBasePath) {
51
+ if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
52
+ console.error('Error: analyzeMessagesBasePath is required for getStartMessageContent.');
53
+ return null;
54
+ }
55
+
56
+ const startMessageFilePath = path.join(analyzeMessagesBasePath, '_shared', 'start', '1.md');
57
+
58
+ try {
59
+ const fileContent = await fs.readFile(startMessageFilePath, 'utf8');
60
+ return fileContent;
61
+ } catch (error) {
62
+ if (error.code === 'ENOENT') {
63
+ console.warn(`Default start message file not found: ${startMessageFilePath}.`);
64
+ return null;
65
+ } else {
66
+ console.error(`Error reading default start message file ${startMessageFilePath}: ${error.message}`);
67
+ throw error;
68
+ }
69
+ }
70
+ }
71
+
72
+ module.exports = {
73
+ getSystemMessageContent,
74
+ getStartMessageContent
75
+ };
@@ -2,11 +2,11 @@
2
2
  * Component: AnalyzerUtils Index
3
3
  * Block-UUID: b403b6a1-230b-4247-8cd6-2a3d068f4bbf
4
4
  * Parent-UUID: N/A
5
- * Version: 1.1.0
5
+ * Version: 1.2.0
6
6
  * Description: Aggregates and exports all utility functions from the AnalyzerUtils module.
7
7
  * Language: JavaScript
8
8
  * Created-at: 2025-08-28T15:56:40.319Z
9
- * Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0)
9
+ * Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0), Gemini 2.5 Flash (v1.2.0)
10
10
  */
11
11
 
12
12
 
@@ -18,6 +18,7 @@ const { saveConfiguration } = require('./saver');
18
18
  const { getAnalyzerSchema } = require('./schemaLoader');
19
19
  const { deleteAnalyzer } = require('./management');
20
20
  const { getAnalyzerInstructionsContent } = require('./instructionLoader');
21
+ const { getSystemMessageContent, getStartMessageContent } = require('./defaultPromptLoader'); // NEW: Import default prompt loaders
21
22
 
22
23
  module.exports = {
23
24
  buildChatIdToPathMap,
@@ -28,4 +29,6 @@ module.exports = {
28
29
  deleteAnalyzer,
29
30
  getAnalyzerInstructionsContent,
30
31
  saveConfiguration,
32
+ getSystemMessageContent,
33
+ getStartMessageContent
31
34
  };
@@ -28,7 +28,7 @@ const path = require('path');
28
28
  * @param {boolean} [options.ensureConfigs=false] - If true, ensures config.json files exist in the analyzer, content, and instructions directories. Defaults to false.
29
29
  * @returns {Promise<{success: boolean, message?: string}>} A promise that resolves with a result object.
30
30
  */
31
- async function saveAnalyzerConfiguration(analyzeMessagesBasePath, analyzerId, instructionsContent, options = {}) {
31
+ async function saveConfiguration(analyzeMessagesBasePath, analyzerId, instructionsContent, options = {}) {
32
32
  const { ensureConfigs = false } = options;
33
33
 
34
34
  // 1. Validate inputs
@@ -129,5 +129,5 @@ async function ensureConfigJson(dirPath, label) {
129
129
 
130
130
 
131
131
  module.exports = {
132
- saveAnalyzerConfiguration,
132
+ saveConfiguration,
133
133
  };
@@ -63,6 +63,8 @@ const {
63
63
  getAnalyzerSchema,
64
64
  deleteAnalyzer,
65
65
  getAnalyzerInstructionsContent,
66
+ getSystemMessageContent,
67
+ getStartMessageContent,
66
68
  saveAnalyzerConfiguration,
67
69
  } = AnalyzerUtils;
68
70
 
@@ -398,6 +400,8 @@ module.exports = {
398
400
  getAnalyzerSchema,
399
401
  deleteAnalyzer,
400
402
  getAnalyzerInstructionsContent,
403
+ getSystemMessageContent,
404
+ getStartMessageContent,
401
405
 
402
406
  // ChatUtils
403
407
  getChatMessages,