|
@@ -8,6 +8,9 @@ const { spawnSync } = require('child_process');
|
|
|
const ROOT = __dirname;
|
|
const ROOT = __dirname;
|
|
|
const EXCLUDED_ROOTS = new Set(['.claude', '.git', '.github', '.playwright-cli', '.vscode', 'coverage', 'dist', 'node_modules', 'output', 'outputs']);
|
|
const EXCLUDED_ROOTS = new Set(['.claude', '.git', '.github', '.playwright-cli', '.vscode', 'coverage', 'dist', 'node_modules', 'output', 'outputs']);
|
|
|
const EXCLUDED_FILES = new Set(['.env', '.env.local', '.npmrc', 'poll_reply.log', 'poll_state.json']);
|
|
const EXCLUDED_FILES = new Set(['.env', '.env.local', '.npmrc', 'poll_reply.log', 'poll_state.json']);
|
|
|
|
|
+const WORKSPACE_GITIGNORE_TEMPLATE = path.join(ROOT, 'templates', 'workspace.gitignore');
|
|
|
|
|
+const WORKSPACE_GITIGNORE_START = '# >>> qiwei-assistant managed ignores >>>';
|
|
|
|
|
+const WORKSPACE_GITIGNORE_END = '# <<< qiwei-assistant managed ignores <<<';
|
|
|
|
|
|
|
|
function usage() {
|
|
function usage() {
|
|
|
return [
|
|
return [
|
|
@@ -19,7 +22,7 @@ function usage() {
|
|
|
' fmode-qiwei workspace [客户项目目录] --smoke',
|
|
' fmode-qiwei workspace [客户项目目录] --smoke',
|
|
|
' fmode-qiwei preview [客户项目目录] [--no-open] [--port 4320]',
|
|
' fmode-qiwei preview [客户项目目录] [--no-open] [--port 4320]',
|
|
|
'',
|
|
'',
|
|
|
- 'workspace 模式会写入 .claude/plugins、.claude/skills 和项目级 .mcp.json。',
|
|
|
|
|
|
|
+ 'workspace 模式会写入 .claude/plugins、.claude/skills、项目级 .mcp.json,并补全 .gitignore。',
|
|
|
'preview 模式会启动工作台、检查当前状态并打开浏览器。',
|
|
'preview 模式会启动工作台、检查当前状态并打开浏览器。',
|
|
|
].join('\n');
|
|
].join('\n');
|
|
|
}
|
|
}
|
|
@@ -42,6 +45,7 @@ function assertRequiredFiles() {
|
|
|
'mcp/src/server.js',
|
|
'mcp/src/server.js',
|
|
|
'runtime/callback-service/src/index.mjs',
|
|
'runtime/callback-service/src/index.mjs',
|
|
|
'qiwei.runtime.config.example.mjs',
|
|
'qiwei.runtime.config.example.mjs',
|
|
|
|
|
+ 'templates/workspace.gitignore',
|
|
|
'skills/qiwei-dashboard/SKILL.md',
|
|
'skills/qiwei-dashboard/SKILL.md',
|
|
|
'skills/qiwei-goal-management/SKILL.md',
|
|
'skills/qiwei-goal-management/SKILL.md',
|
|
|
'skills/qiwei-real-estate-auto-reply/SKILL.md',
|
|
'skills/qiwei-real-estate-auto-reply/SKILL.md',
|
|
@@ -89,6 +93,23 @@ function copyTree(source, destination, filter = () => true) {
|
|
|
fs.copyFileSync(source, destination);
|
|
fs.copyFileSync(source, destination);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function mergeWorkspaceGitignore(target) {
|
|
|
|
|
+ const gitignorePath = path.join(target, '.gitignore');
|
|
|
|
|
+ const managedBlock = fs.readFileSync(WORKSPACE_GITIGNORE_TEMPLATE, 'utf8').trim();
|
|
|
|
|
+ let current = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf8') : '';
|
|
|
|
|
+ const start = current.indexOf(WORKSPACE_GITIGNORE_START);
|
|
|
|
|
+ const end = current.indexOf(WORKSPACE_GITIGNORE_END, start + WORKSPACE_GITIGNORE_START.length);
|
|
|
|
|
+
|
|
|
|
|
+ if (start >= 0 && end >= start) {
|
|
|
|
|
+ current = `${current.slice(0, start)}${managedBlock}${current.slice(end + WORKSPACE_GITIGNORE_END.length)}`;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const prefix = current.trimEnd();
|
|
|
|
|
+ current = `${prefix}${prefix ? '\n\n' : ''}${managedBlock}\n`;
|
|
|
|
|
+ }
|
|
|
|
|
+ fs.writeFileSync(gitignorePath, current.replace(/\n*$/, '\n'), 'utf8');
|
|
|
|
|
+ return gitignorePath;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function run(command, args, cwd, options = {}) {
|
|
function run(command, args, cwd, options = {}) {
|
|
|
const useCmd = process.platform === 'win32' && command === 'npm';
|
|
const useCmd = process.platform === 'win32' && command === 'npm';
|
|
|
const result = spawnSync(useCmd ? 'cmd.exe' : command, useCmd ? ['/d', '/s', '/c', 'npm', ...args] : args, {
|
|
const result = spawnSync(useCmd ? 'cmd.exe' : command, useCmd ? ['/d', '/s', '/c', 'npm', ...args] : args, {
|
|
@@ -104,6 +125,7 @@ function run(command, args, cwd, options = {}) {
|
|
|
function installWorkspace(targetInput, options = {}) {
|
|
function installWorkspace(targetInput, options = {}) {
|
|
|
const target = path.resolve(targetInput || process.cwd());
|
|
const target = path.resolve(targetInput || process.cwd());
|
|
|
fs.mkdirSync(target, { recursive: true });
|
|
fs.mkdirSync(target, { recursive: true });
|
|
|
|
|
+ mergeWorkspaceGitignore(target);
|
|
|
const pluginsRoot = path.join(target, '.claude', 'plugins');
|
|
const pluginsRoot = path.join(target, '.claude', 'plugins');
|
|
|
const skillsRoot = path.join(target, '.claude', 'skills');
|
|
const skillsRoot = path.join(target, '.claude', 'skills');
|
|
|
const pluginDir = path.join(pluginsRoot, 'qiwei-assistant');
|
|
const pluginDir = path.join(pluginsRoot, 'qiwei-assistant');
|