daftari 1.30.0 → 1.31.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.
Files changed (282) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/README.md +139 -4
  3. package/dist/access/rbac.d.ts +1 -0
  4. package/dist/access/rbac.d.ts.map +1 -1
  5. package/dist/access/rbac.js +7 -0
  6. package/dist/access/rbac.js.map +1 -1
  7. package/dist/audit/checks/broken_refs.d.ts +1 -1
  8. package/dist/audit/checks/broken_refs.d.ts.map +1 -1
  9. package/dist/audit/checks/broken_refs.js +77 -22
  10. package/dist/audit/checks/broken_refs.js.map +1 -1
  11. package/dist/audit/collect.d.ts +1 -0
  12. package/dist/audit/collect.d.ts.map +1 -1
  13. package/dist/audit/collect.js +22 -2
  14. package/dist/audit/collect.js.map +1 -1
  15. package/dist/audit/index.d.ts.map +1 -1
  16. package/dist/audit/index.js +9 -3
  17. package/dist/audit/index.js.map +1 -1
  18. package/dist/audit/links.d.ts.map +1 -1
  19. package/dist/audit/links.js +9 -3
  20. package/dist/audit/links.js.map +1 -1
  21. package/dist/audit/report.d.ts.map +1 -1
  22. package/dist/audit/report.js +2 -0
  23. package/dist/audit/report.js.map +1 -1
  24. package/dist/audit/types.d.ts +4 -1
  25. package/dist/audit/types.d.ts.map +1 -1
  26. package/dist/audit/types.js.map +1 -1
  27. package/dist/backfill/derive.d.ts.map +1 -1
  28. package/dist/backfill/derive.js +1 -0
  29. package/dist/backfill/derive.js.map +1 -1
  30. package/dist/cli.d.ts.map +1 -1
  31. package/dist/cli.js +18 -0
  32. package/dist/cli.js.map +1 -1
  33. package/dist/court/precedent.d.ts.map +1 -1
  34. package/dist/court/precedent.js +6 -1
  35. package/dist/court/precedent.js.map +1 -1
  36. package/dist/curation/consumes.d.ts +24 -0
  37. package/dist/curation/consumes.d.ts.map +1 -0
  38. package/dist/curation/consumes.js +122 -0
  39. package/dist/curation/consumes.js.map +1 -0
  40. package/dist/curation/edge-staleness.d.ts +47 -0
  41. package/dist/curation/edge-staleness.d.ts.map +1 -0
  42. package/dist/curation/edge-staleness.js +258 -0
  43. package/dist/curation/edge-staleness.js.map +1 -0
  44. package/dist/curation/edges.d.ts.map +1 -1
  45. package/dist/curation/edges.js +164 -10
  46. package/dist/curation/edges.js.map +1 -1
  47. package/dist/curation/lint.d.ts +4 -1
  48. package/dist/curation/lint.d.ts.map +1 -1
  49. package/dist/curation/lint.js +61 -6
  50. package/dist/curation/lint.js.map +1 -1
  51. package/dist/curation/provenance.d.ts +2 -0
  52. package/dist/curation/provenance.d.ts.map +1 -1
  53. package/dist/curation/provenance.js +2 -0
  54. package/dist/curation/provenance.js.map +1 -1
  55. package/dist/curation/read-log.d.ts +19 -0
  56. package/dist/curation/read-log.d.ts.map +1 -0
  57. package/dist/curation/read-log.js +120 -0
  58. package/dist/curation/read-log.js.map +1 -0
  59. package/dist/curation/review-throughput.d.ts +24 -0
  60. package/dist/curation/review-throughput.d.ts.map +1 -0
  61. package/dist/curation/review-throughput.js +102 -0
  62. package/dist/curation/review-throughput.js.map +1 -0
  63. package/dist/curation/staged-actions.d.ts +11 -1
  64. package/dist/curation/staged-actions.d.ts.map +1 -1
  65. package/dist/curation/staged-actions.js +102 -24
  66. package/dist/curation/staged-actions.js.map +1 -1
  67. package/dist/curation/structural.d.ts +16 -0
  68. package/dist/curation/structural.d.ts.map +1 -0
  69. package/dist/curation/structural.js +64 -0
  70. package/dist/curation/structural.js.map +1 -0
  71. package/dist/curation/tension-blast.d.ts +4 -0
  72. package/dist/curation/tension-blast.d.ts.map +1 -1
  73. package/dist/curation/tension-blast.js +9 -0
  74. package/dist/curation/tension-blast.js.map +1 -1
  75. package/dist/curation/tension.d.ts +5 -2
  76. package/dist/curation/tension.d.ts.map +1 -1
  77. package/dist/curation/tension.js +68 -25
  78. package/dist/curation/tension.js.map +1 -1
  79. package/dist/curation/tier0.d.ts +27 -0
  80. package/dist/curation/tier0.d.ts.map +1 -0
  81. package/dist/curation/tier0.js +196 -0
  82. package/dist/curation/tier0.js.map +1 -0
  83. package/dist/curation/tier1.d.ts +30 -0
  84. package/dist/curation/tier1.d.ts.map +1 -0
  85. package/dist/curation/tier1.js +142 -0
  86. package/dist/curation/tier1.js.map +1 -0
  87. package/dist/curation/tier2.d.ts +43 -0
  88. package/dist/curation/tier2.d.ts.map +1 -0
  89. package/dist/curation/tier2.js +182 -0
  90. package/dist/curation/tier2.js.map +1 -0
  91. package/dist/curation/vault-docs.d.ts +5 -1
  92. package/dist/curation/vault-docs.d.ts.map +1 -1
  93. package/dist/curation/vault-docs.js +14 -0
  94. package/dist/curation/vault-docs.js.map +1 -1
  95. package/dist/eval/generate.js +22 -5
  96. package/dist/eval/generate.js.map +1 -1
  97. package/dist/eval/index.d.ts.map +1 -1
  98. package/dist/eval/index.js +173 -25
  99. package/dist/eval/index.js.map +1 -1
  100. package/dist/eval/llm.js +1 -1
  101. package/dist/eval/llm.js.map +1 -1
  102. package/dist/eval/prune.d.ts +24 -0
  103. package/dist/eval/prune.d.ts.map +1 -0
  104. package/dist/eval/prune.js +83 -0
  105. package/dist/eval/prune.js.map +1 -0
  106. package/dist/eval/storage.d.ts +3 -0
  107. package/dist/eval/storage.d.ts.map +1 -1
  108. package/dist/eval/storage.js +14 -0
  109. package/dist/eval/storage.js.map +1 -1
  110. package/dist/frontmatter/schema.d.ts.map +1 -1
  111. package/dist/frontmatter/schema.js +19 -1
  112. package/dist/frontmatter/schema.js.map +1 -1
  113. package/dist/frontmatter/types.d.ts +4 -1
  114. package/dist/frontmatter/types.d.ts.map +1 -1
  115. package/dist/frontmatter/types.js +8 -0
  116. package/dist/frontmatter/types.js.map +1 -1
  117. package/dist/import/index.d.ts.map +1 -1
  118. package/dist/import/index.js +44 -9
  119. package/dist/import/index.js.map +1 -1
  120. package/dist/import/langgraph-store.d.ts +53 -0
  121. package/dist/import/langgraph-store.d.ts.map +1 -0
  122. package/dist/import/langgraph-store.js +292 -0
  123. package/dist/import/langgraph-store.js.map +1 -0
  124. package/dist/index.d.ts +5 -0
  125. package/dist/index.d.ts.map +1 -1
  126. package/dist/index.js +56 -18
  127. package/dist/index.js.map +1 -1
  128. package/dist/lifecycle/lock.d.ts +9 -1
  129. package/dist/lifecycle/lock.d.ts.map +1 -1
  130. package/dist/lifecycle/lock.js +34 -9
  131. package/dist/lifecycle/lock.js.map +1 -1
  132. package/dist/okf/export.d.ts +12 -0
  133. package/dist/okf/export.d.ts.map +1 -0
  134. package/dist/okf/export.js +115 -0
  135. package/dist/okf/export.js.map +1 -0
  136. package/dist/okf/import.d.ts +24 -0
  137. package/dist/okf/import.d.ts.map +1 -0
  138. package/dist/okf/import.js +107 -0
  139. package/dist/okf/import.js.map +1 -0
  140. package/dist/okf/index.d.ts +2 -0
  141. package/dist/okf/index.d.ts.map +1 -0
  142. package/dist/okf/index.js +147 -0
  143. package/dist/okf/index.js.map +1 -0
  144. package/dist/okf/map.d.ts +16 -0
  145. package/dist/okf/map.d.ts.map +1 -0
  146. package/dist/okf/map.js +149 -0
  147. package/dist/okf/map.js.map +1 -0
  148. package/dist/okf/types.d.ts +9 -0
  149. package/dist/okf/types.d.ts.map +1 -0
  150. package/dist/okf/types.js +48 -0
  151. package/dist/okf/types.js.map +1 -0
  152. package/dist/search/coverage.d.ts.map +1 -1
  153. package/dist/search/coverage.js +1 -1
  154. package/dist/search/coverage.js.map +1 -1
  155. package/dist/search/hybrid.d.ts +19 -0
  156. package/dist/search/hybrid.d.ts.map +1 -1
  157. package/dist/search/hybrid.js +58 -10
  158. package/dist/search/hybrid.js.map +1 -1
  159. package/dist/search/reindex.d.ts +1 -0
  160. package/dist/search/reindex.d.ts.map +1 -1
  161. package/dist/search/reindex.js +41 -11
  162. package/dist/search/reindex.js.map +1 -1
  163. package/dist/search/watcher.d.ts +2 -0
  164. package/dist/search/watcher.d.ts.map +1 -1
  165. package/dist/search/watcher.js +21 -10
  166. package/dist/search/watcher.js.map +1 -1
  167. package/dist/serve/index.d.ts +36 -0
  168. package/dist/serve/index.d.ts.map +1 -0
  169. package/dist/serve/index.js +507 -0
  170. package/dist/serve/index.js.map +1 -0
  171. package/dist/server.d.ts +10 -1
  172. package/dist/server.d.ts.map +1 -1
  173. package/dist/server.js +89 -14
  174. package/dist/server.js.map +1 -1
  175. package/dist/sleep/index.d.ts +2 -0
  176. package/dist/sleep/index.d.ts.map +1 -1
  177. package/dist/sleep/index.js +212 -21
  178. package/dist/sleep/index.js.map +1 -1
  179. package/dist/sleep/report.d.ts +3 -0
  180. package/dist/sleep/report.d.ts.map +1 -1
  181. package/dist/sleep/report.js +52 -0
  182. package/dist/sleep/report.js.map +1 -1
  183. package/dist/sleep/tension-scan-state.d.ts +19 -0
  184. package/dist/sleep/tension-scan-state.d.ts.map +1 -0
  185. package/dist/sleep/tension-scan-state.js +0 -0
  186. package/dist/sleep/tension-scan-state.js.map +1 -0
  187. package/dist/sleep/tension-scan.d.ts +44 -0
  188. package/dist/sleep/tension-scan.d.ts.map +1 -0
  189. package/dist/sleep/tension-scan.js +0 -0
  190. package/dist/sleep/tension-scan.js.map +1 -0
  191. package/dist/storage/backend.d.ts +12 -0
  192. package/dist/storage/backend.d.ts.map +1 -0
  193. package/dist/storage/backend.js +231 -0
  194. package/dist/storage/backend.js.map +1 -0
  195. package/dist/storage/backends/fs.d.ts +4 -0
  196. package/dist/storage/backends/fs.d.ts.map +1 -0
  197. package/dist/storage/backends/fs.js +99 -0
  198. package/dist/storage/backends/fs.js.map +1 -0
  199. package/dist/storage/fs-walk.d.ts +5 -0
  200. package/dist/storage/fs-walk.d.ts.map +1 -0
  201. package/dist/storage/fs-walk.js +28 -0
  202. package/dist/storage/fs-walk.js.map +1 -0
  203. package/dist/storage/index-db.d.ts +16 -0
  204. package/dist/storage/index-db.d.ts.map +1 -1
  205. package/dist/storage/index-db.js +94 -5
  206. package/dist/storage/index-db.js.map +1 -1
  207. package/dist/storage/local.d.ts +1 -0
  208. package/dist/storage/local.d.ts.map +1 -1
  209. package/dist/storage/local.js +12 -0
  210. package/dist/storage/local.js.map +1 -1
  211. package/dist/storage/sync.d.ts +25 -0
  212. package/dist/storage/sync.d.ts.map +1 -0
  213. package/dist/storage/sync.js +308 -0
  214. package/dist/storage/sync.js.map +1 -0
  215. package/dist/sync/index.d.ts +2 -0
  216. package/dist/sync/index.d.ts.map +1 -0
  217. package/dist/sync/index.js +136 -0
  218. package/dist/sync/index.js.map +1 -0
  219. package/dist/themes/clustering.d.ts +6 -11
  220. package/dist/themes/clustering.d.ts.map +1 -1
  221. package/dist/themes/clustering.js +76 -84
  222. package/dist/themes/clustering.js.map +1 -1
  223. package/dist/tools/consumes.d.ts +14 -0
  224. package/dist/tools/consumes.d.ts.map +1 -0
  225. package/dist/tools/consumes.js +99 -0
  226. package/dist/tools/consumes.js.map +1 -0
  227. package/dist/tools/curation.d.ts +2 -0
  228. package/dist/tools/curation.d.ts.map +1 -1
  229. package/dist/tools/curation.js +53 -15
  230. package/dist/tools/curation.js.map +1 -1
  231. package/dist/tools/edge-staleness.d.ts +28 -0
  232. package/dist/tools/edge-staleness.d.ts.map +1 -0
  233. package/dist/tools/edge-staleness.js +205 -0
  234. package/dist/tools/edge-staleness.js.map +1 -0
  235. package/dist/tools/edges.d.ts.map +1 -1
  236. package/dist/tools/edges.js +27 -21
  237. package/dist/tools/edges.js.map +1 -1
  238. package/dist/tools/read.d.ts +15 -1
  239. package/dist/tools/read.d.ts.map +1 -1
  240. package/dist/tools/read.js +142 -29
  241. package/dist/tools/read.js.map +1 -1
  242. package/dist/tools/receipt.d.ts.map +1 -1
  243. package/dist/tools/receipt.js +16 -7
  244. package/dist/tools/receipt.js.map +1 -1
  245. package/dist/tools/search.d.ts +1 -0
  246. package/dist/tools/search.d.ts.map +1 -1
  247. package/dist/tools/search.js +147 -5
  248. package/dist/tools/search.js.map +1 -1
  249. package/dist/tools/staged-actions.d.ts +3 -0
  250. package/dist/tools/staged-actions.d.ts.map +1 -1
  251. package/dist/tools/staged-actions.js +227 -22
  252. package/dist/tools/staged-actions.js.map +1 -1
  253. package/dist/tools/themes.d.ts +8 -0
  254. package/dist/tools/themes.d.ts.map +1 -1
  255. package/dist/tools/themes.js +208 -122
  256. package/dist/tools/themes.js.map +1 -1
  257. package/dist/tools/tier1.d.ts +14 -0
  258. package/dist/tools/tier1.d.ts.map +1 -0
  259. package/dist/tools/tier1.js +169 -0
  260. package/dist/tools/tier1.js.map +1 -0
  261. package/dist/tools/tier2.d.ts +27 -0
  262. package/dist/tools/tier2.d.ts.map +1 -0
  263. package/dist/tools/tier2.js +344 -0
  264. package/dist/tools/tier2.js.map +1 -0
  265. package/dist/tools/write.d.ts +9 -1
  266. package/dist/tools/write.d.ts.map +1 -1
  267. package/dist/tools/write.js +492 -6
  268. package/dist/tools/write.js.map +1 -1
  269. package/dist/utils/config.d.ts +52 -0
  270. package/dist/utils/config.d.ts.map +1 -1
  271. package/dist/utils/config.js +372 -2
  272. package/dist/utils/config.js.map +1 -1
  273. package/dist/utils/run-id.d.ts +3 -0
  274. package/dist/utils/run-id.d.ts.map +1 -0
  275. package/dist/utils/run-id.js +19 -0
  276. package/dist/utils/run-id.js.map +1 -0
  277. package/dist/utils/vault-gitignore.d.ts +1 -1
  278. package/dist/utils/vault-gitignore.d.ts.map +1 -1
  279. package/dist/utils/vault-gitignore.js +4 -1
  280. package/dist/utils/vault-gitignore.js.map +1 -1
  281. package/package.json +21 -1
  282. package/templates/config.yaml +8 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,111 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.31.0] - 2026-07-22
