tasuku 3.0.0-beta.4 → 3.0.0-beta.5
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/package.json +3 -2
- package/skills/tasuku/SKILL.md +223 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tasuku",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.5",
|
|
4
4
|
"description": "タスク — The minimal task runner",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"simple",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"email": "hiroki.osame@gmail.com"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
|
-
"dist"
|
|
20
|
+
"dist",
|
|
21
|
+
"skills"
|
|
21
22
|
],
|
|
22
23
|
"type": "module",
|
|
23
24
|
"types": "./dist/index.d.mts",
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tasuku
|
|
3
|
+
description: Minimal task runner for Node.js — displays loading, success, error, warning, and skipped states in the terminal. Use when creating CLI task runners, progress displays, or terminal UIs with tasuku.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# tasuku
|
|
7
|
+
|
|
8
|
+
Minimal task runner for Node.js. Renders task states to stderr, keeps stdout clean.
|
|
9
|
+
|
|
10
|
+
## Quick Start
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import task from 'tasuku'
|
|
14
|
+
|
|
15
|
+
await task('Build project', async ({ setTitle }) => {
|
|
16
|
+
await build()
|
|
17
|
+
setTitle('Build complete')
|
|
18
|
+
})
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Entry Points
|
|
22
|
+
|
|
23
|
+
| Import | Use |
|
|
24
|
+
|--------|-----|
|
|
25
|
+
| `tasuku` | Default (pinned renderer + default theme) |
|
|
26
|
+
| `tasuku/inline` | Inline renderer (sequential, no cursor manipulation) |
|
|
27
|
+
| `tasuku/create` | Raw factory (`createTasuku`, `pinned`, `inline`) |
|
|
28
|
+
| `tasuku/theme/claude` | Claude Code theme (shimmer + truecolor) |
|
|
29
|
+
| `tasuku/theme/blink` | Reduced-motion theme (pulsing dot) |
|
|
30
|
+
| `tasuku/theme/codex` | OpenAI Codex theme (cosine shimmer) |
|
|
31
|
+
|
|
32
|
+
Theme entry points export both `{ theme }` (data) and a default export (pre-composed task runner).
|
|
33
|
+
|
|
34
|
+
## `createTasuku`
|
|
35
|
+
|
|
36
|
+
The convenience `createTasuku` from `tasuku` or `tasuku/inline` accepts **partial** overrides — renderer and theme default to the entry point's built-in:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { createTasuku } from 'tasuku'
|
|
40
|
+
import { theme } from 'tasuku/theme/claude'
|
|
41
|
+
const task = createTasuku({ theme }) // renderer defaults to pinned
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The raw `createTasuku` from `tasuku/create` requires all options:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { createTasuku, pinned } from 'tasuku/create'
|
|
48
|
+
const task = createTasuku({ renderer: pinned, theme })
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Task Inner API
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
await task('Title', async (api) => {
|
|
55
|
+
api.setTitle('Updated title')
|
|
56
|
+
api.setStatus('step 2') // dimmed, in brackets: [step 2]
|
|
57
|
+
api.setOutput('result data') // → result data below task
|
|
58
|
+
api.setWarning('careful') // yellow ⚠ state
|
|
59
|
+
api.setError('failed') // red ✖ state
|
|
60
|
+
api.skip('not needed') // gray ⊘ state, throws (never returns)
|
|
61
|
+
api.signal // AbortSignal — cooperative cancellation
|
|
62
|
+
api.streamPreview // Writable for live streaming output
|
|
63
|
+
api.startTime() / api.stopTime() // elapsed time: (3s), (1m 30s)
|
|
64
|
+
})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
| Method | Effect |
|
|
68
|
+
|--------|--------|
|
|
69
|
+
| `setTitle(s)` | Update task title |
|
|
70
|
+
| `setStatus(s?)` | Show `[status]` after title, clear with no arg |
|
|
71
|
+
| `setOutput(s \| { message })` | Show `→ message` below task. Accepts string or object with `.message` |
|
|
72
|
+
| `setWarning(s?)` | Warning state. Accepts `Error \| string \| false \| null`. Falsy reverts to loading |
|
|
73
|
+
| `setError(s?)` | Error state. Same types as setWarning. Thrown errors auto-set this |
|
|
74
|
+
| `skip(msg?)` | Skip task. Throws internally — code after is unreachable. Promise resolves `undefined` |
|
|
75
|
+
| `streamPreview` | `Writable` stream for live output. Handles `\r` for progress bars. Shows last `previewLines` (default 5) lines with `(+ N lines)` indicator. Call `.clear()` to remove |
|
|
76
|
+
| `startTime()` | Start/restart elapsed timer. Shown as `(Xs)`, `(Xm Ys)`, `(Xh Ym)`. Hidden if < 1s |
|
|
77
|
+
| `stopTime()` | Stop timer, return elapsed ms. Display freezes at stopped value |
|
|
78
|
+
|
|
79
|
+
## Task Promise
|
|
80
|
+
|
|
81
|
+
`task()` returns a `TaskPromise<T>` — a Promise with live properties:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const p = task('Deploy', async () => data)
|
|
85
|
+
p.state // 'loading' | 'success' | 'error' | 'warning' | 'skipped'
|
|
86
|
+
p.warning // string | undefined (message when state is 'warning')
|
|
87
|
+
p.error // string | undefined (message when state is 'error')
|
|
88
|
+
p.skipped // string | undefined (message when state is 'skipped')
|
|
89
|
+
p.clear() // remove from UI, returns same promise for chaining
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`.clear()` can be chained before `await` — clears automatically on completion:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const result = await task('Temporary', async () => 42).clear()
|
|
96
|
+
// result === 42, task removed from UI
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Signal (AbortSignal)
|
|
100
|
+
|
|
101
|
+
The signal is **cooperative** — only cancels if passed to APIs that respect it (`fetch`, `setTimeout` from `timers/promises`, etc.).
|
|
102
|
+
|
|
103
|
+
Auto-aborted when:
|
|
104
|
+
- In `task.group()`: a sibling task throws (when `stopOnError: true`, the default)
|
|
105
|
+
- In nested tasks: the parent task throws
|
|
106
|
+
|
|
107
|
+
The error that caused the abort is on `signal.reason`.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
await task('Multi-step', async ({ signal }) => {
|
|
111
|
+
await step1(signal)
|
|
112
|
+
signal.throwIfAborted() // bail between steps
|
|
113
|
+
await step2(signal)
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
External signal:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const controller = new AbortController()
|
|
121
|
+
task('Cancellable', fn, { signal: controller.signal })
|
|
122
|
+
controller.abort()
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Groups
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const results = await task.group(task => [
|
|
129
|
+
task('Step 1', async () => 'a'),
|
|
130
|
+
task('Step 2', async () => 'b'),
|
|
131
|
+
], {
|
|
132
|
+
concurrency: 2,
|
|
133
|
+
stopOnError: true,
|
|
134
|
+
maxVisible: 10,
|
|
135
|
+
signal: controller.signal,
|
|
136
|
+
})
|
|
137
|
+
// results === ['a', 'b'] — array of return values
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
| Option | Default | Description |
|
|
141
|
+
|--------|---------|-------------|
|
|
142
|
+
| `concurrency` | `1` | Parallel tasks |
|
|
143
|
+
| `stopOnError` | `true` | Abort group on first failure |
|
|
144
|
+
| `maxVisible` | `rows - 2` | `number` or `(terminalHeight) => number`. Active tasks prioritized. Lifted on `.clear()` |
|
|
145
|
+
| `signal` | — | External `AbortSignal` |
|
|
146
|
+
|
|
147
|
+
Group returns `TaskGroupPromise` with `.clear()` to remove all tasks.
|
|
148
|
+
|
|
149
|
+
## Nesting
|
|
150
|
+
|
|
151
|
+
Tasks nest automatically via async context tracking — works across modules:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
await task('Parent', async () => {
|
|
155
|
+
await task('Child A', async () => { /* ... */ })
|
|
156
|
+
await task('Child B', async () => { /* ... */ })
|
|
157
|
+
})
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Renderers
|
|
161
|
+
|
|
162
|
+
**Pinned** (default): Task list fixed at bottom, spinner animates in-place, `console.log` moved above.
|
|
163
|
+
|
|
164
|
+
**Inline**: Sequential output, no cursor manipulation. Use when:
|
|
165
|
+
- Console.log ordering matters
|
|
166
|
+
- Logging to a file or pipe
|
|
167
|
+
- Running multiple `createTasuku()` instances concurrently
|
|
168
|
+
|
|
169
|
+
Multiple inline renderers on the same stream are supported. Multiple pinned renderers are not (they share a cursor save/restore slot). Use separate output streams for concurrent pinned instances.
|
|
170
|
+
|
|
171
|
+
## Theme Object
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
type TasukuTheme = {
|
|
175
|
+
spinner: string[] // pre-colored frames, e.g. [yellow('⠋'), ...]
|
|
176
|
+
spinnerInterval?: number // ms between frames (default: 80)
|
|
177
|
+
icons: {
|
|
178
|
+
pending: string // all pre-colored
|
|
179
|
+
success: string
|
|
180
|
+
error: string
|
|
181
|
+
warning: string
|
|
182
|
+
skipped: string
|
|
183
|
+
parent: string // parent task with children
|
|
184
|
+
parentError: string
|
|
185
|
+
}
|
|
186
|
+
colors: {
|
|
187
|
+
title?: (text: string, state: State, frame: number) => string
|
|
188
|
+
dim: (text: string) => string // status, elapsed time
|
|
189
|
+
secondary: (text: string) => string // output text, stream preview
|
|
190
|
+
error?: (text: string) => string // error output message
|
|
191
|
+
warning?: (text: string) => string // warning output message
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
The `title` color receives the animation frame counter — enables per-frame effects like shimmer.
|
|
197
|
+
|
|
198
|
+
## Options
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
task('Title', fn, {
|
|
202
|
+
showTime: true, // auto-start elapsed timer
|
|
203
|
+
previewLines: 5, // max lines for streamPreview (default 5, min 1)
|
|
204
|
+
signal: abortSignal, // external abort signal
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## States
|
|
209
|
+
|
|
210
|
+
| State | Icon | Trigger |
|
|
211
|
+
|-------|------|---------|
|
|
212
|
+
| pending | ◼ | Queued in group |
|
|
213
|
+
| loading | ⠋ | Task executing |
|
|
214
|
+
| success | ✔ | Task completed |
|
|
215
|
+
| warning | ⚠ | `setWarning(msg)` |
|
|
216
|
+
| error | ✖ | `setError(msg)` or thrown error |
|
|
217
|
+
| skipped | ⊘ | `skip(msg)` |
|
|
218
|
+
|
|
219
|
+
## Output Stream
|
|
220
|
+
|
|
221
|
+
Default: `process.stderr`. Override via `createTasuku({ outputStream })`.
|
|
222
|
+
|
|
223
|
+
Task UI renders to stderr so stdout stays clean for program output (`mytool | jq`).
|