codealmanac 0.1.8 → 0.1.9
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/dist/{chunk-73A5TGBC.js → chunk-QLHJP2XK.js} +2 -2
- package/dist/{cli-HIXXCUSQ.js → cli-W3OYVJYH.js} +3 -3
- package/dist/codealmanac.js +1 -1
- package/dist/{doctor-IS6N7V63.js → doctor-ODFNJUKH.js} +2 -2
- package/dist/{register-commands-JAPO3AUB.js → register-commands-JHC2OFKM.js} +18 -10
- package/dist/register-commands-JHC2OFKM.js.map +1 -0
- package/dist/{wiki-EHZ7LG7R.js → wiki-IPSRRGOT.js} +15 -16
- package/dist/wiki-IPSRRGOT.js.map +1 -0
- package/guides/mini.md +2 -2
- package/guides/reference.md +9 -9
- package/hooks/almanac-capture.sh +9 -1
- package/package.json +1 -1
- package/dist/register-commands-JAPO3AUB.js.map +0 -1
- package/dist/wiki-EHZ7LG7R.js.map +0 -1
- /package/dist/{chunk-73A5TGBC.js.map → chunk-QLHJP2XK.js.map} +0 -0
- /package/dist/{cli-HIXXCUSQ.js.map → cli-W3OYVJYH.js.map} +0 -0
- /package/dist/{doctor-IS6N7V63.js.map → doctor-ODFNJUKH.js.map} +0 -0
|
@@ -140,23 +140,22 @@ function describeLastCapture(almanacDir, nowFn) {
|
|
|
140
140
|
message: "last capture: never"
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
entries
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
).map((e) => {
|
|
143
|
+
const logDirs = [path.join(almanacDir, "logs"), almanacDir];
|
|
144
|
+
const captures = logDirs.flatMap((dir) => {
|
|
145
|
+
let entries;
|
|
146
|
+
try {
|
|
147
|
+
entries = readdirSync(dir);
|
|
148
|
+
} catch {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
return entries.filter(
|
|
152
|
+
(e) => e.startsWith(".capture-") && (e.endsWith(".log") || e.endsWith(".jsonl"))
|
|
153
|
+
).map((e) => ({ dir, name: e }));
|
|
154
|
+
}).map((e) => {
|
|
156
155
|
try {
|
|
157
156
|
return {
|
|
158
|
-
name: e,
|
|
159
|
-
mtime: statSync(path.join(
|
|
157
|
+
name: e.name,
|
|
158
|
+
mtime: statSync(path.join(e.dir, e.name)).mtimeMs
|
|
160
159
|
};
|
|
161
160
|
} catch {
|
|
162
161
|
return null;
|
|
@@ -235,4 +234,4 @@ function countHealthProblems(jsonStdout) {
|
|
|
235
234
|
export {
|
|
236
235
|
gatherWikiChecks
|
|
237
236
|
};
|
|
238
|
-
//# sourceMappingURL=wiki-
|
|
237
|
+
//# sourceMappingURL=wiki-IPSRRGOT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/doctor-checks/wiki.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\n\nimport type Database from \"better-sqlite3\";\n\nimport { ensureFreshIndex } from \"../../indexer/index.js\";\nimport { openIndex } from \"../../indexer/schema.js\";\nimport { findNearestAlmanacDir } from \"../../paths.js\";\nimport { findEntry } from \"../../registry/index.js\";\nimport { runHealth, type HealthReport } from \"../health.js\";\nimport { formatDuration } from \"./duration.js\";\nimport type { Check, DoctorOptions } from \"./types.js\";\n\nexport async function gatherWikiChecks(options: DoctorOptions): Promise<Check[]> {\n const checks: Check[] = [];\n const repoRoot = findNearestAlmanacDir(options.cwd);\n\n if (repoRoot === null) {\n checks.push({\n status: \"info\",\n key: \"wiki.none\",\n message: \"No wiki in current directory\",\n fix: \"run: almanac bootstrap (to create one in this repo)\",\n });\n return checks;\n }\n\n checks.push({\n status: \"info\",\n key: \"wiki.repo\",\n message: `repo: ${repoRoot}`,\n });\n\n try {\n await ensureFreshIndex({ repoRoot });\n } catch {\n // non-fatal: counts below and the health probe report any real issue.\n }\n\n checks.push(await describeRegistry(repoRoot));\n\n const almanacDir = path.join(repoRoot, \".almanac\");\n const dbPath = path.join(almanacDir, \"index.db\");\n checks.push(...describeCounts(dbPath));\n checks.push(describeIndexFreshness(dbPath));\n checks.push(describeLastCapture(almanacDir, options.now));\n checks.push(await describeHealth(repoRoot, options));\n\n return checks;\n}\n\nasync function describeRegistry(repoRoot: string): Promise<Check> {\n try {\n const entry = await findEntry({ path: repoRoot });\n if (entry !== null) {\n return {\n status: \"ok\",\n key: \"wiki.registered\",\n message: `registered as '${entry.name}'`,\n };\n }\n return {\n status: \"info\",\n key: \"wiki.registered\",\n message: \"not yet registered (will register on first command)\",\n };\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n status: \"problem\",\n key: \"wiki.registered\",\n message: `could not read registry: ${msg}`,\n fix: \"inspect ~/.almanac/registry.json; remove or fix the malformed entry\",\n };\n }\n}\n\nfunction describeCounts(dbPath: string): Check[] {\n const checks: Check[] = [];\n let pageCount: number | null = null;\n let topicCount: number | null = null;\n\n if (existsSync(dbPath)) {\n try {\n const db = openIndex(dbPath);\n try {\n pageCount = countRows(db, \"pages\");\n topicCount = countRows(db, \"topics\");\n } finally {\n db.close();\n }\n } catch {\n pageCount = null;\n }\n }\n\n if (pageCount !== null) {\n checks.push({\n status: \"info\",\n key: \"wiki.pages\",\n message: `pages: ${pageCount}`,\n });\n }\n if (topicCount !== null) {\n checks.push({\n status: \"info\",\n key: \"wiki.topics\",\n message: `topics: ${topicCount}`,\n });\n }\n\n return checks;\n}\n\nfunction countRows(db: Database.Database, table: string): number {\n const row = db\n .prepare<[], { n: number }>(`SELECT COUNT(*) AS n FROM ${table}`)\n .get();\n return row?.n ?? 0;\n}\n\nfunction describeIndexFreshness(dbPath: string): Check {\n if (!existsSync(dbPath)) {\n return {\n status: \"info\",\n key: \"wiki.index\",\n message: \"index: not built yet (run any query command)\",\n };\n }\n try {\n const dbMtime = statSync(dbPath).mtimeMs;\n const age = Date.now() - dbMtime;\n return {\n status: \"info\",\n key: \"wiki.index\",\n message: `index: rebuilt ${formatDuration(age)} ago`,\n };\n } catch {\n return {\n status: \"info\",\n key: \"wiki.index\",\n message: \"index: present\",\n };\n }\n}\n\nfunction describeLastCapture(\n almanacDir: string,\n nowFn?: () => Date,\n): Check {\n if (!existsSync(almanacDir)) {\n return {\n status: \"info\",\n key: \"wiki.capture\",\n message: \"last capture: never\",\n };\n }\n const logDirs = [path.join(almanacDir, \"logs\"), almanacDir];\n const captures = logDirs\n .flatMap((dir) => {\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return [];\n }\n return entries\n .filter(\n (e) =>\n e.startsWith(\".capture-\") &&\n (e.endsWith(\".log\") || e.endsWith(\".jsonl\")),\n )\n .map((e) => ({ dir, name: e }));\n })\n .map((e) => {\n try {\n return {\n name: e.name,\n mtime: statSync(path.join(e.dir, e.name)).mtimeMs,\n };\n } catch {\n return null;\n }\n })\n .filter((e): e is { name: string; mtime: number } => e !== null);\n if (captures.length === 0) {\n return {\n status: \"info\",\n key: \"wiki.capture\",\n message: \"last capture: never\",\n };\n }\n captures.sort((a, b) => b.mtime - a.mtime);\n const latest = captures[0]!;\n const now = (nowFn?.() ?? new Date()).getTime();\n const age = now - latest.mtime;\n return {\n status: \"info\",\n key: \"wiki.capture\",\n message: `last capture: ${formatDuration(age)} ago (${latest.name})`,\n };\n}\n\nasync function describeHealth(\n repoRoot: string,\n options: DoctorOptions,\n): Promise<Check> {\n const healthFn = options.runHealthFn ?? runHealth;\n try {\n const healthRes = await healthFn({\n cwd: repoRoot,\n json: true,\n });\n const problems = countHealthProblems(healthRes.stdout);\n if (problems === 0) {\n return {\n status: \"ok\",\n key: \"wiki.health\",\n message: \"almanac health reports 0 problems\",\n };\n }\n return {\n status: \"problem\",\n key: \"wiki.health\",\n message: `almanac health reports ${problems} problem${problems === 1 ? \"\" : \"s\"}`,\n fix: \"run: almanac health\",\n };\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n status: \"info\",\n key: \"wiki.health\",\n message: `could not run almanac health: ${msg}`,\n };\n }\n}\n\nconst HEALTH_PROBLEM_KEYS: (keyof HealthReport)[] = [\n \"orphans\",\n \"stale\",\n \"dead_refs\",\n \"broken_links\",\n \"broken_xwiki\",\n \"empty_topics\",\n \"empty_pages\",\n \"slug_collisions\",\n];\n\nfunction countHealthProblems(jsonStdout: string): number {\n try {\n const report = JSON.parse(jsonStdout) as Partial<HealthReport>;\n let total = 0;\n for (const key of HEALTH_PROBLEM_KEYS) {\n const arr = report[key];\n if (Array.isArray(arr)) total += arr.length;\n }\n return total;\n } catch {\n return 0;\n }\n}\n"],"mappings":"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","names":[]}
|
package/guides/mini.md
CHANGED
|
@@ -210,9 +210,9 @@ Empty stdout plus `# 0 results` on stderr means the query ran and genuinely matc
|
|
|
210
210
|
```bash
|
|
211
211
|
almanac doctor # install.hook: ok/problem, wiki.capture: last capture age
|
|
212
212
|
almanac hook status # just the hook entry
|
|
213
|
-
ls -lah .almanac/.capture-*.log
|
|
213
|
+
ls -lah .almanac/logs/.capture-*.log
|
|
214
214
|
```
|
|
215
|
-
No logs at all → the hook isn't installed, or bailed before backgrounding, or `cwd` was outside any wiki (silent correct no-op). Capture ran but wrote nothing → the reviewer rejected the draft for notability, or the session was pure-read. Check
|
|
215
|
+
No logs at all → the hook isn't installed, or bailed before backgrounding, or `cwd` was outside any wiki (silent correct no-op). Capture ran but wrote nothing → the reviewer rejected the draft for notability, or the session was pure-read. Check `.almanac/logs/.capture-<id>.log` for the writer/reviewer transcript.
|
|
216
216
|
|
|
217
217
|
---
|
|
218
218
|
|
package/guides/reference.md
CHANGED
|
@@ -117,7 +117,7 @@ All topic subcommands accept `--wiki <name>`. `list` / `show` accept `--json`.
|
|
|
117
117
|
|
|
118
118
|
#### `almanac bootstrap`
|
|
119
119
|
|
|
120
|
-
Spawns an agent to create initial wiki stubs. Requires `ANTHROPIC_API_KEY` or a logged-in Claude subscription. `--quiet` suppresses per-tool streaming. `--model <model>` overrides the model. `--force` overwrites an existing populated wiki. Writes `.almanac/.bootstrap-<timestamp>.log`.
|
|
120
|
+
Spawns an agent to create initial wiki stubs. Requires `ANTHROPIC_API_KEY` or a logged-in Claude subscription. `--quiet` suppresses per-tool streaming. `--model <model>` overrides the model. `--force` overwrites an existing populated wiki. Writes `.almanac/logs/.bootstrap-<timestamp>.log`.
|
|
121
121
|
|
|
122
122
|
Bootstrap is the scaffolding path — it creates `.almanac/pages/`, `.almanac/topics.yaml`, `.almanac/README.md`, and stub entity pages based on what the agent reads in the repo.
|
|
123
123
|
|
|
@@ -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>.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.
|
|
135
|
+
Writes SDK transcript to `.almanac/logs/.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
|
|
|
@@ -455,7 +455,7 @@ Claude Code invokes `SessionEnd` hooks after each session. Payload on stdin:
|
|
|
455
455
|
|
|
456
456
|
1. Parse payload with `jq`. Missing `jq` → exit 0 silently.
|
|
457
457
|
2. Walk upward from `cwd` for a `.almanac/`. Bounded at filesystem root.
|
|
458
|
-
3. Background `almanac capture "$TRANSCRIPT" --session "$SESSION_ID" --quiet`, redirect to `.almanac/.capture-$SESSION_ID.log`, `disown`.
|
|
458
|
+
3. Background `almanac capture "$TRANSCRIPT" --session "$SESSION_ID" --quiet`, redirect to `.almanac/logs/.capture-$SESSION_ID.log`, `disown`.
|
|
459
459
|
4. Exit always `0`. Capture failures must never break Claude Code's session-end path.
|
|
460
460
|
|
|
461
461
|
Falls back to `npx --no-install codealmanac` if `almanac` isn't on `PATH`.
|
|
@@ -482,7 +482,7 @@ Falls back to `npx --no-install codealmanac` if `almanac` isn't on `PATH`.
|
|
|
482
482
|
```bash
|
|
483
483
|
almanac doctor # catch-all — reports hook state + last capture age
|
|
484
484
|
almanac hook status # just the hook entry
|
|
485
|
-
ls -lah .almanac/.capture-*.log
|
|
485
|
+
ls -lah .almanac/logs/.capture-*.log
|
|
486
486
|
```
|
|
487
487
|
|
|
488
488
|
Installed but no log: `SessionEnd` didn't fire (rare, hard crash), or script bailed before backgrounding (add `set -x` to trace), or no `.almanac/` upward from `cwd` (silent correct no-op).
|
|
@@ -490,7 +490,7 @@ Installed but no log: `SessionEnd` didn't fire (rare, hard crash), or script bai
|
|
|
490
490
|
### Diagnosing "capture ran but wrote nothing"
|
|
491
491
|
|
|
492
492
|
```bash
|
|
493
|
-
tail -200 .almanac/.capture-<id>.log
|
|
493
|
+
tail -200 .almanac/logs/.capture-<id>.log
|
|
494
494
|
```
|
|
495
495
|
|
|
496
496
|
Common causes:
|
|
@@ -678,7 +678,7 @@ Missing `files:` frontmatter, OR path referenced only in inline prose (not via `
|
|
|
678
678
|
almanac doctor # reports hook state + last capture age + auth
|
|
679
679
|
claude auth status # OAuth token present?
|
|
680
680
|
echo "${ANTHROPIC_API_KEY:0:10}" # API key fallback?
|
|
681
|
-
ls -lah .almanac/.capture-*.log
|
|
681
|
+
ls -lah .almanac/logs/.capture-*.log
|
|
682
682
|
```
|
|
683
683
|
|
|
684
684
|
No logs at all → script bailed pre-background. Add `set -x` to `hooks/almanac-capture.sh` to trace. If the hook itself isn't installed, `almanac doctor` reports `install.hook: problem` with `run: almanac setup --yes`.
|
|
@@ -693,9 +693,9 @@ Case sensitivity on Linux. Schema v2 stores `original_path` for case-preserving
|
|
|
693
693
|
|
|
694
694
|
### Forensics files
|
|
695
695
|
|
|
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`.
|
|
698
|
-
- `.almanac/.bootstrap-<timestamp>.log` — one per bootstrap. Gitignored by default.
|
|
696
|
+
- `.almanac/logs/.capture-<session-id>.jsonl` — SDK message stream from `almanac capture` (one JSON object per line). Writer + reviewer interleaved.
|
|
697
|
+
- `.almanac/logs/.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`.
|
|
698
|
+
- `.almanac/logs/.bootstrap-<timestamp>.log` — one per bootstrap. Gitignored by default.
|
|
699
699
|
|
|
700
700
|
---
|
|
701
701
|
|
package/hooks/almanac-capture.sh
CHANGED
|
@@ -13,6 +13,13 @@
|
|
|
13
13
|
|
|
14
14
|
set -u
|
|
15
15
|
|
|
16
|
+
# CodeAlmanac's own bootstrap/capture agents run Claude Code internally.
|
|
17
|
+
# Their SessionEnd events must not trigger another capture, or one capture
|
|
18
|
+
# can become an unbounded capture chain.
|
|
19
|
+
if [ "${CODEALMANAC_INTERNAL_SESSION:-}" = "1" ]; then
|
|
20
|
+
exit 0
|
|
21
|
+
fi
|
|
22
|
+
|
|
16
23
|
# Be forgiving: if jq is missing, we can't parse the payload, so no-op.
|
|
17
24
|
if ! command -v jq >/dev/null 2>&1; then
|
|
18
25
|
exit 0
|
|
@@ -33,7 +40,8 @@ CWD=$(echo "$INPUT" | jq -r '.cwd // empty')
|
|
|
33
40
|
DIR="$CWD"
|
|
34
41
|
while [ "$DIR" != "/" ] && [ -n "$DIR" ]; do
|
|
35
42
|
if [ -d "$DIR/.almanac" ]; then
|
|
36
|
-
LOG_DIR="$DIR/.almanac"
|
|
43
|
+
LOG_DIR="$DIR/.almanac/logs"
|
|
44
|
+
mkdir -p "$LOG_DIR" || exit 0
|
|
37
45
|
# Prefer `almanac` on PATH; fall back to `npx codealmanac` if the
|
|
38
46
|
# binary isn't linked (happens with non-global installs).
|
|
39
47
|
if command -v almanac >/dev/null 2>&1; then
|
package/package.json
CHANGED