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
package/frontend/dist/index.html
CHANGED
|
@@ -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-
|
|
21
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
20
|
+
<script type="module" crossorigin src="/assets/index-Bt5iVPZj.js"></script>
|
|
21
|
+
<link rel="stylesheet" crossorigin href="/assets/index-AGUes-VG.css">
|
|
22
22
|
</head>
|
|
23
23
|
<body>
|
|
24
24
|
<div id="root"></div>
|
package/frontend/src/api/keys.ts
CHANGED
|
@@ -7,7 +7,8 @@ import { apiFetch, API_BASE } from './_base'
|
|
|
7
7
|
export interface ApiKey {
|
|
8
8
|
id: string
|
|
9
9
|
name: string
|
|
10
|
-
token_preview
|
|
10
|
+
token_preview?: string
|
|
11
|
+
token_prefix?: string
|
|
11
12
|
scopes: string[]
|
|
12
13
|
expires_at: string | null
|
|
13
14
|
created_at: string
|
|
@@ -29,7 +30,13 @@ export async function listApiKeys(): Promise<ApiKeyListResponse> {
|
|
|
29
30
|
const res = await apiFetch(`${API_BASE}/api/keys`)
|
|
30
31
|
if (!res.ok) throw new Error(`Keys API error: ${res.status}`)
|
|
31
32
|
const data = await res.json()
|
|
32
|
-
|
|
33
|
+
if (Array.isArray(data)) {
|
|
34
|
+
return { keys: data, available_scopes: ['*'] }
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
keys: data.keys || [],
|
|
38
|
+
available_scopes: data.available_scopes || ['*']
|
|
39
|
+
}
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
export async function issueApiKey(name: string, scopes?: string[], expiresAt?: string | null): Promise<IssuedApiKey> {
|
|
@@ -226,6 +226,10 @@ export function setPluginLocked(id: string, locked: boolean): Promise<Result> {
|
|
|
226
226
|
return post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/lock`, { locked })
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
export function setPluginActivation(id: string, enabled: boolean): Promise<Result & { activation?: { enabled: boolean; state: string } }> {
|
|
230
|
+
return post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/activation`, { enabled }, "PUT")
|
|
231
|
+
}
|
|
232
|
+
|
|
229
233
|
export function deployPluginToStore(id: string, autoLock = true): Promise<Result & { storePackage?: any }> {
|
|
230
234
|
return post(`${API_BASE}/api/plugins/${encodeURIComponent(id)}/deploy-store`, { autoLock })
|
|
231
235
|
}
|
|
@@ -102,7 +102,8 @@ export function CardEngine({ plugin }: { plugin: PluginInfo }) {
|
|
|
102
102
|
const [drawer, setDrawer] = useState(false)
|
|
103
103
|
return <CardRunner card={card}>
|
|
104
104
|
<section className={`card card-${card.template}${owned ? ' card-owned' : ''}`} style={brandStyle(card.branding)} data-density={card.branding.density} aria-label={`${card.title} card`}>
|
|
105
|
-
|
|
105
|
+
<Header card={card} onOpenDrawer={() => setDrawer(true)} />
|
|
106
|
+
{card.description && <p className="card-muted card-description">{card.description}</p>}
|
|
106
107
|
<CardScenes plugin={plugin}><div className="card-regions">
|
|
107
108
|
{card.regions.filter(region => !['actions', 'form', 'keypad'].includes(region.widget)).map((region, i) => <section key={i} className={`card-region card-region-${region.widget}`} style={{ gridColumn: `span ${Math.min(12, Math.max(1, region.span || 12))}` }}>
|
|
108
109
|
{region.title && <h3>{region.title}</h3>}<Region region={region} plugin={plugin} />
|
|
@@ -31,5 +31,5 @@
|
|
|
31
31
|
@media (prefers-reduced-motion:no-preference){.card-drawer{animation:card-slide .18s ease-out}@keyframes card-slide{from{transform:translateX(24px);opacity:0}}}
|
|
32
32
|
.card-scene-track{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:thin;gap:var(--card-gap);overscroll-behavior-x:contain}.card-scene{flex:0 0 100%;min-width:0;scroll-snap-align:start;padding:4px}.card-scene-controls{margin-bottom:var(--card-gap)}.card-scenes[data-state=inactive] .card-scene-track{opacity:.65}.card-scenes[aria-busy=true] .card-pill{animation:card-running 1.1s ease-in-out infinite}@keyframes card-running{50%{box-shadow:0 0 0 3px color-mix(in srgb,var(--card-color) 28%,transparent)}}@media(prefers-reduced-motion:reduce){.card-scenes[aria-busy=true] .card-pill{animation:none}.card-scene-track{scroll-behavior:auto}}
|
|
33
33
|
.card-scene-track{position:relative}.card-context-menu{display:grid;gap:8px;padding:12px;border:1px solid var(--card-line);border-radius:var(--card-radius);background:var(--card-surface);box-shadow:0 8px 24px #0002}.card-context-menu button{text-align:left}
|
|
34
|
-
.card.card-owned{border:
|
|
34
|
+
.card.card-owned{border:1px solid var(--card-line);background:var(--card-surface);border-radius:var(--card-radius);padding:var(--card-gap);box-shadow:0 1px 3px rgba(0,0,0,0.06)}.card-owned .card-link{color:var(--text-primary,#111)}.card-permissions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.card-permissions label{display:flex;align-items:center;gap:8px}.card-execution{margin-bottom:var(--card-gap)}
|
|
35
35
|
.card-scenes,.card-scene-track{min-width:0;max-width:100%}.card-scene{box-sizing:border-box}.card-execution fieldset{min-inline-size:0;box-sizing:border-box;width:100%}.card-execution select,.card-execution input:not([type=checkbox]){min-width:0;width:100%;box-sizing:border-box}.card-permissions label{white-space:normal}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { useMemo, useState, useEffect } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getApiBase,
|
|
4
|
+
connectClient,
|
|
5
|
+
fetchActiveIntegrations,
|
|
6
|
+
fetchExtensionStatus,
|
|
7
|
+
listApiKeys,
|
|
8
|
+
issueApiKey,
|
|
9
|
+
revokeApiKey,
|
|
10
|
+
type ApiKey,
|
|
11
|
+
type IssuedApiKey,
|
|
12
|
+
} from '../api'
|
|
3
13
|
|
|
4
14
|
type Preset = {
|
|
5
15
|
id: string
|
|
@@ -88,6 +98,13 @@ export default function IntegrationsPage({ activeBrainId }: { activeBrainId?: st
|
|
|
88
98
|
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null)
|
|
89
99
|
const [activeIdes, setActiveIdes] = useState<string[]>([])
|
|
90
100
|
const [extStatus, setExtStatus] = useState<{ available: boolean; connected: boolean } | null>(null)
|
|
101
|
+
const [keys, setKeys] = useState<ApiKey[]>([])
|
|
102
|
+
const [keysLoading, setKeysLoading] = useState(false)
|
|
103
|
+
const [createdToken, setCreatedToken] = useState<IssuedApiKey | null>(null)
|
|
104
|
+
const [tokenName, setTokenName] = useState('')
|
|
105
|
+
const [tokenScope, setTokenScope] = useState('*')
|
|
106
|
+
const [isIssuingToken, setIsIssuingToken] = useState(false)
|
|
107
|
+
const [revokingId, setRevokingId] = useState<string | null>(null)
|
|
91
108
|
|
|
92
109
|
const baseUrl = useMemo(() => {
|
|
93
110
|
const configured = getApiBase()
|
|
@@ -95,9 +112,25 @@ export default function IntegrationsPage({ activeBrainId }: { activeBrainId?: st
|
|
|
95
112
|
return window.location.origin
|
|
96
113
|
}, [])
|
|
97
114
|
|
|
115
|
+
const loadKeys = () => {
|
|
116
|
+
setKeysLoading(true)
|
|
117
|
+
listApiKeys()
|
|
118
|
+
.then(res => {
|
|
119
|
+
setKeys(res.keys || [])
|
|
120
|
+
})
|
|
121
|
+
.catch(e => {
|
|
122
|
+
console.error('Failed to load keys', e)
|
|
123
|
+
})
|
|
124
|
+
.finally(() => {
|
|
125
|
+
setKeysLoading(false)
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
98
129
|
useEffect(() => {
|
|
99
130
|
let active = true
|
|
100
131
|
|
|
132
|
+
loadKeys()
|
|
133
|
+
|
|
101
134
|
fetchActiveIntegrations()
|
|
102
135
|
.then(res => {
|
|
103
136
|
if (active && res.success && Array.isArray(res.active)) {
|
|
@@ -119,6 +152,34 @@ export default function IntegrationsPage({ activeBrainId }: { activeBrainId?: st
|
|
|
119
152
|
return () => { active = false }
|
|
120
153
|
}, [activeBrainId])
|
|
121
154
|
|
|
155
|
+
const handleCreateToken = async (name: string, scopes: string[]) => {
|
|
156
|
+
setIsIssuingToken(true)
|
|
157
|
+
setMessage(null)
|
|
158
|
+
try {
|
|
159
|
+
const issued = await issueApiKey(name || 'Personal Access Token', scopes)
|
|
160
|
+
setCreatedToken(issued)
|
|
161
|
+
setMessage({ type: 'success', text: `Generated new token "${issued.name}". Copy it below.` })
|
|
162
|
+
loadKeys()
|
|
163
|
+
} catch (e) {
|
|
164
|
+
setMessage({ type: 'error', text: (e as Error).message || 'Failed to issue token.' })
|
|
165
|
+
} finally {
|
|
166
|
+
setIsIssuingToken(false)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const handleRevokeToken = async (id: string) => {
|
|
171
|
+
setRevokingId(id)
|
|
172
|
+
try {
|
|
173
|
+
await revokeApiKey(id)
|
|
174
|
+
setMessage({ type: 'success', text: 'Token revoked successfully.' })
|
|
175
|
+
loadKeys()
|
|
176
|
+
} catch (e) {
|
|
177
|
+
setMessage({ type: 'error', text: (e as Error).message || 'Failed to revoke token.' })
|
|
178
|
+
} finally {
|
|
179
|
+
setRevokingId(null)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
122
183
|
const filteredPresets = useMemo(() => {
|
|
123
184
|
if (activeIdes.length === 0) return PRESETS
|
|
124
185
|
return PRESETS.filter(preset => activeIdes.includes(preset.id))
|
|
@@ -281,7 +342,7 @@ export default function IntegrationsPage({ activeBrainId }: { activeBrainId?: st
|
|
|
281
342
|
color: 'var(--text-secondary)',
|
|
282
343
|
lineHeight: '1.4'
|
|
283
344
|
}}>
|
|
284
|
-
|
|
345
|
+
Download the extension package with your active brain address and access token automatically baked inside. Zero manual token entry required.
|
|
285
346
|
</div>
|
|
286
347
|
|
|
287
348
|
<div style={{
|
|
@@ -297,32 +358,48 @@ export default function IntegrationsPage({ activeBrainId }: { activeBrainId?: st
|
|
|
297
358
|
1. Download zip & unzip locally.{"\n"}
|
|
298
359
|
2. Go to chrome://extensions in browser.{"\n"}
|
|
299
360
|
3. Enable "Developer mode" (top right).{"\n"}
|
|
300
|
-
4. Click "Load unpacked" & select unzipped folder.
|
|
361
|
+
4. Click "Load unpacked" & select unzipped folder.{"\n"}
|
|
362
|
+
✓ Token and brain address are pre-configured automatically.
|
|
301
363
|
</div>
|
|
302
364
|
|
|
303
|
-
<div style={{ display: 'flex', gap: 10, marginTop: 'auto', paddingTop: 8 }}>
|
|
365
|
+
<div style={{ display: 'flex', gap: 10, marginTop: 'auto', paddingTop: 8, flexWrap: 'wrap' }}>
|
|
304
366
|
<a
|
|
305
367
|
href={`${baseUrl}/api/extension/download`}
|
|
306
368
|
download
|
|
307
369
|
className="btn btn-sm btn-primary"
|
|
308
370
|
style={{
|
|
309
|
-
background: 'linear-gradient(135deg, #
|
|
371
|
+
background: 'linear-gradient(135deg, #10b981 0%, #047857 100%)',
|
|
310
372
|
border: 'none',
|
|
311
|
-
boxShadow: '0 2px 4px rgba(
|
|
373
|
+
boxShadow: '0 2px 4px rgba(16, 185, 129, 0.3)',
|
|
312
374
|
fontWeight: 600,
|
|
313
375
|
cursor: 'pointer',
|
|
314
376
|
textDecoration: 'none',
|
|
315
377
|
display: 'inline-flex',
|
|
316
378
|
alignItems: 'center',
|
|
317
379
|
justifyContent: 'center',
|
|
318
|
-
padding: '
|
|
380
|
+
padding: '8px 14px',
|
|
319
381
|
borderRadius: '6px',
|
|
320
382
|
color: '#fff',
|
|
321
383
|
fontSize: '12px'
|
|
322
384
|
}}
|
|
323
385
|
>
|
|
324
|
-
⬇ Download Extension Zip
|
|
386
|
+
⬇ Download Pre-Configured Extension Zip
|
|
325
387
|
</a>
|
|
388
|
+
<button
|
|
389
|
+
className="btn btn-sm"
|
|
390
|
+
onClick={() => handleCreateToken('Chrome Extension', ['*'])}
|
|
391
|
+
disabled={isIssuingToken}
|
|
392
|
+
style={{
|
|
393
|
+
background: 'rgba(255, 255, 255, 0.05)',
|
|
394
|
+
border: '1px solid var(--border)',
|
|
395
|
+
fontWeight: 500,
|
|
396
|
+
cursor: isIssuingToken ? 'default' : 'pointer',
|
|
397
|
+
color: 'var(--text-secondary)',
|
|
398
|
+
fontSize: '12px'
|
|
399
|
+
}}
|
|
400
|
+
>
|
|
401
|
+
{isIssuingToken ? 'Generating...' : '🔑 Generate Extension Token'}
|
|
402
|
+
</button>
|
|
326
403
|
</div>
|
|
327
404
|
</div>
|
|
328
405
|
|
|
@@ -449,6 +526,236 @@ export default function IntegrationsPage({ activeBrainId }: { activeBrainId?: st
|
|
|
449
526
|
)
|
|
450
527
|
})}
|
|
451
528
|
</div>
|
|
529
|
+
|
|
530
|
+
{createdToken && (
|
|
531
|
+
<div style={{
|
|
532
|
+
marginTop: 24,
|
|
533
|
+
marginBottom: 16,
|
|
534
|
+
padding: 16,
|
|
535
|
+
borderRadius: 10,
|
|
536
|
+
background: 'rgba(16, 185, 129, 0.08)',
|
|
537
|
+
border: '1px solid rgba(16, 185, 129, 0.4)',
|
|
538
|
+
boxShadow: '0 4px 16px rgba(16, 185, 129, 0.1)',
|
|
539
|
+
}}>
|
|
540
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
|
|
541
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
|
542
|
+
<span style={{ fontSize: 18 }}>🔑</span>
|
|
543
|
+
<strong style={{ color: '#34d399', fontSize: 15 }}>Token Issued: {createdToken.name}</strong>
|
|
544
|
+
</div>
|
|
545
|
+
<button
|
|
546
|
+
onClick={() => setCreatedToken(null)}
|
|
547
|
+
style={{
|
|
548
|
+
background: 'none',
|
|
549
|
+
border: 'none',
|
|
550
|
+
color: 'var(--text-tertiary)',
|
|
551
|
+
cursor: 'pointer',
|
|
552
|
+
fontSize: 16,
|
|
553
|
+
}}
|
|
554
|
+
>
|
|
555
|
+
✕
|
|
556
|
+
</button>
|
|
557
|
+
</div>
|
|
558
|
+
<p style={{ margin: '0 0 10px', fontSize: 13, color: 'var(--text-secondary)' }}>
|
|
559
|
+
Make sure to copy this token now. It will not be shown again. Paste this token into the Chrome extension settings or your client authorization headers.
|
|
560
|
+
</p>
|
|
561
|
+
<div style={{ display: 'flex', gap: 10, alignItems: 'center', flexWrap: 'wrap' }}>
|
|
562
|
+
<input
|
|
563
|
+
readOnly
|
|
564
|
+
value={createdToken.token}
|
|
565
|
+
style={{
|
|
566
|
+
flex: 1,
|
|
567
|
+
minWidth: 260,
|
|
568
|
+
background: 'var(--bg-primary)',
|
|
569
|
+
border: '1px solid rgba(16, 185, 129, 0.4)',
|
|
570
|
+
borderRadius: 6,
|
|
571
|
+
padding: '8px 12px',
|
|
572
|
+
fontFamily: 'monospace',
|
|
573
|
+
fontSize: 13,
|
|
574
|
+
color: '#34d399',
|
|
575
|
+
}}
|
|
576
|
+
onClick={(e) => (e.target as HTMLInputElement).select()}
|
|
577
|
+
/>
|
|
578
|
+
<button
|
|
579
|
+
className="btn btn-sm btn-primary"
|
|
580
|
+
onClick={() => copy('new-token', createdToken.token)}
|
|
581
|
+
style={{
|
|
582
|
+
background: '#10b981',
|
|
583
|
+
border: 'none',
|
|
584
|
+
fontWeight: 600,
|
|
585
|
+
cursor: 'pointer',
|
|
586
|
+
padding: '8px 16px',
|
|
587
|
+
}}
|
|
588
|
+
>
|
|
589
|
+
{copied === 'new-token' ? 'Copied!' : 'Copy Token'}
|
|
590
|
+
</button>
|
|
591
|
+
</div>
|
|
592
|
+
</div>
|
|
593
|
+
)}
|
|
594
|
+
|
|
595
|
+
<div style={{ marginTop: 32, borderTop: '1px solid var(--border)', paddingTop: 24 }}>
|
|
596
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 16, flexWrap: 'wrap', gap: 12 }}>
|
|
597
|
+
<div>
|
|
598
|
+
<h2 style={{ margin: '0 0 4px', fontSize: 20 }}>Personal Access Tokens & API Keys</h2>
|
|
599
|
+
<p style={{ margin: 0, color: 'var(--text-tertiary)', fontSize: 13 }}>
|
|
600
|
+
Authenticate external applications, browser extensions, and IDE daemons with your Total Recall brain.
|
|
601
|
+
</p>
|
|
602
|
+
</div>
|
|
603
|
+
</div>
|
|
604
|
+
|
|
605
|
+
<div style={{
|
|
606
|
+
background: 'var(--bg-secondary)',
|
|
607
|
+
border: '1px solid var(--border)',
|
|
608
|
+
borderRadius: 10,
|
|
609
|
+
padding: 16,
|
|
610
|
+
marginBottom: 20,
|
|
611
|
+
display: 'flex',
|
|
612
|
+
flexDirection: 'column',
|
|
613
|
+
gap: 12
|
|
614
|
+
}}>
|
|
615
|
+
<h4 style={{ margin: 0, fontSize: 14 }}>Create New Access Token</h4>
|
|
616
|
+
<div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
|
|
617
|
+
<input
|
|
618
|
+
type="text"
|
|
619
|
+
placeholder="Token name (e.g. Chrome Extension, Laptop, CI)"
|
|
620
|
+
value={tokenName}
|
|
621
|
+
onChange={(e) => setTokenName(e.target.value)}
|
|
622
|
+
style={{
|
|
623
|
+
flex: '2 1 200px',
|
|
624
|
+
background: 'var(--bg-primary)',
|
|
625
|
+
border: '1px solid var(--border)',
|
|
626
|
+
borderRadius: 6,
|
|
627
|
+
padding: '8px 12px',
|
|
628
|
+
color: 'var(--text-primary)',
|
|
629
|
+
fontSize: 13,
|
|
630
|
+
}}
|
|
631
|
+
/>
|
|
632
|
+
<select
|
|
633
|
+
value={tokenScope}
|
|
634
|
+
onChange={(e) => setTokenScope(e.target.value)}
|
|
635
|
+
style={{
|
|
636
|
+
flex: '1 1 140px',
|
|
637
|
+
background: 'var(--bg-primary)',
|
|
638
|
+
border: '1px solid var(--border)',
|
|
639
|
+
borderRadius: 6,
|
|
640
|
+
padding: '8px 12px',
|
|
641
|
+
color: 'var(--text-primary)',
|
|
642
|
+
fontSize: 13,
|
|
643
|
+
}}
|
|
644
|
+
>
|
|
645
|
+
<option value="*">Full Access (*)</option>
|
|
646
|
+
<option value="memory:read,memory:write">Memory Read/Write</option>
|
|
647
|
+
<option value="memory:read">Memory Read Only</option>
|
|
648
|
+
</select>
|
|
649
|
+
<button
|
|
650
|
+
className="btn btn-sm btn-primary"
|
|
651
|
+
onClick={() => {
|
|
652
|
+
handleCreateToken(tokenName || 'Personal Access Token', tokenScope.split(','))
|
|
653
|
+
setTokenName('')
|
|
654
|
+
}}
|
|
655
|
+
disabled={isIssuingToken}
|
|
656
|
+
style={{
|
|
657
|
+
background: 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)',
|
|
658
|
+
border: 'none',
|
|
659
|
+
fontWeight: 600,
|
|
660
|
+
cursor: isIssuingToken ? 'default' : 'pointer',
|
|
661
|
+
padding: '8px 16px',
|
|
662
|
+
color: '#fff',
|
|
663
|
+
}}
|
|
664
|
+
>
|
|
665
|
+
{isIssuingToken ? 'Generating...' : 'Generate Token'}
|
|
666
|
+
</button>
|
|
667
|
+
</div>
|
|
668
|
+
</div>
|
|
669
|
+
|
|
670
|
+
<div style={{
|
|
671
|
+
background: 'var(--bg-secondary)',
|
|
672
|
+
border: '1px solid var(--border)',
|
|
673
|
+
borderRadius: 10,
|
|
674
|
+
overflow: 'hidden'
|
|
675
|
+
}}>
|
|
676
|
+
<table style={{ width: '100%', borderCollapse: 'collapse', textAlign: 'left', fontSize: 13 }}>
|
|
677
|
+
<thead>
|
|
678
|
+
<tr style={{ borderBottom: '1px solid var(--border)', background: 'rgba(255, 255, 255, 0.02)' }}>
|
|
679
|
+
<th style={{ padding: '10px 14px', color: 'var(--text-tertiary)', fontWeight: 500 }}>Name</th>
|
|
680
|
+
<th style={{ padding: '10px 14px', color: 'var(--text-tertiary)', fontWeight: 500 }}>Token Prefix</th>
|
|
681
|
+
<th style={{ padding: '10px 14px', color: 'var(--text-tertiary)', fontWeight: 500 }}>Scopes</th>
|
|
682
|
+
<th style={{ padding: '10px 14px', color: 'var(--text-tertiary)', fontWeight: 500 }}>Created</th>
|
|
683
|
+
<th style={{ padding: '10px 14px', color: 'var(--text-tertiary)', fontWeight: 500 }}>Status</th>
|
|
684
|
+
<th style={{ padding: '10px 14px', color: 'var(--text-tertiary)', fontWeight: 500, textAlign: 'right' }}>Actions</th>
|
|
685
|
+
</tr>
|
|
686
|
+
</thead>
|
|
687
|
+
<tbody>
|
|
688
|
+
{keysLoading && (
|
|
689
|
+
<tr>
|
|
690
|
+
<td colSpan={6} style={{ padding: 20, textAlign: 'center', color: 'var(--text-tertiary)' }}>
|
|
691
|
+
Loading tokens...
|
|
692
|
+
</td>
|
|
693
|
+
</tr>
|
|
694
|
+
)}
|
|
695
|
+
{!keysLoading && keys.length === 0 && (
|
|
696
|
+
<tr>
|
|
697
|
+
<td colSpan={6} style={{ padding: 20, textAlign: 'center', color: 'var(--text-tertiary)' }}>
|
|
698
|
+
No access tokens generated yet.
|
|
699
|
+
</td>
|
|
700
|
+
</tr>
|
|
701
|
+
)}
|
|
702
|
+
{!keysLoading && keys.map(k => {
|
|
703
|
+
const prefix = k.token_prefix || k.token_preview || 'tr_...'
|
|
704
|
+
const isRevoked = k.revoked
|
|
705
|
+
return (
|
|
706
|
+
<tr key={k.id} style={{ borderBottom: '1px solid var(--border)', opacity: isRevoked ? 0.5 : 1 }}>
|
|
707
|
+
<td style={{ padding: '10px 14px', fontWeight: 500 }}>
|
|
708
|
+
{k.name}
|
|
709
|
+
</td>
|
|
710
|
+
<td style={{ padding: '10px 14px', fontFamily: 'monospace', color: 'var(--text-secondary)' }}>
|
|
711
|
+
{prefix}...
|
|
712
|
+
</td>
|
|
713
|
+
<td style={{ padding: '10px 14px', color: 'var(--text-tertiary)', fontSize: 12 }}>
|
|
714
|
+
{Array.isArray(k.scopes) ? k.scopes.join(', ') : '*'}
|
|
715
|
+
</td>
|
|
716
|
+
<td style={{ padding: '10px 14px', color: 'var(--text-tertiary)', fontSize: 12 }}>
|
|
717
|
+
{k.created_at ? new Date(k.created_at).toLocaleDateString() : '—'}
|
|
718
|
+
</td>
|
|
719
|
+
<td style={{ padding: '10px 14px' }}>
|
|
720
|
+
<span style={{
|
|
721
|
+
display: 'inline-block',
|
|
722
|
+
padding: '2px 8px',
|
|
723
|
+
borderRadius: 4,
|
|
724
|
+
fontSize: 11,
|
|
725
|
+
fontWeight: 600,
|
|
726
|
+
background: isRevoked ? 'rgba(239, 68, 68, 0.1)' : 'rgba(16, 185, 129, 0.1)',
|
|
727
|
+
color: isRevoked ? '#f87171' : '#34d399',
|
|
728
|
+
border: isRevoked ? '1px solid rgba(239, 68, 68, 0.2)' : '1px solid rgba(16, 185, 129, 0.2)'
|
|
729
|
+
}}>
|
|
730
|
+
{isRevoked ? 'Revoked' : 'Active'}
|
|
731
|
+
</span>
|
|
732
|
+
</td>
|
|
733
|
+
<td style={{ padding: '10px 14px', textAlign: 'right' }}>
|
|
734
|
+
{!isRevoked && (
|
|
735
|
+
<button
|
|
736
|
+
className="btn btn-sm"
|
|
737
|
+
onClick={() => handleRevokeToken(k.id)}
|
|
738
|
+
disabled={revokingId === k.id}
|
|
739
|
+
style={{
|
|
740
|
+
background: 'rgba(239, 68, 68, 0.1)',
|
|
741
|
+
border: '1px solid rgba(239, 68, 68, 0.2)',
|
|
742
|
+
color: '#f87171',
|
|
743
|
+
cursor: 'pointer',
|
|
744
|
+
fontSize: 11,
|
|
745
|
+
padding: '4px 8px'
|
|
746
|
+
}}
|
|
747
|
+
>
|
|
748
|
+
{revokingId === k.id ? 'Revoking...' : 'Revoke'}
|
|
749
|
+
</button>
|
|
750
|
+
)}
|
|
751
|
+
</td>
|
|
752
|
+
</tr>
|
|
753
|
+
)
|
|
754
|
+
})}
|
|
755
|
+
</tbody>
|
|
756
|
+
</table>
|
|
757
|
+
</div>
|
|
758
|
+
</div>
|
|
452
759
|
</div>
|
|
453
760
|
)
|
|
454
761
|
}
|