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,17 @@
1
+ // A same-origin, top-level navigation has already passed the server's Fetch
2
+ // Metadata checks. Preserve its view fragment before replacing it with the
3
+ // short-lived sign-in ticket. Never put that ticket in a query string.
4
+ (() => {
5
+ const ticket = document.body.dataset.bootstrapTicket;
6
+ const target = new URL(document.body.dataset.bootstrapTarget, location.origin);
7
+ if (!ticket || target.origin !== location.origin || !['/index.html', '/setup.html'].includes(target.pathname)) return;
8
+ const raw = location.hash.replace(/^#/, '');
9
+ const previous = new URLSearchParams(raw);
10
+ const view = previous.has('ticket') ? previous.get('view') || '' : raw;
11
+ const safeView = view.length <= 1024 && /^(?:overview|sessions|queue|archives|restore|retention|rules|settings|health|live|shared(?:\?project=[A-Za-z0-9%._~-]+)?|cleanup-review|recovery-access|agent-settings|resource-settings|cleanup-settings|recovery-kit|recovery-phrase|automatic-archiving|google-drive|storage-targets)$/.test(view);
12
+ const fragment = new URLSearchParams({ ticket });
13
+ if (safeView) fragment.set('view', view);
14
+ target.hash = fragment.toString();
15
+ document.body.removeAttribute('data-bootstrap-ticket');
16
+ location.replace(target.href);
17
+ })();
package/web/index.html CHANGED
@@ -55,7 +55,10 @@
55
55
  </head>
56
56
  <body>
57
57
  <aside>
58
- <div class="brand"><span>⌑</span>Sealkeep</div>
58
+ <div class="brand-block">
59
+ <div class="brand"><span>⌑</span>Sealkeep</div>
60
+ <div class="surface-refresh" id="rail-refresh-state" role="status" aria-live="polite" hidden><span class="surface-spinner"></span>Updating</div>
61
+ </div>
59
62
 
60
63
  <!-- The identity strip is always first (design-system: components/cards.html):
61
64
  who this vault belongs to, what they pay for, and how much of it is used —
@@ -73,6 +76,7 @@
73
76
  <li id="acct-phrase"><span class="dot"></span><span class="acct-fact-text" id="acct-phrase-text">—</span></li>
74
77
  <li id="acct-storage"><span class="dot"></span><span class="acct-fact-text" id="acct-storage-text">—</span></li>
75
78
  <li id="acct-disk"><span class="dot"></span><span class="acct-fact-text" id="acct-disk-text">—</span></li>
79
+ <li id="acct-escrow" hidden><span class="dot"></span><span class="acct-fact-text" id="acct-escrow-text">—</span></li>
76
80
  </ul>
77
81
  <div class="acct-door-slot" id="acct-door-slot"></div>
78
82
  </div>
@@ -83,14 +87,16 @@
83
87
  between "pick what to archive" and anywhere else a full reload. The
84
88
  list mounts on first entry and stays mounted — switching back is
85
89
  instant. -->
86
- <button data-view="sessions"><span class="glyph">◱</span>Memory pool</button>
87
- <button data-view="queue"><span class="glyph">◴</span>Queue<span class="count" id="count-queue"></span></button>
90
+ <button data-view="sessions"><span class="glyph">◱</span>Sessions</button>
91
+ <button data-view="queue"><span class="glyph">◴</span>Backup activity<span class="count" id="count-queue"></span></button>
88
92
  <button data-view="archives"><span class="glyph">▣</span>My vault<span class="count" id="count-archives"></span></button>
93
+ <button data-view="live"><span class="glyph">◉</span>Live</button>
94
+ <button data-view="shared"><span class="glyph">◎</span>Shared projects</button>
95
+ <button data-view="health"><span class="glyph">⚙</span>Health<span class="count" id="count-health"></span></button>
89
96
  <button data-view="settings"><span class="glyph">◧</span>Settings</button>
90
97
  <!-- Badged like Queue and Archives. It was the one nav item without a
91
98
  count, on a product where "if this machine is lost, so is every
92
99
  archive on it" is a Health warning. -->
93
- <button data-view="health"><span class="glyph">⚙</span>Health<span class="count" id="count-health"></span></button>
94
100
  </nav>
95
101
 
96
102
  <div class="privacy">
@@ -101,29 +107,35 @@
101
107
 
102
108
  <main>
103
109
  <header>
104
- <h1 id="headline">Your agent history</h1>
110
+ <div class="headline-row">
111
+ <h1 id="headline">Your agent history</h1>
112
+ <div class="surface-refresh" id="page-refresh-state" role="status" aria-live="polite" hidden><span class="surface-spinner"></span>Updating</div>
113
+ </div>
105
114
  <p class="lede" id="lede">Reading live state from the Sealkeep agent on this machine.</p>
106
115
  <p class="pill busy" id="connection">Connecting</p>
107
116
  <p class="pill" id="daemon" hidden></p>
108
117
  </header>
109
118
 
110
119
  <section id="gate" class="panel gate pad" hidden>
111
- <h2>Local token required</h2>
112
- <p class="note">This browser has not been given its key yet. Paste the token from <code id="token-path">local-api-token</code> in your Sealkeep data folder (<code>~/.sealkeep</code>, or <code>~/.vaultline</code> for older vaults) — a local file, so nothing here is sent anywhere. The browser <code>sealkeep ui</code> opened is signed in already.</p>
120
+ <h2>Open Sealkeep securely</h2>
121
+ <p class="note">Confirm that you want this tab to open this computer's Sealkeep dashboard. Your recovery key stays on this computer; nothing needs to be pasted.</p>
122
+ <a id="gate-open-local" class="primary" href="./index.html?open_local=1">Open this computer's dashboard</a>
113
123
  <form id="token-form">
114
- <input id="token-input" type="password" autocomplete="off" spellcheck="false" placeholder="local API token" aria-label="Local API token">
115
- <button type="submit" class="action">Connect</button>
124
+ <button type="submit" class="action">Ask another Sealkeep tab for access</button>
116
125
  </form>
117
126
  <p id="gate-error" class="error" hidden></p>
118
127
  </section>
119
128
 
120
129
  <div id="app" hidden>
121
130
  <section id="view-overview" class="view">
131
+ <div id="home-decisions" class="home-decisions" aria-label="Backup, disk and recovery status"><p class="note">Checking backup status. Your existing files are unchanged.</p></div>
132
+ <details class="page-details">
133
+ <summary>Storage totals and technical details</summary>
122
134
  <div class="metrics">
123
135
  <div class="metric"><h3>Sessions preserved</h3><b id="m-archives">–</b><small id="m-bytes"></small></div>
124
136
  <div class="metric"><h3>Waiting</h3><b id="m-queue">–</b><small id="m-queue-detail"></small></div>
125
137
  <div class="metric"><h3>Off this machine</h3><b id="m-remote" class="small">–</b><small id="m-remote-hint"></small></div>
126
- <div class="metric"><h3>Disk you can reclaim</h3><b id="m-reclaim">–</b><small id="m-policy"></small></div>
138
+ <div class="metric"><h3>Originals eligible for cleanup</h3><b id="m-reclaim">–</b><small id="m-policy"></small></div>
127
139
  </div>
128
140
 
129
141
  <!-- The signature device: the same rule the product is named after, with live numbers on both sides. -->
@@ -133,8 +145,11 @@
133
145
  <span class="side sealed" id="boundary-below"></span>
134
146
  </div>
135
147
  <p class="note" id="boundary-note">Everything below this line is ciphertext. Nothing above it leaves this machine.</p>
148
+ <p class="note">Sessions are conversations. A conversation can have several archive versions. Versioned source history is not the amount currently occupying your disk.</p>
149
+ </details>
136
150
 
137
- <h2>Agents</h2>
151
+ <h2>Detected agent folders</h2>
152
+ <p class="note">Finding a folder does not confirm that memory capture or search is working. <a href="#health">Check agent memory connections</a>.</p>
138
153
  <div class="panel" id="agents"></div>
139
154
  </section>
140
155
 
@@ -149,8 +164,8 @@
149
164
  <p class="note" id="retention-summary"></p>
150
165
  </div>
151
166
  <div class="actions">
152
- <button id="upload" class="action" type="button">Upload pending</button>
153
- <button id="reclaim" class="action danger" type="button" disabled>Move sources to trash</button>
167
+ <button id="upload" class="action" type="button">Send waiting archives</button>
168
+ <button id="reclaim" class="action danger" type="button" disabled>Free up disk</button>
154
169
  </div>
155
170
  </div>
156
171
  <div id="upload-progress" hidden>
@@ -160,10 +175,19 @@
160
175
  <button id="upload-cancel" class="action" type="button">Stop after this archive</button>
161
176
  </div>
162
177
  </div>
163
- <p class="note">The button reclaims what the rules allow: a verified remote copy, the grace period passed, nothing using the file. Any vault row can also do it one at a time. Reclaimed files go to your trash — Sealkeep never deletes.</p>
178
+ <p class="note">The button permanently removes only originals whose exact remote copy and search entry are ready, grace period has passed, bytes are unchanged, and no agent is using the file. Encrypted archives remain available; Codex keeps a tiny same-session resume pointer.</p>
164
179
  <p class="note"><a href="#rules">Edit the rules that decide what becomes eligible →</a></p>
165
180
  </div>
166
181
  <div class="panel pad" id="automation-panel" style="margin-top:var(--gap)" hidden></div>
182
+ <div class="panel pad callout warn" id="queue-attention" style="margin-top:var(--gap)" role="status" hidden>
183
+ <div class="row">
184
+ <div>
185
+ <h3 id="queue-attention-title">Automatic archiving needs attention</h3>
186
+ <p class="note" id="queue-attention-detail"></p>
187
+ </div>
188
+ <a class="action" id="queue-attention-action" href="#automatic-archiving">Fix automatic archiving</a>
189
+ </div>
190
+ </div>
167
191
  <div class="panel" id="queue-panel" style="margin-top:var(--gap)"></div>
168
192
  </section>
169
193
 
@@ -171,84 +195,143 @@
171
195
  <!-- The library: folders of sessions, every verb on its row. The
172
196
  automatic side (uploads, rules-driven reclaim) lives with the Queue,
173
197
  where work in motion belongs. -->
198
+ <p class="vault-refresh loading" id="archive-refresh-state" role="status" aria-live="polite" hidden></p>
174
199
  <div class="panel" id="archives-panel"></div>
175
200
  <div class="panel pad" style="margin-top:var(--gap)">
176
- <p class="note"><b>If this machine is lost:</b> your recovery phrase plus <code>sealkeep cloud login</code> on any machine reaches every copy in managed storage. The phrase is the only key — no copy anywhere can be opened without it.</p>
201
+ <p class="note"><b>If this machine is lost:</b> sign in to your Sealkeep account and unlock your vault with your recovery phrase or a usable Recovery Kit backup code. Account sign-in alone cannot decrypt your archives. Google Drive sign-in alone cannot rediscover Drive-only archives; restoring those also needs Sealkeep's local catalog from another machine or backup. Keep your Recovery Kit somewhere other than this computer. Under a <i>Keep everything</i> policy, Free up disk keeps your originals; change this machine's retention settings before reviewing cleanup.</p>
177
202
  </div>
178
203
  </section>
179
204
 
180
205
  <section id="view-settings" class="view" hidden>
206
+ <p id="settings-load-state" class="note" role="status">Loading this computer's saved settings. Changes cannot be saved until they arrive.</p>
181
207
  <div class="metrics">
182
208
  <div class="metric"><h3>Waiting to encrypt</h3><b id="set-queue">–</b><small id="set-queue-detail"></small></div>
183
209
  <div class="metric"><h3>Last checked in</h3><b id="set-sync" class="small">–</b><small id="set-sync-ago"></small></div>
184
210
  <div class="metric"><h3>Sessions preserved</h3><b id="set-archives">–</b><small>on this machine</small></div>
185
- <div class="metric"><h3>Next reclaim window</h3><b id="set-reclaim-window" class="small">–</b><small id="set-reclaim-detail"></small></div>
211
+ <div class="metric"><h3 id="set-reclaim-label">Automatic reclaim</h3><b id="set-reclaim-window" class="small">–</b><small id="set-reclaim-detail"></small></div>
186
212
  </div>
187
213
 
188
214
  <form id="settings-form">
189
215
  <div class="panel pad">
190
- <h3>Identity</h3>
216
+ <h3 id="machine-identity">This computer's name</h3>
191
217
  <div class="field">
192
218
  <label for="f-device-label">Device label</label>
193
219
  <input id="f-device-label" type="text" maxlength="80" autocomplete="off" spellcheck="false" placeholder="this machine's name">
194
220
  </div>
195
221
 
196
- <h3>Watching</h3>
222
+ <h3 id="machine-agents">Agents and excluded files</h3>
197
223
  <div class="field">
198
224
  <label class="opt"><input id="f-watch-codex" type="checkbox"> Codex</label>
199
225
  <label class="opt"><input id="f-watch-claude" type="checkbox"> Claude Code</label>
200
226
  </div>
201
227
  <div class="field">
202
- <label for="f-watched-paths">Extra paths to watch, one per line</label>
203
- <textarea id="f-watched-paths" rows="3" spellcheck="false" placeholder="/mnt/extra-sessions"></textarea>
228
+ <label for="f-exclusions">Transcript storage paths to skip, one per line</label>
229
+ <textarea id="f-exclusions" rows="3" spellcheck="false" placeholder="~/.codex/sessions/private/**"></textarea>
230
+ <p class="note">A folder path skips that whole folder; <code>*</code>, <code>**</code>, and <code>?</code> patterns work too. Sealkeep currently watches only the standard Codex and Claude Code session stores shown above.</p>
231
+ </div>
232
+
233
+ <h3>Storage connections on this computer</h3>
234
+ <div class="field" id="storage-targets-panel">
235
+ <div id="storage-targets-rows"><p class="note">Loading destinations…</p></div>
236
+ <p class="note error" id="storage-targets-error" hidden></p>
237
+ <p class="note">This computer follows your account's storage order. Connect or disconnect this machine below. <a href="https://sealkeep.spala.ai/?view=storage#account" target="_blank" rel="noopener">Manage destinations, priorities and project rules in SealKeep Cloud</a>.</p>
204
238
  </div>
239
+
205
240
  <div class="field">
206
- <label for="f-exclusions">Never watch these, one per line</label>
207
- <textarea id="f-exclusions" rows="3" spellcheck="false" placeholder="/Users/me/client-work/**"></textarea>
241
+ <label for="f-local-archive-cache-days">Keep recent encrypted archive copies on this machine (days)</label>
242
+ <div class="row">
243
+ <input id="f-local-archive-cache-days" type="number" min="0" max="3650" step="1" inputmode="numeric" aria-describedby="f-local-archive-cache-note">
244
+ <label class="opt"><input id="f-local-archive-cache-all" type="checkbox"> Keep every encrypted archive copy here</label>
245
+ </div>
246
+ <p class="note" id="f-local-archive-cache-note">Seven days is recommended. After that, Sealkeep automatically removes only the local <code>.skarchive</code> duplicate once a readable cloud or bucket copy is verified. Your original Codex and Claude Code transcript files are separate and are never changed by this setting. Use 0 to remove verified duplicates immediately.</p>
208
247
  </div>
209
248
 
210
- <h3>Unlocking</h3>
249
+ <h3>Unlocking and recovery</h3>
211
250
  <div class="field" id="remember-panel">
212
251
  <p class="note" id="remember-state">Checking whether this machine holds the recovery phrase…</p>
213
252
  <div class="row" id="remember-form" hidden>
214
- <input id="f-remember-phrase" type="password" autocomplete="off" spellcheck="false" placeholder="your 24-word recovery phrase" aria-label="Recovery phrase">
253
+ <input id="f-remember-phrase" type="password" autocomplete="off" spellcheck="false" placeholder="your recovery phrase — all words, in order" aria-label="Recovery phrase">
215
254
  <button type="button" class="action" id="remember-go">Remember it on this machine</button>
216
255
  </div>
217
256
  <p class="note error" id="remember-error" hidden></p>
218
- <p class="note">Kept in this machine's keychain so archiving can run without you typing the phrase each time. It is checked against the vault before it is stored, and it is never sent anywhere.</p>
257
+ <p class="note">Checked against the vault, then kept only in this machine's keychain — it goes to the Sealkeep agent on 127.0.0.1 and never off this machine.</p>
258
+ <div class="row" id="reveal-row" hidden>
259
+ <button type="button" class="action" id="reveal-go">Reveal recovery phrase</button>
260
+ </div>
261
+ <textarea id="reveal-phrase" readonly rows="3" hidden spellcheck="false" aria-label="Recovery phrase"></textarea>
262
+ <p class="note" id="reveal-warning" hidden>Write these words down and put them somewhere safe — anyone who sees them can open every archive. They hide again in a minute, and each reveal is written to this vault's audit log.</p>
263
+ <div class="panel pad recovery-access" id="recovery-access-panel" style="margin-top:.8rem">
264
+ <b>Recovery access</b>
265
+ <p class="note">Check whether the recovery phrase is saved here and backup codes are registered. This does not test an archive restore. Keep your downloaded kit somewhere outside this computer; Drive-only history also needs its SealKeep catalog.</p>
266
+ <div class="row">
267
+ <button type="button" class="action primary" id="recovery-access-check">Check my recovery access</button>
268
+ </div>
269
+ <p class="note" id="recovery-access-keychain">Keychain: checking whether this machine holds its recovery phrase…</p>
270
+ <p class="note" id="recovery-access-cloud">Cloud Recovery Kit: checking…</p>
271
+ <p class="pill" id="recovery-access-status" role="status" aria-live="polite" hidden></p>
272
+ <div id="recovery-access-form" hidden>
273
+ <p class="note">Recover this machine from a saved Recovery Kit. The file stays in this tab; its candidates are checked one at a time by the local agent.</p>
274
+ <div class="field">
275
+ <label for="recovery-access-file">Choose a saved Recovery Kit (.txt)</label>
276
+ <input id="recovery-access-file" type="file" accept=".txt,text/plain" autocomplete="off">
277
+ </div>
278
+ <div class="row">
279
+ <label for="recovery-access-code">Or paste one backup code</label>
280
+ <input id="recovery-access-code" type="password" autocomplete="off" spellcheck="false" placeholder="SK-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XX" aria-label="Backup recovery code">
281
+ <button type="button" class="action primary" id="recovery-access-go">Recover this machine</button>
282
+ </div>
283
+ <p class="note error" id="recovery-access-error" hidden></p>
284
+ </div>
285
+ </div>
286
+ <div class="panel pad" id="recovery-kit-panel" style="margin-top:.8rem">
287
+ <b>Backup Recovery Kit</b>
288
+ <p class="note" id="recovery-kit-state">Checking your Recovery Kit…</p>
289
+ <div class="row">
290
+ <button type="button" class="action" id="recovery-kit-create">Generate backup codes</button>
291
+ <button type="button" class="action" id="recovery-kit-download" hidden>Download these codes</button>
292
+ <a class="action" id="recovery-kit-account" href="#recovery-kit" target="_blank" rel="noopener" hidden>Reconnect account</a>
293
+ </div>
294
+ <ol class="plain" id="recovery-kit-codes" hidden></ol>
295
+ <p class="note error" id="recovery-kit-error" hidden></p>
296
+ <p class="note">Five one-time codes can restore this vault after Google sign-in when every trusted machine is gone. Creating a new set invalidates the previous set. Codes are shown once and never sent to SealKeep Cloud.</p>
297
+ </div>
298
+ </div>
299
+
300
+ <h3>Approve a new machine</h3>
301
+ <div class="field" id="device-enrollment-panel">
302
+ <p class="note" id="device-enrollment-empty">Checking for machines waiting for access…</p>
303
+ <div id="device-enrollment-list"></div>
304
+ <p class="note error" id="device-enrollment-error" hidden></p>
305
+ <p class="note">A new machine shows a six-digit comparison code. Type that same code here to approve it. This machine encrypts the vault identity directly to the new machine; SealKeep Cloud relays ciphertext and never receives your recovery phrase.</p>
219
306
  </div>
220
307
 
221
308
  <h3>Automatic archiving</h3>
222
309
  <div class="field" id="autopilot-panel">
223
310
  <p class="note" id="autopilot-state">Checking whether the background service is running…</p>
311
+ <div class="automation-checks" id="autopilot-checks" aria-live="polite"></div>
224
312
  <div class="row" id="autopilot-form" hidden>
225
313
  <button type="button" class="action" id="autopilot-go">Turn on automatic archiving</button>
314
+ <button type="button" class="action" id="autopilot-unlock" hidden>Store recovery phrase</button>
226
315
  </div>
227
316
  <p class="note error" id="autopilot-error" hidden></p>
228
- <p class="note">When on, Sealkeep runs at login and archives new sessions on its own — no terminal, nothing to keep open. Off by default; you can always archive by hand from the <a href="#sessions">Memory pool</a>.</p>
317
+ <p class="note">When on, Sealkeep runs at login and archives new sessions on its own — no terminal, nothing to keep open. If it stops checking in, the repair action checks its installation and asks this machine to activate it again. Off by default; you can always archive by hand from <a href="#sessions">Sessions</a>.</p>
229
318
  </div>
230
319
 
231
- <h3>Reclaiming</h3>
320
+ <h3 id="machine-cleanup">Automatic disk cleanup</h3>
232
321
  <div class="field">
233
322
  <label class="opt"><input id="f-reclaim-enabled" type="checkbox"> Let this machine reclaim disk space on its own</label>
234
- <p class="note">Off by default. When on, the source moves to the trash only once its archive is verified in storage and the grace period has passed. Policy and timing stay in the <a href="#rules">Free up disk rules</a> — this only switches this machine's permission to act on them.</p>
235
- </div>
236
- <div class="field">
237
- <label for="f-trash-strategy">Trash location</label>
238
- <select id="f-trash-strategy">
239
- <option value="auto">Automatic — this machine's own trash</option>
240
- <option value="macos-trash">macOS Trash</option>
241
- <option value="xdg-trash">XDG Trash</option>
242
- <option value="windows-recycle-bin">Windows Recycle Bin</option>
243
- <option value="vaultline-trash">Sealkeep-owned trash folder</option>
244
- </select>
245
- <p class="note" id="f-trash-resolved"></p>
323
+ <p class="note">Off by default. When on, this machine permanently frees only originals whose encrypted archive is verified in storage, searchable, unchanged, idle, and past the grace period. Codex keeps a tiny same-session resume pointer. Policy and timing stay in the <a href="#rules">Free up disk rules</a>.</p>
246
324
  </div>
247
325
 
248
- <h3>Schedule and bandwidth</h3>
326
+ <h3 id="machine-resources">Speed and resource limits</h3>
249
327
  <div class="row">
250
328
  <div class="field"><label for="f-interval">Check every (minutes)</label><input id="f-interval" type="number" min="1" max="1440"></div>
251
- <div class="field"><label for="f-bandwidth">Upload limit, Mbps (blank for none)</label><input id="f-bandwidth" type="number" min="0" placeholder="unlimited"></div>
329
+ <div class="field">
330
+ <label for="f-bandwidth">Background network limit, Mbps (blank for automatic)</label>
331
+ <input id="f-bandwidth" type="number" min="1" max="100000" step="1" inputmode="numeric" placeholder="automatic · 8 Mbps">
332
+ <p class="note">Automatic shares one 8 Mbps background ceiling across Sealkeep jobs so agent calls, meetings, and normal browsing keep network headroom. This applies to unattended archive and shared-memory transfers on this machine.</p>
333
+ <p class="note">Background sealing, indexing, and memory preparation share a low-priority CPU budget targeting 30% of one CPU core. Short bursts can exceed this target. Large index workers have a 1.5 GB RSS safety limit. Foreground MCP searches are not throttled.</p>
334
+ </div>
252
335
  <div class="field">
253
336
  <label for="f-reserve">Always keep free, MB (blank for automatic)</label>
254
337
  <input id="f-reserve" type="number" min="200" placeholder="automatic">
@@ -258,7 +341,7 @@
258
341
 
259
342
  <div class="row">
260
343
  <p class="note" id="settings-saved"></p>
261
- <div class="actions"><button type="submit" class="action">Save</button></div>
344
+ <div class="actions"><button type="submit" class="action" id="settings-save" disabled>Save machine settings</button></div>
262
345
  </div>
263
346
  </div>
264
347
  </form>
@@ -297,15 +380,15 @@
297
380
  through five dropdowns had to be assembled. Chips in the same group
298
381
  (ages, sizes, agents) replace each other; groups stack. -->
299
382
  <div class="chips" id="chips" role="group" aria-label="Show only">
300
- <button type="button" class="chip on" data-group="state" data-value="unarchived">Not archived yet</button>
301
- <button type="button" class="chip" data-group="state" data-value="sealing">Queued to seal</button>
302
- <button type="button" class="chip" data-group="state" data-value="archived">Already archived</button>
303
- <!-- Cloud-state chips are a plan feature: they answer "which of these
304
- would survive losing this disk", which only means something when the
305
- account has storage. Unhidden by drawPlan() when a plan exists. -->
306
- <button type="button" class="chip pro-chip" data-group="state" data-value="stored" hidden title="Sessions with a verified copy in your cloud storage">In your cloud</button>
307
- <button type="button" class="chip pro-chip" data-group="state" data-value="unstored" hidden title="Sessions that would be lost with this disk — not yet verified in your cloud">Not in cloud yet</button>
308
- <span class="chip-sep"></span>
383
+ <button type="button" class="chip on" data-group="state" data-value="unarchived" aria-pressed="true">Ready to archive</button>
384
+ <button type="button" class="chip" data-group="state" data-value="sealing" aria-pressed="false">Queued to seal</button>
385
+ <button type="button" class="chip" data-group="state" data-value="archived" aria-pressed="false">Already archived</button>
386
+ <!-- Cloud-state chips answer whether a session survives losing this
387
+ disk. Any configured storage target makes that useful, including
388
+ free accounts and bring-your-own storage. -->
389
+ <button type="button" class="chip storage-chip" data-group="state" data-value="stored" aria-pressed="false" hidden title="Sessions with a verified copy in configured storage">In storage</button>
390
+ <button type="button" class="chip storage-chip" data-group="state" data-value="unstored" aria-pressed="false" hidden title="Sessions that would be lost with this disk — not yet verified in configured storage">Not in storage yet</button>
391
+ <details class="session-more-filters"><summary>Filter by project, age, size or agent</summary><div class="session-filter-options">
309
392
  <button type="button" class="chip" data-group="age" data-value="7">Older than 7 days</button>
310
393
  <button type="button" class="chip" data-group="age" data-value="30">Older than 30 days</button>
311
394
  <button type="button" class="chip" data-group="age" data-value="90">Older than 90 days</button>
@@ -315,6 +398,7 @@
315
398
  <span class="chip-sep"></span>
316
399
  <button type="button" class="chip" data-group="agent" data-value="codex">Codex</button>
317
400
  <button type="button" class="chip" data-group="agent" data-value="claude">Claude Code</button>
401
+ </div></details>
318
402
  </div>
319
403
  <div class="filters">
320
404
  <input type="search" id="f-search" placeholder="Search paths…" aria-label="Search session paths">
@@ -336,7 +420,7 @@
336
420
  <div class="scroll">
337
421
  <table>
338
422
  <thead><tr>
339
- <th style="width:2rem"><input type="checkbox" id="all" title="Select every unarchived session"></th>
423
+ <th style="width:2rem"><input type="checkbox" id="all" aria-label="Select every shown session ready to archive"></th>
340
424
  <th class="n">size</th><th class="n">last touched</th><th>project</th><th>session</th><th>state</th>
341
425
  </tr></thead>
342
426
  <tbody id="rows"><tr><td colspan="6" class="note">Reading sessions…</td></tr></tbody>
@@ -344,6 +428,7 @@
344
428
  </div>
345
429
  <div class="bar">
346
430
  <button type="button" id="archive" class="action primary" disabled>Archive selected</button>
431
+ <button type="button" id="send-archived" class="action" hidden disabled>Send complete sealed shown to storage</button>
347
432
  <span id="chosen" class="note"></span>
348
433
  </div>
349
434
  <p id="result" class="note" style="margin:.8rem 0 0"></p>
@@ -365,7 +450,7 @@
365
450
  <label class="opt"><input type="radio" name="policy" value="sync-only">
366
451
  <div><b>Upload, but keep the original</b><span>Archives go to storage; nothing is removed from disk.</span></div></label>
367
452
  <label class="opt"><input type="radio" name="policy" value="archive-and-reclaim">
368
- <div><b>Reclaim once safely stored</b><span>The source moves to the trash after the archive is verified in storage and the grace period has passed.</span></div></label>
453
+ <div><b>Reclaim once safely stored</b><span>Permanently free the local original after its archive is verified and searchable, unchanged, idle, and past the grace period.</span></div></label>
369
454
  <label class="opt"><input type="radio" name="policy" value="manual-approval">
370
455
  <div><b>Ask me first</b><span>Sealkeep lists what it would reclaim and waits for approval.</span></div></label>
371
456
  </fieldset>
@@ -377,7 +462,7 @@
377
462
  <div><label class="f" for="grace">Then wait this long after it is verified (days)</label><input type="number" id="grace" min="0" value="7"></div>
378
463
  </div>
379
464
  <div class="rowgrid" style="margin-top:.75rem">
380
- <div><label class="f" for="deleteAfter">Delete the archive from storage after (days)</label><input type="number" id="deleteAfter" min="0" placeholder="never"></div>
465
+ <div><label class="f" for="deleteAfter">Mark the backup as expired after (days)</label><input type="number" id="deleteAfter" min="0" placeholder="never"><small>Marks it for review; this does not delete it automatically.</small></div>
381
466
  <div><label class="f">&nbsp;</label><span style="font-size:.85rem;color:var(--soft)">Leave empty for never.</span></div>
382
467
  </div>
383
468
  </fieldset>
@@ -421,6 +506,13 @@
421
506
  this view will stop and say so before anything happens.
422
507
  </p>
423
508
  <p id="copies-line" style="margin:0 0 .9rem">Looking at what is stored off this machine…</p>
509
+ <div id="copies-controls" class="row" hidden style="margin:0 0 .75rem;align-items:center">
510
+ <label class="sr-only" for="copies-filter">Filter stored copies</label>
511
+ <input id="copies-filter" type="search" autocomplete="off" spellcheck="false"
512
+ placeholder="Filter by archive ref or storage…" style="min-width:min(28rem,100%);flex:1">
513
+ <span id="copies-visible" class="note" role="status" aria-live="polite"></span>
514
+ <button type="button" class="action" id="copies-more" hidden>Show 100 more</button>
515
+ </div>
424
516
  <div id="copies-wrap">
425
517
  <table id="copies-table" hidden>
426
518
  <thead><tr><th>Ref</th><th>Size</th><th>Age</th><th></th></tr></thead>
@@ -444,9 +536,9 @@
444
536
  </fieldset>
445
537
 
446
538
  <div class="note">
447
- <strong>Reclaiming is not deleting.</strong> Sources move to the OS trash, never <code>unlink</code>, and only after
448
- the archive is verified in remote storage, the age and grace periods have both passed, and the file is idle.
449
- If any of those cannot be established, Sealkeep keeps the file.
539
+ <strong>Reclaiming deletes only the verified local original.</strong> The encrypted archive remains in storage, and a Codex
540
+ session keeps a tiny same-ID resume pointer. Sealkeep permanently frees the original only after remote verification,
541
+ search coverage, age and grace, exact-byte, and idle-file checks all pass. Otherwise it keeps the file.
450
542
  </div>
451
543
 
452
544
  <div class="note" id="gap">
@@ -459,6 +551,112 @@
459
551
  <section id="view-health" class="view" hidden>
460
552
  <div class="panel" id="checks"></div>
461
553
  </section>
554
+
555
+ <section id="view-shared" class="view" hidden>
556
+ <div class="panel pad project-suggestions-panel">
557
+ <div class="row project-suggestions-head">
558
+ <div>
559
+ <h2>Suggested from this machine</h2>
560
+ <p class="note">Only the project name is created in SealKeep Cloud. Folder paths stay here on this machine.</p>
561
+ </div>
562
+ <span class="project-local-badge">Local folders</span>
563
+ </div>
564
+ <p class="note warn" id="team-project-plan" hidden>
565
+ Your personal project history is already preserved. Creating a memory pool shared with other people requires the Team plan.
566
+ <a id="team-project-plan-action" href="https://sealkeep.spala.ai/?view=plan#account" target="_blank" rel="noopener">See Team plan</a>
567
+ </p>
568
+ <div id="team-suggestions" class="project-suggestion-grid"><p class="note">Looking for project folders used by Codex and Claude…</p></div>
569
+ <div id="team-project-builder" class="project-builder" hidden>
570
+ <div class="project-builder-copy">
571
+ <strong id="team-project-builder-title">Create one project</strong>
572
+ <span id="team-project-builder-detail">The selected folders will search and write the same project memory.</span>
573
+ </div>
574
+ <label class="f project-name-field" for="team-project-name">
575
+ Project name
576
+ <input id="team-project-name" maxlength="120" autocomplete="off" placeholder="Checkout platform">
577
+ </label>
578
+ <button type="button" class="action" id="team-project-continue">Continue in SealKeep Cloud</button>
579
+ <span class="note" id="team-project-result" role="status" aria-live="polite"></span>
580
+ </div>
581
+ <div id="team-project-pending" class="project-pending-list"></div>
582
+ </div>
583
+
584
+ <div class="panel pad" id="team-project-repair" hidden>
585
+ <div class="row" style="justify-content:space-between;align-items:baseline">
586
+ <h2 style="margin:0">History from unavailable folders</h2>
587
+ <span class="project-local-badge">Review required</span>
588
+ </div>
589
+ <p class="note">Sealkeep found preserved history whose exact old folder is not detected now. Choose a current folder explicitly; names never decide which history moves.</p>
590
+ <div id="team-project-repair-controls" class="project-repair-controls" hidden>
591
+ <label class="sr-only" for="team-project-repair-filter">Filter unavailable project history</label>
592
+ <input id="team-project-repair-filter" type="search" autocomplete="off" spellcheck="false"
593
+ placeholder="Filter unavailable projects…">
594
+ <span id="team-project-repair-visible" class="note" role="status" aria-live="polite"></span>
595
+ <button id="team-project-repair-more" class="action" type="button" hidden>Show more</button>
596
+ </div>
597
+ <div id="team-project-repair-list"></div>
598
+ </div>
599
+
600
+ <div class="panel pad">
601
+ <div class="row" style="justify-content:space-between;align-items:baseline">
602
+ <h2 style="margin:0">Connected project memory</h2>
603
+ <a class="action" href="https://sealkeep.spala.ai/?view=projects#account" target="_blank" rel="noopener">Open Projects in SealKeep Cloud</a>
604
+ </div>
605
+ <div id="team-available" style="margin-top:.8rem"></div>
606
+ <p class="note" id="team-status">A folder is only a doorway into shared memory. Teammates' files are not copied into it; Codex and Claude receive relevant encrypted project history through Sealkeep.</p>
607
+ <p class="note"><b>Keys stay local.</b> The cloud coordinates account access; this machine performs the encryption before anything becomes usable.</p>
608
+ </div>
609
+
610
+ <div class="panel pad">
611
+ <h2>Live channels this machine follows</h2>
612
+ <div id="space-channels"><p class="note">None yet. When a teammate shares a session, follow it from the Live page — it appears here automatically.</p></div>
613
+ </div>
614
+ </section>
615
+
616
+ <section id="view-live" class="view" hidden>
617
+ <div class="panel pad">
618
+ <h3>Share a session live</h3>
619
+ <div class="row">
620
+ <select id="share-session" aria-label="Session to share"><option value="">loading sessions…</option></select>
621
+ <input id="share-channel" type="text" placeholder="channel id" autocomplete="off" spellcheck="false" pattern="[A-Za-z0-9-]{1,64}" aria-label="Channel id" style="max-width:200px">
622
+ <button type="button" class="action" id="share-start">Share live</button>
623
+ </div>
624
+ <p class="note" id="share-status">Pick the session you are working in, keep or edit the channel id, and share. Send the channel id to whoever should follow.</p>
625
+ <div id="share-active"></div>
626
+ </div>
627
+
628
+ <div class="panel pad">
629
+ <h3>Follow a shared session</h3>
630
+ <div class="row">
631
+ <input id="live-channel" type="text" placeholder="channel id from a teammate" autocomplete="off" spellcheck="false" pattern="[A-Za-z0-9-]{1,64}" aria-label="Channel to follow">
632
+ <button type="button" class="action" id="live-follow">Follow</button>
633
+ <button type="button" id="live-stop" hidden>Stop</button>
634
+ </div>
635
+ <p class="note" id="live-status">Enter the channel a teammate shared, then Follow. Read-only: you see their session; you cannot drive it.</p>
636
+ <pre id="live-mirror" class="live-mirror" hidden></pre>
637
+ </div>
638
+
639
+ <div class="panel pad">
640
+ <h3>Messages and agent approval</h3>
641
+ <p class="note">Choose how far teammates' words travel on a channel — and speak into it yourself. Everything is sealed on this machine before it moves.</p>
642
+ <div class="row">
643
+ <input id="coop-channel" type="text" placeholder="channel id" autocomplete="off" spellcheck="false" pattern="[A-Za-z0-9-]{1,64}" aria-label="Cooperation channel" style="max-width:180px">
644
+ <select id="coop-mode" aria-label="Cooperation mode">
645
+ <option value="suggest">Review messages before my agent receives them</option>
646
+ <option value="open">Allow messages directly to my agent</option>
647
+ <option value="observe">People only — do not send to my agent</option>
648
+ </select>
649
+ <button type="button" class="action" id="coop-apply">Set mode</button>
650
+ </div>
651
+ <div class="row">
652
+ <input id="coop-text" type="text" placeholder="say something to the channel…" autocomplete="off" style="flex:1;min-width:200px" aria-label="Message text">
653
+ <select id="coop-kind" aria-label="Message kind"><option>suggest</option><option>note</option><option>handoff</option></select>
654
+ <button type="button" class="action" id="coop-send">Send</button>
655
+ </div>
656
+ <p class="note" id="coop-note">suggest is the safe default: nothing reaches your agent until you approve it here or with <code>sealkeep bridge review</code>.</p>
657
+ <div id="coop-held"></div>
658
+ </div>
659
+ </section>
462
660
  </div>
463
661
 
464
662
  <footer>