total-recall-brain 3.45.0 → 3.46.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/bin/total-recall.mjs +7 -2
  2. package/frontend/dist/assets/index-BRYE1jmv.css +1 -0
  3. package/frontend/dist/assets/index-D1goIPjC.js +5598 -0
  4. package/frontend/dist/index.html +2 -2
  5. package/frontend/dist/sw.js +5 -4
  6. package/frontend/src/App.tsx +183 -236
  7. package/frontend/src/api/auth-inventory.ts +62 -0
  8. package/frontend/src/api/memory.ts +13 -8
  9. package/frontend/src/api/plugin-credentials.ts +23 -0
  10. package/frontend/src/api/plugins.ts +37 -53
  11. package/frontend/src/api/workspace-drawers.ts +97 -0
  12. package/frontend/src/components/BrainSelector.tsx +9 -3
  13. package/frontend/src/components/plugins/PluginPanel.tsx +83 -42
  14. package/frontend/src/components/plugins/PluginSettings.tsx +10 -20
  15. package/frontend/src/components/plugins/PluginWorkspace.tsx +367 -0
  16. package/frontend/src/components/plugins/ScopedPluginCommands.tsx +142 -0
  17. package/frontend/src/components/plugins/plugin-frame.ts +44 -33
  18. package/frontend/src/components/plugins/scoped-plugin-operations.ts +28 -0
  19. package/frontend/src/components/workspace/DrawerChat.tsx +110 -0
  20. package/frontend/src/components/workspace/DrawerLayout.tsx +196 -0
  21. package/frontend/src/components/workspace/DrawerMarkup.tsx +49 -0
  22. package/frontend/src/components/workspace/PluginChunkLibrary.tsx +92 -0
  23. package/frontend/src/components/workspace/PluginHome.tsx +76 -0
  24. package/frontend/src/components/workspace/WorkspaceDrawers.tsx +96 -0
  25. package/frontend/src/components/workspace/WorkspacePage.tsx +95 -0
  26. package/frontend/src/components/workspace/usePluginDesign.ts +38 -0
  27. package/frontend/src/index.css +409 -136
  28. package/frontend/src/pages/HelpPage.tsx +15 -46
  29. package/frontend/src/pages/MemoryPage.tsx +19 -36
  30. package/frontend/src/pages/SettingsPage.tsx +1 -1
  31. package/metadata.plugin.schema.json +53 -227
  32. package/package.json +1 -1
  33. package/scaffold/.agent/skills/plugin/SKILL.md +13 -11
  34. package/scaffold/.agent/skills/plugin/evals/README.md +14 -21
  35. package/scaffold/.agent/skills/plugin/evals/cases/01-fabricated-seed.mjs +15 -18
  36. package/scaffold/.agent/skills/plugin/evals/cases/02-reassuring-default.mjs +19 -24
  37. package/scaffold/.agent/skills/plugin/evals/cases/03-declared-template.mjs +12 -20
  38. package/scaffold/.agent/skills/plugin/evals/cases/04-home-collects-credential.mjs +35 -0
  39. package/scaffold/.agent/skills/plugin/evals/cases/05-host-leak-in-scaffold.mjs +8 -28
  40. package/scaffold/.agent/skills/plugin/evals/cases/06-correct-plugin.mjs +85 -47
  41. package/scaffold/.agent/skills/plugin/evals/run.mjs +17 -18
  42. package/scaffold/.agent/skills/plugin/prompts/05-credentials.md +4 -4
  43. package/scaffold/.agent/skills/plugin/prompts/07-scaffold.md +2 -2
  44. package/scaffold/.agent/skills/plugin/prompts/08-verify.md +4 -4
  45. package/scaffold/.agent/skills/plugin/references/anti-patterns.md +2 -2
  46. package/scaffold/.agent/skills/plugin/references/generative-home.md +38 -0
  47. package/scaffold/.agent/skills/plugin/references/scaffold.md +5 -5
  48. package/scaffold/.agent/skills/plugin/references/surfaces.md +13 -4
  49. package/scaffold/.agent/skills/plugin/scripts/record.mjs +75 -153
  50. package/scaffold/.agent/skills/plugin/subagents/plugin-reviewer.md +4 -4
  51. package/scaffold/.agent/skills/total-recall/plugins/auth/DESIGN.md +76 -0
  52. package/scaffold/.agent/skills/total-recall/plugins/auth/README.md +3 -1
  53. package/scaffold/.agent/skills/total-recall/plugins/auth/cli.mjs +20 -15
  54. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +6 -6
  55. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +2 -1
  56. package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +13 -51
  57. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/access-overview.md +17 -0
  58. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/agent-login.md +20 -0
  59. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/baseline-audit.md +22 -0
  60. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/credential-repository-binding.md +17 -0
  61. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/credential-store-maintenance.md +17 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/dashboard-password.md +18 -0
  63. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/dashboard-sessions.md +18 -0
  64. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/endpoint-probe.md +23 -0
  65. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/google-sign-in.md +21 -0
  66. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/mesh-machines.md +16 -0
  67. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/passkey-enrollment.md +21 -0
  68. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/registered-brains.md +16 -0
  69. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/scoped-access-keys.md +17 -0
  70. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/secret-inventory.md +25 -0
  71. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/signing-key-rotation.md +22 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/home.js +375 -0
  73. package/scaffold/.agent/skills/total-recall/plugins/automations/{ui/DESIGN.md → DESIGN.md} +32 -21
  74. package/scaffold/.agent/skills/total-recall/plugins/automations/adapters.mjs +17 -1
  75. package/scaffold/.agent/skills/total-recall/plugins/automations/cli.mjs +10 -1
  76. package/scaffold/.agent/skills/total-recall/plugins/automations/package-lock.json +6 -6
  77. package/scaffold/.agent/skills/total-recall/plugins/automations/package.json +4 -3
  78. package/scaffold/.agent/skills/total-recall/plugins/automations/plugin.json +11 -27
  79. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/automations.js +2 -2
  80. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/control-ledger.md +42 -0
  81. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/local-inventory-triage.md +17 -0
  82. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/pending-control.md +39 -0
  83. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/run-evidence.md +41 -0
  84. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/schedule-vs-run-evidence.md +17 -0
  85. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/source-coverage.md +41 -0
  86. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/{card.js → home.js} +32 -27
  87. package/scaffold/.agent/skills/total-recall/plugins/code-quality/DESIGN.md +53 -0
  88. package/scaffold/.agent/skills/total-recall/plugins/code-quality/cli.mjs +23 -0
  89. package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/run-core.mjs +4 -2
  90. package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/check.mjs +4 -2
  91. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +6 -6
  92. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +2 -1
  93. package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +40 -40
  94. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/config.md +15 -0
  95. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/detect.md +15 -0
  96. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/gate.md +15 -0
  97. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/init.md +15 -0
  98. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/report.md +17 -0
  99. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/run.md +17 -0
  100. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/snapshot.md +15 -0
  101. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/code-quality-report.mjs +55 -23
  102. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/home.mjs +214 -0
  103. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/DESIGN.md +146 -0
  104. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +6 -6
  105. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +2 -1
  106. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +51 -34
  107. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/command.mjs +1 -1
  108. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/create.md +35 -0
  109. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/history.md +35 -0
  110. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/library.md +49 -0
  111. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/list.md +42 -0
  112. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/promote.md +40 -0
  113. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/read.md +25 -0
  114. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/remove.md +26 -0
  115. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/rollback.md +26 -0
  116. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/show.md +53 -0
  117. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/status.md +40 -0
  118. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/test-path.md +38 -0
  119. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/test.md +46 -0
  120. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/update.md +32 -0
  121. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/home.js +533 -0
  122. package/scaffold/.agent/skills/total-recall/plugins/embeddings/DESIGN.md +110 -0
  123. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +6 -6
  124. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +2 -1
  125. package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +13 -10
  126. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/benchmark.md +49 -0
  127. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/coverage.md +53 -0
  128. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/models.md +43 -0
  129. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/pull.md +41 -0
  130. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/status.md +59 -0
  131. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/home.js +353 -0
  132. package/scaffold/.agent/skills/total-recall/plugins/git/DESIGN.md +31 -0
  133. package/scaffold/.agent/skills/total-recall/plugins/git/README.md +25 -1
  134. package/scaffold/.agent/skills/total-recall/plugins/git/cli.mjs +5 -1
  135. package/scaffold/.agent/skills/total-recall/plugins/git/package-lock.json +6 -6
  136. package/scaffold/.agent/skills/total-recall/plugins/git/package.json +2 -1
  137. package/scaffold/.agent/skills/total-recall/plugins/git/plugin.json +17 -27
  138. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/commit-memory.mjs +30 -6
  139. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/fleet.mjs +24 -6
  140. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/secret-firewall.mjs +33 -7
  141. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/undo.mjs +29 -5
  142. package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/unmerged.mjs +182 -0
  143. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/change-comparison.md +27 -0
  144. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/commit-identity.md +22 -0
  145. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/create-worktree.md +25 -0
  146. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/registered-worktrees.md +22 -0
  147. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/remove-worktree.md +23 -0
  148. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/repository-ledger.md +25 -0
  149. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/unmerged-work.md +22 -0
  150. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/upstream-divergence.md +17 -0
  151. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/worktree-conflict-triage.md +17 -0
  152. package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/worktree-terminal.md +22 -0
  153. package/scaffold/.agent/skills/total-recall/plugins/git/ui/home.js +273 -0
  154. package/scaffold/.agent/skills/total-recall/plugins/mesh/DESIGN.md +35 -0
  155. package/scaffold/.agent/skills/total-recall/plugins/mesh/README.md +4 -5
  156. package/scaffold/.agent/skills/total-recall/plugins/mesh/cli.mjs +9 -3
  157. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +6 -6
  158. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +2 -1
  159. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +37 -39
  160. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +5 -3
  161. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/active-device-dispatch.md +22 -0
  162. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/control-probe.md +25 -0
  163. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/control-server.md +22 -0
  164. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/credential-readiness.md +23 -0
  165. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/elected-leader.md +22 -0
  166. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/enrollment-key.md +22 -0
  167. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/file-receipt.md +25 -0
  168. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/fleet-execution.md +23 -0
  169. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/fleet-presence.md +23 -0
  170. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/interactive-ssh.md +22 -0
  171. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/local-enrollment.md +23 -0
  172. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/mesh-policy.md +23 -0
  173. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/network-atlas.md +25 -0
  174. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/node-roster.md +26 -0
  175. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/node-selection-proof.md +17 -0
  176. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/owner-observations.md +23 -0
  177. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/peer-path.md +23 -0
  178. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/pinned-leader.md +24 -0
  179. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/reachability-evidence-ladder.md +17 -0
  180. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/recorded-login.md +23 -0
  181. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/remote-execution.md +22 -0
  182. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/secret-grants.md +26 -0
  183. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/{card.js → home.js} +93 -22
  184. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/DESIGN.md +86 -0
  185. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +19 -0
  186. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +5 -1
  187. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +6 -6
  188. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +2 -1
  189. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +43 -22
  190. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/chat.mjs +80 -0
  191. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/adapter-docs-freshness.md +16 -0
  192. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/chat-handoff.md +26 -0
  193. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/fleet-maintenance.md +21 -0
  194. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/harness-inventory.md +21 -0
  195. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/included-access.md +18 -0
  196. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/included-usage-verification.md +15 -0
  197. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/independent-review.md +17 -0
  198. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/managed-execution.md +20 -0
  199. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/official-documentation.md +18 -0
  200. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/quota-recovery.md +21 -0
  201. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/review-routing-decision.md +16 -0
  202. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/route-work.md +18 -0
  203. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/routing-evidence.md +18 -0
  204. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/run-ledger.md +18 -0
  205. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/home.js +198 -0
  206. package/scaffold/.agent/skills/total-recall/plugins/openwiki/DESIGN.md +75 -0
  207. package/scaffold/.agent/skills/total-recall/plugins/openwiki/README.md +2 -0
  208. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +17 -14
  209. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +6 -6
  210. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +2 -1
  211. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +10 -44
  212. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +5 -4
  213. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +3 -4
  214. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/ingest.mjs +23 -18
  215. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +8 -3
  216. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +6 -3
  217. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +3 -5
  218. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/token.mjs +21 -47
  219. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +17 -6
  220. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/auto-refresh.md +18 -0
  221. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/bootstrap-pages.md +18 -0
  222. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/generate-wiki.md +21 -0
  223. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/generator-settings.md +18 -0
  224. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/host-probe.md +18 -0
  225. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/ingest-preview.md +18 -0
  226. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/link-hygiene.md +21 -0
  227. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/link-topology.md +19 -0
  228. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/passage-search.md +19 -0
  229. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/propagation-plan.md +18 -0
  230. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/provider-credentials.md +18 -0
  231. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/refresh-report.md +18 -0
  232. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/task-evidence.md +22 -0
  233. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/upstream-record.md +18 -0
  234. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/watch-upstream.md +18 -0
  235. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/wiki-atlas.md +19 -0
  236. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/panel.js +261 -513
  237. package/scaffold/.agent/skills/total-recall/plugins/security/DESIGN.md +84 -0
  238. package/scaffold/.agent/skills/total-recall/plugins/security/README.md +4 -2
  239. package/scaffold/.agent/skills/total-recall/plugins/security/cli.mjs +7 -19
  240. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +6 -6
  241. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +2 -3
  242. package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +19 -52
  243. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/device-evidence.md +21 -0
  244. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/evidence-desk.md +18 -0
  245. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/guided-device-review.md +17 -0
  246. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/host-and-network.md +21 -0
  247. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/https-headers.md +17 -0
  248. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/mesh-coverage.md +18 -0
  249. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/private-security-tools.md +16 -0
  250. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/single-origin-header-check.md +17 -0
  251. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/source-review.md +21 -0
  252. package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/ssh-permission-plan.md +17 -0
  253. package/scaffold/.agent/skills/total-recall/plugins/security/ui/home.js +283 -0
  254. package/scaffold/.agent/skills/total-recall/plugins/ssss/DESIGN.md +93 -0
  255. package/scaffold/.agent/skills/total-recall/plugins/ssss/package-lock.json +2 -2
  256. package/scaffold/.agent/skills/total-recall/plugins/ssss/package.json +2 -1
  257. package/scaffold/.agent/skills/total-recall/plugins/ssss/plugin.json +5 -3
  258. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/conformance.md +26 -0
  259. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/registry.md +37 -0
  260. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/repair.md +42 -0
  261. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/scaffold.md +33 -0
  262. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/status.md +43 -0
  263. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/validate.md +34 -0
  264. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/validation-diagnostics.md +17 -0
  265. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/workspace-registry-preflight.md +17 -0
  266. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/home.js +348 -0
  267. package/scaffold/.agent/skills/total-recall/references/operations.md +2 -0
  268. package/src/cli/api.mjs +3 -3
  269. package/src/cli/brief.mjs +3 -0
  270. package/src/cli/config.mjs +16 -0
  271. package/src/cli/connect.mjs +2 -7
  272. package/src/cli/plugin/chunks.mjs +145 -0
  273. package/src/cli/plugin/create.mjs +24 -52
  274. package/src/cli/plugin/index.mjs +20 -9
  275. package/src/cli/setup.mjs +2 -9
  276. package/src/cli/start.mjs +1 -0
  277. package/src/cli/startup.mjs +18 -0
  278. package/src/core/app-deploy/design-tokens.mjs +14 -9
  279. package/src/core/app-deploy/ui-elements.mjs +1 -1
  280. package/src/core/brain-registry.mjs +5 -0
  281. package/src/core/brain-updates.mjs +5 -1
  282. package/src/core/daemon-control.mjs +5 -1
  283. package/src/core/dashboard-bundle.mjs +261 -0
  284. package/src/core/default-plugin-refresh.mjs +39 -0
  285. package/src/core/ensure-dependencies.mjs +19 -15
  286. package/src/core/memory-brain.mjs +30 -8
  287. package/src/core/plugin-activation.mjs +63 -20
  288. package/src/core/plugin-contracts/{card.mjs → manifest.mjs} +23 -57
  289. package/src/core/plugin-contracts/startup-check.mjs +49 -0
  290. package/src/core/plugin-contracts/ui.mjs +9 -3
  291. package/src/core/plugin-distribution.mjs +6 -6
  292. package/src/core/plugin-lifecycle.mjs +58 -0
  293. package/src/core/plugin-loader.mjs +9 -5
  294. package/src/core/plugin-runner.mjs +21 -10
  295. package/src/core/plugin-startup-checks.mjs +44 -0
  296. package/src/core/plugin-state.mjs +19 -5
  297. package/src/core/plugin-store.mjs +30 -11
  298. package/src/core/project-id.mjs +15 -5
  299. package/src/core/required-plugins.mjs +31 -6
  300. package/src/core/schema.mjs +2 -0
  301. package/src/core/ssss-operation-service.mjs +1 -0
  302. package/src/core/startup-health.mjs +28 -3
  303. package/src/core/testing/plugin-fixture.mjs +22 -21
  304. package/src/core/throttled-fetch.mjs +25 -18
  305. package/src/core/ui-chunk-choice.mjs +77 -0
  306. package/src/core/ui-chunk.registry.json +23 -0
  307. package/src/core/ui-chunks.mjs +434 -0
  308. package/src/core/vault-cache.mjs +58 -59
  309. package/src/core/workspace-compositions.mjs +151 -0
  310. package/src/core/workspace-drawers.mjs +79 -0
  311. package/src/server/api.mjs +4 -27
  312. package/src/server/index.mjs +28 -21
  313. package/src/server/memory-events.mjs +31 -0
  314. package/src/server/plugin-brain-targets.mjs +89 -0
  315. package/src/server/rest.mjs +2 -0
  316. package/src/server/route-inventory.mjs +3 -2
  317. package/src/server/route-manifest.json +52 -4
  318. package/src/server/routes/_shared.mjs +7 -14
  319. package/src/server/routes/brains.mjs +29 -44
  320. package/src/server/routes/dashboard.mjs +26 -0
  321. package/src/server/routes/plugins.mjs +154 -45
  322. package/src/server/routes/ui-chunks.mjs +192 -0
  323. package/frontend/dist/assets/index-DACh1dhx.js +0 -5613
  324. package/frontend/dist/assets/index-DtwsDyFM.css +0 -1
  325. package/frontend/src/components/plugins/card/CardEngine.tsx +0 -108
  326. package/frontend/src/components/plugins/card/CardScenes.tsx +0 -103
  327. package/frontend/src/components/plugins/card/ExecutionPicker.tsx +0 -64
  328. package/frontend/src/components/plugins/card/args.ts +0 -28
  329. package/frontend/src/components/plugins/card/card.css +0 -32
  330. package/frontend/src/components/plugins/card/cli-line.ts +0 -13
  331. package/frontend/src/components/plugins/card/contract.ts +0 -91
  332. package/frontend/src/components/plugins/card/format.ts +0 -49
  333. package/frontend/src/components/plugins/card/runner-context.ts +0 -11
  334. package/frontend/src/components/plugins/card/runner.tsx +0 -43
  335. package/frontend/src/components/plugins/card/theme.ts +0 -35
  336. package/frontend/src/components/plugins/card/use-source.ts +0 -22
  337. package/frontend/src/components/plugins/card/widgets.tsx +0 -94
  338. package/frontend/src/components/plugins/workspace/WorkspaceHost.tsx +0 -23
  339. package/frontend/src/pages/PluginsPage.tsx +0 -1719
  340. package/scaffold/.agent/skills/plugin/evals/cases/04-card-collects-credential.mjs +0 -47
  341. package/scaffold/.agent/skills/plugin/prompts/06-card.md +0 -46
  342. package/scaffold/.agent/skills/plugin/references/card.md +0 -90
  343. package/scaffold/.agent/skills/plugin/subagents/card-designer.md +0 -60
  344. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/DESIGN.md +0 -67
  345. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/card.js +0 -1179
  346. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/DESIGN.md +0 -32
  347. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +0 -588
  348. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +0 -575
  349. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/DESIGN.md +0 -32
  350. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +0 -482
  351. package/scaffold/.agent/skills/total-recall/plugins/git/ui/DESIGN.md +0 -100
  352. package/scaffold/.agent/skills/total-recall/plugins/git/ui/card.js +0 -637
  353. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/DESIGN.md +0 -217
  354. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +0 -32
  355. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +0 -1276
  356. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +0 -45
  357. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +0 -1401
  358. package/scaffold/.agent/skills/total-recall/plugins/security/scripts/build-ui.mjs +0 -4
  359. package/scaffold/.agent/skills/total-recall/plugins/security/ui/DESIGN.md +0 -41
  360. package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +0 -396
  361. package/scaffold/.agent/skills/total-recall/plugins/security/ui/panel.js +0 -98
  362. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/DESIGN.md +0 -15
  363. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/card.js +0 -182
