winter-super-cli 2026.6.26 → 2026.6.28

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 (122) hide show
  1. package/CHANGELOG.md +28 -5
  2. package/README.md +66 -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 +206 -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 +16 -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 +21 -1
  109. package/src/cli/config.js +42 -4
  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 +45 -8
  114. package/src/cli/repl-commands.js +123 -2
  115. package/src/cli/repl.js +183 -87
  116. package/src/cli/slash-commands.js +3 -1
  117. package/src/cli/tui.js +133 -37
  118. package/src/mcp/client.js +46 -5
  119. package/src/tools/agent.js +316 -25
  120. package/src/tools/executor.js +314 -11
  121. package/src/tools/permission.js +20 -17
  122. 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(flushPasteBuffer, PASTE_DELAY);
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
 
@@ -1880,7 +1963,10 @@ ${colors.reset}
1880
1963
  if (this.isBrowserInteractionRequest(rawText)) return true;
1881
1964
 
1882
1965
  // Even without explicit target, some verbs are strong enough on their own
1883
- const strongActionAlone = /\b(fix|debug|deploy|build|test|commit|install|run|refactor|sửa|chạy|cài|triển khai|xây dựng)\b/i;
1966
+ const continuationAction = /\b(continue|resume|start|begin|tiep|tiếp|bat dau|bắt đầu)\b/i;
1967
+ if (continuationAction.test(text)) return true;
1968
+
1969
+ const strongActionAlone = /\b(fix|debug|deploy|build|test|commit|install|run|refactor|start|begin|sửa|chạy|cài|triển khai|xây dựng|bắt đầu|bat dau)\b/i;
1884
1970
  if (strongActionAlone.test(text)) return true;
1885
1971
 
1886
1972
  return actionPattern.test(text) && targetPattern.test(text);
@@ -1907,6 +1993,38 @@ ${colors.reset}
1907
1993
  return true;
1908
1994
  }
1909
1995
 
