opencode-v2 1.1.53
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/AGENTS.md +27 -0
- package/Dockerfile +18 -0
- package/README.md +15 -0
- package/bin/opencode +84 -0
- package/bunfig.toml +5 -0
- package/package.json +126 -0
- package/parsers-config.ts +253 -0
- package/script/build.ts +193 -0
- package/script/postinstall.mjs +125 -0
- package/script/publish.ts +181 -0
- package/script/schema.ts +47 -0
- package/script/seed-e2e.ts +50 -0
- package/src/acp/README.md +164 -0
- package/src/acp/agent.ts +1676 -0
- package/src/acp/session.ts +117 -0
- package/src/acp/types.ts +23 -0
- package/src/agent/agent.ts +414 -0
- package/src/agent/generate.txt +75 -0
- package/src/agent/prompt/compaction.txt +12 -0
- package/src/agent/prompt/explore.txt +18 -0
- package/src/agent/prompt/summary.txt +11 -0
- package/src/agent/prompt/title.txt +44 -0
- package/src/auth/index.ts +70 -0
- package/src/bun/index.ts +137 -0
- package/src/bun/registry.ts +48 -0
- package/src/bus/bus-event.ts +43 -0
- package/src/bus/global.ts +10 -0
- package/src/bus/index.ts +105 -0
- package/src/cli/bootstrap.ts +17 -0
- package/src/cli/cmd/acp.ts +70 -0
- package/src/cli/cmd/agent.ts +257 -0
- package/src/cli/cmd/auth.ts +400 -0
- package/src/cli/cmd/cmd.ts +7 -0
- package/src/cli/cmd/debug/agent.ts +167 -0
- package/src/cli/cmd/debug/config.ts +16 -0
- package/src/cli/cmd/debug/file.ts +97 -0
- package/src/cli/cmd/debug/index.ts +48 -0
- package/src/cli/cmd/debug/lsp.ts +52 -0
- package/src/cli/cmd/debug/ripgrep.ts +87 -0
- package/src/cli/cmd/debug/scrap.ts +16 -0
- package/src/cli/cmd/debug/skill.ts +16 -0
- package/src/cli/cmd/debug/snapshot.ts +52 -0
- package/src/cli/cmd/export.ts +88 -0
- package/src/cli/cmd/generate.ts +38 -0
- package/src/cli/cmd/github.ts +1540 -0
- package/src/cli/cmd/import.ts +147 -0
- package/src/cli/cmd/mcp.ts +755 -0
- package/src/cli/cmd/models.ts +77 -0
- package/src/cli/cmd/pr.ts +112 -0
- package/src/cli/cmd/run.ts +617 -0
- package/src/cli/cmd/serve.ts +20 -0
- package/src/cli/cmd/session.ts +135 -0
- package/src/cli/cmd/stats.ts +426 -0
- package/src/cli/cmd/tui/app.tsx +801 -0
- package/src/cli/cmd/tui/attach.ts +52 -0
- package/src/cli/cmd/tui/component/border.tsx +21 -0
- package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-command.tsx +148 -0
- package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-model.tsx +234 -0
- package/src/cli/cmd/tui/component/dialog-provider.tsx +266 -0
- package/src/cli/cmd/tui/component/dialog-session-list.tsx +108 -0
- package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-skill.tsx +36 -0
- package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
- package/src/cli/cmd/tui/component/dialog-status.tsx +177 -0
- package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
- package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
- package/src/cli/cmd/tui/component/logo.tsx +85 -0
- package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +666 -0
- package/src/cli/cmd/tui/component/prompt/frecency.tsx +89 -0
- package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
- package/src/cli/cmd/tui/component/prompt/index.tsx +1132 -0
- package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
- package/src/cli/cmd/tui/component/spinner.tsx +24 -0
- package/src/cli/cmd/tui/component/textarea-keybindings.ts +73 -0
- package/src/cli/cmd/tui/component/tips.tsx +153 -0
- package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
- package/src/cli/cmd/tui/context/args.tsx +15 -0
- package/src/cli/cmd/tui/context/directory.ts +13 -0
- package/src/cli/cmd/tui/context/exit.tsx +52 -0
- package/src/cli/cmd/tui/context/helper.tsx +25 -0
- package/src/cli/cmd/tui/context/keybind.tsx +100 -0
- package/src/cli/cmd/tui/context/kv.tsx +52 -0
- package/src/cli/cmd/tui/context/local.tsx +409 -0
- package/src/cli/cmd/tui/context/prompt.tsx +18 -0
- package/src/cli/cmd/tui/context/route.tsx +46 -0
- package/src/cli/cmd/tui/context/sdk.tsx +101 -0
- package/src/cli/cmd/tui/context/sync.tsx +470 -0
- package/src/cli/cmd/tui/context/theme/aura.json +69 -0
- package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
- package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
- package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
- package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
- package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
- package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
- package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
- package/src/cli/cmd/tui/context/theme/github.json +233 -0
- package/src/cli/cmd/tui/context/theme/gruvbox.json +242 -0
- package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
- package/src/cli/cmd/tui/context/theme/lucent-orng.json +237 -0
- package/src/cli/cmd/tui/context/theme/material.json +235 -0
- package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
- package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
- package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
- package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
- package/src/cli/cmd/tui/context/theme/nord.json +223 -0
- package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
- package/src/cli/cmd/tui/context/theme/orng.json +249 -0
- package/src/cli/cmd/tui/context/theme/osaka-jade.json +93 -0
- package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
- package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
- package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
- package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
- package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
- package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
- package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
- package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
- package/src/cli/cmd/tui/context/theme.tsx +1152 -0
- package/src/cli/cmd/tui/event.ts +48 -0
- package/src/cli/cmd/tui/routes/home.tsx +140 -0
- package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +64 -0
- package/src/cli/cmd/tui/routes/session/dialog-message.tsx +109 -0
- package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
- package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
- package/src/cli/cmd/tui/routes/session/footer.tsx +91 -0
- package/src/cli/cmd/tui/routes/session/header.tsx +142 -0
- package/src/cli/cmd/tui/routes/session/index.tsx +2126 -0
- package/src/cli/cmd/tui/routes/session/permission.tsx +508 -0
- package/src/cli/cmd/tui/routes/session/question.tsx +466 -0
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +313 -0
- package/src/cli/cmd/tui/thread.ts +175 -0
- package/src/cli/cmd/tui/ui/dialog-alert.tsx +68 -0
- package/src/cli/cmd/tui/ui/dialog-confirm.tsx +93 -0
- package/src/cli/cmd/tui/ui/dialog-export-options.tsx +215 -0
- package/src/cli/cmd/tui/ui/dialog-help.tsx +49 -0
- package/src/cli/cmd/tui/ui/dialog-prompt.tsx +88 -0
- package/src/cli/cmd/tui/ui/dialog-select.tsx +399 -0
- package/src/cli/cmd/tui/ui/dialog.tsx +167 -0
- package/src/cli/cmd/tui/ui/link.tsx +28 -0
- package/src/cli/cmd/tui/ui/spinner.ts +368 -0
- package/src/cli/cmd/tui/ui/toast.tsx +100 -0
- package/src/cli/cmd/tui/util/clipboard.ts +159 -0
- package/src/cli/cmd/tui/util/editor.ts +32 -0
- package/src/cli/cmd/tui/util/signal.ts +7 -0
- package/src/cli/cmd/tui/util/terminal.ts +114 -0
- package/src/cli/cmd/tui/util/transcript.ts +98 -0
- package/src/cli/cmd/tui/worker.ts +152 -0
- package/src/cli/cmd/uninstall.ts +357 -0
- package/src/cli/cmd/upgrade.ts +73 -0
- package/src/cli/cmd/web.ts +81 -0
- package/src/cli/error.ts +57 -0
- package/src/cli/logo.ts +6 -0
- package/src/cli/network.ts +60 -0
- package/src/cli/ui.ts +113 -0
- package/src/cli/upgrade.ts +25 -0
- package/src/command/index.ts +150 -0
- package/src/command/template/initialize.txt +10 -0
- package/src/command/template/review.txt +99 -0
- package/src/config/config.ts +1477 -0
- package/src/config/markdown.ts +98 -0
- package/src/env/index.ts +28 -0
- package/src/file/ignore.ts +83 -0
- package/src/file/index.ts +583 -0
- package/src/file/ripgrep.ts +375 -0
- package/src/file/time.ts +69 -0
- package/src/file/watcher.ts +127 -0
- package/src/flag/flag.ts +97 -0
- package/src/format/formatter.ts +366 -0
- package/src/format/index.ts +137 -0
- package/src/global/index.ts +55 -0
- package/src/id/id.ts +83 -0
- package/src/ide/index.ts +76 -0
- package/src/index.ts +159 -0
- package/src/installation/index.ts +246 -0
- package/src/lsp/client.ts +252 -0
- package/src/lsp/index.ts +485 -0
- package/src/lsp/language.ts +119 -0
- package/src/lsp/server.ts +2046 -0
- package/src/mcp/auth.ts +132 -0
- package/src/mcp/index.ts +934 -0
- package/src/mcp/oauth-callback.ts +200 -0
- package/src/mcp/oauth-provider.ts +154 -0
- package/src/patch/index.ts +680 -0
- package/src/permission/arity.ts +163 -0
- package/src/permission/index.ts +210 -0
- package/src/permission/next.ts +280 -0
- package/src/plugin/codex.ts +624 -0
- package/src/plugin/copilot.ts +327 -0
- package/src/plugin/index.ts +138 -0
- package/src/project/bootstrap.ts +35 -0
- package/src/project/instance.ts +114 -0
- package/src/project/project.ts +371 -0
- package/src/project/state.ts +70 -0
- package/src/project/vcs.ts +76 -0
- package/src/provider/auth.ts +147 -0
- package/src/provider/models.ts +133 -0
- package/src/provider/provider.ts +1262 -0
- package/src/provider/sdk/copilot/README.md +5 -0
- package/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +164 -0
- package/src/provider/sdk/copilot/chat/get-response-metadata.ts +15 -0
- package/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +17 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts +64 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts +780 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts +28 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
- package/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts +87 -0
- package/src/provider/sdk/copilot/copilot-provider.ts +100 -0
- package/src/provider/sdk/copilot/index.ts +2 -0
- package/src/provider/sdk/copilot/openai-compatible-error.ts +27 -0
- package/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts +303 -0
- package/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts +22 -0
- package/src/provider/sdk/copilot/responses/openai-config.ts +18 -0
- package/src/provider/sdk/copilot/responses/openai-error.ts +22 -0
- package/src/provider/sdk/copilot/responses/openai-responses-api-types.ts +207 -0
- package/src/provider/sdk/copilot/responses/openai-responses-language-model.ts +1732 -0
- package/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts +177 -0
- package/src/provider/sdk/copilot/responses/openai-responses-settings.ts +1 -0
- package/src/provider/sdk/copilot/responses/tool/code-interpreter.ts +88 -0
- package/src/provider/sdk/copilot/responses/tool/file-search.ts +128 -0
- package/src/provider/sdk/copilot/responses/tool/image-generation.ts +115 -0
- package/src/provider/sdk/copilot/responses/tool/local-shell.ts +65 -0
- package/src/provider/sdk/copilot/responses/tool/web-search-preview.ts +104 -0
- package/src/provider/sdk/copilot/responses/tool/web-search.ts +103 -0
- package/src/provider/transform.ts +828 -0
- package/src/pty/index.ts +250 -0
- package/src/question/index.ts +171 -0
- package/src/scheduler/index.ts +61 -0
- package/src/server/error.ts +36 -0
- package/src/server/event.ts +7 -0
- package/src/server/mdns.ts +60 -0
- package/src/server/routes/config.ts +92 -0
- package/src/server/routes/experimental.ts +208 -0
- package/src/server/routes/file.ts +197 -0
- package/src/server/routes/global.ts +183 -0
- package/src/server/routes/mcp.ts +225 -0
- package/src/server/routes/permission.ts +68 -0
- package/src/server/routes/project.ts +82 -0
- package/src/server/routes/provider.ts +165 -0
- package/src/server/routes/pty.ts +169 -0
- package/src/server/routes/question.ts +98 -0
- package/src/server/routes/session.ts +939 -0
- package/src/server/routes/tui.ts +379 -0
- package/src/server/server.ts +613 -0
- package/src/session/compaction.ts +226 -0
- package/src/session/index.ts +524 -0
- package/src/session/instruction.ts +197 -0
- package/src/session/llm.ts +289 -0
- package/src/session/message-v2.ts +802 -0
- package/src/session/message.ts +189 -0
- package/src/session/processor.ts +407 -0
- package/src/session/prompt/agent.txt +43 -0
- package/src/session/prompt/anthropic-20250930.txt +166 -0
- package/src/session/prompt/anthropic.txt +105 -0
- package/src/session/prompt/beast.txt +147 -0
- package/src/session/prompt/build-switch.txt +5 -0
- package/src/session/prompt/codex_header.txt +79 -0
- package/src/session/prompt/copilot-gpt-5.txt +143 -0
- package/src/session/prompt/gemini.txt +155 -0
- package/src/session/prompt/max-steps.txt +16 -0
- package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
- package/src/session/prompt/plan.txt +26 -0
- package/src/session/prompt/qwen.txt +109 -0
- package/src/session/prompt/research.txt +81 -0
- package/src/session/prompt/trinity.txt +97 -0
- package/src/session/prompt.ts +1952 -0
- package/src/session/retry.ts +97 -0
- package/src/session/revert.ts +121 -0
- package/src/session/status.ts +76 -0
- package/src/session/summary.ts +217 -0
- package/src/session/system.ts +54 -0
- package/src/session/todo.ts +37 -0
- package/src/share/share-next.ts +200 -0
- package/src/share/share.ts +92 -0
- package/src/shell/shell.ts +67 -0
- package/src/skill/discovery.ts +97 -0
- package/src/skill/index.ts +1 -0
- package/src/skill/skill.ts +188 -0
- package/src/snapshot/index.ts +255 -0
- package/src/storage/storage.ts +227 -0
- package/src/tool/agent-enter.txt +1 -0
- package/src/tool/agent-exit.txt +1 -0
- package/src/tool/agent.ts +237 -0
- package/src/tool/apply_patch.ts +281 -0
- package/src/tool/apply_patch.txt +33 -0
- package/src/tool/bash.ts +269 -0
- package/src/tool/bash.txt +115 -0
- package/src/tool/batch.ts +175 -0
- package/src/tool/batch.txt +24 -0
- package/src/tool/chat-enter.txt +15 -0
- package/src/tool/chat-exit.txt +7 -0
- package/src/tool/chat.ts +217 -0
- package/src/tool/codesearch.ts +132 -0
- package/src/tool/codesearch.txt +12 -0
- package/src/tool/edit.ts +655 -0
- package/src/tool/edit.txt +10 -0
- package/src/tool/external-directory.ts +32 -0
- package/src/tool/glob.ts +78 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +147 -0
- package/src/tool/grep.txt +8 -0
- package/src/tool/invalid.ts +17 -0
- package/src/tool/ls.ts +121 -0
- package/src/tool/ls.txt +1 -0
- package/src/tool/lsp.ts +96 -0
- package/src/tool/lsp.txt +19 -0
- package/src/tool/multiedit.ts +46 -0
- package/src/tool/multiedit.txt +41 -0
- package/src/tool/plan-enter.txt +14 -0
- package/src/tool/plan-exit.txt +13 -0
- package/src/tool/plan.ts +130 -0
- package/src/tool/question.ts +33 -0
- package/src/tool/question.txt +10 -0
- package/src/tool/read.ts +211 -0
- package/src/tool/read.txt +12 -0
- package/src/tool/registry.ts +167 -0
- package/src/tool/research-enter.txt +1 -0
- package/src/tool/research-exit.txt +1 -0
- package/src/tool/research.ts +134 -0
- package/src/tool/skill.ts +123 -0
- package/src/tool/task.ts +165 -0
- package/src/tool/task.txt +60 -0
- package/src/tool/todo.ts +53 -0
- package/src/tool/todoread.txt +14 -0
- package/src/tool/todowrite.txt +167 -0
- package/src/tool/tool.ts +89 -0
- package/src/tool/truncation.ts +106 -0
- package/src/tool/webfetch.ts +186 -0
- package/src/tool/webfetch.txt +13 -0
- package/src/tool/websearch.ts +150 -0
- package/src/tool/websearch.txt +14 -0
- package/src/tool/write.ts +85 -0
- package/src/tool/write.txt +8 -0
- package/src/util/abort.ts +35 -0
- package/src/util/archive.ts +16 -0
- package/src/util/color.ts +19 -0
- package/src/util/context.ts +25 -0
- package/src/util/defer.ts +12 -0
- package/src/util/eventloop.ts +20 -0
- package/src/util/filesystem.ts +93 -0
- package/src/util/fn.ts +11 -0
- package/src/util/format.ts +20 -0
- package/src/util/iife.ts +3 -0
- package/src/util/keybind.ts +103 -0
- package/src/util/lazy.ts +18 -0
- package/src/util/locale.ts +81 -0
- package/src/util/lock.ts +98 -0
- package/src/util/log.ts +180 -0
- package/src/util/proxied.ts +3 -0
- package/src/util/queue.ts +32 -0
- package/src/util/rpc.ts +66 -0
- package/src/util/scrap.ts +10 -0
- package/src/util/signal.ts +12 -0
- package/src/util/timeout.ts +14 -0
- package/src/util/token.ts +7 -0
- package/src/util/wildcard.ts +56 -0
- package/src/worktree/index.ts +574 -0
- package/sst-env.d.ts +9 -0
- package/test/acp/agent-interface.test.ts +51 -0
- package/test/acp/event-subscription.test.ts +436 -0
- package/test/agent/agent.test.ts +675 -0
- package/test/bun.test.ts +53 -0
- package/test/cli/github-action.test.ts +161 -0
- package/test/cli/github-remote.test.ts +80 -0
- package/test/cli/import.test.ts +38 -0
- package/test/cli/tui/transcript.test.ts +322 -0
- package/test/config/agent-color.test.ts +71 -0
- package/test/config/config.test.ts +1802 -0
- package/test/config/fixtures/empty-frontmatter.md +4 -0
- package/test/config/fixtures/frontmatter.md +28 -0
- package/test/config/fixtures/markdown-header.md +11 -0
- package/test/config/fixtures/no-frontmatter.md +1 -0
- package/test/config/fixtures/weird-model-id.md +13 -0
- package/test/config/markdown.test.ts +228 -0
- package/test/file/ignore.test.ts +10 -0
- package/test/file/path-traversal.test.ts +198 -0
- package/test/file/ripgrep.test.ts +39 -0
- package/test/fixture/fixture.ts +45 -0
- package/test/fixture/lsp/fake-lsp-server.js +77 -0
- package/test/ide/ide.test.ts +82 -0
- package/test/keybind.test.ts +421 -0
- package/test/lsp/client.test.ts +95 -0
- package/test/mcp/headers.test.ts +153 -0
- package/test/mcp/oauth-browser.test.ts +249 -0
- package/test/memory/abort-leak.test.ts +136 -0
- package/test/patch/patch.test.ts +348 -0
- package/test/permission/arity.test.ts +33 -0
- package/test/permission/next.test.ts +690 -0
- package/test/permission-task.test.ts +319 -0
- package/test/plugin/auth-override.test.ts +44 -0
- package/test/plugin/codex.test.ts +123 -0
- package/test/preload.ts +63 -0
- package/test/project/project.test.ts +120 -0
- package/test/provider/amazon-bedrock.test.ts +445 -0
- package/test/provider/copilot/convert-to-copilot-messages.test.ts +523 -0
- package/test/provider/copilot/copilot-chat-model.test.ts +592 -0
- package/test/provider/gitlab-duo.test.ts +262 -0
- package/test/provider/provider.test.ts +2129 -0
- package/test/provider/transform.test.ts +2022 -0
- package/test/question/question.test.ts +300 -0
- package/test/scheduler.test.ts +73 -0
- package/test/server/session-list.test.ts +39 -0
- package/test/server/session-select.test.ts +78 -0
- package/test/session/compaction.test.ts +293 -0
- package/test/session/instruction.test.ts +170 -0
- package/test/session/llm.test.ts +691 -0
- package/test/session/message-v2.test.ts +786 -0
- package/test/session/prompt-missing-file.test.ts +53 -0
- package/test/session/prompt-special-chars.test.ts +56 -0
- package/test/session/prompt-variant.test.ts +60 -0
- package/test/session/retry.test.ts +179 -0
- package/test/session/revert-compact.test.ts +285 -0
- package/test/session/session.test.ts +71 -0
- package/test/skill/discovery.test.ts +60 -0
- package/test/skill/skill.test.ts +388 -0
- package/test/snapshot/snapshot.test.ts +1040 -0
- package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
- package/test/tool/apply_patch.test.ts +559 -0
- package/test/tool/bash.test.ts +399 -0
- package/test/tool/external-directory.test.ts +127 -0
- package/test/tool/fixtures/large-image.png +0 -0
- package/test/tool/fixtures/models-api.json +38413 -0
- package/test/tool/grep.test.ts +110 -0
- package/test/tool/question.test.ts +107 -0
- package/test/tool/read.test.ts +358 -0
- package/test/tool/registry.test.ts +122 -0
- package/test/tool/skill.test.ts +112 -0
- package/test/tool/truncation.test.ts +159 -0
- package/test/util/filesystem.test.ts +39 -0
- package/test/util/format.test.ts +59 -0
- package/test/util/iife.test.ts +36 -0
- package/test/util/lazy.test.ts +50 -0
- package/test/util/lock.test.ts +72 -0
- package/test/util/timeout.test.ts +21 -0
- package/test/util/wildcard.test.ts +75 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import { Session } from "../../src/session"
|
|
4
|
+
import { Bus } from "../../src/bus"
|
|
5
|
+
import { Log } from "../../src/util/log"
|
|
6
|
+
import { Instance } from "../../src/project/instance"
|
|
7
|
+
|
|
8
|
+
const projectRoot = path.join(__dirname, "../..")
|
|
9
|
+
Log.init({ print: false })
|
|
10
|
+
|
|
11
|
+
describe("session.started event", () => {
|
|
12
|
+
test("should emit session.started event when session is created", async () => {
|
|
13
|
+
await Instance.provide({
|
|
14
|
+
directory: projectRoot,
|
|
15
|
+
fn: async () => {
|
|
16
|
+
let eventReceived = false
|
|
17
|
+
let receivedInfo: Session.Info | undefined
|
|
18
|
+
|
|
19
|
+
const unsub = Bus.subscribe(Session.Event.Created, (event) => {
|
|
20
|
+
eventReceived = true
|
|
21
|
+
receivedInfo = event.properties.info as Session.Info
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const session = await Session.create({})
|
|
25
|
+
|
|
26
|
+
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
27
|
+
|
|
28
|
+
unsub()
|
|
29
|
+
|
|
30
|
+
expect(eventReceived).toBe(true)
|
|
31
|
+
expect(receivedInfo).toBeDefined()
|
|
32
|
+
expect(receivedInfo?.id).toBe(session.id)
|
|
33
|
+
expect(receivedInfo?.projectID).toBe(session.projectID)
|
|
34
|
+
expect(receivedInfo?.directory).toBe(session.directory)
|
|
35
|
+
expect(receivedInfo?.title).toBe(session.title)
|
|
36
|
+
|
|
37
|
+
await Session.remove(session.id)
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test("session.started event should be emitted before session.updated", async () => {
|
|
43
|
+
await Instance.provide({
|
|
44
|
+
directory: projectRoot,
|
|
45
|
+
fn: async () => {
|
|
46
|
+
const events: string[] = []
|
|
47
|
+
|
|
48
|
+
const unsubStarted = Bus.subscribe(Session.Event.Created, () => {
|
|
49
|
+
events.push("started")
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const unsubUpdated = Bus.subscribe(Session.Event.Updated, () => {
|
|
53
|
+
events.push("updated")
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const session = await Session.create({})
|
|
57
|
+
|
|
58
|
+
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
59
|
+
|
|
60
|
+
unsubStarted()
|
|
61
|
+
unsubUpdated()
|
|
62
|
+
|
|
63
|
+
expect(events).toContain("started")
|
|
64
|
+
expect(events).toContain("updated")
|
|
65
|
+
expect(events.indexOf("started")).toBeLessThan(events.indexOf("updated"))
|
|
66
|
+
|
|
67
|
+
await Session.remove(session.id)
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
})
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test"
|
|
2
|
+
import { Discovery } from "../../src/skill/discovery"
|
|
3
|
+
import path from "path"
|
|
4
|
+
|
|
5
|
+
const CLOUDFLARE_SKILLS_URL = "https://developers.cloudflare.com/.well-known/skills/"
|
|
6
|
+
|
|
7
|
+
describe("Discovery.pull", () => {
|
|
8
|
+
test("downloads skills from cloudflare url", async () => {
|
|
9
|
+
const dirs = await Discovery.pull(CLOUDFLARE_SKILLS_URL)
|
|
10
|
+
expect(dirs.length).toBeGreaterThan(0)
|
|
11
|
+
for (const dir of dirs) {
|
|
12
|
+
expect(dir).toStartWith(Discovery.dir())
|
|
13
|
+
const md = path.join(dir, "SKILL.md")
|
|
14
|
+
expect(await Bun.file(md).exists()).toBe(true)
|
|
15
|
+
}
|
|
16
|
+
}, 30_000)
|
|
17
|
+
|
|
18
|
+
test("url without trailing slash works", async () => {
|
|
19
|
+
const dirs = await Discovery.pull(CLOUDFLARE_SKILLS_URL.replace(/\/$/, ""))
|
|
20
|
+
expect(dirs.length).toBeGreaterThan(0)
|
|
21
|
+
for (const dir of dirs) {
|
|
22
|
+
const md = path.join(dir, "SKILL.md")
|
|
23
|
+
expect(await Bun.file(md).exists()).toBe(true)
|
|
24
|
+
}
|
|
25
|
+
}, 30_000)
|
|
26
|
+
|
|
27
|
+
test("returns empty array for invalid url", async () => {
|
|
28
|
+
const dirs = await Discovery.pull("https://example.invalid/.well-known/skills/")
|
|
29
|
+
expect(dirs).toEqual([])
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test("returns empty array for non-json response", async () => {
|
|
33
|
+
const dirs = await Discovery.pull("https://example.com/")
|
|
34
|
+
expect(dirs).toEqual([])
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test("downloads reference files alongside SKILL.md", async () => {
|
|
38
|
+
const dirs = await Discovery.pull(CLOUDFLARE_SKILLS_URL)
|
|
39
|
+
// find a skill dir that should have reference files (e.g. agents-sdk)
|
|
40
|
+
const agentsSdk = dirs.find((d) => d.endsWith("/agents-sdk"))
|
|
41
|
+
if (agentsSdk) {
|
|
42
|
+
const refs = path.join(agentsSdk, "references")
|
|
43
|
+
expect(await Bun.file(path.join(agentsSdk, "SKILL.md")).exists()).toBe(true)
|
|
44
|
+
// agents-sdk has reference files per the index
|
|
45
|
+
const refDir = await Array.fromAsync(new Bun.Glob("**/*.md").scan({ cwd: refs, onlyFiles: true }))
|
|
46
|
+
expect(refDir.length).toBeGreaterThan(0)
|
|
47
|
+
}
|
|
48
|
+
}, 30_000)
|
|
49
|
+
|
|
50
|
+
test("caches downloaded files on second pull", async () => {
|
|
51
|
+
// first pull to populate cache
|
|
52
|
+
const first = await Discovery.pull(CLOUDFLARE_SKILLS_URL)
|
|
53
|
+
expect(first.length).toBeGreaterThan(0)
|
|
54
|
+
|
|
55
|
+
// second pull should return same results from cache
|
|
56
|
+
const second = await Discovery.pull(CLOUDFLARE_SKILLS_URL)
|
|
57
|
+
expect(second.length).toBe(first.length)
|
|
58
|
+
expect(second.sort()).toEqual(first.sort())
|
|
59
|
+
}, 60_000)
|
|
60
|
+
})
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { test, expect } from "bun:test"
|
|
2
|
+
import { Skill } from "../../src/skill"
|
|
3
|
+
import { Instance } from "../../src/project/instance"
|
|
4
|
+
import { tmpdir } from "../fixture/fixture"
|
|
5
|
+
import path from "path"
|
|
6
|
+
import fs from "fs/promises"
|
|
7
|
+
|
|
8
|
+
async function createGlobalSkill(homeDir: string) {
|
|
9
|
+
const skillDir = path.join(homeDir, ".claude", "skills", "global-test-skill")
|
|
10
|
+
await fs.mkdir(skillDir, { recursive: true })
|
|
11
|
+
await Bun.write(
|
|
12
|
+
path.join(skillDir, "SKILL.md"),
|
|
13
|
+
`---
|
|
14
|
+
name: global-test-skill
|
|
15
|
+
description: A global skill from ~/.claude/skills for testing.
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Global Test Skill
|
|
19
|
+
|
|
20
|
+
This skill is loaded from the global home directory.
|
|
21
|
+
`,
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
test("discovers skills from .opencode/skill/ directory", async () => {
|
|
26
|
+
await using tmp = await tmpdir({
|
|
27
|
+
git: true,
|
|
28
|
+
init: async (dir) => {
|
|
29
|
+
const skillDir = path.join(dir, ".opencode", "skill", "test-skill")
|
|
30
|
+
await Bun.write(
|
|
31
|
+
path.join(skillDir, "SKILL.md"),
|
|
32
|
+
`---
|
|
33
|
+
name: test-skill
|
|
34
|
+
description: A test skill for verification.
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
# Test Skill
|
|
38
|
+
|
|
39
|
+
Instructions here.
|
|
40
|
+
`,
|
|
41
|
+
)
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
await Instance.provide({
|
|
46
|
+
directory: tmp.path,
|
|
47
|
+
fn: async () => {
|
|
48
|
+
const skills = await Skill.all()
|
|
49
|
+
expect(skills.length).toBe(1)
|
|
50
|
+
const testSkill = skills.find((s) => s.name === "test-skill")
|
|
51
|
+
expect(testSkill).toBeDefined()
|
|
52
|
+
expect(testSkill!.description).toBe("A test skill for verification.")
|
|
53
|
+
expect(testSkill!.location).toContain("skill/test-skill/SKILL.md")
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test("returns skill directories from Skill.dirs", async () => {
|
|
59
|
+
await using tmp = await tmpdir({
|
|
60
|
+
git: true,
|
|
61
|
+
init: async (dir) => {
|
|
62
|
+
const skillDir = path.join(dir, ".opencode", "skill", "dir-skill")
|
|
63
|
+
await Bun.write(
|
|
64
|
+
path.join(skillDir, "SKILL.md"),
|
|
65
|
+
`---
|
|
66
|
+
name: dir-skill
|
|
67
|
+
description: Skill for dirs test.
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
# Dir Skill
|
|
71
|
+
`,
|
|
72
|
+
)
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
const home = process.env.OPENCODE_TEST_HOME
|
|
77
|
+
process.env.OPENCODE_TEST_HOME = tmp.path
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
await Instance.provide({
|
|
81
|
+
directory: tmp.path,
|
|
82
|
+
fn: async () => {
|
|
83
|
+
const dirs = await Skill.dirs()
|
|
84
|
+
const skillDir = path.join(tmp.path, ".opencode", "skill", "dir-skill")
|
|
85
|
+
expect(dirs).toContain(skillDir)
|
|
86
|
+
expect(dirs.length).toBe(1)
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
} finally {
|
|
90
|
+
process.env.OPENCODE_TEST_HOME = home
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test("discovers multiple skills from .opencode/skill/ directory", async () => {
|
|
95
|
+
await using tmp = await tmpdir({
|
|
96
|
+
git: true,
|
|
97
|
+
init: async (dir) => {
|
|
98
|
+
const skillDir1 = path.join(dir, ".opencode", "skill", "skill-one")
|
|
99
|
+
const skillDir2 = path.join(dir, ".opencode", "skill", "skill-two")
|
|
100
|
+
await Bun.write(
|
|
101
|
+
path.join(skillDir1, "SKILL.md"),
|
|
102
|
+
`---
|
|
103
|
+
name: skill-one
|
|
104
|
+
description: First test skill.
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
# Skill One
|
|
108
|
+
`,
|
|
109
|
+
)
|
|
110
|
+
await Bun.write(
|
|
111
|
+
path.join(skillDir2, "SKILL.md"),
|
|
112
|
+
`---
|
|
113
|
+
name: skill-two
|
|
114
|
+
description: Second test skill.
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
# Skill Two
|
|
118
|
+
`,
|
|
119
|
+
)
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
await Instance.provide({
|
|
124
|
+
directory: tmp.path,
|
|
125
|
+
fn: async () => {
|
|
126
|
+
const skills = await Skill.all()
|
|
127
|
+
expect(skills.length).toBe(2)
|
|
128
|
+
expect(skills.find((s) => s.name === "skill-one")).toBeDefined()
|
|
129
|
+
expect(skills.find((s) => s.name === "skill-two")).toBeDefined()
|
|
130
|
+
},
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
test("skips skills with missing frontmatter", async () => {
|
|
135
|
+
await using tmp = await tmpdir({
|
|
136
|
+
git: true,
|
|
137
|
+
init: async (dir) => {
|
|
138
|
+
const skillDir = path.join(dir, ".opencode", "skill", "no-frontmatter")
|
|
139
|
+
await Bun.write(
|
|
140
|
+
path.join(skillDir, "SKILL.md"),
|
|
141
|
+
`# No Frontmatter
|
|
142
|
+
|
|
143
|
+
Just some content without YAML frontmatter.
|
|
144
|
+
`,
|
|
145
|
+
)
|
|
146
|
+
},
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
await Instance.provide({
|
|
150
|
+
directory: tmp.path,
|
|
151
|
+
fn: async () => {
|
|
152
|
+
const skills = await Skill.all()
|
|
153
|
+
expect(skills).toEqual([])
|
|
154
|
+
},
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
test("discovers skills from .claude/skills/ directory", async () => {
|
|
159
|
+
await using tmp = await tmpdir({
|
|
160
|
+
git: true,
|
|
161
|
+
init: async (dir) => {
|
|
162
|
+
const skillDir = path.join(dir, ".claude", "skills", "claude-skill")
|
|
163
|
+
await Bun.write(
|
|
164
|
+
path.join(skillDir, "SKILL.md"),
|
|
165
|
+
`---
|
|
166
|
+
name: claude-skill
|
|
167
|
+
description: A skill in the .claude/skills directory.
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
# Claude Skill
|
|
171
|
+
`,
|
|
172
|
+
)
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
await Instance.provide({
|
|
177
|
+
directory: tmp.path,
|
|
178
|
+
fn: async () => {
|
|
179
|
+
const skills = await Skill.all()
|
|
180
|
+
expect(skills.length).toBe(1)
|
|
181
|
+
const claudeSkill = skills.find((s) => s.name === "claude-skill")
|
|
182
|
+
expect(claudeSkill).toBeDefined()
|
|
183
|
+
expect(claudeSkill!.location).toContain(".claude/skills/claude-skill/SKILL.md")
|
|
184
|
+
},
|
|
185
|
+
})
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
test("discovers global skills from ~/.claude/skills/ directory", async () => {
|
|
189
|
+
await using tmp = await tmpdir({ git: true })
|
|
190
|
+
|
|
191
|
+
const originalHome = process.env.OPENCODE_TEST_HOME
|
|
192
|
+
process.env.OPENCODE_TEST_HOME = tmp.path
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
await createGlobalSkill(tmp.path)
|
|
196
|
+
await Instance.provide({
|
|
197
|
+
directory: tmp.path,
|
|
198
|
+
fn: async () => {
|
|
199
|
+
const skills = await Skill.all()
|
|
200
|
+
expect(skills.length).toBe(1)
|
|
201
|
+
expect(skills[0].name).toBe("global-test-skill")
|
|
202
|
+
expect(skills[0].description).toBe("A global skill from ~/.claude/skills for testing.")
|
|
203
|
+
expect(skills[0].location).toContain(".claude/skills/global-test-skill/SKILL.md")
|
|
204
|
+
},
|
|
205
|
+
})
|
|
206
|
+
} finally {
|
|
207
|
+
process.env.OPENCODE_TEST_HOME = originalHome
|
|
208
|
+
}
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
test("returns empty array when no skills exist", async () => {
|
|
212
|
+
await using tmp = await tmpdir({ git: true })
|
|
213
|
+
|
|
214
|
+
await Instance.provide({
|
|
215
|
+
directory: tmp.path,
|
|
216
|
+
fn: async () => {
|
|
217
|
+
const skills = await Skill.all()
|
|
218
|
+
expect(skills).toEqual([])
|
|
219
|
+
},
|
|
220
|
+
})
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
test("discovers skills from .agents/skills/ directory", async () => {
|
|
224
|
+
await using tmp = await tmpdir({
|
|
225
|
+
git: true,
|
|
226
|
+
init: async (dir) => {
|
|
227
|
+
const skillDir = path.join(dir, ".agents", "skills", "agent-skill")
|
|
228
|
+
await Bun.write(
|
|
229
|
+
path.join(skillDir, "SKILL.md"),
|
|
230
|
+
`---
|
|
231
|
+
name: agent-skill
|
|
232
|
+
description: A skill in the .agents/skills directory.
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
# Agent Skill
|
|
236
|
+
`,
|
|
237
|
+
)
|
|
238
|
+
},
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
await Instance.provide({
|
|
242
|
+
directory: tmp.path,
|
|
243
|
+
fn: async () => {
|
|
244
|
+
const skills = await Skill.all()
|
|
245
|
+
expect(skills.length).toBe(1)
|
|
246
|
+
const agentSkill = skills.find((s) => s.name === "agent-skill")
|
|
247
|
+
expect(agentSkill).toBeDefined()
|
|
248
|
+
expect(agentSkill!.location).toContain(".agents/skills/agent-skill/SKILL.md")
|
|
249
|
+
},
|
|
250
|
+
})
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
test("discovers global skills from ~/.agents/skills/ directory", async () => {
|
|
254
|
+
await using tmp = await tmpdir({ git: true })
|
|
255
|
+
|
|
256
|
+
const originalHome = process.env.OPENCODE_TEST_HOME
|
|
257
|
+
process.env.OPENCODE_TEST_HOME = tmp.path
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
const skillDir = path.join(tmp.path, ".agents", "skills", "global-agent-skill")
|
|
261
|
+
await fs.mkdir(skillDir, { recursive: true })
|
|
262
|
+
await Bun.write(
|
|
263
|
+
path.join(skillDir, "SKILL.md"),
|
|
264
|
+
`---
|
|
265
|
+
name: global-agent-skill
|
|
266
|
+
description: A global skill from ~/.agents/skills for testing.
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
# Global Agent Skill
|
|
270
|
+
|
|
271
|
+
This skill is loaded from the global home directory.
|
|
272
|
+
`,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
await Instance.provide({
|
|
276
|
+
directory: tmp.path,
|
|
277
|
+
fn: async () => {
|
|
278
|
+
const skills = await Skill.all()
|
|
279
|
+
expect(skills.length).toBe(1)
|
|
280
|
+
expect(skills[0].name).toBe("global-agent-skill")
|
|
281
|
+
expect(skills[0].description).toBe("A global skill from ~/.agents/skills for testing.")
|
|
282
|
+
expect(skills[0].location).toContain(".agents/skills/global-agent-skill/SKILL.md")
|
|
283
|
+
},
|
|
284
|
+
})
|
|
285
|
+
} finally {
|
|
286
|
+
process.env.OPENCODE_TEST_HOME = originalHome
|
|
287
|
+
}
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
test("discovers skills from both .claude/skills/ and .agents/skills/", async () => {
|
|
291
|
+
await using tmp = await tmpdir({
|
|
292
|
+
git: true,
|
|
293
|
+
init: async (dir) => {
|
|
294
|
+
const claudeDir = path.join(dir, ".claude", "skills", "claude-skill")
|
|
295
|
+
const agentDir = path.join(dir, ".agents", "skills", "agent-skill")
|
|
296
|
+
await Bun.write(
|
|
297
|
+
path.join(claudeDir, "SKILL.md"),
|
|
298
|
+
`---
|
|
299
|
+
name: claude-skill
|
|
300
|
+
description: A skill in the .claude/skills directory.
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
# Claude Skill
|
|
304
|
+
`,
|
|
305
|
+
)
|
|
306
|
+
await Bun.write(
|
|
307
|
+
path.join(agentDir, "SKILL.md"),
|
|
308
|
+
`---
|
|
309
|
+
name: agent-skill
|
|
310
|
+
description: A skill in the .agents/skills directory.
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
# Agent Skill
|
|
314
|
+
`,
|
|
315
|
+
)
|
|
316
|
+
},
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
await Instance.provide({
|
|
320
|
+
directory: tmp.path,
|
|
321
|
+
fn: async () => {
|
|
322
|
+
const skills = await Skill.all()
|
|
323
|
+
expect(skills.length).toBe(2)
|
|
324
|
+
expect(skills.find((s) => s.name === "claude-skill")).toBeDefined()
|
|
325
|
+
expect(skills.find((s) => s.name === "agent-skill")).toBeDefined()
|
|
326
|
+
},
|
|
327
|
+
})
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
test("properly resolves directories that skills live in", async () => {
|
|
331
|
+
await using tmp = await tmpdir({
|
|
332
|
+
git: true,
|
|
333
|
+
init: async (dir) => {
|
|
334
|
+
const opencodeSkillDir = path.join(dir, ".opencode", "skill", "agent-skill")
|
|
335
|
+
const opencodeSkillsDir = path.join(dir, ".opencode", "skills", "agent-skill")
|
|
336
|
+
const claudeDir = path.join(dir, ".claude", "skills", "claude-skill")
|
|
337
|
+
const agentDir = path.join(dir, ".agents", "skills", "agent-skill")
|
|
338
|
+
await Bun.write(
|
|
339
|
+
path.join(claudeDir, "SKILL.md"),
|
|
340
|
+
`---
|
|
341
|
+
name: claude-skill
|
|
342
|
+
description: A skill in the .claude/skills directory.
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
# Claude Skill
|
|
346
|
+
`,
|
|
347
|
+
)
|
|
348
|
+
await Bun.write(
|
|
349
|
+
path.join(agentDir, "SKILL.md"),
|
|
350
|
+
`---
|
|
351
|
+
name: agent-skill
|
|
352
|
+
description: A skill in the .agents/skills directory.
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
# Agent Skill
|
|
356
|
+
`,
|
|
357
|
+
)
|
|
358
|
+
await Bun.write(
|
|
359
|
+
path.join(opencodeSkillDir, "SKILL.md"),
|
|
360
|
+
`---
|
|
361
|
+
name: opencode-skill
|
|
362
|
+
description: A skill in the .opencode/skill directory.
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
# OpenCode Skill
|
|
366
|
+
`,
|
|
367
|
+
)
|
|
368
|
+
await Bun.write(
|
|
369
|
+
path.join(opencodeSkillsDir, "SKILL.md"),
|
|
370
|
+
`---
|
|
371
|
+
name: opencode-skill
|
|
372
|
+
description: A skill in the .opencode/skills directory.
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
# OpenCode Skill
|
|
376
|
+
`,
|
|
377
|
+
)
|
|
378
|
+
},
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
await Instance.provide({
|
|
382
|
+
directory: tmp.path,
|
|
383
|
+
fn: async () => {
|
|
384
|
+
const dirs = await Skill.dirs()
|
|
385
|
+
expect(dirs.length).toBe(4)
|
|
386
|
+
},
|
|
387
|
+
})
|
|
388
|
+
})
|