zhuge-workflow 0.1.0

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 (80) hide show
  1. package/dist/index.js +801 -0
  2. package/dist/index.js.map +1 -0
  3. package/package.json +61 -0
  4. package/templates/claude/CLAUDE-ccg.md +258 -0
  5. package/templates/claude/CLAUDE.md +106 -0
  6. package/templates/claude/commands/ccg/_context.md +152 -0
  7. package/templates/claude/commands/ccg/spec-impl.md +161 -0
  8. package/templates/claude/commands/ccg/spec-plan-trellis.md +239 -0
  9. package/templates/claude/commands/ccg/spec-plan.md +225 -0
  10. package/templates/claude/commands/ccg/spec-research.md +113 -0
  11. package/templates/claude/commands/ccg/spec-review.md +127 -0
  12. package/templates/claude/commands/developer/brainstorm.md +5 -0
  13. package/templates/claude/commands/developer/design-checklist.md +81 -0
  14. package/templates/claude/commands/developer/design-doc.md +188 -0
  15. package/templates/claude/commands/developer/requirement-doc.md +150 -0
  16. package/templates/claude/commands/developer/requirement-interrogate.md +71 -0
  17. package/templates/claude/commands/developer/status.md +55 -0
  18. package/templates/claude/rules/bash-style.md +46 -0
  19. package/templates/claude/rules/claude-code-defensive.md +99 -0
  20. package/templates/claude/rules/doc-sync.md +49 -0
  21. package/templates/claude/rules/ops-safety.md +32 -0
  22. package/templates/claude/skills/bash-style/SKILL.md +244 -0
  23. package/templates/claude/skills/brainstorming/SKILL.md +48 -0
  24. package/templates/claude/skills/dotnet-dev/SKILL.md +250 -0
  25. package/templates/claude/skills/dotnet-dev/references/dotnet-style.md +991 -0
  26. package/templates/claude/skills/mcp-builder/LICENSE.txt +202 -0
  27. package/templates/claude/skills/mcp-builder/SKILL.md +328 -0
  28. package/templates/claude/skills/mcp-builder/reference/evaluation.md +602 -0
  29. package/templates/claude/skills/mcp-builder/reference/mcp_best_practices.md +915 -0
  30. package/templates/claude/skills/mcp-builder/reference/node_mcp_server.md +916 -0
  31. package/templates/claude/skills/mcp-builder/reference/python_mcp_server.md +752 -0
  32. package/templates/claude/skills/mcp-builder/scripts/connections.py +151 -0
  33. package/templates/claude/skills/mcp-builder/scripts/evaluation.py +373 -0
  34. package/templates/claude/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  35. package/templates/claude/skills/mcp-builder/scripts/requirements.txt +2 -0
  36. package/templates/claude/skills/ops-safety/SKILL.md +130 -0
  37. package/templates/claude/skills/python-dev/SKILL.md +281 -0
  38. package/templates/claude/skills/skill-creator/LICENSE.txt +202 -0
  39. package/templates/claude/skills/skill-creator/SKILL.md +209 -0
  40. package/templates/claude/skills/skill-creator/scripts/init_skill.py +303 -0
  41. package/templates/claude/skills/skill-creator/scripts/package_skill.py +110 -0
  42. package/templates/claude/skills/skill-creator/scripts/quick_validate.py +65 -0
  43. package/templates/claude/skills/sqlserver-executor/SKILL.md +201 -0
  44. package/templates/claude/skills/sqlserver-executor/assets/config-example.json +26 -0
  45. package/templates/claude/skills/sqlserver-executor/config.json +12 -0
  46. package/templates/claude/skills/sqlserver-executor/scripts/sql_executor.py +404 -0
  47. package/templates/claude/skills/ui-ux-pro-max/SKILL.md +228 -0
  48. package/templates/claude/skills/ui-ux-pro-max/data/charts.csv +26 -0
  49. package/templates/claude/skills/ui-ux-pro-max/data/colors.csv +97 -0
  50. package/templates/claude/skills/ui-ux-pro-max/data/landing.csv +31 -0
  51. package/templates/claude/skills/ui-ux-pro-max/data/products.csv +97 -0
  52. package/templates/claude/skills/ui-ux-pro-max/data/prompts.csv +24 -0
  53. package/templates/claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  54. package/templates/claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  55. package/templates/claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  56. package/templates/claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  57. package/templates/claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  58. package/templates/claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  59. package/templates/claude/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  60. package/templates/claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  61. package/templates/claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  62. package/templates/claude/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  63. package/templates/claude/skills/ui-ux-pro-max/data/styles.csv +59 -0
  64. package/templates/claude/skills/ui-ux-pro-max/data/typography.csv +58 -0
  65. package/templates/claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  66. package/templates/claude/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  67. package/templates/claude/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
  68. package/templates/claude/skills/ui-ux-pro-max/scripts/core.py +238 -0
  69. package/templates/claude/skills/ui-ux-pro-max/scripts/search.py +61 -0
  70. package/templates/claude/skills/webapp-testing/LICENSE.txt +202 -0
  71. package/templates/claude/skills/webapp-testing/SKILL.md +96 -0
  72. package/templates/claude/skills/webapp-testing/examples/console_logging.py +35 -0
  73. package/templates/claude/skills/webapp-testing/examples/element_discovery.py +40 -0
  74. package/templates/claude/skills/webapp-testing/examples/static_html_automation.py +33 -0
  75. package/templates/claude/skills/webapp-testing/scripts/with_server.py +106 -0
  76. package/templates/init/claude-agents/ccg-impl.md +199 -0
  77. package/templates/init/claude-agents/ccg-review.md +146 -0
  78. package/templates/init/claude-agents/dispatch.md +253 -0
  79. package/templates/init/claude-hooks/inject-subagent-context.py +964 -0
  80. package/templates/init/trellis-scripts/task.sh +1326 -0
