@lousy-agents/cli 2.9.0 → 2.10.0
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/index.js +45 -12
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +202 -12
- package/dist/mcp-server.js.map +1 -1
- package/package.json +4 -4
package/dist/mcp-server.js
CHANGED
|
@@ -40951,6 +40951,7 @@ class AjvJsonSchemaValidator {
|
|
|
40951
40951
|
*
|
|
40952
40952
|
* @experimental
|
|
40953
40953
|
*/
|
|
40954
|
+
|
|
40954
40955
|
/**
|
|
40955
40956
|
* Experimental task features for low-level MCP servers.
|
|
40956
40957
|
*
|
|
@@ -40984,6 +40985,162 @@ class ExperimentalServerTasks {
|
|
|
40984
40985
|
requestStream(request, resultSchema, options) {
|
|
40985
40986
|
return this._server.requestStream(request, resultSchema, options);
|
|
40986
40987
|
}
|
|
40988
|
+
/**
|
|
40989
|
+
* Sends a sampling request and returns an AsyncGenerator that yields response messages.
|
|
40990
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
40991
|
+
*
|
|
40992
|
+
* For task-augmented requests, yields 'taskCreated' and 'taskStatus' messages
|
|
40993
|
+
* before the final result.
|
|
40994
|
+
*
|
|
40995
|
+
* @example
|
|
40996
|
+
* ```typescript
|
|
40997
|
+
* const stream = server.experimental.tasks.createMessageStream({
|
|
40998
|
+
* messages: [{ role: 'user', content: { type: 'text', text: 'Hello' } }],
|
|
40999
|
+
* maxTokens: 100
|
|
41000
|
+
* }, {
|
|
41001
|
+
* onprogress: (progress) => {
|
|
41002
|
+
* // Handle streaming tokens via progress notifications
|
|
41003
|
+
* console.log('Progress:', progress.message);
|
|
41004
|
+
* }
|
|
41005
|
+
* });
|
|
41006
|
+
*
|
|
41007
|
+
* for await (const message of stream) {
|
|
41008
|
+
* switch (message.type) {
|
|
41009
|
+
* case 'taskCreated':
|
|
41010
|
+
* console.log('Task created:', message.task.taskId);
|
|
41011
|
+
* break;
|
|
41012
|
+
* case 'taskStatus':
|
|
41013
|
+
* console.log('Task status:', message.task.status);
|
|
41014
|
+
* break;
|
|
41015
|
+
* case 'result':
|
|
41016
|
+
* console.log('Final result:', message.result);
|
|
41017
|
+
* break;
|
|
41018
|
+
* case 'error':
|
|
41019
|
+
* console.error('Error:', message.error);
|
|
41020
|
+
* break;
|
|
41021
|
+
* }
|
|
41022
|
+
* }
|
|
41023
|
+
* ```
|
|
41024
|
+
*
|
|
41025
|
+
* @param params - The sampling request parameters
|
|
41026
|
+
* @param options - Optional request options (timeout, signal, task creation params, onprogress, etc.)
|
|
41027
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
41028
|
+
*
|
|
41029
|
+
* @experimental
|
|
41030
|
+
*/
|
|
41031
|
+
createMessageStream(params, options) {
|
|
41032
|
+
// Access client capabilities via the server
|
|
41033
|
+
const clientCapabilities = this._server.getClientCapabilities();
|
|
41034
|
+
// Capability check - only required when tools/toolChoice are provided
|
|
41035
|
+
if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
|
|
41036
|
+
throw new Error('Client does not support sampling tools capability.');
|
|
41037
|
+
}
|
|
41038
|
+
// Message structure validation - always validate tool_use/tool_result pairs.
|
|
41039
|
+
// These may appear even without tools/toolChoice in the current request when
|
|
41040
|
+
// a previous sampling request returned tool_use and this is a follow-up with results.
|
|
41041
|
+
if (params.messages.length > 0) {
|
|
41042
|
+
const lastMessage = params.messages[params.messages.length - 1];
|
|
41043
|
+
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
|
|
41044
|
+
const hasToolResults = lastContent.some(c => c.type === 'tool_result');
|
|
41045
|
+
const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : undefined;
|
|
41046
|
+
const previousContent = previousMessage
|
|
41047
|
+
? Array.isArray(previousMessage.content)
|
|
41048
|
+
? previousMessage.content
|
|
41049
|
+
: [previousMessage.content]
|
|
41050
|
+
: [];
|
|
41051
|
+
const hasPreviousToolUse = previousContent.some(c => c.type === 'tool_use');
|
|
41052
|
+
if (hasToolResults) {
|
|
41053
|
+
if (lastContent.some(c => c.type !== 'tool_result')) {
|
|
41054
|
+
throw new Error('The last message must contain only tool_result content if any is present');
|
|
41055
|
+
}
|
|
41056
|
+
if (!hasPreviousToolUse) {
|
|
41057
|
+
throw new Error('tool_result blocks are not matching any tool_use from the previous message');
|
|
41058
|
+
}
|
|
41059
|
+
}
|
|
41060
|
+
if (hasPreviousToolUse) {
|
|
41061
|
+
// Extract tool_use IDs from previous message and tool_result IDs from current message
|
|
41062
|
+
const toolUseIds = new Set(previousContent.filter(c => c.type === 'tool_use').map(c => c.id));
|
|
41063
|
+
const toolResultIds = new Set(lastContent.filter(c => c.type === 'tool_result').map(c => c.toolUseId));
|
|
41064
|
+
if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every(id => toolResultIds.has(id))) {
|
|
41065
|
+
throw new Error('ids of tool_result blocks and tool_use blocks from previous message do not match');
|
|
41066
|
+
}
|
|
41067
|
+
}
|
|
41068
|
+
}
|
|
41069
|
+
return this.requestStream({
|
|
41070
|
+
method: 'sampling/createMessage',
|
|
41071
|
+
params
|
|
41072
|
+
}, CreateMessageResultSchema, options);
|
|
41073
|
+
}
|
|
41074
|
+
/**
|
|
41075
|
+
* Sends an elicitation request and returns an AsyncGenerator that yields response messages.
|
|
41076
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
41077
|
+
*
|
|
41078
|
+
* For task-augmented requests (especially URL-based elicitation), yields 'taskCreated'
|
|
41079
|
+
* and 'taskStatus' messages before the final result.
|
|
41080
|
+
*
|
|
41081
|
+
* @example
|
|
41082
|
+
* ```typescript
|
|
41083
|
+
* const stream = server.experimental.tasks.elicitInputStream({
|
|
41084
|
+
* mode: 'url',
|
|
41085
|
+
* message: 'Please authenticate',
|
|
41086
|
+
* elicitationId: 'auth-123',
|
|
41087
|
+
* url: 'https://example.com/auth'
|
|
41088
|
+
* }, {
|
|
41089
|
+
* task: { ttl: 300000 } // Task-augmented for long-running auth flow
|
|
41090
|
+
* });
|
|
41091
|
+
*
|
|
41092
|
+
* for await (const message of stream) {
|
|
41093
|
+
* switch (message.type) {
|
|
41094
|
+
* case 'taskCreated':
|
|
41095
|
+
* console.log('Task created:', message.task.taskId);
|
|
41096
|
+
* break;
|
|
41097
|
+
* case 'taskStatus':
|
|
41098
|
+
* console.log('Task status:', message.task.status);
|
|
41099
|
+
* break;
|
|
41100
|
+
* case 'result':
|
|
41101
|
+
* console.log('User action:', message.result.action);
|
|
41102
|
+
* break;
|
|
41103
|
+
* case 'error':
|
|
41104
|
+
* console.error('Error:', message.error);
|
|
41105
|
+
* break;
|
|
41106
|
+
* }
|
|
41107
|
+
* }
|
|
41108
|
+
* ```
|
|
41109
|
+
*
|
|
41110
|
+
* @param params - The elicitation request parameters
|
|
41111
|
+
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
41112
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
41113
|
+
*
|
|
41114
|
+
* @experimental
|
|
41115
|
+
*/
|
|
41116
|
+
elicitInputStream(params, options) {
|
|
41117
|
+
// Access client capabilities via the server
|
|
41118
|
+
const clientCapabilities = this._server.getClientCapabilities();
|
|
41119
|
+
const mode = params.mode ?? 'form';
|
|
41120
|
+
// Capability check based on mode
|
|
41121
|
+
switch (mode) {
|
|
41122
|
+
case 'url': {
|
|
41123
|
+
if (!clientCapabilities?.elicitation?.url) {
|
|
41124
|
+
throw new Error('Client does not support url elicitation.');
|
|
41125
|
+
}
|
|
41126
|
+
break;
|
|
41127
|
+
}
|
|
41128
|
+
case 'form': {
|
|
41129
|
+
if (!clientCapabilities?.elicitation?.form) {
|
|
41130
|
+
throw new Error('Client does not support form elicitation.');
|
|
41131
|
+
}
|
|
41132
|
+
break;
|
|
41133
|
+
}
|
|
41134
|
+
}
|
|
41135
|
+
// Normalize params to ensure mode is set for form mode (defaults to 'form' per spec)
|
|
41136
|
+
const normalizedParams = mode === 'form' && params.mode === undefined ? { ...params, mode: 'form' } : params;
|
|
41137
|
+
// Cast to ServerRequest needed because TypeScript can't narrow the union type
|
|
41138
|
+
// based on the discriminated 'method' field when constructing the object literal
|
|
41139
|
+
return this.requestStream({
|
|
41140
|
+
method: 'elicitation/create',
|
|
41141
|
+
params: normalizedParams
|
|
41142
|
+
}, ElicitResultSchema, options);
|
|
41143
|
+
}
|
|
40987
41144
|
/**
|
|
40988
41145
|
* Gets the current status of a task.
|
|
40989
41146
|
*
|
|
@@ -45828,6 +45985,17 @@ function defaultExec(command, args, options) {
|
|
|
45828
45985
|
*/ function createScriptDiscoveryGateway() {
|
|
45829
45986
|
return new FileSystemScriptDiscoveryGateway();
|
|
45830
45987
|
}
|
|
45988
|
+
/**
|
|
45989
|
+
* Creates a FeedbackLoopCommandsGateway that discovers mandatory commands from package.json scripts.
|
|
45990
|
+
*/ function createFeedbackLoopCommandsGateway(scriptGateway) {
|
|
45991
|
+
const gateway = scriptGateway ?? createScriptDiscoveryGateway();
|
|
45992
|
+
return {
|
|
45993
|
+
async getMandatoryCommands (targetDir) {
|
|
45994
|
+
const scripts = await gateway.discoverScripts(targetDir);
|
|
45995
|
+
return scripts.filter((s)=>s.isMandatory).map((s)=>s.name);
|
|
45996
|
+
}
|
|
45997
|
+
};
|
|
45998
|
+
}
|
|
45831
45999
|
|
|
45832
46000
|
;// CONCATENATED MODULE: ./src/gateways/skill-file-gateway.ts
|
|
45833
46001
|
/**
|
|
@@ -65618,24 +65786,43 @@ const remark = unified().use(remarkParse).use(remarkStringify).freeze()
|
|
|
65618
65786
|
overallQualityScore: 0,
|
|
65619
65787
|
suggestions: [
|
|
65620
65788
|
"No agent instruction files found. Supported formats: .github/copilot-instructions.md, .github/instructions/*.md, .github/agents/*.md, AGENTS.md, CLAUDE.md"
|
|
65621
|
-
]
|
|
65789
|
+
],
|
|
65790
|
+
parsingErrors: []
|
|
65622
65791
|
},
|
|
65623
65792
|
diagnostics: []
|
|
65624
65793
|
};
|
|
65625
65794
|
}
|
|
65626
65795
|
// Analyze each file
|
|
65627
65796
|
const fileStructures = new Map();
|
|
65797
|
+
const parsingErrors = [];
|
|
65628
65798
|
for (const file of discoveredFiles){
|
|
65629
65799
|
try {
|
|
65630
65800
|
const structure = await this.astGateway.parseFile(file.filePath);
|
|
65631
65801
|
fileStructures.set(file.filePath, structure);
|
|
65632
|
-
} catch
|
|
65633
|
-
|
|
65802
|
+
} catch (error) {
|
|
65803
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown parsing error";
|
|
65804
|
+
parsingErrors.push({
|
|
65805
|
+
filePath: file.filePath,
|
|
65806
|
+
error: errorMessage
|
|
65807
|
+
});
|
|
65634
65808
|
}
|
|
65635
65809
|
}
|
|
65810
|
+
// Sort parsing errors for deterministic output
|
|
65811
|
+
parsingErrors.sort((a, b)=>a.filePath.localeCompare(b.filePath));
|
|
65636
65812
|
// Score each mandatory command across all files
|
|
65637
65813
|
const commandScores = [];
|
|
65638
65814
|
const diagnostics = [];
|
|
65815
|
+
// Emit diagnostics for parsing errors
|
|
65816
|
+
for (const pe of parsingErrors){
|
|
65817
|
+
diagnostics.push({
|
|
65818
|
+
filePath: pe.filePath,
|
|
65819
|
+
line: 1,
|
|
65820
|
+
severity: "warning",
|
|
65821
|
+
message: `Failed to parse file: ${pe.error}`,
|
|
65822
|
+
ruleId: "instruction/parse-error",
|
|
65823
|
+
target: "instruction"
|
|
65824
|
+
});
|
|
65825
|
+
}
|
|
65639
65826
|
for (const command of mandatoryCommands){
|
|
65640
65827
|
const bestAnalysis = this.findBestScore(command, discoveredFiles, fileStructures, headingPatterns, proximityWindow, diagnostics);
|
|
65641
65828
|
if (bestAnalysis) {
|
|
@@ -65663,12 +65850,17 @@ const remark = unified().use(remarkParse).use(remarkStringify).freeze()
|
|
|
65663
65850
|
const overallQualityScore = commandScores.length > 0 ? Math.round(commandScores.reduce((sum, s)=>sum + s.compositeScore, 0) / commandScores.length * 100) : 0;
|
|
65664
65851
|
// Generate suggestions
|
|
65665
65852
|
const suggestions = this.generateSuggestions(commandScores);
|
|
65853
|
+
if (parsingErrors.length > 0) {
|
|
65854
|
+
const skippedFiles = parsingErrors.map((pe)=>pe.filePath).join(", ");
|
|
65855
|
+
suggestions.push(`${parsingErrors.length} file(s) could not be parsed and were skipped: ${skippedFiles}. Analysis may be incomplete.`);
|
|
65856
|
+
}
|
|
65666
65857
|
return {
|
|
65667
65858
|
result: {
|
|
65668
65859
|
discoveredFiles,
|
|
65669
65860
|
commandScores,
|
|
65670
65861
|
overallQualityScore,
|
|
65671
|
-
suggestions
|
|
65862
|
+
suggestions,
|
|
65863
|
+
parsingErrors
|
|
65672
65864
|
},
|
|
65673
65865
|
diagnostics
|
|
65674
65866
|
};
|
|
@@ -65903,22 +66095,19 @@ const remark = unified().use(remarkParse).use(remarkStringify).freeze()
|
|
|
65903
66095
|
|
|
65904
66096
|
|
|
65905
66097
|
|
|
66098
|
+
|
|
65906
66099
|
/**
|
|
65907
66100
|
* Analyzes the structural quality of feedback loop documentation in instruction files.
|
|
65908
66101
|
* Assesses structural context, execution clarity, and loop completeness.
|
|
65909
66102
|
*/ const analyzeInstructionQualityHandler = async (args)=>{
|
|
65910
66103
|
const dir = args.targetDir || process.cwd();
|
|
66104
|
+
if (!await file_system_utils_fileExists(dir)) {
|
|
66105
|
+
return types_errorResponse(`Target directory does not exist: ${dir}`);
|
|
66106
|
+
}
|
|
65911
66107
|
try {
|
|
65912
66108
|
const discoveryGateway = createInstructionFileDiscoveryGateway();
|
|
65913
66109
|
const astGateway = createMarkdownAstGateway();
|
|
65914
|
-
|
|
65915
|
-
const scriptGateway = createScriptDiscoveryGateway();
|
|
65916
|
-
const commandsGateway = {
|
|
65917
|
-
async getMandatoryCommands (targetDir) {
|
|
65918
|
-
const scripts = await scriptGateway.discoverScripts(targetDir);
|
|
65919
|
-
return scripts.filter((s)=>s.isMandatory).map((s)=>s.name);
|
|
65920
|
-
}
|
|
65921
|
-
};
|
|
66110
|
+
const commandsGateway = createFeedbackLoopCommandsGateway();
|
|
65922
66111
|
const useCase = new AnalyzeInstructionQualityUseCase(discoveryGateway, astGateway, commandsGateway);
|
|
65923
66112
|
const output = await useCase.execute({
|
|
65924
66113
|
targetDir: dir
|
|
@@ -65938,6 +66127,7 @@ const remark = unified().use(remarkParse).use(remarkStringify).freeze()
|
|
|
65938
66127
|
})),
|
|
65939
66128
|
overallQualityScore: output.result.overallQualityScore,
|
|
65940
66129
|
suggestions: output.result.suggestions,
|
|
66130
|
+
parsingErrors: output.result.parsingErrors,
|
|
65941
66131
|
diagnostics: output.diagnostics.map((d)=>({
|
|
65942
66132
|
filePath: d.filePath,
|
|
65943
66133
|
line: d.line,
|