@yawlabs/ctxlint 0.9.15 → 0.9.16

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.
Files changed (2) hide show
  1. package/dist/index.js +31 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -43854,7 +43854,7 @@ import { readFileSync as readFileSync4 } from "node:fs";
43854
43854
  import { resolve as resolve8, dirname as dirname3 } from "node:path";
43855
43855
  import { fileURLToPath } from "node:url";
43856
43856
  function loadVersion() {
43857
- if (true) return "0.9.15";
43857
+ if (true) return "0.9.16";
43858
43858
  const __dir = dirname3(fileURLToPath(import.meta.url));
43859
43859
  const pkgPath = resolve8(__dir, "../package.json");
43860
43860
  const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
@@ -44771,7 +44771,23 @@ var init_fixer = __esm({
44771
44771
  // src/mcp/server.ts
44772
44772
  var server_exports = {};
44773
44773
  import * as path9 from "node:path";
44774
- var contextCheckEnum, mcpCheckEnum, sessionCheckEnum, server, transport;
44774
+ function validateProjectPath(rawPath) {
44775
+ if (!rawPath) return process.cwd();
44776
+ if (PATH_DISALLOWED.test(rawPath)) {
44777
+ throw new Error("projectPath contains disallowed characters");
44778
+ }
44779
+ const resolved = path9.resolve(rawPath);
44780
+ if (!isDirectory(resolved)) {
44781
+ throw new Error("projectPath is not an existing directory");
44782
+ }
44783
+ return resolved;
44784
+ }
44785
+ function validateFilePathInput(rawPath) {
44786
+ if (PATH_DISALLOWED.test(rawPath)) {
44787
+ throw new Error("path contains disallowed characters");
44788
+ }
44789
+ }
44790
+ var contextCheckEnum, mcpCheckEnum, sessionCheckEnum, PATH_DISALLOWED, server, transport;
44775
44791
  var init_server3 = __esm({
44776
44792
  async "src/mcp/server.ts"() {
44777
44793
  "use strict";
@@ -44791,13 +44807,14 @@ var init_server3 = __esm({
44791
44807
  contextCheckEnum = external_exports3.enum(ALL_CHECKS);
44792
44808
  mcpCheckEnum = external_exports3.enum(ALL_MCP_CHECKS);
44793
44809
  sessionCheckEnum = external_exports3.enum(ALL_SESSION_CHECKS);
44810
+ PATH_DISALLOWED = /[\n\r\t;`|]|\$\(|\$\{/;
44794
44811
  server = new McpServer({
44795
44812
  name: "ctxlint",
44796
44813
  version: VERSION
44797
44814
  });
44798
44815
  server.tool(
44799
44816
  "ctxlint_audit",
44800
- "Audit AI agent context files (CLAUDE.md, AGENTS.md, etc.) in the project. Checks for stale references, invalid commands, redundant content, contradictions, frontmatter issues, and token waste. Use ctxlint_mcp_audit for MCP configs or ctxlint_session_audit for session checks.",
44817
+ "Audit AI agent context files (CLAUDE.md, AGENTS.md, etc.) in the project. Checks for stale references, invalid commands, redundant content, contradictions, frontmatter issues, and token waste. Scoped to context-file checks only; MCP-config and session-level checks are exposed as separate tools.",
44801
44818
  {
44802
44819
  projectPath: external_exports3.string().optional().describe("Path to the project root. Defaults to current working directory."),
44803
44820
  checks: external_exports3.array(contextCheckEnum).optional().describe("Which context-file checks to run. Defaults to all.")
@@ -44809,9 +44826,9 @@ var init_server3 = __esm({
44809
44826
  openWorldHint: false
44810
44827
  },
44811
44828
  async ({ projectPath, checks }) => {
44812
- const root = path9.resolve(projectPath || process.cwd());
44813
- const activeChecks = checks?.length ? checks : ALL_CHECKS;
44814
44829
  try {
44830
+ const root = validateProjectPath(projectPath);
44831
+ const activeChecks = checks?.length ? checks : ALL_CHECKS;
44815
44832
  const result = await runAudit(root, activeChecks);
44816
44833
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
44817
44834
  } catch (err) {
@@ -44843,7 +44860,8 @@ var init_server3 = __esm({
44843
44860
  },
44844
44861
  async ({ path: filePath, projectPath }) => {
44845
44862
  try {
44846
- const root = path9.resolve(projectPath || process.cwd());
44863
+ validateFilePathInput(filePath);
44864
+ const root = validateProjectPath(projectPath);
44847
44865
  const resolved = path9.resolve(root, filePath);
44848
44866
  const result = {
44849
44867
  path: filePath,
@@ -44885,8 +44903,8 @@ var init_server3 = __esm({
44885
44903
  openWorldHint: false
44886
44904
  },
44887
44905
  async ({ projectPath }) => {
44888
- const root = path9.resolve(projectPath || process.cwd());
44889
44906
  try {
44907
+ const root = validateProjectPath(projectPath);
44890
44908
  const discovered = await scanForContextFiles(root);
44891
44909
  const parsed = discovered.map((f) => parseContextFile(f));
44892
44910
  const files = parsed.map((f) => ({
@@ -44936,9 +44954,9 @@ var init_server3 = __esm({
44936
44954
  openWorldHint: false
44937
44955
  },
44938
44956
  async ({ projectPath, checks }) => {
44939
- const root = path9.resolve(projectPath || process.cwd());
44940
- const activeChecks = checks?.length ? checks : ALL_CHECKS;
44941
44957
  try {
44958
+ const root = validateProjectPath(projectPath);
44959
+ const activeChecks = checks?.length ? checks : ALL_CHECKS;
44942
44960
  const result = await runAudit(root, activeChecks);
44943
44961
  const fixSummary = applyFixes(result, { quiet: true });
44944
44962
  return {
@@ -44986,9 +45004,9 @@ var init_server3 = __esm({
44986
45004
  openWorldHint: false
44987
45005
  },
44988
45006
  async ({ projectPath, checks, includeGlobal }) => {
44989
- const root = path9.resolve(projectPath || process.cwd());
44990
- const activeChecks = checks?.length ? checks : ALL_MCP_CHECKS;
44991
45007
  try {
45008
+ const root = validateProjectPath(projectPath);
45009
+ const activeChecks = checks?.length ? checks : ALL_MCP_CHECKS;
44992
45010
  const result = await runAudit(root, activeChecks, {
44993
45011
  mcp: true,
44994
45012
  mcpOnly: true,
@@ -45023,9 +45041,9 @@ var init_server3 = __esm({
45023
45041
  openWorldHint: true
45024
45042
  },
45025
45043
  async ({ projectPath, checks }) => {
45026
- const root = path9.resolve(projectPath || process.cwd());
45027
- const activeChecks = checks?.length ? checks : ALL_SESSION_CHECKS;
45028
45044
  try {
45045
+ const root = validateProjectPath(projectPath);
45046
+ const activeChecks = checks?.length ? checks : ALL_SESSION_CHECKS;
45029
45047
  const result = await runAudit(root, activeChecks, {
45030
45048
  session: true,
45031
45049
  sessionOnly: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/ctxlint",
3
- "version": "0.9.15",
3
+ "version": "0.9.16",
4
4
  "description": "Lint your AI agent context files, MCP server configs, and session data against your actual codebase",
5
5
  "bin": {
6
6
  "ctxlint": "dist/index.js"