total-recall-brain 3.41.2 → 3.41.4

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 (128) hide show
  1. package/bin/total-recall.mjs +19 -4
  2. package/frontend/dist/assets/{index-BG9NkVUy.css → index-BIQmqDKP.css} +1 -1
  3. package/frontend/dist/assets/{index-BtuiZqwP.js → index-CRzjQLu7.js} +7 -7
  4. package/frontend/dist/index.html +2 -2
  5. package/frontend/dist/sw.js +8 -5
  6. package/frontend/src/api/auth.ts +0 -3
  7. package/frontend/src/components/plugins/PluginPanel.tsx +7 -3
  8. package/frontend/src/components/plugins/card/CardEngine.tsx +1 -1
  9. package/frontend/src/pages/LoginPage.tsx +1 -41
  10. package/frontend/src/pages/PluginsPage.tsx +14 -7
  11. package/package.json +7 -5
  12. package/scaffold/.agent/skills/plugin/scripts/record.mjs +6 -3
  13. package/scaffold/.agent/skills/total-recall/plugins/auth/cli.mjs +197 -31
  14. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +6 -6
  15. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +1 -1
  16. package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +8 -1
  17. package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +48 -0
  18. package/scaffold/.agent/skills/total-recall/plugins/auth/src/login-projections.mjs +42 -0
  19. package/scaffold/.agent/skills/total-recall/plugins/auth/src/mesh-secrets.mjs +18 -0
  20. package/scaffold/.agent/skills/total-recall/plugins/auth/src/routes/secrets.mjs +5 -2
  21. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-carriers.mjs +76 -0
  22. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-prune.mjs +37 -0
  23. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-sync.mjs +53 -17
  24. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/DESIGN.md +56 -8
  25. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/card.js +1068 -204
  26. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/panel.js +4 -2
  27. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/DESIGN.md +32 -0
  28. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +436 -274
  29. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +12 -12
  30. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +1 -1
  31. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/DESIGN.md +16 -2
  32. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +461 -242
  33. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +12 -12
  34. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +1 -1
  35. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +1 -7
  36. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/DESIGN.md +17 -2
  37. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +426 -300
  38. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +23 -8
  39. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +6 -2
  40. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/DESIGN.md +32 -0
  41. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +350 -283
  42. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +23 -8
  43. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +5 -1
  44. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/card.js +31 -19
  45. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +23 -10
  46. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +5 -3
  47. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +1 -1
  48. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/grants.mjs +7 -3
  49. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +61 -38
  50. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/leader-election.mjs +57 -2
  51. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +220 -36
  52. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/server/routes/mesh.mjs +7 -2
  53. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +65 -0
  54. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/BRICK.md +59 -0
  55. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +534 -0
  56. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +139 -0
  57. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +2849 -0
  58. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +26 -0
  59. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +376 -0
  60. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +37 -0
  61. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/adapters/dsh.mjs +446 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +23 -0
  63. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +398 -0
  64. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +152 -0
  65. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +82 -0
  66. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +90 -0
  67. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +415 -0
  68. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +36 -0
  69. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/setup.mjs +35 -0
  70. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/tracker.mjs +133 -0
  71. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +233 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +32 -0
  73. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +845 -0
  74. package/scaffold/.agent/skills/total-recall/plugins/openwiki/capability/BRICK.md +64 -0
  75. package/scaffold/.agent/skills/total-recall/plugins/openwiki/capability/index.mjs +250 -0
  76. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +344 -14
  77. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +2917 -140
  78. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +9 -3
  79. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +223 -5
  80. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +129 -0
  81. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +355 -0
  82. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +375 -0
  83. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +37 -10
  84. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +986 -280
  85. package/scaffold/.agent/skills/total-recall/plugins/security/cli.mjs +7 -1
  86. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +25 -10
  87. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +6 -2
  88. package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +1 -1
  89. package/scaffold/.agent/skills/total-recall/plugins/security/src/scanner.mjs +17 -3
  90. package/scaffold/.agent/skills/total-recall/plugins/security/ui/DESIGN.md +38 -15
  91. package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +60 -34
  92. package/src/cli/command.mjs +23 -18
  93. package/src/cli/config.mjs +3 -0
  94. package/src/cli/connect.mjs +12 -116
  95. package/src/cli/daemon.mjs +23 -1
  96. package/src/cli/harness.mjs +0 -1
  97. package/src/cli/plugin/copies.mjs +8 -5
  98. package/src/cli/plugin/create.mjs +56 -3
  99. package/src/cli/plugin/index.mjs +40 -5
  100. package/src/cli/plugin/monetization.mjs +232 -12
  101. package/src/cli/preflight.mjs +161 -0
  102. package/src/cli/rebuild.mjs +22 -0
  103. package/src/cli/reset-password.mjs +3 -2
  104. package/src/cli/skill.mjs +8 -2
  105. package/src/cli/status.mjs +25 -7
  106. package/src/core/automatic-brain-updates.mjs +9 -3
  107. package/src/core/brain-updates.mjs +63 -5
  108. package/src/core/cli-commands.mjs +2 -0
  109. package/src/core/context-compiler.mjs +8 -1
  110. package/src/core/default-plugins.mjs +1 -1
  111. package/src/core/global-brain-updates.mjs +21 -1
  112. package/src/core/mesh-brain-updates.mjs +5 -2
  113. package/src/core/meta-harness.mjs +32 -79
  114. package/src/core/plugin-dependencies.mjs +6 -1
  115. package/src/core/plugin-runner.mjs +6 -1
  116. package/src/core/plugin-store.mjs +67 -1
  117. package/src/core/plugin-updates.mjs +1 -1
  118. package/src/core/portable-skills-maintenance.mjs +19 -0
  119. package/src/core/preflight-gate.mjs +77 -0
  120. package/src/core/preflight-receipt.mjs +123 -0
  121. package/src/core/required-plugins.mjs +7 -0
  122. package/src/core/runtime.mjs +0 -3
  123. package/src/core/skills-registry.mjs +33 -3
  124. package/src/core/surface.mjs +38 -1
  125. package/src/server/auth.mjs +41 -1
  126. package/src/server/memory-app.mjs +2 -1
  127. package/src/server/routes/auth.mjs +25 -1
  128. package/src/server/routes/plugins.mjs +17 -4
