Commit Graph

7 Commits

Author SHA1 Message Date
kshitijk4poor
ea2f4a688e fix(disk-cleanup): declare pre_tool_call in provides_hooks; tidy owner keying
The plugin now registers a pre_tool_call hook, but plugin.yaml still listed
only post_tool_call/on_session_end, so `plugin doctor` warned "registration
adds hook 'pre_tool_call' not listed in provides_hooks" and catalog/capability
listings under-reported what the plugin hooks.

Also: README notes calls without a tool_call_id (execute_code RPC) are not
tracked; a single _owner() helper keys both _pre_call and
_recent_test_tracks so the two can't drift; drop the unused `result`
parameter from the post hook (still absorbed by **_); trim the _pre_call
comment.
2026-10-02 00:55:59 +05:30
Froraut
c467053f52 fix(disk-cleanup): address review — key snapshots per session, fail closed on unsnapshotted paths
The pre/post snapshot handshake had two ways to mark a user's existing
file as created, which queues it for deletion when the turn ends:

- Snapshots were keyed by tool_call_id alone. llama.cpp sends one
  constant id for every call. When session B's pre hook ran between
  session A's pre and post, A consumed B's snapshot. A's
  already-existing test_user.py then looked "not in existing", and A
  tracked it.
- Every pre_tool_call hook sees the original args. Another plugin's
  `modify` directive is merged afterwards, and post_tool_call sees the
  final args. A path swapped in by that hook was never snapshotted, so
  "not in existing" held for it too. The file was tracked even when the
  write was refused.

Snapshots are now keyed by (task_id or session_id, tool_call_id), the
identity both hooks receive from the dispatcher. They store the paths the
call named that did not exist yet, instead of the ones that did. The post
hook tracks a path only if its own snapshot saw it absent and it exists
now. Any path the snapshot did not cover fails closed.

I reproduced both end to end through model_tools.handle_function_call
with a second plugin's modify hook and two interleaved sessions. The
user's file was deleted before this fix and survives after it, and a
file the call really created is still cleaned up. The README hook
contract is updated to match.

(cherry picked from commit 8d0b853981f1ab0775549f4831a3d4f733a46106)
2026-10-02 00:55:59 +05:30
Froraut
17d55a2032 fix(disk-cleanup): track only files a tool call created, never pre-existing ones
post_tool_call sent write_file/patch paths, every absolute path in a
terminal command AND every path in its output to dg.track(), gated only
on `p.exists()` plus the test_*/tmp_* name rule. Category 'test' is
deleted at age 0 by quick(), which on_session_end runs after every turn,
and directories are rmtree'd. So a user's cron script
$HERMES_HOME/scripts/test_uptime.py the agent merely patched, or a hook
dir $HERMES_HOME/hooks/test_notify it listed (`ls -la`, `find ... -name
'test_*'`), was irreversibly deleted when the turn ended — then the
emptied scripts/ and hooks/ dirs too. The plugin's contract is files
"created during Hermes sessions".

A pre_tool_call hook now snapshots which of the call's argument paths
already exist (keyed by tool_call_id; it never raises, since pre hooks
fail closed; entries expire after an hour if the post hook never
fires). post_tool_call tracks a path only when the call named it, it
did not exist before and exists now. Paths seen only in terminal output
carry no such proof and are no longer tracked; no snapshot means
nothing is tracked. Existing tests now drive the real hook order.

(cherry picked from commit e0e0e1f7450df0c75a8499fe57b63dc46c6d2af2)
2026-10-02 00:55:59 +05:30
teknium1
4586cde64d chore: mark the deliberate /tmp literals and shrink the lint baseline to one code block
The seventeen remaining literals are container-side paths, AF_UNIX socket-path-limit
candidates on darwin, detection needles, guard regexes and guidance text that tells the
model to avoid /tmp. Each carries an inline `no-tmp: ok — <why>` so the reason lives
next to the line; the baseline keeps only a fenced tree listing where a marker would render.
2026-09-19 10:44:26 -07:00
teknium1
33f3d96b99 fix(disk-cleanup): never rmtree protected top-level dirs; never track kanban/
The tracked-item delete path in quick() called shutil.rmtree() on any tracked
directory without consulting the protection list, which only the empty-dir
sweep used. guess_category() files every path under cache/ as "temp", so a
terminal command that merely mentioned $HERMES_HOME/cache tracked the
directory itself, and 7 days later quick() removed cache/ wholesale — taking
cache/terminal (terminal snapshots) with it and breaking every later command
with a mktemp "No such file or directory".

Fix: _is_protected_dir() — a tracked DIRECTORY that is HERMES_HOME itself or
sits under an _EMPTY_DIR_PROTECTED_TOP_LEVEL tree is never tracked by
guess_category(), never listed by dry_run(), and skipped (logged SKIPPED,
entry dropped) by quick(). Files under cache/ still age out as before.

kanban/ (task attachments and workspaces have their own lifecycle) is added to
both _NEVER_TRACK_TOP_LEVEL and _EMPTY_DIR_PROTECTED_TOP_LEVEL; stale pre-fix
"test" entries under it are dropped by the existing re-validation instead of
deleted. The kanban row was first proposed in #80842 (@nicha16).

Fixes #114552
2026-09-18 09:22:13 -07:00
teknium1
0631710ae4 fix(disk-cleanup): protect every per-profile user tree and trim tests to two invariants
Extends the salvaged #112860 entry (`workspace`) to the whole class: `plans` and
`home` are bootstrapped alongside `workspace` by `hermes_cli/profiles.py::_PROFILE_DIRS`
and listed as user data in `profile_distribution.py::USER_OWNED_EXCLUDE`, so a
`test_*`/`tmp_*` file inside any of them is a user's file, never scratch.

Trims the contributor's five tests to two invariants: the end-to-end
post_tool_call -> on_session_end path (workspace file survives, a root-level
`tmp_scratch.py` control is still removed) and the empty-dir sweep leaving a
directory under `workspace/` alone. Documents the protected trees in the plugin
README and the built-in-plugins page.

Dropped: test_workspace_project_tree_never_tracked, test_quick_keeps_workspace_test_file,
test_root_level_test_file_still_auto_deleted (folded into the E2E test as its control).

Part of #112859.
2026-09-16 16:54:19 -07:00
Teknium
a25c8c6a56 docs(plugins): rename disk-guardian to disk-cleanup + bundled-plugins docs
The original name was cute but non-obvious; disk-cleanup says what it
does. Plugin directory, script, state path, log lines, slash command,
and test module all renamed. No user-visible state exists yet, so no
migration path is needed.

New website page "Built-in Plugins" documents the <repo>/plugins/<name>/
source, how discovery interacts with user/project plugins, the
HERMES_DISABLE_BUNDLED_PLUGINS escape hatch, disk-cleanup's hook
behaviour and deletion rules, and guidance on when a plugin belongs
bundled vs. user-installable. Added to the Features → Core sidebar next
to the main Plugins page, with a cross-reference from plugins.md.
2026-04-20 04:46:45 -07:00