crbro-memory 2.10.0 → 2.11.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 (205) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +256 -465
  3. package/SECURITY.md +114 -12
  4. package/bin/crbro.mjs +539 -300
  5. package/dist/build-id.json +10 -0
  6. package/dist/cli/common.js +211 -0
  7. package/dist/cli/export.js +522 -0
  8. package/dist/cli/import.js +683 -0
  9. package/dist/cli/markdown.js +313 -0
  10. package/dist/cli/mcpclient.js +107 -0
  11. package/dist/cli/serve.js +453 -0
  12. package/dist/cli/view.js +358 -0
  13. package/dist/cli/viewer-page.js +378 -0
  14. package/dist/daemon/daemon.js +119 -11
  15. package/dist/daemon/endpoint.js +222 -21
  16. package/dist/daemon/lines.js +102 -13
  17. package/dist/daemon/proxy.js +480 -125
  18. package/dist/daemon/surface.js +116 -0
  19. package/dist/daemon/trace.js +73 -0
  20. package/dist/engine/atrest.js +132 -0
  21. package/dist/engine/backup.js +139 -19
  22. package/dist/engine/brain.js +22 -6
  23. package/dist/engine/codexconfig.js +476 -0
  24. package/dist/engine/cortex.js +667 -232
  25. package/dist/engine/doctor.js +312 -14
  26. package/dist/engine/heat.js +81 -37
  27. package/dist/engine/hippocampus.js +18 -7
  28. package/dist/engine/hookrefresh.js +296 -0
  29. package/dist/engine/hookverify.js +15 -3
  30. package/dist/engine/installer.js +1022 -0
  31. package/dist/engine/installio.js +279 -0
  32. package/dist/engine/keychain.js +721 -162
  33. package/dist/engine/maintenance.js +355 -87
  34. package/dist/engine/modinstall.js +98 -45
  35. package/dist/engine/prefrontal.js +29 -6
  36. package/dist/engine/quarantine.js +204 -0
  37. package/dist/engine/secrets.js +41 -5
  38. package/dist/engine/shelf.js +25 -3
  39. package/dist/engine/synapses.js +183 -80
  40. package/dist/engine/triggers.js +141 -11
  41. package/dist/index.js +37 -3
  42. package/dist/mcp-surface.json +1 -0
  43. package/dist/miner/extractor.js +64 -17
  44. package/dist/miner/scheduler.js +144 -68
  45. package/dist/search/index.js +797 -176
  46. package/dist/search/semantic.js +208 -18
  47. package/dist/search/tokenize.js +44 -0
  48. package/dist/server.js +583 -373
  49. package/dist/sync/git.js +203 -72
  50. package/dist/sync/space.js +100 -25
  51. package/dist/sync/validate.js +204 -0
  52. package/dist/utils/budget.js +15 -2
  53. package/dist/utils/fs.js +40 -6
  54. package/dist/utils/ids.js +128 -14
  55. package/dist/utils/lock.js +94 -7
  56. package/hooks/crbro-codex.mjs +284 -0
  57. package/hooks/crbro-guard.mjs +281 -173
  58. package/hooks/crbro-hooks.shipped.json +20 -0
  59. package/hooks/crbro-lifecycle.mjs +16 -4
  60. package/hooks/crbro-subagent.mjs +180 -180
  61. package/package.json +9 -5
  62. package/dist/daemon/daemon.d.ts +0 -25
  63. package/dist/daemon/daemon.d.ts.map +0 -1
  64. package/dist/daemon/daemon.js.map +0 -1
  65. package/dist/daemon/endpoint.d.ts +0 -66
  66. package/dist/daemon/endpoint.d.ts.map +0 -1
  67. package/dist/daemon/endpoint.js.map +0 -1
  68. package/dist/daemon/lines.d.ts +0 -55
  69. package/dist/daemon/lines.d.ts.map +0 -1
  70. package/dist/daemon/lines.js.map +0 -1
  71. package/dist/daemon/proxy.d.ts +0 -55
  72. package/dist/daemon/proxy.d.ts.map +0 -1
  73. package/dist/daemon/proxy.js.map +0 -1
  74. package/dist/engine/backup.d.ts +0 -68
  75. package/dist/engine/backup.d.ts.map +0 -1
  76. package/dist/engine/backup.js.map +0 -1
  77. package/dist/engine/brain.d.ts +0 -79
  78. package/dist/engine/brain.d.ts.map +0 -1
  79. package/dist/engine/brain.js.map +0 -1
  80. package/dist/engine/cortex.d.ts +0 -682
  81. package/dist/engine/cortex.d.ts.map +0 -1
  82. package/dist/engine/cortex.js.map +0 -1
  83. package/dist/engine/dates.d.ts +0 -28
  84. package/dist/engine/dates.d.ts.map +0 -1
  85. package/dist/engine/dates.js.map +0 -1
  86. package/dist/engine/doctor.d.ts +0 -93
  87. package/dist/engine/doctor.d.ts.map +0 -1
  88. package/dist/engine/doctor.js.map +0 -1
  89. package/dist/engine/evidence.d.ts +0 -26
  90. package/dist/engine/evidence.d.ts.map +0 -1
  91. package/dist/engine/evidence.js.map +0 -1
  92. package/dist/engine/heat.d.ts +0 -28
  93. package/dist/engine/heat.d.ts.map +0 -1
  94. package/dist/engine/heat.js.map +0 -1
  95. package/dist/engine/hippocampus.d.ts +0 -60
  96. package/dist/engine/hippocampus.d.ts.map +0 -1
  97. package/dist/engine/hippocampus.js.map +0 -1
  98. package/dist/engine/hookverify.d.ts +0 -42
  99. package/dist/engine/hookverify.d.ts.map +0 -1
  100. package/dist/engine/hookverify.js.map +0 -1
  101. package/dist/engine/keychain.d.ts +0 -32
  102. package/dist/engine/keychain.d.ts.map +0 -1
  103. package/dist/engine/keychain.js.map +0 -1
  104. package/dist/engine/maintenance.d.ts +0 -218
  105. package/dist/engine/maintenance.d.ts.map +0 -1
  106. package/dist/engine/maintenance.js.map +0 -1
  107. package/dist/engine/modinstall.d.ts +0 -215
  108. package/dist/engine/modinstall.d.ts.map +0 -1
  109. package/dist/engine/modinstall.js.map +0 -1
  110. package/dist/engine/postmortem.d.ts +0 -81
  111. package/dist/engine/postmortem.d.ts.map +0 -1
  112. package/dist/engine/postmortem.js.map +0 -1
  113. package/dist/engine/prefrontal.d.ts +0 -64
  114. package/dist/engine/prefrontal.d.ts.map +0 -1
  115. package/dist/engine/prefrontal.js.map +0 -1
  116. package/dist/engine/projects.d.ts +0 -20
  117. package/dist/engine/projects.d.ts.map +0 -1
  118. package/dist/engine/projects.js.map +0 -1
  119. package/dist/engine/secrets.d.ts +0 -30
  120. package/dist/engine/secrets.d.ts.map +0 -1
  121. package/dist/engine/secrets.js.map +0 -1
  122. package/dist/engine/shelf.d.ts +0 -155
  123. package/dist/engine/shelf.d.ts.map +0 -1
  124. package/dist/engine/shelf.js.map +0 -1
  125. package/dist/engine/source.d.ts +0 -6
  126. package/dist/engine/source.d.ts.map +0 -1
  127. package/dist/engine/source.js.map +0 -1
  128. package/dist/engine/synapses.d.ts +0 -82
  129. package/dist/engine/synapses.d.ts.map +0 -1
  130. package/dist/engine/synapses.js.map +0 -1
  131. package/dist/engine/triggers.d.ts +0 -53
  132. package/dist/engine/triggers.d.ts.map +0 -1
  133. package/dist/engine/triggers.js.map +0 -1
  134. package/dist/engine/usage.d.ts +0 -61
  135. package/dist/engine/usage.d.ts.map +0 -1
  136. package/dist/engine/usage.js.map +0 -1
  137. package/dist/index.d.ts +0 -2
  138. package/dist/index.d.ts.map +0 -1
  139. package/dist/index.js.map +0 -1
  140. package/dist/miner/extractor.d.ts +0 -12
  141. package/dist/miner/extractor.d.ts.map +0 -1
  142. package/dist/miner/extractor.js.map +0 -1
  143. package/dist/miner/index.d.ts +0 -61
  144. package/dist/miner/index.d.ts.map +0 -1
  145. package/dist/miner/index.js.map +0 -1
  146. package/dist/miner/scheduler.d.ts +0 -30
  147. package/dist/miner/scheduler.d.ts.map +0 -1
  148. package/dist/miner/scheduler.js.map +0 -1
  149. package/dist/miner/types.d.ts +0 -11
  150. package/dist/miner/types.d.ts.map +0 -1
  151. package/dist/miner/types.js.map +0 -1
  152. package/dist/search/index.d.ts +0 -328
  153. package/dist/search/index.d.ts.map +0 -1
  154. package/dist/search/index.js.map +0 -1
  155. package/dist/search/quality.d.ts +0 -18
  156. package/dist/search/quality.d.ts.map +0 -1
  157. package/dist/search/quality.js.map +0 -1
  158. package/dist/search/semantic.d.ts +0 -80
  159. package/dist/search/semantic.d.ts.map +0 -1
  160. package/dist/search/semantic.js.map +0 -1
  161. package/dist/search/synonyms.d.ts +0 -2
  162. package/dist/search/synonyms.d.ts.map +0 -1
  163. package/dist/search/synonyms.js.map +0 -1
  164. package/dist/search/tokenize.d.ts +0 -39
  165. package/dist/search/tokenize.d.ts.map +0 -1
  166. package/dist/search/tokenize.js.map +0 -1
  167. package/dist/server.d.ts +0 -41
  168. package/dist/server.d.ts.map +0 -1
  169. package/dist/server.js.map +0 -1
  170. package/dist/sync/git.d.ts +0 -36
  171. package/dist/sync/git.d.ts.map +0 -1
  172. package/dist/sync/git.js.map +0 -1
  173. package/dist/sync/materialize.d.ts +0 -36
  174. package/dist/sync/materialize.d.ts.map +0 -1
  175. package/dist/sync/materialize.js.map +0 -1
  176. package/dist/sync/ops.d.ts +0 -147
  177. package/dist/sync/ops.d.ts.map +0 -1
  178. package/dist/sync/ops.js.map +0 -1
  179. package/dist/sync/space.d.ts +0 -118
  180. package/dist/sync/space.d.ts.map +0 -1
  181. package/dist/sync/space.js.map +0 -1
  182. package/dist/types/index.d.ts +0 -369
  183. package/dist/types/index.d.ts.map +0 -1
  184. package/dist/types/index.js.map +0 -1
  185. package/dist/utils/budget.d.ts +0 -44
  186. package/dist/utils/budget.d.ts.map +0 -1
  187. package/dist/utils/budget.js.map +0 -1
  188. package/dist/utils/fs.d.ts +0 -59
  189. package/dist/utils/fs.d.ts.map +0 -1
  190. package/dist/utils/fs.js.map +0 -1
  191. package/dist/utils/hash.d.ts +0 -20
  192. package/dist/utils/hash.d.ts.map +0 -1
  193. package/dist/utils/hash.js.map +0 -1
  194. package/dist/utils/ids.d.ts +0 -47
  195. package/dist/utils/ids.d.ts.map +0 -1
  196. package/dist/utils/ids.js.map +0 -1
  197. package/dist/utils/lock.d.ts +0 -13
  198. package/dist/utils/lock.d.ts.map +0 -1
  199. package/dist/utils/lock.js.map +0 -1
  200. package/dist/utils/transcripts.d.ts +0 -63
  201. package/dist/utils/transcripts.d.ts.map +0 -1
  202. package/dist/utils/transcripts.js.map +0 -1
  203. package/dist/version.d.ts +0 -26
  204. package/dist/version.d.ts.map +0 -1
  205. package/dist/version.js.map +0 -1
