Skip to content

fix(coding-agents): don't let one stray file abort the Claude import, and give Prime Agent the companion skill (#3771, #3772) - #3812

Merged
nicoloboschi merged 2 commits into
mainfrom
fix/3771-3772-coding-agents
Aug 26, 2026
Merged

fix(coding-agents): don't let one stray file abort the Claude import, and give Prime Agent the companion skill (#3771, #3772)#3812
nicoloboschi merged 2 commits into
mainfrom
fix/3771-3772-coding-agents

Conversation

@nicoloboschi

Copy link
Copy Markdown
Collaborator

Summary

Two independent coding-agents fixes, both small enough to share a PR.

#3771 — a stray file aborted the whole Claude history import. claudeHistory prefilters ~/.claude/projects candidates by encoded NAME and hands each match to jsonlFiles, which gated on existsSync — TRUE for a regular file — and then readdirSync, which throws ENOTDIR. That escaped importLocalHistory, which documents that it never throws, and whose caller (importConversations in installer.ts) has no catch of its own: one junk entry killed the entire --import-conversations run instead of costing that entry.

The guard belongs in the listing rather than at the call site the issue suggested — jsonlFiles already owned "there is nothing here to list" via existsSync, and a stray file is that same case reached through a different errno. A listDir helper now holds it, which also closes the identical hole one level up (a regular file at ~/.claude/projects was equally fatal) and sheds a stat per candidate directory plus its TOCTOU window. The dsh reader already handles its own case with a try/catch and is left alone.

#3772 — Prime Agent never received the companion skill. It documents the same discovery roots the other skills-capable hosts use, so it can load the skill and today only does so by accident, when the user also runs Codex or dsh and it picks ours up from the shared ~/.agents root. installSkill/uninstallSkill are now wired into its adapter, into Prime Agent's own ~/.prime/agent/skills: uninstallSkill removes a fixed directory name, so installing to the shared root would make uninstall prime-agent delete Codex's and dsh's copy. Uninstall's skill removal sits outside the settings.json guard so a hand-deleted settings file can't strand the skill.

Closes #3771.
Closes #3772.

Type of change

  • Feature
  • Bug fix
  • Hotfix
  • Spike / exploration
  • Documentation
  • Refactor

Test plan

  • src/core/history.test.ts — two new Claude regression tests: a stray file named like the project dir of a subdirectory (so the prefix filter hands it to the listing), and a regular file where ~/.claude/projects itself belongs. Both were verified to fail on the pre-fix listing with the exact reported error (ENOTDIR: not a directory, scandir '…/.claude/projects/-Users-x-dev-myrepo-sub'), and the first still imports the real session alongside the junk entry.
  • src/installer.test.ts — prime-agent joins the cross-host skill install/uninstall matrix, plus a test that installing Codex and Prime Agent and then uninstalling Prime Agent leaves the shared ~/.agents copy intact.
  • npx vitest run --exclude 'src/e2e/**' → 658 passed, 23 skipped. ./scripts/hooks/lint.sh clean, ./scripts/hooks/check-unused.sh shows nothing new.
  • README regenerated through npm run skill:build + sync-coding-agents-doc.mjs after linting; only the docs page moved, the skill regions are untouched.

Notes for the reviewer

🤖 Generated with Claude Code

https://claude.ai/code/session_01AHvpDBNP3CXfVL88WnazmC

… and give Prime Agent the skill

`importLocalHistory` documents that it never throws, but the Claude reader did:
`jsonlFiles` gated on `existsSync`, which is TRUE for a regular file sitting where
a project directory was expected, and the `readdirSync` behind it threw ENOTDIR
straight out of `--import-conversations` — one junk entry killed the whole run
instead of costing that entry. A `listDir` helper now owns "there is nothing here
to list", which also closes the same hole one level up on `~/.claude/projects`
itself. (#3771)

Prime Agent documents the same skill-discovery roots the other skills-capable
hosts use but never received the packaged companion skill, so it only ever picked
one up by accident from the shared `~/.agents` root. It now installs into its own
`~/.prime/agent/skills`: `uninstallSkill` removes a fixed directory name, so
writing to the shared root would make `uninstall prime-agent` delete Codex's and
dsh's copy. (#3772)

Closes #3771
Closes #3772

Claude-Session: https://claude.ai/code/session_01AHvpDBNP3CXfVL88WnazmC
@strix-security

strix-security Bot commented Aug 26, 2026

Copy link
Copy Markdown

Strix Security Review

Warning

This pull request has 1 commit after the last Strix review (d14f90e). Strix has not reviewed these changes.
Automatic review on push is off for this repository. To review the latest changes, tag @strix-security in a comment, or turn on re-review on push.

No security issues found.

Updated for d14f90e.


Reviewed by Strix
Re-run review · Configure security review settings

@nicoloboschi
nicoloboschi merged commit e04d02e into main Aug 26, 2026
91 checks passed
@nicoloboschi
nicoloboschi deleted the fix/3771-3772-coding-agents branch August 26, 2026 12:50
feniix added a commit to feniix/hindsight that referenced this pull request Aug 28, 2026
…bort the history import

dshHistory guarded its root with existsSync, which is true for a regular
file, and then called readdirSync on it unguarded: a file at
~/.dsh/sessions threw ENOTDIR out of importLocalHistory, which documents
that it never throws, and whose caller in installer.ts does not catch.
Route the root listing through the module's listDir helper (which vectorize-io#3812
introduced for the Claude reader) and let the per-project loop use it too,
dropping its private try/catch.

Regression test seeds a regular file at the sessions root and fails with
the reported ENOTDIR without the change. A second test covers the
per-project case, which had no importLocalHistory coverage for dsh.

Closes vectorize-io#3771.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant