@diegonogueiradev_/mcp-graph 1.0.0 → 2.0.1

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 (220) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +240 -0
  3. package/dist/api/middleware/error-handler.d.ts +3 -0
  4. package/dist/api/middleware/error-handler.d.ts.map +1 -0
  5. package/dist/api/middleware/error-handler.js +35 -0
  6. package/dist/api/middleware/error-handler.js.map +1 -0
  7. package/dist/api/middleware/validate.d.ts +5 -0
  8. package/dist/api/middleware/validate.d.ts.map +1 -0
  9. package/dist/api/middleware/validate.js +23 -0
  10. package/dist/api/middleware/validate.js.map +1 -0
  11. package/dist/api/router.d.ts +11 -0
  12. package/dist/api/router.d.ts.map +1 -0
  13. package/dist/api/router.js +41 -0
  14. package/dist/api/router.js.map +1 -0
  15. package/dist/api/routes/capture.d.ts +3 -0
  16. package/dist/api/routes/capture.d.ts.map +1 -0
  17. package/dist/api/routes/capture.js +31 -0
  18. package/dist/api/routes/capture.js.map +1 -0
  19. package/dist/api/routes/context.d.ts +4 -0
  20. package/dist/api/routes/context.d.ts.map +1 -0
  21. package/dist/api/routes/context.js +25 -0
  22. package/dist/api/routes/context.js.map +1 -0
  23. package/dist/api/routes/docs-cache.d.ts +4 -0
  24. package/dist/api/routes/docs-cache.d.ts.map +1 -0
  25. package/dist/api/routes/docs-cache.js +79 -0
  26. package/dist/api/routes/docs-cache.js.map +1 -0
  27. package/dist/api/routes/edges.d.ts +4 -0
  28. package/dist/api/routes/edges.d.ts.map +1 -0
  29. package/dist/api/routes/edges.js +50 -0
  30. package/dist/api/routes/edges.js.map +1 -0
  31. package/dist/api/routes/events.d.ts +4 -0
  32. package/dist/api/routes/events.d.ts.map +1 -0
  33. package/dist/api/routes/events.js +37 -0
  34. package/dist/api/routes/events.js.map +1 -0
  35. package/dist/api/routes/graph.d.ts +4 -0
  36. package/dist/api/routes/graph.d.ts.map +1 -0
  37. package/dist/api/routes/graph.js +39 -0
  38. package/dist/api/routes/graph.js.map +1 -0
  39. package/dist/api/routes/import.d.ts +4 -0
  40. package/dist/api/routes/import.d.ts.map +1 -0
  41. package/dist/api/routes/import.js +92 -0
  42. package/dist/api/routes/import.js.map +1 -0
  43. package/dist/api/routes/insights.d.ts +4 -0
  44. package/dist/api/routes/insights.d.ts.map +1 -0
  45. package/dist/api/routes/insights.js +40 -0
  46. package/dist/api/routes/insights.js.map +1 -0
  47. package/dist/api/routes/integrations.d.ts +4 -0
  48. package/dist/api/routes/integrations.d.ts.map +1 -0
  49. package/dist/api/routes/integrations.js +56 -0
  50. package/dist/api/routes/integrations.js.map +1 -0
  51. package/dist/api/routes/nodes.d.ts +4 -0
  52. package/dist/api/routes/nodes.d.ts.map +1 -0
  53. package/dist/api/routes/nodes.js +123 -0
  54. package/dist/api/routes/nodes.js.map +1 -0
  55. package/dist/api/routes/project.d.ts +4 -0
  56. package/dist/api/routes/project.d.ts.map +1 -0
  57. package/dist/api/routes/project.js +33 -0
  58. package/dist/api/routes/project.js.map +1 -0
  59. package/dist/api/routes/search.d.ts +4 -0
  60. package/dist/api/routes/search.d.ts.map +1 -0
  61. package/dist/api/routes/search.js +25 -0
  62. package/dist/api/routes/search.js.map +1 -0
  63. package/dist/api/routes/skills.d.ts +3 -0
  64. package/dist/api/routes/skills.d.ts.map +1 -0
  65. package/dist/api/routes/skills.js +16 -0
  66. package/dist/api/routes/skills.js.map +1 -0
  67. package/dist/api/routes/stats.d.ts +4 -0
  68. package/dist/api/routes/stats.d.ts.map +1 -0
  69. package/dist/api/routes/stats.js +14 -0
  70. package/dist/api/routes/stats.js.map +1 -0
  71. package/dist/cli/commands/import-cmd.d.ts +3 -0
  72. package/dist/cli/commands/import-cmd.d.ts.map +1 -0
  73. package/dist/cli/commands/import-cmd.js +38 -0
  74. package/dist/cli/commands/import-cmd.js.map +1 -0
  75. package/dist/cli/commands/init.d.ts +3 -0
  76. package/dist/cli/commands/init.d.ts.map +1 -0
  77. package/dist/cli/commands/init.js +55 -0
  78. package/dist/cli/commands/init.js.map +1 -0
  79. package/dist/cli/commands/serve.d.ts +3 -0
  80. package/dist/cli/commands/serve.d.ts.map +1 -0
  81. package/dist/cli/commands/serve.js +18 -0
  82. package/dist/cli/commands/serve.js.map +1 -0
  83. package/dist/cli/commands/stats.d.ts +3 -0
  84. package/dist/cli/commands/stats.d.ts.map +1 -0
  85. package/dist/cli/commands/stats.js +39 -0
  86. package/dist/cli/commands/stats.js.map +1 -0
  87. package/dist/cli/index.d.ts +3 -0
  88. package/dist/cli/index.d.ts.map +1 -0
  89. package/dist/cli/index.js +17 -0
  90. package/dist/cli/index.js.map +1 -0
  91. package/dist/core/capture/content-extractor.d.ts +21 -0
  92. package/dist/core/capture/content-extractor.d.ts.map +1 -0
  93. package/dist/core/capture/content-extractor.js +74 -0
  94. package/dist/core/capture/content-extractor.js.map +1 -0
  95. package/dist/core/capture/web-capture.d.ts +20 -0
  96. package/dist/core/capture/web-capture.d.ts.map +1 -0
  97. package/dist/core/capture/web-capture.js +51 -0
  98. package/dist/core/capture/web-capture.js.map +1 -0
  99. package/dist/core/config/config-loader.d.ts +3 -0
  100. package/dist/core/config/config-loader.d.ts.map +1 -0
  101. package/dist/core/config/config-loader.js +43 -0
  102. package/dist/core/config/config-loader.js.map +1 -0
  103. package/dist/core/config/config-schema.d.ts +11 -0
  104. package/dist/core/config/config-schema.d.ts.map +1 -0
  105. package/dist/core/config/config-schema.js +12 -0
  106. package/dist/core/config/config-schema.js.map +1 -0
  107. package/dist/core/docs/docs-cache-store.d.ts +24 -0
  108. package/dist/core/docs/docs-cache-store.d.ts.map +1 -0
  109. package/dist/core/docs/docs-cache-store.js +61 -0
  110. package/dist/core/docs/docs-cache-store.js.map +1 -0
  111. package/dist/core/docs/docs-syncer.d.ts +13 -0
  112. package/dist/core/docs/docs-syncer.d.ts.map +1 -0
  113. package/dist/core/docs/docs-syncer.js +38 -0
  114. package/dist/core/docs/docs-syncer.js.map +1 -0
  115. package/dist/core/events/event-bus.d.ts +26 -0
  116. package/dist/core/events/event-bus.d.ts.map +1 -0
  117. package/dist/core/events/event-bus.js +47 -0
  118. package/dist/core/events/event-bus.js.map +1 -0
  119. package/dist/core/events/event-types.d.ts +57 -0
  120. package/dist/core/events/event-types.d.ts.map +1 -0
  121. package/dist/core/events/event-types.js +2 -0
  122. package/dist/core/events/event-types.js.map +1 -0
  123. package/dist/core/graph/mermaid-export.d.ts +9 -0
  124. package/dist/core/graph/mermaid-export.d.ts.map +1 -0
  125. package/dist/core/graph/mermaid-export.js +80 -0
  126. package/dist/core/graph/mermaid-export.js.map +1 -0
  127. package/dist/core/importer/prd-to-graph.d.ts.map +1 -1
  128. package/dist/core/importer/prd-to-graph.js +7 -0
  129. package/dist/core/importer/prd-to-graph.js.map +1 -1
  130. package/dist/core/insights/bottleneck-detector.d.ts +31 -0
  131. package/dist/core/insights/bottleneck-detector.d.ts.map +1 -0
  132. package/dist/core/insights/bottleneck-detector.js +69 -0
  133. package/dist/core/insights/bottleneck-detector.js.map +1 -0
  134. package/dist/core/insights/metrics-calculator.d.ts +31 -0
  135. package/dist/core/insights/metrics-calculator.d.ts.map +1 -0
  136. package/dist/core/insights/metrics-calculator.js +78 -0
  137. package/dist/core/insights/metrics-calculator.js.map +1 -0
  138. package/dist/core/insights/skill-recommender.d.ts +21 -0
  139. package/dist/core/insights/skill-recommender.d.ts.map +1 -0
  140. package/dist/core/insights/skill-recommender.js +129 -0
  141. package/dist/core/insights/skill-recommender.js.map +1 -0
  142. package/dist/core/integrations/serena-reader.d.ts +18 -0
  143. package/dist/core/integrations/serena-reader.d.ts.map +1 -0
  144. package/dist/core/integrations/serena-reader.js +50 -0
  145. package/dist/core/integrations/serena-reader.js.map +1 -0
  146. package/dist/core/integrations/tool-status.d.ts +18 -0
  147. package/dist/core/integrations/tool-status.d.ts.map +1 -0
  148. package/dist/core/integrations/tool-status.js +92 -0
  149. package/dist/core/integrations/tool-status.js.map +1 -0
  150. package/dist/core/parser/file-reader.d.ts +13 -0
  151. package/dist/core/parser/file-reader.d.ts.map +1 -0
  152. package/dist/core/parser/file-reader.js +52 -0
  153. package/dist/core/parser/file-reader.js.map +1 -0
  154. package/dist/core/parser/read-html.d.ts +7 -0
  155. package/dist/core/parser/read-html.d.ts.map +1 -0
  156. package/dist/core/parser/read-html.js +51 -0
  157. package/dist/core/parser/read-html.js.map +1 -0
  158. package/dist/core/parser/read-pdf.d.ts +10 -0
  159. package/dist/core/parser/read-pdf.d.ts.map +1 -0
  160. package/dist/core/parser/read-pdf.js +16 -0
  161. package/dist/core/parser/read-pdf.js.map +1 -0
  162. package/dist/core/planner/next-task.d.ts.map +1 -1
  163. package/dist/core/planner/next-task.js +4 -1
  164. package/dist/core/planner/next-task.js.map +1 -1
  165. package/dist/core/search/fts-search.d.ts.map +1 -1
  166. package/dist/core/search/fts-search.js +6 -1
  167. package/dist/core/search/fts-search.js.map +1 -1
  168. package/dist/core/store/migrations.d.ts.map +1 -1
  169. package/dist/core/store/migrations.js +38 -0
  170. package/dist/core/store/migrations.js.map +1 -1
  171. package/dist/core/store/sqlite-store.d.ts +7 -0
  172. package/dist/core/store/sqlite-store.d.ts.map +1 -1
  173. package/dist/core/store/sqlite-store.js +28 -3
  174. package/dist/core/store/sqlite-store.js.map +1 -1
  175. package/dist/core/utils/logger.d.ts +1 -0
  176. package/dist/core/utils/logger.d.ts.map +1 -1
  177. package/dist/core/utils/logger.js +5 -0
  178. package/dist/core/utils/logger.js.map +1 -1
  179. package/dist/mcp/init-project.d.ts.map +1 -1
  180. package/dist/mcp/init-project.js +12 -16
  181. package/dist/mcp/init-project.js.map +1 -1
  182. package/dist/mcp/server.d.ts +1 -0
  183. package/dist/mcp/server.js +17 -2
  184. package/dist/mcp/server.js.map +1 -1
  185. package/dist/mcp/stdio.js +0 -0
  186. package/dist/mcp/tools/export-mermaid.d.ts +4 -0
  187. package/dist/mcp/tools/export-mermaid.d.ts.map +1 -0
  188. package/dist/mcp/tools/export-mermaid.js +27 -0
  189. package/dist/mcp/tools/export-mermaid.js.map +1 -0
  190. package/dist/mcp/tools/index.d.ts.map +1 -1
  191. package/dist/mcp/tools/index.js +2 -0
  192. package/dist/mcp/tools/index.js.map +1 -1
  193. package/dist/web/dashboard/dist/assets/code-graph-tab-jvBo8Q9t.js +1 -0
  194. package/dist/web/dashboard/dist/assets/constants-CLJl-f3f.js +1 -0
  195. package/dist/web/dashboard/dist/assets/graph-tab-BoKfDlvO.js +1 -0
  196. package/dist/web/dashboard/dist/assets/graph-utils-BZV40eAE.css +1 -0
  197. package/dist/web/dashboard/dist/assets/graph-utils-uGOH4eMw.js +23 -0
  198. package/dist/web/dashboard/dist/assets/index-DM_LGeRr.css +1 -0
  199. package/dist/web/dashboard/dist/assets/index-DrHbgcp5.js +53 -0
  200. package/dist/web/dashboard/dist/assets/insights-tab-D7sHV2xV.js +1 -0
  201. package/dist/web/dashboard/dist/assets/prd-backlog-tab-C_Uq1Qte.js +1 -0
  202. package/dist/web/dashboard/dist/index.html +13 -0
  203. package/dist/web/public/css/styles.css +646 -0
  204. package/dist/web/public/index.html +209 -0
  205. package/dist/web/public/js/api-client.js +85 -0
  206. package/dist/web/public/js/app.js +112 -0
  207. package/dist/web/public/js/capture-form.js +196 -0
  208. package/dist/web/public/js/filters.js +94 -0
  209. package/dist/web/public/js/force-graph-renderer.js +498 -0
  210. package/dist/web/public/js/graph-renderer.js +62 -0
  211. package/dist/web/public/js/import-form.js +105 -0
  212. package/dist/web/public/js/node-detail.js +106 -0
  213. package/dist/web/public/js/tabs/code-graph-tab.js +66 -0
  214. package/dist/web/public/js/tabs/graph-tab.js +238 -0
  215. package/dist/web/public/js/tabs/insights-tab.js +236 -0
  216. package/dist/web/public/js/tabs/knowledge-tab.js +201 -0
  217. package/dist/web/public/js/tabs/prd-backlog-tab.js +167 -0
  218. package/dist/web/public/vendor/force-graph.min.js +5 -0
  219. package/dist/web/public/vendor/mermaid.min.js +2843 -0
  220. package/package.json +22 -3
