winter-super-cli 2026.6.24 → 2026.6.27

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 (123) hide show
  1. package/CHANGELOG.md +28 -5
  2. package/README.md +85 -0
  3. package/package.json +5 -1
  4. package/resources/local/gsap-skills/.claude-plugin/marketplace.json +20 -0
  5. package/resources/local/gsap-skills/.claude-plugin/plugin.json +6 -0
  6. package/resources/local/gsap-skills/.cursor-plugin/marketplace.json +13 -0
  7. package/resources/local/gsap-skills/.cursor-plugin/plugin.json +22 -0
  8. package/resources/local/gsap-skills/.github/copilot-instructions.md +17 -0
  9. package/resources/local/gsap-skills/.github/instructions/react.instructions.md +15 -0
  10. package/resources/local/gsap-skills/.github/instructions/scrolltrigger.instructions.md +18 -0
  11. package/resources/local/gsap-skills/AGENTS.md +27 -0
  12. package/resources/local/gsap-skills/CLAUDE.md +1 -0
  13. package/resources/local/gsap-skills/GEMINI.md +1 -0
  14. package/resources/local/gsap-skills/LICENSE +21 -0
  15. package/resources/local/gsap-skills/README.md +163 -0
  16. package/resources/local/gsap-skills/assets/gsap-green.svg +7 -0
  17. package/resources/local/gsap-skills/assets/gsap-icon-inverted.svg +15 -0
  18. package/resources/local/gsap-skills/assets/gsap-icon-square.svg +1 -0
  19. package/resources/local/gsap-skills/assets/gsap-white.svg +7 -0
  20. package/resources/local/gsap-skills/examples/README.md +29 -0
  21. package/resources/local/gsap-skills/examples/nuxt/app/app.vue +3 -0
  22. package/resources/local/gsap-skills/examples/nuxt/app/composables/useGSAP.ts +91 -0
  23. package/resources/local/gsap-skills/examples/nuxt/app/pages/index.vue +55 -0
  24. package/resources/local/gsap-skills/examples/nuxt/nuxt.config.ts +4 -0
  25. package/resources/local/gsap-skills/examples/nuxt/package.json +18 -0
  26. package/resources/local/gsap-skills/examples/react/App.jsx +46 -0
  27. package/resources/local/gsap-skills/examples/react/index.html +12 -0
  28. package/resources/local/gsap-skills/examples/react/main.jsx +9 -0
  29. package/resources/local/gsap-skills/examples/react/package.json +21 -0
  30. package/resources/local/gsap-skills/examples/react/vite.config.js +7 -0
  31. package/resources/local/gsap-skills/examples/vanilla/index.html +33 -0
  32. package/resources/local/gsap-skills/examples/vanilla/main.js +36 -0
  33. package/resources/local/gsap-skills/examples/vue/app.vue +47 -0
  34. package/resources/local/gsap-skills/examples/vue/index.html +15 -0
  35. package/resources/local/gsap-skills/examples/vue/main.js +9 -0
  36. package/resources/local/gsap-skills/examples/vue/package.json +19 -0
  37. package/resources/local/gsap-skills/examples/vue/vite.config.js +7 -0
  38. package/resources/local/gsap-skills/skills/gsap-core/SKILL.md +254 -0
  39. package/resources/local/gsap-skills/skills/gsap-frameworks/SKILL.md +266 -0
  40. package/resources/local/gsap-skills/skills/gsap-performance/SKILL.md +79 -0
  41. package/resources/local/gsap-skills/skills/gsap-plugins/SKILL.md +433 -0
  42. package/resources/local/gsap-skills/skills/gsap-react/SKILL.md +136 -0
  43. package/resources/local/gsap-skills/skills/gsap-scrolltrigger/SKILL.md +296 -0
  44. package/resources/local/gsap-skills/skills/gsap-timeline/SKILL.md +107 -0
  45. package/resources/local/gsap-skills/skills/gsap-utils/SKILL.md +284 -0
  46. package/resources/local/gsap-skills/skills/llms.txt +39 -0
  47. package/resources/local/hermes-agent-core/AGENTS.md +1132 -0
  48. package/resources/local/hermes-agent-core/LICENSE +21 -0
  49. package/resources/local/hermes-agent-core/README.md +215 -0
  50. package/resources/local/hermes-agent-core/docs/2026-05-07-s6-overlay-dynamic-subagent-gateways.md +434 -0
  51. package/resources/local/hermes-agent-core/hermes-already-has-routines.md +160 -0
  52. package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/DESCRIPTION.md +3 -0
  53. package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/claude-code/SKILL.md +745 -0
  54. package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/codex/SKILL.md +130 -0
  55. package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/hermes-agent/SKILL.md +1021 -0
  56. package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/kanban-codex-lane/SKILL.md +277 -0
  57. package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/kanban-codex-lane/templates/pmb-codex-lane-prompt.md +57 -0
  58. package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/opencode/SKILL.md +219 -0
  59. package/resources/local/hermes-agent-core/skills/github/DESCRIPTION.md +3 -0
  60. package/resources/local/hermes-agent-core/skills/github/codebase-inspection/SKILL.md +116 -0
  61. package/resources/local/hermes-agent-core/skills/github/github-auth/SKILL.md +247 -0
  62. package/resources/local/hermes-agent-core/skills/github/github-auth/scripts/gh-env.sh +66 -0
  63. package/resources/local/hermes-agent-core/skills/github/github-code-review/SKILL.md +481 -0
  64. package/resources/local/hermes-agent-core/skills/github/github-code-review/references/review-output-template.md +74 -0
  65. package/resources/local/hermes-agent-core/skills/github/github-issues/SKILL.md +370 -0
  66. package/resources/local/hermes-agent-core/skills/github/github-issues/templates/bug-report.md +35 -0
  67. package/resources/local/hermes-agent-core/skills/github/github-issues/templates/feature-request.md +31 -0
  68. package/resources/local/hermes-agent-core/skills/github/github-pr-workflow/SKILL.md +367 -0
  69. package/resources/local/hermes-agent-core/skills/github/github-pr-workflow/references/ci-troubleshooting.md +183 -0
  70. package/resources/local/hermes-agent-core/skills/github/github-pr-workflow/references/conventional-commits.md +71 -0
  71. package/resources/local/hermes-agent-core/skills/github/github-pr-workflow/templates/pr-body-bugfix.md +35 -0
  72. package/resources/local/hermes-agent-core/skills/github/github-pr-workflow/templates/pr-body-feature.md +33 -0
  73. package/resources/local/hermes-agent-core/skills/github/github-repo-management/SKILL.md +516 -0
  74. package/resources/local/hermes-agent-core/skills/github/github-repo-management/references/github-api-cheatsheet.md +161 -0
  75. package/resources/local/hermes-agent-core/skills/mcp/DESCRIPTION.md +3 -0
  76. package/resources/local/hermes-agent-core/skills/mcp/native-mcp/SKILL.md +357 -0
  77. package/resources/local/hermes-agent-core/skills/software-development/debugging-hermes-tui-commands/SKILL.md +152 -0
  78. package/resources/local/hermes-agent-core/skills/software-development/hermes-agent-skill-authoring/SKILL.md +165 -0
  79. package/resources/local/hermes-agent-core/skills/software-development/hermes-s6-container-supervision/SKILL.md +176 -0
  80. package/resources/local/hermes-agent-core/skills/software-development/node-inspect-debugger/SKILL.md +319 -0
  81. package/resources/local/hermes-agent-core/skills/software-development/plan/SKILL.md +58 -0
  82. package/resources/local/hermes-agent-core/skills/software-development/python-debugpy/SKILL.md +375 -0
  83. package/resources/local/hermes-agent-core/skills/software-development/requesting-code-review/SKILL.md +280 -0
  84. package/resources/local/hermes-agent-core/skills/software-development/spike/SKILL.md +197 -0
  85. package/resources/local/hermes-agent-core/skills/software-development/subagent-driven-development/SKILL.md +352 -0
  86. package/resources/local/hermes-agent-core/skills/software-development/subagent-driven-development/references/context-budget-discipline.md +53 -0
  87. package/resources/local/hermes-agent-core/skills/software-development/subagent-driven-development/references/gates-taxonomy.md +93 -0
  88. package/resources/local/hermes-agent-core/skills/software-development/systematic-debugging/SKILL.md +367 -0
  89. package/resources/local/hermes-agent-core/skills/software-development/test-driven-development/SKILL.md +343 -0
  90. package/resources/local/hermes-agent-core/skills/software-development/writing-plans/SKILL.md +297 -0
  91. package/resources/local/manifest.json +12 -0
  92. package/rule.md +2 -0
  93. package/scripts/audit-pack.js +5 -0
  94. package/scripts/smoke-browser.js +53 -0
  95. package/scripts/smoke-package.js +38 -4
  96. package/skill.md +36 -4
  97. package/skills/gsap.md +26 -0
  98. package/skills/hermes-agent.md +17 -0
  99. package/src/agent/agent-definitions.js +4 -4
  100. package/src/agent/runtime.js +179 -5
  101. package/src/agent/subagent-child.js +44 -0
  102. package/src/ai/capability-scorecard.js +193 -14
  103. package/src/ai/hermes-core.js +77 -0
  104. package/src/ai/model-capabilities.js +42 -2
  105. package/src/ai/prompts/system-prompt.js +18 -2
  106. package/src/ai/small-model-amplifier.js +35 -7
  107. package/src/ai/workflow-selector.js +22 -1
  108. package/src/cli/commands.js +46 -2
  109. package/src/cli/config.js +45 -6
  110. package/src/cli/context-loader.js +253 -9
  111. package/src/cli/conversation-format.js +5 -0
  112. package/src/cli/input-controller.js +79 -10
  113. package/src/cli/prompt-builder.js +47 -8
  114. package/src/cli/repl-commands.js +115 -0
  115. package/src/cli/repl.js +343 -85
  116. package/src/cli/slash-commands.js +4 -2
  117. package/src/cli/tui.js +133 -37
  118. package/src/mcp/client.js +54 -11
  119. package/src/mcp/presets.js +114 -0
  120. package/src/tools/agent.js +316 -25
  121. package/src/tools/executor.js +412 -12
  122. package/src/tools/permission.js +20 -17
  123. package/winter.d.ts +112 -10