@@ -0,0 +1,353 @@
1
+ /**
2
+ * Embeddings Home — the plugin's native page.
3
+ *
4
+ * Answers, from the plugin's own JSON operations: which provider serves
5
+ * vectors and whether text leaves this machine, how much of the vault has a
6
+ * usable vector, which models the endpoint offers, and how fast the selected
7
+ * model embeds. Reads `status` and `models` on open; benchmark and pull run
8
+ * only when the operator asks. Anything not reported renders as a dash.
9
+ */
10
+
11
+ const DASH = '—';
12
+ const BENCHMARK_MAX = 20;
13
+
14
+ function escapeHtml(value) {
15
+ return String(value).replace(/[&<>"']/g, c => ({
16
+ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;',
17
+ }[c]));
18
+ }
19
+
20
+ /** A reported value, or a dash when the operation did not report one. */
21
+ function shown(value) {
22
+ return value === null || value === undefined || value === '' ? DASH : escapeHtml(value);
23
+ }
24
+
25
+ function formatBytes(n) {
26
+ if (!Number.isFinite(n)) return DASH;
27
+ if (n < 1024) return `${n} B`;
28
+ if (n < 1024 ** 2) return `${(n / 1024).toFixed(1)} KB`;
29
+ if (n < 1024 ** 3) return `${(n / 1024 ** 2).toFixed(1)} MB`;
30
+ return `${(n / 1024 ** 3).toFixed(2)} GB`;
31
+ }
32
+
33
+ /** host.run may hand back parsed JSON, raw stdout, or a { stdout } envelope. */
34
+ export function parseResult(res) {
35
+ if (res && typeof res === 'object' && typeof res.stdout === 'string') return parseResult(res.stdout);
36
+ if (res && typeof res === 'object') return res;
37
+ if (typeof res === 'string' && res.trim().startsWith('{')) return JSON.parse(res);
38
+ throw new Error('the operation returned no JSON');
39
+ }
40
+
41
+ const LOCALITY = {
42
+ local: { tone: 'ok', label: 'Local', note: 'Text sent for embedding stays on this machine.' },
43
+ remote: { tone: 'warn', label: 'Remote', note: 'The endpoint or the selected model runs on another machine, so vault text leaves this host.' },
44
+ unknown: { tone: 'warn', label: 'Unknown', note: 'No local model qualifies. Total Recall may try a hosted provider, which would send vault text off this machine.' },
45
+ disabled: { tone: 'muted', label: 'Disabled', note: 'Embeddings are turned off for this brain.' },
46
+ };
47
+
48
+ export class EmbeddingsHome extends HTMLElement {
49
+ constructor() {
50
+ super();
51
+ this.status = { phase: 'loading' };
52
+ this.models = { phase: 'loading' };
53
+ this.bench = { phase: 'idle' };
54
+ this.pull = { phase: 'idle' };
55
+ this.count = 10;
56
+ this.pullModel = '';
57
+ }
58
+
59
+ connectedCallback() {
60
+ if (!this.shadowRoot) this.attachShadow({ mode: 'open' });
61
+ this.render();
62
+ this.load();
63
+ }
64
+
65
+ async read(op, args) {
66
+ try {
67
+ return { phase: 'ready', data: parseResult(await this.host.run(op, args)) };
68
+ } catch (err) {
69
+ return { phase: 'unavailable', error: err?.message || String(err) };
70
+ }
71
+ }
72
+
73
+ async load() {
74
+ if (!this.host) {
75
+ const error = 'No Total Recall host is connected, so the plugin operations cannot run.';
76
+ this.status = { phase: 'unavailable', error };
77
+ this.models = { phase: 'unavailable', error };
78
+ this.render();
79
+ return;
80
+ }
81
+ this.status = { phase: 'loading' };
82
+ this.models = { phase: 'loading' };
83
+ this.render();
84
+ [this.status, this.models] = await Promise.all([
85
+ this.read('status', ['--json']),
86
+ this.read('models', ['--json']),
87
+ ]);
88
+ this.render();
89
+ }
90
+
91
+ /** Runs a user-triggered operation; a JSON body with ok:false is a failure. */
92
+ async act(slot, op, args) {
93
+ if (!this.host || this[slot].phase === 'running') return;
94
+ this[slot] = { phase: 'running' };
95
+ this.render();
96
+ const result = await this.read(op, args);
97
+ if (result.phase !== 'ready') this[slot] = { phase: 'failed', error: result.error };
98
+ else if (result.data.ok === false) this[slot] = { phase: 'failed', error: result.data.reason || 'the operation reported a failure', data: result.data };
99
+ else this[slot] = { phase: 'done', data: result.data };
100
+ this.render();
101
+ }
102
+
103
+ runBenchmark() {
104
+ const n = Number(this.count);
105
+ if (!Number.isInteger(n) || n < 1 || n > BENCHMARK_MAX) {
106
+ this.bench = { phase: 'failed', error: `Samples must be a whole number from 1 to ${BENCHMARK_MAX}.` };
107
+ this.render();
108
+ return;
109
+ }
110
+ this.act('bench', 'benchmark', ['--count', String(n), '--json']);
111
+ }
112
+
113
+ async runPull() {
114
+ const model = this.pullModel.trim();
115
+ if (!model) {
116
+ this.pull = { phase: 'failed', error: 'Type the exact model name to pull.' };
117
+ this.render();
118
+ return;
119
+ }
120
+ await this.act('pull', 'pull', [model, '--json']);
121
+ if (this.pull.phase === 'done') this.load();
122
+ }
123
+
124
+ renderProvider() {
125
+ const s = this.status;
126
+ if (s.phase === 'loading') return `<p class="notice" data-design-component="notice">Reading provider status${DASH}</p>`;
127
+ if (s.phase !== 'ready') return `<p class="notice bad" data-design-component="notice">Provider status unavailable: ${escapeHtml(s.error)}</p>`;
128
+ const d = s.data;
129
+ const loc = LOCALITY[d.locality] || { tone: 'warn', label: d.locality || 'Unreported', note: '' };
130
+ const attempts = Array.isArray(d.attempts) ? d.attempts : [];
131
+ return `
132
+ <div class="verdict">
133
+ <span class="chip ${loc.tone}" data-design-component="locality-chip">${escapeHtml(loc.label)}</span>
134
+ <span class="note">${escapeHtml(loc.note)}</span>
135
+ </div>
136
+ <dl class="facts">
137
+ <div><dt>Provider</dt><dd>${shown(d.provider)}</dd></div>
138
+ <div><dt>Endpoint</dt><dd class="mono">${shown(d.endpoint)}</dd></div>
139
+ <div><dt>Selected model</dt><dd class="mono">${shown(d.selected_model)}</dd></div>
140
+ <div><dt>Vector width</dt><dd class="mono">${d.embedding_dims ? `${escapeHtml(d.embedding_dims)} dims` : DASH}</dd></div>
141
+ </dl>
142
+ ${d.reason ? `<p class="notice" data-design-component="notice">${escapeHtml(d.reason)}</p>` : ''}
143
+ ${attempts.length ? `
144
+ <ul class="attempts">
145
+ ${attempts.map(a => `
146
+ <li class="mono ${a.reachable ? 'ok' : 'bad'}">${escapeHtml(a.url)} ${DASH} ${a.reachable ? 'reachable' : `unreachable: ${shown(a.reason)}`}</li>`).join('')}
147
+ </ul>` : ''}`;
148
+ }
149
+
150
+ renderCredentials() {
151
+ const fallback = this.status.phase === 'ready' ? this.status.data.hosted_fallback : null;
152
+ return `
153
+ <dl class="facts">
154
+ <div><dt>Hosted fallback</dt><dd class="mono">${shown(fallback)}</dd></div>
155
+ <div><dt>Credential owner</dt><dd>Auth</dd></div>
156
+ </dl>
157
+ <p class="notice" data-design-component="notice">Keys for hosted embedding providers are held by the Auth owner. This plugin does not read, list or display them, so their readiness is reported as unknown rather than guessed.</p>`;
158
+ }
159
+
160
+ renderCoverage() {
161
+ const s = this.status;
162
+ if (s.phase === 'loading') return `<p class="notice" data-design-component="notice">Counting vectors${DASH}</p>`;
163
+ if (s.phase !== 'ready') return `<p class="notice bad" data-design-component="notice">Coverage unavailable: ${escapeHtml(s.error)}</p>`;
164
+ const b = s.data.brain;
165
+ if (!b) return '<p class="notice" data-design-component="notice">No brain was found in the working directory or home, so there is no vault to measure.</p>';
166
+ if (b.state !== 'ok') {
167
+ return `
168
+ <p class="notice warn" data-design-component="notice">Index state <span class="mono">${shown(b.state)}</span>: ${shown(b.reason)}</p>
169
+ <dl class="facts">
170
+ <div><dt>Brain</dt><dd class="mono">${shown(b.dir)}</dd></div>
171
+ <div><dt>Vault nodes</dt><dd class="mono">${shown(b.vault_nodes)}</dd></div>
172
+ <div><dt>Missing a vector</dt><dd class="mono">${shown(b.missing)}</dd></div>
173
+ </dl>`;
174
+ }
175
+ const counts = [
176
+ ['Usable', b.embedded, 'ok'],
177
+ ['Stale', b.stale, b.stale ? 'warn' : ''],
178
+ ['Wrong width', b.mismatched, b.mismatched ? 'warn' : ''],
179
+ ['Missing', b.missing, b.missing ? 'warn' : ''],
180
+ ['Orphaned rows', b.orphaned, ''],
181
+ ];
182
+ return `
183
+ <div class="coverage">
184
+ <div class="figure" data-design-component="coverage-figure">${b.percent === null || b.percent === undefined ? DASH : `${escapeHtml(b.percent)}%`}</div>
185
+ <div class="figure-caption">${shown(b.embedded)} of ${shown(b.vault_nodes)} vault nodes have a current, correct-width vector</div>
186
+ </div>
187
+ <ul class="counts">
188
+ ${counts.map(([label, value, tone]) => `
189
+ <li class="count-row ${tone}" data-design-component="count-row"><span>${label}</span><span class="mono">${shown(value)}</span></li>`).join('')}
190
+ </ul>
191
+ <dl class="facts">
192
+ <div><dt>Indexed by</dt><dd class="mono">${shown(b.model)}</dd></div>
193
+ <div><dt>Index rows</dt><dd class="mono">${shown(b.rows)}</dd></div>
194
+ <div><dt>Index size</dt><dd class="mono">${formatBytes(b.db_bytes)}</dd></div>
195
+ <div><dt>Unparseable files</dt><dd class="mono">${shown(b.parse_errors)}</dd></div>
196
+ <div><dt>Brain</dt><dd class="mono">${shown(b.dir)}</dd></div>
197
+ </dl>
198
+ ${b.stale || b.mismatched || b.missing ? '<p class="notice" data-design-component="notice">Rebuild the unusable vectors with <span class="mono">total-recall compile</span>.</p>' : ''}`;
199
+ }
200
+
201
+ renderModels() {
202
+ const m = this.models;
203
+ if (m.phase === 'loading') return `<p class="notice" data-design-component="notice">Listing models${DASH}</p>`;
204
+ if (m.phase !== 'ready') return `<p class="notice bad" data-design-component="notice">Model list unavailable: ${escapeHtml(m.error)}</p>`;
205
+ const d = m.data;
206
+ if (d.reachable === false) return '<p class="notice bad" data-design-component="notice">No endpoint answered. The endpoints tried are listed under Provider.</p>';
207
+ const rows = Array.isArray(d.models) ? d.models : [];
208
+ if (!rows.length) return `<p class="notice" data-design-component="notice">${shown(d.url)} reports no models. Pull one below.</p>`;
209
+ return `
210
+ <p class="caption">${shown(d.url)} ${DASH} the vault needs ${shown(d.vault_dims)}-dim vectors</p>
211
+ <ul class="models">
212
+ ${rows.map(r => `
213
+ <li class="model-row${r.name === d.selected ? ' selected' : ''}" data-design-component="model-row">
214
+ <span class="mono name">${shown(r.name)}${r.name === d.selected ? ' <span class="tag ok">selected</span>' : ''}</span>
215
+ <span class="tags">
216
+ <span class="tag">${r.dims ? `${escapeHtml(r.dims)} dims` : 'width unknown'}</span>
217
+ <span class="tag ${r.embedding_capable ? 'ok' : ''}">${r.embedding_capable ? 'embeds' : 'no embedding'}</span>
218
+ <span class="tag ${r.compatible ? 'ok' : 'warn'}">${r.compatible ? 'vault-compatible' : 'not usable'}</span>
219
+ ${r.upstream ? '<span class="tag warn">upstream</span>' : ''}
220
+ </span>
221
+ </li>`).join('')}
222
+ </ul>`;
223
+ }
224
+
225
+ renderBenchmark() {
226
+ const b = this.bench;
227
+ const running = b.phase === 'running';
228
+ const d = b.data || {};
229
+ return `
230
+ <div class="action">
231
+ <label class="field">Samples
232
+ <input id="bench-count" type="number" min="1" max="${BENCHMARK_MAX}" step="1" value="${escapeHtml(this.count)}" ${running ? 'disabled' : ''}>
233
+ </label>
234
+ <button id="bench-run" type="button" class="primary" data-design-component="button-primary" ${running || !this.host ? 'disabled' : ''}>${running ? 'Measuring' : 'Run benchmark'}</button>
235
+ </div>
236
+ <p class="caption">Embeds a neutral sentence with the selected model, never vault text. Runs only against a local model.</p>
237
+ ${b.phase === 'failed' ? `<p class="notice bad" data-design-component="notice">Benchmark failed: ${escapeHtml(b.error)}</p>` : ''}
238
+ ${b.phase === 'done' ? `
239
+ <dl class="facts">
240
+ <div><dt>Per embedding</dt><dd class="mono">${shown(d.ms_per_embedding)} ms</dd></div>
241
+ <div><dt>Range</dt><dd class="mono">${shown(d.min_ms)}${DASH}${shown(d.max_ms)} ms</dd></div>
242
+ <div><dt>Samples</dt><dd class="mono">${shown(d.samples)} × ${shown(d.dims)} dims</dd></div>
243
+ <div><dt>Full vault</dt><dd class="mono">${d.projected_minutes === null || d.projected_minutes === undefined ? DASH : `about ${escapeHtml(d.projected_minutes)} min for ${shown(d.vault_nodes)} nodes`}</dd></div>
244
+ <div><dt>Measured</dt><dd class="mono">${shown(d.model)} on ${shown(d.url)}</dd></div>
245
+ </dl>` : ''}`;
246
+ }
247
+
248
+ renderPull() {
249
+ const p = this.pull;
250
+ const running = p.phase === 'running';
251
+ const d = p.data || {};
252
+ return `
253
+ <div class="action">
254
+ <label class="field grow">Model name
255
+ <input id="pull-model" type="text" spellcheck="false" autocomplete="off" value="${escapeHtml(this.pullModel)}" ${running ? 'disabled' : ''}>
256
+ </label>
257
+ <button id="pull-run" type="button" class="primary" data-design-component="button-primary" ${running || !this.host ? 'disabled' : ''}>${running ? 'Pulling' : 'Pull model'}</button>
258
+ </div>
259
+ <p class="caption">Downloads the named model to the configured loopback endpoint. Cloud and upstream models are refused. A pull can take several minutes.</p>
260
+ ${p.phase === 'failed' ? `<p class="notice bad" data-design-component="notice">Pull failed${d.model ? ` for <span class="mono">${escapeHtml(d.model)}</span>` : ''}: ${escapeHtml(p.error)}</p>` : ''}
261
+ ${p.phase === 'done' ? `<p class="notice ok" data-design-component="notice"><span class="mono">${shown(d.model)}</span> is ready on <span class="mono">${shown(d.url)}</span>.</p>` : ''}`;
262
+ }
263
+
264
+ render() {
265
+ const root = this.shadowRoot;
266
+ if (!root) return;
267
+ const loading = this.status.phase === 'loading' || this.models.phase === 'loading';
268
+ root.innerHTML = `
269
+ <style>
270
+ :host {
271
+ display: block;
272
+ box-sizing: border-box;
273
+ padding: var(--spacing-lg, 16px);
274
+ color: var(--colors-text, #ecfeff);
275
+ background: var(--colors-background, #07171d);
276
+ font-family: var(--typography-body-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
277
+ font-size: var(--typography-body-font-size, 13px);
278
+ }
279
+ *, *::before, *::after { box-sizing: border-box; }
280
+ @media (prefers-reduced-motion: reduce) {
281
+ *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
282
+ }
283
+ header { display: flex; align-items: center; justify-content: space-between; gap: var(--spacing-md, 12px); flex-wrap: wrap; margin-bottom: var(--spacing-lg, 16px); }
284
+ h1 { margin: 0; font-size: 18px; }
285
+ h1 + p { margin: 2px 0 0; color: var(--colors-muted, #67e8f9); font-size: var(--typography-label-font-size, 11px); }
286
+ h2 { margin: 0 0 var(--spacing-md, 12px); font-size: var(--typography-label-font-size, 11px); font-weight: var(--typography-label-font-weight, 700); letter-spacing: 0.05em; text-transform: uppercase; color: var(--colors-muted, #67e8f9); }
287
+ .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--spacing-md, 12px); }
288
+ section { background: var(--colors-surface, #0e2a35); border: 1px solid var(--colors-line, #164e63); border-radius: var(--rounded-md, 6px); padding: var(--spacing-md, 12px); min-width: 0; }
289
+ .mono { font-family: var(--typography-mono-font-family, 'JetBrains Mono', 'Fira Code', monospace); font-size: var(--typography-mono-font-size, 12px); overflow-wrap: anywhere; }
290
+ .verdict { display: flex; align-items: center; gap: var(--spacing-sm, 8px); flex-wrap: wrap; margin-bottom: var(--spacing-md, 12px); }
291
+ .chip { font-size: var(--typography-label-font-size, 11px); font-weight: 700; text-transform: uppercase; padding: var(--spacing-xs, 4px) var(--spacing-sm, 8px); border-radius: var(--rounded-md, 6px); border: 1px solid currentColor; }
292
+ .note, .caption { color: var(--colors-muted, #67e8f9); font-size: var(--typography-label-font-size, 11px); }
293
+ .caption { margin: 0 0 var(--spacing-sm, 8px); }
294
+ .ok { color: var(--colors-ok, #10b981); }
295
+ .warn { color: var(--colors-warn, #f59e0b); }
296
+ .bad { color: var(--colors-danger, #ef4444); }
297
+ .muted { color: var(--colors-muted, #67e8f9); }
298
+ .facts { display: grid; gap: var(--spacing-xs, 4px); margin: 0; }
299
+ .facts div { display: flex; justify-content: space-between; gap: var(--spacing-md, 12px); }
300
+ dt { color: var(--colors-muted, #67e8f9); }
301
+ dd { margin: 0; text-align: right; }
302
+ .notice { margin: var(--spacing-sm, 8px) 0 0; padding: var(--spacing-sm, 8px); background: var(--colors-background, #07171d); border-radius: var(--rounded-sm, 4px); }
303
+ .attempts, .counts, .models { list-style: none; margin: var(--spacing-sm, 8px) 0 0; padding: 0; display: grid; gap: var(--spacing-xs, 4px); }
304
+ .coverage { display: flex; align-items: baseline; gap: var(--spacing-md, 12px); flex-wrap: wrap; margin-bottom: var(--spacing-sm, 8px); }
305
+ .figure { font-family: var(--typography-figure-font-family, 'JetBrains Mono', monospace); font-size: var(--typography-figure-font-size, 28px); font-weight: var(--typography-figure-font-weight, 800); }
306
+ .figure-caption { color: var(--colors-muted, #67e8f9); }
307
+ .count-row { display: flex; justify-content: space-between; font-family: var(--typography-mono-font-family, 'JetBrains Mono', monospace); font-size: var(--typography-mono-font-size, 12px); }
308
+ .count-row:not(.ok):not(.warn) { color: var(--colors-muted, #67e8f9); }
309
+ .counts { margin-bottom: var(--spacing-md, 12px); }
310
+ .model-row { display: flex; justify-content: space-between; align-items: center; gap: var(--spacing-sm, 8px); flex-wrap: wrap; background: var(--colors-background, #07171d); border: 1px solid var(--colors-line, #164e63); border-radius: var(--rounded-sm, 4px); padding: var(--spacing-sm, 8px); }
311
+ .model-row.selected { border-color: var(--colors-primary, #06b6d4); }
312
+ .tags { display: flex; gap: var(--spacing-xs, 4px); flex-wrap: wrap; }
313
+ .tag { font-size: 10px; padding: 2px 6px; border-radius: var(--rounded-sm, 4px); border: 1px solid var(--colors-line, #164e63); color: var(--colors-muted, #67e8f9); }
314
+ .tag.ok { color: var(--colors-ok, #10b981); }
315
+ .tag.warn { color: var(--colors-warn, #f59e0b); }
316
+ .action { display: flex; align-items: flex-end; gap: var(--spacing-sm, 8px); flex-wrap: wrap; margin-bottom: var(--spacing-sm, 8px); }
317
+ .field { display: grid; gap: var(--spacing-xs, 4px); color: var(--colors-muted, #67e8f9); font-size: var(--typography-label-font-size, 11px); }
318
+ .field.grow { flex: 1 1 180px; }
319
+ input { min-height: 44px; padding: 0 var(--spacing-sm, 8px); color: var(--colors-text, #ecfeff); background: var(--colors-background, #07171d); border: 1px solid var(--colors-line, #164e63); border-radius: var(--rounded-sm, 4px); font-family: var(--typography-mono-font-family, 'JetBrains Mono', monospace); }
320
+ input[type=number] { width: 88px; }
321
+ button.primary { min-height: 44px; padding: 0 var(--spacing-lg, 16px); border: 0; border-radius: var(--rounded-sm, 4px); cursor: pointer; font-weight: 700; color: var(--colors-on-primary, #07171d); background: var(--colors-primary, #06b6d4); transition: background 0.15s ease; }
322
+ button.primary:hover:not(:disabled) { background: var(--colors-primary-hover, #22d3ee); }
323
+ button:disabled { opacity: 0.6; cursor: not-allowed; }
324
+ button.refresh { min-height: 44px; padding: 0 var(--spacing-md, 12px); color: var(--colors-text, #ecfeff); background: transparent; border: 1px solid var(--colors-line, #164e63); border-radius: var(--rounded-sm, 4px); cursor: pointer; }
325
+ button:focus-visible, input:focus-visible { outline: 2px solid var(--colors-primary-hover, #22d3ee); outline-offset: 2px; }
326
+ </style>
327
+ <header>
328
+ <div>
329
+ <h1>Embeddings</h1>
330
+ <p>Vectors behind Total Recall search for this brain</p>
331
+ </div>
332
+ <button id="refresh" type="button" class="refresh" ${loading || !this.host ? 'disabled' : ''}>${loading ? 'Reading' : 'Refresh'}</button>
333
+ </header>
334
+ <div class="grid">
335
+ <section data-design-component="section" aria-labelledby="h-provider"><h2 id="h-provider">Provider</h2>${this.renderProvider()}</section>
336
+ <section data-design-component="section" aria-labelledby="h-coverage"><h2 id="h-coverage">Vault coverage</h2>${this.renderCoverage()}</section>
337
+ <section data-design-component="section" aria-labelledby="h-models"><h2 id="h-models">Models on the endpoint</h2>${this.renderModels()}</section>
338
+ <section data-design-component="section" aria-labelledby="h-credentials"><h2 id="h-credentials">Credentials</h2>${this.renderCredentials()}</section>
339
+ <section data-design-component="section" aria-labelledby="h-benchmark"><h2 id="h-benchmark">Benchmark</h2>${this.renderBenchmark()}</section>
340
+ <section data-design-component="section" aria-labelledby="h-pull"><h2 id="h-pull">Pull a model</h2>${this.renderPull()}</section>
341
+ </div>`;
342
+
343
+ root.getElementById('refresh')?.addEventListener('click', () => this.load());
344
+ root.getElementById('bench-count')?.addEventListener('input', e => { this.count = e.target.value; });
345
+ root.getElementById('bench-run')?.addEventListener('click', () => this.runBenchmark());
346
+ root.getElementById('pull-model')?.addEventListener('input', e => { this.pullModel = e.target.value; });
347
+ root.getElementById('pull-run')?.addEventListener('click', () => this.runPull());
348
+ }
349
+ }
350
+
351
+ if (!customElements.get('tr-embeddings-home')) {
352
+ customElements.define('tr-embeddings-home', EmbeddingsHome);
353
+ }
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: Git Copper Ledger
3
+ description: A copper and paper ledger for repository state and linked worktrees.
4
+ colors:
5
+ background: "#fcf7ef"
6
+ surface: "#f5e9d9"
7
+ text: "#32241b"
8
+ border: "#b29176"
9
+ accent: "#85411c"
10
+ muted: "#684b38"
11
+ danger: "#9c2924"
12
+ typography:
13
+ body:
14
+ fontFamily: "system-ui, sans-serif"
15
+ heading:
16
+ fontFamily: "Georgia, serif"
17
+ mono:
18
+ fontFamily: "ui-monospace, monospace"
19
+ spacing:
20
+ md: 16px
21
+ rounded:
22
+ md: 6px
23
+ ---
24
+
25
+ # Git Copper Ledger
26
+
27
+ Use a warm paper background, a serif title, and tabular monospace counts. The repository audit reads first. Present conflicts and unpushed commits beside separate staged, unstaged, and untracked counts. Reserve copper for navigation and focus, and use red with a written label for failures.
28
+
29
+ Below the audit, list the registered worktrees like ledger entries. Give each entry its own branch or commit, path, and state. Wrap long paths and stack the form and metrics at narrow widths. Use an inset confirmation with the exact target for worktree changes.
30
+
31
+ Treat a missing measurement as unknown. Label ahead and behind as local upstream comparisons. Announce read and action results in text, preserve a visible keyboard focus outline, and keep controls at least 44 pixels tall.
@@ -13,6 +13,8 @@ total-recall git --help # the plugin's operations
13
13
  total-recall git commit --help # one plugin operation's help (-h is git's usage)
