@vibe-coder/cli 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -78
- package/README.zh.md +140 -0
- package/dist/cli.js +398 -181
- package/package.json +14 -3
package/README.md
CHANGED
|
@@ -1,141 +1,142 @@
|
|
|
1
|
-
|
|
2
1
|
<div align="center">
|
|
3
2
|
|
|
4
3
|
# 🌊 Vibe Coding CLI
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
**A vibe coding ecosystem builder tailored for OpenCode**
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@vibe-coder/cli)
|
|
8
|
+
[](../../LICENSE.md)
|
|
9
|
+
[](https://bun.sh)
|
|
7
10
|
|
|
8
|
-
[
|
|
9
|
-
[](../../LICENSE.md)
|
|
10
|
-
[](https://bun.sh)
|
|
11
|
+
**English** · [简体中文](https://github.com/HelloGGX/skill/blob/main/packages/vibe/README.zh.md)
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
> *Seamlessly aggregate AI tools and context rules, making your Agent truly understand your codebase.*
|
|
13
14
|
|
|
14
15
|
</div>
|
|
15
16
|
|
|
16
|
-
## 📖
|
|
17
|
+
## 📖 Introduction
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
`@vibe-coder/cli` is a modern command-line scaffolding tool built specifically for the **OpenCode** platform. Its core objective is to quickly set up a Vibe Coding development environment and simplify resource management for specification-driven development.
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
With the `vibe` command, you can pull TypeScript/Python tool scripts or Markdown rule files from remote GitHub repositories with a single click. It seamlessly registers them into your OpenCode configuration and manages the underlying runtime dependency environments, allowing you to focus entirely on "co-creating code with AI."
|
|
21
22
|
|
|
22
|
-
## ✨
|
|
23
|
+
## ✨ Features
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
25
|
+
* 🛠 **Fully Automated Tool Management:** Quickly parse, select, and download `.ts` / `.py` scripts from any GitHub repository straight to your local setup, ready to use out of the box.
|
|
26
|
+
* 📜 **Context & Capabilities United:** A unique ecosystem aggregation capability that perfectly blends the **tools/skills** needed for Agent execution with your **guidelines and best practices**. Supports on-demand installation of `.md` rule files so the AI truly understands your architectural intent.
|
|
27
|
+
* 📦 **Smart Configuration Injection:** Automatically intercepts and updates `.opencode/opencode.jsonc`, silently injecting tool enable-switches and Prompt instruction paths. Say goodbye to manual configuration forever.
|
|
28
|
+
* ⚡ **Lightning-Fast Parallel Updates:** Designed with a concurrency model to simultaneously handle resource comparison and pulling from multiple source repositories, drastically reducing update wait times.
|
|
29
|
+
* 🪄 **Standard Skills Aggregation:** Deeply integrated with Vercel's `pnpx skills` ecosystem, allowing you to manage standard Agent skill libraries alongside local extension resources within a unified CLI workflow.
|
|
29
30
|
|
|
30
31
|
---
|
|
31
32
|
|
|
32
|
-
## 🚀
|
|
33
|
+
## 🚀 Quick Start
|
|
33
34
|
|
|
34
|
-
###
|
|
35
|
+
### Prerequisites
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
* [Node.js](https://www.google.com/search?q=https://nodejs.org/) >= 18.0.0 or [Bun](https://bun.sh/) >= 1.0.0
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
# 使用 npm
|
|
40
|
-
npm install -g vibe-coding-cli
|
|
39
|
+
### Installation
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
bun add -g vibe-coding-cli
|
|
41
|
+
Install as a global package:
|
|
44
42
|
|
|
45
|
-
```
|
|
43
|
+
```bash
|
|
44
|
+
# Using npm
|
|
45
|
+
npm i -g @vibe-coder/cli
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
# Using bun
|
|
48
|
+
bun add -g @vibe-coder/cli
|
|
49
|
+
```
|
|
48
50
|
|
|
49
|
-
###
|
|
51
|
+
### Basic Usage
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
Initialize and add an ecosystem library (e.g., `helloggx/skill` from this project):
|
|
52
54
|
|
|
53
55
|
```bash
|
|
54
56
|
vibe add helloggx/skill
|
|
55
|
-
|
|
56
57
|
```
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
*The CLI will pop up an interactive menu, allowing you to flexibly select the **Tools** and **Rules** you want to install, automatically configuring the entire environment for you.*
|
|
59
60
|
|
|
60
61
|
---
|
|
61
62
|
|
|
62
|
-
## 📚
|
|
63
|
+
## 📚 Commands
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
| Command | Alias | Description |
|
|
66
|
+
| --- | --- | --- |
|
|
67
|
+
| `vibe add <repo>` | `a` | Parses the target GitHub repository, pops up a UI list, installs selected tools and rules on demand, and automatically injects configurations. |
|
|
68
|
+
| `vibe list` | `ls` | Prints a clear status map of all installed resources (local tools, context rules, global standard skills) in the current project. |
|
|
69
|
+
| `vibe update` | `up` | Concurrently pulls all source repositories recorded in `vibe-lock.json`, intelligently comparing and overwriting local scripts and rules. |
|
|
70
|
+
| `vibe remove [resource]` | `rm` | **No arguments:** Opens a UI multi-select list to remove local items.<br>
|
|
65
71
|
|
|
66
|
-
|
|
67
|
-
vibe add <repository>
|
|
72
|
+
<br>**With arguments:** Quickly matches and removes specified standard skills or local tools, cleaning up configurations synchronously. |
|
|
68
73
|
|
|
69
|
-
|
|
74
|
+
---
|
|
70
75
|
|
|
71
|
-
|
|
76
|
+
## 🏗️ Build Your Own Resource Repository
|
|
72
77
|
|
|
73
|
-
|
|
74
|
-
2. 克隆并解析目标仓库中的 `tool` 文件夹。
|
|
75
|
-
3. 提供交互式多选列表,让你选择需要的具体工具。
|
|
76
|
-
4. 自动拷贝文件、更新 `opencode.jsonc` 并配置 Python 依赖环境(如果需要)。
|
|
78
|
+
We highly encourage you or your team to create a dedicated Vibe Coding resource repository on GitHub to standardize your favorite AI tools and custom coding guidelines across all your projects.
|
|
77
79
|
|
|
78
|
-
###
|
|
80
|
+
### Recommended Directory Structure
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
To ensure perfect compatibility with `@vibe-coder/cli`, we recommend the following convention (referencing the `helloggx/skill` repository):
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
your-custom-repo/
|
|
86
|
+
├── skill/ # (Optional) Standard Vercel AI Agent skills
|
|
87
|
+
├── tool/ # Custom TS/Python executable tools
|
|
88
|
+
│ ├── get_dsl.ts
|
|
89
|
+
│ ├── get_dsl.py # 💡 Python scripts should share the exact name as the TS tool calling them
|
|
90
|
+
│ └── shadcn_vue_init.ts
|
|
91
|
+
└── rules/ # Personalized Markdown context rules
|
|
92
|
+
├── common/ # Global rules applicable to all projects
|
|
93
|
+
│ ├── coding-style.md
|
|
94
|
+
│ └── security.md
|
|
95
|
+
└── typescript/ # Tech-stack specific rules
|
|
96
|
+
└── coding-style.md # 💡 Recommended to share the name with the extended common rule
|
|
82
97
|
|
|
83
98
|
```
|
|
84
99
|
|
|
85
|
-
|
|
86
|
-
清晰打印当前项目中安装的所有本地 Tools(来自 `vibe-lock.json`)以及已安装的标准 Skills,便于进行环境审查。
|
|
100
|
+
### Organization Best Practices
|
|
87
101
|
|
|
88
|
-
|
|
102
|
+
* **Cross-Language Tool Linkage**: If your `.ts` tool script relies on an underlying `.py` script, **ensure both files share the exact same base name** (e.g., `get_dsl.ts` and `get_dsl.py`). The CLI intelligently detects and pulls both files together.
|
|
103
|
+
* **Rule Inheritance & Overrides**:
|
|
104
|
+
* Always place your global, universal coding rules in the `rules/common/` directory.
|
|
105
|
+
* When creating tech-stack specific rules (e.g., under `rules/typescript/`) that need to inherit from a `common` rule, it is highly recommended to **use the exact same file name** and explicitly state the inheritance at the top of the file:
|
|
106
|
+
*> This file extends [common/coding-style.md](https://www.google.com/search?q=../common/coding-style.md) with TypeScript specific content.*
|
|
89
107
|
|
|
90
|
-
```bash
|
|
91
|
-
vibe update
|
|
92
|
-
|
|
93
|
-
```
|
|
94
108
|
|
|
95
|
-
**功能**:
|
|
96
|
-
自动执行标准 Skills 的升级,并根据锁文件记录的源仓库,拉取并覆盖最新的本地工具脚本,保持生态环境最新。
|
|
97
109
|
|
|
98
110
|
---
|
|
99
111
|
|
|
100
|
-
## 📂
|
|
112
|
+
## 📂 Workspace Structure
|
|
101
113
|
|
|
102
|
-
|
|
114
|
+
After running `vibe add`, the tool will automatically take over and maintain the following structure in your project's root directory:
|
|
103
115
|
|
|
104
116
|
```text
|
|
105
117
|
your-project/
|
|
106
118
|
├── .opencode/
|
|
107
|
-
│ ├── tool/ #
|
|
108
|
-
│
|
|
109
|
-
│
|
|
110
|
-
│
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
└── requirements.txt # (自动维护) 补充 Python 工具运行所需的核心依赖
|
|
114
|
-
|
|
119
|
+
│ ├── tool/ # Pulled underlying .ts / .py tool scripts
|
|
120
|
+
│ ├── rules/ # Pulled .md rule files (categorized by type)
|
|
121
|
+
│ ├── opencode.jsonc # Core OpenCode config (CLI auto-injects tool switches and paths)
|
|
122
|
+
│ └── vibe-lock.json # State lock file, accurately recording resource sources and versions
|
|
123
|
+
├── .venv/ # (Auto-created as needed) Isolated Python virtual environment
|
|
124
|
+
└── requirements.txt # (Auto-maintained as needed) Python script dependencies
|
|
115
125
|
```
|
|
116
126
|
|
|
117
127
|
---
|
|
118
128
|
|
|
119
|
-
## 🛠️
|
|
129
|
+
## 🛠️ Development
|
|
120
130
|
|
|
121
|
-
|
|
131
|
+
This project is built on top of the lightning-fast [Bun](https://bun.sh/) runtime.
|
|
122
132
|
|
|
123
133
|
```bash
|
|
124
|
-
# 1.
|
|
125
|
-
bun
|
|
126
|
-
|
|
127
|
-
#
|
|
128
|
-
bun run dev --help
|
|
129
|
-
|
|
130
|
-
# 3. 类型检查
|
|
131
|
-
bun run typecheck
|
|
132
|
-
|
|
133
|
-
# 4. 构建生产版本 (输出至 ./dist)
|
|
134
|
-
bun run build
|
|
135
|
-
|
|
134
|
+
bun install # 1. Install dependencies
|
|
135
|
+
bun run dev --help # 2. Local debugging
|
|
136
|
+
bun run typecheck # 3. Type checking
|
|
137
|
+
bun run build # 4. Build production version (outputs to ./dist)
|
|
136
138
|
```
|
|
137
139
|
|
|
138
|
-
## 📄
|
|
140
|
+
## 📄 License
|
|
139
141
|
|
|
140
|
-
|
|
141
|
-
© 2026 [HelloGGX](https://github.com/HelloGGX)
|
|
142
|
+
[MIT License](https://www.google.com/search?q=../../LICENSE.md) © 2026 [HelloGGX](https://github.com/HelloGGX)
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# 🌊 Vibe Coding CLI
|
|
4
|
+
|
|
5
|
+
**专为 OpenCode 打造的 vibe coding 生态构建工具**
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@vibe-coder/cli)
|
|
8
|
+
[](../../LICENSE.md)
|
|
9
|
+
[](https://bun.sh)
|
|
10
|
+
|
|
11
|
+
[English](https://github.com/HelloGGX/skill/blob/main/packages/vibe/README.md) · **简体中文**
|
|
12
|
+
|
|
13
|
+
> *一键聚合 AI 工具与上下文规范,让 Agent 真正懂你的代码架构。*
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
## 📖 简介 (Introduction)
|
|
18
|
+
|
|
19
|
+
`@vibe-coder/cli` 是一个专为 **OpenCode** 平台打造的现代命令行脚手架工具。它的核心目标是快速搭建 Vibe Coding 的开发环境,简化规范驱动开发的资源管理。
|
|
20
|
+
|
|
21
|
+
通过 `vibe` 命令,你可以一键拉取远程 GitHub 仓库中的 TypeScript/Python 工具脚本或 Markdown 规则文件,自动无缝注册到 OpenCode 配置中,并接管底层运行依赖,让你专注于**“与 AI 共创代码”**本身。
|
|
22
|
+
|
|
23
|
+
## ✨ 核心特性 (Features)
|
|
24
|
+
|
|
25
|
+
- 🛠 **全自动化工具管理**: 支持从任意 GitHub 仓库快速解析、多选并下载 `.ts` / `.py` 脚本至本地开箱即用。
|
|
26
|
+
- 📜 **Context 与 Capabilities 完美融合**: 独创生态聚合能力,将 Agent 执行所需的**工具技能**与**行为准则**深度绑定。支持按需安装 `.md` 规则文件,让 AI 真正懂你的架构意图。
|
|
27
|
+
- 📦 **智能配置注入**: 自动拦截并更新 `.opencode/opencode.jsonc`,无感注入工具开关与 Prompt 指令路径,告别繁琐的手动配置。
|
|
28
|
+
- ⚡ **并行极速更新**: 基于并发模型设计,同时处理多个源仓库的资源对比与拉取,大幅缩短更新等待时间。
|
|
29
|
+
- 🪄 **标准技能聚合**: 与 Vercel 的 `pnpx skills` 生态深度集成,在统一的 CLI 流程中同时管理标准 Agent 技能库和本地扩展资源。
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 🚀 快速开始 (Quick Start)
|
|
34
|
+
|
|
35
|
+
### 环境要求 (Prerequisites)
|
|
36
|
+
- [Node.js](https://nodejs.org/) >= 18.0.0 或 [Bun](https://bun.sh/) >= 1.0.0
|
|
37
|
+
|
|
38
|
+
### 安装
|
|
39
|
+
|
|
40
|
+
作为全局包安装:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# 使用 npm
|
|
44
|
+
npm i -g @vibe-coder/cli
|
|
45
|
+
|
|
46
|
+
# 使用 bun
|
|
47
|
+
bun add -g @vibe-coder/cli
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 基础用法
|
|
51
|
+
|
|
52
|
+
初始化并添加一个生态库(例如本项目的 `helloggx/skill`):
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
vibe add helloggx/skill
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
*CLI 将唤起交互式菜单,允许你灵活多选想要安装的 **Tools (工具)** 和 **Rules (规则)**,并自动为你完成所有环境配置。*
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 📚 命令指南 (Commands)
|
|
63
|
+
|
|
64
|
+
| 命令 | 别名 | 功能描述 |
|
|
65
|
+
| --- | --- | --- |
|
|
66
|
+
| `vibe add <repo>` | `a` | 解析目标 GitHub 仓库,唤起 UI 列表,按需安装工具和规则文件,并自动注入配置。 |
|
|
67
|
+
| `vibe list` | `ls` | 清晰打印当前项目中所有已安装资源(本地工具、上下文规则、全局标准技能)的态势图。 |
|
|
68
|
+
| `vibe update` | `up` | 一键并发拉取 `vibe-lock.json` 中的所有源仓库,智能比对并覆盖本地脚本与规则。 |
|
|
69
|
+
| `vibe remove [资源]` | `rm` | **无参运行**:唤起 UI 多选列表删除本地项。<br>
|
|
70
|
+
|
|
71
|
+
<br>**带参运行**:快捷匹配并移除指定的标准技能或本地工具,并同步清理配置。 |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 🏗️ 构建你自己的资源仓库
|
|
76
|
+
|
|
77
|
+
我们强烈鼓励你或团队在 GitHub 上创建专属的 Vibe Coding 资源仓库,以在所有项目中标准化团队最喜欢的 AI 工具和自定义编码规范。
|
|
78
|
+
|
|
79
|
+
### 推荐目录结构
|
|
80
|
+
|
|
81
|
+
为确保与 `@vibe-coder/cli` 完美兼容,推荐采用以下约定(可参考 `helloggx/skill`):
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
your-custom-repo/
|
|
85
|
+
├── skill/ # (可选) 标准的 Vercel AI Agent 技能库
|
|
86
|
+
├── tool/ # 自定义 TS/Python 可执行工具
|
|
87
|
+
│ ├── get_dsl.ts
|
|
88
|
+
│ ├── get_dsl.py # 💡 Python 脚本应与其调用的 TS 工具同名
|
|
89
|
+
│ └── shadcn_vue_init.ts
|
|
90
|
+
└── rules/ # 个性化 Markdown 上下文规则
|
|
91
|
+
├── common/ # 适用于所有项目的全局通用规则
|
|
92
|
+
│ ├── coding-style.md
|
|
93
|
+
│ └── security.md
|
|
94
|
+
└── typescript/ # 特定技术栈规则
|
|
95
|
+
└── coding-style.md # 💡 建议与被扩展的通用规则同名
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 组织最佳实践
|
|
99
|
+
|
|
100
|
+
* **跨语言工具联动**:若你的 `.ts` 工具依赖底层的 `.py` 脚本,**请确保两文件基础名称完全一致**(如 `get_dsl.ts` 和 `get_dsl.py`)。CLI 会智能识别并一并拉取。
|
|
101
|
+
* **规则继承与扩展**:
|
|
102
|
+
* 全局通用规则务必放在 `rules/common/` 下。
|
|
103
|
+
* 为特定技术栈编写规则时(如 `rules/typescript/`),若需继承 `common` 规则,建议**保持同名**,并在文件顶部显式声明继承关系:
|
|
104
|
+
*> 此文件扩展了 [common/coding-style.md](https://www.google.com/search?q=../common/coding-style.md) 并增加了 TS 特定内容。*
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 📂 目录与配置规范 (Workspace Structure)
|
|
111
|
+
|
|
112
|
+
运行 `vibe add` 后,工具将在项目根目录自动接管并维护以下结构:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
your-project/
|
|
116
|
+
├── .opencode/
|
|
117
|
+
│ ├── tool/ # 底层 .ts / .py 工具脚本
|
|
118
|
+
│ ├── rules/ # .md 规则文件(按类别归档)
|
|
119
|
+
│ ├── opencode.jsonc # OpenCode 核心配置(CLI 自动注入工具开关与指令路径)
|
|
120
|
+
│ └── vibe-lock.json # 状态锁文件,精准记录资源来源与版本
|
|
121
|
+
├── .venv/ # (按需自动创建) 隔离的 Python 虚拟环境
|
|
122
|
+
└── requirements.txt # (按需自动维护) Python 脚本依赖清单
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 🛠️ 开发者指南 (Development)
|
|
128
|
+
|
|
129
|
+
本项目基于极速的 [Bun](https://bun.sh/) 运行时构建。
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
bun install # 1. 安装依赖
|
|
133
|
+
bun run dev --help # 2. 本地调试
|
|
134
|
+
bun run typecheck # 3. 类型检查
|
|
135
|
+
bun run build # 4. 构建生产版本 (输出至 ./dist)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## 📄 许可证 (License)
|
|
139
|
+
|
|
140
|
+
[MIT License](https://www.google.com/search?q=../../LICENSE.md) © 2026 [HelloGGX](https://github.com/HelloGGX)
|
package/dist/cli.js
CHANGED
|
@@ -1317,6 +1317,25 @@ class Vt extends x {
|
|
|
1317
1317
|
}
|
|
1318
1318
|
}
|
|
1319
1319
|
}
|
|
1320
|
+
|
|
1321
|
+
class kt extends x {
|
|
1322
|
+
get cursor() {
|
|
1323
|
+
return this.value ? 0 : 1;
|
|
1324
|
+
}
|
|
1325
|
+
get _value() {
|
|
1326
|
+
return this.cursor === 0;
|
|
1327
|
+
}
|
|
1328
|
+
constructor(e) {
|
|
1329
|
+
super(e, false), this.value = !!e.initialValue, this.on("userInput", () => {
|
|
1330
|
+
this.value = this._value;
|
|
1331
|
+
}), this.on("confirm", (s) => {
|
|
1332
|
+
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = s, this.state = "submit", this.close();
|
|
1333
|
+
}), this.on("cursor", () => {
|
|
1334
|
+
this.value = !this.value;
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1320
1339
|
class yt extends x {
|
|
1321
1340
|
options;
|
|
1322
1341
|
cursor = 0;
|
|
@@ -1689,6 +1708,33 @@ var X2 = (t) => {
|
|
|
1689
1708
|
B2.push(w);
|
|
1690
1709
|
return h && B2.push(g), B2;
|
|
1691
1710
|
};
|
|
1711
|
+
var Re = (t) => {
|
|
1712
|
+
const r = t.active ?? "Yes", s = t.inactive ?? "No";
|
|
1713
|
+
return new kt({ active: r, inactive: s, signal: t.signal, input: t.input, output: t.output, initialValue: t.initialValue ?? true, render() {
|
|
1714
|
+
const i = t.withGuide ?? _.withGuide, a = `${i ? `${import_picocolors2.default.gray(d)}
|
|
1715
|
+
` : ""}${W2(this.state)} ${t.message}
|
|
1716
|
+
`, o = this.value ? r : s;
|
|
1717
|
+
switch (this.state) {
|
|
1718
|
+
case "submit": {
|
|
1719
|
+
const u = i ? `${import_picocolors2.default.gray(d)} ` : "";
|
|
1720
|
+
return `${a}${u}${import_picocolors2.default.dim(o)}`;
|
|
1721
|
+
}
|
|
1722
|
+
case "cancel": {
|
|
1723
|
+
const u = i ? `${import_picocolors2.default.gray(d)} ` : "";
|
|
1724
|
+
return `${a}${u}${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(o))}${i ? `
|
|
1725
|
+
${import_picocolors2.default.gray(d)}` : ""}`;
|
|
1726
|
+
}
|
|
1727
|
+
default: {
|
|
1728
|
+
const u = i ? `${import_picocolors2.default.cyan(d)} ` : "", l = i ? import_picocolors2.default.cyan(x2) : "";
|
|
1729
|
+
return `${a}${u}${this.value ? `${import_picocolors2.default.green(Q2)} ${r}` : `${import_picocolors2.default.dim(H2)} ${import_picocolors2.default.dim(r)}`}${t.vertical ? i ? `
|
|
1730
|
+
${import_picocolors2.default.cyan(d)} ` : `
|
|
1731
|
+
` : ` ${import_picocolors2.default.dim("/")} `}${this.value ? `${import_picocolors2.default.dim(H2)} ${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.green(Q2)} ${s}`}
|
|
1732
|
+
${l}
|
|
1733
|
+
`;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
} }).prompt();
|
|
1737
|
+
};
|
|
1692
1738
|
var R2 = { message: (t = [], { symbol: r = import_picocolors2.default.gray(d), secondarySymbol: s = import_picocolors2.default.gray(d), output: i = process.stdout, spacing: a = 1, withGuide: o } = {}) => {
|
|
1693
1739
|
const u = [], l = o ?? _.withGuide, n = l ? s : "", c = l ? `${r} ` : "", g = l ? `${s} ` : "";
|
|
1694
1740
|
for (let p = 0;p < a; p++)
|
|
@@ -1868,10 +1914,10 @@ var bt2 = ({ indicator: t = "dots", onCancel: r, output: s = process.stdout, can
|
|
|
1868
1914
|
var zt = { light: C("─", "-"), heavy: C("━", "="), block: C("█", "#") };
|
|
1869
1915
|
var Qt = `${import_picocolors2.default.gray(d)} `;
|
|
1870
1916
|
|
|
1871
|
-
// src/add.ts
|
|
1872
|
-
import { execSync } from "child_process";
|
|
1873
|
-
import { existsSync, mkdirSync
|
|
1874
|
-
import
|
|
1917
|
+
// src/commands/add.ts
|
|
1918
|
+
import { execSync as execSync2 } from "child_process";
|
|
1919
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync2 } from "fs";
|
|
1920
|
+
import path4 from "path";
|
|
1875
1921
|
|
|
1876
1922
|
// ../../node_modules/.bun/simple-git@3.32.2/node_modules/simple-git/dist/esm/index.js
|
|
1877
1923
|
var import_file_exists = __toESM(require_dist(), 1);
|
|
@@ -5958,6 +6004,10 @@ async function cleanupTempDir(dir) {
|
|
|
5958
6004
|
await rm(dir, { recursive: true, force: true });
|
|
5959
6005
|
}
|
|
5960
6006
|
|
|
6007
|
+
// src/utils/config.ts
|
|
6008
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
6009
|
+
import path from "path";
|
|
6010
|
+
|
|
5961
6011
|
// src/constants.ts
|
|
5962
6012
|
var OPENCODE_DIR = ".opencode";
|
|
5963
6013
|
var TOOL_SUBDIR = "tool";
|
|
@@ -5973,7 +6023,29 @@ var YELLOW = "\x1B[33m";
|
|
|
5973
6023
|
var DIM = "\x1B[38;5;102m";
|
|
5974
6024
|
var TEXT = "\x1B[38;5;145m";
|
|
5975
6025
|
|
|
5976
|
-
// src/
|
|
6026
|
+
// src/utils/error.ts
|
|
6027
|
+
function handleExecError(error, context, severity = "warn" /* WARN */) {
|
|
6028
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6029
|
+
const formatted = `${context}
|
|
6030
|
+
${YELLOW}${message}${RESET}`;
|
|
6031
|
+
switch (severity) {
|
|
6032
|
+
case "error" /* ERROR */:
|
|
6033
|
+
R2.error(formatted);
|
|
6034
|
+
process.exit(1);
|
|
6035
|
+
case "warn" /* WARN */:
|
|
6036
|
+
R2.warn(formatted);
|
|
6037
|
+
break;
|
|
6038
|
+
default:
|
|
6039
|
+
R2.info(formatted);
|
|
6040
|
+
}
|
|
6041
|
+
}
|
|
6042
|
+
|
|
6043
|
+
// src/utils/config.ts
|
|
6044
|
+
function parseJsonc(content) {
|
|
6045
|
+
let safeJsonStr = content.replace(/"(?:\\.|[^"\\])*"|\/\/[^\n]*|\/\*[\s\S]*?\*\//g, (m) => m.startsWith('"') ? m : "");
|
|
6046
|
+
safeJsonStr = safeJsonStr.replace(/,\s*([\]}])/g, "$1");
|
|
6047
|
+
return JSON.parse(safeJsonStr);
|
|
6048
|
+
}
|
|
5977
6049
|
function getLockFilePath() {
|
|
5978
6050
|
return path.join(process.cwd(), OPENCODE_DIR, LOCK_FILE);
|
|
5979
6051
|
}
|
|
@@ -5984,6 +6056,8 @@ function readLockFile() {
|
|
|
5984
6056
|
const parsed = JSON.parse(readFileSync(lockPath, "utf-8"));
|
|
5985
6057
|
if (!parsed.rules)
|
|
5986
6058
|
parsed.rules = {};
|
|
6059
|
+
if (!parsed.tools)
|
|
6060
|
+
parsed.tools = {};
|
|
5987
6061
|
return parsed;
|
|
5988
6062
|
}
|
|
5989
6063
|
} catch (e2) {}
|
|
@@ -6016,138 +6090,174 @@ function ensureOpencodeConfig() {
|
|
|
6016
6090
|
writeFileSync(configPath, jsoncContent, "utf-8");
|
|
6017
6091
|
}
|
|
6018
6092
|
}
|
|
6019
|
-
function
|
|
6020
|
-
if (newTools.length === 0)
|
|
6093
|
+
function updateOpencodeConfig(newTools, newRulePaths) {
|
|
6094
|
+
if (newTools.length === 0 && newRulePaths.length === 0)
|
|
6021
6095
|
return;
|
|
6022
6096
|
const configPath = path.join(process.cwd(), OPENCODE_DIR, CONFIG_FILE);
|
|
6023
6097
|
if (!existsSync(configPath))
|
|
6024
6098
|
return;
|
|
6025
6099
|
try {
|
|
6026
6100
|
const content = readFileSync(configPath, "utf-8");
|
|
6027
|
-
|
|
6028
|
-
safeJsonStr = safeJsonStr.replace(/,\s*([\]}])/g, "$1");
|
|
6029
|
-
const config = JSON.parse(safeJsonStr);
|
|
6030
|
-
config.tools = config.tools || {};
|
|
6101
|
+
const config = parseJsonc(content);
|
|
6031
6102
|
let updated = false;
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6103
|
+
if (newTools.length > 0) {
|
|
6104
|
+
config.tools = config.tools || {};
|
|
6105
|
+
for (const tool of newTools) {
|
|
6106
|
+
if (!config.tools[tool]) {
|
|
6107
|
+
config.tools[tool] = true;
|
|
6108
|
+
updated = true;
|
|
6109
|
+
}
|
|
6110
|
+
}
|
|
6111
|
+
}
|
|
6112
|
+
if (newRulePaths.length > 0) {
|
|
6113
|
+
config.instructions = config.instructions || [];
|
|
6114
|
+
for (const rulePath of newRulePaths) {
|
|
6115
|
+
if (!config.instructions.includes(rulePath)) {
|
|
6116
|
+
config.instructions.push(rulePath);
|
|
6117
|
+
updated = true;
|
|
6118
|
+
}
|
|
6036
6119
|
}
|
|
6037
6120
|
}
|
|
6038
6121
|
if (updated)
|
|
6039
6122
|
writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
6040
6123
|
} catch (e2) {
|
|
6041
|
-
|
|
6042
|
-
${YELLOW}Warning: Failed to inject tools into opencode.jsonc. ${e2.message}${RESET}`);
|
|
6124
|
+
handleExecError(e2, "Failed to update opencode.jsonc", "warn" /* WARN */);
|
|
6043
6125
|
}
|
|
6044
6126
|
}
|
|
6045
|
-
function
|
|
6046
|
-
if (
|
|
6127
|
+
function removeOpencodeConfig(toolsToRemove, rulesToRemove) {
|
|
6128
|
+
if (toolsToRemove.length === 0 && rulesToRemove.length === 0)
|
|
6047
6129
|
return;
|
|
6048
6130
|
const configPath = path.join(process.cwd(), OPENCODE_DIR, CONFIG_FILE);
|
|
6049
6131
|
if (!existsSync(configPath))
|
|
6050
6132
|
return;
|
|
6051
6133
|
try {
|
|
6052
6134
|
const content = readFileSync(configPath, "utf-8");
|
|
6053
|
-
|
|
6054
|
-
safeJsonStr = safeJsonStr.replace(/,\s*([\]}])/g, "$1");
|
|
6055
|
-
const config = JSON.parse(safeJsonStr);
|
|
6056
|
-
config.instructions = config.instructions || [];
|
|
6135
|
+
const config = parseJsonc(content);
|
|
6057
6136
|
let updated = false;
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
config.
|
|
6137
|
+
if (toolsToRemove.length > 0 && config.tools) {
|
|
6138
|
+
for (const tool of toolsToRemove) {
|
|
6139
|
+
if (tool in config.tools) {
|
|
6140
|
+
delete config.tools[tool];
|
|
6141
|
+
updated = true;
|
|
6142
|
+
}
|
|
6143
|
+
}
|
|
6144
|
+
}
|
|
6145
|
+
if (rulesToRemove.length > 0 && config.instructions) {
|
|
6146
|
+
const originalLength = config.instructions.length;
|
|
6147
|
+
config.instructions = config.instructions.filter((inst) => {
|
|
6148
|
+
return !rulesToRemove.some((rule) => inst.includes(`/${RULES_SUBDIR}/${rule}/`));
|
|
6149
|
+
});
|
|
6150
|
+
if (config.instructions.length !== originalLength) {
|
|
6061
6151
|
updated = true;
|
|
6062
6152
|
}
|
|
6063
6153
|
}
|
|
6064
6154
|
if (updated)
|
|
6065
6155
|
writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
6066
6156
|
} catch (e2) {
|
|
6067
|
-
|
|
6068
|
-
${YELLOW}Warning: Failed to inject instructions into opencode.jsonc. ${e2.message}${RESET}`);
|
|
6157
|
+
handleExecError(e2, "Failed to remove items from opencode.jsonc", "warn" /* WARN */);
|
|
6069
6158
|
}
|
|
6070
6159
|
}
|
|
6160
|
+
|
|
6161
|
+
// src/utils/file.ts
|
|
6162
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, cpSync, readdirSync, rmSync } from "fs";
|
|
6163
|
+
import path2 from "path";
|
|
6071
6164
|
function copyToolFiles(toolName, sourceDir, targetDir) {
|
|
6072
6165
|
let hasPython = false;
|
|
6073
6166
|
const tsFile = `${toolName}.ts`;
|
|
6074
6167
|
const pyFile = `${toolName}.py`;
|
|
6075
|
-
const srcTs =
|
|
6076
|
-
if (
|
|
6077
|
-
cpSync(srcTs,
|
|
6078
|
-
const srcPy =
|
|
6079
|
-
if (
|
|
6080
|
-
cpSync(srcPy,
|
|
6168
|
+
const srcTs = path2.join(sourceDir, tsFile);
|
|
6169
|
+
if (existsSync2(srcTs))
|
|
6170
|
+
cpSync(srcTs, path2.join(targetDir, tsFile), { recursive: true });
|
|
6171
|
+
const srcPy = path2.join(sourceDir, pyFile);
|
|
6172
|
+
if (existsSync2(srcPy)) {
|
|
6173
|
+
cpSync(srcPy, path2.join(targetDir, pyFile), { recursive: true });
|
|
6081
6174
|
hasPython = true;
|
|
6082
6175
|
}
|
|
6083
6176
|
return hasPython;
|
|
6084
6177
|
}
|
|
6085
6178
|
function installRules(categories, rulesSourceDir, targetRulesDir) {
|
|
6086
|
-
if (!
|
|
6087
|
-
|
|
6179
|
+
if (!existsSync2(targetRulesDir))
|
|
6180
|
+
mkdirSync2(targetRulesDir, { recursive: true });
|
|
6088
6181
|
const installedRulePaths = [];
|
|
6089
|
-
const
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
const files = readdirSync(commonSource).filter((f) => f.endsWith(".md"));
|
|
6095
|
-
for (const file of files) {
|
|
6096
|
-
cpSync(path.join(commonSource, file), path.join(commonTarget, file));
|
|
6097
|
-
installedRulePaths.push(`./${RULES_SUBDIR}/common/${file}`);
|
|
6098
|
-
}
|
|
6099
|
-
}
|
|
6100
|
-
for (const category of categories) {
|
|
6101
|
-
const catSource = path.join(rulesSourceDir, category);
|
|
6102
|
-
const catTarget = path.join(targetRulesDir, category);
|
|
6103
|
-
if (existsSync(catSource)) {
|
|
6104
|
-
if (!existsSync(catTarget))
|
|
6105
|
-
mkdirSync(catTarget, { recursive: true });
|
|
6106
|
-
const files = readdirSync(catSource).filter((f) => f.endsWith(".md"));
|
|
6182
|
+
const copyDir = (srcFolder, targetFolder, relativePathPrefix) => {
|
|
6183
|
+
if (existsSync2(srcFolder)) {
|
|
6184
|
+
if (!existsSync2(targetFolder))
|
|
6185
|
+
mkdirSync2(targetFolder, { recursive: true });
|
|
6186
|
+
const files = readdirSync(srcFolder).filter((f) => f.endsWith(".md"));
|
|
6107
6187
|
for (const file of files) {
|
|
6108
|
-
cpSync(
|
|
6109
|
-
installedRulePaths.push(`./${RULES_SUBDIR}/${
|
|
6188
|
+
cpSync(path2.join(srcFolder, file), path2.join(targetFolder, file));
|
|
6189
|
+
installedRulePaths.push(`./${RULES_SUBDIR}/${relativePathPrefix}/${file}`);
|
|
6110
6190
|
}
|
|
6111
6191
|
}
|
|
6192
|
+
};
|
|
6193
|
+
copyDir(path2.join(rulesSourceDir, "common"), path2.join(targetRulesDir, "common"), "common");
|
|
6194
|
+
for (const category of categories) {
|
|
6195
|
+
copyDir(path2.join(rulesSourceDir, category), path2.join(targetRulesDir, category), category);
|
|
6112
6196
|
}
|
|
6113
6197
|
return installedRulePaths;
|
|
6114
6198
|
}
|
|
6199
|
+
function removeToolFiles(toolName, targetDir) {
|
|
6200
|
+
const tsFile = path2.join(targetDir, `${toolName}.ts`);
|
|
6201
|
+
const pyFile = path2.join(targetDir, `${toolName}.py`);
|
|
6202
|
+
if (existsSync2(tsFile))
|
|
6203
|
+
rmSync(tsFile, { force: true });
|
|
6204
|
+
if (existsSync2(pyFile))
|
|
6205
|
+
rmSync(pyFile, { force: true });
|
|
6206
|
+
}
|
|
6207
|
+
function removeRuleCategory(category, targetRulesDir) {
|
|
6208
|
+
const catDir = path2.join(targetRulesDir, category);
|
|
6209
|
+
if (existsSync2(catDir)) {
|
|
6210
|
+
rmSync(catDir, { recursive: true, force: true });
|
|
6211
|
+
}
|
|
6212
|
+
}
|
|
6213
|
+
|
|
6214
|
+
// src/utils/python.ts
|
|
6215
|
+
import { execSync } from "child_process";
|
|
6216
|
+
import { existsSync as existsSync3, writeFileSync as writeFileSync2, readFileSync as readFileSync2 } from "fs";
|
|
6217
|
+
import path3 from "path";
|
|
6115
6218
|
function setupPythonEnvironment(rootDir, spinner) {
|
|
6116
6219
|
spinner.message(`Initializing Python environment in ./.venv ...`);
|
|
6117
6220
|
try {
|
|
6118
|
-
const reqPath =
|
|
6221
|
+
const reqPath = path3.join(rootDir, "requirements.txt");
|
|
6119
6222
|
const reqContent = `# 核心依赖
|
|
6120
6223
|
requests>=2.28.0
|
|
6121
6224
|
urllib3>=1.26.0
|
|
6122
6225
|
python-dotenv>=0.19.0
|
|
6123
6226
|
`;
|
|
6124
|
-
if (!
|
|
6125
|
-
|
|
6227
|
+
if (!existsSync3(reqPath)) {
|
|
6228
|
+
writeFileSync2(reqPath, reqContent, "utf-8");
|
|
6126
6229
|
} else {
|
|
6127
|
-
const existingReq =
|
|
6230
|
+
const existingReq = readFileSync2(reqPath, "utf-8");
|
|
6128
6231
|
if (!existingReq.includes("requests>="))
|
|
6129
|
-
|
|
6232
|
+
writeFileSync2(reqPath, existingReq + `
|
|
6130
6233
|
` + reqContent, "utf-8");
|
|
6131
6234
|
}
|
|
6132
|
-
const venvPath =
|
|
6133
|
-
if (!
|
|
6235
|
+
const venvPath = path3.join(rootDir, ".venv");
|
|
6236
|
+
if (!existsSync3(venvPath)) {
|
|
6134
6237
|
try {
|
|
6135
6238
|
execSync(`python3 -m venv "${venvPath}"`, { stdio: "ignore" });
|
|
6136
6239
|
} catch {
|
|
6137
6240
|
execSync(`python -m venv "${venvPath}"`, { stdio: "ignore" });
|
|
6138
6241
|
}
|
|
6139
6242
|
}
|
|
6140
|
-
const pipCmd = process.platform === "win32" ?
|
|
6243
|
+
const pipCmd = process.platform === "win32" ? path3.join(venvPath, "Scripts", "pip") : path3.join(venvPath, "bin", "pip");
|
|
6141
6244
|
spinner.message(`Installing Python dependencies...`);
|
|
6142
6245
|
execSync(`"${pipCmd}" install -r "${reqPath}"`, { stdio: "ignore" });
|
|
6143
6246
|
} catch (pyError) {
|
|
6144
|
-
|
|
6247
|
+
spinner.stop();
|
|
6248
|
+
handleExecError(pyError, "Failed to initialize Python environment. Manual setup required.", "warn" /* WARN */);
|
|
6145
6249
|
}
|
|
6146
6250
|
}
|
|
6251
|
+
function getPythonActivationCmd() {
|
|
6252
|
+
const isWin = process.platform === "win32";
|
|
6253
|
+
return isWin ? ".\\.venv\\Scripts\\Activate.ps1" : "source .venv/bin/activate";
|
|
6254
|
+
}
|
|
6255
|
+
|
|
6256
|
+
// src/commands/add.ts
|
|
6147
6257
|
async function runAdd(args) {
|
|
6148
6258
|
const repository = args[0];
|
|
6149
6259
|
if (!repository) {
|
|
6150
|
-
|
|
6260
|
+
handleExecError(new Error("Repository name is missing"), "Argument Error", "error" /* ERROR */);
|
|
6151
6261
|
process.exit(1);
|
|
6152
6262
|
}
|
|
6153
6263
|
const repoUrl = `https://github.com/${repository}.git`;
|
|
@@ -6156,9 +6266,9 @@ async function runAdd(args) {
|
|
|
6156
6266
|
Target: ${CYAN}${OPENCODE_DIR}${RESET}`, "Initializing");
|
|
6157
6267
|
R2.step("Executing standard skills installer (pnpx skills add)...");
|
|
6158
6268
|
try {
|
|
6159
|
-
|
|
6160
|
-
} catch {
|
|
6161
|
-
|
|
6269
|
+
execSync2(`pnpx skills add ${repository} --agent opencode`, { stdio: "inherit" });
|
|
6270
|
+
} catch (err) {
|
|
6271
|
+
handleExecError(err, "Skills installer finished with warnings", "warn" /* WARN */);
|
|
6162
6272
|
}
|
|
6163
6273
|
const s = bt2();
|
|
6164
6274
|
s.start("Fetching remote repository...");
|
|
@@ -6166,89 +6276,85 @@ Target: ${CYAN}${OPENCODE_DIR}${RESET}`, "Initializing");
|
|
|
6166
6276
|
try {
|
|
6167
6277
|
tempDir = await cloneRepo(repoUrl);
|
|
6168
6278
|
s.stop("Remote repository parsed.");
|
|
6169
|
-
const toolDirPath =
|
|
6170
|
-
const rulesDirPath =
|
|
6171
|
-
const hasTools =
|
|
6172
|
-
const hasRules =
|
|
6173
|
-
if (!hasTools && !hasRules)
|
|
6174
|
-
return
|
|
6175
|
-
}
|
|
6279
|
+
const toolDirPath = path4.join(tempDir, "tool");
|
|
6280
|
+
const rulesDirPath = path4.join(tempDir, "rules");
|
|
6281
|
+
const hasTools = existsSync4(toolDirPath);
|
|
6282
|
+
const hasRules = existsSync4(rulesDirPath);
|
|
6283
|
+
if (!hasTools && !hasRules)
|
|
6284
|
+
return handleExecError(new Error(`Neither "tool' nor "rules' directory found in repository.`), "warn" /* WARN */);
|
|
6176
6285
|
let selectedTools = [];
|
|
6177
6286
|
let selectedRules = [];
|
|
6178
6287
|
if (hasTools) {
|
|
6179
|
-
const
|
|
6180
|
-
if (
|
|
6181
|
-
const
|
|
6288
|
+
const opts = readdirSync2(toolDirPath).filter((f) => f.endsWith(".ts")).map((f) => f.replace(/\.ts$/, ""));
|
|
6289
|
+
if (opts.length > 0) {
|
|
6290
|
+
const res = await je({
|
|
6182
6291
|
message: "Select tools to install (space to toggle)",
|
|
6183
|
-
options:
|
|
6292
|
+
options: opts.map((t) => ({ value: t, label: t })),
|
|
6184
6293
|
required: false
|
|
6185
6294
|
});
|
|
6186
|
-
if (Ct(
|
|
6295
|
+
if (Ct(res))
|
|
6187
6296
|
return Ne("Installation cancelled.");
|
|
6188
|
-
if (Array.isArray(
|
|
6189
|
-
selectedTools =
|
|
6297
|
+
if (Array.isArray(res))
|
|
6298
|
+
selectedTools = res;
|
|
6190
6299
|
}
|
|
6191
6300
|
}
|
|
6192
6301
|
if (hasRules) {
|
|
6193
|
-
const
|
|
6194
|
-
if (
|
|
6195
|
-
const
|
|
6196
|
-
message: "Select rule categories to install
|
|
6197
|
-
options:
|
|
6302
|
+
const opts = readdirSync2(rulesDirPath, { withFileTypes: true }).filter((d2) => d2.isDirectory() && d2.name !== "common").map((d2) => d2.name);
|
|
6303
|
+
if (opts.length > 0) {
|
|
6304
|
+
const res = await je({
|
|
6305
|
+
message: "Select rule categories to install",
|
|
6306
|
+
options: opts.map((r) => ({ value: r, label: r })),
|
|
6198
6307
|
required: false
|
|
6199
6308
|
});
|
|
6200
|
-
if (Ct(
|
|
6309
|
+
if (Ct(res))
|
|
6201
6310
|
return Ne("Installation cancelled.");
|
|
6202
|
-
if (Array.isArray(
|
|
6203
|
-
selectedRules =
|
|
6311
|
+
if (Array.isArray(res))
|
|
6312
|
+
selectedRules = res;
|
|
6204
6313
|
}
|
|
6205
6314
|
}
|
|
6206
|
-
if (selectedTools.length === 0 && selectedRules.length === 0)
|
|
6207
|
-
Ne("No tools or rules selected.");
|
|
6208
|
-
return;
|
|
6209
|
-
}
|
|
6315
|
+
if (selectedTools.length === 0 && selectedRules.length === 0)
|
|
6316
|
+
return Ne("No tools or rules selected.");
|
|
6210
6317
|
const installSpinner = bt2();
|
|
6211
6318
|
installSpinner.start(`Installing to ${OPENCODE_DIR}/ ...`);
|
|
6319
|
+
ensureOpencodeConfig();
|
|
6212
6320
|
const lockData = readLockFile();
|
|
6213
6321
|
const now = new Date().toISOString();
|
|
6214
6322
|
let requiresPython = false;
|
|
6215
|
-
|
|
6323
|
+
let installedRulePaths = [];
|
|
6216
6324
|
if (selectedTools.length > 0) {
|
|
6217
|
-
const targetToolDir =
|
|
6218
|
-
if (!
|
|
6219
|
-
|
|
6325
|
+
const targetToolDir = path4.join(process.cwd(), OPENCODE_DIR, TOOL_SUBDIR);
|
|
6326
|
+
if (!existsSync4(targetToolDir))
|
|
6327
|
+
mkdirSync3(targetToolDir, { recursive: true });
|
|
6220
6328
|
for (const tool of selectedTools) {
|
|
6221
|
-
|
|
6222
|
-
if (hasPy)
|
|
6329
|
+
if (copyToolFiles(tool, toolDirPath, targetToolDir))
|
|
6223
6330
|
requiresPython = true;
|
|
6224
6331
|
if (lockData.tools)
|
|
6225
6332
|
lockData.tools[tool] = { source: repoUrl, installedAt: now };
|
|
6226
6333
|
}
|
|
6227
|
-
updateOpencodeConfigTools(selectedTools);
|
|
6228
6334
|
}
|
|
6229
6335
|
if (selectedRules.length > 0) {
|
|
6230
|
-
const targetRulesDir =
|
|
6231
|
-
|
|
6336
|
+
const targetRulesDir = path4.join(process.cwd(), OPENCODE_DIR, RULES_SUBDIR);
|
|
6337
|
+
installedRulePaths = installRules(selectedRules, rulesDirPath, targetRulesDir);
|
|
6232
6338
|
for (const rule of selectedRules) {
|
|
6233
6339
|
if (!lockData.rules)
|
|
6234
6340
|
lockData.rules = {};
|
|
6235
6341
|
lockData.rules[rule] = { source: repoUrl, installedAt: now };
|
|
6236
6342
|
}
|
|
6237
|
-
updateOpencodeConfigInstructions(installedRulePaths);
|
|
6238
6343
|
}
|
|
6344
|
+
updateOpencodeConfig(selectedTools, installedRulePaths);
|
|
6239
6345
|
writeLockFile(lockData);
|
|
6240
|
-
if (requiresPython)
|
|
6346
|
+
if (requiresPython)
|
|
6241
6347
|
setupPythonEnvironment(process.cwd(), installSpinner);
|
|
6348
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
6349
|
+
installSpinner.stop(`${GREEN}Successfully installed ${selectedTools.length + selectedRules.length} items.${RESET}`);
|
|
6350
|
+
if (requiresPython) {
|
|
6351
|
+
Ve(`Your Python tools are ready. Run:
|
|
6352
|
+
|
|
6353
|
+
${CYAN}${getPythonActivationCmd()}${RESET}`, "\uD83D\uDC0D Python Environment");
|
|
6242
6354
|
}
|
|
6243
|
-
const totalInstalled = selectedTools.length + selectedRules.length;
|
|
6244
|
-
installSpinner.stop(`${GREEN}Successfully installed ${totalInstalled} items.${RESET}`);
|
|
6245
6355
|
} catch (error) {
|
|
6246
6356
|
s.stop("Failed to fetch repository.");
|
|
6247
|
-
|
|
6248
|
-
R2.error(`${YELLOW}Git Error:${RESET}
|
|
6249
|
-
${error.message}`);
|
|
6250
|
-
else
|
|
6251
|
-
R2.error(`Error: ${error.message}`);
|
|
6357
|
+
handleExecError(error, "Repository Fetch Error", "error" /* ERROR */);
|
|
6252
6358
|
} finally {
|
|
6253
6359
|
if (tempDir)
|
|
6254
6360
|
await cleanupTempDir(tempDir).catch(() => {});
|
|
@@ -6256,57 +6362,48 @@ ${error.message}`);
|
|
|
6256
6362
|
Le(`✨ Workspace updated for ${CYAN}${OPENCODE_DIR}${RESET}`);
|
|
6257
6363
|
}
|
|
6258
6364
|
|
|
6259
|
-
// src/list.ts
|
|
6260
|
-
import { execSync as
|
|
6365
|
+
// src/commands/list.ts
|
|
6366
|
+
import { execSync as execSync3 } from "child_process";
|
|
6261
6367
|
async function runList(args) {
|
|
6262
6368
|
const lockData = readLockFile();
|
|
6263
6369
|
console.log(`
|
|
6264
6370
|
${BOLD}\uD83D\uDEE0️ Installed Tools (${OPENCODE_DIR}/${TOOL_SUBDIR}):${RESET}
|
|
6265
6371
|
`);
|
|
6266
6372
|
const tools = Object.keys(lockData.tools || {});
|
|
6267
|
-
if (tools.length === 0)
|
|
6373
|
+
if (tools.length === 0)
|
|
6268
6374
|
console.log(` ${DIM}No tools installed yet.${RESET}`);
|
|
6269
|
-
|
|
6270
|
-
tools.forEach((t) => {
|
|
6271
|
-
const source = lockData.tools[t]?.source || "unknown";
|
|
6272
|
-
console.log(` ${CYAN}◆${RESET} ${t} ${DIM}(${source})${RESET}`);
|
|
6273
|
-
});
|
|
6274
|
-
}
|
|
6375
|
+
else
|
|
6376
|
+
tools.forEach((t) => console.log(` ${CYAN}◆${RESET} ${t} ${DIM}(${lockData.tools[t]?.source || "unknown"})${RESET}`));
|
|
6275
6377
|
console.log(`
|
|
6276
6378
|
${BOLD}\uD83D\uDCDC Installed Rules (${OPENCODE_DIR}/${RULES_SUBDIR}):${RESET}
|
|
6277
6379
|
`);
|
|
6278
6380
|
const rules = Object.keys(lockData.rules || {});
|
|
6279
|
-
if (rules.length === 0)
|
|
6381
|
+
if (rules.length === 0)
|
|
6280
6382
|
console.log(` ${DIM}No rules installed yet.${RESET}`);
|
|
6281
|
-
|
|
6282
|
-
rules.forEach((r) => {
|
|
6283
|
-
const source = lockData.rules[r]?.source || "unknown";
|
|
6284
|
-
console.log(` ${CYAN}◆${RESET} ${r} ${DIM}(${source})${RESET}`);
|
|
6285
|
-
});
|
|
6286
|
-
}
|
|
6383
|
+
else
|
|
6384
|
+
rules.forEach((r) => console.log(` ${CYAN}◆${RESET} ${r} ${DIM}(${lockData.rules[r]?.source || "unknown"})${RESET}`));
|
|
6287
6385
|
console.log(`
|
|
6288
6386
|
${BOLD}\uD83E\uDE84 Installed Skills (Standard):${RESET}
|
|
6289
6387
|
`);
|
|
6290
6388
|
try {
|
|
6291
|
-
|
|
6389
|
+
execSync3("pnpx skills ls", { stdio: "inherit" });
|
|
6292
6390
|
} catch (error) {
|
|
6293
|
-
|
|
6391
|
+
handleExecError(error, "No standard skills found or failed to fetch", "warn" /* WARN */);
|
|
6294
6392
|
}
|
|
6295
|
-
console.log();
|
|
6296
6393
|
}
|
|
6297
6394
|
|
|
6298
|
-
// src/update.ts
|
|
6299
|
-
import { execSync as
|
|
6300
|
-
import { existsSync as
|
|
6301
|
-
import
|
|
6395
|
+
// src/commands/update.ts
|
|
6396
|
+
import { execSync as execSync4 } from "child_process";
|
|
6397
|
+
import { existsSync as existsSync5 } from "fs";
|
|
6398
|
+
import path5 from "path";
|
|
6302
6399
|
async function runUpdate(args) {
|
|
6303
6400
|
console.log(`
|
|
6304
6401
|
${BOLD}\uD83E\uDE84 Updating Standard Skills...${RESET}
|
|
6305
6402
|
`);
|
|
6306
6403
|
try {
|
|
6307
|
-
|
|
6404
|
+
execSync4("pnpx skills update", { stdio: "inherit" });
|
|
6308
6405
|
} catch (error) {
|
|
6309
|
-
|
|
6406
|
+
handleExecError(error, "Failed to update standard skills", "warn" /* WARN */);
|
|
6310
6407
|
}
|
|
6311
6408
|
console.log(`
|
|
6312
6409
|
${BOLD}\uD83D\uDCE6 Updating Local Tools & Rules...${RESET}
|
|
@@ -6315,73 +6412,174 @@ ${BOLD}\uD83D\uDCE6 Updating Local Tools & Rules...${RESET}
|
|
|
6315
6412
|
const toolNames = Object.keys(lockData.tools || {});
|
|
6316
6413
|
const ruleNames = Object.keys(lockData.rules || {});
|
|
6317
6414
|
if (toolNames.length === 0 && ruleNames.length === 0) {
|
|
6318
|
-
console.log(` ${DIM}No local
|
|
6415
|
+
return console.log(` ${DIM}No local items to update.${RESET}
|
|
6319
6416
|
`);
|
|
6320
|
-
return;
|
|
6321
6417
|
}
|
|
6322
6418
|
const itemsBySource = {};
|
|
6323
6419
|
toolNames.forEach((t) => {
|
|
6324
|
-
const
|
|
6325
|
-
if (
|
|
6326
|
-
itemsBySource[
|
|
6327
|
-
itemsBySource[
|
|
6420
|
+
const s2 = lockData.tools[t]?.source;
|
|
6421
|
+
if (s2) {
|
|
6422
|
+
itemsBySource[s2] = itemsBySource[s2] || { tools: [], rules: [] };
|
|
6423
|
+
itemsBySource[s2].tools.push(t);
|
|
6328
6424
|
}
|
|
6329
6425
|
});
|
|
6330
6426
|
ruleNames.forEach((r) => {
|
|
6331
|
-
const
|
|
6332
|
-
if (
|
|
6333
|
-
itemsBySource[
|
|
6334
|
-
itemsBySource[
|
|
6427
|
+
const s2 = lockData.rules[r]?.source;
|
|
6428
|
+
if (s2) {
|
|
6429
|
+
itemsBySource[s2] = itemsBySource[s2] || { tools: [], rules: [] };
|
|
6430
|
+
itemsBySource[s2].rules.push(r);
|
|
6335
6431
|
}
|
|
6336
6432
|
});
|
|
6337
|
-
const targetToolDir =
|
|
6338
|
-
const targetRulesDir =
|
|
6433
|
+
const targetToolDir = path5.join(process.cwd(), OPENCODE_DIR, TOOL_SUBDIR);
|
|
6434
|
+
const targetRulesDir = path5.join(process.cwd(), OPENCODE_DIR, RULES_SUBDIR);
|
|
6339
6435
|
const now = new Date().toISOString();
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6436
|
+
const sourcesCount = Object.keys(itemsBySource).length;
|
|
6437
|
+
const s = bt2();
|
|
6438
|
+
s.start(`Fetching from ${CYAN}${sourcesCount}${RESET} source(s) concurrently...`);
|
|
6439
|
+
const updatePromises = Object.entries(itemsBySource).map(async ([source, items]) => {
|
|
6344
6440
|
let tempDir = null;
|
|
6441
|
+
let successCount = 0;
|
|
6442
|
+
const logs = [];
|
|
6345
6443
|
try {
|
|
6346
6444
|
tempDir = await cloneRepo(source);
|
|
6347
|
-
if (items.tools.length > 0) {
|
|
6348
|
-
const
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
successCount++;
|
|
6355
|
-
console.log(` ${GREEN}✓${RESET} Updated tool: ${tool}`);
|
|
6356
|
-
}
|
|
6445
|
+
if (items.tools.length > 0 && existsSync5(path5.join(tempDir, "tool"))) {
|
|
6446
|
+
for (const tool of items.tools) {
|
|
6447
|
+
copyToolFiles(tool, path5.join(tempDir, "tool"), targetToolDir);
|
|
6448
|
+
if (lockData.tools[tool])
|
|
6449
|
+
lockData.tools[tool].installedAt = now;
|
|
6450
|
+
successCount++;
|
|
6451
|
+
logs.push(` ${GREEN}✓${RESET} Updated tool: ${tool}`);
|
|
6357
6452
|
}
|
|
6358
6453
|
}
|
|
6359
|
-
if (items.rules.length > 0) {
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
successCount++;
|
|
6367
|
-
console.log(` ${GREEN}✓${RESET} Updated rule: ${rule}`);
|
|
6368
|
-
}
|
|
6454
|
+
if (items.rules.length > 0 && existsSync5(path5.join(tempDir, "rules"))) {
|
|
6455
|
+
installRules(items.rules, path5.join(tempDir, "rules"), targetRulesDir);
|
|
6456
|
+
for (const rule of items.rules) {
|
|
6457
|
+
if (lockData.rules[rule])
|
|
6458
|
+
lockData.rules[rule].installedAt = now;
|
|
6459
|
+
successCount++;
|
|
6460
|
+
logs.push(` ${GREEN}✓${RESET} Updated rule: ${rule}`);
|
|
6369
6461
|
}
|
|
6370
6462
|
}
|
|
6371
|
-
|
|
6463
|
+
return { source, success: true, count: successCount, logs };
|
|
6372
6464
|
} catch (err) {
|
|
6373
|
-
|
|
6465
|
+
return { source, success: false, count: 0, error: err, logs: [] };
|
|
6374
6466
|
} finally {
|
|
6375
6467
|
if (tempDir)
|
|
6376
6468
|
await cleanupTempDir(tempDir).catch(() => {});
|
|
6377
6469
|
}
|
|
6470
|
+
});
|
|
6471
|
+
const results = await Promise.allSettled(updatePromises);
|
|
6472
|
+
s.stop(`Finished fetching from ${sourcesCount} source(s).`);
|
|
6473
|
+
let totalSuccessCount = 0;
|
|
6474
|
+
for (const result of results) {
|
|
6475
|
+
if (result.status === "fulfilled") {
|
|
6476
|
+
const { source, success, count, logs, error } = result.value;
|
|
6477
|
+
if (success) {
|
|
6478
|
+
totalSuccessCount += count;
|
|
6479
|
+
logs.forEach((log) => console.log(log));
|
|
6480
|
+
} else {
|
|
6481
|
+
handleExecError(error, `Failed to fetch from ${source}`, "warn" /* WARN */);
|
|
6482
|
+
}
|
|
6483
|
+
} else {
|
|
6484
|
+
handleExecError(result.reason, "Unexpected error during concurrent update", "error" /* ERROR */);
|
|
6485
|
+
}
|
|
6378
6486
|
}
|
|
6379
6487
|
writeLockFile(lockData);
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6488
|
+
if (totalSuccessCount > 0) {
|
|
6489
|
+
console.log(`${TEXT}✓ Successfully updated ${totalSuccessCount} local item(s)${RESET}
|
|
6490
|
+
`);
|
|
6383
6491
|
}
|
|
6384
|
-
|
|
6492
|
+
}
|
|
6493
|
+
|
|
6494
|
+
// src/commands/remove.ts
|
|
6495
|
+
import { execSync as execSync5 } from "child_process";
|
|
6496
|
+
import path6 from "path";
|
|
6497
|
+
async function runRemove(args) {
|
|
6498
|
+
We(`${BG_CYAN} vibe cli ${RESET}`);
|
|
6499
|
+
R2.step("Executing standard skills remover (pnpx skills remove)...");
|
|
6500
|
+
try {
|
|
6501
|
+
const cmdArgs = args.length > 0 ? args.join(" ") : "";
|
|
6502
|
+
execSync5(`pnpx skills remove ${cmdArgs}`.trim(), { stdio: "inherit" });
|
|
6503
|
+
} catch (err) {
|
|
6504
|
+
R2.warn("Skills remover finished with warnings or nothing to remove.");
|
|
6505
|
+
}
|
|
6506
|
+
const lockData = readLockFile();
|
|
6507
|
+
const installedTools = Object.keys(lockData.tools || {});
|
|
6508
|
+
const installedRules = Object.keys(lockData.rules || {});
|
|
6509
|
+
if (installedTools.length === 0 && installedRules.length === 0) {
|
|
6510
|
+
R2.info(`No local tools or rules found in ${OPENCODE_DIR}.`);
|
|
6511
|
+
return Le(`✨ Removal process completed.`);
|
|
6512
|
+
}
|
|
6513
|
+
let toolsToRemove = [];
|
|
6514
|
+
let rulesToRemove = [];
|
|
6515
|
+
if (args.length > 0) {
|
|
6516
|
+
for (const arg of args) {
|
|
6517
|
+
if (installedTools.includes(arg))
|
|
6518
|
+
toolsToRemove.push(arg);
|
|
6519
|
+
else if (installedRules.includes(arg))
|
|
6520
|
+
rulesToRemove.push(arg);
|
|
6521
|
+
else {
|
|
6522
|
+
R2.info(`Local item '${arg}' not found, skipping local cleanup.`);
|
|
6523
|
+
}
|
|
6524
|
+
}
|
|
6525
|
+
} else {
|
|
6526
|
+
if (installedTools.length > 0) {
|
|
6527
|
+
const res = await je({
|
|
6528
|
+
message: "Select local tools to remove (space to toggle)",
|
|
6529
|
+
options: installedTools.map((t) => ({ value: t, label: t })),
|
|
6530
|
+
required: false
|
|
6531
|
+
});
|
|
6532
|
+
if (Ct(res))
|
|
6533
|
+
return Ne("Operation cancelled.");
|
|
6534
|
+
if (Array.isArray(res))
|
|
6535
|
+
toolsToRemove = res;
|
|
6536
|
+
}
|
|
6537
|
+
if (installedRules.length > 0) {
|
|
6538
|
+
const res = await je({
|
|
6539
|
+
message: "Select rule categories to remove (space to toggle)",
|
|
6540
|
+
options: installedRules.map((r) => ({ value: r, label: r })),
|
|
6541
|
+
required: false
|
|
6542
|
+
});
|
|
6543
|
+
if (Ct(res))
|
|
6544
|
+
return Ne("Operation cancelled.");
|
|
6545
|
+
if (Array.isArray(res))
|
|
6546
|
+
rulesToRemove = res;
|
|
6547
|
+
}
|
|
6548
|
+
}
|
|
6549
|
+
if (toolsToRemove.length === 0 && rulesToRemove.length === 0) {
|
|
6550
|
+
if (args.length === 0)
|
|
6551
|
+
Ne("No local items selected for removal.");
|
|
6552
|
+
else
|
|
6553
|
+
Le(`✨ Removal process completed.`);
|
|
6554
|
+
return;
|
|
6555
|
+
}
|
|
6556
|
+
const confirm = await Re({
|
|
6557
|
+
message: `Are you sure you want to completely remove ${toolsToRemove.length} local tool(s) and ${rulesToRemove.length} local rule(s)?`
|
|
6558
|
+
});
|
|
6559
|
+
if (Ct(confirm) || !confirm) {
|
|
6560
|
+
return Ne("Operation cancelled.");
|
|
6561
|
+
}
|
|
6562
|
+
const s = bt2();
|
|
6563
|
+
s.start(`Cleaning up local workspace...`);
|
|
6564
|
+
try {
|
|
6565
|
+
const targetToolDir = path6.join(process.cwd(), OPENCODE_DIR, TOOL_SUBDIR);
|
|
6566
|
+
const targetRulesDir = path6.join(process.cwd(), OPENCODE_DIR, RULES_SUBDIR);
|
|
6567
|
+
for (const tool of toolsToRemove) {
|
|
6568
|
+
removeToolFiles(tool, targetToolDir);
|
|
6569
|
+
delete lockData.tools[tool];
|
|
6570
|
+
}
|
|
6571
|
+
for (const rule of rulesToRemove) {
|
|
6572
|
+
removeRuleCategory(rule, targetRulesDir);
|
|
6573
|
+
delete lockData.rules[rule];
|
|
6574
|
+
}
|
|
6575
|
+
removeOpencodeConfig(toolsToRemove, rulesToRemove);
|
|
6576
|
+
writeLockFile(lockData);
|
|
6577
|
+
s.stop(`${GREEN}Successfully removed selected local items.${RESET}`);
|
|
6578
|
+
} catch (e2) {
|
|
6579
|
+
s.stop("Failed to complete local removal.");
|
|
6580
|
+
handleExecError(e2, "Removal Error", "error" /* ERROR */);
|
|
6581
|
+
}
|
|
6582
|
+
Le(`✨ Workspace cleaned for ${CYAN}${OPENCODE_DIR}${RESET}`);
|
|
6385
6583
|
}
|
|
6386
6584
|
|
|
6387
6585
|
// src/cli.ts
|
|
@@ -6393,9 +6591,20 @@ var VIBE_LOGO = [
|
|
|
6393
6591
|
" ╚████╔╝ ██║██████╔╝███████╗",
|
|
6394
6592
|
" ╚═══╝ ╚═╝╚═════╝ ╚══════╝"
|
|
6395
6593
|
];
|
|
6594
|
+
var GRAYS = [
|
|
6595
|
+
"\x1B[38;5;250m",
|
|
6596
|
+
"\x1B[38;5;248m",
|
|
6597
|
+
"\x1B[38;5;245m",
|
|
6598
|
+
"\x1B[38;5;243m",
|
|
6599
|
+
"\x1B[38;5;240m",
|
|
6600
|
+
"\x1B[38;5;238m"
|
|
6601
|
+
];
|
|
6396
6602
|
function showLogo() {
|
|
6397
6603
|
console.log();
|
|
6398
|
-
VIBE_LOGO.forEach((line) =>
|
|
6604
|
+
VIBE_LOGO.forEach((line, i) => {
|
|
6605
|
+
const color = GRAYS[i] || GRAYS[GRAYS.length - 1];
|
|
6606
|
+
console.log(`${color}${line}${RESET}`);
|
|
6607
|
+
});
|
|
6399
6608
|
console.log();
|
|
6400
6609
|
}
|
|
6401
6610
|
function showBanner() {
|
|
@@ -6405,6 +6614,7 @@ function showBanner() {
|
|
|
6405
6614
|
console.log(` ${DIM}$${RESET} ${TEXT}vibe add <repository>${RESET} ${DIM}Add skills & tools${RESET}`);
|
|
6406
6615
|
console.log(` ${DIM}$${RESET} ${TEXT}vibe list${RESET} ${DIM}List installed tools & skills${RESET}`);
|
|
6407
6616
|
console.log(` ${DIM}$${RESET} ${TEXT}vibe update${RESET} ${DIM}Update installed tools & skills${RESET}`);
|
|
6617
|
+
console.log(` ${DIM}$${RESET} ${TEXT}vibe remove${RESET} ${DIM}Remove tools & rules${RESET}`);
|
|
6408
6618
|
console.log();
|
|
6409
6619
|
console.log(`${DIM}Example:${RESET} vibe add helloggx/skill`);
|
|
6410
6620
|
console.log();
|
|
@@ -6419,6 +6629,7 @@ ${BOLD}Manage Tools & Skills:${RESET}
|
|
|
6419
6629
|
https://github.com/helloggx/skill
|
|
6420
6630
|
list, ls List installed tools & skills for .opencode
|
|
6421
6631
|
update, up Update all local tools and standard skills
|
|
6632
|
+
remove, rm Remove selected tools & rules from .opencode
|
|
6422
6633
|
|
|
6423
6634
|
${BOLD}Options:${RESET}
|
|
6424
6635
|
--help, -h Show this help message
|
|
@@ -6427,6 +6638,7 @@ ${BOLD}Examples:${RESET}
|
|
|
6427
6638
|
${DIM}$${RESET} vibe add helloggx/skill
|
|
6428
6639
|
${DIM}$${RESET} vibe list ${DIM}# list installed tools and skills${RESET}
|
|
6429
6640
|
${DIM}$${RESET} vibe update ${DIM}# check and update all items${RESET}
|
|
6641
|
+
${DIM}$${RESET} vibe remove ${DIM}# remove selected tools and rules${RESET}
|
|
6430
6642
|
|
|
6431
6643
|
The Design-Driven Agent Skills Ecosystem
|
|
6432
6644
|
`);
|
|
@@ -6445,6 +6657,11 @@ async function main() {
|
|
|
6445
6657
|
showLogo();
|
|
6446
6658
|
await runAdd(args.slice(1));
|
|
6447
6659
|
break;
|
|
6660
|
+
case "rm":
|
|
6661
|
+
case "remove":
|
|
6662
|
+
console.clear();
|
|
6663
|
+
await runRemove(args.slice(1));
|
|
6664
|
+
break;
|
|
6448
6665
|
case "ls":
|
|
6449
6666
|
case "list":
|
|
6450
6667
|
await runList(args.slice(1));
|
package/package.json
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibe-coder/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Vibe Coding development tool",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
|
+
"author": "HelloGGX",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/HelloGGX/skill.git"
|
|
12
|
+
},
|
|
7
13
|
"bin": {
|
|
8
14
|
"vibe": "./bin/vibe"
|
|
9
15
|
},
|
|
@@ -22,7 +28,8 @@
|
|
|
22
28
|
"keywords": [
|
|
23
29
|
"cli",
|
|
24
30
|
"agent-skills",
|
|
25
|
-
"skills"
|
|
31
|
+
"skills",
|
|
32
|
+
"vibe-coding"
|
|
26
33
|
],
|
|
27
34
|
"dependencies": {
|
|
28
35
|
"@clack/prompts": "^1.0.1",
|
|
@@ -33,5 +40,9 @@
|
|
|
33
40
|
"@types/bun": "1.3.9",
|
|
34
41
|
"@types/node": "22.13.9",
|
|
35
42
|
"typescript": "5.8.2"
|
|
36
|
-
}
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/HelloGGX/skill/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/HelloGGX/skill#readme"
|
|
37
48
|
}
|