@roarpeng/graphflow 1.1.0 → 1.2.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 (142) hide show
  1. package/README.md +1 -1
  2. package/dist/agents/insight.js +1 -1
  3. package/dist/agents/insight.js.map +1 -1
  4. package/dist/config/defaults.d.ts.map +1 -1
  5. package/dist/config/defaults.js +1 -0
  6. package/dist/config/defaults.js.map +1 -1
  7. package/dist/config/embedding-factory.d.ts.map +1 -1
  8. package/dist/config/embedding-factory.js +23 -12
  9. package/dist/config/embedding-factory.js.map +1 -1
  10. package/dist/config/loader.d.ts +11 -0
  11. package/dist/config/loader.d.ts.map +1 -1
  12. package/dist/config/loader.js +103 -0
  13. package/dist/config/loader.js.map +1 -1
  14. package/dist/core/agent-assignment.d.ts +39 -0
  15. package/dist/core/agent-assignment.d.ts.map +1 -0
  16. package/dist/core/agent-assignment.js +73 -0
  17. package/dist/core/agent-assignment.js.map +1 -0
  18. package/dist/core/dag-checkpoint.d.ts +83 -0
  19. package/dist/core/dag-checkpoint.d.ts.map +1 -0
  20. package/dist/core/dag-checkpoint.js +164 -0
  21. package/dist/core/dag-checkpoint.js.map +1 -0
  22. package/dist/core/dag-engine.d.ts +9 -0
  23. package/dist/core/dag-engine.d.ts.map +1 -1
  24. package/dist/core/dag-engine.js +42 -0
  25. package/dist/core/dag-engine.js.map +1 -1
  26. package/dist/core/orchestrator-context.d.ts +10 -0
  27. package/dist/core/orchestrator-context.d.ts.map +1 -0
  28. package/dist/core/orchestrator-context.js +112 -0
  29. package/dist/core/orchestrator-context.js.map +1 -0
  30. package/dist/core/orchestrator-episode.d.ts +13 -0
  31. package/dist/core/orchestrator-episode.d.ts.map +1 -0
  32. package/dist/core/orchestrator-episode.js +128 -0
  33. package/dist/core/orchestrator-episode.js.map +1 -0
  34. package/dist/core/orchestrator-route.d.ts +20 -0
  35. package/dist/core/orchestrator-route.d.ts.map +1 -0
  36. package/dist/core/orchestrator-route.js +51 -0
  37. package/dist/core/orchestrator-route.js.map +1 -0
  38. package/dist/core/orchestrator.d.ts +2 -38
  39. package/dist/core/orchestrator.d.ts.map +1 -1
  40. package/dist/core/orchestrator.js +97 -286
  41. package/dist/core/orchestrator.js.map +1 -1
  42. package/dist/core/triage.d.ts +21 -0
  43. package/dist/core/triage.d.ts.map +1 -1
  44. package/dist/core/triage.js +25 -6
  45. package/dist/core/triage.js.map +1 -1
  46. package/dist/core/types.d.ts +53 -0
  47. package/dist/core/types.d.ts.map +1 -1
  48. package/dist/graph/context-slicer-types.d.ts +62 -0
  49. package/dist/graph/context-slicer-types.d.ts.map +1 -0
  50. package/dist/graph/context-slicer-types.js +13 -0
  51. package/dist/graph/context-slicer-types.js.map +1 -0
  52. package/dist/graph/context-slicer-utils.d.ts +24 -0
  53. package/dist/graph/context-slicer-utils.d.ts.map +1 -0
  54. package/dist/graph/context-slicer-utils.js +118 -0
  55. package/dist/graph/context-slicer-utils.js.map +1 -0
  56. package/dist/graph/context-slicer.d.ts +6 -61
  57. package/dist/graph/context-slicer.d.ts.map +1 -1
  58. package/dist/graph/context-slicer.js +73 -170
  59. package/dist/graph/context-slicer.js.map +1 -1
  60. package/dist/graph/file-indexer-cache.d.ts +34 -0
  61. package/dist/graph/file-indexer-cache.d.ts.map +1 -0
  62. package/dist/graph/file-indexer-cache.js +105 -0
  63. package/dist/graph/file-indexer-cache.js.map +1 -0
  64. package/dist/graph/file-indexer-edges.d.ts +55 -0
  65. package/dist/graph/file-indexer-edges.d.ts.map +1 -0
  66. package/dist/graph/file-indexer-edges.js +258 -0
  67. package/dist/graph/file-indexer-edges.js.map +1 -0
  68. package/dist/graph/file-indexer-nodes.d.ts +43 -0
  69. package/dist/graph/file-indexer-nodes.d.ts.map +1 -0
  70. package/dist/graph/file-indexer-nodes.js +137 -0
  71. package/dist/graph/file-indexer-nodes.js.map +1 -0
  72. package/dist/graph/file-indexer-walker.d.ts +35 -0
  73. package/dist/graph/file-indexer-walker.d.ts.map +1 -0
  74. package/dist/graph/file-indexer-walker.js +80 -0
  75. package/dist/graph/file-indexer-walker.js.map +1 -0
  76. package/dist/graph/file-indexer.d.ts +13 -39
  77. package/dist/graph/file-indexer.d.ts.map +1 -1
  78. package/dist/graph/file-indexer.js +167 -600
  79. package/dist/graph/file-indexer.js.map +1 -1
  80. package/dist/index.d.ts +1 -1
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +2 -1
  83. package/dist/index.js.map +1 -1
  84. package/dist/integrations/agent-mcp-installer.d.ts +25 -1
  85. package/dist/integrations/agent-mcp-installer.d.ts.map +1 -1
  86. package/dist/integrations/agent-mcp-installer.js +160 -4
  87. package/dist/integrations/agent-mcp-installer.js.map +1 -1
  88. package/dist/integrations/skill-installer.d.ts +50 -0
  89. package/dist/integrations/skill-installer.d.ts.map +1 -0
  90. package/dist/integrations/skill-installer.js +373 -0
  91. package/dist/integrations/skill-installer.js.map +1 -0
  92. package/dist/learning/embeddings.d.ts +11 -0
  93. package/dist/learning/embeddings.d.ts.map +1 -1
  94. package/dist/learning/embeddings.js +24 -0
  95. package/dist/learning/embeddings.js.map +1 -1
  96. package/dist/learning/episodic-memory.d.ts +3 -2
  97. package/dist/learning/episodic-memory.d.ts.map +1 -1
  98. package/dist/learning/episodic-memory.js +105 -10
  99. package/dist/learning/episodic-memory.js.map +1 -1
  100. package/dist/learning/local-embedding.d.ts.map +1 -1
  101. package/dist/learning/local-embedding.js +16 -0
  102. package/dist/learning/local-embedding.js.map +1 -1
  103. package/dist/learning/seed-skills.d.ts +21 -0
  104. package/dist/learning/seed-skills.d.ts.map +1 -0
  105. package/dist/learning/seed-skills.js +113 -0
  106. package/dist/learning/seed-skills.js.map +1 -0
  107. package/dist/learning/skill-evolution.d.ts +1 -1
  108. package/dist/learning/skill-evolution.d.ts.map +1 -1
  109. package/dist/learning/skill-evolution.js +1 -1
  110. package/dist/learning/skill-evolution.js.map +1 -1
  111. package/dist/learning/skill-package.d.ts +55 -0
  112. package/dist/learning/skill-package.d.ts.map +1 -0
  113. package/dist/learning/skill-package.js +115 -0
  114. package/dist/learning/skill-package.js.map +1 -0
  115. package/dist/learning/triage-telemetry.d.ts +43 -0
  116. package/dist/learning/triage-telemetry.d.ts.map +1 -0
  117. package/dist/learning/triage-telemetry.js +114 -0
  118. package/dist/learning/triage-telemetry.js.map +1 -0
  119. package/dist/surfaces/cli/index.js +65 -0
  120. package/dist/surfaces/cli/index.js.map +1 -1
  121. package/dist/surfaces/cli/init.d.ts +12 -2
  122. package/dist/surfaces/cli/init.d.ts.map +1 -1
  123. package/dist/surfaces/cli/init.js +109 -30
  124. package/dist/surfaces/cli/init.js.map +1 -1
  125. package/dist/surfaces/cli/output.d.ts.map +1 -1
  126. package/dist/surfaces/cli/output.js +5 -0
  127. package/dist/surfaces/cli/output.js.map +1 -1
  128. package/dist/surfaces/cli/runtime/graph.d.ts +23 -0
  129. package/dist/surfaces/cli/runtime/graph.d.ts.map +1 -1
  130. package/dist/surfaces/cli/runtime/graph.js +40 -0
  131. package/dist/surfaces/cli/runtime/graph.js.map +1 -1
  132. package/dist/surfaces/cli/runtime/routing.d.ts.map +1 -1
  133. package/dist/surfaces/cli/runtime/routing.js +8 -1
  134. package/dist/surfaces/cli/runtime/routing.js.map +1 -1
  135. package/dist/surfaces/cli/runtime.d.ts +1 -1
  136. package/dist/surfaces/cli/runtime.d.ts.map +1 -1
  137. package/dist/surfaces/cli/runtime.js +4 -1
  138. package/dist/surfaces/cli/runtime.js.map +1 -1
  139. package/dist/surfaces/mcp/tool-definitions.js +20 -20
  140. package/dist/surfaces/mcp/tool-definitions.js.map +1 -1
  141. package/package.json +3 -3
  142. package/scripts/safe-postinstall.cjs +323 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roarpeng/graphflow",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -72,7 +72,7 @@
