total-recall-brain 3.44.0 → 3.46.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 (502) hide show
  1. package/bin/total-recall.mjs +10 -6
  2. package/docs/ARCHITECTURE.md +10 -7
  3. package/docs/reference/cli-reference.md +13 -8
  4. package/frontend/dist/assets/index-BRYE1jmv.css +1 -0
  5. package/frontend/dist/assets/index-D1goIPjC.js +5598 -0
  6. package/frontend/dist/index.html +2 -2
  7. package/frontend/dist/sw.js +5 -4
  8. package/frontend/src/App.tsx +185 -238
  9. package/frontend/src/api/auth-inventory.ts +62 -0
  10. package/frontend/src/api/memory.ts +13 -8
  11. package/frontend/src/api/plugin-credentials.ts +23 -0
  12. package/frontend/src/api/plugins.ts +37 -53
  13. package/frontend/src/api/workspace-drawers.ts +97 -0
  14. package/frontend/src/components/BrainSelector.tsx +9 -3
  15. package/frontend/src/components/plugins/PluginPanel.tsx +83 -42
  16. package/frontend/src/components/plugins/PluginSettings.tsx +10 -20
  17. package/frontend/src/components/plugins/PluginWorkspace.tsx +367 -0
  18. package/frontend/src/components/plugins/ScopedPluginCommands.tsx +142 -0
  19. package/frontend/src/components/plugins/plugin-frame.ts +44 -33
  20. package/frontend/src/components/plugins/scoped-plugin-operations.ts +28 -0
  21. package/frontend/src/components/workspace/DrawerChat.tsx +110 -0
  22. package/frontend/src/components/workspace/DrawerLayout.tsx +196 -0
  23. package/frontend/src/components/workspace/DrawerMarkup.tsx +49 -0
  24. package/frontend/src/components/workspace/PluginChunkLibrary.tsx +92 -0
  25. package/frontend/src/components/workspace/PluginHome.tsx +76 -0
  26. package/frontend/src/components/workspace/WorkspaceDrawers.tsx +96 -0
  27. package/frontend/src/components/workspace/WorkspacePage.tsx +95 -0
  28. package/frontend/src/components/workspace/usePluginDesign.ts +38 -0
  29. package/frontend/src/index.css +409 -136
  30. package/frontend/src/pages/HelpPage.tsx +15 -46
  31. package/frontend/src/pages/MemoryPage.tsx +19 -36
  32. package/frontend/src/pages/SettingsPage.tsx +1 -1
  33. package/metadata.plugin.schema.json +53 -227
  34. package/package.json +1 -1
  35. package/scaffold/.agent/skills/plugin/SKILL.md +13 -11
  36. package/scaffold/.agent/skills/plugin/evals/README.md +14 -21
  37. package/scaffold/.agent/skills/plugin/evals/cases/01-fabricated-seed.mjs +15 -18
  38. package/scaffold/.agent/skills/plugin/evals/cases/02-reassuring-default.mjs +19 -24
  39. package/scaffold/.agent/skills/plugin/evals/cases/03-declared-template.mjs +12 -20
  40. package/scaffold/.agent/skills/plugin/evals/cases/04-home-collects-credential.mjs +35 -0
  41. package/scaffold/.agent/skills/plugin/evals/cases/05-host-leak-in-scaffold.mjs +8 -28
  42. package/scaffold/.agent/skills/plugin/evals/cases/06-correct-plugin.mjs +85 -47
  43. package/scaffold/.agent/skills/plugin/evals/run.mjs +17 -18
  44. package/scaffold/.agent/skills/plugin/prompts/05-credentials.md +4 -4
  45. package/scaffold/.agent/skills/plugin/prompts/07-scaffold.md +2 -2
  46. package/scaffold/.agent/skills/plugin/prompts/08-verify.md +4 -4
  47. package/scaffold/.agent/skills/plugin/references/anti-patterns.md +2 -2
  48. package/scaffold/.agent/skills/plugin/references/generative-home.md +38 -0
  49. package/scaffold/.agent/skills/plugin/references/scaffold.md +5 -5
  50. package/scaffold/.agent/skills/plugin/references/surfaces.md +13 -4
  51. package/scaffold/.agent/skills/plugin/scripts/record.mjs +75 -153
  52. package/scaffold/.agent/skills/plugin/subagents/plugin-reviewer.md +4 -4
  53. package/scaffold/.agent/skills/total-recall/plugins/auth/DESIGN.md +76 -0
  54. package/scaffold/.agent/skills/total-recall/plugins/auth/README.md +3 -1
  55. package/scaffold/.agent/skills/total-recall/plugins/auth/cli.mjs +20 -15
  56. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +7 -7
  57. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +2 -1
  58. package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +13 -51
  59. package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +20 -1
  60. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-store.mjs +12 -1
  61. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/access-overview.md +17 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/agent-login.md +20 -0
  63. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/baseline-audit.md +22 -0
  64. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/credential-repository-binding.md +17 -0
  65. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/credential-store-maintenance.md +17 -0
  66. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/dashboard-password.md +18 -0
  67. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/dashboard-sessions.md +18 -0
  68. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/endpoint-probe.md +23 -0
  69. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/google-sign-in.md +21 -0
  70. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/mesh-machines.md +16 -0
  71. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/passkey-enrollment.md +21 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/registered-brains.md +16 -0
  73. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/scoped-access-keys.md +17 -0
  74. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/secret-inventory.md +25 -0
  75. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/signing-key-rotation.md +22 -0
  76. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/home.js +375 -0
  77. package/scaffold/.agent/skills/total-recall/plugins/automations/BRICK.md +7 -0
  78. package/scaffold/.agent/skills/total-recall/plugins/automations/DESIGN.md +53 -0
  79. package/scaffold/.agent/skills/total-recall/plugins/automations/LICENSE +21 -0
  80. package/scaffold/.agent/skills/total-recall/plugins/automations/README.md +66 -0
  81. package/scaffold/.agent/skills/total-recall/plugins/automations/adapters.mjs +247 -0
  82. package/scaffold/.agent/skills/total-recall/plugins/automations/capability/index.mjs +16 -0
  83. package/scaffold/.agent/skills/total-recall/plugins/automations/cli.mjs +130 -0
  84. package/{src/core/plugin-cron.mjs → scaffold/.agent/skills/total-recall/plugins/automations/cron.mjs} +1 -3
  85. package/scaffold/.agent/skills/total-recall/plugins/automations/inventory.mjs +88 -0
  86. package/scaffold/.agent/skills/total-recall/plugins/automations/package-lock.json +7661 -0
  87. package/scaffold/.agent/skills/total-recall/plugins/automations/package.json +36 -0
  88. package/scaffold/.agent/skills/total-recall/plugins/automations/plugin.json +151 -0
  89. package/scaffold/.agent/skills/total-recall/plugins/automations/scheduler.mjs +246 -0
  90. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/automations.js +2 -0
  91. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/control-ledger.md +42 -0
  92. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/local-inventory-triage.md +17 -0
  93. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/pending-control.md +39 -0
  94. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/run-evidence.md +41 -0
  95. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/schedule-vs-run-evidence.md +17 -0
  96. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/source-coverage.md +41 -0
  97. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/home.js +278 -0
  98. package/scaffold/.agent/skills/total-recall/plugins/code-quality/DESIGN.md +53 -0
  99. package/scaffold/.agent/skills/total-recall/plugins/code-quality/cli.mjs +23 -0
  100. package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/run-core.mjs +5 -3
  101. package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/check.mjs +61 -7
  102. package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/report-data.mjs +40 -14
  103. package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/report.mjs +15 -40
  104. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +7 -7
  105. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +2 -1
  106. package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +40 -40
  107. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/config.md +15 -0
  108. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/detect.md +15 -0
  109. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/gate.md +15 -0
  110. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/init.md +15 -0
  111. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/report.md +17 -0
  112. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/run.md +17 -0
  113. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/snapshot.md +15 -0
  114. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/code-quality-report.mjs +55 -23
  115. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/home.mjs +214 -0
  116. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/DESIGN.md +146 -0
  117. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +7 -7
  118. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +2 -1
  119. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +51 -34
  120. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/command.mjs +1 -1
  121. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/create.md +35 -0
  122. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/history.md +35 -0
  123. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/library.md +49 -0
  124. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/list.md +42 -0
  125. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/promote.md +40 -0
  126. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/read.md +25 -0
  127. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/remove.md +26 -0
  128. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/rollback.md +26 -0
  129. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/show.md +53 -0
  130. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/status.md +40 -0
  131. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/test-path.md +38 -0
  132. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/test.md +46 -0
  133. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/update.md +32 -0
  134. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/home.js +533 -0
  135. package/scaffold/.agent/skills/total-recall/plugins/embeddings/DESIGN.md +110 -0
  136. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +7 -7
  137. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +2 -1
  138. package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +13 -10
  139. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/benchmark.md +49 -0
  140. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/coverage.md +53 -0
  141. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/models.md +43 -0
  142. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/pull.md +41 -0
  143. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/status.md +59 -0
  144. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/home.js +353 -0
  145. package/scaffold/.agent/skills/total-recall/plugins/git/DESIGN.md +31 -0
  146. package/scaffold/.agent/skills/total-recall/plugins/git/README.md +136 -0
  147. package/scaffold/.agent/skills/total-recall/plugins/{git-sentinel → git}/cli.mjs +140 -24
  148. package/scaffold/.agent/skills/total-recall/plugins/{git-sentinel → git}/package-lock.json +9 -9
  149. package/scaffold/.agent/skills/total-recall/plugins/{git-sentinel → git}/package.json +4 -2
  150. package/scaffold/.agent/skills/total-recall/plugins/git/plugin.json +151 -0
  151. package/scaffold/.agent/skills/total-recall/plugins/git/src/lib/context.mjs +94 -0
  152. package/scaffold/.agent/skills/total-recall/plugins/git/src/lib/phase3-spec-support.mjs +50 -0
  153. package/scaffold/.agent/skills/total-recall/plugins/git/src/lib/runtime.mjs +40 -0
  154. package/scaffold/.agent/skills/total-recall/plugins/git/src/lib/spec-support.mjs +51 -0
  155. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/_support.mjs +195 -0
  156. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/auth.mjs +201 -0
  157. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/bisect.mjs +40 -0
  158. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/cli-meta.mjs +159 -0
  159. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/commit-memory.mjs +54 -0
  160. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/commit.mjs +46 -0
  161. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/fleet.mjs +174 -0
  162. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/force-push.mjs +58 -0
  163. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/group.mjs +119 -0
  164. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/handoff.mjs +59 -0
  165. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/message.mjs +22 -0
  166. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/resolve.mjs +60 -0
  167. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/rules.mjs +81 -0
  168. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/secret-firewall.mjs +92 -0
  169. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/undo.mjs +156 -0
  170. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/unmerged.mjs +182 -0
  171. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/why.mjs +16 -0
  172. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/change-comparison.md +27 -0
  173. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/commit-identity.md +22 -0
  174. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/create-worktree.md +25 -0
  175. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/registered-worktrees.md +22 -0
  176. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/remove-worktree.md +23 -0
  177. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/repository-ledger.md +25 -0
  178. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/unmerged-work.md +22 -0
  179. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/upstream-divergence.md +17 -0
  180. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/worktree-conflict-triage.md +17 -0
  181. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/worktree-terminal.md +22 -0
  182. package/scaffold/.agent/skills/total-recall/plugins/git/ui/home.js +273 -0
  183. package/scaffold/.agent/skills/total-recall/plugins/mesh/DESIGN.md +35 -0
  184. package/scaffold/.agent/skills/total-recall/plugins/mesh/README.md +4 -5
  185. package/scaffold/.agent/skills/total-recall/plugins/mesh/cli.mjs +9 -3
  186. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +7 -7
  187. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +2 -1
  188. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +37 -39
  189. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +5 -3
  190. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/active-device-dispatch.md +22 -0
  191. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/control-probe.md +25 -0
  192. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/control-server.md +22 -0
  193. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/credential-readiness.md +23 -0
  194. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/elected-leader.md +22 -0
  195. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/enrollment-key.md +22 -0
  196. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/file-receipt.md +25 -0
  197. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/fleet-execution.md +23 -0
  198. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/fleet-presence.md +23 -0
  199. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/interactive-ssh.md +22 -0
  200. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/local-enrollment.md +23 -0
  201. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/mesh-policy.md +23 -0
  202. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/network-atlas.md +25 -0
  203. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/node-roster.md +26 -0
  204. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/node-selection-proof.md +17 -0
  205. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/owner-observations.md +23 -0
  206. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/peer-path.md +23 -0
  207. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/pinned-leader.md +24 -0
  208. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/reachability-evidence-ladder.md +17 -0
  209. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/recorded-login.md +23 -0
  210. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/remote-execution.md +22 -0
  211. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/secret-grants.md +26 -0
  212. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/{card.js → home.js} +93 -22
  213. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/DESIGN.md +86 -0
  214. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +44 -9
  215. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/BRICK.md +1 -1
  216. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +18 -6
  217. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +128 -24
  218. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +7 -7
  219. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +3 -2
  220. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +188 -34
  221. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +17 -3
  222. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/adoption.mjs +2 -2
  223. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +3 -3
  224. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +92 -18
  225. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/chat.mjs +80 -0
  226. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/control.mjs +145 -0
  227. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +42 -21
  228. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch-request.mjs +4 -2
  229. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +33 -9
  230. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +55 -11
  231. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +26 -4
  232. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/hermes.mjs +29 -1
  233. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/index.mjs +1 -1
  234. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/included-usage.mjs +1 -1
  235. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/jobs.mjs +84 -0
  236. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +3 -12
  237. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/maintenance.mjs +17 -0
  238. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/mcp-server.mjs +228 -0
  239. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/process-manager.mjs +25 -2
  240. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/reasoning.mjs +1 -1
  241. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/remote-operation.mjs +5 -1
  242. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +34 -3
  243. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/reviews.mjs +25 -0
  244. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +1 -1
  245. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/claude.mjs +319 -0
  246. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/codex.mjs +387 -0
  247. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/result.mjs +67 -0
  248. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/resume.mjs +373 -0
  249. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/run.mjs +223 -0
  250. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session-jobs.mjs +72 -0
  251. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/setup.mjs +6 -3
  252. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/termination.mjs +16 -12
  253. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +32 -1
  254. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/usage-queue.mjs +1 -1
  255. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/verify-ssss.mjs +3 -3
  256. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +285 -40
  257. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +76 -9
  258. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/adapter-docs-freshness.md +16 -0
  259. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/chat-handoff.md +26 -0
  260. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/fleet-maintenance.md +21 -0
  261. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/harness-inventory.md +21 -0
  262. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/included-access.md +18 -0
  263. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/included-usage-verification.md +15 -0
  264. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/independent-review.md +17 -0
  265. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/managed-execution.md +20 -0
  266. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/official-documentation.md +18 -0
  267. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/quota-recovery.md +21 -0
  268. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/review-routing-decision.md +16 -0
  269. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/route-work.md +18 -0
  270. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/routing-evidence.md +18 -0
  271. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/run-ledger.md +18 -0
  272. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/home.js +198 -0
  273. package/scaffold/.agent/skills/total-recall/plugins/openwiki/DESIGN.md +75 -0
  274. package/scaffold/.agent/skills/total-recall/plugins/openwiki/README.md +2 -0
  275. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +64 -32
  276. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +7 -7
  277. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +2 -1
  278. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +10 -44
  279. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +5 -4
  280. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +3 -4
  281. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/ingest.mjs +23 -18
  282. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +8 -3
  283. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh-diagnostics.mjs +44 -0
  284. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +123 -113
  285. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +3 -5
  286. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/token.mjs +21 -47
  287. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +17 -6
  288. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/auto-refresh.md +18 -0
  289. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/bootstrap-pages.md +18 -0
  290. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/generate-wiki.md +21 -0
  291. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/generator-settings.md +18 -0
  292. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/host-probe.md +18 -0
  293. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/ingest-preview.md +18 -0
  294. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/link-hygiene.md +21 -0
  295. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/link-topology.md +19 -0
  296. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/passage-search.md +19 -0
  297. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/propagation-plan.md +18 -0
  298. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/provider-credentials.md +18 -0
  299. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/refresh-report.md +18 -0
  300. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/task-evidence.md +22 -0
  301. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/upstream-record.md +18 -0
  302. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/watch-upstream.md +18 -0
  303. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/wiki-atlas.md +19 -0
  304. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/panel.js +261 -513
  305. package/scaffold/.agent/skills/total-recall/plugins/security/DESIGN.md +84 -0
  306. package/scaffold/.agent/skills/total-recall/plugins/security/README.md +4 -2
  307. package/scaffold/.agent/skills/total-recall/plugins/security/cli.mjs +7 -19
  308. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +7 -7
  309. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +2 -3
  310. package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +19 -52
  311. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/device-evidence.md +21 -0
  312. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/evidence-desk.md +18 -0
  313. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/guided-device-review.md +17 -0
  314. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/host-and-network.md +21 -0
  315. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/https-headers.md +17 -0
  316. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/mesh-coverage.md +18 -0
  317. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/private-security-tools.md +16 -0
  318. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/single-origin-header-check.md +17 -0
  319. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/source-review.md +21 -0
  320. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/ssh-permission-plan.md +17 -0
  321. package/scaffold/.agent/skills/total-recall/plugins/security/ui/home.js +283 -0
  322. package/scaffold/.agent/skills/total-recall/plugins/ssss/DESIGN.md +93 -0
  323. package/scaffold/.agent/skills/total-recall/plugins/ssss/package-lock.json +2 -2
  324. package/scaffold/.agent/skills/total-recall/plugins/ssss/package.json +2 -1
  325. package/scaffold/.agent/skills/total-recall/plugins/ssss/plugin.json +5 -3
  326. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/conformance.md +26 -0
  327. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/registry.md +37 -0
  328. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/repair.md +42 -0
  329. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/scaffold.md +33 -0
  330. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/status.md +43 -0
  331. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/validate.md +34 -0
  332. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/validation-diagnostics.md +17 -0
  333. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/workspace-registry-preflight.md +17 -0
  334. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/home.js +348 -0
  335. package/scaffold/.agent/skills/total-recall/references/operations.md +3 -1
  336. package/src/cli/agent.mjs +1 -1
  337. package/src/cli/api.mjs +3 -3
  338. package/src/cli/brief.mjs +3 -0
  339. package/src/cli/command.mjs +41 -2
  340. package/src/cli/config.mjs +16 -0
  341. package/src/cli/connect.mjs +2 -7
  342. package/src/cli/dream.mjs +93 -69
  343. package/src/cli/harness.mjs +4 -4
  344. package/src/cli/help.mjs +1 -1
  345. package/src/cli/init.mjs +0 -25
  346. package/src/cli/lessons.mjs +51 -0
  347. package/src/cli/memory-plugin.mjs +1 -1
  348. package/src/cli/plugin/chunks.mjs +145 -0
  349. package/src/cli/plugin/copies.mjs +64 -14
  350. package/src/cli/plugin/create.mjs +30 -59
  351. package/src/cli/plugin/index.mjs +31 -16
  352. package/src/cli/plugin/install.mjs +10 -15
  353. package/src/cli/plugin/remove.mjs +1 -1
  354. package/src/cli/plugin/search.mjs +2 -2
  355. package/src/cli/preflight.mjs +19 -6
  356. package/src/cli/proposals.mjs +1 -1
  357. package/src/cli/recall.mjs +66 -23
  358. package/src/cli/remember.mjs +3 -14
  359. package/src/cli/server.mjs +18 -0
  360. package/src/cli/setup.mjs +2 -9
  361. package/src/cli/start.mjs +1 -0
  362. package/src/cli/startup.mjs +19 -0
  363. package/src/cli/task.mjs +9 -2
  364. package/src/cli/update.mjs +6 -2
  365. package/src/core/access-ledger.mjs +78 -0
  366. package/src/core/agent-manager.mjs +2 -2
  367. package/src/core/app-deploy/design-tokens.mjs +14 -9
  368. package/src/core/app-deploy/ui-elements.mjs +1 -1
  369. package/src/core/brain-locate.mjs +15 -0
  370. package/src/core/brain-registry.mjs +5 -0
  371. package/src/core/brain-updates.mjs +35 -11
  372. package/src/core/claude-hooks.mjs +3 -1
  373. package/src/core/cleanup-task.mjs +15 -0
  374. package/src/core/cli-commands.mjs +2 -0
  375. package/src/core/cli-maintenance.mjs +4 -1
  376. package/src/core/cli-semantic-index.mjs +23 -3
  377. package/src/core/context-compiler.mjs +20 -0
  378. package/src/core/daemon-control.mjs +5 -1
  379. package/src/core/daemon-loop.mjs +39 -62
  380. package/src/core/dashboard-bundle.mjs +261 -0
  381. package/src/core/default-plugins.mjs +1 -1
  382. package/src/core/dream.mjs +33 -105
  383. package/src/core/ensure-dependencies.mjs +152 -0
  384. package/src/core/fast-recall.mjs +2 -2
  385. package/src/core/field-evaluation.mjs +23 -0
  386. package/src/core/gate-mode.mjs +1 -1
  387. package/src/core/harness-hooks.mjs +14 -2
  388. package/src/core/lesson-hooks.mjs +74 -0
  389. package/src/core/lesson-memory.mjs +24 -0
  390. package/src/core/lesson-sessions.mjs +52 -0
  391. package/src/core/lessons.mjs +96 -0
  392. package/src/core/memory-brain.mjs +30 -8
  393. package/src/core/meta-harness.mjs +2 -2
  394. package/src/core/optimizer.mjs +66 -165
  395. package/src/core/plugin-activation.mjs +63 -20
  396. package/src/core/plugin-contracts/{card.mjs → manifest.mjs} +26 -57
  397. package/src/core/plugin-contracts/startup-check.mjs +49 -0
  398. package/src/core/plugin-contracts/ui.mjs +9 -3
  399. package/src/core/plugin-distribution.mjs +6 -6
  400. package/src/core/plugin-lifecycle.mjs +58 -0
  401. package/src/core/plugin-loader.mjs +21 -8
  402. package/src/core/plugin-runner.mjs +21 -10
  403. package/src/core/plugin-runtime.mjs +40 -1
  404. package/src/core/plugin-startup-checks.mjs +44 -0
  405. package/src/core/plugin-state.mjs +19 -5
  406. package/src/core/plugin-store.mjs +64 -33
  407. package/src/core/post-mortem.mjs +52 -36
  408. package/src/core/preflight-gate.mjs +23 -2
  409. package/src/core/project-id.mjs +15 -5
  410. package/src/core/proposal-applier.mjs +31 -2
  411. package/src/core/repo-sync.mjs +4 -6
  412. package/src/core/required-plugins.mjs +57 -10
  413. package/src/core/rule-length.mjs +23 -0
  414. package/src/core/runtime.mjs +1 -1
  415. package/src/core/scheduler.mjs +35 -43
  416. package/src/core/schema.mjs +3 -2
  417. package/src/core/search.mjs +4 -3
  418. package/src/core/server-service.mjs +148 -0
  419. package/src/core/session-watcher.mjs +19 -1
  420. package/src/core/skill-gap.mjs +16 -0
  421. package/src/core/ssss-kernel-bridge.mjs +32 -4
  422. package/src/core/ssss-operation-service.mjs +1 -0
  423. package/src/core/startup-health.mjs +34 -4
  424. package/src/core/surface.mjs +65 -54
  425. package/src/core/task-executors.mjs +54 -106
  426. package/src/core/testing/plugin-fixture.mjs +22 -21
  427. package/src/core/throttled-fetch.mjs +25 -18
  428. package/src/core/ui-chunk-choice.mjs +77 -0
  429. package/src/core/ui-chunk.registry.json +23 -0
  430. package/src/core/ui-chunks.mjs +434 -0
  431. package/src/core/validated-write.mjs +1 -0
  432. package/src/core/vault-cache.mjs +58 -59
  433. package/src/core/vector-field.mjs +134 -192
  434. package/src/core/workspace-compositions.mjs +151 -0
  435. package/src/core/workspace-drawers.mjs +79 -0
  436. package/src/server/api.mjs +4 -27
  437. package/src/server/index.mjs +28 -21
  438. package/src/server/invoke-core-child.mjs +24 -0
  439. package/src/server/invoke-core-operations.mjs +102 -0
  440. package/src/server/memory-events.mjs +31 -0
  441. package/src/server/plugin-brain-targets.mjs +89 -0
  442. package/src/server/rest.mjs +2 -0
  443. package/src/server/route-inventory.mjs +3 -2
  444. package/src/server/route-manifest.json +47 -55
  445. package/src/server/routes/_shared.mjs +7 -14
  446. package/src/server/routes/brains.mjs +29 -62
  447. package/src/server/routes/context.mjs +0 -41
  448. package/src/server/routes/dashboard.mjs +26 -0
  449. package/src/server/routes/invoke.mjs +26 -1
  450. package/src/server/routes/plugins.mjs +154 -45
  451. package/src/server/routes/ssss.mjs +0 -169
  452. package/src/server/routes/system.mjs +0 -15
  453. package/src/server/routes/tasks.mjs +0 -26
  454. package/src/server/routes/ui-chunks.mjs +192 -0
  455. package/src/server/routes/vault.mjs +2 -23
  456. package/frontend/dist/assets/index-DD4qONvH.js +0 -5607
  457. package/frontend/dist/assets/index-DtwsDyFM.css +0 -1
  458. package/frontend/src/components/plugins/card/CardEngine.tsx +0 -108
  459. package/frontend/src/components/plugins/card/CardScenes.tsx +0 -103
  460. package/frontend/src/components/plugins/card/ExecutionPicker.tsx +0 -64
  461. package/frontend/src/components/plugins/card/args.ts +0 -28
  462. package/frontend/src/components/plugins/card/card.css +0 -32
  463. package/frontend/src/components/plugins/card/cli-line.ts +0 -13
  464. package/frontend/src/components/plugins/card/contract.ts +0 -91
  465. package/frontend/src/components/plugins/card/format.ts +0 -49
  466. package/frontend/src/components/plugins/card/runner-context.ts +0 -11
  467. package/frontend/src/components/plugins/card/runner.tsx +0 -43
  468. package/frontend/src/components/plugins/card/theme.ts +0 -35
  469. package/frontend/src/components/plugins/card/use-source.ts +0 -22
  470. package/frontend/src/components/plugins/card/widgets.tsx +0 -94
  471. package/frontend/src/components/plugins/workspace/WorkspaceHost.tsx +0 -23
  472. package/frontend/src/pages/PluginsPage.tsx +0 -1719
  473. package/scaffold/.agent/skills/plugin/evals/cases/04-card-collects-credential.mjs +0 -47
  474. package/scaffold/.agent/skills/plugin/prompts/06-card.md +0 -46
  475. package/scaffold/.agent/skills/plugin/references/card.md +0 -90
  476. package/scaffold/.agent/skills/plugin/subagents/card-designer.md +0 -60
  477. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/DESIGN.md +0 -67
  478. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/card.js +0 -1179
  479. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/DESIGN.md +0 -32
  480. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +0 -588
  481. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +0 -575
  482. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/DESIGN.md +0 -32
  483. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +0 -482
  484. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/README.md +0 -53
  485. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/plugin.json +0 -129
  486. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/DESIGN.md +0 -100
  487. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/card.js +0 -637
  488. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/DESIGN.md +0 -217
  489. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +0 -32
  490. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +0 -1276
  491. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +0 -45
  492. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +0 -1401
  493. package/scaffold/.agent/skills/total-recall/plugins/security/scripts/build-ui.mjs +0 -4
  494. package/scaffold/.agent/skills/total-recall/plugins/security/ui/DESIGN.md +0 -41
  495. package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +0 -396
  496. package/scaffold/.agent/skills/total-recall/plugins/security/ui/panel.js +0 -98
  497. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/DESIGN.md +0 -15
  498. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/card.js +0 -182
  499. package/src/core/append-log.mjs +0 -131
  500. package/src/core/plugin-tasks.mjs +0 -173
  501. package/templates/onboarding-interview.md +0 -82
  502. /package/scaffold/.agent/skills/total-recall/plugins/{git-sentinel → git}/LICENSE +0 -0
