winter-super-cli 2026.6.26 → 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 +66 -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 +16 -2
- package/src/ai/small-model-amplifier.js +35 -7
- package/src/ai/workflow-selector.js +22 -1
- package/src/cli/commands.js +21 -1
- package/src/cli/config.js +42 -4
- 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 +45 -8
- package/src/cli/repl-commands.js +115 -0
- package/src/cli/repl.js +147 -86
- package/src/cli/slash-commands.js +3 -1
- package/src/cli/tui.js +133 -37
- package/src/mcp/client.js +46 -5
- package/src/tools/agent.js +316 -25
- package/src/tools/executor.js +310 -9
- package/src/tools/permission.js +20 -17
- package/winter.d.ts +112 -10
package/src/cli/repl.js
CHANGED
|
@@ -427,6 +427,7 @@ export class WinterREPL {
|
|
|
427
427
|
const shouldDrop = (entry) => {
|
|
428
428
|
const text = typeof entry === 'string' ? entry : entry?.text || '';
|
|
429
429
|
return text.startsWith('[Required local resources]')
|
|
430
|
+
|| text.startsWith('[Auto-loaded resource application profile]')
|
|
430
431
|
|| text.startsWith('[Auto-applied skills]')
|
|
431
432
|
|| text.startsWith('[Project rule file')
|
|
432
433
|
|| text.startsWith('[Startup local resource index]')
|
|
@@ -442,7 +443,11 @@ export class WinterREPL {
|
|
|
442
443
|
`awesome-design-md: ${resourcePaths.designs}`,
|
|
443
444
|
`karpathy-tools: ${resourcePaths.karpathy}`,
|
|
444
445
|
`page-agent: ${resourcePaths.pageAgent}`,
|
|
446
|
+
`hermes-agent-core: ${resourcePaths.hermesAgentCore}`,
|
|
447
|
+
`gsap-skills: ${resourcePaths.gsapSkills}`,
|
|
445
448
|
`ecc: ${resourcePaths.ecc}`,
|
|
449
|
+
`codex: ${resourcePaths.codex.root}`,
|
|
450
|
+
`claude: ${resourcePaths.claude.root}`,
|
|
446
451
|
];
|
|
447
452
|
await this.session.replaceMemory(
|
|
448
453
|
'[Startup local resource index]',
|
|
@@ -671,8 +676,8 @@ export class WinterREPL {
|
|
|
671
676
|
}
|
|
672
677
|
}
|
|
673
678
|
|
|
674
|
-
await this.bootstrapProjectCapabilities();
|
|
675
679
|
await this.compactStartupMemories({ projectInstructionFiles, autoCreateDocs });
|
|
680
|
+
await this.bootstrapProjectCapabilities();
|
|
676
681
|
|
|
677
682
|
// Codebase Index is intentionally lazy/on-demand. Top-tier coding agents do
|
|
678
683
|
// not make first-run chat pay for a repo-wide scan, and this also prevents
|
|
@@ -718,6 +723,7 @@ export class WinterREPL {
|
|
|
718
723
|
this._pasteTimer = null;
|
|
719
724
|
this._isPasteChunk = false;
|
|
720
725
|
this._pasteChunkTimer = null;
|
|
726
|
+
this._pasteCounter = 0;
|
|
721
727
|
const PASTE_DELAY = 80;
|
|
722
728
|
|
|
723
729
|
process.stdin.on('data', (chunk) => {
|
|
@@ -736,7 +742,7 @@ export class WinterREPL {
|
|
|
736
742
|
}
|
|
737
743
|
});
|
|
738
744
|
|
|
739
|
-
const flushPasteBuffer = () => {
|
|
745
|
+
const flushPasteBuffer = async () => {
|
|
740
746
|
this._pasteTimer = null;
|
|
741
747
|
if (this._pasteBuffer.length === 0) return;
|
|
742
748
|
|
|
@@ -772,6 +778,19 @@ export class WinterREPL {
|
|
|
772
778
|
this._multilineBuffer.push(...this._pasteBuffer);
|
|
773
779
|
this._pasteBuffer = [];
|
|
774
780
|
|
|
781
|
+
if (this.shouldAutoPersistBufferedPaste(this._multilineBuffer, { isPasteChunk: this._isPasteChunk })) {
|
|
782
|
+
const pastedText = this._multilineBuffer.join('\n').trimEnd();
|
|
783
|
+
if (this.shouldPersistPastedText(pastedText)) {
|
|
784
|
+
const paste = await this.persistPastedText(pastedText);
|
|
785
|
+
this._multilineBuffer = [];
|
|
786
|
+
this._isPasteChunk = false;
|
|
787
|
+
const reference = this.formatPastedTextReference(paste);
|
|
788
|
+
console.log(`${colors.cyan}│ ${colors.dim}${reference}${colors.reset}`);
|
|
789
|
+
this.submitInputQueue(reference);
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
775
794
|
// If they pressed Enter on an empty line, submit the multiline buffer!
|
|
776
795
|
if (isJustEmptyEnter && this._multilineBuffer.length > 1) {
|
|
777
796
|
// Remove the trailing empty line
|
|
@@ -788,6 +807,14 @@ export class WinterREPL {
|
|
|
788
807
|
return;
|
|
789
808
|
}
|
|
790
809
|
|
|
810
|
+
if (this.shouldPersistPastedText(combined)) {
|
|
811
|
+
const paste = await this.persistPastedText(combined);
|
|
812
|
+
const reference = this.formatPastedTextReference(paste);
|
|
813
|
+
console.log(`${colors.cyan}│ ${colors.dim}${reference}${colors.reset}`);
|
|
814
|
+
this.submitInputQueue(reference);
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
|
|
791
818
|
this.submitInputQueue(combined);
|
|
792
819
|
return;
|
|
793
820
|
}
|
|
@@ -816,7 +843,14 @@ export class WinterREPL {
|
|
|
816
843
|
this.rl.on('line', (line) => {
|
|
817
844
|
this._pasteBuffer.push(line);
|
|
818
845
|
if (this._pasteTimer) clearTimeout(this._pasteTimer);
|
|
819
|
-
this._pasteTimer = setTimeout(
|
|
846
|
+
this._pasteTimer = setTimeout(() => {
|
|
847
|
+
void flushPasteBuffer().catch((error) => {
|
|
848
|
+
this._pasteBuffer = [];
|
|
849
|
+
this._multilineBuffer = [];
|
|
850
|
+
console.log(`\n${colors.red}? Paste error: ${error.message}${colors.reset}\n`);
|
|
851
|
+
if (this.running && !this.readlineClosed) this.showInputPrompt();
|
|
852
|
+
});
|
|
853
|
+
}, PASTE_DELAY);
|
|
820
854
|
});
|
|
821
855
|
|
|
822
856
|
this.rl.on('close', async () => {
|
|
@@ -863,6 +897,55 @@ export class WinterREPL {
|
|
|
863
897
|
return this.inputController.handleDirectClipboardPaste();
|
|
864
898
|
}
|
|
865
899
|
|
|
900
|
+
getPasteStorageDir() {
|
|
901
|
+
return path.join(this.config?.winterDir || path.join(homedir(), '.winter'), 'pastes');
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
normalizePastedText(text = '') {
|
|
905
|
+
return String(text || '')
|
|
906
|
+
.replace(/\x1b\[200~/g, '')
|
|
907
|
+
.replace(/\x1b\[201~/g, '')
|
|
908
|
+
.replace(/\r\n/g, '\n')
|
|
909
|
+
.replace(/\r/g, '\n');
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
getPastedTextLineCount(text = '') {
|
|
913
|
+
const value = this.normalizePastedText(text);
|
|
914
|
+
if (!value) return 0;
|
|
915
|
+
return value.split(/\r\n|\r|\n/).length;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
shouldPersistPastedText(text = '', { minLines = 8, minChars = 4000 } = {}) {
|
|
919
|
+
const value = this.normalizePastedText(text);
|
|
920
|
+
return this.getPastedTextLineCount(value) >= minLines || value.length >= minChars;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
shouldAutoPersistBufferedPaste(buffer = [], { isPasteChunk = false } = {}) {
|
|
924
|
+
if (!Array.isArray(buffer) || buffer.length === 0) return false;
|
|
925
|
+
const manualMultiline = buffer[0] === '';
|
|
926
|
+
const text = this.normalizePastedText(buffer.join('\n')).trimEnd();
|
|
927
|
+
return Boolean(text) && this.shouldPersistPastedText(text) && (isPasteChunk || !manualMultiline);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
async persistPastedText(text = '') {
|
|
931
|
+
const content = this.normalizePastedText(text);
|
|
932
|
+
const dir = this.getPasteStorageDir();
|
|
933
|
+
await fs.mkdir(dir, { recursive: true });
|
|
934
|
+
this._pasteCounter = Number(this._pasteCounter || 0) + 1;
|
|
935
|
+
const filePath = path.join(dir, `paste_${this._pasteCounter}_${Date.now()}.txt`);
|
|
936
|
+
await fs.writeFile(filePath, content, 'utf8');
|
|
937
|
+
return {
|
|
938
|
+
index: this._pasteCounter,
|
|
939
|
+
path: filePath,
|
|
940
|
+
lines: this.getPastedTextLineCount(content),
|
|
941
|
+
chars: content.length,
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
formatPastedTextReference(paste = {}) {
|
|
946
|
+
return `[Pasted text #${paste.index || 1}: ${paste.lines || 0} lines -> ${paste.path}]`;
|
|
947
|
+
}
|
|
948
|
+
|
|
866
949
|
buildInputPanel() {
|
|
867
950
|
return this.inputController.buildInputPanel();
|
|
868
951
|
}
|
|
@@ -1744,14 +1827,14 @@ ${colors.reset}
|
|
|
1744
1827
|
case 'review':
|
|
1745
1828
|
return byName(['Read', 'Grep', 'Glob', 'Bash', 'WebFetch']);
|
|
1746
1829
|
case 'debug':
|
|
1747
|
-
return byName(['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob', 'OpenBrowser', 'BrowserDebug', 'WebFetch', 'MCP', 'Parallel']);
|
|
1830
|
+
return byName(['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob', 'OpenBrowser', 'VisibleBrowser', 'BrowserDebug', 'WebFetch', 'MCP', 'Parallel']);
|
|
1748
1831
|
case 'research':
|
|
1749
1832
|
return byName(['Read', 'Grep', 'Glob', 'WebFetch', 'WebSearch', 'Parallel']);
|
|
1750
1833
|
case 'design':
|
|
1751
1834
|
case 'ui':
|
|
1752
|
-
return byName(['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob', 'OpenBrowser', 'BrowserDebug', 'WebFetch', 'MCP']);
|
|
1835
|
+
return byName(['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob', 'OpenBrowser', 'VisibleBrowser', 'BrowserDebug', 'WebFetch', 'MCP']);
|
|
1753
1836
|
default:
|
|
1754
|
-
return byName(['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep', 'OpenBrowser', 'BrowserDebug', 'WebFetch', 'WebSearch', 'MCP', 'Parallel', 'Agent']);
|
|
1837
|
+
return byName(['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep', 'OpenBrowser', 'VisibleBrowser', 'BrowserDebug', 'WebFetch', 'WebSearch', 'MCP', 'Parallel', 'Agent', 'DelegateTask', 'ParallelAgent']);
|
|
1755
1838
|
}
|
|
1756
1839
|
}
|
|
1757
1840
|
|
|
@@ -1944,7 +2027,7 @@ ${colors.reset}
|
|
|
1944
2027
|
'For browser interaction tasks you MUST use tools, not prose:',
|
|
1945
2028
|
'1. If chrome-devtools MCP is configured, call MCP {"server":"chrome-devtools","tool":"list"} first if needed.',
|
|
1946
2029
|
'2. Use chrome-devtools MCP tools such as new_page/navigate_page, take_snapshot, click, fill/fill_form, evaluate_script, list_network_requests, and take_screenshot in visible Chrome.',
|
|
1947
|
-
'3. Use WebFetch only for static text extraction. WebFetch cannot click buttons, fill forms, or preserve page state. BrowserDebug is headless and should be fallback only.',
|
|
2030
|
+
'3. Use WebFetch only for static text extraction. WebFetch cannot click buttons, fill forms, or preserve page state. Use VisibleBrowser when MCP is unavailable and the user needs visible browser control. BrowserDebug is headless and should be fallback only.',
|
|
1948
2031
|
'4. Do not say "đã bấm", "đã điền", "đã mở", or "đã kiểm tra" until a browser/MCP tool result proves it.',
|
|
1949
2032
|
'',
|
|
1950
2033
|
`Original user request: ${request}`,
|
|
@@ -1962,7 +2045,7 @@ ${colors.reset}
|
|
|
1962
2045
|
'DO NOT say "I have updated/created/fixed" without a tool call proving it.',
|
|
1963
2046
|
'DO NOT describe what you would do. Actually DO IT with tool calls.',
|
|
1964
2047
|
'',
|
|
1965
|
-
'Available tools: Read, Write, Edit, Bash, Glob, Grep, OpenBrowser, BrowserDebug, WebFetch, WebSearch, MCP.',
|
|
2048
|
+
'Available tools: Read, Write, Edit, Bash, Glob, Grep, OpenBrowser, VisibleBrowser, BrowserDebug, WebFetch, WebSearch, MCP.',
|
|
1966
2049
|
'',
|
|
1967
2050
|
'If native tool calls are not supported, output exactly one fallback tool call:',
|
|
1968
2051
|
'<invoke name="Read"><parameter name="path">README.md</parameter></invoke>',
|
|
@@ -1985,7 +2068,7 @@ ${colors.reset}
|
|
|
1985
2068
|
const hints = [];
|
|
1986
2069
|
|
|
1987
2070
|
if (/\b(click|fill|submit|press|select|navigate|bam|dien|chon|nhan|vao|bấm|điền|chọn|nhấn|vào)\b/i.test(text) && /\b(web|website|page|url|http|chrome|browser|form|button|link|trang|nut|nút|dang ky|dang nhap|khach hang|đăng ký|đăng nhập|khách hàng)\b/i.test(text)) {
|
|
1988
|
-
hints.push('TOOL HINT: This is a live browser interaction. Do NOT use WebFetch alone. Prefer visible Chrome via MCP {"server":"chrome-devtools","tool":"list"} then chrome-devtools tools new_page/navigate_page, take_snapshot, click, fill/fill_form, evaluate_script, list_network_requests, and take_screenshot. Only use BrowserDebug as headless fallback. Only claim click/fill/navigation after MCP or BrowserDebug evidence.');
|
|
2071
|
+
hints.push('TOOL HINT: This is a live browser interaction. Do NOT use WebFetch alone. Prefer visible Chrome via MCP {"server":"chrome-devtools","tool":"list"} then chrome-devtools tools new_page/navigate_page, take_snapshot, click, fill/fill_form, evaluate_script, list_network_requests, and take_screenshot. If MCP is unavailable, call VisibleBrowser for real visible Puppeteer control. Only use BrowserDebug as headless fallback. Only claim click/fill/navigation after MCP, VisibleBrowser, or BrowserDebug evidence.');
|
|
1989
2072
|
}
|
|
1990
2073
|
|
|
1991
2074
|
// Detect file reading requests
|
|
@@ -2108,6 +2191,9 @@ ${colors.reset}
|
|
|
2108
2191
|
if ((options?.requireToolEvidence && this.responseNeedsToolEvidence(assistantMsg.content)) || isFakeCompletion) {
|
|
2109
2192
|
return { assistantMsg, toolCalls, finalContent: '', finishReason: 'tool_evidence_required' };
|
|
2110
2193
|
}
|
|
2194
|
+
if (options?.deferFinalContent) {
|
|
2195
|
+
return { assistantMsg, toolCalls, finalContent: assistantMsg.content, finishReason };
|
|
2196
|
+
}
|
|
2111
2197
|
this.printAssistantAnswer(assistantMsg.content, startedAt, totalUsage);
|
|
2112
2198
|
return { assistantMsg, toolCalls, finalContent: assistantMsg.content, finishReason };
|
|
2113
2199
|
}
|
|
@@ -2122,7 +2208,7 @@ ${colors.reset}
|
|
|
2122
2208
|
const toolCallParts = [];
|
|
2123
2209
|
let finishReason = null;
|
|
2124
2210
|
let printed = false;
|
|
2125
|
-
const bufferToolModeContent =
|
|
2211
|
+
const bufferToolModeContent = false;
|
|
2126
2212
|
|
|
2127
2213
|
for await (const chunk of this.ai.streamRequest(messages, options)) {
|
|
2128
2214
|
if (chunk.usage) this.addUsage(totalUsage, chunk.usage);
|
|
@@ -2239,6 +2325,14 @@ ${colors.reset}
|
|
|
2239
2325
|
finishReason: 'tool_evidence_required',
|
|
2240
2326
|
};
|
|
2241
2327
|
}
|
|
2328
|
+
if (options?.deferFinalContent) {
|
|
2329
|
+
return {
|
|
2330
|
+
assistantMsg: { content: visibleContent },
|
|
2331
|
+
toolCalls,
|
|
2332
|
+
finalContent: visibleContent,
|
|
2333
|
+
finishReason,
|
|
2334
|
+
};
|
|
2335
|
+
}
|
|
2242
2336
|
this.printAssistantAnswer(visibleContent, startedAt, totalUsage);
|
|
2243
2337
|
return {
|
|
2244
2338
|
assistantMsg: { content: visibleContent },
|
|
@@ -2275,7 +2369,7 @@ ${colors.reset}
|
|
|
2275
2369
|
'/provider', '/model', '/models', '/providers',
|
|
2276
2370
|
'/theme:toggle', '/tui',
|
|
2277
2371
|
'/auto', '/debug', '/doctor', '/context', '/scorecard', '/swe',
|
|
2278
|
-
'/read', '/write', '/glob', '/grep', '/bash',
|
|
2372
|
+
'/read', '/write', '/glob', '/grep', '/bash', '/browser', '/paste',
|
|
2279
2373
|
'/codex', '/claude', '/karpathy', '/agents',
|
|
2280
2374
|
'/resources', '/designs', '/skills',
|
|
2281
2375
|
'/ecc',
|
|
@@ -2374,7 +2468,7 @@ ${colors.reset}
|
|
|
2374
2468
|
const executionProfile = this.selectExecutionProfile(messages, { enableTools: false });
|
|
2375
2469
|
const latestUserText = this.getLatestUserText(messages);
|
|
2376
2470
|
const browserInteraction = this.isBrowserInteractionRequest(latestUserText);
|
|
2377
|
-
const hasBrowserEvidence = toolSummaries.some(summary => /^(MCP|BrowserDebug|OpenBrowser):/i.test(summary));
|
|
2471
|
+
const hasBrowserEvidence = toolSummaries.some(summary => /^(MCP|VisibleBrowser|BrowserDebug|OpenBrowser):/i.test(summary));
|
|
2378
2472
|
const finalMessages = [
|
|
2379
2473
|
...messages,
|
|
2380
2474
|
{
|
|
@@ -2387,7 +2481,7 @@ ${colors.reset}
|
|
|
2387
2481
|
'Start with the actual outcome, then mention only the most relevant files/commands. Avoid broad generic advice.',
|
|
2388
2482
|
'If a tool failed, explain the concrete failure briefly and answer with the available evidence.',
|
|
2389
2483
|
'Do not repeat the plan. Do not re-summarize unrelated project context. Do not claim memory/tool state that is not visible in the transcript.',
|
|
2390
|
-
browserInteraction && !hasBrowserEvidence ? 'Important: The user asked for browser interaction, but no MCP/BrowserDebug/OpenBrowser result is available. You must say the browser action was NOT performed; do not claim you clicked, filled, navigated, or inspected pages.' : '',
|
|
2484
|
+
browserInteraction && !hasBrowserEvidence ? 'Important: The user asked for browser interaction, but no MCP/VisibleBrowser/BrowserDebug/OpenBrowser result is available. You must say the browser action was NOT performed; do not claim you clicked, filled, navigated, or inspected pages.' : '',
|
|
2391
2485
|
toolSummaries.length ? `Tool summary:\n${toolSummaries.join('\n')}` : '',
|
|
2392
2486
|
].filter(Boolean).join('\n'),
|
|
2393
2487
|
},
|
|
@@ -2412,7 +2506,7 @@ ${colors.reset}
|
|
|
2412
2506
|
this.addUsage(totalUsage, response.usage);
|
|
2413
2507
|
let content = response.choices?.[0]?.message?.content || '';
|
|
2414
2508
|
if (browserInteraction && !hasBrowserEvidence && this.detectFakeCompletion(content)) {
|
|
2415
|
-
content = 'Chưa thực hiện được thao tác trên trình duyệt: lượt này không có bằng chứng từ MCP/BrowserDebug/OpenBrowser, nên Winter chặn câu trả lời để tránh báo sai. Hãy bật chrome-devtools MCP hoặc dùng
|
|
2509
|
+
content = 'Chưa thực hiện được thao tác trên trình duyệt: lượt này không có bằng chứng từ MCP/VisibleBrowser/BrowserDebug/OpenBrowser, nên Winter chặn câu trả lời để tránh báo sai. Hãy bật chrome-devtools MCP hoặc dùng VisibleBrowser để Winter gọi đúng browser tool.';
|
|
2416
2510
|
}
|
|
2417
2511
|
|
|
2418
2512
|
if (this.spinner) this.spinner.stop();
|
|
@@ -2457,7 +2551,7 @@ ${colors.reset}
|
|
|
2457
2551
|
if (this.spinner) this.spinner.stop();
|
|
2458
2552
|
|
|
2459
2553
|
if (validation.browserInteraction && !validation.hasBrowserEvidence && this.detectFakeCompletion(content)) {
|
|
2460
|
-
content = 'Chưa thực hiện được thao tác trên trình duyệt: lượt này không có bằng chứng từ MCP/BrowserDebug/OpenBrowser, nên Winter chặn câu trả lời để tránh báo sai. Hãy bật chrome-devtools MCP hoặc dùng
|
|
2554
|
+
content = 'Chưa thực hiện được thao tác trên trình duyệt: lượt này không có bằng chứng từ MCP/VisibleBrowser/BrowserDebug/OpenBrowser, nên Winter chặn câu trả lời để tránh báo sai. Hãy bật chrome-devtools MCP hoặc dùng VisibleBrowser để Winter gọi đúng browser tool.';
|
|
2461
2555
|
}
|
|
2462
2556
|
|
|
2463
2557
|
if (content) {
|
|
@@ -2481,7 +2575,7 @@ ${colors.reset}
|
|
|
2481
2575
|
this.addUsage(totalUsage, response.usage);
|
|
2482
2576
|
content = response.choices?.[0]?.message?.content || '';
|
|
2483
2577
|
if (validation.browserInteraction && !validation.hasBrowserEvidence && this.detectFakeCompletion(content)) {
|
|
2484
|
-
content = 'Chưa thực hiện được thao tác trên trình duyệt: lượt này không có bằng chứng từ MCP/BrowserDebug/OpenBrowser, nên Winter chặn câu trả lời để tránh báo sai. Hãy bật chrome-devtools MCP hoặc dùng
|
|
2578
|
+
content = 'Chưa thực hiện được thao tác trên trình duyệt: lượt này không có bằng chứng từ MCP/VisibleBrowser/BrowserDebug/OpenBrowser, nên Winter chặn câu trả lời để tránh báo sai. Hãy bật chrome-devtools MCP hoặc dùng VisibleBrowser để Winter gọi đúng browser tool.';
|
|
2485
2579
|
}
|
|
2486
2580
|
if (content) {
|
|
2487
2581
|
this.printAssistantAnswer(content, startedAt, totalUsage);
|
|
@@ -2889,7 +2983,7 @@ ${colors.reset}
|
|
|
2889
2983
|
messages.push({ role: 'system', content: toolHint });
|
|
2890
2984
|
}
|
|
2891
2985
|
|
|
2892
|
-
const { finalContent, usedMutatingTools } = await this.runConversation(messages, 'Thinking', tools);
|
|
2986
|
+
const { finalContent, usedMutatingTools, autoVerified } = await this.runConversation(messages, 'Thinking', tools);
|
|
2893
2987
|
|
|
2894
2988
|
const allToolCalls = [];
|
|
2895
2989
|
for (const msg of messages) {
|
|
@@ -2914,7 +3008,7 @@ ${colors.reset}
|
|
|
2914
3008
|
});
|
|
2915
3009
|
|
|
2916
3010
|
// Tự động verify: nếu AI đã dùng tools (sửa code), chạy test/build.
|
|
2917
|
-
if (finalContent && this.shouldAutoVerifyAfterTools(message, usedMutatingTools)) {
|
|
3011
|
+
if (!autoVerified && finalContent && this.shouldAutoVerifyAfterTools(message, usedMutatingTools)) {
|
|
2918
3012
|
const sessionContext = this.session?.getContext?.() || {};
|
|
2919
3013
|
const profile = String(sessionContext.workflowProfile || 'general');
|
|
2920
3014
|
const amplifier = sessionContext.smallModelAmplifier || {};
|
|
@@ -2965,7 +3059,7 @@ ${colors.reset}
|
|
|
2965
3059
|
].filter(Boolean).join('\n');
|
|
2966
3060
|
|
|
2967
3061
|
const amplifier = buildSmallModelAmplification({
|
|
2968
|
-
modelTier: this.
|
|
3062
|
+
modelTier: this.getActiveModelTier(),
|
|
2969
3063
|
workflowProfile: workflow.profile,
|
|
2970
3064
|
depth: workflow.depth,
|
|
2971
3065
|
});
|
|
@@ -3115,35 +3209,10 @@ Do NOT stop until all errors are resolved.`;
|
|
|
3115
3209
|
}
|
|
3116
3210
|
|
|
3117
3211
|
async runAgent(role, task) {
|
|
3118
|
-
const
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
];
|
|
3123
|
-
|
|
3124
|
-
const promptHistory = this.getCompressedPromptHistory({
|
|
3125
|
-
limit: 40,
|
|
3126
|
-
keepRecent: 16,
|
|
3127
|
-
maxTotalChars: 16000,
|
|
3128
|
-
});
|
|
3129
|
-
if (promptHistory.summary) {
|
|
3130
|
-
messages.push({ role: 'system', content: `Compressed prior conversation:\n${promptHistory.summary}` });
|
|
3131
|
-
}
|
|
3132
|
-
for (const entry of promptHistory.entries) {
|
|
3133
|
-
messages.push({ role: entry.role, content: entry.content });
|
|
3134
|
-
}
|
|
3135
|
-
|
|
3136
|
-
messages.push({ role: 'user', content: `Task: ${task}` });
|
|
3137
|
-
|
|
3138
|
-
const agentTools = this.getAgentToolsForDefinition(agentDefinition);
|
|
3139
|
-
const { finalContent, usedMutatingTools } = await this.runConversation(messages, `Subagent [${agentDefinition.id}]`, agentTools);
|
|
3140
|
-
|
|
3141
|
-
await this.session.addToHistory({ role: 'user', content: `[subagent:${agentDefinition.id}] ${task}` });
|
|
3142
|
-
await this.session.addToHistory({ role: 'assistant', content: finalContent });
|
|
3143
|
-
|
|
3144
|
-
if (finalContent && this.shouldAutoVerifyAfterTools(task, usedMutatingTools)) {
|
|
3145
|
-
await this.verifyAndHeal(messages, agentTools, 2);
|
|
3146
|
-
}
|
|
3212
|
+
const result = await this.tools.agentTool.run(task, { role: role || 'general' });
|
|
3213
|
+
await this.session.addToHistory({ role: 'user', content: `[subagent:${result.role || role || 'general'}] ${task}` });
|
|
3214
|
+
await this.session.addToHistory({ role: 'assistant', content: result.finalContent || result.summary || result.error || '' });
|
|
3215
|
+
return result;
|
|
3147
3216
|
}
|
|
3148
3217
|
|
|
3149
3218
|
async listAgentDefinitions() {
|
|
@@ -3420,6 +3489,14 @@ Light mode enabled for safety. Heavy codebase, graph, and git context are skippe
|
|
|
3420
3489
|
await this.session.replaceMemory('[Required local resources]', requiredLocalResources, 'resource');
|
|
3421
3490
|
}
|
|
3422
3491
|
|
|
3492
|
+
const projectInstructionFiles = await this.readProjectInstructionFiles();
|
|
3493
|
+
const resourceApplicationProfile = await this.contextLoader.getResourceApplicationProfile({ projectInstructionFiles });
|
|
3494
|
+
if (resourceApplicationProfile) {
|
|
3495
|
+
await this.session.updateContext('resourceApplicationProfile', resourceApplicationProfile);
|
|
3496
|
+
await this.session.replaceMemory('[Auto-loaded resource application profile]', resourceApplicationProfile, 'resource');
|
|
3497
|
+
this.startupNotice('resource profile loaded');
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3423
3500
|
const skillSnapshot = await this.inferStartupSkills();
|
|
3424
3501
|
await this.session.updateContext('availableSkillCatalog', skillSnapshot.availableSkills);
|
|
3425
3502
|
await this.session.updateContext('activeSkills', skillSnapshot.activeSkills);
|
|
@@ -3431,43 +3508,7 @@ Light mode enabled for safety. Heavy codebase, graph, and git context are skippe
|
|
|
3431
3508
|
}
|
|
3432
3509
|
|
|
3433
3510
|
async inferStartupSkills() {
|
|
3434
|
-
|
|
3435
|
-
const signals = await this.getProjectSignals();
|
|
3436
|
-
const normalizedSignals = new Set(signals.map(value => value.toLowerCase()));
|
|
3437
|
-
|
|
3438
|
-
const hasAny = (...items) => items.some(item => normalizedSignals.has(item));
|
|
3439
|
-
const activeSkills = new Set([
|
|
3440
|
-
'coding',
|
|
3441
|
-
'debug',
|
|
3442
|
-
'refactor',
|
|
3443
|
-
'test',
|
|
3444
|
-
]);
|
|
3445
|
-
|
|
3446
|
-
if (hasAny('react', 'next', 'nextjs', 'tsx', 'jsx', 'vue', 'svelte', 'vite')) {
|
|
3447
|
-
['vercel-react-best-practices', 'web-design-guidelines', 'frontend-design', 'design'].forEach(skill => activeSkills.add(skill));
|
|
3448
|
-
}
|
|
3449
|
-
|
|
3450
|
-
if (hasAny('design', 'ui', 'ux', 'css', 'tailwind', 'styled-components', 'scss', 'style', 'component')) {
|
|
3451
|
-
['web-design-guidelines', 'frontend-design', 'design'].forEach(skill => activeSkills.add(skill));
|
|
3452
|
-
}
|
|
3453
|
-
|
|
3454
|
-
if (hasAny('claude', 'agent', 'mcp', 'plugin', 'skill', 'automation', 'workflow')) {
|
|
3455
|
-
['skill-creator', 'claude-automation-recommender', 'claude-md-improver', 'agent-development', 'hook-development', 'command-development', 'plugin-dev'].forEach(skill => activeSkills.add(skill));
|
|
3456
|
-
}
|
|
3457
|
-
|
|
3458
|
-
if (hasAny('docs', 'markdown', 'md', 'readme', 'documentation')) {
|
|
3459
|
-
['claude-md-improver', 'docs', 'writing-rules'].forEach(skill => activeSkills.add(skill));
|
|
3460
|
-
}
|
|
3461
|
-
|
|
3462
|
-
if (hasAny('figma', 'design-md', 'brand', 'brand-guidelines', 'style-guide')) {
|
|
3463
|
-
['vibefigma', 'web-design-guidelines'].forEach(skill => activeSkills.add(skill));
|
|
3464
|
-
}
|
|
3465
|
-
|
|
3466
|
-
const filtered = [...activeSkills].filter(skill => catalog.has(skill));
|
|
3467
|
-
return {
|
|
3468
|
-
availableSkills: [...catalog],
|
|
3469
|
-
activeSkills: filtered,
|
|
3470
|
-
};
|
|
3511
|
+
return this.contextLoader.inferStartupSkills();
|
|
3471
3512
|
}
|
|
3472
3513
|
|
|
3473
3514
|
async getStartupSkillCatalog() {
|
|
@@ -3647,6 +3688,9 @@ Light mode enabled for safety. Heavy codebase, graph, and git context are skippe
|
|
|
3647
3688
|
case undefined:
|
|
3648
3689
|
case 'list':
|
|
3649
3690
|
console.log(`${colors.cyan}Permission Allowlist:${colors.reset}`);
|
|
3691
|
+
console.log(` Full access: ${config.sandbox?.enabled === false ? 'on' : 'off'}`);
|
|
3692
|
+
console.log(` Sandbox enabled: ${config.sandbox?.enabled !== false}`);
|
|
3693
|
+
console.log(` Restrict workspace: ${config.sandbox?.restrictToWorkspace !== false}`);
|
|
3650
3694
|
console.log(` Tools: ${(config.permissions.allowlist.tools || []).join(', ') || 'none'}`);
|
|
3651
3695
|
console.log(` Commands: ${(config.permissions.allowlist.commands || []).join(', ') || 'none'}`);
|
|
3652
3696
|
console.log(` MCP Servers: ${(config.permissions.allowlist.mcpServers || []).join(', ') || 'none'}`);
|
|
@@ -3673,8 +3717,25 @@ Light mode enabled for safety. Heavy codebase, graph, and git context are skippe
|
|
|
3673
3717
|
console.log(`${colors.green}✓ Updated prompt policy${colors.reset}`);
|
|
3674
3718
|
break;
|
|
3675
3719
|
}
|
|
3720
|
+
case 'full': {
|
|
3721
|
+
const value = String(rest[0] || 'on').toLowerCase();
|
|
3722
|
+
const enabled = !(value === 'off' || value === 'false' || value === '0' || value === 'no');
|
|
3723
|
+
if (typeof this.config.setFullAccess === 'function') {
|
|
3724
|
+
await this.config.setFullAccess(enabled);
|
|
3725
|
+
} else {
|
|
3726
|
+
config.sandbox = {
|
|
3727
|
+
...(config.sandbox || {}),
|
|
3728
|
+
enabled: !enabled,
|
|
3729
|
+
restrictToWorkspace: !enabled,
|
|
3730
|
+
};
|
|
3731
|
+
config.permissions.promptByDefault = !enabled;
|
|
3732
|
+
await this.config.save(config);
|
|
3733
|
+
}
|
|
3734
|
+
console.log(`${colors.green}Full access ${enabled ? 'enabled' : 'disabled'}${colors.reset}`);
|
|
3735
|
+
break;
|
|
3736
|
+
}
|
|
3676
3737
|
default:
|
|
3677
|
-
console.log(`${colors.yellow}Usage: /permissions <list|allow|prompt>${colors.reset}`);
|
|
3738
|
+
console.log(`${colors.yellow}Usage: /permissions <list|allow|prompt|full>${colors.reset}`);
|
|
3678
3739
|
}
|
|
3679
3740
|
}
|
|
3680
3741
|
|
|
@@ -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
45
|
{ cmd: '/mcp', desc: 'MCP server management', sub: ['list', 'add', 'preset', 'install', 'remove', 'allow', 'tools'] },
|
|
45
|
-
{ cmd: '/permissions', desc: 'Permission allowlist', sub: ['list', 'allow', 'prompt'] },
|
|
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>' },
|