@roarpeng/graphflow 1.0.9 → 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 (147) hide show
  1. package/README.md +9 -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/graph/graphify-file-client.d.ts.map +1 -1
  81. package/dist/graph/graphify-file-client.js +16 -6
  82. package/dist/graph/graphify-file-client.js.map +1 -1
  83. package/dist/index.d.ts +1 -1
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +2 -1
  86. package/dist/index.js.map +1 -1
  87. package/dist/integrations/agent-mcp-installer.d.ts +25 -1
  88. package/dist/integrations/agent-mcp-installer.d.ts.map +1 -1
  89. package/dist/integrations/agent-mcp-installer.js +189 -9
  90. package/dist/integrations/agent-mcp-installer.js.map +1 -1
  91. package/dist/integrations/skill-installer.d.ts +50 -0
  92. package/dist/integrations/skill-installer.d.ts.map +1 -0
  93. package/dist/integrations/skill-installer.js +373 -0
  94. package/dist/integrations/skill-installer.js.map +1 -0
  95. package/dist/learning/embeddings.d.ts +11 -0
  96. package/dist/learning/embeddings.d.ts.map +1 -1
  97. package/dist/learning/embeddings.js +24 -0
  98. package/dist/learning/embeddings.js.map +1 -1
  99. package/dist/learning/episodic-memory.d.ts +3 -2
  100. package/dist/learning/episodic-memory.d.ts.map +1 -1
  101. package/dist/learning/episodic-memory.js +105 -10
  102. package/dist/learning/episodic-memory.js.map +1 -1
  103. package/dist/learning/local-embedding.d.ts.map +1 -1
  104. package/dist/learning/local-embedding.js +16 -0
  105. package/dist/learning/local-embedding.js.map +1 -1
  106. package/dist/learning/seed-skills.d.ts +21 -0
  107. package/dist/learning/seed-skills.d.ts.map +1 -0
  108. package/dist/learning/seed-skills.js +113 -0
  109. package/dist/learning/seed-skills.js.map +1 -0
  110. package/dist/learning/skill-evolution.d.ts +1 -1
  111. package/dist/learning/skill-evolution.d.ts.map +1 -1
  112. package/dist/learning/skill-evolution.js +1 -1
  113. package/dist/learning/skill-evolution.js.map +1 -1
  114. package/dist/learning/skill-package.d.ts +55 -0
  115. package/dist/learning/skill-package.d.ts.map +1 -0
  116. package/dist/learning/skill-package.js +115 -0
  117. package/dist/learning/skill-package.js.map +1 -0
  118. package/dist/learning/triage-telemetry.d.ts +43 -0
  119. package/dist/learning/triage-telemetry.d.ts.map +1 -0
  120. package/dist/learning/triage-telemetry.js +114 -0
  121. package/dist/learning/triage-telemetry.js.map +1 -0
  122. package/dist/surfaces/cli/index.js +65 -0
  123. package/dist/surfaces/cli/index.js.map +1 -1
  124. package/dist/surfaces/cli/init.d.ts +17 -1
  125. package/dist/surfaces/cli/init.d.ts.map +1 -1
  126. package/dist/surfaces/cli/init.js +254 -25
  127. package/dist/surfaces/cli/init.js.map +1 -1
  128. package/dist/surfaces/cli/output.d.ts.map +1 -1
  129. package/dist/surfaces/cli/output.js +5 -0
  130. package/dist/surfaces/cli/output.js.map +1 -1
  131. package/dist/surfaces/cli/runtime/graph.d.ts +23 -0
  132. package/dist/surfaces/cli/runtime/graph.d.ts.map +1 -1
  133. package/dist/surfaces/cli/runtime/graph.js +40 -0
  134. package/dist/surfaces/cli/runtime/graph.js.map +1 -1
  135. package/dist/surfaces/cli/runtime/routing.d.ts.map +1 -1
  136. package/dist/surfaces/cli/runtime/routing.js +8 -1
  137. package/dist/surfaces/cli/runtime/routing.js.map +1 -1
  138. package/dist/surfaces/cli/runtime.d.ts +1 -1
  139. package/dist/surfaces/cli/runtime.d.ts.map +1 -1
  140. package/dist/surfaces/cli/runtime.js +4 -1
  141. package/dist/surfaces/cli/runtime.js.map +1 -1
  142. package/dist/surfaces/cursor-rules/graphflow.mdc +131 -0
  143. package/dist/surfaces/mcp/tool-definitions.js +20 -20
  144. package/dist/surfaces/mcp/tool-definitions.js.map +1 -1
  145. package/package.json +4 -3
  146. package/scripts/safe-postinstall.cjs +323 -5
  147. package/src/surfaces/cursor-rules/graphflow.mdc +131 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roarpeng/graphflow",
