@pi-unipi/unipi 3.0.0-alpha.28 → 3.0.0-alpha.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +1 -0
- package/package.json +21 -21
- package/packages/ask-user/package.json +2 -2
- package/packages/autocomplete/package.json +1 -1
- package/packages/background-tasks/package.json +2 -2
- package/packages/btw/package.json +2 -2
- package/packages/compactor/package.json +3 -3
- package/packages/core/package.json +1 -1
- package/packages/footer/package.json +3 -3
- package/packages/fusion/package.json +4 -4
- package/packages/info-screen/package.json +2 -2
- package/packages/input-shortcuts/package.json +2 -2
- package/packages/kanboard/package.json +7 -7
- package/packages/long-horizon/package.json +2 -2
- package/packages/mcp/package.json +2 -2
- package/packages/memory/package.json +3 -3
- package/packages/notify/README.md +4 -0
- package/packages/notify/activity.ts +4 -2
- package/packages/notify/events.ts +116 -11
- package/packages/notify/input-needed-message.ts +27 -0
- package/packages/notify/package.json +2 -2
- package/packages/notify/settings.ts +2 -0
- package/packages/notify/skills/configure-notify/SKILL.md +4 -2
- package/packages/skill-registry/package.json +2 -2
- package/packages/subagents/package.json +3 -3
- package/packages/unipi/bundled.js +84 -19
- package/packages/updater/package.json +2 -2
- package/packages/utility/package.json +2 -2
- package/packages/watchdog/package.json +3 -3
- package/packages/web-api/package.json +2 -2
- package/packages/workflow/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [3.0.0-alpha.29] — 2026-10-04
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- `notify`: prompts that send no event of their own (third-party `ask_user` tools, the permission prompt, the plan review) can notify through the new **Input Needed** event (`input_needed`, off by default); closing any prompt now stops its reminders. (GitHub #38)
|
|
13
|
+
|
|
9
14
|
## [3.0.0-alpha.28] — 2026-10-04
|
|
10
15
|
|
|
11
16
|
### Changed
|
package/README.md
CHANGED
|
@@ -249,6 +249,7 @@ The recent releases, in short. The [changelog](CHANGELOG.md) has the details.
|
|
|
249
249
|
|
|
250
250
|
| Release | What changed for you |
|
|
251
251
|
|---|---|
|
|
252
|
+
| alpha.29 | Plan mode plans with you: it asks before it submits, blocks only edits outside the plan, and the review shows a summary beside the steps. Notify can alert on any prompt the agent waits on (Input Needed). |
|
|
252
253
|
| alpha.27 | The footer shows tokens in and out and the session cost under the input. It fits narrow and short windows. Each part of the stats line, the frame badges and the rainbow can be turned off in `/unipi:settings` → Footer. The classic footer is gone. |
|
|
253
254
|
| alpha.25 | The Unicrab splash at startup. A new `/unipi:info`: this session, the context bucket, compaction savings and `s`/`p`/`g` scope tags. Prompts that UniPi sends for you (goal, summarize, answer) show as a UniPi panel, not as your own message. |
|
|
254
255
|
| alpha.24 | The `summarize` skill and `/unipi:summarize [focus]`. Long work ends with a short recap: the answer first, then findings, open items and questions. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/unipi",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "All-in-one extension suite for Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -83,26 +83,26 @@
|
|
|
83
83
|
"typebox": "^1.1.38"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
|
-
"@pi-unipi/ask-user": "3.0.0-alpha.
|
|
87
|
-
"@pi-unipi/background-tasks": "3.0.0-alpha.
|
|
88
|
-
"@pi-unipi/btw": "3.0.0-alpha.
|
|
89
|
-
"@pi-unipi/command-enchantment": "3.0.0-alpha.
|
|
90
|
-
"@pi-unipi/compactor": "3.0.0-alpha.
|
|
91
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
92
|
-
"@pi-unipi/footer": "3.0.0-alpha.
|
|
93
|
-
"@pi-unipi/fusion": "3.0.0-alpha.
|
|
94
|
-
"@pi-unipi/info-screen": "3.0.0-alpha.
|
|
95
|
-
"@pi-unipi/input-shortcuts": "3.0.0-alpha.
|
|
96
|
-
"@pi-unipi/kanboard": "3.0.0-alpha.
|
|
97
|
-
"@pi-unipi/mcp": "3.0.0-alpha.
|
|
98
|
-
"@pi-unipi/memory": "3.0.0-alpha.
|
|
99
|
-
"@pi-unipi/notify": "3.0.0-alpha.
|
|
100
|
-
"@pi-unipi/skill-registry": "3.0.0-alpha.
|
|
101
|
-
"@pi-unipi/subagents": "3.0.0-alpha.
|
|
102
|
-
"@pi-unipi/updater": "3.0.0-alpha.
|
|
103
|
-
"@pi-unipi/utility": "3.0.0-alpha.
|
|
104
|
-
"@pi-unipi/web-api": "3.0.0-alpha.
|
|
105
|
-
"@pi-unipi/workflow": "3.0.0-alpha.
|
|
86
|
+
"@pi-unipi/ask-user": "3.0.0-alpha.29",
|
|
87
|
+
"@pi-unipi/background-tasks": "3.0.0-alpha.29",
|
|
88
|
+
"@pi-unipi/btw": "3.0.0-alpha.29",
|
|
89
|
+
"@pi-unipi/command-enchantment": "3.0.0-alpha.29",
|
|
90
|
+
"@pi-unipi/compactor": "3.0.0-alpha.29",
|
|
91
|
+
"@pi-unipi/core": "3.0.0-alpha.29",
|
|
92
|
+
"@pi-unipi/footer": "3.0.0-alpha.29",
|
|
93
|
+
"@pi-unipi/fusion": "3.0.0-alpha.29",
|
|
94
|
+
"@pi-unipi/info-screen": "3.0.0-alpha.29",
|
|
95
|
+
"@pi-unipi/input-shortcuts": "3.0.0-alpha.29",
|
|
96
|
+
"@pi-unipi/kanboard": "3.0.0-alpha.29",
|
|
97
|
+
"@pi-unipi/mcp": "3.0.0-alpha.29",
|
|
98
|
+
"@pi-unipi/memory": "3.0.0-alpha.29",
|
|
99
|
+
"@pi-unipi/notify": "3.0.0-alpha.29",
|
|
100
|
+
"@pi-unipi/skill-registry": "3.0.0-alpha.29",
|
|
101
|
+
"@pi-unipi/subagents": "3.0.0-alpha.29",
|
|
102
|
+
"@pi-unipi/updater": "3.0.0-alpha.29",
|
|
103
|
+
"@pi-unipi/utility": "3.0.0-alpha.29",
|
|
104
|
+
"@pi-unipi/web-api": "3.0.0-alpha.29",
|
|
105
|
+
"@pi-unipi/workflow": "3.0.0-alpha.29"
|
|
106
106
|
},
|
|
107
107
|
"devDependencies": {
|
|
108
108
|
"@earendil-works/pi-agent-core": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/ask-user",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Structured user input tool for Pi coding agent — single-select, multi-select, freeform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
43
|
+
"@pi-unipi/core": "3.0.0-alpha.29"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/background-tasks",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Background tasks for UniPi — durable shell jobs and delegated background agents with a footer dock",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@earendil-works/pi-ai": "^0.87.1",
|
|
13
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
13
|
+
"@pi-unipi/core": "3.0.0-alpha.29",
|
|
14
14
|
"turndown": "^7.2.4"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/btw",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "A pi extension for parallel side conversations with /unipi:btw — part of the Unipi suite",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "extensions/btw.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@earendil-works/pi-tui": "^0.87.1"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
40
|
+
"@pi-unipi/core": "3.0.0-alpha.29"
|
|
41
41
|
},
|
|
42
42
|
"pi": {
|
|
43
43
|
"extensions": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/compactor",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Compaction for Pi — lossless zero-LLM or model summaries, rebuilt from full history, with session recall",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
37
|
-
"@pi-unipi/info-screen": "3.0.0-alpha.
|
|
36
|
+
"@pi-unipi/core": "3.0.0-alpha.29",
|
|
37
|
+
"@pi-unipi/info-screen": "3.0.0-alpha.29",
|
|
38
38
|
"@earendil-works/pi-agent-core": "^0.87.1"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/footer",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Persistent status bar for Unipi — subscribes to UNIPI_EVENTS and renders key stats from all unipi packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"access": "public"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
36
|
-
"@pi-unipi/background-tasks": "3.0.0-alpha.
|
|
35
|
+
"@pi-unipi/core": "3.0.0-alpha.29",
|
|
36
|
+
"@pi-unipi/background-tasks": "3.0.0-alpha.29"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/fusion",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Devin-style model picker, fusion presets (lead + sidekick), and Local Fusion runtime for UniPi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"access": "public"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
36
|
-
"@pi-unipi/subagents": "3.0.0-alpha.
|
|
37
|
-
"@pi-unipi/utility": "3.0.0-alpha.
|
|
35
|
+
"@pi-unipi/core": "3.0.0-alpha.29",
|
|
36
|
+
"@pi-unipi/subagents": "3.0.0-alpha.29",
|
|
37
|
+
"@pi-unipi/utility": "3.0.0-alpha.29"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"@earendil-works/pi-ai": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/info-screen",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Unicrab startup splash and the /unipi:info dashboard — this session, context, usage, compaction savings",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
36
|
+
"@pi-unipi/core": "3.0.0-alpha.29"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/input-shortcuts",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Keyboard shortcuts for stash/restore, undo/redo, clipboard, and thinking toggle — chord-based overlay system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
36
|
+
"@pi-unipi/core": "3.0.0-alpha.29"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/kanboard",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Kanboard v3 — deferred-work board: CLI/daemon bridge, task runner and skill",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"access": "public"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
34
|
+
"@pi-unipi/core": "3.0.0-alpha.29"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
"themes": []
|
|
49
49
|
},
|
|
50
50
|
"optionalDependencies": {
|
|
51
|
-
"@pi-unipi/kanboard-linux-x64": "3.0.0-alpha.
|
|
52
|
-
"@pi-unipi/kanboard-linux-arm64": "3.0.0-alpha.
|
|
53
|
-
"@pi-unipi/kanboard-darwin-x64": "3.0.0-alpha.
|
|
54
|
-
"@pi-unipi/kanboard-darwin-arm64": "3.0.0-alpha.
|
|
55
|
-
"@pi-unipi/kanboard-win32-x64": "3.0.0-alpha.
|
|
51
|
+
"@pi-unipi/kanboard-linux-x64": "3.0.0-alpha.29",
|
|
52
|
+
"@pi-unipi/kanboard-linux-arm64": "3.0.0-alpha.29",
|
|
53
|
+
"@pi-unipi/kanboard-darwin-x64": "3.0.0-alpha.29",
|
|
54
|
+
"@pi-unipi/kanboard-darwin-arm64": "3.0.0-alpha.29",
|
|
55
|
+
"@pi-unipi/kanboard-win32-x64": "3.0.0-alpha.29"
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/long-horizon",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Long-horizon execution for Pi — mode-gated /goal /ralph /swarm /graph orchestration with a TypeSafe prompt judge",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
40
|
+
"@pi-unipi/core": "3.0.0-alpha.29"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/mcp",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "MCP server management extension for Pi coding agent — browse, add, configure, and use MCP servers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"test": "npx tsx --test tests/**/*.test.ts"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
33
|
+
"@pi-unipi/core": "3.0.0-alpha.29"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/memory",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Persistent cross-session memory on MemPalace (auto-installed): daemon-routed writes, shared palace with other agents, for Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"README.md"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
46
|
-
"@pi-unipi/info-screen": "3.0.0-alpha.
|
|
45
|
+
"@pi-unipi/core": "3.0.0-alpha.29",
|
|
46
|
+
"@pi-unipi/info-screen": "3.0.0-alpha.29",
|
|
47
47
|
"js-yaml": "^4.1.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
@@ -71,9 +71,12 @@ notify_user({ title: "Build failed", message: "tsc found 12 errors.", priority:
|
|
|
71
71
|
| `session_shutdown` | off | The session ends. |
|
|
72
72
|
| `ask_user_prompt` | off | The agent asks you a question and waits. |
|
|
73
73
|
| `permission_request` | off | A permission prompt opens. This needs [`@gotgenes/pi-permission-system`](https://www.npmjs.com/package/@gotgenes/pi-permission-system). |
|
|
74
|
+
| `input_needed` | off | The agent waits on any prompt while it runs. Covers prompts that send no event of their own — third-party `ask_user` tools, the permission prompt, the plan review. |
|
|
74
75
|
|
|
75
76
|
`ask_user_prompt` and `permission_request` are blocking events. The agent stops until you answer.
|
|
76
77
|
|
|
78
|
+
`input_needed` is the catch-all for the same situation: Pi fires it around every blocking prompt, including ones that emit no event of their own. It only fires while the agent is running — prompts you open yourself while the agent is idle (for example `/unipi:settings`) stay quiet — and a prompt already announced as `ask_user_prompt` or `permission_request` is not announced twice. Closing any prompt stops its reminders.
|
|
79
|
+
|
|
77
80
|
## Settings
|
|
78
81
|
|
|
79
82
|
Open `/unipi:settings` → **Notify**. The file is `~/.unipi/config/notify/config.json`. A project file at `.unipi/config/notify/config.json` overrides it.
|
|
@@ -104,6 +107,7 @@ A reminder has the text `(still waiting)` in its title and `high` priority. Remi
|
|
|
104
107
|
- You press a key.
|
|
105
108
|
- herdr reports that the agent is not blocked.
|
|
106
109
|
- The agent starts a new turn.
|
|
110
|
+
- The prompt closes.
|
|
107
111
|
- The session ends.
|
|
108
112
|
|
|
109
113
|
Only one reminder runs at a time. Silence after input does not apply to blocking events.
|
|
@@ -26,6 +26,7 @@ const VALID_PLATFORMS: ReadonlySet<NotifyPlatform> = new Set([
|
|
|
26
26
|
const BLOCKING_EVENTS: ReadonlySet<string> = new Set([
|
|
27
27
|
"ask_user_prompt",
|
|
28
28
|
"permission_request",
|
|
29
|
+
"input_needed",
|
|
29
30
|
]);
|
|
30
31
|
|
|
31
32
|
/** Whether an event type is a human-blocking prompt. */
|
|
@@ -51,8 +52,9 @@ export function resetInputActivity(): void {
|
|
|
51
52
|
* Empty `platforms` (while enabled) silences all incoming channels, matching
|
|
52
53
|
* `events.*.platforms: []` → all enabled.
|
|
53
54
|
*
|
|
54
|
-
* Human-blocking events (`ask_user_prompt`, `permission_request
|
|
55
|
-
* filter entirely — the keypress that triggered
|
|
55
|
+
* Human-blocking events (`ask_user_prompt`, `permission_request`,
|
|
56
|
+
* `input_needed`) bypass the filter entirely — the keypress that triggered
|
|
57
|
+
* them must not mute them.
|
|
56
58
|
*/
|
|
57
59
|
export function filterPlatformsAfterInput(
|
|
58
60
|
platforms: NotifyPlatform[],
|
|
@@ -15,6 +15,7 @@ import { sendTelegramNotification } from "./platforms/telegram.js";
|
|
|
15
15
|
import { sendNtfyNotification } from "./platforms/ntfy.js";
|
|
16
16
|
import { buildAskUserPromptMessage } from "./ask-user-prompt-message.js";
|
|
17
17
|
import { buildPermissionPromptMessage } from "./permission-prompt-message.js";
|
|
18
|
+
import { buildInputNeededMessage } from "./input-needed-message.js";
|
|
18
19
|
import { summarizeLastMessage } from "./summarize.js";
|
|
19
20
|
import { filterPlatformsAfterInput, isBlockingEvent } from "./activity.js";
|
|
20
21
|
|
|
@@ -75,6 +76,22 @@ const unsubs: Array<() => void> = [];
|
|
|
75
76
|
/** Pending re-notify interval for an unanswered blocking prompt. */
|
|
76
77
|
let renotifyTimer: ReturnType<typeof setInterval> | undefined;
|
|
77
78
|
|
|
79
|
+
/**
|
|
80
|
+
* A `ui_prompt_start` within this window of an ask_user/permission alert is
|
|
81
|
+
* the same prompt — pi emits the bus event and the lifecycle event back to
|
|
82
|
+
* back. Exported for tests.
|
|
83
|
+
*/
|
|
84
|
+
export const PROMPT_DEDUP_MS = 2000;
|
|
85
|
+
|
|
86
|
+
/** Whether an agent run is in progress — `input_needed` fires only while it is. */
|
|
87
|
+
let agentRunning = false;
|
|
88
|
+
|
|
89
|
+
/** Open blocking UI prompts (`ui_prompt_start`/`ui_prompt_end` pairing). */
|
|
90
|
+
let openPrompts = 0;
|
|
91
|
+
|
|
92
|
+
/** When the last ask_user/permission alert went out, for ui_prompt de-dup. */
|
|
93
|
+
let lastBlockingAlertAt = 0;
|
|
94
|
+
|
|
78
95
|
/** Cancel any pending re-notify timer. Safe to call at any time. */
|
|
79
96
|
export function disarmRenotify(): void {
|
|
80
97
|
const timer = renotifyTimer;
|
|
@@ -128,9 +145,33 @@ function armRenotify(
|
|
|
128
145
|
renotifyTimer = timer;
|
|
129
146
|
}
|
|
130
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Dispatch a human-blocking prompt alert: high priority plus the reminder
|
|
150
|
+
* loop. Non-`input_needed` alerts also stamp `lastBlockingAlertAt` so the
|
|
151
|
+
* back-to-back `ui_prompt_start` for the same prompt is seen as announced.
|
|
152
|
+
*/
|
|
153
|
+
function notifyBlocking(
|
|
154
|
+
pi: ExtensionAPI,
|
|
155
|
+
eventKey: string,
|
|
156
|
+
title: string,
|
|
157
|
+
message: string,
|
|
158
|
+
platforms: NotifyPlatform[],
|
|
159
|
+
config: NotifyConfig,
|
|
160
|
+
cwd: string,
|
|
161
|
+
dispatch: DispatchNotification,
|
|
162
|
+
): void {
|
|
163
|
+
if (eventKey !== "input_needed") lastBlockingAlertAt = Date.now();
|
|
164
|
+
dispatch(pi, title, message, platforms, eventKey, config, cwd, "high").catch(() => {
|
|
165
|
+
// Silently ignore — background notification failure is non-blocking.
|
|
166
|
+
});
|
|
167
|
+
armRenotify(pi, title, message, platforms, eventKey, config, cwd, dispatch);
|
|
168
|
+
}
|
|
169
|
+
|
|
131
170
|
/** Unregister all previously registered pi.events.on() listeners. */
|
|
132
171
|
function unregisterAll(): void {
|
|
133
172
|
disarmRenotify();
|
|
173
|
+
agentRunning = false;
|
|
174
|
+
openPrompts = 0;
|
|
134
175
|
for (const unsub of unsubs) {
|
|
135
176
|
try { unsub(); } catch { /* ignore */ }
|
|
136
177
|
}
|
|
@@ -161,6 +202,7 @@ export const BUILTIN_EVENTS: Record<
|
|
|
161
202
|
session_shutdown: { hook: "session_shutdown", label: "Session End" },
|
|
162
203
|
ask_user_prompt: { hook: UNIPI_EVENTS.ASK_USER_PROMPT, label: "Question Asked" },
|
|
163
204
|
permission_request: { hook: PERMISSION_UI_PROMPT_EVENT, label: "Permission Request" },
|
|
205
|
+
input_needed: { hook: "ui_prompt_start", label: "Input Needed" },
|
|
164
206
|
};
|
|
165
207
|
|
|
166
208
|
/**
|
|
@@ -184,7 +226,9 @@ export function registerEventListeners(
|
|
|
184
226
|
unregisterAll();
|
|
185
227
|
// Register built-in events (except agent lifecycle notifications which have custom logic)
|
|
186
228
|
for (const [eventKey, def] of Object.entries(BUILTIN_EVENTS)) {
|
|
187
|
-
|
|
229
|
+
// Agent notifications have custom logic; input_needed has its own
|
|
230
|
+
// ui_prompt_start registration below (with agent-running + de-dup guards).
|
|
231
|
+
if (isAgentNotificationEvent(eventKey) || eventKey === "input_needed") continue;
|
|
188
232
|
|
|
189
233
|
const eventConfig = config.events[eventKey];
|
|
190
234
|
if (!eventConfig?.enabled) continue;
|
|
@@ -192,6 +236,12 @@ export function registerEventListeners(
|
|
|
192
236
|
const handler = (payload: unknown) => {
|
|
193
237
|
const title = `Pi — ${def.label}`;
|
|
194
238
|
const message = buildEventMessage(eventKey, payload);
|
|
239
|
+
// Human-blocking prompts: high priority, reminder loop, and a stamp
|
|
240
|
+
// that keeps the follow-up ui_prompt_start from double-firing.
|
|
241
|
+
if (isBlockingEvent(eventKey)) {
|
|
242
|
+
notifyBlocking(pi, eventKey, title, message, eventConfig.platforms, config, cwd, dispatch);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
195
245
|
// Fire-and-forget: don't block the event emitter
|
|
196
246
|
dispatch(
|
|
197
247
|
pi,
|
|
@@ -205,9 +255,6 @@ export function registerEventListeners(
|
|
|
205
255
|
).catch(() => {
|
|
206
256
|
// Silently ignore — background notification failure is non-blocking.
|
|
207
257
|
});
|
|
208
|
-
if (isBlockingEvent(eventKey)) {
|
|
209
|
-
armRenotify(pi, title, message, eventConfig.platforms, eventKey, config, cwd, dispatch);
|
|
210
|
-
}
|
|
211
258
|
};
|
|
212
259
|
|
|
213
260
|
// Pi lifecycle events are dispatched via ExtensionRunner — must use
|
|
@@ -225,14 +272,16 @@ export function registerEventListeners(
|
|
|
225
272
|
const askUserConfig = config.events["ask_user_prompt"];
|
|
226
273
|
if (askUserConfig?.enabled) {
|
|
227
274
|
unsubs.push(pi.events.on(ASK_USER_PROMPT_EVENT, (payload: unknown) => {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
275
|
+
notifyBlocking(
|
|
276
|
+
pi,
|
|
277
|
+
"ask_user_prompt",
|
|
278
|
+
`Pi — ${BUILTIN_EVENTS.ask_user_prompt.label}`,
|
|
279
|
+
buildAskUserPromptMessage(payload),
|
|
280
|
+
askUserConfig.platforms,
|
|
281
|
+
config,
|
|
282
|
+
cwd,
|
|
283
|
+
dispatch,
|
|
234
284
|
);
|
|
235
|
-
armRenotify(pi, title, message, askUserConfig.platforms, "ask_user_prompt", config, cwd, dispatch);
|
|
236
285
|
}));
|
|
237
286
|
}
|
|
238
287
|
|
|
@@ -242,11 +291,67 @@ export function registerEventListeners(
|
|
|
242
291
|
if ((payload as { active?: unknown } | null)?.active === false) disarmRenotify();
|
|
243
292
|
}));
|
|
244
293
|
(pi as any).on("agent_start", () => {
|
|
294
|
+
agentRunning = true;
|
|
245
295
|
disarmRenotify();
|
|
246
296
|
});
|
|
247
297
|
|
|
248
298
|
registerAgentNotification(pi, "agent_end", config, cwd, dispatch);
|
|
249
299
|
registerAgentNotification(pi, "agent_settled", config, cwd, dispatch);
|
|
300
|
+
|
|
301
|
+
// Keep the agent-running flag in sync. Registered after the agent
|
|
302
|
+
// notification handlers above so the first agent_end handler stays the
|
|
303
|
+
// notification path (pi.on handlers fire in registration order).
|
|
304
|
+
(pi as any).on("agent_end", () => {
|
|
305
|
+
agentRunning = false;
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
registerInputNeeded(pi, config, cwd, dispatch);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* pi ≥0.84.4 fires `ui_prompt_start`/`ui_prompt_end` around every blocking
|
|
313
|
+
* user-facing prompt — including ones that emit no bus event of their own
|
|
314
|
+
* (third-party ask_user tools, the permission prompt, the plan review).
|
|
315
|
+
*
|
|
316
|
+
* The start/end pair is registered whenever we are not a subagent child,
|
|
317
|
+
* independent of the `input_needed` flag: the open-prompt counter must stay
|
|
318
|
+
* paired so a prompt closing also disarms ask_user/permission reminders.
|
|
319
|
+
* Only the notification itself respects the flag, and it fires only while
|
|
320
|
+
* the agent is running — a `ui_prompt_start` while idle is the user's own
|
|
321
|
+
* overlay (e.g. /unipi:settings).
|
|
322
|
+
*/
|
|
323
|
+
function registerInputNeeded(
|
|
324
|
+
pi: ExtensionAPI,
|
|
325
|
+
config: NotifyConfig,
|
|
326
|
+
cwd: string,
|
|
327
|
+
dispatch: DispatchNotification,
|
|
328
|
+
): void {
|
|
329
|
+
// Subagent children never own a user-facing prompt.
|
|
330
|
+
if (process.env.UNIPI_SUBAGENT_CHILD === "1") return;
|
|
331
|
+
|
|
332
|
+
(pi as any).on("ui_prompt_start", (payload: unknown) => {
|
|
333
|
+
openPrompts += 1;
|
|
334
|
+
const eventConfig = config.events["input_needed"];
|
|
335
|
+
if (!eventConfig?.enabled) return;
|
|
336
|
+
if (!agentRunning) return;
|
|
337
|
+
// Same prompt already announced as ask_user/permission_request.
|
|
338
|
+
if (Date.now() - lastBlockingAlertAt < PROMPT_DEDUP_MS) return;
|
|
339
|
+
notifyBlocking(
|
|
340
|
+
pi,
|
|
341
|
+
"input_needed",
|
|
342
|
+
`Pi — ${BUILTIN_EVENTS.input_needed.label}`,
|
|
343
|
+
buildInputNeededMessage(payload),
|
|
344
|
+
eventConfig.platforms,
|
|
345
|
+
config,
|
|
346
|
+
cwd,
|
|
347
|
+
dispatch,
|
|
348
|
+
);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
(pi as any).on("ui_prompt_end", () => {
|
|
352
|
+
openPrompts = Math.max(0, openPrompts - 1);
|
|
353
|
+
if (openPrompts === 0) disarmRenotify();
|
|
354
|
+
});
|
|
250
355
|
}
|
|
251
356
|
|
|
252
357
|
/** Get all platforms that are currently enabled in config */
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pi-unipi/notify — Internal helper: build notification message from pi's
|
|
3
|
+
* `ui_prompt_start` lifecycle payload.
|
|
4
|
+
*
|
|
5
|
+
* @internal — not part of the public API. Shared by the event listener and tests.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Longest prompt title kept verbatim before an ellipsis is appended. */
|
|
9
|
+
export const INPUT_TITLE_MAX_CHARS = 120;
|
|
10
|
+
|
|
11
|
+
function cleanKind(value: unknown): string {
|
|
12
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : "prompt";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Truncate by code points (Array.from) so surrogate pairs are never split. */
|
|
16
|
+
function truncate(text: string, max: number): string {
|
|
17
|
+
const chars = Array.from(text);
|
|
18
|
+
return chars.length <= max ? text : `${chars.slice(0, max).join("")}…`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Build a human-readable notification message from a ui_prompt_start payload. */
|
|
22
|
+
export function buildInputNeededMessage(payload: unknown): string {
|
|
23
|
+
const p = (payload ?? {}) as { title?: unknown; kind?: unknown };
|
|
24
|
+
const title = typeof p.title === "string" ? p.title.replace(/\s+/g, " ").trim() : "";
|
|
25
|
+
if (title.length === 0) return `Waiting for your input (${cleanKind(p.kind)})`;
|
|
26
|
+
return `Waiting for your input: ${truncate(title, INPUT_TITLE_MAX_CHARS)}`;
|
|
27
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/notify",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Cross-platform notification extension for Pi — native OS, Gotify, and Telegram notifications for agent lifecycle events",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
37
|
+
"@pi-unipi/core": "3.0.0-alpha.29",
|
|
38
38
|
"node-notifier": "^10.0.1"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
@@ -30,6 +30,7 @@ export const DEFAULT_CONFIG: NotifyConfig = {
|
|
|
30
30
|
session_shutdown: { enabled: false, platforms: [] },
|
|
31
31
|
ask_user_prompt: { enabled: false, platforms: [] },
|
|
32
32
|
permission_request: { enabled: false, platforms: [] },
|
|
33
|
+
input_needed: { enabled: false, platforms: [] },
|
|
33
34
|
},
|
|
34
35
|
native: {
|
|
35
36
|
enabled: true,
|
|
@@ -79,6 +80,7 @@ const EVENT_PHRASES: Record<string, string> = {
|
|
|
79
80
|
session_shutdown: "the session shuts down.",
|
|
80
81
|
ask_user_prompt: "the agent asks you a question.",
|
|
81
82
|
permission_request: "a permission prompt opens.",
|
|
83
|
+
input_needed: "the agent is waiting on any prompt (covers tools that send no event of their own).",
|
|
82
84
|
};
|
|
83
85
|
|
|
84
86
|
/** One section per known event: enable + platform routing. */
|
|
@@ -38,7 +38,8 @@ Help users configure the `@pi-unipi/notify` notification system.
|
|
|
38
38
|
"memory_consolidated": { "enabled": false, "platforms": [] },
|
|
39
39
|
"session_shutdown": { "enabled": false, "platforms": [] },
|
|
40
40
|
"ask_user_prompt": { "enabled": false, "platforms": [] },
|
|
41
|
-
"permission_request": { "enabled": false, "platforms": [] }
|
|
41
|
+
"permission_request": { "enabled": false, "platforms": [] },
|
|
42
|
+
"input_needed": { "enabled": false, "platforms": [] }
|
|
42
43
|
},
|
|
43
44
|
"native": {
|
|
44
45
|
"enabled": true,
|
|
@@ -207,10 +208,11 @@ ntfy uses dedicated `ntfy.json` files at both global and project scope, with ful
|
|
|
207
208
|
| `session_shutdown` | Off | Session ends |
|
|
208
209
|
| `ask_user_prompt` | Off | Agent asked a question and is waiting for an answer |
|
|
209
210
|
| `permission_request` | Off | A permission prompt is about to be shown |
|
|
211
|
+
| `input_needed` | Off | The agent waits on any prompt while it runs (covers tools that send no event of their own) |
|
|
210
212
|
|
|
211
213
|
Each event can override `platforms` — empty array means use `defaultPlatforms`.
|
|
212
214
|
|
|
213
|
-
`ask_user_prompt` and `
|
|
215
|
+
`ask_user_prompt`, `permission_request` and `input_needed` are **blocking** events: while one is unanswered the agent is parked, so notify re-sends it periodically (see the Re-notify unanswered prompts section under Platforms).
|
|
214
216
|
|
|
215
217
|
### `permission_request`
|
|
216
218
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/skill-registry",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Skill registry for pi — per-project skill on/off, a skill vault, and jev-judged skill exposure",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"main": "index.ts",
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
36
|
+
"@pi-unipi/core": "3.0.0-alpha.29"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/subagents",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Subagents for UniPi — Devin-model independent child agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"test": "npx tsx --test src/__tests__/*.test.ts"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
13
|
-
"@pi-unipi/utility": "3.0.0-alpha.
|
|
12
|
+
"@pi-unipi/core": "3.0.0-alpha.29",
|
|
13
|
+
"@pi-unipi/utility": "3.0.0-alpha.29",
|
|
14
14
|
"@earendil-works/pi-agent-core": "^0.87.1",
|
|
15
15
|
"acorn": "8.18.0"
|
|
16
16
|
},
|
|
@@ -25336,10 +25336,10 @@ import { dirname as dirname20, join as join37 } from "node:path";
|
|
|
25336
25336
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
25337
25337
|
function primaryArg(name, args) {
|
|
25338
25338
|
if (!args) return "";
|
|
25339
|
-
const
|
|
25339
|
+
const truncate3 = (v, max) => v.length > max ? `${v.slice(0, Math.max(0, max - 1))}\u2026` : v;
|
|
25340
25340
|
const firstLine3 = (v) => v.split("\n", 1)[0] ?? "";
|
|
25341
25341
|
const value = name === "bash" ? args.command : name === "read" || name === "edit" || name === "write" ? args.path ?? args.file_path ?? args.filePath : Object.values(args).find((entry) => typeof entry === "string");
|
|
25342
|
-
return typeof value === "string" ?
|
|
25342
|
+
return typeof value === "string" ? truncate3(firstLine3(value), 100) : "";
|
|
25343
25343
|
}
|
|
25344
25344
|
var DENY_WITH_NOTE = "Deny with note\u2026";
|
|
25345
25345
|
var BACKGROUND_DENY_NOTE = "Permission denied for this tool: this agent is running in the background, where tools that would require approval are automatically denied. Do not retry variants of this call; finish what you can without it and say in your report what needs approval.";
|
|
@@ -36577,8 +36577,8 @@ function renderMcpSettingsOverlay(params) {
|
|
|
36577
36577
|
const selected = i === state2.selectedIndex;
|
|
36578
36578
|
const statusIcon = server.status === "running" ? "\u25CF" : server.status === "error" ? "\u2717" : server.enabled ? "\u25CB" : "\u25CB";
|
|
36579
36579
|
const label = `${statusIcon} ${server.enabled ? "" : "disabled \xB7 "}${server.name}`;
|
|
36580
|
-
const tools = server.status === "running" && server.toolCount > 0 ? `${server.toolCount} tools` : server.status === "error" && server.error ?
|
|
36581
|
-
const value = `${
|
|
36580
|
+
const tools = server.status === "running" && server.toolCount > 0 ? `${server.toolCount} tools` : server.status === "error" && server.error ? truncate3(server.error, 20) : "stopped";
|
|
36581
|
+
const value = `${truncate3(server.command, 24)} \xB7 ${tools} \xB7 [${server.source}]`;
|
|
36582
36582
|
body.push(hubExactRow(hubRowColumns({
|
|
36583
36583
|
inner,
|
|
36584
36584
|
selected,
|
|
@@ -36600,7 +36600,7 @@ function renderMcpSettingsOverlay(params) {
|
|
|
36600
36600
|
title: hubBoldText(hubFrameTitle("mcp", [], `\u2014 ${state2.viewScope}`)),
|
|
36601
36601
|
borderFg: (t) => hubTheme.fg("borderMuted", t)
|
|
36602
36602
|
});
|
|
36603
|
-
function
|
|
36603
|
+
function truncate3(text, n) {
|
|
36604
36604
|
return text.length > n ? text.slice(0, n - 1) + "\u2026" : text;
|
|
36605
36605
|
}
|
|
36606
36606
|
}
|
|
@@ -36879,7 +36879,8 @@ var VALID_PLATFORMS = /* @__PURE__ */ new Set([
|
|
|
36879
36879
|
]);
|
|
36880
36880
|
var BLOCKING_EVENTS = /* @__PURE__ */ new Set([
|
|
36881
36881
|
"ask_user_prompt",
|
|
36882
|
-
"permission_request"
|
|
36882
|
+
"permission_request",
|
|
36883
|
+
"input_needed"
|
|
36883
36884
|
]);
|
|
36884
36885
|
function isBlockingEvent(eventType) {
|
|
36885
36886
|
return eventType !== void 0 && BLOCKING_EVENTS.has(eventType);
|
|
@@ -36948,7 +36949,8 @@ var DEFAULT_CONFIG5 = {
|
|
|
36948
36949
|
memory_consolidated: { enabled: false, platforms: [] },
|
|
36949
36950
|
session_shutdown: { enabled: false, platforms: [] },
|
|
36950
36951
|
ask_user_prompt: { enabled: false, platforms: [] },
|
|
36951
|
-
permission_request: { enabled: false, platforms: [] }
|
|
36952
|
+
permission_request: { enabled: false, platforms: [] },
|
|
36953
|
+
input_needed: { enabled: false, platforms: [] }
|
|
36952
36954
|
},
|
|
36953
36955
|
native: {
|
|
36954
36956
|
enabled: true,
|
|
@@ -36992,7 +36994,8 @@ var EVENT_PHRASES = {
|
|
|
36992
36994
|
memory_consolidated: "a memory consolidation completes.",
|
|
36993
36995
|
session_shutdown: "the session shuts down.",
|
|
36994
36996
|
ask_user_prompt: "the agent asks you a question.",
|
|
36995
|
-
permission_request: "a permission prompt opens."
|
|
36997
|
+
permission_request: "a permission prompt opens.",
|
|
36998
|
+
input_needed: "the agent is waiting on any prompt (covers tools that send no event of their own)."
|
|
36996
36999
|
};
|
|
36997
37000
|
var EVENT_SECTIONS = Object.keys(DEFAULT_CONFIG5.events).map((event) => ({
|
|
36998
37001
|
title: event,
|
|
@@ -37558,6 +37561,22 @@ function buildPermissionPromptMessage(payload) {
|
|
|
37558
37561
|
return parts.join(" ");
|
|
37559
37562
|
}
|
|
37560
37563
|
|
|
37564
|
+
// packages/notify/input-needed-message.ts
|
|
37565
|
+
var INPUT_TITLE_MAX_CHARS = 120;
|
|
37566
|
+
function cleanKind(value) {
|
|
37567
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : "prompt";
|
|
37568
|
+
}
|
|
37569
|
+
function truncate2(text, max) {
|
|
37570
|
+
const chars = Array.from(text);
|
|
37571
|
+
return chars.length <= max ? text : `${chars.slice(0, max).join("")}\u2026`;
|
|
37572
|
+
}
|
|
37573
|
+
function buildInputNeededMessage(payload) {
|
|
37574
|
+
const p = payload ?? {};
|
|
37575
|
+
const title = typeof p.title === "string" ? p.title.replace(/\s+/g, " ").trim() : "";
|
|
37576
|
+
if (title.length === 0) return `Waiting for your input (${cleanKind(p.kind)})`;
|
|
37577
|
+
return `Waiting for your input: ${truncate2(title, INPUT_TITLE_MAX_CHARS)}`;
|
|
37578
|
+
}
|
|
37579
|
+
|
|
37561
37580
|
// packages/notify/summarize.ts
|
|
37562
37581
|
var SYSTEM_PROMPT2 = "Summarize this in one concise sentence for a push notification. Reply with ONLY the summary.";
|
|
37563
37582
|
var MAX_INPUT_CHARS = 2e3;
|
|
@@ -37675,6 +37694,10 @@ function defaultEventPriority(eventKey) {
|
|
|
37675
37694
|
var sessionCtx = null;
|
|
37676
37695
|
var unsubs = [];
|
|
37677
37696
|
var renotifyTimer;
|
|
37697
|
+
var PROMPT_DEDUP_MS = 2e3;
|
|
37698
|
+
var agentRunning = false;
|
|
37699
|
+
var openPrompts = 0;
|
|
37700
|
+
var lastBlockingAlertAt = 0;
|
|
37678
37701
|
function disarmRenotify() {
|
|
37679
37702
|
const timer = renotifyTimer;
|
|
37680
37703
|
renotifyTimer = void 0;
|
|
@@ -37707,8 +37730,16 @@ function armRenotify(pi, title, message, platforms, eventType, config, cwd, disp
|
|
|
37707
37730
|
timer.unref?.();
|
|
37708
37731
|
renotifyTimer = timer;
|
|
37709
37732
|
}
|
|
37733
|
+
function notifyBlocking(pi, eventKey, title, message, platforms, config, cwd, dispatch) {
|
|
37734
|
+
if (eventKey !== "input_needed") lastBlockingAlertAt = Date.now();
|
|
37735
|
+
dispatch(pi, title, message, platforms, eventKey, config, cwd, "high").catch(() => {
|
|
37736
|
+
});
|
|
37737
|
+
armRenotify(pi, title, message, platforms, eventKey, config, cwd, dispatch);
|
|
37738
|
+
}
|
|
37710
37739
|
function unregisterAll() {
|
|
37711
37740
|
disarmRenotify();
|
|
37741
|
+
agentRunning = false;
|
|
37742
|
+
openPrompts = 0;
|
|
37712
37743
|
for (const unsub of unsubs) {
|
|
37713
37744
|
try {
|
|
37714
37745
|
unsub();
|
|
@@ -37732,18 +37763,23 @@ var BUILTIN_EVENTS = {
|
|
|
37732
37763
|
memory_consolidated: { hook: UNIPI_EVENTS.MEMORY_CONSOLIDATED, label: "Memory Saved" },
|
|
37733
37764
|
session_shutdown: { hook: "session_shutdown", label: "Session End" },
|
|
37734
37765
|
ask_user_prompt: { hook: UNIPI_EVENTS.ASK_USER_PROMPT, label: "Question Asked" },
|
|
37735
|
-
permission_request: { hook: PERMISSION_UI_PROMPT_EVENT, label: "Permission Request" }
|
|
37766
|
+
permission_request: { hook: PERMISSION_UI_PROMPT_EVENT, label: "Permission Request" },
|
|
37767
|
+
input_needed: { hook: "ui_prompt_start", label: "Input Needed" }
|
|
37736
37768
|
};
|
|
37737
37769
|
var LIFECYCLE_EVENTS = /* @__PURE__ */ new Set(["agent_end", "agent_settled", "session_shutdown"]);
|
|
37738
37770
|
function registerEventListeners(pi, config, cwd, dispatch = dispatchNotification) {
|
|
37739
37771
|
unregisterAll();
|
|
37740
37772
|
for (const [eventKey, def] of Object.entries(BUILTIN_EVENTS)) {
|
|
37741
|
-
if (isAgentNotificationEvent(eventKey)) continue;
|
|
37773
|
+
if (isAgentNotificationEvent(eventKey) || eventKey === "input_needed") continue;
|
|
37742
37774
|
const eventConfig = config.events[eventKey];
|
|
37743
37775
|
if (!eventConfig?.enabled) continue;
|
|
37744
37776
|
const handler = (payload) => {
|
|
37745
37777
|
const title = `Pi \u2014 ${def.label}`;
|
|
37746
37778
|
const message = buildEventMessage(eventKey, payload);
|
|
37779
|
+
if (isBlockingEvent(eventKey)) {
|
|
37780
|
+
notifyBlocking(pi, eventKey, title, message, eventConfig.platforms, config, cwd, dispatch);
|
|
37781
|
+
return;
|
|
37782
|
+
}
|
|
37747
37783
|
dispatch(
|
|
37748
37784
|
pi,
|
|
37749
37785
|
title,
|
|
@@ -37755,9 +37791,6 @@ function registerEventListeners(pi, config, cwd, dispatch = dispatchNotification
|
|
|
37755
37791
|
defaultEventPriority(eventKey)
|
|
37756
37792
|
).catch(() => {
|
|
37757
37793
|
});
|
|
37758
|
-
if (isBlockingEvent(eventKey)) {
|
|
37759
|
-
armRenotify(pi, title, message, eventConfig.platforms, eventKey, config, cwd, dispatch);
|
|
37760
|
-
}
|
|
37761
37794
|
};
|
|
37762
37795
|
if (LIFECYCLE_EVENTS.has(eventKey)) {
|
|
37763
37796
|
pi.on(def.hook, handler);
|
|
@@ -37768,23 +37801,55 @@ function registerEventListeners(pi, config, cwd, dispatch = dispatchNotification
|
|
|
37768
37801
|
const askUserConfig = config.events["ask_user_prompt"];
|
|
37769
37802
|
if (askUserConfig?.enabled) {
|
|
37770
37803
|
unsubs.push(pi.events.on(ASK_USER_PROMPT_EVENT, (payload) => {
|
|
37771
|
-
|
|
37772
|
-
|
|
37773
|
-
|
|
37774
|
-
|
|
37775
|
-
|
|
37804
|
+
notifyBlocking(
|
|
37805
|
+
pi,
|
|
37806
|
+
"ask_user_prompt",
|
|
37807
|
+
`Pi \u2014 ${BUILTIN_EVENTS.ask_user_prompt.label}`,
|
|
37808
|
+
buildAskUserPromptMessage(payload),
|
|
37809
|
+
askUserConfig.platforms,
|
|
37810
|
+
config,
|
|
37811
|
+
cwd,
|
|
37812
|
+
dispatch
|
|
37776
37813
|
);
|
|
37777
|
-
armRenotify(pi, title, message, askUserConfig.platforms, "ask_user_prompt", config, cwd, dispatch);
|
|
37778
37814
|
}));
|
|
37779
37815
|
}
|
|
37780
37816
|
unsubs.push(pi.events.on("herdr:blocked", (payload) => {
|
|
37781
37817
|
if (payload?.active === false) disarmRenotify();
|
|
37782
37818
|
}));
|
|
37783
37819
|
pi.on("agent_start", () => {
|
|
37820
|
+
agentRunning = true;
|
|
37784
37821
|
disarmRenotify();
|
|
37785
37822
|
});
|
|
37786
37823
|
registerAgentNotification(pi, "agent_end", config, cwd, dispatch);
|
|
37787
37824
|
registerAgentNotification(pi, "agent_settled", config, cwd, dispatch);
|
|
37825
|
+
pi.on("agent_end", () => {
|
|
37826
|
+
agentRunning = false;
|
|
37827
|
+
});
|
|
37828
|
+
registerInputNeeded(pi, config, cwd, dispatch);
|
|
37829
|
+
}
|
|
37830
|
+
function registerInputNeeded(pi, config, cwd, dispatch) {
|
|
37831
|
+
if (process.env.UNIPI_SUBAGENT_CHILD === "1") return;
|
|
37832
|
+
pi.on("ui_prompt_start", (payload) => {
|
|
37833
|
+
openPrompts += 1;
|
|
37834
|
+
const eventConfig = config.events["input_needed"];
|
|
37835
|
+
if (!eventConfig?.enabled) return;
|
|
37836
|
+
if (!agentRunning) return;
|
|
37837
|
+
if (Date.now() - lastBlockingAlertAt < PROMPT_DEDUP_MS) return;
|
|
37838
|
+
notifyBlocking(
|
|
37839
|
+
pi,
|
|
37840
|
+
"input_needed",
|
|
37841
|
+
`Pi \u2014 ${BUILTIN_EVENTS.input_needed.label}`,
|
|
37842
|
+
buildInputNeededMessage(payload),
|
|
37843
|
+
eventConfig.platforms,
|
|
37844
|
+
config,
|
|
37845
|
+
cwd,
|
|
37846
|
+
dispatch
|
|
37847
|
+
);
|
|
37848
|
+
});
|
|
37849
|
+
pi.on("ui_prompt_end", () => {
|
|
37850
|
+
openPrompts = Math.max(0, openPrompts - 1);
|
|
37851
|
+
if (openPrompts === 0) disarmRenotify();
|
|
37852
|
+
});
|
|
37788
37853
|
}
|
|
37789
37854
|
function getEnabledPlatforms(config, ntfyEnabled) {
|
|
37790
37855
|
const enabled = [];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/updater",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Auto-updater, changelog browser, and readme browser for Unipi — checks npm registry, renders CHANGELOG.md and README.md files in TUI overlays",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
37
|
+
"@pi-unipi/core": "3.0.0-alpha.29"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/utility",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Utility commands and tools for Pi coding agent — lifecycle, diagnostics, cache, analytics, display, batch execution",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
39
|
+
"@pi-unipi/core": "3.0.0-alpha.29"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {},
|
|
42
42
|
"peerDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/watchdog",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Jev watchdog for long-running tool calls and background tasks — judges stuck work via TypeSafe System One and kills or warns",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"access": "public"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@pi-unipi/background-tasks": "3.0.0-alpha.
|
|
36
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
35
|
+
"@pi-unipi/background-tasks": "3.0.0-alpha.29",
|
|
36
|
+
"@pi-unipi/core": "3.0.0-alpha.29"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/web-api",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Web search, read, and summarize tools with provider-based backend selection for Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"README.md"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
34
|
+
"@pi-unipi/core": "3.0.0-alpha.29",
|
|
35
35
|
"defuddle": "^0.18.1",
|
|
36
36
|
"linkedom": "^0.18.12",
|
|
37
37
|
"wreq-js": "^2.3.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/workflow",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.29",
|
|
4
4
|
"description": "Plan mode and permission modes for the Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
30
|
+
"@pi-unipi/core": "3.0.0-alpha.29"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@earendil-works/pi-ai": "^0.87.1",
|