14
14
  ```
15
15
 
16
+ The native Home opens with an audit and registered worktrees. It reads diff statistics on request and confirms the exact destination or target before a worktree change. Its [design](DESIGN.md) and SSSS blocks under `ui/chunks/` ship with the plugin.
17
+
16
18
  ## Install
17
19
 
18
20
  ```bash
@@ -65,10 +67,28 @@ The task `cli update --scheduled` runs daily on every node.
65
67
  ## Across the mesh
66
68
 
67
69
  ```bash
68
- total-recall git fleet --all-nodes # dirty, unpushed, behind, diverged, stale stashes, abandoned worktrees
70
+ total-recall git fleet --all-nodes # dirty, unpushed, behind, diverged, stale stashes, abandoned worktrees, unmerged
69
71
  total-recall git where <commit> # machines and checkouts that contain a commit
70
72
  ```
71
73
 
74
+ ## Unmerged work
75
+
76
+ ```bash
77
+ total-recall git unmerged [--json] # this repository
78
+ total-recall git unmerged --registered # every registered repository
79
+ ```
80
+
81
+ Lists local branches with commits the default branch lacks, linked worktrees with uncommitted
82
+ changes, and detached worktrees holding commits that no branch contains (removing such a worktree
83
+ loses them). A commit counts as landed when the default branch, local or origin, reaches it or holds
84
+ an equivalent patch, so rebased and cherry-picked work is not listed; a squash merge is a different
85
+ patch, so delete the branch once it has landed. Stale worktree records and branches kept on purpose
86
+ (`git config --add totalrecall.keepBranch <name>`) are shown but not counted. Registered brains
87
+ that are not git repositories are skipped.
88
+
89
+ The plugin declares this report as its `startup_check`, so `total-recall startup check` and
90
+ `brief` show the outstanding count and where it is whenever a session starts.
91
+
72
92
  ## Intent
