@gitsense/gsc-utils 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gsc-utils.cjs.js +158 -22
- package/dist/gsc-utils.esm.js +158 -22
- package/package.json +1 -1
- package/src/AnalyzerUtils/index.js +2 -0
- package/src/AnalyzerUtils/saver.js +133 -0
- package/src/GitSenseChatUtils.js +3 -2
package/dist/gsc-utils.cjs.js
CHANGED
|
@@ -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$
|
|
22
|
-
const path$
|
|
21
|
+
const fs$7 = require$$0;
|
|
22
|
+
const path$5 = 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$
|
|
56
|
+
const messagesDir = path$5.join(dirname, messageType);
|
|
57
57
|
const messages = [];
|
|
58
58
|
|
|
59
59
|
try {
|
|
60
60
|
// Read all files in the directory
|
|
61
|
-
const files = fs$
|
|
61
|
+
const files = fs$7.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$
|
|
73
|
-
const filePath = path$
|
|
74
|
-
const fileContent = fs$
|
|
72
|
+
if (path$5.extname(file) === '.md') {
|
|
73
|
+
const filePath = path$5.join(messagesDir, file);
|
|
74
|
+
const fileContent = fs$7.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$
|
|
10929
|
-
const path$
|
|
10928
|
+
const fs$6 = require$$0.promises;
|
|
10929
|
+
const path$4 = 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$
|
|
10938
|
+
const configPath = path$4.join(dirPath, 'config.json');
|
|
10939
10939
|
try {
|
|
10940
|
-
const fileContent = await fs$
|
|
10940
|
+
const fileContent = await fs$6.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$
|
|
10977
|
+
const analyzerEntries = await fs$6.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$
|
|
10982
|
+
const analyzerPath = path$4.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$
|
|
10986
|
+
const contentEntries = await fs$6.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$
|
|
10991
|
+
const contentPath = path$4.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$
|
|
10995
|
+
const instructionsEntries = await fs$6.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$
|
|
11000
|
+
const instructionsPath = path$4.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$
|
|
11005
|
+
const instructionsFilePath = path$4.join(instructionsPath, '1.md');
|
|
11006
11006
|
try {
|
|
11007
|
-
await fs$
|
|
11007
|
+
await fs$6.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$
|
|
11011
|
+
const stats = await fs$6.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
|
|
|
@@ -11051,6 +11051,139 @@ var discovery = {
|
|
|
11051
11051
|
getAnalyzers: getAnalyzers$2,
|
|
11052
11052
|
readConfig: readConfig$1};
|
|
11053
11053
|
|
|
11054
|
+
/**
|
|
11055
|
+
* Component: Analyzer Saver Utility
|
|
11056
|
+
* Block-UUID: a373f4ba-89ce-465f-8624-24258c923e61
|
|
11057
|
+
* Parent-UUID: N/A
|
|
11058
|
+
* Version: 1.1.0
|
|
11059
|
+
* Description: Utility function to save or update an analyzer configuration based on its ID and content.
|
|
11060
|
+
* Language: JavaScript
|
|
11061
|
+
* Created-at: 2025-07-12T04:12:33.454Z
|
|
11062
|
+
* Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash Thinking (v1.1.0)
|
|
11063
|
+
*/
|
|
11064
|
+
|
|
11065
|
+
const fs$5 = require$$0.promises;
|
|
11066
|
+
const path$3 = require$$1;
|
|
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;
|
|
11085
|
+
|
|
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('.');
|
|
11108
|
+
};
|
|
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$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');
|
|
11125
|
+
|
|
11126
|
+
try {
|
|
11127
|
+
// 4. Create directories recursively
|
|
11128
|
+
await fs$5.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$5.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$3.join(dirPath, 'config.json');
|
|
11159
|
+
let config = {};
|
|
11160
|
+
|
|
11161
|
+
try {
|
|
11162
|
+
const fileContent = await fs$5.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$5.writeFile(configPath, JSON.stringify(config, null, 4), 'utf8');
|
|
11180
|
+
}
|
|
11181
|
+
|
|
11182
|
+
|
|
11183
|
+
var saver = {
|
|
11184
|
+
saveConfiguration: saveConfiguration$1,
|
|
11185
|
+
};
|
|
11186
|
+
|
|
11054
11187
|
/*
|
|
11055
11188
|
* Component: AnalyzerUtils Schema Loader
|
|
11056
11189
|
* Block-UUID: 0c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f
|
|
@@ -11414,6 +11547,7 @@ const { buildChatIdToPathMap: buildChatIdToPathMap$1 } = contextMapper;
|
|
|
11414
11547
|
const { processLLMAnalysisResponse: processLLMAnalysisResponse$1 } = responseProcessor;
|
|
11415
11548
|
const { validateLLMAnalysisData: validateLLMAnalysisData$1 } = dataValidator;
|
|
11416
11549
|
const { getAnalyzers: getAnalyzers$1 } = discovery;
|
|
11550
|
+
const { saveConfiguration } = saver;
|
|
11417
11551
|
const { getAnalyzerSchema: getAnalyzerSchema$1 } = schemaLoader;
|
|
11418
11552
|
const { deleteAnalyzer: deleteAnalyzer$1 } = management;
|
|
11419
11553
|
const { getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1 } = instructionLoader;
|
|
@@ -11426,6 +11560,7 @@ var AnalyzerUtils$1 = {
|
|
|
11426
11560
|
getAnalyzerSchema: getAnalyzerSchema$1,
|
|
11427
11561
|
deleteAnalyzer: deleteAnalyzer$1,
|
|
11428
11562
|
getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1,
|
|
11563
|
+
saveConfiguration,
|
|
11429
11564
|
};
|
|
11430
11565
|
|
|
11431
11566
|
/**
|
|
@@ -11648,7 +11783,7 @@ const CodeBlockUtils = CodeBlockUtils$4;
|
|
|
11648
11783
|
const ContextUtils = ContextUtils$2;
|
|
11649
11784
|
const MessageUtils = MessageUtils$3;
|
|
11650
11785
|
const AnalysisBlockUtils = AnalysisBlockUtils$3;
|
|
11651
|
-
const AnalyzerUtils = AnalyzerUtils$1;
|
|
11786
|
+
const AnalyzerUtils = AnalyzerUtils$1;
|
|
11652
11787
|
const PatchUtils = PatchUtils$2;
|
|
11653
11788
|
const GSToolBlockUtils = GSToolBlockUtils$3;
|
|
11654
11789
|
const LLMUtils = LLMUtils$1;
|
|
@@ -11688,7 +11823,7 @@ const {
|
|
|
11688
11823
|
validateOverviewMetadata,
|
|
11689
11824
|
} = AnalysisBlockUtils;
|
|
11690
11825
|
|
|
11691
|
-
const {
|
|
11826
|
+
const {
|
|
11692
11827
|
buildChatIdToPathMap,
|
|
11693
11828
|
processLLMAnalysisResponse,
|
|
11694
11829
|
validateLLMAnalysisData,
|
|
@@ -11696,6 +11831,7 @@ const { // Updated AnalyzerUtils destructuring
|
|
|
11696
11831
|
getAnalyzerSchema,
|
|
11697
11832
|
deleteAnalyzer,
|
|
11698
11833
|
getAnalyzerInstructionsContent,
|
|
11834
|
+
saveAnalyzerConfiguration,
|
|
11699
11835
|
} = AnalyzerUtils;
|
|
11700
11836
|
|
|
11701
11837
|
const {
|
package/dist/gsc-utils.esm.js
CHANGED
|
@@ -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$
|
|
20
|
-
const path$
|
|
19
|
+
const fs$7 = require$$0;
|
|
20
|
+
const path$5 = 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$
|
|
54
|
+
const messagesDir = path$5.join(dirname, messageType);
|
|
55
55
|
const messages = [];
|
|
56
56
|
|
|
57
57
|
try {
|
|
58
58
|
// Read all files in the directory
|
|
59
|
-
const files = fs$
|
|
59
|
+
const files = fs$7.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$
|
|
71
|
-
const filePath = path$
|
|
72
|
-
const fileContent = fs$
|
|
70
|
+
if (path$5.extname(file) === '.md') {
|
|
71
|
+
const filePath = path$5.join(messagesDir, file);
|
|
72
|
+
const fileContent = fs$7.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$
|
|
10927
|
-
const path$
|
|
10926
|
+
const fs$6 = require$$0.promises;
|
|
10927
|
+
const path$4 = 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$
|
|
10936
|
+
const configPath = path$4.join(dirPath, 'config.json');
|
|
10937
10937
|
try {
|
|
10938
|
-
const fileContent = await fs$
|
|
10938
|
+
const fileContent = await fs$6.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$
|
|
10975
|
+
const analyzerEntries = await fs$6.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$
|
|
10980
|
+
const analyzerPath = path$4.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$
|
|
10984
|
+
const contentEntries = await fs$6.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$
|
|
10989
|
+
const contentPath = path$4.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$
|
|
10993
|
+
const instructionsEntries = await fs$6.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$
|
|
10998
|
+
const instructionsPath = path$4.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$
|
|
11003
|
+
const instructionsFilePath = path$4.join(instructionsPath, '1.md');
|
|
11004
11004
|
try {
|
|
11005
|
-
await fs$
|
|
11005
|
+
await fs$6.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$
|
|
11009
|
+
const stats = await fs$6.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
|
|
|
@@ -11049,6 +11049,139 @@ var discovery = {
|
|
|
11049
11049
|
getAnalyzers: getAnalyzers$2,
|
|
11050
11050
|
readConfig: readConfig$1};
|
|
11051
11051
|
|
|
11052
|
+
/**
|
|
11053
|
+
* Component: Analyzer Saver Utility
|
|
11054
|
+
* Block-UUID: a373f4ba-89ce-465f-8624-24258c923e61
|
|
11055
|
+
* Parent-UUID: N/A
|
|
11056
|
+
* Version: 1.1.0
|
|
11057
|
+
* Description: Utility function to save or update an analyzer configuration based on its ID and content.
|
|
11058
|
+
* Language: JavaScript
|
|
11059
|
+
* Created-at: 2025-07-12T04:12:33.454Z
|
|
11060
|
+
* Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash Thinking (v1.1.0)
|
|
11061
|
+
*/
|
|
11062
|
+
|
|
11063
|
+
const fs$5 = require$$0.promises;
|
|
11064
|
+
const path$3 = require$$1;
|
|
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;
|
|
11083
|
+
|
|
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('.');
|
|
11106
|
+
};
|
|
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$3.join(analyzeMessagesBasePath, analyzerName);
|
|
11120
|
+
const contentDir = path$3.join(analyzerDir, contentType);
|
|
11121
|
+
const instructionsDir = path$3.join(contentDir, instructionsType);
|
|
11122
|
+
const instructionsFilePath = path$3.join(instructionsDir, '1.md');
|
|
11123
|
+
|
|
11124
|
+
try {
|
|
11125
|
+
// 4. Create directories recursively
|
|
11126
|
+
await fs$5.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$5.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$3.join(dirPath, 'config.json');
|
|
11157
|
+
let config = {};
|
|
11158
|
+
|
|
11159
|
+
try {
|
|
11160
|
+
const fileContent = await fs$5.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$5.writeFile(configPath, JSON.stringify(config, null, 4), 'utf8');
|
|
11178
|
+
}
|
|
11179
|
+
|
|
11180
|
+
|
|
11181
|
+
var saver = {
|
|
11182
|
+
saveConfiguration: saveConfiguration$1,
|
|
11183
|
+
};
|
|
11184
|
+
|
|
11052
11185
|
/*
|
|
11053
11186
|
* Component: AnalyzerUtils Schema Loader
|
|
11054
11187
|
* Block-UUID: 0c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f
|
|
@@ -11412,6 +11545,7 @@ const { buildChatIdToPathMap: buildChatIdToPathMap$1 } = contextMapper;
|
|
|
11412
11545
|
const { processLLMAnalysisResponse: processLLMAnalysisResponse$1 } = responseProcessor;
|
|
11413
11546
|
const { validateLLMAnalysisData: validateLLMAnalysisData$1 } = dataValidator;
|
|
11414
11547
|
const { getAnalyzers: getAnalyzers$1 } = discovery;
|
|
11548
|
+
const { saveConfiguration } = saver;
|
|
11415
11549
|
const { getAnalyzerSchema: getAnalyzerSchema$1 } = schemaLoader;
|
|
11416
11550
|
const { deleteAnalyzer: deleteAnalyzer$1 } = management;
|
|
11417
11551
|
const { getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1 } = instructionLoader;
|
|
@@ -11424,6 +11558,7 @@ var AnalyzerUtils$1 = {
|
|
|
11424
11558
|
getAnalyzerSchema: getAnalyzerSchema$1,
|
|
11425
11559
|
deleteAnalyzer: deleteAnalyzer$1,
|
|
11426
11560
|
getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$1,
|
|
11561
|
+
saveConfiguration,
|
|
11427
11562
|
};
|
|
11428
11563
|
|
|
11429
11564
|
/**
|
|
@@ -11646,7 +11781,7 @@ const CodeBlockUtils = CodeBlockUtils$4;
|
|
|
11646
11781
|
const ContextUtils = ContextUtils$2;
|
|
11647
11782
|
const MessageUtils = MessageUtils$3;
|
|
11648
11783
|
const AnalysisBlockUtils = AnalysisBlockUtils$3;
|
|
11649
|
-
const AnalyzerUtils = AnalyzerUtils$1;
|
|
11784
|
+
const AnalyzerUtils = AnalyzerUtils$1;
|
|
11650
11785
|
const PatchUtils = PatchUtils$2;
|
|
11651
11786
|
const GSToolBlockUtils = GSToolBlockUtils$3;
|
|
11652
11787
|
const LLMUtils = LLMUtils$1;
|
|
@@ -11686,7 +11821,7 @@ const {
|
|
|
11686
11821
|
validateOverviewMetadata,
|
|
11687
11822
|
} = AnalysisBlockUtils;
|
|
11688
11823
|
|
|
11689
|
-
const {
|
|
11824
|
+
const {
|
|
11690
11825
|
buildChatIdToPathMap,
|
|
11691
11826
|
processLLMAnalysisResponse,
|
|
11692
11827
|
validateLLMAnalysisData,
|
|
@@ -11694,6 +11829,7 @@ const { // Updated AnalyzerUtils destructuring
|
|
|
11694
11829
|
getAnalyzerSchema,
|
|
11695
11830
|
deleteAnalyzer,
|
|
11696
11831
|
getAnalyzerInstructionsContent,
|
|
11832
|
+
saveAnalyzerConfiguration,
|
|
11697
11833
|
} = AnalyzerUtils;
|
|
11698
11834
|
|
|
11699
11835
|
const {
|
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@ const { buildChatIdToPathMap } = require('./contextMapper');
|
|
|
14
14
|
const { processLLMAnalysisResponse } = require('./responseProcessor');
|
|
15
15
|
const { validateLLMAnalysisData } = require('./dataValidator');
|
|
16
16
|
const { getAnalyzers } = require('./discovery');
|
|
17
|
+
const { saveConfiguration } = require('./saver');
|
|
17
18
|
const { getAnalyzerSchema } = require('./schemaLoader');
|
|
18
19
|
const { deleteAnalyzer } = require('./management');
|
|
19
20
|
const { getAnalyzerInstructionsContent } = require('./instructionLoader');
|
|
@@ -26,4 +27,5 @@ module.exports = {
|
|
|
26
27
|
getAnalyzerSchema,
|
|
27
28
|
deleteAnalyzer,
|
|
28
29
|
getAnalyzerInstructionsContent,
|
|
30
|
+
saveConfiguration,
|
|
29
31
|
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component: Analyzer Saver Utility
|
|
3
|
+
* Block-UUID: a373f4ba-89ce-465f-8624-24258c923e61
|
|
4
|
+
* Parent-UUID: N/A
|
|
5
|
+
* Version: 1.1.0
|
|
6
|
+
* Description: Utility function to save or update an analyzer configuration based on its ID and content.
|
|
7
|
+
* Language: JavaScript
|
|
8
|
+
* Created-at: 2025-07-12T04:12:33.454Z
|
|
9
|
+
* Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash Thinking (v1.1.0)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const fs = require('fs').promises;
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Saves or updates an analyzer configuration.
|
|
18
|
+
*
|
|
19
|
+
* This function takes the analyzer ID and its full instructions content,
|
|
20
|
+
* parses the ID to determine the directory structure, creates directories
|
|
21
|
+
* if necessary, saves the instructions to '1.md'. Optionally, it can
|
|
22
|
+
* ensure config.json files exist with labels derived from directory names.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} analyzeMessagesBasePath - The absolute or relative path to the 'messages/analyze' directory.
|
|
25
|
+
* @param {string} analyzerId - The unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
|
|
26
|
+
* @param {string} instructionsContent - The full content of the analyzer instructions message to be saved in '1.md'.
|
|
27
|
+
* @param {object} [options={}] - Optional configuration options.
|
|
28
|
+
* @param {boolean} [options.ensureConfigs=false] - If true, ensures config.json files exist in the analyzer, content, and instructions directories. Defaults to false.
|
|
29
|
+
* @returns {Promise<{success: boolean, message?: string}>} A promise that resolves with a result object.
|
|
30
|
+
*/
|
|
31
|
+
async function saveConfiguration(analyzeMessagesBasePath, analyzerId, instructionsContent, options = {}) {
|
|
32
|
+
const { ensureConfigs = false } = options;
|
|
33
|
+
|
|
34
|
+
// 1. Validate inputs
|
|
35
|
+
if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
|
|
36
|
+
return { success: false, message: 'analyzeMessagesBasePath is required.' };
|
|
37
|
+
}
|
|
38
|
+
if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
|
|
39
|
+
return { success: false, message: 'analyzerId is required.' };
|
|
40
|
+
}
|
|
41
|
+
if (typeof instructionsContent !== 'string' || instructionsContent.trim() === '') {
|
|
42
|
+
return { success: false, message: 'instructionsContent is required.' };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 2. Parse analyzerId
|
|
46
|
+
const parts = analyzerId.split('::');
|
|
47
|
+
if (parts.length !== 3) {
|
|
48
|
+
return { success: false, message: `Invalid analyzerId format. Expected 'analyzer_name::content_type::instructions_type', but got '${analyzerId}'.` };
|
|
49
|
+
}
|
|
50
|
+
const [analyzerName, contentType, instructionsType] = parts;
|
|
51
|
+
|
|
52
|
+
// Helper to validate directory names based on README.md rules
|
|
53
|
+
const isValidDirName = (name) => {
|
|
54
|
+
// Cannot start with underscore, cannot contain dots, must be alphanumeric, dash, or underscore
|
|
55
|
+
return /^[a-zA-Z0-9_-]+$/.test(name) && !name.startsWith('_') && !name.includes('.');
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
if (!isValidDirName(analyzerName)) {
|
|
59
|
+
return { success: false, message: `Invalid analyzer name '${analyzerName}'. Names must be alphanumeric, dash, or underscore, cannot start with underscore, and cannot contain dots.` };
|
|
60
|
+
}
|
|
61
|
+
if (!isValidDirName(contentType)) {
|
|
62
|
+
return { success: false, message: `Invalid content type name '${contentType}'. Names must be alphanumeric, dash, or underscore, cannot start with underscore, and cannot contain dots.` };
|
|
63
|
+
}
|
|
64
|
+
if (!isValidDirName(instructionsType)) {
|
|
65
|
+
return { success: false, message: `Invalid instructions type name '${instructionsType}'. Names must be alphanumeric, dash, or underscore, cannot start with underscore, and cannot contain dots.` };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 3. Construct directory paths
|
|
69
|
+
const analyzerDir = path.join(analyzeMessagesBasePath, analyzerName);
|
|
70
|
+
const contentDir = path.join(analyzerDir, contentType);
|
|
71
|
+
const instructionsDir = path.join(contentDir, instructionsType);
|
|
72
|
+
const instructionsFilePath = path.join(instructionsDir, '1.md');
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
// 4. Create directories recursively
|
|
76
|
+
await fs.mkdir(instructionsDir, { recursive: true });
|
|
77
|
+
|
|
78
|
+
// 5. Save instructions content to 1.md
|
|
79
|
+
const finalContent = `; role: assistant\n\n\n${instructionsContent}`;
|
|
80
|
+
await fs.writeFile(instructionsFilePath, finalContent, 'utf8');
|
|
81
|
+
|
|
82
|
+
// 6. Optionally create/Update config.json files
|
|
83
|
+
if (ensureConfigs) {
|
|
84
|
+
await ensureConfigJson(analyzerDir, analyzerName);
|
|
85
|
+
await ensureConfigJson(contentDir, contentType);
|
|
86
|
+
await ensureConfigJson(instructionsDir, instructionsType);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { success: true, message: `Analyzer configuration '${analyzerId}' saved successfully.` };
|
|
90
|
+
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error(`Error saving analyzer configuration '${analyzerId}':`, error);
|
|
93
|
+
return { success: false, message: `Failed to save analyzer configuration: ${error.message}` };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Ensures a config.json file exists in the given directory with a label.
|
|
99
|
+
* If the file exists, it reads it and adds the label if missing.
|
|
100
|
+
* If the file doesn't exist, it creates it with the label.
|
|
101
|
+
*
|
|
102
|
+
* @param {string} dirPath - The path to the directory.
|
|
103
|
+
* @param {string} label - The label to ensure is in the config.json.
|
|
104
|
+
*/
|
|
105
|
+
async function ensureConfigJson(dirPath, label) {
|
|
106
|
+
const configPath = path.join(dirPath, 'config.json');
|
|
107
|
+
let config = {};
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const fileContent = await fs.readFile(configPath, 'utf8');
|
|
111
|
+
config = JSON.parse(fileContent);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
// If file doesn't exist or parsing fails, start with an empty config
|
|
114
|
+
if (error.code !== 'ENOENT') {
|
|
115
|
+
console.warn(`Failed to read or parse existing config.json in ${dirPath}: ${error.message}`);
|
|
116
|
+
}
|
|
117
|
+
config = {}; // Ensure config is an object even on error
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Add or update the label if it's missing or empty
|
|
121
|
+
if (!config.label || typeof config.label !== 'string' || config.label.trim() === '') {
|
|
122
|
+
// Capitalize the first letter for the label
|
|
123
|
+
config.label = label.charAt(0).toUpperCase() + label.slice(1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Write the updated config back to the file
|
|
127
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 4), 'utf8');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
module.exports = {
|
|
132
|
+
saveConfiguration,
|
|
133
|
+
};
|
package/src/GitSenseChatUtils.js
CHANGED
|
@@ -15,7 +15,7 @@ const CodeBlockUtils = require('./CodeBlockUtils');
|
|
|
15
15
|
const ContextUtils = require('./ContextUtils');
|
|
16
16
|
const MessageUtils = require('./MessageUtils');
|
|
17
17
|
const AnalysisBlockUtils = require('./AnalysisBlockUtils');
|
|
18
|
-
const AnalyzerUtils = require('./AnalyzerUtils');
|
|
18
|
+
const AnalyzerUtils = require('./AnalyzerUtils');
|
|
19
19
|
const PatchUtils = require('./PatchUtils');
|
|
20
20
|
const GSToolBlockUtils = require('./GSToolBlockUtils');
|
|
21
21
|
const LLMUtils = require('./LLMUtils');
|
|
@@ -55,7 +55,7 @@ const {
|
|
|
55
55
|
validateOverviewMetadata,
|
|
56
56
|
} = AnalysisBlockUtils;
|
|
57
57
|
|
|
58
|
-
const {
|
|
58
|
+
const {
|
|
59
59
|
buildChatIdToPathMap,
|
|
60
60
|
processLLMAnalysisResponse,
|
|
61
61
|
validateLLMAnalysisData,
|
|
@@ -63,6 +63,7 @@ const { // Updated AnalyzerUtils destructuring
|
|
|
63
63
|
getAnalyzerSchema,
|
|
64
64
|
deleteAnalyzer,
|
|
65
65
|
getAnalyzerInstructionsContent,
|
|
66
|
+
saveAnalyzerConfiguration,
|
|
66
67
|
} = AnalyzerUtils;
|
|
67
68
|
|
|
68
69
|
const {
|