package/dist/index.js ADDED
@@ -0,0 +1,801 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/commands/setup.ts
7
+ import chalk2 from "chalk";
8
+ import { checkbox, confirm, select } from "@inquirer/prompts";
9
+
10
+ // src/utils/shell.ts
11
+ import { execa } from "execa";
12
+ async function exec(cmd, args, opts) {
13
+ return execa(cmd, args, { ...opts, reject: true });
14
+ }
15
+ async function execInherit(cmd, args, opts) {
16
+ return execa(cmd, args, {
17
+ ...opts,
18
+ stdio: "inherit"
19
+ });
20
+ }
21
+ async function commandExists(cmd) {
22
+ try {
23
+ await execa("which", [cmd]);
24
+ return true;
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+
30
+ // src/adapters/base-adapter.ts
31
+ var BaseAdapter = class {
32
+ /** 执行命令并提取版本号 */
33
+ async getVersionFromCommand(cmd, args = ["--version"]) {
34
+ try {
35
+ const result = await exec(cmd, args);
36
+ const stdout = String(result.stdout ?? "");
37
+ const match = stdout.match(/v?(\d+\.\d+\.\d+)/);
38
+ return match?.[1];
39
+ } catch {
40
+ return void 0;
41
+ }
42
+ }
43
+ /** 检查命令是否存在 */
44
+ commandExists(cmd) {
45
+ return commandExists(cmd);
46
+ }
47
+ /** 获取 npm 包最新版本 */
48
+ async getLatestNpmVersion(packageName) {
49
+ try {
50
+ const result = await exec("npm", ["info", packageName, "version"]);
51
+ return String(result.stdout ?? "").trim();
52
+ } catch {
53
+ return void 0;
54
+ }
55
+ }
56
+ };
57
+
58
+ // src/adapters/openspec.adapter.ts
59
+ var OpenSpecAdapter = class extends BaseAdapter {
60
+ meta = {
61
+ name: "openspec",
62
+ displayName: "OpenSpec",
63
+ description: "AI-native spec-driven development",
64
+ installMethod: "npm-global",
65
+ required: false,
66
+ order: 1,
67
+ interactive: false,
68
+ pinnedVersion: "1.1.1"
69
+ };
70
+ packageName = "@fission-ai/openspec";
71
+ binName = "openspec";
72
+ async check() {
73
+ const installed = await this.commandExists(this.binName);
74
+ if (!installed) return { installed: false };
75
+ const version = await this.getVersionFromCommand(this.binName);
76
+ const latest = await this.getLatestNpmVersion(this.packageName);
77
+ return {
78
+ installed: true,
79
+ version,
80
+ latestVersion: latest,
81
+ updateAvailable: !!(version && latest && version !== latest)
82
+ };
83
+ }
84
+ async install(version) {
85
+ const pkg = version ? `${this.packageName}@${version}` : this.packageName;
86
+ await execInherit("npm", ["install", "-g", pkg]);
87
+ }
88
+ async update(version) {
89
+ if (version) {
90
+ await execInherit("npm", ["install", "-g", `${this.packageName}@${version}`]);
91
+ } else {
92
+ await execInherit("npm", ["update", "-g", this.packageName]);
93
+ }
94
+ }
95
+ async uninstall() {
96
+ await execInherit("npm", ["uninstall", "-g", this.packageName]);
97
+ }
98
+ async initProject(cwd) {
99
+ await execInherit(this.binName, ["init"], { cwd });
100
+ }
101
+ };
102
+
103
+ // src/adapters/trellis.adapter.ts
104
+ var TrellisAdapter = class extends BaseAdapter {
105
+ meta = {
106
+ name: "trellis",
107
+ displayName: "Trellis",
108
+ description: "AI workflow structure for Claude Code and Cursor",
109
+ installMethod: "npm-global",
110
+ required: false,
111
+ order: 2,
112
+ interactive: false,
113
+ pinnedVersion: "0.2.15"
114
+ };
115
+ packageName = "@mindfoldhq/trellis";
116
+ binName = "trellis";
117
+ async check() {
118
+ const installed = await this.commandExists(this.binName);
119
+ if (!installed) return { installed: false };
120
+ const version = await this.getVersionFromCommand(this.binName);
121
+ const latest = await this.getLatestNpmVersion(this.packageName);
122
+ return {
123
+ installed: true,
124
+ version,
125
+ latestVersion: latest,
126
+ updateAvailable: !!(version && latest && version !== latest)
127
+ };
128
+ }
129
+ async install(version) {
130
+ const pkg = version ? `${this.packageName}@${version}` : this.packageName;
131
+ await execInherit("npm", ["install", "-g", pkg]);
132
+ }
133
+ async update(version) {
134
+ if (version) {
135
+ await execInherit("npm", ["install", "-g", `${this.packageName}@${version}`]);
136
+ } else {
137
+ await execInherit("npm", ["update", "-g", this.packageName]);
138
+ }
139
+ }
140
+ async uninstall() {
141
+ await execInherit("npm", ["uninstall", "-g", this.packageName]);
142
+ }
143
+ async initProject(cwd) {
144
+ await execInherit(this.binName, ["init"], { cwd });
145
+ }
146
+ };
147
+
148
+ // src/adapters/ccb.adapter.ts
149
+ import { existsSync } from "fs";
150
+ import { resolve as resolve2 } from "path";
151
+
152
+ // src/utils/platform.ts
153
+ import { homedir } from "os";
154
+ import { resolve } from "path";
155
+ function expandHome(p) {
156
+ if (p.startsWith("~/") || p === "~") {
157
+ return resolve(homedir(), p.slice(2));
158
+ }
159
+ return p;
160
+ }
161
+ function getHome() {
162
+ return process.env.ZHUGE_HOME || homedir();
163
+ }
164
+ function isCI() {
165
+ return process.env.ZHUGE_CI === "true" || process.env.CI === "true";
166
+ }
167
+
168
+ // src/adapters/ccb.adapter.ts
169
+ var CcbAdapter = class extends BaseAdapter {
170
+ meta = {
171
+ name: "ccb",
172
+ displayName: "Claude Code Bridge (CCB)",
173
+ description: "Multi-model collaboration via split-pane terminal",
174
+ installMethod: "git-clone-script",
175
+ required: false,
176
+ order: 3,
177
+ interactive: false
178
+ };
179
+ repoUrl = "https://github.com/bfly123/claude_code_bridge.git";
180
+ get cloneDir() {
181
+ return resolve2(getHome(), ".local/share/claude_code_bridge");
182
+ }
183
+ async check() {
184
+ const installed = await this.commandExists("ccb");
185
+ if (!installed) return { installed: false };
186
+ const version = await this.getVersionFromCommand("ccb");
187
+ return { installed: true, version };
188
+ }
189
+ async install() {
190
+ if (!existsSync(this.cloneDir)) {
191
+ await execInherit("git", ["clone", this.repoUrl, this.cloneDir]);
192
+ }
193
+ await execInherit("bash", ["./install.sh", "install"], { cwd: this.cloneDir });
194
+ }
195
+ async update() {
196
+ if (existsSync(this.cloneDir)) {
197
+ await execInherit("git", ["-C", this.cloneDir, "pull"]);
198
+ } else {
199
+ await execInherit("git", ["clone", this.repoUrl, this.cloneDir]);
200
+ }
201
+ await execInherit("bash", ["./install.sh", "install"], { cwd: this.cloneDir });
202
+ }
203
+ async uninstall() {
204
+ if (existsSync(this.cloneDir)) {
205
+ await execInherit("bash", ["./install.sh", "uninstall"], { cwd: this.cloneDir });
206
+ }
207
+ }
208
+ };
209
+
210
+ // src/adapters/ccg.adapter.ts
211
+ import { existsSync as existsSync2 } from "fs";
212
+ import { resolve as resolve3 } from "path";
213
+ var CcgAdapter = class extends BaseAdapter {
214
+ meta = {
215
+ name: "ccg",
216
+ displayName: "CCG Workflow",
217
+ description: "Claude Code enhanced multi-model workflow",
218
+ installMethod: "npx",
219
+ required: false,
220
+ order: 4,
221
+ interactive: true,
222
+ pinnedVersion: "1.7.61"
223
+ };
224
+ get configPath() {
225
+ return resolve3(getHome(), ".claude/.ccg/config.toml");
226
+ }
227
+ async check() {
228
+ const installed = existsSync2(this.configPath);
229
+ if (!installed) return { installed: false };
230
+ return { installed: true, version: "detected" };
231
+ }
232
+ async install(version) {
233
+ const pkg = version ? `ccg-workflow@${version}` : "ccg-workflow@latest";
234
+ await execInherit("npx", [pkg]);
235
+ }
236
+ async update(version) {
237
+ await this.install(version);
238
+ }
239
+ async uninstall() {
240
+ const ccgDir = resolve3(getHome(), ".claude/.ccg");
241
+ if (existsSync2(ccgDir)) {
242
+ const { rmSync } = await import("fs");
243
+ rmSync(ccgDir, { recursive: true, force: true });
244
+ }
245
+ }
246
+ };
247
+
248
+ // src/adapters/index.ts
249
+ function getAllAdapters() {
250
+ return [
251
+ new OpenSpecAdapter(),
252
+ new TrellisAdapter(),
253
+ new CcbAdapter(),
254
+ new CcgAdapter()
255
+ ].sort((a, b) => a.meta.order - b.meta.order);
256
+ }
257
+
258
+ // src/utils/logger.ts
259
+ import chalk from "chalk";
260
+ import ora from "ora";
261
+ function info(msg) {
262
+ console.log(chalk.blue("\u2139"), msg);
263
+ }
264
+ function success(msg) {
265
+ console.log(chalk.green("\u2714"), msg);
266
+ }
267
+ function warn(msg) {
268
+ console.log(chalk.yellow("\u26A0"), msg);
269
+ }
270
+ function error(msg) {
271
+ console.log(chalk.red("\u2716"), msg);
272
+ }
273
+ function spinner(text) {
274
+ return ora({ text, color: "cyan" }).start();
275
+ }
276
+ function title(text) {
277
+ console.log();
278
+ console.log(chalk.bold.cyan(text));
279
+ console.log(chalk.dim("\u2500".repeat(text.length + 4)));
280
+ }
281
+
282
+ // src/core/plugin-runner.ts
283
+ async function checkAllAdapters(adapters) {
284
+ const spin = spinner("Checking installed tools...");
285
+ const results = [];
286
+ for (const adapter of adapters) {
287
+ try {
288
+ const status = await adapter.check();
289
+ let action;
290
+ if (!status.installed) {
291
+ action = "install";
292
+ } else if (status.updateAvailable) {
293
+ action = "update";
294
+ } else {
295
+ action = "skip";
296
+ }
297
+ results.push({ adapter, status, action });
298
+ } catch {
299
+ results.push({
300
+ adapter,
301
+ status: { installed: false },
302
+ action: "install"
303
+ });
304
+ }
305
+ }
306
+ spin.succeed("Tool check complete");
307
+ return results;
308
+ }
309
+ async function runAdapter(adapter, action, version) {
310
+ if (adapter.meta.interactive) {
311
+ console.log();
312
+ info(`Starting ${adapter.meta.displayName} (interactive)...`);
313
+ console.log();
314
+ await adapter[action](version);
315
+ console.log();
316
+ } else {
317
+ const spin = spinner(
318
+ `${action === "install" ? "Installing" : "Updating"} ${adapter.meta.displayName}${version ? `@${version}` : ""}...`
319
+ );
320
+ try {
321
+ await adapter[action](version);
322
+ spin.succeed(`${adapter.meta.displayName} ${action === "install" ? "installed" : "updated"}${version ? ` (v${version})` : ""}`);
323
+ } catch (err) {
324
+ spin.fail(`${adapter.meta.displayName} ${action} failed`);
325
+ throw err;
326
+ }
327
+ }
328
+ }
329
+
330
+ // src/core/config-deployer.ts
331
+ import { resolve as resolve5, dirname as dirname2, basename } from "path";
332
+ import {
333
+ existsSync as existsSync4,
334
+ readFileSync,
335
+ writeFileSync,
336
+ copyFileSync,
337
+ mkdirSync,
338
+ renameSync,
339
+ readdirSync,
340
+ statSync as statSync2
341
+ } from "fs";
342
+
343
+ // src/core/config-source.ts
344
+ import { resolve as resolve4, dirname } from "path";
345
+ import { existsSync as existsSync3, statSync } from "fs";
346
+ import { fileURLToPath } from "url";
347
+ var __dirname = dirname(fileURLToPath(import.meta.url));
348
+ function getBundledTemplatesDir() {
349
+ let dir = __dirname;
350
+ for (let i = 0; i < 5; i++) {
351
+ const candidate = resolve4(dir, "templates");
352
+ if (existsSync3(candidate) && statSync(candidate).isDirectory()) {
353
+ return candidate;
354
+ }
355
+ dir = resolve4(dir, "..");
356
+ }
357
+ throw new Error("Could not find templates directory");
358
+ }
359
+
360
+ // src/core/config-deployer.ts
361
+ async function deployConfigs(targets) {
362
+ const templatesDir = getBundledTemplatesDir();
363
+ for (const target of targets) {
364
+ const spin = spinner(`Deploying configs to ${target.displayName}...`);
365
+ try {
366
+ let deployed = 0;
367
+ for (const rule of target.rules) {
368
+ const sourcePath = resolve5(templatesDir, target.name, rule.source);
369
+ const targetPath = expandHome(rule.target);
370
+ if (!existsSync4(sourcePath)) {
371
+ continue;
372
+ }
373
+ mkdirSync(dirname2(targetPath), { recursive: true });
374
+ if (statSync2(sourcePath).isDirectory()) {
375
+ deployed += deployDirectory(sourcePath, targetPath, rule.strategy);
376
+ } else {
377
+ deployFile(sourcePath, targetPath, rule);
378
+ deployed++;
379
+ }
380
+ }
381
+ spin.succeed(`${target.displayName}: ${deployed} file(s) deployed`);
382
+ } catch (err) {
383
+ spin.fail(`${target.displayName}: deploy failed`);
384
+ error(String(err));
385
+ }
386
+ }
387
+ }
388
+ function deployFile(source, target, rule) {
389
+ switch (rule.strategy) {
390
+ case "replace":
391
+ deployReplace(source, target);
392
+ break;
393
+ case "append":
394
+ deployAppend(source, target);
395
+ break;
396
+ case "merge-section":
397
+ if (!rule.sectionMarker) {
398
+ throw new Error(`merge-section requires sectionMarker for ${rule.source}`);
399
+ }
400
+ deployMergeSection(source, target, rule.sectionMarker);
401
+ break;
402
+ }
403
+ }
404
+ function deployReplace(source, target) {
405
+ if (existsSync4(target)) {
406
+ const backupPath = `${target}.bak.${Date.now()}`;
407
+ renameSync(target, backupPath);
408
+ }
409
+ copyFileSync(source, target);
410
+ }
411
+ function deployAppend(source, target) {
412
+ const content = readFileSync(source, "utf-8");
413
+ if (existsSync4(target)) {
414
+ const existing = readFileSync(target, "utf-8");
415
+ if (existing.includes(content.trim())) return;
416
+ writeFileSync(target, existing + "\n" + content);
417
+ } else {
418
+ writeFileSync(target, content);
419
+ }
420
+ }
421
+ function deployMergeSection(source, target, marker) {
422
+ const newContent = readFileSync(source, "utf-8");
423
+ if (!existsSync4(target)) {
424
+ writeFileSync(target, newContent);
425
+ return;
426
+ }
427
+ const existing = readFileSync(target, "utf-8");
428
+ const startIdx = existing.indexOf(marker.start);
429
+ const endIdx = existing.indexOf(marker.end);
430
+ if (startIdx !== -1 && endIdx !== -1) {
431
+ const before = existing.substring(0, startIdx);
432
+ const after = existing.substring(endIdx + marker.end.length);
433
+ writeFileSync(target, before + newContent + after);
434
+ } else {
435
+ warn(`Section markers not found in ${basename(target)}, appending instead`);
436
+ writeFileSync(target, existing + "\n" + newContent);
437
+ }
438
+ }
439
+ function deployDirectory(sourceDir, targetDir, _strategy) {
440
+ mkdirSync(targetDir, { recursive: true });
441
+ let count = 0;
442
+ for (const entry of readdirSync(sourceDir, { withFileTypes: true })) {
443
+ const srcPath = resolve5(sourceDir, entry.name);
444
+ const tgtPath = resolve5(targetDir, entry.name);
445
+ if (entry.isDirectory()) {
446
+ count += deployDirectory(srcPath, tgtPath, _strategy);
447
+ } else {
448
+ copyFileSync(srcPath, tgtPath);
449
+ count++;
450
+ }
451
+ }
452
+ return count;
453
+ }
454
+
455
+ // src/configs/claude.config.ts
456
+ import { existsSync as existsSync5 } from "fs";
457
+ var claudeConfig = {
458
+ name: "claude",
459
+ displayName: "Claude Code",
460
+ configDir: "~/.claude",
461
+ detect: async () => existsSync5(expandHome("~/.claude")),
462
+ rules: [
463
+ // CLAUDE.md - Global 区块(个人配置)
464
+ {
465
+ source: "CLAUDE.md",
466
+ target: "~/.claude/CLAUDE.md",
467
+ strategy: "merge-section",
468
+ sectionMarker: {
469
+ start: "<!-- Global -->",
470
+ end: "<!-- Global_END -->"
471
+ }
472
+ },
473
+ // CLAUDE.md - CCG 增强区块
474
+ {
475
+ source: "CLAUDE-ccg.md",
476
+ target: "~/.claude/CLAUDE.md",
477
+ strategy: "merge-section",
478
+ sectionMarker: {
479
+ start: "<!-- CCG \u589E\u5F3A -->",
480
+ end: "<!-- CCG \u589E\u5F3A_END -->"
481
+ }
482
+ },
483
+ // rules - 整体替换(全部由 zhuge 管理)
484
+ {
485
+ source: "rules",
486
+ target: "~/.claude/rules",
487
+ strategy: "replace"
488
+ },
489
+ // skills - 只复制 zhuge 管理的,不删除已有的(保护 CCB/第三方 skill)
490
+ {
491
+ source: "skills",
492
+ target: "~/.claude/skills",
493
+ strategy: "replace"
494
+ },
495
+ // commands/developer - 只复制 zhuge 管理的(保护 CCG 的 commands/ccg/)
496
+ {
497
+ source: "commands",
498
+ target: "~/.claude/commands",
499
+ strategy: "replace"
500
+ }
501
+ ]
502
+ };
503
+
504
+ // src/configs/index.ts
505
+ function getAllConfigTargets() {
506
+ return [claudeConfig];
507
+ }
508
+ function getConfigTargetsByNames(names) {
509
+ const all = getAllConfigTargets();
510
+ return all.filter((t) => names.includes(t.name));
511
+ }
512
+
513
+ // src/commands/setup.ts
514
+ async function setupCommand(options) {
515
+ const ciMode = options.yes || isCI();
516
+ title("zhuge setup");
517
+ const adapters = getAllAdapters();
518
+ const actions = await checkAllAdapters(adapters);
519
+ printStatusTable(actions);
520
+ const actionable = actions.filter((a) => a.action !== "skip");
521
+ const skippable = actions.filter((a) => a.action === "skip");
522
+ if (actionable.length === 0 && skippable.length === actions.length) {
523
+ success("All tools are up to date!");
524
+ }
525
+ let selected;
526
+ if (ciMode) {
527
+ selected = actionable;
528
+ } else if (actionable.length === 0) {
529
+ const reconfig = await confirm({
530
+ message: "All tools installed. Reconfigure any tool?",
531
+ default: false
532
+ });
533
+ if (!reconfig) {
534
+ selected = [];
535
+ } else {
536
+ const choices = skippable.map((a) => ({
537
+ name: `${a.adapter.meta.displayName} (reconfigure)`,
538
+ value: a
539
+ }));
540
+ const picked = await checkbox({
541
+ message: "Select tools to reconfigure:",
542
+ choices
543
+ });
544
+ selected = picked.map((p) => ({ ...p, action: "install" }));
545
+ }
546
+ } else {
547
+ const choices = actionable.map((a) => ({
548
+ name: formatActionChoice(a),
549
+ value: a,
550
+ checked: true
551
+ }));
552
+ selected = await checkbox({
553
+ message: "Select tools to install/update:",
554
+ choices
555
+ });
556
+ }
557
+ if (selected.length > 0) {
558
+ const versionMap = /* @__PURE__ */ new Map();
559
+ if (!ciMode) {
560
+ for (const item of selected) {
561
+ if (item.adapter.meta.pinnedVersion) {
562
+ const strategy = await select({
563
+ message: `${item.adapter.meta.displayName} - Version strategy:`,
564
+ choices: [
565
+ {
566
+ name: `Pinned v${item.adapter.meta.pinnedVersion} (tested with zhuge)`,
567
+ value: "pinned"
568
+ },
569
+ { name: "Latest version", value: "latest" }
570
+ ]
571
+ });
572
+ if (strategy === "pinned") {
573
+ versionMap.set(item.adapter.meta.name, item.adapter.meta.pinnedVersion);
574
+ }
575
+ }
576
+ }
577
+ }
578
+ console.log();
579
+ for (const item of selected) {
580
+ try {
581
+ const version = versionMap.get(item.adapter.meta.name);
582
+ await runAdapter(item.adapter, item.action === "skip" ? "install" : item.action, version);
583
+ } catch (err) {
584
+ error(`Failed: ${item.adapter.meta.displayName} - ${err}`);
585
+ }
586
+ }
587
+ }
588
+ await deployConfigsPhase(ciMode);
589
+ console.log();
590
+ title("Setup Complete");
591
+ if (selected.length > 0) {
592
+ for (const item of selected) {
593
+ const verb = item.action === "update" ? "Updated" : "Installed";
594
+ success(`${verb}: ${item.adapter.meta.displayName}`);
595
+ }
596
+ } else {
597
+ info("No tools were installed or updated.");
598
+ }
599
+ }
600
+ function printStatusTable(actions) {
601
+ console.log();
602
+ const header = ` ${pad("Tool", 24)} ${pad("Status", 10)} ${pad("Version", 12)} Action`;
603
+ console.log(chalk2.dim(header));
604
+ console.log(chalk2.dim(" " + "\u2500".repeat(64)));
605
+ for (const { adapter, status, action } of actions) {
606
+ const name = pad(adapter.meta.displayName, 24);
607
+ const st = status.installed ? chalk2.green(pad("OK", 10)) : chalk2.red(pad("Missing", 10));
608
+ const ver = pad(status.version || "-", 12);
609
+ const act = action === "install" ? chalk2.yellow("Install") : action === "update" ? chalk2.cyan(`Update \u2192 ${status.latestVersion || "?"}`) : chalk2.dim("Skip");
610
+ console.log(` ${name} ${st} ${ver} ${act}`);
611
+ }
612
+ console.log();
613
+ }
614
+ function formatActionChoice(a) {
615
+ if (a.action === "install") {
616
+ return `${a.adapter.meta.displayName} - Install`;
617
+ }
618
+ return `${a.adapter.meta.displayName} - Update to ${a.status.latestVersion || "latest"}`;
619
+ }
620
+ function pad(s, len) {
621
+ return s.padEnd(len);
622
+ }
623
+ async function deployConfigsPhase(ciMode) {
624
+ console.log();
625
+ if (ciMode) {
626
+ info("Config deployment skipped in CI mode (use zhuge setup interactively)");
627
+ return;
628
+ }
629
+ const deploy = await confirm({
630
+ message: "Deploy AI tool config files?",
631
+ default: true
632
+ });
633
+ if (!deploy) return;
634
+ const targets = await checkbox({
635
+ message: "Deploy configs to:",
636
+ choices: [
637
+ { name: "Claude Code (~/.claude/)", value: "claude", checked: true }
638
+ ]
639
+ });
640
+ if (targets.length === 0) {
641
+ info("No config targets selected, skipping.");
642
+ return;
643
+ }
644
+ const configTargets = getConfigTargetsByNames(targets);
645
+ await deployConfigs(configTargets);
646
+ }
647
+
648
+ // src/commands/init.ts
649
+ import { existsSync as existsSync6, writeFileSync as writeFileSync2, readFileSync as readFileSync2, mkdirSync as mkdirSync2, copyFileSync as copyFileSync2, readdirSync as readdirSync2 } from "fs";
650
+ import { resolve as resolve6 } from "path";
651
+ async function initCommand() {
652
+ const cwd = process.cwd();
653
+ title("zhuge init");
654
+ if (!existsSync6(resolve6(cwd, ".git"))) {
655
+ error('Current directory is not a git repository. Run "git init" first.');
656
+ process.exit(1);
657
+ }
658
+ const checks = await Promise.all([
659
+ commandExists("openspec"),
660
+ commandExists("trellis")
661
+ ]);
662
+ if (!checks[0]) {
663
+ warn('OpenSpec not installed. Run "zhuge setup" first to install it.');
664
+ info("Skipping OpenSpec init...");
665
+ }
666
+ if (!checks[1]) {
667
+ warn('Trellis not installed. Run "zhuge setup" first to install it.');
668
+ info("Skipping Trellis init...");
669
+ }
670
+ if (checks[0]) {
671
+ console.log();
672
+ info("Running OpenSpec init...");
673
+ console.log();
674
+ try {
675
+ await execInherit("openspec", ["init"], { cwd });
676
+ success("OpenSpec init complete");
677
+ } catch (err) {
678
+ error(`OpenSpec init failed: ${err}`);
679
+ }
680
+ }
681
+ if (checks[1]) {
682
+ console.log();
683
+ info("Running Trellis init...");
684
+ console.log();
685
+ try {
686
+ await execInherit("trellis", ["init"], { cwd });
687
+ success("Trellis init complete");
688
+ } catch (err) {
689
+ error(`Trellis init failed: ${err}`);
690
+ }
691
+ }
692
+ console.log();
693
+ info("Running zhuge init...");
694
+ await zhugeOwnInit(cwd);
695
+ console.log();
696
+ title("Init Complete");
697
+ success(`Project initialized at ${cwd}`);
698
+ }
699
+ async function zhugeOwnInit(cwd) {
700
+ const zhugeDir = resolve6(cwd, ".zhuge");
701
+ mkdirSync2(zhugeDir, { recursive: true });
702
+ const stateFile = resolve6(zhugeDir, "init-state.json");
703
+ const state = {
704
+ version: "0.1.0",
705
+ initializedAt: (/* @__PURE__ */ new Date()).toISOString(),
706
+ tools: {
707
+ openspec: existsSync6(resolve6(cwd, "openspec")) || existsSync6(resolve6(cwd, "specs")),
708
+ trellis: existsSync6(resolve6(cwd, ".trellis"))
709
+ }
710
+ };
711
+ writeFileSync2(stateFile, JSON.stringify(state, null, 2));
712
+ const claudeMdPath = resolve6(cwd, "CLAUDE.md");
713
+ if (existsSync6(claudeMdPath)) {
714
+ const existing = readFileSync2(claudeMdPath, "utf-8");
715
+ const zhugeSection = buildZhugeSection(cwd);
716
+ if (!existing.includes("<!-- zhuge-workflow -->")) {
717
+ writeFileSync2(claudeMdPath, existing + "\n" + zhugeSection);
718
+ success("Updated project CLAUDE.md with zhuge section");
719
+ } else {
720
+ info("CLAUDE.md already contains zhuge section, skipping");
721
+ }
722
+ } else {
723
+ const content = buildProjectClaudeMd(cwd);
724
+ writeFileSync2(claudeMdPath, content);
725
+ success("Created project CLAUDE.md");
726
+ }
727
+ deployInitTemplates(cwd);
728
+ const gitignorePath = resolve6(cwd, ".gitignore");
729
+ if (existsSync6(gitignorePath)) {
730
+ const gitignore = readFileSync2(gitignorePath, "utf-8");
731
+ if (!gitignore.includes(".zhuge/")) {
732
+ writeFileSync2(gitignorePath, gitignore.trimEnd() + "\n.zhuge/\n");
733
+ }
734
+ }
735
+ success("zhuge init complete");
736
+ }
737
+ function buildZhugeSection(cwd) {
738
+ const parts = [
739
+ "<!-- zhuge-workflow -->",
740
+ "",
741
+ "## Workflow",
742
+ ""
743
+ ];
744
+ if (existsSync6(resolve6(cwd, "specs")) || existsSync6(resolve6(cwd, "openspec"))) {
745
+ parts.push("- OpenSpec specs available in `specs/` or `openspec/`");
746
+ }
747
+ if (existsSync6(resolve6(cwd, ".trellis"))) {
748
+ parts.push("- Trellis workflow configured in `.trellis/`");
749
+ }
750
+ parts.push("");
751
+ parts.push("<!-- zhuge-workflow-end -->");
752
+ return parts.join("\n");
753
+ }
754
+ function buildProjectClaudeMd(cwd) {
755
+ const parts = [
756
+ `# ${resolve6(cwd).split("/").pop() || "Project"}`,
757
+ ""
758
+ ];
759
+ parts.push(buildZhugeSection(cwd));
760
+ return parts.join("\n");
761
+ }
762
+ function deployInitTemplates(cwd) {
763
+ const templatesDir = resolve6(getBundledTemplatesDir(), "init");
764
+ if (!existsSync6(templatesDir)) {
765
+ warn("Init templates not found, skipping file replacements");
766
+ return;
767
+ }
768
+ const mappings = [
769
+ { source: "claude-agents", target: ".claude/agents" },
770
+ { source: "claude-hooks", target: ".claude/hooks" },
771
+ { source: "trellis-scripts", target: ".trellis/scripts" }
772
+ ];
773
+ let count = 0;
774
+ for (const { source, target } of mappings) {
775
+ const srcDir = resolve6(templatesDir, source);
776
+ if (!existsSync6(srcDir)) continue;
777
+ const tgtDir = resolve6(cwd, target);
778
+ mkdirSync2(tgtDir, { recursive: true });
779
+ for (const entry of readdirSync2(srcDir, { withFileTypes: true })) {
780
+ if (entry.isFile()) {
781
+ copyFileSync2(resolve6(srcDir, entry.name), resolve6(tgtDir, entry.name));
782
+ count++;
783
+ }
784
+ }
785
+ }
786
+ if (count > 0) {
787
+ success(`Deployed ${count} zhuge enhanced file(s)`);
788
+ }
789
+ }
790
+
791
+ // src/index.ts
792
+ var program = new Command();
793
+ program.name("zhuge").description("AI development workflow installer and manager").version("0.1.0");
794
+ program.command("setup").description("Install external tools and deploy AI config files").option("--yes", "Skip all prompts and use defaults (CI mode)").action(async (options) => {
795
+ await setupCommand(options);
796
+ });
797
+ program.command("init").description("Initialize project-level documents in current directory").action(async () => {
798
+ await initCommand();
799
+ });
800
+ program.parse();
801
+ //# sourceMappingURL=index.js.map