claude-ide-bridge 1.1.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.
Files changed (273) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +263 -0
  3. package/dist/activityLog.d.ts +26 -0
  4. package/dist/activityLog.js +76 -0
  5. package/dist/activityLog.js.map +1 -0
  6. package/dist/bridge.d.ts +19 -0
  7. package/dist/bridge.js +277 -0
  8. package/dist/bridge.js.map +1 -0
  9. package/dist/config.d.ts +22 -0
  10. package/dist/config.js +221 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/errors.d.ts +16 -0
  13. package/dist/errors.js +20 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/extensionClient.d.ts +193 -0
  16. package/dist/extensionClient.js +698 -0
  17. package/dist/extensionClient.js.map +1 -0
  18. package/dist/fileLock.d.ts +12 -0
  19. package/dist/fileLock.js +30 -0
  20. package/dist/fileLock.js.map +1 -0
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.js +38 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/lockfile.d.ts +12 -0
  25. package/dist/lockfile.js +127 -0
  26. package/dist/lockfile.js.map +1 -0
  27. package/dist/logger.d.ts +16 -0
  28. package/dist/logger.js +68 -0
  29. package/dist/logger.js.map +1 -0
  30. package/dist/probe.d.ts +22 -0
  31. package/dist/probe.js +45 -0
  32. package/dist/probe.js.map +1 -0
  33. package/dist/server.d.ts +25 -0
  34. package/dist/server.js +265 -0
  35. package/dist/server.js.map +1 -0
  36. package/dist/tools/activityLog.d.ts +39 -0
  37. package/dist/tools/activityLog.js +49 -0
  38. package/dist/tools/activityLog.js.map +1 -0
  39. package/dist/tools/aiComments.d.ts +26 -0
  40. package/dist/tools/aiComments.js +196 -0
  41. package/dist/tools/aiComments.js.map +1 -0
  42. package/dist/tools/bridgeStatus.d.ts +21 -0
  43. package/dist/tools/bridgeStatus.js +41 -0
  44. package/dist/tools/bridgeStatus.js.map +1 -0
  45. package/dist/tools/checkDocumentDirty.d.ts +28 -0
  46. package/dist/tools/checkDocumentDirty.js +61 -0
  47. package/dist/tools/checkDocumentDirty.js.map +1 -0
  48. package/dist/tools/clipboard.d.ts +50 -0
  49. package/dist/tools/clipboard.js +82 -0
  50. package/dist/tools/clipboard.js.map +1 -0
  51. package/dist/tools/closeTabs.d.ts +49 -0
  52. package/dist/tools/closeTabs.js +77 -0
  53. package/dist/tools/closeTabs.js.map +1 -0
  54. package/dist/tools/debug.d.ts +154 -0
  55. package/dist/tools/debug.js +248 -0
  56. package/dist/tools/debug.js.map +1 -0
  57. package/dist/tools/decorations.d.ts +92 -0
  58. package/dist/tools/decorations.js +150 -0
  59. package/dist/tools/decorations.js.map +1 -0
  60. package/dist/tools/diffDebugger.d.ts +62 -0
  61. package/dist/tools/diffDebugger.js +245 -0
  62. package/dist/tools/diffDebugger.js.map +1 -0
  63. package/dist/tools/editText.d.ts +80 -0
  64. package/dist/tools/editText.js +274 -0
  65. package/dist/tools/editText.js.map +1 -0
  66. package/dist/tools/fileOperations.d.ts +111 -0
  67. package/dist/tools/fileOperations.js +280 -0
  68. package/dist/tools/fileOperations.js.map +1 -0
  69. package/dist/tools/fileWatcher.d.ts +54 -0
  70. package/dist/tools/fileWatcher.js +100 -0
  71. package/dist/tools/fileWatcher.js.map +1 -0
  72. package/dist/tools/findFiles.d.ts +31 -0
  73. package/dist/tools/findFiles.js +119 -0
  74. package/dist/tools/findFiles.js.map +1 -0
  75. package/dist/tools/fixAllLintErrors.d.ts +29 -0
  76. package/dist/tools/fixAllLintErrors.js +114 -0
  77. package/dist/tools/fixAllLintErrors.js.map +1 -0
  78. package/dist/tools/flowGuardian.d.ts +61 -0
  79. package/dist/tools/flowGuardian.js +311 -0
  80. package/dist/tools/flowGuardian.js.map +1 -0
  81. package/dist/tools/formatDocument.d.ts +30 -0
  82. package/dist/tools/formatDocument.js +132 -0
  83. package/dist/tools/formatDocument.js.map +1 -0
  84. package/dist/tools/formatFile.d.ts +28 -0
  85. package/dist/tools/formatFile.js +110 -0
  86. package/dist/tools/formatFile.js.map +1 -0
  87. package/dist/tools/getBufferContent.d.ts +38 -0
  88. package/dist/tools/getBufferContent.js +100 -0
  89. package/dist/tools/getBufferContent.js.map +1 -0
  90. package/dist/tools/getCurrentSelection.d.ts +43 -0
  91. package/dist/tools/getCurrentSelection.js +75 -0
  92. package/dist/tools/getCurrentSelection.js.map +1 -0
  93. package/dist/tools/getDiagnostics.d.ts +38 -0
  94. package/dist/tools/getDiagnostics.js +204 -0
  95. package/dist/tools/getDiagnostics.js.map +1 -0
  96. package/dist/tools/getDocumentSymbols.d.ts +27 -0
  97. package/dist/tools/getDocumentSymbols.js +133 -0
  98. package/dist/tools/getDocumentSymbols.js.map +1 -0
  99. package/dist/tools/getFileTree.d.ts +36 -0
  100. package/dist/tools/getFileTree.js +111 -0
  101. package/dist/tools/getFileTree.js.map +1 -0
  102. package/dist/tools/getGitDiff.d.ts +34 -0
  103. package/dist/tools/getGitDiff.js +57 -0
  104. package/dist/tools/getGitDiff.js.map +1 -0
  105. package/dist/tools/getGitLog.d.ts +30 -0
  106. package/dist/tools/getGitLog.js +65 -0
  107. package/dist/tools/getGitLog.js.map +1 -0
  108. package/dist/tools/getGitStatus.d.ts +26 -0
  109. package/dist/tools/getGitStatus.js +95 -0
  110. package/dist/tools/getGitStatus.js.map +1 -0
  111. package/dist/tools/getOpenEditors.d.ts +21 -0
  112. package/dist/tools/getOpenEditors.js +84 -0
  113. package/dist/tools/getOpenEditors.js.map +1 -0
  114. package/dist/tools/getProjectInfo.d.ts +20 -0
  115. package/dist/tools/getProjectInfo.js +315 -0
  116. package/dist/tools/getProjectInfo.js.map +1 -0
  117. package/dist/tools/getToolCapabilities.d.ts +23 -0
  118. package/dist/tools/getToolCapabilities.js +249 -0
  119. package/dist/tools/getToolCapabilities.js.map +1 -0
  120. package/dist/tools/getWorkspaceFolders.d.ts +21 -0
  121. package/dist/tools/getWorkspaceFolders.js +47 -0
  122. package/dist/tools/getWorkspaceFolders.js.map +1 -0
  123. package/dist/tools/gitHistory.d.ts +78 -0
  124. package/dist/tools/gitHistory.js +151 -0
  125. package/dist/tools/gitHistory.js.map +1 -0
  126. package/dist/tools/gitWrite.d.ts +335 -0
  127. package/dist/tools/gitWrite.js +859 -0
  128. package/dist/tools/gitWrite.js.map +1 -0
  129. package/dist/tools/github/actions.d.ts +67 -0
  130. package/dist/tools/github/actions.js +155 -0
  131. package/dist/tools/github/actions.js.map +1 -0
  132. package/dist/tools/github/index.d.ts +4 -0
  133. package/dist/tools/github/index.js +5 -0
  134. package/dist/tools/github/index.js.map +1 -0
  135. package/dist/tools/github/issues.d.ts +140 -0
  136. package/dist/tools/github/issues.js +279 -0
  137. package/dist/tools/github/issues.js.map +1 -0
  138. package/dist/tools/github/pr.d.ts +101 -0
  139. package/dist/tools/github/pr.js +215 -0
  140. package/dist/tools/github/pr.js.map +1 -0
  141. package/dist/tools/github/review.d.ts +101 -0
  142. package/dist/tools/github/review.js +292 -0
  143. package/dist/tools/github/review.js.map +1 -0
  144. package/dist/tools/github/shared.d.ts +4 -0
  145. package/dist/tools/github/shared.js +12 -0
  146. package/dist/tools/github/shared.js.map +1 -0
  147. package/dist/tools/github.d.ts +308 -0
  148. package/dist/tools/github.js +656 -0
  149. package/dist/tools/github.js.map +1 -0
  150. package/dist/tools/hoverAtCursor.d.ts +22 -0
  151. package/dist/tools/hoverAtCursor.js +51 -0
  152. package/dist/tools/hoverAtCursor.js.map +1 -0
  153. package/dist/tools/httpClient.d.ts +83 -0
  154. package/dist/tools/httpClient.js +335 -0
  155. package/dist/tools/httpClient.js.map +1 -0
  156. package/dist/tools/index.d.ts +7 -0
  157. package/dist/tools/index.js +246 -0
  158. package/dist/tools/index.js.map +1 -0
  159. package/dist/tools/inlayHints.d.ts +38 -0
  160. package/dist/tools/inlayHints.js +56 -0
  161. package/dist/tools/inlayHints.js.map +1 -0
  162. package/dist/tools/linters/biome.d.ts +2 -0
  163. package/dist/tools/linters/biome.js +44 -0
  164. package/dist/tools/linters/biome.js.map +1 -0
  165. package/dist/tools/linters/cargo.d.ts +2 -0
  166. package/dist/tools/linters/cargo.js +45 -0
  167. package/dist/tools/linters/cargo.js.map +1 -0
  168. package/dist/tools/linters/eslint.d.ts +2 -0
  169. package/dist/tools/linters/eslint.js +59 -0
  170. package/dist/tools/linters/eslint.js.map +1 -0
  171. package/dist/tools/linters/govet.d.ts +2 -0
  172. package/dist/tools/linters/govet.js +37 -0
  173. package/dist/tools/linters/govet.js.map +1 -0
  174. package/dist/tools/linters/pyright.d.ts +2 -0
  175. package/dist/tools/linters/pyright.js +34 -0
  176. package/dist/tools/linters/pyright.js.map +1 -0
  177. package/dist/tools/linters/ruff.d.ts +2 -0
  178. package/dist/tools/linters/ruff.js +30 -0
  179. package/dist/tools/linters/ruff.js.map +1 -0
  180. package/dist/tools/linters/types.d.ts +16 -0
  181. package/dist/tools/linters/types.js +2 -0
  182. package/dist/tools/linters/types.js.map +1 -0
  183. package/dist/tools/linters/typescript.d.ts +2 -0
  184. package/dist/tools/linters/typescript.js +38 -0
  185. package/dist/tools/linters/typescript.js.map +1 -0
  186. package/dist/tools/lsp.d.ts +310 -0
  187. package/dist/tools/lsp.js +684 -0
  188. package/dist/tools/lsp.js.map +1 -0
  189. package/dist/tools/notebook.d.ts +95 -0
  190. package/dist/tools/notebook.js +144 -0
  191. package/dist/tools/notebook.js.map +1 -0
  192. package/dist/tools/openDiff.d.ts +41 -0
  193. package/dist/tools/openDiff.js +116 -0
  194. package/dist/tools/openDiff.js.map +1 -0
  195. package/dist/tools/openFile.d.ts +34 -0
  196. package/dist/tools/openFile.js +102 -0
  197. package/dist/tools/openFile.js.map +1 -0
  198. package/dist/tools/organizeImports.d.ts +29 -0
  199. package/dist/tools/organizeImports.js +64 -0
  200. package/dist/tools/organizeImports.js.map +1 -0
  201. package/dist/tools/planPersistence.d.ts +196 -0
  202. package/dist/tools/planPersistence.js +437 -0
  203. package/dist/tools/planPersistence.js.map +1 -0
  204. package/dist/tools/replaceBlock.d.ts +40 -0
  205. package/dist/tools/replaceBlock.js +105 -0
  206. package/dist/tools/replaceBlock.js.map +1 -0
  207. package/dist/tools/runCommand.d.ts +43 -0
  208. package/dist/tools/runCommand.js +141 -0
  209. package/dist/tools/runCommand.js.map +1 -0
  210. package/dist/tools/runTests.d.ts +32 -0
  211. package/dist/tools/runTests.js +160 -0
  212. package/dist/tools/runTests.js.map +1 -0
  213. package/dist/tools/saveDocument.d.ts +28 -0
  214. package/dist/tools/saveDocument.js +58 -0
  215. package/dist/tools/saveDocument.js.map +1 -0
  216. package/dist/tools/searchAndReplace.d.ts +50 -0
  217. package/dist/tools/searchAndReplace.js +203 -0
  218. package/dist/tools/searchAndReplace.js.map +1 -0
  219. package/dist/tools/searchWorkspace.d.ts +52 -0
  220. package/dist/tools/searchWorkspace.js +159 -0
  221. package/dist/tools/searchWorkspace.js.map +1 -0
  222. package/dist/tools/setActiveWorkspaceFolder.d.ts +28 -0
  223. package/dist/tools/setActiveWorkspaceFolder.js +32 -0
  224. package/dist/tools/setActiveWorkspaceFolder.js.map +1 -0
  225. package/dist/tools/tasks.d.ts +56 -0
  226. package/dist/tools/tasks.js +89 -0
  227. package/dist/tools/tasks.js.map +1 -0
  228. package/dist/tools/terminal.d.ts +241 -0
  229. package/dist/tools/terminal.js +539 -0
  230. package/dist/tools/terminal.js.map +1 -0
  231. package/dist/tools/testRunners/cargoTest.d.ts +2 -0
  232. package/dist/tools/testRunners/cargoTest.js +123 -0
  233. package/dist/tools/testRunners/cargoTest.js.map +1 -0
  234. package/dist/tools/testRunners/goTest.d.ts +2 -0
  235. package/dist/tools/testRunners/goTest.js +106 -0
  236. package/dist/tools/testRunners/goTest.js.map +1 -0
  237. package/dist/tools/testRunners/pytest.d.ts +2 -0
  238. package/dist/tools/testRunners/pytest.js +133 -0
  239. package/dist/tools/testRunners/pytest.js.map +1 -0
  240. package/dist/tools/testRunners/types.d.ts +18 -0
  241. package/dist/tools/testRunners/types.js +2 -0
  242. package/dist/tools/testRunners/types.js.map +1 -0
  243. package/dist/tools/testRunners/vitestJest.d.ts +3 -0
  244. package/dist/tools/testRunners/vitestJest.js +178 -0
  245. package/dist/tools/testRunners/vitestJest.js.map +1 -0
  246. package/dist/tools/typeHierarchy.d.ts +45 -0
  247. package/dist/tools/typeHierarchy.js +65 -0
  248. package/dist/tools/typeHierarchy.js.map +1 -0
  249. package/dist/tools/utils.d.ts +54 -0
  250. package/dist/tools/utils.js +267 -0
  251. package/dist/tools/utils.js.map +1 -0
  252. package/dist/tools/vscodeCommands.d.ts +59 -0
  253. package/dist/tools/vscodeCommands.js +108 -0
  254. package/dist/tools/vscodeCommands.js.map +1 -0
  255. package/dist/tools/watchDiagnostics.d.ts +32 -0
  256. package/dist/tools/watchDiagnostics.js +87 -0
  257. package/dist/tools/watchDiagnostics.js.map +1 -0
  258. package/dist/tools/workspaceSettings.d.ts +67 -0
  259. package/dist/tools/workspaceSettings.js +102 -0
  260. package/dist/tools/workspaceSettings.js.map +1 -0
  261. package/dist/tools/workspaceSnapshots.d.ts +174 -0
  262. package/dist/tools/workspaceSnapshots.js +474 -0
  263. package/dist/tools/workspaceSnapshots.js.map +1 -0
  264. package/dist/transport.d.ts +57 -0
  265. package/dist/transport.js +417 -0
  266. package/dist/transport.js.map +1 -0
  267. package/dist/version.d.ts +2 -0
  268. package/dist/version.js +3 -0
  269. package/dist/version.js.map +1 -0
  270. package/dist/wsUtils.d.ts +9 -0
  271. package/dist/wsUtils.js +54 -0
  272. package/dist/wsUtils.js.map +1 -0
  273. package/package.json +69 -0
