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.
Files changed (274) hide show
  1. package/ARCHITECTURE.md +163 -14
  2. package/CHANGELOG.md +223 -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.js +4 -4
  16. package/dist/packages/sealkeep-crypto/src/squeeze.d.ts +6 -0
  17. package/dist/packages/sealkeep-crypto/src/squeeze.js +39 -0
  18. package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/stream.d.ts +36 -3
  19. package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/stream.js +196 -37
  20. package/dist/site/index.html +1808 -1904
  21. package/dist/site/llms.txt +67 -0
  22. package/dist/site/trust/architecture-data-flow.html +53 -0
  23. package/dist/site/trust/audit-roadmap.html +37 -0
  24. package/dist/site/trust/deployment-responsibility.html +11 -0
  25. package/dist/site/trust/dpa-sample.html +30 -0
  26. package/dist/site/trust/release-provenance.html +21 -0
  27. package/dist/site/trust/subprocessors.html +15 -0
  28. package/dist/site/trust/threat-model.html +34 -0
  29. package/dist/site/trust/toms.html +41 -0
  30. package/dist/site/trust-document.css +32 -0
  31. package/dist/site/trust.html +73 -0
  32. package/dist/site/visual/assets/index-8Nxnkc7o.js +207 -0
  33. package/dist/site/visual/assets/index-oxLy1bpy.css +1 -0
  34. package/dist/site/visual/index.html +18 -0
  35. package/dist/site.zip +0 -0
  36. package/dist/src/activity.d.ts +9 -0
  37. package/dist/src/activity.js +90 -1
  38. package/dist/src/adapters.d.ts +175 -5
  39. package/dist/src/adapters.js +961 -73
  40. package/dist/src/agent-context.d.ts +135 -0
  41. package/dist/src/agent-context.js +1059 -0
  42. package/dist/src/archive-copies.d.ts +47 -0
  43. package/dist/src/archive-copies.js +179 -0
  44. package/dist/src/audit.d.ts +1 -1
  45. package/dist/src/audit.js +29 -4
  46. package/dist/src/autopilot.d.ts +52 -7
  47. package/dist/src/autopilot.js +143 -25
  48. package/dist/src/background-bandwidth.d.ts +46 -0
  49. package/dist/src/background-bandwidth.js +301 -0
  50. package/dist/src/background-cpu.d.ts +82 -0
  51. package/dist/src/background-cpu.js +212 -0
  52. package/dist/src/background-worker-error.d.ts +12 -0
  53. package/dist/src/background-worker-error.js +18 -0
  54. package/dist/src/branding.d.ts +24 -1
  55. package/dist/src/branding.js +31 -1
  56. package/dist/src/bridge.d.ts +233 -0
  57. package/dist/src/bridge.js +604 -0
  58. package/dist/src/byte-stream.d.ts +91 -0
  59. package/dist/src/byte-stream.js +385 -0
  60. package/dist/src/chunk-store.d.ts +41 -8
  61. package/dist/src/chunk-store.js +161 -65
  62. package/dist/src/cli.js +1698 -163
  63. package/dist/src/cloud.d.ts +841 -31
  64. package/dist/src/cloud.js +3196 -277
  65. package/dist/src/context-background.d.ts +37 -0
  66. package/dist/src/context-background.js +309 -0
  67. package/dist/src/context-drain-child.d.ts +1 -0
  68. package/dist/src/context-drain-child.js +98 -0
  69. package/dist/src/context-reader.d.ts +118 -0
  70. package/dist/src/context-reader.js +447 -0
  71. package/dist/src/control-plane/auth.d.ts +32 -4
  72. package/dist/src/control-plane/auth.js +85 -24
  73. package/dist/src/control-plane/server.js +19 -6
  74. package/dist/src/control-plane.d.ts +17 -1
  75. package/dist/src/control-plane.js +32 -6
  76. package/dist/src/crypto.d.ts +1 -1
  77. package/dist/src/crypto.js +5 -5
  78. package/dist/src/daemon-lease.d.ts +70 -0
  79. package/dist/src/daemon-lease.js +420 -0
  80. package/dist/src/daemon.d.ts +94 -1
  81. package/dist/src/daemon.js +1082 -105
  82. package/dist/src/darwin-service-policy.d.ts +41 -0
  83. package/dist/src/darwin-service-policy.js +60 -0
  84. package/dist/src/dashboard-cli.js +15 -15
  85. package/dist/src/device-authorization.d.ts +37 -0
  86. package/dist/src/device-authorization.js +199 -0
  87. package/dist/src/device-enrollment.d.ts +91 -0
  88. package/dist/src/device-enrollment.js +349 -0
  89. package/dist/src/disk.d.ts +17 -12
  90. package/dist/src/disk.js +43 -17
  91. package/dist/src/doctor.d.ts +35 -1
  92. package/dist/src/doctor.js +316 -41
  93. package/dist/src/durable-ticket-lock.d.ts +24 -0
  94. package/dist/src/durable-ticket-lock.js +232 -0
  95. package/dist/src/enroll.d.ts +1 -1
  96. package/dist/src/enroll.js +13 -7
  97. package/dist/src/env.d.ts +10 -1
  98. package/dist/src/env.js +11 -3
  99. package/dist/src/errors.d.ts +8 -8
  100. package/dist/src/errors.js +6 -6
  101. package/dist/src/flush.d.ts +12 -0
  102. package/dist/src/flush.js +37 -0
  103. package/dist/src/heartbeat.d.ts +86 -12
  104. package/dist/src/heartbeat.js +415 -29
  105. package/dist/src/index-background-watchdog.d.ts +1 -0
  106. package/dist/src/index-background-watchdog.js +94 -0
  107. package/dist/src/index-background-work.d.ts +21 -0
  108. package/dist/src/index-background-work.js +25 -0
  109. package/dist/src/index-background.d.ts +64 -0
  110. package/dist/src/index-background.js +394 -0
  111. package/dist/src/index-build-child.d.ts +1 -0
  112. package/dist/src/index-build-child.js +109 -0
  113. package/dist/src/index-manifest.d.ts +52 -0
  114. package/dist/src/index-manifest.js +444 -0
  115. package/dist/src/index-publication-proof.d.ts +84 -0
  116. package/dist/src/index-publication-proof.js +380 -0
  117. package/dist/src/index-publication-state.d.ts +149 -0
  118. package/dist/src/index-publication-state.js +696 -0
  119. package/dist/src/index-publication-verifier.d.ts +89 -0
  120. package/dist/src/index-publication-verifier.js +341 -0
  121. package/dist/src/index-publish.d.ts +62 -0
  122. package/dist/src/index-publish.js +540 -0
  123. package/dist/src/index-scratch-cleanup.d.ts +19 -0
  124. package/dist/src/index-scratch-cleanup.js +166 -0
  125. package/dist/src/index-segment-types.d.ts +132 -0
  126. package/dist/src/index-segment-types.js +21 -0
  127. package/dist/src/index-segments.d.ts +9 -0
  128. package/dist/src/index-segments.js +516 -0
  129. package/dist/src/index-store.d.ts +123 -0
  130. package/dist/src/index-store.js +495 -0
  131. package/dist/src/index-sync.d.ts +91 -15
  132. package/dist/src/index-sync.js +286 -53
  133. package/dist/src/index-upgrade-publication.d.ts +30 -0
  134. package/dist/src/index-upgrade-publication.js +179 -0
  135. package/dist/src/integration-manager.d.ts +32 -0
  136. package/dist/src/integration-manager.js +394 -0
  137. package/dist/src/leakscan.js +1 -1
  138. package/dist/src/local-api.d.ts +56 -15
  139. package/dist/src/local-api.js +4979 -541
  140. package/dist/src/machine-settings.d.ts +51 -0
  141. package/dist/src/machine-settings.js +166 -0
  142. package/dist/src/managed-chunks.d.ts +5 -2
  143. package/dist/src/managed-chunks.js +14 -14
  144. package/dist/src/mcp-install.d.ts +11 -9
  145. package/dist/src/mcp-install.js +73 -28
  146. package/dist/src/mcp-workspace.d.ts +18 -0
  147. package/dist/src/mcp-workspace.js +50 -0
  148. package/dist/src/mcp.js +294 -25
  149. package/dist/src/migrate.js +27 -21
  150. package/dist/src/notify.d.ts +1 -1
  151. package/dist/src/notify.js +5 -5
  152. package/dist/src/offload.d.ts +201 -14
  153. package/dist/src/offload.js +1848 -140
  154. package/dist/src/onboarding.d.ts +8 -1
  155. package/dist/src/onboarding.js +4 -4
  156. package/dist/src/packages.d.ts +2 -2
  157. package/dist/src/packages.js +10 -2
  158. package/dist/src/passkey.d.ts +0 -1
  159. package/dist/src/passkey.js +2 -7
  160. package/dist/src/password-lock.d.ts +2 -2
  161. package/dist/src/password-lock.js +6 -6
  162. package/dist/src/paths.d.ts +2 -0
  163. package/dist/src/paths.js +2 -0
  164. package/dist/src/presence.d.ts +86 -0
  165. package/dist/src/presence.js +240 -0
  166. package/dist/src/progress-deadline.d.ts +21 -0
  167. package/dist/src/progress-deadline.js +91 -0
  168. package/dist/src/project-repair.d.ts +55 -0
  169. package/dist/src/project-repair.js +131 -0
  170. package/dist/src/providers/gcs.d.ts +28 -7
  171. package/dist/src/providers/gcs.js +35 -24
  172. package/dist/src/providers/gdrive.d.ts +71 -8
  173. package/dist/src/providers/gdrive.js +223 -50
  174. package/dist/src/providers/index.d.ts +11 -3
  175. package/dist/src/providers/index.js +30 -10
  176. package/dist/src/providers/s3.d.ts +30 -8
  177. package/dist/src/providers/s3.js +41 -30
  178. package/dist/src/providers/safe-storage-fetch.d.ts +12 -0
  179. package/dist/src/providers/safe-storage-fetch.js +72 -0
  180. package/dist/src/queue.d.ts +136 -19
  181. package/dist/src/queue.js +862 -96
  182. package/dist/src/reclaim-transaction.d.ts +156 -0
  183. package/dist/src/reclaim-transaction.js +1027 -0
  184. package/dist/src/recovery-codes.d.ts +32 -0
  185. package/dist/src/recovery-codes.js +338 -0
  186. package/dist/src/recovery.js +12 -9
  187. package/dist/src/rehydrate.d.ts +25 -22
  188. package/dist/src/rehydrate.js +319 -23
  189. package/dist/src/restore.d.ts +57 -4
  190. package/dist/src/restore.js +272 -36
  191. package/dist/src/resume-stub.d.ts +92 -0
  192. package/dist/src/resume-stub.js +417 -0
  193. package/dist/src/retention.d.ts +98 -7
  194. package/dist/src/retention.js +1066 -62
  195. package/dist/src/rotate.js +3 -3
  196. package/dist/src/search.d.ts +566 -8
  197. package/dist/src/search.js +5897 -290
  198. package/dist/src/secrets.d.ts +51 -7
  199. package/dist/src/secrets.js +316 -24
  200. package/dist/src/service.d.ts +49 -11
  201. package/dist/src/service.js +776 -35
  202. package/dist/src/share.js +3 -3
  203. package/dist/src/shared-spaces.d.ts +98 -0
  204. package/dist/src/shared-spaces.js +214 -0
  205. package/dist/src/source-reader.d.ts +73 -0
  206. package/dist/src/source-reader.js +715 -0
  207. package/dist/src/spool.d.ts +1 -1
  208. package/dist/src/spool.js +1 -1
  209. package/dist/src/start-tui.js +2 -1
  210. package/dist/src/start.js +2 -2
  211. package/dist/src/storage-endpoint.d.ts +21 -0
  212. package/dist/src/storage-endpoint.js +122 -0
  213. package/dist/src/storage-setup.js +12 -12
  214. package/dist/src/storage-targets.d.ts +109 -6
  215. package/dist/src/storage-targets.js +975 -67
  216. package/dist/src/stream-to-cloud.d.ts +5 -1
  217. package/dist/src/stream-to-cloud.js +34 -14
  218. package/dist/src/sync-rules.d.ts +31 -6
  219. package/dist/src/sync-rules.js +153 -14
  220. package/dist/src/team-backfill-scheduling.d.ts +8 -0
  221. package/dist/src/team-backfill-scheduling.js +33 -0
  222. package/dist/src/team-backfill.d.ts +116 -0
  223. package/dist/src/team-backfill.js +1429 -0
  224. package/dist/src/team-index-cache.d.ts +16 -0
  225. package/dist/src/team-index-cache.js +152 -0
  226. package/dist/src/team-offboarding.d.ts +38 -0
  227. package/dist/src/team-offboarding.js +1043 -0
  228. package/dist/src/team-presence.d.ts +127 -0
  229. package/dist/src/team-presence.js +904 -0
  230. package/dist/src/team-publication-policy.d.ts +20 -0
  231. package/dist/src/team-publication-policy.js +140 -0
  232. package/dist/src/team-realtime.d.ts +68 -0
  233. package/dist/src/team-realtime.js +816 -0
  234. package/dist/src/team-source-facts-cache.d.ts +23 -0
  235. package/dist/src/team-source-facts-cache.js +255 -0
  236. package/dist/src/trash.d.ts +1 -1
  237. package/dist/src/trash.js +2 -2
  238. package/dist/src/tui.js +11 -12
  239. package/dist/src/types.d.ts +173 -7
  240. package/dist/src/types.js +20 -0
  241. package/dist/src/ui-server.d.ts +163 -35
  242. package/dist/src/ui-server.js +712 -72
  243. package/dist/src/ui.d.ts +1 -2
  244. package/dist/src/ui.js +1 -2
  245. package/dist/src/upload.d.ts +27 -0
  246. package/dist/src/upload.js +383 -43
  247. package/dist/src/vault.d.ts +226 -30
  248. package/dist/src/vault.js +1776 -192
  249. package/dist/src/watcher.d.ts +7 -1
  250. package/dist/src/watcher.js +198 -55
  251. package/dist/src/worker.d.ts +27 -3
  252. package/dist/src/worker.js +274 -55
  253. package/package.json +33 -12
  254. package/scripts/native-reboot-rehearsal.mjs +90 -0
  255. package/web/app.js +6032 -343
  256. package/web/bootstrap.js +17 -0
  257. package/web/index.html +255 -57
  258. package/web/rail.js +317 -40
  259. package/web/retention.html +2 -2
  260. package/web/rules-view.js +188 -16
  261. package/web/sessions-view.js +485 -62
  262. package/web/sessions.html +2 -2
  263. package/web/setup-api.js +152 -29
  264. package/web/setup-logic.js +68 -9
  265. package/web/setup.html +113 -44
  266. package/web/setup.js +604 -71
  267. package/web/style.css +513 -98
  268. package/dist/packages/vaultline-crypto/src/chunk-access.js +0 -93
  269. /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/aead.d.ts +0 -0
  270. /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/aead.js +0 -0
  271. /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/format.js +0 -0
  272. /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/recipients.d.ts +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
