@knip/mcp 0.0.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.
Files changed (115) hide show
  1. package/README.md +53 -0
  2. package/docs/blog/brief-history.md +30 -0
  3. package/docs/blog/knip-v3.mdx +88 -0
  4. package/docs/blog/knip-v4.mdx +149 -0
  5. package/docs/blog/knip-v5.mdx +190 -0
  6. package/docs/blog/migration-to-v1.md +65 -0
  7. package/docs/blog/release-notes-v2.md +46 -0
  8. package/docs/blog/slim-down-to-speed-up.md +269 -0
  9. package/docs/blog/state-of-knip.md +191 -0
  10. package/docs/blog/two-years.mdx +107 -0
  11. package/docs/docs/blog/brief-history.md +30 -0
  12. package/docs/docs/blog/for-editors-and-agents.md +109 -0
  13. package/docs/docs/blog/knip-v3.mdx +88 -0
  14. package/docs/docs/blog/knip-v4.mdx +149 -0
  15. package/docs/docs/blog/knip-v5.mdx +190 -0
  16. package/docs/docs/blog/migration-to-v1.md +65 -0
  17. package/docs/docs/blog/release-notes-v2.md +46 -0
  18. package/docs/docs/blog/slim-down-to-speed-up.md +269 -0
  19. package/docs/docs/blog/state-of-knip.md +191 -0
  20. package/docs/docs/blog/two-years.mdx +107 -0
  21. package/docs/docs/explanations/comparison-and-migration.md +129 -0
  22. package/docs/docs/explanations/entry-files.md +70 -0
  23. package/docs/docs/explanations/plugins.md +318 -0
  24. package/docs/docs/explanations/why-use-knip.md +128 -0
  25. package/docs/docs/features/auto-fix.mdx +333 -0
  26. package/docs/docs/features/compilers.md +172 -0
  27. package/docs/docs/features/integrated-monorepos.md +52 -0
  28. package/docs/docs/features/monorepos-and-workspaces.md +134 -0
  29. package/docs/docs/features/production-mode.md +95 -0
  30. package/docs/docs/features/reporters.md +302 -0
  31. package/docs/docs/features/rules-and-filters.md +102 -0
  32. package/docs/docs/features/script-parser.md +156 -0
  33. package/docs/docs/features/source-mapping.md +100 -0
  34. package/docs/docs/guides/configuring-project-files.md +205 -0
  35. package/docs/docs/guides/contributing.md +24 -0
  36. package/docs/docs/guides/handling-issues.mdx +646 -0
  37. package/docs/docs/guides/issue-reproduction.md +94 -0
  38. package/docs/docs/guides/namespace-imports.md +125 -0
  39. package/docs/docs/guides/performance.md +97 -0
  40. package/docs/docs/guides/troubleshooting.md +127 -0
  41. package/docs/docs/guides/using-knip-in-ci.md +54 -0
  42. package/docs/docs/guides/working-with-commonjs.md +72 -0
  43. package/docs/docs/index.mdx +160 -0
  44. package/docs/docs/overview/configuration.md +104 -0
  45. package/docs/docs/overview/features.md +66 -0
  46. package/docs/docs/overview/getting-started.mdx +195 -0
  47. package/docs/docs/overview/screenshots-videos.md +42 -0
  48. package/docs/docs/playground.mdx +38 -0
  49. package/docs/docs/reference/cli.md +481 -0
  50. package/docs/docs/reference/configuration.md +413 -0
  51. package/docs/docs/reference/dynamic-configuration.mdx +72 -0
  52. package/docs/docs/reference/faq.md +441 -0
  53. package/docs/docs/reference/issue-types.md +43 -0
  54. package/docs/docs/reference/jsdoc-tsdoc-tags.md +122 -0
  55. package/docs/docs/reference/known-issues.md +64 -0
  56. package/docs/docs/reference/plugins/.gitkeep +0 -0
  57. package/docs/docs/reference/plugins.md +238 -0
  58. package/docs/docs/reference/related-tooling.md +46 -0
  59. package/docs/docs/sponsors.mdx +65 -0
  60. package/docs/docs/typescript/unused-dependencies.md +86 -0
  61. package/docs/docs/typescript/unused-exports.md +87 -0
  62. package/docs/docs/writing-a-plugin/argument-parsing.md +202 -0
  63. package/docs/docs/writing-a-plugin/index.md +376 -0
  64. package/docs/docs/writing-a-plugin/inputs.md +162 -0
  65. package/docs/explanations/comparison-and-migration.md +129 -0
  66. package/docs/explanations/entry-files.md +70 -0
  67. package/docs/explanations/plugins.md +318 -0
  68. package/docs/explanations/why-use-knip.md +128 -0
  69. package/docs/features/auto-fix.mdx +333 -0
  70. package/docs/features/compilers.md +172 -0
  71. package/docs/features/integrated-monorepos.md +52 -0
  72. package/docs/features/monorepos-and-workspaces.md +134 -0
  73. package/docs/features/production-mode.md +95 -0
  74. package/docs/features/reporters.md +302 -0
  75. package/docs/features/rules-and-filters.md +102 -0
  76. package/docs/features/script-parser.md +156 -0
  77. package/docs/features/source-mapping.md +100 -0
  78. package/docs/guides/configuring-project-files.md +205 -0
  79. package/docs/guides/contributing.md +24 -0
  80. package/docs/guides/handling-issues.mdx +646 -0
  81. package/docs/guides/issue-reproduction.md +94 -0
  82. package/docs/guides/namespace-imports.md +125 -0
  83. package/docs/guides/performance.md +97 -0
  84. package/docs/guides/troubleshooting.md +127 -0
  85. package/docs/guides/using-knip-in-ci.md +54 -0
  86. package/docs/guides/working-with-commonjs.md +72 -0
  87. package/docs/index.mdx +156 -0
  88. package/docs/overview/configuration.md +104 -0
  89. package/docs/overview/features.md +66 -0
  90. package/docs/overview/getting-started.mdx +195 -0
  91. package/docs/overview/screenshots-videos.md +42 -0
  92. package/docs/playground.mdx +38 -0
  93. package/docs/reference/cli.md +481 -0
  94. package/docs/reference/configuration.md +413 -0
  95. package/docs/reference/dynamic-configuration.mdx +72 -0
  96. package/docs/reference/faq.md +441 -0
  97. package/docs/reference/issue-types.md +43 -0
  98. package/docs/reference/jsdoc-tsdoc-tags.md +122 -0
  99. package/docs/reference/known-issues.md +64 -0
  100. package/docs/reference/plugins/.gitkeep +0 -0
  101. package/docs/reference/plugins.md +238 -0
  102. package/docs/reference/related-tooling.md +46 -0
  103. package/docs/sponsors.mdx +65 -0
  104. package/docs/typescript/unused-dependencies.md +86 -0
  105. package/docs/typescript/unused-exports.md +87 -0
  106. package/docs/writing-a-plugin/argument-parsing.md +202 -0
  107. package/docs/writing-a-plugin/index.md +376 -0
  108. package/docs/writing-a-plugin/inputs.md +162 -0
  109. package/license +15 -0
  110. package/package.json +38 -0
  111. package/src/cli.js +13 -0
  112. package/src/curated-resources.js +62 -0
  113. package/src/server.js +129 -0
  114. package/src/texts.js +76 -0
  115. package/src/tools.js +68 -0