72
72
  "@types/node": "^25.9.1",
73
73
  "@typescript-eslint/eslint-plugin": "^8.60.0",
74
74
  "@typescript-eslint/parser": "^8.60.0",
75
- "@vitest/coverage-v8": "^4.1.8",
75
+ "@vitest/coverage-v8": "^3.2.6",
76
76
  "eslint": "^10.4.0",
77
77
  "husky": "^9.1.7",
78
78
  "lint-staged": "^16.4.0",
@@ -80,7 +80,7 @@
80
80
  "tree-sitter-wasms": "0.1.11",
81
81
  "tsx": "^4.22.3",
82
82
  "typescript": "^6.0.3",
83
- "vitest": "^4.1.7"
83
+ "vitest": "^3.2.6"
84
84
  },
85
85
  "dependencies": {
86
86
  "@modelcontextprotocol/sdk": "^1.29.0",
@@ -1,11 +1,56 @@
1
1
  #!/usr/bin/env node
2
- const { existsSync, mkdirSync, copyFileSync, readFileSync } = require("node:fs");
2
+ const { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, unlinkSync } = require("node:fs");
3
3
  const { join } = require("node:path");
4
4
  const { homedir } = require("node:os");
5
5
  const { spawnSync } = require("node:child_process");
6
6
 
7
7
  const isWindows = process.platform === "win32";
8
8
 
9
+ // ─── 版本比较与自动更新 ───
10
+
11
+ /** 版本标记文件路径:记录上次安装的 GraphFlow 版本号 */
12
+ const VERSION_FILE = join(homedir(), ".graphflow-install-version");
13
+
14
+ /**
15
+ * 读取上次安装时记录的版本号
16
+ * @returns {string | null} 上次版本号,不存在则返回 null
17
+ */
18
+ function readPreviousVersion() {
19
+ try {
20
+ if (existsSync(VERSION_FILE)) {
21
+ return readFileSync(VERSION_FILE, "utf8").trim();
22
+ }
23
+ } catch {
24
+ // 忽略读取失败
25
+ }
26
+ return null;
27
+ }
28
+
29
+ /**
30
+ * 将当前版本号写入标记文件
31
+ * @param {string} version 当前版本号
32
+ */
33
+ function writeCurrentVersion(version) {
34
+ try {
35
+ writeFileSync(VERSION_FILE, version, "utf8");
36
+ } catch {
37
+ // 忽略写入失败
38
+ }
39
+ }
40
+
41
+ /**
42
+ * 比较版本号,判断是否需要强制更新 Skill/Rules/MCP 文件
43
+ * @param {string} currentVersion 当前安装的版本号
44
+ * @returns {boolean} 是否需要强制更新
45
+ */
46
+ function needsForceUpdate(currentVersion) {
47
+ const previousVersion = readPreviousVersion();
48
+ if (!previousVersion) {
49
+ return true; // 首次安装或无版本记录,强制更新
50
+ }
51
+ return previousVersion !== currentVersion;
52
+ }
53
+
9
54
  function resolveHomePaths() {
10
55
  const home = homedir();
11
56
  const appData = process.env.APPDATA || (isWindows ? join(home, "AppData", "Roaming") : "");
@@ -147,6 +192,231 @@ function isGlobalInstall() {
147
192
  return false;
148
193
  }
149
194
 
195
+ /**
196
+ * 获取 Cursor Rules 源文件路径(graphflow.mdc)
197
+ * 优先从 dist 目录查找,回退到 src 目录。
198
+ * @returns {string | null} 源文件路径,不存在则返回 null
199
+ */
200
+ function getCursorRulesSourceFile() {
201
+ const candidates = [
202
+ join(__dirname, "..", "dist", "surfaces", "cursor-rules", "graphflow.mdc"),
203
+ join(__dirname, "..", "src", "surfaces", "cursor-rules", "graphflow.mdc"),
204
+ ];
205
+ for (const filePath of candidates) {
206
+ if (existsSync(filePath)) {
207
+ return filePath;
208
+ }
209
+ }
210
+ return null;
211
+ }
212
+
213
+ /**
214
+ * 获取 CLAUDE.md 源文件路径
215
+ * 优先从包根目录查找。
216
+ * @returns {string | null} 源文件路径,不存在则返回 null
217
+ */
218
+ function getClaudeMdSourceFile() {
219
+ const candidates = [
220
+ join(__dirname, "..", "CLAUDE.md"),
221
+ ];
222
+ for (const filePath of candidates) {
223
+ if (existsSync(filePath)) {
224
+ return filePath;
225
+ }
226
+ }
227
+ return null;
228
+ }
229
+
230
+ /**
231
+ * 获取 Cursor rules 目录列表。
232
+ * Cursor 的 rules 目录为 ~/.cursor/rules/(跨平台一致),
233
+ * 也有用户使用 %APPDATA%/Cursor/User/rules/。
234
+ * @returns {Array<{name: string, rulesDir: string}>} Cursor rules 目录列表
235
+ */
236
+ function getCursorRulesDirs() {
237
+ const { home, appData } = resolveHomePaths();
238
+ const dirs = [];
239
+
240
+ // ~/.cursor/rules — Cursor 的标准 rules 目录
241
+ if (existsSync(join(home, ".cursor"))) {
242
+ dirs.push({
243
+ name: "Cursor (~/.cursor)",
244
+ rulesDir: join(home, ".cursor", "rules"),
245
+ });
246
+ }
247
+
248
+ // %APPDATA%/Cursor/User/rules — Windows 上的备选目录
249
+ if (isWindows && existsSync(join(appData, "Cursor", "User"))) {
250
+ dirs.push({
251
+ name: "Cursor (AppData)",
252
+ rulesDir: join(appData, "Cursor", "User", "rules"),
253
+ });
254
+ }
255
+
256
+ return dirs;
257
+ }
258
+
259
+ /**
260
+ * 通用文件安装逻辑:检测 marker → 创建目标目录 → 复制文件 → 已存在且内容相同则跳过
261
+ * @param {string} sourceFile 源文件路径
262
+ * @param {string} destDir 目标目录
263
+ * @param {string} destFileName 目标文件名
264
+ * @returns {{status: string, reason?: string}} 安装结果
265
+ */
266
+ function installFileToDir(sourceFile, destDir, destFileName) {
267
+ if (!existsSync(sourceFile)) {
268
+ return { status: "skipped", reason: "源文件不存在" };
269
+ }
270
+
271
+ const destFile = join(destDir, destFileName);
272
+ const existed = existsSync(destFile);
273
+
274
+ if (existed) {
275
+ const existingContent = readFileSync(destFile, "utf8");
276
+ const newContent = readFileSync(sourceFile, "utf8");
277
+ if (existingContent === newContent) {
278
+ return { status: "skipped", reason: "已是最新" };
279
+ }
280
+ }
281
+
282
+ mkdirSync(destDir, { recursive: true });
283
+ copyFileSync(sourceFile, destFile);
284
+
285
+ return { status: existed ? "updated" : "created" };
286
+ }
287
+
288
+ /**
289
+ * 检测并安装 Cursor Rules(graphflow.mdc)到 Cursor rules 目录
290
+ * @returns {{status: string, reason?: string} | null} 安装结果,无需安装则返回 null
291
+ */
292
+ function installCursorRules() {
293
+ const sourceFile = getCursorRulesSourceFile();
294
+ if (!sourceFile) {
295
+ return { status: "skipped", reason: "Cursor Rules 源文件不存在" };
296
+ }
297
+
298
+ const dirs = getCursorRulesDirs();
299
+ if (dirs.length === 0) {
300
+ return null; // 未检测到 Cursor,跳过
301
+ }
302
+
303
+ // 只需要安装到第一个有效目录
304
+ const target = dirs[0];
305
+ return installFileToDir(sourceFile, target.rulesDir, "graphflow.mdc");
306
+ }
307
+
308
+ /**
309
+ * 检测并安装 CLAUDE.md 到 ~/.claude/CLAUDE.md(Claude Code 约定)
310
+ * @returns {{status: string, reason?: string} | null} 安装结果,无需安装则返回 null
311
+ */
312
+ function installClaudeMd() {
313
+ const sourceFile = getClaudeMdSourceFile();
314
+ if (!sourceFile) {
315
+ return { status: "skipped", reason: "CLAUDE.md 源文件不存在" };
316
+ }
317
+
318
+ const { home } = resolveHomePaths();
319
+ const claudeDir = join(home, ".claude");
320
+
321
+ // 检测 ~/.claude 是否存在(Claude Code 的 marker 目录)
322
+ if (!existsSync(claudeDir)) {
323
+ return null; // 未检测到 Claude Code,跳过
324
+ }
325
+
326
+ return installFileToDir(sourceFile, claudeDir, "CLAUDE.md");
327
+ }
328
+
329
+ /**
330
+ * 注入 workspace 级 MCP 配置到已存在的 workspace MCP 文件。
331
+ * 仅在检测到 .cursor/mcp.json 或 .vscode/mcp.json 时生效(更安全,只在当前项目内)。
332
+ * @param {string} workspaceRoot 当前项目根目录
333
+ * @returns {Array<{configPath: string, status: string}>} 注入结果列表
334
+ */
335
+ function installWorkspaceLevelMcp(workspaceRoot) {
336
+ const results = [];
337
+ const configFiles = [
338
+ { path: join(workspaceRoot, ".cursor", "mcp.json"), name: "Cursor", key: "mcpServers" },
339
+ { path: join(workspaceRoot, ".vscode", "mcp.json"), name: "VS Code", key: "servers" },
340
+ ];
341
+
342
+ const mcpEntry = {
343
+ command: "npx",
344
+ args: ["-y", "--package=@roarpeng/graphflow", "graphflow-mcp"],
345
+ env: { GRAPHFLOW_MCP_STDIO: "1", GRAPHFLOW_LOG_JSON: "1" },
346
+ };
347
+
348
+ for (const config of configFiles) {
349
+ if (!existsSync(config.path)) {
350
+ continue; // 该 workspace 级配置不存在,跳过
351
+ }
352
+
353
+ try {
354
+ let json = {};
355
+ try {
356
+ json = JSON.parse(readFileSync(config.path, "utf8"));
357
+ } catch {
358
+ // 配置文件为空或损坏,初始化为空对象
359
+ }
360
+
361
+ const servers = json[config.key] || {};
362
+ if (servers.graphflow) {
363
+ results.push({ configPath: config.path, status: "skipped", name: config.name, reason: "already configured" });
364
+ continue;
365
+ }
366
+
367
+ servers.graphflow = mcpEntry;
368
+ json[config.key] = servers;
369
+ writeFileSync(config.path, JSON.stringify(json, null, 2) + "\n", "utf8");
370
+ results.push({ configPath: config.path, status: "created", name: config.name });
371
+ console.log(`[GraphFlow] Workspace 级 MCP 已注入到 ${config.path} (${config.name})`);
372
+ } catch (err) {
373
+ results.push({ configPath: config.path, status: "error", name: config.name, reason: err.message });
374
+ console.log(`[GraphFlow] Workspace 级 MCP 注入失败 ${config.path}: ${err.message}`);
375
+ }
376
+ }
377
+
378
+ return results;
379
+ }
380
+
381
+ /**
382
+ * 在 workspace 级创建 .graphflow/skills/ 目录并复制 Skill 文件。
383
+ * 仅在检测到 .cursor/mcp.json 或 .vscode/mcp.json 时生效。
384
+ * @param {string} workspaceRoot 当前项目根目录
385
+ */
386
+ function installWorkspaceLevelSkills(workspaceRoot) {
387
+ const configFiles = [
388
+ join(workspaceRoot, ".cursor", "mcp.json"),
389
+ join(workspaceRoot, ".vscode", "mcp.json"),
390
+ ];
391
+ const hasWorkspaceConfig = configFiles.some((p) => existsSync(p));
392
+
393
+ if (!hasWorkspaceConfig) {
394
+ return; // 无 workspace 级 MCP 配置,跳过 Skill 安装
395
+ }
396
+
397
+ const skillSourceDir = getSkillSourceDir();
398
+ if (!skillSourceDir) {
399
+ return;
400
+ }
401
+
402
+ // 在 .graphflow/skills/graphflow/ 下创建 workspace 级 Skill
403
+ const skillDestDir = join(workspaceRoot, ".graphflow", "skills", "graphflow");
404
+ const result = installSkill(skillDestDir, skillSourceDir);
405
+ if (result.status !== "skipped") {
406
+ console.log(`[GraphFlow] Workspace 级 Skill: ${result.status}${result.reason ? ` (${result.reason})` : ""} -> ${skillDestDir}`);
407
+ }
408
+
409
+ // 同时安装 Cursor Rules 到 workspace 级 .cursor/rules/
410
+ const cursorRulesSource = getCursorRulesSourceFile();
411
+ if (cursorRulesSource && existsSync(join(workspaceRoot, ".cursor"))) {
412
+ const cursorRulesDir = join(workspaceRoot, ".cursor", "rules");
413
+ const rulesResult = installFileToDir(cursorRulesSource, cursorRulesDir, "graphflow.mdc");
414
+ if (rulesResult.status !== "skipped") {
415
+ console.log(`[GraphFlow] Workspace 级 Cursor Rules: ${rulesResult.status}${rulesResult.reason ? ` (${rulesResult.reason})` : ""}`);
416
+ }
417
+ }
418
+ }
419
+
150
420
  function main() {
151
421
  if (process.env.GRAPHFLOW_SKIP_POSTINSTALL === "1" || process.env.CI === "true") {
152
422
  process.exit(0);
@@ -156,13 +426,44 @@ function main() {
156
426
  const explicitlyEnabled = process.env.GRAPHFLOW_ENABLE_POSTINSTALL === "1";
157
427
 
158
428
  if (!globalInstall && !explicitlyEnabled) {
159
- console.log("[GraphFlow] Local install detected. Auto-setup skipped to avoid modifying your global config.");
160
- console.log("[GraphFlow] To install GraphFlow MCP + Skill, run:");
161
- console.log("[GraphFlow] npx @roarpeng/graphflow install");
429
+ // 本地安装:检测 workspace MCP 配置,若有则自动注入 workspace MCP + Skill
430
+ const workspaceRoot = process.cwd();
431
+ const workspaceMcpResults = installWorkspaceLevelMcp(workspaceRoot);
432
+ const hasWorkspaceConfig = workspaceMcpResults.some((r) => r.status === "created" || r.status === "skipped");
433
+
434
+ if (hasWorkspaceConfig) {
435
+ console.log("[GraphFlow] 检测到 workspace 级 MCP 配置,已自动注入 workspace 级 GraphFlow MCP。");
436
+ installWorkspaceLevelSkills(workspaceRoot);
437
+ console.log("[GraphFlow] 如需完整安装(用户级 MCP + Trae Skill),运行:");
438
+ console.log("[GraphFlow] npx @roarpeng/graphflow install");
439
+ } else {
440
+ console.log("[GraphFlow] Local install detected. Auto-setup skipped to avoid modifying your global config.");
441
+ console.log("[GraphFlow] To install GraphFlow MCP + Skill, run:");
442
+ console.log("[GraphFlow] npx @roarpeng/graphflow install");
443
+ }
162
444
  process.exit(0);
163
445
  }
164
446
 
447
+ // 读取当前版本号,用于版本比较和强制更新
448
+ let currentVersion = "unknown";
449
+ try {
450
+ const pkg = require("../package.json");
451
+ currentVersion = pkg.version || "unknown";
452
+ } catch {
453
+ // npm 包中 package.json 在上层目录;如果读取失败则跳过版本比较
454
+ }
455
+
456
+ const forceUpdate = needsForceUpdate(currentVersion);
457
+ const previousVersion = readPreviousVersion();
458
+
165
459
  console.log(`[GraphFlow] Running post-install setup (${globalInstall ? "global install" : "explicitly enabled"})...`);
460
+ console.log(`[GraphFlow] 版本: ${currentVersion}`);
461
+
462
+ if (forceUpdate && previousVersion) {
463
+ console.log(`[GraphFlow] 检测到版本变化 (${previousVersion} → ${currentVersion}),将强制更新所有 Skill/Rules/MCP 文件`);
464
+ } else if (forceUpdate && !previousVersion) {
465
+ console.log("[GraphFlow] 首次安装,将安装所有 Skill/Rules/MCP 文件");
466
+ }
166
467
 
167
468
  const skillSourceDir = getSkillSourceDir();
168
469
  const traeDirs = getTraeUserDirs();
@@ -185,6 +486,23 @@ function main() {
185
486
  console.log(`[GraphFlow] MCP install skipped: ${mcpResult.reason}`);
186
487
  }
187
488
 
489
+ // ─── Cursor Rules 安装 ───
490
+ const cursorRulesResult = installCursorRules();
491
+ if (cursorRulesResult) {
492
+ console.log(`[GraphFlow] Cursor Rules: ${cursorRulesResult.status}${cursorRulesResult.reason ? ` (${cursorRulesResult.reason})` : ""}`);
493
+ }
494
+
495
+ // ─── Claude Code 约定安装 ───
496
+ const claudeMdResult = installClaudeMd();
497
+ if (claudeMdResult) {
498
+ console.log(`[GraphFlow] Claude Code 约定: ${claudeMdResult.status}${claudeMdResult.reason ? ` (${claudeMdResult.reason})` : ""}`);
499
+ }
500
+
501
+ // 写入当前版本号标记文件
502
+ if (currentVersion !== "unknown") {
503
+ writeCurrentVersion(currentVersion);
504
+ }
505
+
188
506
  console.log("[GraphFlow] Post-install complete.");
189
507
  }
190
508
 
@@ -192,4 +510,4 @@ if (require.main === module) {
192
510
  main();
193
511
  }
194
512
 
195
- module.exports = { installSkill, detectTrae, getTraeUserDirs, getSkillSourceDir };
513
+ module.exports = { installSkill, detectTrae, getTraeUserDirs, getSkillSourceDir, readPreviousVersion, writeCurrentVersion, needsForceUpdate, VERSION_FILE };