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
@@ -0,0 +1,79 @@
1
+ /** Private dashboard chrome settings, shared by the HTTP and CLI adapters. */
2
+ import path from 'node:path';
3
+ import { executePluginState, PluginStateStore } from './plugin-state-store.mjs';
4
+
5
+ const OWNER = 'workspace-ui';
6
+ const ID = /^[a-z][a-z0-9-]{0,63}$/;
7
+ const EMPTY = { html: '', chunks: [], panels: [], shortcuts: [] };
8
+ export const MAX_DRAWER_HTML_BYTES = 64 * 1024;
9
+
10
+ export class DrawerInputError extends Error {}
11
+
12
+ function stateFile(brainDir, edge) {
13
+ if (edge !== 'right' && edge !== 'bottom') throw new DrawerInputError('Choose the right or bottom drawer.');
14
+ return path.join(brainDir, 'config', `workspace-drawer-${edge}.json`);
15
+ }
16
+
17
+ function list(value, name, limit) {
18
+ if (!Array.isArray(value) || value.length > limit) throw new DrawerInputError(`${name} must contain at most ${limit} items.`);
19
+ return value;
20
+ }
21
+
22
+ function shortcutHref(value) {
23
+ if (typeof value !== 'string' || value.length > 1024 || /[\u0000-\u0020\u007f\\]/.test(value)) {
24
+ throw new DrawerInputError('Use a dashboard path or an HTTPS address for each shortcut.');
25
+ }
26
+ const base = 'https://workspace.invalid';
27
+ let url;
28
+ try { url = new URL(value, base); } catch { throw new DrawerInputError('Invalid shortcut address.'); }
29
+ if (value.startsWith('/') && !value.startsWith('//') && url.origin === base && !url.pathname.startsWith('//') &&
30
+ !/%(?:2f|5c)/i.test(url.pathname)) {
31
+ return url.pathname + url.search + url.hash;
32
+ }
33
+ if (value.startsWith('https://') && !url.username && !url.password) return url.href;
34
+ throw new DrawerInputError('Use a dashboard path or an HTTPS address for each shortcut.');
35
+ }
36
+
37
+ export function validateDrawerConfig(value) {
38
+ if (!value || typeof value !== 'object' || Array.isArray(value) || Object.keys(value).some(key => !Object.hasOwn(EMPTY, key))) {
39
+ throw new DrawerInputError('Invalid drawer configuration.');
40
+ }
41
+ const { html = '', chunks = [], panels = [], shortcuts = [] } = value;
42
+ if (typeof html !== 'string' || Buffer.byteLength(html, 'utf8') > MAX_DRAWER_HTML_BYTES) {
43
+ throw new DrawerInputError('Drawer HTML must be at most 64 KiB.');
44
+ }
45
+ const chunkIds = list(chunks, 'Chunks', 8).map(key => {
46
+ if (typeof key !== 'string' || key.split(':').length !== 2 || key.split(':').some(id => !ID.test(id))) {
47
+ throw new DrawerInputError('Each chunk needs a plugin ID and a chunk ID.');
48
+ }
49
+ return key;
50
+ });
51
+ const references = list(panels, 'Panels', 6).map(panel => {
52
+ if (typeof panel?.plugin !== 'string' || typeof panel?.element !== 'string' ||
53
+ !ID.test(panel.plugin) || !ID.test(panel.element)) throw new DrawerInputError('Invalid plugin panel reference.');
54
+ return { plugin: panel.plugin, element: panel.element };
55
+ });
56
+ const links = list(shortcuts, 'Shortcuts', 16).map(shortcut => {
57
+ const label = typeof shortcut?.label === 'string' ? shortcut.label.trim() : '';
58
+ if (!label || label.length > 80 || /[\u0000-\u001f\u007f]/.test(label)) throw new DrawerInputError('Give each shortcut a name of 1–80 characters.');
59
+ return { label, href: shortcutHref(shortcut.href) };
60
+ });
61
+ return { html, chunks: [...new Set(chunkIds)], panels: references, shortcuts: links };
62
+ }
63
+
64
+ export function readDrawerConfig(brainDir, edge) {
65
+ const store = new PluginStateStore(stateFile(brainDir, edge), OWNER);
66
+ const config = validateDrawerConfig(store.read(EMPTY));
67
+ return { config, version: store.version };
68
+ }
69
+
70
+ export async function writeDrawerConfig(brainDir, edge, config, version) {
71
+ if (version !== null && (typeof version !== 'string' || !/^[0-9a-f]{64}$/.test(version))) {
72
+ throw new DrawerInputError('Reload the drawer before saving.');
73
+ }
74
+ const value = validateDrawerConfig(config);
75
+ const result = await executePluginState({
76
+ file: stateFile(brainDir, edge), plugin: OWNER, action: 'write', value, expectedVersion: version,
77
+ });
78
+ return { config: value, version: result.version };
79
+ }
@@ -15,10 +15,10 @@ import { runInSandbox } from '../core/sandbox.mjs';
15
15
  import { resolveAgentDir } from '../cli/agent-dir.mjs';
