fix(pi-notify): default Kitty visibility to always

This commit is contained in:
云服务部-叶林立
2026-08-26 10:36:03 +08:00
parent dc925e1eeb
commit fcdaa25b8f
7 changed files with 13 additions and 11 deletions
+1 -1
View File
@@ -86,7 +86,7 @@
- `pi-context-view` 只观察上下文占用,不参与压缩策略。 - `pi-context-view` 只观察上下文占用,不参与压缩策略。
- `pi-condense` 负责压缩已经进入会话的历史工具结果,与 Context Mode 的输入隔离职责互补;`extensions/condense.ts` 只在 `settings.json` 尚无 `contextPrune.enabled` 时写入 `true`,必须保留用户显式设置的 `false`,配置无效时不得覆盖原文件。其他参数沿用上游默认,包括 `agent-message` 触发模式和 skill 路径保护。 - `pi-condense` 负责压缩已经进入会话的历史工具结果,与 Context Mode 的输入隔离职责互补;`extensions/condense.ts` 只在 `settings.json` 尚无 `contextPrune.enabled` 时写入 `true`,必须保留用户显式设置的 `false`,配置无效时不得覆盖原文件。其他参数沿用上游默认,包括 `agent-message` 触发模式和 skill 路径保护。
- Codex fast mode 只为符合条件的 `openai-codex-responses` 请求设置 priority service tier。`/fast-mode on|off` 同时更新当前分支记录与 Pi agent 目录中的 owner-only 全局默认值;新会话继承全局值,已有分支记录优先,配置缺失或无效时回退为关闭。 - Codex fast mode 只为符合条件的 `openai-codex-responses` 请求设置 priority service tier。`/fast-mode on|off` 同时更新当前分支记录与 Pi agent 目录中的 owner-only 全局默认值;新会话继承全局值,已有分支记录优先,配置缺失或无效时回退为关闭。
- Kitty 通知只在 TUI 模式的 `agent_settled` 后发送;自动重试、自动 compaction 和 follow-up 期间不得提前通知或重置总耗时。默认 `o=unfocused``a=focus`,每个 Pi Session 使用独立稳定 ID,标题和正文必须 Base64 编码。 - Kitty 通知只在 TUI 模式的 `agent_settled` 后发送;自动重试、自动 compaction 和 follow-up 期间不得提前通知或重置总耗时。默认 `o=always``a=focus`,每个 Pi Session 使用独立稳定 ID,标题和正文必须 Base64 编码。
- `/notify on|off` 只覆盖当前 Session;持久默认来自 `PI_NOTIFY_*` 环境变量。`PI_NOTIFY_MESSAGE_SOURCE=none` 必须继续提供不泄露回复正文的隐私模式,非 TUI 模式不得写入 OSC 序列。 - `/notify on|off` 只覆盖当前 Session;持久默认来自 `PI_NOTIFY_*` 环境变量。`PI_NOTIFY_MESSAGE_SOURCE=none` 必须继续提供不泄露回复正文的隐私模式,非 TUI 模式不得写入 OSC 序列。
- 权限策略默认允许常规工具,允许 FFF 工具;拒绝 Bash 直搜和敏感凭据路径;Git 非只读操作、包管理、外部目录、文件/系统/网络高风险操作与普通 MCP 调用先由 `pi-permission-system` 判为 `ask` - 权限策略默认允许常规工具,允许 FFF 工具;拒绝 Bash 直搜和敏感凭据路径;Git 非只读操作、包管理、外部目录、文件/系统/网络高风险操作与普通 MCP 调用先由 `pi-permission-system` 判为 `ask`
- SSH 权限沿用同一条 `pi-permission-system` gate 与 `auto-review` authorizer chain`ssh_connect``ssh_cd``ssh_read``ssh_write``ssh_edit``ssh_find``ssh_grep` 默认 `ask`;连接前的证据解析已导入 host ID 为非秘密 target、port 与请求/default cwdAutoReview 只可依据用户直接消息中的明确目标授权连接。`ssh_bash` 通过 `shellTools` 映射到完整 Bash 策略并设置 `decisionFloor: "ask"`,把普通 Bash `allow` 提升为复核请求,同时保留原有 `ask` 与硬 `deny`。全部远端路径不得送入基于本机 cwd 的 `path` / `external_directory` 归一化。 - SSH 权限沿用同一条 `pi-permission-system` gate 与 `auto-review` authorizer chain`ssh_connect``ssh_cd``ssh_read``ssh_write``ssh_edit``ssh_find``ssh_grep` 默认 `ask`;连接前的证据解析已导入 host ID 为非秘密 target、port 与请求/default cwdAutoReview 只可依据用户直接消息中的明确目标授权连接。`ssh_bash` 通过 `shellTools` 映射到完整 Bash 策略并设置 `decisionFloor: "ask"`,把普通 Bash `allow` 提升为复核请求,同时保留原有 `ask` 与硬 `deny`。全部远端路径不得送入基于本机 cwd 的 `path` / `external_directory` 归一化。
+2 -2
View File
@@ -330,8 +330,8 @@ Hippo CLI:从升级后的组合包读取固定版本,先通过 npm 确认版
`pi-notify/` 直接加载本地维护源码。它只在交互式 TUI 中监听 `agent_settled`,因此自动重试、自动 `pi-notify/` 直接加载本地维护源码。它只在交互式 TUI 中监听 `agent_settled`,因此自动重试、自动
compaction 和排队 follow-up 完成前不会提前通知。Kitty 后端使用 Base64 OSC 99、每个 Pi Session compaction 和排队 follow-up 完成前不会提前通知。Kitty 后端使用 Base64 OSC 99、每个 Pi Session
独立的稳定通知 ID、显式 `a=focus`,并默认设置 `o=unfocused`:来源 Kitty window/pane 有键盘 独立的稳定通知 ID、显式 `a=focus`,并默认设置 `o=always`即使来源 Kitty window/pane 正在接收
焦点时不打扰,切到其他 Kitty 窗口、tab 或 pane 后才通知,点击通知由 Kitty 返回原始来源 键盘输入也会显示通知,点击通知由 Kitty 返回原始来源;仍可通过环境变量改用 `unfocused``invisible`
默认忽略不足 3 秒的短任务。`/notify on|off|test|status` 可控制当前 Session;持久默认通过 默认忽略不足 3 秒的短任务。`/notify on|off|test|status` 可控制当前 Session;持久默认通过
`PI_NOTIFY_ENABLED``PI_NOTIFY_MIN_SECONDS``PI_NOTIFY_VISIBILITY``PI_NOTIFY_ACTION` `PI_NOTIFY_ENABLED``PI_NOTIFY_MIN_SECONDS``PI_NOTIFY_VISIBILITY``PI_NOTIFY_ACTION`
+2 -2
View File
@@ -7,7 +7,7 @@ Kitty-first completion notifications for Pi. This repository maintains a source
- Waits for Pi's `agent_settled` event, so retries, automatic compaction, and queued follow-ups do not notify early. - Waits for Pi's `agent_settled` event, so retries, automatic compaction, and queued follow-ups do not notify early.
- Uses Kitty OSC 99 with Base64 payloads, an ID unique to each Pi session, and explicit `a=focus`. - Uses Kitty OSC 99 with Base64 payloads, an ID unique to each Pi session, and explicit `a=focus`.
- Defaults to `o=unfocused`: no notification while the originating Kitty window/pane has keyboard focus; clicking a notification returns to that exact source window. - Defaults to `o=always`: notifications remain visible while the originating Kitty window/pane has keyboard focus; clicking a notification returns to that exact source window.
- Measures the entire run across automatic retries and ignores runs shorter than three seconds by default. - Measures the entire run across automatic retries and ignores runs shorter than three seconds by default.
- Emits terminal sequences only in interactive TUI mode, never into JSON, print, or RPC output. - Emits terminal sequences only in interactive TUI mode, never into JSON, print, or RPC output.
- Uses macOS AppleScript outside Kitty and a sanitized OSC 777 fallback outside macOS. - Uses macOS AppleScript outside Kitty and a sanitized OSC 777 fallback outside macOS.
@@ -37,7 +37,7 @@ Command overrides are session-local. Use environment variables for persistent de
- `PI_NOTIFY_MESSAGE_SOURCE`: `assistant`, `user`, or privacy mode `none`; default `assistant`. - `PI_NOTIFY_MESSAGE_SOURCE`: `assistant`, `user`, or privacy mode `none`; default `assistant`.
- `PI_NOTIFY_MESSAGE_MAX`: maximum message characters before ellipsis; default `80`, maximum `500`. - `PI_NOTIFY_MESSAGE_MAX`: maximum message characters before ellipsis; default `80`, maximum `500`.
- `PI_NOTIFY_MIN_SECONDS`: minimum complete run duration; default `3`, range `0``3600`. - `PI_NOTIFY_MIN_SECONDS`: minimum complete run duration; default `3`, range `0``3600`.
- `PI_NOTIFY_VISIBILITY`: Kitty policy `unfocused`, `invisible`, or `always`; default `unfocused`. - `PI_NOTIFY_VISIBILITY`: Kitty policy `unfocused`, `invisible`, or `always`; default `always`.
- `PI_NOTIFY_ACTION`: Kitty click action `focus` or `none`; default `focus`. - `PI_NOTIFY_ACTION`: Kitty click action `focus` or `none`; default `focus`.
- `PI_NOTIFY_SOUND_CMD`: optional shell command run after the notification. This is trusted local configuration and executes through a shell. - `PI_NOTIFY_SOUND_CMD`: optional shell command run after the notification. This is trusted local configuration and executes through a shell.
+1 -1
View File
@@ -14,7 +14,7 @@ The source is maintained directly in this repository. It is not a submodule and
- Notify on `agent_settled` rather than `agent_end`, preserving elapsed time and the latest messages across retries. - Notify on `agent_settled` rather than `agent_end`, preserving elapsed time and the latest messages across retries.
- Restrict terminal output to TUI mode so OSC sequences cannot corrupt RPC, JSON, or print output. - Restrict terminal output to TUI mode so OSC sequences cannot corrupt RPC, JSON, or print output.
- Give each Pi session a stable unique OSC 99 notification ID. - Give each Pi session a stable unique OSC 99 notification ID.
- Make Kitty click-to-focus explicit and default visibility to the source-window-aware `unfocused` policy. - Make Kitty click-to-focus explicit and default visibility to `always`, while retaining `unfocused` and `invisible` as opt-in policies.
- Add duration filtering, enable/privacy/action settings, status template fields, and `/notify` controls. - Add duration filtering, enable/privacy/action settings, status template fields, and `/notify` controls.
- Keep Base64 Kitty payloads, harden OSC metadata/fallback sanitization, and ignore detached-process spawn errors. - Keep Base64 Kitty payloads, harden OSC metadata/fallback sanitization, and ignore detached-process spawn errors.
- Add lifecycle, multi-window metadata, fallback, parser, and configuration tests. - Add lifecycle, multi-window metadata, fallback, parser, and configuration tests.
+2 -2
View File
@@ -22,8 +22,8 @@ export function parseEnabled(value: string | undefined): boolean {
export function parseKittyVisibility(value: string | undefined): KittyVisibility { export function parseKittyVisibility(value: string | undefined): KittyVisibility {
const normalized = value?.trim().toLowerCase(); const normalized = value?.trim().toLowerCase();
if (normalized === "always" || normalized === "invisible") return normalized; if (normalized === "always" || normalized === "unfocused" || normalized === "invisible") return normalized;
return "unfocused"; return "always";
} }
export function parseNotificationAction(value: string | undefined): NotificationAction { export function parseNotificationAction(value: string | undefined): NotificationAction {
+1 -1
View File
@@ -54,7 +54,7 @@ describe("config", () => {
durationMs: 4_200, durationMs: 4_200,
minDurationMs: 3_000, minDurationMs: 3_000,
notificationId: "pi-session", notificationId: "pi-session",
visibility: "unfocused", visibility: "always",
action: "focus", action: "focus",
soundCommand: undefined, soundCommand: undefined,
}); });
+4 -2
View File
@@ -33,9 +33,11 @@ describe("parsers", () => {
assert.equal(parseEnabled(undefined), true); assert.equal(parseEnabled(undefined), true);
assert.equal(parseEnabled("off"), false); assert.equal(parseEnabled("off"), false);
assert.equal(parseEnabled("yes"), true); assert.equal(parseEnabled("yes"), true);
assert.equal(parseKittyVisibility(undefined), "unfocused"); assert.equal(parseKittyVisibility(undefined), "always");
assert.equal(parseKittyVisibility("always"), "always"); assert.equal(parseKittyVisibility("always"), "always");
assert.equal(parseKittyVisibility("invalid"), "unfocused"); assert.equal(parseKittyVisibility("unfocused"), "unfocused");
assert.equal(parseKittyVisibility("invisible"), "invisible");
assert.equal(parseKittyVisibility("invalid"), "always");
assert.equal(parseNotificationAction("none"), "none"); assert.equal(parseNotificationAction("none"), "none");
assert.equal(parseNotificationAction("invalid"), "focus"); assert.equal(parseNotificationAction("invalid"), "focus");
}); });