@kirosnn/mosaic 0.73.0 → 0.75.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.
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  <h1 align="center">Mosaic CLI</h1>
6
6
 
7
7
  <p align="center">
8
- <strong>Version 0.73.0</strong>
8
+ <strong>Version 0.75.0</strong>
9
9
  </p>
10
10
 
11
11
  <p align="center">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kirosnn/mosaic",
3
- "version": "0.73.0",
3
+ "version": "0.75.0",
4
4
  "description": "The open source coding agent.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -52,4 +52,4 @@
52
52
  "zod": "^3.23.8",
53
53
  "zod-to-json-schema": "^3.25.1"
54
54
  }
55
- }
55
+ }
@@ -5,7 +5,7 @@ import { getToolsPrompt } from './toolsPrompt';
5
5
 
6
6
  export const DEFAULT_SYSTEM_PROMPT = `You are Mosaic, an AI coding agent operating in the user's terminal.
7
7
  You assist with software engineering tasks: coding, debugging, refactoring, testing, and documentation.
8
- Version : 0.73.0 *(Beta)*
8
+ Version : 0.75.0 *(Beta)*
9
9
 
10
10
  # Environment
11
11
 
@@ -1,3 +1,9 @@
1
+ import { NATIVE_SERVER_IDS } from '../../mcp/types';
2
+
3
+ const NATIVE_SERVER_LABELS: Record<string, string> = {
4
+ navigation: 'Browser Navigation',
5
+ };
6
+
1
7
  export const TOOLS_PROMPT = `
2
8
  # Available Tools
3
9
 
@@ -32,21 +38,28 @@ List directory contents.
32
38
  ## Search & Discovery
33
39
 
34
40
  ### explore (RECOMMENDED for understanding context)
35
- Autonomous exploration agent that intelligently searches the codebase.
41
+ Autonomous exploration agent that intelligently searches the codebase and the web.
36
42
  - purpose (string, required): What to find/understand
37
43
 
44
+ The explore agent has access to: read, glob, grep, list, fetch (web pages), and search (web search).
45
+ It can look up external documentation, API references, and tutorials when needed.
46
+
38
47
  USE EXPLORE WHEN:
39
48
  - Starting work on an unfamiliar codebase
40
49
  - Understanding how something works
41
50
  - Finding related code, patterns, or architecture
42
51
  - You're unsure where to make changes
52
+ - You need to look up library/framework documentation
53
+ - You need to research an API or find usage examples online
43
54
 
44
55
  Examples:
45
56
  - explore(purpose="Find API endpoints and understand routing")
46
57
  - explore(purpose="Understand the authentication flow")
47
58
  - explore(purpose="Find UserService and all its usages")
59
+ - explore(purpose="Look up the React Query documentation for useQuery options")
60
+ - explore(purpose="Find the Playwright API docs for page.waitForSelector")
48
61
 
49
- The explore tool is INTELLIGENT - it autonomously reads files, follows imports, and builds understanding. This is MORE EFFICIENT than manual glob/grep/read cycles.
62
+ The explore tool is INTELLIGENT - it autonomously reads files, follows imports, searches the web, reads documentation, and builds understanding. This is MORE EFFICIENT than manual glob/grep/read/fetch cycles.
50
63
 
51
64
  ### glob
52
65
  Find files by name pattern. Fast file discovery.
@@ -138,6 +151,7 @@ CRITICAL: Never ask questions in plain text. Always use this tool.
138
151
  | Task | Tool | Example |
139
152
  |------|------|---------|
140
153
  | Understand codebase/architecture | explore | explore(purpose="How does auth work?") |
154
+ | Look up external documentation | explore | explore(purpose="Find React Query docs for useMutation") |
141
155
  | Find files by name | glob | glob(pattern="**/*.config.ts") |
142
156
  | Find specific text | grep | grep(query="handleSubmit", file_type="tsx") |
143
157
  | Read file contents | read | read(path="src/auth.ts") |
@@ -148,6 +162,7 @@ CRITICAL: Never ask questions in plain text. Always use this tool.
148
162
  | Need user input | question | question(prompt="...", options=[...]) |
149
163
 
150
164
  PREFER EXPLORE for understanding context before making changes.
165
+ PREFER EXPLORE for looking up documentation - it can search the web and read doc pages.
151
166
  PREFER grep with file_type for targeted text searches.
152
167
 
153
168
  # Continuation - CRITICAL
