synabun 2.0.10 → 2.1.0
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 +86 -0
- package/README.md +25 -2
- package/THIRD-PARTY-LICENSES.md +22 -0
- package/bin/synabun.js +71 -24
- package/docs/whatsapp.md +2 -2
- package/hooks/claude-code/pre-websearch.mjs +12 -1
- package/hooks/claude-code/shared.mjs +5 -0
- package/hooks/claude-code/stop.mjs +1 -1
- package/lib/claude-hooks.js +172 -18
- package/lib/client-config-repair.js +17 -8
- package/lib/desktop-app.js +7 -1
- package/lib/external-tools.js +1 -1
- package/lib/first-launch-protection.js +57 -12
- package/lib/mcp-dist.js +176 -0
- package/lib/release-npm-ci.mjs +138 -0
- package/lib/release-publish.mjs +91 -0
- package/lib/release-scan.mjs +50 -0
- package/lib/server-crash-record.js +123 -0
- package/lib/server-exit.js +318 -0
- package/lib/server-supervisor.js +508 -0
- package/lib/start-launcher.js +37 -4
- package/lib/tools-cli.js +45 -0
- package/lib/update-snapshot.js +228 -0
- package/lib/virustotal.mjs +192 -0
- package/lib/windows-crash-event.js +269 -0
- package/mcp-server/dist/http.d.ts +20 -1
- package/mcp-server/dist/http.d.ts.map +1 -1
- package/mcp-server/dist/http.js +59 -12
- package/mcp-server/dist/http.js.map +1 -1
- package/mcp-server/dist/index.d.ts +33 -27
- package/mcp-server/dist/index.d.ts.map +1 -1
- package/mcp-server/dist/index.js +128 -143
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/preload.js +1 -1
- package/mcp-server/dist/preload.js.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.js +81 -28
- package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
- package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
- package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
- package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
- package/mcp-server/dist/services/neural-interface.d.ts +16 -10
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js +67 -11
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/server-instructions.d.ts +7 -2
- package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
- package/mcp-server/dist/services/server-instructions.js +20 -62
- package/mcp-server/dist/services/server-instructions.js.map +1 -1
- package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
- package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-catalog.js +339 -0
- package/mcp-server/dist/services/tool-catalog.js.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
- package/mcp-server/dist/services/tool-list.d.ts +108 -0
- package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list.js +334 -0
- package/mcp-server/dist/services/tool-list.js.map +1 -0
- package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
- package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-runtime.js +400 -0
- package/mcp-server/dist/services/tool-runtime.js.map +1 -0
- package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
- package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
- package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
- package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +10 -10
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +22 -13
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
- package/mcp-server/dist/tools/image-tools.d.ts +1 -1
- package/mcp-server/dist/tools/image-tools.js +1 -1
- package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
- package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill-tools.js +639 -0
- package/mcp-server/dist/tools/skill-tools.js.map +1 -0
- package/mcp-server/dist/tools/skill.d.ts +7 -0
- package/mcp-server/dist/tools/skill.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill.js +11 -0
- package/mcp-server/dist/tools/skill.js.map +1 -0
- package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
- package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
- package/mcp-server/dist/tools/tool-groups.js +147 -0
- package/mcp-server/dist/tools/tool-groups.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-format.js +7 -4
- package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
- package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
- package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -1
- package/mcp-server/src/http.ts +75 -12
- package/mcp-server/src/index.ts +147 -154
- package/mcp-server/src/preload.ts +12 -12
- package/mcp-server/src/services/codex-config-heal.ts +80 -29
- package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
- package/mcp-server/src/services/neural-interface.ts +79 -20
- package/mcp-server/src/services/server-instructions.ts +27 -63
- package/mcp-server/src/services/tool-catalog.ts +403 -0
- package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
- package/mcp-server/src/services/tool-list.ts +410 -0
- package/mcp-server/src/services/tool-runtime.ts +457 -0
- package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
- package/mcp-server/src/tools/agents.ts +22 -14
- package/mcp-server/src/tools/image-tools.ts +1 -1
- package/mcp-server/src/tools/skill-tools.ts +589 -0
- package/mcp-server/src/tools/skill.ts +13 -0
- package/mcp-server/src/tools/tool-groups.ts +164 -0
- package/mcp-server/src/tools/whiteboard-format.ts +9 -3
- package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
- package/neural-interface/i18n/en.json +3463 -200
- package/neural-interface/i18n/pt-BR.json +3411 -151
- package/neural-interface/lib/assistant-api.js +127 -28
- package/neural-interface/lib/assistant-brains/claude.js +4 -3
- package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
- package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
- package/neural-interface/lib/assistant-brains/codex.js +9 -5
- package/neural-interface/lib/assistant-brains/opencode.js +120 -54
- package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
- package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
- package/neural-interface/lib/assistant-catalog.js +6 -7
- package/neural-interface/lib/assistant-dispatch.js +871 -156
- package/neural-interface/lib/assistant-envelope.js +3 -1
- package/neural-interface/lib/assistant-persona.js +80 -11
- package/neural-interface/lib/assistant-plan-permissions.js +10 -9
- package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
- package/neural-interface/lib/assistant-route-gate.js +6 -4
- package/neural-interface/lib/assistant-router.js +13 -8
- package/neural-interface/lib/assistant-runtime.js +56 -18
- package/neural-interface/lib/assistant-task-prompt.js +78 -14
- package/neural-interface/lib/assistant-tools.js +51 -0
- package/neural-interface/lib/backup-service.js +620 -3
- package/neural-interface/lib/backup-zip-reader.js +10 -5
- package/neural-interface/lib/backup-zip-writer.js +257 -0
- package/neural-interface/lib/browser-execution.js +10 -2
- package/neural-interface/lib/browser-guard-cdp.js +83 -0
- package/neural-interface/lib/browser-network-guard.js +284 -0
- package/neural-interface/lib/browser-policy-roots.js +64 -0
- package/neural-interface/lib/browser-tool-policy.js +186 -31
- package/neural-interface/lib/claude-agent-bridge.js +4 -2
- package/neural-interface/lib/claude-hooks-status.js +103 -0
- package/neural-interface/lib/claude-temporary.js +5 -11
- package/neural-interface/lib/cli-install.js +18 -138
- package/neural-interface/lib/cli-resolver.js +4 -1
- package/neural-interface/lib/cli-update-planner.js +32 -31
- package/neural-interface/lib/cloudflared/tunnel.js +42 -2
- package/neural-interface/lib/codex-mcp-approvals.js +11 -0
- package/neural-interface/lib/codex-worker-app-server.js +172 -0
- package/neural-interface/lib/confined-fs.js +30 -3
- package/neural-interface/lib/crash-notice-api.js +98 -0
- package/neural-interface/lib/editor-completion-opencode.js +68 -68
- package/neural-interface/lib/exec-loop-command.js +4 -8
- package/neural-interface/lib/http-guards.js +8 -2
- package/neural-interface/lib/install-details.js +4 -1
- package/neural-interface/lib/mcp-agent-servers.js +67 -0
- package/neural-interface/lib/mcp-client-config.js +0 -29
- package/neural-interface/lib/mcp-external-servers.js +323 -0
- package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
- package/neural-interface/lib/morelogin.js +30 -0
- package/neural-interface/lib/native-loop-providers.js +547 -47
- package/neural-interface/lib/native-loop-runtime.js +268 -41
- package/neural-interface/lib/opencode-config.js +557 -0
- package/neural-interface/lib/opencode-db-schema.js +17 -34
- package/neural-interface/lib/opencode-history.js +48 -218
- package/neural-interface/lib/opencode-mcp-ready.js +108 -0
- package/neural-interface/lib/opencode-native-boundary.js +44 -0
- package/neural-interface/lib/opencode-protocol.js +249 -112
- package/neural-interface/lib/opencode-runtime-config.js +32 -22
- package/neural-interface/lib/opencode-serve-records.js +39 -21
- package/neural-interface/lib/opencode-v2-client.js +48 -153
- package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
- package/neural-interface/lib/opencode-worker-data.js +27 -0
- package/neural-interface/lib/opencode2-client.js +73 -37
- package/neural-interface/lib/opencode2-proxy.js +23 -63
- package/neural-interface/lib/opencode2-translate.js +51 -2
- package/neural-interface/lib/owner-authority.js +249 -0
- package/neural-interface/lib/page-session.js +275 -0
- package/neural-interface/lib/peer-identity.js +763 -0
- package/neural-interface/lib/request-gate.js +17 -2
- package/neural-interface/lib/rulesets/api.js +1 -1
- package/neural-interface/lib/rulesets/fs-safe.js +1 -1
- package/neural-interface/lib/rulesets/installer.js +92 -27
- package/neural-interface/lib/rulesets/json-edit.js +1 -1
- package/neural-interface/lib/session-cache-builder.js +17 -30
- package/neural-interface/lib/session-title-generator.js +58 -36
- package/neural-interface/lib/skills/api-v2.js +495 -0
- package/neural-interface/lib/skills/bundle.js +418 -0
- package/neural-interface/lib/skills/catalog.js +294 -0
- package/neural-interface/lib/skills/creation-api.js +191 -0
- package/neural-interface/lib/skills/creation-brief.js +247 -0
- package/neural-interface/lib/skills/creation-sources.js +267 -0
- package/neural-interface/lib/skills/creation.js +843 -0
- package/neural-interface/lib/skills/deploy.js +564 -0
- package/neural-interface/lib/skills/digest.js +119 -0
- package/neural-interface/lib/skills/discover.js +111 -0
- package/neural-interface/lib/skills/draft-confinement.js +214 -0
- package/neural-interface/lib/skills/eval-confinement.js +397 -0
- package/neural-interface/lib/skills/eval-sandbox.js +280 -0
- package/neural-interface/lib/skills/eval-trace.js +119 -0
- package/neural-interface/lib/skills/evals-api.js +212 -0
- package/neural-interface/lib/skills/evals.js +1573 -0
- package/neural-interface/lib/skills/export.js +200 -0
- package/neural-interface/lib/skills/frontmatter.js +64 -0
- package/neural-interface/lib/skills/health.js +75 -0
- package/neural-interface/lib/skills/json-edit.js +165 -0
- package/neural-interface/lib/skills/known-bridge-digests.json +387 -0
- package/neural-interface/lib/skills/known-bridges.js +96 -0
- package/neural-interface/lib/skills/library.js +823 -0
- package/neural-interface/lib/skills/local-store.js +21 -0
- package/neural-interface/lib/skills/migration.js +433 -0
- package/neural-interface/lib/skills/operations.js +45 -0
- package/neural-interface/lib/skills/ownership.js +427 -0
- package/neural-interface/lib/skills/packages.js +88 -0
- package/neural-interface/lib/skills/reviews.js +212 -0
- package/neural-interface/lib/skills/revision.js +80 -0
- package/neural-interface/lib/skills/roots.js +262 -0
- package/neural-interface/lib/skills/runtime-checks.js +355 -0
- package/neural-interface/lib/skills/scan-assets.js +252 -0
- package/neural-interface/lib/skills/scan-context.js +26 -0
- package/neural-interface/lib/skills/scan-shell.js +324 -0
- package/neural-interface/lib/skills/scan.js +364 -0
- package/neural-interface/lib/skills/scanners.js +54 -0
- package/neural-interface/lib/skills/service.js +522 -0
- package/neural-interface/lib/skills/telemetry.js +113 -0
- package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
- package/neural-interface/lib/tool-lists.js +124 -0
- package/neural-interface/lib/whatsapp/bridge.js +6 -3
- package/neural-interface/lib/worker-confinement.js +1192 -0
- package/neural-interface/lib/worker-guard-setting.js +56 -0
- package/neural-interface/lib/worker-mcp-channel.js +175 -0
- package/neural-interface/lib/worker-relay-ports.js +227 -0
- package/neural-interface/lib/worker-resume.js +229 -0
- package/neural-interface/lib/worker-sandbox.js +299 -0
- package/neural-interface/package-lock.json +18 -12
- package/neural-interface/package.json +2 -2
- package/neural-interface/public/index.html +3 -1
- package/neural-interface/public/index2d.html +19 -11
- package/neural-interface/public/onboarding.html +2 -2
- package/neural-interface/public/shared/account-menu.js +8 -5
- package/neural-interface/public/shared/agent-runtime-options.js +35 -19
- package/neural-interface/public/shared/api.js +1527 -1336
- package/neural-interface/public/shared/app-frame.js +192 -0
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +33 -2
- package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
- package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
- package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +49 -35
- package/neural-interface/public/shared/assistant/asst-control.js +157 -26
- package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
- package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
- package/neural-interface/public/shared/assistant/asst-limit-dock.js +40 -0
- package/neural-interface/public/shared/assistant/asst-limit-wait.js +294 -0
- package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
- package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
- package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
- package/neural-interface/public/shared/assistant/asst-panel.js +106 -11
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
- package/neural-interface/public/shared/assistant/asst-render.js +401 -77
- package/neural-interface/public/shared/assistant/asst-route.js +83 -12
- package/neural-interface/public/shared/assistant/asst-scenes.js +2 -0
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +67 -4
- package/neural-interface/public/shared/assistant/asst-slash.js +9 -7
- package/neural-interface/public/shared/assistant/asst-state.js +11 -15
- package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +59 -21
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +156 -16
- package/neural-interface/public/shared/automation-context.js +5 -2
- package/neural-interface/public/shared/cc-dropdown.js +89 -19
- package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
- package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
- package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
- package/neural-interface/public/shared/cdx/cdx-output.js +8 -7
- package/neural-interface/public/shared/cdx/cdx-panel.js +45 -149
- package/neural-interface/public/shared/cdx/cdx-protocol.js +28 -1
- package/neural-interface/public/shared/cdx/cdx-render.js +47 -29
- package/neural-interface/public/shared/cdx/cdx-requests.js +3 -3
- package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +11 -3
- package/neural-interface/public/shared/cdx/cdx-tabs.js +52 -39
- package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
- package/neural-interface/public/shared/cli-install-view.js +4 -8
- package/neural-interface/public/shared/cli-status.js +2 -2
- package/neural-interface/public/shared/constants.js +2 -2
- package/neural-interface/public/shared/context-menu-areas.js +34 -0
- package/neural-interface/public/shared/context-menu-logic.js +243 -0
- package/neural-interface/public/shared/context-menu-model.js +366 -0
- package/neural-interface/public/shared/context-menu.js +372 -0
- package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
- package/neural-interface/public/shared/crash-notice-view.js +168 -0
- package/neural-interface/public/shared/desktop-update-view.js +20 -0
- package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
- package/neural-interface/public/shared/html-shell.js +9 -11
- package/neural-interface/public/shared/i18n.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +47 -252
- package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +6 -21
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
- package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
- package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
- package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +0 -21
- package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +14 -47
- package/neural-interface/public/shared/page-session.js +96 -0
- package/neural-interface/public/shared/registry.js +5 -3
- package/neural-interface/public/shared/retired-2d.js +3 -0
- package/neural-interface/public/shared/schedules-view.js +195 -61
- package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
- package/neural-interface/public/shared/settings/settings-data.js +3 -1
- package/neural-interface/public/shared/settings/settings-ia.js +6 -6
- package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
- package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
- package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
- package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
- package/neural-interface/public/shared/skills/ss-args.js +96 -0
- package/neural-interface/public/shared/skills/ss-creation.js +219 -0
- package/neural-interface/public/shared/skills/ss-dialog.js +130 -0
- package/neural-interface/public/shared/skills/ss-doc.js +173 -0
- package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
- package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
- package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
- package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
- package/neural-interface/public/shared/skills/ss-evals.js +417 -0
- package/neural-interface/public/shared/skills/ss-form.js +159 -0
- package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
- package/neural-interface/public/shared/skills/ss-ids.js +32 -0
- package/neural-interface/public/shared/skills/ss-lint.js +141 -0
- package/neural-interface/public/shared/skills/ss-presets.js +117 -0
- package/neural-interface/public/shared/skills/ss-profiles.js +475 -0
- package/neural-interface/public/shared/skills/ss-resources.js +165 -0
- package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
- package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
- package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
- package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
- package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai.js +236 -0
- package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
- package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
- package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
- package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
- package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
- package/neural-interface/public/shared/skills/studio/sx-dom.js +229 -0
- package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
- package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
- package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
- package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
- package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
- package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
- package/neural-interface/public/shared/skills/studio/sx-install-flow.js +279 -0
- package/neural-interface/public/shared/skills/studio/sx-install.js +296 -0
- package/neural-interface/public/shared/skills/studio/sx-library-view.js +639 -0
- package/neural-interface/public/shared/skills/studio/sx-library.js +475 -0
- package/neural-interface/public/shared/skills/studio/sx-main.js +681 -0
- package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
- package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
- package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
- package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
- package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
- package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
- package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
- package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
- package/neural-interface/public/shared/skills/studio/sx-subject.js +248 -0
- package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
- package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
- package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
- package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +425 -0
- package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
- package/neural-interface/public/shared/styles.css +1525 -1779
- package/neural-interface/public/shared/synabun-mascot.js +1115 -9
- package/neural-interface/public/shared/tool-list-picker.js +55 -0
- package/neural-interface/public/shared/tool-list-storage.js +24 -0
- package/neural-interface/public/shared/tool-list-view.js +112 -0
- package/neural-interface/public/shared/tour/tour-actor.js +268 -0
- package/neural-interface/public/shared/tour/tour-beats.js +336 -0
- package/neural-interface/public/shared/tour/tour-engine.js +884 -0
- package/neural-interface/public/shared/tour/tour-ink.js +390 -0
- package/neural-interface/public/shared/tour/tour-stage.js +440 -0
- package/neural-interface/public/shared/tour/tour-state.js +40 -0
- package/neural-interface/public/shared/tour/tour-tips.js +99 -0
- package/neural-interface/public/shared/tour/tour.css +144 -0
- package/neural-interface/public/shared/ui-automation-studio.js +91 -128
- package/neural-interface/public/shared/ui-claude-panel.js +77 -5
- package/neural-interface/public/shared/ui-command-runner.js +6 -3
- package/neural-interface/public/shared/ui-context-menu.js +295 -0
- package/neural-interface/public/shared/ui-cost-widget.js +57 -59
- package/neural-interface/public/shared/ui-crash-notice.js +187 -0
- package/neural-interface/public/shared/ui-detail.js +15 -3
- package/neural-interface/public/shared/ui-image-gallery.js +50 -47
- package/neural-interface/public/shared/ui-keybinds.js +26 -1
- package/neural-interface/public/shared/ui-menubar.js +8 -18
- package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +7 -1
- package/neural-interface/public/shared/ui-navbar.js +4 -24
- package/neural-interface/public/shared/ui-panels.js +96 -65
- package/neural-interface/public/shared/ui-schedules-studio.js +507 -423
- package/neural-interface/public/shared/ui-sessions.js +5 -3
- package/neural-interface/public/shared/ui-settings.js +594 -462
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +1 -1
- package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
- package/neural-interface/public/shared/ui-sidepanel-windows.js +16 -11
- package/neural-interface/public/shared/ui-skills.js +33 -2830
- package/neural-interface/public/shared/ui-styleguide.js +5 -2
- package/neural-interface/public/shared/ui-sync.js +15 -5
- package/neural-interface/public/shared/ui-terminal.js +124 -180
- package/neural-interface/public/shared/ui-tool-updates.js +3 -1
- package/neural-interface/public/shared/ui-tooltip.js +10 -5
- package/neural-interface/public/shared/ui-trash.js +6 -4
- package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
- package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
- package/neural-interface/public/shared/ui-tutorial.css +47 -100
- package/neural-interface/public/shared/ui-tutorial.js +285 -509
- package/neural-interface/public/shared/ui-update.js +38 -2
- package/neural-interface/public/shared/ui-whiteboard.js +311 -58
- package/neural-interface/public/shared/ui-worker-end.js +4 -0
- package/neural-interface/public/shared/ui-workspaces.js +3 -2
- package/neural-interface/public/shared/view-variant.js +66 -0
- package/neural-interface/public/shared/whatsapp/wa-view.js +1 -1
- package/neural-interface/public/shared/whiteboard-list.js +172 -0
- package/neural-interface/public/shared/worker-end.js +10 -3
- package/neural-interface/public/shared/worker-restart.js +12 -0
- package/neural-interface/public/sidepanel-session.html +1 -1
- package/neural-interface/public/variant/2d/background.js +2 -1
- package/neural-interface/public/variant/2d/context-menu.js +8 -2
- package/neural-interface/public/variant/2d/graph.js +42 -20
- package/neural-interface/public/variant/2d/hulls.js +14 -9
- package/neural-interface/public/variant/2d/lasso.js +11 -7
- package/neural-interface/public/variant/2d/main.js +32 -1
- package/neural-interface/public/variant/2d/minimap.js +11 -13
- package/neural-interface/public/variant/3d/main.js +69 -6
- package/neural-interface/public/variant/3d/map-controls.js +24 -9
- package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat.css +17 -0
- package/neural-interface/public/vendor/caveat/manifest.json +12 -0
- package/neural-interface/public/vendor/yaml/LICENSE +13 -0
- package/neural-interface/public/vendor/yaml/manifest.json +4 -0
- package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
- package/neural-interface/scripts/build-vendor.mjs +32 -0
- package/neural-interface/server.js +3934 -2454
- package/neural-interface/templates/rulesets/core.md +1 -1
- package/neural-interface/templates/rulesets/legacy-hashes.json +18 -0
- package/neural-interface/templates/rulesets/manifest.json +8 -8
- package/npm-shrinkwrap.json +18 -12
- package/package.json +16 -3
- package/postinstall.js +9 -4
- package/preuninstall.js +1 -1
- package/setup.js +97 -322
- package/skills/skill-forge/SKILL.md +177 -0
- package/skills/skill-forge/evals/evals.json +54 -0
- package/skills/skill-forge/references/package.md +105 -0
- package/skills/skill-forge/references/review-and-recovery.md +63 -0
- package/skills/skill-forge/references/runtime-profiles.md +20 -0
- package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
- package/skills/synabun/SKILL.md +10 -7
- package/skills/synabun/modules/audit.md +1 -5
- package/skills/synabun/modules/changelog.md +1 -5
- package/skills/synabun/modules/idea.md +1 -1
- package/skills/synabun/modules/memorize.md +6 -9
- package/skills/synabun/modules/schedule.md +4 -4
- package/mcp-server/dist/services/profiles.d.ts +0 -120
- package/mcp-server/dist/services/profiles.d.ts.map +0 -1
- package/mcp-server/dist/services/profiles.js +0 -387
- package/mcp-server/dist/services/profiles.js.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
- package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
- package/mcp-server/dist/tools/leonardo.d.ts +0 -13
- package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo.js +0 -21
- package/mcp-server/dist/tools/leonardo.js.map +0 -1
- package/mcp-server/dist/tools/profile.d.ts +0 -17
- package/mcp-server/dist/tools/profile.d.ts.map +0 -1
- package/mcp-server/dist/tools/profile.js +0 -114
- package/mcp-server/dist/tools/profile.js.map +0 -1
- package/mcp-server/src/services/profiles.ts +0 -428
- package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
- package/mcp-server/src/tools/leonardo.ts +0 -30
- package/mcp-server/src/tools/profile.ts +0 -122
- package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
- package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
- package/neural-interface/lib/mcp-profile-servers.js +0 -120
- package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
- package/skills/leonardo/SKILL.md +0 -168
- package/skills/leonardo/icon.svg +0 -1
- package/skills/leonardo/modules/browser-guide.md +0 -378
- package/skills/leonardo/modules/image-prompter.md +0 -283
- package/skills/leonardo/modules/model-advisor.md +0 -100
- package/skills/leonardo/modules/prompt-library.md +0 -110
- package/skills/leonardo/modules/style-guide.md +0 -186
- package/skills/leonardo/modules/video-prompter.md +0 -317
|
@@ -23,7 +23,7 @@ import { createStickyScrollController } from './ui-scroll-follow.js';
|
|
|
23
23
|
import { requestGeneratedSessionTitle } from './session-title.js';
|
|
24
24
|
import { wireFileLinks } from './ui-file-links.js';
|
|
25
25
|
import { WORKER_END_CLASS, backToAssistant, buildWorkerEndCard, endWorkerRunOnClose, forgetWorkerEnd, trackWorkerEnd, updateWorkerEndBusy } from './ui-worker-end.js';
|
|
26
|
-
import { isDispatchedRun, isEndOfRunAbort } from './worker-end.js';
|
|
26
|
+
import { isDispatchedRun, isEndOfRunAbort, workerEndView } from './worker-end.js';
|
|
27
27
|
import { runAwaitsAnswer } from './sidepanel-session-status.js';
|
|
28
28
|
// ── cp/ feature modules (SDK-engine CLI parity: diffs, agents, bash, perms, statusline) ──
|
|
29
29
|
import { setCpCtx } from './cp/cp-ctx.js';
|
|
@@ -2600,7 +2600,7 @@ function injectStyles() {
|
|
|
2600
2600
|
border: 0.5px solid rgba(255,255,255,0.05);
|
|
2601
2601
|
border-radius: 6px;
|
|
2602
2602
|
font-size: 11px; color: rgba(255,255,255,0.7);
|
|
2603
|
-
cursor:
|
|
2603
|
+
cursor: move;
|
|
2604
2604
|
transition: background 0.15s, border-color 0.15s;
|
|
2605
2605
|
}
|
|
2606
2606
|
.cp-queue-item:hover {
|
|
@@ -2614,7 +2614,7 @@ function injectStyles() {
|
|
|
2614
2614
|
background: rgba(120,180,255,0.08);
|
|
2615
2615
|
}
|
|
2616
2616
|
.cp-queue-drag {
|
|
2617
|
-
color: rgba(255,255,255,0.2); cursor:
|
|
2617
|
+
color: rgba(255,255,255,0.2); cursor: move;
|
|
2618
2618
|
font-size: 10px; user-select: none; flex-shrink: 0;
|
|
2619
2619
|
}
|
|
2620
2620
|
.cp-queue-text {
|
|
@@ -5442,7 +5442,8 @@ function _processTabMsg(tab, msg) {
|
|
|
5442
5442
|
if (expectRunning && !(tab.sendStartedAt > tab._reattachSentAt)) {
|
|
5443
5443
|
console.log('[claude-panel] No orphan to reattach — the turn ended while disconnected');
|
|
5444
5444
|
finishTab(tab, true);
|
|
5445
|
-
|
|
5445
|
+
// A dispatched worker's session says what became of its run (resumed, or how it ended), not only this.
|
|
5446
|
+
_lostTurnLine(tab).then((line) => { if (!tab.closed) appendStatus(tab, line); });
|
|
5446
5447
|
}
|
|
5447
5448
|
// Prompts queued behind a Compact when the socket closed: nothing says it finished.
|
|
5448
5449
|
if (tab._queueWaits === 'session') _compactQueue.after(tab, 'lost');
|
|
@@ -10452,8 +10453,11 @@ export async function attachClaudeAutomation(run, { focus = !!run?.focus, isCanc
|
|
|
10452
10453
|
}
|
|
10453
10454
|
if (!tab) return { ok: false, reason: 'tab_limit' };
|
|
10454
10455
|
const running = run.status === 'starting' || run.status === 'running';
|
|
10456
|
+
// A dispatched worker a server restart cut off: suspended until the next start resumes it as the same run
|
|
10457
|
+
// (lib/assistant-dispatch.js). It still owns this tab; nothing of its cut-off turn runs any more.
|
|
10458
|
+
const suspended = run.status === 'suspended';
|
|
10455
10459
|
tab.automationRunId = run.runId;
|
|
10456
|
-
tab.automationActive = running;
|
|
10460
|
+
tab.automationActive = running || suspended;
|
|
10457
10461
|
tab.automationOwnerId = nativeLoopWindowId;
|
|
10458
10462
|
tab.releasedRunId = null;
|
|
10459
10463
|
tab.sdkMode = true;
|
|
@@ -10467,6 +10471,12 @@ export async function attachClaudeAutomation(run, { focus = !!run?.focus, isCanc
|
|
|
10467
10471
|
setRunning(tab, running);
|
|
10468
10472
|
updatePillLabel(tab);
|
|
10469
10473
|
tab._automationIteration = run.currentIteration;
|
|
10474
|
+
// Resumed after a server restart: what the run did while this window was away (the continuation prompt, its first
|
|
10475
|
+
// steps: events sent before the page reconnected) is in its transcript, not in this tab, which reads it again.
|
|
10476
|
+
// That holds for a run that resumed and ended while this window was away too.
|
|
10477
|
+
const resumes = Number(run.resumes) || 0;
|
|
10478
|
+
const resumedSinceSeen = resumes > (tab._automationResumes || 0);
|
|
10479
|
+
if (tab._automationHydrated && resumedSinceSeen) tab._automationHydrated = false;
|
|
10470
10480
|
if (!tab._automationHydrated) {
|
|
10471
10481
|
tab._automationHydrated = true;
|
|
10472
10482
|
if (tab.messagesEl) tab.messagesEl.innerHTML = '';
|
|
@@ -10476,6 +10486,10 @@ export async function attachClaudeAutomation(run, { focus = !!run?.focus, isCanc
|
|
|
10476
10486
|
return { ok: false, reason: 'dismissed' };
|
|
10477
10487
|
}
|
|
10478
10488
|
}
|
|
10489
|
+
if (running && resumedSinceSeen && tab._automationResumes !== undefined) appendStatus(tab, 'Resumed after the server restart — the run continues here.');
|
|
10490
|
+
tab._automationResumes = Math.max(tab._automationResumes || 0, resumes);
|
|
10491
|
+
if (suspended) _showRunSuspended(tab, run);
|
|
10492
|
+
else tab._automationSuspendedAt = null;
|
|
10479
10493
|
// (A dispatched worker's failure, with its reason, is on its end card.)
|
|
10480
10494
|
if (run.status === 'failed' && run.error && !isDispatchedRun(run) && tab._automationLifecycleError !== run.error) {
|
|
10481
10495
|
tab._automationLifecycleError = run.error;
|
|
@@ -10527,6 +10541,64 @@ function hasLiveBackgroundWork(tab) {
|
|
|
10527
10541
|
return false;
|
|
10528
10542
|
}
|
|
10529
10543
|
|
|
10544
|
+
const LOST_TURN_LINE = 'Connection lost — this turn did not survive the disconnect.';
|
|
10545
|
+
// What a tab says when the turn it showed did not survive a lost connection. When its session is a dispatched worker's
|
|
10546
|
+
// (a tab opened on that session), the line says what became of the run: resumed after a server restart (in its own
|
|
10547
|
+
// tab), or how it ended, with its reason. A tab the user continued by hand after its run ended keeps the generic line:
|
|
10548
|
+
// the turn that was cut off was the user's own.
|
|
10549
|
+
async function _lostTurnLine(tab) {
|
|
10550
|
+
if (!tab?.sessionId || tab.releasedRunId) return LOST_TURN_LINE;
|
|
10551
|
+
try {
|
|
10552
|
+
const res = await fetch('/api/sidepanel-runs');
|
|
10553
|
+
const runs = res.ok ? ((await res.json())?.runs || []) : [];
|
|
10554
|
+
const run = runs.find((item) => item?.providerSessionId === tab.sessionId && isDispatchedRun(item));
|
|
10555
|
+
if (!run) return LOST_TURN_LINE;
|
|
10556
|
+
if (run.status === 'suspended') return 'SynaBun restarted — this worker run is being resumed in its own tab.';
|
|
10557
|
+
if (run.status === 'starting' || run.status === 'running') {
|
|
10558
|
+
return Number(run.resumes) > 0 ? 'SynaBun restarted — this worker run was resumed and continues in its own tab.' : LOST_TURN_LINE;
|
|
10559
|
+
}
|
|
10560
|
+
let dispatch = null;
|
|
10561
|
+
try {
|
|
10562
|
+
const reply = await fetch(`/api/assistant/runs/${encodeURIComponent(run.runId)}`);
|
|
10563
|
+
if (reply.ok) dispatch = (await reply.json())?.run || null;
|
|
10564
|
+
} catch {}
|
|
10565
|
+
const view = workerEndView(run, dispatch);
|
|
10566
|
+
return view ? `This session's worker run ended: ${view.title}${view.detail ? ` — ${view.detail}` : ''}` : LOST_TURN_LINE;
|
|
10567
|
+
} catch {
|
|
10568
|
+
return LOST_TURN_LINE;
|
|
10569
|
+
}
|
|
10570
|
+
}
|
|
10571
|
+
|
|
10572
|
+
// A run tab whose run the server suspended as it restarted (status 'suspended'): its turn was cut off, so the tab
|
|
10573
|
+
// stops looking busy (spinner, a tool row and its timer, background shells: all went with the CLI) and says the run
|
|
10574
|
+
// resumes. Once per suspension.
|
|
10575
|
+
function _showRunSuspended(tab, run) {
|
|
10576
|
+
const key = run?.suspendedAt || 'suspended';
|
|
10577
|
+
if (tab._automationSuspendedAt === key) return;
|
|
10578
|
+
tab._automationSuspendedAt = key;
|
|
10579
|
+
finishTab(tab, true);
|
|
10580
|
+
_closeCutOffTools(tab);
|
|
10581
|
+
appendStatus(tab, 'SynaBun restarted — resuming this run…');
|
|
10582
|
+
}
|
|
10583
|
+
|
|
10584
|
+
// Every tool call of the tab still waiting for its result is closed as cut off, through the path a result takes (the
|
|
10585
|
+
// card's state, its timer, an agent card), and the background work the tab showed is over.
|
|
10586
|
+
function _closeCutOffTools(tab) {
|
|
10587
|
+
const $msgs = tab?.messagesEl;
|
|
10588
|
+
if (!$msgs) return;
|
|
10589
|
+
for (const card of $msgs.querySelectorAll('.tool-card[data-tool-id]')) {
|
|
10590
|
+
if (card.classList.contains('tool-ok') || card.classList.contains('tool-error') || card.dataset.resolved === '1') continue;
|
|
10591
|
+
if (!card.dataset.toolId) continue;
|
|
10592
|
+
try { updateToolResult(tab, { type: 'tool_result', tool_use_id: card.dataset.toolId, is_error: true, content: 'Cut off by the server restart.' }); } catch {}
|
|
10593
|
+
}
|
|
10594
|
+
let shells = false;
|
|
10595
|
+
for (const task of tab.bgTasks?.values?.() || []) {
|
|
10596
|
+
if (task?.status === 'running') { task.status = 'stopped'; shells = true; }
|
|
10597
|
+
}
|
|
10598
|
+
if (shells) { try { renderBgTray(tab); } catch {} }
|
|
10599
|
+
_setBackgroundWork(tab, []);
|
|
10600
|
+
}
|
|
10601
|
+
|
|
10530
10602
|
// The end of a worker the Assistant dispatched (ui-worker-end.js): one card,
|
|
10531
10603
|
// the last row of its transcript. Its button closes this tab the way the X
|
|
10532
10604
|
// does (a warm worker that finished its task is completed, one still at work
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { emit, on } from './state.js';
|
|
3
3
|
import { KEYS, COLOR_PALETTE } from './constants.js';
|
|
4
4
|
import { storage } from './storage.js';
|
|
5
|
+
import { frameRect, clampBox } from './app-frame.js';
|
|
5
6
|
import { commandLaunchPayload, selectCommandGroups, isCommandLaunchAvailable } from './command-runner-model.js';
|
|
6
7
|
|
|
7
8
|
const $ = id => document.getElementById(id);
|
|
@@ -35,9 +36,11 @@ export function initCommandRunner() { return on('command-runner:open', openPanel
|
|
|
35
36
|
function clampPanel() {
|
|
36
37
|
if (!_panel) return;
|
|
37
38
|
const width = _panel.offsetWidth, height = _panel.offsetHeight;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
_panel.style.
|
|
39
|
+
// Inside the app frame (8px from the window and the bar, as before, and clear of an open explorer)
|
|
40
|
+
const f = frameRect();
|
|
41
|
+
const at = clampBox(parseFloat(_panel.style.left) || f.left, parseFloat(_panel.style.top) || f.top, width, height, f);
|
|
42
|
+
_panel.style.left = at.x + 'px';
|
|
43
|
+
_panel.style.top = at.y + 'px';
|
|
41
44
|
}
|
|
42
45
|
function openPanel() {
|
|
43
46
|
if (_panel) { $('cr-search')?.focus(); return; }
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun Neural Interface — The app's right-click menu
|
|
3
|
+
// A right-click anywhere that has no menu of its own opens the app's menu
|
|
4
|
+
// instead of the browser's: page actions, then what fits what was clicked
|
|
5
|
+
// (selected text, a link, an image, a memory, the memory map, the 2D graph,
|
|
6
|
+
// the focus-mode whiteboard), then the app's panels and tools. The
|
|
7
|
+
// ContextMenu key and Shift+F10 open it at the focused element.
|
|
8
|
+
//
|
|
9
|
+
// The rule: the app's menu opens unless the element under the pointer shows
|
|
10
|
+
// a menu of its own for that very click. Such an element takes the event
|
|
11
|
+
// (preventDefault) only when it opens its menu: the terminal's viewport, a
|
|
12
|
+
// File Explorer row or its empty tree, an editor tab, a 2D graph card, an
|
|
13
|
+
// Automation Studio item or folder, the map's canvas (OrbitControls takes
|
|
14
|
+
// every right-click there for right-drag pan; the map opens this menu itself
|
|
15
|
+
// when the right button comes up where it went down). An area that only
|
|
16
|
+
// suppressed the browser's menu would leave the user with nothing, so none
|
|
17
|
+
// does. NATIVE_CONTEXTMENU_SELECTORS names exact elements, never a whole
|
|
18
|
+
// screen or panel. Fields keep the browser's menu (spelling, paste), and so
|
|
19
|
+
// does any right-click with Shift held.
|
|
20
|
+
//
|
|
21
|
+
// The items are context-menu-model.js; the component is context-menu.js;
|
|
22
|
+
// the areas registry is context-menu-areas.js. Every action is a function the
|
|
23
|
+
// app already has: a registered keybind action, a bus event the menubar
|
|
24
|
+
// emits, a panel's button, sendToPanel, the memory card's functions.
|
|
25
|
+
// ═══════════════════════════════════════════
|
|
26
|
+
|
|
27
|
+
import { openContextMenu, isContextMenuOpen } from './context-menu.js';
|
|
28
|
+
import { isEditableTarget, isMenuKey, nativeMenuReason, selectionPayload, usableImage, usableLink } from './context-menu-logic.js';
|
|
29
|
+
import { buildAppMenu } from './context-menu-model.js';
|
|
30
|
+
import { areaAt, registerContextMenuArea } from './context-menu-areas.js';
|
|
31
|
+
import { t } from './i18n.js';
|
|
32
|
+
import { state, emit } from './state.js';
|
|
33
|
+
import { actionForKey, getShortcutLabel, hasAction, runAction } from './ui-keybinds.js';
|
|
34
|
+
import { isGuest, hasPermission } from './ui-sync.js';
|
|
35
|
+
import { sendToPanel } from './ui-claude-panel.js';
|
|
36
|
+
import { closeMemoryCard, focusLinkedMemories, getOpenCardsSnapshot } from './ui-detail.js';
|
|
37
|
+
import { formatMemoryForCLI } from './ui-terminal.js';
|
|
38
|
+
import { fetchMemory } from './api.js';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Where the browser's menu stays: the exact elements with a menu of their own (also for a click their handler did
|
|
42
|
+
* not take, such as Shift+F10 on them or a moment before they are wired), the other menus themselves, code editors,
|
|
43
|
+
* and what is not SynaBun's page or sits above the menu. Never a whole screen or panel: the rest of a panel gets the
|
|
44
|
+
* app's menu. Add `data-native-contextmenu` to an element to keep the browser's menu there.
|
|
45
|
+
*/
|
|
46
|
+
export const NATIVE_CONTEXTMENU_SELECTORS = [
|
|
47
|
+
'[data-native-contextmenu]',
|
|
48
|
+
'.term-viewport', '.xterm', '#term-context-menu', // terminals (docked and floating) and their menu
|
|
49
|
+
'#fe-tree', '.fe-ctx-flyout', // the File Explorer's tree (rows and its empty space) and its menus
|
|
50
|
+
'.cm-editor', '.fe-editor-menu', // a code editor anywhere; the editor's menus and palette
|
|
51
|
+
'#context-menu', // the 2D graph's card menu
|
|
52
|
+
'.explorer-ctx-menu', '.as-context-menu', // the Explorer's and the Automation Studio's menus
|
|
53
|
+
'.browser-canvas', // the SynaBun browser's view of another site (Back / Reload here would act on SynaBun)
|
|
54
|
+
'#loading-overlay', // the loading / restart screen, above the menu
|
|
55
|
+
];
|
|
56
|
+
const OPT_OUT = NATIVE_CONTEXTMENU_SELECTORS.join(', ');
|
|
57
|
+
const SEARCH_MAX = 500; // a search for the selection takes its first 500 characters
|
|
58
|
+
const KEY_ECHO_MS = 800; // the contextmenu event a menu key sends after its keydown already opened the menu
|
|
59
|
+
|
|
60
|
+
let _installed = false;
|
|
61
|
+
let _keyboardOpenedAt = -Infinity;
|
|
62
|
+
|
|
63
|
+
// ═══════════════════════════════════════════
|
|
64
|
+
// AREAS (context-menu-areas.js; re-exported here for the pages that already import this module)
|
|
65
|
+
// ═══════════════════════════════════════════
|
|
66
|
+
|
|
67
|
+
export { registerContextMenuArea };
|
|
68
|
+
|
|
69
|
+
// A row of the memory Explorer.
|
|
70
|
+
const explorerArea = {
|
|
71
|
+
id: 'memory-explorer',
|
|
72
|
+
match(el) {
|
|
73
|
+
const row = el?.closest?.('.explorer-memory[data-id]');
|
|
74
|
+
return row ? { kind: 'memory', memory: { id: row.dataset.id } } : null;
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// A memory card (ui-detail.js names its element after the memory's first 8 characters).
|
|
79
|
+
const cardArea = {
|
|
80
|
+
id: 'memory-card',
|
|
81
|
+
match(el) {
|
|
82
|
+
const card = el?.closest?.('.detail-card');
|
|
83
|
+
if (!card?.id) return null;
|
|
84
|
+
const open = getOpenCardsSnapshot().find((c) => card.id === `detail-card-${String(c.memoryId).slice(0, 8)}`);
|
|
85
|
+
return open ? { kind: 'memory', memory: { id: open.memoryId, card: true } } : null;
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// ═══════════════════════════════════════════
|
|
90
|
+
// WHAT WAS CLICKED
|
|
91
|
+
// ═══════════════════════════════════════════
|
|
92
|
+
|
|
93
|
+
const elementOf = (node) => (node && node.nodeType !== 1 ? node.parentElement : node) || null;
|
|
94
|
+
|
|
95
|
+
// The selected text, when the right-click is on it (or the keyboard opened the menu while something is selected).
|
|
96
|
+
function selectionAt(el) {
|
|
97
|
+
const sel = window.getSelection?.();
|
|
98
|
+
if (!sel || sel.isCollapsed || !sel.rangeCount) return '';
|
|
99
|
+
const text = selectionPayload(sel.toString());
|
|
100
|
+
if (!text) return '';
|
|
101
|
+
if (!el || el === document.body || el === document.documentElement) return text;
|
|
102
|
+
for (let i = 0; i < sel.rangeCount; i++) {
|
|
103
|
+
try { if (sel.getRangeAt(i).intersectsNode(el)) return text; } catch { /* a node from another document */ }
|
|
104
|
+
}
|
|
105
|
+
return '';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function linkAt(el) {
|
|
109
|
+
const a = el?.closest?.('a[href]');
|
|
110
|
+
if (!a) return null;
|
|
111
|
+
const raw = a.getAttribute('href');
|
|
112
|
+
let resolved = null;
|
|
113
|
+
try { resolved = new URL(raw, document.baseURI).href; } catch { /* not an address */ }
|
|
114
|
+
return usableLink(raw, resolved);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function imageAt(el) {
|
|
118
|
+
const img = el?.closest?.('img');
|
|
119
|
+
return img ? usableImage(img.currentSrc || img.src) : null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** What the menu is about for an element (null: the page itself). */
|
|
123
|
+
export function contextAt(el) {
|
|
124
|
+
return { selection: selectionAt(el), link: linkAt(el), image: imageAt(el), area: areaAt(el) };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ═══════════════════════════════════════════
|
|
128
|
+
// WHAT THE MENU CAN DO (the app's own functions)
|
|
129
|
+
// ═══════════════════════════════════════════
|
|
130
|
+
|
|
131
|
+
async function copyText(text) {
|
|
132
|
+
const value = String(text ?? '');
|
|
133
|
+
try {
|
|
134
|
+
if (navigator.clipboard?.writeText) { await navigator.clipboard.writeText(value); return true; }
|
|
135
|
+
} catch { /* not allowed here (an address that is not secure): the fallback below */ }
|
|
136
|
+
const area = document.createElement('textarea');
|
|
137
|
+
area.value = value;
|
|
138
|
+
area.setAttribute('readonly', '');
|
|
139
|
+
area.style.cssText = 'position:fixed;top:-1000px;left:0;opacity:0;';
|
|
140
|
+
document.body.appendChild(area);
|
|
141
|
+
area.select();
|
|
142
|
+
let ok = false;
|
|
143
|
+
try { ok = document.execCommand('copy'); } catch { /* nothing more to try */ }
|
|
144
|
+
area.remove();
|
|
145
|
+
return ok;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function toggleFullscreen() {
|
|
149
|
+
if (document.fullscreenElement) return document.exitFullscreen?.();
|
|
150
|
+
return document.documentElement.requestFullscreen?.();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// The search bar's own path: its input event shows "Searching…", waits its debounce and searches.
|
|
154
|
+
function searchMemories(text) {
|
|
155
|
+
const query = selectionPayload(text, SEARCH_MAX);
|
|
156
|
+
const input = document.getElementById('search-input');
|
|
157
|
+
if (!input || !query) return;
|
|
158
|
+
input.value = query;
|
|
159
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const findNode = (id) => state.allNodes?.find((n) => n.id === id) || null;
|
|
163
|
+
|
|
164
|
+
// A memory the page has (the slim graph copy is enough to open it), else the one the server has.
|
|
165
|
+
async function withMemory(id, fn) {
|
|
166
|
+
const node = findNode(id);
|
|
167
|
+
if (node) return fn(node);
|
|
168
|
+
const full = await fetchMemory(id).catch(() => null);
|
|
169
|
+
if (full?.payload) return fn({ id, payload: full.payload });
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// The AI panel gets the whole memory (the graph's copy of its content is cut at 500 characters).
|
|
174
|
+
async function sendMemory(id) {
|
|
175
|
+
const full = await fetchMemory(id).catch(() => null);
|
|
176
|
+
const node = full?.payload ? { id, payload: full.payload } : findNode(id);
|
|
177
|
+
if (node) await sendToPanel(formatMemoryForCLI(node));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export const ACTIONS = {
|
|
181
|
+
back: () => history.back(),
|
|
182
|
+
forward: () => history.forward(),
|
|
183
|
+
reload: () => location.reload(),
|
|
184
|
+
copyText,
|
|
185
|
+
toggleFullscreen,
|
|
186
|
+
openInNewTab: (href) => { window.open(href, '_blank', 'noopener,noreferrer'); },
|
|
187
|
+
searchMemories,
|
|
188
|
+
sendText: (text) => sendToPanel(text),
|
|
189
|
+
runAction: (actionId) => runAction(actionId),
|
|
190
|
+
press: (id) => document.getElementById(id)?.click(),
|
|
191
|
+
emit: (name, payload) => emit(name, payload),
|
|
192
|
+
openMemory: (id) => withMemory(id, (node) => emit('node-selected', node)),
|
|
193
|
+
showLinked: (id) => withMemory(id, (node) => { emit('node-selected', node); focusLinkedMemories(node.id); }),
|
|
194
|
+
sendMemory,
|
|
195
|
+
closeCard: (id) => closeMemoryCard(id),
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
function canGoBack() {
|
|
199
|
+
const nav = window.navigation;
|
|
200
|
+
return typeof nav?.canGoBack === 'boolean' ? nav.canGoBack : history.length > 1;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function canGoForward() {
|
|
204
|
+
const nav = window.navigation;
|
|
205
|
+
return typeof nav?.canGoForward === 'boolean' ? nav.canGoForward : true; // unknown without the Navigation API
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** The menu model's environment as the page is now (labels, keys and states are read at every open). */
|
|
209
|
+
export function menuEnv() {
|
|
210
|
+
return {
|
|
211
|
+
t,
|
|
212
|
+
shortcut: (actionId) => getShortcutLabel(actionId),
|
|
213
|
+
hasAction,
|
|
214
|
+
hasElement: (id) => !!document.getElementById(id),
|
|
215
|
+
isActive: (id) => !!document.getElementById(id)?.classList.contains('active'),
|
|
216
|
+
allowed: (perm) => !isGuest() || hasPermission(perm),
|
|
217
|
+
appIcon: (id) => (id && document.getElementById(id)?.querySelector('.menu-icon')?.innerHTML) || '',
|
|
218
|
+
page: {
|
|
219
|
+
url: location.href,
|
|
220
|
+
canGoBack: canGoBack(),
|
|
221
|
+
canGoForward: canGoForward(),
|
|
222
|
+
fullscreen: !!document.fullscreenElement,
|
|
223
|
+
fullscreenEnabled: document.fullscreenEnabled !== false && typeof document.documentElement.requestFullscreen === 'function',
|
|
224
|
+
},
|
|
225
|
+
act: ACTIONS,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ═══════════════════════════════════════════
|
|
230
|
+
// OPENING
|
|
231
|
+
// ═══════════════════════════════════════════
|
|
232
|
+
|
|
233
|
+
// One menu at a time: the menubar, the dropdowns that listen for it, and the menus that only close on a click.
|
|
234
|
+
function closeOtherMenus() {
|
|
235
|
+
emit('panel:close-all-dropdowns');
|
|
236
|
+
document.getElementById('term-context-menu')?.classList.remove('open');
|
|
237
|
+
document.getElementById('context-menu')?.classList.remove('open');
|
|
238
|
+
document.querySelectorAll('.as-context-menu, .explorer-ctx-menu').forEach((el) => el.remove());
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function open(ctx, placement) {
|
|
242
|
+
const items = buildAppMenu(ctx, menuEnv());
|
|
243
|
+
closeOtherMenus();
|
|
244
|
+
return openContextMenu({ items, label: t('contextMenu.label'), ...placement });
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Open the app's menu from an area that detects its own right-click (the memory map, where a right-drag pans):
|
|
249
|
+
* what is at `target`, with `area` in place of what the registered areas would say.
|
|
250
|
+
* @param {{ x?: number, y?: number, target?: Element | null, area?: object | null, keyboard?: boolean,
|
|
251
|
+
* anchorRect?: DOMRect | null, returnFocus?: Element | null }} o
|
|
252
|
+
*/
|
|
253
|
+
export function openAppContextMenu({ x, y, target = null, area = null, keyboard = false, anchorRect = null, returnFocus } = {}) {
|
|
254
|
+
const el = elementOf(target);
|
|
255
|
+
const ctx = contextAt(el);
|
|
256
|
+
if (area) ctx.area = area;
|
|
257
|
+
return open(ctx, { x, y, anchorRect, keyboard, returnFocus: returnFocus === undefined ? document.activeElement : returnFocus });
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function onContextMenu(event) {
|
|
261
|
+
// The menu key's own contextmenu event, after its keydown opened the menu.
|
|
262
|
+
if (isContextMenuOpen() && performance.now() - _keyboardOpenedAt < KEY_ECHO_MS) { event.preventDefault(); return; }
|
|
263
|
+
const el = elementOf(event.target);
|
|
264
|
+
const reason = nativeMenuReason(event, {
|
|
265
|
+
inOwnMenu: !!el?.closest?.('.app-ctx-menu'),
|
|
266
|
+
editable: isEditableTarget(el),
|
|
267
|
+
optedOut: !!el?.closest?.(OPT_OUT),
|
|
268
|
+
});
|
|
269
|
+
if (reason === 'own-menu') { event.preventDefault(); return; }
|
|
270
|
+
if (reason) return;
|
|
271
|
+
event.preventDefault();
|
|
272
|
+
open(contextAt(el), { x: event.clientX, y: event.clientY, keyboard: false, returnFocus: document.activeElement });
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function onKeyDown(event) {
|
|
276
|
+
if (event.defaultPrevented || !isMenuKey(event) || isContextMenuOpen() || actionForKey(event)) return;
|
|
277
|
+
const active = document.activeElement;
|
|
278
|
+
const el = active && active !== document.body && active !== document.documentElement ? active : null;
|
|
279
|
+
if (el && (isEditableTarget(el) || el.closest(OPT_OUT) || el.closest('.app-ctx-menu'))) return;
|
|
280
|
+
event.preventDefault();
|
|
281
|
+
_keyboardOpenedAt = performance.now();
|
|
282
|
+
open(contextAt(el), { anchorRect: el?.getBoundingClientRect() || null, keyboard: true, returnFocus: el });
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** Install the app's right-click menu (once per page). */
|
|
286
|
+
export function initAppContextMenu() {
|
|
287
|
+
if (_installed) return;
|
|
288
|
+
_installed = true;
|
|
289
|
+
registerContextMenuArea(explorerArea);
|
|
290
|
+
registerContextMenuArea(cardArea);
|
|
291
|
+
// Bubble phase at the window: every handler of the page has had the event first.
|
|
292
|
+
window.addEventListener('contextmenu', onContextMenu);
|
|
293
|
+
// A menu key the user bound to an action stays that action (actionForKey), whichever listener runs first.
|
|
294
|
+
document.addEventListener('keydown', onKeyDown);
|
|
295
|
+
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { on, emit } from './state.js';
|
|
10
10
|
import { KEYS } from './constants.js';
|
|
11
11
|
import { storage } from './storage.js';
|
|
12
|
+
import { clampToFrame } from './app-frame.js';
|
|
12
13
|
|
|
13
14
|
// ── State ──
|
|
14
15
|
|
|
@@ -39,10 +40,10 @@ export function initCostWidget() {
|
|
|
39
40
|
if (!_docked) {
|
|
40
41
|
const savedPos = _loadPos();
|
|
41
42
|
if (savedPos) {
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
_widget.style.left =
|
|
45
|
-
_widget.style.top =
|
|
43
|
+
// Inside the app frame (about 270 × 60 of it on screen)
|
|
44
|
+
const at = clampToFrame(savedPos.left, savedPos.top, 270, 60);
|
|
45
|
+
_widget.style.left = at.x + 'px';
|
|
46
|
+
_widget.style.top = at.y + 'px';
|
|
46
47
|
} else {
|
|
47
48
|
_widget.style.right = '24px';
|
|
48
49
|
_widget.style.bottom = '24px';
|
|
@@ -531,47 +532,47 @@ function _toggleCollapse() {
|
|
|
531
532
|
|
|
532
533
|
// ── Drag ──
|
|
533
534
|
|
|
534
|
-
function _makeDraggable(header) {
|
|
535
|
-
header.style.cursor = '
|
|
536
|
-
|
|
537
|
-
header.addEventListener('mousedown', (e) => {
|
|
535
|
+
function _makeDraggable(header) {
|
|
536
|
+
header.style.cursor = 'move';
|
|
537
|
+
|
|
538
|
+
header.addEventListener('mousedown', (e) => {
|
|
538
539
|
if (e.target.closest('.cw-collapse') || e.target.closest('.cw-scan')) return;
|
|
539
540
|
e.preventDefault();
|
|
540
541
|
|
|
541
542
|
// If docked, undock on drag
|
|
542
543
|
if (_docked) _undock();
|
|
543
|
-
|
|
544
|
-
const rect = _widget.getBoundingClientRect();
|
|
545
|
-
_drag = {
|
|
546
|
-
startX: e.clientX,
|
|
547
|
-
startY: e.clientY,
|
|
548
|
-
origLeft: rect.left,
|
|
549
|
-
origTop: rect.top,
|
|
550
|
-
width: rect.width,
|
|
551
|
-
height: rect.height,
|
|
552
|
-
};
|
|
553
|
-
let dragRaf = 0;
|
|
554
|
-
let pendingPos = null;
|
|
555
|
-
const applyDrag = () => {
|
|
556
|
-
dragRaf = 0;
|
|
557
|
-
if (!_widget || !pendingPos) return;
|
|
558
|
-
_widget.style.left = pendingPos.left + 'px';
|
|
559
|
-
_widget.style.top = pendingPos.top + 'px';
|
|
560
|
-
};
|
|
561
|
-
const scheduleDrag = (left, top) => {
|
|
562
|
-
pendingPos = { left, top };
|
|
563
|
-
if (!dragRaf) dragRaf = requestAnimationFrame(applyDrag);
|
|
564
|
-
};
|
|
565
|
-
const flushDrag = () => {
|
|
566
|
-
if (dragRaf) {
|
|
567
|
-
cancelAnimationFrame(dragRaf);
|
|
568
|
-
dragRaf = 0;
|
|
569
|
-
}
|
|
570
|
-
applyDrag();
|
|
571
|
-
};
|
|
572
|
-
header.style.cursor = '
|
|
573
|
-
|
|
574
|
-
// Reset right/bottom positioning and switch to left/top
|
|
544
|
+
|
|
545
|
+
const rect = _widget.getBoundingClientRect();
|
|
546
|
+
_drag = {
|
|
547
|
+
startX: e.clientX,
|
|
548
|
+
startY: e.clientY,
|
|
549
|
+
origLeft: rect.left,
|
|
550
|
+
origTop: rect.top,
|
|
551
|
+
width: rect.width,
|
|
552
|
+
height: rect.height,
|
|
553
|
+
};
|
|
554
|
+
let dragRaf = 0;
|
|
555
|
+
let pendingPos = null;
|
|
556
|
+
const applyDrag = () => {
|
|
557
|
+
dragRaf = 0;
|
|
558
|
+
if (!_widget || !pendingPos) return;
|
|
559
|
+
_widget.style.left = pendingPos.left + 'px';
|
|
560
|
+
_widget.style.top = pendingPos.top + 'px';
|
|
561
|
+
};
|
|
562
|
+
const scheduleDrag = (left, top) => {
|
|
563
|
+
pendingPos = { left, top };
|
|
564
|
+
if (!dragRaf) dragRaf = requestAnimationFrame(applyDrag);
|
|
565
|
+
};
|
|
566
|
+
const flushDrag = () => {
|
|
567
|
+
if (dragRaf) {
|
|
568
|
+
cancelAnimationFrame(dragRaf);
|
|
569
|
+
dragRaf = 0;
|
|
570
|
+
}
|
|
571
|
+
applyDrag();
|
|
572
|
+
};
|
|
573
|
+
header.style.cursor = 'move';
|
|
574
|
+
|
|
575
|
+
// Reset right/bottom positioning and switch to left/top
|
|
575
576
|
_widget.style.right = 'auto';
|
|
576
577
|
_widget.style.bottom = 'auto';
|
|
577
578
|
_widget.style.left = _drag.origLeft + 'px';
|
|
@@ -581,25 +582,22 @@ function _makeDraggable(header) {
|
|
|
581
582
|
if (!_drag) return;
|
|
582
583
|
const dx = ev.clientX - _drag.startX;
|
|
583
584
|
const dy = ev.clientY - _drag.startY;
|
|
584
|
-
let newLeft = _drag.origLeft + dx;
|
|
585
|
-
let newTop = _drag.origTop + dy;
|
|
586
|
-
// Constrain to
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
_savePos(parseInt(_widget.style.left), parseInt(_widget.style.top));
|
|
601
|
-
_drag = null;
|
|
602
|
-
}
|
|
585
|
+
let newLeft = _drag.origLeft + dx;
|
|
586
|
+
let newTop = _drag.origTop + dy;
|
|
587
|
+
// Constrain to the app frame
|
|
588
|
+
({ x: newLeft, y: newTop } = clampToFrame(newLeft, newTop, _drag.width, _drag.height));
|
|
589
|
+
scheduleDrag(newLeft, newTop);
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
const onUp = () => {
|
|
593
|
+
document.removeEventListener('mousemove', onMove);
|
|
594
|
+
document.removeEventListener('mouseup', onUp);
|
|
595
|
+
header.style.cursor = 'move';
|
|
596
|
+
if (_drag) {
|
|
597
|
+
flushDrag();
|
|
598
|
+
_savePos(parseInt(_widget.style.left), parseInt(_widget.style.top));
|
|
599
|
+
_drag = null;
|
|
600
|
+
}
|
|
603
601
|
};
|
|
604
602
|
|
|
605
603
|
document.addEventListener('mousemove', onMove);
|