loop-task 1.1.0 → 1.4.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.
Files changed (130) hide show
  1. package/README.md +250 -113
  2. package/dist/board/App.js +340 -0
  3. package/dist/board/board-log.js +18 -0
  4. package/dist/board/components/ActionButtons.js +45 -0
  5. package/dist/board/components/BoardButton.js +58 -0
  6. package/dist/board/components/ConfirmModal.js +36 -0
  7. package/dist/board/components/CreateForm.js +309 -0
  8. package/dist/board/components/CreateProjectModal.js +104 -0
  9. package/dist/board/components/DeleteProjectConfirm.js +53 -0
  10. package/dist/board/components/DetailView.js +25 -0
  11. package/dist/board/components/EditProjectModal.js +106 -0
  12. package/dist/board/components/FilterBar.js +16 -0
  13. package/dist/board/components/Footer.js +52 -0
  14. package/dist/board/components/Header.js +46 -0
  15. package/dist/board/components/HelpModal.js +36 -0
  16. package/dist/board/components/Inspector.js +12 -0
  17. package/dist/board/components/LogModal.js +58 -0
  18. package/dist/board/components/Navigator.js +84 -0
  19. package/dist/board/components/ProjectsModal.js +70 -0
  20. package/dist/board/components/ProjectsPage.js +105 -0
  21. package/dist/board/components/RunHistory.js +83 -0
  22. package/dist/board/components/TaskBrowser.js +95 -0
  23. package/dist/board/components/TaskFilterBar.js +6 -0
  24. package/dist/board/components/TaskForm.js +177 -0
  25. package/dist/board/components/Timeline.js +5 -0
  26. package/dist/board/daemon.js +117 -0
  27. package/dist/board/format.js +102 -0
  28. package/dist/board/hooks/useBoardKeybindings.js +299 -0
  29. package/dist/board/hooks/useBreakpoint.js +6 -0
  30. package/dist/board/hooks/useHoverState.js +11 -0
  31. package/dist/board/hooks/useLogStream.js +32 -0
  32. package/dist/board/hooks/useLoopPolling.js +28 -0
  33. package/dist/board/hooks/useTaskKeybindings.js +114 -0
  34. package/dist/board/index.js +32 -0
  35. package/dist/board/router.js +16 -0
  36. package/dist/board/state.js +99 -0
  37. package/dist/board/toast.js +65 -0
  38. package/dist/board/types.js +1 -0
  39. package/dist/cli.js +134 -93
  40. package/dist/cli.js.map +1 -1
  41. package/dist/client/commands.d.ts +11 -0
  42. package/dist/client/commands.d.ts.map +1 -0
  43. package/dist/client/commands.js +317 -0
  44. package/dist/client/commands.js.map +1 -0
  45. package/dist/client/ipc.d.ts +5 -0
  46. package/dist/client/ipc.d.ts.map +1 -0
  47. package/dist/client/ipc.js +96 -0
  48. package/dist/client/ipc.js.map +1 -0
  49. package/dist/config/constants.js +29 -0
  50. package/dist/config/paths.js +49 -0
  51. package/dist/core/command-runner.js +82 -0
  52. package/dist/core/foreground-loop.js +81 -0
  53. package/dist/core/log-parser.js +29 -0
  54. package/dist/core/log-rotator.js +25 -0
  55. package/dist/core/loop-controller.js +429 -0
  56. package/dist/daemon/daemon-log.js +11 -0
  57. package/dist/daemon/index.d.ts +2 -0
  58. package/dist/daemon/index.d.ts.map +1 -0
  59. package/dist/daemon/index.js +43 -0
  60. package/dist/daemon/index.js.map +1 -0
  61. package/dist/daemon/manager.d.ts +17 -0
  62. package/dist/daemon/manager.d.ts.map +1 -0
  63. package/dist/daemon/manager.js +260 -0
  64. package/dist/daemon/manager.js.map +1 -0
  65. package/dist/daemon/projects.js +104 -0
  66. package/dist/daemon/server.d.ts +15 -0
  67. package/dist/daemon/server.d.ts.map +1 -0
  68. package/dist/daemon/server.js +345 -0
  69. package/dist/daemon/server.js.map +1 -0
  70. package/dist/daemon/spawner.d.ts +3 -0
  71. package/dist/daemon/spawner.d.ts.map +1 -0
  72. package/dist/daemon/spawner.js +82 -0
  73. package/dist/daemon/spawner.js.map +1 -0
  74. package/dist/daemon/state.d.ts +15 -0
  75. package/dist/daemon/state.d.ts.map +1 -0
  76. package/dist/daemon/state.js +151 -0
  77. package/dist/daemon/state.js.map +1 -0
  78. package/dist/daemon/task-manager.js +59 -0
  79. package/dist/duration.js +4 -4
  80. package/dist/entry.js +11 -0
  81. package/dist/esm-loader.js +36 -0
  82. package/dist/i18n/en.json +386 -0
  83. package/dist/i18n/index.js +11 -0
  84. package/dist/ipc/handlers/logs-stream.js +65 -0
  85. package/dist/ipc/send.js +5 -0
  86. package/dist/logger.js +0 -1
  87. package/dist/loop-config.d.ts +13 -0
  88. package/dist/loop-config.d.ts.map +1 -0
  89. package/dist/loop-config.js +83 -0
  90. package/dist/loop-config.js.map +1 -0
  91. package/dist/loop.d.ts +43 -2
  92. package/dist/loop.d.ts.map +1 -1
  93. package/dist/loop.js +247 -2
  94. package/dist/loop.js.map +1 -1
  95. package/dist/open-board.d.ts +2 -0
  96. package/dist/open-board.d.ts.map +1 -0
  97. package/dist/open-board.js +19 -0
  98. package/dist/open-board.js.map +1 -0
  99. package/dist/shared/clipboard.js +19 -0
  100. package/dist/shared/fs-utils.js +11 -0
  101. package/dist/shared/sleep.js +17 -0
  102. package/dist/shared/tail.js +4 -0
  103. package/dist/tui/app.d.ts +57 -0
  104. package/dist/tui/app.d.ts.map +1 -0
  105. package/dist/tui/app.js +167 -0
  106. package/dist/tui/app.js.map +1 -0
  107. package/dist/tui/create-loop.d.ts +3 -0
  108. package/dist/tui/create-loop.d.ts.map +1 -0
  109. package/dist/tui/create-loop.js +90 -0
  110. package/dist/tui/create-loop.js.map +1 -0
  111. package/dist/tui/dashboard.d.ts +2 -0
  112. package/dist/tui/dashboard.d.ts.map +1 -0
  113. package/dist/tui/dashboard.js +45 -0
  114. package/dist/tui/dashboard.js.map +1 -0
  115. package/dist/tui/events.d.ts +3 -0
  116. package/dist/tui/events.d.ts.map +1 -0
  117. package/dist/tui/events.js +244 -0
  118. package/dist/tui/events.js.map +1 -0
  119. package/dist/tui/popup.d.ts +3 -0
  120. package/dist/tui/popup.d.ts.map +1 -0
  121. package/dist/tui/popup.js +58 -0
  122. package/dist/tui/popup.js.map +1 -0
  123. package/dist/tui/render.d.ts +9 -0
  124. package/dist/tui/render.d.ts.map +1 -0
  125. package/dist/tui/render.js +305 -0
  126. package/dist/tui/render.js.map +1 -0
  127. package/dist/types.d.ts +74 -0
  128. package/dist/types.d.ts.map +1 -1
  129. package/dist/types.js +0 -1
  130. package/package.json +64 -55