@@ -17,8 +17,8 @@
17
17
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
18
18
  <link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,600;12..96,800&family=Cabinet+Grotesk:wght@700;800&family=Chivo+Mono:wght@500;700&family=Cinzel:wght@600;700;900&family=Cormorant+Garamond:ital,wght@0,600;0,700;1,600;1,700&family=DM+Mono:wght@500&family=DM+Sans:wght@500;700&family=Fraunces:opsz,wght@9..144,600;9..144,800&family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;700&family=Lexend:wght@600;800&family=Newsreader:ital,opsz,wght@0,6..72,600;1,6..72,600&family=Orbitron:wght@700;900&family=Outfit:wght@500;700;800&family=Plus+Jakarta+Sans:wght@600;700;800&family=Space+Grotesk:wght@600;700&family=Syne:wght@700;800&display=swap" rel="stylesheet" />
19
19
  <title>Total Recall — Portable Memory</title>
20
- <script type="module" crossorigin src="/assets/index-BtuiZqwP.js"></script>
21
- <link rel="stylesheet" crossorigin href="/assets/index-BG9NkVUy.css">
20
+ <script type="module" crossorigin src="/assets/index-CRzjQLu7.js"></script>
21
+ <link rel="stylesheet" crossorigin href="/assets/index-BIQmqDKP.css">
22
22
  </head>
23
23
  <body>
24
24
  <div id="root"></div>
