This commit is contained in:
2026-01-19 03:32:49 +08:00
commit 449d2ffdd7
26 changed files with 5739 additions and 0 deletions

44
.cnb.yml Normal file
View File

@@ -0,0 +1,44 @@
# .cnb.yml
include:
- https://cnb.cool/kevisual/cnb/-/blob/main/.cnb/template.yml
.common_env: &common_env
env:
TO_REPO: kevisual/skill-runner
TO_URL: git.xiongxiao.me
imports:
- https://cnb.cool/kevisual/env/-/blob/main/.env.development
$:
vscode:
- docker:
image: docker.cnb.cool/kevisual/dev-env:latest
services:
- vscode
- docker
imports: !reference [.common_env, imports]
# 开发环境启动后会执行的任务
# stages:
# - name: pnpm install
# script: pnpm install
stages: !reference [.dev_tempalte, stages]
.common_sync_to_gitea: &common_sync_to_gitea
- <<: *common_env
services: !reference [.common_sync_to_gitea_template, services]
stages: !reference [.common_sync_to_gitea_template, stages]
.common_sync_from_gitea: &common_sync_from_gitea
- <<: *common_env
services: !reference [.common_sync_from_gitea_template, services]
stages: !reference [.common_sync_from_gitea_template, stages]
main:
web_trigger_sync_to_gitea:
- <<: *common_sync_to_gitea
web_trigger_sync_from_gitea:
- <<: *common_sync_from_gitea
api_trigger_sync_to_gitea:
- <<: *common_sync_to_gitea
api_trigger_sync_from_gitea:
- <<: *common_sync_from_gitea

11
.cnb/web_trigger.yml Normal file
View File

@@ -0,0 +1,11 @@
# .cnb/web_trigger.yml
branch:
# 如下按钮在分支名以 release 开头的分支详情页面显示
- reg: "^main"
buttons:
- name: 同步代码到gitea
description: 同步代码到gitea
event: web_trigger_sync_to_gitea
- name: 同步gitea代码到当前仓库
description: 同步gitea代码到当前仓库
event: web_trigger_sync_from_gitea

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules

11
readme.md Normal file
View File

@@ -0,0 +1,11 @@
# 右键运行opencode
本项目旨在实现通过右键菜单快速运行 OpenCode 脚本的功能,提升用户的工作效率。
## vscode插件
id: abearxiong.skill-runner
选中文本,右键点击“运行技能”,即可在终端中执行预设的 OpenCode 命令,并将选中的文本作为参数传递。
目标:简化 OpenCode 脚本的执行流程,使用户能够更便捷地运行脚本。

2
skill-runner-vscode/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules
*.vsix

View File

@@ -0,0 +1 @@
enable-pre-post-scripts = true

View File

@@ -0,0 +1,5 @@
import { defineConfig } from '@vscode/test-cli';
export default defineConfig({
files: 'out/test/**/*.test.js',
});

View File

@@ -0,0 +1,5 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": ["dbaeumer.vscode-eslint", "connor4312.esbuild-problem-matchers", "ms-vscode.extension-test-runner"]
}

21
skill-runner-vscode/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,21 @@
// A launch configuration that compiles the extension and then opens it inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}"
}
]
}

View File

@@ -0,0 +1,13 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false, // set this to true to hide the "out" folder with the compiled JS files
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
},
"search.exclude": {
"out": true, // set this to false to include "out" folder in search results
"dist": true // set this to false to include "dist" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off"
}

64
skill-runner-vscode/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,64 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
{
"version": "2.0.0",
"tasks": [
{
"label": "watch",
"dependsOn": [
"npm: watch:tsc",
"npm: watch:esbuild"
],
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "npm",
"script": "watch:esbuild",
"group": "build",
"problemMatcher": "$esbuild-watch",
"isBackground": true,
"label": "npm: watch:esbuild",
"presentation": {
"group": "watch",
"reveal": "never"
}
},
{
"type": "npm",
"script": "watch:tsc",
"group": "build",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"label": "npm: watch:tsc",
"presentation": {
"group": "watch",
"reveal": "never"
}
},
{
"type": "npm",
"script": "watch-tests",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never",
"group": "watchers"
},
"group": "build"
},
{
"label": "tasks: watch-tests",
"dependsOn": [
"npm: watch",
"npm: watch-tests"
],
"problemMatcher": []
}
]
}