package/SECURITY.md CHANGED
@@ -42,10 +42,20 @@ applies the same filter to everything it prints. Text is always redacted whole
42
42
  and cut to length afterwards: a cut first could leave half a token the filter
43
43
  no longer recognises.
44
44
 
45
+ Since 2.11 it also covers the decision rationale and the fact aliases
46
+ (`keywords`) of `crbro_learn`, and the notes of `crbro_revise`; `crbro_audit`
47
+ counts a credential found in any of them with its entry. A private key is
48
+ redacted whole — through its `END` line, or every base64 line after the
49
+ header when there is none — not just its header. Labels written without a
50
+ separator (`PASS value`, `la contraseña value (…`) are caught when the value
51
+ mixes character classes; plain prose after the same words is not.
52
+
45
53
  It is tuned for precision, not recall: it matches shapes that are credentials
46
54
  and essentially nothing else, because a false positive silently corrupts real
47
55
  knowledge. The consequence is that a credential in a shape it does not know
48
- passes. Treat it as a net, not as a guarantee.
56
+ passes. Treat it as a net, not as a guarantee. `npm run bench` measures it:
57
+ every synthetic value must be gone from the redacted text (not merely the text
58
+ changed), and the release gate allows no false positive on its innocent set.
49
59
 
50
60
  Sharing is stricter than storing: a neuron that contains a credential is
