sealkeep 0.8.1 → 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 (275) hide show
  1. package/ARCHITECTURE.md +163 -14
  2. package/CHANGELOG.md +244 -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 +1746 -166
  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.d.ts +1 -0
  150. package/dist/src/migrate.js +33 -5
  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 +5897 -290
  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 +235 -29
  249. package/dist/src/vault.js +1783 -190
  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/recipients.d.ts +0 -0
  274. /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/sha256-stream.d.ts +0 -0
  275. /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/sha256-stream.js +0 -0
@@ -1,3 +1,28 @@
1
+ /**
2
+ * The GUI, reachable without typing a command.
3
+ *
4
+ * PRODUCT_ARCHITECTURE.md §5: the terminal is the free tier's interface, not
5
+ * the product's. `src/local-api.ts` already serves the settings surface and
6
+ * `web/` already draws it — what was missing was a way to get a browser
7
+ * pointed at it, authenticated, without a person copying a token by hand.
8
+ *
9
+ * This module is the plumbing for that and nothing else. It starts (or finds)
10
+ * the loopback server, mints a short-lived one-use browser ticket, and launches
11
+ * a browser. Every line printed to a terminal lives in cli.ts, so this stays
12
+ * usable by any surface that is not a terminal — the native shell in §5 v2
13
+ * being the obvious one.
14
+ */
15
+ declare const LOOPBACK_HOST = "127.0.0.1";
16
+ /**
17
+ * `taskpolicy -B` is PID-only on macOS. Its supported command form is `-a`,
18
+ * which gives the child application scheduling/resource policy instead of
19
+ * inheriting an old service definition's background policy. Keep both paths
20
+ * argument-vector based: no shell parses a PID or command.
21
+ */
22
+ export declare function uiPsIdentityCommand(pid: number, targetPlatform?: NodeJS.Platform): {
23
+ file: string;
24
+ args: string[];
25
+ };
1
26
  /**
2
27
  * The name to show a person, as opposed to the address to bind.
3
28
  *
@@ -24,8 +49,6 @@ export declare const DISPLAY_HOST = "localhost";
24
49
  * window on an odd port beats a correct error.
25
50
  */
26
51
  export declare const DEFAULT_UI_PORT = 7477;
27
- /** The hostnames this service answers to, mirrored by ALLOWED_HOSTS in local-api.ts. */
28
- export declare const UI_HOSTNAMES: readonly ["localhost", "127.0.0.1", "vault.line", "vault.localhost"];
29
52
  /**
30
53
  * Where a running server announces itself, so a second `sealkeep ui` finds it.
31
54
  *
@@ -35,31 +58,50 @@ export declare const UI_HOSTNAMES: readonly ["localhost", "127.0.0.1", "vault.li
35
58
  * else in there rather than being the one loose file.
36
59
  */
37
60
  export declare const uiRecordPath: (dataDir: string) => string;
61
+ export type UiOwner = "interactive" | "autopilot";
38
62
  export type UiRecord = {
39
63
  port: number;
40
64
  pid: number;
41
65
  startedAt: string;
66
+ /** Who owns the listener lifecycle. Absent means an older interactive build. */
67
+ owner?: UiOwner;
68
+ /** The stable port this listener attempted before any collision fallback. */
69
+ requestedPort?: number;
70
+ /** Per-listener generation. Required for authenticated adoption and exact cleanup. */
71
+ instanceId?: string;
72
+ /** Kernel process generation; unlike pid, this is not reused after a crash. */
73
+ processIdentity?: string;
42
74
  };
43
75
  /** Anything unreadable, truncated, or not describing a usable port reads as "no server", never as an error. */
44
76
  export declare function readUiRecord(dataDir: string): Promise<UiRecord | null>;
45
77
  /**
46
- * Written in place rather than through a temp file and a rename: a half-written
47
- * record fails to parse, and failing to parse already means "start a fresh
48
- * server", which is the safe answer. Atomicity would buy nothing.
78
+ * Atomically published: a reader sees either the preceding complete owner or
79
+ * the next complete owner, never a truncated file that could start a second
80
+ * mutating API server.
49
81
  */
50
82
  export declare function writeUiRecord(dataDir: string, record: UiRecord): Promise<void>;
51
83
  /**
52
- * Removes the record only when it still names this server's port. Two servers
53
- * can exist at once (a second one starts whenever the first is unreachable),
54
- * and the first to shut down must not delete the survivor's announcement.
84
+ * Removes the record only when it still names this exact listener generation.
85
+ * A closing old process must not delete a replacement's announcement.
55
86
  */
56
- export declare function clearUiRecord(dataDir: string, port?: number): Promise<void>;
87
+ export declare function clearUiRecord(dataDir: string, port?: number, instanceId?: string): Promise<void>;
88
+ export type ProcessIdentityLookupResult = {
89
+ state: "identified";
90
+ identity: string;
91
+ } | {
92
+ state: "dead";
93
+ } | {
94
+ state: "unknown";
95
+ };
96
+ export type ProcessIdentityLookup = (pid: number) => Promise<ProcessIdentityLookupResult>;
97
+ export declare const uiProcessIdentity: ProcessIdentityLookup;
57
98
  /** Where a person goes. Bound on loopback, named so it can be read and typed. */
