total-recall-brain 3.45.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 (362) hide show
  1. package/bin/total-recall.mjs +4 -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/ensure-dependencies.mjs +19 -15
  285. package/src/core/memory-brain.mjs +30 -8
  286. package/src/core/plugin-activation.mjs +63 -20
  287. package/src/core/plugin-contracts/{card.mjs → manifest.mjs} +23 -57
  288. package/src/core/plugin-contracts/startup-check.mjs +49 -0
  289. package/src/core/plugin-contracts/ui.mjs +9 -3
  290. package/src/core/plugin-distribution.mjs +6 -6
  291. package/src/core/plugin-lifecycle.mjs +58 -0
  292. package/src/core/plugin-loader.mjs +9 -5
  293. package/src/core/plugin-runner.mjs +21 -10
  294. package/src/core/plugin-startup-checks.mjs +44 -0
  295. package/src/core/plugin-state.mjs +19 -5
  296. package/src/core/plugin-store.mjs +30 -11
  297. package/src/core/project-id.mjs +15 -5
  298. package/src/core/required-plugins.mjs +31 -6
  299. package/src/core/schema.mjs +2 -0
  300. package/src/core/ssss-operation-service.mjs +1 -0
  301. package/src/core/startup-health.mjs +28 -3
  302. package/src/core/testing/plugin-fixture.mjs +22 -21
  303. package/src/core/throttled-fetch.mjs +25 -18
  304. package/src/core/ui-chunk-choice.mjs +77 -0
  305. package/src/core/ui-chunk.registry.json +23 -0
  306. package/src/core/ui-chunks.mjs +434 -0
  307. package/src/core/vault-cache.mjs +58 -59
  308. package/src/core/workspace-compositions.mjs +151 -0
  309. package/src/core/workspace-drawers.mjs +79 -0
  310. package/src/server/api.mjs +4 -27
  311. package/src/server/index.mjs +28 -21
  312. package/src/server/memory-events.mjs +31 -0
  313. package/src/server/plugin-brain-targets.mjs +89 -0
  314. package/src/server/rest.mjs +2 -0
  315. package/src/server/route-inventory.mjs +3 -2
  316. package/src/server/route-manifest.json +52 -4
  317. package/src/server/routes/_shared.mjs +7 -14
  318. package/src/server/routes/brains.mjs +29 -44
  319. package/src/server/routes/dashboard.mjs +26 -0
  320. package/src/server/routes/plugins.mjs +154 -45
  321. package/src/server/routes/ui-chunks.mjs +192 -0
  322. package/frontend/dist/assets/index-DACh1dhx.js +0 -5613
  323. package/frontend/dist/assets/index-DtwsDyFM.css +0 -1
  324. package/frontend/src/components/plugins/card/CardEngine.tsx +0 -108
  325. package/frontend/src/components/plugins/card/CardScenes.tsx +0 -103
  326. package/frontend/src/components/plugins/card/ExecutionPicker.tsx +0 -64
  327. package/frontend/src/components/plugins/card/args.ts +0 -28
  328. package/frontend/src/components/plugins/card/card.css +0 -32
  329. package/frontend/src/components/plugins/card/cli-line.ts +0 -13
  330. package/frontend/src/components/plugins/card/contract.ts +0 -91
  331. package/frontend/src/components/plugins/card/format.ts +0 -49
  332. package/frontend/src/components/plugins/card/runner-context.ts +0 -11
  333. package/frontend/src/components/plugins/card/runner.tsx +0 -43
  334. package/frontend/src/components/plugins/card/theme.ts +0 -35
  335. package/frontend/src/components/plugins/card/use-source.ts +0 -22
  336. package/frontend/src/components/plugins/card/widgets.tsx +0 -94
  337. package/frontend/src/components/plugins/workspace/WorkspaceHost.tsx +0 -23
  338. package/frontend/src/pages/PluginsPage.tsx +0 -1719
  339. package/scaffold/.agent/skills/plugin/evals/cases/04-card-collects-credential.mjs +0 -47
  340. package/scaffold/.agent/skills/plugin/prompts/06-card.md +0 -46
  341. package/scaffold/.agent/skills/plugin/references/card.md +0 -90
  342. package/scaffold/.agent/skills/plugin/subagents/card-designer.md +0 -60
  343. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/DESIGN.md +0 -67
  344. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/card.js +0 -1179
  345. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/DESIGN.md +0 -32
  346. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +0 -588
  347. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +0 -575
  348. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/DESIGN.md +0 -32
  349. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +0 -482
  350. package/scaffold/.agent/skills/total-recall/plugins/git/ui/DESIGN.md +0 -100
  351. package/scaffold/.agent/skills/total-recall/plugins/git/ui/card.js +0 -637
  352. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/DESIGN.md +0 -217
  353. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +0 -32
  354. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +0 -1276
  355. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +0 -45
  356. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +0 -1401
  357. package/scaffold/.agent/skills/total-recall/plugins/security/scripts/build-ui.mjs +0 -4
  358. package/scaffold/.agent/skills/total-recall/plugins/security/ui/DESIGN.md +0 -41
  359. package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +0 -396
  360. package/scaffold/.agent/skills/total-recall/plugins/security/ui/panel.js +0 -98
  361. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/DESIGN.md +0 -15
  362. package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/card.js +0 -182
