mstro-app 0.4.3 → 0.4.10

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 (306) hide show
  1. package/dist/server/cli/headless/claude-invoker-process.d.ts +11 -0
  2. package/dist/server/cli/headless/claude-invoker-process.d.ts.map +1 -0
  3. package/dist/server/cli/headless/claude-invoker-process.js +140 -0
  4. package/dist/server/cli/headless/claude-invoker-process.js.map +1 -0
  5. package/dist/server/cli/headless/claude-invoker-stall.d.ts +40 -0
  6. package/dist/server/cli/headless/claude-invoker-stall.d.ts.map +1 -0
  7. package/dist/server/cli/headless/claude-invoker-stall.js +98 -0
  8. package/dist/server/cli/headless/claude-invoker-stall.js.map +1 -0
  9. package/dist/server/cli/headless/claude-invoker-stream.d.ts +44 -0
  10. package/dist/server/cli/headless/claude-invoker-stream.d.ts.map +1 -0
  11. package/dist/server/cli/headless/claude-invoker-stream.js +276 -0
  12. package/dist/server/cli/headless/claude-invoker-stream.js.map +1 -0
  13. package/dist/server/cli/headless/claude-invoker-tools.d.ts +21 -0
  14. package/dist/server/cli/headless/claude-invoker-tools.d.ts.map +1 -0
  15. package/dist/server/cli/headless/claude-invoker-tools.js +137 -0
  16. package/dist/server/cli/headless/claude-invoker-tools.js.map +1 -0
  17. package/dist/server/cli/headless/claude-invoker.d.ts +6 -4
  18. package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
  19. package/dist/server/cli/headless/claude-invoker.js +10 -807
  20. package/dist/server/cli/headless/claude-invoker.js.map +1 -1
  21. package/dist/server/cli/headless/haiku-assessments.d.ts +62 -0
  22. package/dist/server/cli/headless/haiku-assessments.d.ts.map +1 -0
  23. package/dist/server/cli/headless/haiku-assessments.js +281 -0
  24. package/dist/server/cli/headless/haiku-assessments.js.map +1 -0
  25. package/dist/server/cli/headless/headless-logger.d.ts +3 -2
  26. package/dist/server/cli/headless/headless-logger.d.ts.map +1 -1
  27. package/dist/server/cli/headless/headless-logger.js +28 -5
  28. package/dist/server/cli/headless/headless-logger.js.map +1 -1
  29. package/dist/server/cli/headless/native-timeout-detector.d.ts +44 -0
  30. package/dist/server/cli/headless/native-timeout-detector.d.ts.map +1 -0
  31. package/dist/server/cli/headless/native-timeout-detector.js +99 -0
  32. package/dist/server/cli/headless/native-timeout-detector.js.map +1 -0
  33. package/dist/server/cli/headless/stall-assessor.d.ts +2 -110
  34. package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
  35. package/dist/server/cli/headless/stall-assessor.js +65 -457
  36. package/dist/server/cli/headless/stall-assessor.js.map +1 -1
  37. package/dist/server/cli/improvisation-attachments.d.ts +21 -0
  38. package/dist/server/cli/improvisation-attachments.d.ts.map +1 -0
  39. package/dist/server/cli/improvisation-attachments.js +116 -0
  40. package/dist/server/cli/improvisation-attachments.js.map +1 -0
  41. package/dist/server/cli/improvisation-retry.d.ts +52 -0
  42. package/dist/server/cli/improvisation-retry.d.ts.map +1 -0
  43. package/dist/server/cli/improvisation-retry.js +434 -0
  44. package/dist/server/cli/improvisation-retry.js.map +1 -0
  45. package/dist/server/cli/improvisation-session-manager.d.ts +10 -266
  46. package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
  47. package/dist/server/cli/improvisation-session-manager.js +117 -1079
  48. package/dist/server/cli/improvisation-session-manager.js.map +1 -1
  49. package/dist/server/cli/improvisation-types.d.ts +86 -0
  50. package/dist/server/cli/improvisation-types.d.ts.map +1 -0
  51. package/dist/server/cli/improvisation-types.js +10 -0
  52. package/dist/server/cli/improvisation-types.js.map +1 -0
  53. package/dist/server/cli/prompt-builders.d.ts +68 -0
  54. package/dist/server/cli/prompt-builders.d.ts.map +1 -0
  55. package/dist/server/cli/prompt-builders.js +312 -0
  56. package/dist/server/cli/prompt-builders.js.map +1 -0
  57. package/dist/server/index.js +33 -212
  58. package/dist/server/index.js.map +1 -1
  59. package/dist/server/mcp/bouncer-haiku.d.ts +10 -0
  60. package/dist/server/mcp/bouncer-haiku.d.ts.map +1 -0
  61. package/dist/server/mcp/bouncer-haiku.js +152 -0
  62. package/dist/server/mcp/bouncer-haiku.js.map +1 -0
  63. package/dist/server/mcp/bouncer-integration.d.ts +3 -4
  64. package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
  65. package/dist/server/mcp/bouncer-integration.js +50 -196
  66. package/dist/server/mcp/bouncer-integration.js.map +1 -1
  67. package/dist/server/mcp/security-analysis.d.ts +38 -0
  68. package/dist/server/mcp/security-analysis.d.ts.map +1 -0
  69. package/dist/server/mcp/security-analysis.js +183 -0
  70. package/dist/server/mcp/security-analysis.js.map +1 -0
  71. package/dist/server/mcp/security-audit.d.ts +1 -1
  72. package/dist/server/mcp/security-audit.d.ts.map +1 -1
  73. package/dist/server/mcp/security-patterns.d.ts +1 -25
  74. package/dist/server/mcp/security-patterns.d.ts.map +1 -1
  75. package/dist/server/mcp/security-patterns.js +55 -260
  76. package/dist/server/mcp/security-patterns.js.map +1 -1
  77. package/dist/server/server-setup.d.ts +22 -0
  78. package/dist/server/server-setup.d.ts.map +1 -0
  79. package/dist/server/server-setup.js +101 -0
  80. package/dist/server/server-setup.js.map +1 -0
  81. package/dist/server/services/file-explorer-ops.d.ts +24 -0
  82. package/dist/server/services/file-explorer-ops.d.ts.map +1 -0
  83. package/dist/server/services/file-explorer-ops.js +211 -0
  84. package/dist/server/services/file-explorer-ops.js.map +1 -0
  85. package/dist/server/services/files.d.ts +2 -85
  86. package/dist/server/services/files.d.ts.map +1 -1
  87. package/dist/server/services/files.js +7 -427
  88. package/dist/server/services/files.js.map +1 -1
  89. package/dist/server/services/plan/composer.d.ts.map +1 -1
  90. package/dist/server/services/plan/composer.js +2 -1
  91. package/dist/server/services/plan/composer.js.map +1 -1
  92. package/dist/server/services/plan/executor.d.ts.map +1 -1
  93. package/dist/server/services/plan/executor.js +3 -1
  94. package/dist/server/services/plan/executor.js.map +1 -1
  95. package/dist/server/services/plan/parser-core.d.ts +20 -0
  96. package/dist/server/services/plan/parser-core.d.ts.map +1 -0
  97. package/dist/server/services/plan/parser-core.js +350 -0
  98. package/dist/server/services/plan/parser-core.js.map +1 -0
  99. package/dist/server/services/plan/parser-migration.d.ts +5 -0
  100. package/dist/server/services/plan/parser-migration.d.ts.map +1 -0
  101. package/dist/server/services/plan/parser-migration.js +124 -0
  102. package/dist/server/services/plan/parser-migration.js.map +1 -0
  103. package/dist/server/services/plan/parser.d.ts +0 -8
  104. package/dist/server/services/plan/parser.d.ts.map +1 -1
  105. package/dist/server/services/plan/parser.js +50 -569
  106. package/dist/server/services/plan/parser.js.map +1 -1
  107. package/dist/server/services/plan/review-gate.d.ts +2 -0
  108. package/dist/server/services/plan/review-gate.d.ts.map +1 -1
  109. package/dist/server/services/plan/review-gate.js +2 -2
  110. package/dist/server/services/plan/review-gate.js.map +1 -1
  111. package/dist/server/services/plan/types.d.ts +2 -0
  112. package/dist/server/services/plan/types.d.ts.map +1 -1
  113. package/dist/server/services/platform-credentials.d.ts +24 -0
  114. package/dist/server/services/platform-credentials.d.ts.map +1 -0
  115. package/dist/server/services/platform-credentials.js +68 -0
  116. package/dist/server/services/platform-credentials.js.map +1 -0
  117. package/dist/server/services/platform.d.ts +1 -31
  118. package/dist/server/services/platform.d.ts.map +1 -1
  119. package/dist/server/services/platform.js +10 -119
  120. package/dist/server/services/platform.js.map +1 -1
  121. package/dist/server/services/terminal/pty-manager.d.ts +7 -97
  122. package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
  123. package/dist/server/services/terminal/pty-manager.js +53 -266
  124. package/dist/server/services/terminal/pty-manager.js.map +1 -1
  125. package/dist/server/services/terminal/pty-utils.d.ts +57 -0
  126. package/dist/server/services/terminal/pty-utils.d.ts.map +1 -0
  127. package/dist/server/services/terminal/pty-utils.js +141 -0
  128. package/dist/server/services/terminal/pty-utils.js.map +1 -0
  129. package/dist/server/services/websocket/file-definition-handlers.d.ts +4 -0
  130. package/dist/server/services/websocket/file-definition-handlers.d.ts.map +1 -0
  131. package/dist/server/services/websocket/file-definition-handlers.js +153 -0
  132. package/dist/server/services/websocket/file-definition-handlers.js.map +1 -0
  133. package/dist/server/services/websocket/file-explorer-handlers.d.ts.map +1 -1
  134. package/dist/server/services/websocket/file-explorer-handlers.js +52 -391
  135. package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
  136. package/dist/server/services/websocket/file-search-handlers.d.ts +5 -0
  137. package/dist/server/services/websocket/file-search-handlers.d.ts.map +1 -0
  138. package/dist/server/services/websocket/file-search-handlers.js +238 -0
  139. package/dist/server/services/websocket/file-search-handlers.js.map +1 -0
  140. package/dist/server/services/websocket/file-utils.js +3 -3
  141. package/dist/server/services/websocket/file-utils.js.map +1 -1
  142. package/dist/server/services/websocket/git-branch-handlers.d.ts +7 -0
  143. package/dist/server/services/websocket/git-branch-handlers.d.ts.map +1 -0
  144. package/dist/server/services/websocket/git-branch-handlers.js +110 -0
  145. package/dist/server/services/websocket/git-branch-handlers.js.map +1 -0
  146. package/dist/server/services/websocket/git-diff-handlers.d.ts +6 -0
  147. package/dist/server/services/websocket/git-diff-handlers.d.ts.map +1 -0
  148. package/dist/server/services/websocket/git-diff-handlers.js +123 -0
  149. package/dist/server/services/websocket/git-diff-handlers.js.map +1 -0
  150. package/dist/server/services/websocket/git-handlers.d.ts +2 -31
  151. package/dist/server/services/websocket/git-handlers.d.ts.map +1 -1
  152. package/dist/server/services/websocket/git-handlers.js +35 -541
  153. package/dist/server/services/websocket/git-handlers.js.map +1 -1
  154. package/dist/server/services/websocket/git-log-handlers.d.ts +6 -0
  155. package/dist/server/services/websocket/git-log-handlers.d.ts.map +1 -0
  156. package/dist/server/services/websocket/git-log-handlers.js +128 -0
  157. package/dist/server/services/websocket/git-log-handlers.js.map +1 -0
  158. package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -1
  159. package/dist/server/services/websocket/git-pr-handlers.js +13 -53
  160. package/dist/server/services/websocket/git-pr-handlers.js.map +1 -1
  161. package/dist/server/services/websocket/git-tag-handlers.d.ts +6 -0
  162. package/dist/server/services/websocket/git-tag-handlers.d.ts.map +1 -0
  163. package/dist/server/services/websocket/git-tag-handlers.js +76 -0
  164. package/dist/server/services/websocket/git-tag-handlers.js.map +1 -0
  165. package/dist/server/services/websocket/git-utils.d.ts +43 -0
  166. package/dist/server/services/websocket/git-utils.d.ts.map +1 -0
  167. package/dist/server/services/websocket/git-utils.js +201 -0
  168. package/dist/server/services/websocket/git-utils.js.map +1 -0
  169. package/dist/server/services/websocket/handler.d.ts +2 -0
  170. package/dist/server/services/websocket/handler.d.ts.map +1 -1
  171. package/dist/server/services/websocket/handler.js +37 -126
  172. package/dist/server/services/websocket/handler.js.map +1 -1
  173. package/dist/server/services/websocket/plan-board-handlers.d.ts +11 -0
  174. package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -0
  175. package/dist/server/services/websocket/plan-board-handlers.js +218 -0
  176. package/dist/server/services/websocket/plan-board-handlers.js.map +1 -0
  177. package/dist/server/services/websocket/plan-execution-handlers.d.ts +9 -0
  178. package/dist/server/services/websocket/plan-execution-handlers.d.ts.map +1 -0
  179. package/dist/server/services/websocket/plan-execution-handlers.js +142 -0
  180. package/dist/server/services/websocket/plan-execution-handlers.js.map +1 -0
  181. package/dist/server/services/websocket/plan-handlers.d.ts +7 -2
  182. package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -1
  183. package/dist/server/services/websocket/plan-handlers.js +6 -925
  184. package/dist/server/services/websocket/plan-handlers.js.map +1 -1
  185. package/dist/server/services/websocket/plan-helpers.d.ts +19 -0
  186. package/dist/server/services/websocket/plan-helpers.d.ts.map +1 -0
  187. package/dist/server/services/websocket/plan-helpers.js +199 -0
  188. package/dist/server/services/websocket/plan-helpers.js.map +1 -0
  189. package/dist/server/services/websocket/plan-issue-handlers.d.ts +12 -0
  190. package/dist/server/services/websocket/plan-issue-handlers.d.ts.map +1 -0
  191. package/dist/server/services/websocket/plan-issue-handlers.js +162 -0
  192. package/dist/server/services/websocket/plan-issue-handlers.js.map +1 -0
  193. package/dist/server/services/websocket/plan-sprint-handlers.d.ts +7 -0
  194. package/dist/server/services/websocket/plan-sprint-handlers.d.ts.map +1 -0
  195. package/dist/server/services/websocket/plan-sprint-handlers.js +206 -0
  196. package/dist/server/services/websocket/plan-sprint-handlers.js.map +1 -0
  197. package/dist/server/services/websocket/quality-complexity.d.ts +14 -0
  198. package/dist/server/services/websocket/quality-complexity.d.ts.map +1 -0
  199. package/dist/server/services/websocket/quality-complexity.js +262 -0
  200. package/dist/server/services/websocket/quality-complexity.js.map +1 -0
  201. package/dist/server/services/websocket/quality-fix-agent.d.ts +16 -0
  202. package/dist/server/services/websocket/quality-fix-agent.d.ts.map +1 -0
  203. package/dist/server/services/websocket/quality-fix-agent.js +140 -0
  204. package/dist/server/services/websocket/quality-fix-agent.js.map +1 -0
  205. package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
  206. package/dist/server/services/websocket/quality-handlers.js +34 -346
  207. package/dist/server/services/websocket/quality-handlers.js.map +1 -1
  208. package/dist/server/services/websocket/quality-linting.d.ts +9 -0
  209. package/dist/server/services/websocket/quality-linting.d.ts.map +1 -0
  210. package/dist/server/services/websocket/quality-linting.js +178 -0
  211. package/dist/server/services/websocket/quality-linting.js.map +1 -0
  212. package/dist/server/services/websocket/quality-review-agent.d.ts +19 -0
  213. package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -0
  214. package/dist/server/services/websocket/quality-review-agent.js +206 -0
  215. package/dist/server/services/websocket/quality-review-agent.js.map +1 -0
  216. package/dist/server/services/websocket/quality-service.d.ts +3 -51
  217. package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
  218. package/dist/server/services/websocket/quality-service.js +9 -651
  219. package/dist/server/services/websocket/quality-service.js.map +1 -1
  220. package/dist/server/services/websocket/quality-tools.d.ts +23 -0
  221. package/dist/server/services/websocket/quality-tools.d.ts.map +1 -0
  222. package/dist/server/services/websocket/quality-tools.js +208 -0
  223. package/dist/server/services/websocket/quality-tools.js.map +1 -0
  224. package/dist/server/services/websocket/quality-types.d.ts +59 -0
  225. package/dist/server/services/websocket/quality-types.d.ts.map +1 -0
  226. package/dist/server/services/websocket/quality-types.js +101 -0
  227. package/dist/server/services/websocket/quality-types.js.map +1 -0
  228. package/dist/server/services/websocket/session-handlers.d.ts +3 -4
  229. package/dist/server/services/websocket/session-handlers.d.ts.map +1 -1
  230. package/dist/server/services/websocket/session-handlers.js +3 -378
  231. package/dist/server/services/websocket/session-handlers.js.map +1 -1
  232. package/dist/server/services/websocket/session-history.d.ts +4 -0
  233. package/dist/server/services/websocket/session-history.d.ts.map +1 -0
  234. package/dist/server/services/websocket/session-history.js +208 -0
  235. package/dist/server/services/websocket/session-history.js.map +1 -0
  236. package/dist/server/services/websocket/session-initialization.d.ts +5 -0
  237. package/dist/server/services/websocket/session-initialization.d.ts.map +1 -0
  238. package/dist/server/services/websocket/session-initialization.js +163 -0
  239. package/dist/server/services/websocket/session-initialization.js.map +1 -0
  240. package/dist/server/services/websocket/types.d.ts +12 -2
  241. package/dist/server/services/websocket/types.d.ts.map +1 -1
  242. package/package.json +1 -1
  243. package/server/cli/headless/claude-invoker-process.ts +204 -0
  244. package/server/cli/headless/claude-invoker-stall.ts +164 -0
  245. package/server/cli/headless/claude-invoker-stream.ts +353 -0
  246. package/server/cli/headless/claude-invoker-tools.ts +187 -0
  247. package/server/cli/headless/claude-invoker.ts +15 -1096
  248. package/server/cli/headless/haiku-assessments.ts +365 -0
  249. package/server/cli/headless/headless-logger.ts +26 -5
  250. package/server/cli/headless/native-timeout-detector.ts +117 -0
  251. package/server/cli/headless/stall-assessor.ts +65 -618
  252. package/server/cli/improvisation-attachments.ts +148 -0
  253. package/server/cli/improvisation-retry.ts +602 -0
  254. package/server/cli/improvisation-session-manager.ts +140 -1349
  255. package/server/cli/improvisation-types.ts +98 -0
  256. package/server/cli/prompt-builders.ts +370 -0
  257. package/server/index.ts +35 -246
  258. package/server/mcp/bouncer-haiku.ts +182 -0
  259. package/server/mcp/bouncer-integration.ts +87 -248
  260. package/server/mcp/security-analysis.ts +217 -0
  261. package/server/mcp/security-audit.ts +1 -1
  262. package/server/mcp/security-patterns.ts +60 -283
  263. package/server/server-setup.ts +114 -0
  264. package/server/services/file-explorer-ops.ts +293 -0
  265. package/server/services/files.ts +20 -532
  266. package/server/services/plan/composer.ts +2 -1
  267. package/server/services/plan/executor.ts +3 -1
  268. package/server/services/plan/parser-core.ts +406 -0
  269. package/server/services/plan/parser-migration.ts +128 -0
  270. package/server/services/plan/parser.ts +52 -620
  271. package/server/services/plan/review-gate.ts +4 -2
  272. package/server/services/plan/types.ts +2 -0
  273. package/server/services/platform-credentials.ts +83 -0
  274. package/server/services/platform.ts +15 -141
  275. package/server/services/terminal/pty-manager.ts +66 -313
  276. package/server/services/terminal/pty-utils.ts +176 -0
  277. package/server/services/websocket/file-definition-handlers.ts +165 -0
  278. package/server/services/websocket/file-explorer-handlers.ts +37 -452
  279. package/server/services/websocket/file-search-handlers.ts +291 -0
  280. package/server/services/websocket/file-utils.ts +3 -3
  281. package/server/services/websocket/git-branch-handlers.ts +130 -0
  282. package/server/services/websocket/git-diff-handlers.ts +140 -0
  283. package/server/services/websocket/git-handlers.ts +40 -625
  284. package/server/services/websocket/git-log-handlers.ts +149 -0
  285. package/server/services/websocket/git-pr-handlers.ts +17 -62
  286. package/server/services/websocket/git-tag-handlers.ts +91 -0
  287. package/server/services/websocket/git-utils.ts +230 -0
  288. package/server/services/websocket/handler.ts +39 -126
  289. package/server/services/websocket/plan-board-handlers.ts +277 -0
  290. package/server/services/websocket/plan-execution-handlers.ts +184 -0
  291. package/server/services/websocket/plan-handlers.ts +8 -1114
  292. package/server/services/websocket/plan-helpers.ts +215 -0
  293. package/server/services/websocket/plan-issue-handlers.ts +204 -0
  294. package/server/services/websocket/plan-sprint-handlers.ts +252 -0
  295. package/server/services/websocket/quality-complexity.ts +294 -0
  296. package/server/services/websocket/quality-fix-agent.ts +181 -0
  297. package/server/services/websocket/quality-handlers.ts +36 -404
  298. package/server/services/websocket/quality-linting.ts +187 -0
  299. package/server/services/websocket/quality-review-agent.ts +246 -0
  300. package/server/services/websocket/quality-service.ts +11 -762
  301. package/server/services/websocket/quality-tools.ts +209 -0
  302. package/server/services/websocket/quality-types.ts +169 -0
  303. package/server/services/websocket/session-handlers.ts +5 -437
  304. package/server/services/websocket/session-history.ts +222 -0
  305. package/server/services/websocket/session-initialization.ts +209 -0
  306. package/server/services/websocket/types.ts +17 -0