1996
+ responseIndicatesUnfinishedAction(content = '') {
1997
+ const raw = String(content || '').trim();
1998
+ if (!raw) return false;
1999
+ const text = `${raw}\n${this.normalizeIntentText(raw)}`.toLowerCase();
2000
+
2001
+ const inProgress = /\b(đang|dang|sẽ|se|tiếp theo|tiep theo|next(?:,|\s+i|\s+step)?|i(?:'ll| will| am going to)|going to|để tôi|de toi|let me|cần (?:thêm|sửa|tạo|viết)|can (?:add|create|implement)|need to (?:add|create|implement|edit|write|fix)|thiếu .*?(?:endpoint|api|view|ui|frontend|backend|route|function)|missing .*?(?:endpoint|api|view|ui|frontend|backend|route|function))\b/i;
2002
+ const workVerb = /\b(làm|lam|sửa|sua|thêm|them|tạo|tao|viết|viet|cập nhật|cap nhat|implement|add|create|write|edit|update|patch|fix|build|wire|connect|endpoint|api|view|ui|frontend|backend)\b/i;
2003
+ const onlyInspection = /\b(đọc|doc|read|grep|search|inspect|kiểm tra|kiem tra|found|thấy|thay|xác định|xac dinh)\b/i;
2004
+
2005
+ if (inProgress.test(text) && (workVerb.test(text) || onlyInspection.test(text))) return true;
2006
+ if (/đang làm tiếp|dang lam tiep|doing next|working on it|đang sửa|dang sua|đang thêm|dang them/i.test(text)) return true;
2007
+ return false;
2008
+ }
2009
+
2010
+ buildUnfinishedActionCorrection(messages = [], content = '') {
2011
+ const request = this.getLatestUserText(messages);
2012
+ return [
2013
+ 'RUNTIME ENFORCEMENT: Your previous response was only progress/status, not completion.',
2014
+ '',
2015
+ 'You already inspected, but the user asked you to continue/do the work. Keep going with tool calls now:',
2016
+ '1. If you identified missing backend/frontend pieces, call Read/Grep for the exact files still needed.',
2017
+ '2. Call Edit/Write/InsertText/StrReplaceAll to make the code changes.',
2018
+ '3. Call Bash to run the closest test/build/smoke check.',
2019
+ '4. Only then give the final answer.',
2020
+ '',
2021
+ 'Do not answer with "đang làm", "sẽ thêm", "cần thêm", or a plan. Use tools.',
2022
+ '',
2023
+ `Original user request: ${request}`,
2024
+ content ? `Blocked progress response: ${String(content).slice(0, 1000)}` : '',
2025
+ ].filter(Boolean).join('\n');
2026
+ }
2027
+
1910
2028
  isBrowserInteractionRequest(text = '') {
1911
2029
  const raw = String(text || '');
1912
2030
  const normalized = this.normalizeIntentText(raw);
@@ -1944,7 +2062,7 @@ ${colors.reset}
1944
2062
  'For browser interaction tasks you MUST use tools, not prose:',
1945
2063
  '1. If chrome-devtools MCP is configured, call MCP {"server":"chrome-devtools","tool":"list"} first if needed.',
1946
2064
  '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.',
2065
+ '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
2066
  '4. Do not say "đã bấm", "đã điền", "đã mở", or "đã kiểm tra" until a browser/MCP tool result proves it.',
1949
2067
  '',
1950
2068
  `Original user request: ${request}`,
@@ -1962,7 +2080,7 @@ ${colors.reset}
1962
2080
  'DO NOT say "I have updated/created/fixed" without a tool call proving it.',
1963
2081
  'DO NOT describe what you would do. Actually DO IT with tool calls.',
1964
2082
  '',
1965
- 'Available tools: Read, Write, Edit, Bash, Glob, Grep, OpenBrowser, BrowserDebug, WebFetch, WebSearch, MCP.',
2083
+ 'Available tools: Read, Write, Edit, Bash, Glob, Grep, OpenBrowser, VisibleBrowser, BrowserDebug, WebFetch, WebSearch, MCP.',
1966
2084
  '',
1967
2085
  'If native tool calls are not supported, output exactly one fallback tool call:',
1968
2086
  '<invoke name="Read"><parameter name="path">README.md</parameter></invoke>',
@@ -1985,7 +2103,7 @@ ${colors.reset}
1985
2103
  const hints = [];
1986
2104
 
1987
2105
  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.');
2106
+ 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
2107
  }
1990
2108
 
1991
2109
  // Detect file reading requests
@@ -2108,6 +2226,9 @@ ${colors.reset}
2108
2226
  if ((options?.requireToolEvidence && this.responseNeedsToolEvidence(assistantMsg.content)) || isFakeCompletion) {
2109
2227
  return { assistantMsg, toolCalls, finalContent: '', finishReason: 'tool_evidence_required' };
2110
2228
  }
2229
+ if (options?.deferFinalContent) {
2230
+ return { assistantMsg, toolCalls, finalContent: assistantMsg.content, finishReason };
2231
+ }
2111
2232
  this.printAssistantAnswer(assistantMsg.content, startedAt, totalUsage);
2112
2233
  return { assistantMsg, toolCalls, finalContent: assistantMsg.content, finishReason };
2113
2234
  }
@@ -2122,7 +2243,7 @@ ${colors.reset}
2122
2243
  const toolCallParts = [];
2123
2244
  let finishReason = null;
2124
2245
  let printed = false;
2125
- const bufferToolModeContent = options?.enableTools === true;
2246
+ const bufferToolModeContent = false;
2126
2247
 
2127
2248
  for await (const chunk of this.ai.streamRequest(messages, options)) {
2128
2249
  if (chunk.usage) this.addUsage(totalUsage, chunk.usage);
@@ -2239,6 +2360,14 @@ ${colors.reset}
2239
2360
  finishReason: 'tool_evidence_required',
2240
2361
  };
2241
2362
  }
2363
+ if (options?.deferFinalContent) {
2364
+ return {
2365
+ assistantMsg: { content: visibleContent },
2366
+ toolCalls,
2367
+ finalContent: visibleContent,
2368
+ finishReason,
2369
+ };
2370
+ }
2242
2371
  this.printAssistantAnswer(visibleContent, startedAt, totalUsage);