@@ -124,12 +124,15 @@ async function staleWhileRevalidate(request) {
124
124
  // ─── Cache-First ──────────────────────────────────────────────────────────────
125
125
 
126
126
  async function cacheFirst(request) {
127
- const cached = await caches.match(request);
128
- if (cached) return cached;
127
+ try {
128
+ const cached = await caches.match(request);
129
+ if (cached) return cached;
130
+ } catch {
131
+ // unreadable cache entry: fall through to the network
132
+ }
129
133
  const response = await fetch(request);
130
- if (response && response.ok && response.status === 200) {
131
- const cache = await caches.open(CACHE_NAME);
132
- cache.put(request, response.clone()).catch(() => {});
134
+ if (response && response.ok && response.status === 200 && response.type === 'basic') {
135
+ caches.open(CACHE_NAME).then((cache) => cache.put(request, response.clone())).catch(() => {});
133
136
  }
134
137
  return response;
135
138
  }
@@ -75,7 +75,6 @@ export async function logout(): Promise<void> {
75
75
  export interface AuthProvidersResponse {
76
76
  password: { configured: boolean }
77
77
  passkey: { enabled: boolean; has_passkeys: boolean; count: number }
78
- google: { configured: boolean; client_id: string | null }
79
78
  }
80
79
 
81
80
  export async function getAuthProviders(): Promise<AuthProvidersResponse> {
@@ -85,13 +84,11 @@ export async function getAuthProviders(): Promise<AuthProvidersResponse> {
85
84
  return {
86
85
  password: { configured: true },
87
86
  passkey: { enabled: false, has_passkeys: false, count: 0 },
88
- google: { configured: false, client_id: null },
89
87
  }
90
88
  } catch {
91
89
  return {
92
90
  password: { configured: true },
93
91
  passkey: { enabled: false, has_passkeys: false, count: 0 },
94
- google: { configured: false, client_id: null },
95
92
  }
96
93
  }
97
94
  }
@@ -20,7 +20,8 @@ export function pluginElements(plugin: PluginInfo): PluginElement[] {
20
20
  /** Loads owner code; no plugin identities or provider behavior belong here. */
21
21
  export function PluginPanel({ plugin, elementId, readOnly = false }: { plugin: PluginInfo; elementId?: string; readOnly?: boolean }) {
22
22
  const elements = pluginElements(plugin).filter(element => element.kind !== 'settings' && (!elementId || element.id === elementId))
23
- const [selected, setSelected] = useState(elements[0]?.id || '')
23
+ const cardElement = elements.find(item => item.kind === 'card')
24
+ const [selected, setSelected] = useState(elementId || cardElement?.id || elements[0]?.id || '')
24
25
  const [error, setError] = useState('')
25
26
  const frame = useRef<HTMLIFrameElement>(null)
26
27
  const [document, setDocument] = useState('')
@@ -67,7 +68,7 @@ export function PluginPanel({ plugin, elementId, readOnly = false }: { plugin: P
67
68
  if (data.type !== 'run') return
68
69
  const target = event.source as Window
69
70
  const reply = (result?: unknown, error?: string) => { if (!disposed) target.postMessage({ channel, type: 'result', requestId: data.requestId, result, error }, '*') }
70
- if (!allowedFrameCommand(data, allowed, secretCommands) || active >= 4) { reply(undefined, 'Operation is not available'); return }
71
+ if (!allowedFrameCommand(data, allowed, secretCommands) || active >= 12) { reply(undefined, 'Operation is not available'); return }
71
72
  active++
72
73
  window.dispatchEvent(new CustomEvent('plugin-command-activity', { detail: { pluginId: plugin.id, requestId: data.requestId, command: data.subcommand, running: true } }))
73
74
  try {
@@ -106,8 +107,11 @@ export function PluginPanel({ plugin, elementId, readOnly = false }: { plugin: P
106
107
  return dispose
107
108
  }, [plugin.id, selected, plugin.sha256, elementId, readOnly])
108
109
 
110
+ const currentElement = elements.find(item => item.id === selected) || elements[0]
111
+ const showNav = elements.length > 1 && currentElement?.kind !== 'card'
112
+
109
113
  return <section>
110
- {elements.length > 1 && <nav style={{ display: 'flex', gap: 8 }}>
114
+ {showNav && <nav style={{ display: 'flex', gap: 8 }}>
111
115
  {elements.map(element => <button key={element.id} className="btn btn-sm" onClick={() => setSelected(element.id)} aria-pressed={selected === element.id}>{element.description || element.id}</button>)}
112
116
  </nav>}
113
117
  {error && <div role="alert" className="alert alert-error">{error}</div>}
@@ -98,7 +98,7 @@ export function CardEngine({ plugin }: { plugin: PluginInfo }) {
98
98
  {card.description && <p className="card-muted card-description">{card.description}</p>}
99
99
  <CardScenes plugin={plugin}>
100
100
  {card.face
101
- ? <PluginPanel plugin={plugin} elementId={card.face.id} readOnly />
101
+ ? <PluginPanel plugin={plugin} elementId={card.face.id} />
102
102
  : <p className="card-error" role="alert">{plugin.name} has not supplied its card face.</p>}
103
103
  </CardScenes>
104
104
  {card.branding.provider && <footer className="card-footer">{card.branding.provider.url ? <a href={card.branding.provider.url} target="_blank" rel="noreferrer noopener">{card.branding.provider.name}</a> : card.branding.provider.name} is a trademark of its owner. This plugin connects to the service with your own account.</footer>}
@@ -88,14 +88,6 @@ export default function LoginPage({ onAuthenticated }: Props) {
88
88
  }
89
89
  }
90
90
 
91
- function handleGoogleLogin() {
92
- if (providers?.google && !providers.google.configured) {
93
- setError("Google OAuth2 is not configured. Provide GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in the Auth Plugin.")
94
- return
95
- }
96
- window.location.href = "/auth/google"
97
- }
98
-
99
91
  useEffect(() => {
100
92
  inputRef.current?.focus()
101
93
  }, [needsReset, isFirstTime])
@@ -324,7 +316,7 @@ export default function LoginPage({ onAuthenticated }: Props) {
324
316
  </button>
325
317
  </form>
326
318
 
327
- {(!needsReset && !isFirstTime && (providers?.passkey?.has_passkeys || providers?.google?.configured)) && (
319
+ {(!needsReset && !isFirstTime && providers?.passkey?.has_passkeys) && (
328
320
  <div style={{ display: "flex", flexDirection: "column", gap: 10, marginTop: -4 }}>
329
321
  <div style={{ display: "flex", alignItems: "center", gap: 12, margin: "6px 0" }}>
330
322
  <div style={{ flex: 1, height: 1, background: "var(--border)" }} />
@@ -376,38 +368,6 @@ export default function LoginPage({ onAuthenticated }: Props) {
376
368
  )}
377
369
  </button>
378
370
  )}
379
-
380
- {providers?.google?.configured && (
381
- <button
382
- type="button"
383
- id="btn-google-login"
384
- onClick={handleGoogleLogin}
385
- disabled={loading || passkeyLoading}
386
- className="btn btn-secondary"
387
- style={{
388
- width: "100%",
389
- minHeight: 44,
390
- justifyContent: "center",
391
- fontSize: 13.5,
392
- borderRadius: 12,
393
- display: "flex",
394
- alignItems: "center",
395
- gap: 8,
396
- background: "rgba(255, 255, 255, 0.05)",
397
- borderColor: "rgba(255, 255, 255, 0.15)",
398
- color: "var(--text-primary)",
399
- cursor: loading || passkeyLoading ? "not-allowed" : "pointer",
400
- }}
401
- >
402
- <svg width="16" height="16" viewBox="0 0 24 24">
403
- <path fill="#4285F4" d="M23.745 12.27c0-.7-.06-1.4-.19-2.07H12v4.51h6.6c-.29 1.52-1.14 2.82-2.4 3.68v3.05h3.88c2.27-2.09 3.665-5.17 3.665-9.17z"/>
404
- <path fill="#34A853" d="M12 24c3.24 0 5.95-1.08 7.93-2.91l-3.88-3.05c-1.08.72-2.45 1.16-4.05 1.16-3.12 0-5.77-2.1-6.72-4.93H1.25v3.15C3.26 21.36 7.33 24 12 24z"/>
405
- <path fill="#FBBC05" d="M5.28 14.27c-.25-.72-.38-1.49-.38-2.27s.13-1.55.38-2.27V6.58H1.25C.45 8.18 0 9.99 0 12s.45 3.82 1.25 5.42l4.03-3.15z"/>
406
- <path fill="#EA4335" d="M12 4.75c1.77 0 3.35.61 4.6 1.8l3.42-3.42C17.95 1.19 15.24 0 12 0 7.33 0 3.26 2.64 1.25 6.58l4.03 3.15c.95-2.83 3.6-4.98 6.72-4.98z"/>
407
- </svg>
408
- Sign in with Google
409
- </button>
410
- )}
411
371
  </div>
412
372
  )}
413
373
 
@@ -22,7 +22,6 @@ import {
22
22
  import { renderMarkdown } from "../components/MarkdownUtils"
23
23
  import { PluginPanel, pluginElements } from "../components/plugins/PluginPanel"
24
24
  import { PluginSettings } from "../components/plugins/PluginSettings"
25
- import { CardEngine } from "../components/plugins/card/CardEngine"
26
25
 
27
26
  interface PluginsPageProps {
28
27
  activeBrainId?: string | null
@@ -76,8 +75,8 @@ const AGENT_RECIPE_PROMPT = `You are my coding agent. Author a bespoke Total Rec
76
75
  - Real interactive controls executing plugin subcommands via host.run(subcommand, args)
77
76
 
78
77
  4. Distribution:
79
- - Private: keep in .agent/skills/total-recall/plugins/<id>
80
- - Store: publish via total-recall deploy-store <id>`
78
+ - Private: keep in .agent/plugins/<id>
79
+ - Mesh: share peer-to-peer via total-recall plugin share <id>`
81
80
 
82
81
  function resolvePluginBranding(p: { id: string; branding?: { icon?: string | null; color?: string | null; badge?: string | null } }) {
83
82
  const custom = p.branding || {}
@@ -499,7 +498,7 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
499
498
  setWorkspaceActiveIds(next)
500
499
  try { localStorage.setItem("tr_workspace_plugins", JSON.stringify([...next])) } catch {}
501
500
  await setPluginActivation(p.id, false)
502
- setAlert({ type: "success", message: `Moved ${p.name} from workspace to Plugin Store` })
501
+ setAlert({ type: "success", message: `Deactivated card for ${p.name}` })
503
502
  await loadLocal()
504
503
  } catch (err: any) {
505
504
  setAlert({ type: "error", message: err?.message || `Could not deactivate ${p.name}` })
@@ -772,7 +771,7 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
772
771
  <div style={{ display: "flex", justifyContent: "space-between", gap: "12px", flexWrap: "wrap", marginBottom: "20px" }}>
773
772
  <div role="tablist" style={{ display: "flex", gap: "8px" }}>
774
773
  {tabButton("installed", "My Cards", myCards.length)}
775
- {tabButton("bundled", "Plugin Store (Bundled)", filteredStoreCatalog.length)}
774
+ {tabButton("bundled", "Plugin Catalog", filteredStoreCatalog.length)}
776
775
  {tabButton("mesh", "On the mesh")}
777
776
  </div>
778
777
  <div style={{ display: "flex", gap: "8px", flexWrap: "wrap" }}>
@@ -795,7 +794,7 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
795
794
  </div>
796
795
  <div style={muted}>
797
796
  {viewMode === "workspace"
798
- ? "Core runtime foundation and activated repository cards. Optional tools live in the Plugin Store."
797
+ ? "Core runtime foundation and activated repository cards. Standalone tools live in the Plugin Catalog."
799
798
  : "All plugin packages installed on this host."}
800
799
  </div>
801
800
  </div>
@@ -839,7 +838,7 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
839
838
  onTouchEnd={cancelLongPress}
840
839
  style={{ display: "flex", flexDirection: "column", gap: "8px", minWidth: 0 }}
841
840
  >
842
- <CardEngine plugin={p} />
841
+ <PluginPanel plugin={p} />
843
842
  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "0 4px", fontSize: "11px", color: "var(--text-tertiary)", flexWrap: "wrap", gap: "6px" }}>
844
843
  <div style={{ display: "flex", gap: "6px", alignItems: "center", flexWrap: "wrap" }}>
845
844
  <span className="badge">{p.scope}</span>
@@ -848,6 +847,14 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
848
847
  {!p.valid && <span className="badge badge-error">invalid manifest</span>}
849
848
  {p.modified_since_install && <span className="badge badge-warning">changed since install</span>}
850
849
  </div>
850
+ <button
851
+ type="button"
852
+ className="btn btn-ghost btn-xs"
853
+ onClick={() => openDetail(p, "details")}
854
+ style={{ fontSize: "11px", color: "var(--text-secondary)" }}
855
+ >
856
+ Settings &amp; usage
857
+ </button>
851
858
  {!DEFAULT_CORE_PLUGINS.has(p.id) && (
852
859
  <button
853
860
  type="button"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "total-recall-brain",
3
- "version": "3.41.2",
3
+ "version": "3.41.4",
4
4
  "description": "The Vibe Coding Brain & Autonomous Software Factory: memory, rules, secrets, and 33 visual plugins automatically managed across all your devices.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -56,7 +56,8 @@
56
56
  "prepublishOnly": "npm run check:package && npm run check:dist && npm run check:ssss-registry && node scripts/check-scaffold-state.mjs",
57
57
  "check:ssss-registry": "node scripts/check-ssss-registry.mjs",
58
58
  "check:package": "node scripts/check-memory-package.mjs",
59
- "start:memory": "node src/server/memory-server.mjs"
59
+ "start:memory": "node src/server/memory-server.mjs",
60
+ "ssss": "ssss"
60
61
  },
61
62
  "repository": {
62
63
  "type": "git",
@@ -76,7 +77,7 @@
76
77
  "homepage": "https://github.com/gregiteen/total-recall#readme",
77
78
  "dependencies": {
78
79
  "@simplewebauthn/server": "^13.3.2",
79
- "@ssss/cli": "npm:@gregiteen/ssss-cli@0.11.2",
80
+ "@ssss/cli": "npm:@gregiteen/ssss-cli@0.14.3",
80
81
  "bcrypt": "^6.0.0",
81
82
  "better-sqlite3": "^12.11.1",
82
83
  "cookie-parser": "^1.4.7",
@@ -88,6 +89,7 @@
88
89
  "jsonwebtoken": "^9.0.3",
89
90
  "lodash-es": "^4.18.1",
90
91
  "natural": "^8.1.1",
92
+ "openwiki": "^0.7.3",
91
93
  "preact": "^10.29.7",
92
94
  "sqlite-vss": "^0.1.2",
93
95
  "ws": "^8.18.0",
@@ -103,8 +105,8 @@
103
105
  "@vitest/coverage-v8": "^4.1.12",
104
106
  "gray-matter": "^4.0.3",
105
107
  "jsdom": "^29.1.1",
106
- "react": "^19.2.7",
107
- "react-dom": "^19.2.7",
108
+ "react": "^19.3.1",
109
+ "react-dom": "^19.3.1",
108
110
  "react-router-dom": "^7.18.1",
109
111
  "recharts": "^3.9.2",
110
112
  "skills": "^1.5.7",
@@ -47,7 +47,9 @@ function walk(dir, out = [], base = root) {
47
47
  /* ── manifest ────────────────────────────────────────────────────────────── */
48
48
 
49
49
  let manifest = null;
50
- if (want('--manifest')) {
50
+ // Every selected section depends on manifest facts. Section filtering must not
51
+ // skip prerequisite loading and then report a vacuous successful check run.
52
+ {
51
53
  const file = path.join(root, 'plugin.json');
52
54
  if (!fs.existsSync(file)) {
53
55
  record('manifest', 'FAIL', 'plugin.json exists', 'no plugin.json in ' + root);
@@ -62,7 +64,7 @@ if (want('--manifest')) {
62
64
  }
63
65
 
64
66
  // Validate with the real contract when this skill is inside a Total Recall checkout.
65
- if (manifest) {
67
+ if (manifest && want('--manifest')) {
66
68
  const loaderPath = path.resolve(import.meta.dirname, '../../../../src/core/plugin-loader.mjs');
67
69
  if (fs.existsSync(loaderPath)) {
68
70
  try {
@@ -82,7 +84,8 @@ if (manifest) {
82
84
 
83
85
  // Card declaration
84
86
  const elements = manifest.ui?.elements || [];
85
- const faces = elements.filter((e) => e && (e.kind === 'card' || e.kind === 'panel'));
87
+ // One face (kind 'card') plus any number of screens (kind 'panel'); a panel is never the face.
88
+ const faces = elements.filter((e) => e && e.kind === 'card');
86
89
  if (manifest.card_layout !== undefined) {
87
90
  record('manifest', 'FAIL', 'no template', "'card_layout' is declared; a face is bespoke owner code");
88
91
  } else {