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.
- package/README.md +232 -0
- package/dashboard/dist/android-chrome-192x192.png +0 -0
- package/dashboard/dist/android-chrome-512x512.png +0 -0
- package/dashboard/dist/apple-touch-icon.png +0 -0
- package/dashboard/dist/assets/index-DImKqodm.js +69 -0
- package/dashboard/dist/assets/index-mHXgqqkj.css +1 -0
- package/dashboard/dist/favicon-16x16.png +0 -0
- package/dashboard/dist/favicon-32x32.png +0 -0
- package/dashboard/dist/favicon.ico +0 -0
- package/dashboard/dist/index.html +24 -0
- package/dashboard/dist/logo-mark.svg +8 -0
- package/dashboard/dist/site.webmanifest +11 -0
- package/dist/adapters/claude-code.js +168 -0
- package/dist/adapters/hook-events.js +86 -0
- package/dist/adapters/sync-claude-code.js +85 -0
- package/dist/cli/ai-budget-warning.js +19 -0
- package/dist/cli/commands/agent-event.js +80 -0
- package/dist/cli/commands/checkpoint.js +36 -0
- package/dist/cli/commands/context.js +27 -0
- package/dist/cli/commands/daemon.js +139 -0
- package/dist/cli/commands/export.js +36 -0
- package/dist/cli/commands/init.js +63 -0
- package/dist/cli/commands/key.js +65 -0
- package/dist/cli/commands/license.js +57 -0
- package/dist/cli/commands/milestone.js +64 -0
- package/dist/cli/commands/prompt.js +75 -0
- package/dist/cli/commands/recap.js +48 -0
- package/dist/cli/commands/restore-fork.js +101 -0
- package/dist/cli/commands/status.js +26 -0
- package/dist/cli/commands/test.js +33 -0
- package/dist/cli/commands/timeline.js +23 -0
- package/dist/cli/commands/why.js +71 -0
- package/dist/cli/context.js +48 -0
- package/dist/cli/index.js +77 -0
- package/dist/cli/license-gate.js +26 -0
- package/dist/cli/preflight.js +28 -0
- package/dist/core/agent-context.js +46 -0
- package/dist/core/agent-hooks.js +68 -0
- package/dist/core/ai-budget.js +27 -0
- package/dist/core/chat-retrieval.js +36 -0
- package/dist/core/context-tree.js +135 -0
- package/dist/core/diff.js +30 -0
- package/dist/core/engine.js +321 -0
- package/dist/core/export.js +98 -0
- package/dist/core/file-history.js +31 -0
- package/dist/core/manifest.js +102 -0
- package/dist/core/recap.js +49 -0
- package/dist/core/test-runner.js +23 -0
- package/dist/daemon/listen.js +26 -0
- package/dist/daemon/pidfile.js +36 -0
- package/dist/daemon/server.js +554 -0
- package/dist/db/database.js +631 -0
- package/dist/db/schema.js +186 -0
- package/dist/git/git.js +22 -0
- package/dist/licensing/config.js +28 -0
- package/dist/licensing/license-client.js +45 -0
- package/dist/licensing/license-manager.js +89 -0
- package/dist/licensing/license-payload.js +12 -0
- package/dist/licensing/license-store.js +96 -0
- package/dist/licensing/machine-id.js +78 -0
- package/dist/licensing/secret-store.js +102 -0
- package/dist/licensing/verify-license.js +20 -0
- package/dist/llm/agent-prompt.js +36 -0
- package/dist/llm/annotate-checkpoint.js +67 -0
- package/dist/llm/annotate.js +11 -0
- package/dist/llm/anthropic-provider.js +97 -0
- package/dist/llm/chat.js +35 -0
- package/dist/llm/community-pricing.js +75 -0
- package/dist/llm/factory.js +17 -0
- package/dist/llm/http-error.js +25 -0
- package/dist/llm/noop-provider.js +19 -0
- package/dist/llm/openai-provider.js +85 -0
- package/dist/llm/pricing.js +55 -0
- package/dist/llm/prompt.js +103 -0
- package/dist/llm/provider.js +2 -0
- package/dist/llm/schema.js +49 -0
- package/dist/llm/social-post.js +49 -0
- package/dist/objects/store.js +31 -0
- package/dist/shared/config.js +45 -0
- package/dist/shared/redaction.js +18 -0
- package/dist/shared/types.js +2 -0
- package/dist/watcher/ignore-rules.js +92 -0
- package/dist/watcher/watcher.js +249 -0
- 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>`.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|