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.
- package/CHANGELOG.md +28 -5
- package/README.md +85 -0
- package/package.json +5 -1
- package/resources/local/gsap-skills/.claude-plugin/marketplace.json +20 -0
- package/resources/local/gsap-skills/.claude-plugin/plugin.json +6 -0
- package/resources/local/gsap-skills/.cursor-plugin/marketplace.json +13 -0
- package/resources/local/gsap-skills/.cursor-plugin/plugin.json +22 -0
- package/resources/local/gsap-skills/.github/copilot-instructions.md +17 -0
- package/resources/local/gsap-skills/.github/instructions/react.instructions.md +15 -0
- package/resources/local/gsap-skills/.github/instructions/scrolltrigger.instructions.md +18 -0
- package/resources/local/gsap-skills/AGENTS.md +27 -0
- package/resources/local/gsap-skills/CLAUDE.md +1 -0
- package/resources/local/gsap-skills/GEMINI.md +1 -0
- package/resources/local/gsap-skills/LICENSE +21 -0
- package/resources/local/gsap-skills/README.md +163 -0
- package/resources/local/gsap-skills/assets/gsap-green.svg +7 -0
- package/resources/local/gsap-skills/assets/gsap-icon-inverted.svg +15 -0
- package/resources/local/gsap-skills/assets/gsap-icon-square.svg +1 -0
- package/resources/local/gsap-skills/assets/gsap-white.svg +7 -0
- package/resources/local/gsap-skills/examples/README.md +29 -0
- package/resources/local/gsap-skills/examples/nuxt/app/app.vue +3 -0
- package/resources/local/gsap-skills/examples/nuxt/app/composables/useGSAP.ts +91 -0
- package/resources/local/gsap-skills/examples/nuxt/app/pages/index.vue +55 -0
- package/resources/local/gsap-skills/examples/nuxt/nuxt.config.ts +4 -0
- package/resources/local/gsap-skills/examples/nuxt/package.json +18 -0
- package/resources/local/gsap-skills/examples/react/App.jsx +46 -0
- package/resources/local/gsap-skills/examples/react/index.html +12 -0
- package/resources/local/gsap-skills/examples/react/main.jsx +9 -0
- package/resources/local/gsap-skills/examples/react/package.json +21 -0
- package/resources/local/gsap-skills/examples/react/vite.config.js +7 -0
- package/resources/local/gsap-skills/examples/vanilla/index.html +33 -0
- package/resources/local/gsap-skills/examples/vanilla/main.js +36 -0
- package/resources/local/gsap-skills/examples/vue/app.vue +47 -0
- package/resources/local/gsap-skills/examples/vue/index.html +15 -0
- package/resources/local/gsap-skills/examples/vue/main.js +9 -0
- package/resources/local/gsap-skills/examples/vue/package.json +19 -0
- package/resources/local/gsap-skills/examples/vue/vite.config.js +7 -0
- package/resources/local/gsap-skills/skills/gsap-core/SKILL.md +254 -0
- package/resources/local/gsap-skills/skills/gsap-frameworks/SKILL.md +266 -0
- package/resources/local/gsap-skills/skills/gsap-performance/SKILL.md +79 -0
- package/resources/local/gsap-skills/skills/gsap-plugins/SKILL.md +433 -0
- package/resources/local/gsap-skills/skills/gsap-react/SKILL.md +136 -0
- package/resources/local/gsap-skills/skills/gsap-scrolltrigger/SKILL.md +296 -0
- package/resources/local/gsap-skills/skills/gsap-timeline/SKILL.md +107 -0
- package/resources/local/gsap-skills/skills/gsap-utils/SKILL.md +284 -0
- package/resources/local/gsap-skills/skills/llms.txt +39 -0
- package/resources/local/hermes-agent-core/AGENTS.md +1132 -0
- package/resources/local/hermes-agent-core/LICENSE +21 -0
- package/resources/local/hermes-agent-core/README.md +215 -0
- package/resources/local/hermes-agent-core/docs/2026-05-07-s6-overlay-dynamic-subagent-gateways.md +434 -0
- package/resources/local/hermes-agent-core/hermes-already-has-routines.md +160 -0
- package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/DESCRIPTION.md +3 -0
- package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/claude-code/SKILL.md +745 -0
- package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/codex/SKILL.md +130 -0
- package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/hermes-agent/SKILL.md +1021 -0
- package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/kanban-codex-lane/SKILL.md +277 -0
- package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/kanban-codex-lane/templates/pmb-codex-lane-prompt.md +57 -0
- package/resources/local/hermes-agent-core/skills/autonomous-ai-agents/opencode/SKILL.md +219 -0
- package/resources/local/hermes-agent-core/skills/github/DESCRIPTION.md +3 -0
- package/resources/local/hermes-agent-core/skills/github/codebase-inspection/SKILL.md +116 -0
- package/resources/local/hermes-agent-core/skills/github/github-auth/SKILL.md +247 -0
- package/resources/local/hermes-agent-core/skills/github/github-auth/scripts/gh-env.sh +66 -0
- package/resources/local/hermes-agent-core/skills/github/github-code-review/SKILL.md +481 -0
- package/resources/local/hermes-agent-core/skills/github/github-code-review/references/review-output-template.md +74 -0
- package/resources/local/hermes-agent-core/skills/github/github-issues/SKILL.md +370 -0
- package/resources/local/hermes-agent-core/skills/github/github-issues/templates/bug-report.md +35 -0
- package/resources/local/hermes-agent-core/skills/github/github-issues/templates/feature-request.md +31 -0
- package/resources/local/hermes-agent-core/skills/github/github-pr-workflow/SKILL.md +367 -0
- package/resources/local/hermes-agent-core/skills/github/github-pr-workflow/references/ci-troubleshooting.md +183 -0
- package/resources/local/hermes-agent-core/skills/github/github-pr-workflow/references/conventional-commits.md +71 -0
- package/resources/local/hermes-agent-core/skills/github/github-pr-workflow/templates/pr-body-bugfix.md +35 -0
- package/resources/local/hermes-agent-core/skills/github/github-pr-workflow/templates/pr-body-feature.md +33 -0
- package/resources/local/hermes-agent-core/skills/github/github-repo-management/SKILL.md +516 -0
- package/resources/local/hermes-agent-core/skills/github/github-repo-management/references/github-api-cheatsheet.md +161 -0
- package/resources/local/hermes-agent-core/skills/mcp/DESCRIPTION.md +3 -0
- package/resources/local/hermes-agent-core/skills/mcp/native-mcp/SKILL.md +357 -0
- package/resources/local/hermes-agent-core/skills/software-development/debugging-hermes-tui-commands/SKILL.md +152 -0
- package/resources/local/hermes-agent-core/skills/software-development/hermes-agent-skill-authoring/SKILL.md +165 -0
- package/resources/local/hermes-agent-core/skills/software-development/hermes-s6-container-supervision/SKILL.md +176 -0
- package/resources/local/hermes-agent-core/skills/software-development/node-inspect-debugger/SKILL.md +319 -0
- package/resources/local/hermes-agent-core/skills/software-development/plan/SKILL.md +58 -0
- package/resources/local/hermes-agent-core/skills/software-development/python-debugpy/SKILL.md +375 -0
- package/resources/local/hermes-agent-core/skills/software-development/requesting-code-review/SKILL.md +280 -0
- package/resources/local/hermes-agent-core/skills/software-development/spike/SKILL.md +197 -0
- package/resources/local/hermes-agent-core/skills/software-development/subagent-driven-development/SKILL.md +352 -0
- package/resources/local/hermes-agent-core/skills/software-development/subagent-driven-development/references/context-budget-discipline.md +53 -0
- package/resources/local/hermes-agent-core/skills/software-development/subagent-driven-development/references/gates-taxonomy.md +93 -0
- package/resources/local/hermes-agent-core/skills/software-development/systematic-debugging/SKILL.md +367 -0
- package/resources/local/hermes-agent-core/skills/software-development/test-driven-development/SKILL.md +343 -0
- package/resources/local/hermes-agent-core/skills/software-development/writing-plans/SKILL.md +297 -0
- package/resources/local/manifest.json +12 -0
- package/rule.md +2 -0
- package/scripts/audit-pack.js +5 -0
- package/scripts/smoke-browser.js +53 -0
- package/scripts/smoke-package.js +38 -4
- package/skill.md +36 -4
- package/skills/gsap.md +26 -0
- package/skills/hermes-agent.md +17 -0
- package/src/agent/agent-definitions.js +4 -4
- package/src/agent/runtime.js +179 -5
- package/src/agent/subagent-child.js +44 -0
- package/src/ai/capability-scorecard.js +193 -14
- package/src/ai/hermes-core.js +77 -0
- package/src/ai/model-capabilities.js +42 -2
- package/src/ai/prompts/system-prompt.js +18 -2
- package/src/ai/small-model-amplifier.js +35 -7
- package/src/ai/workflow-selector.js +22 -1
- package/src/cli/commands.js +46 -2
- package/src/cli/config.js +45 -6
- package/src/cli/context-loader.js +253 -9
- package/src/cli/conversation-format.js +5 -0
- package/src/cli/input-controller.js +79 -10
- package/src/cli/prompt-builder.js +47 -8
- package/src/cli/repl-commands.js +115 -0
- package/src/cli/repl.js +343 -85
- package/src/cli/slash-commands.js +4 -2
- package/src/cli/tui.js +133 -37
- package/src/mcp/client.js +54 -11
- package/src/mcp/presets.js +114 -0
- package/src/tools/agent.js +316 -25
- package/src/tools/executor.js +412 -12
- package/src/tools/permission.js +20 -17
- 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
|
|
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}
|
|
43
|
-
status: `${c.bright}${c.cyan}WINTER${c.reset} ${c.dim}
|
|
44
|
-
hint: `${c.dim}@file${c.reset} attach
|
|
45
|
-
prompt: `${c.bright}${c.green}winter${c.reset} ${c.dim}
|
|
46
|
-
bottom: `${c.dim}
|
|
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
|
|
64
|
-
const
|
|
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
|
|
149
|
+
`${white}Winter dashboard${reset} ${dim}Hermes-style agent core: skills, memory, tools, subagents, gateway discipline.${reset}`,
|
|
72
150
|
'',
|
|
73
|
-
|
|
151
|
+
statusBar,
|
|
74
152
|
'',
|
|
75
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
109
|
-
`${c.brightGreen}
|
|
110
|
-
`${c.brightGreen}
|
|
111
|
-
`${c.brightGreen}
|
|
112
|
-
`${c.brightGreen}
|
|
113
|
-
`${c.brightGreen}
|
|
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
|
|
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}
|
|
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}
|
|
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}
|
|
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
|
|
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
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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
|
+
}
|