@@ -0,0 +1,162 @@
1
+ ---
2
+ title: Inputs
3
+ sidebar:
4
+ order: 2
5
+ ---
6
+
7
+ You may have noticed functions like `toDeferResolve` and `toEntry`. They're a
8
+ way for plugins to tell what they've found and how Knip should handle those. The
9
+ more precise a plugin can be, the better it is for results and performance.
10
+ Here's an overview of all input type functions:
11
+
12
+ - [toEntry][1]
13
+ - [toProductionEntry][2]
14
+ - [toProject][3]
15
+ - [toDependency][4]
16
+ - [toProductionDependency][5]
17
+ - [toDeferResolve][6]
18
+ - [toDeferResolveEntry][7]
19
+ - [toConfig][8]
20
+ - [toBinary][9]
21
+ - [toAlias][10]
22
+ - [Options][11]
23
+
24
+ ## toEntry
25
+
26
+ An `entry` input is just like an `entry` in the configuration. It should either
27
+ be an absolute or relative path, and glob patterns are allowed.
28
+
29
+ ## toProductionEntry
30
+
31
+ A production `entry` input is just like an `production` in the configuration. It
32
+ should either be an absolute or relative path, and it can have glob patterns.
33
+
34
+ ## toProject
35
+
36
+ A `project` input is the equivalent of `project` patterns in the configuration.
37
+ It should either be an absolute or relative path, and (negated) glob patterns
38
+ are allowed.
39
+
40
+ ## toDependency
41
+
42
+ The `dependency` indicates the entry is a dependency, belonging in either the
43
+ `"dependencies"` or `"devDependencies"` section of `package.json`.
44
+
45
+ ## toProductionDependency
46
+
47
+ The production `dependency` indicates the entry is a production dependency,
48
+ expected to be listed in `"dependencies"`.
49
+
50
+ ## toDeferResolve
51
+
52
+ The `deferResolve` input type is used to defer the resolution of a specifier.
53
+ This could be resolved to a dependency or an entry file. For instance, the
54
+ specifier `"input"` could be resolved to `"input.js"`, `"input.tsx"`,
55
+ `"input/index.js"` or the `"input"` package name. Local files are added as entry
56
+ files, package names are external dependencies.
57
+
58
+ If this does not lead to a resolution, the specifier will be reported under
59
+ "unresolved imports".
60
+
61
+ ## toDeferResolveEntry
62
+
63
+ The `deferResolveEntry` input type is similar to `deferResolve`, but it's used
64
+ for entry files only (not dependencies) and unresolved inputs are ignored. It's
65
+ different from `toEntry` as glob patterns are not supported.
66
+
67
+ ## toConfig
68
+
69
+ The `config` input type is a way for plugins to reference a configuration file
70
+ that should be handled by a different plugin. For instance, Angular
71
+ configurations might contain references to `tsConfig` and `karmaConfig` files,
72
+ so these `config` files can then be handled by the TypeScript and Karma plugins,
73
+ respectively.
74
+
75
+ Example:
76
+
77
+ ```ts
78
+ toConfig('typescript', './path/to/tsconfig.json');
79
+ ```
80
+
81
+ For instance, the Angular plugin uses this to tell Knip about its `tsConfig`
82
+ value in `angular.json` projects.
83
+
84
+ ## toBinary
85
+
86
+ The `binary` input type isn't used by plugins directly, but by the shell script
87
+ parser (through the `getInputsFromScripts` helper). Think of GitHub Actions
88
+ workflow YAML files or husky scripts. Using this input type, a binary is
89
+ "assigned" to the dependency that has it as a `"bin"` in their `package.json`.
90
+
91
+ ## toAlias
92
+
93
+ The `alias` input type adds path aliases to the core module resolver. They're
94
+ added to `compilerOptions.paths` so the syntax is identical.
95
+
96
+ ## Options
97
+
98
+ When creating inputs from specifiers, an extra `options` object as the second
99
+ argument can be provided.
100
+
101
+ ### dir
102
+
103
+ The optional `dir` option assigns the input to a different workspace. For
104
+ instance, GitHub Action workflows are always stored in the root workspace, and
105
+ support `working-directory` in job steps. For example:
106
+
107
+ ```yaml
108
+ jobs:
109
+ stylelint:
110
+ runs-on: ubuntu-latest
111
+ steps:
112
+ - run: npx esbuild
113
+ working-directory: packages/app
114
+ ```
115
+
116
+ The GitHub Action plugin understands `working-directory` and adds this `dir` to
117
+ the input:
118
+
119
+ ```ts
120
+ toDependency('esbuild', { dir: 'packages/app' });
121
+ ```
122
+
123
+ Knip now understands `esbuild` is a dependency of the workspace in the
124
+ `packages/app` directory.
125
+
126
+ ### optional
127
+
128
+ Use the `optional` flag to indicate the dependency is optional. Then, a
129
+ dependency won't be flagged as unlisted if it isn't.
130
+
131
+ ### allowIncludeExports
132
+
133
+ By default, exports of entry files such as `src/index.ts` or the files in
134
+ `package.json#exports` are not reported as unused. When using the
135
+ `--include-entry-exports` flag or `isIncludeExports: true` option, unused
136
+ exports on such entry files are also reported.
137
+
138
+ Exports of entry files coming from plugins are not included in the analysis,
139
+ even with the option enabled. This is because certain tools and frameworks
140
+ consume named exports from entry files, causing false positives.
141
+
142
+ The `allowIncludeExports` option allows the exports of entry files to be
143
+ reported as unused when using `--include-entry-exports`. This option is
144
+ typically used with the [toProductionEntry][2] input type.
145
+
146
+ Example:
147
+
148
+ ```ts
149
+ toProductionEntry('./entry.ts', { allowIncludeExports: true });
150
+ ```
151
+
152
+ [1]: #toentry
153
+ [2]: #toproductionentry
154
+ [3]: #toproject
155
+ [4]: #todependency
156
+ [5]: #toproductiondependency
157
+ [6]: #todeferresolve
158
+ [7]: #todeferresolveentry
159
+ [8]: #toconfig
160
+ [9]: #tobinary
161
+ [10]: #toalias
162
+ [11]: #options
package/license ADDED
@@ -0,0 +1,15 @@
1
+ ISC License (ISC)
2
+
3
+ Copyright 2022-2025 Lars Kappert
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any purpose
6
+ with or without fee is hereby granted, provided that the above copyright notice
7
+ and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
11
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
13
+ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
14
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
15
+ THIS SOFTWARE.
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@knip/mcp",
3
+ "version": "0.0.1",
4
+ "description": "Knip MCP Server",
5
+ "type": "module",
6
+ "bin": {
7
+ "knip-mcp": "./src/cli.js"
8
+ },
9
+ "exports": {
10
+ ".": "./src/server.js",
11
+ "./tools": "./src/tools.js"
12
+ },
13
+ "files": [
14
+ "src",
15
+ "docs"
16
+ ],
17
+ "keywords": [
18
+ "knip",
19
+ "mcp",
20
+ "model-context-protocol"
21
+ ],
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/webpro-nl/knip",
25
+ "directory": "packages/mcp-server"
26
+ },
27
+ "author": "Lars Kappert <lars@webpro.nl>",
28
+ "license": "ISC",
29
+ "dependencies": {
30
+ "@modelcontextprotocol/sdk": "^1.24.3",
31
+ "zod": "^4.1.11",
32
+ "knip": "5.75.0"
33
+ },
34
+ "engines": {
35
+ "node": ">=18.18.0"
36
+ },
37
+ "scripts": {}
38
+ }
package/src/cli.js ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { mcpServer } from './server.js';
4
+
5
+ function disconnect() {
6
+ mcpServer.close();
7
+ process.exitCode = 0;
8
+ }
9
+
10
+ await mcpServer.connect(new StdioServerTransport());
11
+
12
+ process.on('SIGINT', disconnect);
13
+ process.on('SIGTERM', disconnect);
@@ -0,0 +1,62 @@
1
+ export const CURATED_RESOURCES = {
2
+ 'getting-started': {
3
+ name: 'Getting Started',
4
+ description: 'New to Knip? Start here for installation and first run',
5
+ path: 'overview/getting-started.mdx',
6
+ },
7
+ configuration: {
8
+ name: 'Configuration',
9
+ description: 'Understand configuration basics, defaults, and file locations',
10
+ path: 'overview/configuration.md',
11
+ },
12
+ 'configuring-project-files': {
13
+ name: 'Configuring Project Files',
14
+ description: 'READ FIRST for unused files or false positives. Covers entry/project patterns',
15
+ path: 'guides/configuring-project-files.md',
16
+ },
17
+ 'handling-issues': {
18
+ name: 'Handling Issues',
19
+ description: 'How to handle each issue type: files, dependencies, exports, types, duplicates',
20
+ path: 'guides/handling-issues.mdx',
21
+ },
22
+ 'monorepos-and-workspaces': {
23
+ name: 'Monorepos & Workspaces',
24
+ description: 'Multi-package repo? Configure workspaces and cross-references here',
25
+ path: 'features/monorepos-and-workspaces.md',
26
+ },
27
+ 'production-mode': {
28
+ name: 'Production Mode',
29
+ description: 'Exclude tests, stories, devDependencies with --production and --strict flags',
30
+ path: 'features/production-mode.md',
31
+ },
32
+ compilers: {
33
+ name: 'Compilers',
34
+ description: 'Using .vue, .svelte, .astro, .mdx files? Configure compilers to parse them',
35
+ path: 'features/compilers.md',
36
+ },
37
+ 'configuration-reference': {
38
+ name: 'Configuration Reference',
39
+ description: 'Complete reference of all config options: entry, project, ignore, plugins, etc.',
40
+ path: 'reference/configuration.md',
41
+ },
42
+ 'plugins-explanation': {
43
+ name: 'Plugins',
44
+ description: 'Config files showing as unused? Understand plugin config vs entry files',
45
+ path: 'explanations/plugins.md',
46
+ },
47
+ 'entry-files': {
48
+ name: 'Entry Files',
49
+ description: 'Understand how Knip discovers entry files and default patterns per plugin',
50
+ path: 'explanations/entry-files.md',
51
+ },
52
+ 'plugin-list': {
53
+ name: 'Plugin List',
54
+ description: 'Check if a plugin exists for your tool (Jest, Vitest, ESLint, etc.)',
55
+ path: 'reference/plugins.md',
56
+ },
57
+ 'known-issues': {
58
+ name: 'Known Issues',
59
+ description: 'Errors or unexpected behavior? Check workarounds for common problems',
60
+ path: 'reference/known-issues.md',
61
+ },
62
+ };
package/src/server.js ADDED
@@ -0,0 +1,129 @@
1
+ process.env.NO_COLOR = '1';
2
+
3
+ import { readFileSync } from 'node:fs';
4
+ import { dirname, join } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ import { z } from 'zod';
8
+ import { CURATED_RESOURCES } from './curated-resources.js';
9
+ import {
10
+ DOC_TOOL_DESCRIPTION,
11
+ DOC_TOOL_TOPIC_DESCRIPTION,
12
+ ERROR_HINT,
13
+ RUN_KNIP_TOOL_DESCRIPTION,
14
+ WORKFLOW,
15
+ } from './texts.js';
16
+ import { getDocs, readContent } from './tools.js';
17
+
18
+ const __dirname = dirname(fileURLToPath(import.meta.url));
19
+ const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
20
+
21
+ const DOCS = 'knip://docs';
22
+
23
+ class MCP {
24
+ constructor() {
25
+ this.server = new McpServer({ name: 'Knip', version: pkg.version });
26
+ this.#registerPrompts();
27
+ this.#registerResources();
28
+ this.#registerTools();
29
+ }
30
+
31
+ #registerPrompts() {
32
+ const resources = Object.entries(CURATED_RESOURCES).map(([id, doc]) => ({
33
+ uri: `${DOCS}/${id}`,
34
+ name: doc.name,
35
+ description: doc.description,
36
+ }));
37
+
38
+ this.server.registerPrompt(
39
+ 'knip-configure',
40
+ {
41
+ description: 'Set up and optimize Knip configuration. Guides through initial setup and iterative refinement.',
42
+ arguments: [{ name: 'cwd', description: 'Working directory (default: current directory)', required: false }],
43
+ },
44
+ async ({ cwd }) => ({
45
+ messages: [
46
+ {
47
+ role: 'user',
48
+ content: {
49
+ type: 'text',
50
+ text: `Help me configure Knip for ${cwd || 'this project'}.\n\n${WORKFLOW}`,
51
+ },
52
+ },
53
+ ],
54
+ resources,
55
+ })
56
+ );
57
+ }
58
+
59
+ #registerResources() {
60
+ for (const [id, doc] of Object.entries(CURATED_RESOURCES)) {
61
+ const uri = `${DOCS}/${id}`;
62
+ this.server.registerResource(
63
+ doc.name,
64
+ uri,
65
+ { description: doc.description, mimeType: 'text/markdown' },
66
+ async () => ({ contents: [{ uri, mimeType: 'text/markdown', text: readContent(doc.path) }] })
67
+ );
68
+ }
69
+
70
+ this.server.registerResource(
71
+ 'docs',
72
+ new ResourceTemplate(`${DOCS}/{+path}`, { list: undefined }),
73
+ { description: 'Get Knip documentation page by path', mimeType: 'text/markdown' },
74
+ async (uri, { path }) => {
75
+ const result = getDocs(path);
76
+ if ('content' in result) return { content: [{ type: 'text', text: result.content }] };
77
+ const errorText = `Documentation not found: ${path}`;
78
+ return { contents: [{ uri, mimeType: 'text/plain', text: errorText }] };
79
+ }
80
+ );
81
+ }
82
+
83
+ #registerTools() {
84
+ this.server.registerTool(
85
+ 'knip-run',
86
+ {
87
+ description: RUN_KNIP_TOOL_DESCRIPTION,
88
+ inputSchema: {
89
+ cwd: z.string().optional().describe('Working directory (default: workspace root)'),
90
+ },
91
+ },
92
+ async opts => {
93
+ try {
94
+ const cwd = opts.cwd || process.cwd();
95
+ const results = await getResults(cwd);
96
+ return { content: [{ type: 'text', text: JSON.stringify(results) }] };
97
+ } catch (error) {
98
+ const message = error instanceof Error ? error.message : String(error);
99
+ return {
100
+ content: [{ type: 'text', text: JSON.stringify({ error: message, hint: ERROR_HINT }) }],
101
+ isError: true,
102
+ };
103
+ }
104
+ }
105
+ );
106
+
107
+ this.server.registerTool(
108
+ 'knip-docs',
109
+ { description: DOC_TOOL_DESCRIPTION, inputSchema: { topic: z.string().describe(DOC_TOOL_TOPIC_DESCRIPTION) } },
110
+ async ({ topic }) => {
111
+ const docs = getDocs(topic);
112
+ if ('content' in docs) return { content: [{ type: 'text', text: docs.content }] };
113
+ return { content: [{ type: 'text', text: docs.error }], isError: true };
114
+ }
115
+ );
116
+ }
117
+
118
+ connect(transport) {
119
+ return this.server.connect(transport);
120
+ }
121
+
122
+ close() {
123
+ return this.server.close();
124
+ }
125
+ }
126
+
127
+ const mcpServer = new MCP();
128
+
129
+ export { mcpServer };
package/src/texts.js ADDED
@@ -0,0 +1,76 @@
1
+ import { CURATED_RESOURCES } from './curated-resources.js';
2
+
3
+ export const WORKFLOW = `Workflow:
4
+ 1. Read essential documentation resources to understand Knip configuration
5
+ 2. Run analysis (knip-run) to get configuration hints and issues
6
+ 3. Address the hints by adjusting knip.json
7
+ 4. Repeat steps 2-3 until no hints remain and false positives are minimized
8
+
9
+ Essential resources:
10
+ - configuring-project-files (must read to configure entry patterns)
11
+ - handling-issues (comprehensive guide to deal with any reported issue type)
12
+ - configuration-reference (all knip.json configuration options)
13
+
14
+ For direct "run knip" or "clean up codebase" requests: Always make sure to run this workflow first.
15
+
16
+ Important (potential next steps after workflow is finished):
17
+ - Before suggesting fixes/solutions, make sure to consult "handling-issues" and "reference/jsdoc-tsdoc-tags"
18
+ - Read "getting-started" and "reference/cli" to install knip and start using Knip from CLI
19
+ - If requested to clean up, consult "features/auto-fix"
20
+ - Knip does not find/fix unused variables/imports within files (use another linter for that)
21
+ `;
22
+
23
+ // pkg.contributes.languageModelTools[0].modelDescription
24
+ export const RUN_KNIP_TOOL_DESCRIPTION = `Run Knip and return configuration hints and issues.
25
+
26
+ Returns:
27
+ - configurationHints: Ordered suggestions to improve configuration (address these first)
28
+ - counters: Summary counts of each issue type
29
+ - files: List of unused files
30
+ - issues: Detailed issues by type (dependencies, exports, types, etc.)
31
+ - configFile: Current config file status
32
+
33
+ Iterate: adjust knip.json based on hints, run again until no hints remain and false positives are minimized.`;
34
+
35
+ // pkg.contributes.languageModelTools[1].modelDescription
36
+ export const DOC_TOOL_DESCRIPTION = `Get Knip documentation by topic.
37
+
38
+ If registered resources are unavailable, use this tool.
39
+
40
+ Available topics (use these IDs):
41
+ ${Object.entries(CURATED_RESOURCES)
42
+ .map(([id, doc]) => `- ${id}: ${doc.description}`)
43
+ .join('\n')}
44
+
45
+ Can also fetch any doc by path (e.g., "reference/cli" or "guides/troubleshooting").
46
+ Use this instead of fetching from knip.dev.`;
47
+
48
+ // pkg.contributes.languageModelTools[1].inputSchema.properties.topic.description
49
+ export const DOC_TOOL_TOPIC_DESCRIPTION =
50
+ 'Topic key (e.g. "configuring-project-files") for curated resources, or path (e.g. "explanations/plugins") for all available docs';
51
+
52
+ export const ERROR_HINT = `For unexpected errors (exit code 2) such as "error loading file":
53
+ - Consult docs: known-issues and configuration-reference
54
+ - If no config file exists, create knip.json in root: {"$schema":"https://unpkg.com/knip@5/schema.json"}
55
+ - Damage control for "error loading file":
56
+ 1) First try to disable the related plugin's config file:
57
+ - E.g. vite: { config: [] }
58
+ - In a monorepo use e.g. { workspaces: { "packages/lib": { vite: { config: [] } } } }
59
+ - If this succeeds, add the file as a regular entry point
60
+ 2) Then try to disable the related plugin:
61
+ - E.g. vite: false
62
+ - In a monorepo use e.g. { workspaces: { "packages/lib": { vite: false } } }
63
+ - If this succeeds, add the file as a regular entry point
64
+ 3) As a last resort, ignore the workspace: ignoreWorkspaces: ["packages/lib"]
65
+ - Run knip again`;
66
+
67
+ export const CONFIG_REVIEW_HINT = `Review the existing configuration for potential improvements:
68
+
69
+ - Never use "ignore" patterns (hides real issues!), always prefer specific solutions, other ignore* options are allowed
70
+ - Many unused exported types? Add: ignoreExportsUsedInFile: { interface: true, type: true } (prefer this over other ignore* options)
71
+ - Remove ignore patterns that don't match any files
72
+ - Redundant ignore patterns: Knip respects .gitignore by default (node_modules, dist, build, .git)
73
+ - Remove entry patterns covered by config defaults and plugins
74
+ - Config files (e.g. vite.config.ts) showing as unused? Enable/disable the plugin explicitly
75
+ - Dependencies matching Node.js builtins: add to ignoreDependencies (e.g. buffer, process)
76
+ - Unresolved imports from path aliases: add paths to Knip config (tsconfig.json semantics)`;
package/src/tools.js ADDED
@@ -0,0 +1,68 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { createOptions, createSession, finalizeConfigurationHints, KNIP_CONFIG_LOCATIONS } from 'knip/session';
5
+ import { CURATED_RESOURCES } from './curated-resources.js';
6
+ import { CONFIG_REVIEW_HINT } from './texts.js';
7
+
8
+ export { ERROR_HINT } from './texts.js';
9
+
10
+ const __dirname = dirname(fileURLToPath(import.meta.url));
11
+ const docsDir = join(__dirname, '../docs');
12
+
13
+ /**
14
+ * @param {import('knip/session').Results} results
15
+ * @param {{ cwd: string, configFilePath: string | undefined }} options
16
+ */
17
+ export function buildResults(results, options) {
18
+ return {
19
+ configFile: options.configFilePath
20
+ ? { exists: true, filePath: options.configFilePath, reviewHint: CONFIG_REVIEW_HINT }
21
+ : { exists: false, locations: KNIP_CONFIG_LOCATIONS },
22
+ configurationHints: finalizeConfigurationHints(results, options),
23
+ counters: results.counters,
24
+ files: Array.from(results.issues.files),
25
+ issues: Object.fromEntries(Object.entries(results.issues).filter(([key]) => key !== 'files' && key !== '_files')),
26
+ };
27
+ }
28
+
29
+ /**
30
+ * @param {string} cwd
31
+ */
32
+ export async function getResults(cwd) {
33
+ const options = await createOptions({ cwd, isSession: true, isUseTscFiles: false });
34
+ const session = await createSession(options);
35
+ return buildResults(session.getResults(), options);
36
+ }
37
+
38
+ /** @param {string} filePath */
39
+ export function readContent(filePath) {
40
+ try {
41
+ const content = readFileSync(join(docsDir, filePath), 'utf-8');
42
+ return content.replace(/^---[\s\S]*?---\n/, '');
43
+ } catch (error) {
44
+ return `Error reading ${filePath}: ${error.message}`;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * @param {string} topic
50
+ * @returns {{ content: string } | { error: string }}
51
+ */
52
+ export function getDocs(topic) {
53
+ const content = findDocPage(topic);
54
+ if (content) return { content };
55
+ return { error: `Documentation not found: ${topic}. Available: ${Object.keys(CURATED_RESOURCES).join(', ')}` };
56
+ }
57
+
58
+ /** @param {string} topic */
59
+ function findDocPage(topic) {
60
+ if (CURATED_RESOURCES[topic]) return readContent(CURATED_RESOURCES[topic].path);
61
+
62
+ for (const ext of ['.md', '.mdx']) {
63
+ const filePath = join(docsDir, `${topic}${ext}`);
64
+ if (existsSync(filePath)) return readContent(`${topic}${ext}`);
65
+ }
66
+
67
+ return null;
68
+ }