@agent-lint/mcp 0.3.3 → 0.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @agent-lint/mcp Changelog
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 637e0e2: Add maintenance rule installation to `agent-lint init`, make repeated installs update managed rule files cleanly, and expand maintenance snippets so agents can infer Agent Lint tasks from plain-English context requests.
8
+
9
+ ## 0.3.4
10
+
11
+ ### Patch Changes
12
+
13
+ - a4047fa: Fix doctor workspace discovery and report persistence regressions, and align cross-platform fixture coverage for CLI and MCP outputs.
14
+
3
15
  ## [0.3.3]
4
16
 
5
17
  ### Fixed
package/dist/bin.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  logMcp,
5
5
  runHttpServer,
6
6
  runStdioServer
7
- } from "./chunk-DYP46E6V.js";
7
+ } from "./chunk-PAQI5DE3.js";
8
8
 
9
9
  // src/bin.ts
10
10
  var nodeVersion = parseInt(process.versions.node.split(".")[0], 10);
@@ -17304,19 +17304,6 @@ var artifactTypeValues = [
17304
17304
  "plans"
17305
17305
  ];
17306
17306
  var artifactTypeSchema = external_exports.enum(artifactTypeValues);
17307
- var contextDocumentSchema = external_exports.object({
17308
- label: external_exports.string().min(1).max(120),
17309
- content: external_exports.string().min(1).max(2e5),
17310
- path: external_exports.string().min(1).max(512).optional(),
17311
- type: artifactTypeSchema.optional(),
17312
- priority: external_exports.number().int().min(0).max(10).optional()
17313
- });
17314
- var artifactSubmissionSchema = external_exports.object({
17315
- type: artifactTypeSchema,
17316
- content: external_exports.string().min(1).max(1e6),
17317
- contextDocuments: external_exports.array(contextDocumentSchema).max(20).optional(),
17318
- userId: external_exports.string().min(1).max(128).optional()
17319
- });
17320
17307
  var qualityMetricIds = [
17321
17308
  "clarity",
17322
17309
  "specificity",
@@ -17356,71 +17343,112 @@ var AGENT_HINTS = [
17356
17343
  ecosystem: "Root docs",
17357
17344
  patterns: ["AGENTS.md", "CLAUDE.md"],
17358
17345
  examples: ["AGENTS.md", "CLAUDE.md"],
17346
+ discoveryTier: "canonical",
17359
17347
  notes: "Prefer root-level files when available."
17360
17348
  },
17361
17349
  {
17362
17350
  ecosystem: "Nested policy docs",
17363
- patterns: ["**/.agents/**/*.md", "docs/**/agents*.md"],
17364
- examples: [".agents/AGENTS.md", "docs/agent_guide.md"]
17351
+ patterns: [
17352
+ ".agents/AGENTS.md",
17353
+ ".agents/**/AGENTS.md",
17354
+ ".agents/CLAUDE.md",
17355
+ ".agents/**/CLAUDE.md"
17356
+ ],
17357
+ examples: [".agents/AGENTS.md", ".agents/team/CLAUDE.md"],
17358
+ discoveryTier: "canonical"
17359
+ },
17360
+ {
17361
+ ecosystem: "Fallback docs",
17362
+ patterns: ["docs/**/agents*.md"],
17363
+ examples: ["docs/agent_guide.md"],
17364
+ discoveryTier: "fallback"
17365
17365
  }
17366
17366
  ];
