@clix-so/clix-agent-skills 0.1.1 → 0.1.3
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 +10 -8
- package/dist/bin/cli.js +13 -3
- package/dist/bin/commands/install.js +20 -5
- package/dist/bin/utils/mcp.js +321 -44
- package/package.json +8 -2
- package/skills/integration/SKILL.md +57 -4
- package/skills/integration/references/mcp-integration.md +62 -0
- package/skills/integration/scripts/install-mcp.sh +150 -0
package/README.md
CHANGED
|
@@ -7,9 +7,9 @@ is a self-contained package that can be loaded and executed by AI clients.
|
|
|
7
7
|
|
|
8
8
|
Agents skills on this repository are built on the
|
|
9
9
|
[open agent skills standard](https://agentskills.io/home). Please refer to the
|
|
10
|
-
[official documentation](https://agentskills.io/
|
|
11
|
-
of support AI clients. Depending on the AI client you are using, you
|
|
12
|
-
skills in different ways.
|
|
10
|
+
[official documentation](https://agentskills.io/home#adoption) for up-to-date
|
|
11
|
+
information of support AI clients. Depending on the AI client you are using, you
|
|
12
|
+
can install skills in different ways.
|
|
13
13
|
|
|
14
14
|
### Universal CLI (Recommended)
|
|
15
15
|
|
|
@@ -18,7 +18,9 @@ For **Cursor**, **VS Code**, **Claude Desktop**, **OpenCode**, **Goose**,
|
|
|
18
18
|
and configure the Clix MCP Server automatically:
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
npx @clix-so/clix-agent-skills install <skill-name> --client <your-client>
|
|
21
|
+
npx @clix-so/clix-agent-skills@latest install <skill-name> --client <your-client>
|
|
22
|
+
# For example, to install integration skill on Cursor:
|
|
23
|
+
# npx @clix-so/clix-agent-skills@latest install integration --client cursor
|
|
22
24
|
```
|
|
23
25
|
|
|
24
26
|
**Supported Clients:**
|
|
@@ -55,7 +57,7 @@ Alternatively, you can install a single skill directly by running:
|
|
|
55
57
|
```bash
|
|
56
58
|
/plugin install <plugin-name>@<marketplace-name>
|
|
57
59
|
# For example
|
|
58
|
-
/plugin install clix-integration@clix-agent-skills
|
|
60
|
+
# /plugin install clix-integration@clix-agent-skills
|
|
59
61
|
```
|
|
60
62
|
|
|
61
63
|
Remember to restart Claude Code after installation to load the new skills.
|
|
@@ -81,10 +83,10 @@ incorrectly** due to the non-deterministic nature of AI.
|
|
|
81
83
|
|
|
82
84
|
It is critical that you **carefully review and verify all actions** performed by
|
|
83
85
|
these skills. While they are designed to be helpful, you remain responsible for
|
|
84
|
-
checking their output before use.
|
|
86
|
+
checking their output before use. Please use them with caution and supervision.
|
|
85
87
|
|
|
86
88
|
## License
|
|
87
89
|
|
|
88
90
|
Each skill in this repository is governed by its own license. For specific terms
|
|
89
|
-
and conditions, please consult the `LICENSE` file located within each
|
|
90
|
-
individual directory.
|
|
91
|
+
and conditions, please consult the `LICENSE.txt` file located within each
|
|
92
|
+
skill's individual directory.
|
package/dist/bin/cli.js
CHANGED
|
@@ -7,22 +7,32 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
const commander_1 = require("commander");
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
9
|
const install_1 = require("./commands/install");
|
|
10
|
+
const package_json_1 = require("../../package.json");
|
|
11
|
+
/**
|
|
12
|
+
* Extracts error message from unknown error type
|
|
13
|
+
*/
|
|
14
|
+
function getErrorMessage(error) {
|
|
15
|
+
if (error instanceof Error) {
|
|
16
|
+
return error.message;
|
|
17
|
+
}
|
|
18
|
+
return String(error);
|
|
19
|
+
}
|
|
10
20
|
const program = new commander_1.Command();
|
|
11
21
|
program
|
|
12
22
|
.name("clix-agent-skills")
|
|
13
23
|
.description("CLI to manage and install Clix Agent Skills")
|
|
14
|
-
.version(
|
|
24
|
+
.version(package_json_1.version);
|
|
15
25
|
program
|
|
16
26
|
.command("install <skill>")
|
|
17
27
|
.description("Install a specific agent skill")
|
|
18
|
-
.option("-c, --client <client>", "Target AI client (cursor, claude, vscode, manual)")
|
|
28
|
+
.option("-c, --client <client>", "Target AI client (cursor, claude, vscode, amp, kiro, amazonq, codex, opencode, manual)")
|
|
19
29
|
.option("-p, --path <path>", "Custom installation path (default: .clix/skills)")
|
|
20
30
|
.action(async (skill, options) => {
|
|
21
31
|
try {
|
|
22
32
|
await (0, install_1.installSkill)(skill, options);
|
|
23
33
|
}
|
|
24
34
|
catch (error) {
|
|
25
|
-
console.error(chalk_1.default.red("Error installing skill:"), error
|
|
35
|
+
console.error(chalk_1.default.red("Error installing skill:"), getErrorMessage(error));
|
|
26
36
|
process.exit(1);
|
|
27
37
|
}
|
|
28
38
|
});
|
|
@@ -9,6 +9,15 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
9
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
10
|
const ora_1 = __importDefault(require("ora"));
|
|
11
11
|
const mcp_1 = require("../utils/mcp");
|
|
12
|
+
/**
|
|
13
|
+
* Extracts error message from unknown error type
|
|
14
|
+
*/
|
|
15
|
+
function getErrorMessage(error) {
|
|
16
|
+
if (error instanceof Error) {
|
|
17
|
+
return error.message;
|
|
18
|
+
}
|
|
19
|
+
return String(error);
|
|
20
|
+
}
|
|
12
21
|
async function installSkill(skillName, options) {
|
|
13
22
|
const spinner = (0, ora_1.default)(`Installing skill: ${chalk_1.default.bold(skillName)}`).start();
|
|
14
23
|
// 1. Locate Skill in current package
|
|
@@ -80,6 +89,12 @@ async function installSkill(skillName, options) {
|
|
|
80
89
|
case "amp":
|
|
81
90
|
relativeDest = ".amp/skills";
|
|
82
91
|
break;
|
|
92
|
+
case "kiro":
|
|
93
|
+
relativeDest = ".kiro/skills";
|
|
94
|
+
break;
|
|
95
|
+
case "amazonq":
|
|
96
|
+
relativeDest = ".amazonq/skills";
|
|
97
|
+
break;
|
|
83
98
|
default:
|
|
84
99
|
relativeDest = options.client.startsWith(".") ? `${options.client}/skills` : `.clix/skills`;
|
|
85
100
|
}
|
|
@@ -91,16 +106,16 @@ async function installSkill(skillName, options) {
|
|
|
91
106
|
await fs_extra_1.default.copy(skillSourcePath, destPath);
|
|
92
107
|
spinner.succeed(`Skill files installed to ${chalk_1.default.green(relativeDest + "/" + skillName)}`);
|
|
93
108
|
}
|
|
94
|
-
catch (
|
|
95
|
-
spinner.fail(`Failed to copy skill files: ${
|
|
96
|
-
throw
|
|
109
|
+
catch (error) {
|
|
110
|
+
spinner.fail(`Failed to copy skill files: ${getErrorMessage(error)}`);
|
|
111
|
+
throw error;
|
|
97
112
|
}
|
|
98
113
|
// 4. MCP Configuration
|
|
99
114
|
try {
|
|
100
115
|
await (0, mcp_1.configureMCP)(options.client);
|
|
101
116
|
}
|
|
102
|
-
catch (
|
|
103
|
-
console.warn(chalk_1.default.yellow(`MCP Configuration warning: ${
|
|
117
|
+
catch (error) {
|
|
118
|
+
console.warn(chalk_1.default.yellow(`MCP Configuration warning: ${getErrorMessage(error)}`));
|
|
104
119
|
}
|
|
105
120
|
console.log(`\n${chalk_1.default.green("✔")} Skill ${chalk_1.default.bold(skillName)} is ready to use!`);
|
|
106
121
|
console.log(` - Docs: ${path_1.default.join(destPath, "SKILL.md")}`);
|
package/dist/bin/utils/mcp.js
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
@@ -9,12 +42,262 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
9
42
|
const os_1 = __importDefault(require("os"));
|
|
10
43
|
const chalk_1 = __importDefault(require("chalk"));
|
|
11
44
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
45
|
+
const TOML = __importStar(require("@iarna/toml"));
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// Constants
|
|
48
|
+
// ============================================================================
|
|
49
|
+
const CLIX_MCP_SERVER_ENTRY = {
|
|
50
|
+
command: "npx",
|
|
51
|
+
args: ["-y", "@clix-so/clix-mcp-server@latest"],
|
|
17
52
|
};
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Helper Functions
|
|
55
|
+
// ============================================================================
|
|
56
|
+
/**
|
|
57
|
+
* Extracts error message from unknown error type
|
|
58
|
+
*/
|
|
59
|
+
function getErrorMessage(error) {
|
|
60
|
+
if (error instanceof Error) {
|
|
61
|
+
return error.message;
|
|
62
|
+
}
|
|
63
|
+
return String(error);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Gets the MCP servers object from JSON config based on client type
|
|
67
|
+
*/
|
|
68
|
+
function getMcpServersFromConfig(config, configKey) {
|
|
69
|
+
if (configKey === "amp.mcpServers") {
|
|
70
|
+
return config["amp.mcpServers"];
|
|
71
|
+
}
|
|
72
|
+
return config.mcpServers;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Sets the MCP servers object in JSON config based on client type
|
|
76
|
+
*/
|
|
77
|
+
function setMcpServersInConfig(config, configKey, servers) {
|
|
78
|
+
if (configKey === "amp.mcpServers") {
|
|
79
|
+
config["amp.mcpServers"] = servers;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
config.mcpServers = servers;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Creates empty JSON config structure based on client type
|
|
87
|
+
*/
|
|
88
|
+
function createEmptyConfig(configKey) {
|
|
89
|
+
if (configKey === "amp.mcpServers") {
|
|
90
|
+
return { "amp.mcpServers": {} };
|
|
91
|
+
}
|
|
92
|
+
return { mcpServers: {} };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Gets config path, key, and format for a specific client
|
|
96
|
+
*/
|
|
97
|
+
function getClientConfig(client) {
|
|
98
|
+
const home = os_1.default.homedir();
|
|
99
|
+
switch (client.toLowerCase()) {
|
|
100
|
+
case "cursor": {
|
|
101
|
+
// Check for project-level definition first
|
|
102
|
+
const projectCursorPath = path_1.default.join(process.cwd(), ".cursor", "mcp.json");
|
|
103
|
+
if (fs_extra_1.default.existsSync(projectCursorPath)) {
|
|
104
|
+
return { path: projectCursorPath, configKey: "mcpServers", format: "json" };
|
|
105
|
+
}
|
|
106
|
+
// Fallback to global
|
|
107
|
+
return {
|
|
108
|
+
path: path_1.default.join(home, ".cursor", "mcp.json"),
|
|
109
|
+
configKey: "mcpServers",
|
|
110
|
+
format: "json",
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
case "claude": {
|
|
114
|
+
let configPath = null;
|
|
115
|
+
if (process.platform === "darwin") {
|
|
116
|
+
configPath = path_1.default.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
117
|
+
}
|
|
118
|
+
else if (process.platform === "win32") {
|
|
119
|
+
configPath = path_1.default.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
|
|
120
|
+
}
|
|
121
|
+
else if (process.platform === "linux") {
|
|
122
|
+
configPath = path_1.default.join(home, ".config", "Claude", "claude_desktop_config.json");
|
|
123
|
+
}
|
|
124
|
+
return configPath ? { path: configPath, configKey: "mcpServers", format: "json" } : null;
|
|
125
|
+
}
|
|
126
|
+
case "vscode":
|
|
127
|
+
return {
|
|
128
|
+
path: path_1.default.join(home, ".vscode", "mcp.json"),
|
|
129
|
+
configKey: "mcpServers",
|
|
130
|
+
format: "json",
|
|
131
|
+
};
|
|
132
|
+
case "amp": {
|
|
133
|
+
let ampConfigPath;
|
|
134
|
+
if (process.platform === "win32") {
|
|
135
|
+
ampConfigPath = path_1.default.join(process.env.USERPROFILE || home, ".config", "amp", "settings.json");
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
ampConfigPath = path_1.default.join(home, ".config", "amp", "settings.json");
|
|
139
|
+
}
|
|
140
|
+
return { path: ampConfigPath, configKey: "amp.mcpServers", format: "json" };
|
|
141
|
+
}
|
|
142
|
+
case "kiro":
|
|
143
|
+
return {
|
|
144
|
+
path: path_1.default.join(process.cwd(), ".kiro", "settings", "mcp.json"),
|
|
145
|
+
configKey: "mcpServers",
|
|
146
|
+
format: "json",
|
|
147
|
+
};
|
|
148
|
+
case "amazonq":
|
|
149
|
+
return {
|
|
150
|
+
path: path_1.default.join(home, ".aws", "amazonq", "agents", "default.json"),
|
|
151
|
+
configKey: "mcpServers",
|
|
152
|
+
format: "json",
|
|
153
|
+
};
|
|
154
|
+
case "codex":
|
|
155
|
+
return {
|
|
156
|
+
path: path_1.default.join(home, ".codex", "config.toml"),
|
|
157
|
+
configKey: "mcp_servers",
|
|
158
|
+
format: "toml",
|
|
159
|
+
};
|
|
160
|
+
default:
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// ============================================================================
|
|
165
|
+
// TOML Configuration (Codex)
|
|
166
|
+
// ============================================================================
|
|
167
|
+
async function configureCodexTOML(configPath) {
|
|
168
|
+
const nicePath = configPath.replace(os_1.default.homedir(), "~");
|
|
169
|
+
console.log(chalk_1.default.blue(`Checking MCP config at ${nicePath}...`));
|
|
170
|
+
let config = {};
|
|
171
|
+
if (!fs_extra_1.default.existsSync(configPath)) {
|
|
172
|
+
const { create } = await inquirer_1.default.prompt([
|
|
173
|
+
{
|
|
174
|
+
type: "confirm",
|
|
175
|
+
name: "create",
|
|
176
|
+
message: `Config file not found at ${nicePath}. Create it?`,
|
|
177
|
+
default: true,
|
|
178
|
+
},
|
|
179
|
+
]);
|
|
180
|
+
if (!create) {
|
|
181
|
+
console.log(chalk_1.default.yellow("Skipping MCP configuration. You can configure manually later."));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(configPath));
|
|
186
|
+
config = { mcp_servers: {} };
|
|
187
|
+
await fs_extra_1.default.writeFile(configPath, TOML.stringify(config), "utf-8");
|
|
188
|
+
console.log(chalk_1.default.green(`✔ Created config file at ${nicePath}`));
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
console.log(chalk_1.default.red(`Failed to create config file: ${getErrorMessage(error)}`));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
// Read existing TOML config
|
|
197
|
+
try {
|
|
198
|
+
const content = await fs_extra_1.default.readFile(configPath, "utf-8");
|
|
199
|
+
config = TOML.parse(content);
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
console.log(chalk_1.default.red(`Failed to parse existing config TOML: ${getErrorMessage(error)}`));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Initialize mcp_servers if not present
|
|
207
|
+
if (!config.mcp_servers) {
|
|
208
|
+
config.mcp_servers = {};
|
|
209
|
+
}
|
|
210
|
+
// Check if already configured
|
|
211
|
+
if (config.mcp_servers["clix-mcp-server"]) {
|
|
212
|
+
console.log(chalk_1.default.green("✔ Clix MCP Server is already configured."));
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
// Ask to inject
|
|
216
|
+
const { inject } = await inquirer_1.default.prompt([
|
|
217
|
+
{
|
|
218
|
+
type: "confirm",
|
|
219
|
+
name: "inject",
|
|
220
|
+
message: `Add Clix MCP Server to ${nicePath}?`,
|
|
221
|
+
default: true,
|
|
222
|
+
},
|
|
223
|
+
]);
|
|
224
|
+
if (inject) {
|
|
225
|
+
config.mcp_servers["clix-mcp-server"] = CLIX_MCP_SERVER_ENTRY;
|
|
226
|
+
await fs_extra_1.default.writeFile(configPath, TOML.stringify(config), "utf-8");
|
|
227
|
+
console.log(chalk_1.default.green(`✔ Added Clix MCP Server to configuration. Please restart codex.`));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
async function configureOpenCode() {
|
|
231
|
+
const configPath = path_1.default.join(process.cwd(), "opencode.json");
|
|
232
|
+
const nicePath = "opencode.json";
|
|
233
|
+
console.log(chalk_1.default.blue(`Checking MCP config at ${nicePath}...`));
|
|
234
|
+
let config = {};
|
|
235
|
+
if (!fs_extra_1.default.existsSync(configPath)) {
|
|
236
|
+
const { create } = await inquirer_1.default.prompt([
|
|
237
|
+
{
|
|
238
|
+
type: "confirm",
|
|
239
|
+
name: "create",
|
|
240
|
+
message: `Config file not found at ${nicePath}. Create it?`,
|
|
241
|
+
default: true,
|
|
242
|
+
},
|
|
243
|
+
]);
|
|
244
|
+
if (!create) {
|
|
245
|
+
console.log(chalk_1.default.yellow("Skipping MCP configuration. You can configure manually later."));
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
config = {
|
|
250
|
+
$schema: "https://opencode.ai/config.json",
|
|
251
|
+
mcp: {},
|
|
252
|
+
};
|
|
253
|
+
await fs_extra_1.default.writeJSON(configPath, config, { spaces: 2 });
|
|
254
|
+
console.log(chalk_1.default.green(`✔ Created config file at ${nicePath}`));
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
console.log(chalk_1.default.red(`Failed to create config file: ${getErrorMessage(error)}`));
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
try {
|
|
263
|
+
config = await fs_extra_1.default.readJSON(configPath);
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
console.log(chalk_1.default.red(`Failed to parse existing config JSON: ${getErrorMessage(error)}`));
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// Initialize mcp if not present
|
|
271
|
+
if (!config.mcp) {
|
|
272
|
+
config.mcp = {};
|
|
273
|
+
}
|
|
274
|
+
// Check if already configured
|
|
275
|
+
if (config.mcp["clix-mcp-server"]) {
|
|
276
|
+
console.log(chalk_1.default.green("✔ Clix MCP Server is already configured."));
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
// Ask to inject
|
|
280
|
+
const { inject } = await inquirer_1.default.prompt([
|
|
281
|
+
{
|
|
282
|
+
type: "confirm",
|
|
283
|
+
name: "inject",
|
|
284
|
+
message: `Add Clix MCP Server to ${nicePath}?`,
|
|
285
|
+
default: true,
|
|
286
|
+
},
|
|
287
|
+
]);
|
|
288
|
+
if (inject) {
|
|
289
|
+
config.mcp["clix-mcp-server"] = {
|
|
290
|
+
type: "local",
|
|
291
|
+
command: ["npx", "-y", "@clix-so/clix-mcp-server@latest"],
|
|
292
|
+
enabled: true,
|
|
293
|
+
};
|
|
294
|
+
await fs_extra_1.default.writeJSON(configPath, config, { spaces: 2 });
|
|
295
|
+
console.log(chalk_1.default.green(`✔ Added Clix MCP Server to configuration. Please restart opencode.`));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// ============================================================================
|
|
299
|
+
// Main Function
|
|
300
|
+
// ============================================================================
|
|
18
301
|
async function configureMCP(client) {
|
|
19
302
|
let targetClient = client;
|
|
20
303
|
if (!targetClient) {
|
|
@@ -27,12 +310,14 @@ async function configureMCP(client) {
|
|
|
27
310
|
{ name: "Cursor", value: "cursor" },
|
|
28
311
|
{ name: "Claude Desktop", value: "claude" },
|
|
29
312
|
{ name: "VS Code", value: "vscode" },
|
|
313
|
+
{ name: "Amp", value: "amp" },
|
|
314
|
+
{ name: "Kiro", value: "kiro" },
|
|
315
|
+
{ name: "Amazon Q", value: "amazonq" },
|
|
30
316
|
{ name: "Codex", value: "codex" },
|
|
31
317
|
{ name: "OpenCode", value: "opencode" },
|
|
32
318
|
{ name: "Letta", value: "letta" },
|
|
33
319
|
{ name: "Goose", value: "goose" },
|
|
34
320
|
{ name: "GitHub", value: "github" },
|
|
35
|
-
{ name: "Amp", value: "amp" },
|
|
36
321
|
{ name: "None / Manual", value: "manual" },
|
|
37
322
|
],
|
|
38
323
|
},
|
|
@@ -43,15 +328,27 @@ async function configureMCP(client) {
|
|
|
43
328
|
console.log(chalk_1.default.blue("Skipping automatic MCP configuration."));
|
|
44
329
|
return;
|
|
45
330
|
}
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
|
|
331
|
+
// Handle OpenCode separately (different JSON structure)
|
|
332
|
+
if (targetClient === "opencode") {
|
|
333
|
+
await configureOpenCode();
|
|
49
334
|
return;
|
|
50
335
|
}
|
|
336
|
+
// Get client config
|
|
337
|
+
const clientConfig = getClientConfig(targetClient);
|
|
338
|
+
if (!clientConfig) {
|
|
339
|
+
console.log(chalk_1.default.yellow(`Could not determine config path for ${targetClient}. Skipping.`));
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
// Handle TOML format (Codex)
|
|
343
|
+
if (clientConfig.format === "toml") {
|
|
344
|
+
await configureCodexTOML(clientConfig.path);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
// Handle JSON format (all other clients)
|
|
348
|
+
const { path: configPath, configKey } = clientConfig;
|
|
51
349
|
const nicePath = configPath.replace(os_1.default.homedir(), "~");
|
|
52
350
|
console.log(chalk_1.default.blue(`Checking MCP config at ${nicePath}...`));
|
|
53
351
|
if (!fs_extra_1.default.existsSync(configPath)) {
|
|
54
|
-
// For now, confirm before creating new file
|
|
55
352
|
const { create } = await inquirer_1.default.prompt([
|
|
56
353
|
{
|
|
57
354
|
type: "confirm",
|
|
@@ -66,26 +363,30 @@ async function configureMCP(client) {
|
|
|
66
363
|
}
|
|
67
364
|
try {
|
|
68
365
|
await fs_extra_1.default.ensureDir(path_1.default.dirname(configPath));
|
|
69
|
-
await fs_extra_1.default.writeJSON(configPath,
|
|
366
|
+
await fs_extra_1.default.writeJSON(configPath, createEmptyConfig(configKey), { spaces: 2 });
|
|
70
367
|
console.log(chalk_1.default.green(`✔ Created config file at ${nicePath}`));
|
|
71
368
|
}
|
|
72
369
|
catch (error) {
|
|
73
|
-
console.log(chalk_1.default.red(`Failed to create config file: ${error
|
|
370
|
+
console.log(chalk_1.default.red(`Failed to create config file: ${getErrorMessage(error)}`));
|
|
74
371
|
return;
|
|
75
372
|
}
|
|
76
373
|
}
|
|
77
374
|
// Read config
|
|
78
|
-
let config
|
|
375
|
+
let config;
|
|
79
376
|
try {
|
|
80
377
|
config = await fs_extra_1.default.readJSON(configPath);
|
|
81
378
|
}
|
|
82
|
-
catch (
|
|
83
|
-
console.log(chalk_1.default.red(
|
|
379
|
+
catch (error) {
|
|
380
|
+
console.log(chalk_1.default.red(`Failed to parse existing config JSON: ${getErrorMessage(error)}`));
|
|
84
381
|
return;
|
|
85
382
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (
|
|
383
|
+
// Get or create mcpServers object
|
|
384
|
+
let mcpServers = getMcpServersFromConfig(config, configKey);
|
|
385
|
+
if (!mcpServers) {
|
|
386
|
+
mcpServers = {};
|
|
387
|
+
setMcpServersInConfig(config, configKey, mcpServers);
|
|
388
|
+
}
|
|
389
|
+
if (mcpServers["clix-mcp-server"]) {
|
|
89
390
|
console.log(chalk_1.default.green("✔ Clix MCP Server is already configured."));
|
|
90
391
|
return;
|
|
91
392
|
}
|
|
@@ -99,33 +400,9 @@ async function configureMCP(client) {
|
|
|
99
400
|
},
|
|
100
401
|
]);
|
|
101
402
|
if (inject) {
|
|
102
|
-
|
|
403
|
+
mcpServers["clix-mcp-server"] = CLIX_MCP_SERVER_ENTRY;
|
|
404
|
+
setMcpServersInConfig(config, configKey, mcpServers);
|
|
103
405
|
await fs_extra_1.default.writeJSON(configPath, config, { spaces: 2 });
|
|
104
406
|
console.log(chalk_1.default.green(`✔ Added Clix MCP Server to configuration. Please restart ${targetClient}.`));
|
|
105
407
|
}
|
|
106
408
|
}
|
|
107
|
-
function getConfigPath(client) {
|
|
108
|
-
const home = os_1.default.homedir();
|
|
109
|
-
switch (client.toLowerCase()) {
|
|
110
|
-
case "cursor":
|
|
111
|
-
// Check for project-level definition first
|
|
112
|
-
const projectCursorPath = path_1.default.join(process.cwd(), ".cursor", "mcp.json");
|
|
113
|
-
if (fs_extra_1.default.existsSync(projectCursorPath)) {
|
|
114
|
-
return projectCursorPath;
|
|
115
|
-
}
|
|
116
|
-
// Fallback to global
|
|
117
|
-
return path_1.default.join(home, ".cursor", "mcp.json");
|
|
118
|
-
case "claude":
|
|
119
|
-
if (process.platform === "darwin") {
|
|
120
|
-
return path_1.default.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
121
|
-
}
|
|
122
|
-
else if (process.platform === "win32") {
|
|
123
|
-
return path_1.default.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
|
|
124
|
-
}
|
|
125
|
-
return null;
|
|
126
|
-
case "vscode":
|
|
127
|
-
return path_1.default.join(home, ".vscode", "mcp.json"); // Standard VS Code MCP path assumption
|
|
128
|
-
default:
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clix-so/clix-agent-skills",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "An open collection of agent skills for Clix.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,11 @@
|
|
|
16
16
|
"dev": "ts-node src/bin/cli.ts",
|
|
17
17
|
"test": "jest",
|
|
18
18
|
"lint": "prettier --check .",
|
|
19
|
-
"lint:fix": "prettier --write ."
|
|
19
|
+
"lint:fix": "prettier --write .",
|
|
20
|
+
"sync-version": "ts-node scripts/sync-version.ts",
|
|
21
|
+
"preversion": "npm run sync-version",
|
|
22
|
+
"postversion": "npm run sync-version",
|
|
23
|
+
"prepublishOnly": "npm run sync-version && npm run build && npm test"
|
|
20
24
|
},
|
|
21
25
|
"keywords": [
|
|
22
26
|
"clix",
|
|
@@ -32,6 +36,7 @@
|
|
|
32
36
|
"url": "https://github.com/clix-so/skills"
|
|
33
37
|
},
|
|
34
38
|
"dependencies": {
|
|
39
|
+
"@iarna/toml": "^2.2.5",
|
|
35
40
|
"chalk": "^4.1.2",
|
|
36
41
|
"commander": "^14.0.2",
|
|
37
42
|
"fs-extra": "^11.3.3",
|
|
@@ -40,6 +45,7 @@
|
|
|
40
45
|
},
|
|
41
46
|
"devDependencies": {
|
|
42
47
|
"@types/fs-extra": "^11.0.4",
|
|
48
|
+
"@types/iarna__toml": "^2.0.5",
|
|
43
49
|
"@types/inquirer": "^9.0.9",
|
|
44
50
|
"@types/jest": "^30.0.0",
|
|
45
51
|
"@types/node": "^25.0.3",
|
|
@@ -5,7 +5,6 @@ description:
|
|
|
5
5
|
projects. Provides step-by-step guidance for installation, initialization, and
|
|
6
6
|
verification. Use when the user asks to install, setup, or configure Clix
|
|
7
7
|
analytics.
|
|
8
|
-
version: 0.1.0
|
|
9
8
|
---
|
|
10
9
|
|
|
11
10
|
# Clix SDK Integration Skill
|
|
@@ -42,7 +41,8 @@ latest verified SDK source code.
|
|
|
42
41
|
- Run: `bash scripts/install-mcp.sh`
|
|
43
42
|
- The script will:
|
|
44
43
|
- Verify the package is available
|
|
45
|
-
- Auto-detect the MCP client (
|
|
44
|
+
- Auto-detect the MCP client (OpenCode, Amp, Codex, Cursor, Claude
|
|
45
|
+
Desktop, VS Code, etc.)
|
|
46
46
|
- Automatically configure the MCP server in the appropriate config file
|
|
47
47
|
- Provide clear instructions for restart
|
|
48
48
|
- Instruct user to restart their agent/IDE to load the new server.
|
|
@@ -55,8 +55,8 @@ latest verified SDK source code.
|
|
|
55
55
|
|
|
56
56
|
## Interaction Guidelines for Agents
|
|
57
57
|
|
|
58
|
-
When using this skill (for example inside Claude Code, Codex,
|
|
59
|
-
AI IDEs), follow these behaviors:
|
|
58
|
+
When using this skill (for example inside OpenCode, Amp, Claude Code, Codex,
|
|
59
|
+
Cursor, or other AI IDEs), follow these behaviors:
|
|
60
60
|
|
|
61
61
|
- **Start with reconnaissance**
|
|
62
62
|
- Inspect the project structure first (list key files like `package.json`,
|
|
@@ -123,6 +123,9 @@ Examine the codebase structure to determine platform:
|
|
|
123
123
|
- **Other**: If it’s not one of the above, stop and ask the user—this skill is
|
|
124
124
|
mobile-only.
|
|
125
125
|
|
|
126
|
+
**Priority rule (important):** If React Native or Flutter is detected, treat it
|
|
127
|
+
as the primary platform even if native `ios/` and `android/` folders exist.
|
|
128
|
+
|
|
126
129
|
**Step 2.2: Verify Detection**
|
|
127
130
|
|
|
128
131
|
Confirm platform detection with user if ambiguous:
|
|
@@ -238,6 +241,42 @@ Run validation checks:
|
|
|
238
241
|
- Verify environment variables are accessible
|
|
239
242
|
- Verify SDK is properly imported and initialized
|
|
240
243
|
|
|
244
|
+
### Platform Verification Checklists (UI Steps → Repo Verification)
|
|
245
|
+
|
|
246
|
+
Use these checklists to verify manual UI steps were actually completed.
|
|
247
|
+
|
|
248
|
+
#### iOS Verification
|
|
249
|
+
|
|
250
|
+
- **Dependencies present**: `Podfile`/`Podfile.lock` or SwiftPM/Xcode references
|
|
251
|
+
- **Entitlements present**: an `*.entitlements` file exists and is wired to the
|
|
252
|
+
correct target(s)
|
|
253
|
+
- **Capabilities configured**: `project.pbxproj` reflects required capabilities
|
|
254
|
+
(as applicable to Push Notifications / Background Modes)
|
|
255
|
+
|
|
256
|
+
#### Android Verification
|
|
257
|
+
|
|
258
|
+
- **Dependencies present**: module-level `build.gradle` / `build.gradle.kts`
|
|
259
|
+
includes required SDK dependencies
|
|
260
|
+
- **Manifest updated**: `AndroidManifest.xml` contains required permissions,
|
|
261
|
+
services/receivers (as required by the SDK)
|
|
262
|
+
- **Firebase config placed** (if used): `google-services.json` exists in the
|
|
263
|
+
expected module directory (commonly `app/`)
|
|
264
|
+
|
|
265
|
+
#### React Native Verification
|
|
266
|
+
|
|
267
|
+
- **JS dependency**: `package.json` includes the Clix package
|
|
268
|
+
- **iOS native**: `ios/Podfile.lock` updated after `pod install` (when required)
|
|
269
|
+
- **Android native**: Gradle + Manifest updates present if required by the SDK
|
|
270
|
+
- **Initialization**: root entrypoint initializes the SDK exactly once
|
|
271
|
+
|
|
272
|
+
#### Flutter Verification
|
|
273
|
+
|
|
274
|
+
- **Pub dependency**: `pubspec.yaml` includes the required packages and
|
|
275
|
+
`pubspec.lock` is updated after `flutter pub get`
|
|
276
|
+
- **iOS native**: `ios/Podfile.lock` updated after `pod install` (when required)
|
|
277
|
+
- **Android native**: Gradle + Manifest updates present if required
|
|
278
|
+
- **Initialization**: SDK initialized before `runApp`
|
|
279
|
+
|
|
241
280
|
**Step 5.3: Documentation**
|
|
242
281
|
|
|
243
282
|
Create or update documentation:
|
|
@@ -388,6 +427,20 @@ Future<void> main() async {
|
|
|
388
427
|
6. **Document changes** - Update README and configuration files
|
|
389
428
|
7. **Version control** - Add `.env` to `.gitignore`, commit `.env.example`
|
|
390
429
|
|
|
430
|
+
## Docs Usage Note (MCP vs Static vs Web Docs)
|
|
431
|
+
|
|
432
|
+
- If MCP tools are available: treat `search_sdk` results as the source of truth
|
|
433
|
+
for initialization/API usage.
|
|
434
|
+
- If MCP tools are unavailable: you may reference the official quickstarts below
|
|
435
|
+
for **manual steps**, and use `examples/` + `references/` for code patterns.
|
|
436
|
+
|
|
437
|
+
**Official quickstarts:**
|
|
438
|
+
|
|
439
|
+
- iOS: `https://docs.clix.so/sdk-quickstart-ios`
|
|
440
|
+
- Android: `https://docs.clix.so/sdk-quickstart-android`
|
|
441
|
+
- React Native: `https://docs.clix.so/sdk-quickstart-react-native`
|
|
442
|
+
- Flutter: `https://docs.clix.so/sdk-quickstart-flutter`
|
|
443
|
+
|
|
391
444
|
## Progressive Disclosure
|
|
392
445
|
|
|
393
446
|
- **Level 1**: This SKILL.md file (always loaded)
|
|
@@ -282,3 +282,65 @@ claude mcp add --transport stdio clix-mcp-server -- npx -y @clix-so/clix-mcp-ser
|
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
```
|
|
285
|
+
|
|
286
|
+
#### Amp
|
|
287
|
+
|
|
288
|
+
**Setup**
|
|
289
|
+
|
|
290
|
+
Amp uses `amp.mcpServers` in VS Code settings files. Configure in either:
|
|
291
|
+
|
|
292
|
+
- **Workspace settings**: `.vscode/settings.json` (recommended for
|
|
293
|
+
project-specific setup)
|
|
294
|
+
- **User settings**: `~/.vscode/settings.json` (for global setup)
|
|
295
|
+
|
|
296
|
+
1. Open `.vscode/settings.json` (create if it doesn't exist).
|
|
297
|
+
2. Add the configuration:
|
|
298
|
+
|
|
299
|
+
```json
|
|
300
|
+
{
|
|
301
|
+
"amp.mcpServers": {
|
|
302
|
+
"clix-mcp-server": {
|
|
303
|
+
"command": "npx",
|
|
304
|
+
"args": ["-y", "@clix-so/clix-mcp-server@latest"]
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
3. Restart Amp or reload the VS Code window.
|
|
311
|
+
|
|
312
|
+
**Note**: The server name `clix-mcp-server` ensures tools appear as
|
|
313
|
+
`clix-mcp-server:*` (e.g., `clix-mcp-server:search_sdk`,
|
|
314
|
+
`clix-mcp-server:search_docs`). See
|
|
315
|
+
[Amp MCP documentation](https://ampcode.com/manual#mcp) for more details.
|
|
316
|
+
|
|
317
|
+
#### OpenCode
|
|
318
|
+
|
|
319
|
+
**Setup**
|
|
320
|
+
|
|
321
|
+
OpenCode uses `opencode.json` or `opencode.jsonc` files in your project root.
|
|
322
|
+
See [OpenCode MCP documentation](https://opencode.ai/docs/mcp-servers/) for
|
|
323
|
+
details.
|
|
324
|
+
|
|
325
|
+
1. Open `opencode.json` or `opencode.jsonc` (create if it doesn't exist).
|
|
326
|
+
2. Add the configuration:
|
|
327
|
+
|
|
328
|
+
```json
|
|
329
|
+
{
|
|
330
|
+
"$schema": "https://opencode.ai/config.json",
|
|
331
|
+
"mcp": {
|
|
332
|
+
"clix-mcp-server": {
|
|
333
|
+
"type": "local",
|
|
334
|
+
"command": ["npx", "-y", "@clix-so/clix-mcp-server@latest"],
|
|
335
|
+
"enabled": true
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
3. Restart OpenCode or reload the configuration.
|
|
342
|
+
|
|
343
|
+
**Note**: The server name `clix-mcp-server` ensures tools appear as
|
|
344
|
+
`clix-mcp-server:*` (e.g., `clix-mcp-server:search_sdk`,
|
|
345
|
+
`clix-mcp-server:search_docs`). You can reference the server in prompts with
|
|
346
|
+
`use clix-mcp-server` or add it to your `AGENTS.md` file.
|
|
@@ -58,6 +58,30 @@ get_config_path() {
|
|
|
58
58
|
vscode)
|
|
59
59
|
echo "${home}/.vscode/mcp.json"
|
|
60
60
|
;;
|
|
61
|
+
amp)
|
|
62
|
+
# Amp uses VS Code settings.json format
|
|
63
|
+
# Check workspace settings first, then user settings
|
|
64
|
+
if [ -f ".vscode/settings.json" ]; then
|
|
65
|
+
echo ".vscode/settings.json"
|
|
66
|
+
elif [ -f "${home}/.vscode/settings.json" ]; then
|
|
67
|
+
echo "${home}/.vscode/settings.json"
|
|
68
|
+
else
|
|
69
|
+
# Default to workspace settings
|
|
70
|
+
echo ".vscode/settings.json"
|
|
71
|
+
fi
|
|
72
|
+
;;
|
|
73
|
+
opencode)
|
|
74
|
+
# OpenCode uses opencode.json or opencode.jsonc in project root
|
|
75
|
+
# Check for .jsonc first (preferred), then .json
|
|
76
|
+
if [ -f "opencode.jsonc" ]; then
|
|
77
|
+
echo "opencode.jsonc"
|
|
78
|
+
elif [ -f "opencode.json" ]; then
|
|
79
|
+
echo "opencode.json"
|
|
80
|
+
else
|
|
81
|
+
# Default to .jsonc
|
|
82
|
+
echo "opencode.jsonc"
|
|
83
|
+
fi
|
|
84
|
+
;;
|
|
61
85
|
*)
|
|
62
86
|
echo ""
|
|
63
87
|
;;
|
|
@@ -116,6 +140,112 @@ EOF
|
|
|
116
140
|
log "${GREEN}✔ Configured Clix MCP Server in Codex config${RESET}"
|
|
117
141
|
}
|
|
118
142
|
|
|
143
|
+
# Configure MCP for Amp (uses amp.mcpServers in VS Code settings.json)
|
|
144
|
+
configure_amp() {
|
|
145
|
+
local config_path="$1"
|
|
146
|
+
local config_dir=$(dirname "$config_path")
|
|
147
|
+
|
|
148
|
+
mkdir -p "$config_dir"
|
|
149
|
+
|
|
150
|
+
if [ ! -f "$config_path" ]; then
|
|
151
|
+
echo '{}' > "$config_path"
|
|
152
|
+
log "${GREEN}✔ Created Amp settings file${RESET}"
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# Check if already configured
|
|
156
|
+
if grep -q "clix-mcp-server" "$config_path" 2>/dev/null; then
|
|
157
|
+
log "${GREEN}✔ Clix MCP Server already configured in Amp${RESET}"
|
|
158
|
+
return 0
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
# Use node to safely update JSON
|
|
162
|
+
if command -v node &> /dev/null; then
|
|
163
|
+
node <<EOF
|
|
164
|
+
const fs = require('fs');
|
|
165
|
+
const path = '$config_path';
|
|
166
|
+
let config = {};
|
|
167
|
+
try {
|
|
168
|
+
const content = fs.readFileSync(path, 'utf8');
|
|
169
|
+
config = JSON.parse(content);
|
|
170
|
+
} catch (e) {
|
|
171
|
+
config = {};
|
|
172
|
+
}
|
|
173
|
+
if (!config['amp.mcpServers']) config['amp.mcpServers'] = {};
|
|
174
|
+
config['amp.mcpServers']['clix-mcp-server'] = {
|
|
175
|
+
command: 'npx',
|
|
176
|
+
args: ['-y', '@clix-so/clix-mcp-server@latest']
|
|
177
|
+
};
|
|
178
|
+
fs.writeFileSync(path, JSON.stringify(config, null, 2) + '\n');
|
|
179
|
+
EOF
|
|
180
|
+
log "${GREEN}✔ Configured Clix MCP Server in Amp${RESET}"
|
|
181
|
+
else
|
|
182
|
+
log "${YELLOW}⚠️ Node.js not found. Please manually add to $config_path:${RESET}"
|
|
183
|
+
log "${BLUE}{${RESET}"
|
|
184
|
+
log "${BLUE} \"amp.mcpServers\": {${RESET}"
|
|
185
|
+
log "${BLUE} \"clix-mcp-server\": {${RESET}"
|
|
186
|
+
log "${BLUE} \"command\": \"npx\",${RESET}"
|
|
187
|
+
log "${BLUE} \"args\": [\"-y\", \"@clix-so/clix-mcp-server@latest\"]${RESET}"
|
|
188
|
+
log "${BLUE} }${RESET}"
|
|
189
|
+
log "${BLUE} }${RESET}"
|
|
190
|
+
log "${BLUE}}${RESET}"
|
|
191
|
+
fi
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
# Configure MCP for OpenCode (uses opencode.json/jsonc with mcp section)
|
|
195
|
+
configure_opencode() {
|
|
196
|
+
local config_path="$1"
|
|
197
|
+
|
|
198
|
+
if [ ! -f "$config_path" ]; then
|
|
199
|
+
# Create new opencode.jsonc file
|
|
200
|
+
cat > "$config_path" <<'EOF'
|
|
201
|
+
{
|
|
202
|
+
"$schema": "https://opencode.ai/config.json",
|
|
203
|
+
"mcp": {}
|
|
204
|
+
}
|
|
205
|
+
EOF
|
|
206
|
+
log "${GREEN}✔ Created OpenCode config file${RESET}"
|
|
207
|
+
fi
|
|
208
|
+
|
|
209
|
+
# Check if already configured
|
|
210
|
+
if grep -q "clix-mcp-server" "$config_path" 2>/dev/null; then
|
|
211
|
+
log "${GREEN}✔ Clix MCP Server already configured in OpenCode${RESET}"
|
|
212
|
+
return 0
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
# Use node to safely update JSON/JSONC
|
|
216
|
+
if command -v node &> /dev/null; then
|
|
217
|
+
node <<EOF
|
|
218
|
+
const fs = require('fs');
|
|
219
|
+
const path = '$config_path';
|
|
220
|
+
let content = fs.readFileSync(path, 'utf8');
|
|
221
|
+
// Remove comments for JSONC parsing (simple approach)
|
|
222
|
+
let jsonContent = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
|
|
223
|
+
let config = JSON.parse(jsonContent);
|
|
224
|
+
if (!config.mcp) config.mcp = {};
|
|
225
|
+
config.mcp['clix-mcp-server'] = {
|
|
226
|
+
type: 'local',
|
|
227
|
+
command: ['npx', '-y', '@clix-so/clix-mcp-server@latest'],
|
|
228
|
+
enabled: true
|
|
229
|
+
};
|
|
230
|
+
// Write back as JSONC if original was .jsonc, otherwise JSON
|
|
231
|
+
const isJsonc = path.endsWith('.jsonc');
|
|
232
|
+
fs.writeFileSync(path, JSON.stringify(config, null, 2) + '\n');
|
|
233
|
+
EOF
|
|
234
|
+
log "${GREEN}✔ Configured Clix MCP Server in OpenCode${RESET}"
|
|
235
|
+
else
|
|
236
|
+
log "${YELLOW}⚠️ Node.js not found. Please manually add to $config_path:${RESET}"
|
|
237
|
+
log "${BLUE}{${RESET}"
|
|
238
|
+
log "${BLUE} \"mcp\": {${RESET}"
|
|
239
|
+
log "${BLUE} \"clix-mcp-server\": {${RESET}"
|
|
240
|
+
log "${BLUE} \"type\": \"local\",${RESET}"
|
|
241
|
+
log "${BLUE} \"command\": [\"npx\", \"-y\", \"@clix-so/clix-mcp-server@latest\"],${RESET}"
|
|
242
|
+
log "${BLUE} \"enabled\": true${RESET}"
|
|
243
|
+
log "${BLUE} }${RESET}"
|
|
244
|
+
log "${BLUE} }${RESET}"
|
|
245
|
+
log "${BLUE}}${RESET}"
|
|
246
|
+
fi
|
|
247
|
+
}
|
|
248
|
+
|
|
119
249
|
# Configure MCP for JSON-based clients
|
|
120
250
|
configure_json_client() {
|
|
121
251
|
local config_path="$1"
|
|
@@ -163,6 +293,20 @@ EOF
|
|
|
163
293
|
|
|
164
294
|
# Auto-detect client
|
|
165
295
|
detect_client() {
|
|
296
|
+
# Check for OpenCode (check for opencode.json/jsonc or opencode command)
|
|
297
|
+
if [ -f "opencode.json" ] || [ -f "opencode.jsonc" ] || command -v opencode &> /dev/null; then
|
|
298
|
+
echo "opencode"
|
|
299
|
+
return
|
|
300
|
+
fi
|
|
301
|
+
|
|
302
|
+
# Check for Amp (check for amp.mcpServers in settings.json or amp command)
|
|
303
|
+
if command -v amp &> /dev/null || \
|
|
304
|
+
grep -q "amp.mcpServers" ".vscode/settings.json" 2>/dev/null || \
|
|
305
|
+
grep -q "amp.mcpServers" "${HOME}/.vscode/settings.json" 2>/dev/null; then
|
|
306
|
+
echo "amp"
|
|
307
|
+
return
|
|
308
|
+
fi
|
|
309
|
+
|
|
166
310
|
# Check for Codex
|
|
167
311
|
if [ -f "${HOME}/.codex/config.toml" ] || command -v codex &> /dev/null; then
|
|
168
312
|
echo "codex"
|
|
@@ -222,6 +366,10 @@ if [ "$detected_client" != "unknown" ]; then
|
|
|
222
366
|
|
|
223
367
|
if [ "$detected_client" = "codex" ]; then
|
|
224
368
|
configure_codex "$config_path"
|
|
369
|
+
elif [ "$detected_client" = "amp" ]; then
|
|
370
|
+
configure_amp "$config_path"
|
|
371
|
+
elif [ "$detected_client" = "opencode" ]; then
|
|
372
|
+
configure_opencode "$config_path"
|
|
225
373
|
else
|
|
226
374
|
configure_json_client "$config_path"
|
|
227
375
|
fi
|
|
@@ -235,6 +383,8 @@ if [ "$detected_client" != "unknown" ]; then
|
|
|
235
383
|
else
|
|
236
384
|
log "${YELLOW}⚠️ Could not auto-detect MCP client.${RESET}"
|
|
237
385
|
log "${BLUE}The package is ready to use. Configure manually:${RESET}"
|
|
386
|
+
log "${BLUE} - OpenCode: Add to opencode.json or opencode.jsonc${RESET}"
|
|
387
|
+
log "${BLUE} - Amp: Add to .vscode/settings.json or ~/.vscode/settings.json${RESET}"
|
|
238
388
|
log "${BLUE} - Codex: Add to ~/.codex/config.toml${RESET}"
|
|
239
389
|
log "${BLUE} - Cursor: Add to .cursor/mcp.json or ~/.cursor/mcp.json${RESET}"
|
|
240
390
|
log "${BLUE} - Claude Desktop: Add to config file${RESET}"
|