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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawn, spawnSync } from 'child_process';
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, appendFileSync, chmodSync } from 'fs';
|
|
3
3
|
import { join, resolve, isAbsolute } from 'path';
|
|
4
|
+
import { withPackagedPathLast } from './augmented-path.js';
|
|
4
5
|
|
|
5
6
|
const GITHUB_URL_RE = /^https?:\/\/github\.com\/([\w.-]+)\/([\w.-]+?)(?:\.git)?\/?$/i;
|
|
6
7
|
|
|
@@ -87,11 +88,22 @@ export function maskEnv(env) {
|
|
|
87
88
|
return out;
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
/**
|
|
92
|
+
* The environment of a git / package-manager run: this process's, with a
|
|
93
|
+
* packaged application's runtime and npm's global bin after the user's own
|
|
94
|
+
* PATH (augmented-path.js withPackagedPathLast): a repository is installed
|
|
95
|
+
* with the user's npm, pnpm, yarn, uv or pip when they have one, SynaBun's
|
|
96
|
+
* bundled npm only when they have none. Unchanged for an npm or Git install.
|
|
97
|
+
*/
|
|
98
|
+
export function installEnv(extra = {}, base = process.env) {
|
|
99
|
+
return withPackagedPathLast({ ...base, ...extra });
|
|
100
|
+
}
|
|
101
|
+
|
|
90
102
|
async function runCommand(cmd, args, opts = {}) {
|
|
91
103
|
return new Promise((resolvePromise) => {
|
|
92
104
|
const child = spawn(cmd, args, {
|
|
93
105
|
cwd: opts.cwd,
|
|
94
|
-
env:
|
|
106
|
+
env: installEnv(opts.env || {}),
|
|
95
107
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
96
108
|
shell: false,
|
|
97
109
|
});
|
|
@@ -466,7 +478,7 @@ export async function installDependencies({ dataHome, name, repoPath, onLine })
|
|
|
466
478
|
|
|
467
479
|
if (hasPyproject || hasRequirements) {
|
|
468
480
|
if (hasUvLock || hasPyproject) {
|
|
469
|
-
const uvExists = spawnSync('which', ['uv']).status === 0;
|
|
481
|
+
const uvExists = spawnSync('which', ['uv'], { env: installEnv() }).status === 0;
|
|
470
482
|
if (uvExists) {
|
|
471
483
|
logInstall(dataHome, name, 'running uv sync');
|
|
472
484
|
const res = await runCommand('uv', ['sync'], { cwd: repoPath, onLine: (line) => { logInstall(dataHome, name, line); onLine?.(line); } });
|
|
@@ -99,6 +99,15 @@ export function filterInjected(results, { caller, session, generation } = {}, co
|
|
|
99
99
|
if (seen.size > 500) seen.delete(seen.values().next().value);
|
|
100
100
|
return fresh;
|
|
101
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Record memories as already in an Assistant conversation's context (its user-context digest, a
|
|
104
|
+
* nudge or a cue: lib/assistant-user-context.js), in the same ledger automatic recall reads: they
|
|
105
|
+
* are not injected again in that context generation.
|
|
106
|
+
*/
|
|
107
|
+
export function markInjected(rows, { session, generation } = {}) {
|
|
108
|
+
const list = (Array.isArray(rows) ? rows : []).filter(r => r && r.id).map(r => ({ id: r.id, revision: r.revision }));
|
|
109
|
+
if (list.length) filterInjected(list, { caller: 'assistant', session, generation });
|
|
110
|
+
}
|
|
102
111
|
function input(body) {
|
|
103
112
|
if (typeof body?.query !== 'string' || !body.query.trim() || body.query.length > 16000) throw new Error('query must be non-empty text of at most 16000 characters.');
|
|
104
113
|
const out = {query:body.query};
|
|
@@ -316,9 +325,14 @@ async function planConflict(text, body, ctx, retrieve) {
|
|
|
316
325
|
// The assistant passes { origin:'assistant', defer:true }: retrieval and ranking
|
|
317
326
|
// run now, but nothing is rendered or committed to the injection ledger until
|
|
318
327
|
// it calls finish(tier) with the size its prompt-urgency judgment chose;
|
|
319
|
-
// finish(null) withholds the memories.
|
|
320
|
-
|
|
328
|
+
// finish(null) withholds the memories. `divert` (category names; the assistant's
|
|
329
|
+
// user-context engine) keeps those categories out of the rendered block: they
|
|
330
|
+
// are searched and ranked with the rest, then returned apart as `diverted`
|
|
331
|
+
// (never rendered, never committed here). The HTTP route never passes options.
|
|
332
|
+
export async function hookRecall(body = {}, retrieve = retrieveMemory, { origin = null, defer = false, divert = null } = {}) {
|
|
321
333
|
const opts=input(body);
|
|
334
|
+
const divertSet=Array.isArray(divert) && divert.length ? new Set(divert.map(String)) : null;
|
|
335
|
+
const isDiverted=r=>!!divertSet && divertSet.has(String(r.category));
|
|
322
336
|
const ctx=origin ? {...hookContext(body),origin} : hookContext(body);
|
|
323
337
|
const judgeOff=body.judge === false;
|
|
324
338
|
// `surface` implies ranking; `rank:true` alone keeps meaning brief-rank.
|
|
@@ -332,7 +346,7 @@ export async function hookRecall(body = {}, retrieve = retrieveMemory, { origin
|
|
|
332
346
|
return out;
|
|
333
347
|
};
|
|
334
348
|
const skipFollowup=()=>{
|
|
335
|
-
const out=withStale({results:[],context:'',already_present:false,skipped:'referential-followup',estimated_tokens:0,ranked:false,rank_surface:null,judged:0,dropped:[],floor:null});
|
|
349
|
+
const out=withStale({results:[],context:'',already_present:false,skipped:'referential-followup',estimated_tokens:0,ranked:false,rank_surface:null,judged:0,dropped:[],floor:null,diverted:[]});
|
|
336
350
|
return defer ? {...out,deferred:true,candidates:0,finish:()=>out} : out;
|
|
337
351
|
};
|
|
338
352
|
// A judged ranking decides relevance for follow-ups too; the regex is the
|
|
@@ -347,7 +361,8 @@ export async function hookRecall(body = {}, retrieve = retrieveMemory, { origin
|
|
|
347
361
|
const budget=Math.max(100,Math.min(2000,Number(body.token_budget)||600));
|
|
348
362
|
const identity={caller:body.caller,session:body.claudeSessionId || body.session,generation:body.context_generation};
|
|
349
363
|
let candidates=filterInjected(result.results,identity,false);
|
|
350
|
-
|
|
364
|
+
// "Already supplied" is about the block: a diverted category never renders in it.
|
|
365
|
+
const alreadyPresent=result.results.some(r=>!isDiverted(r)) && !candidates.some(r=>!isDiverted(r));
|
|
351
366
|
let ranked=false, scores=null, dropped=[], floor=null, logId=null;
|
|
352
367
|
if (canRank && (candidates.length > 1 || (floorWanted && candidates.length === 1))) {
|
|
353
368
|
const settings=surfaceConfig(surface);
|
|
@@ -370,6 +385,14 @@ export async function hookRecall(body = {}, retrieve = retrieveMemory, { origin
|
|
|
370
385
|
}
|
|
371
386
|
if (!ranked && isReferentialFollowup(opts.query)) return skipFollowup();
|
|
372
387
|
}
|
|
388
|
+
// Diverted categories leave the candidates here, after the ranking and its floor judged them.
|
|
389
|
+
let diverted=[];
|
|
390
|
+
if (divertSet) {
|
|
391
|
+
diverted=candidates.filter(isDiverted).map(r=>({id:r.id,revision:r.revision,category:r.category,project:r.project,content:r.content,
|
|
392
|
+
subcategory:r.payload?.subcategory ?? null,importance:r.payload?.importance ?? null,created_at:r.created_at,updated_at:r.payload?.updated_at ?? r.created_at,
|
|
393
|
+
related_memory_ids:r.payload?.related_memory_ids ?? null,score:r.score,ranked:ranked && scores.has(r.id),relevance:ranked && scores.has(r.id) ? scores.get(r.id) : null}));
|
|
394
|
+
candidates=candidates.filter(r=>!isDiverted(r));
|
|
395
|
+
}
|
|
373
396
|
// The first `lim` candidates that fit `tok` tokens (the classic path: limit / budget).
|
|
374
397
|
const render=(lim,tok)=>{
|
|
375
398
|
const pool=surface ? candidates.slice(0,lim) : candidates;
|
|
@@ -394,7 +417,7 @@ export async function hookRecall(body = {}, retrieve = retrieveMemory, { origin
|
|
|
394
417
|
// `scores` null: the row is still annotated, with no candidates.
|
|
395
418
|
const outcome=(extra)=>({surface,floor,
|
|
396
419
|
candidates:scores ? [...scores].map(([id,relevance])=>({id,relevance,level:relevanceLevel(relevance)})) : [],
|
|
397
|
-
...extra,dropped:dropped.map(d=>d.id)});
|
|
420
|
+
...extra,dropped:dropped.map(d=>d.id),...(diverted.length ? {diverted:diverted.map(d=>d.id)} : {})});
|
|
398
421
|
// Commit what was injected to the ledger, record it on the ranking's log row, shape the answer.
|
|
399
422
|
const finalize=({results,context,delivered},extra={})=>{
|
|
400
423
|
filterInjected(delivered,identity);
|
|
@@ -402,6 +425,7 @@ export async function hookRecall(body = {}, retrieve = retrieveMemory, { origin
|
|
|
402
425
|
const out={results:results.filter(r=>delivered.some(h=>h.id===r.id)),context,already_present:alreadyPresent,
|
|
403
426
|
estimated_tokens:estimateTokens(context),degraded:result.degraded,ranked,rank_surface:ranked ? surface : null,
|
|
404
427
|
judged:scores?.size ?? 0,dropped,floor};
|
|
428
|
+
if (divertSet) out.diverted=diverted;
|
|
405
429
|
if (ranked && !delivered.length && dropped.length) out.skipped='judged-irrelevant';
|
|
406
430
|
return out;
|
|
407
431
|
};
|
|
@@ -415,7 +439,7 @@ export async function hookRecall(body = {}, retrieve = retrieveMemory, { origin
|
|
|
415
439
|
if (!tier) {
|
|
416
440
|
if (logId) annotateTypeSafeLog(logId,outcome({injected:[],withheld:'prompt-urgency'}));
|
|
417
441
|
settled={results:[],context:'',already_present:false,estimated_tokens:0,degraded:result.degraded,ranked,
|
|
418
|
-
rank_surface:ranked ? surface : null,judged:scores?.size ?? 0,dropped,floor,withheld:'prompt-urgency'};
|
|
442
|
+
rank_surface:ranked ? surface : null,judged:scores?.size ?? 0,dropped,floor,withheld:'prompt-urgency',...(divertSet ? {diverted:[]} : {})};
|
|
419
443
|
return settled;
|
|
420
444
|
}
|
|
421
445
|
const lim=Math.max(1,Math.min(50,Math.floor(Number(tier.limit))||limit));
|
|
@@ -424,7 +448,7 @@ export async function hookRecall(body = {}, retrieve = retrieveMemory, { origin
|
|
|
424
448
|
return settled;
|
|
425
449
|
};
|
|
426
450
|
return {deferred:true,ranked,rank_surface:ranked ? surface : null,judged:scores?.size ?? 0,dropped,floor,
|
|
427
|
-
already_present:alreadyPresent,degraded:result.degraded,candidates:candidates.length,finish};
|
|
451
|
+
already_present:alreadyPresent,degraded:result.degraded,candidates:candidates.length,...(divertSet ? {diverted} : {}),finish};
|
|
428
452
|
}
|
|
429
453
|
|
|
430
454
|
/**
|
|
@@ -248,6 +248,9 @@ export async function createCodexNativeLoopAdapter(options = {}) {
|
|
|
248
248
|
collectMedia = null,
|
|
249
249
|
// Assistant task runs: the browser policy's hook and the run's notes (a function: never in the state file).
|
|
250
250
|
runMode = 'loop', onNote = null, browserPolicyTrust = null,
|
|
251
|
+
// Inherited variables to remove before extraEnv applies (the Codex account's launch:
|
|
252
|
+
// lib/codex-accounts.js launchFor() — inherited OpenAI/Codex credentials never reach the run).
|
|
253
|
+
unsetEnv = [],
|
|
251
254
|
} = options;
|
|
252
255
|
const permissionPolicy = normalizePermissionPolicy(rawPolicy);
|
|
253
256
|
const capability = normalizeCapability(rawCapability);
|
|
@@ -281,7 +284,9 @@ export async function createCodexNativeLoopAdapter(options = {}) {
|
|
|
281
284
|
// Computer-use workers: the grant unlocks the `computer` group in the MCP child.
|
|
282
285
|
SYNABUN_DESKTOP_GRANT: typeof desktopGrantProvider === 'function' ? desktopGrantProvider() || undefined : undefined,
|
|
283
286
|
});
|
|
284
|
-
const
|
|
287
|
+
const inherited = { ...process.env };
|
|
288
|
+
for (const key of Array.isArray(unsetEnv) ? unsetEnv : []) delete inherited[key];
|
|
289
|
+
const env = stringEnv({ ...inherited, ...pins, CODEX_HOME: codexHome, ...(browserPolicy ? { SYNABUN_BROWSER_POLICY_CWD: cwd || process.cwd() } : {}), ...stringEnv(extraEnv) });
|
|
285
290
|
const config = {};
|
|
286
291
|
if (Object.keys(pins).length) config.mcp_servers = { SynaBun: { env: pins } };
|
|
287
292
|
if (extended) config.model_context_window = Math.floor(Number(modelContextWindow));
|
|
@@ -423,6 +428,11 @@ export async function createClaudeNativeLoopAdapter(options = {}) {
|
|
|
423
428
|
extraEnv = {}, permissionPolicy: rawPolicy = 'auto', permissionBroker = null,
|
|
424
429
|
capability: rawCapability = 'full', maxBudgetUsd = null, outputSchema = null, runMode = 'loop',
|
|
425
430
|
desktopGrantProvider = null,
|
|
431
|
+
// Inherited variables to remove before extraEnv applies (the Claude account's launch:
|
|
432
|
+
// credentials the server was started with never reach a worker).
|
|
433
|
+
unsetEnv = [],
|
|
434
|
+
// The host's last word on the environment: on Windows the Git Bash it names (lib/git-bash/).
|
|
435
|
+
childEnv = null,
|
|
426
436
|
} = options;
|
|
427
437
|
const permissionPolicy = normalizePermissionPolicy(rawPolicy);
|
|
428
438
|
const capability = normalizeCapability(rawCapability);
|
|
@@ -432,8 +442,10 @@ export async function createClaudeNativeLoopAdapter(options = {}) {
|
|
|
432
442
|
let alive = true;
|
|
433
443
|
let sessionId = null;
|
|
434
444
|
let activeTurn = null;
|
|
435
|
-
const
|
|
436
|
-
|
|
445
|
+
const inherited = cleanClaudeEnvironment();
|
|
446
|
+
for (const key of Array.isArray(unsetEnv) ? unsetEnv : []) delete inherited[key];
|
|
447
|
+
const ownEnv = stringEnv({
|
|
448
|
+
...inherited,
|
|
437
449
|
SYNABUN_TERMINAL_SESSION: runId,
|
|
438
450
|
SYNABUN_PROJECT: cwd ? memoryProject(cwd) : 'global',
|
|
439
451
|
SYNABUN_PROFILE: 'full',
|
|
@@ -442,6 +454,7 @@ export async function createClaudeNativeLoopAdapter(options = {}) {
|
|
|
442
454
|
SYNABUN_RUN_MODE: runMode === 'task' ? 'task' : undefined,
|
|
443
455
|
...stringEnv(extraEnv),
|
|
444
456
|
});
|
|
457
|
+
const env = typeof childEnv === 'function' ? stringEnv(childEnv(ownEnv)) : ownEnv;
|
|
445
458
|
const brokerRequest = async (request) => {
|
|
446
459
|
try {
|
|
447
460
|
const reply = await permissionBroker.request({
|
|
@@ -649,11 +662,16 @@ export async function createClaudeNativeLoopAdapter(options = {}) {
|
|
|
649
662
|
}
|
|
650
663
|
if (pumpError) throw pumpError;
|
|
651
664
|
})();
|
|
652
|
-
pump.catch((error) =>
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
665
|
+
pump.catch((error) => {
|
|
666
|
+
// dispose() aborts the query when the run ends, however it ended, and the
|
|
667
|
+
// SDK throws "Claude Code process aborted by user" for it: not a failure.
|
|
668
|
+
if (abortController.signal.aborted) return;
|
|
669
|
+
onEvent({
|
|
670
|
+
provider: 'claude-code',
|
|
671
|
+
runId,
|
|
672
|
+
event: { type: 'synabun.error', message: error?.message || String(error) },
|
|
673
|
+
});
|
|
674
|
+
});
|
|
657
675
|
|
|
658
676
|
return {
|
|
659
677
|
identity: () => ({ providerSessionId: sessionId }),
|
|
@@ -373,9 +373,14 @@ export class NativeLoopRuntime {
|
|
|
373
373
|
record.startupCancelPromise = new Promise((resolveCancel) => { record._cancelStartup = resolveCancel; });
|
|
374
374
|
this.records.set(runId, record);
|
|
375
375
|
this._emit('sidepanel:run-created', record);
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
376
|
+
// A task run's (assistant dispatch) maxMinutes is work time, which its dispatcher counts and
|
|
377
|
+
// enforces (assistant-dispatch.js, the work clock): idle time between its turns does not count,
|
|
378
|
+
// so it gets no wall-clock cap here. A loop's maxMinutes stays the wall clock.
|
|
379
|
+
if (record.runMode !== 'task') {
|
|
380
|
+
const maxMs = Math.max(1, Number(nativeState.maxMinutes) || 30) * 60_000;
|
|
381
|
+
record.timer = setTimeout(() => { this.stop(runId, 'time_cap').catch(() => {}); }, maxMs);
|
|
382
|
+
record.timer.unref?.();
|
|
383
|
+
}
|
|
379
384
|
|
|
380
385
|
const startupSignal = record.startupAbortController.signal;
|
|
381
386
|
const factoryPromise = Promise.resolve().then(() => factory({
|
|
@@ -510,7 +515,7 @@ export class NativeLoopRuntime {
|
|
|
510
515
|
return;
|
|
511
516
|
}
|
|
512
517
|
const elapsed = this.now() - new Date(state.startedAt || record.startedAt).getTime();
|
|
513
|
-
if (elapsed >= Math.max(1, Number(state.maxMinutes) || 30) * 60_000) {
|
|
518
|
+
if (record.runMode !== 'task' && elapsed >= Math.max(1, Number(state.maxMinutes) || 30) * 60_000) {
|
|
514
519
|
await this.stop(record.runId, 'time_cap');
|
|
515
520
|
return;
|
|
516
521
|
}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun — the OS PATH a new terminal would get
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// A process keeps the PATH it was started with. SynaBun started from Finder,
|
|
6
|
+
// the Dock, the Start menu or a login item got the desktop's PATH, often
|
|
7
|
+
// without ~/.local/bin or Homebrew; started before a CLI was installed, it
|
|
8
|
+
// never sees the folder the installer added. This reads the PATH the
|
|
9
|
+
// operating system would give a terminal opened now:
|
|
10
|
+
//
|
|
11
|
+
// Windows the machine PATH, then the user PATH, from the registry
|
|
12
|
+
// (`reg query`; REG_EXPAND_SZ expanded with this process's
|
|
13
|
+
// environment), which is how Windows builds a new process's
|
|
14
|
+
// PATH. No PowerShell.
|
|
15
|
+
// macOS, Linux the PATH the user's login shell ends up with
|
|
16
|
+
// (`$SHELL -i -l -c`, which runs .zprofile/.zshrc,
|
|
17
|
+
// .bash_profile/.bashrc: nvm, asdf, mise, fnm, Homebrew's
|
|
18
|
+
// shellenv), started from the launchd default PATH, in a
|
|
19
|
+
// session of its own with no terminal, under a short timeout;
|
|
20
|
+
// on macOS also /etc/paths and /etc/paths.d
|
|
21
|
+
//
|
|
22
|
+
// The answer is cached briefly (`ttlMs`), read again in the background when it
|
|
23
|
+
// goes stale, and handed to augmented-path.js (rememberOsPath), whose PATH
|
|
24
|
+
// every lookup and spawn of a user's CLI uses. Re-check reads it again at once
|
|
25
|
+
// (refresh({ force: true })). A failed read keeps the previous answer and is
|
|
26
|
+
// retried sooner. Nothing here throws.
|
|
27
|
+
|
|
28
|
+
import { execFile, spawn } from 'node:child_process';
|
|
29
|
+
import { randomBytes } from 'node:crypto';
|
|
30
|
+
import { readFileSync, readdirSync } from 'node:fs';
|
|
31
|
+
import os from 'node:os';
|
|
32
|
+
import path from 'node:path';
|
|
33
|
+
import { rememberOsPath } from './augmented-path.js';
|
|
34
|
+
|
|
35
|
+
/** Where Windows keeps PATH: the machine's, then the user's (the order Windows joins them in). */
|
|
36
|
+
export const WINDOWS_PATH_KEYS = Object.freeze([
|
|
37
|
+
'HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment',
|
|
38
|
+
'HKCU\\Environment',
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
/** The PATH launchd gives an app on macOS (and a sane start on Linux): what a new terminal's shell begins from. */
|
|
42
|
+
export const LAUNCHD_PATH = '/usr/bin:/bin:/usr/sbin:/sbin';
|
|
43
|
+
|
|
44
|
+
/** Shells that take `-i -l -c`. Others (csh, nu, xonsh, pwsh …) are read through /bin/sh -l. */
|
|
45
|
+
const INTERACTIVE_LOGIN_SHELLS = new Set(['bash', 'zsh', 'ksh', 'ksh93', 'mksh', 'fish', 'yash']);
|
|
46
|
+
const LOGIN_ONLY_SHELLS = new Set(['sh', 'dash']);
|
|
47
|
+
const MAX_SHELL_OUTPUT = 1024 * 1024;
|
|
48
|
+
|
|
49
|
+
export function splitPathValue(value, platform = process.platform) {
|
|
50
|
+
return String(value || '').split(platform === 'win32' ? ';' : ':')
|
|
51
|
+
.map(entry => platform === 'win32' ? entry.trim().replace(/^"(.*)"$/, '$1').trim() : entry.trim())
|
|
52
|
+
.filter(Boolean);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function dedupePath(entries, platform = process.platform) {
|
|
56
|
+
const seen = new Set();
|
|
57
|
+
return entries.filter((entry) => {
|
|
58
|
+
const text = String(entry || '').trim();
|
|
59
|
+
if (!text) return false;
|
|
60
|
+
const key = platform === 'win32' ? text.toLowerCase().replace(/[\\/]+$/, '') : text.replace(/\/+$/, '') || '/';
|
|
61
|
+
if (seen.has(key)) return false;
|
|
62
|
+
seen.add(key);
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The Path value in what `reg query <key> /v Path` prints:
|
|
69
|
+
*
|
|
70
|
+
* HKEY_CURRENT_USER\Environment
|
|
71
|
+
* Path REG_EXPAND_SZ %USERPROFILE%\AppData\Local\Microsoft\WindowsApps;C:\Users\you\.local\bin
|
|
72
|
+
*
|
|
73
|
+
* → { type: 'REG_EXPAND_SZ', value: '…' }, or null when there is none.
|
|
74
|
+
*/
|
|
75
|
+
export function parseRegQuery(text) {
|
|
76
|
+
for (const line of String(text || '').split(/\r?\n/)) {
|
|
77
|
+
const match = line.match(/^\s+(\S+)\s+(REG_EXPAND_SZ|REG_SZ)(?:\s+(.*))?$/i);
|
|
78
|
+
if (match && match[1].toLowerCase() === 'path') return { type: match[2].toUpperCase(), value: (match[3] || '').trim() };
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** %NAME% replaced from `env` (names compared without case, as Windows does); unknown names stay as written. */
|
|
84
|
+
export function expandWindowsVars(value, env = process.env) {
|
|
85
|
+
const lookup = new Map(Object.entries(env || {}).map(([name, val]) => [name.toUpperCase(), val]));
|
|
86
|
+
return String(value || '').replace(/%([^%;]+)%/g, (whole, name) => {
|
|
87
|
+
const found = lookup.get(name.toUpperCase());
|
|
88
|
+
return found == null || found === '' ? whole : String(found);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function decodeUtf8(buffer) {
|
|
93
|
+
try { return new TextDecoder('utf-8', { fatal: true }).decode(buffer); } catch { return null; }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* `reg query <key> /v Path`, its output as text. reg.exe writes in the
|
|
98
|
+
* console's code page; a folder name outside ASCII (C:\Users\João) is then not
|
|
99
|
+
* UTF-8, and the query is asked again through a console switched to UTF-8
|
|
100
|
+
* (chcp 65001). Fixed strings only: nothing of a request reaches either line.
|
|
101
|
+
*/
|
|
102
|
+
export async function runRegQuery(key, { env = process.env, timeoutMs = 3000, execFileImpl = execFile } = {}) {
|
|
103
|
+
const systemRoot = env.SystemRoot || env.SYSTEMROOT || 'C:\\Windows';
|
|
104
|
+
const reg = path.win32.join(systemRoot, 'System32', 'reg.exe');
|
|
105
|
+
const comspec = env.ComSpec || env.COMSPEC || path.win32.join(systemRoot, 'System32', 'cmd.exe');
|
|
106
|
+
const run = (file, args, extra = {}) => new Promise((resolve) => {
|
|
107
|
+
try {
|
|
108
|
+
execFileImpl(file, args, { encoding: 'buffer', timeout: timeoutMs, windowsHide: true, env, maxBuffer: 1024 * 1024, ...extra }, (error, stdout) => {
|
|
109
|
+
resolve({ error, stdout: Buffer.isBuffer(stdout) ? stdout : Buffer.from(String(stdout || '')) });
|
|
110
|
+
});
|
|
111
|
+
} catch (error) {
|
|
112
|
+
resolve({ error, stdout: Buffer.alloc(0) });
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
const first = await run(reg, ['query', key, '/v', 'Path']);
|
|
116
|
+
if (!first.stdout.length) throw first.error || new Error('reg.exe printed nothing');
|
|
117
|
+
const text = decodeUtf8(first.stdout);
|
|
118
|
+
if (text !== null) return text;
|
|
119
|
+
const second = await run(comspec, ['/d', '/s', '/c', `"chcp 65001 >nul & "${reg}" query "${key}" /v Path"`], { windowsVerbatimArguments: true });
|
|
120
|
+
return (second.stdout.length && decodeUtf8(second.stdout)) || first.stdout.toString('latin1');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** The registry's PATH: machine entries, then user entries, each once. */
|
|
124
|
+
export async function readWindowsPath({ env = process.env, query = runRegQuery, timeoutMs = 3000 } = {}) {
|
|
125
|
+
const entries = [];
|
|
126
|
+
const sources = [];
|
|
127
|
+
const errors = [];
|
|
128
|
+
for (const key of WINDOWS_PATH_KEYS) {
|
|
129
|
+
try {
|
|
130
|
+
const found = parseRegQuery(await query(key, { env, timeoutMs }));
|
|
131
|
+
if (found) {
|
|
132
|
+
const part = splitPathValue(expandWindowsVars(found.value, env), 'win32');
|
|
133
|
+
entries.push(...part);
|
|
134
|
+
sources.push(...part.map(dir => ({ dir, source: key.startsWith('HKLM') ? 'system' : 'user' })));
|
|
135
|
+
}
|
|
136
|
+
} catch (error) {
|
|
137
|
+
errors.push(`${key}: ${String(error?.message || error).split(/\r?\n/)[0]}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return { entries: dedupePath(entries, 'win32'), sources, ok: entries.length > 0, errors };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** The user's login shell: $SHELL, else the account's (a launchd- or desktop-started app may have no SHELL). */
|
|
144
|
+
export function loginShellOf({ env = process.env, userInfo = () => os.userInfo() } = {}) {
|
|
145
|
+
if (env.SHELL) return env.SHELL;
|
|
146
|
+
try { return userInfo()?.shell || null; } catch { return null; }
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* How to ask `shell` for the PATH a login session ends with. The PATH is
|
|
151
|
+
* printed on a line of its own between two marker lines, so whatever the
|
|
152
|
+
* startup files print around it (banners, warnings) is ignored.
|
|
153
|
+
*/
|
|
154
|
+
export function loginShellCommand(shell, marker) {
|
|
155
|
+
const name = path.posix.basename(String(shell || '')).toLowerCase();
|
|
156
|
+
const script = `printf '%s\\n' '${marker}' "$PATH" '${marker}'`;
|
|
157
|
+
if (INTERACTIVE_LOGIN_SHELLS.has(name)) return { file: shell, args: ['-i', '-l', '-c', script] };
|
|
158
|
+
if (LOGIN_ONLY_SHELLS.has(name)) return { file: shell, args: ['-l', '-c', script] };
|
|
159
|
+
return { file: '/bin/sh', args: ['-l', '-c', script] };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** The PATH line between the two markers, or null. */
|
|
163
|
+
export function parseLoginShellOutput(text, marker) {
|
|
164
|
+
const lines = String(text || '').split(/\r?\n/);
|
|
165
|
+
for (let i = 0; i + 2 < lines.length; i++) {
|
|
166
|
+
if (lines[i] === marker && lines[i + 2] === marker) return lines[i + 1];
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* The PATH the user's login shell builds. Started in a session of its own
|
|
173
|
+
* (detached: no controlling terminal, so a startup file cannot wait on
|
|
174
|
+
* /dev/tty), from the launchd default PATH, in the home folder; killed with
|
|
175
|
+
* its whole group after `timeoutMs`.
|
|
176
|
+
*/
|
|
177
|
+
export function readLoginShellPath({
|
|
178
|
+
env = process.env,
|
|
179
|
+
platform = process.platform,
|
|
180
|
+
shell = loginShellOf({ env }),
|
|
181
|
+
spawnImpl = spawn,
|
|
182
|
+
timeoutMs = 4000,
|
|
183
|
+
home = env.HOME || os.homedir(),
|
|
184
|
+
} = {}) {
|
|
185
|
+
return new Promise((resolve) => {
|
|
186
|
+
const marker = `SYNABUN_PATH_${randomBytes(6).toString('hex').toUpperCase()}`;
|
|
187
|
+
const command = loginShellCommand(shell || '/bin/sh', marker);
|
|
188
|
+
const childEnv = { ...env, PATH: LAUNCHD_PATH, TERM: 'dumb' };
|
|
189
|
+
let child = null;
|
|
190
|
+
let out = '';
|
|
191
|
+
let settled = false;
|
|
192
|
+
let timer = null;
|
|
193
|
+
const finish = (result) => {
|
|
194
|
+
if (settled) return;
|
|
195
|
+
settled = true;
|
|
196
|
+
clearTimeout(timer);
|
|
197
|
+
resolve({ shell: command.file, ...result });
|
|
198
|
+
};
|
|
199
|
+
const killGroup = () => {
|
|
200
|
+
try { process.kill(-child.pid, 'SIGKILL'); } catch { try { child?.kill('SIGKILL'); } catch { /* gone */ } }
|
|
201
|
+
};
|
|
202
|
+
try {
|
|
203
|
+
child = spawnImpl(command.file, command.args, { env: childEnv, cwd: home, stdio: ['ignore', 'pipe', 'ignore'], detached: platform !== 'win32' });
|
|
204
|
+
} catch (error) {
|
|
205
|
+
return finish({ entries: [], ok: false, error: `${command.file} could not be started: ${error?.message || error}` });
|
|
206
|
+
}
|
|
207
|
+
timer = setTimeout(() => {
|
|
208
|
+
killGroup();
|
|
209
|
+
finish({ entries: [], ok: false, error: `${command.file} did not answer within ${Math.round(timeoutMs / 100) / 10} s` });
|
|
210
|
+
}, timeoutMs);
|
|
211
|
+
timer.unref?.();
|
|
212
|
+
child.on('error', (error) => finish({ entries: [], ok: false, error: `${command.file} could not be started: ${error?.message || error}` }));
|
|
213
|
+
child.stdout?.setEncoding?.('utf8');
|
|
214
|
+
child.stdout?.on('data', (chunk) => {
|
|
215
|
+
out += chunk;
|
|
216
|
+
if (out.length > MAX_SHELL_OUTPUT) {
|
|
217
|
+
killGroup();
|
|
218
|
+
finish({ entries: [], ok: false, error: `${command.file} printed too much` });
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
child.on('close', () => {
|
|
222
|
+
const line = parseLoginShellOutput(out, marker);
|
|
223
|
+
if (line == null) return finish({ entries: [], ok: false, error: `${command.file} did not print a PATH` });
|
|
224
|
+
finish({ entries: dedupePath(splitPathValue(line, platform), platform), ok: true, error: null });
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** macOS's /etc/paths, then each file of /etc/paths.d in name order (what path_helper builds a login PATH from). */
|
|
230
|
+
export function readEtcPaths({ readFile = readFileSync, readdir = readdirSync } = {}) {
|
|
231
|
+
const out = [];
|
|
232
|
+
const take = (file) => {
|
|
233
|
+
try {
|
|
234
|
+
for (const line of String(readFile(file, 'utf8')).split(/\r?\n/)) {
|
|
235
|
+
const entry = line.trim();
|
|
236
|
+
if (entry && !entry.startsWith('#')) out.push(entry);
|
|
237
|
+
}
|
|
238
|
+
} catch { /* not there */ }
|
|
239
|
+
};
|
|
240
|
+
take('/etc/paths');
|
|
241
|
+
let names = [];
|
|
242
|
+
try { names = readdir('/etc/paths.d').map(String).sort(); } catch { /* not there */ }
|
|
243
|
+
for (const name of names) take(`/etc/paths.d/${name}`);
|
|
244
|
+
return out;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* A cached reader of the OS PATH. `cached()` answers at once (and starts a
|
|
249
|
+
* read in the background when the answer is stale); `refresh()` waits for one.
|
|
250
|
+
*/
|
|
251
|
+
export function createOsPathReader({
|
|
252
|
+
platform = process.platform,
|
|
253
|
+
env = process.env,
|
|
254
|
+
ttlMs = 60_000,
|
|
255
|
+
failureTtlMs = 15_000,
|
|
256
|
+
readWindows = readWindowsPath,
|
|
257
|
+
readLoginShell = readLoginShellPath,
|
|
258
|
+
readEtc = readEtcPaths,
|
|
259
|
+
remember = rememberOsPath,
|
|
260
|
+
now = Date.now,
|
|
261
|
+
} = {}) {
|
|
262
|
+
let state = { entries: [], at: 0, ok: false, source: null, error: null, shell: null };
|
|
263
|
+
let inflight = null;
|
|
264
|
+
|
|
265
|
+
async function read() {
|
|
266
|
+
if (env.SYNABUN_TOOL_DISCOVERY === 'path') return { entries: [], ok: true, source: 'off', error: null, shell: null };
|
|
267
|
+
if (platform === 'win32') {
|
|
268
|
+
const found = await readWindows({ env });
|
|
269
|
+
return { entries: found.entries, sources: found.sources || [], ok: found.ok, source: 'registry', error: found.errors?.length ? found.errors.join('; ') : null, shell: null };
|
|
270
|
+
}
|
|
271
|
+
const found = await readLoginShell({ env, platform });
|
|
272
|
+
const etc = platform === 'darwin' ? readEtc() : [];
|
|
273
|
+
const entries = dedupePath([...(found.entries || []), ...etc], platform);
|
|
274
|
+
return {
|
|
275
|
+
entries,
|
|
276
|
+
ok: !!found.ok,
|
|
277
|
+
source: found.ok ? 'login-shell' : etc.length ? 'etc-paths' : 'none',
|
|
278
|
+
error: found.error || null,
|
|
279
|
+
shell: found.shell || null,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function snapshot() {
|
|
284
|
+
return { entries: state.entries.slice(), sources: (state.sources || []).map(entry => ({ ...entry })), at: state.at, ok: state.ok, source: state.source, error: state.error, shell: state.shell };
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function stale() {
|
|
288
|
+
return !state.at || now() - state.at >= (state.ok ? ttlMs : failureTtlMs);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function refresh({ force = false } = {}) {
|
|
292
|
+
if (inflight) return inflight;
|
|
293
|
+
if (!force && !stale()) return Promise.resolve(snapshot());
|
|
294
|
+
inflight = (async () => {
|
|
295
|
+
let result;
|
|
296
|
+
try { result = await read(); } catch (error) { result = { entries: [], ok: false, source: 'none', error: String(error?.message || error), shell: null }; }
|
|
297
|
+
// A read that failed keeps what an earlier one found.
|
|
298
|
+
const entries = result.ok || !state.entries.length ? result.entries : state.entries;
|
|
299
|
+
state = { ...result, entries, at: now() };
|
|
300
|
+
try { remember(entries); } catch { /* nothing to tell */ }
|
|
301
|
+
return snapshot();
|
|
302
|
+
})().finally(() => { inflight = null; });
|
|
303
|
+
return inflight;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function cached() {
|
|
307
|
+
if (stale() && !inflight) refresh().catch(() => {});
|
|
308
|
+
return state.entries.slice();
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function invalidate() {
|
|
312
|
+
state = { ...state, at: 0 };
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return { refresh, cached, invalidate, snapshot, stale };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** This process's reader (server.js starts it at boot; Re-check forces it). */
|
|
319
|
+
export const osPath = createOsPathReader();
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
} from 'fs';
|
|
6
6
|
import { join, resolve, dirname } from 'path';
|
|
7
7
|
import os from 'node:os';
|
|
8
|
+
import { runGitReadSync } from './git-read.js';
|
|
8
9
|
|
|
9
10
|
const PLUGINS_ROOT = () => join(os.homedir(), '.claude', 'plugins');
|
|
10
11
|
const INSTALLED_PLUGINS_FILE = () => join(PLUGINS_ROOT(), 'installed_plugins.json');
|
|
@@ -48,9 +49,10 @@ function claudeNotFoundErr() {
|
|
|
48
49
|
return { ok: false, error: 'Claude Code CLI not found on PATH. Install `claude` to manage plugins.' };
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
// (git is asked as lib/git-read.js runs a read: the folder comes from a request, or from Claude Code's registry)
|
|
51
53
|
function gitHeadSha(repoPath) {
|
|
52
54
|
if (!repoPath || !existsSync(repoPath)) return 'unknown';
|
|
53
|
-
const r =
|
|
55
|
+
const r = runGitReadSync(repoPath, ['rev-parse', 'HEAD'], { encoding: 'utf-8' });
|
|
54
56
|
const out = (r.stdout || '').trim();
|
|
55
57
|
return out || 'unknown';
|
|
56
58
|
}
|
|
@@ -252,7 +254,7 @@ export function repairSynabunPlugins() {
|
|
|
252
254
|
if (!meta.ok) { failed.push({ marketplaceName: name, error: meta.error }); continue; }
|
|
253
255
|
let githubUrl = null;
|
|
254
256
|
try {
|
|
255
|
-
const r =
|
|
257
|
+
const r = runGitReadSync(path, ['remote', 'get-url', 'origin'], { encoding: 'utf-8' });
|
|
256
258
|
const u = (r.stdout || '').trim();
|
|
257
259
|
if (/^https?:\/\//.test(u)) githubUrl = u.replace(/\.git$/, '');
|
|
258
260
|
} catch {}
|
|
@@ -18,8 +18,8 @@ import {
|
|
|
18
18
|
resolve,
|
|
19
19
|
sep,
|
|
20
20
|
} from 'node:path';
|
|
21
|
-
import { spawnSync } from 'node:child_process';
|
|
22
21
|
import { isMainThread, parentPort, Worker, workerData } from 'node:worker_threads';
|
|
22
|
+
import { runGitReadSync } from './git-read.js';
|
|
23
23
|
|
|
24
24
|
export const PROJECT_STORAGE_SAFE_CONFIRMATION = 'CLEAR SELECTED CACHES';
|
|
25
25
|
export const PROJECT_STORAGE_DEPENDENCY_CONFIRMATION = 'DELETE DEPENDENCIES';
|
|
@@ -216,11 +216,11 @@ function measurePath(rootPath, { entryLimit = MEASURE_ENTRY_LIMIT } = {}) {
|
|
|
216
216
|
return { bytes, fileCount, incomplete, containsRepository };
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
// Both questions are reads, run as lib/git-read.js runs one: a registered project is a folder like any other, and
|
|
220
|
+
// listing its files starts nothing its own git configuration names (`git ls-files` asks the file system monitor).
|
|
219
221
|
function gitInfoForProject(projectRoot) {
|
|
220
222
|
const canonicalProjectRoot = canonicalExistingPath(projectRoot);
|
|
221
|
-
const probe =
|
|
222
|
-
encoding: 'utf8', timeout: 5_000, windowsHide: true,
|
|
223
|
-
});
|
|
223
|
+
const probe = runGitReadSync(projectRoot, ['rev-parse', '--show-toplevel'], { encoding: 'utf8', timeout: 5_000 });
|
|
224
224
|
if (probe.status !== 0) {
|
|
225
225
|
let current = canonicalProjectRoot;
|
|
226
226
|
while (true) {
|
|
@@ -237,9 +237,7 @@ function gitInfoForProject(projectRoot) {
|
|
|
237
237
|
if (!pathIsWithin(gitRoot, canonicalProjectRoot, { allowEqual: true })) {
|
|
238
238
|
return { isRepository: false, verified: false, root: gitRoot, tracked: [] };
|
|
239
239
|
}
|
|
240
|
-
const listed =
|
|
241
|
-
encoding: 'buffer', timeout: 20_000, maxBuffer: 64 * 1024 * 1024, windowsHide: true,
|
|
242
|
-
});
|
|
240
|
+
const listed = runGitReadSync(gitRoot, ['ls-files', '-z'], { encoding: 'buffer', timeout: 20_000, maxBuffer: 64 * 1024 * 1024 });
|
|
243
241
|
if (listed.status !== 0 || listed.error) {
|
|
244
242
|
return { isRepository: true, verified: false, root: gitRoot, tracked: [] };
|
|
245
243
|
}
|