@pingvinen/donna-assistant 0.7.0 → 0.8.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 +1 -0
- package/package.json +1 -1
- package/src/installer.cjs +1 -1
- package/stubs/claude-code/donna/focus.md +16 -0
- package/workflows/focus.md +317 -0
package/README.md
CHANGED
|
@@ -141,6 +141,7 @@ Most commands are safe to run again. Want to update your role? Run `/donna:set-r
|
|
|
141
141
|
| `/donna:relearn-tools` | Update CLI tool knowledge after upgrades |
|
|
142
142
|
| `/donna:help` | Conversational troubleshooting for config, storage, or skill issues |
|
|
143
143
|
| `/donna:contribute-idea` | Submit a feature idea or bug report via GitHub Issues |
|
|
144
|
+
| `/donna:focus` | Distill today's tasks into a short prioritized focus list |
|
|
144
145
|
|
|
145
146
|
## License
|
|
146
147
|
|
package/package.json
CHANGED
package/src/installer.cjs
CHANGED
|
@@ -79,7 +79,7 @@ async function run(options = {}) {
|
|
|
79
79
|
for (const provider of detected) {
|
|
80
80
|
fs.cpSync(provider.stubSource, provider.stubTarget, { recursive: true });
|
|
81
81
|
output.success(
|
|
82
|
-
`Copied donna skills (setup, add-task, done, set-role, begin-the-day, add-tool, relearn-tools, run-tools, help, contribute-idea, adjust-tool) to ${provider.stubTarget}`,
|
|
82
|
+
`Copied donna skills (setup, add-task, done, set-role, begin-the-day, add-tool, relearn-tools, run-tools, help, contribute-idea, adjust-tool, focus) to ${provider.stubTarget}`,
|
|
83
83
|
);
|
|
84
84
|
}
|
|
85
85
|
} else {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: donna:focus
|
|
3
|
+
description: Distill today's tasks into a short prioritized focus list
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Write
|
|
7
|
+
- Bash
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<objective>
|
|
11
|
+
Run the Donna focus workflow.
|
|
12
|
+
</objective>
|
|
13
|
+
|
|
14
|
+
<execution_context>
|
|
15
|
+
@~/.donna/workflows/focus.md
|
|
16
|
+
</execution_context>
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# Donna Focus Workflow
|
|
2
|
+
|
|
3
|
+
<objective>
|
|
4
|
+
Read today's daily file, score open tasks on urgency and context signals, optionally re-query active tools for enriched data, and produce a short prioritized focus list written to daily/focus.md and printed to the terminal. This is a read-only operation relative to the daily file: only focus.md is written.
|
|
5
|
+
</objective>
|
|
6
|
+
|
|
7
|
+
<step name="read-config">
|
|
8
|
+
Read `~/.config/donna/config.md`.
|
|
9
|
+
|
|
10
|
+
If the file does not exist, print:
|
|
11
|
+
```
|
|
12
|
+
✗ Donna is not configured. Run /donna:setup first.
|
|
13
|
+
```
|
|
14
|
+
Stop.
|
|
15
|
+
|
|
16
|
+
Extract the `storage_repo`, `daily_folder` (default: `daily`), and `auto_push` (default: false) fields from the YAML frontmatter.
|
|
17
|
+
|
|
18
|
+
**Obsidian sync:** Check if `<storage_repo>/.obsidian/daily-notes.json` exists.
|
|
19
|
+
- If it exists and has a `folder` field that differs from `<daily_folder>`: update `<daily_folder>` to match Obsidian's value, and update `~/.config/donna/config.md` with the new `daily_folder`. Print `✓ Synced daily folder with Obsidian: <daily_folder>`.
|
|
20
|
+
- If `<storage_repo>/.obsidian/` exists but `daily-notes.json` does not exist or has no `folder` field: write `<storage_repo>/.obsidian/daily-notes.json` with `{"folder":"<daily_folder>"}`. Print `✓ Configured Obsidian daily notes to use <daily_folder>/`.
|
|
21
|
+
- Otherwise: do nothing.
|
|
22
|
+
</step>
|
|
23
|
+
|
|
24
|
+
<step name="check-pending-migrations">
|
|
25
|
+
Read `~/.donna/state.md` with the Read tool. If the file does not exist or has no `pending_migrations` field in its YAML frontmatter, skip this step.
|
|
26
|
+
|
|
27
|
+
For each entry in `pending_migrations`:
|
|
28
|
+
|
|
29
|
+
**`move-standing-files`:** Move standing files from storage repo root to donna/ subfolder.
|
|
30
|
+
|
|
31
|
+
Run via Bash:
|
|
32
|
+
```bash
|
|
33
|
+
STORAGE_REPO="<storage_repo>"
|
|
34
|
+
DONNA_DIR="$STORAGE_REPO/donna"
|
|
35
|
+
MOVED=0
|
|
36
|
+
|
|
37
|
+
mkdir -p "$DONNA_DIR"
|
|
38
|
+
for FILE in role.md recurring.md role-research.md; do
|
|
39
|
+
if [ -f "$STORAGE_REPO/$FILE" ] && [ ! -f "$DONNA_DIR/$FILE" ]; then
|
|
40
|
+
mv "$STORAGE_REPO/$FILE" "$DONNA_DIR/$FILE"
|
|
41
|
+
echo "Moved $FILE to donna/$FILE"
|
|
42
|
+
MOVED=$((MOVED + 1))
|
|
43
|
+
fi
|
|
44
|
+
done
|
|
45
|
+
|
|
46
|
+
echo "MOVED=$MOVED"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
If MOVED > 0, commit the move:
|
|
50
|
+
```bash
|
|
51
|
+
git -C <storage_repo> add -A
|
|
52
|
+
git -C <storage_repo> diff --cached --quiet || git -C <storage_repo> commit -m "donna(migrate): move standing files to donna/ subfolder"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If `auto_push` is true in config, also push.
|
|
56
|
+
|
|
57
|
+
**`backfill-tool-type`:** Backfill `type` on existing tool sections in tools.md using heuristic detection.
|
|
58
|
+
|
|
59
|
+
Read `<storage_repo>/donna/tools.md` with the Read tool. If the file does not exist or has no tool sections, skip this handler.
|
|
60
|
+
|
|
61
|
+
For each tool section (starting with `## <tool_name>`), check if a `- type:` line already exists. If the `- type:` line is missing, detect the correct type:
|
|
62
|
+
|
|
63
|
+
1. If the tool section contains a `- command:` line where the value starts with `mcp:` (e.g., `- command: mcp:linear`), insert `- type: mcp` immediately after the `- command:` line.
|
|
64
|
+
2. Else, if the tool section contains a `- base_url:` line:
|
|
65
|
+
- If the capabilities section contains entries that look like GraphQL queries (contain `query {` or `mutation {`), insert `- type: graphql` immediately after `## <tool_name>` (REST/GraphQL tools have no `- command:` line).
|
|
66
|
+
- Otherwise, insert `- type: rest` immediately after `## <tool_name>`.
|
|
67
|
+
3. Else (no `mcp:` prefix, no `base_url` field), insert `- type: cli` immediately after the `- command:` line.
|
|
68
|
+
|
|
69
|
+
Write the updated file back with the Write tool. If any changes were made, commit:
|
|
70
|
+
```bash
|
|
71
|
+
git -C <storage_repo> add -A
|
|
72
|
+
git -C <storage_repo> diff --cached --quiet || git -C <storage_repo> commit -m "donna(migrate): backfill tool types on existing tools"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
If `auto_push` is true in config, also push.
|
|
76
|
+
|
|
77
|
+
After processing all pending migrations, update `~/.donna/state.md` with the Write tool: remove the completed entries from `pending_migrations`. If no entries remain, write:
|
|
78
|
+
```markdown
|
|
79
|
+
---
|
|
80
|
+
pending_migrations: []
|
|
81
|
+
---
|
|
82
|
+
```
|
|
83
|
+
</step>
|
|
84
|
+
|
|
85
|
+
<step name="read-daily-file">
|
|
86
|
+
Get today's date via Bash:
|
|
87
|
+
```bash
|
|
88
|
+
date +%Y-%m-%d
|
|
89
|
+
```
|
|
90
|
+
Store as `<today>`.
|
|
91
|
+
|
|
92
|
+
Construct the daily file path: `<storage_repo>/<daily_folder>/<today>.md`.
|
|
93
|
+
|
|
94
|
+
Read the daily file with the Read tool. If the file does not exist, print:
|
|
95
|
+
```
|
|
96
|
+
✗ No daily file for today. Run /donna:begin-the-day first.
|
|
97
|
+
```
|
|
98
|
+
Stop.
|
|
99
|
+
|
|
100
|
+
Store the file content as `<daily_content>`.
|
|
101
|
+
</step>
|
|
102
|
+
|
|
103
|
+
<step name="parse-open-tasks">
|
|
104
|
+
Extract all lines from `<daily_content>` matching `- [ ] ` (open tasks only — do NOT include closed `- [x]` tasks per D-12).
|
|
105
|
+
|
|
106
|
+
Store as `<open_tasks>` list. Count the total number of open items as `<total_open_count>` (used for the footer per D-18).
|
|
107
|
+
|
|
108
|
+
For each open task line, parse the following components:
|
|
109
|
+
- **Tool tag:** leading `(<tool_tag>) ` if present — regex `\(\w+\) ` appearing after `- [ ] `
|
|
110
|
+
- **Carry-forward count:** trailing ` (N times)` suffix where N is an integer >= 1. If present, extract N. If absent, this item is "new today" (D-11 freshness signal).
|
|
111
|
+
- **URL/identifier:** trailing ` [<text>](<url>)` link pattern
|
|
112
|
+
- **Description text:** everything between the tool tag (if any) and the trailing suffixes
|
|
113
|
+
|
|
114
|
+
For scoring purposes, classify each item:
|
|
115
|
+
- Has urgency keyword (case-insensitive scan of description + tool tag): "due today", "due tomorrow", "blocking", "urgent", "ASAP" → urgency_signal = HIGH
|
|
116
|
+
- Has `(N times)` with N >= 5 → chronic_neglect_signal = HIGH
|
|
117
|
+
- Has `(N times)` with 1 <= N < 5 → carry_signal = MEDIUM
|
|
118
|
+
- Has no `(N times)` suffix → freshness_signal = MILD (new today)
|
|
119
|
+
|
|
120
|
+
Store the parsed open tasks as `<open_tasks>` — each entry retaining the full original line plus parsed components.
|
|
121
|
+
</step>
|
|
122
|
+
|
|
123
|
+
<step name="enrich-from-tools">
|
|
124
|
+
Collect the unique tool tags from `<open_tasks>` (e.g., `gh`, `jira`). If no tool tags are present in any open task, skip this step and set `<enriched_data>` to an empty map.
|
|
125
|
+
|
|
126
|
+
Read `<storage_repo>/donna/tools.md` with the Read tool. If the file does not exist, skip this step (tools are optional).
|
|
127
|
+
|
|
128
|
+
For each unique tool tag found in `<open_tasks>`, find the matching `## <tool_name>` section in tools.md where `<tool_name>` matches the tag. If no matching section is found, skip that tool.
|
|
129
|
+
|
|
130
|
+
For each matched tool, extract:
|
|
131
|
+
- `type` field (default `cli` if absent)
|
|
132
|
+
- `command` field (for cli tools)
|
|
133
|
+
- `base_url`, `auth_header`, `auth_secret` fields (for rest/graphql tools)
|
|
134
|
+
- Capabilities list under `### Capabilities`
|
|
135
|
+
|
|
136
|
+
**If only one tool tag is found**, run it directly (no Task spawning needed) using the type-aware execution logic below.
|
|
137
|
+
|
|
138
|
+
**If multiple tool tags are found**, spawn one Task agent per tool. Each agent receives:
|
|
139
|
+
- The tool name, type, and its capabilities list
|
|
140
|
+
- For REST/GraphQL tools: the base_url, auth_header, and auth_secret fields
|
|
141
|
+
- For MCP tools: the capability names with mcp: prefix
|
|
142
|
+
- Instructions to execute all capabilities and return results as a structured list
|
|
143
|
+
- Instructions to NEVER write to any file or run git commands
|
|
144
|
+
|
|
145
|
+
**CRITICAL constraints for Task agents:**
|
|
146
|
+
- Agents return raw task lists and enrichment data ONLY
|
|
147
|
+
- Agents must NOT write to any file (no Write tool calls)
|
|
148
|
+
- Agents must NOT run git commands (SSH signing constraint from CLAUDE.md)
|
|
149
|
+
- DO NOT run git commands
|
|
150
|
+
- All file writing happens in the main workflow after agents return
|
|
151
|
+
|
|
152
|
+
**Global timeout:** Wait for all Task agents to complete, up to 2 minutes total. After 2 minutes, collect whatever results have been returned and treat non-responding tools as failed with warning: `! <tool_name>: timed out (2-minute batch limit)`.
|
|
153
|
+
|
|
154
|
+
**Type-aware execution within each agent (or direct execution for single tool):**
|
|
155
|
+
|
|
156
|
+
For `type: cli` capabilities (format: `<name>: <cli_invocation>`):
|
|
157
|
+
```bash
|
|
158
|
+
timeout 10 <cli_invocation> 2>&1
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
For `type: rest` capabilities (format: `<name>: <METHOD> /path`):
|
|
162
|
+
1. Read `<storage_repo>/donna/secrets.md` with the Read tool. Parse key-value pairs from under the frontmatter.
|
|
163
|
+
2. Resolve the `auth_secret` key to get the actual secret value. If the key is not found in secrets.md or the value is `REPLACE_WITH_YOUR_SECRET`, add warning `! <tool_name>: missing secret <auth_secret> — edit donna/secrets.md` and skip this tool.
|
|
164
|
+
3. For each capability, run via Bash with a 10-second timeout:
|
|
165
|
+
```bash
|
|
166
|
+
timeout 10 curl -s -H "<auth_header>: <resolved_secret>" "<base_url><path>" 2>&1
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
For `type: graphql` capabilities (format: `<name>: <graphql_query>`):
|
|
170
|
+
1. Same secrets resolution as REST.
|
|
171
|
+
2. For each capability, run via Bash with a 10-second timeout:
|
|
172
|
+
```bash
|
|
173
|
+
timeout 10 curl -s -X POST -H "<auth_header>: <resolved_secret>" -H "Content-Type: application/json" -d '{"query":"<graphql_query>"}' "<base_url>" 2>&1
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
For `type: mcp` capabilities (format: `<name>: mcp:<server>/<tool>`):
|
|
177
|
+
1. Invoke the MCP tool directly using Claude's native MCP tool invocation (NOT via Bash).
|
|
178
|
+
|
|
179
|
+
**On any tool failure (exit non-zero, timeout, missing secret):** Log warning `! <tool_name>: <error_description>`, continue with text-only signals for that tool's items (D-15 graceful fallback). Never retry.
|
|
180
|
+
|
|
181
|
+
Store enriched results as `<enriched_data>`: a map keyed by tool tag, containing the fresh task list and any status metadata returned (PR review state, Jira status, etc.).
|
|
182
|
+
Collect all warning messages as `<tool_warnings>`.
|
|
183
|
+
</step>
|
|
184
|
+
|
|
185
|
+
<step name="score-and-rank">
|
|
186
|
+
Apply priority signals to each open task in `<open_tasks>` (per D-08 through D-12):
|
|
187
|
+
|
|
188
|
+
**Text-analysis signals (always applied):**
|
|
189
|
+
|
|
190
|
+
1. **Urgency keywords (D-08, HIGH signal):** Scan the full task line (case-insensitive) for: "due today", "due tomorrow", "blocking", "urgent", "ASAP". Any match elevates this item to the top tier.
|
|
191
|
+
|
|
192
|
+
2. **Chronic neglect (D-09, HIGH signal):** Items with `(N times)` where N >= 5 have been ignored repeatedly — elevated priority. These are chronically neglected tasks that demand attention.
|
|
193
|
+
|
|
194
|
+
3. **Carry-forward (D-09, MEDIUM signal):** Items with `(N times)` where 1 <= N < 5 have been carried forward — moderate priority increase based on how long they've been open.
|
|
195
|
+
|
|
196
|
+
4. **Freshness (D-11, MILD signal):** Items WITHOUT a `(N times)` suffix are new today. Mild positive signal — they are fresh and haven't been neglected yet.
|
|
197
|
+
|
|
198
|
+
5. **Open state (D-12):** Already filtered in the parse step — only open items reach scoring.
|
|
199
|
+
|
|
200
|
+
**Tool enrichment signals (D-14, applied when `<enriched_data>` is available):**
|
|
201
|
+
|
|
202
|
+
For each open task with a tool tag, look up the corresponding item in `<enriched_data>`:
|
|
203
|
+
- PR with review-requested status: elevated priority (action needed from user)
|
|
204
|
+
- PR with changes-requested: elevated priority (blocking the PR author)
|
|
205
|
+
- PR that is mergeable/approved: moderate signal (quick win)
|
|
206
|
+
- Jira item "In Progress": moderate signal (active work)
|
|
207
|
+
- Jira item "Blocked": elevated priority
|
|
208
|
+
- Any status indicating action is needed from the user: elevated priority
|
|
209
|
+
|
|
210
|
+
**Ranking:**
|
|
211
|
+
|
|
212
|
+
Claude selects 3–8 items dynamically based on the urgency distribution (D-17):
|
|
213
|
+
- On a quiet day with few urgent items: show 3–4 items
|
|
214
|
+
- On a busy day with many urgent items: show up to 8 items
|
|
215
|
+
- The goal is a focused, actionable list — not a comprehensive one
|
|
216
|
+
|
|
217
|
+
Produce `<focus_items>` as an ordered list. Each item includes:
|
|
218
|
+
- The original task description (clean, without state prefix)
|
|
219
|
+
- A reason tag explaining why it was prioritized (e.g., "due today", "review requested", "urgent", "carried 8 times", "new today", "blocking")
|
|
220
|
+
|
|
221
|
+
The count of items NOT included in the focus list is: `<other_count>` = `<total_open_count>` - count of `<focus_items>`.
|
|
222
|
+
</step>
|
|
223
|
+
|
|
224
|
+
<step name="write-focus-file">
|
|
225
|
+
Get the current time via Bash:
|
|
226
|
+
```bash
|
|
227
|
+
date +%H:%M
|
|
228
|
+
```
|
|
229
|
+
Store as `<generated_time>`.
|
|
230
|
+
|
|
231
|
+
Write to `<storage_repo>/<daily_folder>/focus.md` with the Write tool (D-04, D-06, D-07). The file is overwritten entirely each run.
|
|
232
|
+
|
|
233
|
+
File content format:
|
|
234
|
+
```markdown
|
|
235
|
+
---
|
|
236
|
+
date: <today>
|
|
237
|
+
generated: <generated_time>
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Focus (<today>, <generated_time>)
|
|
241
|
+
|
|
242
|
+
1. <item description> — <reason tag>
|
|
243
|
+
2. <item description> — <reason tag>
|
|
244
|
+
...
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
<other_count> other items in today's file
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
CRITICAL: Only write to `<storage_repo>/<daily_folder>/focus.md`. NEVER modify the daily file `<storage_repo>/<daily_folder>/<today>.md`.
|
|
251
|
+
|
|
252
|
+
If there are tool warnings from `<tool_warnings>`, append them after the footer:
|
|
253
|
+
```markdown
|
|
254
|
+
---
|
|
255
|
+
<other_count> other items in today's file
|
|
256
|
+
|
|
257
|
+
## Warnings
|
|
258
|
+
! <tool_name>: <warning>
|
|
259
|
+
```
|
|
260
|
+
</step>
|
|
261
|
+
|
|
262
|
+
<step name="git-commit">
|
|
263
|
+
Run via Bash:
|
|
264
|
+
```bash
|
|
265
|
+
git -C <storage_repo> add -A
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Check whether there is anything to commit:
|
|
269
|
+
```bash
|
|
270
|
+
git -C <storage_repo> status --porcelain
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
If the output is empty, skip the commit and continue.
|
|
274
|
+
|
|
275
|
+
Otherwise, run:
|
|
276
|
+
```bash
|
|
277
|
+
git -C <storage_repo> commit -m "donna(focus): focus list for <today>"
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
If `auto_push` is true in config, also run:
|
|
281
|
+
```bash
|
|
282
|
+
git -C <storage_repo> push
|
|
283
|
+
```
|
|
284
|
+
</step>
|
|
285
|
+
|
|
286
|
+
<step name="print-focus">
|
|
287
|
+
Print to the terminal with banner, following the begin-the-day pattern:
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
══════════════════════════════════════
|
|
291
|
+
Donna — Focus for <today>
|
|
292
|
+
══════════════════════════════════════
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Then print each focus item numbered, with reason tag:
|
|
296
|
+
```
|
|
297
|
+
1. <item description> — <reason tag>
|
|
298
|
+
2. <item description> — <reason tag>
|
|
299
|
+
...
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Then print the footer:
|
|
303
|
+
```
|
|
304
|
+
---
|
|
305
|
+
<other_count> other items in today's file
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
If there are tool warnings from `<tool_warnings>`, print each warning:
|
|
309
|
+
```
|
|
310
|
+
! <tool_name>: <warning>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
End with the closing banner line:
|
|
314
|
+
```
|
|
315
|
+
══════════════════════════════════════
|
|
316
|
+
```
|
|
317
|
+
</step>
|