@@ -16,12 +16,14 @@ export async function listMemory(brainId?: string, category?: string, status?: s
16
16
  }
17
17
 
18
18
  const ids = brainId.split(',')
19
+ const globalParams = new URLSearchParams(params)
20
+ globalParams.set('brain', 'global')
19
21
  const fetchPromises = ids.map(async (id) => {
20
22
  const url = id === 'global'
21
- ? `${API_BASE}/api/memory?${params}`
22
- : `${API_BASE}/api/brains/${id}/nodes?${params}`
23
+ ? `${API_BASE}/api/memory?${globalParams}`
24
+ : `${API_BASE}/api/brains/${encodeURIComponent(id)}/nodes?${params}`
23
25
  try {
24
- const res = await apiFetch(url)
26
+ const res = await apiFetch(url, { cache: 'no-store' })
25
27
  if (!res.ok) return []
26
28
  const data = await res.json()
27
29
  return Array.isArray(data) ? data : (data.nodes || [])
@@ -54,10 +56,11 @@ export async function listMemory(brainId?: string, category?: string, status?: s
54
56
  return merged
55
57
  }
56
58
 
57
- export async function searchMemory(query: string, category?: string): Promise<MemoryNode[]> {
59
+ export async function searchMemory(query: string, category?: string, brainId?: string): Promise<MemoryNode[]> {
58
60
  const params = new URLSearchParams({ q: query })
59
61
  if (category) params.set('category', category)
60
- const res = await apiFetch(`${API_BASE}/api/memory?${params}`)
62
+ if (brainId) params.set('brain', brainId)
63
+ const res = await apiFetch(`${API_BASE}/api/memory?${params}`, { cache: 'no-store' })
61
64
  if (!res.ok) throw new Error(`Memory API error: ${res.status}`)
62
65
  const data = await res.json()
63
66
  return Array.isArray(data) ? data : (data.nodes || [])
@@ -167,10 +170,12 @@ export async function fetchOpenWikiNodes(
167
170
  // Reuse listMemory brain routing (global vs project:name), then keep openwiki-tagged only.
168
171
  // Server also filters tag=openwiki when we hit /api/memory?tag=openwiki.
169
172
  const params = new URLSearchParams({ tag: 'openwiki', limit: '500' })
173
+ const globalParams = new URLSearchParams(params)
174
+ globalParams.set('brain', 'global')
170
175
  const ids = active.split(',').map((s) => s.trim()).filter(Boolean)
171
176
 
172
177
  if (ids.length === 0 || (ids.length === 1 && ids[0] === 'global')) {
173
- const res = await apiFetch(`${API_BASE}/api/memory?${params}`)
178
+ const res = await apiFetch(`${API_BASE}/api/memory?${globalParams}`, { cache: 'no-store' })
174
179
  if (!res.ok) throw new Error(`OpenWiki nodes error: ${res.status}`)
175
180
  const data = await res.json()
176
181
  const nodes = Array.isArray(data) ? data : (data.nodes ?? [])
@@ -181,7 +186,7 @@ export async function fetchOpenWikiNodes(
181
186
  const fetchPromises = ids.map(async (id) => {
182
187
  try {
183
188
  if (id === 'global') {
184
- const res = await apiFetch(`${API_BASE}/api/memory?${params}`)
189
+ const res = await apiFetch(`${API_BASE}/api/memory?${globalParams}`, { cache: 'no-store' })
185
190
  if (!res.ok) return []
186
191
  const data = await res.json()
187
192
  return Array.isArray(data) ? data : (data.nodes ?? [])
@@ -190,7 +195,7 @@ export async function fetchOpenWikiNodes(
190
195
  const res = await apiFetch(`${API_BASE}/api/brains/${encodeURIComponent(id)}/nodes`)
191
196
  if (!res.ok) {
192
197
  // Fallback: memory list with brain header already set by apiFetch
193
- const res2 = await apiFetch(`${API_BASE}/api/memory?${params}&brain=${encodeURIComponent(id)}`)
198
+ const res2 = await apiFetch(`${API_BASE}/api/memory?${params}&brain=${encodeURIComponent(id)}`, { cache: 'no-store' })
194
199
  if (!res2.ok) return []
195
200
  const data2 = await res2.json()
196
201
  return Array.isArray(data2) ? data2 : (data2.nodes ?? [])
@@ -0,0 +1,23 @@
1
+ import { apiFetch, API_BASE } from './_base'
2
+ import type { PluginInfo } from './plugins'
3
+
4
+ export async function readSavedPluginCredentials() {
5
+ const response = await apiFetch(`${API_BASE}/api/plugins/auth/secrets?catalog=0`)
6
+ if (!response.ok) throw new Error('Could not check saved credentials.')
7
+ const payload = await response.json()
8
+ const rows = Array.isArray(payload) ? payload : payload?.keys
9
+ if (!Array.isArray(rows)) throw new Error('Could not check saved credentials.')
10
+ return new Set<string>(rows.filter(row => typeof row?.key === 'string' && row.set !== false).map(row => row.key))
11
+ }
12
+
13
+ export async function savePluginCredential(plugin: PluginInfo, key: string, value: string, brainId?: string) {
14
+ const runtime = plugin.manifest?.runtime as { modules?: { credentials?: string } } | undefined
15
+ const route = runtime?.modules?.credentials
16
+ ? `/api/plugins/${encodeURIComponent(plugin.id)}/credentials${brainId ? `?brain=${encodeURIComponent(brainId)}` : ''}`
17
+ : '/api/plugins/auth/secrets'
18
+ const response = await apiFetch(API_BASE + route, {
19
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
20
+ body: JSON.stringify({ key, value, tags: [`plugin:${plugin.id}`] }),
21
+ })
22
+ if (!response.ok) throw new Error('Could not verify and save the credential.')
23
+ }
@@ -4,7 +4,7 @@
4
4
  // plugin came from, its content hash, whether it is shared, and — for peers —
5
5
  // whether that peer answered. There are no ratings, reviews or install counts.
6
6
 
7
- import { apiFetch, API_BASE, patch } from "./_base"
7
+ import { apiFetch, API_BASE } from "./_base"
8
8
 
9
9
  export type PluginSourceKind = "bundled" | "public" | "peer" | "git" | "local" | "link"
10
10
 
@@ -21,33 +21,9 @@ export interface PluginTask {
21
21
  last_run: string | null
22
22
  }
23
23
 
24
- export interface CardFaceAction {
25
- subcommand: string
26
- label: string
27
- icon?: string
28
- color?: string
29
- }
30
-
31
- export interface CardFaceMetric {
32
- label: string
33
- value: string
34
- }
35
-
36
- export interface CardFaceConfig {
37
- skin?: string
38
- theme?: string
39
- headline?: string
40
- primary_color?: string
41
- secondary_color?: string
42
- accent_color?: string
43
- touch_layout?: string
44
- quick_actions?: CardFaceAction[]
45
- metrics?: CardFaceMetric[]
46
- interactive?: boolean
47
- }
48
-
49
24
  export interface PluginInfo {
50
25
  id: string
26
+ core?: boolean
51
27
  name: string
52
28
  version: string
53
29
  description: string
@@ -57,7 +33,7 @@ export interface PluginInfo {
57
33
  use_cases: string[]
58
34
  valid: boolean
59
35
  errors: string[]
60
- scope: "project" | "global"
36
+ scope: "project" | "global" | "scaffold"
61
37
  linked: boolean
62
38
  dir: string
63
39
  shared: boolean
@@ -73,16 +49,26 @@ export interface PluginInfo {
73
49
  categories: Array<{ name: string; description?: string; node_type?: string }>
74
50
  tasks: PluginTask[]
75
51
  openwiki_hubs: Array<{ title?: string; path: string }>
76
- cli: { command: string | null; subcommands: Array<{ name: string; description?: string }> } | null
52
+ cli: { command: string | null; subcommands: Array<{ name: string; description?: string; sensitive_output?: boolean; terminal_only?: boolean }> } | null
77
53
  has_generator: boolean
78
54
  branding?: { icon?: string | null; image?: string | null; color?: string | null; badge?: string | null; name?: string; wordmark?: string; accent?: string; background?: string }
79
- card_face?: CardFaceConfig
80
55
  locked?: boolean
81
56
  store_deployed?: boolean
82
57
  secrets?: Array<{ key: string; description?: string; required?: boolean }>
83
58
  manifest?: Record<string, unknown>
84
- activation?: { state: 'active' | 'inactive'; enabled: boolean }
85
- ui?: { elements: Array<{ id: string; kind: string; tag: string; module: string; description?: string }> } | null
59
+ activation?: { state: 'active' | 'inactive' | 'error' | 'mixed'; enabled: boolean; required?: boolean; mode?: 'on-use' }
60
+ activationByBrain?: BrainPluginActivation[]
61
+ servingAvailable?: boolean
62
+ ui?: { home?: string; elements: Array<{ id: string; kind: string; tag: string; module: string; description?: string }> } | null
63
+ }
64
+
65
+ export interface BrainPluginActivation {
66
+ brainId: string
67
+ name: string
68
+ state: 'active' | 'inactive' | 'error' | 'unavailable'
69
+ enabled: boolean
70
+ required?: boolean
71
+ mode?: 'on-use'
86
72
  }
87
73
 
88
74
  export interface BundledPlugin {
@@ -154,20 +140,18 @@ async function post(url: string, body: unknown, method = "POST"): Promise<Result
154
140
  }
155
141
  }
156
142
 
157
- export async function fetchPlugins(): Promise<PluginInfo[]> {
158
- try {
159
- const res = await apiFetch(`${API_BASE}/api/plugins`)
160
- if (!res.ok) return []
161
- const data = await readJson(res)
162
- return Array.isArray(data.plugins) ? data.plugins : []
163
- } catch {
164
- return []
165
- }
143
+ export async function fetchPlugins(brain?: string): Promise<PluginInfo[]> {
144
+ const selector = brain === undefined ? '' : `?brain=${encodeURIComponent(brain)}`
145
+ const res = await apiFetch(`${API_BASE}/api/plugins${selector}`, { cache: 'no-store' })
146
+ const data = await readJson(res)
147
+ if (!res.ok) throw new Error(data.error || `Could not load plugins (${res.status})`)
148
+ if (!Array.isArray(data.plugins)) throw new Error("The server did not return a plugin list")
149
+ return data.plugins
166
150
  }
167
151
 
168
152
  export async function fetchPlugin(id: string): Promise<PluginInfo | null> {
169
153
  try {
170
- const res = await apiFetch(`${API_BASE}/api/plugins/${encodeURIComponent(id)}`)
154
+ const res = await apiFetch(`${API_BASE}/api/plugins/${encodeURIComponent(id)}`, { cache: 'no-store' })
171
155
  if (!res.ok) return null
172
156
  const data = await readJson(res)
173
157
  return data.plugin || null
@@ -178,7 +162,7 @@ export async function fetchPlugin(id: string): Promise<PluginInfo | null> {
178
162
 
179
163
  export async function fetchBundledPlugins(): Promise<BundledPlugin[]> {
180
164
  try {
181
- const res = await apiFetch(`${API_BASE}/api/plugins/available`)
165
+ const res = await apiFetch(`${API_BASE}/api/plugins/available`, { cache: 'no-store' })
182
166
  if (!res.ok) return []
183
167
  const data = await readJson(res)
184
168
  return Array.isArray(data.plugins) ? data.plugins : []
@@ -190,7 +174,7 @@ export async function fetchBundledPlugins(): Promise<BundledPlugin[]> {
190
174
  /** Asks every mesh peer live; `null` means this node could not ask at all. */
191
175
  export async function fetchPeerPlugins(): Promise<PeersResponse | null> {
192
176
  try {
193
- const res = await apiFetch(`${API_BASE}/api/plugins/peers`)
177
+ const res = await apiFetch(`${API_BASE}/api/plugins/peers`, { cache: 'no-store' })
194
178
  if (!res.ok) return null
195
179
  const data = await readJson(res)
196
180
  return { mesh: data.mesh || { available: false, configured: false }, peers: Array.isArray(data.peers) ? data.peers : [] }
@@ -215,21 +199,21 @@ export function updatePluginBranding(id: string, branding: { icon?: string; imag
215
199
  return post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/branding`, { branding })
216
200
  }
217
201
 
218
- export function updatePluginCardFace(
219
- id: string,
220
- updates: { card_face?: CardFaceConfig; branding?: Record<string, unknown> }
221
- ): Promise<Result & { card_face?: CardFaceConfig; branding?: Record<string, unknown> }> {
222
- return patch(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/card-face`, updates)
223
- }
224
-
225
202
  export function setPluginLocked(id: string, locked: boolean): Promise<Result> {
226
203
  return post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/lock`, { locked })
227
204
  }
228
205
 
229
- export function setPluginActivation(id: string, enabled: boolean): Promise<Result & { activation?: { enabled: boolean; state: string } }> {
230
- return post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/activation`, { enabled }, "PUT")
206
+ export function setPluginActivation(id: string, value: boolean | 'on-use' | 'use', brainIds?: string[]): Promise<Result & {
207
+ activation?: { enabled: boolean; state: string }
208
+ cleanup?: PluginCleanup
209
+ results?: Array<Pick<BrainPluginActivation, 'brainId' | 'name'> & Result & { cleanup?: PluginCleanup }>
210
+ }> {
211
+ const policy = typeof value === 'boolean' ? { enabled: value } : { mode: value }
212
+ return post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/activation`, { ...policy, brainIds }, "PUT")
231
213
  }
232
214
 
215
+ interface PluginCleanup { ok: boolean; state: string; error?: string }
216
+
233
217
  export function deployPluginToStore(id: string, autoLock = true): Promise<Result & { storePackage?: any }> {
234
218
  return post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/deploy-store`, { autoLock })
235
219
  }
@@ -238,7 +222,7 @@ export async function runPluginCommand(
238
222
  id: string,
239
223
  subcommand = "",
240
224
  args: string[] = [],
241
- options?: { stdin?: string; execution?: PluginExecution }
225
+ options?: { stdin?: string; execution?: PluginExecution; brainId?: string }
242
226
  ): Promise<{ success: boolean; output?: string; error?: string; exitCode?: number | null; timedOut?: boolean }> {
243
227
  const res = await post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/run`, { subcommand, args, ...(options || {}) })
244
228
  if (res.error) return { success: false, error: res.error }
@@ -0,0 +1,97 @@
1
+ import { apiFetch, getApiBase } from './_base'
2
+
3
+ export type DrawerSide = 'right' | 'bottom'
4
+ export interface PanelRef { plugin: string; element: string }
5
+ export interface DrawerConfig {
6
+ html: string
7
+ chunks: string[]
8
+ panels: PanelRef[]
9
+ shortcuts: { label: string; href: string }[]
10
+ }
11
+ export interface DrawerRevision { config: DrawerConfig; version: string | null }
12
+ export interface PluginDesign { revision: string | null; css: string; components: string[] }
13
+ export interface WorkspaceChunk {
14
+ key: string
15
+ plugin: string
16
+ id: string
17
+ title: string
18
+ description: string
19
+ surfaces: string[]
20
+ panel?: string
21
+ operations?: string[]
22
+ data?: string[]
23
+ sha256: string
24
+ }
25
+
26
+ export interface SavedPageSummary { id: string; title: string; version: string }
27
+ export interface SavedPage extends SavedPageSummary { chunks: WorkspaceChunk[] }
28
+
29
+ export function listSavedPages(brainId: string, signal: AbortSignal) {
30
+ return request<{ pages: SavedPageSummary[] }>(
31
+ `/api/workspace/pages?brain=${encodeURIComponent(brainId)}`, { signal },
32
+ )
33
+ }
34
+
35
+ export function readSavedPage(id: string, brainId: string, signal: AbortSignal) {
36
+ return request<SavedPage>(
37
+ `/api/workspace/pages/${encodeURIComponent(id)}?brain=${encodeURIComponent(brainId)}`, { signal },
38
+ )
39
+ }
40
+
41
+ export function readWorkspaceComposition(plugin: string, signal: AbortSignal, brainId?: string) {
42
+ const scope = brainId ? `?brain=${encodeURIComponent(brainId)}` : ''
43
+ return request<{ chunks: WorkspaceChunk[]; version: string | null }>(
44
+ `/api/ui-chunks/${encodeURIComponent(plugin)}/composition/current${scope}`, { signal },
45
+ )
46
+ }
47
+
48
+ async function request<T>(path: string, options?: RequestInit): Promise<T> {
49
+ const response = await apiFetch(getApiBase() + path, { cache: 'no-store', ...options })
50
+ if (!response.headers.get('content-type')?.includes('application/json')) {
51
+ throw new Error('This server does not support saved drawer layouts yet.')
52
+ }
53
+ const data = await response.json()
54
+ if (!response.ok) throw new Error(data.error?.message || data.error || 'Could not load the workspace layout.')
55
+ return data as T
56
+ }
57
+
58
+ export function readDrawer(side: DrawerSide, signal?: AbortSignal) {
59
+ return request<DrawerRevision>(`/api/dashboard/drawers/${side}`, { signal })
60
+ }
61
+
62
+ export function saveDrawer(side: DrawerSide, revision: DrawerRevision) {
63
+ return request<DrawerRevision>(`/api/dashboard/drawers/${side}`, {
64
+ method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(revision),
65
+ })
66
+ }
67
+
68
+ export function findWorkspaceChunks(
69
+ surface: DrawerSide | 'page', query: string, signal?: AbortSignal, plugin?: string,
70
+ brainId?: string, page?: { limit: number; offset: number },
71
+ ) {
72
+ const params = new URLSearchParams({ surface, q: query, limit: String(page?.limit ?? 24) })
73
+ if (page) params.set('offset', String(page.offset))
74
+ if (plugin) params.set('plugin', plugin)
75
+ if (brainId) params.set('brain', brainId)
76
+ return request<{ chunks: WorkspaceChunk[]; total: number }>(`/api/ui-chunks?${params}`, { signal })
77
+ }
78
+
79
+ export function readPluginDesign(plugin: string, revision: string | null, signal: AbortSignal, brainId?: string) {
80
+ const params = new URLSearchParams()
81
+ if (revision) params.set('revision', revision)
82
+ if (brainId) params.set('brain', brainId)
83
+ const query = params.size ? `?${params}` : ''
84
+ return request<PluginDesign | { unchanged: true }>(
85
+ `/api/ui-chunks/${encodeURIComponent(plugin)}/design/revision${query}`, { signal },
86
+ )
87
+ }
88
+
89
+ export async function readWorkspaceChunk(key: string, surface: DrawerSide | 'page', signal?: AbortSignal, brainId?: string) {
90
+ const [plugin, id] = key.split(':')
91
+ const params = new URLSearchParams({ surface })
92
+ if (brainId) params.set('brain', brainId)
93
+ const data = await request<{ chunk: WorkspaceChunk & { html: string } }>(
94
+ `/api/ui-chunks/${encodeURIComponent(plugin)}/${encodeURIComponent(id)}?${params}`, { signal },
95
+ )
96
+ return data.chunk
97
+ }
@@ -16,6 +16,7 @@ interface BrainInfo {
16
16
  interface BrainSelectorProps {
17
17
  activeBrainId: string
18
18
  onBrainChange: (brainId: string) => void
19
+ onSelectionComplete?: () => void
19
20
  }
20
21
 
21
22
  function layerDot(layer: string, multi = false): string {
@@ -31,7 +32,7 @@ function layerBadge(layer: string): string {
31
32
  return 'P'
32
33
  }
33
34
 
34
- export default function BrainSelector({ activeBrainId, onBrainChange }: BrainSelectorProps) {
35
+ export default function BrainSelector({ activeBrainId, onBrainChange, onSelectionComplete }: BrainSelectorProps) {
35
36
  const [brains, setBrains] = useState<BrainInfo[]>([])
36
37
  const [expanded, setExpanded] = useState(false)
37
38
  const [loading, setLoading] = useState(true)
@@ -42,7 +43,7 @@ export default function BrainSelector({ activeBrainId, onBrainChange }: BrainSel
42
43
  setLoading(true)
43
44
  setError(null)
44
45
  try {
45
- const res = await apiFetch(`${getApiBase()}/api/brains`)
46
+ const res = await apiFetch(`${getApiBase()}/api/brains`, { cache: 'no-store' })
46
47
  if (!res.ok) {
47
48
  const body = await res.json().catch(() => ({}))
48
49
  throw new Error(body.error || `Brains API ${res.status}`)
@@ -121,6 +122,7 @@ export default function BrainSelector({ activeBrainId, onBrainChange }: BrainSel
121
122
  const handleSelectOnly = (id: string) => {
122
123
  setSelection([id])
123
124
  setExpanded(false)
125
+ onSelectionComplete?.()
124
126
  }
125
127
 
126
128
  if (loading) {
@@ -224,7 +226,7 @@ export default function BrainSelector({ activeBrainId, onBrainChange }: BrainSel
224
226
  data-testid="brain-selector-menu"
225
227
  style={{
226
228
  position: 'absolute',
227
- bottom: '100%',
229
+ top: '100%',
228
230
  left: 0,
229
231
  right: 0,
230
232
  marginBottom: 6,
@@ -360,6 +362,10 @@ export default function BrainSelector({ activeBrainId, onBrainChange }: BrainSel
360
362
  </div>
361
363
  )
362
364
  })}
365
+ {onSelectionComplete && <button type="button" className="btn btn-ghost btn-sm" onClick={() => {
366
+ setExpanded(false)
367
+ onSelectionComplete()
368
+ }}>Done</button>}
363
369
  </div>
364
370
  )}
365
371
  </div>
@@ -2,8 +2,10 @@ import { useEffect, useRef, useState } from 'react'
2
2
  import type { PluginInfo } from '../../api/plugins'
3
3
  import { runPluginCommand } from '../../api/plugins'
4
4
  import { apiFetch, API_BASE } from '../../api/_base'
5
- import { pluginFrameDocument, allowedFrameCommand, pluginCommandTimeouts, sanitizePluginScreens } from './plugin-frame'
6
- import type { PluginScreen } from './plugin-frame'
5
+ import { readSavedPluginCredentials, savePluginCredential } from '../../api/plugin-credentials'
6
+ import { changeAuthCredential, readAuthInventory } from '../../api/auth-inventory'
7
+ import { usePluginDesign } from '../workspace/usePluginDesign'
8
+ import { pluginFrameDocument, allowedFrameCommand, browserPluginOperations, pluginCommandTimeouts } from './plugin-frame'
7
9
 
8
10
  export interface PluginElement {
9
11
  id: string
@@ -11,10 +13,13 @@ export interface PluginElement {
11
13
  tag: string
12
14
  module: string
13
15
  description?: string
16
+ events?: string[]
17
+ props?: { view?: unknown }
14
18
  }
15
19
 
16
20
  export function pluginElements(plugin: PluginInfo): PluginElement[] {
17
- return (plugin.manifest?.ui as { elements?: PluginElement[] } | undefined)?.elements || plugin.ui?.elements || []
21
+ const elements = (plugin.manifest?.ui as { elements?: PluginElement[] } | undefined)?.elements || plugin.ui?.elements || []
22
+ return elements.filter(element => ['panel', 'form', 'list', 'detail', 'settings', 'widget'].includes(element.kind))
18
23
  }
19
24
 
20
25
  export function parsePluginOutput(rawOutput: string | undefined): unknown {
@@ -40,57 +45,93 @@ export function parsePluginOutput(rawOutput: string | undefined): unknown {
40
45
  }
41
46
  }
42
47
 
43
- /** Loads owner code; no plugin identities or provider behavior belong here. */
44
- export function PluginPanel({ plugin, elementId, readOnly = false }: { plugin: PluginInfo; elementId?: string; readOnly?: boolean }) {
48
+ /** Loads owner code in an isolated document. Auth's inventory is a privileged bridge. */
49
+ export function PluginPanel({ plugin, elementId, readOnly = false, designCss, brainId }: {
50
+ plugin: PluginInfo; elementId?: string; readOnly?: boolean; designCss?: string; brainId?: string
51
+ }) {
45
52
  const elements = pluginElements(plugin).filter(element => element.kind !== 'settings' && (!elementId || element.id === elementId))
46
- const cardElement = elements.find(item => item.kind === 'card')
47
- const [selected, setSelected] = useState(elementId || cardElement?.id || elements[0]?.id || '')
53
+ const home = (plugin.manifest?.ui as { home?: string } | undefined)?.home || plugin.ui?.home
54
+ const [selected, setSelected] = useState(elementId || home || elements[0]?.id || '')
55
+ const currentElement = elements.find(item => item.id === selected) || elements[0]
56
+ const usesOwnerDesign = designCss === undefined && currentElement
57
+ const ownerDesign = usePluginDesign(usesOwnerDesign ? plugin.id : undefined, brainId)
58
+ const css = designCss ?? ownerDesign?.design?.css ?? ''
48
59
  const [error, setError] = useState('')
49
60
  const frame = useRef<HTMLIFrameElement>(null)
61
+ const activeChannel = useRef('')
50
62
  const [document, setDocument] = useState('')
51
63
  const [height, setHeight] = useState(240)
52
64
 
53
65
  useEffect(() => {
54
66
  let disposed = false
67
+ const controller = new AbortController()
55
68
  setError('')
56
69
  setDocument('')
57
70
  const channel = crypto.randomUUID()
71
+ activeChannel.current = channel
58
72
  const commands = plugin.manifest?.cli as { subcommands?: Array<{ name: string; effect?: string; args?: Array<{ secret?: boolean; type?: string; flag?: string }> }> } | undefined
59
73
  const readCommands = new Set((commands?.subcommands || []).filter(command => command.effect === 'read').map(command => command.name))
60
- const allowed = new Set((plugin.cli?.subcommands || []).filter(command => !readOnly || readCommands.has(command.name)).map(command => command.name))
74
+ const allowed = new Set(browserPluginOperations(plugin).filter(command => !readOnly || readCommands.has(command.name)).map(command => command.name))
61
75
  const secretCommands = new Set((commands?.subcommands || []).filter(command => {
62
76
  const secrets = command.args?.filter(arg => arg.secret === true) || []
63
77
  return secrets.length === 1 && secrets[0].type === 'string' && secrets[0].flag === undefined
64
78
  }).map(command => command.name))
65
79
  const element = elements.find(item => item.id === selected) || elements[0]
66
- let ownerScreens: PluginScreen[] = []
67
- const showScreen = (event: Event) => {
68
- const detail = (event as CustomEvent).detail
69
- if (disposed || element?.kind !== 'card' || detail?.pluginId !== plugin.id || !ownerScreens.some(screen => screen.id === detail.screen)) return
70
- frame.current?.contentWindow?.postMessage({ channel, type: 'show-screen', screen: detail.screen }, '*')
71
- }
80
+ const credentials = plugin.secrets || []
81
+ const credentialPanel = element?.events?.includes('save-token') === true && !!element.props?.view && credentials.length === 1
82
+ const authInventory = plugin.id === 'auth' && element?.events?.includes('auth-inventory') === true
83
+ const authChanges = authInventory && !readOnly && element?.events?.includes('auth-credential-mutate') === true
72
84
  let active = 0
85
+ let changingCredential = false
73
86
  const message = async (event: MessageEvent) => {
74
87
  if (disposed || event.source !== frame.current?.contentWindow || event.origin !== 'null' || event.data?.channel !== channel) return
75
88
  const data = event.data
76
- if (data.type === 'screens') {
77
- if (element?.kind === 'card') {
78
- ownerScreens = sanitizePluginScreens(data.screens)
79
- window.dispatchEvent(new CustomEvent('plugin-screens', { detail: { pluginId: plugin.id, screens: ownerScreens } }))
80
- }
89
+ if (data.type === 'height' && Number.isFinite(data.height)) setHeight(Math.max(128, Math.min(1000, data.height)))
90
+ if (data.type === 'error') setError('Could not open the plugin interface')
91
+ const target = event.source as Window
92
+ const reply = (result?: unknown, error?: string) => { if (!disposed) target.postMessage({ channel, type: 'result', requestId: data.requestId, result, error }, '*') }
93
+ if (data.type === 'auth-credential-mutate') {
94
+ if (!authChanges || changingCredential) { reply(undefined, 'Credential changes are unavailable'); return }
95
+ changingCredential = true
96
+ try {
97
+ reply(await changeAuthCredential(data.change, controller.signal))
98
+ } catch (error) {
99
+ reply(undefined, error instanceof Error ? error.message : 'Could not change the credential')
100
+ } finally { changingCredential = false }
81
101
  return
82
102
  }
83
- if (data.type === 'screen-changed') {
84
- if (element?.kind === 'card' && ownerScreens.some(screen => screen.id === data.screen))
85
- window.dispatchEvent(new CustomEvent('plugin-screen-changed', { detail: { pluginId: plugin.id, screen: data.screen } }))
103
+ if (data.type === 'auth-inventory') {
104
+ if (!authInventory || active >= 12) { reply(undefined, 'Auth inventory is unavailable'); return }
105
+ active++
106
+ try {
107
+ reply(await readAuthInventory(data.resource, controller.signal))
108
+ } catch (error) {
109
+ reply(undefined, error instanceof Error ? error.message : 'Could not load the inventory')
110
+ } finally { active-- }
111
+ return
112
+ }
113
+ if (data.type === 'credential-status' || data.type === 'credential-save') {
114
+ if (!credentialPanel || active >= 12) { reply(undefined, 'Credential check is unavailable'); return }
115
+ const { key } = credentials[0]
116
+ active++
117
+ try {
118
+ if (data.type === 'credential-save') {
119
+ if (readOnly || data.key !== key || typeof data.value !== 'string' || !data.value.trim() || data.value.length > 16384) {
120
+ reply(undefined, 'Credential update is unavailable')
121
+ return
122
+ }
123
+ await savePluginCredential(plugin, key, data.value, brainId)
124
+ reply({ present: true, secretKey: key })
125
+ } else {
126
+ const saved = await readSavedPluginCredentials()
127
+ reply({ present: saved.has(key), secretKey: key })
128
+ }
129
+ } catch {
130
+ reply(undefined, data.type === 'credential-save' ? 'Could not verify and save the credential.' : 'Could not check saved credentials.')
131
+ } finally { active-- }
86
132
  return
87
133
  }
88
- if (data.type === 'contextmenu') window.dispatchEvent(new CustomEvent('plugin-context-menu', { detail: { pluginId: plugin.id } }))
89
- if (data.type === 'height' && Number.isFinite(data.height)) setHeight(Math.max(128, Math.min(1000, data.height)))
90
- if (data.type === 'error') setError('Could not open the plugin interface')
91
134
  if (data.type !== 'run') return
92
- const target = event.source as Window
93
- const reply = (result?: unknown, error?: string) => { if (!disposed) target.postMessage({ channel, type: 'result', requestId: data.requestId, result, error }, '*') }
94
135
 
95
136
  let subcommand = data.subcommand
96
137
  let args = Array.isArray(data.args) ? [...data.args] : []
@@ -101,11 +142,11 @@ export function PluginPanel({ plugin, elementId, readOnly = false }: { plugin: P
101
142
 
102
143
  if (!allowedFrameCommand({ ...data, subcommand, args }, allowed, secretCommands) || active >= 12) { reply(undefined, 'Operation is not available'); return }
103
144
  active++
104
- window.dispatchEvent(new CustomEvent('plugin-command-activity', { detail: { pluginId: plugin.id, requestId: data.requestId, command: subcommand, running: true } }))
105
145
  try {
106
146
  const finalArgs = args.includes('--json') ? args : [...args, '--json']
107
- const result = data.stdin !== undefined
108
- ? await runPluginCommand(plugin.id, subcommand, finalArgs, { stdin: data.stdin })
147
+ const options = { ...(brainId ? { brainId } : {}), ...(data.stdin !== undefined ? { stdin: data.stdin } : {}) }
148
+ const result = Object.keys(options).length
149
+ ? await runPluginCommand(plugin.id, subcommand, finalArgs, options)
109
150
  : await runPluginCommand(plugin.id, subcommand, finalArgs)
110
151
  if (!result.success) { reply(undefined, data.stdin !== undefined ? 'Credential operation failed' : result.output || result.error || 'Operation failed'); return }
111
152
  if (data.stdin !== undefined) {
@@ -114,22 +155,18 @@ export function PluginPanel({ plugin, elementId, readOnly = false }: { plugin: P
114
155
  }
115
156
  reply(parsePluginOutput(result.output))
116
157
  } catch { reply(undefined, 'Operation failed') }
117
- finally {
118
- active--
119
- window.dispatchEvent(new CustomEvent('plugin-command-activity', { detail: { pluginId: plugin.id, requestId: data.requestId, command: subcommand, running: false } }))
120
- }
158
+ finally { active-- }
121
159
  }
122
160
  window.addEventListener('message', message)
123
- window.addEventListener('plugin-show-screen', showScreen)
124
161
  const dispose = () => {
125
162
  disposed = true
163
+ controller.abort()
126
164
  window.removeEventListener('message', message)
127
- window.removeEventListener('plugin-show-screen', showScreen)
128
- if (element?.kind === 'card') window.dispatchEvent(new CustomEvent('plugin-screens', { detail: { pluginId: plugin.id, screens: [] } }))
129
165
  }
130
166
  if (!element) return dispose
131
167
  const load = async () => {
132
- const response = await apiFetch(`${API_BASE}/api/plugins/${encodeURIComponent(plugin.id)}/ui/${encodeURIComponent(element.id)}`)
168
+ const scope = brainId ? `?brain=${encodeURIComponent(brainId)}` : ''
169
+ const response = await apiFetch(`${API_BASE}/api/plugins/${encodeURIComponent(plugin.id)}/ui/${encodeURIComponent(element.id)}${scope}`, { cache: 'no-store' })
133
170
  if (!response.ok) throw new Error(`Could not open ${plugin.name} (${response.status})`)
134
171
  const source = await response.text()
135
172
  if (source.length > 1024 * 1024) throw new Error('The plugin interface is too large')
@@ -137,14 +174,17 @@ export function PluginPanel({ plugin, elementId, readOnly = false }: { plugin: P
137
174
  const styles = getComputedStyle(window.document.documentElement)
138
175
  const theme: Record<string, string> = {}
139
176
  for (const name of ['--text-primary', '--text-secondary', '--text-tertiary', '--bg-primary', '--bg-secondary', '--border', '--accent', '--font-sans', '--color-text', '--color-surface', '--color-border', '--spacing-md', '--radius-md']) theme[name] = styles.getPropertyValue(name)
140
- setDocument(pluginFrameDocument(source, element.tag, channel, theme, plugin.id, pluginCommandTimeouts(plugin.manifest), [...allowed]))
177
+ setDocument(pluginFrameDocument(source, element.tag, channel, theme, plugin.id, pluginCommandTimeouts(plugin.manifest), [...allowed], credentialPanel, authInventory, authChanges))
141
178
  }
142
179
  load().catch(err => { if (!disposed) setError(err.message) })
143
180
  return dispose
144
- }, [plugin.id, selected, plugin.sha256, elementId, readOnly])
181
+ }, [plugin.id, selected, plugin.sha256, elementId, readOnly, brainId])
145
182
 
146
- const currentElement = elements.find(item => item.id === selected) || elements[0]
147
- const showNav = elements.length > 1 && currentElement?.kind !== 'card'
183
+ useEffect(() => {
184
+ frame.current?.contentWindow?.postMessage({ channel: activeChannel.current, type: 'design', css }, '*')
185
+ }, [css])
186
+
187
+ const showNav = elements.length > 1
148
188
 
149
189
  return <section>
150
190
  {showNav && <nav style={{ display: 'flex', gap: 8 }}>
@@ -154,6 +194,7 @@ export function PluginPanel({ plugin, elementId, readOnly = false }: { plugin: P
154
194
  {elements.length === 0 && <p>This plugin has not supplied its interface yet.</p>}
155
195
  {document && <iframe ref={frame} title={`${plugin.name} interface`} sandbox="allow-scripts" referrerPolicy="no-referrer"
156
196
  allow="camera 'none'; microphone 'none'; geolocation 'none'; clipboard-read 'none'; clipboard-write 'none'"
197
+ onLoad={() => frame.current?.contentWindow?.postMessage({ channel: activeChannel.current, type: 'design', css }, '*')}
157
198
  srcDoc={document} style={{ width: '100%', height, border: 0 }} />}
158
199
  </section>
159
200
  }