total-recall-brain 3.45.0 → 3.46.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/bin/total-recall.mjs +7 -2
  2. package/frontend/dist/assets/index-BRYE1jmv.css +1 -0
  3. package/frontend/dist/assets/index-D1goIPjC.js +5598 -0
  4. package/frontend/dist/index.html +2 -2
  5. package/frontend/dist/sw.js +5 -4
  6. package/frontend/src/App.tsx +183 -236
  7. package/frontend/src/api/auth-inventory.ts +62 -0
  8. package/frontend/src/api/memory.ts +13 -8
  9. package/frontend/src/api/plugin-credentials.ts +23 -0
  10. package/frontend/src/api/plugins.ts +37 -53
  11. package/frontend/src/api/workspace-drawers.ts +97 -0
  12. package/frontend/src/components/BrainSelector.tsx +9 -3
  13. package/frontend/src/components/plugins/PluginPanel.tsx +83 -42
  14. package/frontend/src/components/plugins/PluginSettings.tsx +10 -20
  15. package/frontend/src/components/plugins/PluginWorkspace.tsx +367 -0
  16. package/frontend/src/components/plugins/ScopedPluginCommands.tsx +142 -0
  17. package/frontend/src/components/plugins/plugin-frame.ts +44 -33
  18. package/frontend/src/components/plugins/scoped-plugin-operations.ts +28 -0
  19. package/frontend/src/components/workspace/DrawerChat.tsx +110 -0
  20. package/frontend/src/components/workspace/DrawerLayout.tsx +196 -0
  21. package/frontend/src/components/workspace/DrawerMarkup.tsx +49 -0
  22. package/frontend/src/components/workspace/PluginChunkLibrary.tsx +92 -0
  23. package/frontend/src/components/workspace/PluginHome.tsx +76 -0
  24. package/frontend/src/components/workspace/WorkspaceDrawers.tsx +96 -0
  25. package/frontend/src/components/workspace/WorkspacePage.tsx +95 -0
  26. package/frontend/src/components/workspace/usePluginDesign.ts +38 -0
  27. package/frontend/src/index.css +409 -136
  28. package/frontend/src/pages/HelpPage.tsx +15 -46
  29. package/frontend/src/pages/MemoryPage.tsx +19 -36
  30. package/frontend/src/pages/SettingsPage.tsx +1 -1
  31. package/metadata.plugin.schema.json +53 -227
  32. package/package.json +1 -1
  33. package/scaffold/.agent/skills/plugin/SKILL.md +13 -11
  34. package/scaffold/.agent/skills/plugin/evals/README.md +14 -21
  35. package/scaffold/.agent/skills/plugin/evals/cases/01-fabricated-seed.mjs +15 -18
  36. package/scaffold/.agent/skills/plugin/evals/cases/02-reassuring-default.mjs +19 -24
  37. package/scaffold/.agent/skills/plugin/evals/cases/03-declared-template.mjs +12 -20
  38. package/scaffold/.agent/skills/plugin/evals/cases/04-home-collects-credential.mjs +35 -0
  39. package/scaffold/.agent/skills/plugin/evals/cases/05-host-leak-in-scaffold.mjs +8 -28
  40. package/scaffold/.agent/skills/plugin/evals/cases/06-correct-plugin.mjs +85 -47
  41. package/scaffold/.agent/skills/plugin/evals/run.mjs +17 -18
  42. package/scaffold/.agent/skills/plugin/prompts/05-credentials.md +4 -4
  43. package/scaffold/.agent/skills/plugin/prompts/07-scaffold.md +2 -2
  44. package/scaffold/.agent/skills/plugin/prompts/08-verify.md +4 -4
  45. package/scaffold/.agent/skills/plugin/references/anti-patterns.md +2 -2
  46. package/scaffold/.agent/skills/plugin/references/generative-home.md +38 -0
  47. package/scaffold/.agent/skills/plugin/references/scaffold.md +5 -5
  48. package/scaffold/.agent/skills/plugin/references/surfaces.md +13 -4
  49. package/scaffold/.agent/skills/plugin/scripts/record.mjs +75 -153
  50. package/scaffold/.agent/skills/plugin/subagents/plugin-reviewer.md +4 -4
  51. package/scaffold/.agent/skills/total-recall/plugins/auth/DESIGN.md +76 -0
  52. package/scaffold/.agent/skills/total-recall/plugins/auth/README.md +3 -1
  53. package/scaffold/.agent/skills/total-recall/plugins/auth/cli.mjs +20 -15
  54. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +6 -6
  55. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +2 -1
  56. package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +13 -51
  57. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/access-overview.md +17 -0
  58. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/agent-login.md +20 -0
  59. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/baseline-audit.md +22 -0
  60. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/credential-repository-binding.md +17 -0
  61. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/credential-store-maintenance.md +17 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/dashboard-password.md +18 -0
  63. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/dashboard-sessions.md +18 -0
  64. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/endpoint-probe.md +23 -0
  65. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/google-sign-in.md +21 -0
  66. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/mesh-machines.md +16 -0
  67. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/passkey-enrollment.md +21 -0
  68. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/registered-brains.md +16 -0
  69. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/scoped-access-keys.md +17 -0
  70. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/secret-inventory.md +25 -0
  71. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/signing-key-rotation.md +22 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/home.js +375 -0
  73. package/scaffold/.agent/skills/total-recall/plugins/automations/{ui/DESIGN.md → DESIGN.md} +32 -21
  74. package/scaffold/.agent/skills/total-recall/plugins/automations/adapters.mjs +17 -1
  75. package/scaffold/.agent/skills/total-recall/plugins/automations/cli.mjs +10 -1
  76. package/scaffold/.agent/skills/total-recall/plugins/automations/package-lock.json +6 -6
  77. package/scaffold/.agent/skills/total-recall/plugins/automations/package.json +4 -3
  78. package/scaffold/.agent/skills/total-recall/plugins/automations/plugin.json +11 -27
  79. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/automations.js +2 -2
  80. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/control-ledger.md +42 -0
  81. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/local-inventory-triage.md +17 -0
  82. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/pending-control.md +39 -0
  83. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/run-evidence.md +41 -0
  84. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/schedule-vs-run-evidence.md +17 -0
  85. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/source-coverage.md +41 -0
  86. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/{card.js → home.js} +32 -27
  87. package/scaffold/.agent/skills/total-recall/plugins/code-quality/DESIGN.md +53 -0
  88. package/scaffold/.agent/skills/total-recall/plugins/code-quality/cli.mjs +23 -0
  89. package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/run-core.mjs +4 -2
  90. package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/check.mjs +4 -2
  91. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +6 -6
  92. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +2 -1
  93. package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +40 -40
  94. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/config.md +15 -0
  95. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/detect.md +15 -0
  96. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/gate.md +15 -0
  97. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/init.md +15 -0
  98. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/report.md +17 -0
  99. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/run.md +17 -0
  100. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/snapshot.md +15 -0
  101. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/code-quality-report.mjs +55 -23
  102. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/home.mjs +214 -0
  103. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/DESIGN.md +146 -0
  104. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +6 -6
  105. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +2 -1
  106. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +51 -34
  107. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/command.mjs +1 -1
  108. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/create.md +35 -0
  109. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/history.md +35 -0
  110. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/library.md +49 -0
  111. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/list.md +42 -0
  112. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/promote.md +40 -0
  113. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/read.md +25 -0
  114. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/remove.md +26 -0
  115. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/rollback.md +26 -0
  116. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/show.md +53 -0
  117. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/status.md +40 -0
  118. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/test-path.md +38 -0
  119. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/test.md +46 -0
  120. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/update.md +32 -0
  121. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/home.js +533 -0
  122. package/scaffold/.agent/skills/total-recall/plugins/embeddings/DESIGN.md +110 -0
  123. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +6 -6
  124. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +2 -1
  125. package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +13 -10
  126. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/benchmark.md +49 -0
  127. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/coverage.md +53 -0
  128. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/models.md +43 -0
  129. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/pull.md +41 -0
  130. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/status.md +59 -0
  131. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/home.js +353 -0
  132. package/scaffold/.agent/skills/total-recall/plugins/git/DESIGN.md +31 -0
  133. package/scaffold/.agent/skills/total-recall/plugins/git/README.md +25 -1
  134. package/scaffold/.agent/skills/total-recall/plugins/git/cli.mjs +5 -1
  135. package/scaffold/.agent/skills/total-recall/plugins/git/package-lock.json +6 -6
  136. package/scaffold/.agent/skills/total-recall/plugins/git/package.json +2 -1
  137. package/scaffold/.agent/skills/total-recall/plugins/git/plugin.json +17 -27
  138. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/commit-memory.mjs +30 -6
  139. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/fleet.mjs +24 -6
  140. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/secret-firewall.mjs +33 -7
  141. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/undo.mjs +29 -5
  142. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/unmerged.mjs +182 -0
  143. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/change-comparison.md +27 -0
  144. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/commit-identity.md +22 -0
  145. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/create-worktree.md +25 -0
  146. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/registered-worktrees.md +22 -0
  147. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/remove-worktree.md +23 -0
  148. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/repository-ledger.md +25 -0
  149. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/unmerged-work.md +22 -0
  150. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/upstream-divergence.md +17 -0
  151. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/worktree-conflict-triage.md +17 -0
  152. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/worktree-terminal.md +22 -0
  153. package/scaffold/.agent/skills/total-recall/plugins/git/ui/home.js +273 -0
  154. package/scaffold/.agent/skills/total-recall/plugins/mesh/DESIGN.md +35 -0
  155. package/scaffold/.agent/skills/total-recall/plugins/mesh/README.md +4 -5
  156. package/scaffold/.agent/skills/total-recall/plugins/mesh/cli.mjs +9 -3
  157. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +6 -6
  158. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +2 -1
  159. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +37 -39
  160. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +5 -3
  161. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/active-device-dispatch.md +22 -0
  162. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/control-probe.md +25 -0
  163. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/control-server.md +22 -0
  164. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/credential-readiness.md +23 -0
  165. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/elected-leader.md +22 -0
  166. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/enrollment-key.md +22 -0
  167. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/file-receipt.md +25 -0
  168. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/fleet-execution.md +23 -0
  169. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/fleet-presence.md +23 -0
  170. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/interactive-ssh.md +22 -0
  171. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/local-enrollment.md +23 -0
  172. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/mesh-policy.md +23 -0
  173. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/network-atlas.md +25 -0
  174. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/node-roster.md +26 -0
  175. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/node-selection-proof.md +17 -0
  176. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/owner-observations.md +23 -0
  177. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/peer-path.md +23 -0
  178. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/pinned-leader.md +24 -0
  179. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/reachability-evidence-ladder.md +17 -0
  180. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/recorded-login.md +23 -0
  181. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/remote-execution.md +22 -0
  182. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/secret-grants.md +26 -0
  183. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/{card.js → home.js} +93 -22
  184. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/DESIGN.md +86 -0
  185. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +19 -0
  186. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +5 -1
  187. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +6 -6
  188. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +2 -1
  189. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +43 -22
  190. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/chat.mjs +80 -0
  191. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/adapter-docs-freshness.md +16 -0
  192. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/chat-handoff.md +26 -0
  193. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/fleet-maintenance.md +21 -0
  194. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/harness-inventory.md +21 -0
  195. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/included-access.md +18 -0
  196. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/included-usage-verification.md +15 -0
  197. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/independent-review.md +17 -0
  198. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/managed-execution.md +20 -0
  199. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/official-documentation.md +18 -0
  200. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/quota-recovery.md +21 -0
  201. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/review-routing-decision.md +16 -0
  202. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/route-work.md +18 -0
  203. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/routing-evidence.md +18 -0
  204. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/run-ledger.md +18 -0
  205. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/home.js +198 -0
  206. package/scaffold/.agent/skills/total-recall/plugins/openwiki/DESIGN.md +75 -0
  207. package/scaffold/.agent/skills/total-recall/plugins/openwiki/README.md +2 -0
  208. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +17 -14
  209. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +6 -6
  210. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +2 -1
  211. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +10 -44
  212. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +5 -4
  213. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +3 -4
  214. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/ingest.mjs +23 -18
  215. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +8 -3
  216. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +6 -3
  217. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +3 -5
  218. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/token.mjs +21 -47
  219. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +17 -6
  220. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/auto-refresh.md +18 -0
  221. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/bootstrap-pages.md +18 -0
  222. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/generate-wiki.md +21 -0
  223. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/generator-settings.md +18 -0
  224. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/host-probe.md +18 -0
  225. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/ingest-preview.md +18 -0
  226. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/link-hygiene.md +21 -0
  227. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/link-topology.md +19 -0
  228. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/passage-search.md +19 -0
  229. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/propagation-plan.md +18 -0
  230. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/provider-credentials.md +18 -0
  231. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/refresh-report.md +18 -0
  232. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/task-evidence.md +22 -0
  233. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/upstream-record.md +18 -0
  234. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/watch-upstream.md +18 -0
  235. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/wiki-atlas.md +19 -0
  236. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/panel.js +261 -513
  237. package/scaffold/.agent/skills/total-recall/plugins/security/DESIGN.md +84 -0
  238. package/scaffold/.agent/skills/total-recall/plugins/security/README.md +4 -2
  239. package/scaffold/.agent/skills/total-recall/plugins/security/cli.mjs +7 -19
  240. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +6 -6
  241. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +2 -3
  242. package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +19 -52
  243. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/device-evidence.md +21 -0
  244. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/evidence-desk.md +18 -0
  245. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/guided-device-review.md +17 -0
  246. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/host-and-network.md +21 -0
  247. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/https-headers.md +17 -0
  248. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/mesh-coverage.md +18 -0
  249. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/private-security-tools.md +16 -0
  250. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/single-origin-header-check.md +17 -0
  251. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/source-review.md +21 -0
  252. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/ssh-permission-plan.md +17 -0
  253. package/scaffold/.agent/skills/total-recall/plugins/security/ui/home.js +283 -0
  254. package/scaffold/.agent/skills/total-recall/plugins/ssss/DESIGN.md +93 -0
  255. package/scaffold/.agent/skills/total-recall/plugins/ssss/package-lock.json +2 -2
  256. package/scaffold/.agent/skills/total-recall/plugins/ssss/package.json +2 -1
  257. package/scaffold/.agent/skills/total-recall/plugins/ssss/plugin.json +5 -3
  258. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/conformance.md +26 -0
  259. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/registry.md +37 -0
  260. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/repair.md +42 -0
  261. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/scaffold.md +33 -0
  262. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/status.md +43 -0
  263. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/validate.md +34 -0
  264. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/validation-diagnostics.md +17 -0
  265. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/workspace-registry-preflight.md +17 -0
  266. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/home.js +348 -0
  267. package/scaffold/.agent/skills/total-recall/references/operations.md +2 -0
  268. package/src/cli/api.mjs +3 -3
  269. package/src/cli/brief.mjs +3 -0
  270. package/src/cli/config.mjs +16 -0
  271. package/src/cli/connect.mjs +2 -7
  272. package/src/cli/plugin/chunks.mjs +145 -0
  273. package/src/cli/plugin/create.mjs +24 -52
  274. package/src/cli/plugin/index.mjs +20 -9
  275. package/src/cli/setup.mjs +2 -9
  276. package/src/cli/start.mjs +1 -0
  277. package/src/cli/startup.mjs +18 -0
  278. package/src/core/app-deploy/design-tokens.mjs +14 -9
  279. package/src/core/app-deploy/ui-elements.mjs +1 -1
  280. package/src/core/brain-registry.mjs +5 -0
  281. package/src/core/brain-updates.mjs +5 -1
  282. package/src/core/daemon-control.mjs +5 -1
  283. package/src/core/dashboard-bundle.mjs +261 -0
  284. package/src/core/default-plugin-refresh.mjs +39 -0
  285. package/src/core/ensure-dependencies.mjs +19 -15
  286. package/src/core/memory-brain.mjs +30 -8
  287. package/src/core/plugin-activation.mjs +63 -20
  288. package/src/core/plugin-contracts/{card.mjs → manifest.mjs} +23 -57
  289. package/src/core/plugin-contracts/startup-check.mjs +49 -0
  290. package/src/core/plugin-contracts/ui.mjs +9 -3
  291. package/src/core/plugin-distribution.mjs +6 -6
  292. package/src/core/plugin-lifecycle.mjs +58 -0
  293. package/src/core/plugin-loader.mjs +9 -5
  294. package/src/core/plugin-runner.mjs +21 -10
  295. package/src/core/plugin-startup-checks.mjs +44 -0
  296. package/src/core/plugin-state.mjs +19 -5
  297. package/src/core/plugin-store.mjs +30 -11
  298. package/src/core/project-id.mjs +15 -5
  299. package/src/core/required-plugins.mjs +31 -6
  300. package/src/core/schema.mjs +2 -0
  301. package/src/core/ssss-operation-service.mjs +1 -0
  302. package/src/core/startup-health.mjs +28 -3
  303. package/src/core/testing/plugin-fixture.mjs +22 -21
  304. package/src/core/throttled-fetch.mjs +25 -18
  305. package/src/core/ui-chunk-choice.mjs +77 -0
  306. package/src/core/ui-chunk.registry.json +23 -0
  307. package/src/core/ui-chunks.mjs +434 -0
  308. package/src/core/vault-cache.mjs +58 -59
  309. package/src/core/workspace-compositions.mjs +151 -0
  310. package/src/core/workspace-drawers.mjs +79 -0
  311. package/src/server/api.mjs +4 -27
  312. package/src/server/index.mjs +28 -21
  313. package/src/server/memory-events.mjs +31 -0
  314. package/src/server/plugin-brain-targets.mjs +89 -0
  315. package/src/server/rest.mjs +2 -0
  316. package/src/server/route-inventory.mjs +3 -2
  317. package/src/server/route-manifest.json +52 -4
  318. package/src/server/routes/_shared.mjs +7 -14
  319. package/src/server/routes/brains.mjs +29 -44
  320. package/src/server/routes/dashboard.mjs +26 -0
  321. package/src/server/routes/plugins.mjs +154 -45
  322. package/src/server/routes/ui-chunks.mjs +192 -0
  323. package/frontend/dist/assets/index-DACh1dhx.js +0 -5613
  324. package/frontend/dist/assets/index-DtwsDyFM.css +0 -1
  325. package/frontend/src/components/plugins/card/CardEngine.tsx +0 -108
  326. package/frontend/src/components/plugins/card/CardScenes.tsx +0 -103
  327. package/frontend/src/components/plugins/card/ExecutionPicker.tsx +0 -64
  328. package/frontend/src/components/plugins/card/args.ts +0 -28
  329. package/frontend/src/components/plugins/card/card.css +0 -32
  330. package/frontend/src/components/plugins/card/cli-line.ts +0 -13
  331. package/frontend/src/components/plugins/card/contract.ts +0 -91
  332. package/frontend/src/components/plugins/card/format.ts +0 -49
  333. package/frontend/src/components/plugins/card/runner-context.ts +0 -11
  334. package/frontend/src/components/plugins/card/runner.tsx +0 -43
  335. package/frontend/src/components/plugins/card/theme.ts +0 -35
  336. package/frontend/src/components/plugins/card/use-source.ts +0 -22
  337. package/frontend/src/components/plugins/card/widgets.tsx +0 -94
  338. package/frontend/src/components/plugins/workspace/WorkspaceHost.tsx +0 -23
  339. package/frontend/src/pages/PluginsPage.tsx +0 -1719
  340. package/scaffold/.agent/skills/plugin/evals/cases/04-card-collects-credential.mjs +0 -47
  341. package/scaffold/.agent/skills/plugin/prompts/06-card.md +0 -46
  342. package/scaffold/.agent/skills/plugin/references/card.md +0 -90
  343. package/scaffold/.agent/skills/plugin/subagents/card-designer.md +0 -60
  344. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/DESIGN.md +0 -67
  345. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/card.js +0 -1179
  346. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/DESIGN.md +0 -32
  347. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +0 -588
  348. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +0 -575
  349. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/DESIGN.md +0 -32
  350. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +0 -482
  351. package/scaffold/.agent/skills/total-recall/plugins/git/ui/DESIGN.md +0 -100
  352. package/scaffold/.agent/skills/total-recall/plugins/git/ui/card.js +0 -637
  353. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/DESIGN.md +0 -217
  354. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +0 -32
  355. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +0 -1276
  356. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +0 -45
  357. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +0 -1401
  358. package/scaffold/.agent/skills/total-recall/plugins/security/scripts/build-ui.mjs +0 -4
  359. package/scaffold/.agent/skills/total-recall/plugins/security/ui/DESIGN.md +0 -41
  360. package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +0 -396
  361. package/scaffold/.agent/skills/total-recall/plugins/security/ui/panel.js +0 -98
  362. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/DESIGN.md +0 -15
  363. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/card.js +0 -182
