codealmanac 0.1.4 → 0.1.6

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.
@@ -7,7 +7,7 @@ Groupings match `almanac --help`:
7
7
  1. **Query** — `search`, `show`, `health`, `list`
8
8
  2. **Edit** — `tag`, `untag`, `topics ...`
9
9
  3. **Wiki lifecycle** — `bootstrap`, `capture`, `hook ...`, `reindex`
10
- 4. **Setup** — `setup`, `uninstall`, `doctor`
10
+ 4. **Setup** — `setup`, `uninstall`, `doctor`, `update`
11
11
 
12
12
  Every query/edit command auto-registers the current repo in `~/.almanac/registry.json` on first run. Exceptions: `list --drop` (skips auto-register so the removal intent isn't undone) and the setup group (installers, not wiki commands — they never touch the registry).
13
13
 
@@ -36,7 +36,7 @@ There is no `almanac init` command. The two ways a wiki gets scaffolded are `alm
36
36
  | `--limit <n>` | int ≥0 | unbounded | Cap results. |
37
37
 
38
38
  **Default output:** one slug per line to stdout. When zero pages match, stdout is empty and stderr emits `# 0 results` (a breadcrumb so users can tell "matched nothing" apart from "command broken"). `--json` is silent on stderr — `[]` is the unambiguous empty signal there.
39
- **`--json` schema:** JSON array of `{slug, title, updated_at, topics, path}`.
39
+ **`--json` schema:** JSON array of `{slug, title, updated_at, archived_at, superseded_by, topics}`. `title` is the page's frontmatter title (nullable when no frontmatter). `updated_at` is epoch seconds (file mtime). `archived_at` is epoch seconds or `null`. `superseded_by` is a slug string or `null`. `topics` is an array of topic slugs, sorted ascending. No `path` field — use `almanac show <slug> --path` (or `--json`) for the absolute path.
40
40
  **Exit:** `0` always (empty result isn't an error). Arg-parse failures exit `1` with an `almanac:` error.
41
41
 
42
42
  #### `almanac show [slug]`
@@ -103,7 +103,7 @@ Flags: `--wiki <name>`.
103
103
 
104
104
  #### `almanac topics` (DAG management)
105
105
 
106
- - `almanac topics list` — list all topics with page counts. `--json` emits an array of `{slug, description, parents[], children[], page_count}`.
106
+ - `almanac topics list` — list all topics with page counts. `--json` emits an array of `{slug, title, description, page_count}`. `page_count` excludes archived pages (matches `topics show`). `parents`/`children` are only on `topics show <slug> --json`; use that when you need DAG edges.
107
107
  - `almanac topics show <slug>` — description, parents, children, pages. `--descendants` includes pages tagged with descendant topics (walks the DAG subtree).
108
108
  - `almanac topics create <name>` — `--parent <slug>` repeatable. Rejects if any parent slug doesn't exist.
109
109
  - `almanac topics link <child> <parent>` / `almanac topics unlink <child> <parent>` — add/remove a DAG edge. `link` is cycle-checked (§5). `unlink` is idempotent.
@@ -132,7 +132,7 @@ Run the writer/reviewer pipeline on a Claude Code session transcript. Usually au
132
132
  | `--quiet` | Suppress per-tool streaming; print only the final summary. |
133
133
  | `--model <model>` | Override the agent model. |
134
134
 
135
- Writes SDK transcript to `.almanac/.capture-<session-id>.log`. A writer subagent drafts pages; a reviewer subagent enforces notability + writing conventions (§9) before drafts land.
135
+ Writes SDK transcript to `.almanac/.capture-<session-id>.jsonl` (one JSON message per line). When invoked manually without `--session`, falls back to `.capture-<timestamp>.jsonl` so repeated runs don't clobber each other. A writer subagent drafts pages; a reviewer subagent enforces notability + writing conventions (§9) before drafts land.
136
136
 
137
137
  #### `almanac hook install | uninstall | status`
138
138
 
@@ -204,13 +204,32 @@ Read-only install + current-wiki health report. Every check reports a state; non
204
204
 
205
205
  Each check has a stable `key` safe for scripting. ✗ entries include a `fix` field with a one-line "run: …" hint. Parse `--json` and count `status === "problem"` for a pass/fail gate.
206
206
 
207
+ The report also includes an `## Updates` section (`updates: Check[]` in `--json`) with keys `update.status`, `update.last_check`, `update.notifier`, and `update.dismissed`. `update.status === "problem"` when a new version is available — mirrors the pre-command banner.
208
+
209
+ #### `almanac update`
210
+
211
+ Upgrade command + the controls for the nag banner. See §11 for the full update-notifier architecture.
212
+
213
+ | Flag | Semantics |
214
+ |---|---|
215
+ | (none) | Run `npm i -g codealmanac@latest` synchronously in the foreground. Inherits stdio so you see npm's progress bar, permission prompts, and peer-dep warnings verbatim. |
216
+ | `--dismiss` | Mark the current `latest_version` as "don't nag". No install. Banner is suppressed until a newer version ships. |
217
+ | `--check` | Force a registry query now, bypassing the 24h cache. Prints the result. No install. |
218
+ | `--enable-notifier` | Set `update_notifier: true` in `~/.almanac/config.json` (default). |
219
+ | `--disable-notifier` | Set `update_notifier: false` — banner stops showing entirely. `almanac doctor` still reports update status. |
220
+
221
+ **Exit codes:** `0` on successful install / check / dismiss / toggle. Install propagates npm's exit code on failure. `--check` exits `1` when the registry is unreachable.
222
+
223
+ **EACCES:** if `npm i -g` fails with a permission error, try `sudo npm i -g codealmanac@latest`, or switch to a version manager (nvm/volta/fnm) that doesn't require root. codealmanac will never sudo on your behalf — silent privilege escalation would violate the trust contract.
224
+
207
225
  ### 1.5 `--stdin` pipe semantics
208
226
 
209
227
  Commands that accept `--stdin`: `show`, `tag`, `health`.
210
228
 
211
229
  - One slug per line; blank lines ignored; whitespace trimmed.
212
230
  - Output order mirrors input order.
213
- - Missing slugs don't abort logged to stderr, pipeline continues. `show --stdin` writes a "not found" marker per slug and keeps exit `0` for pipeline resilience.
231
+ - Missing slugs don't abort the output every found slug still gets printed, and each missing slug writes `almanac: no such page "<slug>"` to stderr.
232
+ - **Exit code reflects completeness.** `show --stdin` exits `1` if any slug was missing, `0` only when every requested slug resolved. This is what `xargs` + CI wants: a pipeline that silently drops slugs is a bug, not a feature. Use `|| true` or `; :` to continue past it when you genuinely don't care.
214
233
  - `--stdin` must be explicit. No `isTTY` auto-detection (confusing under script redirection).
215
234
 
216
235
  ---
@@ -674,11 +693,66 @@ Case sensitivity on Linux. Schema v2 stores `original_path` for case-preserving
674
693
 
675
694
  ### Forensics files
676
695
 
677
- - `.almanac/.capture-<session-id>.log` — per-session SDK transcript from capture. Writer + reviewer interleaved.
696
+ - `.almanac/.capture-<session-id>.jsonl` — SDK message stream from `almanac capture` (one JSON object per line). Writer + reviewer interleaved.
697
+ - `.almanac/.capture-<session-id>.log` — companion sidecar written by the SessionEnd hook: stdout+stderr of `almanac capture`, human-readable. Present only for hook-invoked captures; manual invocations emit only the `.jsonl`.
678
698
  - `.almanac/.bootstrap-<timestamp>.log` — one per bootstrap. Gitignored by default.
679
699
 
680
700
  ---
681
701
 
702
+ ## 11. Updates: nag banner + manual install
703
+
704
+ Tier B design, per the pair review. No silent auto-install. The CLI self-schedules a detached background version check after each command; the next command's banner reflects what that check learned. Installing is always a foreground action the user chooses.
705
+
706
+ ### How it works
707
+
708
+ ```
709
+ command runs
710
+
711
+ ├─ pre: announceUpdateIfAvailable() ── reads ~/.almanac/update-state.json (sync)
712
+ │ prints stderr banner if outdated
713
+
714
+ ├─ (command does its thing)
715
+
716
+ └─ post: spawn --internal-check-updates (detached, stdio: ignore)
717
+ queries registry.npmjs.org
718
+ writes ~/.almanac/update-state.json
719
+ exits
720
+ ```
721
+
722
+ ### State files
723
+
724
+ - **`~/.almanac/update-state.json`** — written by the background worker + `almanac update`. Shape: `{last_check_at, installed_version, latest_version, dismissed_versions[], last_fetch_failed_at?}`. `last_check_at` is epoch seconds; `dismissed_versions` is a list of version strings the user muted via `--dismiss`. Missing / malformed → all read paths return defaults. Never break the CLI.
725
+ - **`~/.almanac/config.json`** — `{update_notifier: boolean}`. Toggles whether the banner ever prints. Default `true`. Flip via `almanac update --enable-notifier` / `--disable-notifier`.
726
+
727
+ ### Cache behavior
728
+
729
+ - Background check runs at most once per 24h (comparing `last_check_at` to now).
730
+ - `almanac update --check` bypasses the cache for immediate status.
731
+ - Failed registry fetches bump `last_check_at` anyway so a one-shot failure doesn't hammer the registry on every subsequent invocation. The 24h cycle resumes as normal.
732
+ - Network timeout is 3s; longer would be noticeable in the background spawn.
733
+
734
+ ### Dismissal semantics
735
+
736
+ `almanac update --dismiss` appends the current `latest_version` to `dismissed_versions[]`. The banner suppresses **only that specific version** — when a newer one ships, `latest_version` moves on and the banner reappears. Multiple consecutive dismissals accumulate; `dismissed_versions` is never trimmed automatically. If you find yourself dismissing every release, `almanac update --disable-notifier` is the right tool instead.
737
+
738
+ Dismissal does NOT prevent `almanac update` from installing. It only silences the banner.
739
+
740
+ ### Test / CI gating
741
+
742
+ The post-command background spawn is gated on `process.env.NODE_ENV !== "test"`, `!process.env.VITEST`, and `!process.env.CODEALMANAC_SKIP_UPDATE_CHECK`. Test suites never fork update workers; CI pipelines that want to opt out set `CODEALMANAC_SKIP_UPDATE_CHECK=1`.
743
+
744
+ ### Why not auto-install
745
+
746
+ From the pair review:
747
+ - Silent install without consent violates trust norms; users expect to choose when their tooling changes under them.
748
+ - `npm i -g` prefixes diverge across nvm, volta, fnm, and system Node; guessing wrong corrupts the PATH.
749
+ - Detached-child survival is fragile in Claude Code subprocesses, CI runners, and Windows — a mid-install kill leaves a half-linked binary.
750
+ - Mid-invocation binary swap breaks `import()` of dist chunks that haven't yet been loaded.
751
+
752
+ The manual `almanac update` in the foreground resolves all of these: user sees what's running, npm picks its own prefix, the child is owned by the user's shell, and the running process doesn't touch its own files.
753
+
754
+ ---
755
+
682
756
  ## When in doubt
683
757
 
684
758
  - `almanac --help` / `almanac <command> --help` — flags are always current for the installed build.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codealmanac",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "A living wiki for codebases, maintained by AI agents. Documents what the code can't say: decisions, flows, invariants, incidents, gotchas.",
5
5
  "keywords": [
6
6
  "wiki",
@@ -34,7 +34,7 @@
34
34
  "LICENSE"
35
35
  ],
36
36
  "engines": {
37
- "node": ">=20"
37
+ "node": "20.x || 22.x || 23.x || 24.x || 25.x"
38
38
  },
39
39
  "scripts": {
40
40
  "build": "tsup",
@@ -6,7 +6,7 @@ You are a second set of eyes. Your value is catching things the writer missed
6
6
 
7
7
  ## Before you start
8
8
 
9
- You have `Read`, `Grep`, `Glob`, and `Bash`. Use `almanac search`, `almanac show <slug>`, `almanac info <slug>`, and `almanac list` to understand what already exists.
9
+ You have `Read`, `Grep`, `Glob`, and `Bash`. Use `almanac search`, `almanac show <slug>` (add `--meta` for metadata only), and `almanac list` to understand what already exists.
10
10
 
11
11
  Read:
12
12
 
package/prompts/writer.md CHANGED
@@ -7,7 +7,7 @@ You have a reviewer subagent available. Invoke it when you want a second set of
7
7
  ## What you're reading
8
8
 
9
9
  - The session transcript (file path passed as input)
10
- - Existing wiki pages, via `almanac search`, `almanac show <slug>`, `almanac info <slug>`
10
+ - Existing wiki pages, via `almanac search` and `almanac show <slug>` (add `--meta` for metadata only)
11
11
  - The repo's `.almanac/README.md` — conventions and notability bar
12
12
  - Source files referenced in the session, via `Read` / `Grep`
13
13