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,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SynaBun Assistant's budget split (surface budget-split) — the questions,
|
|
3
|
+
* not the transport.
|
|
4
|
+
*
|
|
5
|
+
* A session has one dollar budget for the assistant's own turns and every
|
|
6
|
+
* worker run. What is left is divided across the providers (Claude Code,
|
|
7
|
+
* Codex, OpenCode) so each provider's runs draw from a share. Jev cannot
|
|
8
|
+
* answer an amount, so each provider gets one Score question over the same
|
|
9
|
+
* state: how much of the spend still to come will land on it. The questions
|
|
10
|
+
* cannot see each other's answers; the caller (neural-interface
|
|
11
|
+
* lib/assistant-budget-split.js) turns the scores into weights, normalises
|
|
12
|
+
* them, applies the brain's reserve, rounds to cents and makes the shares add
|
|
13
|
+
* up to exactly what is left.
|
|
14
|
+
*
|
|
15
|
+
* Jev only divides money the user already allowed: the total, what was spent
|
|
16
|
+
* and what is left are facts in the state, never something it sets. It never
|
|
17
|
+
* picks a model for a task: the questions are about providers' shares of the
|
|
18
|
+
* spend, and routing stays with the brain and the router.
|
|
19
|
+
*
|
|
20
|
+
* Keep the wording of the instructions and levels stable: changing it
|
|
21
|
+
* invalidates the cache and moves the numbers the split was tuned on (the
|
|
22
|
+
* caller's SHARE_LEVEL_FRACTIONS map these five levels). Returns null
|
|
23
|
+
* whenever no judgment is available, including an answer missing for any
|
|
24
|
+
* provider asked; the caller then uses its deterministic split.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { judge, score, readScore, type Answer } from './typesafe.js';
|
|
28
|
+
import { redactCredentials } from './typesafe-config.js';
|
|
29
|
+
import type { JudgeContext } from './memory-judgments.js';
|
|
30
|
+
|
|
31
|
+
export const BUDGET_PROVIDERS = ['claude-code', 'codex', 'opencode'] as const;
|
|
32
|
+
export type BudgetProvider = typeof BUDGET_PROVIDERS[number];
|
|
33
|
+
const NAMES: Record<BudgetProvider, string> = { 'claude-code': 'Claude Code', codex: 'Codex', opencode: 'OpenCode' };
|
|
34
|
+
/** Question ids (code only; never sent as meaning). */
|
|
35
|
+
const QUESTION_IDS: Record<BudgetProvider, string> = { 'claude-code': 'share_claude_code', codex: 'share_codex', opencode: 'share_opencode' };
|
|
36
|
+
|
|
37
|
+
/** The ordered levels of every provider's question, lowest first. */
|
|
38
|
+
export const SHARE_LEVELS = [
|
|
39
|
+
'None of it: no remaining work is likely to run on this provider, or it cannot run anything now.',
|
|
40
|
+
'A small part: an occasional task, such as one review or a side task, or only cheap work.',
|
|
41
|
+
'A moderate part: a regular share of the remaining tasks, alongside the other providers.',
|
|
42
|
+
'A large part: most of the expensive remaining work, such as the main coding tasks.',
|
|
43
|
+
'Nearly all of it: practically every remaining dollar is spent on this provider.',
|
|
44
|
+
] as const;
|
|
45
|
+
|
|
46
|
+
export interface BudgetSplitModel { id?: string | null; price?: string | null; billing?: string | null; tier?: string | null }
|
|
47
|
+
export interface BudgetSplitProvider {
|
|
48
|
+
eligible?: boolean; why?: string | null;
|
|
49
|
+
spentUsd?: number; brainUsd?: number; runsUsd?: number; shareUsd?: number | null; leftUsd?: number | null;
|
|
50
|
+
liveRuns?: number; runningRuns?: number; recentUsd?: number | null;
|
|
51
|
+
account?: { mode?: string | null; usageLeftPercent?: number | null; limited?: boolean | null } | null;
|
|
52
|
+
models?: BudgetSplitModel[];
|
|
53
|
+
}
|
|
54
|
+
export interface BudgetSplitTask { taskClass?: string | null; summary?: string | null; provider?: string | null; model?: string | null }
|
|
55
|
+
export interface BudgetSplitInput {
|
|
56
|
+
/** The providers to ask about (eligible ones); the rest get no share. */
|
|
57
|
+
ask: string[];
|
|
58
|
+
budget: { amountUsd: number; spentUsd: number; leftUsd: number; warnAtUsd?: number | null };
|
|
59
|
+
checkpoint?: { reason?: string | null; needs?: string[] } | null;
|
|
60
|
+
brain?: { provider?: string | null; model?: string | null; price?: string | null; billing?: string | null } | null;
|
|
61
|
+
routeMode?: string | null;
|
|
62
|
+
savedRoutes?: Array<{ taskClass?: string | null; provider?: string | null; model?: string | null; effort?: string | null; price?: string | null; billing?: string | null }>;
|
|
63
|
+
providers?: Partial<Record<string, BudgetSplitProvider>>;
|
|
64
|
+
tasks?: BudgetSplitTask[];
|
|
65
|
+
task?: BudgetSplitTask | null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface BudgetShareScore { score: number; confidence: number; probabilities: Record<string, number> | null }
|
|
69
|
+
export interface BudgetSplitJudgment { scores: Partial<Record<BudgetProvider, BudgetShareScore>> }
|
|
70
|
+
|
|
71
|
+
// State budgets (characters, items).
|
|
72
|
+
const SUMMARY_CLIP = 200;
|
|
73
|
+
const MAX_TASKS = 12;
|
|
74
|
+
const MAX_ROUTES = 16;
|
|
75
|
+
const MAX_MODELS = 4;
|
|
76
|
+
|
|
77
|
+
const text = (value: unknown) => (typeof value === 'string' ? value : value === null || value === undefined ? '' : String(value));
|
|
78
|
+
/** Credentials out first, then the cut: a secret split by a cut would slip past the patterns. */
|
|
79
|
+
const safe = (value: unknown, max: number) => {
|
|
80
|
+
const clean = redactCredentials(text(value));
|
|
81
|
+
return clean.length > max ? `${clean.slice(0, max - 1)}…` : clean;
|
|
82
|
+
};
|
|
83
|
+
const usd = (value: unknown) => (Number.isFinite(Number(value)) ? Math.round(Number(value) * 100) / 100 : null);
|
|
84
|
+
const isProvider = (value: unknown): value is BudgetProvider => typeof value === 'string' && (BUDGET_PROVIDERS as readonly string[]).includes(value);
|
|
85
|
+
const label = (value: unknown) => (isProvider(value) ? value : value ? safe(value, 40) : null);
|
|
86
|
+
|
|
87
|
+
function taskRow(row: BudgetSplitTask | null | undefined) {
|
|
88
|
+
if (!row || typeof row !== 'object') return null;
|
|
89
|
+
return { task_class: row.taskClass ? safe(row.taskClass, 20) : null, summary: row.summary ? safe(row.summary, SUMMARY_CLIP) : null, provider: label(row.provider), model: row.model ? safe(row.model, 80) : null };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** The state every provider's question reads, bounded and redacted. Amounts in US dollars. */
|
|
93
|
+
export function budgetSplitState(input: BudgetSplitInput): Record<string, unknown> {
|
|
94
|
+
const budget = input.budget || { amountUsd: 0, spentUsd: 0, leftUsd: 0 };
|
|
95
|
+
const providers: Record<string, unknown> = {};
|
|
96
|
+
for (const provider of BUDGET_PROVIDERS) {
|
|
97
|
+
const row = input.providers?.[provider];
|
|
98
|
+
if (!row) continue;
|
|
99
|
+
providers[provider] = {
|
|
100
|
+
name: NAMES[provider],
|
|
101
|
+
can_run: row.eligible !== false,
|
|
102
|
+
why_not: row.eligible === false && row.why ? safe(row.why, 40) : null,
|
|
103
|
+
spent_usd: usd(row.spentUsd) ?? 0,
|
|
104
|
+
spent_by_assistant_usd: usd(row.brainUsd) ?? 0,
|
|
105
|
+
spent_by_workers_usd: usd(row.runsUsd) ?? 0,
|
|
106
|
+
current_share_usd: usd(row.shareUsd),
|
|
107
|
+
current_share_left_usd: usd(row.leftUsd),
|
|
108
|
+
runs_live: Math.max(0, Math.floor(Number(row.liveRuns) || 0)),
|
|
109
|
+
runs_working_now: Math.max(0, Math.floor(Number(row.runningRuns) || 0)),
|
|
110
|
+
recent_spend_usd: usd(row.recentUsd),
|
|
111
|
+
account: row.account ? {
|
|
112
|
+
billing: row.account.mode ? safe(row.account.mode, 20) : null,
|
|
113
|
+
usage_left_percent: Number.isFinite(Number(row.account.usageLeftPercent)) ? Math.round(Number(row.account.usageLeftPercent)) : null,
|
|
114
|
+
limited: typeof row.account.limited === 'boolean' ? row.account.limited : null,
|
|
115
|
+
} : null,
|
|
116
|
+
models_routed_here: (Array.isArray(row.models) ? row.models : []).slice(0, MAX_MODELS).map((m) => ({
|
|
117
|
+
model: m?.id ? safe(m.id, 80) : null, list_price_per_mtok: m?.price ? safe(m.price, 40) : null, billing: m?.billing ? safe(m.billing, 20) : null, tier: m?.tier ? safe(m.tier, 10) : null,
|
|
118
|
+
})),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
session_budget: {
|
|
123
|
+
total_usd: usd(budget.amountUsd) ?? 0,
|
|
124
|
+
spent_usd: usd(budget.spentUsd) ?? 0,
|
|
125
|
+
left_usd: usd(budget.leftUsd) ?? 0,
|
|
126
|
+
warning_at_usd: usd(budget.warnAtUsd),
|
|
127
|
+
note: 'Spend is counted at list price for every provider, subscription work included. The budget pays for the assistant\'s own turns and every worker run.',
|
|
128
|
+
},
|
|
129
|
+
checkpoint: {
|
|
130
|
+
reason: input.checkpoint?.reason ? safe(input.checkpoint.reason, 40) : null,
|
|
131
|
+
providers_short_of_money: (Array.isArray(input.checkpoint?.needs) ? input.checkpoint!.needs : []).filter(isProvider),
|
|
132
|
+
},
|
|
133
|
+
assistant: input.brain ? {
|
|
134
|
+
runs_on: label(input.brain.provider), model: input.brain.model ? safe(input.brain.model, 80) : null,
|
|
135
|
+
list_price_per_mtok: input.brain.price ? safe(input.brain.price, 40) : null, billing: input.brain.billing ? safe(input.brain.billing, 20) : null,
|
|
136
|
+
} : null,
|
|
137
|
+
route_mode: input.routeMode ? safe(input.routeMode, 20) : null,
|
|
138
|
+
saved_routes: (Array.isArray(input.savedRoutes) ? input.savedRoutes : []).slice(0, MAX_ROUTES).map((r) => ({
|
|
139
|
+
task_class: r?.taskClass ? safe(r.taskClass, 20) : null, provider: label(r?.provider), model: r?.model ? safe(r.model, 80) : null,
|
|
140
|
+
list_price_per_mtok: r?.price ? safe(r.price, 40) : null, billing: r?.billing ? safe(r.billing, 20) : null,
|
|
141
|
+
})),
|
|
142
|
+
providers,
|
|
143
|
+
session_tasks_so_far: (Array.isArray(input.tasks) ? input.tasks : []).slice(-MAX_TASKS).map(taskRow).filter(Boolean),
|
|
144
|
+
task_being_routed_now: taskRow(input.task),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const shareQuestion = (provider: BudgetProvider) => score(
|
|
149
|
+
'An AI assistant session has a dollar budget (`session_budget`). It pays for the assistant\'s own turns (the assistant runs on `assistant.runs_on`) ' +
|
|
150
|
+
'and for worker runs on three providers (`providers`). `saved_routes` say which provider each kind of task is sent to, `session_tasks_so_far` are the tasks routed so far, ' +
|
|
151
|
+
'`task_being_routed_now` is the task being routed at this moment, and `checkpoint` says why the budget is being divided again. ' +
|
|
152
|
+
`Of the money still to be spent in this session (\`session_budget.left_usd\`), how much will go to work on ${NAMES[provider]} (\`providers.${provider}\`): its worker runs, ` +
|
|
153
|
+
`plus the assistant's own turns when \`assistant.runs_on\` is ${provider}? Judge from the tasks likely to come next, where the saved routes send them, the runs still working, and what the models cost.`,
|
|
154
|
+
[...SHARE_LEVELS],
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
function probabilitiesOf(answer: Answer | undefined): Record<string, number> | null {
|
|
158
|
+
if (answer?.type !== 'score' || !answer.probabilities || typeof answer.probabilities !== 'object') return null;
|
|
159
|
+
const out: Record<string, number> = {};
|
|
160
|
+
for (const [key, value] of Object.entries(answer.probabilities)) if (Number.isFinite(Number(value))) out[key] = Number(value);
|
|
161
|
+
return Object.keys(out).length ? out : null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* One request: a Score for each provider in `input.ask`. All or nothing: a
|
|
166
|
+
* missing or wrong-typed answer for any provider asked is no judgment (null).
|
|
167
|
+
*/
|
|
168
|
+
export async function judgeBudgetSplit(input: BudgetSplitInput, options: JudgeContext = {}): Promise<BudgetSplitJudgment | null> {
|
|
169
|
+
const ask = [...new Set((Array.isArray(input?.ask) ? input.ask : []).filter(isProvider))];
|
|
170
|
+
if (!ask.length) return null;
|
|
171
|
+
const questions: Record<string, ReturnType<typeof score>> = {};
|
|
172
|
+
for (const provider of ask) questions[QUESTION_IDS[provider]] = shareQuestion(provider);
|
|
173
|
+
const answers = await judge(budgetSplitState(input), questions, { ...options, surface: 'budget-split' });
|
|
174
|
+
if (!answers) return null;
|
|
175
|
+
const scores: BudgetSplitJudgment['scores'] = {};
|
|
176
|
+
for (const provider of ask) {
|
|
177
|
+
const answer = answers[QUESTION_IDS[provider]];
|
|
178
|
+
const read = readScore(answer);
|
|
179
|
+
if (!read) return null;
|
|
180
|
+
scores[provider] = { score: read.score, confidence: read.confidence, probabilities: probabilitiesOf(answer) };
|
|
181
|
+
}
|
|
182
|
+
return { scores };
|
|
183
|
+
}
|
|
@@ -166,39 +166,12 @@ function saveCategoriesToDisk(categories: CustomCategory[]): void {
|
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
/**
|
|
170
|
-
* Built-in categories that must always exist (created if missing on startup).
|
|
171
|
-
* youtube-videos is the trailer dedup ledger that youtube_upload writes and
|
|
172
|
-
* youtube_source reads — pre-seeding it means manual remember / the UI / routing
|
|
173
|
-
* all see it, not just the validation-bypassing auto-record path.
|
|
174
|
-
*/
|
|
175
|
-
const BUILTIN_CATEGORIES: Array<{ name: string; description: string; parent?: string }> = [
|
|
176
|
-
{
|
|
177
|
-
name: 'youtube-videos',
|
|
178
|
-
description: 'One memory per uploaded YouTube trailer — the dedup ledger. Written automatically by youtube_upload; tagged with canonical source ids (igdb:/appid:/ytid:/name:) that youtube_source reads to skip already-posted trailers. Do not store anything else here.',
|
|
179
|
-
parent: 'social',
|
|
180
|
-
},
|
|
181
|
-
];
|
|
182
|
-
|
|
183
|
-
/** Append any missing built-in categories and persist. Idempotent. */
|
|
184
|
-
function ensureBuiltinCategories(): void {
|
|
185
|
-
const cats = loadCategoriesFromDisk();
|
|
186
|
-
const have = new Set(cats.map((c) => c.name));
|
|
187
|
-
let changed = false;
|
|
188
|
-
for (const b of BUILTIN_CATEGORIES) {
|
|
189
|
-
if (have.has(b.name)) continue;
|
|
190
|
-
const cat: CustomCategory = { name: b.name, description: b.description, created_at: new Date().toISOString() };
|
|
191
|
-
if (b.parent && have.has(b.parent)) cat.parent = b.parent; // only attach the parent if it exists
|
|
192
|
-
cats.push(cat);
|
|
193
|
-
changed = true;
|
|
194
|
-
}
|
|
195
|
-
if (changed) saveCategoriesToDisk(cats);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
169
|
/**
|
|
199
170
|
* Initialize the local category cache for the active connection.
|
|
200
|
-
* Seeds the cache file from SQLite (source of truth) or empty
|
|
201
|
-
*
|
|
171
|
+
* Seeds the cache file from SQLite (source of truth), or empty when the DB has none.
|
|
172
|
+
* No category is created here: a fresh install has none. A project's defaults are
|
|
173
|
+
* made when the project is added, a feature's category the first time it saves
|
|
174
|
+
* (ensureCategory / ensureFeatureCategory).
|
|
202
175
|
*/
|
|
203
176
|
export async function initCategoryCache(): Promise<void> {
|
|
204
177
|
const filePath = getCategoriesPath();
|
|
@@ -214,10 +187,82 @@ export async function initCategoryCache(): Promise<void> {
|
|
|
214
187
|
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');
|
|
215
188
|
}
|
|
216
189
|
|
|
217
|
-
ensureBuiltinCategories();
|
|
218
190
|
invalidateCategoryCache();
|
|
219
191
|
}
|
|
220
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Categories that features save into by name. None exists on a fresh install:
|
|
195
|
+
* each is created the first time something is stored in it (ensureFeatureCategory),
|
|
196
|
+
* whether the writer is SynaBun itself or a model told to use that name by a hook.
|
|
197
|
+
* Keep the descriptions in step with hooks/claude-code/shared.mjs FEATURE_CATEGORIES.
|
|
198
|
+
*/
|
|
199
|
+
export const FEATURE_CATEGORIES: Record<string, { description: string; is_parent?: boolean }> = {
|
|
200
|
+
conversations: {
|
|
201
|
+
description: 'Indexed conversation sessions with compacted summaries for cross-session recall: session metadata (date, branch, session id) and topic summaries, so past conversations can be found by asking for them.',
|
|
202
|
+
},
|
|
203
|
+
'communication-style': {
|
|
204
|
+
description: 'How the user communicates and works: patterns in how they give instructions, correct, decide and signal frustration, and their stated preferences.',
|
|
205
|
+
},
|
|
206
|
+
plans: {
|
|
207
|
+
description: 'Implementation plans stored after plan mode approval, one child category per project.',
|
|
208
|
+
is_parent: true,
|
|
209
|
+
},
|
|
210
|
+
uncategorized: {
|
|
211
|
+
description: 'Fallback for memories stored without a category.',
|
|
212
|
+
},
|
|
213
|
+
ideas: {
|
|
214
|
+
description: 'Brainstormed features, experiments, and creative explorations (the /synabun idea skill).',
|
|
215
|
+
},
|
|
216
|
+
schedules: {
|
|
217
|
+
description: 'One memory per schedule created from a conversation (the /synabun schedule skill): name, template, schedule id, cron, group, profile and model.',
|
|
218
|
+
},
|
|
219
|
+
'youtube-videos': {
|
|
220
|
+
description: 'One memory per uploaded YouTube trailer — the dedup ledger. Written automatically by youtube_upload; tagged with canonical source ids (igdb:/appid:/ytid:/name:) that youtube_source reads to skip already-posted trailers. Do not store anything else here.',
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Create a category the first time something saves into it. Idempotent: an existing
|
|
226
|
+
* category is left exactly as it is. The parent is attached only when it already
|
|
227
|
+
* exists. Returns true when the category exists afterwards.
|
|
228
|
+
*/
|
|
229
|
+
export function ensureCategory(name: string, description: string, options: { parent?: string; is_parent?: boolean } = {}): boolean {
|
|
230
|
+
try {
|
|
231
|
+
if (categoryExists(name)) return true;
|
|
232
|
+
const parent = options.parent && categoryExists(options.parent) ? options.parent : undefined;
|
|
233
|
+
addCategory(name, description, parent, undefined, options.is_parent && !parent);
|
|
234
|
+
return true;
|
|
235
|
+
} catch (err) {
|
|
236
|
+
console.error(`Failed to create category "${name}":`, err instanceof Error ? err.message : err);
|
|
237
|
+
return categoryExists(name);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* ensureCategory for a name of FEATURE_CATEGORIES, or a project's plan category
|
|
243
|
+
* `plans-<project>` (made under "plans", as hooks/claude-code/post-plan.mjs does);
|
|
244
|
+
* false for any other name.
|
|
245
|
+
*/
|
|
246
|
+
export function ensureFeatureCategory(name: string): boolean {
|
|
247
|
+
const feature = Object.prototype.hasOwnProperty.call(FEATURE_CATEGORIES, name) ? FEATURE_CATEGORIES[name] : null;
|
|
248
|
+
if (feature) return ensureCategory(name, feature.description, { is_parent: feature.is_parent });
|
|
249
|
+
if (/^plans-[a-z0-9][a-z0-9-]*$/.test(name) && name.length <= MAX_LENGTH && ensureFeatureCategory('plans')) {
|
|
250
|
+
return ensureCategory(name, `Implementation plans for ${name.slice('plans-'.length)} project`, { parent: 'plans' });
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* The name of a project's default parent category, as the project's defaults
|
|
257
|
+
* are created (hooks/claude-code/shared.mjs projectCategoryLabel): the label
|
|
258
|
+
* normalized and cut to 16 characters, so `<label>-architecture` stays within 30.
|
|
259
|
+
*/
|
|
260
|
+
export function projectCategoryLabel(project: string): string {
|
|
261
|
+
let label = String(project || '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
|
|
262
|
+
if (label.length > 16) label = label.slice(0, 16).replace(/-$/, '');
|
|
263
|
+
return label || 'global';
|
|
264
|
+
}
|
|
265
|
+
|
|
221
266
|
/**
|
|
222
267
|
* Call after a connection switch to re-point the file watcher
|
|
223
268
|
* at the new connection's category file and sync from database if needed.
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
* Having both forms defines the same TOML key twice, so Codex rejects the
|
|
8
8
|
* configuration and starts with defaults.
|
|
9
9
|
*
|
|
10
|
-
* This module
|
|
11
|
-
*
|
|
10
|
+
* This module edits the SynaBun MCP tables and the known ignored feature keys
|
|
11
|
+
* emitted by its old Settings writer. All unrelated configuration is left
|
|
12
|
+
* byte-for-byte intact. Repairs keep a backup; file writes are atomic,
|
|
12
13
|
* preserve the original mode, and are idempotent.
|
|
13
14
|
*/
|
|
14
15
|
import {
|
|
@@ -56,6 +57,7 @@ export interface CodexMcpDefinition {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
export type HealReason =
|
|
60
|
+
| 'removed_ignored_settings'
|
|
59
61
|
| 'removed_duplicate_inline_env'
|
|
60
62
|
| 'normalized_inline_env'
|
|
61
63
|
| 'removed_managed_profile_override'
|
|
@@ -364,15 +366,20 @@ export function healCodexConfig(configPath: string): HealResult {
|
|
|
364
366
|
}
|
|
365
367
|
|
|
366
368
|
const before = inspectCodexConfigContent(content);
|
|
367
|
-
|
|
369
|
+
const cleaned = removeIgnoredCodexSettings(content);
|
|
370
|
+
if (cleaned === content && !before.connected && !before.issues.length) {
|
|
368
371
|
return { healed: false, reason: 'no_synabun_section' };
|
|
369
372
|
}
|
|
370
|
-
const repaired = repairCodexConfigContent(
|
|
373
|
+
const repaired = repairCodexConfigContent(cleaned);
|
|
374
|
+
if (cleaned !== content) repaired.reason = 'removed_ignored_settings';
|
|
371
375
|
if (!repaired.reason || repaired.content === content) {
|
|
372
376
|
return { healed: false, reason: 'no_duplicate', inspection: before };
|
|
373
377
|
}
|
|
374
378
|
|
|
375
379
|
try {
|
|
380
|
+
// Keep the exact original, including unrelated tables and its permissions.
|
|
381
|
+
const backup = `${configPath}.synabun-backup-${Date.now()}-${process.pid}`;
|
|
382
|
+
copyFileSync(configPath, backup);
|
|
376
383
|
atomicWrite(configPath, repaired.content);
|
|
377
384
|
} catch (err) {
|
|
378
385
|
return { healed: false, reason: 'write_error', error: err instanceof Error ? err.message : String(err) };
|
|
@@ -384,6 +391,30 @@ export function healCodexConfig(configPath: string): HealResult {
|
|
|
384
391
|
};
|
|
385
392
|
}
|
|
386
393
|
|
|
394
|
+
/** Narrow repair for keys emitted by the old Settings writer. These literal
|
|
395
|
+
* dotted keys are ignored by Codex; personality's feature flag is removed.
|
|
396
|
+
* Do not sweep arbitrary user flags or normalize unrelated TOML. */
|
|
397
|
+
export function removeIgnoredCodexSettings(content: string): string {
|
|
398
|
+
let section = '';
|
|
399
|
+
let multiline: string | null = null;
|
|
400
|
+
return content.split(/(?<=\n)/).filter(line => {
|
|
401
|
+
// Avoid treating text inside TOML multiline strings as configuration.
|
|
402
|
+
const delimiters = line.match(/"""|'''/g) || [];
|
|
403
|
+
if (multiline) {
|
|
404
|
+
if (delimiters.filter(d => d === multiline).length % 2) multiline = null;
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
for (const delimiter of delimiters) if (delimiters.filter(d => d === delimiter).length % 2) multiline = delimiter;
|
|
408
|
+
const header = /^\s*\[([^\]]+)\]\s*(?:#.*)?$/.exec(line.trim());
|
|
409
|
+
if (header) section = header[1].replace(/["']/g, '').trim();
|
|
410
|
+
else if (/^\s*\[/.test(line)) section = '__other_table__';
|
|
411
|
+
if (!section && /^\s*["']features\.(?:personality|fast_mode|apps|unified_exec)["']\s*=\s*(?:true|false)\s*(?:#.*)?$/.test(line.trim())) return false;
|
|
412
|
+
if ((!section && /^\s*features\.personality\s*=\s*(?:true|false)\s*(?:#.*)?$/.test(line.trim()))
|
|
413
|
+
|| (section === 'features' && /^\s*(?:personality|"personality"|'personality')\s*=\s*(?:true|false)\s*(?:#.*)?$/.test(line.trim()))) return false;
|
|
414
|
+
return true;
|
|
415
|
+
}).join('');
|
|
416
|
+
}
|
|
417
|
+
|
|
387
418
|
export function upsertCodexMcpConfig(configPath: string, definition: CodexMcpDefinition): CodexConfigInspection {
|
|
388
419
|
let content = '';
|
|
389
420
|
if (existsSync(configPath)) content = readFileSync(configPath, 'utf-8');
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { readdirSync, readFileSync } from 'node:fs';
|
|
17
17
|
import path from 'node:path';
|
|
18
18
|
import { performance } from 'node:perf_hooks';
|
|
19
|
-
import { z } from 'zod';
|
|
19
|
+
import { z } from 'zod/v3';
|
|
20
20
|
import type { JudgeUsage } from './typesafe.js';
|
|
21
21
|
import { typesafeConfig, mutateTypeSafeConfig, type TypeSafeConfig } from './typesafe-config.js';
|
|
22
22
|
import { hashCorpusFiles, isPinnedModel } from './browser-assist-gate.js';
|
|
@@ -173,6 +173,33 @@ export function callerDesktopGrant(): string | null {
|
|
|
173
173
|
return sanitizeDesktopGrant(process.env.SYNABUN_DESKTOP_GRANT);
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
/** WhatsApp brain credentials look exactly like the ones the Neural Interface mints (assistant-runtime.js mintBrainCredential). */
|
|
177
|
+
export function sanitizeBrainCredential(v: string | undefined | null): string | null {
|
|
178
|
+
return typeof v === 'string' && /^sbb_[A-Za-z0-9_-]{43}$/.test(v.trim()) ? v.trim() : null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// The brain credential of the request being handled (whatsapp_send_file). Its own context per HTTP
|
|
182
|
+
// request, never a field of the CallerIdentity: identities are shared by every request that names the
|
|
183
|
+
// same X-Synabun-Terminal pin (not a secret), so a credential kept there could be read by a concurrent
|
|
184
|
+
// request that only forged the pin.
|
|
185
|
+
const credentialAls = new AsyncLocalStorage<string | null>();
|
|
186
|
+
|
|
187
|
+
/** Run `fn` with this request's brain credential (http.ts, around every transport.handleRequest). */
|
|
188
|
+
export function runWithBrainCredential<T>(credential: string | null, fn: () => T): T {
|
|
189
|
+
return credentialAls.run(credential, fn);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* The WhatsApp brain credential of the current caller (whatsapp_send_file sends it on its one request
|
|
194
|
+
* and nowhere else): the request's own header over HTTP (X-Synabun-Brain-Token, the Claude brain),
|
|
195
|
+
* SYNABUN_BRAIN_TOKEN for stdio children (the Codex and OpenCode brains). Never the host process's
|
|
196
|
+
* env for an HTTP caller.
|
|
197
|
+
*/
|
|
198
|
+
export function callerBrainCredential(): string | null {
|
|
199
|
+
if (httpMode) return credentialAls.getStore() ?? null;
|
|
200
|
+
return sanitizeBrainCredential(process.env.SYNABUN_BRAIN_TOKEN);
|
|
201
|
+
}
|
|
202
|
+
|
|
176
203
|
/**
|
|
177
204
|
* Role of the current caller: the ALS identity's role over HTTP (derived from
|
|
178
205
|
* X-Synabun-Role on every request), or SYNABUN_ROLE for stdio children —
|
|
@@ -132,7 +132,8 @@ async function requestOnce(
|
|
|
132
132
|
method: string,
|
|
133
133
|
path: string,
|
|
134
134
|
body?: Record<string, unknown>,
|
|
135
|
-
timeout = DEFAULT_TIMEOUT
|
|
135
|
+
timeout = DEFAULT_TIMEOUT,
|
|
136
|
+
extraHeaders: Record<string, string> = {},
|
|
136
137
|
): Promise<NiResponse> {
|
|
137
138
|
const cancellation = browserCancellation.getStore();
|
|
138
139
|
const callerSignal = cancellation?.signal;
|
|
@@ -166,6 +167,8 @@ async function requestOnce(
|
|
|
166
167
|
headers['X-Synabun-Deadline'] = String(deadline);
|
|
167
168
|
// Lets the server refuse advisory payloads and auto-heal for a batch step on its own authority.
|
|
168
169
|
if (batchContext.getStore()) headers['X-Synabun-Batch'] = '1';
|
|
170
|
+
// One request's own headers (whatsappSendFile's brain credential): never sent on any other request.
|
|
171
|
+
for (const [name, value] of Object.entries(extraHeaders)) if (value) headers[name] = value;
|
|
169
172
|
const opts: RequestInit = {
|
|
170
173
|
method,
|
|
171
174
|
headers,
|
|
@@ -199,7 +202,9 @@ async function requestOnce(
|
|
|
199
202
|
if (controller.signal.aborted || /abort/i.test(msg)) {
|
|
200
203
|
return { error: `Request timed out after ${timeout}ms; outcome may be uncertain. Inspect the page before retrying.`, code: 'REQUEST_TIMEOUT', outcome: 'uncertain' };
|
|
201
204
|
}
|
|
202
|
-
|
|
205
|
+
// The system's own code for it (fetch puts it on `cause`): ECONNREFUSED means the request never left.
|
|
206
|
+
const cause = (err as { cause?: { code?: unknown }; code?: unknown } | null)?.cause?.code ?? (err as { code?: unknown } | null)?.code ?? /\b(E[A-Z_]{3,})\b/.exec(msg)?.[1];
|
|
207
|
+
return { error: `Neural Interface unreachable: ${msg}. Is the Neural Interface server running?`, code: 'TRANSPORT_ERROR', outcome: 'uncertain', ...(typeof cause === 'string' ? { transportCode: cause } : {}) };
|
|
203
208
|
} finally {
|
|
204
209
|
clearTimeout(timer);
|
|
205
210
|
callerSignal?.removeEventListener('abort', cancel);
|
|
@@ -1486,3 +1491,30 @@ export async function assistantKillAll(body: { assistantSessionId?: string; work
|
|
|
1486
1491
|
export async function assistantFocus(runId: string, focus: boolean): Promise<NiResponse> {
|
|
1487
1492
|
return request('POST', assistantRunPath(runId, '/focus'), { focus });
|
|
1488
1493
|
}
|
|
1494
|
+
|
|
1495
|
+
// whatsapp_send_file: the server's own deadline for the send is 120 s (lib/whatsapp/manager.js); this
|
|
1496
|
+
// one outlives it so a server timeout is reported as the server's.
|
|
1497
|
+
const WHATSAPP_SEND_FILE_TIMEOUT = 130_000;
|
|
1498
|
+
export const WHATSAPP_SEND_FILE_UNCERTAIN = 'SynaBun did not answer in time: the file may or may not have arrived. Do not send it again unless the user asks.';
|
|
1499
|
+
export const WHATSAPP_SEND_FILE_LOST = 'SynaBun\'s answer was lost: the file may or may not have arrived. Do not send it again unless the user asks.';
|
|
1500
|
+
// The request never reached SynaBun (nothing listens, no route to it): nothing was sent, for certain.
|
|
1501
|
+
const WHATSAPP_SEND_FILE_NEVER_LEFT = new Set(['ECONNREFUSED', 'ENOTFOUND', 'EAI_AGAIN', 'EHOSTUNREACH', 'ENETUNREACH', 'EADDRNOTAVAIL']);
|
|
1502
|
+
|
|
1503
|
+
/**
|
|
1504
|
+
* whatsapp_send_file → POST /api/assistant/whatsapp/send-file: exactly one request (requestOnce, no
|
|
1505
|
+
* retry of any kind), because a timeout may come after WhatsApp took the file. `credential` (the
|
|
1506
|
+
* WhatsApp brain's own, identity.ts callerBrainCredential) rides on this request alone; without it
|
|
1507
|
+
* the server refuses (403).
|
|
1508
|
+
*/
|
|
1509
|
+
export async function whatsappSendFile(body: { path: string; caption?: string; as?: string }, credential: string | null): Promise<NiResponse> {
|
|
1510
|
+
const result = await requestOnce('POST', '/api/assistant/whatsapp/send-file', body as Record<string, unknown>, WHATSAPP_SEND_FILE_TIMEOUT,
|
|
1511
|
+
credential ? { 'X-Synabun-Brain-Token': credential } : {});
|
|
1512
|
+
if (result.code === 'REQUEST_TIMEOUT') return { ok: false, code: 'TIMEOUT', uncertain: true, error: WHATSAPP_SEND_FILE_UNCERTAIN };
|
|
1513
|
+
// Any other failure of the transport after the request left (a reset socket, an answer that is not JSON) may
|
|
1514
|
+
// come after WhatsApp took the file: as uncertain as a timeout, never "is the server running?".
|
|
1515
|
+
if (result.code === 'TRANSPORT_ERROR') {
|
|
1516
|
+
if (WHATSAPP_SEND_FILE_NEVER_LEFT.has(String(result.transportCode))) return { ok: false, code: 'UNREACHABLE', error: 'SynaBun is not reachable (is it running?): nothing was sent.' };
|
|
1517
|
+
return { ok: false, code: 'TRANSPORT_ERROR', uncertain: true, error: WHATSAPP_SEND_FILE_LOST };
|
|
1518
|
+
}
|
|
1519
|
+
return result;
|
|
1520
|
+
}
|
|
@@ -31,7 +31,7 @@ export const SURFACES = [
|
|
|
31
31
|
'browser-page-state', 'browser-target', 'browser-social',
|
|
32
32
|
'task-boundary', 'session-lookup', 'user-learning', 'claim-check',
|
|
33
33
|
'edit-stale', 'supersession', 'compact-digest', 'plan-conflict',
|
|
34
|
-
'worker-outcome', 'worker-claim', 'desktop-target',
|
|
34
|
+
'worker-outcome', 'worker-claim', 'desktop-target', 'budget-split',
|
|
35
35
|
] as const;
|
|
36
36
|
export type SurfaceName = typeof SURFACES[number];
|
|
37
37
|
|
|
@@ -94,6 +94,7 @@ export const SURFACE_META: Record<SurfaceName, SurfaceMeta> = {
|
|
|
94
94
|
'worker-outcome': { label: 'Worker outcome', description: 'Assistant workers: reads done / blocked / needs input from a final message that has no ## Result block (instead of spending a retry turn), and what kept a failed or blocked run from finishing (capability, access, needs the user, transient), which decides whether escalation is offered.', fallback: 'one result-retry worker turn; every failed, blocked or result-less run offers a one-tier escalation' },
|
|
95
95
|
'worker-claim': { label: 'Worker claim', description: 'Assistant workers: whether a run reported done while claiming success (tests pass, fixed, verified) that its own command output does not show. Flags the run so the Assistant verifies before reporting; asked only when the turn exposed commands or tool results.', fallback: 'no check', ridesWith: 'worker-outcome' },
|
|
96
96
|
'desktop-target': { label: 'Desktop target', description: 'Computer use: ranks the visible controls of the front window against a computer_ax intent. Advisory; one low-risk press by intent only behind the desktop benchmark gate.', fallback: 'the full accessibility tree, or a word-overlap ranking when an intent is given' },
|
|
97
|
+
'budget-split': { label: 'Budget split', description: 'Assistant sessions with a budget: how much of the money still to be spent will land on each provider (Claude Code, Codex, OpenCode), asked at the first route and at checkpoints (a share used up, a budget change, a run ending). It only divides what the user allowed: shares never add up to more than is left, and it never picks a model.', fallback: 'weights from the saved routes, the session\'s tasks and live runs, times the list price of the routed models; the brain keeps its reserve either way' },
|
|
97
98
|
};
|
|
98
99
|
|
|
99
100
|
const SURFACE_DEFAULTS: Record<SurfaceName, SurfaceSettings> = {
|
|
@@ -132,6 +133,8 @@ const SURFACE_DEFAULTS: Record<SurfaceName, SurfaceSettings> = {
|
|
|
132
133
|
// Rider of worker-outcome. Flags a run for verification, so the bar is the claim-check bar.
|
|
133
134
|
'worker-claim': { enabled: true, timeoutMs: 2500, minProbability: 0.9 },
|
|
134
135
|
'desktop-target': { ...DESKTOP_TARGET_DEFAULTS },
|
|
136
|
+
// On the route path (agent_route waits for the first split), never per tick: one call per checkpoint.
|
|
137
|
+
'budget-split': { enabled: true, timeoutMs: 2000 },
|
|
135
138
|
};
|
|
136
139
|
|
|
137
140
|
// --- Config shape ---
|