11
+
12
+ The self-hosted deployment release: one always-on `daftari serve` instance
13
+ over Streamable HTTP with per-session identity (static tokens and/or OAuth
14
+ 2.1), plus durable object-storage backing (S3/Azure/GCS-interop) behind the
15
+ canonical local git working copy. Design record:
16
+ `docs/superpowers/specs/2026-07-20-self-hosted-server-mode-design.md`.
17
+
18
+ ### Added
19
+
20
+ - **`daftari serve` — server mode over Streamable HTTP (#5).** One always-on
21
+ instance, many MCP clients, per-session RBAC identity resolved at session
22
+ open (zero tool changes — every existence-disclosure invariant applies per
23
+ connection). Static bearer tokens declared in config with values in env
24
+ vars. Fail-loud posture throughout: a non-loopback bind refuses without
25
+ auth AND an explicit `server.transport_security: external` declaration
26
+ (daftari never terminates TLS); with auth configured a bad credential is a
27
+ 401 at session open, never a guest downgrade; loopback binds carry a
28
+ DNS-rebinding guard (Host/Origin validated before routing). The process
29
+ lock learns modes: a stray stdio invocation refuses against a live server,
30
+ a new serve refuses against any live holder, and deliberate replacement is
31
+ `daftari serve --takeover` (stdio-vs-stdio keeps its classic takeover;
32
+ stale locks are still overwritten silently).
33
+ - **OAuth 2.1 resource-server auth for serve (#7).** Bearer JWTs verified
34
+ against your IdP's JWKS (issuer + audience + signature + expiry via
35
+ `jose`), with the subject claim mapped through a config-declared subjects
36
+ table. A valid token with an unmapped subject is 403 — authenticated, not
37
+ authorized — never a guest, never a default role. Composes with static
38
+ tokens (agents on tokens, humans through the IdP). Hardened: https-only
39
+ issuer/JWKS URLs (loopback http for test IdPs only), constant-time static
40
+ token matching, `Object.prototype`-collision-proof subject lookup.
41
+ - **Pluggable storage backends as sync targets (#6).** The local git working
42
+ copy stays canonical; a backend is a dumb `get/put/list/delete` target.
43
+ Backends: `fs` (local/mounted directory), `s3` (S3, MinIO, R2, GCS via its
44
+ S3-interop endpoint), `azure` (Blob/ADLS Gen2) — cloud SDKs are optional
45
+ peer dependencies loaded on demand, credentials come only from the SDKs'
46
+ environment chains, custom endpoints must be https. `daftari sync` pushes
47
+ incrementally against a remote hash manifest (tree + `.git` + durable
48
+ `.daftari` journals; the rebuildable index/locks never sync) and
49
+ `daftari sync --restore` rebuilds a vault into an empty directory with
50
+ per-object hash verification and a reindex. `daftari serve` can push on a
51
+ cadence (`storage.sync_interval_minutes`). Security posture: `.git/config`
52
+ and `.git/hooks` are never synced or restored (git executes what they
53
+ declare — a backup channel must not deliver code), and restore re-enforces
54
+ every exclusion against the untrusted manifest.
55
+ - **Agent-as-judge rerank pool on `vault_search` (#3).** Opt-in
56
+ `rerank_candidates`: the server prepares the fused candidate pool and the
57
+ protocol; the calling agent is the judge.
58
+ - **Per-document theme distributions (#58).** True multi-theme membership via
59
+ chunk-level clustering.
60
+ - **Configurable tool-exposure tiers (#103, #104).** `tools.tier`
61
+ (`core`/`standard`/`full`) plus `include`/`exclude` lists in config.
62
+ - **Resumable reindex (#54).** Per-batch embedding commits so an interrupted
63
+ reindex resumes instead of restarting.
64
+ - **`daftari eval prune` (#100)** — `results/` and `scores/` housekeeping —
65
+ and eval v1 polish (#102): honest exit codes, skipped-run reporting, resume
66
+ validation, tier-aware triviality, intra-call dedupe, `--max-nodes`.
67
+ - **Advisory domain-boundary enforcement (#4)** and inline structural decay
68
+ checks (orphans, deprecated-still-linked) in the curation engine.
69
+ - **Advisory supersede nudge** when overwriting an existing doc, and a YAML
70
+ config error hint for comment lines that lost their `#`.
71
+ - **`daftari okf export|import` — Open Knowledge Format bridge.** OKF is Google
72
+ Cloud's vendor-neutral spec (v0.1) for the LLM-wiki pattern — a directory of
73
+ markdown files with YAML frontmatter — which is exactly Daftari's storage
74
+ model. `okf export` renders a vault as a portable OKF bundle: each doc becomes
75
+ an OKF concept doc carrying the core `type` / `title` / `description` /
76
+ `resource` / `tags` / `timestamp` fields plus a verbatim `daftari` sidecar for
77
+ lossless round-trip, alongside generated `index.md` and `log.md` reserved
78
+ files; the source vault is never mutated. `okf import` adopts an OKF bundle
79
+ into a vault — a bundle from `okf export` round-trips exactly via its sidecar,
80
+ while a foreign bundle is mapped conservatively (docs land as `draft` in the
81
+ `accumulation` domain, the source OKF `type` preserved in `okf_type`); writes
82
+ auto-commit and the index is rebuilt. `--dry-run` previews the import plan.
83
+
84
+ - **The compilation pipeline (#232–#236, #141, #217).** Edge provenance
85
+ classes with type-directed change dispatch (tier 1), structure-first tier-0
86
+ lint checks with a ratify gate, a semantic-review queue with typed verdicts
87
+ (tier 2), the compiled `consumes` dependency graph (run-correlated reads ×
88
+ writes, #233), edge staleness classes and the broken-read rate (#234),
89
+ proposal deltas (write action type, `run_id` provenance, inter-proposal
90
+ tension, a propose-only role, #235), write-protection tiers
91
+ (source/compiled/manual with a demote-then-write escape hatch, #141), a
92
+ review-throughput lint aggregate, and edge-graph existence disclosure
93
+ (blast B′, edges/lint omission) extending the 2026-07-14 RBAC spec (#217).
94
+ - **`sleep` tension-scan dream-type (#228)** closing the day-0 detection gap,
95
+ a langgraph-store adapter with the dedup-is-not-epistemics demo (#227),
96
+ the daftari.dev landing page (#226), and MCP Registry metadata (#222).
97
+ - **Dev maturity (#238–#242):** e2e gate on the built server, tag-driven npm
98
+ release via OIDC trusted publishing, automated code + security review on
99
+ PRs, an `@claude` mention responder, and a nightly maintenance loop.
100
+
101
+ ### Fixed
102
+
103
+ - Canonical-path tension/provenance gates in `vault_status`, `vault_receipt`,
104
+ and precedent lookups (#216), and tier-1 anchors that are unreadable leak
105
+ neither provenance metadata nor existence (#252).
106
+ - `daftari audit` no longer flags on-disk assets and unaudited siblings as
107
+ missing (#255); eval exit codes and resume validation honesty (#102).
108
+
109
+ ### Performance
110
+
111
+ - SQL-authoritative edge reads with write-through and stat-marker self-heal
112
+ (#236), FTS5 `snippet()` for lexical excerpts on the chunk path, and the
113
+ file watcher filters non-markdown events at watch time (#107).
114
+
10
115
  ## [1.30.0] - 2026-07-13
11
116
 
12
117
  ### Added
@@ -1377,6 +1482,7 @@ vault to AI agents, exposing 13 tools over stdio.
1377
1482
  example documents, git history, search index); `daftari --vault` serves it.
1378
1483
  - 160 tests covering all 13 tools and their supporting modules.
1379
1484
 
1485
+ [1.31.0]: https://github.com/mavaali/daftari/releases/tag/v1.31.0
1380
1486
  [1.5.1]: https://github.com/mavaali/daftari/releases/tag/v1.5.1
1381
1487
  [1.4.0]: https://github.com/mavaali/daftari/releases/tag/v1.4.0
1382
1488
  [1.1.1]: https://github.com/mavaali/daftari/releases/tag/v1.1.1
package/README.md CHANGED
@@ -116,6 +116,31 @@ The curation engine is advisory: `vault_lint` reports problems and
116
116
  `vault_tension_log` records contradictions. Neither auto-fixes anything. Every
117
117
  change is a deliberate, attributable act.
118
118
 
119
+ ### Tool tiers
120
+
121
+ Every advertised tool costs the agent context tokens and a decision branch.
122
+ The `tools` block in `.daftari/config.yaml` picks how much of the registry
123
+ `tools/list` advertises:
124
+
125
+ ```yaml
126
+ tools:
127
+ tier: standard # core | standard | full (default: full)
128
+ include: # add tools the tier omits
129
+ - vault_tension_log
130
+ exclude: # remove tools the tier includes — exclude wins
131
+ - vault_status
132
+ ```
133
+
134
+ `core` is the search-before-derive loop (`vault_search`, `vault_read`,
135
+ `vault_write`, `vault_index`, `vault_lint`, `vault_status`); `standard` adds
136
+ the full document lifecycle (append/promote/deprecate/supersede/merge,
137
+ confidence and tier setters, propose/ratify) plus diagnostics; `full` is
138
+ everything. `--tools <tier>` overrides the tier for one invocation. Filtering
139
+ only changes what is *advertised* — calls to any registered tool still work,
140
+ so an agent holding a cached tool name keeps working across a tier change.
141
+ Unknown names in `include`/`exclude` warn at startup and are ignored, so a
142
+ config written for a newer daftari still loads.
143
+
119
144
  **Evaluate (opt-in, requires an Anthropic API key):** `daftari eval` — scores how
120
145
  well an LLM can use the curation surface to answer multi-hop questions about the
121
146
  vault. See the [design spec](docs/superpowers/specs/2026-05-31-cortex-quality-metric-design.md)
@@ -243,6 +268,110 @@ daftari backfill --plan
243
268
  daftari backfill --apply --scope specs
244
269
  ```
245
270
 
271
+ ## Open Knowledge Format (OKF)
272
+
273
+ [OKF](https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing/)
274
+ is Google Cloud's vendor-neutral spec (v0.1) for the LLM-wiki pattern: a
275
+ directory of markdown files with YAML frontmatter that any producer can emit and
276
+ any consumer can read without translation. A Daftari vault *is* that pattern, so
277
+ `daftari okf` bridges the two directions.
278
+
279
+ **Export** renders the vault as a portable OKF bundle — every doc becomes an OKF
280
+ concept doc (the core `type` / `title` / `description` / `resource` / `tags` /
281
+ `timestamp` fields, plus a verbatim `daftari` sidecar for lossless round-trip),
282
+ with generated `index.md` (progressive-disclosure listing) and `log.md`
283
+ (chronological history). The source vault is never mutated.
284
+
285
+ ```bash
286
+ daftari okf export ./my-vault --out ./okf-bundle
287
+ daftari okf export ./my-vault --out ./okf-bundle --collection pricing
288
+ ```
289
+
290
+ **Import** adopts an OKF bundle into a vault. A bundle produced by `okf export`
291
+ round-trips exactly via its sidecar; a foreign bundle is mapped conservatively
292
+ (docs land as `draft` in the `accumulation` domain, the original OKF `type` is
293
+ preserved in an `okf_type` field). Writes auto-commit and the index is rebuilt.
294
+
295
+ ```bash
296
+ daftari okf import ./okf-bundle --into ./my-vault --dry-run
297
+ daftari okf import ./okf-bundle --into ./my-vault
298
+ ```
299
+
300
+ ## Server mode (self-hosted)
301
+
302
+ By default daftari is a per-user stdio process. `daftari serve` starts the
303
+ same vault as **one always-on instance over Streamable HTTP** — for a team, or
304
+ for clients that can't spawn a local process (claude.ai web/mobile, Cowork):
305
+
306
+ ```bash
307
+ daftari serve --vault ./my-vault # http://127.0.0.1:8787/mcp
308
+ daftari serve --vault ./my-vault --bind 0.0.0.0 --port 9000
309
+ ```
310
+
311
+ Identity is **per MCP session**, resolved when the session opens, so every
312
+ RBAC and existence-disclosure rule applies per connection with zero tool
313
+ changes. Two composable auth schemes, both declared in config:
314
+
315
+ ```yaml
316
+ server:
317
+ transport_security: external # required off-loopback: TLS terminates upstream
318
+ auth:
319
+ tokens: # static bearer tokens (agents, ETL)
320
+ - env: DAFTARI_TOKEN_ETL # the VALUE lives in this env var, never in config
321
+ user: agent:etl
322
+ role: admin
323
+ oauth: # OAuth 2.1 resource server (humans via your IdP)
324
+ issuer: https://idp.example.com
325
+ audience: daftari
326
+ jwks_uri: https://idp.example.com/.well-known/jwks.json
327
+ subjects:
328
+ "alice@example.com": { user: human:alice, role: analyst }
329
+ ```
330
+
331
+ The posture is fail-loud, never silent-downgrade: a non-loopback bind refuses
332
+ to start without auth **and** the explicit `transport_security: external`
333
+ acknowledgment (daftari never terminates TLS itself — put Caddy/nginx/a load
334
+ balancer in front); with any auth configured, a bad or missing credential is
335
+ a 401 at session open and a valid JWT whose subject isn't mapped is a 403 —
336
+ neither ever becomes the guest. Guest sessions exist only in the no-auth
337
+ loopback configuration. A running server also refuses to be silently killed:
338
+ stray stdio invocations against the same vault refuse to start, and replacing
339
+ a live holder requires a deliberate `daftari serve --takeover`.
340
+
341
+ ## Storage backing
342
+
343
+ A self-hosted vault can push to durable object storage (#6). The local git
344
+ working copy stays canonical — reads, writes, auto-commits, locks, and the
345
+ index all stay exactly as above — and the backing is a dumb sync target:
346
+
347
+ ```yaml
348
+ # .daftari/config.yaml
349
+ storage:
350
+ backend: s3 # fs | s3 | azure
351
+ bucket: team-vault
352
+ region: us-east-1
353
+ # endpoint: https://… # MinIO / R2 / GCS S3-interop endpoints
354
+ # sync_interval_minutes: 15 # daftari serve pushes on this cadence
355
+ ```
356
+
357
+ ```bash
358
+ daftari sync --vault ./my-vault # incremental push
359
+ daftari sync --vault ./my-vault --dry-run # show the diff only
360
+ daftari sync --vault ./empty-dir --restore --backend s3 --bucket team-vault
361
+ ```
362
+
363
+ The push covers the markdown tree, the `.git` directory, and durable
364
+ `.daftari` journals; the rebuildable SQLite index and lock files never sync.
365
+ Neither do `.git/config` and `.git/hooks` — git *executes* what those
366
+ declare, and a backup channel must not deliver code (`git clone` refuses to
367
+ transmit them for the same reason), so re-add remotes and local git config
368
+ by hand after a restore.
369
+ Cloud backends load their SDKs (`@aws-sdk/client-s3`, `@azure/storage-blob`)
370
+ as optional dependencies — install the one you use; credentials come from the
371
+ SDK's standard environment chain, never from vault config. GCS is reached via
372
+ its S3-interoperability endpoint. Restore refuses non-empty directories and
373
+ reindexes when done.
374
+
246
375
  ## How it compares
247
376
 
248
377
  | |AGENTS.md |RAG |Daftari |
@@ -257,12 +386,18 @@ daftari backfill --apply --scope specs
257
386
 
258
387
  Deliberately deferred to keep the surface tight:
259
388
 
260
- - **Cloud-hosted multi-tenant server** with S3/GCS backend and token auth
261
- - **Remote MCP transport** for claude.ai web, mobile, and Cowork (v1 is a local desktop extension for Claude Desktop and Claude Code)
389
+ - **Cloud-hosted multi-tenant SaaS** (self-hosted server mode HAS shipped
390
+ see [Server mode](#server-mode-self-hosted) and
391
+ [Storage backing](#storage-backing); the project itself hosts nothing)
262
392
  - **Conflict resolution beyond file-level locks** (CRDTs, semantic merge)
263
393
  - **Background curation agent** running lint on a cadence
264
- - **LLM reranking** of search results
265
- - **Enforced domain separation** (v1 documents the convention; v2 enforces it)
394
+ - **Enforced domain separation** (v1 documents the convention; v2 enforces it —
395
+ advisory boundary warnings shipped in the meantime: `vault_lint`'s
396
+ `domainLeaks` check and write-time `domain_warnings`)
397
+
398
+ (LLM reranking, deferred here originally, has since shipped as the opt-in
399
+ agent-as-judge `rerank_candidates` on `vault_search`: the server prepares the
400
+ fused candidate pool and the protocol; the calling agent is the judge.)
266
401
 
267
402
  Each is a clean increment on a surface that already works.
268
403
 
@@ -12,6 +12,7 @@ export declare function canRead(role: RoleConfig | null, collection: string): bo
12
12
  export declare function canWrite(role: RoleConfig | null, collection: string): boolean;
13
13
  export declare function canPromote(role: RoleConfig | null): boolean;
14
14
  export declare function canRatify(role: RoleConfig | null): boolean;
15
+ export declare function isProposeOnly(role: RoleConfig | null): boolean;
15
16
  export declare function hasAnyRead(role: RoleConfig | null): boolean;
16
17
  export declare function filterByReadPermission<T extends {
17
18
  collection: string;
@@ -1 +1 @@
1
- {"version":3,"file":"rbac.d.ts","sourceRoot":"","sources":["../../src/access/rbac.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEpE,eAAO,MAAM,UAAU,UAAU,CAAC;AAClC,eAAO,MAAM,QAAQ,MAAM,CAAC;AAI5B,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CACzB;AAKD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,aAAa,CAEf;AAID,wBAAgB,WAAW,CAAC,IAAI,SAAU,GAAG,aAAa,CAEzD;AAOD,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAE5E;AAGD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAE7E;AAGD,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE3D;AAMD,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE1D;AAID,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE3D;AAID,wBAAgB,sBAAsB,CAAC,CAAC,SAAS;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,EACrE,IAAI,EAAE,UAAU,GAAG,IAAI,EACvB,KAAK,EAAE,CAAC,EAAE,GACT,CAAC,EAAE,CAEL"}
1
+ {"version":3,"file":"rbac.d.ts","sourceRoot":"","sources":["../../src/access/rbac.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEpE,eAAO,MAAM,UAAU,UAAU,CAAC;AAClC,eAAO,MAAM,QAAQ,MAAM,CAAC;AAI5B,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CACzB;AAKD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,aAAa,CAEf;AAID,wBAAgB,WAAW,CAAC,IAAI,SAAU,GAAG,aAAa,CAEzD;AAOD,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAE5E;AAGD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAE7E;AAGD,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE3D;AAMD,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE1D;AAMD,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE9D;AAID,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAE3D;AAID,wBAAgB,sBAAsB,CAAC,CAAC,SAAS;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,EACrE,IAAI,EAAE,UAAU,GAAG,IAAI,EACvB,KAAK,EAAE,CAAC,EAAE,GACT,CAAC,EAAE,CAEL"}
@@ -42,6 +42,13 @@ export function canPromote(role) {
42
42
  export function canRatify(role) {
43
43
  return role?.ratify ?? false;
44
44
  }
45
+ // True if the role is propose-only (#235): its writes must land as staged
46
+ // `write` proposals, never as direct mutations. vault_write coerces; every
47
+ // other write tool denies. The write grant still scopes WHICH collections the
48
+ // role may propose into.
49
+ export function isProposeOnly(role) {
50
+ return role?.proposeOnly ?? false;
51
+ }
45
52
  // True if the role has read access to at least one collection. Curation tools
46
53
  // (lint, tension log, provenance) are open to anyone with any read grant.
47
54
  export function hasAnyRead(role) {
@@ -1 +1 @@
1
- {"version":3,"file":"rbac.js","sourceRoot":"","sources":["../../src/access/rbac.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,0EAA0E;AAI1E,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC;AAClC,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,CAAC;AAU5B,+EAA+E;AAC/E,6EAA6E;AAC7E,2BAA2B;AAC3B,MAAM,UAAU,aAAa,CAC3B,MAAqB,EACrB,IAAY,EACZ,QAAgB;IAEhB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;AAClE,CAAC;AAED,2EAA2E;AAC3E,0BAA0B;AAC1B,MAAM,UAAU,WAAW,CAAC,IAAI,GAAG,OAAO;IACxC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACpD,CAAC;AAED,SAAS,OAAO,CAAC,IAAc,EAAE,UAAkB;IACjD,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAC9D,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,OAAO,CAAC,IAAuB,EAAE,UAAkB;IACjE,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AACzD,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,QAAQ,CAAC,IAAuB,EAAE,UAAkB;IAClE,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AAC1D,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,OAAO,IAAI,EAAE,OAAO,IAAI,KAAK,CAAC;AAChC,CAAC;AAED,8EAA8E;AAC9E,4EAA4E;AAC5E,wEAAwE;AACxE,kDAAkD;AAClD,MAAM,UAAU,SAAS,CAAC,IAAuB;IAC/C,OAAO,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC;AAC/B,CAAC;AAED,8EAA8E;AAC9E,0EAA0E;AAC1E,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,OAAO,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;AAC/C,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,MAAM,UAAU,sBAAsB,CACpC,IAAuB,EACvB,KAAU;IAEV,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AAChE,CAAC"}
1
+ {"version":3,"file":"rbac.js","sourceRoot":"","sources":["../../src/access/rbac.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,0EAA0E;AAI1E,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC;AAClC,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,CAAC;AAU5B,+EAA+E;AAC/E,6EAA6E;AAC7E,2BAA2B;AAC3B,MAAM,UAAU,aAAa,CAC3B,MAAqB,EACrB,IAAY,EACZ,QAAgB;IAEhB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;AAClE,CAAC;AAED,2EAA2E;AAC3E,0BAA0B;AAC1B,MAAM,UAAU,WAAW,CAAC,IAAI,GAAG,OAAO;IACxC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACpD,CAAC;AAED,SAAS,OAAO,CAAC,IAAc,EAAE,UAAkB;IACjD,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAC9D,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,OAAO,CAAC,IAAuB,EAAE,UAAkB;IACjE,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AACzD,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,QAAQ,CAAC,IAAuB,EAAE,UAAkB;IAClE,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AAC1D,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,OAAO,IAAI,EAAE,OAAO,IAAI,KAAK,CAAC;AAChC,CAAC;AAED,8EAA8E;AAC9E,4EAA4E;AAC5E,wEAAwE;AACxE,kDAAkD;AAClD,MAAM,UAAU,SAAS,CAAC,IAAuB;IAC/C,OAAO,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC;AAC/B,CAAC;AAED,0EAA0E;AAC1E,2EAA2E;AAC3E,8EAA8E;AAC9E,yBAAyB;AACzB,MAAM,UAAU,aAAa,CAAC,IAAuB;IACnD,OAAO,IAAI,EAAE,WAAW,IAAI,KAAK,CAAC;AACpC,CAAC;AAED,8EAA8E;AAC9E,0EAA0E;AAC1E,MAAM,UAAU,UAAU,CAAC,IAAuB;IAChD,OAAO,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;AAC/C,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,MAAM,UAAU,sBAAsB,CACpC,IAAuB,EACvB,KAAU;IAEV,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AAChE,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import type { BrokenRefFinding, LinkEdge, RepoSnapshot } from "../types.js";
2
- export declare function checkBrokenRefs(snapshots: RepoSnapshot[], edges: LinkEdge[]): BrokenRefFinding[];
2
+ export declare function checkBrokenRefs(snapshots: RepoSnapshot[], edges: LinkEdge[], existsWithin?: (rootAbs: string, targetAbs: string) => boolean): BrokenRefFinding[];
3
3
  //# sourceMappingURL=broken_refs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"broken_refs.d.ts","sourceRoot":"","sources":["../../../src/audit/checks/broken_refs.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE5E,wBAAgB,eAAe,CAAC,SAAS,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,gBAAgB,EAAE,CA0DhG"}
1
+ {"version":3,"file":"broken_refs.d.ts","sourceRoot":"","sources":["../../../src/audit/checks/broken_refs.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAS5E,wBAAgB,eAAe,CAC7B,SAAS,EAAE,YAAY,EAAE,EACzB,KAAK,EAAE,QAAQ,EAAE,EAIjB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,GAC7D,gBAAgB,EAAE,CAiGpB"}
@@ -1,32 +1,72 @@
1
1
  // src/audit/checks/broken_refs.ts
2
2
  // Pure function: given snapshots and classified edges, return every broken
3
- // reference as a BrokenRefFinding. No throws. No classes.
3
+ // reference as a BrokenRefFinding. No throws. No classes. Disk access enters
4
+ // ONLY through the injected `existsWithin` oracle — the orchestrator passes
5
+ // collect.ts's symlink-safe implementation; tests pass a fake; omitting it
6
+ // reproduces the index-only behavior. The oracle receives the CONTAINMENT
7
+ // ROOT alongside the target because existence and confinement must be
8
+ // decided together: a lexical check here plus a bare exists() there would
9
+ // let a committed symlink (repo/escape -> /) walk the probe back out.
4
10
  //
5
11
  // Resolution logic:
6
12
  // 1. Look up target repo by name; if not found → missing_file.
7
13
  // 2. Look up targetPath in that repo's docs Map.
8
14
  // 3. If not found and targetPath lacks a ".md" extension, try targetPath +
9
15
  // ".md" (spec §7 bare-path fallback).
10
- // 4. If still not found missing_file.
11
- // 5. If found and targetAnchor is set: check DocSnapshot.headings. If absent
16
+ // 4. Still not found, edge escaped every configured repo (outOfScope):
17
+ // existing on disk out_of_scope_target (the audit can't vouch for it,
18
+ // but the link is not broken — #133); absent → missing_file.
19
+ // 5. Still not found, in-scope: existing on disk → NOT a finding — the doc
20
+ // index only holds glob-matched markdown, and references to real assets
21
+ // (.png, .pdf, .dagitty, …) are legitimate (#132). Anchors into such
22
+ // files are unverifiable and deliberately not flagged.
23
+ // 6. Otherwise → missing_file.
24
+ // 7. If found and targetAnchor is set: check DocSnapshot.headings. If absent
12
25
  // → missing_anchor.
13
- export function checkBrokenRefs(snapshots, edges) {
26
+ import { isAbsolute, relative as nodeRelative, resolve as nodeResolve } from "node:path";
27
+ // True iff `abs` sits at or under `root` (lexical containment; both sides are
28
+ // already-resolved absolute paths).
29
+ function within(root, abs) {
30
+ const rel = nodeRelative(root, abs);
31
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
32
+ }
33
+ export function checkBrokenRefs(snapshots, edges,
34
+ // Must return true only when targetAbs exists on disk AND its REAL
35
+ // (symlink-resolved) location sits under rootAbs. See
36
+ // collect.ts#symlinkSafeExistsWithin for the production implementation.
37
+ existsWithin) {
14
38
  // Index snapshots by repo name for O(1) lookup.
15
39
  const byRepo = new Map();
16
40
  for (const snap of snapshots) {
17
41
  byRepo.set(snap.config.name, snap);
18
42
  }
43
+ // The existence oracle is CONFINED (security review on #255): probing an
44
+ // arbitrary resolvedAbs would let anyone who can author a doc turn the
45
+ // audit report into a host-filesystem existence probe
46
+ // ([x](../../../../etc/shadow) → out_of_scope_target vs missing_file).
47
+ // #133's actual case is UNAUDITED SIBLINGS, so out-of-scope probes are
48
+ // allowed only under the parent directories of the configured repo roots;
49
+ // anything further out is reported missing_file without ever touching
50
+ // disk — exactly the pre-oracle behavior. A repo mounted directly under
51
+ // the filesystem root gets NO sibling scope: its "parent" would be the
52
+ // entire filesystem and the confinement would collapse to none, so
53
+ // out-of-scope refs from such a repo stay unprobed.
54
+ const siblingScopes = snapshots.flatMap((s) => {
55
+ const parent = nodeResolve(s.config.path, "..");
56
+ return nodeResolve(parent, "..") === parent ? [] : [parent];
57
+ });
19
58
  const findings = [];
20
59
  for (const edge of edges) {
60
+ const finding = (kind, path) => ({
61
+ kind,
62
+ source: { repo: edge.sourceRepo, path: edge.sourcePath },
63
+ target: { repo: edge.targetRepo, path, anchor: edge.targetAnchor },
64
+ rawHref: edge.rawHref,
65
+ });
21
66
  const targetSnap = byRepo.get(edge.targetRepo);
22
67
  if (!targetSnap) {
23
68
  // Target repo itself is unknown — treat as missing file.
24
- findings.push({
25
- kind: "missing_file",
26
- source: { repo: edge.sourceRepo, path: edge.sourcePath },
27
- target: { repo: edge.targetRepo, path: edge.targetPath, anchor: edge.targetAnchor },
28
- rawHref: edge.rawHref,
29
- });
69
+ findings.push(finding("missing_file", edge.targetPath));
30
70
  continue;
31
71
  }
32
72
  // Resolve the target doc: exact match, then .md fallback.
@@ -41,24 +81,39 @@ export function checkBrokenRefs(snapshots, edges) {
41
81
  }
42
82
  }
43
83
  if (resolvedPath === null) {
44
- findings.push({
45
- kind: "missing_file",
46
- source: { repo: edge.sourceRepo, path: edge.sourcePath },
47
- target: { repo: edge.targetRepo, path: edge.targetPath, anchor: edge.targetAnchor },
48
- rawHref: edge.rawHref,
49
- });
84
+ if (edge.outOfScope) {
85
+ // The href escaped every audited repo (#133). A file that exists out
86
+ // there is not a broken link — but it stays VISIBLE with its own
87
+ // kind, never silently passed: the audit cannot vouch for a target
88
+ // it does not scan. The probe runs only inside the sibling scopes
89
+ // (see above); a target beyond them is missing_file, unprobed.
90
+ const resolvedAbs = edge.resolvedAbs;
91
+ // Lexical pre-filter picks the candidate scope without touching
92
+ // disk; the oracle then re-verifies containment on REAL paths.
93
+ const scope = resolvedAbs !== undefined ? siblingScopes.find((s) => within(s, resolvedAbs)) : undefined;
94
+ findings.push(finding(resolvedAbs !== undefined && scope !== undefined && existsWithin?.(scope, resolvedAbs)
95
+ ? "out_of_scope_target"
96
+ : "missing_file", edge.targetPath));
97
+ continue;
98
+ }
99
+ // In-scope miss: the docs map only holds glob-matched markdown, but a
100
+ // reference to a real on-disk asset is legitimate (#132) — one
101
+ // existence probe, no finding. Anchors into assets are unverifiable.
102
+ // The probe is confined to the target repo root: a URL-derived
103
+ // targetPath can carry ../ segments, and escaping paths must not be
104
+ // probed (same oracle concern as above).
105
+ const abs = nodeResolve(targetSnap.config.path, edge.targetPath);
106
+ if (within(targetSnap.config.path, abs) && existsWithin?.(targetSnap.config.path, abs)) {
107
+ continue;
108
+ }
109
+ findings.push(finding("missing_file", edge.targetPath));
50
110
  continue;
51
111
  }
52
112
  // File found. Check anchor if present.
53
113
  if (edge.targetAnchor !== null) {
54
114
  const doc = targetSnap.docs.get(resolvedPath);
55
115
  if (doc && !doc.headings.has(edge.targetAnchor)) {
56
- findings.push({
57
- kind: "missing_anchor",
58
- source: { repo: edge.sourceRepo, path: edge.sourcePath },
59
- target: { repo: edge.targetRepo, path: resolvedPath, anchor: edge.targetAnchor },
60
- rawHref: edge.rawHref,
61
- });
116
+ findings.push(finding("missing_anchor", resolvedPath));
62
117
  }
63
118
  }
64
119
  }
@@ -1 +1 @@
1
- {"version":3,"file":"broken_refs.js","sourceRoot":"","sources":["../../../src/audit/checks/broken_refs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"broken_refs.js","sourceRoot":"","sources":["../../../src/audit/checks/broken_refs.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,2EAA2E;AAC3E,6EAA6E;AAC7E,4EAA4E;AAC5E,2EAA2E;AAC3E,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E;AAC1E,sEAAsE;AACtE,EAAE;AACF,oBAAoB;AACpB,iEAAiE;AACjE,mDAAmD;AACnD,6EAA6E;AAC7E,2CAA2C;AAC3C,yEAAyE;AACzE,6EAA6E;AAC7E,kEAAkE;AAClE,6EAA6E;AAC7E,6EAA6E;AAC7E,0EAA0E;AAC1E,4DAA4D;AAC5D,iCAAiC;AACjC,+EAA+E;AAC/E,yBAAyB;AAEzB,OAAO,EAAE,UAAU,EAAE,QAAQ,IAAI,YAAY,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AAGzF,8EAA8E;AAC9E,oCAAoC;AACpC,SAAS,MAAM,CAAC,IAAY,EAAE,GAAW;IACvC,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACpC,OAAO,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,SAAyB,EACzB,KAAiB;AACjB,mEAAmE;AACnE,sDAAsD;AACtD,wEAAwE;AACxE,YAA8D;IAE9D,gDAAgD;IAChD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;IAC/C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,yEAAyE;IACzE,uEAAuE;IACvE,sDAAsD;IACtD,uEAAuE;IACvE,uEAAuE;IACvE,0EAA0E;IAC1E,sEAAsE;IACtE,wEAAwE;IACxE,uEAAuE;IACvE,mEAAmE;IACnE,oDAAoD;IACpD,MAAM,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QAC5C,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAChD,OAAO,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAuB,EAAE,CAAC;IAExC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,CAAC,IAA8B,EAAE,IAAY,EAAoB,EAAE,CAAC,CAAC;YACnF,IAAI;YACJ,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE;YACxD,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE;YAClE,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/C,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,yDAAyD;YACzD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YACxD,SAAS;QACX,CAAC;QAED,0DAA0D;QAC1D,IAAI,YAAY,GAAkB,IAAI,CAAC;QACvC,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACzC,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC;QACjC,CAAC;aAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,KAAK,CAAC;YACvC,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBAChC,YAAY,GAAG,MAAM,CAAC;YACxB,CAAC;QACH,CAAC;QAED,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;YAC1B,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACpB,qEAAqE;gBACrE,iEAAiE;gBACjE,mEAAmE;gBACnE,kEAAkE;gBAClE,+DAA+D;gBAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;gBACrC,gEAAgE;gBAChE,+DAA+D;gBAC/D,MAAM,KAAK,GACT,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC5F,QAAQ,CAAC,IAAI,CACX,OAAO,CACL,WAAW,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,IAAI,YAAY,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC;oBACpF,CAAC,CAAC,qBAAqB;oBACvB,CAAC,CAAC,cAAc,EAClB,IAAI,CAAC,UAAU,CAChB,CACF,CAAC;gBACF,SAAS;YACX,CAAC;YACD,sEAAsE;YACtE,+DAA+D;YAC/D,qEAAqE;YACrE,+DAA+D;YAC/D,oEAAoE;YACpE,yCAAyC;YACzC,MAAM,GAAG,GAAG,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YACjE,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,YAAY,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;gBACvF,SAAS;YACX,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YACxD,SAAS;QACX,CAAC;QAED,uCAAuC;QACvC,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAC9C,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;gBAChD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { type Result } from "../frontmatter/types.js";
2
2
  import type { AuditConfig, AuditError, RepoSnapshot } from "./types.js";
3
+ export declare function symlinkSafeExistsWithin(rootAbs: string, targetAbs: string): boolean;
3
4
  export declare function collectRepos(config: AuditConfig): Promise<Result<RepoSnapshot[], AuditError>>;
4
5
  //# sourceMappingURL=collect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../../src/audit/collect.ts"],"names":[],"mappings":"AAWA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAA2B,YAAY,EAAE,MAAM,YAAY,CAAC;AAqKjG,wBAAsB,YAAY,CAChC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,UAAU,CAAC,CAAC,CAa7C"}
1
+ {"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../../src/audit/collect.ts"],"names":[],"mappings":"AAWA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAA2B,YAAY,EAAE,MAAM,YAAY,CAAC;AAYjG,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CASnF;AAoKD,wBAAsB,YAAY,CAChC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,UAAU,CAAC,CAAC,CAa7C"}
@@ -3,14 +3,34 @@
3
3
  // frontmatter, extract headings (GitHub-slugged) and links, then batch
4
4
  // git log to populate mtimes; on any git failure, fall back to fs mtime.
5
5
  import { execFileSync } from "node:child_process";
6
- import { statSync } from "node:fs";
6
+ import { realpathSync, statSync } from "node:fs";
7
7
  import { readFile } from "node:fs/promises";
8
- import { resolve as nodeResolve } from "node:path";
8
+ import { isAbsolute, relative as nodeRelative, resolve as nodeResolve } from "node:path";
9
9
  import { glob } from "glob";
10
10
  import matter from "gray-matter";
11
11
  import { err, ok } from "../frontmatter/types.js";
12
12
  import { extractLinksFromBody } from "./links.js";
13
13
  import { runtimeError } from "./types.js";
14
+ // The disk oracle for checkBrokenRefs (#132/#133): true iff targetAbs
15
+ // exists AND its REAL location sits under rootAbs. realpathSync resolves
16
+ // every component, so a symlink committed inside an audited repo
17
+ // (escape -> /) cannot route the probe outside the containment root — a
18
+ // lexical check plus a bare existsSync would (security review on #255).
19
+ // rootAbs is expected to be already-real: repo roots are realpathSync'd at
20
+ // config load, and the parent prefix of a real path is itself real.
21
+ // A nonexistent target makes realpathSync throw ENOENT → false, which is
22
+ // exactly the "missing" answer.
23
+ export function symlinkSafeExistsWithin(rootAbs, targetAbs) {
24
+ let real;
25
+ try {
26
+ real = realpathSync(targetAbs);
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ const rel = nodeRelative(rootAbs, real);
32
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
33
+ }
14
34
  function slugify(heading) {
15
35
  // GitHub slug: lowercase, strip non-alphanumeric (keep `-_`), whitespace -> `-`.
16
36
  return heading
@@ -1 +1 @@
1
- {"version":3,"file":"collect.js","sourceRoot":"","sources":["../../src/audit/collect.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collect.js","sourceRoot":"","sources":["../../src/audit/collect.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAqBvE,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAqED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,GAAE,cAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8H9F"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAqBvE,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAqED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,GAAE,cAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoI9F"}
@@ -11,7 +11,7 @@ import { createAnthropicClient } from "../eval/llm.js";
11
11
  import { checkBrokenRefs } from "./checks/broken_refs.js";
12
12
  import { checkDescribesRefs } from "./checks/describes_refs.js";
13
13
  import { checkStaleness } from "./checks/staleness.js";
14
- import { collectRepos } from "./collect.js";
14
+ import { collectRepos, symlinkSafeExistsWithin } from "./collect.js";
15
15
  import { parseAuditConfig } from "./config.js";
16
16
  import { classifyDescribesEdges } from "./describes.js";
17
17
  import { computeExitCode } from "./exit.js";
@@ -135,7 +135,10 @@ export async function runAudit(argv, overrides = {}) {
135
135
  }
136
136
  const snapshots = collected.value;
137
137
  const edges = classifyEdges(snapshots);
138
- const brokenRefs = checkBrokenRefs(snapshots, edges);
138
+ // The disk oracle lets the pure check distinguish real breaks from
139
+ // references to on-disk assets (#132) and unaudited siblings (#133) —
140
+ // symlink-safe, so a committed link cannot route the probe off-scope.
141
+ const brokenRefs = checkBrokenRefs(snapshots, edges, symlinkSafeExistsWithin);
139
142
  const staleness = checkStaleness(snapshots, edges, config.staleness.thresholdDays, new Date());
140
143
  const describesEdges = classifyDescribesEdges(snapshots);
141
144
  const describesRefs = checkDescribesRefs(snapshots, describesEdges);
@@ -162,7 +165,10 @@ export async function runAudit(argv, overrides = {}) {
162
165
  docsScanned: snapshots
163
166
  .filter((s) => s.config.type !== "code")
164
167
  .reduce((n, s) => n + s.docs.size, 0),
165
- brokenRefs: brokenRefs.length,
168
+ // Out-of-scope targets are visibility, not breakage (#133): their own
169
+ // total, excluded from brokenRefs so the failOn gate never trips on them.
170
+ brokenRefs: brokenRefs.filter((f) => f.kind !== "out_of_scope_target").length,
171
+ outOfScopeTargets: brokenRefs.filter((f) => f.kind === "out_of_scope_target").length,
166
172
  directlyStale: staleness.filter((f) => f.kind === "direct").length,
167
173
  transitivelyStale: staleness.filter((f) => f.kind === "transitive").length,
168
174
  brokenDescribes: describesRefs.length,