total-recall-brain 3.40.1 → 3.40.3
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.
- package/README.md +152 -41
- package/bin/total-recall.mjs +16 -76
- package/docs/reference/cli-reference.md +10 -10
- package/extension/background.js +6 -2
- package/extension/config.js +8 -0
- package/extension/lib/brain-client.js +29 -4
- package/extension/options/options.html +1 -0
- package/extension/sidepanel/sidepanel.html +1 -0
- package/frontend/dist/assets/{index-CvQRdT2j.css → index-AGUes-VG.css} +1 -1
- package/frontend/dist/assets/index-Bt5iVPZj.js +5618 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/src/api/keys.ts +9 -2
- package/frontend/src/api/plugins.ts +4 -0
- package/frontend/src/components/plugins/card/CardEngine.tsx +2 -1
- package/frontend/src/components/plugins/card/card.css +1 -1
- package/frontend/src/pages/IntegrationsPage.tsx +315 -8
- package/frontend/src/pages/PluginsPage.tsx +532 -87
- package/package.json +6 -5
- package/scaffold/.agent/skills/meta-harness/references/optimized/original.md +1 -1
- package/scaffold/.agent/skills/meta-harness/references/optimized/section-09.md +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +10 -10
- package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +1 -6
- package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +0 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/browser-session.mjs +309 -4
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +44 -34
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/google-oauth.mjs +6 -4
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-catalog.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-rotation-recipes.mjs +118 -4
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/routes/auth.mjs +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-env-export.mjs +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-remote-deploy.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-rotate.mjs +24 -6
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/card.js +164 -123
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/README.md +65 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/cli.mjs +76 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/package.json +19 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/plugin.json +290 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/adapters/dsh.mjs +446 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/documentation.mjs +152 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/executor.mjs +71 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/runtime.mjs +36 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/setup.mjs +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/worker.mjs +175 -0
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +413 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/README.md +84 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/cli.mjs +79 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/check.mjs +6 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/report.mjs +6 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/run-core.mjs +27 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/snapshot.mjs +163 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/check.mjs +757 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/config.schema.json +86 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/detect.mjs +89 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/report-data.mjs +145 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/report.mjs +210 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/state.mjs +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +2869 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +28 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +186 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/DESIGN.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +368 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/code-quality-report.mjs +129 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/README.md +73 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/cli.mjs +375 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/examples/commands/echo-tool.mjs +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/examples/commands/group.mjs +262 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/examples/commands/project-id.mjs +74 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +2869 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +31 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +221 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/schemas/cli_command.schema.json +107 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/skills/composable-cli/SKILL.md +63 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/command.mjs +313 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/compile.mjs +19 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/compose.mjs +144 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/contract.mjs +110 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/library.mjs +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/registry.mjs +192 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/resolve.mjs +221 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/risk.mjs +126 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/ssss-documents.mjs +29 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/DESIGN.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +273 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/README.md +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/cli.mjs +310 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +2826 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +11 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +62 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +297 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/README.md +43 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/cli.mjs +258 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +4005 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/plugin.json +125 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/DESIGN.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/card.js +278 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/README.md +9 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/cli.mjs +6 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +4721 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +3 -21
- package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +14 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +10 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/headscale-client.mjs +5 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/leader-election.mjs +4 -13
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh-access-verify.mjs +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh-files.mjs +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +2 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/test-support/memory-root.mjs +14 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/README.md +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +124 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +4097 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +12 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +165 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/ingest.mjs +127 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +279 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/panel.js +539 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/README.md +67 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/cli.mjs +932 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +3256 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +297 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/scripts/build-ui.mjs +4 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/skills/security/SKILL.md +37 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/src/android.mjs +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/src/devices.mjs +94 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/src/machines.mjs +164 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/src/scanner.mjs +41 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/src/windows.mjs +42 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/DESIGN.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +95 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/panel.js +98 -0
- package/scaffold/.agent/skills/total-recall/references/auth.md +1 -1
- package/src/cli/brief.mjs +33 -9
- package/src/cli/command.mjs +2 -7
- package/src/cli/config.mjs +1 -0
- package/src/cli/connect.mjs +5 -0
- package/src/cli/context.mjs +2 -1
- package/src/cli/daemon.mjs +36 -1
- package/src/cli/doctor.mjs +6 -0
- package/src/cli/harness.mjs +3 -0
- package/src/cli/help.mjs +26 -0
- package/src/cli/init.mjs +4 -4
- package/src/cli/memory-entry.mjs +1 -0
- package/src/cli/memory-init.mjs +2 -0
- package/src/cli/plugin/index.mjs +11 -0
- package/src/cli/plugin/install.mjs +2 -1
- package/src/cli/rebuild.mjs +3 -1
- package/src/cli/startup.mjs +2 -1
- package/src/cli/update.mjs +19 -0
- package/src/core/automatic-brain-updates.mjs +67 -0
- package/src/core/brain-updates.mjs +21 -2
- package/src/core/cli-commands.mjs +71 -0
- package/src/core/cli-maintenance.mjs +45 -0
- package/src/core/cli-quick-reference.mjs +20 -0
- package/src/core/cli-semantic-index.mjs +722 -0
- package/src/core/context-compiler.mjs +27 -1
- package/src/core/crons.mjs +2 -13
- package/src/core/daemon-control.mjs +6 -4
- package/src/core/daemon-loop.mjs +12 -8
- package/src/core/default-plugins.mjs +5 -0
- package/src/core/global-brain-updates.mjs +39 -0
- package/src/core/mesh-brain-updates.mjs +30 -0
- package/src/core/meta-harness.mjs +108 -0
- package/src/core/plugin-dependencies.mjs +2 -1
- package/src/core/plugin-loader.mjs +2 -1
- package/src/core/plugin-runner.mjs +12 -4
- package/src/core/plugin-setup.mjs +20 -0
- package/src/core/plugin-store.mjs +22 -4
- package/src/core/plugin-tasks.mjs +1 -1
- package/src/core/project-brain.mjs +2 -0
- package/src/core/project-status.mjs +64 -0
- package/src/core/required-plugins.mjs +46 -0
- package/src/core/scaffold-plugins.mjs +17 -3
- package/src/core/source-brain-updates.mjs +47 -0
- package/src/core/startup-health.mjs +5 -3
- package/src/core/surface.mjs +44 -10
- package/src/server/routes/extension.mjs +53 -8
- package/templates/onboarding-interview.md +1 -1
- package/frontend/dist/assets/index-SOVUlZqm.js +0 -5596
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
deployPluginToStore,
|
|
14
14
|
runPluginCommand,
|
|
15
15
|
fetchPluginReadme,
|
|
16
|
+
setPluginActivation,
|
|
16
17
|
type PluginInfo,
|
|
17
18
|
type BundledPlugin,
|
|
18
19
|
type PeersResponse,
|
|
@@ -43,6 +44,41 @@ const PEER_STATUS_LABEL: Record<PeerNode["status"], string> = {
|
|
|
43
44
|
const mono: CSSProperties = { fontFamily: "var(--font-mono)", fontSize: "12px" }
|
|
44
45
|
const muted: CSSProperties = { color: "var(--text-secondary)", fontSize: "13px", lineHeight: 1.5 }
|
|
45
46
|
|
|
47
|
+
const DEFAULT_CORE_PLUGINS = new Set([
|
|
48
|
+
"auth",
|
|
49
|
+
"mesh",
|
|
50
|
+
"openwiki",
|
|
51
|
+
"composable-cli",
|
|
52
|
+
"cli-agents",
|
|
53
|
+
"code-quality",
|
|
54
|
+
"security",
|
|
55
|
+
"embeddings",
|
|
56
|
+
"git-sentinel"
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
const AGENT_RECIPE_PROMPT = `You are my coding agent. Author a bespoke Total Recall plugin for [DOMAIN] following the Total Recall Plugin Recipe:
|
|
60
|
+
|
|
61
|
+
1. Scaffold:
|
|
62
|
+
total-recall scaffold-plugin <id> --title "<Name>" --description "<Description>"
|
|
63
|
+
|
|
64
|
+
2. Manifest (plugin.json):
|
|
65
|
+
- id: lowercase kebab-case
|
|
66
|
+
- name: Clear Title
|
|
67
|
+
- branding: { name, color, badge }
|
|
68
|
+
- cli: command name and subcommands with effect (read/write)
|
|
69
|
+
- ui: elements declaring the Web Component tag <tr-plugin-<id>-card>
|
|
70
|
+
- secrets: declare required keys, never store plain text
|
|
71
|
+
|
|
72
|
+
3. Web Component (ui/card.js):
|
|
73
|
+
- Register <tr-plugin-<id>-card>
|
|
74
|
+
- Standardized layout with clean borders and >=44px touch targets
|
|
75
|
+
- Authentic purpose-built domain tools (NO fake audio equalizers or fake skins)
|
|
76
|
+
- Real interactive controls executing plugin subcommands via host.run(subcommand, args)
|
|
77
|
+
|
|
78
|
+
4. Distribution:
|
|
79
|
+
- Private: keep in .agent/skills/total-recall/plugins/<id>
|
|
80
|
+
- Store: publish via total-recall deploy-store <id>`
|
|
81
|
+
|
|
46
82
|
function resolvePluginBranding(p: { id: string; branding?: { icon?: string | null; color?: string | null; badge?: string | null } }) {
|
|
47
83
|
const custom = p.branding || {}
|
|
48
84
|
return {
|
|
@@ -334,6 +370,17 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
|
|
|
334
370
|
const [output, setOutput] = useState<{ text: string; ok: boolean } | null>(null)
|
|
335
371
|
const [readme, setReadme] = useState("")
|
|
336
372
|
|
|
373
|
+
// Agent Plugin Recipe & Workspace State
|
|
374
|
+
const [recipeOpen, setRecipeOpen] = useState(false)
|
|
375
|
+
const [viewMode, setViewMode] = useState<"workspace" | "all">("workspace")
|
|
376
|
+
const [workspaceActiveIds, setWorkspaceActiveIds] = useState<Set<string>>(() => {
|
|
377
|
+
try {
|
|
378
|
+
const stored = localStorage.getItem("tr_workspace_plugins")
|
|
379
|
+
if (stored) return new Set(JSON.parse(stored))
|
|
380
|
+
} catch {}
|
|
381
|
+
return new Set<string>()
|
|
382
|
+
})
|
|
383
|
+
|
|
337
384
|
// Branding Customization Modal state
|
|
338
385
|
const [brandingOpen, setBrandingOpen] = useState(false)
|
|
339
386
|
const [brandingPlugin, setBrandingPlugin] = useState<PluginInfo | null>(null)
|
|
@@ -420,6 +467,52 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
|
|
|
420
467
|
return [p.id, p.name, p.description, ...p.use_cases].some((v) => v.toLowerCase().includes(q))
|
|
421
468
|
}, [query, useCase])
|
|
422
469
|
|
|
470
|
+
const isWorkspaceCard = useCallback((p: { id: string; scope?: string }) => {
|
|
471
|
+
if (p.scope === "project") return true
|
|
472
|
+
if (DEFAULT_CORE_PLUGINS.has(p.id)) return true
|
|
473
|
+
if (workspaceActiveIds.has(p.id)) return true
|
|
474
|
+
return false
|
|
475
|
+
}, [workspaceActiveIds])
|
|
476
|
+
|
|
477
|
+
const addToWorkspace = async (p: { id: string; name: string }) => {
|
|
478
|
+
setBusy(p.id)
|
|
479
|
+
try {
|
|
480
|
+
const next = new Set(workspaceActiveIds)
|
|
481
|
+
next.add(p.id)
|
|
482
|
+
setWorkspaceActiveIds(next)
|
|
483
|
+
try { localStorage.setItem("tr_workspace_plugins", JSON.stringify([...next])) } catch {}
|
|
484
|
+
await setPluginActivation(p.id, true)
|
|
485
|
+
setAlert({ type: "success", message: `Added ${p.name} to workspace dashboard` })
|
|
486
|
+
await loadLocal()
|
|
487
|
+
} catch (err: any) {
|
|
488
|
+
setAlert({ type: "error", message: err?.message || `Could not activate ${p.name}` })
|
|
489
|
+
} finally {
|
|
490
|
+
setBusy(null)
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const removeFromWorkspace = async (p: { id: string; name: string }) => {
|
|
495
|
+
setBusy(p.id)
|
|
496
|
+
try {
|
|
497
|
+
const next = new Set(workspaceActiveIds)
|
|
498
|
+
next.delete(p.id)
|
|
499
|
+
setWorkspaceActiveIds(next)
|
|
500
|
+
try { localStorage.setItem("tr_workspace_plugins", JSON.stringify([...next])) } catch {}
|
|
501
|
+
await setPluginActivation(p.id, false)
|
|
502
|
+
setAlert({ type: "success", message: `Moved ${p.name} from workspace to Plugin Store` })
|
|
503
|
+
await loadLocal()
|
|
504
|
+
} catch (err: any) {
|
|
505
|
+
setAlert({ type: "error", message: err?.message || `Could not deactivate ${p.name}` })
|
|
506
|
+
} finally {
|
|
507
|
+
setBusy(null)
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const copyAgentPrompt = () => {
|
|
512
|
+
void navigator.clipboard?.writeText(AGENT_RECIPE_PROMPT)
|
|
513
|
+
setAlert({ type: "success", message: "Copied Agent Plugin Recipe prompt to clipboard" })
|
|
514
|
+
}
|
|
515
|
+
|
|
423
516
|
const doInstall = async (source: string, opts: { link?: boolean; global?: boolean } = {}) => {
|
|
424
517
|
setBusy(source)
|
|
425
518
|
setAlert(null)
|
|
@@ -572,7 +665,68 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
|
|
|
572
665
|
}
|
|
573
666
|
|
|
574
667
|
const filteredInstalled = installed.filter(matches)
|
|
575
|
-
const
|
|
668
|
+
const myCards = filteredInstalled.filter(isWorkspaceCard)
|
|
669
|
+
const shownInstalled = viewMode === "workspace" ? myCards : filteredInstalled
|
|
670
|
+
|
|
671
|
+
const storeCatalog = useMemo(() => {
|
|
672
|
+
const map = new Map<string, {
|
|
673
|
+
id: string;
|
|
674
|
+
name: string;
|
|
675
|
+
version: string;
|
|
676
|
+
description: string;
|
|
677
|
+
use_cases: string[];
|
|
678
|
+
installed: boolean;
|
|
679
|
+
inWorkspace: boolean;
|
|
680
|
+
sourcePlugin?: PluginInfo;
|
|
681
|
+
branding?: { icon?: string | null; color?: string | null; badge?: string | null };
|
|
682
|
+
cli?: { command: string | null; subcommands?: Array<{ name: string; description?: string }> } | null;
|
|
683
|
+
tasks?: any[];
|
|
684
|
+
secrets?: any[];
|
|
685
|
+
}>()
|
|
686
|
+
|
|
687
|
+
// Add bundled plugins
|
|
688
|
+
for (const b of bundled) {
|
|
689
|
+
const inst = installed.find((i) => i.id === b.id)
|
|
690
|
+
map.set(b.id, {
|
|
691
|
+
id: b.id,
|
|
692
|
+
name: b.name,
|
|
693
|
+
version: b.version,
|
|
694
|
+
description: b.description,
|
|
695
|
+
use_cases: b.use_cases || [],
|
|
696
|
+
installed: b.installed || !!inst,
|
|
697
|
+
inWorkspace: inst ? isWorkspaceCard(inst) : false,
|
|
698
|
+
sourcePlugin: inst,
|
|
699
|
+
branding: b.branding || (inst ? inst.branding : undefined),
|
|
700
|
+
cli: b.cli || (inst ? inst.cli : null),
|
|
701
|
+
tasks: b.tasks || (inst ? inst.tasks : []),
|
|
702
|
+
secrets: inst?.secrets || []
|
|
703
|
+
})
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// Add any installed plugins that aren't in bundled
|
|
707
|
+
for (const inst of installed) {
|
|
708
|
+
if (!map.has(inst.id)) {
|
|
709
|
+
map.set(inst.id, {
|
|
710
|
+
id: inst.id,
|
|
711
|
+
name: inst.name,
|
|
712
|
+
version: inst.version,
|
|
713
|
+
description: inst.description,
|
|
714
|
+
use_cases: inst.use_cases || [],
|
|
715
|
+
installed: true,
|
|
716
|
+
inWorkspace: isWorkspaceCard(inst),
|
|
717
|
+
sourcePlugin: inst,
|
|
718
|
+
branding: inst.branding,
|
|
719
|
+
cli: inst.cli,
|
|
720
|
+
tasks: inst.tasks,
|
|
721
|
+
secrets: inst.secrets || []
|
|
722
|
+
})
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
return Array.from(map.values())
|
|
727
|
+
}, [bundled, installed, isWorkspaceCard])
|
|
728
|
+
|
|
729
|
+
const filteredStoreCatalog = storeCatalog.filter(matches)
|
|
576
730
|
|
|
577
731
|
const tabButton = (id: Tab, label: string, count?: number) => (
|
|
578
732
|
<button
|
|
@@ -583,7 +737,7 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
|
|
|
583
737
|
onClick={() => setTab(id)}
|
|
584
738
|
>
|
|
585
739
|
{label}
|
|
586
|
-
{count !== undefined && <span style={{ opacity: 0.75, fontWeight: 500 }}>{count}</span>}
|
|
740
|
+
{count !== undefined && <span style={{ opacity: 0.75, fontWeight: 500, marginLeft: "4px" }}>{count}</span>}
|
|
587
741
|
</button>
|
|
588
742
|
)
|
|
589
743
|
|
|
@@ -593,13 +747,18 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
|
|
|
593
747
|
<div>
|
|
594
748
|
<h1>Plugins</h1>
|
|
595
749
|
<p>
|
|
596
|
-
|
|
750
|
+
Modular capability system for Total Recall and SSSS apps — memory categories, agent context, commands, and design-token UI.
|
|
597
751
|
Customizable branding, locked release status, and direct store deployment are managed on each card.
|
|
598
752
|
</p>
|
|
599
753
|
</div>
|
|
600
|
-
<
|
|
601
|
-
|
|
602
|
-
|
|
754
|
+
<div style={{ display: "flex", gap: "8px" }}>
|
|
755
|
+
<button className="btn btn-ghost" onClick={() => setRecipeOpen(true)}>
|
|
756
|
+
Agent Recipe
|
|
757
|
+
</button>
|
|
758
|
+
<button className="btn btn-primary" onClick={() => { setInstallOpen(true); setAlert(null) }}>
|
|
759
|
+
Install from source…
|
|
760
|
+
</button>
|
|
761
|
+
</div>
|
|
603
762
|
</div>
|
|
604
763
|
|
|
605
764
|
{alert && (
|
|
@@ -612,8 +771,8 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
|
|
|
612
771
|
|
|
613
772
|
<div style={{ display: "flex", justifyContent: "space-between", gap: "12px", flexWrap: "wrap", marginBottom: "20px" }}>
|
|
614
773
|
<div role="tablist" style={{ display: "flex", gap: "8px" }}>
|
|
615
|
-
{tabButton("installed", "
|
|
616
|
-
{tabButton("bundled", "Bundled",
|
|
774
|
+
{tabButton("installed", "My Cards", myCards.length)}
|
|
775
|
+
{tabButton("bundled", "Plugin Store (Bundled)", filteredStoreCatalog.length)}
|
|
617
776
|
{tabButton("mesh", "On the mesh")}
|
|
618
777
|
</div>
|
|
619
778
|
<div style={{ display: "flex", gap: "8px", flexWrap: "wrap" }}>
|
|
@@ -627,96 +786,311 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
|
|
|
627
786
|
</div>
|
|
628
787
|
|
|
629
788
|
{tab === "installed" && (
|
|
630
|
-
loading ? <div style={muted}>Loading…</div> :
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
<div className="card-grid" style={{ gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 360px), 1fr))", gap: "22px" }}>
|
|
637
|
-
{filteredInstalled.map((p) => {
|
|
638
|
-
return (
|
|
639
|
-
<div
|
|
640
|
-
key={`${p.scope}:${p.id}`}
|
|
641
|
-
onContextMenu={(e) => handleContextMenu(p, e)}
|
|
642
|
-
onTouchStart={(e) => handleTouchStart(p, e)}
|
|
643
|
-
onTouchEnd={cancelLongPress}
|
|
644
|
-
style={{ display: "flex", flexDirection: "column", gap: "8px" }}
|
|
645
|
-
>
|
|
646
|
-
<CardEngine plugin={p} />
|
|
647
|
-
<div style={{ display: "flex", gap: "6px", alignItems: "center", padding: "0 4px", fontSize: "11px", color: "var(--text-tertiary)" }}>
|
|
648
|
-
<span className="badge">{p.scope}</span>
|
|
649
|
-
<span className="badge">{sourceLabel(p)}</span>
|
|
650
|
-
{p.shared && <span className="badge badge-accent">shared</span>}
|
|
651
|
-
{!p.valid && <span className="badge badge-error">invalid manifest</span>}
|
|
652
|
-
{p.modified_since_install && <span className="badge badge-warning">changed since install</span>}
|
|
653
|
-
</div>
|
|
789
|
+
loading ? <div style={muted}>Loading…</div> : (
|
|
790
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
|
|
791
|
+
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: "12px" }}>
|
|
792
|
+
<div>
|
|
793
|
+
<div style={{ fontWeight: 600, fontSize: "15px" }}>
|
|
794
|
+
{viewMode === "workspace" ? "Active Workspace Cards" : "All Installed Plugins"}
|
|
654
795
|
</div>
|
|
655
|
-
|
|
656
|
-
|
|
796
|
+
<div style={muted}>
|
|
797
|
+
{viewMode === "workspace"
|
|
798
|
+
? "Core runtime foundation and activated repository cards. Optional tools live in the Plugin Store."
|
|
799
|
+
: "All plugin packages installed on this host."}
|
|
800
|
+
</div>
|
|
801
|
+
</div>
|
|
802
|
+
<div style={{ display: "flex", gap: "6px" }}>
|
|
803
|
+
<button
|
|
804
|
+
type="button"
|
|
805
|
+
className={`btn btn-xs ${viewMode === "workspace" ? "btn-primary" : "btn-ghost"}`}
|
|
806
|
+
onClick={() => setViewMode("workspace")}
|
|
807
|
+
>
|
|
808
|
+
Workspace ({myCards.length})
|
|
809
|
+
</button>
|
|
810
|
+
<button
|
|
811
|
+
type="button"
|
|
812
|
+
className={`btn btn-xs ${viewMode === "all" ? "btn-primary" : "btn-ghost"}`}
|
|
813
|
+
onClick={() => setViewMode("all")}
|
|
814
|
+
>
|
|
815
|
+
All Installed ({installed.length})
|
|
816
|
+
</button>
|
|
817
|
+
</div>
|
|
818
|
+
</div>
|
|
819
|
+
|
|
820
|
+
{shownInstalled.length === 0 ? (
|
|
821
|
+
<Empty title={viewMode === "workspace" ? "No workspace cards active" : "No plugins installed"}>
|
|
822
|
+
{viewMode === "workspace" ? (
|
|
823
|
+
<>
|
|
824
|
+
Explore the <button type="button" className="btn btn-ghost btn-sm" onClick={() => setTab("bundled")}>Plugin Store</button> to add capabilities or ask your agent to author one.
|
|
825
|
+
</>
|
|
826
|
+
) : (
|
|
827
|
+
<>Start with a <button type="button" className="btn btn-ghost btn-sm" onClick={() => setTab("bundled")}>bundled plugin</button> or see what your peers share.</>
|
|
828
|
+
)}
|
|
829
|
+
</Empty>
|
|
830
|
+
) : (
|
|
831
|
+
<div className="card-grid" style={{ gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 360px), 1fr))", gap: "22px" }}>
|
|
832
|
+
{shownInstalled.map((p) => {
|
|
833
|
+
return (
|
|
834
|
+
<div
|
|
835
|
+
key={`${p.scope}:${p.id}`}
|
|
836
|
+
onContextMenu={(e) => handleContextMenu(p, e)}
|
|
837
|
+
onTouchStart={(e) => handleTouchStart(p, e)}
|
|
838
|
+
onTouchEnd={cancelLongPress}
|
|
839
|
+
style={{ display: "flex", flexDirection: "column", gap: "8px" }}
|
|
840
|
+
>
|
|
841
|
+
<CardEngine plugin={p} />
|
|
842
|
+
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "0 4px", fontSize: "11px", color: "var(--text-tertiary)", flexWrap: "wrap", gap: "6px" }}>
|
|
843
|
+
<div style={{ display: "flex", gap: "6px", alignItems: "center", flexWrap: "wrap" }}>
|
|
844
|
+
<span className="badge">{p.scope}</span>
|
|
845
|
+
<span className="badge">{sourceLabel(p)}</span>
|
|
846
|
+
{p.shared && <span className="badge badge-accent">shared</span>}
|
|
847
|
+
{!p.valid && <span className="badge badge-error">invalid manifest</span>}
|
|
848
|
+
{p.modified_since_install && <span className="badge badge-warning">changed since install</span>}
|
|
849
|
+
</div>
|
|
850
|
+
{!DEFAULT_CORE_PLUGINS.has(p.id) && (
|
|
851
|
+
<button
|
|
852
|
+
type="button"
|
|
853
|
+
className="btn btn-ghost btn-xs"
|
|
854
|
+
onClick={() => removeFromWorkspace(p)}
|
|
855
|
+
style={{ fontSize: "11px", color: "var(--text-secondary)" }}
|
|
856
|
+
title="Move back to Plugin Store"
|
|
857
|
+
>
|
|
858
|
+
Remove from Workspace
|
|
859
|
+
</button>
|
|
860
|
+
)}
|
|
861
|
+
</div>
|
|
862
|
+
</div>
|
|
863
|
+
)
|
|
864
|
+
})}
|
|
865
|
+
</div>
|
|
866
|
+
)}
|
|
657
867
|
</div>
|
|
658
868
|
)
|
|
659
869
|
)}
|
|
660
870
|
|
|
661
871
|
{tab === "bundled" && (
|
|
662
|
-
loading ? <div style={muted}>Loading…</div> :
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
<
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
872
|
+
loading ? <div style={muted}>Loading…</div> : (
|
|
873
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "20px" }}>
|
|
874
|
+
{/* Agent Plugin Recipe Hero Banner */}
|
|
875
|
+
<div className="card" style={{
|
|
876
|
+
background: "linear-gradient(135deg, rgba(30, 41, 59, 0.7) 0%, rgba(15, 23, 42, 0.85) 100%)",
|
|
877
|
+
border: "1px solid rgba(99, 102, 241, 0.3)",
|
|
878
|
+
padding: "20px",
|
|
879
|
+
display: "flex",
|
|
880
|
+
flexDirection: "column",
|
|
881
|
+
gap: "14px"
|
|
882
|
+
}}>
|
|
883
|
+
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: "16px", flexWrap: "wrap" }}>
|
|
884
|
+
<div>
|
|
885
|
+
<div style={{ display: "flex", alignItems: "center", gap: "8px", marginBottom: "4px" }}>
|
|
886
|
+
<span className="badge" style={{ background: "rgba(99, 102, 241, 0.2)", color: "#818cf8", borderColor: "rgba(99, 102, 241, 0.4)", fontSize: "11px" }}>
|
|
887
|
+
AGENT RECIPE ARCHITECTURE
|
|
888
|
+
</span>
|
|
889
|
+
<span style={{ fontSize: "11px", color: "var(--text-tertiary)" }}>
|
|
890
|
+
Declarative Recipes · Private or Store
|
|
891
|
+
</span>
|
|
892
|
+
</div>
|
|
893
|
+
<h2 style={{ fontSize: "18px", fontWeight: 700, margin: 0, color: "#f8fafc" }}>
|
|
894
|
+
Build Bespoke Plugins with Your Coding Agent
|
|
895
|
+
</h2>
|
|
896
|
+
<p style={{ ...muted, margin: "6px 0 0 0", maxWidth: "640px" }}>
|
|
897
|
+
Total Recall plugins are not generated by closed system templates; your contextual coding agent (Antigravity, Claude, Codex, DSH) builds them from a declarative Recipe. Run them privately in your workspace or publish them to the Plugin Store.
|
|
898
|
+
</p>
|
|
899
|
+
</div>
|
|
900
|
+
<div style={{ display: "flex", gap: "8px", flexWrap: "wrap" }}>
|
|
901
|
+
<button
|
|
902
|
+
type="button"
|
|
903
|
+
className="btn btn-primary btn-sm"
|
|
904
|
+
onClick={() => setRecipeOpen(true)}
|
|
905
|
+
>
|
|
906
|
+
View Agent Recipe
|
|
907
|
+
</button>
|
|
908
|
+
<button
|
|
909
|
+
type="button"
|
|
910
|
+
className="btn btn-ghost btn-sm"
|
|
911
|
+
onClick={copyAgentPrompt}
|
|
912
|
+
>
|
|
913
|
+
Copy Agent Prompt
|
|
914
|
+
</button>
|
|
915
|
+
<button
|
|
916
|
+
type="button"
|
|
917
|
+
className="btn btn-ghost btn-sm"
|
|
918
|
+
onClick={() => { setInstallOpen(true); setAlert(null) }}
|
|
919
|
+
>
|
|
920
|
+
Install from source…
|
|
921
|
+
</button>
|
|
922
|
+
</div>
|
|
923
|
+
</div>
|
|
924
|
+
</div>
|
|
925
|
+
|
|
926
|
+
{filteredStoreCatalog.length === 0 ? (
|
|
927
|
+
<Empty title="No plugins match in store" />
|
|
928
|
+
) : (
|
|
929
|
+
<div className="card-grid" style={{ gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 340px), 1fr))", gap: "16px" }}>
|
|
930
|
+
{filteredStoreCatalog.map((item) => {
|
|
931
|
+
const branding = resolvePluginBranding(item)
|
|
932
|
+
return (
|
|
933
|
+
<div
|
|
934
|
+
key={item.id}
|
|
935
|
+
className="card"
|
|
936
|
+
style={{
|
|
937
|
+
display: "flex",
|
|
938
|
+
flexDirection: "column",
|
|
939
|
+
gap: "10px",
|
|
940
|
+
borderTop: `3px solid ${branding.color}`,
|
|
941
|
+
background: "var(--bg-secondary)"
|
|
942
|
+
}}
|
|
943
|
+
>
|
|
944
|
+
<div style={{ display: "flex", justifyContent: "space-between", gap: "8px", alignItems: "flex-start" }}>
|
|
945
|
+
<div style={{ display: "flex", gap: "10px", alignItems: "center" }}>
|
|
946
|
+
<div
|
|
947
|
+
style={{
|
|
948
|
+
width: "34px",
|
|
949
|
+
height: "34px",
|
|
950
|
+
borderRadius: "8px",
|
|
951
|
+
background: `${branding.color}20`,
|
|
952
|
+
border: `1px solid ${branding.color}40`,
|
|
953
|
+
display: "flex",
|
|
954
|
+
alignItems: "center",
|
|
955
|
+
justifyContent: "center",
|
|
956
|
+
fontWeight: 700,
|
|
957
|
+
fontSize: "12px",
|
|
958
|
+
color: branding.color
|
|
959
|
+
}}
|
|
960
|
+
>
|
|
961
|
+
{branding.icon || item.name.slice(0, 2).toUpperCase()}
|
|
962
|
+
</div>
|
|
963
|
+
<div>
|
|
964
|
+
<div style={{ fontWeight: 600, fontSize: "14px", lineHeight: 1.2 }}>{item.name}</div>
|
|
965
|
+
<div style={{ ...mono, color: "var(--text-tertiary)", fontSize: "11px" }}>
|
|
966
|
+
{item.id} · v{item.version}
|
|
967
|
+
</div>
|
|
968
|
+
</div>
|
|
689
969
|
</div>
|
|
690
|
-
<div>
|
|
691
|
-
<span style={{
|
|
692
|
-
|
|
970
|
+
<div style={{ display: "flex", flexDirection: "column", alignItems: "flex-end", gap: "4px" }}>
|
|
971
|
+
<span className="badge" style={{ background: `${branding.color}15`, color: branding.color, borderColor: `${branding.color}35`, fontSize: "10px" }}>
|
|
972
|
+
{branding.badge}
|
|
973
|
+
</span>
|
|
974
|
+
{item.inWorkspace && (
|
|
975
|
+
<span className="badge badge-success" style={{ fontSize: "10px" }}>
|
|
976
|
+
✓ In Workspace
|
|
977
|
+
</span>
|
|
978
|
+
)}
|
|
693
979
|
</div>
|
|
694
980
|
</div>
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
{
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
981
|
+
|
|
982
|
+
<div style={{ ...muted, fontSize: "12px", minHeight: "36px" }}>
|
|
983
|
+
{item.description}
|
|
984
|
+
</div>
|
|
985
|
+
|
|
986
|
+
<div style={{ display: "flex", gap: "4px", flexWrap: "wrap", fontSize: "10px" }}>
|
|
987
|
+
{item.cli && (
|
|
988
|
+
<span className="badge" style={{ fontFamily: "var(--font-mono)" }}>
|
|
989
|
+
CLI ({item.cli.subcommands?.length || 1})
|
|
990
|
+
</span>
|
|
991
|
+
)}
|
|
992
|
+
{item.tasks && item.tasks.length > 0 && (
|
|
993
|
+
<span className="badge" style={{ fontFamily: "var(--font-mono)" }}>
|
|
994
|
+
{item.tasks.length} {item.tasks.length === 1 ? "task" : "tasks"}
|
|
995
|
+
</span>
|
|
996
|
+
)}
|
|
997
|
+
{item.secrets && item.secrets.length > 0 && (
|
|
998
|
+
<span className="badge" style={{ fontFamily: "var(--font-mono)" }}>
|
|
999
|
+
{item.secrets.length} {item.secrets.length === 1 ? "secret" : "secrets"}
|
|
1000
|
+
</span>
|
|
1001
|
+
)}
|
|
1002
|
+
{DEFAULT_CORE_PLUGINS.has(item.id) && (
|
|
1003
|
+
<span className="badge" style={{ background: "rgba(59, 130, 246, 0.15)", color: "#60a5fa" }}>
|
|
1004
|
+
Core Bundle
|
|
1005
|
+
</span>
|
|
1006
|
+
)}
|
|
1007
|
+
</div>
|
|
1008
|
+
|
|
1009
|
+
<UseCaseChips useCases={item.use_cases} />
|
|
1010
|
+
|
|
1011
|
+
<div style={{ marginTop: "auto", display: "flex", justifyContent: "space-between", alignItems: "center", gap: "8px", paddingTop: "8px", borderTop: "1px solid var(--border)" }}>
|
|
1012
|
+
<button
|
|
1013
|
+
type="button"
|
|
1014
|
+
className="btn btn-ghost btn-sm"
|
|
1015
|
+
onClick={() => {
|
|
1016
|
+
if (item.sourcePlugin) {
|
|
1017
|
+
openDetail(item.sourcePlugin, "preview")
|
|
1018
|
+
} else {
|
|
1019
|
+
openDetail({
|
|
1020
|
+
id: item.id,
|
|
1021
|
+
name: item.name,
|
|
1022
|
+
version: item.version,
|
|
1023
|
+
description: item.description,
|
|
1024
|
+
author: null,
|
|
1025
|
+
license: null,
|
|
1026
|
+
homepage: null,
|
|
1027
|
+
use_cases: item.use_cases,
|
|
1028
|
+
valid: true,
|
|
1029
|
+
errors: [],
|
|
1030
|
+
scope: "global",
|
|
1031
|
+
linked: false,
|
|
1032
|
+
dir: "",
|
|
1033
|
+
shared: false,
|
|
1034
|
+
mesh_shared: false,
|
|
1035
|
+
share_url: null,
|
|
1036
|
+
source: { kind: "bundled", ref: item.id },
|
|
1037
|
+
installed_at: null,
|
|
1038
|
+
sha256: null,
|
|
1039
|
+
installed_sha256: null,
|
|
1040
|
+
modified_since_install: false,
|
|
1041
|
+
file_count: null,
|
|
1042
|
+
size_bytes: null,
|
|
1043
|
+
categories: [],
|
|
1044
|
+
tasks: item.tasks || [],
|
|
1045
|
+
openwiki_hubs: [],
|
|
1046
|
+
cli: item.cli as any,
|
|
1047
|
+
has_generator: false,
|
|
1048
|
+
branding: item.branding
|
|
1049
|
+
}, "preview")
|
|
1050
|
+
}
|
|
1051
|
+
}}
|
|
1052
|
+
>
|
|
1053
|
+
Preview
|
|
712
1054
|
</button>
|
|
713
|
-
|
|
1055
|
+
|
|
1056
|
+
<div style={{ display: "flex", gap: "6px" }}>
|
|
1057
|
+
{!item.installed ? (
|
|
1058
|
+
<button
|
|
1059
|
+
type="button"
|
|
1060
|
+
className="btn btn-primary btn-sm"
|
|
1061
|
+
disabled={busy === item.id}
|
|
1062
|
+
onClick={() => doInstall(item.id)}
|
|
1063
|
+
>
|
|
1064
|
+
{busy === item.id ? "Installing…" : "Install"}
|
|
1065
|
+
</button>
|
|
1066
|
+
) : item.inWorkspace ? (
|
|
1067
|
+
<button
|
|
1068
|
+
type="button"
|
|
1069
|
+
className="btn btn-ghost btn-sm"
|
|
1070
|
+
disabled={busy === item.id}
|
|
1071
|
+
onClick={() => removeFromWorkspace(item.sourcePlugin || item)}
|
|
1072
|
+
style={{ fontSize: "11px" }}
|
|
1073
|
+
>
|
|
1074
|
+
Remove from Workspace
|
|
1075
|
+
</button>
|
|
1076
|
+
) : (
|
|
1077
|
+
<button
|
|
1078
|
+
type="button"
|
|
1079
|
+
className="btn btn-primary btn-sm"
|
|
1080
|
+
disabled={busy === item.id}
|
|
1081
|
+
onClick={() => addToWorkspace(item.sourcePlugin || item)}
|
|
1082
|
+
>
|
|
1083
|
+
{busy === item.id ? "Adding…" : "+ Add to Workspace"}
|
|
1084
|
+
</button>
|
|
1085
|
+
)}
|
|
1086
|
+
</div>
|
|
1087
|
+
</div>
|
|
714
1088
|
</div>
|
|
715
|
-
|
|
716
|
-
)
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
1089
|
+
)
|
|
1090
|
+
})}
|
|
1091
|
+
</div>
|
|
1092
|
+
)}
|
|
1093
|
+
</div>
|
|
720
1094
|
)
|
|
721
1095
|
)}
|
|
722
1096
|
|
|
@@ -909,6 +1283,77 @@ export default function PluginsPage({ activeBrainId }: PluginsPageProps) {
|
|
|
909
1283
|
</div>
|
|
910
1284
|
)}
|
|
911
1285
|
|
|
1286
|
+
{/* Agent Plugin Recipe Modal */}
|
|
1287
|
+
{recipeOpen && (
|
|
1288
|
+
<div
|
|
1289
|
+
role="dialog"
|
|
1290
|
+
aria-modal="true"
|
|
1291
|
+
aria-label="Agent Plugin Recipe"
|
|
1292
|
+
onClick={() => setRecipeOpen(false)}
|
|
1293
|
+
style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.65)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1000, padding: "16px" }}
|
|
1294
|
+
>
|
|
1295
|
+
<div
|
|
1296
|
+
className="card"
|
|
1297
|
+
onClick={(e) => e.stopPropagation()}
|
|
1298
|
+
style={{ width: "100%", maxWidth: "680px", maxHeight: "90vh", overflowY: "auto", display: "flex", flexDirection: "column", gap: "16px" }}
|
|
1299
|
+
>
|
|
1300
|
+
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
|
1301
|
+
<div>
|
|
1302
|
+
<h3 style={{ margin: 0, fontSize: "17px", fontWeight: 700 }}>Agent Plugin Recipe</h3>
|
|
1303
|
+
<div style={{ ...muted, fontSize: "12px" }}>How your coding agent authors private or store plugins</div>
|
|
1304
|
+
</div>
|
|
1305
|
+
<button className="btn btn-ghost btn-sm" onClick={() => setRecipeOpen(false)}>✕</button>
|
|
1306
|
+
</div>
|
|
1307
|
+
|
|
1308
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "12px", fontSize: "13px" }}>
|
|
1309
|
+
<div style={{ background: "var(--bg-tertiary)", padding: "12px", borderRadius: "8px", border: "1px solid var(--border)" }}>
|
|
1310
|
+
<div style={{ fontWeight: 600, marginBottom: "4px" }}>1. Command your agent</div>
|
|
1311
|
+
<div style={muted}>
|
|
1312
|
+
Copy and send this instruction to your coding agent (Antigravity, Claude, Codex, DSH):
|
|
1313
|
+
</div>
|
|
1314
|
+
<pre style={{ ...mono, background: "rgba(0,0,0,0.4)", padding: "10px", borderRadius: "6px", marginTop: "8px", whiteSpace: "pre-wrap", overflowX: "auto", fontSize: "11px", color: "#a5b4fc" }}>
|
|
1315
|
+
{AGENT_RECIPE_PROMPT}
|
|
1316
|
+
</pre>
|
|
1317
|
+
<div style={{ display: "flex", justifyContent: "flex-end", marginTop: "8px" }}>
|
|
1318
|
+
<button type="button" className="btn btn-primary btn-sm" onClick={() => copyAgentPrompt()}>
|
|
1319
|
+
Copy Agent Prompt
|
|
1320
|
+
</button>
|
|
1321
|
+
</div>
|
|
1322
|
+
</div>
|
|
1323
|
+
|
|
1324
|
+
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "12px" }}>
|
|
1325
|
+
<div style={{ background: "var(--bg-tertiary)", padding: "12px", borderRadius: "8px", border: "1px solid var(--border)" }}>
|
|
1326
|
+
<div style={{ fontWeight: 600, color: "#38bdf8", marginBottom: "4px" }}>🔒 Private Plugins</div>
|
|
1327
|
+
<div style={{ ...muted, fontSize: "12px", lineHeight: 1.4 }}>
|
|
1328
|
+
Store directly inside <code style={mono}>.agent/skills/total-recall/plugins/<id></code> or link locally. Never shared outside this machine or project. Zero cloud exposure.
|
|
1329
|
+
</div>
|
|
1330
|
+
</div>
|
|
1331
|
+
|
|
1332
|
+
<div style={{ background: "var(--bg-tertiary)", padding: "12px", borderRadius: "8px", border: "1px solid var(--border)" }}>
|
|
1333
|
+
<div style={{ fontWeight: 600, color: "#a855f7", marginBottom: "4px" }}>🌐 Plugin Store Distribution</div>
|
|
1334
|
+
<div style={{ ...muted, fontSize: "12px", lineHeight: 1.4 }}>
|
|
1335
|
+
Deploy to the store via <code style={mono}>total-recall deploy-store <id></code>. Cryptographically signed and distributed across the mesh for team consumption.
|
|
1336
|
+
</div>
|
|
1337
|
+
</div>
|
|
1338
|
+
</div>
|
|
1339
|
+
|
|
1340
|
+
<div style={{ background: "rgba(16, 185, 129, 0.08)", padding: "12px", borderRadius: "8px", border: "1px solid rgba(16, 185, 129, 0.2)" }}>
|
|
1341
|
+
<div style={{ fontWeight: 600, color: "#10b981", marginBottom: "4px" }}>Quality Invariants Enforced</div>
|
|
1342
|
+
<ul style={{ margin: "4px 0 0 16px", padding: 0, fontSize: "12px", color: "var(--text-secondary)" }}>
|
|
1343
|
+
<li>Guaranteed Title, Brand Glyph, Version, and Settings drawer trigger on every card</li>
|
|
1344
|
+
<li>Authentic domain tools only — zero fake audio equalizers or fake skins</li>
|
|
1345
|
+
<li>Touch-first ergonomics with minimum 44px tap targets</li>
|
|
1346
|
+
</ul>
|
|
1347
|
+
</div>
|
|
1348
|
+
</div>
|
|
1349
|
+
|
|
1350
|
+
<div style={{ display: "flex", justifyContent: "flex-end", marginTop: "8px" }}>
|
|
1351
|
+
<button type="button" className="btn btn-ghost" onClick={() => setRecipeOpen(false)}>Close</button>
|
|
1352
|
+
</div>
|
|
1353
|
+
</div>
|
|
1354
|
+
</div>
|
|
1355
|
+
)}
|
|
1356
|
+
|
|
912
1357
|
{/* Plugin Detail & Interactive Preview Drawer */}
|
|
913
1358
|
{detail && (
|
|
914
1359
|
<div role="dialog" aria-modal="true" aria-label={detail.name} onClick={closeDetail}
|