73
93
 
74
94
  ```bash
@@ -105,8 +125,12 @@ total-recall git add -A
105
125
  total-recall git commit -m "<message>"
106
126
  total-recall git push
107
127
  total-recall git fleet --json
128
+ total-recall git unmerged
108
129
  total-recall git undo --list
109
130
  ```
110
131
 
132
+ Finish what you start: land a branch or worktree once its work is done, then remove it. `unmerged`
133
+ shows what is still outside the default branch.
134
+
111
135
  A refused commit or push names the rule or the auth key that matched; fix the cause, never bypass
112
136
  the guard. Raw commands this plugin owns: `git <command>`.
@@ -254,7 +254,11 @@ function worktrees(cwd) {
254
254
  }
255
255
 
256
256
  function worktreeOperation(action, values, target, cwd) {
257
- if (action === 'worktree-list') return { ok: true, worktrees: worktrees(cwd) };
257
+ if (action === 'worktree-list') {
258
+ const registered = worktrees(cwd);
259
+ const root = git(['rev-parse', '--show-toplevel'], cwd);
260
+ return { ok: true, worktrees: registered, current: root.ok ? root.stdout.replace(/\n$/, '') : null };
261
+ }
258
262
  const targetPath = path.resolve(cwd, target);
259
263
  if (action === 'worktree-create') {
260
264
  const commit = resolveCommit(values.base ?? 'HEAD', cwd);
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "tr-plugin-git",
3
- "version": "1.1.5",
3
+ "version": "2.2.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "tr-plugin-git",
9
- "version": "1.1.5",
9
+ "version": "2.2.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@gregiteen/ssss-cli": "0.14.5"
13
13
  },
14
14
  "devDependencies": {
15
- "total-recall-brain": "3.44.0",
15
+ "total-recall-brain": "3.45.0",
16
16
  "vitest": "^4.1.10"
17
17
  }
18
18
  },