51
61
  **refused** for sharing, not redacted, because sending a teammate a mangled
@@ -68,9 +78,13 @@ it, and it goes back into a config file in plain text. `crbro_secret` and
68
78
  CRBRO invents no cryptography. The store lives outside the brain on purpose,
69
79
  so normal memory sync, share and backups do not include that store. Keep custom
70
80
  `CRBRO_KEYS_DIR` locations outside the brain, repositories and synced folders.
71
- Never add the encrypted store to Git or a release package. The value is read
72
- from stdin by the CLI, never from arguments, so it stays out of shell history
73
- and the process table.
81
+ Never add the encrypted store to Git or a release package. The CLI reads the
82
+ value from stdin, never from its arguments, so it stays out of shell history.
83
+ How it then reaches the store depends on the platform: on Windows and Linux it
84
+ goes to PowerShell and `secret-tool` through stdin; on **macOS** `security(1)`
85
+ has no stdin form, so the value (base64-encoded, which is not encryption) is
86
+ on that command's argument list for the few milliseconds the call lasts, where
87
+ another process of the same machine could read it with `ps`.
74
88
 
75
89
  What it does not do: protect against code running as your own user. DPAPI,
76
90
  the login keychain and the Secret Service all open for the logged-in account.
@@ -82,11 +96,59 @@ and uses it only to authenticate to the intended service; never print it for
82
96
  convenience. There is no promise that a secret used for authentication never
