whydid 1.0.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.
Files changed (84) hide show
  1. package/README.md +232 -0
  2. package/dashboard/dist/android-chrome-192x192.png +0 -0
  3. package/dashboard/dist/android-chrome-512x512.png +0 -0
  4. package/dashboard/dist/apple-touch-icon.png +0 -0
  5. package/dashboard/dist/assets/index-DImKqodm.js +69 -0
  6. package/dashboard/dist/assets/index-mHXgqqkj.css +1 -0
  7. package/dashboard/dist/favicon-16x16.png +0 -0
  8. package/dashboard/dist/favicon-32x32.png +0 -0
  9. package/dashboard/dist/favicon.ico +0 -0
  10. package/dashboard/dist/index.html +24 -0
  11. package/dashboard/dist/logo-mark.svg +8 -0
  12. package/dashboard/dist/site.webmanifest +11 -0
  13. package/dist/adapters/claude-code.js +168 -0
  14. package/dist/adapters/hook-events.js +86 -0
  15. package/dist/adapters/sync-claude-code.js +85 -0
  16. package/dist/cli/ai-budget-warning.js +19 -0
  17. package/dist/cli/commands/agent-event.js +80 -0
  18. package/dist/cli/commands/checkpoint.js +36 -0
  19. package/dist/cli/commands/context.js +27 -0
  20. package/dist/cli/commands/daemon.js +139 -0
  21. package/dist/cli/commands/export.js +36 -0
  22. package/dist/cli/commands/init.js +63 -0
  23. package/dist/cli/commands/key.js +65 -0
  24. package/dist/cli/commands/license.js +57 -0
  25. package/dist/cli/commands/milestone.js +64 -0
  26. package/dist/cli/commands/prompt.js +75 -0
  27. package/dist/cli/commands/recap.js +48 -0
  28. package/dist/cli/commands/restore-fork.js +101 -0
  29. package/dist/cli/commands/status.js +26 -0
  30. package/dist/cli/commands/test.js +33 -0
  31. package/dist/cli/commands/timeline.js +23 -0
  32. package/dist/cli/commands/why.js +71 -0
  33. package/dist/cli/context.js +48 -0
  34. package/dist/cli/index.js +77 -0
  35. package/dist/cli/license-gate.js +26 -0
  36. package/dist/cli/preflight.js +28 -0
  37. package/dist/core/agent-context.js +46 -0
  38. package/dist/core/agent-hooks.js +68 -0
  39. package/dist/core/ai-budget.js +27 -0
  40. package/dist/core/chat-retrieval.js +36 -0
  41. package/dist/core/context-tree.js +135 -0
  42. package/dist/core/diff.js +30 -0
  43. package/dist/core/engine.js +321 -0
  44. package/dist/core/export.js +98 -0
  45. package/dist/core/file-history.js +31 -0
  46. package/dist/core/manifest.js +102 -0
  47. package/dist/core/recap.js +49 -0
  48. package/dist/core/test-runner.js +23 -0
  49. package/dist/daemon/listen.js +26 -0
  50. package/dist/daemon/pidfile.js +36 -0
  51. package/dist/daemon/server.js +554 -0
  52. package/dist/db/database.js +631 -0
  53. package/dist/db/schema.js +186 -0
  54. package/dist/git/git.js +22 -0
  55. package/dist/licensing/config.js +28 -0
  56. package/dist/licensing/license-client.js +45 -0
  57. package/dist/licensing/license-manager.js +89 -0
  58. package/dist/licensing/license-payload.js +12 -0
  59. package/dist/licensing/license-store.js +96 -0
  60. package/dist/licensing/machine-id.js +78 -0
  61. package/dist/licensing/secret-store.js +102 -0
  62. package/dist/licensing/verify-license.js +20 -0
  63. package/dist/llm/agent-prompt.js +36 -0
  64. package/dist/llm/annotate-checkpoint.js +67 -0
  65. package/dist/llm/annotate.js +11 -0
  66. package/dist/llm/anthropic-provider.js +97 -0
  67. package/dist/llm/chat.js +35 -0
  68. package/dist/llm/community-pricing.js +75 -0
  69. package/dist/llm/factory.js +17 -0
  70. package/dist/llm/http-error.js +25 -0
  71. package/dist/llm/noop-provider.js +19 -0
  72. package/dist/llm/openai-provider.js +85 -0
  73. package/dist/llm/pricing.js +55 -0
  74. package/dist/llm/prompt.js +103 -0
  75. package/dist/llm/provider.js +2 -0
  76. package/dist/llm/schema.js +49 -0
  77. package/dist/llm/social-post.js +49 -0
  78. package/dist/objects/store.js +31 -0
  79. package/dist/shared/config.js +45 -0
  80. package/dist/shared/redaction.js +18 -0
  81. package/dist/shared/types.js +2 -0
  82. package/dist/watcher/ignore-rules.js +92 -0
  83. package/dist/watcher/watcher.js +249 -0
  84. package/package.json +55 -0
