@otto-assistant/bridge 0.4.92
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/bin.js +2 -0
- package/dist/agent-model.e2e.test.js +755 -0
- package/dist/ai-tool-to-genai.js +233 -0
- package/dist/ai-tool-to-genai.test.js +267 -0
- package/dist/ai-tool.js +6 -0
- package/dist/anthropic-auth-plugin.js +728 -0
- package/dist/anthropic-auth-plugin.test.js +125 -0
- package/dist/anthropic-auth-state.js +231 -0
- package/dist/bin.js +90 -0
- package/dist/channel-management.js +227 -0
- package/dist/cli-parsing.test.js +137 -0
- package/dist/cli-send-thread.e2e.test.js +356 -0
- package/dist/cli.js +3276 -0
- package/dist/commands/abort.js +65 -0
- package/dist/commands/action-buttons.js +245 -0
- package/dist/commands/add-project.js +113 -0
- package/dist/commands/agent.js +335 -0
- package/dist/commands/ask-question.js +274 -0
- package/dist/commands/btw.js +116 -0
- package/dist/commands/compact.js +120 -0
- package/dist/commands/context-usage.js +140 -0
- package/dist/commands/create-new-project.js +130 -0
- package/dist/commands/diff.js +63 -0
- package/dist/commands/file-upload.js +275 -0
- package/dist/commands/fork.js +220 -0
- package/dist/commands/gemini-apikey.js +70 -0
- package/dist/commands/login.js +885 -0
- package/dist/commands/mcp.js +239 -0
- package/dist/commands/memory-snapshot.js +24 -0
- package/dist/commands/mention-mode.js +44 -0
- package/dist/commands/merge-worktree.js +159 -0
- package/dist/commands/model-variant.js +364 -0
- package/dist/commands/model.js +776 -0
- package/dist/commands/new-worktree.js +366 -0
- package/dist/commands/paginated-select.js +57 -0
- package/dist/commands/permissions.js +274 -0
- package/dist/commands/queue.js +206 -0
- package/dist/commands/remove-project.js +115 -0
- package/dist/commands/restart-opencode-server.js +127 -0
- package/dist/commands/resume.js +149 -0
- package/dist/commands/run-command.js +79 -0
- package/dist/commands/screenshare.js +303 -0
- package/dist/commands/screenshare.test.js +20 -0
- package/dist/commands/session-id.js +78 -0
- package/dist/commands/session.js +176 -0
- package/dist/commands/share.js +80 -0
- package/dist/commands/tasks.js +205 -0
- package/dist/commands/types.js +2 -0
- package/dist/commands/undo-redo.js +305 -0
- package/dist/commands/unset-model.js +138 -0
- package/dist/commands/upgrade.js +42 -0
- package/dist/commands/user-command.js +155 -0
- package/dist/commands/verbosity.js +125 -0
- package/dist/commands/worktree-settings.js +43 -0
- package/dist/commands/worktrees.js +410 -0
- package/dist/condense-memory.js +33 -0
- package/dist/config.js +94 -0
- package/dist/context-awareness-plugin.js +363 -0
- package/dist/context-awareness-plugin.test.js +124 -0
- package/dist/critique-utils.js +95 -0
- package/dist/database.js +1310 -0
- package/dist/db.js +251 -0
- package/dist/db.test.js +138 -0
- package/dist/debounce-timeout.js +28 -0
- package/dist/debounced-process-flush.js +77 -0
- package/dist/discord-bot.js +1008 -0
- package/dist/discord-command-registration.js +524 -0
- package/dist/discord-urls.js +81 -0
- package/dist/discord-utils.js +591 -0
- package/dist/discord-utils.test.js +134 -0
- package/dist/errors.js +157 -0
- package/dist/escape-backticks.test.js +429 -0
- package/dist/event-stream-real-capture.e2e.test.js +533 -0
- package/dist/eventsource-parser.test.js +327 -0
- package/dist/exec-async.js +26 -0
- package/dist/external-opencode-sync.js +480 -0
- package/dist/format-tables.js +302 -0
- package/dist/format-tables.test.js +308 -0
- package/dist/forum-sync/config.js +79 -0
- package/dist/forum-sync/discord-operations.js +154 -0
- package/dist/forum-sync/index.js +5 -0
- package/dist/forum-sync/markdown.js +113 -0
- package/dist/forum-sync/sync-to-discord.js +417 -0
- package/dist/forum-sync/sync-to-files.js +190 -0
- package/dist/forum-sync/types.js +53 -0
- package/dist/forum-sync/watchers.js +307 -0
- package/dist/gateway-proxy-reconnect.e2e.test.js +394 -0
- package/dist/gateway-proxy.e2e.test.js +483 -0
- package/dist/genai-worker-wrapper.js +111 -0
- package/dist/genai-worker.js +311 -0
- package/dist/genai.js +232 -0
- package/dist/generated/browser.js +17 -0
- package/dist/generated/client.js +37 -0
- package/dist/generated/commonInputTypes.js +10 -0
- package/dist/generated/enums.js +52 -0
- package/dist/generated/internal/class.js +49 -0
- package/dist/generated/internal/prismaNamespace.js +253 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js +223 -0
- package/dist/generated/models/bot_api_keys.js +1 -0
- package/dist/generated/models/bot_tokens.js +1 -0
- package/dist/generated/models/channel_agents.js +1 -0
- package/dist/generated/models/channel_directories.js +1 -0
- package/dist/generated/models/channel_mention_mode.js +1 -0
- package/dist/generated/models/channel_models.js +1 -0
- package/dist/generated/models/channel_verbosity.js +1 -0
- package/dist/generated/models/channel_worktrees.js +1 -0
- package/dist/generated/models/forum_sync_configs.js +1 -0
- package/dist/generated/models/global_models.js +1 -0
- package/dist/generated/models/ipc_requests.js +1 -0
- package/dist/generated/models/part_messages.js +1 -0
- package/dist/generated/models/scheduled_tasks.js +1 -0
- package/dist/generated/models/session_agents.js +1 -0
- package/dist/generated/models/session_events.js +1 -0
- package/dist/generated/models/session_models.js +1 -0
- package/dist/generated/models/session_start_sources.js +1 -0
- package/dist/generated/models/thread_sessions.js +1 -0
- package/dist/generated/models/thread_worktrees.js +1 -0
- package/dist/generated/models.js +1 -0
- package/dist/heap-monitor.js +122 -0
- package/dist/hrana-server.js +263 -0
- package/dist/hrana-server.test.js +370 -0
- package/dist/html-actions.js +123 -0
- package/dist/html-actions.test.js +70 -0
- package/dist/html-components.js +117 -0
- package/dist/html-components.test.js +34 -0
- package/dist/image-optimizer-plugin.js +153 -0
- package/dist/image-utils.js +112 -0
- package/dist/interaction-handler.js +397 -0
- package/dist/ipc-polling.js +252 -0
- package/dist/ipc-tools-plugin.js +193 -0
- package/dist/kimaki-digital-twin.e2e.test.js +161 -0
- package/dist/kimaki-opencode-plugin-loading.e2e.test.js +87 -0
- package/dist/kimaki-opencode-plugin.js +17 -0
- package/dist/kimaki-opencode-plugin.test.js +98 -0
- package/dist/limit-heading-depth.js +25 -0
- package/dist/limit-heading-depth.test.js +105 -0
- package/dist/logger.js +165 -0
- package/dist/markdown.js +342 -0
- package/dist/markdown.test.js +257 -0
- package/dist/message-finish-field.e2e.test.js +165 -0
- package/dist/message-formatting.js +413 -0
- package/dist/message-formatting.test.js +73 -0
- package/dist/message-preprocessing.js +330 -0
- package/dist/onboarding-tutorial.js +172 -0
- package/dist/onboarding-welcome.js +37 -0
- package/dist/openai-realtime.js +224 -0
- package/dist/opencode-command-detection.js +65 -0
- package/dist/opencode-command-detection.test.js +240 -0
- package/dist/opencode-command.js +129 -0
- package/dist/opencode-command.test.js +48 -0
- package/dist/opencode-interrupt-plugin.js +361 -0
- package/dist/opencode-interrupt-plugin.test.js +458 -0
- package/dist/opencode.js +861 -0
- package/dist/otto/branding.js +22 -0
- package/dist/otto/index.js +21 -0
- package/dist/parse-permission-rules.test.js +117 -0
- package/dist/patch-text-parser.js +97 -0
- package/dist/plugin-logger.js +59 -0
- package/dist/privacy-sanitizer.js +105 -0
- package/dist/queue-advanced-abort.e2e.test.js +293 -0
- package/dist/queue-advanced-action-buttons.e2e.test.js +206 -0
- package/dist/queue-advanced-e2e-setup.js +786 -0
- package/dist/queue-advanced-footer.e2e.test.js +472 -0
- package/dist/queue-advanced-model-switch.e2e.test.js +299 -0
- package/dist/queue-advanced-permissions-typing.e2e.test.js +180 -0
- package/dist/queue-advanced-question.e2e.test.js +261 -0
- package/dist/queue-advanced-typing-interrupt.e2e.test.js +114 -0
- package/dist/queue-advanced-typing.e2e.test.js +153 -0
- package/dist/queue-drain-after-interactive-ui.e2e.test.js +119 -0
- package/dist/queue-interrupt-drain.e2e.test.js +135 -0
- package/dist/queue-question-select-drain.e2e.test.js +120 -0
- package/dist/runtime-idle-sweeper.js +52 -0
- package/dist/runtime-lifecycle.e2e.test.js +508 -0
- package/dist/sentry.js +23 -0
- package/dist/session-handler/agent-utils.js +67 -0
- package/dist/session-handler/event-stream-state.js +420 -0
- package/dist/session-handler/event-stream-state.test.js +563 -0
- package/dist/session-handler/model-utils.js +124 -0
- package/dist/session-handler/opencode-session-event-log.js +94 -0
- package/dist/session-handler/thread-runtime-state.js +104 -0
- package/dist/session-handler/thread-session-runtime.js +3258 -0
- package/dist/session-handler.js +9 -0
- package/dist/session-search.js +100 -0
- package/dist/session-search.test.js +40 -0
- package/dist/session-title-rename.test.js +80 -0
- package/dist/startup-service.js +153 -0
- package/dist/startup-time.e2e.test.js +296 -0
- package/dist/store.js +17 -0
- package/dist/system-message.js +613 -0
- package/dist/system-message.test.js +602 -0
- package/dist/task-runner.js +295 -0
- package/dist/task-schedule.js +209 -0
- package/dist/task-schedule.test.js +71 -0
- package/dist/test-utils.js +299 -0
- package/dist/thinking-utils.js +35 -0
- package/dist/thread-message-queue.e2e.test.js +999 -0
- package/dist/tools.js +357 -0
- package/dist/undo-redo.e2e.test.js +161 -0
- package/dist/unnest-code-blocks.js +146 -0
- package/dist/unnest-code-blocks.test.js +673 -0
- package/dist/upgrade.js +114 -0
- package/dist/utils.js +144 -0
- package/dist/voice-attachment.js +34 -0
- package/dist/voice-handler.js +646 -0
- package/dist/voice-message.e2e.test.js +1021 -0
- package/dist/voice.js +447 -0
- package/dist/voice.test.js +235 -0
- package/dist/wait-session.js +94 -0
- package/dist/websockify.js +69 -0
- package/dist/worker-types.js +4 -0
- package/dist/worktree-lifecycle.e2e.test.js +308 -0
- package/dist/worktree-utils.js +3 -0
- package/dist/worktrees.js +929 -0
- package/dist/worktrees.test.js +189 -0
- package/dist/xml.js +92 -0
- package/dist/xml.test.js +32 -0
- package/package.json +98 -0
- package/schema.prisma +295 -0
- package/skills/batch/SKILL.md +87 -0
- package/skills/critique/SKILL.md +112 -0
- package/skills/egaki/SKILL.md +100 -0
- package/skills/errore/SKILL.md +647 -0
- package/skills/event-sourcing-state/SKILL.md +252 -0
- package/skills/gitchamber/SKILL.md +93 -0
- package/skills/goke/SKILL.md +644 -0
- package/skills/jitter/EDITOR.md +219 -0
- package/skills/jitter/EXPORT-INTERNALS.md +309 -0
- package/skills/jitter/SKILL.md +158 -0
- package/skills/jitter/jitter-clipboard.json +1042 -0
- package/skills/jitter/package.json +14 -0
- package/skills/jitter/tsconfig.json +15 -0
- package/skills/jitter/utils/actions.ts +212 -0
- package/skills/jitter/utils/export.ts +114 -0
- package/skills/jitter/utils/index.ts +141 -0
- package/skills/jitter/utils/snapshot.ts +154 -0
- package/skills/jitter/utils/traverse.ts +246 -0
- package/skills/jitter/utils/types.ts +279 -0
- package/skills/jitter/utils/wait.ts +133 -0
- package/skills/lintcn/SKILL.md +873 -0
- package/skills/new-skill/SKILL.md +211 -0
- package/skills/npm-package/SKILL.md +239 -0
- package/skills/playwriter/SKILL.md +35 -0
- package/skills/proxyman/SKILL.md +215 -0
- package/skills/security-review/SKILL.md +208 -0
- package/skills/simplify/SKILL.md +58 -0
- package/skills/spiceflow/SKILL.md +14 -0
- package/skills/termcast/SKILL.md +945 -0
- package/skills/tuistory/SKILL.md +250 -0
- package/skills/usecomputer/SKILL.md +264 -0
- package/skills/x-articles/SKILL.md +554 -0
- package/skills/zele/SKILL.md +112 -0
- package/skills/zustand-centralized-state/SKILL.md +1004 -0
- package/src/agent-model.e2e.test.ts +976 -0
- package/src/ai-tool-to-genai.test.ts +296 -0
- package/src/ai-tool-to-genai.ts +283 -0
- package/src/ai-tool.ts +39 -0
- package/src/anthropic-auth-plugin.test.ts +159 -0
- package/src/anthropic-auth-plugin.ts +861 -0
- package/src/anthropic-auth-state.ts +282 -0
- package/src/bin.ts +111 -0
- package/src/channel-management.ts +334 -0
- package/src/cli-parsing.test.ts +195 -0
- package/src/cli-send-thread.e2e.test.ts +464 -0
- package/src/cli.ts +4581 -0
- package/src/commands/abort.ts +89 -0
- package/src/commands/action-buttons.ts +364 -0
- package/src/commands/add-project.ts +149 -0
- package/src/commands/agent.ts +473 -0
- package/src/commands/ask-question.ts +390 -0
- package/src/commands/btw.ts +164 -0
- package/src/commands/compact.ts +157 -0
- package/src/commands/context-usage.ts +199 -0
- package/src/commands/create-new-project.ts +190 -0
- package/src/commands/diff.ts +91 -0
- package/src/commands/file-upload.ts +389 -0
- package/src/commands/fork.ts +321 -0
- package/src/commands/gemini-apikey.ts +104 -0
- package/src/commands/login.ts +1173 -0
- package/src/commands/mcp.ts +307 -0
- package/src/commands/memory-snapshot.ts +30 -0
- package/src/commands/mention-mode.ts +68 -0
- package/src/commands/merge-worktree.ts +223 -0
- package/src/commands/model-variant.ts +483 -0
- package/src/commands/model.ts +1053 -0
- package/src/commands/new-worktree.ts +510 -0
- package/src/commands/paginated-select.ts +81 -0
- package/src/commands/permissions.ts +397 -0
- package/src/commands/queue.ts +271 -0
- package/src/commands/remove-project.ts +155 -0
- package/src/commands/restart-opencode-server.ts +162 -0
- package/src/commands/resume.ts +230 -0
- package/src/commands/run-command.ts +123 -0
- package/src/commands/screenshare.test.ts +30 -0
- package/src/commands/screenshare.ts +366 -0
- package/src/commands/session-id.ts +109 -0
- package/src/commands/session.ts +227 -0
- package/src/commands/share.ts +106 -0
- package/src/commands/tasks.ts +293 -0
- package/src/commands/types.ts +25 -0
- package/src/commands/undo-redo.ts +386 -0
- package/src/commands/unset-model.ts +173 -0
- package/src/commands/upgrade.ts +52 -0
- package/src/commands/user-command.ts +198 -0
- package/src/commands/verbosity.ts +173 -0
- package/src/commands/worktree-settings.ts +70 -0
- package/src/commands/worktrees.ts +552 -0
- package/src/condense-memory.ts +36 -0
- package/src/config.ts +111 -0
- package/src/context-awareness-plugin.test.ts +142 -0
- package/src/context-awareness-plugin.ts +510 -0
- package/src/critique-utils.ts +139 -0
- package/src/database.ts +1876 -0
- package/src/db.test.ts +162 -0
- package/src/db.ts +286 -0
- package/src/debounce-timeout.ts +43 -0
- package/src/debounced-process-flush.ts +104 -0
- package/src/discord-bot.ts +1330 -0
- package/src/discord-command-registration.ts +693 -0
- package/src/discord-urls.ts +88 -0
- package/src/discord-utils.test.ts +153 -0
- package/src/discord-utils.ts +800 -0
- package/src/errors.ts +201 -0
- package/src/escape-backticks.test.ts +469 -0
- package/src/event-stream-real-capture.e2e.test.ts +692 -0
- package/src/eventsource-parser.test.ts +351 -0
- package/src/exec-async.ts +35 -0
- package/src/external-opencode-sync.ts +685 -0
- package/src/format-tables.test.ts +335 -0
- package/src/format-tables.ts +445 -0
- package/src/forum-sync/config.ts +92 -0
- package/src/forum-sync/discord-operations.ts +241 -0
- package/src/forum-sync/index.ts +9 -0
- package/src/forum-sync/markdown.ts +172 -0
- package/src/forum-sync/sync-to-discord.ts +595 -0
- package/src/forum-sync/sync-to-files.ts +294 -0
- package/src/forum-sync/types.ts +175 -0
- package/src/forum-sync/watchers.ts +454 -0
- package/src/gateway-proxy-reconnect.e2e.test.ts +523 -0
- package/src/gateway-proxy.e2e.test.ts +640 -0
- package/src/genai-worker-wrapper.ts +164 -0
- package/src/genai-worker.ts +386 -0
- package/src/genai.ts +321 -0
- package/src/generated/browser.ts +114 -0
- package/src/generated/client.ts +138 -0
- package/src/generated/commonInputTypes.ts +736 -0
- package/src/generated/enums.ts +88 -0
- package/src/generated/internal/class.ts +384 -0
- package/src/generated/internal/prismaNamespace.ts +2386 -0
- package/src/generated/internal/prismaNamespaceBrowser.ts +326 -0
- package/src/generated/models/bot_api_keys.ts +1288 -0
- package/src/generated/models/bot_tokens.ts +1656 -0
- package/src/generated/models/channel_agents.ts +1256 -0
- package/src/generated/models/channel_directories.ts +1859 -0
- package/src/generated/models/channel_mention_mode.ts +1300 -0
- package/src/generated/models/channel_models.ts +1288 -0
- package/src/generated/models/channel_verbosity.ts +1228 -0
- package/src/generated/models/channel_worktrees.ts +1300 -0
- package/src/generated/models/forum_sync_configs.ts +1452 -0
- package/src/generated/models/global_models.ts +1288 -0
- package/src/generated/models/ipc_requests.ts +1485 -0
- package/src/generated/models/part_messages.ts +1302 -0
- package/src/generated/models/scheduled_tasks.ts +2320 -0
- package/src/generated/models/session_agents.ts +1086 -0
- package/src/generated/models/session_events.ts +1439 -0
- package/src/generated/models/session_models.ts +1114 -0
- package/src/generated/models/session_start_sources.ts +1408 -0
- package/src/generated/models/thread_sessions.ts +1781 -0
- package/src/generated/models/thread_worktrees.ts +1356 -0
- package/src/generated/models.ts +30 -0
- package/src/heap-monitor.ts +152 -0
- package/src/hrana-server.test.ts +434 -0
- package/src/hrana-server.ts +314 -0
- package/src/html-actions.test.ts +87 -0
- package/src/html-actions.ts +174 -0
- package/src/html-components.test.ts +38 -0
- package/src/html-components.ts +181 -0
- package/src/image-optimizer-plugin.ts +194 -0
- package/src/image-utils.ts +149 -0
- package/src/interaction-handler.ts +576 -0
- package/src/ipc-polling.ts +326 -0
- package/src/ipc-tools-plugin.ts +236 -0
- package/src/kimaki-digital-twin.e2e.test.ts +199 -0
- package/src/kimaki-opencode-plugin-loading.e2e.test.ts +109 -0
- package/src/kimaki-opencode-plugin.test.ts +108 -0
- package/src/kimaki-opencode-plugin.ts +18 -0
- package/src/limit-heading-depth.test.ts +116 -0
- package/src/limit-heading-depth.ts +26 -0
- package/src/logger.ts +208 -0
- package/src/markdown.test.ts +308 -0
- package/src/markdown.ts +410 -0
- package/src/message-finish-field.e2e.test.ts +192 -0
- package/src/message-formatting.test.ts +81 -0
- package/src/message-formatting.ts +533 -0
- package/src/message-preprocessing.ts +455 -0
- package/src/onboarding-tutorial.ts +176 -0
- package/src/onboarding-welcome.ts +49 -0
- package/src/openai-realtime.ts +358 -0
- package/src/opencode-command-detection.test.ts +307 -0
- package/src/opencode-command-detection.ts +76 -0
- package/src/opencode-command.test.ts +70 -0
- package/src/opencode-command.ts +188 -0
- package/src/opencode-interrupt-plugin.test.ts +677 -0
- package/src/opencode-interrupt-plugin.ts +477 -0
- package/src/opencode.ts +1110 -0
- package/src/otto/branding.ts +23 -0
- package/src/otto/index.ts +22 -0
- package/src/parse-permission-rules.test.ts +127 -0
- package/src/patch-text-parser.ts +107 -0
- package/src/plugin-logger.ts +68 -0
- package/src/privacy-sanitizer.ts +142 -0
- package/src/queue-advanced-abort.e2e.test.ts +382 -0
- package/src/queue-advanced-action-buttons.e2e.test.ts +268 -0
- package/src/queue-advanced-e2e-setup.ts +873 -0
- package/src/queue-advanced-footer.e2e.test.ts +576 -0
- package/src/queue-advanced-model-switch.e2e.test.ts +383 -0
- package/src/queue-advanced-permissions-typing.e2e.test.ts +245 -0
- package/src/queue-advanced-question.e2e.test.ts +316 -0
- package/src/queue-advanced-typing-interrupt.e2e.test.ts +146 -0
- package/src/queue-advanced-typing.e2e.test.ts +199 -0
- package/src/queue-drain-after-interactive-ui.e2e.test.ts +151 -0
- package/src/queue-interrupt-drain.e2e.test.ts +166 -0
- package/src/queue-question-select-drain.e2e.test.ts +152 -0
- package/src/runtime-idle-sweeper.ts +76 -0
- package/src/runtime-lifecycle.e2e.test.ts +641 -0
- package/src/schema.sql +173 -0
- package/src/sentry.ts +26 -0
- package/src/session-handler/agent-utils.ts +97 -0
- package/src/session-handler/event-stream-fixtures/real-session-action-buttons.jsonl +45 -0
- package/src/session-handler/event-stream-fixtures/real-session-footer-suppressed-on-pre-idle-interrupt.jsonl +40 -0
- package/src/session-handler/event-stream-fixtures/real-session-permission-external-file.jsonl +23 -0
- package/src/session-handler/event-stream-fixtures/real-session-task-normal.jsonl +22 -0
- package/src/session-handler/event-stream-fixtures/real-session-task-three-parallel-sleeps.jsonl +277 -0
- package/src/session-handler/event-stream-fixtures/real-session-task-user-interruption.jsonl +46 -0
- package/src/session-handler/event-stream-fixtures/session-abort-after-idle-race.jsonl +21 -0
- package/src/session-handler/event-stream-fixtures/session-concurrent-messages-serialized.jsonl +56 -0
- package/src/session-handler/event-stream-fixtures/session-explicit-abort.jsonl +44 -0
- package/src/session-handler/event-stream-fixtures/session-normal-completion.jsonl +29 -0
- package/src/session-handler/event-stream-fixtures/session-tool-call-noisy-stream.jsonl +29 -0
- package/src/session-handler/event-stream-fixtures/session-two-completions-same-session.jsonl +50 -0
- package/src/session-handler/event-stream-fixtures/session-user-interruption.jsonl +59 -0
- package/src/session-handler/event-stream-fixtures/session-voice-queued-followup.jsonl +52 -0
- package/src/session-handler/event-stream-state.test.ts +645 -0
- package/src/session-handler/event-stream-state.ts +608 -0
- package/src/session-handler/model-utils.ts +183 -0
- package/src/session-handler/opencode-session-event-log.ts +130 -0
- package/src/session-handler/thread-runtime-state.ts +212 -0
- package/src/session-handler/thread-session-runtime.ts +4281 -0
- package/src/session-handler.ts +15 -0
- package/src/session-search.test.ts +50 -0
- package/src/session-search.ts +148 -0
- package/src/session-title-rename.test.ts +112 -0
- package/src/startup-service.ts +200 -0
- package/src/startup-time.e2e.test.ts +373 -0
- package/src/store.ts +122 -0
- package/src/system-message.test.ts +612 -0
- package/src/system-message.ts +723 -0
- package/src/task-runner.ts +421 -0
- package/src/task-schedule.test.ts +84 -0
- package/src/task-schedule.ts +311 -0
- package/src/test-utils.ts +435 -0
- package/src/thinking-utils.ts +61 -0
- package/src/thread-message-queue.e2e.test.ts +1219 -0
- package/src/tools.ts +430 -0
- package/src/undici.d.ts +12 -0
- package/src/undo-redo.e2e.test.ts +209 -0
- package/src/unnest-code-blocks.test.ts +713 -0
- package/src/unnest-code-blocks.ts +185 -0
- package/src/upgrade.ts +127 -0
- package/src/utils.ts +212 -0
- package/src/voice-attachment.ts +51 -0
- package/src/voice-handler.ts +908 -0
- package/src/voice-message.e2e.test.ts +1255 -0
- package/src/voice.test.ts +281 -0
- package/src/voice.ts +627 -0
- package/src/wait-session.ts +147 -0
- package/src/websockify.ts +101 -0
- package/src/worker-types.ts +64 -0
- package/src/worktree-lifecycle.e2e.test.ts +391 -0
- package/src/worktree-utils.ts +4 -0
- package/src/worktrees.test.ts +223 -0
- package/src/worktrees.ts +1294 -0
- package/src/xml.test.ts +38 -0
- package/src/xml.ts +121 -0
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
import { test, expect } from 'vitest';
|
|
2
|
+
import { unnestCodeBlocksFromLists } from './unnest-code-blocks.js';
|
|
3
|
+
// Discord markdown quirks (as of 2026-02):
|
|
4
|
+
// - Fenced code blocks nested inside list indentation often don't render at all.
|
|
5
|
+
// (Discord effectively wants fences at the start of the line.)
|
|
6
|
+
// - If a list line is accidentally concatenated with the next list marker or a fence,
|
|
7
|
+
// e.g. `**Title**- bullet` or `Text:```ts`, Discord won't parse it as a list/code block.
|
|
8
|
+
// These tests lock down that `unnestCodeBlocksFromLists()` produces Discord-friendly output.
|
|
9
|
+
test('basic - single item with code block', () => {
|
|
10
|
+
const input = `- Item 1
|
|
11
|
+
\`\`\`js
|
|
12
|
+
const x = 1
|
|
13
|
+
\`\`\``;
|
|
14
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
15
|
+
expect(result).toMatchInlineSnapshot(`
|
|
16
|
+
"- Item 1
|
|
17
|
+
|
|
18
|
+
\`\`\`js
|
|
19
|
+
const x = 1
|
|
20
|
+
\`\`\`"
|
|
21
|
+
`);
|
|
22
|
+
});
|
|
23
|
+
test('multiple items - code in middle item only', () => {
|
|
24
|
+
const input = `- Item 1
|
|
25
|
+
- Item 2
|
|
26
|
+
\`\`\`js
|
|
27
|
+
const x = 1
|
|
28
|
+
\`\`\`
|
|
29
|
+
- Item 3`;
|
|
30
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
31
|
+
expect(result).toMatchInlineSnapshot(`
|
|
32
|
+
"- Item 1
|
|
33
|
+
- Item 2
|
|
34
|
+
|
|
35
|
+
\`\`\`js
|
|
36
|
+
const x = 1
|
|
37
|
+
\`\`\`
|
|
38
|
+
- Item 3"
|
|
39
|
+
`);
|
|
40
|
+
});
|
|
41
|
+
test('multiple code blocks in one item', () => {
|
|
42
|
+
const input = `- Item with two code blocks
|
|
43
|
+
\`\`\`js
|
|
44
|
+
const a = 1
|
|
45
|
+
\`\`\`
|
|
46
|
+
\`\`\`python
|
|
47
|
+
b = 2
|
|
48
|
+
\`\`\``;
|
|
49
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
50
|
+
expect(result).toMatchInlineSnapshot(`
|
|
51
|
+
"- Item with two code blocks
|
|
52
|
+
|
|
53
|
+
\`\`\`js
|
|
54
|
+
const a = 1
|
|
55
|
+
\`\`\`
|
|
56
|
+
\`\`\`python
|
|
57
|
+
b = 2
|
|
58
|
+
\`\`\`"
|
|
59
|
+
`);
|
|
60
|
+
});
|
|
61
|
+
test('nested list with code', () => {
|
|
62
|
+
const input = `- Item 1
|
|
63
|
+
- Nested item
|
|
64
|
+
\`\`\`js
|
|
65
|
+
const x = 1
|
|
66
|
+
\`\`\`
|
|
67
|
+
- Item 2`;
|
|
68
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
69
|
+
expect(result).toMatchInlineSnapshot(`
|
|
70
|
+
"- Item 1
|
|
71
|
+
- Nested item
|
|
72
|
+
|
|
73
|
+
\`\`\`js
|
|
74
|
+
const x = 1
|
|
75
|
+
\`\`\`
|
|
76
|
+
- Item 2"
|
|
77
|
+
`);
|
|
78
|
+
});
|
|
79
|
+
test('ordered list preserves numbering', () => {
|
|
80
|
+
const input = `1. First item
|
|
81
|
+
\`\`\`js
|
|
82
|
+
const a = 1
|
|
83
|
+
\`\`\`
|
|
84
|
+
2. Second item
|
|
85
|
+
3. Third item`;
|
|
86
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
87
|
+
expect(result).toMatchInlineSnapshot(`
|
|
88
|
+
"1. First item
|
|
89
|
+
|
|
90
|
+
\`\`\`js
|
|
91
|
+
const a = 1
|
|
92
|
+
\`\`\`
|
|
93
|
+
2. Second item
|
|
94
|
+
3. Third item"
|
|
95
|
+
`);
|
|
96
|
+
});
|
|
97
|
+
test('list without code blocks unchanged', () => {
|
|
98
|
+
const input = `- Item 1
|
|
99
|
+
- Item 2
|
|
100
|
+
- Item 3`;
|
|
101
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
102
|
+
expect(result).toMatchInlineSnapshot(`
|
|
103
|
+
"- Item 1
|
|
104
|
+
- Item 2
|
|
105
|
+
- Item 3"
|
|
106
|
+
`);
|
|
107
|
+
});
|
|
108
|
+
test('mixed - some items have code, some dont', () => {
|
|
109
|
+
const input = `- Normal item
|
|
110
|
+
- Item with code
|
|
111
|
+
\`\`\`js
|
|
112
|
+
const x = 1
|
|
113
|
+
\`\`\`
|
|
114
|
+
- Another normal item
|
|
115
|
+
- Another with code
|
|
116
|
+
\`\`\`python
|
|
117
|
+
y = 2
|
|
118
|
+
\`\`\``;
|
|
119
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
120
|
+
expect(result).toMatchInlineSnapshot(`
|
|
121
|
+
"- Normal item
|
|
122
|
+
- Item with code
|
|
123
|
+
|
|
124
|
+
\`\`\`js
|
|
125
|
+
const x = 1
|
|
126
|
+
\`\`\`
|
|
127
|
+
- Another normal item
|
|
128
|
+
- Another with code
|
|
129
|
+
|
|
130
|
+
\`\`\`python
|
|
131
|
+
y = 2
|
|
132
|
+
\`\`\`"
|
|
133
|
+
`);
|
|
134
|
+
});
|
|
135
|
+
test('text before and after code in same item', () => {
|
|
136
|
+
const input = `- Start text
|
|
137
|
+
\`\`\`js
|
|
138
|
+
const x = 1
|
|
139
|
+
\`\`\`
|
|
140
|
+
End text`;
|
|
141
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
142
|
+
expect(result).toMatchInlineSnapshot(`
|
|
143
|
+
"- Start text
|
|
144
|
+
|
|
145
|
+
\`\`\`js
|
|
146
|
+
const x = 1
|
|
147
|
+
\`\`\`
|
|
148
|
+
- End text"
|
|
149
|
+
`);
|
|
150
|
+
});
|
|
151
|
+
test('preserves content outside lists', () => {
|
|
152
|
+
const input = `# Heading
|
|
153
|
+
|
|
154
|
+
Some paragraph text.
|
|
155
|
+
|
|
156
|
+
- List item
|
|
157
|
+
\`\`\`js
|
|
158
|
+
const x = 1
|
|
159
|
+
\`\`\`
|
|
160
|
+
|
|
161
|
+
More text after.`;
|
|
162
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
163
|
+
expect(result).toMatchInlineSnapshot(`
|
|
164
|
+
"# Heading
|
|
165
|
+
|
|
166
|
+
Some paragraph text.
|
|
167
|
+
|
|
168
|
+
- List item
|
|
169
|
+
|
|
170
|
+
\`\`\`js
|
|
171
|
+
const x = 1
|
|
172
|
+
\`\`\`
|
|
173
|
+
|
|
174
|
+
More text after."
|
|
175
|
+
`);
|
|
176
|
+
});
|
|
177
|
+
test('code block at root level unchanged', () => {
|
|
178
|
+
const input = `\`\`\`js
|
|
179
|
+
const x = 1
|
|
180
|
+
\`\`\``;
|
|
181
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
182
|
+
expect(result).toMatchInlineSnapshot(`
|
|
183
|
+
"\`\`\`js
|
|
184
|
+
const x = 1
|
|
185
|
+
\`\`\`"
|
|
186
|
+
`);
|
|
187
|
+
});
|
|
188
|
+
test('handles code block without language', () => {
|
|
189
|
+
const input = `- Item
|
|
190
|
+
\`\`\`
|
|
191
|
+
plain code
|
|
192
|
+
\`\`\``;
|
|
193
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
194
|
+
expect(result).toMatchInlineSnapshot(`
|
|
195
|
+
"- Item
|
|
196
|
+
|
|
197
|
+
\`\`\`
|
|
198
|
+
plain code
|
|
199
|
+
\`\`\`"
|
|
200
|
+
`);
|
|
201
|
+
});
|
|
202
|
+
test('handles empty list item with code', () => {
|
|
203
|
+
const input = `- \`\`\`js
|
|
204
|
+
const x = 1
|
|
205
|
+
\`\`\``;
|
|
206
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
207
|
+
expect(result).toMatchInlineSnapshot(`
|
|
208
|
+
"\`\`\`js
|
|
209
|
+
const x = 1
|
|
210
|
+
\`\`\`"
|
|
211
|
+
`);
|
|
212
|
+
});
|
|
213
|
+
test('numbered list with text after code block', () => {
|
|
214
|
+
const input = `1. First item
|
|
215
|
+
\`\`\`js
|
|
216
|
+
const a = 1
|
|
217
|
+
\`\`\`
|
|
218
|
+
Text after the code
|
|
219
|
+
2. Second item`;
|
|
220
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
221
|
+
expect(result).toMatchInlineSnapshot(`
|
|
222
|
+
"1. First item
|
|
223
|
+
|
|
224
|
+
\`\`\`js
|
|
225
|
+
const a = 1
|
|
226
|
+
\`\`\`
|
|
227
|
+
- Text after the code
|
|
228
|
+
2. Second item"
|
|
229
|
+
`);
|
|
230
|
+
});
|
|
231
|
+
test('numbered list with multiple code blocks and text between', () => {
|
|
232
|
+
const input = `1. First item
|
|
233
|
+
\`\`\`js
|
|
234
|
+
const a = 1
|
|
235
|
+
\`\`\`
|
|
236
|
+
Middle text
|
|
237
|
+
\`\`\`python
|
|
238
|
+
b = 2
|
|
239
|
+
\`\`\`
|
|
240
|
+
Final text
|
|
241
|
+
2. Second item`;
|
|
242
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
243
|
+
expect(result).toMatchInlineSnapshot(`
|
|
244
|
+
"1. First item
|
|
245
|
+
|
|
246
|
+
\`\`\`js
|
|
247
|
+
const a = 1
|
|
248
|
+
\`\`\`
|
|
249
|
+
- Middle text
|
|
250
|
+
|
|
251
|
+
\`\`\`python
|
|
252
|
+
b = 2
|
|
253
|
+
\`\`\`
|
|
254
|
+
- Final text
|
|
255
|
+
2. Second item"
|
|
256
|
+
`);
|
|
257
|
+
});
|
|
258
|
+
test('unordered list with multiple code blocks and text between', () => {
|
|
259
|
+
const input = `- First item
|
|
260
|
+
\`\`\`js
|
|
261
|
+
const a = 1
|
|
262
|
+
\`\`\`
|
|
263
|
+
Middle text
|
|
264
|
+
\`\`\`python
|
|
265
|
+
b = 2
|
|
266
|
+
\`\`\`
|
|
267
|
+
Final text
|
|
268
|
+
- Second item`;
|
|
269
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
270
|
+
expect(result).toMatchInlineSnapshot(`
|
|
271
|
+
"- First item
|
|
272
|
+
|
|
273
|
+
\`\`\`js
|
|
274
|
+
const a = 1
|
|
275
|
+
\`\`\`
|
|
276
|
+
- Middle text
|
|
277
|
+
|
|
278
|
+
\`\`\`python
|
|
279
|
+
b = 2
|
|
280
|
+
\`\`\`
|
|
281
|
+
- Final text
|
|
282
|
+
- Second item"
|
|
283
|
+
`);
|
|
284
|
+
});
|
|
285
|
+
test('numbered list starting from 5', () => {
|
|
286
|
+
const input = `5. Fifth item
|
|
287
|
+
\`\`\`js
|
|
288
|
+
code
|
|
289
|
+
\`\`\`
|
|
290
|
+
Text after
|
|
291
|
+
6. Sixth item`;
|
|
292
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
293
|
+
expect(result).toMatchInlineSnapshot(`
|
|
294
|
+
"5. Fifth item
|
|
295
|
+
|
|
296
|
+
\`\`\`js
|
|
297
|
+
code
|
|
298
|
+
\`\`\`
|
|
299
|
+
- Text after
|
|
300
|
+
6. Sixth item"
|
|
301
|
+
`);
|
|
302
|
+
});
|
|
303
|
+
test('deeply nested list with code', () => {
|
|
304
|
+
const input = `- Level 1
|
|
305
|
+
- Level 2
|
|
306
|
+
- Level 3
|
|
307
|
+
\`\`\`js
|
|
308
|
+
deep code
|
|
309
|
+
\`\`\`
|
|
310
|
+
Text after deep code
|
|
311
|
+
- Another level 3
|
|
312
|
+
- Back to level 2`;
|
|
313
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
314
|
+
expect(result).toMatchInlineSnapshot(`
|
|
315
|
+
"- Level 1
|
|
316
|
+
- Level 2
|
|
317
|
+
- Level 3
|
|
318
|
+
|
|
319
|
+
\`\`\`js
|
|
320
|
+
deep code
|
|
321
|
+
\`\`\`
|
|
322
|
+
- Text after deep code
|
|
323
|
+
- Another level 3
|
|
324
|
+
- Back to level 2"
|
|
325
|
+
`);
|
|
326
|
+
});
|
|
327
|
+
test('nested numbered list inside unordered with code', () => {
|
|
328
|
+
const input = `- Unordered item
|
|
329
|
+
1. Nested numbered
|
|
330
|
+
\`\`\`js
|
|
331
|
+
code
|
|
332
|
+
\`\`\`
|
|
333
|
+
Text after
|
|
334
|
+
2. Second nested
|
|
335
|
+
- Another unordered`;
|
|
336
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
337
|
+
expect(result).toMatchInlineSnapshot(`
|
|
338
|
+
"- Unordered item
|
|
339
|
+
1. Nested numbered
|
|
340
|
+
|
|
341
|
+
\`\`\`js
|
|
342
|
+
code
|
|
343
|
+
\`\`\`
|
|
344
|
+
- Text after
|
|
345
|
+
2. Second nested
|
|
346
|
+
- Another unordered"
|
|
347
|
+
`);
|
|
348
|
+
});
|
|
349
|
+
test('code block at end of numbered item no text after', () => {
|
|
350
|
+
const input = `1. First with text
|
|
351
|
+
\`\`\`js
|
|
352
|
+
code here
|
|
353
|
+
\`\`\`
|
|
354
|
+
2. Second item
|
|
355
|
+
3. Third item`;
|
|
356
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
357
|
+
expect(result).toMatchInlineSnapshot(`
|
|
358
|
+
"1. First with text
|
|
359
|
+
|
|
360
|
+
\`\`\`js
|
|
361
|
+
code here
|
|
362
|
+
\`\`\`
|
|
363
|
+
2. Second item
|
|
364
|
+
3. Third item"
|
|
365
|
+
`);
|
|
366
|
+
});
|
|
367
|
+
test('multiple items each with code and text after', () => {
|
|
368
|
+
const input = `1. First
|
|
369
|
+
\`\`\`js
|
|
370
|
+
code1
|
|
371
|
+
\`\`\`
|
|
372
|
+
After first
|
|
373
|
+
2. Second
|
|
374
|
+
\`\`\`python
|
|
375
|
+
code2
|
|
376
|
+
\`\`\`
|
|
377
|
+
After second
|
|
378
|
+
3. Third no code`;
|
|
379
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
380
|
+
expect(result).toMatchInlineSnapshot(`
|
|
381
|
+
"1. First
|
|
382
|
+
|
|
383
|
+
\`\`\`js
|
|
384
|
+
code1
|
|
385
|
+
\`\`\`
|
|
386
|
+
- After first
|
|
387
|
+
2. Second
|
|
388
|
+
|
|
389
|
+
\`\`\`python
|
|
390
|
+
code2
|
|
391
|
+
\`\`\`
|
|
392
|
+
- After second
|
|
393
|
+
3. Third no code"
|
|
394
|
+
`);
|
|
395
|
+
});
|
|
396
|
+
test('code block immediately after list marker', () => {
|
|
397
|
+
const input = `1. \`\`\`js
|
|
398
|
+
immediate code
|
|
399
|
+
\`\`\`
|
|
400
|
+
2. Normal item`;
|
|
401
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
402
|
+
expect(result).toMatchInlineSnapshot(`
|
|
403
|
+
"\`\`\`js
|
|
404
|
+
immediate code
|
|
405
|
+
\`\`\`
|
|
406
|
+
2. Normal item"
|
|
407
|
+
`);
|
|
408
|
+
});
|
|
409
|
+
test('code block with filename metadata', () => {
|
|
410
|
+
const input = `- Item with code
|
|
411
|
+
\`\`\`tsx filename=example.tsx
|
|
412
|
+
const x = 1
|
|
413
|
+
\`\`\``;
|
|
414
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
415
|
+
expect(result).toMatchInlineSnapshot(`
|
|
416
|
+
"- Item with code
|
|
417
|
+
|
|
418
|
+
\`\`\`tsx filename=example.tsx
|
|
419
|
+
const x = 1
|
|
420
|
+
\`\`\`"
|
|
421
|
+
`);
|
|
422
|
+
});
|
|
423
|
+
test('numbered list with filename metadata code block', () => {
|
|
424
|
+
const input = `1. First item
|
|
425
|
+
\`\`\`tsx filename=app.tsx
|
|
426
|
+
export default function App() {}
|
|
427
|
+
\`\`\`
|
|
428
|
+
2. Second item`;
|
|
429
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
430
|
+
expect(result).toMatchInlineSnapshot(`
|
|
431
|
+
"1. First item
|
|
432
|
+
|
|
433
|
+
\`\`\`tsx filename=app.tsx
|
|
434
|
+
export default function App() {}
|
|
435
|
+
\`\`\`
|
|
436
|
+
2. Second item"
|
|
437
|
+
`);
|
|
438
|
+
});
|
|
439
|
+
test('inline fence in list item stays inline (discord formatting issue)', () => {
|
|
440
|
+
const input = `- File: playwriter/src/aria-snapshot.ts
|
|
441
|
+
- Add helper function (~line 477, after isTextRole):\`\`\`ts
|
|
442
|
+
function isSubstringOfAny(needle: string, haystack: Set<string>): boolean {
|
|
443
|
+
for (const str of haystack) {
|
|
444
|
+
if (str.includes(needle)) {
|
|
445
|
+
return true
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return false
|
|
449
|
+
}
|
|
450
|
+
\`\`\``;
|
|
451
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
452
|
+
expect(result).toMatchInlineSnapshot(`
|
|
453
|
+
"- File: playwriter/src/aria-snapshot.ts
|
|
454
|
+
- Add helper function (~line 477, after isTextRole):\`\`\`ts
|
|
455
|
+
function isSubstringOfAny(needle: string, haystack: Set<string>): boolean {
|
|
456
|
+
for (const str of haystack) {
|
|
457
|
+
if (str.includes(needle)) {
|
|
458
|
+
return true
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return false
|
|
462
|
+
}
|
|
463
|
+
\`\`\`"
|
|
464
|
+
`);
|
|
465
|
+
});
|
|
466
|
+
test('numbered list with ) delimiter and code block after continuation text', () => {
|
|
467
|
+
const input = `What to test (no mocks, real processes):
|
|
468
|
+
|
|
469
|
+
1) **"Older client must not kill newer server"**
|
|
470
|
+
- Start a tiny HTTP server on an ephemeral port that serves \`/version\` as something **higher than** our current version.
|
|
471
|
+
- Run \`ensureRelayServer({ restartOnVersionMismatch: true })\` pointed at that port.
|
|
472
|
+
- Assert:
|
|
473
|
+
- the server is **still listening** afterward (port not killed)
|
|
474
|
+
- no relay is spawned / no kill attempted
|
|
475
|
+
This directly exercises:
|
|
476
|
+
\`\`\`ts
|
|
477
|
+
if (serverVersion !== null && compareVersions(serverVersion, VERSION) > 0) return
|
|
478
|
+
\`\`\`
|
|
479
|
+
|
|
480
|
+
2) **"Newer client may restart older server (when allowed)"**
|
|
481
|
+
- Start a tiny HTTP server that returns a **lower** \`/version\`.
|
|
482
|
+
- Call \`ensureRelayServer({ restartOnVersionMismatch: true })\`.
|
|
483
|
+
- Assert the old server gets killed (port frees).`;
|
|
484
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
485
|
+
expect('\n' + result).toMatchInlineSnapshot(`
|
|
486
|
+
"
|
|
487
|
+
What to test (no mocks, real processes):
|
|
488
|
+
|
|
489
|
+
1) **"Older client must not kill newer server"**
|
|
490
|
+
- Start a tiny HTTP server on an ephemeral port that serves \`/version\` as something **higher than** our current version.
|
|
491
|
+
- Run \`ensureRelayServer({ restartOnVersionMismatch: true })\` pointed at that port.
|
|
492
|
+
- Assert:
|
|
493
|
+
- the server is **still listening** afterward (port not killed)
|
|
494
|
+
- no relay is spawned / no kill attempted
|
|
495
|
+
This directly exercises:
|
|
496
|
+
\`\`\`ts
|
|
497
|
+
if (serverVersion !== null && compareVersions(serverVersion, VERSION) > 0) return
|
|
498
|
+
\`\`\`
|
|
499
|
+
|
|
500
|
+
2) **"Newer client may restart older server (when allowed)"**
|
|
501
|
+
- Start a tiny HTTP server that returns a **lower** \`/version\`.
|
|
502
|
+
- Call \`ensureRelayServer({ restartOnVersionMismatch: true })\`.
|
|
503
|
+
- Assert the old server gets killed (port frees)."
|
|
504
|
+
`);
|
|
505
|
+
// Desired Discord formatting:
|
|
506
|
+
// - Preserve newline between the "1) ..." line and the nested "- Start..." list
|
|
507
|
+
// - Keep fenced code blocks on their own lines (not glued to surrounding text)
|
|
508
|
+
expect(result).toContain('1) **"Older client must not kill newer server"**\n');
|
|
509
|
+
expect(result).toContain('\n- Start a tiny HTTP server');
|
|
510
|
+
expect(result).toContain('\nThis directly exercises:\n');
|
|
511
|
+
expect(result).toMatch(/\n```ts\n[\s\S]*\n```\n/);
|
|
512
|
+
// Regression: these are the two failure modes seen in the session message
|
|
513
|
+
expect(result).not.toContain('**"Older client must not kill newer server"**- Start');
|
|
514
|
+
expect(result).not.toContain('exercises:```');
|
|
515
|
+
});
|
|
516
|
+
test('unordered list with blank line before fenced code block', () => {
|
|
517
|
+
const input = `- Item with spacing
|
|
518
|
+
|
|
519
|
+
\`\`\`ts
|
|
520
|
+
const x = 1
|
|
521
|
+
\`\`\`
|
|
522
|
+
- Next item`;
|
|
523
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
524
|
+
expect('\n' + result).toMatchInlineSnapshot(`
|
|
525
|
+
"
|
|
526
|
+
- Item with spacing
|
|
527
|
+
|
|
528
|
+
\`\`\`ts
|
|
529
|
+
const x = 1
|
|
530
|
+
\`\`\`
|
|
531
|
+
- Next item"
|
|
532
|
+
`);
|
|
533
|
+
});
|
|
534
|
+
test('ordered list item containing fenced code and trailing paragraph', () => {
|
|
535
|
+
const input = `1) Item title
|
|
536
|
+
\`\`\`js
|
|
537
|
+
console.log('hi')
|
|
538
|
+
\`\`\`
|
|
539
|
+
trailing text
|
|
540
|
+
2) Second item`;
|
|
541
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
542
|
+
expect('\n' + result).toMatchInlineSnapshot(`
|
|
543
|
+
"
|
|
544
|
+
1. Item title
|
|
545
|
+
|
|
546
|
+
\`\`\`js
|
|
547
|
+
console.log('hi')
|
|
548
|
+
\`\`\`
|
|
549
|
+
- trailing text
|
|
550
|
+
2) Second item"
|
|
551
|
+
`);
|
|
552
|
+
});
|
|
553
|
+
test('two top-level lists back-to-back (ensure newline between them)', () => {
|
|
554
|
+
const input = `- a
|
|
555
|
+
- b
|
|
556
|
+
1) c
|
|
557
|
+
- d`;
|
|
558
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
559
|
+
expect('\n' + result).toMatchInlineSnapshot(`
|
|
560
|
+
"
|
|
561
|
+
- a
|
|
562
|
+
- b
|
|
563
|
+
1) c
|
|
564
|
+
- d"
|
|
565
|
+
`);
|
|
566
|
+
});
|
|
567
|
+
test('top-level list followed by top-level fenced code then paragraph', () => {
|
|
568
|
+
const input = `- Item
|
|
569
|
+
\`\`\`ts
|
|
570
|
+
type X = { a: 1 }
|
|
571
|
+
\`\`\`
|
|
572
|
+
After.`;
|
|
573
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
574
|
+
expect('\n' + result).toMatchInlineSnapshot(`
|
|
575
|
+
"
|
|
576
|
+
- Item
|
|
577
|
+
\`\`\`ts
|
|
578
|
+
type X = { a: 1 }
|
|
579
|
+
\`\`\`
|
|
580
|
+
After."
|
|
581
|
+
`);
|
|
582
|
+
});
|
|
583
|
+
test('task list item with fenced code', () => {
|
|
584
|
+
const input = `- [ ] Do thing
|
|
585
|
+
\`\`\`sh
|
|
586
|
+
echo hi
|
|
587
|
+
\`\`\``;
|
|
588
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
589
|
+
expect('\n' + result).toMatchInlineSnapshot(`
|
|
590
|
+
"
|
|
591
|
+
- [ ] Do thing
|
|
592
|
+
|
|
593
|
+
\`\`\`sh
|
|
594
|
+
echo hi
|
|
595
|
+
\`\`\`"
|
|
596
|
+
`);
|
|
597
|
+
});
|
|
598
|
+
test('checked task list item keeps a single checkbox marker', () => {
|
|
599
|
+
const input = `- [x] Ship fix
|
|
600
|
+
\`\`\`ts
|
|
601
|
+
console.log('done')
|
|
602
|
+
\`\`\``;
|
|
603
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
604
|
+
expect('\n' + result).toMatchInlineSnapshot(`
|
|
605
|
+
"
|
|
606
|
+
- [x] Ship fix
|
|
607
|
+
|
|
608
|
+
\`\`\`ts
|
|
609
|
+
console.log('done')
|
|
610
|
+
\`\`\`"
|
|
611
|
+
`);
|
|
612
|
+
});
|
|
613
|
+
test('task list item with trailing text keeps one checkbox marker after hoisting code', () => {
|
|
614
|
+
const input = `- [ ] Do thing
|
|
615
|
+
\`\`\`sh
|
|
616
|
+
echo hi
|
|
617
|
+
\`\`\`
|
|
618
|
+
then report back`;
|
|
619
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
620
|
+
expect('\n' + result).toMatchInlineSnapshot(`
|
|
621
|
+
"
|
|
622
|
+
- [ ] Do thing
|
|
623
|
+
|
|
624
|
+
\`\`\`sh
|
|
625
|
+
echo hi
|
|
626
|
+
\`\`\`
|
|
627
|
+
- then report back"
|
|
628
|
+
`);
|
|
629
|
+
});
|
|
630
|
+
test('fenced code block indented more than list marker', () => {
|
|
631
|
+
const input = `- Item
|
|
632
|
+
\`\`\`ts
|
|
633
|
+
const x = 1
|
|
634
|
+
\`\`\`
|
|
635
|
+
- Next`;
|
|
636
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
637
|
+
expect('\n' + result).toMatchInlineSnapshot(`
|
|
638
|
+
"
|
|
639
|
+
- Item
|
|
640
|
+
|
|
641
|
+
\`\`\`ts
|
|
642
|
+
const x = 1
|
|
643
|
+
\`\`\`
|
|
644
|
+
- Next"
|
|
645
|
+
`);
|
|
646
|
+
});
|
|
647
|
+
test('ordered list with multiple paragraphs and code', () => {
|
|
648
|
+
const input = `1) Title
|
|
649
|
+
First paragraph.
|
|
650
|
+
|
|
651
|
+
Second paragraph.
|
|
652
|
+
|
|
653
|
+
\`\`\`ts
|
|
654
|
+
const x = 1
|
|
655
|
+
\`\`\`
|
|
656
|
+
|
|
657
|
+
After code.
|
|
658
|
+
2) Next`;
|
|
659
|
+
const result = unnestCodeBlocksFromLists(input);
|
|
660
|
+
expect('\n' + result).toMatchInlineSnapshot(`
|
|
661
|
+
"
|
|
662
|
+
1. Title
|
|
663
|
+
First paragraph.
|
|
664
|
+
|
|
665
|
+
Second paragraph.
|
|
666
|
+
|
|
667
|
+
\`\`\`ts
|
|
668
|
+
const x = 1
|
|
669
|
+
\`\`\`
|
|
670
|
+
- After code.
|
|
671
|
+
2) Next"
|
|
672
|
+
`);
|
|
673
|
+
});
|