winter-super-cli 2026.6.23 → 2026.6.26

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
@@ -162,6 +162,25 @@ Winter reads config from the user profile directory. Typical settings include:
162
162
  - MCP servers
163
163
  - sandbox / allowlist options
164
164
 
165
+ ### Chrome DevTools MCP
166
+
167
+ Winter has a built-in preset for ChromeDevTools/chrome-devtools-mcp:
168
+
169
+ ```bash
170
+ winter mcp preset chrome-devtools --isolated
171
+ winter mcp tools chrome-devtools
172
+ ```
173
+
174
+ In the REPL, use the same flow with slash commands:
175
+
176
+ ```text
177
+ /mcp preset chrome-devtools --isolated
178
+ /mcp tools chrome-devtools
179
+ ```
180
+
181
+ The preset registers the `chrome-devtools` MCP server, allowlists it, and gives Winter runtime hints to use its page navigation, click, fill, snapshot, screenshot, console, network, and performance tools for live browser debugging. Omit `--headless` when you want to watch Winter operate Chrome in a normal visible window.
182
+ It requires Node.js 22.12+ and a current Chrome installation, matching the upstream MCP package requirements.
183
+
165
184
  ### Minimal example
166
185
 
167
186
  ```json
package/bin/winter.js CHANGED
@@ -13,6 +13,7 @@ import { SessionManager } from '../src/session/manager.js';
13
13
  import { AIProviderManager } from '../src/ai/providers.js';
14
14
  import { CommandParser } from '../src/cli/commands.js';
15
15
  import { supportsUnicodeUi } from '../src/cli/terminal-ui.js';
16
+ import { IDEServer } from '../src/mcp/ide-server.js';
16
17
 
17
18
  const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
18
19
  const version = pkg.version;
@@ -23,7 +24,7 @@ const COMMANDS = new Set([
23
24
  'autopilot', 'plan',
24
25
  'provider', 'providers', 'model', 'models', 'ecc', 'page-agent', 'pageagent',
25
26
  'resources', 'htmlfx', 'memory-vault', 'doctor', 'context', 'scorecard',
26
- 'tui',
27
+ 'tui', 'rag',
27
28
  ]);
28
29
 
29
30
  function isInteractiveRequest(args) {
@@ -69,6 +70,7 @@ Commands:
69
70
  winter context [task] Inspect model context for this project
70
71
  winter scorecard Score Winter capability gates
71
72
  winter doctor [full|tools] Diagnose context, provider, and tools
73
+ winter rag <action> RAG query/index/status/reset
72
74
  winter provider [name] Show/switch provider
73
75
  winter providers List providers
74
76
  winter model [model] Show/set active provider model
@@ -89,6 +91,7 @@ Flags:
89
91
 
90
92
  winter -h, --help Show help
91
93
  winter -v, --version Show version
94
+ winter --mcp [--port n] Start VS Code/IDE MCP bridge
92
95
 
93
96
  Version ${version}
94
97
  `);