@@ -235,8 +250,63 @@ export function getToolsPrompt(mcpToolInfos?: Array<{ serverId: string; name: st
235
250
  return TOOLS_PROMPT;
236
251
  }
237
252
 
238
- const mcpSection = buildMcpToolsSection(mcpToolInfos);
239
- return TOOLS_PROMPT + '\n\n' + mcpSection;
253
+ const nativeTools = mcpToolInfos.filter(t => NATIVE_SERVER_IDS.has(t.serverId));
254
+ const externalTools = mcpToolInfos.filter(t => !NATIVE_SERVER_IDS.has(t.serverId));
255
+
256
+ let result = TOOLS_PROMPT;
257
+
258
+ if (nativeTools.length > 0) {
259
+ result += '\n\n' + buildNativeToolsSection(nativeTools);
260
+ }
261
+
262
+ if (externalTools.length > 0) {
263
+ result += '\n\n' + buildMcpToolsSection(externalTools);
264
+ }
265
+
266
+ return result;
267
+ }
268
+
269
+ function buildNativeToolsSection(tools: Array<{ serverId: string; name: string; description: string; inputSchema: Record<string, unknown>; canonicalId: string; safeId: string }>): string {
270
+ const lines: string[] = [];
271
+
272
+ const byServer = new Map<string, typeof tools>();
273
+ for (const t of tools) {
274
+ const list = byServer.get(t.serverId) || [];
275
+ list.push(t);
276
+ byServer.set(t.serverId, list);
277
+ }
278
+
279
+ for (const [serverId, serverTools] of byServer) {
280
+ const label = NATIVE_SERVER_LABELS[serverId] || serverId.charAt(0).toUpperCase() + serverId.slice(1);
281
+ lines.push(`## ${label}`);
282
+ lines.push('');
283
+
284
+ for (const t of serverTools) {
285
+ lines.push(`### ${t.safeId}`);
286
+ if (t.description) {
287
+ lines.push(t.description);
288
+ }
289
+ const schema = t.inputSchema;
290
+ if (schema && typeof schema === 'object' && schema.properties) {
291
+ const props = schema.properties as Record<string, Record<string, unknown>>;
292
+ const required = (schema.required || []) as string[];
293
+ const paramLines: string[] = [];
294
+ for (const [key, propSchema] of Object.entries(props)) {
295
+ const type = propSchema.type || 'unknown';
296
+ const desc = propSchema.description || '';
297
+ const req = required.includes(key) ? 'required' : 'optional';
298
+ paramLines.push(`- ${key} (${type}, ${req})${desc ? ': ' + desc : ''}`);
299
+ }
300
+ if (paramLines.length > 0) {
301
+ lines.push('Parameters:');
302
+ lines.push(...paramLines);
303
+ }
304
+ }
305
+ lines.push('');
306
+ }
307
+ }
308
+
309
+ return lines.join('\n');
240
310
  }
241
311
 
242
312
  function buildMcpToolsSection(tools: Array<{ serverId: string; name: string; description: string; inputSchema: Record<string, unknown>; canonicalId: string; safeId: string }>): string {
@@ -283,4 +353,4 @@ function buildMcpToolsSection(tools: Array<{ serverId: string; name: string; des
283
353
  }
284
354
 
285
355
  return lines.join('\n');
286
- }
356
+ }
@@ -3,10 +3,10 @@ import { z } from 'zod';
3
3
  import { executeExploreTool } from './exploreExecutor';
4
4
 
5
5
  export const explore: CoreTool = tool({
6
- description: `Explore the codebase autonomously to gather information.
7
- This tool launches an exploration agent that will use read, glob, grep, and list tools iteratively.
8
- The agent will continue exploring until it has gathered enough information to answer the purpose.
9
- Use this for open-ended exploration tasks like understanding code structure, finding implementations, etc.`,
6
+ description: `Explore the codebase and web autonomously to gather information.
7
+ This tool launches an exploration agent that will use read, glob, grep, list, fetch, and search tools iteratively.
8
+ The agent can search the web for documentation and fetch web pages when needed.
9
+ Use this for open-ended exploration tasks like understanding code structure, finding implementations, looking up documentation, etc.`,
10
10
  parameters: z.object({
11
11
  purpose: z.string().describe('The goal of the exploration - what information you need to gather'),
12
12
  }),
@@ -20,13 +20,15 @@ let exploreLogs: ExploreLog[] = [];
20
20
 
21
21
  const EXPLORE_TIMEOUT = 8 * 60 * 1000;
22
22
 
23
- const EXPLORE_SYSTEM_PROMPT = `You are an exploration agent that gathers information from a codebase.
23
+ const EXPLORE_SYSTEM_PROMPT = `You are an exploration agent that gathers information from a codebase and the web.
24
24
 
25
- Your goal is to explore the codebase to fulfill the given purpose. You have access to these tools:
25
+ Your goal is to explore the codebase and external documentation to fulfill the given purpose. You have access to these tools:
26
26
  - read: Read file contents
27
27
  - glob: Find files by pattern
28
28
  - grep: Search for text in files
29
29
  - list: List directory contents
30
+ - fetch: Fetch a URL and return its content as markdown (for reading documentation pages, API docs, etc.)
31
+ - search: Search the web for documentation, tutorials, API references, error solutions
30
32
 
31
33
  IMPORTANT RULES:
32
34
  1. Be thorough but efficient - don't repeat the same searches
@@ -34,7 +36,10 @@ IMPORTANT RULES:
34
36
  3. If you cannot find the information after reasonable exploration, call "done" with what you found
35
37
  4. Focus on the purpose - don't explore unrelated areas
36
38
  5. Summarize findings clearly and include relevant file paths and code snippets
37
- 6. You MUST call the "done" tool when finished - this is the only way to complete the exploration`;
39
+ 6. You MUST call the "done" tool when finished - this is the only way to complete the exploration
40
+ 7. When the purpose involves understanding a library, framework, or external API, use search to find official documentation, then fetch to read the relevant pages
41
+ 8. Prefer official documentation over blog posts or Stack Overflow when possible
42
+ 9. If search is unavailable, you can still use fetch with known documentation URLs`;
38
43
 
39
44
  const MAX_STEPS = 100;
40
45
 
@@ -170,6 +175,53 @@ function createExploreTools() {
170
175
  return result.result;
171
176
  },
172
177
  }),
