diff --git a/TOOLS.md b/TOOLS.md index 5d0d3a8..1539d61 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -142,17 +142,19 @@ Helper script: `~/clawd/bin/brain-dump` ```bash brain-dump list [--priority now,soon] [--due] [--limit N] brain-dump add --text "..." --priority soon [--context "..."] -brain-dump edit [--text "..."] [--priority ...] [--context "..."] +brain-dump add --recurring --text "..." --frequency daily [--when evening] [--note "..."] [--context "..."] +brain-dump edit [--text "..."] [--priority|--frequency|--when|--note|--context "..."] brain-dump done brain-dump show brain-dump nudged ,,... -brain-dump recurring [--when evening] +brain-dump recurring ``` - Data: `memory/brain-dump.json` - `--due` filters by nudge interval: now=1d, soon=3d, someday=7d - `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 **Heartbeat workflow:** diff --git a/bin/brain-dump b/bin/brain-dump index 7394c08..2ef6364 100755 --- a/bin/brain-dump +++ b/bin/brain-dump @@ -41,29 +41,32 @@ function formatTask(t) { 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 --- function cmdList(args) { const data = load(); let tasks = data.tasks || []; - // Filter by priority const prioArg = getFlag(args, '--priority'); if (prioArg) { const prios = prioArg.split(',').map(s => s.trim()); tasks = tasks.filter(t => prios.includes(t.priority)); } - // Filter by due if (args.includes('--due')) { tasks = tasks.filter(isDue); } - // Sort: now > soon > someday const prioOrder = { now: 0, soon: 1, someday: 2 }; tasks.sort((a, b) => (prioOrder[a.priority] ?? 3) - (prioOrder[b.priority] ?? 3)); - // Limit const limitArg = getFlag(args, '--limit'); if (limitArg) { tasks = tasks.slice(0, parseInt(limitArg, 10)); @@ -80,43 +83,71 @@ function cmdList(args) { } function cmdAdd(args) { + const isRecurring = args.includes('--recurring'); const text = getFlag(args, '--text'); if (!text) { console.error('--text required'); process.exit(1); } - const priority = getFlag(args, '--priority') || 'soon'; const context = getFlag(args, '--context') || undefined; const data = load(); - 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}`); + + if (isRecurring) { + const frequency = getFlag(args, '--frequency') || 'daily'; + const when = getFlag(args, '--when') || undefined; + const note = getFlag(args, '--note') || undefined; + const item = { id: shortId(), text, frequency }; + if (when) item.when = when; + if (note) item.note = note; + if (context) item.context = context; + data.recurring = data.recurring || []; + 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) { const id = args[0]; - if (!id) { console.error('Usage: brain-dump edit [--text ...] [--priority ...] [--context ...]'); process.exit(1); } + if (!id) { console.error('Usage: brain-dump edit [--text ...] [--priority ...] [--context ...] [--frequency ...] [--when ...] [--note ...]'); process.exit(1); } 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 priority = getFlag(args, '--priority'); const context = getFlag(args, '--context'); + if (text) item.text = text; + if (context !== null && context !== undefined) item.context = context; - if (text) task.text = text; - if (priority) task.priority = priority; - if (context !== null && context !== undefined) task.context = context; - - save(data); - console.log(`Updated: ${formatTask(task)}`); + if (isRecurring) { + const frequency = getFlag(args, '--frequency'); + const when = getFlag(args, '--when'); + const note = getFlag(args, '--note'); + if (frequency) item.frequency = frequency; + 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) { @@ -124,12 +155,27 @@ function cmdDone(args) { if (!id) { console.error('Usage: brain-dump done '); process.exit(1); } 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]; - save(data); - console.log(`Done: ${removed.text}`); + // Check tasks + let idx = (data.tasks || []).findIndex(t => t.id === id); + 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) { @@ -137,10 +183,11 @@ function cmdShow(args) { if (!id) { console.error('Usage: brain-dump show '); process.exit(1); } const data = load(); - const task = (data.tasks || []).find(t => t.id === id); - if (!task) { console.error(`Task ${id} not found.`); process.exit(1); } + const item = (data.tasks || []).find(t => t.id === id) + || (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) { @@ -161,19 +208,15 @@ function cmdNudged(args) { console.log(`Marked ${count} task(s) as nudged.`); } -function cmdRecurring(args) { +function cmdRecurring() { const data = load(); - const when = getFlag(args, '--when'); - let items = data.recurring || []; - if (when) { - items = items.filter(r => r.when === when); - } + const items = data.recurring || []; if (items.length === 0) { console.log('No recurring items.'); return; } 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 'show': cmdShow(args); break; case 'nudged': cmdNudged(args); break; - case 'recurring': cmdRecurring(args); break; + case 'recurring': cmdRecurring(); break; default: console.log(`Usage: brain-dump Commands: list [--priority now,soon] [--due] [--limit N] add --text "..." --priority soon [--context "..."] - edit [--text "..."] [--priority ...] [--context "..."] + add --recurring --text "..." --frequency daily [--when evening] [--note "..."] [--context "..."] + edit [--text "..."] [--priority|--frequency|--when|--note|--context "..."] done show nudged ,,... - recurring [--when evening]`); + recurring`); } diff --git a/memory/brain-dump.json b/memory/brain-dump.json index d39c874..12dea42 100644 --- a/memory/brain-dump.json +++ b/memory/brain-dump.json @@ -2,7 +2,7 @@ "description": "Task tracking — auto-captured from chat or manually added. Done tasks get deleted.", "recurring": [ { - "id": "nose-shower", + "id": "843efabf", "text": "Nose shower 👃🚿", "frequency": "daily", "when": "evening",