taskify-nostr 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/README.md +271 -0
- package/dist/aiClient.js +40 -0
- package/dist/completions.js +637 -0
- package/dist/config.js +39 -0
- package/dist/index.js +2074 -0
- package/dist/nostrRuntime.js +888 -0
- package/dist/onboarding.js +93 -0
- package/dist/render.js +207 -0
- package/dist/shared/agentDispatcher.js +595 -0
- package/dist/shared/agentIdempotency.js +50 -0
- package/dist/shared/agentRuntime.js +7 -0
- package/dist/shared/agentSecurity.js +161 -0
- package/dist/shared/boardUtils.js +441 -0
- package/dist/shared/dateUtils.js +123 -0
- package/dist/shared/nostr.js +70 -0
- package/dist/shared/settingsTypes.js +23 -0
- package/dist/shared/taskTypes.js +12 -0
- package/dist/shared/taskUtils.js +261 -0
- package/dist/taskCache.js +59 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# taskify-cli
|
|
2
|
+
|
|
3
|
+
A command-line client for managing tasks over the Nostr protocol.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd taskify-cli
|
|
9
|
+
npm install
|
|
10
|
+
npm link # installs `taskify` globally
|
|
11
|
+
taskify --help
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**Requirements:** Node.js 22+ (for `--experimental-strip-types`)
|
|
15
|
+
|
|
16
|
+
If `npm link` fails due to permissions:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm link --prefix ~/.local
|
|
20
|
+
# then add ~/.local/bin to your PATH
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Setup
|
|
26
|
+
|
|
27
|
+
### Private key
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
taskify config set nsec nsec1...
|
|
31
|
+
# or via environment variable (takes precedence):
|
|
32
|
+
export TASKIFY_NSEC=nsec1...
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Relays (optional — defaults provided)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
taskify config set relay wss://relay.damus.io
|
|
39
|
+
taskify relay list
|
|
40
|
+
taskify relay status
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Show config
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
taskify config show
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Command Reference
|
|
52
|
+
|
|
53
|
+
### Task commands
|
|
54
|
+
|
|
55
|
+
| Command | Options | Description |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| `list` | `--board` `--status open\|done\|any` `--column` `--json` | List tasks |
|
|
58
|
+
| `add <title>` | `--board` `--due` `--priority 1\|2\|3` `--note` `--subtask` `--column` | Create a task |
|
|
59
|
+
| `show <taskId>` | `--board` `--json` | Show full task details |
|
|
60
|
+
| `update <taskId>` | `--title` `--due` `--priority` `--note` `--column` | Update task fields |
|
|
61
|
+
| `done <taskId>` | `--board` | Mark a task done |
|
|
62
|
+
| `reopen <taskId>` | `--board` | Reopen a completed task |
|
|
63
|
+
| `delete <taskId>` | `--board` `--force` | Delete a task |
|
|
64
|
+
| `search <query>` | `--board` `--status` `--json` | Full-text search across tasks |
|
|
65
|
+
| `subtask <taskId> <ref>` | `--board` `--done` `--reopen` | Toggle a subtask (ref = index or title substring) |
|
|
66
|
+
| `remind <taskId> <presets...>` | `--board` | Set reminder presets (e.g. `1d 1h`) |
|
|
67
|
+
| `assign <taskId> <npub\|hex>` | `--board` | Assign a user to a task |
|
|
68
|
+
| `unassign <taskId> <npub\|hex>` | `--board` | Unassign a user from a task |
|
|
69
|
+
|
|
70
|
+
### Inbox
|
|
71
|
+
|
|
72
|
+
| Command | Options | Description |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| `inbox list` | `--board` | List inbox items (tasks flagged for triage) |
|
|
75
|
+
| `inbox add <title>` | `--board` | Quick-capture a task to inbox |
|
|
76
|
+
| `inbox triage <taskId>` | `--board` `--column` `--priority` `--due` `--yes` | Interactively triage an inbox item |
|
|
77
|
+
|
|
78
|
+
### Export / Import
|
|
79
|
+
|
|
80
|
+
| Command | Options | Description |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| `export` | `--board` `--format json\|csv\|md` `--status` `--output <file>` | Export tasks |
|
|
83
|
+
| `import <file>` | `--board` `--dry-run` `--yes` | Import tasks from JSON or CSV |
|
|
84
|
+
|
|
85
|
+
Export formats:
|
|
86
|
+
- `json` — JSON array (default)
|
|
87
|
+
- `csv` — RFC 4180 with headers: `id,title,status,priority,dueISO,column,boardName,note,subtasks,createdAt`
|
|
88
|
+
- `md` — Markdown checklist grouped by column
|
|
89
|
+
|
|
90
|
+
Import accepts `.json` (array of `{title, note?, priority?, dueISO?, column?, subtasks?}`) or `.csv` (same schema as export). Duplicate titles on the same board are skipped.
|
|
91
|
+
|
|
92
|
+
### Board management
|
|
93
|
+
|
|
94
|
+
| Command | Options | Description |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `boards` | `--json` | List all boards with task counts |
|
|
97
|
+
| `board list` | | List joined boards |
|
|
98
|
+
| `board join <boardId>` | `--name` `--relay` | Join a board by Nostr event id |
|
|
99
|
+
| `board leave <boardId>` | | Leave a board |
|
|
100
|
+
| `board create <name>` | `--kind lists\|week` `--relay` | Create and publish a new board |
|
|
101
|
+
| `board sync [boardId]` | | Sync board metadata and columns from relay |
|
|
102
|
+
| `board columns [board]` | | List columns for a board |
|
|
103
|
+
| `board children <board>` | | List child boards (compound boards only) |
|
|
104
|
+
|
|
105
|
+
### Relay management
|
|
106
|
+
|
|
107
|
+
| Command | Description |
|
|
108
|
+
|---|---|
|
|
109
|
+
| `relay status` | Show relay connection status |
|
|
110
|
+
| `relay list` | List configured relays |
|
|
111
|
+
| `relay add <url>` | Add a relay |
|
|
112
|
+
| `relay remove <url>` | Remove a relay |
|
|
113
|
+
|
|
114
|
+
### Trust
|
|
115
|
+
|
|
116
|
+
| Command | Description |
|
|
117
|
+
|---|---|
|
|
118
|
+
| `trust add <npub>` | Mark an npub as trusted |
|
|
119
|
+
| `trust remove <npub>` | Remove a trusted npub |
|
|
120
|
+
| `trust list` | List all trusted npubs |
|
|
121
|
+
|
|
122
|
+
### AI agent (`taskify agent`)
|
|
123
|
+
|
|
124
|
+
| Command | Options | Description |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| `agent config show` | | Show AI agent config (key masked) |
|
|
127
|
+
| `agent config set-key <key>` | | Set OpenAI API key |
|
|
128
|
+
| `agent config set-model <model>` | | Set model (default: `gpt-4o-mini`) |
|
|
129
|
+
| `agent config set-url <url>` | | Set base URL (default: OpenAI) |
|
|
130
|
+
| `agent add <description>` | `--board` `--yes` `--dry-run` `--json` | NL → task via AI extraction |
|
|
131
|
+
| `agent triage` | `--board` `--yes` `--dry-run` `--json` | AI priority suggestions across open tasks |
|
|
132
|
+
|
|
133
|
+
`agent add` extracts title, note, priority, due date, column, and subtasks from a natural language description. Reviews extracted fields before creating (skippable with `--yes`).
|
|
134
|
+
|
|
135
|
+
`agent triage` sends all open tasks to the AI for priority scoring, prints a suggestion table, then applies changes on confirmation.
|
|
136
|
+
|
|
137
|
+
API key can also be set via `TASKIFY_AGENT_API_KEY` environment variable.
|
|
138
|
+
|
|
139
|
+
### Cache
|
|
140
|
+
|
|
141
|
+
| Command | Description |
|
|
142
|
+
|---|---|
|
|
143
|
+
| `cache status` | Show cache age and task counts |
|
|
144
|
+
| `cache clear` | Clear the local task cache |
|
|
145
|
+
|
|
146
|
+
### Shell completions
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# zsh
|
|
150
|
+
taskify completions --shell zsh > ~/.zsh/completions/_taskify
|
|
151
|
+
echo 'fpath=(~/.zsh/completions $fpath)' >> ~/.zshrc
|
|
152
|
+
echo 'autoload -U compinit && compinit' >> ~/.zshrc
|
|
153
|
+
source ~/.zshrc
|
|
154
|
+
|
|
155
|
+
# bash
|
|
156
|
+
taskify completions --shell bash > ~/.bash_completion.d/taskify
|
|
157
|
+
source ~/.bash_completion.d/taskify
|
|
158
|
+
|
|
159
|
+
# fish
|
|
160
|
+
taskify completions --shell fish > ~/.config/fish/completions/taskify.fish
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Column support
|
|
166
|
+
|
|
167
|
+
Boards with columns (`kind: lists` or `kind: week`) support column-aware operations:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Add a task to a specific column
|
|
171
|
+
taskify add "Fix auth bug" --board "Dev" --column "Bugs"
|
|
172
|
+
|
|
173
|
+
# Filter list by column
|
|
174
|
+
taskify list --board "Dev" --column "In Progress"
|
|
175
|
+
|
|
176
|
+
# Move a task to a different column
|
|
177
|
+
taskify update <taskId> --column "Done"
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Week boards auto-assign tasks to today's column (YYYY-MM-DD) when no `--column` is specified.
|
|
181
|
+
|
|
182
|
+
Use `taskify board sync` to pull the latest column definitions from the relay, then `taskify board columns` to list them.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Compound boards
|
|
187
|
+
|
|
188
|
+
Compound boards aggregate multiple child boards. `taskify list` on a compound board fetches and merges tasks from all children automatically.
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
taskify board sync
|
|
192
|
+
taskify board children "My Compound Board"
|
|
193
|
+
taskify list --board "My Compound Board" # merges all children
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Adding tasks to a compound board directly is not allowed — use a child board instead.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Example output
|
|
201
|
+
|
|
202
|
+
### `taskify list`
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
Board: Dev
|
|
206
|
+
ID TITLE DUE PRI COL TRUST
|
|
207
|
+
e5100d28 Ship v2 release (2/4) 2026-03-15 2 Backlog ✓
|
|
208
|
+
a8c2f4b0 Fix login bug 2026-03-10 3 Bugs ✓
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
- **ID** — 8-char prefix (accepted by all commands)
|
|
212
|
+
- **TITLE** — truncated at 40 chars; `(N/M)` = completed/total subtasks
|
|
213
|
+
- **COL** — column name if on a lists/compound board
|
|
214
|
+
- **TRUST** — `✓` if `lastEditedBy` is a trusted npub
|
|
215
|
+
|
|
216
|
+
### `taskify list --json`
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
[
|
|
220
|
+
{
|
|
221
|
+
"id": "a8c2f4b0...",
|
|
222
|
+
"boardId": "...",
|
|
223
|
+
"boardName": "Dev",
|
|
224
|
+
"title": "Fix login bug",
|
|
225
|
+
"note": "",
|
|
226
|
+
"dueISO": "2026-03-10",
|
|
227
|
+
"priority": 3,
|
|
228
|
+
"column": "bugs-col-id",
|
|
229
|
+
"completed": false,
|
|
230
|
+
"subtasks": [],
|
|
231
|
+
"assignees": [],
|
|
232
|
+
"inboxItem": false,
|
|
233
|
+
"createdAt": 1773019736
|
|
234
|
+
}
|
|
235
|
+
]
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Agent usage
|
|
241
|
+
|
|
242
|
+
Taskify is built for AI agent workflows. All commands support `--json` output and exit `0` on success / `1` on error. A 10-second relay timeout is enforced; connections are torn down on exit.
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
# List open tasks as JSON
|
|
246
|
+
taskify list --status any --json
|
|
247
|
+
|
|
248
|
+
# Create a task with AI assistance
|
|
249
|
+
taskify agent add "urgent: fix the login crash by tomorrow" --board Dev --yes
|
|
250
|
+
|
|
251
|
+
# Triage priorities across the board
|
|
252
|
+
taskify agent triage --board Dev --yes
|
|
253
|
+
|
|
254
|
+
# Bulk import from JSON
|
|
255
|
+
taskify import tasks.json --board Dev --yes
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Trust model
|
|
259
|
+
|
|
260
|
+
- **`✓ trusted`** — `lastEditedBy` pubkey is in your trusted list
|
|
261
|
+
- **`✗ untrusted`** — editor unknown or not in list
|
|
262
|
+
- **`? unknown`** — no editor information
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Environment variables
|
|
267
|
+
|
|
268
|
+
| Variable | Description |
|
|
269
|
+
|---|---|
|
|
270
|
+
| `TASKIFY_NSEC` | Override saved private key |
|
|
271
|
+
| `TASKIFY_AGENT_API_KEY` | OpenAI API key for `taskify agent` |
|
package/dist/aiClient.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal fetch-based OpenAI-compatible AI client.
|
|
3
|
+
* No npm packages — uses Node 18+ built-in fetch.
|
|
4
|
+
*/
|
|
5
|
+
export async function callAI(opts) {
|
|
6
|
+
const timeout = opts.timeoutMs ?? 30_000;
|
|
7
|
+
const controller = new AbortController();
|
|
8
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
9
|
+
let response;
|
|
10
|
+
try {
|
|
11
|
+
response = await fetch(`${opts.baseUrl}/chat/completions`, {
|
|
12
|
+
method: "POST",
|
|
13
|
+
headers: {
|
|
14
|
+
"Content-Type": "application/json",
|
|
15
|
+
"Authorization": `Bearer ${opts.apiKey}`,
|
|
16
|
+
},
|
|
17
|
+
body: JSON.stringify({
|
|
18
|
+
model: opts.model,
|
|
19
|
+
messages: [
|
|
20
|
+
{ role: "system", content: opts.systemPrompt },
|
|
21
|
+
{ role: "user", content: opts.userMessage },
|
|
22
|
+
],
|
|
23
|
+
}),
|
|
24
|
+
signal: controller.signal,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
clearTimeout(timer);
|
|
29
|
+
}
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
const body = await response.text().catch(() => "");
|
|
32
|
+
throw new Error(`AI API error ${response.status}: ${body.slice(0, 200)}`);
|
|
33
|
+
}
|
|
34
|
+
const data = await response.json();
|
|
35
|
+
const content = data?.choices?.[0]?.message?.content;
|
|
36
|
+
if (!content) {
|
|
37
|
+
throw new Error("AI API returned no content in choices[0].message.content");
|
|
38
|
+
}
|
|
39
|
+
return content;
|
|
40
|
+
}
|