@aliou/pi-processes 0.9.5 → 0.10.0
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/CONTRIBUTING.md +40 -42
- package/README.md +54 -84
- package/extensions/process-tabs.ts +26 -0
- package/extensions/processes/client.ts +194 -0
- package/extensions/processes/commands/clear.ts +29 -0
- package/extensions/processes/commands/kill.ts +152 -0
- package/extensions/processes/commands/overview.ts +102 -0
- package/extensions/processes/components/overview-component.ts +729 -0
- package/extensions/processes/components/overview-panel.ts +177 -0
- package/extensions/processes/config/defaults.ts +28 -0
- package/extensions/processes/config/index.ts +13 -0
- package/extensions/processes/config/loader.ts +62 -0
- package/extensions/processes/config/migrations/000-import-legacy-process-config.ts +113 -0
- package/extensions/processes/config/migrations/001-v0-9-4-to-v0-10-0-config.ts +184 -0
- package/extensions/processes/config/migrations/002-stamp-v0-10-0-config-version.ts +21 -0
- package/extensions/processes/config/migrations/index.ts +25 -0
- package/extensions/processes/config/schema.ts +9 -0
- package/extensions/processes/config/types.ts +72 -0
- package/extensions/processes/constants.ts +1 -0
- package/extensions/processes/handlers/commands.ts +113 -0
- package/extensions/processes/handlers/kill-process.ts +31 -0
- package/extensions/processes/handlers/notifications.ts +147 -0
- package/extensions/processes/handlers/requests.ts +114 -0
- package/extensions/processes/handlers/subscriptions.ts +144 -0
- package/extensions/processes/hooks/background-blocker.ts +201 -0
- package/extensions/processes/hooks/cleanup.ts +43 -0
- package/extensions/processes/hooks/event-bridge.ts +32 -0
- package/extensions/processes/i18n/index.ts +3 -0
- package/extensions/processes/i18n/messages.ts +27 -0
- package/extensions/processes/i18n/translator.ts +49 -0
- package/extensions/processes/index.ts +109 -0
- package/extensions/processes/message-renderer.ts +117 -0
- package/extensions/processes/notification-sender.ts +43 -0
- package/extensions/processes/notifications/classify.ts +27 -0
- package/extensions/processes/notifications/log-matchers.ts +146 -0
- package/extensions/processes/notifications/registry.ts +225 -0
- package/extensions/processes/notifications/render-content.ts +122 -0
- package/extensions/processes/notifications/service.ts +336 -0
- package/extensions/processes/notifications/types.ts +11 -0
- package/extensions/processes/settings/apply-setting-change.ts +30 -0
- package/extensions/processes/settings/build-sections.ts +420 -0
- package/extensions/processes/settings/index.ts +42 -0
- package/extensions/processes/tools/clear/index.ts +21 -0
- package/extensions/processes/tools/clear/render.ts +40 -0
- package/extensions/processes/tools/components/index.ts +4 -0
- package/extensions/processes/tools/components/process-action-header.ts +31 -0
- package/extensions/processes/tools/components/process-action-title.ts +17 -0
- package/extensions/processes/tools/components/tool-layout.ts +70 -0
- package/extensions/processes/tools/components/watch.ts +53 -0
- package/extensions/processes/tools/index.ts +265 -0
- package/extensions/processes/tools/list/index.ts +157 -0
- package/extensions/processes/tools/list/render.ts +211 -0
- package/extensions/processes/tools/notify.ts +191 -0
- package/extensions/processes/tools/output/index.ts +307 -0
- package/extensions/processes/tools/output/render.ts +229 -0
- package/extensions/processes/tools/schema.ts +263 -0
- package/extensions/processes/tools/start/index.ts +64 -0
- package/extensions/processes/tools/start/render.ts +67 -0
- package/extensions/processes/tools/stop/index.ts +35 -0
- package/extensions/processes/tools/stop/render.ts +43 -0
- package/extensions/processes/tools/update/index.ts +320 -0
- package/extensions/processes/tools/update/render.ts +251 -0
- package/extensions/processes/tools/utils.ts +112 -0
- package/extensions/processes/tools/watch-format.ts +14 -0
- package/extensions/processes/tools/write/index.ts +75 -0
- package/extensions/processes/tools/write/render.ts +68 -0
- package/extensions/processes/utils/truncate.ts +285 -0
- package/extensions/processes-dock/client.ts +60 -0
- package/extensions/processes-dock/commands/dock.ts +70 -0
- package/extensions/processes-dock/commands/pin.ts +166 -0
- package/extensions/processes-dock/components/log-dock-component.ts +375 -0
- package/extensions/processes-dock/dock-state.ts +33 -0
- package/extensions/processes-dock/index.ts +28 -0
- package/extensions/processes-dock/logs-client.ts +5 -0
- package/extensions/processes-dock/widget/setup.ts +520 -0
- package/extensions/processes-dock/widget/status.ts +149 -0
- package/extensions/processes-dock/widget/types.ts +16 -0
- package/extensions/processes-logs/client.ts +51 -0
- package/extensions/processes-logs/commands/logs.ts +108 -0
- package/extensions/processes-logs/completions.ts +31 -0
- package/extensions/processes-logs/components/log-file-viewer.ts +274 -0
- package/extensions/processes-logs/components/log-overlay-component.ts +685 -0
- package/extensions/processes-logs/index.ts +27 -0
- package/extensions/processes-logs/logs-client.ts +101 -0
- package/extensions/shared/line-buffer.ts +35 -0
- package/extensions/shared/output-payload.ts +28 -0
- package/extensions/shared/ui.ts +146 -0
- package/package.json +34 -9
- package/schema.json +134 -0
- package/skills/pi-processes/SKILL.md +496 -25
- package/src/get-manager.ts +15 -0
- package/src/manager/index.ts +182 -0
- package/src/manager/internal-types.ts +130 -0
- package/src/manager/limits.ts +15 -0
- package/src/manager/process-log-store.ts +422 -0
- package/src/manager/process-output.ts +345 -0
- package/src/manager/process-registry.ts +78 -0
- package/src/manager/process-runtime-controller.ts +499 -0
- package/src/protocol/broadcasts.ts +14 -0
- package/src/protocol/channels.ts +30 -0
- package/src/protocol/commands.ts +24 -0
- package/src/protocol/index.ts +34 -0
- package/src/protocol/logs.ts +23 -0
- package/src/protocol/notifications.ts +48 -0
- package/src/protocol/requests.ts +76 -0
- package/src/types.ts +66 -0
- package/src/utils/ansi.ts +2 -4
- package/src/utils/format.ts +24 -32
- package/src/utils/index.ts +5 -1
- package/src/utils/is-record.ts +3 -0
- package/src/utils/match-line.ts +32 -0
- package/src/utils/platform.ts +13 -0
- package/src/utils/shorten-path.ts +11 -0
- package/src/utils/signals.ts +22 -0
- package/src/commands/clear/command.ts +0 -14
- package/src/commands/clear/index.ts +0 -1
- package/src/commands/completions.ts +0 -38
- package/src/commands/dock/command.ts +0 -29
- package/src/commands/dock/index.ts +0 -1
- package/src/commands/index.ts +0 -33
- package/src/commands/kill/command.ts +0 -69
- package/src/commands/kill/index.ts +0 -1
- package/src/commands/logs/command.ts +0 -47
- package/src/commands/logs/index.ts +0 -1
- package/src/commands/pick-process.ts +0 -34
- package/src/commands/pin/command.ts +0 -34
- package/src/commands/pin/index.ts +0 -1
- package/src/commands/processes/command.ts +0 -39
- package/src/commands/processes/index.ts +0 -1
- package/src/commands/settings/apply-setting-change.ts +0 -72
- package/src/commands/settings/build-sections.ts +0 -160
- package/src/commands/settings/command.ts +0 -20
- package/src/commands/settings/index.ts +0 -1
- package/src/components/log-dock-component.test.ts +0 -29
- package/src/components/log-dock-component.ts +0 -236
- package/src/components/log-file-viewer.ts +0 -317
- package/src/components/log-overlay-component.ts +0 -546
- package/src/components/panel-helpers.ts +0 -37
- package/src/components/process-picker-component.ts +0 -166
- package/src/components/processes-component.ts +0 -485
- package/src/components/status-format.ts +0 -38
- package/src/config.ts +0 -107
- package/src/constants/index.ts +0 -16
- package/src/constants/types.ts +0 -119
- package/src/hooks/background-blocker.ts +0 -66
- package/src/hooks/cleanup.ts +0 -10
- package/src/hooks/index.ts +0 -32
- package/src/hooks/message-renderer.ts +0 -115
- package/src/hooks/process-end.ts +0 -69
- package/src/hooks/process-watch.ts +0 -85
- package/src/hooks/utils.ts +0 -23
- package/src/hooks/widget/index.ts +0 -2
- package/src/hooks/widget/setup.ts +0 -167
- package/src/hooks/widget/status-widget.ts +0 -105
- package/src/hooks/widget/types.ts +0 -20
- package/src/index.ts +0 -35
- package/src/manager.test.ts +0 -331
- package/src/manager.ts +0 -758
- package/src/tools/actions/clear.ts +0 -20
- package/src/tools/actions/debug.ts +0 -155
- package/src/tools/actions/index.ts +0 -171
- package/src/tools/actions/kill.ts +0 -89
- package/src/tools/actions/list.ts +0 -188
- package/src/tools/actions/logs.ts +0 -117
- package/src/tools/actions/output-truncate.ts +0 -187
- package/src/tools/actions/output.test.ts +0 -392
- package/src/tools/actions/output.ts +0 -447
- package/src/tools/actions/start.ts +0 -245
- package/src/tools/actions/write.ts +0 -113
- package/src/tools/index.ts +0 -207
- package/src/utils/ansi.test.ts +0 -22
- package/src/utils/command-executor.test.ts +0 -48
- package/src/utils/keybindings.ts +0 -71
package/CONTRIBUTING.md
CHANGED
|
@@ -8,6 +8,11 @@ Keep development details, testing notes, internal tool guidance, and docs build
|
|
|
8
8
|
|
|
9
9
|
## Development
|
|
10
10
|
|
|
11
|
+
Requirements:
|
|
12
|
+
|
|
13
|
+
- Node.js `22.19.0` or newer
|
|
14
|
+
- pnpm `10.26.1`
|
|
15
|
+
|
|
11
16
|
Install dependencies:
|
|
12
17
|
|
|
13
18
|
```bash
|
|
@@ -17,20 +22,34 @@ pnpm install
|
|
|
17
22
|
Run checks:
|
|
18
23
|
|
|
19
24
|
```bash
|
|
20
|
-
pnpm lint
|
|
21
25
|
pnpm typecheck
|
|
26
|
+
pnpm lint
|
|
27
|
+
pnpm test
|
|
28
|
+
pnpm test:e2e
|
|
22
29
|
```
|
|
23
30
|
|
|
24
31
|
## Repository layout
|
|
25
32
|
|
|
26
|
-
- `src/` -
|
|
27
|
-
- `
|
|
28
|
-
- `
|
|
29
|
-
- `
|
|
30
|
-
- `
|
|
33
|
+
- `src/` - Pi-agnostic process management, types, protocol, and utilities
|
|
34
|
+
- `extensions/processes/` - core extension, process tool (start, list, output, update, write, stop, clear), settings, lifecycle hooks, notifications, protocol handlers, `/ps`, `/ps:kill`, `/ps:clear`, and `/ps:settings`
|
|
35
|
+
- `extensions/processes-logs/` - `/ps:logs` command and log overlay
|
|
36
|
+
- `extensions/processes-dock/` - `/ps:dock`, `/ps:pin`, the dock widget, and the status widget
|
|
37
|
+
- `extensions/shared/` - shared UI helpers (`statusDot`, `processStatusTone`, `LineComponent`, etc.) used across all three extensions
|
|
31
38
|
- `skills/` - shipped package skills
|
|
32
39
|
- `.agents/skills/` - local repo-only skills for development workflows
|
|
33
|
-
|
|
40
|
+
|
|
41
|
+
## Package metadata
|
|
42
|
+
|
|
43
|
+
The package targets Pi `0.80.3`.
|
|
44
|
+
|
|
45
|
+
Pi bundles core packages for extensions. Keep direct imports of these packages in `peerDependencies` with `"*"` ranges and exact local versions in `devDependencies`:
|
|
46
|
+
|
|
47
|
+
- `@earendil-works/pi-ai`
|
|
48
|
+
- `@earendil-works/pi-coding-agent`
|
|
49
|
+
- `@earendil-works/pi-tui`
|
|
50
|
+
- `typebox`
|
|
51
|
+
|
|
52
|
+
Keep normal third-party runtime dependencies in `dependencies`.
|
|
34
53
|
|
|
35
54
|
## Internal behavior
|
|
36
55
|
|
|
@@ -58,15 +77,17 @@ pnpm lint
|
|
|
58
77
|
pnpm typecheck
|
|
59
78
|
```
|
|
60
79
|
|
|
61
|
-
Useful manual process scripts
|
|
80
|
+
Useful manual process scripts live under `tests/e2e/scripts/`:
|
|
62
81
|
|
|
63
82
|
```bash
|
|
64
|
-
./
|
|
65
|
-
./
|
|
66
|
-
./
|
|
67
|
-
./
|
|
83
|
+
./tests/e2e/scripts/continuous-output.sh # long-running stdout
|
|
84
|
+
./tests/e2e/scripts/error-log.sh # interleaved info/error on stdout+stderr
|
|
85
|
+
./tests/e2e/scripts/exited-task.sh # finite, exits 0
|
|
86
|
+
./tests/e2e/scripts/crash-on-file.sh <name> # waits for a marker file then crashes
|
|
68
87
|
```
|
|
69
88
|
|
|
89
|
+
See `.agents/skills/pi-processes-testing/SKILL.md` for the full manual QA workflow and the complete fixture script reference.
|
|
90
|
+
|
|
70
91
|
## Docs conventions
|
|
71
92
|
|
|
72
93
|
### README
|
|
@@ -86,38 +107,15 @@ Avoid putting these in `README.md`:
|
|
|
86
107
|
- detailed tool-call schemas
|
|
87
108
|
- release workflow notes
|
|
88
109
|
|
|
89
|
-
###
|
|
90
|
-
|
|
91
|
-
Use HTML comments in `README.md`:
|
|
92
|
-
|
|
93
|
-
```md
|
|
94
|
-
<!-- VIDEO: {"id":"process-panel","title":"Browse and manage processes from the panel"} -->
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
GitHub ignores these comments. The docs page build turns them into video blocks.
|
|
98
|
-
|
|
99
|
-
Add one placeholder for each feature section.
|
|
100
|
-
|
|
101
|
-
## Docs page build
|
|
102
|
-
|
|
103
|
-
The generated docs page lives under `.github/docs-site/` and is isolated from the extension source.
|
|
104
|
-
|
|
105
|
-
It reads `README.md`, converts markdown into structured content, replaces video placeholders, highlights code with Shiki, and builds a static page with Vite and Tailwind.
|
|
106
|
-
|
|
107
|
-
The GitHub Actions workflow for this lives in `.github/workflows/docs-page.yml`.
|
|
110
|
+
### Docs page build
|
|
108
111
|
|
|
109
|
-
|
|
112
|
+
The docs page is generated from `README.md` by an external build, not in this repo. Keep `README.md` self-contained with only standard markdown.
|
|
110
113
|
|
|
111
|
-
|
|
114
|
+
## Future design notes
|
|
112
115
|
|
|
113
|
-
|
|
116
|
+
Unimplemented design notes live in `docs/`:
|
|
114
117
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
3. runs migrations
|
|
118
|
-
4. checks server logs
|
|
119
|
-
5. updates seed data
|
|
120
|
-
6. reruns tests
|
|
121
|
-
7. cleans up the process
|
|
118
|
+
- `docs/future-cleanup-hooks.md` - planned `cleanup` support for `process start` / `process stop`
|
|
119
|
+
- `docs/future-persistent-manager.md` - planned cross-session process persistence
|
|
122
120
|
|
|
123
|
-
|
|
121
|
+
These describe intended future behavior, not current behavior. Active implementation work goes under `.agents/plans/`.
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-

|
|
1
|
+

|
|
2
2
|
|
|
3
3
|
# pi-processes
|
|
4
4
|
|
|
@@ -10,6 +10,8 @@ This extension lets Pi keep long-running commands alive while the conversation c
|
|
|
10
10
|
|
|
11
11
|
When a task needs a long-running command, Pi can start it in the background by itself and keep helping with the rest of the work.
|
|
12
12
|
|
|
13
|
+
[](https://assets.aliou.me/pi-extensions/demos/processes/v0.10.0/agent-starts-processes.mp4)
|
|
14
|
+
|
|
13
15
|
That means Pi can, for example:
|
|
14
16
|
|
|
15
17
|
- start a dev server and keep coding
|
|
@@ -17,9 +19,7 @@ That means Pi can, for example:
|
|
|
17
19
|
- run a local API while it inspects logs
|
|
18
20
|
- watch build output without blocking the conversation
|
|
19
21
|
|
|
20
|
-
You can then inspect, pin, or
|
|
21
|
-
|
|
22
|
-
<!-- VIDEO: {"id":"agent-starts-processes","title":"Pi starts a long-running process and keeps working"} -->
|
|
22
|
+
You can then inspect, pin, stop, or clear those processes from the UI.
|
|
23
23
|
|
|
24
24
|
## Installation
|
|
25
25
|
|
|
@@ -35,9 +35,19 @@ From git:
|
|
|
35
35
|
pi install git:github.com/aliou/pi-processes
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
## How Pi stays in the loop
|
|
39
|
+
|
|
40
|
+
Pi does not wait around for a background process. After it starts one, it keeps helping with the rest of the work and gets brought back automatically when something happens:
|
|
41
|
+
|
|
42
|
+
- a readiness marker appears in the logs (a server prints "ready")
|
|
43
|
+
- an error appears in the logs (a build prints a type error)
|
|
44
|
+
- the process exits, whether it succeeded, failed, or was killed
|
|
45
|
+
|
|
46
|
+
That is how Pi can start a dev server and then keep coding, or run a test watcher and react when a test fails, without sleeping or polling. If a watch fires too often, Pi can quiet it without restarting the process.
|
|
47
|
+
|
|
38
48
|
## Open the process panel
|
|
39
49
|
|
|
40
|
-
Use `/ps` to open the main process panel.
|
|
50
|
+
Use `/ps` to open the main process panel. It shows running and finished processes, with the most recent output preview. The preview opens on the newest page so you can see live activity without scrolling.
|
|
41
51
|
|
|
42
52
|
From there you can:
|
|
43
53
|
|
|
@@ -47,53 +57,45 @@ From there you can:
|
|
|
47
57
|
- kill a running process
|
|
48
58
|
- clear finished entries
|
|
49
59
|
|
|
50
|
-
Keys:
|
|
51
|
-
|
|
52
|
-
- `j/k` or arrow keys: move selection
|
|
53
|
-
- `J/K`: scroll preview
|
|
54
|
-
- `enter`: pin selected process to the dock
|
|
55
|
-
- `x`: kill selected process
|
|
56
|
-
- `c`: clear finished processes
|
|
57
|
-
- `q` or `esc`: close
|
|
58
|
-
|
|
59
|
-
<!-- VIDEO: {"id":"process-panel","title":"Browse and manage processes from the panel"} -->
|
|
60
|
-
|
|
61
60
|
## Inspect logs
|
|
62
61
|
|
|
63
|
-
Use `/ps:logs [id
|
|
62
|
+
Use `/ps:logs [id]` to open the log overlay for one process. The viewer is cached per process, so switching tabs preserves scroll position and follow mode.
|
|
64
63
|
|
|
65
64
|
This is useful when Pi started a server, watcher, or local API and you want to follow what it is doing in more detail.
|
|
66
65
|
|
|
67
|
-
|
|
66
|
+
## Control the dock
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
- `g/G`: jump to top or bottom
|
|
71
|
-
- `j/k` or arrow keys: scroll
|
|
72
|
-
- `s`: switch between combined, stdout, and stderr
|
|
73
|
-
- `f`: toggle follow mode
|
|
74
|
-
- `/`: search
|
|
75
|
-
- `n/N`: move between search matches
|
|
76
|
-
- `q` or `esc`: close
|
|
68
|
+
Use `/ps:dock [expand|collapse|close]` to control dock visibility.
|
|
77
69
|
|
|
78
|
-
|
|
70
|
+
The dock gives you a compact live view without leaving the conversation.
|
|
79
71
|
|
|
80
72
|
## Pin one process
|
|
81
73
|
|
|
82
|
-
Use `/ps:pin [id
|
|
74
|
+
Use `/ps:pin [id]` to keep the dock focused on one process.
|
|
83
75
|
|
|
84
76
|
This is useful when one process matters more than the others, such as a dev server or a test watcher.
|
|
85
77
|
|
|
86
78
|
Without arguments, Pi shows a picker.
|
|
87
79
|
|
|
88
|
-
|
|
80
|
+
## Stop and clear processes
|
|
89
81
|
|
|
90
|
-
|
|
82
|
+
Use `/ps:kill [id]` to stop a running process, and `/ps:clear` to remove finished entries from the panel and free their log storage.
|
|
91
83
|
|
|
92
|
-
|
|
84
|
+
`/ps:kill` waits for the process to actually exit (or time out), so the result it reports reflects what happened. Without arguments, Pi shows a picker.
|
|
93
85
|
|
|
94
|
-
|
|
86
|
+
`/ps:clear` never touches live processes.
|
|
87
|
+
|
|
88
|
+
## Keep a status line in view
|
|
89
|
+
|
|
90
|
+
Enable the status widget in `/ps:settings` to show a compact line of running processes below the editor. Each process shows a status dot, its name, and its state, with `+N more` overflow when the line does not fit.
|
|
95
91
|
|
|
96
|
-
|
|
92
|
+
It is disabled by default. The widget reflows on resize and clears itself when the process list is empty.
|
|
93
|
+
|
|
94
|
+
## Send input to a process
|
|
95
|
+
|
|
96
|
+
Use the `process` tool with `action: "write"` to send bytes to a running process's stdin. This is how you drive interactive servers, REPLs, and CLIs that expect input after they start.
|
|
97
|
+
|
|
98
|
+
Pass `input` for the bytes to write, and set `end: true` to close stdin (for example to signal EOF to a waiting process).
|
|
97
99
|
|
|
98
100
|
## Adjust settings
|
|
99
101
|
|
|
@@ -106,78 +108,46 @@ Available settings include:
|
|
|
106
108
|
- shell path override
|
|
107
109
|
- dock defaults
|
|
108
110
|
- follow mode behavior
|
|
111
|
+
- status widget toggle
|
|
109
112
|
- optional background command interception
|
|
110
113
|
|
|
111
|
-
<!-- VIDEO: {"id":"settings","title":"Adjust process extension settings"} -->
|
|
112
|
-
|
|
113
114
|
## Platform support
|
|
114
115
|
|
|
115
116
|
- macOS: supported
|
|
116
117
|
- Linux: supported
|
|
117
118
|
- Windows: not supported
|
|
118
119
|
|
|
119
|
-
##
|
|
120
|
+
## Troubleshooting
|
|
120
121
|
|
|
121
|
-
|
|
122
|
+
### Pi started something and I want to see more output
|
|
122
123
|
|
|
123
|
-
|
|
124
|
-
- set `repeat: true` to trigger on every match
|
|
125
|
-
- scope by stream (`stdout`, `stderr`, `both`) to reduce noise
|
|
124
|
+
Open `/ps` for a quick overview, or use `/ps:logs` for full logs.
|
|
126
125
|
|
|
127
|
-
|
|
126
|
+
### I want one process to stay visible
|
|
128
127
|
|
|
129
|
-
|
|
130
|
-
{
|
|
131
|
-
"action": "start",
|
|
132
|
-
"name": "dev-server",
|
|
133
|
-
"command": "pnpm dev",
|
|
134
|
-
"logWatches": [
|
|
135
|
-
{ "pattern": "ready on http://localhost:3000" }
|
|
136
|
-
]
|
|
137
|
-
}
|
|
138
|
-
```
|
|
128
|
+
Use `/ps:pin` to focus the dock on that process.
|
|
139
129
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
```json
|
|
143
|
-
{
|
|
144
|
-
"action": "start",
|
|
145
|
-
"name": "builder",
|
|
146
|
-
"command": "pnpm build --watch",
|
|
147
|
-
"logWatches": [
|
|
148
|
-
{ "pattern": "TypeError|ReferenceError", "stream": "stderr" }
|
|
149
|
-
]
|
|
150
|
-
}
|
|
151
|
-
```
|
|
130
|
+
### I want Pi to avoid shell background tricks
|
|
152
131
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
```json
|
|
156
|
-
{
|
|
157
|
-
"action": "start",
|
|
158
|
-
"name": "worker",
|
|
159
|
-
"command": "pnpm worker",
|
|
160
|
-
"logWatches": [
|
|
161
|
-
{ "pattern": "job completed", "stream": "stdout", "repeat": true }
|
|
162
|
-
]
|
|
163
|
-
}
|
|
164
|
-
```
|
|
132
|
+
Enable background command interception in `/ps:settings`. When enabled, Pi avoids normal shell background patterns and uses the process workflow instead.
|
|
165
133
|
|
|
166
|
-
|
|
134
|
+
## Feature demos
|
|
167
135
|
|
|
168
|
-
|
|
136
|
+
**Watch a file-backed log and recover from an error**
|
|
169
137
|
|
|
170
|
-
|
|
138
|
+
[](https://assets.aliou.me/pi-extensions/demos/processes/v0.10.0/debug-from-log.mp4)
|
|
171
139
|
|
|
172
|
-
Open
|
|
140
|
+
**Open the log overlay and inspect output**
|
|
173
141
|
|
|
174
|
-
|
|
142
|
+
[](https://assets.aliou.me/pi-extensions/demos/processes/v0.10.0/inspect-logs.mp4)
|
|
175
143
|
|
|
176
|
-
|
|
144
|
+
**Stop and clear processes**
|
|
177
145
|
|
|
178
|
-
|
|
146
|
+
[](https://assets.aliou.me/pi-extensions/demos/processes/v0.10.0/stop-and-clear.mp4)
|
|
179
147
|
|
|
180
|
-
|
|
148
|
+
**Send input to a running process**
|
|
149
|
+
|
|
150
|
+
[](https://assets.aliou.me/pi-extensions/demos/processes/v0.10.0/send-input.mp4)
|
|
181
151
|
|
|
182
152
|
## Contributing
|
|
183
153
|
|
|
@@ -185,4 +155,4 @@ For development, testing, docs generation, and extension internals, see [CONTRIB
|
|
|
185
155
|
|
|
186
156
|
## License
|
|
187
157
|
|
|
188
|
-
MIT
|
|
158
|
+
MIT
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
import type { ProcessInfo } from "../src/types";
|
|
4
|
+
import { truncateCmd } from "../src/utils/format";
|
|
5
|
+
import { MAX_TAB_NAME, statusDot } from "./shared/ui";
|
|
6
|
+
|
|
7
|
+
export { MAX_TAB_NAME, statusDot as renderProcessTabDot };
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Render a process tab: ` dot label ` with active highlight.
|
|
11
|
+
*
|
|
12
|
+
* Truncates the name to `MAX_TAB_NAME` without padding, so tabs stay compact
|
|
13
|
+
* (`● api` not `● api `). The active tab is rendered on a selected
|
|
14
|
+
* background; inactive tabs use a dim label.
|
|
15
|
+
*/
|
|
16
|
+
export function renderProcessTab(
|
|
17
|
+
process: ProcessInfo,
|
|
18
|
+
active: boolean,
|
|
19
|
+
theme: Theme,
|
|
20
|
+
): string {
|
|
21
|
+
const dot = statusDot(process, active, theme);
|
|
22
|
+
const label = truncateCmd(process.name, MAX_TAB_NAME);
|
|
23
|
+
return active
|
|
24
|
+
? theme.bg("selectedBg", ` ${dot} ${theme.fg("accent", label)} `)
|
|
25
|
+
: ` ${dot} ${theme.fg("dim", label)} `;
|
|
26
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core-extension request/command helpers for the `/ps` overview panel.
|
|
3
|
+
*
|
|
4
|
+
* The overview panel prefers the existing `pi.events` protocol channels over
|
|
5
|
+
* calling the manager directly so a future split-out of the panel stays cheap.
|
|
6
|
+
* These helpers are the core equivalent of `extensions/processes-logs/client.ts`
|
|
7
|
+
* and `extensions/processes-dock/client.ts`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { EventBus } from "@earendil-works/pi-coding-agent";
|
|
11
|
+
import {
|
|
12
|
+
CHANNELS,
|
|
13
|
+
type CommandClearPayload,
|
|
14
|
+
type CommandKillPayload,
|
|
15
|
+
type CommandPinPayload,
|
|
16
|
+
type CommandPinResult,
|
|
17
|
+
type ProcessProtocolConfig,
|
|
18
|
+
type RequestCombinedOutputPayload,
|
|
19
|
+
type RequestConfigPayload,
|
|
20
|
+
type RequestGetPayload,
|
|
21
|
+
type RequestListPayload,
|
|
22
|
+
} from "../../src/protocol";
|
|
23
|
+
import type { KillResult, ProcessInfo } from "../../src/types";
|
|
24
|
+
|
|
25
|
+
export type ProcessLogLine = { type: "stdout" | "stderr"; text: string };
|
|
26
|
+
|
|
27
|
+
export function requestProcessList(events: EventBus): ProcessInfo[] {
|
|
28
|
+
let processes: ProcessInfo[] = [];
|
|
29
|
+
const payload: RequestListPayload = {
|
|
30
|
+
reply: (result) => {
|
|
31
|
+
processes = result;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
events.emit(CHANNELS.REQUEST_LIST, payload);
|
|
35
|
+
return processes;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function requestProcess(
|
|
39
|
+
events: EventBus,
|
|
40
|
+
id: string,
|
|
41
|
+
): ProcessInfo | null {
|
|
42
|
+
let process: ProcessInfo | null = null;
|
|
43
|
+
const payload: RequestGetPayload = {
|
|
44
|
+
id,
|
|
45
|
+
reply: (result) => {
|
|
46
|
+
process = result;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
events.emit(CHANNELS.REQUEST_GET, payload);
|
|
50
|
+
return process;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function requestConfig(events: EventBus): ProcessProtocolConfig {
|
|
54
|
+
let config: ProcessProtocolConfig | null = null;
|
|
55
|
+
const payload: RequestConfigPayload = {
|
|
56
|
+
reply: (result) => {
|
|
57
|
+
config = result;
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
events.emit(CHANNELS.REQUEST_CONFIG, payload);
|
|
61
|
+
if (!config) {
|
|
62
|
+
throw new Error("processes core extension did not reply to config request");
|
|
63
|
+
}
|
|
64
|
+
return config;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function requestCombinedOutput(
|
|
68
|
+
events: EventBus,
|
|
69
|
+
id: string,
|
|
70
|
+
tailLines?: number,
|
|
71
|
+
): ProcessLogLine[] {
|
|
72
|
+
let lines: ProcessLogLine[] | null = null;
|
|
73
|
+
const payload: RequestCombinedOutputPayload = {
|
|
74
|
+
id,
|
|
75
|
+
tailLines,
|
|
76
|
+
reply: (result) => {
|
|
77
|
+
lines = result;
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
events.emit(CHANNELS.REQUEST_COMBINED_OUTPUT, payload);
|
|
81
|
+
return lines ?? [];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Kill a managed process. Resolves when the kill handler replies, or with a
|
|
86
|
+
* timeout error result if no listener responds.
|
|
87
|
+
*
|
|
88
|
+
* The kill handler runs `killIntentionally` asynchronously, so its reply fires
|
|
89
|
+
* on a later microtask rather than during the emit. That is why this returns a
|
|
90
|
+
* Promise (unlike the synchronous `requestClear`/`requestProcessList`): a
|
|
91
|
+
* synchronous read of `result` would always miss the reply and report failure.
|
|
92
|
+
*
|
|
93
|
+
* The safety timeout defaults to the kill timeout plus headroom so a successful
|
|
94
|
+
* slow kill still resolves first. The timer is unref'd so it never keeps the
|
|
95
|
+
* event loop alive.
|
|
96
|
+
*/
|
|
97
|
+
export function requestKill(
|
|
98
|
+
events: EventBus,
|
|
99
|
+
id: string,
|
|
100
|
+
options?: { signal?: NodeJS.Signals; timeoutMs?: number },
|
|
101
|
+
): Promise<KillResult> {
|
|
102
|
+
return new Promise((resolve) => {
|
|
103
|
+
let settled = false;
|
|
104
|
+
const killTimeoutMs = options?.timeoutMs ?? 3000;
|
|
105
|
+
const payload: CommandKillPayload = {
|
|
106
|
+
id,
|
|
107
|
+
signal: options?.signal,
|
|
108
|
+
timeoutMs: killTimeoutMs,
|
|
109
|
+
reply: (result) => {
|
|
110
|
+
if (settled) return;
|
|
111
|
+
settled = true;
|
|
112
|
+
clearTimeout(timer);
|
|
113
|
+
resolve(result);
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
const timer = setTimeout(() => {
|
|
117
|
+
if (settled) return;
|
|
118
|
+
settled = true;
|
|
119
|
+
resolve(killTimeoutResult(id));
|
|
120
|
+
}, killTimeoutMs + 2000);
|
|
121
|
+
// Unref so a parked timer never keeps the event loop alive.
|
|
122
|
+
timer.unref?.();
|
|
123
|
+
events.emit(CHANNELS.COMMAND_KILL, payload);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function killTimeoutResult(id: string): KillResult {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
reason: "error",
|
|
131
|
+
info: {
|
|
132
|
+
id,
|
|
133
|
+
name: "(unknown)",
|
|
134
|
+
pid: -1,
|
|
135
|
+
command: "",
|
|
136
|
+
cwd: "",
|
|
137
|
+
startTime: 0,
|
|
138
|
+
endTime: null,
|
|
139
|
+
status: "exited",
|
|
140
|
+
exitCode: null,
|
|
141
|
+
success: false,
|
|
142
|
+
stdoutFile: "",
|
|
143
|
+
stderrFile: "",
|
|
144
|
+
endReason: null,
|
|
145
|
+
signal: null,
|
|
146
|
+
errorMessage: "No kill handler replied",
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function requestClear(events: EventBus): number {
|
|
152
|
+
let cleared = 0;
|
|
153
|
+
const payload: CommandClearPayload = {
|
|
154
|
+
reply: (value) => {
|
|
155
|
+
cleared = value;
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
events.emit(CHANNELS.COMMAND_CLEAR, payload);
|
|
159
|
+
return cleared;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Pin a process to the dock. Resolves when the dock extension replies, or
|
|
164
|
+
* rejects if no dock handler responds within `timeoutMs`.
|
|
165
|
+
*
|
|
166
|
+
* The dock extension must be loaded for this to succeed. If it is not
|
|
167
|
+
* registered, no listener will reply and the promise rejects with a timeout.
|
|
168
|
+
*/
|
|
169
|
+
export function requestPin(
|
|
170
|
+
events: EventBus,
|
|
171
|
+
id: string | null,
|
|
172
|
+
timeoutMs = 200,
|
|
173
|
+
): Promise<CommandPinResult> {
|
|
174
|
+
return new Promise((resolve) => {
|
|
175
|
+
let settled = false;
|
|
176
|
+
const payload: CommandPinPayload = {
|
|
177
|
+
id,
|
|
178
|
+
reply: (result) => {
|
|
179
|
+
if (settled) return;
|
|
180
|
+
settled = true;
|
|
181
|
+
clearTimeout(timer);
|
|
182
|
+
resolve(result);
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
const timer = setTimeout(() => {
|
|
186
|
+
if (settled) return;
|
|
187
|
+
settled = true;
|
|
188
|
+
resolve({ ok: false, error: "Dock extension is not available" });
|
|
189
|
+
}, timeoutMs);
|
|
190
|
+
// The timeout needs to be unref'd so it never keeps the event loop alive.
|
|
191
|
+
timer.unref?.();
|
|
192
|
+
events.emit(CHANNELS.COMMAND_PIN, payload);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtensionAPI,
|
|
3
|
+
ExtensionCommandContext,
|
|
4
|
+
} from "@earendil-works/pi-coding-agent";
|
|
5
|
+
import { requestClear } from "../client";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Register `/ps:clear`.
|
|
9
|
+
*
|
|
10
|
+
* Removes finished processes from the list via the clear protocol channel,
|
|
11
|
+
* mirroring main's behavior. Returns the count of cleared processes.
|
|
12
|
+
*/
|
|
13
|
+
export function registerClearCommand(pi: ExtensionAPI): void {
|
|
14
|
+
const events = pi.events;
|
|
15
|
+
pi.registerCommand("ps:clear", {
|
|
16
|
+
description: "Remove finished processes from the list.",
|
|
17
|
+
handler: async (_args: string, ctx: ExtensionCommandContext) => {
|
|
18
|
+
const cleared = requestClear(events);
|
|
19
|
+
if (cleared === 0) {
|
|
20
|
+
ctx.ui.notify("No finished processes to clear.", "info");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
ctx.ui.notify(
|
|
24
|
+
`Cleared ${cleared} finished process${cleared === 1 ? "" : "es"}.`,
|
|
25
|
+
"info",
|
|
26
|
+
);
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|