daimon 0.5.0 → 0.7.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/CHANGELOG.md +106 -0
- package/README.md +43 -29
- package/dist/cli.js +79 -66
- package/dist/dashboard/3rdpartylicenses.txt +4 -4
- package/dist/dashboard/browser/{chunk-HFJ25UTJ.js → chunk-25VLDASM.js} +4 -4
- package/dist/dashboard/browser/chunk-5PAHWCG5.js +1 -0
- package/dist/dashboard/browser/chunk-6BDWIJ3G.js +3 -0
- package/dist/dashboard/browser/chunk-6C6GHU3A.js +1 -0
- package/dist/dashboard/browser/{chunk-JX3IOOXU.js → chunk-7NRE3SNA.js} +3 -3
- package/dist/dashboard/browser/chunk-BDYOKQF3.js +1 -0
- package/dist/dashboard/browser/chunk-CILFSVSP.js +2 -0
- package/dist/dashboard/browser/chunk-GDJOSLWM.js +1 -0
- package/dist/dashboard/browser/chunk-HYGMRGYR.js +4 -0
- package/dist/dashboard/browser/chunk-HYIZMKSF.js +1 -0
- package/dist/dashboard/browser/chunk-IQZZO5IM.js +3 -0
- package/dist/dashboard/browser/chunk-J5UK77OJ.js +1 -0
- package/dist/dashboard/browser/chunk-JI63U3KC.js +2 -0
- package/dist/dashboard/browser/chunk-K43KW4K2.js +4 -0
- package/dist/dashboard/browser/chunk-KLH6B22T.js +1 -0
- package/dist/dashboard/browser/chunk-L2PHC6DL.js +1 -0
- package/dist/dashboard/browser/{chunk-Q7R63OUT.js → chunk-LBRCWYRN.js} +1 -1
- package/dist/dashboard/browser/chunk-MHYQENOC.js +1 -0
- package/dist/dashboard/browser/{chunk-AEERNAF7.js → chunk-NDSAQ2HK.js} +1 -1
- package/dist/dashboard/browser/chunk-OHX55ZU4.js +2 -0
- package/dist/dashboard/browser/chunk-OUXULJ3Z.js +3 -0
- package/dist/dashboard/browser/chunk-P5IU57TV.js +2 -0
- package/dist/dashboard/browser/{chunk-3TYCIBMV.js → chunk-PJPGLT4T.js} +1 -1
- package/dist/dashboard/browser/chunk-Q3N4MMWW.js +5 -0
- package/dist/dashboard/browser/chunk-RIDV4B55.js +5 -0
- package/dist/dashboard/browser/chunk-SR5JAOLW.js +2 -0
- package/dist/dashboard/browser/{chunk-ZVU34B5S.js → chunk-UC3XMN2Y.js} +1 -1
- package/dist/dashboard/browser/chunk-UU5K6ZPO.js +1 -0
- package/dist/dashboard/browser/chunk-XXIJQBCQ.js +2 -0
- package/dist/dashboard/browser/chunk-Y6B6X4Y6.js +2 -0
- package/dist/dashboard/browser/chunk-YA4AZONZ.js +5 -0
- package/dist/dashboard/browser/chunk-YNCTXEXX.js +3 -0
- package/dist/dashboard/browser/chunk-YNQPX5G6.js +1 -0
- package/dist/dashboard/browser/{chunk-SLQ2WBUA.js → chunk-YYAZGY5M.js} +1 -1
- package/dist/dashboard/browser/chunk-ZDNBWNU5.js +1 -0
- package/dist/dashboard/browser/chunk-ZEO5YLWG.js +3 -0
- package/dist/dashboard/browser/chunk-ZVUH3ISD.js +2 -0
- package/dist/dashboard/browser/index.html +1 -1
- package/dist/dashboard/browser/main-IDF27PFI.js +1 -0
- package/dist/main.js +57 -44
- package/dist/mcp.js +3 -2
- package/package.json +2 -2
- package/dist/dashboard/browser/chunk-5UAN6ETO.js +0 -1
- package/dist/dashboard/browser/chunk-AX3RJNG4.js +0 -1
- package/dist/dashboard/browser/chunk-BADBUP5C.js +0 -3
- package/dist/dashboard/browser/chunk-BF6RQFHS.js +0 -2
- package/dist/dashboard/browser/chunk-C65CUT7O.js +0 -4
- package/dist/dashboard/browser/chunk-CNIZYK4A.js +0 -1
- package/dist/dashboard/browser/chunk-D4BFRQ63.js +0 -4
- package/dist/dashboard/browser/chunk-E235WGFQ.js +0 -3
- package/dist/dashboard/browser/chunk-F2EDJ6FT.js +0 -4
- package/dist/dashboard/browser/chunk-HFAARBWL.js +0 -1
- package/dist/dashboard/browser/chunk-LQNYSOSZ.js +0 -1
- package/dist/dashboard/browser/chunk-MBVVV35N.js +0 -1
- package/dist/dashboard/browser/chunk-NC2VPB4Y.js +0 -2
- package/dist/dashboard/browser/chunk-NXNVIINH.js +0 -1
- package/dist/dashboard/browser/chunk-QLKOKZDG.js +0 -9
- package/dist/dashboard/browser/chunk-QQSPJIPQ.js +0 -1
- package/dist/dashboard/browser/chunk-SCAIGUJL.js +0 -6
- package/dist/dashboard/browser/chunk-TSB6OOH2.js +0 -6
- package/dist/dashboard/browser/chunk-WWUKM5OG.js +0 -1
- package/dist/dashboard/browser/chunk-ZYE3XQS4.js +0 -2
- package/dist/dashboard/browser/main-Z6L5VPBT.js +0 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,112 @@ All notable changes to Daimon are documented here. The format follows [Keep a Ch
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.7.0] — 2026-05-20
|
|
8
|
+
|
|
9
|
+
Strategic theme: **Memory and reach.** v0.7 makes the *past* actionable (history surfaces) and broadens *what* daimon can manage (polyglot dev servers, whole-workspace orchestration, refreshed TUI).
|
|
10
|
+
|
|
11
|
+
### Added (M37) — History dashboard surface
|
|
12
|
+
|
|
13
|
+
- **T1a — Bundle-size persistence.** New `bundles` table in `~/.daimon/history.db` (`app, ts, initialKB, lazyKB, fileCount`). The registry persists one row per `onBundleUpdate` (Angular esbuild bundle parse), so the dashboard can render long-term bundle trends without an external store. The new table is additive — v0.6 history.db files migrate forward automatically on first open via `CREATE TABLE IF NOT EXISTS`. `daimon snapshot` carries the last 100 bundle rows per app in the payload.
|
|
14
|
+
- **T1b — `GET /api/history/trends`.** New aggregated time-series endpoint: `?app=<name>&metric=<compile|bundle|errors|restarts>&since=<24h|7d|30d>` returns `{app, metric, since, points:[{t, v, v2?}], _meta:{aggregation, count}}`. `compile` averages ms per bucket. `bundle` returns initialKB as `v` and lazyKB as `v2`. `errors` counts `error-new` + `error-recur` events per bucket. `restarts` counts `status` transitions where `to=starting` and `from ∈ {error, serving, compiling}`. Aggregation is hour-buckets for `24h` and day-buckets for `7d`/`30d`. Companion endpoint `/api/history/bundles` returns raw rows.
|
|
15
|
+
- **T1c — Dashboard `Trends` route.** New lazy-loaded `/trends` page with four charts (compile · bundle · errors · restarts) rendered via the existing chart.js lazy chunk from M30 — no new chart dep. Bundle chart stacks initialKB + lazyKB per app. Toggle between `24h` / `7d` / `30d` and between "All apps" and a single-app focus. Linked from the nav rail with `g t` shortcut.
|
|
16
|
+
- **T1d — Fixture-daemon harness (partial H1).** New `test/history-trends.test.mjs` exercises `History.recordBundle` / `queryBundles` and the four `trends()` aggregations against a temp sqlite db, so the Trends backend is verified without a real `~/.daimon/history.db`. Wired into `npm test`.
|
|
17
|
+
|
|
18
|
+
### Deferred (M37 → v0.7.1)
|
|
19
|
+
|
|
20
|
+
- **H1 — Vitest + Playwright dashboard scaffolding.** The non-trivial dev-dep + per-component spec layer carries over from v0.6.1; only the History.ts fixture-daemon harness lands in v0.7.0. Reason: keeps the Trends surface shipping on schedule while leaving the dashboard-test footprint for a focused v0.7.1 weekend.
|
|
21
|
+
- **H3 — WCAG AA contrast audit.** Visual inspection task across light/dark/reduced-motion tonal surfaces — also pushed to v0.7.1 alongside H1.
|
|
22
|
+
|
|
23
|
+
### Changed (M37)
|
|
24
|
+
|
|
25
|
+
- **Initial-route gzip transfer: 126.44 KB** — Trends route + `getTrends` + `getBundles` API are entirely lazy. Initial bundle stays under the 130 KB v0.6 ceiling.
|
|
26
|
+
|
|
27
|
+
### Added (M38) — Whole-workspace orchestration
|
|
28
|
+
|
|
29
|
+
- **T2a — `daimon orchestrate <profile>`.** New CLI / HTTP / MCP verb. `POST /api/orchestrate?profile=<name>&goal=serving|healthy|stable&timeoutMs=<n>[&dryRun=true&budget=<tokens>]`. Resolves the profile's app list, cascade-starts every app via the existing F18 depends-topo ordering, waits up to `timeoutMs/2` per app for the goal, and runs **one** round of `runAutoFix` + restart + wait on stragglers. Returns `{profile, goal, perApp:[{name, reached, tries, fixed?, stillFailing?:[…first 3 parsed errors], waitedMs}], totalMs, allReached}`. `goal=stable` requires serving + healthy + 5s idle (same definition as `focus --until stable`).
|
|
30
|
+
- **T2b — MCP `orchestrate` tool.** Same surface exposed to Claude; documented as the recommended way to "bring up my whole workspace" in one call. Inputs: `profile, goal?, timeoutMs?, dryRun?, budget?`. Returns the same shape as the HTTP endpoint.
|
|
31
|
+
- **T2c — Idempotency + dry-run.** Apps already at goal are no-ops (`tries:0, reached:true`). `--dry-run` returns `{dryRun:true, plannedOrder:[…topo levels…], alreadyHealthy:[…]}` without starting anything.
|
|
32
|
+
- **`--budget <tokens>`.** Honors a token budget like `overview`: drops `stillFailing` entries first (≈60 tokens each), then trims already-reached `perApp` rows, recording counts in `_meta.omitted`.
|
|
33
|
+
- **Decision locked in (no recursion).** Orchestrate runs at most **one** try-fix round per app. Stragglers land in `stillFailing` and the caller decides the next move. Keeps results predictable, preserves per-rule attribution, and avoids compound-round confusion. Upgrade path is bounded-by-progress retry, not an N-round cap.
|
|
34
|
+
- **Tests:** new `test/orchestrate.test.mjs` covers (1) dry-run reports planned order, (2) unknown profile error, (3) already-healthy short-circuit, (4) happy-path cascade reaches goal, (5) one try-fix round + stillFailing surfacing.
|
|
35
|
+
|
|
36
|
+
### Added (M39) — Polyglot dev-server discovery
|
|
37
|
+
|
|
38
|
+
- **T3a — Marker-file detectors for non-JS stacks.** `discoverApps` now detects Django (`manage.py` containing a `django` import), Rails (`bin/rails` + `Gemfile`), FastAPI (`fastapi` mention in `pyproject.toml` or `requirements.txt`), Go air (`.air.toml` or `air.toml`), and Rust trunk (`Trunk.toml`). Each profile gets a sensible default serve command (`python manage.py runserver`, `bin/rails server`, `uvicorn main:app --reload`, `air`, `trunk serve`) which can be overridden via `overrides.<name>.command`.
|
|
39
|
+
- **T3b — `DiscoveredApp.serverProfile`.** New optional field — `'angular'|'nx'|'vite'|'storybook'|'django'|'rails'|'fastapi'|'go-air'|'rust-trunk'`. Existing JS detectors now also tag their apps with `serverProfile` matching `workspaceType`. Polyglot apps get `workspaceType: 'polyglot'` + a specific `serverProfile`. The field is additive; v0.6 configs and snapshots still parse unchanged.
|
|
40
|
+
- **T3c — Polyglot parser hints.** `parseLine` gains serving / compiling / error patterns for Django (`Watching for file changes with StatReloader` → compiling, `Quit the server with CONTROL-C` → serving, `Traceback` + `File "..."` back-fill → error+location), Rails (`Puma starting`, `Use Ctrl-C to stop`, `ActionController::*` / `NameError(...)` + `file.rb:L:in` back-fill), FastAPI (`Uvicorn running on`, `Application startup complete`, ASGI tracebacks), Go air (`building...`, `running...`, `file.go:L:C:` location detection + `panic:` patterns), and Rust trunk (`error[E0425]` + `--> file.rs:L:C` back-fill). New `ParserTool` values: `django`, `rails`, `fastapi`, `go-air`, `rust-trunk`, `python`. Stack-trace locations now resolve `.py` / `.rb` / `.go` / `.rs` file extensions alongside JS/TS.
|
|
41
|
+
- **T3d — `daimon discover --explain` updates.** `/api/discovery/explain` (and `daimon discover --explain` / `daimon list --explain`) now annotate each detected app with `workspaceType` + `serverProfile` and append a `N polyglot app(s) found (django, fastapi, ...)` hint to the suggestion when any non-JS profile is present. The rejection-reason hint now also mentions `manage.py / Gemfile / pyproject.toml (fastapi) / .air.toml / Trunk.toml`.
|
|
42
|
+
- **Polyglot doctor rules (report-only).** Three new sibling rules to M36's `orphan-node-modules`: `orphan-venv` (Python — flags missing `.venv` / `venv` or one stamped older than `pyproject.toml` / `requirements.txt`), `orphan-bundler-cache` (Ruby — `vendor/bundle` missing or older than `Gemfile.lock`), `orphan-cargo-target` (Rust — `target/` missing or older than `Cargo.lock`). All three are **report-only** and emit a `would suggest: ...` paragraph — daimon never runs `pip install`, `bundle install`, or `cargo build`. Default `doctor.autoFix.permitted` extends to include them.
|
|
43
|
+
- **Parser corpus fixtures.** New `test/fixtures/parsers/{django,rails,fastapi,go-air,rust-trunk}.{log,expected.json}` covered by the existing M33 corpus test (≥95% capture rate + tool + status assertions).
|
|
44
|
+
- **Tests:** new `test/polyglot-discovery.test.mjs` covers each detector (strict markers — `manage.py` without `django` import is rejected; JS detector precedence on Vite + `manage.py`; JS apps still tagged with `serverProfile === workspaceType`).
|
|
45
|
+
- **Decisions locked in** (re-affirmed from PLAN-v0.7.md):
|
|
46
|
+
- Daimon **never invokes** `pip install`, `bundle install`, `cargo build`, `go mod download` — the polyglot orphan rules are report-only, never a shell-out.
|
|
47
|
+
- Polyglot detectors run **unconditionally** on every searchRoot, guarded by strict markers (`manage.py` must contain `django`, `pyproject.toml`/`requirements.txt` must declare `fastapi`) and JS precedence (`nx.json`/`angular.json`/vite/storybook detected first).
|
|
48
|
+
- No new `searchRoots[*].polyglot: true` opt-in is introduced.
|
|
49
|
+
|
|
50
|
+
### Added (M40) — TUI parity refresh
|
|
51
|
+
|
|
52
|
+
- **T6a — Shortcut alignment.** The Ink TUI now uses `/` for filter (the prior `t` tag-pick remains), `j`/`k` (in addition to `↑`/`↓`) for navigation, a `g <key>` chord that surfaces dashboard-style view hints (`g a` apps, `g e` errors, `g v` events, `g s` settings, `g n` sessions), and `r` requires a `y`/`n` snack-confirm before restarting — matching the dashboard's M35 anti-fatfinger behaviour. `o` (open URL) and `s` (start) are preserved. Stop is rebound to `S` (shift-S) because `x` now means try-fix (per T6c).
|
|
53
|
+
- **T6b — Per-app 20-cell event ribbon.** Each app row in the TUI gains a second line with a 20-cell ASCII bar (`▓▓░▒▓▓░░░░░░░░░░░░░░ srv·err·cmp·stp`) representing the last 60 minutes of status events, computed with the same algorithm as the dashboard's H5 ribbon. Glyphs: `▓` serving, `█` error, `▒` compiling/starting, `░` stopped, `·` empty bucket. Powered by the new `src/tui/ribbon.ts` helper (covered by `test/tui-ribbon.test.mjs`).
|
|
54
|
+
- **T6c — Focus / try-fix / orchestrate from the TUI.** New action keys on the selected app: `f` runs the M34 "focus until stable" wait (5s idle on serving + healthy, 180s budget) and surfaces the outcome in the footer status line; `x` runs `try-fix` (runAutoFix on the permitted rule set + restart + wait for healthy) and reports `fixed N` + reached/timeout; `O` (shift-O) opens an inline orchestrate dialog — type a profile name + Enter to run the M38 `orchestrateProfile` with `goal=healthy, timeoutMs=300_000` and see the result on the footer. All three call the in-process registry directly (no HTTP round-trip), so the TUI keeps working over SSH without network access.
|
|
55
|
+
- **T6d — Headless mode unchanged.** `--headless` + `config.headless: true` continue to skip the TUI entirely. No new daemon flags.
|
|
56
|
+
- **Footer status line.** A new auto-dismissing `[i] …` line surfaces the outcome of `f` / `x` / `O` actions (plus `r` confirm and `g <key>` view hints) for ~4 seconds — necessary because the TUI no longer relitigates ambient state when an in-flight action completes.
|
|
57
|
+
- **Tests:** new `test/tui-ribbon.test.mjs` covers the ribbon helper (60-min window, error-over-serving ranking, per-app filtering, glyph rendering, count aggregation).
|
|
58
|
+
|
|
59
|
+
## [0.6.0] — 2026-05-20
|
|
60
|
+
|
|
61
|
+
Strategic theme: **Every signal becomes actionable.** M33 deepens parser coverage so every tool's errors land structured; M34 turns daimon into a 3-call agent surface (overview → try-fix → focus); M35 ships keyboard / logs / ribbon polish; M36 broadens auto-heal with four new doctor rules and opt-in health-probe path discovery.
|
|
62
|
+
|
|
63
|
+
### Added (M33) — Parser depth
|
|
64
|
+
|
|
65
|
+
- **P1 — Parser corpus + tests.** New `test/fixtures/parsers/*.log` for Vite, Storybook, Jest, Nx, Angular esbuild, webpack, and Node native, each paired with a `.expected.json` of `{tool, status, errors:[{file,line,col,code}]}`. New `test/parser-corpus.test.mjs` replays every fixture through `parseLine` and asserts ≥95% capture rate on file-bearing lines plus tool tagging. Captures parser regressions in CI instead of via screenshots.
|
|
66
|
+
- **P2 — Multi-tool parsers.** `parseLine` now detects and tags errors from Vite (`[vite]`, `[plugin:vite:…]`, `transformWithEsbuild`), Storybook (`ERR!`, `builder-vite`), Jest (`FAIL <path>`, `● <test>`), Nx (`> NX … failed`, `Failed tasks:`), webpack (`Module not found:`, `ERROR in <path>[:L:C|<sp>L:C]`), Node native (`Error|TypeError|… at <file>:<L>:<C>`), and TSC-style `file(line,col): error TSnnn`. Parsed entries gain a new optional `tool` field (`ParserTool` in `types.ts`). Stack-trace style `(file:line:col)` locations are extracted and also back-fill the most-recent error entry that has no file.
|
|
67
|
+
- **P3 — Errors-panel grouping by tool.** Dashboard `Errors` page gains a fourth `Group by` tab: `tool`. Each tool group renders with a colored chip per tool (esbuild/vite → primary, jest/nx → secondary, storybook/webpack → tertiary, node/typescript → neutral) and lists per-app, per-file rows.
|
|
68
|
+
|
|
69
|
+
### Fixed (M33)
|
|
70
|
+
|
|
71
|
+
- **Webpack "compiled with N errors" no longer clears the error map.** The serving pattern was loosened to `webpack compiled (?:successfully|in)` so a build summary that includes errors does not transition the state to `serving` and wipe collected errors.
|
|
72
|
+
|
|
73
|
+
### Added (M34) — Agent-first surface
|
|
74
|
+
|
|
75
|
+
- **A1 — `daimon focus <app>`.** New CLI / HTTP / MCP verb. One round-trip subscribe-then-act over `POST /api/apps/:name/focus?until=serving|healthy|stable[&timeoutMs=]` that streams NDJSON events: `{kind:"subscribed"|"status"|"health"|"error"|"done", …}`. `--until stable` resolves when the app is serving + healthy with no event for ≥5s. Designed so an agent issues one MCP call and reads a coherent narrative instead of polling. CLI exits when the stream ends; MCP `focus` aggregates events into `{events, final}`.
|
|
76
|
+
- **A2 — `diff_errors` MCP tool.** Wraps the existing F2 `errors --since-last --client <id>` HTTP endpoint as a dedicated MCP tool with a `budget` (token) cap; overflow rows are dropped and reported as `_meta.omitted`. Compact `{file,line,col,code,tool,message}` per entry.
|
|
77
|
+
- **A3 — `daimon try-fix <app>`.** New CLI / HTTP / MCP verb. `POST /api/apps/:name/try-fix?until=…` composes `runAutoFix` (permitted rules), `registry.restart(name)`, and `registry.waitFor(name, until)`, then returns `{before:{status,health,errCount,firstError}, after:{status,health,errCount}, fixed:[ruleName], stillFailing:[…first 5 parsed errors], reached, waitedMs}`. Never edits user source — only daemon state, exactly as the F58 rules already did.
|
|
78
|
+
- **A4 — `daimon overview --budget <tokens>`.** Both the HTTP endpoint and the CLI accept a token budget. Rows past the budget are dropped from `needsAttention` first, then `recentlyChanged`, with the counts reported as `_meta.omitted.{needsAttention,recentlyChanged}`. Makes the session-opener predictable for agents.
|
|
79
|
+
- **Test:** new `test/overview-budget.test.mjs` covers the truncation invariants (no-op under-budget, truncates over-budget, no-op on empty input).
|
|
80
|
+
|
|
81
|
+
### Added (M35 partial) — Dashboard depth
|
|
82
|
+
|
|
83
|
+
- **H2 — Keyboard shortcuts realigned with the v0.6 spec.** `g e` now jumps to **Errors** (was Events; Events moved to `g v`). `g s` now jumps to **Settings** (alias of `/config`; the previous `g s` → Sessions moved to `g n`). The legacy `g r` → Errors and `g c` → Settings bindings remain as aliases for muscle memory. `r` (restart focused app) now requires a snack-bar confirm before firing, eliminating accidental restarts during keyboard navigation.
|
|
84
|
+
- **H4 — Logs page: regex filter + jump-to-next-error.** A `.* regex` toggle on the filter bar switches between substring and regex matching (case-insensitive). Invalid patterns surface inline (`mat-icon warning` + parser message) instead of throwing. A `Next error` button scrolls the virtual viewport to the next `severity === 'error'` row from the current visible end, wrapping to the top.
|
|
85
|
+
- **H5 — Per-app event ribbon.** Each card on `Apps` gains a 6px ribbon between the workspace-tone accent and the status row, showing the last 60 minutes of status events as 20 colored buckets (primary tint = serving, error = error, tertiary = compiling/starting, outline-variant = stopped). Hover shows a `last 60 min: 5 serving · 2 error` summary. Empty for apps with no recent transitions.
|
|
86
|
+
|
|
87
|
+
### Deferred (M35 → v0.6.1)
|
|
88
|
+
|
|
89
|
+
- **H1 — Vitest + Playwright dashboard tests.** Adds non-trivial dev-deps (Vitest + Playwright + Angular bridge config), a fixture-daemon harness, and per-component specs. Out of scope for the v0.6.0 weekend; will land in v0.6.1.
|
|
90
|
+
- **H3 — WCAG AA contrast audit.** Needs visual inspection across all M3 tonal surfaces under light + dark + reduced-motion. Pushed to v0.6.1 alongside H1; reduced-motion path from M30 is already verified.
|
|
91
|
+
|
|
92
|
+
### Fixed (M35 follow-up) — Initial-route bundle back under budget
|
|
93
|
+
|
|
94
|
+
- **Initial-route gzip transfer: 126.01 KB** (down from 151 KB at v0.5 HEAD; well under the 130 KB v0.6 ceiling). Achieved with three surgical lazy-loads, no functional change:
|
|
95
|
+
- `MatDialog` import is now dynamic — the keyboard `?` help dialog imports `@angular/material/dialog` only when triggered.
|
|
96
|
+
- `<dm-command-palette>` is wrapped in `@defer (when paletteActivated())`; the palette mounts on first `Ctrl/⌘+K`, and the activation handler re-dispatches the `daimon:cmdk` event so the user only presses the chord once.
|
|
97
|
+
- `MatMenu`-based dropdowns in `dm-topbar` and `dm-theme-toggle` are replaced with native-button + `@if` popovers (`HostListener('document:click')` for outside-click close). Removes `MatMenuModule` + CDK overlay/portal from the initial chunk.
|
|
98
|
+
- `MatSnackBar` is no longer eager in `dm-topbar`; `runProfile()` now uses a small inline DOM toast (positioned via `mat-sys-inverse-surface` tokens to stay in M3). The apps-list (route-lazy) keeps `MatSnackBar` for the `r` restart confirm — that import lives in its own lazy chunk.
|
|
99
|
+
- Bundle structure delta: `MatDialog`/`MatMenu`/`MatSnackBar`/Overlay+Portal moved out of eager into either a deferred chunk or are absent. No functional regression: the help dialog still opens on `?`, the palette still opens on `⌘K`, the workspace + profile dropdowns still work, and the runProfile toast still appears.
|
|
100
|
+
|
|
101
|
+
### Added (M36) — Auto-heal expansion
|
|
102
|
+
|
|
103
|
+
- **E1 — Health-probe path auto-discovery.** On first `serving` (when there is no `overrides.<name>.url`, no `overrides.<name>.healthProbePath`, and the global `healthProbe.path` is the default `/`), the monitor runs one in-flight scan against `['/', '/health', '/-/health', '/api/health', '/ready', '/healthz']`, taking the first strictly-2xx response. The discovered path is stored on `AppState.discoveredHealthPath` and an event is recorded: `discovered probe path: /health (pin via POST /api/apps/<name>/health/pin or daimon pin-health <name> --accept)`. The discovery is used by subsequent probes immediately, but **persistence is opt-in** — nothing is written to `daimon.config.json` until the user accepts.
|
|
104
|
+
- **`daimon pin-health <name> [--accept] [--path <p>]` + `POST /api/apps/:name/health/pin`.** Without `--accept` the CLI just reports the discovered candidate; with `--accept` it writes `overrides.<name>.healthProbePath` to the active `daimon.config.json` and triggers soft-reload. `AppOverride.healthProbePath` is a new optional field; v0.5 configs continue to load unchanged.
|
|
105
|
+
- **E2 — Four new doctor rules** added to `daimon doctor --auto-fix`:
|
|
106
|
+
- `port-conflict-pred` — predicts which configured `portRange` endpoints + pinned ports are already in LISTEN. Reports only; no kill.
|
|
107
|
+
- `node-version-mismatch` — compares `.nvmrc` then `package.json#engines.node` against `process.versions.node`. Reports only; switching Node versions stays a user action.
|
|
108
|
+
- `orphan-node-modules` — flags `searchRoots` whose `package.json` exists but `node_modules` is missing, or older than `package-lock.json` / `pnpm-lock.yaml` / `yarn.lock`. Per locked decision in PLAN-v0.6.md, daimon **never runs npm/pnpm/yarn install** — the rule emits a `would suggest: (cd ... && npm install)` paragraph instead.
|
|
109
|
+
- `dead-search-root` — finds `searchRoots` that no longer resolve on disk and removes them from the config file (with a soft-reload), printing a `to undo: re-add` paragraph.
|
|
110
|
+
- All four rules are added to `ALL_AUTO_FIX` and to the default `doctor.autoFix.permitted` list. v0.5 configs whose `permitted` list is shorter are honored as-is — the new rules just don't activate for them.
|
|
111
|
+
- **Test:** `test/autofix-rules.test.mjs` asserts the new rule names are present in `ALL_AUTO_FIX` and the original M28 rules are still listed (backwards-compat smoke).
|
|
112
|
+
|
|
7
113
|
## [0.5.0] — 2026-05-19
|
|
8
114
|
|
|
9
115
|
Strategic theme: **Claude path first. Dashboard second. Auto-heal everywhere.**
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Daimon
|
|
2
2
|
|
|
3
|
-
A local manager for Angular / Nx / Vite / Storybook
|
|
3
|
+
A local manager for dev servers: Angular / Nx / Vite / Storybook out of the box, plus Django / Rails / FastAPI / Go-air / Rust-trunk (v0.7). One daemon owns all your `serve` processes, auto-assigns ports, dedup'd error captures across every supported tool, exposes a loopback HTTP API + JSON CLI + MCP server. Built so you and Claude Code can both query app state without parsing thousands of log lines.
|
|
4
4
|
|
|
5
5
|
Loopback only. Single user. No cloud. No telemetry.
|
|
6
6
|
|
|
@@ -69,10 +69,10 @@ The daemon auto-spawns on the first `daimon` call that needs it. To suppress: `D
|
|
|
69
69
|
## CLI
|
|
70
70
|
|
|
71
71
|
```bash
|
|
72
|
-
daimon list [--tag <name>] [--workspace <label>]
|
|
73
|
-
daimon status <name>
|
|
72
|
+
daimon list [--tag <name>] [--workspace <label>] [--explain] [--full] [--stream]
|
|
73
|
+
daimon status <name> [--full]
|
|
74
74
|
daimon errors <name> [--since 2m] [--since-last] [--client <id>] [--structured]
|
|
75
|
-
daimon events [--since 1h] [--app <name>]
|
|
75
|
+
daimon events [--since 1h] [--app <name>] [--stream]
|
|
76
76
|
daimon wait <name> [--until serving|healthy|stopped|error] [--timeout 60s]
|
|
77
77
|
daimon logs <name> [--tail N] [--since 30s]
|
|
78
78
|
daimon start <name> [--with-deps]
|
|
@@ -80,39 +80,59 @@ daimon stop <name>
|
|
|
80
80
|
daimon restart <name>
|
|
81
81
|
daimon up [<profile>] # topological start; waits for each level to reach healthy
|
|
82
82
|
daimon down [<profile>]
|
|
83
|
+
daimon overview [--workspace <label>] [--profile <name>] [--budget <tokens>] # decision-ready snapshot
|
|
84
|
+
daimon ensure <name> [--until serving|healthy] [--timeout 60s]
|
|
85
|
+
daimon ensure-up <profile> [--until serving|healthy] [--timeout 60s]
|
|
86
|
+
daimon focus <name> [--until serving|healthy|stable] [--timeout 180s] # one-shot subscribe-then-act (v0.6)
|
|
87
|
+
daimon try-fix <name> [--until healthy] [--timeout 60s] # doctor + restart + wait (v0.6)
|
|
88
|
+
daimon orchestrate <profile> [--goal serving|healthy|stable] [--dry-run] [--budget <tokens>] # whole-workspace bring-up (v0.7)
|
|
89
|
+
daimon trends <name> --metric compile|bundle|errors|restarts [--since 24h|7d|30d] # history time-series (v0.7)
|
|
90
|
+
daimon discover [--explain] [--dry-run] # what daimon would (or did) detect
|
|
91
|
+
daimon why-empty # alias of `daimon list --explain`
|
|
83
92
|
daimon history <name> # uptime%, restart count, compile p50/p95, top errors
|
|
84
|
-
daimon why <name> # last transition + 5 preceding events
|
|
93
|
+
daimon why <name> # last transition + 5 preceding events
|
|
85
94
|
daimon tasks <name> # discovered non-serve tasks
|
|
86
95
|
daimon run <name> <task> [--watch] [-- args...]
|
|
87
96
|
daimon snapshot <name> # bundle state for bug reports
|
|
88
97
|
daimon env <name> [--use <file>] # env-file switcher
|
|
89
98
|
daimon clean <name> [--deep] [--yes]
|
|
90
99
|
daimon record / replay
|
|
91
|
-
daimon doctor
|
|
100
|
+
daimon doctor [--auto-fix] [--dry-run] # config sanity checks + rule-based self-repair (v0.5+)
|
|
101
|
+
daimon pin-health <name> [--accept] [--path <p>] # opt-in health-probe path discovery (v0.6)
|
|
102
|
+
daimon export-config [--redacted] # paste-ready config for bug reports
|
|
92
103
|
daimon free-port <port> [--force]
|
|
93
|
-
daimon init
|
|
104
|
+
daimon init [--auto] # interactive (or non-interactive) config scaffolder
|
|
94
105
|
```
|
|
95
106
|
|
|
96
|
-
All CLI commands print compact JSON on stdout. Errors are compact JSON on stderr with non-zero exit. Exit codes: `0` success, `1` generic error, `2` timeout (used by `daimon wait`).
|
|
107
|
+
All CLI commands print compact JSON on stdout by default (`--full` for the verbose v0.4 shape). Errors are compact JSON on stderr with non-zero exit. Exit codes: `0` success, `1` generic error, `2` timeout (used by `daimon wait`, `daimon focus`, `daimon ensure*`).
|
|
97
108
|
|
|
98
109
|
## HTTP API
|
|
99
110
|
|
|
100
|
-
Bound to `127.0.0.1:<apiPort>` only. The dashboard at `/`
|
|
111
|
+
Bound to `127.0.0.1:<apiPort>` only. The dashboard at `/` is an Angular 20 SPA (Material 3, zoneless, signals) bundled into the published tarball — it shows apps, errors grouped by file/app/tool, live logs, doctor, trends (v0.7), settings editor, and one-click actions.
|
|
101
112
|
|
|
102
113
|
```
|
|
103
|
-
GET /api/apps
|
|
114
|
+
GET /api/apps # compact by default; ?format=full for v0.4 shape
|
|
104
115
|
GET /api/apps/:name
|
|
105
116
|
GET /api/apps/:name/errors[?since=2m]
|
|
106
117
|
GET /api/apps/:name/errors/since-last?client=<id>
|
|
107
118
|
GET /api/apps/:name/logs?tail=N&since=30s
|
|
108
|
-
GET /api/apps/:name/logs/stream
|
|
119
|
+
GET /api/apps/:name/logs/stream # Server-Sent Events
|
|
109
120
|
GET /api/apps/:name/wait?until=serving&timeout=60
|
|
110
|
-
GET /api/events?since=5m&app=<name
|
|
121
|
+
GET /api/events[?since=5m&app=<name>&stream=ndjson]
|
|
122
|
+
GET /api/overview[?budget=<tokens>&workspace=&profile=] # v0.5
|
|
123
|
+
GET /api/discovery/explain # v0.5
|
|
111
124
|
GET /api/history/{events,compile-times,tasks,summary/:name,why/:name}
|
|
112
|
-
GET /api/
|
|
125
|
+
GET /api/history/trends?app=&metric=&since= # v0.7
|
|
126
|
+
GET /api/history/bundles?app= # v0.7
|
|
127
|
+
GET /api/config # current config (env redacted)
|
|
113
128
|
POST /api/apps/:name/(start|stop|restart|snapshot|clean|run/:task)
|
|
114
|
-
|
|
115
|
-
POST /api/
|
|
129
|
+
POST /api/apps/:name/focus?until=… # NDJSON event stream (v0.6)
|
|
130
|
+
POST /api/apps/:name/try-fix?until=… # v0.6
|
|
131
|
+
POST /api/apps/:name/health/pin # v0.6 (with --accept)
|
|
132
|
+
POST /api/orchestrate?profile=&goal=&timeoutMs=&dryRun=&budget= # v0.7
|
|
133
|
+
POST /api/doctor/auto-fix[?dryRun=true]
|
|
134
|
+
PATCH /api/config # If-Match: <etag>; 412 on conflict
|
|
135
|
+
POST /api/config/reload # soft reload — no running children killed
|
|
116
136
|
POST /api/shutdown
|
|
117
137
|
```
|
|
118
138
|
|
|
@@ -121,34 +141,28 @@ If `config.apiToken` is set, mutating endpoints require `Authorization: Bearer <
|
|
|
121
141
|
## Claude Code integration
|
|
122
142
|
|
|
123
143
|
```bash
|
|
124
|
-
daimon claude install
|
|
125
|
-
# or pick: --skill, --commands, --agent
|
|
126
|
-
# or interactive: daimon claude install
|
|
144
|
+
daimon claude install # writes a single SKILL.md (no per-command slash files since v0.5)
|
|
127
145
|
```
|
|
128
146
|
|
|
129
|
-
|
|
147
|
+
Daimon installs a single skill at `~/.claude/skills/daimon/SKILL.md` (~120 useful tokens) that documents every verb inline. Old per-command `~/.claude/commands/daimon-*.md` files from v0.3/v0.4 are removed (or renamed to `.bak` if you've edited them since install). An optional `~/.claude/agents/daimon-runner.md` subagent can be installed with `--agent`.
|
|
130
148
|
|
|
131
|
-
|
|
132
|
-
- **Slash commands** at `~/.claude/commands/daimon-{status,start,stop,restart,errors,logs,up,doctor,why,wait}.md`.
|
|
133
|
-
- **Subagent** at `~/.claude/agents/daimon-runner.md` — specialized dev-loop orchestrator.
|
|
134
|
-
|
|
135
|
-
Templates are rendered from a single source of truth (`src/cliSurface.ts`), so they cannot drift from the actual command surface.
|
|
149
|
+
The skill is rendered from a single source of truth (`src/cliSurface.ts`) so it cannot drift from the actual command surface.
|
|
136
150
|
|
|
137
151
|
Daimon stamps the current version into the artifact frontmatter. When you upgrade daimon, the next CLI call nudges you (once per 24h) to run `daimon claude update`. Silence with `DAIMON_NO_CLAUDE_NUDGE=1`.
|
|
138
152
|
|
|
139
153
|
```bash
|
|
140
154
|
daimon claude status # what's installed and at which version
|
|
141
155
|
daimon claude update # refresh based on the install manifest
|
|
142
|
-
daimon claude uninstall
|
|
156
|
+
daimon claude uninstall
|
|
143
157
|
```
|
|
144
158
|
|
|
145
|
-
For raw MCP use
|
|
159
|
+
For raw MCP use:
|
|
146
160
|
|
|
147
161
|
```bash
|
|
148
162
|
claude mcp add daimon -- daimon mcp
|
|
149
163
|
```
|
|
150
164
|
|
|
151
|
-
The MCP server exposes: `list_apps`, `get_status`, `get_errors`, `get_logs`, `start_app`, `stop_app`, `restart_app`, `wait_for_app`.
|
|
165
|
+
The MCP server exposes: `list_apps`, `get_status`, `get_errors`, `get_logs`, `start_app`, `stop_app`, `restart_app`, `wait_for_app`, plus the agent-first verbs added in v0.5–v0.7: `overview`, `ensure`, `ensure_up`, `focus`, `try_fix`, `diff_errors`, `orchestrate`. The recommended session opener is `overview` (compact-by-default, token-budgetable); the recommended one-call workspace bring-up is `orchestrate <profile> goal=stable`.
|
|
152
166
|
|
|
153
167
|
## State files (in `~/.daimon/`)
|
|
154
168
|
|
|
@@ -156,7 +170,7 @@ The MCP server exposes: `list_apps`, `get_status`, `get_errors`, `get_logs`, `st
|
|
|
156
170
|
- `daemon.lock` — `{ pid, apiPort, version, startedAt, headless }`
|
|
157
171
|
- `state.json` — sticky port assignments
|
|
158
172
|
- `cursors.json` — per-client error cursors for `--since-last`
|
|
159
|
-
- `history.db` — SQLite of events, compile times, task runs
|
|
173
|
+
- `history.db` — SQLite of events, compile times, task runs, and per-app bundle sizes (the last powers the v0.7 Trends dashboard)
|
|
160
174
|
- `logs/<name>.log[.N]` — when `logs.enabled` is true
|
|
161
175
|
- `snapshots/<name>-<ts>.json` — `daimon snapshot` output
|
|
162
176
|
- `notifications.log` — desktop notification audit
|
|
@@ -183,7 +197,7 @@ The `summary.url` field returned by the API was synthetic `http://127.0.0.1:<por
|
|
|
183
197
|
npm test
|
|
184
198
|
```
|
|
185
199
|
|
|
186
|
-
|
|
200
|
+
60 `node:test` cases across small focused files: dependency-graph math, bundle parsing, notifier throttling, compile-time regression, the parser fixture corpus (Vite/Storybook/Jest/Nx/Angular esbuild/webpack/Node/Django/Rails/FastAPI/Go-air/Rust-trunk — see `test/fixtures/parsers/`), `overview` budget truncation, auto-fix rule registry, `orchestrate` dry-run/cascade/try-fix paths, polyglot discovery (strict markers + JS precedence), and the TUI ribbon helper. No vitest dependency. The dashboard's Vitest + Playwright layer is deferred to v0.7.1.
|
|
187
201
|
|
|
188
202
|
## License
|
|
189
203
|
|