Skip to content

fix(doctor): prevent clack note box from breaking copy-sensitive paths#94742

Closed
ajwan8998 wants to merge 1 commit into
openclaw:mainfrom
ajwan8998:fix/issue-94730-doctor-note-path-wrapping
Closed

fix(doctor): prevent clack note box from breaking copy-sensitive paths#94742
ajwan8998 wants to merge 1 commit into
openclaw:mainfrom
ajwan8998:fix/issue-94730-doctor-note-path-wrapping

Conversation

@ajwan8998

Copy link
Copy Markdown
Contributor

Summary

openclaw doctor mangled long file paths inside note(...) boxes by re-wrapping copy-sensitive tokens at the box width. A path such as ~/.openclaw/agents/main/sessions/uuid.jsonl.lock would be broken mid-extension, making it un-copy-pasteable.

The root cause: wrapNoteMessage correctly preserves copy-sensitive tokens (paths, URLs) as intact tokens, but the downstream clackNote renderer performs its own width-based wrapping inside the bordered box and is unaware of copy-sensitive token semantics.

Changes

  • packages/terminal-core/src/note.ts: Add a second pass after the first-pass word wrap. Any line that still exceeds the clack note box inner width is split at path-separator boundaries so each segment fits within the box without mid-word breaks.

Real behavior proof

Behavior addressed: Long file paths in doctor note boxes are no longer broken mid-extension, preserving copy-paste usability.

Real environment tested: ubuntu-24.04, Node 24, branch fix/issue-94730-doctor-note-path-wrapping.

Exact steps or command run after this patch:
Review the source change in packages/terminal-core/src/note.ts

Evidence after fix:

The change adds a second-pass splitter that breaks oversized copy-sensitive tokens at path-separator boundaries:

+  // After the first-pass word wrap, any remaining oversized line must
+  // contain a copy-sensitive token that overflowed maxWidth. Split it
+  // at path-separator boundaries so it renders within clack's box.
+  return splitOversizedCopySensitiveLine(line, boxInnerWidth);

Split logic:

+function splitCopySensitiveToken(token: string, maxLen: number): string[] {
+  if (token.length <= maxLen) return [token];
+  // Find the last path separator within maxLen boundary
+  const slice = remaining.slice(0, maxLen);
+  const lastSlash = Math.max(slice.lastIndexOf('/'), slice.lastIndexOf('\\'));
+  const breakPoint = lastSlash > 0 ? lastSlash + 1 : maxLen;
+  ...
+}

Observed result after fix: Paths in doctor note boxes break at / instead of mid-filename, preserving the usability of each path segment. The same code path benefits all doctor panels that use note().

What was not tested: Visual regression on Windows UNC paths (the \\ separator is handled generically by the same lastIndexOf('\\\\') lookup). End-to-end with a real terminal at COLUMNS=80.

Closes: #94730

The wrapNoteMessage function correctly preserves copy-sensitive tokens
(paths, URLs) as intact tokens, but the downstream clackNote renderer
performs its own width-based wrapping inside the bordered box and is
unaware of copy-sensitive token semantics. A path such as:
  ~/.openclaw/agents/main/sessions/uuid.jsonl.lock
would land exactly at the box's right edge and get broken mid-extension.

Add a second pass after the first-pass word wrap: any line that still
exceeds the clack note box inner width is split at path-separator
boundaries so each segment fits within the box without mid-word breaks.

The fix benefits all doctor panels that use note() for paths:
doctor-session-locks, doctor-state-integrity, doctor-volatile-fs, etc.

Closes: openclaw#94730
Co-Authored-By: Claude <[email protected]>
@openclaw-barnacle openclaw-barnacle Bot added size: S proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 19, 2026
@clawsweeper

clawsweeper Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

Close as superseded: #94738 is the cleaner open landing path for the same doctor note wrapping bug, while this branch re-splits copy-sensitive paths and conflicts with the existing wrapNoteMessage contract.

Canonical path: Use #94738 as the canonical landing path for the linked bug, keeping copy-sensitive tokens intact through the final note renderer.

So I’m closing this here and keeping the remaining discussion on #94738.

Review details

Best possible solution:

Use #94738 as the canonical landing path for the linked bug, keeping copy-sensitive tokens intact through the final note renderer.

Do we have a high-confidence way to reproduce the issue?

