total-recall-brain 3.44.0 → 3.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/total-recall.mjs +10 -6
- package/docs/ARCHITECTURE.md +10 -7
- package/docs/reference/cli-reference.md +13 -8
- 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 +185 -238
- 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 +7 -7
- 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/src/cli-secret.mjs +20 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-store.mjs +12 -1
- 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/BRICK.md +7 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/DESIGN.md +53 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/LICENSE +21 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/README.md +66 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/adapters.mjs +247 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/capability/index.mjs +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/cli.mjs +130 -0
- package/{src/core/plugin-cron.mjs → scaffold/.agent/skills/total-recall/plugins/automations/cron.mjs} +1 -3
- package/scaffold/.agent/skills/total-recall/plugins/automations/inventory.mjs +88 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/package-lock.json +7661 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/package.json +36 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/plugin.json +151 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/scheduler.mjs +246 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/automations.js +2 -0
- 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/home.js +278 -0
- 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 +5 -3
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/check.mjs +61 -7
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/report-data.mjs +40 -14
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/report.mjs +15 -40
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +7 -7
- 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 +7 -7
- 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 +7 -7
- 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 +136 -0
- package/scaffold/.agent/skills/total-recall/plugins/{git-sentinel → git}/cli.mjs +140 -24
- package/scaffold/.agent/skills/total-recall/plugins/{git-sentinel → git}/package-lock.json +9 -9
- package/scaffold/.agent/skills/total-recall/plugins/{git-sentinel → git}/package.json +4 -2
- package/scaffold/.agent/skills/total-recall/plugins/git/plugin.json +151 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/lib/context.mjs +94 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/lib/phase3-spec-support.mjs +50 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/lib/runtime.mjs +40 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/lib/spec-support.mjs +51 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/_support.mjs +195 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/auth.mjs +201 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/bisect.mjs +40 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/cli-meta.mjs +159 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/commit-memory.mjs +54 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/commit.mjs +46 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/fleet.mjs +174 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/force-push.mjs +58 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/group.mjs +119 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/handoff.mjs +59 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/message.mjs +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/resolve.mjs +60 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/rules.mjs +81 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/secret-firewall.mjs +92 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/undo.mjs +156 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/unmerged.mjs +182 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/why.mjs +16 -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 +7 -7
- 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 +44 -9
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/BRICK.md +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +18 -6
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +128 -24
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +7 -7
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +188 -34
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +17 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/adoption.mjs +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +92 -18
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/chat.mjs +80 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/control.mjs +145 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +42 -21
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch-request.mjs +4 -2
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +33 -9
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +55 -11
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +26 -4
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/hermes.mjs +29 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/index.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/included-usage.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/jobs.mjs +84 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +3 -12
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/maintenance.mjs +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/mcp-server.mjs +228 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/process-manager.mjs +25 -2
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/reasoning.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/remote-operation.mjs +5 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +34 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/reviews.mjs +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/claude.mjs +319 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/codex.mjs +387 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/result.mjs +67 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/resume.mjs +373 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session/run.mjs +223 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/session-jobs.mjs +72 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/setup.mjs +6 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/termination.mjs +16 -12
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +32 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/usage-queue.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/verify-ssss.mjs +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +285 -40
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +76 -9
- 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 +64 -32
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +7 -7
- 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-diagnostics.mjs +44 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +123 -113
- 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 +7 -7
- 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 +3 -1
- package/src/cli/agent.mjs +1 -1
- package/src/cli/api.mjs +3 -3
- package/src/cli/brief.mjs +3 -0
- package/src/cli/command.mjs +41 -2
- package/src/cli/config.mjs +16 -0
- package/src/cli/connect.mjs +2 -7
- package/src/cli/dream.mjs +93 -69
- package/src/cli/harness.mjs +4 -4
- package/src/cli/help.mjs +1 -1
- package/src/cli/init.mjs +0 -25
- package/src/cli/lessons.mjs +51 -0
- package/src/cli/memory-plugin.mjs +1 -1
- package/src/cli/plugin/chunks.mjs +145 -0
- package/src/cli/plugin/copies.mjs +64 -14
- package/src/cli/plugin/create.mjs +30 -59
- package/src/cli/plugin/index.mjs +31 -16
- package/src/cli/plugin/install.mjs +10 -15
- package/src/cli/plugin/remove.mjs +1 -1
- package/src/cli/plugin/search.mjs +2 -2
- package/src/cli/preflight.mjs +19 -6
- package/src/cli/proposals.mjs +1 -1
- package/src/cli/recall.mjs +66 -23
- package/src/cli/remember.mjs +3 -14
- package/src/cli/server.mjs +18 -0
- package/src/cli/setup.mjs +2 -9
- package/src/cli/start.mjs +1 -0
- package/src/cli/startup.mjs +19 -0
- package/src/cli/task.mjs +9 -2
- package/src/cli/update.mjs +6 -2
- package/src/core/access-ledger.mjs +78 -0
- package/src/core/agent-manager.mjs +2 -2
- package/src/core/app-deploy/design-tokens.mjs +14 -9
- package/src/core/app-deploy/ui-elements.mjs +1 -1
- package/src/core/brain-locate.mjs +15 -0
- package/src/core/brain-registry.mjs +5 -0
- package/src/core/brain-updates.mjs +35 -11
- package/src/core/claude-hooks.mjs +3 -1
- package/src/core/cleanup-task.mjs +15 -0
- package/src/core/cli-commands.mjs +2 -0
- package/src/core/cli-maintenance.mjs +4 -1
- package/src/core/cli-semantic-index.mjs +23 -3
- package/src/core/context-compiler.mjs +20 -0
- package/src/core/daemon-control.mjs +5 -1
- package/src/core/daemon-loop.mjs +39 -62
- package/src/core/dashboard-bundle.mjs +261 -0
- package/src/core/default-plugins.mjs +1 -1
- package/src/core/dream.mjs +33 -105
- package/src/core/ensure-dependencies.mjs +152 -0
- package/src/core/fast-recall.mjs +2 -2
- package/src/core/field-evaluation.mjs +23 -0
- package/src/core/gate-mode.mjs +1 -1
- package/src/core/harness-hooks.mjs +14 -2
- package/src/core/lesson-hooks.mjs +74 -0
- package/src/core/lesson-memory.mjs +24 -0
- package/src/core/lesson-sessions.mjs +52 -0
- package/src/core/lessons.mjs +96 -0
- package/src/core/memory-brain.mjs +30 -8
- package/src/core/meta-harness.mjs +2 -2
- package/src/core/optimizer.mjs +66 -165
- package/src/core/plugin-activation.mjs +63 -20
- package/src/core/plugin-contracts/{card.mjs → manifest.mjs} +26 -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 +21 -8
- package/src/core/plugin-runner.mjs +21 -10
- package/src/core/plugin-runtime.mjs +40 -1
- package/src/core/plugin-startup-checks.mjs +44 -0
- package/src/core/plugin-state.mjs +19 -5
- package/src/core/plugin-store.mjs +64 -33
- package/src/core/post-mortem.mjs +52 -36
- package/src/core/preflight-gate.mjs +23 -2
- package/src/core/project-id.mjs +15 -5
- package/src/core/proposal-applier.mjs +31 -2
- package/src/core/repo-sync.mjs +4 -6
- package/src/core/required-plugins.mjs +57 -10
- package/src/core/rule-length.mjs +23 -0
- package/src/core/runtime.mjs +1 -1
- package/src/core/scheduler.mjs +35 -43
- package/src/core/schema.mjs +3 -2
- package/src/core/search.mjs +4 -3
- package/src/core/server-service.mjs +148 -0
- package/src/core/session-watcher.mjs +19 -1
- package/src/core/skill-gap.mjs +16 -0
- package/src/core/ssss-kernel-bridge.mjs +32 -4
- package/src/core/ssss-operation-service.mjs +1 -0
- package/src/core/startup-health.mjs +34 -4
- package/src/core/surface.mjs +65 -54
- package/src/core/task-executors.mjs +54 -106
- 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/validated-write.mjs +1 -0
- package/src/core/vault-cache.mjs +58 -59
- package/src/core/vector-field.mjs +134 -192
- 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/invoke-core-child.mjs +24 -0
- package/src/server/invoke-core-operations.mjs +102 -0
- 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 +47 -55
- package/src/server/routes/_shared.mjs +7 -14
- package/src/server/routes/brains.mjs +29 -62
- package/src/server/routes/context.mjs +0 -41
- package/src/server/routes/dashboard.mjs +26 -0
- package/src/server/routes/invoke.mjs +26 -1
- package/src/server/routes/plugins.mjs +154 -45
- package/src/server/routes/ssss.mjs +0 -169
- package/src/server/routes/system.mjs +0 -15
- package/src/server/routes/tasks.mjs +0 -26
- package/src/server/routes/ui-chunks.mjs +192 -0
- package/src/server/routes/vault.mjs +2 -23
- package/frontend/dist/assets/index-DD4qONvH.js +0 -5607
- 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-sentinel/README.md +0 -53
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/plugin.json +0 -129
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/DESIGN.md +0 -100
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/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/src/core/append-log.mjs +0 -131
- package/src/core/plugin-tasks.mjs +0 -173
- package/templates/onboarding-interview.md +0 -82
- /package/scaffold/.agent/skills/total-recall/plugins/{git-sentinel → git}/LICENSE +0 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { createValidator } from '@ssss/cli/validator';
|
|
5
|
+
import { discoverPlugins, resolvePluginFile, validatePluginManifest } from './plugin-loader.mjs';
|
|
6
|
+
import { pluginActivation } from './plugin-state.mjs';
|
|
7
|
+
import { executePluginState, listPluginStates, PluginStateStore } from './plugin-state-store.mjs';
|
|
8
|
+
import { collectCssVariables, extractFrontmatter, resolveTokenReferences } from './app-deploy/design-tokens.mjs';
|
|
9
|
+
|
|
10
|
+
const type = 'ui-chunk:chunk';
|
|
11
|
+
const idPattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
12
|
+
const timestampPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
13
|
+
const surfaces = new Set(['page', 'left', 'right', 'bottom']);
|
|
14
|
+
const maxFileBytes = 64 * 1024;
|
|
15
|
+
const maxQueryLength = 1024;
|
|
16
|
+
const POOL = 'workspace-chunk-pool';
|
|
17
|
+
export const uiChunkRegistryPath = path.join(import.meta.dirname, 'ui-chunk.registry.json');
|
|
18
|
+
const registry = JSON.parse(fs.readFileSync(uiChunkRegistryPath, 'utf8'));
|
|
19
|
+
const validator = createValidator({ extensions: [registry] });
|
|
20
|
+
|
|
21
|
+
export class UiChunkInputError extends Error {}
|
|
22
|
+
class UiChunkFileError extends Error {}
|
|
23
|
+
|
|
24
|
+
function isId(value) {
|
|
25
|
+
return typeof value === 'string' && value.length <= 64 && idPattern.test(value);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isText(value, max) {
|
|
29
|
+
return typeof value === 'string' && value.trim().length > 0 &&
|
|
30
|
+
value.length <= max && !/[\u0000-\u001f\u007f]/u.test(value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function validTimestamp(value) {
|
|
34
|
+
return typeof value === 'string' && timestampPattern.test(value) && Number.isFinite(Date.parse(value));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function validList(list, max, test) {
|
|
38
|
+
return Array.isArray(list) && list.length > 0 && list.length <= max &&
|
|
39
|
+
new Set(list).size === list.length && list.every(test);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// An installed plugin itself may be a deliberate owner link. Files and directories
|
|
43
|
+
// inside its resolved root must be regular, and never traverse another link.
|
|
44
|
+
function ownerFile(root, relative) {
|
|
45
|
+
const filename = path.join(root, relative);
|
|
46
|
+
if (!filename.startsWith(root + path.sep) || fs.realpathSync(filename) !== filename || !fs.lstatSync(filename).isFile()) {
|
|
47
|
+
throw new UiChunkFileError('Chunk files and DESIGN.md must be regular files inside the plugin.');
|
|
48
|
+
}
|
|
49
|
+
return filename;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function readOwnerFile(root, relative) {
|
|
53
|
+
const filename = ownerFile(root, relative);
|
|
54
|
+
const fd = fs.openSync(filename, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
|
|
55
|
+
try {
|
|
56
|
+
const stat = fs.fstatSync(fd);
|
|
57
|
+
if (!stat.isFile() || fs.realpathSync(filename) !== filename) {
|
|
58
|
+
throw new UiChunkFileError('Chunk files must be regular files inside the plugin.');
|
|
59
|
+
}
|
|
60
|
+
if (stat.size > maxFileBytes) throw new UiChunkFileError('Chunk file exceeds 64 KiB.');
|
|
61
|
+
const buffer = Buffer.alloc(Math.min(stat.size + 1, maxFileBytes + 1));
|
|
62
|
+
let used = 0;
|
|
63
|
+
while (used < buffer.length) {
|
|
64
|
+
const count = fs.readSync(fd, buffer, used, buffer.length - used, null);
|
|
65
|
+
if (count === 0) break;
|
|
66
|
+
used += count;
|
|
67
|
+
}
|
|
68
|
+
if (used !== stat.size) throw new UiChunkFileError('Chunk file changed while being read. Retry.');
|
|
69
|
+
return buffer.subarray(0, used);
|
|
70
|
+
} finally {
|
|
71
|
+
fs.closeSync(fd);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const componentProperties = {
|
|
76
|
+
backgroundColor: 'background-color', textColor: 'color', color: 'color',
|
|
77
|
+
borderColor: 'border-color', borderWidth: 'border-width', borderStyle: 'border-style',
|
|
78
|
+
rounded: 'border-radius', padding: 'padding', gap: 'gap', size: 'inline-size',
|
|
79
|
+
width: 'width', height: 'height', fontFamily: 'font-family', fontSize: 'font-size',
|
|
80
|
+
fontWeight: 'font-weight', lineHeight: 'line-height', letterSpacing: 'letter-spacing',
|
|
81
|
+
fontFeature: 'font-feature-settings', fontVariation: 'font-variation-settings',
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
function designValue(value) {
|
|
85
|
+
const css = String(value);
|
|
86
|
+
if (/[;{}<>\\\r\n]|\/\*|\burl\s*\(/i.test(css)) {
|
|
87
|
+
throw new UiChunkFileError('Unsafe design token value.');
|
|
88
|
+
}
|
|
89
|
+
return css;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function compilePluginDesign(markdown) {
|
|
93
|
+
// Older owners published the token map in a fenced YAML section.
|
|
94
|
+
const legacy = !/^\uFEFF?---(?:\r?\n|$)/.test(markdown) &&
|
|
95
|
+
markdown.match(/^```yaml\r?\n(tokens:\r?\n[\s\S]*?)^```[ \t]*$/m);
|
|
96
|
+
if (/^\uFEFF?---(?:\r?\n|$)/.test(markdown) && !/^\uFEFF?---\r?\n[\s\S]*?\r?\n---[ \t]*(?:\r?\n|$)/.test(markdown)) {
|
|
97
|
+
throw new UiChunkFileError('Incomplete design frontmatter.');
|
|
98
|
+
}
|
|
99
|
+
const tokens = extractFrontmatter(legacy ? '---\n' + legacy[1] + '---\n' : markdown);
|
|
100
|
+
const flat = Object.entries(tokens.tokens || {}).filter(([name, value]) =>
|
|
101
|
+
/^(?:color|font|spacing|radius|border-radius)(?:-[a-z0-9-]+)?$/.test(name) &&
|
|
102
|
+
(typeof value === 'string' || typeof value === 'number'));
|
|
103
|
+
const entries = new Map([...flat, ...collectCssVariables(tokens)]);
|
|
104
|
+
const properties = Object.fromEntries([...entries].map(([name, value]) => ['--' + name, designValue(value)]));
|
|
105
|
+
const resolved = resolveTokenReferences(tokens);
|
|
106
|
+
const components = [];
|
|
107
|
+
const rules = Object.entries(resolved.components || {}).map(([component, values]) => {
|
|
108
|
+
if (!/^[A-Za-z0-9_-]{1,80}$/.test(component) || !values || typeof values !== 'object') return '';
|
|
109
|
+
const definitions = { ...values.typography, ...values };
|
|
110
|
+
const declarations = Object.entries(componentProperties).flatMap(([key, property]) => {
|
|
111
|
+
const value = definitions[key];
|
|
112
|
+
return typeof value === 'string' || typeof value === 'number' ? [property + ':' + designValue(value) + ';'] : [];
|
|
113
|
+
});
|
|
114
|
+
if (!declarations.length) return '';
|
|
115
|
+
components.push(component);
|
|
116
|
+
return '[data-design-component="' + component + '"]{' + declarations.join('') + '}';
|
|
117
|
+
});
|
|
118
|
+
const css = ':root{' + Object.entries(properties).map(([name, value]) => name + ':' + value + ';').join('') + '}\n' +
|
|
119
|
+
rules.join('\n');
|
|
120
|
+
return { css, components };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function readPluginDesign(plugin, { projectRoot = process.cwd(), revision } = {}) {
|
|
124
|
+
if (!isId(plugin)) throw new UiChunkInputError('Invalid plugin ID.');
|
|
125
|
+
const owner = discoverPlugins(projectRoot).find(entry => entry.id === plugin && entry.valid);
|
|
126
|
+
if (!owner || !pluginActivation(owner, { projectRoot }).enabled) return null;
|
|
127
|
+
const root = fs.realpathSync(owner.dir);
|
|
128
|
+
const declared = owner.manifest.ui?.design_tokens;
|
|
129
|
+
for (const file of declared ? [declared] : ['DESIGN.md', 'ui/DESIGN.md']) {
|
|
130
|
+
let content;
|
|
131
|
+
try {
|
|
132
|
+
content = readOwnerFile(root, file);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
if (!declared && error.code === 'ENOENT') continue;
|
|
135
|
+
throw new UiChunkInputError('The plugin design file could not be read.');
|
|
136
|
+
}
|
|
137
|
+
const version = createHash('sha256').update(content).digest('hex');
|
|
138
|
+
if (version === revision) return { unchanged: true };
|
|
139
|
+
try {
|
|
140
|
+
return { revision: version, ...compilePluginDesign(new TextDecoder('utf-8', { fatal: true }).decode(content)) };
|
|
141
|
+
} catch {
|
|
142
|
+
throw new UiChunkInputError('The plugin design contains invalid tokens. Showing the last valid design.');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return { revision: null, css: '', components: [] };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function chunkDirectory(root) {
|
|
149
|
+
for (const relative of ['ui', 'ui/chunks']) {
|
|
150
|
+
const directory = path.join(root, relative);
|
|
151
|
+
let stat;
|
|
152
|
+
try {
|
|
153
|
+
stat = fs.lstatSync(directory);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
if (error.code === 'ENOENT') return null;
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
159
|
+
throw new UiChunkFileError('ui/chunks must be a regular directory inside the plugin.');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return path.join(root, 'ui', 'chunks');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function nativePanel(manifest, id, root) {
|
|
166
|
+
const element = manifest.ui?.elements?.find(entry => entry.id === id);
|
|
167
|
+
if (!element || !['panel', 'form', 'list', 'detail', 'widget'].includes(element.kind)) {
|
|
168
|
+
throw new UiChunkFileError('panel must identify a declared native content element.');
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
resolvePluginFile(root, element.module);
|
|
172
|
+
} catch {
|
|
173
|
+
throw new UiChunkFileError('The declared panel module is unavailable.');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function readChunk(root, manifest, id) {
|
|
178
|
+
const contents = readOwnerFile(root, 'ui/chunks/' + id + '.md');
|
|
179
|
+
return parseChunk(contents, root, manifest, id);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function parseChunk(contents, root, manifest, id) {
|
|
183
|
+
let source;
|
|
184
|
+
try {
|
|
185
|
+
source = new TextDecoder('utf-8', { fatal: true }).decode(contents);
|
|
186
|
+
} catch {
|
|
187
|
+
throw new UiChunkFileError('Chunk file must be UTF-8.');
|
|
188
|
+
}
|
|
189
|
+
const result = validator.validateDocument(source);
|
|
190
|
+
if (!result.valid || result.data?.type !== type) {
|
|
191
|
+
throw new UiChunkFileError('Invalid SSSS UI chunk frontmatter. Run total-recall ssss validate for field errors.');
|
|
192
|
+
}
|
|
193
|
+
const data = result.data;
|
|
194
|
+
if (data.plugin !== manifest.id || data.id !== id) {
|
|
195
|
+
throw new UiChunkFileError('Chunk identity must match the owning manifest and filename.');
|
|
196
|
+
}
|
|
197
|
+
if (!isText(data.title, 120) || !isText(data.description, 600) || !validTimestamp(data.timestamp)) {
|
|
198
|
+
throw new UiChunkFileError('Chunk needs a short title, description and ISO timestamp.');
|
|
199
|
+
}
|
|
200
|
+
if (!validList(data.intents, 12, item => isText(item, 100)) ||
|
|
201
|
+
!validList(data.surfaces, 4, surface => surfaces.has(surface))) {
|
|
202
|
+
throw new UiChunkFileError('Chunk needs distinct intent strings and allowed surfaces.');
|
|
203
|
+
}
|
|
204
|
+
if (data.panel !== undefined) {
|
|
205
|
+
if (!isId(data.panel)) throw new UiChunkFileError('Invalid panel ID.');
|
|
206
|
+
nativePanel(manifest, data.panel, root);
|
|
207
|
+
}
|
|
208
|
+
const operations = new Map(manifest.cli?.subcommands?.map(command => [command.name, command]));
|
|
209
|
+
if (data.operations !== undefined && !validList(data.operations, 24, operation => operations.has(operation))) {
|
|
210
|
+
throw new UiChunkFileError('operations must name distinct CLI operations declared by this plugin.');
|
|
211
|
+
}
|
|
212
|
+
if (data.data !== undefined && !validList(data.data, 24, ref => {
|
|
213
|
+
if (!isText(ref, 200)) return false;
|
|
214
|
+
const separator = ref.indexOf(':');
|
|
215
|
+
const operation = separator > 0 && operations.get(ref.slice(0, separator));
|
|
216
|
+
return operation && operation.sensitive_output !== true &&
|
|
217
|
+
/^(?:\/(?:[^~/]|~[01])*)+$/u.test(ref.slice(separator + 1));
|
|
218
|
+
})) {
|
|
219
|
+
throw new UiChunkFileError('data must name non-sensitive declared operations and JSON pointers in the form operation:/path.');
|
|
220
|
+
}
|
|
221
|
+
const html = result.body.trim();
|
|
222
|
+
if (!html.startsWith('<') || html.includes('\0')) {
|
|
223
|
+
throw new UiChunkFileError('Chunk body must contain raw HTML.');
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
key: data.plugin + ':' + id,
|
|
227
|
+
plugin: data.plugin,
|
|
228
|
+
id,
|
|
229
|
+
title: data.title.trim(),
|
|
230
|
+
description: data.description.trim(),
|
|
231
|
+
intents: data.intents.map(intent => intent.trim()),
|
|
232
|
+
surfaces: data.surfaces,
|
|
233
|
+
...(data.panel === undefined ? {} : { panel: data.panel }),
|
|
234
|
+
...(data.operations === undefined ? {} : { operations: data.operations }),
|
|
235
|
+
...(data.data === undefined ? {} : { data: data.data }),
|
|
236
|
+
sha256: createHash('sha256').update(contents).digest('hex'),
|
|
237
|
+
html,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function metadata({ html: _html, ...chunk }) {
|
|
242
|
+
return chunk;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function poolDirectory(brainDir) {
|
|
246
|
+
return path.join(brainDir, 'config', POOL);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function poolFile(brainDir, plugin, id) {
|
|
250
|
+
return path.join(poolDirectory(brainDir), plugin + ':' + id + '.json');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function poolChunk(value, root, manifest, id) {
|
|
254
|
+
if (!value || value.plugin !== manifest.id || value.id !== id ||
|
|
255
|
+
typeof value.markdown !== 'string' || Buffer.byteLength(value.markdown) > maxFileBytes) {
|
|
256
|
+
throw new UiChunkFileError('Invalid workspace block record.');
|
|
257
|
+
}
|
|
258
|
+
return { ...parseChunk(Buffer.from(value.markdown), root, manifest, id), origin: 'workspace' };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export async function addWorkspaceUiChunk(brainDir, { plugin, id, markdown }, projectRoot = process.cwd()) {
|
|
262
|
+
if (!isId(plugin) || !isId(id)) throw new UiChunkInputError('Invalid block identity.');
|
|
263
|
+
const owner = discoverPlugins(projectRoot).find(entry => entry.id === plugin && entry.valid);
|
|
264
|
+
if (!owner || !pluginActivation(owner, { projectRoot }).enabled) throw new UiChunkInputError('The block owner must be installed and enabled.');
|
|
265
|
+
const root = fs.realpathSync(owner.dir);
|
|
266
|
+
const directory = chunkDirectory(root);
|
|
267
|
+
if (directory && fs.lstatSync(path.join(directory, id + '.md'), { throwIfNoEntry: false })) {
|
|
268
|
+
throw new UiChunkInputError('That block ID belongs to the installed plugin.');
|
|
269
|
+
}
|
|
270
|
+
const value = { plugin, id, markdown };
|
|
271
|
+
let chunk;
|
|
272
|
+
try { chunk = poolChunk(value, root, owner.manifest, id); }
|
|
273
|
+
catch (error) {
|
|
274
|
+
if (error instanceof UiChunkFileError) throw new UiChunkInputError(error.message);
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
277
|
+
const file = poolFile(brainDir, plugin, id);
|
|
278
|
+
const result = await executePluginState({ file, plugin: POOL, action: 'write', value, expectedVersion: null });
|
|
279
|
+
return { chunk: metadata(chunk), version: result.version };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function diagnostic(error, plugin, id) {
|
|
283
|
+
const message = error instanceof UiChunkFileError
|
|
284
|
+
? error.message
|
|
285
|
+
: 'Could not read the owner chunk files.';
|
|
286
|
+
return { plugin, ...(id ? { id } : {}), message };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function validateUiChunkFile(filename, { pluginDir } = {}) {
|
|
290
|
+
if (typeof filename !== 'string' || !filename) throw new UiChunkInputError('Specify a chunk file.');
|
|
291
|
+
const file = path.resolve(filename);
|
|
292
|
+
const root = fs.realpathSync(pluginDir || path.resolve(file, '../../..'));
|
|
293
|
+
const id = path.basename(file, '.md');
|
|
294
|
+
if (!isId(id) || fs.realpathSync(path.dirname(file)) !== chunkDirectory(root) ||
|
|
295
|
+
path.basename(file) !== id + '.md') {
|
|
296
|
+
throw new UiChunkInputError('Place the file at ui/chunks/<id>.md inside its plugin.');
|
|
297
|
+
}
|
|
298
|
+
const manifest = JSON.parse(readOwnerFile(root, 'plugin.json').toString('utf8'));
|
|
299
|
+
if (!validatePluginManifest(manifest).valid) throw new UiChunkInputError('The owner plugin manifest is invalid.');
|
|
300
|
+
ownerFile(root, 'DESIGN.md');
|
|
301
|
+
return metadata(readChunk(root, manifest, id));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function tokens(value) {
|
|
305
|
+
return new Set(value.normalize('NFKC').toLowerCase().match(/[\p{L}\p{N}]+/gu) || []);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function scoreChunk(chunk, query, terms) {
|
|
309
|
+
if (!query) return 0;
|
|
310
|
+
if (query === chunk.key || query === chunk.id) return Number.MAX_SAFE_INTEGER;
|
|
311
|
+
const identity = tokens(chunk.key + ' ' + chunk.title);
|
|
312
|
+
const intents = tokens([...chunk.intents, ...(chunk.operations || []), ...(chunk.data || [])].join(' '));
|
|
313
|
+
const description = tokens(chunk.description);
|
|
314
|
+
let score = 0;
|
|
315
|
+
for (const term of terms) {
|
|
316
|
+
score += (identity.has(term) ? 5 : 0) + (intents.has(term) ? 3 : 0) + (description.has(term) ? 1 : 0);
|
|
317
|
+
}
|
|
318
|
+
return score;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export function searchUiChunks({ projectRoot = process.cwd(), brainDir, plugin, surface, query = '', limit = 40, offset = 0 } = {}) {
|
|
322
|
+
if (plugin !== undefined && !isId(plugin)) throw new UiChunkInputError('Invalid plugin ID.');
|
|
323
|
+
if (surface !== undefined && !surfaces.has(surface)) throw new UiChunkInputError('Invalid UI surface.');
|
|
324
|
+
if (typeof query !== 'string' || query.length > maxQueryLength) throw new UiChunkInputError('Chunk query exceeds 1024 characters or is invalid.');
|
|
325
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 200) throw new UiChunkInputError('Limit must be between 1 and 200.');
|
|
326
|
+
if (!Number.isSafeInteger(offset) || offset < 0) throw new UiChunkInputError('Offset must be a nonnegative integer.');
|
|
327
|
+
const chunks = [];
|
|
328
|
+
const diagnostics = [];
|
|
329
|
+
const normalized = query.trim().toLowerCase();
|
|
330
|
+
const terms = tokens(normalized);
|
|
331
|
+
const installed = discoverPlugins(projectRoot).filter(owner => owner.valid && (!plugin || owner.id === plugin));
|
|
332
|
+
const visible = new Map();
|
|
333
|
+
const keys = new Set();
|
|
334
|
+
const add = (record) => {
|
|
335
|
+
if (keys.has(record.key)) return;
|
|
336
|
+
keys.add(record.key);
|
|
337
|
+
if (surface && !record.surfaces.includes(surface)) return;
|
|
338
|
+
const score = scoreChunk(record, normalized, terms);
|
|
339
|
+
if (!normalized || score > 0) chunks.push({ chunk: metadata(record), score });
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
for (const owner of installed) {
|
|
343
|
+
try {
|
|
344
|
+
if (!pluginActivation(owner, { projectRoot }).enabled) continue;
|
|
345
|
+
const root = fs.realpathSync(owner.dir);
|
|
346
|
+
const directory = chunkDirectory(root);
|
|
347
|
+
visible.set(owner.id, { root, manifest: owner.manifest, directory });
|
|
348
|
+
if (!directory) continue;
|
|
349
|
+
const files = fs.readdirSync(directory).filter(name => name.endsWith('.md')).sort();
|
|
350
|
+
if (!files.length) continue;
|
|
351
|
+
ownerFile(root, 'DESIGN.md');
|
|
352
|
+
for (const file of files) {
|
|
353
|
+
const id = path.basename(file, '.md');
|
|
354
|
+
if (!isId(id)) {
|
|
355
|
+
diagnostics.push({ plugin: owner.id, message: 'Chunk filename must be <kebab-case-id>.md.' });
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
try {
|
|
359
|
+
add(readChunk(root, owner.manifest, id));
|
|
360
|
+
} catch (error) {
|
|
361
|
+
diagnostics.push(diagnostic(error, owner.id, id));
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
} catch (error) {
|
|
365
|
+
diagnostics.push(diagnostic(error, owner.id));
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (brainDir) {
|
|
369
|
+
for (const { value } of listPluginStates(poolDirectory(brainDir), POOL)) {
|
|
370
|
+
const owner = visible.get(value?.plugin);
|
|
371
|
+
if (!owner || !isId(value.id)) continue;
|
|
372
|
+
try {
|
|
373
|
+
if (owner.directory && fs.lstatSync(path.join(owner.directory, value.id + '.md'), { throwIfNoEntry: false })) continue;
|
|
374
|
+
add(poolChunk(value, owner.root, owner.manifest, value.id));
|
|
375
|
+
} catch (error) { diagnostics.push(diagnostic(error, value.plugin, value.id)); }
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
chunks.sort((a, b) => b.score - a.score || a.chunk.key.localeCompare(b.chunk.key, 'en'));
|
|
379
|
+
return { chunks: chunks.slice(offset, offset + limit).map(entry => entry.chunk), total: chunks.length, diagnostics, retrieval: 'lexical' };
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export function getUiChunk(plugin, id, { projectRoot = process.cwd(), surface, brainDir } = {}) {
|
|
383
|
+
if (!isId(plugin) || !isId(id)) throw new UiChunkInputError('Invalid chunk identity.');
|
|
384
|
+
if (surface !== undefined && !surfaces.has(surface)) throw new UiChunkInputError('Invalid UI surface.');
|
|
385
|
+
const owner = discoverPlugins(projectRoot).find(entry => entry.id === plugin && entry.valid);
|
|
386
|
+
if (!owner) return null;
|
|
387
|
+
try {
|
|
388
|
+
if (!pluginActivation(owner, { projectRoot }).enabled) return null;
|
|
389
|
+
const root = fs.realpathSync(owner.dir);
|
|
390
|
+
const directory = chunkDirectory(root);
|
|
391
|
+
let chunk;
|
|
392
|
+
if (directory && fs.lstatSync(path.join(directory, id + '.md'), { throwIfNoEntry: false })) {
|
|
393
|
+
ownerFile(root, 'DESIGN.md');
|
|
394
|
+
chunk = readChunk(root, owner.manifest, id);
|
|
395
|
+
} else if (brainDir) {
|
|
396
|
+
const record = new PluginStateStore(poolFile(brainDir, plugin, id), POOL).read(null);
|
|
397
|
+
if (record) chunk = poolChunk(record, root, owner.manifest, id);
|
|
398
|
+
}
|
|
399
|
+
if (!chunk) return null;
|
|
400
|
+
return !surface || chunk.surfaces.includes(surface) ? chunk : null;
|
|
401
|
+
} catch {
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export function auditUiChunkCoverage({ projectRoot = process.cwd(), plugin } = {}) {
|
|
407
|
+
if (plugin !== undefined && !isId(plugin)) throw new UiChunkInputError('Invalid plugin ID.');
|
|
408
|
+
return discoverPlugins(projectRoot).filter(owner => !plugin || owner.id === plugin).map(owner => {
|
|
409
|
+
let design = null;
|
|
410
|
+
for (const file of ['DESIGN.md', 'ui/DESIGN.md']) {
|
|
411
|
+
try {
|
|
412
|
+
ownerFile(fs.realpathSync(owner.dir), file);
|
|
413
|
+
design = file;
|
|
414
|
+
break;
|
|
415
|
+
} catch { /* Check the other supported owner path. */ }
|
|
416
|
+
}
|
|
417
|
+
const { chunks, total, diagnostics } = searchUiChunks({ projectRoot, plugin: owner.id, surface: 'page', limit: 200 });
|
|
418
|
+
const covered = new Set(chunks.flatMap(chunk => chunk.operations || []));
|
|
419
|
+
const operations = owner.manifest?.cli?.subcommands?.map(command => command.name) || [];
|
|
420
|
+
const missing = operations.filter(operation => !covered.has(operation));
|
|
421
|
+
return {
|
|
422
|
+
plugin: owner.id,
|
|
423
|
+
active: owner.valid && pluginActivation(owner, { projectRoot }).enabled,
|
|
424
|
+
design,
|
|
425
|
+
panels: (owner.manifest?.ui?.elements || []).filter(element =>
|
|
426
|
+
['panel', 'form', 'list', 'detail', 'widget'].includes(element.kind)).map(element => element.id),
|
|
427
|
+
pageBlocks: total,
|
|
428
|
+
dataBindings: [...new Set(chunks.flatMap(chunk => chunk.data || []))].sort(),
|
|
429
|
+
operations: { total: operations.length, missing },
|
|
430
|
+
partial: chunks.length < total,
|
|
431
|
+
diagnostics,
|
|
432
|
+
};
|
|
433
|
+
});
|
|
434
|
+
}
|
package/src/core/vault-cache.mjs
CHANGED
|
@@ -9,7 +9,8 @@ import { brainDir } from './local-config.mjs';
|
|
|
9
9
|
* Supports multiple vault directories (global + project brains)
|
|
10
10
|
* without cross-contamination.
|
|
11
11
|
*/
|
|
12
|
-
const cacheMap = new Map(); // vaultDir → { nodes, watcher }
|
|
12
|
+
const cacheMap = new Map(); // vaultDir → { nodes, watcher, retryWatcherAt }
|
|
13
|
+
const WATCH_RETRY_MS = 30_000;
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Files the runtime regenerates itself (OKF bundle manifest and changelog, the
|
|
@@ -35,19 +36,15 @@ export function isGeneratedVaultPath(relPath) {
|
|
|
35
36
|
*/
|
|
36
37
|
export function getNodes(vaultDir) {
|
|
37
38
|
const resolvedDir = vaultDir || path.join(brainDir, 'memory-vault');
|
|
39
|
+
start(resolvedDir);
|
|
38
40
|
const entry = cacheMap.get(resolvedDir);
|
|
39
|
-
if (entry
|
|
41
|
+
if (entry.nodes !== null) {
|
|
40
42
|
logger.debug('Vault cache hit', { vaultDir: resolvedDir });
|
|
41
43
|
return entry.nodes;
|
|
42
44
|
}
|
|
43
45
|
logger.debug('Vault cache miss, loading nodes from disk', { vaultDir: resolvedDir });
|
|
44
46
|
const nodes = loadNodes(resolvedDir);
|
|
45
|
-
if (entry)
|
|
46
|
-
entry.nodes = nodes;
|
|
47
|
-
} else {
|
|
48
|
-
cacheMap.set(resolvedDir, { nodes, watcher: null });
|
|
49
|
-
startWatcher(resolvedDir);
|
|
50
|
-
}
|
|
47
|
+
if (entry.watcher) entry.nodes = nodes;
|
|
51
48
|
return nodes;
|
|
52
49
|
}
|
|
53
50
|
|
|
@@ -86,61 +83,56 @@ export function invalidate(vaultDir) {
|
|
|
86
83
|
*
|
|
87
84
|
* @param {string} root - Directory to watch
|
|
88
85
|
* @param {(eventType: string, filename: string) => void} onChange - Receives paths relative to root
|
|
86
|
+
* @param {(error: Error) => void} onError - Stops the whole watch if coverage is lost
|
|
89
87
|
* @returns {{ close: () => void }}
|
|
90
88
|
*/
|
|
91
|
-
function watchTree(root, onChange) {
|
|
89
|
+
function watchTree(root, onChange, onError) {
|
|
92
90
|
if (process.platform === 'darwin' || process.platform === 'win32') {
|
|
93
91
|
const watcher = fs.watch(root, { recursive: true }, onChange);
|
|
92
|
+
watcher.on('error', onError);
|
|
94
93
|
watcher.unref();
|
|
95
94
|
return watcher;
|
|
96
95
|
}
|
|
97
96
|
|
|
98
97
|
const watchers = new Map();
|
|
98
|
+
const close = () => {
|
|
99
|
+
for (const watcher of watchers.values()) watcher.close();
|
|
100
|
+
watchers.clear();
|
|
101
|
+
};
|
|
99
102
|
const watchDir = (dir) => {
|
|
100
103
|
if (watchers.has(dir)) return;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
const watcher = fs.watch(dir, (eventType, filename) => {
|
|
105
|
+
if (!filename) return;
|
|
106
|
+
const full = path.join(dir, String(filename));
|
|
107
|
+
if (eventType === 'rename') {
|
|
108
|
+
try {
|
|
109
|
+
if (fs.lstatSync(full).isDirectory()) walk(full);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (error.code !== 'ENOENT') {
|
|
112
|
+
onError(error);
|
|
113
|
+
return;
|
|
111
114
|
}
|
|
112
115
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
} catch {
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
watcher.on('error', () => {
|
|
119
|
-
watcher.close();
|
|
120
|
-
watchers.delete(dir);
|
|
116
|
+
}
|
|
117
|
+
onChange(eventType, path.relative(root, full));
|
|
121
118
|
});
|
|
119
|
+
watcher.on('error', onError);
|
|
122
120
|
watcher.unref();
|
|
123
121
|
watchers.set(dir, watcher);
|
|
124
122
|
};
|
|
125
123
|
const walk = (dir) => {
|
|
126
124
|
watchDir(dir);
|
|
127
|
-
|
|
128
|
-
try {
|
|
129
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
130
|
-
} catch {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
for (const item of entries) {
|
|
125
|
+
for (const item of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
134
126
|
if (item.isDirectory()) walk(path.join(dir, item.name));
|
|
135
127
|
}
|
|
136
128
|
};
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
};
|
|
129
|
+
try {
|
|
130
|
+
walk(root);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
close();
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
return { close };
|
|
144
136
|
}
|
|
145
137
|
|
|
146
138
|
/**
|
|
@@ -150,29 +142,36 @@ function watchTree(root, onChange) {
|
|
|
150
142
|
* @param {string} [vaultDir] - Path to the vault directory to watch
|
|
151
143
|
*/
|
|
152
144
|
function startWatcher(vaultDir) {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
if (!entry || entry.watcher) return;
|
|
156
|
-
|
|
157
|
-
if (!fs.existsSync(resolvedDir)) {
|
|
158
|
-
try {
|
|
159
|
-
fs.mkdirSync(resolvedDir, { recursive: true });
|
|
160
|
-
} catch (err) {
|
|
161
|
-
logger.error('Failed to create vault directory for watcher', { error: err.message });
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
145
|
+
const entry = cacheMap.get(vaultDir);
|
|
146
|
+
if (entry.watcher || entry.retryWatcherAt > Date.now()) return;
|
|
165
147
|
|
|
166
|
-
|
|
148
|
+
const onError = (error) => {
|
|
149
|
+
const watcher = entry.watcher;
|
|
150
|
+
entry.watcher = null;
|
|
151
|
+
entry.nodes = null;
|
|
152
|
+
entry.retryWatcherAt = Date.now() + WATCH_RETRY_MS;
|
|
153
|
+
watcher?.close();
|
|
154
|
+
logger.warn('Vault cache watcher unavailable. Reading from disk until the watcher recovers.', {
|
|
155
|
+
vaultDir,
|
|
156
|
+
code: error.code,
|
|
157
|
+
error: error.message,
|
|
158
|
+
});
|
|
159
|
+
};
|
|
167
160
|
try {
|
|
168
|
-
|
|
161
|
+
if (!fs.existsSync(vaultDir)) fs.mkdirSync(vaultDir, { recursive: true });
|
|
162
|
+
logger.info('Starting filesystem watcher for vault cache', { vaultDir });
|
|
163
|
+
const watcher = watchTree(vaultDir, (eventType, filename) => {
|
|
169
164
|
if (filename && filename.endsWith('.md') && !isGeneratedVaultPath(filename)) {
|
|
170
165
|
logger.debug(`Vault filesystem change detected (${eventType}: ${filename}), invalidating cache`);
|
|
171
|
-
invalidate(
|
|
166
|
+
invalidate(vaultDir);
|
|
172
167
|
}
|
|
168
|
+
}, (error) => {
|
|
169
|
+
if (entry.watcher === watcher) onError(error);
|
|
173
170
|
});
|
|
174
|
-
|
|
175
|
-
|
|
171
|
+
entry.watcher = watcher;
|
|
172
|
+
entry.retryWatcherAt = 0;
|
|
173
|
+
} catch (error) {
|
|
174
|
+
onError(error);
|
|
176
175
|
}
|
|
177
176
|
}
|
|
178
177
|
|
|
@@ -184,7 +183,7 @@ function startWatcher(vaultDir) {
|
|
|
184
183
|
export function start(vaultDir) {
|
|
185
184
|
const resolvedDir = vaultDir || path.join(brainDir, 'memory-vault');
|
|
186
185
|
if (!cacheMap.has(resolvedDir)) {
|
|
187
|
-
cacheMap.set(resolvedDir, { nodes: null, watcher: null });
|
|
186
|
+
cacheMap.set(resolvedDir, { nodes: null, watcher: null, retryWatcherAt: 0 });
|
|
188
187
|
}
|
|
189
188
|
startWatcher(resolvedDir);
|
|
190
189
|
}
|