| 452 | // @-file mention completion, served from the workspace filesystem (shell-style: |
| 453 | // resolve the dir part of the typed word, list it, filter by the basename). |
| 454 | private completePath(word: string): Array<{ display: string; meta: string; text: string }> { |
| 455 | try { |
| 456 | const cwd = process.env.CLAWCODEX_WORKSPACE || process.env.CLAWCODEX_CWD || process.cwd() |
| 457 | const stripped = word.startsWith('@') ? word.slice(1) : word |
| 458 | const slash = stripped.lastIndexOf('/') |
| 459 | const dirPart = slash === -1 ? '' : stripped.slice(0, slash + 1) |
| 460 | const base = (slash === -1 ? stripped : stripped.slice(slash + 1)).toLowerCase() |
| 461 | const absDir = pathResolve(cwd, dirPart || '.') |
| 462 | return readdirSync(absDir, { withFileTypes: true }) |
| 463 | .filter(e => !e.name.startsWith('.') && e.name.toLowerCase().startsWith(base)) |
| 464 | .slice(0, 50) |
| 465 | .map(e => { |
| 466 | const isDir = e.isDirectory() |
| 467 | const rel = dirPart + e.name + (isDir ? '/' : '') |
| 468 | return { display: rel, meta: isDir ? 'dir' : 'file', text: rel } |
| 469 | }) |
| 470 | } catch { |
| 471 | return [] |
| 472 | } |
| 473 | } |
| 474 | |
| 475 | // Build a unified diff for Edit/Write tool results so the app renders a colored |
| 476 | // ```diff block (turnController.pushInlineDiffSegment). Other tools → undefined |