synabun 2.0.5 → 2.0.9
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/CHANGELOG.md +78 -0
- package/README.md +2 -1
- package/THIRD-PARTY-LICENSES.md +13 -0
- package/docs/whatsapp.md +151 -16
- package/hooks/claude-code/post-plan.mjs +6 -30
- package/hooks/claude-code/session-start.mjs +1 -4
- package/hooks/claude-code/shared.mjs +112 -75
- package/lib/child-path.js +303 -0
- package/lib/claude-hooks.js +2 -1
- package/lib/data-home-migration.js +2 -0
- package/lib/desktop-app.js +265 -0
- package/lib/external-tools.js +7 -3
- package/lib/log-redact.js +102 -0
- package/lib/package-processes.js +670 -0
- package/lib/packaged-runtime.js +138 -11
- package/lib/runtime-dependencies.js +225 -0
- package/mcp-server/dist/http.d.ts +3 -1
- package/mcp-server/dist/http.d.ts.map +1 -1
- package/mcp-server/dist/http.js +15 -4
- package/mcp-server/dist/http.js.map +1 -1
- package/mcp-server/dist/index.d.ts.map +1 -1
- package/mcp-server/dist/index.js +9 -6
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/services/browser-bench.d.ts +1 -1
- package/mcp-server/dist/services/browser-bench.d.ts.map +1 -1
- package/mcp-server/dist/services/browser-bench.js +1 -1
- package/mcp-server/dist/services/browser-bench.js.map +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts +108 -0
- package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -0
- package/mcp-server/dist/services/budget-judgments.js +153 -0
- package/mcp-server/dist/services/budget-judgments.js.map +1 -0
- package/mcp-server/dist/services/categories.d.ts +35 -2
- package/mcp-server/dist/services/categories.d.ts.map +1 -1
- package/mcp-server/dist/services/categories.js +77 -33
- package/mcp-server/dist/services/categories.js.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.d.ts +5 -1
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.js +41 -4
- package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
- package/mcp-server/dist/services/desktop-bench.d.ts +7 -7
- package/mcp-server/dist/services/desktop-bench.d.ts.map +1 -1
- package/mcp-server/dist/services/desktop-bench.js +1 -1
- package/mcp-server/dist/services/desktop-bench.js.map +1 -1
- package/mcp-server/dist/services/identity.d.ts +11 -0
- package/mcp-server/dist/services/identity.d.ts.map +1 -1
- package/mcp-server/dist/services/identity.js +24 -0
- package/mcp-server/dist/services/identity.js.map +1 -1
- package/mcp-server/dist/services/neural-interface.d.ts +13 -0
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js +34 -2
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/typesafe-config.d.ts +1 -1
- package/mcp-server/dist/services/typesafe-config.d.ts.map +1 -1
- package/mcp-server/dist/services/typesafe-config.js +4 -1
- package/mcp-server/dist/services/typesafe-config.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +11 -8
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +35 -14
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/bluesky.js +1 -1
- package/mcp-server/dist/tools/bluesky.js.map +1 -1
- package/mcp-server/dist/tools/browser-advanced.d.ts +1 -1
- package/mcp-server/dist/tools/browser-advanced.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-advanced.js +1 -1
- package/mcp-server/dist/tools/browser-advanced.js.map +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-batch.js +1 -1
- package/mcp-server/dist/tools/browser-batch.js.map +1 -1
- package/mcp-server/dist/tools/browser-cheatsheet.d.ts +1 -1
- package/mcp-server/dist/tools/browser-cheatsheet.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-cheatsheet.js +1 -1
- package/mcp-server/dist/tools/browser-cheatsheet.js.map +1 -1
- package/mcp-server/dist/tools/browser-interact.d.ts +1 -1
- package/mcp-server/dist/tools/browser-interact.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-interact.js +1 -1
- package/mcp-server/dist/tools/browser-interact.js.map +1 -1
- package/mcp-server/dist/tools/browser-navigate.d.ts +1 -1
- package/mcp-server/dist/tools/browser-navigate.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-navigate.js +1 -1
- package/mcp-server/dist/tools/browser-navigate.js.map +1 -1
- package/mcp-server/dist/tools/browser-observe.d.ts +1 -1
- package/mcp-server/dist/tools/browser-observe.d.ts.map +1 -1
- package/mcp-server/dist/tools/browser-observe.js +1 -1
- package/mcp-server/dist/tools/browser-observe.js.map +1 -1
- package/mcp-server/dist/tools/card-tools.d.ts +1 -1
- package/mcp-server/dist/tools/card-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/card-tools.js +1 -1
- package/mcp-server/dist/tools/card-tools.js.map +1 -1
- package/mcp-server/dist/tools/category.d.ts +1 -1
- package/mcp-server/dist/tools/category.d.ts.map +1 -1
- package/mcp-server/dist/tools/category.js +5 -1
- package/mcp-server/dist/tools/category.js.map +1 -1
- package/mcp-server/dist/tools/choice.d.ts +1 -1
- package/mcp-server/dist/tools/choice.d.ts.map +1 -1
- package/mcp-server/dist/tools/choice.js +1 -1
- package/mcp-server/dist/tools/choice.js.map +1 -1
- package/mcp-server/dist/tools/computer.d.ts +1 -1
- package/mcp-server/dist/tools/computer.d.ts.map +1 -1
- package/mcp-server/dist/tools/computer.js +1 -1
- package/mcp-server/dist/tools/computer.js.map +1 -1
- package/mcp-server/dist/tools/discord-channel.d.ts +1 -1
- package/mcp-server/dist/tools/discord-channel.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-channel.js +1 -1
- package/mcp-server/dist/tools/discord-channel.js.map +1 -1
- package/mcp-server/dist/tools/discord-guild.d.ts +1 -1
- package/mcp-server/dist/tools/discord-guild.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-guild.js +1 -1
- package/mcp-server/dist/tools/discord-guild.js.map +1 -1
- package/mcp-server/dist/tools/discord-member.d.ts +1 -1
- package/mcp-server/dist/tools/discord-member.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-member.js +1 -1
- package/mcp-server/dist/tools/discord-member.js.map +1 -1
- package/mcp-server/dist/tools/discord-message.d.ts +1 -1
- package/mcp-server/dist/tools/discord-message.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-message.js +1 -1
- package/mcp-server/dist/tools/discord-message.js.map +1 -1
- package/mcp-server/dist/tools/discord-onboarding.d.ts +1 -1
- package/mcp-server/dist/tools/discord-onboarding.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-onboarding.js +1 -1
- package/mcp-server/dist/tools/discord-onboarding.js.map +1 -1
- package/mcp-server/dist/tools/discord-role.d.ts +1 -1
- package/mcp-server/dist/tools/discord-role.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-role.js +1 -1
- package/mcp-server/dist/tools/discord-role.js.map +1 -1
- package/mcp-server/dist/tools/discord-thread.d.ts +1 -1
- package/mcp-server/dist/tools/discord-thread.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-thread.js +1 -1
- package/mcp-server/dist/tools/discord-thread.js.map +1 -1
- package/mcp-server/dist/tools/discord-webhook.d.ts +1 -1
- package/mcp-server/dist/tools/discord-webhook.d.ts.map +1 -1
- package/mcp-server/dist/tools/discord-webhook.js +1 -1
- package/mcp-server/dist/tools/discord-webhook.js.map +1 -1
- package/mcp-server/dist/tools/fb-groups.d.ts +1 -1
- package/mcp-server/dist/tools/fb-groups.d.ts.map +1 -1
- package/mcp-server/dist/tools/fb-groups.js +1 -1
- package/mcp-server/dist/tools/fb-groups.js.map +1 -1
- package/mcp-server/dist/tools/forget.d.ts +1 -1
- package/mcp-server/dist/tools/forget.d.ts.map +1 -1
- package/mcp-server/dist/tools/forget.js +1 -1
- package/mcp-server/dist/tools/forget.js.map +1 -1
- package/mcp-server/dist/tools/git-tools.d.ts +1 -1
- package/mcp-server/dist/tools/git-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/git-tools.js +1 -1
- package/mcp-server/dist/tools/git-tools.js.map +1 -1
- package/mcp-server/dist/tools/gsc/experience.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/experience.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/experience.js +1 -1
- package/mcp-server/dist/tools/gsc/experience.js.map +1 -1
- package/mcp-server/dist/tools/gsc/indexing.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/indexing.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/indexing.js +1 -1
- package/mcp-server/dist/tools/gsc/indexing.js.map +1 -1
- package/mcp-server/dist/tools/gsc/inspect.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/inspect.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/inspect.js +1 -1
- package/mcp-server/dist/tools/gsc/inspect.js.map +1 -1
- package/mcp-server/dist/tools/gsc/navigate.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/navigate.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/navigate.js +1 -1
- package/mcp-server/dist/tools/gsc/navigate.js.map +1 -1
- package/mcp-server/dist/tools/gsc/performance.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/performance.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/performance.js +1 -1
- package/mcp-server/dist/tools/gsc/performance.js.map +1 -1
- package/mcp-server/dist/tools/gsc/settings.d.ts +1 -1
- package/mcp-server/dist/tools/gsc/settings.d.ts.map +1 -1
- package/mcp-server/dist/tools/gsc/settings.js +1 -1
- package/mcp-server/dist/tools/gsc/settings.js.map +1 -1
- package/mcp-server/dist/tools/image-tools.d.ts +1 -1
- package/mcp-server/dist/tools/image-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/image-tools.js +1 -1
- package/mcp-server/dist/tools/image-tools.js.map +1 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +1 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js +1 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js.map +1 -1
- package/mcp-server/dist/tools/loop.d.ts +1 -1
- package/mcp-server/dist/tools/loop.d.ts.map +1 -1
- package/mcp-server/dist/tools/loop.js +1 -1
- package/mcp-server/dist/tools/loop.js.map +1 -1
- package/mcp-server/dist/tools/memories.d.ts +1 -1
- package/mcp-server/dist/tools/memories.d.ts.map +1 -1
- package/mcp-server/dist/tools/memories.js +1 -1
- package/mcp-server/dist/tools/memories.js.map +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
- package/mcp-server/dist/tools/morelogin.js +1 -1
- package/mcp-server/dist/tools/morelogin.js.map +1 -1
- package/mcp-server/dist/tools/profile.d.ts +1 -1
- package/mcp-server/dist/tools/profile.d.ts.map +1 -1
- package/mcp-server/dist/tools/profile.js +1 -1
- package/mcp-server/dist/tools/profile.js.map +1 -1
- package/mcp-server/dist/tools/recall.d.ts +1 -1
- package/mcp-server/dist/tools/recall.d.ts.map +1 -1
- package/mcp-server/dist/tools/recall.js +1 -1
- package/mcp-server/dist/tools/recall.js.map +1 -1
- package/mcp-server/dist/tools/reflect.d.ts +1 -1
- package/mcp-server/dist/tools/reflect.d.ts.map +1 -1
- package/mcp-server/dist/tools/reflect.js +1 -1
- package/mcp-server/dist/tools/reflect.js.map +1 -1
- package/mcp-server/dist/tools/remember.d.ts +1 -1
- package/mcp-server/dist/tools/remember.d.ts.map +1 -1
- package/mcp-server/dist/tools/remember.js +13 -11
- package/mcp-server/dist/tools/remember.js.map +1 -1
- package/mcp-server/dist/tools/restore.d.ts +1 -1
- package/mcp-server/dist/tools/restore.d.ts.map +1 -1
- package/mcp-server/dist/tools/restore.js +1 -1
- package/mcp-server/dist/tools/restore.js.map +1 -1
- package/mcp-server/dist/tools/style-guide-tools.d.ts +1 -1
- package/mcp-server/dist/tools/style-guide-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/style-guide-tools.js +1 -1
- package/mcp-server/dist/tools/style-guide-tools.js.map +1 -1
- package/mcp-server/dist/tools/sync.d.ts +1 -1
- package/mcp-server/dist/tools/sync.d.ts.map +1 -1
- package/mcp-server/dist/tools/sync.js +1 -1
- package/mcp-server/dist/tools/sync.js.map +1 -1
- package/mcp-server/dist/tools/tictactoe-tools.d.ts +1 -1
- package/mcp-server/dist/tools/tictactoe-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/tictactoe-tools.js +1 -1
- package/mcp-server/dist/tools/tictactoe-tools.js.map +1 -1
- package/mcp-server/dist/tools/utils.d.ts +1 -1
- package/mcp-server/dist/tools/utils.d.ts.map +1 -1
- package/mcp-server/dist/tools/utils.js +1 -1
- package/mcp-server/dist/tools/utils.js.map +1 -1
- package/mcp-server/dist/tools/whatsapp-send-file.d.ts +17 -0
- package/mcp-server/dist/tools/whatsapp-send-file.d.ts.map +1 -0
- package/mcp-server/dist/tools/whatsapp-send-file.js +44 -0
- package/mcp-server/dist/tools/whatsapp-send-file.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard-tools.d.ts +3 -3
- package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
- package/mcp-server/dist/tools/youtube/analytics.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/analytics.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/analytics.js +1 -1
- package/mcp-server/dist/tools/youtube/analytics.js.map +1 -1
- package/mcp-server/dist/tools/youtube/download.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/download.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/download.js +1 -1
- package/mcp-server/dist/tools/youtube/download.js.map +1 -1
- package/mcp-server/dist/tools/youtube/media.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/media.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/media.js +1 -1
- package/mcp-server/dist/tools/youtube/media.js.map +1 -1
- package/mcp-server/dist/tools/youtube/metadata.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/metadata.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/metadata.js +1 -1
- package/mcp-server/dist/tools/youtube/metadata.js.map +1 -1
- package/mcp-server/dist/tools/youtube/navigate.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/navigate.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/navigate.js +1 -1
- package/mcp-server/dist/tools/youtube/navigate.js.map +1 -1
- package/mcp-server/dist/tools/youtube/playlist.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/playlist.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/playlist.js +1 -1
- package/mcp-server/dist/tools/youtube/playlist.js.map +1 -1
- package/mcp-server/dist/tools/youtube/schedule.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/schedule.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/schedule.js +1 -1
- package/mcp-server/dist/tools/youtube/schedule.js.map +1 -1
- package/mcp-server/dist/tools/youtube/source.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/source.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/source.js +1 -1
- package/mcp-server/dist/tools/youtube/source.js.map +1 -1
- package/mcp-server/dist/tools/youtube/upload.d.ts +1 -1
- package/mcp-server/dist/tools/youtube/upload.d.ts.map +1 -1
- package/mcp-server/dist/tools/youtube/upload.js +4 -9
- package/mcp-server/dist/tools/youtube/upload.js.map +1 -1
- package/mcp-server/dist/tui.js +18 -5
- package/mcp-server/dist/tui.js.map +1 -1
- package/mcp-server/dist/version.d.ts +5 -0
- package/mcp-server/dist/version.d.ts.map +1 -0
- package/mcp-server/dist/version.js +21 -0
- package/mcp-server/dist/version.js.map +1 -0
- package/mcp-server/package-lock.json +3 -3
- package/mcp-server/package.json +3 -3
- package/mcp-server/run.mjs +15 -9
- package/mcp-server/src/http.ts +18 -3
- package/mcp-server/src/index.ts +9 -6
- package/mcp-server/src/services/browser-bench.ts +1 -1
- package/mcp-server/src/services/budget-judgments.ts +183 -0
- package/mcp-server/src/services/categories.ts +77 -32
- package/mcp-server/src/services/codex-config-heal.ts +35 -4
- package/mcp-server/src/services/desktop-bench.ts +1 -1
- package/mcp-server/src/services/identity.ts +27 -0
- package/mcp-server/src/services/neural-interface.ts +34 -2
- package/mcp-server/src/services/typesafe-config.ts +4 -1
- package/mcp-server/src/tools/agents.ts +34 -15
- package/mcp-server/src/tools/bluesky.ts +1 -1
- package/mcp-server/src/tools/browser-advanced.ts +1 -1
- package/mcp-server/src/tools/browser-batch.ts +1 -1
- package/mcp-server/src/tools/browser-cheatsheet.ts +1 -1
- package/mcp-server/src/tools/browser-interact.ts +1 -1
- package/mcp-server/src/tools/browser-navigate.ts +1 -1
- package/mcp-server/src/tools/browser-observe.ts +1 -1
- package/mcp-server/src/tools/card-tools.ts +1 -1
- package/mcp-server/src/tools/category.ts +6 -1
- package/mcp-server/src/tools/choice.ts +1 -1
- package/mcp-server/src/tools/computer.ts +1 -1
- package/mcp-server/src/tools/discord-channel.ts +1 -1
- package/mcp-server/src/tools/discord-guild.ts +1 -1
- package/mcp-server/src/tools/discord-member.ts +1 -1
- package/mcp-server/src/tools/discord-message.ts +1 -1
- package/mcp-server/src/tools/discord-onboarding.ts +1 -1
- package/mcp-server/src/tools/discord-role.ts +1 -1
- package/mcp-server/src/tools/discord-thread.ts +1 -1
- package/mcp-server/src/tools/discord-webhook.ts +1 -1
- package/mcp-server/src/tools/fb-groups.ts +1 -1
- package/mcp-server/src/tools/forget.ts +1 -1
- package/mcp-server/src/tools/git-tools.ts +1 -1
- package/mcp-server/src/tools/gsc/experience.ts +1 -1
- package/mcp-server/src/tools/gsc/indexing.ts +1 -1
- package/mcp-server/src/tools/gsc/inspect.ts +1 -1
- package/mcp-server/src/tools/gsc/navigate.ts +1 -1
- package/mcp-server/src/tools/gsc/performance.ts +1 -1
- package/mcp-server/src/tools/gsc/settings.ts +1 -1
- package/mcp-server/src/tools/image-tools.ts +1 -1
- package/mcp-server/src/tools/leonardo-browser-tools.ts +1 -1
- package/mcp-server/src/tools/loop.ts +1 -1
- package/mcp-server/src/tools/memories.ts +1 -1
- package/mcp-server/src/tools/morelogin.ts +1 -1
- package/mcp-server/src/tools/profile.ts +1 -1
- package/mcp-server/src/tools/recall.ts +1 -1
- package/mcp-server/src/tools/reflect.ts +1 -1
- package/mcp-server/src/tools/remember.ts +13 -12
- package/mcp-server/src/tools/restore.ts +1 -1
- package/mcp-server/src/tools/style-guide-tools.ts +1 -1
- package/mcp-server/src/tools/sync.ts +1 -1
- package/mcp-server/src/tools/tictactoe-tools.ts +1 -1
- package/mcp-server/src/tools/utils.ts +1 -1
- package/mcp-server/src/tools/whatsapp-send-file.ts +51 -0
- package/mcp-server/src/tools/whiteboard-tools.ts +1 -1
- package/mcp-server/src/tools/youtube/analytics.ts +1 -1
- package/mcp-server/src/tools/youtube/download.ts +1 -1
- package/mcp-server/src/tools/youtube/media.ts +1 -1
- package/mcp-server/src/tools/youtube/metadata.ts +1 -1
- package/mcp-server/src/tools/youtube/navigate.ts +1 -1
- package/mcp-server/src/tools/youtube/playlist.ts +1 -1
- package/mcp-server/src/tools/youtube/schedule.ts +1 -1
- package/mcp-server/src/tools/youtube/source.ts +1 -1
- package/mcp-server/src/tools/youtube/upload.ts +4 -12
- package/mcp-server/src/tui.ts +24 -10
- package/mcp-server/src/version.ts +22 -0
- package/neural-interface/i18n/en.json +645 -57
- package/neural-interface/i18n/pt-BR.json +644 -56
- package/neural-interface/lib/account-usage.js +163 -0
- package/neural-interface/lib/agent-sandbox-elevation.js +102 -0
- package/neural-interface/lib/agent-sandbox-setting.js +57 -0
- package/neural-interface/lib/assistant-api.js +274 -52
- package/neural-interface/lib/assistant-brains/claude.js +15 -2
- package/neural-interface/lib/assistant-brains/codex.js +3 -0
- package/neural-interface/lib/assistant-brains/opencode.js +17 -4
- package/neural-interface/lib/assistant-budget-planner.js +390 -0
- package/neural-interface/lib/assistant-budget-split.js +408 -0
- package/neural-interface/lib/assistant-budget.js +94 -95
- package/neural-interface/lib/assistant-config.js +62 -14
- package/neural-interface/lib/assistant-dispatch.js +432 -125
- package/neural-interface/lib/assistant-jev.js +26 -3
- package/neural-interface/lib/assistant-persona.js +68 -11
- package/neural-interface/lib/assistant-plan-permissions.js +8 -1
- package/neural-interface/lib/assistant-route-accounts.js +14 -0
- package/neural-interface/lib/assistant-route-gate-codex.js +3 -1
- package/neural-interface/lib/assistant-route-gate.js +19 -3
- package/neural-interface/lib/assistant-router.js +373 -42
- package/neural-interface/lib/assistant-runtime.js +312 -48
- package/neural-interface/lib/assistant-user-writer.js +4 -2
- package/neural-interface/lib/augmented-path.js +317 -53
- package/neural-interface/lib/claude-accounts.js +342 -31
- package/neural-interface/lib/claude-agent-bridge.js +90 -3
- package/neural-interface/lib/claude-executable.js +6 -1
- package/neural-interface/lib/claude-model-catalog.js +3 -3
- package/neural-interface/lib/claude-panel-auth.js +221 -0
- package/neural-interface/lib/claude-profile-api-key.js +62 -0
- package/neural-interface/lib/cli-install-api.js +137 -0
- package/neural-interface/lib/cli-install.js +797 -0
- package/neural-interface/lib/cli-path.js +130 -0
- package/neural-interface/lib/cli-resolver.js +744 -0
- package/neural-interface/lib/cli-update-planner.js +143 -7
- package/neural-interface/lib/codex-account-auth.js +180 -0
- package/neural-interface/lib/codex-accounts.js +502 -0
- package/neural-interface/lib/codex-capabilities.js +2 -1
- package/neural-interface/lib/codex-compat-rpc.js +8 -2
- package/neural-interface/lib/codex-mcp-approvals.js +5 -1
- package/neural-interface/lib/codex-panel-auth.js +62 -0
- package/neural-interface/lib/codex-session-settings.js +1 -1
- package/neural-interface/lib/codex-settings-schema.js +122 -0
- package/neural-interface/lib/desktop/config.js +3 -0
- package/neural-interface/lib/exec-loop-command.js +3 -1
- package/neural-interface/lib/git-bash/bzip2.js +339 -0
- package/neural-interface/lib/git-bash/claude-settings.js +73 -0
- package/neural-interface/lib/git-bash/extract-worker.js +34 -0
- package/neural-interface/lib/git-bash/install.js +529 -0
- package/neural-interface/lib/git-bash/licenses/COPYING +360 -0
- package/neural-interface/lib/git-bash/licenses/LGPL-2.1 +511 -0
- package/neural-interface/lib/git-bash/manager.js +268 -0
- package/neural-interface/lib/git-bash/pins.js +206 -0
- package/neural-interface/lib/git-bash/pins.json +34 -0
- package/neural-interface/lib/git-bash/resolver.js +194 -0
- package/neural-interface/lib/git-read.js +34 -2
- package/neural-interface/lib/install-details.js +163 -0
- package/neural-interface/lib/mcp-installer.js +14 -2
- package/neural-interface/lib/native-loop-providers.js +22 -4
- package/neural-interface/lib/native-loop-runtime.js +9 -4
- package/neural-interface/lib/os-path.js +319 -0
- package/neural-interface/lib/provider-panel-api-key-auth.js +92 -0
- package/neural-interface/lib/provider-panel-terminal-auth.js +96 -0
- package/neural-interface/lib/pty-host/core.js +2 -1
- package/neural-interface/lib/pty-host/manager.js +27 -2
- package/neural-interface/lib/remote-policy.js +20 -11
- package/neural-interface/lib/session-indexer.js +3 -1
- package/neural-interface/lib/session-title-generator.js +6 -3
- package/neural-interface/lib/system-about.js +340 -0
- package/neural-interface/lib/system-activity.js +66 -0
- package/neural-interface/lib/terminal-env.js +11 -3
- package/neural-interface/lib/terminal-path.js +55 -0
- package/neural-interface/lib/virtual-socket.js +12 -1
- package/neural-interface/lib/whatsapp/baileys-adapter.js +165 -45
- package/neural-interface/lib/whatsapp/bridge.js +78 -34
- package/neural-interface/lib/whatsapp/commands.js +13 -14
- package/neural-interface/lib/whatsapp/config.js +134 -20
- package/neural-interface/lib/whatsapp/fake-baileys.js +99 -14
- package/neural-interface/lib/whatsapp/host-core.js +168 -35
- package/neural-interface/lib/whatsapp/inbound.js +5 -3
- package/neural-interface/lib/whatsapp/local-file.js +524 -0
- package/neural-interface/lib/whatsapp/manager.js +92 -32
- package/neural-interface/lib/whatsapp/paths.js +11 -1
- package/neural-interface/lib/whatsapp/protocol.js +65 -5
- package/neural-interface/lib/whatsapp/redact.js +63 -0
- package/neural-interface/lib/whatsapp/service.js +343 -91
- package/neural-interface/lib/whatsapp/transcription.js +463 -0
- package/neural-interface/package-lock.json +2 -2
- package/neural-interface/package.json +1 -1
- package/neural-interface/public/index.html +2 -0
- package/neural-interface/public/index2d.html +2 -0
- package/neural-interface/public/offline.html +16 -1
- package/neural-interface/public/onboarding.html +96 -2
- package/neural-interface/public/shared/account-i18n.js +7 -0
- package/neural-interface/public/shared/account-menu.js +542 -0
- package/neural-interface/public/shared/account-usage.js +79 -0
- package/neural-interface/public/shared/account-view.js +336 -0
- package/neural-interface/public/shared/agent-runtime-options.js +28 -8
- package/neural-interface/public/shared/assistant/asst-account-menu.js +298 -0
- package/neural-interface/public/shared/assistant/asst-accounts.js +182 -184
- package/neural-interface/public/shared/assistant/asst-api.js +39 -2
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +288 -32
- package/neural-interface/public/shared/assistant/asst-budget.js +259 -303
- package/neural-interface/public/shared/assistant/asst-mascot.js +126 -7
- package/neural-interface/public/shared/assistant/asst-menu.js +219 -80
- package/neural-interface/public/shared/assistant/asst-model-chip.js +135 -0
- package/neural-interface/public/shared/assistant/asst-panel.js +87 -16
- package/neural-interface/public/shared/assistant/asst-render.js +38 -7
- package/neural-interface/public/shared/assistant/asst-route.js +72 -14
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +45 -6
- package/neural-interface/public/shared/assistant/asst-slash.js +1 -1
- package/neural-interface/public/shared/assistant/asst-state.js +1 -1
- package/neural-interface/public/shared/assistant/asst-styles.js +160 -29
- package/neural-interface/public/shared/cdx/cdx-commands.js +4 -1
- package/neural-interface/public/shared/cdx/cdx-features.js +22 -14
- package/neural-interface/public/shared/cdx/cdx-icons.js +2 -0
- package/neural-interface/public/shared/cdx/cdx-panel.js +49 -108
- package/neural-interface/public/shared/cdx/cdx-settings.js +231 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +172 -111
- package/neural-interface/public/shared/cdx/cdx-tabs.js +264 -664
- package/neural-interface/public/shared/cdx/cdx-ws.js +2 -0
- package/neural-interface/public/shared/claude-account-view.js +3 -0
- package/neural-interface/public/shared/cli-install-view.js +392 -0
- package/neural-interface/public/shared/cli-status.js +282 -22
- package/neural-interface/public/shared/cp/cp-events.js +2 -1
- package/neural-interface/public/shared/cp/cp-styles.js +46 -0
- package/neural-interface/public/shared/desktop-bridge.js +39 -0
- package/neural-interface/public/shared/desktop-titlebar-page.js +59 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +122 -0
- package/neural-interface/public/shared/desktop-titlebar.js +153 -0
- package/neural-interface/public/shared/desktop-update-view.js +462 -0
- package/neural-interface/public/shared/editor/editor-panel.js +1 -1
- package/neural-interface/public/shared/explorer/fx-main.js +1 -1
- package/neural-interface/public/shared/git-bash-view.js +145 -0
- package/neural-interface/public/shared/html-shell.js +1 -0
- package/neural-interface/public/shared/i18n.js +19 -1
- package/neural-interface/public/shared/install-details-view.js +86 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +4 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +36 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +17 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +169 -2
- package/neural-interface/public/shared/pwa-install-page.js +3 -1
- package/neural-interface/public/shared/settings/settings-about-pane.js +271 -0
- package/neural-interface/public/shared/settings/settings-about.js +254 -0
- package/neural-interface/public/shared/settings/settings-ia.js +15 -0
- package/neural-interface/public/shared/showcase-privacy.js +490 -0
- package/neural-interface/public/shared/storage.js +30 -3
- package/neural-interface/public/shared/styles.css +281 -32
- package/neural-interface/public/shared/synabun-mascot.js +48 -2
- package/neural-interface/public/shared/ui-claude-panel.js +262 -217
- package/neural-interface/public/shared/ui-cli-banner.js +355 -0
- package/neural-interface/public/shared/ui-explorer.js +2 -0
- package/neural-interface/public/shared/ui-git-bash.js +124 -0
- package/neural-interface/public/shared/ui-judgments.js +10 -1
- package/neural-interface/public/shared/ui-loading.js +30 -6
- package/neural-interface/public/shared/ui-menubar.js +13 -3
- package/neural-interface/public/shared/ui-navbar.js +3 -1
- package/neural-interface/public/shared/ui-provider-auth.js +104 -0
- package/neural-interface/public/shared/ui-provider-terminal-auth.js +223 -0
- package/neural-interface/public/shared/ui-sessions.js +9 -3
- package/neural-interface/public/shared/ui-settings.js +55 -3
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -1
- package/neural-interface/public/shared/ui-sync.js +8 -0
- package/neural-interface/public/shared/ui-terminal.js +17 -0
- package/neural-interface/public/shared/ui-tool-updates.js +5 -0
- package/neural-interface/public/shared/ui-update.js +598 -7
- package/neural-interface/public/shared/ui-whatsapp.js +21 -6
- package/neural-interface/public/shared/whatsapp/wa-view.js +51 -8
- package/neural-interface/public/shared/worker-end.js +2 -0
- package/neural-interface/public/sw.js +1 -1
- package/neural-interface/public/variant/2d/main.js +10 -1
- package/neural-interface/public/variant/3d/main.js +10 -1
- package/neural-interface/scripts/rebuild-pty.js +14 -2
- package/neural-interface/server.js +1384 -679
- package/npm-shrinkwrap.json +4424 -0
- package/package.json +57 -2
- package/postinstall.js +61 -47
- package/preuninstall.js +8 -35
- package/setup.js +80 -47
- package/skills/synabun/modules/idea.md +1 -1
- package/skills/synabun/modules/schedule.md +1 -1
- package/updater.cmd +2 -2
- package/updater.mjs +97 -3
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Assistant budget split (pure: buckets, shares, coverage)
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// A session with a budget (assistant-budget.js) divides what is left across
|
|
6
|
+
// three buckets, one per provider: claude-code, codex, opencode. A provider's
|
|
7
|
+
// runs draw from its share; the Assistant's own turns (brain turns, direct and
|
|
8
|
+
// continuation routes) draw from the share of the brain's provider, which
|
|
9
|
+
// keeps a reserve for them that the workers on that provider cannot spend.
|
|
10
|
+
//
|
|
11
|
+
// Who decides the weights: Jev (surface budget-split, one Score per provider:
|
|
12
|
+
// how much of the spend still to come lands there), else the fixed heuristic
|
|
13
|
+
// fallbackWeights(). Either way the code here does the money: the weights are
|
|
14
|
+
// normalised, the brain's reserve applied, and what is left is divided in whole
|
|
15
|
+
// cents that add up exactly to it. A provider a checkpoint found short gets
|
|
16
|
+
// more only when the weights give it more: when they do not, its tasks move to
|
|
17
|
+
// another provider (the router) and its runs stop. Nothing here raises the
|
|
18
|
+
// total or picks a model.
|
|
19
|
+
//
|
|
20
|
+
// Everything in this file is pure; assistant-budget-planner.js owns the state.
|
|
21
|
+
|
|
22
|
+
import { listedCount, priceText, providerAllHidden, providerEmpty, rowIsHidden, findModel, defaultModelRow } from './assistant-catalog.js';
|
|
23
|
+
import { BUDGET_WARN_RATIO, floorCents, roundUsd } from './assistant-budget.js';
|
|
24
|
+
|
|
25
|
+
export const BUDGET_PROVIDERS = Object.freeze(['claude-code', 'codex', 'opencode']);
|
|
26
|
+
export const PROVIDER_LABELS = Object.freeze({ 'claude-code': 'Claude Code', codex: 'Codex', opencode: 'OpenCode' });
|
|
27
|
+
|
|
28
|
+
// The brain's reserve inside its provider's share: 10 % of what is left, at least $0.50 (never more than is left).
|
|
29
|
+
export const BRAIN_FLOOR_RATIO = 0.1;
|
|
30
|
+
export const BRAIN_FLOOR_MIN_USD = 0.5;
|
|
31
|
+
// Less than this cannot pay for a model call: the share counts as used up.
|
|
32
|
+
export const MIN_SPEND_USD = 0.01;
|
|
33
|
+
|
|
34
|
+
// What each level of Jev's Score question (mcp-server/src/services/budget-judgments.ts SHARE_LEVELS, lowest
|
|
35
|
+
// first) stands for as a share of the spend still to come. The expected share is these weighted by the
|
|
36
|
+
// answer's probabilities, else read off its probability-weighted position.
|
|
37
|
+
export const SHARE_LEVEL_FRACTIONS = Object.freeze([0, 0.1, 0.3, 0.6, 0.9]);
|
|
38
|
+
|
|
39
|
+
// What one task of a class tends to cost, relative to a quick task (the fallback's weights).
|
|
40
|
+
export const CLASS_COST_WEIGHTS = Object.freeze({
|
|
41
|
+
chat: 0.5, quick: 1, research: 1.5, browser: 1.5, computer: 1.5, automation: 1,
|
|
42
|
+
review: 2, code: 3, design: 3, image_gen: 2, video_gen: 2, complex: 4,
|
|
43
|
+
});
|
|
44
|
+
// A model's blended list price ($/MTok: (3 × input + output) / 4) is divided by this to give its price index.
|
|
45
|
+
export const PRICE_INDEX_BASE_USD = 5;
|
|
46
|
+
|
|
47
|
+
const arr = (value) => (Array.isArray(value) ? value : []);
|
|
48
|
+
const num = (value, fallback = 0) => (Number.isFinite(Number(value)) ? Number(value) : fallback);
|
|
49
|
+
const r8 = (value) => Number((Number(value) || 0).toFixed(8));
|
|
50
|
+
const isProvider = (value) => BUDGET_PROVIDERS.includes(value);
|
|
51
|
+
|
|
52
|
+
// ── buckets ───────────────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Which providers can take a share now → { [provider]: { eligible, reason } }.
|
|
56
|
+
* no_models the user disabled every model, or the provider answered with none connected
|
|
57
|
+
* signed_out every account of the provider is signed out
|
|
58
|
+
* limited every signed-in account is out of subscription usage
|
|
59
|
+
* A provider whose model list is merely unavailable stays eligible (routing is lenient there too). The
|
|
60
|
+
* brain's provider is always eligible (its turns are paid from it); `reason` then says what else is wrong.
|
|
61
|
+
*/
|
|
62
|
+
export function bucketEligibility({ catalog = null, accounts = null, brainProvider = null } = {}) {
|
|
63
|
+
const out = {};
|
|
64
|
+
for (const provider of BUDGET_PROVIDERS) {
|
|
65
|
+
let reason = null;
|
|
66
|
+
if (catalog) {
|
|
67
|
+
if (providerEmpty(catalog, provider) || providerAllHidden(catalog, provider)) reason = 'no_models';
|
|
68
|
+
else if (listedCount(catalog, provider) > 0 || arr(catalog.models?.[provider]).length) {
|
|
69
|
+
const usable = arr(catalog.models?.[provider]).filter((row) => !rowIsHidden(catalog, { ...row, provider: row.provider || provider }) && row.status !== 'unavailable');
|
|
70
|
+
if (!usable.length) reason = 'no_models';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!reason && accounts && Object.hasOwn(accounts, provider)) {
|
|
74
|
+
const rows = arr(accounts[provider]);
|
|
75
|
+
if (rows.length) {
|
|
76
|
+
const usable = rows.filter((row) => row && row.signedIn !== false && row.usage?.limited !== true);
|
|
77
|
+
if (!usable.length) reason = rows.every((row) => row?.signedIn === false) ? 'signed_out' : 'limited';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
out[provider] = provider === brainProvider ? { eligible: true, reason: reason ? `brain:${reason}` : 'brain' } : { eligible: !reason, reason };
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ── prices ────────────────────────────────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
/** The catalog row a target runs on (its provider default when it names no model), or null. */
|
|
88
|
+
export function rowOf(catalog, provider, model) {
|
|
89
|
+
if (!catalog || !provider) return null;
|
|
90
|
+
try { return model ? findModel(catalog, provider, model)?.row || null : defaultModelRow(catalog, provider); } catch { return null; }
|
|
91
|
+
}
|
|
92
|
+
/** A row's list price: its own (Claude, OpenCode), else its list-price equivalent (Codex: billed by plan). */
|
|
93
|
+
export function listPriceOf(row, { pricing = null, provider = null, model = null } = {}) {
|
|
94
|
+
if (row?.price) return row.price;
|
|
95
|
+
if (row?.listPrice) return row.listPrice;
|
|
96
|
+
if ((provider || row?.provider) === 'codex' && pricing?.codexPrice) {
|
|
97
|
+
try { return pricing.codexPrice(model || row?.id || null) || null; } catch { return null; }
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
/** Is the model free (catalog basis free)? Free models need no share. */
|
|
102
|
+
export function isFreePrice(price) { return !!price && (price.basis === 'free' || (num(price.input) === 0 && num(price.output) === 0 && price.basis !== 'plan')); }
|
|
103
|
+
/** A model's price index for the fallback: its blended list price / $5, 0 when free, 1 when unknown. */
|
|
104
|
+
export function priceIndex(price) {
|
|
105
|
+
if (!price) return 1;
|
|
106
|
+
if (isFreePrice(price)) return 0;
|
|
107
|
+
const blended = (3 * num(price.input) + num(price.output)) / 4;
|
|
108
|
+
if (!(blended > 0)) return 1;
|
|
109
|
+
return Math.min(20, Math.max(0.05, blended / PRICE_INDEX_BASE_USD));
|
|
110
|
+
}
|
|
111
|
+
/** "$5/$25" (or "free", "plan (list …)") for the Jev state; null when unknown. */
|
|
112
|
+
export function priceLabel(row, price) {
|
|
113
|
+
if (!price && !row) return null;
|
|
114
|
+
try { return row ? priceText(row.price || null, row.listPrice || (row.price ? null : price)) : priceText(price); } catch { return null; }
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* How the work is paid for: 'free' (a free model), 'api' (an API key, or OpenCode's own providers), 'plan'
|
|
118
|
+
* (a Claude / ChatGPT subscription). `account`: the account row the work would run under, when known.
|
|
119
|
+
*/
|
|
120
|
+
export function billingOf(provider, price, account = null) {
|
|
121
|
+
if (isFreePrice(price)) return 'free';
|
|
122
|
+
if (provider === 'opencode') return 'api';
|
|
123
|
+
if (account?.mode === 'apiKey') return 'api';
|
|
124
|
+
return 'plan';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── weights ───────────────────────────────────────────────────────────────
|
|
128
|
+
|
|
129
|
+
const classWeight = (taskClass) => CLASS_COST_WEIGHTS[taskClass] ?? 1;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The deterministic split's weights, used when Jev is off, unreachable or answers nothing usable. Each
|
|
133
|
+
* eligible provider is weighted by the work the session is likely to send it, times what that work's models
|
|
134
|
+
* cost (priceIndex):
|
|
135
|
+
* - every task class once: on the provider its saved route names, else on the brain's provider (chat
|
|
136
|
+
* always on the brain's: it never runs anywhere else)
|
|
137
|
+
* - every task routed so far in this session: twice, on the provider it went to
|
|
138
|
+
* - the task being routed now: three times, on its provider
|
|
139
|
+
* - the Assistant's own turns: twice a quick task, on the brain's provider at the brain's model price
|
|
140
|
+
* - every live run: once its class, on its provider
|
|
141
|
+
* - a provider a checkpoint found short (`needs`): at least one quick task
|
|
142
|
+
* Ineligible providers get 0. When nothing weighs anything (every model free), every eligible provider weighs
|
|
143
|
+
* the same. → { [provider]: number }
|
|
144
|
+
*/
|
|
145
|
+
export function fallbackWeights({
|
|
146
|
+
eligible = {}, routing = {}, brain = null, catalog = null, pricing = null,
|
|
147
|
+
tasks = [], task = null, liveRuns = [], needs = [], classes = Object.keys(CLASS_COST_WEIGHTS),
|
|
148
|
+
} = {}) {
|
|
149
|
+
const weights = Object.fromEntries(BUDGET_PROVIDERS.map((p) => [p, 0]));
|
|
150
|
+
const brainProvider = isProvider(brain?.provider) ? brain.provider : null;
|
|
151
|
+
const price = (provider, model) => priceIndex(listPriceOf(rowOf(catalog, provider, model), { pricing, provider, model }));
|
|
152
|
+
const add = (provider, model, weight) => { if (isProvider(provider) && eligible[provider]?.eligible !== false) weights[provider] += weight * price(provider, model); };
|
|
153
|
+
const prefs = routing?.preferences && typeof routing.preferences === 'object' ? routing.preferences : {};
|
|
154
|
+
for (const taskClass of classes) {
|
|
155
|
+
// Chat always runs here, on the brain, whatever its saved route says (assistant-router.js evaluateRoute).
|
|
156
|
+
const pref = taskClass === 'chat' ? null : prefs[taskClass];
|
|
157
|
+
if (pref?.provider) add(pref.provider, pref.model || (pref.kind === 'direct' && pref.provider === brainProvider ? brain?.model || null : null), classWeight(taskClass));
|
|
158
|
+
else if (brainProvider) add(brainProvider, brain?.model || null, classWeight(taskClass));
|
|
159
|
+
}
|
|
160
|
+
for (const row of arr(tasks)) add(row?.provider, row?.model || null, 2 * classWeight(row?.taskClass));
|
|
161
|
+
if (task?.provider) add(task.provider, task.model || null, 3 * classWeight(task.taskClass));
|
|
162
|
+
if (brainProvider) add(brainProvider, brain?.model || null, 2);
|
|
163
|
+
for (const run of arr(liveRuns)) add(run?.provider, run?.model || null, classWeight(run?.taskClass));
|
|
164
|
+
for (const provider of arr(needs)) if (isProvider(provider) && eligible[provider]?.eligible !== false && weights[provider] <= 0) weights[provider] = Math.max(weights[provider], price(provider, null) > 0 ? 1 : 0);
|
|
165
|
+
const pool = BUDGET_PROVIDERS.filter((p) => eligible[p]?.eligible !== false);
|
|
166
|
+
if (pool.length && pool.every((p) => !(weights[p] > 0))) for (const p of pool) weights[p] = 1;
|
|
167
|
+
return weights;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** The expected share (0-1) one Score answer stands for: SHARE_LEVEL_FRACTIONS weighted by its probabilities, else interpolated at its position. */
|
|
171
|
+
export function shareFromScore(answer) {
|
|
172
|
+
if (!answer || typeof answer !== 'object') return null;
|
|
173
|
+
const levels = SHARE_LEVEL_FRACTIONS;
|
|
174
|
+
const probs = answer.probabilities && typeof answer.probabilities === 'object' ? answer.probabilities : null;
|
|
175
|
+
if (probs) {
|
|
176
|
+
let total = 0;
|
|
177
|
+
let expected = 0;
|
|
178
|
+
for (const [key, value] of Object.entries(probs)) {
|
|
179
|
+
const index = Number(key);
|
|
180
|
+
const p = Number(value);
|
|
181
|
+
if (!Number.isInteger(index) || index < 0 || index >= levels.length || !Number.isFinite(p) || p < 0) continue;
|
|
182
|
+
total += p;
|
|
183
|
+
expected += p * levels[index];
|
|
184
|
+
}
|
|
185
|
+
if (total > 0.5) return expected / total;
|
|
186
|
+
}
|
|
187
|
+
const position = Number(answer.score);
|
|
188
|
+
if (!Number.isFinite(position)) return null;
|
|
189
|
+
const at = Math.min(levels.length - 1, Math.max(0, position));
|
|
190
|
+
const low = Math.floor(at);
|
|
191
|
+
const high = Math.min(levels.length - 1, low + 1);
|
|
192
|
+
return levels[low] + (levels[high] - levels[low]) * (at - low);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Jev's answer → weights over the eligible providers, or null when it does not cover every one of them
|
|
197
|
+
* (the deterministic split is used then). An ineligible provider weighs 0 whatever was answered.
|
|
198
|
+
*/
|
|
199
|
+
export function jevWeights(judgment, eligible = {}) {
|
|
200
|
+
const scores = judgment?.scores;
|
|
201
|
+
if (!scores || typeof scores !== 'object') return null;
|
|
202
|
+
const out = Object.fromEntries(BUDGET_PROVIDERS.map((p) => [p, 0]));
|
|
203
|
+
for (const provider of BUDGET_PROVIDERS) {
|
|
204
|
+
if (eligible[provider]?.eligible === false) continue;
|
|
205
|
+
const share = shareFromScore(scores[provider]);
|
|
206
|
+
if (share === null) return null;
|
|
207
|
+
out[provider] = Math.max(0, share);
|
|
208
|
+
}
|
|
209
|
+
return out;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ── dividing ──────────────────────────────────────────────────────────────
|
|
213
|
+
|
|
214
|
+
/** `total` cents over `parts` (weights ≥ 0) by largest remainder: whole cents that add up exactly to `total`. */
|
|
215
|
+
export function apportion(total, parts) {
|
|
216
|
+
const keys = Object.keys(parts);
|
|
217
|
+
const out = Object.fromEntries(keys.map((key) => [key, 0]));
|
|
218
|
+
const sum = keys.reduce((acc, key) => acc + Math.max(0, num(parts[key])), 0);
|
|
219
|
+
if (!(total > 0) || !(sum > 0)) return out;
|
|
220
|
+
const rows = keys.map((key, index) => {
|
|
221
|
+
const exact = (total * Math.max(0, num(parts[key]))) / sum;
|
|
222
|
+
return { key, index, base: Math.floor(exact + 1e-9), rest: exact - Math.floor(exact + 1e-9) };
|
|
223
|
+
});
|
|
224
|
+
let given = rows.reduce((acc, row) => acc + row.base, 0);
|
|
225
|
+
for (const row of [...rows].sort((a, b) => b.rest - a.rest || a.index - b.index)) {
|
|
226
|
+
if (given >= total) break;
|
|
227
|
+
row.base += 1;
|
|
228
|
+
given += 1;
|
|
229
|
+
}
|
|
230
|
+
for (const row of rows) out[row.key] = row.base;
|
|
231
|
+
return out;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Divide what is left (`leftUsd`, rounded down to the cent) across the providers by `weights`, then raise the
|
|
236
|
+
* brain's reserve on its provider, taken from the others in proportion to what they got. Ineligible providers
|
|
237
|
+
* get nothing. → { allocCents: { [provider]: cents }, leftCents, brainFloorCents, floorsCents }
|
|
238
|
+
* Σ allocCents === leftCents, always.
|
|
239
|
+
*/
|
|
240
|
+
export function divideLeft({ leftUsd = 0, weights = {}, eligible = {}, brainProvider = null } = {}) {
|
|
241
|
+
const leftCents = floorCents(leftUsd);
|
|
242
|
+
const pool = BUDGET_PROVIDERS.filter((p) => eligible[p]?.eligible !== false);
|
|
243
|
+
const zero = Object.fromEntries(BUDGET_PROVIDERS.map((p) => [p, 0]));
|
|
244
|
+
if (!leftCents || !pool.length) return { allocCents: zero, leftCents, brainFloorCents: 0, floorsCents: { ...zero } };
|
|
245
|
+
const parts = Object.fromEntries(pool.map((p) => [p, Math.max(0, num(weights[p]))]));
|
|
246
|
+
if (pool.every((p) => !(parts[p] > 0))) {
|
|
247
|
+
// Nothing weighs anything: the brain's provider takes it (its turns must be paid), else equal shares.
|
|
248
|
+
if (brainProvider && pool.includes(brainProvider)) parts[brainProvider] = 1;
|
|
249
|
+
else for (const p of pool) parts[p] = 1;
|
|
250
|
+
}
|
|
251
|
+
const alloc = { ...zero, ...apportion(leftCents, parts) };
|
|
252
|
+
// Floors.
|
|
253
|
+
const brainFloorCents = brainProvider && pool.includes(brainProvider)
|
|
254
|
+
? Math.min(leftCents, Math.max(Math.round(BRAIN_FLOOR_RATIO * leftCents), Math.round(BRAIN_FLOOR_MIN_USD * 100)))
|
|
255
|
+
: 0;
|
|
256
|
+
const floors = { ...zero };
|
|
257
|
+
if (brainFloorCents) floors[brainProvider] = brainFloorCents;
|
|
258
|
+
const deficit = Object.fromEntries(BUDGET_PROVIDERS.map((p) => [p, Math.max(0, floors[p] - alloc[p])]));
|
|
259
|
+
const needed = BUDGET_PROVIDERS.reduce((acc, p) => acc + deficit[p], 0);
|
|
260
|
+
if (needed > 0) {
|
|
261
|
+
const surplus = Object.fromEntries(BUDGET_PROVIDERS.map((p) => [p, Math.max(0, alloc[p] - floors[p])]));
|
|
262
|
+
const taken = apportion(needed, surplus);
|
|
263
|
+
for (const p of BUDGET_PROVIDERS) alloc[p] = alloc[p] - (taken[p] || 0) + deficit[p];
|
|
264
|
+
}
|
|
265
|
+
return { allocCents: alloc, leftCents, brainFloorCents: floors[brainProvider] || 0, floorsCents: floors };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ── what a session can still spend ────────────────────────────────────────
|
|
269
|
+
|
|
270
|
+
/** spend.providers[p] → { brainUsd, runsUsd, spentUsd, liveRuns, runningRuns }, zeros for the missing. */
|
|
271
|
+
export function providerSpendOf(spend, provider) {
|
|
272
|
+
const row = spend?.providers?.[provider] || {};
|
|
273
|
+
const brainUsd = Math.max(0, num(row.brainUsd));
|
|
274
|
+
const runsUsd = Math.max(0, num(row.runsUsd));
|
|
275
|
+
return { brainUsd, runsUsd, spentUsd: r8(brainUsd + runsUsd), liveRuns: Math.max(0, num(row.liveRuns)), runningRuns: Math.max(0, num(row.runningRuns)) };
|
|
276
|
+
}
|
|
277
|
+
/** Every provider's spend added up. */
|
|
278
|
+
export function totalSpentOf(spend) { return r8(BUDGET_PROVIDERS.reduce((acc, p) => acc + providerSpendOf(spend, p).spentUsd, 0)); }
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* What a session with a budget can still spend, from its split and what was spent since.
|
|
282
|
+
* Without a split (none was made yet) every eligible provider may use everything that is left.
|
|
283
|
+
* leftUsd the session's: budget − everything spent (≥ 0)
|
|
284
|
+
* providers[p] { spentUsd, brainUsd, runsUsd, shareUsd, leftUsd, workerLeftUsd, liveRuns, runningRuns, eligible }
|
|
285
|
+
* leftUsd = share − spent; workerLeftUsd = that minus the brain's reserve still unspent
|
|
286
|
+
* (on the reserve's provider); both capped at the session's leftUsd
|
|
287
|
+
* brainProvider the provider the brain runs on now; brainLeftUsd what its turns may still spend
|
|
288
|
+
* brainReserveLeftUsd the reserve the brain has not used yet (workers on its provider cannot touch it)
|
|
289
|
+
*/
|
|
290
|
+
export function coverageOf({ amountUsd = 0, split = null, spend = null, brainProvider = null } = {}) {
|
|
291
|
+
const spent = totalSpentOf(spend);
|
|
292
|
+
const leftUsd = Math.max(0, r8(num(amountUsd) - spent));
|
|
293
|
+
const reserveProvider = split?.brainProvider || null;
|
|
294
|
+
const reserveSpent = reserveProvider ? providerSpendOf(spend, reserveProvider).brainUsd : 0;
|
|
295
|
+
const brainReserveLeftUsd = split && reserveProvider
|
|
296
|
+
? Math.max(0, r8(num(split.brainSpentAtSplitUsd) + num(split.brainFloorUsd) - reserveSpent))
|
|
297
|
+
: 0;
|
|
298
|
+
const providers = {};
|
|
299
|
+
for (const provider of BUDGET_PROVIDERS) {
|
|
300
|
+
const used = providerSpendOf(spend, provider);
|
|
301
|
+
const eligible = split ? split.eligible?.[provider]?.eligible !== false : true;
|
|
302
|
+
if (!split) {
|
|
303
|
+
providers[provider] = { ...used, shareUsd: null, leftUsd, workerLeftUsd: leftUsd, eligible };
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
const shareUsd = r8(num(split.shares?.[provider]));
|
|
307
|
+
const own = Math.max(0, r8(shareUsd - used.spentUsd));
|
|
308
|
+
const reserve = provider === reserveProvider ? Math.min(own, brainReserveLeftUsd) : 0;
|
|
309
|
+
providers[provider] = {
|
|
310
|
+
...used, shareUsd, eligible,
|
|
311
|
+
leftUsd: Math.min(leftUsd, own),
|
|
312
|
+
workerLeftUsd: Math.min(leftUsd, Math.max(0, r8(own - reserve))),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const current = isProvider(brainProvider) ? brainProvider : reserveProvider;
|
|
316
|
+
return {
|
|
317
|
+
amountUsd: num(amountUsd), spentUsd: spent, leftUsd, hasSplit: !!split, providers,
|
|
318
|
+
brainProvider: current || null, brainLeftUsd: current ? providers[current].leftUsd : leftUsd, brainReserveLeftUsd,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Can `provider` pay for more work now? `forBrain`: the Assistant's own turn (it may use its reserve); a
|
|
324
|
+
* worker may not. `free`: the work runs on a free model and needs no share (the session must still be under
|
|
325
|
+
* its budget).
|
|
326
|
+
*/
|
|
327
|
+
export function coversWork(coverage, { provider, forBrain = false, free = false, minUsd = MIN_SPEND_USD } = {}) {
|
|
328
|
+
if (!coverage) return true;
|
|
329
|
+
if (coverage.leftUsd < minUsd) return false;
|
|
330
|
+
if (free) return true;
|
|
331
|
+
const row = coverage.providers?.[provider];
|
|
332
|
+
if (!row) return false;
|
|
333
|
+
return (forBrain ? row.leftUsd : row.workerLeftUsd) >= minUsd;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/** The providers whose share is used up for workers (or ineligible), in BUDGET_PROVIDERS order. */
|
|
337
|
+
export function dryProviders(coverage, { minUsd = MIN_SPEND_USD } = {}) {
|
|
338
|
+
if (!coverage?.hasSplit) return coverage && coverage.leftUsd < minUsd ? [...BUDGET_PROVIDERS] : [];
|
|
339
|
+
return BUDGET_PROVIDERS.filter((p) => !coverage.providers[p] || coverage.providers[p].workerLeftUsd < minUsd);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ── the view (API, live packet, agent_usage) ──────────────────────────────
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* The session's budget as the UI and the brain see it.
|
|
346
|
+
* setting { unlimited, amountUsd, version }
|
|
347
|
+
* coverage coverageOf() (ignored under No limit)
|
|
348
|
+
* split the session's split record, or null
|
|
349
|
+
* spend what the session spent (by provider, brain and runs)
|
|
350
|
+
*/
|
|
351
|
+
export function budgetView({ sessionId = null, setting = null, coverage = null, split = null, spend = null, unpricedRuns = 0, brainProvider = null } = {}) {
|
|
352
|
+
const unlimited = !setting || setting.unlimited === true;
|
|
353
|
+
const spentUsd = totalSpentOf(spend);
|
|
354
|
+
const brainUsd = r8(BUDGET_PROVIDERS.reduce((acc, p) => acc + providerSpendOf(spend, p).brainUsd, 0));
|
|
355
|
+
const dispatchUsd = r8(spentUsd - brainUsd);
|
|
356
|
+
const base = {
|
|
357
|
+
sessionId, mode: unlimited ? 'unlimited' : 'limited', unlimited, version: Number(setting?.version) || 0,
|
|
358
|
+
amountUsd: unlimited ? null : roundUsd(setting.amountUsd),
|
|
359
|
+
spentUsd: roundUsd(spentUsd), brainUsd: roundUsd(brainUsd), dispatchUsd: roundUsd(dispatchUsd),
|
|
360
|
+
// Before rounding: whether money is left is decided on the exact numbers.
|
|
361
|
+
totalUsd: Number(spentUsd.toFixed(4)), unpricedRuns: Math.max(0, num(unpricedRuns)),
|
|
362
|
+
};
|
|
363
|
+
if (unlimited) {
|
|
364
|
+
// No limit: no shares, but each provider's spend is still shown.
|
|
365
|
+
const providers = BUDGET_PROVIDERS.map((provider) => {
|
|
366
|
+
const used = providerSpendOf(spend, provider);
|
|
367
|
+
return {
|
|
368
|
+
provider, label: PROVIDER_LABELS[provider], eligible: true, reason: null, isBrain: provider === brainProvider,
|
|
369
|
+
shareUsd: null, spentUsd: roundUsd(used.spentUsd), brainSpentUsd: roundUsd(used.brainUsd), runsSpentUsd: roundUsd(used.runsUsd),
|
|
370
|
+
leftUsd: null, workerLeftUsd: null, liveRuns: used.liveRuns, runningRuns: used.runningRuns, weight: null, judged: null,
|
|
371
|
+
};
|
|
372
|
+
});
|
|
373
|
+
return { ...base, leftUsd: null, warnAtUsd: null, warned: false, exceeded: false, split: null, brainProvider: brainProvider || null, providers, dry: [] };
|
|
374
|
+
}
|
|
375
|
+
const amount = num(setting.amountUsd);
|
|
376
|
+
const warnAtUsd = roundUsd(amount * BUDGET_WARN_RATIO);
|
|
377
|
+
const cov = coverage || coverageOf({ amountUsd: amount, split, spend, brainProvider });
|
|
378
|
+
const providers = BUDGET_PROVIDERS.map((provider) => {
|
|
379
|
+
const row = cov.providers[provider];
|
|
380
|
+
const judged = split?.jev?.scores?.[provider] || null;
|
|
381
|
+
return {
|
|
382
|
+
provider, label: PROVIDER_LABELS[provider],
|
|
383
|
+
eligible: row.eligible, reason: split?.eligible?.[provider]?.reason || null,
|
|
384
|
+
isBrain: provider === (cov.brainProvider || split?.brainProvider || null),
|
|
385
|
+
shareUsd: row.shareUsd === null ? null : roundUsd(row.shareUsd),
|
|
386
|
+
spentUsd: roundUsd(row.spentUsd), brainSpentUsd: roundUsd(row.brainUsd), runsSpentUsd: roundUsd(row.runsUsd),
|
|
387
|
+
leftUsd: roundUsd(row.leftUsd), workerLeftUsd: roundUsd(row.workerLeftUsd),
|
|
388
|
+
liveRuns: row.liveRuns, runningRuns: row.runningRuns,
|
|
389
|
+
weight: split ? Number(num(split.weights?.[provider]).toFixed(4)) : null,
|
|
390
|
+
judged: judged ? { score: Number(num(judged.score).toFixed(3)), confidence: Number(num(judged.confidence).toFixed(3)) } : null,
|
|
391
|
+
};
|
|
392
|
+
});
|
|
393
|
+
return {
|
|
394
|
+
...base,
|
|
395
|
+
leftUsd: roundUsd(cov.leftUsd), warnAtUsd, warned: spentUsd >= warnAtUsd, exceeded: spentUsd >= amount || cov.leftUsd < MIN_SPEND_USD,
|
|
396
|
+
brainProvider: cov.brainProvider || null,
|
|
397
|
+
split: split ? {
|
|
398
|
+
source: split.source, reason: split.reason || null, updatedAt: split.at || null, fallbackWhy: split.fallbackWhy || null,
|
|
399
|
+
leftAtSplitUsd: roundUsd(split.leftUsd), brainProvider: split.brainProvider || null,
|
|
400
|
+
brainFloorUsd: roundUsd(split.brainFloorUsd), brainReserveLeftUsd: roundUsd(cov.brainReserveLeftUsd),
|
|
401
|
+
needs: arr(split.needs), logId: split.jev?.logId ?? null,
|
|
402
|
+
providers,
|
|
403
|
+
} : null,
|
|
404
|
+
// Before the first split every provider shares what is left; `providers` still says what each spent.
|
|
405
|
+
providers,
|
|
406
|
+
dry: dryProviders(cov),
|
|
407
|
+
};
|
|
408
|
+
}
|