sealkeep 0.9.0 → 0.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.
- package/ARCHITECTURE.md +163 -14
- package/CHANGELOG.md +223 -1
- package/CONTROL_PLANE.md +2 -2
- package/LICENSE +1 -1
- package/README.md +108 -22
- package/THIRD_PARTY.md +2 -2
- package/THREAT_MODEL.md +23 -4
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/chunk-access.d.ts +26 -4
- package/dist/packages/sealkeep-crypto/src/chunk-access.js +219 -0
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/envelope.d.ts +11 -1
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/envelope.js +58 -21
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/format.d.ts +2 -2
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/index.d.ts +1 -0
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/index.js +1 -0
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/recipients.js +4 -4
- package/dist/packages/sealkeep-crypto/src/squeeze.d.ts +6 -0
- package/dist/packages/sealkeep-crypto/src/squeeze.js +39 -0
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/stream.d.ts +36 -3
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/stream.js +196 -37
- package/dist/site/index.html +1808 -1904
- package/dist/site/llms.txt +67 -0
- package/dist/site/trust/architecture-data-flow.html +53 -0
- package/dist/site/trust/audit-roadmap.html +37 -0
- package/dist/site/trust/deployment-responsibility.html +11 -0
- package/dist/site/trust/dpa-sample.html +30 -0
- package/dist/site/trust/release-provenance.html +21 -0
- package/dist/site/trust/subprocessors.html +15 -0
- package/dist/site/trust/threat-model.html +34 -0
- package/dist/site/trust/toms.html +41 -0
- package/dist/site/trust-document.css +32 -0
- package/dist/site/trust.html +73 -0
- package/dist/site/visual/assets/index-8Nxnkc7o.js +207 -0
- package/dist/site/visual/assets/index-oxLy1bpy.css +1 -0
- package/dist/site/visual/index.html +18 -0
- package/dist/site.zip +0 -0
- package/dist/src/activity.d.ts +9 -0
- package/dist/src/activity.js +90 -1
- package/dist/src/adapters.d.ts +175 -5
- package/dist/src/adapters.js +961 -73
- package/dist/src/agent-context.d.ts +135 -0
- package/dist/src/agent-context.js +1059 -0
- package/dist/src/archive-copies.d.ts +47 -0
- package/dist/src/archive-copies.js +179 -0
- package/dist/src/audit.d.ts +1 -1
- package/dist/src/audit.js +29 -4
- package/dist/src/autopilot.d.ts +52 -7
- package/dist/src/autopilot.js +143 -25
- package/dist/src/background-bandwidth.d.ts +46 -0
- package/dist/src/background-bandwidth.js +301 -0
- package/dist/src/background-cpu.d.ts +82 -0
- package/dist/src/background-cpu.js +212 -0
- package/dist/src/background-worker-error.d.ts +12 -0
- package/dist/src/background-worker-error.js +18 -0
- package/dist/src/branding.d.ts +24 -1
- package/dist/src/branding.js +31 -1
- package/dist/src/bridge.d.ts +233 -0
- package/dist/src/bridge.js +604 -0
- package/dist/src/byte-stream.d.ts +91 -0
- package/dist/src/byte-stream.js +385 -0
- package/dist/src/chunk-store.d.ts +41 -8
- package/dist/src/chunk-store.js +161 -65
- package/dist/src/cli.js +1698 -163
- package/dist/src/cloud.d.ts +841 -31
- package/dist/src/cloud.js +3196 -277
- package/dist/src/context-background.d.ts +37 -0
- package/dist/src/context-background.js +309 -0
- package/dist/src/context-drain-child.d.ts +1 -0
- package/dist/src/context-drain-child.js +98 -0
- package/dist/src/context-reader.d.ts +118 -0
- package/dist/src/context-reader.js +447 -0
- package/dist/src/control-plane/auth.d.ts +32 -4
- package/dist/src/control-plane/auth.js +85 -24
- package/dist/src/control-plane/server.js +19 -6
- package/dist/src/control-plane.d.ts +17 -1
- package/dist/src/control-plane.js +32 -6
- package/dist/src/crypto.d.ts +1 -1
- package/dist/src/crypto.js +5 -5
- package/dist/src/daemon-lease.d.ts +70 -0
- package/dist/src/daemon-lease.js +420 -0
- package/dist/src/daemon.d.ts +94 -1
- package/dist/src/daemon.js +1082 -105
- package/dist/src/darwin-service-policy.d.ts +41 -0
- package/dist/src/darwin-service-policy.js +60 -0
- package/dist/src/dashboard-cli.js +15 -15
- package/dist/src/device-authorization.d.ts +37 -0
- package/dist/src/device-authorization.js +199 -0
- package/dist/src/device-enrollment.d.ts +91 -0
- package/dist/src/device-enrollment.js +349 -0
- package/dist/src/disk.d.ts +17 -12
- package/dist/src/disk.js +43 -17
- package/dist/src/doctor.d.ts +35 -1
- package/dist/src/doctor.js +316 -41
- package/dist/src/durable-ticket-lock.d.ts +24 -0
- package/dist/src/durable-ticket-lock.js +232 -0
- package/dist/src/enroll.d.ts +1 -1
- package/dist/src/enroll.js +13 -7
- package/dist/src/env.d.ts +10 -1
- package/dist/src/env.js +11 -3
- package/dist/src/errors.d.ts +8 -8
- package/dist/src/errors.js +6 -6
- package/dist/src/flush.d.ts +12 -0
- package/dist/src/flush.js +37 -0
- package/dist/src/heartbeat.d.ts +86 -12
- package/dist/src/heartbeat.js +415 -29
- package/dist/src/index-background-watchdog.d.ts +1 -0
- package/dist/src/index-background-watchdog.js +94 -0
- package/dist/src/index-background-work.d.ts +21 -0
- package/dist/src/index-background-work.js +25 -0
- package/dist/src/index-background.d.ts +64 -0
- package/dist/src/index-background.js +394 -0
- package/dist/src/index-build-child.d.ts +1 -0
- package/dist/src/index-build-child.js +109 -0
- package/dist/src/index-manifest.d.ts +52 -0
- package/dist/src/index-manifest.js +444 -0
- package/dist/src/index-publication-proof.d.ts +84 -0
- package/dist/src/index-publication-proof.js +380 -0
- package/dist/src/index-publication-state.d.ts +149 -0
- package/dist/src/index-publication-state.js +696 -0
- package/dist/src/index-publication-verifier.d.ts +89 -0
- package/dist/src/index-publication-verifier.js +341 -0
- package/dist/src/index-publish.d.ts +62 -0
- package/dist/src/index-publish.js +540 -0
- package/dist/src/index-scratch-cleanup.d.ts +19 -0
- package/dist/src/index-scratch-cleanup.js +166 -0
- package/dist/src/index-segment-types.d.ts +132 -0
- package/dist/src/index-segment-types.js +21 -0
- package/dist/src/index-segments.d.ts +9 -0
- package/dist/src/index-segments.js +516 -0
- package/dist/src/index-store.d.ts +123 -0
- package/dist/src/index-store.js +495 -0
- package/dist/src/index-sync.d.ts +91 -15
- package/dist/src/index-sync.js +286 -53
- package/dist/src/index-upgrade-publication.d.ts +30 -0
- package/dist/src/index-upgrade-publication.js +179 -0
- package/dist/src/integration-manager.d.ts +32 -0
- package/dist/src/integration-manager.js +394 -0
- package/dist/src/leakscan.js +1 -1
- package/dist/src/local-api.d.ts +56 -15
- package/dist/src/local-api.js +4979 -541
- package/dist/src/machine-settings.d.ts +51 -0
- package/dist/src/machine-settings.js +166 -0
- package/dist/src/managed-chunks.d.ts +5 -2
- package/dist/src/managed-chunks.js +14 -14
- package/dist/src/mcp-install.d.ts +11 -9
- package/dist/src/mcp-install.js +73 -28
- package/dist/src/mcp-workspace.d.ts +18 -0
- package/dist/src/mcp-workspace.js +50 -0
- package/dist/src/mcp.js +294 -25
- package/dist/src/migrate.js +27 -21
- package/dist/src/notify.d.ts +1 -1
- package/dist/src/notify.js +5 -5
- package/dist/src/offload.d.ts +201 -14
- package/dist/src/offload.js +1848 -140
- package/dist/src/onboarding.d.ts +8 -1
- package/dist/src/onboarding.js +4 -4
- package/dist/src/packages.d.ts +2 -2
- package/dist/src/packages.js +10 -2
- package/dist/src/passkey.d.ts +0 -1
- package/dist/src/passkey.js +2 -7
- package/dist/src/password-lock.d.ts +2 -2
- package/dist/src/password-lock.js +6 -6
- package/dist/src/paths.d.ts +2 -0
- package/dist/src/paths.js +2 -0
- package/dist/src/presence.d.ts +86 -0
- package/dist/src/presence.js +240 -0
- package/dist/src/progress-deadline.d.ts +21 -0
- package/dist/src/progress-deadline.js +91 -0
- package/dist/src/project-repair.d.ts +55 -0
- package/dist/src/project-repair.js +131 -0
- package/dist/src/providers/gcs.d.ts +28 -7
- package/dist/src/providers/gcs.js +35 -24
- package/dist/src/providers/gdrive.d.ts +71 -8
- package/dist/src/providers/gdrive.js +223 -50
- package/dist/src/providers/index.d.ts +11 -3
- package/dist/src/providers/index.js +30 -10
- package/dist/src/providers/s3.d.ts +30 -8
- package/dist/src/providers/s3.js +41 -30
- package/dist/src/providers/safe-storage-fetch.d.ts +12 -0
- package/dist/src/providers/safe-storage-fetch.js +72 -0
- package/dist/src/queue.d.ts +136 -19
- package/dist/src/queue.js +862 -96
- package/dist/src/reclaim-transaction.d.ts +156 -0
- package/dist/src/reclaim-transaction.js +1027 -0
- package/dist/src/recovery-codes.d.ts +32 -0
- package/dist/src/recovery-codes.js +338 -0
- package/dist/src/recovery.js +12 -9
- package/dist/src/rehydrate.d.ts +25 -22
- package/dist/src/rehydrate.js +319 -23
- package/dist/src/restore.d.ts +57 -4
- package/dist/src/restore.js +272 -36
- package/dist/src/resume-stub.d.ts +92 -0
- package/dist/src/resume-stub.js +417 -0
- package/dist/src/retention.d.ts +98 -7
- package/dist/src/retention.js +1066 -62
- package/dist/src/rotate.js +3 -3
- package/dist/src/search.d.ts +566 -8
- package/dist/src/search.js +5897 -290
- package/dist/src/secrets.d.ts +51 -7
- package/dist/src/secrets.js +316 -24
- package/dist/src/service.d.ts +49 -11
- package/dist/src/service.js +776 -35
- package/dist/src/share.js +3 -3
- package/dist/src/shared-spaces.d.ts +98 -0
- package/dist/src/shared-spaces.js +214 -0
- package/dist/src/source-reader.d.ts +73 -0
- package/dist/src/source-reader.js +715 -0
- package/dist/src/spool.d.ts +1 -1
- package/dist/src/spool.js +1 -1
- package/dist/src/start-tui.js +2 -1
- package/dist/src/start.js +2 -2
- package/dist/src/storage-endpoint.d.ts +21 -0
- package/dist/src/storage-endpoint.js +122 -0
- package/dist/src/storage-setup.js +12 -12
- package/dist/src/storage-targets.d.ts +109 -6
- package/dist/src/storage-targets.js +975 -67
- package/dist/src/stream-to-cloud.d.ts +5 -1
- package/dist/src/stream-to-cloud.js +34 -14
- package/dist/src/sync-rules.d.ts +31 -6
- package/dist/src/sync-rules.js +153 -14
- package/dist/src/team-backfill-scheduling.d.ts +8 -0
- package/dist/src/team-backfill-scheduling.js +33 -0
- package/dist/src/team-backfill.d.ts +116 -0
- package/dist/src/team-backfill.js +1429 -0
- package/dist/src/team-index-cache.d.ts +16 -0
- package/dist/src/team-index-cache.js +152 -0
- package/dist/src/team-offboarding.d.ts +38 -0
- package/dist/src/team-offboarding.js +1043 -0
- package/dist/src/team-presence.d.ts +127 -0
- package/dist/src/team-presence.js +904 -0
- package/dist/src/team-publication-policy.d.ts +20 -0
- package/dist/src/team-publication-policy.js +140 -0
- package/dist/src/team-realtime.d.ts +68 -0
- package/dist/src/team-realtime.js +816 -0
- package/dist/src/team-source-facts-cache.d.ts +23 -0
- package/dist/src/team-source-facts-cache.js +255 -0
- package/dist/src/trash.d.ts +1 -1
- package/dist/src/trash.js +2 -2
- package/dist/src/tui.js +11 -12
- package/dist/src/types.d.ts +173 -7
- package/dist/src/types.js +20 -0
- package/dist/src/ui-server.d.ts +163 -35
- package/dist/src/ui-server.js +712 -72
- package/dist/src/ui.d.ts +1 -2
- package/dist/src/ui.js +1 -2
- package/dist/src/upload.d.ts +27 -0
- package/dist/src/upload.js +383 -43
- package/dist/src/vault.d.ts +226 -30
- package/dist/src/vault.js +1776 -192
- package/dist/src/watcher.d.ts +7 -1
- package/dist/src/watcher.js +198 -55
- package/dist/src/worker.d.ts +27 -3
- package/dist/src/worker.js +274 -55
- package/package.json +33 -12
- package/scripts/native-reboot-rehearsal.mjs +90 -0
- package/web/app.js +6032 -343
- package/web/bootstrap.js +17 -0
- package/web/index.html +255 -57
- package/web/rail.js +317 -40
- package/web/retention.html +2 -2
- package/web/rules-view.js +188 -16
- package/web/sessions-view.js +485 -62
- package/web/sessions.html +2 -2
- package/web/setup-api.js +152 -29
- package/web/setup-logic.js +68 -9
- package/web/setup.html +113 -44
- package/web/setup.js +604 -71
- package/web/style.css +513 -98
- package/dist/packages/vaultline-crypto/src/chunk-access.js +0 -93
- /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/aead.d.ts +0 -0
- /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/aead.js +0 -0
- /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/format.js +0 -0
- /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/recipients.d.ts +0 -0
- /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/sha256-stream.d.ts +0 -0
- /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/sha256-stream.js +0 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -25,13 +25,19 @@ The client is trusted to handle plaintext. The control plane and object store ar
|
|
|
25
25
|
segments hashed under a storage-scoped key, readable identity in a sealed sidecar.
|
|
26
26
|
- `index-sync`: the sealed content index, pulled and pushed as ciphertext so every
|
|
27
27
|
machine of the vault searches the whole history.
|
|
28
|
-
- `retention`: active-session detection, policy evaluation,
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
- `retention`: active-session detection, policy evaluation, verified/searchable gates,
|
|
29
|
+
and journaled source staging with a durable permanent-purge boundary.
|
|
30
|
+
- `restore`: integrity checks, atomic output, native adapter mapping; reclaimed
|
|
31
|
+
Codex history keeps a lightweight native pointer and full restore is explicit.
|
|
32
|
+
`openFromCloud` is the no-local-record path — a machine reading an archive it
|
|
33
|
+
never sealed — and so must discover the remote layout itself: a chunk folder
|
|
34
|
+
is reassembled from the sealed sidecar's own chunk headers, hash-checked per
|
|
35
|
+
chunk, because the record that would otherwise describe it lives on somebody
|
|
36
|
+
else's laptop.
|
|
31
37
|
- `local-api`: loopback API shared by CLI/TUI/desktop/MCP.
|
|
32
38
|
|
|
33
39
|
Implemented as: `src/adapters.ts`, `src/watcher.ts`, `src/queue.ts`, `src/worker.ts`,
|
|
34
|
-
`packages/
|
|
40
|
+
`packages/sealkeep-crypto/`, `src/providers/`, `src/secrets.ts`, `src/upload.ts`,
|
|
35
41
|
`src/chunk-store.ts`, `src/index-sync.ts`, `src/stream-to-cloud.ts`,
|
|
36
42
|
`src/retention.ts` with `src/activity.ts` and `src/trash.ts`, `src/restore.ts` with
|
|
37
43
|
`src/rehydrate.ts`, `src/share.ts`, `src/rotate.ts`,
|
|
@@ -63,11 +69,41 @@ archive on retry.
|
|
|
63
69
|
|
|
64
70
|
## 2.2 Hook boundary
|
|
65
71
|
|
|
66
|
-
Hook
|
|
67
|
-
path (`transcript_path`, `rollout_path`, and camelCase spellings),
|
|
68
|
-
readable, enqueue, and exit. Unknown vendor fields are ignored rather
|
|
69
|
-
so a schema change cannot break preservation.
|
|
70
|
-
`sealkeep queue run
|
|
72
|
+
Hook command lines hold no secret. Preservation hooks parse the lifecycle payload
|
|
73
|
+
for a transcript path (`transcript_path`, `rollout_path`, and camelCase spellings),
|
|
74
|
+
verify it is readable, enqueue, and exit. Unknown vendor fields are ignored rather
|
|
75
|
+
than parsed, so a schema change cannot break preservation. Archive encryption
|
|
76
|
+
happens later in `sealkeep queue run`.
|
|
77
|
+
|
|
78
|
+
Automatic context has a deliberately split latency contract:
|
|
79
|
+
|
|
80
|
+
- `hook context` is the synchronous agent-facing lane. It uses the machine's
|
|
81
|
+
normal keystore, atomically claims one prepared context file, authenticates and
|
|
82
|
+
decrypts it locally, and exits. It performs no discovery, hosted request,
|
|
83
|
+
archive refresh, search, publication, or membership reconciliation. Prepared
|
|
84
|
+
context is consumed once and the hook fails open after two seconds.
|
|
85
|
+
- `hook context-sync` is the asynchronous producer. It publishes team progress
|
|
86
|
+
before expensive recall work, reconciles the local realtime inbox, refreshes
|
|
87
|
+
and searches the encrypted index, then seals the bounded result locally for a
|
|
88
|
+
later safe boundary. Provider latency therefore changes freshness, never the
|
|
89
|
+
latency of the current prompt or tool result.
|
|
90
|
+
|
|
91
|
+
Autopilot has a similarly explicit deletion boundary. A fresh installation
|
|
92
|
+
preserves, indexes, and uploads, while `local-settings.json` records
|
|
93
|
+
`reclaimEnabled: false`; neither the generated service unit nor the running
|
|
94
|
+
daemon receives standing reclaim permission. `sealkeep autopilot --reclaim`
|
|
95
|
+
or the confirmed local Settings switch records that permission. Retention
|
|
96
|
+
rules remain a separate eligibility layer: enabling the machine switch repairs
|
|
97
|
+
a non-reclaiming policy to `archive-and-reclaim`, while selecting a
|
|
98
|
+
keep-originals policy revokes the machine switch. Re-running Autopilot during
|
|
99
|
+
an upgrade preserves an existing saved choice and its timing/manual-approval
|
|
100
|
+
policy instead of applying fresh-install defaults.
|
|
101
|
+
|
|
102
|
+
Session resume remains non-blocking: a reclaimed Codex transcript keeps its same
|
|
103
|
+
session id as a tiny valid native pointer. The resumed agent uses MCP search for
|
|
104
|
+
relevant preserved memory. Downloading every historical byte is deliberately an
|
|
105
|
+
explicit `sealkeep recover <archive-id> --native --overwrite backup` action, so a
|
|
106
|
+
resume neither downloads gigabytes nor races an agent's open transcript handle.
|
|
71
107
|
|
|
72
108
|
## 3. Archive envelope (implemented, format v2)
|
|
73
109
|
|
|
@@ -90,7 +126,7 @@ time before any chunk is touched. An archive is durable only after the provider
|
|
|
90
126
|
the byte count and checksum the client computed; `remote.verifiedAt` records that, and
|
|
91
127
|
retention reads it.
|
|
92
128
|
|
|
93
|
-
Full specification, test vectors, and tamper coverage: `packages/
|
|
129
|
+
Full specification, test vectors, and tamper coverage: `packages/sealkeep-crypto/`.
|
|
94
130
|
|
|
95
131
|
## 4. Control-plane API v1
|
|
96
132
|
|
|
@@ -98,7 +134,7 @@ Authentication is on by default. `SEALKEEP_CONTROL_PLANE_DEV=1` disables device
|
|
|
98
134
|
and keeps state in memory for local interface work; `/health` reports
|
|
99
135
|
`mode: development-interface` so a misconfigured deployment is visible in one request.
|
|
100
136
|
|
|
101
|
-
All non-enrollment endpoints require an Ed25519 device signature over
|
|
137
|
+
All non-enrollment endpoints require an Ed25519 device signature over the frozen legacy protocol string
|
|
102
138
|
`vaultline-request:v1\n<METHOD>\n<path>\n<timestamp>\n<nonce>\n<sha256(body)>`, presented in
|
|
103
139
|
`x-vaultline-device`, `-timestamp`, `-nonce`, and `-signature`. Timestamps outside a
|
|
104
140
|
five-minute window are refused, and a nonce cache rejects verbatim replays.
|
|
@@ -132,6 +168,119 @@ deletes an archive; the response reports how many archives were retained. Revoca
|
|
|
132
168
|
retroactive for ciphertext an attacker already holds — the client-side counterpart is
|
|
133
169
|
`sealkeep recipients remove` followed by `sealkeep rewrap`.
|
|
134
170
|
|
|
171
|
+
### What the plan buys
|
|
172
|
+
|
|
173
|
+
Sealkeep works without an account. The vault, the sealing, the restore, the
|
|
174
|
+
search and your own bucket are all local and always free — that is the product,
|
|
175
|
+
and none of it phones anywhere. What a plan buys is the small hosted layer that
|
|
176
|
+
removes setup nobody wants to do themselves, and it is enforced here rather
|
|
177
|
+
than in the client, because a check the client makes is a check the customer
|
|
178
|
+
can delete.
|
|
179
|
+
|
|
180
|
+
| Capability | Needs | Why it costs |
|
|
181
|
+
| --- | --- | --- |
|
|
182
|
+
| Local vault, archive, restore, search | free | never touches this plane |
|
|
183
|
+
| Your own bucket (S3, R2, B2, GCS) | free | your provider, your bill |
|
|
184
|
+
| Key escrow — a sealed copy of the vault key | any paid tier | we hold and mind a row for you |
|
|
185
|
+
| Machine registry, per-machine delete rights, revocation | any paid tier | identity is coordination, which is what this plane is for |
|
|
186
|
+
| Connect Google Drive | any paid tier | our OAuth app and our server-held client secret |
|
|
187
|
+
| Managed storage (upload, index slot) | `pro` / `team` | our GCS, our bytes, metered against quota |
|
|
188
|
+
|
|
189
|
+
The tiers are `free | pro_lite | pro | team` on `account.plan`. Every gate
|
|
190
|
+
answers **402**, never 400 or 403, so a client can tell "you have not paid for
|
|
191
|
+
this" apart from "you are not allowed to do this" — they need different words
|
|
192
|
+
in front of a person, and the CLI codes the first as `payment_required`.
|
|
193
|
+
|
|
194
|
+
Seats are the other axis, enforced at device registration and counted over
|
|
195
|
+
**active** machines only, so revoking one frees its seat at once: `pro_lite` 3,
|
|
196
|
+
`pro` 10, `team` 100, and `free` cannot register a machine at all. The panel's
|
|
197
|
+
`PACKAGES` list carries the same numbers; they have to be changed together or
|
|
198
|
+
the page starts promising something the plane refuses.
|
|
199
|
+
|
|
200
|
+
`team` is what the B2B features already in the client hang from — recipient
|
|
201
|
+
keys (`sealkeep recipients` + `rewrap`), project-scoped membership
|
|
202
|
+
(`--project`, `space members`), owner-key delete authority, and corporate
|
|
203
|
+
bucket routing. None of that was new work; what was missing was a tier to sell
|
|
204
|
+
it as and a limit that meant anything.
|
|
205
|
+
|
|
206
|
+
A warning from writing these guards: **error strings are expression-evaluated**,
|
|
207
|
+
so a bare word that matches an assigned variable name is rewritten. "Every
|
|
208
|
+
machine seat on this plan is in use" shipped to a customer as "Every
|
|
209
|
+
vars.machine seat…" because a later step assigns `machine`. Re-read every
|
|
210
|
+
refusal against a live account before believing it.
|
|
211
|
+
|
|
212
|
+
**A lapsed subscription stops writes at once and reads after 30 days.** The
|
|
213
|
+
grace window runs from `subscription.current_period_end` (falling back to
|
|
214
|
+
`updated_at`), and the download lease reports `reading_on_grace` and
|
|
215
|
+
`grace_until` so a client can warn before the door shuts. The asymmetry is
|
|
216
|
+
deliberate: the bytes are the customer's, and a billing failure should never be
|
|
217
|
+
the reason they cannot get their own history out. Archives on their own bucket
|
|
218
|
+
or their own Drive are untouched by any of this — they were never ours to hold.
|
|
219
|
+
|
|
220
|
+
Escrow READS are never gated. Refusing someone the sealed copy of their own
|
|
221
|
+
vault key because a card expired could lock them out of everything they own.
|
|
222
|
+
|
|
223
|
+
### `/v1/cloud/security/*` — watching without reading
|
|
224
|
+
|
|
225
|
+
The plane holds ciphertext. It could not scan a transcript for a leaked key if
|
|
226
|
+
it wanted to, and it should not want to. So the scan runs on the developer's
|
|
227
|
+
own machine, where the plaintext briefly exists, and only the verdict travels:
|
|
228
|
+
the rule that matched, how many times, which machine, which archive.
|
|
229
|
+
|
|
230
|
+
Never the matched text. Never the surrounding line. Not even `maskSecret`'s
|
|
231
|
+
preview — that is masked well enough for a terminal, not well enough for a
|
|
232
|
+
database that keeps it forever. And never the project name, which by design
|
|
233
|
+
never reaches this plane at all. `test/security-findings.test.ts` pins the wire
|
|
234
|
+
shape as an allow-list, so a new field is a deliberate decision rather than an
|
|
235
|
+
accident.
|
|
236
|
+
|
|
237
|
+
`POST /security/findings` records one row per rule, not per match: a session
|
|
238
|
+
that pasted the same key forty times is one problem, and forty rows would bury
|
|
239
|
+
the other findings under it. `GET /security/findings` is the company's feed.
|
|
240
|
+
`GET /security/policy` hands every machine the company's own patterns, plus
|
|
241
|
+
`block_on_high`, which is what turns detection into prevention — a machine that
|
|
242
|
+
pulls it refuses to seal a session carrying a high-severity match rather than
|
|
243
|
+
reporting it afterwards.
|
|
244
|
+
|
|
245
|
+
Reporting is best-effort by construction. An account below `team` answers 402
|
|
246
|
+
and the client stops asking; a network failure loses a report. The one thing it
|
|
247
|
+
must never do is cost anyone a seal.
|
|
248
|
+
|
|
249
|
+
### Seats, and why they are not storage
|
|
250
|
+
|
|
251
|
+
`account.seats` is the purchased machine allowance and beats the tier default.
|
|
252
|
+
It exists because storage is the wrong axis for a company: a team that keeps
|
|
253
|
+
everything in its own bucket consumes none of ours and would otherwise pay for
|
|
254
|
+
a storage tier it never touches. Seats and `quota_bytes` are priced apart, so
|
|
255
|
+
bring-your-own-bucket costs seats alone.
|
|
256
|
+
|
|
257
|
+
### Self-hosting
|
|
258
|
+
|
|
259
|
+
`SEALKEEP_CLOUD_URL` points a machine at any compatible plane, and every path
|
|
260
|
+
that reaches this one honours it — `cloud.ts`, `enroll.ts`, `local-api.ts`,
|
|
261
|
+
`storage-targets.ts`. The only hard-coded address is `DEFAULT_CLOUD_URL`. The
|
|
262
|
+
test suite runs a full seal → chunk upload → download → restore against a stub
|
|
263
|
+
plane on `127.0.0.1` via that variable, so this is a tested path rather than an
|
|
264
|
+
aspiration. What a self-hosting customer needs from us is the plane itself and
|
|
265
|
+
this contract, not a client change.
|
|
266
|
+
|
|
267
|
+
### `DELETE /v1/cloud/archives/:vault_key`
|
|
268
|
+
|
|
269
|
+
Destroying is authorised separately from reading, because the bearer token
|
|
270
|
+
names the account and not the machine: every laptop paired to a company account
|
|
271
|
+
presents an identical one. The body carries either a **machine key** (issued
|
|
272
|
+
once at device registration, only its bcrypt is stored) or an **owner key**
|
|
273
|
+
(minted by a completed web sign-in, which a CLI token cannot perform). An
|
|
274
|
+
archive records `sealed_by_machine` at upload completion; a machine may delete
|
|
275
|
+
what it sealed, an owner key may delete anything, and everything else is
|
|
276
|
+
refused. Allowed and refused attempts both write an audit row. Archives
|
|
277
|
+
predating this carry no stamp and remain account-wide deletable — attribution
|
|
278
|
+
starts at the next upload.
|
|
279
|
+
|
|
280
|
+
Credentials travel in the request body rather than a header because this
|
|
281
|
+
control plane does not surface request headers to endpoint logic; that was
|
|
282
|
+
measured, not assumed.
|
|
283
|
+
|
|
135
284
|
### `GET /v1/audit`
|
|
136
285
|
|
|
137
286
|
Account-scoped audit events: action, outcome, identifiers, and counts. No content.
|
|
@@ -167,7 +316,7 @@ command. Bodies are capped at 1 MB, validated with strict schemas, and rejected
|
|
|
167
316
|
|
|
168
317
|
## 5. Local MCP contract
|
|
169
318
|
|
|
170
|
-
MCP tools call local APIs, not provider SDKs directly. `
|
|
319
|
+
MCP tools call local APIs, not provider SDKs directly. `sealkeep_create_upload` returns a lease object; it must never receive a cloud secret. Search defaults to metadata. Recover and archive require explicit local authorization/recovery secret.
|
|
171
320
|
|
|
172
321
|
## 6. Failure behavior
|
|
173
322
|
|
|
@@ -184,8 +333,8 @@ Implemented and tested end to end: capture (hooks, watcher, durable queue), encr
|
|
|
184
333
|
(format v2 with vectors and a tamper suite), provider clients (SigV4 verified against AWS's
|
|
185
334
|
published example; multipart, GCS resumable, and the plain object verbs exercised against
|
|
186
335
|
in-process emulators), verified upload, the chunk-folder remote layout with hashed naming
|
|
187
|
-
and sealed identity, retention with
|
|
188
|
-
and
|
|
336
|
+
and sealed identity, retention with crash-safe staging and permanent source reclaim, restore including native adapter paths
|
|
337
|
+
and the lightweight resume pointer, the sealed index sync, the loopback API behind the dashboard and
|
|
189
338
|
TUI, the MCP server and its installer, the control plane with device auth and audit,
|
|
190
339
|
search, and the local audit log.
|
|
191
340
|
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,227 @@
|
|
|
3
3
|
Notable changes, by published version. Sealkeep is pre-1.0: minor versions
|
|
4
4
|
may change behavior, and say so here when they do.
|
|
5
5
|
|
|
6
|
+
## 0.11.0 — 2026-09-16 — automatic memory that works, and an append-only index
|
|
7
|
+
|
|
8
|
+
**Automatic recall now works on a real, long-lived vault.** The hook lane
|
|
9
|
+
(`sealkeep hook context-sync` → daemon → `sealkeep hook context`) silently did
|
|
10
|
+
nothing on a vault with months of history; every cause below was found by
|
|
11
|
+
running it, not reading it.
|
|
12
|
+
|
|
13
|
+
- Test daemons no longer re-target the machine's real agent hooks at a
|
|
14
|
+
temporary vault; the installer repairs hooks aimed at a vanished vault, and
|
|
15
|
+
`sealkeep doctor` fails, naming the path, when hooks route to a different
|
|
16
|
+
live vault.
|
|
17
|
+
- The recall child is no longer CPU-paused behind the hours-long index
|
|
18
|
+
catch-up; each recall bounds its hosted index refresh, its start-of-session
|
|
19
|
+
team steps and its presence publish/catch-up to seconds, answering from the
|
|
20
|
+
local index when the plane is slow. The presence upload was a silent three-
|
|
21
|
+
to-six-second tail that tripped the stall deadline after the scan had
|
|
22
|
+
finished, so the pass was killed at the finish line and retried.
|
|
23
|
+
- Nothing is injected when nothing was recalled. Personal vaults recall across
|
|
24
|
+
untagged sessions (hand-archived, or sealed before project tags existed)
|
|
25
|
+
without ever crossing into a different stable project key; `sealkeep archive
|
|
26
|
+
<file>` tags the agent and project itself.
|
|
27
|
+
- Recall picks up to three specific terms from the prompt (never the project
|
|
28
|
+
name), prefers a session's later excerpts, and stops after the second
|
|
29
|
+
productive scan. "Recent preserved sessions" lists each session once, by its
|
|
30
|
+
newest snapshot: a live session is sealed every few minutes, and its
|
|
31
|
+
snapshots used to fill all five lines and hide every other session.
|
|
32
|
+
- A session's end drops its queued recall work — including what a pass still
|
|
33
|
+
running for it writes afterwards; within a priority tier the newest request
|
|
34
|
+
is served first, so a finished session never delays the one being typed in.
|
|
35
|
+
Day-old prepared context, state and locks are swept, and the daemon's first
|
|
36
|
+
heartbeat removes replace-temporaries left by unclean stops.
|
|
37
|
+
- The recall child's no-progress deadline is 20 s (was 8 s): a healthy pass on
|
|
38
|
+
a large vault reports progress 4–6 s apart under ordinary load, and every
|
|
39
|
+
budgeted hosted wait now keeps reporting progress while it lasts. The
|
|
40
|
+
two-minute absolute ceiling is unchanged.
|
|
41
|
+
- The service heartbeat records the recall lane (`context`: state, consecutive
|
|
42
|
+
failures, last error as a stable word), and `sealkeep doctor` reports
|
|
43
|
+
`automatic-recall` — a warning after three failed passes in a row, otherwise
|
|
44
|
+
when memory was last prepared. Hooks fail open, so this is the only place a
|
|
45
|
+
dying lane is distinguishable from one with nothing to recall.
|
|
46
|
+
- A memory hook that cannot unlock the vault still answers the agent's empty
|
|
47
|
+
object, but now leaves a marker the next successful hook clears, and doctor
|
|
48
|
+
fails `automatic-recall` naming the agent, the time and the secret backend
|
|
49
|
+
the hook ran with. On a real host the hooks were pinned to a secret backend
|
|
50
|
+
that no longer held the phrase: sealing and uploading kept working while
|
|
51
|
+
indexing, recall and hook capture were silently off.
|
|
52
|
+
- `sealkeep_recover` is dry-run by default, as its context pack already said;
|
|
53
|
+
`sealkeep recover --dry-run` matches.
|
|
54
|
+
- A seal now keeps the tokens it extracted from the plaintext as a sealed
|
|
55
|
+
sidecar beside the record (`<archive-id>.sktokens`, kilobytes) before it
|
|
56
|
+
merges them into the index, and the index catch-up indexes such an archive
|
|
57
|
+
from that file alone — nothing is decrypted or downloaded again. On a real
|
|
58
|
+
vault the merge had failed silently for 2,300 seals in one week, discarding
|
|
59
|
+
their tokens and re-queuing 1.85 TB of history for a full decrypt that never
|
|
60
|
+
completed. A merge or sidecar that fails is now named (`SealkeepIndexDeferred`
|
|
61
|
+
warning; `index.merge` / `index.tokens` audit entries).
|
|
62
|
+
- **A term lookup no longer reads the whole index.** The index is sealed in
|
|
63
|
+
independent chunks (`zstd-chunk`) and each checkpoint writes a sealed term
|
|
64
|
+
directory beside it (`content-index.directory.skindex`: the byte offset of
|
|
65
|
+
every 64th token row and the archive/metadata regions). A query
|
|
66
|
+
binary-searches the directory, opens only the chunks holding its window and
|
|
67
|
+
parses a few hundred rows — the old read decrypted and inflated 100 MB and
|
|
68
|
+
parsed 1.5 million rows for every term, 8–12 s each on a real vault. An
|
|
69
|
+
index without a usable directory (older, or pulled from another machine)
|
|
70
|
+
still takes the full read.
|
|
71
|
+
- **The index is append-only.** `sealkeep index migrate` moves a vault's
|
|
72
|
+
index onto sealed, immutable segments (`index/segments/`: one sealed body,
|
|
73
|
+
its envelope and a sealed term directory per segment, listed in a plaintext
|
|
74
|
+
manifest that holds only ids and counts). A sealed memory never changes, so
|
|
75
|
+
its index rows are written once: a seal appends a one-archive segment
|
|
76
|
+
instead of re-reading, rewriting and re-uploading the whole index; the
|
|
77
|
+
catch-up writes each checkpoint's batch as a segment and never holds more
|
|
78
|
+
than one batch, so the background child no longer dies on a large vault
|
|
79
|
+
(2 million terms exceeded its 1 GB heap on every attempt); a removed archive
|
|
80
|
+
becomes a tombstone that every lookup and the next compaction honour.
|
|
81
|
+
Compaction streams small segments into one bigger immutable segment — the
|
|
82
|
+
small-segment rule at seal time, the full policy in the build lane. A
|
|
83
|
+
lookup opens every segment's directory and reads only the blocks holding
|
|
84
|
+
its terms, then merges: 0.3–0.8 s per term on a 2-million-term vault, in a
|
|
85
|
+
process that stays under 350 MB. `index drop` keeps a migrated vault on
|
|
86
|
+
segments; a changed extraction policy resets the segments and re-indexes
|
|
87
|
+
instead of looping the daemon on "coverage incomplete"; `index status`
|
|
88
|
+
answers from the manifest. The single blob is still produced for the cloud
|
|
89
|
+
by a foreground build (the background child publishes only when the merged
|
|
90
|
+
index fits 400,000 tokens), and another machine's newer cloud index is not
|
|
91
|
+
yet folded into segments — both follow when segments themselves are
|
|
92
|
+
published; until then a segmented vault skips the pull of that blob, which
|
|
93
|
+
cost every recall pass the 2 s it was budgeted and a plain search 30 s on a
|
|
94
|
+
slow plane. Opening a segment unwraps its key once per process (two scrypt
|
|
95
|
+
derivations, ~70 ms each, were paid again for every decrypted window): a
|
|
96
|
+
term lookup is 5–40 ms, a full merge across segments under 200 ms, and
|
|
97
|
+
prompt → prepared memory on the 4,000-archive vault is 3.0–3.5 s.
|
|
98
|
+
- **A local seal indexes itself.** Only the cloud seal path collected a
|
|
99
|
+
session's tokens as it sealed; a session sealed locally (no cloud, a cloud
|
|
100
|
+
that is unreachable, `sealkeep archive`) waited for the background catch-up,
|
|
101
|
+
which on a real vault sits behind hours of multi-gigabyte snapshots — the
|
|
102
|
+
session a person had just finished was the last thing that became
|
|
103
|
+
searchable. The daemon, the CLI and the MCP server now index a full seal as
|
|
104
|
+
part of the seal (chunk-compressed, up to the whale threshold; a delta is
|
|
105
|
+
still indexed as one chain by the catch-up), on segments always and on a
|
|
106
|
+
blob index while it is small and no catch-up is building it (the blob has
|
|
107
|
+
one writer at a time) — a large blob is merged whole in-process, and that
|
|
108
|
+
is the crash the segments exist to avoid, so a large vault gets seal-time
|
|
109
|
+
indexing by migrating. As on the cloud path, a failed entry is
|
|
110
|
+
named (`SealkeepIndexDeferred`, audit `index.merge`), never a failed seal.
|
|
111
|
+
- **Segments travel between machines.** On a store that can hold objects
|
|
112
|
+
(bring-your-own storage) a machine uploads each of its immutable segments
|
|
113
|
+
once — three objects per segment, a per-machine head, a heads map for
|
|
114
|
+
discovery — and a peer downloads only the segments it has not seen,
|
|
115
|
+
registering them as remote: never compacted with its own, replaced when
|
|
116
|
+
the source publishes a newer set, the source's tombstones honoured. The
|
|
117
|
+
managed plane holds only the index's meta and blob objects, so a
|
|
118
|
+
segmented vault there keeps publishing the blob merged from its segments
|
|
119
|
+
(a foreground build always, the background child while the merge fits
|
|
120
|
+
400,000 tokens) and converts a peer's newer blob into one remote segment,
|
|
121
|
+
skipping its own publication and any blob over 64 MiB. The daemon runs a
|
|
122
|
+
publish pass whenever the manifest has moved since the last publication,
|
|
123
|
+
so a seal reaches the other machines without waiting for a catch-up.
|
|
124
|
+
- **A transcript is indexed once.** A full re-seal of a file that replaces an
|
|
125
|
+
earlier snapshot (`supersedes`) is now the only snapshot of that file the
|
|
126
|
+
index holds: older snapshots are skipped by the catch-up, purged from a
|
|
127
|
+
blob index and tombstoned on segments, and `index status` no longer counts
|
|
128
|
+
them as missing. On a real vault the catch-up backlog was 416 snapshots of
|
|
129
|
+
a handful of multi-gigabyte Codex rollouts — one June rollout of 2.7 GB had
|
|
130
|
+
been sealed 88 times, and every copy was queued for a full decrypt. A
|
|
131
|
+
delta seal (the bytes appended since the last seal) now indexes those bytes
|
|
132
|
+
inline, under its own id and chunks, instead of waiting for the catch-up to
|
|
133
|
+
decrypt the whole chain again, each part answering for its own bytes.
|
|
134
|
+
- Migrating a vault whose index carried another machine's sessions (pulled
|
|
135
|
+
from the account index) no longer loses them: the first build after the
|
|
136
|
+
migration tombstoned every one of them as "indexed here but no longer here"
|
|
137
|
+
— on the rehearsal's dev vault, all eleven of a teammate's sessions. A
|
|
138
|
+
migrated segment now records which rows are this machine's and which came
|
|
139
|
+
from elsewhere; only the former can ever be pruned, and `index status`
|
|
140
|
+
counts both.
|
|
141
|
+
- Interrupted builds no longer leave the plaintext index behind. A killed
|
|
142
|
+
catch-up (the background child running out of memory, a reboot) left its
|
|
143
|
+
streaming checkpoint's staging file — every token of every session, in the
|
|
144
|
+
clear — under `index/` forever, because the sweep only knew sealed temps; a
|
|
145
|
+
real vault held 1.9 GB of them. Staging files older than an hour are swept
|
|
146
|
+
at the start of every build, under `index/` and `index/segments/` alike.
|
|
147
|
+
- Automatic recall runs its terms concurrently, quotes two sessions per term
|
|
148
|
+
(`snippetLimit`) and takes sessions whose sealed bytes are on this disk
|
|
149
|
+
first (`quoteLocalFirst`) — a reclaimed session's quote is a ranged fetch
|
|
150
|
+
from the cloud, seconds on a slow plane. The top-ranked cloud-only session
|
|
151
|
+
still keeps its quote (one per term): a teammate's session is never on this
|
|
152
|
+
disk, and the rehearsal showed the person's own sessions filling every slot
|
|
153
|
+
while the colleague's decision ranked first and went unquoted.
|
|
154
|
+
- A preserved Claude Code session's one line ("Recent preserved sessions", a
|
|
155
|
+
teammate's finished note) is its last assistant message. The scrape used to
|
|
156
|
+
take the last string in the file, which in a Claude transcript is the
|
|
157
|
+
harness's own reminder — so a session read as `<system-reminder>
|
|
158
|
+
<total_tokens>…`. Harness scaffolding is skipped in the fallback too, an
|
|
159
|
+
index pass re-derives a scaffold line while the source is still on disk,
|
|
160
|
+
and a quote never comes from the harness or from memory Sealkeep itself
|
|
161
|
+
injected on an earlier turn (a transcript carries both, and both matched —
|
|
162
|
+
a matching line with nothing else to show is dropped rather than quoted
|
|
163
|
+
raw). When two copies of the index are merged, a real one-liner wins over
|
|
164
|
+
a scaffold one from either side. A budgeted hosted index refresh is
|
|
165
|
+
attempted once a minute per process instead of once per lookup, and search
|
|
166
|
+
ranking no longer scans the record list inside its comparator. Prompt →
|
|
167
|
+
prepared memory on a 4,000-archive vault: 15 s → 2.5–4 s.
|
|
168
|
+
- The index build interns posting tags (one string per archive chunk instead
|
|
169
|
+
of one per posting — 19 million on a real vault) and no longer indexes
|
|
170
|
+
numbers of four or more digits or digit-bearing tokens of sixteen or more
|
|
171
|
+
characters (a quarter of a real vault's vocabulary: line numbers, byte
|
|
172
|
+
counts, timestamps, base64 slivers). Ids such as `p04946`, `s3`, `sha256`,
|
|
173
|
+
`429` stay searchable.
|
|
174
|
+
- The index catch-up schedules archives over 256 MB after every ordinary
|
|
175
|
+
session (newest-first within each group). Eight ~2.6 GB snapshots at the
|
|
176
|
+
head of a real vault's queue had held the lane for a week: nothing could
|
|
177
|
+
checkpoint before the first finished, and under the shared CPU budget and
|
|
178
|
+
daily restarts it never did. A checkpoint that fails to save is now named
|
|
179
|
+
(`SealkeepIndexCheckpoint` warning) instead of silently making "safe to
|
|
180
|
+
stop; it resumes here" untrue.
|
|
181
|
+
|
|
182
|
+
- Contributor removal preserves authenticated shared history in durable owner
|
|
183
|
+
custody before changing membership, then republishes it for the surviving
|
|
184
|
+
roster. Interrupted handoffs resume without needing the contributor's machine.
|
|
185
|
+
- Invitation acceptance checks a preserved history snapshot atomically. Writes
|
|
186
|
+
made while an invitation is pending require a refreshed snapshot; accepted
|
|
187
|
+
members receive preserved history through the owner's background handoff.
|
|
188
|
+
- Team snippets use the authenticated project index, validate archive facts and
|
|
189
|
+
membership, and enforce bounded streaming reads and decompression. Personal
|
|
190
|
+
index records cannot override the authorization facts used for a shared read.
|
|
191
|
+
- Concurrent backfill staging uses unique temporary files. Archive transfer
|
|
192
|
+
completion is reported only after its final journal state is durable.
|
|
193
|
+
- A secret-free indexing watchdog now resumes and terminates its exact worker
|
|
194
|
+
if the owning service dies while that worker is CPU-paused. Work starts only
|
|
195
|
+
after the watchdog confirms ownership; watchdog failure stops the worker.
|
|
196
|
+
- Concurrent scratch-space claims retry if the competing owner released its
|
|
197
|
+
lease during collision handling. Team realtime shutdown now drains pending
|
|
198
|
+
refreshes and writes instead of reconnecting or writing after close returns.
|
|
199
|
+
- Enterprise deployment acceptance remains pending. The verification record in
|
|
200
|
+
`docs/enterprise-verification-2026-09-05.md` distinguishes hosted tests from
|
|
201
|
+
unverified isolated-runtime promises and records explicit operating limits.
|
|
202
|
+
|
|
203
|
+
## 0.10.0 — 2026-09-04
|
|
204
|
+
|
|
205
|
+
**Archived Codex sessions stay resumable without keeping their bulky local
|
|
206
|
+
transcripts.** Safe disk reclaim leaves a tiny native rollout at the original
|
|
207
|
+
path, so `codex resume <session-id>` still opens the same thread. The pointer
|
|
208
|
+
tells Codex to use the local Sealkeep MCP, and recall searches every preserved
|
|
209
|
+
snapshot carrying that exact Codex session UUID—not only the most recent
|
|
210
|
+
archive. Questions whose facts span several resume/reclaim cycles are ranked
|
|
211
|
+
inside that session boundary and never widened to unrelated threads.
|
|
212
|
+
|
|
213
|
+
- Reclaim now fails closed unless the encrypted archive and the current
|
|
214
|
+
immutable managed search index are both verified. On a repeated resume it
|
|
215
|
+
also requires a current positive publication receipt and searchable postings
|
|
216
|
+
for every earlier reclaimed continuation, then rechecks all receipts and the
|
|
217
|
+
exact index head immediately before unlinking the source.
|
|
218
|
+
- Historical indexing and context delivery run outside the interactive hook
|
|
219
|
+
path. Background work is serial and cooperative, targets at most 30% CPU,
|
|
220
|
+
shares one 8 Mbit/s vault-wide transfer ceiling, and runs in children with
|
|
221
|
+
explicit heap/RSS, cancellation, and progress-deadline limits.
|
|
222
|
+
- Existing encrypted v3 indexes upgrade through the same managed CAS protocol
|
|
223
|
+
in the bounded background child. A successful publication avoids a full
|
|
224
|
+
rebuild; interrupted publication retains a durable retry marker, while an
|
|
225
|
+
incompatible or divergent index follows the authenticated rebuild path.
|
|
226
|
+
|
|
6
227
|
## 0.9.0 — 2026-08-20
|
|
7
228
|
|
|
8
229
|
**Share a project, not the vault.** Until now a registered key opened everything
|
|
@@ -48,7 +269,8 @@ that no longer needs a spacious disk.
|
|
|
48
269
|
a failed queue job used a stylesheet class that did not exist, five notes
|
|
49
270
|
used an undefined token, and the retention view typed over edits in progress
|
|
50
271
|
and could then save the policy you thought you had changed.
|
|
51
|
-
-
|
|
272
|
+
- Archive helpers accept an explicit typed test chunk size; production has no
|
|
273
|
+
undocumented environment override.
|
|
52
274
|
Proving a multi-chunk archive used to mean writing 24 MB; it now takes 120 KB,
|
|
53
275
|
which is why the suite stopped exhausting disks.
|
|
54
276
|
- New: `npm run browser:audit` and `npm run browser:panel` — real Chrome,
|
package/CONTROL_PLANE.md
CHANGED
|
@@ -7,7 +7,7 @@ The control plane stores device identities, encrypted manifests, and provider co
|
|
|
7
7
|
```sh
|
|
8
8
|
npm run control-plane # authenticated, durable
|
|
9
9
|
SEALKEEP_CONTROL_PLANE_DEV=1 npm run control-plane # unauthenticated, in memory
|
|
10
|
-
docker build -t
|
|
10
|
+
docker build -t sealkeep-control-plane . && docker run -p 8787:8787 -v sealkeep-data:/data sealkeep-control-plane
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Endpoints:
|
|
@@ -44,7 +44,7 @@ deployed, stop it.
|
|
|
44
44
|
```json
|
|
45
45
|
{
|
|
46
46
|
"provider": "s3 | r2 | gcs | vaultline",
|
|
47
|
-
"bucket": "
|
|
47
|
+
"bucket": "sealkeep-archives",
|
|
48
48
|
"region": "us-east-1",
|
|
49
49
|
"prefix": "v1/accounts/<account-id>",
|
|
50
50
|
"credentialMode": "server-managed | byo-role | byo-service-account"
|
package/LICENSE
CHANGED