Skip to content

fix(claude): keep statusline wrappers chaining trail helper (#756) - #760

Merged
shhdwi merged 1 commit into
trailhq:mainfrom
ege-arhan:fix/init-statusline-shadowing-756
Nov 7, 2026
Merged

shhdwi merged 1 commit into
trailhq:mainfrom
ege-arhan:fix/init-statusline-shadowing-756

Conversation

@ege-arhan

Copy link
Copy Markdown
Contributor

Closes #756

What changed

isGraftStatusline used a substring regex (/(graft|trail)-statusline\.cjs|\.trail\/statusline\.cjs/) to check whether a settings entry belongs to Trail/Graft. When a user created a custom wrapper or chained statusline command piping to or calling .trail/statusline.cjs, applyStatusline matched the substring, treated the command as Trail's own, and replaced it on re-merge.

Tightened STATUSLINE_HELPER to match standalone node invocations of the shim (including legacy shapes and sh -c wrappers) from start to finish, leaving command pipelines and wrapper scripts preserved as foreign status lines.

Verification

  • Added a test in test/claude-settings-merge.test.ts for chained wrapper commands.
  • Ran node --import tsx --test test/claude-settings-merge.test.ts (all 20 tests pass).

@trailhq-graft

trailhq-graft Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

🌱 graft blast radius

1 area changed → 4 areas can be affected. 11 dependent symbols, depth 2.
Tag: @anirudhkumar-nanonets — 4 of 5 areas · @shhdwi — 5 of 5 areas

flowchart TB
  A0(("Host Integration<br/>6 symbols"))
  A1(("CLI Entry Point<br/>2 symbols"))
  A2(("Claude Initialization<br/>2 symbols"))
  A3(("Installation Paths<br/>1 symbol"))
  classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
  class A0,A1,A2,A3 reached;
Loading
Can be affected Symbols Nearest hop Reached from
Host Integration 6 src/hosts/claude-global.ts:L1-L278 claude-global.ts — imports, depth 1 Settings Merge
CLI Entry Point 2 src/cli.ts:L1-L2847 cli.ts — imports, depth 1 Settings Merge
Claude Initialization 2 src/claude/init.ts:L1-L305 init.ts — imports, depth 1 Settings Merge
Installation Paths 1 src/init/install-paths.ts:L1-L84 install-paths.ts — imports, depth 2 Settings Merge
Who knows this code — 2 people across 5 areas
Area Who knows it
Settings Merge · changed @anirudhkumar-nanonets — 10 commits, last 10d ago · @shhdwi — 4 commits, last 14d ago
Host Integration · affected @shhdwi — 14 commits, last 10d ago · @anirudhkumar-nanonets — 6 commits, last 22d ago
CLI Entry Point · affected @anirudhkumar-nanonets — 64 commits, last 4d ago · @shhdwi — 51 commits, last 10d ago
Claude Initialization · affected @anirudhkumar-nanonets — 26 commits, last 10d ago · @shhdwi — 15 commits, last 10d ago
Installation Paths · affected @shhdwi — 1 commit, last 14d ago

Ownership is git history over each area's own files, weighted towards recent work (120-day half-life). Merge commits and bots are dropped, and you are dropped from your own PR. A name with no @ has no GitHub handle in its commit email — tag them by hand, or add a .mailmap entry. A suggestion from history, not a CODEOWNERS rule.

All 11 dependent symbols, grouped by area

Host Integration — 6 symbols in 6 files

  • src/hosts/claude-global.ts:L1-L278 — claude-global.ts (imports, depth 1)
    31: import { mergeGraftHooks } from '../claude/settings-merge.js';
  • src/hosts/codex-hooks.ts:L1-L165 — codex-hooks.ts (imports, depth 1)
    9: import { failOpen } from '../claude/settings-merge.js';
  • src/hosts/cursor-hooks.ts:L1-L117 — cursor-hooks.ts (imports, depth 1)
    32: import { failOpen } from '../claude/settings-merge.js';
  • src/hosts/retract.ts:L1-L545 — retract.ts (imports, depth 1)
    37: import { isGraftAllowEntry, isGraftFooterRegex } from '../claude/settings-merge.js';
  • src/hosts/init.ts:L1-L124 — init.ts (imports, depth 2)
  • src/hosts/plan.ts:L1-L101 — plan.ts (imports, depth 2)

CLI Entry Point — 2 symbols in 2 files

  • src/cli.ts:L1-L2847 — cli.ts (imports, depth 1)
    23: import { statuslineWanted } from "./claude/settings-merge.js";
  • src/upkeep-run.ts:L1-L103 — upkeep-run.ts (imports, depth 2)

Claude Initialization — 2 symbols in 2 files

  • src/claude/init.ts:L1-L305 — init.ts (imports, depth 1)
    6: import { mergeGraftSettings, mergeTrailShared, mergeTrailLocal } from './settings-merge.js';
  • src/claude/hooks.ts:L1-L580 — hooks.ts (imports, depth 2)

Installation Paths — 1 symbol in 1 file

  • src/init/install-paths.ts:L1-L84 — install-paths.ts (imports, depth 2)
Test signal per changed area — 1 –

Reached = a node under a test path has a resolved edge into the changed symbol. It undercounts anything called indirectly — through a CLI, a spawned process or a dynamic import — so read a low ratio as “look here”, never as a coverage gate.

  • – Settings Merge — 1 test file changed here: test/claude-settings-merge.test.ts
19 test suites also reference this code

19 symbols, kept out of the diagram and the table so they cannot crowd out the areas a reviewer has to look at.

  • test/claude-hook-timeouts.test.ts
  • test/claude-hooks-fail-open-all.test.ts
  • test/claude-init.test.ts
  • test/claude-pre-bash-fail-open.test.ts
  • test/claude-pre-bash-wiring.test.ts
  • test/claude-pre-bash.test.ts
  • test/claude-shim-template.test.ts
  • test/cli-status-codex.test.ts
  • test/graft-to-trail.test.ts
  • test/hosts-claude-global.test.ts
  • test/hosts-codex-hooks-2.test.ts
  • test/hosts-codex-hooks.test.ts
  • test/hosts-codex-trust.test.ts
  • test/hosts-cursor-hooks.test.ts
  • test/hosts-retract.test.ts
  • test/hosts-trail.test.ts
  • test/skills-probes-trail-files.test.ts
  • test/trail-init-layout.test.ts
  • test/trail-init-upgrade.test.ts

graft blast · origin/main...HEAD · depth 2 · 2 changed files

Open the interactive graph → — click an area to see its dependent symbols at file:line.

github-actions Bot added a commit that referenced this pull request Nov 6, 2026
@shhdwi
shhdwi merged commit bc7e9e4 into trailhq:main Nov 7, 2026
8 checks passed
github-actions Bot added a commit that referenced this pull request Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

init writes statusLine into settings.local.json (shadows the user's own), and a wrapper that chains Trail's line is treated as Trail's and replaced

2 participants