View File

@@ -0,0 +1,14 @@
.vscode/**
.vscode-test/**
out/**
node_modules/**
src/**
.gitignore
.yarnrc
esbuild.js
vsc-extension-quickstart.md
**/tsconfig.json
**/eslint.config.mjs
**/*.map
**/*.ts
**/.vscode-test.*

View File

@@ -0,0 +1,9 @@
# Change Log
All notable changes to the "skill-runner" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
## [Unreleased]
- Initial release

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,65 @@
# Skill Runner
一个简单的 VS Code 扩展,允许您通过右键菜单或命令面板在终端中运行自定义命令,并将选中的文本作为参数传递。
## 功能
- **右键菜单运行** - 在编辑器中选中文本后,右键点击选择"运行技能"执行命令
- **命令面板运行** - 通过 `Ctrl+Shift+P` (或 `Cmd+Shift+P`) 打开命令面板,搜索"Runner: 运行命令"
- **自动处理选中文本** - 选中的文本会自动去除首尾空格,换行和多余空格会被替换为单个空格
- **可自定义命令** - 通过设置或命令面板配置要执行的命令
## 使用方法
### 方法一:右键菜单
1. 在编辑器中选中文本(例如技能名称或参数)
2. 右键点击
3. 选择"运行技能"
### 方法二:命令面板
1.`Ctrl+Shift+P` (Windows/Linux) 或 `Cmd+Shift+P` (macOS)
2. 输入 "Runner: 运行命令"
3. 按回车执行
### 配置命令
1.`Ctrl+Shift+P` (Windows/Linux) 或 `Cmd+Shift+P` (macOS)
2. 输入 "Runner: 配置命令"
3. 输入您想要执行的命令
4. 保存配置
或者在 VS Code 设置中搜索 `skill-runner.command` 进行配置。
## 扩展设置
* `skill-runner.command`: 要在终端中运行的命令(默认:`opencode run`
## 示例
假设配置命令为 `opencode run`
- 选中文本 `hello` → 执行 `opencode run hello`
- 选中文本 `foo bar` → 执行 `opencode run foo bar`
- 选中多行文本会自动合并为单行
## 开发
```bash
# 安装依赖
pnpm install
# 编译
pnpm run compile
# 监听模式
pnpm run watch
# 运行测试
pnpm run test
```
## License
MIT

1
skill-runner-vscode/dist/extension.js vendored Normal file
View File

@@ -0,0 +1 @@
"use strict";var g=Object.create;var a=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var w=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var C=(n,o)=>{for(var t in o)a(n,t,{get:o[t],enumerable:!0})},l=(n,o,t,d)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of v(o))!f.call(n,s)&&s!==t&&a(n,s,{get:()=>o[s],enumerable:!(d=p(o,s))||d.enumerable});return n};var x=(n,o,t)=>(t=n!=null?g(w(n)):{},l(o||!n||!n.__esModule?a(t,"default",{value:n,enumerable:!0}):t,n)),k=n=>l(a({},"__esModule",{value:!0}),n);var $={};C($,{activate:()=>T,deactivate:()=>h});module.exports=k($);var e=x(require("vscode"));function T(n){console.log("skill-runner extension is now active!");let o=async()=>{let r=e.workspace.getConfiguration("skill-runner").get("command","opencode run"),i=e.window.activeTextEditor,c=i?.document.getText(i.selection)||"";c&&(c=c.trim().replace(/\s+/g," "));let u=e.window.createTerminal("Opencode Runner");c?u.sendText(`${r} ${c}`):u.sendText(r),u.show(),e.window.showInformationMessage(`Executing: ${c?`${r} ${c}`:r}`)},t=e.commands.registerCommand("skill-runner.run",o),d=e.commands.registerCommand("skill-runner.runPalette",o),s=e.commands.registerCommand("skill-runner.configure",async()=>{let m=e.workspace.getConfiguration("skill-runner"),r=m.get("command","opencode run"),i=await e.window.showInputBox({prompt:"Enter the command to run",value:r,placeHolder:"e.g., opencode run, npm run dev, etc."});i!==void 0&&(await m.update("command",i,e.ConfigurationTarget.Global),e.window.showInformationMessage(`Command updated to: ${i}`))});n.subscriptions.push(t,d,s)}function h(){}0&&(module.exports={activate,deactivate});