@@ -0,0 +1,76 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { findWorkspaceChunks, readWorkspaceComposition, type WorkspaceChunk } from '../../api/workspace-drawers'
3
+ import type { PluginInfo } from '../../api/plugins'
4
+ import { drawerPanels, PublishedChunk } from './DrawerLayout'
5
+ import { PluginPanel } from '../plugins/PluginPanel'
6
+ import { scopedPluginOperations } from '../plugins/scoped-plugin-operations'
7
+ import { usePluginDesign } from './usePluginDesign'
8
+
9
+ export function PluginHome({ plugin, plugins, brainId, onCommand }: {
10
+ plugin: PluginInfo; plugins: PluginInfo[] | null; brainId?: string; onCommand: (name: string) => void
11
+ }) {
12
+ const [defaults, setDefaults] = useState<WorkspaceChunk[]>([])
13
+ const [published, setPublished] = useState<{ chunks: WorkspaceChunk[]; version: string | null }>()
14
+ const [loading, setLoading] = useState(true)
15
+ const liveDesign = usePluginDesign(plugin.id, brainId)
16
+ const designCss = liveDesign?.design?.css ?? ''
17
+ const panels = drawerPanels(plugin)
18
+ const home = (plugin.manifest?.ui as { home?: string } | undefined)?.home || plugin.ui?.home
19
+ const panel = panels.find(element => element.id === home) || panels[0]
20
+ const operations = scopedPluginOperations(plugin)
21
+ const chunks = published?.chunks.length ? published.chunks : defaults
22
+
23
+ useEffect(() => {
24
+ const controller = new AbortController()
25
+ void findWorkspaceChunks('page', '', controller.signal, plugin.id, brainId).then(({ chunks }) => {
26
+ if (controller.signal.aborted) return
27
+ const ownerDefault = panel?.id && chunks.find(chunk => chunk.panel === panel.id)
28
+ setDefaults(ownerDefault ? [ownerDefault] : chunks.slice(0, 1))
29
+ }).catch(() => {}).finally(() => {
30
+ if (!controller.signal.aborted) setLoading(false)
31
+ })
32
+ return () => controller.abort()
33
+ }, [plugin.id, panel?.id, brainId])
34
+
35
+ useEffect(() => {
36
+ const controller = new AbortController()
37
+ let timer: ReturnType<typeof setTimeout>
38
+ const refresh = async () => {
39
+ try {
40
+ const next = await readWorkspaceComposition(plugin.id, controller.signal, brainId)
41
+ if (!controller.signal.aborted) {
42
+ setPublished(current => current?.version === next.version &&
43
+ current.chunks.map(chunk => chunk.sha256).join() === next.chunks.map(chunk => chunk.sha256).join() ? current : next)
44
+ }
45
+ } catch { /* The owner default remains available on an older or unreachable server. */ }
46
+ finally {
47
+ if (!controller.signal.aborted) timer = setTimeout(refresh, 2500)
48
+ }
49
+ }
50
+ void refresh()
51
+ return () => { controller.abort(); clearTimeout(timer) }
52
+ }, [plugin.id, brainId])
53
+
54
+ return <div className="plugin-home">
55
+ {loading && <p role="status">Loading published blocks…</p>}
56
+ {liveDesign?.issue && <p role="status">{liveDesign.issue}</p>}
57
+ {!loading && chunks.map(chunk =>
58
+ <div key={`${chunk.key}:${chunk.sha256}`} className="plugin-home">
59
+ <PublishedChunk name={chunk.key} side="page" plugins={plugins} brainId={brainId} design={chunk.plugin === plugin.id ? liveDesign?.design : undefined}
60
+ designOwner={chunk.plugin === plugin.id ? undefined : chunk.plugin} />
61
+ </div>
62
+ )}
63
+ {!loading && !published?.chunks.length && panel && !chunks.some(chunk => chunk.panel === panel.id) &&
64
+ <PluginPanel plugin={plugin} elementId={panel.id} designCss={designCss} brainId={brainId} />}
65
+ {!published?.chunks.length && !chunks.some(chunk => chunk.operations?.length) && operations.length > 0 && <section aria-label="Plugin operations">
66
+ <h2>Start a workflow</h2>
67
+ <ul className="plugin-home-operations">
68
+ {operations.slice(0, 6).map(command => <li key={command.name}>
69
+ <button type="button" className="btn btn-ghost" onClick={() => onCommand(command.name)}>{command.name}</button>
70
+ {command.description && <span>{command.description}</span>}
71
+ </li>)}
72
+ </ul>
73
+ </section>}
74
+ {!panel && !loading && !chunks.length && <p className="plugin-muted">This plugin has yet to publish a dedicated Home interface.</p>}
75
+ </div>
76
+ }
@@ -0,0 +1,96 @@
1
+ import { useEffect, useRef, useState, type ReactNode } from 'react'
2
+ import type { PluginInfo } from '../../api/plugins'
3
+ import type { DrawerSide } from '../../api/workspace-drawers'
4
+ import HelpPage from '../../pages/HelpPage'
5
+ import { DrawerChat } from './DrawerChat'
6
+ import { DrawerLayout, DrawerPanel } from './DrawerLayout'
7
+
8
+ export type WorkspaceEdge = 'left' | DrawerSide
9
+ const tools = ['Phone', 'Text', 'Shortcuts', 'Chat', 'Custom'] as const
10
+ type Tool = (typeof tools)[number]
11
+
12
+ function EdgeDrawer({ side, title, open, onChange, children }: {
13
+ side: DrawerSide; title: string; open: boolean; onChange: (edge: WorkspaceEdge | null) => void; children: ReactNode
14
+ }) {
15
+ const toggle = useRef<HTMLButtonElement>(null)
16
+ const closeButton = useRef<HTMLButtonElement>(null)
17
+ const content = useRef<HTMLElement>(null)
18
+ const panelId = `workspace-drawer-${side}`
19
+
20
+ useEffect(() => {
21
+ if (open) closeButton.current?.focus()
22
+ return () => {
23
+ if (open && content.current?.contains(document.activeElement)) toggle.current?.focus()
24
+ }
25
+ }, [open])
26
+ const close = () => {
27
+ toggle.current?.focus()
28
+ onChange(null)
29
+ }
30
+ return <>
31
+ <button type="button" className={`workspace-edge-handle workspace-edge-handle--${side}`}
32
+ ref={toggle} aria-label={side === 'right' ? 'Help drawer' : 'Bottom drawer'}
33
+ aria-controls={panelId} aria-expanded={open} onClick={() => open ? close() : onChange(side)}
34
+ onKeyDown={event => { if (event.key === 'Escape' && open) close() }}>
35
+ <svg width="13" height="13" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden="true">
36
+ <path d={side === 'right' ? (open ? 'm6 3 5 5-5 5' : 'm10 3-5 5 5 5') : (open ? 'm3 6 5 5 5-5' : 'm3 10 5-5 5 5')} />
37
+ </svg>
38
+ {title}
39
+ </button>
40
+ <aside ref={content} id={panelId} aria-label={title} inert={!open}
41
+ className={`workspace-edge-panel workspace-edge-panel--${side}${open ? ' open' : ''}`}
42
+ onKeyDown={event => { if (event.key === 'Escape') { event.stopPropagation(); close() } }}>
43
+ <header className="workspace-edge-header">
44
+ <h2>{title}</h2>
45
+ <button type="button" ref={closeButton} className="btn btn-ghost btn-sm" onClick={close}>Close</button>
46
+ </header>
47
+ {open && <div className="workspace-edge-body">{children}</div>}
48
+ </aside>
49
+ </>
50
+ }
51
+
52
+ function HelpDrawer({ plugins, brainId }: { plugins: PluginInfo[] | null; brainId?: string }) {
53
+ const [custom, setCustom] = useState(false)
54
+ return <>
55
+ <div className="drawer-section-tabs" role="group" aria-label="Help sections">
56
+ <button type="button" className="btn btn-ghost btn-sm" aria-pressed={!custom} onClick={() => setCustom(false)}>Reference</button>
57
+ <button type="button" className="btn btn-ghost btn-sm" aria-pressed={custom} onClick={() => setCustom(true)}>Custom</button>
58
+ </div>
59
+ {custom ? (brainId ? <DrawerLayout key={brainId} side="right" view="custom" plugins={plugins} brainId={brainId} />
60
+ : <p className="drawer-note">Select one local brain to open custom help.</p>) : <HelpPage embedded />}
61
+ </>
62
+ }
63
+
64
+ function ToolsDrawer({ plugins, activeBrainId, brainId }: { plugins: PluginInfo[] | null; activeBrainId: string; brainId?: string }) {
65
+ const [section, setSection] = useState<Tool>('Shortcuts')
66
+ return <>
67
+ <div className="drawer-section-tabs" role="group" aria-label="Bottom drawer tools">
68
+ {tools.map(tool => <button key={tool} type="button" className="btn btn-ghost btn-sm"
69
+ aria-pressed={tool === section} onClick={() => setSection(tool)}>{tool}</button>)}
70
+ </div>
71
+ {(section === 'Phone' || section === 'Text') && (brainId
72
+ ? <DrawerPanel plugins={plugins} reference={{ plugin: section.toLowerCase(), element: section.toLowerCase() }} brainId={brainId} />
73
+ : <p className="drawer-note">Select one local brain to open {section}.</p>)}
74
+ {section === 'Chat' && (plugins ? <DrawerChat plugin={plugins.find(plugin => plugin.id === 'meta-harness')}
75
+ activeBrainId={activeBrainId} /> : <p role="status">Loading Metaharness…</p>)}
76
+ {section === 'Shortcuts' && <DrawerLayout side="bottom" view="shortcuts" plugins={plugins} brainId={brainId} />}
77
+ {section === 'Custom' && (brainId ? <DrawerLayout key={brainId} side="bottom" view="custom" plugins={plugins} brainId={brainId} />
78
+ : <p className="drawer-note">Select one local brain to open custom tools.</p>)}
79
+ </>
80
+ }
81
+
82
+ export function WorkspaceDrawers({ edge, onChange, plugins, activeBrainId }: {
83
+ edge: WorkspaceEdge | null
84
+ onChange: (edge: WorkspaceEdge | null) => void
85
+ plugins: PluginInfo[] | null
86
+ activeBrainId: string
87
+ }) {
88
+ const brainId = !activeBrainId.includes(',') && (activeBrainId === 'global' || activeBrainId.startsWith('project:'))
89
+ ? activeBrainId : undefined
90
+ return <>
91
+ <EdgeDrawer side="right" title="Help" open={edge === 'right'} onChange={onChange}><HelpDrawer plugins={plugins} brainId={brainId} /></EdgeDrawer>
92
+ <EdgeDrawer side="bottom" title="Tools" open={edge === 'bottom'} onChange={onChange}>
93
+ <ToolsDrawer plugins={plugins} activeBrainId={activeBrainId} brainId={brainId} />
94
+ </EdgeDrawer>
95
+ </>
96
+ }
@@ -0,0 +1,95 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { Link } from 'react-router-dom'
3
+ import type { PluginInfo } from '../../api/plugins'
4
+ import { listSavedPages, readSavedPage, type SavedPage, type SavedPageSummary } from '../../api/workspace-drawers'
5
+ import { PublishedChunk } from './DrawerLayout'
6
+
7
+ export function SavedPages({ brainId, drawerOpen, activePageId, onOpenPage }: {
8
+ brainId?: string
9
+ drawerOpen: boolean
10
+ activePageId: string | null
11
+ onOpenPage: () => void
12
+ }) {
13
+ const [expanded, setExpanded] = useState(false)
14
+ return <details className="sidebar-memory sidebar-saved-pages" onToggle={event => setExpanded(event.currentTarget.open)}>
15
+ <summary className="nav-link">
16
+ Saved pages <span className="plugin-folder-chevron" aria-hidden="true">{expanded ? '▾' : '›'}</span>
17
+ </summary>
18
+ {drawerOpen && expanded && (brainId
19
+ ? <SavedPageLinks key={brainId} brainId={brainId} activePageId={activePageId} onOpenPage={onOpenPage} />
20
+ : <p className="plugin-folder-message">Select one brain to see its saved pages.</p>)}
21
+ </details>
22
+ }
23
+
24
+ function SavedPageLinks({ brainId, activePageId, onOpenPage }: {
25
+ brainId: string
26
+ activePageId: string | null
27
+ onOpenPage: () => void
28
+ }) {
29
+ const [result, setResult] = useState<{ pages: SavedPageSummary[] } | { error: string }>()
30
+ useEffect(() => {
31
+ const controller = new AbortController()
32
+ void listSavedPages(brainId, controller.signal).then(
33
+ data => { if (!controller.signal.aborted) setResult(data) },
34
+ () => { if (!controller.signal.aborted) setResult({ error: 'Could not load saved pages.' }) },
35
+ )
36
+ return () => controller.abort()
37
+ }, [brainId])
38
+
39
+ if (!result) return <p className="plugin-folder-message" role="status">Loading saved pages…</p>
40
+ if ('error' in result) return <p className="plugin-folder-message" role="alert">{result.error}</p>
41
+ if (!result.pages.length) return <p className="plugin-folder-message">No saved pages</p>
42
+
43
+ return <ul className="plugin-folder-list" aria-label="Saved pages">
44
+ {result.pages.map(page => {
45
+ const query = new URLSearchParams({ page: page.id, brain: brainId })
46
+ const current = page.id === activePageId
47
+ return <li key={page.id}>
48
+ <Link to={`/memory?${query}`} className={`nav-link ${current ? 'active' : ''}`}
49
+ aria-current={current ? 'page' : undefined} onClick={onOpenPage}>{page.title}</Link>
50
+ </li>
51
+ })}
52
+ </ul>
53
+ }
54
+
55
+ export function WorkspacePage({ id, brainId, plugins }: {
56
+ id: string
57
+ brainId?: string
58
+ plugins: PluginInfo[] | null
59
+ }) {
60
+ return brainId
61
+ ? <SavedPageContent key={`${brainId}:${id}`} id={id} brainId={brainId} plugins={plugins} />
62
+ : <section className="plugin-workspace-page" aria-label="Saved page">
63
+ <p>Select one brain to open this saved page.</p>
64
+ </section>
65
+ }
66
+
67
+ function SavedPageContent({ id, brainId, plugins }: {
68
+ id: string
69
+ brainId: string
70
+ plugins: PluginInfo[] | null
71
+ }) {
72
+ const [result, setResult] = useState<SavedPage | { error: string }>()
73
+ useEffect(() => {
74
+ const controller = new AbortController()
75
+ void readSavedPage(id, brainId, controller.signal).then(
76
+ page => { if (!controller.signal.aborted) setResult(page) },
77
+ () => { if (!controller.signal.aborted) setResult({ error: 'Could not open this saved page in the selected brain.' }) },
78
+ )
79
+ return () => controller.abort()
80
+ }, [id, brainId])
81
+
82
+ const page = result && 'chunks' in result ? result : undefined
83
+ return <section className="plugin-workspace-page" aria-labelledby="saved-page-title">
84
+ <header className="plugin-drawer-header">
85
+ <h1 id="saved-page-title">{page?.title || 'Saved page'}</h1>
86
+ <Link className="btn btn-ghost btn-sm" to="/memory">Close</Link>
87
+ </header>
88
+ {!result && <p role="status">Loading saved page…</p>}
89
+ {result && 'error' in result && <p role="alert">{result.error}</p>}
90
+ {page && !page.chunks.length && <p className="plugin-muted">No page blocks are available in this brain.</p>}
91
+ {page?.chunks.map(chunk =>
92
+ <PublishedChunk key={`${chunk.key}:${chunk.sha256}`} name={chunk.key} side="page" plugins={plugins}
93
+ brainId={brainId} designOwner={chunk.plugin} />)}
94
+ </section>
95
+ }
@@ -0,0 +1,38 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { readPluginDesign, type PluginDesign } from '../../api/workspace-drawers'
3
+
4
+ export function usePluginDesign(pluginId: string | undefined, brainId?: string) {
5
+ const [current, setCurrent] = useState<{ pluginId: string; brainId?: string; design?: PluginDesign; issue?: string }>()
6
+ useEffect(() => {
7
+ if (!pluginId) return
8
+ const controller = new AbortController()
9
+ let timer: ReturnType<typeof setTimeout>
10
+ let revision: string | null = null
11
+ const refresh = async () => {
12
+ try {
13
+ const result = await readPluginDesign(pluginId, revision, controller.signal, brainId)
14
+ if (controller.signal.aborted) return
15
+ if ('unchanged' in result) {
16
+ setCurrent(current => current?.issue ? { ...current, issue: undefined } : current)
17
+ } else {
18
+ revision = result.revision
19
+ setCurrent(current => current?.pluginId === pluginId && current.brainId === brainId && current.design?.revision === result.revision && !current.issue
20
+ ? current : { pluginId, brainId, design: result })
21
+ }
22
+ } catch (error) {
23
+ if (!controller.signal.aborted) {
24
+ const issue = error instanceof Error ? error.message : 'Could not refresh the plugin design.'
25
+ setCurrent(current => ({ pluginId, brainId, design: current?.pluginId === pluginId && current.brainId === brainId ? current.design : undefined, issue }))
26
+ }
27
+ } finally {
28
+ if (!controller.signal.aborted) timer = setTimeout(refresh, 2500)
29
+ }
30
+ }
31
+ void refresh()
32
+ return () => {
33
+ controller.abort()
34
+ clearTimeout(timer)
35
+ }
36
+ }, [pluginId, brainId])
37
+ return current?.pluginId === pluginId && current?.brainId === brainId ? current : undefined
38
+ }