@@ -0,0 +1,78 @@
1
+ import { calculateVelocity } from "../planner/velocity.js";
2
+ import { logger } from "../utils/logger.js";
3
+ const ALL_STATUSES = ["backlog", "ready", "in_progress", "blocked", "done"];
4
+ /**
5
+ * Calculate comprehensive metrics from the graph.
6
+ */
7
+ export function calculateMetrics(doc) {
8
+ logger.info("Calculating metrics", { nodes: doc.nodes.length });
9
+ const tasks = doc.nodes.filter((n) => n.type === "task" || n.type === "subtask");
10
+ const doneTasks = tasks.filter((n) => n.status === "done");
11
+ // Status distribution
12
+ const statusCounts = new Map();
13
+ for (const status of ALL_STATUSES)
14
+ statusCounts.set(status, 0);
15
+ for (const node of doc.nodes) {
16
+ const count = statusCounts.get(node.status) ?? 0;
17
+ statusCounts.set(node.status, count + 1);
18
+ }
19
+ const totalNodes = doc.nodes.length;
20
+ const statusDistribution = ALL_STATUSES.map((status) => {
21
+ const count = statusCounts.get(status) ?? 0;
22
+ return {
23
+ status,
24
+ count,
25
+ percentage: totalNodes > 0 ? Math.round((count / totalNodes) * 100) : 0,
26
+ };
27
+ });
28
+ // Velocity from existing planner
29
+ let velocityData = { tasksCompleted: 0, avgPointsPerTask: 0, avgCompletionHours: 0 };
30
+ try {
31
+ const velocity = calculateVelocity(doc);
32
+ velocityData = {
33
+ tasksCompleted: velocity.overall.totalTasksCompleted,
34
+ avgPointsPerTask: velocity.overall.totalPoints > 0 && velocity.overall.totalTasksCompleted > 0
35
+ ? Math.round(velocity.overall.totalPoints / velocity.overall.totalTasksCompleted * 10) / 10
36
+ : 0,
37
+ avgCompletionHours: velocity.overall.avgCompletionHours ?? 0,
38
+ };
39
+ }
40
+ catch {
41
+ // Velocity calculation may fail with no sprints
42
+ }
43
+ // Sprint progress
44
+ const sprintMap = new Map();
45
+ for (const task of tasks) {
46
+ const sprint = task.sprint ?? "__unassigned__";
47
+ const list = sprintMap.get(sprint) ?? [];
48
+ list.push(task);
49
+ sprintMap.set(sprint, list);
50
+ }
51
+ const sprintProgress = [];
52
+ for (const [sprint, sprintTasks] of sprintMap) {
53
+ if (sprint === "__unassigned__")
54
+ continue;
55
+ const total = sprintTasks.length;
56
+ const done = sprintTasks.filter((t) => t.status === "done").length;
57
+ const inProgress = sprintTasks.filter((t) => t.status === "in_progress").length;
58
+ const blocked = sprintTasks.filter((t) => t.status === "blocked" || t.blocked).length;
59
+ sprintProgress.push({
60
+ sprint,
61
+ total,
62
+ done,
63
+ inProgress,
64
+ blocked,
65
+ percentage: total > 0 ? Math.round((done / total) * 100) : 0,
66
+ });
67
+ }
68
+ sprintProgress.sort((a, b) => a.sprint.localeCompare(b.sprint));
69
+ return {
70
+ totalNodes,
71
+ totalTasks: tasks.length,
72
+ completionRate: tasks.length > 0 ? Math.round((doneTasks.length / tasks.length) * 100) : 0,
73
+ statusDistribution,
74
+ velocity: velocityData,
75
+ sprintProgress,
76
+ };
77
+ }
78
+ //# sourceMappingURL=metrics-calculator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics-calculator.js","sourceRoot":"","sources":["../../../src/core/insights/metrics-calculator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AA8B5C,MAAM,YAAY,GAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;AAE1F;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAkB;IACjD,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAEhE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IACjF,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IAE3D,sBAAsB;IACtB,MAAM,YAAY,GAAG,IAAI,GAAG,EAAsB,CAAC;IACnD,KAAK,MAAM,MAAM,IAAI,YAAY;QAAE,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC/D,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACjD,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;IACpC,MAAM,kBAAkB,GAAyB,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QAC3E,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5C,OAAO;YACL,MAAM;YACN,KAAK;YACL,UAAU,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;SACxE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,iCAAiC;IACjC,IAAI,YAAY,GAAG,EAAE,cAAc,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,CAAC;IACrF,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACxC,YAAY,GAAG;YACb,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,mBAAmB;YACpD,gBAAgB,EAAE,QAAQ,CAAC,OAAO,CAAC,WAAW,GAAG,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAC,mBAAmB,GAAG,CAAC;gBAC5F,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,mBAAmB,GAAG,EAAE,CAAC,GAAG,EAAE;gBAC3F,CAAC,CAAC,CAAC;YACL,kBAAkB,EAAE,QAAQ,CAAC,OAAO,CAAC,kBAAkB,IAAI,CAAC;SAC7D,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;IAClD,CAAC;IAED,kBAAkB;IAClB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuB,CAAC;IACjD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,gBAAgB,CAAC;QAC/C,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACzC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,MAAM,cAAc,GAAqB,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,SAAS,EAAE,CAAC;QAC9C,IAAI,MAAM,KAAK,gBAAgB;YAAE,SAAS;QAC1C,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC;QACjC,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;QACnE,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,MAAM,CAAC;QAChF,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;QACtF,cAAc,CAAC,IAAI,CAAC;YAClB,MAAM;YACN,KAAK;YACL,IAAI;YACJ,UAAU;YACV,OAAO;YACP,UAAU,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;SAC7D,CAAC,CAAC;IACL,CAAC;IAED,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAEhE,OAAO;QACL,UAAU;QACV,UAAU,EAAE,KAAK,CAAC,MAAM;QACxB,cAAc,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1F,kBAAkB;QAClB,QAAQ,EAAE,YAAY;QACtB,cAAc;KACf,CAAC;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { GraphDocument } from "../graph/graph-types.js";
2
+ export interface SkillInfo {
3
+ name: string;
4
+ description: string;
5
+ category: string;
6
+ filePath: string;
7
+ }
8
+ export interface SkillRecommendation {
9
+ skill: string;
10
+ reason: string;
11
+ phase: string;
12
+ }
13
+ /**
14
+ * Scan skills directory for SKILL.md files and extract frontmatter.
15
+ */
16
+ export declare function scanSkills(basePath: string): Promise<SkillInfo[]>;
17
+ /**
18
+ * Generate skill recommendations based on current graph state.
19
+ */
20
+ export declare function recommendSkills(doc: GraphDocument, availableSkills: SkillInfo[]): SkillRecommendation[];
21
+ //# sourceMappingURL=skill-recommender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-recommender.d.ts","sourceRoot":"","sources":["../../../src/core/insights/skill-recommender.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG7D,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CA6BvE;AAgCD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,aAAa,EAClB,eAAe,EAAE,SAAS,EAAE,GAC3B,mBAAmB,EAAE,CA8EvB"}
@@ -0,0 +1,129 @@
1
+ import path from "node:path";
2
+ import { readdir, readFile } from "node:fs/promises";
3
+ import { logger } from "../utils/logger.js";
4
+ /**
5
+ * Scan skills directory for SKILL.md files and extract frontmatter.
6
+ */
7
+ export async function scanSkills(basePath) {
8
+ const skillsDirs = [
9
+ path.join(basePath, "copilot-ecosystem", "skills", "agents"),
10
+ path.join(basePath, ".claude", "skills"),
11
+ ];
12
+ const skills = [];
13
+ for (const dir of skillsDirs) {
14
+ try {
15
+ const entries = await readdir(dir, { withFileTypes: true });
16
+ for (const entry of entries) {
17
+ if (!entry.isDirectory())
18
+ continue;
19
+ const skillMdPath = path.join(dir, entry.name, "SKILL.md");
20
+ try {
21
+ const content = await readFile(skillMdPath, "utf-8");
22
+ const info = parseSkillFrontmatter(content, entry.name, skillMdPath);
23
+ if (info)
24
+ skills.push(info);
25
+ }
26
+ catch {
27
+ // No SKILL.md in this directory
28
+ }
29
+ }
30
+ }
31
+ catch {
32
+ // Directory doesn't exist
33
+ }
34
+ }
35
+ logger.info("Skills scanned", { count: skills.length });
36
+ return skills;
37
+ }
38
+ function parseSkillFrontmatter(content, dirName, filePath) {
39
+ // Parse YAML frontmatter between --- delimiters
40
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
41
+ if (!match) {
42
+ return {
43
+ name: dirName,
44
+ description: extractFirstLine(content),
45
+ category: "general",
46
+ filePath,
47
+ };
48
+ }
49
+ const frontmatter = match[1];
50
+ const name = extractField(frontmatter, "name") ?? dirName;
51
+ const description = extractField(frontmatter, "description") ?? extractFirstLine(content);
52
+ const category = extractField(frontmatter, "category") ?? "general";
53
+ return { name, description, category, filePath };
54
+ }
55
+ function extractField(yaml, field) {
56
+ const match = yaml.match(new RegExp(`^${field}:\\s*(.+)$`, "m"));
57
+ return match ? match[1].trim().replace(/^["']|["']$/g, "") : null;
58
+ }
59
+ function extractFirstLine(content) {
60
+ const lines = content.split("\n").filter((l) => l.trim() && !l.startsWith("---") && !l.startsWith("#"));
61
+ return lines[0]?.trim().substring(0, 120) ?? "";
62
+ }
63
+ /**
64
+ * Generate skill recommendations based on current graph state.
65
+ */
66
+ export function recommendSkills(doc, availableSkills) {
67
+ const recommendations = [];
68
+ const skillNames = new Set(availableSkills.map((s) => s.name));
69
+ const tasksByStatus = new Map();
70
+ for (const node of doc.nodes) {
71
+ if (node.type === "task" || node.type === "subtask") {
72
+ const count = tasksByStatus.get(node.status) ?? 0;
73
+ tasksByStatus.set(node.status, count + 1);
74
+ }
75
+ }
76
+ const inProgressCount = tasksByStatus.get("in_progress") ?? 0;
77
+ const backlogCount = tasksByStatus.get("backlog") ?? 0;
78
+ const blockedCount = tasksByStatus.get("blocked") ?? 0;
79
+ // Tasks without tests
80
+ const tasksWithoutTests = doc.nodes.filter((n) => (n.type === "task" || n.type === "subtask") &&
81
+ n.status === "in_progress" &&
82
+ !n.tags?.includes("tested"));
83
+ if (tasksWithoutTests.length > 0 && skillNames.has("polyglot-test-generator")) {
84
+ recommendations.push({
85
+ skill: "polyglot-test-generator",
86
+ reason: `${tasksWithoutTests.length} tasks in progress without test coverage`,
87
+ phase: "IMPLEMENT",
88
+ });
89
+ }
90
+ // Review pending
91
+ const readyForReview = doc.nodes.filter((n) => n.type === "task" && n.status === "in_progress" && n.tags?.includes("review-pending"));
92
+ if (readyForReview.length > 0 && skillNames.has("code-reviewer")) {
93
+ recommendations.push({
94
+ skill: "code-reviewer",
95
+ reason: `${readyForReview.length} tasks pending review`,
96
+ phase: "REVIEW",
97
+ });
98
+ }
99
+ // High blocked count
100
+ if (blockedCount > 3) {
101
+ recommendations.push({
102
+ skill: "dev-flow-orchestrator",
103
+ reason: `${blockedCount} blocked tasks — consider re-planning dependencies`,
104
+ phase: "ANALYZE",
105
+ });
106
+ }
107
+ // Large backlog
108
+ if (backlogCount > 20 && inProgressCount === 0) {
109
+ recommendations.push({
110
+ skill: "dev-flow-orchestrator",
111
+ reason: `${backlogCount} tasks in backlog with none in progress — start sprint planning`,
112
+ phase: "PLAN",
113
+ });
114
+ }
115
+ // Missing acceptance criteria
116
+ const missingAC = doc.nodes.filter((n) => (n.type === "task" || n.type === "epic") &&
117
+ n.status !== "done" &&
118
+ (!n.acceptanceCriteria || n.acceptanceCriteria.length === 0));
119
+ if (missingAC.length > 5) {
120
+ recommendations.push({
121
+ skill: "create-prd-chat-mode",
122
+ reason: `${missingAC.length} tasks/epics without acceptance criteria`,
123
+ phase: "DESIGN",
124
+ });
125
+ }
126
+ logger.info("Skill recommendations generated", { count: recommendations.length });
127
+ return recommendations;
128
+ }
129
+ //# sourceMappingURL=skill-recommender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-recommender.js","sourceRoot":"","sources":["../../../src/core/insights/skill-recommender.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAe5C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB;IAC/C,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,mBAAmB,EAAE,QAAQ,EAAE,QAAQ,CAAC;QAC5D,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC;KACzC,CAAC;IAEF,MAAM,MAAM,GAAgB,EAAE,CAAC;IAE/B,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;oBAAE,SAAS;gBACnC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBAC3D,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;oBACrD,MAAM,IAAI,GAAG,qBAAqB,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;oBACrE,IAAI,IAAI;wBAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9B,CAAC;gBAAC,MAAM,CAAC;oBACP,gCAAgC;gBAClC,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IACxD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAe,EAAE,OAAe,EAAE,QAAgB;IAC/E,gDAAgD;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACrD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;YACL,IAAI,EAAE,OAAO;YACb,WAAW,EAAE,gBAAgB,CAAC,OAAO,CAAC;YACtC,QAAQ,EAAE,SAAS;YACnB,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC;IAC1D,MAAM,WAAW,GAAG,YAAY,CAAC,WAAW,EAAE,aAAa,CAAC,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC1F,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,EAAE,UAAU,CAAC,IAAI,SAAS,CAAC;IAEpE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AACnD,CAAC;AAED,SAAS,YAAY,CAAC,IAAY,EAAE,KAAa;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC;IACjE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACpE,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAe;IACvC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IACxG,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,GAAkB,EAClB,eAA4B;IAE5B,MAAM,eAAe,GAA0B,EAAE,CAAC;IAClD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAE/D,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACpD,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClD,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,MAAM,eAAe,GAAG,aAAa,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAEvD,sBAAsB;IACtB,MAAM,iBAAiB,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CACxC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;QAC3C,CAAC,CAAC,MAAM,KAAK,aAAa;QAC1B,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAC9B,CAAC;IACF,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,yBAAyB,CAAC,EAAE,CAAC;QAC9E,eAAe,CAAC,IAAI,CAAC;YACnB,KAAK,EAAE,yBAAyB;YAChC,MAAM,EAAE,GAAG,iBAAiB,CAAC,MAAM,0CAA0C;YAC7E,KAAK,EAAE,WAAW;SACnB,CAAC,CAAC;IACL,CAAC;IAED,iBAAiB;IACjB,MAAM,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,aAAa,IAAI,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAC7F,CAAC;IACF,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;QACjE,eAAe,CAAC,IAAI,CAAC;YACnB,KAAK,EAAE,eAAe;YACtB,MAAM,EAAE,GAAG,cAAc,CAAC,MAAM,uBAAuB;YACvD,KAAK,EAAE,QAAQ;SAChB,CAAC,CAAC;IACL,CAAC;IAED,qBAAqB;IACrB,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACrB,eAAe,CAAC,IAAI,CAAC;YACnB,KAAK,EAAE,uBAAuB;YAC9B,MAAM,EAAE,GAAG,YAAY,oDAAoD;YAC3E,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;IACL,CAAC;IAED,gBAAgB;IAChB,IAAI,YAAY,GAAG,EAAE,IAAI,eAAe,KAAK,CAAC,EAAE,CAAC;QAC/C,eAAe,CAAC,IAAI,CAAC;YACnB,KAAK,EAAE,uBAAuB;YAC9B,MAAM,EAAE,GAAG,YAAY,iEAAiE;YACxF,KAAK,EAAE,MAAM;SACd,CAAC,CAAC;IACL,CAAC;IAED,8BAA8B;IAC9B,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAChC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;QACxC,CAAC,CAAC,MAAM,KAAK,MAAM;QACnB,CAAC,CAAC,CAAC,CAAC,kBAAkB,IAAI,CAAC,CAAC,kBAAkB,CAAC,MAAM,KAAK,CAAC,CAAC,CAC/D,CAAC;IACF,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,eAAe,CAAC,IAAI,CAAC;YACnB,KAAK,EAAE,sBAAsB;YAC7B,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,0CAA0C;YACrE,KAAK,EAAE,QAAQ;SAChB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,iCAAiC,EAAE,EAAE,KAAK,EAAE,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC;IAClF,OAAO,eAAe,CAAC;AACzB,CAAC"}
@@ -0,0 +1,18 @@
1
+ export interface SerenaMemory {
2
+ name: string;
3
+ content: string;
4
+ sizeBytes: number;
5
+ }
6
+ /**
7
+ * List all Serena memory files from the project directory.
8
+ */
9
+ export declare function listSerenaMemories(basePath: string): Promise<string[]>;
10
+ /**
11
+ * Read a specific Serena memory file.
12
+ */
13
+ export declare function readSerenaMemory(basePath: string, name: string): Promise<SerenaMemory | null>;
14
+ /**
15
+ * Read all Serena memories at once.
16
+ */
17
+ export declare function readAllSerenaMemories(basePath: string): Promise<SerenaMemory[]>;
18
+ //# sourceMappingURL=serena-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serena-reader.d.ts","sourceRoot":"","sources":["../../../src/core/integrations/serena-reader.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAS5E;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAanG;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAUrF"}
@@ -0,0 +1,50 @@
1
+ import path from "node:path";
2
+ import { readdir, readFile } from "node:fs/promises";
3
+ import { logger } from "../utils/logger.js";
4
+ const SERENA_MEMORIES_DIR = ".serena/memories";
5
+ /**
6
+ * List all Serena memory files from the project directory.
7
+ */
8
+ export async function listSerenaMemories(basePath) {
9
+ try {
10
+ const dir = path.join(basePath, SERENA_MEMORIES_DIR);
11
+ const files = await readdir(dir);
12
+ return files.filter((f) => f.endsWith(".md")).map((f) => f.replace(/\.md$/, ""));
13
+ }
14
+ catch {
15
+ logger.info("No Serena memories directory found", { basePath });
16
+ return [];
17
+ }
18
+ }
19
+ /**
20
+ * Read a specific Serena memory file.
21
+ */
22
+ export async function readSerenaMemory(basePath, name) {
23
+ try {
24
+ const filePath = path.join(basePath, SERENA_MEMORIES_DIR, `${name}.md`);
25
+ const content = await readFile(filePath, "utf-8");
26
+ return {
27
+ name,
28
+ content,
29
+ sizeBytes: Buffer.byteLength(content, "utf-8"),
30
+ };
31
+ }
32
+ catch {
33
+ logger.info("Serena memory not found", { name });
34
+ return null;
35
+ }
36
+ }
37
+ /**
38
+ * Read all Serena memories at once.
39
+ */
40
+ export async function readAllSerenaMemories(basePath) {
41
+ const names = await listSerenaMemories(basePath);
42
+ const memories = [];
43
+ for (const name of names) {
44
+ const memory = await readSerenaMemory(basePath, name);
45
+ if (memory)
46
+ memories.push(memory);
47
+ }
48
+ return memories;
49
+ }
50
+ //# sourceMappingURL=serena-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serena-reader.js","sourceRoot":"","sources":["../../../src/core/integrations/serena-reader.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAQ5C,MAAM,mBAAmB,GAAG,kBAAkB,CAAC;AAE/C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAgB;IACvD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IACnF,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,oCAAoC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChE,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAgB,EAAE,IAAY;IACnE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,mBAAmB,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;QACxE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAClD,OAAO;YACL,IAAI;YACJ,OAAO;YACP,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC;SAC/C,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,QAAgB;IAC1D,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAmB,EAAE,CAAC;IAEpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACtD,IAAI,MAAM;YAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,18 @@
1
+ export interface ToolInfo {
2
+ installed: boolean;
3
+ running: boolean;
4
+ url?: string;
5
+ details?: Record<string, unknown>;
6
+ }
7
+ export interface IntegrationsStatus {
8
+ gitnexus: ToolInfo;
9
+ serena: ToolInfo & {
10
+ memories: string[];
11
+ };
12
+ playwright: ToolInfo;
13
+ }
14
+ /**
15
+ * Detect status of all ecosystem tools.
16
+ */
17
+ export declare function getIntegrationsStatus(basePath: string): Promise<IntegrationsStatus>;
18
+ //# sourceMappingURL=tool-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-status.d.ts","sourceRoot":"","sources":["../../../src/core/integrations/tool-status.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,QAAQ,GAAG;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC1C,UAAU,EAAE,QAAQ,CAAC;CACtB;AA6DD;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA+BzF"}
@@ -0,0 +1,92 @@
1
+ import { logger } from "../utils/logger.js";
2
+ /**
3
+ * Detect whether a local HTTP service is running by attempting a fetch.
4
+ */
5
+ async function probeHttp(url, timeoutMs = 2000) {
6
+ try {
7
+ const controller = new AbortController();
8
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
9
+ const res = await fetch(url, { signal: controller.signal });
10
+ clearTimeout(timer);
11
+ return res.ok || res.status < 500;
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+ /**
18
+ * Check if a command-line tool is installed by looking for it in PATH.
19
+ */
20
+ async function isCommandInstalled(command) {
21
+ try {
22
+ const { execFile } = await import("node:child_process");
23
+ const { promisify } = await import("node:util");
24
+ const exec = promisify(execFile);
25
+ await exec("which", [command]);
26
+ return true;
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ /**
33
+ * Read Serena memory file names from .serena/memories/ directory.
34
+ */
35
+ async function readSerenaMemories(basePath) {
36
+ try {
37
+ const path = await import("node:path");
38
+ const { readdir } = await import("node:fs/promises");
39
+ const memoriesDir = path.join(basePath, ".serena", "memories");
40
+ const files = await readdir(memoriesDir);
41
+ return files.filter((f) => f.endsWith(".md")).map((f) => f.replace(/\.md$/, ""));
42
+ }
43
+ catch {
44
+ return [];
45
+ }
46
+ }
47
+ /**
48
+ * Check if Serena is configured for this project.
49
+ */
50
+ async function isSerenaConfigured(basePath) {
51
+ try {
52
+ const path = await import("node:path");
53
+ const { access } = await import("node:fs/promises");
54
+ await access(path.join(basePath, ".serena"));
55
+ return true;
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ }
61
+ /**
62
+ * Detect status of all ecosystem tools.
63
+ */
64
+ export async function getIntegrationsStatus(basePath) {
65
+ logger.info("Checking integrations status", { basePath });
66
+ const GITNEXUS_PORT = parseInt(process.env.GITNEXUS_PORT || "3737", 10);
67
+ const gitnexusUrl = `http://localhost:${GITNEXUS_PORT}`;
68
+ const [gitnexusInstalled, gitnexusRunning, serenaConfigured, serenaMemories, playwrightInstalled] = await Promise.all([
69
+ isCommandInstalled("gitnexus"),
70
+ probeHttp(gitnexusUrl),
71
+ isSerenaConfigured(basePath),
72
+ readSerenaMemories(basePath),
73
+ isCommandInstalled("npx").then(() => true).catch(() => false),
74
+ ]);
75
+ return {
76
+ gitnexus: {
77
+ installed: gitnexusInstalled,
78
+ running: gitnexusRunning,
79
+ ...(gitnexusRunning ? { url: gitnexusUrl } : {}),
80
+ },
81
+ serena: {
82
+ installed: serenaConfigured,
83
+ running: serenaConfigured,
84
+ memories: serenaMemories,
85
+ },
86
+ playwright: {
87
+ installed: playwrightInstalled,
88
+ running: false,
89
+ },
90
+ };
91
+ }
92
+ //# sourceMappingURL=tool-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-status.js","sourceRoot":"","sources":["../../../src/core/integrations/tool-status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface FileReadResult {
2
+ text: string;
3
+ originalName: string;
4
+ format: string;
5
+ sizeBytes: number;
6
+ }
7
+ /**
8
+ * Read a file and extract its text content based on extension.
9
+ * Supports: .md, .txt, .pdf, .html, .htm
10
+ */
11
+ export declare function readFileContent(filePath: string, originalName?: string): Promise<FileReadResult>;
12
+ export declare function isSupportedFormat(filename: string): boolean;
13
+ //# sourceMappingURL=file-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-reader.d.ts","sourceRoot":"","sources":["../../../src/core/parser/file-reader.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,cAAc,CAAC,CA4CzB;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG3D"}
@@ -0,0 +1,52 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { readPdfBuffer } from "./read-pdf.js";
4
+ import { readHtmlContent } from "./read-html.js";
5
+ import { logger } from "../utils/logger.js";
6
+ const SUPPORTED_EXTENSIONS = new Set([".md", ".txt", ".pdf", ".html", ".htm"]);
7
+ /**
8
+ * Read a file and extract its text content based on extension.
9
+ * Supports: .md, .txt, .pdf, .html, .htm
10
+ */
11
+ export async function readFileContent(filePath, originalName) {
12
+ const name = originalName ?? path.basename(filePath);
13
+ const ext = path.extname(name).toLowerCase();
14
+ if (!SUPPORTED_EXTENSIONS.has(ext)) {
15
+ throw new Error(`Unsupported file format: "${ext}". Supported: ${[...SUPPORTED_EXTENSIONS].join(", ")}`);
16
+ }
17
+ logger.info("Reading file", { name, ext });
18
+ const buffer = await readFile(filePath);
19
+ const sizeBytes = buffer.length;
20
+ let text;
21
+ switch (ext) {
22
+ case ".pdf": {
23
+ const result = await readPdfBuffer(buffer);
24
+ text = result.text;
25
+ break;
26
+ }
27
+ case ".html":
28
+ case ".htm": {
29
+ const html = buffer.toString("utf-8");
30
+ text = await readHtmlContent(html);
31
+ break;
32
+ }
33
+ case ".md":
34
+ case ".txt":
35
+ default: {
36
+ text = buffer.toString("utf-8");
37
+ break;
38
+ }
39
+ }
40
+ logger.info("File read complete", { name, format: ext, textLength: text.length });
41
+ return {
42
+ text,
43
+ originalName: name,
44
+ format: ext,
45
+ sizeBytes,
46
+ };
47
+ }
48
+ export function isSupportedFormat(filename) {
49
+ const ext = path.extname(filename).toLowerCase();
50
+ return SUPPORTED_EXTENSIONS.has(ext);
51
+ }
52
+ //# sourceMappingURL=file-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-reader.js","sourceRoot":"","sources":["../../../src/core/parser/file-reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAS/E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,YAAqB;IAErB,MAAM,IAAI,GAAG,YAAY,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAE7C,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,6BAA6B,GAAG,iBAAiB,CAAC,GAAG,oBAAoB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxF,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC;IAChC,IAAI,IAAY,CAAC;IAEjB,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;YAC3C,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACnB,MAAM;QACR,CAAC;QACD,KAAK,OAAO,CAAC;QACb,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACtC,IAAI,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM;QACR,CAAC;QACD,KAAK,KAAK,CAAC;QACX,KAAK,MAAM,CAAC;QACZ,OAAO,CAAC,CAAC,CAAC;YACR,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAChC,MAAM;QACR,CAAC;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAElF,OAAO;QACL,IAAI;QACJ,YAAY,EAAE,IAAI;QAClB,MAAM,EAAE,GAAG;QACX,SAAS;KACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,OAAO,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Extract text content from an HTML string using cheerio.
3
+ * Converts headings to markdown format so the parser pipeline can segment them.
4
+ * Strips tags, scripts, styles, and normalizes whitespace.
5
+ */
6
+ export declare function readHtmlContent(html: string): Promise<string>;
7
+ //# sourceMappingURL=read-html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-html.d.ts","sourceRoot":"","sources":["../../../src/core/parser/read-html.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA6CnE"}
@@ -0,0 +1,51 @@
1
+ import { logger } from "../utils/logger.js";
2
+ const HEADING_MAP = {
3
+ h1: "#",
4
+ h2: "##",
5
+ h3: "###",
6
+ h4: "####",
7
+ h5: "#####",
8
+ h6: "######",
9
+ };
10
+ /**
11
+ * Extract text content from an HTML string using cheerio.
12
+ * Converts headings to markdown format so the parser pipeline can segment them.
13
+ * Strips tags, scripts, styles, and normalizes whitespace.
14
+ */
15
+ export async function readHtmlContent(html) {
16
+ // Dynamic import — cheerio is heavy, lazy-load
17
+ const { load } = await import("cheerio");
18
+ logger.info("Parsing HTML content", { sizeChars: html.length });
19
+ const $ = load(html);
20
+ // Remove non-content elements
21
+ $("script, style, nav, footer, header, noscript, iframe").remove();
22
+ // Convert HTML headings to markdown headings
23
+ for (const [tag, prefix] of Object.entries(HEADING_MAP)) {
24
+ $(tag).each(function () {
25
+ const el = $(this);
26
+ const text = el.text().trim();
27
+ el.replaceWith(`\n\n${prefix} ${text}\n\n`);
28
+ });
29
+ }
30
+ // Convert list items to markdown bullets
31
+ $("li").each(function () {
32
+ const el = $(this);
33
+ const text = el.text().trim();
34
+ el.replaceWith(`\n- ${text}`);
35
+ });
36
+ // Add line breaks for block elements
37
+ const blockElements = "p, div, section, article, blockquote, pre, br, tr";
38
+ $(blockElements).each(function () {
39
+ $(this).prepend("\n");
40
+ $(this).append("\n");
41
+ });
42
+ // Extract text from body (or whole doc if no body)
43
+ const rawText = $("body").length ? $("body").text() : $.root().text();
44
+ const text = rawText
45
+ .replace(/[ \t]+/g, " ")
46
+ .replace(/\n{3,}/g, "\n\n")
47
+ .trim();
48
+ logger.info("HTML parsed", { textLength: text.length });
49
+ return text;
50
+ }
51
+ //# sourceMappingURL=read-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-html.js","sourceRoot":"","sources":["../../../src/core/parser/read-html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,WAAW,GAA2B;IAC1C,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,KAAK;IACT,EAAE,EAAE,MAAM;IACV,EAAE,EAAE,OAAO;IACX,EAAE,EAAE,QAAQ;CACb,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,+CAA+C;IAC/C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IAEzC,MAAM,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAEhE,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IAErB,8BAA8B;IAC9B,CAAC,CAAC,sDAAsD,CAAC,CAAC,MAAM,EAAE,CAAC;IAEnE,6CAA6C;IAC7C,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACxD,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACV,MAAM,EAAE,GAAG,CAAC,CAAC,IAAc,CAAC,CAAC;YAC7B,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;YAC9B,EAAE,CAAC,WAAW,CAAC,OAAO,MAAM,IAAI,IAAI,MAAM,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,yCAAyC;IACzC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;QACX,MAAM,EAAE,GAAG,CAAC,CAAC,IAAc,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;QAC9B,EAAE,CAAC,WAAW,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,qCAAqC;IACrC,MAAM,aAAa,GAAG,mDAAmD,CAAC;IAC1E,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC;QACpB,CAAC,CAAC,IAAc,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC,CAAC,IAAc,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,mDAAmD;IACnD,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;IAEtE,MAAM,IAAI,GAAG,OAAO;SACjB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;SAC1B,IAAI,EAAE,CAAC;IAEV,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAExD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,10 @@
1
+ interface PdfReadResult {
2
+ text: string;
3
+ pages: number;
4
+ }
5
+ /**
6
+ * Extract text content from a PDF buffer using pdf-parse.
7
+ */
8
+ export declare function readPdfBuffer(buffer: Buffer): Promise<PdfReadResult>;
9
+ export {};
10
+ //# sourceMappingURL=read-pdf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-pdf.d.ts","sourceRoot":"","sources":["../../../src/core/parser/read-pdf.ts"],"names":[],"mappings":"AAEA,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAc1E"}
@@ -0,0 +1,16 @@
1
+ import { logger } from "../utils/logger.js";
2
+ /**
3
+ * Extract text content from a PDF buffer using pdf-parse.
4
+ */
5
+ export async function readPdfBuffer(buffer) {
6
+ // Dynamic import — pdf-parse is CJS, lazy-load to avoid startup cost
7
+ const pdfParse = (await import("pdf-parse")).default;
8
+ logger.info("Parsing PDF buffer", { sizeBytes: buffer.length });
9
+ const result = await pdfParse(buffer);
10
+ logger.info("PDF parsed", { pages: result.numpages, textLength: result.text.length });
11
+ return {
12
+ text: result.text,
13
+ pages: result.numpages,
14
+ };
15
+ }
16
+ //# sourceMappingURL=read-pdf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-pdf.js","sourceRoot":"","sources":["../../../src/core/parser/read-pdf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAO5C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc;IAChD,qEAAqE;IACrE,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;IAErD,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAEhE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEtC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAEtF,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,KAAK,EAAE,MAAM,CAAC,QAAQ;KACvB,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"next-task.d.ts","sourceRoot":"","sources":["../../../src/core/planner/next-task.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAU,MAAM,yBAAyB,CAAC;AAOhF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,GAAG,IAAI,CA0EtE"}
1
+ {"version":3,"file":"next-task.d.ts","sourceRoot":"","sources":["../../../src/core/planner/next-task.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAU,MAAM,yBAAyB,CAAC;AAOhF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,GAAG,IAAI,CA6EtE"}