16
16
  import { removeSessionEmbeddingFromIndex } from '../core/embeddings.mjs';
17
17
  import path from 'path';
18
- import os from 'os';
19
18
  import fs from 'fs';
20
19
  import matter from '../core/frontmatter.mjs';
21
20
  import { agentDir, brainDir, surfaceDir, instructionsFilePath } from '../core/config.mjs';
21
+ import { resolveVaultFromQuery } from './routes/_shared.mjs';
22
22
 
23
23
  const AGENT_DIR = process.env.AGENT_DIR || agentDir;
24
24
  const BRAIN_DIR = process.env.TR_BRAIN || path.join(AGENT_DIR, 'skills', 'total-recall');
@@ -43,32 +43,9 @@ const MODEL_CATALOG_DIR = path.join(ROOT, 'models', 'catalog', 'total-recall');
43
43
  * @returns {string} Absolute path to the memory-vault directory
44
44
  */
45
45
  function resolveVaultDir(brainId) {
46
- if (!brainId || brainId === 'global') {
47
- return VAULT_DIR;
48
- }
49
-
50
- if (brainId.startsWith('project:')) {
51
- const projectName = brainId.slice('project:'.length);
52
- const globalBrainDir = path.join(os.homedir(), '.agent', 'skills', 'total-recall');
53
- const registryPath = path.join(globalBrainDir, 'config', 'project-registry.json');
54
-
55
- if (fs.existsSync(registryPath)) {
56
- try {
57
- const registry = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
58
- const project = registry.find(p => p.name === projectName);
59
- if (project) {
60
- const projectVaultDir = path.join(project.brainDir, 'memory-vault');
61
- if (fs.existsSync(projectVaultDir)) {
62
- return projectVaultDir;
63
- }
64
- }
65
- } catch {
66
- // Registry parse error — fall through to default
67
- }
68
- }
69
- }
70
-
71
- return VAULT_DIR;
46
+ return typeof brainId === 'string' && (brainId === 'global' || brainId.startsWith('project:'))
47
+ ? resolveVaultFromQuery({ query: { brain: brainId } })
48
+ : VAULT_DIR;
72
49
  }
73
50
 
