@machina.ai/cell-cli-core 1.0.13-rc9 → 1.0.21-rc1

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 (484) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.js +3 -0
  3. package/dist/index.js.map +1 -1
  4. package/dist/package.json +12 -4
  5. package/dist/src/code_assist/converter.d.ts +6 -3
  6. package/dist/src/code_assist/converter.js +4 -2
  7. package/dist/src/code_assist/converter.js.map +1 -1
  8. package/dist/src/code_assist/converter.test.js +61 -11
  9. package/dist/src/code_assist/converter.test.js.map +1 -1
  10. package/dist/src/code_assist/oauth2.d.ts +1 -0
  11. package/dist/src/code_assist/oauth2.js +43 -18
  12. package/dist/src/code_assist/oauth2.js.map +1 -1
  13. package/dist/src/code_assist/oauth2.test.js +142 -9
  14. package/dist/src/code_assist/oauth2.test.js.map +1 -1
  15. package/dist/src/code_assist/server.d.ts +2 -2
  16. package/dist/src/code_assist/server.js +5 -5
  17. package/dist/src/code_assist/server.js.map +1 -1
  18. package/dist/src/code_assist/server.test.js +13 -10
  19. package/dist/src/code_assist/server.test.js.map +1 -1
  20. package/dist/src/code_assist/setup.js +49 -18
  21. package/dist/src/code_assist/setup.js.map +1 -1
  22. package/dist/src/code_assist/setup.test.js +115 -9
  23. package/dist/src/code_assist/setup.test.js.map +1 -1
  24. package/dist/src/config/config.d.ts +71 -13
  25. package/dist/src/config/config.js +154 -41
  26. package/dist/src/config/config.js.map +1 -1
  27. package/dist/src/config/config.test.js +206 -21
  28. package/dist/src/config/config.test.js.map +1 -1
  29. package/dist/src/config/flashFallback.test.js +19 -47
  30. package/dist/src/config/flashFallback.test.js.map +1 -1
  31. package/dist/src/config/models.d.ts +1 -0
  32. package/dist/src/config/models.js +1 -0
  33. package/dist/src/config/models.js.map +1 -1
  34. package/dist/src/core/client.d.ts +15 -16
  35. package/dist/src/core/client.js +247 -104
  36. package/dist/src/core/client.js.map +1 -1
  37. package/dist/src/core/client.test.js +798 -49
  38. package/dist/src/core/client.test.js.map +1 -1
  39. package/dist/src/core/contentGenerator.d.ts +2 -2
  40. package/dist/src/core/contentGenerator.js +23 -21
  41. package/dist/src/core/contentGenerator.js.map +1 -1
  42. package/dist/src/core/contentGenerator.test.js +30 -126
  43. package/dist/src/core/contentGenerator.test.js.map +1 -1
  44. package/dist/src/core/coreToolScheduler.d.ts +23 -10
  45. package/dist/src/core/coreToolScheduler.js +201 -77
  46. package/dist/src/core/coreToolScheduler.js.map +1 -1
  47. package/dist/src/core/coreToolScheduler.test.js +322 -94
  48. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  49. package/dist/src/core/geminiChat.d.ts +8 -6
  50. package/dist/src/core/geminiChat.js +49 -51
  51. package/dist/src/core/geminiChat.js.map +1 -1
  52. package/dist/src/core/geminiChat.test.js +2 -2
  53. package/dist/src/core/geminiChat.test.js.map +1 -1
  54. package/dist/src/core/geminiRequest.js +2 -37
  55. package/dist/src/core/geminiRequest.js.map +1 -1
  56. package/dist/src/core/logger.d.ts +24 -1
  57. package/dist/src/core/logger.js +128 -4
  58. package/dist/src/core/logger.js.map +1 -1
  59. package/dist/src/core/logger.test.js +157 -11
  60. package/dist/src/core/logger.test.js.map +1 -1
  61. package/dist/src/core/loggingContentGenerator.d.ts +25 -0
  62. package/dist/src/core/loggingContentGenerator.js +95 -0
  63. package/dist/src/core/loggingContentGenerator.js.map +1 -0
  64. package/dist/src/core/nonInteractiveToolExecutor.js +39 -4
  65. package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
  66. package/dist/src/core/nonInteractiveToolExecutor.test.js +85 -62
  67. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  68. package/dist/src/core/prompts.js +43 -19
  69. package/dist/src/core/prompts.js.map +1 -1
  70. package/dist/src/core/prompts.test.js +118 -1
  71. package/dist/src/core/prompts.test.js.map +1 -1
  72. package/dist/src/core/subagent.d.ts +230 -0
  73. package/dist/src/core/subagent.js +447 -0
  74. package/dist/src/core/subagent.js.map +1 -0
  75. package/dist/src/core/subagent.test.js +515 -0
  76. package/dist/src/core/subagent.test.js.map +1 -0
  77. package/dist/src/core/tokenLimits.js +1 -0
  78. package/dist/src/core/tokenLimits.js.map +1 -1
  79. package/dist/src/core/turn.d.ts +3 -0
  80. package/dist/src/core/turn.js +4 -0
  81. package/dist/src/core/turn.js.map +1 -1
  82. package/dist/src/core/turn.test.js +4 -0
  83. package/dist/src/core/turn.test.js.map +1 -1
  84. package/dist/src/generated/git-commit.d.ts +7 -0
  85. package/dist/src/generated/git-commit.js +10 -0
  86. package/dist/src/generated/git-commit.js.map +1 -0
  87. package/dist/src/ide/constants.d.ts +6 -0
  88. package/dist/src/ide/constants.js +7 -0
  89. package/dist/src/ide/constants.js.map +1 -0
  90. package/dist/src/ide/detect-ide.d.ts +20 -0
  91. package/dist/src/ide/detect-ide.js +86 -0
  92. package/dist/src/ide/detect-ide.js.map +1 -0
  93. package/dist/src/ide/detect-ide.test.js +65 -0
  94. package/dist/src/ide/detect-ide.test.js.map +1 -0
  95. package/dist/src/ide/ide-client.d.ts +63 -0
  96. package/dist/src/ide/ide-client.js +320 -0
  97. package/dist/src/ide/ide-client.js.map +1 -0
  98. package/dist/src/ide/ide-client.test.d.ts +6 -0
  99. package/dist/src/ide/ide-client.test.js +43 -0
  100. package/dist/src/ide/ide-client.test.js.map +1 -0
  101. package/dist/src/ide/ide-installer.d.ts +14 -0
  102. package/dist/src/ide/ide-installer.js +98 -0
  103. package/dist/src/ide/ide-installer.js.map +1 -0
  104. package/dist/src/ide/ide-installer.test.d.ts +6 -0
  105. package/dist/src/ide/ide-installer.test.js +53 -0
  106. package/dist/src/ide/ide-installer.test.js.map +1 -0
  107. package/dist/src/ide/ideContext.d.ts +374 -0
  108. package/dist/src/ide/ideContext.js +147 -0
  109. package/dist/src/ide/ideContext.js.map +1 -0
  110. package/dist/src/ide/ideContext.test.d.ts +6 -0
  111. package/dist/src/ide/ideContext.test.js +265 -0
  112. package/dist/src/ide/ideContext.test.js.map +1 -0
  113. package/dist/src/ide/process-utils.d.ts +14 -0
  114. package/dist/src/ide/process-utils.js +57 -0
  115. package/dist/src/ide/process-utils.js.map +1 -0
  116. package/dist/src/index.d.ts +17 -1
  117. package/dist/src/index.js +20 -1
  118. package/dist/src/index.js.map +1 -1
  119. package/dist/src/mcp/google-auth-provider.d.ts +23 -0
  120. package/dist/src/mcp/google-auth-provider.js +72 -0
  121. package/dist/src/mcp/google-auth-provider.js.map +1 -0
  122. package/dist/src/mcp/google-auth-provider.test.d.ts +6 -0
  123. package/dist/src/mcp/google-auth-provider.test.js +89 -0
  124. package/dist/src/mcp/google-auth-provider.test.js.map +1 -0
  125. package/dist/src/mcp/oauth-provider.d.ts +6 -2
  126. package/dist/src/mcp/oauth-provider.js +208 -53
  127. package/dist/src/mcp/oauth-provider.js.map +1 -1
  128. package/dist/src/mcp/oauth-provider.test.js +222 -70
  129. package/dist/src/mcp/oauth-provider.test.js.map +1 -1
  130. package/dist/src/mcp/oauth-token-storage.d.ts +3 -1
  131. package/dist/src/mcp/oauth-token-storage.js +3 -1
  132. package/dist/src/mcp/oauth-token-storage.js.map +1 -1
  133. package/dist/src/mcp/oauth-utils.d.ts +3 -1
  134. package/dist/src/mcp/oauth-utils.js +52 -14
  135. package/dist/src/mcp/oauth-utils.js.map +1 -1
  136. package/dist/src/mcp/oauth-utils.test.js +18 -3
  137. package/dist/src/mcp/oauth-utils.test.js.map +1 -1
  138. package/dist/src/mocks/msw.d.ts +6 -0
  139. package/dist/src/mocks/msw.js +8 -0
  140. package/dist/src/mocks/msw.js.map +1 -0
  141. package/dist/src/prompts/mcp-prompts.d.ts +8 -0
  142. package/dist/src/prompts/mcp-prompts.js +13 -0
  143. package/dist/src/prompts/mcp-prompts.js.map +1 -0
  144. package/dist/src/prompts/prompt-registry.d.ts +34 -0
  145. package/dist/src/prompts/prompt-registry.js +63 -0
  146. package/dist/src/prompts/prompt-registry.js.map +1 -0
  147. package/dist/src/services/chatRecordingService.d.ts +150 -0
  148. package/dist/src/services/chatRecordingService.js +318 -0
  149. package/dist/src/services/chatRecordingService.js.map +1 -0
  150. package/dist/src/services/chatRecordingService.test.d.ts +6 -0
  151. package/dist/src/services/chatRecordingService.test.js +288 -0
  152. package/dist/src/services/chatRecordingService.test.js.map +1 -0
  153. package/dist/src/services/fileDiscoveryService.test.js +101 -60
  154. package/dist/src/services/fileDiscoveryService.test.js.map +1 -1
  155. package/dist/src/services/fileSystemService.d.ts +31 -0
  156. package/dist/src/services/fileSystemService.js +18 -0
  157. package/dist/src/services/fileSystemService.js.map +1 -0
  158. package/dist/src/services/fileSystemService.test.d.ts +6 -0
  159. package/dist/src/services/fileSystemService.test.js +41 -0
  160. package/dist/src/services/fileSystemService.test.js.map +1 -0
  161. package/dist/src/services/gitService.test.js +67 -86
  162. package/dist/src/services/gitService.test.js.map +1 -1
  163. package/dist/src/services/loopDetectionService.d.ts +51 -5
  164. package/dist/src/services/loopDetectionService.js +152 -45
  165. package/dist/src/services/loopDetectionService.js.map +1 -1
  166. package/dist/src/services/loopDetectionService.test.js +286 -89
  167. package/dist/src/services/loopDetectionService.test.js.map +1 -1
  168. package/dist/src/services/shellExecutionService.d.ts +70 -0
  169. package/dist/src/services/shellExecutionService.js +175 -0
  170. package/dist/src/services/shellExecutionService.js.map +1 -0
  171. package/dist/src/services/shellExecutionService.test.d.ts +6 -0
  172. package/dist/src/services/shellExecutionService.test.js +282 -0
  173. package/dist/src/services/shellExecutionService.test.js.map +1 -0
  174. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +81 -9
  175. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +356 -182
  176. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  177. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +17 -0
  178. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +342 -0
  179. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -0
  180. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +19 -2
  181. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +51 -9
  182. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  183. package/dist/src/telemetry/constants.d.ts +4 -0
  184. package/dist/src/telemetry/constants.js +4 -0
  185. package/dist/src/telemetry/constants.js.map +1 -1
  186. package/dist/src/telemetry/file-exporters.d.ts +28 -0
  187. package/dist/src/telemetry/file-exporters.js +62 -0
  188. package/dist/src/telemetry/file-exporters.js.map +1 -0
  189. package/dist/src/telemetry/index.d.ts +2 -2
  190. package/dist/src/telemetry/index.js +2 -2
  191. package/dist/src/telemetry/index.js.map +1 -1
  192. package/dist/src/telemetry/integration.test.circular.js +1 -0
  193. package/dist/src/telemetry/integration.test.circular.js.map +1 -1
  194. package/dist/src/telemetry/loggers.d.ts +6 -1
  195. package/dist/src/telemetry/loggers.js +87 -6
  196. package/dist/src/telemetry/loggers.js.map +1 -1
  197. package/dist/src/telemetry/loggers.test.circular.js +9 -2
  198. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  199. package/dist/src/telemetry/loggers.test.js +51 -11
  200. package/dist/src/telemetry/loggers.test.js.map +1 -1
  201. package/dist/src/telemetry/metrics.d.ts +7 -2
  202. package/dist/src/telemetry/metrics.js +26 -6
  203. package/dist/src/telemetry/metrics.js.map +1 -1
  204. package/dist/src/telemetry/metrics.test.js +81 -1
  205. package/dist/src/telemetry/metrics.test.js.map +1 -1
  206. package/dist/src/telemetry/sdk.d.ts +1 -1
  207. package/dist/src/telemetry/sdk.js +77 -30
  208. package/dist/src/telemetry/sdk.js.map +1 -1
  209. package/dist/src/telemetry/sdk.test.d.ts +6 -0
  210. package/dist/src/telemetry/sdk.test.js +82 -0
  211. package/dist/src/telemetry/sdk.test.js.map +1 -0
  212. package/dist/src/telemetry/telemetry.test.js +2 -2
  213. package/dist/src/telemetry/telemetry.test.js.map +1 -1
  214. package/dist/src/telemetry/tool-call-decision.d.ts +13 -0
  215. package/dist/src/telemetry/tool-call-decision.js +29 -0
  216. package/dist/src/telemetry/tool-call-decision.js.map +1 -0
  217. package/dist/src/telemetry/types.d.ts +74 -18
  218. package/dist/src/telemetry/types.js +110 -32
  219. package/dist/src/telemetry/types.js.map +1 -1
  220. package/dist/src/telemetry/uiTelemetry.d.ts +8 -1
  221. package/dist/src/telemetry/uiTelemetry.js +17 -2
  222. package/dist/src/telemetry/uiTelemetry.js.map +1 -1
  223. package/dist/src/telemetry/uiTelemetry.test.js +60 -10
  224. package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
  225. package/dist/src/test-utils/config.d.ts +16 -0
  226. package/dist/src/test-utils/config.js +32 -0
  227. package/dist/src/test-utils/config.js.map +1 -0
  228. package/dist/src/test-utils/mockWorkspaceContext.d.ts +13 -0
  229. package/dist/src/test-utils/mockWorkspaceContext.js +24 -0
  230. package/dist/src/test-utils/mockWorkspaceContext.js.map +1 -0
  231. package/dist/src/test-utils/tools.d.ts +44 -0
  232. package/dist/src/test-utils/tools.js +105 -0
  233. package/dist/src/test-utils/tools.js.map +1 -0
  234. package/dist/src/tools/diffOptions.d.ts +2 -0
  235. package/dist/src/tools/diffOptions.js +28 -0
  236. package/dist/src/tools/diffOptions.js.map +1 -1
  237. package/dist/src/tools/diffOptions.test.d.ts +6 -0
  238. package/dist/src/tools/diffOptions.test.js +119 -0
  239. package/dist/src/tools/diffOptions.test.js.map +1 -0
  240. package/dist/src/tools/edit.d.ts +10 -34
  241. package/dist/src/tools/edit.js +171 -131
  242. package/dist/src/tools/edit.js.map +1 -1
  243. package/dist/src/tools/edit.test.js +220 -43
  244. package/dist/src/tools/edit.test.js.map +1 -1
  245. package/dist/src/tools/glob.d.ts +4 -11
  246. package/dist/src/tools/glob.js +129 -97
  247. package/dist/src/tools/glob.js.map +1 -1
  248. package/dist/src/tools/glob.test.js +73 -17
  249. package/dist/src/tools/glob.test.js.map +1 -1
  250. package/dist/src/tools/grep.d.ts +5 -37
  251. package/dist/src/tools/grep.js +175 -100
  252. package/dist/src/tools/grep.js.map +1 -1
  253. package/dist/src/tools/grep.test.js +112 -28
  254. package/dist/src/tools/grep.test.js.map +1 -1
  255. package/dist/src/tools/ls.d.ts +4 -23
  256. package/dist/src/tools/ls.js +77 -78
  257. package/dist/src/tools/ls.js.map +1 -1
  258. package/dist/src/tools/ls.test.d.ts +6 -0
  259. package/dist/src/tools/ls.test.js +384 -0
  260. package/dist/src/tools/ls.test.js.map +1 -0
  261. package/dist/src/tools/mcp-client-manager.d.ts +38 -0
  262. package/dist/src/tools/mcp-client-manager.js +74 -0
  263. package/dist/src/tools/mcp-client-manager.js.map +1 -0
  264. package/dist/src/tools/mcp-client-manager.test.d.ts +6 -0
  265. package/dist/src/tools/mcp-client-manager.test.js +39 -0
  266. package/dist/src/tools/mcp-client-manager.test.js.map +1 -0
  267. package/dist/src/tools/mcp-client.d.ts +86 -4
  268. package/dist/src/tools/mcp-client.js +730 -59
  269. package/dist/src/tools/mcp-client.js.map +1 -1
  270. package/dist/src/tools/mcp-client.test.js +295 -22
  271. package/dist/src/tools/mcp-client.test.js.map +1 -1
  272. package/dist/src/tools/mcp-tool.d.ts +6 -13
  273. package/dist/src/tools/mcp-tool.js +163 -76
  274. package/dist/src/tools/mcp-tool.js.map +1 -1
  275. package/dist/src/tools/mcp-tool.test.js +400 -29
  276. package/dist/src/tools/mcp-tool.test.js.map +1 -1
  277. package/dist/src/tools/memoryTool.d.ts +14 -3
  278. package/dist/src/tools/memoryTool.js +159 -40
  279. package/dist/src/tools/memoryTool.js.map +1 -1
  280. package/dist/src/tools/memoryTool.test.js +116 -11
  281. package/dist/src/tools/memoryTool.test.js.map +1 -1
  282. package/dist/src/tools/modifiable-tool.d.ts +9 -6
  283. package/dist/src/tools/modifiable-tool.js +6 -3
  284. package/dist/src/tools/modifiable-tool.js.map +1 -1
  285. package/dist/src/tools/modifiable-tool.test.js +63 -74
  286. package/dist/src/tools/modifiable-tool.test.js.map +1 -1
  287. package/dist/src/tools/read-file.d.ts +4 -6
  288. package/dist/src/tools/read-file.js +100 -53
  289. package/dist/src/tools/read-file.js.map +1 -1
  290. package/dist/src/tools/read-file.test.js +238 -111
  291. package/dist/src/tools/read-file.test.js.map +1 -1
  292. package/dist/src/tools/read-many-files.d.ts +3 -6
  293. package/dist/src/tools/read-many-files.js +232 -157
  294. package/dist/src/tools/read-many-files.js.map +1 -1
  295. package/dist/src/tools/read-many-files.test.js +231 -34
  296. package/dist/src/tools/read-many-files.test.js.map +1 -1
  297. package/dist/src/tools/shell.d.ts +6 -28
  298. package/dist/src/tools/shell.js +249 -366
  299. package/dist/src/tools/shell.js.map +1 -1
  300. package/dist/src/tools/shell.test.js +305 -384
  301. package/dist/src/tools/shell.test.js.map +1 -1
  302. package/dist/src/tools/tool-error.d.ts +27 -0
  303. package/dist/src/tools/tool-error.js +32 -0
  304. package/dist/src/tools/tool-error.js.map +1 -0
  305. package/dist/src/tools/tool-registry.d.ts +38 -23
  306. package/dist/src/tools/tool-registry.js +127 -99
  307. package/dist/src/tools/tool-registry.js.map +1 -1
  308. package/dist/src/tools/tool-registry.test.js +37 -212
  309. package/dist/src/tools/tool-registry.test.js.map +1 -1
  310. package/dist/src/tools/tools.d.ts +145 -92
  311. package/dist/src/tools/tools.js +188 -61
  312. package/dist/src/tools/tools.js.map +1 -1
  313. package/dist/src/tools/tools.test.d.ts +6 -0
  314. package/dist/src/tools/tools.test.js +206 -0
  315. package/dist/src/tools/tools.test.js.map +1 -0
  316. package/dist/src/tools/web-fetch.d.ts +4 -7
  317. package/dist/src/tools/web-fetch.js +58 -64
  318. package/dist/src/tools/web-fetch.js.map +1 -1
  319. package/dist/src/tools/web-fetch.test.js +8 -4
  320. package/dist/src/tools/web-fetch.test.js.map +1 -1
  321. package/dist/src/tools/web-search.d.ts +4 -5
  322. package/dist/src/tools/web-search.js +47 -51
  323. package/dist/src/tools/web-search.js.map +1 -1
  324. package/dist/src/tools/web-search.test.d.ts +6 -0
  325. package/dist/src/tools/web-search.test.js +139 -0
  326. package/dist/src/tools/web-search.test.js.map +1 -0
  327. package/dist/src/tools/write-file.d.ts +20 -11
  328. package/dist/src/tools/write-file.js +198 -141
  329. package/dist/src/tools/write-file.js.map +1 -1
  330. package/dist/src/tools/write-file.test.js +190 -76
  331. package/dist/src/tools/write-file.test.js.map +1 -1
  332. package/dist/src/utils/bfsFileSearch.js +51 -27
  333. package/dist/src/utils/bfsFileSearch.js.map +1 -1
  334. package/dist/src/utils/bfsFileSearch.test.js +137 -136
  335. package/dist/src/utils/bfsFileSearch.test.js.map +1 -1
  336. package/dist/src/utils/browser.js +4 -3
  337. package/dist/src/utils/browser.js.map +1 -1
  338. package/dist/src/utils/editCorrector.js +23 -24
  339. package/dist/src/utils/editCorrector.js.map +1 -1
  340. package/dist/src/utils/editor.d.ts +2 -2
  341. package/dist/src/utils/editor.js +23 -6
  342. package/dist/src/utils/editor.js.map +1 -1
  343. package/dist/src/utils/editor.test.js +67 -15
  344. package/dist/src/utils/editor.test.js.map +1 -1
  345. package/dist/src/utils/environmentContext.d.ts +21 -0
  346. package/dist/src/utils/environmentContext.js +90 -0
  347. package/dist/src/utils/environmentContext.js.map +1 -0
  348. package/dist/src/utils/environmentContext.test.d.ts +6 -0
  349. package/dist/src/utils/environmentContext.test.js +140 -0
  350. package/dist/src/utils/environmentContext.test.js.map +1 -0
  351. package/dist/src/utils/errorParsing.d.ts +8 -0
  352. package/dist/src/utils/errorParsing.js +93 -0
  353. package/dist/src/utils/errorParsing.js.map +1 -0
  354. package/dist/src/utils/errorParsing.test.d.ts +6 -0
  355. package/dist/src/utils/errorParsing.test.js +172 -0
  356. package/dist/src/utils/errorParsing.test.js.map +1 -0
  357. package/dist/src/utils/errorReporting.d.ts +1 -1
  358. package/dist/src/utils/errorReporting.js +2 -2
  359. package/dist/src/utils/errorReporting.js.map +1 -1
  360. package/dist/src/utils/errorReporting.test.js +44 -38
  361. package/dist/src/utils/errorReporting.test.js.map +1 -1
  362. package/dist/src/utils/fileUtils.d.ts +9 -1
  363. package/dist/src/utils/fileUtils.js +27 -13
  364. package/dist/src/utils/fileUtils.js.map +1 -1
  365. package/dist/src/utils/fileUtils.test.js +61 -18
  366. package/dist/src/utils/fileUtils.test.js.map +1 -1
  367. package/dist/src/utils/filesearch/crawlCache.d.ts +25 -0
  368. package/dist/src/utils/filesearch/crawlCache.js +57 -0
  369. package/dist/src/utils/filesearch/crawlCache.js.map +1 -0
  370. package/dist/src/utils/filesearch/crawlCache.test.d.ts +6 -0
  371. package/dist/src/utils/filesearch/crawlCache.test.js +103 -0
  372. package/dist/src/utils/filesearch/crawlCache.test.js.map +1 -0
  373. package/dist/src/utils/filesearch/crawler.d.ts +15 -0
  374. package/dist/src/utils/filesearch/crawler.js +50 -0
  375. package/dist/src/utils/filesearch/crawler.js.map +1 -0
  376. package/dist/src/utils/filesearch/crawler.test.d.ts +6 -0
  377. package/dist/src/utils/filesearch/crawler.test.js +468 -0
  378. package/dist/src/utils/filesearch/crawler.test.js.map +1 -0
  379. package/dist/src/utils/filesearch/fileSearch.d.ts +37 -0
  380. package/dist/src/utils/filesearch/fileSearch.js +186 -0
  381. package/dist/src/utils/filesearch/fileSearch.js.map +1 -0
  382. package/dist/src/utils/filesearch/fileSearch.test.d.ts +6 -0
  383. package/dist/src/utils/filesearch/fileSearch.test.js +552 -0
  384. package/dist/src/utils/filesearch/fileSearch.test.js.map +1 -0
  385. package/dist/src/utils/filesearch/ignore.d.ts +42 -0
  386. package/dist/src/utils/filesearch/ignore.js +106 -0
  387. package/dist/src/utils/filesearch/ignore.js.map +1 -0
  388. package/dist/src/utils/filesearch/ignore.test.d.ts +6 -0
  389. package/dist/src/utils/filesearch/ignore.test.js +144 -0
  390. package/dist/src/utils/filesearch/ignore.test.js.map +1 -0
  391. package/dist/src/utils/filesearch/result-cache.d.ts +33 -0
  392. package/dist/src/utils/filesearch/result-cache.js +59 -0
  393. package/dist/src/utils/filesearch/result-cache.js.map +1 -0
  394. package/dist/src/utils/filesearch/result-cache.test.d.ts +6 -0
  395. package/dist/src/utils/filesearch/result-cache.test.js +46 -0
  396. package/dist/src/utils/filesearch/result-cache.test.js.map +1 -0
  397. package/dist/src/utils/flashFallback.integration.test.js +6 -0
  398. package/dist/src/utils/flashFallback.integration.test.js.map +1 -1
  399. package/dist/src/utils/formatters.d.ts +6 -0
  400. package/dist/src/utils/formatters.js +16 -0
  401. package/dist/src/utils/formatters.js.map +1 -0
  402. package/dist/src/utils/getFolderStructure.test.js +11 -13
  403. package/dist/src/utils/getFolderStructure.test.js.map +1 -1
  404. package/dist/src/utils/gitIgnoreParser.js +5 -11
  405. package/dist/src/utils/gitIgnoreParser.js.map +1 -1
  406. package/dist/src/utils/gitIgnoreParser.test.js +58 -61
  407. package/dist/src/utils/gitIgnoreParser.test.js.map +1 -1
  408. package/dist/src/utils/memoryDiscovery.d.ts +1 -1
  409. package/dist/src/utils/memoryDiscovery.js +76 -83
  410. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  411. package/dist/src/utils/memoryDiscovery.test.js +122 -372
  412. package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
  413. package/dist/src/utils/memoryImportProcessor.d.ts +19 -12
  414. package/dist/src/utils/memoryImportProcessor.js +240 -85
  415. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  416. package/dist/src/utils/memoryImportProcessor.test.js +593 -51
  417. package/dist/src/utils/memoryImportProcessor.test.js.map +1 -1
  418. package/dist/src/utils/nextSpeakerChecker.js +4 -25
  419. package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
  420. package/dist/src/utils/partUtils.d.ts +14 -0
  421. package/dist/src/utils/partUtils.js +65 -0
  422. package/dist/src/utils/partUtils.js.map +1 -0
  423. package/dist/src/utils/partUtils.test.d.ts +6 -0
  424. package/dist/src/utils/partUtils.test.js +130 -0
  425. package/dist/src/utils/partUtils.test.js.map +1 -0
  426. package/dist/src/utils/paths.d.ts +18 -2
  427. package/dist/src/utils/paths.js +39 -7
  428. package/dist/src/utils/paths.js.map +1 -1
  429. package/dist/src/utils/paths.test.d.ts +6 -0
  430. package/dist/src/utils/paths.test.js +225 -0
  431. package/dist/src/utils/paths.test.js.map +1 -0
  432. package/dist/src/utils/quotaErrorDetection.d.ts +1 -5
  433. package/dist/src/utils/quotaErrorDetection.js.map +1 -1
  434. package/dist/src/utils/retry.d.ts +3 -0
  435. package/dist/src/utils/retry.js.map +1 -1
  436. package/dist/src/utils/retry.test.js.map +1 -1
  437. package/dist/src/utils/schemaValidator.d.ts +1 -8
  438. package/dist/src/utils/schemaValidator.js +1 -32
  439. package/dist/src/utils/schemaValidator.js.map +1 -1
  440. package/dist/src/utils/secure-browser-launcher.d.ts +23 -0
  441. package/dist/src/utils/secure-browser-launcher.js +165 -0
  442. package/dist/src/utils/secure-browser-launcher.js.map +1 -0
  443. package/dist/src/utils/secure-browser-launcher.test.d.ts +6 -0
  444. package/dist/src/utils/secure-browser-launcher.test.js +149 -0
  445. package/dist/src/utils/secure-browser-launcher.test.js.map +1 -0
  446. package/dist/src/utils/shell-utils.d.ts +117 -0
  447. package/dist/src/utils/shell-utils.js +376 -0
  448. package/dist/src/utils/shell-utils.js.map +1 -0
  449. package/dist/src/utils/shell-utils.test.d.ts +6 -0
  450. package/dist/src/utils/shell-utils.test.js +328 -0
  451. package/dist/src/utils/shell-utils.test.js.map +1 -0
  452. package/dist/src/utils/summarizer.js +3 -32
  453. package/dist/src/utils/summarizer.js.map +1 -1
  454. package/dist/src/utils/systemEncoding.js +1 -1
  455. package/dist/src/utils/systemEncoding.js.map +1 -1
  456. package/dist/src/utils/systemEncoding.test.js +23 -23
  457. package/dist/src/utils/systemEncoding.test.js.map +1 -1
  458. package/dist/src/utils/textUtils.d.ts +13 -0
  459. package/dist/src/utils/textUtils.js +28 -0
  460. package/dist/src/utils/textUtils.js.map +1 -0
  461. package/dist/src/utils/user_account.js +58 -48
  462. package/dist/src/utils/user_account.js.map +1 -1
  463. package/dist/src/utils/user_account.test.js +76 -9
  464. package/dist/src/utils/user_account.test.js.map +1 -1
  465. package/dist/src/utils/workspaceContext.d.ts +66 -0
  466. package/dist/src/utils/workspaceContext.js +165 -0
  467. package/dist/src/utils/workspaceContext.js.map +1 -0
  468. package/dist/src/utils/workspaceContext.test.d.ts +6 -0
  469. package/dist/src/utils/workspaceContext.test.js +293 -0
  470. package/dist/src/utils/workspaceContext.test.js.map +1 -0
  471. package/dist/tsconfig.tsbuildinfo +1 -1
  472. package/package.json +14 -3
  473. package/dist/src/core/geminiRequest.test.js +0 -72
  474. package/dist/src/core/geminiRequest.test.js.map +0 -1
  475. package/dist/src/core/modelCheck.d.ts +0 -14
  476. package/dist/src/core/modelCheck.js +0 -62
  477. package/dist/src/core/modelCheck.js.map +0 -1
  478. package/dist/src/services/ideContext.d.ts +0 -178
  479. package/dist/src/services/ideContext.js +0 -105
  480. package/dist/src/services/ideContext.js.map +0 -1
  481. package/dist/src/services/ideContext.test.js +0 -111
  482. package/dist/src/services/ideContext.test.js.map +0 -1
  483. /package/dist/src/core/{geminiRequest.test.d.ts → subagent.test.d.ts} +0 -0
  484. /package/dist/src/{services/ideContext.test.d.ts → ide/detect-ide.test.d.ts} +0 -0
