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
@@ -30,7 +30,15 @@ export class ToolExecutor {
30
30
  constructor(repl) {
31
31
  this.repl = repl;
32
32
  this.projectPath = repl?.projectPath || process.cwd();
33
- this.allowedCommands = ['git', 'npm', 'node', 'python', 'code', 'pnpm', 'yarn', 'bun', 'pip', 'cargo', 'rustc', 'echo', 'printf', 'cat', 'ls', 'dir', 'type', 'copy', 'mkdir', 'get-childitem', 'set-content', 'get-content', 'test-path', 'get-date'];
33
+ this.allowedCommands = [
34
+ 'git', 'npm', 'npx', 'node', 'python', 'code', 'pnpm', 'yarn', 'bun', 'pip', 'cargo', 'rustc',
35
+ 'powershell', 'pwsh', 'cmd',
36
+ 'echo', 'printf', 'cat', 'ls', 'dir', 'type', 'copy', 'mkdir', 'get-childitem', 'set-content',
37
+ 'get-content', 'test-path', 'get-date', 'where',
38
+ 'ping', 'test-connection', 'curl', 'wget', 'iwr', 'irm', 'invoke-webrequest', 'invoke-restmethod',
39
+ 'nslookup', 'resolve-dnsname', 'tracert', 'traceroute', 'pathping', 'dig', 'ipconfig', 'ifconfig',
40
+ 'ip', 'netstat', 'speedtest', 'speedtest-cli', 'measure-command',
41
+ ];
34
42
  this.blockedPatterns = [
35
43
  { pattern: /\brm\s+-[^\n;|&]*r[^\n;|&]*f\b|\brm\s+-[^\n;|&]*f[^\n;|&]*r\b/i, label: 'rm -rf' },
36
44
  { pattern: /\bremove-item\b[^\n;|&]*(?:-recurse\b[^\n;|&]*-force\b|-force\b[^\n;|&]*-recurse\b)/i, label: 'Remove-Item -Recurse -Force' },
@@ -334,18 +342,68 @@ export class ToolExecutor {
334
342
  {
335
343
  type: 'function',
336
344
  name: 'Agent',
337
- description: 'Spawn a subagent to execute a complex task with planning, execution, and verification workflow.',
345
+ description: 'Spawn and await a real isolated subagent conversation with scoped tools, timeout, execution, verification, and result passing.',
338
346
  parameters: {
339
347
  type: 'object',
340
348
  properties: {
341
349
  task: { type: 'string', description: 'Task description for the agent' },
350
+ role: { type: 'string', description: 'Agent role/profile, e.g. general, debug, review, design, research, swe' },
351
+ context: { type: 'string', description: 'Parent context to pass into the subagent' },
352
+ tools: { type: 'array', items: { type: 'string' }, description: 'Optional restricted tool allowlist for this subagent' },
353
+ process_isolation: { type: 'boolean', description: 'Run subagent in a child process. Defaults true in live REPL.' },
342
354
  max_steps: { type: 'number', description: 'Maximum execution steps (default: 10, max: 25)' },
355
+ timeout_ms: { type: 'number', description: 'Timeout for the subagent run' },
343
356
  provider: { type: 'string', description: 'AI provider to use for this agent' },
344
357
  cwd: { type: 'string', description: 'Working directory' },
345
358
  },
346
359
  required: ['task']
347
360
  }
348
361
  },
362
+ {
363
+ type: 'function',
364
+ name: 'DelegateTask',
365
+ description: 'Delegate a task to a real subagent and wait for summary, changed files, tool evidence, usage, and errors. Alias of Agent with clearer delegation semantics.',
366
+ parameters: {
367
+ type: 'object',
368
+ properties: {
369
+ goal: { type: 'string', description: 'Goal or task for the delegated subagent' },
370
+ task: { type: 'string', description: 'Task description for the delegated subagent' },
371
+ role: { type: 'string', description: 'Agent role/profile' },
372
+ context: { type: 'string', description: 'Parent context to pass into the subagent' },
373
+ tools: { type: 'array', items: { type: 'string' }, description: 'Restricted tool allowlist' },
374
+ process_isolation: { type: 'boolean', description: 'Run subagent in a child process. Defaults true in live REPL.' },
375
+ max_steps: { type: 'number', description: 'Maximum execution steps' },
376
+ timeout_ms: { type: 'number', description: 'Timeout for the delegated run' },
377
+ provider: { type: 'string', description: 'AI provider to use for this subagent' },
378
+ cwd: { type: 'string', description: 'Working directory' },
379
+ }
380
+ }
381
+ },
382
+ {
383
+ type: 'function',
384
+ name: 'ParallelAgent',
385
+ description: 'Run multiple real delegated subagents concurrently and aggregate their summaries, changed files, tool evidence, and failures.',
386
+ parameters: {
387
+ type: 'object',
388
+ properties: {
389
+ tasks: {
390
+ type: 'array',
391
+ items: {
392
+ type: 'object',
393
+ properties: {
394
+ goal: { type: 'string' },
395
+ task: { type: 'string' },
396
+ role: { type: 'string' },
397
+ tools: { type: 'array', items: { type: 'string' } },
398
+ }
399
+ }
400
+ },
401
+ concurrency: { type: 'number', description: 'Maximum subagents to run at once, capped at 6' },
402
+ timeout_ms: { type: 'number', description: 'Timeout per subagent' },
403
+ },
404
+ required: ['tasks']
405
+ }
406
+ },
349
407
  {
350
408
  type: 'function',
351
409
  name: 'InsertText',
@@ -388,6 +446,25 @@ export class ToolExecutor {
388
446
  required: ['url']
389
447
  }
390
448
  },
449
+ {
450
+ type: 'function',
451
+ name: 'VisibleBrowser',
452
+ description: 'Launch and control a real visible Chrome/Chromium browser with Puppeteer. Use when the user asks Winter to actually click, type, navigate, inspect, or screenshot a page and chrome-devtools MCP is unavailable. Actions: open, navigate, click, type, evaluate, screenshot, snapshot.',
453
+ parameters: {
454
+ type: 'object',
455
+ properties: {
456
+ url: { type: 'string', description: 'URL to open or navigate to. Defaults to about:blank.' },
457
+ action: { type: 'string', description: 'open, navigate, click, type, evaluate, screenshot, or snapshot' },
458
+ selector: { type: 'string', description: 'CSS selector for click/type/snapshot targeting' },
459
+ text: { type: 'string', description: 'Text to type for action=type' },
460
+ script: { type: 'string', description: 'JavaScript expression/function body for action=evaluate' },
461
+ wait_for: { type: 'string', description: 'Optional CSS selector to wait for after navigation/action' },
462
+ screenshot_path: { type: 'string', description: 'Optional output PNG path for action=screenshot' },
463
+ keep_open: { type: 'boolean', description: 'Leave the browser open after action. Default false.' },
464
+ browser: { type: 'string', description: 'chrome or chromium. Defaults to chrome.' }
465
+ }
466
+ }
467
+ },
391
468
  {
392
469
  type: 'function',
393
470
  name: 'OpenBrowser',
@@ -544,6 +621,8 @@ export class ToolExecutor {
544
621
  return await this.parallelExecute(input.tools ?? input.calls ?? [], { cwd });
545
622
  case 'BrowserDebug':
546
623
  return await this.browserDebug(input.url ?? input.uri, input.action);
624
+ case 'VisibleBrowser':
625
+ return await this.visibleBrowser(input, cwd);
547
626
  case 'OpenBrowser':
548
627
  return await this.openBrowser(input.url ?? input.uri ?? input.href, input.browser);
549
628
  case 'WebFetch':
@@ -563,7 +642,35 @@ export class ToolExecutor {
563
642
  case 'AskUserQuestion':
564
643
  return await this.interactiveTool.askQuestion(input.questions ?? input.question);
565
644
  case 'Agent':
566
- return await this.agentTool.run(input.task, { maxSteps: input.max_steps ?? input.maxSteps, provider: input.provider, cwd: input.cwd });
645
+ return await this.agentTool.run(input.task, {
646
+ role: input.role ?? input.agent,
647
+ context: input.context,
648
+ tools: input.tools,
649
+ processIsolation: input.process_isolation ?? input.processIsolation,
650
+ maxSteps: input.max_steps ?? input.maxSteps,
651
+ timeoutMs: input.timeout_ms ?? input.timeoutMs,
652
+ provider: input.provider,
653
+ cwd: input.cwd,
654
+ });
655
+ case 'DelegateTask':
656
+ return await this.agentTool.run(input.task ?? input.goal, {
657
+ role: input.role ?? input.agent,
658
+ context: input.context,
659
+ tools: input.tools,
660
+ processIsolation: input.process_isolation ?? input.processIsolation,
661
+ maxSteps: input.max_steps ?? input.maxSteps,
662
+ timeoutMs: input.timeout_ms ?? input.timeoutMs,
663
+ provider: input.provider,
664
+ cwd: input.cwd,
665
+ });
666
+ case 'ParallelAgent':
667
+ return await this.agentTool.runParallel(input.tasks, {
668
+ concurrency: input.concurrency,
669
+ timeoutMs: input.timeout_ms ?? input.timeoutMs,
670
+ processIsolation: input.process_isolation ?? input.processIsolation,
671
+ provider: input.provider,
672
+ cwd: input.cwd,
673
+ });
567
674
  case 'InsertText':
568
675
  return await this.insertTextTool.insert(this.resolveInputPath(input.file_path ?? input.path ?? input.file, cwd), input.insert_text ?? input.text ?? input.content, input);
569
676
  case 'StrReplaceAll':
@@ -586,7 +693,7 @@ export class ToolExecutor {
586
693
  return {
587
694
  success: false,
588
695
  error: `Unknown tool: ${toolName}`,
589
- availableTools: ['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep', 'TaskCreate', 'TaskUpdate', 'TaskList', 'MCP', 'Parallel', 'OpenBrowser', 'BrowserDebug', 'WebFetch', 'WebSearch', 'WebArchive', 'HtmlEffectiveness', 'NotebookRead', 'NotebookEdit', 'TodoWrite', 'TodoList', 'ScheduleWakeup', 'AskUserQuestion', 'Agent', 'InsertText', 'StrReplaceAll'],
696
+ availableTools: ['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep', 'TaskCreate', 'TaskUpdate', 'TaskList', 'MCP', 'Parallel', 'OpenBrowser', 'VisibleBrowser', 'BrowserDebug', 'WebFetch', 'WebSearch', 'WebArchive', 'HtmlEffectiveness', 'NotebookRead', 'NotebookEdit', 'TodoWrite', 'TodoList', 'ScheduleWakeup', 'AskUserQuestion', 'Agent', 'DelegateTask', 'ParallelAgent', 'InsertText', 'StrReplaceAll'],
590
697
  recovery: 'Call one of the available tools. For file writes use Write with { "file_path": "...", "content": "..." }. For shell commands use Bash with { "command": "..." }.',
591
698
  };
592
699
  }
@@ -730,9 +837,9 @@ export class ToolExecutor {
730
837
  return { success: true, coerced: true, args: { notebook_path: notebookPath, cell_id: cellId, new_source: newSource } };
731
838
  }
732
839
 
733
- if (toolName === 'WebFetch' || toolName === 'WebArchive' || toolName === 'BrowserDebug') {
840
+ if (toolName === 'WebFetch' || toolName === 'WebArchive' || toolName === 'BrowserDebug' || toolName === 'VisibleBrowser') {
734
841
  const url = pick('url', 'uri', 'href');
735
- if (!url) {
842
+ if (!url && toolName !== 'VisibleBrowser') {
736
843
  return { success: false, error: 'url is required', recovery: `Example: ${toolName} {"url":"https://example.com"}` };
737
844
  }
738
845
  const next = { ...args, url };
@@ -745,6 +852,21 @@ export class ToolExecutor {
745
852
  return { success: true, coerced: true, args: { ...args, url, browser } };
746
853
  }
747
854
 
855
+ if (toolName === 'Agent' || toolName === 'DelegateTask') {
856
+ const task = pick('task', 'goal', 'prompt', 'description');
857
+ if (!task) {
858
+ return { success: false, error: 'task is required', recovery: `Example: ${toolName} {"task":"Inspect the failing test and report the first blocker"}` };
859
+ }
860
+ return { success: true, coerced: true, args: { ...args, task } };
861
+ }
862
+
863
+ if (toolName === 'ParallelAgent') {
864
+ if (!Array.isArray(args.tasks) || args.tasks.length === 0) {
865
+ return { success: false, error: 'tasks array is required', recovery: 'Example: ParallelAgent {"tasks":[{"goal":"Review auth"},{"goal":"Inspect tests"}]}' };
866
+ }
867
+ return { success: true, coerced: true, args };
868
+ }
869
+
748
870
  if (toolName === 'WebSearch') {
749
871
  const query = pick('query', 'q', 'search', 'search_query', 'searchQuery');
750
872
  if (!query) {
@@ -783,6 +905,9 @@ export class ToolExecutor {
783
905
  const cfg = await this.getRuntimeConfig();
784
906
  const permissionCommands = cfg.permissions?.allowlist?.commands || [];
785
907
  const sandbox = cfg.sandbox || {};
908
+ if (sandbox.enabled === false) {
909
+ return { success: true };
910
+ }
786
911
  const sandboxCommands = sandbox.enabled === false ? [] : (sandbox.allowedCommands || this.allowedCommands);
787
912
  const allowed = new Set([
788
913
  ...this.allowedCommands,
@@ -842,14 +967,19 @@ export class ToolExecutor {
842
967
  const summary = {
843
968
  success: result.success !== false,
844
969
  };
845
- for (const key of ['error', 'path', 'count', 'exitCode', 'server', 'tool']) {
970
+ for (const key of ['error', 'path', 'count', 'exitCode', 'server', 'tool', 'url', 'title', 'action', 'visible', 'controlled', 'keptOpen', 'agentId', 'role', 'status', 'summary', 'processIsolated', 'childPid']) {
846
971
  if (result[key] !== undefined) summary[key] = result[key];
847
972
  }
848
973
  if (typeof result.stdout === 'string') summary.stdout = result.stdout.slice(0, 1000);
849
974
  if (typeof result.stderr === 'string') summary.stderr = result.stderr.slice(0, 1000);
850
975
  if (typeof result.content === 'string') summary.content = result.content.slice(0, 1000);
976
+ if (typeof result.domSnippet === 'string') summary.domSnippet = result.domSnippet.slice(0, 1000);
977
+ if (Array.isArray(result.consoleErrors)) summary.consoleErrors = result.consoleErrors.slice(-10);
978
+ if (Array.isArray(result.networkErrors)) summary.networkErrors = result.networkErrors.slice(-10);
851
979
  if (Array.isArray(result.files)) summary.files = result.files.slice(0, 20);
852
980
  if (Array.isArray(result.matches)) summary.matches = result.matches.slice(0, 20);
981
+ if (Array.isArray(result.changedFiles)) summary.changedFiles = result.changedFiles.slice(0, 20);
982
+ if (Array.isArray(result.toolSummaries)) summary.toolSummaries = result.toolSummaries.slice(0, 20);
853
983
  return summary;
854
984
  }
855
985
 
@@ -907,10 +1037,32 @@ export class ToolExecutor {
907
1037
 
908
1038
  const retryPolicy = await this.getRetryPolicy();
909
1039
  try {
910
- const result = await withRetry(() => client.callTool(toolName, argumentsObject), retryPolicy);
1040
+ const result = await withRetry(() => client.callTool(toolName, argumentsObject), {
1041
+ ...retryPolicy,
1042
+ retryable: error => error?.code !== 'MCP_REQUEST_TIMEOUT',
1043
+ });
911
1044
  return { success: true, server: serverName, tool: toolName, result };
912
1045
  } catch (error) {
913
- return { success: false, error: error.message, server: serverName, tool: toolName, recovery: 'Inspect the MCP server error, verify the tool name and arguments, then retry with corrected arguments.' };
1046
+ if (error?.code === 'MCP_REQUEST_TIMEOUT') {
1047
+ await client.close();
1048
+ this.mcpClients.delete(serverName);
1049
+ return {
1050
+ success: false,
1051
+ error: error.message,
1052
+ code: error.code,
1053
+ server: serverName,
1054
+ tool: toolName,
1055
+ timeoutMs: error.timeoutMs,
1056
+ recovery: `MCP server "${serverName}" did not answer "${toolName}" before the timeout. Do not blindly retry the same call. First run /mcp tools ${serverName} to confirm the server responds, narrow the tool arguments, or increase this server's requestTimeoutMs if the tool is expected to be slow.`,
1057
+ };
1058
+ }
1059
+ return {
1060
+ success: false,
1061
+ error: error.message,
1062
+ server: serverName,
1063
+ tool: toolName,
1064
+ recovery: `MCP tool "${toolName}" failed on server "${serverName}". Check the server stderr/logs and compare the arguments with /mcp tools ${serverName}; retry only after correcting the failing input.`,
1065
+ };
914
1066
  }
915
1067
  }
916
1068
 
@@ -1007,6 +1159,15 @@ export class ToolExecutor {
1007
1159
  browseropen: 'OpenBrowser',
1008
1160
  openchrome: 'OpenBrowser',
1009
1161
  launchchrome: 'OpenBrowser',
1162
+ visiblebrowser: 'VisibleBrowser',
1163
+ visible_browser: 'VisibleBrowser',
1164
+ browsercontrol: 'VisibleBrowser',
1165
+ browser_control: 'VisibleBrowser',
1166
+ browseraction: 'VisibleBrowser',
1167
+ chromecontrol: 'VisibleBrowser',
1168
+ chrome_control: 'VisibleBrowser',
1169
+ clickbrowser: 'VisibleBrowser',
1170
+ browserclick: 'VisibleBrowser',
1010
1171
  browserdebug: 'BrowserDebug',
1011
1172
  browser: 'BrowserDebug',
1012
1173
  browserinspect: 'BrowserDebug',
@@ -1049,6 +1210,13 @@ export class ToolExecutor {
1049
1210
  agent: 'Agent',
1050
1211
  subagent: 'Agent',
1051
1212
  agentrun: 'Agent',
1213
+ delegatetask: 'DelegateTask',
1214
+ delegate: 'DelegateTask',
1215
+ taskdelegate: 'DelegateTask',
1216
+ spawnagent: 'DelegateTask',
1217
+ parallelagent: 'ParallelAgent',
1218
+ multiagent: 'ParallelAgent',
1219
+ parallelagents: 'ParallelAgent',
1052
1220
  };
1053
1221
  return aliases[normalized] || raw;
1054
1222
  }
@@ -1078,6 +1246,7 @@ export class ToolExecutor {
1078
1246
  case 'WebFetch':
1079
1247
  case 'WebArchive':
1080
1248
  case 'BrowserDebug':
1249
+ case 'VisibleBrowser':
1081
1250
  return { url: value };
1082
1251
  case 'TaskCreate':
1083
1252
  case 'TodoWrite':
@@ -1085,6 +1254,7 @@ export class ToolExecutor {
1085
1254
  case 'ScheduleWakeup':
1086
1255
  return { prompt: value };
1087
1256
  case 'Agent':
1257
+ case 'DelegateTask':
1088
1258
  return { task: value };
1089
1259
  default:
1090
1260
  return { input: value };
@@ -1451,10 +1621,11 @@ export class ToolExecutor {
1451
1621
  async execWindowsCommand(command, cwd, timeout, requestedShell = 'auto') {
1452
1622
  const shell = requestedShell === 'auto' ? this.detectWindowsShell(command) : requestedShell;
1453
1623
  if (shell === 'cmd') {
1454
- return await execFileAsync('cmd.exe', ['/d', '/s', '/c', command], {
1624
+ return await execFileAsync('cmd.exe', ['/d', '/c', command], {
1455
1625
  cwd,
1456
1626
  timeout,
1457
1627
  windowsHide: true,
1628
+ windowsVerbatimArguments: true,
1458
1629
  maxBuffer: 10 * 1024 * 1024,
1459
1630
  });
1460
1631
  }
@@ -1480,7 +1651,7 @@ export class ToolExecutor {
1480
1651
 
1481
1652
  looksLikeCmd(command) {
1482
1653
  return /\s(&&|\|\|)\s/.test(command)
1483
- || /(^|[&]\s*)(dir|copy|xcopy|del|erase|move|ren|type|echo|set|if|for|mkdir|rmdir)\b/i.test(command)
1654
+ || /(^|[&]\s*)(dir|copy|xcopy|del|erase|move|ren|type|echo|set|if|for|mkdir|rmdir|where)\b/i.test(command)
1484
1655
  || /^\s*@?echo\s+/i.test(command)
1485
1656
  || /(^|\s)(\/b|\/s|\/q|\/y)\b/i.test(command);
1486
1657
  }
@@ -2109,6 +2280,138 @@ export class ToolExecutor {
2109
2280
  }
2110
2281
  }
2111
2282
 
2283
+ async visibleBrowser(input = {}, cwd = this.projectPath) {
2284
+ const url = String(input.url ?? input.uri ?? input.href ?? 'about:blank');
2285
+ const action = String(input.action || (url ? 'open' : 'snapshot')).toLowerCase();
2286
+ const selector = input.selector || input.css || input.target;
2287
+ const text = input.text ?? input.value ?? input.input;
2288
+ const script = input.script ?? input.js ?? input.code;
2289
+ const waitFor = input.wait_for ?? input.waitFor;
2290
+ const keepOpen = input.keep_open === true || input.keepOpen === true;
2291
+ const browserName = String(input.browser || 'chrome').toLowerCase();
2292
+ const screenshotPath = input.screenshot_path ?? input.screenshotPath;
2293
+
2294
+ let puppeteer;
2295
+ try {
2296
+ puppeteer = (await import('puppeteer')).default;
2297
+ } catch {
2298
+ return {
2299
+ success: false,
2300
+ error: 'Thư viện puppeteer chưa được cài đặt.',
2301
+ recovery: 'Run Bash {"command":"npm install puppeteer --no-save"} or configure chrome-devtools MCP, then retry VisibleBrowser.',
2302
+ };
2303
+ }
2304
+
2305
+ let browser;
2306
+ try {
2307
+ const launchOptions = {
2308
+ headless: false,
2309
+ defaultViewport: null,
2310
+ args: ['--start-maximized'],
2311
+ };
2312
+ if (browserName === 'chrome') {
2313
+ launchOptions.channel = 'chrome';
2314
+ }
2315
+
2316
+ browser = await puppeteer.launch(launchOptions).catch(async error => {
2317
+ if (launchOptions.channel) {
2318
+ const fallbackOptions = { ...launchOptions };
2319
+ delete fallbackOptions.channel;
2320
+ return await puppeteer.launch(fallbackOptions);
2321
+ }
2322
+ throw error;
2323
+ });
2324
+
2325
+ const page = await browser.newPage();
2326
+ const consoleLogs = [];
2327
+ const networkErrors = [];
2328
+ page.on('console', msg => {
2329
+ if (['error', 'warning'].includes(msg.type())) {
2330
+ consoleLogs.push(`[${msg.type()}] ${msg.text()}`);
2331
+ }
2332
+ });
2333
+ page.on('requestfailed', request => {
2334
+ networkErrors.push(`${request.method()} ${request.url()} - ${request.failure()?.errorText}`);
2335
+ });
2336
+
2337
+ if (url && url !== 'about:blank') {
2338
+ await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
2339
+ } else {
2340
+ await page.goto('about:blank', { waitUntil: 'domcontentloaded', timeout: 30000 });
2341
+ }
2342
+
2343
+ let actionResult = null;
2344
+ if (waitFor) {
2345
+ await page.waitForSelector(waitFor, { timeout: 15000 });
2346
+ }
2347
+
2348
+ if (action === 'navigate' || action === 'open') {
2349
+ actionResult = { navigated: page.url() };
2350
+ } else if (action === 'click') {
2351
+ if (!selector) throw new Error('selector is required for VisibleBrowser action=click');
2352
+ await page.waitForSelector(selector, { timeout: 15000 });
2353
+ await page.click(selector);
2354
+ actionResult = { clicked: selector };
2355
+ } else if (action === 'type' || action === 'fill') {
2356
+ if (!selector) throw new Error('selector is required for VisibleBrowser action=type');
2357
+ await page.waitForSelector(selector, { timeout: 15000 });
2358
+ await page.click(selector, { clickCount: 3 });
2359
+ await page.type(selector, String(text ?? ''), { delay: 10 });
2360
+ actionResult = { typed: selector, text: String(text ?? '') };
2361
+ } else if (action === 'evaluate' || action === 'eval') {
2362
+ if (!script) throw new Error('script is required for VisibleBrowser action=evaluate');
2363
+ actionResult = await page.evaluate(source => (0, eval)(source), String(script));
2364
+ } else if (action === 'screenshot') {
2365
+ const outputPath = screenshotPath
2366
+ ? this.resolveInputPath(screenshotPath, cwd)
2367
+ : path.join(cwd, '.winter', `visible-browser-${Date.now()}.png`);
2368
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
2369
+ await page.screenshot({ path: outputPath, fullPage: true });
2370
+ actionResult = { screenshotPath: outputPath };
2371
+ } else if (action === 'snapshot') {
2372
+ actionResult = selector
2373
+ ? await page.$eval(selector, el => el.outerHTML.slice(0, 3000))
2374
+ : await page.evaluate(() => document.body?.innerHTML?.slice(0, 3000) || '');
2375
+ } else {
2376
+ throw new Error(`Unsupported VisibleBrowser action: ${action}`);
2377
+ }
2378
+
2379
+ const title = await page.title().catch(() => '');
2380
+ const currentUrl = page.url();
2381
+ const domSnippet = await page.evaluate(() => document.body?.innerText?.slice(0, 1600) || '').catch(() => '');
2382
+
2383
+ if (!keepOpen) {
2384
+ await browser.close();
2385
+ }
2386
+
2387
+ return {
2388
+ success: true,
2389
+ visible: true,
2390
+ controlled: true,
2391
+ browser: browserName,
2392
+ action,
2393
+ url: currentUrl,
2394
+ title,
2395
+ actionResult,
2396
+ consoleErrors: consoleLogs.slice(-10),
2397
+ networkErrors: networkErrors.slice(-10),
2398
+ domSnippet,
2399
+ keptOpen: keepOpen,
2400
+ };
2401
+ } catch (error) {
2402
+ if (browser && !keepOpen) {
2403
+ await browser.close().catch(() => {});
2404
+ }
2405
+ return {
2406
+ success: false,
2407
+ error: error.message,
2408
+ url,
2409
+ action,
2410
+ recovery: 'Use a valid URL and CSS selector. If Chrome launch fails, install Chrome or retry with browser:"chromium"; for persistent live control use chrome-devtools MCP.',
2411
+ };
2412
+ }
2413
+ }
2414
+
2112
2415
  buildBrowserLaunchCommand(url = 'about:blank', browser = 'chrome', platform = process.platform) {
2113
2416
  const targetUrl = String(url || 'about:blank');
2114
2417
  const targetBrowser = String(browser || 'chrome').toLowerCase();
@@ -13,18 +13,20 @@ export class PermissionManager {
13
13
  const permissions = cfg.permissions || {};
14
14
  const allowlist = permissions.allowlist || {};
15
15
 
16
- return {
17
- promptByDefault: permissions.promptByDefault !== false,
18
- allowedTools: new Set([...(allowlist.tools || []), ...DEFAULT_ALLOWED]),
19
- allowedCommands: new Set(allowlist.commands || []),
20
- allowedServers: new Set(allowlist.mcpServers || []),
21
- };
22
- }
23
-
24
- async isAllowedTool(toolName) {
25
- const policy = await this.getPolicy();
26
- return policy.allowedTools.has(toolName);
27
- }
16
+ return {
17
+ promptByDefault: permissions.promptByDefault !== false,
18
+ fullAccess: cfg.sandbox?.enabled === false,
19
+ allowedTools: new Set([...(allowlist.tools || []), ...DEFAULT_ALLOWED]),
20
+ allowedCommands: new Set(allowlist.commands || []),
21
+ allowedServers: new Set(allowlist.mcpServers || []),
22
+ };
23
+ }
24
+
25
+ async isAllowedTool(toolName) {
26
+ const policy = await this.getPolicy();
27
+ if (policy.fullAccess) return true;
28
+ return policy.allowedTools.has(toolName);
29
+ }
28
30
 
29
31
  async shouldPromptForTool(toolName) {
30
32
  const policy = await this.getPolicy();
@@ -37,11 +39,12 @@ export class PermissionManager {
37
39
  return await this.shouldPromptForTool(toolName);
38
40
  }
39
41
 
40
- async isMcpServerAllowed(serverName) {
41
- if (!serverName) return false;
42
- const policy = await this.getPolicy();
43
- return policy.allowedServers.has(serverName);
44
- }
42
+ async isMcpServerAllowed(serverName) {
43
+ if (!serverName) return false;
44
+ const policy = await this.getPolicy();
45
+ if (policy.fullAccess) return true;
46
+ return policy.allowedServers.has(serverName);
47
+ }
45
48
 
46
49
  async allowTool(toolName) {
47
50
  if (!this.config?.load || !this.config?.save) return;
package/winter.d.ts CHANGED
@@ -56,7 +56,7 @@ declare module './src/cli/snowflake-logo.js' {
56
56
  export function providerStatus(name: string, status: string): string;
57
57
  }
58
58
 
59
- declare module './src/cli/tui.js' {
59
+ declare module './src/cli/tui.js' {
60
60
  export interface TuiHistoryEntry {
61
61
  role?: 'user' | 'assistant' | string;
62
62
  content?: string;
@@ -157,10 +157,98 @@ declare module './src/cli/tui.js' {
157
157
  width?: number;
158
158
  title?: string;
159
159
  }): string;
160
- }
161
-
162
- declare module './src/cli/repl.js' {
163
- export interface WinterREPLOptions {
160
+ }
161
+
162
+ declare module './src/ai/capability-scorecard.js' {
163
+ export interface CapabilityProbe {
164
+ key: string;
165
+ label: string;
166
+ ok?: boolean;
167
+ }
168
+
169
+ export interface CapabilityArea {
170
+ id: string;
171
+ label: string;
172
+ weight: number;
173
+ target: string;
174
+ passed: number;
175
+ total: number;
176
+ score: number;
177
+ percent: number;
178
+ probes: CapabilityProbe[];
179
+ checks: CapabilityProbe[];
180
+ }
181
+
182
+ export interface CapabilityGap {
183
+ id: string;
184
+ label: string;
185
+ missing: string[];
186
+ }
187
+
188
+ export interface CapabilityScorecard {
189
+ target: number;
190
+ overall: number;
191
+ score: number;
192
+ maxScore: number;
193
+ status: 'ready' | 'below-target';
194
+ competitors: Array<{
195
+ name: string;
196
+ strengths: string[];
197
+ }>;
198
+ areas: CapabilityArea[];
199
+ gaps: CapabilityGap[];
200
+ }
201
+
202
+ export const WINTER_CAPABILITY_TARGET: number;
203
+ export function assessWinterCapabilities(repl?: Record<string, unknown>): Promise<CapabilityScorecard>;
204
+ export function formatCapabilityScorecard(
205
+ report: CapabilityScorecard,
206
+ options?: { colors?: Record<string, string> }
207
+ ): string;
208
+ }
209
+
210
+ declare module './src/ai/hermes-core.js' {
211
+ export interface HermesCoreSignals {
212
+ agent: boolean;
213
+ skills: boolean;
214
+ memory: boolean;
215
+ automation: boolean;
216
+ gateway: boolean;
217
+ tui: boolean;
218
+ mcp: boolean;
219
+ }
220
+
221
+ export const HERMES_CORE_RESOURCE: string;
222
+ export function detectHermesCoreSignals(input?: {
223
+ taskText?: string;
224
+ projectSignals?: string[];
225
+ }): HermesCoreSignals;
226
+ export function shouldApplyHermesCore(input?: {
227
+ taskText?: string;
228
+ projectSignals?: string[];
229
+ }): boolean;
230
+ export function buildHermesCoreContract(options?: { compact?: boolean }): string;
231
+ }
232
+
233
+ declare module './src/ai/small-model-amplifier.js' {
234
+ export interface SmallModelAmplification {
235
+ weak: boolean;
236
+ maxToolTurns: number;
237
+ enforceSelfCritique: boolean;
238
+ hint: string;
239
+ }
240
+
241
+ export function isWeakTier(modelTier?: string): boolean;
242
+ export function buildCodingMasteryContract(options?: { compact?: boolean }): string;
243
+ export function buildSmallModelAmplification(options?: {
244
+ modelTier?: string;
245
+ workflowProfile?: string;
246
+ depth?: string;
247
+ }): SmallModelAmplification;
248
+ }
249
+
250
+ declare module './src/cli/repl.js' {
251
+ export interface WinterREPLOptions {
164
252
  projectPath?: string;
165
253
  sessionId?: string | null;
166
254
  version?: string;
@@ -176,11 +264,25 @@ declare module './src/cli/repl.js' {
176
264
  start(): Promise<void>;
177
265
  showStatus(): void;
178
266
  showTuiDashboard(): void;
179
- showInputPrompt(): void;
180
- closeInputBox(): void;
181
- buildInputPanel(): {
182
- top: string;
183
- status: string;
267
+ showInputPrompt(): void;
268
+ closeInputBox(): void;
269
+ chat(message: string, imageAttachments?: unknown[]): Promise<void>;
270
+ runConversation(messages: unknown[], label?: string, tools?: unknown[] | null): Promise<{
271
+ finalContent: string;
272
+ usedTools: boolean;
273
+ usedMutatingTools: boolean;
274
+ autoVerified?: boolean;
275
+ autoVerificationPassed?: boolean;
276
+ }>;
277
+ inferVerificationCommands(task?: string): Promise<string[]>;
278
+ runVerification(commands?: string[] | null): Promise<{
279
+ passed: boolean;
280
+ details: Array<{ cmd: string; passed: boolean; output: string }>;
281
+ }>;
282
+ runAutoHealing(task: string): Promise<void>;
283
+ buildInputPanel(): {
284
+ top: string;
285
+ status: string;
184
286
  hint: string;
185
287
  prompt: string;
186
288
  bottom: string;