@@ -36,13 +36,14 @@ export const SLASH_COMMANDS = [
36
36
  { cmd: '/grep', desc: 'Search files', usage: '/grep <pattern>' },
37
37
  { cmd: '/bash', desc: 'Run command', usage: '/bash <command>' },
38
38
  { cmd: '/image', desc: 'Analyze image/screenshot or clipboard image', usage: '/image [file] [question]' },
39
+ { cmd: '/paste', desc: 'Read clipboard text or image', usage: '/paste [prompt]' },
39
40
  { cmd: '/design', desc: 'Design commands', sub: ['search', 'add', 'apply', 'list', 'preview'] },
40
41
  { cmd: '/designs', desc: 'List/search awesome-design-md systems', usage: '/designs [query]' },
41
42
  { cmd: '/skill', desc: 'Skills management', sub: ['list', 'enable', 'create'] },
42
43
  { cmd: '/skills', desc: 'List local Winter/Codex/Claude skills' },
43
44
  { cmd: '/plugin', desc: 'Plugin management', sub: ['list', 'install', 'remove'] },
44
- { cmd: '/mcp', desc: 'MCP server management', sub: ['list', 'add', 'remove', 'allow'] },
45
- { cmd: '/permissions', desc: 'Permission allowlist', sub: ['list', 'allow', 'prompt'] },
45
+ { cmd: '/mcp', desc: 'MCP server management', sub: ['list', 'add', 'preset', 'install', 'remove', 'allow', 'tools'] },
46
+ { cmd: '/permissions', desc: 'Permission allowlist', sub: ['list', 'allow', 'prompt', 'full'] },
46
47
  { cmd: '/stats', desc: 'Tool usage statistics' },
47
48
  { cmd: '/replay', desc: 'Replay recent session/tool events', usage: '/replay [count]' },
48
49
  { cmd: '/diff', desc: 'Preview git diff', usage: '/diff [--cached|--confirm]' },
@@ -57,6 +58,7 @@ export const SLASH_COMMANDS = [
57
58
  { cmd: '/composer', desc: 'Multi-file editing mode (like Cursor Composer)', usage: '/composer <task>' },
58
59
  { cmd: '/complete', desc: 'Trigger inline code completion', usage: '/complete <file> [line] [col]' },
59
60
  { cmd: '/browse', desc: 'Browse URL in Chrome via browser automation', usage: '/browse <url>' },
61
+ { cmd: '/browser', desc: 'Control visible Chrome', usage: '/browser <open|click|type|screenshot|snapshot|eval> [url] [--selector css] [--text value] [--keep-open]' },
60
62
  { cmd: '/ensemble', desc: 'Run all AI providers in parallel', usage: '/ensemble <prompt>' },
61
63
  { cmd: '/vote', desc: 'Run multiple models and vote for best answer', usage: '/vote <prompt>' },
62
64
  { cmd: '/orchestrate', desc: 'Full pipeline: classify → parallel → merge → review', usage: '/orchestrate <task>' },
package/src/cli/tui.js CHANGED
@@ -1,4 +1,4 @@
1
- import { terminalWidth, visibleWidth, wrapText } from './terminal-ui.js';
1
+ import { terminalWidth, visibleWidth } from './terminal-ui.js';
2
2
 
3
3
  const WINTER_LOGO = [
4
4
  ' __ __ _____ _ _ _______ ______ _____ ',
@@ -14,15 +14,90 @@ function basenameFromPath(filePath, fallback = 'project') {
14
14
  return parts[parts.length - 1] || fallback;
15
15
  }
16
16
 
17
+ function stripAnsi(text = '') {
18
+ return String(text || '').replace(/\x1b\[[0-9;]*m/g, '');
19
+ }
20
+
21
+ function clampText(text = '', max = 72) {
22
+ const value = String(text || '');
23
+ if (visibleWidth(value) <= max) return value;
24
+ const plain = stripAnsi(value);
25
+ return `${plain.slice(0, Math.max(0, max - 3))}...`;
26
+ }
27
+
28
+ function formatCount(value, fallback = 0) {
29
+ const number = Number(value ?? fallback);
30
+ return Number.isFinite(number) ? number : fallback;
31
+ }
32
+
33
+ function summarizeTools(events = []) {
34
+ if (!Array.isArray(events) || events.length === 0) return 'idle';
35
+ return events.slice(-4).map(event => {
36
+ const name = event.toolName || event.tool || event.name || 'tool';
37
+ const ok = event.success === false ? 'fail' : 'ok';
38
+ return `${name}:${ok}`;
39
+ }).join(' ');
40
+ }
41
+
42
+ function summarizeHistory(entries = []) {
43
+ if (!Array.isArray(entries) || entries.length === 0) return [];
44
+ return entries.slice(-4).map(entry => {
45
+ const role = entry.role === 'assistant' ? 'Winter' : entry.role === 'user' ? 'You' : entry.role || 'event';
46
+ const content = typeof entry.content === 'string'
47
+ ? entry.content
48
+ : Array.isArray(entry.content)
49
+ ? entry.content.map(part => part?.text || part?.content || '').join(' ')
50
+ : entry.text || '';
51
+ const compact = clampText(content.replace(/\s+/g, ' ').trim(), 78);
52
+ return compact ? `${role}: ${compact}` : '';
53
+ }).filter(Boolean);
54
+ }
55
+
56
+ function formatRecentHistoryLine(entry) {
57
+ if (typeof entry === 'string') return entry;
58
+ if (!entry || typeof entry !== 'object') return '';
59
+ const role = entry.role === 'assistant' ? 'Winter' : entry.role === 'user' ? 'You' : entry.role || 'event';
60
+ const content = typeof entry.content === 'string'
61
+ ? entry.content
62
+ : Array.isArray(entry.content)
63
+ ? entry.content.map(part => part?.text || part?.content || '').join(' ')
64
+ : entry.text || '';
65
+ const compact = clampText(String(content || '').replace(/\s+/g, ' ').trim(), 78);
66
+ return compact ? `${role}: ${compact}` : '';
67
+ }
68
+
69
+ function sectionLine(label, value, c = {}) {
70
+ return `${c.dim || ''}${label.padEnd(10)}${c.reset || ''} ${value}`;
71
+ }
72
+
17
73
  export function buildTuiSnapshot(repl = {}) {
18
74
  const provider = repl.ai?.getActiveProvider?.() || 'provider';
19
75
  const model = repl.ai?.providers?.[provider]?.model || 'model';
76
+ const context = repl.session?.getContext?.() || {};
77
+ const history = repl.session?.getHistory?.() || [];
78
+ const toolEvents = repl.session?.getToolEvents?.() || [];
79
+ const codebaseStats = repl.codebaseSearcher?.indexer?.getStats?.() || {};
80
+ const activeSkills = Array.isArray(context.activeSkills?.value)
81
+ ? context.activeSkills.value
82
+ : Array.isArray(context.activeSkills)
83
+ ? context.activeSkills
84
+ : [];
85
+
20
86
  return {
21
87
  provider,
22
88
  model,
89
+ modelTier: repl.ai?._modelTier || repl.getActiveModelTier?.() || 'unknown',
23
90
  projectPath: repl.projectPath || process.cwd(),
24
91
  sessionShort: String(repl.session?.getSessionId?.() || 'session').slice(0, 8),
25
92
  projectName: basenameFromPath(repl.projectPath || process.cwd()),
93
+ statusText: repl.isProcessing ? 'running' : 'ready',
94
+ queueText: Array.isArray(repl.taskQueue) && repl.taskQueue.length > 0 ? `${repl.taskQueue.length} queued` : 'empty',
95
+ codebaseFiles: formatCount(codebaseStats.totalFiles),
96
+ codebaseChunks: formatCount(codebaseStats.totalChunks),
97
+ toolSummary: summarizeTools(toolEvents),
98
+ recentHistory: summarizeHistory(history),
99
+ activeSkills: activeSkills.slice(0, 8),
100
+ hermesCore: true,
26
101
  };
27
102
  }
28
103
 
@@ -39,40 +114,57 @@ export function renderInputPanel(snapshot, {
39
114
  : snapshot.provider || snapshot.model || 'model';
40
115
 
41
116
  return {
42
- top: `${c.dim}┌${''.repeat(innerWidth + 2)}┐${c.reset}`,
43
- status: `${c.bright}${c.cyan}WINTER${c.reset} ${c.dim}·${c.reset} ${projectName} ${c.dim}·${c.reset} ${providerModel}`,
44
- hint: `${c.dim}@file${c.reset} attach · ${c.dim}!cmd${c.reset} bash · ${c.dim}^V img${c.reset} paste`,
45
- prompt: `${c.bright}${c.green}winter${c.reset} ${c.dim}›${c.reset} `,
46
- bottom: `${c.dim}└${''.repeat(innerWidth + 2)}┘${c.reset}`,
117
+ top: `${c.dim}+${'-'.repeat(innerWidth + 2)}+${c.reset}`,
118
+ status: `${c.bright}${c.cyan}WINTER${c.reset} ${c.dim}.${c.reset} ${projectName} ${c.dim}.${c.reset} ${providerModel}`,
119
+ hint: `${c.dim}@file${c.reset} attach . ${c.dim}!cmd${c.reset} bash . ${c.dim}Ctrl+V${c.reset}/${c.dim}^V img${c.reset}`,
120
+ prompt: `${c.bright}${c.green}winter${c.reset} ${c.dim}>${c.reset} `,
121
+ bottom: `${c.dim}+${'-'.repeat(innerWidth + 2)}+${c.reset}`,
47
122
  };
48
123
  }
49
124
 
50
125
  export function renderLandingTui(snapshot, { colors } = {}) {
51
126
  const c = colors || {};
52
127
  const W = Math.max(60, Math.min(process.stdout.columns || 80, 140));
53
-
128
+
54
129
  const bright = c.bright || '\x1b[1m';
55
130
  const green = c.brightGreen || c.green || '\x1b[92m';
56
131
  const white = c.white || '\x1b[37m';
57
132
  const dim = c.dim || '\x1b[2m';
58
133
  const reset = c.reset || '\x1b[0m';
59
- const bgBlue = '\x1b[48;5;236m';
134
+ const bgBlue = '\x1b[48;5;236m';
60
135
 
61
136
  const logoLines = WINTER_LOGO.map(line => `${bright}${green}${line}${reset}`);
62
-
63
- const leftStatus = ` ${snapshot.provider} · ${snapshot.model} `;
64
- const rightStatus = ` ESC×2 exit · /help `;
65
- const padding = Math.max(0, W - leftStatus.length - rightStatus.length);
137
+ const leftStatus = ` ${snapshot.provider} / ${snapshot.model} `;
138
+ const rightStatus = ' /tui /help /doctor tools ';
139
+ const padding = Math.max(0, W - stripAnsi(leftStatus).length - stripAnsi(rightStatus).length);
66
140
  const statusBar = `${bgBlue}${white}${leftStatus}${' '.repeat(padding)}${rightStatus}${reset}`;
141
+ const recent = snapshot.recentHistory?.length
142
+ ? snapshot.recentHistory.map(formatRecentHistoryLine).filter(Boolean).map(line => `${dim}- ${line}${reset}`)
143
+ : [`${dim}- No recent messages loaded.${reset}`];
144
+ const skills = snapshot.activeSkills?.length ? snapshot.activeSkills.join(', ') : 'coding, debug, test';
67
145
 
68
146
  return [
69
147
  ...logoLines,
70
148
  '',
71
- `${white}Winter will run commands on your behalf to help you build.${reset}`,
149
+ `${white}Winter dashboard${reset} ${dim}Hermes-style agent core: skills, memory, tools, subagents, gateway discipline.${reset}`,
72
150
  '',
73
- `${white}Directory${reset} ${dim}${snapshot.projectPath}${reset}`,
151
+ statusBar,
74
152
  '',
75
- statusBar
153
+ `${bgBlue}${white} STATUS ${reset}`,
154
+ sectionLine('Project', `${snapshot.projectName} ${dim}${snapshot.projectPath}${reset}`, c),
155
+ sectionLine('Model', `${snapshot.provider}/${snapshot.model} ${dim}${snapshot.modelTier || 'unknown'}${reset}`, c),
156
+ sectionLine('Session', `${snapshot.sessionShort} ${dim}${snapshot.statusText || 'ready'} . queue ${snapshot.queueText || 'empty'}${reset}`, c),
157
+ sectionLine('Codebase', `${snapshot.codebaseFiles || 0} files, ${snapshot.codebaseChunks || 0} chunks`, c),
158
+ sectionLine('Tools', snapshot.toolSummary || 'idle', c),
159
+ '',
160
+ `${bgBlue}${white} AGENT CORE ${reset}`,
161
+ sectionLine('Hermes', 'self-improve . skill lifecycle . session search . subagents . automation', c),
162
+ sectionLine('Skills', skills, c),
163
+ sectionLine('Gateway', 'MCP diagnostics . timeout handling . concrete tool evidence', c),
164
+ '',
165
+ `${bgBlue}${white} RECENT ${reset}`,
166
+ ...recent,
167
+ renderCommandCenter({ colors: c, width: W }),
76
168
  ].join('\n');
77
169
  }
78
170
 
@@ -84,11 +176,11 @@ export function renderStatusPanel(snapshot, { colors, title = 'Status' } = {}) {
84
176
  return [
85
177
  '',
86
178
  header,
87
- `${c.dim}Project :${c.reset} ${snapshot.projectName} (${snapshot.projectPath})`,
88
- `${c.dim}Model :${c.reset} ${snapshot.provider}/${snapshot.model} (${snapshot.modelTier})`,
89
- `${c.dim}Session :${c.reset} ${snapshot.sessionShort} | State: ${snapshot.statusText}`,
90
- `${c.dim}Codebase:${c.reset} ${snapshot.codebaseFiles} files, ${snapshot.codebaseChunks} chunks`,
91
- `${c.dim}Activity:${c.reset} ${snapshot.toolSummary || 'idle'}`,
179
+ sectionLine('Project', `${snapshot.projectName} (${snapshot.projectPath})`, c),
180
+ sectionLine('Model', `${snapshot.provider}/${snapshot.model} (${snapshot.modelTier || 'unknown'})`, c),
181
+ sectionLine('Session', `${snapshot.sessionShort} | ${snapshot.statusText || 'ready'} | queue ${snapshot.queueText || 'empty'}`, c),
182
+ sectionLine('Codebase', `${snapshot.codebaseFiles || 0} files, ${snapshot.codebaseChunks || 0} chunks`, c),
183
+ sectionLine('Activity', snapshot.toolSummary || 'idle', c),
92
184
  ''
93
185
  ].join('\n');
94
186
  }
@@ -101,16 +193,20 @@ export function renderCommandCenter({ colors, width = 80 } = {}) {
101
193
  const c = colors || {};
102
194
  const bgBlue = '\x1b[48;5;236m';
103
195
  const header = `${bgBlue}${c.white} COMMAND CENTER ${c.reset}`;
104
-
196
+ const hint = `${c.dim}Slash commands share one workflow: inspect real state, use tools, verify, then report evidence.${c.reset}`;
197
+
105
198
  return [
106
199
  '',
107
200
  header,
108
- `${c.brightGreen}B${c.reset} ${c.bright}${c.cyan}Build ${c.reset} ${c.dim}/auto /debug /tdd /swe /composer${c.reset}`,
109
- `${c.brightGreen}I${c.reset} ${c.bright}${c.cyan}Inspect${c.reset} ${c.dim}/read /grep /glob /search /context${c.reset}`,
110
- `${c.brightGreen}M${c.reset} ${c.bright}${c.cyan}Model ${c.reset} ${c.dim}/provider /providers /model /models /scorecard${c.reset}`,
111
- `${c.brightGreen}K${c.reset} ${c.bright}${c.cyan}Memory ${c.reset} ${c.dim}/remember /memories /memory-vault /compress${c.reset}`,
112
- `${c.brightGreen}V${c.reset} ${c.bright}${c.cyan}Visual ${c.reset} ${c.dim}/image /paste ^V img /designs /page-agent${c.reset}`,
113
- `${c.brightGreen}S${c.reset} ${c.bright}${c.cyan}System ${c.reset} ${c.dim}/doctor full /stats /permissions /mcp /help${c.reset}`,
201
+ hint,
202
+ `${c.brightGreen}B${c.reset} ${c.bright}${c.cyan}Build ${c.reset} ${c.dim}/auto /debug /tdd /swe /composer /plan fetch${c.reset}`,
203
+ `${c.brightGreen}I${c.reset} ${c.bright}${c.cyan}Inspect ${c.reset} ${c.dim}/read /grep /glob /search /context /doctor tools${c.reset}`,
204
+ `${c.brightGreen}M${c.reset} ${c.bright}${c.cyan}Model ${c.reset} ${c.dim}/provider /providers /model /models /scorecard${c.reset}`,
205
+ `${c.brightGreen}K${c.reset} ${c.bright}${c.cyan}Memory ${c.reset} ${c.dim}/remember /memories /memory-vault /compress /stats${c.reset}`,
206
+ `${c.brightGreen}A${c.reset} ${c.bright}${c.cyan}Agent ${c.reset} ${c.dim}/skills hermes-agent /mcp /resources /agent /parallel${c.reset}`,
207
+ `${c.brightGreen}G${c.reset} ${c.bright}${c.cyan}Gateway ${c.reset} ${c.dim}/mcp list /mcp tools chrome-devtools /permissions list${c.reset}`,
208
+ `${c.brightGreen}V${c.reset} ${c.bright}${c.cyan}Visual ${c.reset} ${c.dim}/image /paste Ctrl+V /designs /page-agent /htmlfx${c.reset}`,
209
+ `${c.brightGreen}S${c.reset} ${c.bright}${c.cyan}System ${c.reset} ${c.dim}/doctor full /stats /resources /help${c.reset}`,
114
210
  ''
115
211
  ].join('\n');
116
212
  }
@@ -119,16 +215,16 @@ export function renderSplitPanel({ title, left = [], right = [], colors, width =
119
215
  const c = colors || {};
120
216
  const bgBlue = '\x1b[48;5;236m';
121
217
  const header = `${bgBlue}${c.white} ${(title || 'Info').toUpperCase()} ${c.reset}`;
122
-
218
+
123
219
  const innerWidth = Math.max(56, width - 4);
124
220
  const leftWidth = Math.floor(innerWidth * 0.5);
125
-
221
+
126
222
  const rows = [];
127
223
  const count = Math.max(left.length, right.length);
128
224
  for (let i = 0; i < count; i++) {
129
225
  const lText = String(left[i] || '');
130
226
  const rText = String(right[i] || '');
131
- const lPlain = lText.replace(/\x1b\[[0-9;]*m/g, '');
227
+ const lPlain = stripAnsi(lText);
132
228
  const lPad = Math.max(0, leftWidth - lPlain.length);
133
229
  rows.push(`${lText}${' '.repeat(lPad)} ${rText}`);
134
230
  }
@@ -145,7 +241,7 @@ export function renderHistoryPanel(entries = [], { colors, title = 'Recent Sessi
145
241
  const c = colors || {};
146
242
  const bgBlue = '\x1b[48;5;236m';
147
243
  const header = `${bgBlue}${c.white} ${title.toUpperCase()} ${c.reset}`;
148
-
244
+
149
245
  const body = entries.length > 0
150
246
  ? entries.map(entry => {
151
247
  const role = entry.role === 'assistant' ? 'Winter' : entry.role === 'user' ? 'You' : entry.role || 'event';
@@ -166,7 +262,7 @@ export function renderAssistantPanel({ content = '', footer = '', colors, title
166
262
  const c = colors || {};
167
263
  const bgBlue = '\x1b[48;5;236m';
168
264
  const header = `${bgBlue}${c.white} ${title.toUpperCase()} ${c.reset}`;
169
-
265
+
170
266
  const parts = [];
171
267
  if (title) parts.push('', header);
172
268
  if (content) parts.push(content);
@@ -176,15 +272,15 @@ export function renderAssistantPanel({ content = '', footer = '', colors, title
176
272
 
177
273
  export function renderToolPanel({ toolName = 'Tool', summary = '', success = true, colors } = {}) {
178
274
  const c = colors || {};
179
- const status = success ? `${c.brightGreen}✓${c.reset}` : `${c.red}✖${c.reset}`;
180
-
275
+ const status = success ? `${c.brightGreen}OK${c.reset}` : `${c.red}FAIL${c.reset}`;
276
+
181
277
  if (!summary.includes('\n')) {
182
- return `${status} ${c.bright}${c.cyan}${toolName}${c.reset} ${c.dim}· ${summary}${c.reset}`;
278
+ return `${status} ${c.bright}${c.cyan}${toolName}${c.reset} ${c.dim}. ${summary}${c.reset}`;
183
279
  }
184
280
 
185
281
  const lines = summary.split('\n');
186
282
  const firstLine = lines.shift();
187
-
283
+
188
284
  const formattedRest = lines.map(line => {
189
285
  if (line.startsWith('+')) return ` ${c.green}${line}${c.reset}`;
190
286
  if (line.startsWith('-')) return ` ${c.red}${line}${c.reset}`;
@@ -192,7 +288,7 @@ export function renderToolPanel({ toolName = 'Tool', summary = '', success = tru
192
288
  return ` ${c.dim}${line}${c.reset}`;
193
289
  }).join('\n');
194
290
 
195
- let output = `${status} ${c.bright}${c.cyan}${toolName}${c.reset} ${c.dim}· ${firstLine}${c.reset}`;
291
+ let output = `${status} ${c.bright}${c.cyan}${toolName}${c.reset} ${c.dim}. ${firstLine}${c.reset}`;
196
292
  if (formattedRest) output += `\n${formattedRest}`;
197
293
  return output;
198
294
  }
package/src/mcp/client.js CHANGED
@@ -1,7 +1,22 @@
1
- import { spawn } from 'child_process';
2
- import { encodeMcpMessage, decodeMcpMessages, createNotification, createRequest } from './protocol.js';
3
-
4
- export class MCPClient {
1
+ import { spawn } from 'child_process';
2
+ import { encodeMcpMessage, decodeMcpMessages, createNotification, createRequest } from './protocol.js';
3
+
4
+ export class MCPRequestTimeoutError extends Error {
5
+ constructor({ method, timeoutMs, requestId, serverName, lastStderr } = {}) {
6
+ const serverText = serverName ? ` on ${serverName}` : '';
7
+ const stderrText = lastStderr ? `; stderr: ${lastStderr}` : '';
8
+ super(`MCP request timed out after ${timeoutMs}ms: ${method}${serverText}${stderrText}`);
9
+ this.name = 'MCPRequestTimeoutError';
10
+ this.code = 'MCP_REQUEST_TIMEOUT';
11
+ this.method = method;
12
+ this.timeoutMs = timeoutMs;
13
+ this.requestId = requestId;
14
+ this.serverName = serverName;
15
+ this.lastStderr = lastStderr;
16
+ }
17
+ }
18
+
19
+ export class MCPClient {
5
20
  constructor(serverConfig = {}) {
6
21
  this.serverConfig = serverConfig;
7
22
  this.process = null;
@@ -22,12 +37,14 @@ export class MCPClient {
22
37
  throw new Error('MCP server command is required');
23
38
  }
24
39
 
25
- const args = Array.isArray(this.serverConfig.args) ? this.serverConfig.args : [];
26
- this.process = spawn(command, args, {
27
- stdio: ['pipe', 'pipe', 'pipe'],
28
- shell: false,
29
- windowsHide: true,
30
- });
40
+ const args = Array.isArray(this.serverConfig.args) ? this.serverConfig.args : [];
41
+ this.process = spawn(command, args, {
42
+ stdio: ['pipe', 'pipe', 'pipe'],
43
+ cwd: this.serverConfig.cwd || undefined,
44
+ env: { ...process.env, ...(this.serverConfig.env || {}) },
45
+ shell: false,
46
+ windowsHide: true,
47
+ });
31
48
 
32
49
  this.process.stdout.on('data', chunk => this.handleStdout(chunk));
33
50
  this.process.stderr.on('data', chunk => {
@@ -92,7 +109,15 @@ export class MCPClient {
92
109
  return new Promise((resolve, reject) => {
93
110
  const timer = setTimeout(() => {
94
111
  this.pending.delete(id);
95
- reject(new Error(`MCP request timed out: ${method}`));
112
+ const error = new MCPRequestTimeoutError({
113
+ method,
114
+ timeoutMs: this.requestTimeoutMs,
115
+ requestId: id,
116
+ serverName: this.serverConfig.name,
117
+ lastStderr: this.lastStderr,
118
+ });
119
+ reject(error);
120
+ this.closeAfterTimeout(error);
96
121
  }, this.requestTimeoutMs);
97
122
  this.pending.set(id, { resolve, reject, timer });
98
123
  this.process.stdin.write(packet, error => {
@@ -136,6 +161,24 @@ export class MCPClient {
136
161
  }
137
162
  }
138
163
 
164
+ closeAfterTimeout(error) {
165
+ this.rejectAllPending(error || new Error('MCP server timed out'));
166
+ if (!this.process) return;
167
+ const processRef = this.process;
168
+ this.process = null;
169
+ this.initialized = false;
170
+ try {
171
+ processRef.stdin?.destroy?.();
172
+ } catch {
173
+ // Best-effort cleanup after a timed-out request.
174
+ }
175
+ try {
176
+ processRef.kill();
177
+ } catch {
178
+ // Process may already be gone.
179
+ }
180
+ }
181
+
139
182
  rejectAllPending(error) {
140
183
  for (const pending of this.pending.values()) {
141
184
  clearTimeout(pending.timer);
@@ -0,0 +1,114 @@
1
+ export const CHROME_DEVTOOLS_MCP_NAME = 'chrome-devtools';
2
+
3
+ const CHROME_DEVTOOLS_PACKAGE = 'chrome-devtools-mcp@latest';
4
+ const CHROME_DEVTOOLS_SOURCE = 'https://github.com/ChromeDevTools/chrome-devtools-mcp';
5
+
6
+ const CHROME_DEVTOOLS_FLAGS_WITH_VALUES = new Set([
7
+ '--browser-url',
8
+ '--channel',
9
+ '--executablePath',
10
+ '--logFile',
11
+ '--viewport',
12
+ '--proxy-server',
13
+ ]);
14
+
15
+ const CHROME_DEVTOOLS_BOOLEAN_FLAGS = new Set([
16
+ '--headless',
17
+ '--isolated',
18
+ '--acceptInsecureCerts',
19
+ '--help',
20
+ ]);
21
+
22
+ export function normalizeMcpPresetName(name = '') {
23
+ return String(name || '').trim().toLowerCase();
24
+ }
25
+
26
+ export function isChromeDevtoolsPreset(name = '') {
27
+ return ['chrome-devtools', 'chromedevtools', 'chrome', 'devtools', 'cdp'].includes(normalizeMcpPresetName(name));
28
+ }
29
+
30
+ export function buildChromeDevtoolsArgs(options = []) {
31
+ const input = Array.isArray(options) ? [...options] : [];
32
+ const args = ['-y', CHROME_DEVTOOLS_PACKAGE];
33
+
34
+ for (let index = 0; index < input.length; index += 1) {
35
+ const flag = input[index];
36
+ if (!String(flag || '').startsWith('--')) continue;
37
+
38
+ if (CHROME_DEVTOOLS_BOOLEAN_FLAGS.has(flag)) {
39
+ args.push(flag);
40
+ continue;
41
+ }
42
+
43
+ if (CHROME_DEVTOOLS_FLAGS_WITH_VALUES.has(flag)) {
44
+ const value = input[index + 1];
45
+ if (value === undefined || String(value).startsWith('--')) {
46
+ throw new Error(`Missing value for ${flag}`);
47
+ }
48
+ args.push(flag, String(value));
49
+ index += 1;
50
+ }
51
+ }
52
+
53
+ return args;
54
+ }
55
+
56
+ export function createChromeDevtoolsMcpServer(options = [], platform = process.platform, env = process.env) {
57
+ const npxArgs = buildChromeDevtoolsArgs(options);
58
+ const common = {
59
+ name: CHROME_DEVTOOLS_MCP_NAME,
60
+ enabled: true,
61
+ requestTimeoutMs: 60000,
62
+ metadata: {
63
+ preset: CHROME_DEVTOOLS_MCP_NAME,
64
+ source: CHROME_DEVTOOLS_SOURCE,
65
+ purpose: 'Chrome DevTools MCP for live browser automation, debugging, screenshots, console, network, and performance traces.',
66
+ },
67
+ };
68
+
69
+ if (platform === 'win32') {
70
+ return {
71
+ ...common,
72
+ command: 'cmd',
73
+ args: ['/c', 'npx', ...npxArgs],
74
+ env: {
75
+ SystemRoot: env.SystemRoot || 'C:\\Windows',
76
+ PROGRAMFILES: env.PROGRAMFILES || 'C:\\Program Files',
77
+ },
78
+ };
79
+ }
80
+
81
+ return {
82
+ ...common,
83
+ command: 'npx',
84
+ args: npxArgs,
85
+ };
86
+ }
87
+
88
+ export function getMcpPreset(name, options = []) {
89
+ if (isChromeDevtoolsPreset(name)) {
90
+ return createChromeDevtoolsMcpServer(options);
91
+ }
92
+ throw new Error(`Unknown MCP preset: ${name}`);
93
+ }
94
+
95
+ export function ensureMcpConfigShape(config = {}) {
96
+ config.mcp = config.mcp || { servers: [] };
97
+ config.mcp.servers = Array.isArray(config.mcp.servers) ? config.mcp.servers : [];
98
+ config.permissions = config.permissions || { allowlist: {} };
99
+ config.permissions.allowlist = config.permissions.allowlist || {};
100
+ config.permissions.allowlist.tools = config.permissions.allowlist.tools || [];
101
+ config.permissions.allowlist.commands = config.permissions.allowlist.commands || [];
102
+ config.permissions.allowlist.mcpServers = config.permissions.allowlist.mcpServers || [];
103
+ return config;
104
+ }
105
+
106
+ export function upsertMcpServer(config, server) {
107
+ ensureMcpConfigShape(config);
108
+ config.mcp.servers = config.mcp.servers.filter(item => item.name !== server.name);
109
+ config.mcp.servers.push(server);
110
+ config.permissions.allowlist.mcpServers = [
111
+ ...new Set([...(config.permissions.allowlist.mcpServers || []), server.name]),
112
+ ];
113
+ return config;
114
+ }