package/README.md ADDED
@@ -0,0 +1,232 @@
1
+ # whydid
2
+
3
+ A local-first time machine for AI-assisted coding. whydid automatically
4
+ records meaningful AI/manual changes to your project as a recoverable
5
+ state graph, explains them with your own LLM key, and lets you inspect
6
+ diffs, restore, and fork — all offline, all on your machine.
7
+
8
+ > **Vibe code without losing control.** Every meaningful change becomes a
9
+ > recoverable state you can understand, compare, restore, or fork.
10
+
11
+ ## Requirements
12
+
13
+ Node.js **24+** (or 23.4+). whydid uses the built-in `node:sqlite` module,
14
+ which isn't available unflagged on older Node — the CLI checks this at
15
+ startup and fails with a clear message rather than a stack trace if your
16
+ `node` resolves to an older build. If you have multiple Node installs,
17
+ `which -a node` and `node --version` will show which one is active.
18
+
19
+ ## Quick start
20
+
21
+ ```bash
22
+ npm install -g whydid
23
+ whydid login <licenseKey> # from your purchase email — see https://whydid.dev/pricing
24
+
25
+ cd /path/to/your/project
26
+ whydid init
27
+ whydid daemon start
28
+ # open the printed http://127.0.0.1:<port>/?token=... URL
29
+ ```
30
+
31
+ `whydid login` activates this machine against your license (2 devices per
32
+ purchase). Run `whydid license` any time to check status with no network
33
+ call, and `whydid logout` to free up this machine's activation slot.
34
+
35
+ **Building from source instead of installing the published package?** See
36
+ [Development](#development) below.
37
+
38
+ ## AI annotations (BYOK, optional)
39
+
40
+ By default whydid runs with no AI calls at all. To turn on annotations —
41
+ a one-line summary + reason + risk level generated after each checkpoint —
42
+ set a provider in `.whydid/config.json` and export the matching key:
43
+
44
+ ```json
45
+ { "ai": { "provider": "anthropic", "model": "" } }
46
+ ```
47
+
48
+ ```bash
49
+ export ANTHROPIC_API_KEY=sk-ant-... # or OPENAI_API_KEY for "openai"
50
+ ```
51
+
52
+ If no key is found, whydid silently falls back to no-op — checkpoints
53
+ always work regardless of AI availability (spec §44). Diff text sent to
54
+ the model is redacted for secrets first (`.env` values, API keys, JWTs,
55
+ credentialed URLs — see `src/shared/redaction.ts`).
56
+
57
+ ## CLI
58
+
59
+ ```
60
+ whydid init initialize whydid in the current project
61
+ whydid status show current state summary
62
+ whydid checkpoint manually create a checkpoint
63
+ whydid timeline print the state timeline
64
+ whydid why <file> [--ask] explain a file's FULL history; --ask asks your LLM live
65
+ whydid prompt <file> generate a ready-to-paste revert/continue prompt for your AI agent
66
+ whydid restore <stateId> safely restore an earlier state
67
+ whydid fork <stateId> <name> fork a new branch from a state
68
+ whydid test run the configured test command, record pass/fail
69
+ whydid recap (alias: doctor) summarize today's changes, churn, risk
70
+ whydid export --format <fmt> export history as json | markdown | html
71
+ whydid daemon start|stop|status
72
+ ```
73
+
74
+ Once `whydid init` has run, whydid's filesystem watcher automatically
75
+ checkpoints meaningful changes as you (or an AI agent) edit the project —
76
+ no need to run `whydid checkpoint` after every change, though it's there
77
+ for manual use. If a provider is configured, checkpoints are annotated
78
+ automatically too, both from the watcher and from manual `checkpoint`.
79
+
80
+ ### Context across coding agents
81
+
82
+ `whydid init` installs managed context instructions for Codex (`AGENTS.md`),
83
+ Claude Code (`CLAUDE.md`), and Cursor (`.cursor/rules/whydid-context.mdc`).
84
+ Fresh sessions are instructed to read `WHYDID_SUMMARY.md` and the relevant
85
+ directory's `CONTEXT.md`, so recent decisions follow the project when founders
86
+ switch tools or share the repo. Existing instructions are preserved; whydid
87
+ adds or updates only its own marked section. Review and commit these files with
88
+ the code to share context.
89
+
90
+ `whydid init` also registers project hooks for Codex and Cursor. Their prompts
91
+ and turn boundaries are recorded in the local database and appear in the same
92
+ Sessions view as Claude Code; the watcher links checkpoints to the active
93
+ turn. Hook events use each tool's supported lifecycle interface rather than
94
+ reading private transcript files. Hook commands require the `whydid` CLI on
95
+ the editor's `PATH`; Codex may ask you to trust project hooks, and Cursor runs
96
+ project hooks only in a trusted workspace. If hooks are unavailable, ordinary
97
+ file-watcher checkpoints continue to work without prompt attribution.
98
+
99
+ ### Session-aware checkpointing (Claude Code)
100
+
101
+ If you're running whydid inside a project that's also open in Claude Code,
102
+ the daemon reads Claude Code's own local session transcripts
103
+ (`~/.claude/projects/<slug>/*.jsonl`) to correlate checkpoints with the
104
+ actual prompt that caused them — not a guess from the diff, the real
105
+ instruction. Two concrete effects:
106
+
107
+ - **Checkpoints split at prompt boundaries.** If you ask for one thing,
108
+ then ask for a second thing, whydid force-checkpoints the first task's
109
+ changes the moment the second prompt starts — two independently
110
+ revertible states instead of one merged one — rather than waiting for
111
+ the file-watcher's debounce timer.
112
+ - **`whydid why` shows the real instruction**, not an LLM's best guess from
113
+ the diff, and grounds AI annotations in it too.
114
+
115
+ This reads an undocumented local format, so it fails soft: if the session
116
+ directory isn't found (a different project, a different agent, or the
117
+ format changes in a future Claude Code version), whydid falls back to
118
+ plain debounce-based checkpointing exactly as before — nothing here is
119
+ required for whydid to work.
120
+
121
+ ### Same-file history and cross-change dependencies
122
+
123
+ `whydid why <file>` shows every state that ever touched that file, oldest
124
+ first — not just the most recent one — and flags when a later change
125
+ landed on top of an earlier one in the same file, so reverting the earlier
126
+ one visibly risks the later one before you do it. The dashboard's State
127
+ Detail page has the same view under the file's **History** tab.
128
+
129
+ ### AI-generated agent prompts
130
+
131
+ `whydid prompt <file> --mode revert` (or `--mode continue --instruction
132
+ "..."`) asks your configured LLM to write a ready-to-paste prompt for your
133
+ own coding agent — grounded in the target change's real diff and, when
134
+ there's later work on the same file, an explicit warning not to disturb
135
+ it (or an honest "a clean revert isn't possible here" when the two changes
136
+ overlap on the same lines). Also available from the dashboard via the
137
+ **⚡ Agent prompt** button on any file in a state.
138
+
139
+ ## How it works
140
+
141
+ - **State engine** (`src/core/engine.ts`): every checkpoint is a full
142
+ file manifest (path → content hash), stored in SQLite, with changed
143
+ file content written to a content-addressed object store
144
+ (`.whydid/objects/`, SHA-256, deduplicated). States form a graph via
145
+ `parent_state_id` — never a flat list.
146
+ - **Restore** always snapshots whatever is currently on disk as a real,
147
+ permanent state *before* touching anything, then writes the target
148
+ state's files back. Nothing is ever deleted or overwritten without
149
+ first being recoverable.
150
+ - **Fork** does the same safety-snapshot, then branches a new state off
151
+ any point in history, leaving the original timeline completely intact.
152
+ - **Diffs** are computed on demand from two stored blobs — nothing extra
153
+ is stored per diff.
154
+ - A **filesystem watcher** (chokidar) debounces bursts of edits and
155
+ auto-checkpoints after a quiet period; `.gitignore` and built-in
156
+ excludes (`node_modules`, `.git`, `.whydid`, `dist`, `build`, etc.) are
157
+ always respected. It's started by the daemon, so `whydid daemon start`
158
+ is what makes auto-checkpointing live.
159
+ - **AI annotations**: after a checkpoint, whydid builds a redacted diff +
160
+ context, sends it to your configured provider (`AnthropicProvider` /
161
+ `OpenAIProvider`, both plain `fetch`-based, BYOK), and stores the
162
+ structured result (summary, reason, decisions, risk) — surfaced in
163
+ `whydid why`, the dashboard, `recap`, and `export`.
164
+ - A local **daemon** (Express, bound to `127.0.0.1` only, token-authed)
165
+ exposes the engine over HTTP and serves the built **React dashboard**.
166
+
167
+ ## Dashboard
168
+
169
+ `whydid daemon start` opens a full app, not a single page:
170
+
171
+ - **Timeline** — the branching state graph, recap strip, search (summaries/
172
+ reasons/state ids) and risk-level filtering.
173
+ - **State Detail** — AI reasoning up front, diff viewer, file History tab,
174
+ ⚡ Agent Prompt generation, Restore/Fork.
175
+ - **Sessions** — Claude Code, Codex, and Cursor sessions, prompts, and the
176
+ states each turn produced.
177
+ - **Settings** — configure the AI provider/model and privacy toggles (spec
178
+ §21: send prompts / send diffs, independently) through a form — no
179
+ manual JSON editing, and the toggles are actually enforced on every LLM
180
+ call, not just displayed.
181
+ - **Export** — JSON/Markdown/HTML, one click from the sidebar.
182
+
183
+ ## What's implemented
184
+
185
+ - Local SQLite state **graph** (real branches — restore/fork parent on
186
+ their true target/source, not a safety-snapshot dead end), content-
187
+ addressed snapshot storage, real line-diff stats
188
+ - Filesystem watcher with debounced auto-checkpointing, live in the daemon
189
+ - Restore and fork, both safety-snapshotting the current state first
190
+ - Real Claude Code session/turn correlation (ground-truth prompts, not
191
+ guesses) with prompt-boundary checkpoint segregation, verified against
192
+ this project's own real session transcripts
193
+ - Codex and Cursor session/prompt capture through supported project hooks,
194
+ with checkpoints linked to the active turn and live Sessions views
195
+ - Same-file change history with cross-change dependency flagging, and
196
+ AI-generated revert/continue prompts for your coding agent
197
+ - A local dashboard with a real multi-lane branching graph (not a flat
198
+ list), AI reasoning surfaced inline, a recap strip, file history, and
199
+ agent-prompt generation — all on a brand-consistent design system
200
+ shared with the landing page
201
+ - Real Anthropic + OpenAI LLM providers (BYOK, raw fetch, no extra SDK
202
+ deps), wired end-to-end into checkpoint + auto-watcher + `why --ask` +
203
+ agent-prompt generation, behind deterministic secret redaction and a
204
+ `NoopProvider` fallback
205
+ - `whydid test`, `whydid recap`/`doctor`, `whydid export` (JSON/MD/HTML)
206
+ - Automated tests cover the spec's §57 critical acceptance scenario
207
+ end-to-end (init → edit → checkpoint → edit → checkpoint → restore →
208
+ verify preserved → fork → verify graph), agent event capture, and
209
+ turn-boundary segregation
210
+
211
+ ## Deferred (not built in this pass)
212
+
213
+ Parsing Codex/Cursor private transcript formats remains deferred; supported
214
+ project hooks provide their session and prompt events without depending on
215
+ private transcript formats.
216
+
217
+ ## Development
218
+
219
+ Building from source (contributing, or testing a change) instead of
220
+ `npm install -g whydid`:
221
+
222
+ ```bash
223
+ npm install
224
+ npm run build
225
+ npm run dashboard:build
226
+ npm link # installs `whydid` as a global command pointing at this checkout
227
+
228
+ npm test # Vitest
229
+ npm run typecheck
230
+ ```
231
+
232
+ Without `npm link`, run it as `node /path/to/whydid/dist/cli/index.js <command>`.