qwen-base 1.0.2 → 1.0.4
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/bin/install.js +66 -8
- package/package.json +1 -1
package/bin/install.js
CHANGED
|
@@ -4,6 +4,7 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const os = require('os');
|
|
6
6
|
const readline = require('readline');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
7
8
|
|
|
8
9
|
const green = '\x1b[32m';
|
|
9
10
|
const cyan = '\x1b[36m';
|
|
@@ -30,7 +31,6 @@ const args = process.argv.slice(2);
|
|
|
30
31
|
const hasGlobal = args.includes('--global') || args.includes('-g');
|
|
31
32
|
const hasLocal = args.includes('--local') || args.includes('-l');
|
|
32
33
|
const hasHelp = args.includes('--help') || args.includes('-h');
|
|
33
|
-
const skipTools = args.includes('--skip-tools');
|
|
34
34
|
|
|
35
35
|
function parseConfigDirArg() {
|
|
36
36
|
const idx = args.findIndex(arg => arg === '--config-dir' || arg === '-c');
|
|
@@ -76,6 +76,18 @@ function countFiles(dir) {
|
|
|
76
76
|
return count;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
function wireMcp(workspaceDir, mcpIndexPath) {
|
|
80
|
+
const mcpJsonPath = path.join(workspaceDir, '.mcp.json');
|
|
81
|
+
let mcpConfig = {};
|
|
82
|
+
if (fs.existsSync(mcpJsonPath)) {
|
|
83
|
+
try { mcpConfig = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf8')); } catch (e) {}
|
|
84
|
+
}
|
|
85
|
+
if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
|
|
86
|
+
const normalizedPath = mcpIndexPath.replace(/\\/g, '/');
|
|
87
|
+
mcpConfig.mcpServers['base-mcp'] = { command: 'node', args: [normalizedPath], type: 'stdio' };
|
|
88
|
+
fs.writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
|
|
89
|
+
}
|
|
90
|
+
|
|
79
91
|
console.log(banner);
|
|
80
92
|
|
|
81
93
|
if (hasHelp) {
|
|
@@ -85,7 +97,6 @@ if (hasHelp) {
|
|
|
85
97
|
${cyan}-g, --global${reset} Install globally (to Qwen config directory)
|
|
86
98
|
${cyan}-l, --local${reset} Install locally (to ./.qwen/ in current directory)
|
|
87
99
|
${cyan}-c, --config-dir <path>${reset} Specify custom Qwen config directory
|
|
88
|
-
${cyan}--skip-tools${reset} Skip OSS analysis tool installation
|
|
89
100
|
${cyan}-h, --help${reset} Show this help message
|
|
90
101
|
|
|
91
102
|
${yellow}Examples:${reset}
|
|
@@ -98,6 +109,7 @@ if (hasHelp) {
|
|
|
98
109
|
${yellow}What gets installed:${reset}
|
|
99
110
|
${cyan}commands/qwen-base/${reset} 11 slash commands
|
|
100
111
|
${cyan}base/ Framework (core, transform, domains, schemas, rules, tools)
|
|
112
|
+
${cyan}.mcp.json base-mcp server registration
|
|
101
113
|
`);
|
|
102
114
|
process.exit(0);
|
|
103
115
|
}
|
|
@@ -107,26 +119,27 @@ function install(isGlobal) {
|
|
|
107
119
|
const configDir = expandTilde(explicitConfigDir) || expandTilde(process.env.QWEN_CONFIG_DIR);
|
|
108
120
|
const globalDir = configDir || path.join(os.homedir(), '.qwen');
|
|
109
121
|
const qwenDir = isGlobal ? globalDir : path.join(process.cwd(), '.qwen');
|
|
110
|
-
const
|
|
122
|
+
const baseDest = path.join(qwenDir, 'base');
|
|
111
123
|
const cmdsDest = path.join(qwenDir, 'commands', 'qwen-base');
|
|
124
|
+
const workspaceRoot = isGlobal ? os.homedir() : process.cwd();
|
|
112
125
|
|
|
113
126
|
const locationLabel = isGlobal
|
|
114
127
|
? qwenDir.replace(os.homedir(), '~')
|
|
115
128
|
: qwenDir.replace(process.cwd(), '.');
|
|
116
129
|
|
|
117
|
-
if (fs.existsSync(
|
|
130
|
+
if (fs.existsSync(baseDest) || fs.existsSync(cmdsDest)) {
|
|
118
131
|
console.log(` ${yellow}Existing installation found at ${locationLabel}${reset}`);
|
|
119
132
|
console.log(` Updating...`);
|
|
120
|
-
if (fs.existsSync(
|
|
133
|
+
if (fs.existsSync(baseDest)) fs.rmSync(baseDest, { recursive: true, force: true });
|
|
121
134
|
if (fs.existsSync(cmdsDest)) fs.rmSync(cmdsDest, { recursive: true, force: true });
|
|
122
135
|
}
|
|
123
136
|
|
|
124
137
|
console.log(` Installing to ${cyan}${locationLabel}${reset}\n`);
|
|
125
138
|
|
|
126
|
-
// Copy framework (
|
|
139
|
+
// Copy framework (src/ → base/)
|
|
127
140
|
if (fs.existsSync(path.join(src, 'src'))) {
|
|
128
|
-
copyDir(path.join(src, 'src'),
|
|
129
|
-
console.log(` ${green}+${reset} base/ ${dim}(${countFiles(
|
|
141
|
+
copyDir(path.join(src, 'src'), baseDest);
|
|
142
|
+
console.log(` ${green}+${reset} base/ ${dim}(${countFiles(baseDest)} framework files)${reset}`);
|
|
130
143
|
}
|
|
131
144
|
|
|
132
145
|
// Copy commands
|
|
@@ -136,6 +149,51 @@ function install(isGlobal) {
|
|
|
136
149
|
console.log(` ${green}+${reset} commands/qwen-base/ ${dim}(${countFiles(cmdsDest)} commands)${reset}`);
|
|
137
150
|
}
|
|
138
151
|
|
|
152
|
+
// Wire BASE MCP server into .mcp.json
|
|
153
|
+
const mcpIndexPath = path.join(baseDest, 'packages', 'base-mcp', 'index.js');
|
|
154
|
+
if (fs.existsSync(mcpIndexPath)) {
|
|
155
|
+
wireMcp(workspaceRoot, mcpIndexPath);
|
|
156
|
+
console.log(` ${green}+${reset} Wired base-mcp in .mcp.json`);
|
|
157
|
+
|
|
158
|
+
// Install MCP dependencies
|
|
159
|
+
const mcpDir = path.join(baseDest, 'packages', 'base-mcp');
|
|
160
|
+
try {
|
|
161
|
+
execSync('npm install --production --silent', { cwd: mcpDir, stdio: 'pipe' });
|
|
162
|
+
console.log(` ${green}+${reset} MCP dependencies installed`);
|
|
163
|
+
} catch (e) {
|
|
164
|
+
console.log(` ${yellow}!${reset} MCP deps install failed — run cd ${mcpDir} && npm install${reset}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Wire BASE Python hooks into settings.json
|
|
169
|
+
const settingsPath = path.join(qwenDir, 'settings.json');
|
|
170
|
+
let settings = {};
|
|
171
|
+
if (fs.existsSync(settingsPath)) {
|
|
172
|
+
try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch (e) {}
|
|
173
|
+
}
|
|
174
|
+
if (!settings.hooks) settings.hooks = {};
|
|
175
|
+
|
|
176
|
+
const hookFiles = [
|
|
177
|
+
{ event: 'UserPromptSubmit', file: 'base-pulse-check.py' },
|
|
178
|
+
{ event: 'UserPromptSubmit', file: 'psmm-injector.py' },
|
|
179
|
+
{ event: 'SessionStart', file: 'satellite-detection.py' },
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
for (const hook of hookFiles) {
|
|
183
|
+
const hookPath = path.join(baseDest, 'hooks', hook.file).replace(/\\/g, '/');
|
|
184
|
+
const hookCommand = `python3 ${hookPath}`;
|
|
185
|
+
if (!settings.hooks[hook.event]) settings.hooks[hook.event] = [];
|
|
186
|
+
const exists = settings.hooks[hook.event].some(h =>
|
|
187
|
+
(h.command && h.command.includes(hook.file)) ||
|
|
188
|
+
(h.hooks && h.hooks.some(i => i.command && i.command.includes(hook.file)))
|
|
189
|
+
);
|
|
190
|
+
if (!exists) {
|
|
191
|
+
settings.hooks[hook.event].push({ hooks: [{ type: 'command', command: hookCommand }] });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
195
|
+
console.log(` ${green}+${reset} Wired BASE hooks in settings.json`);
|
|
196
|
+
|
|
139
197
|
console.log(`
|
|
140
198
|
${green}Done!${reset} Open Qwen Code and type ${cyan}/base${reset} to start.
|
|
141
199
|
`);
|