fix(fs-search): respect platform path separators

Group paths using node:path.sep so POSIX backslashes remain filename characters while Windows continues to treat them as separators.
This commit is contained in:
Tianyi Cui
2026-07-30 22:20:15 +08:00
parent 72220dd821
commit 48b0cb25fd
4 changed files with 36 additions and 10 deletions
+16 -6
View File
@@ -9,6 +9,7 @@
*/
import type { Context } from 'cordis'
import { sep } from 'node:path'
import { defineTool } from '@deepseek-ai/dsh-tools'
import type { GenericCallView } from '@deepseek-ai/dsh-tools'
import type { SpillRef } from '@deepseek-ai/dsh-spill'
@@ -112,16 +113,25 @@ export interface GlobSample {
/** Remove the displayed search-root prefix before choosing a top-level group. */
function relativeToSearchRoot(path: string, root: string): string {
if (root === '.') return path.replace(/^\.[\\/]/, '')
const trimmedRoot = root.replace(/[\\/]+$/, '')
if (trimmedRoot.length === 0) return path.replace(/^[\\/]+/, '')
if (root === '.') return path.startsWith(`.${sep}`) ? path.slice(2) : path
let rootEnd = root.length
while (rootEnd > 0 && root[rootEnd - 1] === sep) rootEnd -= 1
const trimmedRoot = root.slice(0, rootEnd)
if (trimmedRoot.length === 0) return stripLeadingSeparators(path)
if (path === trimmedRoot) return ''
if (path.startsWith(`${trimmedRoot}/`) || path.startsWith(`${trimmedRoot}\\`)) {
if (path.startsWith(`${trimmedRoot}${sep}`)) {
return path.slice(trimmedRoot.length + 1)
}
return path
}
/** Strip only separators recognized by the execution platform. */
function stripLeadingSeparators(path: string): string {
let start = 0
while (path[start] === sep) start += 1
return path.slice(start)
}
/**
* The leading path segment of one display path — the top-level entry, relative
* to the search root, that the path sits under. A path with no separator is its
@@ -131,8 +141,8 @@ function relativeToSearchRoot(path: string, root: string): string {
* empty group.
*/
function topLevelSegment(path: string): string {
const trimmed = path.replace(/^[\\/]+/, '')
const cut = trimmed.search(/[\\/]/)
const trimmed = stripLeadingSeparators(path)
const cut = trimmed.indexOf(sep)
return cut === -1 ? trimmed : trimmed.slice(0, cut)
}