brain-dump: add recurring management, remove --when filter, show full context
This commit is contained in:
parent
3509d29882
commit
0352f8d04b
3 changed files with 94 additions and 48 deletions
8
TOOLS.md
8
TOOLS.md
|
|
@ -142,17 +142,19 @@ Helper script: `~/clawd/bin/brain-dump`
|
||||||
```bash
|
```bash
|
||||||
brain-dump list [--priority now,soon] [--due] [--limit N]
|
brain-dump list [--priority now,soon] [--due] [--limit N]
|
||||||
brain-dump add --text "..." --priority soon [--context "..."]
|
brain-dump add --text "..." --priority soon [--context "..."]
|
||||||
brain-dump edit <id> [--text "..."] [--priority ...] [--context "..."]
|
brain-dump add --recurring --text "..." --frequency daily [--when evening] [--note "..."] [--context "..."]
|
||||||
|
brain-dump edit <id> [--text "..."] [--priority|--frequency|--when|--note|--context "..."]
|
||||||
brain-dump done <id>
|
brain-dump done <id>
|
||||||
brain-dump show <id>
|
brain-dump show <id>
|
||||||
brain-dump nudged <id1>,<id2>,...
|
brain-dump nudged <id1>,<id2>,...
|
||||||
brain-dump recurring [--when evening]
|
brain-dump recurring
|
||||||
```
|
```
|
||||||
|
|
||||||
- Data: `memory/brain-dump.json`
|
- Data: `memory/brain-dump.json`
|
||||||
- `--due` filters by nudge interval: now=1d, soon=3d, someday=7d
|
- `--due` filters by nudge interval: now=1d, soon=3d, someday=7d
|
||||||
- `nudged` marks tasks as just-nudged (resets due timer)
|
- `nudged` marks tasks as just-nudged (resets due timer)
|
||||||
- `recurring` lists recurring reminders (nose shower etc.)
|
- `recurring` lists all recurring items with full context (note, when, frequency)
|
||||||
|
- `add --recurring` / `edit` / `done` work for both tasks and recurring items
|
||||||
- Output is tab-separated for minimal tokens
|
- Output is tab-separated for minimal tokens
|
||||||
|
|
||||||
**Heartbeat workflow:**
|
**Heartbeat workflow:**
|
||||||
|
|
|
||||||
132
bin/brain-dump
132
bin/brain-dump
|
|
@ -41,29 +41,32 @@ function formatTask(t) {
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatRecurring(r) {
|
||||||
|
let line = `${r.id}\t${r.frequency}\t${r.when || '-'}\t${r.text}`;
|
||||||
|
if (r.note) line += `\t${r.note}`;
|
||||||
|
if (r.context) line += `\t${r.context}`;
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
// --- Commands ---
|
// --- Commands ---
|
||||||
|
|
||||||
function cmdList(args) {
|
function cmdList(args) {
|
||||||
const data = load();
|
const data = load();
|
||||||
let tasks = data.tasks || [];
|
let tasks = data.tasks || [];
|
||||||
|
|
||||||
// Filter by priority
|
|
||||||
const prioArg = getFlag(args, '--priority');
|
const prioArg = getFlag(args, '--priority');
|
||||||
if (prioArg) {
|
if (prioArg) {
|
||||||
const prios = prioArg.split(',').map(s => s.trim());
|
const prios = prioArg.split(',').map(s => s.trim());
|
||||||
tasks = tasks.filter(t => prios.includes(t.priority));
|
tasks = tasks.filter(t => prios.includes(t.priority));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter by due
|
|
||||||
if (args.includes('--due')) {
|
if (args.includes('--due')) {
|
||||||
tasks = tasks.filter(isDue);
|
tasks = tasks.filter(isDue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort: now > soon > someday
|
|
||||||
const prioOrder = { now: 0, soon: 1, someday: 2 };
|
const prioOrder = { now: 0, soon: 1, someday: 2 };
|
||||||
tasks.sort((a, b) => (prioOrder[a.priority] ?? 3) - (prioOrder[b.priority] ?? 3));
|
tasks.sort((a, b) => (prioOrder[a.priority] ?? 3) - (prioOrder[b.priority] ?? 3));
|
||||||
|
|
||||||
// Limit
|
|
||||||
const limitArg = getFlag(args, '--limit');
|
const limitArg = getFlag(args, '--limit');
|
||||||
if (limitArg) {
|
if (limitArg) {
|
||||||
tasks = tasks.slice(0, parseInt(limitArg, 10));
|
tasks = tasks.slice(0, parseInt(limitArg, 10));
|
||||||
|
|
@ -80,43 +83,71 @@ function cmdList(args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmdAdd(args) {
|
function cmdAdd(args) {
|
||||||
|
const isRecurring = args.includes('--recurring');
|
||||||
const text = getFlag(args, '--text');
|
const text = getFlag(args, '--text');
|
||||||
if (!text) { console.error('--text required'); process.exit(1); }
|
if (!text) { console.error('--text required'); process.exit(1); }
|
||||||
const priority = getFlag(args, '--priority') || 'soon';
|
|
||||||
const context = getFlag(args, '--context') || undefined;
|
const context = getFlag(args, '--context') || undefined;
|
||||||
|
|
||||||
const data = load();
|
const data = load();
|
||||||
const task = {
|
|
||||||
id: shortId(),
|
if (isRecurring) {
|
||||||
added: new Date().toISOString().slice(0, 10),
|
const frequency = getFlag(args, '--frequency') || 'daily';
|
||||||
text,
|
const when = getFlag(args, '--when') || undefined;
|
||||||
priority,
|
const note = getFlag(args, '--note') || undefined;
|
||||||
};
|
const item = { id: shortId(), text, frequency };
|
||||||
if (context) task.context = context;
|
if (when) item.when = when;
|
||||||
data.tasks = data.tasks || [];
|
if (note) item.note = note;
|
||||||
data.tasks.push(task);
|
if (context) item.context = context;
|
||||||
save(data);
|
data.recurring = data.recurring || [];
|
||||||
console.log(`Added: ${task.id}\t${priority}\t${text}`);
|
data.recurring.push(item);
|
||||||
|
save(data);
|
||||||
|
console.log(`Added recurring: ${formatRecurring(item)}`);
|
||||||
|
} else {
|
||||||
|
const priority = getFlag(args, '--priority') || 'soon';
|
||||||
|
const task = { id: shortId(), added: new Date().toISOString().slice(0, 10), text, priority };
|
||||||
|
if (context) task.context = context;
|
||||||
|
data.tasks = data.tasks || [];
|
||||||
|
data.tasks.push(task);
|
||||||
|
save(data);
|
||||||
|
console.log(`Added: ${task.id}\t${priority}\t${text}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmdEdit(args) {
|
function cmdEdit(args) {
|
||||||
const id = args[0];
|
const id = args[0];
|
||||||
if (!id) { console.error('Usage: brain-dump edit <id> [--text ...] [--priority ...] [--context ...]'); process.exit(1); }
|
if (!id) { console.error('Usage: brain-dump edit <id> [--text ...] [--priority ...] [--context ...] [--frequency ...] [--when ...] [--note ...]'); process.exit(1); }
|
||||||
|
|
||||||
const data = load();
|
const data = load();
|
||||||
const task = (data.tasks || []).find(t => t.id === id);
|
|
||||||
if (!task) { console.error(`Task ${id} not found.`); process.exit(1); }
|
// Check tasks first, then recurring
|
||||||
|
let item = (data.tasks || []).find(t => t.id === id);
|
||||||
|
let isRecurring = false;
|
||||||
|
if (!item) {
|
||||||
|
item = (data.recurring || []).find(r => r.id === id);
|
||||||
|
isRecurring = true;
|
||||||
|
}
|
||||||
|
if (!item) { console.error(`Item ${id} not found.`); process.exit(1); }
|
||||||
|
|
||||||
const text = getFlag(args, '--text');
|
const text = getFlag(args, '--text');
|
||||||
const priority = getFlag(args, '--priority');
|
|
||||||
const context = getFlag(args, '--context');
|
const context = getFlag(args, '--context');
|
||||||
|
if (text) item.text = text;
|
||||||
|
if (context !== null && context !== undefined) item.context = context;
|
||||||
|
|
||||||
if (text) task.text = text;
|
if (isRecurring) {
|
||||||
if (priority) task.priority = priority;
|
const frequency = getFlag(args, '--frequency');
|
||||||
if (context !== null && context !== undefined) task.context = context;
|
const when = getFlag(args, '--when');
|
||||||
|
const note = getFlag(args, '--note');
|
||||||
save(data);
|
if (frequency) item.frequency = frequency;
|
||||||
console.log(`Updated: ${formatTask(task)}`);
|
if (when) item.when = when;
|
||||||
|
if (note !== null && note !== undefined) item.note = note;
|
||||||
|
save(data);
|
||||||
|
console.log(`Updated recurring: ${formatRecurring(item)}`);
|
||||||
|
} else {
|
||||||
|
const priority = getFlag(args, '--priority');
|
||||||
|
if (priority) item.priority = priority;
|
||||||
|
save(data);
|
||||||
|
console.log(`Updated: ${formatTask(item)}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmdDone(args) {
|
function cmdDone(args) {
|
||||||
|
|
@ -124,12 +155,27 @@ function cmdDone(args) {
|
||||||
if (!id) { console.error('Usage: brain-dump done <id>'); process.exit(1); }
|
if (!id) { console.error('Usage: brain-dump done <id>'); process.exit(1); }
|
||||||
|
|
||||||
const data = load();
|
const data = load();
|
||||||
const idx = (data.tasks || []).findIndex(t => t.id === id);
|
|
||||||
if (idx === -1) { console.error(`Task ${id} not found.`); process.exit(1); }
|
|
||||||
|
|
||||||
const removed = data.tasks.splice(idx, 1)[0];
|
// Check tasks
|
||||||
save(data);
|
let idx = (data.tasks || []).findIndex(t => t.id === id);
|
||||||
console.log(`Done: ${removed.text}`);
|
if (idx !== -1) {
|
||||||
|
const removed = data.tasks.splice(idx, 1)[0];
|
||||||
|
save(data);
|
||||||
|
console.log(`Done: ${removed.text}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check recurring
|
||||||
|
idx = (data.recurring || []).findIndex(r => r.id === id);
|
||||||
|
if (idx !== -1) {
|
||||||
|
const removed = data.recurring.splice(idx, 1)[0];
|
||||||
|
save(data);
|
||||||
|
console.log(`Removed recurring: ${removed.text}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(`Item ${id} not found.`);
|
||||||
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmdShow(args) {
|
function cmdShow(args) {
|
||||||
|
|
@ -137,10 +183,11 @@ function cmdShow(args) {
|
||||||
if (!id) { console.error('Usage: brain-dump show <id>'); process.exit(1); }
|
if (!id) { console.error('Usage: brain-dump show <id>'); process.exit(1); }
|
||||||
|
|
||||||
const data = load();
|
const data = load();
|
||||||
const task = (data.tasks || []).find(t => t.id === id);
|
const item = (data.tasks || []).find(t => t.id === id)
|
||||||
if (!task) { console.error(`Task ${id} not found.`); process.exit(1); }
|
|| (data.recurring || []).find(r => r.id === id);
|
||||||
|
if (!item) { console.error(`Item ${id} not found.`); process.exit(1); }
|
||||||
|
|
||||||
console.log(JSON.stringify(task, null, 2));
|
console.log(JSON.stringify(item, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmdNudged(args) {
|
function cmdNudged(args) {
|
||||||
|
|
@ -161,19 +208,15 @@ function cmdNudged(args) {
|
||||||
console.log(`Marked ${count} task(s) as nudged.`);
|
console.log(`Marked ${count} task(s) as nudged.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmdRecurring(args) {
|
function cmdRecurring() {
|
||||||
const data = load();
|
const data = load();
|
||||||
const when = getFlag(args, '--when');
|
const items = data.recurring || [];
|
||||||
let items = data.recurring || [];
|
|
||||||
if (when) {
|
|
||||||
items = items.filter(r => r.when === when);
|
|
||||||
}
|
|
||||||
if (items.length === 0) {
|
if (items.length === 0) {
|
||||||
console.log('No recurring items.');
|
console.log('No recurring items.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const r of items) {
|
for (const r of items) {
|
||||||
console.log(`${r.id}\t${r.frequency}\t${r.when || '-'}\t${r.text}`);
|
console.log(formatRecurring(r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,16 +239,17 @@ switch (cmd) {
|
||||||
case 'done': cmdDone(args); break;
|
case 'done': cmdDone(args); break;
|
||||||
case 'show': cmdShow(args); break;
|
case 'show': cmdShow(args); break;
|
||||||
case 'nudged': cmdNudged(args); break;
|
case 'nudged': cmdNudged(args); break;
|
||||||
case 'recurring': cmdRecurring(args); break;
|
case 'recurring': cmdRecurring(); break;
|
||||||
default:
|
default:
|
||||||
console.log(`Usage: brain-dump <command>
|
console.log(`Usage: brain-dump <command>
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
list [--priority now,soon] [--due] [--limit N]
|
list [--priority now,soon] [--due] [--limit N]
|
||||||
add --text "..." --priority soon [--context "..."]
|
add --text "..." --priority soon [--context "..."]
|
||||||
edit <id> [--text "..."] [--priority ...] [--context "..."]
|
add --recurring --text "..." --frequency daily [--when evening] [--note "..."] [--context "..."]
|
||||||
|
edit <id> [--text "..."] [--priority|--frequency|--when|--note|--context "..."]
|
||||||
done <id>
|
done <id>
|
||||||
show <id>
|
show <id>
|
||||||
nudged <id1>,<id2>,...
|
nudged <id1>,<id2>,...
|
||||||
recurring [--when evening]`);
|
recurring`);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"description": "Task tracking — auto-captured from chat or manually added. Done tasks get deleted.",
|
"description": "Task tracking — auto-captured from chat or manually added. Done tasks get deleted.",
|
||||||
"recurring": [
|
"recurring": [
|
||||||
{
|
{
|
||||||
"id": "nose-shower",
|
"id": "843efabf",
|
||||||
"text": "Nose shower 👃🚿",
|
"text": "Nose shower 👃🚿",
|
||||||
"frequency": "daily",
|
"frequency": "daily",
|
||||||
"when": "evening",
|
"when": "evening",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue