@aliou/pi-processes 0.6.3 → 0.7.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.
@@ -0,0 +1,123 @@
1
+ # Contributing
2
+
3
+ ## Scope
4
+
5
+ `README.md` is for users.
6
+
7
+ Keep development details, testing notes, internal tool guidance, and docs build details in this file.
8
+
9
+ ## Development
10
+
11
+ Install dependencies:
12
+
13
+ ```bash
14
+ pnpm install
15
+ ```
16
+
17
+ Run checks:
18
+
19
+ ```bash
20
+ pnpm lint
21
+ pnpm typecheck
22
+ ```
23
+
24
+ ## Repository layout
25
+
26
+ - `src/` - extension source
27
+ - `src/tools/` - `process` tool and actions
28
+ - `src/commands/` - `/ps` commands and settings UI
29
+ - `src/hooks/` - lifecycle hooks, blocker, message rendering, widgets
30
+ - `src/components/` - TUI components
31
+ - `skills/` - shipped package skills
32
+ - `.agents/skills/` - local repo-only skills for development workflows
33
+ - `.github/docs-site/` - isolated docs page build
34
+
35
+ ## Internal behavior
36
+
37
+ This extension is mainly for agent-managed background processes.
38
+
39
+ Typical flow:
40
+
41
+ 1. Pi starts a long-running command in the background.
42
+ 2. Pi continues other work.
43
+ 3. The user watches, pins, or kills the process from the UI.
44
+ 4. Pi inspects output or logs when needed.
45
+
46
+ Use the `process` tool for long-running commands such as dev servers, test watchers, build watchers, and log tails.
47
+
48
+ Avoid shell background patterns when the process tool fits.
49
+
50
+ Background command blocking is optional. It is controlled by `interception.blockBackgroundCommands`.
51
+
52
+ ## Testing
53
+
54
+ Useful local checks:
55
+
56
+ ```bash
57
+ pnpm lint
58
+ pnpm typecheck
59
+ ```
60
+
61
+ Useful manual process scripts:
62
+
63
+ ```bash
64
+ ./test/test-output.sh
65
+ ./test/test-exit-success.sh 5
66
+ ./test/test-exit-failure.sh 5
67
+ ./test/test-exit-crash.sh 5
68
+ ```
69
+
70
+ ## Docs conventions
71
+
72
+ ### README
73
+
74
+ Keep `README.md` focused on user outcomes:
75
+
76
+ - what the extension does
77
+ - how users interact with it
78
+ - slash commands and UI behavior
79
+ - troubleshooting
80
+
81
+ Avoid putting these in `README.md`:
82
+
83
+ - dev commands
84
+ - test commands
85
+ - internal architecture details
86
+ - detailed tool-call schemas
87
+ - release workflow notes
88
+
89
+ ### Video placeholders
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`.
108
+
109
+ ## Demo pattern
110
+
111
+ For demo recording, use a small self-contained project with a realistic workflow.
112
+
113
+ The best pattern used for this extension was a fake Northwind API project where Pi:
114
+
115
+ 1. starts a server in the background
116
+ 2. runs tests and sees failures
117
+ 3. runs migrations
118
+ 4. checks server logs
119
+ 5. updates seed data
120
+ 6. reruns tests
121
+ 7. cleans up the process
122
+
123
+ That pattern shows why background processes matter in a normal task instead of showing features one by one.
package/README.md CHANGED
@@ -1,155 +1,186 @@
1
- # Processes Extension
1
+ # pi-processes
2
2
 
3
- Manage background processes from Pi. Start long-running commands (dev servers, build watchers, log tailers) without blocking the conversation.
3
+ Manage background processes from Pi without blocking the conversation.
4
4
 
5
- ## Demo
5
+ This extension lets Pi keep long-running commands alive while the conversation continues. It is useful for dev servers, test watchers, local APIs, builds, and log tails.
6
6
 
7
- <video src="https://assets.aliou.me/pi-extensions/2026-01-26-processes-demo.mp4" controls playsinline muted></video>
7
+ ## Let Pi keep working while processes run
8
+
9
+ 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.
10
+
11
+ That means Pi can, for example:
12
+
13
+ - start a dev server and keep coding
14
+ - keep a test watcher running while it fixes failures
15
+ - run a local API while it inspects logs
16
+ - watch build output without blocking the conversation
17
+
18
+ You can then inspect, pin, or stop those processes from the UI.
19
+
20
+ <!-- VIDEO: {"id":"agent-starts-processes","title":"Pi starts a long-running process and keeps working"} -->
8
21
 
9
22
  ## Installation
10
23
 
24
+ From npm:
25
+
11
26
  ```bash