17367
17367
  var SKILL_HINTS = [
17368
17368
  {
17369
17369
  ecosystem: "Windsurf",
17370
- patterns: [".windsurf/skills/**/SKILL.md", ".windsurf/skills/**/*.md"],
17371
- examples: [".windsurf/skills/frontend/SKILL.md"]
17370
+ patterns: [".windsurf/skills/**/SKILL.md"],
17371
+ examples: [".windsurf/skills/frontend/SKILL.md"],
17372
+ discoveryTier: "canonical"
17372
17373
  },
17373
17374
  {
17374
17375
  ecosystem: "Claude/Cline style",
17375
17376
  patterns: [".claude/skills/**/SKILL.md", ".skills/**/SKILL.md", "skills/**/SKILL.md"],
17376
- examples: ["skills/release/SKILL.md", ".claude/skills/testing/SKILL.md"]
17377
+ examples: ["skills/release/SKILL.md", ".claude/skills/testing/SKILL.md"],
17378
+ discoveryTier: "canonical"
17377
17379
  },
17378
17380
  {
17379
17381
  ecosystem: "Agent Skills standard",
17380
17382
  patterns: [".agents/skills/**/SKILL.md", ".github/skills/**/SKILL.md"],
17381
- examples: [".agents/skills/release/SKILL.md", ".github/skills/security-review/SKILL.md"]
17383
+ examples: [".agents/skills/release/SKILL.md", ".github/skills/security-review/SKILL.md"],
17384
+ discoveryTier: "canonical"
17382
17385
  },
17383
17386
  {
17384
17387
  ecosystem: "Generic",
17385
17388
  patterns: ["**/*skill*.md", "**/SKILL.md"],
17386
17389
  examples: ["docs/skills/code-review-skill.md"],
17390
+ discoveryTier: "fallback",
17387
17391
  notes: "Use content heuristics when naming is inconsistent."
17388
17392
  }
17389
17393
  ];
17390
17394
  var RULE_HINTS = [
17391
17395
  {
17392
17396
  ecosystem: "Root/docs",
17393
- patterns: ["rules.md", "docs/rules.md", "docs/**/*rule*.md"],
17394
- examples: ["docs/rules.md", "rules.md"]
17397
+ patterns: ["rules.md", "docs/rules.md"],
17398
+ examples: ["docs/rules.md", "rules.md"],
17399
+ discoveryTier: "canonical"
17395
17400
  },
17396
17401
  {
17397
17402
  ecosystem: "Editor-specific",
17398
17403
  patterns: [".cursor/rules/**/*.md", ".cursor/rules/**/*.mdc", ".windsurf/rules/**/*.md"],
17399
- examples: [".cursor/rules/typescript.mdc"]
17404
+ examples: [".cursor/rules/typescript.mdc"],
17405
+ discoveryTier: "canonical"
17406
+ },
17407
+ {
17408
+ ecosystem: "Fallback docs",
17409
+ patterns: ["docs/**/*rule*.md"],
17410
+ examples: ["docs/backend-rule-overrides.md"],
17411
+ discoveryTier: "fallback"
17400
17412
  }
17401
17413
  ];
17402
17414
  var WORKFLOW_HINTS = [
17403
17415
  {
17404
17416
  ecosystem: "Slash-command docs",
17405
- patterns: ["docs/workflows/**/*.md", "docs/commands/**/*.md", "**/*workflow*.md"],
17406
- examples: ["docs/workflows/release.md", "docs/commands/fix.md"]
17417
+ patterns: ["docs/workflows/**/*.md", "docs/commands/**/*.md"],
17418
+ examples: ["docs/workflows/release.md", "docs/commands/fix.md"],
17419
+ discoveryTier: "canonical"
17407
17420
  },
17408
17421
  {
17409
17422
  ecosystem: "Client command folders",
17410
17423
  patterns: [".claude/commands/**/*.md", ".windsurf/workflows/**/*.md"],
17411
- examples: [".claude/commands/review.md"]
17424
+ examples: [".claude/commands/review.md"],
17425
+ discoveryTier: "canonical"
17426
+ },
17427
+ {
17428
+ ecosystem: "Fallback docs",
17429
+ patterns: ["**/*workflow*.md"],
17430
+ examples: ["docs/deploy-workflow.md"],
17431
+ discoveryTier: "fallback"
17412
17432
  }
17413
17433
  ];