2243
2372
  return {
2244
2373
  assistantMsg: { content: visibleContent },
@@ -2275,7 +2404,7 @@ ${colors.reset}
2275
2404
  '/provider', '/model', '/models', '/providers',
2276
2405
  '/theme:toggle', '/tui',
2277
2406
  '/auto', '/debug', '/doctor', '/context', '/scorecard', '/swe',
2278
- '/read', '/write', '/glob', '/grep', '/bash',
2407
+ '/read', '/write', '/glob', '/grep', '/bash', '/browser', '/paste',
2279
2408
  '/codex', '/claude', '/karpathy', '/agents',
2280
2409
  '/resources', '/designs', '/skills',
2281
2410
  '/ecc',
@@ -2374,7 +2503,7 @@ ${colors.reset}
2374
2503
  const executionProfile = this.selectExecutionProfile(messages, { enableTools: false });
2375
2504
  const latestUserText = this.getLatestUserText(messages);
2376
2505
  const browserInteraction = this.isBrowserInteractionRequest(latestUserText);
2377
- const hasBrowserEvidence = toolSummaries.some(summary => /^(MCP|BrowserDebug|OpenBrowser):/i.test(summary));
2506
+ const hasBrowserEvidence = toolSummaries.some(summary => /^(MCP|VisibleBrowser|BrowserDebug|OpenBrowser):/i.test(summary));
2378
2507
  const finalMessages = [
2379
2508
  ...messages,
2380
2509
  {
@@ -2387,7 +2516,7 @@ ${colors.reset}
2387
2516
  'Start with the actual outcome, then mention only the most relevant files/commands. Avoid broad generic advice.',
2388
2517
  'If a tool failed, explain the concrete failure briefly and answer with the available evidence.',
2389
2518
  '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.' : '',
2519
+ 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
2520
  toolSummaries.length ? `Tool summary:\n${toolSummaries.join('\n')}` : '',
2392
2521
  ].filter(Boolean).join('\n'),
2393
2522
  },
@@ -2412,7 +2541,7 @@ ${colors.reset}
2412
2541
  this.addUsage(totalUsage, response.usage);
2413
2542
  let content = response.choices?.[0]?.message?.content || '';
2414
2543
  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 lại yêu cầu để Winter gọi đúng browser tool.';
2544
+ 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
2545
  }
2417
2546
 
2418
2547
  if (this.spinner) this.spinner.stop();
@@ -2457,7 +2586,7 @@ ${colors.reset}
2457
2586
  if (this.spinner) this.spinner.stop();
2458
2587
 
2459
2588
  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 lại yêu cầu để Winter gọi đúng browser tool.';
2589
+ 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
2590
  }
2462
2591
 
2463
2592
  if (content) {
@@ -2481,7 +2610,7 @@ ${colors.reset}
2481
2610
  this.addUsage(totalUsage, response.usage);
2482
2611
  content = response.choices?.[0]?.message?.content || '';
2483
2612
  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 lại yêu cầu để Winter gọi đúng browser tool.';
2613
+ 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
2614
  }
2486
2615
  if (content) {
2487
2616
  this.printAssistantAnswer(content, startedAt, totalUsage);
@@ -2889,7 +3018,7 @@ ${colors.reset}
2889
3018
  messages.push({ role: 'system', content: toolHint });
2890
3019
  }
2891
3020
 
2892
- const { finalContent, usedMutatingTools } = await this.runConversation(messages, 'Thinking', tools);
3021
+ const { finalContent, usedMutatingTools, autoVerified } = await this.runConversation(messages, 'Thinking', tools);
2893
3022
 
2894
3023
  const allToolCalls = [];
2895
3024
  for (const msg of messages) {
@@ -2914,7 +3043,7 @@ ${colors.reset}
2914
3043
  });
2915
3044
 
2916
3045
  // Tự động verify: nếu AI đã dùng tools (sửa code), chạy test/build.