View File

@@ -0,0 +1,6 @@
{
"version": 3,
"sources": ["../src/extension.ts"],
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAAwB;AAKjB,SAAS,SAAS,SAAkC;AAC1D,UAAQ,IAAI,uCAAuC;AAGnD,QAAM,aAAa,YAAY;AAE9B,UAAM,SAAgB,iBAAU,iBAAiB,cAAc;AAC/D,UAAM,UAAU,OAAO,IAAY,WAAW,cAAc;AAG5D,UAAM,SAAgB,cAAO;AAC7B,QAAI,eAAe,QAAQ,SAAS,QAAQ,OAAO,SAAS,KAAK;AAGjE,QAAI,cAAc;AACjB,qBAAe,aACb,KAAK,EACL,QAAQ,QAAQ,GAAG;AAAA,IACtB;AAGA,UAAM,WAAkB,cAAO,eAAe,iBAAiB;AAC/D,QAAI,cAAc;AACjB,eAAS,SAAS,GAAG,OAAO,IAAI,YAAY,EAAE;AAAA,IAC/C,OAAO;AACN,eAAS,SAAS,OAAO;AAAA,IAC1B;AACA,aAAS,KAAK;AAEd,IAAO,cAAO,uBAAuB,cAAc,eAAe,GAAG,OAAO,IAAI,YAAY,KAAK,OAAO,EAAE;AAAA,EAC3G;AAGA,QAAM,aAAoB,gBAAS,gBAAgB,oBAAoB,UAAU;AAGjF,QAAM,oBAA2B,gBAAS,gBAAgB,2BAA2B,UAAU;AAG/F,QAAM,mBAA0B,gBAAS,gBAAgB,0BAA0B,YAAY;AAC9F,UAAM,SAAgB,iBAAU,iBAAiB,cAAc;AAC/D,UAAM,iBAAiB,OAAO,IAAY,WAAW,cAAc;AAEnE,UAAM,QAAQ,MAAa,cAAO,aAAa;AAAA,MAC9C,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,aAAa;AAAA,IACd,CAAC;AAED,QAAI,UAAU,QAAW;AACxB,YAAM,OAAO,OAAO,WAAW,OAAc,2BAAoB,MAAM;AACvE,MAAO,cAAO,uBAAuB,uBAAuB,KAAK,EAAE;AAAA,IACpE;AAAA,EACD,CAAC;AAED,UAAQ,cAAc,KAAK,YAAY,mBAAmB,gBAAgB;AAC3E;AAEO,SAAS,aAAa;AAAC;",
"names": []
}

View File