58
99
  export declare const uiOrigin: (port: number, host?: string) => string;
59
100
  /** Where this process talks to itself. Always the address, never a name that has to resolve. */
60
101
  export declare const uiProbeOrigin: (port: number) => string;
61
102
  /**
62
- * How the browser gets authenticated: the token rides in the URL fragment.
103
+ * How the browser gets authenticated: a short-lived one-use ticket rides in
104
+ * the URL fragment; the permanent bearer never enters opener argv.
63
105
  *
64
106
  * A fragment is the only part of a URL a browser never transmits. It is not in
65
107
  * the request line, so it cannot reach an access log, a proxy, or a Referer
@@ -72,14 +114,10 @@ export declare const uiProbeOrigin: (port: number) => string;
72
114
  * is the terminal step this whole command exists to remove, and it puts the
73
115
  * secret in scrollback, in `script` logs, and in any pasted transcript.
74
116
  *
75
- * What this does cost: the URL is an argv of the opener process, so it is
76
- * visible to `ps` for the few milliseconds that process lives. That is
77
- * accepted rather than overlooked — the token grants nothing that a local
78
- * process running as this user does not already have, since it can read
79
- * <data-dir>/local-api-token directly. Scrollback is the leak that outlives
80
- * the session; argv is not.
117
+ * The ticket is visible briefly in opener argv, but it expires after seconds,
118
+ * is redeemable once, and can only be minted through the owner-only proof key.
81
119
  */
