fix(edit-selection): accurate per-condition warnings + path-boundary workspace check

cowriting.editSelection collapsed four distinct failures (no editor / no
selection / unsaved / outside the workspace folder) into one misleading
"select some text in a workspace document first" warning — so editing a
selection in a file OUTSIDE the EDH workspace root (e.g. a content-repo file
while the EDH opens sandbox/) was rejected as if no text were selected.

- New pure, vscode-free src/workspacePath.ts: isUnderRoot() (separator-bounded
  membership, fixing a latent startsWith() prefix collision where a sibling
  whose name prefixes the root — e.g. vscode-cowriting-plugin-content vs
  vscode-cowriting-plugin — falsely matched) + selectionRejection() (one
  message per condition). Unit-tested (8 cases), incl. the reported bug.
- Wire isUnderRoot into all five membership checks: extension.ts (editSelection
  guard + renderIfOpen) and the thread/attribution/proposal controllers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ben Stull
2026-06-11 12:12:18 -07:00
parent ce01ef81b5
commit 0bdee1c286
6 changed files with 133 additions and 12 deletions
+2 -1
View File
@@ -16,6 +16,7 @@ import { resolve, shift, type OffsetRange } from "./anchorer";
import { addProposal, proposalBody, removeProposal } from "./proposalModel";
import type { AttributionController } from "./attributionController";
import type { VersionGuard } from "./versionGuard";
import { isUnderRoot } from "./workspacePath";
/** Test-facing snapshot of what is currently rendered for a document. */
export interface RenderedProposal {
@@ -70,7 +71,7 @@ export class ProposalController implements vscode.Disposable {
}
private isTracked(document: vscode.TextDocument): boolean {
return document.uri.scheme === "file" && document.uri.fsPath.startsWith(this.rootDir);
return document.uri.scheme === "file" && isUnderRoot(document.uri.fsPath, this.rootDir);
}
private docPathOf(uri: vscode.Uri): string {
return vscode.workspace.asRelativePath(uri, false);