@qduc/term2 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (621) hide show
  1. package/LICENSE +21 -0
  2. package/dist/agent.d.ts +19 -0
  3. package/dist/agent.d.ts.map +1 -0
  4. package/dist/agent.js +143 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/app.d.ts +22 -0
  7. package/dist/app.d.ts.map +1 -0
  8. package/dist/app.js +403 -0
  9. package/dist/app.js.map +1 -0
  10. package/dist/app.model-command-feedback.test.d.ts +2 -0
  11. package/dist/app.model-command-feedback.test.d.ts.map +1 -0
  12. package/dist/app.model-command-feedback.test.js +19 -0
  13. package/dist/app.model-command-feedback.test.js.map +1 -0
  14. package/dist/app.parseInput.test.d.ts +2 -0
  15. package/dist/app.parseInput.test.d.ts.map +1 -0
  16. package/dist/app.parseInput.test.js +97 -0
  17. package/dist/app.parseInput.test.js.map +1 -0
  18. package/dist/cli.d.ts +3 -0
  19. package/dist/cli.d.ts.map +1 -0
  20. package/dist/cli.js +241 -0
  21. package/dist/cli.js.map +1 -0
  22. package/dist/components/ApprovalPrompt.d.ts +10 -0
  23. package/dist/components/ApprovalPrompt.d.ts.map +1 -0
  24. package/dist/components/ApprovalPrompt.js +163 -0
  25. package/dist/components/ApprovalPrompt.js.map +1 -0
  26. package/dist/components/Banner.d.ts +9 -0
  27. package/dist/components/Banner.d.ts.map +1 -0
  28. package/dist/components/Banner.js +86 -0
  29. package/dist/components/Banner.js.map +1 -0
  30. package/dist/components/BottomArea.d.ts +33 -0
  31. package/dist/components/BottomArea.d.ts.map +1 -0
  32. package/dist/components/BottomArea.js +31 -0
  33. package/dist/components/BottomArea.js.map +1 -0
  34. package/dist/components/BottomArea.test.d.ts +2 -0
  35. package/dist/components/BottomArea.test.d.ts.map +1 -0
  36. package/dist/components/BottomArea.test.js +73 -0
  37. package/dist/components/BottomArea.test.js.map +1 -0
  38. package/dist/components/ChatMessage.d.ts +7 -0
  39. package/dist/components/ChatMessage.d.ts.map +1 -0
  40. package/dist/components/ChatMessage.js +10 -0
  41. package/dist/components/ChatMessage.js.map +1 -0
  42. package/dist/components/CommandMessage.d.ts +15 -0
  43. package/dist/components/CommandMessage.d.ts.map +1 -0
  44. package/dist/components/CommandMessage.js +188 -0
  45. package/dist/components/CommandMessage.js.map +1 -0
  46. package/dist/components/CommandMessage.test.d.ts +2 -0
  47. package/dist/components/CommandMessage.test.d.ts.map +1 -0
  48. package/dist/components/CommandMessage.test.js +35 -0
  49. package/dist/components/CommandMessage.test.js.map +1 -0
  50. package/dist/components/ErrorBoundary.d.ts +27 -0
  51. package/dist/components/ErrorBoundary.d.ts.map +1 -0
  52. package/dist/components/ErrorBoundary.js +77 -0
  53. package/dist/components/ErrorBoundary.js.map +1 -0
  54. package/dist/components/ErrorBoundary.test.d.ts +2 -0
  55. package/dist/components/ErrorBoundary.test.d.ts.map +1 -0
  56. package/dist/components/ErrorBoundary.test.js +32 -0
  57. package/dist/components/ErrorBoundary.test.js.map +1 -0
  58. package/dist/components/Input/PopupManager.d.ts +42 -0
  59. package/dist/components/Input/PopupManager.d.ts.map +1 -0
  60. package/dist/components/Input/PopupManager.js +13 -0
  61. package/dist/components/Input/PopupManager.js.map +1 -0
  62. package/dist/components/InputBox.d.ts +18 -0
  63. package/dist/components/InputBox.d.ts.map +1 -0
  64. package/dist/components/InputBox.js +384 -0
  65. package/dist/components/InputBox.js.map +1 -0
  66. package/dist/components/InputBox.menu-logic.test.d.ts +2 -0
  67. package/dist/components/InputBox.menu-logic.test.d.ts.map +1 -0
  68. package/dist/components/InputBox.menu-logic.test.js +151 -0
  69. package/dist/components/InputBox.menu-logic.test.js.map +1 -0
  70. package/dist/components/InputBox.test.d.ts +2 -0
  71. package/dist/components/InputBox.test.d.ts.map +1 -0
  72. package/dist/components/InputBox.test.js +91 -0
  73. package/dist/components/InputBox.test.js.map +1 -0
  74. package/dist/components/LiveResponse.d.ts +13 -0
  75. package/dist/components/LiveResponse.d.ts.map +1 -0
  76. package/dist/components/LiveResponse.js +16 -0
  77. package/dist/components/LiveResponse.js.map +1 -0
  78. package/dist/components/MarkdownRenderer.d.ts +8 -0
  79. package/dist/components/MarkdownRenderer.d.ts.map +1 -0
  80. package/dist/components/MarkdownRenderer.js +225 -0
  81. package/dist/components/MarkdownRenderer.js.map +1 -0
  82. package/dist/components/MentorMode.test.d.ts +2 -0
  83. package/dist/components/MentorMode.test.d.ts.map +1 -0
  84. package/dist/components/MentorMode.test.js.map +1 -0
  85. package/dist/components/MessageList.d.ts +7 -0
  86. package/dist/components/MessageList.d.ts.map +1 -0
  87. package/dist/components/MessageList.js +29 -0
  88. package/dist/components/MessageList.js.map +1 -0
  89. package/dist/components/MessageList.test.d.ts +2 -0
  90. package/dist/components/MessageList.test.d.ts.map +1 -0
  91. package/dist/components/MessageList.test.js +15 -0
  92. package/dist/components/MessageList.test.js.map +1 -0
  93. package/dist/components/ModelSelectionMenu.d.ts +18 -0
  94. package/dist/components/ModelSelectionMenu.d.ts.map +1 -0
  95. package/dist/components/ModelSelectionMenu.js +91 -0
  96. package/dist/components/ModelSelectionMenu.js.map +1 -0
  97. package/dist/components/ModelSelectionMenu.test.d.ts +2 -0
  98. package/dist/components/ModelSelectionMenu.test.d.ts.map +1 -0
  99. package/dist/components/ModelSelectionMenu.test.js +83 -0
  100. package/dist/components/ModelSelectionMenu.test.js.map +1 -0
  101. package/dist/components/PathSelectionMenu.d.ts +12 -0
  102. package/dist/components/PathSelectionMenu.d.ts.map +1 -0
  103. package/dist/components/PathSelectionMenu.js +42 -0
  104. package/dist/components/PathSelectionMenu.js.map +1 -0
  105. package/dist/components/SettingsSelectionMenu.d.ts +9 -0
  106. package/dist/components/SettingsSelectionMenu.d.ts.map +1 -0
  107. package/dist/components/SettingsSelectionMenu.js +21 -0
  108. package/dist/components/SettingsSelectionMenu.js.map +1 -0
  109. package/dist/components/SlashCommandMenu.d.ts +15 -0
  110. package/dist/components/SlashCommandMenu.d.ts.map +1 -0
  111. package/dist/components/SlashCommandMenu.js +20 -0
  112. package/dist/components/SlashCommandMenu.js.map +1 -0
  113. package/dist/components/StatusBar.d.ts +11 -0
  114. package/dist/components/StatusBar.d.ts.map +1 -0
  115. package/dist/components/StatusBar.js +59 -0
  116. package/dist/components/StatusBar.js.map +1 -0
  117. package/dist/components/TextInput.d.ts +42 -0
  118. package/dist/components/TextInput.d.ts.map +1 -0
  119. package/dist/components/TextInput.js +397 -0
  120. package/dist/components/TextInput.js.map +1 -0
  121. package/dist/components/TextInput.test.d.ts +2 -0
  122. package/dist/components/TextInput.test.d.ts.map +1 -0
  123. package/dist/components/TextInput.test.js +75 -0
  124. package/dist/components/TextInput.test.js.map +1 -0
  125. package/dist/context/InputContext.d.ts +31 -0
  126. package/dist/context/InputContext.d.ts.map +1 -0
  127. package/dist/context/InputContext.js +36 -0
  128. package/dist/context/InputContext.js.map +1 -0
  129. package/dist/context/InputContext.stability.test.d.ts +2 -0
  130. package/dist/context/InputContext.stability.test.d.ts.map +1 -0
  131. package/dist/context/InputContext.stability.test.js +28 -0
  132. package/dist/context/InputContext.stability.test.js.map +1 -0
  133. package/dist/context/InputContext.test.d.ts +2 -0
  134. package/dist/context/InputContext.test.d.ts.map +1 -0
  135. package/dist/context/InputContext.test.js +168 -0
  136. package/dist/context/InputContext.test.js.map +1 -0
  137. package/dist/debug-schema.d.ts +2 -0
  138. package/dist/debug-schema.d.ts.map +1 -0
  139. package/dist/debug-schema.js +22 -0
  140. package/dist/debug-schema.js.map +1 -0
  141. package/dist/hooks/use-conversation.d.ts +78 -0
  142. package/dist/hooks/use-conversation.d.ts.map +1 -0
  143. package/dist/hooks/use-conversation.js +1017 -0
  144. package/dist/hooks/use-conversation.js.map +1 -0
  145. package/dist/hooks/use-input-history.d.ts +16 -0
  146. package/dist/hooks/use-input-history.d.ts.map +1 -0
  147. package/dist/hooks/use-input-history.js +71 -0
  148. package/dist/hooks/use-input-history.js.map +1 -0
  149. package/dist/hooks/use-model-selection.d.ts +27 -0
  150. package/dist/hooks/use-model-selection.d.ts.map +1 -0
  151. package/dist/hooks/use-model-selection.js +187 -0
  152. package/dist/hooks/use-model-selection.js.map +1 -0
  153. package/dist/hooks/use-model-selection.test.d.ts +2 -0
  154. package/dist/hooks/use-model-selection.test.d.ts.map +1 -0
  155. package/dist/hooks/use-model-selection.test.js +28 -0
  156. package/dist/hooks/use-model-selection.test.js.map +1 -0
  157. package/dist/hooks/use-path-completion.d.ts +22 -0
  158. package/dist/hooks/use-path-completion.d.ts.map +1 -0
  159. package/dist/hooks/use-path-completion.js +153 -0
  160. package/dist/hooks/use-path-completion.js.map +1 -0
  161. package/dist/hooks/use-path-completion.test.d.ts +2 -0
  162. package/dist/hooks/use-path-completion.test.d.ts.map +1 -0
  163. package/dist/hooks/use-path-completion.test.js +29 -0
  164. package/dist/hooks/use-path-completion.test.js.map +1 -0
  165. package/dist/hooks/use-setting.d.ts +7 -0
  166. package/dist/hooks/use-setting.d.ts.map +1 -0
  167. package/dist/hooks/use-setting.js +35 -0
  168. package/dist/hooks/use-setting.js.map +1 -0
  169. package/dist/hooks/use-settings-completion.d.ts +23 -0
  170. package/dist/hooks/use-settings-completion.d.ts.map +1 -0
  171. package/dist/hooks/use-settings-completion.js +164 -0
  172. package/dist/hooks/use-settings-completion.js.map +1 -0
  173. package/dist/hooks/use-settings-completion.test.d.ts +2 -0
  174. package/dist/hooks/use-settings-completion.test.d.ts.map +1 -0
  175. package/dist/hooks/use-settings-completion.test.js +334 -0
  176. package/dist/hooks/use-settings-completion.test.js.map +1 -0
  177. package/dist/hooks/use-slash-commands.d.ts +21 -0
  178. package/dist/hooks/use-slash-commands.d.ts.map +1 -0
  179. package/dist/hooks/use-slash-commands.js +87 -0
  180. package/dist/hooks/use-slash-commands.js.map +1 -0
  181. package/dist/hooks/use-slash-commands.test.d.ts +2 -0
  182. package/dist/hooks/use-slash-commands.test.d.ts.map +1 -0
  183. package/dist/hooks/use-slash-commands.test.js +246 -0
  184. package/dist/hooks/use-slash-commands.test.js.map +1 -0
  185. package/dist/lib/editor-impl.d.ts +23 -0
  186. package/dist/lib/editor-impl.d.ts.map +1 -0
  187. package/dist/lib/editor-impl.js +235 -0
  188. package/dist/lib/editor-impl.js.map +1 -0
  189. package/dist/lib/openai-agent-client.chat.test.d.ts +2 -0
  190. package/dist/lib/openai-agent-client.chat.test.d.ts.map +1 -0
  191. package/dist/lib/openai-agent-client.chat.test.js +68 -0
  192. package/dist/lib/openai-agent-client.chat.test.js.map +1 -0
  193. package/dist/lib/openai-agent-client.d.ts +48 -0
  194. package/dist/lib/openai-agent-client.d.ts.map +1 -0
  195. package/dist/lib/openai-agent-client.js +653 -0
  196. package/dist/lib/openai-agent-client.js.map +1 -0
  197. package/dist/lib/openai-agent-client.test.d.ts +2 -0
  198. package/dist/lib/openai-agent-client.test.d.ts.map +1 -0
  199. package/dist/lib/openai-agent-client.test.js +181 -0
  200. package/dist/lib/openai-agent-client.test.js.map +1 -0
  201. package/dist/lib/shell.d.ts +7 -0
  202. package/dist/lib/shell.d.ts.map +1 -0
  203. package/dist/lib/shell.js +56 -0
  204. package/dist/lib/shell.js.map +1 -0
  205. package/dist/lib/tool-invoke.d.ts +4 -0
  206. package/dist/lib/tool-invoke.d.ts.map +1 -0
  207. package/dist/lib/tool-invoke.js +26 -0
  208. package/dist/lib/tool-invoke.js.map +1 -0
  209. package/dist/lib/tool-invoke.test.d.ts +2 -0
  210. package/dist/lib/tool-invoke.test.d.ts.map +1 -0
  211. package/dist/lib/tool-invoke.test.js +19 -0
  212. package/dist/lib/tool-invoke.test.js.map +1 -0
  213. package/dist/no-singleton-imports.test.d.ts +2 -0
  214. package/dist/no-singleton-imports.test.d.ts.map +1 -0
  215. package/dist/no-singleton-imports.test.js +30 -0
  216. package/dist/no-singleton-imports.test.js.map +1 -0
  217. package/dist/prompts/anthropic.md +79 -0
  218. package/dist/prompts/codex.md +97 -0
  219. package/dist/prompts/default.md +77 -0
  220. package/dist/prompts/default.md.bak +77 -0
  221. package/dist/prompts/gpt-5.md +318 -0
  222. package/dist/prompts/lite.md +29 -0
  223. package/dist/prompts/simple-mentor.md +207 -0
  224. package/dist/prompts/simple.md +189 -0
  225. package/dist/providers/index.d.ts +5 -0
  226. package/dist/providers/index.d.ts.map +1 -0
  227. package/dist/providers/index.js +8 -0
  228. package/dist/providers/index.js.map +1 -0
  229. package/dist/providers/openai-compatible/api.d.ts +17 -0
  230. package/dist/providers/openai-compatible/api.d.ts.map +1 -0
  231. package/dist/providers/openai-compatible/api.js +58 -0
  232. package/dist/providers/openai-compatible/api.js.map +1 -0
  233. package/dist/providers/openai-compatible/model.d.ts +17 -0
  234. package/dist/providers/openai-compatible/model.d.ts.map +1 -0
  235. package/dist/providers/openai-compatible/model.js +435 -0
  236. package/dist/providers/openai-compatible/model.js.map +1 -0
  237. package/dist/providers/openai-compatible/provider.d.ts +22 -0
  238. package/dist/providers/openai-compatible/provider.d.ts.map +1 -0
  239. package/dist/providers/openai-compatible/provider.js +43 -0
  240. package/dist/providers/openai-compatible/provider.js.map +1 -0
  241. package/dist/providers/openai-compatible/utils.d.ts +3 -0
  242. package/dist/providers/openai-compatible/utils.d.ts.map +1 -0
  243. package/dist/providers/openai-compatible/utils.js +11 -0
  244. package/dist/providers/openai-compatible/utils.js.map +1 -0
  245. package/dist/providers/openai-compatible.provider.d.ts +8 -0
  246. package/dist/providers/openai-compatible.provider.d.ts.map +1 -0
  247. package/dist/providers/openai-compatible.provider.js +71 -0
  248. package/dist/providers/openai-compatible.provider.js.map +1 -0
  249. package/dist/providers/openai.provider.d.ts +2 -0
  250. package/dist/providers/openai.provider.d.ts.map +1 -0
  251. package/dist/providers/openai.provider.js +36 -0
  252. package/dist/providers/openai.provider.js.map +1 -0
  253. package/dist/providers/openrouter/api.d.ts +39 -0
  254. package/dist/providers/openrouter/api.d.ts.map +1 -0
  255. package/dist/providers/openrouter/api.js +172 -0
  256. package/dist/providers/openrouter/api.js.map +1 -0
  257. package/dist/providers/openrouter/converters.d.ts +8 -0
  258. package/dist/providers/openrouter/converters.d.ts.map +1 -0
  259. package/dist/providers/openrouter/converters.js +382 -0
  260. package/dist/providers/openrouter/converters.js.map +1 -0
  261. package/dist/providers/openrouter/converters.test.d.ts +2 -0
  262. package/dist/providers/openrouter/converters.test.d.ts.map +1 -0
  263. package/dist/providers/openrouter/converters.test.js +158 -0
  264. package/dist/providers/openrouter/converters.test.js.map +1 -0
  265. package/dist/providers/openrouter/index.d.ts +4 -0
  266. package/dist/providers/openrouter/index.d.ts.map +1 -0
  267. package/dist/providers/openrouter/index.js +4 -0
  268. package/dist/providers/openrouter/index.js.map +1 -0
  269. package/dist/providers/openrouter/model.d.ts +14 -0
  270. package/dist/providers/openrouter/model.d.ts.map +1 -0
  271. package/dist/providers/openrouter/model.js +485 -0
  272. package/dist/providers/openrouter/model.js.map +1 -0
  273. package/dist/providers/openrouter/provider.d.ts +15 -0
  274. package/dist/providers/openrouter/provider.d.ts.map +1 -0
  275. package/dist/providers/openrouter/provider.js +21 -0
  276. package/dist/providers/openrouter/provider.js.map +1 -0
  277. package/dist/providers/openrouter/utils.d.ts +10 -0
  278. package/dist/providers/openrouter/utils.d.ts.map +1 -0
  279. package/dist/providers/openrouter/utils.js +27 -0
  280. package/dist/providers/openrouter/utils.js.map +1 -0
  281. package/dist/providers/openrouter.api.retry.test.d.ts +2 -0
  282. package/dist/providers/openrouter.api.retry.test.d.ts.map +1 -0
  283. package/dist/providers/openrouter.api.retry.test.js +148 -0
  284. package/dist/providers/openrouter.api.retry.test.js.map +1 -0
  285. package/dist/providers/openrouter.d.ts +2 -0
  286. package/dist/providers/openrouter.d.ts.map +1 -0
  287. package/dist/providers/openrouter.history.test.d.ts +2 -0
  288. package/dist/providers/openrouter.history.test.d.ts.map +1 -0
  289. package/dist/providers/openrouter.history.test.js +533 -0
  290. package/dist/providers/openrouter.history.test.js.map +1 -0
  291. package/dist/providers/openrouter.js +4 -0
  292. package/dist/providers/openrouter.js.map +1 -0
  293. package/dist/providers/openrouter.provider.createRunner.test.d.ts +2 -0
  294. package/dist/providers/openrouter.provider.createRunner.test.d.ts.map +1 -0
  295. package/dist/providers/openrouter.provider.createRunner.test.js +23 -0
  296. package/dist/providers/openrouter.provider.createRunner.test.js.map +1 -0
  297. package/dist/providers/openrouter.provider.d.ts +2 -0
  298. package/dist/providers/openrouter.provider.d.ts.map +1 -0
  299. package/dist/providers/openrouter.provider.js +56 -0
  300. package/dist/providers/openrouter.provider.js.map +1 -0
  301. package/dist/providers/openrouter.test.d.ts +2 -0
  302. package/dist/providers/openrouter.test.d.ts.map +1 -0
  303. package/dist/providers/openrouter.test.js +1382 -0
  304. package/dist/providers/openrouter.test.js.map +1 -0
  305. package/dist/providers/registry.d.ts +65 -0
  306. package/dist/providers/registry.d.ts.map +1 -0
  307. package/dist/providers/registry.js +44 -0
  308. package/dist/providers/registry.js.map +1 -0
  309. package/dist/providers/registry.test.d.ts +2 -0
  310. package/dist/providers/registry.test.d.ts.map +1 -0
  311. package/dist/providers/registry.test.js +76 -0
  312. package/dist/providers/registry.test.js.map +1 -0
  313. package/dist/providers/web-search/index.d.ts +8 -0
  314. package/dist/providers/web-search/index.d.ts.map +1 -0
  315. package/dist/providers/web-search/index.js +9 -0
  316. package/dist/providers/web-search/index.js.map +1 -0
  317. package/dist/providers/web-search/registry.d.ts +35 -0
  318. package/dist/providers/web-search/registry.d.ts.map +1 -0
  319. package/dist/providers/web-search/registry.js +56 -0
  320. package/dist/providers/web-search/registry.js.map +1 -0
  321. package/dist/providers/web-search/registry.test.d.ts +2 -0
  322. package/dist/providers/web-search/registry.test.d.ts.map +1 -0
  323. package/dist/providers/web-search/registry.test.js +105 -0
  324. package/dist/providers/web-search/registry.test.js.map +1 -0
  325. package/dist/providers/web-search/tavily.provider.d.ts +15 -0
  326. package/dist/providers/web-search/tavily.provider.d.ts.map +1 -0
  327. package/dist/providers/web-search/tavily.provider.js +69 -0
  328. package/dist/providers/web-search/tavily.provider.js.map +1 -0
  329. package/dist/providers/web-search/tavily.provider.test.d.ts +2 -0
  330. package/dist/providers/web-search/tavily.provider.test.d.ts.map +1 -0
  331. package/dist/providers/web-search/tavily.provider.test.js +67 -0
  332. package/dist/providers/web-search/tavily.provider.test.js.map +1 -0
  333. package/dist/providers/web-search/types.d.ts +55 -0
  334. package/dist/providers/web-search/types.d.ts.map +1 -0
  335. package/dist/providers/web-search/types.js +6 -0
  336. package/dist/providers/web-search/types.js.map +1 -0
  337. package/dist/safety-checker.js +57 -0
  338. package/dist/services/conversation-events.d.ts +76 -0
  339. package/dist/services/conversation-events.d.ts.map +1 -0
  340. package/dist/services/conversation-events.js +2 -0
  341. package/dist/services/conversation-events.js.map +1 -0
  342. package/dist/services/conversation-service.d.ts +31 -0
  343. package/dist/services/conversation-service.d.ts.map +1 -0
  344. package/dist/services/conversation-service.js +46 -0
  345. package/dist/services/conversation-service.js.map +1 -0
  346. package/dist/services/conversation-service.test.js +190 -0
  347. package/dist/services/conversation-session.d.ts +99 -0
  348. package/dist/services/conversation-session.d.ts.map +1 -0
  349. package/dist/services/conversation-session.js +978 -0
  350. package/dist/services/conversation-session.js.map +1 -0
  351. package/dist/services/conversation-store.d.ts +24 -0
  352. package/dist/services/conversation-store.d.ts.map +1 -0
  353. package/dist/services/conversation-store.js +216 -0
  354. package/dist/services/conversation-store.js.map +1 -0
  355. package/dist/services/conversation-store.test.d.ts +2 -0
  356. package/dist/services/conversation-store.test.d.ts.map +1 -0
  357. package/dist/services/conversation-store.test.js +167 -0
  358. package/dist/services/conversation-store.test.js.map +1 -0
  359. package/dist/services/execution-context.d.ts +10 -0
  360. package/dist/services/execution-context.d.ts.map +1 -0
  361. package/dist/services/execution-context.js +22 -0
  362. package/dist/services/execution-context.js.map +1 -0
  363. package/dist/services/execution-context.test.d.ts +2 -0
  364. package/dist/services/execution-context.test.d.ts.map +1 -0
  365. package/dist/services/execution-context.test.js +49 -0
  366. package/dist/services/execution-context.test.js.map +1 -0
  367. package/dist/services/file-service.d.ts +12 -0
  368. package/dist/services/file-service.d.ts.map +1 -0
  369. package/dist/services/file-service.js +90 -0
  370. package/dist/services/file-service.js.map +1 -0
  371. package/dist/services/history-service.d.ts +39 -0
  372. package/dist/services/history-service.d.ts.map +1 -0
  373. package/dist/services/history-service.js +152 -0
  374. package/dist/services/history-service.js.map +1 -0
  375. package/dist/services/logging-service.d.ts +75 -0
  376. package/dist/services/logging-service.d.ts.map +1 -0
  377. package/dist/services/logging-service.js +343 -0
  378. package/dist/services/logging-service.js.map +1 -0
  379. package/dist/services/model-service.d.ts +15 -0
  380. package/dist/services/model-service.d.ts.map +1 -0
  381. package/dist/services/model-service.js +46 -0
  382. package/dist/services/model-service.js.map +1 -0
  383. package/dist/services/model-service.test.d.ts +2 -0
  384. package/dist/services/model-service.test.d.ts.map +1 -0
  385. package/dist/services/model-service.test.js +128 -0
  386. package/dist/services/model-service.test.js.map +1 -0
  387. package/dist/services/service-interfaces.d.ts +33 -0
  388. package/dist/services/service-interfaces.d.ts.map +1 -0
  389. package/dist/services/service-interfaces.js +2 -0
  390. package/dist/services/service-interfaces.js.map +1 -0
  391. package/dist/services/settings-service.d.ts +316 -0
  392. package/dist/services/settings-service.d.ts.map +1 -0
  393. package/dist/services/settings-service.js +1128 -0
  394. package/dist/services/settings-service.js.map +1 -0
  395. package/dist/services/settings-service.mock.d.ts +20 -0
  396. package/dist/services/settings-service.mock.d.ts.map +1 -0
  397. package/dist/services/settings-service.mock.js +55 -0
  398. package/dist/services/settings-service.mock.js.map +1 -0
  399. package/dist/services/singleton-deprecation.test.d.ts +2 -0
  400. package/dist/services/singleton-deprecation.test.d.ts.map +1 -0
  401. package/dist/services/singleton-deprecation.test.js +59 -0
  402. package/dist/services/singleton-deprecation.test.js.map +1 -0
  403. package/dist/services/ssh-service.d.ts +32 -0
  404. package/dist/services/ssh-service.d.ts.map +1 -0
  405. package/dist/services/ssh-service.js +119 -0
  406. package/dist/services/ssh-service.js.map +1 -0
  407. package/dist/services/ssh-service.test.d.ts +2 -0
  408. package/dist/services/ssh-service.test.d.ts.map +1 -0
  409. package/dist/services/ssh-service.test.js +269 -0
  410. package/dist/services/ssh-service.test.js.map +1 -0
  411. package/dist/test-search-tool.d.ts +2 -0
  412. package/dist/test-search-tool.d.ts.map +1 -0
  413. package/dist/test-search-tool.js +36 -0
  414. package/dist/test-search-tool.js.map +1 -0
  415. package/dist/tools/apply-patch.d.ts +28 -0
  416. package/dist/tools/apply-patch.d.ts.map +1 -0
  417. package/dist/tools/apply-patch.js +399 -0
  418. package/dist/tools/apply-patch.js.map +1 -0
  419. package/dist/tools/apply-patch.test.d.ts +2 -0
  420. package/dist/tools/apply-patch.test.d.ts.map +1 -0
  421. package/dist/tools/apply-patch.test.js +155 -0
  422. package/dist/tools/apply-patch.test.js.map +1 -0
  423. package/dist/tools/ask-mentor.d.ts +11 -0
  424. package/dist/tools/ask-mentor.d.ts.map +1 -0
  425. package/dist/tools/ask-mentor.js +52 -0
  426. package/dist/tools/ask-mentor.js.map +1 -0
  427. package/dist/tools/ask-mentor.test.d.ts +2 -0
  428. package/dist/tools/ask-mentor.test.d.ts.map +1 -0
  429. package/dist/tools/ask-mentor.test.js +47 -0
  430. package/dist/tools/ask-mentor.test.js.map +1 -0
  431. package/dist/tools/bash.d.ts +10 -0
  432. package/dist/tools/bash.d.ts.map +1 -0
  433. package/dist/tools/bash.js +55 -0
  434. package/dist/tools/bash.js.map +1 -0
  435. package/dist/tools/find-files.d.ts +15 -0
  436. package/dist/tools/find-files.d.ts.map +1 -0
  437. package/dist/tools/find-files.js +179 -0
  438. package/dist/tools/find-files.js.map +1 -0
  439. package/dist/tools/find-files.test.d.ts +2 -0
  440. package/dist/tools/find-files.test.d.ts.map +1 -0
  441. package/dist/tools/find-files.test.js +131 -0
  442. package/dist/tools/find-files.test.js.map +1 -0
  443. package/dist/tools/format-helpers.d.ts +34 -0
  444. package/dist/tools/format-helpers.d.ts.map +1 -0
  445. package/dist/tools/format-helpers.js +131 -0
  446. package/dist/tools/format-helpers.js.map +1 -0
  447. package/dist/tools/grep.d.ts +16 -0
  448. package/dist/tools/grep.d.ts.map +1 -0
  449. package/dist/tools/grep.js +211 -0
  450. package/dist/tools/grep.js.map +1 -0
  451. package/dist/tools/read-file.d.ts +15 -0
  452. package/dist/tools/read-file.d.ts.map +1 -0
  453. package/dist/tools/read-file.js +114 -0
  454. package/dist/tools/read-file.js.map +1 -0
  455. package/dist/tools/read-file.test.d.ts +2 -0
  456. package/dist/tools/read-file.test.d.ts.map +1 -0
  457. package/dist/tools/read-file.test.js +122 -0
  458. package/dist/tools/read-file.test.js.map +1 -0
  459. package/dist/tools/search-replace.d.ts +19 -0
  460. package/dist/tools/search-replace.d.ts.map +1 -0
  461. package/dist/tools/search-replace.js +411 -0
  462. package/dist/tools/search-replace.js.map +1 -0
  463. package/dist/tools/search-replace.test.d.ts +2 -0
  464. package/dist/tools/search-replace.test.d.ts.map +1 -0
  465. package/dist/tools/search-replace.test.js +302 -0
  466. package/dist/tools/search-replace.test.js.map +1 -0
  467. package/dist/tools/search.d.ts +15 -0
  468. package/dist/tools/search.d.ts.map +1 -0
  469. package/dist/tools/search.js +143 -0
  470. package/dist/tools/search.js.map +1 -0
  471. package/dist/tools/shell.d.ts +19 -0
  472. package/dist/tools/shell.d.ts.map +1 -0
  473. package/dist/tools/shell.js +278 -0
  474. package/dist/tools/shell.js.map +1 -0
  475. package/dist/tools/tool-execution-context.d.ts +7 -0
  476. package/dist/tools/tool-execution-context.d.ts.map +1 -0
  477. package/dist/tools/tool-execution-context.js +7 -0
  478. package/dist/tools/tool-execution-context.js.map +1 -0
  479. package/dist/tools/types.d.ts +30 -0
  480. package/dist/tools/types.d.ts.map +1 -0
  481. package/dist/tools/types.js +2 -0
  482. package/dist/tools/types.js.map +1 -0
  483. package/dist/tools/utils.d.ts +12 -0
  484. package/dist/tools/utils.d.ts.map +1 -0
  485. package/dist/tools/utils.js +19 -0
  486. package/dist/tools/utils.js.map +1 -0
  487. package/dist/tools/web-search.d.ts +29 -0
  488. package/dist/tools/web-search.d.ts.map +1 -0
  489. package/dist/tools/web-search.js +106 -0
  490. package/dist/tools/web-search.js.map +1 -0
  491. package/dist/tools/web-search.test.d.ts +2 -0
  492. package/dist/tools/web-search.test.d.ts.map +1 -0
  493. package/dist/tools/web-search.test.js +176 -0
  494. package/dist/tools/web-search.test.js.map +1 -0
  495. package/dist/utils/command-logger.d.ts +11 -0
  496. package/dist/utils/command-logger.d.ts.map +1 -0
  497. package/dist/utils/command-logger.js +34 -0
  498. package/dist/utils/command-logger.js.map +1 -0
  499. package/dist/utils/command-safety/constants.d.ts +21 -0
  500. package/dist/utils/command-safety/constants.d.ts.map +1 -0
  501. package/dist/utils/command-safety/constants.js +245 -0
  502. package/dist/utils/command-safety/constants.js.map +1 -0
  503. package/dist/utils/command-safety/find-helpers.d.ts +15 -0
  504. package/dist/utils/command-safety/find-helpers.d.ts.map +1 -0
  505. package/dist/utils/command-safety/find-helpers.js +218 -0
  506. package/dist/utils/command-safety/find-helpers.js.map +1 -0
  507. package/dist/utils/command-safety/handlers/find-handler.d.ts +6 -0
  508. package/dist/utils/command-safety/handlers/find-handler.d.ts.map +1 -0
  509. package/dist/utils/command-safety/handlers/find-handler.js +113 -0
  510. package/dist/utils/command-safety/handlers/find-handler.js.map +1 -0
  511. package/dist/utils/command-safety/handlers/git-handler.d.ts +6 -0
  512. package/dist/utils/command-safety/handlers/git-handler.d.ts.map +1 -0
  513. package/dist/utils/command-safety/handlers/git-handler.js +68 -0
  514. package/dist/utils/command-safety/handlers/git-handler.js.map +1 -0
  515. package/dist/utils/command-safety/handlers/index.d.ts +13 -0
  516. package/dist/utils/command-safety/handlers/index.d.ts.map +1 -0
  517. package/dist/utils/command-safety/handlers/index.js +20 -0
  518. package/dist/utils/command-safety/handlers/index.js.map +1 -0
  519. package/dist/utils/command-safety/handlers/sed-handler.d.ts +6 -0
  520. package/dist/utils/command-safety/handlers/sed-handler.d.ts.map +1 -0
  521. package/dist/utils/command-safety/handlers/sed-handler.js +94 -0
  522. package/dist/utils/command-safety/handlers/sed-handler.js.map +1 -0
  523. package/dist/utils/command-safety/handlers/types.d.ts +36 -0
  524. package/dist/utils/command-safety/handlers/types.d.ts.map +1 -0
  525. package/dist/utils/command-safety/handlers/types.js +2 -0
  526. package/dist/utils/command-safety/handlers/types.js.map +1 -0
  527. package/dist/utils/command-safety/index.d.ts +14 -0
  528. package/dist/utils/command-safety/index.d.ts.map +1 -0
  529. package/dist/utils/command-safety/index.js +183 -0
  530. package/dist/utils/command-safety/index.js.map +1 -0
  531. package/dist/utils/command-safety/path-analysis.d.ts +4 -0
  532. package/dist/utils/command-safety/path-analysis.d.ts.map +1 -0
  533. package/dist/utils/command-safety/path-analysis.js +153 -0
  534. package/dist/utils/command-safety/path-analysis.js.map +1 -0
  535. package/dist/utils/command-safety/utils.d.ts +2 -0
  536. package/dist/utils/command-safety/utils.d.ts.map +1 -0
  537. package/dist/utils/command-safety/utils.js +22 -0
  538. package/dist/utils/command-safety/utils.js.map +1 -0
  539. package/dist/utils/command-safety.d.ts +21 -0
  540. package/dist/utils/command-safety.d.ts.map +1 -0
  541. package/dist/utils/command-safety.find.test.d.ts +2 -0
  542. package/dist/utils/command-safety.find.test.d.ts.map +1 -0
  543. package/dist/utils/command-safety.find.test.js +342 -0
  544. package/dist/utils/command-safety.find.test.js.map +1 -0
  545. package/dist/utils/command-safety.js +702 -0
  546. package/dist/utils/command-safety.js.map +1 -0
  547. package/dist/utils/command-safety.path.test.d.ts +2 -0
  548. package/dist/utils/command-safety.path.test.d.ts.map +1 -0
  549. package/dist/utils/command-safety.path.test.js +360 -0
  550. package/dist/utils/command-safety.path.test.js.map +1 -0
  551. package/dist/utils/diff.d.ts +2 -0
  552. package/dist/utils/diff.d.ts.map +1 -0
  553. package/dist/utils/diff.js +44 -0
  554. package/dist/utils/diff.js.map +1 -0
  555. package/dist/utils/diff.test.d.ts +2 -0
  556. package/dist/utils/diff.test.d.ts.map +1 -0
  557. package/dist/utils/diff.test.js +85 -0
  558. package/dist/utils/diff.test.js.map +1 -0
  559. package/dist/utils/error-helpers.d.ts +6 -0
  560. package/dist/utils/error-helpers.d.ts.map +1 -0
  561. package/dist/utils/error-helpers.js +46 -0
  562. package/dist/utils/error-helpers.js.map +1 -0
  563. package/dist/utils/error-helpers.test.d.ts +2 -0
  564. package/dist/utils/error-helpers.test.d.ts.map +1 -0
  565. package/dist/utils/error-helpers.test.js +152 -0
  566. package/dist/utils/error-helpers.test.js.map +1 -0
  567. package/dist/utils/execute-shell.d.ts +15 -0
  568. package/dist/utils/execute-shell.d.ts.map +1 -0
  569. package/dist/utils/execute-shell.js +34 -0
  570. package/dist/utils/execute-shell.js.map +1 -0
  571. package/dist/utils/execute-shell.test.d.ts +2 -0
  572. package/dist/utils/execute-shell.test.d.ts.map +1 -0
  573. package/dist/utils/execute-shell.test.js +20 -0
  574. package/dist/utils/execute-shell.test.js.map +1 -0
  575. package/dist/utils/extract-command-messages.d.ts +5 -0
  576. package/dist/utils/extract-command-messages.d.ts.map +1 -0
  577. package/dist/utils/extract-command-messages.js +140 -0
  578. package/dist/utils/extract-command-messages.js.map +1 -0
  579. package/dist/utils/extract-command-messages.repro.test.d.ts +2 -0
  580. package/dist/utils/extract-command-messages.repro.test.d.ts.map +1 -0
  581. package/dist/utils/extract-command-messages.repro.test.js +31 -0
  582. package/dist/utils/extract-command-messages.repro.test.js.map +1 -0
  583. package/dist/utils/extract-command-messages.test.js +57 -0
  584. package/dist/utils/message-buffer.d.ts +2 -0
  585. package/dist/utils/message-buffer.d.ts.map +1 -0
  586. package/dist/utils/message-buffer.js +15 -0
  587. package/dist/utils/message-buffer.js.map +1 -0
  588. package/dist/utils/message-buffer.test.d.ts +2 -0
  589. package/dist/utils/message-buffer.test.d.ts.map +1 -0
  590. package/dist/utils/message-buffer.test.js +17 -0
  591. package/dist/utils/message-buffer.test.js.map +1 -0
  592. package/dist/utils/output-trim.d.ts +31 -0
  593. package/dist/utils/output-trim.d.ts.map +1 -0
  594. package/dist/utils/output-trim.js +71 -0
  595. package/dist/utils/output-trim.js.map +1 -0
  596. package/dist/utils/provider-credentials.d.ts +10 -0
  597. package/dist/utils/provider-credentials.d.ts.map +1 -0
  598. package/dist/utils/provider-credentials.js +22 -0
  599. package/dist/utils/provider-credentials.js.map +1 -0
  600. package/dist/utils/settings-command.d.ts +13 -0
  601. package/dist/utils/settings-command.d.ts.map +1 -0
  602. package/dist/utils/settings-command.js +173 -0
  603. package/dist/utils/settings-command.js.map +1 -0
  604. package/dist/utils/ssh-config-parser.d.ts +21 -0
  605. package/dist/utils/ssh-config-parser.d.ts.map +1 -0
  606. package/dist/utils/ssh-config-parser.js +89 -0
  607. package/dist/utils/ssh-config-parser.js.map +1 -0
  608. package/dist/utils/ssh-config-parser.test.d.ts +2 -0
  609. package/dist/utils/ssh-config-parser.test.d.ts.map +1 -0
  610. package/dist/utils/ssh-config-parser.test.js +153 -0
  611. package/dist/utils/ssh-config-parser.test.js.map +1 -0
  612. package/dist/utils/streaming-updater.d.ts +7 -0
  613. package/dist/utils/streaming-updater.d.ts.map +1 -0
  614. package/dist/utils/streaming-updater.js +41 -0
  615. package/dist/utils/streaming-updater.js.map +1 -0
  616. package/dist/utils/throttle.d.ts +7 -0
  617. package/dist/utils/throttle.d.ts.map +1 -0
  618. package/dist/utils/throttle.js +49 -0
  619. package/dist/utils/throttle.js.map +1 -0
  620. package/package.json +108 -0
  621. package/readme.md +428 -0