@@ -6533,9 +6533,9 @@
6533
6533
  }
6534
6534
  },
6535
6535
  "node_modules/total-recall-brain": {
6536
- "version": "3.44.0",
6537
- "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.44.0.tgz",
6538
- "integrity": "sha512-VNPaIO9zsSwoxAsJ5ByIQBP9zPpLq4RiQO7Vrex4rBOHFQJT50P7utcZiLMSZTyZJU4C/m5uB8qTCSBMp6+l6Q==",
6536
+ "version": "3.45.0",
6537
+ "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.45.0.tgz",
6538
+ "integrity": "sha512-HDYfROazZbsLHQsFPnlBcSpe1HL1QEi7JG8x/eNRUI06RxVQsZWl8LwBo2lTWjWRDrKmCy7BUmSXQDuWF3lrEw==",
6539
6539
  "dev": true,
6540
6540
  "license": "MIT",
6541
6541
  "workspaces": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tr-plugin-git",
3
- "version": "1.1.5",
3
+ "version": "2.2.0",
4
4
  "type": "module",
5
5
  "description": "Reports the state of the current git repository: branch, dirty files, unpushed commits and stashes.",
6
6
  "scripts": {
@@ -11,6 +11,7 @@
11
11
  "files": [
12
12
  "cli.mjs",
13
13
  "plugin.json",
14
+ "DESIGN.md",
14
15
  "src/",
15
16
  "README.md",
16
17
  "LICENSE",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://github.com/gregiteen/total-recall/blob/main/metadata.plugin.schema.json",
3
3
  "id": "git",
4
4
  "name": "Git",
5
- "version": "2.0.1",
5
+ "version": "2.2.0",
6
6
  "description": "The whole git CLI through Total Recall: sign-in from the auth store, guarded commits and pushes, undo, fleet state, and the intent behind every change.",
7
7
  "author": "Total Recall",
8
8
  "license": "MIT",
@@ -54,6 +54,9 @@
54
54
  { "name": "list", "flag": "--list", "type": "boolean", "label": "List snapshots" }
55
55
  ] },
56
56
  { "name": "fleet", "description": "Dirty, unpushed, behind, diverged, stale stashes and abandoned worktrees across registered repositories; --all-nodes for the mesh", "effect": "read", "timeout_ms": 600000 },
57
+ { "name": "unmerged", "description": "Branches with commits not in the default branch, worktrees with uncommitted changes and detached worktrees holding commits on no branch; --registered for every registered repository", "effect": "read", "output": "json", "timeout_ms": 600000, "args": [
58
+ { "name": "registered", "flag": "--registered", "type": "boolean", "label": "Every registered repository" }
59
+ ] },
57
60
  { "name": "where", "description": "Machines and checkouts that contain a commit", "effect": "read", "args": [
58
61
  { "name": "commit", "type": "string", "label": "Commit", "required": true, "positional": true }
59
62
  ] },
@@ -88,35 +91,21 @@
88
91
  }
