brain-dump: add recurring management, remove --when filter, show full context

This commit is contained in:
Agent 2026-02-07 14:07:57 +00:00
parent 3509d29882
commit 0352f8d04b
3 changed files with 94 additions and 48 deletions

View file

@ -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:**

View file

@ -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`);
} }

View file

@ -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",