secondbrain-py 0.2.1__py3-none-any.whl

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 (273) hide show
  1. brain/__init__.py +0 -0
  2. brain/__main__.py +18 -0
  3. brain/_capture_command.py +445 -0
  4. brain/_compose.py +52 -0
  5. brain/activity.py +206 -0
  6. brain/ask.py +631 -0
  7. brain/audio.py +591 -0
  8. brain/backfill/__init__.py +12 -0
  9. brain/backfill/search_extras.py +141 -0
  10. brain/backfill/source_rows.py +101 -0
  11. brain/bin/__init__.py +1 -0
  12. brain/bin/_launcher.py +107 -0
  13. brain/bin/down.py +8 -0
  14. brain/bin/launchd.py +268 -0
  15. brain/bin/monitor.py +570 -0
  16. brain/bin/rebuild.py +8 -0
  17. brain/bin/status.py +8 -0
  18. brain/bin/up.py +8 -0
  19. brain/brief.py +272 -0
  20. brain/capture.py +49 -0
  21. brain/chat.py +293 -0
  22. brain/cli.py +9760 -0
  23. brain/cli_claude.py +81 -0
  24. brain/cli_connect.py +285 -0
  25. brain/cli_demo.py +266 -0
  26. brain/config.py +1949 -0
  27. brain/connect.py +925 -0
  28. brain/db.py +540 -0
  29. brain/demo/__init__.py +452 -0
  30. brain/demo/corpus/manifest.json +403 -0
  31. brain/demo/embedder.py +74 -0
  32. brain/durations.py +84 -0
  33. brain/edit_session.py +156 -0
  34. brain/editor.py +67 -0
  35. brain/elicit/__init__.py +16 -0
  36. brain/elicit/detectors.py +250 -0
  37. brain/elicit/drafter.py +70 -0
  38. brain/elicit/queue.py +220 -0
  39. brain/elicit/schema.py +48 -0
  40. brain/elicit/session.py +445 -0
  41. brain/embedding_targets.py +54 -0
  42. brain/embeddings.py +424 -0
  43. brain/enrichment.py +808 -0
  44. brain/errors.py +357 -0
  45. brain/eval/__init__.py +129 -0
  46. brain/eval/answer_eval.py +281 -0
  47. brain/eval/baseline.py +265 -0
  48. brain/eval/concept_extraction.py +378 -0
  49. brain/eval/corpus.py +152 -0
  50. brain/eval/errors.py +19 -0
  51. brain/eval/graph_baseline.py +226 -0
  52. brain/eval/graph_retrieval.py +202 -0
  53. brain/eval/graph_runner.py +319 -0
  54. brain/eval/metrics.py +101 -0
  55. brain/eval/runner.py +223 -0
  56. brain/format.py +783 -0
  57. brain/gaps.py +390 -0
  58. brain/graph_rag/__init__.py +94 -0
  59. brain/graph_rag/_retrieval_common.py +113 -0
  60. brain/graph_rag/aggregates.py +303 -0
  61. brain/graph_rag/aliases/__init__.py +583 -0
  62. brain/graph_rag/backends/__init__.py +10 -0
  63. brain/graph_rag/backends/_age_helpers.py +473 -0
  64. brain/graph_rag/backends/age.py +782 -0
  65. brain/graph_rag/backends/base.py +272 -0
  66. brain/graph_rag/build.py +344 -0
  67. brain/graph_rag/communities.py +644 -0
  68. brain/graph_rag/communities_summary.py +437 -0
  69. brain/graph_rag/concepts.py +202 -0
  70. brain/graph_rag/cooccur.py +193 -0
  71. brain/graph_rag/cross_type.py +312 -0
  72. brain/graph_rag/extract.py +885 -0
  73. brain/graph_rag/fuse.py +371 -0
  74. brain/graph_rag/global_.py +412 -0
  75. brain/graph_rag/grouping.py +372 -0
  76. brain/graph_rag/person_resolver.py +167 -0
  77. brain/graph_rag/reconcile.py +792 -0
  78. brain/graph_rag/relational.py +353 -0
  79. brain/graph_rag/retrieve.py +526 -0
  80. brain/graph_rag/router.py +288 -0
  81. brain/graph_rag/schema.py +320 -0
  82. brain/graph_rag/sync.py +237 -0
  83. brain/graph_rag/tenancy.py +43 -0
  84. brain/graph_rag/themes.py +501 -0
  85. brain/graph_rag/weighting.py +202 -0
  86. brain/ingest/__init__.py +1926 -0
  87. brain/ingest/chunker.py +249 -0
  88. brain/ingest/docx.py +40 -0
  89. brain/ingest/gmail.py +621 -0
  90. brain/ingest/markdown.py +37 -0
  91. brain/ingest/pdf.py +61 -0
  92. brain/ingest/stdin.py +22 -0
  93. brain/ingest/sub_tokens.py +91 -0
  94. brain/ingest/text.py +16 -0
  95. brain/interactions.py +205 -0
  96. brain/maintenance.py +355 -0
  97. brain/mcp_server.py +3405 -0
  98. brain/migrations/001_init.sql +43 -0
  99. brain/migrations/002_qwen3_embedding.sql +17 -0
  100. brain/migrations/003_vault_model.sql +41 -0
  101. brain/migrations/004_relax_content_hash_uniqueness.sql +18 -0
  102. brain/migrations/005_derived_links.sql +67 -0
  103. brain/migrations/006_dedup_file_by_source_path.sql +25 -0
  104. brain/migrations/007_email_thread_and_draft.sql +15 -0
  105. brain/migrations/008_gmail_thread_unique.sql +11 -0
  106. brain/migrations/009_chunks_weighted_tsv.sql +28 -0
  107. brain/migrations/010_interactions.sql +30 -0
  108. brain/migrations/011_documents_summary.sql +23 -0
  109. brain/migrations/012_graphrag.sql +171 -0
  110. brain/migrations/013_graphrag_communities.sql +125 -0
  111. brain/migrations/014_graphrag_community_summary_hash.sql +33 -0
  112. brain/migrations/015_interactions_graph_targets.sql +89 -0
  113. brain/migrations/016_index_hygiene.sql +61 -0
  114. brain/migrations/017_elicit.sql +30 -0
  115. brain/migrations/018_review_gap_signal_kinds.sql +40 -0
  116. brain/migrations/019_search_queries.sql +35 -0
  117. brain/migrations/020_link_suggestions.sql +40 -0
  118. brain/migrations/021_timeline_doc_date.sql +34 -0
  119. brain/migrations/022_link_suggestions_undirected.sql +84 -0
  120. brain/migrations/023_search_queries_fts_count.sql +28 -0
  121. brain/quartz_overrides/__init__.py +8 -0
  122. brain/quartz_overrides/quartz/bootstrap-cli.mjs +65 -0
  123. brain/quartz_overrides/quartz/build.ts +568 -0
  124. brain/quartz_overrides/quartz/cli/args.js +152 -0
  125. brain/quartz_overrides/quartz/cli/build_partial_handler.js +544 -0
  126. brain/quartz_overrides/quartz/cli/handlers.js +636 -0
  127. brain/quartz_overrides/quartz/components/CommandPalette.tsx +172 -0
  128. brain/quartz_overrides/quartz/components/Explorer.tsx +198 -0
  129. brain/quartz_overrides/quartz/components/Footer.tsx +27 -0
  130. brain/quartz_overrides/quartz/components/Graph.tsx +468 -0
  131. brain/quartz_overrides/quartz/components/PageTitle.tsx +72 -0
  132. brain/quartz_overrides/quartz/components/RelatedDocs.tsx +38 -0
  133. brain/quartz_overrides/quartz/components/Search.tsx +161 -0
  134. brain/quartz_overrides/quartz/components/SummaryLede.tsx +72 -0
  135. brain/quartz_overrides/quartz/components/index.ts +92 -0
  136. brain/quartz_overrides/quartz/components/pages/TagContent.tsx +272 -0
  137. brain/quartz_overrides/quartz/components/scripts/commandPalette.inline.ts +665 -0
  138. brain/quartz_overrides/quartz/components/scripts/explorer.inline.ts +768 -0
  139. brain/quartz_overrides/quartz/components/scripts/graph.inline.ts +2302 -0
  140. brain/quartz_overrides/quartz/components/scripts/relatedDocs.inline.ts +163 -0
  141. brain/quartz_overrides/quartz/components/scripts/search.inline.ts +1011 -0
  142. brain/quartz_overrides/quartz/plugins/emitters/contentIndex.ts +546 -0
  143. brain/quartz_overrides/quartz/plugins/transformers/codeCopy.ts +94 -0
  144. brain/quartz_overrides/quartz/plugins/transformers/derivedFenceMark.ts +302 -0
  145. brain/quartz_overrides/quartz/plugins/transformers/emailThread.ts +148 -0
  146. brain/quartz_overrides/quartz/plugins/transformers/emptyDoorFilter.ts +213 -0
  147. brain/quartz_overrides/quartz/plugins/transformers/index.ts +114 -0
  148. brain/quartz_overrides/quartz/plugins/transformers/linkKindMark.ts +205 -0
  149. brain/quartz_overrides/quartz/plugins/transformers/linkSourceTag.ts +104 -0
  150. brain/quartz_overrides/quartz/plugins/transformers/relativeDate.ts +100 -0
  151. brain/quartz_overrides/quartz/plugins/transformers/reloadSignal.ts +131 -0
  152. brain/quartz_overrides/quartz/processors/parse.ts +371 -0
  153. brain/quartz_overrides/quartz/processors/parser_cache.ts +78 -0
  154. brain/quartz_overrides/quartz/static/brain-logo-dark.png +0 -0
  155. brain/quartz_overrides/quartz/static/brain-logo-light.png +0 -0
  156. brain/quartz_overrides/quartz/static/codeCopy.js +196 -0
  157. brain/quartz_overrides/quartz/static/emailThread.js +334 -0
  158. brain/quartz_overrides/quartz/static/favicon.ico +0 -0
  159. brain/quartz_overrides/quartz/static/icon.png +0 -0
  160. brain/quartz_overrides/quartz/static/linkSourceTag.js +104 -0
  161. brain/quartz_overrides/quartz/static/relativeDate.js +142 -0
  162. brain/quartz_overrides/quartz/static/reload.js +168 -0
  163. brain/quartz_overrides/quartz/styles/brain/_article.scss +252 -0
  164. brain/quartz_overrides/quartz/styles/brain/_atmosphere.scss +113 -0
  165. brain/quartz_overrides/quartz/styles/brain/_callouts.scss +180 -0
  166. brain/quartz_overrides/quartz/styles/brain/_cmdk.scss +7 -0
  167. brain/quartz_overrides/quartz/styles/brain/_code.scss +208 -0
  168. brain/quartz_overrides/quartz/styles/brain/_command_palette.scss +369 -0
  169. brain/quartz_overrides/quartz/styles/brain/_email_thread.scss +228 -0
  170. brain/quartz_overrides/quartz/styles/brain/_explorer.scss +142 -0
  171. brain/quartz_overrides/quartz/styles/brain/_home.scss +182 -0
  172. brain/quartz_overrides/quartz/styles/brain/_links.scss +322 -0
  173. brain/quartz_overrides/quartz/styles/brain/_marginalia.scss +117 -0
  174. brain/quartz_overrides/quartz/styles/brain/_motion.scss +175 -0
  175. brain/quartz_overrides/quartz/styles/brain/_people_hub.scss +100 -0
  176. brain/quartz_overrides/quartz/styles/brain/_related_docs.scss +137 -0
  177. brain/quartz_overrides/quartz/styles/brain/_search.scss +252 -0
  178. brain/quartz_overrides/quartz/styles/brain/_sidebar.scss +468 -0
  179. brain/quartz_overrides/quartz/styles/brain/_summary_lede.scss +56 -0
  180. brain/quartz_overrides/quartz/styles/brain/_surface.scss +43 -0
  181. brain/quartz_overrides/quartz/styles/brain/_tag_content.scss +118 -0
  182. brain/quartz_overrides/quartz/styles/brain/_tokens.scss +197 -0
  183. brain/quartz_overrides/quartz/styles/brain/_typography.scss +92 -0
  184. brain/quartz_overrides/quartz/styles/custom.scss +89 -0
  185. brain/quartz_overrides/quartz/styles/graph.scss +505 -0
  186. brain/quartz_overrides/quartz/util/ctx.ts +92 -0
  187. brain/quartz_overrides/quartz/util/fastpath_manifest.ts +608 -0
  188. brain/quartz_overrides/quartz/util/path.ts +358 -0
  189. brain/quartz_overrides/quartz/util/sourceIcons.ts +55 -0
  190. brain/quartz_overrides/quartz.config.ts +270 -0
  191. brain/quartz_overrides/quartz.layout.ts +314 -0
  192. brain/queries.py +1188 -0
  193. brain/rank_fusion.py +8 -0
  194. brain/resurface.py +210 -0
  195. brain/review/__init__.py +26 -0
  196. brain/review/emit.py +27 -0
  197. brain/review/queries.py +436 -0
  198. brain/review/render.py +196 -0
  199. brain/review/scans.py +355 -0
  200. brain/review/weekly.py +413 -0
  201. brain/search.py +704 -0
  202. brain/set_similarity.py +15 -0
  203. brain/setup.py +1205 -0
  204. brain/tags.py +56 -0
  205. brain/templates/Caddyfile.j2 +9 -0
  206. brain/templates/__init__.py +1 -0
  207. brain/templates/bin/__init__.py +1 -0
  208. brain/templates/bin/_brain-brief-fg.sh +25 -0
  209. brain/templates/bin/_brain-build-fg.sh +53 -0
  210. brain/templates/bin/_brain-watcher-fg.sh +65 -0
  211. brain/templates/bin/brain-down.sh +89 -0
  212. brain/templates/bin/brain-status.sh +83 -0
  213. brain/templates/bin/brain-up.sh +221 -0
  214. brain/templates/docker/age/Dockerfile +79 -0
  215. brain/templates/docker-compose.stock.yml.j2 +26 -0
  216. brain/templates/docker-compose.yml.j2 +34 -0
  217. brain/templates/env.example +190 -0
  218. brain/templates/launchd/__init__.py +1 -0
  219. brain/templates/launchd/com.brain.brief.plist.j2 +45 -0
  220. brain/templates/launchd/com.brain.build.plist.j2 +46 -0
  221. brain/templates/launchd/com.brain.watcher.plist.j2 +46 -0
  222. brain/templates/skill/SKILL.md +63 -0
  223. brain/templates/skill/__init__.py +1 -0
  224. brain/timeline.py +834 -0
  225. brain/todo.py +124 -0
  226. brain/uninstall.py +185 -0
  227. brain/vault/__init__.py +115 -0
  228. brain/vault/_atomic.py +25 -0
  229. brain/vault/daily_index.py +228 -0
  230. brain/vault/derived_links/__init__.py +50 -0
  231. brain/vault/derived_links/directory.py +683 -0
  232. brain/vault/derived_links/fence.py +408 -0
  233. brain/vault/derived_links/gws.py +64 -0
  234. brain/vault/derived_links/participants.py +143 -0
  235. brain/vault/derived_links/pass_runner.py +362 -0
  236. brain/vault/derived_links/rules.py +137 -0
  237. brain/vault/export.py +683 -0
  238. brain/vault/frontmatter.py +165 -0
  239. brain/vault/graph.py +620 -0
  240. brain/vault/graph_format.py +388 -0
  241. brain/vault/link_rewrite.py +235 -0
  242. brain/vault/links.py +260 -0
  243. brain/vault/note_builder.py +211 -0
  244. brain/vault/paths.py +55 -0
  245. brain/vault/quartz_overlay.py +236 -0
  246. brain/vault/rename.py +591 -0
  247. brain/vault/resolver.py +304 -0
  248. brain/vault/slug.py +127 -0
  249. brain/vault/sync.py +1513 -0
  250. brain/vault/sync_summaries.py +264 -0
  251. brain/vault/templates.py +145 -0
  252. brain/vault/watch.py +1052 -0
  253. brain/wiki/__init__.py +6 -0
  254. brain/wiki/_github_slugger.py +76 -0
  255. brain/wiki/_person_name.py +314 -0
  256. brain/wiki/build_homepage.py +541 -0
  257. brain/wiki/build_partial.py +273 -0
  258. brain/wiki/build_people.py +934 -0
  259. brain/wiki/build_related.py +758 -0
  260. brain/wiki/build_swap.py +585 -0
  261. brain/wiki/build_watcher.py +975 -0
  262. brain/wiki/edit_classifier.py +215 -0
  263. brain/wiki/errors.py +10 -0
  264. brain/wiki/fastpath_manifest.py +475 -0
  265. brain/wiki/fastpath_state.py +174 -0
  266. brain/wiki/install.py +296 -0
  267. brain/wiki/slug.py +111 -0
  268. secondbrain_py-0.2.1.dist-info/METADATA +195 -0
  269. secondbrain_py-0.2.1.dist-info/RECORD +273 -0
  270. secondbrain_py-0.2.1.dist-info/WHEEL +5 -0
  271. secondbrain_py-0.2.1.dist-info/entry_points.txt +11 -0
  272. secondbrain_py-0.2.1.dist-info/licenses/LICENSE +21 -0
  273. secondbrain_py-0.2.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,505 @@
