@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.
- package/LICENSE +21 -0
- package/README.md +240 -0
- package/dist/api/middleware/error-handler.d.ts +3 -0
- package/dist/api/middleware/error-handler.d.ts.map +1 -0
- package/dist/api/middleware/error-handler.js +35 -0
- package/dist/api/middleware/error-handler.js.map +1 -0
- package/dist/api/middleware/validate.d.ts +5 -0
- package/dist/api/middleware/validate.d.ts.map +1 -0
- package/dist/api/middleware/validate.js +23 -0
- package/dist/api/middleware/validate.js.map +1 -0
- package/dist/api/router.d.ts +11 -0
- package/dist/api/router.d.ts.map +1 -0
- package/dist/api/router.js +41 -0
- package/dist/api/router.js.map +1 -0
- package/dist/api/routes/capture.d.ts +3 -0
- package/dist/api/routes/capture.d.ts.map +1 -0
- package/dist/api/routes/capture.js +31 -0
- package/dist/api/routes/capture.js.map +1 -0
- package/dist/api/routes/context.d.ts +4 -0
- package/dist/api/routes/context.d.ts.map +1 -0
- package/dist/api/routes/context.js +25 -0
- package/dist/api/routes/context.js.map +1 -0
- package/dist/api/routes/docs-cache.d.ts +4 -0
- package/dist/api/routes/docs-cache.d.ts.map +1 -0
- package/dist/api/routes/docs-cache.js +79 -0
- package/dist/api/routes/docs-cache.js.map +1 -0
- package/dist/api/routes/edges.d.ts +4 -0
- package/dist/api/routes/edges.d.ts.map +1 -0
- package/dist/api/routes/edges.js +50 -0
- package/dist/api/routes/edges.js.map +1 -0
- package/dist/api/routes/events.d.ts +4 -0
- package/dist/api/routes/events.d.ts.map +1 -0
- package/dist/api/routes/events.js +37 -0
- package/dist/api/routes/events.js.map +1 -0
- package/dist/api/routes/graph.d.ts +4 -0
- package/dist/api/routes/graph.d.ts.map +1 -0
- package/dist/api/routes/graph.js +39 -0
- package/dist/api/routes/graph.js.map +1 -0
- package/dist/api/routes/import.d.ts +4 -0
- package/dist/api/routes/import.d.ts.map +1 -0
- package/dist/api/routes/import.js +92 -0
- package/dist/api/routes/import.js.map +1 -0
- package/dist/api/routes/insights.d.ts +4 -0
- package/dist/api/routes/insights.d.ts.map +1 -0
- package/dist/api/routes/insights.js +40 -0
- package/dist/api/routes/insights.js.map +1 -0
- package/dist/api/routes/integrations.d.ts +4 -0
- package/dist/api/routes/integrations.d.ts.map +1 -0
- package/dist/api/routes/integrations.js +56 -0
- package/dist/api/routes/integrations.js.map +1 -0
- package/dist/api/routes/nodes.d.ts +4 -0
- package/dist/api/routes/nodes.d.ts.map +1 -0
- package/dist/api/routes/nodes.js +123 -0
- package/dist/api/routes/nodes.js.map +1 -0
- package/dist/api/routes/project.d.ts +4 -0
- package/dist/api/routes/project.d.ts.map +1 -0
- package/dist/api/routes/project.js +33 -0
- package/dist/api/routes/project.js.map +1 -0
- package/dist/api/routes/search.d.ts +4 -0
- package/dist/api/routes/search.d.ts.map +1 -0
- package/dist/api/routes/search.js +25 -0
- package/dist/api/routes/search.js.map +1 -0
- package/dist/api/routes/skills.d.ts +3 -0
- package/dist/api/routes/skills.d.ts.map +1 -0
- package/dist/api/routes/skills.js +16 -0
- package/dist/api/routes/skills.js.map +1 -0
- package/dist/api/routes/stats.d.ts +4 -0
- package/dist/api/routes/stats.d.ts.map +1 -0
- package/dist/api/routes/stats.js +14 -0
- package/dist/api/routes/stats.js.map +1 -0
- package/dist/cli/commands/import-cmd.d.ts +3 -0
- package/dist/cli/commands/import-cmd.d.ts.map +1 -0
- package/dist/cli/commands/import-cmd.js +38 -0
- package/dist/cli/commands/import-cmd.js.map +1 -0
- package/dist/cli/commands/init.d.ts +3 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +55 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +3 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +18 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/stats.d.ts +3 -0
- package/dist/cli/commands/stats.d.ts.map +1 -0
- package/dist/cli/commands/stats.js +39 -0
- package/dist/cli/commands/stats.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +17 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/capture/content-extractor.d.ts +21 -0
- package/dist/core/capture/content-extractor.d.ts.map +1 -0
- package/dist/core/capture/content-extractor.js +74 -0
- package/dist/core/capture/content-extractor.js.map +1 -0
- package/dist/core/capture/web-capture.d.ts +20 -0
- package/dist/core/capture/web-capture.d.ts.map +1 -0
- package/dist/core/capture/web-capture.js +51 -0
- package/dist/core/capture/web-capture.js.map +1 -0
- package/dist/core/config/config-loader.d.ts +3 -0
- package/dist/core/config/config-loader.d.ts.map +1 -0
- package/dist/core/config/config-loader.js +43 -0
- package/dist/core/config/config-loader.js.map +1 -0
- package/dist/core/config/config-schema.d.ts +11 -0
- package/dist/core/config/config-schema.d.ts.map +1 -0
- package/dist/core/config/config-schema.js +12 -0
- package/dist/core/config/config-schema.js.map +1 -0
- package/dist/core/docs/docs-cache-store.d.ts +24 -0
- package/dist/core/docs/docs-cache-store.d.ts.map +1 -0
- package/dist/core/docs/docs-cache-store.js +61 -0
- package/dist/core/docs/docs-cache-store.js.map +1 -0
- package/dist/core/docs/docs-syncer.d.ts +13 -0
- package/dist/core/docs/docs-syncer.d.ts.map +1 -0
- package/dist/core/docs/docs-syncer.js +38 -0
- package/dist/core/docs/docs-syncer.js.map +1 -0
- package/dist/core/events/event-bus.d.ts +26 -0
- package/dist/core/events/event-bus.d.ts.map +1 -0
- package/dist/core/events/event-bus.js +47 -0
- package/dist/core/events/event-bus.js.map +1 -0
- package/dist/core/events/event-types.d.ts +57 -0
- package/dist/core/events/event-types.d.ts.map +1 -0
- package/dist/core/events/event-types.js +2 -0
- package/dist/core/events/event-types.js.map +1 -0
- package/dist/core/graph/mermaid-export.d.ts +9 -0
- package/dist/core/graph/mermaid-export.d.ts.map +1 -0
- package/dist/core/graph/mermaid-export.js +80 -0
- package/dist/core/graph/mermaid-export.js.map +1 -0
- package/dist/core/importer/prd-to-graph.d.ts.map +1 -1
- package/dist/core/importer/prd-to-graph.js +7 -0
- package/dist/core/importer/prd-to-graph.js.map +1 -1
- package/dist/core/insights/bottleneck-detector.d.ts +31 -0
- package/dist/core/insights/bottleneck-detector.d.ts.map +1 -0
- package/dist/core/insights/bottleneck-detector.js +69 -0
- package/dist/core/insights/bottleneck-detector.js.map +1 -0
- package/dist/core/insights/metrics-calculator.d.ts +31 -0
- package/dist/core/insights/metrics-calculator.d.ts.map +1 -0
- package/dist/core/insights/metrics-calculator.js +78 -0
- package/dist/core/insights/metrics-calculator.js.map +1 -0
- package/dist/core/insights/skill-recommender.d.ts +21 -0
- package/dist/core/insights/skill-recommender.d.ts.map +1 -0
- package/dist/core/insights/skill-recommender.js +129 -0
- package/dist/core/insights/skill-recommender.js.map +1 -0
- package/dist/core/integrations/serena-reader.d.ts +18 -0
- package/dist/core/integrations/serena-reader.d.ts.map +1 -0
- package/dist/core/integrations/serena-reader.js +50 -0
- package/dist/core/integrations/serena-reader.js.map +1 -0
- package/dist/core/integrations/tool-status.d.ts +18 -0
- package/dist/core/integrations/tool-status.d.ts.map +1 -0
- package/dist/core/integrations/tool-status.js +92 -0
- package/dist/core/integrations/tool-status.js.map +1 -0
- package/dist/core/parser/file-reader.d.ts +13 -0
- package/dist/core/parser/file-reader.d.ts.map +1 -0
- package/dist/core/parser/file-reader.js +52 -0
- package/dist/core/parser/file-reader.js.map +1 -0
- package/dist/core/parser/read-html.d.ts +7 -0
- package/dist/core/parser/read-html.d.ts.map +1 -0
- package/dist/core/parser/read-html.js +51 -0
- package/dist/core/parser/read-html.js.map +1 -0
- package/dist/core/parser/read-pdf.d.ts +10 -0
- package/dist/core/parser/read-pdf.d.ts.map +1 -0
- package/dist/core/parser/read-pdf.js +16 -0
- package/dist/core/parser/read-pdf.js.map +1 -0
- package/dist/core/planner/next-task.d.ts.map +1 -1
- package/dist/core/planner/next-task.js +4 -1
- package/dist/core/planner/next-task.js.map +1 -1
- package/dist/core/search/fts-search.d.ts.map +1 -1
- package/dist/core/search/fts-search.js +6 -1
- package/dist/core/search/fts-search.js.map +1 -1
- package/dist/core/store/migrations.d.ts.map +1 -1
- package/dist/core/store/migrations.js +38 -0
- package/dist/core/store/migrations.js.map +1 -1
- package/dist/core/store/sqlite-store.d.ts +7 -0
- package/dist/core/store/sqlite-store.d.ts.map +1 -1
- package/dist/core/store/sqlite-store.js +28 -3
- package/dist/core/store/sqlite-store.js.map +1 -1
- package/dist/core/utils/logger.d.ts +1 -0
- package/dist/core/utils/logger.d.ts.map +1 -1
- package/dist/core/utils/logger.js +5 -0
- package/dist/core/utils/logger.js.map +1 -1
- package/dist/mcp/init-project.d.ts.map +1 -1
- package/dist/mcp/init-project.js +12 -16
- package/dist/mcp/init-project.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +17 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/stdio.js +0 -0
- package/dist/mcp/tools/export-mermaid.d.ts +4 -0
- package/dist/mcp/tools/export-mermaid.d.ts.map +1 -0
- package/dist/mcp/tools/export-mermaid.js +27 -0
- package/dist/mcp/tools/export-mermaid.js.map +1 -0
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js +2 -0
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/web/dashboard/dist/assets/code-graph-tab-jvBo8Q9t.js +1 -0
- package/dist/web/dashboard/dist/assets/constants-CLJl-f3f.js +1 -0
- package/dist/web/dashboard/dist/assets/graph-tab-BoKfDlvO.js +1 -0
- package/dist/web/dashboard/dist/assets/graph-utils-BZV40eAE.css +1 -0
- package/dist/web/dashboard/dist/assets/graph-utils-uGOH4eMw.js +23 -0
- package/dist/web/dashboard/dist/assets/index-DM_LGeRr.css +1 -0
- package/dist/web/dashboard/dist/assets/index-DrHbgcp5.js +53 -0
- package/dist/web/dashboard/dist/assets/insights-tab-D7sHV2xV.js +1 -0
- package/dist/web/dashboard/dist/assets/prd-backlog-tab-C_Uq1Qte.js +1 -0
- package/dist/web/dashboard/dist/index.html +13 -0
- package/dist/web/public/css/styles.css +646 -0
- package/dist/web/public/index.html +209 -0
- package/dist/web/public/js/api-client.js +85 -0
- package/dist/web/public/js/app.js +112 -0
- package/dist/web/public/js/capture-form.js +196 -0
- package/dist/web/public/js/filters.js +94 -0
- package/dist/web/public/js/force-graph-renderer.js +498 -0
- package/dist/web/public/js/graph-renderer.js +62 -0
- package/dist/web/public/js/import-form.js +105 -0
- package/dist/web/public/js/node-detail.js +106 -0
- package/dist/web/public/js/tabs/code-graph-tab.js +66 -0
- package/dist/web/public/js/tabs/graph-tab.js +238 -0
- package/dist/web/public/js/tabs/insights-tab.js +236 -0
- package/dist/web/public/js/tabs/knowledge-tab.js +201 -0
- package/dist/web/public/js/tabs/prd-backlog-tab.js +167 -0
- package/dist/web/public/vendor/force-graph.min.js +5 -0
- package/dist/web/public/vendor/mermaid.min.js +2843 -0
- package/package.json +22 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Copilot Ecosystem Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# @diegonogueiradev_/mcp-graph
|
|
2
|
+
|
|
3
|
+
A local-first CLI tool (TypeScript) that converts PRD text files into persistent execution graphs (SQLite), enabling structured, token-efficient agentic workflows.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **PRD to Graph** — Parse PRD text files into structured task graphs with nodes and edges
|
|
8
|
+
- **Local-first** — SQLite persistence, zero external dependencies, no Docker
|
|
9
|
+
- **Smart Routing** — `next` command suggests the best task based on priority, dependencies, and blockers
|
|
10
|
+
- **Context Compression** — Reduce LLM context payload by 70-85% via structural summarization
|
|
11
|
+
- **MCP Protocol** — 26 tools accessible via HTTP or Stdio transport
|
|
12
|
+
- **Web Dashboard** — Real-time browser UI with Mermaid diagrams, backlog management, and insights
|
|
13
|
+
- **REST API** — Full CRUD + search + import + insights via Express
|
|
14
|
+
- **Cross-platform** — Windows, macOS, and Linux compatible
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
### As MCP Server (recommended)
|
|
19
|
+
|
|
20
|
+
Add to your Claude Code `.mcp.json` or Cursor MCP config:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"mcpServers": {
|
|
25
|
+
"mcp-graph": {
|
|
26
|
+
"command": "npx",
|
|
27
|
+
"args": ["@diegonogueiradev_/mcp-graph"]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then use the tools via your MCP client:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
init → import_prd → list → next → update_status → stats
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### From source
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git clone <repo-url>
|
|
43
|
+
cd mcp-graph-workflow
|
|
44
|
+
npm install
|
|
45
|
+
npm run build
|
|
46
|
+
npm run dev # Start HTTP server + dashboard
|
|
47
|
+
npm run dev:stdio # Start MCP Stdio server
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### CLI
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
mcp-graph init # Initialize project
|
|
54
|
+
mcp-graph import docs/my-prd.md # Import PRD file
|
|
55
|
+
mcp-graph stats # Show graph statistics
|
|
56
|
+
mcp-graph stats --json # JSON output
|
|
57
|
+
mcp-graph serve --port 3000 # Start dashboard
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Architecture
|
|
61
|
+
|
|
62
|
+
```mermaid
|
|
63
|
+
graph TD
|
|
64
|
+
CLI[CLI — Commander.js] --> Core
|
|
65
|
+
MCP[MCP Server — HTTP/Stdio] --> Core
|
|
66
|
+
API[REST API — Express] --> Core
|
|
67
|
+
Web[Web Dashboard — Vanilla JS] --> API
|
|
68
|
+
|
|
69
|
+
Core --> Store[SQLite Store — WAL + FTS5]
|
|
70
|
+
Core --> Parser[Parser — classify, extract, segment]
|
|
71
|
+
Core --> Planner[Planner — next-task selection]
|
|
72
|
+
Core --> Context[Context Builder — 70-85% reduction]
|
|
73
|
+
Core --> Insights[Insights — bottlenecks, metrics]
|
|
74
|
+
Core --> Search[Search — FTS5 + TF-IDF reranking]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
src/
|
|
79
|
+
cli/ # Commander.js commands (thin orchestration)
|
|
80
|
+
core/
|
|
81
|
+
graph/ # SQLite persistence + queries + Mermaid export
|
|
82
|
+
importer/ # PRD import pipeline
|
|
83
|
+
parser/ # classify, extract, normalize, segment
|
|
84
|
+
planner/ # next-task selection logic
|
|
85
|
+
context/ # compact context builder
|
|
86
|
+
insights/ # bottleneck detection, metrics
|
|
87
|
+
search/ # FTS5 + TF-IDF search
|
|
88
|
+
events/ # SSE event bus
|
|
89
|
+
store/ # SQLite store, migrations
|
|
90
|
+
config/ # Configuration loader
|
|
91
|
+
docs/ # Docs cache syncer
|
|
92
|
+
utils/ # errors, fs, id, logger, time
|
|
93
|
+
api/ # Express REST API routes + middleware
|
|
94
|
+
mcp/ # MCP server (HTTP + Stdio) + tool wrappers
|
|
95
|
+
schemas/ # Zod v4 schemas
|
|
96
|
+
web/public/ # Dashboard (HTML, CSS, vanilla JS)
|
|
97
|
+
tests/ # Vitest unit/integration + Playwright E2E
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## MCP Tools
|
|
101
|
+
|
|
102
|
+
| Tool | Description |
|
|
103
|
+
|---|---|
|
|
104
|
+
| `init` | Initialize project and SQLite database |
|
|
105
|
+
| `import_prd` | Parse PRD file and generate task graph |
|
|
106
|
+
| `list` | List nodes filtered by type/status/sprint |
|
|
107
|
+
| `show` | Show node details with edges and children |
|
|
108
|
+
| `next` | Suggest next task based on priority and dependencies |
|
|
109
|
+
| `update_status` | Update node status (backlog/ready/in_progress/blocked/done) |
|
|
110
|
+
| `update_node` | Edit node fields (title, description, priority, tags, etc.) |
|
|
111
|
+
| `stats` | Show graph statistics and context reduction metrics |
|
|
112
|
+
| `context` | Build compact context payload for a specific task |
|
|
113
|
+
| `search` | Full-text search across nodes |
|
|
114
|
+
| `rag_context` | RAG-based contextual search via FTS5+TF-IDF |
|
|
115
|
+
| `add_node` | Add a new node to the graph |
|
|
116
|
+
| `add_edge` | Add an edge between nodes |
|
|
117
|
+
| `delete_node` | Delete node with cascade edge cleanup |
|
|
118
|
+
| `delete_edge` | Delete an edge |
|
|
119
|
+
| `list_edges` | List edges filtered by node or type |
|
|
120
|
+
| `move_node` | Move node to a different parent |
|
|
121
|
+
| `clone_node` | Clone a node (optionally with children) |
|
|
122
|
+
| `bulk_update_status` | Update status of multiple nodes at once |
|
|
123
|
+
| `decompose` | Detect large tasks and suggest breakdown |
|
|
124
|
+
| `velocity` | Calculate team velocity and sprint metrics |
|
|
125
|
+
| `dependencies` | Analyze dependency chains, critical path, blockers |
|
|
126
|
+
| `export_graph` | Export the complete graph as JSON |
|
|
127
|
+
| `export_mermaid` | Export the graph as a Mermaid diagram (flowchart or mindmap) |
|
|
128
|
+
| `create_snapshot` | Create a named snapshot of the current graph state |
|
|
129
|
+
| `restore_snapshot` | Restore graph from a snapshot |
|
|
130
|
+
| `list_snapshots` | List available snapshots |
|
|
131
|
+
|
|
132
|
+
## REST API
|
|
133
|
+
|
|
134
|
+
All endpoints under `/api/v1/`:
|
|
135
|
+
|
|
136
|
+
| Method | Endpoint | Description |
|
|
137
|
+
|--------|----------|-------------|
|
|
138
|
+
| POST | `/project/init` | Initialize project |
|
|
139
|
+
| GET | `/nodes` | List all nodes |
|
|
140
|
+
| POST | `/nodes` | Create node |
|
|
141
|
+
| GET | `/edges` | List edges |
|
|
142
|
+
| POST | `/edges` | Create edge |
|
|
143
|
+
| GET | `/stats` | Graph statistics |
|
|
144
|
+
| GET | `/search?q=term` | Full-text search |
|
|
145
|
+
| POST | `/import` | Import PRD file (multipart) |
|
|
146
|
+
| GET | `/graph/document` | Full graph document |
|
|
147
|
+
| GET | `/graph/mermaid` | Mermaid diagram |
|
|
148
|
+
| GET | `/insights/bottlenecks` | Bottleneck report |
|
|
149
|
+
| GET | `/context/preview?nodeId=x` | Compact context for node |
|
|
150
|
+
| GET | `/docs` | Docs cache entries |
|
|
151
|
+
| GET | `/events` | SSE real-time events |
|
|
152
|
+
| GET | `/integrations/status` | Integration status (Serena, GitNexus) |
|
|
153
|
+
| GET | `/skills` | Available skills |
|
|
154
|
+
|
|
155
|
+
## Web Dashboard
|
|
156
|
+
|
|
157
|
+
The dashboard runs at `http://localhost:3000` via `mcp-graph serve` and provides 5 tabs:
|
|
158
|
+
|
|
159
|
+
1. **Graph** — Interactive Mermaid diagram with filters (status, type, direction, format), node table with search/sort, and detail panel
|
|
160
|
+
2. **PRD & Backlog** — PRD source view, backlog list, next task badge, progress bars per epic
|
|
161
|
+
3. **Code Graph** — Integration with GitNexus/Serena code analysis
|
|
162
|
+
4. **Knowledge** — Docs cache and context preview
|
|
163
|
+
5. **Insights** — Bottleneck detection, metrics, and reports
|
|
164
|
+
|
|
165
|
+
Real-time updates via Server-Sent Events (SSE). Dark/light theme toggle.
|
|
166
|
+
|
|
167
|
+
## Testing
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
npm test # Unit + integration tests (Vitest)
|
|
171
|
+
npm run test:watch # Watch mode
|
|
172
|
+
npm run test:e2e # Browser E2E tests (Playwright)
|
|
173
|
+
npm run test:coverage # Coverage report (V8)
|
|
174
|
+
npm run test:bench # Benchmark tests
|
|
175
|
+
npm run test:all # All tests (unit + E2E)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
See [docs/TEST-GUIDE.md](docs/TEST-GUIDE.md) for the full testing guide.
|
|
179
|
+
|
|
180
|
+
## How It Works
|
|
181
|
+
|
|
182
|
+
1. **Parse** — Read PRD text, normalize, segment by headings, classify blocks heuristically
|
|
183
|
+
2. **Transform** — Convert blocks to nodes (epic, task, subtask, requirement, constraint, risk) with edges (depends_on, parent_of, blocks, related_to)
|
|
184
|
+
3. **Persist** — Store graph in local SQLite with WAL mode, FTS5 indexes, and snapshots
|
|
185
|
+
4. **Execute** — Route tasks by priority, dependency resolution, and blocker analysis
|
|
186
|
+
5. **Compress** — Generate minimal context payloads for LLM consumption (70-85% token reduction)
|
|
187
|
+
|
|
188
|
+
## Node Types
|
|
189
|
+
|
|
190
|
+
`epic` | `task` | `subtask` | `requirement` | `constraint` | `milestone` | `acceptance_criteria` | `risk` | `decision`
|
|
191
|
+
|
|
192
|
+
## Status Flow
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
backlog → ready → in_progress → done
|
|
196
|
+
→ blocked
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## XP Anti-Vibe-Coding Workflow
|
|
200
|
+
|
|
201
|
+
The project follows an anti-vibe-coding methodology based on Extreme Programming (XP). Discipline over intuition. Every line of code has a tested purpose, and the execution graph ensures no progress is lost between sessions.
|
|
202
|
+
|
|
203
|
+
### Why a Graph?
|
|
204
|
+
|
|
205
|
+
| Problem | List/Kanban | Graph (mcp-graph) |
|
|
206
|
+
|---------|------------|-------------------|
|
|
207
|
+
| Task dependencies | Invisible or manual | Explicit edges: `blocks`, `depends_on`, `parent_of` |
|
|
208
|
+
| Execution order | Decided by dev each time | `next` auto-resolves based on priority + dependencies |
|
|
209
|
+
| AI context | Dev explains everything | `context` generates compact payload (70-85% fewer tokens) |
|
|
210
|
+
| Session continuity | Lost — "where was I?" | `stats` + `list` show exact state |
|
|
211
|
+
| Hierarchical decomposition | Flat | Tree: PRD → Feature → Story → Task → Subtask |
|
|
212
|
+
|
|
213
|
+
### Key Skills
|
|
214
|
+
|
|
215
|
+
| Skill | Purpose |
|
|
216
|
+
|-------|---------|
|
|
217
|
+
| `/xp-bootstrap` | Sequential workflow: Isolation → Foundation → TDD → Implementation → Optimization → Interface → Deploy |
|
|
218
|
+
| `/project-scaffold` | Auto-setup: `.mcp.json` + `CLAUDE.md` template + `.claude/rules/` + mcp-graph init |
|
|
219
|
+
| `/dev-flow-orchestrator` | Continuous XP cycle: ANALYZE → DESIGN → PLAN → IMPLEMENT → VALIDATE → REVIEW → HANDOFF → LISTENING |
|
|
220
|
+
| `/track-with-mcp-graph` | Keep graph in sync with real work state |
|
|
221
|
+
|
|
222
|
+
## Contributing
|
|
223
|
+
|
|
224
|
+
1. Fork the repository
|
|
225
|
+
2. Create a feature branch: `git checkout -b feature/my-feature`
|
|
226
|
+
3. Follow TDD: write failing test first, then implement
|
|
227
|
+
4. Ensure all checks pass: `npm run build && npm test && npm run test:e2e`
|
|
228
|
+
5. Submit a PR with clear description
|
|
229
|
+
|
|
230
|
+
## Documentation
|
|
231
|
+
|
|
232
|
+
| Document | Description |
|
|
233
|
+
|---|---|
|
|
234
|
+
| [CLAUDE.md](CLAUDE.md) | AI agent instructions, conventions, and rules |
|
|
235
|
+
| [docs/ARCHITECTURE-GUIDE.md](docs/ARCHITECTURE-GUIDE.md) | Complete architecture guide |
|
|
236
|
+
| [docs/TEST-GUIDE.md](docs/TEST-GUIDE.md) | Testing guide and best practices |
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../../src/api/middleware/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AA4B/D,wBAAgB,YAAY,CAC1B,GAAG,EAAE,KAAK,EACV,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,YAAY,GAClB,IAAI,CAeN"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import { McpGraphError, GraphNotInitializedError, NodeNotFoundError, ValidationError, SnapshotNotFoundError, FileNotFoundError, } from "../../core/utils/errors.js";
|
|
3
|
+
import { logger } from "../../core/utils/logger.js";
|
|
4
|
+
function mapErrorToStatus(err) {
|
|
5
|
+
if (err instanceof GraphNotInitializedError)
|
|
6
|
+
return 409;
|
|
7
|
+
if (err instanceof NodeNotFoundError)
|
|
8
|
+
return 404;
|
|
9
|
+
if (err instanceof FileNotFoundError)
|
|
10
|
+
return 404;
|
|
11
|
+
if (err instanceof SnapshotNotFoundError)
|
|
12
|
+
return 404;
|
|
13
|
+
if (err instanceof ValidationError)
|
|
14
|
+
return 400;
|
|
15
|
+
if (err instanceof z.ZodError)
|
|
16
|
+
return 400;
|
|
17
|
+
if (err instanceof McpGraphError)
|
|
18
|
+
return 400;
|
|
19
|
+
return 500;
|
|
20
|
+
}
|
|
21
|
+
export function errorHandler(err, _req, res, _next) {
|
|
22
|
+
const status = mapErrorToStatus(err);
|
|
23
|
+
const body = { error: err.message };
|
|
24
|
+
if (err instanceof ValidationError) {
|
|
25
|
+
body.details = err.issues;
|
|
26
|
+
}
|
|
27
|
+
else if (err instanceof z.ZodError) {
|
|
28
|
+
body.details = err.issues;
|
|
29
|
+
}
|
|
30
|
+
if (status >= 500) {
|
|
31
|
+
logger.error("Unhandled API error", { error: err.message, stack: err.stack });
|
|
32
|
+
}
|
|
33
|
+
res.status(status).json(body);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=error-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../../src/api/middleware/error-handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAC3B,OAAO,EACL,aAAa,EACb,wBAAwB,EACxB,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAOpD,SAAS,gBAAgB,CAAC,GAAU;IAClC,IAAI,GAAG,YAAY,wBAAwB;QAAE,OAAO,GAAG,CAAC;IACxD,IAAI,GAAG,YAAY,iBAAiB;QAAE,OAAO,GAAG,CAAC;IACjD,IAAI,GAAG,YAAY,iBAAiB;QAAE,OAAO,GAAG,CAAC;IACjD,IAAI,GAAG,YAAY,qBAAqB;QAAE,OAAO,GAAG,CAAC;IACrD,IAAI,GAAG,YAAY,eAAe;QAAE,OAAO,GAAG,CAAC;IAC/C,IAAI,GAAG,YAAY,CAAC,CAAC,QAAQ;QAAE,OAAO,GAAG,CAAC;IAC1C,IAAI,GAAG,YAAY,aAAa;QAAE,OAAO,GAAG,CAAC;IAC7C,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,GAAU,EACV,IAAa,EACb,GAAa,EACb,KAAmB;IAEnB,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,IAAI,GAAsB,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;IAEvD,IAAI,GAAG,YAAY,eAAe,EAAE,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC;IAC5B,CAAC;SAAM,IAAI,GAAG,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;QACrC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;QAClB,MAAM,CAAC,KAAK,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IAChF,CAAC;IAED,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from "express";
|
|
2
|
+
import type { ZodType } from "zod/v4";
|
|
3
|
+
export declare function validateBody(schema: ZodType): (req: Request, res: Response, next: NextFunction) => void;
|
|
4
|
+
export declare function validateQuery(schema: ZodType): (req: Request, res: Response, next: NextFunction) => void;
|
|
5
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/api/middleware/validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAItC,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAUvG;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CASxG"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ValidationError } from "../../core/utils/errors.js";
|
|
2
|
+
export function validateBody(schema) {
|
|
3
|
+
return (req, _res, next) => {
|
|
4
|
+
const result = schema.safeParse(req.body);
|
|
5
|
+
if (!result.success) {
|
|
6
|
+
next(new ValidationError("Invalid request body", result.error.issues));
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
req.body = result.data;
|
|
10
|
+
next();
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function validateQuery(schema) {
|
|
14
|
+
return (req, _res, next) => {
|
|
15
|
+
const result = schema.safeParse(req.query);
|
|
16
|
+
if (!result.success) {
|
|
17
|
+
next(new ValidationError("Invalid query parameters", result.error.issues));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
next();
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/api/middleware/validate.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,MAAM,UAAU,YAAY,CAAC,MAAe;IAC1C,OAAO,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB,EAAQ,EAAE;QAChE,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,CAAC,IAAI,eAAe,CAAC,sBAAsB,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;YACvE,OAAO;QACT,CAAC;QACD,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACvB,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAe;IAC3C,OAAO,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB,EAAQ,EAAE;QAChE,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,CAAC,IAAI,eAAe,CAAC,0BAA0B,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QACD,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import type { SqliteStore } from "../core/store/sqlite-store.js";
|
|
3
|
+
import type { GraphEventBus } from "../core/events/event-bus.js";
|
|
4
|
+
export interface ApiRouterOptions {
|
|
5
|
+
store: SqliteStore;
|
|
6
|
+
basePath?: string;
|
|
7
|
+
eventBus?: GraphEventBus;
|
|
8
|
+
}
|
|
9
|
+
export declare function createApiRouter(options: ApiRouterOptions): Router;
|
|
10
|
+
export declare function createApiRouter(store: SqliteStore): Router;
|
|
11
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/api/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAiBjE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAAC;AACnE,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { createProjectRouter } from "./routes/project.js";
|
|
3
|
+
import { createNodesRouter } from "./routes/nodes.js";
|
|
4
|
+
import { createEdgesRouter } from "./routes/edges.js";
|
|
5
|
+
import { createStatsRouter } from "./routes/stats.js";
|
|
6
|
+
import { createSearchRouter } from "./routes/search.js";
|
|
7
|
+
import { createGraphRouter } from "./routes/graph.js";
|
|
8
|
+
import { createImportRouter } from "./routes/import.js";
|
|
9
|
+
import { createIntegrationsRouter } from "./routes/integrations.js";
|
|
10
|
+
import { createInsightsRouter } from "./routes/insights.js";
|
|
11
|
+
import { createSkillsRouter } from "./routes/skills.js";
|
|
12
|
+
import { createCaptureRouter } from "./routes/capture.js";
|
|
13
|
+
import { createDocsCacheRouter } from "./routes/docs-cache.js";
|
|
14
|
+
import { createContextRouter } from "./routes/context.js";
|
|
15
|
+
import { createEventsRouter } from "./routes/events.js";
|
|
16
|
+
import { errorHandler } from "./middleware/error-handler.js";
|
|
17
|
+
export function createApiRouter(storeOrOptions) {
|
|
18
|
+
const store = "store" in storeOrOptions ? storeOrOptions.store : storeOrOptions;
|
|
19
|
+
const basePath = "basePath" in storeOrOptions ? (storeOrOptions.basePath ?? process.cwd()) : process.cwd();
|
|
20
|
+
const eventBus = "eventBus" in storeOrOptions ? storeOrOptions.eventBus : undefined;
|
|
21
|
+
const router = Router();
|
|
22
|
+
router.use("/project", createProjectRouter(store));
|
|
23
|
+
router.use("/nodes", createNodesRouter(store));
|
|
24
|
+
router.use("/edges", createEdgesRouter(store));
|
|
25
|
+
router.use("/stats", createStatsRouter(store));
|
|
26
|
+
router.use("/search", createSearchRouter(store));
|
|
27
|
+
router.use("/graph", createGraphRouter(store));
|
|
28
|
+
router.use("/import", createImportRouter(store));
|
|
29
|
+
router.use("/integrations", createIntegrationsRouter(store, basePath));
|
|
30
|
+
router.use("/insights", createInsightsRouter(store, basePath));
|
|
31
|
+
router.use("/skills", createSkillsRouter(basePath));
|
|
32
|
+
router.use("/capture", createCaptureRouter());
|
|
33
|
+
router.use("/docs", createDocsCacheRouter(store));
|
|
34
|
+
router.use("/context", createContextRouter(store));
|
|
35
|
+
if (eventBus) {
|
|
36
|
+
router.use("/events", createEventsRouter(eventBus));
|
|
37
|
+
}
|
|
38
|
+
router.use(errorHandler);
|
|
39
|
+
return router;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/api/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../../src/api/routes/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAajC,wBAAgB,mBAAmB,IAAI,MAAM,CAsB5C"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { z } from "zod/v4";
|
|
3
|
+
import { validateBody } from "../middleware/validate.js";
|
|
4
|
+
import { captureWebPage } from "../../core/capture/web-capture.js";
|
|
5
|
+
import { logger } from "../../core/utils/logger.js";
|
|
6
|
+
const CaptureRequestSchema = z.object({
|
|
7
|
+
url: z.url("url must be a valid URL"),
|
|
8
|
+
selector: z.string().optional(),
|
|
9
|
+
timeout: z.number().int().positive().max(60_000).optional(),
|
|
10
|
+
waitForSelector: z.string().optional(),
|
|
11
|
+
});
|
|
12
|
+
export function createCaptureRouter() {
|
|
13
|
+
const router = Router();
|
|
14
|
+
/**
|
|
15
|
+
* POST /capture
|
|
16
|
+
* Capture a web page and extract structured content.
|
|
17
|
+
*/
|
|
18
|
+
router.post("/", validateBody(CaptureRequestSchema), async (req, res, next) => {
|
|
19
|
+
try {
|
|
20
|
+
const { url, selector, timeout, waitForSelector } = req.body;
|
|
21
|
+
logger.info("Capture request received", { url, selector });
|
|
22
|
+
const result = await captureWebPage(url, { selector, timeout, waitForSelector });
|
|
23
|
+
res.status(200).json(result);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
next(err);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return router;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../../src/api/routes/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAEpD,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,yBAAyB,CAAC;IACrC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;IAC3D,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACvC,CAAC,CAAC;AAEH,MAAM,UAAU,mBAAmB;IACjC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB;;;OAGG;IACH,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,oBAAoB,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC5E,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,IAA4C,CAAC;YAErG,MAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;YAE3D,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC;YAEjF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/api/routes/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAGpE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAwB9D"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { buildTaskContext } from "../../core/context/compact-context.js";
|
|
3
|
+
export function createContextRouter(store) {
|
|
4
|
+
const router = Router();
|
|
5
|
+
router.get("/preview", (req, res, next) => {
|
|
6
|
+
try {
|
|
7
|
+
const nodeId = req.query.nodeId;
|
|
8
|
+
if (!nodeId) {
|
|
9
|
+
res.status(400).json({ error: "Missing 'nodeId' query parameter" });
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const context = buildTaskContext(store, nodeId);
|
|
13
|
+
if (!context) {
|
|
14
|
+
res.status(404).json({ error: `Node not found: ${nodeId}` });
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
res.json(context);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
next(err);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return router;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/api/routes/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAEzE,MAAM,UAAU,mBAAmB,CAAC,KAAkB;IACpD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAA4B,CAAC;YACtD,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC,CAAC;gBACpE,OAAO;YACT,CAAC;YAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAChD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,MAAM,EAAE,EAAE,CAAC,CAAC;gBAC7D,OAAO;YACT,CAAC;YAED,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs-cache.d.ts","sourceRoot":"","sources":["../../../src/api/routes/docs-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAcpE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAyEhE"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { DocsCacheStore } from "../../core/docs/docs-cache-store.js";
|
|
3
|
+
import { DocsSyncer } from "../../core/docs/docs-syncer.js";
|
|
4
|
+
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
|
5
|
+
const SEVEN_DAYS_MS = 7 * ONE_DAY_MS;
|
|
6
|
+
function getFreshness(fetchedAt) {
|
|
7
|
+
const age = Date.now() - new Date(fetchedAt).getTime();
|
|
8
|
+
if (age < ONE_DAY_MS)
|
|
9
|
+
return "fresh";
|
|
10
|
+
if (age < SEVEN_DAYS_MS)
|
|
11
|
+
return "aging";
|
|
12
|
+
return "stale";
|
|
13
|
+
}
|
|
14
|
+
export function createDocsCacheRouter(store) {
|
|
15
|
+
const router = Router();
|
|
16
|
+
const cacheStore = new DocsCacheStore(store.getDb());
|
|
17
|
+
router.get("/", (req, res, next) => {
|
|
18
|
+
try {
|
|
19
|
+
const lib = req.query.lib;
|
|
20
|
+
if (lib) {
|
|
21
|
+
const results = cacheStore.searchDocs(lib);
|
|
22
|
+
res.json(results.map((d) => ({
|
|
23
|
+
...d,
|
|
24
|
+
freshness: getFreshness(d.fetchedAt),
|
|
25
|
+
})));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const docs = cacheStore.listCached();
|
|
29
|
+
res.json(docs.map((d) => ({
|
|
30
|
+
...d,
|
|
31
|
+
freshness: getFreshness(d.fetchedAt),
|
|
32
|
+
})));
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
next(err);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
router.get("/:libId", (req, res, next) => {
|
|
39
|
+
try {
|
|
40
|
+
const doc = cacheStore.getDoc(req.params.libId);
|
|
41
|
+
if (!doc) {
|
|
42
|
+
res.status(404).json({ error: `Doc not found: ${req.params.libId}` });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
res.json({ ...doc, freshness: getFreshness(doc.fetchedAt) });
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
next(err);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
router.post("/sync", async (req, res, next) => {
|
|
52
|
+
try {
|
|
53
|
+
const { lib } = req.body;
|
|
54
|
+
if (!lib) {
|
|
55
|
+
res.status(400).json({ error: "Missing 'lib' in request body" });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Create a no-op fetcher that returns a placeholder — real Context7 integration
|
|
59
|
+
// requires MCP client connection which is not available in the REST API context.
|
|
60
|
+
// The sync endpoint stores the lib name for future MCP-based sync.
|
|
61
|
+
const placeholderFetcher = {
|
|
62
|
+
async resolveLibraryId(name) {
|
|
63
|
+
return `context7:${name}`;
|
|
64
|
+
},
|
|
65
|
+
async queryDocs() {
|
|
66
|
+
return `Documentation placeholder for ${lib}. Use Context7 MCP tools for full sync.`;
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const syncer = new DocsSyncer(cacheStore, placeholderFetcher);
|
|
70
|
+
const doc = await syncer.syncLib(lib);
|
|
71
|
+
res.status(201).json({ ...doc, freshness: getFreshness(doc.fetchedAt) });
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
next(err);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return router;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=docs-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs-cache.js","sourceRoot":"","sources":["../../../src/api/routes/docs-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edges.d.ts","sourceRoot":"","sources":["../../../src/api/routes/edges.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAUpE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CA4C5D"}
|