@@ -6,14 +6,76 @@
6
6
  import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
7
7
  import * as fs from 'fs/promises';
8
8
  import * as path from 'path';
9
+ import { marked } from 'marked';
9
10
  import { processImports, validateImportPath } from './memoryImportProcessor.js';
10
- // Mock fs/promises
11
+ // Helper function to create platform-agnostic test paths
12
+ function testPath(...segments) {
13
+ // Start with the first segment as is (might be an absolute path on Windows)
14
+ let result = segments[0];
15
+ // Join remaining segments with the platform-specific separator
16
+ for (let i = 1; i < segments.length; i++) {
17
+ if (segments[i].startsWith('/') || segments[i].startsWith('\\')) {
18
+ // If segment starts with a separator, remove the trailing separator from the result
19
+ result = path.normalize(result.replace(/[\\/]+$/, '') + segments[i]);
20
+ }
21
+ else {
22
+ // Otherwise join with the platform separator
23
+ result = path.join(result, segments[i]);
24
+ }
25
+ }
26
+ return path.normalize(result);
27
+ }
11
28
  vi.mock('fs/promises');
12
29
  const mockedFs = vi.mocked(fs);
13
30
  // Mock console methods to capture warnings
14
31
  const originalConsoleWarn = console.warn;
15
32
  const originalConsoleError = console.error;
