@polderlabs/bizar 3.23.1 → 4.2.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.
Files changed (361) hide show
  1. package/README.md +83 -16
  2. package/bizar-dash/.bizar/activity.log +3 -0
  3. package/bizar-dash/.bizar/graph/.graphify_analysis.json +1540 -0
  4. package/bizar-dash/.bizar/graph/.graphify_labels.json +1 -0
  5. package/bizar-dash/.bizar/graph/GRAPH_REPORT.md +404 -0
  6. package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/0661b816358db84dfdb7f10443db8a61152fd20b3fee950caf8fbf32920a1790.json +1 -0
  7. package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/16da06d774142a6e5d74829ad982531286a6193ef798de8f593db029e123ec32.json +1 -0
  8. package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/27e5697c01254c69c64c5a33896669073b40afb5ba88375102ae77fa5404136d.json +1 -0
  9. package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/532997898027254aa4c0932243dc71d2f55888181232b65974961934997dc85b.json +1 -0
  10. package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/84e3451a64c7f99f0cd6a88b0748d7426780486f53ab4935b7476b28c08f8293.json +1 -0
  11. package/bizar-dash/.bizar/graph/cache/ast/v0.8.46/88e5ea5f3e78fa69353fe9e6a8d1a05391d54605e25600cb125531eb5a6432ff.json +1 -0
  12. package/bizar-dash/.bizar/graph/cache/stat-index.json +1 -0
  13. package/bizar-dash/.bizar/graph/graph.html +307 -0
  14. package/bizar-dash/.bizar/graph/graph.json +40267 -0
  15. package/bizar-dash/.bizar/graph/manifest.json +762 -0
  16. package/bizar-dash/.graphifyignore +40 -0
  17. package/bizar-dash/.obsidian/README.md +14 -0
  18. package/bizar-dash/.obsidian/daily/2026-06-25.md +9 -0
  19. package/bizar-dash/.obsidian/vault.json +7 -0
  20. package/bizar-dash/.od-skills/web-prototype-e1429c1737/SKILL.md +103 -0
  21. package/bizar-dash/.od-skills/web-prototype-e1429c1737/assets/template.html +338 -0
  22. package/bizar-dash/.od-skills/web-prototype-e1429c1737/example.html +81 -0
  23. package/bizar-dash/.od-skills/web-prototype-e1429c1737/open-design.json +172 -0
  24. package/bizar-dash/.od-skills/web-prototype-e1429c1737/references/checklist.md +44 -0
  25. package/bizar-dash/.od-skills/web-prototype-e1429c1737/references/layouts.md +247 -0
  26. package/bizar-dash/CHANGELOG.md +474 -0
  27. package/bizar-dash/DESIGN.md +136 -0
  28. package/bizar-dash/dist/assets/main-B3RgW6FS.js +331 -0
  29. package/bizar-dash/dist/assets/main-B3RgW6FS.js.map +1 -0
  30. package/bizar-dash/dist/assets/main-DlJ8wgLR.css +1 -0
  31. package/bizar-dash/dist/assets/mobile-CsZQAswA.css +1 -0
  32. package/bizar-dash/dist/assets/mobile-DbxIw8BG.js +2 -0
  33. package/bizar-dash/dist/assets/mobile-DbxIw8BG.js.map +1 -0
  34. package/bizar-dash/dist/assets/mobile-Dvq2d53Y.js +354 -0
  35. package/bizar-dash/dist/assets/mobile-Dvq2d53Y.js.map +1 -0
  36. package/bizar-dash/dist/index.html +40 -0
  37. package/bizar-dash/dist/mobile.html +22 -0
  38. package/bizar-dash/plans/debug-plan/comments.json +1 -0
  39. package/bizar-dash/plans/debug-plan/meta.json +10 -0
  40. package/bizar-dash/plans/debug-plan/plan.json +174 -0
  41. package/bizar-dash/scripts/smoke-bg-retry.mjs +246 -0
  42. package/bizar-dash/src/cli/dashboard-ports.mjs +488 -0
  43. package/bizar-dash/src/cli.mjs +522 -0
  44. package/bizar-dash/src/server/activity-log.mjs +174 -0
  45. package/bizar-dash/src/server/agents-store.mjs +465 -0
  46. package/bizar-dash/src/server/api.mjs +138 -0
  47. package/bizar-dash/src/server/artifact-template.html +810 -0
  48. package/bizar-dash/src/server/artifacts-store.mjs +733 -0
  49. package/bizar-dash/src/server/auth.mjs +381 -0
  50. package/bizar-dash/src/server/background-store.mjs +447 -0
  51. package/bizar-dash/src/server/bg-poller.mjs +305 -0
  52. package/bizar-dash/src/server/bg-retry.mjs +574 -0
  53. package/bizar-dash/src/server/browser.mjs +40 -0
  54. package/bizar-dash/src/server/diagnostics-store.mjs +148 -0
  55. package/bizar-dash/src/server/dialog-poller.mjs +105 -0
  56. package/bizar-dash/src/server/dialog-store.mjs +177 -0
  57. package/bizar-dash/src/server/glyphs/mdx-compiler.mjs +583 -0
  58. package/bizar-dash/src/server/lib/path-safe.mjs +283 -0
  59. package/bizar-dash/src/server/memory-git.mjs +329 -0
  60. package/bizar-dash/src/server/memory-lightrag.mjs +767 -0
  61. package/bizar-dash/src/server/memory-schema.mjs +145 -0
  62. package/bizar-dash/src/server/memory-secrets.mjs +84 -0
  63. package/bizar-dash/src/server/memory-store.mjs +471 -0
  64. package/bizar-dash/src/server/mod-security.mjs +398 -0
  65. package/bizar-dash/src/server/mods-loader.mjs +1067 -0
  66. package/bizar-dash/src/server/notifications-store.mjs +243 -0
  67. package/bizar-dash/src/server/obsidian-store.mjs +318 -0
  68. package/bizar-dash/src/server/opencode-runner.mjs +279 -0
  69. package/bizar-dash/src/server/pair-store.mjs +138 -0
  70. package/bizar-dash/src/server/projects-store.mjs +364 -0
  71. package/bizar-dash/src/server/providers-store.mjs +789 -0
  72. package/bizar-dash/src/server/routes/_shared.mjs +415 -0
  73. package/bizar-dash/src/server/routes/activity.mjs +110 -0
  74. package/bizar-dash/src/server/routes/agents.mjs +134 -0
  75. package/bizar-dash/src/server/routes/artifacts.mjs +279 -0
  76. package/bizar-dash/src/server/routes/auth.mjs +69 -0
  77. package/bizar-dash/src/server/routes/background.mjs +165 -0
  78. package/bizar-dash/src/server/routes/chat.mjs +485 -0
  79. package/bizar-dash/src/server/routes/config.mjs +129 -0
  80. package/bizar-dash/src/server/routes/diagnostics.mjs +50 -0
  81. package/bizar-dash/src/server/routes/dialogs.mjs +86 -0
  82. package/bizar-dash/src/server/routes/fs.mjs +429 -0
  83. package/bizar-dash/src/server/routes/history.mjs +78 -0
  84. package/bizar-dash/src/server/routes/memory.mjs +658 -0
  85. package/bizar-dash/src/server/routes/misc.mjs +89 -0
  86. package/bizar-dash/src/server/routes/mods.mjs +359 -0
  87. package/bizar-dash/src/server/routes/notifications.mjs +54 -0
  88. package/bizar-dash/src/server/routes/obsidian.mjs +239 -0
  89. package/bizar-dash/src/server/routes/opencode-sessions.mjs +55 -0
  90. package/bizar-dash/src/server/routes/overview.mjs +91 -0
  91. package/bizar-dash/src/server/routes/pair.mjs +67 -0
  92. package/bizar-dash/src/server/routes/projects.mjs +175 -0
  93. package/bizar-dash/src/server/routes/providers.mjs +47 -0
  94. package/bizar-dash/src/server/routes/schedules.mjs +104 -0
  95. package/bizar-dash/src/server/routes/settings.mjs +51 -0
  96. package/bizar-dash/src/server/routes/skills.mjs +76 -0
  97. package/bizar-dash/src/server/routes/tasks.mjs +468 -0
  98. package/bizar-dash/src/server/routes/themes.mjs +51 -0
  99. package/bizar-dash/src/server/routes-v2/auth.mjs +59 -0
  100. package/bizar-dash/src/server/routes-v2/events.mjs +107 -0
  101. package/bizar-dash/src/server/routes-v2/health.mjs +21 -0
  102. package/bizar-dash/src/server/routes-v2/index.mjs +90 -0
  103. package/bizar-dash/src/server/routes-v2/sessions.mjs +111 -0
  104. package/bizar-dash/src/server/schedules-runner.mjs +369 -0
  105. package/bizar-dash/src/server/schedules-store.mjs +268 -0
  106. package/bizar-dash/src/server/search-store.mjs +220 -0
  107. package/bizar-dash/src/server/serve-info.mjs +684 -0
  108. package/bizar-dash/src/server/server.mjs +796 -0
  109. package/bizar-dash/src/server/settings-store.mjs +45 -0
  110. package/bizar-dash/src/server/skills-store.mjs +300 -0
  111. package/bizar-dash/src/server/state.mjs +437 -0
  112. package/bizar-dash/src/server/tailscale-store.mjs +113 -0
  113. package/bizar-dash/src/server/task-delegator.mjs +824 -0
  114. package/bizar-dash/src/server/tasks-store.mjs +508 -0
  115. package/bizar-dash/src/server/tui.mjs +923 -0
  116. package/bizar-dash/src/server/update-store.mjs +168 -0
  117. package/bizar-dash/src/server/v2-auth-file.mjs +99 -0
  118. package/bizar-dash/src/server/v2-event-bus.mjs +128 -0
  119. package/bizar-dash/src/server/watcher.mjs +81 -0
  120. package/bizar-dash/src/server/yaml.mjs +238 -0
  121. package/bizar-dash/src/web/App.tsx +718 -0
  122. package/bizar-dash/src/web/MobileApp.tsx +408 -0
  123. package/bizar-dash/src/web/components/ArtifactCreateDialog.tsx +95 -0
  124. package/bizar-dash/src/web/components/ArtifactListDialog.tsx +55 -0
  125. package/bizar-dash/src/web/components/ArtifactViewer.tsx +143 -0
  126. package/bizar-dash/src/web/components/AuditDialog.tsx +79 -0
  127. package/bizar-dash/src/web/components/BgStatusBadge.tsx +32 -0
  128. package/bizar-dash/src/web/components/Button.tsx +56 -0
  129. package/bizar-dash/src/web/components/CanvasContextMenu.tsx +68 -0
  130. package/bizar-dash/src/web/components/Card.tsx +40 -0
  131. package/bizar-dash/src/web/components/CollapsibleSection.tsx +72 -0
  132. package/bizar-dash/src/web/components/CommandDialog.tsx +66 -0
  133. package/bizar-dash/src/web/components/EmptyState.tsx +30 -0
  134. package/bizar-dash/src/web/components/FileBrowser.tsx +633 -0
  135. package/bizar-dash/src/web/components/HelpDialog.tsx +55 -0
  136. package/bizar-dash/src/web/components/KillConfirmDialog.tsx +88 -0
  137. package/bizar-dash/src/web/components/Modal.tsx +215 -0
  138. package/bizar-dash/src/web/components/Notifications.tsx +241 -0
  139. package/bizar-dash/src/web/components/SearchModal.tsx +224 -0
  140. package/bizar-dash/src/web/components/Sidebar.tsx +66 -0
  141. package/bizar-dash/src/web/components/Spinner.tsx +19 -0
  142. package/bizar-dash/src/web/components/StatusBadge.tsx +25 -0
  143. package/bizar-dash/src/web/components/Tag.tsx +28 -0
  144. package/bizar-dash/src/web/components/Toast.tsx +150 -0
  145. package/bizar-dash/src/web/components/Topbar.tsx +368 -0
  146. package/bizar-dash/src/web/components/VisualPlanDialog.tsx +58 -0
  147. package/bizar-dash/src/web/components/chat/AgentChip.tsx +68 -0
  148. package/bizar-dash/src/web/components/chat/ChatBubble.tsx +60 -0
  149. package/bizar-dash/src/web/components/chat/ChatThread.tsx +88 -0
  150. package/bizar-dash/src/web/components/chat/ChatTopBar.tsx +50 -0
  151. package/bizar-dash/src/web/components/chat/Composer.tsx +164 -0
  152. package/bizar-dash/src/web/components/chat/ConfirmModal.tsx +54 -0
  153. package/bizar-dash/src/web/components/chat/EmptyState.tsx +21 -0
  154. package/bizar-dash/src/web/components/chat/FirstRunGreeting.tsx +18 -0
  155. package/bizar-dash/src/web/components/chat/FloatingComposer.tsx +32 -0
  156. package/bizar-dash/src/web/components/chat/InfoPanel.tsx +119 -0
  157. package/bizar-dash/src/web/components/chat/LoadingSkeleton.tsx +19 -0
  158. package/bizar-dash/src/web/components/chat/MessageBubble.tsx +60 -0
  159. package/bizar-dash/src/web/components/chat/SessionList.tsx +153 -0
  160. package/bizar-dash/src/web/components/chat/StreamingIndicator.tsx +9 -0
  161. package/bizar-dash/src/web/components/chat/SuggestionCards.tsx +55 -0
  162. package/bizar-dash/src/web/components/chat/WelcomeScreen.tsx +36 -0
  163. package/bizar-dash/src/web/components/chat/index.ts +20 -0
  164. package/bizar-dash/src/web/components/chat/useAutoGrowTextarea.ts +18 -0
  165. package/bizar-dash/src/web/components/chat/useChat.ts +219 -0
  166. package/bizar-dash/src/web/components/chat/useSlashCommands.ts +47 -0
  167. package/bizar-dash/src/web/index.html +37 -0
  168. package/bizar-dash/src/web/lib/api.ts +193 -0
  169. package/bizar-dash/src/web/lib/markdown.tsx +59 -0
  170. package/bizar-dash/src/web/lib/types.ts +668 -0
  171. package/bizar-dash/src/web/lib/utils.ts +114 -0
  172. package/bizar-dash/src/web/lib/ws.ts +176 -0
  173. package/bizar-dash/src/web/main.tsx +34 -0
  174. package/bizar-dash/src/web/mobile/MobileApp.tsx +278 -0
  175. package/bizar-dash/src/web/mobile/MobileBottomNav.tsx +38 -0
  176. package/bizar-dash/src/web/mobile/MobileTopbar.tsx +115 -0
  177. package/bizar-dash/src/web/mobile/components/MobileBottomSheet.tsx +182 -0
  178. package/bizar-dash/src/web/mobile/components/MobileListItem.tsx +64 -0
  179. package/bizar-dash/src/web/mobile/components/MobileModal.tsx +123 -0
  180. package/bizar-dash/src/web/mobile/views/MobileActivity.tsx +273 -0
  181. package/bizar-dash/src/web/mobile/views/MobileAgents.tsx +374 -0
  182. package/bizar-dash/src/web/mobile/views/MobileArtifactCanvas.tsx +439 -0
  183. package/bizar-dash/src/web/mobile/views/MobileArtifacts.tsx +143 -0
  184. package/bizar-dash/src/web/mobile/views/MobileChat.tsx +180 -0
  185. package/bizar-dash/src/web/mobile/views/MobileConfig.tsx +175 -0
  186. package/bizar-dash/src/web/mobile/views/MobileHistory.tsx +191 -0
  187. package/bizar-dash/src/web/mobile/views/MobileMods.tsx +149 -0
  188. package/bizar-dash/src/web/mobile/views/MobileMore.tsx +121 -0
  189. package/bizar-dash/src/web/mobile/views/MobileNotifications.tsx +137 -0
  190. package/bizar-dash/src/web/mobile/views/MobilePlans.tsx +26 -0
  191. package/bizar-dash/src/web/mobile/views/MobileSchedules.tsx +685 -0
  192. package/bizar-dash/src/web/mobile/views/MobileSearchModal.tsx +172 -0
  193. package/bizar-dash/src/web/mobile/views/MobileSettings.tsx +388 -0
  194. package/bizar-dash/src/web/mobile/views/MobileSkills.tsx +153 -0
  195. package/bizar-dash/src/web/mobile/views/MobileTasks.tsx +564 -0
  196. package/bizar-dash/src/web/mobile.html +20 -0
  197. package/bizar-dash/src/web/mobile.tsx +13 -0
  198. package/bizar-dash/src/web/styles/chat.css +198 -0
  199. package/bizar-dash/src/web/styles/glyphs.css +960 -0
  200. package/bizar-dash/src/web/styles/main.css +8855 -0
  201. package/bizar-dash/src/web/styles/mobile-chat.css +5 -0
  202. package/bizar-dash/src/web/styles/mobile.css +1960 -0
  203. package/bizar-dash/src/web/views/Activity.tsx +1203 -0
  204. package/bizar-dash/src/web/views/Agents.tsx +701 -0
  205. package/bizar-dash/src/web/views/Artifacts.tsx +1480 -0
  206. package/bizar-dash/src/web/views/BackgroundAgents.tsx +450 -0
  207. package/bizar-dash/src/web/views/Chat.tsx +190 -0
  208. package/bizar-dash/src/web/views/Config.tsx +2063 -0
  209. package/bizar-dash/src/web/views/History.tsx +335 -0
  210. package/bizar-dash/src/web/views/ModView.tsx +207 -0
  211. package/bizar-dash/src/web/views/Mods.tsx +693 -0
  212. package/bizar-dash/src/web/views/Overview.tsx +812 -0
  213. package/bizar-dash/src/web/views/Providers.tsx +302 -0
  214. package/bizar-dash/src/web/views/Schedules.tsx +802 -0
  215. package/bizar-dash/src/web/views/Settings.tsx +1787 -0
  216. package/bizar-dash/src/web/views/Skills.tsx +431 -0
  217. package/bizar-dash/src/web/views/Tasks.tsx +1523 -0
  218. package/bizar-dash/src/web/views/glyphs/GlyphRenderer.tsx +613 -0
  219. package/bizar-dash/src/web/views/glyphs/components.tsx +1098 -0
  220. package/bizar-dash/templates/mod/FORMAT.md +76 -0
  221. package/bizar-dash/templates/mod/hello-mod/README.md +19 -0
  222. package/bizar-dash/templates/mod/hello-mod/agents/greeter.md +8 -0
  223. package/bizar-dash/templates/mod/hello-mod/commands/hello.md +6 -0
  224. package/bizar-dash/templates/mod/hello-mod/mod.json +20 -0
  225. package/bizar-dash/templates/mod/hello-mod/routes/ping.mjs +9 -0
  226. package/bizar-dash/templates/mod/hello-mod/views/HelloView.tsx +10 -0
  227. package/bizar-dash/tests/dashboard-ports.test.mjs +138 -0
  228. package/bizar-dash/tests/graphify-mod-spawn.node.test.mjs +90 -0
  229. package/bizar-dash/tests/memory-cli.test.mjs +542 -0
  230. package/bizar-dash/tests/memory-config.test.mjs +422 -0
  231. package/bizar-dash/tests/memory-git.test.mjs +246 -0
  232. package/bizar-dash/tests/memory-lightrag.test.mjs +153 -0
  233. package/bizar-dash/tests/memory-protocol-drift.test.mjs +45 -0
  234. package/bizar-dash/tests/memory-schema.test.mjs +198 -0
  235. package/bizar-dash/tests/memory-secrets.test.mjs +121 -0
  236. package/bizar-dash/tests/memory-store.test.mjs +390 -0
  237. package/bizar-dash/tests/memory-sync.test.mjs +141 -0
  238. package/bizar-dash/tests/mod-instructions.node.test.mjs +188 -0
  239. package/bizar-dash/tests/mod-security.test.mjs +273 -0
  240. package/bizar-dash/tests/mod-upgrade.node.test.mjs +357 -0
  241. package/bizar-dash/tests/no-agent-browser.node.test.mjs +98 -0
  242. package/bizar-dash/tests/obsidian-back-compat.test.mjs +199 -0
  243. package/bizar-dash/tests/opencode-runner.test.mjs +172 -0
  244. package/bizar-dash/tests/path-safe.test.mjs +108 -0
  245. package/bizar-dash/tests/providers-store-backup-keys.node.test.mjs +333 -0
  246. package/bizar-dash/tests/smoke-v2.mjs +212 -0
  247. package/bizar-dash/tests/strip-thinking.test.mjs +175 -0
  248. package/bizar-dash/tests/submit-feedback.test.mjs +353 -0
  249. package/bizar-dash/tests/tmux-wrap.test.mjs +145 -0
  250. package/bizar-dash/tests/yaml.test.mjs +128 -0
  251. package/bizar-dash/tsconfig.json +23 -0
  252. package/bizar-dash/vite.config.ts +27 -0
  253. package/cli/atomic.mjs +73 -0
  254. package/cli/banner.mjs +1 -1
  255. package/cli/bin.mjs +44 -47
  256. package/cli/bootstrap.mjs +1 -1
  257. package/cli/copy.mjs +25 -16
  258. package/cli/dev-link.mjs +17 -1
  259. package/cli/doctor.mjs +4 -4
  260. package/cli/doctor.test.mjs +2 -2
  261. package/cli/init.mjs +135 -1
  262. package/cli/install.mjs +31 -39
  263. package/cli/memory-constants.mjs +59 -0
  264. package/cli/memory.mjs +1436 -0
  265. package/cli/service.mjs +5 -6
  266. package/cli/utils.mjs +6 -3
  267. package/config/AGENTS.md +7 -7
  268. package/config/agents/_shared/AGENT_BASELINE.md +59 -61
  269. package/config/opencode.json +13 -38
  270. package/config/skills/memory-protocol/SKILL.md +105 -0
  271. package/config/skills/obsidian/SKILL.md +270 -65
  272. package/install.sh +59 -19
  273. package/package.json +49 -14
  274. package/packages/sdk/LICENSE +21 -0
  275. package/packages/sdk/README.md +80 -0
  276. package/packages/sdk/src/client.ts +183 -0
  277. package/packages/sdk/src/errors.ts +120 -0
  278. package/packages/sdk/src/events.ts +153 -0
  279. package/packages/sdk/src/index.ts +63 -0
  280. package/packages/sdk/src/types.ts +176 -0
  281. package/packages/sdk/src/version.ts +4 -0
  282. package/packages/sdk/tests/client.test.ts +217 -0
  283. package/packages/sdk/tests/errors.test.ts +108 -0
  284. package/packages/sdk/tests/events.test.ts +139 -0
  285. package/packages/sdk/tests/fixtures/fetch-mock.ts +152 -0
  286. package/packages/sdk/tests/fixtures/sse-mock.ts +30 -0
  287. package/packages/sdk/tsconfig.json +25 -0
  288. package/packages/sdk/vitest.config.ts +9 -0
  289. package/plugins/bizar/LICENSE +21 -0
  290. package/plugins/bizar/README.md +448 -0
  291. package/plugins/bizar/dist/index.js +29901 -0
  292. package/plugins/bizar/index.ts +1491 -0
  293. package/plugins/bizar/scripts/check-forbidden-imports.sh +33 -0
  294. package/plugins/bizar/src/background-state.ts +551 -0
  295. package/plugins/bizar/src/background.ts +1250 -0
  296. package/plugins/bizar/src/commands-impl.ts +464 -0
  297. package/plugins/bizar/src/commands.ts +1168 -0
  298. package/plugins/bizar/src/dashboard-client.ts +233 -0
  299. package/plugins/bizar/src/event-stream.ts +606 -0
  300. package/plugins/bizar/src/fingerprint.ts +120 -0
  301. package/plugins/bizar/src/handoff.ts +79 -0
  302. package/plugins/bizar/src/http-client.ts +467 -0
  303. package/plugins/bizar/src/key-rotation.ts +218 -0
  304. package/plugins/bizar/src/logger.ts +144 -0
  305. package/plugins/bizar/src/loop.ts +176 -0
  306. package/plugins/bizar/src/opencode-runner.ts +390 -0
  307. package/plugins/bizar/src/options.ts +421 -0
  308. package/plugins/bizar/src/plan-fs.ts +323 -0
  309. package/plugins/bizar/src/reasoning-clean.ts +454 -0
  310. package/plugins/bizar/src/report.ts +178 -0
  311. package/plugins/bizar/src/research-prompt.ts +35 -0
  312. package/plugins/bizar/src/serve-info.ts +228 -0
  313. package/plugins/bizar/src/serve.ts +496 -0
  314. package/plugins/bizar/src/settings.ts +349 -0
  315. package/plugins/bizar/src/state.ts +298 -0
  316. package/plugins/bizar/src/tools/bg-collect.ts +104 -0
  317. package/plugins/bizar/src/tools/bg-get-comments.ts +239 -0
  318. package/plugins/bizar/src/tools/bg-kill.ts +87 -0
  319. package/plugins/bizar/src/tools/bg-spawn.ts +401 -0
  320. package/plugins/bizar/src/tools/bg-status.ts +99 -0
  321. package/plugins/bizar/src/tools/open-kb.ts +191 -0
  322. package/plugins/bizar/src/tools/plan-action.ts +767 -0
  323. package/plugins/bizar/src/tools/read-glyph-feedback.ts +170 -0
  324. package/plugins/bizar/src/tools/wait-for-feedback.ts +402 -0
  325. package/plugins/bizar/tests/attach-handler-bug.test.ts +169 -0
  326. package/plugins/bizar/tests/background-state.test.ts +277 -0
  327. package/plugins/bizar/tests/background.test.ts +402 -0
  328. package/plugins/bizar/tests/block.test.ts +195 -0
  329. package/plugins/bizar/tests/canonical-key-order.test.ts +75 -0
  330. package/plugins/bizar/tests/commands-impl.test.ts +442 -0
  331. package/plugins/bizar/tests/commands.test.ts +584 -0
  332. package/plugins/bizar/tests/config.test.ts +122 -0
  333. package/plugins/bizar/tests/dashboard-client.test.ts +159 -0
  334. package/plugins/bizar/tests/dispose.test.ts +336 -0
  335. package/plugins/bizar/tests/event-stream.test.ts +409 -0
  336. package/plugins/bizar/tests/event.test.ts +262 -0
  337. package/plugins/bizar/tests/fingerprint.test.ts +162 -0
  338. package/plugins/bizar/tests/http-client.test.ts +404 -0
  339. package/plugins/bizar/tests/init-helpers.test.ts +203 -0
  340. package/plugins/bizar/tests/integration/slash-command.test.ts +348 -0
  341. package/plugins/bizar/tests/integration/tool-routing.test.ts +314 -0
  342. package/plugins/bizar/tests/key-rotation.test.ts +396 -0
  343. package/plugins/bizar/tests/loop.test.ts +397 -0
  344. package/plugins/bizar/tests/options.test.ts +276 -0
  345. package/plugins/bizar/tests/reasoning-clean.test.ts +422 -0
  346. package/plugins/bizar/tests/serve.test.ts +339 -0
  347. package/plugins/bizar/tests/settings.test.ts +351 -0
  348. package/plugins/bizar/tests/stall-think.test.ts +750 -0
  349. package/plugins/bizar/tests/state.test.ts +276 -0
  350. package/plugins/bizar/tests/tools/bg-collect.test.ts +337 -0
  351. package/plugins/bizar/tests/tools/bg-get-comments.test.ts +485 -0
  352. package/plugins/bizar/tests/tools/bg-kill.test.ts +235 -0
  353. package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +147 -0
  354. package/plugins/bizar/tests/tools/bg-spawn.test.ts +311 -0
  355. package/plugins/bizar/tests/tools/bg-status.test.ts +217 -0
  356. package/plugins/bizar/tests/tools/opencode-runner.test.ts +115 -0
  357. package/plugins/bizar/tests/tools/plan-action.test.ts +599 -0
  358. package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +253 -0
  359. package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +390 -0
  360. package/plugins/bizar/tests/update-deadlock.test.ts +145 -0
  361. package/plugins/bizar/tsconfig.json +29 -0