package/README.md CHANGED
@@ -1,113 +1,250 @@
1
- # loop-task
2
-
3
- A cross-platform CLI that repeatedly executes a shell command at a human-readable interval.
4
-
5
- Inspired by agent loops, but intentionally simple.
6
-
7
- ## Installation
8
-
9
- ```bash
10
- npm install -g loop-task
11
- ```
12
-
13
- Or use directly with npx:
14
-
15
- ```bash
16
- npx loop-task 30m npm test
17
- ```
18
-
19
- ## Usage
20
-
21
- ```bash
22
- loop-task [options] <interval> <command>
23
- ```
24
-
25
- ### Basic examples
26
-
27
- ```bash
28
- loop-task 30m npm test
29
- loop-task 1h opencode --prompt '/ob-init'
30
- loop-task 1d node sync.js
31
- ```
32
-
33
- ### With npx
34
-
35
- ```bash
36
- npx loop-task 30m npm test
37
- npx loop-task 1h opencode --prompt '/ob-init'
38
- ```
39
-
40
- ### Options
41
-
42
- Options must come before the interval:
43
-
44
- | Option | Description |
45
- | ----------------- | -------------------------------- |
46
- | `--now` | Run immediately before waiting |
47
- | `--max-runs <n>` | Stop after N executions |
48
- | `--verbose` | Show execution details |
49
- | `-h, --help` | Display help |
50
- | `-V, --version` | Display version |
51
-
52
- ## Examples
53
-
54
- ### Agent workflows
55
-
56
- ```bash
57
- npx loop-task 30m --now -- opencode run "search for missing translation text and translate them, 3 maximum" --model "opencode/big-pickle"
58
- ```
59
-
60
- ### Run tests every 30 minutes
61
-
62
- ```bash
63
- loop-task 30m npm test
64
- ```
65
-
66
- ### Run immediately, then every hour
67
-
68
- ```bash
69
- loop-task --now 1h npm test
70
- ```
71
-
72
- ### Run up to 5 times then stop
73
-
74
- ```bash
75
- loop-task --max-runs 5 5m npm test
76
- ```
77
-
78
- ### Verbose mode
79
-
80
- ```bash
81
- loop-task --verbose 30m npm test
82
- ```
83
-
84
- Shows start/end timestamps, exit code, execution duration, and next scheduled run.
85
-
86
- ## Supported intervals
87
-
88
- | Format | Description |
89
- | ------ | ----------- |
90
- | `10s` | 10 seconds |
91
- | `5m` | 5 minutes |
92
- | `1h` | 1 hour |
93
- | `1d` | 1 day |
94
- | `1w` | 1 week |
95
-
96
- ## Behavior
97
-
98
- - **No overlapping**: waits for the command to finish before starting the next interval
99
- - **Resilient**: continues looping even if a command exits with a non-zero code
100
- - **Graceful shutdown**: finishes current execution on Ctrl+C, then exits cleanly
101
-
102
- ## Development
103
-
104
- ```bash
105
- pnpm install
106
- pnpm run build
107
- pnpm run test
108
- pnpm run lint
109
- ```
110
-
111
- ## License
112
-
113
- MIT
1
+ <div align="center">
2
+
3
+ # loop-task
4
+
5
+ **Run commands on repeat. Manage them from a terminal board.**
6
+
7
+ `loop-task` is a cross-platform CLI that runs shell commands at human-readable intervals. Create loops in the background, manage them from an interactive TUI board, or run them in the foreground.
8
+
9
+ [![npm version](https://img.shields.io/npm/v/loop-task?style=flat-square&color=black)](https://www.npmjs.com/package/loop-task)
10
+ [![npm downloads](https://img.shields.io/npm/dm/loop-task?style=flat-square&color=black)](https://www.npmjs.com/package/loop-task)
11
+ [![license](https://img.shields.io/npm/l/loop-task?style=flat-square&color=black)](./LICENSE)
12
+ [![node](https://img.shields.io/node/v/loop-task?style=flat-square&color=black)](https://nodejs.org)
13
+
14
+ </div>
15
+
16
+ ## Quick start
17
+
18
+ ```bash
19
+ npm install -g loop-task
20
+ loop-task # open the board (requires Bun)
21
+ loop-task start # start the daemon, restore persisted loops
22
+ loop-task new 30m -- npm test # create a background loop
23
+ loop-task run --now 10s -- echo hi # run a loop in the foreground
24
+ ```
25
+
26
+ Or run it directly:
27
+
28
+ ```bash
29
+ npx loop-task
30
+ npx loop-task new 30m -- npm test
31
+ ```
32
+
33
+ ## Requirements
34
+
35
+ - **Node.js >= 20** — required for all commands
36
+ - **Bun >= 1.2** — required for the interactive board only
37
+
38
+ Install Bun:
39
+
40
+ ```bash
41
+ npm install -g bun
42
+ ```
43
+
44
+ `start`, `new`, and `run` work with Node alone. The board auto-delegates to Bun when needed.
45
+
46
+ ## Concepts
47
+
48
+ ### Loops
49
+
50
+ A **loop** is a schedule — it defines *when* something runs. Loops trigger **tasks**.
51
+
52
+ | Field | Description |
53
+ | ----- | ----------- |
54
+ | **Interval** | How often to run (`30s`, `5m`, `1h`, `1d`, `1w`) |
55
+ | **Task** | Inline command or a reference to a previously defined task |
56
+ | **Description** | Optional label shown in the list; defaults to the task name |
57
+ | **Run immediately?** | Run once now, then every interval, or wait the first interval |
58
+ | **Max runs** | Stop after N runs, or leave blank to run forever |
59
+
60
+ ### Tasks
61
+
62
+ A **task** is an executable unit — it defines *what* runs. Tasks can chain to other tasks on success or failure.
63
+
64
+ | Field | Description |
65
+ | ----- | ----------- |
66
+ | **Name** | A short label for the task |
67
+ | **Command** | The full command line |
68
+ | **On success** | Optional task to run when this one exits with code 0 |
69
+ | **On failure** | Optional task to run when this one exits with a non-zero code |
70
+
71
+ Tasks are reusable — the same task can be referenced by multiple loops or by other tasks' success/failure chains.
72
+
73
+ ### Projects
74
+
75
+ A **project** is an organizational scope for loops. Every loop belongs to exactly one project. The board shows only loops in the currently selected project.
76
+
77
+ | Field | Description |
78
+ | ----- | ----------- |
79
+ | **Name** | A short label for the project |
80
+ | **Color** | One of six colors: white, cyan, orange, green, red, yellow |
81
+
82
+ Key behaviors:
83
+ - **Default project** — always present, cannot be renamed or deleted. New loops are assigned here when no other project is selected.
84
+ - **Color bullets** each loop in the navigator displays a colored bullet (●) matching its project color.
85
+ - **Project filter** — the board shows only loops belonging to the currently active project. The selection persists across sessions via `localStorage`.
86
+
87
+ To use projects from the board:
88
+ - Press `c` to open the **Project selector** (switch between projects)
89
+ - Click **Manage Projects** in the filter bar (or use the keyboard shortcut) to open the **Manage Projects** page
90
+ - From the Manage Projects page: `n` creates a new project, `e` renames the selected project, `d` deletes it, `Esc` returns to the board
91
+
92
+ From the CLI:
93
+ - `loop-task project list` list all projects
94
+ - `loop-task project new <name> [--color <color>]` create a project
95
+ - `loop-task project rename <id|name> <new-name>` — rename a project
96
+ - `loop-task project color <id|name> <color>` — change a project's color
97
+ - `loop-task project delete <id|name>` — delete a project (loops move to Default)
98
+ - `loop-task new <interval> --project <name> -- <command>` create a loop assigned to a project
99
+
100
+ Colors can be a name (`white`, `cyan`, `green`, `yellow`, `orange`, `pink`) or a `#rrggbb` hex value.
101
+
102
+ ## Commands
103
+
104
+ | Command | Description |
105
+ | ------- | ----------- |
106
+ | `loop-task` | Open the interactive board (requires Bun) |
107
+ | `loop-task start` | Start the background daemon, restore persisted loops |
108
+ | `loop-task new <interval> -- <command>` | Create a background loop (creates an inline task) |
109
+ | `loop-task new <interval> --project <name> -- <command>` | Create a loop assigned to a project |
110
+ | `loop-task run <interval> -- <command>` | Run a loop in the foreground |
111
+ | `loop-task project list` | List all projects |
112
+ | `loop-task project new <name> [--color <color>]` | Create a project |
113
+ | `loop-task project rename <id\|name> <new-name>` | Rename a project |
114
+ | `loop-task project color <id\|name> <color>` | Change project color |
115
+ | `loop-task project delete <id\|name>` | Delete a project (loops move to Default) |
116
+
117
+ ### Options (for `new` and `run`)
118
+
119
+ | Option | Description |
120
+ | ------ | ----------- |
121
+ | `--now` | Run immediately before waiting |
122
+ | `--max-runs <n>` | Stop after N executions |
123
+ | `--cwd <dir>` | Working directory for the command |
124
+ | `--verbose` | Show execution details |
125
+ | `-h, --help` | Display help |
126
+ | `-V, --version` | Display version |
127
+
128
+ ## Examples
129
+
130
+ ```bash
131
+ # Run tests every 30 minutes
132
+ loop-task new 30m -- npm test
133
+
134
+ # Run immediately, then every hour
135
+ loop-task new --now 1h -- npm test
136
+
137
+ # Run up to 5 times, then stop
138
+ loop-task run --max-runs 5 5m -- npm test
139
+
140
+ # Agent workflow — schedule an AI task every 30 minutes
141
+ loop-task new 30m --now -- opencode run "search missing translations and translate them, 3 maximum" --model "opencode/big-pickle"
142
+ # Run in a specific directory
143
+ loop-task new 30m --cwd ./packages/api -- npm test
144
+
145
+ # Verbose mode
146
+ loop-task run --verbose 30m -- npm test
147
+ ```
148
+
149
+ When the command has its own flags, use `--` to stop argument parsing:
150
+
151
+ ```bash
152
+ loop-task new 30m -- node -e "console.log('hello')"
153
+ ```
154
+
155
+ ## The board
156
+
157
+ The board is the primary way to manage loops and tasks. It shows all loops, their status, run history, and logs in a single terminal interface.
158
+
159
+ ### Board controls
160
+
161
+ ```
162
+ ↑/↓, j/k move selection
163
+ Enter edit selected loop
164
+ e edit loop
165
+ d/del delete loop
166
+ p pause (when waiting) / play (when idle/paused)
167
+ s stop loop (resets schedule)
168
+ n create a new loop
169
+ t create a new task
170
+ o cycle sort mode (order by)
171
+ ←/→ switch between panels
172
+ / search loops
173
+ h toggle help
174
+ esc quit
175
+ ```
176
+
177
+ Destructive actions (pause, force run, delete) prompt a confirmation before executing.
178
+
179
+ ### Pause vs Stop
180
+
181
+ - **Pause** (`p`) — temporarily halts the loop. Resuming continues the original schedule (e.g., a loop that runs every 6h at :00 paused at 12:00 and resumed at 14:00 will still fire at 16:00).
182
+ - **Stop** (`s`) — halts the loop and clears the schedule. Playing starts a fresh interval from now (e.g., the same loop stopped at 12:00 and played at 14:00 will fire at 20:00).
183
+
184
+ ## How it works
185
+
186
+ ```
187
+ loop-task (board) ──IPC──► daemon ──► loop 1 ──► task (command)
188
+ ├──► loop 2 ──► task ──► on-success task
189
+ └──► loop 3 ──► task ──► on-failure task
190
+ ```
191
+
192
+ - The **daemon** is a background process that manages all loops and tasks. It starts automatically when you run `loop-task start` or any command that needs it.
193
+ - The **board** is a terminal UI that connects to the daemon via IPC.
194
+ - **Loops** define schedules and reference tasks. **Tasks** define commands and optional success/failure chains.
195
+ - Loops and tasks **persist to disk** — they survive daemon restarts and system reboots. When the daemon starts, it restores all loops and accounts for elapsed time.
196
+
197
+ ### Lifecycle
198
+
199
+ 1. `loop-task start` or `loop-task new ...` spawns the daemon if not running
200
+ 2. The daemon creates a loop and a task, and persists their state to disk
201
+ 3. `loop-task` opens the board for interactive management
202
+ 4. Closing the board or terminal does **not** stop loops — the daemon keeps running
203
+ 5. After a reboot, `loop-task start` restores all persisted loops with correct timing
204
+
205
+ ## Supported intervals
206
+
207
+ | Format | Description |
208
+ | ------ | ----------- |
209
+ | `10s` | 10 seconds |
210
+ | `5m` | 5 minutes |
211
+ | `1h` | 1 hour |
212
+ | `1d` | 1 day |
213
+ | `1w` | 1 week |
214
+
215
+ ## Behavior
216
+
217
+ - **No overlapping** — waits for the command to finish before starting the next interval
218
+ - **Resilient** — continues looping even if a command exits with a non-zero code
219
+ - **Persistent** — loop and task state is saved after every run; survives restarts
220
+ - **Graceful shutdown** — background loops are daemon-managed; foreground loops finish the current execution on Ctrl+C
221
+
222
+ ## Development
223
+
224
+ Requires [Bun](https://bun.sh) >= 1.2 for package management and the board, and [Node.js](https://nodejs.org) >= 20 for the CLI and daemon.
225
+
226
+ ```bash
227
+ bun install
228
+ npm run build
229
+ ```
230
+
231
+ Run locally:
232
+
233
+ ```bash
234
+ bun run dev # board
235
+ node dist/entry.js new --now 30m -- npm test # background loop
236
+ node dist/entry.js run --now --max-runs 1 10s -- echo hello # foreground
237
+ ```
238
+
239
+ Quality gates:
240
+
241
+ ```bash
242
+ bun run typecheck
243
+ bun run lint
244
+ bun run test
245
+ npm run build
246
+ ```
247
+
248
+ ## License
249
+
250
+ MIT