17414
17434
  var PLAN_HINTS = [
17415
17435
  {
17416
17436
  ecosystem: "Roadmap/plan docs",
17417
- patterns: ["docs/**/*plan*.md", "docs/**/*roadmap*.md", "docs/**/*backlog*.md"],
17418
- examples: ["docs/phased_implementation_plan.md", "docs/roadmap_master.md"]
17437
+ patterns: ["docs/plans/**/*.md", "docs/backlog/**/*.md"],
17438
+ examples: ["docs/plans/auth-and-billing-rollout.md", "docs/backlog/q2.md"],
17439
+ discoveryTier: "canonical"
17419
17440
  },
17420
17441
  {
17421
17442
  ecosystem: "Top-level planning",
17422
17443
  patterns: ["PLAN.md", "great_plan.md", "PRD.md"],
17423
- examples: ["docs/great_plan.md", "docs/PRD.md"]
17444
+ examples: ["PLAN.md", "PRD.md"],
17445
+ discoveryTier: "canonical"
17446
+ },
17447
+ {
17448
+ ecosystem: "Fallback docs",
17449
+ patterns: ["docs/**/*plan*.md", "docs/**/*roadmap*.md", "docs/**/*backlog*.md"],
17450
+ examples: ["docs/phased_implementation_plan.md", "docs/roadmap_master.md"],
17451
+ discoveryTier: "fallback"
17424
17452
  }
17425
17453
  ];
17426
17454
  function getArtifactPathHints(type) {
@@ -17438,6 +17466,9 @@ function getArtifactPathHints(type) {
17438
17466
  }
17439
17467
  return PLAN_HINTS;
17440
17468
  }