package/cli/atomic.mjs ADDED
@@ -0,0 +1,73 @@
1
+ /**
2
+ * src/server/atomic.mjs
3
+ *
4
+ * Atomic file I/O utilities for the Bizar Memory Service. Uses the
5
+ * proven tmp+rename pattern to ensure files are either fully written or
6
+ * not written at all (no partial writes on crash).
7
+ *
8
+ * tmp files use `process.ppid + process.pid` to avoid collisions when
9
+ * multiple processes race on the same file.
10
+ */
11
+
12
+ import { writeFileSync, renameSync, existsSync, readFileSync } from 'node:fs';
13
+
14
+ /**
15
+ * Atomically write a JSON file. Write to a temp file then rename over
16
+ * the target so readers never see a partially-written document.
17
+ *
18
+ * @param {string} filePath
19
+ * @param {unknown} data — will be JSON-stringified with 2-space indent
20
+ */
21
+ export function atomicWriteJson(filePath, data) {
22
+ const tmp = `${filePath}.tmp.${process.ppid}+${process.pid}`;
23
+ writeFileSync(tmp, JSON.stringify(data, null, 2) + '\n', 'utf8');
24
+ renameSync(tmp, filePath);
25
+ }
26
+
27
+ /**
28
+ * Atomically write a text file.
29
+ *
30
+ * @param {string} filePath
31
+ * @param {string} text
32
+ */
33
+ export function atomicWriteText(filePath, text) {
34
+ const tmp = `${filePath}.tmp.${process.ppid}+${process.pid}`;
35
+ writeFileSync(tmp, text, 'utf8');
36
+ renameSync(tmp, filePath);
37
+ }
38
+
39
+ /**
40
+ * Safe JSON read. Returns `fallback` on any error (missing file,
41
+ * empty file, malformed JSON, permission error).
42
+ *
43
+ * @template T
44
+ * @param {string} filePath
45
+ * @param {T} [fallback=null]
46
+ * @returns {T}
47
+ */
48
+ export function safeReadJSON(filePath, fallback = null) {
49
+ try {
50
+ if (!existsSync(filePath)) return fallback;
51
+ const text = readFileSync(filePath, 'utf8');
52
+ if (!text.trim()) return fallback;
53
+ return JSON.parse(text);
54
+ } catch {
55
+ return fallback;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Safe text read. Returns `fallback` on any error.
61
+ *
62
+ * @param {string} filePath
63
+ * @param {string} [fallback='']
64
+ * @returns {string}
65
+ */
66
+ export function safeReadText(filePath, fallback = '') {
67
+ try {
68
+ if (!existsSync(filePath)) return fallback;
69
+ return readFileSync(filePath, 'utf8');
70
+ } catch {
71
+ return fallback;
72
+ }
73
+ }
package/cli/banner.mjs CHANGED
@@ -25,7 +25,7 @@ export function showBanner() {
25
25
  console.log(chalk.hex('#6366f1').bold(RUNE_HELM));
26
26
  console.log(chalk.hex('#a855f7')(' Norse Pantheon Agent System for opencode'));
27
27
  console.log();
28
- console.log(chalk.dim(' 13 agents · 4 cost tiers · Obsidian vault long-term memory · RTK · Semble · Skills CLI · Mods'));
28
+ console.log(chalk.dim(' 13 agents · 4 cost tiers · Obsidian vault long-term memory · Headroom · Semble · Skills CLI · Mods'));
29
29
  console.log();
30
30
  }
31
31
 
package/cli/bin.mjs CHANGED
@@ -86,6 +86,7 @@ function showHelp() {
86
86
  update Auto-update everything (opencode + bizar + dash + plugin)
87
87
  service Manage the background service daemon
88
88
  bg <subcommand> Manage background agents (list/view/kill/logs)
89
+ memory <subcommand> Manage project memory (Bizar Memory Service)
89
90
  dash <subcommand> Manage the dashboard (start/stop/status/cleanup/tui)
90
91
  browser-harness-up Start Chromium for browser-harness (start/stop/status/restart)
91
92
  dev-link [src] Symlink the local plugin source into opencode's plugin dir
@@ -271,7 +272,7 @@ function showDoctorHelp() {
271
272
  • plugin path resolves
272
273
  • @polderlabs/bizar-plugin is installed globally
273
274
  • core agent files are installed (odin, quick, thor, tyr)
274
- rtk / semble / skills on PATH (lenient — at least one)
275
+ headroom / semble / skills on PATH (lenient — at least one)
275
276
  • dashboard reachable (skipped if no port file)
276
277
  • provider.minimax block + MiniMax model flags are sane
277
278
 
@@ -487,12 +488,26 @@ function showDashHelp() {
487
488
  `);
488
489
  }
489
490
 
491
+ function showMemoryHelp() {
492
+ console.log(`
493
+ memory <subcommand> Manage project memory (local-only or Git-shared Obsidian vault)
494
+ Subcommands: init, setup, status, link, unlink, write, pull, commit,
495
+ push, sync, reindex, conflicts, doctor
496
+ `);
497
+ }
498
+
490
499
  /**
491
- * Detect whether @polderlabs/bizar-dash is installed locally.
492
- * We probe the global npm root, but also look in the local node_modules
493
- * of the bizar package itself.
500
+ * Detect whether the dashboard CLI is available.
501
+ * v4.0.0: primary path is the relative one (dashboard ships inside the
502
+ * same package at bizar-dash/src/cli.mjs). A global-npm fallback is
503
+ * kept for legacy users who still have @polderlabs/bizar-dash installed.
494
504
  */
495
505
  async function findBizarDash() {
506
+ // v4.0.0 — primary: relative import inside the same package
507
+ const primaryPath = join(import.meta.dirname, '..', 'bizar-dash', 'src', 'cli.mjs');
508
+ if (existsSync(primaryPath)) return primaryPath;
509
+
510
+ // Legacy fallback: global npm install of @polderlabs/bizar-dash
496
511
  const { execSync } = await import('node:child_process');
497
512
  try {
498
513
  const root = execSync('npm root -g', { encoding: 'utf8', timeout: 5000 }).trim();
@@ -513,9 +528,9 @@ async function findBizarDash() {
513
528
  async function delegateToDash(argsForDash) {
514
529
  const dashPath = await findBizarDash();
515
530
  if (!dashPath) {
516
- console.log('The Bizar dashboard lives in a separate package.');
517
- console.log('Install it with:');
518
- console.log(chalk.cyan(' npm install -g @polderlabs/bizar-dash'));
531
+ console.log('The Bizar dashboard is part of this package.');
532
+ console.log('If you see this error, the install may be corrupted.');
533
+ console.log('Please report at: github.com/DrB0rk/BizarHarness/issues');
519
534
  return;
520
535
  }
521
536
  const { spawn } = await import('node:child_process');
@@ -627,6 +642,12 @@ async function main() {
627
642
  } else if (args[0] === 'init') {
628
643
  if (isHelpRequest) showInitHelp();
629
644
  else await runInit(process.cwd());
645
+ } else if (args[0] === 'memory') {
646
+ if (isHelpRequest && !args[1]) showMemoryHelp();
647
+ else {
648
+ const { runMemory } = await import('./memory.mjs');
649
+ await runMemory(args[1], args.slice(2));
650
+ }
630
651
  } else if (args[0] === 'export') {
631
652
  if (isHelpRequest) showExportHelp();
632
653
  else await runExport(parseFlag('--target'));
@@ -750,48 +771,25 @@ function parseDashOpts(dashArgs) {
750
771
 
751
772
  /**
752
773
  * Try to load the dashboard CLI module.
753
- * Try 1: import via the package exports map (@polderlabs/bizar-dash/dash-cli)
754
- * Try 2: file path probing for older installs or dev trees
774
+ * v4.0.0: the dashboard ships inside this package at bizar-dash/src/cli.mjs.
775
+ * A legacy npm-global fallback is kept for the transitional period.
755
776
  */
756
777
  async function loadDashCli() {
757
- // Try 1: import via exports map (requires Tyr's package.json changes)
758
- try {
759
- const mod = await import('@polderlabs/bizar-dash/dash-cli');
760
- return mod;
761
- } catch (_e) {
762
- // fall through to file probing
763
- }
764
-
765
- // Try 2: dynamic npm root -g (most reliable for global installs)
766
- try {
767
- const { execFileSync } = await import('node:child_process');
768
- const { pathToFileURL } = await import('node:url');
769
- const { join } = await import('node:path');
770
- const npmRoot = execFileSync('npm', ['root', '-g'], { encoding: 'utf8', timeout: 5000 }).trim();
771
- if (npmRoot) {
772
- const cliPath = join(npmRoot, '@polderlabs', 'bizar-dash', 'src', 'cli.mjs');
773
- const mod = await import(pathToFileURL(cliPath).href);
774
- return mod;
775
- }
776
- } catch (_e) {
777
- /* fall through */
778
- }
779
-
780
- // Try 3: file path probing
781
- const { join } = await import('node:path');
782
- const { homedir } = await import('node:os');
778
+ // v4.0.0 — primary: relative import inside the same package
779
+ const { pathToFileURL } = await import('node:url');
783
780
  const candidates = [
784
- // npm global install
785
- join(homedir(), '.npm-global', 'lib', 'node_modules', '@polderlabs', 'bizar-dash', 'src', 'cli.mjs'),
786
- // nvm
787
- join(homedir(), '.nvm', 'versions', 'node'),
788
- // relative to current process
789
- join(process.execPath, '..', '..', 'lib', 'node_modules', '@polderlabs', 'bizar-dash', 'src', 'cli.mjs'),
790
- // local node_modules
791
- join(process.cwd(), 'node_modules', '@polderlabs', 'bizar-dash', 'src', 'cli.mjs'),
781
+ join(import.meta.dirname, '..', 'bizar-dash', 'src', 'cli.mjs'),
782
+ // Legacy fallbacks for users with @polderlabs/bizar-dash still installed:
783
+ ...(async () => {
784
+ const { execFileSync } = await import('node:child_process');
785
+ try {
786
+ const npmRoot = execFileSync('npm', ['root', '-g'], { encoding: 'utf8', timeout: 5000 }).trim();
787
+ if (npmRoot) return [join(npmRoot, '@polderlabs', 'bizar-dash', 'src', 'cli.mjs')];
788
+ } catch { /* ignore */ }
789
+ return [];
790
+ })(),
792
791
  ];
793
792
 
794
- const { pathToFileURL } = await import('node:url');
795
793
  for (const p of candidates) {
796
794
  try {
797
795
  const url = pathToFileURL(p).href;
@@ -815,9 +813,8 @@ async function runDash(dashArgs) {
815
813
 
816
814
  const dashModule = await loadDashCli();
817
815
  if (!dashModule) {
818
- console.error(chalk.red(' ✗ Dashboard not installed.'));
819
- console.error(chalk.dim(' Run: npm install -g @polderlabs/bizar-dash'));
820
- console.error(chalk.dim(' Or: npx -y @polderlabs/bizar install'));
816
+ console.error(chalk.red(' ✗ Dashboard not found.'));
817
+ console.error(chalk.dim(' this should not happen — please report a bug at github.com/DrB0rk/BizarHarness/issues'));
821
818
  process.exit(1);
822
819
  }
823
820
 
package/cli/bootstrap.mjs CHANGED
@@ -49,7 +49,7 @@ export function checkSetupStatus() {
49
49
  */
50
50
  function printSetupBanner() {
51
51
  // Use console.log directly to avoid chalk formatting issues in non-TTY
52
- console.log('\n ⚡ First-time setup — Bizar needs to install agents, plugin, RTK, Semble, Skills CLI...\n');
52
+ console.log('\n ⚡ First-time setup — Bizar needs to install agents, plugin, Headroom, Semble, Skills CLI...\n');
53
53
  }
54
54
 
55
55
  /**
package/cli/copy.mjs CHANGED
@@ -289,6 +289,9 @@ export async function installPluginBizar(projectRoot) {
289
289
  // The Bizar plugin now lives in a separate npm package
290
290
  // (@polderlabs/bizar-plugin). The interactive installer copies it from
291
291
  // there; the source tree no longer carries plugins/bizar/.
292
+ // TODO (forward-compat): when plugins/bizar + bizar-dash + packages/sdk are
293
+ // collapsed into one package, the plugin entry point will be
294
+ // src/plugin/index.ts and the copy source should be updated here.
292
295
  spinner.info(chalk.dim(' ℹ No local plugins/bizar/ — using @polderlabs/bizar-plugin from npm'));
293
296
  return { copied: 0, errors: [] };
294
297
  }
@@ -338,43 +341,49 @@ export async function installPluginBizar(projectRoot) {
338
341
  }
339
342
  }
340
343
 
341
- export async function installRtk() {
344
+ export async function installHeadroom() {
342
345
  const { execSync } = await import('node:child_process');
343
346
 
344
347
  const already = await detectRtk();
345
348
  if (already) {
346
- const spinner = ora({ text: 'Configuring RTK for opencode...', color: 'magenta' }).start();
349
+ const spinner = ora({ text: 'Configuring Headroom for opencode...', color: 'magenta' }).start();
347
350
  try {
348
- execSync('rtk init -g --opencode', { stdio: 'pipe' });
349
- spinner.succeed(chalk.green('RTK configured for opencode'));
351
+ execSync('headroom wrap opencode', { stdio: 'pipe' });
352
+ spinner.succeed(chalk.green('Headroom configured for opencode'));
350
353
  } catch {
351
- spinner.warn(chalk.yellow('Could not auto-configure RTK — run `rtk init -g --opencode` manually'));
354
+ spinner.warn(chalk.yellow('Could not auto-configure Headroom — run `headroom wrap opencode` manually'));
352
355
  }
353
356
  return true;
354
357
  }
355
358
 
356
- const spinner = ora({ text: 'Installing RTK (Rust Token Killer)...', color: 'magenta' }).start();
359
+ const spinner = ora({ text: 'Installing Headroom (context compressor)...', color: 'magenta' }).start();
357
360
 
358
361
  if (process.platform === 'win32') {
359
- // RTK ships a bash-only installer; no PowerShell equivalent. On
360
- // Windows the user must install RTK manually (e.g. via Cargo or
361
- // prebuilt binary) and re-run `rtk init -g --opencode`.
362
- spinner.fail(chalk.red('Automatic RTK install not supported on Windows. Install manually from https://github.com/rtk-ai/rtk'));
362
+ spinner.fail(chalk.red('Automatic Headroom install not supported on Windows. Install manually: pip install "headroom-ai[all]"'));
363
363
  return false;
364
364
  }
365
365
 
366
366
  try {
367
367
  execSync(
368
- 'curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh',
368
+ 'pip install --user "headroom-ai[all]"',
369
369
  { stdio: 'pipe', timeout: 60000 },
370
370
  );
371
- spinner.text = 'Configuring RTK for opencode...';
372
- execSync('rtk init -g --opencode', { stdio: 'pipe' });
373
- spinner.succeed(chalk.green('RTK installed and configured for opencode'));
371
+ spinner.text = 'Configuring Headroom for opencode...';
372
+ execSync('headroom wrap opencode', { stdio: 'pipe' });
373
+ spinner.succeed(chalk.green('Headroom installed and configured for opencode'));
374
374
  return true;
375
375
  } catch {
376
- spinner.fail(chalk.red('RTK install failed. Install manually from https://github.com/rtk-ai/rtk'));
377
- return false;
376
+ // Fall back to npm
377
+ try {
378
+ execSync('npm install -g headroom-ai', { stdio: 'pipe', timeout: 60000 });
379
+ spinner.text = 'Configuring Headroom for opencode...';
380
+ execSync('headroom wrap opencode', { stdio: 'pipe' });
381
+ spinner.succeed(chalk.green('Headroom installed (npm) and configured for opencode'));
382
+ return true;
383
+ } catch {
384
+ spinner.fail(chalk.red('Headroom install failed. Install manually: pip install "headroom-ai[all]" or npm install -g headroom-ai'));
385
+ return false;
386
+ }
378
387
  }
379
388
  }
380
389
 
package/cli/dev-link.mjs CHANGED
@@ -51,7 +51,23 @@ function pluginDest() {
51
51
  * Returns true on success, false on refusal.
52
52
  */
53
53
  export function createDevLink(sourceDir = null, opts = {}) {
54
- const resolvedSource = resolve(process.cwd(), sourceDir ?? 'plugins/bizar');
54
+ const defaultSource = 'plugins/bizar';
55
+ const resolvedSource = resolve(process.cwd(), sourceDir ?? defaultSource);
56
+
57
+ // Forward-compatibility: if the legacy path doesn't exist, fall back to the
58
+ // collapsed layout (plugins/bizar + bizar-dash + sdk collapsed into one pkg).
59
+ // When that restructure ships, the plugin entry point will be src/plugin/index.ts.
60
+ if (!existsSync(resolvedSource)) {
61
+ const collapsedSource = resolve(process.cwd(), 'src', 'plugin', 'index.ts');
62
+ // Only switch if the collapsed path actually exists — preserve the original
63
+ // error for genuinely missing sources.
64
+ if (existsSync(collapsedSource)) {
65
+ // sourceDir was not explicitly passed — use the collapsed path silently
66
+ // so `bizar dev-link` works without args in the new layout.
67
+ resolvedSource = resolve(process.cwd(), 'src', 'plugin');
68
+ }
69
+ }
70
+
55
71
  const dest = pluginDest();
56
72
  const parentDir = join(dest, '..');
57
73
 
package/cli/doctor.mjs CHANGED
@@ -9,8 +9,8 @@
9
9
  * result without re-printing the per-check output.
10
10
  *
11
11
  * The checks are intentionally tolerant: missing optional tools
12
- * (rtk/semble/skills) don't fail the run, and the dashboard check is
13
- * skipped silently if no port file exists. The goal is "is your
12
+ * (headroom/semble/skills) don't fail the run, and the dashboard check
13
+ * is skipped silently if no port file exists. The goal is "is your
14
14
  * install healthy?" not "is every conceivable thing present?".
15
15
  *
16
16
  * Usage:
@@ -187,13 +187,13 @@ async function checkAgentFilesInstalled() {
187
187
  }
188
188
 
189
189
  /**
190
- * Lenient: passes if at least one of rtk/semble/skills is on PATH.
190
+ * Lenient: passes if at least one of headroom/semble/skills is on PATH.
191
191
  * These are informational — none of them are strictly required for
192
192
  * `bizar doctor` to do its job, and missing them shouldn't fail the
193
193
  * overall health report.
194
194
  */
195
195
  async function checkToolsAvailable() {
196
- const tools = ['rtk', 'semble', 'skills'];
196
+ const tools = ['headroom', 'semble', 'skills'];
197
197
  const found = tools.filter(which);
198
198
  if (found.length === 0) {
199
199
  throw new Error(`none of ${tools.join('/')} on PATH`);
@@ -8,7 +8,7 @@
8
8
  * tmpdir, and craft the opencode.json + agents/ directory to drive
9
9
  * specific pass/fail outcomes. For checks that depend on global
10
10
  * npm-installed packages or external CLIs (e.g. opencode --version,
11
- * npm root -g, which rtk), we accept that they may pass or fail
11
+ * npm root -g, which headroom), we accept that they may pass or fail
12
12
  * depending on the test environment and just verify the framework
13
13
  * returns the right shape.
14
14
  */
@@ -116,7 +116,7 @@ describe('runDoctor() shape', () => {
116
116
 
117
117
  test('silent mode suppresses ALL output when nothing fails', async () => {
118
118
  // Build a fully healthy environment. We can't make opencode reachable
119
- // or rtk installed without modifying PATH, so we settle for: no failures
119
+ // or headroom installed without modifying PATH, so we settle for: no failures
120
120
  // means no output at all. Since we know some checks will fail in a
121
121
  // bare tmpdir, this test is structured to assert the negative case
122
122
  // differently: we verify silent+no-fail produces 0 lines.
package/cli/init.mjs CHANGED
@@ -87,7 +87,17 @@ export function writePrePushNotesFile(bizarDir) {
87
87
  console.log(chalk.green(` ✓ Created ${ppnPath}`));
88
88
  }
89
89
 
90
- export async function runInit(cwd) {
90
+ export async function runInit(cwd, opts = {}) {
91
+ // Extract memory-related non-interactive flags from opts.
92
+ // Acceptable shapes:
93
+ // opts = { skipMemory: true }
94
+ // opts = { memoryMode: 'managed', memoryRepoName: 'my-repo' }
95
+ // opts = { memoryMode: 'local-only' }
96
+ // (We also accept `args` for callers that pass raw argv — uncommon since
97
+ // bin.mjs only calls runInit(process.cwd()) today.)
98
+ const skipMemory = !!opts.skipMemory || process.env.BIZAR_SKIP_INSTALL;
99
+ const memoryModeOpt = opts.memoryMode || null;
100
+ const memoryRepoNameOpt = opts.memoryRepoName || null;
91
101
  console.log(chalk.bold.hex('#10b981')('\n ᛗ BIZARHARNESS INIT ᛗ\n'));
92
102
 
93
103
  const bizarDir = join(cwd, '.bizar');
@@ -229,6 +239,130 @@ ${stack.runner ? `- Dev: \`${stack.runner}\`` : ''}
229
239
  }
230
240
  }
231
241
 
242
+ // ── Memory configuration (Bizar Memory Service Phase 1) ──────────────────
243
+ // Writes `.bizar/memory.json` so the dashboard / API knows where the vault
244
+ // lives and which mode we're in. Gated on `BIZAR_SKIP_INSTALL` and the
245
+ // explicit `--skip-memory` opt (callers that pre-supply a config file pass
246
+ // `skipMemory: true` to avoid the interactive prompt).
247
+ console.log(chalk.bold('\n--- Memory ---\n'));
248
+ const memoryJsonPath = join(bizarDir, 'memory.json');
249
+ if (existsSync(memoryJsonPath)) {
250
+ console.log(chalk.dim(` - memory config already exists at ${memoryJsonPath} (skipped)`));
251
+ } else if (skipMemory) {
252
+ console.log(chalk.dim(' - memory config: skipped (BIZAR_SKIP_INSTALL or skipMemory opt)'));
253
+ } else {
254
+ try {
255
+ const inquirer = (await import('inquirer')).default;
256
+ const initialMode = memoryModeOpt
257
+ ? memoryModeOpt
258
+ : (await inquirer.prompt([{
259
+ type: 'list',
260
+ name: 'memoryMode',
261
+ message: 'Memory backend',
262
+ choices: [
263
+ { name: 'managed (shared user-level repo at ~/.local/share/bizar/memory/bizar-memory/)', value: 'managed' },
264
+ { name: 'local-only (vault stays in this project at .obsidian/)', value: 'local-only' },
265
+ ],
266
+ default: 'managed',
267
+ }])).memoryMode;
268
+ const memoryMode = initialMode === 'managed' ? 'managed' : 'local-only';
269
+
270
+ let repoName = memoryMode === 'managed'
271
+ ? (memoryRepoNameOpt || 'bizar-memory')
272
+ : null;
273
+ if (memoryMode === 'managed' && !memoryRepoNameOpt) {
274
+ const answer = await inquirer.prompt([{
275
+ type: 'input',
276
+ name: 'repoName',
277
+ message: 'Memory repo name',
278
+ default: 'bizar-memory',
279
+ }]);
280
+ repoName = answer.repoName || 'bizar-memory';
281
+ }
282
+
283
+ const projectId = basename(cwd) || 'project';
284
+ const home = process.env.HOME || process.env.USERPROFILE || process.cwd();
285
+ const managedPath = join(home, '.local', 'share', 'bizar', 'memory', repoName || 'bizar-memory');
286
+ const vaultPath = memoryMode === 'managed' ? managedPath : join(cwd, '.obsidian');
287
+
288
+ const { atomicWriteJson } = await import('./atomic.mjs');
289
+ const config = {
290
+ version: 1,
291
+ backend: 'bizar-local',
292
+ projectId,
293
+ memoryRepo: {
294
+ mode: memoryMode,
295
+ path: vaultPath,
296
+ remote: null,
297
+ branch: 'main',
298
+ namespace: memoryMode === 'managed' ? `projects/${projectId}` : null,
299
+ },
300
+ namespaces: {
301
+ project: `projects/${projectId}`,
302
+ global: 'global/bizar',
303
+ user: `users/${process.env.USER || process.env.USERNAME || 'local'}`,
304
+ },
305
+ lightrag: {
306
+ enabled: false,
307
+ host: '127.0.0.1',
308
+ port: 9621,
309
+ workingDir: join(cwd, '.bizar', 'lightrag'),
310
+ },
311
+ git: {
312
+ autoPullOnSessionStart: false,
313
+ autoCommitOnMemoryWrite: false,
314
+ autoPushOnSessionEnd: false,
315
+ commitAuthor: 'Bizar Memory <bizar-memory@local>',
316
+ commitMessageTemplate: `memory(${projectId}): {summary}`,
317
+ },
318
+ };
319
+ atomicWriteJson(memoryJsonPath, config);
320
+ console.log(chalk.green(` ✓ Created ${memoryJsonPath} (mode: ${memoryMode})`));
321
+ if (memoryMode === 'managed') {
322
+ console.log(chalk.dim(` Vault path: ${vaultPath} (shared user-level repo)`));
323
+ } else {
324
+ console.log(chalk.dim(` Vault path: ${vaultPath} (local-only)`));
325
+ }
326
+ } catch (err) {
327
+ // Inquirer prompt can throw if stdin is not a TTY (CI). Fall back to
328
+ // a minimal local-only config so init still completes cleanly.
329
+ console.log(chalk.yellow(` ⚠ Memory config prompt failed (${err.message || err}); defaulting to local-only.`));
330
+ try {
331
+ const projectId = basename(cwd) || 'project';
332
+ const { atomicWriteJson } = await import('./atomic.mjs');
333
+ const fallback = {
334
+ version: 1,
335
+ backend: 'bizar-local',
336
+ projectId,
337
+ memoryRepo: {
338
+ mode: 'local-only',
339
+ path: join(cwd, '.obsidian'),
340
+ remote: null,
341
+ branch: 'main',
342
+ namespace: null,
343
+ },
344
+ namespaces: {
345
+ project: `projects/${projectId}`,
346
+ global: 'global/bizar',
347
+ user: `users/${process.env.USER || process.env.USERNAME || 'local'}`,
348
+ },
349
+ lightrag: { enabled: false, host: '127.0.0.1', port: 9621, workingDir: join(cwd, '.bizar', 'lightrag') },
350
+ git: {
351
+ autoPullOnSessionStart: false,
352
+ autoCommitOnMemoryWrite: false,
353
+ autoPushOnSessionEnd: false,
354
+ commitAuthor: 'Bizar Memory <bizar-memory@local>',
355
+ commitMessageTemplate: `memory(${projectId}): {summary}`,
356
+ },
357
+ };
358
+ atomicWriteJson(memoryJsonPath, fallback);
359
+ console.log(chalk.green(` ✓ Created ${memoryJsonPath} (mode: local-only — fallback)`));
360
+ } catch (innerErr) {
361
+ console.log(chalk.dim(` - memory config write failed (${innerErr.message || innerErr}); skipping`));
362
+ }
363
+ }
364
+ }
365
+
232
366
  console.log(chalk.dim('\n Project initialized. Run `@frigg` to ask questions about the codebase.\n'));
233
367
  return true;
234
368
  }
package/cli/install.mjs CHANGED
@@ -5,8 +5,8 @@ import { join } from 'node:path';
5
5
 
6
6
  import { showBanner, showPantheon, sectionHeading } from './banner.mjs';
7
7
  import { promptComponents, promptInstallMode, promptAgents, promptSkillPacks, promptApiKeys, promptConfirmInstall, promptRestartOpenCode } from './prompts.mjs';
8
- import { detectOpenCode, detectRtk, detectSemble, detectSkillsCli, detectUv, buildSummary, opencodeAgentsDir, opencodeConfigDir, repoPath } from './utils.mjs';
9
- import { installAgents, installAgentsMd, installSkill, installOpencodeJson, installBizarFolder, installPluginBizar, installRtk, installSemble, installSkillsCli, installCuratedSkills, installRules, installHooks, installCommands, installCommandsBizar, mergeToolsIntoUserConfig } from './copy.mjs';
8
+ import { detectOpenCode, detectHeadroom, detectSemble, detectSkillsCli, detectUv, buildSummary, opencodeAgentsDir, opencodeConfigDir, repoPath } from './utils.mjs';
9
+ import { installAgents, installAgentsMd, installSkill, installOpencodeJson, installBizarFolder, installPluginBizar, installHeadroom, installSemble, installSkillsCli, installCuratedSkills, installRules, installHooks, installCommands, installCommandsBizar, mergeToolsIntoUserConfig } from './copy.mjs';
10
10
 
11
11
  const AGENT_FILES = [
12
12
  'odin.md', 'vor.md', 'frigg.md', 'quick.md',
@@ -327,30 +327,17 @@ async function promptAndInstallOptional() {
327
327
  console.log(' ✓ @polderlabs/bizar-plugin already installed');
328
328
  }
329
329
 
330
- // Dashboard
331
- const dashInstalled = await isPackageInstalled('@polderlabs/bizar-dash');
332
- if (!dashInstalled) {
333
- console.log('');
334
- console.log(' The Bizar dashboard provides the web UI (React + Vite) and TUI (blessed).');
335
- console.log(' It\'s optional — install it for the full experience, or use the CLI alone.');
336
- const install = await promptYesNo(
337
- 'Install @polderlabs/bizar-dash?',
338
- true,
339
- );
340
- if (install) {
341
- try {
342
- console.log(' Installing @polderlabs/bizar-dash...');
343
- execSync('npm install -g @polderlabs/bizar-dash', { stdio: 'inherit' });
344
- console.log(' ✓ @polderlabs/bizar-dash installed');
345
- } catch (err) {
346
- console.log(` ✗ Failed to install @polderlabs/bizar-dash: ${err.message}`);
347
- console.log(' You can install it later with: npm install -g @polderlabs/bizar-dash');
348
- }
349
- } else {
350
- console.log(' Skipped. Install later with: npm install -g @polderlabs/bizar-dash');
351
- }
330
+ // Dashboard — v4.0.0: ships inside this package at <repo>/bizar-dash/
331
+ // Verify the directory is present; it's a corrupted install if missing.
332
+ const dashDir = join(__dirname, '..', 'bizar-dash');
333
+ const dashPkgJson = join(dashDir, 'package.json');
334
+ if (!existsSync(dashPkgJson)) {
335
+ console.error('');
336
+ console.error(' ✗ Dashboard directory not found at bizar-dash/.');
337
+ console.error(' This looks like a corrupted install.');
338
+ console.error(' Please report at: github.com/DrB0rk/BizarHarness/issues');
352
339
  } else {
353
- console.log(' ✓ @polderlabs/bizar-dash already installed');
340
+ console.log(' ✓ Dashboard directory present (bizar-dash/)');
354
341
  }
355
342
  }
356
343
 
@@ -567,32 +554,37 @@ export async function runPostInstall() {
567
554
  }
568
555
  console.log('BizarHarness: agents installed.');
569
556
 
570
- // Install RTK
571
- const rtkPresent = await detectRtk();
572
- if (!rtkPresent) {
573
- console.log('BizarHarness: installing RTK (token optimizer)...');
557
+ // Install Headroom
558
+ const headroomPresent = await detectHeadroom();
559
+ if (!headroomPresent) {
560
+ console.log('BizarHarness: installing Headroom (context compressor)...');
574
561
  try {
575
562
  if (process.platform === 'win32') {
576
- // RTK ships a bash-only installer; on Windows the user installs it
577
- // manually (e.g. `cargo install --git https://github.com/rtk-ai/rtk`).
578
- console.log('BizarHarness: RTK bash installer does not run on Windows. Install manually from https://github.com/rtk-ai/rtk');
563
+ console.log('BizarHarness: Automatic Headroom install not supported on Windows. Install manually: pip install "headroom-ai[all]"');
579
564
  } else {
580
565
  execSync(
581
- 'curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh',
566
+ 'pip install --user "headroom-ai[all]"',
582
567
  { stdio: 'pipe', timeout: 60000 },
583
568
  );
584
- execSync('rtk init -g --opencode', { stdio: 'pipe' });
585
- console.log('BizarHarness: RTK installed and configured.');
569
+ execSync('headroom wrap opencode', { stdio: 'pipe' });
570
+ console.log('BizarHarness: Headroom installed and configured.');
586
571
  }
587
572
  } catch {
588
- console.log('BizarHarness: RTK install failed. Install manually from https://github.com/rtk-ai/rtk');
573
+ // Fall back to npm
574
+ try {
575
+ execSync('npm install -g headroom-ai', { stdio: 'pipe', timeout: 60000 });
576
+ execSync('headroom wrap opencode', { stdio: 'pipe' });
577
+ console.log('BizarHarness: Headroom installed (npm) and configured.');
578
+ } catch {
579
+ console.log('BizarHarness: Headroom install failed. Install manually: pip install "headroom-ai[all]" or npm install -g headroom-ai');
580
+ }
589
581
  }
590
582
  } else {
591
583
  try {
592
- execSync('rtk init -g --opencode', { stdio: 'pipe' });
593
- console.log('BizarHarness: RTK configured for opencode.');
584
+ execSync('headroom wrap opencode', { stdio: 'pipe' });
585
+ console.log('BizarHarness: Headroom configured for opencode.');
594
586
  } catch {
595
- console.log('BizarHarness: could not configure RTK. Run `rtk init -g --opencode` manually.');
587
+ console.log('BizarHarness: could not configure Headroom. Run `headroom wrap opencode` manually.');
596
588
  }
597
589
  }
598
590