@gitsense/gsc-utils 0.2.15 → 0.2.17
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 +189 -112
- package/dist/gsc-utils.esm.js +189 -112
- package/package.json +1 -1
- package/src/AnalyzerUtils/defaultPromptLoader.js +1 -1
- package/src/AnalyzerUtils/discovery.js +24 -8
- package/src/GSToolBlockUtils.js +68 -7
package/dist/gsc-utils.cjs.js
CHANGED
|
@@ -8684,13 +8684,13 @@ var PatchUtils$2 = {
|
|
|
8684
8684
|
|
|
8685
8685
|
/**
|
|
8686
8686
|
* Component: GitSense Tool Block Utilities
|
|
8687
|
-
* Block-UUID:
|
|
8688
|
-
* Parent-UUID:
|
|
8689
|
-
* Version: 1.
|
|
8690
|
-
* Description: Provides utility functions for identifying and parsing GitSense Chat Tool Blocks.
|
|
8687
|
+
* Block-UUID: 8e1f7b4e-7e30-48b4-a7fc-643bf647661f
|
|
8688
|
+
* Parent-UUID: 72db6a5f-3b09-49e8-8f39-d4e3d37b510a
|
|
8689
|
+
* Version: 1.1.0
|
|
8690
|
+
* Description: Provides utility functions for identifying and parsing GitSense Chat Tool Blocks, and now for replacing them within markdown.
|
|
8691
8691
|
* Language: JavaScript
|
|
8692
|
-
* Created-at: 2025-
|
|
8693
|
-
* Authors: Gemini 2.5 Pro (v1.0.0)
|
|
8692
|
+
* Created-at: 2025-09-12T17:23:34.779Z
|
|
8693
|
+
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Flash (v1.1.0)
|
|
8694
8694
|
*/
|
|
8695
8695
|
|
|
8696
8696
|
/**
|
|
@@ -8780,14 +8780,75 @@ function parseToolBlock$1(content) {
|
|
|
8780
8780
|
}
|
|
8781
8781
|
}
|
|
8782
8782
|
|
|
8783
|
+
/**
|
|
8784
|
+
* Formats tool data into a GitSense Chat Tool Block string.
|
|
8785
|
+
*
|
|
8786
|
+
* @param {object} toolData - The tool data object to format.
|
|
8787
|
+
* @returns {string} The formatted GitSense Chat Tool Block string.
|
|
8788
|
+
*/
|
|
8783
8789
|
function formatToolBlock(toolData) {
|
|
8784
8790
|
return `# GitSense Chat Tool\n\n${JSON.stringify(toolData, null, 2)}`;
|
|
8785
8791
|
}
|
|
8786
8792
|
|
|
8793
|
+
/**
|
|
8794
|
+
* Replaces a specific GitSense Chat Tool Block within a markdown string with updated tool data.
|
|
8795
|
+
* This function leverages CodeBlockUtils for robust parsing and updating.
|
|
8796
|
+
*
|
|
8797
|
+
* @param {string} markdownContent - The original markdown string containing code blocks.
|
|
8798
|
+
* @param {string} toolName - The 'tool' property value of the target GitSense Chat Tool Block to replace.
|
|
8799
|
+
* @param {Object} newToolData - The new tool data object to insert into the block.
|
|
8800
|
+
* @returns {string} The markdown content with the specified tool block updated.
|
|
8801
|
+
* @throws {Error} If the target tool block is not found or if CodeBlockUtils encounters an error.
|
|
8802
|
+
*/
|
|
8803
|
+
function replaceToolBlock(markdownContent, toolName, newToolData, processCodeBlocks, updateCodeBlockByIndex) {
|
|
8804
|
+
if (typeof markdownContent !== 'string' || !toolName || !newToolData) {
|
|
8805
|
+
throw new Error("Missing required parameters for replaceToolBlock.");
|
|
8806
|
+
}
|
|
8807
|
+
|
|
8808
|
+
// We can't require them as this will create a circular dependency
|
|
8809
|
+
if (!processCodeBlocks || !updateCodeBlockByIndex) {
|
|
8810
|
+
throw new Error("Missing required dependencies processCodeBlocks and/or updateCodeBlockByIndex.");
|
|
8811
|
+
}
|
|
8812
|
+
|
|
8813
|
+
// 1. Process the markdown content to find all code blocks
|
|
8814
|
+
const { blocks, warnings } = processCodeBlocks(markdownContent, { silent: true });
|
|
8815
|
+
|
|
8816
|
+
let targetBlockIndex = -1;
|
|
8817
|
+
|
|
8818
|
+
// 2. Iterate through the processed blocks to find the target GitSense Chat Tool Block
|
|
8819
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
8820
|
+
const block = blocks[i];
|
|
8821
|
+
if (block.type === 'gs-tool' && block.toolData && block.toolData.tool === toolName) {
|
|
8822
|
+
targetBlockIndex = i;
|
|
8823
|
+
break; // Found the first matching tool block
|
|
8824
|
+
}
|
|
8825
|
+
}
|
|
8826
|
+
|
|
8827
|
+
if (targetBlockIndex === -1) {
|
|
8828
|
+
console.warn(`replaceToolBlock: No GitSense Chat Tool Block with name "${toolName}" found to replace.`);
|
|
8829
|
+
return markdownContent; // Return original content if no replacement occurred
|
|
8830
|
+
}
|
|
8831
|
+
|
|
8832
|
+
// 3. Format the new tool data into the content that goes *inside* the fences
|
|
8833
|
+
const newContentBetweenFences = formatToolBlock(newToolData);
|
|
8834
|
+
|
|
8835
|
+
// 4. Use CodeBlockUtils.updateCodeBlockByIndex to perform the replacement
|
|
8836
|
+
// The language for GitSense Tool Blocks is always 'txt'
|
|
8837
|
+
const updatedMarkdown = updateCodeBlockByIndex(
|
|
8838
|
+
markdownContent,
|
|
8839
|
+
targetBlockIndex,
|
|
8840
|
+
newContentBetweenFences,
|
|
8841
|
+
'txt'
|
|
8842
|
+
);
|
|
8843
|
+
|
|
8844
|
+
return updatedMarkdown;
|
|
8845
|
+
}
|
|
8846
|
+
|
|
8787
8847
|
var GSToolBlockUtils$3 = {
|
|
8788
8848
|
isToolBlock: isToolBlock$1,
|
|
8789
8849
|
parseToolBlock: parseToolBlock$1,
|
|
8790
|
-
formatToolBlock
|
|
8850
|
+
formatToolBlock,
|
|
8851
|
+
replaceToolBlock,
|
|
8791
8852
|
};
|
|
8792
8853
|
|
|
8793
8854
|
/*
|
|
@@ -11072,11 +11133,11 @@ var dataValidator = {
|
|
|
11072
11133
|
};
|
|
11073
11134
|
|
|
11074
11135
|
/*
|
|
11075
|
-
* Component: AnalyzerUtils
|
|
11076
|
-
* Block-UUID:
|
|
11136
|
+
* Component: AnalyzerUtils Instruction Loader
|
|
11137
|
+
* Block-UUID: 0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5e
|
|
11077
11138
|
* Parent-UUID: N/A
|
|
11078
11139
|
* Version: 1.0.0
|
|
11079
|
-
* Description: Provides utility functions for
|
|
11140
|
+
* Description: Provides utility functions for loading raw analyzer instruction content.
|
|
11080
11141
|
* Language: JavaScript
|
|
11081
11142
|
* Created-at: 2025-08-28T23:48:00.000Z
|
|
11082
11143
|
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
@@ -11085,6 +11146,67 @@ var dataValidator = {
|
|
|
11085
11146
|
const fs$7 = require$$0.promises;
|
|
11086
11147
|
const path$5 = require$$1;
|
|
11087
11148
|
|
|
11149
|
+
/**
|
|
11150
|
+
* Retrieves the raw Markdown content of the analyzer's '1.md' instruction file.
|
|
11151
|
+
*
|
|
11152
|
+
* @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
|
|
11153
|
+
* @param {string} analyzerId - The unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
|
|
11154
|
+
* @returns {Promise<string|null>} A promise that resolves with the full Markdown content of the '1.md' file, or null if not found/invalid.
|
|
11155
|
+
*/
|
|
11156
|
+
async function getAnalyzerInstructionsContent$3(analyzeMessagesBasePath, analyzerId) {
|
|
11157
|
+
if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
|
|
11158
|
+
console.error('Error: analyzeMessagesBasePath is required.');
|
|
11159
|
+
return null;
|
|
11160
|
+
}
|
|
11161
|
+
if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
|
|
11162
|
+
console.error('Error: analyzerId is required.');
|
|
11163
|
+
return null;
|
|
11164
|
+
}
|
|
11165
|
+
|
|
11166
|
+
const parts = analyzerId.split('::');
|
|
11167
|
+
if (parts.length !== 3) {
|
|
11168
|
+
console.error(`Error: Invalid analyzerId format. Expected 'analyzer_name::content_type::instructions_type', but got '${analyzerId}'.`);
|
|
11169
|
+
return null;
|
|
11170
|
+
}
|
|
11171
|
+
const [analyzerName, contentType, instructionsType] = parts;
|
|
11172
|
+
|
|
11173
|
+
const instructionsFilePath = path$5.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
|
|
11174
|
+
|
|
11175
|
+
try {
|
|
11176
|
+
const fileContent = await fs$7.readFile(instructionsFilePath, 'utf8');
|
|
11177
|
+
const parts = fileContent.split('\n\n\n');
|
|
11178
|
+
parts.shift();
|
|
11179
|
+
return parts.join('\n\n\n');
|
|
11180
|
+
} catch (error) {
|
|
11181
|
+
if (error.code === 'ENOENT') {
|
|
11182
|
+
console.warn(`Analyzer instructions file not found: ${instructionsFilePath}`);
|
|
11183
|
+
return null;
|
|
11184
|
+
} else {
|
|
11185
|
+
console.error(`Error reading analyzer instructions file ${instructionsFilePath}: ${error.message}`);
|
|
11186
|
+
throw error;
|
|
11187
|
+
}
|
|
11188
|
+
}
|
|
11189
|
+
}
|
|
11190
|
+
|
|
11191
|
+
var instructionLoader = {
|
|
11192
|
+
getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$3
|
|
11193
|
+
};
|
|
11194
|
+
|
|
11195
|
+
/*
|
|
11196
|
+
* Component: AnalyzerUtils Discovery
|
|
11197
|
+
* Block-UUID: a87a86c4-69fc-4cbb-80a8-857f56122395
|
|
11198
|
+
* Parent-UUID: 0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5f
|
|
11199
|
+
* Version: 1.1.0
|
|
11200
|
+
* Description: Provides utility functions for discovering available analyzers.
|
|
11201
|
+
* Language: JavaScript
|
|
11202
|
+
* Created-at: 2025-08-28T23:48:00.000Z
|
|
11203
|
+
* Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0)
|
|
11204
|
+
*/
|
|
11205
|
+
|
|
11206
|
+
const fs$6 = require$$0.promises;
|
|
11207
|
+
const path$4 = require$$1;
|
|
11208
|
+
const { getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$2 } = instructionLoader;
|
|
11209
|
+
|
|
11088
11210
|
/**
|
|
11089
11211
|
* Reads and parses the config.json file in a directory.
|
|
11090
11212
|
* @param {string} dirPath - The path to the directory.
|
|
@@ -11092,9 +11214,9 @@ const path$5 = require$$1;
|
|
|
11092
11214
|
* or null if the file doesn't exist or is invalid.
|
|
11093
11215
|
*/
|
|
11094
11216
|
async function readConfig$1(dirPath) {
|
|
11095
|
-
const configPath = path$
|
|
11217
|
+
const configPath = path$4.join(dirPath, 'config.json');
|
|
11096
11218
|
try {
|
|
11097
|
-
const fileContent = await fs$
|
|
11219
|
+
const fileContent = await fs$6.readFile(configPath, 'utf8');
|
|
11098
11220
|
return JSON.parse(fileContent);
|
|
11099
11221
|
} catch (error) {
|
|
11100
11222
|
if (error.code !== 'ENOENT') {
|
|
@@ -11125,47 +11247,50 @@ function isValidDirName(name) {
|
|
|
11125
11247
|
* An analyzer is considered valid if a '1.md' file exists in the instructions directory.
|
|
11126
11248
|
*
|
|
11127
11249
|
* @param {string} analyzeMessagesBasePath - The absolute or relative path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
|
|
11128
|
-
* @
|
|
11250
|
+
* @param {object} [options={}] - Optional configuration.
|
|
11251
|
+
* @param {boolean} [options.includeDescription=false] - Whether to include the description of the analyzer.
|
|
11252
|
+
* @returns {Promise<Array<{id: string, label: string, name: string, protected: boolean, description?: string}>>} A promise that resolves to an array of analyzer objects.
|
|
11129
11253
|
*/
|
|
11130
|
-
async function getAnalyzers$2(analyzeMessagesBasePath) {
|
|
11254
|
+
async function getAnalyzers$2(analyzeMessagesBasePath, options = {}) {
|
|
11255
|
+
const { includeDescription = false } = options;
|
|
11131
11256
|
const analyzers = [];
|
|
11132
11257
|
|
|
11133
11258
|
try {
|
|
11134
|
-
const analyzerEntries = await fs$
|
|
11259
|
+
const analyzerEntries = await fs$6.readdir(analyzeMessagesBasePath, { withFileTypes: true });
|
|
11135
11260
|
|
|
11136
11261
|
for (const analyzerEntry of analyzerEntries) {
|
|
11137
11262
|
if (analyzerEntry.isDirectory() && isValidDirName(analyzerEntry.name)) {
|
|
11138
11263
|
const analyzerName = analyzerEntry.name;
|
|
11139
|
-
const analyzerPath = path$
|
|
11264
|
+
const analyzerPath = path$4.join(analyzeMessagesBasePath, analyzerName);
|
|
11140
11265
|
const analyzerConfig = await readConfig$1(analyzerPath);
|
|
11141
11266
|
const analyzerLabel = analyzerConfig?.label || analyzerName;
|
|
11142
11267
|
|
|
11143
|
-
const contentEntries = await fs$
|
|
11268
|
+
const contentEntries = await fs$6.readdir(analyzerPath, { withFileTypes: true });
|
|
11144
11269
|
|
|
11145
11270
|
for (const contentEntry of contentEntries) {
|
|
11146
11271
|
if (contentEntry.isDirectory() && isValidDirName(contentEntry.name)) {
|
|
11147
11272
|
const contentType = contentEntry.name;
|
|
11148
|
-
const contentPath = path$
|
|
11273
|
+
const contentPath = path$4.join(analyzerPath, contentType);
|
|
11149
11274
|
const contentConfig = await readConfig$1(contentPath);
|
|
11150
11275
|
const contentLabel = contentConfig?.label || contentType;
|
|
11151
11276
|
|
|
11152
|
-
const instructionsEntries = await fs$
|
|
11277
|
+
const instructionsEntries = await fs$6.readdir(contentPath, { withFileTypes: true });
|
|
11153
11278
|
|
|
11154
11279
|
for (const instructionsEntry of instructionsEntries) {
|
|
11155
11280
|
if (instructionsEntry.isDirectory() && isValidDirName(instructionsEntry.name)) {
|
|
11156
11281
|
const instructionsType = instructionsEntry.name;
|
|
11157
|
-
const instructionsPath = path$
|
|
11282
|
+
const instructionsPath = path$4.join(contentPath, instructionsType);
|
|
11158
11283
|
const instructionsConfig = await readConfig$1(instructionsPath);
|
|
11159
11284
|
const instructionsLabel = instructionsConfig?.label || instructionsType;
|
|
11160
11285
|
|
|
11161
11286
|
// Check for the existence of 1.md to confirm a valid analyzer configuration
|
|
11162
|
-
const instructionsFilePath = path$
|
|
11287
|
+
const instructionsFilePath = path$4.join(instructionsPath, '1.md');
|
|
11163
11288
|
try {
|
|
11164
|
-
await fs$
|
|
11289
|
+
await fs$6.access(instructionsFilePath); // Check if file exists and is accessible
|
|
11165
11290
|
|
|
11166
11291
|
// If analyzerName starts with 'tutorial-', check its last modified time.
|
|
11167
11292
|
if (analyzerName.startsWith('tutorial-')) {
|
|
11168
|
-
const stats = await fs$
|
|
11293
|
+
const stats = await fs$6.stat(instructionsFilePath);
|
|
11169
11294
|
const lastModified = stats.mtime.getTime(); // Get timestamp in milliseconds
|
|
11170
11295
|
const sixtyMinutesAgo = Date.now() - (60 * 60 * 1000); // Current time - 60 minutes in ms
|
|
11171
11296
|
|
|
@@ -11178,11 +11303,23 @@ async function getAnalyzers$2(analyzeMessagesBasePath) {
|
|
|
11178
11303
|
const analyzerId = `${analyzerName}::${contentType}::${instructionsType}`;
|
|
11179
11304
|
const analyzerFullLabel = `${analyzerLabel} (${contentLabel} - ${instructionsLabel})`;
|
|
11180
11305
|
|
|
11306
|
+
let descriptionContent = null;
|
|
11307
|
+
if (includeDescription) {
|
|
11308
|
+
try {
|
|
11309
|
+
descriptionContent = await getAnalyzerInstructionsContent$2(analyzeMessagesBasePath, analyzerId);
|
|
11310
|
+
} catch (descError) {
|
|
11311
|
+
console.warn(`Warning: Could not load description for ${analyzerId}: ${descError.message}`);
|
|
11312
|
+
descriptionContent = null;
|
|
11313
|
+
}
|
|
11314
|
+
}
|
|
11315
|
+
|
|
11181
11316
|
analyzers.push({
|
|
11182
11317
|
id: analyzerId,
|
|
11183
11318
|
label: analyzerFullLabel,
|
|
11184
|
-
|
|
11185
|
-
|
|
11319
|
+
name: analyzerName,
|
|
11320
|
+
protected: analyzerConfig?.protected || false,
|
|
11321
|
+
...(descriptionContent && { description: descriptionContent })
|
|
11322
|
+
});
|
|
11186
11323
|
} catch (error) {
|
|
11187
11324
|
// If 1.md doesn't exist, this is not a complete analyzer configuration, skip.
|
|
11188
11325
|
if (error.code !== 'ENOENT') {
|
|
@@ -11219,8 +11356,8 @@ var discovery = {
|
|
|
11219
11356
|
* Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash Thinking (v1.1.0)
|
|
11220
11357
|
*/
|
|
11221
11358
|
|
|
11222
|
-
const fs$
|
|
11223
|
-
const path$
|
|
11359
|
+
const fs$5 = require$$0.promises;
|
|
11360
|
+
const path$3 = require$$1;
|
|
11224
11361
|
|
|
11225
11362
|
/**
|
|
11226
11363
|
* Saves or updates an analyzer configuration.
|
|
@@ -11275,18 +11412,18 @@ async function saveConfiguration$1(analyzeMessagesBasePath, analyzerId, instruct
|
|
|
11275
11412
|
}
|
|
11276
11413
|
|
|
11277
11414
|
// 3. Construct directory paths
|
|
11278
|
-
const analyzerDir = path$
|
|
11279
|
-
const contentDir = path$
|
|
11280
|
-
const instructionsDir = path$
|
|
11281
|
-
const instructionsFilePath = path$
|
|
11415
|
+
const analyzerDir = path$3.join(analyzeMessagesBasePath, analyzerName);
|
|
11416
|
+
const contentDir = path$3.join(analyzerDir, contentType);
|
|
11417
|
+
const instructionsDir = path$3.join(contentDir, instructionsType);
|
|
11418
|
+
const instructionsFilePath = path$3.join(instructionsDir, '1.md');
|
|
11282
11419
|
|
|
11283
11420
|
try {
|
|
11284
11421
|
// 4. Create directories recursively
|
|
11285
|
-
await fs$
|
|
11422
|
+
await fs$5.mkdir(instructionsDir, { recursive: true });
|
|
11286
11423
|
|
|
11287
11424
|
// 5. Save instructions content to 1.md
|
|
11288
11425
|
const finalContent = `; role: assistant\n\n\n${instructionsContent}`;
|
|
11289
|
-
await fs$
|
|
11426
|
+
await fs$5.writeFile(instructionsFilePath, finalContent, 'utf8');
|
|
11290
11427
|
|
|
11291
11428
|
// 6. Optionally create/Update config.json files
|
|
11292
11429
|
if (ensureConfigs) {
|
|
@@ -11312,11 +11449,11 @@ async function saveConfiguration$1(analyzeMessagesBasePath, analyzerId, instruct
|
|
|
11312
11449
|
* @param {string} label - The label to ensure is in the config.json.
|
|
11313
11450
|
*/
|
|
11314
11451
|
async function ensureConfigJson(dirPath, label) {
|
|
11315
|
-
const configPath = path$
|
|
11452
|
+
const configPath = path$3.join(dirPath, 'config.json');
|
|
11316
11453
|
let config = {};
|
|
11317
11454
|
|
|
11318
11455
|
try {
|
|
11319
|
-
const fileContent = await fs$
|
|
11456
|
+
const fileContent = await fs$5.readFile(configPath, 'utf8');
|
|
11320
11457
|
config = JSON.parse(fileContent);
|
|
11321
11458
|
} catch (error) {
|
|
11322
11459
|
// If file doesn't exist or parsing fails, start with an empty config
|
|
@@ -11333,7 +11470,7 @@ async function ensureConfigJson(dirPath, label) {
|
|
|
11333
11470
|
}
|
|
11334
11471
|
|
|
11335
11472
|
// Write the updated config back to the file
|
|
11336
|
-
await fs$
|
|
11473
|
+
await fs$5.writeFile(configPath, JSON.stringify(config, null, 4), 'utf8');
|
|
11337
11474
|
}
|
|
11338
11475
|
|
|
11339
11476
|
|
|
@@ -11352,8 +11489,8 @@ var saver = {
|
|
|
11352
11489
|
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
11353
11490
|
*/
|
|
11354
11491
|
|
|
11355
|
-
const fs$
|
|
11356
|
-
const path$
|
|
11492
|
+
const fs$4 = require$$0.promises;
|
|
11493
|
+
const path$2 = require$$1;
|
|
11357
11494
|
const CodeBlockUtils$1 = CodeBlockUtils$4;
|
|
11358
11495
|
|
|
11359
11496
|
/**
|
|
@@ -11439,10 +11576,10 @@ async function getAnalyzerSchema$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11439
11576
|
}
|
|
11440
11577
|
const [analyzerName, contentType, instructionsType] = parts;
|
|
11441
11578
|
|
|
11442
|
-
const instructionsFilePath = path$
|
|
11579
|
+
const instructionsFilePath = path$2.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
|
|
11443
11580
|
|
|
11444
11581
|
try {
|
|
11445
|
-
const fileContent = await fs$
|
|
11582
|
+
const fileContent = await fs$4.readFile(instructionsFilePath, 'utf8');
|
|
11446
11583
|
const { blocks } = CodeBlockUtils$1.extractCodeBlocks(fileContent, { silent: true });
|
|
11447
11584
|
const jsonBlocks = blocks.filter(block => block.type === 'code' && block.language === 'json');
|
|
11448
11585
|
|
|
@@ -11513,8 +11650,8 @@ var schemaLoader = {
|
|
|
11513
11650
|
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
11514
11651
|
*/
|
|
11515
11652
|
|
|
11516
|
-
const fs$
|
|
11517
|
-
const path$
|
|
11653
|
+
const fs$3 = require$$0.promises;
|
|
11654
|
+
const path$1 = require$$1;
|
|
11518
11655
|
const { readConfig } = discovery; // Import helper from discovery
|
|
11519
11656
|
|
|
11520
11657
|
/**
|
|
@@ -11524,7 +11661,7 @@ const { readConfig } = discovery; // Import helper from discovery
|
|
|
11524
11661
|
*/
|
|
11525
11662
|
async function isDirectoryEmpty(dirPath) {
|
|
11526
11663
|
try {
|
|
11527
|
-
const files = await fs$
|
|
11664
|
+
const files = await fs$3.readdir(dirPath);
|
|
11528
11665
|
return files.length === 0 || (files.length === 1 && files[0] === 'config.json');
|
|
11529
11666
|
} catch (error) {
|
|
11530
11667
|
if (error.code === 'ENOENT') {
|
|
@@ -11555,10 +11692,10 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11555
11692
|
}
|
|
11556
11693
|
const [analyzerName, contentType, instructionsType] = parts;
|
|
11557
11694
|
|
|
11558
|
-
const analyzerDir = path$
|
|
11559
|
-
const contentDir = path$
|
|
11560
|
-
const instructionsDir = path$
|
|
11561
|
-
const instructionsFilePath = path$
|
|
11695
|
+
const analyzerDir = path$1.join(analyzeMessagesBasePath, analyzerName);
|
|
11696
|
+
const contentDir = path$1.join(analyzerDir, contentType);
|
|
11697
|
+
const instructionsDir = path$1.join(contentDir, instructionsType);
|
|
11698
|
+
const instructionsFilePath = path$1.join(instructionsDir, '1.md');
|
|
11562
11699
|
|
|
11563
11700
|
try {
|
|
11564
11701
|
// 1. Check for protection at all levels
|
|
@@ -11579,7 +11716,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11579
11716
|
|
|
11580
11717
|
// 2. Delete the 1.md file
|
|
11581
11718
|
try {
|
|
11582
|
-
await fs$
|
|
11719
|
+
await fs$3.unlink(instructionsFilePath);
|
|
11583
11720
|
} catch (error) {
|
|
11584
11721
|
if (error.code === 'ENOENT') {
|
|
11585
11722
|
return { success: false, message: `Analyzer instructions file not found: ${instructionsFilePath}. It may have already been deleted.` };
|
|
@@ -11593,7 +11730,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11593
11730
|
// Check and delete instructions directory
|
|
11594
11731
|
if (await isDirectoryEmpty(instructionsDir)) {
|
|
11595
11732
|
try {
|
|
11596
|
-
await fs$
|
|
11733
|
+
await fs$3.rmdir(instructionsDir);
|
|
11597
11734
|
deletedDirs.push(instructionsDir);
|
|
11598
11735
|
} catch (error) {
|
|
11599
11736
|
console.warn(`Warning: Could not remove empty instructions directory ${instructionsDir}: ${error.message}`);
|
|
@@ -11603,7 +11740,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11603
11740
|
// Check and delete content directory
|
|
11604
11741
|
if (await isDirectoryEmpty(contentDir)) {
|
|
11605
11742
|
try {
|
|
11606
|
-
await fs$
|
|
11743
|
+
await fs$3.rmdir(contentDir);
|
|
11607
11744
|
deletedDirs.push(contentDir);
|
|
11608
11745
|
} catch (error) {
|
|
11609
11746
|
console.warn(`Warning: Could not remove empty content directory ${contentDir}: ${error.message}`);
|
|
@@ -11613,7 +11750,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11613
11750
|
// Check and delete analyzer directory
|
|
11614
11751
|
if (await isDirectoryEmpty(analyzerDir)) {
|
|
11615
11752
|
try {
|
|
11616
|
-
await fs$
|
|
11753
|
+
await fs$3.rmdir(analyzerDir);
|
|
11617
11754
|
deletedDirs.push(analyzerDir);
|
|
11618
11755
|
} catch (error) {
|
|
11619
11756
|
console.warn(`Warning: Could not remove empty analyzer directory ${analyzerDir}: ${error.message}`);
|
|
@@ -11631,69 +11768,9 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11631
11768
|
var management = {
|
|
11632
11769
|
deleteAnalyzer: deleteAnalyzer$2};
|
|
11633
11770
|
|
|
11634
|
-
/*
|
|
11635
|
-
* Component: AnalyzerUtils Instruction Loader
|
|
11636
|
-
* Block-UUID: 0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5e
|
|
11637
|
-
* Parent-UUID: N/A
|
|
11638
|
-
* Version: 1.0.0
|
|
11639
|
-
* Description: Provides utility functions for loading raw analyzer instruction content.
|
|
11640
|
-
* Language: JavaScript
|
|
11641
|
-
* Created-at: 2025-08-28T23:48:00.000Z
|
|
11642
|
-
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
11643
|
-
*/
|
|
11644
|
-
|
|
11645
|
-
const fs$3 = require$$0.promises;
|
|
11646
|
-
const path$1 = require$$1;
|
|
11647
|
-
|
|
11648
|
-
/**
|
|
11649
|
-
* Retrieves the raw Markdown content of the analyzer's '1.md' instruction file.
|
|
11650
|
-
*
|
|
11651
|
-
* @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
|
|
11652
|
-
* @param {string} analyzerId - The unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
|
|
11653
|
-
* @returns {Promise<string|null>} A promise that resolves with the full Markdown content of the '1.md' file, or null if not found/invalid.
|
|
11654
|
-
*/
|
|
11655
|
-
async function getAnalyzerInstructionsContent$2(analyzeMessagesBasePath, analyzerId) {
|
|
11656
|
-
if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
|
|
11657
|
-
console.error('Error: analyzeMessagesBasePath is required.');
|
|
11658
|
-
return null;
|
|
11659
|
-
}
|
|
11660
|
-
if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
|
|
11661
|
-
console.error('Error: analyzerId is required.');
|
|
11662
|
-
return null;
|
|
11663
|
-
}
|
|
11664
|
-
|
|
11665
|
-
const parts = analyzerId.split('::');
|
|
11666
|
-
if (parts.length !== 3) {
|
|
11667
|
-
console.error(`Error: Invalid analyzerId format. Expected 'analyzer_name::content_type::instructions_type', but got '${analyzerId}'.`);
|
|
11668
|
-
return null;
|
|
11669
|
-
}
|
|
11670
|
-
const [analyzerName, contentType, instructionsType] = parts;
|
|
11671
|
-
|
|
11672
|
-
const instructionsFilePath = path$1.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
|
|
11673
|
-
|
|
11674
|
-
try {
|
|
11675
|
-
const fileContent = await fs$3.readFile(instructionsFilePath, 'utf8');
|
|
11676
|
-
const parts = fileContent.split('\n\n\n');
|
|
11677
|
-
parts.shift();
|
|
11678
|
-
return parts.join('\n\n\n');
|
|
11679
|
-
} catch (error) {
|
|
11680
|
-
if (error.code === 'ENOENT') {
|
|
11681
|
-
console.warn(`Analyzer instructions file not found: ${instructionsFilePath}`);
|
|
11682
|
-
return null;
|
|
11683
|
-
} else {
|
|
11684
|
-
console.error(`Error reading analyzer instructions file ${instructionsFilePath}: ${error.message}`);
|
|
11685
|
-
throw error;
|
|
11686
|
-
}
|
|
11687
|
-
}
|
|
11688
|
-
}
|
|
11689
|
-
|
|
11690
|
-
var instructionLoader = {
|
|
11691
|
-
getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$2
|
|
11692
|
-
};
|
|
11693
|
-
|
|
11694
11771
|
/*
|
|
11695
11772
|
* Component: AnalyzerUtils Default Prompt Loader
|
|
11696
|
-
* Block-UUID:
|
|
11773
|
+
* Block-UUID: be863744-6461-4b94-97ce-b1d177e9e881
|
|
11697
11774
|
* Parent-UUID: N/A
|
|
11698
11775
|
* Version: 1.0.0
|
|
11699
11776
|
* Description: Provides utility functions for loading shared, default prompt components (system and start messages).
|
package/dist/gsc-utils.esm.js
CHANGED
|
@@ -8682,13 +8682,13 @@ var PatchUtils$2 = {
|
|
|
8682
8682
|
|
|
8683
8683
|
/**
|
|
8684
8684
|
* Component: GitSense Tool Block Utilities
|
|
8685
|
-
* Block-UUID:
|
|
8686
|
-
* Parent-UUID:
|
|
8687
|
-
* Version: 1.
|
|
8688
|
-
* Description: Provides utility functions for identifying and parsing GitSense Chat Tool Blocks.
|
|
8685
|
+
* Block-UUID: 8e1f7b4e-7e30-48b4-a7fc-643bf647661f
|
|
8686
|
+
* Parent-UUID: 72db6a5f-3b09-49e8-8f39-d4e3d37b510a
|
|
8687
|
+
* Version: 1.1.0
|
|
8688
|
+
* Description: Provides utility functions for identifying and parsing GitSense Chat Tool Blocks, and now for replacing them within markdown.
|
|
8689
8689
|
* Language: JavaScript
|
|
8690
|
-
* Created-at: 2025-
|
|
8691
|
-
* Authors: Gemini 2.5 Pro (v1.0.0)
|
|
8690
|
+
* Created-at: 2025-09-12T17:23:34.779Z
|
|
8691
|
+
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Flash (v1.1.0)
|
|
8692
8692
|
*/
|
|
8693
8693
|
|
|
8694
8694
|
/**
|
|
@@ -8778,14 +8778,75 @@ function parseToolBlock$1(content) {
|
|
|
8778
8778
|
}
|
|
8779
8779
|
}
|
|
8780
8780
|
|
|
8781
|
+
/**
|
|
8782
|
+
* Formats tool data into a GitSense Chat Tool Block string.
|
|
8783
|
+
*
|
|
8784
|
+
* @param {object} toolData - The tool data object to format.
|
|
8785
|
+
* @returns {string} The formatted GitSense Chat Tool Block string.
|
|
8786
|
+
*/
|
|
8781
8787
|
function formatToolBlock(toolData) {
|
|
8782
8788
|
return `# GitSense Chat Tool\n\n${JSON.stringify(toolData, null, 2)}`;
|
|
8783
8789
|
}
|
|
8784
8790
|
|
|
8791
|
+
/**
|
|
8792
|
+
* Replaces a specific GitSense Chat Tool Block within a markdown string with updated tool data.
|
|
8793
|
+
* This function leverages CodeBlockUtils for robust parsing and updating.
|
|
8794
|
+
*
|
|
8795
|
+
* @param {string} markdownContent - The original markdown string containing code blocks.
|
|
8796
|
+
* @param {string} toolName - The 'tool' property value of the target GitSense Chat Tool Block to replace.
|
|
8797
|
+
* @param {Object} newToolData - The new tool data object to insert into the block.
|
|
8798
|
+
* @returns {string} The markdown content with the specified tool block updated.
|
|
8799
|
+
* @throws {Error} If the target tool block is not found or if CodeBlockUtils encounters an error.
|
|
8800
|
+
*/
|
|
8801
|
+
function replaceToolBlock(markdownContent, toolName, newToolData, processCodeBlocks, updateCodeBlockByIndex) {
|
|
8802
|
+
if (typeof markdownContent !== 'string' || !toolName || !newToolData) {
|
|
8803
|
+
throw new Error("Missing required parameters for replaceToolBlock.");
|
|
8804
|
+
}
|
|
8805
|
+
|
|
8806
|
+
// We can't require them as this will create a circular dependency
|
|
8807
|
+
if (!processCodeBlocks || !updateCodeBlockByIndex) {
|
|
8808
|
+
throw new Error("Missing required dependencies processCodeBlocks and/or updateCodeBlockByIndex.");
|
|
8809
|
+
}
|
|
8810
|
+
|
|
8811
|
+
// 1. Process the markdown content to find all code blocks
|
|
8812
|
+
const { blocks, warnings } = processCodeBlocks(markdownContent, { silent: true });
|
|
8813
|
+
|
|
8814
|
+
let targetBlockIndex = -1;
|
|
8815
|
+
|
|
8816
|
+
// 2. Iterate through the processed blocks to find the target GitSense Chat Tool Block
|
|
8817
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
8818
|
+
const block = blocks[i];
|
|
8819
|
+
if (block.type === 'gs-tool' && block.toolData && block.toolData.tool === toolName) {
|
|
8820
|
+
targetBlockIndex = i;
|
|
8821
|
+
break; // Found the first matching tool block
|
|
8822
|
+
}
|
|
8823
|
+
}
|
|
8824
|
+
|
|
8825
|
+
if (targetBlockIndex === -1) {
|
|
8826
|
+
console.warn(`replaceToolBlock: No GitSense Chat Tool Block with name "${toolName}" found to replace.`);
|
|
8827
|
+
return markdownContent; // Return original content if no replacement occurred
|
|
8828
|
+
}
|
|
8829
|
+
|
|
8830
|
+
// 3. Format the new tool data into the content that goes *inside* the fences
|
|
8831
|
+
const newContentBetweenFences = formatToolBlock(newToolData);
|
|
8832
|
+
|
|
8833
|
+
// 4. Use CodeBlockUtils.updateCodeBlockByIndex to perform the replacement
|
|
8834
|
+
// The language for GitSense Tool Blocks is always 'txt'
|
|
8835
|
+
const updatedMarkdown = updateCodeBlockByIndex(
|
|
8836
|
+
markdownContent,
|
|
8837
|
+
targetBlockIndex,
|
|
8838
|
+
newContentBetweenFences,
|
|
8839
|
+
'txt'
|
|
8840
|
+
);
|
|
8841
|
+
|
|
8842
|
+
return updatedMarkdown;
|
|
8843
|
+
}
|
|
8844
|
+
|
|
8785
8845
|
var GSToolBlockUtils$3 = {
|
|
8786
8846
|
isToolBlock: isToolBlock$1,
|
|
8787
8847
|
parseToolBlock: parseToolBlock$1,
|
|
8788
|
-
formatToolBlock
|
|
8848
|
+
formatToolBlock,
|
|
8849
|
+
replaceToolBlock,
|
|
8789
8850
|
};
|
|
8790
8851
|
|
|
8791
8852
|
/*
|
|
@@ -11070,11 +11131,11 @@ var dataValidator = {
|
|
|
11070
11131
|
};
|
|
11071
11132
|
|
|
11072
11133
|
/*
|
|
11073
|
-
* Component: AnalyzerUtils
|
|
11074
|
-
* Block-UUID:
|
|
11134
|
+
* Component: AnalyzerUtils Instruction Loader
|
|
11135
|
+
* Block-UUID: 0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5e
|
|
11075
11136
|
* Parent-UUID: N/A
|
|
11076
11137
|
* Version: 1.0.0
|
|
11077
|
-
* Description: Provides utility functions for
|
|
11138
|
+
* Description: Provides utility functions for loading raw analyzer instruction content.
|
|
11078
11139
|
* Language: JavaScript
|
|
11079
11140
|
* Created-at: 2025-08-28T23:48:00.000Z
|
|
11080
11141
|
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
@@ -11083,6 +11144,67 @@ var dataValidator = {
|
|
|
11083
11144
|
const fs$7 = require$$0.promises;
|
|
11084
11145
|
const path$5 = require$$1;
|
|
11085
11146
|
|
|
11147
|
+
/**
|
|
11148
|
+
* Retrieves the raw Markdown content of the analyzer's '1.md' instruction file.
|
|
11149
|
+
*
|
|
11150
|
+
* @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
|
|
11151
|
+
* @param {string} analyzerId - The unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
|
|
11152
|
+
* @returns {Promise<string|null>} A promise that resolves with the full Markdown content of the '1.md' file, or null if not found/invalid.
|
|
11153
|
+
*/
|
|
11154
|
+
async function getAnalyzerInstructionsContent$3(analyzeMessagesBasePath, analyzerId) {
|
|
11155
|
+
if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
|
|
11156
|
+
console.error('Error: analyzeMessagesBasePath is required.');
|
|
11157
|
+
return null;
|
|
11158
|
+
}
|
|
11159
|
+
if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
|
|
11160
|
+
console.error('Error: analyzerId is required.');
|
|
11161
|
+
return null;
|
|
11162
|
+
}
|
|
11163
|
+
|
|
11164
|
+
const parts = analyzerId.split('::');
|
|
11165
|
+
if (parts.length !== 3) {
|
|
11166
|
+
console.error(`Error: Invalid analyzerId format. Expected 'analyzer_name::content_type::instructions_type', but got '${analyzerId}'.`);
|
|
11167
|
+
return null;
|
|
11168
|
+
}
|
|
11169
|
+
const [analyzerName, contentType, instructionsType] = parts;
|
|
11170
|
+
|
|
11171
|
+
const instructionsFilePath = path$5.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
|
|
11172
|
+
|
|
11173
|
+
try {
|
|
11174
|
+
const fileContent = await fs$7.readFile(instructionsFilePath, 'utf8');
|
|
11175
|
+
const parts = fileContent.split('\n\n\n');
|
|
11176
|
+
parts.shift();
|
|
11177
|
+
return parts.join('\n\n\n');
|
|
11178
|
+
} catch (error) {
|
|
11179
|
+
if (error.code === 'ENOENT') {
|
|
11180
|
+
console.warn(`Analyzer instructions file not found: ${instructionsFilePath}`);
|
|
11181
|
+
return null;
|
|
11182
|
+
} else {
|
|
11183
|
+
console.error(`Error reading analyzer instructions file ${instructionsFilePath}: ${error.message}`);
|
|
11184
|
+
throw error;
|
|
11185
|
+
}
|
|
11186
|
+
}
|
|
11187
|
+
}
|
|
11188
|
+
|
|
11189
|
+
var instructionLoader = {
|
|
11190
|
+
getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$3
|
|
11191
|
+
};
|
|
11192
|
+
|
|
11193
|
+
/*
|
|
11194
|
+
* Component: AnalyzerUtils Discovery
|
|
11195
|
+
* Block-UUID: a87a86c4-69fc-4cbb-80a8-857f56122395
|
|
11196
|
+
* Parent-UUID: 0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5f
|
|
11197
|
+
* Version: 1.1.0
|
|
11198
|
+
* Description: Provides utility functions for discovering available analyzers.
|
|
11199
|
+
* Language: JavaScript
|
|
11200
|
+
* Created-at: 2025-08-28T23:48:00.000Z
|
|
11201
|
+
* Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0)
|
|
11202
|
+
*/
|
|
11203
|
+
|
|
11204
|
+
const fs$6 = require$$0.promises;
|
|
11205
|
+
const path$4 = require$$1;
|
|
11206
|
+
const { getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$2 } = instructionLoader;
|
|
11207
|
+
|
|
11086
11208
|
/**
|
|
11087
11209
|
* Reads and parses the config.json file in a directory.
|
|
11088
11210
|
* @param {string} dirPath - The path to the directory.
|
|
@@ -11090,9 +11212,9 @@ const path$5 = require$$1;
|
|
|
11090
11212
|
* or null if the file doesn't exist or is invalid.
|
|
11091
11213
|
*/
|
|
11092
11214
|
async function readConfig$1(dirPath) {
|
|
11093
|
-
const configPath = path$
|
|
11215
|
+
const configPath = path$4.join(dirPath, 'config.json');
|
|
11094
11216
|
try {
|
|
11095
|
-
const fileContent = await fs$
|
|
11217
|
+
const fileContent = await fs$6.readFile(configPath, 'utf8');
|
|
11096
11218
|
return JSON.parse(fileContent);
|
|
11097
11219
|
} catch (error) {
|
|
11098
11220
|
if (error.code !== 'ENOENT') {
|
|
@@ -11123,47 +11245,50 @@ function isValidDirName(name) {
|
|
|
11123
11245
|
* An analyzer is considered valid if a '1.md' file exists in the instructions directory.
|
|
11124
11246
|
*
|
|
11125
11247
|
* @param {string} analyzeMessagesBasePath - The absolute or relative path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
|
|
11126
|
-
* @
|
|
11248
|
+
* @param {object} [options={}] - Optional configuration.
|
|
11249
|
+
* @param {boolean} [options.includeDescription=false] - Whether to include the description of the analyzer.
|
|
11250
|
+
* @returns {Promise<Array<{id: string, label: string, name: string, protected: boolean, description?: string}>>} A promise that resolves to an array of analyzer objects.
|
|
11127
11251
|
*/
|
|
11128
|
-
async function getAnalyzers$2(analyzeMessagesBasePath) {
|
|
11252
|
+
async function getAnalyzers$2(analyzeMessagesBasePath, options = {}) {
|
|
11253
|
+
const { includeDescription = false } = options;
|
|
11129
11254
|
const analyzers = [];
|
|
11130
11255
|
|
|
11131
11256
|
try {
|
|
11132
|
-
const analyzerEntries = await fs$
|
|
11257
|
+
const analyzerEntries = await fs$6.readdir(analyzeMessagesBasePath, { withFileTypes: true });
|
|
11133
11258
|
|
|
11134
11259
|
for (const analyzerEntry of analyzerEntries) {
|
|
11135
11260
|
if (analyzerEntry.isDirectory() && isValidDirName(analyzerEntry.name)) {
|
|
11136
11261
|
const analyzerName = analyzerEntry.name;
|
|
11137
|
-
const analyzerPath = path$
|
|
11262
|
+
const analyzerPath = path$4.join(analyzeMessagesBasePath, analyzerName);
|
|
11138
11263
|
const analyzerConfig = await readConfig$1(analyzerPath);
|
|
11139
11264
|
const analyzerLabel = analyzerConfig?.label || analyzerName;
|
|
11140
11265
|
|
|
11141
|
-
const contentEntries = await fs$
|
|
11266
|
+
const contentEntries = await fs$6.readdir(analyzerPath, { withFileTypes: true });
|
|
11142
11267
|
|
|
11143
11268
|
for (const contentEntry of contentEntries) {
|
|
11144
11269
|
if (contentEntry.isDirectory() && isValidDirName(contentEntry.name)) {
|
|
11145
11270
|
const contentType = contentEntry.name;
|
|
11146
|
-
const contentPath = path$
|
|
11271
|
+
const contentPath = path$4.join(analyzerPath, contentType);
|
|
11147
11272
|
const contentConfig = await readConfig$1(contentPath);
|
|
11148
11273
|
const contentLabel = contentConfig?.label || contentType;
|
|
11149
11274
|
|
|
11150
|
-
const instructionsEntries = await fs$
|
|
11275
|
+
const instructionsEntries = await fs$6.readdir(contentPath, { withFileTypes: true });
|
|
11151
11276
|
|
|
11152
11277
|
for (const instructionsEntry of instructionsEntries) {
|
|
11153
11278
|
if (instructionsEntry.isDirectory() && isValidDirName(instructionsEntry.name)) {
|
|
11154
11279
|
const instructionsType = instructionsEntry.name;
|
|
11155
|
-
const instructionsPath = path$
|
|
11280
|
+
const instructionsPath = path$4.join(contentPath, instructionsType);
|
|
11156
11281
|
const instructionsConfig = await readConfig$1(instructionsPath);
|
|
11157
11282
|
const instructionsLabel = instructionsConfig?.label || instructionsType;
|
|
11158
11283
|
|
|
11159
11284
|
// Check for the existence of 1.md to confirm a valid analyzer configuration
|
|
11160
|
-
const instructionsFilePath = path$
|
|
11285
|
+
const instructionsFilePath = path$4.join(instructionsPath, '1.md');
|
|
11161
11286
|
try {
|
|
11162
|
-
await fs$
|
|
11287
|
+
await fs$6.access(instructionsFilePath); // Check if file exists and is accessible
|
|
11163
11288
|
|
|
11164
11289
|
// If analyzerName starts with 'tutorial-', check its last modified time.
|
|
11165
11290
|
if (analyzerName.startsWith('tutorial-')) {
|
|
11166
|
-
const stats = await fs$
|
|
11291
|
+
const stats = await fs$6.stat(instructionsFilePath);
|
|
11167
11292
|
const lastModified = stats.mtime.getTime(); // Get timestamp in milliseconds
|
|
11168
11293
|
const sixtyMinutesAgo = Date.now() - (60 * 60 * 1000); // Current time - 60 minutes in ms
|
|
11169
11294
|
|
|
@@ -11176,11 +11301,23 @@ async function getAnalyzers$2(analyzeMessagesBasePath) {
|
|
|
11176
11301
|
const analyzerId = `${analyzerName}::${contentType}::${instructionsType}`;
|
|
11177
11302
|
const analyzerFullLabel = `${analyzerLabel} (${contentLabel} - ${instructionsLabel})`;
|
|
11178
11303
|
|
|
11304
|
+
let descriptionContent = null;
|
|
11305
|
+
if (includeDescription) {
|
|
11306
|
+
try {
|
|
11307
|
+
descriptionContent = await getAnalyzerInstructionsContent$2(analyzeMessagesBasePath, analyzerId);
|
|
11308
|
+
} catch (descError) {
|
|
11309
|
+
console.warn(`Warning: Could not load description for ${analyzerId}: ${descError.message}`);
|
|
11310
|
+
descriptionContent = null;
|
|
11311
|
+
}
|
|
11312
|
+
}
|
|
11313
|
+
|
|
11179
11314
|
analyzers.push({
|
|
11180
11315
|
id: analyzerId,
|
|
11181
11316
|
label: analyzerFullLabel,
|
|
11182
|
-
|
|
11183
|
-
|
|
11317
|
+
name: analyzerName,
|
|
11318
|
+
protected: analyzerConfig?.protected || false,
|
|
11319
|
+
...(descriptionContent && { description: descriptionContent })
|
|
11320
|
+
});
|
|
11184
11321
|
} catch (error) {
|
|
11185
11322
|
// If 1.md doesn't exist, this is not a complete analyzer configuration, skip.
|
|
11186
11323
|
if (error.code !== 'ENOENT') {
|
|
@@ -11217,8 +11354,8 @@ var discovery = {
|
|
|
11217
11354
|
* Authors: Gemini 2.5 Flash Thinking (v1.0.0), Gemini 2.5 Flash Thinking (v1.1.0)
|
|
11218
11355
|
*/
|
|
11219
11356
|
|
|
11220
|
-
const fs$
|
|
11221
|
-
const path$
|
|
11357
|
+
const fs$5 = require$$0.promises;
|
|
11358
|
+
const path$3 = require$$1;
|
|
11222
11359
|
|
|
11223
11360
|
/**
|
|
11224
11361
|
* Saves or updates an analyzer configuration.
|
|
@@ -11273,18 +11410,18 @@ async function saveConfiguration$1(analyzeMessagesBasePath, analyzerId, instruct
|
|
|
11273
11410
|
}
|
|
11274
11411
|
|
|
11275
11412
|
// 3. Construct directory paths
|
|
11276
|
-
const analyzerDir = path$
|
|
11277
|
-
const contentDir = path$
|
|
11278
|
-
const instructionsDir = path$
|
|
11279
|
-
const instructionsFilePath = path$
|
|
11413
|
+
const analyzerDir = path$3.join(analyzeMessagesBasePath, analyzerName);
|
|
11414
|
+
const contentDir = path$3.join(analyzerDir, contentType);
|
|
11415
|
+
const instructionsDir = path$3.join(contentDir, instructionsType);
|
|
11416
|
+
const instructionsFilePath = path$3.join(instructionsDir, '1.md');
|
|
11280
11417
|
|
|
11281
11418
|
try {
|
|
11282
11419
|
// 4. Create directories recursively
|
|
11283
|
-
await fs$
|
|
11420
|
+
await fs$5.mkdir(instructionsDir, { recursive: true });
|
|
11284
11421
|
|
|
11285
11422
|
// 5. Save instructions content to 1.md
|
|
11286
11423
|
const finalContent = `; role: assistant\n\n\n${instructionsContent}`;
|
|
11287
|
-
await fs$
|
|
11424
|
+
await fs$5.writeFile(instructionsFilePath, finalContent, 'utf8');
|
|
11288
11425
|
|
|
11289
11426
|
// 6. Optionally create/Update config.json files
|
|
11290
11427
|
if (ensureConfigs) {
|
|
@@ -11310,11 +11447,11 @@ async function saveConfiguration$1(analyzeMessagesBasePath, analyzerId, instruct
|
|
|
11310
11447
|
* @param {string} label - The label to ensure is in the config.json.
|
|
11311
11448
|
*/
|
|
11312
11449
|
async function ensureConfigJson(dirPath, label) {
|
|
11313
|
-
const configPath = path$
|
|
11450
|
+
const configPath = path$3.join(dirPath, 'config.json');
|
|
11314
11451
|
let config = {};
|
|
11315
11452
|
|
|
11316
11453
|
try {
|
|
11317
|
-
const fileContent = await fs$
|
|
11454
|
+
const fileContent = await fs$5.readFile(configPath, 'utf8');
|
|
11318
11455
|
config = JSON.parse(fileContent);
|
|
11319
11456
|
} catch (error) {
|
|
11320
11457
|
// If file doesn't exist or parsing fails, start with an empty config
|
|
@@ -11331,7 +11468,7 @@ async function ensureConfigJson(dirPath, label) {
|
|
|
11331
11468
|
}
|
|
11332
11469
|
|
|
11333
11470
|
// Write the updated config back to the file
|
|
11334
|
-
await fs$
|
|
11471
|
+
await fs$5.writeFile(configPath, JSON.stringify(config, null, 4), 'utf8');
|
|
11335
11472
|
}
|
|
11336
11473
|
|
|
11337
11474
|
|
|
@@ -11350,8 +11487,8 @@ var saver = {
|
|
|
11350
11487
|
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
11351
11488
|
*/
|
|
11352
11489
|
|
|
11353
|
-
const fs$
|
|
11354
|
-
const path$
|
|
11490
|
+
const fs$4 = require$$0.promises;
|
|
11491
|
+
const path$2 = require$$1;
|
|
11355
11492
|
const CodeBlockUtils$1 = CodeBlockUtils$4;
|
|
11356
11493
|
|
|
11357
11494
|
/**
|
|
@@ -11437,10 +11574,10 @@ async function getAnalyzerSchema$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11437
11574
|
}
|
|
11438
11575
|
const [analyzerName, contentType, instructionsType] = parts;
|
|
11439
11576
|
|
|
11440
|
-
const instructionsFilePath = path$
|
|
11577
|
+
const instructionsFilePath = path$2.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
|
|
11441
11578
|
|
|
11442
11579
|
try {
|
|
11443
|
-
const fileContent = await fs$
|
|
11580
|
+
const fileContent = await fs$4.readFile(instructionsFilePath, 'utf8');
|
|
11444
11581
|
const { blocks } = CodeBlockUtils$1.extractCodeBlocks(fileContent, { silent: true });
|
|
11445
11582
|
const jsonBlocks = blocks.filter(block => block.type === 'code' && block.language === 'json');
|
|
11446
11583
|
|
|
@@ -11511,8 +11648,8 @@ var schemaLoader = {
|
|
|
11511
11648
|
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
11512
11649
|
*/
|
|
11513
11650
|
|
|
11514
|
-
const fs$
|
|
11515
|
-
const path$
|
|
11651
|
+
const fs$3 = require$$0.promises;
|
|
11652
|
+
const path$1 = require$$1;
|
|
11516
11653
|
const { readConfig } = discovery; // Import helper from discovery
|
|
11517
11654
|
|
|
11518
11655
|
/**
|
|
@@ -11522,7 +11659,7 @@ const { readConfig } = discovery; // Import helper from discovery
|
|
|
11522
11659
|
*/
|
|
11523
11660
|
async function isDirectoryEmpty(dirPath) {
|
|
11524
11661
|
try {
|
|
11525
|
-
const files = await fs$
|
|
11662
|
+
const files = await fs$3.readdir(dirPath);
|
|
11526
11663
|
return files.length === 0 || (files.length === 1 && files[0] === 'config.json');
|
|
11527
11664
|
} catch (error) {
|
|
11528
11665
|
if (error.code === 'ENOENT') {
|
|
@@ -11553,10 +11690,10 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11553
11690
|
}
|
|
11554
11691
|
const [analyzerName, contentType, instructionsType] = parts;
|
|
11555
11692
|
|
|
11556
|
-
const analyzerDir = path$
|
|
11557
|
-
const contentDir = path$
|
|
11558
|
-
const instructionsDir = path$
|
|
11559
|
-
const instructionsFilePath = path$
|
|
11693
|
+
const analyzerDir = path$1.join(analyzeMessagesBasePath, analyzerName);
|
|
11694
|
+
const contentDir = path$1.join(analyzerDir, contentType);
|
|
11695
|
+
const instructionsDir = path$1.join(contentDir, instructionsType);
|
|
11696
|
+
const instructionsFilePath = path$1.join(instructionsDir, '1.md');
|
|
11560
11697
|
|
|
11561
11698
|
try {
|
|
11562
11699
|
// 1. Check for protection at all levels
|
|
@@ -11577,7 +11714,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11577
11714
|
|
|
11578
11715
|
// 2. Delete the 1.md file
|
|
11579
11716
|
try {
|
|
11580
|
-
await fs$
|
|
11717
|
+
await fs$3.unlink(instructionsFilePath);
|
|
11581
11718
|
} catch (error) {
|
|
11582
11719
|
if (error.code === 'ENOENT') {
|
|
11583
11720
|
return { success: false, message: `Analyzer instructions file not found: ${instructionsFilePath}. It may have already been deleted.` };
|
|
@@ -11591,7 +11728,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11591
11728
|
// Check and delete instructions directory
|
|
11592
11729
|
if (await isDirectoryEmpty(instructionsDir)) {
|
|
11593
11730
|
try {
|
|
11594
|
-
await fs$
|
|
11731
|
+
await fs$3.rmdir(instructionsDir);
|
|
11595
11732
|
deletedDirs.push(instructionsDir);
|
|
11596
11733
|
} catch (error) {
|
|
11597
11734
|
console.warn(`Warning: Could not remove empty instructions directory ${instructionsDir}: ${error.message}`);
|
|
@@ -11601,7 +11738,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11601
11738
|
// Check and delete content directory
|
|
11602
11739
|
if (await isDirectoryEmpty(contentDir)) {
|
|
11603
11740
|
try {
|
|
11604
|
-
await fs$
|
|
11741
|
+
await fs$3.rmdir(contentDir);
|
|
11605
11742
|
deletedDirs.push(contentDir);
|
|
11606
11743
|
} catch (error) {
|
|
11607
11744
|
console.warn(`Warning: Could not remove empty content directory ${contentDir}: ${error.message}`);
|
|
@@ -11611,7 +11748,7 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11611
11748
|
// Check and delete analyzer directory
|
|
11612
11749
|
if (await isDirectoryEmpty(analyzerDir)) {
|
|
11613
11750
|
try {
|
|
11614
|
-
await fs$
|
|
11751
|
+
await fs$3.rmdir(analyzerDir);
|
|
11615
11752
|
deletedDirs.push(analyzerDir);
|
|
11616
11753
|
} catch (error) {
|
|
11617
11754
|
console.warn(`Warning: Could not remove empty analyzer directory ${analyzerDir}: ${error.message}`);
|
|
@@ -11629,69 +11766,9 @@ async function deleteAnalyzer$2(analyzeMessagesBasePath, analyzerId) {
|
|
|
11629
11766
|
var management = {
|
|
11630
11767
|
deleteAnalyzer: deleteAnalyzer$2};
|
|
11631
11768
|
|
|
11632
|
-
/*
|
|
11633
|
-
* Component: AnalyzerUtils Instruction Loader
|
|
11634
|
-
* Block-UUID: 0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5e
|
|
11635
|
-
* Parent-UUID: N/A
|
|
11636
|
-
* Version: 1.0.0
|
|
11637
|
-
* Description: Provides utility functions for loading raw analyzer instruction content.
|
|
11638
|
-
* Language: JavaScript
|
|
11639
|
-
* Created-at: 2025-08-28T23:48:00.000Z
|
|
11640
|
-
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
11641
|
-
*/
|
|
11642
|
-
|
|
11643
|
-
const fs$3 = require$$0.promises;
|
|
11644
|
-
const path$1 = require$$1;
|
|
11645
|
-
|
|
11646
|
-
/**
|
|
11647
|
-
* Retrieves the raw Markdown content of the analyzer's '1.md' instruction file.
|
|
11648
|
-
*
|
|
11649
|
-
* @param {string} analyzeMessagesBasePath - The absolute path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
|
|
11650
|
-
* @param {string} analyzerId - The unique ID of the analyzer (format: 'analyzer_name::content_type::instructions_type').
|
|
11651
|
-
* @returns {Promise<string|null>} A promise that resolves with the full Markdown content of the '1.md' file, or null if not found/invalid.
|
|
11652
|
-
*/
|
|
11653
|
-
async function getAnalyzerInstructionsContent$2(analyzeMessagesBasePath, analyzerId) {
|
|
11654
|
-
if (typeof analyzeMessagesBasePath !== 'string' || analyzeMessagesBasePath.trim() === '') {
|
|
11655
|
-
console.error('Error: analyzeMessagesBasePath is required.');
|
|
11656
|
-
return null;
|
|
11657
|
-
}
|
|
11658
|
-
if (typeof analyzerId !== 'string' || analyzerId.trim() === '') {
|
|
11659
|
-
console.error('Error: analyzerId is required.');
|
|
11660
|
-
return null;
|
|
11661
|
-
}
|
|
11662
|
-
|
|
11663
|
-
const parts = analyzerId.split('::');
|
|
11664
|
-
if (parts.length !== 3) {
|
|
11665
|
-
console.error(`Error: Invalid analyzerId format. Expected 'analyzer_name::content_type::instructions_type', but got '${analyzerId}'.`);
|
|
11666
|
-
return null;
|
|
11667
|
-
}
|
|
11668
|
-
const [analyzerName, contentType, instructionsType] = parts;
|
|
11669
|
-
|
|
11670
|
-
const instructionsFilePath = path$1.join(analyzeMessagesBasePath, analyzerName, contentType, instructionsType, '1.md');
|
|
11671
|
-
|
|
11672
|
-
try {
|
|
11673
|
-
const fileContent = await fs$3.readFile(instructionsFilePath, 'utf8');
|
|
11674
|
-
const parts = fileContent.split('\n\n\n');
|
|
11675
|
-
parts.shift();
|
|
11676
|
-
return parts.join('\n\n\n');
|
|
11677
|
-
} catch (error) {
|
|
11678
|
-
if (error.code === 'ENOENT') {
|
|
11679
|
-
console.warn(`Analyzer instructions file not found: ${instructionsFilePath}`);
|
|
11680
|
-
return null;
|
|
11681
|
-
} else {
|
|
11682
|
-
console.error(`Error reading analyzer instructions file ${instructionsFilePath}: ${error.message}`);
|
|
11683
|
-
throw error;
|
|
11684
|
-
}
|
|
11685
|
-
}
|
|
11686
|
-
}
|
|
11687
|
-
|
|
11688
|
-
var instructionLoader = {
|
|
11689
|
-
getAnalyzerInstructionsContent: getAnalyzerInstructionsContent$2
|
|
11690
|
-
};
|
|
11691
|
-
|
|
11692
11769
|
/*
|
|
11693
11770
|
* Component: AnalyzerUtils Default Prompt Loader
|
|
11694
|
-
* Block-UUID:
|
|
11771
|
+
* Block-UUID: be863744-6461-4b94-97ce-b1d177e9e881
|
|
11695
11772
|
* Parent-UUID: N/A
|
|
11696
11773
|
* Version: 1.0.0
|
|
11697
11774
|
* Description: Provides utility functions for loading shared, default prompt components (system and start messages).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Component: AnalyzerUtils Default Prompt Loader
|
|
3
|
-
* Block-UUID:
|
|
3
|
+
* Block-UUID: be863744-6461-4b94-97ce-b1d177e9e881
|
|
4
4
|
* Parent-UUID: N/A
|
|
5
5
|
* Version: 1.0.0
|
|
6
6
|
* Description: Provides utility functions for loading shared, default prompt components (system and start messages).
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Component: AnalyzerUtils Discovery
|
|
3
|
-
* Block-UUID:
|
|
4
|
-
* Parent-UUID:
|
|
5
|
-
* Version: 1.
|
|
3
|
+
* Block-UUID: a87a86c4-69fc-4cbb-80a8-857f56122395
|
|
4
|
+
* Parent-UUID: 0b1c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5f
|
|
5
|
+
* Version: 1.1.0
|
|
6
6
|
* Description: Provides utility functions for discovering available analyzers.
|
|
7
7
|
* Language: JavaScript
|
|
8
8
|
* Created-at: 2025-08-28T23:48:00.000Z
|
|
9
|
-
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
9
|
+
* Authors: Gemini 2.5 Flash (v1.0.0), Gemini 2.5 Flash (v1.1.0)
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
const fs = require('fs').promises;
|
|
14
14
|
const path = require('path');
|
|
15
|
+
const { getAnalyzerInstructionsContent } = require('./instructionLoader');
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Reads and parses the config.json file in a directory.
|
|
@@ -53,9 +54,12 @@ function isValidDirName(name) {
|
|
|
53
54
|
* An analyzer is considered valid if a '1.md' file exists in the instructions directory.
|
|
54
55
|
*
|
|
55
56
|
* @param {string} analyzeMessagesBasePath - The absolute or relative path to the base directory containing the analyzer message files (e.g., 'messages/analyze').
|
|
56
|
-
* @
|
|
57
|
+
* @param {object} [options={}] - Optional configuration.
|
|
58
|
+
* @param {boolean} [options.includeDescription=false] - Whether to include the description of the analyzer.
|
|
59
|
+
* @returns {Promise<Array<{id: string, label: string, name: string, protected: boolean, description?: string}>>} A promise that resolves to an array of analyzer objects.
|
|
57
60
|
*/
|
|
58
|
-
async function getAnalyzers(analyzeMessagesBasePath) {
|
|
61
|
+
async function getAnalyzers(analyzeMessagesBasePath, options = {}) {
|
|
62
|
+
const { includeDescription = false } = options;
|
|
59
63
|
const analyzers = [];
|
|
60
64
|
|
|
61
65
|
try {
|
|
@@ -106,11 +110,23 @@ async function getAnalyzers(analyzeMessagesBasePath) {
|
|
|
106
110
|
const analyzerId = `${analyzerName}::${contentType}::${instructionsType}`;
|
|
107
111
|
const analyzerFullLabel = `${analyzerLabel} (${contentLabel} - ${instructionsLabel})`;
|
|
108
112
|
|
|
113
|
+
let descriptionContent = null;
|
|
114
|
+
if (includeDescription) {
|
|
115
|
+
try {
|
|
116
|
+
descriptionContent = await getAnalyzerInstructionsContent(analyzeMessagesBasePath, analyzerId);
|
|
117
|
+
} catch (descError) {
|
|
118
|
+
console.warn(`Warning: Could not load description for ${analyzerId}: ${descError.message}`);
|
|
119
|
+
descriptionContent = null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
109
123
|
analyzers.push({
|
|
110
124
|
id: analyzerId,
|
|
111
125
|
label: analyzerFullLabel,
|
|
112
|
-
|
|
113
|
-
|
|
126
|
+
name: analyzerName,
|
|
127
|
+
protected: analyzerConfig?.protected || false,
|
|
128
|
+
...(descriptionContent && { description: descriptionContent })
|
|
129
|
+
});
|
|
114
130
|
} catch (error) {
|
|
115
131
|
// If 1.md doesn't exist, this is not a complete analyzer configuration, skip.
|
|
116
132
|
if (error.code !== 'ENOENT') {
|
package/src/GSToolBlockUtils.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Component: GitSense Tool Block Utilities
|
|
3
|
-
* Block-UUID:
|
|
4
|
-
* Parent-UUID:
|
|
5
|
-
* Version: 1.
|
|
6
|
-
* Description: Provides utility functions for identifying and parsing GitSense Chat Tool Blocks.
|
|
3
|
+
* Block-UUID: 8e1f7b4e-7e30-48b4-a7fc-643bf647661f
|
|
4
|
+
* Parent-UUID: 72db6a5f-3b09-49e8-8f39-d4e3d37b510a
|
|
5
|
+
* Version: 1.1.0
|
|
6
|
+
* Description: Provides utility functions for identifying and parsing GitSense Chat Tool Blocks, and now for replacing them within markdown.
|
|
7
7
|
* Language: JavaScript
|
|
8
|
-
* Created-at: 2025-
|
|
9
|
-
* Authors: Gemini 2.5 Pro (v1.0.0)
|
|
8
|
+
* Created-at: 2025-09-12T17:23:34.779Z
|
|
9
|
+
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Flash (v1.1.0)
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
|
|
@@ -97,12 +97,73 @@ function parseToolBlock(content) {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Formats tool data into a GitSense Chat Tool Block string.
|
|
102
|
+
*
|
|
103
|
+
* @param {object} toolData - The tool data object to format.
|
|
104
|
+
* @returns {string} The formatted GitSense Chat Tool Block string.
|
|
105
|
+
*/
|
|
100
106
|
function formatToolBlock(toolData) {
|
|
101
107
|
return `# GitSense Chat Tool\n\n${JSON.stringify(toolData, null, 2)}`;
|
|
102
108
|
}
|
|
103
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Replaces a specific GitSense Chat Tool Block within a markdown string with updated tool data.
|
|
112
|
+
* This function leverages CodeBlockUtils for robust parsing and updating.
|
|
113
|
+
*
|
|
114
|
+
* @param {string} markdownContent - The original markdown string containing code blocks.
|
|
115
|
+
* @param {string} toolName - The 'tool' property value of the target GitSense Chat Tool Block to replace.
|
|
116
|
+
* @param {Object} newToolData - The new tool data object to insert into the block.
|
|
117
|
+
* @returns {string} The markdown content with the specified tool block updated.
|
|
118
|
+
* @throws {Error} If the target tool block is not found or if CodeBlockUtils encounters an error.
|
|
119
|
+
*/
|
|
120
|
+
function replaceToolBlock(markdownContent, toolName, newToolData, processCodeBlocks, updateCodeBlockByIndex) {
|
|
121
|
+
if (typeof markdownContent !== 'string' || !toolName || !newToolData) {
|
|
122
|
+
throw new Error("Missing required parameters for replaceToolBlock.");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// We can't require them as this will create a circular dependency
|
|
126
|
+
if (!processCodeBlocks || !updateCodeBlockByIndex) {
|
|
127
|
+
throw new Error("Missing required dependencies processCodeBlocks and/or updateCodeBlockByIndex.");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 1. Process the markdown content to find all code blocks
|
|
131
|
+
const { blocks, warnings } = processCodeBlocks(markdownContent, { silent: true });
|
|
132
|
+
|
|
133
|
+
let targetBlockIndex = -1;
|
|
134
|
+
|
|
135
|
+
// 2. Iterate through the processed blocks to find the target GitSense Chat Tool Block
|
|
136
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
137
|
+
const block = blocks[i];
|
|
138
|
+
if (block.type === 'gs-tool' && block.toolData && block.toolData.tool === toolName) {
|
|
139
|
+
targetBlockIndex = i;
|
|
140
|
+
break; // Found the first matching tool block
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (targetBlockIndex === -1) {
|
|
145
|
+
console.warn(`replaceToolBlock: No GitSense Chat Tool Block with name "${toolName}" found to replace.`);
|
|
146
|
+
return markdownContent; // Return original content if no replacement occurred
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 3. Format the new tool data into the content that goes *inside* the fences
|
|
150
|
+
const newContentBetweenFences = formatToolBlock(newToolData);
|
|
151
|
+
|
|
152
|
+
// 4. Use CodeBlockUtils.updateCodeBlockByIndex to perform the replacement
|
|
153
|
+
// The language for GitSense Tool Blocks is always 'txt'
|
|
154
|
+
const updatedMarkdown = updateCodeBlockByIndex(
|
|
155
|
+
markdownContent,
|
|
156
|
+
targetBlockIndex,
|
|
157
|
+
newContentBetweenFences,
|
|
158
|
+
'txt'
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
return updatedMarkdown;
|
|
162
|
+
}
|
|
163
|
+
|
|
104
164
|
module.exports = {
|
|
105
165
|
isToolBlock,
|
|
106
166
|
parseToolBlock,
|
|
107
|
-
formatToolBlock
|
|
167
|
+
formatToolBlock,
|
|
168
|
+
replaceToolBlock,
|
|
108
169
|
}
|