feat: add ask notifications
This commit is contained in:
@@ -18,6 +18,7 @@ The codebase is split so the implementation reads through file boundaries and na
|
||||
- `src/answer-commands.ts` — `/answer`, `/answer:again`, and `/ask:replay` command wiring
|
||||
- `src/answer-extraction.ts` — configured extraction model selection and raw-JSON extraction retries
|
||||
- `src/ask-payload-store.ts` — branch-aware persisted ask payload lookup
|
||||
- `src/notifications.ts` — best-effort ask notification payload rendering and channel execution
|
||||
- `src/schema.ts` — TypeBox schema
|
||||
- `src/types.ts` — shared types
|
||||
|
||||
@@ -76,7 +77,8 @@ The codebase is split so the implementation reads through file boundaries and na
|
||||
- config schema migrations preserve user-provided values and add new defaults only when fields are absent
|
||||
- replay payload lookup scans only the current session branch and revalidates payloads before use
|
||||
- invalid persisted keymaps fall back to default keymaps for the current session without discarding valid behaviour settings
|
||||
- ask settings behaviour changes persist immediately from the settings list
|
||||
- invalid notification channels are skipped and fall back to the default bell channel if none are valid
|
||||
- ask settings behaviour and notification enabled changes persist immediately from the settings list
|
||||
- when the ask config file is missing, the first ask use writes a default persisted config snapshot under `~/.pi/agent/extensions/`
|
||||
- legacy root config files move into `~/.pi/agent/extensions/` only when the current config file is absent
|
||||
- live config updates can affect an in-progress ask flow immediately
|
||||
|
||||
+65
-3
@@ -28,7 +28,7 @@ Unsupported future versions or invalid files are backed up and defaults are load
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"schemaVersion": 3,
|
||||
"answer": {
|
||||
"extractionModels": [
|
||||
{ "provider": "openai-codex", "id": "gpt-5.4-mini" },
|
||||
@@ -51,6 +51,10 @@ Unsupported future versions or invalid files are backed up and defaults are load
|
||||
"confirm": "enter",
|
||||
"optionNote": "n",
|
||||
"questionNote": "shift+n"
|
||||
},
|
||||
"notifications": {
|
||||
"enabled": true,
|
||||
"channels": ["bell"]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -107,6 +111,52 @@ These settings affect only the `/answer` command. Normal `ask_user` tool calls d
|
||||
- default: `true`
|
||||
- effect: when disabled, the ask flow hides the footer keymap hints
|
||||
|
||||
## Notifications
|
||||
|
||||
Notifications are best-effort external alerts emitted once per ask session, when the ask UI opens and is waiting for input.
|
||||
|
||||
### `notifications.enabled`
|
||||
|
||||
- type: boolean
|
||||
- default: `true`
|
||||
- effect: enables or disables external ask notifications
|
||||
- settings UI: this is the only notification field toggled by `/ask-settings` or `?` in the ask flow
|
||||
|
||||
### `notifications.channels`
|
||||
|
||||
- type: array
|
||||
- default: `["bell"]`
|
||||
- supported channels:
|
||||
- `"bell"` writes BEL (`\u0007`)
|
||||
- `"osc9"` writes an OSC 9 terminal notification
|
||||
- `"osc777"` writes an OSC 777 title/body notification
|
||||
- `{ "type": "command", "command": string }` runs a shell command
|
||||
- effect: channels run in order; failures are ignored and never fail the ask flow
|
||||
- invalid channels are skipped; if none are valid, pi-ask falls back to `["bell"]`
|
||||
|
||||
Notification text:
|
||||
|
||||
```txt
|
||||
Question waiting: <label or prompt>
|
||||
```
|
||||
|
||||
Command channels receive these environment variables:
|
||||
|
||||
```sh
|
||||
ASK_NOTIFY_EVENT=question.waiting
|
||||
ASK_NOTIFY_TITLE="pi ask"
|
||||
ASK_NOTIFY_MESSAGE="Question waiting: <label or prompt>"
|
||||
```
|
||||
|
||||
cmux example:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "command",
|
||||
"command": "cmux notify --title \"$ASK_NOTIFY_TITLE\" --body \"$ASK_NOTIFY_MESSAGE\""
|
||||
}
|
||||
```
|
||||
|
||||
## Keymaps
|
||||
|
||||
`keymaps` must contain all 6 configurable actions if present.
|
||||
@@ -216,7 +266,7 @@ Invalid keymaps include:
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"schemaVersion": 3,
|
||||
"answer": {
|
||||
"extractionRetries": 1,
|
||||
"extractionTimeoutMs": 30000,
|
||||
@@ -237,6 +287,15 @@ Invalid keymaps include:
|
||||
"confirm": "ctrl+k",
|
||||
"optionNote": "x",
|
||||
"questionNote": "shift+x"
|
||||
},
|
||||
"notifications": {
|
||||
"enabled": true,
|
||||
"channels": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "cmux notify --title \"$ASK_NOTIFY_TITLE\" --body \"$ASK_NOTIFY_MESSAGE\""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -246,9 +305,12 @@ Invalid keymaps include:
|
||||
When editing this config for a user:
|
||||
|
||||
- preserve unrelated fields
|
||||
- keep `schemaVersion` at `2`
|
||||
- keep `schemaVersion` at `3`
|
||||
- preserve `answer.extractionModels` as explicit provider/id pairs
|
||||
- keep `answer.extractionRetries` between `0` and `3`
|
||||
- do not assign reserved bindings to configurable actions
|
||||
- do not create duplicate configurable bindings
|
||||
- preserve existing `notifications.channels` unless the user asks to change notification targets
|
||||
- only toggle `notifications.enabled` unless the user asks to configure channels
|
||||
- use a `cmux notify` command channel when the user asks for cmux notifications
|
||||
- after changing the file, tell the user to run `/reload` or restart pi
|
||||
|
||||
+7
-3
@@ -206,9 +206,9 @@ This document defines the stable external behavior. It does not explain internal
|
||||
- `/answer` extraction may use an internal `freeform: true` option for open-ended questions with no explicit choices; these render as user-input-only questions with the label `Type your answer:`, no numbered option row, and no selection caret; this marker is not part of the public `ask_user` tool contract
|
||||
- `/answer:again` command to replay the latest `/answer`-extracted form on the current branch
|
||||
- `/ask:replay` command to replay the latest real `ask_user` form on the current branch
|
||||
- ask settings list with binary behaviour toggles
|
||||
- ask settings list with binary behaviour and notification toggles
|
||||
- `?` in the ask flow and `/ask-settings` in pi open the same lightweight ask settings overlay
|
||||
- behaviour settings persist immediately when changed: `Auto-submit when answered without notes`, `Confirm dismiss when dirty`, `Double-press review shortcuts`, and `Show footer hints`
|
||||
- settings persist immediately when changed: `Auto-submit when answered without notes`, `Confirm dismiss when dirty`, `Double-press review shortcuts`, `Notifications`, and `Show footer hints`
|
||||
- `Keymaps` is a persisted config section for `cancel`, `dismiss`, `toggle`, `confirm`, `optionNote`, and `questionNote`
|
||||
- the settings list shows the absolute config file path for changing customizable ask keymaps
|
||||
- if the flow is already on the review tab, all questions are answered, and no notes exist, enabling auto-submit can complete the current ask flow immediately
|
||||
@@ -245,7 +245,11 @@ If `ctx.hasUI === false`, the tool returns a `Needs user input` message in `cont
|
||||
|
||||
Validation is handled inside the tool so malformed calls produce the same structured error shape as other invalid payloads instead of relying on pre-execution schema failures.
|
||||
|
||||
The ask flow subscribes to runtime settings updates while open. In practice, this means changing `Auto-submit when answered without notes`, `Confirm dismiss when dirty`, `Double-press review shortcuts`, `Show footer hints`, or reloading config-backed keymaps can affect the in-progress ask flow immediately instead of only future asks.
|
||||
The ask flow subscribes to runtime settings updates while open. In practice, this means changing `Auto-submit when answered without notes`, `Confirm dismiss when dirty`, `Double-press review shortcuts`, `Notifications`, `Show footer hints`, or reloading config-backed keymaps can affect the in-progress ask flow immediately instead of only future asks.
|
||||
|
||||
## Notifications
|
||||
|
||||
When enabled, pi-ask emits one best-effort external notification per ask session after the ask UI opens and waits for input. The default title is `pi ask`; the message is `Question waiting: <label or prompt>`. Channels run in configured order and failures never fail or cancel the ask flow.
|
||||
|
||||
## Slash command replay/extraction
|
||||
|
||||
|
||||
Reference in New Issue
Block a user