pi-open-path-links0.1.0
Turn bare file paths in the pi transcript into clickable links: click the path to open the file with the default application, click 📂 to open its folder in the file manager.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-open-path-links
Make file paths in the pi transcript clickable.
- Click the path → opens the file with your OS default application.
- Click the 📂 glyph next to it → opens the containing folder in your file manager.
Zero configuration, no dependencies, works with every model.
中文说明见下方 中文 一节(中英对照)。
pi: Handover notes are in docs/playbooks/fly-domain-exposure-handover.md
↑ click here
📂 ← or click here for the folder
Why two targets instead of Cmd / Cmd+Shift
Terminals implement clickable text with OSC 8 hyperlinks: the application
emits ESC ] 8 ; params ; URI ST text ESC ] 8 ; ; ST, and the terminal decides
when to open URI. The program never learns which modifier was held, so
"Cmd opens the file, Cmd+Shift opens the folder" is not expressible — the
terminal hands the same single URI to the OS in both cases.
pi exposes registerMessageRenderer only for custom messages, so an extension
cannot intercept mouse events on assistant messages either.
This package therefore emits two adjacent links. It is the same number of clicks, and it keeps the modifier keys free for your terminal's own bindings.
| Target | Action | Under the hood (macOS) |
|---|---|---|
path/to/file.md |
open with default app | open path/to/file.md |
📂 |
open containing folder | open path/to/ |
On Linux it uses xdg-open, on Windows start / explorer.
Install
pi install npm:pi-open-path-links
Then restart pi (or /reload). No configuration file is created.
Requirements
- pi ≥ 1.0 (uses
registerMarkdownTransformer) - A terminal with OSC 8 support: Ghostty, iTerm2, WezTerm, Kitty, Alacritty, VS Code terminal, …
- macOS, Linux or Windows
What gets linkified
Only paths that exist on disk are rewritten. That is a deliberate safety
rule: it keeps version strings (v1.2.3), bare file names (AGENTS.md),
non-existent paths and URLs untouched.
| Input | Linkified |
|---|---|
docs/playbooks/handover.md (exists) |
✅ |
~/Desktop/notes.md (exists) |
✅ |
/Users/me/project/src/a.ts (exists) |
✅ |
docs/playbooks/missing.md |
❌ not on disk |
AGENTS.md |
❌ no directory part |
v1.2.3, lib/foo.ts (missing) |
❌ |
https://github.com/o/r/blob/main/a.md |
❌ URL |
`cat docs/a.md` / fenced code |
❌ code |
[text](https://example.com) |
❌ already a link |
Unicode (CJK) file names are supported.
Commands
| Command | Action |
|---|---|
/open <path> |
open the file with the default application |
/reveal <path> |
reveal the file in the file manager (selects it) |
/opendir <path|dir> |
open the containing directory in the file manager |
<path> accepts ~, relative (resolved against the session working
directory), and absolute forms.
These commands are useful when the terminal does not handle file:// links, or
when the path appears inside tool output (tool output is not transformed — see
limitations).
Scope and limitations
The transformer runs in pi's interactive transcript only, for two surfaces:
- assistant messages
- user messages
Consequences:
| Place | Linkified |
|---|---|
| Paths the assistant writes in its answer | ✅ |
| Paths you type | ✅ |
bash / read / grep / find tool output |
❌ |
pi -p non-interactive output |
❌ (no TUI rendering) |
| Exported / shared sessions (HTML, Markdown) | ❌ |
Everything on the machine is covered — every pi session, every provider, every model — because the package is registered as a user-level extension. Other machines need the package installed; other agents (Claude Code, Codex CLI, …) are unaffected.
Configuration
| Variable | Effect |
|---|---|
PI_OPEN_PATH_LINKS=0 |
disable the extension entirely |
To drop the folder glyph and keep only file links, disable the extension and register your own transformer, or open an issue — a flag is easy to add.
How it works
pi.registerMarkdownTransformer()receives each message's Markdown before pi renders it.- Code fences, inline code and existing links are stashed away.
- Bare path candidates matching
PATH_REare resolved against the sessioncwd(~and absolute paths supported) and kept only if they exist. - Surviving paths become
[path](file:///abs/path)plus[📂](file:///abs/dir). - pi's Markdown renderer turns those into OSC 8 hyperlinks
(
@earendil-works/pi-tuicomponents/markdown.js), which your terminal makes clickable.
Development
git clone https://github.com/uniStark/pi-open-path-links.git
cd pi-open-path-links
npm install
npm test # node --test, 16 tests, no pi required
pi -e . # try it for one pi invocation
The linkification logic lives in src/linkify.ts and has no pi dependency, so it
is unit-tested in isolation.
License
MIT © Adrian Stark
中文
让 pi 对话里的文件路径可点击。
- 点击路径本身 → 用系统默认应用打开该文件
- 点击旁边的 📂 → 在文件管理器中打开它所在的目录
零配置、无依赖、对所有模型生效。
为什么是两个可点目标,而不是 Cmd / Cmd+Shift
终端实现可点文字依赖 OSC 8 超链接:程序发出
ESC ] 8 ; params ; URI ST 文本 ESC ] 8 ; ; ST,由终端决定何时打开 URI。
程序无法得知用户按下了哪个修饰键,所以"Cmd 开文件、Cmd+Shift 开目录"
在 OSC 8 层面无法表达 —— 两种情况终端交给系统的都是同一条 URI。
pi 的 registerMessageRenderer 只对自定义消息生效,扩展也无法拦截助手消息的鼠标事件。
因此本包输出两个相邻链接:点击次数相同,同时把修饰键留给终端自己的绑定。
| 点击目标 | 行为 | macOS 底层命令 |
|---|---|---|
path/to/file.md |
默认应用打开 | open path/to/file.md |
📂 |
打开所在目录 | open path/to/ |
Linux 用 xdg-open,Windows 用 start / explorer。
安装
pi install npm:pi-open-path-links
然后重启 pi(或 /reload)。不会生成任何配置文件。
环境要求
- pi ≥ 1.0(依赖
registerMarkdownTransformer) - 支持 OSC 8 的终端:Ghostty、iTerm2、WezTerm、Kitty、Alacritty、VS Code 终端…
- macOS / Linux / Windows
哪些路径会被转换
只有磁盘上真实存在的路径才会被改写。这是刻意的安全策略,避免误伤版本号
(v1.2.3)、裸文件名(AGENTS.md)、不存在的路径和 URL。
| 输入 | 是否转换 |
|---|---|
docs/playbooks/handover.md(存在) |
✅ |
~/Desktop/notes.md(存在) |
✅ |
/Users/me/project/src/a.ts(存在) |
✅ |
docs/playbooks/missing.md |
❌ 不存在 |
AGENTS.md |
❌ 无目录分隔符 |
v1.2.3、lib/foo.ts(不存在) |
❌ |
https://github.com/o/r/blob/main/a.md |
❌ URL |
`cat docs/a.md` / 代码块 |
❌ 代码 |
[text](https://example.com) |
❌ 已是链接 |
支持中文等 Unicode 文件名。
命令
| 命令 | 行为 |
|---|---|
/open <路径> |
用默认应用打开文件 |
/reveal <路径> |
在文件管理器中定位并选中该文件 |
/opendir <路径|目录> |
在文件管理器中打开所在目录 |
<路径> 支持 ~、相对路径(按会话工作目录解析)与绝对路径。
当终端不处理 file:// 链接,或路径出现在工具输出里时(工具输出不会被转换),
用这些命令更可靠。
生效范围与限制
transformer 只在 pi 的交互式转录区生效,覆盖两处:
- 助手消息
- 用户消息
因此:
| 位置 | 是否可点 |
|---|---|
| 助手正文里写的路径 | ✅ |
| 你自己输入的路径 | ✅ |
bash / read / grep / find 工具输出 |
❌ |
pi -p 非交互输出 |
❌(无 TUI 渲染) |
| 导出的 HTML / Markdown 会话 | ❌ |
因为以用户级扩展注册,所以本机所有 pi 会话、所有 provider、所有模型都生效。 其他机器需要各自安装;其他 agent(Claude Code、Codex CLI 等)不受影响。
配置
| 环境变量 | 作用 |
|---|---|
PI_OPEN_PATH_LINKS=0 |
完全禁用本扩展 |
如果不需要 📂,禁用本扩展并自行注册 transformer,或者提 issue —— 加一个开关很容易。
工作原理
pi.registerMarkdownTransformer()在渲染前拿到消息 Markdown- 代码块、行内代码、已有链接先被占位符保护起来
- 匹配
PATH_RE的候选路径按会话cwd解析(支持~与绝对路径),只保留真实存在的 - 命中的路径变成
[路径](file:///绝对路径)加[📂](file:///目录) - pi 的 Markdown 渲染器把它们转成 OSC 8 超链接
(
@earendil-works/pi-tui的components/markdown.js),终端即可点击
开发
git clone https://github.com/uniStark/pi-open-path-links.git
cd pi-open-path-links
npm install
npm test # node --test,16 个用例,不需要 pi
pi -e . # 单次运行试用
路径转换逻辑在 src/linkify.ts,不依赖 pi,可独立单测。
许可
MIT © Adrian Stark