3
- "version": "1.0.9",
3
+ "version": "1.2.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -9,6 +9,7 @@
9
9
  "wasm",
10
10
  "scripts/safe-postinstall.cjs",
11
11
  "src/surfaces/trae-skill",
12
+ "src/surfaces/cursor-rules",
12
13
  "README.md",
13
14
  "LICENSE",
14
15
  "CHANGELOG.md",
@@ -71,7 +72,7 @@
71
72
  "@types/node": "^25.9.1",
72
73
  "@typescript-eslint/eslint-plugin": "^8.60.0",
73
74
  "@typescript-eslint/parser": "^8.60.0",
74
- "@vitest/coverage-v8": "^4.1.8",
75
+ "@vitest/coverage-v8": "^3.2.6",
75
76
  "eslint": "^10.4.0",
76
77
  "husky": "^9.1.7",
77
78
  "lint-staged": "^16.4.0",
@@ -79,7 +80,7 @@
79
80
  "tree-sitter-wasms": "0.1.11",
80
81
  "tsx": "^4.22.3",
81
82
  "typescript": "^6.0.3",
82
- "vitest": "^4.1.7"
83
+ "vitest": "^3.2.6"
83
84
  },
84
85
  "dependencies": {
85
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 };
@@ -0,0 +1,131 @@
1
+ ---
2
+ description: Use GraphFlow first for token-efficient repo context, planning, and orchestration.
3
+ globs:
4
+ - "**/*"
5
+ alwaysApply: true
6
+ ---
7
+
8
+ # GraphFlow Token-First Rule
9
+
10
+ GraphFlow is a graph-based context and planning service backed by a persistent MCP server. It turns codebases into queryable knowledge graphs, delivering token-efficient compressed context, task planning, and orchestration.
11
+
12
+ Before broad code exploration, implementation, debugging, review, planning, or architecture questions:
13
+
14
+ 1. Call `graphflow_preview_context` with the user's task/query.
15
+ 2. Use the returned `summary`, `anchors`, `refillPreview`, and `tokenBudget` as the first context source.
16
+ 3. Read full files only when:
17
+ - GraphFlow anchors point to that file/symbol,
18
+ - the compressed context is insufficient,
19
+ - or exact edits require the file body.
20
+ 4. For multi-step or ambiguous work, call `graphflow_plan` before implementation.
21
+ 5. For graph freshness after project changes, call `graphflow_index`.
22
+ 6. Report token budget when available:
23
+ - estimated raw tokens,
24
+ - compressed tokens,
25
+ - estimated savings percent,
26
+ - max context token budget.
27
+
28
+ Do not scan the whole repository, recursively inspect many files, or read large files before trying GraphFlow context.
29
+
30
+ ## Tool Inventory (18 MCP Tools)
31
+
32
+ ### Core Context Tools (Highest Frequency)
33
+
34
+ | Tool | Purpose | Call Frequency |
35
+ |------|---------|---------------|
36
+ | `graphflow_preview_context` | Compress task context with token budget | **Highest** - default first step |
37
+ | `graphflow_expand_anchor` | Expand a single anchor to full content | **High** - dive deeper into specific items |
38
+
39
+ ### Planning Tools (High Frequency)
40
+
41
+ | Tool | Purpose | Call Frequency |
42
+ |------|---------|---------------|
43
+ | `graphflow_plan` | Multi-step task decomposition & DAG | High - before complex work |
44
+ | `graphflow_plan_insight` | Six Thinking Hats + 5-Why deep analysis | Medium - ambiguous/high-stakes tasks |
45
+ | `graphflow_run` | Plan + context package (bridge mode) | Medium - full task packaging |
46
+ | `graphflow_report_outcome` | Report bridge-mode execution outcome back | Medium - close the learning loop |
47
+
48
+ ### Graph Management Tools (Medium Frequency)
49
+
50
+ | Tool | Purpose | Call Frequency |
51
+ |------|---------|---------------|
52
+ | `graphflow_index` | Incremental workspace re-index | Medium - after file changes |
53
+ | `graphflow_index_file` | Single file incremental index | Medium-High - after saving a file |
54
+ | `graphflow_rebuild` | Clear cache + full re-index | Low - when graph is stale/corrupted |
55
+ | `graphflow_inspect_graph` | Graph stats & sample nodes/edges | Low - check graph health |
56
+ | `graphflow_enrich_graph` | Semantic enrichment of symbols | Rare - LLM-powered enrichment |
57
+ | `graphflow_model_download` | Download local compression model | Rare - offline setup |
58
+
59
+ ### Collaboration & Insights Tools (Low Frequency)
60
+
61
+ | Tool | Purpose | Call Frequency |
62
+ |------|---------|---------------|
63
+ | `graphflow_export_artifact` | Export graph to portable artifact | Low - team sharing |
64
+ | `graphflow_import_artifact` | Import graph artifact | Low - skip full index on new machine |
65
+ | `graphflow_skill_insights` | Learned skill patterns | Low - leverage prior learning |
66
+ | `graphflow_stats` | Cumulative token savings stats | Low - ROI tracking |
67
+ | `graphflow_metrics` | Prometheus-compatible metrics | Low - observability |
68
+ | `graphflow_diagnose` | Provider health & model routing | Rare - config issues |
69
+
70
+ ## Standard Workflows
71
+
72
+ ### Workflow 1: Context First (90% of tasks)
73
+
74
+ **Use when:** Answering code questions, exploring codebase, understanding modules
75
+
76
+ ```
77
+ Step 1: graphflow_preview_context(query: "<your question>")
78
+ Step 2: Read summary + anchors as primary context
79
+ Step 3: Expand specific anchors with graphflow_expand_anchor when needed
80
+ Step 4: Read full files only when exact edits required
81
+ ```
82
+
83
+ ### Workflow 2: Plan Before Coding (complex tasks)
84
+
85
+ **Use when:** Multi-step changes, refactors, features with unclear scope
86
+
87
+ ```
88
+ Step 1: graphflow_preview_context(query: "<task>")
89
+ Step 2: graphflow_plan(task: "<task description>")
90
+ Step 3: Review plan steps and dependencies
91
+ Step 4: Execute step by step, using GraphFlow context for each step
92
+ Step 5: graphflow_index() after major changes
93
+ ```
94
+
95
+ ### Workflow 3: Deep Analysis (complex/ambiguous tasks)
96
+
97
+ **Use when:** High-stakes changes, root-cause analysis, ambiguous requirements
98
+
99
+ ```
100
+ Step 1: graphflow_preview_context(query: "<task>")
101
+ Step 2: graphflow_plan_insight(task: "<task>")
102
+ Step 3: Review analysis and apply findings
103
+ ```
104
+
105
+ ## Bridge-mode outcome reporting
106
+
107
+ After `graphflow_run`, the external agent **must** call `graphflow_report_outcome` to close the skill flywheel loop:
108
+
109
+ - Pass `episodeId` from the run result, a `success` boolean, and optional `lessons`.
110
+ - Do this after executing the work described in the returned `executionDescriptor`, whether the task succeeded or failed.
111
+ - When the run returns `agentWorkItems`, answer each prompt with your model and call `graphflow_submit_insight` once per item (before or with `graphflow_report_outcome`).
112
+
113
+ CLI fallback:
114
+
115
+ ```bash
116
+ graphflow --json outcome report <episodeId> <success>
117
+ ```
118
+
119
+ If MCP is unavailable, use the CLI fallback and always request JSON output:
120
+
121
+ ```bash
122
+ graphflow --json context preview "<query>"
123
+ graphflow --json plan "<task>"
124
+ graphflow --json graph inspect
125
+ graphflow --json skill insights
126
+ graphflow --json route diagnose
127
+ ```
128
+
129
+ Treat GraphFlow outputs as structured machine-readable data, not prose.
130
+
131
+ When the user asks about saving token usage, optimizing context, repo understanding, or learning from Graphify, prioritize GraphFlow context compression over ordinary file search.