@tekmidian/pai 0.12.2 → 0.13.1
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/dist/cli/index.mjs +2 -2
- package/dist/cli/program.d.mts.map +1 -1
- package/dist/cli/program.mjs +3 -2
- package/dist/cli/program.mjs.map +1 -1
- package/dist/{config-BuhHWyOK.mjs → config-C8m-tPhP.mjs} +22 -2
- package/dist/config-C8m-tPhP.mjs.map +1 -0
- package/dist/daemon/index.mjs +2 -2
- package/dist/{daemon-Ca7YXHUW.mjs → daemon-D2aKb4mJ.mjs} +2 -2
- package/dist/{daemon-Ca7YXHUW.mjs.map → daemon-D2aKb4mJ.mjs.map} +1 -1
- package/dist/daemon-mcp/index.mjs +581 -2
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/{pick-C5sUQ5g_.mjs → pick-B0A-8Tfw.mjs} +1100 -445
- package/dist/pick-B0A-8Tfw.mjs.map +1 -0
- package/dist/skills/Tasks/SKILL.md +101 -0
- package/docs/commands/README.md +6 -0
- package/docs/commands/backup.md +1 -1
- package/docs/commands/clear-names.md +1 -1
- package/docs/commands/daemon.md +1 -1
- package/docs/commands/db.md +1 -1
- package/docs/commands/end.md +1 -1
- package/docs/commands/help.md +1 -1
- package/docs/commands/kg.md +1 -1
- package/docs/commands/mcp.md +1 -1
- package/docs/commands/memory.md +1 -1
- package/docs/commands/notify.md +1 -1
- package/docs/commands/observation.md +1 -1
- package/docs/commands/obsidian.md +1 -1
- package/docs/commands/pause.md +1 -1
- package/docs/commands/project.md +1 -1
- package/docs/commands/projects.md +1 -1
- package/docs/commands/registry.md +1 -1
- package/docs/commands/restore.md +1 -1
- package/docs/commands/sessions.md +1 -1
- package/docs/commands/setup.md +1 -1
- package/docs/commands/shell-init.md +1 -1
- package/docs/commands/skill.md +1 -1
- package/docs/commands/task.md +90 -0
- package/docs/commands/topic.md +1 -1
- package/docs/commands/update.md +1 -1
- package/docs/commands/zettel.md +1 -1
- package/package.json +1 -1
- package/plugins/productivity/plugin.json +2 -2
- package/plugins/productivity/skills/Tasks/SKILL.md +126 -0
- package/dist/config-BuhHWyOK.mjs.map +0 -1
- package/dist/pick-C5sUQ5g_.mjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as PaiClient } from "../ipc-client-CoyUHPod.mjs";
|
|
3
|
-
import { o as loadConfig } from "../config-
|
|
3
|
+
import { o as loadConfig } from "../config-C8m-tPhP.mjs";
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
6
|
|
|
@@ -3767,6 +3767,580 @@ USE WHEN user says 'trace idea', 'how did X evolve', 'history of X in notes', 'w
|
|
|
3767
3767
|
Builds a chronological timeline of how an idea first appeared and evolved across vault notes. Extracts relevant excerpts. Identifies inflection points where framing shifted. Summarizes the evolution arc (first appearance → development → current state).`
|
|
3768
3768
|
};
|
|
3769
3769
|
|
|
3770
|
+
//#endregion
|
|
3771
|
+
//#region src/daemon-mcp/prompts/reconstruct.ts
|
|
3772
|
+
const reconstruct = {
|
|
3773
|
+
description: "Retroactively create session notes from JSONL transcripts and git history when automatic capture failed or was incomplete",
|
|
3774
|
+
content: `## Reconstruct Skill
|
|
3775
|
+
|
|
3776
|
+
USE WHEN user says 'reconstruct sessions', 'rebuild session notes', 'recover session notes', 'retroactively create notes', 'create notes from git history', 'notes are missing', 'backfill session notes', 'reconstruct what we did', OR /reconstruct.
|
|
3777
|
+
|
|
3778
|
+
### What This Skill Does
|
|
3779
|
+
|
|
3780
|
+
Reconstructs session notes for a PAI-registered project by reading:
|
|
3781
|
+
1. Git commit history (authoritative record of what was built)
|
|
3782
|
+
2. JSONL transcripts (user messages reveal intent, decisions, and context)
|
|
3783
|
+
|
|
3784
|
+
Generates one session note per day (or per logical session if multiple sessions existed in a day), numbered sequentially from the highest existing note number.
|
|
3785
|
+
|
|
3786
|
+
**ONLY include what can be verified from git log and JSONL. Never invent or embellish content.**
|
|
3787
|
+
|
|
3788
|
+
---
|
|
3789
|
+
|
|
3790
|
+
### Arguments
|
|
3791
|
+
|
|
3792
|
+
| Argument | Default | Description |
|
|
3793
|
+
|----------|---------|-------------|
|
|
3794
|
+
| \`--days N\` | 7 | Reconstruct notes for the last N days |
|
|
3795
|
+
| \`--since YYYY-MM-DD\` | — | Reconstruct from this date forward |
|
|
3796
|
+
| \`--until YYYY-MM-DD\` | today | Reconstruct up to this date |
|
|
3797
|
+
| \`--dry-run\` | false | Show what would be created without writing files |
|
|
3798
|
+
| \`--commit\` | false | Git commit the created notes after writing |
|
|
3799
|
+
|
|
3800
|
+
---
|
|
3801
|
+
|
|
3802
|
+
### Pre-Action Check
|
|
3803
|
+
|
|
3804
|
+
Before starting, verify:
|
|
3805
|
+
|
|
3806
|
+
1. **Project is registered**: Run \`pai project detect\` (or \`pai project list\`) to confirm the current project is known to PAI and get its Notes directory path.
|
|
3807
|
+
2. **Notes directory exists**: The target directory should be \`Notes/YYYY/MM/\`. Create it if absent.
|
|
3808
|
+
3. **Find highest existing note number**: Scan all \`Notes/**/*.md\` files for the pattern \`^NNNN\` to find max note number. New notes continue from there.
|
|
3809
|
+
4. **NEVER overwrite existing notes**: If a note file already exists for that date/session, skip it and warn the user.
|
|
3810
|
+
|
|
3811
|
+
---
|
|
3812
|
+
|
|
3813
|
+
### Step 1 — Find JSONL Files
|
|
3814
|
+
|
|
3815
|
+
Claude Code encodes project paths lossily: \`/\`, spaces, dots, hyphens all become \`-\`. A project may have been accessed from multiple base directories (e.g., \`~/Daten/Cloud/Development/ai/PAI\` and \`~/dev/ai/PAI\` both encode to different paths).
|
|
3816
|
+
|
|
3817
|
+
**Search strategy — use glob patterns, not exact paths:**
|
|
3818
|
+
|
|
3819
|
+
\`\`\`bash
|
|
3820
|
+
# Find all encoded project directories that might match this project
|
|
3821
|
+
ls ~/.claude/projects/ | grep -i "<project-slug-fragment>"
|
|
3822
|
+
|
|
3823
|
+
# For each candidate, look for JSONL files
|
|
3824
|
+
ls ~/.claude/projects/<encoded-path>/*.jsonl 2>/dev/null
|
|
3825
|
+
|
|
3826
|
+
# Also check the dev copy if the project has one
|
|
3827
|
+
# Example: if cwd is ~/dev/ai/PAI, also check ~/Daten/Cloud/Development/ai/PAI encoding
|
|
3828
|
+
\`\`\`
|
|
3829
|
+
|
|
3830
|
+
Collect ALL JSONL files from ALL matching encoded paths. A session may have been started from either location.
|
|
3831
|
+
|
|
3832
|
+
---
|
|
3833
|
+
|
|
3834
|
+
### Step 2 — Determine Time Range
|
|
3835
|
+
|
|
3836
|
+
Calculate the date range from arguments:
|
|
3837
|
+
- \`--days 7\` → from (today - 7 days) to today
|
|
3838
|
+
- \`--since 2026-03-01\` → from that date to today (or --until date)
|
|
3839
|
+
- Default: last 7 days
|
|
3840
|
+
|
|
3841
|
+
---
|
|
3842
|
+
|
|
3843
|
+
### Step 3 — Extract Git History
|
|
3844
|
+
|
|
3845
|
+
For each day in the range:
|
|
3846
|
+
|
|
3847
|
+
\`\`\`bash
|
|
3848
|
+
git -C <project-dir> log \\
|
|
3849
|
+
--after="YYYY-MM-DD 00:00:00" \\
|
|
3850
|
+
--before="YYYY-MM-DD 23:59:59" \\
|
|
3851
|
+
--format="%H|%ad|%s" \\
|
|
3852
|
+
--date=short \\
|
|
3853
|
+
--stat
|
|
3854
|
+
\`\`\`
|
|
3855
|
+
|
|
3856
|
+
Group commits by day. If no commits on a day, skip that day (no note to reconstruct).
|
|
3857
|
+
|
|
3858
|
+
Also capture:
|
|
3859
|
+
- Files changed per commit (\`--stat\`)
|
|
3860
|
+
- Author date (not committer date) for accurate day grouping
|
|
3861
|
+
|
|
3862
|
+
---
|
|
3863
|
+
|
|
3864
|
+
### Step 4 — Extract User Messages from JSONL
|
|
3865
|
+
|
|
3866
|
+
For each JSONL file, parse messages where \`type == "user"\` AND \`message.role == "user"\`:
|
|
3867
|
+
|
|
3868
|
+
\`\`\`
|
|
3869
|
+
Each line is a JSON object. Look for:
|
|
3870
|
+
{
|
|
3871
|
+
"type": "user",
|
|
3872
|
+
"message": {
|
|
3873
|
+
"role": "user",
|
|
3874
|
+
"content": "..." | [{"type": "text", "text": "..."}]
|
|
3875
|
+
},
|
|
3876
|
+
"timestamp": "2026-03-15T10:23:45.000Z"
|
|
3877
|
+
}
|
|
3878
|
+
\`\`\`
|
|
3879
|
+
|
|
3880
|
+
Filter messages by timestamp to match the day being reconstructed.
|
|
3881
|
+
|
|
3882
|
+
Extract:
|
|
3883
|
+
- The text content of user messages (ignore tool_result entries)
|
|
3884
|
+
- Timestamps for ordering
|
|
3885
|
+
- Session ID (\`sessionId\` field) to group messages per session
|
|
3886
|
+
|
|
3887
|
+
**SKIP** messages that are:
|
|
3888
|
+
- Tool results (\`content\` is array with \`type: "tool_result"\`)
|
|
3889
|
+
- System-generated (very short single-word messages like "go", "continue")
|
|
3890
|
+
- Pure confirmations ("yes", "ok", "sounds good")
|
|
3891
|
+
|
|
3892
|
+
**KEEP** messages that reveal:
|
|
3893
|
+
- Intent ("build a feature that...", "I need X to do Y")
|
|
3894
|
+
- Decisions ("let's use approach A instead of B")
|
|
3895
|
+
- Architectural choices
|
|
3896
|
+
- Problem descriptions
|
|
3897
|
+
- Requirements changes
|
|
3898
|
+
|
|
3899
|
+
---
|
|
3900
|
+
|
|
3901
|
+
### Step 5 — Identify Logical Sessions
|
|
3902
|
+
|
|
3903
|
+
A "logical session" is a continuous work block. Use these signals to split a day into multiple sessions:
|
|
3904
|
+
- Gap of more than 3 hours between messages
|
|
3905
|
+
- Different JSONL session IDs with significant time gaps
|
|
3906
|
+
- Commits with clearly different themes separated by time
|
|
3907
|
+
|
|
3908
|
+
If only one logical session exists for a day, create one note. If multiple exist, create one note per session with a suffix: \`NNNN - YYYY-MM-DD - Title.md\`, \`NNNN+1 - YYYY-MM-DD - Title (2).md\`.
|
|
3909
|
+
|
|
3910
|
+
---
|
|
3911
|
+
|
|
3912
|
+
### Step 6 — Generate Note Title
|
|
3913
|
+
|
|
3914
|
+
The note title comes from synthesizing git commits for that session:
|
|
3915
|
+
- If commits share a theme: use that theme ("Implement vault indexer")
|
|
3916
|
+
- If commits are varied: use the primary/largest change ("Refactor session notes + misc fixes")
|
|
3917
|
+
- Use the conventional commit prefix if present: "feat: Add dark mode" → "Add Dark Mode"
|
|
3918
|
+
- Title should be 3-7 words, title-case
|
|
3919
|
+
|
|
3920
|
+
---
|
|
3921
|
+
|
|
3922
|
+
### Step 7 — Write the Note
|
|
3923
|
+
|
|
3924
|
+
**Note filename format:** \`NNNN - YYYY-MM-DD - Title.md\`
|
|
3925
|
+
|
|
3926
|
+
**Path:** \`Notes/YYYY/MM/NNNN - YYYY-MM-DD - Title.md\`
|
|
3927
|
+
|
|
3928
|
+
**Content template:**
|
|
3929
|
+
|
|
3930
|
+
\`\`\`markdown
|
|
3931
|
+
# Session: [Title]
|
|
3932
|
+
|
|
3933
|
+
**Date:** YYYY-MM-DD
|
|
3934
|
+
**Status:** Completed
|
|
3935
|
+
**Reconstructed:** true (from JSONL + git history)
|
|
3936
|
+
|
|
3937
|
+
---
|
|
3938
|
+
|
|
3939
|
+
## Work Done
|
|
3940
|
+
|
|
3941
|
+
[Group related commits into logical sections by theme/component, not by commit order.
|
|
3942
|
+
Each section describes WHAT was built and WHY, derived from commit messages and user messages.
|
|
3943
|
+
Use present-tense descriptions: "Add X", "Fix Y", "Refactor Z".]
|
|
3944
|
+
|
|
3945
|
+
## Key Decisions
|
|
3946
|
+
|
|
3947
|
+
[Architectural choices, technology selections, approach changes.
|
|
3948
|
+
ONLY include decisions that are explicitly stated in user messages or strongly implied by commit message changes (e.g., a series of "revert" commits followed by a new approach).
|
|
3949
|
+
Format as bullet points.]
|
|
3950
|
+
|
|
3951
|
+
## Known Issues at End of Session
|
|
3952
|
+
|
|
3953
|
+
[Bugs discovered, things left unfinished.
|
|
3954
|
+
Derive from: last commits in session (if they add TODOs or fix-me comments), user messages mentioning problems, or explicit "not done yet" statements.
|
|
3955
|
+
Omit this section if nothing can be verified.]
|
|
3956
|
+
|
|
3957
|
+
---
|
|
3958
|
+
|
|
3959
|
+
**Tags:** #[project-slug] #reconstructed
|
|
3960
|
+
\`\`\`
|
|
3961
|
+
|
|
3962
|
+
**Filling rules:**
|
|
3963
|
+
- Work Done: Always present (use commits as primary source)
|
|
3964
|
+
- Key Decisions: Only if verifiable from user messages or commit patterns
|
|
3965
|
+
- Known Issues: Only if verifiable; omit section entirely if nothing found
|
|
3966
|
+
- Tags: Use the PAI project slug from \`pai project detect\`
|
|
3967
|
+
|
|
3968
|
+
---
|
|
3969
|
+
|
|
3970
|
+
### Step 8 — Output Summary
|
|
3971
|
+
|
|
3972
|
+
After writing (or dry-run preview):
|
|
3973
|
+
|
|
3974
|
+
\`\`\`
|
|
3975
|
+
Reconstructed N session notes:
|
|
3976
|
+
0042 - 2026-03-13 - Implement Reranker → Notes/2026/03/
|
|
3977
|
+
0043 - 2026-03-14 - Add Recency Boost → Notes/2026/03/
|
|
3978
|
+
0044 - 2026-03-15 - Zettelkasten Schema Update → Notes/2026/03/
|
|
3979
|
+
|
|
3980
|
+
Skipped: 2026-03-12 (no commits)
|
|
3981
|
+
Skipped: 2026-03-16 (note already exists: 0041 - 2026-03-16 - ...)
|
|
3982
|
+
\`\`\`
|
|
3983
|
+
|
|
3984
|
+
If \`--commit\` was passed:
|
|
3985
|
+
\`\`\`bash
|
|
3986
|
+
git add Notes/
|
|
3987
|
+
git commit -m "docs: reconstruct session notes for YYYY-MM-DD to YYYY-MM-DD"
|
|
3988
|
+
\`\`\`
|
|
3989
|
+
|
|
3990
|
+
---
|
|
3991
|
+
|
|
3992
|
+
### Step 9 — Extract Knowledge Graph Triples
|
|
3993
|
+
|
|
3994
|
+
After reconstructing the session notes, extract structured facts as triples and add them to the temporal knowledge graph. This populates the KG with verifiable facts from the historical record so that future queries (\`kg_query\`, \`pai kg query\`) can answer questions about past decisions.
|
|
3995
|
+
|
|
3996
|
+
For each reconstructed note, call \`kg_add\` to store key facts. Examples of facts worth extracting:
|
|
3997
|
+
|
|
3998
|
+
- **Project decisions**: \`subject=<project>\`, \`predicate=decided_to\`, \`object=<decision>\`
|
|
3999
|
+
- **Version bumps**: \`subject=<project>\`, \`predicate=shipped_version\`, \`object=<version>\`
|
|
4000
|
+
- **Architectural choices**: \`subject=<component>\`, \`predicate=uses\`, \`object=<technology>\`
|
|
4001
|
+
- **Status changes**: \`subject=<project>\`, \`predicate=status\`, \`object=<current_state>\`
|
|
4002
|
+
- **Dependencies**: \`subject=<project>\`, \`predicate=depends_on\`, \`object=<library>\`
|
|
4003
|
+
- **Ownership / location**: \`subject=<file_or_module>\`, \`predicate=lives_at\`, \`object=<path>\`
|
|
4004
|
+
|
|
4005
|
+
**Procedure for each fact:**
|
|
4006
|
+
|
|
4007
|
+
1. Call \`kg_query\` first with the same \`(subject, predicate)\` to check if a fact already exists.
|
|
4008
|
+
2. If a new fact supersedes an old one (same subject + predicate, different object), call \`kg_invalidate\` on the old triple's id BEFORE adding the new one.
|
|
4009
|
+
3. Call \`kg_add\` with the new fact, setting \`source_session\` to the reconstructed note filename and \`confidence: "EXTRACTED"\`.
|
|
4010
|
+
|
|
4011
|
+
**Quality rules:**
|
|
4012
|
+
|
|
4013
|
+
- Only extract **atomic, verifiable facts** that can be traced back to a commit, a user message, or an explicit decision in the note.
|
|
4014
|
+
- Skip opinions, speculation ("seems like", "probably"), and aspirational statements ("we should").
|
|
4015
|
+
- Use \`snake_case\` predicates.
|
|
4016
|
+
- Maximum **15 triples per note** — pick the most important.
|
|
4017
|
+
- Never invent project names, versions, or paths. Copy them verbatim.
|
|
4018
|
+
|
|
4019
|
+
**Alternative (batch mode):** If reconstructing many notes at once, instead of calling \`kg_add\` interactively you may run \`pai kg backfill --project <slug>\` from the terminal after the notes are written. The backfill walks every note in \`Notes/YYYY/MM/\`, runs the same extractor the session-summary-worker uses, and is idempotent (state file at \`~/.config/pai/kg-backfill-state.json\`).
|
|
4020
|
+
|
|
4021
|
+
After extraction, append a one-line note to the summary output:
|
|
4022
|
+
\`\`\`
|
|
4023
|
+
KG: extracted N triples (M added, K superseded) across the reconstructed notes.
|
|
4024
|
+
\`\`\`
|
|
4025
|
+
|
|
4026
|
+
---
|
|
4027
|
+
|
|
4028
|
+
### Anti-Defaults
|
|
4029
|
+
|
|
4030
|
+
- **NEVER overwrite existing notes.** Skip silently, report in summary.
|
|
4031
|
+
- **NEVER invent content.** If a decision isn't in the JSONL or deducible from commits, leave it out.
|
|
4032
|
+
- **NEVER fabricate commit messages.** Copy them verbatim from git log.
|
|
4033
|
+
- **NEVER assume intent from assistant messages.** Only user messages reveal intent.
|
|
4034
|
+
- **NEVER add speculation.** "It appears that..." or "likely..." should not appear in notes.
|
|
4035
|
+
- **DO trim noise.** Skip trivial messages ("ok", "yes", "go") that add no signal.
|
|
4036
|
+
- **DO handle missing JSONL gracefully.** If no JSONL files found, generate notes from git only — mark the "Key Decisions" section as "Not available (no JSONL transcript found)".`
|
|
4037
|
+
};
|
|
4038
|
+
|
|
4039
|
+
//#endregion
|
|
4040
|
+
//#region src/daemon-mcp/prompts/whisper.ts
|
|
4041
|
+
const whisper = {
|
|
4042
|
+
description: "Manage whisper rules — persistent behavioral constraints injected on every prompt",
|
|
4043
|
+
content: `## Whisper Rules Management
|
|
4044
|
+
|
|
4045
|
+
USE WHEN user says 'whisper', 'add whisper rule', 'remove whisper rule', 'list whisper rules', 'show whisper rules', '/whisper', OR wants to manage persistent behavioral rules.
|
|
4046
|
+
|
|
4047
|
+
Manage the rules that PAI injects into every prompt via the whisper-rules hook.
|
|
4048
|
+
|
|
4049
|
+
Rules are stored in \`~/.claude/whisper-rules.md\` — one rule per line, plain text.
|
|
4050
|
+
The hook reads this file on every UserPromptSubmit and injects it as a \`<system-reminder>\`.
|
|
4051
|
+
Rules survive compaction, /clear, and session restarts.
|
|
4052
|
+
|
|
4053
|
+
### Usage
|
|
4054
|
+
|
|
4055
|
+
- \`/whisper\` — show current rules
|
|
4056
|
+
- \`/whisper add <rule>\` — add a new rule
|
|
4057
|
+
- \`/whisper remove <number>\` — remove rule by line number
|
|
4058
|
+
- \`/whisper list\` — list rules with line numbers
|
|
4059
|
+
- \`/whisper clear\` — remove all rules (with confirmation)
|
|
4060
|
+
|
|
4061
|
+
### Workflow
|
|
4062
|
+
|
|
4063
|
+
**Show current rules:**
|
|
4064
|
+
Read \`~/.claude/whisper-rules.md\` and display each rule with a line number.
|
|
4065
|
+
If the file doesn't exist, say "No whisper rules configured."
|
|
4066
|
+
|
|
4067
|
+
**Add a rule:**
|
|
4068
|
+
Append the rule as a new line to \`~/.claude/whisper-rules.md\`.
|
|
4069
|
+
Create the file if it doesn't exist.
|
|
4070
|
+
Do NOT add duplicate rules — check if a similar rule already exists.
|
|
4071
|
+
|
|
4072
|
+
**Remove a rule:**
|
|
4073
|
+
Read the file, remove the line at the given number, write the file back.
|
|
4074
|
+
Show the removed rule for confirmation.
|
|
4075
|
+
|
|
4076
|
+
**Clear all rules:**
|
|
4077
|
+
Ask for confirmation first ("This will remove all N rules. Confirm?").
|
|
4078
|
+
Only proceed if the user explicitly confirms.
|
|
4079
|
+
|
|
4080
|
+
### Important
|
|
4081
|
+
|
|
4082
|
+
- Rules should be short, imperative statements (1-2 lines max)
|
|
4083
|
+
- Every rule is injected on EVERY prompt — keep the list focused on truly critical rules
|
|
4084
|
+
- Too many rules dilute their effectiveness and waste tokens
|
|
4085
|
+
- The file does not exist by default — PAI ships the hook, the user adds their own rules
|
|
4086
|
+
- Rules are global (shared across all sessions and projects)
|
|
4087
|
+
`
|
|
4088
|
+
};
|
|
4089
|
+
|
|
4090
|
+
//#endregion
|
|
4091
|
+
//#region src/daemon-mcp/prompts/consolidate.ts
|
|
4092
|
+
const consolidate = {
|
|
4093
|
+
description: "Consolidate and clean up session notes — merge duplicates, fix titles, renumber sequentially",
|
|
4094
|
+
content: `## Consolidate Skill
|
|
4095
|
+
|
|
4096
|
+
USE WHEN user says 'consolidate notes', 'clean up notes', 'merge duplicate notes', 'fix session notes', 'deduplicate notes', '/consolidate', OR notes directory has duplicates or bad titles.
|
|
4097
|
+
|
|
4098
|
+
### What This Skill Does
|
|
4099
|
+
|
|
4100
|
+
Cleans up a project's session notes directory by:
|
|
4101
|
+
1. Finding duplicate/superseded notes (same topic, different compaction snapshots)
|
|
4102
|
+
2. Keeping the most complete version of each topic
|
|
4103
|
+
3. Fixing garbage titles (renaming files and H1 headings)
|
|
4104
|
+
4. Renumbering sequentially (0001, 0002, 0003...)
|
|
4105
|
+
5. Optionally committing the cleanup
|
|
4106
|
+
|
|
4107
|
+
### Arguments
|
|
4108
|
+
|
|
4109
|
+
- No args: consolidate current project
|
|
4110
|
+
- \`--project <slug>\`: consolidate a specific project
|
|
4111
|
+
- \`--dry-run\`: show what would change without modifying files
|
|
4112
|
+
|
|
4113
|
+
### Workflow
|
|
4114
|
+
|
|
4115
|
+
**Step 1: Find the notes directory**
|
|
4116
|
+
Use \`pai project detect\` to find the current project, then locate \`Notes/YYYY/MM/\` for the current month.
|
|
4117
|
+
|
|
4118
|
+
**Step 2: Inventory all notes**
|
|
4119
|
+
List all .md files in the month directory. For each note, read:
|
|
4120
|
+
- Filename (number, date, title)
|
|
4121
|
+
- H1 heading inside the file
|
|
4122
|
+
- Line count (proxy for completeness)
|
|
4123
|
+
- First 20 lines (to understand the topic)
|
|
4124
|
+
|
|
4125
|
+
**Step 3: Group by topic**
|
|
4126
|
+
Group notes that cover the same topic. Two notes are "same topic" if:
|
|
4127
|
+
- Their filenames are identical (except the number)
|
|
4128
|
+
- OR their H1 titles share >50% word overlap (Jaccard similarity)
|
|
4129
|
+
- OR one is a strict subset of the other (shorter note's content is contained in the longer one)
|
|
4130
|
+
|
|
4131
|
+
**Step 4: For each group, keep the best**
|
|
4132
|
+
- Keep the note with the most lines (most complete)
|
|
4133
|
+
- Delete the others
|
|
4134
|
+
- If the kept note has a bad title (garbage from user messages, too long, generic), rename it based on the H1 or the Focus/Work Done section
|
|
4135
|
+
|
|
4136
|
+
**Step 5: Renumber sequentially**
|
|
4137
|
+
After deduplication, renumber all remaining notes: 0001, 0002, 0003...
|
|
4138
|
+
Preserve the date and title in the filename.
|
|
4139
|
+
|
|
4140
|
+
**Step 6: Fix H1 headings**
|
|
4141
|
+
Ensure each note's H1 matches its filename title and number.
|
|
4142
|
+
|
|
4143
|
+
**Step 7: Report and optionally commit**
|
|
4144
|
+
Show what was done:
|
|
4145
|
+
- Notes deleted (with reason)
|
|
4146
|
+
- Notes renamed (old → new)
|
|
4147
|
+
- Notes renumbered
|
|
4148
|
+
Then ask if the user wants to commit: \`git add Notes/ && git commit -m "docs: consolidate session notes"\`
|
|
4149
|
+
|
|
4150
|
+
### Title Quality Rules
|
|
4151
|
+
|
|
4152
|
+
A title is "garbage" if it:
|
|
4153
|
+
- Quotes a user message verbatim (conversational tone, starts with lowercase)
|
|
4154
|
+
- Contains \`[object Object]\`, hex hashes, \`task-notification\`
|
|
4155
|
+
- Is longer than 80 characters
|
|
4156
|
+
- Is generic: "New Session", "Continued Session", "Session N"
|
|
4157
|
+
|
|
4158
|
+
Fix by reading the note's ## Work Done or **Focus:** line and deriving a descriptive title.
|
|
4159
|
+
|
|
4160
|
+
### Safety
|
|
4161
|
+
|
|
4162
|
+
- NEVER delete a note that is the ONLY one for its topic
|
|
4163
|
+
- NEVER delete notes from previous months (only consolidate current month)
|
|
4164
|
+
- Show the plan before executing (unless --force)
|
|
4165
|
+
- Always preserve the most complete version
|
|
4166
|
+
`
|
|
4167
|
+
};
|
|
4168
|
+
|
|
4169
|
+
//#endregion
|
|
4170
|
+
//#region src/daemon-mcp/prompts/advisor.ts
|
|
4171
|
+
const advisor = {
|
|
4172
|
+
description: "Manage budget-aware advisor mode — control model tiering for subagents based on weekly usage",
|
|
4173
|
+
content: `## Advisor Mode Management
|
|
4174
|
+
|
|
4175
|
+
USE WHEN user says 'advisor', 'budget mode', 'set advisor', 'save budget', '/advisor', 'how much budget', OR wants to control model tiering for subagents.
|
|
4176
|
+
|
|
4177
|
+
ALSO USE WHEN user says plain-language budget/mode phrases like:
|
|
4178
|
+
- "go easy on the budget", "save tokens", "be conservative" → set mode to conservative
|
|
4179
|
+
- "use haiku only", "strict mode", "budget is tight" → set mode to strict
|
|
4180
|
+
- "lock it down", "critical mode", "almost out of budget" → set mode to critical
|
|
4181
|
+
- "go full power", "use whatever model", "no budget constraints", "normal mode", "unrestricted" → set mode to normal
|
|
4182
|
+
- "back to auto", "reset advisor", "let the budget decide" → set mode to auto
|
|
4183
|
+
|
|
4184
|
+
When you detect these, write the appropriate mode to \`~/.claude/advisor-mode.json\` and confirm what you did.
|
|
4185
|
+
|
|
4186
|
+
Advisor mode controls which models subagents use, based on weekly budget consumption.
|
|
4187
|
+
|
|
4188
|
+
### Configuration
|
|
4189
|
+
|
|
4190
|
+
The config file is at \`~/.claude/advisor-mode.json\`:
|
|
4191
|
+
\`\`\`json
|
|
4192
|
+
{
|
|
4193
|
+
"weeklyBudgetPercent": 90,
|
|
4194
|
+
"mode": "auto"
|
|
4195
|
+
}
|
|
4196
|
+
\`\`\`
|
|
4197
|
+
|
|
4198
|
+
### Usage
|
|
4199
|
+
|
|
4200
|
+
- \`/advisor\` — show current mode and budget
|
|
4201
|
+
- \`/advisor set <percent>\` — set weekly budget percentage (triggers auto mode calculation)
|
|
4202
|
+
- \`/advisor mode <normal|conservative|strict|critical>\` — force a specific mode
|
|
4203
|
+
- \`/advisor auto\` — reset to auto mode (derives from weeklyBudgetPercent)
|
|
4204
|
+
- \`/advisor force <model>\` — force all subagents to use a specific model (haiku/sonnet/opus)
|
|
4205
|
+
- \`/advisor reset\` — remove the config file (no advisor guidance injected)
|
|
4206
|
+
- Or just say it in plain language — see triggers above
|
|
4207
|
+
|
|
4208
|
+
### Mode Thresholds (auto mode)
|
|
4209
|
+
|
|
4210
|
+
| Budget Used | Mode | Subagent Model | Behavior |
|
|
4211
|
+
|-------------|------|----------------|----------|
|
|
4212
|
+
| < 60% | normal | Any | No constraints |
|
|
4213
|
+
| 60-80% | conservative | Haiku preferred | Escalate to sonnet only if haiku insufficient |
|
|
4214
|
+
| 80-92% | strict | Haiku only | Minimize spawning, no opus subagents |
|
|
4215
|
+
| > 92% | critical | Haiku or none | Essential work only, minimize all token usage |
|
|
4216
|
+
|
|
4217
|
+
### Workflow
|
|
4218
|
+
|
|
4219
|
+
**Show current status:**
|
|
4220
|
+
Read \`~/.claude/advisor-mode.json\`. Display the mode, budget percentage, and what model constraints are active.
|
|
4221
|
+
|
|
4222
|
+
**Update budget percentage:**
|
|
4223
|
+
The user reads their weekly budget from the statusline (e.g., "7d: 63% → Fr. 08:00").
|
|
4224
|
+
Write the percentage to \`weeklyBudgetPercent\` in the config file.
|
|
4225
|
+
If mode is "auto", the whisper hook will compute the appropriate tier.
|
|
4226
|
+
|
|
4227
|
+
**Force a mode:**
|
|
4228
|
+
Set \`mode\` to the desired value. Overrides auto calculation.
|
|
4229
|
+
Useful when the user wants to be aggressive (normal) or cautious (strict) regardless of actual budget.
|
|
4230
|
+
|
|
4231
|
+
**Force a model:**
|
|
4232
|
+
Set \`forceModel\` to "haiku", "sonnet", or "opus". ALL subagents will use this model.
|
|
4233
|
+
Useful for testing or when the user knows exactly what they want.
|
|
4234
|
+
|
|
4235
|
+
### Integration
|
|
4236
|
+
|
|
4237
|
+
The advisor config is read by the whisper-rules hook on every prompt. Changes take effect immediately — no restart needed. The guidance appears as an ADVISOR MODE line in the system-reminder alongside the whisper rules.
|
|
4238
|
+
`
|
|
4239
|
+
};
|
|
4240
|
+
|
|
4241
|
+
//#endregion
|
|
4242
|
+
//#region src/daemon-mcp/prompts/tasks.ts
|
|
4243
|
+
const tasks = {
|
|
4244
|
+
description: "Run the task bus — read cross-session work from the tracker, dispatch it to the sessions that own it, and file findings",
|
|
4245
|
+
content: `## Task Bus
|
|
4246
|
+
|
|
4247
|
+
USE WHEN user says 'morning routine', 'what needs doing', 'run the routine', 'check my tasks', 'dispatch tasks', 'file a finding', 'add this to todoist', 'what did we find', OR /tasks.
|
|
4248
|
+
|
|
4249
|
+
The bus is shared state that outlives any one session. Session-local work stays in each project's \`Notes/TODO.md\`; the bus carries work that is **broader than one session** — findings discovered sideways, and work belonging to a project other than the one you are in.
|
|
4250
|
+
|
|
4251
|
+
### Pre-Action Check (MANDATORY)
|
|
4252
|
+
|
|
4253
|
+
\`\`\`bash
|
|
4254
|
+
pai task list --limit 1
|
|
4255
|
+
\`\`\`
|
|
4256
|
+
|
|
4257
|
+
If this prints "Task bus is not configured", tell the user to run \`pai setup\` and complete the Task Bus step, then stop. Do not work around it by calling the Todoist MCP directly — the bus resolves ownership against the PAI registry, which the raw MCP knows nothing about.
|
|
4258
|
+
|
|
4259
|
+
---
|
|
4260
|
+
|
|
4261
|
+
### Workflow 1 — Morning Routine
|
|
4262
|
+
|
|
4263
|
+
**Trigger:** "morning routine", "what needs doing", "run the routine".
|
|
4264
|
+
|
|
4265
|
+
**Step 1 — Read what is open**
|
|
4266
|
+
\`\`\`bash
|
|
4267
|
+
pai task list --today # due today or overdue; drop --today for everything
|
|
4268
|
+
\`\`\`
|
|
4269
|
+
|
|
4270
|
+
**Step 2 — Report before acting.** Group by owner, lead with overdue and \`p1\`. Never dispatch silently — the user sees the list before sessions start receiving work.
|
|
4271
|
+
|
|
4272
|
+
**Step 3 — Dispatch**
|
|
4273
|
+
\`\`\`bash
|
|
4274
|
+
pai task dispatch --today --dry-run # always preview
|
|
4275
|
+
pai task dispatch --today # then, once approved
|
|
4276
|
+
\`\`\`
|
|
4277
|
+
|
|
4278
|
+
| Symbol | Outcome | Meaning |
|
|
4279
|
+
|---|---|---|
|
|
4280
|
+
| \`→\` | delivered | Sent to an already-running session |
|
|
4281
|
+
| \`+\` | spawned | None running; one was launched, then sent to |
|
|
4282
|
+
| \`?\` | unrouted | No owner resolved — stays in the findings inbox |
|
|
4283
|
+
| \`!\` | unlaunchable | Owner resolved but has no PAI alias to launch |
|
|
4284
|
+
| \`·\` | skipped | Auto-dispatch off, or no transport — reported only |
|
|
4285
|
+
|
|
4286
|
+
On \`!\`: the fix is \`pai project name <identifier> <shortname>\`. Only aliased projects can be dispatched to — say this rather than reporting a vague failure.
|
|
4287
|
+
|
|
4288
|
+
On \`?\`: normal, not an error. Triage is pending.
|
|
4289
|
+
|
|
4290
|
+
**Step 4 — Report honestly.** State what actually reached a session. If nothing was dispatched because auto-dispatch is off, say so plainly rather than implying work was handed off.
|
|
4291
|
+
|
|
4292
|
+
---
|
|
4293
|
+
|
|
4294
|
+
### Workflow 2 — File a Finding
|
|
4295
|
+
|
|
4296
|
+
**Trigger:** "file a finding", "add this to todoist", or **any time you discover something outside the current task**.
|
|
4297
|
+
|
|
4298
|
+
\`\`\`bash
|
|
4299
|
+
pai task add "Short actionable title" \\
|
|
4300
|
+
--owner <project> \\
|
|
4301
|
+
--body "Full procedure AND reasoning" \\
|
|
4302
|
+
--priority p2 \\
|
|
4303
|
+
--url "hook://..."
|
|
4304
|
+
\`\`\`
|
|
4305
|
+
|
|
4306
|
+
Rules:
|
|
4307
|
+
- **\`--body\` is not optional in practice.** Enough that the task is actionable months later, or by the user alone, without re-deriving anything. A bare title is a reminder that something was once known — worthless later.
|
|
4308
|
+
- **Omit \`--owner\` when you genuinely do not know.** It lands in the findings inbox for triage. Guessing is worse than leaving it unrouted.
|
|
4309
|
+
- **Prefer \`hook://\` URLs over file paths** for \`--url\` (get one via \`mcp__hook__hookmark_link\`). They survive renames and open in DEVONthink To Go on iOS. Plain paths are the fallback.
|
|
4310
|
+
- **No generic checklist items.** A recurring item earns its place only because something *actually failed silently*. Otherwise the routine becomes noise and gets ignored.
|
|
4311
|
+
|
|
4312
|
+
---
|
|
4313
|
+
|
|
4314
|
+
### Workflow 3 — Triage
|
|
4315
|
+
|
|
4316
|
+
**Trigger:** "triage", "what did we find", or weekly.
|
|
4317
|
+
|
|
4318
|
+
\`\`\`bash
|
|
4319
|
+
pai task list --limit 100
|
|
4320
|
+
\`\`\`
|
|
4321
|
+
|
|
4322
|
+
For each \`unrouted\` item, decide with the user: assign an owner, act now, or delete. Assigning means adding a \`pai:<project>\` label on the tracker — authoritative, and it survives the task being moved.
|
|
4323
|
+
|
|
4324
|
+
**The findings inbox should normally be empty.** If it is filling up, the bus has become another place for items to rot. Say so — that is a judgement about the system, not about the user.
|
|
4325
|
+
|
|
4326
|
+
---
|
|
4327
|
+
|
|
4328
|
+
### Ownership
|
|
4329
|
+
|
|
4330
|
+
1. A \`pai:<project>\` label — **authoritative**
|
|
4331
|
+
2. Enclosing sub-project name matched against PAI aliases — fallback
|
|
4332
|
+
3. Otherwise unrouted
|
|
4333
|
+
|
|
4334
|
+
A label matching nothing does **not** fall through to the container. The user meant somewhere specific; quietly routing elsewhere is worse than not routing.
|
|
4335
|
+
|
|
4336
|
+
### Notes
|
|
4337
|
+
|
|
4338
|
+
- \`pai task done <id>\` closes a task. Dispatched tasks instruct the receiving session to do this, so work is not dispatched twice.
|
|
4339
|
+
- One-way by design: PAI and its sessions write; a routine reads. Nothing reads the tracker back into PAI state.
|
|
4340
|
+
- Architecture and verified API constraints: \`Notes/docs/task-bus.md\`.
|
|
4341
|
+
`
|
|
4342
|
+
};
|
|
4343
|
+
|
|
3770
4344
|
//#endregion
|
|
3771
4345
|
//#region src/daemon-mcp/resources/aesthetic.ts
|
|
3772
4346
|
const aesthetic = {
|
|
@@ -4646,7 +5220,12 @@ async function startShim() {
|
|
|
4646
5220
|
"vault-connect": vaultConnect,
|
|
4647
5221
|
"vault-emerge": vaultEmerge,
|
|
4648
5222
|
"vault-orphans": vaultOrphans,
|
|
4649
|
-
"vault-trace": vaultTrace
|
|
5223
|
+
"vault-trace": vaultTrace,
|
|
5224
|
+
"reconstruct": reconstruct,
|
|
5225
|
+
"whisper": whisper,
|
|
5226
|
+
"consolidate": consolidate,
|
|
5227
|
+
"advisor": advisor,
|
|
5228
|
+
"tasks": tasks
|
|
4650
5229
|
};
|
|
4651
5230
|
for (const [promptName, skill] of Object.entries(SKILL_PROMPTS)) server.prompt(promptName, skill.description, () => ({ messages: [{
|
|
4652
5231
|
role: "user",
|