89
92
  ]
90
93
  },
91
- "card_face": {
92
- "skin": "copper-obsidian",
93
- "theme": "copper",
94
- "headline": "Worktree Hygiene & Repository Watch",
95
- "primary_color": "#b45309",
96
- "secondary_color": "#0c0a09",
97
- "accent_color": "#f59e0b",
98
- "touch_layout": "comfortable",
99
- "interactive": true,
100
- "quick_actions": [
101
- {
102
- "subcommand": "audit",
103
- "label": "AUDIT"
104
- },
105
- {
106
- "subcommand": "diff",
107
- "label": "DIFFSTAT"
108
- }
109
- ]
110
- },
111
94
  "ui": {
112
- "design_tokens": "ui/DESIGN.md",
95
+ "design_tokens": "DESIGN.md",
96
+ "home": "repository",
113
97
  "elements": [
114
98
  {
115
- "id": "card",
116
- "kind": "card",
117
- "tag": "tr-git-card",
118
- "module": "ui/card.js",
119
- "description": "Git Hygiene Repository Hygiene Card Face"
99
+ "id": "repository",
100
+ "kind": "panel",
101
+ "tag": "tr-git-home",
102
+ "module": "ui/home.js",
103
+ "description": "Repository audit, diff stats, and linked worktrees",
104
+ "tokens": ["color-text", "color-surface", "color-border", "spacing-md", "radius-md"],
105
+ "optional_tokens": [
106
+ "color-background", "color-accent", "color-muted", "color-danger",
107
+ "typography-body-font-family", "typography-heading-font-family", "typography-mono-font-family"
108
+ ]
120
109
  }
121
110
  ]
122
111
  },