82
- export declare const uiUrl: (port: number, token: string) => string;
120
+ export declare const uiUrl: (port: number, ticket: string) => string;
83
121
  export type BrowserResult = {
84
122
  opened: boolean;
85
123
  /** The opener that ran, for a message that names what failed rather than "something went wrong". */
@@ -128,17 +166,18 @@ export declare function openInBrowser(url: string, options?: {
128
166
  graceMs?: number;
129
167
  }): Promise<BrowserResult>;
130
168
  /**
131
- * Is a Sealkeep local API still listening on `port`, and is it *this* vault's?
132
- *
133
- * Two questions, because a recorded port answers neither. A port is reused by
134
- * whatever process grabs it next, so `/health` first establishes that the
135
- * listener is one of ours at all. Then a `/v1/status` call carrying this
136
- * vault's token establishes that it reads the same token file — that is, that
137
- * it serves this data dir and not a second vault's. 401 is the only answer
138
- * that means "not this vault": every other status got past the token check,
139
- * including the 404 a data dir with no vault yet would return.
169
+ * Is this exact listener generation serving this vault?
170
+ *
171
+ * The request contains only a fresh nonce. The listener signs that nonce plus
172
+ * its server-observed port and generation with an owner-only key. A stale or
173
+ * hostile process can neither learn the API bearer nor relay a genuine
174
+ * listener's answer from another port.
140
175
  */
141
- export declare function servesThisVault(port: number, token: string, fetchImpl?: typeof fetch): Promise<boolean>;
176
+ export type UiProbeCredentials = {
177
+ proofKey: string;
178
+ instanceId: string;
179
+ };
180
+ export declare function servesThisVault(port: number, credentials: UiProbeCredentials, fetchImpl?: typeof fetch): Promise<boolean>;
142
181
  export type UiHandle = {
143
182
  port: number;
144
183
  origin: string;
@@ -149,17 +188,27 @@ export type UiHandle = {
149
188
  * the URL happens to be spelled.
150
189
  */
151
190
  address: string;
152
- /** The full URL including the token fragment. Print it only when no browser could be opened. */
191
+ /** The full URL including the one-use ticket. Print it only when no browser could be opened. */
153
192
  url: string;
154
193
  /** True when an already-running server was reused; nothing new was started and close() is a no-op. */
155
194
  reused: boolean;
156
195
  /** Set when reused, so a caller can say who owns the server it just pointed at. */
157
196
  running: UiRecord | null;
197
+ /** Exact listener generation; cleanup and supervisor status never match on port alone. */
198
+ instanceId: string;
199
+ /**
200
+ * Authoritative only for a listener created by this handle. A supervisor
201
+ * must not tear down its own healthy server merely because a large vault
202
+ * request kept the event loop busy longer than the loopback probe timeout.
203
+ * Reused handles deliberately return false: their owner still has to be
204
+ * verified over the authenticated health endpoint.
205
+ */
206
+ isListening: () => boolean;
158
207
  browser: BrowserResult;
159
208
  close: () => Promise<void>;
160
209
  };
161
210
  export type UiOptions = {
162
- /** 0 — the default — asks the OS for an ephemeral port, so two vaults never fight over one. */
211
+ /** Defaults to stable 7477; 0 explicitly asks the OS for an ephemeral port. */
163
212
  port?: number;
164
213
  /** False for a headless surface that serves the API but has no window to open. */
165
214
  openBrowser?: boolean;
@@ -167,13 +216,14 @@ export type UiOptions = {
167
216
  open?: (url: string) => Promise<BrowserResult>;
168
217
  /** Injected by tests that need to control what the reuse probe sees. */
169
218
  fetchImpl?: typeof fetch;
170
- /**
171
- * False for `sealkeep api`, whose port is a stable address other tools are
172
- * pointed at — handing it back an ephemeral one because a window happened to
173
- * be open would break the thing that makes it useful. It still announces
174
- * itself, so a later `sealkeep ui` finds it rather than starting a second.
175
- */
219
+ /** Legacy compatibility only; false no longer bypasses singleton ownership. */
176
220
  reuse?: boolean;
221
+ /** Recorded lifecycle owner; it never changes the loopback or auth policy. */
222
+ owner?: UiOwner;
223
+ /** True means a daemon is waiting to take queue/worker ownership after unlock. */
224
+ onRecoveryPhraseAvailable?: () => boolean;
225
+ /** Test seam for process-generation lookup failures. */
226
+ processIdentityLookup?: ProcessIdentityLookup;
177
227
  };
178
228
  /**
179
229
  * Starts the local UI, or points at the one already running for this vault.
@@ -185,3 +235,81 @@ export type UiOptions = {
185
235
  * what someone typing the command twice actually meant.
186
236
  */
187
237
  export declare function startUi(dataDir: string, options?: UiOptions): Promise<UiHandle>;
238
+ /**
239
+ * Runtime evidence for the background service's UI lane.
240
+ *
241
+ * This is deliberately state, not preference: `daemon --serve-ui` in the
242
+ * native service definition is the preference. This owner-only record merely
243
+ * says which process is supervising the listener now, where it actually
244
+ * landed after a port collision, and why it is retrying if it could not bind.
245
+ */
246
+ export declare const uiSupervisorPath: (dataDir: string) => string;
247
+ export type UiSupervisorRecord = {
248
+ version: 1;
249
+ instanceId: string;
250
+ pid: number;
251
+ processIdentity: string;
252
+ state: "starting" | "running" | "retrying" | "off";
253
+ requestedPort: number;
254
+ port: number | null;
255
+ listenerPid: number | null;
256
+ listenerOwner: UiOwner | null;
257
+ listenerInstanceId: string | null;
258
+ ownsListener: boolean;
259
+ startedAt: string;
260
+ checkedAt: string;
261
+ nextRetryAt: string | null;
262
+ lastError: string | null;
263
+ };
264
+ export type UiRuntimeStatus = {
265
+ supervised: boolean;
266
+ available: boolean;
267
+ state: "off" | "running" | "retrying";
268
+ requestedPort: number;
269
+ port: number | null;
270
+ /** Actual reachable loopback URL. It never contains the local bearer token. */
271
+ origin: string | null;
272
+ address: typeof LOOPBACK_HOST | null;
273
+ fallback: boolean;
274
+ supervisorPid: number | null;
275
+ listenerPid: number | null;
276
+ listenerOwner: UiOwner | null;
277
+ checkedAt: string | null;
278
+ nextRetryAt: string | null;
279
+ lastError: string | null;
280
+ };
281
+ /** Live truth for CLI/setup status; stale pid/record files never count as available. */
282
+ export declare function uiRuntimeStatus(dataDir: string, options?: {
283
+ fetchImpl?: typeof fetch;
284
+ processIdentityLookup?: ProcessIdentityLookup;
285
+ }): Promise<UiRuntimeStatus>;
286
+ export type UiSupervisor = {
287
+ /** True only for the generation holding the per-vault supervisor lease. */
288
+ owned: boolean;
289
+ /** Ask the supervisor to verify or repair its listener immediately. */
290
+ refresh(): Promise<UiRuntimeStatus>;
291
+ status(): Promise<UiRuntimeStatus>;
292
+ /** Stops only a listener this supervisor created; a reused interactive UI remains open. */
293
+ close(): Promise<void>;
294
+ };
295
+ export type UiSupervisorOptions = {
296
+ port?: number;
297
+ retryMs?: number;
298
+ fetchImpl?: typeof fetch;
299
+ /** Test seam; production always reuses startUi. */
300
+ start?: typeof startUi;
301
+ /** True means this service will own the worker once the phrase becomes available. */
302
+ onRecoveryPhraseAvailable?: () => boolean;
303
+ /** Test seam for process-generation lookup failures. */
304
+ processIdentityLookup?: ProcessIdentityLookup;
305
+ };
306
+ /**
307
+ * Keeps one authenticated loopback UI available beside Autopilot.
308
+ *
309
+ * It opens no window. A live UI already serving this vault is reused and
310
+ * watched; if that owner later exits, the next bounded check replaces it. An
311
+ * unrelated process on 7477 is never adopted: startUi falls back to a free
312
+ * loopback port and the exact port is written to both runtime records.
313
+ */
314
+ export declare function startUiSupervisor(dataDir: string, options?: UiSupervisorOptions): Promise<UiSupervisor>;
315
+ export {};