@animus-labs/cortex 0.2.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 (293) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +73 -0
  3. package/dist/budget-guard.d.ts +75 -0
  4. package/dist/budget-guard.d.ts.map +1 -0
  5. package/dist/budget-guard.js +142 -0
  6. package/dist/budget-guard.js.map +1 -0
  7. package/dist/compaction/compaction.d.ts +99 -0
  8. package/dist/compaction/compaction.d.ts.map +1 -0
  9. package/dist/compaction/compaction.js +302 -0
  10. package/dist/compaction/compaction.js.map +1 -0
  11. package/dist/compaction/failsafe.d.ts +57 -0
  12. package/dist/compaction/failsafe.d.ts.map +1 -0
  13. package/dist/compaction/failsafe.js +135 -0
  14. package/dist/compaction/failsafe.js.map +1 -0
  15. package/dist/compaction/index.d.ts +381 -0
  16. package/dist/compaction/index.d.ts.map +1 -0
  17. package/dist/compaction/index.js +979 -0
  18. package/dist/compaction/index.js.map +1 -0
  19. package/dist/compaction/microcompaction.d.ts +219 -0
  20. package/dist/compaction/microcompaction.d.ts.map +1 -0
  21. package/dist/compaction/microcompaction.js +536 -0
  22. package/dist/compaction/microcompaction.js.map +1 -0
  23. package/dist/compaction/observational/buffering.d.ts +225 -0
  24. package/dist/compaction/observational/buffering.d.ts.map +1 -0
  25. package/dist/compaction/observational/buffering.js +354 -0
  26. package/dist/compaction/observational/buffering.js.map +1 -0
  27. package/dist/compaction/observational/constants.d.ts +70 -0
  28. package/dist/compaction/observational/constants.d.ts.map +1 -0
  29. package/dist/compaction/observational/constants.js +507 -0
  30. package/dist/compaction/observational/constants.js.map +1 -0
  31. package/dist/compaction/observational/index.d.ts +219 -0
  32. package/dist/compaction/observational/index.d.ts.map +1 -0
  33. package/dist/compaction/observational/index.js +641 -0
  34. package/dist/compaction/observational/index.js.map +1 -0
  35. package/dist/compaction/observational/observer.d.ts +97 -0
  36. package/dist/compaction/observational/observer.d.ts.map +1 -0
  37. package/dist/compaction/observational/observer.js +424 -0
  38. package/dist/compaction/observational/observer.js.map +1 -0
  39. package/dist/compaction/observational/recall-tool.d.ts +27 -0
  40. package/dist/compaction/observational/recall-tool.d.ts.map +1 -0
  41. package/dist/compaction/observational/recall-tool.js +93 -0
  42. package/dist/compaction/observational/recall-tool.js.map +1 -0
  43. package/dist/compaction/observational/reflector.d.ts +94 -0
  44. package/dist/compaction/observational/reflector.d.ts.map +1 -0
  45. package/dist/compaction/observational/reflector.js +167 -0
  46. package/dist/compaction/observational/reflector.js.map +1 -0
  47. package/dist/compaction/observational/types.d.ts +271 -0
  48. package/dist/compaction/observational/types.d.ts.map +1 -0
  49. package/dist/compaction/observational/types.js +15 -0
  50. package/dist/compaction/observational/types.js.map +1 -0
  51. package/dist/context-manager.d.ts +134 -0
  52. package/dist/context-manager.d.ts.map +1 -0
  53. package/dist/context-manager.js +170 -0
  54. package/dist/context-manager.js.map +1 -0
  55. package/dist/cortex-agent.d.ts +1020 -0
  56. package/dist/cortex-agent.d.ts.map +1 -0
  57. package/dist/cortex-agent.js +3589 -0
  58. package/dist/cortex-agent.js.map +1 -0
  59. package/dist/error-classifier.d.ts +48 -0
  60. package/dist/error-classifier.d.ts.map +1 -0
  61. package/dist/error-classifier.js +152 -0
  62. package/dist/error-classifier.js.map +1 -0
  63. package/dist/event-bridge.d.ts +166 -0
  64. package/dist/event-bridge.d.ts.map +1 -0
  65. package/dist/event-bridge.js +381 -0
  66. package/dist/event-bridge.js.map +1 -0
  67. package/dist/index.d.ts +55 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +57 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/mcp-client.d.ts +119 -0
  72. package/dist/mcp-client.d.ts.map +1 -0
  73. package/dist/mcp-client.js +474 -0
  74. package/dist/mcp-client.js.map +1 -0
  75. package/dist/model-wrapper.d.ts +58 -0
  76. package/dist/model-wrapper.d.ts.map +1 -0
  77. package/dist/model-wrapper.js +86 -0
  78. package/dist/model-wrapper.js.map +1 -0
  79. package/dist/noop-logger.d.ts +4 -0
  80. package/dist/noop-logger.d.ts.map +1 -0
  81. package/dist/noop-logger.js +8 -0
  82. package/dist/noop-logger.js.map +1 -0
  83. package/dist/prompt-diagnostics.d.ts +47 -0
  84. package/dist/prompt-diagnostics.d.ts.map +1 -0
  85. package/dist/prompt-diagnostics.js +230 -0
  86. package/dist/prompt-diagnostics.js.map +1 -0
  87. package/dist/provider-manager.d.ts +224 -0
  88. package/dist/provider-manager.d.ts.map +1 -0
  89. package/dist/provider-manager.js +563 -0
  90. package/dist/provider-manager.js.map +1 -0
  91. package/dist/provider-registry.d.ts +115 -0
  92. package/dist/provider-registry.d.ts.map +1 -0
  93. package/dist/provider-registry.js +305 -0
  94. package/dist/provider-registry.js.map +1 -0
  95. package/dist/schema-converter.d.ts +20 -0
  96. package/dist/schema-converter.d.ts.map +1 -0
  97. package/dist/schema-converter.js +48 -0
  98. package/dist/schema-converter.js.map +1 -0
  99. package/dist/skill-preprocessor.d.ts +46 -0
  100. package/dist/skill-preprocessor.d.ts.map +1 -0
  101. package/dist/skill-preprocessor.js +237 -0
  102. package/dist/skill-preprocessor.js.map +1 -0
  103. package/dist/skill-registry.d.ts +107 -0
  104. package/dist/skill-registry.d.ts.map +1 -0
  105. package/dist/skill-registry.js +330 -0
  106. package/dist/skill-registry.js.map +1 -0
  107. package/dist/skill-tool.d.ts +54 -0
  108. package/dist/skill-tool.d.ts.map +1 -0
  109. package/dist/skill-tool.js +88 -0
  110. package/dist/skill-tool.js.map +1 -0
  111. package/dist/sub-agent-manager.d.ts +90 -0
  112. package/dist/sub-agent-manager.d.ts.map +1 -0
  113. package/dist/sub-agent-manager.js +192 -0
  114. package/dist/sub-agent-manager.js.map +1 -0
  115. package/dist/token-estimator.d.ts +23 -0
  116. package/dist/token-estimator.d.ts.map +1 -0
  117. package/dist/token-estimator.js +27 -0
  118. package/dist/token-estimator.js.map +1 -0
  119. package/dist/tool-contract.d.ts +68 -0
  120. package/dist/tool-contract.d.ts.map +1 -0
  121. package/dist/tool-contract.js +35 -0
  122. package/dist/tool-contract.js.map +1 -0
  123. package/dist/tool-result-persistence.d.ts +89 -0
  124. package/dist/tool-result-persistence.d.ts.map +1 -0
  125. package/dist/tool-result-persistence.js +152 -0
  126. package/dist/tool-result-persistence.js.map +1 -0
  127. package/dist/tools/bash/index.d.ts +71 -0
  128. package/dist/tools/bash/index.d.ts.map +1 -0
  129. package/dist/tools/bash/index.js +485 -0
  130. package/dist/tools/bash/index.js.map +1 -0
  131. package/dist/tools/bash/interactive.d.ts +47 -0
  132. package/dist/tools/bash/interactive.d.ts.map +1 -0
  133. package/dist/tools/bash/interactive.js +262 -0
  134. package/dist/tools/bash/interactive.js.map +1 -0
  135. package/dist/tools/bash/safety.d.ts +149 -0
  136. package/dist/tools/bash/safety.d.ts.map +1 -0
  137. package/dist/tools/bash/safety.js +1116 -0
  138. package/dist/tools/bash/safety.js.map +1 -0
  139. package/dist/tools/edit.d.ts +57 -0
  140. package/dist/tools/edit.d.ts.map +1 -0
  141. package/dist/tools/edit.js +310 -0
  142. package/dist/tools/edit.js.map +1 -0
  143. package/dist/tools/glob.d.ts +34 -0
  144. package/dist/tools/glob.d.ts.map +1 -0
  145. package/dist/tools/glob.js +268 -0
  146. package/dist/tools/glob.js.map +1 -0
  147. package/dist/tools/grep.d.ts +53 -0
  148. package/dist/tools/grep.d.ts.map +1 -0
  149. package/dist/tools/grep.js +673 -0
  150. package/dist/tools/grep.js.map +1 -0
  151. package/dist/tools/index.d.ts +62 -0
  152. package/dist/tools/index.d.ts.map +1 -0
  153. package/dist/tools/index.js +52 -0
  154. package/dist/tools/index.js.map +1 -0
  155. package/dist/tools/read.d.ts +43 -0
  156. package/dist/tools/read.d.ts.map +1 -0
  157. package/dist/tools/read.js +459 -0
  158. package/dist/tools/read.js.map +1 -0
  159. package/dist/tools/runtime.d.ts +62 -0
  160. package/dist/tools/runtime.d.ts.map +1 -0
  161. package/dist/tools/runtime.js +116 -0
  162. package/dist/tools/runtime.js.map +1 -0
  163. package/dist/tools/shared/cwd-tracker.d.ts +32 -0
  164. package/dist/tools/shared/cwd-tracker.d.ts.map +1 -0
  165. package/dist/tools/shared/cwd-tracker.js +44 -0
  166. package/dist/tools/shared/cwd-tracker.js.map +1 -0
  167. package/dist/tools/shared/edit-history.d.ts +55 -0
  168. package/dist/tools/shared/edit-history.d.ts.map +1 -0
  169. package/dist/tools/shared/edit-history.js +72 -0
  170. package/dist/tools/shared/edit-history.js.map +1 -0
  171. package/dist/tools/shared/edit-matcher.d.ts +83 -0
  172. package/dist/tools/shared/edit-matcher.d.ts.map +1 -0
  173. package/dist/tools/shared/edit-matcher.js +359 -0
  174. package/dist/tools/shared/edit-matcher.js.map +1 -0
  175. package/dist/tools/shared/file-mutation-lock.d.ts +22 -0
  176. package/dist/tools/shared/file-mutation-lock.d.ts.map +1 -0
  177. package/dist/tools/shared/file-mutation-lock.js +35 -0
  178. package/dist/tools/shared/file-mutation-lock.js.map +1 -0
  179. package/dist/tools/shared/gitignore.d.ts +17 -0
  180. package/dist/tools/shared/gitignore.d.ts.map +1 -0
  181. package/dist/tools/shared/gitignore.js +59 -0
  182. package/dist/tools/shared/gitignore.js.map +1 -0
  183. package/dist/tools/shared/pdf-extractor.d.ts +96 -0
  184. package/dist/tools/shared/pdf-extractor.d.ts.map +1 -0
  185. package/dist/tools/shared/pdf-extractor.js +196 -0
  186. package/dist/tools/shared/pdf-extractor.js.map +1 -0
  187. package/dist/tools/shared/read-registry.d.ts +66 -0
  188. package/dist/tools/shared/read-registry.d.ts.map +1 -0
  189. package/dist/tools/shared/read-registry.js +65 -0
  190. package/dist/tools/shared/read-registry.js.map +1 -0
  191. package/dist/tools/shared/safe-env.d.ts +18 -0
  192. package/dist/tools/shared/safe-env.d.ts.map +1 -0
  193. package/dist/tools/shared/safe-env.js +70 -0
  194. package/dist/tools/shared/safe-env.js.map +1 -0
  195. package/dist/tools/sub-agent.d.ts +91 -0
  196. package/dist/tools/sub-agent.d.ts.map +1 -0
  197. package/dist/tools/sub-agent.js +89 -0
  198. package/dist/tools/sub-agent.js.map +1 -0
  199. package/dist/tools/task-output.d.ts +38 -0
  200. package/dist/tools/task-output.d.ts.map +1 -0
  201. package/dist/tools/task-output.js +186 -0
  202. package/dist/tools/task-output.js.map +1 -0
  203. package/dist/tools/tool-search/index.d.ts +40 -0
  204. package/dist/tools/tool-search/index.d.ts.map +1 -0
  205. package/dist/tools/tool-search/index.js +110 -0
  206. package/dist/tools/tool-search/index.js.map +1 -0
  207. package/dist/tools/tool-search/registry.d.ts +82 -0
  208. package/dist/tools/tool-search/registry.d.ts.map +1 -0
  209. package/dist/tools/tool-search/registry.js +238 -0
  210. package/dist/tools/tool-search/registry.js.map +1 -0
  211. package/dist/tools/undo-edit.d.ts +51 -0
  212. package/dist/tools/undo-edit.d.ts.map +1 -0
  213. package/dist/tools/undo-edit.js +231 -0
  214. package/dist/tools/undo-edit.js.map +1 -0
  215. package/dist/tools/web-fetch/cache.d.ts +49 -0
  216. package/dist/tools/web-fetch/cache.d.ts.map +1 -0
  217. package/dist/tools/web-fetch/cache.js +89 -0
  218. package/dist/tools/web-fetch/cache.js.map +1 -0
  219. package/dist/tools/web-fetch/index.d.ts +53 -0
  220. package/dist/tools/web-fetch/index.d.ts.map +1 -0
  221. package/dist/tools/web-fetch/index.js +513 -0
  222. package/dist/tools/web-fetch/index.js.map +1 -0
  223. package/dist/tools/write.d.ts +59 -0
  224. package/dist/tools/write.d.ts.map +1 -0
  225. package/dist/tools/write.js +316 -0
  226. package/dist/tools/write.js.map +1 -0
  227. package/dist/types.d.ts +881 -0
  228. package/dist/types.d.ts.map +1 -0
  229. package/dist/types.js +16 -0
  230. package/dist/types.js.map +1 -0
  231. package/dist/working-tags.d.ts +44 -0
  232. package/dist/working-tags.d.ts.map +1 -0
  233. package/dist/working-tags.js +103 -0
  234. package/dist/working-tags.js.map +1 -0
  235. package/package.json +87 -0
  236. package/src/budget-guard.ts +170 -0
  237. package/src/compaction/compaction.ts +386 -0
  238. package/src/compaction/failsafe.ts +185 -0
  239. package/src/compaction/index.ts +1199 -0
  240. package/src/compaction/microcompaction.ts +709 -0
  241. package/src/compaction/observational/buffering.ts +430 -0
  242. package/src/compaction/observational/constants.ts +532 -0
  243. package/src/compaction/observational/index.ts +837 -0
  244. package/src/compaction/observational/observer.ts +510 -0
  245. package/src/compaction/observational/recall-tool.ts +130 -0
  246. package/src/compaction/observational/reflector.ts +221 -0
  247. package/src/compaction/observational/types.ts +343 -0
  248. package/src/context-manager.ts +237 -0
  249. package/src/cortex-agent.ts +4297 -0
  250. package/src/error-classifier.ts +199 -0
  251. package/src/event-bridge.ts +508 -0
  252. package/src/index.ts +292 -0
  253. package/src/mcp-client.ts +582 -0
  254. package/src/model-wrapper.ts +128 -0
  255. package/src/noop-logger.ts +9 -0
  256. package/src/prompt-diagnostics.ts +296 -0
  257. package/src/provider-manager.ts +823 -0
  258. package/src/provider-registry.ts +386 -0
  259. package/src/schema-converter.ts +51 -0
  260. package/src/skill-preprocessor.ts +314 -0
  261. package/src/skill-registry.ts +378 -0
  262. package/src/skill-tool.ts +130 -0
  263. package/src/sub-agent-manager.ts +236 -0
  264. package/src/token-estimator.ts +26 -0
  265. package/src/tool-contract.ts +113 -0
  266. package/src/tool-result-persistence.ts +197 -0
  267. package/src/tools/bash/index.ts +633 -0
  268. package/src/tools/bash/interactive.ts +302 -0
  269. package/src/tools/bash/safety.ts +1297 -0
  270. package/src/tools/edit.ts +422 -0
  271. package/src/tools/glob.ts +330 -0
  272. package/src/tools/grep.ts +819 -0
  273. package/src/tools/index.ts +110 -0
  274. package/src/tools/read.ts +580 -0
  275. package/src/tools/runtime.ts +173 -0
  276. package/src/tools/shared/cwd-tracker.ts +50 -0
  277. package/src/tools/shared/edit-history.ts +96 -0
  278. package/src/tools/shared/edit-matcher.ts +457 -0
  279. package/src/tools/shared/file-mutation-lock.ts +40 -0
  280. package/src/tools/shared/gitignore.ts +61 -0
  281. package/src/tools/shared/pdf-extractor.ts +290 -0
  282. package/src/tools/shared/read-registry.ts +93 -0
  283. package/src/tools/shared/safe-env.ts +82 -0
  284. package/src/tools/sub-agent.ts +171 -0
  285. package/src/tools/task-output.ts +236 -0
  286. package/src/tools/tool-search/index.ts +167 -0
  287. package/src/tools/tool-search/registry.ts +278 -0
  288. package/src/tools/undo-edit.ts +314 -0
  289. package/src/tools/web-fetch/cache.ts +112 -0
  290. package/src/tools/web-fetch/index.ts +604 -0
  291. package/src/tools/write.ts +385 -0
  292. package/src/types.ts +1057 -0
  293. package/src/working-tags.ts +118 -0
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Interactive command detection for Bash.
3
+ *
4
+ * Catches commands that would block waiting for TTY input (editors,
5
+ * pagers, REPLs, interactive DB clients) and rejects them with a
6
+ * concrete non-interactive suggestion. Prevents the agent from burning
7
+ * its entire timeout budget on a hung `vim` or `psql` invocation.
8
+ *
9
+ * This is a UX gate, not a security gate: it sits at the end of the
10
+ * safety cascade after all security layers have passed. Security checks
11
+ * always come first.
12
+ *
13
+ * The module is pure — no I/O, no global state — so the rule set can be
14
+ * exhaustively unit-tested without a shell.
15
+ */
16
+ import { splitOnShellOperators } from './safety.js';
17
+ // ---------------------------------------------------------------------------
18
+ // Rule groups
19
+ // ---------------------------------------------------------------------------
20
+ const EDITORS = ['vim', 'vi', 'nvim', 'emacs', 'emacsclient', 'nano', 'pico', 'ed', 'joe'];
21
+ const MONITORS = ['top', 'htop', 'atop', 'btop', 'watch'];
22
+ const PAGERS = ['less', 'more', 'most'];
23
+ function alwaysInteractive(name, suggestion) {
24
+ return { name, check: () => suggestion };
25
+ }
26
+ const RULES = [
27
+ ...EDITORS.map((name) => alwaysInteractive(name, `${name} is a terminal editor and will block waiting for input. Use the Edit or Write tools to modify files instead.`)),
28
+ ...MONITORS.map((name) => alwaysInteractive(name, `${name} runs continuously and blocks the shell. Use a one-shot alternative (e.g. \`ps aux | head\`, \`uptime\`, \`df -h\`).`)),
29
+ // Pagers block even when piped — they paginate on keypress.
30
+ ...PAGERS.map((name) => alwaysInteractive(name, `${name} paginates and will block waiting for a keypress. Use \`cat\`, \`head\`, or \`tail\` instead.`)),
31
+ // Python: interactive unless given a script file or -c/-m.
32
+ ...['python', 'python2', 'python3'].map((name) => ({
33
+ name,
34
+ check: (args) => pythonCheck(name, args),
35
+ })),
36
+ { name: 'node', check: nodeCheck },
37
+ { name: 'ruby', check: rubyCheck },
38
+ alwaysInteractive('irb', 'irb opens an interactive Ruby shell. Use `ruby -e "..."` for one-off code.'),
39
+ { name: 'mongo', check: (args) => mongoCheck('mongo', args) },
40
+ { name: 'mongosh', check: (args) => mongoCheck('mongosh', args) },
41
+ { name: 'sqlite3', check: sqliteCheck },
42
+ { name: 'psql', check: psqlCheck },
43
+ { name: 'mysql', check: mysqlCheck },
44
+ { name: 'mariadb', check: mysqlCheck },
45
+ ];
46
+ // Fast lookup by basename.
47
+ const RULES_BY_NAME = new Map(RULES.map((r) => [r.name, r]));
48
+ // ---------------------------------------------------------------------------
49
+ // Public entry point
50
+ // ---------------------------------------------------------------------------
51
+ /**
52
+ * Check a full shell command for interactive invocations. Splits on
53
+ * shell operators (`;`, `&&`, `||`, `|`) and inspects each sub-command
54
+ * independently — `cat file | less` is rejected because the `less`
55
+ * sub-command is interactive, even though `cat` is not.
56
+ *
57
+ * Returns the first interactive sub-command's rejection; if all
58
+ * sub-commands are non-interactive, returns `{ allowed: true }`.
59
+ */
60
+ export function checkInteractive(command) {
61
+ const subs = splitOnShellOperators(command);
62
+ for (const sub of subs) {
63
+ const tokens = tokenize(sub);
64
+ const program = findProgram(tokens);
65
+ if (!program)
66
+ continue;
67
+ const rule = RULES_BY_NAME.get(program.name);
68
+ if (!rule)
69
+ continue;
70
+ const suggestion = rule.check(program.args);
71
+ if (suggestion !== null) {
72
+ return {
73
+ allowed: false,
74
+ reason: `Interactive command detected. ${suggestion}`,
75
+ };
76
+ }
77
+ }
78
+ return { allowed: true };
79
+ }
80
+ // ---------------------------------------------------------------------------
81
+ // Tokenization
82
+ // ---------------------------------------------------------------------------
83
+ /**
84
+ * Minimal shell-aware tokenizer: splits on unquoted whitespace, keeps
85
+ * single/double-quoted regions intact (quotes themselves are stripped),
86
+ * and honors backslash escapes. Sufficient for identifying the program
87
+ * token and distinguishing flags from positional args; not a complete
88
+ * POSIX shell parser.
89
+ */
90
+ export function tokenize(command) {
91
+ const tokens = [];
92
+ let current = '';
93
+ let inSingle = false;
94
+ let inDouble = false;
95
+ for (let i = 0; i < command.length; i++) {
96
+ const ch = command[i];
97
+ if (!inSingle && ch === '\\' && i + 1 < command.length) {
98
+ current += command[i + 1];
99
+ i++;
100
+ continue;
101
+ }
102
+ if (!inDouble && ch === "'") {
103
+ inSingle = !inSingle;
104
+ continue;
105
+ }
106
+ if (!inSingle && ch === '"') {
107
+ inDouble = !inDouble;
108
+ continue;
109
+ }
110
+ if (!inSingle && !inDouble && /\s/u.test(ch)) {
111
+ if (current.length > 0) {
112
+ tokens.push(current);
113
+ current = '';
114
+ }
115
+ continue;
116
+ }
117
+ current += ch;
118
+ }
119
+ if (current.length > 0)
120
+ tokens.push(current);
121
+ return tokens;
122
+ }
123
+ /**
124
+ * Find the effective program name and argument list, accounting for:
125
+ * 1. Leading `KEY=VALUE` env var prefixes (`FOO=bar vim file`)
126
+ * 2. The `env` wrapper (`env FOO=bar vim file` or `env -u BAR vim`)
127
+ *
128
+ * Returns the program's basename (last path segment) and the remaining
129
+ * arg tokens, or `null` if no program token is present.
130
+ */
131
+ export function findProgram(tokens) {
132
+ let i = 0;
133
+ while (i < tokens.length && isEnvAssignment(tokens[i]))
134
+ i++;
135
+ if (i < tokens.length && tokens[i] === 'env') {
136
+ i++;
137
+ // `env`'s flags that take a subsequent argument. We need to skip
138
+ // both the flag and its value so a value that doesn't look like a
139
+ // flag (e.g. `env -u OLD vim`) isn't mistaken for the program.
140
+ const ARG_FLAGS_SHORT = new Set(['-u', '-C', '-S']);
141
+ const ARG_FLAGS_LONG = new Set(['--unset', '--chdir', '--split-string']);
142
+ while (i < tokens.length) {
143
+ const t = tokens[i];
144
+ if (isEnvAssignment(t)) {
145
+ i++;
146
+ continue;
147
+ }
148
+ if (!t.startsWith('-'))
149
+ break;
150
+ if (ARG_FLAGS_SHORT.has(t) || ARG_FLAGS_LONG.has(t)) {
151
+ i += 2; // consume flag + value
152
+ continue;
153
+ }
154
+ // --long=value form or flags with no arg (-i, -0, --verbose, etc.)
155
+ i++;
156
+ }
157
+ }
158
+ if (i >= tokens.length)
159
+ return null;
160
+ const prog = tokens[i];
161
+ const basename = prog.split('/').pop() ?? prog;
162
+ return { name: basename, args: tokens.slice(i + 1) };
163
+ }
164
+ function isEnvAssignment(token) {
165
+ return /^[A-Za-z_][A-Za-z0-9_]*=/u.test(token);
166
+ }
167
+ // ---------------------------------------------------------------------------
168
+ // Per-program predicates
169
+ // ---------------------------------------------------------------------------
170
+ function pythonCheck(name, args) {
171
+ for (let i = 0; i < args.length; i++) {
172
+ const arg = args[i];
173
+ // -c / -m consume the next arg but the presence alone is enough.
174
+ if (arg === '-c' || arg === '-m')
175
+ return null;
176
+ if (arg === '-V' || arg === '--version')
177
+ return null;
178
+ if (arg === '-h' || arg === '--help')
179
+ return null;
180
+ // Script file.
181
+ if (/\.py[ocw]?$/u.test(arg) && !arg.startsWith('-'))
182
+ return null;
183
+ // Any positional arg is treated as a script (matches how Python's argv
184
+ // parser works).
185
+ if (!arg.startsWith('-'))
186
+ return null;
187
+ }
188
+ return `${name} without a script or \`-c\`/\`-m\` starts an interactive REPL and will block. Provide a script file or use \`${name} -c "..."\`.`;
189
+ }
190
+ function nodeCheck(args) {
191
+ for (const arg of args) {
192
+ if (arg === '-e' ||
193
+ arg === '--eval' ||
194
+ arg === '-p' ||
195
+ arg === '--print' ||
196
+ arg === '-v' ||
197
+ arg === '--version' ||
198
+ arg === '-h' ||
199
+ arg === '--help') {
200
+ return null;
201
+ }
202
+ if (!arg.startsWith('-'))
203
+ return null; // script file or --file
204
+ }
205
+ return 'node without a script or `-e` starts an interactive REPL and will block. Provide a script file or use `node -e "..."`.';
206
+ }
207
+ function rubyCheck(args) {
208
+ for (const arg of args) {
209
+ if (arg === '-e' || arg === '-v' || arg === '--version' || arg === '-h' || arg === '--help') {
210
+ return null;
211
+ }
212
+ if (!arg.startsWith('-'))
213
+ return null;
214
+ }
215
+ return 'ruby without a script or `-e` reads from stdin and will block. Provide a `.rb` file or use `ruby -e "..."`.';
216
+ }
217
+ function mongoCheck(name, args) {
218
+ if (args.includes('--eval') || args.includes('-e') || args.includes('--version') || args.includes('--help')) {
219
+ return null;
220
+ }
221
+ // Executing a script file is also non-interactive.
222
+ if (args.some((a) => /\.js$/u.test(a) && !a.startsWith('-')))
223
+ return null;
224
+ return `${name} without \`--eval\` or a script file opens an interactive shell. Use \`${name} --eval "..."\`.`;
225
+ }
226
+ function sqliteCheck(args) {
227
+ if (args.includes('-cmd') || args.includes('-batch') || args.includes('-version') || args.includes('--help')) {
228
+ return null;
229
+ }
230
+ // sqlite3 <db> "<sql>" — two or more non-flag args means the second is a query.
231
+ const nonFlag = args.filter((a) => !a.startsWith('-'));
232
+ if (nonFlag.length >= 2)
233
+ return null;
234
+ return 'sqlite3 without a SQL argument opens an interactive prompt. Use `sqlite3 <db> "<sql>"` or pass `-cmd "..."`.';
235
+ }
236
+ function psqlCheck(args) {
237
+ // -c / --command: inline SQL. -f / --file: script file. -l / --list: list DBs.
238
+ // --version / -V: version. All are single-shot, non-interactive.
239
+ // NOTE: -h means "host" in psql, NOT help. We do not treat it as safe.
240
+ const safeFlags = new Set([
241
+ '-c', '--command', '-f', '--file', '-l', '--list', '--version', '-V', '--help',
242
+ ]);
243
+ for (const arg of args) {
244
+ if (safeFlags.has(arg))
245
+ return null;
246
+ // Flags written as --command=VALUE.
247
+ if (arg.startsWith('--command=') || arg.startsWith('--file='))
248
+ return null;
249
+ }
250
+ return 'psql without `-c` or `-f` opens an interactive prompt. Use `psql -c "SELECT ..."` or `psql -f script.sql`.';
251
+ }
252
+ function mysqlCheck(args) {
253
+ const safeFlags = new Set(['-e', '--execute', '--version', '-V', '--help', '-?']);
254
+ for (const arg of args) {
255
+ if (safeFlags.has(arg))
256
+ return null;
257
+ if (arg.startsWith('--execute='))
258
+ return null;
259
+ }
260
+ return 'mysql without `-e` opens an interactive prompt. Use `mysql -e "SELECT ..."`.';
261
+ }
262
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../../src/tools/bash/interactive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Bash tool safety layers.
3
+ *
4
+ * Seven layers of defense-in-depth for shell command execution, plus a
5
+ * final UX gate:
6
+ * 1. Environment variable stripping
7
+ * 2. Critical path protection
8
+ * 3. Command classification
9
+ * 4. Path validation for write commands
10
+ * 5. Obfuscation and injection detection
11
+ * 6. Script preflight
12
+ * 6.5. Interactive command detection (UX gate — prevents silent timeouts
13
+ * on editors, pagers, REPLs, and interactive DB clients)
14
+ * 7. Auto-mode classifier (utility model LLM call)
15
+ *
16
+ * Reference: docs/cortex/tools/bash.md (Safety Architecture)
17
+ */
18
+ export type CommandClassification = 'read' | 'write' | 'create' | 'network' | 'safe-stdin' | 'unknown';
19
+ export interface SafetyCheckResult {
20
+ allowed: boolean;
21
+ reason?: string | undefined;
22
+ classification?: CommandClassification | undefined;
23
+ }
24
+ /**
25
+ * Build a safe environment for child processes by stripping dangerous variables.
26
+ * Adds CORTEX_SHELL=exec as a context marker.
27
+ *
28
+ * Delegates to the shared buildSafeEnv utility so that both the Bash tool
29
+ * and the MCP client use the same blocklist.
30
+ *
31
+ * @param parentEnv - The source environment (typically process.env)
32
+ * @param overrides - Optional env var overrides that bypass the blocklist
33
+ */
34
+ export declare function buildSafeEnv(parentEnv: NodeJS.ProcessEnv, overrides?: Record<string, string>): Record<string, string>;
35
+ /**
36
+ * Check if a target path resolves to a critical system directory.
37
+ */
38
+ export declare function isCriticalPath(targetPath: string): boolean;
39
+ /**
40
+ * Split a command string on shell operators (; && || |) while respecting
41
+ * quoted strings. Returns the individual sub-commands.
42
+ */
43
+ export declare function splitOnShellOperators(command: string): string[];
44
+ /**
45
+ * Classify a command (potentially compound) by its potential impact.
46
+ * For compound commands, returns the highest-risk classification
47
+ * among all sub-commands.
48
+ */
49
+ export declare function classifyCommand(command: string): CommandClassification;
50
+ /**
51
+ * Extract target paths from write/create commands.
52
+ * Returns the paths that would be modified by the command.
53
+ * Handles compound commands by extracting paths from all sub-commands.
54
+ */
55
+ export declare function extractWritePaths(command: string): string[];
56
+ /**
57
+ * Validate that write paths are within the allowed working directory.
58
+ */
59
+ export declare function validateWritePaths(command: string, workingDirectory: string, currentCwd: string): SafetyCheckResult;
60
+ /**
61
+ * Strip invisible Unicode characters that could be used for obfuscation.
62
+ */
63
+ export declare function stripInvisibleChars(command: string): string;
64
+ /**
65
+ * Per-character quote context. Describes the quoting state at a given position.
66
+ */
67
+ export type QuoteContext = 'none' | 'single' | 'double' | 'backtick' | 'escaped';
68
+ /**
69
+ * Analyze the quoting context of each character in a shell command.
70
+ * Returns an array of QuoteContext values, one per character, indicating
71
+ * whether that position is inside single quotes, double quotes, backticks,
72
+ * escaped, or unquoted. Handles nested escapes correctly (e.g., `\"` inside
73
+ * double quotes keeps the next character as "double", not "escaped").
74
+ */
75
+ export declare function analyzeQuoteState(command: string): QuoteContext[];
76
+ /**
77
+ * Detect IFS variable manipulation in unquoted context.
78
+ * `IFS=` inside quotes is harmless (just a string literal).
79
+ * Unquoted `IFS=` is a shell variable assignment that can enable attacks.
80
+ */
81
+ export declare function checkIfsInjection(command: string, states: QuoteContext[]): SafetyCheckResult;
82
+ /**
83
+ * Detect access to sensitive /proc and /sys paths in unquoted context.
84
+ * Quoted references (e.g., `echo "/proc/self/environ"`) are harmless string
85
+ * literals. Unquoted references indicate actual filesystem access attempts.
86
+ */
87
+ export declare function checkProcSysAccess(command: string, states: QuoteContext[]): SafetyCheckResult;
88
+ /**
89
+ * Detect jq command abuse: system() calls, @sh filter for shell injection,
90
+ * and -n with module imports that could load malicious jq modules.
91
+ */
92
+ export declare function checkJqAbuse(command: string): SafetyCheckResult;
93
+ /**
94
+ * Detect ANSI-C quoting ($'...') with hex or octal escape sequences that
95
+ * encode potentially dangerous content. Simple escapes like $'\n' and $'\t'
96
+ * are legitimate and allowed.
97
+ */
98
+ export declare function checkAnsiCQuoting(command: string): SafetyCheckResult;
99
+ /**
100
+ * Detect heredoc patterns and validate their content. Unquoted heredoc
101
+ * delimiters (<<EOF) allow variable expansion and command substitution in
102
+ * the body, which can be used for injection. Quoted delimiters (<<'EOF')
103
+ * are treated as literal text and are safe.
104
+ */
105
+ export declare function checkHeredocInjection(command: string): SafetyCheckResult;
106
+ /**
107
+ * Detect brace expansion patterns ({a,b} or {1..N}) in unquoted context
108
+ * that target suspicious paths or combine with dangerous commands.
109
+ */
110
+ export declare function checkBraceExpansion(command: string, states: QuoteContext[]): SafetyCheckResult;
111
+ /**
112
+ * Detect escape chains and printf hex/octal patterns that can hide dangerous
113
+ * commands from string-level pattern matching.
114
+ */
115
+ export declare function checkEnhancedEscapes(command: string, states: QuoteContext[]): SafetyCheckResult;
116
+ /**
117
+ * Check a command for obfuscation and injection patterns.
118
+ */
119
+ export declare function checkObfuscation(command: string): SafetyCheckResult;
120
+ /**
121
+ * Check if a command is running a script file, and if so,
122
+ * scan the script for shell syntax bleed.
123
+ */
124
+ export declare function checkScriptPreflight(command: string, cwd: string): Promise<SafetyCheckResult>;
125
+ /**
126
+ * Auto-mode classifier that uses the utility model to classify whether
127
+ * a command should be blocked in autonomous mode.
128
+ *
129
+ * The full implementation will:
130
+ * 1. Fast check (256 max tokens): quick classification
131
+ * 2. Full analysis (4096 max tokens): if fast check is uncertain
132
+ *
133
+ * Fail-safe behavior: when auto-approve mode is active (isAutoApprove=true)
134
+ * but no classifier function is available, this layer BLOCKS the command.
135
+ * When auto-approve is not active, the consumer's permission resolver
136
+ * (beforeToolCall) has already approved, so this layer passes through.
137
+ */
138
+ export declare function checkAutoModeClassifier(_command: string, _description: string | undefined, _utilityComplete?: ((context: unknown) => Promise<unknown>) | undefined, isAutoApprove?: boolean): Promise<SafetyCheckResult>;
139
+ /**
140
+ * Run all safety layers on a command.
141
+ * Returns the first failure or { allowed: true } if all pass.
142
+ */
143
+ export declare function runSafetyChecks(command: string, workingDirectory: string, currentCwd: string, options?: {
144
+ utilityComplete?: ((context: unknown) => Promise<unknown>) | undefined;
145
+ description?: string | undefined;
146
+ /** Whether the consumer is in auto-approve mode. When true and no classifier is available, Layer 7 blocks. */
147
+ isAutoApprove?: boolean | undefined;
148
+ }): Promise<SafetyCheckResult>;
149
+ //# sourceMappingURL=safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../../src/tools/bash/safety.ts"],"names":[],"mappings":"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"}