@@ -0,0 +1,56 @@
const esbuild = require("esbuild");
const production = process.argv.includes('--production');
const watch = process.argv.includes('--watch');
/**
* @type {import('esbuild').Plugin}
*/
const esbuildProblemMatcherPlugin = {
name: 'esbuild-problem-matcher',
setup(build) {
build.onStart(() => {
console.log('[watch] build started');
});
build.onEnd((result) => {
result.errors.forEach(({ text, location }) => {
console.error(`✘ [ERROR] ${text}`);
console.error(` ${location.file}:${location.line}:${location.column}:`);
});
console.log('[watch] build finished');
});
},
};
async function main() {
const ctx = await esbuild.context({
entryPoints: [
'src/extension.ts'
],
bundle: true,
format: 'cjs',
minify: production,
sourcemap: !production,
sourcesContent: false,
platform: 'node',
outfile: 'dist/extension.js',
external: ['vscode'],
logLevel: 'silent',
plugins: [
/* add to the end of plugins array */
esbuildProblemMatcherPlugin,
],
});
if (watch) {
await ctx.watch();
} else {
await ctx.rebuild();
await ctx.dispose();
}
}
main().catch(e => {
console.error(e);
process.exit(1);
});

View File

@@ -0,0 +1,27 @@
import typescriptEslint from "typescript-eslint";
export default [{
files: ["**/*.ts"],
}, {
plugins: {
"@typescript-eslint": typescriptEslint.plugin,
},
languageOptions: {
parser: typescriptEslint.parser,
ecmaVersion: 2022,
sourceType: "module",
},
rules: {
"@typescript-eslint/naming-convention": ["warn", {
selector: "import",
format: ["camelCase", "PascalCase"],
}],
curly: "warn",
eqeqeq: "warn",
"no-throw-literal": "warn",
semi: "warn",
},
}];

View File

@@ -0,0 +1,91 @@
{
"name": "skill-runner",
"displayName": "Skill Runner",
"publisher": "abearxiong",
"description": "右键运行命令插件",
"version": "0.0.1",
"repository": {
"type": "git",
"url": "https://cnb.cool/skillpod/skill-runner"
},
"license": "MIT",
"engines": {
"vscode": "^1.108.1"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:skill-runner.run"
],
"main": "./dist/extension.js",
"contributes": {
"commands": [
{
"command": "skill-runner.run",
"title": "运行技能"
},
{
"command": "skill-runner.runPalette",
"title": "Runner: 运行命令"
},
{
"command": "skill-runner.configure",
"title": "Runner: 配置命令"
}
],
"menus": {
"editor/context": [
{
"command": "skill-runner.run",
"group": "navigation"
}
],
"commandPalette": [
{
"command": "skill-runner.runPalette"
},
{
"command": "skill-runner.configure"
}
]
},
"configuration": {
"title": "Skill Runner",
"properties": {
"skill-runner.command": {
"type": "string",
"default": "opencode run",
"description": "要在终端中运行的命令"
}
}
}
},
"scripts": {
"vscode:prepublish": "pnpm run package",
"compile": "pnpm run check-types && pnpm run lint && node esbuild.js",
"watch": "npm-run-all -p watch:*",
"watch:esbuild": "node esbuild.js --watch",
"watch:tsc": "tsc --noEmit --watch --project tsconfig.json",
"package": "pnpm run check-types && pnpm run lint && node esbuild.js --production",
"compile-tests": "tsc -p . --outDir out",
"watch-tests": "tsc -p . -w --outDir out",
"pretest": "pnpm run compile-tests && pnpm run compile && pnpm run lint",
"check-types": "tsc --noEmit",
"lint": "eslint src",
"test": "vscode-test"
},
"devDependencies": {
"@types/mocha": "^10.0.10",
"@types/node": "22.x",
"@types/vscode": "^1.108.1",
"@vscode/test-cli": "^0.0.12",
"@vscode/test-electron": "^2.5.2",
"@vscode/vsce": "^3.7.1",
"esbuild": "^0.27.2",
"eslint": "^9.39.2",
"npm-run-all": "^4.1.5",
"typescript": "^5.9.3",
"typescript-eslint": "^8.52.0"
}
}

5126
skill-runner-vscode/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
onlyBuiltDependencies:
- esbuild

View File