12
27
  pi install npm:@aliou/pi-processes
13
28
  ```
14
29
 
15
- Or from git:
30
+ From git:
16
31
 
17
32
  ```bash
18
33
  pi install git:github.com/aliou/pi-processes
19
34
  ```
20
35
 
21
- ## Features
36
+ ## Open the process panel
22
37
 
23
- - **Tool**: `process` with actions: `start`, `list`, `output`, `logs`, `kill`, `clear`
24
- - **Commands**: `/ps` (interactive panel), `/ps:pin` (pin dock to process), `/ps:logs` (open log overlay), `/ps:kill` (kill process), `/ps:clear` (clear finished), `/ps:dock` (control dock visibility), `/ps:settings`
25
- - **Log Dock**: Unified view for all process logs with color-coded prefixes
26
- - **Follow Mode**: Automatically shows dock when processes start (enabled by default)
27
- - **Focus Mode**: Filter to a single process's logs
28
- - Auto-cleanup on session exit
29
- - File-based logging (logs written to temp files, not memory)
30
- - Friendly process names (auto-inferred or custom)
38
+ Use `/ps` to open the main process panel.
31
39
 
32
- ## Usage
40
+ From there you can:
33
41
 
34
- ### Tool (for agent)
42
+ - see running and finished processes
43
+ - inspect recent output
44
+ - pin a process to the dock
45
+ - kill a running process
46
+ - clear finished entries
35
47
 
36
- ```
37
- process start "pnpm dev" name="backend-dev"
38
- process start "pnpm build" name="build" alertOnSuccess=true
39
- process start "pnpm test" alertOnFailure=true
40
- process list
41
- process output id="backend"
42
- process logs id="proc_1"
43
- process kill id="backend"
44
- process clear
45
- ```
48
+ Keys:
49
+
50
+ - `j/k` or arrow keys: move selection
51
+ - `J/K`: scroll preview
52
+ - `enter`: pin selected process to the dock
53
+ - `x`: kill selected process
54
+ - `c`: clear finished processes
55
+ - `q` or `esc`: close
56
+
57
+ <!-- VIDEO: {"id":"process-panel","title":"Browse and manage processes from the panel"} -->
58
+
59
+ ## Inspect logs
46
60
 
47
- **Alert parameters** (for `start` action):
48
- - `alertOnSuccess` (default: false) - Get a turn to react when process completes successfully. Use for builds/tests where you need confirmation.
49
- - `alertOnFailure` (default: true) - Get a turn to react when process fails/crashes. Use to be alerted of unexpected failures.
50
- - `alertOnKill` (default: false) - Get a turn to react if killed by external signal. Note: killing via tool never triggers a turn.
61
+ Use `/ps:logs [id|name]` to open the log overlay for one process.
51
62
 
52
- **Important:** You don't need to poll or wait for processes. Notifications arrive automatically based on your preferences. Start processes and continue with other work - you'll be informed if something requires attention.
63
+ This is useful when Pi started a server, watcher, or local API and you want to follow what it is doing in more detail.
53
64
 
54
- Note: User always sees process updates in the UI. The alert flags control whether the agent gets a turn to react (e.g. check results, fix code, restart).
65
+ Keys:
55
66
 
56
- ### Commands (interactive)
67
+ - `tab` / `shift+tab`: switch process tabs
68
+ - `g/G`: jump to top or bottom
69
+ - `j/k` or arrow keys: scroll
70
+ - `s`: switch between combined, stdout, and stderr
71
+ - `f`: toggle follow mode
72
+ - `/`: search
73
+ - `n/N`: move between search matches
74
+ - `q` or `esc`: close
57
75
 
58
- #### `/ps` - Open full panel
76
+ <!-- VIDEO: {"id":"inspect-logs","title":"Open the log overlay and inspect output"} -->
59
77
 
60
- View and manage all processes in an interactive panel:
61
- - `j/k` - select process
62
- - `J/K` - scroll logs
63
- - `enter` - focus on selected process
64
- - `x` - kill selected process
65
- - `c` - clear finished processes
66
- - `q` - quit
78
+ ## Pin one process
67
79
 
68
- #### `/ps:pin [id|name]` - Pin dock to a process
80
+ Use `/ps:pin [id|name]` to keep the dock focused on one process.
69
81
 
70
- Pin the dock to a specific process. Opens the dock automatically if hidden.
82
+ This is useful when one process matters more than the others, such as a dev server or a test watcher.
71
83
 
72
- Without arguments, shows a picker to select a process.
84
+ Without arguments, Pi shows a picker.
73
85
 
74
- #### `/ps:logs [id|name]` - Open log overlay
86
+ <!-- VIDEO: {"id":"pin-process","title":"Pin the dock to one process"} -->
75
87
 
76
- Open the interactive log viewer overlay (search, scroll, stream filter).
88
+ ## Control the dock
77
89
 
78
- #### `/ps:kill [id|name]` - Kill a process
90
+ Use `/ps:dock [show|hide|toggle]` to control dock visibility.
79
91
 
80
- Kill a running process. Without arguments, shows a picker.
92
+ The dock gives you a compact live view without leaving the conversation.
81
93
 
82
- #### `/ps:clear` - Clear finished
94
+ <!-- VIDEO: {"id":"dock-control","title":"Show, hide, and use the dock"} -->
83
95
 
84
- Remove all finished processes from the list.
96
+ ## Adjust settings
85
97
 
86
- #### `/ps:dock [show|hide|toggle]` - Control dock
98
+ Use `/ps:settings` to configure the extension.
87
99
 
88
- Control dock visibility. Without arguments, it toggles state. With arguments:
89
- - `show` - Show dock (open)
90
- - `hide` - Hide dock
91
- - `toggle` - Cycle dock visibility state
100
+ Available settings include:
92
101
 
93
- ### Log Dock
102
+ - process list size
103
+ - output limits
104
+ - shell path override
105
+ - dock defaults
106
+ - follow mode behavior
107
+ - optional background command interception
94
108
 
95
- The log dock shows interleaved logs from all processes with color-coded prefixes:
109
+ <!-- VIDEO: {"id":"settings","title":"Adjust process extension settings"} -->
96
110
 
111
+ ## Platform support
112
+
113
+ - macOS: supported
114
+ - Linux: supported
115
+ - Windows: not supported
116
+
117
+ ## Runtime log watch alerts
118
+
119
+ Use `process` tool `start` with `logWatches` to trigger immediate alerts while the process is still running.
120
+
121
+ - default behavior: each watch fires once (`repeat: false`)
122
+ - set `repeat: true` to trigger on every match
123
+ - scope by stream (`stdout`, `stderr`, `both`) to reduce noise
124
+
125
+ Example: server ready marker (one-time default)
126
+
127
+ ```json
128
+ {
129
+ "action": "start",
130
+ "name": "dev-server",
131
+ "command": "pnpm dev",
132
+ "logWatches": [
133
+ { "pattern": "ready on http://localhost:3000" }
134
+ ]
135
+ }
97
136
  ```
98
- [dev] GET /api/users 200 45ms (cyan)
99
- [test] Running auth.test.ts... (yellow)
100
- [dev] POST /api/auth 200 12ms
101
- [test] ✓ login flow
102
- ...
137
+
138
+ Example: error marker from stderr
139
+
140
+ ```json
141
+ {
142
+ "action": "start",
143
+ "name": "builder",
144
+ "command": "pnpm build --watch",
145
+ "logWatches": [
146
+ { "pattern": "TypeError|ReferenceError", "stream": "stderr" }
147
+ ]
148
+ }
103
149
  ```
104
150
 
105
- **Dock Keyboard Shortcuts** (when dock is open):
106
- - `h` - focus previous process
107
- - `l` - focus next process
108
- - `f` - toggle focus mode (filter to single process)
109
- - `x` - kill focused process
110
- - `q` - close/unfocus dock
111
- - Follow mode toggle is only available via settings (`/ps:settings`)
151
+ Example: repeatable watch on stdout only
152
+
153
+ ```json
154
+ {
155
+ "action": "start",
156
+ "name": "worker",
157
+ "command": "pnpm worker",
158
+ "logWatches": [
159
+ { "pattern": "job completed", "stream": "stdout", "repeat": true }
160
+ ]
161
+ }
162
+ ```
112
163
 
113
- **Dock States:**
114
- - `collapsed` (1-2 lines): Summary + last log line
115
- - `open` (8-12 lines): Full interleaved or focused logs
164
+ Invalid regex patterns fail fast at process start with a clear error.
116
165
 
117
- ### Deprecated Commands (backward compatible)
166
+ ## Troubleshooting
118
167
 
119
- The following commands are deprecated but still work with a warning:
120
- - `/process:list` → Use `/ps` instead
121
- - `/process:stream` → Use `/ps:pin` instead
122
- - `/process:logs` → Use `/ps:logs` instead
123
- - `/process:kill` → Use `/ps:kill` instead
124
- - `/process:clear` → Use `/ps:clear` instead
168
+ ### Pi started something and I want to see more output
125
169
 
126
- ## Settings
170
+ Open `/ps` for a quick overview, or use `/ps:logs` for full logs.
127
171
 
128
- Configure via `/ps:settings` or `~/.pi/agent/extensions/processes.json`:
172
+ ### I want one process to stay visible
129
173
 
130
- - **Widget**: Dock default state, dock height
131
- - **Follow Mode**: Enable by default, auto-hide on finish
132
- - **Process List**: Max visible processes, max preview lines
133
- - **Output Limits**: Default tail lines, max output lines
134
- - **Execution**: Shell path override
135
- - **Interception**: Block background commands
174
+ Use `/ps:pin` to focus the dock on that process.
136
175
 
137
- ## Test Scripts
176
+ ### I want Pi to avoid shell background tricks
138
177
 
139
- Test scripts in `src/test/` directory:
178
+ Enable background command interception in `/ps:settings`. When enabled, Pi avoids normal shell background patterns and uses the process workflow instead.
140
179
 
141
- ```bash
142
- ./src/test/test-output.sh # Continuous output (80 chars/sec)
143
- ./src/test/test-exit-success.sh 5 # Exits successfully after 5s
144
- ./src/test/test-exit-failure.sh 5 # Exits with code 1 after 5s
145
- ./src/test/test-exit-crash.sh 5 # Exits with code 137 after 5s
146
- ```
180
+ ## Contributing
181
+
182
+ For development, testing, docs generation, and extension internals, see [CONTRIBUTING.md](./CONTRIBUTING.md).
147
183
 
148
- ## Future Improvements
184
+ ## License
149
185
 
150
- - [ ] **Configurable keybindings UI**: Allow editing keybindings in settings panel
151
- - [ ] **Process filtering**: Filter by name/status in full panel
152
- - [ ] **Log search**: Search within logs (Ctrl+F in dock)
153
- - [ ] **Copy log path**: Keyboard shortcut to copy log file path
154
- - [ ] **Open in editor**: Keyboard shortcut to open logs in $EDITOR
155
- - [ ] **Sound notifications**: Play sound on process completion
186
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aliou/pi-processes",
3
- "version": "0.6.3",
3
+ "version": "0.7.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "private": false,
@@ -18,6 +18,9 @@
18
18
  "extensions": [
19
19
  "./src/index.ts"
20
20
  ],
21
+ "skills": [
22
+ "./skills/pi-processes"
23
+ ],
21
24
  "video": "https://assets.aliou.me/pi-extensions/demos/pi-processes.mp4"
22
25
  },
23
26
  "publishConfig": {
@@ -25,7 +28,9 @@
25
28
  },
26
29
  "files": [
27
30
  "src",
28
- "README.md"
31
+ "skills",
32
+ "README.md",
33
+ "CONTRIBUTING.md"
29
34
  ],
30
35
  "dependencies": {
31
36
  "@aliou/pi-utils-settings": "^0.10.0",
@@ -64,6 +69,7 @@
64
69
  "check:lockfile": "pnpm install --frozen-lockfile --ignore-scripts",
65
70
  "changeset": "changeset",
66
71
  "version": "changeset version",
72
+ "test": "vitest run",
67
73
  "release": "pnpm changeset publish"
68
74
  }
69
75
  }
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: pi-processes
3
+ description: Manage long-running commands in the background with the process tool. Use when a task needs a dev server, test watcher, build watcher, local API, or log tail to keep running while the conversation continues.
4
+ ---
5
+
6
+ # pi-processes
7
+
8
+ Use this skill when work needs a long-running command to stay alive while Pi continues with other steps.
9
+
10
+ ## Prefer this workflow
11
+
12
+ - Use the `process` tool for long-running commands.
13
+ - Avoid shell background patterns when the process tool fits.
14
+ - Give processes stable, clear names.
15
+ - Continue the task after starting a process instead of waiting on it.
16
+ - Inspect output or log files only when needed.
17
+ - Kill and clear processes when they are no longer useful.
18
+
19
+ ## Good fits
20
+
21
+ - `pnpm dev`
22
+ - `npm run server`
23
+ - `pnpm test --watch`
24
+ - `tail -f <logfile>`
25
+ - local preview or build watchers
26
+
27
+ ## Typical flow
28
+
29
+ 1. Start the long-running command with a clear name.
30
+ 2. Continue the main task.
31
+ 3. Inspect `output` or `logs` if something needs attention.
32
+ 4. Use alert flags when success or failure should trigger a follow-up turn.
33
+ 5. Kill and clear the process when done.
34
+
35
+ ## Notes
36
+
37
+ - Users can inspect and manage running processes from `/ps`.
38
+ - Use `write` when a process expects stdin input.
39
+ - Use `output` for a quick tail and `logs` when the full log files are more useful.
@@ -19,7 +19,7 @@ export function registerPsKillCommand(
19
19
  let processId: string | undefined;
20
20
 
21
21
  if (arg) {
22
- const proc = manager.find(arg);
22
+ const proc = manager.get(arg);
23
23
  if (!proc) {
24
24
  return;
25
25
  }
@@ -49,18 +49,18 @@ export function registerPsKillCommand(
49
49
  }
50
50
  }
51
51
 
52
+ if (!processId) return;
53
+
52
54
  const proc = manager.get(processId);
53
- if (!proc) {
54
- return;
55
- }
55
+ if (!proc) return;
56
56
 
57
57
  const signal =
58
58
  proc.status === "terminate_timeout" ? "SIGKILL" : "SIGTERM";
59
59
  const timeoutMs = signal === "SIGKILL" ? 200 : 3000;
60
- const result = await manager.kill(processId, { signal, timeoutMs });
60
+ const result = await manager.kill(proc.id, { signal, timeoutMs });
61
61
 
62
62
  if (result.ok) {
63
- if (dockActions.getFocusedProcessId() === processId) {
63
+ if (dockActions.getFocusedProcessId() === proc.id) {
64
64
  dockActions.setFocus(null);
65
65
  }
66
66
  }
@@ -18,7 +18,7 @@ export function registerPsLogsCommand(
18
18
  let processId: string | undefined;
19
19
 
20
20
  if (arg) {
21
- const proc = manager.find(arg);
21
+ const proc = manager.get(arg);
22
22
  if (!proc) return;
23
23
  processId = proc.id;
24
24
  }
@@ -17,7 +17,7 @@ export function registerPsPinCommand(
17
17
  let processId: string | undefined;
18
18
 
19
19
  if (arg) {
20
- const proc = manager.find(arg);
20
+ const proc = manager.get(arg);
21
21
  if (!proc) {
22
22
  return;
23
23
  }
@@ -27,6 +27,7 @@ export function registerPsPinCommand(
27
27
  if (!processId) return;
28
28
  }
29
29
 
30
+ if (!processId) return;
30
31
  dockActions.setFocus(processId);
31
32
  },
32
33
  });
@@ -13,7 +13,7 @@ export function buildSettingsSections(
13
13
  id: "processList.maxVisibleProcesses",
14
14
  label: "Max visible processes",
15
15
  description:
16
- "Maximum processes shown in the /processes list before scrolling",
16
+ "Maximum processes shown in the /ps list before scrolling",
17
17
  currentValue: String(
18
18
  tabConfig?.processList?.maxVisibleProcesses ??
19
19
  resolved.processList.maxVisibleProcesses,
@@ -17,8 +17,6 @@ import { LIVE_STATUSES } from "../constants";
17
17
  import type { ProcessManager } from "../manager";
18
18
  import { LogFileViewer } from "./log-file-viewer";
19
19
 
20
- const POLL_INTERVAL_MS = 500;
21
-
22
20
  const PROCESS_COLORS: ThemeColor[] = [
23
21
  "accent",
24
22
  "warning",
@@ -47,7 +45,6 @@ export class LogDockComponent implements Component {
47
45
  private mode: "collapsed" | "open";
48
46
  private focusedProcessId: string | null;
49
47
 
50
- private timer: ReturnType<typeof setInterval> | null = null;
51
48
  private unsubscribeManager: (() => void) | null = null;
52
49
 
53
50
  /** One viewer per process, lazily created, follow:true. */
@@ -64,10 +61,6 @@ export class LogDockComponent implements Component {
64
61
  this.mode = options.mode;
65
62
  this.focusedProcessId = options.focusedProcessId;
66
63
 
67
- this.timer = setInterval(() => {
68
- this.tui.requestRender();
69
- }, POLL_INTERVAL_MS);
70
-
71
64
  this.unsubscribeManager = this.manager.onEvent(() => {
72
65
  this.tui.requestRender();
73
66
  });
@@ -227,10 +220,6 @@ export class LogDockComponent implements Component {
227
220
  }
228
221
 
229
222
  dispose(): void {
230
- if (this.timer) {
231
- clearInterval(this.timer);
232
- this.timer = null;
233
- }
234
223
  this.unsubscribeManager?.();
235
224
  this.viewers.clear();
236
225
  this.processColors.clear();
@@ -61,7 +61,6 @@ export class LogOverlayComponent implements Component {
61
61
  private mode: OverlayMode = "normal";
62
62
  private searchInput: Input = new Input();
63
63
 
64
- private timer: ReturnType<typeof setInterval> | null = null;
65
64
  private unsubscribeManager: (() => void) | null = null;
66
65
 
67
66
  constructor(opts: LogOverlayOptions) {
@@ -91,10 +90,6 @@ export class LogOverlayComponent implements Component {
91
90
  this.tui.requestRender();
92
91
  });
93
92
 
94
- this.timer = setInterval(() => {
95
- this.tui.requestRender();
96
- }, 300);
97
-
98
93
  this.searchInput.onSubmit = (query) => {
99
94
  const trimmed = query.trim();
100
95
  if (trimmed) {
@@ -163,10 +158,6 @@ export class LogOverlayComponent implements Component {
163
158
  // ---------------------------------------------------------------------------
164
159
 
165
160
  private close(): void {
166
- if (this.timer) {
167
- clearInterval(this.timer);
168
- this.timer = null;
169
- }
170
161
  this.unsubscribeManager?.();
171
162
  this.unsubscribeManager = null;
172
163
  this.done();