mirror of
https://fastgit.cc/https://github.com/anomalyco/opencode
synced 2026-05-02 23:04:07 +08:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30e10127f2 | ||
|
|
5e66fc2318 | ||
|
|
c1c99c7e0f | ||
|
|
04e3e83db3 | ||
|
|
4273714a62 | ||
|
|
a21e237706 | ||
|
|
aa9105649d | ||
|
|
53be288040 | ||
|
|
13dbf912ca | ||
|
|
69966c73f8 | ||
|
|
a00de2df08 | ||
|
|
5e72f50554 | ||
|
|
d558f15c91 | ||
|
|
614a23698f | ||
|
|
a2191ce6fb | ||
|
|
168350c981 | ||
|
|
f5f55062f1 | ||
|
|
360194e219 | ||
|
|
5ee994c31f | ||
|
|
fc73d4b1f9 | ||
|
|
936f4cb0c6 | ||
|
|
a5b20f973f | ||
|
|
872b1e068f | ||
|
|
e4e0b8fd34 | ||
|
|
c5368e7412 | ||
|
|
1d682544b9 | ||
|
|
d9210af98c | ||
|
|
ef633fe92e | ||
|
|
5500698734 | ||
|
|
e7631763f3 | ||
|
|
18a572b079 | ||
|
|
060a62ecfb | ||
|
|
ac3813549a | ||
|
|
b14da5fb1f | ||
|
|
416f2235fc | ||
|
|
4fabca426a | ||
|
|
7e9050edb9 | ||
|
|
3c49a9b7dd | ||
|
|
ad66b97463 | ||
|
|
10a0b7f60c | ||
|
|
ac8709ac7a | ||
|
|
2d9ed06367 | ||
|
|
50be2aee39 |
8
.github/workflows/publish.yml
vendored
8
.github/workflows/publish.yml
vendored
@@ -1,4 +1,5 @@
|
||||
name: publish
|
||||
run-name: "${{ format('v{0}', inputs.version) }}"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -7,6 +8,10 @@ on:
|
||||
description: "Version to publish"
|
||||
required: true
|
||||
type: string
|
||||
title:
|
||||
description: "Custom title for this run"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
@@ -32,7 +37,7 @@ jobs:
|
||||
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.2.17
|
||||
bun-version: 1.2.19
|
||||
|
||||
- name: Install makepkg
|
||||
run: |
|
||||
@@ -52,7 +57,6 @@ jobs:
|
||||
run: |
|
||||
bun install
|
||||
OPENCODE_VERSION=${{ inputs.version }} ./script/publish.ts
|
||||
working-directory: ./packages/opencode
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
|
||||
AUR_KEY: ${{ secrets.AUR_KEY }}
|
||||
|
||||
2
.github/workflows/stats.yml
vendored
2
.github/workflows/stats.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
bun-version: latest
|
||||
|
||||
- name: Run stats script
|
||||
run: bun scripts/stats.ts
|
||||
run: bun script/stats.ts
|
||||
|
||||
- name: Commit stats
|
||||
run: |
|
||||
|
||||
1
STATS.md
1
STATS.md
@@ -32,3 +32,4 @@
|
||||
| 2025-07-28 | 105,446 (+2,802) | 136,016 (+1,280) | 241,462 (+4,082) |
|
||||
| 2025-07-29 | 108,998 (+3,552) | 137,542 (+1,526) | 246,540 (+5,078) |
|
||||
| 2025-07-30 | 113,544 (+4,546) | 140,317 (+2,775) | 253,861 (+7,321) |
|
||||
| 2025-07-31 | 118,339 (+4,795) | 143,344 (+3,027) | 261,683 (+7,822) |
|
||||
|
||||
171
bun.lock
171
bun.lock
@@ -25,7 +25,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "opencode",
|
||||
"version": "0.0.5",
|
||||
"version": "0.0.0",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -47,6 +47,8 @@
|
||||
"hono": "catalog:",
|
||||
"hono-openapi": "0.4.8",
|
||||
"isomorphic-git": "1.32.1",
|
||||
"jsonc-parser": "3.3.1",
|
||||
"minimatch": "10.0.3",
|
||||
"open": "10.1.2",
|
||||
"remeda": "catalog:",
|
||||
"tree-sitter": "0.22.4",
|
||||
@@ -78,6 +80,7 @@
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.80.1",
|
||||
"@tsconfig/node22": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/web": {
|
||||
@@ -159,11 +162,11 @@
|
||||
|
||||
"@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.1", "", { "dependencies": { "@astrojs/internal-helpers": "0.6.1", "@astrojs/prism": "3.2.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.1.0", "js-yaml": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.1", "remark-smartypants": "^3.0.2", "shiki": "^3.0.0", "smol-toml": "^1.3.1", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1", "vfile": "^6.0.3" } }, "sha512-c5F5gGrkczUaTVgmMW9g1YMJGzOtRvjjhw6IfGuxarM6ct09MpwysP10US729dy07gg8y+ofVifezvP3BNsWZg=="],
|
||||
|
||||
"@astrojs/mdx": ["@astrojs/mdx@4.3.0", "", { "dependencies": { "@astrojs/markdown-remark": "6.3.2", "@mdx-js/mdx": "^3.1.0", "acorn": "^8.14.1", "es-module-lexer": "^1.6.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "kleur": "^4.1.5", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.4", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-OGX2KvPeBzjSSKhkCqrUoDMyzFcjKt5nTE5SFw3RdoLf0nrhyCXBQcCyclzWy1+P+XpOamn+p+hm1EhpCRyPxw=="],
|
||||
"@astrojs/mdx": ["@astrojs/mdx@4.3.1", "", { "dependencies": { "@astrojs/markdown-remark": "6.3.3", "@mdx-js/mdx": "^3.1.0", "acorn": "^8.14.1", "es-module-lexer": "^1.6.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "kleur": "^4.1.5", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.4", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-0ynzkFd5p2IFDLPAfAcGizg44WyS0qUr43nP2vQkvrPlpoPEMeeoi1xWiWsVqQNaZ0FOmNqfUviUn52nm9mLag=="],
|
||||
|
||||
"@astrojs/prism": ["@astrojs/prism@3.2.0", "", { "dependencies": { "prismjs": "^1.29.0" } }, "sha512-GilTHKGCW6HMq7y3BUv9Ac7GMe/MO9gi9GW62GzKtth0SwukCu/qp2wLiGpEujhY+VVhaG9v7kv/5vFzvf4NYw=="],
|
||||
|
||||
"@astrojs/sitemap": ["@astrojs/sitemap@3.4.1", "", { "dependencies": { "sitemap": "^8.0.0", "stream-replace-string": "^2.0.0", "zod": "^3.24.2" } }, "sha512-VjZvr1e4FH6NHyyHXOiQgLiw94LnCVY4v06wN/D0gZKchTMkg71GrAHJz81/huafcmavtLkIv26HnpfDq6/h/Q=="],
|
||||
"@astrojs/sitemap": ["@astrojs/sitemap@3.4.2", "", { "dependencies": { "sitemap": "^8.0.0", "stream-replace-string": "^2.0.0", "zod": "^3.24.4" } }, "sha512-wfN2dZzdkto6yaMtOFa/J9gc60YE3wl3rgSBoNJ+MU3lJVUMsDY9xf9uAVi8Mp/zEQKFDSJlQzBvqQUpw0Hf6g=="],
|
||||
|
||||
"@astrojs/solid-js": ["@astrojs/solid-js@5.1.0", "", { "dependencies": { "vite": "^6.3.5", "vite-plugin-solid": "^2.11.6" }, "peerDependencies": { "solid-devtools": "^0.30.1", "solid-js": "^1.8.5" }, "optionalPeers": ["solid-devtools"] }, "sha512-VmPHOU9k7m6HHCT2Y1mNzifilUnttlowBM36frGcfj5wERJE9Ci0QtWJbzdf6AlcoIirb7xVw+ByupU011Di9w=="],
|
||||
|
||||
@@ -203,19 +206,19 @@
|
||||
|
||||
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
|
||||
|
||||
"@babel/helpers": ["@babel/helpers@7.27.6", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.27.6" } }, "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug=="],
|
||||
"@babel/helpers": ["@babel/helpers@7.28.2", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.2" } }, "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw=="],
|
||||
|
||||
"@babel/parser": ["@babel/parser@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.0" }, "bin": "./bin/babel-parser.js" }, "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g=="],
|
||||
|
||||
"@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="],
|
||||
|
||||
"@babel/runtime": ["@babel/runtime@7.27.6", "", {}, "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q=="],
|
||||
"@babel/runtime": ["@babel/runtime@7.28.2", "", {}, "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA=="],
|
||||
|
||||
"@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
|
||||
|
||||
"@babel/traverse": ["@babel/traverse@7.28.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/types": "^7.28.0", "debug": "^4.3.1" } }, "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg=="],
|
||||
|
||||
"@babel/types": ["@babel/types@7.28.1", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ=="],
|
||||
"@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
|
||||
|
||||
"@capsizecss/unpack": ["@capsizecss/unpack@2.4.0", "", { "dependencies": { "blob-to-buffer": "^1.2.8", "cross-fetch": "^3.0.4", "fontkit": "^2.0.2" } }, "sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q=="],
|
||||
|
||||
@@ -225,17 +228,17 @@
|
||||
|
||||
"@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="],
|
||||
|
||||
"@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.3.3", "", { "peerDependencies": { "unenv": "2.0.0-rc.17", "workerd": "^1.20250508.0" }, "optionalPeers": ["workerd"] }, "sha512-/M3MEcj3V2WHIRSW1eAQBPRJ6JnGQHc6JKMAPLkDb7pLs3m6X9ES/+K3ceGqxI6TKeF32AWAi7ls0AYzVxCP0A=="],
|
||||
"@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.5.0", "", { "peerDependencies": { "unenv": "2.0.0-rc.19", "workerd": "^1.20250722.0" }, "optionalPeers": ["workerd"] }, "sha512-CZe9B2VbjIQjBTyc+KoZcN1oUcm4T6GgCXoel9O7647djHuSRAa6sM6G+NdxWArATZgeMMbsvn9C50GCcnIatA=="],
|
||||
|
||||
"@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250709.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-VqwcvnbI8FNCP87ZWNHA3/sAC5U9wMbNnjBG0sHEYzM7B9RPHKYHdVKdBEWhzZXnkQYMK81IHm4CZsK16XxAuQ=="],
|
||||
"@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250730.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-X3egNyTjLQaECYe34x8Al7r4oXAhcN3a8+8qcpNCcq1sgtuHIeAwS9potgRR/mwkGfmrJn7nfAyDKC4vrkniQQ=="],
|
||||
|
||||
"@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250709.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-A54ttSgXMM4huChPTThhkieOjpDxR+srVOO9zjTHVIyoQxA8zVsku4CcY/GQ95RczMV+yCKVVu/tAME7vwBFuA=="],
|
||||
"@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250730.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/4bvcaGY/9v0rghgKboGiyPKKGQTbDnQ1EeY0oN0SSQH0Cp3OBzqwni/JRvh8TEaD+5azJnSFLlFZj9w7fo+hw=="],
|
||||
|
||||
"@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250709.0", "", { "os": "linux", "cpu": "x64" }, "sha512-no4O3OK+VXINIxv99OHJDpIgML2ZssrSvImwLtULzqm+cl4t1PIfXNRUqj89ujTkmad+L9y4G6dBQMPCLnmlGg=="],
|
||||
"@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250730.0", "", { "os": "linux", "cpu": "x64" }, "sha512-I4ZsXYdNkqkJnzNFKADMufiLIzRdIRsN7dSH8UCPw2fYp1BbKA10AkKVqitFwBxIY8eOzQ6Vf7c41AjLQmtJqA=="],
|
||||
|
||||
"@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250709.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-7cNICk2Qd+m4QGrcmWyAuZJXTHt1ud6isA+dic7Yk42WZmwXhlcUATyvFD9FSQNFcldjuRB4n8JlWEFqZBn+lw=="],
|
||||
"@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250730.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-tTpO6139jFQ5vxgtBZgS8Y8R1jVidS4n7s37x5xO9bCWLZoL0kTj38UGZ8FENkTeaMxE9Mm//nbQol7TfJ2nZg=="],
|
||||
|
||||
"@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250709.0", "", { "os": "win32", "cpu": "x64" }, "sha512-j1AyO8V/62Q23EJplWgzBlRCqo/diXgox58AbDqSqgyzCBAlvUzXQRDBab/FPNG/erRqt7I1zQhahrBhrM0uLA=="],
|
||||
"@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250730.0", "", { "os": "win32", "cpu": "x64" }, "sha512-paVHgocuilMzOU+gEyKR/86j/yI+QzmSHRnqdd8OdQ37Hf6SyPX7kQj6VVNRXbzVHWix1WxaJsXfTGK1LK05wA=="],
|
||||
|
||||
"@cloudflare/workers-types": ["@cloudflare/workers-types@4.20250522.0", "", {}, "sha512-9RIffHobc35JWeddzBguGgPa4wLDr5x5F94+0/qy7LiV6pTBQ/M5qGEN9VA16IDT3EUpYI0WKh6VpcmeVEtVtw=="],
|
||||
|
||||
@@ -243,59 +246,59 @@
|
||||
|
||||
"@ctrl/tinycolor": ["@ctrl/tinycolor@4.1.0", "", {}, "sha512-WyOx8cJQ+FQus4Mm4uPIZA64gbk3Wxh0so5Lcii0aJifqwoVOlfFtorjLE0Hen4OYyHZMXDWqMmaQemBhgxFRQ=="],
|
||||
|
||||
"@emnapi/runtime": ["@emnapi/runtime@1.4.4", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg=="],
|
||||
"@emnapi/runtime": ["@emnapi/runtime@1.4.5", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.6", "", { "os": "aix", "cpu": "ppc64" }, "sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw=="],
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.8", "", { "os": "aix", "cpu": "ppc64" }, "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.6", "", { "os": "android", "cpu": "arm" }, "sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg=="],
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.8", "", { "os": "android", "cpu": "arm" }, "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.6", "", { "os": "android", "cpu": "arm64" }, "sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA=="],
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.8", "", { "os": "android", "cpu": "arm64" }, "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.6", "", { "os": "android", "cpu": "x64" }, "sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A=="],
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.8", "", { "os": "android", "cpu": "x64" }, "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA=="],
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg=="],
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.6", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg=="],
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.6", "", { "os": "freebsd", "cpu": "x64" }, "sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ=="],
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.6", "", { "os": "linux", "cpu": "arm" }, "sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw=="],
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.8", "", { "os": "linux", "cpu": "arm" }, "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ=="],
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.6", "", { "os": "linux", "cpu": "ia32" }, "sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw=="],
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.8", "", { "os": "linux", "cpu": "ia32" }, "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.6", "", { "os": "linux", "cpu": "none" }, "sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg=="],
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.6", "", { "os": "linux", "cpu": "none" }, "sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw=="],
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.6", "", { "os": "linux", "cpu": "ppc64" }, "sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw=="],
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.6", "", { "os": "linux", "cpu": "none" }, "sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w=="],
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.6", "", { "os": "linux", "cpu": "s390x" }, "sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw=="],
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.6", "", { "os": "linux", "cpu": "x64" }, "sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig=="],
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.8", "", { "os": "linux", "cpu": "x64" }, "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ=="],
|
||||
|
||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.6", "", { "os": "none", "cpu": "arm64" }, "sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q=="],
|
||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.8", "", { "os": "none", "cpu": "arm64" }, "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.6", "", { "os": "none", "cpu": "x64" }, "sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g=="],
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.8", "", { "os": "none", "cpu": "x64" }, "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg=="],
|
||||
|
||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.6", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg=="],
|
||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.8", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.6", "", { "os": "openbsd", "cpu": "x64" }, "sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw=="],
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.8", "", { "os": "openbsd", "cpu": "x64" }, "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ=="],
|
||||
|
||||
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.6", "", { "os": "none", "cpu": "arm64" }, "sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA=="],
|
||||
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.8", "", { "os": "none", "cpu": "arm64" }, "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.6", "", { "os": "sunos", "cpu": "x64" }, "sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA=="],
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.8", "", { "os": "sunos", "cpu": "x64" }, "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q=="],
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.6", "", { "os": "win32", "cpu": "ia32" }, "sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ=="],
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.6", "", { "os": "win32", "cpu": "x64" }, "sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA=="],
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.8", "", { "os": "win32", "cpu": "x64" }, "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw=="],
|
||||
|
||||
"@expressive-code/core": ["@expressive-code/core@0.41.3", "", { "dependencies": { "@ctrl/tinycolor": "^4.0.4", "hast-util-select": "^6.0.2", "hast-util-to-html": "^9.0.1", "hast-util-to-text": "^4.0.1", "hastscript": "^9.0.0", "postcss": "^8.4.38", "postcss-nested": "^6.0.1", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1" } }, "sha512-9qzohqU7O0+JwMEEgQhnBPOw5DtsQRBXhW++5fvEywsuX44vCGGof1SL5OvPElvNgaWZ4pFZAFSlkNOkGyLwSQ=="],
|
||||
|
||||
@@ -353,6 +356,10 @@
|
||||
|
||||
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="],
|
||||
|
||||
"@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="],
|
||||
|
||||
"@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg=="],
|
||||
|
||||
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||
@@ -447,45 +454,45 @@
|
||||
|
||||
"@rollup/pluginutils": ["@rollup/pluginutils@5.2.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.45.0", "", { "os": "android", "cpu": "arm" }, "sha512-2o/FgACbji4tW1dzXOqAV15Eu7DdgbKsF2QKcxfG4xbh5iwU7yr5RRP5/U+0asQliSYv5M4o7BevlGIoSL0LXg=="],
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.46.2", "", { "os": "android", "cpu": "arm" }, "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA=="],
|
||||
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.45.0", "", { "os": "android", "cpu": "arm64" }, "sha512-PSZ0SvMOjEAxwZeTx32eI/j5xSYtDCRxGu5k9zvzoY77xUNssZM+WV6HYBLROpY5CkXsbQjvz40fBb7WPwDqtQ=="],
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.46.2", "", { "os": "android", "cpu": "arm64" }, "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ=="],
|
||||
|
||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.45.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BA4yPIPssPB2aRAWzmqzQ3y2/KotkLyZukVB7j3psK/U3nVJdceo6qr9pLM2xN6iRP/wKfxEbOb1yrlZH6sYZg=="],
|
||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.46.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ=="],
|
||||
|
||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.45.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Pr2o0lvTwsiG4HCr43Zy9xXrHspyMvsvEw4FwKYqhli4FuLE5FjcZzuQ4cfPe0iUFCvSQG6lACI0xj74FDZKRA=="],
|
||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.46.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA=="],
|
||||
|
||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.45.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lYE8LkE5h4a/+6VnnLiL14zWMPnx6wNbDG23GcYFpRW1V9hYWHAw9lBZ6ZUIrOaoK7NliF1sdwYGiVmziUF4vA=="],
|
||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.46.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg=="],
|
||||
|
||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.45.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-PVQWZK9sbzpvqC9Q0GlehNNSVHR+4m7+wET+7FgSnKG3ci5nAMgGmr9mGBXzAuE5SvguCKJ6mHL6vq1JaJ/gvw=="],
|
||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.46.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.45.0", "", { "os": "linux", "cpu": "arm" }, "sha512-hLrmRl53prCcD+YXTfNvXd776HTxNh8wPAMllusQ+amcQmtgo3V5i/nkhPN6FakW+QVLoUUr2AsbtIRPFU3xIA=="],
|
||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.46.2", "", { "os": "linux", "cpu": "arm" }, "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.45.0", "", { "os": "linux", "cpu": "arm" }, "sha512-XBKGSYcrkdiRRjl+8XvrUR3AosXU0NvF7VuqMsm7s5nRy+nt58ZMB19Jdp1RdqewLcaYnpk8zeVs/4MlLZEJxw=="],
|
||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.46.2", "", { "os": "linux", "cpu": "arm" }, "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.45.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-fRvZZPUiBz7NztBE/2QnCS5AtqLVhXmUOPj9IHlfGEXkapgImf4W9+FSkL8cWqoAjozyUzqFmSc4zh2ooaeF6g=="],
|
||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.46.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.45.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Btv2WRZOcUGi8XU80XwIvzTg4U6+l6D0V6sZTrZx214nrwxw5nAi8hysaXj/mctyClWgesyuxbeLylCBNauimg=="],
|
||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.46.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg=="],
|
||||
|
||||
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.45.0", "", { "os": "linux", "cpu": "none" }, "sha512-Li0emNnwtUZdLwHjQPBxn4VWztcrw/h7mgLyHiEI5Z0MhpeFGlzaiBHpSNVOMB/xucjXTTcO+dhv469Djr16KA=="],
|
||||
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.46.2", "", { "os": "linux", "cpu": "none" }, "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA=="],
|
||||
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.45.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-sB8+pfkYx2kvpDCfd63d5ScYT0Fz1LO6jIb2zLZvmK9ob2D8DeVqrmBDE0iDK8KlBVmsTNzrjr3G1xV4eUZhSw=="],
|
||||
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.46.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.45.0", "", { "os": "linux", "cpu": "none" }, "sha512-5GQ6PFhh7E6jQm70p1aW05G2cap5zMOvO0se5JMecHeAdj5ZhWEHbJ4hiKpfi1nnnEdTauDXxPgXae/mqjow9w=="],
|
||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.46.2", "", { "os": "linux", "cpu": "none" }, "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.45.0", "", { "os": "linux", "cpu": "none" }, "sha512-N/euLsBd1rekWcuduakTo/dJw6U6sBP3eUq+RXM9RNfPuWTvG2w/WObDkIvJ2KChy6oxZmOSC08Ak2OJA0UiAA=="],
|
||||
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.46.2", "", { "os": "linux", "cpu": "none" }, "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw=="],
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.45.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-2l9sA7d7QdikL0xQwNMO3xURBUNEWyHVHfAsHsUdq+E/pgLTUcCE+gih5PCdmyHmfTDeXUWVhqL0WZzg0nua3g=="],
|
||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.46.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.45.0", "", { "os": "linux", "cpu": "x64" }, "sha512-XZdD3fEEQcwG2KrJDdEQu7NrHonPxxaV0/w2HpvINBdcqebz1aL+0vM2WFJq4DeiAVT6F5SUQas65HY5JDqoPw=="],
|
||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.46.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.45.0", "", { "os": "linux", "cpu": "x64" }, "sha512-7ayfgvtmmWgKWBkCGg5+xTQ0r5V1owVm67zTrsEY1008L5ro7mCyGYORomARt/OquB9KY7LpxVBZes+oSniAAQ=="],
|
||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.46.2", "", { "os": "linux", "cpu": "x64" }, "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA=="],
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.45.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-B+IJgcBnE2bm93jEW5kHisqvPITs4ddLOROAcOc/diBgrEiQJJ6Qcjby75rFSmH5eMGrqJryUgJDhrfj942apQ=="],
|
||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.46.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g=="],
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.45.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-+CXwwG66g0/FpWOnP/v1HnrGVSOygK/osUbu3wPRy8ECXjoYKjRAyfxYpDQOfghC5qPJYLPH0oN4MCOjwgdMug=="],
|
||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.46.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.45.0", "", { "os": "win32", "cpu": "x64" }, "sha512-SRf1cytG7wqcHVLrBc9VtPK4pU5wxiB/lNIkNmW2ApKXIg+RpqwHfsaEK+e7eH4A1BpI6BX/aBWXxZCIrJg3uA=="],
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.46.2", "", { "os": "win32", "cpu": "x64" }, "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg=="],
|
||||
|
||||
"@shikijs/core": ["@shikijs/core@3.4.2", "", { "dependencies": { "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ=="],
|
||||
|
||||
@@ -503,8 +510,6 @@
|
||||
|
||||
"@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="],
|
||||
|
||||
"@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
|
||||
|
||||
"@sindresorhus/is": ["@sindresorhus/is@7.0.2", "", {}, "sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw=="],
|
||||
|
||||
"@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.0.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.3.1", "@smithy/util-hex-encoding": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-7XoWfZqWb/QoR/rAU4VSi0mWnO2vu9/ltS6JZ5ZSZv0eovLVfDfu0/AX4ub33RsJTOth3TiFWSHS5YdztvFnig=="],
|
||||
@@ -565,7 +570,7 @@
|
||||
|
||||
"@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="],
|
||||
|
||||
"@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
|
||||
"@types/react": ["@types/react@19.1.9", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA=="],
|
||||
|
||||
"@types/sax": ["@types/sax@1.2.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A=="],
|
||||
|
||||
@@ -691,7 +696,7 @@
|
||||
|
||||
"camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="],
|
||||
|
||||
"caniuse-lite": ["caniuse-lite@1.0.30001727", "", {}, "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q=="],
|
||||
"caniuse-lite": ["caniuse-lite@1.0.30001731", "", {}, "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg=="],
|
||||
|
||||
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
|
||||
|
||||
@@ -829,7 +834,7 @@
|
||||
|
||||
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.183", "", {}, "sha512-vCrDBYjQCAEefWGjlK3EpoSKfKbT10pR4XXPdn65q7snuNOZnthoVpBfZPykmDapOKfoD+MMIPG8ZjKyyc9oHA=="],
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.193", "", {}, "sha512-eePuBZXM9OVCwfYUhd2OzESeNGnWmLyeu0XAEjf7xjijNjHFdeJSzuRUGN4ueT2tEYo5YqjHramKEFxz67p3XA=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
|
||||
|
||||
@@ -853,7 +858,7 @@
|
||||
|
||||
"esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="],
|
||||
|
||||
"esbuild": ["esbuild@0.25.6", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.6", "@esbuild/android-arm": "0.25.6", "@esbuild/android-arm64": "0.25.6", "@esbuild/android-x64": "0.25.6", "@esbuild/darwin-arm64": "0.25.6", "@esbuild/darwin-x64": "0.25.6", "@esbuild/freebsd-arm64": "0.25.6", "@esbuild/freebsd-x64": "0.25.6", "@esbuild/linux-arm": "0.25.6", "@esbuild/linux-arm64": "0.25.6", "@esbuild/linux-ia32": "0.25.6", "@esbuild/linux-loong64": "0.25.6", "@esbuild/linux-mips64el": "0.25.6", "@esbuild/linux-ppc64": "0.25.6", "@esbuild/linux-riscv64": "0.25.6", "@esbuild/linux-s390x": "0.25.6", "@esbuild/linux-x64": "0.25.6", "@esbuild/netbsd-arm64": "0.25.6", "@esbuild/netbsd-x64": "0.25.6", "@esbuild/openbsd-arm64": "0.25.6", "@esbuild/openbsd-x64": "0.25.6", "@esbuild/openharmony-arm64": "0.25.6", "@esbuild/sunos-x64": "0.25.6", "@esbuild/win32-arm64": "0.25.6", "@esbuild/win32-ia32": "0.25.6", "@esbuild/win32-x64": "0.25.6" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg=="],
|
||||
"esbuild": ["esbuild@0.25.8", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.8", "@esbuild/android-arm": "0.25.8", "@esbuild/android-arm64": "0.25.8", "@esbuild/android-x64": "0.25.8", "@esbuild/darwin-arm64": "0.25.8", "@esbuild/darwin-x64": "0.25.8", "@esbuild/freebsd-arm64": "0.25.8", "@esbuild/freebsd-x64": "0.25.8", "@esbuild/linux-arm": "0.25.8", "@esbuild/linux-arm64": "0.25.8", "@esbuild/linux-ia32": "0.25.8", "@esbuild/linux-loong64": "0.25.8", "@esbuild/linux-mips64el": "0.25.8", "@esbuild/linux-ppc64": "0.25.8", "@esbuild/linux-riscv64": "0.25.8", "@esbuild/linux-s390x": "0.25.8", "@esbuild/linux-x64": "0.25.8", "@esbuild/netbsd-arm64": "0.25.8", "@esbuild/netbsd-x64": "0.25.8", "@esbuild/openbsd-arm64": "0.25.8", "@esbuild/openbsd-x64": "0.25.8", "@esbuild/openharmony-arm64": "0.25.8", "@esbuild/sunos-x64": "0.25.8", "@esbuild/win32-arm64": "0.25.8", "@esbuild/win32-ia32": "0.25.8", "@esbuild/win32-x64": "0.25.8" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q=="],
|
||||
|
||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||
|
||||
@@ -957,7 +962,7 @@
|
||||
|
||||
"gray-matter": ["gray-matter@4.0.3", "", { "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" } }, "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q=="],
|
||||
|
||||
"h3": ["h3@1.15.3", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.4", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.0", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z6GknHqyX0h9aQaTx22VZDf6QyZn+0Nh+Ym8O/u0SGSkyF5cuTJYKlc8MkzW3Nzf9LE1ivcpmYC3FUGpywhuUQ=="],
|
||||
"h3": ["h3@1.15.4", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.2", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ=="],
|
||||
|
||||
"handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="],
|
||||
|
||||
@@ -1111,6 +1116,8 @@
|
||||
|
||||
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
||||
|
||||
"jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="],
|
||||
|
||||
"kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="],
|
||||
|
||||
"kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
|
||||
@@ -1267,7 +1274,9 @@
|
||||
|
||||
"mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
|
||||
|
||||
"miniflare": ["miniflare@4.20250709.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "^5.28.5", "workerd": "1.20250709.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-dRGXi6Do9ArQZt7205QGWZ1tD6k6xQNY/mAZBAtiaQYvKxFuNyiHYlFnSN8Co4AFCVOozo/U52sVAaHvlcmnew=="],
|
||||
"miniflare": ["miniflare@4.20250730.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "^7.10.0", "workerd": "1.20250730.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-avGXBStHQSqcJr8ra1mJ3/OQvnLZ49B1uAILQapAha1DHNZZvXWLIgUVre/WGY6ZOlNGFPh5CJ+dXLm4yuV3Jw=="],
|
||||
|
||||
"minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="],
|
||||
|
||||
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
||||
|
||||
@@ -1309,7 +1318,7 @@
|
||||
|
||||
"node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="],
|
||||
|
||||
"node-mock-http": ["node-mock-http@1.0.1", "", {}, "sha512-0gJJgENizp4ghds/Ywu2FCmcRsgBTmRQzYPZm61wy+Em2sBarSka0OhQS5huLBg6od1zkNpnWMCZloQDFVvOMQ=="],
|
||||
"node-mock-http": ["node-mock-http@1.0.2", "", {}, "sha512-zWaamgDUdo9SSLw47we78+zYw/bDr5gH8pH7oRRs8V3KmBtu8GLgGIbV2p/gRPd3LWpEOpjQj7X1FOU3VFMJ8g=="],
|
||||
|
||||
"node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="],
|
||||
|
||||
@@ -1381,7 +1390,7 @@
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
|
||||
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
||||
|
||||
"pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="],
|
||||
|
||||
@@ -1433,7 +1442,7 @@
|
||||
|
||||
"recma-build-jsx": ["recma-build-jsx@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-build-jsx": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew=="],
|
||||
|
||||
"recma-jsx": ["recma-jsx@1.0.0", "", { "dependencies": { "acorn-jsx": "^5.0.0", "estree-util-to-js": "^2.0.0", "recma-parse": "^1.0.0", "recma-stringify": "^1.0.0", "unified": "^11.0.0" } }, "sha512-5vwkv65qWwYxg+Atz95acp8DMu1JDSqdGkA2Of1j6rCreyFUE/gp15fC8MnGEuG1W68UKjM6x6+YTWIh7hZM/Q=="],
|
||||
"recma-jsx": ["recma-jsx@1.0.1", "", { "dependencies": { "acorn-jsx": "^5.0.0", "estree-util-to-js": "^2.0.0", "recma-parse": "^1.0.0", "recma-stringify": "^1.0.0", "unified": "^11.0.0" }, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w=="],
|
||||
|
||||
"recma-parse": ["recma-parse@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "esast-util-from-js": "^2.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ=="],
|
||||
|
||||
@@ -1487,7 +1496,7 @@
|
||||
|
||||
"retext-stringify": ["retext-stringify@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unified": "^11.0.0" } }, "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA=="],
|
||||
|
||||
"rollup": ["rollup@4.45.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.45.0", "@rollup/rollup-android-arm64": "4.45.0", "@rollup/rollup-darwin-arm64": "4.45.0", "@rollup/rollup-darwin-x64": "4.45.0", "@rollup/rollup-freebsd-arm64": "4.45.0", "@rollup/rollup-freebsd-x64": "4.45.0", "@rollup/rollup-linux-arm-gnueabihf": "4.45.0", "@rollup/rollup-linux-arm-musleabihf": "4.45.0", "@rollup/rollup-linux-arm64-gnu": "4.45.0", "@rollup/rollup-linux-arm64-musl": "4.45.0", "@rollup/rollup-linux-loongarch64-gnu": "4.45.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.45.0", "@rollup/rollup-linux-riscv64-gnu": "4.45.0", "@rollup/rollup-linux-riscv64-musl": "4.45.0", "@rollup/rollup-linux-s390x-gnu": "4.45.0", "@rollup/rollup-linux-x64-gnu": "4.45.0", "@rollup/rollup-linux-x64-musl": "4.45.0", "@rollup/rollup-win32-arm64-msvc": "4.45.0", "@rollup/rollup-win32-ia32-msvc": "4.45.0", "@rollup/rollup-win32-x64-msvc": "4.45.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-WLjEcJRIo7i3WDDgOIJqVI2d+lAC3EwvOGy+Xfq6hs+GQuAA4Di/H72xmXkOhrIWFg2PFYSKZYfH0f4vfKXN4A=="],
|
||||
"rollup": ["rollup@4.46.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.46.2", "@rollup/rollup-android-arm64": "4.46.2", "@rollup/rollup-darwin-arm64": "4.46.2", "@rollup/rollup-darwin-x64": "4.46.2", "@rollup/rollup-freebsd-arm64": "4.46.2", "@rollup/rollup-freebsd-x64": "4.46.2", "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", "@rollup/rollup-linux-arm-musleabihf": "4.46.2", "@rollup/rollup-linux-arm64-gnu": "4.46.2", "@rollup/rollup-linux-arm64-musl": "4.46.2", "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", "@rollup/rollup-linux-ppc64-gnu": "4.46.2", "@rollup/rollup-linux-riscv64-gnu": "4.46.2", "@rollup/rollup-linux-riscv64-musl": "4.46.2", "@rollup/rollup-linux-s390x-gnu": "4.46.2", "@rollup/rollup-linux-x64-gnu": "4.46.2", "@rollup/rollup-linux-x64-musl": "4.46.2", "@rollup/rollup-win32-arm64-msvc": "4.46.2", "@rollup/rollup-win32-ia32-msvc": "4.46.2", "@rollup/rollup-win32-x64-msvc": "4.46.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg=="],
|
||||
|
||||
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
||||
|
||||
@@ -1667,7 +1676,7 @@
|
||||
|
||||
"undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
|
||||
|
||||
"unenv": ["unenv@2.0.0-rc.17", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.4", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-B06u0wXkEd+o5gOCMl/ZHl5cfpYbDZKAT+HWTL+Hws6jWu7dCiqBBXXXzMFcFVJb8D4ytAnYmxJA83uwOQRSsg=="],
|
||||
"unenv": ["unenv@2.0.0-rc.19", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-t/OMHBNAkknVCI7bVB9OWjUUAwhVv9vsPIAGnNUxnu3FxPQN11rjh0sksLMzc3g7IlTgvHmOTl4JM7JHpcv5wA=="],
|
||||
|
||||
"unicode-properties": ["unicode-properties@1.4.1", "", { "dependencies": { "base64-js": "^1.3.0", "unicode-trie": "^2.0.0" } }, "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg=="],
|
||||
|
||||
@@ -1725,11 +1734,11 @@
|
||||
|
||||
"vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="],
|
||||
|
||||
"vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
|
||||
"vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"vite-plugin-solid": ["vite-plugin-solid@2.11.7", "", { "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" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-5TgK1RnE449g0Ryxb9BXqem89RSy7fE8XGVCo+Gw84IHgPuPVP7nYNP6WBVAaY/0xw+OqfdQee+kusL0y3XYNg=="],
|
||||
"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=="],
|
||||
|
||||
"vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="],
|
||||
|
||||
@@ -1753,9 +1762,9 @@
|
||||
|
||||
"wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="],
|
||||
|
||||
"workerd": ["workerd@1.20250709.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250709.0", "@cloudflare/workerd-darwin-arm64": "1.20250709.0", "@cloudflare/workerd-linux-64": "1.20250709.0", "@cloudflare/workerd-linux-arm64": "1.20250709.0", "@cloudflare/workerd-windows-64": "1.20250709.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-BqLPpmvRN+TYUSG61OkWamsGdEuMwgvabP8m0QOHIfofnrD2YVyWqE1kXJ0GH5EsVEuWamE5sR8XpTfsGBmIpg=="],
|
||||
"workerd": ["workerd@1.20250730.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250730.0", "@cloudflare/workerd-darwin-arm64": "1.20250730.0", "@cloudflare/workerd-linux-64": "1.20250730.0", "@cloudflare/workerd-linux-arm64": "1.20250730.0", "@cloudflare/workerd-windows-64": "1.20250730.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-w6e0WM2YGfYQGmg0dewZeLUYIxAzMYK1R31vaS4HHHjgT32Xqj0eVQH+leegzY51RZPNCvw5pe8DFmW4MGf8Fg=="],
|
||||
|
||||
"wrangler": ["wrangler@4.24.3", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.3.3", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20250709.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.17", "workerd": "1.20250709.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250709.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-stB1Wfs5NKlspsAzz8SBujBKsDqT5lpCyrL+vSUMy3uueEtI1A5qyORbKoJhIguEbwHfWS39mBsxzm6Vm1J2cg=="],
|
||||
"wrangler": ["wrangler@4.27.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.5.0", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20250730.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.19", "workerd": "1.20250730.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250730.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-YNHZyMNWebFt9jD6dc20tQrCmnSzJj3SoB0FFa90w11Cx4lbP3d+rUZYjb18Zt+OGSMay1wT2PzwT2vCTskkmg=="],
|
||||
|
||||
"wrap-ansi": ["wrap-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q=="],
|
||||
|
||||
@@ -1821,9 +1830,9 @@
|
||||
|
||||
"@ampproject/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="],
|
||||
|
||||
"@astrojs/mdx/@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.2", "", { "dependencies": { "@astrojs/internal-helpers": "0.6.1", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.1.0", "js-yaml": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.2.1", "smol-toml": "^1.3.1", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1", "vfile": "^6.0.3" } }, "sha512-bO35JbWpVvyKRl7cmSJD822e8YA8ThR/YbUsciWNA7yTcqpIAL2hJDToWP5KcZBWxGT6IOdOkHSXARSNZc4l/Q=="],
|
||||
"@astrojs/mdx/@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.3", "", { "dependencies": { "@astrojs/internal-helpers": "0.6.1", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.1.0", "js-yaml": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.2.1", "smol-toml": "^1.3.4", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1", "vfile": "^6.0.3" } }, "sha512-DDRtD1sPvAuA7ms2btc9A7/7DApKqgLMNrE6kh5tmkfy8utD0Z738gqd3p5aViYYdUtHIyEJ1X4mCMxfCfu15w=="],
|
||||
|
||||
"@astrojs/mdx/source-map": ["source-map@0.7.4", "", {}, "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="],
|
||||
"@astrojs/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||
|
||||
"@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
||||
|
||||
@@ -1837,7 +1846,7 @@
|
||||
|
||||
"@jridgewell/gen-mapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="],
|
||||
|
||||
"@mdx-js/mdx/source-map": ["source-map@0.7.4", "", {}, "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="],
|
||||
"@mdx-js/mdx/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||
|
||||
"@openauthjs/openauth/@standard-schema/spec": ["@standard-schema/spec@1.0.0-beta.3", "", {}, "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw=="],
|
||||
|
||||
@@ -1861,7 +1870,7 @@
|
||||
|
||||
"bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
|
||||
|
||||
"estree-util-to-js/source-map": ["source-map@0.7.4", "", {}, "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="],
|
||||
"estree-util-to-js/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||
|
||||
"express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
||||
|
||||
@@ -1879,6 +1888,8 @@
|
||||
|
||||
"miniflare/sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="],
|
||||
|
||||
"miniflare/undici": ["undici@7.13.0", "", {}, "sha512-l+zSMssRqrzDcb3fjMkjjLGmuiiK2pMIcV++mJaAc9vhjSGpvM7h43QgP+OAMb1GImHmbPyG2tBXeuyG5iY4gA=="],
|
||||
|
||||
"miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="],
|
||||
|
||||
"minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||
|
||||
@@ -19,6 +19,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"formatter": {
|
||||
"test": {
|
||||
"extensions": [".json"],
|
||||
"command": ["sed", "-i", "s/name/poop/g", "$FILE"]
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"context7": {
|
||||
"type": "remote",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"dev": "bun run packages/opencode/src/index.ts",
|
||||
"typecheck": "bun run --filter='*' typecheck",
|
||||
"stainless": "./scripts/stainless",
|
||||
"postinstall": "./scripts/hooks"
|
||||
"postinstall": "./script/hooks"
|
||||
},
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
|
||||
@@ -45,11 +45,13 @@
|
||||
"hono": "catalog:",
|
||||
"hono-openapi": "0.4.8",
|
||||
"isomorphic-git": "1.32.1",
|
||||
"jsonc-parser": "3.3.1",
|
||||
"minimatch": "10.0.3",
|
||||
"open": "10.1.2",
|
||||
"remeda": "catalog:",
|
||||
"turndown": "7.2.0",
|
||||
"tree-sitter": "0.22.4",
|
||||
"tree-sitter-bash": "0.23.3",
|
||||
"turndown": "7.2.0",
|
||||
"vscode-jsonrpc": "8.2.1",
|
||||
"xdg-basedir": "5.1.0",
|
||||
"yargs": "18.0.0",
|
||||
|
||||
@@ -18,12 +18,13 @@ const GOARCH: Record<string, string> = {
|
||||
}
|
||||
|
||||
const targets = [
|
||||
["windows", "x64"],
|
||||
["linux", "arm64"],
|
||||
["linux", "x64"],
|
||||
["linux", "x64-baseline"],
|
||||
["darwin", "x64"],
|
||||
["darwin", "x64-baseline"],
|
||||
["darwin", "arm64"],
|
||||
["windows", "x64"],
|
||||
]
|
||||
|
||||
await $`rm -rf dist`
|
||||
@@ -37,7 +38,7 @@ for (const [os, arch] of targets) {
|
||||
await $`CGO_ENABLED=0 GOOS=${os} GOARCH=${GOARCH[arch]} go build -ldflags="-s -w -X main.Version=${version}" -o ../opencode/dist/${name}/bin/tui ../tui/cmd/opencode/main.go`.cwd(
|
||||
"../tui",
|
||||
)
|
||||
await $`bun build --define OPENCODE_VERSION="'${version}'" --compile --minify --target=bun-${os}-${arch} --outfile=dist/${name}/bin/opencode ./src/index.ts ./dist/${name}/bin/tui`
|
||||
await $`bun build --define OPENCODE_TUI_PATH="'../../../dist/${name}/bin/tui'" --define OPENCODE_VERSION="'${version}'" --compile --target=bun-${os}-${arch} --outfile=dist/${name}/bin/opencode ./src/index.ts`
|
||||
await $`rm -rf ./dist/${name}/bin/tui`
|
||||
await Bun.file(`dist/${name}/package.json`).write(
|
||||
JSON.stringify(
|
||||
@@ -51,7 +52,7 @@ for (const [os, arch] of targets) {
|
||||
2,
|
||||
),
|
||||
)
|
||||
if (!dry) await $`cd dist/${name} && bun publish --access public --tag ${npmTag}`
|
||||
if (!dry) await $`cd dist/${name} && chmod 777 -R . && bun publish --access public --tag ${npmTag}`
|
||||
optionalDependencies[name] = version
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,16 @@ import { FileWatcher } from "../../file/watch"
|
||||
import { Mode } from "../../session/mode"
|
||||
import { Ide } from "../../ide"
|
||||
|
||||
declare global {
|
||||
const OPENCODE_TUI_PATH: string
|
||||
}
|
||||
|
||||
if (typeof OPENCODE_TUI_PATH !== "undefined") {
|
||||
await import(OPENCODE_TUI_PATH as string, {
|
||||
with: { type: "file" },
|
||||
})
|
||||
}
|
||||
|
||||
export const TuiCommand = cmd({
|
||||
command: "$0 [project]",
|
||||
describe: "start opencode tui",
|
||||
@@ -71,16 +81,16 @@ export const TuiCommand = cmd({
|
||||
|
||||
let cmd = ["go", "run", "./main.go"]
|
||||
let cwd = Bun.fileURLToPath(new URL("../../../../tui/cmd/opencode", import.meta.url))
|
||||
if (Bun.embeddedFiles.length > 0) {
|
||||
const blob = Bun.embeddedFiles[0] as File
|
||||
let binaryName = blob.name
|
||||
const tui = Bun.embeddedFiles.find((item) => (item as File).name.includes("tui")) as File
|
||||
if (tui) {
|
||||
let binaryName = tui.name
|
||||
if (process.platform === "win32" && !binaryName.endsWith(".exe")) {
|
||||
binaryName += ".exe"
|
||||
}
|
||||
const binary = path.join(Global.Path.cache, "tui", binaryName)
|
||||
const file = Bun.file(binary)
|
||||
if (!(await file.exists())) {
|
||||
await Bun.write(file, blob, { mode: 0o755 })
|
||||
await Bun.write(file, tui, { mode: 0o755 })
|
||||
await fs.chmod(binary, 0o755)
|
||||
}
|
||||
cwd = process.cwd()
|
||||
|
||||
@@ -5,7 +5,11 @@ import { UI } from "./ui"
|
||||
export function FormatError(input: unknown) {
|
||||
if (MCP.Failed.isInstance(input))
|
||||
return `MCP server "${input.data.name}" failed. Note, opencode does not support MCP authentication yet.`
|
||||
if (Config.JsonError.isInstance(input)) return `Config file at ${input.data.path} is not valid JSON`
|
||||
if (Config.JsonError.isInstance(input)) {
|
||||
return (
|
||||
`Config file at ${input.data.path} is not valid JSON(C)` + (input.data.message ? `: ${input.data.message}` : "")
|
||||
)
|
||||
}
|
||||
if (Config.InvalidError.isInstance(input))
|
||||
return [
|
||||
`Config file at ${input.data.path} is invalid`,
|
||||
|
||||
@@ -12,6 +12,7 @@ import { NamedError } from "../util/error"
|
||||
import matter from "gray-matter"
|
||||
import { Flag } from "../flag/flag"
|
||||
import { Auth } from "../auth"
|
||||
import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser"
|
||||
|
||||
export namespace Config {
|
||||
const log = Log.create({ service: "config" })
|
||||
@@ -277,6 +278,17 @@ export namespace Config {
|
||||
.optional()
|
||||
.describe("Custom provider configurations and model overrides"),
|
||||
mcp: z.record(z.string(), Mcp).optional().describe("MCP (Model Context Protocol) server configurations"),
|
||||
formatter: z
|
||||
.record(
|
||||
z.string(),
|
||||
z.object({
|
||||
disabled: z.boolean().optional(),
|
||||
command: z.array(z.string()).optional(),
|
||||
environment: z.record(z.string(), z.string()).optional(),
|
||||
extensions: z.array(z.string()).optional(),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
instructions: z.array(z.string()).optional().describe("Additional instruction files or patterns to include"),
|
||||
layout: Layout.optional().describe("@deprecated Always uses stretch layout."),
|
||||
permission: z
|
||||
@@ -320,10 +332,11 @@ export namespace Config {
|
||||
export type Info = z.output<typeof Info>
|
||||
|
||||
export const global = lazy(async () => {
|
||||
let result = pipe(
|
||||
let result: Info = pipe(
|
||||
{},
|
||||
mergeDeep(await load(path.join(Global.Path.config, "config.json"))),
|
||||
mergeDeep(await load(path.join(Global.Path.config, "opencode.json"))),
|
||||
mergeDeep(await load(path.join(Global.Path.config, "opencode.jsonc"))),
|
||||
)
|
||||
|
||||
await import(path.join(Global.Path.config, "config"), {
|
||||
@@ -344,7 +357,7 @@ export namespace Config {
|
||||
return result
|
||||
})
|
||||
|
||||
async function load(configPath: string) {
|
||||
async function load(configPath: string): Promise<Info> {
|
||||
let text = await Bun.file(configPath)
|
||||
.text()
|
||||
.catch((err) => {
|
||||
@@ -371,11 +384,20 @@ export namespace Config {
|
||||
}
|
||||
}
|
||||
|
||||
let data: any
|
||||
try {
|
||||
data = JSON.parse(text)
|
||||
} catch (err) {
|
||||
throw new JsonError({ path: configPath }, { cause: err as Error })
|
||||
const errors: JsoncParseError[] = []
|
||||
const data = parseJsonc(text, errors, { allowTrailingComma: true })
|
||||
if (errors.length) {
|
||||
throw new JsonError({
|
||||
path: configPath,
|
||||
message: errors
|
||||
.map((e) => {
|
||||
const lines = text.substring(0, e.offset).split("\n")
|
||||
const line = lines.length
|
||||
const column = lines[lines.length - 1].length + 1
|
||||
return `${printParseErrorCode(e.error)} at line ${line}, column ${column}`
|
||||
})
|
||||
.join("; "),
|
||||
})
|
||||
}
|
||||
|
||||
const parsed = Info.safeParse(data)
|
||||
@@ -392,6 +414,7 @@ export namespace Config {
|
||||
"ConfigJsonError",
|
||||
z.object({
|
||||
path: z.string(),
|
||||
message: z.string().optional(),
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
@@ -129,7 +129,9 @@ export const clang: Info = {
|
||||
command: ["clang-format", "-i", "$FILE"],
|
||||
extensions: [".c", ".cc", ".cpp", ".cxx", ".c++", ".h", ".hh", ".hpp", ".hxx", ".h++", ".ino", ".C", ".H"],
|
||||
async enabled() {
|
||||
return Bun.which("clang-format") !== null
|
||||
const app = App.info()
|
||||
const items = await Filesystem.findUp(".clang-format", app.path.cwd, app.path.root)
|
||||
return items.length > 0
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -5,20 +5,40 @@ import { Log } from "../util/log"
|
||||
import path from "path"
|
||||
|
||||
import * as Formatter from "./formatter"
|
||||
import { Config } from "../config/config"
|
||||
import { mergeDeep } from "remeda"
|
||||
|
||||
export namespace Format {
|
||||
const log = Log.create({ service: "format" })
|
||||
|
||||
const state = App.state("format", () => {
|
||||
const state = App.state("format", async () => {
|
||||
const enabled: Record<string, boolean> = {}
|
||||
const cfg = await Config.get()
|
||||
|
||||
const formatters = { ...Formatter } as Record<string, Formatter.Info>
|
||||
for (const [name, item] of Object.entries(cfg.formatter ?? {})) {
|
||||
if (item.disabled) {
|
||||
delete formatters[name]
|
||||
continue
|
||||
}
|
||||
const result: Formatter.Info = mergeDeep(formatters[name] ?? {}, {
|
||||
command: [],
|
||||
extensions: [],
|
||||
...item,
|
||||
})
|
||||
result.enabled = async () => true
|
||||
result.name = name
|
||||
formatters[name] = result
|
||||
}
|
||||
|
||||
return {
|
||||
enabled,
|
||||
formatters,
|
||||
}
|
||||
})
|
||||
|
||||
async function isEnabled(item: Formatter.Info) {
|
||||
const s = state()
|
||||
const s = await state()
|
||||
let status = s.enabled[item.name]
|
||||
if (status === undefined) {
|
||||
status = await item.enabled()
|
||||
@@ -28,8 +48,10 @@ export namespace Format {
|
||||
}
|
||||
|
||||
async function getFormatter(ext: string) {
|
||||
const formatters = await state().then((x) => x.formatters)
|
||||
const result = []
|
||||
for (const item of Object.values(Formatter)) {
|
||||
for (const item of Object.values(formatters)) {
|
||||
log.info("checking", { name: item.name, ext })
|
||||
if (!item.extensions.includes(ext)) continue
|
||||
if (!(await isEnabled(item))) continue
|
||||
result.push(item)
|
||||
|
||||
@@ -13,6 +13,7 @@ export namespace Global {
|
||||
export const Path = {
|
||||
data,
|
||||
bin: path.join(data, "bin"),
|
||||
log: path.join(data, "log"),
|
||||
cache,
|
||||
config,
|
||||
state,
|
||||
@@ -23,6 +24,7 @@ await Promise.all([
|
||||
fs.mkdir(Global.Path.data, { recursive: true }),
|
||||
fs.mkdir(Global.Path.config, { recursive: true }),
|
||||
fs.mkdir(Global.Path.state, { recursive: true }),
|
||||
fs.mkdir(Global.Path.log, { recursive: true }),
|
||||
])
|
||||
|
||||
const CACHE_VERSION = "3"
|
||||
|
||||
@@ -5,6 +5,7 @@ export namespace Identifier {
|
||||
const prefixes = {
|
||||
session: "ses",
|
||||
message: "msg",
|
||||
permission: "per",
|
||||
user: "usr",
|
||||
part: "prt",
|
||||
} as const
|
||||
|
||||
@@ -2,6 +2,7 @@ import { App } from "../app/app"
|
||||
import { z } from "zod"
|
||||
import { Bus } from "../bus"
|
||||
import { Log } from "../util/log"
|
||||
import { Identifier } from "../id/id"
|
||||
|
||||
export namespace Permission {
|
||||
const log = Log.create({ service: "permission" })
|
||||
@@ -9,7 +10,11 @@ export namespace Permission {
|
||||
export const Info = z
|
||||
.object({
|
||||
id: z.string(),
|
||||
type: z.string(),
|
||||
pattern: z.string().optional(),
|
||||
sessionID: z.string(),
|
||||
messageID: z.string(),
|
||||
callID: z.string().optional(),
|
||||
title: z.string(),
|
||||
metadata: z.record(z.any()),
|
||||
time: z.object({
|
||||
@@ -17,12 +22,16 @@ export namespace Permission {
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
ref: "permission.info",
|
||||
ref: "Permission",
|
||||
})
|
||||
export type Info = z.infer<typeof Info>
|
||||
|
||||
export const Event = {
|
||||
Updated: Bus.event("permission.updated", Info),
|
||||
Replied: Bus.event(
|
||||
"permission.replied",
|
||||
z.object({ sessionID: z.string(), permissionID: z.string(), response: z.string() }),
|
||||
),
|
||||
}
|
||||
|
||||
const state = App.state(
|
||||
@@ -40,7 +49,7 @@ export namespace Permission {
|
||||
|
||||
const approved: {
|
||||
[sessionID: string]: {
|
||||
[permissionID: string]: Info
|
||||
[permissionID: string]: boolean
|
||||
}
|
||||
} = {}
|
||||
|
||||
@@ -52,34 +61,34 @@ export namespace Permission {
|
||||
async (state) => {
|
||||
for (const pending of Object.values(state.pending)) {
|
||||
for (const item of Object.values(pending)) {
|
||||
item.reject(new RejectedError(item.info.sessionID, item.info.id))
|
||||
item.reject(new RejectedError(item.info.sessionID, item.info.id, item.info.callID))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
export function ask(input: {
|
||||
id: Info["id"]
|
||||
sessionID: Info["sessionID"]
|
||||
type: Info["type"]
|
||||
title: Info["title"]
|
||||
pattern?: Info["pattern"]
|
||||
callID?: Info["callID"]
|
||||
sessionID: Info["sessionID"]
|
||||
messageID: Info["messageID"]
|
||||
metadata: Info["metadata"]
|
||||
}) {
|
||||
return
|
||||
const { pending, approved } = state()
|
||||
log.info("asking", {
|
||||
sessionID: input.sessionID,
|
||||
permissionID: input.id,
|
||||
messageID: input.messageID,
|
||||
toolCallID: input.callID,
|
||||
})
|
||||
if (approved[input.sessionID]?.[input.id]) {
|
||||
log.info("previously approved", {
|
||||
sessionID: input.sessionID,
|
||||
permissionID: input.id,
|
||||
})
|
||||
return
|
||||
}
|
||||
if (approved[input.sessionID]?.[input.pattern ?? input.type]) return
|
||||
const info: Info = {
|
||||
id: input.id,
|
||||
id: Identifier.ascending("permission"),
|
||||
type: input.type,
|
||||
sessionID: input.sessionID,
|
||||
messageID: input.messageID,
|
||||
callID: input.callID,
|
||||
title: input.title,
|
||||
metadata: input.metadata,
|
||||
time: {
|
||||
@@ -88,40 +97,42 @@ export namespace Permission {
|
||||
}
|
||||
pending[input.sessionID] = pending[input.sessionID] || {}
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
pending[input.sessionID][input.id] = {
|
||||
pending[input.sessionID][info.id] = {
|
||||
info,
|
||||
resolve,
|
||||
reject,
|
||||
}
|
||||
setTimeout(() => {
|
||||
respond({
|
||||
sessionID: input.sessionID,
|
||||
permissionID: input.id,
|
||||
response: "always",
|
||||
})
|
||||
}, 1000)
|
||||
Bus.publish(Event.Updated, info)
|
||||
})
|
||||
}
|
||||
|
||||
export function respond(input: {
|
||||
sessionID: Info["sessionID"]
|
||||
permissionID: Info["id"]
|
||||
response: "once" | "always" | "reject"
|
||||
}) {
|
||||
export const Response = z.enum(["once", "always", "reject"])
|
||||
export type Response = z.infer<typeof Response>
|
||||
|
||||
export function respond(input: { sessionID: Info["sessionID"]; permissionID: Info["id"]; response: Response }) {
|
||||
log.info("response", input)
|
||||
const { pending, approved } = state()
|
||||
const match = pending[input.sessionID]?.[input.permissionID]
|
||||
if (!match) return
|
||||
delete pending[input.sessionID][input.permissionID]
|
||||
if (input.response === "reject") {
|
||||
match.reject(new RejectedError(input.sessionID, input.permissionID))
|
||||
match.reject(new RejectedError(input.sessionID, input.permissionID, match.info.callID))
|
||||
return
|
||||
}
|
||||
match.resolve()
|
||||
Bus.publish(Event.Replied, {
|
||||
sessionID: input.sessionID,
|
||||
permissionID: input.permissionID,
|
||||
response: input.response,
|
||||
})
|
||||
if (input.response === "always") {
|
||||
approved[input.sessionID] = approved[input.sessionID] || {}
|
||||
approved[input.sessionID][input.permissionID] = match.info
|
||||
approved[input.sessionID][match.info.pattern ?? match.info.type] = true
|
||||
for (const item of Object.values(pending[input.sessionID])) {
|
||||
if ((item.info.pattern ?? item.info.type) === (match.info.pattern ?? match.info.type)) {
|
||||
respond({ sessionID: item.info.sessionID, permissionID: item.info.id, response: input.response })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +140,7 @@ export namespace Permission {
|
||||
constructor(
|
||||
public readonly sessionID: string,
|
||||
public readonly permissionID: string,
|
||||
public readonly toolCallID?: string,
|
||||
) {
|
||||
super(`The user rejected permission to use this functionality`)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { LSP } from "../lsp"
|
||||
import { MessageV2 } from "../session/message-v2"
|
||||
import { Mode } from "../session/mode"
|
||||
import { callTui, TuiRoute } from "./tui"
|
||||
import { Permission } from "../permission"
|
||||
|
||||
const ERRORS = {
|
||||
400: {
|
||||
@@ -457,6 +458,40 @@ export namespace Server {
|
||||
return c.json(messages)
|
||||
},
|
||||
)
|
||||
.get(
|
||||
"/session/:id/message/:messageID",
|
||||
describeRoute({
|
||||
description: "Get a message from a session",
|
||||
operationId: "session.message",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Message",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(
|
||||
z.object({
|
||||
info: MessageV2.Info,
|
||||
parts: MessageV2.Part.array(),
|
||||
}),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator(
|
||||
"param",
|
||||
z.object({
|
||||
id: z.string().openapi({ description: "Session ID" }),
|
||||
messageID: z.string().openapi({ description: "Message ID" }),
|
||||
}),
|
||||
),
|
||||
async (c) => {
|
||||
const params = c.req.valid("param")
|
||||
const message = await Session.getMessage(params.id, params.messageID)
|
||||
return c.json(message)
|
||||
},
|
||||
)
|
||||
.post(
|
||||
"/session/:id/message",
|
||||
describeRoute({
|
||||
@@ -545,6 +580,37 @@ export namespace Server {
|
||||
return c.json(session)
|
||||
},
|
||||
)
|
||||
.post(
|
||||
"/session/:id/permissions/:permissionID",
|
||||
describeRoute({
|
||||
description: "Respond to a permission request",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Permission processed successfully",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.boolean()),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator(
|
||||
"param",
|
||||
z.object({
|
||||
id: z.string(),
|
||||
permissionID: z.string(),
|
||||
}),
|
||||
),
|
||||
zValidator("json", z.object({ response: Permission.Response })),
|
||||
async (c) => {
|
||||
const params = c.req.valid("param")
|
||||
const id = params.id
|
||||
const permissionID = params.permissionID
|
||||
Permission.respond({ sessionID: id, permissionID, response: c.req.valid("json").response })
|
||||
return c.json(true)
|
||||
},
|
||||
)
|
||||
.get(
|
||||
"/config/providers",
|
||||
describeRoute({
|
||||
@@ -839,6 +905,120 @@ export namespace Server {
|
||||
}),
|
||||
async (c) => c.json(await callTui(c)),
|
||||
)
|
||||
.post(
|
||||
"/tui/open-sessions",
|
||||
describeRoute({
|
||||
description: "Open the session dialog",
|
||||
operationId: "tui.openSessions",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Session dialog opened successfully",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.boolean()),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (c) => c.json(await callTui(c)),
|
||||
)
|
||||
.post(
|
||||
"/tui/open-themes",
|
||||
describeRoute({
|
||||
description: "Open the theme dialog",
|
||||
operationId: "tui.openThemes",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Theme dialog opened successfully",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.boolean()),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (c) => c.json(await callTui(c)),
|
||||
)
|
||||
.post(
|
||||
"/tui/open-models",
|
||||
describeRoute({
|
||||
description: "Open the model dialog",
|
||||
operationId: "tui.openModels",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Model dialog opened successfully",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.boolean()),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (c) => c.json(await callTui(c)),
|
||||
)
|
||||
.post(
|
||||
"/tui/submit-prompt",
|
||||
describeRoute({
|
||||
description: "Submit the prompt",
|
||||
operationId: "tui.submitPrompt",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Prompt submitted successfully",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.boolean()),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (c) => c.json(await callTui(c)),
|
||||
)
|
||||
.post(
|
||||
"/tui/clear-prompt",
|
||||
describeRoute({
|
||||
description: "Clear the prompt",
|
||||
operationId: "tui.clearPrompt",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Prompt cleared successfully",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.boolean()),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (c) => c.json(await callTui(c)),
|
||||
)
|
||||
.post(
|
||||
"/tui/execute-command",
|
||||
describeRoute({
|
||||
description: "Execute a TUI command (e.g. switch_mode)",
|
||||
operationId: "tui.executeCommand",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Command executed successfully",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.boolean()),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zValidator(
|
||||
"json",
|
||||
z.object({
|
||||
command: z.string(),
|
||||
}),
|
||||
),
|
||||
async (c) => c.json(await callTui(c)),
|
||||
)
|
||||
.route("/tui/control", TuiRoute)
|
||||
|
||||
return result
|
||||
|
||||
@@ -256,7 +256,10 @@ export namespace Session {
|
||||
}
|
||||
|
||||
export async function getMessage(sessionID: string, messageID: string) {
|
||||
return Storage.readJSON<MessageV2.Info>("session/message/" + sessionID + "/" + messageID)
|
||||
return {
|
||||
info: await Storage.readJSON<MessageV2.Info>("session/message/" + sessionID + "/" + messageID),
|
||||
parts: await getParts(sessionID, messageID),
|
||||
}
|
||||
}
|
||||
|
||||
export async function getParts(sessionID: string, messageID: string) {
|
||||
@@ -377,6 +380,36 @@ export namespace Session {
|
||||
l.info("chatting")
|
||||
|
||||
const inputMode = input.mode ?? "build"
|
||||
|
||||
// Process revert cleanup first, before creating new messages
|
||||
const session = await get(input.sessionID)
|
||||
if (session.revert) {
|
||||
let msgs = await messages(input.sessionID)
|
||||
const messageID = session.revert.messageID
|
||||
const [preserve, remove] = splitWhen(msgs, (x) => x.info.id === messageID)
|
||||
msgs = preserve
|
||||
for (const msg of remove) {
|
||||
await Storage.remove(`session/message/${input.sessionID}/${msg.info.id}`)
|
||||
await Bus.publish(MessageV2.Event.Removed, { sessionID: input.sessionID, messageID: msg.info.id })
|
||||
}
|
||||
const last = preserve.at(-1)
|
||||
if (session.revert.partID && last) {
|
||||
const partID = session.revert.partID
|
||||
const [preserveParts, removeParts] = splitWhen(last.parts, (x) => x.id === partID)
|
||||
last.parts = preserveParts
|
||||
for (const part of removeParts) {
|
||||
await Storage.remove(`session/part/${input.sessionID}/${last.info.id}/${part.id}`)
|
||||
await Bus.publish(MessageV2.Event.PartRemoved, {
|
||||
sessionID: input.sessionID,
|
||||
messageID: last.info.id,
|
||||
partID: part.id,
|
||||
})
|
||||
}
|
||||
}
|
||||
await update(input.sessionID, (draft) => {
|
||||
draft.revert = undefined
|
||||
})
|
||||
}
|
||||
const userMsg: MessageV2.Info = {
|
||||
id: input.messageID ?? Identifier.ascending("message"),
|
||||
role: "user",
|
||||
@@ -544,6 +577,10 @@ export namespace Session {
|
||||
await updatePart(part)
|
||||
}
|
||||
|
||||
// mark session as updated
|
||||
// used for session list sorting (indicates when session was most recently interacted with)
|
||||
await update(input.sessionID, (_draft) => {})
|
||||
|
||||
if (isLocked(input.sessionID)) {
|
||||
return new Promise((resolve) => {
|
||||
const queue = state().queued.get(input.sessionID) ?? []
|
||||
@@ -560,35 +597,6 @@ export namespace Session {
|
||||
|
||||
const model = await Provider.getModel(input.providerID, input.modelID)
|
||||
let msgs = await messages(input.sessionID)
|
||||
const session = await get(input.sessionID)
|
||||
|
||||
if (session.revert) {
|
||||
const messageID = session.revert.messageID
|
||||
const [preserve, remove] = splitWhen(msgs, (x) => x.info.id === messageID)
|
||||
msgs = preserve
|
||||
for (const msg of remove) {
|
||||
if (msg.info.id === userMsg.id) continue
|
||||
await Storage.remove(`session/message/${input.sessionID}/${msg.info.id}`)
|
||||
await Bus.publish(MessageV2.Event.Removed, { sessionID: input.sessionID, messageID: msg.info.id })
|
||||
}
|
||||
const last = preserve.at(-1)
|
||||
if (session.revert.partID && last) {
|
||||
const partID = session.revert.partID
|
||||
const [preserveParts, removeParts] = splitWhen(last.parts, (x) => x.id === partID)
|
||||
last.parts = preserveParts
|
||||
for (const part of removeParts) {
|
||||
await Storage.remove(`session/part/${input.sessionID}/${last.info.id}/${part.id}`)
|
||||
await Bus.publish(MessageV2.Event.PartRemoved, {
|
||||
sessionID: input.sessionID,
|
||||
messageID: last.info.id,
|
||||
partID: part.id,
|
||||
})
|
||||
}
|
||||
}
|
||||
await update(input.sessionID, (draft) => {
|
||||
draft.revert = undefined
|
||||
})
|
||||
}
|
||||
|
||||
const previous = msgs.filter((x) => x.info.role === "assistant").at(-1)?.info as MessageV2.Assistant
|
||||
const outputLimit = Math.min(model.info.limit.output, OUTPUT_TOKEN_MAX) || OUTPUT_TOKEN_MAX
|
||||
@@ -713,6 +721,7 @@ export namespace Session {
|
||||
sessionID: input.sessionID,
|
||||
abort: abort.signal,
|
||||
messageID: assistantMsg.id,
|
||||
callID: options.toolCallId,
|
||||
metadata: async (val) => {
|
||||
const match = processor.partFromToolCall(options.toolCallId)
|
||||
if (match && match.state.status === "running") {
|
||||
|
||||
@@ -2,17 +2,24 @@ import { z } from "zod"
|
||||
import { Tool } from "./tool"
|
||||
import DESCRIPTION from "./bash.txt"
|
||||
import { App } from "../app/app"
|
||||
|
||||
// import Parser from "tree-sitter"
|
||||
// import Bash from "tree-sitter-bash"
|
||||
// import { Config } from "../config/config"
|
||||
import { Permission } from "../permission"
|
||||
import { Config } from "../config/config"
|
||||
import { Filesystem } from "../util/filesystem"
|
||||
import path from "path"
|
||||
import { lazy } from "../util/lazy"
|
||||
import { minimatch } from "minimatch"
|
||||
|
||||
const MAX_OUTPUT_LENGTH = 30000
|
||||
const DEFAULT_TIMEOUT = 1 * 60 * 1000
|
||||
const MAX_TIMEOUT = 10 * 60 * 1000
|
||||
|
||||
// const parser = new Parser()
|
||||
// parser.setLanguage(Bash.language as any)
|
||||
const parser = lazy(async () => {
|
||||
const { default: Parser } = await import("tree-sitter")
|
||||
const Bash = await import("tree-sitter-bash")
|
||||
const p = new Parser()
|
||||
p.setLanguage(Bash.language as any)
|
||||
return p
|
||||
})
|
||||
|
||||
export const BashTool = Tool.define("bash", {
|
||||
description: DESCRIPTION,
|
||||
@@ -28,9 +35,8 @@ export const BashTool = Tool.define("bash", {
|
||||
async execute(params, ctx) {
|
||||
const timeout = Math.min(params.timeout ?? DEFAULT_TIMEOUT, MAX_TIMEOUT)
|
||||
const app = App.info()
|
||||
/*
|
||||
const _cfg = await Config.get()
|
||||
const tree = parser.parse(params.command)
|
||||
const cfg = await Config.get()
|
||||
const tree = await parser().then((p) => p.parse(params.command))
|
||||
const permissions = (() => {
|
||||
const value = cfg.permission?.bash
|
||||
if (!value)
|
||||
@@ -79,7 +85,7 @@ export const BashTool = Tool.define("bash", {
|
||||
if (!needsAsk && command[0] !== "cd") {
|
||||
const ask = (() => {
|
||||
for (const [pattern, value] of Object.entries(permissions)) {
|
||||
if (new Bun.Glob(pattern).match(node.text)) {
|
||||
if (minimatch(node.text, pattern)) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
@@ -91,15 +97,16 @@ export const BashTool = Tool.define("bash", {
|
||||
|
||||
if (needsAsk) {
|
||||
await Permission.ask({
|
||||
id: "bash",
|
||||
type: "bash",
|
||||
sessionID: ctx.sessionID,
|
||||
messageID: ctx.messageID,
|
||||
callID: ctx.callID,
|
||||
title: params.command,
|
||||
metadata: {
|
||||
command: params.command,
|
||||
},
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
const process = Bun.spawn({
|
||||
cmd: ["bash", "-c", params.command],
|
||||
|
||||
@@ -35,61 +35,78 @@ export const EditTool = Tool.define("edit", {
|
||||
}
|
||||
|
||||
const app = App.info()
|
||||
const filepath = path.isAbsolute(params.filePath) ? params.filePath : path.join(app.path.cwd, params.filePath)
|
||||
if (!Filesystem.contains(app.path.cwd, filepath)) {
|
||||
throw new Error(`File ${filepath} is not in the current working directory`)
|
||||
const filePath = path.isAbsolute(params.filePath) ? params.filePath : path.join(app.path.cwd, params.filePath)
|
||||
if (!Filesystem.contains(app.path.cwd, filePath)) {
|
||||
throw new Error(`File ${filePath} is not in the current working directory`)
|
||||
}
|
||||
|
||||
const cfg = await Config.get()
|
||||
if (cfg.permission?.edit === "ask")
|
||||
await Permission.ask({
|
||||
id: "edit",
|
||||
sessionID: ctx.sessionID,
|
||||
title: "Edit this file: " + filepath,
|
||||
metadata: {
|
||||
filePath: filepath,
|
||||
oldString: params.oldString,
|
||||
newString: params.newString,
|
||||
},
|
||||
})
|
||||
|
||||
let diff = ""
|
||||
let contentOld = ""
|
||||
let contentNew = ""
|
||||
await (async () => {
|
||||
if (params.oldString === "") {
|
||||
contentNew = params.newString
|
||||
await Bun.write(filepath, params.newString)
|
||||
diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew))
|
||||
if (cfg.permission?.edit === "ask") {
|
||||
await Permission.ask({
|
||||
type: "edit",
|
||||
sessionID: ctx.sessionID,
|
||||
messageID: ctx.messageID,
|
||||
callID: ctx.callID,
|
||||
title: "Edit this file: " + filePath,
|
||||
metadata: {
|
||||
filePath,
|
||||
diff,
|
||||
},
|
||||
})
|
||||
}
|
||||
await Bun.write(filePath, params.newString)
|
||||
await Bus.publish(File.Event.Edited, {
|
||||
file: filepath,
|
||||
file: filePath,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const file = Bun.file(filepath)
|
||||
const file = Bun.file(filePath)
|
||||
const stats = await file.stat().catch(() => {})
|
||||
if (!stats) throw new Error(`File ${filepath} not found`)
|
||||
if (stats.isDirectory()) throw new Error(`Path is a directory, not a file: ${filepath}`)
|
||||
await FileTime.assert(ctx.sessionID, filepath)
|
||||
if (!stats) throw new Error(`File ${filePath} not found`)
|
||||
if (stats.isDirectory()) throw new Error(`Path is a directory, not a file: ${filePath}`)
|
||||
await FileTime.assert(ctx.sessionID, filePath)
|
||||
contentOld = await file.text()
|
||||
|
||||
contentNew = replace(contentOld, params.oldString, params.newString, params.replaceAll)
|
||||
|
||||
diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew))
|
||||
if (cfg.permission?.edit === "ask") {
|
||||
await Permission.ask({
|
||||
type: "edit",
|
||||
sessionID: ctx.sessionID,
|
||||
messageID: ctx.messageID,
|
||||
callID: ctx.callID,
|
||||
title: "Edit this file: " + filePath,
|
||||
metadata: {
|
||||
filePath,
|
||||
diff,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
await file.write(contentNew)
|
||||
await Bus.publish(File.Event.Edited, {
|
||||
file: filepath,
|
||||
file: filePath,
|
||||
})
|
||||
contentNew = await file.text()
|
||||
diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew))
|
||||
})()
|
||||
|
||||
const diff = trimDiff(createTwoFilesPatch(filepath, filepath, contentOld, contentNew))
|
||||
|
||||
FileTime.read(ctx.sessionID, filepath)
|
||||
FileTime.read(ctx.sessionID, filePath)
|
||||
|
||||
let output = ""
|
||||
await LSP.touchFile(filepath, true)
|
||||
await LSP.touchFile(filePath, true)
|
||||
const diagnostics = await LSP.diagnostics()
|
||||
for (const [file, issues] of Object.entries(diagnostics)) {
|
||||
if (issues.length === 0) continue
|
||||
if (file === filepath) {
|
||||
if (file === filePath) {
|
||||
output += `\nThis file has errors, please fix\n<file_diagnostics>\n${issues.map(LSP.Diagnostic.pretty).join("\n")}\n</file_diagnostics>\n`
|
||||
continue
|
||||
}
|
||||
@@ -104,7 +121,7 @@ export const EditTool = Tool.define("edit", {
|
||||
diagnostics,
|
||||
diff,
|
||||
},
|
||||
title: `${path.relative(app.path.root, filepath)}`,
|
||||
title: `${path.relative(app.path.root, filePath)}`,
|
||||
output,
|
||||
}
|
||||
},
|
||||
|
||||
@@ -20,7 +20,7 @@ export const TaskTool = Tool.define("task", async () => {
|
||||
async execute(params, ctx) {
|
||||
const session = await Session.create(ctx.sessionID)
|
||||
const msg = await Session.getMessage(ctx.sessionID, ctx.messageID)
|
||||
if (msg.role !== "assistant") throw new Error("Not an assistant message")
|
||||
if (msg.info.role !== "assistant") throw new Error("Not an assistant message")
|
||||
const agent = await Agent.get(params.subagent_type)
|
||||
const messageID = Identifier.ascending("message")
|
||||
const parts: Record<string, MessageV2.ToolPart> = {}
|
||||
@@ -38,8 +38,8 @@ export const TaskTool = Tool.define("task", async () => {
|
||||
})
|
||||
|
||||
const model = agent.model ?? {
|
||||
modelID: msg.modelID,
|
||||
providerID: msg.providerID,
|
||||
modelID: msg.info.modelID,
|
||||
providerID: msg.info.providerID,
|
||||
}
|
||||
|
||||
ctx.abort.addEventListener("abort", () => {
|
||||
@@ -50,7 +50,7 @@ export const TaskTool = Tool.define("task", async () => {
|
||||
sessionID: session.id,
|
||||
modelID: model.modelID,
|
||||
providerID: model.providerID,
|
||||
mode: msg.mode,
|
||||
mode: msg.info.mode,
|
||||
system: agent.prompt,
|
||||
tools: {
|
||||
...agent.tools,
|
||||
|
||||
53
packages/opencode/src/tool/test.ts
Normal file
53
packages/opencode/src/tool/test.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import Parser from "tree-sitter";
|
||||
import Bash from "tree-sitter-bash";
|
||||
|
||||
const parser = new Parser();
|
||||
parser.setLanguage(Bash.language as any);
|
||||
|
||||
const sourceCode = `cd --foo foo/bar && echo "hello" && cd ../baz`;
|
||||
|
||||
const tree = parser.parse(sourceCode);
|
||||
|
||||
// Function to extract commands and arguments
|
||||
function extractCommands(
|
||||
node: any,
|
||||
): Array<{ command: string; args: string[] }> {
|
||||
const commands: Array<{ command: string; args: string[] }> = [];
|
||||
|
||||
function traverse(node: any) {
|
||||
if (node.type === "command") {
|
||||
const commandNode = node.child(0);
|
||||
if (commandNode) {
|
||||
const command = commandNode.text;
|
||||
const args: string[] = [];
|
||||
|
||||
// Extract arguments
|
||||
for (let i = 1; i < node.childCount; i++) {
|
||||
const child = node.child(i);
|
||||
if (child && child.type === "word") {
|
||||
args.push(child.text);
|
||||
}
|
||||
}
|
||||
|
||||
commands.push({ command, args });
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse children
|
||||
for (let i = 0; i < node.childCount; i++) {
|
||||
traverse(node.child(i));
|
||||
}
|
||||
}
|
||||
|
||||
traverse(node);
|
||||
return commands;
|
||||
}
|
||||
|
||||
// Extract and display commands
|
||||
console.log("Source code: " + sourceCode);
|
||||
const commands = extractCommands(tree.rootNode);
|
||||
console.log("Extracted commands:");
|
||||
commands.forEach((cmd, index) => {
|
||||
console.log(`${index + 1}. Command: ${cmd.command}`);
|
||||
console.log(` Args: [${cmd.args.join(", ")}]`);
|
||||
});
|
||||
@@ -7,6 +7,7 @@ export namespace Tool {
|
||||
export type Context<M extends Metadata = Metadata> = {
|
||||
sessionID: string
|
||||
messageID: string
|
||||
callID?: string
|
||||
abort: AbortSignal
|
||||
metadata(input: { title?: string; metadata?: M }): void
|
||||
}
|
||||
|
||||
@@ -31,8 +31,10 @@ export const WriteTool = Tool.define("write", {
|
||||
const cfg = await Config.get()
|
||||
if (cfg.permission?.edit === "ask")
|
||||
await Permission.ask({
|
||||
id: "write",
|
||||
type: "write",
|
||||
sessionID: ctx.sessionID,
|
||||
messageID: ctx.messageID,
|
||||
callID: ctx.callID,
|
||||
title: exists ? "Overwrite this file: " + filepath : "Create new file: " + filepath,
|
||||
metadata: {
|
||||
filePath: filepath,
|
||||
|
||||
@@ -53,12 +53,10 @@ export namespace Log {
|
||||
|
||||
export async function init(options: Options) {
|
||||
if (options.level) level = options.level
|
||||
const dir = path.join(Global.Path.data, "log")
|
||||
await fs.mkdir(dir, { recursive: true })
|
||||
cleanup(dir)
|
||||
cleanup(Global.Path.log)
|
||||
if (options.print) return
|
||||
logpath = path.join(
|
||||
dir,
|
||||
Global.Path.log,
|
||||
options.dev ? "dev.log" : new Date().toISOString().split(".")[0].replace(/:/g, "") + ".log",
|
||||
)
|
||||
const logfile = Bun.file(logpath)
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Log } from "../../src/util/log"
|
||||
const ctx = {
|
||||
sessionID: "test",
|
||||
messageID: "",
|
||||
toolCallID: "",
|
||||
abort: AbortSignal.any([]),
|
||||
metadata: () => {},
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import path from "path"
|
||||
const ctx = {
|
||||
sessionID: "test",
|
||||
messageID: "",
|
||||
toolCallID: "",
|
||||
abort: AbortSignal.any([]),
|
||||
metadata: () => {},
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
configured_endpoints: 26
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-5bf6a39123d248d306490c1dee61b46ba113ea2c415a4de1a631c76462769c49.yml
|
||||
openapi_spec_hash: 3c5b25f121429281275ffd70c9d5cfe4
|
||||
config_hash: 1ae82c93499b9f0b9ba828b8919f9cb3
|
||||
configured_endpoints: 34
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-2ebd9d5478864042a2e01b4995f42acbc39069fa7fcccd1c2e567366ee6c243d.yml
|
||||
openapi_spec_hash: 2a34451b288ea30af1cb61332c417c2a
|
||||
config_hash: 11a6f0803eb407367c3f677d3e524c37
|
||||
|
||||
@@ -103,6 +103,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#ToolStatePending">ToolStatePending</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#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>
|
||||
|
||||
Methods:
|
||||
@@ -113,6 +114,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}/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#AssistantMessage">AssistantMessage</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">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Messages">Messages</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#SessionMessagesResponse">SessionMessagesResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="post /session/{id}/revert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Revert">Revert</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#SessionRevertParams">SessionRevertParams</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}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Share">Share</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>
|
||||
@@ -120,9 +122,25 @@ Methods:
|
||||
- <code title="post /session/{id}/unrevert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unrevert">Unrevert</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="delete /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unshare">Unshare</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>
|
||||
|
||||
## Permissions
|
||||
|
||||
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#Permission">Permission</a>
|
||||
|
||||
Methods:
|
||||
|
||||
- <code title="post /session/{id}/permissions/{permissionID}">client.Session.Permissions.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPermissionService.Respond">Respond</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>, permissionID <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#SessionPermissionRespondParams">SessionPermissionRespondParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
|
||||
# Tui
|
||||
|
||||
Methods:
|
||||
|
||||
- <code title="post /tui/append-prompt">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.AppendPrompt">AppendPrompt</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</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#TuiAppendPromptParams">TuiAppendPromptParams</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 /tui/clear-prompt">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.ClearPrompt">ClearPrompt</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/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="post /tui/execute-command">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.ExecuteCommand">ExecuteCommand</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</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#TuiExecuteCommandParams">TuiExecuteCommandParams</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 /tui/open-help">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.OpenHelp">OpenHelp</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/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="post /tui/open-models">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.OpenModels">OpenModels</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/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="post /tui/open-sessions">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.OpenSessions">OpenSessions</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/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="post /tui/open-themes">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.OpenThemes">OpenThemes</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/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="post /tui/submit-prompt">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.SubmitPrompt">SubmitPrompt</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/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
|
||||
@@ -54,8 +54,8 @@ type EventListResponse struct {
|
||||
// [EventListResponseEventMessageRemovedProperties],
|
||||
// [EventListResponseEventMessagePartUpdatedProperties],
|
||||
// [EventListResponseEventMessagePartRemovedProperties],
|
||||
// [EventListResponseEventStorageWriteProperties],
|
||||
// [EventListResponseEventPermissionUpdatedProperties],
|
||||
// [EventListResponseEventStorageWriteProperties], [Permission],
|
||||
// [EventListResponseEventPermissionRepliedProperties],
|
||||
// [EventListResponseEventFileEditedProperties],
|
||||
// [EventListResponseEventSessionUpdatedProperties],
|
||||
// [EventListResponseEventSessionDeletedProperties],
|
||||
@@ -101,9 +101,10 @@ func (r *EventListResponse) UnmarshalJSON(data []byte) (err error) {
|
||||
// [EventListResponseEventMessagePartUpdated],
|
||||
// [EventListResponseEventMessagePartRemoved],
|
||||
// [EventListResponseEventStorageWrite], [EventListResponseEventPermissionUpdated],
|
||||
// [EventListResponseEventFileEdited], [EventListResponseEventSessionUpdated],
|
||||
// [EventListResponseEventSessionDeleted], [EventListResponseEventSessionIdle],
|
||||
// [EventListResponseEventSessionError], [EventListResponseEventServerConnected],
|
||||
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
|
||||
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
||||
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
||||
// [EventListResponseEventServerConnected],
|
||||
// [EventListResponseEventFileWatcherUpdated],
|
||||
// [EventListResponseEventIdeInstalled].
|
||||
func (r EventListResponse) AsUnion() EventListResponseUnion {
|
||||
@@ -116,9 +117,10 @@ func (r EventListResponse) AsUnion() EventListResponseUnion {
|
||||
// [EventListResponseEventMessagePartUpdated],
|
||||
// [EventListResponseEventMessagePartRemoved],
|
||||
// [EventListResponseEventStorageWrite], [EventListResponseEventPermissionUpdated],
|
||||
// [EventListResponseEventFileEdited], [EventListResponseEventSessionUpdated],
|
||||
// [EventListResponseEventSessionDeleted], [EventListResponseEventSessionIdle],
|
||||
// [EventListResponseEventSessionError], [EventListResponseEventServerConnected],
|
||||
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
|
||||
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
||||
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
||||
// [EventListResponseEventServerConnected],
|
||||
// [EventListResponseEventFileWatcherUpdated] or
|
||||
// [EventListResponseEventIdeInstalled].
|
||||
type EventListResponseUnion interface {
|
||||
@@ -169,6 +171,11 @@ func init() {
|
||||
Type: reflect.TypeOf(EventListResponseEventPermissionUpdated{}),
|
||||
DiscriminatorValue: "permission.updated",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventPermissionReplied{}),
|
||||
DiscriminatorValue: "permission.replied",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventFileEdited{}),
|
||||
@@ -643,9 +650,9 @@ func (r EventListResponseEventStorageWriteType) IsKnown() bool {
|
||||
}
|
||||
|
||||
type EventListResponseEventPermissionUpdated struct {
|
||||
Properties EventListResponseEventPermissionUpdatedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
|
||||
JSON eventListResponseEventPermissionUpdatedJSON `json:"-"`
|
||||
Properties Permission `json:"properties,required"`
|
||||
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
|
||||
JSON eventListResponseEventPermissionUpdatedJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventPermissionUpdatedJSON contains the JSON metadata for the
|
||||
@@ -667,56 +674,6 @@ func (r eventListResponseEventPermissionUpdatedJSON) RawJSON() string {
|
||||
|
||||
func (r EventListResponseEventPermissionUpdated) implementsEventListResponse() {}
|
||||
|
||||
type EventListResponseEventPermissionUpdatedProperties struct {
|
||||
ID string `json:"id,required"`
|
||||
Metadata map[string]interface{} `json:"metadata,required"`
|
||||
SessionID string `json:"sessionID,required"`
|
||||
Time EventListResponseEventPermissionUpdatedPropertiesTime `json:"time,required"`
|
||||
Title string `json:"title,required"`
|
||||
JSON eventListResponseEventPermissionUpdatedPropertiesJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventPermissionUpdatedPropertiesJSON contains the JSON metadata
|
||||
// for the struct [EventListResponseEventPermissionUpdatedProperties]
|
||||
type eventListResponseEventPermissionUpdatedPropertiesJSON struct {
|
||||
ID apijson.Field
|
||||
Metadata apijson.Field
|
||||
SessionID apijson.Field
|
||||
Time apijson.Field
|
||||
Title apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventPermissionUpdatedProperties) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventPermissionUpdatedPropertiesJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type EventListResponseEventPermissionUpdatedPropertiesTime struct {
|
||||
Created float64 `json:"created,required"`
|
||||
JSON eventListResponseEventPermissionUpdatedPropertiesTimeJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventPermissionUpdatedPropertiesTimeJSON contains the JSON
|
||||
// metadata for the struct [EventListResponseEventPermissionUpdatedPropertiesTime]
|
||||
type eventListResponseEventPermissionUpdatedPropertiesTimeJSON struct {
|
||||
Created apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventPermissionUpdatedPropertiesTime) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventPermissionUpdatedPropertiesTimeJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type EventListResponseEventPermissionUpdatedType string
|
||||
|
||||
const (
|
||||
@@ -731,6 +688,70 @@ func (r EventListResponseEventPermissionUpdatedType) IsKnown() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventPermissionReplied struct {
|
||||
Properties EventListResponseEventPermissionRepliedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventPermissionRepliedType `json:"type,required"`
|
||||
JSON eventListResponseEventPermissionRepliedJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventPermissionRepliedJSON contains the JSON metadata for the
|
||||
// struct [EventListResponseEventPermissionReplied]
|
||||
type eventListResponseEventPermissionRepliedJSON struct {
|
||||
Properties apijson.Field
|
||||
Type apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventPermissionReplied) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventPermissionRepliedJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r EventListResponseEventPermissionReplied) implementsEventListResponse() {}
|
||||
|
||||
type EventListResponseEventPermissionRepliedProperties struct {
|
||||
PermissionID string `json:"permissionID,required"`
|
||||
Response string `json:"response,required"`
|
||||
SessionID string `json:"sessionID,required"`
|
||||
JSON eventListResponseEventPermissionRepliedPropertiesJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventPermissionRepliedPropertiesJSON contains the JSON metadata
|
||||
// for the struct [EventListResponseEventPermissionRepliedProperties]
|
||||
type eventListResponseEventPermissionRepliedPropertiesJSON struct {
|
||||
PermissionID apijson.Field
|
||||
Response apijson.Field
|
||||
SessionID apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventPermissionRepliedProperties) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventPermissionRepliedPropertiesJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type EventListResponseEventPermissionRepliedType string
|
||||
|
||||
const (
|
||||
EventListResponseEventPermissionRepliedTypePermissionReplied EventListResponseEventPermissionRepliedType = "permission.replied"
|
||||
)
|
||||
|
||||
func (r EventListResponseEventPermissionRepliedType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseEventPermissionRepliedTypePermissionReplied:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventFileEdited struct {
|
||||
Properties EventListResponseEventFileEditedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventFileEditedType `json:"type,required"`
|
||||
@@ -1354,6 +1375,7 @@ const (
|
||||
EventListResponseTypeMessagePartRemoved EventListResponseType = "message.part.removed"
|
||||
EventListResponseTypeStorageWrite EventListResponseType = "storage.write"
|
||||
EventListResponseTypePermissionUpdated EventListResponseType = "permission.updated"
|
||||
EventListResponseTypePermissionReplied EventListResponseType = "permission.replied"
|
||||
EventListResponseTypeFileEdited EventListResponseType = "file.edited"
|
||||
EventListResponseTypeSessionUpdated EventListResponseType = "session.updated"
|
||||
EventListResponseTypeSessionDeleted EventListResponseType = "session.deleted"
|
||||
@@ -1366,7 +1388,7 @@ const (
|
||||
|
||||
func (r EventListResponseType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeStorageWrite, EventListResponseTypePermissionUpdated, EventListResponseTypeFileEdited, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionIdle, EventListResponseTypeSessionError, EventListResponseTypeServerConnected, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeIdeInstalled:
|
||||
case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeStorageWrite, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeFileEdited, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionIdle, EventListResponseTypeSessionError, EventListResponseTypeServerConnected, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeIdeInstalled:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -24,7 +24,8 @@ import (
|
||||
// automatically. You should not instantiate this service directly, and instead use
|
||||
// the [NewSessionService] method instead.
|
||||
type SessionService struct {
|
||||
Options []option.RequestOption
|
||||
Options []option.RequestOption
|
||||
Permissions *SessionPermissionService
|
||||
}
|
||||
|
||||
// NewSessionService generates a new service that applies the given options to each
|
||||
@@ -33,6 +34,7 @@ type SessionService struct {
|
||||
func NewSessionService(opts ...option.RequestOption) (r *SessionService) {
|
||||
r = &SessionService{}
|
||||
r.Options = opts
|
||||
r.Permissions = NewSessionPermissionService(opts...)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -100,6 +102,22 @@ func (r *SessionService) Init(ctx context.Context, id string, body SessionInitPa
|
||||
return
|
||||
}
|
||||
|
||||
// Get a message from a session
|
||||
func (r *SessionService) Message(ctx context.Context, id string, messageID string, opts ...option.RequestOption) (res *SessionMessageResponse, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
if id == "" {
|
||||
err = errors.New("missing required id parameter")
|
||||
return
|
||||
}
|
||||
if messageID == "" {
|
||||
err = errors.New("missing required messageID parameter")
|
||||
return
|
||||
}
|
||||
path := fmt.Sprintf("session/%s/message/%s", id, messageID)
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
||||
return
|
||||
}
|
||||
|
||||
// List messages for a session
|
||||
func (r *SessionService) Messages(ctx context.Context, id string, opts ...option.RequestOption) (res *[]SessionMessagesResponse, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
@@ -2012,6 +2030,29 @@ func (r userMessageTimeJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type SessionMessageResponse struct {
|
||||
Info Message `json:"info,required"`
|
||||
Parts []Part `json:"parts,required"`
|
||||
JSON sessionMessageResponseJSON `json:"-"`
|
||||
}
|
||||
|
||||
// sessionMessageResponseJSON contains the JSON metadata for the struct
|
||||
// [SessionMessageResponse]
|
||||
type sessionMessageResponseJSON struct {
|
||||
Info apijson.Field
|
||||
Parts apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *SessionMessageResponse) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r sessionMessageResponseJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type SessionMessagesResponse struct {
|
||||
Info Message `json:"info,required"`
|
||||
Parts []Part `json:"parts,required"`
|
||||
|
||||
@@ -176,6 +176,32 @@ func TestSessionInit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionMessage(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.Message(
|
||||
context.TODO(),
|
||||
"id",
|
||||
"messageID",
|
||||
)
|
||||
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 TestSessionMessages(t *testing.T) {
|
||||
t.Skip("skipped: tests are disabled for the time being")
|
||||
baseURL := "http://localhost:4010"
|
||||
|
||||
130
packages/sdk/go/sessionpermission.go
Normal file
130
packages/sdk/go/sessionpermission.go
Normal file
@@ -0,0 +1,130 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
package opencode
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||
"github.com/sst/opencode-sdk-go/internal/param"
|
||||
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||
"github.com/sst/opencode-sdk-go/option"
|
||||
)
|
||||
|
||||
// SessionPermissionService 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 [NewSessionPermissionService] method instead.
|
||||
type SessionPermissionService struct {
|
||||
Options []option.RequestOption
|
||||
}
|
||||
|
||||
// NewSessionPermissionService 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 NewSessionPermissionService(opts ...option.RequestOption) (r *SessionPermissionService) {
|
||||
r = &SessionPermissionService{}
|
||||
r.Options = opts
|
||||
return
|
||||
}
|
||||
|
||||
// Respond to a permission request
|
||||
func (r *SessionPermissionService) Respond(ctx context.Context, id string, permissionID string, body SessionPermissionRespondParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
if id == "" {
|
||||
err = errors.New("missing required id parameter")
|
||||
return
|
||||
}
|
||||
if permissionID == "" {
|
||||
err = errors.New("missing required permissionID parameter")
|
||||
return
|
||||
}
|
||||
path := fmt.Sprintf("session/%s/permissions/%s", id, permissionID)
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||
return
|
||||
}
|
||||
|
||||
type Permission struct {
|
||||
ID string `json:"id,required"`
|
||||
MessageID string `json:"messageID,required"`
|
||||
Metadata map[string]interface{} `json:"metadata,required"`
|
||||
SessionID string `json:"sessionID,required"`
|
||||
Time PermissionTime `json:"time,required"`
|
||||
Title string `json:"title,required"`
|
||||
Type string `json:"type,required"`
|
||||
CallID string `json:"callID"`
|
||||
Pattern string `json:"pattern"`
|
||||
JSON permissionJSON `json:"-"`
|
||||
}
|
||||
|
||||
// permissionJSON contains the JSON metadata for the struct [Permission]
|
||||
type permissionJSON struct {
|
||||
ID apijson.Field
|
||||
MessageID apijson.Field
|
||||
Metadata apijson.Field
|
||||
SessionID apijson.Field
|
||||
Time apijson.Field
|
||||
Title apijson.Field
|
||||
Type apijson.Field
|
||||
CallID apijson.Field
|
||||
Pattern apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *Permission) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r permissionJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type PermissionTime struct {
|
||||
Created float64 `json:"created,required"`
|
||||
JSON permissionTimeJSON `json:"-"`
|
||||
}
|
||||
|
||||
// permissionTimeJSON contains the JSON metadata for the struct [PermissionTime]
|
||||
type permissionTimeJSON struct {
|
||||
Created apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *PermissionTime) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r permissionTimeJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type SessionPermissionRespondParams struct {
|
||||
Response param.Field[SessionPermissionRespondParamsResponse] `json:"response,required"`
|
||||
}
|
||||
|
||||
func (r SessionPermissionRespondParams) MarshalJSON() (data []byte, err error) {
|
||||
return apijson.MarshalRoot(r)
|
||||
}
|
||||
|
||||
type SessionPermissionRespondParamsResponse string
|
||||
|
||||
const (
|
||||
SessionPermissionRespondParamsResponseOnce SessionPermissionRespondParamsResponse = "once"
|
||||
SessionPermissionRespondParamsResponseAlways SessionPermissionRespondParamsResponse = "always"
|
||||
SessionPermissionRespondParamsResponseReject SessionPermissionRespondParamsResponse = "reject"
|
||||
)
|
||||
|
||||
func (r SessionPermissionRespondParamsResponse) IsKnown() bool {
|
||||
switch r {
|
||||
case SessionPermissionRespondParamsResponseOnce, SessionPermissionRespondParamsResponseAlways, SessionPermissionRespondParamsResponseReject:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
43
packages/sdk/go/sessionpermission_test.go
Normal file
43
packages/sdk/go/sessionpermission_test.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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 TestSessionPermissionRespond(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.Permissions.Respond(
|
||||
context.TODO(),
|
||||
"id",
|
||||
"permissionID",
|
||||
opencode.SessionPermissionRespondParams{
|
||||
Response: opencode.F(opencode.SessionPermissionRespondParamsResponseOnce),
|
||||
},
|
||||
)
|
||||
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())
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,22 @@ func (r *TuiService) AppendPrompt(ctx context.Context, body TuiAppendPromptParam
|
||||
return
|
||||
}
|
||||
|
||||
// Clear the prompt
|
||||
func (r *TuiService) ClearPrompt(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
path := "tui/clear-prompt"
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
||||
return
|
||||
}
|
||||
|
||||
// Execute a TUI command (e.g. switch_mode)
|
||||
func (r *TuiService) ExecuteCommand(ctx context.Context, body TuiExecuteCommandParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
path := "tui/execute-command"
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||
return
|
||||
}
|
||||
|
||||
// Open the help dialog
|
||||
func (r *TuiService) OpenHelp(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
@@ -47,6 +63,38 @@ func (r *TuiService) OpenHelp(ctx context.Context, opts ...option.RequestOption)
|
||||
return
|
||||
}
|
||||
|
||||
// Open the model dialog
|
||||
func (r *TuiService) OpenModels(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
path := "tui/open-models"
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
||||
return
|
||||
}
|
||||
|
||||
// Open the session dialog
|
||||
func (r *TuiService) OpenSessions(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
path := "tui/open-sessions"
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
||||
return
|
||||
}
|
||||
|
||||
// Open the theme dialog
|
||||
func (r *TuiService) OpenThemes(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
path := "tui/open-themes"
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
||||
return
|
||||
}
|
||||
|
||||
// Submit the prompt
|
||||
func (r *TuiService) SubmitPrompt(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
path := "tui/submit-prompt"
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
||||
return
|
||||
}
|
||||
|
||||
type TuiAppendPromptParams struct {
|
||||
Text param.Field[string] `json:"text,required"`
|
||||
}
|
||||
@@ -54,3 +102,11 @@ type TuiAppendPromptParams struct {
|
||||
func (r TuiAppendPromptParams) MarshalJSON() (data []byte, err error) {
|
||||
return apijson.MarshalRoot(r)
|
||||
}
|
||||
|
||||
type TuiExecuteCommandParams struct {
|
||||
Command param.Field[string] `json:"command,required"`
|
||||
}
|
||||
|
||||
func (r TuiExecuteCommandParams) MarshalJSON() (data []byte, err error) {
|
||||
return apijson.MarshalRoot(r)
|
||||
}
|
||||
|
||||
@@ -37,6 +37,52 @@ func TestTuiAppendPrompt(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTuiClearPrompt(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.Tui.ClearPrompt(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())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTuiExecuteCommand(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.Tui.ExecuteCommand(context.TODO(), opencode.TuiExecuteCommandParams{
|
||||
Command: opencode.F("command"),
|
||||
})
|
||||
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 TestTuiOpenHelp(t *testing.T) {
|
||||
t.Skip("skipped: tests are disabled for the time being")
|
||||
baseURL := "http://localhost:4010"
|
||||
@@ -58,3 +104,91 @@ func TestTuiOpenHelp(t *testing.T) {
|
||||
t.Fatalf("err should be nil: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTuiOpenModels(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.Tui.OpenModels(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())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTuiOpenSessions(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.Tui.OpenSessions(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())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTuiOpenThemes(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.Tui.OpenThemes(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())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTuiSubmitPrompt(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.Tui.SubmitPrompt(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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
import type { Options as ClientOptions, TDataShape, Client } from './client';
|
||||
import type { EventSubscribeData, EventSubscribeResponses, AppGetData, AppGetResponses, AppInitData, AppInitResponses, ConfigGetData, ConfigGetResponses, SessionListData, SessionListResponses, SessionCreateData, SessionCreateResponses, SessionCreateErrors, SessionDeleteData, SessionDeleteResponses, SessionInitData, SessionInitResponses, SessionAbortData, SessionAbortResponses, SessionUnshareData, SessionUnshareResponses, SessionShareData, SessionShareResponses, SessionSummarizeData, SessionSummarizeResponses, SessionMessagesData, SessionMessagesResponses, SessionChatData, SessionChatResponses, SessionRevertData, SessionRevertResponses, SessionUnrevertData, SessionUnrevertResponses, ConfigProvidersData, ConfigProvidersResponses, FindTextData, FindTextResponses, FindFilesData, FindFilesResponses, FindSymbolsData, FindSymbolsResponses, FileReadData, FileReadResponses, FileStatusData, FileStatusResponses, AppLogData, AppLogResponses, AppModesData, AppModesResponses, TuiAppendPromptData, TuiAppendPromptResponses, TuiOpenHelpData, TuiOpenHelpResponses } from './types.gen';
|
||||
import type { EventSubscribeData, EventSubscribeResponses, AppGetData, AppGetResponses, AppInitData, AppInitResponses, ConfigGetData, ConfigGetResponses, SessionListData, SessionListResponses, SessionCreateData, SessionCreateResponses, SessionCreateErrors, SessionDeleteData, SessionDeleteResponses, SessionInitData, SessionInitResponses, SessionAbortData, SessionAbortResponses, SessionUnshareData, SessionUnshareResponses, SessionShareData, SessionShareResponses, SessionSummarizeData, SessionSummarizeResponses, SessionMessagesData, SessionMessagesResponses, SessionChatData, SessionChatResponses, SessionMessageData, SessionMessageResponses, SessionRevertData, SessionRevertResponses, SessionUnrevertData, SessionUnrevertResponses, PostSessionByIdPermissionsByPermissionIdData, PostSessionByIdPermissionsByPermissionIdResponses, ConfigProvidersData, ConfigProvidersResponses, FindTextData, FindTextResponses, FindFilesData, FindFilesResponses, FindSymbolsData, FindSymbolsResponses, FileReadData, FileReadResponses, FileStatusData, FileStatusResponses, AppLogData, AppLogResponses, AppModesData, AppModesResponses, TuiAppendPromptData, TuiAppendPromptResponses, TuiOpenHelpData, TuiOpenHelpResponses, TuiOpenSessionsData, TuiOpenSessionsResponses, TuiOpenThemesData, TuiOpenThemesResponses, TuiOpenModelsData, TuiOpenModelsResponses, TuiSubmitPromptData, TuiSubmitPromptResponses, TuiClearPromptData, TuiClearPromptResponses, TuiExecuteCommandData, TuiExecuteCommandResponses } from './types.gen';
|
||||
import { client as _heyApiClient } from './client.gen';
|
||||
|
||||
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
|
||||
@@ -223,6 +223,16 @@ class Session extends _HeyApiClient {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a message from a session
|
||||
*/
|
||||
public message<ThrowOnError extends boolean = false>(options: Options<SessionMessageData, ThrowOnError>) {
|
||||
return (options.client ?? this._client).get<SessionMessageResponses, unknown, ThrowOnError>({
|
||||
url: '/session/{id}/message/{messageID}',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert a message
|
||||
*/
|
||||
@@ -326,9 +336,86 @@ class Tui extends _HeyApiClient {
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the session dialog
|
||||
*/
|
||||
public openSessions<ThrowOnError extends boolean = false>(options?: Options<TuiOpenSessionsData, ThrowOnError>) {
|
||||
return (options?.client ?? this._client).post<TuiOpenSessionsResponses, unknown, ThrowOnError>({
|
||||
url: '/tui/open-sessions',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the theme dialog
|
||||
*/
|
||||
public openThemes<ThrowOnError extends boolean = false>(options?: Options<TuiOpenThemesData, ThrowOnError>) {
|
||||
return (options?.client ?? this._client).post<TuiOpenThemesResponses, unknown, ThrowOnError>({
|
||||
url: '/tui/open-themes',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the model dialog
|
||||
*/
|
||||
public openModels<ThrowOnError extends boolean = false>(options?: Options<TuiOpenModelsData, ThrowOnError>) {
|
||||
return (options?.client ?? this._client).post<TuiOpenModelsResponses, unknown, ThrowOnError>({
|
||||
url: '/tui/open-models',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit the prompt
|
||||
*/
|
||||
public submitPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiSubmitPromptData, ThrowOnError>) {
|
||||
return (options?.client ?? this._client).post<TuiSubmitPromptResponses, unknown, ThrowOnError>({
|
||||
url: '/tui/submit-prompt',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the prompt
|
||||
*/
|
||||
public clearPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiClearPromptData, ThrowOnError>) {
|
||||
return (options?.client ?? this._client).post<TuiClearPromptResponses, unknown, ThrowOnError>({
|
||||
url: '/tui/clear-prompt',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a TUI command (e.g. switch_mode)
|
||||
*/
|
||||
public executeCommand<ThrowOnError extends boolean = false>(options?: Options<TuiExecuteCommandData, ThrowOnError>) {
|
||||
return (options?.client ?? this._client).post<TuiExecuteCommandResponses, unknown, ThrowOnError>({
|
||||
url: '/tui/execute-command',
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options?.headers
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class OpencodeClient extends _HeyApiClient {
|
||||
/**
|
||||
* Respond to a permission request
|
||||
*/
|
||||
public postSessionByIdPermissionsByPermissionId<ThrowOnError extends boolean = false>(options: Options<PostSessionByIdPermissionsByPermissionIdData, ThrowOnError>) {
|
||||
return (options.client ?? this._client).post<PostSessionByIdPermissionsByPermissionIdResponses, unknown, ThrowOnError>({
|
||||
url: '/session/{id}/permissions/{permissionID}',
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers
|
||||
}
|
||||
});
|
||||
}
|
||||
event = new Event({ client: this._client });
|
||||
app = new App({ client: this._client });
|
||||
config = new Config({ client: this._client });
|
||||
|
||||
@@ -17,6 +17,8 @@ export type Event = ({
|
||||
} & EventStorageWrite) | ({
|
||||
type: 'permission.updated';
|
||||
} & EventPermissionUpdated) | ({
|
||||
type: 'permission.replied';
|
||||
} & EventPermissionReplied) | ({
|
||||
type: 'file.edited';
|
||||
} & EventFileEdited) | ({
|
||||
type: 'session.updated';
|
||||
@@ -355,12 +357,16 @@ export type EventStorageWrite = {
|
||||
|
||||
export type EventPermissionUpdated = {
|
||||
type: string;
|
||||
properties: PermissionInfo;
|
||||
properties: Permission;
|
||||
};
|
||||
|
||||
export type PermissionInfo = {
|
||||
export type Permission = {
|
||||
id: string;
|
||||
type: string;
|
||||
pattern?: string;
|
||||
sessionID: string;
|
||||
messageID: string;
|
||||
callID?: string;
|
||||
title: string;
|
||||
metadata: {
|
||||
[key: string]: unknown;
|
||||
@@ -370,6 +376,15 @@ export type PermissionInfo = {
|
||||
};
|
||||
};
|
||||
|
||||
export type EventPermissionReplied = {
|
||||
type: string;
|
||||
properties: {
|
||||
sessionID: string;
|
||||
permissionID: string;
|
||||
response: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type EventFileEdited = {
|
||||
type: string;
|
||||
properties: {
|
||||
@@ -575,6 +590,11 @@ export type Config = {
|
||||
type: 'remote';
|
||||
} & McpRemoteConfig);
|
||||
};
|
||||
formatter?: {
|
||||
[key: string]: {
|
||||
disabled?: boolean;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Additional instruction files or patterns to include
|
||||
*/
|
||||
@@ -1193,6 +1213,34 @@ export type SessionChatResponses = {
|
||||
|
||||
export type SessionChatResponse = SessionChatResponses[keyof SessionChatResponses];
|
||||
|
||||
export type SessionMessageData = {
|
||||
body?: never;
|
||||
path: {
|
||||
/**
|
||||
* Session ID
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Message ID
|
||||
*/
|
||||
messageID: string;
|
||||
};
|
||||
query?: never;
|
||||
url: '/session/{id}/message/{messageID}';
|
||||
};
|
||||
|
||||
export type SessionMessageResponses = {
|
||||
/**
|
||||
* Message
|
||||
*/
|
||||
200: {
|
||||
info: Message;
|
||||
parts: Array<Part>;
|
||||
};
|
||||
};
|
||||
|
||||
export type SessionMessageResponse = SessionMessageResponses[keyof SessionMessageResponses];
|
||||
|
||||
export type SessionRevertData = {
|
||||
body?: {
|
||||
messageID: string;
|
||||
@@ -1232,6 +1280,27 @@ export type SessionUnrevertResponses = {
|
||||
|
||||
export type SessionUnrevertResponse = SessionUnrevertResponses[keyof SessionUnrevertResponses];
|
||||
|
||||
export type PostSessionByIdPermissionsByPermissionIdData = {
|
||||
body?: {
|
||||
response: 'once' | 'always' | 'reject';
|
||||
};
|
||||
path: {
|
||||
id: string;
|
||||
permissionID: string;
|
||||
};
|
||||
query?: never;
|
||||
url: '/session/{id}/permissions/{permissionID}';
|
||||
};
|
||||
|
||||
export type PostSessionByIdPermissionsByPermissionIdResponses = {
|
||||
/**
|
||||
* Permission processed successfully
|
||||
*/
|
||||
200: boolean;
|
||||
};
|
||||
|
||||
export type PostSessionByIdPermissionsByPermissionIdResponse = PostSessionByIdPermissionsByPermissionIdResponses[keyof PostSessionByIdPermissionsByPermissionIdResponses];
|
||||
|
||||
export type ConfigProvidersData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
@@ -1445,6 +1514,104 @@ export type TuiOpenHelpResponses = {
|
||||
|
||||
export type TuiOpenHelpResponse = TuiOpenHelpResponses[keyof TuiOpenHelpResponses];
|
||||
|
||||
export type TuiOpenSessionsData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/tui/open-sessions';
|
||||
};
|
||||
|
||||
export type TuiOpenSessionsResponses = {
|
||||
/**
|
||||
* Session dialog opened successfully
|
||||
*/
|
||||
200: boolean;
|
||||
};
|
||||
|
||||
export type TuiOpenSessionsResponse = TuiOpenSessionsResponses[keyof TuiOpenSessionsResponses];
|
||||
|
||||
export type TuiOpenThemesData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/tui/open-themes';
|
||||
};
|
||||
|
||||
export type TuiOpenThemesResponses = {
|
||||
/**
|
||||
* Theme dialog opened successfully
|
||||
*/
|
||||
200: boolean;
|
||||
};
|
||||
|
||||
export type TuiOpenThemesResponse = TuiOpenThemesResponses[keyof TuiOpenThemesResponses];
|
||||
|
||||
export type TuiOpenModelsData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/tui/open-models';
|
||||
};
|
||||
|
||||
export type TuiOpenModelsResponses = {
|
||||
/**
|
||||
* Model dialog opened successfully
|
||||
*/
|
||||
200: boolean;
|
||||
};
|
||||
|
||||
export type TuiOpenModelsResponse = TuiOpenModelsResponses[keyof TuiOpenModelsResponses];
|
||||
|
||||
export type TuiSubmitPromptData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/tui/submit-prompt';
|
||||
};
|
||||
|
||||
export type TuiSubmitPromptResponses = {
|
||||
/**
|
||||
* Prompt submitted successfully
|
||||
*/
|
||||
200: boolean;
|
||||
};
|
||||
|
||||
export type TuiSubmitPromptResponse = TuiSubmitPromptResponses[keyof TuiSubmitPromptResponses];
|
||||
|
||||
export type TuiClearPromptData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/tui/clear-prompt';
|
||||
};
|
||||
|
||||
export type TuiClearPromptResponses = {
|
||||
/**
|
||||
* Prompt cleared successfully
|
||||
*/
|
||||
200: boolean;
|
||||
};
|
||||
|
||||
export type TuiClearPromptResponse = TuiClearPromptResponses[keyof TuiClearPromptResponses];
|
||||
|
||||
export type TuiExecuteCommandData = {
|
||||
body?: {
|
||||
command: string;
|
||||
};
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/tui/execute-command';
|
||||
};
|
||||
|
||||
export type TuiExecuteCommandResponses = {
|
||||
/**
|
||||
* Command executed successfully
|
||||
*/
|
||||
200: boolean;
|
||||
};
|
||||
|
||||
export type TuiExecuteCommandResponse = TuiExecuteCommandResponses[keyof TuiExecuteCommandResponses];
|
||||
|
||||
export type ClientOptions = {
|
||||
baseUrl: `${string}://${string}` | (string & {});
|
||||
};
|
||||
44
packages/sdk/src/resources/session/index.ts
Normal file
44
packages/sdk/src/resources/session/index.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
export {
|
||||
Permissions,
|
||||
type Permission,
|
||||
type PermissionRespondResponse,
|
||||
type PermissionRespondParams,
|
||||
} from './permissions';
|
||||
export {
|
||||
SessionResource,
|
||||
type AssistantMessage,
|
||||
type FilePart,
|
||||
type FilePartInput,
|
||||
type FilePartSource,
|
||||
type FilePartSourceText,
|
||||
type FileSource,
|
||||
type Message,
|
||||
type Part,
|
||||
type Session,
|
||||
type SnapshotPart,
|
||||
type StepFinishPart,
|
||||
type StepStartPart,
|
||||
type SymbolSource,
|
||||
type TextPart,
|
||||
type TextPartInput,
|
||||
type ToolPart,
|
||||
type ToolStateCompleted,
|
||||
type ToolStateError,
|
||||
type ToolStatePending,
|
||||
type ToolStateRunning,
|
||||
type UserMessage,
|
||||
type SessionListResponse,
|
||||
type SessionDeleteResponse,
|
||||
type SessionAbortResponse,
|
||||
type SessionInitResponse,
|
||||
type SessionMessageResponse,
|
||||
type SessionMessagesResponse,
|
||||
type SessionSummarizeResponse,
|
||||
type SessionChatParams,
|
||||
type SessionInitParams,
|
||||
type SessionMessageParams,
|
||||
type SessionRevertParams,
|
||||
type SessionSummarizeParams,
|
||||
} from './session';
|
||||
64
packages/sdk/src/resources/session/permissions.ts
Normal file
64
packages/sdk/src/resources/session/permissions.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
import { APIResource } from '../../core/resource';
|
||||
import { APIPromise } from '../../core/api-promise';
|
||||
import { RequestOptions } from '../../internal/request-options';
|
||||
import { path } from '../../internal/utils/path';
|
||||
|
||||
export class Permissions extends APIResource {
|
||||
/**
|
||||
* Respond to a permission request
|
||||
*/
|
||||
respond(
|
||||
permissionID: string,
|
||||
params: PermissionRespondParams,
|
||||
options?: RequestOptions,
|
||||
): APIPromise<PermissionRespondResponse> {
|
||||
const { id, ...body } = params;
|
||||
return this._client.post(path`/session/${id}/permissions/${permissionID}`, { body, ...options });
|
||||
}
|
||||
}
|
||||
|
||||
export interface Permission {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
metadata: { [key: string]: unknown };
|
||||
|
||||
sessionID: string;
|
||||
|
||||
time: Permission.Time;
|
||||
|
||||
title: string;
|
||||
|
||||
toolCallID?: string;
|
||||
}
|
||||
|
||||
export namespace Permission {
|
||||
export interface Time {
|
||||
created: number;
|
||||
}
|
||||
}
|
||||
|
||||
export type PermissionRespondResponse = boolean;
|
||||
|
||||
export interface PermissionRespondParams {
|
||||
/**
|
||||
* Path param:
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* Body param:
|
||||
*/
|
||||
response: 'once' | 'always' | 'reject';
|
||||
}
|
||||
|
||||
export declare namespace Permissions {
|
||||
export {
|
||||
type Permission as Permission,
|
||||
type PermissionRespondResponse as PermissionRespondResponse,
|
||||
type PermissionRespondParams as PermissionRespondParams,
|
||||
};
|
||||
}
|
||||
645
packages/sdk/src/resources/session/session.ts
Normal file
645
packages/sdk/src/resources/session/session.ts
Normal file
@@ -0,0 +1,645 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
import { APIResource } from '../../core/resource';
|
||||
import * as SessionAPI from './session';
|
||||
import * as Shared from '../shared';
|
||||
import * as PermissionsAPI from './permissions';
|
||||
import { Permission, PermissionRespondParams, PermissionRespondResponse, Permissions } from './permissions';
|
||||
import { APIPromise } from '../../core/api-promise';
|
||||
import { RequestOptions } from '../../internal/request-options';
|
||||
import { path } from '../../internal/utils/path';
|
||||
|
||||
export class SessionResource extends APIResource {
|
||||
permissions: PermissionsAPI.Permissions = new PermissionsAPI.Permissions(this._client);
|
||||
|
||||
/**
|
||||
* Create a new session
|
||||
*/
|
||||
create(options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.post('/session', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* List all sessions
|
||||
*/
|
||||
list(options?: RequestOptions): APIPromise<SessionListResponse> {
|
||||
return this._client.get('/session', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a session and all its data
|
||||
*/
|
||||
delete(id: string, options?: RequestOptions): APIPromise<SessionDeleteResponse> {
|
||||
return this._client.delete(path`/session/${id}`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort a session
|
||||
*/
|
||||
abort(id: string, options?: RequestOptions): APIPromise<SessionAbortResponse> {
|
||||
return this._client.post(path`/session/${id}/abort`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send a new message to a session
|
||||
*/
|
||||
chat(id: string, body: SessionChatParams, options?: RequestOptions): APIPromise<AssistantMessage> {
|
||||
return this._client.post(path`/session/${id}/message`, { body, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze the app and create an AGENTS.md file
|
||||
*/
|
||||
init(id: string, body: SessionInitParams, options?: RequestOptions): APIPromise<SessionInitResponse> {
|
||||
return this._client.post(path`/session/${id}/init`, { body, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a message from a session
|
||||
*/
|
||||
message(
|
||||
messageID: string,
|
||||
params: SessionMessageParams,
|
||||
options?: RequestOptions,
|
||||
): APIPromise<SessionMessageResponse> {
|
||||
const { id } = params;
|
||||
return this._client.get(path`/session/${id}/message/${messageID}`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* List messages for a session
|
||||
*/
|
||||
messages(id: string, options?: RequestOptions): APIPromise<SessionMessagesResponse> {
|
||||
return this._client.get(path`/session/${id}/message`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert a message
|
||||
*/
|
||||
revert(id: string, body: SessionRevertParams, options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.post(path`/session/${id}/revert`, { body, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Share a session
|
||||
*/
|
||||
share(id: string, options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.post(path`/session/${id}/share`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Summarize the session
|
||||
*/
|
||||
summarize(
|
||||
id: string,
|
||||
body: SessionSummarizeParams,
|
||||
options?: RequestOptions,
|
||||
): APIPromise<SessionSummarizeResponse> {
|
||||
return this._client.post(path`/session/${id}/summarize`, { body, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore all reverted messages
|
||||
*/
|
||||
unrevert(id: string, options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.post(path`/session/${id}/unrevert`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshare the session
|
||||
*/
|
||||
unshare(id: string, options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.delete(path`/session/${id}/share`, options);
|
||||
}
|
||||
}
|
||||
|
||||
export interface AssistantMessage {
|
||||
id: string;
|
||||
|
||||
cost: number;
|
||||
|
||||
mode: string;
|
||||
|
||||
modelID: string;
|
||||
|
||||
path: AssistantMessage.Path;
|
||||
|
||||
providerID: string;
|
||||
|
||||
role: 'assistant';
|
||||
|
||||
sessionID: string;
|
||||
|
||||
system: Array<string>;
|
||||
|
||||
time: AssistantMessage.Time;
|
||||
|
||||
tokens: AssistantMessage.Tokens;
|
||||
|
||||
error?:
|
||||
| Shared.ProviderAuthError
|
||||
| Shared.UnknownError
|
||||
| AssistantMessage.MessageOutputLengthError
|
||||
| Shared.MessageAbortedError;
|
||||
|
||||
summary?: boolean;
|
||||
}
|
||||
|
||||
export namespace AssistantMessage {
|
||||
export interface Path {
|
||||
cwd: string;
|
||||
|
||||
root: string;
|
||||
}
|
||||
|
||||
export interface Time {
|
||||
created: number;
|
||||
|
||||
completed?: number;
|
||||
}
|
||||
|
||||
export interface Tokens {
|
||||
cache: Tokens.Cache;
|
||||
|
||||
input: number;
|
||||
|
||||
output: number;
|
||||
|
||||
reasoning: number;
|
||||
}
|
||||
|
||||
export namespace Tokens {
|
||||
export interface Cache {
|
||||
read: number;
|
||||
|
||||
write: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface MessageOutputLengthError {
|
||||
data: unknown;
|
||||
|
||||
name: 'MessageOutputLengthError';
|
||||
}
|
||||
}
|
||||
|
||||
export interface FilePart {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
mime: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
type: 'file';
|
||||
|
||||
url: string;
|
||||
|
||||
filename?: string;
|
||||
|
||||
source?: FilePartSource;
|
||||
}
|
||||
|
||||
export interface FilePartInput {
|
||||
mime: string;
|
||||
|
||||
type: 'file';
|
||||
|
||||
url: string;
|
||||
|
||||
id?: string;
|
||||
|
||||
filename?: string;
|
||||
|
||||
source?: FilePartSource;
|
||||
}
|
||||
|
||||
export type FilePartSource = FileSource | SymbolSource;
|
||||
|
||||
export interface FilePartSourceText {
|
||||
end: number;
|
||||
|
||||
start: number;
|
||||
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface FileSource {
|
||||
path: string;
|
||||
|
||||
text: FilePartSourceText;
|
||||
|
||||
type: 'file';
|
||||
}
|
||||
|
||||
export type Message = UserMessage | AssistantMessage;
|
||||
|
||||
export type Part =
|
||||
| TextPart
|
||||
| FilePart
|
||||
| ToolPart
|
||||
| StepStartPart
|
||||
| StepFinishPart
|
||||
| SnapshotPart
|
||||
| Part.PatchPart;
|
||||
|
||||
export namespace Part {
|
||||
export interface PatchPart {
|
||||
id: string;
|
||||
|
||||
files: Array<string>;
|
||||
|
||||
hash: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
type: 'patch';
|
||||
}
|
||||
}
|
||||
|
||||
export interface Session {
|
||||
id: string;
|
||||
|
||||
time: Session.Time;
|
||||
|
||||
title: string;
|
||||
|
||||
version: string;
|
||||
|
||||
parentID?: string;
|
||||
|
||||
revert?: Session.Revert;
|
||||
|
||||
share?: Session.Share;
|
||||
}
|
||||
|
||||
export namespace Session {
|
||||
export interface Time {
|
||||
created: number;
|
||||
|
||||
updated: number;
|
||||
}
|
||||
|
||||
export interface Revert {
|
||||
messageID: string;
|
||||
|
||||
diff?: string;
|
||||
|
||||
partID?: string;
|
||||
|
||||
snapshot?: string;
|
||||
}
|
||||
|
||||
export interface Share {
|
||||
url: string;
|
||||
}
|
||||
}
|
||||
|
||||
export interface SnapshotPart {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
snapshot: string;
|
||||
|
||||
type: 'snapshot';
|
||||
}
|
||||
|
||||
export interface StepFinishPart {
|
||||
id: string;
|
||||
|
||||
cost: number;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
tokens: StepFinishPart.Tokens;
|
||||
|
||||
type: 'step-finish';
|
||||
}
|
||||
|
||||
export namespace StepFinishPart {
|
||||
export interface Tokens {
|
||||
cache: Tokens.Cache;
|
||||
|
||||
input: number;
|
||||
|
||||
output: number;
|
||||
|
||||
reasoning: number;
|
||||
}
|
||||
|
||||
export namespace Tokens {
|
||||
export interface Cache {
|
||||
read: number;
|
||||
|
||||
write: number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface StepStartPart {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
type: 'step-start';
|
||||
}
|
||||
|
||||
export interface SymbolSource {
|
||||
kind: number;
|
||||
|
||||
name: string;
|
||||
|
||||
path: string;
|
||||
|
||||
range: SymbolSource.Range;
|
||||
|
||||
text: FilePartSourceText;
|
||||
|
||||
type: 'symbol';
|
||||
}
|
||||
|
||||
export namespace SymbolSource {
|
||||
export interface Range {
|
||||
end: Range.End;
|
||||
|
||||
start: Range.Start;
|
||||
}
|
||||
|
||||
export namespace Range {
|
||||
export interface End {
|
||||
character: number;
|
||||
|
||||
line: number;
|
||||
}
|
||||
|
||||
export interface Start {
|
||||
character: number;
|
||||
|
||||
line: number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface TextPart {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
text: string;
|
||||
|
||||
type: 'text';
|
||||
|
||||
synthetic?: boolean;
|
||||
|
||||
time?: TextPart.Time;
|
||||
}
|
||||
|
||||
export namespace TextPart {
|
||||
export interface Time {
|
||||
start: number;
|
||||
|
||||
end?: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface TextPartInput {
|
||||
text: string;
|
||||
|
||||
type: 'text';
|
||||
|
||||
id?: string;
|
||||
|
||||
synthetic?: boolean;
|
||||
|
||||
time?: TextPartInput.Time;
|
||||
}
|
||||
|
||||
export namespace TextPartInput {
|
||||
export interface Time {
|
||||
start: number;
|
||||
|
||||
end?: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ToolPart {
|
||||
id: string;
|
||||
|
||||
callID: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
state: ToolStatePending | ToolStateRunning | ToolStateCompleted | ToolStateError;
|
||||
|
||||
tool: string;
|
||||
|
||||
type: 'tool';
|
||||
}
|
||||
|
||||
export interface ToolStateCompleted {
|
||||
input: { [key: string]: unknown };
|
||||
|
||||
metadata: { [key: string]: unknown };
|
||||
|
||||
output: string;
|
||||
|
||||
status: 'completed';
|
||||
|
||||
time: ToolStateCompleted.Time;
|
||||
|
||||
title: string;
|
||||
}
|
||||
|
||||
export namespace ToolStateCompleted {
|
||||
export interface Time {
|
||||
end: number;
|
||||
|
||||
start: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ToolStateError {
|
||||
error: string;
|
||||
|
||||
input: { [key: string]: unknown };
|
||||
|
||||
status: 'error';
|
||||
|
||||
time: ToolStateError.Time;
|
||||
}
|
||||
|
||||
export namespace ToolStateError {
|
||||
export interface Time {
|
||||
end: number;
|
||||
|
||||
start: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ToolStatePending {
|
||||
status: 'pending';
|
||||
}
|
||||
|
||||
export interface ToolStateRunning {
|
||||
status: 'running';
|
||||
|
||||
time: ToolStateRunning.Time;
|
||||
|
||||
input?: unknown;
|
||||
|
||||
metadata?: { [key: string]: unknown };
|
||||
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export namespace ToolStateRunning {
|
||||
export interface Time {
|
||||
start: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface UserMessage {
|
||||
id: string;
|
||||
|
||||
role: 'user';
|
||||
|
||||
sessionID: string;
|
||||
|
||||
time: UserMessage.Time;
|
||||
}
|
||||
|
||||
export namespace UserMessage {
|
||||
export interface Time {
|
||||
created: number;
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionListResponse = Array<Session>;
|
||||
|
||||
export type SessionDeleteResponse = boolean;
|
||||
|
||||
export type SessionAbortResponse = boolean;
|
||||
|
||||
export type SessionInitResponse = boolean;
|
||||
|
||||
export interface SessionMessageResponse {
|
||||
info: Message;
|
||||
|
||||
parts: Array<Part>;
|
||||
}
|
||||
|
||||
export type SessionMessagesResponse = Array<SessionMessagesResponse.SessionMessagesResponseItem>;
|
||||
|
||||
export namespace SessionMessagesResponse {
|
||||
export interface SessionMessagesResponseItem {
|
||||
info: SessionAPI.Message;
|
||||
|
||||
parts: Array<SessionAPI.Part>;
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionSummarizeResponse = boolean;
|
||||
|
||||
export interface SessionChatParams {
|
||||
modelID: string;
|
||||
|
||||
parts: Array<TextPartInput | FilePartInput>;
|
||||
|
||||
providerID: string;
|
||||
|
||||
messageID?: string;
|
||||
|
||||
mode?: string;
|
||||
|
||||
system?: string;
|
||||
|
||||
tools?: { [key: string]: boolean };
|
||||
}
|
||||
|
||||
export interface SessionInitParams {
|
||||
messageID: string;
|
||||
|
||||
modelID: string;
|
||||
|
||||
providerID: string;
|
||||
}
|
||||
|
||||
export interface SessionMessageParams {
|
||||
/**
|
||||
* Session ID
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface SessionRevertParams {
|
||||
messageID: string;
|
||||
|
||||
partID?: string;
|
||||
}
|
||||
|
||||
export interface SessionSummarizeParams {
|
||||
modelID: string;
|
||||
|
||||
providerID: string;
|
||||
}
|
||||
|
||||
SessionResource.Permissions = Permissions;
|
||||
|
||||
export declare namespace SessionResource {
|
||||
export {
|
||||
type AssistantMessage as AssistantMessage,
|
||||
type FilePart as FilePart,
|
||||
type FilePartInput as FilePartInput,
|
||||
type FilePartSource as FilePartSource,
|
||||
type FilePartSourceText as FilePartSourceText,
|
||||
type FileSource as FileSource,
|
||||
type Message as Message,
|
||||
type Part as Part,
|
||||
type Session as Session,
|
||||
type SnapshotPart as SnapshotPart,
|
||||
type StepFinishPart as StepFinishPart,
|
||||
type StepStartPart as StepStartPart,
|
||||
type SymbolSource as SymbolSource,
|
||||
type TextPart as TextPart,
|
||||
type TextPartInput as TextPartInput,
|
||||
type ToolPart as ToolPart,
|
||||
type ToolStateCompleted as ToolStateCompleted,
|
||||
type ToolStateError as ToolStateError,
|
||||
type ToolStatePending as ToolStatePending,
|
||||
type ToolStateRunning as ToolStateRunning,
|
||||
type UserMessage as UserMessage,
|
||||
type SessionListResponse as SessionListResponse,
|
||||
type SessionDeleteResponse as SessionDeleteResponse,
|
||||
type SessionAbortResponse as SessionAbortResponse,
|
||||
type SessionInitResponse as SessionInitResponse,
|
||||
type SessionMessageResponse as SessionMessageResponse,
|
||||
type SessionMessagesResponse as SessionMessagesResponse,
|
||||
type SessionSummarizeResponse as SessionSummarizeResponse,
|
||||
type SessionChatParams as SessionChatParams,
|
||||
type SessionInitParams as SessionInitParams,
|
||||
type SessionMessageParams as SessionMessageParams,
|
||||
type SessionRevertParams as SessionRevertParams,
|
||||
type SessionSummarizeParams as SessionSummarizeParams,
|
||||
};
|
||||
|
||||
export {
|
||||
Permissions as Permissions,
|
||||
type Permission as Permission,
|
||||
type PermissionRespondResponse as PermissionRespondResponse,
|
||||
type PermissionRespondParams as PermissionRespondParams,
|
||||
};
|
||||
}
|
||||
@@ -118,15 +118,29 @@ resources:
|
||||
share: post /session/{id}/share
|
||||
unshare: delete /session/{id}/share
|
||||
summarize: post /session/{id}/summarize
|
||||
message: get /session/{id}/message/{messageID}
|
||||
messages: get /session/{id}/message
|
||||
chat: post /session/{id}/message
|
||||
revert: post /session/{id}/revert
|
||||
unrevert: post /session/{id}/unrevert
|
||||
|
||||
subresources:
|
||||
permissions:
|
||||
models:
|
||||
permission: Permission
|
||||
methods:
|
||||
respond: post /session/{id}/permissions/{permissionID}
|
||||
|
||||
tui:
|
||||
methods:
|
||||
appendPrompt: post /tui/append-prompt
|
||||
submitPrompt: post /tui/submit-prompt
|
||||
clearPrompt: post /tui/clear-prompt
|
||||
openHelp: post /tui/open-help
|
||||
openSessions: post /tui/open-sessions
|
||||
openThemes: post /tui/open-themes
|
||||
openModels: post /tui/open-models
|
||||
executeCommand: post /tui/execute-command
|
||||
|
||||
settings:
|
||||
disable_mock_tests: true
|
||||
|
||||
27
packages/sdk/tests/api-resources/session/permissions.test.ts
Normal file
27
packages/sdk/tests/api-resources/session/permissions.test.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
import Opencode from '@opencode-ai/sdk';
|
||||
|
||||
const client = new Opencode({ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010' });
|
||||
|
||||
describe('resource permissions', () => {
|
||||
// skipped: tests are disabled for the time being
|
||||
test.skip('respond: only required params', async () => {
|
||||
const responsePromise = client.session.permissions.respond('permissionID', {
|
||||
id: 'id',
|
||||
response: 'once',
|
||||
});
|
||||
const rawResponse = await responsePromise.asResponse();
|
||||
expect(rawResponse).toBeInstanceOf(Response);
|
||||
const response = await responsePromise;
|
||||
expect(response).not.toBeInstanceOf(Response);
|
||||
const dataAndResponse = await responsePromise.withResponse();
|
||||
expect(dataAndResponse.data).toBe(response);
|
||||
expect(dataAndResponse.response).toBe(rawResponse);
|
||||
});
|
||||
|
||||
// skipped: tests are disabled for the time being
|
||||
test.skip('respond: required and optional params', async () => {
|
||||
const response = await client.session.permissions.respond('permissionID', { id: 'id', response: 'once' });
|
||||
});
|
||||
});
|
||||
@@ -86,7 +86,7 @@ func main() {
|
||||
logger := slog.New(apiHandler)
|
||||
slog.SetDefault(logger)
|
||||
|
||||
slog.Debug("TUI launched", "app", appInfoStr, "modes", modesStr)
|
||||
slog.Debug("TUI launched", "app", appInfoStr, "modes", modesStr, "url", url)
|
||||
|
||||
go func() {
|
||||
err = clipboard.Init()
|
||||
|
||||
@@ -24,7 +24,7 @@ require (
|
||||
|
||||
replace (
|
||||
github.com/charmbracelet/x/input => ./input
|
||||
github.com/sst/opencode-sdk-go => ./sdk
|
||||
github.com/sst/opencode-sdk-go => ../sdk/go
|
||||
)
|
||||
|
||||
require golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||
|
||||
@@ -26,26 +26,28 @@ type Message struct {
|
||||
}
|
||||
|
||||
type App struct {
|
||||
Info opencode.App
|
||||
Modes []opencode.Mode
|
||||
Providers []opencode.Provider
|
||||
Version string
|
||||
StatePath string
|
||||
Config *opencode.Config
|
||||
Client *opencode.Client
|
||||
State *State
|
||||
ModeIndex int
|
||||
Mode *opencode.Mode
|
||||
Provider *opencode.Provider
|
||||
Model *opencode.Model
|
||||
Session *opencode.Session
|
||||
Messages []Message
|
||||
Commands commands.CommandRegistry
|
||||
InitialModel *string
|
||||
InitialPrompt *string
|
||||
IntitialMode *string
|
||||
compactCancel context.CancelFunc
|
||||
IsLeaderSequence bool
|
||||
Info opencode.App
|
||||
Modes []opencode.Mode
|
||||
Providers []opencode.Provider
|
||||
Version string
|
||||
StatePath string
|
||||
Config *opencode.Config
|
||||
Client *opencode.Client
|
||||
State *State
|
||||
ModeIndex int
|
||||
Mode *opencode.Mode
|
||||
Provider *opencode.Provider
|
||||
Model *opencode.Model
|
||||
Session *opencode.Session
|
||||
Messages []Message
|
||||
Permissions []opencode.Permission
|
||||
CurrentPermission opencode.Permission
|
||||
Commands commands.CommandRegistry
|
||||
InitialModel *string
|
||||
InitialPrompt *string
|
||||
IntitialMode *string
|
||||
compactCancel context.CancelFunc
|
||||
IsLeaderSequence bool
|
||||
}
|
||||
|
||||
type SessionCreatedMsg = struct {
|
||||
@@ -73,6 +75,9 @@ type SetEditorContentMsg struct {
|
||||
type FileRenderedMsg struct {
|
||||
FilePath string
|
||||
}
|
||||
type PermissionRespondedToMsg struct {
|
||||
Response opencode.SessionPermissionRespondParamsResponse
|
||||
}
|
||||
|
||||
func New(
|
||||
ctx context.Context,
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/charmbracelet/bubbles/v2/spinner"
|
||||
tea "github.com/charmbracelet/bubbletea/v2"
|
||||
@@ -344,9 +345,13 @@ func (m *editorComponent) Content() string {
|
||||
hint = base(keyText+" again") + muted(" to exit")
|
||||
} else if m.app.IsBusy() {
|
||||
keyText := m.getInterruptKeyText()
|
||||
if m.interruptKeyInDebounce {
|
||||
status := "working"
|
||||
if m.app.CurrentPermission.ID != "" {
|
||||
status = "waiting for permission"
|
||||
}
|
||||
if m.interruptKeyInDebounce && m.app.CurrentPermission.ID == "" {
|
||||
hint = muted(
|
||||
"working",
|
||||
status,
|
||||
) + m.spinner.View() + muted(
|
||||
" ",
|
||||
) + base(
|
||||
@@ -355,7 +360,10 @@ func (m *editorComponent) Content() string {
|
||||
" interrupt",
|
||||
)
|
||||
} else {
|
||||
hint = muted("working") + m.spinner.View() + muted(" ") + base(keyText) + muted(" interrupt")
|
||||
hint = muted(status) + m.spinner.View()
|
||||
if m.app.CurrentPermission.ID == "" {
|
||||
hint += muted(" ") + base(keyText) + muted(" interrupt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,14 +525,18 @@ func (m *editorComponent) SetValueWithAttachments(value string) {
|
||||
|
||||
i := 0
|
||||
for i < len(value) {
|
||||
r, size := utf8.DecodeRuneInString(value[i:])
|
||||
// Check if filepath and add attachment
|
||||
if value[i] == '@' {
|
||||
start := i + 1
|
||||
if r == '@' {
|
||||
start := i + size
|
||||
end := start
|
||||
for end < len(value) && value[end] != ' ' && value[end] != '\t' && value[end] != '\n' && value[end] != '\r' {
|
||||
end++
|
||||
for end < len(value) {
|
||||
nextR, nextSize := utf8.DecodeRuneInString(value[end:])
|
||||
if nextR == ' ' || nextR == '\t' || nextR == '\n' || nextR == '\r' {
|
||||
break
|
||||
}
|
||||
end += nextSize
|
||||
}
|
||||
|
||||
if end > start {
|
||||
filePath := value[start:end]
|
||||
slog.Debug("test", "filePath", filePath)
|
||||
@@ -541,8 +553,8 @@ func (m *editorComponent) SetValueWithAttachments(value string) {
|
||||
}
|
||||
|
||||
// Not a valid file path, insert the character normally
|
||||
m.textarea.InsertRune(rune(value[i]))
|
||||
i++
|
||||
m.textarea.InsertRune(r)
|
||||
i += size
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package chat
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -22,16 +23,17 @@ import (
|
||||
)
|
||||
|
||||
type blockRenderer struct {
|
||||
textColor compat.AdaptiveColor
|
||||
border bool
|
||||
borderColor *compat.AdaptiveColor
|
||||
borderColorRight bool
|
||||
paddingTop int
|
||||
paddingBottom int
|
||||
paddingLeft int
|
||||
paddingRight int
|
||||
marginTop int
|
||||
marginBottom int
|
||||
textColor compat.AdaptiveColor
|
||||
border bool
|
||||
borderColor *compat.AdaptiveColor
|
||||
borderLeft bool
|
||||
borderRight bool
|
||||
paddingTop int
|
||||
paddingBottom int
|
||||
paddingLeft int
|
||||
paddingRight int
|
||||
marginTop int
|
||||
marginBottom int
|
||||
}
|
||||
|
||||
type renderingOption func(*blockRenderer)
|
||||
@@ -54,10 +56,26 @@ func WithBorderColor(color compat.AdaptiveColor) renderingOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithBorderColorRight(color compat.AdaptiveColor) renderingOption {
|
||||
func WithBorderLeft() renderingOption {
|
||||
return func(c *blockRenderer) {
|
||||
c.borderColorRight = true
|
||||
c.borderColor = &color
|
||||
c.borderLeft = true
|
||||
c.borderRight = false
|
||||
}
|
||||
}
|
||||
|
||||
func WithBorderRight() renderingOption {
|
||||
return func(c *blockRenderer) {
|
||||
c.borderLeft = false
|
||||
c.borderRight = true
|
||||
}
|
||||
}
|
||||
|
||||
func WithBorderBoth(value bool) renderingOption {
|
||||
return func(c *blockRenderer) {
|
||||
if value {
|
||||
c.borderLeft = true
|
||||
c.borderRight = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +134,8 @@ func renderContentBlock(
|
||||
renderer := &blockRenderer{
|
||||
textColor: t.TextMuted(),
|
||||
border: true,
|
||||
borderLeft: true,
|
||||
borderRight: false,
|
||||
paddingTop: 1,
|
||||
paddingBottom: 1,
|
||||
paddingLeft: 2,
|
||||
@@ -144,19 +164,17 @@ func renderContentBlock(
|
||||
BorderStyle(lipgloss.ThickBorder()).
|
||||
BorderLeft(true).
|
||||
BorderRight(true).
|
||||
BorderLeftForeground(borderColor).
|
||||
BorderLeftForeground(t.BackgroundPanel()).
|
||||
BorderLeftBackground(t.Background()).
|
||||
BorderRightForeground(t.BackgroundPanel()).
|
||||
BorderRightBackground(t.Background())
|
||||
|
||||
if renderer.borderColorRight {
|
||||
style = style.
|
||||
BorderLeftBackground(t.Background()).
|
||||
BorderLeftForeground(t.BackgroundPanel()).
|
||||
BorderRightForeground(borderColor).
|
||||
BorderRightBackground(t.Background())
|
||||
if renderer.borderLeft {
|
||||
style = style.BorderLeftForeground(borderColor)
|
||||
}
|
||||
if renderer.borderRight {
|
||||
style = style.BorderRightForeground(borderColor)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
content = style.Render(content)
|
||||
@@ -223,7 +241,7 @@ func renderText(
|
||||
if !showToolDetails && toolCalls != nil && len(toolCalls) > 0 {
|
||||
content = content + "\n\n"
|
||||
for _, toolCall := range toolCalls {
|
||||
title := renderToolTitle(toolCall, width)
|
||||
title := renderToolTitle(toolCall, width-2)
|
||||
style := styles.NewStyle()
|
||||
if toolCall.State.Status == opencode.ToolPartStateStatusError {
|
||||
style = style.Foreground(t.Error())
|
||||
@@ -247,7 +265,8 @@ func renderText(
|
||||
content,
|
||||
width,
|
||||
WithTextColor(t.Text()),
|
||||
WithBorderColorRight(t.Secondary()),
|
||||
WithBorderColor(t.Secondary()),
|
||||
WithBorderRight(),
|
||||
)
|
||||
case opencode.AssistantMessage:
|
||||
return renderContentBlock(
|
||||
@@ -263,6 +282,7 @@ func renderText(
|
||||
func renderToolDetails(
|
||||
app *app.App,
|
||||
toolCall opencode.ToolPart,
|
||||
permission opencode.Permission,
|
||||
width int,
|
||||
) string {
|
||||
measure := util.Measure("chat.renderToolDetails")
|
||||
@@ -301,6 +321,39 @@ func renderToolDetails(
|
||||
borderColor := t.BackgroundPanel()
|
||||
defaultStyle := styles.NewStyle().Background(backgroundColor).Width(width - 6).Render
|
||||
|
||||
permissionContent := ""
|
||||
if permission.ID != "" {
|
||||
borderColor = t.Warning()
|
||||
|
||||
base := styles.NewStyle().Background(backgroundColor)
|
||||
text := base.Foreground(t.Text()).Bold(true).Render
|
||||
muted := base.Foreground(t.TextMuted()).Render
|
||||
permissionContent = "Permission required to run this tool:\n\n"
|
||||
permissionContent += text(
|
||||
"enter ",
|
||||
) + muted(
|
||||
"accept ",
|
||||
) + text(
|
||||
"a",
|
||||
) + muted(
|
||||
" accept always ",
|
||||
) + text(
|
||||
"esc",
|
||||
) + muted(
|
||||
" reject",
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
if permission.Metadata != nil {
|
||||
metadata := toolCall.State.Metadata.(map[string]any)
|
||||
if metadata == nil {
|
||||
metadata = map[string]any{}
|
||||
}
|
||||
maps.Copy(metadata, permission.Metadata)
|
||||
toolCall.State.Metadata = metadata
|
||||
}
|
||||
|
||||
if toolCall.State.Metadata != nil {
|
||||
metadata := toolCall.State.Metadata.(map[string]any)
|
||||
switch toolCall.Tool {
|
||||
@@ -351,12 +404,20 @@ func renderToolDetails(
|
||||
title := renderToolTitle(toolCall, width)
|
||||
title = style.Render(title)
|
||||
content := title + "\n" + body
|
||||
if permissionContent != "" {
|
||||
permissionContent = styles.NewStyle().
|
||||
Background(backgroundColor).
|
||||
Padding(1, 2).
|
||||
Render(permissionContent)
|
||||
content += "\n" + permissionContent
|
||||
}
|
||||
content = renderContentBlock(
|
||||
app,
|
||||
content,
|
||||
width,
|
||||
WithPadding(0),
|
||||
WithBorderColor(borderColor),
|
||||
WithBorderBoth(permission.ID != ""),
|
||||
)
|
||||
return content
|
||||
}
|
||||
@@ -417,7 +478,7 @@ func renderToolDetails(
|
||||
data, _ := json.Marshal(item)
|
||||
var toolCall opencode.ToolPart
|
||||
_ = json.Unmarshal(data, &toolCall)
|
||||
step := renderToolTitle(toolCall, width)
|
||||
step := renderToolTitle(toolCall, width-2)
|
||||
step = "∟ " + step
|
||||
steps = append(steps, step)
|
||||
}
|
||||
@@ -460,7 +521,18 @@ func renderToolDetails(
|
||||
|
||||
title := renderToolTitle(toolCall, width)
|
||||
content := title + "\n\n" + body
|
||||
return renderContentBlock(app, content, width, WithBorderColor(borderColor))
|
||||
|
||||
if permissionContent != "" {
|
||||
content += "\n\n\n" + permissionContent
|
||||
}
|
||||
|
||||
return renderContentBlock(
|
||||
app,
|
||||
content,
|
||||
width,
|
||||
WithBorderColor(borderColor),
|
||||
WithBorderBoth(permission.ID != ""),
|
||||
)
|
||||
}
|
||||
|
||||
func renderToolName(name string) string {
|
||||
@@ -575,6 +647,10 @@ func renderToolTitle(
|
||||
}
|
||||
|
||||
title = truncate.StringWithTail(title, uint(width-6), "...")
|
||||
if toolCall.State.Error != "" {
|
||||
t := theme.CurrentTheme()
|
||||
title = styles.NewStyle().Foreground(t.Error()).Render(title)
|
||||
}
|
||||
return title
|
||||
}
|
||||
|
||||
|
||||
@@ -100,8 +100,6 @@ func (m *messagesComponent) Init() tea.Cmd {
|
||||
}
|
||||
|
||||
func (m *messagesComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
measure := util.Measure("messages.Update")
|
||||
defer measure("from", fmt.Sprintf("%T", msg))
|
||||
var cmds []tea.Cmd
|
||||
switch msg := msg.(type) {
|
||||
case tea.MouseClickMsg:
|
||||
@@ -199,6 +197,12 @@ func (m *messagesComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.cache.Clear()
|
||||
cmds = append(cmds, m.renderView())
|
||||
}
|
||||
case opencode.EventListResponseEventPermissionUpdated:
|
||||
m.tail = true
|
||||
return m, m.renderView()
|
||||
case opencode.EventListResponseEventPermissionReplied:
|
||||
m.tail = true
|
||||
return m, m.renderView()
|
||||
case renderCompleteMsg:
|
||||
m.partCount = msg.partCount
|
||||
m.lineCount = msg.lineCount
|
||||
@@ -214,6 +218,7 @@ func (m *messagesComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
m.tail = m.viewport.AtBottom()
|
||||
|
||||
viewport, cmd := m.viewport.Update(msg)
|
||||
m.viewport = viewport
|
||||
cmds = append(cmds, cmd)
|
||||
@@ -465,7 +470,13 @@ func (m *messagesComponent) renderView() tea.Cmd {
|
||||
revertedToolCount++
|
||||
continue
|
||||
}
|
||||
if !m.showToolDetails {
|
||||
|
||||
permission := opencode.Permission{}
|
||||
if m.app.CurrentPermission.CallID == part.CallID {
|
||||
permission = m.app.CurrentPermission
|
||||
}
|
||||
|
||||
if !m.showToolDetails && permission.ID == "" {
|
||||
if !hasTextPart {
|
||||
orphanedToolCalls = append(orphanedToolCalls, part)
|
||||
}
|
||||
@@ -477,12 +488,14 @@ func (m *messagesComponent) renderView() tea.Cmd {
|
||||
part.ID,
|
||||
m.showToolDetails,
|
||||
width,
|
||||
permission.ID,
|
||||
)
|
||||
content, cached = m.cache.Get(key)
|
||||
if !cached {
|
||||
content = renderToolDetails(
|
||||
m.app,
|
||||
part,
|
||||
permission,
|
||||
width,
|
||||
)
|
||||
content = lipgloss.PlaceHorizontal(
|
||||
@@ -498,6 +511,7 @@ func (m *messagesComponent) renderView() tea.Cmd {
|
||||
content = renderToolDetails(
|
||||
m.app,
|
||||
part,
|
||||
permission,
|
||||
width,
|
||||
)
|
||||
content = lipgloss.PlaceHorizontal(
|
||||
@@ -618,6 +632,40 @@ func (m *messagesComponent) renderView() tea.Cmd {
|
||||
blocks = append(blocks, content)
|
||||
}
|
||||
|
||||
if m.app.CurrentPermission.ID != "" &&
|
||||
m.app.CurrentPermission.SessionID != m.app.Session.ID {
|
||||
response, err := m.app.Client.Session.Message(
|
||||
context.Background(),
|
||||
m.app.CurrentPermission.SessionID,
|
||||
m.app.CurrentPermission.MessageID,
|
||||
)
|
||||
if err != nil || response == nil {
|
||||
slog.Error("Failed to get message from child session", "error", err)
|
||||
} else {
|
||||
for _, part := range response.Parts {
|
||||
if part.CallID == m.app.CurrentPermission.CallID {
|
||||
content := renderToolDetails(
|
||||
m.app,
|
||||
part.AsUnion().(opencode.ToolPart),
|
||||
m.app.CurrentPermission,
|
||||
width,
|
||||
)
|
||||
content = lipgloss.PlaceHorizontal(
|
||||
m.width,
|
||||
lipgloss.Center,
|
||||
content,
|
||||
styles.WhitespaceStyle(t.Background()),
|
||||
)
|
||||
if content != "" {
|
||||
partCount++
|
||||
lineCount += lipgloss.Height(content) + 1
|
||||
blocks = append(blocks, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final := []string{}
|
||||
clipboard := []string{}
|
||||
var selection *selection
|
||||
@@ -846,9 +894,7 @@ func (m *messagesComponent) View() string {
|
||||
)
|
||||
}
|
||||
|
||||
measure := util.Measure("messages.View")
|
||||
viewport := m.viewport.View()
|
||||
measure()
|
||||
return styles.NewStyle().
|
||||
Background(t.Background()).
|
||||
Render(m.header + "\n" + viewport)
|
||||
|
||||
@@ -138,8 +138,6 @@ func (s *sessionDialog) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
)
|
||||
}
|
||||
case "n":
|
||||
s.app.Session = &opencode.Session{}
|
||||
s.app.Messages = []app.Message{}
|
||||
return s, tea.Sequence(
|
||||
util.CmdHandler(modal.CloseModalMsg{}),
|
||||
util.CmdHandler(app.SessionClearedMsg{}),
|
||||
|
||||
@@ -103,9 +103,6 @@ func (a Model) Init() tea.Cmd {
|
||||
}
|
||||
|
||||
func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
measure := util.Measure("app.Update")
|
||||
defer measure("from", fmt.Sprintf("%T", msg))
|
||||
|
||||
var cmd tea.Cmd
|
||||
var cmds []tea.Cmd
|
||||
|
||||
@@ -113,6 +110,44 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case tea.KeyPressMsg:
|
||||
keyString := msg.String()
|
||||
|
||||
if a.app.CurrentPermission.ID != "" {
|
||||
if keyString == "enter" || keyString == "esc" || keyString == "a" {
|
||||
sessionID := a.app.CurrentPermission.SessionID
|
||||
permissionID := a.app.CurrentPermission.ID
|
||||
a.editor.Focus()
|
||||
a.app.Permissions = a.app.Permissions[1:]
|
||||
if len(a.app.Permissions) > 0 {
|
||||
a.app.CurrentPermission = a.app.Permissions[0]
|
||||
} else {
|
||||
a.app.CurrentPermission = opencode.Permission{}
|
||||
}
|
||||
response := opencode.SessionPermissionRespondParamsResponseOnce
|
||||
switch keyString {
|
||||
case "enter":
|
||||
response = opencode.SessionPermissionRespondParamsResponseOnce
|
||||
case "a":
|
||||
response = opencode.SessionPermissionRespondParamsResponseAlways
|
||||
case "esc":
|
||||
response = opencode.SessionPermissionRespondParamsResponseReject
|
||||
}
|
||||
|
||||
return a, func() tea.Msg {
|
||||
resp, err := a.app.Client.Session.Permissions.Respond(
|
||||
context.Background(),
|
||||
sessionID,
|
||||
permissionID,
|
||||
opencode.SessionPermissionRespondParams{Response: opencode.F(response)},
|
||||
)
|
||||
if err != nil {
|
||||
slog.Error("Failed to respond to permission request", "error", err)
|
||||
return toast.NewErrorToast("Failed to respond to permission request")
|
||||
}
|
||||
slog.Debug("Responded to permission request", "response", resp)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Handle active modal
|
||||
if a.modal != nil {
|
||||
switch keyString {
|
||||
@@ -341,6 +376,9 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
updated, cmd := a.editor.Focus()
|
||||
a.editor = updated.(chat.EditorComponent)
|
||||
cmds = append(cmds, cmd)
|
||||
case app.SessionClearedMsg:
|
||||
a.app.Session = &opencode.Session{}
|
||||
a.app.Messages = []app.Message{}
|
||||
case dialog.CompletionDialogCloseMsg:
|
||||
a.showCompletionDialog = false
|
||||
case opencode.EventListResponseEventInstallationUpdated:
|
||||
@@ -364,7 +402,7 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
a.app.Session = &msg.Properties.Info
|
||||
}
|
||||
case opencode.EventListResponseEventMessagePartUpdated:
|
||||
slog.Info("message part updated", "message", msg.Properties.Part.MessageID, "part", msg.Properties.Part.ID)
|
||||
slog.Debug("message part updated", "message", msg.Properties.Part.MessageID, "part", msg.Properties.Part.ID)
|
||||
if msg.Properties.Part.SessionID == a.app.Session.ID {
|
||||
messageIndex := slices.IndexFunc(a.app.Messages, func(m app.Message) bool {
|
||||
switch casted := m.Info.(type) {
|
||||
@@ -402,7 +440,7 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
}
|
||||
case opencode.EventListResponseEventMessagePartRemoved:
|
||||
slog.Info("message part removed", "session", msg.Properties.SessionID, "message", msg.Properties.MessageID, "part", msg.Properties.PartID)
|
||||
slog.Debug("message part removed", "session", msg.Properties.SessionID, "message", msg.Properties.MessageID, "part", msg.Properties.PartID)
|
||||
if msg.Properties.SessionID == a.app.Session.ID {
|
||||
messageIndex := slices.IndexFunc(a.app.Messages, func(m app.Message) bool {
|
||||
switch casted := m.Info.(type) {
|
||||
@@ -438,7 +476,7 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
}
|
||||
case opencode.EventListResponseEventMessageRemoved:
|
||||
slog.Info("message removed", "session", msg.Properties.SessionID, "message", msg.Properties.MessageID)
|
||||
slog.Debug("message removed", "session", msg.Properties.SessionID, "message", msg.Properties.MessageID)
|
||||
if msg.Properties.SessionID == a.app.Session.ID {
|
||||
messageIndex := slices.IndexFunc(a.app.Messages, func(m app.Message) bool {
|
||||
switch casted := m.Info.(type) {
|
||||
@@ -480,6 +518,25 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
})
|
||||
}
|
||||
}
|
||||
case opencode.EventListResponseEventPermissionUpdated:
|
||||
slog.Debug("permission updated", "session", msg.Properties.SessionID, "permission", msg.Properties.ID)
|
||||
a.app.Permissions = append(a.app.Permissions, msg.Properties)
|
||||
a.app.CurrentPermission = a.app.Permissions[0]
|
||||
a.editor.Blur()
|
||||
case opencode.EventListResponseEventPermissionReplied:
|
||||
index := slices.IndexFunc(a.app.Permissions, func(p opencode.Permission) bool {
|
||||
return p.ID == msg.Properties.PermissionID
|
||||
})
|
||||
if index > -1 {
|
||||
a.app.Permissions = append(a.app.Permissions[:index], a.app.Permissions[index+1:]...)
|
||||
}
|
||||
if a.app.CurrentPermission.ID == msg.Properties.PermissionID {
|
||||
if len(a.app.Permissions) > 0 {
|
||||
a.app.CurrentPermission = a.app.Permissions[0]
|
||||
} else {
|
||||
a.app.CurrentPermission = opencode.Permission{}
|
||||
}
|
||||
}
|
||||
case opencode.EventListResponseEventSessionError:
|
||||
switch err := msg.Properties.Error.AsUnion().(type) {
|
||||
case nil:
|
||||
@@ -564,6 +621,15 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case "/tui/open-help":
|
||||
helpDialog := dialog.NewHelpDialog(a.app)
|
||||
a.modal = helpDialog
|
||||
case "/tui/open-sessions":
|
||||
sessionDialog := dialog.NewSessionDialog(a.app)
|
||||
a.modal = sessionDialog
|
||||
case "/tui/open-themes":
|
||||
themeDialog := dialog.NewThemeDialog()
|
||||
a.modal = themeDialog
|
||||
case "/tui/open-models":
|
||||
modelDialog := dialog.NewModelDialog(a.app)
|
||||
a.modal = modelDialog
|
||||
case "/tui/append-prompt":
|
||||
var body struct {
|
||||
Text string `json:"text"`
|
||||
@@ -575,6 +641,34 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
text = " " + text
|
||||
}
|
||||
a.editor.SetValueWithAttachments(existing + text + " ")
|
||||
case "/tui/submit-prompt":
|
||||
updated, cmd := a.editor.Submit()
|
||||
a.editor = updated.(chat.EditorComponent)
|
||||
cmds = append(cmds, cmd)
|
||||
case "/tui/clear-prompt":
|
||||
updated, cmd := a.editor.Clear()
|
||||
a.editor = updated.(chat.EditorComponent)
|
||||
cmds = append(cmds, cmd)
|
||||
case "/tui/execute-command":
|
||||
var body struct {
|
||||
Command string `json:"command"`
|
||||
}
|
||||
json.Unmarshal((msg.Body), &body)
|
||||
command := commands.Command{}
|
||||
for _, cmd := range a.app.Commands {
|
||||
if string(cmd.Name) == body.Command {
|
||||
command = cmd
|
||||
break
|
||||
}
|
||||
}
|
||||
if command.Name == "" {
|
||||
slog.Error("Invalid command passed to /tui/execute-command", "command", body.Command)
|
||||
return a, nil
|
||||
}
|
||||
updated, cmd := a.executeCommand(commands.Command(command))
|
||||
a = updated.(Model)
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
@@ -613,8 +707,6 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
func (a Model) View() string {
|
||||
measure := util.Measure("app.View")
|
||||
defer measure()
|
||||
t := theme.CurrentTheme()
|
||||
|
||||
var mainLayout string
|
||||
@@ -674,8 +766,6 @@ func (a Model) openFile(filepath string) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
func (a Model) home() string {
|
||||
measure := util.Measure("home.View")
|
||||
defer measure()
|
||||
t := theme.CurrentTheme()
|
||||
effectiveWidth := a.width - 4
|
||||
baseStyle := styles.NewStyle().Background(t.Background())
|
||||
@@ -796,8 +886,6 @@ func (a Model) home() string {
|
||||
}
|
||||
|
||||
func (a Model) chat() string {
|
||||
measure := util.Measure("chat.View")
|
||||
defer measure()
|
||||
effectiveWidth := a.width - 4
|
||||
t := theme.CurrentTheme()
|
||||
editorView := a.editor.View()
|
||||
@@ -911,9 +999,8 @@ func (a Model) executeCommand(command commands.Command) (tea.Model, tea.Cmd) {
|
||||
if a.app.Session.ID == "" {
|
||||
return a, nil
|
||||
}
|
||||
a.app.Session = &opencode.Session{}
|
||||
a.app.Messages = []app.Message{}
|
||||
cmds = append(cmds, util.CmdHandler(app.SessionClearedMsg{}))
|
||||
|
||||
case commands.SessionListCommand:
|
||||
sessionDialog := dialog.NewSessionDialog(a.app)
|
||||
a.modal = sessionDialog
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
configured_endpoints: 26
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-62d8fccba4eb8dc3a80434e0849eab3352e49fb96a718bb7b6d17ed8e582b716.yml
|
||||
openapi_spec_hash: 4ff9376cf9634e91731e63fe482ea532
|
||||
config_hash: 1ae82c93499b9f0b9ba828b8919f9cb3
|
||||
configured_endpoints: 28
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-90f0ff2a2f214a34b74f49a5909e95c31f617bd9bb881da24ab3fe664424c79d.yml
|
||||
openapi_spec_hash: 5ef69219c1869f78455b0c5374f638f8
|
||||
config_hash: 7707d73ebbd7ad7042ab70466b39348d
|
||||
|
||||
@@ -103,6 +103,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#ToolStatePending">ToolStatePending</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#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>
|
||||
|
||||
Methods:
|
||||
@@ -113,6 +114,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}/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#AssistantMessage">AssistantMessage</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">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Messages">Messages</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#SessionMessagesResponse">SessionMessagesResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
- <code title="post /session/{id}/revert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Revert">Revert</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#SessionRevertParams">SessionRevertParams</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}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Share">Share</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>
|
||||
@@ -120,6 +122,16 @@ Methods:
|
||||
- <code title="post /session/{id}/unrevert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unrevert">Unrevert</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="delete /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unshare">Unshare</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>
|
||||
|
||||
## Permissions
|
||||
|
||||
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#Permission">Permission</a>
|
||||
|
||||
Methods:
|
||||
|
||||
- <code title="post /session/{id}/permissions/{permissionID}">client.Session.Permissions.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPermissionService.Respond">Respond</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>, permissionID <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#SessionPermissionRespondParams">SessionPermissionRespondParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||
|
||||
# Tui
|
||||
|
||||
Methods:
|
||||
|
||||
@@ -54,8 +54,7 @@ type EventListResponse struct {
|
||||
// [EventListResponseEventMessageRemovedProperties],
|
||||
// [EventListResponseEventMessagePartUpdatedProperties],
|
||||
// [EventListResponseEventMessagePartRemovedProperties],
|
||||
// [EventListResponseEventStorageWriteProperties],
|
||||
// [EventListResponseEventPermissionUpdatedProperties],
|
||||
// [EventListResponseEventStorageWriteProperties], [Permission],
|
||||
// [EventListResponseEventFileEditedProperties],
|
||||
// [EventListResponseEventSessionUpdatedProperties],
|
||||
// [EventListResponseEventSessionDeletedProperties],
|
||||
@@ -643,9 +642,9 @@ func (r EventListResponseEventStorageWriteType) IsKnown() bool {
|
||||
}
|
||||
|
||||
type EventListResponseEventPermissionUpdated struct {
|
||||
Properties EventListResponseEventPermissionUpdatedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
|
||||
JSON eventListResponseEventPermissionUpdatedJSON `json:"-"`
|
||||
Properties Permission `json:"properties,required"`
|
||||
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
|
||||
JSON eventListResponseEventPermissionUpdatedJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventPermissionUpdatedJSON contains the JSON metadata for the
|
||||
@@ -667,56 +666,6 @@ func (r eventListResponseEventPermissionUpdatedJSON) RawJSON() string {
|
||||
|
||||
func (r EventListResponseEventPermissionUpdated) implementsEventListResponse() {}
|
||||
|
||||
type EventListResponseEventPermissionUpdatedProperties struct {
|
||||
ID string `json:"id,required"`
|
||||
Metadata map[string]interface{} `json:"metadata,required"`
|
||||
SessionID string `json:"sessionID,required"`
|
||||
Time EventListResponseEventPermissionUpdatedPropertiesTime `json:"time,required"`
|
||||
Title string `json:"title,required"`
|
||||
JSON eventListResponseEventPermissionUpdatedPropertiesJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventPermissionUpdatedPropertiesJSON contains the JSON metadata
|
||||
// for the struct [EventListResponseEventPermissionUpdatedProperties]
|
||||
type eventListResponseEventPermissionUpdatedPropertiesJSON struct {
|
||||
ID apijson.Field
|
||||
Metadata apijson.Field
|
||||
SessionID apijson.Field
|
||||
Time apijson.Field
|
||||
Title apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventPermissionUpdatedProperties) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventPermissionUpdatedPropertiesJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type EventListResponseEventPermissionUpdatedPropertiesTime struct {
|
||||
Created float64 `json:"created,required"`
|
||||
JSON eventListResponseEventPermissionUpdatedPropertiesTimeJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventPermissionUpdatedPropertiesTimeJSON contains the JSON
|
||||
// metadata for the struct [EventListResponseEventPermissionUpdatedPropertiesTime]
|
||||
type eventListResponseEventPermissionUpdatedPropertiesTimeJSON struct {
|
||||
Created apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventPermissionUpdatedPropertiesTime) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventPermissionUpdatedPropertiesTimeJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type EventListResponseEventPermissionUpdatedType string
|
||||
|
||||
const (
|
||||
|
||||
@@ -24,7 +24,8 @@ import (
|
||||
// automatically. You should not instantiate this service directly, and instead use
|
||||
// the [NewSessionService] method instead.
|
||||
type SessionService struct {
|
||||
Options []option.RequestOption
|
||||
Options []option.RequestOption
|
||||
Permissions *SessionPermissionService
|
||||
}
|
||||
|
||||
// NewSessionService generates a new service that applies the given options to each
|
||||
@@ -33,6 +34,7 @@ type SessionService struct {
|
||||
func NewSessionService(opts ...option.RequestOption) (r *SessionService) {
|
||||
r = &SessionService{}
|
||||
r.Options = opts
|
||||
r.Permissions = NewSessionPermissionService(opts...)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -100,6 +102,22 @@ func (r *SessionService) Init(ctx context.Context, id string, body SessionInitPa
|
||||
return
|
||||
}
|
||||
|
||||
// Get a message from a session
|
||||
func (r *SessionService) Message(ctx context.Context, id string, messageID string, opts ...option.RequestOption) (res *SessionMessageResponse, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
if id == "" {
|
||||
err = errors.New("missing required id parameter")
|
||||
return
|
||||
}
|
||||
if messageID == "" {
|
||||
err = errors.New("missing required messageID parameter")
|
||||
return
|
||||
}
|
||||
path := fmt.Sprintf("session/%s/message/%s", id, messageID)
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
||||
return
|
||||
}
|
||||
|
||||
// List messages for a session
|
||||
func (r *SessionService) Messages(ctx context.Context, id string, opts ...option.RequestOption) (res *[]SessionMessagesResponse, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
@@ -2012,6 +2030,29 @@ func (r userMessageTimeJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type SessionMessageResponse struct {
|
||||
Info Message `json:"info,required"`
|
||||
Parts []Part `json:"parts,required"`
|
||||
JSON sessionMessageResponseJSON `json:"-"`
|
||||
}
|
||||
|
||||
// sessionMessageResponseJSON contains the JSON metadata for the struct
|
||||
// [SessionMessageResponse]
|
||||
type sessionMessageResponseJSON struct {
|
||||
Info apijson.Field
|
||||
Parts apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *SessionMessageResponse) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r sessionMessageResponseJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type SessionMessagesResponse struct {
|
||||
Info Message `json:"info,required"`
|
||||
Parts []Part `json:"parts,required"`
|
||||
|
||||
@@ -176,6 +176,32 @@ func TestSessionInit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionMessage(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.Message(
|
||||
context.TODO(),
|
||||
"id",
|
||||
"messageID",
|
||||
)
|
||||
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 TestSessionMessages(t *testing.T) {
|
||||
t.Skip("skipped: tests are disabled for the time being")
|
||||
baseURL := "http://localhost:4010"
|
||||
|
||||
126
packages/tui/sdk/sessionpermission.go
Normal file
126
packages/tui/sdk/sessionpermission.go
Normal file
@@ -0,0 +1,126 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
package opencode
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||
"github.com/sst/opencode-sdk-go/internal/param"
|
||||
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||
"github.com/sst/opencode-sdk-go/option"
|
||||
)
|
||||
|
||||
// SessionPermissionService 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 [NewSessionPermissionService] method instead.
|
||||
type SessionPermissionService struct {
|
||||
Options []option.RequestOption
|
||||
}
|
||||
|
||||
// NewSessionPermissionService 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 NewSessionPermissionService(opts ...option.RequestOption) (r *SessionPermissionService) {
|
||||
r = &SessionPermissionService{}
|
||||
r.Options = opts
|
||||
return
|
||||
}
|
||||
|
||||
// Respond to a permission request
|
||||
func (r *SessionPermissionService) Respond(ctx context.Context, id string, permissionID string, body SessionPermissionRespondParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||
opts = append(r.Options[:], opts...)
|
||||
if id == "" {
|
||||
err = errors.New("missing required id parameter")
|
||||
return
|
||||
}
|
||||
if permissionID == "" {
|
||||
err = errors.New("missing required permissionID parameter")
|
||||
return
|
||||
}
|
||||
path := fmt.Sprintf("session/%s/permissions/%s", id, permissionID)
|
||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||
return
|
||||
}
|
||||
|
||||
type Permission struct {
|
||||
ID string `json:"id,required"`
|
||||
MessageID string `json:"messageID,required"`
|
||||
Metadata map[string]interface{} `json:"metadata,required"`
|
||||
SessionID string `json:"sessionID,required"`
|
||||
Time PermissionTime `json:"time,required"`
|
||||
Title string `json:"title,required"`
|
||||
ToolCallID string `json:"toolCallID"`
|
||||
JSON permissionJSON `json:"-"`
|
||||
}
|
||||
|
||||
// permissionJSON contains the JSON metadata for the struct [Permission]
|
||||
type permissionJSON struct {
|
||||
ID apijson.Field
|
||||
MessageID apijson.Field
|
||||
Metadata apijson.Field
|
||||
SessionID apijson.Field
|
||||
Time apijson.Field
|
||||
Title apijson.Field
|
||||
ToolCallID apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *Permission) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r permissionJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type PermissionTime struct {
|
||||
Created float64 `json:"created,required"`
|
||||
JSON permissionTimeJSON `json:"-"`
|
||||
}
|
||||
|
||||
// permissionTimeJSON contains the JSON metadata for the struct [PermissionTime]
|
||||
type permissionTimeJSON struct {
|
||||
Created apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *PermissionTime) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r permissionTimeJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type SessionPermissionRespondParams struct {
|
||||
Response param.Field[SessionPermissionRespondParamsResponse] `json:"response,required"`
|
||||
}
|
||||
|
||||
func (r SessionPermissionRespondParams) MarshalJSON() (data []byte, err error) {
|
||||
return apijson.MarshalRoot(r)
|
||||
}
|
||||
|
||||
type SessionPermissionRespondParamsResponse string
|
||||
|
||||
const (
|
||||
SessionPermissionRespondParamsResponseOnce SessionPermissionRespondParamsResponse = "once"
|
||||
SessionPermissionRespondParamsResponseAlways SessionPermissionRespondParamsResponse = "always"
|
||||
SessionPermissionRespondParamsResponseReject SessionPermissionRespondParamsResponse = "reject"
|
||||
)
|
||||
|
||||
func (r SessionPermissionRespondParamsResponse) IsKnown() bool {
|
||||
switch r {
|
||||
case SessionPermissionRespondParamsResponseOnce, SessionPermissionRespondParamsResponseAlways, SessionPermissionRespondParamsResponseReject:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
43
packages/tui/sdk/sessionpermission_test.go
Normal file
43
packages/tui/sdk/sessionpermission_test.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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 TestSessionPermissionRespond(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.Permissions.Respond(
|
||||
context.TODO(),
|
||||
"id",
|
||||
"permissionID",
|
||||
opencode.SessionPermissionRespondParams{
|
||||
Response: opencode.F(opencode.SessionPermissionRespondParamsResponseOnce),
|
||||
},
|
||||
)
|
||||
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())
|
||||
}
|
||||
}
|
||||
@@ -69,12 +69,7 @@ export default defineConfig({
|
||||
|
||||
{
|
||||
label: "Usage",
|
||||
items: [
|
||||
"docs/cli",
|
||||
"docs/ide",
|
||||
"docs/share",
|
||||
"docs/github",
|
||||
]
|
||||
items: ["docs/cli", "docs/ide", "docs/share", "docs/github"],
|
||||
},
|
||||
|
||||
{
|
||||
@@ -86,9 +81,10 @@ export default defineConfig({
|
||||
"docs/models",
|
||||
"docs/themes",
|
||||
"docs/keybinds",
|
||||
"docs/permissions",
|
||||
"docs/mcp-servers",
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
components: {
|
||||
Hero: "./src/components/Hero.astro",
|
||||
|
||||
@@ -5,12 +5,17 @@ description: Using the opencode JSON config.
|
||||
|
||||
You can configure opencode using a JSON config file.
|
||||
|
||||
```json title="opencode.json"
|
||||
## Format
|
||||
|
||||
opencode supports both JSON and JSONC (JSON with Comments) formats. You can use comments in your configuration files:
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
// Theme configuration
|
||||
"theme": "opencode",
|
||||
"model": "anthropic/claude-sonnet-4-20250514",
|
||||
"autoupdate": true
|
||||
"autoupdate": true,
|
||||
}
|
||||
```
|
||||
|
||||
@@ -199,7 +204,7 @@ about rules here](/docs/rules).
|
||||
|
||||
You can configure specialized agents for specific tasks through the `agent` option.
|
||||
|
||||
```json title="opencode.json"
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"agent": {
|
||||
@@ -208,11 +213,12 @@ You can configure specialized agents for specific tasks through the `agent` opti
|
||||
"model": "anthropic/claude-sonnet-4-20250514",
|
||||
"prompt": "You are a code reviewer. Focus on security, performance, and maintainability.",
|
||||
"tools": {
|
||||
// Disable file modification tools for review-only agent
|
||||
"write": false,
|
||||
"edit": false
|
||||
}
|
||||
}
|
||||
}
|
||||
"edit": false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
@@ -239,6 +245,29 @@ The `disabled_providers` option accepts an array of provider IDs. When a provide
|
||||
|
||||
---
|
||||
|
||||
### Permissions
|
||||
|
||||
You can configure permissions to control what AI agents can do in your codebase through the `permission` option.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"permission": {
|
||||
"edit": "ask",
|
||||
"bash": "ask"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The permissions system allows you to configure explicit approval requirements for sensitive operations:
|
||||
|
||||
- `edit` - Controls whether file editing operations require user approval (`"ask"` or `"allow"`)
|
||||
- `bash` - Controls whether bash commands require user approval (can be `"ask"`/`"allow"` or a pattern map)
|
||||
|
||||
[Learn more about permissions here](/docs/permissions).
|
||||
|
||||
---
|
||||
|
||||
## Variables
|
||||
|
||||
You can use variable substitution in your config files to reference environment variables and file contents.
|
||||
|
||||
74
packages/web/src/content/docs/docs/permissions.mdx
Normal file
74
packages/web/src/content/docs/docs/permissions.mdx
Normal file
@@ -0,0 +1,74 @@
|
||||
---
|
||||
title: Permissions
|
||||
description: Control what agents can do in your codebase.
|
||||
---
|
||||
|
||||
By default, opencode **allows all operations** without requiring explicit approval.
|
||||
|
||||
The permissions system provides granular control to restrict what actions AI agents can perform in your codebase, allowing you to configure explicit approval requirements for sensitive operations like file editing, bash commands, and more.
|
||||
|
||||
---
|
||||
|
||||
## Configure
|
||||
|
||||
Permissions are configured in your `opencode.json` file under the `permission` key. Here are the available options.
|
||||
|
||||
---
|
||||
|
||||
### edit
|
||||
|
||||
Use the `permission.edit` key to control whether file editing operations require user approval.
|
||||
|
||||
- `"ask"` - Prompt for approval before editing files
|
||||
- `"allow"` - Allow all file editing operations without approval
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"permission": {
|
||||
"edit": "ask"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### bash
|
||||
|
||||
Controls whether bash commands require user approval.
|
||||
|
||||
:::tip
|
||||
You can specify which commands you want to have run without approval.
|
||||
:::
|
||||
|
||||
This can be configured globally or with specific patterns. Setting this to `"ask"` is the strictest mode, requiring approval for all bash commands.
|
||||
|
||||
For example.
|
||||
|
||||
- **Ask for approval for all commands**
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"permission": {
|
||||
"bash": "ask"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Approve specific commands**
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"permission": {
|
||||
"bash": {
|
||||
"git status": "allow",
|
||||
"git diff": "allow",
|
||||
"npm run build": "allow",
|
||||
"ls": "allow",
|
||||
"pwd": "allow"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -45,6 +45,126 @@ You can customize the base URL for any provider by setting the `baseURL` option.
|
||||
|
||||
---
|
||||
|
||||
## Custom provider
|
||||
|
||||
To add any **OpenAI-compatible** provider that's not listed in `opencode auth login`:
|
||||
|
||||
:::tip
|
||||
You can use any OpenAI-compatible provider with opencode. Most modern AI providers offer OpenAI-compatible APIs.
|
||||
:::
|
||||
|
||||
1. Run `opencode auth login` and scroll down to **Other**.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◆ Select provider
|
||||
│ ...
|
||||
│ ● Other
|
||||
└
|
||||
```
|
||||
|
||||
2. Enter a unique ID for the provider.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◇ Enter provider id
|
||||
│ myprovider
|
||||
└
|
||||
```
|
||||
|
||||
:::note
|
||||
Choose a memorable ID, you'll use this in your config file.
|
||||
:::
|
||||
|
||||
3. Enter your API key for the provider.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
▲ This only stores a credential for myprovider - you will need configure it in opencode.json, check the docs for examples.
|
||||
│
|
||||
◇ Enter your API key
|
||||
│ sk-...
|
||||
└
|
||||
```
|
||||
|
||||
4. Create or update your `opencode.json` file in your project directory:
|
||||
|
||||
```json title="opencode.json" ""myprovider"" {5-15}
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"provider": {
|
||||
"myprovider": {
|
||||
"npm": "@ai-sdk/openai-compatible",
|
||||
"name": "My AI ProviderDisplay Name",
|
||||
"options": {
|
||||
"baseURL": "https://api.myprovider.com/v1"
|
||||
},
|
||||
"models": {
|
||||
"my-model-name": {
|
||||
"name": "My Model Display Name"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here are the configuration options:
|
||||
|
||||
- **npm**: AI SDK package to use, `@ai-sdk/openai-compatible` for OpenAI-compatible providers
|
||||
- **name**: Display name in UI.
|
||||
- **models**: Available models.
|
||||
- **options.baseURL**: API endpoint URL.
|
||||
- **options.apiKey**: Optionally set the API key, if not using auth.
|
||||
- **options.headers**: Optionally set custom headers.
|
||||
|
||||
More on the advanced options in the example below.
|
||||
|
||||
5. Run the `/models` command and your custom provider and models will appear in the selection list.
|
||||
|
||||
---
|
||||
|
||||
##### Example
|
||||
|
||||
Here's an example setting the `apiKey` and `headers` options.
|
||||
|
||||
```json title="opencode.json" {9,11}
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"provider": {
|
||||
"myprovider": {
|
||||
"npm": "@ai-sdk/openai-compatible",
|
||||
"name": "My AI ProviderDisplay Name",
|
||||
"options": {
|
||||
"baseURL": "https://api.myprovider.com/v1",
|
||||
"apiKey": "{env:ANTHROPIC_API_KEY}",
|
||||
"headers": {
|
||||
"Authorization": "Bearer custom-token"
|
||||
}
|
||||
},
|
||||
"models": {
|
||||
"my-model-name": {
|
||||
"name": "My Model Display Name"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We are setting the `apiKey` using the `env` variable syntax, [learn more](/docs/config#env-vars).
|
||||
|
||||
---
|
||||
|
||||
## Directory
|
||||
|
||||
Let's look at some of the providers in detail. If you'd like to add a provider to the
|
||||
@@ -62,7 +182,7 @@ To use Amazon Bedrock with opencode:
|
||||
|
||||
1. Head over to the **Model catalog** in the Amazon Bedrock console and request
|
||||
access to the models you want.
|
||||
|
||||
|
||||
:::tip
|
||||
You need to have access to the model you want in Amazon Bedrock.
|
||||
:::
|
||||
@@ -74,27 +194,27 @@ To use Amazon Bedrock with opencode:
|
||||
- `AWS_PROFILE`: First login through AWS IAM Identity Center (or AWS SSO) using
|
||||
`aws sso login`. Then get the name of the profile you want to use.
|
||||
- `AWS_BEARER_TOKEN_BEDROCK`: You can generate a long-term API key from the
|
||||
Amazon Bedrock console.
|
||||
|
||||
Amazon Bedrock console.
|
||||
|
||||
Once you have one of the above, set it while running opencode.
|
||||
|
||||
|
||||
```bash
|
||||
AWS_ACCESS_KEY_ID=XXX opencode
|
||||
```
|
||||
|
||||
|
||||
Or add it to a `.env` file in the project root.
|
||||
|
||||
|
||||
```bash title=".env"
|
||||
AWS_ACCESS_KEY_ID=XXX
|
||||
```
|
||||
|
||||
|
||||
Or add it to your bash profile.
|
||||
|
||||
|
||||
```bash title="~/.bash_profile"
|
||||
export AWS_ACCESS_KEY_ID=XXX
|
||||
```
|
||||
|
||||
2. Run the `/models` command to select the model you want.
|
||||
1. Run the `/models` command to select the model you want.
|
||||
|
||||
---
|
||||
|
||||
@@ -117,8 +237,165 @@ $ opencode auth login
|
||||
└
|
||||
```
|
||||
|
||||
This will ask you login with your Anthropic account in your browser. Now all the
|
||||
the Anthropic models should be available when you use the `/models` command.
|
||||
Here you can select the **Claude Pro/Max** option and it'll open your browser
|
||||
and ask you to authenticate.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
┌ Add credential
|
||||
│
|
||||
◇ Select provider
|
||||
│ Anthropic
|
||||
│
|
||||
◆ Login method
|
||||
│ ● Claude Pro/Max
|
||||
│ ○ Create API Key
|
||||
│ ○ Manually enter API Key
|
||||
└
|
||||
```
|
||||
|
||||
Now all the the Anthropic models should be available when you use the `/models` command.
|
||||
|
||||
##### Using API keys
|
||||
|
||||
You can also select **Create API Key** if you don't have a Pro/Max subscription. It'll also open your browser and ask you to login to Anthropic and give you a code you can paste in your terminal.
|
||||
|
||||
Or if you already have an API key, you can select **Manually enter API Key** and paste it in your terminal.
|
||||
|
||||
---
|
||||
|
||||
### Azure OpenAI
|
||||
|
||||
1. Head over to the [Azure portal](https://portal.azure.com/) and create an **Azure OpenAI** resource. You'll need:
|
||||
|
||||
- **Resource name**: This becomes part of your API endpoint (`https://RESOURCE_NAME.openai.azure.com/`)
|
||||
- **API key**: Either `KEY 1` or `KEY 2` from your resource
|
||||
|
||||
2. Go to [Azure AI Foundry](https://ai.azure.com/) and deploy a model.
|
||||
|
||||
:::note
|
||||
The deployment name must match the model name for opencode to work properly.
|
||||
:::
|
||||
|
||||
3. Run `opencode auth login` and select **Azure**.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◆ Select provider
|
||||
│ ● Azure
|
||||
│ ...
|
||||
└
|
||||
```
|
||||
|
||||
4. Enter your API key.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◇ Select provider
|
||||
│ Azure
|
||||
│
|
||||
◇ Enter your API key
|
||||
│ _
|
||||
└
|
||||
```
|
||||
|
||||
5. Set your resource name as an environment variable:
|
||||
|
||||
```bash
|
||||
AZURE_RESOURCE_NAME=XXX opencode
|
||||
```
|
||||
|
||||
Or add it to a `.env` file in the project root:
|
||||
|
||||
```bash title=".env"
|
||||
AZURE_RESOURCE_NAME=XXX
|
||||
```
|
||||
|
||||
Or add it to your bash profile:
|
||||
|
||||
```bash title="~/.bash_profile"
|
||||
export AZURE_RESOURCE_NAME=XXX
|
||||
```
|
||||
|
||||
6. Run the `/models` command to select your deployed model.
|
||||
|
||||
---
|
||||
|
||||
### DeepSeek
|
||||
|
||||
1. Head over to the [DeepSeek console](https://platform.deepseek.com/), create an account, and click **Create new API key**.
|
||||
|
||||
2. Run `opencode auth login` and select **DeepSeek**.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◆ Select provider
|
||||
│ ● DeepSeek
|
||||
│ ...
|
||||
└
|
||||
```
|
||||
|
||||
3. Enter your DeepSeek API key.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◇ Select provider
|
||||
│ DeepSeek
|
||||
│
|
||||
◇ Enter your API key
|
||||
│ _
|
||||
└
|
||||
```
|
||||
|
||||
4. Run the `/models` command to select a DeepSeek model like _DeepSeek Reasoner_.
|
||||
|
||||
---
|
||||
|
||||
### Fireworks AI
|
||||
|
||||
1. Head over to the [Fireworks AI console](https://app.fireworks.ai/), create an account, and click **Create API Key**.
|
||||
|
||||
2. Run `opencode auth login` and select **Fireworks AI**.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◆ Select provider
|
||||
│ ● Fireworks AI
|
||||
│ ...
|
||||
└
|
||||
```
|
||||
|
||||
3. Enter your Fireworks AI API key.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◇ Select provider
|
||||
│ Fireworks AI
|
||||
│
|
||||
◇ Enter your API key
|
||||
│ _
|
||||
└
|
||||
```
|
||||
|
||||
4. Run the `/models` command to select a model like _Kimi K2 Instruct_.
|
||||
|
||||
---
|
||||
|
||||
@@ -136,7 +413,7 @@ subscription](https://github.com/features/copilot/plans) to use.
|
||||
```bash
|
||||
$ opencode auth login
|
||||
┌ Add credential
|
||||
|
||||
|
||||
│
|
||||
◇ Select provider
|
||||
│ GitHub Copilot
|
||||
@@ -173,7 +450,7 @@ subscription](https://github.com/features/copilot/plans) to use.
|
||||
│ ...
|
||||
└
|
||||
```
|
||||
|
||||
|
||||
3. Enter the API key for the provider.
|
||||
|
||||
```bash
|
||||
@@ -227,6 +504,78 @@ In this example:
|
||||
|
||||
---
|
||||
|
||||
### Moonshot AI
|
||||
|
||||
To use Kimi K2 from Moonshot AI:
|
||||
|
||||
1. Head over to the [Moonshot AI console](https://platform.moonshot.ai/console), create an account, and click **Create API key**.
|
||||
|
||||
2. Run `opencode auth login` and select **Other**.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◆ Select provider
|
||||
│ ...
|
||||
│ ● Other
|
||||
└
|
||||
```
|
||||
|
||||
3. Enter `moonshot` as the provider ID.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◇ Select provider
|
||||
│ Other
|
||||
│
|
||||
◇ Enter provider id
|
||||
│ moonshot
|
||||
└
|
||||
```
|
||||
|
||||
4. Enter your Moonshot API key.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◇ Enter your API key
|
||||
│ sk-...
|
||||
└
|
||||
```
|
||||
|
||||
5. Configure Moonshot in your opencode config.
|
||||
|
||||
```json title="opencode.json" "\"moonshot\"" {5-15}
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"provider": {
|
||||
"moonshot": {
|
||||
"npm": "@ai-sdk/openai-compatible",
|
||||
"name": "Moonshot AI",
|
||||
"options": {
|
||||
"baseURL": "https://api.moonshot.ai/v1"
|
||||
},
|
||||
"models": {
|
||||
"kimi-k2-0711-preview": {
|
||||
"name": "Kimi K2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
6. Run the `/models` command to select _Kimi K2_.
|
||||
|
||||
---
|
||||
|
||||
### Ollama
|
||||
|
||||
You can configure opencode to use local models through Ollama.
|
||||
@@ -279,7 +628,7 @@ https://platform.openai.com/api-keys
|
||||
│ ...
|
||||
└
|
||||
```
|
||||
|
||||
|
||||
3. Enter the API key for the provider.
|
||||
|
||||
```bash
|
||||
@@ -317,7 +666,7 @@ https://platform.openai.com/api-keys
|
||||
│ ...
|
||||
└
|
||||
```
|
||||
|
||||
|
||||
3. Enter the API key for the provider.
|
||||
|
||||
```bash
|
||||
@@ -336,14 +685,14 @@ https://platform.openai.com/api-keys
|
||||
4. Many OpenRouter models are preloaded by default, run the `/models` command to select the one you want.
|
||||
|
||||
You can also add additional models through your opencode config.
|
||||
|
||||
|
||||
```json title="opencode.json" {6}
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"provider": {
|
||||
"openrouter": {
|
||||
"models": {
|
||||
"somecoolnewmodel": {},
|
||||
"somecoolnewmodel": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -351,7 +700,7 @@ https://platform.openai.com/api-keys
|
||||
```
|
||||
|
||||
5. You can also customize them through your opencode config. Here's an example of specifying a provider
|
||||
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
@@ -372,21 +721,23 @@ https://platform.openai.com/api-keys
|
||||
}
|
||||
```
|
||||
|
||||
{ /*
|
||||
---
|
||||
|
||||
### Custom
|
||||
TODO: Test a model that actually works, currently getting errors form the API
|
||||
for Qwen non-thinking models.
|
||||
|
||||
To add any **OpenAI-compatible** provider that's not listed in `opencode auth login`:
|
||||
### Cerebras
|
||||
|
||||
:::tip
|
||||
You can use any OpenAI-compatible provider with opencode.
|
||||
:::
|
||||
Cerebras offers fast inference with generous free tiers and competitive pricing.
|
||||
|
||||
1. Scroll down to **Other**.
|
||||
1. Head over to the [Cerebras console](https://inference.cerebras.ai/), create an account, and generate an API key.
|
||||
|
||||
2. Run `opencode auth login` and select **Other**.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◆ Select provider
|
||||
@@ -395,68 +746,111 @@ You can use any OpenAI-compatible provider with opencode.
|
||||
└
|
||||
```
|
||||
|
||||
2. Enter the ID for the provider.
|
||||
3. Enter `cerebras` as the provider ID.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◆ Select provider
|
||||
│ ...
|
||||
│ ● Other
|
||||
│
|
||||
◇ Enter provider id
|
||||
│ _
|
||||
└
|
||||
```
|
||||
|
||||
You can use any ID you want, we'll use this later in the opencode config.
|
||||
|
||||
3. Add the API keys for the provider.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◇ Select provider
|
||||
│ Other
|
||||
│
|
||||
◇ Enter provider id
|
||||
│ coolnewprovider
|
||||
│
|
||||
▲ This only stores a credential for coolnewprovider - you will need configure it in opencode.json, check the docs for examples.
|
||||
│
|
||||
◆ Enter your API key
|
||||
│ _
|
||||
│ cerebras
|
||||
└
|
||||
```
|
||||
|
||||
4. Configure the provider in your [opencode config](/docs/config).
|
||||
4. Enter your Cerebras API key.
|
||||
|
||||
```json title="opencode.json" "coolnewprovider" {7,9-11}
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◇ Enter your API key
|
||||
│ csk-...
|
||||
└
|
||||
```
|
||||
|
||||
5. Configure Cerebras in your opencode config.
|
||||
|
||||
```json title="opencode.json" "cerebras" {5-19}
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"provider": {
|
||||
"coolnewprovider": {
|
||||
"npm": "@ai-sdk/openai-compatible",
|
||||
"cerebras": {
|
||||
"npm": "@ai-sdk/cerebras",
|
||||
"name": "Cerebras",
|
||||
"options": {
|
||||
"baseURL": "https://api.newaicompany.com/v1"
|
||||
"baseURL": "https://api.cerebras.ai/v1"
|
||||
},
|
||||
"models": {
|
||||
"newmodel-m1-0711-preview": {}
|
||||
"qwen-3-235b-a22b": {
|
||||
"name": "Qwen-3-235b-a22b"
|
||||
},
|
||||
"llama-3.3-70b": {
|
||||
"name": "Llama-3.3-70b"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
A couple of things to note here:
|
||||
6. Run the `/models` command to select a Cerebras model.
|
||||
|
||||
- We are using the provider ID we entered earlier, `coolnewprovider` in
|
||||
this example.
|
||||
- The `baseURL` is the OpenAI-compatible endpoint for the provider.
|
||||
- And we are listing the models we want to use. This will show up when we run
|
||||
the `/models` command.
|
||||
*/ }
|
||||
|
||||
---
|
||||
|
||||
### Together AI
|
||||
|
||||
1. Head over to the [Together AI console](https://api.together.ai), create an account, and click **Add Key**.
|
||||
|
||||
2. Run `opencode auth login` and select **Together AI**.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◆ Select provider
|
||||
│ ● Together AI
|
||||
│ ...
|
||||
└
|
||||
```
|
||||
|
||||
3. Enter your Together AI API key.
|
||||
|
||||
```bash
|
||||
$ opencode auth login
|
||||
|
||||
┌ Add credential
|
||||
│
|
||||
◇ Select provider
|
||||
│ Together AI
|
||||
│
|
||||
◇ Enter your API key
|
||||
│ _
|
||||
└
|
||||
```
|
||||
|
||||
4. Run the `/models` command to select a model like _Kimi K2 Instruct_.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you are having trouble with configuring a provider, check the following:
|
||||
|
||||
1. **Check the auth setup**: Run `opencode auth list` to see if the credentials
|
||||
for the provider are added to your config.
|
||||
|
||||
This doesn't apply to providers like Amazon Bedrock, that rely on environment variables for their auth.
|
||||
|
||||
2. For custom providers, check the opencode config and:
|
||||
|
||||
- Make sure the provider ID used in `opencode auth login` matches the ID in your opencode config.
|
||||
- The right npm package is used for the provider. For example, use `@ai-sdk/cerebras` for Cerebras. And for all other OpenAI-compatible providers, use `@ai-sdk/openai-compatible`.
|
||||
- Check correct API endpoint is used in the `options.baseURL` field.
|
||||
|
||||
@@ -12,8 +12,8 @@ if (!version) {
|
||||
process.env["OPENCODE_VERSION"] = version
|
||||
|
||||
await import(`../packages/opencode/script/publish.ts`)
|
||||
await import(`../packages/sdk/stainless/generate.ts`)
|
||||
await import(`../packages/sdk/js/script/publish.ts`)
|
||||
// await import(`../packages/sdk/stainless/generate.ts`)
|
||||
|
||||
if (!snapshot) {
|
||||
await $`git commit -am "Release v${version}"`
|
||||
@@ -9,10 +9,8 @@ while [ "$#" -gt 0 ]; do
|
||||
esac
|
||||
done
|
||||
|
||||
git fetch --force --tags
|
||||
|
||||
# Get the latest Git tag
|
||||
latest_tag=$(git tag --sort=committerdate | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | tail -1)
|
||||
# Get the latest release from GitHub
|
||||
latest_tag=$(gh release list --limit 1 --json tagName --jq '.[0].tagName')
|
||||
|
||||
# If there is no tag, exit the script
|
||||
if [ -z "$latest_tag" ]; then
|
||||
@@ -22,8 +20,9 @@ fi
|
||||
|
||||
echo "Latest tag: $latest_tag"
|
||||
|
||||
# Split the tag into major, minor, and patch numbers
|
||||
IFS='.' read -ra VERSION <<< "$latest_tag"
|
||||
# Remove the 'v' prefix and split into major, minor, and patch numbers
|
||||
version_without_v=${latest_tag#v}
|
||||
IFS='.' read -ra VERSION <<< "$version_without_v"
|
||||
|
||||
if [ "$minor" = true ]; then
|
||||
# Increment the minor version and reset patch to 0
|
||||
@@ -39,5 +38,5 @@ fi
|
||||
|
||||
echo "New version: $new_version"
|
||||
|
||||
git tag $new_version
|
||||
git push --tags
|
||||
gh workflow run publish.yml -f version="$new_version"
|
||||
|
||||
@@ -57,7 +57,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
})
|
||||
|
||||
terminal.show()
|
||||
terminal.sendText(`OPENCODE_THEME=system OPENCODE_CALLER=vscode opencode --port ${port}`)
|
||||
terminal.sendText(`OPENCODE_CALLER=vscode opencode --port ${port}`)
|
||||
|
||||
const fileRef = getActiveFile()
|
||||
if (!fileRef) return
|
||||
|
||||
Reference in New Issue
Block a user