@@ -1,1179 +0,0 @@
1
- /**
2
- * Auth & Secrets — Hardware WebAuthn FIDO2, OAuth Identity & Secrets Store.
3
- *
4
- * This face is purpose-built for the operator: it provides an instant
5
- * verdict on the secrets store, hardware biometric passkeys, Google OAuth
6
- * account tokens, and system security audit baseline findings.
7
- *
8
- * Every value traces directly to a host command read. A value the command did not
9
- * supply renders an em dash with its reason; nothing is seeded, and nothing is
10
- * defaulted to a reassuring word.
11
- *
12
- * Design rationale: ui/DESIGN.md.
13
- */
14
-
15
- const DASH = '\u2014';
16
-
17
- function escapeHtml(value) {
18
- if (value === null || value === undefined) return '';
19
- return String(value).replace(/[&<>"']/g, (c) => ({
20
- '&': '&amp;',
21
- '<': '&lt;',
22
- '>': '&gt;',
23
- '"': '&quot;',
24
- "'": '&#39;',
25
- }[c]));
26
- }
27
-
28
- function asObject(result) {
29
- if (result === null || result === undefined) return null;
30
- if (typeof result === 'object') {
31
- if (typeof result.output === 'string') {
32
- try {
33
- const parsed = JSON.parse(result.output);
34
- return typeof parsed === 'object' ? parsed : null;
35
- } catch {
36
- return null;
37
- }
38
- }
39
- return result;
40
- }
41
- if (typeof result === 'string') {
42
- try {
43
- const parsed = JSON.parse(result);
44
- return typeof parsed === 'object' ? parsed : null;
45
- } catch {
46
- return null;
47
- }
48
- }
49
- return null;
50
- }
51
-
52
- export class AuthCard extends HTMLElement {
53
- constructor() {
54
- super();
55
- this.screen = 'secrets';
56
- this.busy = false;
57
- this.statusData = null;
58
- this.passkeysData = null;
59
- this.googleData = null;
60
- this.secretsData = null;
61
- this.auditData = null;
62
- this.lastError = null;
63
- this.lastAttempt = null;
64
- this.activeFilter = 'all';
65
- this.confirmAction = null;
66
- }
67
-
68
- get screens() {
69
- return [
70
- { id: 'secrets', label: 'Secrets Store' },
71
- { id: 'google', label: 'Google OAuth' },
72
- { id: 'passkeys', label: 'Passkeys' },
73
- { id: 'audit', label: 'Audit & Sessions' },
74
- ];
75
- }
76
-
77
- connectedCallback() {
78
- if (!this.shadowRoot) this.attachShadow({ mode: 'open' });
79
- this.render();
80
- this.onScreen = (event) => {
81
- const detail = event.detail || {};
82
- if (detail.id && this.screens.some((s) => s.id === detail.id)) {
83
- this.screen = detail.id;
84
- this.paint();
85
- }
86
- };
87
- window.addEventListener('tr:screen-change', this.onScreen);
88
- this.readAll();
89
- }
90
-
91
- disconnectedCallback() {
92
- window.removeEventListener('tr:screen-change', this.onScreen);
93
- }
94
-
95
- async readAll() {
96
- if (this.busy) return;
97
- this.busy = true;
98
- this.lastAttempt = new Date().toISOString();
99
- this.lastError = null;
100
- this.paint();
101
-
102
- try {
103
- if (this.host && typeof this.host.run === 'function') {
104
- const [statusRes, passkeysRes, googleRes, secretsRes, auditRes] = await Promise.allSettled([
105
- this.host.run('status', ['--json']),
106
- this.host.run('passkey', ['list', '--json']),
107
- this.host.run('google', ['accounts', '--json']),
108
- this.host.run('secret', ['list', '--json']),
109
- this.host.run('audit', ['--json']),
110
- ]);
111
-
112
- if (statusRes.status === 'fulfilled') {
113
- this.statusData = asObject(statusRes.value);
114
- } else {
115
- this.statusData = null;
116
- }
117
-
118
- if (passkeysRes.status === 'fulfilled') {
119
- this.passkeysData = asObject(passkeysRes.value);
120
- } else {
121
- this.passkeysData = null;
122
- }
123
-
124
- if (googleRes.status === 'fulfilled') {
125
- this.googleData = asObject(googleRes.value);
126
- } else {
127
- this.googleData = null;
128
- }
129
-
130
- if (secretsRes.status === 'fulfilled') {
131
- this.secretsData = asObject(secretsRes.value);
132
- } else {
133
- this.secretsData = null;
134
- }
135
-
136
- if (auditRes.status === 'fulfilled') {
137
- this.auditData = asObject(auditRes.value);
138
- } else {
139
- this.auditData = null;
140
- }
141
- }
142
- } catch (err) {
143
- this.lastError = err && err.message ? err.message : String(err);
144
- this.statusData = null;
145
- this.passkeysData = null;
146
- this.googleData = null;
147
- this.secretsData = null;
148
- this.auditData = null;
149
- } finally {
150
- this.busy = false;
151
- this.paint();
152
- }
153
- }
154
-
155
- async refreshGoogleAccount(accountId) {
156
- if (!this.host || typeof this.host.run !== 'function' || this.busy) return;
157
- this.busy = true;
158
- this.paint();
159
- try {
160
- await this.host.run('google', ['refresh', accountId, '--json']);
161
- await this.readAll();
162
- } catch (err) {
163
- this.lastError = err && err.message ? err.message : String(err);
164
- this.busy = false;
165
- this.paint();
166
- }
167
- }
168
-
169
- async revokePasskey(credentialId) {
170
- if (!this.host || typeof this.host.run !== 'function' || this.busy) return;
171
- this.busy = true;
172
- this.paint();
173
- try {
174
- await this.host.run('passkey', ['delete', credentialId, '--json']);
175
- this.confirmAction = null;
176
- await this.readAll();
177
- } catch (err) {
178
- this.lastError = err && err.message ? err.message : String(err);
179
- this.busy = false;
180
- this.paint();
181
- }
182
- }
183
-
184
- computeVerdict() {
185
- if (this.lastError) {
186
- return { tone: 'danger', label: 'Read Error', detail: this.lastError };
187
- }
188
- if (!this.statusData && !this.secretsData) {
189
- return { tone: 'muted', label: 'Unchecked', detail: 'Reading telemetry' };
190
- }
191
-
192
- const overdueCount = (this.secretsData?.keys || []).filter((k) => k.rotation_overdue).length;
193
- const auditPassed = this.auditData?.passed ?? true;
194
- const findingsCount = this.auditData?.findings_count ?? 0;
195
-
196
- if (!auditPassed || findingsCount > 0) {
197
- return {
198
- tone: 'danger',
199
- label: 'Policy Flagged',
200
- detail: `${findingsCount} security baseline findings detected`,
201
- };
202
- }
203
- if (overdueCount > 0) {
204
- return {
205
- tone: 'warn',
206
- label: 'Rotation Due',
207
- detail: `${overdueCount} secret keys overdue for 90-day rotation`,
208
- };
209
- }
210
- return {
211
- tone: 'ok',
212
- label: 'Secure',
213
- detail: 'Hardware passkeys active, zero findings, secrets sealed',
214
- };
215
- }
216
-
217
- render() {
218
- const root = this.shadowRoot;
219
- if (!root) return;
220
-
221
- root.innerHTML = `
222
- <style>
223
- :host {
224
- display: block;
225
- font-family: var(--font-body, 'Outfit', system-ui, sans-serif);
226
- color: var(--text-primary, var(--face-text-default, #f1f5f9));
227
- background: var(--bg-primary, var(--face-bg-default, #090d16));
228
- border: 1px solid var(--border, var(--face-border-default, #1e293b));
229
- border-radius: var(--border-radius, 8px);
230
- box-sizing: border-box;
231
- padding: 16px;
232
- min-width: 320px;
233
- max-width: 100%;
234
- line-height: 1.4;
235
-
236
- /* Palette Tokens */
237
- --face-text-default: #f1f5f9;
238
- --face-bg-default: #090d16;
239
- --face-border-default: #1e293b;
240
- --face-primary: #10b981;
241
- --face-primary-bg: #064e3b;
242
- --face-primary-text: #041f17;
243
- --face-accent: #34d399;
244
- --face-ok: #059669;
245
- --face-ok-bg: rgba(5, 150, 105, 0.15);
246
- --face-warn: #d97706;
247
- --face-warn-bg: rgba(217, 119, 6, 0.15);
248
- --face-danger: #dc2626;
249
- --face-danger-bg: rgba(220, 38, 38, 0.15);
250
- --face-muted: var(--text-secondary, #94a3b8);
251
- --face-surface: var(--bg-secondary, #0f172a);
252
- --face-surface-subtle: rgba(255, 255, 255, 0.03);
253
- --face-border: var(--border, #1e293b);
254
- --face-border-active: #334155;
255
- --face-font-mono: var(--font-mono, 'JetBrains Mono', ui-monospace, monospace);
256
- }
257
-
258
- @media (prefers-reduced-motion: reduce) {
259
- * {
260
- animation-duration: 0.01ms !important;
261
- transition-duration: 0.01ms !important;
262
- }
263
- }
264
-
265
- .header {
266
- display: flex;
267
- align-items: center;
268
- justify-content: space-between;
269
- flex-wrap: wrap;
270
- gap: 12px;
271
- padding-bottom: 14px;
272
- border-bottom: 1px solid var(--face-border);
273
- }
274
-
275
- .brand-group {
276
- display: flex;
277
- align-items: center;
278
- gap: 10px;
279
- }
280
-
281
- .wordmark {
282
- font-size: 15px;
283
- font-weight: 700;
284
- letter-spacing: 0.05em;
285
- text-transform: uppercase;
286
- color: var(--text-primary, var(--face-text-default));
287
- }
288
-
289
- .badge {
290
- font-family: var(--face-font-mono);
291
- font-size: 11px;
292
- font-weight: 600;
293
- padding: 2px 8px;
294
- border-radius: 4px;
295
- background: var(--face-primary-bg);
296
- color: var(--face-accent);
297
- border: 1px solid rgba(52, 211, 153, 0.3);
298
- text-transform: uppercase;
299
- }
300
-
301
- .verdict-line {
302
- display: flex;
303
- align-items: center;
304
- gap: 8px;
305
- padding: 4px 10px;
306
- border-radius: 6px;
307
- font-size: 13px;
308
- font-weight: 600;
309
- }
310
-
311
- .verdict-line[data-tone="ok"] {
312
- background: var(--face-ok-bg);
313
- color: var(--face-accent);
314
- border: 1px solid rgba(5, 150, 105, 0.3);
315
- }
316
-
317
- .verdict-line[data-tone="warn"] {
318
- background: var(--face-warn-bg);
319
- color: var(--face-warn);
320
- border: 1px solid rgba(217, 119, 6, 0.3);
321
- }
322
-
323
- .verdict-line[data-tone="danger"] {
324
- background: var(--face-danger-bg);
325
- color: var(--face-danger);
326
- border: 1px solid rgba(220, 38, 38, 0.3);
327
- }
328
-
329
- .verdict-line[data-tone="muted"] {
330
- background: var(--face-surface);
331
- color: var(--face-muted);
332
- border: 1px solid var(--face-border);
333
- }
334
-
335
- .verdict-dot {
336
- width: 8px;
337
- height: 8px;
338
- border-radius: 50%;
339
- background: currentColor;
340
- }
341
-
342
- .tabs-nav {
343
- display: flex;
344
- align-items: center;
345
- gap: 6px;
346
- margin-top: 14px;
347
- margin-bottom: 16px;
348
- border-bottom: 1px solid var(--face-border);
349
- padding-bottom: 10px;
350
- overflow-x: auto;
351
- }
352
-
353
- .tab-btn {
354
- min-height: 44px;
355
- padding: 8px 14px;
356
- border-radius: 6px;
357
- border: 1px solid transparent;
358
- background: transparent;
359
- color: var(--face-muted);
360
- font-family: inherit;
361
- font-size: 13px;
362
- font-weight: 600;
363
- cursor: pointer;
364
- white-space: nowrap;
365
- display: inline-flex;
366
- align-items: center;
367
- gap: 6px;
368
- }
369
-
370
- .tab-btn:hover {
371
- color: var(--text-primary, var(--face-text-default));
372
- background: var(--face-surface-subtle);
373
- }
374
-
375
- .tab-btn.active {
376
- color: var(--face-accent);
377
- background: var(--face-surface);
378
- border-color: var(--face-border-active);
379
- }
380
-
381
- .refresh-btn {
382
- min-height: 44px;
383
- padding: 8px 14px;
384
- border-radius: 6px;
385
- border: 1px solid var(--face-border);
386
- background: var(--face-surface);
387
- color: var(--text-primary, var(--face-text-default));
388
- font-family: inherit;
389
- font-size: 13px;
390
- font-weight: 500;
391
- cursor: pointer;
392
- display: inline-flex;
393
- align-items: center;
394
- gap: 6px;
395
- margin-left: auto;
396
- }
397
-
398
- .refresh-btn:hover {
399
- background: var(--face-border-active);
400
- }
401
-
402
- .screen-container {
403
- min-height: 220px;
404
- }
405
-
406
- .metrics-strip {
407
- display: grid;
408
- grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
409
- gap: 10px;
410
- margin-bottom: 16px;
411
- }
412
-
413
- .metric-card {
414
- background: var(--face-surface);
415
- border: 1px solid var(--face-border);
416
- border-radius: 6px;
417
- padding: 10px 12px;
418
- }
419
-
420
- .metric-label {
421
- font-size: 11px;
422
- color: var(--face-muted);
423
- text-transform: uppercase;
424
- letter-spacing: 0.04em;
425
- margin-bottom: 4px;
426
- }
427
-
428
- .metric-value {
429
- font-family: var(--face-font-mono);
430
- font-size: 18px;
431
- font-weight: 700;
432
- color: var(--text-primary, var(--face-text-default));
433
- }
434
-
435
- .metric-sub {
436
- font-size: 11px;
437
- color: var(--face-muted);
438
- margin-top: 2px;
439
- }
440
-
441
- .item-list {
442
- display: flex;
443
- flex-direction: column;
444
- gap: 8px;
445
- }
446
-
447
- .item-row {
448
- background: var(--face-surface);
449
- border: 1px solid var(--face-border);
450
- border-radius: 6px;
451
- padding: 12px;
452
- display: flex;
453
- align-items: center;
454
- justify-content: space-between;
455
- flex-wrap: wrap;
456
- gap: 10px;
457
- }
458
-
459
- .item-main {
460
- display: flex;
461
- flex-direction: column;
462
- gap: 3px;
463
- }
464
-
465
- .item-title {
466
- font-size: 14px;
467
- font-weight: 600;
468
- color: var(--text-primary, var(--face-text-default));
469
- display: flex;
470
- align-items: center;
471
- gap: 8px;
472
- }
473
-
474
- .item-meta {
475
- font-family: var(--face-font-mono);
476
- font-size: 12px;
477
- color: var(--face-muted);
478
- }
479
-
480
- .action-btn {
481
- min-height: 44px;
482
- padding: 8px 14px;
483
- border-radius: 6px;
484
- font-family: inherit;
485
- font-size: 13px;
486
- font-weight: 600;
487
- cursor: pointer;
488
- display: inline-flex;
489
- align-items: center;
490
- justify-content: center;
491
- gap: 6px;
492
- border: 1px solid transparent;
493
- }
494
-
495
- .action-btn.primary {
496
- background: var(--face-primary);
497
- color: var(--face-primary-text);
498
- }
499
-
500
- .action-btn.primary:hover {
501
- background: var(--face-accent);
502
- }
503
-
504
- .action-btn.secondary {
505
- background: var(--face-surface-subtle);
506
- border-color: var(--face-border);
507
- color: var(--text-primary, var(--face-text-default));
508
- }
509
-
510
- .action-btn.secondary:hover {
511
- background: var(--face-border-active);
512
- }
513
-
514
- .action-btn.danger {
515
- background: var(--face-danger-bg);
516
- border-color: rgba(220, 38, 38, 0.4);
517
- color: var(--face-danger);
518
- }
519
-
520
- .action-btn.danger:hover {
521
- background: rgba(220, 38, 38, 0.25);
522
- }
523
-
524
- .empty-state {
525
- text-align: center;
526
- padding: 32px 16px;
527
- border: 1px dashed var(--face-border);
528
- border-radius: 6px;
529
- color: var(--face-muted);
530
- }
531
-
532
- .empty-title {
533
- font-size: 14px;
534
- font-weight: 600;
535
- color: var(--text-primary, var(--face-text-default));
536
- margin-bottom: 6px;
537
- }
538
-
539
- .empty-text {
540
- font-size: 13px;
541
- margin-bottom: 14px;
542
- max-width: 440px;
543
- margin-left: auto;
544
- margin-right: auto;
545
- }
546
-
547
- .table-responsive {
548
- width: 100%;
549
- overflow-x: auto;
550
- border: 1px solid var(--face-border);
551
- border-radius: 6px;
552
- }
553
-
554
- table {
555
- width: 100%;
556
- border-collapse: collapse;
557
- font-size: 13px;
558
- text-align: left;
559
- }
560
-
561
- th {
562
- background: var(--face-surface);
563
- color: var(--face-muted);
564
- font-weight: 600;
565
- padding: 10px 12px;
566
- border-bottom: 1px solid var(--face-border);
567
- text-transform: uppercase;
568
- font-size: 11px;
569
- letter-spacing: 0.05em;
570
- }
571
-
572
- td {
573
- padding: 10px 12px;
574
- border-bottom: 1px solid var(--face-border);
575
- color: var(--text-primary, var(--face-text-default));
576
- }
577
-
578
- tr:last-child td {
579
- border-bottom: none;
580
- }
581
-
582
- .code-cell {
583
- font-family: var(--face-font-mono);
584
- font-size: 12px;
585
- }
586
-
587
- .status-pill {
588
- display: inline-flex;
589
- align-items: center;
590
- gap: 6px;
591
- padding: 2px 8px;
592
- border-radius: 4px;
593
- font-size: 11px;
594
- font-weight: 600;
595
- font-family: var(--face-font-mono);
596
- }
597
-
598
- .status-pill.ok {
599
- background: var(--face-ok-bg);
600
- color: var(--face-accent);
601
- }
602
-
603
- .status-pill.warn {
604
- background: var(--face-warn-bg);
605
- color: var(--face-warn);
606
- }
607
-
608
- .status-pill.danger {
609
- background: var(--face-danger-bg);
610
- color: var(--face-danger);
611
- }
612
-
613
- .status-pill.muted {
614
- background: var(--face-surface-subtle);
615
- color: var(--face-muted);
616
- }
617
-
618
- .filter-strip {
619
- display: flex;
620
- align-items: center;
621
- gap: 8px;
622
- margin-bottom: 12px;
623
- flex-wrap: wrap;
624
- }
625
-
626
- .filter-btn {
627
- min-height: 32px;
628
- padding: 4px 10px;
629
- border-radius: 4px;
630
- border: 1px solid var(--face-border);
631
- background: var(--face-surface);
632
- color: var(--face-muted);
633
- font-size: 12px;
634
- font-weight: 500;
635
- cursor: pointer;
636
- }
637
-
638
- .filter-btn.active {
639
- background: var(--face-primary-bg);
640
- color: var(--face-accent);
641
- border-color: rgba(52, 211, 153, 0.4);
642
- }
643
-
644
- .confirmation-box {
645
- background: var(--face-danger-bg);
646
- border: 1px solid var(--face-danger);
647
- border-radius: 6px;
648
- padding: 14px;
649
- margin-bottom: 16px;
650
- display: flex;
651
- align-items: center;
652
- justify-content: space-between;
653
- flex-wrap: wrap;
654
- gap: 12px;
655
- }
656
-
657
- .footer-note {
658
- margin-top: 16px;
659
- padding-top: 12px;
660
- border-top: 1px solid var(--face-border);
661
- display: flex;
662
- align-items: center;
663
- justify-content: space-between;
664
- flex-wrap: wrap;
665
- gap: 8px;
666
- font-size: 12px;
667
- color: var(--face-muted);
668
- }
669
- </style>
670
-
671
- <div class="header">
672
- <div class="brand-group">
673
- <div class="wordmark">AUTH & SECRETS</div>
674
- </div>
675
- <div id="verdict" class="verdict-line" data-tone="muted">
676
- <div class="verdict-dot"></div>
677
- <span id="verdict-label">Checking...</span>
678
- </div>
679
- </div>
680
-
681
- <div class="tabs-nav">
682
- <button class="tab-btn" data-screen="secrets">Secrets</button>
683
- <button class="tab-btn" data-screen="passkeys">Passkeys</button>
684
- <button class="tab-btn" data-screen="google">Google OAuth</button>
685
- <button class="tab-btn" data-screen="audit">Audit & Sessions</button>
686
- <button class="refresh-btn" id="refresh-action">Refresh</button>
687
- </div>
688
-
689
- <div id="confirmation-zone"></div>
690
- <div id="screen-zone" class="screen-container"></div>
691
-
692
- <div class="footer-note">
693
- <span id="last-attempt-note">Attempted: ${DASH}</span>
694
- <span>Isolated Auth Secrets Store Follows TR_SECRETS_BRAIN</span>
695
- </div>
696
- `;
697
-
698
- this.bindEvents();
699
- this.paint();
700
- }
701
-
702
- bindEvents() {
703
- const root = this.shadowRoot;
704
- if (!root) return;
705
-
706
- root.querySelectorAll('.tab-btn').forEach((btn) => {
707
- btn.addEventListener('click', (e) => {
708
- const target = e.currentTarget;
709
- const targetScreen = target?.getAttribute('data-screen');
710
- if (targetScreen) {
711
- this.screen = targetScreen;
712
- root.querySelectorAll('.tab-btn').forEach((b) => b.classList.remove('active'));
713
- target.classList.add('active');
714
- this.paint();
715
- }
716
- });
717
- });
718
-
719
- const refreshBtn = root.getElementById('refresh-action');
720
- if (refreshBtn) {
721
- refreshBtn.addEventListener('click', () => this.readAll());
722
- }
723
- }
724
-
725
- paint() {
726
- const root = this.shadowRoot;
727
- if (!root) return;
728
-
729
- // Update active tab
730
- root.querySelectorAll('.tab-btn').forEach((btn) => {
731
- btn.classList.toggle('active', btn.getAttribute('data-screen') === this.screen);
732
- });
733
-
734
- // Update verdict
735
- const verdict = this.computeVerdict();
736
- const verdictEl = root.getElementById('verdict');
737
- const verdictLabel = root.getElementById('verdict-label');
738
- if (verdictEl && verdictLabel) {
739
- verdictEl.setAttribute('data-tone', verdict.tone);
740
- verdictLabel.textContent = `${verdict.label} — ${verdict.detail}`;
741
- }
742
-
743
- // Update last attempt
744
- const attemptEl = root.getElementById('last-attempt-note');
745
- if (attemptEl) {
746
- attemptEl.textContent = this.lastAttempt
747
- ? `Last checked: ${new Date(this.lastAttempt).toLocaleTimeString()}`
748
- : `Attempted: ${DASH}`;
749
- }
750
-
751
- // Confirmation zone
752
- const confirmZone = root.getElementById('confirmation-zone');
753
- if (confirmZone) {
754
- if (this.confirmAction) {
755
- confirmZone.innerHTML = `
756
- <div class="confirmation-box">
757
- <div>
758
- <strong>Confirm Revocation:</strong> Are you sure you want to revoke passkey <code>${escapeHtml(
759
- this.confirmAction.name || this.confirmAction.id
760
- )}</code>? This hardware authenticator will no longer grant access.
761
- </div>
762
- <div style="display: flex; gap: 8px;">
763
- <button class="action-btn danger" id="btn-confirm-delete">Revoke Passkey</button>
764
- <button class="action-btn secondary" id="btn-cancel-delete">Cancel</button>
765
- </div>
766
- </div>
767
- `;
768
- confirmZone.querySelector('#btn-confirm-delete')?.addEventListener('click', () => {
769
- this.revokePasskey(this.confirmAction.id);
770
- });
771
- confirmZone.querySelector('#btn-cancel-delete')?.addEventListener('click', () => {
772
- this.confirmAction = null;
773
- this.paint();
774
- });
775
- } else {
776
- confirmZone.innerHTML = '';
777
- }
778
- }
779
-
780
- // Render active screen
781
- const screenZone = root.getElementById('screen-zone');
782
- if (!screenZone) return;
783
-
784
- switch (this.screen) {
785
- case 'passkeys':
786
- this.paintPasskeys(screenZone);
787
- break;
788
- case 'google':
789
- this.paintGoogle(screenZone);
790
- break;
791
- case 'secrets':
792
- this.paintSecrets(screenZone);
793
- break;
794
- case 'audit':
795
- this.paintAudit(screenZone);
796
- break;
797
- default:
798
- this.paintPasskeys(screenZone);
799
- }
800
- }
801
-
802
- paintPasskeys(container) {
803
- const passkeys = this.passkeysData?.passkeys || [];
804
- const count = this.passkeysData?.count ?? passkeys.length;
805
- const isEnabled = this.statusData?.passkey?.enabled ?? true;
806
-
807
- container.innerHTML = `
808
- <div class="metrics-strip">
809
- <div class="metric-card">
810
- <div class="metric-label">Registered Passkeys</div>
811
- <div class="metric-value">${count}</div>
812
- <div class="metric-sub">${count === 1 ? '1 hardware key' : `${count} keys active`}</div>
813
- </div>
814
- <div class="metric-card">
815
- <div class="metric-label">Biometric FIDO2</div>
816
- <div class="metric-value" style="color: ${isEnabled ? 'var(--face-accent)' : 'var(--face-muted)'};">
817
- ${isEnabled ? 'Active' : 'Disabled'}
818
- </div>
819
- <div class="metric-sub">WebAuthn Relying Party</div>
820
- </div>
821
- <div class="metric-card">
822
- <div class="metric-label">Local Authenticator</div>
823
- <div class="metric-value">Platform</div>
824
- <div class="metric-sub">Touch ID / Platform Key</div>
825
- </div>
826
- </div>
827
-
828
- <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
829
- <h4 style="margin: 0; font-size: 14px;">Registered Hardware Authenticators</h4>
830
- <div style="font-size: 12px; color: var(--face-muted);">
831
- Protected by Biometric Security Policy
832
- </div>
833
- </div>
834
-
835
- ${
836
- passkeys.length === 0
837
- ? `
838
- <div class="empty-state">
839
- <div class="empty-title">Zero Passkeys Registered</div>
840
- <div class="empty-text">
841
- No hardware biometric passkeys are registered yet. Register your device Touch ID, Face ID, or YubiKey hardware key for cryptographic sign-in.
842
- </div>
843
- <div style="font-size: 12px; font-family: var(--face-font-mono); color: var(--face-muted); background: var(--face-surface); padding: 8px 12px; border-radius: 4px; display: inline-block;">
844
- total-recall auth passkey register
845
- </div>
846
- </div>
847
- `
848
- : `
849
- <div class="item-list">
850
- ${passkeys
851
- .map(
852
- (pk) => `
853
- <div class="item-row">
854
- <div class="item-main">
855
- <div class="item-title">
856
- <span>${escapeHtml(pk.name || 'Hardware Authenticator')}</span>
857
- <span class="status-pill ok">Active</span>
858
- </div>
859
- <div class="item-meta">
860
- ID: ${escapeHtml(pk.id || DASH)} · Added: ${
861
- pk.created_at ? new Date(pk.created_at).toLocaleDateString() : DASH
862
- } · Last Used: ${pk.last_used_at ? new Date(pk.last_used_at).toLocaleDateString() : 'Never'}
863
- </div>
864
- </div>
865
- <div>
866
- <button class="action-btn danger btn-revoke-passkey" data-id="${escapeHtml(
867
- pk.id
868
- )}" data-name="${escapeHtml(pk.name || pk.id)}">
869
- Revoke
870
- </button>
871
- </div>
872
- </div>
873
- `
874
- )
875
- .join('')}
876
- </div>
877
- `
878
- }
879
- `;
880
-
881
- container.querySelectorAll('.btn-revoke-passkey').forEach((btn) => {
882
- btn.addEventListener('click', (e) => {
883
- const id = e.currentTarget?.getAttribute('data-id');
884
- const name = e.currentTarget?.getAttribute('data-name');
885
- if (id) {
886
- this.confirmAction = { type: 'passkey', id, name };
887
- this.paint();
888
- }
889
- });
890
- });
891
- }
892
-
893
- paintGoogle(container) {
894
- const accounts = this.googleData?.accounts || [];
895
- const isConfigured = this.statusData?.google_oauth2?.configured ?? (accounts.length > 0);
896
- const clientId = this.statusData?.google_oauth2?.client_id || DASH;
897
-
898
- container.innerHTML = `
899
- <div class="metrics-strip">
900
- <div class="metric-card">
901
- <div class="metric-label">Google Accounts</div>
902
- <div class="metric-value">${accounts.length}</div>
903
- <div class="metric-sub">${accounts.length === 1 ? '1 active connection' : `${accounts.length} connections`}</div>
904
- </div>
905
- <div class="metric-card">
906
- <div class="metric-label">OAuth2 Service</div>
907
- <div class="metric-value" style="color: ${isConfigured ? 'var(--face-accent)' : 'var(--face-warn)'};">
908
- ${isConfigured ? 'Configured' : 'Missing Credentials'}
909
- </div>
910
- <div class="metric-sub">Client ID: ${escapeHtml(clientId.slice(0, 16))}…</div>
911
- </div>
912
- <div class="metric-card">
913
- <div class="metric-label">Session Scopes</div>
914
- <div class="metric-value">OpenID + API</div>
915
- <div class="metric-sub">Verified OAuth Callback</div>
916
- </div>
917
- </div>
918
-
919
- <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
920
- <h4 style="margin: 0; font-size: 14px;">Connected Google Cloud Accounts</h4>
921
- <div style="font-size: 12px; color: var(--face-muted);">
922
- Encrypted Token Rotation
923
- </div>
924
- </div>
925
-
926
- ${
927
- accounts.length === 0
928
- ? `
929
- <div class="empty-state">
930
- <div class="empty-title">Zero Google Accounts Connected</div>
931
- <div class="empty-text">
932
- No Google OAuth accounts are connected. Connect your Google account to grant API access and authenticate sessions.
933
- </div>
934
- <div style="font-size: 12px; font-family: var(--face-font-mono); color: var(--face-muted); background: var(--face-surface); padding: 8px 12px; border-radius: 4px; display: inline-block;">
935
- total-recall auth google connect
936
- </div>
937
- </div>
938
- `
939
- : `
940
- <div class="item-list">
941
- ${accounts
942
- .map((acc) => {
943
- const isExpired = acc.expiry ? new Date(acc.expiry).getTime() < Date.now() : false;
944
- const scopesCount = Array.isArray(acc.scopes) ? acc.scopes.length : 0;
945
- return `
946
- <div class="item-row">
947
- <div class="item-main">
948
- <div class="item-title">
949
- <span>${escapeHtml(acc.email || acc.account_id)}</span>
950
- <span class="status-pill ${isExpired ? 'warn' : 'ok'}">
951
- ${isExpired ? 'Token Expired' : 'Connected'}
952
- </span>
953
- </div>
954
- <div class="item-meta">
955
- Scopes: ${scopesCount} granted · Expiry: ${
956
- acc.expiry ? new Date(acc.expiry).toLocaleString() : DASH
957
- } · Last Refresh: ${acc.updated_at ? new Date(acc.updated_at).toLocaleString() : DASH}
958
- </div>
959
- </div>
960
- <div style="display: flex; gap: 8px;">
961
- <button class="action-btn secondary btn-refresh-google" data-id="${escapeHtml(acc.account_id)}">
962
- Refresh Token
963
- </button>
964
- </div>
965
- </div>
966
- `;
967
- })
968
- .join('')}
969
- </div>
970
- `
971
- }
972
- `;
973
-
974
- container.querySelectorAll('.btn-refresh-google').forEach((btn) => {
975
- btn.addEventListener('click', (e) => {
976
- const id = e.currentTarget?.getAttribute('data-id');
977
- if (id) this.refreshGoogleAccount(id);
978
- });
979
- });
980
- }
981
-
982
- paintSecrets(container) {
983
- const keys = this.secretsData?.keys || [];
984
- const storePath = this.secretsData?.store || DASH;
985
- const overdueCount = keys.filter((k) => k.rotation_overdue).length;
986
- const sharedCount = keys.filter((k) => k.shared_value).length;
987
-
988
- let filteredKeys = keys;
989
- if (this.activeFilter === 'overdue') {
990
- filteredKeys = keys.filter((k) => k.rotation_overdue);
991
- } else if (this.activeFilter === 'ai') {
992
- filteredKeys = keys.filter((k) =>
993
- ['google', 'openai', 'anthropic', 'deepseek', 'openrouter'].includes(k.provider)
994
- );
995
- } else if (this.activeFilter === 'infra') {
996
- filteredKeys = keys.filter((k) =>
997
- ['vercel', 'digitalocean', 'stripe', 'mailcow', 'smtp2go', 'telnyx'].includes(k.provider)
998
- );
999
- }
1000
-
1001
- container.innerHTML = `
1002
- <div class="metrics-strip">
1003
- <div class="metric-card">
1004
- <div class="metric-label">Active Secrets</div>
1005
- <div class="metric-value">${keys.length}</div>
1006
- <div class="metric-sub">Single Secrets Store</div>
1007
- </div>
1008
- <div class="metric-card">
1009
- <div class="metric-label">Overdue Rotations</div>
1010
- <div class="metric-value" style="color: ${overdueCount > 0 ? 'var(--face-warn)' : 'var(--face-accent)'};">
1011
- ${overdueCount}
1012
- </div>
1013
- <div class="metric-sub">${overdueCount === 0 ? 'All keys fresh' : 'Exceeds 90-day cycle'}</div>
1014
- </div>
1015
- <div class="metric-card">
1016
- <div class="metric-label">Shared Bindings</div>
1017
- <div class="metric-value">${sharedCount}</div>
1018
- <div class="metric-sub">Multi-repo consumers</div>
1019
- </div>
1020
- </div>
1021
-
1022
- <div class="filter-strip">
1023
- <button class="filter-btn ${this.activeFilter === 'all' ? 'active' : ''}" data-filter="all">
1024
- All Keys (${keys.length})
1025
- </button>
1026
- <button class="filter-btn ${this.activeFilter === 'overdue' ? 'active' : ''}" data-filter="overdue">
1027
- Overdue (${overdueCount})
1028
- </button>
1029
- <button class="filter-btn ${this.activeFilter === 'ai' ? 'active' : ''}" data-filter="ai">
1030
- AI & LLM
1031
- </button>
1032
- <button class="filter-btn ${this.activeFilter === 'infra' ? 'active' : ''}" data-filter="infra">
1033
- Infrastructure
1034
- </button>
1035
- </div>
1036
-
1037
- <div class="table-responsive">
1038
- <table>
1039
- <thead>
1040
- <tr>
1041
- <th>Key Identifier</th>
1042
- <th>Provider</th>
1043
- <th>Bound Repositories</th>
1044
- <th>Fingerprint</th>
1045
- <th>Rotation Status</th>
1046
- </tr>
1047
- </thead>
1048
- <tbody>
1049
- ${
1050
- filteredKeys.length === 0
1051
- ? `
1052
- <tr>
1053
- <td colspan="5" style="text-align: center; color: var(--face-muted); padding: 24px;">
1054
- No secret keys match the active filter.
1055
- </td>
1056
- </tr>
1057
- `
1058
- : filteredKeys
1059
- .slice(0, 50)
1060
- .map(
1061
- (k) => `
1062
- <tr>
1063
- <td class="code-cell">
1064
- <strong>${escapeHtml(k.key)}</strong>
1065
- </td>
1066
- <td>${escapeHtml(k.provider_name || k.provider || DASH)}</td>
1067
- <td class="code-cell" style="font-size: 11px;">
1068
- ${escapeHtml(Array.isArray(k.repos) ? k.repos.join(', ') : k.repo || 'global')}
1069
- </td>
1070
- <td class="code-cell">${escapeHtml(k.fingerprint || DASH)}</td>
1071
- <td>
1072
- <span class="status-pill ${k.rotation_overdue ? 'warn' : 'ok'}">
1073
- ${k.rotation_overdue ? 'Overdue' : 'Fresh'}
1074
- </span>
1075
- </td>
1076
- </tr>
1077
- `
1078
- )
1079
- .join('')
1080
- }
1081
- </tbody>
1082
- </table>
1083
- </div>
1084
-
1085
- <div style="font-size: 11px; font-family: var(--face-font-mono); color: var(--face-muted); margin-top: 10px;">
1086
- Store: ${escapeHtml(storePath)}
1087
- </div>
1088
- `;
1089
-
1090
- container.querySelectorAll('.filter-btn').forEach((btn) => {
1091
- btn.addEventListener('click', (e) => {
1092
- const filter = e.currentTarget?.getAttribute('data-filter');
1093
- if (filter) {
1094
- this.activeFilter = filter;
1095
- this.paintSecrets(container);
1096
- }
1097
- });
1098
- });
1099
- }
1100
-
1101
- paintAudit(container) {
1102
- const findings = this.auditData?.findings || [];
1103
- const passed = this.auditData?.passed ?? true;
1104
- const findingsCount = this.auditData?.findings_count ?? findings.length;
1105
- const auditTitle = this.auditData?.audit || 'Total Recall Auth Security Baseline';
1106
-
1107
- container.innerHTML = `
1108
- <div class="metrics-strip">
1109
- <div class="metric-card">
1110
- <div class="metric-label">Security Baseline</div>
1111
- <div class="metric-value" style="color: ${passed ? 'var(--face-accent)' : 'var(--face-danger)'};">
1112
- ${passed ? 'PASS' : 'FAIL'}
1113
- </div>
1114
- <div class="metric-sub">Deterministic Audit</div>
1115
- </div>
1116
- <div class="metric-card">
1117
- <div class="metric-label">Findings Count</div>
1118
- <div class="metric-value" style="color: ${findingsCount > 0 ? 'var(--face-danger)' : 'var(--face-accent)'};">
1119
- ${findingsCount}
1120
- </div>
1121
- <div class="metric-sub">${findingsCount === 0 ? 'Zero vulnerabilities' : 'Issues detected'}</div>
1122
- </div>
1123
- <div class="metric-card">
1124
- <div class="metric-label">Audit Engine</div>
1125
- <div class="metric-value">Active</div>
1126
- <div class="metric-sub">Hardware Token Verification</div>
1127
- </div>
1128
- </div>
1129
-
1130
- <div style="margin-bottom: 12px;">
1131
- <h4 style="margin: 0 0 4px 0; font-size: 14px;">${escapeHtml(auditTitle)}</h4>
1132
- <div style="font-size: 12px; color: var(--face-muted);">
1133
- Deterministic security posture verification across credentials, session tokens, and permissions.
1134
- </div>
1135
- </div>
1136
-
1137
- ${
1138
- findings.length === 0
1139
- ? `
1140
- <div class="empty-state">
1141
- <div class="empty-title" style="color: var(--face-accent);">Zero Findings Detected</div>
1142
- <div class="empty-text">
1143
- All security baselines satisfied. Permissions, session signing keys, and credential stores are compliant with Total Recall security policies.
1144
- </div>
1145
- </div>
1146
- `
1147
- : `
1148
- <div class="item-list">
1149
- ${findings
1150
- .map(
1151
- (f) => `
1152
- <div class="item-row">
1153
- <div class="item-main">
1154
- <div class="item-title">
1155
- <span class="status-pill ${f.severity === 'critical' ? 'danger' : 'warn'}">
1156
- ${escapeHtml(f.severity || 'Warning')}
1157
- </span>
1158
- <span>${escapeHtml(f.title || f.check || 'Policy Violation')}</span>
1159
- </div>
1160
- <div class="item-meta">
1161
- ${escapeHtml(f.detail || f.message || DASH)}
1162
- </div>
1163
- </div>
1164
- </div>
1165
- `
1166
- )
1167
- .join('')}
1168
- </div>
1169
- `
1170
- }
1171
- `;
1172
- }
1173
- }
1174
-
1175
- if (!customElements.get('tr-auth-card')) {
1176
- customElements.define('tr-auth-card', AuthCard);
1177
- }
1178
-
1179
- export { asObject, escapeHtml };