sealkeep 0.9.0 → 0.11.1

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 (274) hide show
  1. package/ARCHITECTURE.md +163 -14
  2. package/CHANGELOG.md +252 -1
  3. package/CONTROL_PLANE.md +2 -2
  4. package/LICENSE +1 -1
  5. package/README.md +108 -22
  6. package/THIRD_PARTY.md +2 -2
  7. package/THREAT_MODEL.md +23 -4
  8. package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/chunk-access.d.ts +26 -4
  9. package/dist/packages/sealkeep-crypto/src/chunk-access.js +219 -0
  10. package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/envelope.d.ts +11 -1
  11. package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/envelope.js +58 -21
  12. package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/format.d.ts +2 -2
  13. package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/index.d.ts +1 -0
  14. package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/index.js +1 -0
  15. package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/recipients.d.ts +1 -0
  16. package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/recipients.js +53 -13
  17. package/dist/packages/sealkeep-crypto/src/squeeze.d.ts +6 -0
  18. package/dist/packages/sealkeep-crypto/src/squeeze.js +39 -0
  19. package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/stream.d.ts +36 -3
  20. package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/stream.js +196 -37
  21. package/dist/site/index.html +1808 -1904
  22. package/dist/site/llms.txt +67 -0
  23. package/dist/site/trust/architecture-data-flow.html +53 -0
  24. package/dist/site/trust/audit-roadmap.html +37 -0
  25. package/dist/site/trust/deployment-responsibility.html +11 -0
  26. package/dist/site/trust/dpa-sample.html +30 -0
  27. package/dist/site/trust/release-provenance.html +21 -0
  28. package/dist/site/trust/subprocessors.html +15 -0
  29. package/dist/site/trust/threat-model.html +34 -0
  30. package/dist/site/trust/toms.html +41 -0
  31. package/dist/site/trust-document.css +32 -0
  32. package/dist/site/trust.html +73 -0
  33. package/dist/site/visual/assets/index-8Nxnkc7o.js +207 -0
  34. package/dist/site/visual/assets/index-oxLy1bpy.css +1 -0
  35. package/dist/site/visual/index.html +18 -0
  36. package/dist/site.zip +0 -0
  37. package/dist/src/activity.d.ts +9 -0
  38. package/dist/src/activity.js +90 -1
  39. package/dist/src/adapters.d.ts +175 -5
  40. package/dist/src/adapters.js +961 -73
  41. package/dist/src/agent-context.d.ts +135 -0
  42. package/dist/src/agent-context.js +1059 -0
  43. package/dist/src/archive-copies.d.ts +47 -0
  44. package/dist/src/archive-copies.js +179 -0
  45. package/dist/src/audit.d.ts +1 -1
  46. package/dist/src/audit.js +29 -4
  47. package/dist/src/autopilot.d.ts +52 -7
  48. package/dist/src/autopilot.js +143 -25
  49. package/dist/src/background-bandwidth.d.ts +46 -0
  50. package/dist/src/background-bandwidth.js +301 -0
  51. package/dist/src/background-cpu.d.ts +82 -0
  52. package/dist/src/background-cpu.js +212 -0
  53. package/dist/src/background-worker-error.d.ts +12 -0
  54. package/dist/src/background-worker-error.js +18 -0
  55. package/dist/src/branding.d.ts +24 -1
  56. package/dist/src/branding.js +31 -1
  57. package/dist/src/bridge.d.ts +233 -0
  58. package/dist/src/bridge.js +604 -0
  59. package/dist/src/byte-stream.d.ts +91 -0
  60. package/dist/src/byte-stream.js +385 -0
  61. package/dist/src/chunk-store.d.ts +41 -8
  62. package/dist/src/chunk-store.js +161 -65
  63. package/dist/src/cli.js +1698 -163
  64. package/dist/src/cloud.d.ts +841 -31
  65. package/dist/src/cloud.js +3196 -277
  66. package/dist/src/context-background.d.ts +37 -0
  67. package/dist/src/context-background.js +309 -0
  68. package/dist/src/context-drain-child.d.ts +1 -0
  69. package/dist/src/context-drain-child.js +98 -0
  70. package/dist/src/context-reader.d.ts +118 -0
  71. package/dist/src/context-reader.js +447 -0
  72. package/dist/src/control-plane/auth.d.ts +32 -4
  73. package/dist/src/control-plane/auth.js +85 -24
  74. package/dist/src/control-plane/server.js +19 -6
  75. package/dist/src/control-plane.d.ts +17 -1
  76. package/dist/src/control-plane.js +32 -6
  77. package/dist/src/crypto.d.ts +1 -1
  78. package/dist/src/crypto.js +5 -5
  79. package/dist/src/daemon-lease.d.ts +70 -0
  80. package/dist/src/daemon-lease.js +420 -0
  81. package/dist/src/daemon.d.ts +94 -1
  82. package/dist/src/daemon.js +1082 -105
  83. package/dist/src/darwin-service-policy.d.ts +41 -0
  84. package/dist/src/darwin-service-policy.js +60 -0
  85. package/dist/src/dashboard-cli.js +15 -15
  86. package/dist/src/device-authorization.d.ts +37 -0
  87. package/dist/src/device-authorization.js +199 -0
  88. package/dist/src/device-enrollment.d.ts +91 -0
  89. package/dist/src/device-enrollment.js +349 -0
  90. package/dist/src/disk.d.ts +17 -12
  91. package/dist/src/disk.js +43 -17
  92. package/dist/src/doctor.d.ts +35 -1
  93. package/dist/src/doctor.js +332 -41
  94. package/dist/src/durable-ticket-lock.d.ts +24 -0
  95. package/dist/src/durable-ticket-lock.js +232 -0
  96. package/dist/src/enroll.d.ts +1 -1
  97. package/dist/src/enroll.js +13 -7
  98. package/dist/src/env.d.ts +10 -1
  99. package/dist/src/env.js +11 -3
  100. package/dist/src/errors.d.ts +8 -8
  101. package/dist/src/errors.js +6 -6
  102. package/dist/src/flush.d.ts +12 -0
  103. package/dist/src/flush.js +37 -0
  104. package/dist/src/heartbeat.d.ts +86 -12
  105. package/dist/src/heartbeat.js +415 -29
  106. package/dist/src/index-background-watchdog.d.ts +1 -0
  107. package/dist/src/index-background-watchdog.js +94 -0
  108. package/dist/src/index-background-work.d.ts +21 -0
  109. package/dist/src/index-background-work.js +25 -0
  110. package/dist/src/index-background.d.ts +64 -0
  111. package/dist/src/index-background.js +394 -0
  112. package/dist/src/index-build-child.d.ts +1 -0
  113. package/dist/src/index-build-child.js +109 -0
  114. package/dist/src/index-manifest.d.ts +52 -0
  115. package/dist/src/index-manifest.js +444 -0
  116. package/dist/src/index-publication-proof.d.ts +84 -0
  117. package/dist/src/index-publication-proof.js +380 -0
  118. package/dist/src/index-publication-state.d.ts +149 -0
  119. package/dist/src/index-publication-state.js +696 -0
  120. package/dist/src/index-publication-verifier.d.ts +89 -0
  121. package/dist/src/index-publication-verifier.js +341 -0
  122. package/dist/src/index-publish.d.ts +62 -0
  123. package/dist/src/index-publish.js +540 -0
  124. package/dist/src/index-scratch-cleanup.d.ts +19 -0
  125. package/dist/src/index-scratch-cleanup.js +166 -0
  126. package/dist/src/index-segment-types.d.ts +132 -0
  127. package/dist/src/index-segment-types.js +21 -0
  128. package/dist/src/index-segments.d.ts +9 -0
  129. package/dist/src/index-segments.js +516 -0
  130. package/dist/src/index-store.d.ts +123 -0
  131. package/dist/src/index-store.js +495 -0
  132. package/dist/src/index-sync.d.ts +91 -15
  133. package/dist/src/index-sync.js +286 -53
  134. package/dist/src/index-upgrade-publication.d.ts +30 -0
  135. package/dist/src/index-upgrade-publication.js +179 -0
  136. package/dist/src/integration-manager.d.ts +32 -0
  137. package/dist/src/integration-manager.js +394 -0
  138. package/dist/src/leakscan.js +1 -1
  139. package/dist/src/local-api.d.ts +56 -15
  140. package/dist/src/local-api.js +4979 -541
  141. package/dist/src/machine-settings.d.ts +51 -0
  142. package/dist/src/machine-settings.js +166 -0
  143. package/dist/src/managed-chunks.d.ts +5 -2
  144. package/dist/src/managed-chunks.js +14 -14
  145. package/dist/src/mcp-install.d.ts +11 -9
  146. package/dist/src/mcp-install.js +73 -28
  147. package/dist/src/mcp-workspace.d.ts +18 -0
  148. package/dist/src/mcp-workspace.js +50 -0
  149. package/dist/src/mcp.js +294 -25
  150. package/dist/src/migrate.js +27 -21
  151. package/dist/src/notify.d.ts +1 -1
  152. package/dist/src/notify.js +5 -5
  153. package/dist/src/offload.d.ts +201 -14
  154. package/dist/src/offload.js +1848 -140
  155. package/dist/src/onboarding.d.ts +8 -1
  156. package/dist/src/onboarding.js +4 -4
  157. package/dist/src/packages.d.ts +2 -2
  158. package/dist/src/packages.js +10 -2
  159. package/dist/src/passkey.d.ts +0 -1
  160. package/dist/src/passkey.js +2 -7
  161. package/dist/src/password-lock.d.ts +2 -2
  162. package/dist/src/password-lock.js +6 -6
  163. package/dist/src/paths.d.ts +2 -0
  164. package/dist/src/paths.js +2 -0
  165. package/dist/src/presence.d.ts +86 -0
  166. package/dist/src/presence.js +240 -0
  167. package/dist/src/progress-deadline.d.ts +21 -0
  168. package/dist/src/progress-deadline.js +91 -0
  169. package/dist/src/project-repair.d.ts +55 -0
  170. package/dist/src/project-repair.js +131 -0
  171. package/dist/src/providers/gcs.d.ts +28 -7
  172. package/dist/src/providers/gcs.js +35 -24
  173. package/dist/src/providers/gdrive.d.ts +71 -8
  174. package/dist/src/providers/gdrive.js +223 -50
  175. package/dist/src/providers/index.d.ts +11 -3
  176. package/dist/src/providers/index.js +30 -10
  177. package/dist/src/providers/s3.d.ts +30 -8
  178. package/dist/src/providers/s3.js +41 -30
  179. package/dist/src/providers/safe-storage-fetch.d.ts +12 -0
  180. package/dist/src/providers/safe-storage-fetch.js +72 -0
  181. package/dist/src/queue.d.ts +136 -19
  182. package/dist/src/queue.js +862 -96
  183. package/dist/src/reclaim-transaction.d.ts +156 -0
  184. package/dist/src/reclaim-transaction.js +1027 -0
  185. package/dist/src/recovery-codes.d.ts +32 -0
  186. package/dist/src/recovery-codes.js +338 -0
  187. package/dist/src/recovery.js +12 -9
  188. package/dist/src/rehydrate.d.ts +25 -22
  189. package/dist/src/rehydrate.js +319 -23
  190. package/dist/src/restore.d.ts +57 -4
  191. package/dist/src/restore.js +272 -36
  192. package/dist/src/resume-stub.d.ts +92 -0
  193. package/dist/src/resume-stub.js +417 -0
  194. package/dist/src/retention.d.ts +98 -7
  195. package/dist/src/retention.js +1066 -62
  196. package/dist/src/rotate.js +3 -3
  197. package/dist/src/search.d.ts +566 -8
  198. package/dist/src/search.js +5940 -297
  199. package/dist/src/secrets.d.ts +51 -7
  200. package/dist/src/secrets.js +316 -24
  201. package/dist/src/service.d.ts +49 -11
  202. package/dist/src/service.js +776 -35
  203. package/dist/src/share.js +3 -3
  204. package/dist/src/shared-spaces.d.ts +98 -0
  205. package/dist/src/shared-spaces.js +214 -0
  206. package/dist/src/source-reader.d.ts +73 -0
  207. package/dist/src/source-reader.js +715 -0
  208. package/dist/src/spool.d.ts +1 -1
  209. package/dist/src/spool.js +1 -1
  210. package/dist/src/start-tui.js +2 -1
  211. package/dist/src/start.js +2 -2
  212. package/dist/src/storage-endpoint.d.ts +21 -0
  213. package/dist/src/storage-endpoint.js +122 -0
  214. package/dist/src/storage-setup.js +12 -12
  215. package/dist/src/storage-targets.d.ts +109 -6
  216. package/dist/src/storage-targets.js +975 -67
  217. package/dist/src/stream-to-cloud.d.ts +5 -1
  218. package/dist/src/stream-to-cloud.js +34 -14
  219. package/dist/src/sync-rules.d.ts +31 -6
  220. package/dist/src/sync-rules.js +153 -14
  221. package/dist/src/team-backfill-scheduling.d.ts +8 -0
  222. package/dist/src/team-backfill-scheduling.js +33 -0
  223. package/dist/src/team-backfill.d.ts +116 -0
  224. package/dist/src/team-backfill.js +1429 -0
  225. package/dist/src/team-index-cache.d.ts +16 -0
  226. package/dist/src/team-index-cache.js +152 -0
  227. package/dist/src/team-offboarding.d.ts +38 -0
  228. package/dist/src/team-offboarding.js +1043 -0
  229. package/dist/src/team-presence.d.ts +127 -0
  230. package/dist/src/team-presence.js +904 -0
  231. package/dist/src/team-publication-policy.d.ts +20 -0
  232. package/dist/src/team-publication-policy.js +140 -0
  233. package/dist/src/team-realtime.d.ts +68 -0
  234. package/dist/src/team-realtime.js +816 -0
  235. package/dist/src/team-source-facts-cache.d.ts +23 -0
  236. package/dist/src/team-source-facts-cache.js +255 -0
  237. package/dist/src/trash.d.ts +1 -1
  238. package/dist/src/trash.js +2 -2
  239. package/dist/src/tui.js +11 -12
  240. package/dist/src/types.d.ts +173 -7
  241. package/dist/src/types.js +20 -0
  242. package/dist/src/ui-server.d.ts +163 -35
  243. package/dist/src/ui-server.js +712 -72
  244. package/dist/src/ui.d.ts +1 -2
  245. package/dist/src/ui.js +1 -2
  246. package/dist/src/upload.d.ts +27 -0
  247. package/dist/src/upload.js +383 -43
  248. package/dist/src/vault.d.ts +226 -30
  249. package/dist/src/vault.js +1776 -192
  250. package/dist/src/watcher.d.ts +7 -1
  251. package/dist/src/watcher.js +198 -55
  252. package/dist/src/worker.d.ts +27 -3
  253. package/dist/src/worker.js +274 -55
  254. package/package.json +33 -12
  255. package/scripts/native-reboot-rehearsal.mjs +90 -0
  256. package/web/app.js +6032 -343
  257. package/web/bootstrap.js +17 -0
  258. package/web/index.html +255 -57
  259. package/web/rail.js +317 -40
  260. package/web/retention.html +2 -2
  261. package/web/rules-view.js +188 -16
  262. package/web/sessions-view.js +485 -62
  263. package/web/sessions.html +2 -2
  264. package/web/setup-api.js +152 -29
  265. package/web/setup-logic.js +68 -9
  266. package/web/setup.html +113 -44
  267. package/web/setup.js +604 -71
  268. package/web/style.css +513 -98
  269. package/dist/packages/vaultline-crypto/src/chunk-access.js +0 -93
  270. /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/aead.d.ts +0 -0
  271. /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/aead.js +0 -0
  272. /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/format.js +0 -0
  273. /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/sha256-stream.d.ts +0 -0
  274. /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/sha256-stream.js +0 -0
