moderado 0.3.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 (275) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +208 -0
  3. package/dist/args.d.ts +26 -0
  4. package/dist/args.d.ts.map +1 -0
  5. package/dist/args.js +108 -0
  6. package/dist/args.js.map +1 -0
  7. package/dist/commands/chat.d.ts +121 -0
  8. package/dist/commands/chat.d.ts.map +1 -0
  9. package/dist/commands/chat.js +1484 -0
  10. package/dist/commands/chat.js.map +1 -0
  11. package/dist/commands/doctor.d.ts +3 -0
  12. package/dist/commands/doctor.d.ts.map +1 -0
  13. package/dist/commands/doctor.js +61 -0
  14. package/dist/commands/doctor.js.map +1 -0
  15. package/dist/commands/init.d.ts +27 -0
  16. package/dist/commands/init.d.ts.map +1 -0
  17. package/dist/commands/init.js +172 -0
  18. package/dist/commands/init.js.map +1 -0
  19. package/dist/commands/interactive_menu.d.ts +3 -0
  20. package/dist/commands/interactive_menu.d.ts.map +1 -0
  21. package/dist/commands/interactive_menu.js +98 -0
  22. package/dist/commands/interactive_menu.js.map +1 -0
  23. package/dist/commands/models.d.ts +8 -0
  24. package/dist/commands/models.d.ts.map +1 -0
  25. package/dist/commands/models.js +81 -0
  26. package/dist/commands/models.js.map +1 -0
  27. package/dist/commands/run.d.ts +3 -0
  28. package/dist/commands/run.d.ts.map +1 -0
  29. package/dist/commands/run.js +140 -0
  30. package/dist/commands/run.js.map +1 -0
  31. package/dist/config.d.ts +44 -0
  32. package/dist/config.d.ts.map +1 -0
  33. package/dist/config.js +195 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/credentials.d.ts +14 -0
  36. package/dist/credentials.d.ts.map +1 -0
  37. package/dist/credentials.js +23 -0
  38. package/dist/credentials.js.map +1 -0
  39. package/dist/diagnostic_log.d.ts +2 -0
  40. package/dist/diagnostic_log.d.ts.map +1 -0
  41. package/dist/diagnostic_log.js +21 -0
  42. package/dist/diagnostic_log.js.map +1 -0
  43. package/dist/index.d.ts +3 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +83 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/model_pricing.d.ts +4 -0
  48. package/dist/model_pricing.d.ts.map +1 -0
  49. package/dist/model_pricing.js +10 -0
  50. package/dist/model_pricing.js.map +1 -0
  51. package/dist/sessions.d.ts +203 -0
  52. package/dist/sessions.d.ts.map +1 -0
  53. package/dist/sessions.js +82 -0
  54. package/dist/sessions.js.map +1 -0
  55. package/dist/ui/box.d.ts +14 -0
  56. package/dist/ui/box.d.ts.map +1 -0
  57. package/dist/ui/box.js +52 -0
  58. package/dist/ui/box.js.map +1 -0
  59. package/dist/ui/file_mentions.d.ts +38 -0
  60. package/dist/ui/file_mentions.d.ts.map +1 -0
  61. package/dist/ui/file_mentions.js +119 -0
  62. package/dist/ui/file_mentions.js.map +1 -0
  63. package/dist/ui/help_modal.d.ts +2 -0
  64. package/dist/ui/help_modal.d.ts.map +1 -0
  65. package/dist/ui/help_modal.js +101 -0
  66. package/dist/ui/help_modal.js.map +1 -0
  67. package/dist/ui/model_selector.d.ts +48 -0
  68. package/dist/ui/model_selector.d.ts.map +1 -0
  69. package/dist/ui/model_selector.js +829 -0
  70. package/dist/ui/model_selector.js.map +1 -0
  71. package/dist/ui/popup.d.ts +78 -0
  72. package/dist/ui/popup.d.ts.map +1 -0
  73. package/dist/ui/popup.js +274 -0
  74. package/dist/ui/popup.js.map +1 -0
  75. package/dist/ui/prompt.d.ts +21 -0
  76. package/dist/ui/prompt.d.ts.map +1 -0
  77. package/dist/ui/prompt.js +128 -0
  78. package/dist/ui/prompt.js.map +1 -0
  79. package/dist/ui/provider_connect.d.ts +33 -0
  80. package/dist/ui/provider_connect.d.ts.map +1 -0
  81. package/dist/ui/provider_connect.js +175 -0
  82. package/dist/ui/provider_connect.js.map +1 -0
  83. package/dist/ui/renderer.d.ts +19 -0
  84. package/dist/ui/renderer.d.ts.map +1 -0
  85. package/dist/ui/renderer.js +147 -0
  86. package/dist/ui/renderer.js.map +1 -0
  87. package/dist/ui/session_screen.d.ts +32 -0
  88. package/dist/ui/session_screen.d.ts.map +1 -0
  89. package/dist/ui/session_screen.js +148 -0
  90. package/dist/ui/session_screen.js.map +1 -0
  91. package/dist/ui/session_terminal.d.ts +46 -0
  92. package/dist/ui/session_terminal.d.ts.map +1 -0
  93. package/dist/ui/session_terminal.js +342 -0
  94. package/dist/ui/session_terminal.js.map +1 -0
  95. package/dist/ui/terminal_approval.d.ts +14 -0
  96. package/dist/ui/terminal_approval.d.ts.map +1 -0
  97. package/dist/ui/terminal_approval.js +98 -0
  98. package/dist/ui/terminal_approval.js.map +1 -0
  99. package/dist/ui/welcome.d.ts +130 -0
  100. package/dist/ui/welcome.d.ts.map +1 -0
  101. package/dist/ui/welcome.js +990 -0
  102. package/dist/ui/welcome.js.map +1 -0
  103. package/dist/vendor/contracts/approvals.d.ts +91 -0
  104. package/dist/vendor/contracts/approvals.d.ts.map +1 -0
  105. package/dist/vendor/contracts/approvals.js +22 -0
  106. package/dist/vendor/contracts/approvals.js.map +1 -0
  107. package/dist/vendor/contracts/events.d.ts +1215 -0
  108. package/dist/vendor/contracts/events.d.ts.map +1 -0
  109. package/dist/vendor/contracts/events.js +94 -0
  110. package/dist/vendor/contracts/events.js.map +1 -0
  111. package/dist/vendor/contracts/index.d.ts +7 -0
  112. package/dist/vendor/contracts/index.d.ts.map +1 -0
  113. package/dist/vendor/contracts/index.js +7 -0
  114. package/dist/vendor/contracts/index.js.map +1 -0
  115. package/dist/vendor/contracts/messages.d.ts +181 -0
  116. package/dist/vendor/contracts/messages.d.ts.map +1 -0
  117. package/dist/vendor/contracts/messages.js +40 -0
  118. package/dist/vendor/contracts/messages.js.map +1 -0
  119. package/dist/vendor/contracts/models.d.ts +117 -0
  120. package/dist/vendor/contracts/models.d.ts.map +1 -0
  121. package/dist/vendor/contracts/models.js +37 -0
  122. package/dist/vendor/contracts/models.js.map +1 -0
  123. package/dist/vendor/contracts/provider.d.ts +121 -0
  124. package/dist/vendor/contracts/provider.d.ts.map +1 -0
  125. package/dist/vendor/contracts/provider.js +64 -0
  126. package/dist/vendor/contracts/provider.js.map +1 -0
  127. package/dist/vendor/contracts/tools.d.ts +305 -0
  128. package/dist/vendor/contracts/tools.d.ts.map +1 -0
  129. package/dist/vendor/contracts/tools.js +65 -0
  130. package/dist/vendor/contracts/tools.js.map +1 -0
  131. package/dist/vendor/core/agent.d.ts +39 -0
  132. package/dist/vendor/core/agent.d.ts.map +1 -0
  133. package/dist/vendor/core/agent.js +710 -0
  134. package/dist/vendor/core/agent.js.map +1 -0
  135. package/dist/vendor/core/host_event_stream.d.ts +9 -0
  136. package/dist/vendor/core/host_event_stream.d.ts.map +1 -0
  137. package/dist/vendor/core/host_event_stream.js +12 -0
  138. package/dist/vendor/core/host_event_stream.js.map +1 -0
  139. package/dist/vendor/core/index.d.ts +7 -0
  140. package/dist/vendor/core/index.d.ts.map +1 -0
  141. package/dist/vendor/core/index.js +7 -0
  142. package/dist/vendor/core/index.js.map +1 -0
  143. package/dist/vendor/core/policy.d.ts +19 -0
  144. package/dist/vendor/core/policy.d.ts.map +1 -0
  145. package/dist/vendor/core/policy.js +31 -0
  146. package/dist/vendor/core/policy.js.map +1 -0
  147. package/dist/vendor/core/router.d.ts +26 -0
  148. package/dist/vendor/core/router.d.ts.map +1 -0
  149. package/dist/vendor/core/router.js +222 -0
  150. package/dist/vendor/core/router.js.map +1 -0
  151. package/dist/vendor/core/subagent.d.ts +29 -0
  152. package/dist/vendor/core/subagent.d.ts.map +1 -0
  153. package/dist/vendor/core/subagent.js +66 -0
  154. package/dist/vendor/core/subagent.js.map +1 -0
  155. package/dist/vendor/core/think_filter.d.ts +14 -0
  156. package/dist/vendor/core/think_filter.d.ts.map +1 -0
  157. package/dist/vendor/core/think_filter.js +136 -0
  158. package/dist/vendor/core/think_filter.js.map +1 -0
  159. package/dist/vendor/providers/fake/fake_provider.d.ts +16 -0
  160. package/dist/vendor/providers/fake/fake_provider.d.ts.map +1 -0
  161. package/dist/vendor/providers/fake/fake_provider.js +89 -0
  162. package/dist/vendor/providers/fake/fake_provider.js.map +1 -0
  163. package/dist/vendor/providers/index.d.ts +6 -0
  164. package/dist/vendor/providers/index.d.ts.map +1 -0
  165. package/dist/vendor/providers/index.js +6 -0
  166. package/dist/vendor/providers/index.js.map +1 -0
  167. package/dist/vendor/providers/model_discovery.d.ts +28 -0
  168. package/dist/vendor/providers/model_discovery.d.ts.map +1 -0
  169. package/dist/vendor/providers/model_discovery.js +106 -0
  170. package/dist/vendor/providers/model_discovery.js.map +1 -0
  171. package/dist/vendor/providers/nvidia/nvidia_adapter.d.ts +23 -0
  172. package/dist/vendor/providers/nvidia/nvidia_adapter.d.ts.map +1 -0
  173. package/dist/vendor/providers/nvidia/nvidia_adapter.js +197 -0
  174. package/dist/vendor/providers/nvidia/nvidia_adapter.js.map +1 -0
  175. package/dist/vendor/providers/nvidia/sse_parser.d.ts +3 -0
  176. package/dist/vendor/providers/nvidia/sse_parser.d.ts.map +1 -0
  177. package/dist/vendor/providers/nvidia/sse_parser.js +84 -0
  178. package/dist/vendor/providers/nvidia/sse_parser.js.map +1 -0
  179. package/dist/vendor/providers/openai_compatible_adapter.d.ts +10 -0
  180. package/dist/vendor/providers/openai_compatible_adapter.d.ts.map +1 -0
  181. package/dist/vendor/providers/openai_compatible_adapter.js +8 -0
  182. package/dist/vendor/providers/openai_compatible_adapter.js.map +1 -0
  183. package/dist/vendor/tools/checkpoints.d.ts +27 -0
  184. package/dist/vendor/tools/checkpoints.d.ts.map +1 -0
  185. package/dist/vendor/tools/checkpoints.js +145 -0
  186. package/dist/vendor/tools/checkpoints.js.map +1 -0
  187. package/dist/vendor/tools/diagnostics.d.ts +11 -0
  188. package/dist/vendor/tools/diagnostics.d.ts.map +1 -0
  189. package/dist/vendor/tools/diagnostics.js +16 -0
  190. package/dist/vendor/tools/diagnostics.js.map +1 -0
  191. package/dist/vendor/tools/diff.d.ts +7 -0
  192. package/dist/vendor/tools/diff.d.ts.map +1 -0
  193. package/dist/vendor/tools/diff.js +48 -0
  194. package/dist/vendor/tools/diff.js.map +1 -0
  195. package/dist/vendor/tools/errors.d.ts +17 -0
  196. package/dist/vendor/tools/errors.d.ts.map +1 -0
  197. package/dist/vendor/tools/errors.js +33 -0
  198. package/dist/vendor/tools/errors.js.map +1 -0
  199. package/dist/vendor/tools/git_workspace.d.ts +14 -0
  200. package/dist/vendor/tools/git_workspace.d.ts.map +1 -0
  201. package/dist/vendor/tools/git_workspace.js +42 -0
  202. package/dist/vendor/tools/git_workspace.js.map +1 -0
  203. package/dist/vendor/tools/index.d.ts +22 -0
  204. package/dist/vendor/tools/index.d.ts.map +1 -0
  205. package/dist/vendor/tools/index.js +22 -0
  206. package/dist/vendor/tools/index.js.map +1 -0
  207. package/dist/vendor/tools/jail.d.ts +17 -0
  208. package/dist/vendor/tools/jail.d.ts.map +1 -0
  209. package/dist/vendor/tools/jail.js +221 -0
  210. package/dist/vendor/tools/jail.js.map +1 -0
  211. package/dist/vendor/tools/lsp.d.ts +3 -0
  212. package/dist/vendor/tools/lsp.d.ts.map +1 -0
  213. package/dist/vendor/tools/lsp.js +43 -0
  214. package/dist/vendor/tools/lsp.js.map +1 -0
  215. package/dist/vendor/tools/mcp.d.ts +9 -0
  216. package/dist/vendor/tools/mcp.d.ts.map +1 -0
  217. package/dist/vendor/tools/mcp.js +54 -0
  218. package/dist/vendor/tools/mcp.js.map +1 -0
  219. package/dist/vendor/tools/mcp_adapter.d.ts +15 -0
  220. package/dist/vendor/tools/mcp_adapter.d.ts.map +1 -0
  221. package/dist/vendor/tools/mcp_adapter.js +29 -0
  222. package/dist/vendor/tools/mcp_adapter.js.map +1 -0
  223. package/dist/vendor/tools/registry.d.ts +10 -0
  224. package/dist/vendor/tools/registry.d.ts.map +1 -0
  225. package/dist/vendor/tools/registry.js +126 -0
  226. package/dist/vendor/tools/registry.js.map +1 -0
  227. package/dist/vendor/tools/tools/apply_patch.d.ts +3 -0
  228. package/dist/vendor/tools/tools/apply_patch.d.ts.map +1 -0
  229. package/dist/vendor/tools/tools/apply_patch.js +49 -0
  230. package/dist/vendor/tools/tools/apply_patch.js.map +1 -0
  231. package/dist/vendor/tools/tools/edit_file.d.ts +3 -0
  232. package/dist/vendor/tools/tools/edit_file.d.ts.map +1 -0
  233. package/dist/vendor/tools/tools/edit_file.js +71 -0
  234. package/dist/vendor/tools/tools/edit_file.js.map +1 -0
  235. package/dist/vendor/tools/tools/git_diff.d.ts +3 -0
  236. package/dist/vendor/tools/tools/git_diff.d.ts.map +1 -0
  237. package/dist/vendor/tools/tools/git_diff.js +91 -0
  238. package/dist/vendor/tools/tools/git_diff.js.map +1 -0
  239. package/dist/vendor/tools/tools/language_intelligence.d.ts +4 -0
  240. package/dist/vendor/tools/tools/language_intelligence.d.ts.map +1 -0
  241. package/dist/vendor/tools/tools/language_intelligence.js +13 -0
  242. package/dist/vendor/tools/tools/language_intelligence.js.map +1 -0
  243. package/dist/vendor/tools/tools/list_files.d.ts +9 -0
  244. package/dist/vendor/tools/tools/list_files.d.ts.map +1 -0
  245. package/dist/vendor/tools/tools/list_files.js +165 -0
  246. package/dist/vendor/tools/tools/list_files.js.map +1 -0
  247. package/dist/vendor/tools/tools/read_file.d.ts +3 -0
  248. package/dist/vendor/tools/tools/read_file.d.ts.map +1 -0
  249. package/dist/vendor/tools/tools/read_file.js +72 -0
  250. package/dist/vendor/tools/tools/read_file.js.map +1 -0
  251. package/dist/vendor/tools/tools/run_command.d.ts +12 -0
  252. package/dist/vendor/tools/tools/run_command.d.ts.map +1 -0
  253. package/dist/vendor/tools/tools/run_command.js +421 -0
  254. package/dist/vendor/tools/tools/run_command.js.map +1 -0
  255. package/dist/vendor/tools/tools/run_diagnostics.d.ts +3 -0
  256. package/dist/vendor/tools/tools/run_diagnostics.d.ts.map +1 -0
  257. package/dist/vendor/tools/tools/run_diagnostics.js +11 -0
  258. package/dist/vendor/tools/tools/run_diagnostics.js.map +1 -0
  259. package/dist/vendor/tools/tools/search_files.d.ts +3 -0
  260. package/dist/vendor/tools/tools/search_files.d.ts.map +1 -0
  261. package/dist/vendor/tools/tools/search_files.js +120 -0
  262. package/dist/vendor/tools/tools/search_files.js.map +1 -0
  263. package/dist/vendor/tools/tools/web_search.d.ts +46 -0
  264. package/dist/vendor/tools/tools/web_search.d.ts.map +1 -0
  265. package/dist/vendor/tools/tools/web_search.js +187 -0
  266. package/dist/vendor/tools/tools/web_search.js.map +1 -0
  267. package/dist/vendor/tools/tools/write_file.d.ts +3 -0
  268. package/dist/vendor/tools/tools/write_file.d.ts.map +1 -0
  269. package/dist/vendor/tools/tools/write_file.js +52 -0
  270. package/dist/vendor/tools/tools/write_file.js.map +1 -0
  271. package/dist/windows_credentials.d.ts +15 -0
  272. package/dist/windows_credentials.d.ts.map +1 -0
  273. package/dist/windows_credentials.js +23 -0
  274. package/dist/windows_credentials.js.map +1 -0
  275. package/package.json +28 -0