@@ -0,0 +1,702 @@
1
+ import parse from 'bash-parser';
2
+ import path from 'path';
3
+ import { loggingService } from '../services/logging-service.js';
4
+ // 1. CONSTANTS
5
+ // Note: 'sed' is useful for read-only transformations. We allow it by default
6
+ // but add guards below to prevent in-place edits (-i) and unapproved redirections.
7
+ const ALLOWED_COMMANDS = new Set([
8
+ 'ls',
9
+ 'pwd',
10
+ 'grep',
11
+ 'cat',
12
+ 'echo',
13
+ 'head',
14
+ 'tail',
15
+ 'sed',
16
+ 'find',
17
+ ]);
18
+ const BLOCKED_COMMANDS = new Set([
19
+ // Filesystem
20
+ 'rm',
21
+ 'rmdir',
22
+ 'mkfs',
23
+ 'dd',
24
+ 'mv',
25
+ 'cp',
26
+ // System
27
+ 'sudo',
28
+ 'su',
29
+ 'chmod',
30
+ 'chown',
31
+ 'shutdown',
32
+ 'reboot',
33
+ // Network/Web
34
+ 'curl',
35
+ 'wget',
36
+ 'ssh',
37
+ 'scp',
38
+ 'netstat',
39
+ // Package Managers / installers
40
+ 'apt',
41
+ 'yum',
42
+ 'npm',
43
+ 'yarn',
44
+ 'pnpm',
45
+ 'pip',
46
+ 'gem',
47
+ // Dangerous wrappers / misc
48
+ 'eval',
49
+ 'exec',
50
+ 'kill',
51
+ 'killall',
52
+ ]);
53
+ /* legacy containsDangerousCommand removed — replaced by classifyCommand + path analysis */
54
+ /**
55
+ * Validate command safety using an AST parser.
56
+ * Returns true when a command requires user approval.
57
+ * Throws for invalid/empty inputs.
58
+ */
59
+ export var SafetyStatus;
60
+ (function (SafetyStatus) {
61
+ SafetyStatus["GREEN"] = "GREEN";
62
+ SafetyStatus["YELLOW"] = "YELLOW";
63
+ SafetyStatus["RED"] = "RED";
64
+ })(SafetyStatus || (SafetyStatus = {}));
65
+ // Extract a best-effort string for a word/arg node, including expansions.
66
+ function extractWordText(word) {
67
+ if (!word)
68
+ return undefined;
69
+ if (typeof word === 'string')
70
+ return word;
71
+ if (typeof word.text === 'string')
72
+ return word.text;
73
+ if (typeof word.value === 'string')
74
+ return word.value;
75
+ if (typeof word.content === 'string')
76
+ return word.content;
77
+ if (word.parameter)
78
+ return `$${word.parameter}`;
79
+ if (Array.isArray(word.parts)) {
80
+ return word.parts
81
+ .map((part) => extractWordText(part) ?? '')
82
+ .join('');
83
+ }
84
+ return undefined;
85
+ }
86
+ // 2. FIND COMMAND HELPERS
87
+ /**
88
+ * Check if a find command has dangerous execution flags (-exec, -execdir, -ok, -okdir, -delete)
89
+ */
90
+ function hasFindDangerousExecution(args) {
91
+ for (let i = 0; i < args.length; i++) {
92
+ const argText = extractWordText(args[i]);
93
+ if (!argText)
94
+ continue;
95
+ // Check for -delete flag
96
+ if (argText === '-delete') {
97
+ return { dangerous: true, reason: 'find -delete (destructive)' };
98
+ }
99
+ // Check for execution flags
100
+ const execFlags = ['-exec', '-execdir', '-ok', '-okdir'];
101
+ if (!execFlags.includes(argText))
102
+ continue;
103
+ // Found an exec flag - analyze the command it executes
104
+ // Find the terminator (; or +)
105
+ let terminatorIndex = -1;
106
+ for (let j = i + 1; j < args.length; j++) {
107
+ const term = extractWordText(args[j]);
108
+ if (term === ';' ||
109
+ term === '+' ||
110
+ term === '\\;' ||
111
+ term === '\\+') {
112
+ terminatorIndex = j;
113
+ break;
114
+ }
115
+ }
116
+ if (terminatorIndex === -1) {
117
+ // Malformed -exec (no terminator)
118
+ return {
119
+ dangerous: true,
120
+ reason: `find ${argText} without terminator`,
121
+ };
122
+ }
123
+ // Extract the command between exec flag and terminator
124
+ const execArgs = args.slice(i + 1, terminatorIndex);
125
+ // Check for redirects (which indicate shell operations)
126
+ const hasRedirect = execArgs.some((a) => a?.type === 'Redirect');
127
+ if (hasRedirect) {
128
+ return {
129
+ dangerous: true,
130
+ reason: `find ${argText} with shell redirection`,
131
+ };
132
+ }
133
+ const execCommand = execArgs
134
+ .map(a => extractWordText(a))
135
+ .filter(Boolean);
136
+ if (execCommand.length === 0) {
137
+ return {
138
+ dangerous: true,
139
+ reason: `find ${argText} with empty command`,
140
+ };
141
+ }
142
+ const cmdName = execCommand[0];
143
+ if (!cmdName) {
144
+ return {
145
+ dangerous: true,
146
+ reason: `find ${argText} with undefined command`,
147
+ };
148
+ }
149
+ // Check if {} is the command itself (executing found files)
150
+ if (cmdName === '{}') {
151
+ return {
152
+ dangerous: true,
153
+ reason: `find ${argText} {} (executes found files directly)`,
154
+ };
155
+ }
156
+ // Check for destructive commands
157
+ const destructiveCmds = [
158
+ 'rm',
159
+ 'shred',
160
+ 'chmod',
161
+ 'chown',
162
+ 'mv',
163
+ 'dd',
164
+ 'mkfs',
165
+ 'truncate',
166
+ 'tee',
167
+ 'cp',
168
+ 'ln',
169
+ 'install',
170
+ 'rsync',
171
+ ];
172
+ if (destructiveCmds.includes(cmdName)) {
173
+ return {
174
+ dangerous: true,
175
+ reason: `find ${argText} ${cmdName} (destructive)`,
176
+ };
177
+ }
178
+ // Check for dangerous interpreters and meta-executors
179
+ // These can all invoke arbitrary commands or scripts
180
+ const dangerousInterpreters = [
181
+ // Shells
182
+ 'sh',
183
+ 'bash',
184
+ 'zsh',
185
+ 'ksh',
186
+ 'dash',
187
+ 'fish',
188
+ 'tcsh',
189
+ 'csh',
190
+ // Script interpreters
191
+ 'perl',
192
+ 'python',
193
+ 'python2',
194
+ 'python3',
195
+ 'ruby',
196
+ 'node',
197
+ 'nodejs',
198
+ 'php',
199
+ 'lua',
200
+ // Meta-executors that can run commands
201
+ 'env',
202
+ 'xargs',
203
+ 'parallel',
204
+ 'nohup',
205
+ 'nice',
206
+ 'ionice',
207
+ 'timeout',
208
+ 'stdbuf',
209
+ 'script',
210
+ 'expect',
211
+ // Text processors that can execute
212
+ 'awk',
213
+ 'gawk',
214
+ 'mawk',
215
+ 'nawk',
216
+ 'sed',
217
+ 'ed',
218
+ // Editors that can run shell commands
219
+ 'vim',
220
+ 'nvim',
221
+ 'emacs',
222
+ ];
223
+ // Handle both bare names and full paths like /usr/bin/python
224
+ const isDangerousInterpreter = dangerousInterpreters.some(interp => cmdName === interp || cmdName.endsWith(`/${interp}`));
225
+ if (isDangerousInterpreter) {
226
+ return {
227
+ dangerous: true,
228
+ reason: `find ${argText} ${cmdName} (can execute commands)`,
229
+ };
230
+ }
231
+ // Check for shell metacharacters in command
232
+ const fullExecCmd = execCommand.join(' ');
233
+ if (/[|&;$`<>]/.test(fullExecCmd)) {
234
+ return {
235
+ dangerous: true,
236
+ reason: `find ${argText} with shell metacharacters`,
237
+ };
238
+ }
239
+ }
240
+ return { dangerous: false };
241
+ }
242
+ /**
243
+ * Check for suspicious find flags that warrant YELLOW classification
244
+ */
245
+ function hasFindSuspiciousFlags(args) {
246
+ for (const arg of args) {
247
+ const argText = extractWordText(arg);
248
+ if (!argText)
249
+ continue;
250
+ // File output flags
251
+ if (['-fprint', '-fprint0', '-fprintf', '-fls'].some(flag => argText.startsWith(flag))) {
252
+ return {
253
+ suspicious: true,
254
+ reason: `find ${argText} (file output)`,
255
+ };
256
+ }
257
+ // Symlink following
258
+ if (['-L', '-follow', '-H'].includes(argText)) {
259
+ return {
260
+ suspicious: true,
261
+ reason: `find ${argText} (symlink following)`,
262
+ };
263
+ }
264
+ // SUID/SGID permission searches
265
+ if (argText === '-perm') {
266
+ // Check the next argument for dangerous permission patterns
267
+ const nextIdx = args.indexOf(arg) + 1;
268
+ if (nextIdx < args.length) {
269
+ const permValue = extractWordText(args[nextIdx]);
270
+ if (permValue) {
271
+ // Numeric SUID/SGID patterns (e.g., -4000, /6000)
272
+ const hasNumericSuid = /[-\/]?[2467]000/.test(permValue);
273
+ // Symbolic SUID/SGID patterns (e.g., -u+s, /g+s, +s)
274
+ const hasSymbolicSuid = /[ug]?\+s/.test(permValue);
275
+ if (hasNumericSuid || hasSymbolicSuid) {
276
+ return {
277
+ suspicious: true,
278
+ reason: `find -perm ${permValue} (SUID/SGID search)`,
279
+ };
280
+ }
281
+ }
282
+ }
283
+ }
284
+ // Inode-based searches (can bypass path restrictions)
285
+ if (argText === '-inum') {
286
+ return {
287
+ suspicious: true,
288
+ reason: 'find -inum (inode-based access bypasses path checks)',
289
+ };
290
+ }
291
+ // Read-only exec (still suspicious, requires approval)
292
+ if (['-exec', '-execdir', '-ok', '-okdir'].includes(argText)) {
293
+ // If we reach here, hasFindDangerousExecution already passed (not RED)
294
+ // but any -exec usage should still be YELLOW
295
+ return {
296
+ suspicious: true,
297
+ reason: `find ${argText} (command execution)`,
298
+ };
299
+ }
300
+ }
301
+ return { suspicious: false };
302
+ }
303
+ // 3. PATH ANALYSIS HELPER
304
+ function analyzePathRisk(inputPath) {
305
+ const candidate = inputPath?.trim();
306
+ if (!candidate)
307
+ return SafetyStatus.GREEN;
308
+ // RED: Home directory and sensitive paths
309
+ // Check for various home directory representations
310
+ const homePatterns = [
311
+ /^~/, // Tilde
312
+ /^\$HOME/, // $HOME variable
313
+ /^\$\{HOME\}/, // ${HOME} variable
314
+ /^\$USER/, // $USER variable
315
+ /^\$LOGNAME/, // $LOGNAME variable
316
+ /^\$XDG_/, // XDG variables
317
+ /^\/home\//, // Linux home directories
318
+ /^\/Users\//, // macOS home directories
319
+ /^\/root($|\/)/, // Root's home
320
+ ];
321
+ const isHomeRelated = homePatterns.some(pattern => pattern.test(candidate));
322
+ if (isHomeRelated) {
323
+ // Extract the path after home prefix for further analysis
324
+ const sliced = candidate
325
+ .replace(/^~/, '')
326
+ .replace(/^\$\{?HOME\}?/, '')
327
+ .replace(/^\$\{?USER\}?/, '')
328
+ .replace(/^\$\{?LOGNAME\}?/, '')
329
+ .replace(/^\/home\/[^/]+/, '')
330
+ .replace(/^\/Users\/[^/]+/, '')
331
+ .replace(/^\/root/, '');
332
+ // Plain home directory access without any suffix is RED
333
+ if (sliced === '' || sliced === '/') {
334
+ loggingService.security('Path risk: home directory access', {
335
+ path: candidate,
336
+ });
337
+ return SafetyStatus.RED;
338
+ }
339
+ // Check for sensitive dotfiles and directories
340
+ const sensitivePaths = [
341
+ '/.ssh',
342
+ '/.gnupg',
343
+ '/.aws',
344
+ '/.kube',
345
+ '/.env',
346
+ '/.git',
347
+ '/.config',
348
+ '/.bash_history',
349
+ '/.zsh_history',
350
+ ];
351
+ if (/^\/\.\w+/.test(sliced) ||
352
+ sensitivePaths.some(sensitive => sliced.includes(sensitive))) {
353
+ loggingService.security('Path risk: home dotfile or config', {
354
+ path: candidate,
355
+ });
356
+ return SafetyStatus.RED;
357
+ }
358
+ }
359
+ // RED: Absolute System Paths
360
+ if (path.isAbsolute(candidate)) {
361
+ const SYSTEM_PATHS = [
362
+ '/etc',
363
+ '/dev',
364
+ '/proc',
365
+ '/var',
366
+ '/usr',
367
+ '/boot',
368
+ '/bin',
369
+ ];
370
+ if (SYSTEM_PATHS.some(sys => candidate.startsWith(sys))) {
371
+ loggingService.security('Path risk: absolute system path', {
372
+ path: candidate,
373
+ });
374
+ return SafetyStatus.RED;
375
+ }
376
+ // Home dotfiles when absolute
377
+ if (/^\/(home|Users)\/[^/]+\/\.\w+/.test(candidate) ||
378
+ candidate.includes('/.ssh') ||
379
+ candidate.includes('/.gitconfig')) {
380
+ loggingService.security('Path risk: absolute home dotfile', {
381
+ path: candidate,
382
+ });
383
+ return SafetyStatus.RED;
384
+ }
385
+ // Other absolute paths are suspicious -> audit
386
+ loggingService.security('Path risk: absolute non-system path', {
387
+ path: candidate,
388
+ });
389
+ return SafetyStatus.YELLOW;
390
+ }
391
+ // RED: Directory Traversal
392
+ if (candidate.includes('..')) {
393
+ loggingService.security('Path risk: directory traversal detected', {
394
+ path: candidate,
395
+ });
396
+ return SafetyStatus.RED;
397
+ }
398
+ // Hidden files -> YELLOW
399
+ const filename = path.basename(candidate);
400
+ if (filename.startsWith('.')) {
401
+ loggingService.security('Path risk: hidden file', { path: candidate });
402
+ return SafetyStatus.YELLOW;
403
+ }
404
+ // Sensitive extensions
405
+ const SENSITIVE_EXTENSIONS = ['.env', '.pem', '.key', '.json'];
406
+ if (SENSITIVE_EXTENSIONS.some(ext => filename.endsWith(ext))) {
407
+ loggingService.security('Path risk: sensitive extension', {
408
+ path: candidate,
409
+ });
410
+ return SafetyStatus.YELLOW;
411
+ }
412
+ return SafetyStatus.GREEN;
413
+ }
414
+ /**
415
+ * Classify command into a SafetyStatus (GREEN/YELLOW/RED)
416
+ */
417
+ export function classifyCommand(commandString) {
418
+ try {
419
+ const reasons = [];
420
+ const truncatedCommand = commandString.substring(0, 200);
421
+ loggingService.security('Classifying command safety', {
422
+ command: truncatedCommand,
423
+ });
424
+ const ast = parse(commandString, { mode: 'bash' });
425
+ let worstStatus = SafetyStatus.GREEN;
426
+ function upgradeStatus(s, reason) {
427
+ if (worstStatus === SafetyStatus.RED)
428
+ return;
429
+ if (s === SafetyStatus.RED)
430
+ worstStatus = SafetyStatus.RED;
431
+ else if (s === SafetyStatus.YELLOW &&
432
+ worstStatus === SafetyStatus.GREEN)
433
+ worstStatus = SafetyStatus.YELLOW;
434
+ if (reason)
435
+ reasons.push(`${s}: ${reason}`);
436
+ }
437
+ function traverse(node) {
438
+ if (!node)
439
+ return;
440
+ if (Array.isArray(node))
441
+ return node.forEach(traverse);
442
+ if (node.type === 'Command') {
443
+ const name = node.name?.text ||
444
+ (node.name &&
445
+ node.name.parts &&
446
+ node.name.parts.map((p) => p.text).join(''));
447
+ if (typeof name === 'string') {
448
+ if (BLOCKED_COMMANDS.has(name)) {
449
+ upgradeStatus(SafetyStatus.RED, `blocked command: ${name}`);
450
+ return;
451
+ }
452
+ if (!ALLOWED_COMMANDS.has(name)) {
453
+ upgradeStatus(SafetyStatus.YELLOW, `unknown or unlisted command: ${name}`);
454
+ }
455
+ }
456
+ const cmdName = typeof name === 'string' ? name : undefined;
457
+ // Special handling for find command
458
+ if (cmdName === 'find' && node.suffix) {
459
+ // Check for dangerous find operations first (RED)
460
+ const dangerResult = hasFindDangerousExecution(node.suffix);
461
+ if (dangerResult.dangerous) {
462
+ upgradeStatus(SafetyStatus.RED, dangerResult.reason || 'find with dangerous flags');
463
+ }
464
+ // Check for suspicious find flags (YELLOW)
465
+ if (!dangerResult.dangerous) {
466
+ const suspiciousResult = hasFindSuspiciousFlags(node.suffix);
467
+ if (suspiciousResult.suspicious) {
468
+ upgradeStatus(SafetyStatus.YELLOW, suspiciousResult.reason ||
469
+ 'find with suspicious flags');
470
+ }
471
+ }
472
+ // Check path arguments for find
473
+ if (!dangerResult.dangerous) {
474
+ // Track if previous arg was a pattern flag like -name, -regex
475
+ let previousArgWasPatternFlag = false;
476
+ for (const arg of node.suffix) {
477
+ if (arg?.type === 'Redirect')
478
+ continue;
479
+ const argText = extractWordText(arg);
480
+ if (!argText)
481
+ continue;
482
+ // Track pattern flags
483
+ if ([
484
+ '-name',
485
+ '-iname',
486
+ '-path',
487
+ '-ipath',
488
+ '-regex',
489
+ '-iregex',
490
+ ].includes(argText)) {
491
+ previousArgWasPatternFlag = true;
492
+ continue;
493
+ }
494
+ // Skip flags
495
+ if (argText.startsWith('-')) {
496
+ previousArgWasPatternFlag = false;
497
+ continue;
498
+ }
499
+ // Skip pattern arguments (the values after -name, -regex, etc.)
500
+ if (previousArgWasPatternFlag) {
501
+ previousArgWasPatternFlag = false;
502
+ continue;
503
+ }
504
+ // Skip glob patterns (contain wildcards)
505
+ if (/[*?[\]]/.test(argText))
506
+ continue;
507
+ // Skip safe relative paths (. and ./)
508
+ if (argText === '.' || argText === './')
509
+ continue;
510
+ // Skip patterns with backslashes (regex patterns)
511
+ if (argText.includes('\\'))
512
+ continue;
513
+ // Root traversal detection (DoS + information disclosure)
514
+ if (argText === '/' || argText === '//') {
515
+ upgradeStatus(SafetyStatus.YELLOW, 'find / (root traversal - resource intensive)');
516
+ continue;
517
+ }
518
+ // For find, analyzing paths is more lenient:
519
+ // - System paths like /etc are YELLOW (not RED)
520
+ // - Home directories and dotfiles are still RED
521
+ const pathStatus = analyzePathRisk(argText);
522
+ if (pathStatus === SafetyStatus.RED) {
523
+ // Keep RED for home directories, dotfiles, and traversal
524
+ // Downgrade system paths to YELLOW
525
+ const homeRelatedPatterns = [
526
+ /^~/, // Tilde
527
+ /^\$/, // Variables like $HOME, $USER
528
+ /^\/home\//, // Linux home
529
+ /^\/Users\//, // macOS home
530
+ /^\/root/, // Root's home
531
+ /\/\.ssh/, // SSH keys
532
+ /\/\.env/, // Environment files
533
+ /\/\.git/, // Git config
534
+ /\/\.aws/, // AWS credentials
535
+ /\/\.kube/, // Kubernetes config
536
+ /\/\.gnupg/, // GPG keys
537
+ /\.\./, // Directory traversal
538
+ ];
539
+ const isHomeRelated = homeRelatedPatterns.some(pattern => pattern.test(argText));
540
+ if (isHomeRelated) {
541
+ upgradeStatus(SafetyStatus.RED, `find dangerous path: ${argText}`);
542
+ }
543
+ else {
544
+ // System paths like /etc get downgraded to YELLOW
545
+ upgradeStatus(SafetyStatus.YELLOW, `find system path: ${argText}`);
546
+ }
547
+ }
548
+ else if (pathStatus === SafetyStatus.YELLOW) {
549
+ upgradeStatus(pathStatus, `find path argument ${argText}`);
550
+ }
551
+ }
552
+ }
553
+ // Done with find-specific handling
554
+ // Don't process suffix generically
555
+ return;
556
+ }
557
+ if (node.suffix) {
558
+ let hasOutputRedirect = false;
559
+ let hasInPlaceEdit = false;
560
+ // First pass: detect dangerous sed patterns
561
+ for (const arg of node.suffix) {
562
+ if (arg?.type === 'Redirect') {
563
+ // Check if it's an output redirect (>, >>)
564
+ const op = arg.op?.text || arg.op;
565
+ if (op === '>' || op === '>>') {
566
+ hasOutputRedirect = true;
567
+ }
568
+ }
569
+ const argText = extractWordText(arg);
570
+ if (argText && argText.startsWith('-')) {
571
+ if (cmdName === 'sed' && argText.startsWith('-i')) {
572
+ hasInPlaceEdit = true;
573
+ }
574
+ }
575
+ }
576
+ // Second pass: classify arguments
577
+ for (const arg of node.suffix) {
578
+ // Redirects: analyze path risk. For `sed`, only mark output redirects as YELLOW
579
+ if (arg?.type === 'Redirect') {
580
+ const fileText = extractWordText(arg.file ?? arg);
581
+ const op = arg.op?.text || arg.op;
582
+ if (cmdName === 'sed' &&
583
+ (op === '>' || op === '>>')) {
584
+ upgradeStatus(SafetyStatus.YELLOW, `sed with output redirection to ${fileText ?? '<unknown>'}`);
585
+ }
586
+ const pathStatus = analyzePathRisk(fileText);
587
+ upgradeStatus(pathStatus, `redirect to ${fileText ?? '<unknown>'}`);
588
+ continue;
589
+ }
590
+ const argText = extractWordText(arg);
591
+ // Flags are normally ignored, but for `sed` the -i flag is dangerous
592
+ // because it performs in-place edits. Detect -i and variants (e.g. -i, -i.bak, -i'')
593
+ if (argText && argText.startsWith('-')) {
594
+ if (cmdName === 'sed' && argText.startsWith('-i')) {
595
+ upgradeStatus(SafetyStatus.RED, `sed in-place edit detected: ${argText}`);
596
+ continue;
597
+ }
598
+ continue; // other flags ignored
599
+ }
600
+ const pathStatus = analyzePathRisk(argText);
601
+ // For `sed`, file arguments are only risky if combined with dangerous operations
602
+ if (cmdName === 'sed' && argText) {
603
+ // If there's an in-place edit or output redirect, path risk matters
604
+ // Otherwise, reading files with sed is safe (GREEN)
605
+ if (hasInPlaceEdit || hasOutputRedirect) {
606
+ if (pathStatus === SafetyStatus.RED)
607
+ upgradeStatus(pathStatus, `sed file argument ${argText}`);
608
+ else
609
+ upgradeStatus(SafetyStatus.YELLOW, `sed file argument ${argText}`);
610
+ }
611
+ else {
612
+ // Read-only sed: only escalate if path itself is risky
613
+ if (pathStatus !== SafetyStatus.GREEN) {
614
+ upgradeStatus(pathStatus, `sed file argument ${argText}`);
615
+ }
616
+ // Otherwise GREEN - read-only sed is safe
617
+ }
618
+ continue;
619
+ }
620
+ // Unknown/opaque args fall back to YELLOW
621
+ if (!argText)
622
+ upgradeStatus(SafetyStatus.YELLOW, 'opaque or unparseable argument');
623
+ else
624
+ upgradeStatus(pathStatus, `argument ${argText}`);
625
+ }
626
+ }
627
+ }
628
+ // recurse common shapes
629
+ if (node.type === 'LogicalExpression') {
630
+ traverse(node.left);
631
+ traverse(node.right);
632
+ return;
633
+ }
634
+ if (node.type === 'Pipeline') {
635
+ (node.commands || []).forEach(traverse);
636
+ return;
637
+ }
638
+ if (node.type === 'Subshell') {
639
+ traverse(node.list);
640
+ return;
641
+ }
642
+ if (node.type === 'CommandSubstitution') {
643
+ (node.commands || []).forEach(traverse);
644
+ return;
645
+ }
646
+ if (node.type === 'Script' || node.type === 'Program') {
647
+ (node.commands || []).forEach(traverse);
648
+ return;
649
+ }
650
+ for (const k of Object.keys(node)) {
651
+ const v = node[k];
652
+ if (v && typeof v === 'object')
653
+ traverse(v);
654
+ }
655
+ }
656
+ if (ast && ast.commands) {
657
+ ast.commands.forEach(traverse);
658
+ }
659
+ loggingService.security('Command classification result', {
660
+ command: truncatedCommand,
661
+ status: worstStatus,
662
+ reasons,
663
+ });
664
+ return worstStatus;
665
+ }
666
+ catch (e) {
667
+ // Fail-safe: unparsable -> audit
668
+ loggingService.warn('Failed to parse command, classifying as YELLOW', {
669
+ command: commandString.substring(0, 200),
670
+ error: e instanceof Error ? e.message : String(e),
671
+ });
672
+ return SafetyStatus.YELLOW;
673
+ }
674
+ }
675
+ /**
676
+ * Validate command safety using an AST parser.
677
+ * Returns true when a command requires user approval.
678
+ * Throws for invalid/empty inputs OR hard-blocked RED classifications.
679
+ */
680
+ export function validateCommandSafety(command) {
681
+ if (!command ||
682
+ typeof command !== 'string' ||
683
+ command.trim().length === 0) {
684
+ throw new Error('Command cannot be empty');
685
+ }
686
+ loggingService.security('Validating command safety', {
687
+ command: command.substring(0, 200),
688
+ });
689
+ const status = classifyCommand(command);
690
+ if (status === SafetyStatus.RED) {
691
+ loggingService.security('Command validation failed: RED (forbidden)', {
692
+ command: command.substring(0, 200),
693
+ });
694
+ throw new Error('Command classified as RED (forbidden)');
695
+ }
696
+ loggingService.security('Validation result', {
697
+ command: command.substring(0, 200),
698
+ status,
699
+ });
700
+ return status === SafetyStatus.YELLOW;
701
+ }
702
+ //# sourceMappingURL=command-safety.js.map