@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
package/dist/logger.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// Prefixed logging utility using @clack/prompts for consistent visual style.
|
|
2
|
+
// All log methods use clack's log.message() with appropriate symbols to prevent
|
|
3
|
+
// output interleaving from concurrent async operations.
|
|
4
|
+
import { log as clackLog } from '@clack/prompts';
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import util from 'node:util';
|
|
8
|
+
import pc from 'picocolors';
|
|
9
|
+
import { sanitizeSensitiveText, sanitizeUnknownValue } from './privacy-sanitizer.js';
|
|
10
|
+
// All known log prefixes - add new ones here to keep alignment consistent
|
|
11
|
+
export const LogPrefix = {
|
|
12
|
+
ABORT: 'ABORT',
|
|
13
|
+
ADD_PROJECT: 'ADD_PROJ',
|
|
14
|
+
AGENT: 'AGENT',
|
|
15
|
+
ASK_QUESTION: 'QUESTION',
|
|
16
|
+
CHANNEL: 'CHANNEL',
|
|
17
|
+
CLI: 'CLI',
|
|
18
|
+
COMPACT: 'COMPACT',
|
|
19
|
+
CREATE_PROJECT: 'NEW_PROJ',
|
|
20
|
+
DB: 'DB',
|
|
21
|
+
DIFF: 'DIFF',
|
|
22
|
+
FILE_UPLOAD: 'FILEUP',
|
|
23
|
+
DISCORD: 'DISCORD',
|
|
24
|
+
FORK: 'FORK',
|
|
25
|
+
FORMATTING: 'FORMAT',
|
|
26
|
+
GENAI: 'GENAI',
|
|
27
|
+
HEAP: 'HEAP',
|
|
28
|
+
GENAI_WORKER: 'GENAI_W',
|
|
29
|
+
INTERACTION: 'INTERACT',
|
|
30
|
+
IPC: 'IPC',
|
|
31
|
+
LOGIN: 'LOGIN',
|
|
32
|
+
MARKDOWN: 'MARKDOWN',
|
|
33
|
+
MCP: 'MCP',
|
|
34
|
+
MODEL: 'MODEL',
|
|
35
|
+
OPENAI: 'OPENAI',
|
|
36
|
+
OPENCODE: 'OPENCODE',
|
|
37
|
+
PERMISSIONS: 'PERMS',
|
|
38
|
+
QUEUE: 'QUEUE',
|
|
39
|
+
REMOVE_PROJECT: 'RM_PROJ',
|
|
40
|
+
RESUME: 'RESUME',
|
|
41
|
+
SESSION: 'SESSION',
|
|
42
|
+
SHARE: 'SHARE',
|
|
43
|
+
TASK: 'TASK',
|
|
44
|
+
TOOLS: 'TOOLS',
|
|
45
|
+
UNDO_REDO: 'UNDO',
|
|
46
|
+
USER_CMD: 'USER_CMD',
|
|
47
|
+
VERBOSITY: 'VERBOSE',
|
|
48
|
+
VOICE: 'VOICE',
|
|
49
|
+
WORKER: 'WORKER',
|
|
50
|
+
THINKING: 'THINK',
|
|
51
|
+
WORKTREE: 'WORKTREE',
|
|
52
|
+
XML: 'XML',
|
|
53
|
+
};
|
|
54
|
+
// compute max length from all known prefixes for alignment
|
|
55
|
+
const MAX_PREFIX_LENGTH = Math.max(...Object.values(LogPrefix).map((p) => p.length));
|
|
56
|
+
// Log file path is set by initLogFile() after the data directory is known.
|
|
57
|
+
// Before initLogFile() is called, file logging is skipped.
|
|
58
|
+
let logFilePath = null;
|
|
59
|
+
/**
|
|
60
|
+
* Initialize file logging. Call this after setDataDir() so the log file
|
|
61
|
+
* is written to `<dataDir>/kimaki.log`. The log file is truncated on
|
|
62
|
+
* every bot startup so it contains only the current run's logs.
|
|
63
|
+
*/
|
|
64
|
+
export function initLogFile(dataDir) {
|
|
65
|
+
logFilePath = path.join(dataDir, 'kimaki.log');
|
|
66
|
+
const logDir = path.dirname(logFilePath);
|
|
67
|
+
if (!fs.existsSync(logDir)) {
|
|
68
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
69
|
+
}
|
|
70
|
+
fs.writeFileSync(logFilePath, `--- kimaki log started at ${new Date().toISOString()} ---\n`);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Set the log file path without truncating. Use this in child processes
|
|
74
|
+
* (like the opencode plugin) that should append to the same log file
|
|
75
|
+
* the bot process already created with initLogFile().
|
|
76
|
+
*/
|
|
77
|
+
export function setLogFilePath(dataDir) {
|
|
78
|
+
logFilePath = path.join(dataDir, 'kimaki.log');
|
|
79
|
+
}
|
|
80
|
+
export function getLogFilePath() {
|
|
81
|
+
return logFilePath;
|
|
82
|
+
}
|
|
83
|
+
function formatArg(arg) {
|
|
84
|
+
if (typeof arg === 'string') {
|
|
85
|
+
return sanitizeSensitiveText(arg, { redactPaths: false });
|
|
86
|
+
}
|
|
87
|
+
const safeArg = sanitizeUnknownValue(arg, { redactPaths: false });
|
|
88
|
+
return util.inspect(safeArg, { colors: true, depth: 4 });
|
|
89
|
+
}
|
|
90
|
+
export function formatErrorWithStack(error) {
|
|
91
|
+
if (error instanceof Error) {
|
|
92
|
+
return sanitizeSensitiveText(error.stack ?? `${error.name}: ${error.message}`, { redactPaths: false });
|
|
93
|
+
}
|
|
94
|
+
if (typeof error === 'string') {
|
|
95
|
+
return sanitizeSensitiveText(error, { redactPaths: false });
|
|
96
|
+
}
|
|
97
|
+
// Keep this stable and safe for unknown values (handles circular structures).
|
|
98
|
+
const safeError = sanitizeUnknownValue(error, { redactPaths: false });
|
|
99
|
+
return sanitizeSensitiveText(util.inspect(safeError, { colors: false, depth: 4 }), {
|
|
100
|
+
redactPaths: false,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function writeToFile(level, prefix, args) {
|
|
104
|
+
const timestamp = new Date().toISOString();
|
|
105
|
+
const message = `[${timestamp}] [${level}] [${prefix}] ${args.map(formatArg).join(' ')}\n`;
|
|
106
|
+
if (!logFilePath) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
fs.appendFileSync(logFilePath, message);
|
|
110
|
+
}
|
|
111
|
+
function getTimestamp() {
|
|
112
|
+
const now = new Date();
|
|
113
|
+
return `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
|
|
114
|
+
}
|
|
115
|
+
function padPrefix(prefix) {
|
|
116
|
+
return prefix.padEnd(MAX_PREFIX_LENGTH);
|
|
117
|
+
}
|
|
118
|
+
function formatMessage(timestamp, prefix, args) {
|
|
119
|
+
return [pc.dim(timestamp), prefix, ...args.map(formatArg)].join(' ');
|
|
120
|
+
}
|
|
121
|
+
const noSpacing = { spacing: 0 };
|
|
122
|
+
// Suppress clack terminal output during vitest runs to avoid flooding
|
|
123
|
+
// test output with hundreds of log lines. File logging still works.
|
|
124
|
+
// Set KIMAKI_TEST_LOGS=1 when rerunning a failing test to see all
|
|
125
|
+
// kimaki logger output in the terminal for debugging.
|
|
126
|
+
const isVitest = !!process.env['KIMAKI_VITEST'];
|
|
127
|
+
const showTestLogs = isVitest && !!process.env['KIMAKI_TEST_LOGS'];
|
|
128
|
+
export function createLogger(prefix) {
|
|
129
|
+
const paddedPrefix = padPrefix(prefix);
|
|
130
|
+
const suppressConsole = isVitest && !showTestLogs;
|
|
131
|
+
const log = (...args) => {
|
|
132
|
+
writeToFile('LOG', prefix, args);
|
|
133
|
+
if (suppressConsole) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
clackLog.message(formatMessage(getTimestamp(), pc.cyan(paddedPrefix), args), {
|
|
137
|
+
...noSpacing,
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
return {
|
|
141
|
+
log,
|
|
142
|
+
error: (...args) => {
|
|
143
|
+
writeToFile('ERROR', prefix, args);
|
|
144
|
+
if (suppressConsole) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
clackLog.error(formatMessage(getTimestamp(), pc.red(paddedPrefix), args), noSpacing);
|
|
148
|
+
},
|
|
149
|
+
warn: (...args) => {
|
|
150
|
+
writeToFile('WARN', prefix, args);
|
|
151
|
+
if (suppressConsole) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
clackLog.warn(formatMessage(getTimestamp(), pc.yellow(paddedPrefix), args), noSpacing);
|
|
155
|
+
},
|
|
156
|
+
info: (...args) => {
|
|
157
|
+
writeToFile('INFO', prefix, args);
|
|
158
|
+
if (suppressConsole) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
clackLog.info(formatMessage(getTimestamp(), pc.blue(paddedPrefix), args), noSpacing);
|
|
162
|
+
},
|
|
163
|
+
debug: log,
|
|
164
|
+
};
|
|
165
|
+
}
|
package/dist/markdown.js
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
// Session-to-markdown renderer for sharing.
|
|
2
|
+
// Generates shareable markdown from OpenCode sessions, formatting
|
|
3
|
+
// user messages, assistant responses, tool calls, and reasoning blocks.
|
|
4
|
+
// Uses errore for type-safe error handling.
|
|
5
|
+
import * as errore from 'errore';
|
|
6
|
+
import { createTaggedError } from 'errore';
|
|
7
|
+
import YAML from 'yaml';
|
|
8
|
+
import { formatDateTime } from './utils.js';
|
|
9
|
+
import { extractNonXmlContent } from './xml.js';
|
|
10
|
+
import { createLogger, LogPrefix } from './logger.js';
|
|
11
|
+
import { SessionNotFoundError, MessagesNotFoundError } from './errors.js';
|
|
12
|
+
// Generic error for unexpected exceptions in async operations
|
|
13
|
+
class UnexpectedError extends createTaggedError({
|
|
14
|
+
name: 'UnexpectedError',
|
|
15
|
+
}) {
|
|
16
|
+
}
|
|
17
|
+
const markdownLogger = createLogger(LogPrefix.MARKDOWN);
|
|
18
|
+
const TOOL_OUTPUT_MAX_CHARS = 30_000;
|
|
19
|
+
export class ShareMarkdown {
|
|
20
|
+
client;
|
|
21
|
+
constructor(client) {
|
|
22
|
+
this.client = client;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Generate a markdown representation of a session
|
|
26
|
+
* @param options Configuration options
|
|
27
|
+
* @returns Error or markdown string
|
|
28
|
+
*/
|
|
29
|
+
async generate(options) {
|
|
30
|
+
const { sessionID, includeSystemInfo, lastAssistantOnly } = options;
|
|
31
|
+
// Get session info
|
|
32
|
+
const sessionResponse = await this.client.session.get({
|
|
33
|
+
sessionID,
|
|
34
|
+
});
|
|
35
|
+
if (!sessionResponse.data) {
|
|
36
|
+
return new SessionNotFoundError({ sessionId: sessionID });
|
|
37
|
+
}
|
|
38
|
+
const session = sessionResponse.data;
|
|
39
|
+
// Get all messages
|
|
40
|
+
const messagesResponse = await this.client.session.messages({
|
|
41
|
+
sessionID,
|
|
42
|
+
});
|
|
43
|
+
if (!messagesResponse.data) {
|
|
44
|
+
return new MessagesNotFoundError({ sessionId: sessionID });
|
|
45
|
+
}
|
|
46
|
+
const messages = messagesResponse.data;
|
|
47
|
+
// If lastAssistantOnly, filter to only the last assistant message
|
|
48
|
+
const messagesToRender = lastAssistantOnly
|
|
49
|
+
? (() => {
|
|
50
|
+
const assistantMessages = messages.filter((m) => m.info.role === 'assistant');
|
|
51
|
+
return assistantMessages.length > 0
|
|
52
|
+
? [assistantMessages[assistantMessages.length - 1]]
|
|
53
|
+
: [];
|
|
54
|
+
})()
|
|
55
|
+
: messages;
|
|
56
|
+
// Build markdown
|
|
57
|
+
const lines = [];
|
|
58
|
+
// Only include header and session info if not lastAssistantOnly
|
|
59
|
+
if (!lastAssistantOnly) {
|
|
60
|
+
// Header
|
|
61
|
+
lines.push(`# ${session.title || 'Untitled Session'}`);
|
|
62
|
+
lines.push('');
|
|
63
|
+
// Session metadata
|
|
64
|
+
if (includeSystemInfo === true) {
|
|
65
|
+
lines.push('## Session Information');
|
|
66
|
+
lines.push('');
|
|
67
|
+
lines.push(`- **Created**: ${formatDateTime(new Date(session.time.created))}`);
|
|
68
|
+
lines.push(`- **Updated**: ${formatDateTime(new Date(session.time.updated))}`);
|
|
69
|
+
if (session.version) {
|
|
70
|
+
lines.push(`- **OpenCode Version**: v${session.version}`);
|
|
71
|
+
}
|
|
72
|
+
lines.push('');
|
|
73
|
+
}
|
|
74
|
+
// Process messages
|
|
75
|
+
lines.push('## Conversation');
|
|
76
|
+
lines.push('');
|
|
77
|
+
}
|
|
78
|
+
for (const message of messagesToRender) {
|
|
79
|
+
const messageLines = this.renderMessage(message.info, message.parts);
|
|
80
|
+
lines.push(...messageLines);
|
|
81
|
+
lines.push('');
|
|
82
|
+
}
|
|
83
|
+
return lines.join('\n');
|
|
84
|
+
}
|
|
85
|
+
renderMessage(message, parts) {
|
|
86
|
+
const lines = [];
|
|
87
|
+
if (message.role === 'user') {
|
|
88
|
+
lines.push('### 👤 User');
|
|
89
|
+
lines.push('');
|
|
90
|
+
for (const part of parts) {
|
|
91
|
+
if (part.type === 'text' && part.text) {
|
|
92
|
+
const cleanedText = extractNonXmlContent(part.text);
|
|
93
|
+
if (cleanedText.trim()) {
|
|
94
|
+
lines.push(cleanedText);
|
|
95
|
+
lines.push('');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (part.type === 'file') {
|
|
99
|
+
lines.push(`📎 **Attachment**: ${part.filename || 'unnamed file'}`);
|
|
100
|
+
if (part.url) {
|
|
101
|
+
lines.push(` - URL: ${part.url}`);
|
|
102
|
+
}
|
|
103
|
+
lines.push('');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (message.role === 'assistant') {
|
|
108
|
+
lines.push(`### 🤖 Assistant (${message.modelID || 'unknown model'})`);
|
|
109
|
+
lines.push('');
|
|
110
|
+
// Filter and process parts
|
|
111
|
+
const filteredParts = parts.filter((part) => {
|
|
112
|
+
if (part.type === 'step-start' && parts.indexOf(part) > 0)
|
|
113
|
+
return false;
|
|
114
|
+
if (part.type === 'snapshot')
|
|
115
|
+
return false;
|
|
116
|
+
if (part.type === 'patch')
|
|
117
|
+
return false;
|
|
118
|
+
if (part.type === 'step-finish')
|
|
119
|
+
return false;
|
|
120
|
+
if (part.type === 'text' && part.synthetic === true)
|
|
121
|
+
return false;
|
|
122
|
+
if (part.type === 'tool' && part.tool === 'todoread')
|
|
123
|
+
return false;
|
|
124
|
+
if (part.type === 'text' && !part.text)
|
|
125
|
+
return false;
|
|
126
|
+
if (part.type === 'tool' &&
|
|
127
|
+
(part.state.status === 'pending' || part.state.status === 'running'))
|
|
128
|
+
return false;
|
|
129
|
+
return true;
|
|
130
|
+
});
|
|
131
|
+
for (const part of filteredParts) {
|
|
132
|
+
const partLines = this.renderPart(part, message);
|
|
133
|
+
lines.push(...partLines);
|
|
134
|
+
}
|
|
135
|
+
// Add completion time if available
|
|
136
|
+
if (message.time?.completed) {
|
|
137
|
+
const duration = message.time.completed - message.time.created;
|
|
138
|
+
lines.push('');
|
|
139
|
+
lines.push(`*Completed in ${this.formatDuration(duration)}*`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return lines;
|
|
143
|
+
}
|
|
144
|
+
renderPart(part, message) {
|
|
145
|
+
const lines = [];
|
|
146
|
+
switch (part.type) {
|
|
147
|
+
case 'text':
|
|
148
|
+
if (part.text) {
|
|
149
|
+
lines.push(part.text);
|
|
150
|
+
lines.push('');
|
|
151
|
+
}
|
|
152
|
+
break;
|
|
153
|
+
case 'reasoning':
|
|
154
|
+
if (part.text) {
|
|
155
|
+
lines.push('<details>');
|
|
156
|
+
lines.push('<summary>💭 Thinking</summary>');
|
|
157
|
+
lines.push('');
|
|
158
|
+
lines.push(part.text);
|
|
159
|
+
lines.push('');
|
|
160
|
+
lines.push('</details>');
|
|
161
|
+
lines.push('');
|
|
162
|
+
}
|
|
163
|
+
break;
|
|
164
|
+
case 'tool':
|
|
165
|
+
if (part.state.status === 'completed') {
|
|
166
|
+
const output = part.state.output || '';
|
|
167
|
+
const isOversized = output.length > TOOL_OUTPUT_MAX_CHARS;
|
|
168
|
+
if (isOversized) {
|
|
169
|
+
lines.push(`> ⚠️ **Large tool output** (${output.length.toLocaleString()} chars, truncated to ${TOOL_OUTPUT_MAX_CHARS.toLocaleString()})`);
|
|
170
|
+
lines.push('');
|
|
171
|
+
}
|
|
172
|
+
lines.push(`#### 🛠️ Tool: ${part.tool}`);
|
|
173
|
+
lines.push('');
|
|
174
|
+
// Render input parameters in YAML
|
|
175
|
+
if (part.state.input && Object.keys(part.state.input).length > 0) {
|
|
176
|
+
lines.push('**Input:**');
|
|
177
|
+
lines.push('```yaml');
|
|
178
|
+
lines.push(YAML.stringify(part.state.input, null, { lineWidth: 0 }));
|
|
179
|
+
lines.push('```');
|
|
180
|
+
lines.push('');
|
|
181
|
+
}
|
|
182
|
+
// Render output, truncated if too large
|
|
183
|
+
if (output) {
|
|
184
|
+
lines.push('**Output:**');
|
|
185
|
+
lines.push('```');
|
|
186
|
+
lines.push(isOversized
|
|
187
|
+
? output.slice(0, TOOL_OUTPUT_MAX_CHARS) +
|
|
188
|
+
'\n...(truncated)'
|
|
189
|
+
: output);
|
|
190
|
+
lines.push('```');
|
|
191
|
+
lines.push('');
|
|
192
|
+
}
|
|
193
|
+
// Add timing info if significant
|
|
194
|
+
if (part.state.time?.start && part.state.time?.end) {
|
|
195
|
+
const duration = part.state.time.end - part.state.time.start;
|
|
196
|
+
if (duration > 2000) {
|
|
197
|
+
lines.push(`*Duration: ${this.formatDuration(duration)}*`);
|
|
198
|
+
lines.push('');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
else if (part.state.status === 'error') {
|
|
203
|
+
lines.push(`#### ❌ Tool Error: ${part.tool}`);
|
|
204
|
+
lines.push('');
|
|
205
|
+
lines.push('```');
|
|
206
|
+
lines.push(part.state.error || 'Unknown error');
|
|
207
|
+
lines.push('```');
|
|
208
|
+
lines.push('');
|
|
209
|
+
}
|
|
210
|
+
break;
|
|
211
|
+
case 'step-start':
|
|
212
|
+
lines.push(`**Started using ${message.providerID}/${message.modelID}**`);
|
|
213
|
+
lines.push('');
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
return lines;
|
|
217
|
+
}
|
|
218
|
+
formatDuration(ms) {
|
|
219
|
+
if (ms < 1000)
|
|
220
|
+
return `${ms}ms`;
|
|
221
|
+
if (ms < 60000)
|
|
222
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
223
|
+
const minutes = Math.floor(ms / 60000);
|
|
224
|
+
const seconds = Math.floor((ms % 60000) / 1000);
|
|
225
|
+
return `${minutes}m ${seconds}s`;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Generate compact session context for voice transcription.
|
|
230
|
+
* Includes system prompt (optional), user messages, assistant text,
|
|
231
|
+
* and tool calls in compact form (name + params only, no output).
|
|
232
|
+
*/
|
|
233
|
+
export function getCompactSessionContext({ client, sessionId, includeSystemPrompt = false, maxMessages = 20, }) {
|
|
234
|
+
return errore.tryAsync({
|
|
235
|
+
try: async () => {
|
|
236
|
+
const messagesResponse = await client.session.messages({
|
|
237
|
+
sessionID: sessionId,
|
|
238
|
+
});
|
|
239
|
+
const messages = messagesResponse.data || [];
|
|
240
|
+
const lines = [];
|
|
241
|
+
// Get system prompt if requested
|
|
242
|
+
// Note: OpenCode SDK doesn't expose system prompt directly. We try multiple approaches:
|
|
243
|
+
// 1. session.system field (if available in future SDK versions)
|
|
244
|
+
// 2. synthetic text part in first assistant message (current approach)
|
|
245
|
+
if (includeSystemPrompt && messages.length > 0) {
|
|
246
|
+
const firstAssistant = messages.find((m) => m.info.role === 'assistant');
|
|
247
|
+
if (firstAssistant) {
|
|
248
|
+
// look for text part marked as synthetic (system prompt)
|
|
249
|
+
const systemPart = (firstAssistant.parts || []).find((p) => p.type === 'text' && p.synthetic === true);
|
|
250
|
+
if (systemPart && 'text' in systemPart && systemPart.text) {
|
|
251
|
+
lines.push('[System Prompt]');
|
|
252
|
+
const truncated = systemPart.text.slice(0, 3000);
|
|
253
|
+
lines.push(truncated);
|
|
254
|
+
if (systemPart.text.length > 3000) {
|
|
255
|
+
lines.push('...(truncated)');
|
|
256
|
+
}
|
|
257
|
+
lines.push('');
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// Process recent messages
|
|
262
|
+
const recentMessages = messages.slice(-maxMessages);
|
|
263
|
+
for (const msg of recentMessages) {
|
|
264
|
+
if (msg.info.role === 'user') {
|
|
265
|
+
const textParts = (msg.parts || [])
|
|
266
|
+
.filter((p) => p.type === 'text')
|
|
267
|
+
.map((p) => (p.type === 'text' ? extractNonXmlContent(p.text || '') : ''))
|
|
268
|
+
.filter(Boolean);
|
|
269
|
+
if (textParts.length > 0) {
|
|
270
|
+
lines.push(`[User]: ${textParts.join(' ').slice(0, 1000)}`);
|
|
271
|
+
lines.push('');
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else if (msg.info.role === 'assistant') {
|
|
275
|
+
// Get assistant text parts (non-synthetic, non-empty)
|
|
276
|
+
const textParts = (msg.parts || [])
|
|
277
|
+
.filter((p) => p.type === 'text' && !p.synthetic && p.text)
|
|
278
|
+
.map((p) => (p.type === 'text' ? p.text : ''))
|
|
279
|
+
.filter(Boolean);
|
|
280
|
+
if (textParts.length > 0) {
|
|
281
|
+
lines.push(`[Assistant]: ${textParts.join(' ').slice(0, 1000)}`);
|
|
282
|
+
lines.push('');
|
|
283
|
+
}
|
|
284
|
+
// Get tool calls in compact form (name + params only)
|
|
285
|
+
const toolParts = (msg.parts || []).filter((p) => p.type === 'tool' &&
|
|
286
|
+
'state' in p &&
|
|
287
|
+
p.state?.status === 'completed');
|
|
288
|
+
for (const part of toolParts) {
|
|
289
|
+
if (part.type === 'tool' && 'tool' in part && 'state' in part) {
|
|
290
|
+
const toolName = part.tool;
|
|
291
|
+
// skip noisy tools
|
|
292
|
+
if (toolName === 'todoread' || toolName === 'todowrite') {
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
const input = part.state?.input || {};
|
|
296
|
+
const normalize = (value) => value.replace(/\s+/g, ' ').trim();
|
|
297
|
+
// compact params: just key=value on one line
|
|
298
|
+
const params = Object.entries(input)
|
|
299
|
+
.map(([k, v]) => {
|
|
300
|
+
const val = typeof v === 'string'
|
|
301
|
+
? v.slice(0, 100)
|
|
302
|
+
: JSON.stringify(v).slice(0, 100);
|
|
303
|
+
return `${k}=${normalize(val)}`;
|
|
304
|
+
})
|
|
305
|
+
.join(', ');
|
|
306
|
+
lines.push(`[Tool ${toolName}]: ${params}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return lines.join('\n').slice(0, 8000);
|
|
312
|
+
},
|
|
313
|
+
catch: (e) => {
|
|
314
|
+
markdownLogger.error('Failed to get compact session context:', e);
|
|
315
|
+
return new UnexpectedError({
|
|
316
|
+
message: 'Failed to get compact session context',
|
|
317
|
+
cause: e,
|
|
318
|
+
});
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Get the last session for a directory (excluding the current one).
|
|
324
|
+
*/
|
|
325
|
+
export function getLastSessionId({ client, excludeSessionId, }) {
|
|
326
|
+
return errore.tryAsync({
|
|
327
|
+
try: async () => {
|
|
328
|
+
const sessionsResponse = await client.session.list();
|
|
329
|
+
const sessions = sessionsResponse.data || [];
|
|
330
|
+
// Sessions are sorted by time, get the most recent one that isn't the current
|
|
331
|
+
const lastSession = sessions.find((s) => s.id !== excludeSessionId);
|
|
332
|
+
return lastSession?.id || null;
|
|
333
|
+
},
|
|
334
|
+
catch: (e) => {
|
|
335
|
+
markdownLogger.error('Failed to get last session:', e);
|
|
336
|
+
return new UnexpectedError({
|
|
337
|
+
message: 'Failed to get last session',
|
|
338
|
+
cause: e,
|
|
339
|
+
});
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
}
|