178
+ fetch: createTool({
179
+ description: 'Fetch a URL and return its content as markdown. Use this to read documentation pages, API references, tutorials, etc.',
180
+ parameters: z.object({
181
+ url: z.string().describe('The URL to fetch (must be a valid HTTP/HTTPS URL)'),
182
+ max_length: z.number().optional().describe('Maximum characters to return (default: 10000, max: 100000)'),
183
+ }),
184
+ execute: async (args) => {
185
+ if (isExploreAborted()) return { error: 'Exploration aborted' };
186
+ const result = await executeTool('fetch', { ...args, max_length: args.max_length ?? 10000 });
187
+ const resultLen = result.result?.length || 0;
188
+ const preview = result.success ? `${resultLen} chars` : (result.error || 'error');
189
+ exploreLogs.push({ tool: 'fetch', args, success: result.success, resultPreview: preview });
190
+ notifyExploreTool('fetch', args, { success: result.success, preview }, resultLen);
191
+ if (!result.success) return { error: result.error };
192
+ return result.result;
193
+ },
194
+ }),
195
+ search: createTool({
196
+ description: 'Search the web and return top results. Use this to find documentation, API references, tutorials, or solutions to errors.',
197
+ parameters: z.object({
198
+ query: z.string().describe('Search query'),
199
+ engine: z.enum(['google', 'bing', 'duckduckgo']).optional().describe('Search engine to use (default: google)'),
200
+ }),
201
+ execute: async (args) => {
202
+ if (isExploreAborted()) return { error: 'Exploration aborted' };
203
+ try {
204
+ const { getMcpManager, isMcpInitialized } = require('../../mcp/index');
205
+ if (!isMcpInitialized()) {
206
+ return { error: 'Web search unavailable (MCP not initialized)' };
207
+ }
208
+ const pm = getMcpManager();
209
+ const callArgs = { query: args.query, engine: args.engine || 'google' };
210
+ const result = await pm.callTool('navigation', 'navigation_search', callArgs);
211
+ const resultLen = result.content?.length || 0;
212
+ const preview = result.isError ? (result.content || 'error') : `${resultLen} chars`;
213
+ exploreLogs.push({ tool: 'search', args: callArgs, success: !result.isError, resultPreview: preview });
214
+ notifyExploreTool('search', callArgs, { success: !result.isError, preview }, resultLen);
215
+ if (result.isError) return { error: result.content || 'Search failed' };
216
+ return result.content;
217
+ } catch (error) {
218
+ const message = error instanceof Error ? error.message : String(error);
219
+ exploreLogs.push({ tool: 'search', args, success: false, resultPreview: message });
220
+ notifyExploreTool('search', args, { success: false, preview: message }, 0);
221
+ return { error: `Web search failed: ${message}` };
222
+ }
223
+ },
224
+ }),
173
225
  done: createTool({
174
226
  description: 'Call this when you have gathered enough information. Provide a comprehensive summary of your findings. This MUST be called to complete the exploration.',
175
227
  parameters: z.object({
@@ -188,7 +240,7 @@ function formatExploreLogs(): string {
188
240
 
189
241
  const lines = ['Tools used:'];
190
242
  for (const log of exploreLogs) {
191
- const argStr = log.args.path || log.args.pattern || log.args.query || '';
243
+ const argStr = log.args.path || log.args.pattern || log.args.query || log.args.url || '';
192
244
  const status = log.success ? '→' : '-';
193
245
  lines.push(` ${status} ${log.tool}(${argStr}) -> ${log.resultPreview || 'ok'}`);
194
246
  }