1
+ // Brain palette for the custom Quartz Graph component.
2
+ //
3
+ // This file is a TEMPLATE. It is installed at
4
+ // `<vault>/.quartz/quartz/styles/graph.scss` by `brain vault render
5
+ // --overlay`. It is brand-new — not a replacement for upstream's
6
+ // `quartz/components/styles/graph.scss`, which carries the
7
+ // component's box layout (sidebar sizing, modal positioning) and
8
+ // is untouched by this overlay. The brain palette below loads
9
+ // alongside it, imported as a sibling stylesheet by the custom
10
+ // `Graph.tsx` and concatenated onto the component's `css` property.
11
+ //
12
+ // Tested against Quartz v4.5.x (April 2026). The CSS variables
13
+ // defined here are referenced by name from
14
+ // `components/scripts/graph.inline.ts` (via the `cssVars`
15
+ // precompute list and the `cssVar()` helper) and by the
16
+ // `D3Config.tierColors` / `sourceColors` defaults in
17
+ // `components/Graph.tsx`. Renaming or removing a variable here
18
+ // requires the matching update in those two files; the renderer
19
+ // would otherwise resolve to an empty string and silently fall
20
+ // through to `--gray`.
21
+
22
+ // brain-extension: the `--brain-tier-*` and `--brain-source-*` tokens
23
+ // formerly declared here moved to
24
+ // `quartz/styles/brain/_tokens.scss` as part of the 2026-05-02
25
+ // redesign (Lane A) so the graph palette and the ingested-link
26
+ // styling (Lane B) share one source of truth.
27
+ //
28
+ // Note: the previous dark-mode block selected on `[data-theme="dark"]`,
29
+ // which Quartz never sets (the dark-mode toggle writes
30
+ // `<html saved-theme="dark">` — see `darkmode.inline.ts`). The new
31
+ // tokens file uses the correct selector so dark-mode source colors
32
+ // actually fire.
33
+ //
34
+ // Future graph-only tokens live alongside the palette in `_tokens.scss`.
35
+
36
+ // brain-extension: in-graph controls (search input + filter chip rows).
37
+ // Rendered as the first child of `.graph-container` / `.global-graph-container`
38
+ // so they sit above the PixiJS canvas. Sized to take minimal vertical space
39
+ // and to wrap if the sidebar is narrow.
40
+ .brain-graph-controls {
41
+ display: flex;
42
+ flex-direction: column;
43
+ gap: 0.25rem;
44
+ margin-bottom: 0.4rem;
45
+ font-size: 0.75rem;
46
+ line-height: 1.2;
47
+ min-width: 0;
48
+ }
49
+
50
+ .brain-graph-toolbar {
51
+ flex-direction: row;
52
+ align-items: center;
53
+ gap: 0.45rem;
54
+ padding: 0.55rem 0.65rem;
55
+ margin-bottom: 0;
56
+ border-bottom: 1px solid var(--rule);
57
+ background: color-mix(in srgb, var(--surface-1) 94%, var(--dark) 6%);
58
+ position: relative;
59
+ z-index: 2;
60
+
61
+ .brain-graph-search {
62
+ max-width: 24rem;
63
+ min-width: 12rem;
64
+ }
65
+
66
+ .brain-graph-chip-row {
67
+ flex-wrap: nowrap;
68
+ overflow-x: auto;
69
+ scrollbar-width: thin;
70
+ }
71
+ }
72
+
73
+ .brain-graph-search {
74
+ width: 100%;
75
+ min-width: 0;
76
+ box-sizing: border-box;
77
+ // brain (Linear-variant feedback): bumped padding so the input
78
+ // stands ~28px tall, visually balancing the 24×24 graph icon
79
+ // buttons absolutely-positioned to its right. Was 0.25rem 0.5rem
80
+ // — too short, read as a stubby strip next to the buttons.
81
+ padding: 0.45rem 0.7rem;
82
+ border: 1px solid var(--lightgray);
83
+ border-radius: 4px;
84
+ background: var(--light);
85
+ color: var(--dark);
86
+ font: inherit;
87
+
88
+ // brain: explicit focus indicator for keyboard users — a border-color
89
+ // change alone wasn't enough at high-contrast settings. Outline-offset
90
+ // keeps the ring outside the rounded border so the visual cue is
91
+ // unambiguous.
92
+ &:focus {
93
+ outline: 2px solid var(--secondary);
94
+ outline-offset: 1px;
95
+ border-color: var(--secondary);
96
+ }
97
+ }
98
+
99
+ .brain-graph-chip-row {
100
+ display: flex;
101
+ flex-wrap: wrap;
102
+ align-items: center;
103
+ gap: 0.2rem;
104
+ }
105
+
106
+ .brain-graph-chip-label {
107
+ color: var(--darkgray);
108
+ margin-right: 0.15rem;
109
+ text-transform: capitalize;
110
+ }
111
+
112
+ // Each chip is a button by element so it remains keyboard-focusable. The
113
+ // "active" class flips it to a filled state so the user reads which values
114
+ // are currently included in the filter at a glance.
115
+ .brain-graph-chip {
116
+ appearance: none;
117
+ border: 1px solid var(--lightgray);
118
+ background: transparent;
119
+ color: var(--darkgray);
120
+ border-radius: 999px;
121
+ padding: 0.1rem 0.55rem;
122
+ font: inherit;
123
+ cursor: pointer;
124
+ transition:
125
+ background-color 0.12s ease,
126
+ color 0.12s ease,
127
+ border-color 0.12s ease;
128
+
129
+ &:hover {
130
+ border-color: var(--gray);
131
+ color: var(--dark);
132
+ }
133
+
134
+ // brain: explicit focus ring for keyboard navigation. `:focus-visible`
135
+ // (vs plain `:focus`) keeps the indicator from showing on mouse-click,
136
+ // which feels noisy on a chip group, while still surfacing it for
137
+ // tab-traversed users.
138
+ &:focus-visible {
139
+ outline: 2px solid var(--secondary);
140
+ outline-offset: 1px;
141
+ }
142
+
143
+ &.active {
144
+ background: var(--secondary);
145
+ border-color: var(--secondary);
146
+ color: var(--light);
147
+ }
148
+
149
+ // The "all" chip gets a subtler accent so it doesn't compete with the
150
+ // value chips for attention — it's a reset affordance, not a filter
151
+ // value in its own right.
152
+ &.brain-graph-chip-all {
153
+ font-weight: 600;
154
+ text-transform: uppercase;
155
+ font-size: 0.65rem;
156
+ letter-spacing: 0.04em;
157
+
158
+ &.active {
159
+ background: var(--tertiary);
160
+ border-color: var(--tertiary);
161
+ }
162
+ }
163
+ }
164
+
165
+ // brain: stock Quartz renders the global-graph button as
166
+ // `<button class="global-graph-icon">` directly inside `.graph-outer`,
167
+ // but its own graph.scss only styles `.graph-icon` (no `global-` prefix
168
+ // and inside a `.graph-icons` wrapper that doesn't exist in the markup).
169
+ // Result on stock Quartz: the button sits unstyled in the top-left,
170
+ // hard to see and easy to miss. We position + size it explicitly so
171
+ // readers can actually find the "open global graph" affordance.
172
+ //
173
+ // brain-extension: `.brain-stock-graph-icon` is a sibling affordance that
174
+ // opens the SAME global-graph modal but with the renderer's brain extensions
175
+ // disabled (stock Quartz visuals). Same visual rules — only the absolute-
176
+ // position offset differs.
177
+ //
178
+ // Layout note (Linear-variant feedback): the buttons are absolutely
179
+ // positioned at the top-right corner. The `.brain-graph-controls`
180
+ // below reserves a `padding-right` equal to both buttons' combined
181
+ // horizontal footprint, so the search input shrinks to leave room
182
+ // rather than slipping under the buttons.
183
+ .graph > .graph-outer > .global-graph-icon,
184
+ .graph > .graph-outer > .brain-stock-graph-icon,
185
+ .graph > .graph-outer > .local-graph-fullscreen-icon,
186
+ .graph > .graph-outer > .brain-graph-workbench-icon {
187
+ position: absolute;
188
+ top: 0;
189
+ margin: 0.3rem;
190
+ cursor: pointer;
191
+ background: none;
192
+ border: none;
193
+ color: var(--dark);
194
+ opacity: 0.5;
195
+ width: 24px;
196
+ height: 24px;
197
+ padding: 0.2rem;
198
+ border-radius: 4px;
199
+ background-color: transparent;
200
+ transition: background-color 0.2s ease, opacity 0.2s ease;
201
+ display: inline-flex;
202
+ align-items: center;
203
+ justify-content: center;
204
+ z-index: 1;
205
+
206
+ svg {
207
+ width: 100%;
208
+ height: 100%;
209
+ }
210
+
211
+ &:hover {
212
+ background-color: var(--lightgray);
213
+ opacity: 1;
214
+ }
215
+
216
+ &:focus-visible {
217
+ outline: 2px solid var(--secondary);
218
+ outline-offset: 1px;
219
+ opacity: 1;
220
+ }
221
+ }
222
+
223
+ .graph > .graph-outer > .global-graph-icon {
224
+ right: 0;
225
+ }
226
+
227
+ // brain-extension: dot-grid affordance sits 28px to the left of the globe so
228
+ // the two icons read as a pair without visually colliding. Width-based offset
229
+ // (`right: 28px`) keeps them aligned to the same right edge regardless of the
230
+ // surrounding sidebar width.
231
+ .graph > .graph-outer > .brain-stock-graph-icon {
232
+ right: 28px;
233
+ }
234
+
235
+ .graph > .graph-outer > .brain-graph-workbench-icon {
236
+ right: 56px;
237
+ }
238
+
239
+ // brain-extension: maximize affordance sits left of the diagnostic,
240
+ // dot-grid, and global buttons. Order reads left-to-right as: local
241
+ // fullscreen / diagnostic workbench / stock / global.
242
+ .graph > .graph-outer > .local-graph-fullscreen-icon {
243
+ right: 84px;
244
+ }
245
+
246
+ // brain: keep upstream's `.graph-outer { height: 250px; overflow: hidden; }`
247
+ // untouched. The compact `.brain-graph-controls` redesign above takes
248
+ // only ~30px of vertical space (vs the previous ~94px), so a 250px
249
+ // container leaves ~220px for the canvas — plenty of room for the
250
+ // cluster — without growing the panel and pushing Table of Contents +
251
+ // Backlinks past the viewport. The d3-zoom fit-to-bounds pass in
252
+ // graph.inline.ts auto-scales the cluster to whatever canvas height
253
+ // we end up with.
254
+ //
255
+ // Defense-in-depth: also let the right sidebar scroll internally if a
256
+ // future content addition (e.g. a long ToC on a deeply-headed page)
257
+ // pushes total content past the viewport. No-op when content fits;
258
+ // gracefully scrolls when it doesn't.
259
+ // brain (Linear variant): global/local graph modal — contrast +
260
+ // positioning override.
261
+ //
262
+ // Stock paints `.global-graph-container` with `var(--light)` +
263
+ // `var(--lightgray)` border, which makes the modal invisible in our
264
+ // charcoal dark mode (page bg = `#0a0a0a` = same as `--light`). We
265
+ // override to `--surface-1` so the panel has elevation, then layer in
266
+ // `--scrim` for the backdrop.
267
+ //
268
+ // brain (Linear-variant feedback round 3): stock's modal centering
269
+ // relies on `display: inline-block` on the outer wrapper plus
270
+ // `transform: translate(-50%, -50%)` on the container, which together
271
+ // have been rendering the modal as a narrow vertical strip on the
272
+ // right edge of the viewport instead of a centered 80vw × 80vh panel.
273
+ // Bypass the recipe entirely:
274
+ // 1. `display: block` on `.global-graph-outer.active` kills the
275
+ // `inline-block` (stock's `width: 100vw` declaration only takes
276
+ // effect reliably on a block-level element).
277
+ // 2. Replace the `transform: translate(-50%, -50%)` centering trick
278
+ // with explicit `left: 10vw; top: 10vh` offsets. No transforms
279
+ // means no chance of an accidental containing-block creation
280
+ // for the fixed-position container.
281
+ .graph > .global-graph-outer,
282
+ .graph > .local-graph-outer,
283
+ .graph > .brain-graph-workbench-outer {
284
+ background: var(--scrim);
285
+ }
286
+
287
+ .graph > .brain-graph-workbench-outer {
288
+ backdrop-filter: blur(4px);
289
+ display: none;
290
+ height: 100%;
291
+ left: 0;
292
+ overflow: hidden;
293
+ position: fixed;
294
+ top: 0;
295
+ width: 100vw;
296
+ z-index: 9999;
297
+ }
298
+
299
+ .graph > .global-graph-outer.active,
300
+ .graph > .local-graph-outer.active,
301
+ .graph > .brain-graph-workbench-outer.active {
302
+ display: block;
303
+ }
304
+
305
+ .graph > .global-graph-outer > .global-graph-container,
306
+ .graph > .local-graph-outer > .local-graph-container {
307
+ background-color: var(--surface-1);
308
+ border-color: var(--rule);
309
+ box-shadow: var(--shadow-md);
310
+ // Explicit positioning replaces stock's `top: 50%; left: 50%;
311
+ // transform: translate(-50%, -50%)` recipe.
312
+ left: 10vw;
313
+ top: 10vh;
314
+ transform: none;
315
+ }
316
+
317
+ .graph > .brain-graph-workbench-outer > .brain-graph-workbench-container {
318
+ background-color: var(--surface-1);
319
+ border: 1px solid var(--rule);
320
+ border-radius: 5px;
321
+ border-color: var(--rule);
322
+ box-sizing: border-box;
323
+ box-shadow: var(--shadow-md);
324
+ position: fixed;
325
+ left: 4vw;
326
+ top: 6vh;
327
+ width: 92vw;
328
+ height: 88vh;
329
+ transform: none;
330
+ }
331
+
332
+ .brain-graph-workbench-shell {
333
+ display: grid;
334
+ grid-template-areas:
335
+ "toolbar toolbar toolbar"
336
+ "rail graph inspector";
337
+ grid-template-columns: 9.5rem minmax(0, 1fr) 18rem;
338
+ grid-template-rows: auto minmax(0, 1fr);
339
+ height: 100%;
340
+ min-height: 0;
341
+ isolation: isolate;
342
+ overflow: hidden;
343
+ }
344
+
345
+ .brain-graph-workbench-shell > .brain-graph-toolbar {
346
+ grid-area: toolbar;
347
+ }
348
+
349
+ .brain-graph-mode-rail {
350
+ grid-area: rail;
351
+ border-right: 1px solid var(--rule);
352
+ background: var(--surface-1);
353
+ padding: 0.75rem;
354
+ display: flex;
355
+ flex-direction: column;
356
+ gap: 0.45rem;
357
+ }
358
+
359
+ .brain-graph-mode {
360
+ appearance: none;
361
+ border: 1px solid var(--lightgray);
362
+ background: transparent;
363
+ color: var(--dark);
364
+ border-radius: 6px;
365
+ padding: 0.55rem 0.6rem;
366
+ text-align: left;
367
+ cursor: pointer;
368
+ font: inherit;
369
+
370
+ small {
371
+ display: block;
372
+ color: var(--darkgray);
373
+ font-size: 0.68rem;
374
+ margin-top: 0.12rem;
375
+ }
376
+
377
+ &.active {
378
+ border-color: var(--secondary);
379
+ background: color-mix(in srgb, var(--secondary) 14%, transparent);
380
+ }
381
+ }
382
+
383
+ .brain-graph-inspector {
384
+ grid-area: inspector;
385
+ align-self: stretch;
386
+ box-sizing: border-box;
387
+ border-left: 1px solid var(--rule);
388
+ background: #202124;
389
+ background-color: #202124;
390
+ color: var(--dark);
391
+ height: 100%;
392
+ justify-self: stretch;
393
+ min-height: 0;
394
+ min-width: 18rem;
395
+ padding: 0.9rem;
396
+ overflow: auto;
397
+ position: relative;
398
+ z-index: 3;
399
+
400
+ h3 {
401
+ margin: 0 0 0.25rem;
402
+ font-size: 1rem;
403
+ }
404
+
405
+ h4 {
406
+ margin: 1rem 0 0.35rem;
407
+ color: var(--darkgray);
408
+ font-size: 0.72rem;
409
+ text-transform: uppercase;
410
+ letter-spacing: 0.04em;
411
+ }
412
+
413
+ ul {
414
+ margin: 0;
415
+ padding-left: 1rem;
416
+ }
417
+ }
418
+
419
+ .brain-graph-inspector-meta {
420
+ color: var(--darkgray);
421
+ margin: 0 0 0.75rem;
422
+ }
423
+
424
+ .brain-graph-metrics {
425
+ display: grid;
426
+ grid-template-columns: 1fr 1fr;
427
+ gap: 0.45rem;
428
+
429
+ > div {
430
+ border: 1px solid var(--lightgray);
431
+ border-radius: 6px;
432
+ padding: 0.45rem;
433
+ }
434
+
435
+ strong,
436
+ span {
437
+ display: block;
438
+ }
439
+ }
440
+
441
+ .brain-graph-canvas-pane {
442
+ grid-area: graph;
443
+ align-self: stretch;
444
+ contain: paint;
445
+ justify-self: stretch;
446
+ min-height: 0;
447
+ min-width: 0;
448
+ overflow: hidden;
449
+ position: relative;
450
+ z-index: 1;
451
+ }
452
+
453
+ .brain-graph-canvas-pane > canvas {
454
+ display: block;
455
+ max-height: 100%;
456
+ max-width: 100%;
457
+ min-width: 0;
458
+ overflow: hidden;
459
+ }
460
+
461
+ .brain-graph-workbench-shell > .brain-graph-tooltip {
462
+ grid-column: 2;
463
+ grid-row: 2;
464
+ }
465
+
466
+ @media (max-width: 900px) {
467
+ .brain-graph-workbench-shell {
468
+ grid-template-areas:
469
+ "toolbar"
470
+ "rail"
471
+ "graph"
472
+ "inspector";
473
+ grid-template-columns: 1fr;
474
+ grid-template-rows: auto auto minmax(22rem, 1fr) auto;
475
+ }
476
+
477
+ .brain-graph-mode-rail {
478
+ flex-direction: row;
479
+ overflow-x: auto;
480
+ border-right: 0;
481
+ border-bottom: 1px solid var(--rule);
482
+ }
483
+
484
+ .brain-graph-inspector {
485
+ border-left: 0;
486
+ border-top: 1px solid var(--rule);
487
+ max-height: 14rem;
488
+ min-width: 0;
489
+ }
490
+ }
491
+
492
+ .sidebar.right {
493
+ overflow-y: auto;
494
+ // Hide the scrollbar gutter so the sidebar reads as a clean column
495
+ // when content fits. Still scrollable via wheel / touchpad gestures.
496
+ scrollbar-width: thin;
497
+ scrollbar-color: var(--lightgray) transparent;
498
+ &::-webkit-scrollbar {
499
+ width: 4px;
500
+ }
501
+ &::-webkit-scrollbar-thumb {
502
+ background: var(--lightgray);
503
+ border-radius: 2px;
504
+ }
505
+ }
@@ -0,0 +1,92 @@
1
+ // Brain wiki — BuildCtx with parser-cache plumbing.
2
+ //
3
+ // This file is a TEMPLATE. It is installed at
4
+ // `<vault>/.quartz/quartz/util/ctx.ts` by `brain vault render --overlay`,
5
+ // overwriting the stock upstream module.
6
+ //
7
+ // Changes from upstream:
8
+ // * `Argv.noCache?: boolean` — opt-out flag. When true, parseMarkdown
9
+ // sets cacheDir to null and the parser cache is disabled for the run.
10
+ // The upstream Quartz CLI handler does not set this flag (it lives in
11
+ // upstream-only handlers.ts which we do not override), so in practice
12
+ // it is always undefined (falsy) and the cache is always active unless
13
+ // a future override of the CLI handler flips it. Wired in as
14
+ // `argv.noCache` so the flag propagates to workers via
15
+ // WorkerSerializableBuildCtx.argv without any additional plumbing.
16
+ // * `BuildCtx.cacheDir?: string | null` — on-disk path for the parser
17
+ // result cache. `null` disables the cache for the run.
18
+ // `undefined` means "not yet set by the caller"; parseMarkdown in
19
+ // parse.ts defaults it to `<argv.directory>/.quartz/.cache/parser`
20
+ // so it matches `bin/brain-rebuild --clean-cache`'s rm target.
21
+ // Optional so existing BuildCtx constructors (upstream handlers.ts
22
+ // and test fixtures) compile without modification.
23
+ // `WorkerSerializableBuildCtx = Omit<BuildCtx, "cfg" | "trie">` so
24
+ // cacheDir auto-propagates to workers via the type — no worker.ts
25
+ // edit needed. The serializableCtx literal in parse.ts does list
26
+ // fields by hand and explicitly includes `cacheDir`.
27
+
28
+ import { QuartzConfig } from "../cfg"
29
+ import { QuartzPluginData } from "../plugins/vfile"
30
+ import { FileTrieNode } from "./fileTrie"
31
+ import { FilePath, FullSlug } from "./path"
32
+
33
+ export interface Argv {
34
+ directory: string
35
+ verbose: boolean
36
+ output: string
37
+ serve: boolean
38
+ watch: boolean
39
+ port: number
40
+ wsPort: number
41
+ remoteDevHost?: string
42
+ concurrency?: number
43
+ // brain: opt-out flag for the parser cache. When true, parseMarkdown
44
+ // sets cacheDir = null so no cache reads or writes occur for this run.
45
+ // Not currently wired from the upstream CLI handler (handlers.ts is not
46
+ // overridden); a future override can expose `--no-cache` via yargs and
47
+ // set this field. Until then it is always undefined = cache active.
48
+ noCache?: boolean
49
+ }
50
+
51
+ export type BuildTimeTrieData = QuartzPluginData & {
52
+ slug: string
53
+ title: string
54
+ filePath: string
55
+ }
56
+
57
+ export interface BuildCtx {
58
+ buildId: string
59
+ argv: Argv
60
+ cfg: QuartzConfig
61
+ allSlugs: FullSlug[]
62
+ allFiles: FilePath[]
63
+ trie?: FileTrieNode<BuildTimeTrieData>
64
+ incremental: boolean
65
+ // brain: on-disk directory for the parser result cache.
66
+ // string — active cache at this path
67
+ // null — cache explicitly disabled for this run (e.g. --no-cache)
68
+ // undefined — not yet set; parseMarkdown.ts defaults to
69
+ // <argv.directory>/.quartz/.cache/parser (matches
70
+ // brain.maintenance._PARSER_CACHE_RELPATH; wiped by
71
+ // `brain-rebuild --clean-cache`).
72
+ // Optional so existing BuildCtx constructors compile without change.
73
+ cacheDir?: string | null
74
+ }
75
+
76
+ export function trieFromAllFiles(allFiles: QuartzPluginData[]): FileTrieNode<BuildTimeTrieData> {
77
+ const trie = new FileTrieNode<BuildTimeTrieData>([])
78
+ allFiles.forEach((file) => {
79
+ if (file.frontmatter) {
80
+ trie.add({
81
+ ...file,
82
+ slug: file.slug!,
83
+ title: file.frontmatter.title,
84
+ filePath: file.filePath!,
85
+ })
86
+ }
87
+ })
88
+
89
+ return trie
90
+ }
91
+
92
+ export type WorkerSerializableBuildCtx = Omit<BuildCtx, "cfg" | "trie">