74
51
  function sha256(content) {
@@ -352,6 +352,8 @@ app.get('/health', requireAuthOrLocal, async (req, res) => {
352
352
  cloudflare: cloudflareStatus,
353
353
  emergency_alerts: emergencyAlerts || null,
354
354
  fetch_gate,
355
+ // Whether the served dashboard is as new as this checkout's frontend sources.
356
+ dashboard: dashboardBundle.state(),
355
357
  vfs: {
356
358
  exists: vaultExists,
357
359
  skill_exists: skillExists,
@@ -444,24 +446,30 @@ try {
444
446
 
445
447
  const frontendDist = path.join(ROOT, 'frontend', 'dist');
446
448
 
447
- // Auto-build frontend if dist/ doesn't exist
448
- if (!fs.existsSync(path.join(frontendDist, 'index.html'))) {
449
- const frontendDir = path.join(ROOT, 'frontend');
450
- if (fs.existsSync(path.join(frontendDir, 'package.json'))) {
451
- logger.info('server', 'Frontend not built. Building automatically...');
452
- try {
453
- const { execSync } = await import('node:child_process');
454
- execSync('npm install --no-audit --no-fund 2>/dev/null && npm run build', {
455
- cwd: frontendDir,
456
- stdio: 'pipe',
457
- timeout: 120_000,
458
- });
459
- logger.info('server', 'Frontend build complete.');
460
- } catch (err) {
461
- logger.warn('server', `Frontend auto-build failed: ${err.message?.split('\\n')[0] || 'unknown error'}. Dashboard will show API info instead.`);
449
+ // Live refresh for the memory page on this port (the /stream monitor listens on 127.0.0.1 only).
450
+ const { memoryEventsHandler } = await import('./memory-events.mjs');
451
+ app.get('/api/memory-events', requireAuth, memoryEventsHandler(logEvents));
452
+
453
+ // Keep the served dashboard as new as its sources. A missing or stale bundle is
454
+ // rebuilt in the background while the current one keeps serving; express.static
455
+ // resolves files per request, so the swapped-in build serves without a restart.
456
+ // Building only when index.html was missing left every later frontend commit unserved.
457
+ const { watchDashboardBundle } = await import('../core/dashboard-bundle.mjs');
458
+ const dashboardBundle = watchDashboardBundle({
459
+ root: ROOT,
460
+ report: (state) => {
461
+ if (state.status === 'current' && state.rebuilt) {
462
+ logger.info('server', `Dashboard bundle rebuilt from newer sources (${Math.round(state.durationMs / 1000)} s); serving it now.`);
463
+ } else if (state.status === 'current') {
464
+ logger.info('server', 'Dashboard bundle is current.');
465
+ } else if (state.retryInMs) {
466
+ logger.info('server', `Dashboard bundle is ${state.status}; rebuilding once the sources stop changing.`);
467
+ } else {
468
+ logger.error('server', `Dashboard bundle is ${state.status} and was not rebuilt: ${state.reason}.${state.build?.output ? ` Build output: ${state.build.output.slice(-1500)}` : ''}`);
462
469
  }
463
- }
464
- }
470
+ },
471
+ });
472
+ dashboardBundle.check();
465
473
 
466
474
  app.use(express.static(frontendDist));
467
475
 
@@ -803,8 +811,7 @@ app.get('/chat', (req, res) => {
803
811
 
804
812
  // SPA fallback — serve index.html for all unmatched routes
805
813
  app.get(/^(.*)$/, (req, res) => {
806
- const indexPath = path.join(frontendDist, 'index.html');
807
- res.sendFile(indexPath, (err) => {
814
+ res.sendFile('index.html', { root: frontendDist }, (err) => {
808
815
  if (err) {
809
816
  // Frontend not built yet — return a helpful message
810
817
  res.status(200).json({
@@ -814,7 +821,7 @@ app.get(/^(.*)$/, (req, res) => {
814
821
  memory: 'GET /api/memory',
815
822
  sandbox: 'POST /api/sandbox',
816
823
  health: 'GET /health',
817
- dashboard: 'Build frontend first: cd frontend && npm run build'
824
+ dashboard: `Dashboard bundle is ${dashboardBundle.state().status}${dashboardBundle.state().reason ? `: ${dashboardBundle.state().reason}` : ''}. The server rebuilds it from frontend/ in the background.`
818
825
  }
819
826
  });
820
827
  }
@@ -874,7 +881,7 @@ const server = app.listen(PORT, HOST, () => {
874
881
 
875
882
  // Only meaningful once the socket is up: asking before the callback fires
876
883
  // reads an empty set, which is "unknown", so the watch never armed.
877
- if (isReachableFromOtherDevices() === false) {
884
+ if (bindResolution.usedLoopbackFallback && isReachableFromOtherDevices() === false) {
878
885
  logger.warn(
879
886
  'server',
880
887
  `Bound to loopback only — no other device can reach this brain at :${PORT}. `
@@ -0,0 +1,24 @@
1
+ /** Full-mode owner work shares invoke's process-group and output limits. */
2
+ import path from 'node:path';
3
+ console.log = console.info = console.debug = (...args) => console.error(...args);
4
+
5
+ try {
6
+ let input = '';
7
+ for await (const chunk of process.stdin) {
8
+ input += chunk;
9
+ if (Buffer.byteLength(input) > 32768) throw new Error('Input limit');
10
+ }
11
+ const { operation, params, brain, registryBrain } = JSON.parse(input);
12
+ // Config and Auth must use the serving brain, not a brain inferred from cwd.
13
+ process.env.AGENT_DIR = path.dirname(path.dirname(brain));
14
+ process.env.TR_SECRETS_BRAIN = brain;
15
+ const { executeCoreOperation } = await import('./invoke-core-operations.mjs');
16
+ const result = await executeCoreOperation(operation, params, { brain, registryBrain });
17
+ process.stdout.write(JSON.stringify({ ok: true, result }));
18
+ } catch (err) {
19
+ // Return curated policy codes only. Never return owner exception text.
20
+ const { InvokeError } = await import('./invoke-execution.mjs');
21
+ process.stdout.write(JSON.stringify({ ok: false, error: err instanceof InvokeError ? err.code : 'operation-failed',
22
+ status: err instanceof InvokeError ? err.status : 502 }));
23
+ process.exitCode = 1;
24
+ }
@@ -0,0 +1,102 @@
1
+ /** Owner adapters for the retired one-off remote routes. */
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import matter from '../core/frontmatter.mjs';
5
+ import { readRegisteredProjects } from '../core/brain-registry.mjs';
6
+ import { InvokeError } from './invoke-execution.mjs';
7
+
8
+ export const CORE_OPERATIONS = Object.freeze({
9
+ 'context.preview': { scope: 'memory:read', family: 'context' },
10
+ 'context.stream': { scope: 'memory:read', family: 'context' },
11
+ 'context.flash.health': { scope: 'memory:read', family: 'context' },
12
+ 'brains.sync': { scope: 'memory:write', family: 'brains' },
13
+ 'tasks.cleanup': { scope: 'tasks:write', family: 'tasks' },
14
+ 'tasks.failed': { scope: 'tasks:read', family: 'tasks' },
15
+ 'vault.hash': { scope: 'memory:read', family: 'vault' },
16
+ });
17
+
18
+ export function validateCoreParams(operation, params) {
19
+ if (params.timeoutMs !== undefined && (!Number.isFinite(Number(params.timeoutMs)) || Number(params.timeoutMs) <= 0)) {
20
+ throw new InvokeError(400, 'invalid-timeout', 'timeoutMs must be positive and finite.');
21
+ }
22
+ const allowed = new Set(['target', 'timeoutMs']);
23
+ if (!['brains.sync', 'context.flash.health'].includes(operation)) allowed.add('brainId');
24
+ if (operation === 'context.stream') for (const key of ['query', 'budget_tokens', 'concurrency', 'min_score']) allowed.add(key);
25
+ if (Object.keys(params).some(key => !allowed.has(key))) throw new InvokeError(400, 'unknown-parameter', 'Unsupported operation parameter.');
26
+ if (params.brainId !== undefined && (typeof params.brainId !== 'string' || !params.brainId || params.brainId.includes(','))) {
27
+ throw new InvokeError(400, 'invalid-brain', 'brainId must select one brain.');
28
+ }
29
+ if (params.brainId !== undefined && !['server', 'global'].includes(params.brainId) &&
30
+ !/^project:[^/\\\0,]+$/.test(params.brainId)) {
31
+ throw new InvokeError(400, 'invalid-brain', 'brainId must select the server or a registered project.');
32
+ }
33
+ if (operation === 'context.stream') {
34
+ if (typeof params.query !== 'string' || !params.query.trim()) throw new InvokeError(400, 'invalid-query', 'query is required.');
35
+ for (const [key, min, max] of [['budget_tokens', 1, 65536], ['concurrency', 1, 4], ['min_score', 0, 100]]) {
36
+ if (params[key] !== undefined && (!Number.isInteger(params[key]) || params[key] < min || params[key] > max)) {
37
+ throw new InvokeError(400, 'invalid-parameter', `Invalid ${key}.`);
38
+ }
39
+ }
40
+ }
41
+ }
42
+
43
+ function selectedBrain(brainId, brain, registryBrain) {
44
+ if (brainId === undefined || brainId === 'server' || brainId === 'global') return brain;
45
+ if (brainId.startsWith('project:')) {
46
+ const name = brainId.slice('project:'.length);
47
+ const project = readRegisteredProjects(registryBrain).find(row => row.name === name || row.project_id === name);
48
+ if (project?.brainDir && fs.existsSync(path.join(project.brainDir, 'memory-vault'))) return project.brainDir;
49
+ }
50
+ throw new InvokeError(404, 'brain-unavailable', 'Selected brain is unavailable.');
51
+ }
52
+
53
+ export async function executeCoreOperation(operation, params, { brain, registryBrain }) {
54
+ if (!Object.hasOwn(CORE_OPERATIONS, operation)) throw new InvokeError(404, 'unknown-operation', 'Unknown operation.');
55
+ validateCoreParams(operation, params);
56
+ const selected = selectedBrain(params.brainId, brain, registryBrain);
57
+ const vaultDir = path.join(selected, 'memory-vault');
58
+ switch (operation) {
59
+ case 'context.preview': {
60
+ const { previewContext } = await import('../core/context-compiler.mjs');
61
+ return previewContext({ vaultDir });
62
+ }
63
+ case 'context.stream': {
64
+ const { streamParallelContext } = await import('../core/parallel-context.mjs');
65
+ const result = await streamParallelContext({ query: params.query, vaultDir,
66
+ budgetTokens: params.budget_tokens, concurrency: params.concurrency, minScore: params.min_score });
67
+ // Provider diagnostics can contain a credential-bearing URL.
68
+ return { ...result, scored: result.scored.map(({ error, ...row }) => error ? { ...row, error: 'provider-failed' } : row) };
69
+ }
70
+ case 'context.flash.health': {
71
+ const { checkFlashHealth } = await import('../core/parallel-context.mjs');
72
+ const { error, ...result } = await checkFlashHealth();
73
+ return error ? { ...result, error: 'provider-unavailable' } : result;
74
+ }
75
+ case 'brains.sync': {
76
+ const { syncAllRepos } = await import('../core/repo-sync.mjs');
77
+ const result = await syncAllRepos({ registryBrain });
78
+ if (result.repos.some(row => row.errors)) throw new InvokeError(502, 'sync-failed', 'Some repositories failed to sync.');
79
+ return { ok: true, ...result };
80
+ }
81
+ case 'tasks.cleanup': {
82
+ const queue = path.join(selected, 'scheduler/queue');
83
+ let deleted = 0;
84
+ if (fs.existsSync(queue)) for (const entry of fs.readdirSync(queue, { withFileTypes: true })) {
85
+ if (!entry.isFile() || !entry.name.endsWith('.md')) continue;
86
+ const file = path.join(queue, entry.name);
87
+ const { data } = matter(fs.readFileSync(file, 'utf8'));
88
+ if (data.status === 'completed') { fs.unlinkSync(file); deleted++; }
89
+ }
90
+ return { deleted };
91
+ }
92
+ case 'tasks.failed': {
93
+ const { listTasks } = await import('../core/task-envelope.mjs');
94
+ const tasks = listTasks(path.join(selected, 'scheduler/queue'), { status: 'failed' });
95
+ return { total: tasks.length, tasks };
96
+ }
97
+ case 'vault.hash': {
98
+ const file = path.join(selected, 'memory-derived/vault-hash.txt');
99
+ return { vault_hash: fs.existsSync(file) ? fs.readFileSync(file, 'utf8').trim() : null, vault_dir: vaultDir };
100
+ }
101
+ }
102
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Live refresh for the memory page, on the dashboard's own port.
3
+ *
4
+ * The page listened to `/stream` on the dashboard origin, but the server
5
+ * serves `/stream` only on the 127.0.0.1 monitor port, so the dashboard got
6
+ * its HTML fallback and the live refresh never connected. This stream is
7
+ * authenticated like the rest of the dashboard API and carries only the
8
+ * subsystem name of the events that change what the page shows, never log
9
+ * contents.
10
+ */
11
+ export const MEMORY_EVENT_SUBSYSTEMS = new Set(['conflict-detector', 'rebuild', 'session-watcher']);
12
+ const HEARTBEAT_MS = 25000;
13
+
14
+ /** @param {import('node:events').EventEmitter} events Emits 'log' entries ({ subsystem, ... }). */
15
+ export function memoryEventsHandler(events, { heartbeatMs = HEARTBEAT_MS } = {}) {
16
+ return (req, res) => {
17
+ res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' });
18
+ res.write(': connected\n\n');
19
+ const onLog = (entry) => {
20
+ if (MEMORY_EVENT_SUBSYSTEMS.has(entry?.subsystem)) res.write(`data: ${JSON.stringify({ subsystem: entry.subsystem })}\n\n`);
21
+ };
22
+ events.on('log', onLog);
23
+ // Comment lines keep proxies from closing an idle stream.
24
+ const heartbeat = setInterval(() => res.write(': ping\n\n'), heartbeatMs);
25
+ heartbeat.unref?.();
26
+ req.on('close', () => {
27
+ events.off('log', onLog);
28
+ clearInterval(heartbeat);
29
+ });
30
+ };
31
+ }
@@ -0,0 +1,89 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { dashboardBrainDir, globalBrainDirFor, readBrainToggles, readRegisteredProjects } from '../core/brain-registry.mjs';
4
+ import { projectPluginsDir } from '../core/plugin-loader.mjs';
5
+ import { readProjectId } from '../core/project-id.mjs';
6
+ import { keyHasScope } from './keys.mjs';
7
+
8
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
9
+ const PROJECT_SELECTOR = /^project:[^/\\:,\x00-\x1f\x7f]{1,160}$/u;
10
+
11
+ const targetError = (status, message) => Object.assign(new Error(message), { status });
12
+
13
+ function optionalDirectoriesAreLocal(brainDir) {
14
+ for (const name of ['plugins', 'memory-vault', 'memory-derived']) {
15
+ try {
16
+ if (!fs.lstatSync(path.join(brainDir, name)).isDirectory()) return false;
17
+ } catch (error) {
18
+ if (error.code !== 'ENOENT') return false;
19
+ }
20
+ }
21
+ return true;
22
+ }
23
+
24
+ function resolveProject(row, sharedBrain, toggles) {
25
+ try {
26
+ if (typeof row.path !== 'string' || !path.isAbsolute(row.path) ||
27
+ typeof row.brainDir !== 'string' || !path.isAbsolute(row.brainDir)) return null;
28
+ const projectRoot = fs.realpathSync(row.path);
29
+ const brainDir = path.dirname(projectPluginsDir(projectRoot));
30
+ const identity = path.join(brainDir, 'config', 'brain.json');
31
+ if (brainDir === sharedBrain || fs.realpathSync(row.brainDir) !== brainDir ||
32
+ fs.realpathSync(brainDir) !== brainDir || fs.realpathSync(identity) !== identity ||
33
+ !fs.lstatSync(identity).isFile() || readProjectId(brainDir) !== row.project_id ||
34
+ toggles[path.resolve(row.brainDir)] === false || toggles[brainDir] === false ||
35
+ !optionalDirectoriesAreLocal(brainDir)) return null;
36
+ return { brainDir, projectRoot };
37
+ } catch {
38
+ return null;
39
+ }
40
+ }
41
+
42
+ function authorize(auth, scope) {
43
+ if (auth?.type === 'dashboard_session') return;
44
+ if (auth?.type !== 'pat' || !keyHasScope(auth, scope)) {
45
+ throw targetError(403, 'The token does not grant access to a selected brain.');
46
+ }
47
+ }
48
+
49
+ /** Resolve selected IDs against server-owned registrations before plugin I/O. */
50
+ export function resolvePluginBrainTargets(ids, auth, { registryBrain = globalBrainDirFor() } = {}) {
51
+ if (!Array.isArray(ids) || !ids.length || ids.length > 64 ||
52
+ ids.some(id => typeof id !== 'string' || (id !== 'global' && !PROJECT_SELECTOR.test(id)))) {
53
+ throw targetError(400, 'Select up to 64 global or registered project brain IDs.');
54
+ }
55
+ let sharedBrain, rows, toggles, globalToggles;
56
+ try {
57
+ const projectRegistryBrain = dashboardBrainDir(process.env, registryBrain);
58
+ sharedBrain = fs.realpathSync(registryBrain);
59
+ globalToggles = ids.includes('global') ? readBrainToggles(registryBrain, { strict: true }) : {};
60
+ const needsProjects = ids.some(id => id !== 'global');
61
+ toggles = needsProjects ? readBrainToggles(projectRegistryBrain, { strict: true }) : {};
62
+ rows = needsProjects ? readRegisteredProjects(projectRegistryBrain) : [];
63
+ } catch {
64
+ throw targetError(503, 'Brain registry metadata is unavailable.');
65
+ }
66
+ const resolved = new Set();
67
+ return [...new Set(ids)].map(brainId => {
68
+ if (brainId === 'global') {
69
+ authorize(auth, 'brain:global');
70
+ if (globalToggles[path.resolve(registryBrain)] === false || globalToggles[sharedBrain] === false) {
71
+ throw targetError(404, 'The selected global brain is unavailable.');
72
+ }
73
+ return { brainId, name: 'Global Brain', brainDir: sharedBrain, projectRoot: null };
74
+ }
75
+ const selector = brainId.slice('project:'.length);
76
+ const matches = rows.filter(row => row.name === selector || row.project_id === selector);
77
+ if (matches.length > 1) throw targetError(409, 'A selected project brain ID is ambiguous.');
78
+ const row = matches[0];
79
+ if (typeof row?.project_id !== 'string' || !UUID.test(row.project_id) || rows.filter(candidate => candidate.project_id === row.project_id).length !== 1) {
80
+ throw targetError(404, 'A selected project brain is unavailable.');
81
+ }
82
+ authorize(auth, 'brain:project-' + row.project_id);
83
+ const target = resolveProject(row, sharedBrain, toggles);
84
+ if (!target) throw targetError(404, 'A selected project brain is unavailable.');
85
+ if (resolved.has(target.brainDir)) throw targetError(400, 'Select each project brain once.');
86
+ resolved.add(target.brainDir);
87
+ return { brainId, name: row.name || selector, ...target };
88
+ });
89
+ }
@@ -121,6 +121,7 @@ import updateRouter from './routes/update.mjs';
121
121
  import { rulesRouter } from './routes/rules.mjs';
122
122
  import notificationsRouter from './routes/notifications.mjs';
123
123
  import pluginsRouter from './routes/plugins.mjs';
124
+ import uiChunksRouter from './routes/ui-chunks.mjs';
124
125
  // ollamaUrl removed — CLI agents replace Ollama
125
126
  import {
126
127
  AGENT_DIR,
@@ -235,6 +236,7 @@ router.use(ssssRouter);
235
236
  router.use(rulesRouter);
236
237
  router.use(notificationsRouter);
237
238
  router.use(pluginsRouter);
239
+ router.use(uiChunksRouter);
238
240
  for (const pluginRouter of await (await import('../core/plugin-runtime.mjs')).loadPluginRouters()) router.use(pluginRouter);
239
241
 
240
242
  export { router as restRouter };
@@ -29,13 +29,14 @@ export function extractRoutes(router) {
29
29
 
30
30
  for (const layer of stack) {
31
31
  if (layer.route) {
32
- const pathStr = layer.route.path;
32
+ // Express keeps aliases and regular expressions in Route.path.
33
+ const paths = [layer.route.path].flat(Infinity).map(String);
33
34
  const methods = Object.keys(layer.route.methods)
34
35
  .filter((method) => layer.route.methods[method])
35
36
  .map((method) => method.toUpperCase());
36
37
 
37
38
  for (const method of methods) {
38
- routes.push({ method, path: pathStr });
39
+ for (const path of paths) routes.push({ method, path });
39
40
  }
40
41
  } else if (layer.name === 'router' && layer.handle && layer.handle.stack) {
41
42
  // Sub-router mounted via router.use()