@@ -0,0 +1,64 @@
import * as vscode from 'vscode';
// 默认命令配置键
const COMMAND_CONFIG_KEY = 'skill-runner.command';
export function activate(context: vscode.ExtensionContext) {
console.log('skill-runner extension is now active!');
// 执行命令的逻辑
const executeRun = async () => {
// 从配置中读取命令,默认为 opencode run
const config = vscode.workspace.getConfiguration('skill-runner');
const command = config.get<string>('command', 'opencode run');
// 获取选中的文本
const editor = vscode.window.activeTextEditor;
let selectedText = editor?.document.getText(editor.selection) || '';
// 处理选中的文本:去除首尾空格,移除所有换行
if (selectedText) {
selectedText = selectedText
.trim()
.replace(/\s+/g, ' ');
}
// 创建终端并执行命令
const terminal = vscode.window.createTerminal('Opencode Runner');
if (selectedText) {
terminal.sendText(`${command} ${selectedText}`);
} else {
terminal.sendText(command);
}
terminal.show();
vscode.window.showInformationMessage(`Executing: ${selectedText ? `${command} ${selectedText}` : command}`);
};
// 注册右键菜单执行命令
const runCommand = vscode.commands.registerCommand('skill-runner.run', executeRun);
// 注册命令面板执行命令
const runPaletteCommand = vscode.commands.registerCommand('skill-runner.runPalette', executeRun);
// 注册配置命令
const configureCommand = vscode.commands.registerCommand('skill-runner.configure', async () => {
const config = vscode.workspace.getConfiguration('skill-runner');
const currentCommand = config.get<string>('command', 'opencode run');
const input = await vscode.window.showInputBox({
prompt: 'Enter the command to run',
value: currentCommand,
placeHolder: 'e.g., opencode run, npm run dev, etc.'
});
if (input !== undefined) {
await config.update('command', input, vscode.ConfigurationTarget.Global);
vscode.window.showInformationMessage(`Command updated to: ${input}`);
}
});
context.subscriptions.push(runCommand, runPaletteCommand, configureCommand);
}
export function deactivate() {}

View File

@@ -0,0 +1,15 @@
import * as assert from 'assert';
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
// import * as myExtension from '../../extension';
suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');
test('Sample test', () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
});
});

View File

@@ -0,0 +1,16 @@
{
"compilerOptions": {
"module": "Node16",
"target": "ES2022",
"lib": [
"ES2022"
],
"sourceMap": true,
"rootDir": "src",
"strict": true, /* enable all strict type-checking options */
/* Additional Checks */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
}
}

View File

@@ -0,0 +1,48 @@
# Welcome to your VS Code Extension
## What's in the folder
* This folder contains all of the files necessary for your extension.
* `package.json` - this is the manifest file in which you declare your extension and command.
* The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesnt yet need to load the plugin.
* `src/extension.ts` - this is the main file where you will provide the implementation of your command.
* The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
* We pass the function containing the implementation of the command as the second parameter to `registerCommand`.
## Setup
* install the recommended extensions (amodio.tsl-problem-matcher, ms-vscode.extension-test-runner, and dbaeumer.vscode-eslint)
## Get up and running straight away
* Press `F5` to open a new window with your extension loaded.
* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`.
* Set breakpoints in your code inside `src/extension.ts` to debug your extension.
* Find output from your extension in the debug console.
## Make changes
* You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`.
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
## Explore the API
* You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`.
## Run tests
* Install the [Extension Test Runner](https://marketplace.visualstudio.com/items?itemName=ms-vscode.extension-test-runner)
* Run the "watch" task via the **Tasks: Run Task** command. Make sure this is running, or tests might not be discovered.
* Open the Testing view from the activity bar and click the Run Test" button, or use the hotkey `Ctrl/Cmd + ; A`
* See the output of the test result in the Test Results view.
* Make changes to `src/test/extension.test.ts` or create new test files inside the `test` folder.
* The provided test runner will only consider files matching the name pattern `**.test.ts`.
* You can create folders inside the `test` folder to structure your tests any way you want.
## Go further
* Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension).
* [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VS Code extension marketplace.
* Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).