@@ -97,6 +100,25 @@ Version ${version}
97
100
  async function main() {
98
101
  const args = process.argv.slice(2);
99
102
 
103
+ if (args.includes('--mcp')) {
104
+ const portIndex = args.indexOf('--port');
105
+ const hostIndex = args.indexOf('--host');
106
+ const projectIndex = args.indexOf('--project');
107
+ const server = new IDEServer({
108
+ port: portIndex !== -1 && args[portIndex + 1] ? Number(args[portIndex + 1]) : undefined,
109
+ host: hostIndex !== -1 && args[hostIndex + 1] ? args[hostIndex + 1] : undefined,
110
+ projectPath: projectIndex !== -1 && args[projectIndex + 1] ? path.resolve(args[projectIndex + 1]) : process.cwd(),
111
+ });
112
+ await server.start();
113
+ const shutdown = async () => {
114
+ await server.stop();
115
+ process.exit(0);
116
+ };
117
+ process.on('SIGINT', shutdown);
118
+ process.on('SIGTERM', shutdown);
119
+ return new Promise(() => {});
120
+ }
121
+
100
122
  if (args.includes('--help') || args.includes('-h')) {
101
123
  printHelp();
102
124
  return;
@@ -341,6 +341,7 @@ function sendMessage(message) {
341
341
  }, 5000);
342
342
 
343
343
  let responseData = '';
344
+ let settled = false;
344
345
 
345
346
  client.connect(SERVER_PORT, SERVER_HOST, () => {
346
347
  client.write(JSON.stringify(message) + '\n');
@@ -348,13 +349,31 @@ function sendMessage(message) {
348
349
 
349
350
  client.on('data', (data) => {
350
351
  responseData += data.toString();
351
- try {
352
- const response = JSON.parse(responseData);
352
+ const lines = responseData.split(/\r?\n/);
353
+ responseData = lines.pop() || '';
354
+
355
+ for (const line of lines) {
356
+ if (!line.trim()) continue;
357
+ let response;
358
+ try {
359
+ response = JSON.parse(line);
360
+ } catch {
361
+ continue;
362
+ }
363
+
364
+ if (response.type === 'server:info') {
365
+ continue;
366
+ }
367
+
368
+ settled = true;
353
369
  clearTimeout(timeout);
354
370
  client.destroy();
355
- resolve(response);
356
- } catch {
357
- // Incomplete JSON, wait for more data
371
+ if (response.type === 'error') {
372
+ reject(new Error(response.message || 'Winter MCP server returned an error'));
373
+ } else {
374
+ resolve(response);
375
+ }
376
+ return;
358
377
  }
359
378
  });
360
379
 
@@ -366,9 +385,17 @@ function sendMessage(message) {
366
385
 
367
386
  client.on('close', () => {
368
387
  clearTimeout(timeout);
369
- if (responseData) {
388
+ if (settled) return;
389
+ if (responseData.trim()) {
370
390
  try {
371
- resolve(JSON.parse(responseData));
391
+ const response = JSON.parse(responseData);
392
+ if (response.type === 'error') {
393
+ reject(new Error(response.message || 'Winter MCP server returned an error'));
394
+ } else if (response.type === 'server:info') {
395
+ reject(new Error('Connection closed before Winter MCP server responded'));
396
+ } else {
397
+ resolve(response);
398
+ }
372
399
  } catch {
373
400
  reject(new Error('Invalid response from Winter MCP server'));
374
401
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "winter-super-cli",
3
- "version": "2026.6.23",
3
+ "version": "2026.6.26",
4
4
  "description": "❄️ AI-Powered Development CLI with Interactive REPL",
5
5
  "type": "module",
6
6
  "main": "bin/winter.js",
@@ -83,7 +83,8 @@
83
83
  },
84
84
  "dependencies": {
85
85
  "cli-highlight": "^2.1.11",
86
- "diff": "^9.0.0"
86
+ "diff": "^9.0.0",
87
+ "glob": "^13.0.6"
87
88
  },
88
89
  "optionalDependencies": {
89
90
  "@colbymchenry/codegraph": "^0.7.12",
package/skill.md CHANGED
@@ -16,10 +16,12 @@ File này định nghĩa cách Winter chọn và áp dụng skill. Không chỉ
16
16
  - **security**: Protect secrets, validate inputs, avoid unsafe shell/file operations.
17
17
  - **performance**: Measure or reason from the hot path before optimizing.
18
18
 
19
- ## Available Local Skills (13)
19
+ ## Available Local Skills (16)
20
20
  - codex-primary-runtime
21
21
  - coding
22
+ - coding.md
22
23
  - debug
24
+ - debug.md
23
25
  - design
24
26
  - learned
25
27
  - performance
@@ -27,6 +29,7 @@ File này định nghĩa cách Winter chọn và áp dụng skill. Không chỉ
27
29
  - security
28
30
  - skill-creator
29
31
  - test
32
+ - test.md
30
33
  - vercel-react-best-practices
31
34
  - vibefigma
32
35
  - web-design-guidelines
@@ -3,13 +3,13 @@ import { pathToFileURL } from 'url';
3
3
  import { promises as fs } from 'fs';
4
4
 
5
5
  const DEFAULT_TOOL_SETS = {
6
- general: ['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep', 'BrowserDebug', 'WebFetch', 'WebSearch', 'Parallel', 'Agent'],
6
+ general: ['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep', 'OpenBrowser', 'BrowserDebug', 'WebFetch', 'WebSearch', 'Parallel', 'Agent'],
7
7
  plan: ['Read', 'Grep', 'Glob', 'WebFetch', 'WebSearch', 'Parallel'],
8
8
  review: ['Read', 'Grep', 'Glob', 'Bash', 'WebFetch'],
9
- debug: ['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob', 'BrowserDebug', 'WebFetch', 'Parallel'],
10
- design: ['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob', 'BrowserDebug', 'WebFetch'],
9
+ debug: ['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob', 'OpenBrowser', 'BrowserDebug', 'WebFetch', 'Parallel'],
10
+ design: ['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob', 'OpenBrowser', 'BrowserDebug', 'WebFetch'],
11
11
  research: ['Read', 'Grep', 'Glob', 'WebFetch', 'WebSearch', 'Parallel'],
12
- swe: ['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob', 'BrowserDebug', 'Parallel'],
12
+ swe: ['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob', 'OpenBrowser', 'BrowserDebug', 'Parallel'],
13
13
  };
14
14
 
15
15
  const BUILTIN_AGENTS = [
@@ -100,7 +100,9 @@ function buildStandardSystemPrompt(options = {}) {
100
100
  'Use tools when they materially improve correctness. Inspect before editing. Verify after changes.',
101
101
  'Use maximum reasoning discipline for every model tier, including tiny, local, free, and routed models.',
102
102
  'Never invent file paths, APIs, command output, or test results.',
103
+ 'For visible browser launch requests such as "mở chrome" or "open Chrome", use OpenBrowser; do not use Bash, Get-Command, Start-Process, or shell launch commands.',
103
104
  'For debug work, locate the first hard failure, patch the root cause, and verify with the closest test/build/browser smoke.',
105
+ 'For live browser debugging and user-visible Chrome control, prefer MCP server chrome-devtools when configured; use its page, click, fill, snapshot, screenshot, console, network, and performance tools before falling back to headless browser automation.',
104
106
  'For design/UI work, inspect the existing interface and design resources first; avoid generic placeholder layouts.',
105
107
  'If the user attaches or pastes an image, analyze it as primary evidence.',
106
108
  '',
@@ -10,6 +10,7 @@ import { DesignCommands } from '../design/commands.js';
10
10
  import { SkillManager } from '../skills/manager.js';
11
11
  import { PluginManager } from '../plugins/manager.js';
12
12
  import { MCPClient } from '../mcp/client.js';
13
+ import { getMcpPreset, upsertMcpServer } from '../mcp/presets.js';
13
14
  import { BenchmarkRunner } from '../ai/benchmark.js';
14
15
  import { redactSecrets } from './secret-env.js';
15
16
  import { formatRuntimeEnvironmentSummary, getRuntimeEnvironment } from './runtime-env.js';
@@ -20,6 +21,7 @@ import { HtmlFxManager } from '../integrations/htmlfx-manager.js';
20
21
  import { selectWorkflow } from '../ai/workflow-selector.js';
21
22
  import { getProfileBlueprint } from '../ai/profile-blueprints.js';
22
23
  import { ToolExecutor } from '../tools/executor.js';
24
+ import { handleRagCommandFromParser } from '../rag/cli.js';
23
25
  import { promises as fs } from 'fs';
24
26
  import path from 'path';
25
27
  import readline from 'node:readline/promises';
@@ -76,6 +78,7 @@ export class CommandParser {
76
78
  resources: this.handleResources.bind(this),
77
79
  htmlfx: this.handleHtmlFx.bind(this),
78
80
  'memory-vault': this.handleMemoryVault.bind(this),
81
+ rag: this.handleRag.bind(this),
79
82
  tui: this.handleTui.bind(this),
80
83
  provider: this.handleProvider.bind(this),
81
84
  providers: this.showProviders.bind(this),
@@ -142,6 +145,7 @@ export class CommandParser {
142
145
  '/htmlfx': () => this.handleHtmlFx(args),
143
146
  '/debug': () => this.handleDebug(args),
144
147
  '/auto': () => this.handleDebug(args),
148
+ '/rag': () => this.handleRag(args),
145
149
  '/autopilot': () => this.handleAutopilot(args),
146
150
  '/exit': () => process.exit(0),
147
151
  };
@@ -234,6 +238,10 @@ export class CommandParser {
234
238
  })}\n`);
235
239
  }
236
240
 
241
+ async handleRag(args = []) {
242
+ await handleRagCommandFromParser(this, args);
243
+ }
244
+
237
245
  async searchResourceFiles(root, query, limit = 30) {
238
246
  const matches = [];
239
247
  const needle = String(query || '').toLowerCase();
@@ -806,6 +814,29 @@ EXECUTION CONTRACT:
806
814
  console.log(`${colors.green}✓ Added MCP server: ${name}${colors.reset}`);
807
815
  break;
808
816
  }
817
+ case 'preset':
818
+ case 'install': {
819
+ const [presetName, ...presetOptions] = rest;
820
+ if (!presetName) {
821
+ console.log(`${colors.yellow}Usage: winter mcp preset <chrome-devtools> [--isolated] [--headless] [--browser-url <url>]${colors.reset}`);
822
+ break;
823
+ }
824
+
825
+ try {
826
+ const server = getMcpPreset(presetName, presetOptions);
827
+ upsertMcpServer(config, server);
828
+ await this.config.save(config);
829
+ console.log(`${colors.green}OK Installed MCP preset: ${server.name}${colors.reset}`);
830
+ console.log(` ${colors.dim}${server.command} ${server.args.join(' ')}${colors.reset}`);
831
+ if (!server.args.includes('--headless')) {
832
+ console.log(` ${colors.dim}Visible Chrome mode: enabled. Use --headless only for background browser runs.${colors.reset}`);
833
+ }
834
+ console.log(` ${colors.dim}Inspect tools with: winter mcp tools ${server.name}${colors.reset}`);
835
+ } catch (error) {
836
+ console.log(`${colors.red}${error.message}${colors.reset}`);
837
+ }
838
+ break;
839
+ }
809
840
  case 'remove': {
810
841
  const name = rest[0];
811
842
  if (!name) {
@@ -861,7 +892,7 @@ EXECUTION CONTRACT:
861
892
  break;
862
893
  }
863
894
  default:
864
- console.log(`${colors.yellow}Usage: winter mcp <list|add|remove|allow|tools>${colors.reset}`);
895
+ console.log(`${colors.yellow}Usage: winter mcp <list|add|preset|install|remove|allow|tools>${colors.reset}`);
865
896
  }
866
897
  }
867
898
 
package/src/cli/config.js CHANGED
@@ -7,6 +7,7 @@ import { promises as fs } from 'fs';
7
7
  import path from 'path';
8
8
  import { homedir } from 'os';
9
9
  import { loadEnvFile, stripInlineSecrets } from './secret-env.js';
10
+ import { CHROME_DEVTOOLS_MCP_NAME, createChromeDevtoolsMcpServer } from '../mcp/presets.js';
10
11
 
11
12
  export class ConfigLoader {
12
13
  constructor() {
@@ -61,13 +62,13 @@ export class ConfigLoader {
61
62
  permissions: {
62
63
  promptByDefault: true,
63
64
  allowlist: {
64
- tools: ['Read', 'Glob', 'Grep', 'LSP', 'TaskCreate', 'TaskUpdate', 'TaskList', 'WebFetch', 'WebSearch', 'Parallel'],
65
+ tools: ['Read', 'Glob', 'Grep', 'LSP', 'TaskCreate', 'TaskUpdate', 'TaskList', 'WebFetch', 'WebSearch', 'Parallel', 'MCP'],
65
66
  commands: [],
66
- mcpServers: [],
67
+ mcpServers: [CHROME_DEVTOOLS_MCP_NAME],
67
68
  },
68
69
  },
69
70
  mcp: {
70
- servers: [],
71
+ servers: [createChromeDevtoolsMcpServer(['--isolated'])],
71
72
  },
72
73
  routing: {
73
74
  strategy: 'heuristic',
@@ -117,12 +117,14 @@ export class PromptBuilder {
117
117
  `Prefer Read/Grep/Glob before editing. Use Write/Edit for file changes.`,
118
118
  `CRITICAL: When the user asks you to fix/create/edit/run/modify anything, you MUST call tools (Read, Write, Edit, Bash, etc.) to actually do it. NEVER just write code in a markdown code block and claim it is done. Winter will detect and block fake completions. If you say "đã sửa/đã tạo/done/fixed" without a tool call, your response will be rejected.`,
119
119
  `Tool call compatibility: if native tool calls are unavailable, output exactly one of these forms and no prose: <invoke name="Read"><parameter name="path">README.md</parameter></invoke> OR {"tool":"Read","arguments":{"path":"README.md"}} OR CALL_TOOL Read {"path":"README.md"}.`,
120
- `Browser capability: You CAN browse URLs! Use WebFetch to fetch page content (text extraction) or BrowserDebug for Chrome automation (JS rendering, screenshots). If user shares a URL or asks to view a website, use these tools automatically.`,
120
+ `Open browser requests: if the user asks to "mở chrome", "open Chrome", or open a URL in a visible browser, use OpenBrowser. Do NOT use Bash, Get-Command, Start-Process, cmd start, or shell app launch commands for this.`,
121
+ `Browser capability: You CAN browse URLs! Use WebFetch only for static page text extraction. For live Chrome debugging and visible browser control, prefer MCP server "chrome-devtools" when configured: use MCP tool "new_page" or "navigate_page", then "take_snapshot", "click", "fill"/"fill_form", "take_screenshot", "evaluate_script", "list_console_messages", "list_network_requests", or performance trace tools. BrowserDebug is headless fallback only when chrome-devtools MCP is unavailable or the user explicitly asks for headless smoke/debug.`,
122
+ `Browser interaction rule: if the user asks to click, press, fill, select, submit, open a web app path, or inspect page-by-page data, WebFetch is not enough and BrowserDebug is not user-visible. Use chrome-devtools MCP so the user can watch the normal Chrome client. Never claim "đã bấm/đã điền/đã mở/đã kiểm tra" from prose alone.`,
121
123
  `When a task touches coding, agents, UI, brand, or design, inspect the relevant required local resource in depth before deciding.`,
122
124
  `If the user asks you to modify, run, inspect, check, publish, commit, or otherwise act on the project, you MUST use tools. Do not claim completion without a tool result from this turn.`,
123
125
  ``,
124
126
  `## Debug Excellence`,
125
- `For bugs, crashes, test failures, or "not working": identify the first hard failure, reproduce or inspect logs, trace the exact runtime path, patch the smallest root cause, and verify with the closest command. For frontend/runtime UI issues, use BrowserDebug when a URL or dev server is available.`,
127
+ `For bugs, crashes, test failures, or "not working": identify the first hard failure, reproduce or inspect logs, trace the exact runtime path, patch the smallest root cause, and verify with the closest command. For frontend/runtime UI issues with a URL/dev server, prefer chrome-devtools MCP in visible Chrome; use BrowserDebug only as a headless fallback.`,
126
128
  ``,
127
129
  `## Design Excellence`,
128
130
  `For UI/design work: inspect existing components/styles and any design resources first. Build a polished, responsive, domain-appropriate interface with complete states and clear interactions. Avoid generic placeholders, fake controls, one-note palettes, and unverified visual claims.`,
@@ -193,7 +195,7 @@ export class PromptBuilder {
193
195
  review: 'You are a Winter review subagent. Critique the request or implementation with specific issues, edge cases, and concrete improvements.',
194
196
  debug: 'You are a Winter debugging subagent. Reproduce or inspect the exact failing path, isolate the first hard blocker, patch the smallest root cause, and verify with the closest test/build/browser smoke.',
195
197
  research: 'You are a Winter research subagent. Gather the important facts, compare options, and summarize only what matters.',
196
- browser: `You are a Winter browser subagent. Bạn CÓ QUYỀN sử dụng tool 'BrowserDebug' để tương tác với trình duyệt. Hãy dùng nó để mở URL, chụp ảnh màn hình (nếu cần), hoặc chạy JS để kiểm tra trang web.`,
198
+ browser: `You are a Winter browser subagent. Bạn CÓ QUYỀN sử dụng chrome-devtools MCP để thao tác Chrome visible cho user xem: mở URL, click, fill form, snapshot, screenshot, đọc console/network. Dùng BrowserDebug chỉ khi cần headless fallback.`,
197
199
  };
198
200
 
199
201
  const rolePrompt = rolePrompts[role] || 'You are a Winter coding subagent. Solve the task directly, use tools when needed, and return a concise result.';
@@ -208,14 +210,14 @@ export class PromptBuilder {
208
210
  '3. [DEBUG EXCELLENCE]: Reproduce or inspect the failing path first, isolate the first hard blocker, patch root cause, and verify with the closest test/build/browser smoke.',
209
211
  '4. [DESIGN EXCELLENCE]: Use rich aesthetics. Default to modern UI frameworks if applicable. Never output plain, ugly HTML/CSS. Ensure responsive, premium feel with micro-animations.',
210
212
  '5. [CODE QUALITY]: Write clean, modular, SOLID code. Check for syntax errors carefully. Do not generate incomplete code blocks.',
211
- '6. [NO HALLUCINATION]: If you don\'t know, use tools (Grep/Read/Web/BrowserDebug) to find out. Do not guess file paths or APIs.',
213
+ '6. [NO HALLUCINATION]: If you don\'t know, use tools (Grep/Read/Web/chrome-devtools MCP/BrowserDebug) to find out. Do not guess file paths or APIs.',
212
214
  '7. [TOOL EXECUTION FIRST]: You DO have file tools. Use Write to create/overwrite files and Edit to patch files. Never say there is no write tool.',
213
215
  '8. [IMAGE INPUTS]: If an image is attached or pasted, analyze it directly and use it as evidence for UI/debug/design decisions.',
214
216
  '',
215
217
  rolePrompt,
216
218
  '',
217
219
  '## Tool Rules',
218
- '- Canonical tools: Read, Write, Edit, Bash, Glob, Grep, TaskCreate, TaskUpdate, TaskList, BrowserDebug, WebFetch, WebSearch.',
220
+ '- Canonical tools: Read, Write, Edit, Bash, Glob, Grep, TaskCreate, TaskUpdate, TaskList, OpenBrowser, BrowserDebug, WebFetch, WebSearch, MCP.',
219
221
  '- If native tool calls are unavailable, output exactly one fallback tool call and no prose: <invoke name="Read"><parameter name="path">README.md</parameter></invoke> OR {"tool":"Read","arguments":{"path":"README.md"}} OR CALL_TOOL Read {"path":"README.md"}.',
220
222
  '- Treat skills, memories, bundled resources, local project rules, and the tool list as operational context. Use them proactively when relevant.',
221
223
  `- Runtime environment:\n${runtimeSummary}`,
@@ -234,11 +236,33 @@ export class PromptBuilder {
234
236
 
235
237
  /** @private */
236
238
  _formatMemories(memories, options = {}) {
237
- return `\n## Memories (Important Context)\n${this._summarizePrompts(memories, {
238
- limit: 8,
239
+ const priorityPatterns = [
240
+ /^\[Recent Work Ledger\]/i,
241
+ /^\[Conversation Summary\]/i,
242
+ /^\[Project Anchor\]/i,
243
+ ];
244
+ const priority = [];
245
+ const regular = [];
246
+
247
+ for (const memory of memories) {
248
+ const text = typeof memory === 'string' ? memory : memory?.text || '';
249
+ if (priorityPatterns.some(pattern => pattern.test(text))) {
250
+ priority.push(memory);
251
+ } else {
252
+ regular.push(memory);
253
+ }
254
+ }
255
+
256
+ const ordered = [
257
+ ...regular.slice(-Math.max(0, (options.limit || 10) - Math.min(priority.length, 4))),
258
+ ...priority.slice(-4),
259
+ ];
260
+
261
+ return `\n## Memories (Important Context)\n${this._summarizePrompts(ordered, {
262
+ limit: options.limit || 10,
239
263
  maxEntryChars: 220,
240
264
  maxTotalChars: options.maxTotalChars || 1200,
241
- mapper: memory => memory.text,
265
+ mapper: memory => typeof memory === 'string' ? memory : memory?.text,
242
266
  })}`;
243
267
  }
244
268
 
@@ -4,6 +4,7 @@ import { colors } from './snowflake-logo.js';
4
4
  import { SLASH_COMMANDS } from './slash-commands.js';
5
5
 
6
6
  import { DesignCommands } from '../design/commands.js';
7
+ import { handleRagCommandFromRepl } from '../rag/cli.js';
7
8
 
8
9
  function getPageAgentRoot(repl) {
9
10
  return repl.contextLoader?.getResourcePaths?.()?.pageAgent || path.join(repl.projectPath, 'resources', 'local', 'page-agent');
@@ -672,6 +673,11 @@ export async function handleSlashCommand(repl, input) {
672
673
  case '/pageagent':
673
674
  await handlePageAgentCommand(repl, args);
674
675
  break;
676
+
677
+ // RAG
678
+ case '/rag':
679
+ await handleRagCommandFromRepl(repl, args);
680
+ break;
675
681
  case '/image':
676
682
  const imagePath = args[0];
677
683
  const imageQuestion = args.slice(1).join(' ');