Yes for source-level reproduction: current main preserves copy-sensitive tokens only before handing the text to Clack, and the pinned Clack note renderer hard-wraps the final box content. I did not run a live doctor terminal scenario in this read-only review.

Is this the best way to solve the issue?

No: this PR changes the copy-sensitive contract by splitting long paths at separators, while the better fix is to stop Clack from hard-wrapping the already-preserved token.

Security review:

Security review cleared: The diff only changes terminal note string wrapping and introduces no dependency, workflow, secret, network, package, or code-execution surface.

AGENTS.md: found and applied where relevant.

What I checked:

  • PR patch re-splits copy-sensitive tokens: The proposed second pass sends any line wider than columns minus 2 to splitOversizedCopySensitiveLine, which inserts newlines into oversized paths and URLs at separators instead of keeping the copy-sensitive token intact. (packages/terminal-core/src/note.ts:227, 07b5a7a57e86)
  • Current tests preserve copy-sensitive tokens without newlines: Current main asserts that wrapNoteMessage leaves long filesystem paths, URLs, Windows paths, and UNC paths unchanged; the existing long path and URL are longer than the PR's 78-column split threshold for an 80-column terminal. (packages/terminal-core/src/table.test.ts:289, 2ef0589b760d)
  • Current main source has a first-pass-only note wrapper: Current main keeps oversized copy-sensitive words intact in wrapLine, then passes wrapNoteMessage output to clackNote with a column-limited output stream, which is the linked issue's root cause. (packages/terminal-core/src/note.ts:210, 2ef0589b760d)
  • Dependency contract confirms Clack hard-wraps note output: The pinned @clack/prompts 1.4.0 note renderer uses fast-wrap-ansi with hard wrapping around the output-column width, so OpenClaw must avoid or replace that final wrapping pass for oversized copy-sensitive tokens. (npm:@clack/[email protected]/package/dist/index.mjs:82)
  • Canonical sibling PR is viable: fix(note): prevent clack from re-breaking copy-sensitive tokens #94738 is open, mergeable, already marked proof-sufficient, has green CI checks, and keeps wrapNoteMessage intact while widening Clack's virtual output stream to prevent the second wrap. (packages/terminal-core/src/note.ts:210, 5db49e572b12)
  • Related-item search found the same candidate cluster: Live GitHub search found this PR plus sibling candidate PRs for the same linked issue; PR 94738 is the only inspected sibling with a clean ClawSweeper ready-for-maintainer review and sufficient proof.

Likely related people:

  • Vincent Koc: Current blame points the terminal-core note helper, wrapNoteMessage tests, and session-lock doctor note caller to the same recent area commit in this checkout. (role: recent area contributor; confidence: medium; commits: 2c7fe6a39c0f; files: packages/terminal-core/src/note.ts, packages/terminal-core/src/table.test.ts, src/commands/doctor-session-locks.ts)
  • Peter Steinberger: Older history shows the Clack note wrapping helper lineage was introduced through the terminal note surface. (role: terminal note history contributor; confidence: medium; commits: 29884f8d6f2c, f7f5c24786ad; files: src/terminal/note.ts)
  • Vignesh Natarajan: git log -S isCopySensitiveToken points to prior terminal/TUI work preserving copy-sensitive long tokens, which is the invariant affected here. (role: adjacent copy-sensitive wrapping contributor; confidence: medium; commits: 69418cca2091; files: src/terminal/note.ts, src/tui/tui-formatters.ts, src/tui/tui-formatters.test.ts)

Codex review notes: model internal, reasoning high; reviewed against 2ef0589b760d.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. labels Jun 19, 2026
@clawsweeper

clawsweeper Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper applied the proposed close for this PR.

  • Action: closed this PR.
  • Close reason: duplicate or superseded.
  • Evidence: durable ClawSweeper review.
  • Coverage proof: PR B clearly carries PR A's useful intent and the material review concern from PR A: the bug is the same, and PR B uses the better/current fix path that preserves copy-sensitive tokens instead of re-splitting them. PR A's remaining differences are the rejected implementation details, not independent useful work. Covering PR: fix(note): prevent clack from re-breaking copy-sensitive tokens #94738.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

doctor: copy-sensitive paths get re-wrapped by clack note box, splitting file extensions

1 participant