From b19bbbefb66785bdd9d3e7a532ab9b3120e946fd Mon Sep 17 00:00:00 2001 From: Daniel Saldarriaga Date: Thu, 3 Sep 2026 11:50:51 +0200 Subject: [PATCH 1/2] fix: support current V2 command API --- bun.lock | 92 +++++++++++++++--------------------------- dist/server.js | 16 +++++--- package.json | 8 ++-- src/server.ts | 15 +++++-- test/server-v2.test.ts | 68 +++++++++++++++++++++---------- 5 files changed, 105 insertions(+), 94 deletions(-) diff --git a/bun.lock b/bun.lock index 183bf55..30a573f 100644 --- a/bun.lock +++ b/bun.lock @@ -6,16 +6,16 @@ "name": "opencode-goal-plugin", "dependencies": { "@opencode-ai/plugin": "^1.17.1", - "@opentui/solid": "^0.4.0", + "@opentui/solid": "0.5.9", "effect": "^3.21.2", "solid-js": "1.9.12", "zod": "^4.1.8", }, "devDependencies": { "@eslint/js": "^10.0.1", - "@opencode-ai/plugin-v2": "npm:@opencode-ai/plugin@0.0.0-next-17055", - "@opencode-ai/theme": "0.0.0-next-17055", - "@opentui/core": "^0.4.0", + "@opencode-ai/plugin-v2": "npm:@opencode-ai/plugin@0.0.0-beta-18593", + "@opencode-ai/theme": "0.0.0-beta-18593", + "@opentui/core": "0.5.9", "@types/bun": "^1.3.13", "eslint": "^10.3.0", "typescript": "^6.0.3", @@ -138,41 +138,41 @@ "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4", "", { "os": "win32", "cpu": "x64" }, "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ=="], - "@opencode-ai/ai": ["@opencode-ai/ai@0.0.0-next-17055", "", { "dependencies": { "@opencode-ai/schema": "0.0.0-next-17055", "@smithy/eventstream-codec": "4.2.14", "@smithy/util-utf8": "4.2.2", "aws4fetch": "1.0.20", "effect": "4.0.0-beta.101", "google-auth-library": "10.5.0" } }, "sha512-7mau+eF28boRehV89aIV13k4WhKP3WQ1A6KTIk2WSjvZurf2LVFePPi0VIbEr43BL242rzR+U0jDn7S9R+tr3w=="], + "@opencode-ai/ai": ["@opencode-ai/ai@0.0.0-beta-18593", "", { "dependencies": { "@opencode-ai/schema": "0.0.0-beta-18593", "@smithy/eventstream-codec": "4.2.14", "@smithy/util-utf8": "4.2.2", "aws4fetch": "1.0.20", "effect": "4.0.0-rc.112", "google-auth-library": "10.5.0" } }, "sha512-FwMNHcvKd0NV5iJErN9/174drHhm21brxM07liTm2mGttUlfbBU9Tvzf2nZyPPWrZBEnr1+pGXtyd/7yZOZbJQ=="], - "@opencode-ai/client": ["@opencode-ai/client@0.0.0-next-17055", "", { "dependencies": { "@opencode-ai/protocol": "0.0.0-next-17055", "@opencode-ai/schema": "0.0.0-next-17055" }, "peerDependencies": { "effect": "4.0.0-beta.101" }, "optionalPeers": ["effect"] }, "sha512-+Ts98xLsGFiaXN+0QhZ/8xLgacEvp0ZcxYWxbo7Aegu1rj8NBYcp9y4DtqrryOgsrlkOWpEA9i47TDzudPNdGg=="], + "@opencode-ai/client": ["@opencode-ai/client@0.0.0-beta-18593", "", { "dependencies": { "@opencode-ai/protocol": "0.0.0-beta-18593", "@opencode-ai/schema": "0.0.0-beta-18593" }, "peerDependencies": { "effect": "4.0.0-rc.112", "solid-js": ">=1.9.0" }, "optionalPeers": ["effect", "solid-js"] }, "sha512-St9canLk4U+8EPEIGR12yDbqvVnbIvYrlB9YGjgBfdktpZmn64hloIVWa/pruLxAEdr2EB3m+5Z5MG7FhpmGkA=="], "@opencode-ai/plugin": ["@opencode-ai/plugin@1.17.1", "", { "dependencies": { "@opencode-ai/sdk": "1.17.1", "effect": "4.0.0-beta.74", "zod": "4.1.8" }, "peerDependencies": { "@opentui/core": ">=0.3.4", "@opentui/keymap": ">=0.3.4", "@opentui/solid": ">=0.3.4" }, "optionalPeers": ["@opentui/core", "@opentui/keymap", "@opentui/solid"] }, "sha512-LoKYrJfVGLCmOXyuIMNsVsO8rkAREyiQWDNvQUUMul5h7uEofsPsytd/jUPa6dJ5GZ9OzYAFyybj7IdnhpFrjA=="], - "@opencode-ai/plugin-v2": ["@opencode-ai/plugin@0.0.0-next-17055", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@opencode-ai/ai": "0.0.0-next-17055", "@opencode-ai/client": "0.0.0-next-17055", "@opencode-ai/schema": "0.0.0-next-17055", "@opencode-ai/sdk": "1.18.5", "@standard-schema/spec": "1.1.0", "effect": "4.0.0-beta.101", "zod": "4.1.8" }, "peerDependencies": { "@opencode-ai/theme": "0.0.0-next-17055", "@opentui/core": ">=0.4.5", "@opentui/keymap": ">=0.4.5", "@opentui/solid": ">=0.4.5", "solid-js": ">=1.9.0" }, "optionalPeers": ["@opencode-ai/theme", "@opentui/core", "@opentui/keymap", "@opentui/solid", "solid-js"] }, "sha512-O+jnBm2435zTv1S2XJUV/o/IJLnSk3CDFhD1L4V9/6mf16dvxW2sRQ6gino/d+Z6HyYgLk37UJh+svvp+aEhNw=="], + "@opencode-ai/plugin-v2": ["@opencode-ai/plugin@0.0.0-beta-18593", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@opencode-ai/ai": "0.0.0-beta-18593", "@opencode-ai/client": "0.0.0-beta-18593", "@opencode-ai/protocol": "0.0.0-beta-18593", "@opencode-ai/schema": "0.0.0-beta-18593", "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112", "zod": "4.1.8" }, "peerDependencies": { "@opencode-ai/theme": "0.0.0-beta-18593", "@opentui/core": ">=0.5.9", "@opentui/solid": ">=0.5.9", "solid-js": ">=1.9.0" }, "optionalPeers": ["@opencode-ai/theme", "@opentui/core", "@opentui/solid", "solid-js"] }, "sha512-y/A7M+pEZuGt3FNPlqOxj5QaIy5VBKqymmxpsER0mp2fp15nOCC3hMOQwt37OF3KMO1lieG5L8oSFl/Ij5YCiw=="], - "@opencode-ai/protocol": ["@opencode-ai/protocol@0.0.0-next-17055", "", { "dependencies": { "@opencode-ai/schema": "0.0.0-next-17055", "effect": "4.0.0-beta.101" } }, "sha512-xPxtFIg9a/8QDvDcoKuyhbqjPFE9CMZP/Hi9Bf25JJDBNysrIimVpTEtCsexxBn2O/ZS+ebxmTfGGbRwgSvs/Q=="], + "@opencode-ai/protocol": ["@opencode-ai/protocol@0.0.0-beta-18593", "", { "dependencies": { "@opencode-ai/schema": "0.0.0-beta-18593", "effect": "4.0.0-rc.112" } }, "sha512-mZgJpNxHiOhZshizDpEFOlBaMJvjBTzwRQxhJBkZ0D0Oc3w43C6Hms4Qr2Fy+73JlR+pvzUc5S5OBpyT6fVzTA=="], - "@opencode-ai/schema": ["@opencode-ai/schema@0.0.0-next-17055", "", { "dependencies": { "@standard-schema/spec": "1.1.0", "effect": "4.0.0-beta.101" } }, "sha512-/E6gaHOVhojt0kJxu+tQ+3/G1xoL5IOn3PY9QP68JVgccXpkNJR3bZF0EX71D1oaRD+EdHLHTFWp2n0x6jUp7A=="], + "@opencode-ai/schema": ["@opencode-ai/schema@0.0.0-beta-18593", "", { "dependencies": { "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112" } }, "sha512-jZgIR17nG6KucYqvCiMcNVuRz4amSTbL9VJXQpo4kA9R8UjMlnpyGqsEqrHQ7xGUhib8FR1NtN6UXWyboaE3pQ=="], - "@opencode-ai/sdk": ["@opencode-ai/sdk@1.18.5", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-7KgMvP5/1oxbhHj6kYBtPSTEdFKYpUeEYOzBTKdzSaRpapUpFFdn6Hkus3rr0rljO0kukWZIgRd3DrVBwTULGA=="], + "@opencode-ai/sdk": ["@opencode-ai/sdk@1.17.1", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-YTMtG3qCWgF37M9suOL5KpQTKU2Ibkd0/eKLS4tEIXe1S2wvUQ+/Hi1QARw4SoD6cy6+KUINvyo6dkhFEo7WLw=="], - "@opencode-ai/theme": ["@opencode-ai/theme@0.0.0-next-17055", "", { "dependencies": { "@opentui/core": "0.4.5", "effect": "4.0.0-beta.101" } }, "sha512-9RurytAQwsBjine2D1CBYVVVV748q9AZPhp39WZaxK/j2hlmVWZDA5dwgm3VXzKa5XPNN4MAk/2JkRDW7atdFw=="], + "@opencode-ai/theme": ["@opencode-ai/theme@0.0.0-beta-18593", "", { "dependencies": { "@opentui/core": "0.5.9", "effect": "4.0.0-rc.112" } }, "sha512-Pz9esAE632n9x9PZDEm1pVX34z8dgqcO2u/7a9qhQ0JGUcg2+WwpBSH8HFfC+qUg7CT/6H0y5g04khlgQHTw/g=="], - "@opentui/core": ["@opentui/core@0.4.0", "", { "dependencies": { "bun-ffi-structs": "0.2.3", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.4.0", "@opentui/core-darwin-x64": "0.4.0", "@opentui/core-linux-arm64": "0.4.0", "@opentui/core-linux-arm64-musl": "0.4.0", "@opentui/core-linux-x64": "0.4.0", "@opentui/core-linux-x64-musl": "0.4.0", "@opentui/core-win32-arm64": "0.4.0", "@opentui/core-win32-x64": "0.4.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-G3TmJmaPoxD6SadwevZNE30H/pMZsr/qneVaKc7bmFBxA+uHgxFSAsMoFYaEqcFJM1dGt22kMJb+YY2ZahzqVw=="], + "@opentui/core": ["@opentui/core@0.5.9", "", { "dependencies": { "bun-ffi-structs": "0.3.1", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.5.9", "@opentui/core-darwin-x64": "0.5.9", "@opentui/core-linux-arm64": "0.5.9", "@opentui/core-linux-arm64-musl": "0.5.9", "@opentui/core-linux-x64": "0.5.9", "@opentui/core-linux-x64-musl": "0.5.9", "@opentui/core-win32-arm64": "0.5.9", "@opentui/core-win32-x64": "0.5.9" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-d0EWYyp6djitu1N1R0o75NrLl4TxY3oJEmRNrX9vSKKC5/jriGQdSV6lJmwiB77O0cxtBnPzWztAV79vA1J2fA=="], - "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.4.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-t7VGLn2LyCGWSrhYdQ2xnq0L0sjg6VOdM6OyFxrZC3HU69m+PXqIhWMpGw/m8V6W7//uM1RX2GQrB/mgJ1Ce0Q=="], + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.5.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-YcpWGD8GwoO3UYYw0kLDI4qof3ElSwWW5M3fNG+Kw87BSjCa5frZqak5xebdZ/XU5Xsk+BjgbBsxbzo9yrIjZQ=="], - "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.4.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-/3goEuLFxn9df4fsLw9MSzbp8T3Rcs0NltCS3k73LcCb27pBmHH2FFNDKIj96m5ktK2JIWglEXcX85/i1qy4ug=="], + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.5.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-xgdZwgcwlDCqi0WPCS1d0GVSd+oKDFX+UVE1ZPei8u8W3pirXGSExxVHNku7QbEYCRvpCeMtoKIa6xN9cVTsoQ=="], - "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.4.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-KBv05c0e+FRUpPKRqrE5bDmmIhiJsho43EDXJuYOUYJAuGsTii8J8ws0Q4GYBIxZa/atG1Wv3rEKR7+RSd29lA=="], + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.5.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-vHBiJp69wMaL+fRMDpnXCCIpPyQRPZEWCWBatnblUUGIWUseqeQlaPow6ljHSbgAd/GjygAf4tFCyTqNT2ezZA=="], - "@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.4.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-8SL+HCpXc1Ott4MYfPzBdNM6XUhknBlqAKOmdDnTxkFSnnadJxhBJo+JYX1jxQP/lkd3jKUpEKDc51k9wud4tg=="], + "@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.5.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-A7GW4NCTInj2vy3X2gVO2Sm8jllgdLxwPdOklPqyl+xqivQtyG9qwS5YXoCk9fBJt10ORhYKETEjYEnIE5xvMQ=="], - "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.4.0", "", { "os": "linux", "cpu": "x64" }, "sha512-n2aZdF2vkzXyV0C0JL9Ok3EDImtWqewZVcFutMkCRK+EQk3a4oa+bl2Y07XpxGN8FZyJxS+R/HWSoDbKBNKDAg=="], + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.5.9", "", { "os": "linux", "cpu": "x64" }, "sha512-rdw7QVopVHwj6fMrJc7hPGVaYg2V5NBlW3MUfkrQBlUlo/87OC4aYDAh5oRIL1CIFD9LjDdh7hwmUNbn/K9Pcw=="], - "@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.4.0", "", { "os": "linux", "cpu": "x64" }, "sha512-EpBHP5S8O83VgI4YIM/CPZTUVIGJjYyk+dcYJl76phtRYF4CwZTvomQqyHb0lzXGZ7LwSDoQxsWtLs/hEOVyPA=="], + "@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.5.9", "", { "os": "linux", "cpu": "x64" }, "sha512-J4wQs1OMPZ4hR93Op1C/BLFmIta2mUJm4M7djevlgcWcal4RSNO4V8QvUXfogWGci+ADZqEmX2osQQDY5NVJpw=="], - "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.4.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-nUoKrHTHDMyqDGSqN7XfKvjaevgS460Pd99tzLCY4rTZcyDTdEUDfnLgEQrkURRCfUsBbwB1lNnq1aP4u+GeZQ=="], + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.5.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-OnmEsGLWwsHrm6sTsWSSesu4LGjSV1JNWqCsEItbuitWaqH6rXdSahSc5jMFsS57bZxUyaRz01yAqiZzUSXnVQ=="], - "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.4.0", "", { "os": "win32", "cpu": "x64" }, "sha512-3uHjGfgjhw+tyxDoF6bs11Gbrt+8VP7k6vAMm9Qyvd8cExDFaNcR1E5Tf/6yR7oxGfh9E951ALue8M7h6l/lLQ=="], + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.5.9", "", { "os": "win32", "cpu": "x64" }, "sha512-/CnAIfKL7+ZeGLyZoXV5zS71Nd8Zn97RUir2DAIY05MJozmfg5s7XOAdUNYuK1cg5mbwlAuqeAsfbuWUAEe15g=="], - "@opentui/solid": ["@opentui/solid@0.4.0", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.4.0", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-tWzJ5PSi7txgbG+4h6vZ3FuTpa/gujQ4D0B4G9LmXddKUq/8lcUBJMHSSEdzSTcIO9fJAOSke2HKK9lsYZ0/fQ=="], + "@opentui/solid": ["@opentui/solid@0.5.9", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.9", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-zGSP/ia9ww+TTMvQMZjJW2+h7fg9YkVRIM723EgvP+v7ZBZ/0vMzPNh7FJ0jET3ysw0h5hsbvcYISs4sUcf+UA=="], "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], @@ -256,7 +256,7 @@ "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], - "bun-ffi-structs": ["bun-ffi-structs@0.2.3", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-pgJiXP+hEgFo9qG51J6ItfY4ocs3vniwNzJ9WhoakB3QB2GdzQxX2EXssentPYlB2hOfJrTjO6iIQkWYzUodpg=="], + "bun-ffi-structs": ["bun-ffi-structs@0.3.1", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-3gM7PpVWLyrwxWjcilSiGuhWanhZivvo6l0u573NziPH6f/gwk6McbaYgn7oJWov6pKGRTDbrg94W5DcJsKTtQ=="], "bun-types": ["bun-types@1.3.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-QXKeHLlOLqQX9LgYaHJfzdBaV21T63HhFJnvuRCcjZiaUDpbs5ED1MgxbMra71CsryN/1dAoXuJJJwIv/2drVA=="], @@ -430,11 +430,11 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "msgpackr": ["msgpackr@2.0.4", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA=="], + "msgpackr": ["msgpackr@2.1.0", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-p/pBCVO63CsvvpkomUnNNag6+n38rULuDA6HHe70o2gtC8ODI52foF/4ko2qQcp6OiErJXTmrZeXmsGGHsIQNQ=="], "msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="], - "multipasta": ["multipasta@0.2.8", "", {}, "sha512-ZPWuMKyv0cSO29f7hozp+k6+crZbQijV8ipMvxNxRf2SwtYGTX1ZX89Kd20VV4H9Znonx+EQn+iy1wGQsJ+b+Q=="], + "multipasta": ["multipasta@0.2.7", "", {}, "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA=="], "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], @@ -514,7 +514,7 @@ "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], - "toml": ["toml@4.3.0", "", {}, "sha512-lVb8X9BsPVuH0M4BKeS91tXAmJvCjQ5UIyAbQFaxkKGyUFK2RPkhwaFSQH8vbpl1d23eu/IBH+dwVMHWaq9A5A=="], + "toml": ["toml@4.1.1", "", {}, "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw=="], "ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="], @@ -532,7 +532,7 @@ "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - "uuid": ["uuid@14.0.1", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew=="], + "uuid": ["uuid@14.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg=="], "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], @@ -552,8 +552,6 @@ "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "yoga-layout": ["yoga-layout@3.2.1", "", {}, "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ=="], - "zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="], "@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=="], @@ -568,21 +566,17 @@ "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - "@opencode-ai/ai/effect": ["effect@4.0.0-beta.101", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.9.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.4", "multipasta": "^0.2.8", "toml": "^4.1.2", "uuid": "^14.0.1", "yaml": "^2.9.0" } }, "sha512-HjowumlIo+orthn4jMlEJPuzIYPBV+uq/XiciHWhiedLsXQpWHdNJHO5d59BVDP5s1LPuvERcktwFqRXnJqnhA=="], - - "@opencode-ai/plugin/@opencode-ai/sdk": ["@opencode-ai/sdk@1.17.1", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-YTMtG3qCWgF37M9suOL5KpQTKU2Ibkd0/eKLS4tEIXe1S2wvUQ+/Hi1QARw4SoD6cy6+KUINvyo6dkhFEo7WLw=="], + "@opencode-ai/ai/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], "@opencode-ai/plugin/effect": ["effect@4.0.0-beta.74", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.8.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.1", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^14.0.0", "yaml": "^2.9.0" } }, "sha512-Yx+Kh12U+i2FmjwEfKs+ePFmpMd43RPD1oGqc/VraSS9bYzvF0Ff3PojwEFEVEewp8xc92Uxu28gTspU4qyvHA=="], - "@opencode-ai/plugin-v2/effect": ["effect@4.0.0-beta.101", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.9.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.4", "multipasta": "^0.2.8", "toml": "^4.1.2", "uuid": "^14.0.1", "yaml": "^2.9.0" } }, "sha512-HjowumlIo+orthn4jMlEJPuzIYPBV+uq/XiciHWhiedLsXQpWHdNJHO5d59BVDP5s1LPuvERcktwFqRXnJqnhA=="], + "@opencode-ai/plugin-v2/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], - "@opencode-ai/protocol/effect": ["effect@4.0.0-beta.101", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.9.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.4", "multipasta": "^0.2.8", "toml": "^4.1.2", "uuid": "^14.0.1", "yaml": "^2.9.0" } }, "sha512-HjowumlIo+orthn4jMlEJPuzIYPBV+uq/XiciHWhiedLsXQpWHdNJHO5d59BVDP5s1LPuvERcktwFqRXnJqnhA=="], + "@opencode-ai/protocol/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], - "@opencode-ai/schema/effect": ["effect@4.0.0-beta.101", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.9.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.4", "multipasta": "^0.2.8", "toml": "^4.1.2", "uuid": "^14.0.1", "yaml": "^2.9.0" } }, "sha512-HjowumlIo+orthn4jMlEJPuzIYPBV+uq/XiciHWhiedLsXQpWHdNJHO5d59BVDP5s1LPuvERcktwFqRXnJqnhA=="], + "@opencode-ai/schema/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], - "@opencode-ai/theme/@opentui/core": ["@opentui/core@0.4.5", "", { "dependencies": { "bun-ffi-structs": "0.2.4", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.4.5", "@opentui/core-darwin-x64": "0.4.5", "@opentui/core-linux-arm64": "0.4.5", "@opentui/core-linux-arm64-musl": "0.4.5", "@opentui/core-linux-x64": "0.4.5", "@opentui/core-linux-x64-musl": "0.4.5", "@opentui/core-win32-arm64": "0.4.5", "@opentui/core-win32-x64": "0.4.5" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-JsgRTPkA6e+Vxmumxai6SElOSlRQkbzNKHlCfemlArRiLhfC1IZ9RXJo2QH4xSu+uBOWAM90uss73/pPlkdEig=="], - - "@opencode-ai/theme/effect": ["effect@4.0.0-beta.101", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.9.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.4", "multipasta": "^0.2.8", "toml": "^4.1.2", "uuid": "^14.0.1", "yaml": "^2.9.0" } }, "sha512-HjowumlIo+orthn4jMlEJPuzIYPBV+uq/XiciHWhiedLsXQpWHdNJHO5d59BVDP5s1LPuvERcktwFqRXnJqnhA=="], + "@opencode-ai/theme/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], @@ -628,34 +622,12 @@ "@opencode-ai/plugin/effect/fast-check": ["fast-check@4.8.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg=="], - "@opencode-ai/plugin/effect/multipasta": ["multipasta@0.2.7", "", {}, "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA=="], - - "@opencode-ai/plugin/effect/toml": ["toml@4.1.1", "", {}, "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw=="], - - "@opencode-ai/plugin/effect/uuid": ["uuid@14.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg=="], + "@opencode-ai/plugin/effect/msgpackr": ["msgpackr@2.0.4", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA=="], "@opencode-ai/protocol/effect/fast-check": ["fast-check@4.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="], "@opencode-ai/schema/effect/fast-check": ["fast-check@4.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="], - "@opencode-ai/theme/@opentui/core/@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.4.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8KUG0oRidnR+oW1RSZJ72/PhZLl+qRRMk5U/mieF4c0SJ5V3tYACpBZAKzQfHNd1f7QzD8FHZct1lPpQgtmkWg=="], - - "@opencode-ai/theme/@opentui/core/@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.4.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-R2bocsg55gwjOqCp/MWFgFYzRmsduKegB6nzgFAPCvAD/L5Jf30xpWJWFlSg3x8vxe1L9WJ84dfqa4M7mZZ3wA=="], - - "@opencode-ai/theme/@opentui/core/@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.4.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-R4MZ25a4CzOAGVjW9aj1hUfzQGVfCJwrwBDbNs2SXaIvzcZqkxCVtU4FoQ5LsaD0j/BdNQVg2CIfFkFsm1fDuQ=="], - - "@opencode-ai/theme/@opentui/core/@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.4.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ieqdyKI6EIYPalYAETB2wsdP83hr5Ifi+dFnBFUmdEEFHsoKwBmn2S7bsTOYlX7Bg03F4/YPIg+IvRpeC+cUJw=="], - - "@opencode-ai/theme/@opentui/core/@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.4.5", "", { "os": "linux", "cpu": "x64" }, "sha512-SNyuQoxMKI1vuJhgxSSW96adWM6LqFl2SoS3GM4tGeneGOanVVG2Y06PvlytXvF4cKik97t0rqkVMRetmOs93w=="], - - "@opencode-ai/theme/@opentui/core/@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.4.5", "", { "os": "linux", "cpu": "x64" }, "sha512-mKVKcIcPiSVVZZsdPSBoWwoa2/TCeQAaMDeHF7PFw2kt5bTXZPP7xxWfRQLCNIcA1eaGl59UuwUWHDR2Ve548Q=="], - - "@opencode-ai/theme/@opentui/core/@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.4.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-GHTTsqeR45q2Iek9Rb7ty+x/hAKn2jZ1ujlCgPR8LBKyF7h0E1dNFryoZ7ehMc3kJndP1sKn836IemKFqxuDdQ=="], - - "@opencode-ai/theme/@opentui/core/@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.4.5", "", { "os": "win32", "cpu": "x64" }, "sha512-Y8T/yXCDGagRGiQrtmuB6AhRcPucKFs/Dre3v8kJwNYqDccI4FzUPKclZ7djfmRZNjl7JUqPhZZP/PwDpQocMg=="], - - "@opencode-ai/theme/@opentui/core/bun-ffi-structs": ["bun-ffi-structs@0.2.4", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-AJzsqoVFs1KBbJbWHIYrVZLDC3NhTqqh25awRXqzoLzmBAKr5oqk6+CwuYHAekKx+VBCYVohBoKuRq40dV+TYg=="], - "@opencode-ai/theme/effect/fast-check": ["fast-check@4.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="], "glob/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="], diff --git a/dist/server.js b/dist/server.js index 2fbca64..c8d8d4b 100644 --- a/dist/server.js +++ b/dist/server.js @@ -2963,11 +2963,17 @@ async function setupV2(context) { } if (registerCommand) { registrations.push(await context.command.transform((draft) => { - if (draft.get(commandName)) - return; - draft.update(commandName, (command) => { - command.description = "Set or view the long-running session goal"; - command.template = goalCommandTemplate(commandName); + draft.add({ + name: commandName, + description: "Set or view the long-running session goal", + execute: async (input) => { + await context.session.prompt({ + ...input.prompt, + sessionID: input.sessionID, + text: goalCommandTemplate(commandName).replaceAll("$ARGUMENTS", () => input.prompt.text.trim()), + delivery: input.delivery + }); + } }); })); } diff --git a/package.json b/package.json index c4c036f..c482ba6 100644 --- a/package.json +++ b/package.json @@ -55,16 +55,16 @@ }, "dependencies": { "@opencode-ai/plugin": "^1.17.1", - "@opentui/solid": "^0.4.0", + "@opentui/solid": "0.5.9", "effect": "^3.21.2", "solid-js": "1.9.12", "zod": "^4.1.8" }, "devDependencies": { "@eslint/js": "^10.0.1", - "@opencode-ai/plugin-v2": "npm:@opencode-ai/plugin@0.0.0-next-17055", - "@opencode-ai/theme": "0.0.0-next-17055", - "@opentui/core": "^0.4.0", + "@opencode-ai/plugin-v2": "npm:@opencode-ai/plugin@0.0.0-beta-18593", + "@opencode-ai/theme": "0.0.0-beta-18593", + "@opentui/core": "0.5.9", "@types/bun": "^1.3.13", "eslint": "^10.3.0", "typescript": "^6.0.3", diff --git a/src/server.ts b/src/server.ts index c63c4a3..2138251 100644 --- a/src/server.ts +++ b/src/server.ts @@ -2089,10 +2089,17 @@ async function setupV2(context: PluginV2.Plugin.Context): Promise { - if (draft.get(commandName)) return - draft.update(commandName, (command) => { - command.description = "Set or view the long-running session goal" - command.template = goalCommandTemplate(commandName) + draft.add({ + name: commandName, + description: "Set or view the long-running session goal", + execute: async (input) => { + await context.session.prompt({ + ...input.prompt, + sessionID: input.sessionID, + text: goalCommandTemplate(commandName).replaceAll("$ARGUMENTS", () => input.prompt.text.trim()), + delivery: input.delivery, + }) + }, }) }), ) diff --git a/test/server-v2.test.ts b/test/server-v2.test.ts index 7103ed2..7364ccf 100644 --- a/test/server-v2.test.ts +++ b/test/server-v2.test.ts @@ -28,8 +28,15 @@ type ToolDraft = { } type MockCommandDraft = { - get(name: string): { name: string; template: string } | undefined - update(name: string, update: (command: { description?: string; template: string }) => void): void + add(command: { + name: string + description?: string + execute: (input: { + sessionID: string + prompt: { text: string; files?: Array<{ uri: string }> } + delivery: "steer" | "queue" + }) => Promise + }): void } type Registration = { dispose: () => Promise } @@ -66,9 +73,15 @@ function controlledStream() { type MockContext = { options: Record - promptCalls: Array<{ sessionID: string; text: string; agents?: Array<{ name: string }> }> + promptCalls: Array<{ + sessionID: string + text: string + files?: Array<{ uri: string }> + agents?: Array<{ name: string }> + delivery?: "steer" | "queue" + }> tools: Array void ? T : never> - commandDraft: MockCommandDraft + commands: Array void ? T : never> hooks: Record void> systemParts: Array<{ type: string; text: string }> stream: ReturnType @@ -82,7 +95,13 @@ type MockContext = { } session: { hook: (name: string, callback: (input: unknown) => void) => Promise - prompt: (input: { sessionID: string; text: string; agents?: Array<{ name: string }> }) => Promise + prompt: (input: { + sessionID: string + text: string + files?: Array<{ uri: string }> + agents?: Array<{ name: string }> + delivery?: "steer" | "queue" + }) => Promise } event: { subscribe: (options?: { signal?: AbortSignal }) => AsyncIterable @@ -91,18 +110,11 @@ type MockContext = { function makeMockContext(options: Record = {}): MockContext { const tools: MockContext["tools"] = [] + const commands: MockContext["commands"] = [] const hooks: MockContext["hooks"] = {} const promptCalls: MockContext["promptCalls"] = [] const disposals: string[] = [] const stream = controlledStream() - const commandDraft: MockCommandDraft = { - get: () => undefined, - update: (name, update) => { - const command = { name, template: "" } - update(command) - commandDraft.get = () => command - }, - } const registration = (name: string): Registration => ({ dispose: async () => { disposals.push(name) @@ -112,14 +124,14 @@ function makeMockContext(options: Record = {}): MockContext { options, promptCalls, tools, - commandDraft, + commands, hooks, systemParts: [], stream, disposals, command: { transform: async (callback) => { - callback(commandDraft) + callback({ add: (command) => commands.push(command) }) return registration("command.transform") }, }, @@ -310,12 +322,26 @@ test("V2 setup registers the /goal command via command transform", async () => { const mock = makeMockContext({ auto_continue: false }) const cleanup = await setupPlugin(mock as never) - const command = mock.commandDraft.get("goal") + const command = mock.commands.find((candidate) => candidate.name === "goal") expect(command).toBeDefined() - expect(command?.template).toContain('OpenCode goal mode command "/goal" was invoked') - expect(command?.template).toContain("$ARGUMENTS") - expect(command?.template).toContain("call get_goal first") - expect(command?.template).toContain("never call it again") + expect(command?.description).toBe("Set or view the long-running session goal") + + await command?.execute({ + sessionID: "ses_command", + prompt: { text: "ship the V2 fix", files: [{ uri: "file:///tmp/context.txt" }] }, + delivery: "queue", + }) + expect(mock.promptCalls).toHaveLength(1) + expect(mock.promptCalls[0]).toMatchObject({ + sessionID: "ses_command", + files: [{ uri: "file:///tmp/context.txt" }], + delivery: "queue", + }) + expect(mock.promptCalls[0]?.text).toContain('OpenCode goal mode command "/goal" was invoked') + expect(mock.promptCalls[0]?.text).toContain("ship the V2 fix") + expect(mock.promptCalls[0]?.text).toContain("call get_goal first") + expect(mock.promptCalls[0]?.text).toContain("never call it again") + expect(mock.promptCalls[0]?.text).not.toContain("$ARGUMENTS") mock.stream.end() await cleanup() @@ -325,7 +351,7 @@ test("V2 setup skips command registration when register_command is false", async const mock = makeMockContext({ auto_continue: false, register_command: false }) const cleanup = await setupPlugin(mock as never) - expect(mock.commandDraft.get("goal")).toBeUndefined() + expect(mock.commands).toHaveLength(0) expect(mock.disposals).not.toContain("command.transform") mock.stream.end() From 9c6d757bfa659920ecdf306085febc4620530a86 Mon Sep 17 00:00:00 2001 From: Daniel Saldarriaga Date: Thu, 3 Sep 2026 12:22:56 +0200 Subject: [PATCH 2/2] fix: preserve command attachment metadata --- bun.lock | 2 +- dist/server.js | 4 ++++ package.json | 2 +- src/server.ts | 4 ++++ test/server-v2.test.ts | 39 ++++++++++++++++++++++++++------------- 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/bun.lock b/bun.lock index 30a573f..a087ebc 100644 --- a/bun.lock +++ b/bun.lock @@ -6,7 +6,7 @@ "name": "opencode-goal-plugin", "dependencies": { "@opencode-ai/plugin": "^1.17.1", - "@opentui/solid": "0.5.9", + "@opentui/solid": ">=0.4.0 <0.6.0", "effect": "^3.21.2", "solid-js": "1.9.12", "zod": "^4.1.8", diff --git a/dist/server.js b/dist/server.js index c8d8d4b..f972708 100644 --- a/dist/server.js +++ b/dist/server.js @@ -2967,8 +2967,12 @@ async function setupV2(context) { name: commandName, description: "Set or view the long-running session goal", execute: async (input) => { + const stripMention = ({ mention: _mention, ...attachment }) => attachment; await context.session.prompt({ ...input.prompt, + files: input.prompt.files?.map(stripMention), + agents: input.prompt.agents?.map(stripMention), + skills: input.prompt.skills?.map(stripMention), sessionID: input.sessionID, text: goalCommandTemplate(commandName).replaceAll("$ARGUMENTS", () => input.prompt.text.trim()), delivery: input.delivery diff --git a/package.json b/package.json index c482ba6..376a030 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ }, "dependencies": { "@opencode-ai/plugin": "^1.17.1", - "@opentui/solid": "0.5.9", + "@opentui/solid": ">=0.4.0 <0.6.0", "effect": "^3.21.2", "solid-js": "1.9.12", "zod": "^4.1.8" diff --git a/src/server.ts b/src/server.ts index 2138251..b2f2c90 100644 --- a/src/server.ts +++ b/src/server.ts @@ -2093,8 +2093,12 @@ async function setupV2(context: PluginV2.Plugin.Context): Promise { + const stripMention = ({ mention: _mention, ...attachment }: T) => attachment await context.session.prompt({ ...input.prompt, + files: input.prompt.files?.map(stripMention), + agents: input.prompt.agents?.map(stripMention), + skills: input.prompt.skills?.map(stripMention), sessionID: input.sessionID, text: goalCommandTemplate(commandName).replaceAll("$ARGUMENTS", () => input.prompt.text.trim()), delivery: input.delivery, diff --git a/test/server-v2.test.ts b/test/server-v2.test.ts index 7364ccf..0e49ec4 100644 --- a/test/server-v2.test.ts +++ b/test/server-v2.test.ts @@ -27,13 +27,21 @@ type ToolDraft = { }): void } +type MockMention = { start: number; end: number; text: string } +type MockPrompt = { + text: string + files?: Array<{ uri: string; mention?: MockMention }> + agents?: Array<{ name: string; mention?: MockMention }> + skills?: Array<{ id: string; mention?: MockMention }> +} + type MockCommandDraft = { add(command: { name: string description?: string execute: (input: { sessionID: string - prompt: { text: string; files?: Array<{ uri: string }> } + prompt: MockPrompt delivery: "steer" | "queue" }) => Promise }): void @@ -75,11 +83,8 @@ type MockContext = { options: Record promptCalls: Array<{ sessionID: string - text: string - files?: Array<{ uri: string }> - agents?: Array<{ name: string }> delivery?: "steer" | "queue" - }> + } & MockPrompt> tools: Array void ? T : never> commands: Array void ? T : never> hooks: Record void> @@ -97,11 +102,8 @@ type MockContext = { hook: (name: string, callback: (input: unknown) => void) => Promise prompt: (input: { sessionID: string - text: string - files?: Array<{ uri: string }> - agents?: Array<{ name: string }> delivery?: "steer" | "queue" - }) => Promise + } & MockPrompt) => Promise } event: { subscribe: (options?: { signal?: AbortSignal }) => AsyncIterable @@ -328,20 +330,31 @@ test("V2 setup registers the /goal command via command transform", async () => { await command?.execute({ sessionID: "ses_command", - prompt: { text: "ship the V2 fix", files: [{ uri: "file:///tmp/context.txt" }] }, + prompt: { + text: "ship $& and $ARGUMENTS", + files: [{ uri: "file:///tmp/context.txt", mention: { start: 5, end: 7, text: "$&" } }], + agents: [{ name: "build", mention: { start: 5, end: 7, text: "$&" } }], + skills: [{ id: "review", mention: { start: 5, end: 7, text: "$&" } }], + }, delivery: "queue", }) expect(mock.promptCalls).toHaveLength(1) expect(mock.promptCalls[0]).toMatchObject({ sessionID: "ses_command", - files: [{ uri: "file:///tmp/context.txt" }], delivery: "queue", }) + expect(mock.promptCalls[0]?.files).toEqual([{ uri: "file:///tmp/context.txt" }]) + expect(mock.promptCalls[0]?.agents).toEqual([{ name: "build" }]) + expect(mock.promptCalls[0]?.skills).toEqual([{ id: "review" }]) expect(mock.promptCalls[0]?.text).toContain('OpenCode goal mode command "/goal" was invoked') - expect(mock.promptCalls[0]?.text).toContain("ship the V2 fix") + expect(mock.promptCalls[0]?.text).toContain("ship $& and $ARGUMENTS") expect(mock.promptCalls[0]?.text).toContain("call get_goal first") expect(mock.promptCalls[0]?.text).toContain("never call it again") - expect(mock.promptCalls[0]?.text).not.toContain("$ARGUMENTS") + expect(mock.promptCalls[0]?.text.match(/\$ARGUMENTS/g)).toHaveLength(1) + + await command?.execute({ sessionID: "ses_empty", prompt: { text: "" }, delivery: "steer" }) + expect(mock.promptCalls[1]).toMatchObject({ sessionID: "ses_empty", delivery: "steer" }) + expect(mock.promptCalls[1]?.text).toContain("If the arguments are empty, call get_goal") mock.stream.end() await cleanup()