@trevonistrevon/pi-loop 0.1.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/AGENTS.md +79 -0
- package/CHANGELOG.md +39 -0
- package/CONTRIBUTING.md +69 -0
- package/LICENSE +21 -0
- package/README.md +82 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +614 -0
- package/dist/loop-parse.d.ts +6 -0
- package/dist/loop-parse.js +150 -0
- package/dist/monitor-manager.d.ts +13 -0
- package/dist/monitor-manager.js +137 -0
- package/dist/scheduler.d.ts +15 -0
- package/dist/scheduler.js +89 -0
- package/dist/store.d.ts +30 -0
- package/dist/store.js +195 -0
- package/dist/trigger-system.d.ts +19 -0
- package/dist/trigger-system.js +130 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.js +1 -0
- package/dist/ui/widget.d.ts +28 -0
- package/dist/ui/widget.js +114 -0
- package/package.json +47 -0
- package/src/index.ts +671 -0
- package/src/loop-parse.ts +163 -0
- package/src/monitor-manager.ts +148 -0
- package/src/scheduler.ts +104 -0
- package/src/store.ts +189 -0
- package/src/trigger-system.ts +132 -0
- package/src/types.ts +59 -0
- package/src/ui/widget.ts +132 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# pi-loop Development Guidelines
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
`pi-loop` is a pi extension providing cron/event-based agent re-wake loops and background process monitoring. Modeled after Claude Code's `/loop`, `CronCreate`, and `MonitorCreate` tools.
|
|
5
|
+
|
|
6
|
+
## Stack
|
|
7
|
+
- TypeScript 6.x (strict, ES2022 target, bundler module resolution)
|
|
8
|
+
- `typebox` for tool parameter validation
|
|
9
|
+
- `vitest` for tests
|
|
10
|
+
- `biome` for linting (linter: on, formatter: off)
|
|
11
|
+
- npm packaging as `@trevonistrevon/pi-loop`
|
|
12
|
+
|
|
13
|
+
## Architecture
|
|
14
|
+
```
|
|
15
|
+
src/
|
|
16
|
+
├── index.ts # Extension entry: 6 tools + /loop /loops commands + widget
|
|
17
|
+
├── types.ts # LoopKind, Trigger spec, LoopEntry, MonitorEntry, LoopConfig
|
|
18
|
+
├── store.ts # File-backed CRUD (.pi/loops/loops.json) with file locking
|
|
19
|
+
├── scheduler.ts # Timer-based cron scheduler with jitter + 7-day expiry
|
|
20
|
+
├── trigger-system.ts # Unified trigger engine: cron timers + pi event subscriptions + hybrid
|
|
21
|
+
├── monitor-manager.ts # ChildProcess tracking, output buffering, event emission, stop
|
|
22
|
+
├── loop-parse.ts # Human interval → cron expression, next-fire computation, jitter
|
|
23
|
+
└── ui/
|
|
24
|
+
└── widget.ts # Persistent widget: active loops + monitors
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Conventions (mirror pi-tasks)
|
|
28
|
+
- No comments unless answering "why", never "what"
|
|
29
|
+
- `debug(...)` helper gated on `PI_LOOP_DEBUG` env var, logs to stderr
|
|
30
|
+
- `textResult(msg)` helper for uniform tool output
|
|
31
|
+
- All tool params use `Type.Object()` with description strings
|
|
32
|
+
- Tool descriptions follow Claude Code format: `## When to Use`, `## When NOT to Use`
|
|
33
|
+
- Cross-extension communication via `pi.events` with `requestId` + reply channels
|
|
34
|
+
- File-backed stores use atomic write (write tmp → rename) + pid-based file locking
|
|
35
|
+
- Widget uses `UICtx.setWidget()` with `render()` callback pattern
|
|
36
|
+
- Tests co-located in `test/`, named `<module>.test.ts`
|
|
37
|
+
|
|
38
|
+
## File Locking Pattern
|
|
39
|
+
Copy TaskStore from pi-tasks: `O_EXCL` lockfile, stale PID detection, `LOCK_RETRY_MS`/`LOCK_MAX_RETRIES`
|
|
40
|
+
|
|
41
|
+
## Trigger Types
|
|
42
|
+
Three trigger types, all stored as `LoopEntry.trigger`:
|
|
43
|
+
- `{ type: "cron", schedule: "*/5 * * * *" }` — timer-based
|
|
44
|
+
- `{ type: "event", source: "tool_execution_start", filter?: "regex:..." | '{"key":"value"}' }` — eventbus-based
|
|
45
|
+
- `{ type: "hybrid", cron: "...", event: { source, filter? }, debounceMs: 30000 }` — both with debounce
|
|
46
|
+
|
|
47
|
+
## Re-wake via System Reminder
|
|
48
|
+
When a loop fires, the scheduler calls `onLoopFire()` which emits `pi.events("loop:fire", ...)`. The extension's listener queues a reminder. On the next `tool_result` event, the reminder is injected as `<system-reminder>` text (mirroring pi-tasks' pattern):
|
|
49
|
+
```
|
|
50
|
+
<system-reminder>
|
|
51
|
+
Scheduled loop "deploy check" fired. Trigger: schedule: */5 * * * *.
|
|
52
|
+
[loop:abc12345]
|
|
53
|
+
</system-reminder>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Monitor Streaming via PI Events
|
|
57
|
+
Monitor stdout/stderr lines are emitted as `pi.events("monitor:output", { monitorId, line, timestamp })`. Tool consumers subscribe to these events. Completion emits `"monitor:done"` / `"monitor:error"`.
|
|
58
|
+
|
|
59
|
+
## pi-tasks Integration
|
|
60
|
+
When `@tintinweb/pi-tasks` is present, `LoopCreate` with `autoTask: true` fires an RPC to create a task. Communication via `pi.events`:
|
|
61
|
+
- `tasks:rpc:ping` on init → detect pi-tasks presence
|
|
62
|
+
- `tasks:ready` listener → late-binding detection
|
|
63
|
+
- `tasks:rpc:create` → auto-create task when loop fires (if `autoTask: true`)
|
|
64
|
+
|
|
65
|
+
## /loop Self-Paced Mode
|
|
66
|
+
When no interval is specified in `/loop prompt`, the loop runs in self-paced mode. The agent receives the prompt, acts on it, and uses `LoopCreate`/`LoopUpdate` to schedule the next iteration. The loop fires once, then the agent decides the next interval dynamically (matching Claude Code's dynamic interval behavior).
|
|
67
|
+
|
|
68
|
+
## Testing
|
|
69
|
+
- `vitest` with `describe`/`it` blocks
|
|
70
|
+
- In-memory stores for unit tests, `tmpdir` for file-backed tests
|
|
71
|
+
- Fake timers (`vi.useFakeTimers`) for scheduler tests
|
|
72
|
+
- Mock pi eventbus for monitor-manager tests
|
|
73
|
+
- `vitest run` in CI, `vitest` for watch mode
|
|
74
|
+
|
|
75
|
+
## Limits
|
|
76
|
+
- Maximum 25 active loops
|
|
77
|
+
- Maximum 25 running monitors
|
|
78
|
+
- 7-day expiry on recurring loops
|
|
79
|
+
- 5-minute default cron interval for self-paced mode
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0] — Initial Release
|
|
4
|
+
|
|
5
|
+
### Tools
|
|
6
|
+
|
|
7
|
+
- **LoopCreate** — Create scheduled (cron), event-triggered, or hybrid re-wake loops
|
|
8
|
+
- **LoopList** — List all active loops with IDs, triggers, status, and next-fire times
|
|
9
|
+
- **LoopDelete** — Delete or pause a loop by ID
|
|
10
|
+
- **MonitorCreate** — Start a background command that streams output via `monitor:output` pi events
|
|
11
|
+
- **MonitorList** — List monitoring processes and their status
|
|
12
|
+
- **MonitorStop** — Stop a running monitor (SIGTERM → 5s → SIGKILL)
|
|
13
|
+
|
|
14
|
+
### Commands
|
|
15
|
+
|
|
16
|
+
- **`/loop [interval] [prompt]`** — Interactive TUI loop creation
|
|
17
|
+
- **`/loops`** — View, create, cancel, and configure loops
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
- Three trigger types: cron (timer), event (eventbus), hybrid (both with debounce)
|
|
22
|
+
- File-backed persistence with pid-based file locking and atomic writes
|
|
23
|
+
- Cron scheduler with per-loop jitter and 7-day expiry
|
|
24
|
+
- Background process monitoring with stdout/stderr streaming
|
|
25
|
+
- Persistent TUI widget showing active loops and monitors
|
|
26
|
+
- System-reminder injection for loop fires (mirrors pi-tasks pattern)
|
|
27
|
+
- Self-paced loop mode for dynamic interval scheduling
|
|
28
|
+
- `@tintinweb/pi-tasks` integration with auto-task creation
|
|
29
|
+
|
|
30
|
+
### Configuration
|
|
31
|
+
|
|
32
|
+
- `PI_LOOP` env var for store path override / disable
|
|
33
|
+
- `PI_LOOP_SCOPE` env var for `memory` | `session` | `project`
|
|
34
|
+
- `PI_LOOP_DEBUG` env var for debug logging
|
|
35
|
+
|
|
36
|
+
### Limits
|
|
37
|
+
|
|
38
|
+
- Maximum 25 active loops
|
|
39
|
+
- Maximum 25 running monitors
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Contributing to @trevonistrevon/pi-loop
|
|
2
|
+
|
|
3
|
+
Thanks for contributing! This document covers local dev setup, conventions, and workflow.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/trevonistrevon/pi-loop.git
|
|
9
|
+
cd pi-loop
|
|
10
|
+
npm install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Scripts
|
|
14
|
+
|
|
15
|
+
| Command | Description |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `npm run typecheck` | TypeScript type checking (`tsc --noEmit`) |
|
|
18
|
+
| `npm run lint` | Lint with Biome |
|
|
19
|
+
| `npm run lint:fix` | Auto-fix lint issues |
|
|
20
|
+
| `npm test` | Run tests (`vitest run`) |
|
|
21
|
+
| `npm run test:watch` | Watch mode |
|
|
22
|
+
| `npm run build` | Compile TypeScript |
|
|
23
|
+
|
|
24
|
+
## Architecture
|
|
25
|
+
|
|
26
|
+
See `AGENTS.md` for the full architecture overview. Key modules:
|
|
27
|
+
|
|
28
|
+
- **`src/index.ts`** — Extension entry: registers 6 tools + `/loop` `/loops` commands + widget lifecycle
|
|
29
|
+
- **`src/types.ts`** — Core types: `LoopEntry`, `MonitorEntry`, `Trigger` variants
|
|
30
|
+
- **`src/store.ts`** — File-backed CRUD with pid-based file locking (atomic write → rename)
|
|
31
|
+
- **`src/scheduler.ts`** — Timer-based cron scheduler with per-loop jitter and 7-day expiry
|
|
32
|
+
- **`src/trigger-system.ts`** — Unified engine: cron timers + pi event subscriptions + hybrid debounce
|
|
33
|
+
- **`src/monitor-manager.ts`** — `ChildProcess` wrapper: stdout/stderr streaming as pi events
|
|
34
|
+
- **`src/loop-parse.ts`** — Human interval parsing (`5m` → cron), cron matching, next-fire computation
|
|
35
|
+
- **`src/ui/widget.ts`** — TUI widget rendering active loops + monitors above the editor
|
|
36
|
+
|
|
37
|
+
## Conventions
|
|
38
|
+
|
|
39
|
+
- **TypeScript 6.x** strict mode, ES2022 target, bundler module resolution
|
|
40
|
+
- **No comments unless answering "why"** — never "what"
|
|
41
|
+
- **`debug(...)`** helper gated on `PI_LOOP_DEBUG` env var, logs to stderr
|
|
42
|
+
- **`textResult(msg)`** helper for uniform tool output strings
|
|
43
|
+
- **Tool params** use `Type.Object()` with description strings from `typebox`
|
|
44
|
+
- **File-backed stores** use atomic write (write tmp → rename) + pid-based file locking
|
|
45
|
+
|
|
46
|
+
## Testing
|
|
47
|
+
|
|
48
|
+
Tests are co-located in `test/` as `<module>.test.ts`. The suite uses:
|
|
49
|
+
|
|
50
|
+
- **vitest** with `describe`/`it`
|
|
51
|
+
- In-memory stores for unit tests
|
|
52
|
+
- `tmpdir` for file-backed store tests
|
|
53
|
+
- `vi.useFakeTimers()` for scheduler tests
|
|
54
|
+
- Mocked pi eventbus for monitor-manager tests
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm test # Run once
|
|
58
|
+
npm run test:watch # Watch mode
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Pull Request Workflow
|
|
62
|
+
|
|
63
|
+
1. Fork, branch, implement
|
|
64
|
+
2. Ensure `npm run typecheck`, `npm run lint`, and `npm test` all pass
|
|
65
|
+
3. Open PR against `main`
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
By contributing, you agree that your contributions will be licensed under the MIT License.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 trevonistrevon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">@trevonistrevon/pi-loop</h1>
|
|
3
|
+
<h6 align="center">Cron and event loops for the pi coding agent. Background monitors, scheduled re-wakes, pi-tasks integration.</h6>
|
|
4
|
+
</p>
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pi install @trevonistrevon/pi-loop
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quick start
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
LoopCreate trigger="5m" prompt="Check if the build passed"
|
|
16
|
+
LoopCreate trigger="tool_execution_start" prompt="Log the tool being used" triggerType="event"
|
|
17
|
+
LoopList
|
|
18
|
+
LoopDelete id="1"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
MonitorCreate command="tail -n0 -f build.log" description="Watch build"
|
|
23
|
+
MonitorList
|
|
24
|
+
MonitorStop monitorId="1"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Commands
|
|
28
|
+
|
|
29
|
+
`/loop [interval] [prompt]` — interactive loop creation.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
/loop # menu
|
|
33
|
+
/loop 5m check the deploy # 5-minute cron loop
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Tools
|
|
37
|
+
|
|
38
|
+
| Tool | What it does |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `LoopCreate` | Schedule a prompt on a cron timer, a pi event, or both with debounce |
|
|
41
|
+
| `LoopList` | Show active loops with IDs, triggers, and next-fire times |
|
|
42
|
+
| `LoopDelete` | Delete or pause a loop |
|
|
43
|
+
| `MonitorCreate` | Run a background command, stream output as `monitor:output` events |
|
|
44
|
+
| `MonitorList` | Show monitors with status, uptime, and output line count |
|
|
45
|
+
| `MonitorStop` | Stop a monitor (SIGTERM → 5s → SIGKILL) |
|
|
46
|
+
|
|
47
|
+
Trigger types: `cron` (`5m`, `1h`, `0 9 * * 1-5`), `event` (any pi event source), or `hybrid` (both, debounced).
|
|
48
|
+
|
|
49
|
+
## pi-tasks
|
|
50
|
+
|
|
51
|
+
Works with [@tintinweb/pi-tasks](https://github.com/tintinweb/pi-tasks). Pass `autoTask: true` on `LoopCreate` and each loop fire auto-creates a tracked task. Detection happens over pi's event bus — no manual wiring.
|
|
52
|
+
|
|
53
|
+
## Widget
|
|
54
|
+
|
|
55
|
+
Active loops and monitors show in a persistent TUI widget above the editor.
|
|
56
|
+
|
|
57
|
+
## Configuration
|
|
58
|
+
|
|
59
|
+
| Variable | Effect | Default |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| `PI_LOOP` | Store path. `off` to disable, absolute or project-relative path | `.pi/loops/loops.json` |
|
|
62
|
+
| `PI_LOOP_SCOPE` | `memory` (ephemeral), `session` (per-session file), `project` (shared) | `session` |
|
|
63
|
+
| `PI_LOOP_DEBUG` | Debug logging to stderr | unset |
|
|
64
|
+
|
|
65
|
+
## Limits
|
|
66
|
+
|
|
67
|
+
25 active loops, 25 running monitors. Recurring loops expire after 7 days.
|
|
68
|
+
|
|
69
|
+
## Development
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm run typecheck
|
|
73
|
+
npm run lint
|
|
74
|
+
npm test
|
|
75
|
+
npm run build
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
MIT — [LICENSE](./LICENSE)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @trevonistrevon/pi-loop — A pi extension providing cron/event-based agent re-wake loops and background process monitoring.
|
|
3
|
+
*
|
|
4
|
+
* Tools:
|
|
5
|
+
* LoopCreate — Create a scheduled or event-triggered re-wake loop
|
|
6
|
+
* LoopList — List all active loops with status and next-fire times
|
|
7
|
+
* LoopDelete — Delete or pause a loop by ID
|
|
8
|
+
* MonitorCreate — Start a background command that streams output via pi events
|
|
9
|
+
* MonitorList — List running monitors
|
|
10
|
+
* MonitorStop — Stop a running monitor
|
|
11
|
+
*
|
|
12
|
+
* Commands:
|
|
13
|
+
* /loop — Schedule a re-wake loop: /loop [interval] [prompt]
|
|
14
|
+
* /loops — Interactive menu: view, create, cancel, settings
|
|
15
|
+
*/
|
|
16
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
17
|
+
export default function (pi: ExtensionAPI): void;
|