83
97
  leaves the computer.
84
98
 
85
- On Windows, 2.10 serializes read-modify-write operations across processes and
86
- checks ciphertext changes before serving cached values. Lock timeouts fail
87
- closed. A crashed short-lived `.lock.guard` is not automatically stolen; stop
88
- all writers and inspect it before manual recovery rather than deleting locks
89
- while another process might own them.
99
+ **The environment is not a keychain (2.11).** Until 2.10 `get` returned any
100
+ variable of the server's environment with the requested name — `USERNAME`,
101
+ `ANTHROPIC_API_KEY`, whatever the client was started with — before looking at
102
+ the store. Now an environment variable counts only when it opts in: a variable
103
+ named `CRBRO_SECRET_<NAME>`, or a plain `<NAME>` that `CRBRO_SECRET_ENV`
104
+ (a comma-separated list) names. That keeps CI and one-off overrides working.
105
+ The answer says `source: env` or `source: keychain`. Every action checks the
106
+ name (`SCREAMING_SNAKE_CASE`).
107
+
108
+ **Destructive writes ask first (2.11).** Through MCP, `set` on a name that
109
+ already holds a different value and `remove` change nothing on the first call:
110
+ they return a `confirm_token` to show the user, and only a second call with
111
+ that token writes. The token is an HMAC under a key that never leaves the
112
+ server process, bound to the name, the state of the store and (for `set`) the
113
+ new value, so a stale token, another value or a restarted server is refused.
114
+ The CLI asks for `--yes` on `remove` as before; a person typing at a terminal
115
+ is the confirmation for `set`.
116
+
117
+ **A missing store is not an empty one (2.11).** On Windows a plain marker
118
+ (`keys.dpapi.marker`, dates only) is written next to the store on every write,
119
+ and every successful write keeps a byte copy of the sealed file in
120
+ `sealed-copies/` (the last `CRBRO_KEYS_COPIES`, default 5; copies are never
121
+ opened except to validate a restore, and they open for the same Windows
122
+ account only). If `keys.dpapi` is missing while the marker, a sealed copy or a
123
+ leftover `*.tmp` says it existed, every operation fails with recovery steps
124
+ instead of answering "no credentials", and `set` refuses to create a new store
125
+ over it unless `--force` is given. `npx crbro-memory secret copies` lists the
126
+ copies and leftovers; `npx crbro-memory secret restore <id> --yes` validates
127
+ one with DPAPI, keeps the current store as a copy and puts it back. A removal
128
+ or an overwrite can therefore be undone until five more writes rotate the copy
129
+ out. Stale temporary files of this release are swept after an hour; the fixed
130
+ `keys.dpapi.tmp` of releases up to 2.9 is never touched, because it may be the
131
+ only copy left. macOS and Linux keep no copies: their stores are the
132
+ operating system's.
133
+
134
+ On macOS and Linux the names live in an index item of their own. Only "not
135
+ found" reads as an empty index; a locked keychain, a denied prompt or an
136
+ unreadable index is an error, and nothing is written. On Linux the index
137
+ replaced `secret-tool search --all`, which printed every value just to list
138
+ names (a store from 2.10 is migrated once, keeping names and descriptions).
139
+
140
+ On Windows, read-modify-write operations are serialized across processes and
141
+ ciphertext changes are checked before serving cached values; the decrypted
142
+ cache is dropped by a timer after 30 seconds. PowerShell is started from its
143
+ absolute System32 path, not looked up from the client's folder. The server
144
+ runs every keychain operation asynchronously, so a slow PowerShell start no
145
+ longer stalls the other conversations of a shared daemon; the store probe is
146
+ remembered for five minutes. Lock timeouts fail closed and say which process
147
+ holds the lock and for how long. Async lock holders refresh a heartbeat, so a
148
+ lock whose owner died is reclaimed even when Windows has reused its PID. A
149
+ crashed short-lived `.lock.guard` is not stolen while waiting; maintenance
150
+ removes one only when it is more than ten minutes old. Stop all writers before
151
+ deleting locks by hand.
90
152
 
