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,268 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Git Bash: the copy in use, and its download
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// On Windows a Claude Code without Git Bash has no Bash tool and runs every
|
|
6
|
+
// hook in PowerShell. The manager keeps the answer to "which Git Bash does a
|
|
7
|
+
// Claude Code started by SynaBun get" (resolver.js) and, on a PC that has
|
|
8
|
+
// none, puts SynaBun's own copy of Git for Windows in place:
|
|
9
|
+
//
|
|
10
|
+
// bundled inside an installed app: <resources>\git (the Windows x64
|
|
11
|
+
// installer carries it; packaging/lib/git-bash.mjs)
|
|
12
|
+
// downloaded on an npm install: DATA_HOME/runtime/git/<version>/, fetched
|
|
13
|
+
// once from the pinned release (pins.js), checked and unpacked
|
|
14
|
+
// by install.js, outside data/ so no backup holds it
|
|
15
|
+
//
|
|
16
|
+
// It downloads only on Windows, only for a processor a release is pinned for,
|
|
17
|
+
// and only when neither the PC nor the app has a Git Bash: at the server's
|
|
18
|
+
// start (ensure) or at the first Claude Code start that finds none (childEnv),
|
|
19
|
+
// once per process. A failed download is not tried again by itself: Settings
|
|
20
|
+
// shows why and has the button that tries again. SYNABUN_GIT_BASH=off turns all
|
|
21
|
+
// of it off: no download, nothing added to any environment.
|
|
22
|
+
//
|
|
23
|
+
// resolution() the Git Bash in use (refreshed when older than half a minute)
|
|
24
|
+
// childEnv(env) the environment of a Claude Code process SynaBun starts
|
|
25
|
+
// gitExecutable() git.exe of SynaBun's copy when it is the one in use (SynaBun's own git features)
|
|
26
|
+
// ensure() download when there is no Git Bash at all; never rejects
|
|
27
|
+
// status() what Settings shows: missing / downloading / ready / failed, and the rest
|
|
28
|
+
// onChange(fn) told when the Git Bash in use changes (the settings of the user's own `claude` follow it)
|
|
29
|
+
// housekeep() what an earlier run left in the data home: a stopped attempt's work folder, a version the
|
|
30
|
+
// pins no longer name (the server runs it once, in the background)
|
|
31
|
+
|
|
32
|
+
import { mkdirSync, readdirSync, statSync } from 'node:fs';
|
|
33
|
+
import { rm } from 'node:fs/promises';
|
|
34
|
+
import { join } from 'node:path';
|
|
35
|
+
import { getDataHome } from '../../../lib/paths.js';
|
|
36
|
+
import { packagedRuntime } from '../../../lib/packaged-runtime.js';
|
|
37
|
+
import { pathEnvValue } from '../augmented-path.js';
|
|
38
|
+
import { sweepStaleWork } from '../cloudflared/install.js';
|
|
39
|
+
import { checkInstalled, GitBashError, installGitBash } from './install.js';
|
|
40
|
+
import { BUNDLED_FOLDER, gitBashPinFor, inTree, MARKER, readGitBashPins } from './pins.js';
|
|
41
|
+
import { gitBashChildEnv, resolveGitBash } from './resolver.js';
|
|
42
|
+
|
|
43
|
+
const VERSION_FOLDER = /^\d+\.\d+\.\d+\.\d+$/;
|
|
44
|
+
|
|
45
|
+
/** `DATA_HOME/runtime/git`: where a downloaded Git for Windows lives. */
|
|
46
|
+
export function gitRoot(dataHome = getDataHome()) {
|
|
47
|
+
return join(dataHome, 'runtime', 'git');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const describe = (error) => ({
|
|
51
|
+
code: error instanceof GitBashError ? error.code : 'disk',
|
|
52
|
+
message: String(error?.message || error),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const same = (a, b) => !!a && !!b && a.path === b.path && a.source === b.source && a.passToClaude === b.passToClaude && a.cmdDir === b.cmdDir;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {object} [o]
|
|
59
|
+
* @param {string} [o.dataHome]
|
|
60
|
+
* @param {{ resources: string } | null} [o.packaged] lib/packaged-runtime.js packagedRuntime()
|
|
61
|
+
* @param {object} [o.pins] pins.js readGitBashPins() (read here when left out; unreadable pins never throw)
|
|
62
|
+
* @param {() => string} [o.pathValue] the PATH a git of the PC is looked for on
|
|
63
|
+
* @param {() => (string|null)} [o.settingsValue] CLAUDE_CODE_GIT_BASH_PATH of the user's ~/.claude/settings.json
|
|
64
|
+
* @param {typeof fetch} [o.fetchImpl]
|
|
65
|
+
* @param {boolean} [o.worker] unpack in a worker thread (the server); tests unpack inline
|
|
66
|
+
* @param {(line: string) => void} [o.log]
|
|
67
|
+
*/
|
|
68
|
+
export function createGitBashManager({
|
|
69
|
+
dataHome = getDataHome(),
|
|
70
|
+
packaged = packagedRuntime(),
|
|
71
|
+
pins,
|
|
72
|
+
platform = process.platform,
|
|
73
|
+
arch = process.arch,
|
|
74
|
+
env = process.env,
|
|
75
|
+
pathValue = () => pathEnvValue(env),
|
|
76
|
+
settingsValue = () => null,
|
|
77
|
+
fetchImpl,
|
|
78
|
+
stallMs,
|
|
79
|
+
worker = true,
|
|
80
|
+
maxAgeMs = 30_000,
|
|
81
|
+
isFile,
|
|
82
|
+
install = installGitBash,
|
|
83
|
+
check = checkInstalled,
|
|
84
|
+
log = () => {},
|
|
85
|
+
now = () => Date.now(),
|
|
86
|
+
} = {}) {
|
|
87
|
+
if (!pins) {
|
|
88
|
+
try {
|
|
89
|
+
pins = readGitBashPins();
|
|
90
|
+
} catch (error) {
|
|
91
|
+
pins = Object.freeze({ version: null, platforms: Object.freeze({}) });
|
|
92
|
+
if (platform === 'win32') log(`[git-bash] ${error?.message || error} SynaBun downloads no Git for Windows until this is repaired.`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const off = String(env.SYNABUN_GIT_BASH || '').trim().toLowerCase() === 'off';
|
|
96
|
+
const pin = gitBashPinFor(pins, platform, arch);
|
|
97
|
+
// `platform` decides which rules apply (Windows'); paths on this disk are in the separators of the system that
|
|
98
|
+
// runs this (the same thing on a Windows PC; tests ask the Windows rules from any system).
|
|
99
|
+
const host = process.platform;
|
|
100
|
+
const root = gitRoot(dataHome);
|
|
101
|
+
const bundledRoot = platform === 'win32' && packaged?.resources ? join(packaged.resources, BUNDLED_FOLDER) : null;
|
|
102
|
+
const downloadedRoot = pin ? join(root, pin.version) : null;
|
|
103
|
+
const ownRoots = [bundledRoot, root].filter(Boolean);
|
|
104
|
+
|
|
105
|
+
const verified = new Map(); // copy root → { sig, result }: a copy is hashed again only when its marker changes
|
|
106
|
+
const listeners = new Set();
|
|
107
|
+
let current = null;
|
|
108
|
+
let refreshedAt = 0;
|
|
109
|
+
let download = null; // { promise, stop, step, progress } while one runs
|
|
110
|
+
let lastError = null;
|
|
111
|
+
let attempted = false; // a download was started in this process (the first-need trigger fires once)
|
|
112
|
+
let settings = null; // what the last sync of the user's settings did (noteSettings)
|
|
113
|
+
|
|
114
|
+
/** SynaBun's own copies, checked: the app's, then the data home's. */
|
|
115
|
+
function copies() {
|
|
116
|
+
if (!pin) return [];
|
|
117
|
+
const out = [];
|
|
118
|
+
for (const [source, copyRoot] of [['bundled', bundledRoot], ['downloaded', downloadedRoot]]) {
|
|
119
|
+
if (!copyRoot) continue;
|
|
120
|
+
let sig = null;
|
|
121
|
+
try { const info = statSync(join(copyRoot, MARKER)); sig = `${info.size}:${info.mtimeMs}:${info.ino}`; } catch { sig = null; }
|
|
122
|
+
let result;
|
|
123
|
+
if (sig === null) result = { ok: false, reason: 'missing' };
|
|
124
|
+
else {
|
|
125
|
+
const known = verified.get(copyRoot);
|
|
126
|
+
const fresh = !(known && known.sig === sig);
|
|
127
|
+
result = fresh ? check(copyRoot, pin, { platform: host }) : known.result;
|
|
128
|
+
// A copy that could not be read just now is asked again next time; a verdict is remembered with its marker.
|
|
129
|
+
verified.set(copyRoot, { sig, result });
|
|
130
|
+
// The tree's empty folders, which an installer of files does not carry (the Windows installer makes them;
|
|
131
|
+
// this puts back one that is gone). Asked once per verdict.
|
|
132
|
+
if (fresh && result.ok) for (const rel of pin.folders || []) { try { mkdirSync(inTree(copyRoot, rel, host), { recursive: true }); } catch { /* a folder SynaBun cannot write: bash runs without it */ } }
|
|
133
|
+
}
|
|
134
|
+
out.push({ source, root: copyRoot, ok: result.ok, reason: result.reason, bash: inTree(copyRoot, pin.bash, host), git: inTree(copyRoot, pin.git, host) });
|
|
135
|
+
}
|
|
136
|
+
return out;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function refresh() {
|
|
140
|
+
let next;
|
|
141
|
+
// macOS, Linux, the kill switch: nothing to look at (no settings read, no PATH walked).
|
|
142
|
+
if (off || platform !== 'win32') next = resolveGitBash({ platform: off ? 'off' : platform });
|
|
143
|
+
else {
|
|
144
|
+
let settingsBash = null;
|
|
145
|
+
try { settingsBash = settingsValue(); } catch { settingsBash = null; }
|
|
146
|
+
let searchPath = '';
|
|
147
|
+
try { searchPath = pathValue(); } catch { searchPath = pathEnvValue(env); }
|
|
148
|
+
next = resolveGitBash({ platform, env, settingsValue: settingsBash, pathValue: searchPath, copies: copies(), ownRoots, ...(isFile ? { isFile } : {}) });
|
|
149
|
+
}
|
|
150
|
+
const changed = !same(current, next);
|
|
151
|
+
current = next;
|
|
152
|
+
refreshedAt = now();
|
|
153
|
+
if (changed) for (const listener of [...listeners]) { try { listener(next); } catch { /* the listener's */ } }
|
|
154
|
+
return current;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function resolution({ maxAge = maxAgeMs } = {}) {
|
|
158
|
+
if (!current || now() - refreshedAt > maxAge) refresh();
|
|
159
|
+
return current;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Versions the pins no longer name, removed without holding the event loop (some ten thousand files each). */
|
|
163
|
+
async function pruneOtherVersions() {
|
|
164
|
+
let names = [];
|
|
165
|
+
try { names = readdirSync(root); } catch { return []; }
|
|
166
|
+
const removed = [];
|
|
167
|
+
for (const name of names) {
|
|
168
|
+
if (!VERSION_FOLDER.test(name) || name === pin?.version) continue;
|
|
169
|
+
// A copy still in use (a Claude Code started before the update) cannot be removed on Windows: the next start tries again.
|
|
170
|
+
try { await rm(join(root, name), { recursive: true, force: true, maxRetries: 2 }); removed.push(name); log(`[git-bash] Removed Git for Windows ${name}, which the pins no longer name.`); } catch { /* in use */ }
|
|
171
|
+
}
|
|
172
|
+
return removed;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Windows: a work folder a stopped attempt left (when no attempt runs now), and versions the pins no longer name. */
|
|
176
|
+
async function housekeep() {
|
|
177
|
+
if (platform !== 'win32' || off || !pin) return { swept: [], removed: [] };
|
|
178
|
+
const swept = download ? [] : sweepStaleWork(root);
|
|
179
|
+
return { swept, removed: await pruneOtherVersions() };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Download SynaBun's copy when there is no Git Bash at all. Resolves the status; never rejects. */
|
|
183
|
+
function ensure({ reason = 'start' } = {}) {
|
|
184
|
+
if (platform !== 'win32' || !pin || off) return Promise.resolve(status());
|
|
185
|
+
if (download) return download.promise.then(() => status());
|
|
186
|
+
if (refresh().source) return Promise.resolve(status());
|
|
187
|
+
attempted = true;
|
|
188
|
+
lastError = null;
|
|
189
|
+
const stop = new AbortController();
|
|
190
|
+
const job = { stop, step: 'download', progress: { phase: 'download', received: 0, total: pin.size } };
|
|
191
|
+
log(`[git-bash] No Git Bash on this PC (${reason}): downloading Git for Windows ${pin.version} (${(pin.size / 1024 / 1024).toFixed(1)} MB) from ${pin.url}`);
|
|
192
|
+
job.promise = install({
|
|
193
|
+
pins, pin, root, fetchImpl, stallMs, worker, platform: host, signal: stop.signal,
|
|
194
|
+
onStep: (step) => { job.step = step; },
|
|
195
|
+
onProgress: (progress) => { job.progress = progress; },
|
|
196
|
+
}).then(async (placed) => {
|
|
197
|
+
log(`[git-bash] Git for Windows ${pin.version} is in place, release file and tree checked: ${placed.path}`);
|
|
198
|
+
verified.delete(downloadedRoot);
|
|
199
|
+
await pruneOtherVersions();
|
|
200
|
+
}, (error) => {
|
|
201
|
+
lastError = describe(error);
|
|
202
|
+
log(`[git-bash] Git for Windows ${pin.version} could not be put in place (${lastError.code}): ${lastError.message}`);
|
|
203
|
+
}).finally(() => {
|
|
204
|
+
if (download === job) download = null;
|
|
205
|
+
// The listeners hear the change (SynaBun's copy now in use); Settings asks for the status itself.
|
|
206
|
+
refresh();
|
|
207
|
+
});
|
|
208
|
+
download = job;
|
|
209
|
+
return job.promise.then(() => status());
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function childEnv(base = env) {
|
|
213
|
+
const r = resolution();
|
|
214
|
+
// The first Claude Code start that finds no Git Bash at all fetches one (once per process; Settings retries).
|
|
215
|
+
if (platform === 'win32' && pin && !off && !r.source && !download && !attempted) ensure({ reason: 'first-need' });
|
|
216
|
+
return gitBashChildEnv(base, r, { platform });
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function gitExecutable() {
|
|
220
|
+
const r = resolution();
|
|
221
|
+
return r.passToClaude && r.git ? r.git : null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function status() {
|
|
225
|
+
const r = current || resolution();
|
|
226
|
+
const base = {
|
|
227
|
+
supported: platform === 'win32',
|
|
228
|
+
pinned: pin ? { version: pin.version, tag: pin.tag, file: pin.file, size: pin.size, url: pin.url } : null,
|
|
229
|
+
source: r.source,
|
|
230
|
+
path: r.path,
|
|
231
|
+
passToClaude: r.passToClaude,
|
|
232
|
+
step: null,
|
|
233
|
+
progress: null,
|
|
234
|
+
error: null,
|
|
235
|
+
settings,
|
|
236
|
+
checkedAt: new Date(refreshedAt || now()).toISOString(),
|
|
237
|
+
};
|
|
238
|
+
if (platform !== 'win32') return { ...base, state: 'unsupported' };
|
|
239
|
+
if (off) return { ...base, state: 'off' };
|
|
240
|
+
if (download) {
|
|
241
|
+
const { phase, received = 0, consumed = 0, total = 0 } = download.progress || {};
|
|
242
|
+
const done = phase === 'extract' ? consumed : received;
|
|
243
|
+
return { ...base, state: 'downloading', step: download.step, progress: { phase, done, total, percent: total ? Math.min(100, Math.floor((done / total) * 100)) : 0 } };
|
|
244
|
+
}
|
|
245
|
+
if (r.source === 'bundled' || r.source === 'downloaded') return { ...base, state: 'ready' };
|
|
246
|
+
if (r.source) return { ...base, state: 'system' };
|
|
247
|
+
// Windows on a processor no release is pinned for (arm64): nothing to download, nothing to retry.
|
|
248
|
+
if (!pin) return { ...base, state: 'unsupported' };
|
|
249
|
+
if (lastError) return { ...base, state: 'failed', error: lastError };
|
|
250
|
+
return { ...base, state: 'missing' };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
pin,
|
|
255
|
+
root,
|
|
256
|
+
ownRoots,
|
|
257
|
+
resolution,
|
|
258
|
+
refresh,
|
|
259
|
+
childEnv,
|
|
260
|
+
gitExecutable,
|
|
261
|
+
ensure,
|
|
262
|
+
status,
|
|
263
|
+
housekeep,
|
|
264
|
+
cancel: () => { if (!download) return false; download.stop.abort(); return true; },
|
|
265
|
+
noteSettings: (result) => { settings = result || null; },
|
|
266
|
+
onChange: (listener) => { listeners.add(listener); return () => listeners.delete(listener); },
|
|
267
|
+
};
|
|
268
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Git for Windows: which one
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// Claude Code on Windows runs its Bash tool and every hook through Git Bash;
|
|
6
|
+
// without one it falls back to PowerShell, where commands written for bash
|
|
7
|
+
// fail (SynaBun's hooks of an installed app among them). SynaBun brings a
|
|
8
|
+
// private copy of Git for Windows for a PC that has none (resolver.js decides
|
|
9
|
+
// when it is the one in use). pins.json beside this file is the one place that
|
|
10
|
+
// knows which: the release, its file for Windows x64, the SHA-256 and size
|
|
11
|
+
// GitHub publishes for it, and what the archive holds once it is unpacked (the
|
|
12
|
+
// tree's digest, and the files SynaBun starts). The running application reads
|
|
13
|
+
// it here (manager.js downloads the file on a Windows npm install), and so does
|
|
14
|
+
// an application build (packaging/lib/git-bash.mjs imports this module from the
|
|
15
|
+
// application it stages): an installer never carries a Git the application
|
|
16
|
+
// would not have fetched itself.
|
|
17
|
+
//
|
|
18
|
+
// To move to another release: change `version`, `tag`, `baseUrl`, `release`
|
|
19
|
+
// and `source`, download the asset from the git-for-windows/git release, put
|
|
20
|
+
// GitHub's digest and size in `sha256` / `size` (check them against the
|
|
21
|
+
// release notes' table), unpack it with this application's own reader and
|
|
22
|
+
// record `tree` and `key` from what install.js treeDigest() reports. Fetch
|
|
23
|
+
// COPYING and LGPL-2.1 of that tag into licenses/. tests/git-bash-pins.test.mjs
|
|
24
|
+
// checks the shape; only a download checks the values.
|
|
25
|
+
//
|
|
26
|
+
// Only node:fs, node:path and node:url here: a build imports this on the Node
|
|
27
|
+
// of the build machine, before the application has a dependency installed.
|
|
28
|
+
|
|
29
|
+
import { readFileSync } from 'node:fs';
|
|
30
|
+
import { join, posix, win32 } from 'node:path';
|
|
31
|
+
import { fileURLToPath } from 'node:url';
|
|
32
|
+
|
|
33
|
+
export const PINS_PATH = fileURLToPath(new URL('./pins.json', import.meta.url));
|
|
34
|
+
/** Git's own license texts of the pinned tag (COPYING, LGPL-2.1): what LICENSE.txt in the copy is made of. */
|
|
35
|
+
export const LICENSES_DIR = fileURLToPath(new URL('./licenses/', import.meta.url));
|
|
36
|
+
|
|
37
|
+
/** Where every pinned file is: Git for Windows' releases on GitHub, over HTTPS, and nowhere else. */
|
|
38
|
+
export const RELEASE_BASE = 'https://github.com/git-for-windows/git/releases/download/';
|
|
39
|
+
const RELEASE_PAGE = 'https://github.com/git-for-windows/git/releases/tag/';
|
|
40
|
+
const SOURCE_TREE = 'https://github.com/git-for-windows/git/tree/';
|
|
41
|
+
|
|
42
|
+
/** The folder of a packaged application that holds its Git for Windows, beside `runtime/` and `app/`. */
|
|
43
|
+
export const BUNDLED_FOLDER = 'git';
|
|
44
|
+
|
|
45
|
+
/** What SynaBun puts at the top of its copy, beside what the release file holds (never part of the tree's digest). */
|
|
46
|
+
export const MARKER = 'synabun-git.json';
|
|
47
|
+
export const ADDED_FILES = Object.freeze(['LICENSE.txt', 'SOURCE.txt', MARKER]);
|
|
48
|
+
|
|
49
|
+
const SHA256 = /^[0-9a-f]{64}$/;
|
|
50
|
+
const VERSION = /^\d+\.\d+\.\d+\.\d+$/;
|
|
51
|
+
const TAG = /^v(\d+\.\d+\.\d+)\.windows\.(\d+)$/;
|
|
52
|
+
const KEY = /^win32-(x64|arm64)$/;
|
|
53
|
+
const FILE_ARCH = Object.freeze({ x64: '64-bit', arm64: 'arm64' });
|
|
54
|
+
const isCount = (value) => Number.isInteger(value) && value > 0 && value < 2 ** 40;
|
|
55
|
+
|
|
56
|
+
/** A path inside the tree as the archive spells it: relative, forward slashes, no `.` or `..`, nothing Windows reads otherwise. */
|
|
57
|
+
export function isTreePath(value) {
|
|
58
|
+
if (typeof value !== 'string' || !value || value.length > 400) return false;
|
|
59
|
+
if (value.startsWith('/') || value.endsWith('/') || /[\\:*?"<>|\0-\x1f]/.test(value)) return false;
|
|
60
|
+
return value.split('/').every((part) => part && part !== '.' && part !== '..' && !/[ .]$/.test(part));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** `rel` (a tree path) inside `root`, in the separators of `platform`. */
|
|
64
|
+
export function inTree(root, rel, platform = process.platform) {
|
|
65
|
+
return (platform === 'win32' ? win32 : posix).join(root, ...rel.split('/'));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The pins as an object every reader can rely on, or an Error that lists what is wrong with them. A pin is
|
|
70
|
+
* `{ key, platform, arch, version, tag, file, url, sha256, size, archive, skip, folders, tree, bash, git, cmd, keyFiles }`:
|
|
71
|
+
* `folders` are the tree's empty folders (a digest of files does not see them; an installer of files carries none).
|
|
72
|
+
* @param {object} raw pins.json, parsed
|
|
73
|
+
*/
|
|
74
|
+
export function validateGitBashPins(raw) {
|
|
75
|
+
const problems = [];
|
|
76
|
+
const version = String(raw?.version || '');
|
|
77
|
+
const tag = String(raw?.tag || '');
|
|
78
|
+
if (!VERSION.test(version)) problems.push(`version "${version}" is not a Git for Windows file version (2.56.0.2)`);
|
|
79
|
+
const tagged = TAG.exec(tag);
|
|
80
|
+
if (!tagged) problems.push(`tag "${tag}" is not a Git for Windows release tag (v2.56.0.windows.2)`);
|
|
81
|
+
else if (`${tagged[1]}.${tagged[2]}` !== version) problems.push(`tag ${tag} is not the release of version ${version}`);
|
|
82
|
+
const baseUrl = String(raw?.baseUrl || '');
|
|
83
|
+
if (baseUrl !== `${RELEASE_BASE}${tag}/`) problems.push(`baseUrl must be ${RELEASE_BASE}${tag}/`);
|
|
84
|
+
if (raw?.release !== `${RELEASE_PAGE}${tag}`) problems.push(`release must be ${RELEASE_PAGE}${tag}`);
|
|
85
|
+
if (raw?.source !== `${SOURCE_TREE}${tag}`) problems.push(`source must be ${SOURCE_TREE}${tag}`);
|
|
86
|
+
if (typeof raw?.origin !== 'string' || !raw.origin.trim()) problems.push('origin (where the checksums come from) is missing');
|
|
87
|
+
if (typeof raw?.license !== 'string' || !raw.license.trim()) problems.push('license is missing');
|
|
88
|
+
const platforms = {};
|
|
89
|
+
for (const [key, entry] of Object.entries(raw?.platforms || {})) {
|
|
90
|
+
const at = KEY.exec(key);
|
|
91
|
+
if (!at) { problems.push(`"${key}" is not a platform Git for Windows is pinned for (win32-x64, win32-arm64)`); continue; }
|
|
92
|
+
const arch = at[1];
|
|
93
|
+
const wrong = [];
|
|
94
|
+
const file = String(entry?.file || '');
|
|
95
|
+
if (file !== `Git-${version}-${FILE_ARCH[arch]}.tar.bz2`) wrong.push(`file must be Git-${version}-${FILE_ARCH[arch]}.tar.bz2`);
|
|
96
|
+
if (!SHA256.test(String(entry?.sha256 || ''))) wrong.push('sha256 is not 64 hex digits');
|
|
97
|
+
if (!isCount(entry?.size)) wrong.push('size is not a number of bytes');
|
|
98
|
+
if (entry?.archive !== 'tar.bz2') wrong.push(`archive "${entry?.archive}" is not a kind this reads (tar.bz2)`);
|
|
99
|
+
const skip = Array.isArray(entry?.skip) ? entry.skip : null;
|
|
100
|
+
if (!skip || !skip.every(isTreePath)) wrong.push('skip must be a list of paths inside the tree');
|
|
101
|
+
const folders = Array.isArray(entry?.folders) ? entry.folders : null;
|
|
102
|
+
if (!folders || !folders.every(isTreePath)) wrong.push('folders must be a list of paths inside the tree');
|
|
103
|
+
const tree = entry?.tree || {};
|
|
104
|
+
if (!isCount(tree.files) || !isCount(tree.bytes) || !SHA256.test(String(tree.sha256 || ''))) wrong.push('tree must give files, bytes and sha256');
|
|
105
|
+
const keyFiles = entry?.key && typeof entry.key === 'object' ? entry.key : {};
|
|
106
|
+
for (const [path, info] of Object.entries(keyFiles)) {
|
|
107
|
+
if (!isTreePath(path) || !isCount(info?.size) || !SHA256.test(String(info?.sha256 || ''))) wrong.push(`key ${path}: a path inside the tree with its size and sha256`);
|
|
108
|
+
if (ADDED_FILES.includes(path)) wrong.push(`key ${path}: a name SynaBun adds itself`);
|
|
109
|
+
}
|
|
110
|
+
for (const role of ['bash', 'git']) {
|
|
111
|
+
if (!isTreePath(entry?.[role]) || !keyFiles[entry[role]]) wrong.push(`${role} must name one of the key files`);
|
|
112
|
+
}
|
|
113
|
+
if (wrong.length) { problems.push(...wrong.map((each) => `${key}: ${each}`)); continue; }
|
|
114
|
+
platforms[key] = Object.freeze({
|
|
115
|
+
key, platform: 'win32', arch, version, tag, file,
|
|
116
|
+
url: `${baseUrl}${file}`,
|
|
117
|
+
sha256: entry.sha256,
|
|
118
|
+
size: entry.size,
|
|
119
|
+
archive: entry.archive,
|
|
120
|
+
skip: Object.freeze([...skip]),
|
|
121
|
+
folders: Object.freeze([...folders]),
|
|
122
|
+
tree: Object.freeze({ files: tree.files, bytes: tree.bytes, sha256: tree.sha256 }),
|
|
123
|
+
bash: entry.bash,
|
|
124
|
+
git: entry.git,
|
|
125
|
+
cmd: posix.dirname(entry.git),
|
|
126
|
+
keyFiles: Object.freeze(Object.fromEntries(Object.entries(keyFiles).map(([path, info]) => [path, Object.freeze({ size: info.size, sha256: info.sha256 })]))),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (!Object.keys(platforms).length && !problems.length) problems.push('no platform is pinned');
|
|
130
|
+
if (problems.length) throw new Error(`The Git for Windows pins are not usable: ${problems.join('; ')}`);
|
|
131
|
+
return Object.freeze({
|
|
132
|
+
name: String(raw.name || 'Git for Windows'),
|
|
133
|
+
version, tag, baseUrl,
|
|
134
|
+
release: raw.release,
|
|
135
|
+
source: raw.source,
|
|
136
|
+
license: raw.license,
|
|
137
|
+
origin: raw.origin,
|
|
138
|
+
platforms: Object.freeze(platforms),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** pins.json, read and checked. Throws when the file is missing or wrong: nothing is downloaded by guesswork. */
|
|
143
|
+
export function readGitBashPins(path = PINS_PATH) {
|
|
144
|
+
return validateGitBashPins(JSON.parse(readFileSync(path, 'utf8')));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** The pin of a platform, or null: Git for Windows exists for Windows only (and is pinned here for x64). */
|
|
148
|
+
export function gitBashPinFor(pins, platform = process.platform, arch = process.arch) {
|
|
149
|
+
if (platform !== 'win32') return null;
|
|
150
|
+
return pins?.platforms?.[`win32-${arch}`] || null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** The Git for Windows of a packaged application: `<resources>/git`. */
|
|
154
|
+
export function bundledGitRoot(resources, platform = process.platform) {
|
|
155
|
+
return (platform === 'win32' ? win32 : posix).join(resources, BUNDLED_FOLDER);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** LICENSE.txt of SynaBun's copy: Git's own license texts of the pinned tag, after a line that says what they cover. */
|
|
159
|
+
export function licenseText(dir = LICENSES_DIR) {
|
|
160
|
+
const copying = readFileSync(join(dir, 'COPYING'), 'utf8');
|
|
161
|
+
const lgpl = readFileSync(join(dir, 'LGPL-2.1'), 'utf8');
|
|
162
|
+
return [
|
|
163
|
+
'Git for Windows is free software. Git itself is distributed under the GNU General Public License,',
|
|
164
|
+
'version 2 (below, as COPYING of the Git source), some of its parts under the GNU Lesser General',
|
|
165
|
+
'Public License, version 2.1 (after it, as LGPL-2.1 of the Git source). The other programs and',
|
|
166
|
+
'libraries of this folder carry their own licenses: usr/share/licenses, ucrt64/share/licenses',
|
|
167
|
+
'and ucrt64/doc. SOURCE.txt says where the source of all of it is.',
|
|
168
|
+
'',
|
|
169
|
+
'='.repeat(78),
|
|
170
|
+
'COPYING',
|
|
171
|
+
'='.repeat(78),
|
|
172
|
+
'',
|
|
173
|
+
copying.replace(/\s+$/, ''),
|
|
174
|
+
'',
|
|
175
|
+
'',
|
|
176
|
+
'='.repeat(78),
|
|
177
|
+
'LGPL-2.1',
|
|
178
|
+
'='.repeat(78),
|
|
179
|
+
'',
|
|
180
|
+
lgpl.replace(/\s+$/, ''),
|
|
181
|
+
'',
|
|
182
|
+
].join('\n');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** SOURCE.txt of SynaBun's copy: what it is, where it came from, where its source is. */
|
|
186
|
+
export function sourceText(pins, pin) {
|
|
187
|
+
return [
|
|
188
|
+
`${pins.name} ${pins.version} (${pins.tag}), for Windows ${pin.arch}, as SynaBun ships it.`,
|
|
189
|
+
'',
|
|
190
|
+
'The files of this folder are those of the release file below, unchanged, except:',
|
|
191
|
+
` - left out: ${pin.skip.join(', ')}`,
|
|
192
|
+
' (links into /proc that Windows cannot create without administrator rights)',
|
|
193
|
+
` - added by SynaBun: ${ADDED_FILES.join(', ')}`,
|
|
194
|
+
'',
|
|
195
|
+
`Release file: ${pin.url}`,
|
|
196
|
+
`SHA-256: ${pin.sha256}`,
|
|
197
|
+
`Release: ${pins.release}`,
|
|
198
|
+
`Source of Git: ${pins.source}`,
|
|
199
|
+
' (and the "Source code" archives of the release above)',
|
|
200
|
+
'Source of the other programs: the Git for Windows project, https://github.com/git-for-windows',
|
|
201
|
+
' (the MSYS2 and MINGW package definitions it builds them from)',
|
|
202
|
+
`License: ${pins.license} for Git (LICENSE.txt); each other program's in usr/share/licenses,`,
|
|
203
|
+
' ucrt64/share/licenses and ucrt64/doc.',
|
|
204
|
+
'',
|
|
205
|
+
].join('\n');
|
|
206
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Git for Windows",
|
|
3
|
+
"version": "2.56.0.2",
|
|
4
|
+
"tag": "v2.56.0.windows.2",
|
|
5
|
+
"baseUrl": "https://github.com/git-for-windows/git/releases/download/v2.56.0.windows.2/",
|
|
6
|
+
"release": "https://github.com/git-for-windows/git/releases/tag/v2.56.0.windows.2",
|
|
7
|
+
"source": "https://github.com/git-for-windows/git/tree/v2.56.0.windows.2",
|
|
8
|
+
"license": "GPL-2.0-only",
|
|
9
|
+
"origin": "Git for Windows' own release file of its stable release v2.56.0.windows.2 (published 2026-10-05). `sha256` and `size` are what GitHub publishes for the asset (`gh release view v2.56.0.windows.2 --repo git-for-windows/git --json assets`: digest sha256:16ca394b…), and the same SHA-256 is in the release notes' own table. The file was downloaded on 2026-10-18 with `gh release download` and both were computed from it and found equal. `tree` and `key` were computed from that download, read by lib/git-bash/bzip2.js and unpacked with `skip` left out: `tree` is every file there, its count, its bytes, and the SHA-256 over one line `path NUL size NUL sha256 LF` per file in path order (install.js treeDigest); `key` is each file SynaBun starts, with its size and SHA-256; `folders` are the tree's empty folders (an installer of files carries none, so the Windows installer makes them).",
|
|
10
|
+
"platforms": {
|
|
11
|
+
"win32-x64": {
|
|
12
|
+
"file": "Git-2.56.0.2-64-bit.tar.bz2",
|
|
13
|
+
"sha256": "16ca394bdb94b372267d79e1e10b68763674f73e03e0648202a7971a8a730a84",
|
|
14
|
+
"size": 118485193,
|
|
15
|
+
"archive": "tar.bz2",
|
|
16
|
+
"skip": ["dev/fd", "dev/stdin", "dev/stdout", "dev/stderr", "etc/mtab"],
|
|
17
|
+
"folders": ["dev/mqueue", "dev/shm", "tmp"],
|
|
18
|
+
"tree": {
|
|
19
|
+
"files": 9617,
|
|
20
|
+
"bytes": 423079170,
|
|
21
|
+
"sha256": "11842baaa80a7e6145959291c338179003bc3b7d4963b891c432c14ee74637a0"
|
|
22
|
+
},
|
|
23
|
+
"bash": "bin/bash.exe",
|
|
24
|
+
"git": "cmd/git.exe",
|
|
25
|
+
"key": {
|
|
26
|
+
"bin/bash.exe": { "size": 45416, "sha256": "6cc575e9112efe6253b6a6999c12aa0240cb3f511aeda3480ae026edc0dc5280" },
|
|
27
|
+
"usr/bin/bash.exe": { "size": 2449886, "sha256": "5490d0da5e7cf9d92068cc48fcc590f2bcf8564add8ff91c3b5fe541eb2d72e3" },
|
|
28
|
+
"cmd/git.exe": { "size": 45400, "sha256": "54bda91c773c6bba2b970424423cfcb80552d92dc6967d766f98931fe1251a54" },
|
|
29
|
+
"ucrt64/bin/git.exe": { "size": 4413272, "sha256": "b824434dfe3b5f9cf648af6c9cc8cb1f6a982cc6e13b6c6ebbe6533c7e51cc2e" },
|
|
30
|
+
"usr/bin/msys-2.0.dll": { "size": 3373151, "sha256": "2a89b7c31b323c42e2fb37900af087aeb27417694e630a210bc75b0369410bc7" }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|