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.
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 +179 -5
  101. package/src/agent/subagent-child.js +44 -0
  102. package/src/ai/capability-scorecard.js +193 -14
  103. package/src/ai/hermes-core.js +77 -0
  104. package/src/ai/model-capabilities.js +42 -2
  105. package/src/ai/prompts/system-prompt.js +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 +115 -0
  115. package/src/cli/repl.js +147 -86
  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 +310 -9
  121. package/src/tools/permission.js +20 -17
  122. package/winter.d.ts +112 -10
@@ -0,0 +1,176 @@
1
+ ---
2
+ name: hermes-s6-container-supervision
3
+ description: Modify, debug, or extend the s6-overlay supervision tree inside the Hermes Agent Docker image — adding new services, debugging profile gateways, understanding the Architecture B main-program pattern.
4
+ version: 1.0.0
5
+ author: Hermes Agent
6
+ license: MIT
7
+ metadata:
8
+ hermes:
9
+ tags: [docker, s6, supervision, gateway, profiles]
10
+ related_skills: [hermes-agent, hermes-agent-dev]
11
+ ---
12
+
13
+ # Hermes s6-overlay Container Supervision
14
+
15
+ ## When to use this skill
16
+
17
+ Load this skill when you're working on:
18
+ - Adding or removing a static service in the Hermes Docker image (something that should be supervised at every container start, like the dashboard)
19
+ - Diagnosing why a per-profile gateway isn't starting, restarting, or surviving `docker restart`
20
+ - Understanding why the container's CMD is `/opt/hermes/docker/main-wrapper.sh` and how leading-dash args reach the user's program
21
+ - Modifying `cont-init.d` boot scripts (UID remap, volume seeding, profile reconciliation)
22
+ - Changing the rendered run-script for per-profile gateways (Phase 4)
23
+
24
+ If you're just running the Hermes Agent and want to use Docker, see `website/docs/user-guide/docker.md` instead.
25
+
26
+ ## Architecture at a glance
27
+
28
+ ```
29
+ /init ← PID 1 (s6-overlay v3.2.3.0)
30
+ ├── cont-init.d ← oneshot setup, runs as root
31
+ │ ├── 01-hermes-setup ← docker/stage2-hook.sh
32
+ │ │ ├── UID/GID remap
33
+ │ │ ├── chown /opt/data
34
+ │ │ ├── chown /opt/data/profiles (every boot)
35
+ │ │ ├── seed .env / config.yaml / SOUL.md
36
+ │ │ └── skills_sync.py
37
+ │ └── 02-reconcile-profiles ← hermes_cli.container_boot
38
+ │ ├── chown /run/service (hermes-writable for runtime register)
39
+ │ └── walk $HERMES_HOME/profiles/<name>/gateway_state.json
40
+ │ → recreate /run/service/gateway-<name>/
41
+ │ → auto-start only those with prior_state == "running"
42
+
43
+ ├── s6-rc.d (static services, in /etc/s6-overlay/s6-rc.d/)
44
+ │ ├── main-hermes/run ← exec sleep infinity (no-op slot)
45
+ │ └── dashboard/run ← if HERMES_DASHBOARD=1, runs `hermes dashboard`
46
+
47
+ ├── /run/service (s6-svscan watches; tmpfs)
48
+ │ ├── gateway-coder/ ← runtime-registered per-profile
49
+ │ │ ├── type ("longrun")
50
+ │ │ ├── run ("#!/command/with-contenv sh ... exec s6-setuidgid hermes hermes -p coder gateway run")
51
+ │ │ ├── down (marker — present means "registered but don't auto-start")
52
+ │ │ └── log/run (s6-log → $HERMES_HOME/logs/gateways/coder/current)
53
+ │ └── ...
54
+
55
+ └── CMD ("main program") ← /opt/hermes/docker/main-wrapper.sh
56
+ └── routes user args: bare exec | hermes subcommand | hermes (no args)
57
+ — exec'd by /init with stdin/stdout/stderr inherited (TTY for --tui)
58
+ ```
59
+
60
+ ## Key files
61
+
62
+ | Path | Role |
63
+ |---|---|
64
+ | `Dockerfile` | s6-overlay install + cont-init.d wiring + `ENTRYPOINT ["/init", "/opt/hermes/docker/main-wrapper.sh"]` |
65
+ | `docker/stage2-hook.sh` | The "old entrypoint logic" — UID remap, chown, seed, skills sync. Runs as cont-init.d/01-hermes-setup. |
66
+ | `docker/cont-init.d/02-reconcile-profiles` | Calls `hermes_cli.container_boot` on every boot to restore profile gateway slots from the persistent volume. |
67
+ | `docker/main-wrapper.sh` | The container's CMD. Routes user args, drops to hermes via `s6-setuidgid`, exec's the chosen program. |
68
+ | `docker/s6-rc.d/main-hermes/run` | No-op `sleep infinity` — slot exists so the s6-rc user bundle is valid; main hermes runs as the CMD, not as a supervised service. |
69
+ | `docker/s6-rc.d/dashboard/run` | Conditional service — `exec sleep infinity` unless `HERMES_DASHBOARD` is truthy. |
70
+ | `docker/entrypoint.sh` | Back-compat shim that `exec`s the stage2 hook. External scripts that hard-coded the old entrypoint path still work. |
71
+ | `hermes_cli/service_manager.py` | `S6ServiceManager`: `register_profile_gateway`, `unregister_profile_gateway`, `start/stop/restart/is_running`, `list_profile_gateways`. |
72
+ | `hermes_cli/container_boot.py` | `reconcile_profile_gateways()` — walks persistent profiles, regenerates s6 slots, emits `container-boot.log`. |
73
+ | `hermes_cli/gateway.py::_dispatch_via_service_manager_if_s6` | Intercepts `hermes gateway start/stop/restart` and routes to s6 when running in a container. |
74
+
75
+ ## Why Architecture B (CMD as main program, not s6-supervised)
76
+
77
+ The original plan (v1–v3) called for main hermes to run as a supervised s6-rc service. Two real s6-overlay v3 mechanics blocked that:
78
+
79
+ 1. **cont-init.d scripts receive no CMD args** — so the stage2 hook can't parse `docker run <image> chat -q "hi"` to set `HERMES_ARGS` for a service `run` script to consume.
80
+ 2. **`/run/s6/basedir/bin/halt` does NOT propagate the exit code** written to `/run/s6-linux-init-container-results/exitcode`. Containers always exit 143 (SIGTERM) regardless. Confirmed by skarnet (s6 author) in [issue #477](https://github.com/just-containers/s6-overlay/issues/477): _"if you want a container shutdown, you need to either have your CMD exit, or, if you have no CMD, write the container exit code you want then call halt"_.
81
+
82
+ So we use the s6-overlay-native CMD pattern: `ENTRYPOINT ["/init", "/opt/hermes/docker/main-wrapper.sh"]`. /init prepends the wrapper to user args automatically — so `docker run <image> --version` becomes `/init main-wrapper.sh --version`, and `--version` doesn't get intercepted by /init's POSIX shell. The wrapper drops to hermes via `s6-setuidgid`, then exec's the chosen program. The program's exit code becomes the container exit code, exactly matching the pre-s6 tini contract.
83
+
84
+ Trade-off: main hermes is unsupervised under s6. That exactly matches its behavior under tini (the pre-s6 image). Dashboard supervision is the only **new** guarantee — and per-profile gateways under `/run/service/` get full supervision.
85
+
86
+ ## Quick recipes
87
+
88
+ ### Verify s6 is PID 1 in a running container
89
+
90
+ ```sh
91
+ docker exec <c> sh -c 'cat /proc/1/comm; readlink /proc/1/exe'
92
+ # Expect: s6-svscan or init / /package/admin/s6/.../s6-svscan
93
+ ```
94
+
95
+ ### Inspect a profile gateway service
96
+
97
+ ```sh
98
+ # /command/ isn't on docker-exec PATH — use absolute path
99
+ docker exec <c> /command/s6-svstat /run/service/gateway-<name>
100
+ # "up (pid …) … seconds" → running
101
+ # "down (exitcode N) … seconds, normally up, want up, …" → s6 wants it up but the process keeps exiting (crash loop)
102
+ # "down … normally up, ready …" → user stopped it
103
+ ```
104
+
105
+ ### Bring a service up/down manually
106
+
107
+ ```sh
108
+ docker exec <c> /command/s6-svc -u /run/service/gateway-<name> # up
109
+ docker exec <c> /command/s6-svc -d /run/service/gateway-<name> # down
110
+ docker exec <c> /command/s6-svc -t /run/service/gateway-<name> # SIGTERM (restart)
111
+ ```
112
+
113
+ ### Watch the cont-init reconciler log
114
+
115
+ ```sh
116
+ docker exec <c> tail -n 50 /opt/data/logs/container-boot.log
117
+ # 2026-05-21T06:18:05+0000 profile=coder prior_state=running action=started
118
+ # 2026-05-21T06:18:05+0000 profile=writer prior_state=stopped action=registered
119
+ ```
120
+
121
+ ### Add a new static service
122
+
123
+ 1. Create `docker/s6-rc.d/<name>/type` with `longrun\n` and `docker/s6-rc.d/<name>/run` (use `#!/command/with-contenv sh` + `# shellcheck shell=sh`).
124
+ 2. Drop to hermes via `s6-setuidgid hermes` at the top of run (unless you specifically need root).
125
+ 3. Create empty `docker/s6-rc.d/<name>/dependencies.d/base` so it waits for the base bundle.
126
+ 4. Create empty `docker/s6-rc.d/user/contents.d/<name>` so it joins the user bundle.
127
+ 5. The `COPY docker/s6-rc.d/` in the Dockerfile picks it up automatically — no other changes.
128
+
129
+ ### Change the per-profile gateway run command
130
+
131
+ Edit `S6ServiceManager._render_run_script` in `hermes_cli/service_manager.py`. The function is also called by `hermes_cli/container_boot.py::_register_service` during boot reconciliation, so it's the single source of truth. Update the corresponding assertion in `tests/hermes_cli/test_service_manager.py::test_s6_register_creates_service_dir_and_triggers_scan`.
132
+
133
+ ### Run the docker test harness
134
+
135
+ ```sh
136
+ docker build -t hermes-agent-harness:latest .
137
+ HERMES_TEST_IMAGE=hermes-agent-harness:latest scripts/run_tests.sh tests/docker/ -v
138
+ # Expect 19 passed, 0 xfailed against the s6 image
139
+ ```
140
+
141
+ The harness lives in `tests/docker/` and skips when Docker isn't available. The per-test timeout is bumped to 180s (see `tests/docker/conftest.py`).
142
+
143
+ ## Common pitfalls
144
+
145
+ ### "command not found" via `docker exec`
146
+
147
+ `/command/` (where s6-overlay puts its binaries) is on PATH only for processes spawned by the supervision tree — services, cont-init.d, main-wrapper.sh. `docker exec <c> s6-svstat …` will fail with "command not found"; always use the absolute path `/command/s6-svstat`. The `hermes` binary works because the Dockerfile adds `/opt/hermes/.venv/bin` to the runtime `ENV PATH`.
148
+
149
+ ### Profile directory ownership
150
+
151
+ The cont-init reconciler runs as hermes (`s6-setuidgid hermes` in `02-reconcile-profiles`). If a profile dir ends up root-owned (e.g. because `docker exec <c> hermes profile create …` ran as root by default), the reconciler can't read SOUL.md and fails with `PermissionError`. Mitigation: `stage2-hook.sh` chowns `$HERMES_HOME/profiles` to hermes on **every** boot, idempotently. Don't remove that block.
152
+
153
+ ### Files written by `docker exec` are root-owned
154
+
155
+ `docker exec` defaults to root. Either pass `--user hermes` or rely on the stage2 chown sweep next reboot. Don't write files under `$HERMES_HOME/profiles/<name>/` as root manually — the next reconcile pass will sweep them but in-flight operations may hit perm errors.
156
+
157
+ ### Service slot exists but s6-svstat says "s6-supervise not running"
158
+
159
+ The service directory is on tmpfs and was wiped on container restart. Either the cont-init reconciler hasn't run yet (give it a moment after `docker restart`) or it failed. Check `docker logs <c> | grep '02-reconcile'`.
160
+
161
+ ### Gateway starts then immediately exits (`down (exitcode 1)` in svstat)
162
+
163
+ Most likely the profile has no model or auth configured. The service slot is correct — the gateway itself is unconfigured. Run `hermes -p <profile> setup` first. The s6 supervisor will keep restarting it; that's the desired behavior (when you fix the config, the next attempt succeeds and stays up).
164
+
165
+ ### Reconciler skipped a profile
166
+
167
+ The reconciler keys on the **presence of `SOUL.md`** as the "real profile" marker. `hermes profile create` always seeds it. If a profile dir is missing SOUL.md (stray directory, partial restore, backup-in-progress), the reconciler skips it intentionally. Add a `SOUL.md` (even empty) to opt back in.
168
+
169
+ ### "Help, the container exits 143!"
170
+
171
+ Check whether something is invoking `s6-svscanctl -t` or `/run/s6/basedir/bin/halt` — both cause /init to begin stage 3 shutdown but return 143 (SIGTERM) rather than the desired exit code. This was the Phase 2 architecture pivot from A to B. For container shutdown with a real exit code, you must let the CMD (main-wrapper.sh) exit normally; do **not** try to control exit from a finish script.
172
+
173
+ ## Related skills
174
+
175
+ - `hermes-agent-dev`: General hermes-agent codebase navigation
176
+ - `hermes-tool-quirks`: Specific Hermes-tool workarounds (sed/grep/etc.) — load when debugging the s6 stack's interaction with hermes built-in tools.
@@ -0,0 +1,319 @@
1
+ ---
2
+ name: node-inspect-debugger
3
+ description: "Debug Node.js via --inspect + Chrome DevTools Protocol CLI."
4
+ version: 1.0.0
5
+ author: Hermes Agent
6
+ license: MIT
7
+ platforms: [linux, macos, windows]
8
+ metadata:
9
+ hermes:
10
+ tags: [debugging, nodejs, node-inspect, cdp, breakpoints, ui-tui]
11
+ related_skills: [systematic-debugging, python-debugpy, debugging-hermes-tui-commands]
12
+ ---
13
+
14
+ # Node.js Inspect Debugger
15
+
16
+ ## Overview
17
+
18
+ When `console.log` isn't enough, drive Node's built-in V8 inspector programmatically from the terminal. You get real breakpoints, step in/over/out, call-stack walking, local/closure scope dumps, and arbitrary expression evaluation in the paused frame.
19
+
20
+ Two tools, pick one:
21
+
22
+ - **`node inspect`** — built-in, zero install, CLI REPL. Best for quick poking.
23
+ - **`ndb` / CDP via `chrome-remote-interface`** — scriptable from Node/Python; best when you want to automate many breakpoints, collect state across runs, or debug non-interactively from an agent loop.
24
+
25
+ **Prefer `node inspect` first.** It's always available and the REPL is fast.
26
+
27
+ ## When to Use
28
+
29
+ - A Node test fails and you need to see intermediate state
30
+ - ui-tui crashes or behaves wrong and you want to inspect React/Ink state pre-render
31
+ - tui_gateway child processes (`_SlashWorker`, PTY bridge workers) misbehave
32
+ - You need to inspect a value in a closure that `console.log` can't reach without patching
33
+ - Perf: attach to a running process to capture a CPU profile or heap snapshot
34
+
35
+ **Don't use for:** things `console.log` solves in under a minute. Breakpoint-driven debugging is heavier; use it when the payoff is real.
36
+
37
+ ## Quick Reference: `node inspect` REPL
38
+
39
+ Launch paused on first line:
40
+
41
+ ```bash
42
+ node inspect path/to/script.js
43
+ # or with tsx
44
+ node --inspect-brk $(which tsx) path/to/script.ts
45
+ ```
46
+
47
+ The `debug>` prompt accepts:
48
+
49
+ | Command | Action |
50
+ |---|---|
51
+ | `c` or `cont` | continue |
52
+ | `n` or `next` | step over |
53
+ | `s` or `step` | step into |
54
+ | `o` or `out` | step out |
55
+ | `pause` | pause running code |
56
+ | `sb('file.js', 42)` | set breakpoint at file.js line 42 |
57
+ | `sb(42)` | set breakpoint at line 42 of current file |
58
+ | `sb('functionName')` | break when function is called |
59
+ | `cb('file.js', 42)` | clear breakpoint |
60
+ | `breakpoints` | list all breakpoints |
61
+ | `bt` | backtrace (call stack) |
62
+ | `list(5)` | show 5 lines of source around current position |
63
+ | `watch('expr')` | evaluate expr on every pause |
64
+ | `watchers` | show watched expressions |
65
+ | `repl` | drop into REPL in current scope (Ctrl+C to exit REPL) |
66
+ | `exec expr` | evaluate expression once |
67
+ | `restart` | restart script |
68
+ | `kill` | kill the script |
69
+ | `.exit` | quit debugger |
70
+
71
+ **In the `repl` sub-mode:** type any JS expression, including access to locals/closure variables. `Ctrl+C` exits back to `debug>`.
72
+
73
+ ## Attaching to a Running Process
74
+
75
+ When the process is already running (e.g. a long-lived dev server or the TUI gateway):
76
+
77
+ ```bash
78
+ # 1. Send SIGUSR1 to enable the inspector on an existing process
79
+ kill -SIGUSR1 <pid>
80
+ # Node prints: Debugger listening on ws://127.0.0.1:9229/<uuid>
81
+
82
+ # 2. Attach the debugger CLI
83
+ node inspect -p <pid>
84
+ # or by URL
85
+ node inspect ws://127.0.0.1:9229/<uuid>
86
+ ```
87
+
88
+ To start a process with the inspector from the beginning:
89
+
90
+ ```bash
91
+ node --inspect script.js # listen on 127.0.0.1:9229, keep running
92
+ node --inspect-brk script.js # listen AND pause on first line
93
+ node --inspect=0.0.0.0:9230 script.js # custom host:port
94
+ ```
95
+
96
+ For TypeScript via tsx:
97
+
98
+ ```bash
99
+ node --inspect-brk --import tsx script.ts
100
+ # or older tsx
101
+ node --inspect-brk -r tsx/cjs script.ts
102
+ ```
103
+
104
+ ## Programmatic CDP (scripting from terminal)
105
+
106
+ When you want to automate — set many breakpoints, capture scope state, script a repro — use `chrome-remote-interface`:
107
+
108
+ ```bash
109
+ npm i -g chrome-remote-interface # or project-local
110
+ # Start your target:
111
+ node --inspect-brk=9229 target.js &
112
+ ```
113
+
114
+ Driver script (save as `/tmp/cdp-debug.js`):
115
+
116
+ ```javascript
117
+ const CDP = require('chrome-remote-interface');
118
+
119
+ (async () => {
120
+ const client = await CDP({ port: 9229 });
121
+ const { Debugger, Runtime } = client;
122
+
123
+ Debugger.paused(async ({ callFrames, reason }) => {
124
+ const top = callFrames[0];
125
+ console.log(`PAUSED: ${reason} @ ${top.url}:${top.location.lineNumber + 1}`);
126
+
127
+ // Walk scopes for locals
128
+ for (const scope of top.scopeChain) {
129
+ if (scope.type === 'local' || scope.type === 'closure') {
130
+ const { result } = await Runtime.getProperties({
131
+ objectId: scope.object.objectId,
132
+ ownProperties: true,
133
+ });
134
+ for (const p of result) {
135
+ console.log(` ${scope.type}.${p.name} =`, p.value?.value ?? p.value?.description);
136
+ }
137
+ }
138
+ }
139
+
140
+ // Evaluate an expression in the paused frame
141
+ const { result } = await Debugger.evaluateOnCallFrame({
142
+ callFrameId: top.callFrameId,
143
+ expression: 'typeof state !== "undefined" ? JSON.stringify(state) : "n/a"',
144
+ });
145
+ console.log('state =', result.value ?? result.description);
146
+
147
+ await Debugger.resume();
148
+ });
149
+
150
+ await Runtime.enable();
151
+ await Debugger.enable();
152
+
153
+ // Set a breakpoint by URL regex + line
154
+ await Debugger.setBreakpointByUrl({
155
+ urlRegex: '.*app\\.tsx$',
156
+ lineNumber: 119, // 0-indexed
157
+ columnNumber: 0,
158
+ });
159
+
160
+ await Runtime.runIfWaitingForDebugger();
161
+ })();
162
+ ```
163
+
164
+ Run it:
165
+
166
+ ```bash
167
+ node /tmp/cdp-debug.js
168
+ ```
169
+
170
+ Hermes-specific note: `chrome-remote-interface` is NOT in `ui-tui/package.json`. Install it to a throwaway location if you don't want to dirty the project:
171
+
172
+ ```bash
173
+ mkdir -p /tmp/cdp-tools && cd /tmp/cdp-tools && npm i chrome-remote-interface
174
+ NODE_PATH=/tmp/cdp-tools/node_modules node /tmp/cdp-debug.js
175
+ ```
176
+
177
+ ## Debugging Hermes ui-tui
178
+
179
+ The TUI is built Ink + tsx. Two common scenarios:
180
+
181
+ ### Debugging a single Ink component under dev
182
+
183
+ `ui-tui/package.json` has `npm run dev` (tsx --watch). Add `--inspect-brk` by running tsx directly:
184
+
185
+ ```bash
186
+ cd /home/bb/hermes-agent/ui-tui
187
+ npm run build # produce dist/ once so transpile isn't needed on first load
188
+ node --inspect-brk dist/entry.js
189
+ # In another terminal:
190
+ node inspect -p <node pid>
191
+ ```
192
+
193
+ Then inside `debug>`:
194
+
195
+ ```
196
+ sb('dist/app.js', 220) # or wherever the suspect render is
197
+ cont
198
+ ```
199
+
200
+ When it pauses, `repl` → inspect `props`, state refs, `useInput` handler values, etc.
201
+
202
+ ### Debugging a running `hermes --tui`
203
+
204
+ The TUI spawns Node from the Python CLI. Easiest path:
205
+
206
+ ```bash
207
+ # 1. Launch TUI
208
+ hermes --tui &
209
+ TUI_PID=$(pgrep -f 'ui-tui/dist/entry' | head -1)
210
+
211
+ # 2. Enable inspector on that Node PID
212
+ kill -SIGUSR1 "$TUI_PID"
213
+
214
+ # 3. Find the WS URL
215
+ curl -s http://127.0.0.1:9229/json/list | jq -r '.[0].webSocketDebuggerUrl'
216
+
217
+ # 4. Attach
218
+ node inspect ws://127.0.0.1:9229/<uuid>
219
+ ```
220
+
221
+ Interacting with the TUI (typing in its window) continues to advance execution; your debugger can pause it on a breakpoint at any `sb(...)`.
222
+
223
+ ### Debugging `_SlashWorker` / PTY child processes
224
+
225
+ Those are Python, not Node — use the `python-debugpy` skill for them. Only Node portions (Ink UI, tui_gateway client, tsx-run tests under `ui-tui/`) use this skill.
226
+
227
+ ## Running Vitest Tests Under the Debugger
228
+
229
+ ```bash
230
+ cd /home/bb/hermes-agent/ui-tui
231
+ # Run a single test file paused on entry
232
+ node --inspect-brk ./node_modules/vitest/vitest.mjs run --no-file-parallelism src/app/foo.test.tsx
233
+ ```
234
+
235
+ In another terminal: `node inspect -p <pid>`, then `sb('src/app/foo.tsx', 42)`, `cont`.
236
+
237
+ Use `--no-file-parallelism` (vitest) or `--runInBand` (jest) so only one worker exists — debugging a pool is painful.
238
+
239
+ ## Heap Snapshots & CPU Profiles (Non-interactive)
240
+
241
+ From the CDP driver above, swap Debugger for `HeapProfiler` / `Profiler`:
242
+
243
+ ```javascript
244
+ // CPU profile for 5 seconds
245
+ await client.Profiler.enable();
246
+ await client.Profiler.start();
247
+ await new Promise(r => setTimeout(r, 5000));
248
+ const { profile } = await client.Profiler.stop();
249
+ require('fs').writeFileSync('/tmp/cpu.cpuprofile', JSON.stringify(profile));
250
+ // Open /tmp/cpu.cpuprofile in Chrome DevTools → Performance tab
251
+ ```
252
+
253
+ ```javascript
254
+ // Heap snapshot
255
+ await client.HeapProfiler.enable();
256
+ const chunks = [];
257
+ client.HeapProfiler.addHeapSnapshotChunk(({ chunk }) => chunks.push(chunk));
258
+ await client.HeapProfiler.takeHeapSnapshot({ reportProgress: false });
259
+ require('fs').writeFileSync('/tmp/heap.heapsnapshot', chunks.join(''));
260
+ ```
261
+
262
+ ## Common Pitfalls
263
+
264
+ 1. **Wrong line numbers in TS source.** Breakpoints hit the emitted JS, not the `.ts`. Either (a) break in the built `dist/*.js`, or (b) enable sourcemaps (`node --enable-source-maps`) and use `sb('src/app.tsx', N)` — but only with CDP clients that follow sourcemaps. `node inspect` CLI does not.
265
+
266
+ 2. **`--inspect` vs `--inspect-brk`.** `--inspect` starts the inspector but doesn't pause; your script races past your first breakpoint if you attach too late. Use `--inspect-brk` when you need to set breakpoints before any code runs.
267
+
268
+ 3. **Port collisions.** Default is `9229`. If multiple Node processes are inspecting, pass `--inspect=0` (random port) and read the actual URL from `/json/list`:
269
+ ```bash
270
+ curl -s http://127.0.0.1:9229/json/list # lists all inspectable targets on the host
271
+ ```
272
+
273
+ 4. **Child processes.** `--inspect` on a parent does NOT inspect its children. Use `NODE_OPTIONS='--inspect-brk' node parent.js` to propagate to every child; be aware they all need unique ports (Node auto-increments when `NODE_OPTIONS='--inspect'` is inherited).
274
+
275
+ 5. **Background kills.** If you `Ctrl+C` out of `node inspect` while the target is paused, the target stays paused. Either `cont` first, or `kill` the target explicitly.
276
+
277
+ 6. **Running `node inspect` through an agent terminal.** It's a PTY-friendly REPL. In Hermes, launch it with `terminal(pty=true)` or `background=true` + `process(action='submit', data='...')`. Non-PTY foreground mode will work for one-shot commands but not for interactive stepping.
278
+
279
+ 7. **Security.** `--inspect=0.0.0.0:9229` exposes arbitrary code execution. Always bind to `127.0.0.1` (the default) unless you have an isolated network.
280
+
281
+ ## Verification Checklist
282
+
283
+ After setting up a debug session, verify:
284
+
285
+ - [ ] `curl -s http://127.0.0.1:9229/json/list` returns exactly the target you expect
286
+ - [ ] First breakpoint actually hits (if it doesn't, you likely missed `--inspect-brk` or attached after execution completed)
287
+ - [ ] Source listing at pause shows the right file (mismatch = sourcemap issue, see pitfall 1)
288
+ - [ ] `exec process.pid` in `repl` returns the PID you meant to attach to
289
+
290
+ ## One-Shot Recipes
291
+
292
+ **"Why is this variable undefined at line X?"**
293
+ ```bash
294
+ node --inspect-brk script.js &
295
+ node inspect -p $!
296
+ # debug>
297
+ sb('script.js', X)
298
+ cont
299
+ # paused. Now:
300
+ repl
301
+ > myVariable
302
+ > Object.keys(this)
303
+ ```
304
+
305
+ **"What's the call path into this function?"**
306
+ ```
307
+ debug> sb('suspectFn')
308
+ debug> cont
309
+ # paused on entry
310
+ debug> bt
311
+ ```
312
+
313
+ **"This async chain hangs — where?"**
314
+ ```
315
+ # Start with --inspect (no -brk), let it run to the hang, then:
316
+ debug> pause
317
+ debug> bt
318
+ # Now you see the stuck frame
319
+ ```
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: plan
3
+ description: "Plan mode: write markdown plan to .hermes/plans/, no exec."
4
+ version: 1.0.0
5
+ author: Hermes Agent
6
+ license: MIT
7
+ platforms: [linux, macos, windows]
8
+ metadata:
9
+ hermes:
10
+ tags: [planning, plan-mode, implementation, workflow]
11
+ related_skills: [writing-plans, subagent-driven-development]
12
+ ---
13
+
14
+ # Plan Mode
15
+
16
+ Use this skill when the user wants a plan instead of execution.
17
+
18
+ ## Core behavior
19
+
20
+ For this turn, you are planning only.
21
+
22
+ - Do not implement code.
23
+ - Do not edit project files except the plan markdown file.
24
+ - Do not run mutating terminal commands, commit, push, or perform external actions.
25
+ - You may inspect the repo or other context with read-only commands/tools when needed.
26
+ - Your deliverable is a markdown plan saved inside the active workspace under `.hermes/plans/`.
27
+
28
+ ## Output requirements
29
+
30
+ Write a markdown plan that is concrete and actionable.
31
+
32
+ Include, when relevant:
33
+ - Goal
34
+ - Current context / assumptions
35
+ - Proposed approach
36
+ - Step-by-step plan
37
+ - Files likely to change
38
+ - Tests / validation
39
+ - Risks, tradeoffs, and open questions
40
+
41
+ If the task is code-related, include exact file paths, likely test targets, and verification steps.
42
+
43
+ ## Save location
44
+
45
+ Save the plan with `write_file` under:
46
+ - `.hermes/plans/YYYY-MM-DD_HHMMSS-<slug>.md`
47
+
48
+ Treat that as relative to the active working directory / backend workspace. Hermes file tools are backend-aware, so using this relative path keeps the plan with the workspace on local, docker, ssh, modal, and daytona backends.
49
+
50
+ If the runtime provides a specific target path, use that exact path.
51
+ If not, create a sensible timestamped filename yourself under `.hermes/plans/`.
52
+
53
+ ## Interaction style
54
+
55
+ - If the request is clear enough, write the plan directly.
56
+ - If no explicit instruction accompanies `/plan`, infer the task from the current conversation context.
57
+ - If it is genuinely underspecified, ask a brief clarifying question instead of guessing.
58
+ - After saving the plan, reply briefly with what you planned and the saved path.