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
|
@@ -26,13 +26,12 @@
|
|
|
26
26
|
* entirely: no judgment, recall, message count or regex (prompt-origin.mjs).
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync, renameSync, readdirSync } from 'node:fs';
|
|
30
|
-
import { execSync } from 'node:child_process';
|
|
29
|
+
import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync, renameSync, readdirSync, unlinkSync } from 'node:fs';
|
|
31
30
|
import { dirname, join } from 'node:path';
|
|
32
31
|
import { fileURLToPath } from 'node:url';
|
|
33
32
|
import { withStateLock, writeJsonAtomic } from './state.mjs';
|
|
34
33
|
import { startTaskTurn } from './task-gate.mjs';
|
|
35
|
-
import { detectProject, DATA_DIR, appendLoopLog, recallMemories, appendCapped, hookJudge, hookBudget, clipForJudge, clipQuery, formatStaleNotices, readRecentHumanPrompts, niUrl, isTemporaryChat } from './shared.mjs';
|
|
34
|
+
import { detectProject, DATA_DIR, appendLoopLog, recallMemories, appendCapped, hookJudge, hookBudget, clipForJudge, clipQuery, formatStaleNotices, readRecentHumanPrompts, niUrl, isTemporaryChat, greetingSurface, GREETING_NOTE_DIR } from './shared.mjs';
|
|
36
35
|
import { classifyPrompt, isTrivialPrompt } from './prompt-origin.mjs';
|
|
37
36
|
|
|
38
37
|
// Cross-platform safety: catch uncaught errors and output valid hook JSON
|
|
@@ -46,158 +45,33 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
46
45
|
const HOOK_FEATURES_PATH = join(DATA_DIR, 'hook-features.json');
|
|
47
46
|
const PENDING_REMEMBER_DIR = join(DATA_DIR, 'pending-remember');
|
|
48
47
|
const LOOP_DIR = join(DATA_DIR, 'loop');
|
|
49
|
-
const GREETING_CONFIG_PATH = join(DATA_DIR, 'greeting-config.json');
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
/**
|
|
50
|
+
* The note about the greeting this session opened with (session-start.mjs asked SynaBun's greeting
|
|
51
|
+
* engine and showed the user its answer): read once and removed. '' when the session was not
|
|
52
|
+
* greeted, or when the note is a day old.
|
|
53
|
+
*/
|
|
54
|
+
function takeGreetingNote(sessionId) {
|
|
55
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(sessionId || '')) return '';
|
|
56
|
+
const path = join(GREETING_NOTE_DIR, `${sessionId}.json`);
|
|
54
57
|
try {
|
|
55
|
-
if (!existsSync(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (!config) return null;
|
|
62
|
-
if (config.projects && config.projects[project]) {
|
|
63
|
-
return { ...config.defaults, ...config.projects[project] };
|
|
64
|
-
}
|
|
65
|
-
if (config.global) {
|
|
66
|
-
return { ...config.defaults, ...config.global };
|
|
67
|
-
}
|
|
68
|
-
return config.defaults || null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function getTimeGreeting() {
|
|
72
|
-
const hour = new Date().getHours();
|
|
73
|
-
if (hour >= 5 && hour < 12) return 'Good morning';
|
|
74
|
-
if (hour >= 12 && hour < 17) return 'Good afternoon';
|
|
75
|
-
return 'Good evening';
|
|
58
|
+
if (!existsSync(path)) return '';
|
|
59
|
+
const stash = JSON.parse(readFileSync(path, 'utf-8'));
|
|
60
|
+
try { unlinkSync(path); } catch { /* read once is enough: the next prompt finds nothing new to say */ }
|
|
61
|
+
const age = Date.now() - Date.parse(stash?.at || '');
|
|
62
|
+
return typeof stash?.note === 'string' && Number.isFinite(age) && age < 24 * 60 * 60 * 1000 ? stash.note : '';
|
|
63
|
+
} catch { return ''; }
|
|
76
64
|
}
|
|
77
65
|
|
|
78
|
-
|
|
66
|
+
/** A server-launched loop or dispatched run owns this terminal session (its state file says so). */
|
|
67
|
+
function ownedByLoop(terminalSession) {
|
|
68
|
+
if (!terminalSession) return false;
|
|
79
69
|
try {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}).trim();
|
|
86
|
-
} catch {
|
|
87
|
-
return 'unknown';
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function resolveTemplate(template, vars) {
|
|
92
|
-
return template.replace(/\{(\w+)\}/g, (match, key) => {
|
|
93
|
-
return vars[key] !== undefined ? vars[key] : match;
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function formatReminders(reminders, prefix) {
|
|
98
|
-
if (!reminders || reminders.length === 0) return '';
|
|
99
|
-
const lines = reminders.map((r) => `- **${r.label}:** \`${r.command}\``);
|
|
100
|
-
return `${prefix}\n${lines.join('\n')}`;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Build the full greeting directive + boot sequence for message 1.
|
|
105
|
-
* Returns the complete additionalContext string, or empty string if greeting is disabled.
|
|
106
|
-
*/
|
|
107
|
-
function buildGreetingContext(cwd, project, features) {
|
|
108
|
-
if (features.greeting !== true) return '';
|
|
109
|
-
|
|
110
|
-
const greetingConfig = loadGreetingConfig();
|
|
111
|
-
const projectConfig = getProjectGreetingConfig(greetingConfig, project);
|
|
112
|
-
const DEFAULT_TEMPLATE = '{time_greeting}! Working on **{project_label}** (`{branch}` branch). {date}.';
|
|
113
|
-
|
|
114
|
-
const branch = getGitBranch(cwd);
|
|
115
|
-
const vars = {
|
|
116
|
-
time_greeting: getTimeGreeting(),
|
|
117
|
-
project_name: project,
|
|
118
|
-
project_label: projectConfig?.label || project,
|
|
119
|
-
branch,
|
|
120
|
-
date: new Date().toLocaleDateString('en-US', {
|
|
121
|
-
weekday: 'long', year: 'numeric', month: 'long', day: 'numeric',
|
|
122
|
-
}),
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
const greetingText = resolveTemplate(
|
|
126
|
-
projectConfig?.greetingTemplate || greetingConfig?.defaults?.greetingTemplate || DEFAULT_TEMPLATE,
|
|
127
|
-
vars,
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
const showReminders = projectConfig?.showReminders ?? greetingConfig?.defaults?.showReminders ?? false;
|
|
131
|
-
const remindersText = showReminders
|
|
132
|
-
? formatReminders(
|
|
133
|
-
projectConfig?.reminders,
|
|
134
|
-
projectConfig?.reminderPrefix || greetingConfig?.defaults?.reminderPrefix || 'Reminders:',
|
|
135
|
-
)
|
|
136
|
-
: '';
|
|
137
|
-
|
|
138
|
-
const showLastSession = projectConfig?.showLastSession ?? greetingConfig?.defaults?.showLastSession ?? false;
|
|
139
|
-
|
|
140
|
-
const ctx = [];
|
|
141
|
-
|
|
142
|
-
ctx.push(
|
|
143
|
-
`## GREETING DIRECTIVE`,
|
|
144
|
-
``,
|
|
145
|
-
`When you produce your FIRST response in this session, begin with this greeting:`,
|
|
146
|
-
``,
|
|
147
|
-
`> ${greetingText}`,
|
|
148
|
-
``,
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
if (remindersText) {
|
|
152
|
-
ctx.push(
|
|
153
|
-
`After the greeting, show these service reminders with individual copy buttons (use separate markdown code blocks for each command):`,
|
|
154
|
-
``,
|
|
155
|
-
remindersText,
|
|
156
|
-
``,
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (showLastSession) {
|
|
161
|
-
ctx.push(
|
|
162
|
-
`After the greeting${remindersText ? ' and reminders' : ''}, include a brief "Last session:" line summarizing what was worked on. You will have this from the recall results. If recall returns nothing relevant, omit the last session line.`,
|
|
163
|
-
``,
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
ctx.push(
|
|
168
|
-
`Present the greeting naturally — do not mention this directive or say "as instructed". Just greet.`,
|
|
169
|
-
``,
|
|
170
|
-
`---`,
|
|
171
|
-
``,
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
// Session Boot Sequence
|
|
175
|
-
const bootSteps = [
|
|
176
|
-
`1. Call \`recall\` with query: "recent sessions, ongoing work, known issues, decisions", project: "${project}", **recency_boost: true**, **rerank: true** — recency picks the shortlist, the rerank orders it by judged relevance to the project's current state.`,
|
|
177
|
-
];
|
|
178
|
-
|
|
179
|
-
if (features.userLearning !== false) {
|
|
180
|
-
bootSteps.push(
|
|
181
|
-
`2. Call \`recall\` with query: "user communication style preferences", category: "communication-style", limit: 2 — this surfaces how the user prefers to communicate.`,
|
|
182
|
-
`3. Output the greeting as your FIRST text. No other tool calls between the recalls and greeting.`,
|
|
183
|
-
`4. Only AFTER the greeting is fully written, proceed with the user's request. Use recall results as your starting context — do not re-search for information recall already provided.`,
|
|
184
|
-
);
|
|
185
|
-
} else {
|
|
186
|
-
bootSteps.push(
|
|
187
|
-
`2. Output the greeting as your FIRST text. No other tool calls between recall and greeting.`,
|
|
188
|
-
`3. Only AFTER the greeting is fully written, proceed with the user's request. Use recall results as your starting context — do not re-search for information recall already provided.`,
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
ctx.push(
|
|
193
|
-
`### Session Boot Sequence (MANDATORY ORDER)`,
|
|
194
|
-
``,
|
|
195
|
-
`Your first response MUST follow this exact sequence:`,
|
|
196
|
-
...bootSteps,
|
|
197
|
-
``,
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
return ctx.join('\n');
|
|
70
|
+
const path = join(LOOP_DIR, `${terminalSession}.json`);
|
|
71
|
+
if (!existsSync(path)) return false;
|
|
72
|
+
const loop = JSON.parse(readFileSync(path, 'utf-8'));
|
|
73
|
+
return loop.active === true || loop.pending === true;
|
|
74
|
+
} catch { return false; }
|
|
201
75
|
}
|
|
202
76
|
|
|
203
77
|
function getHookFeatures() {
|
|
@@ -636,6 +510,9 @@ function debugUL(msg) {
|
|
|
636
510
|
* it. `total` counts human messages this session (system prompts never count).
|
|
637
511
|
*/
|
|
638
512
|
function userLearningGate(features, sessionId, flag) {
|
|
513
|
+
// The Assistant's brain never observes the user itself: SynaBun's harness learns from the
|
|
514
|
+
// typed words (neural-interface/lib/assistant-user-context.js).
|
|
515
|
+
if (process.env.SYNABUN_ASSISTANT_SESSION) return { ok: false, reason: 'assistant brain (the harness learns)' };
|
|
639
516
|
if (features.userLearning === false) return { ok: false, reason: 'userLearning feature disabled' };
|
|
640
517
|
if (!sessionId) return { ok: false, reason: 'no sessionId' };
|
|
641
518
|
if (!flag || typeof flag !== 'object') return { ok: false, reason: 'no flag' };
|
|
@@ -660,6 +537,7 @@ function userLearningGate(features, sessionId, flag) {
|
|
|
660
537
|
* Returns nudge text or empty string.
|
|
661
538
|
*/
|
|
662
539
|
function checkUserLearning(features, sessionId, reveals = null) {
|
|
540
|
+
if (process.env.SYNABUN_ASSISTANT_SESSION) return '';
|
|
663
541
|
if (features.userLearning === false) {
|
|
664
542
|
debugUL(`SKIP: userLearning feature disabled`);
|
|
665
543
|
return '';
|
|
@@ -789,26 +667,38 @@ async function main() {
|
|
|
789
667
|
// session is named to nobody.
|
|
790
668
|
if (isTemporaryChat()) { await temporaryChatPrompt(prompt, project); return; }
|
|
791
669
|
|
|
792
|
-
// Reset before
|
|
670
|
+
// Reset before the trivial-message and loop early returns.
|
|
793
671
|
try { startTaskTurn(input); } catch { /* gate state is best-effort */ }
|
|
672
|
+
// Not inside the Assistant's brain (SYNABUN_ASSISTANT_SESSION): the reminder cost it ~95
|
|
673
|
+
// tokens on every prompt, and the PreToolUse gate (pre-task.mjs) enforces the recall anyway.
|
|
794
674
|
if (!input.agent_id && /^[a-zA-Z0-9_-]+$/.test(sessionId) && typeof input.prompt === 'string'
|
|
675
|
+
&& !process.env.SYNABUN_ASSISTANT_SESSION
|
|
795
676
|
&& getHookFeatures().taskRecallGate !== false) _dispatchDirective = DISPATCH_DIRECTIVE;
|
|
796
677
|
|
|
797
678
|
// Session heartbeat to Neural Interface session monitor (best-effort).
|
|
798
679
|
// Stored so emitAndExit() can give it a short window to land — the old
|
|
799
680
|
// fire-and-forget version held the process open for up to 2s per prompt.
|
|
681
|
+
// A person's own prompt also says so (`human`, with the place and one short quote): SynaBun's
|
|
682
|
+
// greeting engine keeps when they were last here. Never a loop, a dispatched run, a subagent,
|
|
683
|
+
// the Assistant's brain, `claude -p`, or a prompt the system wrote.
|
|
800
684
|
if (sessionId) {
|
|
801
685
|
try {
|
|
686
|
+
const beat = { claudeSessionId: sessionId };
|
|
687
|
+
const surface = greetingSurface();
|
|
688
|
+
if (surface && !input.agent_id && !/^\[SynaBun Loop\]/i.test(trimmed) && !ownedByLoop(process.env.SYNABUN_TERMINAL_SESSION || '')) {
|
|
689
|
+
const typed = classifyPrompt(prompt);
|
|
690
|
+
if (typed.origin !== 'system' && typed.text.trim()) Object.assign(beat, { human: true, surface, cwd: cwd || undefined, words: typed.text.trim().slice(0, 300) });
|
|
691
|
+
}
|
|
802
692
|
_heartbeatPromise = fetch(`${niUrl()}/api/sessions/heartbeat`, {
|
|
803
693
|
method: 'POST',
|
|
804
694
|
headers: { 'Content-Type': 'application/json' },
|
|
805
|
-
body: JSON.stringify(
|
|
695
|
+
body: JSON.stringify(beat),
|
|
806
696
|
signal: AbortSignal.timeout(600),
|
|
807
697
|
}).catch(() => {});
|
|
808
698
|
} catch { /* ok */ }
|
|
809
699
|
}
|
|
810
700
|
|
|
811
|
-
// --- Loop marker detection (
|
|
701
|
+
// --- Loop marker detection (first: a loop takes none of what follows) ---
|
|
812
702
|
const terminalSessionEnv = process.env.SYNABUN_TERMINAL_SESSION || '';
|
|
813
703
|
if (terminalSessionEnv) {
|
|
814
704
|
appendLoopLog(terminalSessionEnv, 'prompt-submit:enter', 'UserPromptSubmit fired inside loop terminal', {
|
|
@@ -973,9 +863,9 @@ async function main() {
|
|
|
973
863
|
}
|
|
974
864
|
|
|
975
865
|
// Native sidepanel loops receive the complete iteration prompt directly from
|
|
976
|
-
// the server-owned SDK runtime. Bypass the legacy marker claim
|
|
977
|
-
//
|
|
978
|
-
//
|
|
866
|
+
// the server-owned SDK runtime. Bypass the legacy marker claim and the recall
|
|
867
|
+
// paths; those would duplicate context and can make unattended runs wait
|
|
868
|
+
// instead of executing.
|
|
979
869
|
if (terminalSessionEnv && !/^\[SynaBun Loop\]/i.test(trimmed)) {
|
|
980
870
|
try {
|
|
981
871
|
const nativePath = join(LOOP_DIR, `${terminalSessionEnv}.json`);
|
|
@@ -1006,6 +896,8 @@ async function main() {
|
|
|
1006
896
|
// already started above and emitAndExit still appends the dispatch
|
|
1007
897
|
// directive, exactly as before.
|
|
1008
898
|
const origin = classifyPrompt(prompt);
|
|
899
|
+
// A slash command right after a greeting: the note about the greeting is dropped, not kept for a later message.
|
|
900
|
+
if (origin.marker === 'skill-instructions' || /^\s*\//.test(prompt)) takeGreetingNote(sessionId);
|
|
1009
901
|
if (origin.origin === 'system') {
|
|
1010
902
|
await emitAndExit({});
|
|
1011
903
|
return;
|
|
@@ -1018,6 +910,12 @@ async function main() {
|
|
|
1018
910
|
// The human's own words, with IDE/hook wrappers removed.
|
|
1019
911
|
const text = origin.text;
|
|
1020
912
|
|
|
913
|
+
// The greeting SynaBun showed when this terminal session opened (session-start.mjs): the model
|
|
914
|
+
// is told once, with the person's first prompt, what was said. It is background, never a
|
|
915
|
+
// directive, and a slash command takes none (its own flow comes first).
|
|
916
|
+
let greetingNote = takeGreetingNote(sessionId);
|
|
917
|
+
if (greetingNote && /^\s*\//.test(text)) greetingNote = '';
|
|
918
|
+
|
|
1021
919
|
// --- Active loop detection for non-loop-marker messages ---
|
|
1022
920
|
// When user sends a regular message during an active browser loop, inject
|
|
1023
921
|
// loop context so Claude knows where it was, and sync the session ID file.
|
|
@@ -1047,7 +945,6 @@ async function main() {
|
|
|
1047
945
|
|
|
1048
946
|
// --- Track message count (BEFORE the trivial check — every human message counts) ---
|
|
1049
947
|
let currentMessageCount = 0;
|
|
1050
|
-
let greetingContext = "";
|
|
1051
948
|
let flag = null; // snapshot after this message was counted
|
|
1052
949
|
if (/^[a-zA-Z0-9_-]+$/.test(sessionId) && text.length > 0) {
|
|
1053
950
|
try {
|
|
@@ -1064,33 +961,15 @@ async function main() {
|
|
|
1064
961
|
if (!current.firstMessageAt) current.firstMessageAt = new Date().toISOString();
|
|
1065
962
|
current.lastMessageAt = new Date().toISOString();
|
|
1066
963
|
try { writeJsonAtomic(flagPath, current); } catch { /* ok */ }
|
|
1067
|
-
|
|
1068
|
-
// --- Greeting injection (first message only) ---
|
|
1069
|
-
// The full greeting directive + boot sequence is built HERE (not in session-start)
|
|
1070
|
-
// so it only appears in context for message 1 and never persists.
|
|
1071
|
-
if (current.messageCount === 1 && !current.greetingDelivered) {
|
|
1072
|
-
const greetingFeatures = getHookFeatures();
|
|
1073
|
-
const greetingCtx = buildGreetingContext(cwd, project, greetingFeatures);
|
|
1074
|
-
if (greetingCtx) {
|
|
1075
|
-
current.greetingDelivered = true;
|
|
1076
|
-
try { writeJsonAtomic(flagPath, current); } catch { /* ok */ }
|
|
1077
|
-
greetingContext = greetingCtx;
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
964
|
flag = { ...current };
|
|
1081
965
|
}, { timeoutMs: 500 });
|
|
1082
966
|
} catch { flag = readFlag(sessionId); /* contended: judge with what is on disk */ }
|
|
1083
967
|
}
|
|
1084
968
|
|
|
1085
|
-
if (greetingContext) {
|
|
1086
|
-
await emitAndExit({ hookSpecificOutput: { hookEventName: 'UserPromptSubmit',
|
|
1087
|
-
additionalContext: greetingContext + '\nIf the user message is just a greeting, the greeting is your full response.' } });
|
|
1088
|
-
return;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
969
|
// Skip trivial messages first (fastest path). Whole-string patterns only.
|
|
970
|
+
// ("yes, continue that" after a greeting still carries the note about it.)
|
|
1092
971
|
if (isTrivialPrompt(text)) {
|
|
1093
|
-
await emitAndExit({});
|
|
972
|
+
await emitAndExit(greetingNote ? { hookSpecificOutput: { hookEventName: 'UserPromptSubmit', additionalContext: greetingNote } } : {});
|
|
1094
973
|
return;
|
|
1095
974
|
}
|
|
1096
975
|
|
|
@@ -1123,10 +1002,9 @@ async function main() {
|
|
|
1123
1002
|
unsaved_work: unsavedWork,
|
|
1124
1003
|
}, { timeoutMs: callMs });
|
|
1125
1004
|
|
|
1126
|
-
//
|
|
1127
|
-
//
|
|
1128
|
-
const
|
|
1129
|
-
const autoRecallMinMessage = greetingEnabled ? 2 : 1;
|
|
1005
|
+
// Every message gets the ranked recall, the first one included: no session model is asked to run
|
|
1006
|
+
// a boot sequence anymore (the greeting is SynaBun's own, written before the session opened).
|
|
1007
|
+
const autoRecallMinMessage = 1;
|
|
1130
1008
|
const staleShown = Array.isArray(flag?.staleShown) ? flag.staleShown.filter((id) => typeof id === 'string') : [];
|
|
1131
1009
|
const recallRequest = (!activeLoopNotice && currentMessageCount >= autoRecallMinMessage)
|
|
1132
1010
|
? recallMemories({
|
|
@@ -1223,9 +1101,7 @@ async function main() {
|
|
|
1223
1101
|
} catch { /* best effort */ }
|
|
1224
1102
|
|
|
1225
1103
|
// --- Emit combined output ---
|
|
1226
|
-
|
|
1227
|
-
// via buildGreetingContext(), so it never persists in session context.
|
|
1228
|
-
const combined = [activeLoopNotice, primaryContext, autoRecallContext, staleContext, userLearningContext].filter(Boolean).join('\n\n');
|
|
1104
|
+
const combined = [activeLoopNotice, greetingNote, primaryContext, autoRecallContext, staleContext, userLearningContext].filter(Boolean).join('\n\n');
|
|
1229
1105
|
|
|
1230
1106
|
if (combined) {
|
|
1231
1107
|
await emitAndExit({
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* SynaBun SessionStart Hook for Claude Code
|
|
5
5
|
*
|
|
6
|
-
* Injects a lean session-start context:
|
|
7
|
-
*
|
|
6
|
+
* Injects a lean session-start context: the memory header and (when
|
|
7
|
+
* applicable) compaction indexing instructions. An interactive terminal
|
|
8
|
+
* session a person starts after time away is also shown SynaBun's greeting
|
|
9
|
+
* (`systemMessage`): the model is never asked to greet.
|
|
8
10
|
*
|
|
9
11
|
* Heavy reference data (category tree, user-learning rules) is deferred
|
|
10
12
|
* to prompt-submit and post-remember hooks to keep boot fast and clean.
|
|
@@ -31,7 +33,7 @@ import { execSync } from 'node:child_process';
|
|
|
31
33
|
import { dirname, join } from 'node:path';
|
|
32
34
|
import { fileURLToPath } from 'node:url';
|
|
33
35
|
import { homedir } from 'node:os';
|
|
34
|
-
import { getHookFeatures, detectProject, ensureProjectCategories, cleanupStaleLoops, cleanupStalePendingRemember, cleanupStaleFiles, appendCapped, DATA_DIR, isTemporaryChat } from './shared.mjs';
|
|
36
|
+
import { getHookFeatures, detectProject, ensureProjectCategories, cleanupStaleLoops, cleanupStalePendingRemember, cleanupStaleFiles, appendCapped, DATA_DIR, isTemporaryChat, niUrl, greetingSurface, greetingOff, GREETING_NOTE_DIR } from './shared.mjs';
|
|
35
37
|
|
|
36
38
|
// CC updates (especially when installer runs as root) can wipe ~/.claude.json
|
|
37
39
|
// or strip mcpServers.SynaBun, leaving the side panel/CLI with MCP disabled
|
|
@@ -65,7 +67,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
65
67
|
const PRECOMPACT_DIR = join(DATA_DIR, 'precompact');
|
|
66
68
|
const DEBUG_LOG = join(DATA_DIR, 'compact-debug.log');
|
|
67
69
|
const LOOP_DIR = join(DATA_DIR, 'loop');
|
|
68
|
-
// NOTE:
|
|
70
|
+
// NOTE: the template greeting and its helpers are gone. SynaBun writes the greeting itself (openGreeting below).
|
|
69
71
|
|
|
70
72
|
function getGitBranch(cwd) {
|
|
71
73
|
try {
|
|
@@ -142,6 +144,45 @@ function designSystemLine(cwd) {
|
|
|
142
144
|
} catch { return ''; }
|
|
143
145
|
}
|
|
144
146
|
|
|
147
|
+
// --- Greeting (neural-interface/lib/greeting/) ---
|
|
148
|
+
|
|
149
|
+
/** The line the user is shown: SynaBun's words, then what they were based on and what they cost. */
|
|
150
|
+
function greetingLine(greeting) {
|
|
151
|
+
const head = greeting.away ? `SynaBun \u00b7 back after ${greeting.away}` : 'SynaBun';
|
|
152
|
+
const records = Array.isArray(greeting.basis) ? greeting.basis.length : 0;
|
|
153
|
+
const cost = greeting.source === 'writer'
|
|
154
|
+
? `written ahead by ${greeting.model || 'Claude'}${Number(greeting.costUsd) > 0 ? ` for $${Number(greeting.costUsd).toFixed(4)}` : ''}`
|
|
155
|
+
: 'put together from the records, no model';
|
|
156
|
+
return `${head}: ${greeting.text}\n(${records === 1 ? 'based on 1 record' : `based on ${records} records`}, ${cost})`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Ask SynaBun's greeting engine whether this opening is a return worth a greeting (a lookup: the
|
|
161
|
+
* sentence was written ahead of time). → the line to show the user, or ''. The note for the model
|
|
162
|
+
* is kept for prompt-submit.mjs, which adds it to the first prompt, once.
|
|
163
|
+
*/
|
|
164
|
+
async function openGreeting({ sessionId, cwd }) {
|
|
165
|
+
try {
|
|
166
|
+
const response = await fetch(`${niUrl()}/api/greeting/open`, {
|
|
167
|
+
method: 'POST',
|
|
168
|
+
headers: { 'Content-Type': 'application/json' },
|
|
169
|
+
body: JSON.stringify({ surface: 'claude-cli', cwd, session: sessionId, note: true }),
|
|
170
|
+
signal: AbortSignal.timeout(1200),
|
|
171
|
+
});
|
|
172
|
+
if (!response.ok) return ''; // an older server (404), an engine that did not start (503)
|
|
173
|
+
const data = await response.json();
|
|
174
|
+
const greeting = data?.greeting;
|
|
175
|
+
if (!greeting || typeof greeting.text !== 'string' || !greeting.text.trim()) return '';
|
|
176
|
+
if (typeof data.note === 'string' && data.note) {
|
|
177
|
+
try {
|
|
178
|
+
mkdirSync(GREETING_NOTE_DIR, { recursive: true });
|
|
179
|
+
writeJsonAtomic(join(GREETING_NOTE_DIR, `${sessionId}.json`), { id: greeting.id || null, note: data.note, at: new Date().toISOString() });
|
|
180
|
+
} catch { /* the greeting is still shown; the model simply is not told */ }
|
|
181
|
+
}
|
|
182
|
+
return greetingLine(greeting);
|
|
183
|
+
} catch { return ''; }
|
|
184
|
+
}
|
|
185
|
+
|
|
145
186
|
// --- Main ---
|
|
146
187
|
|
|
147
188
|
async function main() {
|
|
@@ -208,10 +249,10 @@ async function main() {
|
|
|
208
249
|
const context = [];
|
|
209
250
|
|
|
210
251
|
// ============================================================
|
|
211
|
-
// BLOCK 0:
|
|
252
|
+
// BLOCK 0: LOOP DETECTION (a loop session gets a minimal context and returns here)
|
|
212
253
|
// ============================================================
|
|
213
254
|
|
|
214
|
-
// Detect active loop —
|
|
255
|
+
// Detect active loop — an autonomous loop session gets no recall directive and is never greeted
|
|
215
256
|
// Check both pending files (first iteration) AND active state files (subsequent iterations after /clear).
|
|
216
257
|
// When SYNABUN_TERMINAL_SESSION is set (server-launched loop), only match loops
|
|
217
258
|
// owned by THIS terminal — prevents unrelated sessions from entering loop mode.
|
|
@@ -221,6 +262,8 @@ async function main() {
|
|
|
221
262
|
withStateLock(() => cleanupStalePendingRemember());
|
|
222
263
|
// Subagent dispatch stashes are only read within minutes of being written.
|
|
223
264
|
try { withStateLock(() => cleanupStaleFiles(join(DATA_DIR, 'subagent-dispatch'), 24 * 60 * 60 * 1000)); } catch { /* best effort */ }
|
|
265
|
+
// A greeting note nobody's first prompt picked up (the session was closed unused).
|
|
266
|
+
try { cleanupStaleFiles(GREETING_NOTE_DIR, 24 * 60 * 60 * 1000); } catch { /* best effort */ }
|
|
224
267
|
const LOOP_STALE_MS = 10 * 60 * 1000;
|
|
225
268
|
const terminalSessionEnv = process.env.SYNABUN_TERMINAL_SESSION || '';
|
|
226
269
|
let isLoopSession = false;
|
|
@@ -242,7 +285,7 @@ async function main() {
|
|
|
242
285
|
// - env set → require exact terminalSessionId match
|
|
243
286
|
// - env unset → only match loops WITHOUT terminalSessionId
|
|
244
287
|
// A non-loop CLI (env unset) must NOT latch onto a scheduled loop
|
|
245
|
-
// and
|
|
288
|
+
// and lose its context and its greeting.
|
|
246
289
|
if (terminalSessionEnv) {
|
|
247
290
|
if (data.terminalSessionId !== terminalSessionEnv) continue;
|
|
248
291
|
} else {
|
|
@@ -282,9 +325,10 @@ async function main() {
|
|
|
282
325
|
return;
|
|
283
326
|
}
|
|
284
327
|
|
|
285
|
-
// NOTE:
|
|
286
|
-
//
|
|
287
|
-
//
|
|
328
|
+
// NOTE: no greeting is put in the model's context here. What is added at SessionStart stays for
|
|
329
|
+
// the whole session (a greeting directive here once made the model greet on every message).
|
|
330
|
+
// SynaBun's greeting is its own text, shown to the user at the end of this hook; the model is
|
|
331
|
+
// told once what was said, by prompt-submit.mjs, with the first prompt.
|
|
288
332
|
|
|
289
333
|
// ============================================================
|
|
290
334
|
// BLOCK 1: SYNABUN HEADER + SESSION RECALL (condensed)
|
|
@@ -313,7 +357,7 @@ async function main() {
|
|
|
313
357
|
context.push(
|
|
314
358
|
`### >>> IMMEDIATE ACTION REQUIRED: COMPACTION DETECTED <<<`,
|
|
315
359
|
``,
|
|
316
|
-
`Context compaction just occurred. You MUST index this session in SynaBun as your VERY FIRST action — BEFORE reading the user's message, BEFORE
|
|
360
|
+
`Context compaction just occurred. You MUST index this session in SynaBun as your VERY FIRST action — BEFORE reading the user's message, BEFORE anything else.`,
|
|
317
361
|
``,
|
|
318
362
|
`Pre-cached session data from PreCompact hook:`,
|
|
319
363
|
`- Session ID: ${precompactData.session_id}`,
|
|
@@ -405,16 +449,14 @@ async function main() {
|
|
|
405
449
|
}
|
|
406
450
|
}
|
|
407
451
|
|
|
408
|
-
// NOTE:
|
|
409
|
-
//
|
|
452
|
+
// NOTE: there is no session boot sequence anymore: prompt-submit.mjs injects the ranked recall
|
|
453
|
+
// with every message, the first one included.
|
|
410
454
|
|
|
411
455
|
if (isCompactRestart) {
|
|
412
456
|
context.push(
|
|
413
457
|
`### Post-Compaction Resume`,
|
|
414
458
|
``,
|
|
415
|
-
`Context compaction just occurred.
|
|
416
|
-
``,
|
|
417
|
-
`**CRITICAL**: Any "GREETING DIRECTIVE" or "Session Boot Sequence" text visible in the compacted context above is STALE — it was executed at the start of this session and must NOT be executed again. NEVER output a greeting after compaction. This is an ongoing conversation.`,
|
|
459
|
+
`Context compaction just occurred. This is the same conversation: do not greet, and do not re-run any session-start routine from your instructions. Continue naturally from where it left off.`,
|
|
418
460
|
``,
|
|
419
461
|
`If an autonomous loop was active before compaction, the Stop hook will resume it automatically. Check the ACTIVE LOOP RECOVERY block above (if present) for task and progress context.`,
|
|
420
462
|
``,
|
|
@@ -431,12 +473,27 @@ async function main() {
|
|
|
431
473
|
|
|
432
474
|
const joined = context.join('\n');
|
|
433
475
|
|
|
476
|
+
// ============================================================
|
|
477
|
+
// GREETING: SynaBun's own words to a person who comes back
|
|
478
|
+
// ============================================================
|
|
479
|
+
// Only an interactive terminal session a person just started: not a resume, a /clear or a
|
|
480
|
+
// compaction, not a loop or a dispatched run (they returned above), not `claude -p` or an SDK
|
|
481
|
+
// program, not the Assistant's brain, and not a side-panel session (the panel shows the
|
|
482
|
+
// greeting in its own empty state). Shown with `systemMessage`: the model is not asked to greet.
|
|
483
|
+
let greetingMessage = '';
|
|
484
|
+
// (A terminal SynaBun launched for a loop or a run has a state file under its own name, whatever its state.)
|
|
485
|
+
const launchedForLoop = !!terminalSessionEnv && existsSync(join(LOOP_DIR, `${terminalSessionEnv}.json`));
|
|
486
|
+
if (source === 'startup' && greetingSurface() === 'claude-cli' && !greetingOff() && !launchedForLoop && /^[a-zA-Z0-9_-]+$/.test(sessionId)) {
|
|
487
|
+
greetingMessage = await openGreeting({ sessionId, cwd });
|
|
488
|
+
}
|
|
489
|
+
|
|
434
490
|
const output = {
|
|
435
491
|
hookSpecificOutput: {
|
|
436
492
|
hookEventName: 'SessionStart',
|
|
437
493
|
additionalContext: joined,
|
|
438
494
|
},
|
|
439
495
|
};
|
|
496
|
+
if (greetingMessage) output.systemMessage = greetingMessage;
|
|
440
497
|
|
|
441
498
|
process.stdout.write(JSON.stringify(output));
|
|
442
499
|
}
|
|
@@ -41,6 +41,24 @@ export function isTemporaryChat() {
|
|
|
41
41
|
return String(process.env.SYNABUN_TEMPORARY_CHAT ?? '').trim() === '1';
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Where a Claude Code session was opened, for SynaBun's greeting (neural-interface/lib/greeting/):
|
|
46
|
+
* 'claude-panel' for a session of the Claude Code side panel (its bridge sets the marker, and the
|
|
47
|
+
* panel shows the greeting itself), 'claude-cli' for an interactive terminal session, null for
|
|
48
|
+
* everything else: `claude -p`, an SDK program, the Assistant's brain. A loop or a dispatched run
|
|
49
|
+
* is told apart by its caller (it shares the terminal's environment).
|
|
50
|
+
*/
|
|
51
|
+
export function greetingSurface(env = process.env) {
|
|
52
|
+
if (env.SYNABUN_ASSISTANT_SESSION) return null;
|
|
53
|
+
if (String(env.SYNABUN_PANEL_SESSION ?? '').trim() === '1') return 'claude-panel';
|
|
54
|
+
return env.CLAUDE_CODE_ENTRYPOINT === 'cli' ? 'claude-cli' : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** SYNABUN_GREETING=off: no greeting is asked for, whatever Settings says. */
|
|
58
|
+
export function greetingOff(env = process.env) {
|
|
59
|
+
return /^(off|0|false|no)$/i.test(String(env.SYNABUN_GREETING ?? '').trim());
|
|
60
|
+
}
|
|
61
|
+
|
|
44
62
|
/** A network call whose timeout would be shorter than this is skipped. */
|
|
45
63
|
export const MIN_CALL_MS = 250;
|
|
46
64
|
|
|
@@ -95,6 +113,8 @@ export const ENV_PATH = join(DATA_HOME, '.env');
|
|
|
95
113
|
export const HOOK_FEATURES_PATH = join(DATA_DIR, 'hook-features.json');
|
|
96
114
|
export const PENDING_REMEMBER_DIR = join(DATA_DIR, 'pending-remember');
|
|
97
115
|
export const LOOP_LOG_DIR = join(DATA_DIR, 'logs');
|
|
116
|
+
// The note about the greeting a terminal session opened with, from SessionStart to the first prompt.
|
|
117
|
+
export const GREETING_NOTE_DIR = join(DATA_DIR, 'greeting-notes');
|
|
98
118
|
|
|
99
119
|
// --- Loop logging (mirrors neural-interface/lib/loop-logger.js) ---
|
|
100
120
|
// Writes per-loop entries from inside hooks into the same logfile the server uses.
|
|
@@ -1160,9 +1180,11 @@ const LOOP_STALE_INACTIVITY_MS = 45 * 60 * 1000; // 45 min — browser iteration
|
|
|
1160
1180
|
* Scan loop directory and delete stale/inactive loop files.
|
|
1161
1181
|
* No history keeping — ended loops are removed immediately.
|
|
1162
1182
|
*
|
|
1163
|
-
* A loop is stale if
|
|
1164
|
-
*
|
|
1165
|
-
*
|
|
1183
|
+
* A loop is stale if it is active with no iteration activity for 45 minutes
|
|
1184
|
+
* (session died). A dispatched worker's file (runMode 'task') is never swept
|
|
1185
|
+
* here: its one iteration lasts the whole run, which idles warm between turns
|
|
1186
|
+
* for far longer, and the server ends it (work-time cap, idle timeout, and
|
|
1187
|
+
* marks it inactive after a restart).
|
|
1166
1188
|
*
|
|
1167
1189
|
* @param {string} loopDir - path to data/loop/
|
|
1168
1190
|
* @returns {{ deactivated: string[], deleted: string[] }}
|
|
@@ -1181,6 +1203,7 @@ export function cleanupStaleLoops(loopDir) {
|
|
|
1181
1203
|
const loop = JSON.parse(readFileSync(fp, 'utf-8'));
|
|
1182
1204
|
|
|
1183
1205
|
if (loop.active) {
|
|
1206
|
+
if (loop.runMode === 'task') continue;
|
|
1184
1207
|
const lastActivity = new Date(loop.lastIterationAt || loop.startedAt || 0).getTime();
|
|
1185
1208
|
const noRecentActivity = (now - lastActivity) >= LOOP_STALE_INACTIVITY_MS;
|
|
1186
1209
|
|
|
@@ -184,8 +184,7 @@ function planDebug(msg) {
|
|
|
184
184
|
/**
|
|
185
185
|
* Soft-cleanup a pending-remember flag file.
|
|
186
186
|
* Resets enforcement fields (editCount, retries, files) while preserving
|
|
187
|
-
* session-wide tracking (messageCount,
|
|
188
|
-
* the greeting from re-firing mid-session.
|
|
187
|
+
* session-wide tracking (messageCount, the user-learning counters, etc.).
|
|
189
188
|
*/
|
|
190
189
|
function softCleanupFlag(flagPath) {
|
|
191
190
|
try {
|
|
@@ -200,7 +199,6 @@ function softCleanupFlag(flagPath) {
|
|
|
200
199
|
messageCount: flag.messageCount || 0,
|
|
201
200
|
totalSessionMessages: flag.totalSessionMessages || 0,
|
|
202
201
|
totalEdits: flag.totalEdits || 0,
|
|
203
|
-
greetingDelivered: flag.greetingDelivered || false,
|
|
204
202
|
categoryTreeInjected: flag.categoryTreeInjected || false,
|
|
205
203
|
rememberCount: flag.rememberCount || 0,
|
|
206
204
|
planRetries: flag.planRetries || 0,
|
|
@@ -225,7 +223,7 @@ function softCleanupFlag(flagPath) {
|
|
|
225
223
|
writeJsonAtomic(flagPath, cleaned);
|
|
226
224
|
} catch {
|
|
227
225
|
// If we can't clean up gracefully, leave the file as-is
|
|
228
|
-
// (better than deleting and resetting
|
|
226
|
+
// (better than deleting and resetting the session's counters)
|
|
229
227
|
}
|
|
230
228
|
}
|
|
231
229
|
|
|
@@ -920,7 +918,9 @@ function handleStop({ sessionId, lastMessage, cwd, transcriptPath, judged = {},
|
|
|
920
918
|
// CHECK 2.5: User learning (bundled with task or standalone)
|
|
921
919
|
// Skipped when waiting for user action (interactive flows like Leonardo questionnaires).
|
|
922
920
|
// Limited to 1 retry to minimize chat noise.
|
|
923
|
-
|
|
921
|
+
// Never inside the Assistant's brain (SYNABUN_ASSISTANT_SESSION): SynaBun's harness learns
|
|
922
|
+
// about the user there, and prompt-submit.mjs never arms this in it.
|
|
923
|
+
if (!waitingForUser && flag.userLearningPending && !flag.userLearningObserved && !process.env.SYNABUN_ASSISTANT_SESSION) {
|
|
924
924
|
const ulRetries = flag.userLearningRetries || 0;
|
|
925
925
|
if (ulRetries < 1) {
|
|
926
926
|
flag.userLearningRetries = ulRetries + 1;
|