cxg-workflow 0.1.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.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +266 -0
  3. package/README.zh-CN.md +266 -0
  4. package/bin/cxg.mjs +2 -0
  5. package/dist/cli.d.mts +1 -0
  6. package/dist/cli.d.ts +1 -0
  7. package/dist/cli.mjs +47 -0
  8. package/dist/index.d.mts +133 -0
  9. package/dist/index.d.ts +133 -0
  10. package/dist/index.mjs +6 -0
  11. package/dist/shared/cxg-workflow.BdjkxkKP.mjs +701 -0
  12. package/package.json +68 -0
  13. package/templates/prompts/cxg-analyze.md +94 -0
  14. package/templates/prompts/cxg-commit.md +88 -0
  15. package/templates/prompts/cxg-debug.md +111 -0
  16. package/templates/prompts/cxg-enhance.md +83 -0
  17. package/templates/prompts/cxg-execute.md +74 -0
  18. package/templates/prompts/cxg-feat.md +85 -0
  19. package/templates/prompts/cxg-init.md +96 -0
  20. package/templates/prompts/cxg-optimize.md +88 -0
  21. package/templates/prompts/cxg-plan.md +116 -0
  22. package/templates/prompts/cxg-review.md +99 -0
  23. package/templates/prompts/cxg-test.md +72 -0
  24. package/templates/prompts/cxg-workflow.md +154 -0
  25. package/templates/roles/codex/analyzer.md +50 -0
  26. package/templates/roles/codex/architect.md +46 -0
  27. package/templates/roles/codex/reviewer.md +70 -0
  28. package/templates/skills/cxg/analyze/SKILL.md +60 -0
  29. package/templates/skills/cxg/commit/SKILL.md +53 -0
  30. package/templates/skills/cxg/debug/SKILL.md +63 -0
  31. package/templates/skills/cxg/enhance/SKILL.md +42 -0
  32. package/templates/skills/cxg/execute/SKILL.md +51 -0
  33. package/templates/skills/cxg/feat/SKILL.md +62 -0
  34. package/templates/skills/cxg/init/SKILL.md +44 -0
  35. package/templates/skills/cxg/optimize/SKILL.md +59 -0
  36. package/templates/skills/cxg/plan/SKILL.md +70 -0
  37. package/templates/skills/cxg/review/SKILL.md +55 -0
  38. package/templates/skills/cxg/test/SKILL.md +44 -0
  39. package/templates/skills/cxg/workflow/SKILL.md +108 -0