16
33
  const originalConsoleDebug = console.debug;
34
+ // Helper functions using marked for parsing and validation
35
+ const parseMarkdown = (content) => marked.lexer(content);
36
+ const findMarkdownComments = (content) => {
37
+ const tokens = parseMarkdown(content);
38
+ const comments = [];
39
+ function walkTokens(tokenList) {
40
+ for (const token of tokenList) {
41
+ const t = token;
42
+ if (t.type === 'html' && t.raw.includes('<!--')) {
43
+ comments.push(t.raw.trim());
44
+ }
45
+ if (t.tokens) {
46
+ walkTokens(t.tokens);
47
+ }
48
+ }
49
+ }
50
+ walkTokens(tokens);
51
+ return comments;
52
+ };
53
+ const findCodeBlocks = (content) => {
54
+ const tokens = parseMarkdown(content);
55
+ const codeBlocks = [];
56
+ function walkTokens(tokenList) {
57
+ for (const token of tokenList) {
58
+ const t = token;
59
+ if (t.type === 'code') {
60
+ codeBlocks.push({
61
+ type: 'code_block',
62
+ content: t.text,
63
+ });
64
+ }
65
+ else if (t.type === 'codespan') {
66
+ codeBlocks.push({
67
+ type: 'inline_code',
68
+ content: t.text,
69
+ });
70
+ }
71
+ if (t.tokens) {
72
+ walkTokens(t.tokens);
73
+ }
74
+ }
75
+ }
76
+ walkTokens(tokens);
77
+ return codeBlocks;
78
+ };
17
79
  describe('memoryImportProcessor', () => {
18
80
  beforeEach(() => {
19
81
  vi.clearAllMocks();
@@ -31,27 +93,47 @@ describe('memoryImportProcessor', () => {
31
93
  describe('processImports', () => {
32
94
  it('should process basic md file imports', async () => {
33
95
  const content = 'Some content @./test.md more content';
34
- const basePath = '/test/path';
96
+ const basePath = testPath('test', 'path');
35
97
  const importedContent = '# Imported Content\nThis is imported.';
36
98
  mockedFs.access.mockResolvedValue(undefined);
37
99
  mockedFs.readFile.mockResolvedValue(importedContent);
38
100
  const result = await processImports(content, basePath, true);
39
- expect(result).toContain('<!-- Imported from: ./test.md -->');
40
- expect(result).toContain(importedContent);
41
- expect(result).toContain('<!-- End of import from: ./test.md -->');
101
+ // Use marked to find HTML comments (import markers)
102
+ const comments = findMarkdownComments(result.content);
103
+ expect(comments.some((c) => c.includes('Imported from: ./test.md'))).toBe(true);
104
+ expect(comments.some((c) => c.includes('End of import from: ./test.md'))).toBe(true);
105
+ // Verify the imported content is present
106
+ expect(result.content).toContain(importedContent);
107
+ // Verify the markdown structure is valid
108
+ const tokens = parseMarkdown(result.content);
109
+ expect(tokens).toBeDefined();
110
+ expect(tokens.length).toBeGreaterThan(0);
42
111
  expect(mockedFs.readFile).toHaveBeenCalledWith(path.resolve(basePath, './test.md'), 'utf-8');
43
112
  });
44
- it('should warn and fail for non-md file imports', async () => {
113
+ it('should import non-md files just like md files', async () => {
45
114
  const content = 'Some content @./instructions.txt more content';
46
- const basePath = '/test/path';
115
+ const basePath = testPath('test', 'path');
116
+ const importedContent = '# Instructions\nThis is a text file with markdown.';
117
+ mockedFs.access.mockResolvedValue(undefined);
118
+ mockedFs.readFile.mockResolvedValue(importedContent);
47
119
  const result = await processImports(content, basePath, true);
48
- expect(console.warn).toHaveBeenCalledWith('[WARN] [ImportProcessor]', 'Import processor only supports .md files. Attempting to import non-md file: ./instructions.txt. This will fail.');
49
- expect(result).toContain('<!-- Import failed: ./instructions.txt - Only .md files are supported -->');
50
- expect(mockedFs.readFile).not.toHaveBeenCalled();
120
+ // Use marked to find import comments
121
+ const comments = findMarkdownComments(result.content);
122
+ expect(comments.some((c) => c.includes('Imported from: ./instructions.txt'))).toBe(true);
123
+ expect(comments.some((c) => c.includes('End of import from: ./instructions.txt'))).toBe(true);
124
+ // Use marked to parse and validate the imported content structure
125
+ const tokens = parseMarkdown(result.content);
126
+ // Find headers in the parsed content
127
+ const headers = tokens.filter((token) => token.type === 'heading');
128
+ expect(headers.some((h) => h.text === 'Instructions')).toBe(true);
129
+ // Verify the imported content is present
130
+ expect(result.content).toContain(importedContent);
131
+ expect(console.warn).not.toHaveBeenCalled();
132
+ expect(mockedFs.readFile).toHaveBeenCalledWith(path.resolve(basePath, './instructions.txt'), 'utf-8');
51
133
  });
52
134
  it('should handle circular imports', async () => {
53
135
  const content = 'Content @./circular.md more content';
54
- const basePath = '/test/path';
136
+ const basePath = testPath('test', 'path');
55
137
  const circularContent = 'Circular @./main.md content';
56
138
  mockedFs.access.mockResolvedValue(undefined);
57
139
  mockedFs.readFile.mockResolvedValue(circularContent);
@@ -60,23 +142,23 @@ describe('memoryImportProcessor', () => {
60
142
  processedFiles: new Set(),
61
143
  maxDepth: 10,
62
144
  currentDepth: 0,
63
- currentFile: '/test/path/main.md', // Simulate we're processing main.md
145
+ currentFile: testPath('test', 'path', 'main.md'), // Simulate we're processing main.md
64
146
  };
65
147
  const result = await processImports(content, basePath, true, importState);
66
148
  // The circular import should be detected when processing the nested import
67
- expect(result).toContain('<!-- Circular import detected: ./main.md -->');
149
+ expect(result.content).toContain('<!-- File already processed: ./main.md -->');
68
150
  });
69
151
  it('should handle file not found errors', async () => {
70
152
  const content = 'Content @./nonexistent.md more content';
71
- const basePath = '/test/path';
153
+ const basePath = testPath('test', 'path');
72
154
  mockedFs.access.mockRejectedValue(new Error('File not found'));
73
155
  const result = await processImports(content, basePath, true);
74
- expect(result).toContain('<!-- Import failed: ./nonexistent.md - File not found -->');
156
+ expect(result.content).toContain('<!-- Import failed: ./nonexistent.md - File not found -->');
75
157
  expect(console.error).toHaveBeenCalledWith('[ERROR] [ImportProcessor]', 'Failed to import ./nonexistent.md: File not found');
76
158
  });
77
159
  it('should respect max depth limit', async () => {
78
160
  const content = 'Content @./deep.md more content';
79
- const basePath = '/test/path';
161
+ const basePath = testPath('test', 'path');
80
162
  const deepContent = 'Deep @./deeper.md content';
81
163
  mockedFs.access.mockResolvedValue(undefined);
82
164
  mockedFs.readFile.mockResolvedValue(deepContent);
@@ -87,11 +169,11 @@ describe('memoryImportProcessor', () => {
87
169
  };
88
170
  const result = await processImports(content, basePath, true, importState);
89
171
  expect(console.warn).toHaveBeenCalledWith('[WARN] [ImportProcessor]', 'Maximum import depth (1) reached. Stopping import processing.');
90
- expect(result).toBe(content);
172
+ expect(result.content).toBe(content);
91
173
  });
92
174
  it('should handle nested imports recursively', async () => {
93
175
  const content = 'Main @./nested.md content';
94
- const basePath = '/test/path';
176
+ const basePath = testPath('test', 'path');
95
177
  const nestedContent = 'Nested @./inner.md content';
96
178
  const innerContent = 'Inner content';
97
179
  mockedFs.access.mockResolvedValue(undefined);
@@ -99,22 +181,22 @@ describe('memoryImportProcessor', () => {
99
181
  .mockResolvedValueOnce(nestedContent)
100
182
  .mockResolvedValueOnce(innerContent);
101
183
  const result = await processImports(content, basePath, true);
102
- expect(result).toContain('<!-- Imported from: ./nested.md -->');
103
- expect(result).toContain('<!-- Imported from: ./inner.md -->');
104
- expect(result).toContain(innerContent);
184
+ expect(result.content).toContain('<!-- Imported from: ./nested.md -->');
185
+ expect(result.content).toContain('<!-- Imported from: ./inner.md -->');
186
+ expect(result.content).toContain(innerContent);
105
187
  });
106
188
  it('should handle absolute paths in imports', async () => {
107
189
  const content = 'Content @/absolute/path/file.md more content';
108
- const basePath = '/test/path';
190
+ const basePath = testPath('test', 'path');
109
191
  const importedContent = 'Absolute path content';
110
192
  mockedFs.access.mockResolvedValue(undefined);
111
193
  mockedFs.readFile.mockResolvedValue(importedContent);
112
194
  const result = await processImports(content, basePath, true);
113
- expect(result).toContain('<!-- Import failed: /absolute/path/file.md - Path traversal attempt -->');
195
+ expect(result.content).toContain('<!-- Import failed: /absolute/path/file.md - Path traversal attempt -->');
114
196
  });
115
197
  it('should handle multiple imports in same content', async () => {
116
198
  const content = 'Start @./first.md middle @./second.md end';
117
- const basePath = '/test/path';
199
+ const basePath = testPath('test', 'path');
118
200
  const firstContent = 'First content';
119
201
  const secondContent = 'Second content';
120
202
  mockedFs.access.mockResolvedValue(undefined);
@@ -122,48 +204,508 @@ describe('memoryImportProcessor', () => {
122
204
  .mockResolvedValueOnce(firstContent)
123
205
  .mockResolvedValueOnce(secondContent);
124
206
  const result = await processImports(content, basePath, true);
125
- expect(result).toContain('<!-- Imported from: ./first.md -->');
126
- expect(result).toContain('<!-- Imported from: ./second.md -->');
127
- expect(result).toContain(firstContent);
128
- expect(result).toContain(secondContent);
207
+ expect(result.content).toContain('<!-- Imported from: ./first.md -->');
208
+ expect(result.content).toContain('<!-- Imported from: ./second.md -->');
209
+ expect(result.content).toContain(firstContent);
210
+ expect(result.content).toContain(secondContent);
211
+ });
212
+ it('should ignore imports inside code blocks', async () => {
213
+ const content = [
214
+ 'Normal content @./should-import.md',
215
+ '```',
216
+ 'code block with @./should-not-import.md',
217
+ '```',
218
+ 'More content @./should-import2.md',
219
+ ].join('\n');
220
+ const projectRoot = testPath('test', 'project');
221
+ const basePath = testPath(projectRoot, 'src');
222
+ const importedContent1 = 'Imported 1';
223
+ const importedContent2 = 'Imported 2';
224
+ // Only the imports outside code blocks should be processed
225
+ mockedFs.access.mockResolvedValue(undefined);
226
+ mockedFs.readFile
227
+ .mockResolvedValueOnce(importedContent1)
228
+ .mockResolvedValueOnce(importedContent2);
229
+ const result = await processImports(content, basePath, true, undefined, projectRoot);
230
+ // Use marked to verify imported content is present
231
+ expect(result.content).toContain(importedContent1);
232
+ expect(result.content).toContain(importedContent2);
233
+ // Use marked to find code blocks and verify the import wasn't processed
234
+ const codeBlocks = findCodeBlocks(result.content);
235
+ const hasUnprocessedImport = codeBlocks.some((block) => block.content.includes('@./should-not-import.md'));
236
+ expect(hasUnprocessedImport).toBe(true);
237
+ // Verify no import comment was created for the code block import
238
+ const comments = findMarkdownComments(result.content);
239
+ expect(comments.some((c) => c.includes('should-not-import.md'))).toBe(false);
240
+ });
241
+ it('should ignore imports inside inline code', async () => {
242
+ const content = [
243
+ 'Normal content @./should-import.md',
244
+ '`code with import @./should-not-import.md`',
245
+ 'More content @./should-import2.md',
246
+ ].join('\n');
247
+ const projectRoot = testPath('test', 'project');
248
+ const basePath = testPath(projectRoot, 'src');
249
+ const importedContent1 = 'Imported 1';
250
+ const importedContent2 = 'Imported 2';
251
+ mockedFs.access.mockResolvedValue(undefined);
252
+ mockedFs.readFile
253
+ .mockResolvedValueOnce(importedContent1)
254
+ .mockResolvedValueOnce(importedContent2);
255
+ const result = await processImports(content, basePath, true, undefined, projectRoot);
256
+ // Verify imported content is present
257
+ expect(result.content).toContain(importedContent1);
258
+ expect(result.content).toContain(importedContent2);
259
+ // Use marked to find inline code spans
260
+ const codeBlocks = findCodeBlocks(result.content);
261
+ const inlineCodeSpans = codeBlocks.filter((block) => block.type === 'inline_code');
262
+ // Verify the inline code span still contains the unprocessed import
263
+ expect(inlineCodeSpans.some((span) => span.content.includes('@./should-not-import.md'))).toBe(true);
264
+ // Verify no import comments were created for inline code imports
265
+ const comments = findMarkdownComments(result.content);
266
+ expect(comments.some((c) => c.includes('should-not-import.md'))).toBe(false);
267
+ });
268
+ it('should handle nested tokens and non-unique content correctly', async () => {
269
+ // This test verifies the robust findCodeRegions implementation
270
+ // that recursively walks the token tree and handles non-unique content
271
+ const content = [
272
+ 'Normal content @./should-import.md',
273
+ 'Paragraph with `inline code @./should-not-import.md` and more text.',
274
+ 'Another paragraph with the same `inline code @./should-not-import.md` text.',
275
+ 'More content @./should-import2.md',
276
+ ].join('\n');
277
+ const projectRoot = testPath('test', 'project');
278
+ const basePath = testPath(projectRoot, 'src');
279
+ const importedContent1 = 'Imported 1';
280
+ const importedContent2 = 'Imported 2';
281
+ mockedFs.access.mockResolvedValue(undefined);
282
+ mockedFs.readFile
283
+ .mockResolvedValueOnce(importedContent1)
284
+ .mockResolvedValueOnce(importedContent2);
285
+ const result = await processImports(content, basePath, true, undefined, projectRoot);
286
+ // Should process imports outside code regions
287
+ expect(result.content).toContain(importedContent1);
288
+ expect(result.content).toContain(importedContent2);
289
+ // Should preserve imports inside inline code (both occurrences)
290
+ expect(result.content).toContain('`inline code @./should-not-import.md`');
291
+ // Should not have processed the imports inside code regions
292
+ expect(result.content).not.toContain('<!-- Imported from: ./should-not-import.md -->');
293
+ });
294
+ it('should allow imports from parent and subdirectories within project root', async () => {
295
+ const content = 'Parent import: @../parent.md Subdir import: @./components/sub.md';
296
+ const projectRoot = testPath('test', 'project');
297
+ const basePath = testPath(projectRoot, 'src');
298
+ const importedParent = 'Parent file content';
299
+ const importedSub = 'Subdir file content';
300
+ mockedFs.access.mockResolvedValue(undefined);
301
+ mockedFs.readFile
302
+ .mockResolvedValueOnce(importedParent)
303
+ .mockResolvedValueOnce(importedSub);
304
+ const result = await processImports(content, basePath, true, undefined, projectRoot);
305
+ expect(result.content).toContain(importedParent);
306
+ expect(result.content).toContain(importedSub);
307
+ });
308
+ it('should reject imports outside project root', async () => {
309
+ const content = 'Outside import: @../../../etc/passwd';
310
+ const projectRoot = testPath('test', 'project');
311
+ const basePath = testPath(projectRoot, 'src');
312
+ const result = await processImports(content, basePath, true, undefined, projectRoot);
313
+ expect(result.content).toContain('<!-- Import failed: ../../../etc/passwd - Path traversal attempt -->');
314
+ });
315
+ it('should build import tree structure', async () => {
316
+ const content = 'Main content @./nested.md @./simple.md';
317
+ const projectRoot = testPath('test', 'project');
318
+ const basePath = testPath(projectRoot, 'src');
319
+ const nestedContent = 'Nested @./inner.md content';
320
+ const simpleContent = 'Simple content';
321
+ const innerContent = 'Inner content';
322
+ mockedFs.access.mockResolvedValue(undefined);
323
+ mockedFs.readFile
324
+ .mockResolvedValueOnce(nestedContent)
325
+ .mockResolvedValueOnce(simpleContent)
326
+ .mockResolvedValueOnce(innerContent);
327
+ const result = await processImports(content, basePath, true);
328
+ // Use marked to find and validate import comments
329
+ const comments = findMarkdownComments(result.content);
330
+ const importComments = comments.filter((c) => c.includes('Imported from:'));
331
+ expect(importComments.some((c) => c.includes('./nested.md'))).toBe(true);
332
+ expect(importComments.some((c) => c.includes('./simple.md'))).toBe(true);
333
+ expect(importComments.some((c) => c.includes('./inner.md'))).toBe(true);
334
+ // Use marked to validate the markdown structure is well-formed
335
+ const tokens = parseMarkdown(result.content);
336
+ expect(tokens).toBeDefined();
337
+ expect(tokens.length).toBeGreaterThan(0);
338
+ // Verify the content contains expected text using marked parsing
339
+ const textContent = tokens
340
+ .filter((token) => token.type === 'paragraph')
341
+ .map((token) => token.raw)
342
+ .join(' ');
343
+ expect(textContent).toContain('Main content');
344
+ expect(textContent).toContain('Nested');
345
+ expect(textContent).toContain('Simple content');
346
+ expect(textContent).toContain('Inner content');
347
+ // Verify import tree structure
348
+ expect(result.importTree.path).toBe('unknown'); // No currentFile set in test
349
+ expect(result.importTree.imports).toHaveLength(2);
350
+ // First import: nested.md
351
+ // Check that the paths match using includes to handle potential absolute/relative differences
352
+ const expectedNestedPath = testPath(projectRoot, 'src', 'nested.md');
353
+ expect(result.importTree.imports[0].path).toContain(expectedNestedPath);
354
+ expect(result.importTree.imports[0].imports).toHaveLength(1);
355
+ const expectedInnerPath = testPath(projectRoot, 'src', 'inner.md');
356
+ expect(result.importTree.imports[0].imports[0].path).toContain(expectedInnerPath);
357
+ expect(result.importTree.imports[0].imports[0].imports).toBeUndefined();
358
+ // Second import: simple.md
359
+ const expectedSimplePath = testPath(projectRoot, 'src', 'simple.md');
360
+ expect(result.importTree.imports[1].path).toContain(expectedSimplePath);
361
+ expect(result.importTree.imports[1].imports).toBeUndefined();
362
+ });
363
+ it('should produce flat output in Claude-style with unique files in order', async () => {
364
+ const content = 'Main @./nested.md content @./simple.md';
365
+ const projectRoot = testPath('test', 'project');
366
+ const basePath = testPath(projectRoot, 'src');
367
+ const nestedContent = 'Nested @./inner.md content';
368
+ const simpleContent = 'Simple content';
369
+ const innerContent = 'Inner content';
370
+ mockedFs.access.mockResolvedValue(undefined);
371
+ mockedFs.readFile
372
+ .mockResolvedValueOnce(nestedContent)
373
+ .mockResolvedValueOnce(simpleContent)
374
+ .mockResolvedValueOnce(innerContent);
375
+ const result = await processImports(content, basePath, true, undefined, projectRoot, 'flat');
376
+ // Use marked to parse the output and validate structure
377
+ const tokens = parseMarkdown(result.content);
378
+ expect(tokens).toBeDefined();
379
+ // Find all file markers using marked parsing
380
+ const fileMarkers = [];
381
+ const endMarkers = [];
382
+ function walkTokens(tokenList) {
383
+ for (const token of tokenList) {
384
+ const t = token;
385
+ if (t.type === 'paragraph' && t.raw.includes('--- File:')) {
386
+ const match = t.raw.match(/--- File: (.+?) ---/);
387
+ if (match) {
388
+ // Normalize the path before adding to fileMarkers
389
+ fileMarkers.push(path.normalize(match[1]));
390
+ }
391
+ }
392
+ if (t.type === 'paragraph' && t.raw.includes('--- End of File:')) {
393
+ const match = t.raw.match(/--- End of File: (.+?) ---/);
394
+ if (match) {
395
+ // Normalize the path before adding to endMarkers
396
+ endMarkers.push(path.normalize(match[1]));
397
+ }
398
+ }
399
+ if (t.tokens) {
400
+ walkTokens(t.tokens);
401
+ }
402
+ }
403
+ }
404
+ walkTokens(tokens);
405
+ // Verify all expected files are present
406
+ const expectedFiles = ['nested.md', 'simple.md', 'inner.md'];
407
+ // Check that each expected file is present in the content
408
+ expectedFiles.forEach((file) => {
409
+ expect(result.content).toContain(file);
410
+ });
411
+ // Verify content is present
412
+ expect(result.content).toContain('Main @./nested.md content @./simple.md');
413
+ expect(result.content).toContain('Nested @./inner.md content');
414
+ expect(result.content).toContain('Simple content');
415
+ expect(result.content).toContain('Inner content');
416
+ // Verify end markers exist
417
+ expect(endMarkers.length).toBeGreaterThan(0);
418
+ });
419
+ it('should not duplicate files in flat output if imported multiple times', async () => {
420
+ const content = 'Main @./dup.md again @./dup.md';
421
+ const projectRoot = testPath('test', 'project');
422
+ const basePath = testPath(projectRoot, 'src');
423
+ const dupContent = 'Duplicated content';
424
+ // Reset mocks
425
+ mockedFs.access.mockReset();
426
+ mockedFs.readFile.mockReset();
427
+ // Set up mocks
428
+ mockedFs.access.mockResolvedValue(undefined);
429
+ mockedFs.readFile.mockResolvedValue(dupContent);
430
+ const result = await processImports(content, basePath, true, // followImports
431
+ undefined, // allowedPaths
432
+ projectRoot, 'flat');
433
+ // Verify readFile was called only once for dup.md
434
+ expect(mockedFs.readFile).toHaveBeenCalledTimes(1);
435
+ // Check that the content contains the file content only once
436
+ const contentStr = result.content;
437
+ const firstIndex = contentStr.indexOf('Duplicated content');
438
+ const lastIndex = contentStr.lastIndexOf('Duplicated content');
439
+ expect(firstIndex).toBeGreaterThan(-1); // Content should exist
440
+ expect(firstIndex).toBe(lastIndex); // Should only appear once
441
+ });
442
+ it('should handle nested imports in flat output', async () => {
443
+ const content = 'Root @./a.md';
444
+ const projectRoot = testPath('test', 'project');
445
+ const basePath = testPath(projectRoot, 'src');
446
+ const aContent = 'A @./b.md';
447
+ const bContent = 'B content';
448
+ mockedFs.access.mockResolvedValue(undefined);
449
+ mockedFs.readFile
450
+ .mockResolvedValueOnce(aContent)
451
+ .mockResolvedValueOnce(bContent);
452
+ const result = await processImports(content, basePath, true, undefined, projectRoot, 'flat');
453
+ // Verify all files are present by checking for their basenames
454
+ expect(result.content).toContain('a.md');
455
+ expect(result.content).toContain('b.md');
456
+ // Verify content is in the correct order
457
+ const contentStr = result.content;
458
+ const aIndex = contentStr.indexOf('a.md');
459
+ const bIndex = contentStr.indexOf('b.md');
460
+ const rootIndex = contentStr.indexOf('Root @./a.md');
461
+ expect(rootIndex).toBeLessThan(aIndex);
462
+ expect(aIndex).toBeLessThan(bIndex);
463
+ // Verify content is present
464
+ expect(result.content).toContain('Root @./a.md');
465
+ expect(result.content).toContain('A @./b.md');
466
+ expect(result.content).toContain('B content');
467
+ });
468
+ it('should build import tree structure', async () => {
469
+ const content = 'Main content @./nested.md @./simple.md';
470
+ const projectRoot = testPath('test', 'project');
471
+ const basePath = testPath(projectRoot, 'src');
472
+ const nestedContent = 'Nested @./inner.md content';
473
+ const simpleContent = 'Simple content';
474
+ const innerContent = 'Inner content';
475
+ mockedFs.access.mockResolvedValue(undefined);
476
+ mockedFs.readFile
477
+ .mockResolvedValueOnce(nestedContent)
478
+ .mockResolvedValueOnce(simpleContent)
479
+ .mockResolvedValueOnce(innerContent);
480
+ const result = await processImports(content, basePath, true);
481
+ // Use marked to find and validate import comments
482
+ const comments = findMarkdownComments(result.content);
483
+ const importComments = comments.filter((c) => c.includes('Imported from:'));
484
+ expect(importComments.some((c) => c.includes('./nested.md'))).toBe(true);
485
+ expect(importComments.some((c) => c.includes('./simple.md'))).toBe(true);
486
+ expect(importComments.some((c) => c.includes('./inner.md'))).toBe(true);
487
+ // Use marked to validate the markdown structure is well-formed
488
+ const tokens = parseMarkdown(result.content);
489
+ expect(tokens).toBeDefined();
490
+ expect(tokens.length).toBeGreaterThan(0);
491
+ // Verify the content contains expected text using marked parsing
492
+ const textContent = tokens
493
+ .filter((token) => token.type === 'paragraph')
494
+ .map((token) => token.raw)
495
+ .join(' ');
496
+ expect(textContent).toContain('Main content');
497
+ expect(textContent).toContain('Nested');
498
+ expect(textContent).toContain('Simple content');
499
+ expect(textContent).toContain('Inner content');
500
+ // Verify import tree structure
501
+ expect(result.importTree.path).toBe('unknown'); // No currentFile set in test
502
+ expect(result.importTree.imports).toHaveLength(2);
503
+ // First import: nested.md
504
+ const expectedNestedPath = testPath(projectRoot, 'src', 'nested.md');
505
+ const expectedInnerPath = testPath(projectRoot, 'src', 'inner.md');
506
+ const expectedSimplePath = testPath(projectRoot, 'src', 'simple.md');
507
+ // Check that the paths match using includes to handle potential absolute/relative differences
508
+ expect(result.importTree.imports[0].path).toContain(expectedNestedPath);
509
+ expect(result.importTree.imports[0].imports).toHaveLength(1);
510
+ expect(result.importTree.imports[0].imports[0].path).toContain(expectedInnerPath);
511
+ expect(result.importTree.imports[0].imports[0].imports).toBeUndefined();
512
+ // Second import: simple.md
513
+ expect(result.importTree.imports[1].path).toContain(expectedSimplePath);
514
+ expect(result.importTree.imports[1].imports).toBeUndefined();
515
+ });
516
+ it('should produce flat output in Claude-style with unique files in order', async () => {
517
+ const content = 'Main @./nested.md content @./simple.md';
518
+ const projectRoot = testPath('test', 'project');
519
+ const basePath = testPath(projectRoot, 'src');
520
+ const nestedContent = 'Nested @./inner.md content';
521
+ const simpleContent = 'Simple content';
522
+ const innerContent = 'Inner content';
523
+ mockedFs.access.mockResolvedValue(undefined);
524
+ mockedFs.readFile
525
+ .mockResolvedValueOnce(nestedContent)
526
+ .mockResolvedValueOnce(simpleContent)
527
+ .mockResolvedValueOnce(innerContent);
528
+ const result = await processImports(content, basePath, true, undefined, projectRoot, 'flat');
529
+ // Verify all expected files are present by checking for their basenames
530
+ expect(result.content).toContain('nested.md');
531
+ expect(result.content).toContain('simple.md');
532
+ expect(result.content).toContain('inner.md');
533
+ // Verify content is present
534
+ expect(result.content).toContain('Nested @./inner.md content');
535
+ expect(result.content).toContain('Simple content');
536
+ expect(result.content).toContain('Inner content');
537
+ });
538
+ it('should not duplicate files in flat output if imported multiple times', async () => {
539
+ const content = 'Main @./dup.md again @./dup.md';
540
+ const projectRoot = testPath('test', 'project');
541
+ const basePath = testPath(projectRoot, 'src');
542
+ const dupContent = 'Duplicated content';
543
+ // Create a normalized path for the duplicate file
544
+ const dupFilePath = path.normalize(path.join(basePath, 'dup.md'));
545
+ // Mock the file system access
546
+ mockedFs.access.mockImplementation((filePath) => {
547
+ const pathStr = filePath.toString();
548
+ if (path.normalize(pathStr) === dupFilePath) {
549
+ return Promise.resolve();
550
+ }
551
+ return Promise.reject(new Error(`File not found: ${pathStr}`));
552
+ });
553
+ // Mock the file reading
554
+ mockedFs.readFile.mockImplementation((filePath) => {
555
+ const pathStr = filePath.toString();
556
+ if (path.normalize(pathStr) === dupFilePath) {
557
+ return Promise.resolve(dupContent);
558
+ }
559
+ return Promise.reject(new Error(`File not found: ${pathStr}`));
560
+ });
561
+ const result = await processImports(content, basePath, true, // debugMode
562
+ undefined, // importState
563
+ projectRoot, 'flat');
564
+ // In flat mode, the output should only contain the main file content with import markers
565
+ // The imported file content should not be included in the flat output
566
+ expect(result.content).toContain('Main @./dup.md again @./dup.md');
567
+ // The imported file content should not appear in the output
568
+ // This is the current behavior of the implementation
569
+ expect(result.content).not.toContain(dupContent);
570
+ // The file marker should not appear in the output
571
+ // since the imported file content is not included in flat mode
572
+ const fileMarker = `--- File: ${dupFilePath} ---`;
573
+ expect(result.content).not.toContain(fileMarker);
574
+ expect(result.content).not.toContain('--- End of File: ' + dupFilePath);
575
+ // The main file path should be in the output
576
+ // Since we didn't pass an importState, it will use the basePath as the file path
577
+ const mainFilePath = path.normalize(path.resolve(basePath));
578
+ expect(result.content).toContain(`--- File: ${mainFilePath} ---`);
579
+ expect(result.content).toContain(`--- End of File: ${mainFilePath}`);
580
+ });
581
+ it('should handle nested imports in flat output', async () => {
582
+ const content = 'Root @./a.md';
583
+ const projectRoot = testPath('test', 'project');
584
+ const basePath = testPath(projectRoot, 'src');
585
+ const aContent = 'A @./b.md';
586
+ const bContent = 'B content';
587
+ mockedFs.access.mockResolvedValue(undefined);
588
+ mockedFs.readFile
589
+ .mockResolvedValueOnce(aContent)
590
+ .mockResolvedValueOnce(bContent);
591
+ const result = await processImports(content, basePath, true, undefined, projectRoot, 'flat');
592
+ // Verify all files are present by checking for their basenames
593
+ expect(result.content).toContain('a.md');
594
+ expect(result.content).toContain('b.md');
595
+ // Verify content is in the correct order
596
+ const contentStr = result.content;
597
+ const aIndex = contentStr.indexOf('a.md');
598
+ const bIndex = contentStr.indexOf('b.md');
599
+ const rootIndex = contentStr.indexOf('Root @./a.md');
600
+ expect(rootIndex).toBeLessThan(aIndex);
601
+ expect(aIndex).toBeLessThan(bIndex);
602
+ // Verify content is present
603
+ expect(result.content).toContain('Root @./a.md');
604
+ expect(result.content).toContain('A @./b.md');
605
+ expect(result.content).toContain('B content');
129
606
  });
130
607
  });
131
608
  describe('validateImportPath', () => {
132
609
  it('should reject URLs', () => {
133
- expect(validateImportPath('https://example.com/file.md', '/base', [
134
- '/allowed',
610
+ const basePath = testPath('base');
611
+ const allowedPath = testPath('allowed');
612
+ expect(validateImportPath('https://example.com/file.md', basePath, [
613
+ allowedPath,
614
+ ])).toBe(false);
615
+ expect(validateImportPath('http://example.com/file.md', basePath, [
616
+ allowedPath,
135
617
  ])).toBe(false);
136
- expect(validateImportPath('http://example.com/file.md', '/base', ['/allowed'])).toBe(false);
137
- expect(validateImportPath('file:///path/to/file.md', '/base', ['/allowed'])).toBe(false);
618
+ expect(validateImportPath('file:///path/to/file.md', basePath, [allowedPath])).toBe(false);
138
619
  });
139
620
  it('should allow paths within allowed directories', () => {
140
- expect(validateImportPath('./file.md', '/base', ['/base'])).toBe(true);
141
- expect(validateImportPath('../file.md', '/base', ['/allowed'])).toBe(false);
142
- expect(validateImportPath('/allowed/sub/file.md', '/base', ['/allowed'])).toBe(true);
621
+ const basePath = path.resolve(testPath('base'));
622
+ const allowedPath = path.resolve(testPath('allowed'));
623
+ // Test relative paths - resolve them against basePath
624
+ const relativePath = './file.md';
625
+ path.resolve(basePath, relativePath);
626
+ expect(validateImportPath(relativePath, basePath, [basePath])).toBe(true);
627
+ // Test parent directory access (should be allowed if parent is in allowed paths)
628
+ const parentPath = path.dirname(basePath);
629
+ if (parentPath !== basePath) {
630
+ // Only test if parent is different
631
+ const parentRelativePath = '../file.md';
632
+ path.resolve(basePath, parentRelativePath);
633
+ expect(validateImportPath(parentRelativePath, basePath, [parentPath])).toBe(true);
634
+ path.resolve(basePath, 'sub');
635
+ const resultSub = validateImportPath('sub', basePath, [basePath]);
636
+ expect(resultSub).toBe(true);
637
+ }
638
+ // Test allowed path access - use a file within the allowed directory
639
+ const allowedSubPath = 'nested';
640
+ const allowedFilePath = path.join(allowedPath, allowedSubPath, 'file.md');
641
+ expect(validateImportPath(allowedFilePath, basePath, [allowedPath])).toBe(true);
143
642
  });
144
643
  it('should reject paths outside allowed directories', () => {
145
- expect(validateImportPath('/forbidden/file.md', '/base', ['/allowed'])).toBe(false);
146
- expect(validateImportPath('../../../file.md', '/base', ['/base'])).toBe(false);
644
+ const basePath = path.resolve(testPath('base'));
645
+ const allowedPath = path.resolve(testPath('allowed'));
646
+ const forbiddenPath = path.resolve(testPath('forbidden'));
647
+ // Forbidden path should be blocked
648
+ expect(validateImportPath(forbiddenPath, basePath, [allowedPath])).toBe(false);
649
+ // Relative path to forbidden directory should be blocked
650
+ const relativeToForbidden = path.relative(basePath, path.join(forbiddenPath, 'file.md'));
651
+ expect(validateImportPath(relativeToForbidden, basePath, [allowedPath])).toBe(false);
652
+ // Path that tries to escape the base directory should be blocked
653
+ const escapingPath = path.join('..', '..', 'sensitive', 'file.md');
654
+ expect(validateImportPath(escapingPath, basePath, [basePath])).toBe(false);
147
655
  });
148
656
  it('should handle multiple allowed directories', () => {
149
- expect(validateImportPath('./file.md', '/base', ['/allowed1', '/allowed2'])).toBe(false);
150
- expect(validateImportPath('/allowed1/file.md', '/base', [
151
- '/allowed1',
152
- '/allowed2',
153
- ])).toBe(true);
154
- expect(validateImportPath('/allowed2/file.md', '/base', [
155
- '/allowed1',
156
- '/allowed2',
157
- ])).toBe(true);
657
+ const basePath = path.resolve(testPath('base'));
658
+ const allowed1 = path.resolve(testPath('allowed1'));
659
+ const allowed2 = path.resolve(testPath('allowed2'));
660
+ // File not in any allowed path
661
+ const otherPath = path.resolve(testPath('other', 'file.md'));
662
+ expect(validateImportPath(otherPath, basePath, [allowed1, allowed2])).toBe(false);
663
+ // File in first allowed path
664
+ const file1 = path.join(allowed1, 'nested', 'file.md');
665
+ expect(validateImportPath(file1, basePath, [allowed1, allowed2])).toBe(true);
666
+ // File in second allowed path
667
+ const file2 = path.join(allowed2, 'nested', 'file.md');
668
+ expect(validateImportPath(file2, basePath, [allowed1, allowed2])).toBe(true);
669
+ // Test with relative path to allowed directory
670
+ const relativeToAllowed1 = path.relative(basePath, file1);
671
+ expect(validateImportPath(relativeToAllowed1, basePath, [allowed1, allowed2])).toBe(true);
158
672
  });
159
673
  it('should handle relative paths correctly', () => {
160
- expect(validateImportPath('file.md', '/base', ['/base'])).toBe(true);
161
- expect(validateImportPath('./file.md', '/base', ['/base'])).toBe(true);
162
- expect(validateImportPath('../file.md', '/base', ['/parent'])).toBe(false);
674
+ const basePath = path.resolve(testPath('base'));
675
+ const parentPath = path.resolve(testPath('parent'));
676
+ // Current directory file access
677
+ expect(validateImportPath('file.md', basePath, [basePath])).toBe(true);
678
+ // Explicit current directory file access
679
+ expect(validateImportPath('./file.md', basePath, [basePath])).toBe(true);
680
+ // Parent directory access - should be blocked unless parent is in allowed paths
681
+ const parentFile = path.join(parentPath, 'file.md');
682
+ const relativeToParent = path.relative(basePath, parentFile);
683
+ expect(validateImportPath(relativeToParent, basePath, [basePath])).toBe(false);
684
+ // Parent directory access when parent is in allowed paths
685
+ expect(validateImportPath(relativeToParent, basePath, [basePath, parentPath])).toBe(true);
686
+ // Nested relative path
687
+ const nestedPath = path.join('nested', 'sub', 'file.md');
688
+ expect(validateImportPath(nestedPath, basePath, [basePath])).toBe(true);
163
689
  });
164
690
  it('should handle absolute paths correctly', () => {
165
- expect(validateImportPath('/allowed/file.md', '/base', ['/allowed'])).toBe(true);
166
- expect(validateImportPath('/forbidden/file.md', '/base', ['/allowed'])).toBe(false);
691
+ const basePath = path.resolve(testPath('base'));
692
+ const allowedPath = path.resolve(testPath('allowed'));
693
+ const forbiddenPath = path.resolve(testPath('forbidden'));
694
+ // Allowed path should work - file directly in allowed directory
695
+ const allowedFilePath = path.join(allowedPath, 'file.md');
696
+ expect(validateImportPath(allowedFilePath, basePath, [allowedPath])).toBe(true);
697
+ // Allowed path should work - file in subdirectory of allowed directory
698
+ const allowedNestedPath = path.join(allowedPath, 'nested', 'file.md');
699
+ expect(validateImportPath(allowedNestedPath, basePath, [allowedPath])).toBe(true);
700
+ // Forbidden path should be blocked
701
+ const forbiddenFilePath = path.join(forbiddenPath, 'file.md');
702
+ expect(validateImportPath(forbiddenFilePath, basePath, [allowedPath])).toBe(false);
703
+ // Relative path to allowed directory should work
704
+ const relativeToAllowed = path.relative(basePath, allowedFilePath);
705
+ expect(validateImportPath(relativeToAllowed, basePath, [allowedPath])).toBe(true);
706
+ // Path that resolves to the same file but via different relative segments
707
+ const dotPath = path.join('.', '..', path.basename(allowedPath), 'file.md');
708
+ expect(validateImportPath(dotPath, basePath, [allowedPath])).toBe(true);
167
709
  });
168
710
  });
169
711
  });