@@ -1,3 +1,10 @@
1
+ import { x25519PrivateKeyFromRaw, type Envelope } from "../packages/sealkeep-crypto/src/index.js";
2
+ import type { ArchiveRecord } from "./types.js";
3
+ import type { FetchClient } from "./offload.js";
4
+ import { type IndexPublicationCoverage } from "./index-publication-proof.js";
5
+ import type { ManagedIndexReceipt, RemoteIndexStore } from "./index-sync.js";
6
+ import { type SourceReference } from "./source-reader.js";
7
+ export { backgroundCpuDelayMs } from "./background-cpu.js";
1
8
  export type SearchMode = "metadata" | "content";
2
9
  type HitBase = {
3
10
  id: string;
@@ -5,6 +12,7 @@ type HitBase = {
5
12
  path: string;
6
13
  bytes: number;
7
14
  createdAt: string;
15
+ project?: string | null;
8
16
  };
9
17
  export type MetadataHit = HitBase & {
10
18
  matched: "metadata";
@@ -12,6 +20,13 @@ export type MetadataHit = HitBase & {
12
20
  export type ContentHit = HitBase & {
13
21
  matched: "content";
14
22
  snippets: string[];
23
+ meta?: ArchiveMeta;
24
+ source?: SourceReference;
25
+ context?: {
26
+ source: SourceReference;
27
+ query: string;
28
+ chunkIndex?: number;
29
+ };
15
30
  };
16
31
  export type SearchHit = MetadataHit | ContentHit;
17
32
  /**
@@ -27,12 +42,137 @@ export type SearchHit = MetadataHit | ContentHit;
27
42
  * storage into a ranged fetch of a few chunks instead of a full restore.
28
43
  * Bare ids (v1, or legacy archives) still mean "somewhere in the archive".
29
44
  */
45
+ /** What the index remembers ABOUT a session, beyond its words: when it ran,
46
+ * where it ran, which git commits landed inside that window, which files it
47
+ * touched. This is the layer git itself lacks — the index becomes the join
48
+ * table between commits (the what) and sessions (the why). */
49
+ export type ArchiveMeta = {
50
+ startedAt?: string;
51
+ endedAt?: string;
52
+ /** Public archive creation time, retained as a total-order fallback when a
53
+ * transcript has no parseable session timestamps. */
54
+ archivedAt?: string;
55
+ cwd?: string;
56
+ commits?: Array<{
57
+ h: string;
58
+ s: string;
59
+ }>;
60
+ files?: string[];
61
+ /** Last concise agent-facing line, captured while the source still exists. */
62
+ summary?: string;
63
+ /**
64
+ * The non-secret record facts a fresh machine needs to move an already-sealed
65
+ * object without decrypting its transcript. This lives inside the encrypted
66
+ * index, alongside path/project metadata, and deliberately excludes wrapped
67
+ * keys and provider credentials. In particular, the delta pointer is kept:
68
+ * copying a delta head without its bases would create a destination that
69
+ * cannot restore the session.
70
+ */
71
+ archiveRecord?: ArchiveCatalogFacts;
72
+ };
30
73
  export type ContentIndex = {
31
74
  version: 1 | 2;
75
+ extractionPolicy?: number;
32
76
  builtAt: string;
33
77
  archives: Record<string, string[]>;
34
78
  tokens: Record<string, string[]>;
79
+ meta?: Record<string, ArchiveMeta>;
80
+ };
81
+ export type ArchiveCatalogFacts = {
82
+ v: 1;
83
+ /** Authenticated sealed identity when the managed locator is an alias. */
84
+ envelopeArchiveId?: string;
85
+ /** Commits the entire envelope, including the raw-to-stored range map. */
86
+ envelopeSha256?: string;
87
+ /** Explicit authenticated owner-custody provenance; an alias alone grants none. */
88
+ teamCustody?: true;
89
+ createdAt: string;
90
+ sourceBytes: number;
91
+ sourceSha256: string;
92
+ storedBytes: number;
93
+ ciphertextSha256: string;
94
+ algorithm: string;
95
+ chunks: number;
96
+ delta?: {
97
+ baseArchiveId: string;
98
+ baseBytes: number;
99
+ };
100
+ supersedes?: {
101
+ archiveId: string;
102
+ bytes: number;
103
+ };
104
+ };
105
+ /** Facts suitable for the encrypted cross-machine catalog, never plaintext. */
106
+ export declare function archiveCatalogFacts(record: ArchiveRecord): ArchiveCatalogFacts | null;
107
+ /** Bump when transcript-derived text must be re-extracted, not merely merged. */
108
+ export declare const INDEX_EXTRACTION_POLICY = 3;
109
+ /**
110
+ * Remove only abandoned files from SealKeep's atomic index publications.
111
+ *
112
+ * Age alone is not enough for the sealed OWNED_INDEX_TEMP names below: a
113
+ * large live checkpoint can legitimately spend a long time writing, so a
114
+ * candidate must also be older than the corresponding committed generation.
115
+ * Keeping a full day of additional distance makes this safe across
116
+ * concurrent/manual builders and coarse filesystem timestamps. Unknown
117
+ * names, directories, and temps without a committed successor stay.
118
+ *
119
+ * The plaintext staging files (never sealed, so there is no "committed"
120
+ * counterpart to compare against) use a simpler, shorter age-only rule —
121
+ * see PLAINTEXT_STAGING_JSONL and SEGMENT_STAGING_*.
122
+ */
123
+ export declare function cleanupStaleContentIndexTemps(dataDir: string): Promise<number>;
124
+ export declare function writeArchiveTokenSidecar(dataDir: string, rawPhrase: string, archiveId: string, tokensByChunk: ReadonlyMap<number, ReadonlySet<string>>): Promise<string>;
125
+ /** The archive's preserved seal-time tokens, or null when there is no usable sidecar. */
126
+ export declare function readArchiveTokenSidecar(dataDir: string, rawPhrase: string, archiveId: string): Promise<Map<number, Set<string>> | null>;
127
+ /**
128
+ * Registers one archive's chunk-tagged tokens in an in-memory index, replacing
129
+ * any previous entries for that id and applying the build's caps: bounded
130
+ * tokens per archive, two chunk tags per token. Shared by the seal-time merge
131
+ * and the catch-up's sidecar path so both produce the same entry.
132
+ */
133
+ type IndexableRecordFacts = {
134
+ id: string;
135
+ version?: number;
136
+ createdAt?: string;
137
+ source: {
138
+ agent: string;
139
+ path: string;
140
+ bytes: number;
141
+ sha256?: string;
142
+ project?: string | null;
143
+ projectKey?: string | null;
144
+ projectScope?: string | null;
145
+ };
146
+ cipher?: {
147
+ algorithm: unknown;
148
+ ciphertextSha256: string;
149
+ storedBytes: number;
150
+ chunks?: number;
151
+ };
152
+ delta?: {
153
+ baseArchiveId: string;
154
+ baseBytes: number;
155
+ };
156
+ supersedes?: {
157
+ archiveId: string;
158
+ bytes: number;
159
+ };
35
160
  };
161
+ export declare function applyArchiveTokens(index: ContentIndex, sealed: ArchiveRecord | IndexableRecordFacts, tokensByChunk: ReadonlyMap<number, ReadonlySet<string>>): void;
162
+ /**
163
+ * Removes every project shard, without needing to know which projects exist.
164
+ *
165
+ * Called when the recipient list changes. A shard is sealed to the members a
166
+ * project had when it was written, so ANY change to that list makes every
167
+ * shard potentially stale — and the documented revocation path
168
+ * (`recipients remove` then `rewrap`) rebuilds neither. Leaving them was the
169
+ * whole defect: a revoked key kept opening a file no code ever revisited.
170
+ * Shards are derived data; the next `index build` writes them again.
171
+ */
172
+ export declare function invalidateScopedShards(dataDir: string): Promise<void>;
173
+ /** Cheap unsealed migration check; archive ids are already local metadata. */
174
+ export declare function indexPublicationPending(dataDir: string): Promise<boolean>;
175
+ export declare function contentIndexNeedsPolicyUpgrade(dataDir: string): Promise<boolean>;
36
176
  /**
37
177
  * What deserves an index slot. Transcripts are full of hex digests, base64
38
178
  * blobs, and minified identifiers; every one of those admitted is a real word
@@ -40,6 +180,20 @@ export type ContentIndex = {
40
180
  * long id simply misses content and falls to metadata search, which owns ids.
41
181
  */
42
182
  export declare function indexableToken(token: string): boolean;
183
+ /**
184
+ * True only for raw historical context SealKeep itself injected or returned.
185
+ * The user's query and the agent's later reasoning remain new knowledge; the
186
+ * retrieved payload does not get indexed a second time as a new session.
187
+ */
188
+ export declare function isRecalledMemoryLine(line: string): boolean;
189
+ /** Keeps JSONL boundaries intact across archive/chunk windows. */
190
+ export declare class RecalledMemoryFilter {
191
+ private carry;
192
+ private static readonly MAX_CARRY_CHARS;
193
+ private static readonly TAIL_CHARS;
194
+ push(text: string, final?: boolean): string;
195
+ finish(): string;
196
+ }
43
197
  /**
44
198
  * Round-robin merge of per-chunk token sets: every chunk gets a fair slice of
45
199
  * the archive's token budget. First-chunks-win was the live finding — with a
@@ -53,6 +207,22 @@ export declare function mergeChunkTokens(byChunk: ReadonlyMap<number, ReadonlySe
53
207
  * starves everything past the first chunk of a big archive ("retention"
54
208
  * indexed, "chunk" lost). Bounded so the phonebook stays a phonebook.
55
209
  */
210
+ /**
211
+ * Collects a seal's index tokens as its plaintext streams past, one set per
212
+ * sealed chunk (a posting `<id>@c<n>` later quotes by ranged-reading that
213
+ * chunk alone), so the archive is searchable the moment the seal returns and
214
+ * nobody decrypts it again to index it. Filtered and budgeted at collection:
215
+ * junk (hex digests, base64 runs) never takes a slot, the budget scales with
216
+ * the archive — a flat 4000 starved everything past chunk zero of a 1.7 GB
217
+ * seal — and memory Sealkeep itself injected on an earlier turn is not
218
+ * indexed as if the person had said it. Windowed inside a chunk: a chunk is
219
+ * up to 64 MB, and tokenising that much in one call is what took the index
220
+ * build to the 4 GB heap limit. Shared by the cloud seal and the local one.
221
+ */
222
+ export declare function createSealTokenCollector(totalBytes: number): {
223
+ onPlaintext: (chunkIndex: number, slice: Buffer) => void;
224
+ finish: (totalChunks: number) => Map<number, Set<string>>;
225
+ };
56
226
  export declare function tokenCapFor(sourceBytes: number): number;
57
227
  /** Own-property-safe read: inherited names ("constructor", "toString") answer as absent. */
58
228
  export declare function tokenEntries(tokens: Record<string, string[]>, token: string): string[];
@@ -63,9 +233,13 @@ export declare function tokenEntries(tokens: Record<string, string[]>, token: st
63
233
  */
64
234
  export declare function tokenEntriesExpanded(tokens: Record<string, string[]>, term: string): string[];
65
235
  export declare function tokenize(text: string): string[];
236
+ /** Terms search actually requires. Quoting opts out of conversational cleanup. */
237
+ export declare function contentQueryTerms(query: string): string[];
66
238
  /** Metadata search needs no secret and never touches an archive's contents. */
67
239
  export declare function searchMetadata(dataDir: string, query: string, options?: {
68
240
  agent?: string;
241
+ archiveId?: string;
242
+ sessionId?: string;
69
243
  }): Promise<MetadataHit[]>;
70
244
  /**
71
245
  * Builds the opt-in content index.
@@ -76,6 +250,57 @@ export declare function searchMetadata(dataDir: string, query: string, options?:
76
250
  */
77
251
  export declare function buildContentIndex(dataDir: string, rawPhrase: string, options?: {
78
252
  sync?: boolean;
253
+ /** Cancellation belongs to the historical child that owns this build.
254
+ * It is propagated into remote scratch writes so a graceful stop removes
255
+ * its partial rather than abandoning archive-sized temporary data. */
256
+ signal?: AbortSignal;
257
+ /** Genuine archive/index work, used by the owning child process to reset
258
+ * its idle deadline. This is intentionally not a timer heartbeat. */
259
+ onActivity?: () => void;
260
+ onProgress?: (done: number, total: number, id: string) => void;
261
+ /** Dependency seam for provider/concurrency rehearsals; normal callers let
262
+ * Sealkeep resolve the configured remote store. */
263
+ /** Widened to the full `RemoteIndexStore` (rather than just meta/pull/push)
264
+ * so this same seam can carry a segments-capable store for segments-mode
265
+ * rehearsals; normal callers still let Sealkeep resolve it. */
266
+ remoteStore?: RemoteIndexStore | null;
267
+ /** Archive provider seam. Production resolves each record's stored copy;
268
+ * deterministic tests can supply the same bounded streaming contract. */
269
+ archiveClient?: FetchClient;
270
+ /** Scheduling seam used by the background builder and deterministic
271
+ * rehearsals. It does not add writers: lanes share one in-memory index and
272
+ * every checkpoint still passes through the same serialized promise. */
273
+ scheduling?: {
274
+ lanes?: number;
275
+ /** Fraction of one CPU core historical work may consume over time.
276
+ * Foreground/manual builds omit this; the daemon child uses 0.30. */
277
+ cpuTarget?: number;
278
+ cpuUsage?: typeof process.cpuUsage;
279
+ sleep?: (ms: number) => Promise<void>;
280
+ /** Current RSS guard for derived background work. */
281
+ maxRssBytes?: number;
282
+ rssBytes?: () => number;
283
+ /** Durable daemon-child generation whose private directory owns every
284
+ * derived index scratch file. Foreground builds omit it. */
285
+ scratchGeneration?: string;
286
+ checkpointEvery?: number;
287
+ checkpointAfterMs?: number;
288
+ checkpointLargeArchiveBytes?: number;
289
+ /** How long a compatibility archive may wait for the shared temporary
290
+ * workspace. Current chunk archives do not use that workspace at all. */
291
+ scratchWaitMs?: number;
292
+ /** Maximum time a remote index operation may make no observable progress. */
293
+ remoteIdleMs?: number;
294
+ /** Explicit background network ceiling. Foreground search omits it. */
295
+ backgroundTransferBytesPerSecond?: number;
296
+ now?: () => number;
297
+ /** Segments mode only, blob-fallback publish: publishFromSegments's
298
+ * guard against producing a cloud blob too large to hold in this
299
+ * build's memory. The background daemon child sets this; a foreground
300
+ * build omits it and always publishes. Unused when the store supports
301
+ * `segments` directly (publishSegments streams instead of merging). */
302
+ publishMaxTokens?: number;
303
+ };
79
304
  }): Promise<{
80
305
  archives: number;
81
306
  tokens: number;
@@ -85,6 +310,97 @@ export declare function buildContentIndex(dataDir: string, rawPhrase: string, op
85
310
  pulled: boolean;
86
311
  pushed: boolean;
87
312
  }>;
313
+ /** Pure lookup for `sealkeep why <commit>`: which sessions carry this commit. */
314
+ export declare function sessionsForCommit(index: ContentIndex, commitish: string): Array<{
315
+ id: string;
316
+ meta: ArchiveMeta;
317
+ subject: string;
318
+ }>;
319
+ /**
320
+ * Reads an index from bytes without ever holding it as ONE string.
321
+ *
322
+ * The write side learned this lesson first (see serializeIndex below), and the
323
+ * read side then hit the identical wall: a fully built 1,035-archive index
324
+ * decrypts to ~692 MB of JSON, and `.toString("utf8")` on that throws at V8's
325
+ * ~512 MB string ceiling — so the finished index sealed fine and could not be
326
+ * OPENED. Two formats live here:
327
+ *
328
+ * - version 3 (what serializeIndex writes now): one small JSON document per
329
+ * line — a meta line, then one line per archive, one per token. Parsing is
330
+ * a linear walk splitting on newlines; no line is ever large.
331
+ * - version 2 (what an existing vault may hold): one giant document. It is
332
+ * walked byte-wise — strings tracked through their escapes, arrays through
333
+ * their brackets — and each `"key":value` entry is parsed on its own.
334
+ */
335
+ export declare function parseIndexBuffer(buffer: Buffer): ContentIndex;
336
+ /**
337
+ * Posting lists are a result of concurrent work, not a clock. Give every
338
+ * dated archive an explicit chronological key and use input position only as
339
+ * the stable fallback for legacy entries with no metadata. Unknown entries
340
+ * sort before dated ones so a legacy posting cannot displace a known-current
341
+ * session from the newest-retention window.
342
+ */
343
+ export declare function chronologicalPostings(entries: readonly string[], meta: Readonly<Record<string, ArchiveMeta>>): string[];
344
+ /**
345
+ * Writes a checkpoint's plaintext JSONL without allocating a vault-sized
346
+ * Buffer. The allowed-id snapshot keeps coverage and ciphertext consistent
347
+ * even when a foreground build has several lanes finishing concurrently.
348
+ */
349
+ export declare function writeContentIndexCheckpoint(path: string, index: ContentIndex, signal?: AbortSignal, onYield?: () => void | Promise<void>): Promise<ContentIndexCheckpoint["coverage"]>;
350
+ export type ContentIndexCheckpoint = {
351
+ serialized: Buffer;
352
+ coverage: {
353
+ extractionPolicy: number;
354
+ builtAt: string;
355
+ indexed: string[];
356
+ publication: IndexPublicationCoverage;
357
+ effectivePostingCounts: Record<string, number>;
358
+ /** Where a lookup finds a token without reading the whole file; absent for in-memory snapshots. */
359
+ directory?: IndexDirectoryDraft;
360
+ };
361
+ };
362
+ /**
363
+ * Captures the sealed index bytes and their unsealed coverage description in
364
+ * one synchronous event-loop turn.
365
+ *
366
+ * Index builds use several lanes. A lane can finish another archive while a
367
+ * checkpoint is awaiting its temporary-file write. Reading `index` again
368
+ * after that await made coverage claim the newer archive was searchable even
369
+ * though the ciphertext had been serialized before it arrived. Keeping both
370
+ * products in this immutable checkpoint makes status describe exactly the
371
+ * bytes that were written, while the next checkpoint naturally includes any
372
+ * later archive.
373
+ */
374
+ export declare function snapshotContentIndexCheckpoint(index: ContentIndex): ContentIndexCheckpoint;
375
+ export declare function openVerifiedManagedIndex(envelope: Envelope, ciphertext: Buffer, opener: {
376
+ phrase: string;
377
+ } | {
378
+ privateKey: ReturnType<typeof x25519PrivateKeyFromRaw>;
379
+ }, advertisedCoverage: Readonly<Record<string, string>>): ContentIndex;
380
+ /**
381
+ * Exported for the segmented index's blob fallback (src/index-publish.ts): a
382
+ * managed plane publishes through its CAS generation lane, so the legacy
383
+ * `meta`/`blob` objects it also exposes can be weeks stale. Anything asking
384
+ * "is there a newer account index?" must ask through here, or it reads an
385
+ * August envelope and concludes there is nothing to learn.
386
+ */
387
+ export declare function pullRemoteIndexIfNewerVerified(dataDir: string, phrase: string, store: RemoteIndexStore, localBuiltAt: string | null, save: (envelope: Envelope, ciphertext: Buffer) => Promise<void>, options?: QueryIndexWorkOptions, reuseVerifiedAccountGeneration?: boolean): Promise<{
388
+ pulled: boolean;
389
+ remoteBuiltAt: string | null;
390
+ }>;
391
+ /**
392
+ * Seals the index to disk atomically and pushes it to the vault's remote slot
393
+ * when one is reachable. Sealed local, so sealed remote: pushing costs two
394
+ * PUTs of ciphertext and buys every other machine of this vault a search that
395
+ * needs no rebuild. A token index is highly repetitive JSON and compresses hard.
396
+ */
397
+ export declare function persistContentIndex(dataDir: string, phrase: string, index: ContentIndex, store: RemoteIndexStore | null, options?: {
398
+ signal?: AbortSignal;
399
+ remoteIdleMs?: number;
400
+ maxBytesPerSecond?: number;
401
+ onYield?: () => void | Promise<void>;
402
+ scratchGeneration?: string;
403
+ }): Promise<boolean>;
88
404
  /**
89
405
  * Seal-time indexing: the seal already held every plaintext slice in its
90
406
  * hands, so the tokens arrive here for free — no downloading an archive back
@@ -94,13 +410,36 @@ export declare function buildContentIndex(dataDir: string, rawPhrase: string, op
94
410
  */
95
411
  export declare function indexArchiveTokens(dataDir: string, rawPhrase: string, record: {
96
412
  id: string;
413
+ version?: number;
414
+ createdAt?: string;
97
415
  source: {
98
416
  agent: string;
99
417
  path: string;
100
418
  bytes: number;
419
+ sha256?: string;
420
+ project?: string | null;
421
+ projectKey?: string | null;
422
+ projectScope?: string | null;
423
+ };
424
+ cipher?: {
425
+ algorithm: unknown;
426
+ ciphertextSha256: string;
427
+ storedBytes: number;
428
+ chunks: number;
429
+ };
430
+ delta?: {
431
+ baseArchiveId: string;
432
+ baseBytes: number;
433
+ };
434
+ supersedes?: {
435
+ archiveId: string;
436
+ bytes: number;
101
437
  };
102
438
  }, tokensByChunk: ReadonlyMap<number, ReadonlySet<string>>, options?: {
103
439
  sync?: boolean;
440
+ signal?: AbortSignal;
441
+ remoteIdleMs?: number;
442
+ maxBytesPerSecond?: number;
104
443
  }): Promise<{
105
444
  pushed: boolean;
106
445
  }>;
@@ -112,28 +451,244 @@ export declare function indexArchiveTokens(dataDir: string, rawPhrase: string, r
112
451
  * dropped here and simply re-indexed, which is what "incremental" owes its
113
452
  * caller anyway.
114
453
  */
115
- export declare function normalizeContentIndex(raw: unknown): ContentIndex;
116
- export declare function loadContentIndex(dataDir: string, rawPhrase: string): Promise<ContentIndex>;
454
+ export declare function normalizeContentIndex(raw: unknown, options?: {
455
+ preserveCatalog?: boolean;
456
+ }): ContentIndex;
457
+ /** Advisory admission only: a persisted turn is never a publication receipt. */
458
+ export declare function nextScopedPublication(dataDir: string, scopes: ReadonlyArray<{
459
+ key: string;
460
+ newestArchiveAt: string;
461
+ unpublishedArchiveAt?: string;
462
+ }>, remaining: ReadonlySet<string>, signal?: AbortSignal): Promise<string | undefined>;
463
+ export declare function refreshIndexFromRemote(dataDir: string, rawPhrase: string, options?: QueryIndexWorkOptions & {
464
+ renewCloudToken?: boolean;
465
+ }): Promise<boolean>;
466
+ export declare function loadReadableIndexes(dataDir: string, unlock: {
467
+ phrase: string;
468
+ } | {
469
+ privateKey: string;
470
+ }): Promise<ContentIndex>;
471
+ /**
472
+ * The streaming-with-legacy-fallback core `loadContentIndex` reads its own
473
+ * fixed local slot through, factored out and parameterised on the envelope
474
+ * and ciphertext path instead: a caller decrypting somebody ELSE's sealed
475
+ * index (an account-index publication pulled to a temp file, never this
476
+ * vault's own `content-index.skindex`) gets the identical safe reader —
477
+ * stream first, fall back to the bounded legacy buffer parse — without
478
+ * pretending that file is this vault's local index (it is not cached here,
479
+ * and a failure is not this vault's own "rebuild your index" story).
480
+ */
481
+ export declare function loadContentIndexFromFile(envelope: Envelope, ciphertextPath: string, phrase: string, options?: {
482
+ signal?: AbortSignal;
483
+ onYield?: () => void | Promise<void>;
484
+ }): Promise<ContentIndex>;
485
+ export declare function loadContentIndex(dataDir: string, rawPhrase: string, options?: {
486
+ signal?: AbortSignal;
487
+ onYield?: () => void | Promise<void>;
488
+ }): Promise<ContentIndex>;
489
+ export type QueryIndexWorkOptions = {
490
+ signal?: AbortSignal;
491
+ remoteIdleMs?: number;
492
+ maxBytesPerSecond?: number;
493
+ /**
494
+ * Default true: check the account's hosted index for a newer copy before
495
+ * answering. False answers from the local index as it is — the mode for
496
+ * prompt-time automatic recall, which must return in the moment before an
497
+ * agent's next tool call. The daemon's own sync lane keeps the local index
498
+ * fresh; re-pulling it inside every recall serialised the whole lane behind
499
+ * one network transfer, and no memory ever reached the agent in time.
500
+ */
501
+ refreshRemote?: boolean;
502
+ /**
503
+ * Bounded freshness for time-critical readers: try the hosted index for at
504
+ * most this many milliseconds, then answer from the local index regardless.
505
+ * Prompt-time automatic recall uses this — a teammate's memory pushed a
506
+ * moment ago still arrives when the check is quick, while a slot mid-catch-up
507
+ * can no longer hold every later request hostage. The caller's own signal
508
+ * still aborts the whole search; only the budget is absorbed.
509
+ */
510
+ refreshRemoteBudgetMs?: number;
511
+ /** Internal cooperative scheduling hook used only by daemon-owned work. */
512
+ onYield?: () => void | Promise<void>;
513
+ /** Reports transferred ciphertext bytes without exposing their contents. */
514
+ onProgress?: (bytes: number) => void;
515
+ /** Optional tighter checkpoint ceilings for one interactive context read. */
516
+ maxIndexBytes?: number;
517
+ maxIndexDecodedBytes?: number;
518
+ /** Reports every expanded index chunk, including on a decoded-cache hit. */
519
+ onIndexDecoded?: (bytes: number) => void;
520
+ /** Internal diagnostic: an actual full checkpoint decoder was started. */
521
+ onIndexDecodeStart?: () => void;
522
+ /** Source readers need immutable catalog facts, not query/session metadata. */
523
+ sourceFactsOnly?: boolean;
524
+ strictErrors?: boolean;
525
+ };
526
+ export type StreamedIndexInspection = {
527
+ extractionPolicy: number;
528
+ builtAt: string;
529
+ archiveRefs: string[];
530
+ coverageJson: IndexPublicationCoverage;
531
+ effectivePostingCounts: Record<string, number>;
532
+ /** Present only when query terms were requested. It contains every archive
533
+ * and metadata row but only token rows which that query can inspect. */
534
+ index?: ContentIndex;
535
+ };
536
+ /**
537
+ * Authenticates a managed CAS snapshot and recomputes its exact semantic
538
+ * coverage without materialising the expanded plaintext or complete token map.
539
+ */
540
+ export declare function openVerifiedManagedIndexV3Streaming(envelope: Envelope, ciphertext: Buffer, opener: {
541
+ phrase: string;
542
+ } | {
543
+ privateKey: ReturnType<typeof x25519PrivateKeyFromRaw>;
544
+ }, advertisedCoverage: Readonly<Record<string, string>>, options?: QueryIndexWorkOptions & {
545
+ terms?: readonly string[];
546
+ }): Promise<StreamedIndexInspection>;
547
+ export declare function inspectLocalContentIndexCheckpoint(dataDir: string, rawPhrase: string, options?: QueryIndexWorkOptions): Promise<StreamedIndexInspection & {
548
+ envelope: Envelope;
549
+ ciphertextPath: string;
550
+ }>;
551
+ export type PublishLocalContentIndexCheckpointOptions = QueryIndexWorkOptions & {
552
+ /** Deterministic test seam. Production always resolves the account's managed store. */
553
+ store?: Pick<RemoteIndexStore, "cas">;
554
+ };
555
+ export type PublishedLocalContentIndexCheckpoint = {
556
+ status: "committed";
557
+ builtAt: string;
558
+ archiveRefs: number;
559
+ requirementsRecorded: number;
560
+ receipt: ManagedIndexReceipt;
561
+ };
562
+ /**
563
+ * Publish the already-committed local v3 checkpoint through managed immutable
564
+ * CAS without rebuilding it or retaining its token map.
565
+ *
566
+ * This deliberately is not a convergence writer: an upgrade process cannot
567
+ * merge a remote generation without constructing a new local checkpoint. It
568
+ * therefore accepts an empty head, or a head which is byte-for-byte this same
569
+ * local checkpoint, and refuses every other pre-existing head. Exact local
570
+ * archive requirements are durable before the first remote read/write; their
571
+ * receipts are installed only after `publishFile` has committed and verified
572
+ * both immutable objects by read-back.
573
+ */
574
+ export declare function publishLocalContentIndexCheckpointToManagedCas(dataDir: string, rawPhrase: string, options?: PublishLocalContentIndexCheckpointOptions): Promise<PublishedLocalContentIndexCheckpoint>;
575
+ /**
576
+ * Parses ONLY what a query needs from the sealed index buffer, streaming.
577
+ *
578
+ * Every archive and meta line is kept — a few thousand, small. Of the token
579
+ * lines, only those a query term hits are materialised: the exact token always,
580
+ * plus the first `QUERY_PREFIX_KEEP` prefix forms per term. The result is an
581
+ * index with a dozen token entries instead of a million, which `searchContent`
582
+ * then queries exactly as it would the full one — same maps, same shape.
583
+ */
584
+ export declare function parseIndexForQuery(buffer: Buffer, terms: string[]): ContentIndex;
585
+ type IndexDirectoryDraft = {
586
+ stride: number;
587
+ regions: {
588
+ archives: [number, number];
589
+ tokens: [number, number];
590
+ meta: [number, number];
591
+ };
592
+ entries: Array<[string, number]>;
593
+ };
594
+ export declare function loadContentIndexForQuery(dataDir: string, rawPhrase: string, terms: string[], options?: QueryIndexWorkOptions): Promise<ContentIndex>;
595
+ /**
596
+ * An ordinary authenticated search can lend its compact source catalog to a
597
+ * following bounded context read. A warm hit decodes zero index bytes. Cold
598
+ * reads retain the caller's original encrypted/expanded ceilings; this is not
599
+ * permission to download or expand a larger global index for one citation.
600
+ */
601
+ export declare function loadPersonalSourceFacts(dataDir: string, rawPhrase: string, options?: QueryIndexWorkOptions): Promise<ContentIndex>;
602
+ /**
603
+ * Merge one remotely opened shard through a second, plaintext scope gate.
604
+ *
605
+ * Membership controls whether the object may be downloaded and its recipient
606
+ * wrap controls whether it may be opened. The embedded project line is checked
607
+ * as well: a stale or incorrectly published shard must never make a record from
608
+ * another project visible merely because its postings share the same object.
609
+ */
610
+ export declare function mergeTeamProjectShard(target: ContentIndex, incoming: ContentIndex, project: string, spaceKey: string, origins: Map<string, string>, projectKey?: string): void;
611
+ /** Pull and open exactly the shard belonging to the requested bound project. */
612
+ export declare function pullBoundTeamProjectIndex(dataDir: string, phrase: string, project: string, terms: string[], projectKey?: string, options?: QueryIndexWorkOptions): Promise<{
613
+ index: ContentIndex;
614
+ spaceKey: string;
615
+ membershipVersion: number;
616
+ indexDecodedBytes: number;
617
+ readGuard: import("./cloud.js").TeamReadGuard;
618
+ } | null>;
619
+ export type ProjectMemory = {
620
+ id: string;
621
+ agent: string;
622
+ path: string;
623
+ at: string;
624
+ summary?: string;
625
+ commits?: Array<{
626
+ h: string;
627
+ s: string;
628
+ }>;
629
+ files?: string[];
630
+ };
631
+ /**
632
+ * The newest memories of one project, without a query and without expanding
633
+ * the token map. Used by lifecycle hooks before the user's first prompt has
634
+ * supplied search terms. A second machine first pulls a fresher sealed index;
635
+ * parsing with an empty term list retains only archive/meta lines, so even a
636
+ * million-token vault stays bounded.
637
+ */
638
+ export declare function recentProjectMemories(dataDir: string, rawPhrase: string, project: string, limit?: number, projectKey?: string, options?: QueryIndexWorkOptions): Promise<ProjectMemory[]>;
639
+ /**
640
+ * Removes the content index — all of it.
641
+ *
642
+ * This used to delete the sealed index and its envelope and leave two things
643
+ * behind: the unsealed coverage sidecar, and (since sharding) every project
644
+ * shard. The sidecar is what `index status` reads, so dropping the index left
645
+ * the product cheerfully reporting the archives as searchable when nothing
646
+ * could search them — the worst kind of wrong, because it is reassuring. The
647
+ * shards were worse: sealed slices of the index still readable by project
648
+ * members, surviving a command whose entire job is to remove the index.
649
+ */
117
650
  export declare function dropContentIndex(dataDir: string): Promise<void>;
118
651
  /**
119
652
  * Content search over the opt-in index. Every returned snippet is read from the
120
653
  * archive at query time, so nothing readable is kept on disk between searches.
121
654
  */
122
- export declare function searchContent(dataDir: string, query: string, rawPhrase: string, options?: {
655
+ export declare function searchContent(dataDir: string, query: string, rawPhrase: string, options?: QueryIndexWorkOptions & {
123
656
  agent?: string;
124
657
  snippets?: boolean;
658
+ snippetLimit?: number;
659
+ quoteLocalFirst?: boolean;
660
+ project?: string;
661
+ projectKey?: string;
662
+ archiveId?: string;
663
+ sessionId?: string;
125
664
  }): Promise<SearchHit[]>;
126
665
  export declare function search(dataDir: string, query: string, options?: {
127
666
  mode?: SearchMode;
128
667
  phrase?: string;
129
668
  agent?: string;
669
+ project?: string;
670
+ projectKey?: string;
671
+ archiveId?: string;
672
+ sessionId?: string;
130
673
  }): Promise<SearchHit[]>;
131
674
  /**
132
- * What the index covers, from the unsealed sidecar — no phrase required.
133
- * "Missing" means sealed and durable yet not yet searchable, which is exactly
134
- * the list `sealkeep index build` would work through.
675
+ * What the index covers.
676
+ *
677
+ * `total`/`indexed`/`missing` describe THIS machine's own archives, from the
678
+ * unsealed sidecar, so they need no phrase. That was once the whole answer,
679
+ * and on a team it was a confidently wrong one: a colleague's laptop holds no
680
+ * local record of anything the others sealed, so it reported "0 of 0 archives
681
+ * searchable" for an account full of history it could in fact search. An
682
+ * admin checking whether the team's memory was indexed got a zero that meant
683
+ * "I did not look", printed as though it meant "there is nothing".
684
+ *
685
+ * So when a phrase is offered, the shared index is opened and the corpus is
686
+ * reported too. Left null when no phrase is given or no index exists —
687
+ * unknown, said plainly, rather than a number that reads as none.
135
688
  */
136
- export declare function indexCoverage(dataDir: string): Promise<{
689
+ export declare function indexCoverage(dataDir: string, options?: {
690
+ phrase?: string;
691
+ }): Promise<{
137
692
  total: number;
138
693
  indexed: number;
139
694
  builtAt: string | null;
@@ -143,5 +698,8 @@ export declare function indexCoverage(dataDir: string): Promise<{
143
698
  path: string;
144
699
  agent: string;
145
700
  }[];
701
+ /** Every distinct archive the index can answer for, this machine's and other machines'. */
702
+ searchable: number | null;
703
+ /** Of those, how many this machine never sealed — the team's, pulled in as ciphertext. */
704
+ fromOtherMachines: number | null;
146
705
  }>;
147
- export {};