@polderlabs/bizar 8.0.0 → 9.0.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/.claude/agents/agent-browser.md +1 -1
- package/.claude/agents/baldr.md +1 -1
- package/.claude/agents/forseti.md +1 -1
- package/.claude/agents/frigg.md +1 -1
- package/.claude/agents/heimdall.md +1 -1
- package/.claude/agents/hermod.md +1 -1
- package/.claude/agents/mimir.md +1 -1
- package/.claude/agents/odin.md +1 -1
- package/.claude/agents/quick.md +1 -1
- package/.claude/agents/semble-search.md +1 -1
- package/.claude/agents/thor.md +1 -1
- package/.claude/agents/tyr.md +1 -1
- package/.claude/agents/vidarr.md +1 -1
- package/.claude/agents/vor.md +1 -1
- package/.claude/commands/goal.md +98 -0
- package/.claude/settings.local.json +1 -2
- package/.claude/worktrees/kanban-overhaul/.claude/CLAUDE.md +15 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/_shared/AGENT_BASELINE.md +168 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/_shared/CLAUDE_TOOLS.md +412 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/_shared/SKILLS.md +109 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/agent-browser.md +80 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/baldr.md +49 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/forseti.md +51 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/frigg.md +42 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/heimdall.md +33 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/hermod.md +53 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/mimir.md +49 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/odin.md +287 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/quick.md +34 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/semble-search.md +50 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/thor.md +53 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/tyr.md +56 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/vidarr.md +54 -0
- package/.claude/worktrees/kanban-overhaul/.claude/agents/vor.md +53 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/audit.md +25 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/bizar.md +22 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/explain.md +17 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/init.md +29 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/learn.md +44 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/plan.md +35 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/plow-through.md +50 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/pr-review.md +49 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/setup-provider.md +96 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/tailscale-serve.md +100 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/team.md +132 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/test.md +62 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/validate.md +68 -0
- package/.claude/worktrees/kanban-overhaul/.claude/commands/visual-plan.md +24 -0
- package/.claude/worktrees/kanban-overhaul/.claude/hooks/README.md +92 -0
- package/.claude/worktrees/kanban-overhaul/.claude/hooks/posttooluse-editwrite.mjs +91 -0
- package/.claude/worktrees/kanban-overhaul/.claude/hooks/pretooluse-bash.mjs +81 -0
- package/.claude/worktrees/kanban-overhaul/.claude/hooks/pretooluse-editwrite.mjs +139 -0
- package/.claude/worktrees/kanban-overhaul/.claude/hooks/sessionend-recall.mjs +74 -0
- package/.claude/worktrees/kanban-overhaul/.claude/hooks/sessionstart-prime.mjs +80 -0
- package/.claude/worktrees/kanban-overhaul/.claude/hooks/userpromptsubmit-tag.mjs +80 -0
- package/.claude/worktrees/kanban-overhaul/.claude/hooks/worker-suggest.mjs +110 -0
- package/.claude/worktrees/kanban-overhaul/.claude/settings.json +125 -0
- package/.claude/worktrees/kanban-overhaul/.claude/settings.local.json +8 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/9router/SKILL.md +80 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/9router-chat/SKILL.md +73 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/9router-embeddings/SKILL.md +69 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/9router-image/SKILL.md +86 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/9router-stt/SKILL.md +79 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/9router-tts/SKILL.md +80 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/9router-web-fetch/SKILL.md +99 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/9router-web-search/SKILL.md +91 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/bizar/README.md +9 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/bizar/SKILL.md +450 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-coding-standards/README.md +28 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-coding-standards/SKILL.md +634 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-coding-standards/references/concurrency.md +320 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-coding-standards/references/error-handling.md +229 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-coding-standards/references/memory-safety.md +216 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-coding-standards/references/modern-idioms.md +282 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-coding-standards/references/review-checklist.md +96 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-testing/README.md +28 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-testing/SKILL.md +304 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-testing/references/coverage.md +370 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-testing/references/framework-compare.md +175 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-testing/references/host-test-for-embedded.md +499 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-testing/references/mocking.md +364 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cpp-testing/references/tdd-workflow.md +308 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/cubesandbox/SKILL.md +148 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/embedded-esp-idf/README.md +41 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/embedded-esp-idf/SKILL.md +439 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/embedded-esp-idf/references/freertos-patterns.md +214 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/embedded-esp-idf/references/host-tests.md +164 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/embedded-esp-idf/references/idf-py-commands.md +157 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/embedded-esp-idf/references/kconfig.md +159 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/embedded-esp-idf/references/logging-discipline.md +118 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/embedded-esp-idf/references/memory-and-iram.md +137 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/embedded-esp-idf/references/nvs.md +121 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/embedded-esp-idf/references/packed-structs.md +192 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/embedded-esp-idf/scripts/idf_env.sh +47 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/embedded-esp-idf/scripts/size_check.sh +77 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/glyph/SKILL.md +163 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/harness-engineering/SKILL.md +143 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/lightrag/SKILL.md +81 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/memory-protocol/SKILL.md +105 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/obsidian/SKILL.md +306 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/read-the-damn-docs/SKILL.md +113 -0
- package/.claude/worktrees/kanban-overhaul/.claude/skills/self-improvement/SKILL.md +64 -0
- package/.claude/worktrees/kanban-overhaul/.dockerignore +31 -0
- package/.claude/worktrees/kanban-overhaul/.gitattributes +27 -0
- package/.claude/worktrees/kanban-overhaul/.harness/agents.json +17 -0
- package/.claude/worktrees/kanban-overhaul/.harness/arch-rules.json +69 -0
- package/.claude/worktrees/kanban-overhaul/.harness/topology.json +4 -0
- package/.claude/worktrees/kanban-overhaul/.nvmrc +1 -0
- package/.claude/worktrees/kanban-overhaul/.serena/project.yml +159 -0
- package/.claude/worktrees/kanban-overhaul/AGENTS.md +250 -0
- package/.claude/worktrees/kanban-overhaul/CHANGELOG.md +5410 -0
- package/.claude/worktrees/kanban-overhaul/CLAUDE.md +260 -0
- package/.claude/worktrees/kanban-overhaul/CURRENT_ISSUES_ AND_NEW_FEATURES.md +18 -0
- package/.claude/worktrees/kanban-overhaul/DECISIONS.md +66 -0
- package/.claude/worktrees/kanban-overhaul/Dockerfile +48 -0
- package/.claude/worktrees/kanban-overhaul/FINAL_GOAL.md +397 -0
- package/.claude/worktrees/kanban-overhaul/IMPLEMENTATION_PLAN.md +250 -0
- package/.claude/worktrees/kanban-overhaul/LICENSE +21 -0
- package/.claude/worktrees/kanban-overhaul/MILESTONES.md +257 -0
- package/.claude/worktrees/kanban-overhaul/Makefile +93 -0
- package/.claude/worktrees/kanban-overhaul/PROGRESS.md +1406 -0
- package/.claude/worktrees/kanban-overhaul/README.md +483 -0
- package/.claude/worktrees/kanban-overhaul/ROADMAP.md +609 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/.graphifyignore +40 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/.obsidian/README.md +14 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/.obsidian/daily/2026-06-25.md +9 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/.obsidian/vault.json +7 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/.od-skills/web-prototype-e1429c1737/SKILL.md +103 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/.od-skills/web-prototype-e1429c1737/assets/template.html +338 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/.od-skills/web-prototype-e1429c1737/example.html +81 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/.od-skills/web-prototype-e1429c1737/open-design.json +172 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/.od-skills/web-prototype-e1429c1737/references/checklist.md +44 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/.od-skills/web-prototype-e1429c1737/references/layouts.md +247 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/ARCHITECTURE.md +197 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/CHANGELOG.md +235 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/DESIGN.md +912 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/GLYPH.md +418 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/PLAN.md +1135 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/critique.json +26 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/plans/debug-plan/comments.json +1 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/plans/debug-plan/meta.json +10 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/plans/debug-plan/plan.json +174 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/scripts/smoke-bg-retry.mjs +246 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/agent-baseline/SKILL.md +80 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/agent-browser/SKILL.md +181 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/bizar/SKILL.md +116 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/chat/SKILL.md +74 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/eval/SKILL.md +237 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/headroom/SKILL.md +94 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/lightrag/SKILL.md +86 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/minimax/SKILL.md +80 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/obsidian/SKILL.md +68 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/providers/SKILL.md +75 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/publishing/SKILL.md +146 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/sdk/SKILL.md +138 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/self-improvement/SKILL.md +53 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/skills-cli/SKILL.md +94 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/skills/usage/SKILL.md +62 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/cli/dashboard-ports.mjs +488 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/cli.mjs +537 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/activity-log.mjs +174 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/agents-store.mjs +465 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/api.mjs +223 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/artifact-template.html +810 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/artifacts-store.mjs +733 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/auth.mjs +548 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/background-store.mjs +446 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/backup-store.mjs +530 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/bg-poller.mjs +375 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/bg-retry.mjs +446 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/bg-spawner.mjs +390 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/browser.mjs +40 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/claude-bg-spawner.mjs +390 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/claude-info.mjs +412 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/claude-runner.mjs +284 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/claude-sdk.mjs +191 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/diagnostics-store.mjs +598 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/dialog-poller.mjs +105 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/dialog-store.mjs +177 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/digest-store.mjs +558 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/eval-store.mjs +281 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/eval.mjs +500 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/glyphs/mdx-compiler.mjs +596 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/headroom.mjs +649 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/lib/path-safe.mjs +283 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/lib/rate-limit.mjs +122 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/logger.mjs +71 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/memory-consolidator.mjs +225 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/memory-distillation.mjs +296 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/memory-git.mjs +473 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/memory-lightrag.mjs +1478 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/memory-obsidian.mjs +230 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/memory-schema.mjs +145 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/memory-secrets.mjs +84 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/memory-store.mjs +1093 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/metrics.mjs +268 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/minimax-usage-store.mjs +372 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/minimax.mjs +683 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/mod-security.mjs +398 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/mods-loader.mjs +1243 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/notifications-store.mjs +243 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/obsidian-store.mjs +318 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/ocr.mjs +55 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/otel.mjs +260 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/pair-store.mjs +138 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/progress-parser.mjs +221 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/projects-store.mjs +364 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/providers-store.mjs +1801 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/_shared.mjs +447 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/activity.mjs +195 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/agents-cc.mjs +194 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/agents.mjs +134 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/artifacts.mjs +279 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/auth.mjs +69 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/background.mjs +422 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/backup.mjs +112 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/chat.mjs +727 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/claude-session-detail.mjs +329 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/claude-sessions.mjs +259 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/clipboard.mjs +173 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/config.mjs +180 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/diagnostics.mjs +50 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/dialogs.mjs +86 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/digests.mjs +82 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/distill.mjs +129 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/doctor.mjs +71 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/env-vars.mjs +231 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/eval.mjs +187 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/fs.mjs +429 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/goal-planner.mjs +236 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/goals.mjs +212 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/headroom.mjs +126 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/history.mjs +78 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/lightrag.mjs +169 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/memory.mjs +1524 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/minimax.mjs +133 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/misc.mjs +90 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/mods.mjs +359 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/notifications.mjs +54 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/obsidian.mjs +239 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/ocr.mjs +182 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/overview.mjs +92 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/pair.mjs +67 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/projects.mjs +175 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/providers.mjs +308 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/schedules.mjs +159 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/settings.mjs +51 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/skills.mjs +65 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/tailscale.mjs +46 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/tasks.mjs +518 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/themes.mjs +51 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/update.mjs +340 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/usage.mjs +136 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/users.mjs +102 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/voice.mjs +167 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes/workspaces.mjs +299 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes-v2/auth.mjs +59 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes-v2/events.mjs +121 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes-v2/health.mjs +21 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes-v2/index.mjs +90 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/routes-v2/sessions.mjs +111 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/schedules-runner.mjs +556 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/schedules-store.mjs +268 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/search-store.mjs +220 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/serve-info.mjs +1110 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/server.mjs +966 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/settings-store.mjs +45 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/skills-store.mjs +190 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/state.mjs +437 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/tailscale-store.mjs +113 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/task-delegator.mjs +969 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/tasks-store.mjs +556 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/tui.mjs +923 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/update-store.mjs +168 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/v2-auth-file.mjs +99 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/v2-event-bus.mjs +128 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/voice-store.mjs +229 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/voice-transcribe.mjs +72 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/watcher.mjs +81 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/workers/transcription-worker.mjs +213 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/workspaces.mjs +626 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/server/yaml.mjs +238 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/App.tsx +200 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/data/fetcher.ts +59 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/data/types.ts +168 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/data/useFetch.ts +62 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/data/useWebSocket.ts +153 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/main.tsx +28 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/shell/AppShell.tsx +90 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/shell/PageSkeleton.tsx +29 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/shell/Sidebar.tsx +361 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/shell/StatusBar.tsx +63 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/shell/Topbar.tsx +113 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/shell/index.ts +15 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/activity/ActivityFeed.tsx +137 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/agents/AgentActivity.tsx +101 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/agents/AgentCard.tsx +158 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/agents/AgentDetail.tsx +232 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/Button.tsx +141 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/ButtonGroup.tsx +32 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/Checkbox.tsx +49 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/Field.tsx +78 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/Form.tsx +23 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/IconButton.tsx +112 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/Input.tsx +94 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/RadioGroup.tsx +74 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/Select.tsx +171 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/Slider.tsx +68 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/Switch.tsx +56 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/Textarea.tsx +64 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/Toggle.tsx +36 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/controls/ToggleGroup.tsx +85 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/Accordion.tsx +134 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/Avatar.tsx +175 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/Badge.tsx +93 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/BarList.tsx +101 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/Card.tsx +140 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/Chip.tsx +96 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/Kbd.tsx +42 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/ProgressBar.tsx +93 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/Sparkline.tsx +98 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/StatTile.tsx +150 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/Table.tsx +170 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/Timeline.tsx +130 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/data/ViewHeader.tsx +122 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/Alert.tsx +95 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/Banner.tsx +39 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/ContextMenu.tsx +143 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/Dialog.tsx +149 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/Drawer.tsx +8 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/DropdownMenu.tsx +231 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/EmptyState.tsx +48 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/Popover.tsx +56 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/Sheet.tsx +103 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/Skeleton.tsx +67 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/Spinner.tsx +30 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/Toast.tsx +66 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/feedback/Tooltip.tsx +89 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/goals/GoalCard.tsx +176 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/goals/GoalDetail.tsx +245 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/goals/KeyResult.tsx +115 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/index.ts +349 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/kanban/KanbanBoard.tsx +115 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/kanban/KanbanCard.tsx +391 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/kanban/KanbanCardBadges.tsx +111 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/kanban/KanbanColumn.tsx +181 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/kanban/KanbanContextMenu.tsx +126 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/kanban/KanbanDetailDialog.tsx +638 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/kanban/KanbanEmptyColumn.tsx +43 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/kanban/KanbanProgress.tsx +130 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/kanban/KanbanQuickAdd.tsx +141 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/kanban/KanbanToolbar.tsx +291 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/kanban/useKanbanSelection.ts +90 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/libraries/LibraryGrid.tsx +30 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/libraries/LibraryItem.tsx +161 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/memory/MemoryVault.tsx +144 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/navigation/CommandPalette.tsx +224 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/navigation/NavLink.tsx +81 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/navigation/Pagination.tsx +164 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/navigation/Tabs.tsx +128 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/primitives/Box.tsx +144 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/primitives/Center.tsx +40 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/primitives/Cluster.tsx +67 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/primitives/Grid.tsx +104 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/primitives/Inline.tsx +77 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/primitives/Portal.tsx +33 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/primitives/ScrollArea.tsx +62 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/primitives/Separator.tsx +42 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/primitives/Stack.tsx +73 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/primitives/VisuallyHidden.tsx +49 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/settings/SettingsNav.tsx +91 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/settings/SettingsRow.tsx +88 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/settings/SettingsSection.tsx +109 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/styles/globals.css +220 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/styles/reset.css +57 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/styles/tokens.css +217 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/theme/DensityProvider.tsx +66 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/theme/ThemeProvider.tsx +94 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/theme/ThemeToggle.tsx +88 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/theme/useDensity.ts +15 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/theme/useTheme.ts +16 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/ui/utils/cx.ts +19 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/views/Activity/ActivityView.tsx +71 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/views/Agents/AgentsView.tsx +172 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/views/CommandPalette/AppCommandPalette.tsx +247 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/views/Goals/GoalsView.tsx +137 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/views/Libraries/LibrariesView.tsx +108 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/views/Memory/MemoryView.tsx +77 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/views/Overview/OverviewView.tsx +152 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/views/Router.tsx +72 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/views/Settings/SettingsView.tsx +330 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/views/Tasks/CommandPalettePlaceholder.tsx +106 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/views/Tasks/TasksView.tsx +792 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8/vite-env.d.ts +15 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/src/web/v8.html +17 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/templates/mod/FORMAT.md +76 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/templates/mod/hello-mod/README.md +19 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/templates/mod/hello-mod/agents/greeter.md +8 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/templates/mod/hello-mod/commands/hello.md +6 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/templates/mod/hello-mod/mod.json +20 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/templates/mod/hello-mod/routes/ping.mjs +9 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/templates/mod/hello-mod/views/HelloView.tsx +10 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/tests/setup.ts +63 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/tests/smoke-v2.mjs +212 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/tsconfig.json +23 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/vite.config.ts +66 -0
- package/.claude/worktrees/kanban-overhaul/bizar-dash/vitest.config.ts +20 -0
- package/.claude/worktrees/kanban-overhaul/bizar-plugins/registry.json +62 -0
- package/.claude/worktrees/kanban-overhaul/bookmarklet/bizar-clipper.js +48 -0
- package/.claude/worktrees/kanban-overhaul/browser-extensions/bizar-clipper/README.md +43 -0
- package/.claude/worktrees/kanban-overhaul/browser-extensions/bizar-clipper/background.js +95 -0
- package/.claude/worktrees/kanban-overhaul/browser-extensions/bizar-clipper/content.js +170 -0
- package/.claude/worktrees/kanban-overhaul/browser-extensions/bizar-clipper/icons/icon-128.png +0 -0
- package/.claude/worktrees/kanban-overhaul/browser-extensions/bizar-clipper/icons/icon-16.png +0 -0
- package/.claude/worktrees/kanban-overhaul/browser-extensions/bizar-clipper/icons/icon-48.png +0 -0
- package/.claude/worktrees/kanban-overhaul/browser-extensions/bizar-clipper/icons/icon.svg +4 -0
- package/.claude/worktrees/kanban-overhaul/browser-extensions/bizar-clipper/manifest.json +32 -0
- package/.claude/worktrees/kanban-overhaul/browser-extensions/bizar-clipper/popup.html +66 -0
- package/.claude/worktrees/kanban-overhaul/browser-extensions/bizar-clipper/popup.js +110 -0
- package/.claude/worktrees/kanban-overhaul/bun.lock +1558 -0
- package/.claude/worktrees/kanban-overhaul/cli/agent-browser-up.sh +152 -0
- package/.claude/worktrees/kanban-overhaul/cli/agent-browser-update.mjs +322 -0
- package/.claude/worktrees/kanban-overhaul/cli/artifact-cli.mjs +605 -0
- package/.claude/worktrees/kanban-overhaul/cli/artifact-render.mjs +621 -0
- package/.claude/worktrees/kanban-overhaul/cli/artifact-server.mjs +847 -0
- package/.claude/worktrees/kanban-overhaul/cli/artifact-templates.mjs +523 -0
- package/.claude/worktrees/kanban-overhaul/cli/artifact.mjs +63 -0
- package/.claude/worktrees/kanban-overhaul/cli/atomic.mjs +73 -0
- package/.claude/worktrees/kanban-overhaul/cli/audit.mjs +141 -0
- package/.claude/worktrees/kanban-overhaul/cli/banner.mjs +41 -0
- package/.claude/worktrees/kanban-overhaul/cli/bg.mjs +471 -0
- package/.claude/worktrees/kanban-overhaul/cli/bin.mjs +698 -0
- package/.claude/worktrees/kanban-overhaul/cli/bootstrap.mjs +77 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/artifact.mjs +20 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/claim.mjs +282 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/claude-cmd.mjs +348 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/clip.mjs +163 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/cost.mjs +279 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/dash.mjs +193 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/deploy/cloudflare.mjs +250 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/deploy/docker.mjs +222 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/deploy/fly.mjs +161 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/deploy/vercel.mjs +225 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/deploy.mjs +240 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/eval.mjs +396 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/headroom.mjs +204 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/install.mjs +170 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/lightrag.mjs +170 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/marketplace.mjs +64 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/memory.mjs +25 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/minimax.mjs +288 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/mod.mjs +185 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/ocr.mjs +182 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/plugin.mjs +358 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/rca.mjs +198 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/sandbox.mjs +220 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/service.mjs +79 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/setup-provider.mjs +466 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/tailscale.mjs +258 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/usage.mjs +113 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/util.mjs +577 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/validate.mjs +541 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/voice.mjs +211 -0
- package/.claude/worktrees/kanban-overhaul/cli/commands/workspace.mjs +247 -0
- package/.claude/worktrees/kanban-overhaul/cli/copy.mjs +586 -0
- package/.claude/worktrees/kanban-overhaul/cli/cost-gate.mjs +501 -0
- package/.claude/worktrees/kanban-overhaul/cli/dev-link.mjs +191 -0
- package/.claude/worktrees/kanban-overhaul/cli/digest.mjs +149 -0
- package/.claude/worktrees/kanban-overhaul/cli/doctor.mjs +217 -0
- package/.claude/worktrees/kanban-overhaul/cli/export.mjs +95 -0
- package/.claude/worktrees/kanban-overhaul/cli/feature-list-bridge.mjs +400 -0
- package/.claude/worktrees/kanban-overhaul/cli/heads-up.mjs +295 -0
- package/.claude/worktrees/kanban-overhaul/cli/init.mjs +368 -0
- package/.claude/worktrees/kanban-overhaul/cli/install.mjs +640 -0
- package/.claude/worktrees/kanban-overhaul/cli/memory-constants.mjs +76 -0
- package/.claude/worktrees/kanban-overhaul/cli/memory.mjs +1850 -0
- package/.claude/worktrees/kanban-overhaul/cli/plugin-runtime-deps.mjs +250 -0
- package/.claude/worktrees/kanban-overhaul/cli/post-install-smoke.mjs +256 -0
- package/.claude/worktrees/kanban-overhaul/cli/prompts.mjs +168 -0
- package/.claude/worktrees/kanban-overhaul/cli/providers-detect.mjs +233 -0
- package/.claude/worktrees/kanban-overhaul/cli/provision-claude.mjs +1176 -0
- package/.claude/worktrees/kanban-overhaul/cli/provision.mjs +2233 -0
- package/.claude/worktrees/kanban-overhaul/cli/repair.mjs +209 -0
- package/.claude/worktrees/kanban-overhaul/cli/service-controller.mjs +927 -0
- package/.claude/worktrees/kanban-overhaul/cli/service-env.mjs +139 -0
- package/.claude/worktrees/kanban-overhaul/cli/service.mjs +492 -0
- package/.claude/worktrees/kanban-overhaul/cli/update.mjs +29 -0
- package/.claude/worktrees/kanban-overhaul/cli/utils.mjs +221 -0
- package/.claude/worktrees/kanban-overhaul/cli/worker-dispatcher.mjs +259 -0
- package/.claude/worktrees/kanban-overhaul/config/AGENTS.md +595 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/_shared/AGENT_BASELINE.md +155 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/_shared/CLINE_TOOLS.md +398 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/_shared/SKILLS.md +109 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/agent-browser.md +90 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/baldr.md +60 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/forseti.md +60 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/frigg.md +52 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/heimdall.md +44 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/hermod.md +64 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/mimir.md +60 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/odin.md +310 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/quick.md +47 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/semble-search.md +59 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/thor.md +64 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/tyr.md +67 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/vidarr.md +65 -0
- package/.claude/worktrees/kanban-overhaul/config/agents/vor.md +62 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/audit.md +5 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/bizar.md +22 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/explain.md +5 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/init.md +26 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/learn.md +5 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/plan.md +30 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/plow-through.md +47 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/pr-review.md +5 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/setup-provider.md +95 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/tailscale-serve.md +97 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/team.md +124 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/test.md +60 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/validate.md +66 -0
- package/.claude/worktrees/kanban-overhaul/config/commands/visual-plan.md +19 -0
- package/.claude/worktrees/kanban-overhaul/config/hooks/PostToolUse +66 -0
- package/.claude/worktrees/kanban-overhaul/config/hooks/PreToolUse +82 -0
- package/.claude/worktrees/kanban-overhaul/config/hooks/README.md +68 -0
- package/.claude/worktrees/kanban-overhaul/config/hooks/TaskResume +48 -0
- package/.claude/worktrees/kanban-overhaul/config/hooks/TaskStart +47 -0
- package/.claude/worktrees/kanban-overhaul/config/hooks/UserPromptSubmit +55 -0
- package/.claude/worktrees/kanban-overhaul/config/rules/general.md +9 -0
- package/.claude/worktrees/kanban-overhaul/config/rules/git.md +11 -0
- package/.claude/worktrees/kanban-overhaul/config/rules/javascript.md +10 -0
- package/.claude/worktrees/kanban-overhaul/config/rules/python.md +10 -0
- package/.claude/worktrees/kanban-overhaul/config/rules/testing.md +10 -0
- package/.claude/worktrees/kanban-overhaul/config/rules/thinking.md +56 -0
- package/.claude/worktrees/kanban-overhaul/config/rules/uncertainty.md +70 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/9router/SKILL.md +80 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/9router-chat/SKILL.md +73 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/9router-embeddings/SKILL.md +69 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/9router-image/SKILL.md +86 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/9router-stt/SKILL.md +79 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/9router-tts/SKILL.md +80 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/9router-web-fetch/SKILL.md +99 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/9router-web-search/SKILL.md +91 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/bizar/README.md +9 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/bizar/SKILL.md +447 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-coding-standards/README.md +28 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-coding-standards/SKILL.md +634 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-coding-standards/agents/openai.yaml +4 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-coding-standards/references/concurrency.md +320 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-coding-standards/references/error-handling.md +229 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-coding-standards/references/memory-safety.md +216 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-coding-standards/references/modern-idioms.md +282 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-coding-standards/references/review-checklist.md +96 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-testing/README.md +28 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-testing/SKILL.md +304 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-testing/agents/openai.yaml +4 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-testing/references/coverage.md +370 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-testing/references/framework-compare.md +175 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-testing/references/host-test-for-embedded.md +499 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-testing/references/mocking.md +364 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cpp-testing/references/tdd-workflow.md +308 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/cubesandbox/SKILL.md +148 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/README.md +41 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/SKILL.md +439 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/agents/openai.yaml +4 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/references/freertos-patterns.md +214 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/references/host-tests.md +164 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/references/idf-py-commands.md +157 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/references/kconfig.md +159 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/references/logging-discipline.md +118 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/references/memory-and-iram.md +137 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/references/nvs.md +121 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/references/packed-structs.md +192 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/scripts/idf_env.sh +47 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/embedded-esp-idf/scripts/size_check.sh +77 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/glyph/SKILL.md +163 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/harness-engineering/SKILL.md +142 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/lightrag/SKILL.md +81 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/memory-protocol/SKILL.md +105 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/obsidian/SKILL.md +306 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/read-the-damn-docs/SKILL.md +113 -0
- package/.claude/worktrees/kanban-overhaul/config/skills/self-improvement/SKILL.md +64 -0
- package/.claude/worktrees/kanban-overhaul/config/trigger-patterns.json +186 -0
- package/.claude/worktrees/kanban-overhaul/docker-compose.yml +50 -0
- package/.claude/worktrees/kanban-overhaul/docs/A11Y.md +81 -0
- package/.claude/worktrees/kanban-overhaul/docs/DEPLOY.md +360 -0
- package/.claude/worktrees/kanban-overhaul/docs/DOCKER.md +250 -0
- package/.claude/worktrees/kanban-overhaul/docs/INDEX.md +223 -0
- package/.claude/worktrees/kanban-overhaul/docs/PLUGIN_REGISTRY.md +107 -0
- package/.claude/worktrees/kanban-overhaul/docs/RELEASING.md +693 -0
- package/.claude/worktrees/kanban-overhaul/docs/architecture.md +317 -0
- package/.claude/worktrees/kanban-overhaul/docs/code-review.md +242 -0
- package/.claude/worktrees/kanban-overhaul/docs/curator.md +144 -0
- package/.claude/worktrees/kanban-overhaul/docs/dashboard-ui-migration.md +807 -0
- package/.claude/worktrees/kanban-overhaul/docs/decisions/DEC-001-cline-rewrite.md +114 -0
- package/.claude/worktrees/kanban-overhaul/docs/decisions/DEC-002-in-process-clinecore.md +139 -0
- package/.claude/worktrees/kanban-overhaul/docs/decisions/DEC-003-in-process-memory-vault.md +101 -0
- package/.claude/worktrees/kanban-overhaul/docs/decisions/DEC-004-cline-agent-teams.md +112 -0
- package/.claude/worktrees/kanban-overhaul/docs/decisions/DEC-005-bg-agents-via-dashboard.md +77 -0
- package/.claude/worktrees/kanban-overhaul/docs/decisions/DEC-006-kanban-board.md +69 -0
- package/.claude/worktrees/kanban-overhaul/docs/decisions/DEC-007-tool-approval-gate.md +147 -0
- package/.claude/worktrees/kanban-overhaul/docs/decisions/DEC-008-skill-curator.md +100 -0
- package/.claude/worktrees/kanban-overhaul/docs/decisions/DEC-009-pre-compaction-flush.md +106 -0
- package/.claude/worktrees/kanban-overhaul/docs/decisions/DEC-010-knowledge-graph-tools.md +95 -0
- package/.claude/worktrees/kanban-overhaul/docs/decisions/DEC-011-claude-code-migration.md +172 -0
- package/.claude/worktrees/kanban-overhaul/docs/graph-tools.md +130 -0
- package/.claude/worktrees/kanban-overhaul/docs/migration-guide.md +471 -0
- package/.claude/worktrees/kanban-overhaul/docs/migrations/cline-replacement.md +118 -0
- package/.claude/worktrees/kanban-overhaul/docs/postmortems/2026-06-18-plugin-state-deadlock.md +250 -0
- package/.claude/worktrees/kanban-overhaul/docs/quality-document.md +74 -0
- package/.claude/worktrees/kanban-overhaul/docs/releases/v0.5.2.md +66 -0
- package/.claude/worktrees/kanban-overhaul/docs/releases/v0.5.4.md +85 -0
- package/.claude/worktrees/kanban-overhaul/docs/releases/v2.3.0.md +96 -0
- package/.claude/worktrees/kanban-overhaul/docs/releases/v3.24.0.md +155 -0
- package/.claude/worktrees/kanban-overhaul/docs/releases/v4.0.0.md +123 -0
- package/.claude/worktrees/kanban-overhaul/docs/releases/v7.0.0.md +173 -0
- package/.claude/worktrees/kanban-overhaul/docs/safety.md +216 -0
- package/.claude/worktrees/kanban-overhaul/feature_list.json +1297 -0
- package/.claude/worktrees/kanban-overhaul/init.sh +211 -0
- package/.claude/worktrees/kanban-overhaul/install.sh +498 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/impeccable/INSTRUCTIONS.md +82 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/impeccable/mod.json +37 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/impeccable/route.mjs +136 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/impeccable/web/index.html +180 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/lightrag/INSTRUCTIONS.md +81 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/lightrag/mod.json +61 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/lightrag/route.mjs +461 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/lightrag/web/index.html +263 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/ponytail/INSTRUCTIONS.md +87 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/ponytail/agents/thor.md +64 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/ponytail/mod.json +36 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/ponytail/route.mjs +98 -0
- package/.claude/worktrees/kanban-overhaul/mods-examples/ponytail/web/index.html +126 -0
- package/.claude/worktrees/kanban-overhaul/package.json +154 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/ARCHITECTURE.md +70 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/LICENSE +21 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/README.md +80 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/package.json +30 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/agent-registry.ts +304 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/consensus/byzantine.ts +587 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/consensus/index.ts +147 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/consensus/queen.ts +173 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/consensus/types.ts +199 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/dangerous-patterns.ts +127 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/federation/audit.ts +156 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/federation/budget.ts +269 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/federation/envelope.ts +144 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/federation/hmac.ts +160 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/federation/index.ts +443 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/federation/pii.ts +241 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/federation/policy.ts +112 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/federation/trust.ts +146 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/fingerprint.ts +0 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/index.ts +114 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/mcp/bin.ts +51 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/mcp/server.ts +848 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/memory/index.ts +160 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/router/codemod-intent.ts +125 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/router/index.ts +247 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/router/memory-distillation-shim.mjs +18 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/router/memory-distillation.ts +249 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/router/model-router.ts +235 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/router/q-learning-router.ts +304 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/swarm-topology.ts +279 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/src/version.ts +4 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/tsconfig.json +25 -0
- package/.claude/worktrees/kanban-overhaul/packages/sdk/vitest.config.ts +9 -0
- package/.claude/worktrees/kanban-overhaul/plugins/bizar/ARCHITECTURE.md +72 -0
- package/.claude/worktrees/kanban-overhaul/plugins/bizar/CONSTRAINTS.md +62 -0
- package/.claude/worktrees/kanban-overhaul/plugins/bizar/LICENSE +21 -0
- package/.claude/worktrees/kanban-overhaul/plugins/bizar/README.md +46 -0
- package/.claude/worktrees/kanban-overhaul/plugins/bizar/index.ts +50 -0
- package/.claude/worktrees/kanban-overhaul/plugins/bizar/package.json +18 -0
- package/.claude/worktrees/kanban-overhaul/plugins/bizar/tsconfig.json +29 -0
- package/.claude/worktrees/kanban-overhaul/scripts/bh-full-e2e.mjs +298 -0
- package/.claude/worktrees/kanban-overhaul/scripts/check-agents.mjs +73 -0
- package/.claude/worktrees/kanban-overhaul/scripts/check-arch.sh +80 -0
- package/.claude/worktrees/kanban-overhaul/scripts/check-deps.mjs +492 -0
- package/.claude/worktrees/kanban-overhaul/scripts/clean-state-check.sh +81 -0
- package/.claude/worktrees/kanban-overhaul/scripts/git-hooks/pre-commit +59 -0
- package/.claude/worktrees/kanban-overhaul/scripts/git-hooks/pre-push +54 -0
- package/.claude/worktrees/kanban-overhaul/scripts/install-hooks.sh +29 -0
- package/.claude/worktrees/kanban-overhaul/scripts/install-service.mjs +190 -0
- package/.claude/worktrees/kanban-overhaul/scripts/mirror-claude-md.sh +78 -0
- package/.claude/worktrees/kanban-overhaul/scripts/session-trace.sh +52 -0
- package/.claude/worktrees/kanban-overhaul/scripts/test-in-container.sh +157 -0
- package/.claude/worktrees/kanban-overhaul/scripts/verify-feature.sh +102 -0
- package/.claude/worktrees/kanban-overhaul/skills-lock.json +11 -0
- package/.claude/worktrees/kanban-overhaul/templates/clean-state-checklist.md +55 -0
- package/.claude/worktrees/kanban-overhaul/templates/deploy/cloudflare/README.md +32 -0
- package/.claude/worktrees/kanban-overhaul/templates/deploy/cloudflare/functions-index.template.js +15 -0
- package/.claude/worktrees/kanban-overhaul/templates/deploy/cloudflare/wrangler.toml.template +9 -0
- package/.claude/worktrees/kanban-overhaul/templates/deploy/docker/.env.template +16 -0
- package/.claude/worktrees/kanban-overhaul/templates/deploy/docker/README.md +58 -0
- package/.claude/worktrees/kanban-overhaul/templates/deploy/docker/docker-compose.template.yml +23 -0
- package/.claude/worktrees/kanban-overhaul/templates/deploy/fly/README.md +35 -0
- package/.claude/worktrees/kanban-overhaul/templates/deploy/fly/fly.toml.template +28 -0
- package/.claude/worktrees/kanban-overhaul/templates/deploy/vercel/README.md +29 -0
- package/.claude/worktrees/kanban-overhaul/templates/deploy/vercel/api-index.template.js +18 -0
- package/.claude/worktrees/kanban-overhaul/templates/deploy/vercel/vercel.json.template +16 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/README.md +58 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/citation.json +16 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/code-review.json +16 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/code-search-basic.json +28 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/concise-output.json +16 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/context-window.json +16 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/error-recovery.json +16 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/json-output.json +20 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/latency-bounds.json +16 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/multi-language.json +16 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/regression-suite.json +79 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/response-format.json +30 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/safe-paths.json +16 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/tool-call-correctness.json +24 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/tool-call-multi-step.json +18 -0
- package/.claude/worktrees/kanban-overhaul/templates/eval-fixtures/unicode-handling.json +16 -0
- package/.claude/worktrees/kanban-overhaul/templates/evaluator-rubric.md +50 -0
- package/.claude/worktrees/kanban-overhaul/templates/plan/htmx.min.js +1 -0
- package/.claude/worktrees/kanban-overhaul/templates/plan/library/bug-investigation.mdx +79 -0
- package/.claude/worktrees/kanban-overhaul/templates/plan/library/decision-record.mdx +71 -0
- package/.claude/worktrees/kanban-overhaul/templates/plan/library/feature-design.mdx +92 -0
- package/.claude/worktrees/kanban-overhaul/templates/plan/meta.json.template +8 -0
- package/.claude/worktrees/kanban-overhaul/templates/plan/plan.mdx.template +46 -0
- package/.claude/worktrees/kanban-overhaul/templates/plugin-template/README.md +121 -0
- package/.claude/worktrees/kanban-overhaul/templates/plugin-template/index.js +66 -0
- package/.claude/worktrees/kanban-overhaul/templates/plugin-template/plugin.json +42 -0
- package/.claude/worktrees/kanban-overhaul/templates/plugin-template/tests/plugin.test.js +83 -0
- package/.claude/worktrees/kanban-overhaul/templates/schedules/daily-backup.json +12 -0
- package/.claude/worktrees/kanban-overhaul/templates/schedules/daily-cleanup.json +12 -0
- package/.claude/worktrees/kanban-overhaul/templates/schedules/hourly-health-check.json +12 -0
- package/.claude/worktrees/kanban-overhaul/templates/schedules/webhook-on-push.json +13 -0
- package/.claude/worktrees/kanban-overhaul/templates/schedules/weekly-digest.json +13 -0
- package/.claude/worktrees/kanban-overhaul/templates/sprint-contract.md +47 -0
- package/.claude/worktrees/kanban-overhaul/tsconfig.json +44 -0
- package/.claude/worktrees/kanban-overhaul/vite.config.ts +51 -0
- package/bizar-dash/dist/assets/ActivityFeed-BXIkGGQ1.js +16 -0
- package/bizar-dash/dist/assets/ActivityFeed-BXIkGGQ1.js.map +1 -0
- package/bizar-dash/dist/assets/ActivityView-CBxNNrZa.js +12 -0
- package/bizar-dash/dist/assets/ActivityView-CBxNNrZa.js.map +1 -0
- package/bizar-dash/dist/assets/AgentsView-uv4l21AH.js +23 -0
- package/bizar-dash/dist/assets/AgentsView-uv4l21AH.js.map +1 -0
- package/bizar-dash/dist/assets/BackgroundJobsView-CB4WXIpk.js +6 -0
- package/bizar-dash/dist/assets/BackgroundJobsView-CB4WXIpk.js.map +1 -0
- package/bizar-dash/dist/assets/{Card-C_bvqXdQ.js → Card-CeZsWlcP.js} +1 -1
- package/bizar-dash/dist/assets/{Card-C_bvqXdQ.js.map → Card-CeZsWlcP.js.map} +1 -1
- package/bizar-dash/dist/assets/Chip-OPjSKl2I.js +1 -0
- package/bizar-dash/dist/assets/Chip-OPjSKl2I.js.map +1 -0
- package/bizar-dash/dist/assets/{EmptyState-BWQuKnk9.js → EmptyState-BrLA8mbE.js} +1 -1
- package/bizar-dash/dist/assets/{EmptyState-BWQuKnk9.js.map → EmptyState-BrLA8mbE.js.map} +1 -1
- package/bizar-dash/dist/assets/GoalsView-B8R-kxQr.js +11 -0
- package/bizar-dash/dist/assets/GoalsView-B8R-kxQr.js.map +1 -0
- package/bizar-dash/dist/assets/{Grid-C62gCPqt.js → Grid-B7NgNtff.js} +1 -1
- package/bizar-dash/dist/assets/{Grid-C62gCPqt.js.map → Grid-B7NgNtff.js.map} +1 -1
- package/bizar-dash/dist/assets/Input-BW_5Sl6N.js +1 -0
- package/bizar-dash/dist/assets/Input-BW_5Sl6N.js.map +1 -0
- package/bizar-dash/dist/assets/KanbanCard-B-NOSfMN.js +21 -0
- package/bizar-dash/dist/assets/KanbanCard-B-NOSfMN.js.map +1 -0
- package/bizar-dash/dist/assets/LibrariesView-D6eB7B2A.js +67 -0
- package/bizar-dash/dist/assets/LibrariesView-D6eB7B2A.js.map +1 -0
- package/bizar-dash/dist/assets/MemoryView-MK4m1KbR.js +13 -0
- package/bizar-dash/dist/assets/MemoryView-MK4m1KbR.js.map +1 -0
- package/bizar-dash/dist/assets/OverviewView-CHavfYBa.js +1 -0
- package/bizar-dash/dist/assets/OverviewView-CHavfYBa.js.map +1 -0
- package/bizar-dash/dist/assets/SchedulesView-zV-0pbsz.js +1 -0
- package/bizar-dash/dist/assets/SchedulesView-zV-0pbsz.js.map +1 -0
- package/bizar-dash/dist/assets/Select-B6Ho36Tq.js +11 -0
- package/bizar-dash/dist/assets/Select-B6Ho36Tq.js.map +1 -0
- package/bizar-dash/dist/assets/SettingsRow-Br21uRFz.js +1 -0
- package/bizar-dash/dist/assets/SettingsRow-Br21uRFz.js.map +1 -0
- package/bizar-dash/dist/assets/SettingsView-Cx3uJrus.js +38 -0
- package/bizar-dash/dist/assets/SettingsView-Cx3uJrus.js.map +1 -0
- package/bizar-dash/dist/assets/Sheet-Cmu_4Zea.js +1 -0
- package/bizar-dash/dist/assets/Sheet-Cmu_4Zea.js.map +1 -0
- package/bizar-dash/dist/assets/Slider-B_jPr-SR.js +1 -0
- package/bizar-dash/dist/assets/Slider-B_jPr-SR.js.map +1 -0
- package/bizar-dash/dist/assets/Sparkline-Cmqw0N39.js +1 -0
- package/bizar-dash/dist/assets/Sparkline-Cmqw0N39.js.map +1 -0
- package/bizar-dash/dist/assets/Switch-C7Qyu50Y.js +10 -0
- package/bizar-dash/dist/assets/Switch-C7Qyu50Y.js.map +1 -0
- package/bizar-dash/dist/assets/TasksView-BXADmjgb.js +1 -0
- package/bizar-dash/dist/assets/TasksView-BXADmjgb.js.map +1 -0
- package/bizar-dash/dist/assets/Textarea-KIN98DVH.js +1 -0
- package/bizar-dash/dist/assets/Textarea-KIN98DVH.js.map +1 -0
- package/bizar-dash/dist/assets/{ViewHeader-D6c2cw1b.js → ViewHeader-CPbqI-w8.js} +1 -1
- package/bizar-dash/dist/assets/{ViewHeader-D6c2cw1b.js.map → ViewHeader-CPbqI-w8.js.map} +1 -1
- package/bizar-dash/dist/assets/{brain-DeoXNDE2.js → brain-jN_ldx3U.js} +1 -1
- package/bizar-dash/dist/assets/{brain-DeoXNDE2.js.map → brain-jN_ldx3U.js.map} +1 -1
- package/bizar-dash/dist/assets/{calendar-DRlQkGJc.js → calendar-DZGgPP2_.js} +2 -2
- package/bizar-dash/dist/assets/{calendar-DRlQkGJc.js.map → calendar-DZGgPP2_.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-check-DmYQ3vGp.js → circle-check-XhUtiACZ.js} +1 -1
- package/bizar-dash/dist/assets/{circle-check-DmYQ3vGp.js.map → circle-check-XhUtiACZ.js.map} +1 -1
- package/bizar-dash/dist/assets/clock-BXBnSbox.js +6 -0
- package/bizar-dash/dist/assets/clock-BXBnSbox.js.map +1 -0
- package/bizar-dash/dist/assets/{cmdk-BwN8hcKQ.js → cmdk-D15rXxc5.js} +2 -2
- package/bizar-dash/dist/assets/{cmdk-BwN8hcKQ.js.map → cmdk-D15rXxc5.js.map} +1 -1
- package/bizar-dash/dist/assets/dnd-kit-Bormfg7j.js +5 -0
- package/bizar-dash/dist/assets/{dnd-kit-DR2Qzzxk.js.map → dnd-kit-Bormfg7j.js.map} +1 -1
- package/bizar-dash/dist/assets/git-pull-request-BCt0CEjc.js +11 -0
- package/bizar-dash/dist/assets/git-pull-request-BCt0CEjc.js.map +1 -0
- package/bizar-dash/dist/assets/index-C0JBGB5M.js +1 -0
- package/bizar-dash/dist/assets/index-C0JBGB5M.js.map +1 -0
- package/bizar-dash/dist/assets/index-CrWI7sQR.js +1 -0
- package/bizar-dash/dist/assets/index-CrWI7sQR.js.map +1 -0
- package/bizar-dash/dist/assets/main-CCimEcWH.js +134 -0
- package/bizar-dash/dist/assets/main-CCimEcWH.js.map +1 -0
- package/bizar-dash/dist/assets/{main-COdgjqbZ.css → main-CcQfRfIJ.css} +1 -1
- package/bizar-dash/dist/assets/{minus-CrStJTZ7.js → play-B0rTjpSg.js} +2 -2
- package/bizar-dash/dist/assets/play-B0rTjpSg.js.map +1 -0
- package/bizar-dash/dist/assets/plus-BaTQsS9G.js +6 -0
- package/bizar-dash/dist/assets/plus-BaTQsS9G.js.map +1 -0
- package/bizar-dash/dist/assets/refresh-cw-CoatVcs3.js +6 -0
- package/bizar-dash/dist/assets/refresh-cw-CoatVcs3.js.map +1 -0
- package/bizar-dash/dist/assets/terminal-k-1HFHcN.js +11 -0
- package/bizar-dash/dist/assets/terminal-k-1HFHcN.js.map +1 -0
- package/bizar-dash/dist/assets/trash-2-DtpKnAn2.js +6 -0
- package/bizar-dash/dist/assets/trash-2-DtpKnAn2.js.map +1 -0
- package/bizar-dash/dist/assets/triangle-alert-FHSs_e5b.js +6 -0
- package/bizar-dash/dist/assets/triangle-alert-FHSs_e5b.js.map +1 -0
- package/bizar-dash/dist/assets/{wrench-BJ1WIC4u.js → wrench-CbBE0oQ0.js} +2 -2
- package/bizar-dash/dist/assets/{wrench-BJ1WIC4u.js.map → wrench-CbBE0oQ0.js.map} +1 -1
- package/bizar-dash/dist/v8.html +3 -3
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/server/api.mjs +15 -0
- package/bizar-dash/src/server/bg-poller.mjs +81 -1
- package/bizar-dash/src/server/bg-poller.test.mjs +28 -0
- package/bizar-dash/src/server/progress-parser.mjs +237 -0
- package/bizar-dash/src/server/progress-parser.test.mjs +105 -0
- package/bizar-dash/src/server/routes/agents-cc.mjs +381 -0
- package/bizar-dash/src/server/routes/agents-cc.test.mjs +35 -0
- package/bizar-dash/src/server/routes/goals.mjs +307 -0
- package/bizar-dash/src/server/routes/spawn.mjs +59 -0
- package/bizar-dash/src/server/routes/tasks.mjs +11 -0
- package/bizar-dash/src/server/server.mjs +1 -1
- package/bizar-dash/src/web/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/web/v8/App.tsx +56 -7
- package/bizar-dash/src/web/v8/__tests__/App.test.tsx +2 -2
- package/bizar-dash/src/web/v8/__tests__/BackgroundJobsView.test.tsx +172 -0
- package/bizar-dash/src/web/v8/__tests__/MemoryView.test.tsx +91 -0
- package/bizar-dash/src/web/v8/__tests__/NotificationsPopover.test.tsx +91 -0
- package/bizar-dash/src/web/v8/__tests__/SchedulesView.test.tsx +157 -0
- package/bizar-dash/src/web/v8/__tests__/Topbar.test.tsx +86 -0
- package/bizar-dash/src/web/v8/__tests__/changelog.test.tsx +79 -0
- package/bizar-dash/src/web/v8/__tests__/control-plane.test.tsx +104 -0
- package/bizar-dash/src/web/v8/__tests__/theme.test.tsx +10 -4
- package/bizar-dash/src/web/v8/__tests__/useFetch.test.ts +92 -0
- package/bizar-dash/src/web/v8/__tests__/useWebSocket.test.ts +87 -0
- package/bizar-dash/src/web/v8/__tests__/views.test.tsx +116 -40
- package/bizar-dash/src/web/v8/data/fetcher.ts +59 -0
- package/bizar-dash/src/web/v8/data/types.ts +156 -0
- package/bizar-dash/src/web/v8/data/useFetch.ts +62 -0
- package/bizar-dash/src/web/v8/data/useWebSocket.ts +161 -0
- package/bizar-dash/src/web/v8/shell/Sidebar.tsx +46 -12
- package/bizar-dash/src/web/v8/shell/Topbar.tsx +30 -4
- package/bizar-dash/src/web/v8/ui/agents/AgentDetail.tsx +283 -0
- package/bizar-dash/src/web/v8/ui/agents/AgentStreamPanel.tsx +371 -0
- package/bizar-dash/src/web/v8/ui/feedback/NotificationsPopover.tsx +239 -0
- package/bizar-dash/src/web/v8/ui/goals/GoalDetail.tsx +251 -0
- package/bizar-dash/src/web/v8/ui/kanban/KanbanBoard.tsx +6 -3
- package/bizar-dash/src/web/v8/ui/kanban/KanbanCard.tsx +3 -3
- package/bizar-dash/src/web/v8/ui/kanban/KanbanColumn.tsx +10 -5
- package/bizar-dash/src/web/v8/ui/styles/globals.css +5 -0
- package/bizar-dash/src/web/v8/views/Activity/ActivityView.tsx +415 -16
- package/bizar-dash/src/web/v8/views/Agents/AgentsView.tsx +151 -87
- package/bizar-dash/src/web/v8/views/BackgroundJobs/BackgroundJobsView.tsx +442 -0
- package/bizar-dash/src/web/v8/views/CommandPalette/AppCommandPalette.test.tsx +1 -1
- package/bizar-dash/src/web/v8/views/CommandPalette/AppCommandPalette.tsx +148 -30
- package/bizar-dash/src/web/v8/views/Goals/GoalsView.tsx +176 -67
- package/bizar-dash/src/web/v8/views/Libraries/LibrariesView.tsx +78 -11
- package/bizar-dash/src/web/v8/views/Memory/MemoryView.tsx +212 -42
- package/bizar-dash/src/web/v8/views/Overview/OverviewView.tsx +112 -52
- package/bizar-dash/src/web/v8/views/Router.tsx +23 -37
- package/bizar-dash/src/web/v8/views/Schedules/SchedulesView.tsx +395 -0
- package/bizar-dash/src/web/v8/views/Settings/SettingsView.tsx +651 -210
- package/bizar-dash/src/web/v8/views/Tasks/TasksView.tsx +142 -49
- package/bizar-dash/tests/components/Button.test.tsx +51 -14
- package/bizar-dash/tests/components/Card.test.tsx +37 -20
- package/bizar-dash/tests/components/Dialog.test.tsx +80 -0
- package/bizar-dash/tests/components/Toast.test.tsx +48 -95
- package/bizar-dash/tests/goals-decompose.test.mjs +179 -0
- package/bizar-dash/tests/setup.ts +21 -0
- package/bizar-dash/tests/ui/primitives/VisuallyHidden.test.tsx +30 -15
- package/bizar-dash/vite.config.ts +15 -0
- package/bizar-dash/vitest.config.ts +4 -1
- package/cli/bin.mjs +32 -0
- package/cli/install.mjs +26 -1
- package/cli/provision-claude.mjs +86 -0
- package/package.json +1 -1
- package/packages/sdk/.harness/agents.json +17 -0
- package/packages/sdk/.harness/topology.json +4 -0
- package/scripts/run-dev.mjs +84 -0
- package/bizar-dash/dist/assets/ActivityFeed-BRBtQOHB.js +0 -6
- package/bizar-dash/dist/assets/ActivityFeed-BRBtQOHB.js.map +0 -1
- package/bizar-dash/dist/assets/ActivityView-CwqhxBfh.js +0 -1
- package/bizar-dash/dist/assets/ActivityView-CwqhxBfh.js.map +0 -1
- package/bizar-dash/dist/assets/AgentActivity-6MxU-a9F.js +0 -1
- package/bizar-dash/dist/assets/AgentActivity-6MxU-a9F.js.map +0 -1
- package/bizar-dash/dist/assets/AgentsView-BYrOFdwl.js +0 -8
- package/bizar-dash/dist/assets/AgentsView-BYrOFdwl.js.map +0 -1
- package/bizar-dash/dist/assets/Badge-Cd61wsBa.js +0 -1
- package/bizar-dash/dist/assets/Badge-Cd61wsBa.js.map +0 -1
- package/bizar-dash/dist/assets/GoalsView-Dok0yt9S.js +0 -11
- package/bizar-dash/dist/assets/GoalsView-Dok0yt9S.js.map +0 -1
- package/bizar-dash/dist/assets/KanbanCard-CtTKP6ZX.js +0 -21
- package/bizar-dash/dist/assets/KanbanCard-CtTKP6ZX.js.map +0 -1
- package/bizar-dash/dist/assets/LibrariesView-BcyBQXiY.js +0 -67
- package/bizar-dash/dist/assets/LibrariesView-BcyBQXiY.js.map +0 -1
- package/bizar-dash/dist/assets/MemoryView-49wR4u-y.js +0 -13
- package/bizar-dash/dist/assets/MemoryView-49wR4u-y.js.map +0 -1
- package/bizar-dash/dist/assets/OverviewView-BtQ_UWYj.js +0 -1
- package/bizar-dash/dist/assets/OverviewView-BtQ_UWYj.js.map +0 -1
- package/bizar-dash/dist/assets/ProgressBar-CpvDeq9F.js +0 -1
- package/bizar-dash/dist/assets/ProgressBar-CpvDeq9F.js.map +0 -1
- package/bizar-dash/dist/assets/SettingsRow-DmIe5OUu.js +0 -30
- package/bizar-dash/dist/assets/SettingsRow-DmIe5OUu.js.map +0 -1
- package/bizar-dash/dist/assets/SettingsView-D1KmGWbi.js +0 -48
- package/bizar-dash/dist/assets/SettingsView-D1KmGWbi.js.map +0 -1
- package/bizar-dash/dist/assets/StatTile-BkIP32gG.js +0 -11
- package/bizar-dash/dist/assets/StatTile-BkIP32gG.js.map +0 -1
- package/bizar-dash/dist/assets/TasksView-Cba3GJ42.js +0 -1
- package/bizar-dash/dist/assets/TasksView-Cba3GJ42.js.map +0 -1
- package/bizar-dash/dist/assets/dnd-kit-DR2Qzzxk.js +0 -5
- package/bizar-dash/dist/assets/git-merge-OoqBKQer.js +0 -6
- package/bizar-dash/dist/assets/git-merge-OoqBKQer.js.map +0 -1
- package/bizar-dash/dist/assets/git-pull-request-CXBQTR2f.js +0 -6
- package/bizar-dash/dist/assets/git-pull-request-CXBQTR2f.js.map +0 -1
- package/bizar-dash/dist/assets/main-Cw6gybzS.js +0 -109
- package/bizar-dash/dist/assets/main-Cw6gybzS.js.map +0 -1
- package/bizar-dash/dist/assets/message-square-DUTeIQAR.js +0 -6
- package/bizar-dash/dist/assets/message-square-DUTeIQAR.js.map +0 -1
- package/bizar-dash/dist/assets/minus-CrStJTZ7.js.map +0 -1
- /package/bizar-dash/tests/{BackgroundAgents.test.tsx → v7-archive/BackgroundAgents.test.tsx} +0 -0
- /package/bizar-dash/tests/{a11y → v7-archive/a11y}/forms.test.tsx +0 -0
- /package/bizar-dash/tests/{a11y.test.tsx → v7-archive/a11y.test.tsx} +0 -0
- /package/bizar-dash/tests/{autosave.test.tsx → v7-archive/autosave.test.tsx} +0 -0
- /package/bizar-dash/tests/{backup-restore.test.tsx → v7-archive/backup-restore.test.tsx} +0 -0
- /package/bizar-dash/tests/{chat-composer.test.tsx → v7-archive/chat-composer.test.tsx} +0 -0
- /package/bizar-dash/tests/{communication-log.test.tsx → v7-archive/communication-log.test.tsx} +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/Modal.test.tsx +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/Spinner.test.tsx +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/StatusBadge.test.tsx +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/doctor-panel.test.tsx +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/screenshot-ocr.test.tsx +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/settings-search.test.tsx +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/workspace-selector.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Button.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Checkbox.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/IconButton.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Kbd.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/NumberInput.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/RadioGroup.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/SearchInput.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Select.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Slider.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/TextInput.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Textarea.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Toggle.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/BarChart.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/DataTable.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/EmptyState.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/ErrorState.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/KeyValueList.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/LoadingState.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/Sparkline.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/StatTile.test.tsx +0 -0
- /package/bizar-dash/tests/{dep-graph.test.tsx → v7-archive/dep-graph.test.tsx} +0 -0
- /package/bizar-dash/tests/{eval-web-ui.test.tsx → v7-archive/eval-web-ui.test.tsx} +0 -0
- /package/bizar-dash/tests/{event-log.test.tsx → v7-archive/event-log.test.tsx} +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/feedback/Badge.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/feedback/Dialog.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/feedback/ProgressBar.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/feedback/StatusDot.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/feedback/Toast.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/feedback/Tooltip.test.tsx +0 -0
- /package/bizar-dash/tests/{goal-input.test.tsx → v7-archive/goal-input.test.tsx} +0 -0
- /package/bizar-dash/tests/{goap-planner.test.ts → v7-archive/goap-planner.test.ts} +0 -0
- /package/bizar-dash/tests/{hooks → v7-archive/hooks}/useModal.test.tsx +0 -0
- /package/bizar-dash/tests/{hooks → v7-archive/hooks}/useToast.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/AppShell.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/Breadcrumbs.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/Panel.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/PanelHeader.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/Sidebar.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/Tabs.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/Topbar.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/ViewHeader.test.tsx +0 -0
- /package/bizar-dash/tests/{lib → v7-archive/lib}/i18n.test.ts +0 -0
- /package/bizar-dash/tests/{lib → v7-archive/lib}/search-fuzzy.test.ts +0 -0
- /package/bizar-dash/tests/{lib → v7-archive/lib}/utils.test.ts +0 -0
- /package/bizar-dash/tests/{memory-graph-view.test.tsx → v7-archive/memory-graph-view.test.tsx} +0 -0
- /package/bizar-dash/tests/{mobile-chat.test.tsx → v7-archive/mobile-chat.test.tsx} +0 -0
- /package/bizar-dash/tests/{mobile-layout.test.tsx → v7-archive/mobile-layout.test.tsx} +0 -0
- /package/bizar-dash/tests/{mobile-overview.test.tsx → v7-archive/mobile-overview.test.tsx} +0 -0
- /package/bizar-dash/tests/{mobile-settings.test.tsx → v7-archive/mobile-settings.test.tsx} +0 -0
- /package/bizar-dash/tests/{mobile-tasks.test.tsx → v7-archive/mobile-tasks.test.tsx} +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/navigation/CommandPalette.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/navigation/NavGroup.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/navigation/NavLink.test.tsx +0 -0
- /package/bizar-dash/tests/{quality-gates.test.tsx → v7-archive/quality-gates.test.tsx} +0 -0
- /package/bizar-dash/tests/{settings-layout.test.tsx → v7-archive/settings-layout.test.tsx} +0 -0
- /package/bizar-dash/tests/{settings-mode-wiring.test.tsx → v7-archive/settings-mode-wiring.test.tsx} +0 -0
- /package/bizar-dash/tests/{settings-nav.test.tsx → v7-archive/settings-nav.test.tsx} +0 -0
- /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Box.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Grid.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Inline.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Separator.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Stack.test.tsx +0 -0
- /package/bizar-dash/tests/{views → v7-archive/views}/Agents.test.tsx +0 -0
- /package/bizar-dash/tests/{views → v7-archive/views}/Memory.test.tsx +0 -0
- /package/bizar-dash/tests/{views → v7-archive/views}/Overview.test.tsx +0 -0
- /package/bizar-dash/tests/{views → v7-archive/views}/Tasks.test.tsx +0 -0
- /package/bizar-dash/tests/{views → v7-archive/views}/sidebar.test.tsx +0 -0
- /package/bizar-dash/tests/{views → v7-archive/views}/topbar.test.tsx +0 -0
- /package/bizar-dash/tests/{voice-recorder.test.tsx → v7-archive/voice-recorder.test.tsx} +0 -0
|
@@ -0,0 +1,1478 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/server/memory-lightrag.mjs
|
|
3
|
+
*
|
|
4
|
+
* v4.1.0 — LightRAG orchestrator for the Bizar Memory Service.
|
|
5
|
+
*
|
|
6
|
+
* Owns the local LightRAG server lifecycle (start, stop, health check,
|
|
7
|
+
* query, insert) and bridges it to the markdown vault. Designed so the
|
|
8
|
+
* dashboard, the CLI, and tests can all call the same surface.
|
|
9
|
+
*
|
|
10
|
+
* Lifecycle:
|
|
11
|
+
* - isInstalled() — checks `lightrag-server` is on PATH
|
|
12
|
+
* - isRunning() — GET /health
|
|
13
|
+
* - startServer() — spawn detached, poll /health for up to 30s
|
|
14
|
+
* - stopServer() — read PID file, SIGTERM then SIGKILL
|
|
15
|
+
* - ensureRunning() — idempotent wrapper: returns immediately if
|
|
16
|
+
* the server is already healthy
|
|
17
|
+
* - reindexVault() — top-level: resolve vault → list notes →
|
|
18
|
+
* ensure server → insert each → write marker
|
|
19
|
+
* - query() — POST /query on the running server
|
|
20
|
+
*
|
|
21
|
+
* The server is started as a detached child with `stdio: ['ignore',
|
|
22
|
+
* 'pipe', 'pipe']`; stdout + stderr are tee'd to
|
|
23
|
+
* `<workingDir>/lightrag.log`. The PID is written to
|
|
24
|
+
* `<workingDir>/lightrag.pid` for orphan detection + graceful shutdown.
|
|
25
|
+
*
|
|
26
|
+
* IDs are deterministic: a note at `decisions/foo.md` in projectId
|
|
27
|
+
* `bizarharness` gets id `bizar://bizarharness/decisions/foo.md`. Re-running
|
|
28
|
+
* reindexVault is idempotent because the server keys by this id.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import {
|
|
32
|
+
spawn,
|
|
33
|
+
execFileSync,
|
|
34
|
+
} from 'node:child_process';
|
|
35
|
+
import {
|
|
36
|
+
existsSync,
|
|
37
|
+
readFileSync,
|
|
38
|
+
writeFileSync,
|
|
39
|
+
mkdirSync,
|
|
40
|
+
openSync,
|
|
41
|
+
writeSync,
|
|
42
|
+
closeSync,
|
|
43
|
+
unlinkSync,
|
|
44
|
+
readdirSync,
|
|
45
|
+
statSync,
|
|
46
|
+
appendFileSync,
|
|
47
|
+
} from 'node:fs';
|
|
48
|
+
import { join, dirname, basename } from 'node:path';
|
|
49
|
+
import { homedir } from 'node:os';
|
|
50
|
+
import http from 'node:http';
|
|
51
|
+
import https from 'node:https';
|
|
52
|
+
|
|
53
|
+
import { atomicWriteJson } from './routes/_shared.mjs';
|
|
54
|
+
import { parseFrontmatter } from './yaml.mjs';
|
|
55
|
+
import { warn as logWarn } from './logger.mjs';
|
|
56
|
+
|
|
57
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* v4.7.0 — Per-site log rate limiter for hot-path catches.
|
|
61
|
+
*
|
|
62
|
+
* Several empty catches below sit on stdout/stderr `data` handlers
|
|
63
|
+
* that can fire dozens of times per second when LightRAG is chatty
|
|
64
|
+
* (or the disk is slow). Without rate-limiting, a transient disk
|
|
65
|
+
* hiccup floods the log with thousands of identical warnings and
|
|
66
|
+
* hides the real problem underneath.
|
|
67
|
+
*
|
|
68
|
+
* Returns true the first time it's called for a key within `intervalMs`,
|
|
69
|
+
* then false until the window passes. Default 60s — matches the
|
|
70
|
+
* "if it's still broken, say it again a minute later" pattern.
|
|
71
|
+
*/
|
|
72
|
+
const _lastLog = new Map();
|
|
73
|
+
function _rateLimit(key, intervalMs = 60_000) {
|
|
74
|
+
const now = Date.now();
|
|
75
|
+
const last = _lastLog.get(key) || 0;
|
|
76
|
+
if (now - last < intervalMs) return false;
|
|
77
|
+
_lastLog.set(key, now);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function deepMerge(target, source) {
|
|
82
|
+
const out = { ...target };
|
|
83
|
+
if (source === null || source === undefined) return out;
|
|
84
|
+
for (const key of Object.keys(source)) {
|
|
85
|
+
if (
|
|
86
|
+
source[key] !== null &&
|
|
87
|
+
typeof source[key] === 'object' &&
|
|
88
|
+
!Array.isArray(source[key]) &&
|
|
89
|
+
target[key] !== null &&
|
|
90
|
+
typeof target[key] === 'object' &&
|
|
91
|
+
!Array.isArray(target[key])
|
|
92
|
+
) {
|
|
93
|
+
out[key] = deepMerge(target[key], source[key]);
|
|
94
|
+
} else {
|
|
95
|
+
out[key] = source[key];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Read the last `n` lines of a text file.
|
|
103
|
+
*/
|
|
104
|
+
function readLogTail(filePath, n = 30) {
|
|
105
|
+
if (!existsSync(filePath)) return [];
|
|
106
|
+
try {
|
|
107
|
+
const content = readFileSync(filePath, 'utf8');
|
|
108
|
+
const lines = content.split('\n');
|
|
109
|
+
return lines.slice(-n);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
console.warn('[lightrag] swallowed in readLogTail:', err?.message || err);
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const KNOWN_LLM_BINDINGS = new Set(['ollama', 'openai', 'lollms', 'azure_openai', 'bedrock', 'gemini']);
|
|
117
|
+
const KNOWN_EMBEDDING_BINDINGS = new Set(['ollama', 'openai', 'azure_openai', 'bedrock', 'jina', 'gemini', 'voyageai']);
|
|
118
|
+
|
|
119
|
+
export const LIGHTRAG_DEFAULTS = Object.freeze({
|
|
120
|
+
host: '127.0.0.1',
|
|
121
|
+
port: 9621,
|
|
122
|
+
workingDir: null, // resolved at runtime
|
|
123
|
+
timeoutMs: 30_000,
|
|
124
|
+
pollMs: 1_000,
|
|
125
|
+
startupTimeoutMs: 30_000,
|
|
126
|
+
llmBinding: 'ollama', // ollama | openai | lollms | azure_openai | bedrock | gemini
|
|
127
|
+
embeddingBinding: 'ollama', // ollama | openai | azure_openai | bedrock | jina | gemini | voyageai
|
|
128
|
+
// v4.6.0 — Default to free cline Zen models (no API key required).
|
|
129
|
+
// Per-project overrides via .bizar/memory.json#lightrag.{llmModel,embeddingModel}
|
|
130
|
+
// or env vars BIZAR_LIGHTRAG_LLM / BIZAR_LIGHTRAG_EMBEDDING.
|
|
131
|
+
llmModel: 'cline/gpt-5-nano',
|
|
132
|
+
embeddingModel: 'cline/text-embedding-3-small',
|
|
133
|
+
llmBindingHost: null, // for non-ollama bindings
|
|
134
|
+
embeddingBindingHost: null,
|
|
135
|
+
apiKey: 'env', // 'env' means read from env var; any other string is written to file
|
|
136
|
+
apiKeySource: 'env', // 'env' | 'file'
|
|
137
|
+
/** When true, reindex writes a marker file with full stats. */
|
|
138
|
+
writeMarker: true,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Deep-merge a patch into the lightrag block of .bizar/memory.json.
|
|
143
|
+
*
|
|
144
|
+
* Validates:
|
|
145
|
+
* - llmBinding must be in KNOWN_LLM_BINDINGS
|
|
146
|
+
* - embeddingBinding must be in KNOWN_EMBEDDING_BINDINGS
|
|
147
|
+
* - port must be 1–65535
|
|
148
|
+
*
|
|
149
|
+
* Returns { ok, config, error? }. The returned config is the full
|
|
150
|
+
* merged memory.json (not redacted).
|
|
151
|
+
*
|
|
152
|
+
* If apiKey is the literal string '<empty>' the field is set to ''.
|
|
153
|
+
* The apiKey field is never validated here — the UI decides what to send.
|
|
154
|
+
*/
|
|
155
|
+
export function writeLightRAGConfig(projectRoot, patch) {
|
|
156
|
+
const memPath = join(projectRoot, '.bizar', 'memory.json');
|
|
157
|
+
let mem = {};
|
|
158
|
+
if (existsSync(memPath)) {
|
|
159
|
+
try {
|
|
160
|
+
mem = JSON.parse(readFileSync(memPath, 'utf8'));
|
|
161
|
+
} catch {
|
|
162
|
+
return { ok: false, error: 'memory.json is corrupt', config: null };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Resolve workingDir in patch before validation
|
|
167
|
+
const resolvedPatch = { ...patch };
|
|
168
|
+
if (resolvedPatch.workingDir) {
|
|
169
|
+
if (resolvedPatch.workingDir.startsWith('~')) {
|
|
170
|
+
resolvedPatch.workingDir = join(homedir(), resolvedPatch.workingDir.slice(1));
|
|
171
|
+
} else if (!resolvedPatch.workingDir.startsWith('/')) {
|
|
172
|
+
resolvedPatch.workingDir = join(projectRoot, resolvedPatch.workingDir);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Validate llmBinding
|
|
177
|
+
if (resolvedPatch.llmBinding !== undefined && !KNOWN_LLM_BINDINGS.has(resolvedPatch.llmBinding)) {
|
|
178
|
+
return { ok: false, error: `llmBinding must be one of: ${[...KNOWN_LLM_BINDINGS].join(', ')}`, config: null };
|
|
179
|
+
}
|
|
180
|
+
// Validate embeddingBinding
|
|
181
|
+
if (resolvedPatch.embeddingBinding !== undefined && !KNOWN_EMBEDDING_BINDINGS.has(resolvedPatch.embeddingBinding)) {
|
|
182
|
+
return { ok: false, error: `embeddingBinding must be one of: ${[...KNOWN_EMBEDDING_BINDINGS].join(', ')}`, config: null };
|
|
183
|
+
}
|
|
184
|
+
// Validate port
|
|
185
|
+
if (resolvedPatch.port !== undefined) {
|
|
186
|
+
const port = parseInt(resolvedPatch.port, 10);
|
|
187
|
+
if (!Number.isFinite(port) || port < 1 || port > 65535) {
|
|
188
|
+
return { ok: false, error: 'port must be an integer between 1 and 65535', config: null };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Canonicalise '<empty>' → ''
|
|
193
|
+
if (resolvedPatch.apiKey === '<empty>') resolvedPatch.apiKey = '';
|
|
194
|
+
|
|
195
|
+
const existing = mem.lightrag || {};
|
|
196
|
+
const merged = deepMerge(existing, resolvedPatch);
|
|
197
|
+
mem.lightrag = merged;
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
mkdirSync(dirname(memPath), { recursive: true });
|
|
201
|
+
atomicWriteJson(memPath, mem);
|
|
202
|
+
return { ok: true, config: mem };
|
|
203
|
+
} catch (err) {
|
|
204
|
+
return { ok: false, error: err.message, config: null };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Redact apiKey for safe return to the UI.
|
|
210
|
+
* If apiKey is non-empty, replace with '***'.
|
|
211
|
+
*/
|
|
212
|
+
function redactLightRAG(cfg) {
|
|
213
|
+
if (!cfg) return cfg;
|
|
214
|
+
return {
|
|
215
|
+
...cfg,
|
|
216
|
+
apiKey: cfg.apiKey && cfg.apiKey !== '' ? '***' : cfg.apiKey || undefined,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* v5.x — Detect which LLM provider is available for LightRAG.
|
|
222
|
+
*
|
|
223
|
+
* Decision order:
|
|
224
|
+
* 1. If `llmBinding === 'ollama'`, do a quick async probe of
|
|
225
|
+
* localhost:11434 (or the configured `llmBindingHost`).
|
|
226
|
+
* If reachable → ollama available. If unreachable but an API key
|
|
227
|
+
* is configured for OpenAI / Anthropic / MiniMax → use that instead.
|
|
228
|
+
* 2. For cloud bindings (openai / anthropic / minimax / etc.),
|
|
229
|
+
* check whether the corresponding env var is set. If yes → available.
|
|
230
|
+
* 3. If no provider is detectable, return null and the caller logs
|
|
231
|
+
* a warning and skips reindex.
|
|
232
|
+
*
|
|
233
|
+
* Returns { provider, available, detail } or null.
|
|
234
|
+
*/
|
|
235
|
+
export async function detectAvailableLLM(config) {
|
|
236
|
+
const binding = config.llmBinding || 'ollama';
|
|
237
|
+
|
|
238
|
+
if (binding === 'ollama') {
|
|
239
|
+
const ollamaHost = config.llmBindingHost || 'http://localhost:11434';
|
|
240
|
+
// Quick async probe — give it 1.5s to connect.
|
|
241
|
+
try {
|
|
242
|
+
const controller = new AbortController();
|
|
243
|
+
const t = setTimeout(() => controller.abort(), 1500);
|
|
244
|
+
const res = await fetch(`${ollamaHost}/`, {
|
|
245
|
+
method: 'HEAD',
|
|
246
|
+
signal: controller.signal,
|
|
247
|
+
});
|
|
248
|
+
clearTimeout(t);
|
|
249
|
+
if (res.ok || res.status < 500) {
|
|
250
|
+
return { provider: 'ollama', available: true, detail: ollamaHost };
|
|
251
|
+
}
|
|
252
|
+
} catch {
|
|
253
|
+
// Fall through — ollama not reachable.
|
|
254
|
+
}
|
|
255
|
+
// ollama not reachable; check for cloud API keys as fallback.
|
|
256
|
+
const hasOpenAI = !!(process.env.OPENAI_API_KEY || process.env.OPENAI_API_KEY_2);
|
|
257
|
+
const hasAnthropic = !!(process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_API_KEY_2);
|
|
258
|
+
const hasMinimax = !!(process.env.MINIMAX_API_KEY || process.env.MINIMAX_API_KEY_2);
|
|
259
|
+
if (hasOpenAI || hasAnthropic || hasMinimax) {
|
|
260
|
+
const provider = hasOpenAI ? 'openai' : hasAnthropic ? 'anthropic' : 'minimax';
|
|
261
|
+
return { provider, available: true, detail: `${provider} (ollama unreachable, using API key)` };
|
|
262
|
+
}
|
|
263
|
+
return null; // no ollama, no API key
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Cloud bindings — available if API key is set.
|
|
267
|
+
const apiKeyEnvVars = {
|
|
268
|
+
openai: ['OPENAI_API_KEY', 'OPENAI_API_KEY_2'],
|
|
269
|
+
anthropic: ['ANTHROPIC_API_KEY', 'ANTHROPIC_API_KEY_2'],
|
|
270
|
+
minimax: ['MINIMAX_API_KEY', 'MINIMAX_API_KEY_2'],
|
|
271
|
+
azure_openai: ['AZURE_OPENAI_API_KEY'],
|
|
272
|
+
gemini: ['GEMINI_API_KEY'],
|
|
273
|
+
};
|
|
274
|
+
const relevantKeys = apiKeyEnvVars[binding] || [];
|
|
275
|
+
const hasKey = relevantKeys.some((k) => process.env[k]);
|
|
276
|
+
if (hasKey) {
|
|
277
|
+
return { provider: binding, available: true, detail: binding };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return null; // configured binding but no key detected
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Resolve the LightRAG config for a project.
|
|
285
|
+
* Pulls from `.bizar/memory.json` (lightrag block) and applies defaults.
|
|
286
|
+
*
|
|
287
|
+
* @param {string} projectRoot
|
|
288
|
+
* @returns {{ enabled: boolean, host: string, port: number, workingDir: string, timeoutMs: number, pollMs: number, startupTimeoutMs: number, llmModel: string, embeddingModel: string, writeMarker: boolean, llmBinding: string, embeddingBinding: string, llmBindingHost: string|null, embeddingBindingHost: string|null, apiKey: string, apiKeySource: 'env'|'file' }}
|
|
289
|
+
*/
|
|
290
|
+
export function resolveLightRAGConfig(projectRoot) {
|
|
291
|
+
const path = join(projectRoot, '.bizar', 'memory.json');
|
|
292
|
+
let userCfg = {};
|
|
293
|
+
if (existsSync(path)) {
|
|
294
|
+
try {
|
|
295
|
+
userCfg = JSON.parse(readFileSync(path, 'utf8')).lightrag || {};
|
|
296
|
+
} catch (err) {
|
|
297
|
+
console.warn('[lightrag] swallowed in resolveLightRAGConfig.readMemoryJson:', err?.message || err);
|
|
298
|
+
userCfg = {};
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Resolve workingDir:
|
|
302
|
+
// - empty/missing → <projectRoot>/.bizar/lightrag (default)
|
|
303
|
+
// - starts with ~ → expand to $HOME
|
|
304
|
+
// - absolute → use as-is
|
|
305
|
+
// - relative → resolve against projectRoot
|
|
306
|
+
let workingDir;
|
|
307
|
+
if (!userCfg.workingDir) {
|
|
308
|
+
workingDir = join(projectRoot, '.bizar', 'lightrag');
|
|
309
|
+
} else if (userCfg.workingDir.startsWith('~')) {
|
|
310
|
+
workingDir = join(homedir(), userCfg.workingDir.slice(1));
|
|
311
|
+
} else if (userCfg.workingDir.startsWith('/')) {
|
|
312
|
+
workingDir = userCfg.workingDir;
|
|
313
|
+
} else {
|
|
314
|
+
workingDir = join(projectRoot, userCfg.workingDir);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
enabled: userCfg.enabled !== false,
|
|
319
|
+
host: userCfg.host || LIGHTRAG_DEFAULTS.host,
|
|
320
|
+
port: userCfg.port || LIGHTRAG_DEFAULTS.port,
|
|
321
|
+
workingDir,
|
|
322
|
+
timeoutMs: userCfg.timeoutMs || LIGHTRAG_DEFAULTS.timeoutMs,
|
|
323
|
+
pollMs: userCfg.pollMs || LIGHTRAG_DEFAULTS.pollMs,
|
|
324
|
+
startupTimeoutMs: userCfg.startupTimeoutMs || LIGHTRAG_DEFAULTS.startupTimeoutMs,
|
|
325
|
+
llmBinding: userCfg.llmBinding || LIGHTRAG_DEFAULTS.llmBinding,
|
|
326
|
+
embeddingBinding: userCfg.embeddingBinding || LIGHTRAG_DEFAULTS.embeddingBinding,
|
|
327
|
+
llmBindingHost: userCfg.llmBindingHost || null,
|
|
328
|
+
embeddingBindingHost: userCfg.embeddingBindingHost || null,
|
|
329
|
+
llmModel: userCfg.llmModel || LIGHTRAG_DEFAULTS.llmModel,
|
|
330
|
+
embeddingModel: userCfg.embeddingModel || LIGHTRAG_DEFAULTS.embeddingModel,
|
|
331
|
+
apiKey: userCfg.apiKey !== undefined ? userCfg.apiKey : LIGHTRAG_DEFAULTS.apiKey,
|
|
332
|
+
apiKeySource: userCfg.apiKeySource || LIGHTRAG_DEFAULTS.apiKeySource,
|
|
333
|
+
writeMarker: userCfg.writeMarker !== false,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ── Process management ─────────────────────────────────────────────────────
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Detect whether `lightrag-server` is on PATH. Returns the absolute
|
|
341
|
+
* path or null. Uses `which`-style probing (POSIX `command -v`) and
|
|
342
|
+
* common install dirs.
|
|
343
|
+
*/
|
|
344
|
+
export function findLightragBinary() {
|
|
345
|
+
const candidates = [
|
|
346
|
+
`${homedir()}/.local/bin/lightrag-server`,
|
|
347
|
+
`${homedir()}/.cargo/bin/lightrag-server`,
|
|
348
|
+
'/usr/local/bin/lightrag-server',
|
|
349
|
+
'/usr/bin/lightrag-server',
|
|
350
|
+
];
|
|
351
|
+
for (const c of candidates) {
|
|
352
|
+
if (existsSync(c)) return c;
|
|
353
|
+
}
|
|
354
|
+
try {
|
|
355
|
+
const path = execFileSync('command', ['-v', 'lightrag-server'], {
|
|
356
|
+
encoding: 'utf8',
|
|
357
|
+
timeout: 3000,
|
|
358
|
+
}).trim();
|
|
359
|
+
if (path) return path;
|
|
360
|
+
} catch (err) {
|
|
361
|
+
// command returned non-zero — fall through
|
|
362
|
+
console.warn('[lightrag] swallowed in findLightragBinary.which:', err?.message || err);
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export async function isInstalled() {
|
|
368
|
+
const found = findLightragBinary() !== null;
|
|
369
|
+
if (found) _lightragNotInstalled = false;
|
|
370
|
+
return found;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function httpGet(url, timeoutMs) {
|
|
374
|
+
return new Promise((resolve, reject) => {
|
|
375
|
+
const lib = url.startsWith('https:') ? https : http;
|
|
376
|
+
const req = lib.get(url, { timeout: timeoutMs }, (res) => {
|
|
377
|
+
let data = '';
|
|
378
|
+
res.on('data', (chunk) => (data += chunk));
|
|
379
|
+
res.on('end', () => resolve({ status: res.statusCode, body: data }));
|
|
380
|
+
});
|
|
381
|
+
req.on('error', reject);
|
|
382
|
+
req.on('timeout', () => {
|
|
383
|
+
req.destroy();
|
|
384
|
+
reject(new Error(`timeout after ${timeoutMs}ms`));
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function httpPost(url, body, timeoutMs) {
|
|
390
|
+
return new Promise((resolve, reject) => {
|
|
391
|
+
try {
|
|
392
|
+
const lib = url.startsWith('https:') ? https : http;
|
|
393
|
+
const u = new URL(url);
|
|
394
|
+
const data = typeof body === 'string' ? body : JSON.stringify(body);
|
|
395
|
+
const req = lib.request(
|
|
396
|
+
{
|
|
397
|
+
hostname: u.hostname,
|
|
398
|
+
port: u.port,
|
|
399
|
+
path: u.pathname + u.search,
|
|
400
|
+
method: 'POST',
|
|
401
|
+
timeout: timeoutMs,
|
|
402
|
+
headers: {
|
|
403
|
+
'Content-Type': 'application/json',
|
|
404
|
+
'Content-Length': Buffer.byteLength(data),
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
(res) => {
|
|
408
|
+
let buf = '';
|
|
409
|
+
res.on('data', (chunk) => (buf += chunk));
|
|
410
|
+
res.on('end', () => resolve({ status: res.statusCode, body: buf }));
|
|
411
|
+
},
|
|
412
|
+
);
|
|
413
|
+
req.on('error', reject);
|
|
414
|
+
req.on('timeout', () => {
|
|
415
|
+
req.destroy();
|
|
416
|
+
reject(new Error(`timeout after ${timeoutMs}ms`));
|
|
417
|
+
});
|
|
418
|
+
req.write(data);
|
|
419
|
+
req.end();
|
|
420
|
+
} catch (err) {
|
|
421
|
+
reject(err);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* v5.x — Flag set when LightRAG is confirmed not installed or explicitly
|
|
428
|
+
* disabled. When true, isRunning() returns false immediately without
|
|
429
|
+
* making any network request, preventing ECONNREFUSED log spam from a
|
|
430
|
+
* binary that will never be present.
|
|
431
|
+
*
|
|
432
|
+
* Reset by findLightragBinary() succeeding (e.g. after user installs
|
|
433
|
+
* the binary without restarting the dashboard).
|
|
434
|
+
*/
|
|
435
|
+
let _lightragNotInstalled = false;
|
|
436
|
+
|
|
437
|
+
export async function isRunning(config) {
|
|
438
|
+
// Fast path: skip network check if we already know LightRAG is absent.
|
|
439
|
+
// This suppresses the ECONNREFUSED log spam that otherwise occurs on every
|
|
440
|
+
// poll when the binary is not on PATH.
|
|
441
|
+
if (_lightragNotInstalled) return false;
|
|
442
|
+
try {
|
|
443
|
+
const res = await httpGet(`http://${config.host}:${config.port}/health`, 3000);
|
|
444
|
+
return res.status === 200;
|
|
445
|
+
} catch (err) {
|
|
446
|
+
// Rate-limit: only log once per 60s to avoid flooding the console
|
|
447
|
+
// when LightRAG health-check fails repeatedly.
|
|
448
|
+
if (_rateLimit('isRunning.healthCheck', 60_000)) {
|
|
449
|
+
console.warn('[lightrag] isRunning healthCheck failed:', err?.message || err);
|
|
450
|
+
}
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function killPid(pid, signal) {
|
|
456
|
+
try {
|
|
457
|
+
process.kill(pid, signal);
|
|
458
|
+
return true;
|
|
459
|
+
} catch (err) {
|
|
460
|
+
if (err.code === 'ESRCH') return false; // already dead
|
|
461
|
+
throw err;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Read PID file and check liveness. Returns { pid, alive }.
|
|
467
|
+
*/
|
|
468
|
+
function readPidAlive(pidFile) {
|
|
469
|
+
if (!existsSync(pidFile)) return { pid: null, alive: false };
|
|
470
|
+
try {
|
|
471
|
+
const pid = parseInt(readFileSync(pidFile, 'utf8').trim(), 10);
|
|
472
|
+
if (!Number.isFinite(pid) || pid <= 0) return { pid: null, alive: false };
|
|
473
|
+
const alive = killPid(pid, 0); // signal 0 = probe
|
|
474
|
+
return { pid, alive };
|
|
475
|
+
} catch (err) {
|
|
476
|
+
console.warn('[lightrag] swallowed in readPidAlive:', err?.message || err);
|
|
477
|
+
return { pid: null, alive: false };
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Start the LightRAG server as a detached child.
|
|
483
|
+
* Returns { ok, pid, logPath, error? }.
|
|
484
|
+
*/
|
|
485
|
+
export async function startServer(config, { logger } = {}) {
|
|
486
|
+
const log = (...a) => logger?.info?.('[lightrag]', ...a) || logger?.log?.(...a) || console.log('[lightrag]', ...a);
|
|
487
|
+
const err = (...a) => logger?.warn?.('[lightrag]', ...a) || console.error('[lightrag]', ...a);
|
|
488
|
+
|
|
489
|
+
// Idempotent: if PID file has a live PID, do nothing.
|
|
490
|
+
const pidFile = join(config.workingDir, 'lightrag.pid');
|
|
491
|
+
const logFile = join(config.workingDir, 'lightrag.log');
|
|
492
|
+
mkdirSync(config.workingDir, { recursive: true });
|
|
493
|
+
const { pid: existing, alive: existingAlive } = readPidAlive(pidFile);
|
|
494
|
+
if (existingAlive) {
|
|
495
|
+
log(`server already running (pid ${existing})`);
|
|
496
|
+
return { ok: true, pid: existing, logPath: logFile, alreadyRunning: true };
|
|
497
|
+
}
|
|
498
|
+
// Stale PID file → clean up.
|
|
499
|
+
if (existing && !existingAlive) {
|
|
500
|
+
try {
|
|
501
|
+
unlinkSync(pidFile);
|
|
502
|
+
} catch (err) {
|
|
503
|
+
console.warn('[lightrag] swallowed in startServer.unlinkStalePid:', err?.message || err);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (!findLightragBinary()) {
|
|
508
|
+
_lightragNotInstalled = true;
|
|
509
|
+
return {
|
|
510
|
+
ok: false,
|
|
511
|
+
error:
|
|
512
|
+
'lightrag-server not installed. Run `uv tool install "lightrag-hku[api]"` to install.',
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Spawn detached so the parent's lifetime doesn't drag the server down.
|
|
517
|
+
const bin = findLightragBinary();
|
|
518
|
+
log(`starting ${bin} on http://${config.host}:${config.port} (working-dir ${config.workingDir})`);
|
|
519
|
+
|
|
520
|
+
const child = spawn(
|
|
521
|
+
bin,
|
|
522
|
+
[
|
|
523
|
+
'--host', config.host,
|
|
524
|
+
'--port', String(config.port),
|
|
525
|
+
'--working-dir', config.workingDir,
|
|
526
|
+
'--llm-binding', config.llmBinding || 'ollama',
|
|
527
|
+
'--embedding-binding', config.embeddingBinding || 'ollama',
|
|
528
|
+
],
|
|
529
|
+
{
|
|
530
|
+
cwd: config.workingDir,
|
|
531
|
+
env: {
|
|
532
|
+
...process.env,
|
|
533
|
+
HOST: config.host,
|
|
534
|
+
PORT: String(config.port),
|
|
535
|
+
WORKING_DIR: config.workingDir,
|
|
536
|
+
LLM_MODEL: config.llmModel,
|
|
537
|
+
EMBEDDING_MODEL: config.embeddingModel,
|
|
538
|
+
LLM_BINDING: config.llmBinding || 'ollama',
|
|
539
|
+
EMBEDDING_BINDING: config.embeddingBinding || 'ollama',
|
|
540
|
+
...(config.llmBindingHost ? { LLM_BINDING_HOST: config.llmBindingHost } : {}),
|
|
541
|
+
...(config.embeddingBindingHost ? { EMBEDDING_BINDING_HOST: config.embeddingBindingHost } : {}),
|
|
542
|
+
},
|
|
543
|
+
detached: true,
|
|
544
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
545
|
+
},
|
|
546
|
+
);
|
|
547
|
+
|
|
548
|
+
// Detach the child so it survives the parent exiting.
|
|
549
|
+
child.unref();
|
|
550
|
+
|
|
551
|
+
// Tee stdout + stderr to log file.
|
|
552
|
+
let fd = -1;
|
|
553
|
+
try {
|
|
554
|
+
fd = openSync(logFile, 'a');
|
|
555
|
+
child.stdout?.on('data', (d) => {
|
|
556
|
+
try { writeSync(fd, d); } catch (err) {
|
|
557
|
+
if (_rateLimit('lightrag-write-stdout')) logWarn('lightrag stream write failed (stdout)', { module: 'lightrag', err: err?.message || String(err) });
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
child.stderr?.on('data', (d) => {
|
|
561
|
+
try { writeSync(fd, d); } catch (err) {
|
|
562
|
+
if (_rateLimit('lightrag-write-stderr')) logWarn('lightrag stream write failed (stderr)', { module: 'lightrag', err: err?.message || String(err) });
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
child.on('exit', (code, signal) => {
|
|
566
|
+
try { closeSync(fd); } catch (err) {
|
|
567
|
+
if (_rateLimit('lightrag-close-fd')) logWarn('lightrag close fd failed', { module: 'lightrag', err: err?.message || String(err) });
|
|
568
|
+
}
|
|
569
|
+
try { unlinkSync(pidFile); } catch (err) {
|
|
570
|
+
if (_rateLimit('lightrag-exit-unlink')) logWarn('lightrag pid unlink failed', { module: 'lightrag', err: err?.message || String(err) });
|
|
571
|
+
}
|
|
572
|
+
log(`lightrag-server exited (code=${code}, signal=${signal})`);
|
|
573
|
+
});
|
|
574
|
+
} catch (openErr) {
|
|
575
|
+
err(`failed to open log file ${logFile}: ${openErr.message}`);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
writeFileSync(pidFile, String(child.pid));
|
|
579
|
+
|
|
580
|
+
// Poll /health until ready or timeout.
|
|
581
|
+
const deadline = Date.now() + config.startupTimeoutMs;
|
|
582
|
+
while (Date.now() < deadline) {
|
|
583
|
+
if (await isRunning(config)) {
|
|
584
|
+
log(`lightrag-server ready on http://${config.host}:${config.port}`);
|
|
585
|
+
return { ok: true, pid: child.pid, logPath: logFile };
|
|
586
|
+
}
|
|
587
|
+
await new Promise((r) => setTimeout(r, config.pollMs));
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return {
|
|
591
|
+
ok: false,
|
|
592
|
+
pid: child.pid,
|
|
593
|
+
logPath: logFile,
|
|
594
|
+
error: `started but /health did not respond within ${config.startupTimeoutMs}ms`,
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Stop the LightRAG server. SIGTERM, then SIGKILL after 5s.
|
|
600
|
+
*/
|
|
601
|
+
export async function stopServer(config, { logger } = {}) {
|
|
602
|
+
const log = (...a) => logger?.info?.('[lightrag]', ...a) || console.log('[lightrag]', ...a);
|
|
603
|
+
const pidFile = join(config.workingDir, 'lightrag.pid');
|
|
604
|
+
const { pid, alive } = readPidAlive(pidFile);
|
|
605
|
+
if (!pid || !alive) {
|
|
606
|
+
try { unlinkSync(pidFile); } catch (err) {
|
|
607
|
+
if (_rateLimit('lightrag-stop-notrunning-unlink')) logWarn('lightrag pid unlink failed (not running)', { module: 'lightrag', err: err?.message || String(err) });
|
|
608
|
+
}
|
|
609
|
+
return { ok: true, message: 'not running' };
|
|
610
|
+
}
|
|
611
|
+
log(`stopping lightrag-server (pid ${pid})`);
|
|
612
|
+
killPid(pid, 'SIGTERM');
|
|
613
|
+
await new Promise((r) => setTimeout(r, 5000));
|
|
614
|
+
if (killPid(pid, 0)) {
|
|
615
|
+
log(`escalating to SIGKILL (pid ${pid})`);
|
|
616
|
+
killPid(pid, 'SIGKILL');
|
|
617
|
+
}
|
|
618
|
+
try { unlinkSync(pidFile); } catch (err) {
|
|
619
|
+
if (_rateLimit('lightrag-stop-unlink')) logWarn('lightrag pid unlink failed (stop)', { module: 'lightrag', err: err?.message || String(err) });
|
|
620
|
+
}
|
|
621
|
+
return { ok: true, message: 'stopped' };
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Idempotent: returns immediately if the server is healthy. Otherwise
|
|
626
|
+
* starts it. Returns { ok, started, pid?, error? }.
|
|
627
|
+
*
|
|
628
|
+
* v5.x — Before starting, calls `detectAvailableLLM` to check whether
|
|
629
|
+
* the configured LLM provider is reachable. If no provider is detected
|
|
630
|
+
* (ollama unreachable + no API key), returns { ok: false } with a
|
|
631
|
+
* descriptive error rather than starting LightRAG in a broken state.
|
|
632
|
+
*/
|
|
633
|
+
export async function ensureRunning(config, opts) {
|
|
634
|
+
if (!config.enabled) {
|
|
635
|
+
return { ok: false, started: false, error: 'lightrag disabled in .bizar/memory.json' };
|
|
636
|
+
}
|
|
637
|
+
if (await isRunning(config)) {
|
|
638
|
+
return { ok: true, started: false };
|
|
639
|
+
}
|
|
640
|
+
// v5.x — probe LLM availability before attempting to start.
|
|
641
|
+
const llm = await detectAvailableLLM(config);
|
|
642
|
+
if (!llm) {
|
|
643
|
+
const binding = config.llmBinding || 'ollama';
|
|
644
|
+
return {
|
|
645
|
+
ok: false,
|
|
646
|
+
started: false,
|
|
647
|
+
error: `lightrag cannot start: ${binding} is not reachable and no API key is configured. `
|
|
648
|
+
+ `Set an API key env var (OPENAI_API_KEY, ANTHROPIC_API_KEY, or MINIMAX_API_KEY) `
|
|
649
|
+
+ `or ensure ollama is running, then try again.`,
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
const r = await startServer(config, opts);
|
|
653
|
+
return { ok: r.ok, started: r.ok, pid: r.pid, error: r.error };
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* v5.x — LightRAG startup hook (issue #6).
|
|
658
|
+
*
|
|
659
|
+
* Called by server.mjs on dashboard boot (and exposed via
|
|
660
|
+
* `bizar lightrag autostart`). Reads the active project from
|
|
661
|
+
* `state.projectRoot` (or whatever is passed in), resolves the
|
|
662
|
+
* LightRAG config, and starts the server if the user's settings
|
|
663
|
+
* allow it.
|
|
664
|
+
*
|
|
665
|
+
* Decision flow:
|
|
666
|
+
* 1. Resolve config from .bizar/memory.json — if `lightrag.enabled`
|
|
667
|
+
* is `false`, skip silently (return ok=true, started=false,
|
|
668
|
+
* reason='disabled').
|
|
669
|
+
* 2. Read the env override `BIZAR_LIGHTRAG_AUTOSTART` — if set to
|
|
670
|
+
* '0' / 'false' / 'no', skip.
|
|
671
|
+
* 3. Check if the server is already running — if so, return
|
|
672
|
+
* ok=true, started=false, reason='already-running'.
|
|
673
|
+
* 4. Probe LLM availability (detectAvailableLLM) — if unreachable
|
|
674
|
+
* AND no API key is configured, log a clear warning but still
|
|
675
|
+
* attempt to start the server (the user may have installed
|
|
676
|
+
* ollama mid-session or configured a key after boot).
|
|
677
|
+
* 5. Call `startServer(config)` and return its result.
|
|
678
|
+
*
|
|
679
|
+
* Errors are caught and logged as warnings — startup must not fail
|
|
680
|
+
* the dashboard just because LightRAG couldn't be started (the user
|
|
681
|
+
* may not have the binary installed, may be running the dashboard
|
|
682
|
+
* in an environment where LightRAG isn't needed, etc.).
|
|
683
|
+
*
|
|
684
|
+
* @param {string} projectRoot — path to the active project root
|
|
685
|
+
* (where `.bizar/memory.json` lives). When omitted, the hook
|
|
686
|
+
* returns ok=false with reason='no-project' (the caller didn't
|
|
687
|
+
* tell us where to look).
|
|
688
|
+
* @param {{ logger?: { info?: Function, warn?: Function } }} [opts]
|
|
689
|
+
* @returns {Promise<{ ok: boolean, started: boolean, pid?: number|null, reason?: string, error?: string }>}
|
|
690
|
+
*/
|
|
691
|
+
export async function lightragStartupHook(projectRoot, opts = {}) {
|
|
692
|
+
const log = (...a) => opts?.logger?.info?.('[lightrag]', ...a) || console.log('[lightrag]', ...a);
|
|
693
|
+
const warn = (...a) => opts?.logger?.warn?.('[lightrag]', ...a) || console.warn('[lightrag]', ...a);
|
|
694
|
+
|
|
695
|
+
// 1. No project → can't resolve config.
|
|
696
|
+
if (!projectRoot || typeof projectRoot !== 'string') {
|
|
697
|
+
return { ok: false, started: false, reason: 'no-project' };
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// 2. Resolve config (from .bizar/memory.json).
|
|
701
|
+
let config;
|
|
702
|
+
try {
|
|
703
|
+
config = resolveLightRAGConfig(projectRoot);
|
|
704
|
+
} catch (err) {
|
|
705
|
+
warn('startup hook: failed to resolve config:', err?.message || err);
|
|
706
|
+
return { ok: false, started: false, error: err?.message || String(err) };
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// 3. Check lightrag.enabled flag.
|
|
710
|
+
if (config.enabled === false) {
|
|
711
|
+
_lightragNotInstalled = true;
|
|
712
|
+
log('startup hook: lightrag disabled in .bizar/memory.json, skipping');
|
|
713
|
+
return { ok: true, started: false, reason: 'disabled' };
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// 4. Check env-var override.
|
|
717
|
+
const envAuto = process.env.BIZAR_LIGHTRAG_AUTOSTART;
|
|
718
|
+
if (typeof envAuto === 'string' && /^(0|false|no|off)$/i.test(envAuto.trim())) {
|
|
719
|
+
_lightragNotInstalled = true;
|
|
720
|
+
log(`startup hook: BIZAR_LIGHTRAG_AUTOSTART=${envAuto}, skipping`);
|
|
721
|
+
return { ok: true, started: false, reason: 'env-disabled' };
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// 5. Already running? Nothing to do.
|
|
725
|
+
try {
|
|
726
|
+
if (await isRunning(config)) {
|
|
727
|
+
log('startup hook: lightrag already running');
|
|
728
|
+
return { ok: true, started: false, reason: 'already-running' };
|
|
729
|
+
}
|
|
730
|
+
} catch (err) {
|
|
731
|
+
warn('startup hook: isRunning probe failed:', err?.message || err);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// 6. Probe LLM availability — log a warning if unreachable + no API key,
|
|
735
|
+
// but still attempt to start (user may have installed ollama mid-session).
|
|
736
|
+
const llm = await detectAvailableLLM(config);
|
|
737
|
+
if (!llm) {
|
|
738
|
+
const binding = config.llmBinding || 'ollama';
|
|
739
|
+
warn(
|
|
740
|
+
`startup hook: ${binding} is not reachable and no API key is configured. ` +
|
|
741
|
+
`LightRAG may start in a degraded state. ` +
|
|
742
|
+
`Set an API key env var (OPENAI_API_KEY, ANTHROPIC_API_KEY, or MINIMAX_API_KEY) ` +
|
|
743
|
+
`or ensure ollama is running.`,
|
|
744
|
+
);
|
|
745
|
+
} else {
|
|
746
|
+
log(`startup hook: LLM detected: ${llm.provider} (${llm.detail})`);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// 7. Try to start — still attempt even if LLM probe failed (see step 6 note).
|
|
750
|
+
try {
|
|
751
|
+
const r = await startServer(config, opts);
|
|
752
|
+
if (r.ok) {
|
|
753
|
+
if (r.alreadyRunning) {
|
|
754
|
+
log(`startup hook: lightrag already running (pid=${r.pid})`);
|
|
755
|
+
return { ok: true, started: false, reason: 'already-running', pid: r.pid };
|
|
756
|
+
}
|
|
757
|
+
log(`startup hook: lightrag started (pid=${r.pid})`);
|
|
758
|
+
return { ok: true, started: true, pid: r.pid };
|
|
759
|
+
}
|
|
760
|
+
warn(`startup hook: start failed: ${r.error || 'unknown'}`);
|
|
761
|
+
return { ok: false, started: false, error: r.error || 'start failed' };
|
|
762
|
+
} catch (err) {
|
|
763
|
+
// Catch-all: dashboard boot must not fail because LightRAG couldn't
|
|
764
|
+
// start. Common causes: binary missing (lightrag-server not on PATH),
|
|
765
|
+
// port already in use, working-dir not writable.
|
|
766
|
+
warn('startup hook: caught error:', err?.message || err);
|
|
767
|
+
return { ok: false, started: false, error: err?.message || String(err) };
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// ── Document insertion ────────────────────────────────────────────────────
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Build a deterministic id for a note: `bizar://<projectId>/<relPath>`.
|
|
775
|
+
* The `bizar://` URI scheme is internal — LightRAG uses it as a stable key.
|
|
776
|
+
*/
|
|
777
|
+
function buildDocId(projectId, relPath) {
|
|
778
|
+
const normalized = relPath.replace(/\\/g, '/').replace(/^\/+/, '');
|
|
779
|
+
return `bizar://${projectId}/${normalized}`;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Build the document text LightRAG will index. We prefix with metadata
|
|
784
|
+
* lines so semantic queries can return "what kind of note was this?"
|
|
785
|
+
* context even when only a snippet survives the chunker.
|
|
786
|
+
*/
|
|
787
|
+
function buildDocText(projectId, relPath, note) {
|
|
788
|
+
const fm = note.frontmatter || {};
|
|
789
|
+
const tags = Array.isArray(fm.tags) ? fm.tags.join(', ') : (fm.tags || '');
|
|
790
|
+
const lines = [
|
|
791
|
+
`Source: bizar://${projectId}/${relPath.replace(/^\/+/, '')}`,
|
|
792
|
+
`Project: ${fm.project_id || projectId}`,
|
|
793
|
+
`Type: ${fm.type || 'unknown'}`,
|
|
794
|
+
`Status: ${fm.status || 'unknown'}`,
|
|
795
|
+
`Confidence: ${fm.confidence || 'unknown'}`,
|
|
796
|
+
`Tags: ${tags}`,
|
|
797
|
+
`Memory ID: ${fm.memory_id || ''}`,
|
|
798
|
+
'',
|
|
799
|
+
note.body || '',
|
|
800
|
+
];
|
|
801
|
+
return lines.join('\n');
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Insert one note into LightRAG. Returns { ok, trackId, error? }.
|
|
806
|
+
*
|
|
807
|
+
* LightRAG's HTTP API for inserting a single document is
|
|
808
|
+
* `POST /documents` (text in body, optional `file_source` for tracking).
|
|
809
|
+
* We send: { text, file_source: docId }.
|
|
810
|
+
*/
|
|
811
|
+
export async function insertNote(config, projectId, note) {
|
|
812
|
+
if (!note?.relPath) return { ok: false, error: 'note.relPath required' };
|
|
813
|
+
const docId = buildDocId(projectId, note.relPath);
|
|
814
|
+
const text = buildDocText(projectId, note.relPath, note);
|
|
815
|
+
|
|
816
|
+
const url = `http://${config.host}:${config.port}/documents/text`;
|
|
817
|
+
const body = {
|
|
818
|
+
text,
|
|
819
|
+
file_source: docId,
|
|
820
|
+
};
|
|
821
|
+
try {
|
|
822
|
+
const res = await httpPost(url, body, config.timeoutMs);
|
|
823
|
+
if (res.status >= 200 && res.status < 300) {
|
|
824
|
+
let parsed;
|
|
825
|
+
try { parsed = JSON.parse(res.body); } catch { parsed = { raw: res.body }; }
|
|
826
|
+
return { ok: true, trackId: docId, response: parsed };
|
|
827
|
+
}
|
|
828
|
+
return { ok: false, trackId: docId, error: `HTTP ${res.status}: ${res.body.slice(0, 200)}` };
|
|
829
|
+
} catch (err) {
|
|
830
|
+
return { ok: false, trackId: docId, error: err.message };
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Insert all notes. Returns aggregate { inserted, failed, durationMs }.
|
|
836
|
+
*
|
|
837
|
+
* Sequential insertion — LightRAG's API is request-per-document and
|
|
838
|
+
* concurrent inserts may overwhelm the embedder. For 100+ notes we
|
|
839
|
+
* could batch; for the BizarHarness KB (15-30 notes), sequential is fine.
|
|
840
|
+
*/
|
|
841
|
+
export async function insertAllNotes(config, projectId, notes, { logger } = {}) {
|
|
842
|
+
const log = (...a) => logger?.info?.('[lightrag]', ...a) || logger?.log?.(...a) || console.log('[lightrag]', ...a);
|
|
843
|
+
const start = Date.now();
|
|
844
|
+
let inserted = 0;
|
|
845
|
+
let failed = 0;
|
|
846
|
+
const failures = [];
|
|
847
|
+
for (let i = 0; i < notes.length; i++) {
|
|
848
|
+
const note = notes[i];
|
|
849
|
+
const r = await insertNote(config, projectId, note);
|
|
850
|
+
if (r.ok) {
|
|
851
|
+
inserted++;
|
|
852
|
+
} else {
|
|
853
|
+
failed++;
|
|
854
|
+
failures.push({ relPath: note.relPath, error: r.error });
|
|
855
|
+
}
|
|
856
|
+
if ((i + 1) % 10 === 0 || i === notes.length - 1) {
|
|
857
|
+
log(`progress: ${i + 1}/${notes.length} (inserted=${inserted}, failed=${failed})`);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
return { inserted, failed, failures, durationMs: Date.now() - start };
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// ── Top-level orchestrators ────────────────────────────────────────────────
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* Reindex the entire vault into LightRAG.
|
|
867
|
+
*
|
|
868
|
+
* 1. Resolve config + vault.
|
|
869
|
+
* 2. List notes from disk.
|
|
870
|
+
* 3. Ensure server is running (auto-start).
|
|
871
|
+
* 4. Insert each note.
|
|
872
|
+
* 5. Write marker file with stats.
|
|
873
|
+
*
|
|
874
|
+
* Returns { ok, started, inserted, failed, failures, durationMs, startedAt,
|
|
875
|
+
* markerPath, error? }.
|
|
876
|
+
*/
|
|
877
|
+
export async function reindexVault(projectRoot, opts = {}) {
|
|
878
|
+
const startedAt = new Date().toISOString();
|
|
879
|
+
// Resolve config + vault by reading memory.json directly to avoid
|
|
880
|
+
// pulling in memory-store (which itself imports this module — would cycle).
|
|
881
|
+
const config = resolveLightRAGConfig(projectRoot);
|
|
882
|
+
if (!config.enabled) {
|
|
883
|
+
return { ok: false, started: false, error: 'lightrag disabled in .bizar/memory.json' };
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// Ensure vault dir exists; list notes.
|
|
887
|
+
const memPath = join(projectRoot, '.bizar', 'memory.json');
|
|
888
|
+
if (!existsSync(memPath)) {
|
|
889
|
+
return { ok: false, error: 'memory not initialized — run `bizar memory init` first' };
|
|
890
|
+
}
|
|
891
|
+
const mem = JSON.parse(readFileSync(memPath, 'utf8'));
|
|
892
|
+
const mode = mem.memoryRepo?.mode || 'local-only';
|
|
893
|
+
let vaultRoot;
|
|
894
|
+
let projectId = mem.projectId || basename(projectRoot);
|
|
895
|
+
if (mode === 'local-only') {
|
|
896
|
+
vaultRoot = join(projectRoot, '.obsidian');
|
|
897
|
+
} else {
|
|
898
|
+
const rawPath = mem.memoryRepo?.path || '';
|
|
899
|
+
let expanded;
|
|
900
|
+
if (!rawPath) {
|
|
901
|
+
expanded = join(projectRoot, '.bizar', 'memory');
|
|
902
|
+
} else if (rawPath.startsWith('~')) {
|
|
903
|
+
expanded = join(homedir(), rawPath.slice(1));
|
|
904
|
+
} else if (rawPath.startsWith('/')) {
|
|
905
|
+
expanded = rawPath;
|
|
906
|
+
} else {
|
|
907
|
+
expanded = join(projectRoot, rawPath);
|
|
908
|
+
}
|
|
909
|
+
vaultRoot = join(expanded, 'projects', projectId);
|
|
910
|
+
}
|
|
911
|
+
if (!existsSync(vaultRoot)) {
|
|
912
|
+
return { ok: false, error: `vault not found at ${vaultRoot} — run \`bizar memory init\`` };
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
// Collect all .md files in vault (skip dotfiles).
|
|
916
|
+
const notes = [];
|
|
917
|
+
function walk(dir, prefix) {
|
|
918
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
919
|
+
if (entry.name.startsWith('.')) continue;
|
|
920
|
+
const full = join(dir, entry.name);
|
|
921
|
+
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
922
|
+
if (entry.isDirectory()) {
|
|
923
|
+
walk(full, rel);
|
|
924
|
+
} else if (entry.name.endsWith('.md')) {
|
|
925
|
+
const raw = readFileSync(full, 'utf8');
|
|
926
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
927
|
+
notes.push({ relPath: rel, frontmatter, body });
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
walk(vaultRoot, '');
|
|
932
|
+
|
|
933
|
+
// Always write a marker (even on failure) so `bizar memory status`
|
|
934
|
+
// can report when the last attempt was.
|
|
935
|
+
const cacheDir = join(projectRoot, '.bizar', 'memory-cache');
|
|
936
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
937
|
+
const markerPath = join(cacheDir, 'last-reindex.json');
|
|
938
|
+
const writeMarker = (extra) => {
|
|
939
|
+
if (!config.writeMarker) return;
|
|
940
|
+
const marker = {
|
|
941
|
+
attemptedAt: startedAt,
|
|
942
|
+
finishedAt: new Date().toISOString(),
|
|
943
|
+
durationMs: Date.now() - new Date(startedAt).getTime(),
|
|
944
|
+
ok: false,
|
|
945
|
+
noteCount: notes.length,
|
|
946
|
+
inserted: 0,
|
|
947
|
+
failed: 0,
|
|
948
|
+
failures: [],
|
|
949
|
+
lightrag: {
|
|
950
|
+
host: config.host,
|
|
951
|
+
port: config.port,
|
|
952
|
+
workingDir: config.workingDir,
|
|
953
|
+
},
|
|
954
|
+
...extra,
|
|
955
|
+
};
|
|
956
|
+
atomicWriteJson(markerPath, marker);
|
|
957
|
+
};
|
|
958
|
+
|
|
959
|
+
// Ensure server is up.
|
|
960
|
+
const runResult = await ensureRunning(config, opts);
|
|
961
|
+
if (!runResult.ok) {
|
|
962
|
+
const reason = runResult.error || 'lightrag not running';
|
|
963
|
+
writeMarker({ error: reason, ok: false });
|
|
964
|
+
return {
|
|
965
|
+
ok: false,
|
|
966
|
+
started: false,
|
|
967
|
+
error: reason,
|
|
968
|
+
noteCount: notes.length,
|
|
969
|
+
markerPath,
|
|
970
|
+
startedAt,
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// Insert all notes.
|
|
975
|
+
const result = await insertAllNotes(config, projectId, notes, opts);
|
|
976
|
+
|
|
977
|
+
// Write success marker.
|
|
978
|
+
writeMarker({
|
|
979
|
+
durationMs: result.durationMs,
|
|
980
|
+
ok: result.failed === 0,
|
|
981
|
+
started: runResult.started,
|
|
982
|
+
pid: runResult.pid,
|
|
983
|
+
projectId,
|
|
984
|
+
vaultRoot,
|
|
985
|
+
inserted: result.inserted,
|
|
986
|
+
failed: result.failed,
|
|
987
|
+
failures: result.failures.slice(0, 50),
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
return {
|
|
991
|
+
ok: result.failed === 0,
|
|
992
|
+
started: runResult.started,
|
|
993
|
+
pid: runResult.pid,
|
|
994
|
+
inserted: result.inserted,
|
|
995
|
+
failed: result.failed,
|
|
996
|
+
failures: result.failures,
|
|
997
|
+
durationMs: result.durationMs,
|
|
998
|
+
noteCount: notes.length,
|
|
999
|
+
markerPath,
|
|
1000
|
+
startedAt,
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* v5.x — Re-index a single note into LightRAG.
|
|
1006
|
+
*
|
|
1007
|
+
* Use this for incremental updates (e.g. after a note is written or
|
|
1008
|
+
* updated via the REST API). Unlike `reindexVault` which walks the entire
|
|
1009
|
+
* vault, this only inserts one document.
|
|
1010
|
+
*
|
|
1011
|
+
* Returns { ok, inserted, failed, error? }.
|
|
1012
|
+
*/
|
|
1013
|
+
export async function reindexSingleNote(projectRoot, relPath, opts = {}) {
|
|
1014
|
+
const config = resolveLightRAGConfig(projectRoot);
|
|
1015
|
+
if (!config.enabled) {
|
|
1016
|
+
return { ok: false, error: 'lightrag disabled' };
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
// Resolve vault path (same logic as reindexVault).
|
|
1020
|
+
const memPath = join(projectRoot, '.bizar', 'memory.json');
|
|
1021
|
+
if (!existsSync(memPath)) {
|
|
1022
|
+
return { ok: false, error: 'memory not initialized' };
|
|
1023
|
+
}
|
|
1024
|
+
const mem = JSON.parse(readFileSync(memPath, 'utf8'));
|
|
1025
|
+
const mode = mem.memoryRepo?.mode || 'local-only';
|
|
1026
|
+
let vaultRoot;
|
|
1027
|
+
const projectId = mem.projectId || basename(projectRoot);
|
|
1028
|
+
if (mode === 'local-only') {
|
|
1029
|
+
vaultRoot = join(projectRoot, '.obsidian');
|
|
1030
|
+
} else {
|
|
1031
|
+
const rawPath = mem.memoryRepo?.path || '';
|
|
1032
|
+
let expanded;
|
|
1033
|
+
if (!rawPath) {
|
|
1034
|
+
expanded = join(projectRoot, '.bizar', 'memory');
|
|
1035
|
+
} else if (rawPath.startsWith('~')) {
|
|
1036
|
+
expanded = join(homedir(), rawPath.slice(1));
|
|
1037
|
+
} else if (rawPath.startsWith('/')) {
|
|
1038
|
+
expanded = rawPath;
|
|
1039
|
+
} else {
|
|
1040
|
+
expanded = join(projectRoot, rawPath);
|
|
1041
|
+
}
|
|
1042
|
+
vaultRoot = join(expanded, 'projects', projectId);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
const fullPath = join(vaultRoot, relPath);
|
|
1046
|
+
if (!fullPath.startsWith(vaultRoot)) {
|
|
1047
|
+
return { ok: false, error: 'path traversal attempt blocked' };
|
|
1048
|
+
}
|
|
1049
|
+
if (!existsSync(fullPath)) {
|
|
1050
|
+
return { ok: false, error: `note not found: ${relPath}` };
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// Ensure server is running (uses the same LLM-detection logic as reindexVault).
|
|
1054
|
+
const runResult = await ensureRunning(config, opts);
|
|
1055
|
+
if (!runResult.ok) {
|
|
1056
|
+
return { ok: false, error: runResult.error || 'lightrag server unavailable' };
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
const raw = readFileSync(fullPath, 'utf8');
|
|
1060
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
1061
|
+
const note = { relPath, frontmatter, body };
|
|
1062
|
+
const r = await insertNote(config, projectId, note);
|
|
1063
|
+
|
|
1064
|
+
return {
|
|
1065
|
+
ok: r.ok,
|
|
1066
|
+
inserted: r.ok ? 1 : 0,
|
|
1067
|
+
failed: r.ok ? 0 : 1,
|
|
1068
|
+
error: r.error,
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
/**
|
|
1073
|
+
* Query LightRAG. Returns { ok, mode, response, error? }.
|
|
1074
|
+
*
|
|
1075
|
+
* LightRAG's `/query` endpoint accepts:
|
|
1076
|
+
* { query: string, mode?: 'local'|'global'|'hybrid'|'mix', top_k?: number,
|
|
1077
|
+
* conversation_history?: [], user_prompt?: string, response_type?: string }
|
|
1078
|
+
*/
|
|
1079
|
+
export async function query(config, question, { mode = 'mix', topK = 10 } = {}) {
|
|
1080
|
+
if (!config.enabled) {
|
|
1081
|
+
return { ok: false, error: 'lightrag disabled in .bizar/memory.json' };
|
|
1082
|
+
}
|
|
1083
|
+
if (!(await isRunning(config))) {
|
|
1084
|
+
return { ok: false, error: 'lightrag server not running — run `bizar memory reindex` first' };
|
|
1085
|
+
}
|
|
1086
|
+
const url = `http://${config.host}:${config.port}/query`;
|
|
1087
|
+
try {
|
|
1088
|
+
const res = await httpPost(url, {
|
|
1089
|
+
query: question,
|
|
1090
|
+
mode,
|
|
1091
|
+
top_k: topK,
|
|
1092
|
+
response_type: 'Multiple Paragraphs',
|
|
1093
|
+
}, config.timeoutMs);
|
|
1094
|
+
if (res.status >= 200 && res.status < 300) {
|
|
1095
|
+
let parsed;
|
|
1096
|
+
try { parsed = JSON.parse(res.body); } catch { parsed = { response: res.body }; }
|
|
1097
|
+
return { ok: true, mode, response: parsed };
|
|
1098
|
+
}
|
|
1099
|
+
return { ok: false, mode, error: `HTTP ${res.status}: ${res.body.slice(0, 200)}` };
|
|
1100
|
+
} catch (err) {
|
|
1101
|
+
return { ok: false, mode, error: err.message };
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// ── v4.7.0 — Memory tab helpers ─────────────────────────────────────────────
|
|
1106
|
+
//
|
|
1107
|
+
// Lightweight status / stats / rebuild helpers used by the dedicated Memory
|
|
1108
|
+
// view. The full reindexVault path above already produces a marker file with
|
|
1109
|
+
// most of the numbers we want; these helpers are thin wrappers around it.
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* Aggregate stats for the Memory → LightRAG panel.
|
|
1113
|
+
*
|
|
1114
|
+
* Pulls from:
|
|
1115
|
+
* - the last-reindex.json marker file (writeMarker: true leaves it)
|
|
1116
|
+
* - the configured working dir (where chunks/index files live)
|
|
1117
|
+
* - the running server (PID, alive)
|
|
1118
|
+
*
|
|
1119
|
+
* Returns a defensive default when nothing has been indexed yet.
|
|
1120
|
+
*
|
|
1121
|
+
* @param {string} projectRoot
|
|
1122
|
+
* @returns {{
|
|
1123
|
+
* running: boolean,
|
|
1124
|
+
* pid: number|null,
|
|
1125
|
+
* host: string,
|
|
1126
|
+
* port: number,
|
|
1127
|
+
* workingDir: string,
|
|
1128
|
+
* lastReindexAt: string|null,
|
|
1129
|
+
* lastReindexOk: boolean|null,
|
|
1130
|
+
* lastReindexInserted: number|null,
|
|
1131
|
+
* lastReindexFailed: number|null,
|
|
1132
|
+
* noteCount: number,
|
|
1133
|
+
* indexedApprox: number,
|
|
1134
|
+
* queryCountLast24h: number,
|
|
1135
|
+
* avgResponseMs: number|null,
|
|
1136
|
+
* error?: string,
|
|
1137
|
+
* }}
|
|
1138
|
+
*/
|
|
1139
|
+
export async function stats(projectRoot) {
|
|
1140
|
+
const config = resolveLightRAGConfig(projectRoot);
|
|
1141
|
+
const cacheDir = join(projectRoot, '.bizar', 'memory-cache');
|
|
1142
|
+
const markerPath = join(cacheDir, 'last-reindex.json');
|
|
1143
|
+
const running = await isRunning(config);
|
|
1144
|
+
let pid = null;
|
|
1145
|
+
const pidFile = join(config.workingDir, 'lightrag.pid');
|
|
1146
|
+
if (existsSync(pidFile)) {
|
|
1147
|
+
const parsed = parseIntSafe(readFileSync(pidFile, 'utf8'));
|
|
1148
|
+
if (parsed !== null && parsed > 0) {
|
|
1149
|
+
try {
|
|
1150
|
+
process.kill(parsed, 0);
|
|
1151
|
+
pid = parsed;
|
|
1152
|
+
} catch (err) {
|
|
1153
|
+
console.warn('[lightrag] swallowed in stats.pidProbe:', err?.message || err);
|
|
1154
|
+
pid = null;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
let lastReindexAt = null;
|
|
1160
|
+
let lastReindexOk = null;
|
|
1161
|
+
let lastReindexInserted = null;
|
|
1162
|
+
let lastReindexFailed = null;
|
|
1163
|
+
if (existsSync(markerPath)) {
|
|
1164
|
+
try {
|
|
1165
|
+
const m = JSON.parse(readFileSync(markerPath, 'utf8'));
|
|
1166
|
+
lastReindexAt = m.finishedAt || m.attemptedAt || null;
|
|
1167
|
+
lastReindexOk = m.ok === true;
|
|
1168
|
+
lastReindexInserted = typeof m.inserted === 'number' ? m.inserted : null;
|
|
1169
|
+
lastReindexFailed = typeof m.failed === 'number' ? m.failed : null;
|
|
1170
|
+
} catch (err) {
|
|
1171
|
+
console.warn('[lightrag] swallowed in stats.markerRead:', err?.message || err);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
// Approximate the indexed chunk count from the on-disk KV store. LightRAG
|
|
1176
|
+
// writes its chunks to <workingDir>/kv_store_*.json. We sum the lengths of
|
|
1177
|
+
// the document store as a proxy for "indexed documents"; this is best-effort
|
|
1178
|
+
// and clearly labeled as approximate.
|
|
1179
|
+
let indexedApprox = 0;
|
|
1180
|
+
try {
|
|
1181
|
+
const docStore = join(config.workingDir, 'kv_store_doc_status.json');
|
|
1182
|
+
const fullDocs = join(config.workingDir, 'kv_store_full_docs.json');
|
|
1183
|
+
for (const p of [docStore, fullDocs]) {
|
|
1184
|
+
if (existsSync(p)) {
|
|
1185
|
+
try {
|
|
1186
|
+
const obj = JSON.parse(readFileSync(p, 'utf8'));
|
|
1187
|
+
indexedApprox += Object.keys(obj || {}).length;
|
|
1188
|
+
} catch (err) {
|
|
1189
|
+
console.warn('[lightrag] swallowed in stats.kvStoreRead:', err?.message || err);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
} catch (err) {
|
|
1194
|
+
console.warn('[lightrag] swallowed in stats.kvStoreScan:', err?.message || err);
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// Note count = listNotes from the vault.
|
|
1198
|
+
let noteCount = 0;
|
|
1199
|
+
try {
|
|
1200
|
+
const memPath = join(projectRoot, '.bizar', 'memory.json');
|
|
1201
|
+
if (existsSync(memPath)) {
|
|
1202
|
+
const mem = JSON.parse(readFileSync(memPath, 'utf8'));
|
|
1203
|
+
const projectId = mem.projectId || '';
|
|
1204
|
+
const mode = mem.memoryRepo?.mode || 'local-only';
|
|
1205
|
+
let vaultRoot;
|
|
1206
|
+
if (mode === 'local-only') {
|
|
1207
|
+
vaultRoot = join(projectRoot, '.obsidian');
|
|
1208
|
+
} else {
|
|
1209
|
+
const raw = mem.memoryRepo?.path || '';
|
|
1210
|
+
let expanded;
|
|
1211
|
+
if (!raw) expanded = join(projectRoot, '.bizar', 'memory');
|
|
1212
|
+
else if (raw.startsWith('~')) expanded = join(homedir(), raw.slice(1));
|
|
1213
|
+
else if (raw.startsWith('/')) expanded = raw;
|
|
1214
|
+
else expanded = join(projectRoot, raw);
|
|
1215
|
+
vaultRoot = join(expanded, 'projects', projectId);
|
|
1216
|
+
}
|
|
1217
|
+
if (existsSync(vaultRoot)) {
|
|
1218
|
+
const { readdirSync } = await import('node:fs');
|
|
1219
|
+
function walk(dir) {
|
|
1220
|
+
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
1221
|
+
if (e.name.startsWith('.')) continue;
|
|
1222
|
+
const full = join(dir, e.name);
|
|
1223
|
+
if (e.isDirectory()) walk(full);
|
|
1224
|
+
else if (e.name.endsWith('.md')) noteCount++;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
walk(vaultRoot);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
} catch (err) {
|
|
1231
|
+
console.warn('[lightrag] swallowed in stats.noteCount:', err?.message || err);
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
// Query stats: best-effort — LightRAG's /query endpoint doesn't expose
|
|
1235
|
+
// query counts in the open-core build. We track our own running counter
|
|
1236
|
+
// in a sidecar JSON file.
|
|
1237
|
+
const queryLogPath = join(cacheDir, 'lightrag-query-log.jsonl');
|
|
1238
|
+
let queryCountLast24h = 0;
|
|
1239
|
+
let totalResponseMs = 0;
|
|
1240
|
+
let counted = 0;
|
|
1241
|
+
if (existsSync(queryLogPath)) {
|
|
1242
|
+
try {
|
|
1243
|
+
const lines = readFileSync(queryLogPath, 'utf8').split('\n').filter(Boolean);
|
|
1244
|
+
const cutoff = Date.now() - 24 * 60 * 60 * 1000;
|
|
1245
|
+
for (const line of lines) {
|
|
1246
|
+
try {
|
|
1247
|
+
const rec = JSON.parse(line);
|
|
1248
|
+
if (typeof rec.ts === 'number' && rec.ts >= cutoff) {
|
|
1249
|
+
queryCountLast24h++;
|
|
1250
|
+
if (typeof rec.ms === 'number' && Number.isFinite(rec.ms)) {
|
|
1251
|
+
totalResponseMs += rec.ms;
|
|
1252
|
+
counted++;
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
} catch (err) {
|
|
1256
|
+
console.warn('[lightrag] swallowed in stats.queryLogLine:', err?.message || err);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
} catch (err) {
|
|
1260
|
+
console.warn('[lightrag] swallowed in stats.queryLogRead:', err?.message || err);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
const avgResponseMs = counted > 0 ? Math.round(totalResponseMs / counted) : null;
|
|
1264
|
+
|
|
1265
|
+
return {
|
|
1266
|
+
running,
|
|
1267
|
+
pid: running ? pid : null,
|
|
1268
|
+
host: config.host,
|
|
1269
|
+
port: config.port,
|
|
1270
|
+
workingDir: config.workingDir,
|
|
1271
|
+
lastReindexAt,
|
|
1272
|
+
lastReindexOk,
|
|
1273
|
+
lastReindexInserted,
|
|
1274
|
+
lastReindexFailed,
|
|
1275
|
+
noteCount,
|
|
1276
|
+
indexedApprox,
|
|
1277
|
+
queryCountLast24h,
|
|
1278
|
+
avgResponseMs,
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
function parseIntSafe(s) {
|
|
1283
|
+
const n = parseInt(String(s || '').trim(), 10);
|
|
1284
|
+
return Number.isFinite(n) ? n : null;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
/**
|
|
1288
|
+
* Record a query for stats tracking. Called by the /query endpoint so the
|
|
1289
|
+
* Memory tab can show usage. Best-effort; never throws.
|
|
1290
|
+
*
|
|
1291
|
+
* @param {string} projectRoot
|
|
1292
|
+
* @param {number} durationMs
|
|
1293
|
+
*/
|
|
1294
|
+
export function recordQuery(projectRoot, durationMs) {
|
|
1295
|
+
try {
|
|
1296
|
+
const cacheDir = join(projectRoot, '.bizar', 'memory-cache');
|
|
1297
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
1298
|
+
const path = join(cacheDir, 'lightrag-query-log.jsonl');
|
|
1299
|
+
appendFileSafe(path, JSON.stringify({ ts: Date.now(), ms: Math.max(0, Math.round(durationMs)) }) + '\n');
|
|
1300
|
+
// Truncate if file grows past 5MB — keep last ~50k queries.
|
|
1301
|
+
try {
|
|
1302
|
+
const st = statMaybe(path);
|
|
1303
|
+
if (st && st.size > 5 * 1024 * 1024) {
|
|
1304
|
+
const content = readFileSync(path, 'utf8');
|
|
1305
|
+
const lines = content.split('\n');
|
|
1306
|
+
const keep = lines.slice(-50000).join('\n');
|
|
1307
|
+
writeFileSync(path, keep);
|
|
1308
|
+
}
|
|
1309
|
+
} catch (err) {
|
|
1310
|
+
console.warn('[lightrag] swallowed in recordQuery.truncate:', err?.message || err);
|
|
1311
|
+
}
|
|
1312
|
+
} catch (err) {
|
|
1313
|
+
console.warn('[lightrag] swallowed in recordQuery:', err?.message || err);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
function appendFileSafe(path, content) {
|
|
1318
|
+
try {
|
|
1319
|
+
appendFileSync(path, content);
|
|
1320
|
+
} catch (err) {
|
|
1321
|
+
console.warn('[lightrag] appendFileSync failed, falling back to read+write:', err?.message || err);
|
|
1322
|
+
try {
|
|
1323
|
+
const cur = existsSync(path) ? readFileSync(path, 'utf8') : '';
|
|
1324
|
+
writeFileSync(path, cur + content);
|
|
1325
|
+
} catch (err2) {
|
|
1326
|
+
console.warn('[lightrag] swallowed in appendFileSafe.manualWrite:', err2?.message || err2);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
function statMaybe(path) {
|
|
1332
|
+
try {
|
|
1333
|
+
return statSync(path);
|
|
1334
|
+
} catch {
|
|
1335
|
+
return null;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
/**
|
|
1340
|
+
* Get a graph representation of the LightRAG index.
|
|
1341
|
+
*
|
|
1342
|
+
* If `root` is given, fetches entities reachable within `depth` hops
|
|
1343
|
+
* from that entity via LightRAG's /graph endpoint. Otherwise returns
|
|
1344
|
+
* all entities up to `limit`.
|
|
1345
|
+
*
|
|
1346
|
+
* Falls back to reading .bizar/memory/lightrag/kv_store_*.json directly
|
|
1347
|
+
* when the LightRAG server is unavailable.
|
|
1348
|
+
*
|
|
1349
|
+
* @param {{ projectRoot: string, root?: string|null, depth?: number, limit?: number }}
|
|
1350
|
+
* @returns {Promise<{nodes: Array<{id:string,label:string,type:string,size:number,group:string}>, edges: Array<{source:string,target:string,type:string,weight:number}>}>}
|
|
1351
|
+
*/
|
|
1352
|
+
export async function getLightRAGGraph({ projectRoot, root = null, depth = 2, limit = 200 }) {
|
|
1353
|
+
const config = resolveLightRAGConfig(projectRoot);
|
|
1354
|
+
|
|
1355
|
+
// Attempt to query the running server.
|
|
1356
|
+
if (await isRunning(config)) {
|
|
1357
|
+
try {
|
|
1358
|
+
const nodes = [];
|
|
1359
|
+
const edges = [];
|
|
1360
|
+
|
|
1361
|
+
if (root) {
|
|
1362
|
+
// Use LightRAG's /graph endpoint with root entity.
|
|
1363
|
+
const url = `http://${config.host}:${config.port}/graph?root=${encodeURIComponent(root)}&depth=${depth}&limit=${limit}`;
|
|
1364
|
+
const res = await httpGet(url, config.timeoutMs);
|
|
1365
|
+
if (res.status === 200) {
|
|
1366
|
+
let parsed;
|
|
1367
|
+
try { parsed = JSON.parse(res.body); } catch { parsed = {}; }
|
|
1368
|
+
// LightRAG /graph shape varies; normalise to our contract.
|
|
1369
|
+
// LightRAG returns { entities: [...], relations: [...] } or similar.
|
|
1370
|
+
const ents = parsed.entities || parsed.nodes || [];
|
|
1371
|
+
const rels = parsed.relations || parsed.edges || [];
|
|
1372
|
+
for (const e of ents.slice(0, limit)) {
|
|
1373
|
+
const id = String(e.id || e.name || JSON.stringify(e));
|
|
1374
|
+
nodes.push({
|
|
1375
|
+
id,
|
|
1376
|
+
label: String(e.label || e.name || id).slice(0, 60),
|
|
1377
|
+
type: String(e.type || 'entity'),
|
|
1378
|
+
size: Number(e.size || 1),
|
|
1379
|
+
group: String(e.group || e.type || 'default'),
|
|
1380
|
+
});
|
|
1381
|
+
}
|
|
1382
|
+
for (const r of rels) {
|
|
1383
|
+
edges.push({
|
|
1384
|
+
source: String(r.source || r.from || r.src || ''),
|
|
1385
|
+
target: String(r.target || r.to || r.dst || ''),
|
|
1386
|
+
type: String(r.type || 'related'),
|
|
1387
|
+
weight: Number(r.weight || 1),
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
return { nodes, edges };
|
|
1391
|
+
}
|
|
1392
|
+
} else {
|
|
1393
|
+
// Return all entities from kv_store_full_docs.json.
|
|
1394
|
+
const docsPath = join(config.workingDir, 'kv_store_full_docs.json');
|
|
1395
|
+
if (existsSync(docsPath)) {
|
|
1396
|
+
try {
|
|
1397
|
+
const docs = JSON.parse(readFileSync(docsPath, 'utf8'));
|
|
1398
|
+
const keys = Object.keys(docs || {}).slice(0, limit);
|
|
1399
|
+
// Group by top-level path segment as a proxy for group.
|
|
1400
|
+
for (const k of keys) {
|
|
1401
|
+
const parts = k.replace(/^bizar:\/\//, '').split('/');
|
|
1402
|
+
const group = parts.length > 1 ? parts[0] : 'root';
|
|
1403
|
+
nodes.push({
|
|
1404
|
+
id: k,
|
|
1405
|
+
label: parts[parts.length - 1].replace(/[_-]/g, ' '),
|
|
1406
|
+
type: 'note',
|
|
1407
|
+
size: 1,
|
|
1408
|
+
group,
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
return { nodes, edges };
|
|
1412
|
+
} catch (err) {
|
|
1413
|
+
console.warn('[lightrag] getLightRAGGraph fallback read failed:', err?.message);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
} catch (err) {
|
|
1418
|
+
console.warn('[lightrag] getLightRAGGraph server query failed, falling back:', err?.message);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
// Fallback: read kv_store files directly.
|
|
1423
|
+
const nodes = [];
|
|
1424
|
+
const edges = [];
|
|
1425
|
+
try {
|
|
1426
|
+
const docsPath = join(config.workingDir, 'kv_store_full_docs.json');
|
|
1427
|
+
if (existsSync(docsPath)) {
|
|
1428
|
+
const docs = JSON.parse(readFileSync(docsPath, 'utf8'));
|
|
1429
|
+
const keys = Object.keys(docs || {}).slice(0, limit);
|
|
1430
|
+
for (const k of keys) {
|
|
1431
|
+
const parts = k.replace(/^bizar:\/\//, '').split('/');
|
|
1432
|
+
const group = parts.length > 1 ? parts[0] : 'root';
|
|
1433
|
+
nodes.push({
|
|
1434
|
+
id: k,
|
|
1435
|
+
label: parts[parts.length - 1].replace(/[_-]/g, ' '),
|
|
1436
|
+
type: 'note',
|
|
1437
|
+
size: 1,
|
|
1438
|
+
group,
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
} catch (err) {
|
|
1443
|
+
console.warn('[lightrag] getLightRAGGraph fallback read error:', err?.message);
|
|
1444
|
+
}
|
|
1445
|
+
return { nodes, edges };
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
/**
|
|
1449
|
+
* Rebuild the graph from scratch. Stops the server, wipes the working dir,
|
|
1450
|
+
* and re-runs reindexVault. Returns { ok, started, error?, markerPath? }.
|
|
1451
|
+
*
|
|
1452
|
+
* Idempotent: safe to call when the server is already stopped.
|
|
1453
|
+
*
|
|
1454
|
+
* @param {string} projectRoot
|
|
1455
|
+
* @param {{ logger?: { info?: Function, warn?: Function } }} [opts]
|
|
1456
|
+
*/
|
|
1457
|
+
export async function rebuildGraph(projectRoot, opts = {}) {
|
|
1458
|
+
const config = resolveLightRAGConfig(projectRoot);
|
|
1459
|
+
// Stop server first.
|
|
1460
|
+
await stopServer(config, opts).catch(() => {});
|
|
1461
|
+
// Wipe the working dir contents (preserve the dir itself).
|
|
1462
|
+
try {
|
|
1463
|
+
const { readdirSync } = await import('node:fs');
|
|
1464
|
+
if (existsSync(config.workingDir)) {
|
|
1465
|
+
for (const e of readdirSync(config.workingDir)) {
|
|
1466
|
+
try {
|
|
1467
|
+
unlinkSync(join(config.workingDir, e));
|
|
1468
|
+
} catch (err) {
|
|
1469
|
+
console.warn('[lightrag] swallowed in rebuildGraph.unlinkEntry:', err?.message || err);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
} catch (err) {
|
|
1474
|
+
console.warn('[lightrag] swallowed in rebuildGraph.wipe:', err?.message || err);
|
|
1475
|
+
}
|
|
1476
|
+
// Reindex from scratch.
|
|
1477
|
+
return reindexVault(projectRoot, opts);
|
|
1478
|
+
}
|