91
153
  ### Project and evidence boundaries (2.10)
92
154
 
@@ -142,9 +204,10 @@ What it does not prove:
142
204
  teammate's or the miner's line cannot be rewritten as your own lesson
143
205
  through `promotion_candidates`.
144
206
 
145
- Provenance labels; it does not sanitise. Content arriving through a shared
146
- space is not filtered for secrets or for instructions on the way in. Treat any
147
- line with an `origin` as data, never as an order.
207
+ Provenance labels; it does not sanitise instructions. Since 2.11 content
208
+ arriving through a shared space passes through the secret filter and size and
209
+ shape checks on the way in (see below), but nothing filters what it tells the
210
+ model to do. Treat any line with an `origin` as data, never as an order.
148
211
 
149
212
  ### Team sync over git
150
213
 
@@ -157,6 +220,45 @@ a changed one afterwards. Incoming logs written by a newer, unknown format are
157
220
  skipped rather than half-understood, and an unreadable line is skipped without
158
221
  costing the rest.
159
222
 
223
+ What 2.11 checks, because each of these was accepted as it came:
224
+
225
+ - **Space names** are slugs (letters, digits, `-`, `_`; at most 64) and must
226
+ resolve to a folder directly inside `shared/`. A name like `..` used to make
227
+ `create` run `git add -A` and push the whole brain to the given remote.
228
+ - **Remotes** that start with `-`, contain control characters or carry
229
+ credentials (`https://user:password@…`, `https://token@…`) are refused before
230
+ git runs, so a credential never lands in `.git/config`; use SSH or a
231
+ credential helper. Branches follow git's ref-name rules, including the one
232
+ read from a cloned `space.json`. Positional arguments follow `--`, and git's
233
+ error output passes through the secret filter before it is shown.
234
+ - **No adoption.** A sync merges a folder of the space only into a neuron you
235
+ already share in that space, or into one this machine does not have. A
236
+ folder with the id of a private neuron of yours is left alone and reported
237
+ (`left_alone`): a teammate can no longer turn your neuron into a shared one,
238
+ which would have sent everything you learn about it to the team. Share it
239
+ with `crbro_share` to merge it.
240
+ - **Incoming notes** must name the neuron of their folder (a note that names
241
+ another one is dropped, so it cannot steer where a neuron is written); the
242
+ author label is cut to the charset and length of a local identity; ids,
243
+ kinds and confidences are checked; text is capped and redacted; logs over
244
+ 32 MB are skipped.
245
+ - **Sharing checks every field that travels**: rationales, aliases, revision
246
+ notes, the neuron's name, summary and tags, not only the entry texts. A
247
+ credential in any of them blocks the share.
248
+ - On Windows git is started from its absolute path on `PATH`, never looked up
249
+ in the space folder, whose content comes from teammates. The server runs git
250
+ asynchronously, so a slow push no longer stalls the shared daemon.
251
+
252
+ ### The miner's schedule
253
+
254
+ `setup-miner` and `remove-miner` run every command as an argument array,
255
+ never through a shell. The crontab is read with `crontab -l`, your own lines
256
+ are kept byte for byte, the previous crontab is saved next to the brain as
257
+ `crontab.before-crbro-*.txt`, and the new one is written through stdin.
258
+ Until 2.10 it went through `echo "…" | crontab -`, which expanded `$(…)` and
259
+ backticks in your existing cron lines. On Windows the task runs the absolute
260
+ `npx.cmd`, and the registered command is checked after creation.
261
+
160
262
  ### Hooks never block
161
263
 
162
264
  The guard (`PreToolUse`), the subagent hook (`SubagentStart`) and the