@@ -0,0 +1,119 @@
1
+ import { execSafe, makeRelative, optionalString, requireString, resolveFilePath, success, } from "./utils.js";
2
+ export function createFindFilesTool(workspace, probes) {
3
+ return {
4
+ schema: {
5
+ name: "findFiles",
6
+ description: "Find files by name/glob pattern in the workspace. Respects .gitignore.",
7
+ annotations: { readOnlyHint: true },
8
+ inputSchema: {
9
+ type: "object",
10
+ properties: {
11
+ pattern: {
12
+ type: "string",
13
+ description: "Glob pattern (e.g. '*.config.ts', 'README*')",
14
+ },
15
+ directory: {
16
+ type: "string",
17
+ description: "Subdirectory to search in (relative to workspace)",
18
+ },
19
+ },
20
+ required: ["pattern"],
21
+ additionalProperties: false,
22
+ },
23
+ },
24
+ handler: async (args, signal) => {
25
+ const pattern = requireString(args, "pattern", 200);
26
+ const directory = optionalString(args, "directory", 500);
27
+ const searchDir = directory
28
+ ? resolveFilePath(directory, workspace)
29
+ : workspace;
30
+ if (probes.fd) {
31
+ const fdArgs = ["--glob", pattern, "--max-results", "100", searchDir];
32
+ const result = await execSafe("fd", fdArgs, {
33
+ timeout: 10000,
34
+ signal,
35
+ });
36
+ const files = result.stdout
37
+ .split("\n")
38
+ .filter(Boolean)
39
+ .map((f) => makeRelative(f, workspace));
40
+ const truncated = files.length === 100;
41
+ return success({
42
+ files,
43
+ count: files.length,
44
+ tool: "fd",
45
+ ...(truncated
46
+ ? {
47
+ truncated: true,
48
+ note: "Result limit reached — narrow pattern or use directory",
49
+ }
50
+ : {}),
51
+ });
52
+ }
53
+ if (probes.git) {
54
+ const result = await execSafe("git", ["ls-files", "--cached", "--others", "--exclude-standard"], { cwd: workspace, timeout: 10000, signal });
55
+ const allFiles = result.stdout.split("\n").filter(Boolean);
56
+ // Convert glob to regex — escape metacharacters before glob substitution
57
+ const regexPattern = pattern
58
+ .replace(/\*\*/g, "\0GLOBSTAR\0")
59
+ .replace(/\*/g, "\0STAR\0")
60
+ .replace(/\?/g, "\0Q\0")
61
+ .replace(/[.*+^${}()|[\]\\]/g, "\\$&")
62
+ .replace(/\0GLOBSTAR\0/g, ".*")
63
+ .replace(/\0STAR\0/g, "[^/]*")
64
+ .replace(/\0Q\0/g, "[^/]");
65
+ const regex = new RegExp(`(^|/)${regexPattern}$`, "i");
66
+ const allMatches = allFiles.filter((f) => regex.test(f));
67
+ const files = allMatches.slice(0, 100);
68
+ return success({
69
+ files,
70
+ count: files.length,
71
+ totalMatches: allMatches.length,
72
+ tool: "git-ls-files",
73
+ ...(files.length < allMatches.length
74
+ ? {
75
+ truncated: true,
76
+ note: "Result limit reached — narrow pattern or use directory",
77
+ }
78
+ : {}),
79
+ });
80
+ }
81
+ // Fallback: find
82
+ const findArgs = [
83
+ searchDir,
84
+ "-maxdepth",
85
+ "10",
86
+ "-name",
87
+ pattern,
88
+ "-not",
89
+ "-path",
90
+ "*/node_modules/*",
91
+ "-not",
92
+ "-path",
93
+ "*/.git/*",
94
+ ];
95
+ const result = await execSafe("find", findArgs, {
96
+ timeout: 10000,
97
+ signal,
98
+ });
99
+ const files = result.stdout
100
+ .split("\n")
101
+ .filter(Boolean)
102
+ .map((f) => makeRelative(f, workspace))
103
+ .slice(0, 100);
104
+ const truncated = files.length === 100;
105
+ return success({
106
+ files,
107
+ count: files.length,
108
+ tool: "find",
109
+ ...(truncated
110
+ ? {
111
+ truncated: true,
112
+ note: "Result limit reached — narrow pattern or use directory",
113
+ }
114
+ : {}),
115
+ });
116
+ },
117
+ };
118
+ }
119
+ //# sourceMappingURL=findFiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findFiles.js","sourceRoot":"","sources":["../../src/tools/findFiles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { type ExtensionClient } from "../extensionClient.js";
2
+ import type { ProbeResults } from "../probe.js";
3
+ export declare function createFixAllLintErrorsTool(workspace: string, probes: ProbeResults, extensionClient: ExtensionClient): {
4
+ schema: {
5
+ name: string;
6
+ description: string;
7
+ annotations: {
8
+ destructiveHint: boolean;
9
+ idempotentHint: boolean;
10
+ };
11
+ inputSchema: {
12
+ type: "object";
13
+ properties: {
14
+ filePath: {
15
+ type: string;
16
+ description: string;
17
+ };
18
+ };
19
+ required: string[];
20
+ additionalProperties: false;
21
+ };
22
+ };
23
+ handler: (args: Record<string, unknown>, signal?: AbortSignal) => Promise<{
24
+ content: Array<{
25
+ type: string;
26
+ text: string;
27
+ }>;
28
+ }>;
29
+ };
@@ -0,0 +1,114 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { ExtensionTimeoutError, } from "../extensionClient.js";
4
+ import { error, execSafe, requireString, resolveFilePath, success, } from "./utils.js";
5
+ const JS_FIXERS = [
6
+ { cmd: "eslint", args: (f) => ["--fix", f], probe: "eslint" },
7
+ { cmd: "biome", args: (f) => ["check", "--write", f], probe: "biome" },
8
+ ];
9
+ const PY_FIXERS = [
10
+ { cmd: "ruff", args: (f) => ["check", "--fix", f], probe: "ruff" },
11
+ ];
12
+ const EXT_FIXERS = {
13
+ ".ts": JS_FIXERS,
14
+ ".tsx": JS_FIXERS,
15
+ ".js": JS_FIXERS,
16
+ ".jsx": JS_FIXERS,
17
+ ".py": PY_FIXERS,
18
+ };
19
+ export function createFixAllLintErrorsTool(workspace, probes, extensionClient) {
20
+ return {
21
+ schema: {
22
+ name: "fixAllLintErrors",
23
+ description: "Auto-fix all lint errors in a file. Uses VS Code's source.fixAll action when the extension is connected, or falls back to CLI tools (eslint --fix, biome check --write, ruff check --fix). Returns a summary of changes.",
24
+ annotations: { destructiveHint: true, idempotentHint: true },
25
+ inputSchema: {
26
+ type: "object",
27
+ properties: {
28
+ filePath: {
29
+ type: "string",
30
+ description: "Path to the file to fix (relative to workspace or absolute)",
31
+ },
32
+ },
33
+ required: ["filePath"],
34
+ additionalProperties: false,
35
+ },
36
+ },
37
+ handler: async (args, signal) => {
38
+ const rawPath = requireString(args, "filePath");
39
+ const resolved = resolveFilePath(rawPath, workspace);
40
+ let contentBefore;
41
+ try {
42
+ contentBefore = fs.readFileSync(resolved, "utf-8");
43
+ }
44
+ catch {
45
+ return error({ error: `File not found: ${rawPath}` });
46
+ }
47
+ // Try extension first
48
+ if (extensionClient.isConnected()) {
49
+ try {
50
+ const result = await extensionClient.fixAllLintErrors(resolved);
51
+ if (result !== null) {
52
+ const contentAfter = fs.readFileSync(resolved, "utf-8");
53
+ return success({
54
+ fixed: true,
55
+ source: "extension",
56
+ changes: contentBefore === contentAfter ? "none" : "modified",
57
+ linesBeforeCount: contentBefore.split("\n").length,
58
+ linesAfterCount: contentAfter.split("\n").length,
59
+ });
60
+ }
61
+ }
62
+ catch (err) {
63
+ if (!(err instanceof ExtensionTimeoutError))
64
+ throw err;
65
+ // Timeout — fall through to CLI fallback
66
+ }
67
+ }
68
+ // CLI fallback
69
+ const ext = path.extname(resolved).toLowerCase();
70
+ const candidates = EXT_FIXERS[ext];
71
+ if (!candidates || candidates.length === 0) {
72
+ return error({
73
+ fixed: false,
74
+ source: "cli",
75
+ error: `No lint fixer configured for extension "${ext}"`,
76
+ });
77
+ }
78
+ const fixer = candidates.find((f) => probes[f.probe]);
79
+ if (!fixer) {
80
+ const names = candidates.map((f) => f.cmd).join(", ");
81
+ return error({
82
+ fixed: false,
83
+ source: "cli",
84
+ error: `No available lint fixer found. Tried: ${names}`,
85
+ });
86
+ }
87
+ const result = await execSafe(fixer.cmd, fixer.args(resolved), {
88
+ cwd: workspace,
89
+ timeout: 30_000,
90
+ signal,
91
+ });
92
+ if (result.exitCode !== 0) {
93
+ return error({
94
+ fixed: false,
95
+ source: "cli",
96
+ fixerUsed: fixer.cmd,
97
+ error: result.stderr,
98
+ });
99
+ }
100
+ const contentAfter = fs.readFileSync(resolved, "utf-8");
101
+ return success({
102
+ fixed: true,
103
+ source: "cli",
104
+ fixerUsed: fixer.cmd,
105
+ changes: contentBefore === contentAfter ? "none" : "modified",
106
+ linesBeforeCount: contentBefore.split("\n").length,
107
+ linesAfterCount: contentAfter.split("\n").length,
108
+ stdout: result.stdout,
109
+ stderr: result.stderr,
110
+ });
111
+ },
112
+ };
113
+ }
114
+ //# sourceMappingURL=fixAllLintErrors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixAllLintErrors.js","sourceRoot":"","sources":["../../src/tools/fixAllLintErrors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ export declare function createCheckScopeTool(workspace: string): {
2
+ schema: {
3
+ name: string;
4
+ description: string;
5
+ annotations: {
6
+ readOnlyHint: boolean;
7
+ };
8
+ inputSchema: {
9
+ type: "object";
10
+ required: string[];
11
+ properties: {
12
+ filePath: {
13
+ type: string;
14
+ description: string;
15
+ };
16
+ operation: {
17
+ type: string;
18
+ enum: string[];
19
+ description: string;
20
+ };
21
+ };
22
+ additionalProperties: false;
23
+ };
24
+ };
25
+ handler: (args: Record<string, unknown>) => Promise<{
26
+ content: Array<{
27
+ type: string;
28
+ text: string;
29
+ }>;
30
+ }>;
31
+ };
32
+ export declare function createExpandScopeTool(workspace: string): {
33
+ schema: {
34
+ name: string;
35
+ description: string;
36
+ inputSchema: {
37
+ type: "object";
38
+ required: string[];
39
+ properties: {
40
+ entries: {
41
+ type: string;
42
+ items: {
43
+ type: string;
44
+ };
45
+ description: string;
46
+ };
47
+ fileName: {
48
+ type: string;
49
+ description: string;
50
+ };
51
+ };
52
+ additionalProperties: false;
53
+ };
54
+ };
55
+ handler: (args: Record<string, unknown>) => Promise<{
56
+ content: Array<{
57
+ type: string;
58
+ text: string;
59
+ }>;
60
+ }>;
61
+ };
@@ -0,0 +1,311 @@
1
+ import fsp from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { error, optionalString, requireString, resolveFilePath, success, } from "./utils.js";
4
+ function parseScopeSection(lines) {
5
+ const entries = [];
6
+ for (const line of lines) {
7
+ const match = line.match(/^- (.+)/);
8
+ if (!match)
9
+ continue;
10
+ let pattern = match[1]?.trim();
11
+ if (!pattern)
12
+ continue;
13
+ const isNegation = pattern.startsWith("!");
14
+ if (isNegation)
15
+ pattern = pattern.slice(1);
16
+ entries.push({
17
+ pattern,
18
+ isDirectory: pattern.endsWith("/"),
19
+ isGlob: pattern.includes("*"),
20
+ isNegation,
21
+ });
22
+ }
23
+ return entries;
24
+ }
25
+ function matchesScopeEntry(relativePath, entry) {
26
+ if (entry.isGlob)
27
+ return matchesGlob(relativePath, entry.pattern);
28
+ if (entry.isDirectory) {
29
+ return (relativePath.startsWith(entry.pattern) ||
30
+ relativePath.startsWith(entry.pattern.slice(0, -1)));
31
+ }
32
+ return relativePath === entry.pattern;
33
+ }
34
+ function extractImplicitPaths(content) {
35
+ const paths = new Set();
36
+ // Backtick-wrapped paths
37
+ const backtickRegex = /`([\w./-]+(?:\.\w+)?)`/g;
38
+ let m;
39
+ while ((m = backtickRegex.exec(content)) !== null) {
40
+ const p = m[1];
41
+ if (p.includes("/") || p.includes("."))
42
+ paths.add(p);
43
+ }
44
+ // Bare path-like mentions (word/word.ext or word/word/)
45
+ const bareRegex = /(?:^|\s)((?:[\w-]+\/)+[\w.-]+)/gm;
46
+ while ((m = bareRegex.exec(content)) !== null) {
47
+ paths.add(m[1]);
48
+ }
49
+ return [...paths];
50
+ }
51
+ function matchesGlob(filePath, pattern) {
52
+ // Guard against ReDoS: reject overly complex patterns
53
+ if (pattern.length > 200)
54
+ return false;
55
+ if ((pattern.match(/\*/g) || []).length > 10)
56
+ return false;
57
+ // Collapse consecutive * (same fix as minimatch 10.2.1 for CVE-2026-27904)
58
+ const collapsed = pattern.replace(/\*{3,}/g, "**");
59
+ // Simple glob matching: ** matches any path segments, * matches within segment
60
+ const regexStr = collapsed
61
+ .replace(/[.+^${}()|[\]\\?]/g, "\\$&")
62
+ .replace(/\*\*/g, "§§")
63
+ .replace(/\*/g, "[^/]*")
64
+ .replace(/§§/g, ".*");
65
+ return new RegExp(`^${regexStr}$`).test(filePath);
66
+ }
67
+ export function createCheckScopeTool(workspace) {
68
+ return {
69
+ schema: {
70
+ name: "checkScope",
71
+ description: "Check whether a file path and operation are in-scope for the active plan (.claude-plan.md). Advisory only — returns scope status and suggested action.",
72
+ annotations: { readOnlyHint: true },
73
+ inputSchema: {
74
+ type: "object",
75
+ required: ["filePath"],
76
+ properties: {
77
+ filePath: {
78
+ type: "string",
79
+ description: "File path to check (absolute or relative to workspace)",
80
+ },
81
+ operation: {
82
+ type: "string",
83
+ enum: ["read", "write", "delete", "create"],
84
+ description: "Type of operation being considered. Default: 'write'",
85
+ },
86
+ },
87
+ additionalProperties: false,
88
+ },
89
+ },
90
+ handler: async (args) => {
91
+ const rawPath = requireString(args, "filePath");
92
+ const operation = optionalString(args, "operation") ?? "write";
93
+ const resolved = resolveFilePath(rawPath, workspace);
94
+ const relativePath = path.relative(workspace, resolved);
95
+ // Try to read the plan file
96
+ const planPath = path.join(workspace, ".claude-plan.md");
97
+ if (!(await fsp.access(planPath).then(() => true, () => false))) {
98
+ return success({
99
+ planFound: false,
100
+ inScope: true,
101
+ reason: "No active plan found — all operations permitted",
102
+ suggestedAction: "proceed",
103
+ scopeSection: false,
104
+ });
105
+ }
106
+ const content = await fsp.readFile(planPath, "utf-8");
107
+ // Read operations are always in scope
108
+ if (operation === "read") {
109
+ return success({
110
+ planFound: true,
111
+ inScope: true,
112
+ reason: "Read operations are always in scope",
113
+ suggestedAction: "proceed",
114
+ scopeSection: false,
115
+ });
116
+ }
117
+ // Parse ## Scope section
118
+ const lines = content.split("\n");
119
+ let inScopeSection = false;
120
+ const scopeLines = [];
121
+ for (const line of lines) {
122
+ if (line.match(/^## Scope/i)) {
123
+ inScopeSection = true;
124
+ continue;
125
+ }
126
+ if (inScopeSection && line.match(/^## /))
127
+ break;
128
+ if (inScopeSection)
129
+ scopeLines.push(line);
130
+ }
131
+ const hasExplicitScope = scopeLines.length > 0;
132
+ const scopeEntries = parseScopeSection(scopeLines);
133
+ const implicitPaths = extractImplicitPaths(content);
134
+ // Check explicit scope entries
135
+ if (hasExplicitScope) {
136
+ // Check negations first — if a negation matches, block immediately
137
+ for (const entry of scopeEntries) {
138
+ if (entry.isNegation && matchesScopeEntry(relativePath, entry)) {
139
+ return success({
140
+ planFound: true,
141
+ inScope: false,
142
+ reason: `Excluded by negation pattern: !${entry.pattern}`,
143
+ suggestedAction: "block",
144
+ scopeSection: true,
145
+ });
146
+ }
147
+ }
148
+ // Check positive scope entries
149
+ for (const entry of scopeEntries) {
150
+ if (entry.isNegation)
151
+ continue;
152
+ if (matchesScopeEntry(relativePath, entry)) {
153
+ const reason = entry.isGlob
154
+ ? `Matches scope glob pattern: ${entry.pattern}`
155
+ : entry.isDirectory
156
+ ? `Within scoped directory: ${entry.pattern}`
157
+ : `Exact match in scope: ${entry.pattern}`;
158
+ return success({
159
+ planFound: true,
160
+ inScope: true,
161
+ reason,
162
+ suggestedAction: "proceed",
163
+ scopeSection: true,
164
+ });
165
+ }
166
+ }
167
+ // Check if it's in a mentioned directory but not explicitly scoped
168
+ for (const p of implicitPaths) {
169
+ if (relativePath === p || relativePath.startsWith(`${p}/`)) {
170
+ return success({
171
+ planFound: true,
172
+ inScope: true,
173
+ reason: `Mentioned in plan body but not in explicit Scope section: ${p}`,
174
+ suggestedAction: "warn",
175
+ scopeSection: true,
176
+ });
177
+ }
178
+ }
179
+ const positiveEntries = scopeEntries.filter((e) => !e.isNegation);
180
+ return success({
181
+ planFound: true,
182
+ inScope: false,
183
+ reason: `Not matched by any Scope entry. Scoped to: ${positiveEntries.map((e) => e.pattern).join(", ")}`,
184
+ suggestedAction: "block",
185
+ scopeSection: true,
186
+ });
187
+ }
188
+ // No explicit scope — use implicit mentions
189
+ for (const p of implicitPaths) {
190
+ if (relativePath === p || relativePath.startsWith(`${p}/`)) {
191
+ return success({
192
+ planFound: true,
193
+ inScope: true,
194
+ reason: `Mentioned in plan: ${p}`,
195
+ suggestedAction: "proceed",
196
+ scopeSection: false,
197
+ });
198
+ }
199
+ }
200
+ // Check if any implicit path shares a directory prefix
201
+ const relativeDir = path.dirname(relativePath);
202
+ for (const p of implicitPaths) {
203
+ const pDir = path.dirname(p);
204
+ if (relativeDir === pDir || relativeDir.startsWith(`${pDir}/`)) {
205
+ return success({
206
+ planFound: true,
207
+ inScope: true,
208
+ reason: `In same directory as plan-mentioned file: ${p}`,
209
+ suggestedAction: "proceed",
210
+ scopeSection: false,
211
+ });
212
+ }
213
+ }
214
+ return success({
215
+ planFound: true,
216
+ inScope: false,
217
+ reason: "File not mentioned in plan",
218
+ suggestedAction: "warn",
219
+ scopeSection: false,
220
+ });
221
+ },
222
+ };
223
+ }
224
+ export function createExpandScopeTool(workspace) {
225
+ return {
226
+ schema: {
227
+ name: "expandScope",
228
+ description: "Add entries to the ## Scope section of the active plan (.claude-plan.md). Creates the section if it doesn't exist.",
229
+ inputSchema: {
230
+ type: "object",
231
+ required: ["entries"],
232
+ properties: {
233
+ entries: {
234
+ type: "array",
235
+ items: { type: "string" },
236
+ description: "Scope entries to add (e.g., 'src/utils/', '!dist/', '**/*.test.ts')",
237
+ },
238
+ fileName: {
239
+ type: "string",
240
+ description: "Plan filename (default: .claude-plan.md)",
241
+ },
242
+ },
243
+ additionalProperties: false,
244
+ },
245
+ },
246
+ handler: async (args) => {
247
+ const rawEntries = args.entries;
248
+ if (!Array.isArray(rawEntries) || rawEntries.length === 0) {
249
+ return error("entries must be a non-empty array of strings");
250
+ }
251
+ if (rawEntries.length > 100) {
252
+ return error("Maximum 100 scope entries allowed at once");
253
+ }
254
+ const entries = rawEntries
255
+ .filter((e) => typeof e === "string")
256
+ .map((e) => e.replace(/[\n\r]/g, "").trim())
257
+ .filter((e) => e.length > 0 && e.length <= 200);
258
+ if (entries.length === 0) {
259
+ return error("No valid entries provided");
260
+ }
261
+ const fileName = optionalString(args, "fileName") ?? ".claude-plan.md";
262
+ const planPath = resolveFilePath(fileName, workspace);
263
+ if (!(await fsp.access(planPath).then(() => true, () => false))) {
264
+ return error(`Plan file "${fileName}" not found. Use createPlan to create one.`);
265
+ }
266
+ const content = await fsp.readFile(planPath, "utf-8");
267
+ const lines = content.split("\n");
268
+ // Find ## Scope section
269
+ let scopeStart = -1;
270
+ let scopeEnd = lines.length;
271
+ for (let i = 0; i < lines.length; i++) {
272
+ if (lines[i]?.match(/^## Scope/i)) {
273
+ scopeStart = i;
274
+ for (let j = i + 1; j < lines.length; j++) {
275
+ if (lines[j]?.match(/^## /)) {
276
+ scopeEnd = j;
277
+ break;
278
+ }
279
+ }
280
+ break;
281
+ }
282
+ }
283
+ const newLines = entries.map((e) => `- ${e.trim()}`);
284
+ if (scopeStart === -1) {
285
+ // No Scope section — insert after frontmatter
286
+ let insertAt = 0;
287
+ if (lines[0]?.trim() === "---") {
288
+ for (let i = 1; i < lines.length; i++) {
289
+ if (lines[i]?.trim() === "---") {
290
+ insertAt = i + 1;
291
+ break;
292
+ }
293
+ }
294
+ }
295
+ const section = ["", "## Scope", "", ...newLines, ""];
296
+ lines.splice(insertAt, 0, ...section);
297
+ }
298
+ else {
299
+ // Insert before the next section (or end)
300
+ lines.splice(scopeEnd, 0, ...newLines);
301
+ }
302
+ await fsp.writeFile(planPath, lines.join("\n"), "utf-8");
303
+ return success({
304
+ expanded: true,
305
+ entriesAdded: entries.length,
306
+ entries,
307
+ });
308
+ },
309
+ };
310
+ }
311
+ //# sourceMappingURL=flowGuardian.js.map