mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-20 09:14:22 +01:00
slash commands (#2157)
Co-authored-by: adamdotdevin <2363879+adamdottv@users.noreply.github.com>
This commit is contained in:
9
.opencode/command/commit.md
Normal file
9
.opencode/command/commit.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
commit and push
|
||||||
|
|
||||||
|
make sure it includes a prefix like
|
||||||
|
docs:
|
||||||
|
tui:
|
||||||
|
core:
|
||||||
|
ci:
|
||||||
|
ignore:
|
||||||
|
wip:
|
||||||
8
.opencode/command/hello.md
Normal file
8
.opencode/command/hello.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
description: hello world
|
||||||
|
---
|
||||||
|
|
||||||
|
hey there $ARGUMENTS
|
||||||
|
|
||||||
|
!`ls`
|
||||||
|
check out @README.md
|
||||||
31
bun.lock
31
bun.lock
@@ -26,7 +26,7 @@
|
|||||||
},
|
},
|
||||||
"cloud/core": {
|
"cloud/core": {
|
||||||
"name": "@opencode/cloud-core",
|
"name": "@opencode/cloud-core",
|
||||||
"version": "0.5.12",
|
"version": "0.5.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-sts": "3.782.0",
|
"@aws-sdk/client-sts": "3.782.0",
|
||||||
"drizzle-orm": "0.41.0",
|
"drizzle-orm": "0.41.0",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
},
|
},
|
||||||
"cloud/function": {
|
"cloud/function": {
|
||||||
"name": "@opencode/cloud-function",
|
"name": "@opencode/cloud-function",
|
||||||
"version": "0.5.12",
|
"version": "0.5.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/anthropic": "2.0.0",
|
"@ai-sdk/anthropic": "2.0.0",
|
||||||
"@ai-sdk/openai": "2.0.2",
|
"@ai-sdk/openai": "2.0.2",
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
},
|
},
|
||||||
"cloud/web": {
|
"cloud/web": {
|
||||||
"name": "@opencode/cloud-web",
|
"name": "@opencode/cloud-web",
|
||||||
"version": "0.5.12",
|
"version": "0.5.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kobalte/core": "0.13.9",
|
"@kobalte/core": "0.13.9",
|
||||||
"@openauthjs/solid": "0.0.0-20250322224806",
|
"@openauthjs/solid": "0.0.0-20250322224806",
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
},
|
},
|
||||||
"packages/function": {
|
"packages/function": {
|
||||||
"name": "@opencode/function",
|
"name": "@opencode/function",
|
||||||
"version": "0.5.12",
|
"version": "0.5.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/auth-app": "8.0.1",
|
"@octokit/auth-app": "8.0.1",
|
||||||
"@octokit/rest": "22.0.0",
|
"@octokit/rest": "22.0.0",
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
},
|
},
|
||||||
"packages/opencode": {
|
"packages/opencode": {
|
||||||
"name": "opencode",
|
"name": "opencode",
|
||||||
"version": "0.5.12",
|
"version": "0.5.13",
|
||||||
"bin": {
|
"bin": {
|
||||||
"opencode": "./bin/opencode",
|
"opencode": "./bin/opencode",
|
||||||
},
|
},
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
},
|
},
|
||||||
"packages/plugin": {
|
"packages/plugin": {
|
||||||
"name": "@opencode-ai/plugin",
|
"name": "@opencode-ai/plugin",
|
||||||
"version": "0.5.12",
|
"version": "0.5.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
},
|
},
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
},
|
},
|
||||||
"packages/sdk/js": {
|
"packages/sdk/js": {
|
||||||
"name": "@opencode-ai/sdk",
|
"name": "@opencode-ai/sdk",
|
||||||
"version": "0.5.12",
|
"version": "0.5.13",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hey-api/openapi-ts": "0.80.1",
|
"@hey-api/openapi-ts": "0.80.1",
|
||||||
"@tsconfig/node22": "catalog:",
|
"@tsconfig/node22": "catalog:",
|
||||||
@@ -165,7 +165,7 @@
|
|||||||
},
|
},
|
||||||
"packages/web": {
|
"packages/web": {
|
||||||
"name": "@opencode/web",
|
"name": "@opencode/web",
|
||||||
"version": "0.5.12",
|
"version": "0.5.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/cloudflare": "12.6.3",
|
"@astrojs/cloudflare": "12.6.3",
|
||||||
"@astrojs/markdown-remark": "6.3.1",
|
"@astrojs/markdown-remark": "6.3.1",
|
||||||
@@ -204,6 +204,9 @@
|
|||||||
"web-tree-sitter",
|
"web-tree-sitter",
|
||||||
"tree-sitter-bash",
|
"tree-sitter-bash",
|
||||||
],
|
],
|
||||||
|
"overrides": {
|
||||||
|
"zod": "3.25.76",
|
||||||
|
},
|
||||||
"catalog": {
|
"catalog": {
|
||||||
"@hono/zod-validator": "0.4.2",
|
"@hono/zod-validator": "0.4.2",
|
||||||
"@tsconfig/node22": "22.0.2",
|
"@tsconfig/node22": "22.0.2",
|
||||||
@@ -3063,8 +3066,6 @@
|
|||||||
|
|
||||||
"@astrojs/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
"@astrojs/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||||
|
|
||||||
"@astrojs/sitemap/zod": ["zod@3.25.49", "", {}, "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q=="],
|
|
||||||
|
|
||||||
"@astrojs/solid-js/vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="],
|
"@astrojs/solid-js/vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="],
|
||||||
|
|
||||||
"@astrojs/solid-js/vite-plugin-solid": ["vite-plugin-solid@2.11.8", "", { "dependencies": { "@babel/core": "^7.23.3", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^1.8.4", "merge-anything": "^5.1.7", "solid-refresh": "^0.6.3", "vitefu": "^1.0.4" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", "solid-js": "^1.7.2", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-hFrCxBfv3B1BmFqnJF4JOCYpjrmi/zwyeKjcomQ0khh8HFyQ8SbuBWQ7zGojfrz6HUOBFrJBNySDi/JgAHytWg=="],
|
"@astrojs/solid-js/vite-plugin-solid": ["vite-plugin-solid@2.11.8", "", { "dependencies": { "@babel/core": "^7.23.3", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^1.8.4", "merge-anything": "^5.1.7", "solid-refresh": "^0.6.3", "vitefu": "^1.0.4" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", "solid-js": "^1.7.2", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-hFrCxBfv3B1BmFqnJF4JOCYpjrmi/zwyeKjcomQ0khh8HFyQ8SbuBWQ7zGojfrz6HUOBFrJBNySDi/JgAHytWg=="],
|
||||||
@@ -3161,8 +3162,6 @@
|
|||||||
|
|
||||||
"@mdx-js/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
"@mdx-js/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||||
|
|
||||||
"@modelcontextprotocol/sdk/zod": ["zod@3.25.49", "", {}, "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q=="],
|
|
||||||
|
|
||||||
"@netlify/dev-utils/find-up": ["find-up@7.0.0", "", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="],
|
"@netlify/dev-utils/find-up": ["find-up@7.0.0", "", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="],
|
||||||
|
|
||||||
"@netlify/dev-utils/uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="],
|
"@netlify/dev-utils/uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="],
|
||||||
@@ -3339,8 +3338,6 @@
|
|||||||
|
|
||||||
"astro/vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="],
|
"astro/vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="],
|
||||||
|
|
||||||
"astro/zod": ["zod@3.25.49", "", {}, "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q=="],
|
|
||||||
|
|
||||||
"babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="],
|
"babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="],
|
||||||
|
|
||||||
"bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
|
"bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
|
||||||
@@ -3417,8 +3414,6 @@
|
|||||||
|
|
||||||
"miniflare/youch": ["youch@4.1.0-beta.10", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.4", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.3" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="],
|
"miniflare/youch": ["youch@4.1.0-beta.10", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.4", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.3" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="],
|
||||||
|
|
||||||
"miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="],
|
|
||||||
|
|
||||||
"minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
"minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
|
|
||||||
"minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
"minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
@@ -3463,8 +3458,6 @@
|
|||||||
|
|
||||||
"opencontrol/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
|
"opencontrol/hono": ["hono@4.7.4", "", {}, "sha512-Pst8FuGqz3L7tFF+u9Pu70eI0xa5S3LPUmrNd5Jm8nTHze9FxLTK9Kaj5g/k4UcwuJSXTP65SyHOPLrffpcAJg=="],
|
||||||
|
|
||||||
"opencontrol/zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
|
|
||||||
|
|
||||||
"opencontrol/zod-to-json-schema": ["zod-to-json-schema@3.24.3", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A=="],
|
"opencontrol/zod-to-json-schema": ["zod-to-json-schema@3.24.3", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A=="],
|
||||||
|
|
||||||
"openid-client/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="],
|
"openid-client/jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="],
|
||||||
@@ -3883,8 +3876,6 @@
|
|||||||
|
|
||||||
"opencontrol/@modelcontextprotocol/sdk/pkce-challenge": ["pkce-challenge@4.1.0", "", {}, "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="],
|
"opencontrol/@modelcontextprotocol/sdk/pkce-challenge": ["pkce-challenge@4.1.0", "", {}, "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="],
|
||||||
|
|
||||||
"opencontrol/@modelcontextprotocol/sdk/zod": ["zod@3.25.49", "", {}, "sha512-JMMPMy9ZBk3XFEdbM3iL1brx4NUSejd6xr3ELrrGEfGb355gjhiAWtG3K5o+AViV/3ZfkIrCzXsZn6SbLwTR8Q=="],
|
|
||||||
|
|
||||||
"opencontrol/@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.24.5", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="],
|
"opencontrol/@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.24.5", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="],
|
||||||
|
|
||||||
"prebuild-install/tar-fs/tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
|
"prebuild-install/tar-fs/tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
|
||||||
|
|||||||
15
logs/.496fc674ed58d31f8b883da41cc2adb4564aad58-audit.json
Normal file
15
logs/.496fc674ed58d31f8b883da41cc2adb4564aad58-audit.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"keep": {
|
||||||
|
"days": true,
|
||||||
|
"amount": 14
|
||||||
|
},
|
||||||
|
"auditLog": "/Users/adam/code/opencode/dev/logs/.496fc674ed58d31f8b883da41cc2adb4564aad58-audit.json",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"date": 1755891797740,
|
||||||
|
"name": "/Users/adam/code/opencode/dev/logs/mcp-puppeteer-2025-08-22.log",
|
||||||
|
"hash": "dd9b1f2e98b661ba2f56b91dd9afbdb25e50adbdd52ed1b0eef1d2045235d17c"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hashType": "sha256"
|
||||||
|
}
|
||||||
6
logs/mcp-puppeteer-2025-08-22.log
Normal file
6
logs/mcp-puppeteer-2025-08-22.log
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-08-22 14:43:17.765"}
|
||||||
|
{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-08-22 14:43:17.766"}
|
||||||
|
{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-08-22 14:46:45.539"}
|
||||||
|
{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-08-22 14:46:45.540"}
|
||||||
|
{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-08-22 14:53:08.159"}
|
||||||
|
{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-08-22 14:53:08.160"}
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://opencode.ai/config.json",
|
"$schema": "https://opencode.ai/config.json",
|
||||||
|
|
||||||
"mcp": {
|
"mcp": {
|
||||||
"context7": {
|
|
||||||
"type": "remote",
|
|
||||||
"url": "https://mcp.context7.com/sse"
|
|
||||||
},
|
|
||||||
"weather": {
|
"weather": {
|
||||||
"type": "local",
|
"type": "local",
|
||||||
"command": ["opencode", "x", "@h1deya/mcp-server-weather"]
|
"command": ["opencode", "x", "@h1deya/mcp-server-weather"]
|
||||||
|
|||||||
@@ -51,5 +51,8 @@
|
|||||||
"tree-sitter-bash",
|
"tree-sitter-bash",
|
||||||
"web-tree-sitter"
|
"web-tree-sitter"
|
||||||
],
|
],
|
||||||
|
"overrides": {
|
||||||
|
"zod": "3.25.76"
|
||||||
|
},
|
||||||
"patchedDependencies": {}
|
"patchedDependencies": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Config } from "../src/config/config"
|
|||||||
import { zodToJsonSchema } from "zod-to-json-schema"
|
import { zodToJsonSchema } from "zod-to-json-schema"
|
||||||
|
|
||||||
const file = process.argv[2]
|
const file = process.argv[2]
|
||||||
|
console.log(file)
|
||||||
|
|
||||||
const result = zodToJsonSchema(Config.Info, {
|
const result = zodToJsonSchema(Config.Info, {
|
||||||
/**
|
/**
|
||||||
|
|||||||
44
packages/opencode/src/command/index.ts
Normal file
44
packages/opencode/src/command/index.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import z from "zod"
|
||||||
|
import { App } from "../app/app"
|
||||||
|
import { Config } from "../config/config"
|
||||||
|
|
||||||
|
export namespace Command {
|
||||||
|
export const Info = z
|
||||||
|
.object({
|
||||||
|
name: z.string(),
|
||||||
|
description: z.string().optional(),
|
||||||
|
agent: z.string().optional(),
|
||||||
|
model: z.string().optional(),
|
||||||
|
template: z.string(),
|
||||||
|
})
|
||||||
|
.openapi({
|
||||||
|
ref: "Command",
|
||||||
|
})
|
||||||
|
export type Info = z.infer<typeof Info>
|
||||||
|
|
||||||
|
const state = App.state("command", async () => {
|
||||||
|
const cfg = await Config.get()
|
||||||
|
|
||||||
|
const result: Record<string, Info> = {}
|
||||||
|
|
||||||
|
for (const [name, command] of Object.entries(cfg.command ?? {})) {
|
||||||
|
result[name] = {
|
||||||
|
name,
|
||||||
|
agent: command.agent,
|
||||||
|
model: command.model,
|
||||||
|
description: command.description,
|
||||||
|
template: command.template,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
|
export async function get(name: string) {
|
||||||
|
return state().then((x) => x[name])
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function list() {
|
||||||
|
return state().then((x) => Object.values(x))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -107,6 +107,32 @@ export namespace Config {
|
|||||||
}
|
}
|
||||||
throw new InvalidError({ path: item }, { cause: parsed.error })
|
throw new InvalidError({ path: item }, { cause: parsed.error })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load command markdown files
|
||||||
|
result.command = result.command || {}
|
||||||
|
const markdownCommands = [
|
||||||
|
...(await Filesystem.globUp("command/*.md", Global.Path.config, Global.Path.config)),
|
||||||
|
...(await Filesystem.globUp(".opencode/command/*.md", app.path.cwd, app.path.root)),
|
||||||
|
]
|
||||||
|
for (const item of markdownCommands) {
|
||||||
|
const content = await Bun.file(item).text()
|
||||||
|
const md = matter(content)
|
||||||
|
if (!md.data) continue
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
name: path.basename(item, ".md"),
|
||||||
|
...md.data,
|
||||||
|
template: md.content.trim(),
|
||||||
|
}
|
||||||
|
const parsed = Command.safeParse(config)
|
||||||
|
if (parsed.success) {
|
||||||
|
result.command = mergeDeep(result.command, {
|
||||||
|
[config.name]: parsed.data,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
throw new InvalidError({ path: item }, { cause: parsed.error })
|
||||||
|
}
|
||||||
// Migrate deprecated mode field to agent field
|
// Migrate deprecated mode field to agent field
|
||||||
for (const [name, mode] of Object.entries(result.mode)) {
|
for (const [name, mode] of Object.entries(result.mode)) {
|
||||||
result.agent = mergeDeep(result.agent ?? {}, {
|
result.agent = mergeDeep(result.agent ?? {}, {
|
||||||
@@ -192,6 +218,14 @@ export namespace Config {
|
|||||||
export const Permission = z.union([z.literal("ask"), z.literal("allow"), z.literal("deny")])
|
export const Permission = z.union([z.literal("ask"), z.literal("allow"), z.literal("deny")])
|
||||||
export type Permission = z.infer<typeof Permission>
|
export type Permission = z.infer<typeof Permission>
|
||||||
|
|
||||||
|
export const Command = z.object({
|
||||||
|
template: z.string(),
|
||||||
|
description: z.string().optional(),
|
||||||
|
agent: z.string().optional(),
|
||||||
|
model: z.string().optional(),
|
||||||
|
})
|
||||||
|
export type Command = z.infer<typeof Command>
|
||||||
|
|
||||||
export const Agent = z
|
export const Agent = z
|
||||||
.object({
|
.object({
|
||||||
model: z.string().optional(),
|
model: z.string().optional(),
|
||||||
@@ -305,6 +339,7 @@ export namespace Config {
|
|||||||
theme: z.string().optional().describe("Theme name to use for the interface"),
|
theme: z.string().optional().describe("Theme name to use for the interface"),
|
||||||
keybinds: Keybinds.optional().describe("Custom keybind configurations"),
|
keybinds: Keybinds.optional().describe("Custom keybind configurations"),
|
||||||
tui: TUI.optional().describe("TUI specific settings"),
|
tui: TUI.optional().describe("TUI specific settings"),
|
||||||
|
command: z.record(z.string(), Command).optional(),
|
||||||
plugin: z.string().array().optional(),
|
plugin: z.string().array().optional(),
|
||||||
snapshot: z.boolean().optional(),
|
snapshot: z.boolean().optional(),
|
||||||
share: z
|
share: z
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ export namespace Provider {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async opencode() {
|
async opencode(input) {
|
||||||
return {
|
return {
|
||||||
autoload: true,
|
autoload: Object.keys(input.models).length > 0,
|
||||||
options: {},
|
options: {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { Permission } from "../permission"
|
|||||||
import { lazy } from "../util/lazy"
|
import { lazy } from "../util/lazy"
|
||||||
import { Agent } from "../agent/agent"
|
import { Agent } from "../agent/agent"
|
||||||
import { Auth } from "../auth"
|
import { Auth } from "../auth"
|
||||||
|
import { Command } from "../command"
|
||||||
|
|
||||||
const ERRORS = {
|
const ERRORS = {
|
||||||
400: {
|
400: {
|
||||||
@@ -611,10 +612,12 @@ export namespace Server {
|
|||||||
description: "Created message",
|
description: "Created message",
|
||||||
content: {
|
content: {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
schema: resolver(z.object({
|
schema: resolver(
|
||||||
|
z.object({
|
||||||
info: MessageV2.Assistant,
|
info: MessageV2.Assistant,
|
||||||
parts: MessageV2.Part.array(),
|
parts: MessageV2.Part.array(),
|
||||||
})),
|
}),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -634,6 +637,41 @@ export namespace Server {
|
|||||||
return c.json(msg)
|
return c.json(msg)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
.post(
|
||||||
|
"/session/:id/command",
|
||||||
|
describeRoute({
|
||||||
|
description: "Send a new command to a session",
|
||||||
|
operationId: "session.command",
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: "Created message",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: resolver(
|
||||||
|
z.object({
|
||||||
|
info: MessageV2.Assistant,
|
||||||
|
parts: MessageV2.Part.array(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
zValidator(
|
||||||
|
"param",
|
||||||
|
z.object({
|
||||||
|
id: z.string().openapi({ description: "Session ID" }),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
zValidator("json", Session.CommandInput.omit({ sessionID: true })),
|
||||||
|
async (c) => {
|
||||||
|
const sessionID = c.req.valid("param").id
|
||||||
|
const body = c.req.valid("json")
|
||||||
|
const msg = await Session.command({ ...body, sessionID })
|
||||||
|
return c.json(msg)
|
||||||
|
},
|
||||||
|
)
|
||||||
.post(
|
.post(
|
||||||
"/session/:id/shell",
|
"/session/:id/shell",
|
||||||
describeRoute({
|
describeRoute({
|
||||||
@@ -656,7 +694,7 @@ export namespace Server {
|
|||||||
id: z.string().openapi({ description: "Session ID" }),
|
id: z.string().openapi({ description: "Session ID" }),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
zValidator("json", Session.CommandInput.omit({ sessionID: true })),
|
zValidator("json", Session.ShellInput.omit({ sessionID: true })),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const sessionID = c.req.valid("param").id
|
const sessionID = c.req.valid("param").id
|
||||||
const body = c.req.valid("json")
|
const body = c.req.valid("json")
|
||||||
@@ -753,6 +791,27 @@ export namespace Server {
|
|||||||
return c.json(true)
|
return c.json(true)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
.get(
|
||||||
|
"/command",
|
||||||
|
describeRoute({
|
||||||
|
description: "List all commands",
|
||||||
|
operationId: "command.list",
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: "List of commands",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: resolver(Command.Info.array()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
async (c) => {
|
||||||
|
const commands = await Command.list()
|
||||||
|
return c.json(commands)
|
||||||
|
},
|
||||||
|
)
|
||||||
.get(
|
.get(
|
||||||
"/config/providers",
|
"/config/providers",
|
||||||
describeRoute({
|
describeRoute({
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ import { Permission } from "../permission"
|
|||||||
import { Wildcard } from "../util/wildcard"
|
import { Wildcard } from "../util/wildcard"
|
||||||
import { ulid } from "ulid"
|
import { ulid } from "ulid"
|
||||||
import { defer } from "../util/defer"
|
import { defer } from "../util/defer"
|
||||||
|
import { Command } from "../command"
|
||||||
|
import { $ } from "bun"
|
||||||
|
|
||||||
export namespace Session {
|
export namespace Session {
|
||||||
const log = Log.create({ service: "session" })
|
const log = Log.create({ service: "session" })
|
||||||
@@ -1025,13 +1027,13 @@ export namespace Session {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CommandInput = z.object({
|
export const ShellInput = z.object({
|
||||||
sessionID: Identifier.schema("session"),
|
sessionID: Identifier.schema("session"),
|
||||||
agent: z.string(),
|
agent: z.string(),
|
||||||
command: z.string(),
|
command: z.string(),
|
||||||
})
|
})
|
||||||
export type CommandInput = z.infer<typeof CommandInput>
|
export type ShellInput = z.infer<typeof ShellInput>
|
||||||
export async function shell(input: CommandInput) {
|
export async function shell(input: ShellInput) {
|
||||||
using abort = lock(input.sessionID)
|
using abort = lock(input.sessionID)
|
||||||
const msg: MessageV2.Assistant = {
|
const msg: MessageV2.Assistant = {
|
||||||
id: Identifier.ascending("message"),
|
id: Identifier.ascending("message"),
|
||||||
@@ -1155,6 +1157,72 @@ export namespace Session {
|
|||||||
return { info: msg, parts: [part] }
|
return { info: msg, parts: [part] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const CommandInput = z.object({
|
||||||
|
messageID: Identifier.schema("message").optional(),
|
||||||
|
sessionID: Identifier.schema("session"),
|
||||||
|
agent: z.string().optional(),
|
||||||
|
model: z.string().optional(),
|
||||||
|
arguments: z.string(),
|
||||||
|
command: z.string(),
|
||||||
|
})
|
||||||
|
export type CommandInput = z.infer<typeof CommandInput>
|
||||||
|
const bashRegex = /!`([^`]+)`/g
|
||||||
|
const fileRegex = /@([^\s]+)/g
|
||||||
|
|
||||||
|
export async function command(input: CommandInput) {
|
||||||
|
const command = await Command.get(input.command)
|
||||||
|
const agent = input.agent ?? command.agent ?? "build"
|
||||||
|
const model =
|
||||||
|
input.model ??
|
||||||
|
command.model ??
|
||||||
|
(await Agent.get(agent).then((x) => (x.model ? `${x.model.providerID}/${x.model.modelID}` : undefined))) ??
|
||||||
|
(await Provider.defaultModel().then((x) => `${x.providerID}/${x.modelID}`))
|
||||||
|
let template = command.template.replace("$ARGUMENTS", input.arguments)
|
||||||
|
|
||||||
|
const bash = Array.from(template.matchAll(bashRegex))
|
||||||
|
if (bash.length > 0) {
|
||||||
|
const results = await Promise.all(
|
||||||
|
bash.map(async ([, cmd]) => {
|
||||||
|
try {
|
||||||
|
return await $`${{ raw: cmd }}`.nothrow().text()
|
||||||
|
} catch (error) {
|
||||||
|
return `Error executing command: ${error instanceof Error ? error.message : String(error)}`
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
let index = 0
|
||||||
|
template = template.replace(bashRegex, () => results[index++])
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: template,
|
||||||
|
},
|
||||||
|
] as ChatInput["parts"]
|
||||||
|
|
||||||
|
const matches = template.matchAll(fileRegex)
|
||||||
|
const app = App.info()
|
||||||
|
|
||||||
|
for (const match of matches) {
|
||||||
|
const file = path.join(app.path.cwd, match[1])
|
||||||
|
parts.push({
|
||||||
|
type: "file",
|
||||||
|
url: `file://${file}`,
|
||||||
|
filename: match[1],
|
||||||
|
mime: "text/plain",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return chat({
|
||||||
|
sessionID: input.sessionID,
|
||||||
|
messageID: input.messageID,
|
||||||
|
...Provider.parseModel(model!),
|
||||||
|
agent,
|
||||||
|
parts,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function createProcessor(assistantMsg: MessageV2.Assistant, model: ModelsDev.Model) {
|
function createProcessor(assistantMsg: MessageV2.Assistant, model: ModelsDev.Model) {
|
||||||
const toolcalls: Record<string, MessageV2.ToolPart> = {}
|
const toolcalls: Record<string, MessageV2.ToolPart> = {}
|
||||||
let snapshot: string | undefined
|
let snapshot: string | undefined
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
configured_endpoints: 39
|
configured_endpoints: 41
|
||||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-be3e40e0bf7dde2bb15ff82d5d104418fb47fe335808a1aa6468b0be2210a88f.yml
|
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-d5200eaa145f567a58daa78941ab1141dd63f5f0cfe1596d5c9ecf12d34fea35.yml
|
||||||
openapi_spec_hash: c1bbb3ebd807656bd9f31a618077e76b
|
openapi_spec_hash: abeb66291dc158f2cdc90bf9945e283e
|
||||||
config_hash: eab3723c4c2232a6ba1821151259d6da
|
config_hash: fb625e876313a9f8f31532348fa91f59
|
||||||
|
|||||||
@@ -70,6 +70,16 @@ Methods:
|
|||||||
|
|
||||||
- <code title="get /config">client.Config.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ConfigService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Config">Config</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /config">client.Config.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ConfigService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Config">Config</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
|
# Command
|
||||||
|
|
||||||
|
Response Types:
|
||||||
|
|
||||||
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Command">Command</a>
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
|
||||||
|
- <code title="get /command">client.Command.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#CommandService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Command">Command</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
# Session
|
# Session
|
||||||
|
|
||||||
Params Types:
|
Params Types:
|
||||||
@@ -106,6 +116,7 @@ Response Types:
|
|||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStateRunning">ToolStateRunning</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStateRunning">ToolStateRunning</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#UserMessage">UserMessage</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#UserMessage">UserMessage</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatResponse">SessionChatResponse</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatResponse">SessionChatResponse</a>
|
||||||
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionCommandResponse">SessionCommandResponse</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageResponse">SessionMessageResponse</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageResponse">SessionMessageResponse</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>
|
||||||
|
|
||||||
@@ -118,6 +129,7 @@ Methods:
|
|||||||
- <code title="post /session/{id}/abort">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Abort">Abort</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/abort">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Abort">Abort</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Chat">Chat</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatParams">SessionChatParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatResponse">SessionChatResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Chat">Chat</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatParams">SessionChatParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatResponse">SessionChatResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="get /session/{id}/children">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Children">Children</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /session/{id}/children">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Children">Children</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
- <code title="post /session/{id}/command">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Command">Command</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionCommandParams">SessionCommandParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionCommandResponse">SessionCommandResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="get /session/{id}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /session/{id}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/init">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionInitParams">SessionInitParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/init">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionInitParams">SessionInitParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="get /session/{id}/message/{messageID}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Message">Message</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, messageID <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageResponse">SessionMessageResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /session/{id}/message/{messageID}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Message">Message</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, messageID <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageResponse">SessionMessageResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ type Client struct {
|
|||||||
Find *FindService
|
Find *FindService
|
||||||
File *FileService
|
File *FileService
|
||||||
Config *ConfigService
|
Config *ConfigService
|
||||||
|
Command *CommandService
|
||||||
Session *SessionService
|
Session *SessionService
|
||||||
Tui *TuiService
|
Tui *TuiService
|
||||||
}
|
}
|
||||||
@@ -49,6 +50,7 @@ func NewClient(opts ...option.RequestOption) (r *Client) {
|
|||||||
r.Find = NewFindService(opts...)
|
r.Find = NewFindService(opts...)
|
||||||
r.File = NewFileService(opts...)
|
r.File = NewFileService(opts...)
|
||||||
r.Config = NewConfigService(opts...)
|
r.Config = NewConfigService(opts...)
|
||||||
|
r.Command = NewCommandService(opts...)
|
||||||
r.Session = NewSessionService(opts...)
|
r.Session = NewSessionService(opts...)
|
||||||
r.Tui = NewTuiService(opts...)
|
r.Tui = NewTuiService(opts...)
|
||||||
|
|
||||||
|
|||||||
67
packages/sdk/go/command.go
Normal file
67
packages/sdk/go/command.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||||
|
|
||||||
|
package opencode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||||
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommandService contains methods and other services that help with interacting
|
||||||
|
// with the opencode API.
|
||||||
|
//
|
||||||
|
// Note, unlike clients, this service does not read variables from the environment
|
||||||
|
// automatically. You should not instantiate this service directly, and instead use
|
||||||
|
// the [NewCommandService] method instead.
|
||||||
|
type CommandService struct {
|
||||||
|
Options []option.RequestOption
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCommandService generates a new service that applies the given options to each
|
||||||
|
// request. These options are applied after the parent client's options (if there
|
||||||
|
// is one), and before any request-specific options.
|
||||||
|
func NewCommandService(opts ...option.RequestOption) (r *CommandService) {
|
||||||
|
r = &CommandService{}
|
||||||
|
r.Options = opts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all commands
|
||||||
|
func (r *CommandService) List(ctx context.Context, opts ...option.RequestOption) (res *[]Command, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
path := "command"
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
Name string `json:"name,required"`
|
||||||
|
Template string `json:"template,required"`
|
||||||
|
Agent string `json:"agent"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
JSON commandJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// commandJSON contains the JSON metadata for the struct [Command]
|
||||||
|
type commandJSON struct {
|
||||||
|
Name apijson.Field
|
||||||
|
Template apijson.Field
|
||||||
|
Agent apijson.Field
|
||||||
|
Description apijson.Field
|
||||||
|
Model apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Command) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r commandJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
36
packages/sdk/go/command_test.go
Normal file
36
packages/sdk/go/command_test.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||||
|
|
||||||
|
package opencode_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sst/opencode-sdk-go"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/testutil"
|
||||||
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCommandList(t *testing.T) {
|
||||||
|
t.Skip("skipped: tests are disabled for the time being")
|
||||||
|
baseURL := "http://localhost:4010"
|
||||||
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
|
baseURL = envURL
|
||||||
|
}
|
||||||
|
if !testutil.CheckTestServer(t, baseURL) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client := opencode.NewClient(
|
||||||
|
option.WithBaseURL(baseURL),
|
||||||
|
)
|
||||||
|
_, err := client.Command.List(context.TODO())
|
||||||
|
if err != nil {
|
||||||
|
var apierr *opencode.Error
|
||||||
|
if errors.As(err, &apierr) {
|
||||||
|
t.Log(string(apierr.DumpRequest(true)))
|
||||||
|
}
|
||||||
|
t.Fatalf("err should be nil: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,7 +49,8 @@ type Config struct {
|
|||||||
// automatically
|
// automatically
|
||||||
Autoshare bool `json:"autoshare"`
|
Autoshare bool `json:"autoshare"`
|
||||||
// Automatically update to the latest version
|
// Automatically update to the latest version
|
||||||
Autoupdate bool `json:"autoupdate"`
|
Autoupdate bool `json:"autoupdate"`
|
||||||
|
Command map[string]ConfigCommand `json:"command"`
|
||||||
// Disable providers that are loaded automatically
|
// Disable providers that are loaded automatically
|
||||||
DisabledProviders []string `json:"disabled_providers"`
|
DisabledProviders []string `json:"disabled_providers"`
|
||||||
Experimental ConfigExperimental `json:"experimental"`
|
Experimental ConfigExperimental `json:"experimental"`
|
||||||
@@ -94,6 +95,7 @@ type configJSON struct {
|
|||||||
Agent apijson.Field
|
Agent apijson.Field
|
||||||
Autoshare apijson.Field
|
Autoshare apijson.Field
|
||||||
Autoupdate apijson.Field
|
Autoupdate apijson.Field
|
||||||
|
Command apijson.Field
|
||||||
DisabledProviders apijson.Field
|
DisabledProviders apijson.Field
|
||||||
Experimental apijson.Field
|
Experimental apijson.Field
|
||||||
Formatter apijson.Field
|
Formatter apijson.Field
|
||||||
@@ -664,6 +666,32 @@ func (r ConfigAgentPlanPermissionWebfetch) IsKnown() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ConfigCommand struct {
|
||||||
|
Template string `json:"template,required"`
|
||||||
|
Agent string `json:"agent"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
JSON configCommandJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// configCommandJSON contains the JSON metadata for the struct [ConfigCommand]
|
||||||
|
type configCommandJSON struct {
|
||||||
|
Template apijson.Field
|
||||||
|
Agent apijson.Field
|
||||||
|
Description apijson.Field
|
||||||
|
Model apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ConfigCommand) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r configCommandJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
type ConfigExperimental struct {
|
type ConfigExperimental struct {
|
||||||
Hook ConfigExperimentalHook `json:"hook"`
|
Hook ConfigExperimentalHook `json:"hook"`
|
||||||
JSON configExperimentalJSON `json:"-"`
|
JSON configExperimentalJSON `json:"-"`
|
||||||
|
|||||||
@@ -114,6 +114,18 @@ func (r *SessionService) Children(ctx context.Context, id string, opts ...option
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send a new command to a session
|
||||||
|
func (r *SessionService) Command(ctx context.Context, id string, body SessionCommandParams, opts ...option.RequestOption) (res *SessionCommandResponse, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
if id == "" {
|
||||||
|
err = errors.New("missing required id parameter")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
path := fmt.Sprintf("session/%s/command", id)
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Get session
|
// Get session
|
||||||
func (r *SessionService) Get(ctx context.Context, id string, opts ...option.RequestOption) (res *Session, err error) {
|
func (r *SessionService) Get(ctx context.Context, id string, opts ...option.RequestOption) (res *Session, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
@@ -2301,6 +2313,29 @@ func (r sessionChatResponseJSON) RawJSON() string {
|
|||||||
return r.raw
|
return r.raw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SessionCommandResponse struct {
|
||||||
|
Info AssistantMessage `json:"info,required"`
|
||||||
|
Parts []Part `json:"parts,required"`
|
||||||
|
JSON sessionCommandResponseJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// sessionCommandResponseJSON contains the JSON metadata for the struct
|
||||||
|
// [SessionCommandResponse]
|
||||||
|
type sessionCommandResponseJSON struct {
|
||||||
|
Info apijson.Field
|
||||||
|
Parts apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SessionCommandResponse) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r sessionCommandResponseJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
type SessionMessageResponse struct {
|
type SessionMessageResponse struct {
|
||||||
Info Message `json:"info,required"`
|
Info Message `json:"info,required"`
|
||||||
Parts []Part `json:"parts,required"`
|
Parts []Part `json:"parts,required"`
|
||||||
@@ -2419,6 +2454,18 @@ func (r SessionChatParamsPartsType) IsKnown() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SessionCommandParams struct {
|
||||||
|
Arguments param.Field[string] `json:"arguments,required"`
|
||||||
|
Command param.Field[string] `json:"command,required"`
|
||||||
|
Agent param.Field[string] `json:"agent"`
|
||||||
|
MessageID param.Field[string] `json:"messageID"`
|
||||||
|
Model param.Field[string] `json:"model"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r SessionCommandParams) MarshalJSON() (data []byte, err error) {
|
||||||
|
return apijson.MarshalRoot(r)
|
||||||
|
}
|
||||||
|
|
||||||
type SessionInitParams struct {
|
type SessionInitParams struct {
|
||||||
MessageID param.Field[string] `json:"messageID,required"`
|
MessageID param.Field[string] `json:"messageID,required"`
|
||||||
ModelID param.Field[string] `json:"modelID,required"`
|
ModelID param.Field[string] `json:"modelID,required"`
|
||||||
|
|||||||
@@ -199,6 +199,38 @@ func TestSessionChildren(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSessionCommandWithOptionalParams(t *testing.T) {
|
||||||
|
t.Skip("skipped: tests are disabled for the time being")
|
||||||
|
baseURL := "http://localhost:4010"
|
||||||
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
|
baseURL = envURL
|
||||||
|
}
|
||||||
|
if !testutil.CheckTestServer(t, baseURL) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client := opencode.NewClient(
|
||||||
|
option.WithBaseURL(baseURL),
|
||||||
|
)
|
||||||
|
_, err := client.Session.Command(
|
||||||
|
context.TODO(),
|
||||||
|
"id",
|
||||||
|
opencode.SessionCommandParams{
|
||||||
|
Arguments: opencode.F("arguments"),
|
||||||
|
Command: opencode.F("command"),
|
||||||
|
Agent: opencode.F("agent"),
|
||||||
|
MessageID: opencode.F("msg"),
|
||||||
|
Model: opencode.F("model"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
var apierr *opencode.Error
|
||||||
|
if errors.As(err, &apierr) {
|
||||||
|
t.Log(string(apierr.DumpRequest(true)))
|
||||||
|
}
|
||||||
|
t.Fatalf("err should be nil: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSessionGet(t *testing.T) {
|
func TestSessionGet(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("skipped: tests are disabled for the time being")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ import type {
|
|||||||
SessionChatResponses,
|
SessionChatResponses,
|
||||||
SessionMessageData,
|
SessionMessageData,
|
||||||
SessionMessageResponses,
|
SessionMessageResponses,
|
||||||
|
SessionCommandData,
|
||||||
|
SessionCommandResponses,
|
||||||
SessionShellData,
|
SessionShellData,
|
||||||
SessionShellResponses,
|
SessionShellResponses,
|
||||||
SessionRevertData,
|
SessionRevertData,
|
||||||
@@ -47,6 +49,8 @@ import type {
|
|||||||
SessionUnrevertResponses,
|
SessionUnrevertResponses,
|
||||||
PostSessionByIdPermissionsByPermissionIdData,
|
PostSessionByIdPermissionsByPermissionIdData,
|
||||||
PostSessionByIdPermissionsByPermissionIdResponses,
|
PostSessionByIdPermissionsByPermissionIdResponses,
|
||||||
|
CommandListData,
|
||||||
|
CommandListResponses,
|
||||||
ConfigProvidersData,
|
ConfigProvidersData,
|
||||||
ConfigProvidersResponses,
|
ConfigProvidersResponses,
|
||||||
FindTextData,
|
FindTextData,
|
||||||
@@ -355,6 +359,20 @@ class Session extends _HeyApiClient {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a new command to a session
|
||||||
|
*/
|
||||||
|
public command<ThrowOnError extends boolean = false>(options: Options<SessionCommandData, ThrowOnError>) {
|
||||||
|
return (options.client ?? this._client).post<SessionCommandResponses, unknown, ThrowOnError>({
|
||||||
|
url: "/session/{id}/command",
|
||||||
|
...options,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...options.headers,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run a shell command
|
* Run a shell command
|
||||||
*/
|
*/
|
||||||
@@ -394,6 +412,18 @@ class Session extends _HeyApiClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Command extends _HeyApiClient {
|
||||||
|
/**
|
||||||
|
* List all commands
|
||||||
|
*/
|
||||||
|
public list<ThrowOnError extends boolean = false>(options?: Options<CommandListData, ThrowOnError>) {
|
||||||
|
return (options?.client ?? this._client).get<CommandListResponses, unknown, ThrowOnError>({
|
||||||
|
url: "/command",
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Find extends _HeyApiClient {
|
class Find extends _HeyApiClient {
|
||||||
/**
|
/**
|
||||||
* Find text in files
|
* Find text in files
|
||||||
@@ -592,6 +622,7 @@ export class OpencodeClient extends _HeyApiClient {
|
|||||||
app = new App({ client: this._client })
|
app = new App({ client: this._client })
|
||||||
config = new Config({ client: this._client })
|
config = new Config({ client: this._client })
|
||||||
session = new Session({ client: this._client })
|
session = new Session({ client: this._client })
|
||||||
|
command = new Command({ client: this._client })
|
||||||
find = new Find({ client: this._client })
|
find = new Find({ client: this._client })
|
||||||
file = new File({ client: this._client })
|
file = new File({ client: this._client })
|
||||||
tui = new Tui({ client: this._client })
|
tui = new Tui({ client: this._client })
|
||||||
|
|||||||
@@ -585,6 +585,14 @@ export type Config = {
|
|||||||
*/
|
*/
|
||||||
scroll_speed: number
|
scroll_speed: number
|
||||||
}
|
}
|
||||||
|
command?: {
|
||||||
|
[key: string]: {
|
||||||
|
template: string
|
||||||
|
description?: string
|
||||||
|
agent?: string
|
||||||
|
model?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
plugin?: Array<string>
|
plugin?: Array<string>
|
||||||
snapshot?: boolean
|
snapshot?: boolean
|
||||||
/**
|
/**
|
||||||
@@ -1110,6 +1118,14 @@ export type AgentPartInput = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Command = {
|
||||||
|
name: string
|
||||||
|
description?: string
|
||||||
|
agent?: string
|
||||||
|
model?: string
|
||||||
|
template: string
|
||||||
|
}
|
||||||
|
|
||||||
export type Symbol = {
|
export type Symbol = {
|
||||||
name: string
|
name: string
|
||||||
kind: number
|
kind: number
|
||||||
@@ -1563,6 +1579,36 @@ export type SessionMessageResponses = {
|
|||||||
|
|
||||||
export type SessionMessageResponse = SessionMessageResponses[keyof SessionMessageResponses]
|
export type SessionMessageResponse = SessionMessageResponses[keyof SessionMessageResponses]
|
||||||
|
|
||||||
|
export type SessionCommandData = {
|
||||||
|
body?: {
|
||||||
|
messageID?: string
|
||||||
|
agent?: string
|
||||||
|
model?: string
|
||||||
|
arguments: string
|
||||||
|
command: string
|
||||||
|
}
|
||||||
|
path: {
|
||||||
|
/**
|
||||||
|
* Session ID
|
||||||
|
*/
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
query?: never
|
||||||
|
url: "/session/{id}/command"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SessionCommandResponses = {
|
||||||
|
/**
|
||||||
|
* Created message
|
||||||
|
*/
|
||||||
|
200: {
|
||||||
|
info: AssistantMessage
|
||||||
|
parts: Array<Part>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SessionCommandResponse = SessionCommandResponses[keyof SessionCommandResponses]
|
||||||
|
|
||||||
export type SessionShellData = {
|
export type SessionShellData = {
|
||||||
body?: {
|
body?: {
|
||||||
agent: string
|
agent: string
|
||||||
@@ -1648,6 +1694,22 @@ export type PostSessionByIdPermissionsByPermissionIdResponses = {
|
|||||||
export type PostSessionByIdPermissionsByPermissionIdResponse =
|
export type PostSessionByIdPermissionsByPermissionIdResponse =
|
||||||
PostSessionByIdPermissionsByPermissionIdResponses[keyof PostSessionByIdPermissionsByPermissionIdResponses]
|
PostSessionByIdPermissionsByPermissionIdResponses[keyof PostSessionByIdPermissionsByPermissionIdResponses]
|
||||||
|
|
||||||
|
export type CommandListData = {
|
||||||
|
body?: never
|
||||||
|
path?: never
|
||||||
|
query?: never
|
||||||
|
url: "/command"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CommandListResponses = {
|
||||||
|
/**
|
||||||
|
* List of commands
|
||||||
|
*/
|
||||||
|
200: Array<Command>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CommandListResponse = CommandListResponses[keyof CommandListResponses]
|
||||||
|
|
||||||
export type ConfigProvidersData = {
|
export type ConfigProvidersData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
|
|||||||
@@ -85,6 +85,12 @@ resources:
|
|||||||
methods:
|
methods:
|
||||||
get: get /config
|
get: get /config
|
||||||
|
|
||||||
|
command:
|
||||||
|
models:
|
||||||
|
command: Command
|
||||||
|
methods:
|
||||||
|
list: get /command
|
||||||
|
|
||||||
session:
|
session:
|
||||||
models:
|
models:
|
||||||
session: Session
|
session: Session
|
||||||
@@ -126,6 +132,7 @@ resources:
|
|||||||
message: get /session/{id}/message/{messageID}
|
message: get /session/{id}/message/{messageID}
|
||||||
messages: get /session/{id}/message
|
messages: get /session/{id}/message
|
||||||
chat: post /session/{id}/message
|
chat: post /session/{id}/message
|
||||||
|
command: post /session/{id}/command
|
||||||
shell: post /session/{id}/shell
|
shell: post /session/{id}/shell
|
||||||
update: patch /session/{id}
|
update: patch /session/{id}
|
||||||
revert: post /session/{id}/revert
|
revert: post /session/{id}/revert
|
||||||
|
|||||||
@@ -84,6 +84,10 @@ type SendPrompt = Prompt
|
|||||||
type SendShell = struct {
|
type SendShell = struct {
|
||||||
Command string
|
Command string
|
||||||
}
|
}
|
||||||
|
type SendCommand = struct {
|
||||||
|
Command string
|
||||||
|
Args string
|
||||||
|
}
|
||||||
type SetEditorContentMsg struct {
|
type SetEditorContentMsg struct {
|
||||||
Text string
|
Text string
|
||||||
}
|
}
|
||||||
@@ -183,6 +187,11 @@ func New(
|
|||||||
|
|
||||||
slog.Debug("Loaded config", "config", configInfo)
|
slog.Debug("Loaded config", "config", configInfo)
|
||||||
|
|
||||||
|
customCommands, err := httpClient.Command.List(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
app := &App{
|
app := &App{
|
||||||
Info: appInfo,
|
Info: appInfo,
|
||||||
Agents: agents,
|
Agents: agents,
|
||||||
@@ -194,7 +203,7 @@ func New(
|
|||||||
AgentIndex: agentIndex,
|
AgentIndex: agentIndex,
|
||||||
Session: &opencode.Session{},
|
Session: &opencode.Session{},
|
||||||
Messages: []Message{},
|
Messages: []Message{},
|
||||||
Commands: commands.LoadFromConfig(configInfo),
|
Commands: commands.LoadFromConfig(configInfo, *customCommands),
|
||||||
InitialModel: initialModel,
|
InitialModel: initialModel,
|
||||||
InitialPrompt: initialPrompt,
|
InitialPrompt: initialPrompt,
|
||||||
InitialAgent: initialAgent,
|
InitialAgent: initialAgent,
|
||||||
@@ -793,6 +802,38 @@ func (a *App) SendPrompt(ctx context.Context, prompt Prompt) (*App, tea.Cmd) {
|
|||||||
return a, tea.Batch(cmds...)
|
return a, tea.Batch(cmds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) SendCommand(ctx context.Context, command string, args string) (*App, tea.Cmd) {
|
||||||
|
var cmds []tea.Cmd
|
||||||
|
if a.Session.ID == "" {
|
||||||
|
session, err := a.CreateSession(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return a, toast.NewErrorToast(err.Error())
|
||||||
|
}
|
||||||
|
a.Session = session
|
||||||
|
cmds = append(cmds, util.CmdHandler(SessionCreatedMsg{Session: session}))
|
||||||
|
}
|
||||||
|
|
||||||
|
cmds = append(cmds, func() tea.Msg {
|
||||||
|
_, err := a.Client.Session.Command(
|
||||||
|
context.Background(),
|
||||||
|
a.Session.ID,
|
||||||
|
opencode.SessionCommandParams{
|
||||||
|
Command: opencode.F(command),
|
||||||
|
Arguments: opencode.F(args),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to execute command", "error", err)
|
||||||
|
return toast.NewErrorToast("Failed to execute command")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// The actual response will come through SSE
|
||||||
|
// For now, just return success
|
||||||
|
return a, tea.Batch(cmds...)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) SendShell(ctx context.Context, command string) (*App, tea.Cmd) {
|
func (a *App) SendShell(ctx context.Context, command string) (*App, tea.Cmd) {
|
||||||
var cmds []tea.Cmd
|
var cmds []tea.Cmd
|
||||||
if a.Session.ID == "" {
|
if a.Session.ID == "" {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type Command struct {
|
|||||||
Description string
|
Description string
|
||||||
Keybindings []Keybinding
|
Keybindings []Keybinding
|
||||||
Trigger []string
|
Trigger []string
|
||||||
|
Custom bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Command) Keys() []string {
|
func (c Command) Keys() []string {
|
||||||
@@ -96,6 +97,7 @@ func (r CommandRegistry) Sorted() []Command {
|
|||||||
})
|
})
|
||||||
return commands
|
return commands
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r CommandRegistry) Matches(msg tea.KeyPressMsg, leader bool) []Command {
|
func (r CommandRegistry) Matches(msg tea.KeyPressMsg, leader bool) []Command {
|
||||||
var matched []Command
|
var matched []Command
|
||||||
for _, command := range r.Sorted() {
|
for _, command := range r.Sorted() {
|
||||||
@@ -182,7 +184,7 @@ func parseBindings(bindings ...string) []Keybinding {
|
|||||||
return parsedBindings
|
return parsedBindings
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadFromConfig(config *opencode.Config) CommandRegistry {
|
func LoadFromConfig(config *opencode.Config, customCommands []opencode.Command) CommandRegistry {
|
||||||
defaults := []Command{
|
defaults := []Command{
|
||||||
{
|
{
|
||||||
Name: AppHelpCommand,
|
Name: AppHelpCommand,
|
||||||
@@ -400,6 +402,16 @@ func LoadFromConfig(config *opencode.Config) CommandRegistry {
|
|||||||
}
|
}
|
||||||
registry[command.Name] = command
|
registry[command.Name] = command
|
||||||
}
|
}
|
||||||
|
for _, command := range customCommands {
|
||||||
|
registry[CommandName(command.Name)] = Command{
|
||||||
|
Name: CommandName(command.Name),
|
||||||
|
Description: command.Description,
|
||||||
|
Trigger: []string{command.Name},
|
||||||
|
Keybindings: []Keybinding{},
|
||||||
|
Custom: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
slog.Info("Loaded commands", "commands", registry)
|
slog.Info("Loaded commands", "commands", registry)
|
||||||
return registry
|
return registry
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -224,10 +224,17 @@ func (m *editorComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
case dialog.CompletionSelectedMsg:
|
case dialog.CompletionSelectedMsg:
|
||||||
switch msg.Item.ProviderID {
|
switch msg.Item.ProviderID {
|
||||||
case "commands":
|
case "commands":
|
||||||
commandName := strings.TrimPrefix(msg.Item.Value, "/")
|
command := msg.Item.RawData.(commands.Command)
|
||||||
|
if command.Custom {
|
||||||
|
m.SetValue("/" + command.PrimaryTrigger() + " ")
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
updated, cmd := m.Clear()
|
updated, cmd := m.Clear()
|
||||||
m = updated.(*editorComponent)
|
m = updated.(*editorComponent)
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
|
|
||||||
|
commandName := strings.TrimPrefix(msg.Item.Value, "/")
|
||||||
cmds = append(cmds, util.CmdHandler(commands.ExecuteCommandMsg(m.app.Commands[commands.CommandName(commandName)])))
|
cmds = append(cmds, util.CmdHandler(commands.ExecuteCommandMsg(m.app.Commands[commands.CommandName(commandName)])))
|
||||||
return m, tea.Batch(cmds...)
|
return m, tea.Batch(cmds...)
|
||||||
case "files":
|
case "files":
|
||||||
@@ -481,6 +488,25 @@ func (m *editorComponent) Submit() (tea.Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var cmds []tea.Cmd
|
var cmds []tea.Cmd
|
||||||
|
if strings.HasPrefix(value, "/") {
|
||||||
|
value = value[1:]
|
||||||
|
commandName := strings.Split(value, " ")[0]
|
||||||
|
command := m.app.Commands[commands.CommandName(commandName)]
|
||||||
|
if command.Custom {
|
||||||
|
args := strings.TrimPrefix(value, command.PrimaryTrigger()+" ")
|
||||||
|
cmds = append(
|
||||||
|
cmds,
|
||||||
|
util.CmdHandler(app.SendCommand{Command: string(command.Name), Args: args}),
|
||||||
|
)
|
||||||
|
|
||||||
|
updated, cmd := m.Clear()
|
||||||
|
m = updated.(*editorComponent)
|
||||||
|
cmds = append(cmds, cmd)
|
||||||
|
|
||||||
|
return m, tea.Batch(cmds...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
attachments := m.textarea.GetAttachments()
|
attachments := m.textarea.GetAttachments()
|
||||||
|
|
||||||
prompt := app.Prompt{Text: value, Attachments: attachments}
|
prompt := app.Prompt{Text: value, Attachments: attachments}
|
||||||
|
|||||||
@@ -174,6 +174,10 @@ func (m *messagesComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
m.viewport.GotoBottom()
|
m.viewport.GotoBottom()
|
||||||
m.tail = true
|
m.tail = true
|
||||||
return m, nil
|
return m, nil
|
||||||
|
case app.SendCommand:
|
||||||
|
m.viewport.GotoBottom()
|
||||||
|
m.tail = true
|
||||||
|
return m, nil
|
||||||
case dialog.ThemeSelectedMsg:
|
case dialog.ThemeSelectedMsg:
|
||||||
m.cache.Clear()
|
m.cache.Clear()
|
||||||
m.loading = true
|
m.loading = true
|
||||||
|
|||||||
@@ -408,6 +408,24 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
a.app, cmd = a.app.SendPrompt(context.Background(), msg)
|
a.app, cmd = a.app.SendPrompt(context.Background(), msg)
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
}
|
}
|
||||||
|
case app.SendCommand:
|
||||||
|
// If we're in a child session, switch back to parent before sending prompt
|
||||||
|
if a.app.Session.ParentID != "" {
|
||||||
|
parentSession, err := a.app.Client.Session.Get(context.Background(), a.app.Session.ParentID)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to get parent session", "error", err)
|
||||||
|
return a, toast.NewErrorToast("Failed to get parent session")
|
||||||
|
}
|
||||||
|
a.app.Session = parentSession
|
||||||
|
a.app, cmd = a.app.SendCommand(context.Background(), msg.Command, msg.Args)
|
||||||
|
cmds = append(cmds, tea.Sequence(
|
||||||
|
util.CmdHandler(app.SessionSelectedMsg(parentSession)),
|
||||||
|
cmd,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
a.app, cmd = a.app.SendCommand(context.Background(), msg.Command, msg.Args)
|
||||||
|
cmds = append(cmds, cmd)
|
||||||
|
}
|
||||||
case app.SendShell:
|
case app.SendShell:
|
||||||
// If we're in a child session, switch back to parent before sending prompt
|
// If we're in a child session, switch back to parent before sending prompt
|
||||||
if a.app.Session.ParentID != "" {
|
if a.app.Session.ParentID != "" {
|
||||||
|
|||||||
@@ -67,14 +67,7 @@ export default defineConfig({
|
|||||||
|
|
||||||
{
|
{
|
||||||
label: "Usage",
|
label: "Usage",
|
||||||
items: [
|
items: ["docs/tui", "docs/cli", "docs/ide", "docs/share", "docs/github", "docs/gitlab"],
|
||||||
"docs/tui",
|
|
||||||
"docs/cli",
|
|
||||||
"docs/ide",
|
|
||||||
"docs/share",
|
|
||||||
"docs/github",
|
|
||||||
"docs/gitlab"
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
167
packages/web/src/content/docs/docs/commands.mdx
Normal file
167
packages/web/src/content/docs/docs/commands.mdx
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
---
|
||||||
|
title: Commands
|
||||||
|
description: Create custom commands for repetitive tasks.
|
||||||
|
---
|
||||||
|
|
||||||
|
Define custom commands to automate repetitive coding tasks.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Create command files
|
||||||
|
|
||||||
|
Create markdown files in the `command/` directory to define custom commands.
|
||||||
|
|
||||||
|
Create `.opencode/command/test.md`:
|
||||||
|
|
||||||
|
```md
|
||||||
|
---
|
||||||
|
description: Run tests with coverage
|
||||||
|
agent: build
|
||||||
|
model: anthropic/claude-3-5-sonnet-20241022
|
||||||
|
---
|
||||||
|
|
||||||
|
Run the full test suite with coverage report and show any failures.
|
||||||
|
Focus on the failing tests and suggest fixes.
|
||||||
|
```
|
||||||
|
|
||||||
|
The frontmatter defines command properties. The content becomes the template.
|
||||||
|
|
||||||
|
Use the command by typing `/` followed by the command name.
|
||||||
|
|
||||||
|
```bash frame="none"
|
||||||
|
"/test"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Create command files
|
||||||
|
|
||||||
|
For complex commands, create markdown files in the `command/` directory.
|
||||||
|
|
||||||
|
Create `.opencode/command/test.md`:
|
||||||
|
|
||||||
|
```md
|
||||||
|
---
|
||||||
|
description: Run tests with coverage
|
||||||
|
agent: build
|
||||||
|
model: anthropic/claude-3-5-sonnet-20241022
|
||||||
|
---
|
||||||
|
|
||||||
|
Run the full test suite with coverage report and show any failures.
|
||||||
|
Focus on the failing tests and suggest fixes.
|
||||||
|
```
|
||||||
|
|
||||||
|
The frontmatter defines command properties. The content becomes the template.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Use arguments
|
||||||
|
|
||||||
|
Pass arguments to commands using the `$ARGUMENTS` placeholder.
|
||||||
|
|
||||||
|
```md
|
||||||
|
---
|
||||||
|
description: Create a new component
|
||||||
|
---
|
||||||
|
|
||||||
|
Create a new React component named $ARGUMENTS with TypeScript support.
|
||||||
|
Include proper typing and basic structure.
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the command with arguments:
|
||||||
|
|
||||||
|
```bash frame="none"
|
||||||
|
"/component Button"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Inject shell output
|
||||||
|
|
||||||
|
Use `!`command`` to inject shell command output into your prompt.
|
||||||
|
|
||||||
|
```md
|
||||||
|
---
|
||||||
|
description: Analyze test coverage
|
||||||
|
---
|
||||||
|
|
||||||
|
Here are the current test results:
|
||||||
|
`!npm test`
|
||||||
|
|
||||||
|
Based on these results, suggest improvements to increase coverage.
|
||||||
|
```
|
||||||
|
|
||||||
|
```md
|
||||||
|
---
|
||||||
|
description: Review recent changes
|
||||||
|
---
|
||||||
|
|
||||||
|
Recent git commits:
|
||||||
|
`!git log --oneline -10`
|
||||||
|
|
||||||
|
Review these changes and suggest any improvements.
|
||||||
|
```
|
||||||
|
|
||||||
|
Commands run in your project's root directory and their output becomes part of the prompt.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reference files
|
||||||
|
|
||||||
|
Include files in your command using `@` followed by the filename.
|
||||||
|
|
||||||
|
```md
|
||||||
|
---
|
||||||
|
description: Review component
|
||||||
|
---
|
||||||
|
|
||||||
|
Review the component in @src/components/Button.tsx.
|
||||||
|
Check for performance issues and suggest improvements.
|
||||||
|
```
|
||||||
|
|
||||||
|
The file content gets included in the prompt automatically.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Command properties
|
||||||
|
|
||||||
|
Configure commands with these optional frontmatter properties:
|
||||||
|
|
||||||
|
- **description**: Brief explanation of what the command does
|
||||||
|
- **agent**: Agent to use (defaults to "build")
|
||||||
|
- **model**: Specific model to use for this command
|
||||||
|
|
||||||
|
```md
|
||||||
|
---
|
||||||
|
description: Code review assistant
|
||||||
|
agent: build
|
||||||
|
model: anthropic/claude-3-5-sonnet-20241022
|
||||||
|
---
|
||||||
|
|
||||||
|
Review the code for best practices and suggest improvements.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Command directory
|
||||||
|
|
||||||
|
Store command files in these locations:
|
||||||
|
|
||||||
|
- `.opencode/command/` - Project-specific commands
|
||||||
|
- `command/` - Global commands in config directory
|
||||||
|
|
||||||
|
Project commands take precedence over global ones.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Built-in commands
|
||||||
|
|
||||||
|
opencode includes several built-in commands:
|
||||||
|
|
||||||
|
- `/init` - Initialize project and create AGENTS.md
|
||||||
|
- `/undo` - Revert the last changes
|
||||||
|
- `/redo` - Restore reverted changes
|
||||||
|
- `/share` - Share the current conversation
|
||||||
|
- `/help` - Show available commands and keybinds
|
||||||
|
|
||||||
|
Use `/help` to see all available commands in your setup.
|
||||||
@@ -41,26 +41,10 @@ You can also install it with the following:
|
|||||||
- **Using Node.js**
|
- **Using Node.js**
|
||||||
|
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<TabItem label="npm">
|
<TabItem label="npm">```bash npm install -g opencode-ai ```</TabItem>
|
||||||
```bash
|
<TabItem label="Bun">```bash bun install -g opencode-ai ```</TabItem>
|
||||||
npm install -g opencode-ai
|
<TabItem label="pnpm">```bash pnpm install -g opencode-ai ```</TabItem>
|
||||||
```
|
<TabItem label="Yarn">```bash yarn global add opencode-ai ```</TabItem>
|
||||||
</TabItem>
|
|
||||||
<TabItem label="Bun">
|
|
||||||
```bash
|
|
||||||
bun install -g opencode-ai
|
|
||||||
```
|
|
||||||
</TabItem>
|
|
||||||
<TabItem label="pnpm">
|
|
||||||
```bash
|
|
||||||
pnpm install -g opencode-ai
|
|
||||||
```
|
|
||||||
</TabItem>
|
|
||||||
<TabItem label="Yarn">
|
|
||||||
```bash
|
|
||||||
yarn global add opencode-ai
|
|
||||||
```
|
|
||||||
</TabItem>
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
- **Using Homebrew on macOS and Linux**
|
- **Using Homebrew on macOS and Linux**
|
||||||
@@ -308,4 +292,4 @@ Here's an [example conversation](https://opencode.ai/s/4XP1fce5) with opencode.
|
|||||||
|
|
||||||
And that's it! You are now a pro at using opencode.
|
And that's it! You are now a pro at using opencode.
|
||||||
|
|
||||||
To make it your own, we recommend [picking a theme](/docs/themes), [customizing the keybinds](/docs/keybinds), [configuring code formatters](/docs/formatters), or playing around with the [opencode config](/docs/config).
|
To make it your own, we recommend [picking a theme](/docs/themes), [customizing the keybinds](/docs/keybinds), [configuring code formatters](/docs/formatters), [creating custom commands](/docs/commands), or playing around with the [opencode config](/docs/config).
|
||||||
|
|||||||
Reference in New Issue
Block a user