@lousy-agents/cli 2.9.1 → 2.10.1

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.
@@ -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
- // Skip files that can't be parsed
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
- // Simple commands gateway that discovers npm scripts
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,