2917
- if (finalContent && this.shouldAutoVerifyAfterTools(message, usedMutatingTools)) {
3046
+ if (!autoVerified && finalContent && this.shouldAutoVerifyAfterTools(message, usedMutatingTools)) {
2918
3047
  const sessionContext = this.session?.getContext?.() || {};
2919
3048
  const profile = String(sessionContext.workflowProfile || 'general');
2920
3049
  const amplifier = sessionContext.smallModelAmplifier || {};
@@ -2965,7 +3094,7 @@ ${colors.reset}
2965
3094
  ].filter(Boolean).join('\n');
2966
3095
 
2967
3096
  const amplifier = buildSmallModelAmplification({
2968
- modelTier: this.ai?._modelTier || 'medium',
3097
+ modelTier: this.getActiveModelTier(),
2969
3098
  workflowProfile: workflow.profile,
2970
3099
  depth: workflow.depth,
2971
3100
  });
@@ -3115,35 +3244,10 @@ Do NOT stop until all errors are resolved.`;
3115
3244
  }
3116
3245
 
3117
3246
  async runAgent(role, task) {
3118
- const agentDefinition = await this.agentRegistry.get(role || 'general');
3119
- const context = await this.getProjectContext(task);
3120
- const messages = [
3121
- { role: 'system', content: this.getAgentDefinitionSystemPrompt(agentDefinition, context) }
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
- }
3247
+ const result = await this.tools.agentTool.run(task, { role: role || 'general' });
3248
+ await this.session.addToHistory({ role: 'user', content: `[subagent:${result.role || role || 'general'}] ${task}` });
3249
+ await this.session.addToHistory({ role: 'assistant', content: result.finalContent || result.summary || result.error || '' });
3250
+ return result;
3147
3251
  }
3148
3252
 
3149
3253
  async listAgentDefinitions() {
@@ -3420,6 +3524,14 @@ Light mode enabled for safety. Heavy codebase, graph, and git context are skippe
3420
3524
  await this.session.replaceMemory('[Required local resources]', requiredLocalResources, 'resource');
3421
3525
  }
3422
3526
 
3527
+ const projectInstructionFiles = await this.readProjectInstructionFiles();
3528
+ const resourceApplicationProfile = await this.contextLoader.getResourceApplicationProfile({ projectInstructionFiles });
3529
+ if (resourceApplicationProfile) {
3530
+ await this.session.updateContext('resourceApplicationProfile', resourceApplicationProfile);
3531
+ await this.session.replaceMemory('[Auto-loaded resource application profile]', resourceApplicationProfile, 'resource');
3532
+ this.startupNotice('resource profile loaded');
3533
+ }
3534
+
3423
3535
  const skillSnapshot = await this.inferStartupSkills();
3424
3536
  await this.session.updateContext('availableSkillCatalog', skillSnapshot.availableSkills);
3425
3537
  await this.session.updateContext('activeSkills', skillSnapshot.activeSkills);
@@ -3431,43 +3543,7 @@ Light mode enabled for safety. Heavy codebase, graph, and git context are skippe
3431
3543
  }
3432
3544
 
3433
3545
  async inferStartupSkills() {
3434
- const catalog = await this.getStartupSkillCatalog();
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
- };
3546
+ return this.contextLoader.inferStartupSkills();
3471
3547
  }
3472
3548
 
3473
3549
  async getStartupSkillCatalog() {
@@ -3647,6 +3723,9 @@ Light mode enabled for safety. Heavy codebase, graph, and git context are skippe
3647
3723
  case undefined:
3648
3724
  case 'list':
3649
3725
  console.log(`${colors.cyan}Permission Allowlist:${colors.reset}`);
3726
+ console.log(` Full access: ${config.sandbox?.enabled === false ? 'on' : 'off'}`);
3727
+ console.log(` Sandbox enabled: ${config.sandbox?.enabled !== false}`);
3728
+ console.log(` Restrict workspace: ${config.sandbox?.restrictToWorkspace !== false}`);
3650
3729
  console.log(` Tools: ${(config.permissions.allowlist.tools || []).join(', ') || 'none'}`);
3651
3730
  console.log(` Commands: ${(config.permissions.allowlist.commands || []).join(', ') || 'none'}`);
3652
3731
  console.log(` MCP Servers: ${(config.permissions.allowlist.mcpServers || []).join(', ') || 'none'}`);
@@ -3673,8 +3752,25 @@ Light mode enabled for safety. Heavy codebase, graph, and git context are skippe
3673
3752
  console.log(`${colors.green}✓ Updated prompt policy${colors.reset}`);
3674
3753
  break;
3675
3754
  }
3755
+ case 'full': {
3756
+ const value = String(rest[0] || 'on').toLowerCase();
3757
+ const enabled = !(value === 'off' || value === 'false' || value === '0' || value === 'no');
3758
+ if (typeof this.config.setFullAccess === 'function') {
3759
+ await this.config.setFullAccess(enabled);
3760
+ } else {
3761
+ config.sandbox = {
3762
+ ...(config.sandbox || {}),
3763
+ enabled: !enabled,
3764
+ restrictToWorkspace: !enabled,
3765
+ };
3766
+ config.permissions.promptByDefault = !enabled;
3767
+ await this.config.save(config);
3768
+ }
3769
+ console.log(`${colors.green}Full access ${enabled ? 'enabled' : 'disabled'}${colors.reset}`);
3770
+ break;
3771
+ }
3676
3772
  default:
3677
- console.log(`${colors.yellow}Usage: /permissions <list|allow|prompt>${colors.reset}`);
3773
+ console.log(`${colors.yellow}Usage: /permissions <list|allow|prompt|full>${colors.reset}`);
3678
3774
  }
3679
3775
  }
3680
3776
 
@@ -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>' },