17469
+ function getArtifactDiscoveryPatterns(type, tier = "canonical") {
17470
+ return getArtifactPathHints(type).filter((hint) => hint.discoveryTier === tier).flatMap((hint) => hint.patterns);
17471
+ }
17441
17472
  function buildArtifactPathHintsMarkdown(type) {
17442
17473
  const hints = getArtifactPathHints(type);
17443
17474
  const lines = [
@@ -17450,6 +17481,8 @@ function buildArtifactPathHintsMarkdown(type) {
17450
17481
  for (const hint of hints) {
17451
17482
  lines.push(`## ${hint.ecosystem}`);
17452
17483
  lines.push("");
17484
+ lines.push(`Discovery tier: ${hint.discoveryTier}`);
17485
+ lines.push("");
17453
17486
  lines.push("Patterns:");
17454
17487
  for (const pattern of hint.patterns) {
17455
17488
  lines.push(`- ${pattern}`);
@@ -18197,11 +18230,17 @@ function buildTemplateMarkdown(type) {
18197
18230
  "```"
18198
18231
  ].join("\n");
18199
18232
  }
18233
+ function normalizePath(filePath) {
18234
+ return filePath.replace(/\\/g, "/");
18235
+ }
18200
18236
  var SKIP_DIRS = /* @__PURE__ */ new Set([
18201
18237
  "node_modules",
18202
18238
  ".git",
18203
18239
  ".next",
18204
18240
  ".nuxt",
18241
+ ".turbo",
18242
+ ".idea",
18243
+ ".vscode",
18205
18244
  "dist",
18206
18245
  "build",
18207
18246
  "out",
@@ -18212,51 +18251,18 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
18212
18251
  "vendor",
18213
18252
  "target"
18214
18253
  ]);
18254
+ var ALLOWED_HIDDEN_DIRS = /* @__PURE__ */ new Set([
18255
+ ".agents",
18256
+ ".claude",
18257
+ ".cursor",
18258
+ ".github",
18259
+ ".skills",
18260
+ ".windsurf"
18261
+ ]);
18215
18262
  var ARTIFACT_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".mdc", ".yaml", ".yml", ".txt"]);
18216
18263
  var MAX_FILES = 200;
18217
18264
  var MAX_DEPTH = 6;
18218
18265
  var MAX_FILE_SIZE = 5e5;
18219
- function shouldSkipDir(name) {
18220
- return SKIP_DIRS.has(name) || name.startsWith(".");
18221
- }
18222
- function isArtifactExtension(filePath) {
18223
- return ARTIFACT_EXTENSIONS.has(path.extname(filePath).toLowerCase());
18224
- }
18225
- function inferArtifactType(filePath, content) {
18226
- const normalized = filePath.replace(/\\/g, "/").toLowerCase();
18227
- const lowerContent = content.substring(0, 2e3).toLowerCase();
18228
- if (/agents\.md$/i.test(normalized) || /claude\.md$/i.test(normalized)) {
18229
- return "agents";
18230
- }
18231
- if (normalized.includes("skill")) {
18232
- return "skills";
18233
- }
18234
- if (normalized.includes("rule")) {
18235
- return "rules";
18236
- }
18237
- if (normalized.includes("workflow") || normalized.includes("command")) {
18238
- return "workflows";
18239
- }
18240
- if (normalized.includes("plan") || normalized.includes("roadmap") || normalized.includes("backlog")) {
18241
- return "plans";
18242
- }
18243
- if (lowerContent.includes("agents.md") || lowerContent.includes("claude.md")) {
18244
- return "agents";
18245
- }
18246
- if (lowerContent.includes("disable-model-invocation") || lowerContent.includes("required frontmatter")) {
18247
- return "skills";
18248
- }
18249
- if (lowerContent.includes("activation mode") || lowerContent.includes("do block")) {
18250
- return "rules";
18251
- }
18252
- if (lowerContent.includes("ordered steps") || lowerContent.includes("preconditions")) {
18253
- return "workflows";
18254
- }
18255
- if (lowerContent.includes("acceptance criteria") || lowerContent.includes("## phases")) {
18256
- return "plans";
18257
- }
18258
- return null;
18259
- }
18260
18266
  var REQUIRED_SECTIONS = {
18261
18267
  agents: [
18262
18268
  "quick commands",
@@ -18298,70 +18304,143 @@ var REQUIRED_SECTIONS = {
18298
18304
  "evidence"
18299
18305
  ]
18300
18306
  };
18307
+ var CANONICAL_MATCHERS = artifactTypeValues.flatMap(
18308
+ (type) => getArtifactDiscoveryPatterns(type, "canonical").map((pattern) => ({
18309
+ type,
18310
+ regex: globToRegExp(pattern)
18311
+ }))
18312
+ );
18313
+ function escapeRegExp(value) {
18314
+ return value.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
18315
+ }
18316
+ function globToRegExp(pattern) {
18317
+ const normalizedPattern = normalizePath(pattern);
18318
+ let source = "^";
18319
+ for (let i = 0; i < normalizedPattern.length; i++) {
18320
+ const char = normalizedPattern[i];
18321
+ if (char === "*") {
18322
+ const next = normalizedPattern[i + 1];
18323
+ const afterNext = normalizedPattern[i + 2];
18324
+ if (next === "*" && afterNext === "/") {
18325
+ source += "(?:.*/)?";
18326
+ i += 2;
18327
+ continue;
18328
+ }
18329
+ if (next === "*") {
18330
+ source += ".*";
18331
+ i += 1;
18332
+ continue;
18333
+ }
18334
+ source += "[^/]*";
18335
+ continue;
18336
+ }
18337
+ if (char === "?") {
18338
+ source += "[^/]";
18339
+ continue;
18340
+ }
18341
+ source += escapeRegExp(char);
18342
+ }
18343
+ source += "$";
18344
+ return new RegExp(source, "i");
18345
+ }
18346
+ function shouldSkipDir(name) {
18347
+ return SKIP_DIRS.has(name) || name.startsWith(".") && !ALLOWED_HIDDEN_DIRS.has(name);
18348
+ }
18349
+ function isArtifactExtension(filePath) {
18350
+ return ARTIFACT_EXTENSIONS.has(path.extname(filePath).toLowerCase());
18351
+ }
18352
+ function matchArtifactType(relativePath) {
18353
+ for (const matcher of CANONICAL_MATCHERS) {
18354
+ if (matcher.regex.test(relativePath)) {
18355
+ return matcher.type;
18356
+ }
18357
+ }
18358
+ return null;
18359
+ }
18301
18360
  function findMissingSections(content, type) {
18302
18361
  const lowerContent = content.toLowerCase();
18303
18362
  const required2 = REQUIRED_SECTIONS[type];
18304
18363
  return required2.filter((section) => !lowerContent.includes(section));
18305
18364
  }
18306
- function collectCandidateFiles(rootPath, currentDepth, results) {
18365
+ function collectCandidateFiles(rootPath, currentPath, currentDepth, results) {
18307
18366
  if (currentDepth > MAX_DEPTH || results.length >= MAX_FILES) {
18308
18367
  return;
18309
18368
  }
18310
18369
  let entries;
18311
18370
  try {
18312
- entries = fs.readdirSync(rootPath, { withFileTypes: true });
18371
+ entries = fs.readdirSync(currentPath, { withFileTypes: true });
18313
18372
  } catch {
18314
18373
  return;
18315
18374
  }
18375
+ entries.sort((a, b) => a.name.localeCompare(b.name));
18316
18376
  for (const entry of entries) {
18317
18377
  if (results.length >= MAX_FILES) {
18318
18378
  break;
18319
18379
  }
18320
- const fullPath = path.join(rootPath, entry.name);
18380
+ const fullPath = path.join(currentPath, entry.name);
18321
18381
  if (entry.isDirectory()) {
18322
- if (!shouldSkipDir(entry.name) || entry.name === ".cursor" || entry.name === ".windsurf" || entry.name === ".claude" || entry.name === ".agents") {
18323
- collectCandidateFiles(fullPath, currentDepth + 1, results);
18382
+ if (!shouldSkipDir(entry.name)) {
18383
+ collectCandidateFiles(rootPath, fullPath, currentDepth + 1, results);
18324
18384
  }
18325
- } else if (entry.isFile() && isArtifactExtension(entry.name)) {
18326
- results.push(fullPath);
18385
+ continue;
18386
+ }
18387
+ if (!entry.isFile() || !isArtifactExtension(entry.name)) {
18388
+ continue;
18327
18389
  }
18390
+ const relativePath = normalizePath(path.relative(rootPath, fullPath));
18391
+ const type = matchArtifactType(relativePath);
18392
+ if (!type) {
18393
+ continue;
18394
+ }
18395
+ results.push({
18396
+ filePath: fullPath,
18397
+ relativePath,
18398
+ type
18399
+ });
18328
18400
  }
18329
18401
  }
18330
18402
  function findSuggestedPath(type, rootPath) {
18331
- const hints = getArtifactPathHints(type);
18332
- if (hints.length > 0 && hints[0].examples.length > 0) {
18333
- return path.join(rootPath, hints[0].examples[0]);
18403
+ const canonicalHints = getArtifactPathHints(type).filter(
18404
+ (hint) => hint.discoveryTier === "canonical"
18405
+ );
18406
+ for (const hint of canonicalHints) {
18407
+ if (hint.examples.length > 0) {
18408
+ return path.join(rootPath, hint.examples[0]);
18409
+ }
18410
+ }
18411
+ const allHints = getArtifactPathHints(type);
18412
+ for (const hint of allHints) {
18413
+ if (hint.examples.length > 0) {
18414
+ return path.join(rootPath, hint.examples[0]);
18415
+ }
18334
18416
  }
18335
18417
  return path.join(rootPath, `${type.toUpperCase()}.md`);
18336
18418
  }
18337
18419
  function discoverWorkspaceArtifacts(rootPath) {
18338
18420
  const resolvedRoot = path.resolve(rootPath);
18339
- const candidatePaths = [];
18340
- collectCandidateFiles(resolvedRoot, 0, candidatePaths);
18421
+ const candidateFiles = [];
18422
+ collectCandidateFiles(resolvedRoot, resolvedRoot, 0, candidateFiles);
18423
+ candidateFiles.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
18341
18424
  const discovered = [];
18342
18425
  const foundTypes = /* @__PURE__ */ new Set();
18343
- for (const filePath of candidatePaths) {
18426
+ for (const candidate of candidateFiles) {
18344
18427
  let content;
18345
18428
  let stats;
18346
18429
  try {
18347
- stats = fs.statSync(filePath);
18430
+ stats = fs.statSync(candidate.filePath);
18348
18431
  if (stats.size > MAX_FILE_SIZE) {
18349
18432
  continue;
18350
18433
  }
18351
- content = fs.readFileSync(filePath, "utf-8");
18434
+ content = fs.readFileSync(candidate.filePath, "utf-8");
18352
18435
  } catch {
18353
18436
  continue;
18354
18437
  }
18355
- const type = inferArtifactType(filePath, content);
18356
- if (!type) {
18357
- continue;
18358
- }
18359
- foundTypes.add(type);
18360
- const missingSections = findMissingSections(content, type);
18438
+ foundTypes.add(candidate.type);
18439
+ const missingSections = findMissingSections(content, candidate.type);
18361
18440
  discovered.push({
18362
- filePath,
18363
- relativePath: path.relative(resolvedRoot, filePath),
18364
- type,
18441
+ filePath: candidate.filePath,
18442
+ relativePath: candidate.relativePath,
18443
+ type: candidate.type,
18365
18444
  exists: true,
18366
18445
  sizeBytes: stats.size,
18367
18446
  isEmpty: content.trim().length === 0,
@@ -18374,7 +18453,7 @@ function discoverWorkspaceArtifacts(rootPath) {
18374
18453
  missing.push({
18375
18454
  type,
18376
18455
  suggestedPath: findSuggestedPath(type, resolvedRoot),
18377
- reason: `No ${type} artifact found in the workspace.`
18456
+ reason: `No canonical ${type} artifact found in the workspace.`
18378
18457
  });
18379
18458
  }
18380
18459
  }
@@ -18673,10 +18752,13 @@ function buildQuickCheckMarkdown(signals, changedPaths, changeDescription) {
18673
18752
  return lines.join("\n");
18674
18753
  }
18675
18754
  var CORE_RULES = [
18676
- "After any structural change (new module, new directory, new script, new dependency), call agentlint_quick_check with the changed paths to determine if context artifacts need updating.",
18677
- "Before creating or updating any AGENTS.md, CLAUDE.md, skills, rules, workflows, or plans file, call agentlint_get_guidelines for the artifact type to get the full specification.",
18678
- "When the user asks to review or fix context artifacts, call agentlint_plan_workspace_autofix to discover all artifacts and get a step-by-step fix plan.",
18679
- "Apply recommended changes directly using your file editing capabilities. Do not wait for explicit confirmation.",
18755
+ "Treat plain-English requests about stale, missing, inconsistent, or low-quality AGENTS.md, CLAUDE.md, rules, skills, workflows, or plans as Agent Lint work even if the user does not name Agent Lint explicitly.",
18756
+ "Treat structural change signals such as new modules, new directories, dependency changes, CI/config updates, environment/security changes, or repository reorganization as reasons to check whether context artifacts need updates.",
18757
+ "For full workspace review or fix requests, start with agentlint_plan_workspace_autofix to scan the repository and produce the action plan.",
18758
+ "For targeted structural changes, call agentlint_quick_check with changed paths and/or a short change description before editing any context artifacts.",
18759
+ "Before creating or updating any AGENTS.md, CLAUDE.md, skills, rules, workflows, or plans file, call agentlint_get_guidelines for the artifact type to get the current specification.",
18760
+ "When the user wants ongoing upkeep, use agentlint_emit_maintenance_snippet where supported or append equivalent maintenance instructions to the main project context file.",
18761
+ "Apply recommended context artifact changes directly once Agent Lint has identified what to update.",
18680
18762
  "Keep context artifact files concise (under 10,000 characters). Reference external docs instead of duplicating content."
18681
18763
  ];
18682
18764
  function buildCursorSnippet() {
@@ -19192,8 +19274,8 @@ function resolveServerVersion() {
19192
19274
  if (process.env.npm_package_name === "@agent-lint/mcp" && process.env.npm_package_version) {
19193
19275
  return process.env.npm_package_version;
19194
19276
  }
19195
- if ("0.3.3".length > 0) {
19196
- return "0.3.3";
19277
+ if ("0.4.0".length > 0) {
19278
+ return "0.4.0";
19197
19279
  }
19198
19280
  try {
19199
19281
  const pkg = JSON.parse(
@@ -19673,4 +19755,4 @@ strip-bom-string/index.js:
19673
19755
  * Released under the MIT License.
19674
19756
  *)
19675
19757
  */
19676
- //# sourceMappingURL=chunk-DYP46E6V.js.map
19758
+ //# sourceMappingURL=chunk-PAQI5DE3.js.map