total-recall-brain 3.45.0 → 3.46.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/total-recall.mjs +7 -2
- package/frontend/dist/assets/index-BRYE1jmv.css +1 -0
- package/frontend/dist/assets/index-D1goIPjC.js +5598 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/dist/sw.js +5 -4
- package/frontend/src/App.tsx +183 -236
- package/frontend/src/api/auth-inventory.ts +62 -0
- package/frontend/src/api/memory.ts +13 -8
- package/frontend/src/api/plugin-credentials.ts +23 -0
- package/frontend/src/api/plugins.ts +37 -53
- package/frontend/src/api/workspace-drawers.ts +97 -0
- package/frontend/src/components/BrainSelector.tsx +9 -3
- package/frontend/src/components/plugins/PluginPanel.tsx +83 -42
- package/frontend/src/components/plugins/PluginSettings.tsx +10 -20
- package/frontend/src/components/plugins/PluginWorkspace.tsx +367 -0
- package/frontend/src/components/plugins/ScopedPluginCommands.tsx +142 -0
- package/frontend/src/components/plugins/plugin-frame.ts +44 -33
- package/frontend/src/components/plugins/scoped-plugin-operations.ts +28 -0
- package/frontend/src/components/workspace/DrawerChat.tsx +110 -0
- package/frontend/src/components/workspace/DrawerLayout.tsx +196 -0
- package/frontend/src/components/workspace/DrawerMarkup.tsx +49 -0
- package/frontend/src/components/workspace/PluginChunkLibrary.tsx +92 -0
- package/frontend/src/components/workspace/PluginHome.tsx +76 -0
- package/frontend/src/components/workspace/WorkspaceDrawers.tsx +96 -0
- package/frontend/src/components/workspace/WorkspacePage.tsx +95 -0
- package/frontend/src/components/workspace/usePluginDesign.ts +38 -0
- package/frontend/src/index.css +409 -136
- package/frontend/src/pages/HelpPage.tsx +15 -46
- package/frontend/src/pages/MemoryPage.tsx +19 -36
- package/frontend/src/pages/SettingsPage.tsx +1 -1
- package/metadata.plugin.schema.json +53 -227
- package/package.json +1 -1
- package/scaffold/.agent/skills/plugin/SKILL.md +13 -11
- package/scaffold/.agent/skills/plugin/evals/README.md +14 -21
- package/scaffold/.agent/skills/plugin/evals/cases/01-fabricated-seed.mjs +15 -18
- package/scaffold/.agent/skills/plugin/evals/cases/02-reassuring-default.mjs +19 -24
- package/scaffold/.agent/skills/plugin/evals/cases/03-declared-template.mjs +12 -20
- package/scaffold/.agent/skills/plugin/evals/cases/04-home-collects-credential.mjs +35 -0
- package/scaffold/.agent/skills/plugin/evals/cases/05-host-leak-in-scaffold.mjs +8 -28
- package/scaffold/.agent/skills/plugin/evals/cases/06-correct-plugin.mjs +85 -47
- package/scaffold/.agent/skills/plugin/evals/run.mjs +17 -18
- package/scaffold/.agent/skills/plugin/prompts/05-credentials.md +4 -4
- package/scaffold/.agent/skills/plugin/prompts/07-scaffold.md +2 -2
- package/scaffold/.agent/skills/plugin/prompts/08-verify.md +4 -4
- package/scaffold/.agent/skills/plugin/references/anti-patterns.md +2 -2
- package/scaffold/.agent/skills/plugin/references/generative-home.md +38 -0
- package/scaffold/.agent/skills/plugin/references/scaffold.md +5 -5
- package/scaffold/.agent/skills/plugin/references/surfaces.md +13 -4
- package/scaffold/.agent/skills/plugin/scripts/record.mjs +75 -153
- package/scaffold/.agent/skills/plugin/subagents/plugin-reviewer.md +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/auth/DESIGN.md +76 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/README.md +3 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/cli.mjs +20 -15
- package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +13 -51
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/access-overview.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/agent-login.md +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/baseline-audit.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/credential-repository-binding.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/credential-store-maintenance.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/dashboard-password.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/dashboard-sessions.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/endpoint-probe.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/google-sign-in.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/mesh-machines.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/passkey-enrollment.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/registered-brains.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/scoped-access-keys.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/secret-inventory.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/chunks/signing-key-rotation.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/home.js +375 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/{ui/DESIGN.md → DESIGN.md} +32 -21
- package/scaffold/.agent/skills/total-recall/plugins/automations/adapters.mjs +17 -1
- package/scaffold/.agent/skills/total-recall/plugins/automations/cli.mjs +10 -1
- package/scaffold/.agent/skills/total-recall/plugins/automations/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/automations/package.json +4 -3
- package/scaffold/.agent/skills/total-recall/plugins/automations/plugin.json +11 -27
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/automations.js +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/control-ledger.md +42 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/local-inventory-triage.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/pending-control.md +39 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/run-evidence.md +41 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/schedule-vs-run-evidence.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/source-coverage.md +41 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/{card.js → home.js} +32 -27
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/DESIGN.md +53 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/cli.mjs +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/commands/run-core.mjs +4 -2
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/check.mjs +4 -2
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +40 -40
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/config.md +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/detect.md +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/gate.md +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/init.md +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/report.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/run.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/chunks/snapshot.md +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/code-quality-report.mjs +55 -23
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/home.mjs +214 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/DESIGN.md +146 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +51 -34
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/src/command.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/create.md +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/history.md +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/library.md +49 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/list.md +42 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/promote.md +40 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/read.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/remove.md +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/rollback.md +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/show.md +53 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/status.md +40 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/test-path.md +38 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/test.md +46 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/chunks/update.md +32 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/home.js +533 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/DESIGN.md +110 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +13 -10
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/benchmark.md +49 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/coverage.md +53 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/models.md +43 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/pull.md +41 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/chunks/status.md +59 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/home.js +353 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/DESIGN.md +31 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/README.md +25 -1
- package/scaffold/.agent/skills/total-recall/plugins/git/cli.mjs +5 -1
- package/scaffold/.agent/skills/total-recall/plugins/git/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/git/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/git/plugin.json +17 -27
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/commit-memory.mjs +30 -6
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/fleet.mjs +24 -6
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/secret-firewall.mjs +33 -7
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/undo.mjs +29 -5
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/unmerged.mjs +182 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/change-comparison.md +27 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/commit-identity.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/create-worktree.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/registered-worktrees.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/remove-worktree.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/repository-ledger.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/unmerged-work.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/upstream-divergence.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/worktree-conflict-triage.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/worktree-terminal.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/home.js +273 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/DESIGN.md +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/README.md +4 -5
- package/scaffold/.agent/skills/total-recall/plugins/mesh/cli.mjs +9 -3
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +37 -39
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +5 -3
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/active-device-dispatch.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/control-probe.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/control-server.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/credential-readiness.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/elected-leader.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/enrollment-key.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/file-receipt.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/fleet-execution.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/fleet-presence.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/interactive-ssh.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/local-enrollment.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/mesh-policy.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/network-atlas.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/node-roster.md +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/node-selection-proof.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/owner-observations.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/peer-path.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/pinned-leader.md +24 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/reachability-evidence-ladder.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/recorded-login.md +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/remote-execution.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/chunks/secret-grants.md +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/{card.js → home.js} +93 -22
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/DESIGN.md +86 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +19 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +5 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +43 -22
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/chat.mjs +80 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/adapter-docs-freshness.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/chat-handoff.md +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/fleet-maintenance.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/harness-inventory.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/included-access.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/included-usage-verification.md +15 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/independent-review.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/managed-execution.md +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/official-documentation.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/quota-recovery.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/review-routing-decision.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/route-work.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/routing-evidence.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/run-ledger.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/home.js +198 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/DESIGN.md +75 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/README.md +2 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +17 -14
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +10 -44
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +5 -4
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +3 -4
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/ingest.mjs +23 -18
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +8 -3
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +6 -3
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +3 -5
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/token.mjs +21 -47
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +17 -6
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/auto-refresh.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/bootstrap-pages.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/generate-wiki.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/generator-settings.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/host-probe.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/ingest-preview.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/link-hygiene.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/link-topology.md +19 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/passage-search.md +19 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/propagation-plan.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/provider-credentials.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/refresh-report.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/task-evidence.md +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/upstream-record.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/watch-upstream.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/chunks/wiki-atlas.md +19 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/panel.js +261 -513
- package/scaffold/.agent/skills/total-recall/plugins/security/DESIGN.md +84 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/README.md +4 -2
- package/scaffold/.agent/skills/total-recall/plugins/security/cli.mjs +7 -19
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +2 -3
- package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +19 -52
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/device-evidence.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/evidence-desk.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/guided-device-review.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/host-and-network.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/https-headers.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/mesh-coverage.md +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/private-security-tools.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/single-origin-header-check.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/source-review.md +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/chunks/ssh-permission-plan.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/home.js +283 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/DESIGN.md +93 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/package-lock.json +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/ssss/package.json +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/ssss/plugin.json +5 -3
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/conformance.md +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/registry.md +37 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/repair.md +42 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/scaffold.md +33 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/status.md +43 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/validate.md +34 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/validation-diagnostics.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/chunks/workspace-registry-preflight.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/home.js +348 -0
- package/scaffold/.agent/skills/total-recall/references/operations.md +2 -0
- package/src/cli/api.mjs +3 -3
- package/src/cli/brief.mjs +3 -0
- package/src/cli/config.mjs +16 -0
- package/src/cli/connect.mjs +2 -7
- package/src/cli/plugin/chunks.mjs +145 -0
- package/src/cli/plugin/create.mjs +24 -52
- package/src/cli/plugin/index.mjs +20 -9
- package/src/cli/setup.mjs +2 -9
- package/src/cli/start.mjs +1 -0
- package/src/cli/startup.mjs +18 -0
- package/src/core/app-deploy/design-tokens.mjs +14 -9
- package/src/core/app-deploy/ui-elements.mjs +1 -1
- package/src/core/brain-registry.mjs +5 -0
- package/src/core/brain-updates.mjs +5 -1
- package/src/core/daemon-control.mjs +5 -1
- package/src/core/dashboard-bundle.mjs +261 -0
- package/src/core/default-plugin-refresh.mjs +39 -0
- package/src/core/ensure-dependencies.mjs +19 -15
- package/src/core/memory-brain.mjs +30 -8
- package/src/core/plugin-activation.mjs +63 -20
- package/src/core/plugin-contracts/{card.mjs → manifest.mjs} +23 -57
- package/src/core/plugin-contracts/startup-check.mjs +49 -0
- package/src/core/plugin-contracts/ui.mjs +9 -3
- package/src/core/plugin-distribution.mjs +6 -6
- package/src/core/plugin-lifecycle.mjs +58 -0
- package/src/core/plugin-loader.mjs +9 -5
- package/src/core/plugin-runner.mjs +21 -10
- package/src/core/plugin-startup-checks.mjs +44 -0
- package/src/core/plugin-state.mjs +19 -5
- package/src/core/plugin-store.mjs +30 -11
- package/src/core/project-id.mjs +15 -5
- package/src/core/required-plugins.mjs +31 -6
- package/src/core/schema.mjs +2 -0
- package/src/core/ssss-operation-service.mjs +1 -0
- package/src/core/startup-health.mjs +28 -3
- package/src/core/testing/plugin-fixture.mjs +22 -21
- package/src/core/throttled-fetch.mjs +25 -18
- package/src/core/ui-chunk-choice.mjs +77 -0
- package/src/core/ui-chunk.registry.json +23 -0
- package/src/core/ui-chunks.mjs +434 -0
- package/src/core/vault-cache.mjs +58 -59
- package/src/core/workspace-compositions.mjs +151 -0
- package/src/core/workspace-drawers.mjs +79 -0
- package/src/server/api.mjs +4 -27
- package/src/server/index.mjs +28 -21
- package/src/server/memory-events.mjs +31 -0
- package/src/server/plugin-brain-targets.mjs +89 -0
- package/src/server/rest.mjs +2 -0
- package/src/server/route-inventory.mjs +3 -2
- package/src/server/route-manifest.json +52 -4
- package/src/server/routes/_shared.mjs +7 -14
- package/src/server/routes/brains.mjs +29 -44
- package/src/server/routes/dashboard.mjs +26 -0
- package/src/server/routes/plugins.mjs +154 -45
- package/src/server/routes/ui-chunks.mjs +192 -0
- package/frontend/dist/assets/index-DACh1dhx.js +0 -5613
- package/frontend/dist/assets/index-DtwsDyFM.css +0 -1
- package/frontend/src/components/plugins/card/CardEngine.tsx +0 -108
- package/frontend/src/components/plugins/card/CardScenes.tsx +0 -103
- package/frontend/src/components/plugins/card/ExecutionPicker.tsx +0 -64
- package/frontend/src/components/plugins/card/args.ts +0 -28
- package/frontend/src/components/plugins/card/card.css +0 -32
- package/frontend/src/components/plugins/card/cli-line.ts +0 -13
- package/frontend/src/components/plugins/card/contract.ts +0 -91
- package/frontend/src/components/plugins/card/format.ts +0 -49
- package/frontend/src/components/plugins/card/runner-context.ts +0 -11
- package/frontend/src/components/plugins/card/runner.tsx +0 -43
- package/frontend/src/components/plugins/card/theme.ts +0 -35
- package/frontend/src/components/plugins/card/use-source.ts +0 -22
- package/frontend/src/components/plugins/card/widgets.tsx +0 -94
- package/frontend/src/components/plugins/workspace/WorkspaceHost.tsx +0 -23
- package/frontend/src/pages/PluginsPage.tsx +0 -1719
- package/scaffold/.agent/skills/plugin/evals/cases/04-card-collects-credential.mjs +0 -47
- package/scaffold/.agent/skills/plugin/prompts/06-card.md +0 -46
- package/scaffold/.agent/skills/plugin/references/card.md +0 -90
- package/scaffold/.agent/skills/plugin/subagents/card-designer.md +0 -60
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/DESIGN.md +0 -67
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/card.js +0 -1179
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/DESIGN.md +0 -32
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +0 -588
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +0 -575
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/DESIGN.md +0 -32
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +0 -482
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/DESIGN.md +0 -100
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/card.js +0 -637
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/DESIGN.md +0 -217
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +0 -32
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +0 -1276
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +0 -45
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +0 -1401
- package/scaffold/.agent/skills/total-recall/plugins/security/scripts/build-ui.mjs +0 -4
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/DESIGN.md +0 -41
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +0 -396
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/panel.js +0 -98
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/DESIGN.md +0 -15
- package/scaffold/.agent/skills/total-recall/plugins/ssss/ui/card.js +0 -182
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-D1goIPjC.js"></script>
|
|
21
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BRYE1jmv.css">
|
|
22
22
|
</head>
|
|
23
23
|
<body>
|
|
24
24
|
<div id="root"></div>
|
package/frontend/dist/sw.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Caching strategies:
|
|
5
5
|
* • App shell: Pre-cached on install
|
|
6
|
-
* • /api/* GETs: Stale-While-Revalidate
|
|
6
|
+
* • /api/* GETs: Stale-While-Revalidate except live brain, plugin and chunk reads
|
|
7
7
|
* • /api/memory writes (POST/PUT/PATCH/DELETE): Network-first + offline queue with Background Sync
|
|
8
8
|
* • Static assets: Cache-first
|
|
9
9
|
* • Everything else: Network-first
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
const CACHE_NAME = 'total-recall-v1';
|
|
18
|
-
const API_CACHE = 'total-recall-api-
|
|
18
|
+
const API_CACHE = 'total-recall-api-v3';
|
|
19
19
|
|
|
20
20
|
// Pre-cache app shell
|
|
21
21
|
const PRECACHE_URLS = [
|
|
@@ -59,8 +59,9 @@ self.addEventListener('fetch', (event) => {
|
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
//
|
|
63
|
-
if (url.pathname.startsWith('/v1/')
|
|
62
|
+
// Registry, owner modules and composed views use the current authenticated state.
|
|
63
|
+
if (event.request.cache === 'no-store' || url.pathname.startsWith('/v1/') ||
|
|
64
|
+
/^\/api\/(?:brains|plugins|ui-chunks)(?:\/|$)/.test(url.pathname)) {
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
66
67
|
|
package/frontend/src/App.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react'
|
|
2
|
-
import { BrowserRouter, Routes, Route, NavLink, Navigate, useLocation } from 'react-router-dom'
|
|
1
|
+
import { useState, useEffect, useRef, useCallback, type ReactNode } from 'react'
|
|
2
|
+
import { BrowserRouter, Routes, Route, NavLink, Navigate, useLocation, useSearchParams } from 'react-router-dom'
|
|
3
3
|
import './App.css'
|
|
4
4
|
import { getApiBase, setApiBase, checkSession, logout, registerUnauthedCallback, fetchHealth } from './api'
|
|
5
5
|
import type { HealthData } from './types'
|
|
@@ -10,14 +10,14 @@ import NetworkPage from './pages/NetworkPage'
|
|
|
10
10
|
import { WebhooksPage } from './pages/WebhooksPage'
|
|
11
11
|
import BrainSelector from './components/BrainSelector'
|
|
12
12
|
import RulesPage from './pages/RulesPage'
|
|
13
|
-
import HelpPage from './pages/HelpPage'
|
|
14
13
|
import GraphPage from './pages/GraphPage'
|
|
15
|
-
import
|
|
14
|
+
import PluginWorkspace from './components/plugins/PluginWorkspace'
|
|
16
15
|
import OnboardingPage from './pages/OnboardingPage'
|
|
17
16
|
import { NotificationsPage } from './pages/NotificationsPage'
|
|
18
17
|
import { isOnboardingComplete } from './utils/onboarding'
|
|
19
18
|
import BrandMark from './components/brand/BrandMark'
|
|
20
|
-
import
|
|
19
|
+
import { WorkspaceDrawers, type WorkspaceEdge } from './components/workspace/WorkspaceDrawers'
|
|
20
|
+
import { SavedPages, WorkspacePage } from './components/workspace/WorkspacePage'
|
|
21
21
|
|
|
22
22
|
// ─── Auth state type ──────────────────────────────────────────────────────────
|
|
23
23
|
type AuthState = 'loading' | 'authed' | 'unauthed'
|
|
@@ -71,232 +71,92 @@ function networkGateTone(gate: HealthData['fetch_gate'] | undefined): {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
interface SidebarProps {
|
|
74
|
-
onLogout: () => void
|
|
75
|
-
health: HealthData | null
|
|
76
74
|
activeBrainId: string
|
|
77
75
|
onBrainChange: (id: string) => void
|
|
76
|
+
open: boolean
|
|
77
|
+
onClose: () => void
|
|
78
|
+
onActivity: () => void
|
|
79
|
+
pluginFolder: ReactNode
|
|
80
|
+
savedPagesFolder: ReactNode
|
|
78
81
|
}
|
|
79
82
|
|
|
80
|
-
const getNavLinkClass = ({ isActive }: { isActive: boolean }) => `nav-link ${isActive ? 'active' : ''}
|
|
83
|
+
const getNavLinkClass = ({ isActive }: { isActive: boolean }) => `nav-link ${isActive ? 'active' : ''}`
|
|
81
84
|
|
|
82
|
-
function Sidebar({
|
|
85
|
+
function Sidebar({ activeBrainId, onBrainChange, open, onClose, onActivity, pluginFolder, savedPagesFolder }: SidebarProps) {
|
|
83
86
|
return (
|
|
84
|
-
<aside className="sidebar"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
<span style={{ fontSize: 11, color: 'var(--text-tertiary)', letterSpacing: '0.01em' }}>Portable memory · any IDE</span>
|
|
93
|
-
</div>
|
|
87
|
+
<aside className={`sidebar ${open ? 'open' : ''}`} id="workspace-sidebar" inert={!open}
|
|
88
|
+
onPointerMove={onActivity} onPointerDown={onActivity} onFocus={onActivity} onKeyDown={event => {
|
|
89
|
+
if (event.key === 'Escape') onClose()
|
|
90
|
+
else onActivity()
|
|
91
|
+
}}>
|
|
92
|
+
<div className="sidebar-brains">
|
|
93
|
+
<div className="nav-section-label">Brains</div>
|
|
94
|
+
<BrainSelector activeBrainId={activeBrainId} onBrainChange={onBrainChange} onSelectionComplete={onClose} />
|
|
94
95
|
</div>
|
|
95
|
-
<nav className="sidebar-nav">
|
|
96
|
-
|
|
97
|
-
{
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
</NavLink>
|
|
104
|
-
|
|
105
|
-
<NavLink to="/memory" className={getNavLinkClass} id="nav-memory">
|
|
106
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
107
|
-
<circle cx="12" cy="12" r="10" /><path d="M12 16v-4M12 8h.01" />
|
|
108
|
-
</svg>
|
|
109
|
-
Vault
|
|
110
|
-
</NavLink>
|
|
111
|
-
<NavLink to="/rules" className={getNavLinkClass} id="nav-rules">
|
|
112
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
113
|
-
<path d="M14 2H6a2 2 0 0 0-2 2v16c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V8l-6-6z" />
|
|
114
|
-
<path d="M14 3v5h5M16 13H8M16 17H8M10 9H8" />
|
|
115
|
-
</svg>
|
|
116
|
-
Rules
|
|
117
|
-
</NavLink>
|
|
118
|
-
<NavLink to="/graph" className={getNavLinkClass} id="nav-graph">
|
|
119
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
120
|
-
<circle cx="5" cy="6" r="2" /><circle cx="19" cy="6" r="2" /><circle cx="12" cy="18" r="2" />
|
|
121
|
-
<path d="M7 7l4 9M17 7l-4 9" />
|
|
122
|
-
</svg>
|
|
123
|
-
Graph
|
|
124
|
-
</NavLink>
|
|
125
|
-
|
|
126
|
-
<div className="nav-section-label">Capabilities</div>
|
|
127
|
-
<NavLink to="/plugins" className={getNavLinkClass} id="nav-plugins">
|
|
128
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
129
|
-
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
|
|
130
|
-
<polyline points="3.27 6.96 12 12.01 20.73 6.96" />
|
|
131
|
-
<line x1="12" y1="22.08" x2="12" y2="12" />
|
|
132
|
-
</svg>
|
|
133
|
-
Plugins
|
|
134
|
-
</NavLink>
|
|
135
|
-
|
|
136
|
-
<div className="nav-section-label">Account</div>
|
|
137
|
-
<NavLink to="/network" className={getNavLinkClass} id="nav-network">
|
|
138
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
139
|
-
<rect x="2" y="2" width="20" height="8" rx="2" ry="2" />
|
|
140
|
-
<rect x="2" y="14" width="20" height="8" rx="2" ry="2" />
|
|
141
|
-
<line x1="6" y1="6" x2="6.01" y2="6" />
|
|
142
|
-
<line x1="6" y1="18" x2="6.01" y2="18" />
|
|
143
|
-
</svg>
|
|
144
|
-
Network
|
|
145
|
-
</NavLink>
|
|
146
|
-
<NavLink to="/mesh" className={getNavLinkClass} id="nav-mesh">
|
|
147
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
148
|
-
<path d="M12 2L2 7l10 5 10-5-10-5z" /><path d="M2 17l10 5 10-5" /><path d="M2 12l10 5 10-5" />
|
|
149
|
-
</svg>
|
|
150
|
-
Mesh
|
|
151
|
-
</NavLink>
|
|
152
|
-
<NavLink to="/webhooks" className={getNavLinkClass} id="nav-webhooks">
|
|
153
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
154
|
-
<path d="M22 12h-4l-3 9L9 3l-3 9H2" />
|
|
155
|
-
</svg>
|
|
156
|
-
Webhooks
|
|
157
|
-
</NavLink>
|
|
158
|
-
<NavLink to="/secrets" className={getNavLinkClass} id="nav-secrets">
|
|
159
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
160
|
-
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" /><path d="M7 11V7a5 5 0 0110 0v4" />
|
|
161
|
-
</svg>
|
|
162
|
-
Secrets & Keys
|
|
163
|
-
</NavLink>
|
|
164
|
-
<NavLink to="/notifications" className={getNavLinkClass} id="nav-notifications">
|
|
165
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
166
|
-
<path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9" /><path d="M13.73 21a2 2 0 01-3.46 0" />
|
|
167
|
-
</svg>
|
|
168
|
-
Notifications
|
|
169
|
-
</NavLink>
|
|
170
|
-
<NavLink to="/settings" className={getNavLinkClass} id="nav-settings">
|
|
171
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
172
|
-
<circle cx="12" cy="12" r="3" /><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z" />
|
|
173
|
-
</svg>
|
|
174
|
-
Settings
|
|
175
|
-
</NavLink>
|
|
176
|
-
<NavLink to="/help" className={getNavLinkClass} id="nav-help">
|
|
177
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
178
|
-
<circle cx="12" cy="12" r="10" />
|
|
179
|
-
<path d="M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3" />
|
|
180
|
-
<line x1="12" y1="17" x2="12.01" y2="17" />
|
|
181
|
-
</svg>
|
|
182
|
-
Help
|
|
183
|
-
</NavLink>
|
|
184
|
-
{isOnboardingComplete() && (
|
|
185
|
-
<NavLink to="/onboarding" className={getNavLinkClass} id="nav-onboarding-replay" style={{ opacity: 0.75 }}>
|
|
186
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
187
|
-
<path d="M12 2L2 7l10 5 10-5-10-5z" /><path d="M2 17l10 5 10-5" /><path d="M2 12l10 5 10-5" />
|
|
188
|
-
</svg>
|
|
189
|
-
Setup guide
|
|
190
|
-
</NavLink>
|
|
191
|
-
)}
|
|
96
|
+
<nav className="sidebar-nav" aria-label="Workspace">
|
|
97
|
+
{pluginFolder}
|
|
98
|
+
{savedPagesFolder}
|
|
99
|
+
<details className="sidebar-memory">
|
|
100
|
+
<summary className="nav-link">Memory</summary>
|
|
101
|
+
{!isOnboardingComplete() && <NavLink to="/onboarding" className={getNavLinkClass} id="nav-onboarding" onClick={onClose}>Setup</NavLink>}
|
|
102
|
+
<NavLink to="/memory" className={getNavLinkClass} id="nav-memory" onClick={onClose}>Vault</NavLink>
|
|
103
|
+
<NavLink to="/rules" className={getNavLinkClass} id="nav-rules" onClick={onClose}>Rules</NavLink>
|
|
104
|
+
<NavLink to="/graph" className={getNavLinkClass} id="nav-graph" onClick={onClose}>Graph</NavLink>
|
|
105
|
+
</details>
|
|
192
106
|
</nav>
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
107
|
+
</aside>
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const ACCOUNT_LINKS = [
|
|
112
|
+
['network', 'Network'],
|
|
113
|
+
['mesh', 'Mesh'],
|
|
114
|
+
['webhooks', 'Webhooks'],
|
|
115
|
+
['secrets', 'Secrets & Keys'],
|
|
116
|
+
['notifications', 'Notifications'],
|
|
117
|
+
['settings', 'Settings'],
|
|
118
|
+
] as const
|
|
119
|
+
|
|
120
|
+
function AccountMenu({ health, onLogout }: { health: HealthData | null; onLogout: () => void }) {
|
|
121
|
+
const menu = useRef<HTMLDetailsElement>(null)
|
|
122
|
+
const trigger = useRef<HTMLElement>(null)
|
|
123
|
+
const gate = networkGateTone(health?.fetch_gate)
|
|
124
|
+
const serverOk = health?.status !== 'unreachable'
|
|
125
|
+
const daemonOk = health?.daemon === 'running'
|
|
126
|
+
|
|
127
|
+
function close() {
|
|
128
|
+
if (menu.current) menu.current.open = false
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return <details className="account-menu" ref={menu} onKeyDown={event => {
|
|
132
|
+
if (event.key === 'Escape') { close(); trigger.current?.focus() }
|
|
133
|
+
}}>
|
|
134
|
+
<summary className="btn btn-ghost btn-sm" ref={trigger}>Account</summary>
|
|
135
|
+
<nav className="account-menu-body" aria-label="Account">
|
|
136
|
+
{ACCOUNT_LINKS.map(([path, label]) => <NavLink key={path} to={`/${path}`} className={getNavLinkClass}
|
|
137
|
+
id={`nav-${path}`} onClick={close}>{label}</NavLink>)}
|
|
138
|
+
<NavLink to="/onboarding" className={getNavLinkClass} id="nav-onboarding-replay" onClick={close}>Setup guide</NavLink>
|
|
139
|
+
<label className="account-menu-host">API host
|
|
140
|
+
<select className="select" value={getApiBase()} onChange={event => setApiBase(event.target.value)}>
|
|
213
141
|
<option value="">Local API</option>
|
|
214
|
-
{import.meta.env.VITE_BRAIN_URL &&
|
|
215
|
-
|
|
216
|
-
|
|
142
|
+
{import.meta.env.VITE_BRAIN_URL && <option value={import.meta.env.VITE_BRAIN_URL}>
|
|
143
|
+
{new URL(import.meta.env.VITE_BRAIN_URL).host}
|
|
144
|
+
</option>}
|
|
217
145
|
</select>
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
return (
|
|
229
|
-
<>
|
|
230
|
-
<style>{`@keyframes blink { 0%,100%{opacity:1;} 50%{opacity:0.3;} }`}</style>
|
|
231
|
-
{allGood ? (
|
|
232
|
-
<div style={{ display: 'flex', alignItems: 'center', gap: 5, color: 'var(--text-tertiary)' }}>
|
|
233
|
-
<span className="pulse" /> All Systems Go
|
|
234
|
-
</div>
|
|
235
|
-
) : (
|
|
236
|
-
<>
|
|
237
|
-
<StatusDot ok={!!serverOk} label={serverOk ? 'Server online' : 'Server offline'} />
|
|
238
|
-
<StatusDot ok={daemonOk} label={daemonOk ? 'Daemon' : 'Daemon ' + (health?.daemon ?? 'unknown')} />
|
|
239
|
-
</>
|
|
240
|
-
)}
|
|
241
|
-
<div
|
|
242
|
-
data-testid="network-gate-indicator"
|
|
243
|
-
title={gate.title}
|
|
244
|
-
style={{ display: 'flex', alignItems: 'center', gap: 5, color: 'var(--text-tertiary)' }}
|
|
245
|
-
>
|
|
246
|
-
<span
|
|
247
|
-
style={{
|
|
248
|
-
width: 7,
|
|
249
|
-
height: 7,
|
|
250
|
-
borderRadius: '50%',
|
|
251
|
-
background: gate.color,
|
|
252
|
-
boxShadow: `0 0 6px ${gate.color}80`,
|
|
253
|
-
display: 'inline-block',
|
|
254
|
-
}}
|
|
255
|
-
/>
|
|
256
|
-
<NavLink
|
|
257
|
-
to="/network"
|
|
258
|
-
style={{ color: 'inherit', textDecoration: 'none', fontSize: 11 }}
|
|
259
|
-
title={gate.title}
|
|
260
|
-
>
|
|
261
|
-
{gate.label}
|
|
262
|
-
</NavLink>
|
|
263
|
-
</div>
|
|
264
|
-
</>
|
|
265
|
-
)
|
|
266
|
-
})()}
|
|
267
|
-
</div>
|
|
268
|
-
{/* Logout button */}
|
|
269
|
-
<button
|
|
270
|
-
id="btn-logout"
|
|
271
|
-
onClick={onLogout}
|
|
272
|
-
title="Sign out"
|
|
273
|
-
style={{
|
|
274
|
-
background: 'none',
|
|
275
|
-
border: '1px solid var(--border)',
|
|
276
|
-
borderRadius: 6,
|
|
277
|
-
cursor: 'pointer',
|
|
278
|
-
color: 'var(--text-tertiary)',
|
|
279
|
-
display: 'flex',
|
|
280
|
-
alignItems: 'center',
|
|
281
|
-
gap: 5,
|
|
282
|
-
padding: '4px 8px',
|
|
283
|
-
fontSize: 11,
|
|
284
|
-
transition: 'color 0.15s, border-color 0.15s',
|
|
285
|
-
}}
|
|
286
|
-
onMouseEnter={e => { (e.currentTarget as HTMLElement).style.color = '#ef4444'; (e.currentTarget as HTMLElement).style.borderColor = '#ef4444' }}
|
|
287
|
-
onMouseLeave={e => { (e.currentTarget as HTMLElement).style.color = 'var(--text-tertiary)'; (e.currentTarget as HTMLElement).style.borderColor = 'var(--border)' }}
|
|
288
|
-
>
|
|
289
|
-
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
290
|
-
<path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/>
|
|
291
|
-
<polyline points="16 17 21 12 16 7"/>
|
|
292
|
-
<line x1="21" y1="12" x2="9" y2="12"/>
|
|
293
|
-
</svg>
|
|
294
|
-
Sign out
|
|
295
|
-
</button>
|
|
296
|
-
</div>
|
|
146
|
+
</label>
|
|
147
|
+
<div className="account-menu-health">
|
|
148
|
+
{health ? <>
|
|
149
|
+
{health.version && <span>v{health.version}</span>}
|
|
150
|
+
<StatusDot ok={serverOk} label={serverOk ? 'Server online' : 'Server offline'} />
|
|
151
|
+
<StatusDot ok={daemonOk} label={daemonOk ? 'Daemon running' : `Daemon ${health.daemon ?? 'unknown'}`} />
|
|
152
|
+
<NavLink to="/network" title={gate.title} data-testid="network-gate-indicator" onClick={close}>
|
|
153
|
+
<span aria-hidden="true" style={{ color: gate.color }}>● </span>{gate.label}
|
|
154
|
+
</NavLink>
|
|
155
|
+
</> : <span>Checking status…</span>}
|
|
297
156
|
</div>
|
|
298
|
-
|
|
299
|
-
|
|
157
|
+
<button type="button" className="btn btn-ghost btn-sm" id="btn-logout" onClick={onLogout}>Sign out</button>
|
|
158
|
+
</nav>
|
|
159
|
+
</details>
|
|
300
160
|
}
|
|
301
161
|
|
|
302
162
|
// ─── Main content (routes) ────────────────────────────────────────────────────
|
|
@@ -304,13 +164,20 @@ function Sidebar({ onLogout, health, activeBrainId, onBrainChange }: SidebarProp
|
|
|
304
164
|
function OnboardingRedirect() {
|
|
305
165
|
const location = useLocation()
|
|
306
166
|
// First visit: force guided onboarding until complete (local flag or vault profile)
|
|
307
|
-
if (!isOnboardingComplete() &&
|
|
167
|
+
if (!isOnboardingComplete() && !['/onboarding', '/plugins', '/help'].includes(location.pathname)) {
|
|
308
168
|
return <Navigate to="/onboarding" replace />
|
|
309
169
|
}
|
|
310
170
|
|
|
311
171
|
return null
|
|
312
172
|
}
|
|
313
173
|
|
|
174
|
+
function LegacyPluginsRoute() {
|
|
175
|
+
const [params] = useSearchParams()
|
|
176
|
+
const id = params.get('id') || params.get('plugin')
|
|
177
|
+
const selection = new URLSearchParams(id ? { plugin: id } : { plugins: 'open' })
|
|
178
|
+
return <Navigate to={{ pathname: isOnboardingComplete() ? '/memory' : '/onboarding', search: `?${selection}` }} replace />
|
|
179
|
+
}
|
|
180
|
+
|
|
314
181
|
function MainContent({ activeBrainId }: { activeBrainId: string }) {
|
|
315
182
|
return (
|
|
316
183
|
<main className="main-content" style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden', position: 'relative' }}>
|
|
@@ -326,16 +193,16 @@ function MainContent({ activeBrainId }: { activeBrainId: string }) {
|
|
|
326
193
|
<Route path="/tasks" element={<Navigate to="/plugins?id=automations" replace />} />
|
|
327
194
|
<Route path="/skills" element={<Navigate to="/plugins?id=skill-manager" replace />} />
|
|
328
195
|
<Route path="/openwiki" element={<Navigate to="/plugins?id=openwiki" replace />} />
|
|
329
|
-
<Route path="/plugins" element={<
|
|
196
|
+
<Route path="/plugins" element={<LegacyPluginsRoute />} />
|
|
330
197
|
<Route path="/integrations" element={<Navigate to="/plugins?id=meta-harness" replace />} />
|
|
331
198
|
<Route path="/keys" element={<Navigate to="/secrets" replace />} />
|
|
332
199
|
<Route path="/settings" element={<SettingsPage activeBrainId={activeBrainId} />} />
|
|
333
200
|
<Route path="/network" element={<NetworkPage />} />
|
|
334
201
|
<Route path="/mesh" element={<Navigate to="/plugins?id=mesh" replace />} />
|
|
335
202
|
<Route path="/webhooks" element={<WebhooksPage />} />
|
|
336
|
-
<Route path="/secrets" element={<Navigate to="/
|
|
203
|
+
<Route path="/secrets" element={<Navigate to="/memory?brain=global&plugin=auth" replace />} />
|
|
337
204
|
<Route path="/notifications" element={<NotificationsPage />} />
|
|
338
|
-
<Route path="/help" element={<
|
|
205
|
+
<Route path="/help" element={<Navigate to={isOnboardingComplete() ? '/memory?drawer=help' : '/onboarding?drawer=help'} replace />} />
|
|
339
206
|
{/* Legacy OS-control-plane routes → core product */}
|
|
340
207
|
<Route path="/vault" element={<Navigate to="/memory" replace />} />
|
|
341
208
|
<Route path="/inbox" element={<Navigate to="/tasks" replace />} />
|
|
@@ -360,18 +227,51 @@ function MainContent({ activeBrainId }: { activeBrainId: string }) {
|
|
|
360
227
|
// ─── Root App with auth gate ──────────────────────────────────────────────────
|
|
361
228
|
|
|
362
229
|
const BRAIN_STORAGE_KEY = 'total-recall-active-brain'
|
|
230
|
+
const SIDEBAR_IDLE_MS = 5000
|
|
363
231
|
|
|
364
|
-
function
|
|
232
|
+
function Dashboard() {
|
|
233
|
+
const location = useLocation()
|
|
234
|
+
const [params, setParams] = useSearchParams()
|
|
235
|
+
const requestedEdge = new URLSearchParams(location.search).get('drawer') === 'help' ? 'right' : null
|
|
236
|
+
const [drawerEntry, setDrawerEntry] = useState<{ key: string; edge: WorkspaceEdge | null }>(
|
|
237
|
+
() => ({ key: location.key, edge: requestedEdge })
|
|
238
|
+
)
|
|
239
|
+
if (drawerEntry.key !== location.key) setDrawerEntry({ key: location.key, edge: requestedEdge })
|
|
240
|
+
const edge = drawerEntry.key === location.key ? drawerEntry.edge : requestedEdge
|
|
241
|
+
const setEdge = useCallback((edge: WorkspaceEdge | null) => {
|
|
242
|
+
setDrawerEntry({ key: location.key, edge })
|
|
243
|
+
}, [location.key])
|
|
365
244
|
const [authState, setAuthState] = useState<AuthState>('loading')
|
|
366
245
|
const [health, setHealth] = useState<HealthData | null>(null)
|
|
367
|
-
const
|
|
246
|
+
const sidebarOpen = edge === 'left'
|
|
247
|
+
const sidebarToggle = useRef<HTMLButtonElement>(null)
|
|
248
|
+
const sidebarTimer = useRef<number | undefined>(undefined)
|
|
249
|
+
const [storedBrainId, setStoredBrainId] = useState(
|
|
368
250
|
() => localStorage.getItem(BRAIN_STORAGE_KEY) || 'global'
|
|
369
251
|
)
|
|
252
|
+
const pageId = location.pathname === '/memory' ? params.get('page') : null
|
|
253
|
+
const linkedBrainId = (pageId || params.has('plugin')) ? params.get('brain') : null
|
|
254
|
+
const activeBrainId = linkedBrainId || storedBrainId
|
|
255
|
+
const pageBrainId = activeBrainId.includes(',') ? undefined : activeBrainId
|
|
256
|
+
function setActiveBrainId(id: string) {
|
|
257
|
+
setStoredBrainId(id)
|
|
258
|
+
if (pageId && id !== activeBrainId) {
|
|
259
|
+
const next = new URLSearchParams(params)
|
|
260
|
+
next.delete('page')
|
|
261
|
+
next.delete('brain')
|
|
262
|
+
next.delete('plugin')
|
|
263
|
+
setParams(next, { replace: true })
|
|
264
|
+
} else if (!pageId && linkedBrainId) {
|
|
265
|
+
const next = new URLSearchParams(params)
|
|
266
|
+
next.delete('brain')
|
|
267
|
+
setParams(next, { replace: true })
|
|
268
|
+
}
|
|
269
|
+
}
|
|
370
270
|
|
|
371
271
|
// Persist activeBrainId to localStorage on change
|
|
372
272
|
useEffect(() => {
|
|
373
|
-
localStorage.setItem(BRAIN_STORAGE_KEY,
|
|
374
|
-
}, [
|
|
273
|
+
localStorage.setItem(BRAIN_STORAGE_KEY, storedBrainId)
|
|
274
|
+
}, [storedBrainId])
|
|
375
275
|
|
|
376
276
|
// Register 401 interceptor so any API call that gets a 401 flips us to unauthed
|
|
377
277
|
useEffect(() => {
|
|
@@ -402,6 +302,7 @@ function App() {
|
|
|
402
302
|
|
|
403
303
|
async function handleLogout() {
|
|
404
304
|
await logout()
|
|
305
|
+
setEdge(null)
|
|
405
306
|
setAuthState('unauthed')
|
|
406
307
|
}
|
|
407
308
|
|
|
@@ -409,6 +310,27 @@ function App() {
|
|
|
409
310
|
setAuthState('authed')
|
|
410
311
|
}
|
|
411
312
|
|
|
313
|
+
const closeSidebar = useCallback(() => {
|
|
314
|
+
setEdge(null)
|
|
315
|
+
if (document.activeElement?.closest('#workspace-sidebar')) sidebarToggle.current?.focus()
|
|
316
|
+
}, [setEdge])
|
|
317
|
+
|
|
318
|
+
const closeDrawer = useCallback(() => {
|
|
319
|
+
if (edge === 'left') closeSidebar()
|
|
320
|
+
else setEdge(null)
|
|
321
|
+
}, [edge, closeSidebar, setEdge])
|
|
322
|
+
|
|
323
|
+
const queueSidebarClose = useCallback(() => {
|
|
324
|
+
window.clearTimeout(sidebarTimer.current)
|
|
325
|
+
sidebarTimer.current = window.setTimeout(closeSidebar, SIDEBAR_IDLE_MS)
|
|
326
|
+
}, [closeSidebar])
|
|
327
|
+
|
|
328
|
+
useEffect(() => {
|
|
329
|
+
if (!sidebarOpen) return
|
|
330
|
+
queueSidebarClose()
|
|
331
|
+
return () => window.clearTimeout(sidebarTimer.current)
|
|
332
|
+
}, [sidebarOpen, queueSidebarClose])
|
|
333
|
+
|
|
412
334
|
// Loading state — blank dark screen, no flash of unprotected content
|
|
413
335
|
if (authState === 'loading') {
|
|
414
336
|
return (
|
|
@@ -434,14 +356,39 @@ function App() {
|
|
|
434
356
|
|
|
435
357
|
// Authed — render full dashboard
|
|
436
358
|
return (
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
359
|
+
<PluginWorkspace activeBrainId={activeBrainId} onOpenPlugin={closeSidebar}
|
|
360
|
+
renderShell={(pluginFolder, pluginPage, plugins) => {
|
|
361
|
+
const page = pageId ? <WorkspacePage id={pageId} brainId={pageBrainId} plugins={plugins} /> : pluginPage
|
|
362
|
+
return <div className="app-layout">
|
|
363
|
+
<Sidebar activeBrainId={activeBrainId} onBrainChange={setActiveBrainId}
|
|
364
|
+
open={sidebarOpen} onClose={closeSidebar} onActivity={queueSidebarClose} pluginFolder={pluginFolder}
|
|
365
|
+
savedPagesFolder={<SavedPages brainId={pageBrainId} drawerOpen={sidebarOpen}
|
|
366
|
+
activePageId={pageId} onOpenPage={closeSidebar} />} />
|
|
367
|
+
{edge && <div className="sidebar-scrim" aria-hidden="true" onClick={closeDrawer} />}
|
|
368
|
+
<button type="button" className="sidebar-handle" ref={sidebarToggle} aria-label="Workspace navigation"
|
|
369
|
+
aria-controls="workspace-sidebar" aria-expanded={sidebarOpen} onClick={() => setEdge(sidebarOpen ? null : 'left')}
|
|
370
|
+
onKeyDown={event => { if (event.key === 'Escape' && sidebarOpen) closeSidebar() }}>
|
|
371
|
+
<svg width="14" height="18" viewBox="0 0 14 18" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden="true">
|
|
372
|
+
<path d={sidebarOpen ? 'M9 4 4 9l5 5' : 'm5 4 5 5-5 5'} />
|
|
373
|
+
</svg>
|
|
374
|
+
</button>
|
|
375
|
+
<div className="workspace-main" inert={edge !== null}>
|
|
376
|
+
<header className="workspace-toolbar" aria-label="Dashboard">
|
|
377
|
+
<BrandMark height={64} className="workspace-logo" />
|
|
378
|
+
<AccountMenu health={health} onLogout={handleLogout} />
|
|
379
|
+
</header>
|
|
380
|
+
<div className="workspace-body" hidden={!!page}>
|
|
381
|
+
<MainContent activeBrainId={activeBrainId} />
|
|
382
|
+
</div>
|
|
383
|
+
{page}
|
|
384
|
+
</div>
|
|
385
|
+
<WorkspaceDrawers edge={edge} onChange={setEdge} plugins={plugins} activeBrainId={activeBrainId} />
|
|
386
|
+
</div>
|
|
387
|
+
}}
|
|
388
|
+
/>
|
|
444
389
|
)
|
|
445
390
|
}
|
|
446
391
|
|
|
447
|
-
export default App
|
|
392
|
+
export default function App() {
|
|
393
|
+
return <BrowserRouter><Dashboard /></BrowserRouter>
|
|
394
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { apiFetch, getApiBase } from './_base'
|
|
2
|
+
|
|
3
|
+
const inventory = {
|
|
4
|
+
secrets: { path: '/api/plugins/auth/secrets?catalog=0', list: 'keys', fields: [
|
|
5
|
+
'key', 'label', 'set', 'provider_name', 'repos', 'next_rotate_due', 'rotation_overdue', 'updated_at',
|
|
6
|
+
] },
|
|
7
|
+
brains: { path: '/api/brains', list: 'brains', fields: ['id', 'name', 'layer', 'exists', 'node_count'] },
|
|
8
|
+
machines: { path: '/api/mesh/nodes', list: 'nodes', fields: ['hostname', 'online', 'self', 'os', 'role', 'vault_only'] },
|
|
9
|
+
} as const
|
|
10
|
+
|
|
11
|
+
export async function readAuthInventory(resource: unknown, signal: AbortSignal) {
|
|
12
|
+
if (typeof resource !== 'string' || !Object.hasOwn(inventory, resource)) throw new Error('Unknown Auth inventory')
|
|
13
|
+
const { path, list, fields } = inventory[resource as keyof typeof inventory]
|
|
14
|
+
const response = await apiFetch(getApiBase() + path, { cache: 'no-store', signal })
|
|
15
|
+
if (!response.ok) throw new Error(`Inventory request returned HTTP ${response.status}`)
|
|
16
|
+
const result = await response.json()
|
|
17
|
+
const rows = Array.isArray(result) && resource === 'secrets' ? result : result?.[list]
|
|
18
|
+
if (!Array.isArray(rows) || rows.some(row => !row || typeof row !== 'object' || Array.isArray(row))) {
|
|
19
|
+
throw new Error('Inventory response was incomplete')
|
|
20
|
+
}
|
|
21
|
+
return rows.map(row => Object.fromEntries(fields.flatMap(key => Object.hasOwn(row, key) ? [[key, row[key]]] : [])))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function changeAuthCredential(payload: unknown, signal: AbortSignal) {
|
|
25
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) throw new Error('Choose a credential action.')
|
|
26
|
+
const change = payload as Record<string, unknown>
|
|
27
|
+
const key = change.key
|
|
28
|
+
if (typeof key !== 'string' || !key.trim() || key.length > 256 || /[\x00-\x1f\x7f/\\]/.test(key) || key === '.' || key === '..') {
|
|
29
|
+
throw new Error('Select a valid credential.')
|
|
30
|
+
}
|
|
31
|
+
const path = getApiBase() + '/api/plugins/auth/secrets/' + encodeURIComponent(key)
|
|
32
|
+
const action = change.action
|
|
33
|
+
let response: Response
|
|
34
|
+
if (action === 'edit') {
|
|
35
|
+
const { label, repo } = change
|
|
36
|
+
if (typeof label !== 'string' || label.length > 120 ||
|
|
37
|
+
(repo !== undefined && (typeof repo !== 'string' || repo.length > 256 || /[\x00-\x1f\x7f,]/.test(repo)))) {
|
|
38
|
+
throw new Error('Enter a valid label and one repository binding.')
|
|
39
|
+
}
|
|
40
|
+
response = await apiFetch(path, {
|
|
41
|
+
method: 'PATCH', signal, headers: { 'Content-Type': 'application/json' },
|
|
42
|
+
body: JSON.stringify({ label: label.trim() || null, ...(typeof repo === 'string'
|
|
43
|
+
? { repos: repo.trim() ? [repo.trim()] : [] } : {}) }),
|
|
44
|
+
})
|
|
45
|
+
} else if (action === 'replace') {
|
|
46
|
+
const value = change.value
|
|
47
|
+
if (typeof value !== 'string' || !value.trim() || value.length > 16384) throw new Error('Enter the replacement value.')
|
|
48
|
+
response = await apiFetch(path + '/rotate', {
|
|
49
|
+
method: 'POST', signal, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ value }),
|
|
50
|
+
})
|
|
51
|
+
} else if (action === 'delete' && change.confirm === key) {
|
|
52
|
+
response = await apiFetch(path, { method: 'DELETE', signal })
|
|
53
|
+
} else {
|
|
54
|
+
throw new Error('Choose an action and confirm deletion if requested.')
|
|
55
|
+
}
|
|
56
|
+
if (!response.ok) throw new Error(`Auth returned HTTP ${response.status}.`)
|
|
57
|
+
const result = await response.json()
|
|
58
|
+
if (action === 'delete' ? result?.found !== true : result?.key !== key) {
|
|
59
|
+
throw new Error('Auth did not confirm the credential change.')
|
|
60
|
+
}
|
|
61
|
+
return { ok: true }
|
|
62
|
+
}
|