@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,644 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: goke
|
|
3
|
+
description: >
|
|
4
|
+
goke is a zero-dependency, type-safe CLI framework for TypeScript. CAC replacement
|
|
5
|
+
with Standard Schema support (Zod, Valibot, ArkType). Use goke when building CLI
|
|
6
|
+
tools — it handles commands, subcommands, options, type coercion, help generation,
|
|
7
|
+
and more. Schema-based options give you automatic type inference, coercion from
|
|
8
|
+
strings, and help text generation. ALWAYS read this skill when a repo uses goke
|
|
9
|
+
for its CLI.
|
|
10
|
+
version: 0.0.1
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# goke
|
|
14
|
+
|
|
15
|
+
Zero-dependency, type-safe CLI framework for TypeScript. A CAC replacement with Standard Schema support.
|
|
16
|
+
|
|
17
|
+
5 core APIs: `cli.option`, `cli.use`, `cli.version`, `cli.help`, `cli.parse`.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { goke } from 'goke'
|
|
21
|
+
import { z } from 'zod'
|
|
22
|
+
|
|
23
|
+
const cli = goke('mycli')
|
|
24
|
+
|
|
25
|
+
cli
|
|
26
|
+
.command('serve', 'Start the dev server')
|
|
27
|
+
.option('--port <port>', z.number().default(3000).describe('Port to listen on'))
|
|
28
|
+
.option('--host [host]', z.string().default('localhost').describe('Hostname to bind'))
|
|
29
|
+
.option('--open', 'Open browser on start')
|
|
30
|
+
.action((options) => {
|
|
31
|
+
// options.port: number, options.host: string, options.open: boolean
|
|
32
|
+
console.log(options)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
cli.help()
|
|
36
|
+
cli.version('1.0.0')
|
|
37
|
+
cli.parse()
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Version
|
|
41
|
+
|
|
42
|
+
Import `package.json` with `type: 'json'` and use the `version` field:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import pkg from './package.json' with { type: 'json' }
|
|
46
|
+
|
|
47
|
+
cli.version(pkg.version)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This works in Node.js and keeps the version in sync with `package.json` automatically.
|
|
51
|
+
|
|
52
|
+
## Rules
|
|
53
|
+
|
|
54
|
+
1. Always use schema-based options (Zod, Valibot, etc.) for typed values — without a schema, all values are raw strings
|
|
55
|
+
2. **Never add `(default: X)` in the description string** when using `.default()` — goke extracts the default from the schema and appends it to help output automatically. Adding it in the description shows the default twice
|
|
56
|
+
3. Don't manually type `action` callback arguments — goke infers argument and option types automatically from the command signature and option schemas
|
|
57
|
+
4. Use `<angle brackets>` for required values, `[square brackets]` for optional values — this applies to both command arguments and option values
|
|
58
|
+
5. Use `z.array()` for options that can be passed multiple times (repeatable flags)
|
|
59
|
+
6. Use `z.enum()` for options constrained to a fixed set of values
|
|
60
|
+
7. Write very detailed descriptions for commands and options — agents and users rely on `--help` output as documentation. Include what the option does, when to use it, and examples if relevant
|
|
61
|
+
8. Add `.example()` to commands to show usage patterns in help output — use a `#` comment as the first line to explain the scenario
|
|
62
|
+
9. Options without brackets are boolean flags — `undefined` when not passed, `true` when passed (`--verbose`), `false` when negated (`--no-verbose`). This three-state behavior lets you distinguish "user explicitly set" from "not provided"
|
|
63
|
+
10. Kebab-case options are auto-camelCased in the parsed result (`--max-retries` → `options.maxRetries`)
|
|
64
|
+
11. Use `.use()` for middleware that reacts to global options (logging setup, auth, state init) — it runs before any command action
|
|
65
|
+
12. Place `.use()` after the `.option()` calls it depends on — type safety is positional in the chain
|
|
66
|
+
|
|
67
|
+
## Schema-based options
|
|
68
|
+
|
|
69
|
+
Pass a Standard Schema (Zod, Valibot, ArkType) as the second argument to `.option()` for automatic type coercion. Description, default, and deprecated flag are extracted from the schema.
|
|
70
|
+
|
|
71
|
+
### Typed values
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
// number — string "3000" coerced to number 3000
|
|
75
|
+
.option('--port <port>', z.number().describe('Port number'))
|
|
76
|
+
|
|
77
|
+
// integer — rejects decimals like "3.14"
|
|
78
|
+
.option('--workers <n>', z.int().describe('Number of worker threads'))
|
|
79
|
+
|
|
80
|
+
// string — preserves value as-is (no auto-conversion)
|
|
81
|
+
.option('--name <name>', z.string().describe('Project name'))
|
|
82
|
+
|
|
83
|
+
// boolean value option — accepts "true" or "false" strings
|
|
84
|
+
.option('--flag <flag>', z.boolean().describe('Enable feature'))
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Default values
|
|
88
|
+
|
|
89
|
+
Use `.default()` on the schema. The default is shown in help output automatically.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
// Port defaults to 3000 if not passed
|
|
93
|
+
.option('--port [port]', z.number().default(3000).describe('Port to listen on'))
|
|
94
|
+
|
|
95
|
+
// Host defaults to "localhost"
|
|
96
|
+
.option('--host [host]', z.string().default('localhost').describe('Hostname to bind'))
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Important:** use `[optional]` brackets when the option has a default — `<required>` brackets throw an error when the value is missing, even if a default exists.
|
|
100
|
+
|
|
101
|
+
Help output for the above:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
--port [port] Port to listen on (default: 3000)
|
|
105
|
+
--host [host] Hostname to bind (default: localhost)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The `(default: 3000)` is appended automatically. Never write `.default(3000).describe('Port to listen on (default: 3000)')` — this would display the default twice.
|
|
109
|
+
|
|
110
|
+
### Enum options (constrained values)
|
|
111
|
+
|
|
112
|
+
Use `z.enum()` for options that only accept specific values:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
.option('--format <format>', z.enum(['json', 'yaml', 'csv']).describe('Output format'))
|
|
116
|
+
.option('--env <env>', z.enum(['dev', 'staging', 'production']).describe('Target environment'))
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Invalid values throw a clear error: `expected one of "json", "yaml", "csv", got "xml"`.
|
|
120
|
+
|
|
121
|
+
### Repeatable options (arrays)
|
|
122
|
+
|
|
123
|
+
Use `z.array()` to allow passing the same flag multiple times:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
// Pass --tag multiple times: --tag foo --tag bar → ["foo", "bar"]
|
|
127
|
+
.option('--tag <tag>', z.array(z.string()).describe('Tags (repeatable)'))
|
|
128
|
+
|
|
129
|
+
// Typed array items: --id 1 --id 2 → [1, 2] (numbers, not strings)
|
|
130
|
+
.option('--id <id>', z.array(z.number()).describe('IDs (repeatable)'))
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The optimal way for users to pass array values is repeating the flag:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
mycli deploy --tag v2.1.0 --tag latest --tag rollback
|
|
137
|
+
# → tags: ["v2.1.0", "latest", "rollback"]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
A single value is automatically wrapped: `--tag foo` → `["foo"]`.
|
|
141
|
+
|
|
142
|
+
JSON array strings also work but are less ergonomic: `--ids '[1,2,3]'` → `[1, 2, 3]`.
|
|
143
|
+
|
|
144
|
+
**Non-array schemas reject repeated flags.** If a user passes `--port 3000 --port 4000` with a `z.number()` schema, goke throws `does not accept multiple values`.
|
|
145
|
+
|
|
146
|
+
### Nullable options
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
// Pass empty string "" to get null, or a number
|
|
150
|
+
.option('--timeout <timeout>', z.nullable(z.number()).describe('Timeout in ms, empty for none'))
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Union types
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
// Tries number first, falls back to string
|
|
157
|
+
.option('--val <val>', z.union([z.number(), z.string()]).describe('A number or string value'))
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Deprecated options (hidden from help)
|
|
161
|
+
|
|
162
|
+
Use `.meta({ deprecated: true })` to hide options from `--help` while still parsing them:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
.option('--old-port <port>', z.number().meta({ deprecated: true, description: 'Use --port instead' }))
|
|
166
|
+
.option('--port <port>', z.number().describe('Port number'))
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### No schema = raw strings
|
|
170
|
+
|
|
171
|
+
Without a schema, all values stay as strings. `--port 3000` → `"3000"` (string, not number). Use schemas for type safety.
|
|
172
|
+
|
|
173
|
+
## Brackets
|
|
174
|
+
|
|
175
|
+
| Syntax | Meaning |
|
|
176
|
+
|--------|---------|
|
|
177
|
+
| `<name>` in command | Required argument |
|
|
178
|
+
| `[name]` in command | Optional argument |
|
|
179
|
+
| `[...files]` in command | Variadic (collects remaining args into array) |
|
|
180
|
+
| `<value>` in option | Required value (error if missing) |
|
|
181
|
+
| `[value]` in option | Optional value (`undefined` if flag present without value) |
|
|
182
|
+
| no brackets in option | Boolean flag (`undefined` if not passed, `true` if passed) |
|
|
183
|
+
|
|
184
|
+
**Optionality is determined solely by bracket syntax, not by the schema.** `[square brackets]` makes an option optional regardless of whether the schema is `z.string()` or `z.string().optional()`. The schema's `.optional()` is never consulted for this — it only affects type coercion. So `z.string()` with `[--name]` is treated as optional: if the flag is omitted, `options.name` is `undefined` even though the schema has no `.optional()`.
|
|
185
|
+
|
|
186
|
+
## Global Options and Middleware
|
|
187
|
+
|
|
188
|
+
Global options apply to all commands. Use `.use()` to register middleware that runs before any command action — for reacting to global options (logging, state init, auth).
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
const cli = goke('mycli')
|
|
192
|
+
|
|
193
|
+
cli
|
|
194
|
+
.option('--verbose', z.boolean().default(false).describe('Enable verbose logging'))
|
|
195
|
+
.option('--api-url [url]', z.string().default('https://api.example.com').describe('API base URL'))
|
|
196
|
+
.use((options) => {
|
|
197
|
+
// options.verbose: boolean, options.apiUrl: string — fully typed
|
|
198
|
+
if (options.verbose) {
|
|
199
|
+
process.env.LOG_LEVEL = 'debug'
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
cli
|
|
204
|
+
.command('deploy <env>', 'Deploy to environment')
|
|
205
|
+
.action((env, options) => {
|
|
206
|
+
// options includes global options (verbose, apiUrl) + command options
|
|
207
|
+
console.log(`Deploying to ${env} via ${options.apiUrl}`)
|
|
208
|
+
})
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Middleware runs in registration order, after parsing/validation, before the command action. Type safety is positional — each `.use()` only sees options declared before it in the chain:
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
cli
|
|
215
|
+
.option('--verbose', z.boolean().default(false).describe('Verbose'))
|
|
216
|
+
.use((options) => {
|
|
217
|
+
options.verbose // boolean — typed
|
|
218
|
+
options.port // TypeScript error — not declared yet
|
|
219
|
+
})
|
|
220
|
+
.option('--port <port>', z.number().describe('Port'))
|
|
221
|
+
.use((options) => {
|
|
222
|
+
options.verbose // boolean — still visible
|
|
223
|
+
options.port // number — now visible
|
|
224
|
+
})
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Async middleware is supported — the chain awaits each middleware before proceeding:
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
cli
|
|
231
|
+
.option('--token <token>', z.string().describe('API token'))
|
|
232
|
+
.use(async (options) => {
|
|
233
|
+
globalState.client = await connectToApi(options.token)
|
|
234
|
+
})
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Commands
|
|
238
|
+
|
|
239
|
+
### Basic commands with arguments
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
cli
|
|
243
|
+
.command('deploy <env>', 'Deploy to an environment')
|
|
244
|
+
.option('--dry-run', 'Preview without deploying')
|
|
245
|
+
.action((env, options) => {
|
|
246
|
+
// env: string, options.dryRun: boolean
|
|
247
|
+
})
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Root command (runs when no subcommand given)
|
|
251
|
+
|
|
252
|
+
Use empty string `''` as the command name:
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
// `mycli` runs the root command, `mycli status` runs the subcommand
|
|
256
|
+
cli
|
|
257
|
+
.command('', 'Deploy the current project')
|
|
258
|
+
.option('--env <env>', z.string().default('production').describe('Target environment'))
|
|
259
|
+
.action((options) => {})
|
|
260
|
+
|
|
261
|
+
cli.command('status', 'Show deployment status').action(() => {})
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Space-separated subcommands
|
|
265
|
+
|
|
266
|
+
For git-like nested commands:
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
cli.command('mcp login <url>', 'Login to MCP server').action((url) => {})
|
|
270
|
+
cli.command('mcp logout', 'Logout from MCP server').action(() => {})
|
|
271
|
+
cli.command('git remote add <name> <url>', 'Add a git remote').action((name, url) => {})
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Greedy matching: `mcp login` matches before `mcp` when both exist.
|
|
275
|
+
|
|
276
|
+
### Variadic arguments
|
|
277
|
+
|
|
278
|
+
The last argument can be variadic with `...` prefix:
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
cli
|
|
282
|
+
.command('build <entry> [...otherFiles]', 'Build your app')
|
|
283
|
+
.action((entry, otherFiles, options) => {
|
|
284
|
+
// entry: string, otherFiles: string[]
|
|
285
|
+
})
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Command aliases
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
cli.command('install', 'Install packages').alias('i').action(() => {})
|
|
292
|
+
// Now both `mycli install` and `mycli i` work
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Double-dash `--` (end of options)
|
|
296
|
+
|
|
297
|
+
`--` signals end of options. Everything after it goes into `options['--']` as a separate array, not mixed into positional args. This lets you distinguish command args from passthrough args.
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
cli
|
|
301
|
+
.command('run <script>', 'Run a script with injected env vars')
|
|
302
|
+
.option('--env <env>', z.enum(['dev', 'staging', 'production']).describe('Target environment'))
|
|
303
|
+
.action((script, options) => {
|
|
304
|
+
// runner run --env staging server.js -- --port 3000
|
|
305
|
+
// script = 'server.js'
|
|
306
|
+
// options['--'] = ['--port', '3000']
|
|
307
|
+
const extra = (options['--'] || []).join(' ')
|
|
308
|
+
execSync(`node ${script} ${extra}`, { env: { ...process.env, ...loadSecrets(options.env) } })
|
|
309
|
+
})
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Writing detailed help text
|
|
313
|
+
|
|
314
|
+
Agents and users rely on `--help` as the primary documentation for a CLI. Write descriptions that are thorough and actionable.
|
|
315
|
+
|
|
316
|
+
### Detailed command descriptions
|
|
317
|
+
|
|
318
|
+
Use `string-dedent` for multi-line descriptions:
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
import dedent from 'string-dedent'
|
|
322
|
+
|
|
323
|
+
cli
|
|
324
|
+
.command(
|
|
325
|
+
'release <version>',
|
|
326
|
+
dedent`
|
|
327
|
+
Publish a versioned release to distribution channels.
|
|
328
|
+
|
|
329
|
+
- Validates release metadata and changelog before publishing.
|
|
330
|
+
- Builds production artifacts with reproducible settings.
|
|
331
|
+
- Tags git history using semantic version format.
|
|
332
|
+
- Publishes to npm and creates release notes.
|
|
333
|
+
|
|
334
|
+
> Recommended: run with --dry-run first in CI to verify output.
|
|
335
|
+
`,
|
|
336
|
+
)
|
|
337
|
+
.option('--channel <name>', z.enum(['stable', 'beta', 'alpha']).describe('Target release channel'))
|
|
338
|
+
.option('--dry-run', 'Preview every step without publishing')
|
|
339
|
+
.action((version, options) => {})
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Detailed option descriptions
|
|
343
|
+
|
|
344
|
+
Write descriptions that tell the user exactly what the option does:
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
// Bad — too terse
|
|
348
|
+
.option('--limit [limit]', z.number().default(10).describe('Limit'))
|
|
349
|
+
|
|
350
|
+
// Good — tells what it does, what values are valid
|
|
351
|
+
.option('--limit [limit]', z.number().default(10).describe('Maximum number of results to return'))
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Examples in help output
|
|
355
|
+
|
|
356
|
+
Add `.example()` to commands. Use `#` comments to explain the scenario:
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
cli
|
|
360
|
+
.command('deploy', 'Deploy current app')
|
|
361
|
+
.option('--env <env>', z.enum(['staging', 'production']).describe('Target environment'))
|
|
362
|
+
.example('# Deploy to staging first')
|
|
363
|
+
.example('mycli deploy --env staging')
|
|
364
|
+
.example('# Then deploy to production')
|
|
365
|
+
.example('mycli deploy --env production')
|
|
366
|
+
.action(() => {})
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Root-level examples:
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
cli.example((bin) => `${bin} deploy --env production`)
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Boolean flags
|
|
376
|
+
|
|
377
|
+
Options without brackets are boolean flags. They default to `undefined` (not `false`), so you can distinguish between "not passed" and "explicitly set":
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
.option('--verbose', 'Enable verbose output')
|
|
381
|
+
.option('--no-cache', 'Disable caching')
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
| Input | `options.verbose` | `options.cache` |
|
|
385
|
+
|-------|-------------------|-----------------|
|
|
386
|
+
| *(not passed)* | `undefined` | `undefined` |
|
|
387
|
+
| `--verbose` | `true` | — |
|
|
388
|
+
| `--no-verbose` | `false` | — |
|
|
389
|
+
| `--no-cache` | — | `false` |
|
|
390
|
+
|
|
391
|
+
This lets you apply defaults or merge configs only when the user didn't explicitly set a flag:
|
|
392
|
+
|
|
393
|
+
```ts
|
|
394
|
+
.action((options) => {
|
|
395
|
+
// undefined means "user didn't say" — apply your own default
|
|
396
|
+
const verbose = options.verbose ?? config.verbose ?? false
|
|
397
|
+
})
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
## Dot-nested options
|
|
401
|
+
|
|
402
|
+
```ts
|
|
403
|
+
cli.option('--env <env>', 'Set envs')
|
|
404
|
+
// --env.API_SECRET xxx → options.env = { API_SECRET: 'xxx' }
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Short aliases
|
|
408
|
+
|
|
409
|
+
```ts
|
|
410
|
+
.option('-p, --port <port>', z.number().describe('Port number'))
|
|
411
|
+
// -p 3000 and --port 3000 both work
|
|
412
|
+
// options.port and options.p both equal 3000
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Interactive prompts with @clack/prompts
|
|
416
|
+
|
|
417
|
+
For commands that need user input (login, setup, init), use `@clack/prompts` for select menus, password inputs, and text prompts. **Every interactive input must also be available as a CLI option** so agents and CI can use the command non-interactively.
|
|
418
|
+
|
|
419
|
+
The pattern: check if flags are present — if yes, use them directly. If no flags, fall back to interactive prompts.
|
|
420
|
+
|
|
421
|
+
```ts
|
|
422
|
+
import { select, password, isCancel, cancel } from '@clack/prompts'
|
|
423
|
+
|
|
424
|
+
cli
|
|
425
|
+
.command('login', 'Configure API keys interactively or via flags')
|
|
426
|
+
.option('-p, --provider [name]', z.string().describe('Provider for non-interactive login (google, openai)'))
|
|
427
|
+
.option('-k, --key [key]', z.string().describe('API key for non-interactive login'))
|
|
428
|
+
.action(async (options) => {
|
|
429
|
+
// Non-interactive path (agents, CI)
|
|
430
|
+
if (options.provider) {
|
|
431
|
+
saveKey(options.provider, options.key || await readKeyFromStdin())
|
|
432
|
+
return
|
|
433
|
+
}
|
|
434
|
+
// Interactive path (humans)
|
|
435
|
+
// NEVER use hint in clack select options. looks ugly
|
|
436
|
+
const provider = await select({ message: 'Select provider', options: [...] })
|
|
437
|
+
if (isCancel(provider)) { cancel(); process.exit(0) }
|
|
438
|
+
const key = await password({ message: 'Paste API key' })
|
|
439
|
+
if (isCancel(key)) { cancel(); process.exit(0) }
|
|
440
|
+
saveKey(provider, key.trim())
|
|
441
|
+
})
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## Programmatic help text
|
|
445
|
+
|
|
446
|
+
`cli.helpText()` returns the formatted help string without printing it. Useful for embedding help text in docs, READMEs, or other programmatic uses:
|
|
447
|
+
|
|
448
|
+
```ts
|
|
449
|
+
const cli = goke('mycli')
|
|
450
|
+
cli.command('build', 'Build project')
|
|
451
|
+
cli.option('--watch', 'Watch mode')
|
|
452
|
+
cli.help()
|
|
453
|
+
|
|
454
|
+
const help = cli.helpText()
|
|
455
|
+
// => "mycli\n\nUsage:\n $ mycli ..."
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
The string includes ANSI color codes (same as `--help` output). Strip them if you need plain text.
|
|
459
|
+
|
|
460
|
+
`cli.outputHelp()` still exists and prints to stdout — it calls `helpText()` internally.
|
|
461
|
+
|
|
462
|
+
## Injectable I/O (testing)
|
|
463
|
+
|
|
464
|
+
Override stdout, stderr, argv, and exit for testing:
|
|
465
|
+
|
|
466
|
+
```ts
|
|
467
|
+
import goke, { createConsole } from 'goke'
|
|
468
|
+
|
|
469
|
+
const stdout = { lines: [], write(data) { this.lines.push(data) } }
|
|
470
|
+
const cli = goke('mycli', {
|
|
471
|
+
stdout,
|
|
472
|
+
stderr: process.stderr,
|
|
473
|
+
exit: () => {}, // prevent process.exit in tests
|
|
474
|
+
})
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
## @goke/mcp — MCP ↔ CLI bridge
|
|
478
|
+
|
|
479
|
+
### MCP server → CLI
|
|
480
|
+
|
|
481
|
+
`addMcpCommands` auto-discovers tools from an MCP server and registers them as CLI commands with typed options from JSON Schema:
|
|
482
|
+
|
|
483
|
+
```ts
|
|
484
|
+
import { goke } from 'goke'
|
|
485
|
+
import { addMcpCommands } from '@goke/mcp'
|
|
486
|
+
|
|
487
|
+
const cli = goke('mycli')
|
|
488
|
+
|
|
489
|
+
await addMcpCommands({
|
|
490
|
+
cli,
|
|
491
|
+
getMcpUrl: () => 'https://your-mcp-server.com/mcp',
|
|
492
|
+
oauth: {
|
|
493
|
+
clientName: 'My CLI',
|
|
494
|
+
load: () => loadConfig().oauthState,
|
|
495
|
+
save: (state) => saveConfig({ oauthState: state }),
|
|
496
|
+
},
|
|
497
|
+
loadCache: () => loadConfig().cache,
|
|
498
|
+
saveCache: (cache) => saveConfig({ cache }),
|
|
499
|
+
})
|
|
500
|
+
|
|
501
|
+
cli.help()
|
|
502
|
+
cli.parse()
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
Tools are cached for 1 hour. OAuth is lazy — triggered only on 401 errors.
|
|
506
|
+
|
|
507
|
+
### CLI → MCP server
|
|
508
|
+
|
|
509
|
+
`createMcpAction` turns a CLI into a stdio MCP server. Every command becomes an MCP tool. The MCP command itself is auto-excluded from the tool list.
|
|
510
|
+
|
|
511
|
+
```ts
|
|
512
|
+
import { goke } from 'goke'
|
|
513
|
+
import { z } from 'zod'
|
|
514
|
+
import { createMcpAction } from '@goke/mcp'
|
|
515
|
+
|
|
516
|
+
const cli = goke('mycli')
|
|
517
|
+
|
|
518
|
+
cli
|
|
519
|
+
.command('search', 'Search pages')
|
|
520
|
+
.option('--query <query>', z.string().describe('Search query'))
|
|
521
|
+
.action((options) => findPages(options.query))
|
|
522
|
+
|
|
523
|
+
cli.command('mcp', 'Start MCP server over stdio')
|
|
524
|
+
.action(createMcpAction({ cli }))
|
|
525
|
+
|
|
526
|
+
cli.help()
|
|
527
|
+
cli.parse()
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
Options: `commandFilter`, `sanitizeToolName`, `serverName`, `serverVersion`, `createTransport`.
|
|
531
|
+
|
|
532
|
+
### Installing an MCP server in clients
|
|
533
|
+
|
|
534
|
+
Users can install any CLI that exposes an `mcp` command using [@playwriter/install-mcp](https://github.com/nicepkg/install-mcp) — a cross-platform tool that handles config file locations for every major MCP client:
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
npx @playwriter/install-mcp mycli --client claude-desktop
|
|
538
|
+
npx @playwriter/install-mcp mycli --client cursor
|
|
539
|
+
npx @playwriter/install-mcp mycli --client vscode
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
Supports `claude-desktop`, `cursor`, `vscode`, `windsurf`, `claude-code`, `opencode`, `zed`, `goose`, `cline`, `codex`, `gemini-cli`, and more. For custom arguments: `npx @playwriter/install-mcp 'npx mycli mcp' --client cursor`.
|
|
543
|
+
|
|
544
|
+
## Complete example
|
|
545
|
+
|
|
546
|
+
```ts
|
|
547
|
+
import { goke } from 'goke'
|
|
548
|
+
import { z } from 'zod'
|
|
549
|
+
import dedent from 'string-dedent'
|
|
550
|
+
|
|
551
|
+
const cli = goke('acme')
|
|
552
|
+
|
|
553
|
+
cli
|
|
554
|
+
.command('', 'Run the default workflow')
|
|
555
|
+
.option('--env [env]', z.string().default('development').describe('Target environment'))
|
|
556
|
+
.action((options) => {
|
|
557
|
+
console.log(`Running in ${options.env}`)
|
|
558
|
+
})
|
|
559
|
+
|
|
560
|
+
cli
|
|
561
|
+
.command(
|
|
562
|
+
'deploy <target>',
|
|
563
|
+
dedent`
|
|
564
|
+
Deploy the application to a target environment.
|
|
565
|
+
|
|
566
|
+
- Builds optimized production bundle.
|
|
567
|
+
- Uploads artifacts to the target.
|
|
568
|
+
- Runs post-deploy health checks.
|
|
569
|
+
|
|
570
|
+
> Always deploy to staging first before production.
|
|
571
|
+
`,
|
|
572
|
+
)
|
|
573
|
+
.option('--env <env>', z.enum(['staging', 'production']).describe('Deployment environment'))
|
|
574
|
+
.option('--tag <tag>', z.array(z.string()).describe('Docker image tags to deploy (repeatable)'))
|
|
575
|
+
.option('--workers <n>', z.int().default(4).describe('Number of parallel upload workers'))
|
|
576
|
+
.option('--timeout [ms]', z.number().default(30000).describe('Deployment timeout in milliseconds'))
|
|
577
|
+
.option('--dry-run', 'Preview the deployment plan without executing')
|
|
578
|
+
.option('--verbose', 'Enable detailed deployment logging')
|
|
579
|
+
.example('# Deploy to staging with custom tags')
|
|
580
|
+
.example('acme deploy web --env staging --tag v2.1.0 --tag latest')
|
|
581
|
+
.example('# Dry-run production deploy')
|
|
582
|
+
.example('acme deploy api --env production --dry-run --verbose')
|
|
583
|
+
.action((target, options) => {
|
|
584
|
+
console.log('deploying', target, options)
|
|
585
|
+
})
|
|
586
|
+
|
|
587
|
+
cli
|
|
588
|
+
.command('db migrate', 'Apply pending database migrations in sequence')
|
|
589
|
+
.option('--target <migration>', z.string().describe('Apply up to a specific migration ID'))
|
|
590
|
+
.option('--dry-run', 'Print SQL plan without executing')
|
|
591
|
+
.option('--verbose', 'Show each executed SQL statement')
|
|
592
|
+
.action((options) => {
|
|
593
|
+
console.log('migrating', options)
|
|
594
|
+
})
|
|
595
|
+
|
|
596
|
+
cli
|
|
597
|
+
.command('config set <key> <value>', 'Set a configuration value')
|
|
598
|
+
.action((key, value) => {
|
|
599
|
+
console.log('setting', key, value)
|
|
600
|
+
})
|
|
601
|
+
|
|
602
|
+
cli.help()
|
|
603
|
+
cli.version('1.0.0')
|
|
604
|
+
cli.parse()
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
## `openInBrowser(url)`
|
|
608
|
+
|
|
609
|
+
Opens a URL in the default browser. In non-TTY environments (CI, piped output, agents), prints the URL to stdout instead of opening a browser.
|
|
610
|
+
|
|
611
|
+
```ts
|
|
612
|
+
import { openInBrowser } from 'goke'
|
|
613
|
+
|
|
614
|
+
openInBrowser('https://example.com/dashboard')
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
Use this after generating URLs (OAuth callbacks, dashboards, docs links) so interactive users get a browser tab and non-interactive environments get a printable URL.
|
|
618
|
+
|
|
619
|
+
## Exposing your CLI as a skill
|
|
620
|
+
|
|
621
|
+
When you build a CLI with goke, the optimal way to create a skill for it is a minimal SKILL.md that tells agents to run `--help` before using the CLI. This way descriptions, examples, and usage patterns live in the CLI code (collocated with the implementation) instead of a separate markdown file that can go stale.
|
|
622
|
+
|
|
623
|
+
Example SKILL.md for a CLI built with goke:
|
|
624
|
+
|
|
625
|
+
````markdown
|
|
626
|
+
---
|
|
627
|
+
name: acme
|
|
628
|
+
description: >
|
|
629
|
+
acme is a deployment CLI. Always run `acme --help` before using it
|
|
630
|
+
to discover available commands, options, and usage examples.
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
# acme
|
|
634
|
+
|
|
635
|
+
Always run `acme --help` before using this CLI. The help output contains
|
|
636
|
+
all commands, options, defaults, and usage examples.
|
|
637
|
+
|
|
638
|
+
For subcommand details: `acme <command> --help`
|
|
639
|
+
````
|
|
640
|
+
|
|
641
|
+
This is the recommended pattern because:
|
|
642
|
+
- Descriptions and examples are defined once in `.option()` and `.example()` calls
|
|
643
|
+
- Help output always matches the actual CLI behavior
|
|
644
|
+
- No separate documentation to maintain or keep in sync
|