mirror of
https://github.com/stablyai/orca.git
synced 2026-10-22 08:03:37 +00:00
* fix(mobile): make native-chat file links and path citations tappable (STA-3331)
- Linkify POSIX absolute paths in chat prose (leading-/ regex alternative;
URL guard now keys off the char before the matched slash)
- Parse agent-style path:line(:col) citations in prose, code spans, and the
open flow; line/column ride into the mobile file preview route
- Route non-web markdown hrefs (file: URIs, relative/absolute paths) to the
file opener instead of silently dropping them; unknown schemes stay dead
- Resolve chat paths against the worktree root, not the terminal's live cwd
- Reuse the terminal tap-to-open flow for chat taps (haptic, preview route,
tab activation with retries) via a shared identity-stable hook, and toast
on misses instead of silent no-ops
- Keep snake_case paths whole (intraword underscores are literal text),
scan bold/italic/strike spans for paths, split trailing punctuation off
autolinks, and let taps land while the composer keyboard is up
* fix(mobile): harden chat file tap handling
* refactor(chat): share native chat href routing
* fix(mobile): detect files directly under path roots
* fix(mobile): keep inline tokens and dunder paths intact around emphasis
Review follow-ups on the chat file-link work:
- A rejected intraword `_` token left the scan index past its closing
underscore, so every inline token between two snake_case words was
swallowed and rendered as literal source — including markdown links,
which became untappable. Rescan from just past the opening delimiter.
- Treat a path separator as an intraword flank so `src/__init__.py` and
`a/__tests__/x.ts` stay whole; previously they rendered as bold plus a
remnant that the new absolute-root pattern turned into a tap on `/x.ts`.
- Bound the `:line(:col)` tail so `src/app.ts:1e3` and `:80%` no longer
parse a line number, while a cited range still opens its first line.
- Route chat tap failures through the composer banner (toast fallback):
chat taps happen with the keyboard up, which covers the toast.
- Drop the tap-handler mirror's dep list; the call site rebuilds its
accessors every render, so it could never skip on a route that
rerenders per keystroke.
* Revert "fix(mobile): keep inline tokens and dunder paths intact around emphasis"
This reverts commit 308bfaf22b.
* fix(mobile): preserve chat file-link parsing and feedback
58 lines
1.9 KiB
TypeScript
58 lines
1.9 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { routeNativeChatHref } from './native-chat-href-routing'
|
|
|
|
describe('routeNativeChatHref', () => {
|
|
it('classifies web and mail links', () => {
|
|
expect(routeNativeChatHref('https://example.com/docs')).toEqual({
|
|
kind: 'web',
|
|
url: 'https://example.com/docs'
|
|
})
|
|
expect(routeNativeChatHref(' mailto:dev@example.com ')).toEqual({
|
|
kind: 'web',
|
|
url: 'mailto:dev@example.com'
|
|
})
|
|
})
|
|
|
|
it('parses relative file hrefs and line fragments', () => {
|
|
expect(routeNativeChatHref('docs/plan.md?plain=1#line-7')).toEqual({
|
|
kind: 'file',
|
|
pathText: 'docs/plan.md',
|
|
line: 7
|
|
})
|
|
expect(routeNativeChatHref('docs/plan.md#usage')).toEqual({
|
|
kind: 'file',
|
|
pathText: 'docs/plan.md',
|
|
line: null
|
|
})
|
|
})
|
|
|
|
it('decodes relative and file URI paths', () => {
|
|
expect(routeNativeChatHref('docs/release%20notes.md')).toEqual({
|
|
kind: 'file',
|
|
pathText: 'docs/release notes.md',
|
|
line: null
|
|
})
|
|
expect(routeNativeChatHref('file:///Users/me/wt/My%20File.tsx#L12')).toEqual({
|
|
kind: 'file',
|
|
pathText: '/Users/me/wt/My File.tsx',
|
|
line: 12
|
|
})
|
|
})
|
|
|
|
it('keeps Windows drive paths out of the scheme filter', () => {
|
|
expect(routeNativeChatHref(String.raw`C:\repo\src\index.ts`)).toEqual({
|
|
kind: 'file',
|
|
pathText: String.raw`C:\repo\src\index.ts`,
|
|
line: null
|
|
})
|
|
})
|
|
|
|
it('drops anchors, unknown schemes, malformed file URIs, and empty hrefs', () => {
|
|
expect(routeNativeChatHref('#section')).toEqual({ kind: 'none' })
|
|
expect(routeNativeChatHref(undefined)).toEqual({ kind: 'none' })
|
|
expect(routeNativeChatHref('editor://file/x.ts')).toEqual({ kind: 'none' })
|
|
expect(routeNativeChatHref('javascript:alert(1)')).toEqual({ kind: 'none' })
|
|
expect(routeNativeChatHref('file:///tmp/%E0%A4%A.txt')).toEqual({ kind: 'none' })
|
|
})
|
|
})
|