@@ -0,0 +1,187 @@
1
+ import { z } from 'zod';
2
+ import { WebSearchParamsSchema } from '../../contracts/index.js';
3
+ /** Hosted MCP search services. No credential is required; an API key only raises provider limits. */
4
+ export const EXA_SEARCH_URL = 'https://mcp.exa.ai/mcp';
5
+ export const PARALLEL_SEARCH_URL = 'https://search.parallel.ai/mcp';
6
+ export const DEFAULT_SEARCH_TIMEOUT_MS = 20_000;
7
+ export const MAX_SEARCH_OUTPUT_CHARS = 8_000;
8
+ const MAX_SOURCES = 10;
9
+ const MCP_ACCEPT = 'application/json, text/event-stream';
10
+ const McpSearchResponseSchema = z.object({
11
+ result: z.object({
12
+ isError: z.boolean().optional(),
13
+ content: z.array(z.object({ type: z.string(), text: z.string().optional() })).optional(),
14
+ }),
15
+ });
16
+ const CustomSearchResponseSchema = z.object({
17
+ results: z.array(z.object({ title: z.string().optional(), url: z.string().optional(), snippet: z.string().optional() })),
18
+ });
19
+ export function isAllowedSearchEndpoint(endpoint) {
20
+ try {
21
+ const url = new URL(endpoint);
22
+ return url.protocol === 'https:' || url.hostname === 'localhost' || url.hostname === '127.0.0.1';
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ function parseProvider(value) {
29
+ const text = value?.trim().toLowerCase();
30
+ return text === 'exa' || text === 'parallel' || text === 'custom' ? text : undefined;
31
+ }
32
+ /**
33
+ * Order the search sites deterministically: an explicit endpoint wins, then Exa (best current-events
34
+ * context in live probes), then Parallel. A pinned provider moves to the front and keeps the rest as fallback.
35
+ */
36
+ export function resolveWebSearchTargets(options = {}, env = process.env) {
37
+ const customEndpoint = (options.endpoint ?? env.MODERADO_WEB_SEARCH_ENDPOINT)?.trim();
38
+ const exaKey = env.EXA_API_KEY?.trim();
39
+ const targets = [];
40
+ if (customEndpoint && isAllowedSearchEndpoint(customEndpoint))
41
+ targets.push({ provider: 'custom', url: customEndpoint, tool: '' });
42
+ targets.push({ provider: 'exa', url: exaKey ? `${EXA_SEARCH_URL}?exaApiKey=${encodeURIComponent(exaKey)}` : EXA_SEARCH_URL, tool: 'web_search_exa' });
43
+ targets.push({ provider: 'parallel', url: PARALLEL_SEARCH_URL, tool: 'web_search' });
44
+ const pinned = options.provider ?? parseProvider(env.MODERADO_WEB_SEARCH_PROVIDER);
45
+ if (!pinned)
46
+ return targets;
47
+ const direct = targets.filter((target) => target.provider === pinned);
48
+ return direct.length ? [...direct, ...targets.filter((target) => target.provider !== pinned)] : targets;
49
+ }
50
+ function readMcpText(payload) {
51
+ if (!payload.startsWith('{'))
52
+ return undefined;
53
+ try {
54
+ const parsed = McpSearchResponseSchema.safeParse(JSON.parse(payload));
55
+ if (!parsed.success || parsed.data.result.isError)
56
+ return undefined;
57
+ return parsed.data.result.content?.find((item) => item.text)?.text;
58
+ }
59
+ catch {
60
+ return undefined;
61
+ }
62
+ }
63
+ /** Accept both a direct JSON-RPC body and a server-sent-events stream. */
64
+ export function parseMcpSearchText(body) {
65
+ const direct = readMcpText(body.trim());
66
+ if (direct)
67
+ return direct;
68
+ for (const line of body.split('\n')) {
69
+ const text = line.startsWith('data:') ? readMcpText(line.slice(5).trim()) : undefined;
70
+ if (text)
71
+ return text;
72
+ }
73
+ return undefined;
74
+ }
75
+ export function extractSearchSources(text, limit = MAX_SOURCES) {
76
+ const sources = [];
77
+ const seen = new Set();
78
+ let title = '';
79
+ const add = (url, label) => {
80
+ if (seen.has(url) || sources.length >= limit)
81
+ return;
82
+ seen.add(url);
83
+ sources.push({ title: label || url, url });
84
+ };
85
+ for (const line of text.split('\n')) {
86
+ const trimmed = line.trim();
87
+ if (trimmed.startsWith('Title:')) {
88
+ title = trimmed.slice(6).trim();
89
+ continue;
90
+ }
91
+ if (trimmed.startsWith('URL:')) {
92
+ const url = trimmed.slice(4).trim();
93
+ if (/^https?:\/\//.test(url))
94
+ add(url, title);
95
+ title = '';
96
+ }
97
+ }
98
+ if (!sources.length)
99
+ for (const match of text.matchAll(/https?:\/\/[^\s"'`<>)\]}]+/g))
100
+ add(match[0], '');
101
+ return sources;
102
+ }
103
+ export function boundSearchOutput(text, maxChars = MAX_SEARCH_OUTPUT_CHARS) {
104
+ if (text.length <= maxChars)
105
+ return { output: text, truncated: false };
106
+ return { output: `${text.slice(0, maxChars)}\n\n[search context truncated at ${maxChars} characters]`, truncated: true };
107
+ }
108
+ async function fetchMcpSearch(target, params, signal, fetchImpl) {
109
+ const args = target.provider === 'parallel'
110
+ ? { objective: params.objective ?? params.query, search_queries: [params.query] }
111
+ : { query: params.query, objective: params.objective ?? params.query, numResults: params.maxResults };
112
+ const response = await fetchImpl(target.url, {
113
+ method: 'POST',
114
+ headers: { 'content-type': 'application/json', accept: MCP_ACCEPT },
115
+ body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name: target.tool, arguments: args } }),
116
+ signal,
117
+ });
118
+ if (!response.ok)
119
+ throw new Error(`HTTP ${response.status}`);
120
+ const text = parseMcpSearchText(await response.text());
121
+ if (!text)
122
+ throw new Error('unreadable search response');
123
+ return text;
124
+ }
125
+ async function fetchCustomSearch(endpoint, params, signal, fetchImpl) {
126
+ const url = new URL(endpoint);
127
+ url.searchParams.set('q', params.query);
128
+ url.searchParams.set('limit', String(params.maxResults));
129
+ const response = await fetchImpl(url, { signal });
130
+ if (!response.ok)
131
+ throw new Error(`HTTP ${response.status}`);
132
+ const payload = CustomSearchResponseSchema.safeParse(await response.json().catch(() => undefined));
133
+ if (!payload.success)
134
+ throw new Error('unreadable search response');
135
+ return payload.data.results
136
+ .filter((item) => typeof item.title === 'string' && typeof item.url === 'string')
137
+ .slice(0, params.maxResults)
138
+ .map((item) => `Title: ${item.title}\nURL: ${item.url}${typeof item.snippet === 'string' && item.snippet.length > 0 ? `\n${item.snippet}` : ''}`)
139
+ .join('\n\n');
140
+ }
141
+ function searchSignal(context, timeoutMs) {
142
+ const timeout = AbortSignal.timeout(timeoutMs);
143
+ return context.abortSignal ? AbortSignal.any([context.abortSignal, timeout]) : timeout;
144
+ }
145
+ /** Build a search tool bound to operator configuration so the model only supplies the query. */
146
+ export function createWebSearchTool(options = {}) {
147
+ const timeoutMs = options.timeoutMs ?? DEFAULT_SEARCH_TIMEOUT_MS;
148
+ return {
149
+ name: 'web_search',
150
+ description: `Search the web for current information. Use it immediately for anything that changes over time, such as weather, news, prices, scores, schedules, and releases, instead of running curl or asking the user to look it up. The returned pages are raw excerpts: answer the user with the facts and values only, and never list source URLs, site names, or page titles unless the user explicitly asks for them. The current year is ${new Date().getFullYear()}.`,
151
+ requiresApproval: false,
152
+ parametersSchema: WebSearchParamsSchema,
153
+ async execute(params, context) {
154
+ const explicitEndpoint = params.endpoint?.trim();
155
+ if (explicitEndpoint && !isAllowedSearchEndpoint(explicitEndpoint))
156
+ return { toolName: 'web_search', status: 'error', output: 'Search endpoint must use HTTPS or localhost.' };
157
+ const fetchImpl = options.fetchImpl ?? fetch;
158
+ const failures = [];
159
+ for (const target of resolveWebSearchTargets({ ...options, endpoint: explicitEndpoint ?? options.endpoint })) {
160
+ const signal = searchSignal(context, timeoutMs);
161
+ try {
162
+ const text = target.provider === 'custom' ? await fetchCustomSearch(target.url, params, signal, fetchImpl) : await fetchMcpSearch(target, params, signal, fetchImpl);
163
+ if (!text.trim()) {
164
+ failures.push(`${target.provider}: no results`);
165
+ continue;
166
+ }
167
+ const bounded = boundSearchOutput(text);
168
+ return {
169
+ toolName: 'web_search',
170
+ status: 'success',
171
+ output: bounded.output,
172
+ ...(bounded.truncated ? { truncated: true } : {}),
173
+ metadata: { provider: target.provider, sources: extractSearchSources(bounded.output) },
174
+ };
175
+ }
176
+ catch (error) {
177
+ const timedOut = signal.aborted && !context.abortSignal?.aborted;
178
+ failures.push(`${target.provider}: ${timedOut ? `timed out after ${timeoutMs}ms` : error instanceof Error ? error.message : String(error)}`);
179
+ }
180
+ }
181
+ return { toolName: 'web_search', status: 'error', output: `Web search failed (${failures.join('; ')}).` };
182
+ },
183
+ };
184
+ }
185
+ /** Default registration used when the CLI does not supply operator configuration. */
186
+ export const WebSearchTool = createWebSearchTool();
187
+ //# sourceMappingURL=web_search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web_search.js","sourceRoot":"","sources":["../../src/tools/web_search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { IToolDefinition, WriteFileParams } from '@moderado/contracts';
2
+ export declare const WriteFileTool: IToolDefinition<WriteFileParams>;
3
+ //# sourceMappingURL=write_file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write_file.d.ts","sourceRoot":"","sources":["../../src/tools/write_file.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,eAAe,EAGf,eAAe,EAEhB,MAAM,qBAAqB,CAAC;AAG7B,eAAO,MAAM,aAAa,EAAE,eAAe,CAAC,eAAe,CAiD1D,CAAC"}
@@ -0,0 +1,52 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import crypto from 'node:crypto';
4
+ import { WriteFileParamsSchema, } from '../../contracts/index.js';
5
+ import { resolveInJail } from '../jail.js';
6
+ export const WriteFileTool = {
7
+ name: 'write_file',
8
+ description: 'Create a new file or completely replace an existing file atomically.',
9
+ requiresApproval: true,
10
+ parametersSchema: WriteFileParamsSchema,
11
+ async execute(params, context) {
12
+ const canonicalPath = resolveInJail(context.workspaceRoot, params.path);
13
+ const parentDir = path.dirname(canonicalPath);
14
+ if (!fs.existsSync(parentDir)) {
15
+ fs.mkdirSync(parentDir, { recursive: true });
16
+ }
17
+ const tmpFilename = `.tmp.moderado.${crypto.randomUUID()}`;
18
+ const tmpPath = path.join(parentDir, tmpFilename);
19
+ try {
20
+ fs.writeFileSync(tmpPath, params.content, 'utf8');
21
+ fs.renameSync(tmpPath, canonicalPath);
22
+ }
23
+ catch (err) {
24
+ if (fs.existsSync(tmpPath)) {
25
+ try {
26
+ fs.unlinkSync(tmpPath);
27
+ }
28
+ catch {
29
+ // ignore cleanup failure
30
+ }
31
+ }
32
+ return {
33
+ toolName: 'write_file',
34
+ status: 'error',
35
+ output: `Failed to write file '${params.path}': ${err.message}`,
36
+ };
37
+ }
38
+ const lineCount = params.content.split(/\r?\n/).length;
39
+ const byteLength = Buffer.byteLength(params.content, 'utf8');
40
+ return {
41
+ toolName: 'write_file',
42
+ status: 'success',
43
+ output: `Successfully wrote ${lineCount} lines (${byteLength} bytes) to '${params.path}'.`,
44
+ metadata: {
45
+ path: params.path,
46
+ byteLength,
47
+ lineCount,
48
+ },
49
+ };
50
+ },
51
+ };
52
+ //# sourceMappingURL=write_file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write_file.js","sourceRoot":"","sources":["../../src/tools/write_file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAKL,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,CAAC,MAAM,aAAa,GAAqC;IAC7D,IAAI,EAAE,YAAY;IAClB,WAAW,EAAE,sEAAsE;IACnF,gBAAgB,EAAE,IAAI;IACtB,gBAAgB,EAAE,qBAAqB;IAEvC,KAAK,CAAC,OAAO,CAAC,MAAuB,EAAE,OAA6B;QAClE,MAAM,aAAa,GAAG,aAAa,CAAC,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QACxE,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAE9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,WAAW,GAAG,iBAAiB,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC;QAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAElD,IAAI,CAAC;YACH,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAClD,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3B,IAAI,CAAC;oBACH,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;gBACzB,CAAC;gBAAC,MAAM,CAAC;oBACP,yBAAyB;gBAC3B,CAAC;YACH,CAAC;YACD,OAAO;gBACL,QAAQ,EAAE,YAAY;gBACtB,MAAM,EAAE,OAAO;gBACf,MAAM,EAAE,yBAAyB,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,OAAO,EAAE;aAChE,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;QACvD,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAE7D,OAAO;YACL,QAAQ,EAAE,YAAY;YACtB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,sBAAsB,SAAS,WAAW,UAAU,eAAe,MAAM,CAAC,IAAI,IAAI;YAC1F,QAAQ,EAAE;gBACR,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,UAAU;gBACV,SAAS;aACV;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { CredentialStore } from './credentials.js';
2
+ export interface BridgeResult {
3
+ stdout: string;
4
+ stderr: string;
5
+ }
6
+ export type BridgeRunner = (file: string, args: string[], input: string) => Promise<BridgeResult>;
7
+ export declare class WindowsCredentialStore implements CredentialStore {
8
+ private readonly run;
9
+ constructor(run?: BridgeRunner);
10
+ get(reference: string): Promise<string | undefined>;
11
+ set(reference: string, secret: string): Promise<void>;
12
+ delete(reference: string): Promise<void>;
13
+ private invoke;
14
+ }
15
+ //# sourceMappingURL=windows_credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows_credentials.d.ts","sourceRoot":"","sources":["../src/windows_credentials.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,YAAY;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;CAAE;AACjE,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAIlG,qBAAa,sBAAuB,YAAW,eAAe;IAAe,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,GAAE,YAA4B;IAAW,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAAyK,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAAwD,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAA2D,MAAM;CAAie"}
@@ -0,0 +1,23 @@
1
+ import { spawn } from 'node:child_process';
2
+ const bridge = "$request=[Console]::In.ReadToEnd()|ConvertFrom-Json;Add-Type @'\nusing System;using System.Runtime.InteropServices;public static class ModeradoCred{[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]public struct C{public UInt32 Flags,Type;public string TargetName,Comment;public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;public UInt32 CredentialBlobSize;public IntPtr CredentialBlob;public UInt32 Persist,AttributeCount;public IntPtr Attributes;public string TargetAlias,UserName;}[DllImport(\"Advapi32.dll\",CharSet=CharSet.Unicode,SetLastError=true)]public static extern bool CredRead(string t,UInt32 y,UInt32 f,out IntPtr c);[DllImport(\"Advapi32.dll\",CharSet=CharSet.Unicode,SetLastError=true)]public static extern bool CredWrite(ref C c,UInt32 f);[DllImport(\"Advapi32.dll\",CharSet=CharSet.Unicode,SetLastError=true)]public static extern bool CredDelete(string t,UInt32 y,UInt32 f);[DllImport(\"Advapi32.dll\")]public static extern void CredFree(IntPtr b);}\n'@;try{if($request.operation -eq 'get'){$p=[IntPtr]::Zero;if(-not [ModeradoCred]::CredRead($request.reference,1,0,[ref]$p)){[Console]::Out.Write('{\"ok\":true}');exit 0};try{$c=[Runtime.InteropServices.Marshal]::PtrToStructure($p,[type][ModeradoCred+C]);$s=[Runtime.InteropServices.Marshal]::PtrToStringUni($c.CredentialBlob,[int]($c.CredentialBlobSize/2));[Console]::Out.Write((@{ok=$true;secret=$s}|ConvertTo-Json -Compress))}finally{[ModeradoCred]::CredFree($p)}}elseif($request.operation -eq 'set'){$b=[Text.Encoding]::Unicode.GetBytes($request.secret);$p=[Runtime.InteropServices.Marshal]::AllocHGlobal($b.Length);try{[Runtime.InteropServices.Marshal]::Copy($b,0,$p,$b.Length);$c=New-Object ModeradoCred+C;$c.Type=1;$c.TargetName=$request.reference;$c.CredentialBlobSize=$b.Length;$c.CredentialBlob=$p;$c.Persist=2;$c.UserName='Moderado';if(-not [ModeradoCred]::CredWrite([ref]$c,0)){throw 'write'};[Console]::Out.Write('{\"ok\":true}')}finally{[Runtime.InteropServices.Marshal]::FreeHGlobal($p)}}else{[void][ModeradoCred]::CredDelete($request.reference,1,0);[Console]::Out.Write('{\"ok\":true}')}}catch{[Console]::Error.Write('Credential Manager operation failed');exit 1}";
3
+ function encodedBridge() { return Buffer.from(bridge, 'utf16le').toString('base64'); }
4
+ const defaultRunner = (file, args, input) => new Promise((resolve, reject) => { const child = spawn(file, args, { shell: false, windowsHide: true, stdio: ['pipe', 'pipe', 'pipe'] }); let stdout = ''; let stderr = ''; child.stdout.on('data', (chunk) => { stdout += chunk.toString(); }); child.stderr.on('data', (chunk) => { stderr += chunk.toString(); }); child.on('error', reject); child.on('close', (code) => code === 0 ? resolve({ stdout, stderr }) : reject(new Error(stderr || `PowerShell exited with ${code}`))); child.stdin.end(input); });
5
+ export class WindowsCredentialStore {
6
+ run;
7
+ constructor(run = defaultRunner) {
8
+ this.run = run;
9
+ }
10
+ async get(reference) { const parsed = JSON.parse(await this.invoke('get', reference)); return typeof parsed.secret === 'string' ? parsed.secret : undefined; }
11
+ async set(reference, secret) { await this.invoke('set', reference, secret); }
12
+ async delete(reference) { await this.invoke('delete', reference); }
13
+ async invoke(operation, reference, secret) { try {
14
+ const result = await this.run('powershell.exe', ['-NoProfile', '-NonInteractive', '-EncodedCommand', encodedBridge()], JSON.stringify({ operation, reference, secret }));
15
+ if (!result.stdout.trim())
16
+ throw new Error(result.stderr);
17
+ return result.stdout;
18
+ }
19
+ catch {
20
+ throw new Error('Windows Credential Manager operation failed. Set the provider environment variable to continue.');
21
+ } }
22
+ }
23
+ //# sourceMappingURL=windows_credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows_credentials.js","sourceRoot":"","sources":["../src/windows_credentials.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "moderado",
3
+ "version": "0.3.0",
4
+ "description": "A lightweight, provider-independent CLI coding agent with free-first model routing.",
5
+ "type": "module",
6
+ "bin": {
7
+ "moderado": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "files": ["dist", "README.md", "LICENSE"],
12
+ "engines": { "node": ">=20" },
13
+ "license": "MIT",
14
+ "repository": { "type": "git", "url": "git+https://github.com/marcuz-apl/moderado.git" },
15
+ "bugs": { "url": "https://github.com/marcuz-apl/moderado/issues" },
16
+ "homepage": "https://github.com/marcuz-apl/moderado#readme",
17
+ "keywords": ["ai", "agent", "coding-agent", "cli", "nvidia-nim", "openrouter"],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "typecheck": "tsc --noEmit",
21
+ "start": "node ./dist/index.js",
22
+ "test": "vitest run",
23
+ "prepack": "npm --prefix ../.. run build && npm --prefix ../.. run prepare:package"
24
+ },
25
+ "dependencies": {
26
+ "zod": "^3.24.2"
27
+ }
28
+ }