daimon 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +109 -0
- package/README.md +43 -29
- package/dist/cli.js +187 -74
- package/dist/dashboard/browser/{chunk-NN2YNLGP.js → chunk-2BXIFQGQ.js} +1 -1
- package/dist/dashboard/browser/chunk-3WKRVGPT.js +3 -0
- package/dist/dashboard/browser/chunk-44JIQO3X.js +1 -0
- package/dist/dashboard/browser/chunk-4BAKWDAV.js +1 -0
- package/dist/dashboard/browser/chunk-4OCNYL7T.js +1 -0
- package/dist/dashboard/browser/chunk-6WZJCF24.js +1 -0
- package/dist/dashboard/browser/chunk-7C772RJ3.js +3 -0
- package/dist/dashboard/browser/{chunk-7L4DWDGL.js → chunk-7NPLP3QD.js} +1 -1
- package/dist/dashboard/browser/{chunk-L63FHXGH.js → chunk-7NRE3SNA.js} +3 -3
- package/dist/dashboard/browser/chunk-A4BNXJUT.js +1 -0
- package/dist/dashboard/browser/{chunk-UNT27XFJ.js → chunk-CILFSVSP.js} +1 -1
- package/dist/dashboard/browser/chunk-CM4RQF3A.js +5 -0
- package/dist/dashboard/browser/chunk-CNSXWFDX.js +1 -0
- package/dist/dashboard/browser/chunk-CY5YRTQK.js +1 -0
- package/dist/dashboard/browser/{chunk-ESDYJ3BP.js → chunk-EIWOTZT3.js} +1 -1
- package/dist/dashboard/browser/chunk-GYWEXV2L.js +3 -0
- package/dist/dashboard/browser/chunk-H2N3RBHF.js +1 -0
- package/dist/dashboard/browser/chunk-H3L4MTG4.js +5 -0
- package/dist/dashboard/browser/chunk-I65I7J5Q.js +2 -0
- package/dist/dashboard/browser/chunk-K7S4ITPJ.js +2 -0
- package/dist/dashboard/browser/chunk-KL6X73FV.js +1 -0
- package/dist/dashboard/browser/chunk-KLH6B22T.js +1 -0
- package/dist/dashboard/browser/{chunk-U6AY7XZK.js → chunk-LBL7Z5BE.js} +4 -4
- package/dist/dashboard/browser/chunk-LHAMBNO6.js +1 -0
- package/dist/dashboard/browser/chunk-NX6DTO32.js +1 -0
- package/dist/dashboard/browser/chunk-OHX55ZU4.js +2 -0
- package/dist/dashboard/browser/chunk-P5IE6DI6.js +2 -0
- package/dist/dashboard/browser/chunk-P5IU57TV.js +2 -0
- package/dist/dashboard/browser/{chunk-VZ6E4VQY.js → chunk-Q772THBA.js} +1 -1
- package/dist/dashboard/browser/chunk-QSBOKS53.js +3 -0
- package/dist/dashboard/browser/chunk-V2KNRAE4.js +4 -0
- package/dist/dashboard/browser/{chunk-4ZR4NTJW.js → chunk-VM2FOT77.js} +1 -1
- package/dist/dashboard/browser/index.html +1 -1
- package/dist/dashboard/browser/main-4CQTBXSB.js +1 -0
- package/dist/main.js +70 -51
- package/dist/mcp.js +3 -3
- package/package.json +2 -2
- package/src/templates/claude/skill.md.tmpl +4 -1
- package/src/templates/plugins/example-doctor.mjs +45 -0
- package/dist/dashboard/browser/chunk-4VNZXWQZ.js +0 -3
- package/dist/dashboard/browser/chunk-BLNPJ4WD.js +0 -4
- package/dist/dashboard/browser/chunk-E3HUMJ6S.js +0 -6
- package/dist/dashboard/browser/chunk-EBOHC6KX.js +0 -1
- package/dist/dashboard/browser/chunk-JUZHAE4L.js +0 -2
- package/dist/dashboard/browser/chunk-K46KCL6L.js +0 -1
- package/dist/dashboard/browser/chunk-KDCKLTCZ.js +0 -1
- package/dist/dashboard/browser/chunk-MHOSWLRR.js +0 -3
- package/dist/dashboard/browser/chunk-N5GRSTMJ.js +0 -6
- package/dist/dashboard/browser/chunk-R6J2WYUD.js +0 -1
- package/dist/dashboard/browser/chunk-T2YKGOEM.js +0 -3
- package/dist/dashboard/browser/chunk-V2CQL6W5.js +0 -1
- package/dist/dashboard/browser/chunk-WJUGRIIZ.js +0 -1
- package/dist/dashboard/browser/chunk-WRBP4DQN.js +0 -4
- package/dist/dashboard/browser/chunk-XUU4AY4M.js +0 -2
- package/dist/dashboard/browser/chunk-XYVF5I5T.js +0 -1
- package/dist/dashboard/browser/main-ZADV4SOC.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,115 @@ All notable changes to Daimon are documented here. The format follows [Keep a Ch
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.8.0] — 2026-05-20
|
|
8
|
+
|
|
9
|
+
Strategic theme: **Mature daimon.** v0.5–v0.7 added enormous surface; v0.8 turns inward to polish the surface and harden the internals — a big CLI polish, a reliability pass, self-observability, and a plug-in surface for doctor rules, plus a first-class Tests page that finally lands part of the v0.7.1 dashboard-test debt (H3 contrast audit deferred again to v0.8.1).
|
|
10
|
+
|
|
11
|
+
### Added (M45) — Tests dashboard + H1 carry-over
|
|
12
|
+
|
|
13
|
+
- **T1 — Structured `test`-target summaries.** `parseTaskSummary` (in `src/taskRunner.ts`) now recognizes seven runners: Jest, Vitest, Karma, Playwright, pytest, RSpec, `cargo test`, and `go test` (the last sums multi-package `ok|FAIL pkg D.DDDs` lines). Output shape is now `{ passed, failed, total, suites?, durationMs?, framework, failedTests? }`. `failedTests` captures `{ name, file, line }` from the per-runner failure formatting and is the source of the dashboard's failed-test jumper. `task_runs.summary` continues to be a JSON blob — the new fields are additive.
|
|
14
|
+
- **T2 — `Tests` dashboard route (`/tests`).** New lazy-loaded route. One expansion-panel per app with at least one `test`-named run in the last 30 days. Title row carries an OK / FAIL pill + `passed/total · N failed` label + framework + duration + "<N>m ago" + run count. Body shows a 30-row pass/fail trend ribbon (one tick per run) and, when the most-recent run failed, an inline list of failed tests.
|
|
15
|
+
- **T3 — Failed-test jumper.** Each failed-test row that carries a `{ file, line? }` payload renders a clickable `vscode://file/<path>:<line>` link, identical scheme to the M22 errors panel.
|
|
16
|
+
- **T4 — Nav + shortcut.** New `/tests` entry on the nav rail (`science` icon) and `g x` keyboard chord, alongside the existing `g t`/`g h`/etc. shortcuts.
|
|
17
|
+
- **H1 (carry-over — third schedule slot, partial).** Vitest harness shipped at `dashboard/vitest.config.ts`. Five specs in `dashboard/src/app/tests-page.spec.ts` cover the pure signal-bearing logic — `parseSummary`, `vscodeUri`, `summaryLabel`, `pillKindFor` — extracted into `tests-page-helpers.ts` to keep them runtime-independent. `dashboard/package.json` `test` script is now `vitest run` (no `ng test --watch=false` blocker). The deeper per-component render coverage requires an Angular-linker preset (e.g. `@analogjs/vitest-angular`) — that preset has been moved to v0.9 to keep M45 inside one weekend. Playwright smoke similarly deferred. See `PLAN-v0.8.md` Status section for the trade-off.
|
|
18
|
+
- **H3 — WCAG AA contrast audit.** Deferred to v0.8.1 per the locked descope path (`"If M45 grows, drop H3 first"`). M3 surface-tonal defaults from v0.7 still apply; the dedicated AA sweep across light + dark + reduced-motion remains a focused future pass.
|
|
19
|
+
- **Test surface.** New `test/task-summary.test.mjs` asserts the parser for jest / vitest / pytest / rspec / cargo / go / playwright / null. `dashboard/src/app/tests-page.spec.ts` exercises the five tests-page helpers under Vitest.
|
|
20
|
+
|
|
21
|
+
### Added (M44) — Plug-in surface for doctor rules
|
|
22
|
+
|
|
23
|
+
- **P1 — Plug-in loader.** New `src/plugins.ts`. On daemon start, daimon scans `~/.daimon/plugins/doctor-*.mjs` (configurable via `plugins.dir` in `daimon.config.json`). Each file is dynamically imported with a cache-busting query string so plug-ins can be hot-edited and reloaded by restarting the daemon. Files that fail to import (or fail shape validation) are logged as `[daimon] plug-in skipped: <file> — <reason>` and never crash the daemon.
|
|
24
|
+
- **P2 — Typed `DoctorPlugin` interface.** Defaults to a read-only `scan(ctx)`. Optional `fix(finding, ctx)` and `undo(finding, ctx)`. `DoctorContext` exposes `{ config, apps, history.querySelfMetrics, mutations }` — the `mutations` surface is intentionally narrow and re-uses the M36 mutation primitives (no shell-out, no package-manager calls, no edits to user source).
|
|
25
|
+
- **P3 — Permission gating is fully opt-in.** No plug-in's `fix` ever runs unless its `name` is in `doctor.autoFix.permitted` — the same gate built-in rules use. This applies uniformly to the bundled sample (`src/templates/plugins/example-doctor.mjs`) and to any user-authored plug-in. The loader does **not** track plug-in origin; there is no "bundled / trusted" branch. The loader also rejects names that collide with built-in rules or with another plug-in already loaded in the same pass.
|
|
26
|
+
- **P4 — `daimon plugin list|show <name>|validate <path>`.** New CLI subcommands. `list` returns installed plug-ins with `{name, description, file, status, error, findings}`. `show <name>` prints one plug-in's manifest + last-run findings. `validate <path>` sanity-checks a plug-in file *without* loading it into the running daemon (useful during development). New HTTP endpoints: `GET /api/plugins`, `POST /api/plugins/scan`.
|
|
27
|
+
- **P5 — Sample plug-in template.** `src/templates/plugins/example-doctor.mjs` ships in the tarball (~1.8 KB). Demonstrates a complete `scan` + `fix` cycle with the one-line opt-in instruction. Used as the on-ramp for the permission model — the comment block documents the exact `permitted: [..., 'example-doctor']` line a user must add to enable the `fix`.
|
|
28
|
+
- **P6 — Dashboard surfacing.** Doctor page gains a "Custom rules" section. One card per plug-in with a status chip (`ok` / `failed`), description, file path, error detail (when failed), and per-finding rows with severity chips. Errors surface in the card header. Reuses existing M3 token styling — no new tokens.
|
|
29
|
+
- **P7 — Skill text update.** `~/.claude/skills/daimon/SKILL.md` now lists `daimon plugin list|show|validate`, `daimon self`, `daimon doctor --self`, and `daimon completion` so agents can document a workspace's plug-in surface when asked.
|
|
30
|
+
- **Decisions locked in.** Plug-in surface in v0.8 is **doctor-only** — parser-hint and event-hook plug-ins are deferred to v0.9+ until real-world plug-ins inform the right shape.
|
|
31
|
+
- **Test surface.** New `test/plugins.test.mjs` asserts (1) only `doctor-*.mjs` files are picked up, (2) malformed plug-ins are reported as failed without crashing the loader, (3) names that collide with built-ins are rejected, (4) `runPluginScans` populates `lastFindings` and survives a throwing scan by quarantining the plug-in, and (5) `validatePluginFile` works standalone.
|
|
32
|
+
|
|
33
|
+
### Added (M43) — Self-observability
|
|
34
|
+
|
|
35
|
+
- **O1 — `GET /api/self`.** New endpoint returning daimon's own metrics: `{ pid, version, uptimeMs, rssMB, heapUsedMB, heapTotalMB, eventLoopLagMs, eventLoopLagP95Ms, historyDbQueryMs:{p50,p95,p99}, lockContentionCount, tickIntervalMs, lastTickAt }`. Backed by a new `SelfMetricsCollector` (in `src/selfMetrics.ts`) that probes event-loop lag with a 1s `setInterval` delta and rolls a 60-sample sliding window. `lockContentionCount` and the `historyDbQueryMs` percentiles are wired through call-site instrumentation (additive).
|
|
36
|
+
- **O2 — `daimon doctor --self`.** New `--self` flag on `daimon doctor` runs self-checks: heap above 256 MB, event-loop lag p95 above 100 ms, history-db query p95 above 50 ms. Reports findings in the same `{ok, checks, metrics}` shape as the existing F58 doctor rules. Read-only by design (no auto-fix — self issues require a daemon restart or config tuning).
|
|
37
|
+
- **O3 — `self_metrics` table in history.db.** New `self_metrics(id, ts, rssMB, heapUsedMB, eventLoopLagMs, historyQueryP95Ms)` table created by the existing `CREATE TABLE IF NOT EXISTS` migration — v0.7 databases upgrade in place. The daemon persists one row per minute via the new `History.recordSelfMetric`. Retention follows the existing `history.retentionDays` policy. `daimon snapshot <name>` carries the last 60 rows as `payload.selfMetrics` for diagnostic context.
|
|
38
|
+
- **O4 — Self chart on the Trends dashboard route.** New "Apps / Self" toggle on `/trends`. When **Self** is selected, an additional `dm-trend-chart` card renders rssMB / heapUsedMB / eventLoopLagMs as line series from `/api/self/history`. Reuses the existing chart.js lazy chunk — initial-route gzip stays at **126.46 KB** (v0.7 baseline 126.45 KB, ceiling 130 KB).
|
|
39
|
+
- **O5 — Self-warn events.** When the event-loop lag exceeds 100 ms for ≥5 consecutive ticks, `SelfMetricsCollector` emits a synthetic `{ app:'__daemon__', type:'self-warn', message:'event loop lag sustained: <N>ms (<K> consecutive ticks)' }` event. Surfaces on the existing Events feed alongside per-app events. New `'self-warn'` value in `AppEventType`; the loader only re-fires on rising-edge transitions to avoid flooding.
|
|
40
|
+
- **Test surface.** New `test/self-metrics.test.mjs` asserts (1) `snapshot()` returns plausible pid/version/rss/heap/uptime/lag numbers, (2) `recordQueryMs` correctly feeds the p50/p95/p99 percentile estimates, and (3) the self-warn setter is wired without throwing.
|
|
41
|
+
|
|
42
|
+
### Added (M42) — Reliability pass
|
|
43
|
+
|
|
44
|
+
- **F1 — Parser fuzz tests.** New `test/parser-fuzz.test.mjs` feeds 2,000 deterministically-random mixed-ANSI / multibyte / lone-surrogate / multiline-fragment lines into `parseLine`. Asserts no exceptions, no >10ms slow tail above 2% of iterations, and total time <10s per run. Two regression cases cover empty / whitespace / ANSI-only input and lone surrogate halves.
|
|
45
|
+
- **F2 — History.db stress test.** New `test/history-stress.test.mjs` inserts 100,000 events + 50,000 compile rows + 10,000 bundle rows into a temp sqlite (flushing in 5k-row batches via a new `History._flushForTest()` escape hatch), then queries `/api/history/trends` for every (metric × window × app) combination across three passes. Asserts trends p95 <50ms, p99 <200ms, db size <50MB.
|
|
46
|
+
- **F4 — Lock-file contention.** New `test/lock-contention.test.mjs` isolates `~/.daimon` via temp `HOME`/`USERPROFILE`, then asserts (1) `readLock` tolerates missing/corrupt files, (2) it prunes stale locks pointing at dead PIDs, and (3) parallel `writeLock` calls leave exactly one parseable JSON lock — atomic rename never produces a partial payload.
|
|
47
|
+
- **F5 — Error-map TTL.** New optional `errorRetention.maxAgeMs` config (default `86400000` — 24h) prunes `AppState.errors` entries older than `maxAgeMs` and not seen since. A new `Registry.pruneOldErrors()` walks every app's error map; the daemon wires it on an hourly tick in `main.ts`. Prevents unbounded growth in long-running daemons.
|
|
48
|
+
- **F6 — Log buffer cap audit.** New regression in `test/reliability.test.mjs` exercises the per-app `logBuffer` with a 10,000-line burst and asserts the rolling window stays at `LOG_BUFFER_MAX` and contains exactly the latest 500 lines.
|
|
49
|
+
- **F3 — Daemon crash auto-recovery soak (manual).** Documented in `test/SOAK.md` — 30-iteration kill-and-respawn loop with assertions on orphan PIDs and stale-lock pruning. Not run in CI (would dominate suite budget).
|
|
50
|
+
- **F7 — Memory soak (manual).** Documented in `test/SOAK.md` — 24h procedure with 5 simulated apps, capturing baseline RSS via `daimon self` and the new M43 `self_metrics` table. Acceptance: <10% RSS growth over 24h.
|
|
51
|
+
|
|
52
|
+
### Added (M41) — CLI polish
|
|
53
|
+
|
|
54
|
+
- **C1 — Unified help system.** `daimon --help` now groups commands by category (lifecycle / queries / agent verbs / introspection / config / claude / plugin). Per-command help is available as `daimon <verb> --help` (or `daimon help <verb>`) and follows a single template — synopsis, description, options table, examples, exit codes — driven entirely by `cliSurface.ts` so help, completion, and skill text cannot drift.
|
|
55
|
+
- **C2 — Shell completions.** New `daimon completion <bash|zsh|fish|powershell>` emits a completion script to stdout for the chosen shell. All four shells supported at launch. Completions cover verbs, aliases, and common flags; the bash/PowerShell scripts also auto-complete app names by querying a running daemon (`--no-spawn` is used to avoid starting one for completion).
|
|
56
|
+
- **C3 — Color and TTY awareness.** New `--no-color` flag and `NO_COLOR` env var disable ANSI coloring. When stdout is **not** a TTY (the agent / piped case), output is **never** colored — compact JSON default from M26 is preserved unchanged. TTY mode colors errors red, hints dim, headings bold, keywords cyan. `FORCE_COLOR=1` honored as the per-CI override.
|
|
57
|
+
- **C4 — Levenshtein "did-you-mean" suggestions.** Unknown commands and unknown apps now emit a `did you mean '<X>'?` hint. Tuned to a 2-edit-distance threshold to avoid noise. Apps lookup polls the running daemon.
|
|
58
|
+
- **C5 — Flag convention block in `--help`.** A new "flag conventions" section in the main help documents the canonical flag vocabulary (`--timeout`, `--since`, `--budget`, `--until`, `--app`, `--profile`, `--full/--compact`, `--stream`, `--explain`, `--dry-run`, `--yes`). No flag renames — convergence is documented.
|
|
59
|
+
- **C6 — Muscle-memory aliases.** New aliases: `daimon ls` → `list`, `daimon ps` → `status`, `daimon log` → `logs`. Aliases are documented in `--help` but not duplicated in the main verb list and do not conflict with existing verbs.
|
|
60
|
+
- **C7 — Error message rewrite.** CLI errors now carry a `{ "error": "<short>", "hint": "<actionable next step>", "exit": <code> }` shape in JSON (piped) mode. TTY mode renders the one-line human variant (`error: …` + dim `hint: …`). The "daimon is not running" error nudges the user to `daimon daemon start --detach`. Unknown command / unknown app errors carry suggestions.
|
|
61
|
+
- **C8 — `daimon --version` / `daimon --about`.** `--version` now prints the bare SemVer string (was `{"version":"..."}`). `--about` prints `{version, nodeVersion, platform, configPath, lockPath, running, runningPid, runningPort, claudeArtifacts}` — useful for bug reports. `daimon self` (new lightweight verb) reaches the daemon's `/api/self` endpoint introduced in M43.
|
|
62
|
+
- **Test surface.** New `test/cli-surface.test.mjs` asserts every subcommand has the full help template, aliases resolve to canonical verbs, did-you-mean returns sensible candidates within 2 edits, and the completion script generator produces non-empty output for all four shells.
|
|
63
|
+
|
|
64
|
+
## [0.7.0] — 2026-05-20
|
|
65
|
+
|
|
66
|
+
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).
|
|
67
|
+
|
|
68
|
+
### Added (M37) — History dashboard surface
|
|
69
|
+
|
|
70
|
+
- **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.
|
|
71
|
+
- **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.
|
|
72
|
+
- **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.
|
|
73
|
+
- **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`.
|
|
74
|
+
|
|
75
|
+
### Deferred (M37 → v0.7.1)
|
|
76
|
+
|
|
77
|
+
- **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.
|
|
78
|
+
- **H3 — WCAG AA contrast audit.** Visual inspection task across light/dark/reduced-motion tonal surfaces — also pushed to v0.7.1 alongside H1.
|
|
79
|
+
|
|
80
|
+
### Changed (M37)
|
|
81
|
+
|
|
82
|
+
- **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.
|
|
83
|
+
|
|
84
|
+
### Added (M38) — Whole-workspace orchestration
|
|
85
|
+
|
|
86
|
+
- **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`).
|
|
87
|
+
- **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.
|
|
88
|
+
- **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.
|
|
89
|
+
- **`--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`.
|
|
90
|
+
- **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.
|
|
91
|
+
- **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.
|
|
92
|
+
|
|
93
|
+
### Added (M39) — Polyglot dev-server discovery
|
|
94
|
+
|
|
95
|
+
- **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`.
|
|
96
|
+
- **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.
|
|
97
|
+
- **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.
|
|
98
|
+
- **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`.
|
|
99
|
+
- **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.
|
|
100
|
+
- **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).
|
|
101
|
+
- **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`).
|
|
102
|
+
- **Decisions locked in** (re-affirmed from PLAN-v0.7.md):
|
|
103
|
+
- Daimon **never invokes** `pip install`, `bundle install`, `cargo build`, `go mod download` — the polyglot orphan rules are report-only, never a shell-out.
|
|
104
|
+
- 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).
|
|
105
|
+
- No new `searchRoots[*].polyglot: true` opt-in is introduced.
|
|
106
|
+
|
|
107
|
+
### Added (M40) — TUI parity refresh
|
|
108
|
+
|
|
109
|
+
- **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).
|
|
110
|
+
- **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`).
|
|
111
|
+
- **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.
|
|
112
|
+
- **T6d — Headless mode unchanged.** `--headless` + `config.headless: true` continue to skip the TUI entirely. No new daemon flags.
|
|
113
|
+
- **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.
|
|
114
|
+
- **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).
|
|
115
|
+
|
|
7
116
|
## [0.6.0] — 2026-05-20
|
|
8
117
|
|
|
9
118
|
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.
|
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
|
|