synabun 2.0.0 → 2.0.7
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 +97 -0
- package/NOTICE +5 -0
- package/README.md +2 -1
- package/THIRD-PARTY-LICENSES.md +59 -0
- package/benchmarks/fixtures/browser/README.md +1 -1
- package/benchmarks/fixtures/desktop/README.md +1 -1
- package/docs/whatsapp.md +153 -18
- package/hooks/claude-code/pre-compact.mjs +11 -0
- package/hooks/claude-code/prompt-submit.mjs +60 -184
- package/hooks/claude-code/session-start.mjs +73 -16
- package/hooks/claude-code/shared.mjs +26 -3
- package/hooks/claude-code/stop.mjs +5 -5
- 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/packaged-runtime.js +138 -11
- package/lib/start-launcher.js +88 -1
- 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/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/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/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 +10 -7
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +34 -13
- package/mcp-server/dist/tools/agents.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/tui.js +2 -1
- 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 +2 -2
- package/mcp-server/package.json +1 -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/budget-judgments.ts +183 -0
- package/mcp-server/src/services/codex-config-heal.ts +35 -4
- 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 +33 -14
- package/mcp-server/src/tools/whatsapp-send-file.ts +51 -0
- package/mcp-server/src/tui.ts +2 -1
- package/mcp-server/src/version.ts +22 -0
- package/neural-interface/i18n/en.json +2126 -209
- package/neural-interface/i18n/pt-BR.json +2123 -207
- package/neural-interface/lib/account-usage.js +163 -0
- package/neural-interface/lib/assistant-api.js +316 -57
- package/neural-interface/lib/assistant-brains/claude.js +19 -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-catalog.js +179 -27
- package/neural-interface/lib/assistant-config.js +91 -14
- package/neural-interface/lib/assistant-dispatch.js +494 -138
- package/neural-interface/lib/assistant-hidden-models.js +393 -66
- package/neural-interface/lib/assistant-jev.js +26 -3
- package/neural-interface/lib/assistant-memory.js +24 -10
- package/neural-interface/lib/assistant-persona.js +73 -12
- package/neural-interface/lib/assistant-plan-permissions.js +8 -1
- package/neural-interface/lib/assistant-pricing.js +21 -6
- package/neural-interface/lib/assistant-route-accounts.js +14 -0
- 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 +488 -59
- package/neural-interface/lib/assistant-task-prompt.js +13 -3
- package/neural-interface/lib/assistant-test-density.js +142 -0
- package/neural-interface/lib/assistant-user-context-budgets.js +123 -0
- package/neural-interface/lib/assistant-user-context.js +908 -0
- package/neural-interface/lib/assistant-user-knowledge.js +328 -0
- package/neural-interface/lib/assistant-user-learn.js +404 -0
- package/neural-interface/lib/assistant-user-threads.js +226 -0
- package/neural-interface/lib/assistant-user-writer.js +183 -0
- package/neural-interface/lib/augmented-path.js +317 -53
- package/neural-interface/lib/browser-background-tab.js +134 -0
- package/neural-interface/lib/browser-screenshot.js +678 -61
- package/neural-interface/lib/claude-accounts.js +342 -31
- package/neural-interface/lib/claude-agent-bridge.js +123 -9
- package/neural-interface/lib/claude-executable.js +6 -1
- package/neural-interface/lib/claude-model-catalog.js +33 -5
- 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/claude-temporary.js +46 -7
- 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/cloudflared/install.js +533 -0
- package/neural-interface/lib/cloudflared/manager.js +545 -0
- package/neural-interface/lib/cloudflared/pins.js +115 -0
- package/neural-interface/lib/cloudflared/pins.json +63 -0
- package/neural-interface/lib/cloudflared/tunnel.js +265 -0
- package/neural-interface/lib/codex-account-auth.js +178 -0
- package/neural-interface/lib/codex-accounts.js +489 -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 +120 -0
- package/neural-interface/lib/desktop/config.js +3 -0
- package/neural-interface/lib/editor-completion-endpoint.js +264 -0
- package/neural-interface/lib/editor-completion-opencode.js +436 -0
- package/neural-interface/lib/editor-completion.js +714 -0
- package/neural-interface/lib/editor-config.js +149 -0
- package/neural-interface/lib/editor-files-api.js +268 -0
- package/neural-interface/lib/editor-git-api.js +134 -0
- package/neural-interface/lib/file-explorer-api.js +1039 -0
- package/neural-interface/lib/file-explorer-system.js +355 -0
- package/neural-interface/lib/file-explorer-trash.ps1 +85 -0
- package/neural-interface/lib/file-explorer-watch.js +239 -0
- 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-diff-api.js +103 -0
- package/neural-interface/lib/git-read.js +234 -0
- package/neural-interface/lib/greeting/api.js +89 -0
- package/neural-interface/lib/greeting/budgets.js +90 -0
- package/neural-interface/lib/greeting/engine.js +461 -0
- package/neural-interface/lib/greeting/facts.js +320 -0
- package/neural-interface/lib/greeting/sources.js +252 -0
- package/neural-interface/lib/greeting/writer.js +139 -0
- package/neural-interface/lib/http-guards.js +189 -13
- package/neural-interface/lib/install-details.js +145 -0
- package/neural-interface/lib/machine-names.js +88 -0
- package/neural-interface/lib/mcp-installer.js +14 -2
- package/neural-interface/lib/memory-api.js +31 -7
- package/neural-interface/lib/native-loop-providers.js +26 -8
- package/neural-interface/lib/native-loop-runtime.js +9 -4
- package/neural-interface/lib/os-path.js +319 -0
- package/neural-interface/lib/plugin-installer.js +4 -2
- package/neural-interface/lib/project-storage.js +5 -7
- package/neural-interface/lib/provider-panel-api-key-auth.js +92 -0
- package/neural-interface/lib/provider-panel-terminal-auth.js +95 -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/request-gate.js +589 -0
- package/neural-interface/lib/session-title-generator.js +4 -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/ui-blob-api.js +108 -0
- package/neural-interface/lib/ui-blob-store.js +68 -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 +701 -2
- package/neural-interface/package.json +13 -2
- package/neural-interface/public/index.html +2 -0
- package/neural-interface/public/index2d.html +2 -0
- package/neural-interface/public/install-app.html +9 -6
- package/neural-interface/public/offline.html +19 -3
- package/neural-interface/public/onboarding.html +107 -2
- package/neural-interface/public/shared/account-i18n.js +7 -0
- package/neural-interface/public/shared/account-menu.js +539 -0
- package/neural-interface/public/shared/account-usage.js +19 -0
- package/neural-interface/public/shared/account-view.js +335 -0
- package/neural-interface/public/shared/agent-runtime-options.js +50 -14
- package/neural-interface/public/shared/assistant/asst-accounts.js +182 -184
- package/neural-interface/public/shared/assistant/asst-api.js +32 -2
- package/neural-interface/public/shared/assistant/asst-automation.js +286 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +430 -81
- package/neural-interface/public/shared/assistant/asst-budget.js +259 -303
- package/neural-interface/public/shared/assistant/asst-composer.js +11 -1
- package/neural-interface/public/shared/assistant/asst-mascot.js +140 -61
- package/neural-interface/public/shared/assistant/asst-menu.js +27 -11
- package/neural-interface/public/shared/assistant/asst-panel.js +198 -42
- package/neural-interface/public/shared/assistant/asst-render.js +197 -23
- package/neural-interface/public/shared/assistant/asst-route-models.js +108 -0
- package/neural-interface/public/shared/assistant/asst-route.js +95 -343
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +534 -0
- package/neural-interface/public/shared/assistant/asst-sanitize.js +8 -1
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +31 -9
- package/neural-interface/public/shared/assistant/asst-slash.js +1 -1
- package/neural-interface/public/shared/assistant/asst-state.js +186 -2
- package/neural-interface/public/shared/assistant/asst-styles.js +247 -11
- package/neural-interface/public/shared/blob-store.js +111 -22
- 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 +80 -118
- package/neural-interface/public/shared/cdx/cdx-render.js +25 -89
- package/neural-interface/public/shared/cdx/cdx-settings.js +231 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +164 -107
- package/neural-interface/public/shared/cdx/cdx-tabs.js +348 -668
- 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/constants.js +6 -1
- package/neural-interface/public/shared/cp/cp-events.js +2 -1
- package/neural-interface/public/shared/cp/cp-rehydrate.js +2 -1
- package/neural-interface/public/shared/cp/cp-styles.js +61 -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-ai-logic.js +409 -0
- package/neural-interface/public/shared/editor/editor-ai.js +619 -0
- package/neural-interface/public/shared/editor/editor-commands.js +212 -0
- package/neural-interface/public/shared/editor/editor-compare.js +103 -0
- package/neural-interface/public/shared/editor/editor-completion-list.js +172 -0
- package/neural-interface/public/shared/editor/editor-doc.js +257 -0
- package/neural-interface/public/shared/editor/editor-git-logic.js +131 -0
- package/neural-interface/public/shared/editor/editor-git.js +95 -0
- package/neural-interface/public/shared/editor/editor-languages.js +156 -0
- package/neural-interface/public/shared/editor/editor-lint.js +229 -0
- package/neural-interface/public/shared/editor/editor-loader.js +51 -0
- package/neural-interface/public/shared/editor/editor-markdown.js +90 -0
- package/neural-interface/public/shared/editor/editor-menu.js +233 -0
- package/neural-interface/public/shared/editor/editor-minimap.js +371 -0
- package/neural-interface/public/shared/editor/editor-palette-logic.js +192 -0
- package/neural-interface/public/shared/editor/editor-palette.js +125 -0
- package/neural-interface/public/shared/editor/editor-panel-logic.js +288 -0
- package/neural-interface/public/shared/editor/editor-panel.js +2099 -0
- package/neural-interface/public/shared/editor/editor-prefs.js +224 -0
- package/neural-interface/public/shared/editor/editor-safety.js +500 -0
- package/neural-interface/public/shared/editor/editor-search.js +352 -0
- package/neural-interface/public/shared/editor/editor-statusbar.js +144 -0
- package/neural-interface/public/shared/editor/editor-tabs-logic.js +331 -0
- package/neural-interface/public/shared/editor/editor-tabs.js +233 -0
- package/neural-interface/public/shared/editor/editor-theme.js +244 -0
- package/neural-interface/public/shared/editor/editor-view.js +332 -0
- package/neural-interface/public/shared/explorer/fx-api.js +216 -0
- package/neural-interface/public/shared/explorer/fx-links.js +204 -0
- package/neural-interface/public/shared/explorer/fx-logic.js +537 -0
- package/neural-interface/public/shared/explorer/fx-main.js +865 -0
- package/neural-interface/public/shared/explorer/fx-names.js +87 -0
- package/neural-interface/public/shared/explorer/fx-ops.js +370 -0
- package/neural-interface/public/shared/explorer/fx-popups.js +490 -0
- package/neural-interface/public/shared/explorer/fx-tree.js +790 -0
- package/neural-interface/public/shared/file-links.js +339 -0
- package/neural-interface/public/shared/git-bash-view.js +145 -0
- package/neural-interface/public/shared/greeting/greeting-card.js +178 -0
- package/neural-interface/public/shared/greeting/greeting-view.js +148 -0
- package/neural-interface/public/shared/html-shell.js +161 -165
- 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 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-greeting.js +47 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +131 -17
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +7 -1
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +22 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +158 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +3 -2
- package/neural-interface/public/shared/pwa-install-page.js +32 -2
- package/neural-interface/public/shared/pwa-install.css +3 -3
- package/neural-interface/public/shared/pwa-install.js +100 -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-code-editor-pane.js +412 -0
- package/neural-interface/public/shared/settings/settings-code-editor.js +328 -0
- package/neural-interface/public/shared/settings/settings-greeting.js +133 -0
- package/neural-interface/public/shared/settings/settings-ia.js +33 -4
- package/neural-interface/public/shared/settings/settings-user-context.js +154 -0
- package/neural-interface/public/shared/showcase-privacy.js +489 -0
- package/neural-interface/public/shared/start-bridge.js +238 -19
- package/neural-interface/public/shared/storage.js +30 -3
- package/neural-interface/public/shared/styles.css +1710 -770
- package/neural-interface/public/shared/synabun-mascot.js +68 -58
- package/neural-interface/public/shared/tunnel-view.js +167 -0
- package/neural-interface/public/shared/ui-claude-panel.js +369 -229
- package/neural-interface/public/shared/ui-cli-banner.js +355 -0
- package/neural-interface/public/shared/ui-detail.js +15 -0
- package/neural-interface/public/shared/ui-explorer.js +22 -0
- package/neural-interface/public/shared/ui-file-explorer.js +481 -2496
- package/neural-interface/public/shared/ui-file-links.js +103 -0
- package/neural-interface/public/shared/ui-git-bash.js +124 -0
- package/neural-interface/public/shared/ui-help.js +26 -0
- package/neural-interface/public/shared/ui-invite.js +126 -116
- package/neural-interface/public/shared/ui-judgments.js +10 -1
- package/neural-interface/public/shared/ui-keybinds.js +4 -0
- package/neural-interface/public/shared/ui-loading.js +187 -19
- package/neural-interface/public/shared/ui-menubar.js +25 -33
- package/neural-interface/public/shared/ui-native-loop-router-state.js +11 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +15 -2
- package/neural-interface/public/shared/ui-navbar.js +48 -22
- 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 +509 -490
- package/neural-interface/public/shared/ui-sidepanel-runtime.js +2 -1
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -1
- package/neural-interface/public/shared/ui-sync.js +22 -0
- package/neural-interface/public/shared/ui-terminal.js +40 -5
- package/neural-interface/public/shared/ui-tool-updates.js +5 -0
- package/neural-interface/public/shared/ui-tunnel.js +130 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +6 -2
- package/neural-interface/public/shared/ui-update.js +594 -5
- package/neural-interface/public/shared/ui-whatsapp.js +21 -6
- package/neural-interface/public/shared/ui-whiteboard.js +12 -0
- package/neural-interface/public/shared/ui-worker-end.js +245 -0
- package/neural-interface/public/shared/ui-workspaces.js +41 -27
- package/neural-interface/public/shared/whatsapp/wa-view.js +51 -8
- package/neural-interface/public/shared/worker-end.js +253 -0
- package/neural-interface/public/sw.js +2 -2
- package/neural-interface/public/variant/2d/main.js +10 -1
- package/neural-interface/public/variant/3d/main.js +10 -1
- package/neural-interface/public/vendor/codemirror/chunks/apl-CSDKT72Z.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/asciiarmor-JYYPU5BM.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/asn1-NRWCZDA6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/asterisk-5OU6D4ZQ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/brainfuck-ID4N4SYC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-4RZWGCS2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-ACTJM3JR.js +11 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-S6BMAXLK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-TO2RDOHQ.js +3 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-US2GMZZQ.js +13 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-WYYO5ZAJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-XALZTDJC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-YRNUTRDV.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/chunk-Z3QOKH62.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/clike-OWQBSOGL.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/clojure-KV75UQWC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/cmake-GTEP5Y3C.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/cobol-WCZ7QEGJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/coffeescript-TGLBOT6B.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/commonlisp-WVVI432V.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/crystal-S6R6HLKQ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/css-PDA2RINP.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/cypher-HL5QPL4C.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/d-HHJH2HAJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/diff-MN3A35BY.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-25SQLBVS.js +3 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-27ZGGJJS.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-4E52OJIF.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-6FT73XDC.js +2 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-BE6YGRMW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-CJSGKW2O.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-CRPH2WLI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-CTG7JEQN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-I3FEVELX.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-IM5BBSWZ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-KERUKTIF.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-LXTMWZAM.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-MABASSET.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-MJVBUZLL.js +3 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-MNB3WZVU.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-QYWXOE3U.js +7 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-TEBOFWLZ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-UNXFROM3.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-XL2SLQO6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-XO42Y3AP.js +6 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-Y2WWDWJK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-YFEZKWMU.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dist-ZY7SWQO6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dockerfile-3Y4R4NCH.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dtd-5343GJ4P.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/dylan-FI2CXSW2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ebnf-GNQ77YWA.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ecl-MRPUAE2L.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/eiffel-DZROES27.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/elm-4KICRFKQ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/erlang-3IHYC263.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/factor-C6D3E5UK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/fcl-VYTWUJMI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/forth-ZBO2EH5M.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/fortran-5NDCRWIK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/gas-SKRMOXFP.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/gherkin-L45YXZLW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/groovy-GLPTLN44.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/haskell-E7NF7P4Y.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/haxe-K2NVDOB6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/http-Q6DRQIJB.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/idl-MZYNJVLN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/javascript-6YRYK2HR.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/julia-HXEL2T5G.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/livescript-MV7CI2JZ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/lua-E36NHOOD.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mathematica-3XOZZCMC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mbox-ODYGFKS7.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mirc-WB43AWF5.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mllike-ZT6ET7ZH.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/modelica-LLMZPFGA.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mscgen-2OPNNYFH.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/mumps-6P3HWJH6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/nginx-TCGKQTRW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/nsis-ATIGIXTJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ntriples-5PLBI5OV.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/octave-QF2S3NL6.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/oz-JFIVFFH2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/pascal-JG6SW76V.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/perl-4B3IWVVO.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/pig-ABEBH4MI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/powershell-H32XE7TL.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/properties-NN644MMA.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/protobuf-YKWQK2J3.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/pug-RIYXEKFW.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/puppet-JZQ5WPEV.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/python-EBCGGHAC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/q-5UMH2YQY.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/r-7XMGG453.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/rpm-IEV7TSLR.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ruby-T4SPFPNM.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sas-GEDX67ET.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/scheme-FTLOWKPC.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/shell-HUFRKFSJ.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sieve-P5QUDVYO.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/smalltalk-2SORJNQI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/solr-M22TGAR5.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sparql-4M3KL752.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/spreadsheet-3K23LA4N.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/sql-VHRFMUBI.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/stex-QZDAQUY2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/stylus-7ZDKAKBD.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/swift-WCLCLGMR.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/tcl-JLMU6WOK.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/textile-4CHDKZ4T.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/tiddlywiki-DKMCZZQ4.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/tiki-F4JIG36Q.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/toml-BHMHTIM2.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/troff-YQ2KV5NT.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ttcn-ZHRCVFJY.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/ttcn-cfg-KJOVTY4X.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/turtle-535P5N6I.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/vb-76UMQHOT.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/vbscript-CGNDTK6Z.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/velocity-VSJDO5T5.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/verilog-4T6ETXIP.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/vhdl-T7FNAXUN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/webidl-P6MJSJ6J.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/xquery-UOVILRGN.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/yacas-CV2APROL.js +1 -0
- package/neural-interface/public/vendor/codemirror/chunks/z80-3KFNVM4M.js +1 -0
- package/neural-interface/public/vendor/codemirror/codemirror-6.43.14-75f05e67.min.js +2 -0
- package/neural-interface/public/vendor/codemirror/manifest.json +60 -0
- package/neural-interface/scripts/build-vendor.mjs +78 -2
- package/neural-interface/scripts/vendor-codemirror-entry.js +121 -0
- package/neural-interface/server.js +2085 -1629
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/package.json +5 -8
- package/setup.js +53 -15
- package/benchmarks/browser-live-results.json +0 -79
- package/benchmarks/browser-v2-results.json +0 -258
- package/neural-interface/lib/codex-capabilities.d.ts +0 -41
- package/neural-interface/public/category-logos/claude.svg +0 -1
- package/neural-interface/public/category-logos/gemini-color.svg +0 -1
- package/neural-interface/public/category-logos/openai.svg +0 -1
- package/neural-interface/public/category-logos/synabun.png +0 -0
- package/neural-interface/public/claude.svg +0 -1
- package/neural-interface/public/gallery.svg +0 -6
- package/neural-interface/public/leonardoai.svg +0 -1
- package/neural-interface/public/mcp.svg +0 -4
- package/neural-interface/public/opencode-logo-dark-square.svg +0 -1
- package/neural-interface/public/pin-svgrepo-com.svg +0 -25
- package/neural-interface/public/sessionicon.svg +0 -8
- package/neural-interface/public/toolbar-album.svg +0 -8
- package/neural-interface/public/toolbar-question.svg +0 -6
- package/neural-interface/public/toolbar-sessions.svg +0 -6
- package/neural-interface/scripts/codex-protocol-fixture.mjs +0 -83
- package/skills/synabun/synabunicon.png +0 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
// ── The File Explorer's watcher ──
|
|
2
|
+
// Tells the page which of the folders it shows changed on disk, and when the
|
|
3
|
+
// git state of the project may have, without the page asking again and again.
|
|
4
|
+
// It costs nothing while nothing changes: the operating system reports changes,
|
|
5
|
+
// nothing is polled.
|
|
6
|
+
//
|
|
7
|
+
// Two ways to watch, by what the system offers:
|
|
8
|
+
// recursive one watcher on the project's folder (macOS and Windows have it
|
|
9
|
+
// natively). Every change below the folder arrives; the ones the
|
|
10
|
+
// page did not ask about are dropped here.
|
|
11
|
+
// folders one watcher per folder the page shows (Linux, where a recursive
|
|
12
|
+
// watch is a watch per sub-folder), plus one on .git.
|
|
13
|
+
// Changes are collected for a moment and sent together. Dependencies are
|
|
14
|
+
// injected: the tests drive it with real folders and with a fake `watch`.
|
|
15
|
+
//
|
|
16
|
+
// A watcher that exists is not a watch that works: the system may have no
|
|
17
|
+
// watches left (ENOSPC on Linux), or lose one it had. `state()` says what is
|
|
18
|
+
// really watched, and `onState` when that changes, so the page can read again
|
|
19
|
+
// by itself where nothing will tell it.
|
|
20
|
+
//
|
|
21
|
+
// A watch that failed is not asked for again at once. A watch that is lost
|
|
22
|
+
// each time it is opened would otherwise be opened, lost and opened again as
|
|
23
|
+
// fast as the page and the system can answer one another. It is tried again
|
|
24
|
+
// after a wait that doubles (a second, two, four, ... a minute at most) and
|
|
25
|
+
// starts over once a watch has held for a minute; until then it stays a watch
|
|
26
|
+
// that is not there, whatever folders the page shows meanwhile.
|
|
27
|
+
|
|
28
|
+
import { existsSync, watch as fsWatch } from 'node:fs';
|
|
29
|
+
import { dirname, join, relative, sep } from 'node:path';
|
|
30
|
+
|
|
31
|
+
export const MAX_WATCHED_DIRS = 600;
|
|
32
|
+
/** A watch that failed is tried again after this long, then after twice that, and so on. */
|
|
33
|
+
export const RETRY_FIRST_MS = 1000;
|
|
34
|
+
/** ... and never less often than this. */
|
|
35
|
+
export const RETRY_MAX_MS = 60000;
|
|
36
|
+
/** A watch that held this long was no part of a run of failures: the next wait is the first one again. */
|
|
37
|
+
export const RETRY_QUIET_MS = 60000;
|
|
38
|
+
/** The files of .git whose change means "commit, stage, checkout or merge": the git state is read again. */
|
|
39
|
+
const GIT_STATE_FILES = /^(index|HEAD|ORIG_HEAD|MERGE_HEAD|CHERRY_PICK_HEAD|REVERT_HEAD|packed-refs)$/;
|
|
40
|
+
/** A folder that is not there (any more) is no watch that failed: its next listing says what is true. */
|
|
41
|
+
const NOT_THERE = new Set(['ENOENT', 'ENOTDIR']);
|
|
42
|
+
|
|
43
|
+
/** Which way this system is watched. */
|
|
44
|
+
export function watchStrategy(platform = process.platform) {
|
|
45
|
+
return platform === 'darwin' || platform === 'win32' ? 'recursive' : 'folders';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {object} o
|
|
50
|
+
* @param {string} o.root the project's folder, canonical
|
|
51
|
+
* @param {'recursive' | 'folders'} [o.strategy]
|
|
52
|
+
* @param {(change: { dirs: string[], git: boolean }) => void} o.onChange `dirs`: watched folders (canonical) whose
|
|
53
|
+
* entries changed; `git`: the git state may have changed
|
|
54
|
+
* @param {(error: Error) => void} [o.onError] the watch on the project's folder was lost
|
|
55
|
+
* @param {(state: { scope: 'tree' | 'folders', live: 'full' | 'partial' | 'none' }) => void} [o.onState] what is
|
|
56
|
+
* really watched changed (see `state()`); not called for the state it starts in
|
|
57
|
+
* @param {(relativePath: string) => boolean} [o.ignoresGit] a path git ignores: a change there is no change of state
|
|
58
|
+
* @param {typeof fsWatch} [o.watch] @param {(path: string) => boolean} [o.exists]
|
|
59
|
+
* @param {number} [o.debounceMs] @param {number} [o.maxWaitMs]
|
|
60
|
+
* @param {() => number} [o.now] @param {(fn: () => void, ms: number) => any} [o.setTimer] @param {(timer: any) => void} [o.clearTimer]
|
|
61
|
+
* the clock of the waits between two attempts at a watch that failed (a test moves it by hand)
|
|
62
|
+
* @returns {{ setDirs: (dirs: string[]) => void, close: () => void, count: () => number, strategy: string,
|
|
63
|
+
* state: () => { scope: 'tree' | 'folders', live: 'full' | 'partial' | 'none' } }}
|
|
64
|
+
*/
|
|
65
|
+
export function createTreeWatcher({
|
|
66
|
+
root, strategy = watchStrategy(), onChange, onError = () => {}, onState = () => {}, ignoresGit = () => false,
|
|
67
|
+
watch = fsWatch, exists = existsSync, debounceMs = 120, maxWaitMs = 500,
|
|
68
|
+
now = () => Date.now(), setTimer = (fn, ms) => setTimeout(fn, ms), clearTimer = (timer) => clearTimeout(timer),
|
|
69
|
+
}) {
|
|
70
|
+
let closed = false;
|
|
71
|
+
let wanted = new Set([root]); // the folders the page shows
|
|
72
|
+
let capped = false; // the page shows more folders than are watched
|
|
73
|
+
const watchers = new Map(); // what is watched → FSWatcher
|
|
74
|
+
const failed = new Set(); // what should be watched and is not (no watches left, a watch that was lost)
|
|
75
|
+
const openedAt = new Map(); // what is watched → when that watch was opened
|
|
76
|
+
let retryMs = 0; // the wait that is running, or ran last
|
|
77
|
+
let retryAt = 0; // nothing that failed is asked for again before this
|
|
78
|
+
let retryTimer = null;
|
|
79
|
+
let refused = false; // the system refused a watch in the pass that is under way
|
|
80
|
+
let said = null; // the `live` that was last reported
|
|
81
|
+
const pending = new Set();
|
|
82
|
+
let pendingGit = false;
|
|
83
|
+
let timer = null;
|
|
84
|
+
let firstAt = 0;
|
|
85
|
+
|
|
86
|
+
const slashed = (path) => (sep === '/' ? path : path.split(sep).join('/'));
|
|
87
|
+
|
|
88
|
+
function flush() {
|
|
89
|
+
timer = null;
|
|
90
|
+
if (closed || (!pending.size && !pendingGit)) return;
|
|
91
|
+
const change = { dirs: [...pending], git: pendingGit };
|
|
92
|
+
pending.clear();
|
|
93
|
+
pendingGit = false;
|
|
94
|
+
try { onChange(change); } catch { /* a listener's failure is not the watcher's */ }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Sent a moment after the last change, and never later than `maxWaitMs` after the first of a burst.
|
|
98
|
+
function schedule() {
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
if (!timer) firstAt = now;
|
|
101
|
+
else clearTimeout(timer);
|
|
102
|
+
const wait = Math.max(0, Math.min(debounceMs, firstAt + maxWaitMs - now));
|
|
103
|
+
timer = setTimeout(flush, wait);
|
|
104
|
+
timer.unref?.();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// One change, by its path below the root ('' is the root itself).
|
|
108
|
+
function note(rel) {
|
|
109
|
+
if (closed) return;
|
|
110
|
+
const path = slashed(rel || '');
|
|
111
|
+
if (path === '.git' || path.startsWith('.git/')) {
|
|
112
|
+
const inside = path.slice(5);
|
|
113
|
+
if (GIT_STATE_FILES.test(inside) || inside.startsWith('refs/')) pendingGit = true;
|
|
114
|
+
} else if (!path || !ignoresGit(path)) {
|
|
115
|
+
pendingGit = true;
|
|
116
|
+
}
|
|
117
|
+
const parent = path.includes('/') ? join(root, dirname(path)) : root;
|
|
118
|
+
if (wanted.has(parent)) pending.add(parent);
|
|
119
|
+
// A watched folder that was itself removed or renamed: whoever shows it reads it again and finds out.
|
|
120
|
+
const self = path ? join(root, path) : root;
|
|
121
|
+
if (self !== parent && wanted.has(self)) pending.add(self);
|
|
122
|
+
if (pending.size || pendingGit) schedule();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* What is really watched. `scope`: every change below the project (`tree`), or only changes in the folders the
|
|
127
|
+
* page shows and in git's own files (`folders`: a change inside a closed folder is not seen). `live`: `full`
|
|
128
|
+
* when all of that is watched, `partial` when some of it could not be, `none` when the project's folder is not.
|
|
129
|
+
*/
|
|
130
|
+
const state = () => ({
|
|
131
|
+
scope: strategy === 'recursive' ? 'tree' : 'folders',
|
|
132
|
+
live: failed.has(root) || !watchers.has(root) ? 'none' : failed.size || capped ? 'partial' : 'full',
|
|
133
|
+
});
|
|
134
|
+
function report() {
|
|
135
|
+
if (closed) return;
|
|
136
|
+
const is = state();
|
|
137
|
+
if (is.live === said) return;
|
|
138
|
+
said = is.live;
|
|
139
|
+
try { onState(is); } catch { /* a listener's failure is not the watcher's */ }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Something that should be watched is not: everything that failed is asked for again together, after a wait.
|
|
143
|
+
// One wait covers whatever fails while it runs; the next one is twice as long, unless the watch that failed
|
|
144
|
+
// had held for a while (`heldSince`): that was no part of a run of failures.
|
|
145
|
+
function backOff(heldSince) {
|
|
146
|
+
const at = now();
|
|
147
|
+
if (retryTimer !== null && at < retryAt) return;
|
|
148
|
+
if (heldSince !== undefined && at - heldSince >= RETRY_QUIET_MS) retryMs = 0;
|
|
149
|
+
retryMs = retryMs ? Math.min(retryMs * 2, RETRY_MAX_MS) : RETRY_FIRST_MS;
|
|
150
|
+
retryAt = at + retryMs;
|
|
151
|
+
if (retryTimer !== null) clearTimer(retryTimer);
|
|
152
|
+
retryTimer = setTimer(() => { retryTimer = null; if (closed) return; sync(); report(); }, retryMs);
|
|
153
|
+
retryTimer?.unref?.();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function open(key, path, options, handler) {
|
|
157
|
+
if (watchers.has(key) || closed) return;
|
|
158
|
+
// Still in its wait: the folders the page shows do not ask the system again for a watch it just refused or lost.
|
|
159
|
+
if (failed.has(key) && now() < retryAt) return;
|
|
160
|
+
let watcher;
|
|
161
|
+
try { watcher = watch(path, { persistent: false, ...options }, handler); }
|
|
162
|
+
catch (error) {
|
|
163
|
+
// A folder that is gone says so in its next listing. Anything else (no watches left) is a change nobody
|
|
164
|
+
// will be told of: it is counted, and the page reads again by itself.
|
|
165
|
+
if (key === root || !NOT_THERE.has(error?.code)) { failed.add(key); refused = true; }
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
failed.delete(key);
|
|
169
|
+
openedAt.set(key, now());
|
|
170
|
+
watcher.on?.('error', () => {
|
|
171
|
+
try { watcher.close(); } catch { /* already closed */ }
|
|
172
|
+
if (watchers.get(key) !== watcher) return; // let go of since: not a watch that was lost
|
|
173
|
+
watchers.delete(key);
|
|
174
|
+
if (closed) return;
|
|
175
|
+
// Tried again after its wait; until then it is a watch that is not there.
|
|
176
|
+
if (key === root || exists(path)) { failed.add(key); backOff(openedAt.get(key)); }
|
|
177
|
+
report();
|
|
178
|
+
if (key === root) { try { onError(new Error('The watch on the project folder was lost.')); } catch { /* as above */ } } else note(relative(root, path));
|
|
179
|
+
});
|
|
180
|
+
watchers.set(key, watcher);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function sync() {
|
|
184
|
+
if (closed) return;
|
|
185
|
+
refused = false;
|
|
186
|
+
try { place(); } finally { if (refused) backOff(); }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function place() {
|
|
190
|
+
if (strategy === 'recursive') {
|
|
191
|
+
open(root, root, { recursive: true }, (type, name) => note(name ? String(name) : ''));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
for (const [key, watcher] of watchers) {
|
|
195
|
+
if (key === '.git' || wanted.has(key)) continue;
|
|
196
|
+
try { watcher.close(); } catch { /* already closed */ }
|
|
197
|
+
watchers.delete(key);
|
|
198
|
+
openedAt.delete(key);
|
|
199
|
+
}
|
|
200
|
+
for (const key of failed) if (key !== '.git' && !wanted.has(key)) failed.delete(key);
|
|
201
|
+
for (const dir of wanted) {
|
|
202
|
+
const rel = relative(root, dir);
|
|
203
|
+
open(dir, dir, {}, (type, name) => note(name ? join(rel, String(name)) : rel));
|
|
204
|
+
}
|
|
205
|
+
open('.git', join(root, '.git'), {}, (type, name) => { if (name) note(join('.git', String(name))); });
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
sync();
|
|
209
|
+
said = state().live;
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
strategy,
|
|
213
|
+
/** The folders the page shows now (canonical paths, the root or below it). */
|
|
214
|
+
setDirs(dirs) {
|
|
215
|
+
const next = new Set([root]);
|
|
216
|
+
capped = false;
|
|
217
|
+
for (const dir of dirs || []) {
|
|
218
|
+
if (typeof dir !== 'string' || !(dir === root || dir.startsWith(root.endsWith(sep) ? root : root + sep)) || next.has(dir)) continue;
|
|
219
|
+
if (next.size >= MAX_WATCHED_DIRS) { capped = strategy !== 'recursive'; break; }
|
|
220
|
+
next.add(dir);
|
|
221
|
+
}
|
|
222
|
+
wanted = next;
|
|
223
|
+
sync();
|
|
224
|
+
report();
|
|
225
|
+
},
|
|
226
|
+
state,
|
|
227
|
+
count: () => watchers.size,
|
|
228
|
+
close() {
|
|
229
|
+
closed = true;
|
|
230
|
+
if (timer) clearTimeout(timer);
|
|
231
|
+
timer = null;
|
|
232
|
+
if (retryTimer !== null) clearTimer(retryTimer);
|
|
233
|
+
retryTimer = null;
|
|
234
|
+
for (const watcher of watchers.values()) { try { watcher.close(); } catch { /* already closed */ } }
|
|
235
|
+
watchers.clear();
|
|
236
|
+
pending.clear();
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — bzip2, read
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// Git for Windows publishes its full installation as a .tar.bz2, and Node has
|
|
6
|
+
// no bzip2. A Windows 10 tar.exe may not have one either (older builds stop at
|
|
7
|
+
// "unable to run program bzip2 -d"), so SynaBun reads the file itself, the same
|
|
8
|
+
// way on the build machine and on the user's: this decoder, then the tar
|
|
9
|
+
// reader in install.js.
|
|
10
|
+
//
|
|
11
|
+
// The whole format of bzip2 1.0 (Julian Seward's): one stream or several
|
|
12
|
+
// concatenated, each "BZh1".."BZh9", blocks of Huffman-coded move-to-front
|
|
13
|
+
// values with their runs, the inverse Burrows-Wheeler transform, the final run
|
|
14
|
+
// decoding. Every block's CRC is compared with the one it carries, and every
|
|
15
|
+
// stream's combined CRC with its trailer: a block that decodes to anything else
|
|
16
|
+
// than what was compressed stops the read. A "randomised" block (written only
|
|
17
|
+
// by bzip2 0.9.0, before 1998) is refused rather than guessed at.
|
|
18
|
+
//
|
|
19
|
+
// What it hands out is the decompressed bytes, block by block
|
|
20
|
+
// (bunzip2Blocks: a generator, so a caller can stop at any block, and see how
|
|
21
|
+
// far into the file it got). Every problem is a Bzip2Error.
|
|
22
|
+
//
|
|
23
|
+
// No imports: install.js and the extraction worker load it, and so does a
|
|
24
|
+
// build, from the application it stages.
|
|
25
|
+
|
|
26
|
+
export class Bzip2Error extends Error {
|
|
27
|
+
constructor(message) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.name = 'Bzip2Error';
|
|
30
|
+
this.code = 'unpack';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const BLOCK_MAGIC_HI = 0x314159; // π
|
|
35
|
+
const BLOCK_MAGIC_LO = 0x265359;
|
|
36
|
+
const END_MAGIC_HI = 0x177245; // √π
|
|
37
|
+
const END_MAGIC_LO = 0x385090;
|
|
38
|
+
const MAX_GROUPS = 6;
|
|
39
|
+
const MAX_ALPHA = 258;
|
|
40
|
+
const MAX_CODE_LEN = 20;
|
|
41
|
+
const MAX_SELECTORS = 18002;
|
|
42
|
+
const RUNA = 0;
|
|
43
|
+
const RUNB = 1;
|
|
44
|
+
const GROUP_SIZE = 50;
|
|
45
|
+
|
|
46
|
+
/** CRC-32 as bzip2 has it: polynomial 0x04c11db7, most significant bit first. */
|
|
47
|
+
const CRC_TABLE = (() => {
|
|
48
|
+
const table = new Uint32Array(256);
|
|
49
|
+
for (let i = 0; i < 256; i++) {
|
|
50
|
+
let c = i << 24;
|
|
51
|
+
for (let k = 0; k < 8; k++) c = (c & 0x80000000) ? (c << 1) ^ 0x04c11db7 : c << 1;
|
|
52
|
+
table[i] = c >>> 0;
|
|
53
|
+
}
|
|
54
|
+
return table;
|
|
55
|
+
})();
|
|
56
|
+
|
|
57
|
+
/** Reads a Buffer bit by bit, most significant bit first. */
|
|
58
|
+
class BitReader {
|
|
59
|
+
constructor(buffer) {
|
|
60
|
+
this.buffer = buffer;
|
|
61
|
+
this.pos = 0; // the next byte to take
|
|
62
|
+
this.bits = 0; // what is held, in the low `count` bits
|
|
63
|
+
this.count = 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** `n` bits (1 to 24) as a number. */
|
|
67
|
+
read(n) {
|
|
68
|
+
while (this.count < n) {
|
|
69
|
+
if (this.pos >= this.buffer.length) throw new Bzip2Error('The archive ends inside a compressed block.');
|
|
70
|
+
this.bits = ((this.bits << 8) | this.buffer[this.pos++]) >>> 0;
|
|
71
|
+
this.count += 8;
|
|
72
|
+
}
|
|
73
|
+
this.count -= n;
|
|
74
|
+
const value = (this.bits >>> this.count) & ((1 << n) - 1);
|
|
75
|
+
this.bits &= (1 << this.count) - 1;
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
bit() {
|
|
80
|
+
if (this.count === 0) {
|
|
81
|
+
if (this.pos >= this.buffer.length) throw new Bzip2Error('The archive ends inside a compressed block.');
|
|
82
|
+
this.bits = this.buffer[this.pos++];
|
|
83
|
+
this.count = 8;
|
|
84
|
+
}
|
|
85
|
+
this.count--;
|
|
86
|
+
const value = (this.bits >>> this.count) & 1;
|
|
87
|
+
this.bits &= (1 << this.count) - 1;
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
read32() {
|
|
92
|
+
return ((this.read(16) << 16) | this.read(16)) >>> 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Drop what is left of the current byte (a stream ends on a byte boundary). */
|
|
96
|
+
align() {
|
|
97
|
+
this.bits = 0;
|
|
98
|
+
this.count = 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
get done() {
|
|
102
|
+
return this.count === 0 && this.pos >= this.buffer.length;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Canonical Huffman decoding tables of one group, as bzip2's hbCreateDecodeTables makes them. */
|
|
107
|
+
function decodeTables(lengths, alphaSize) {
|
|
108
|
+
let minLen = 32;
|
|
109
|
+
let maxLen = 0;
|
|
110
|
+
for (let i = 0; i < alphaSize; i++) {
|
|
111
|
+
if (lengths[i] > maxLen) maxLen = lengths[i];
|
|
112
|
+
if (lengths[i] < minLen) minLen = lengths[i];
|
|
113
|
+
}
|
|
114
|
+
const perm = new Int32Array(MAX_ALPHA);
|
|
115
|
+
const base = new Int32Array(MAX_CODE_LEN + 2);
|
|
116
|
+
const limit = new Int32Array(MAX_CODE_LEN + 1).fill(-1);
|
|
117
|
+
let pp = 0;
|
|
118
|
+
for (let len = minLen; len <= maxLen; len++) for (let j = 0; j < alphaSize; j++) if (lengths[j] === len) perm[pp++] = j;
|
|
119
|
+
for (let i = 0; i < alphaSize; i++) base[lengths[i] + 1]++;
|
|
120
|
+
for (let i = 1; i < base.length; i++) base[i] += base[i - 1];
|
|
121
|
+
let vec = 0;
|
|
122
|
+
for (let len = minLen; len <= maxLen; len++) {
|
|
123
|
+
vec += base[len + 1] - base[len];
|
|
124
|
+
limit[len] = vec - 1;
|
|
125
|
+
vec <<= 1;
|
|
126
|
+
}
|
|
127
|
+
for (let len = minLen + 1; len <= maxLen; len++) base[len] = ((limit[len - 1] + 1) << 1) - base[len];
|
|
128
|
+
return { minLen, maxLen, perm, base, limit };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** The next symbol of a group's code. */
|
|
132
|
+
function nextSymbol(reader, table) {
|
|
133
|
+
let len = table.minLen;
|
|
134
|
+
let code = reader.read(len);
|
|
135
|
+
while (len <= table.maxLen && code > table.limit[len]) {
|
|
136
|
+
len++;
|
|
137
|
+
code = (code << 1) | reader.bit();
|
|
138
|
+
}
|
|
139
|
+
if (len > table.maxLen) throw new Bzip2Error('The archive holds a code its tables do not know.');
|
|
140
|
+
const index = code - table.base[len];
|
|
141
|
+
if (index < 0 || index >= MAX_ALPHA) throw new Bzip2Error('The archive holds a code its tables do not know.');
|
|
142
|
+
return table.perm[index];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* One block, from just after its magic: its bytes (the final run decoding done) and the CRC it carries.
|
|
147
|
+
* `tt` is the block's workspace, as large as the stream's block size.
|
|
148
|
+
*/
|
|
149
|
+
function decodeBlock(reader, tt, blockSize) {
|
|
150
|
+
const storedCrc = reader.read32();
|
|
151
|
+
if (reader.bit()) throw new Bzip2Error('The archive has a randomised block (bzip2 0.9.0), which this reader does not read.');
|
|
152
|
+
const origPtr = reader.read(24);
|
|
153
|
+
|
|
154
|
+
// Which byte values the block uses.
|
|
155
|
+
const used = [];
|
|
156
|
+
const inUse16 = reader.read(16);
|
|
157
|
+
for (let i = 0; i < 16; i++) {
|
|
158
|
+
if (!(inUse16 & (0x8000 >>> i))) continue;
|
|
159
|
+
const bits = reader.read(16);
|
|
160
|
+
for (let j = 0; j < 16; j++) if (bits & (0x8000 >>> j)) used.push(i * 16 + j);
|
|
161
|
+
}
|
|
162
|
+
if (!used.length) throw new Bzip2Error('The archive has a block that uses no byte value.');
|
|
163
|
+
const alphaSize = used.length + 2;
|
|
164
|
+
const eob = used.length + 1;
|
|
165
|
+
|
|
166
|
+
// The Huffman groups and which one codes each run of fifty symbols.
|
|
167
|
+
const groups = reader.read(3);
|
|
168
|
+
if (groups < 2 || groups > MAX_GROUPS) throw new Bzip2Error('The archive has a block with an impossible number of code tables.');
|
|
169
|
+
const selectorCount = reader.read(15);
|
|
170
|
+
if (selectorCount < 1) throw new Bzip2Error('The archive has a block without code selectors.');
|
|
171
|
+
const mtfGroups = [0, 1, 2, 3, 4, 5].slice(0, groups);
|
|
172
|
+
const selectors = new Uint8Array(Math.min(selectorCount, MAX_SELECTORS));
|
|
173
|
+
for (let i = 0; i < selectorCount; i++) {
|
|
174
|
+
let j = 0;
|
|
175
|
+
while (reader.bit()) {
|
|
176
|
+
j++;
|
|
177
|
+
if (j >= groups) throw new Bzip2Error('The archive has a block with an impossible code selector.');
|
|
178
|
+
}
|
|
179
|
+
// Selectors past the most a block can use are read and dropped, as bzip2 1.0.8 does.
|
|
180
|
+
if (i >= MAX_SELECTORS) continue;
|
|
181
|
+
const value = mtfGroups[j];
|
|
182
|
+
for (let k = j; k > 0; k--) mtfGroups[k] = mtfGroups[k - 1];
|
|
183
|
+
mtfGroups[0] = value;
|
|
184
|
+
selectors[i] = value;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const tables = [];
|
|
188
|
+
for (let t = 0; t < groups; t++) {
|
|
189
|
+
const lengths = new Uint8Array(alphaSize);
|
|
190
|
+
let current = reader.read(5);
|
|
191
|
+
for (let i = 0; i < alphaSize; i++) {
|
|
192
|
+
for (;;) {
|
|
193
|
+
if (current < 1 || current > MAX_CODE_LEN) throw new Bzip2Error('The archive has a block with an impossible code length.');
|
|
194
|
+
if (!reader.bit()) break;
|
|
195
|
+
current += reader.bit() ? -1 : 1;
|
|
196
|
+
}
|
|
197
|
+
lengths[i] = current;
|
|
198
|
+
}
|
|
199
|
+
tables.push(decodeTables(lengths, alphaSize));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// The move-to-front values and their runs: the block before the inverse transform.
|
|
203
|
+
const counts = new Int32Array(256);
|
|
204
|
+
const order = new Uint8Array(256);
|
|
205
|
+
for (let i = 0; i < 256; i++) order[i] = i;
|
|
206
|
+
let length = 0;
|
|
207
|
+
let selector = 0;
|
|
208
|
+
let left = 0;
|
|
209
|
+
let table = null;
|
|
210
|
+
const next = () => {
|
|
211
|
+
if (left === 0) {
|
|
212
|
+
if (selector >= selectors.length) throw new Bzip2Error('The archive has a block that runs past its code selectors.');
|
|
213
|
+
table = tables[selectors[selector++]];
|
|
214
|
+
left = GROUP_SIZE;
|
|
215
|
+
}
|
|
216
|
+
left--;
|
|
217
|
+
return nextSymbol(reader, table);
|
|
218
|
+
};
|
|
219
|
+
let symbol = next();
|
|
220
|
+
for (;;) {
|
|
221
|
+
if (symbol === eob) break;
|
|
222
|
+
if (symbol === RUNA || symbol === RUNB) {
|
|
223
|
+
let run = 0;
|
|
224
|
+
let weight = 1;
|
|
225
|
+
do {
|
|
226
|
+
run += (symbol === RUNA ? 1 : 2) * weight;
|
|
227
|
+
weight <<= 1;
|
|
228
|
+
if (run > blockSize) throw new Bzip2Error('The archive has a block larger than its stream says blocks are.');
|
|
229
|
+
symbol = next();
|
|
230
|
+
} while (symbol === RUNA || symbol === RUNB);
|
|
231
|
+
const value = used[order[0]];
|
|
232
|
+
if (length + run > blockSize) throw new Bzip2Error('The archive has a block larger than its stream says blocks are.');
|
|
233
|
+
counts[value] += run;
|
|
234
|
+
tt.fill(value, length, length + run);
|
|
235
|
+
length += run;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
if (length >= blockSize) throw new Bzip2Error('The archive has a block larger than its stream says blocks are.');
|
|
239
|
+
const index = symbol - 1;
|
|
240
|
+
const front = order[index];
|
|
241
|
+
order.copyWithin(1, 0, index);
|
|
242
|
+
order[0] = front;
|
|
243
|
+
const value = used[front];
|
|
244
|
+
counts[value]++;
|
|
245
|
+
tt[length++] = value;
|
|
246
|
+
symbol = next();
|
|
247
|
+
}
|
|
248
|
+
if (origPtr >= length) throw new Bzip2Error('The archive has a block whose start lies outside it.');
|
|
249
|
+
|
|
250
|
+
// The inverse Burrows-Wheeler transform: each byte's successor in the upper 24 bits.
|
|
251
|
+
const start = new Int32Array(256);
|
|
252
|
+
for (let i = 0, sum = 0; i < 256; i++) { start[i] = sum; sum += counts[i]; }
|
|
253
|
+
for (let i = 0; i < length; i++) {
|
|
254
|
+
const value = tt[i] & 0xff;
|
|
255
|
+
tt[start[value]++] |= i << 8;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// The final run decoding (four equal bytes and a count), with the CRC over what comes out.
|
|
259
|
+
let out = Buffer.allocUnsafe(Math.max(1024, length + (length >>> 2)));
|
|
260
|
+
let at = 0;
|
|
261
|
+
let crc = 0xffffffff;
|
|
262
|
+
const room = (need) => {
|
|
263
|
+
const bigger = Buffer.allocUnsafe(Math.max(need, out.length * 2));
|
|
264
|
+
out.copy(bigger, 0, 0, at);
|
|
265
|
+
out = bigger;
|
|
266
|
+
};
|
|
267
|
+
let pos = tt[origPtr] >>> 8;
|
|
268
|
+
let last = -1;
|
|
269
|
+
let same = 0;
|
|
270
|
+
for (let i = 0; i < length; i++) {
|
|
271
|
+
const entry = tt[pos];
|
|
272
|
+
const byte = entry & 0xff;
|
|
273
|
+
pos = entry >>> 8;
|
|
274
|
+
if (same === 4) {
|
|
275
|
+
if (at + byte > out.length) room(at + byte);
|
|
276
|
+
for (let k = 0; k < byte; k++) {
|
|
277
|
+
out[at++] = last;
|
|
278
|
+
crc = (crc << 8) ^ CRC_TABLE[((crc >>> 24) ^ last) & 0xff];
|
|
279
|
+
}
|
|
280
|
+
same = 0;
|
|
281
|
+
last = -1;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (byte === last) same++;
|
|
285
|
+
else { last = byte; same = 1; }
|
|
286
|
+
if (at === out.length) room(at + 1);
|
|
287
|
+
out[at++] = byte;
|
|
288
|
+
crc = (crc << 8) ^ CRC_TABLE[((crc >>> 24) ^ byte) & 0xff];
|
|
289
|
+
}
|
|
290
|
+
crc = (~crc) >>> 0;
|
|
291
|
+
if (crc !== storedCrc) throw new Bzip2Error('A block of the archive does not decode to what was compressed (CRC mismatch).');
|
|
292
|
+
return { data: out.subarray(0, at), crc };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* The decompressed bytes of `buffer` (one or more concatenated bzip2 streams), one block at a time. `progress`,
|
|
297
|
+
* when given, is told after each block how far into `buffer` the reader is.
|
|
298
|
+
* @param {Buffer} buffer
|
|
299
|
+
* @param {{ progress?: (consumed: number, total: number) => void }} [o]
|
|
300
|
+
*/
|
|
301
|
+
export function* bunzip2Blocks(buffer, { progress } = {}) {
|
|
302
|
+
const reader = new BitReader(buffer);
|
|
303
|
+
let streams = 0;
|
|
304
|
+
while (!reader.done) {
|
|
305
|
+
// Zero bytes after the last stream are padding some writers leave; anything else has to be a stream.
|
|
306
|
+
if (streams > 0 && buffer.subarray(reader.pos).every((byte) => byte === 0)) break;
|
|
307
|
+
if (reader.read(8) !== 0x42 || reader.read(8) !== 0x5a || reader.read(8) !== 0x68) throw new Bzip2Error(streams ? 'The archive has something after its last stream.' : 'The archive is not a bzip2 file.');
|
|
308
|
+
const level = reader.read(8) - 0x30;
|
|
309
|
+
if (level < 1 || level > 9) throw new Bzip2Error('The archive names an impossible block size.');
|
|
310
|
+
const blockSize = level * 100000;
|
|
311
|
+
const tt = new Uint32Array(blockSize);
|
|
312
|
+
let combined = 0;
|
|
313
|
+
for (;;) {
|
|
314
|
+
const hi = reader.read(24);
|
|
315
|
+
const lo = reader.read(24);
|
|
316
|
+
if (hi === BLOCK_MAGIC_HI && lo === BLOCK_MAGIC_LO) {
|
|
317
|
+
const block = decodeBlock(reader, tt, blockSize);
|
|
318
|
+
combined = (((combined << 1) | (combined >>> 31)) ^ block.crc) >>> 0;
|
|
319
|
+
progress?.(reader.pos, buffer.length);
|
|
320
|
+
if (block.data.length) yield block.data;
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
if (hi === END_MAGIC_HI && lo === END_MAGIC_LO) {
|
|
324
|
+
if (reader.read32() !== combined) throw new Bzip2Error('The archive does not decode to what was compressed (stream CRC mismatch).');
|
|
325
|
+
reader.align();
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
throw new Bzip2Error('The archive has something that is not a bzip2 block.');
|
|
329
|
+
}
|
|
330
|
+
streams++;
|
|
331
|
+
}
|
|
332
|
+
if (!streams) throw new Bzip2Error('The archive is empty.');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** All of `buffer`, decompressed (tests and small files). */
|
|
336
|
+
export function bunzip2(buffer) {
|
|
337
|
+
const parts = [...bunzip2Blocks(buffer)];
|
|
338
|
+
return Buffer.concat(parts);
|
|
339
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Git Bash for the user's own `claude`
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// Every Claude Code that SynaBun starts gets its Git Bash in its environment
|
|
6
|
+
// (resolver.js gitBashChildEnv). A `claude` the user starts in another
|
|
7
|
+
// terminal does not: on a PC whose only Git Bash is SynaBun's copy, that one
|
|
8
|
+
// is named in the `env` block of ~/.claude/settings.json, which Claude Code
|
|
9
|
+
// applies before it looks for Git Bash (checked in its 2.1.302 build:
|
|
10
|
+
// applySafeConfigEnvironmentVariables applies the user settings' env in full,
|
|
11
|
+
// in init(), before the Git Bash lookup).
|
|
12
|
+
//
|
|
13
|
+
// SynaBun's copy is in use env.CLAUDE_CODE_GIT_BASH_PATH = its bash.exe,
|
|
14
|
+
// unless the user put a value of their own there
|
|
15
|
+
// it is not a value that is SynaBun's (a path inside one of
|
|
16
|
+
// its copies) is removed; any other is left
|
|
17
|
+
//
|
|
18
|
+
// Windows only. The file is read and written by the caller's functions
|
|
19
|
+
// (server.js readClaudeSettingsForWrite / writeClaudeSettings: a file that is
|
|
20
|
+
// not JSON is never written over, and the write is atomic). Never throws.
|
|
21
|
+
|
|
22
|
+
import { GIT_BASH_ENV, insideAny } from './resolver.js';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Bring the user's settings in line with the Git Bash in use.
|
|
26
|
+
* @param {object} o
|
|
27
|
+
* @param {{ source: string|null, path: string|null }} o.resolution resolver.js resolveGitBash()
|
|
28
|
+
* @param {string} o.settingsPath ~/.claude/settings.json
|
|
29
|
+
* @param {(path: string) => object} o.read {} when the file does not exist; throws when it is not JSON
|
|
30
|
+
* @param {(path: string, settings: object) => void} o.write
|
|
31
|
+
* @param {string[]} o.ownRoots SynaBun's own Git folders
|
|
32
|
+
* @returns {{ state: 'skipped' | 'unchanged' | 'written' | 'removed' | 'kept-user-value' | 'error', value?: string|null, message?: string }}
|
|
33
|
+
*/
|
|
34
|
+
export function syncClaudeSettingsGitBash({ resolution, settingsPath, read, write, ownRoots = [], platform = process.platform }) {
|
|
35
|
+
if (platform !== 'win32' || !settingsPath) return { state: 'skipped' };
|
|
36
|
+
const ours = resolution?.source === 'bundled' || resolution?.source === 'downloaded' ? resolution.path : null;
|
|
37
|
+
let settings;
|
|
38
|
+
try { settings = read(settingsPath); } catch (error) {
|
|
39
|
+
return { state: 'error', message: String(error?.message || error) };
|
|
40
|
+
}
|
|
41
|
+
if (!settings || typeof settings !== 'object' || Array.isArray(settings)) return { state: 'error', message: `${settingsPath} does not hold a settings object.` };
|
|
42
|
+
const env = settings.env && typeof settings.env === 'object' && !Array.isArray(settings.env) ? settings.env : null;
|
|
43
|
+
const current = typeof env?.[GIT_BASH_ENV] === 'string' ? env[GIT_BASH_ENV] : null;
|
|
44
|
+
const isOurs = current !== null && insideAny(current, ownRoots);
|
|
45
|
+
|
|
46
|
+
if (ours) {
|
|
47
|
+
if (current === ours) return { state: 'unchanged', value: ours };
|
|
48
|
+
// A value of the user's own (one that does not work, or the resolver would have taken it) is theirs to change.
|
|
49
|
+
if (current !== null && !isOurs) return { state: 'kept-user-value', value: current };
|
|
50
|
+
settings.env = { ...(env || {}), [GIT_BASH_ENV]: ours };
|
|
51
|
+
} else {
|
|
52
|
+
if (!isOurs) return { state: 'unchanged', value: current };
|
|
53
|
+
const rest = { ...env };
|
|
54
|
+
delete rest[GIT_BASH_ENV];
|
|
55
|
+
if (Object.keys(rest).length) settings.env = rest;
|
|
56
|
+
else delete settings.env;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
write(settingsPath, settings);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return { state: 'error', message: String(error?.message || error) };
|
|
62
|
+
}
|
|
63
|
+
return ours ? { state: 'written', value: ours } : { state: 'removed', value: null };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** The user's own value of CLAUDE_CODE_GIT_BASH_PATH in their settings, or null (what the resolver weighs). */
|
|
67
|
+
export function settingsGitBashValue({ settingsPath, read }) {
|
|
68
|
+
try {
|
|
69
|
+
const settings = read(settingsPath);
|
|
70
|
+
const value = settings?.env?.[GIT_BASH_ENV];
|
|
71
|
+
return typeof value === 'string' && value.trim() ? value.trim() : null;
|
|
72
|
+
} catch { return null; }
|
|
73
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — Git for Windows: the unpacking, in a thread of its own
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// install.js unpackInWorker() starts this with what unpackAndCheck() takes and
|
|
6
|
+
// a shared flag the server raises to stop it. The reading of the .tar.bz2, the
|
|
7
|
+
// writing of some ten thousand files and the digest of what was written take
|
|
8
|
+
// about a minute of CPU: here, they never hold the server's event loop. The
|
|
9
|
+
// thread answers with messages: `step`, `progress` (a few times a second at
|
|
10
|
+
// most), then `done` with the result or `error` with a GitBashError's code.
|
|
11
|
+
|
|
12
|
+
import { parentPort, workerData } from 'node:worker_threads';
|
|
13
|
+
import { asGitBashError, unpackAndCheck } from './install.js';
|
|
14
|
+
|
|
15
|
+
const { flag, ...options } = workerData;
|
|
16
|
+
let last = 0;
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const result = unpackAndCheck({
|
|
20
|
+
...options,
|
|
21
|
+
stopped: () => Atomics.load(flag, 0) === 1,
|
|
22
|
+
onStep: (step) => parentPort.postMessage({ type: 'step', step }),
|
|
23
|
+
onProgress: (progress) => {
|
|
24
|
+
const now = Date.now();
|
|
25
|
+
if (progress.consumed !== progress.total && now - last < 250) return;
|
|
26
|
+
last = now;
|
|
27
|
+
parentPort.postMessage({ type: 'progress', progress });
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
parentPort.postMessage({ type: 'done', result });
|
|
31
|
+
} catch (failure) {
|
|
32
|
+
const error = asGitBashError(failure, 'unpack', 'The archive could not be unpacked.');
|
|
33
|
+
parentPort.postMessage({ type: 'error', code: error.code, message: error.message, detail: error.detail || null });
|
|
34
|
+
}
|