@@ -0,0 +1,701 @@
1
+ import fs from 'fs-extra';
2
+ import { homedir } from 'node:os';
3
+ import { join, dirname } from 'pathe';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { stringify, parse } from 'smol-toml';
6
+
7
+ const version = "0.1.2";
8
+
9
+ function isWindows() {
10
+ return process.platform === "win32";
11
+ }
12
+ function normalizePath(p) {
13
+ return p.replace(/\\/g, "/");
14
+ }
15
+
16
+ const CODEX_HOME = join(homedir(), ".codex");
17
+ const CXG_DIR = join(CODEX_HOME, ".cxg");
18
+ const CONFIG_FILE = join(CXG_DIR, "config.toml");
19
+ function getCodexHome() {
20
+ return CODEX_HOME;
21
+ }
22
+ function getCxgDir() {
23
+ return CXG_DIR;
24
+ }
25
+ function getConfigPath() {
26
+ return CONFIG_FILE;
27
+ }
28
+ async function ensureCxgDir() {
29
+ await fs.ensureDir(CXG_DIR);
30
+ }
31
+ async function readCxgConfig() {
32
+ try {
33
+ if (await fs.pathExists(CONFIG_FILE)) {
34
+ const content = await fs.readFile(CONFIG_FILE, "utf-8");
35
+ return parse(content);
36
+ }
37
+ } catch {
38
+ }
39
+ return null;
40
+ }
41
+ async function writeCxgConfig(config) {
42
+ await ensureCxgDir();
43
+ const tmpPath = `${CONFIG_FILE}.tmp`;
44
+ await fs.writeFile(tmpPath, stringify(config), "utf-8");
45
+ await fs.rename(tmpPath, CONFIG_FILE);
46
+ }
47
+ function createDefaultConfig(options) {
48
+ return {
49
+ general: {
50
+ version: version,
51
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
52
+ },
53
+ runtime: {
54
+ backend: "codex",
55
+ lite_mode: options?.liteMode || false
56
+ },
57
+ paths: {
58
+ prompts: join(CODEX_HOME, "prompts"),
59
+ skills: join(CODEX_HOME, "skills", "cxg"),
60
+ roles: join(CXG_DIR, "roles", "codex"),
61
+ wrapper: join(CODEX_HOME, "bin", isWindows() ? "codeagent-wrapper.exe" : "codeagent-wrapper")
62
+ },
63
+ commands: {
64
+ installed: []
65
+ },
66
+ mcp: {
67
+ provider: options?.mcpProvider || "skip"
68
+ }
69
+ };
70
+ }
71
+
72
+ const ALL_COMMANDS = [
73
+ "cxg-workflow",
74
+ "cxg-plan",
75
+ "cxg-execute",
76
+ "cxg-feat",
77
+ "cxg-analyze",
78
+ "cxg-debug",
79
+ "cxg-optimize",
80
+ "cxg-test",
81
+ "cxg-review",
82
+ "cxg-enhance",
83
+ "cxg-commit",
84
+ "cxg-init"
85
+ ];
86
+ const WORKFLOW_CONFIGS = [
87
+ { id: "cxg-workflow", name: "\u4E3B\u5DE5\u4F5C\u6D41", nameEn: "Main Workflow", category: "core", description: "5\u9636\u6BB5\u5355\u6A21\u578B\u5F00\u53D1\u4E3B\u6D41\u7A0B\uFF08\u7814\u7A76\u2192\u8BA1\u5212\u2192\u6267\u884C\u2192\u4F18\u5316\u2192\u8BC4\u5BA1\uFF09", descriptionEn: "5-phase single-model workflow", order: 1 },
88
+ { id: "cxg-plan", name: "\u89C4\u5212", nameEn: "Plan", category: "core", description: "\u751F\u6210\u5B9E\u65BD\u8BA1\u5212", descriptionEn: "Generate implementation plan", order: 2 },
89
+ { id: "cxg-execute", name: "\u6267\u884C", nameEn: "Execute", category: "core", description: "\u6839\u636E\u8BA1\u5212\u6267\u884C\u5B9E\u73B0", descriptionEn: "Execute from approved plan", order: 3 },
90
+ { id: "cxg-feat", name: "\u529F\u80FD\u5F00\u53D1", nameEn: "Feature", category: "development", description: "\u667A\u80FD\u529F\u80FD\u5F00\u53D1", descriptionEn: "Smart feature development", order: 4 },
91
+ { id: "cxg-analyze", name: "\u6280\u672F\u5206\u6790", nameEn: "Analyze", category: "development", description: "\u53EA\u5206\u6790\u4E0D\u6539\u52A8\u4EE3\u7801", descriptionEn: "Analysis without code changes", order: 5 },
92
+ { id: "cxg-debug", name: "\u8C03\u8BD5\u4FEE\u590D", nameEn: "Debug", category: "development", description: "\u95EE\u9898\u5B9A\u4F4D\u4E0E\u4FEE\u590D", descriptionEn: "Debug and fix", order: 6 },
93
+ { id: "cxg-optimize", name: "\u6027\u80FD\u4F18\u5316", nameEn: "Optimize", category: "development", description: "\u6027\u80FD\u4E0E\u8D44\u6E90\u4F18\u5316", descriptionEn: "Performance optimization", order: 7 },
94
+ { id: "cxg-test", name: "\u6D4B\u8BD5\u751F\u6210", nameEn: "Test", category: "quality", description: "\u6D4B\u8BD5\u8BBE\u8BA1\u4E0E\u751F\u6210", descriptionEn: "Test generation", order: 8 },
95
+ { id: "cxg-review", name: "\u4EE3\u7801\u5BA1\u67E5", nameEn: "Review", category: "quality", description: "\u8D28\u91CF\u4E0E\u5B89\u5168\u5BA1\u67E5", descriptionEn: "Code quality review", order: 9 },
96
+ { id: "cxg-enhance", name: "Prompt \u589E\u5F3A", nameEn: "Enhance", category: "quality", description: "\u9700\u6C42\u7ED3\u6784\u5316\u589E\u5F3A", descriptionEn: "Prompt enhancement", order: 10 },
97
+ { id: "cxg-commit", name: "\u63D0\u4EA4\u4FE1\u606F", nameEn: "Commit", category: "delivery", description: "Conventional Commit \u751F\u6210", descriptionEn: "Commit message generation", order: 11 },
98
+ { id: "cxg-init", name: "\u4E0A\u4E0B\u6587\u521D\u59CB\u5316", nameEn: "Init Context", category: "bootstrap", description: "\u521D\u59CB\u5316 AGENTS.md", descriptionEn: "Initialize AGENTS.md context", order: 12 }
99
+ ];
100
+ const GITHUB_REPO = "fengshao1227/ccg-workflow";
101
+ const RELEASE_TAG = "preset";
102
+ const BINARY_DOWNLOAD_URL = `https://github.com/${GITHUB_REPO}/releases/download/${RELEASE_TAG}`;
103
+
104
+ function resolveBinaryName() {
105
+ const platform = process.platform;
106
+ const arch = process.arch;
107
+ if (platform === "darwin") {
108
+ return arch === "arm64" ? "codeagent-wrapper-darwin-arm64" : "codeagent-wrapper-darwin-amd64";
109
+ }
110
+ if (platform === "linux") {
111
+ return arch === "arm64" ? "codeagent-wrapper-linux-arm64" : "codeagent-wrapper-linux-amd64";
112
+ }
113
+ if (platform === "win32") {
114
+ return arch === "arm64" ? "codeagent-wrapper-windows-arm64.exe" : "codeagent-wrapper-windows-amd64.exe";
115
+ }
116
+ throw new Error(`Unsupported platform: ${platform}/${arch}`);
117
+ }
118
+ async function downloadBinary(binaryName, destPath) {
119
+ const url = `${BINARY_DOWNLOAD_URL}/${binaryName}`;
120
+ const response = await fetch(url, { redirect: "follow" });
121
+ if (!response.ok) {
122
+ return false;
123
+ }
124
+ const buffer = Buffer.from(await response.arrayBuffer());
125
+ await fs.writeFile(destPath, buffer);
126
+ if (!isWindows()) {
127
+ await fs.chmod(destPath, 493);
128
+ }
129
+ return true;
130
+ }
131
+ async function verifyBinary(binaryPath) {
132
+ try {
133
+ const { execSync } = await import('node:child_process');
134
+ execSync(`"${binaryPath}" --version`, { stdio: "pipe" });
135
+ return true;
136
+ } catch {
137
+ return false;
138
+ }
139
+ }
140
+
141
+ function injectTemplateVariables(content, config) {
142
+ let processed = content;
143
+ const liteModeFlag = config.liteMode ? "--lite " : "";
144
+ processed = processed.replace(/\{\{LITE_MODE_FLAG\}\}/g, liteModeFlag);
145
+ const mcpProvider = config.mcpProvider || "skip";
146
+ if (mcpProvider === "skip") {
147
+ processed = processed.replace(/\{\{MCP_SEARCH_TOOL\}\}/g, "Glob + Grep");
148
+ processed = processed.replace(/\{\{MCP_SEARCH_PARAM\}\}/g, "");
149
+ } else if (mcpProvider === "contextweaver") {
150
+ processed = processed.replace(/\{\{MCP_SEARCH_TOOL\}\}/g, "mcp__contextweaver__codebase-retrieval");
151
+ processed = processed.replace(/\{\{MCP_SEARCH_PARAM\}\}/g, "information_request");
152
+ } else {
153
+ processed = processed.replace(/\{\{MCP_SEARCH_TOOL\}\}/g, "mcp__ace-tool__search_context");
154
+ processed = processed.replace(/\{\{MCP_SEARCH_PARAM\}\}/g, "query");
155
+ }
156
+ return processed;
157
+ }
158
+ function replaceHomePathsInTemplate(content, codexHome) {
159
+ const userHome = homedir();
160
+ const cxgDir = join(codexHome, ".cxg");
161
+ const rolesDir = join(cxgDir, "roles", "codex");
162
+ const binDir = join(codexHome, "bin");
163
+ const norm = (path) => normalizePath(path);
164
+ let processed = content;
165
+ const wrapperName = isWindows() ? "codeagent-wrapper.exe" : "codeagent-wrapper";
166
+ const wrapperPath = `${norm(binDir)}/${wrapperName}`;
167
+ processed = processed.replace(/\{\{WRAPPER_BIN\}\}/g, wrapperPath);
168
+ processed = processed.replace(/\{\{ROLE_ANALYZER\}\}/g, `${norm(rolesDir)}/analyzer.md`);
169
+ processed = processed.replace(/\{\{ROLE_ARCHITECT\}\}/g, `${norm(rolesDir)}/architect.md`);
170
+ processed = processed.replace(/\{\{ROLE_REVIEWER\}\}/g, `${norm(rolesDir)}/reviewer.md`);
171
+ processed = processed.replace(/~\/\.codex\/\.cxg/g, norm(cxgDir));
172
+ processed = processed.replace(/~\/\.codex\/bin/g, norm(binDir));
173
+ processed = processed.replace(/~\/\.codex/g, norm(codexHome));
174
+ processed = processed.replace(/~\//g, `${norm(userHome)}/`);
175
+ return processed;
176
+ }
177
+
178
+ const __filename$1 = fileURLToPath(import.meta.url);
179
+ const __dirname$1 = dirname(__filename$1);
180
+ function findPackageRoot(startDir) {
181
+ let dir = startDir;
182
+ for (let i = 0; i < 5; i++) {
183
+ if (fs.existsSync(join(dir, "package.json"))) {
184
+ return dir;
185
+ }
186
+ dir = dirname(dir);
187
+ }
188
+ return startDir;
189
+ }
190
+ const PACKAGE_ROOT = findPackageRoot(__dirname$1);
191
+ function getWorkflowConfigs() {
192
+ return [...WORKFLOW_CONFIGS].sort((a, b) => a.order - b.order);
193
+ }
194
+ function getAllCommandIds() {
195
+ return [...ALL_COMMANDS];
196
+ }
197
+ async function installCxg(options = {}) {
198
+ const { force = false, liteMode = false, mcpProvider = "skip" } = options;
199
+ const codexHome = join(homedir(), ".codex");
200
+ const promptsDir = join(codexHome, "prompts");
201
+ const skillsDir = join(codexHome, "skills", "cxg");
202
+ const rolesDir = join(codexHome, ".cxg", "roles", "codex");
203
+ const binDir = join(codexHome, "bin");
204
+ const templateDir = join(PACKAGE_ROOT, "templates");
205
+ const installConfig = { liteMode, mcpProvider };
206
+ const result = {
207
+ success: true,
208
+ installedPrompts: [],
209
+ installedSkills: [],
210
+ installedRoles: [],
211
+ errors: []
212
+ };
213
+ await fs.ensureDir(promptsDir);
214
+ await fs.ensureDir(skillsDir);
215
+ await fs.ensureDir(rolesDir);
216
+ await fs.ensureDir(binDir);
217
+ const promptsTemplateDir = join(templateDir, "prompts");
218
+ if (await fs.pathExists(promptsTemplateDir)) {
219
+ for (const cmd of ALL_COMMANDS) {
220
+ const srcFile = join(promptsTemplateDir, `${cmd}.md`);
221
+ const destFile = join(promptsDir, `${cmd}.md`);
222
+ try {
223
+ if (await fs.pathExists(srcFile)) {
224
+ if (force || !await fs.pathExists(destFile)) {
225
+ let content = await fs.readFile(srcFile, "utf-8");
226
+ content = injectTemplateVariables(content, installConfig);
227
+ content = replaceHomePathsInTemplate(content, codexHome);
228
+ await fs.writeFile(destFile, content, "utf-8");
229
+ result.installedPrompts.push(cmd);
230
+ }
231
+ }
232
+ } catch (error) {
233
+ result.errors.push(`Failed to install prompt ${cmd}: ${error}`);
234
+ result.success = false;
235
+ }
236
+ }
237
+ }
238
+ const skillsTemplateDir = join(templateDir, "skills", "cxg");
239
+ if (await fs.pathExists(skillsTemplateDir)) {
240
+ try {
241
+ await fs.copy(skillsTemplateDir, skillsDir, {
242
+ overwrite: force,
243
+ errorOnExist: false
244
+ });
245
+ const replacePathsInDir = async (dir) => {
246
+ const entries = await fs.readdir(dir, { withFileTypes: true });
247
+ for (const entry of entries) {
248
+ const fullPath = join(dir, entry.name);
249
+ if (entry.isDirectory()) {
250
+ await replacePathsInDir(fullPath);
251
+ } else if (entry.name.endsWith(".md")) {
252
+ const original = await fs.readFile(fullPath, "utf-8");
253
+ let processed = injectTemplateVariables(original, installConfig);
254
+ processed = replaceHomePathsInTemplate(processed, codexHome);
255
+ if (processed !== original) {
256
+ await fs.writeFile(fullPath, processed, "utf-8");
257
+ }
258
+ }
259
+ }
260
+ };
261
+ await replacePathsInDir(skillsDir);
262
+ const countSkills = async (dir) => {
263
+ const skills = [];
264
+ const entries = await fs.readdir(dir, { withFileTypes: true });
265
+ for (const entry of entries) {
266
+ if (entry.isDirectory()) {
267
+ const skillFile = join(dir, entry.name, "SKILL.md");
268
+ if (await fs.pathExists(skillFile)) {
269
+ skills.push(entry.name);
270
+ }
271
+ }
272
+ }
273
+ return skills;
274
+ };
275
+ result.installedSkills = await countSkills(skillsDir);
276
+ } catch (error) {
277
+ result.errors.push(`Failed to install skills: ${error}`);
278
+ result.success = false;
279
+ }
280
+ }
281
+ const rolesTemplateDir = join(templateDir, "roles", "codex");
282
+ if (await fs.pathExists(rolesTemplateDir)) {
283
+ try {
284
+ const files = await fs.readdir(rolesTemplateDir);
285
+ for (const file of files) {
286
+ if (file.endsWith(".md")) {
287
+ const srcFile = join(rolesTemplateDir, file);
288
+ const destFile = join(rolesDir, file);
289
+ if (force || !await fs.pathExists(destFile)) {
290
+ const content = await fs.readFile(srcFile, "utf-8");
291
+ const processed = replaceHomePathsInTemplate(content, codexHome);
292
+ await fs.writeFile(destFile, processed, "utf-8");
293
+ result.installedRoles.push(file.replace(".md", ""));
294
+ }
295
+ }
296
+ }
297
+ } catch (error) {
298
+ result.errors.push(`Failed to install roles: ${error}`);
299
+ result.success = false;
300
+ }
301
+ }
302
+ try {
303
+ const binaryName = resolveBinaryName();
304
+ const destBinary = join(binDir, isWindows() ? "codeagent-wrapper.exe" : "codeagent-wrapper");
305
+ const installed = await downloadBinary(binaryName, destBinary);
306
+ if (installed) {
307
+ const verified = await verifyBinary(destBinary);
308
+ if (verified) {
309
+ result.binInstalled = true;
310
+ result.binPath = binDir;
311
+ } else {
312
+ result.errors.push("Binary verification failed");
313
+ result.success = false;
314
+ }
315
+ } else {
316
+ result.errors.push(`Failed to download binary: ${binaryName}`);
317
+ result.success = false;
318
+ }
319
+ } catch (error) {
320
+ result.errors.push(`Failed to install codeagent-wrapper: ${error}`);
321
+ result.success = false;
322
+ }
323
+ return result;
324
+ }
325
+ async function uninstallCxg() {
326
+ const codexHome = join(homedir(), ".codex");
327
+ const promptsDir = join(codexHome, "prompts");
328
+ const skillsDir = join(codexHome, "skills", "cxg");
329
+ const rolesDir = join(codexHome, ".cxg", "roles");
330
+ const cxgDir = join(codexHome, ".cxg");
331
+ const binDir = join(codexHome, "bin");
332
+ const result = {
333
+ success: true,
334
+ removedPrompts: [],
335
+ removedSkills: [],
336
+ removedRoles: [],
337
+ removedBin: false,
338
+ errors: []
339
+ };
340
+ if (await fs.pathExists(promptsDir)) {
341
+ try {
342
+ const files = await fs.readdir(promptsDir);
343
+ for (const file of files) {
344
+ if (file.startsWith("cxg-") && file.endsWith(".md")) {
345
+ await fs.remove(join(promptsDir, file));
346
+ result.removedPrompts.push(file.replace(".md", ""));
347
+ }
348
+ }
349
+ } catch (error) {
350
+ result.errors.push(`Failed to remove prompts: ${error}`);
351
+ result.success = false;
352
+ }
353
+ }
354
+ if (await fs.pathExists(skillsDir)) {
355
+ try {
356
+ const entries = await fs.readdir(skillsDir, { withFileTypes: true });
357
+ for (const entry of entries) {
358
+ if (entry.isDirectory()) {
359
+ result.removedSkills.push(entry.name);
360
+ }
361
+ }
362
+ await fs.remove(skillsDir);
363
+ } catch (error) {
364
+ result.errors.push(`Failed to remove skills: ${error}`);
365
+ result.success = false;
366
+ }
367
+ }
368
+ if (await fs.pathExists(cxgDir)) {
369
+ try {
370
+ if (await fs.pathExists(rolesDir)) {
371
+ const files = await fs.readdir(join(rolesDir, "codex")).catch(() => []);
372
+ for (const file of files) {
373
+ if (typeof file === "string") {
374
+ result.removedRoles.push(file.replace(".md", ""));
375
+ }
376
+ }
377
+ }
378
+ await fs.remove(cxgDir);
379
+ } catch (error) {
380
+ result.errors.push(`Failed to remove .cxg directory: ${error}`);
381
+ result.success = false;
382
+ }
383
+ }
384
+ if (await fs.pathExists(binDir)) {
385
+ try {
386
+ const wrapperName = isWindows() ? "codeagent-wrapper.exe" : "codeagent-wrapper";
387
+ const wrapperPath = join(binDir, wrapperName);
388
+ if (await fs.pathExists(wrapperPath)) {
389
+ await fs.remove(wrapperPath);
390
+ result.removedBin = true;
391
+ }
392
+ } catch (error) {
393
+ result.errors.push(`Failed to remove binary: ${error}`);
394
+ result.success = false;
395
+ }
396
+ }
397
+ return result;
398
+ }
399
+
400
+ const CODEX_CONFIG_PATH = join(homedir(), ".codex", "config.toml");
401
+ async function readCodexConfig() {
402
+ if (await fs.pathExists(CODEX_CONFIG_PATH)) {
403
+ const content = await fs.readFile(CODEX_CONFIG_PATH, "utf-8");
404
+ return parse(content);
405
+ }
406
+ return {};
407
+ }
408
+ async function writeCodexConfig(config) {
409
+ const dir = join(homedir(), ".codex");
410
+ await fs.ensureDir(dir);
411
+ const tmpPath = `${CODEX_CONFIG_PATH}.tmp`;
412
+ await fs.writeFile(tmpPath, stringify(config), "utf-8");
413
+ await fs.rename(tmpPath, CODEX_CONFIG_PATH);
414
+ }
415
+ async function installAceTool(config) {
416
+ try {
417
+ const codexConfig = await readCodexConfig();
418
+ if (!codexConfig.mcp_servers) {
419
+ codexConfig.mcp_servers = {};
420
+ }
421
+ const args = ["-y", "ace-tool@latest"];
422
+ if (config.baseUrl) {
423
+ args.push("--base-url", config.baseUrl);
424
+ }
425
+ if (config.token) {
426
+ args.push("--token", config.token);
427
+ }
428
+ codexConfig.mcp_servers["ace-tool"] = {
429
+ type: "stdio",
430
+ command: "npx",
431
+ args
432
+ };
433
+ await writeCodexConfig(codexConfig);
434
+ return { success: true, message: "ace-tool MCP configured in ~/.codex/config.toml" };
435
+ } catch (error) {
436
+ return { success: false, message: `Failed to configure ace-tool: ${error}` };
437
+ }
438
+ }
439
+ async function installContextWeaver(config) {
440
+ try {
441
+ const contextWeaverDir = join(homedir(), ".contextweaver");
442
+ await fs.ensureDir(contextWeaverDir);
443
+ const envContent = `# ContextWeaver config (auto-generated by CXG)
444
+ EMBEDDINGS_API_KEY=${config.siliconflowApiKey}
445
+ EMBEDDINGS_BASE_URL=https://api.siliconflow.cn/v1/embeddings
446
+ EMBEDDINGS_MODEL=Qwen/Qwen3-Embedding-8B
447
+ EMBEDDINGS_MAX_CONCURRENCY=10
448
+ EMBEDDINGS_DIMENSIONS=1024
449
+ RERANK_API_KEY=${config.siliconflowApiKey}
450
+ RERANK_BASE_URL=https://api.siliconflow.cn/v1/rerank
451
+ RERANK_MODEL=Qwen/Qwen3-Reranker-8B
452
+ RERANK_TOP_N=20
453
+ `;
454
+ const envPath = join(contextWeaverDir, ".env");
455
+ await fs.writeFile(envPath, envContent, { encoding: "utf-8", mode: 384 });
456
+ const codexConfig = await readCodexConfig();
457
+ if (!codexConfig.mcp_servers) {
458
+ codexConfig.mcp_servers = {};
459
+ }
460
+ codexConfig.mcp_servers.contextweaver = {
461
+ type: "stdio",
462
+ command: "contextweaver",
463
+ args: ["mcp"]
464
+ };
465
+ await writeCodexConfig(codexConfig);
466
+ return { success: true, message: "ContextWeaver MCP configured in ~/.codex/config.toml" };
467
+ } catch (error) {
468
+ return { success: false, message: `Failed to configure ContextWeaver: ${error}` };
469
+ }
470
+ }
471
+ async function uninstallMcpServer(id) {
472
+ try {
473
+ const codexConfig = await readCodexConfig();
474
+ if (codexConfig.mcp_servers?.[id]) {
475
+ delete codexConfig.mcp_servers[id];
476
+ await writeCodexConfig(codexConfig);
477
+ }
478
+ return { success: true, message: `${id} MCP removed from config` };
479
+ } catch (error) {
480
+ return { success: false, message: `Failed to uninstall ${id}: ${error}` };
481
+ }
482
+ }
483
+
484
+ async function init(options = {}) {
485
+ console.log();
486
+ console.log(` CXG Workflow v${version}`);
487
+ console.log(` Codex \u5355\u6A21\u578B\u534F\u4F5C\u5DE5\u4F5C\u6D41`);
488
+ console.log();
489
+ const { force = false, liteMode = false, mcpProvider = "skip" } = options;
490
+ console.log(" [1/3] \u5B89\u88C5\u5DE5\u4F5C\u6D41\u7EC4\u4EF6...");
491
+ const result = await installCxg({ force, liteMode, mcpProvider });
492
+ if (result.installedPrompts.length > 0) {
493
+ console.log(` \u2713 Custom Prompts: ${result.installedPrompts.length} \u4E2A`);
494
+ }
495
+ if (result.installedSkills.length > 0) {
496
+ console.log(` \u2713 Skills: ${result.installedSkills.length} \u4E2A`);
497
+ }
498
+ if (result.installedRoles.length > 0) {
499
+ console.log(` \u2713 \u89D2\u8272\u63D0\u793A\u8BCD: ${result.installedRoles.join(", ")}`);
500
+ }
501
+ if (result.binInstalled) {
502
+ console.log(` \u2713 codeagent-wrapper \u2192 ${result.binPath}`);
503
+ }
504
+ if (mcpProvider !== "skip") {
505
+ console.log();
506
+ console.log(" [2/3] \u914D\u7F6E MCP \u4EE3\u7801\u68C0\u7D22...");
507
+ if (mcpProvider === "ace-tool") {
508
+ const aceResult = await installAceTool({});
509
+ if (aceResult.success) {
510
+ console.log(` \u2713 ${aceResult.message}`);
511
+ } else {
512
+ console.log(` \u2717 ${aceResult.message}`);
513
+ }
514
+ } else if (mcpProvider === "contextweaver") {
515
+ console.log(` \u26A0 ContextWeaver \u9700\u8981 SiliconFlow API Key`);
516
+ console.log(` \u8BF7\u624B\u52A8\u914D\u7F6E: ~/.contextweaver/.env`);
517
+ }
518
+ } else {
519
+ console.log();
520
+ console.log(" [2/3] MCP \u914D\u7F6E (\u5DF2\u8DF3\u8FC7)");
521
+ console.log(" \u63D0\u793A: \u4F7F\u7528 --mcp ace-tool \u6216 --mcp contextweaver \u542F\u7528\u4EE3\u7801\u68C0\u7D22");
522
+ }
523
+ console.log();
524
+ console.log(" [3/3] \u4FDD\u5B58\u914D\u7F6E...");
525
+ const config = createDefaultConfig({ mcpProvider, liteMode });
526
+ config.commands.installed = result.installedPrompts;
527
+ await writeCxgConfig(config);
528
+ console.log(" \u2713 ~/.codex/.cxg/config.toml");
529
+ console.log();
530
+ if (result.errors.length > 0) {
531
+ console.log(" \u26A0 \u5B89\u88C5\u5B8C\u6210\uFF0C\u4F46\u6709\u4EE5\u4E0B\u9519\u8BEF:");
532
+ for (const error of result.errors) {
533
+ console.log(` \u2717 ${error}`);
534
+ }
535
+ } else {
536
+ console.log(" \u2713 \u5B89\u88C5\u5B8C\u6210!");
537
+ }
538
+ console.log();
539
+ console.log(" \u5DF2\u5B89\u88C5\u547D\u4EE4:");
540
+ for (const cmd of result.installedPrompts) {
541
+ console.log(` /${cmd}`);
542
+ }
543
+ console.log();
544
+ console.log(" \u4F7F\u7528\u65B9\u6CD5: \u5728 Codex CLI \u4E2D\u8F93\u5165 /<\u547D\u4EE4\u540D> \u8C03\u7528");
545
+ console.log();
546
+ }
547
+
548
+ async function uninstall() {
549
+ console.log();
550
+ console.log(" \u5378\u8F7D CXG Workflow...");
551
+ console.log();
552
+ const result = await uninstallCxg();
553
+ if (result.removedPrompts.length > 0) {
554
+ console.log(` \u2713 \u5DF2\u79FB\u9664 ${result.removedPrompts.length} \u4E2A Custom Prompts`);
555
+ }
556
+ if (result.removedSkills.length > 0) {
557
+ console.log(` \u2713 \u5DF2\u79FB\u9664 ${result.removedSkills.length} \u4E2A Skills`);
558
+ }
559
+ if (result.removedRoles.length > 0) {
560
+ console.log(` \u2713 \u5DF2\u79FB\u9664\u89D2\u8272\u63D0\u793A\u8BCD: ${result.removedRoles.join(", ")}`);
561
+ }
562
+ if (result.removedBin) {
563
+ console.log(" \u2713 \u5DF2\u79FB\u9664 codeagent-wrapper");
564
+ }
565
+ const mcpErrors = [];
566
+ const aceResult = await uninstallMcpServer("ace-tool");
567
+ if (!aceResult.success) {
568
+ mcpErrors.push(aceResult.message);
569
+ }
570
+ const cwResult = await uninstallMcpServer("contextweaver");
571
+ if (!cwResult.success) {
572
+ mcpErrors.push(cwResult.message);
573
+ }
574
+ if (mcpErrors.length > 0) {
575
+ console.log(" \u26A0 MCP \u6E05\u7406\u90E8\u5206\u5931\u8D25:");
576
+ for (const err of mcpErrors) {
577
+ console.log(` \u2717 ${err}`);
578
+ }
579
+ } else {
580
+ console.log(" \u2713 \u5DF2\u6E05\u7406 MCP \u914D\u7F6E");
581
+ }
582
+ const configPath = getConfigPath();
583
+ if (await fs.pathExists(configPath)) {
584
+ await fs.remove(configPath);
585
+ console.log(" \u2713 \u5DF2\u79FB\u9664\u914D\u7F6E\u6587\u4EF6");
586
+ }
587
+ console.log();
588
+ if (result.errors.length > 0) {
589
+ console.log(" \u26A0 \u5378\u8F7D\u5B8C\u6210\uFF0C\u4F46\u6709\u4EE5\u4E0B\u9519\u8BEF:");
590
+ for (const error of result.errors) {
591
+ console.log(` \u2717 ${error}`);
592
+ }
593
+ } else {
594
+ console.log(" \u2713 \u5378\u8F7D\u5B8C\u6210!");
595
+ }
596
+ console.log();
597
+ }
598
+
599
+ async function doctor() {
600
+ console.log();
601
+ console.log(` CXG Workflow Doctor v${version}`);
602
+ console.log();
603
+ const codexHome = join(homedir(), ".codex");
604
+ const results = [];
605
+ const config = await readCxgConfig();
606
+ results.push({
607
+ label: "\u914D\u7F6E\u6587\u4EF6 (~/.codex/.cxg/config.toml)",
608
+ ok: config !== null,
609
+ detail: config ? `v${config.general.version}` : "\u672A\u627E\u5230"
610
+ });
611
+ const promptsDir = join(codexHome, "prompts");
612
+ let promptCount = 0;
613
+ const missingPrompts = [];
614
+ for (const cmd of ALL_COMMANDS) {
615
+ const promptPath = join(promptsDir, `${cmd}.md`);
616
+ if (await fs.pathExists(promptPath)) {
617
+ promptCount++;
618
+ } else {
619
+ missingPrompts.push(cmd);
620
+ }
621
+ }
622
+ results.push({
623
+ label: `Custom Prompts (${promptCount}/${ALL_COMMANDS.length})`,
624
+ ok: promptCount === ALL_COMMANDS.length,
625
+ detail: missingPrompts.length > 0 ? `\u7F3A\u5931: ${missingPrompts.join(", ")}` : void 0
626
+ });
627
+ const skillsDir = join(codexHome, "skills", "cxg");
628
+ let skillCount = 0;
629
+ const missingSkills = [];
630
+ for (const cmd of ALL_COMMANDS) {
631
+ const shortName = cmd.replace("cxg-", "");
632
+ const skillPath = join(skillsDir, shortName, "SKILL.md");
633
+ if (await fs.pathExists(skillPath)) {
634
+ skillCount++;
635
+ } else {
636
+ missingSkills.push(shortName);
637
+ }
638
+ }
639
+ results.push({
640
+ label: `Skills (${skillCount}/${ALL_COMMANDS.length})`,
641
+ ok: skillCount === ALL_COMMANDS.length,
642
+ detail: missingSkills.length > 0 ? `\u7F3A\u5931: ${missingSkills.join(", ")}` : void 0
643
+ });
644
+ const rolesDir = join(codexHome, ".cxg", "roles", "codex");
645
+ const roleNames = ["analyzer", "architect", "reviewer"];
646
+ const missingRoles = [];
647
+ for (const role of roleNames) {
648
+ if (!await fs.pathExists(join(rolesDir, `${role}.md`))) {
649
+ missingRoles.push(role);
650
+ }
651
+ }
652
+ results.push({
653
+ label: `\u89D2\u8272\u63D0\u793A\u8BCD (${roleNames.length - missingRoles.length}/${roleNames.length})`,
654
+ ok: missingRoles.length === 0,
655
+ detail: missingRoles.length > 0 ? `\u7F3A\u5931: ${missingRoles.join(", ")}` : void 0
656
+ });
657
+ const wrapperName = isWindows() ? "codeagent-wrapper.exe" : "codeagent-wrapper";
658
+ const wrapperPath = join(codexHome, "bin", wrapperName);
659
+ const binExists = await fs.pathExists(wrapperPath);
660
+ let binVersion = "";
661
+ if (binExists) {
662
+ try {
663
+ const { execSync } = await import('node:child_process');
664
+ binVersion = execSync(`"${wrapperPath}" --version`, { stdio: "pipe", encoding: "utf-8" }).trim();
665
+ } catch {
666
+ binVersion = "(\u7248\u672C\u68C0\u6D4B\u5931\u8D25)";
667
+ }
668
+ }
669
+ results.push({
670
+ label: "codeagent-wrapper",
671
+ ok: binExists,
672
+ detail: binExists ? binVersion : "\u672A\u5B89\u88C5"
673
+ });
674
+ if (config?.mcp?.provider && config.mcp.provider !== "skip") {
675
+ const codexConfig = join(codexHome, "config.toml");
676
+ const codexConfigExists = await fs.pathExists(codexConfig);
677
+ results.push({
678
+ label: `MCP (${config.mcp.provider})`,
679
+ ok: codexConfigExists,
680
+ detail: codexConfigExists ? "\u5DF2\u914D\u7F6E" : "config.toml \u672A\u627E\u5230"
681
+ });
682
+ }
683
+ let allOk = true;
684
+ for (const r of results) {
685
+ const icon = r.ok ? "\u2713" : "\u2717";
686
+ const detail = r.detail ? ` \u2014 ${r.detail}` : "";
687
+ console.log(` ${icon} ${r.label}${detail}`);
688
+ if (!r.ok) {
689
+ allOk = false;
690
+ }
691
+ }
692
+ console.log();
693
+ if (allOk) {
694
+ console.log(" \u6240\u6709\u68C0\u67E5\u901A\u8FC7!");
695
+ } else {
696
+ console.log(" \u90E8\u5206\u68C0\u67E5\u672A\u901A\u8FC7\uFF0C\u8FD0\u884C npx cxg-workflow init --force \u4FEE\u590D");
697
+ }
698
+ console.log();
699
+ }
700
+
701
+ export { ALL_COMMANDS as A, WORKFLOW_CONFIGS as W, getCodexHome as a, getConfigPath as b, createDefaultConfig as c, doctor as d, getCxgDir as e, getWorkflowConfigs as f, getAllCommandIds as g, installAceTool as h, init as i, installContextWeaver as j, installCxg as k, uninstallCxg as l, uninstallMcpServer as m, readCxgConfig as r, uninstall as u, version as v, writeCxgConfig as w };