@@ -0,0 +1,20 @@
1
+ import { type ManagedIndexReceipt } from "./cloud.js";
2
+ export declare const TEAM_PUBLICATION_POLICY = 1;
3
+ type Identity = {
4
+ origin: string;
5
+ accountId: number;
6
+ vaultId: string;
7
+ };
8
+ export type TeamPublicationPolicyAttempt = Identity & {
9
+ spaceKey: string;
10
+ membershipVersion: number;
11
+ authGeneration: string | null;
12
+ };
13
+ export declare function teamPublicationPolicyCurrent(dataDir: string, attempt: TeamPublicationPolicyAttempt): Promise<boolean>;
14
+ /** Capture before native publication; an executable upgrade never fabricates a receipt. */
15
+ export declare function beginTeamPublicationPolicy(dataDir: string, spaceKey: string, membershipVersion: number, signal?: AbortSignal): Promise<TeamPublicationPolicyAttempt>;
16
+ /** Called only after native CAS read-back and exact local publication obligations succeed. */
17
+ export declare function completeTeamPublicationPolicy(dataDir: string, attempt: TeamPublicationPolicyAttempt, receipt: ManagedIndexReceipt, expectedCoverage: Readonly<Record<string, string>>, requiredRefs: Iterable<string>, signal?: AbortSignal): Promise<void>;
18
+ /** Runs on the independent indexing lane. Failed checks remain pending for its bounded retry. */
19
+ export declare function teamPublicationPolicyNeedsUpgrade(dataDir: string): Promise<boolean>;
20
+ export {};
@@ -0,0 +1,140 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { mkdir, open, readFile, rename, rm } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { accountStatus, cloudAuthGeneration, cloudUrl, getTeamRoster } from "./cloud.js";
5
+ import { readConfig } from "./vault.js";
6
+ import { withProgressDeadline } from "./progress-deadline.js";
7
+ import { fail } from "./errors.js";
8
+ // Separate from extraction and per-archive retention ledger versions. A code
9
+ // correction to scoped catalog selection must also reach fully indexed vaults.
10
+ export const TEAM_PUBLICATION_POLICY = 1;
11
+ const directory = (dataDir) => join(dataDir, "index", "team-publication-policy");
12
+ const hash = (value) => createHash("sha256").update(JSON.stringify(value)).digest("hex");
13
+ const key = (attempt) => hash([
14
+ attempt.origin, attempt.accountId, attempt.vaultId, attempt.spaceKey, attempt.membershipVersion,
15
+ ]);
16
+ const pathFor = (dataDir, attempt) => join(directory(dataDir), `${key(attempt)}.json`);
17
+ const coverageDigest = (coverage) => hash(Object.entries(coverage).sort(([a], [b]) => a.localeCompare(b)));
18
+ async function identity(dataDir, signal) {
19
+ const origin = cloudUrl();
20
+ const authGeneration = await cloudAuthGeneration(dataDir);
21
+ const vaultId = (await readConfig(dataDir)).vaultId;
22
+ const account = await accountStatus(dataDir, undefined, { signal, renewToken: false });
23
+ if (!Number.isSafeInteger(account.id) || account.id <= 0)
24
+ fail("cloud_account_unavailable", "Cannot identify the current publication account");
25
+ if (cloudUrl() !== origin || await cloudAuthGeneration(dataDir) !== authGeneration
26
+ || (await readConfig(dataDir)).vaultId !== vaultId)
27
+ fail("cloud_account_unavailable", "The publication account changed; retry safely");
28
+ return { origin, accountId: account.id, vaultId, authGeneration };
29
+ }
30
+ export async function teamPublicationPolicyCurrent(dataDir, attempt) {
31
+ try {
32
+ const raw = await readFile(pathFor(dataDir, attempt), "utf8");
33
+ if (raw.length > 16_384)
34
+ return false;
35
+ const value = JSON.parse(raw);
36
+ return value.version === 1 && value.policy === TEAM_PUBLICATION_POLICY && value.scope === key(attempt)
37
+ && value.state === "complete" && Number.isSafeInteger(value.revision) && value.revision > 0
38
+ && typeof value.generationId === "string" && /^[a-f0-9]{64}$/.test(value.coverageDigest)
39
+ && /^[a-f0-9]{64}$/.test(value.ciphertextSha256);
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ async function ensurePending(dataDir, attempt) {
46
+ if (await teamPublicationPolicyCurrent(dataDir, attempt))
47
+ return;
48
+ await mkdir(directory(dataDir), { recursive: true, mode: 0o700 });
49
+ let file;
50
+ try {
51
+ file = await open(pathFor(dataDir, attempt), "wx", 0o600);
52
+ }
53
+ catch (error) {
54
+ if (error.code === "EEXIST")
55
+ return;
56
+ throw error;
57
+ }
58
+ try {
59
+ await file.writeFile(JSON.stringify({ version: 1, policy: TEAM_PUBLICATION_POLICY, scope: key(attempt), state: "pending" }) + "\n");
60
+ await file.sync();
61
+ }
62
+ finally {
63
+ await file.close();
64
+ }
65
+ }
66
+ /** Capture before native publication; an executable upgrade never fabricates a receipt. */
67
+ export async function beginTeamPublicationPolicy(dataDir, spaceKey, membershipVersion, signal) {
68
+ return withProgressDeadline("Preparing shared index policy migration", 15_000, signal, async (bounded) => {
69
+ const attempt = { ...await identity(dataDir, bounded), spaceKey, membershipVersion };
70
+ await ensurePending(dataDir, attempt);
71
+ return attempt;
72
+ });
73
+ }
74
+ /** Called only after native CAS read-back and exact local publication obligations succeed. */
75
+ export async function completeTeamPublicationPolicy(dataDir, attempt, receipt, expectedCoverage, requiredRefs, signal) {
76
+ if (receipt.membershipVersion !== attempt.membershipVersion
77
+ || coverageDigest(receipt.coverageJson) !== coverageDigest(expectedCoverage)
78
+ || [...requiredRefs].some((ref) => !Object.hasOwn(receipt.coverageJson, ref))) {
79
+ fail("ciphertext_integrity_failed", "The current shared index policy has not covered its required grants");
80
+ }
81
+ await withProgressDeadline("Confirming shared index policy migration", 15_000, signal, async (bounded) => {
82
+ const current = await identity(dataDir, bounded);
83
+ const roster = await getTeamRoster(dataDir, attempt.spaceKey, undefined, { signal: bounded, renewToken: false });
84
+ if (key({ ...current, spaceKey: attempt.spaceKey, membershipVersion: roster.membership_version }) !== key(attempt)
85
+ || current.authGeneration !== attempt.authGeneration || await cloudAuthGeneration(dataDir) !== attempt.authGeneration) {
86
+ fail("team_state_changed", "Shared index policy migration changed scope; retry in the current account and team");
87
+ }
88
+ await mkdir(directory(dataDir), { recursive: true, mode: 0o700 });
89
+ const target = pathFor(dataDir, attempt);
90
+ const temporary = `${target}.${randomUUID()}.tmp`;
91
+ try {
92
+ const file = await open(temporary, "wx", 0o600);
93
+ try {
94
+ await file.writeFile(JSON.stringify({ version: 1, policy: TEAM_PUBLICATION_POLICY, scope: key(attempt), state: "complete",
95
+ revision: receipt.revision, generationId: receipt.generationId, coverageDigest: coverageDigest(receipt.coverageJson),
96
+ ciphertextSha256: receipt.blob.sha256, committedAt: receipt.committedAt }) + "\n");
97
+ await file.sync();
98
+ }
99
+ finally {
100
+ await file.close();
101
+ }
102
+ bounded.throwIfAborted();
103
+ if (cloudUrl() !== attempt.origin || await cloudAuthGeneration(dataDir) !== attempt.authGeneration
104
+ || (await readConfig(dataDir)).vaultId !== attempt.vaultId) {
105
+ fail("cloud_account_unavailable", "Publication sign-in changed before its policy receipt was saved");
106
+ }
107
+ await rename(temporary, target);
108
+ }
109
+ finally {
110
+ await rm(temporary, { force: true }).catch(() => undefined);
111
+ }
112
+ });
113
+ }
114
+ /** Runs on the independent indexing lane. Failed checks remain pending for its bounded retry. */
115
+ export async function teamPublicationPolicyNeedsUpgrade(dataDir) {
116
+ const config = await readConfig(dataDir);
117
+ const spaces = [...new Set(Object.values(config.teamSpaces ?? {}).map((binding) => binding.spaceKey))];
118
+ if (!spaces.length)
119
+ return false;
120
+ try {
121
+ return await withProgressDeadline("Checking shared index publication policy", 15_000, undefined, async (signal) => {
122
+ const current = await identity(dataDir, signal);
123
+ let pending = false;
124
+ for (const spaceKey of spaces) {
125
+ const roster = await getTeamRoster(dataDir, spaceKey, undefined, { signal, renewToken: false });
126
+ const attempt = { ...current, spaceKey, membershipVersion: roster.membership_version };
127
+ if (!await teamPublicationPolicyCurrent(dataDir, attempt)) {
128
+ await ensurePending(dataDir, attempt);
129
+ pending = true;
130
+ }
131
+ }
132
+ if (await cloudAuthGeneration(dataDir) !== current.authGeneration || cloudUrl() !== current.origin)
133
+ return true;
134
+ return pending;
135
+ });
136
+ }
137
+ catch {
138
+ return true;
139
+ }
140
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Push wake-ups for encrypted cross-account presence.
3
+ *
4
+ * REST remains the durable append log and cursor catch-up path. The daemon
5
+ * keeps one Socket.IO connection per machine, multiplexes every locally bound
6
+ * opaque team-space id over it, and writes received ciphertext rows to a
7
+ * bounded local inbox. Agent hooks read that inbox at tool boundaries, so a
8
+ * busy team does not turn "is anyone already touching this?" into continuous
9
+ * HTTP polling.
10
+ *
11
+ * No user setting is involved: the realtime origin/path are derived from the
12
+ * same hosted API URL the signed-in client already uses, and the bearer stays
13
+ * in the native keystore/in-memory Socket.IO handshake.
14
+ */
15
+ import { type TeamPresenceRow } from "./cloud.js";
16
+ import type { BackendName } from "./secrets.js";
17
+ export type TeamRealtimeStatus = {
18
+ version: 1;
19
+ connected: boolean;
20
+ updatedAt: string;
21
+ subscribedSpaces: string[];
22
+ /** Changes on every successful connection, so hooks know to run one durable catch-up. */
23
+ connectionId?: string;
24
+ lastError?: string;
25
+ };
26
+ export type TeamRealtimeListener = {
27
+ /** Resolves after every space present at startup has an acknowledged subscription. */
28
+ ready: Promise<void>;
29
+ refresh(): Promise<void>;
30
+ close(): Promise<void>;
31
+ status(): TeamRealtimeStatus;
32
+ };
33
+ export type TeamRealtimeRows = {
34
+ rows: TeamPresenceRow[];
35
+ cursor: number;
36
+ gap: boolean;
37
+ };
38
+ /**
39
+ * Cache one validated wire row in its own immutable file. This is O(event),
40
+ * not O(all spaces × inbox size), and atomic hard links make overlapping daemon handoffs
41
+ * converge on the first complete row instead of overwriting one another.
42
+ */
43
+ export declare function cacheRealtimeTeamPresence(dataDir: string, spaceKey: string, value: unknown): Promise<boolean>;
44
+ /** Read only local ciphertext rows newer than a durable cursor. */
45
+ export declare function readRealtimeTeamPresence(dataDir: string, spaceKey: string, after: number): Promise<TeamRealtimeRows>;
46
+ export declare function teamRealtimeChannel(routeKey: string): string;
47
+ export declare function teamRealtimeEndpoint(env?: NodeJS.ProcessEnv): {
48
+ origin: string;
49
+ path: string;
50
+ };
51
+ export declare function readTeamRealtimeStatus(dataDir: string): Promise<TeamRealtimeStatus | null>;
52
+ export declare function teamRealtimeStatusHealthy(status: TeamRealtimeStatus | null, spaceKey: string, options?: {
53
+ now?: number;
54
+ maxAgeMs?: number;
55
+ }): boolean;
56
+ export declare function teamRealtimeHealthy(dataDir: string, spaceKey: string, options?: {
57
+ now?: number;
58
+ maxAgeMs?: number;
59
+ }): Promise<boolean>;
60
+ /**
61
+ * Start the package-owned machine listener. It is deliberately fail-open:
62
+ * missing sign-in, no team spaces, network failures, and auth expiry leave the
63
+ * durable REST path intact and never stop the preservation daemon.
64
+ */
65
+ export declare function startTeamRealtime(dataDir: string, options?: {
66
+ preferred?: BackendName;
67
+ refreshMs?: number;
68
+ }): Promise<TeamRealtimeListener>;