@@ -150,6 +139,7 @@
150
139
  "badge": "Repository Hygiene",
151
140
  "font": "space-grotesk"
152
141
  },
142
+ "startup_check": { "command": "unmerged", "args": ["--json"], "timeout_ms": 20000 },
153
143
  "status": {
154
144
  "command": "audit",
155
145
  "refresh_seconds": 60
@@ -1,4 +1,26 @@
1
+ import { spawn } from 'node:child_process';
1
2
  import { git, tr, ledger, intent, session } from '../lib/context.mjs';
3
+ import { defaultBranch } from './unmerged.mjs';
4
+
5
+ /**
6
+ * Ask OpenWiki to refresh this repository without waiting for it. A due refresh
7
+ * regenerates pages with a model for minutes; OpenWiki throttles repeats, keeps
8
+ * its own 30-minute limit and writes the outcome to openwiki/.refresh-attempt.json.
9
+ * Waiting here held every commit for 30 s, then killed only the CLI: the
10
+ * generator finished on its own while the commit reported the refresh as failed.
11
+ */
12
+ export function requestWikiRefresh(ctx, launch = spawn) {
13
+ try {
14
+ const child = launch(ctx.env.GIT_PLUGIN_TR_BIN || 'total-recall', ['openwiki', 'refresh', '--repo', ctx.cwd, '--apply', '--json'], {
15
+ cwd: ctx.cwd, env: ctx.env, detached: true, stdio: 'ignore', shell: false,
16
+ });
17
+ child.on?.('error', () => {});
18
+ child.unref?.();
19
+ return child.pid ? { status: 'requested', command: 'openwiki refresh', outcome: 'openwiki/.refresh-attempt.json' } : { status: 'failed', command: 'openwiki refresh', reason: 'could not start' };
20
+ } catch {
21
+ return { status: 'failed', command: 'openwiki refresh', reason: 'could not start' };
22
+ }
23
+ }
2
24
 
3
25
  export const guards = [{
4
26
  name: 'commit-memory',
@@ -15,16 +37,18 @@ export const guards = [{
15
37
  // Save the commit before any optional provider call.
16
38
  store.append(record, { idempotencyKey: `commit-${sha}` });
17
39
  const memory = record.decisions.length ? tr(ctx, ['remember', 'decision', `${record.decisions.join('\n')}\nCommit: ${sha}`, '--project', '--slug', `git-decision-${sha}`]) : null;
18
- const available = tr(ctx, ['openwiki', '--help']);
19
40
  let wiki;
20
- if (available.status !== 0 || available.error) wiki = { status: 'skipped', reason: 'OpenWiki is unavailable' };
41
+ // The wiki documents the default branch. Regenerating it from a feature branch spends model
42
+ // calls on pages that only conflict when the branch merges.
43
+ const branch = ctx.git(['symbolic-ref', '--quiet', '--short', 'HEAD']);
44
+ const base = defaultBranch(ctx);
45
+ if (!base || branch.status !== 0 || String(branch.stdout).trim() !== base.name) wiki = { status: 'skipped', reason: 'not on the default branch' };
21
46
  else {
22
- // The current OpenWiki CLI accepts a refresh request, but has no queue verb.
23
- const refresh = tr(ctx, ['openwiki', 'refresh', '--repo', ctx.cwd, '--apply', '--json']);
24
- wiki = { status: refresh.status === 0 && !refresh.error ? 'requested' : 'failed', command: 'openwiki refresh' };
47
+ const available = tr(ctx, ['openwiki', '--help']);
48
+ wiki = available.status !== 0 || available.error ? { status: 'skipped', reason: 'OpenWiki is unavailable' } : requestWikiRefresh(ctx);
25
49
  }
26
50
  store.append({ type: 'git.commit_memory', sha, timestamp: new Date().toISOString(), memory: memory === null ? 'skipped: no named decision' : memory.status === 0 && !memory.error ? 'recorded' : 'failed', openwiki: wiki });
27
51
  if (memory && (memory.status !== 0 || memory.error)) console.error('Commit saved. Repository decision memory failed.');
28
- if (wiki.status === 'failed') console.error('Commit saved. OpenWiki refresh failed.');
52
+ if (wiki.status === 'failed') console.error('Commit saved. The OpenWiki refresh could not be started.');
29
53
  },
30
54
  }];