@@ -0,0 +1,293 @@
1
+ // Copyright (c) 2025-present Mstro, Inc. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file for details.
3
+
4
+ /**
5
+ * File Explorer Operations — CRUD for files/directories in the working directory.
6
+ * All paths are validated to prevent path traversal outside workingDir.
7
+ */
8
+
9
+ import {
10
+ existsSync,
11
+ mkdirSync,
12
+ readdirSync,
13
+ renameSync,
14
+ rmdirSync,
15
+ statSync,
16
+ unlinkSync,
17
+ writeFileSync
18
+ } from 'node:fs'
19
+ import { dirname, join } from 'node:path'
20
+ import {
21
+ containsDangerousPatterns,
22
+ validateBothPathsWithinWorkingDir,
23
+ validatePathWithinWorkingDir
24
+ } from './pathUtils.js'
25
+
26
+ export interface DirectoryEntry {
27
+ name: string
28
+ path: string
29
+ type: 'file' | 'directory'
30
+ size?: number
31
+ modifiedAt?: string
32
+ }
33
+
34
+ export interface FileOperationResult {
35
+ success: boolean
36
+ error?: string
37
+ path?: string
38
+ }
39
+
40
+ export interface ListDirectoryResult {
41
+ success: boolean
42
+ entries?: DirectoryEntry[]
43
+ error?: string
44
+ }
45
+
46
+ export function listDirectory(
47
+ dirPath: string,
48
+ workingDir: string,
49
+ showHidden: boolean = false
50
+ ): ListDirectoryResult {
51
+ if (containsDangerousPatterns(dirPath)) {
52
+ console.error(`[FileService] SECURITY: Dangerous pattern in path: "${dirPath}"`)
53
+ return { success: false, error: 'Invalid path: contains dangerous patterns' }
54
+ }
55
+
56
+ const validation = validatePathWithinWorkingDir(dirPath, workingDir)
57
+ if (!validation.valid) {
58
+ return { success: false, error: validation.error }
59
+ }
60
+
61
+ const resolvedPath = validation.resolvedPath
62
+
63
+ try {
64
+ if (!existsSync(resolvedPath)) {
65
+ return { success: false, error: 'Directory not found' }
66
+ }
67
+
68
+ const stats = statSync(resolvedPath)
69
+ if (!stats.isDirectory()) {
70
+ return { success: false, error: 'Path is not a directory' }
71
+ }
72
+
73
+ const entries = readdirSync(resolvedPath, { withFileTypes: true })
74
+ const directoryEntries: DirectoryEntry[] = entries
75
+ .filter(entry => showHidden || !entry.name.startsWith('.'))
76
+ .map(entry => {
77
+ const entryPath = join(resolvedPath, entry.name)
78
+ const isDir = entry.isDirectory()
79
+
80
+ let size: number | undefined
81
+ let modifiedAt: string | undefined
82
+ try {
83
+ const entryStats = statSync(entryPath)
84
+ modifiedAt = entryStats.mtime.toISOString()
85
+ if (!isDir) size = entryStats.size
86
+ } catch { /* skip */ }
87
+
88
+ const relativePath = entryPath.replace(`${workingDir}/`, '')
89
+ return { name: entry.name, path: relativePath, type: isDir ? 'directory' : 'file', size, modifiedAt } as DirectoryEntry
90
+ })
91
+
92
+ directoryEntries.sort((a, b) => {
93
+ if (a.type === 'directory' && b.type === 'file') return -1
94
+ if (a.type === 'file' && b.type === 'directory') return 1
95
+ return a.name.localeCompare(b.name)
96
+ })
97
+
98
+ return { success: true, entries: directoryEntries }
99
+ } catch (error: unknown) {
100
+ if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'EACCES') {
101
+ return { success: false, error: 'Permission denied' }
102
+ }
103
+ console.error('[FileService] Error listing directory:', error)
104
+ return { success: false, error: error instanceof Error ? error.message : 'Failed to list directory' }
105
+ }
106
+ }
107
+
108
+ export function writeFile(
109
+ filePath: string,
110
+ content: string,
111
+ workingDir: string
112
+ ): FileOperationResult {
113
+ if (containsDangerousPatterns(filePath)) {
114
+ console.error(`[FileService] SECURITY: Dangerous pattern in path: "${filePath}"`)
115
+ return { success: false, error: 'Invalid path: contains dangerous patterns' }
116
+ }
117
+
118
+ const validation = validatePathWithinWorkingDir(filePath, workingDir)
119
+ if (!validation.valid) {
120
+ return { success: false, error: validation.error }
121
+ }
122
+
123
+ const resolvedPath = validation.resolvedPath
124
+
125
+ try {
126
+ const parentDir = dirname(resolvedPath)
127
+ if (!existsSync(parentDir)) mkdirSync(parentDir, { recursive: true })
128
+
129
+ if (existsSync(resolvedPath)) {
130
+ const stats = statSync(resolvedPath)
131
+ if (stats.isDirectory()) {
132
+ return { success: false, error: 'Cannot write to a directory' }
133
+ }
134
+ }
135
+
136
+ writeFileSync(resolvedPath, content, 'utf-8')
137
+ return { success: true, path: resolvedPath.replace(`${workingDir}/`, '') }
138
+ } catch (error: unknown) {
139
+ console.error('[FileService] Error writing file:', error)
140
+ return { success: false, error: error instanceof Error ? error.message : 'Failed to write file' }
141
+ }
142
+ }
143
+
144
+ export function createFile(
145
+ filePath: string,
146
+ workingDir: string
147
+ ): FileOperationResult {
148
+ if (containsDangerousPatterns(filePath)) {
149
+ console.error(`[FileService] SECURITY: Dangerous pattern in path: "${filePath}"`)
150
+ return { success: false, error: 'Invalid path: contains dangerous patterns' }
151
+ }
152
+
153
+ const validation = validatePathWithinWorkingDir(filePath, workingDir)
154
+ if (!validation.valid) {
155
+ return { success: false, error: validation.error }
156
+ }
157
+
158
+ const resolvedPath = validation.resolvedPath
159
+
160
+ try {
161
+ if (existsSync(resolvedPath)) {
162
+ return { success: false, error: 'File already exists' }
163
+ }
164
+
165
+ const parentDir = dirname(resolvedPath)
166
+ if (!existsSync(parentDir)) mkdirSync(parentDir, { recursive: true })
167
+
168
+ writeFileSync(resolvedPath, '', 'utf-8')
169
+ return { success: true, path: resolvedPath.replace(`${workingDir}/`, '') }
170
+ } catch (error: unknown) {
171
+ console.error('[FileService] Error creating file:', error)
172
+ return { success: false, error: error instanceof Error ? error.message : 'Failed to create file' }
173
+ }
174
+ }
175
+
176
+ export function createDirectory(
177
+ dirPath: string,
178
+ workingDir: string
179
+ ): FileOperationResult {
180
+ if (containsDangerousPatterns(dirPath)) {
181
+ console.error(`[FileService] SECURITY: Dangerous pattern in path: "${dirPath}"`)
182
+ return { success: false, error: 'Invalid path: contains dangerous patterns' }
183
+ }
184
+
185
+ const validation = validatePathWithinWorkingDir(dirPath, workingDir)
186
+ if (!validation.valid) {
187
+ return { success: false, error: validation.error }
188
+ }
189
+
190
+ const resolvedPath = validation.resolvedPath
191
+
192
+ try {
193
+ if (existsSync(resolvedPath)) {
194
+ const stats = statSync(resolvedPath)
195
+ if (stats.isDirectory()) {
196
+ return { success: false, error: 'Directory already exists' }
197
+ }
198
+ return { success: false, error: 'A file with that name already exists' }
199
+ }
200
+
201
+ mkdirSync(resolvedPath, { recursive: true })
202
+ return { success: true, path: resolvedPath.replace(`${workingDir}/`, '') }
203
+ } catch (error: unknown) {
204
+ console.error('[FileService] Error creating directory:', error)
205
+ return { success: false, error: error instanceof Error ? error.message : 'Failed to create directory' }
206
+ }
207
+ }
208
+
209
+ export function deleteFile(
210
+ targetPath: string,
211
+ workingDir: string
212
+ ): FileOperationResult {
213
+ if (containsDangerousPatterns(targetPath)) {
214
+ console.error(`[FileService] SECURITY: Dangerous pattern in path: "${targetPath}"`)
215
+ return { success: false, error: 'Invalid path: contains dangerous patterns' }
216
+ }
217
+
218
+ const validation = validatePathWithinWorkingDir(targetPath, workingDir)
219
+ if (!validation.valid) {
220
+ return { success: false, error: validation.error }
221
+ }
222
+
223
+ const resolvedPath = validation.resolvedPath
224
+
225
+ if (resolvedPath === workingDir || resolvedPath === `${workingDir}/`) {
226
+ console.error(`[FileService] SECURITY: Attempted to delete working directory: "${resolvedPath}"`)
227
+ return { success: false, error: 'Cannot delete the working directory' }
228
+ }
229
+
230
+ try {
231
+ if (!existsSync(resolvedPath)) {
232
+ return { success: false, error: 'File or directory not found' }
233
+ }
234
+
235
+ const stats = statSync(resolvedPath)
236
+
237
+ if (stats.isDirectory()) {
238
+ const contents = readdirSync(resolvedPath)
239
+ if (contents.length > 0) {
240
+ return { success: false, error: 'Directory is not empty. Only empty directories can be deleted.' }
241
+ }
242
+ rmdirSync(resolvedPath)
243
+ } else {
244
+ unlinkSync(resolvedPath)
245
+ }
246
+
247
+ return { success: true, path: resolvedPath.replace(`${workingDir}/`, '') }
248
+ } catch (error: unknown) {
249
+ console.error('[FileService] Error deleting file:', error)
250
+ return { success: false, error: error instanceof Error ? error.message : 'Failed to delete' }
251
+ }
252
+ }
253
+
254
+ export function renameFile(
255
+ oldPath: string,
256
+ newPath: string,
257
+ workingDir: string
258
+ ): FileOperationResult {
259
+ if (containsDangerousPatterns(oldPath)) {
260
+ console.error(`[FileService] SECURITY: Dangerous pattern in source path: "${oldPath}"`)
261
+ return { success: false, error: 'Invalid source path: contains dangerous patterns' }
262
+ }
263
+ if (containsDangerousPatterns(newPath)) {
264
+ console.error(`[FileService] SECURITY: Dangerous pattern in destination path: "${newPath}"`)
265
+ return { success: false, error: 'Invalid destination path: contains dangerous patterns' }
266
+ }
267
+
268
+ const validation = validateBothPathsWithinWorkingDir(oldPath, newPath, workingDir)
269
+ if (!validation.valid) {
270
+ return { success: false, error: validation.error }
271
+ }
272
+
273
+ const resolvedOldPath = validation.resolvedSourcePath
274
+ const resolvedNewPath = validation.resolvedDestPath
275
+
276
+ try {
277
+ if (!existsSync(resolvedOldPath)) {
278
+ return { success: false, error: 'Source file or directory not found' }
279
+ }
280
+ if (existsSync(resolvedNewPath)) {
281
+ return { success: false, error: 'Destination already exists' }
282
+ }
283
+
284
+ const parentDir = dirname(resolvedNewPath)
285
+ if (!existsSync(parentDir)) mkdirSync(parentDir, { recursive: true })
286
+
287
+ renameSync(resolvedOldPath, resolvedNewPath)
288
+ return { success: true, path: resolvedNewPath.replace(`${workingDir}/`, '') }
289
+ } catch (error: unknown) {
290
+ console.error('[FileService] Error renaming file:', error)
291
+ return { success: false, error: error instanceof Error ? error.message : 'Failed to rename' }
292
+ }
293
+ }