twining-mcp 1.4.0 → 1.4.2

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 (53) hide show
  1. package/README.md +119 -106
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +2 -1
  4. package/dist/config.js.map +1 -1
  5. package/dist/dashboard/public/app.js +140 -9
  6. package/dist/dashboard/public/index.html +19 -1
  7. package/dist/dashboard/public/style.css +123 -3
  8. package/dist/embeddings/search.d.ts.map +1 -1
  9. package/dist/embeddings/search.js +5 -2
  10. package/dist/embeddings/search.js.map +1 -1
  11. package/dist/engine/archiver.d.ts.map +1 -1
  12. package/dist/engine/archiver.js +15 -11
  13. package/dist/engine/archiver.js.map +1 -1
  14. package/dist/engine/blackboard.d.ts +6 -1
  15. package/dist/engine/blackboard.d.ts.map +1 -1
  16. package/dist/engine/blackboard.js +16 -0
  17. package/dist/engine/blackboard.js.map +1 -1
  18. package/dist/engine/context-assembler.d.ts +6 -0
  19. package/dist/engine/context-assembler.d.ts.map +1 -1
  20. package/dist/engine/context-assembler.js +69 -14
  21. package/dist/engine/context-assembler.js.map +1 -1
  22. package/dist/engine/verify.d.ts +8 -2
  23. package/dist/engine/verify.d.ts.map +1 -1
  24. package/dist/engine/verify.js +27 -9
  25. package/dist/engine/verify.js.map +1 -1
  26. package/dist/server.d.ts.map +1 -1
  27. package/dist/server.js +3 -1
  28. package/dist/server.js.map +1 -1
  29. package/dist/storage/decision-store.d.ts.map +1 -1
  30. package/dist/storage/decision-store.js +8 -18
  31. package/dist/storage/decision-store.js.map +1 -1
  32. package/dist/storage/handoff-store.d.ts +1 -1
  33. package/dist/storage/handoff-store.d.ts.map +1 -1
  34. package/dist/storage/handoff-store.js +45 -17
  35. package/dist/storage/handoff-store.js.map +1 -1
  36. package/dist/tools/blackboard-tools.d.ts.map +1 -1
  37. package/dist/tools/blackboard-tools.js +4 -1
  38. package/dist/tools/blackboard-tools.js.map +1 -1
  39. package/dist/tools/context-tools.d.ts.map +1 -1
  40. package/dist/tools/context-tools.js +3 -0
  41. package/dist/tools/context-tools.js.map +1 -1
  42. package/dist/tools/graph-tools.d.ts.map +1 -1
  43. package/dist/tools/graph-tools.js +6 -4
  44. package/dist/tools/graph-tools.js.map +1 -1
  45. package/dist/tools/lifecycle-tools.d.ts.map +1 -1
  46. package/dist/tools/lifecycle-tools.js +3 -0
  47. package/dist/tools/lifecycle-tools.js.map +1 -1
  48. package/dist/utils/types.d.ts +1 -0
  49. package/dist/utils/types.d.ts.map +1 -1
  50. package/package.json +1 -1
  51. package/src/dashboard/public/app.js +140 -9
  52. package/src/dashboard/public/index.html +19 -1
  53. package/src/dashboard/public/style.css +123 -3
package/README.md CHANGED
@@ -3,8 +3,8 @@
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- <strong>Separate threads, stronger together.</strong><br>
7
- Agent coordination for Claude Code and other MCP clients.
6
+ <strong>Your AI agents forget everything. Twining remembers.</strong><br>
7
+ Persistent project memory for Claude Code and other MCP clients.
8
8
  </p>
9
9
 
10
10
  <p align="center">
@@ -14,172 +14,185 @@
14
14
 
15
15
  ---
16
16
 
17
- Twining provides a shared blackboard, decision tracking with rationale, selective context assembly, a lightweight knowledge graph, agent coordination with capability-based delegation, and local semantic search — all backed by plain JSONL/JSON files that are git-trackable and human-inspectable. Includes an embedded web dashboard for browsing and visualizing all state.
17
+ ## The Problem
18
18
 
19
- ## Features
19
+ You spend two hours with Claude Code making architectural decisions. You choose PostgreSQL over MongoDB. You settle on JWT for auth. You flag a race condition in the payment module. Then the session ends.
20
20
 
21
- - **Shared Blackboard** Append-only message stream for findings, needs, warnings, and questions across agents
22
- - **Decision Tracking** — Record decisions with rationale, alternatives, confidence, dependency chains, and git commit linking
23
- - **Context Assembly** — Build tailored context packages for a task within a token budget, with handoff results and agent suggestions
24
- - **Knowledge Graph** — Lightweight entity-relation graph with traversal, search, and full state export
25
- - **Semantic Search** — Local embeddings via all-MiniLM-L6-v2 with automatic keyword fallback
26
- - **Agent Coordination** — Registry with capability-based discovery, delegation matching, structured handoffs, and liveness tracking
27
- - **Web Dashboard** — Embedded HTTP server with stats, search, decision timeline, interactive graph visualization, and agent coordination views
28
- - **Archiving** — Move stale entries to archive while preserving decision records
21
+ Tomorrow you start a new session. Claude has no idea what happened. The decisions are gone. The warnings are gone. The rationale is gone. You re-explain everything — or worse, Claude silently contradicts yesterday's choices.
29
22
 
30
- ## Quick Start
23
+ This gets worse with multiple agents. Agent A decides on REST. Agent B picks gRPC for the same service. Neither knows the other exists. You find out when the code doesn't compile.
31
24
 
32
- ### Add to Claude Code
25
+ **Context windows are ephemeral. Your project's decisions shouldn't be.**
33
26
 
34
- ```bash
27
+ ## How Twining Fixes It
28
+
29
+ Twining is an MCP server that gives your AI agents persistent project memory. Decisions survive context resets. New sessions start informed. Multi-agent work stays coordinated.
30
+
31
+ ```
32
+ # Install in 10 seconds
35
33
  claude mcp add twining -- npx -y twining-mcp --project .
36
34
  ```
37
35
 
38
- Or scope it to a single project:
36
+ **Record a decision with rationale:**
37
+ ```
38
+ > Use twining_decide to record: chose PostgreSQL over MongoDB for ACID compliance
39
+ ```
40
+ Twining captures the decision, rationale, alternatives considered, confidence level, and affected files — as a structured record, not chat history.
39
41
 
40
- ```bash
41
- claude mcp add twining -s project -- npx -y twining-mcp --project .
42
+ **Start a new session. Get caught up instantly:**
42
43
  ```
44
+ > Use twining_assemble for the database module
45
+ ```
46
+ Twining scores every decision, warning, and finding by relevance to your task, then fills a token budget in priority order. You get exactly the context you need — no firehose, no re-explaining.
43
47
 
44
- ### Manual Configuration
48
+ **Ask why things are the way they are:**
49
+ ```
50
+ > Use twining_why src/auth/middleware.ts
51
+ ```
52
+ Returns the full decision chain for any file: what was decided, when, why, what alternatives were rejected, and which commit implemented it.
45
53
 
46
- Alternatively, add to your `.mcp.json` directly:
54
+ ## Why Not Just Use CLAUDE.md?
47
55
 
48
- ```json
49
- {
50
- "mcpServers": {
51
- "twining": {
52
- "command": "npx",
53
- "args": ["-y", "twining-mcp", "--project", "."]
54
- }
55
- }
56
- }
57
- ```
56
+ CLAUDE.md is static. You write it once and update it manually. It doesn't capture decisions *as they happen*, doesn't track rationale or alternatives, doesn't detect conflicts between agents, and can't selectively assemble context within a token budget.
58
57
 
59
- ### Usage
58
+ Twining is dynamic. Every `twining_decide` call records a structured decision. Every `twining_post` shares a finding or warning. Every `twining_assemble` scores relevance and delivers precisely what the current task needs. The `.twining/` directory is your project's living institutional memory.
60
59
 
61
- Once configured, Twining tools are available in your Claude Code sessions:
60
+ ## Why Not an Orchestrator?
62
61
 
63
- ```
64
- > Use twining_post to share a finding about the auth module
65
- > Use twining_assemble to get context for the refactoring task
66
- > Use twining_decide to record the database choice with rationale
67
- > Use twining_why to understand why we chose PostgreSQL
68
- > Use twining_agents to see which agents are available
69
- ```
62
+ Orchestrators (like agent swarms and hierarchical coordinators) route work by *assigning tasks*. Twining coordinates by *sharing state*. The difference matters:
70
63
 
71
- All state is stored in a `.twining/` directory in your project root.
64
+ - **Orchestrators** hold coordination context in their own context window — a single point of failure that degrades as the window fills
65
+ - **Twining's blackboard** persists coordination state outside any agent's window, surviving context resets without information loss
72
66
 
73
- ### Claude Code Integration
67
+ Agents self-select into work by reading the blackboard. No central bottleneck. No relay that drops context. Every agent sees every other agent's decisions and warnings, directly.
74
68
 
75
- For maximum value with Claude Code, add Twining instructions to your project's `CLAUDE.md`. See **[docs/CLAUDE_TEMPLATE.md](docs/CLAUDE_TEMPLATE.md)** for a ready-to-copy template covering Twining + Serena + GSD integration.
69
+ ## Quick Start
76
70
 
77
- ### Dashboard
71
+ ### Add to Claude Code
78
72
 
79
- The web dashboard starts automatically on port 24282 (configurable via `TWINING_DASHBOARD_PORT`). Open `http://localhost:24282` to browse blackboard entries, decisions, knowledge graph, and agent coordination state.
73
+ ```bash
74
+ claude mcp add twining -- npx -y twining-mcp --project .
75
+ ```
80
76
 
81
- ## Install
77
+ Or scope to a single project:
82
78
 
83
- ```bash
84
- npm install -g twining-mcp
79
+ ```bash
80
+ claude mcp add twining -s project -- npx -y twining-mcp --project .
85
81
  ```
86
82
 
87
- then update mcp settings file:
83
+ ### Manual Configuration
84
+
85
+ Add to your `.mcp.json`:
88
86
 
89
87
  ```json
90
88
  {
91
89
  "mcpServers": {
92
90
  "twining": {
93
- "command": "twining-mcp",
94
- "args": ["--project", "/path/to/your/project"]
91
+ "command": "npx",
92
+ "args": ["-y", "twining-mcp", "--project", "."]
95
93
  }
96
94
  }
97
95
  }
98
96
  ```
99
97
 
100
- If `--project` is omitted, Twining uses the current working directory.
98
+ ### Get the Most Out of It
101
99
 
102
- ## Tools
100
+ Add Twining instructions to your project's `CLAUDE.md` so agents use it automatically. See **[docs/CLAUDE_TEMPLATE.md](docs/CLAUDE_TEMPLATE.md)** for a ready-to-copy template.
103
101
 
104
- ### Blackboard
102
+ ### Dashboard
105
103
 
106
- | Tool | Description |
107
- |------|-------------|
108
- | `twining_post` | Post an entry (finding, need, warning, question) to the shared blackboard |
109
- | `twining_read` | Read blackboard entries with optional filters by type, scope, or agent |
110
- | `twining_query` | Semantic search across blackboard entries, with keyword fallback |
111
- | `twining_recent` | Get the most recent blackboard entries |
104
+ A web dashboard starts automatically at `http://localhost:24282` — browse decisions, blackboard entries, knowledge graph, and agent state. Configurable via `TWINING_DASHBOARD_PORT`.
105
+
106
+ ## What's Inside
112
107
 
113
- ### Decisions
108
+ ### Persistent Decisions
114
109
 
115
- | Tool | Description |
110
+ | Tool | What It Does |
111
+ |------|-------------|
112
+ | `twining_decide` | Record a decision with rationale, alternatives, confidence, and traceability |
113
+ | `twining_why` | Get the full decision chain for any file or scope |
114
+ | `twining_trace` | Trace a decision's dependency chain upstream and downstream |
115
+ | `twining_reconsider` | Flag a decision for reconsideration with impact analysis |
116
+ | `twining_override` | Override a decision, optionally creating a replacement |
117
+ | `twining_search_decisions` | Search decisions by keyword or semantic similarity |
118
+ | `twining_link_commit` | Link a git commit to a decision |
119
+ | `twining_commits` | Find decisions by git commit |
120
+
121
+ ### Shared Blackboard
122
+
123
+ | Tool | What It Does |
116
124
  |------|-------------|
117
- | `twining_decide` | Record a decision with rationale, alternatives, and traceability |
118
- | `twining_why` | Retrieve all decisions affecting a given scope or file |
119
- | `twining_trace` | Trace a decision's dependency chain upstream and/or downstream |
120
- | `twining_reconsider` | Flag a decision for reconsideration with downstream impact analysis |
121
- | `twining_override` | Override a decision with a reason, optionally creating a replacement |
122
- | `twining_search_decisions` | Search decisions by keyword or semantic similarity with filters |
123
- | `twining_link_commit` | Link a git commit hash to an existing decision |
124
- | `twining_commits` | Query decisions by git commit hash |
125
-
126
- ### Context & Lifecycle
127
-
128
- | Tool | Description |
125
+ | `twining_post` | Share a finding, warning, need, or question with all agents |
126
+ | `twining_read` | Read entries filtered by type, scope, or agent |
127
+ | `twining_query` | Semantic search across all entries |
128
+ | `twining_recent` | Get the latest entries |
129
+
130
+ ### Context Assembly
131
+
132
+ | Tool | What It Does |
129
133
  |------|-------------|
130
134
  | `twining_assemble` | Build tailored context for a task within a token budget |
131
- | `twining_summarize` | Get a high-level summary of project state and activity |
132
- | `twining_what_changed` | Report what changed since a given point in time |
133
- | `twining_status` | Overall health check — entry counts, agent counts, warnings, and summary |
134
- | `twining_archive` | Archive old blackboard entries to reduce working set size |
135
- | `twining_export` | Export full Twining state as a single markdown document |
135
+ | `twining_summarize` | High-level summary of project state |
136
+ | `twining_what_changed` | What changed since a given point in time |
137
+ | `twining_status` | Health check — entry counts, warnings, agent status |
138
+ | `twining_archive` | Move stale entries to archive |
139
+ | `twining_export` | Export full state as markdown |
136
140
 
137
141
  ### Knowledge Graph
138
142
 
139
- | Tool | Description |
143
+ | Tool | What It Does |
140
144
  |------|-------------|
141
- | `twining_add_entity` | Add or update a knowledge graph entity (upsert semantics) |
142
- | `twining_add_relation` | Add a relation between two knowledge graph entities |
143
- | `twining_neighbors` | Traverse the knowledge graph from an entity up to depth 3 |
144
- | `twining_graph_query` | Search the knowledge graph by name or property substring |
145
+ | `twining_add_entity` | Add or update an entity |
146
+ | `twining_add_relation` | Add a relation between entities |
147
+ | `twining_neighbors` | Traverse from an entity up to depth 3 |
148
+ | `twining_graph_query` | Search by name or property |
149
+
150
+ Decisions auto-populate the graph: `twining_decide` creates file and function entities with `decided_by` relations for every affected file.
145
151
 
146
152
  ### Agent Coordination
147
153
 
148
- | Tool | Description |
154
+ | Tool | What It Does |
149
155
  |------|-------------|
150
- | `twining_agents` | List registered agents with capabilities, liveness status, and filtering |
151
- | `twining_discover` | Find agents matching required capabilities, ranked by overlap and liveness |
152
- | `twining_delegate` | Post a delegation request to the blackboard with capability requirements |
153
- | `twining_handoff` | Create a handoff between agents with work results and auto-assembled context |
156
+ | `twining_agents` | List agents with capabilities and liveness |
157
+ | `twining_discover` | Find agents matching required capabilities |
158
+ | `twining_delegate` | Post a delegation request with capability requirements |
159
+ | `twining_handoff` | Hand off work with results and auto-assembled context |
154
160
  | `twining_acknowledge` | Acknowledge receipt of a handoff |
155
161
 
156
- ## Architecture
162
+ ## How It Works
157
163
 
158
- Twining is organized in layers:
164
+ All state lives in `.twining/` as plain files — JSONL for the blackboard, JSON for decisions, graph, agents, and handoffs. Everything is `jq`-queryable, `grep`-able, and git-diffable. No database. No cloud. No accounts.
159
165
 
160
- - **Storage Layer** — File-backed stores for blackboard (JSONL), decisions (JSON index + individual files), knowledge graph (JSON), agent registry, and handoff records. All I/O goes through this layer with file locking for concurrent access.
161
- - **Engine Layer** — Business logic for each domain: blackboard posting/querying, decision recording/tracing, graph traversal, context assembly with token budgeting, agent coordination with capability-based discovery and delegation, and archiving.
162
- - **Embeddings Layer** — Lazy-loaded local embeddings using `@huggingface/transformers` with all-MiniLM-L6-v2. Falls back to keyword search if model loading fails. The server never fails to start because of embedding issues.
163
- - **Dashboard Layer** — Embedded HTTP server running alongside MCP stdio transport. Vanilla HTML/CSS/JS with cytoscape.js for graph visualization and vis-timeline for decision timelines. Read-only observer of Twining state.
164
- - **Tools Layer** — MCP tool definitions that map 1:1 to the tool surface. Each tool validates input with Zod and returns structured results.
166
+ **Architecture layers:**
165
167
 
166
- All state lives in `.twining/` as plain files JSONL for the blackboard stream, JSON for decisions, graph, agents, and handoffs. Everything is `jq`-queryable, `grep`-able, and git-diffable.
168
+ - **Storage**File-backed stores with locking for concurrent access
169
+ - **Engine** — Decision tracking, blackboard, graph traversal, context assembly with token budgeting, agent coordination
170
+ - **Embeddings** — Local all-MiniLM-L6-v2 via `@huggingface/transformers`, lazy-loaded, with keyword fallback. The server never fails to start because of embedding issues.
171
+ - **Dashboard** — Read-only web UI with cytoscape.js graph visualization and vis-timeline
172
+ - **Tools** — MCP tool definitions validated with Zod, mapping 1:1 to the tool surface
167
173
 
168
- See [TWINING-DESIGN-SPEC.md](TWINING-DESIGN-SPEC.md) for the full design specification.
174
+ See [TWINING-DESIGN-SPEC.md](TWINING-DESIGN-SPEC.md) for the full specification.
169
175
 
170
- ## Development
176
+ ## FAQ
171
177
 
172
- ```bash
173
- # Install dependencies
174
- npm install
178
+ **Does Twining slow down Claude Code?**
179
+ No. It's a local MCP server — tool calls are local file reads/writes. Semantic search loads lazily on first use.
180
+
181
+ **Can I use it with Cursor, Windsurf, or other MCP clients?**
182
+ Yes. Twining is a standard MCP server. Any MCP host can connect to it.
175
183
 
176
- # Build
177
- npm run build
184
+ **Where does my data go?**
185
+ Nowhere. All state is local in `.twining/`. No telemetry, no cloud, no external calls.
178
186
 
179
- # Run tests
180
- npm test
187
+ **Is Twining an agent orchestrator?**
188
+ No. It's a coordination state layer. It captures what agents decided and why, and makes that knowledge available to future agents. Use it alongside orchestrators, agent teams, or standalone sessions.
181
189
 
182
- # Watch mode
190
+ ## Development
191
+
192
+ ```bash
193
+ npm install # Install dependencies
194
+ npm run build # Build
195
+ npm test # Run tests (444 tests)
183
196
  npm run test:watch
184
197
  ```
185
198
 
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,eAAO,MAAM,cAAc,EAAE,aAgC5B,CAAC;AA+BF;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CAc5D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,eAAO,MAAM,cAAc,EAAE,aAiC5B,CAAC;AA+BF;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CAc5D"}
package/dist/config.js CHANGED
@@ -17,9 +17,10 @@ export const DEFAULT_CONFIG = {
17
17
  default_max_tokens: 4000,
18
18
  priority_weights: {
19
19
  recency: 0.3,
20
- relevance: 0.4,
20
+ relevance: 0.3,
21
21
  decision_confidence: 0.2,
22
22
  warning_boost: 0.1,
23
+ graph_connectivity: 0.1,
23
24
  },
24
25
  },
25
26
  conflict_resolution: "human",
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,IAAI,MAAM,SAAS,CAAC;AAG3B,MAAM,CAAC,MAAM,cAAc,GAAkB;IAC3C,OAAO,EAAE,CAAC;IACV,YAAY,EAAE,EAAE;IAChB,eAAe,EAAE,kBAAkB;IACnC,OAAO,EAAE;QACP,sBAAsB,EAAE,IAAI;QAC5B,8BAA8B,EAAE,IAAI;QACpC,qCAAqC,EAAE,GAAG;KAC3C;IACD,gBAAgB,EAAE;QAChB,kBAAkB,EAAE,IAAI;QACxB,gBAAgB,EAAE;YAChB,OAAO,EAAE,GAAG;YACZ,SAAS,EAAE,GAAG;YACd,mBAAmB,EAAE,GAAG;YACxB,aAAa,EAAE,GAAG;SACnB;KACF;IACD,mBAAmB,EAAE,OAAO;IAC5B,MAAM,EAAE;QACN,QAAQ,EAAE;YACR,aAAa,EAAE,MAAM,EAAE,YAAY;YACnC,aAAa,EAAE,OAAO,EAAE,aAAa;SACtC;KACF;IACD,WAAW,EAAE;QACX,QAAQ,EAAE;YACR,OAAO,EAAE,MAAM,EAAQ,YAAY;YACnC,SAAS,EAAE,OAAO,EAAK,aAAa;YACpC,MAAM,EAAE,QAAQ,EAAO,UAAU;SAClC;KACF;CACF,CAAC;AAEF,4DAA4D;AAC5D,SAAS,SAAS,CAChB,MAA+B,EAC/B,MAA+B;IAE/B,MAAM,MAAM,GAA4B,EAAE,GAAG,MAAM,EAAE,CAAC;IACtD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,SAAS,KAAK,SAAS;YAAE,SAAS;QACtC,IACE,SAAS,KAAK,IAAI;YAClB,OAAO,SAAS,KAAK,QAAQ;YAC7B,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;YACzB,SAAS,KAAK,IAAI;YAClB,OAAO,SAAS,KAAK,QAAQ;YAC7B,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EACzB,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CACrB,SAAoC,EACpC,SAAoC,CACrC,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,UAAkB;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IACvD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;IACD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1E,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,SAAS,CACd,cAAoD,EACpD,MAAiC,CACN,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,IAAI,MAAM,SAAS,CAAC;AAG3B,MAAM,CAAC,MAAM,cAAc,GAAkB;IAC3C,OAAO,EAAE,CAAC;IACV,YAAY,EAAE,EAAE;IAChB,eAAe,EAAE,kBAAkB;IACnC,OAAO,EAAE;QACP,sBAAsB,EAAE,IAAI;QAC5B,8BAA8B,EAAE,IAAI;QACpC,qCAAqC,EAAE,GAAG;KAC3C;IACD,gBAAgB,EAAE;QAChB,kBAAkB,EAAE,IAAI;QACxB,gBAAgB,EAAE;YAChB,OAAO,EAAE,GAAG;YACZ,SAAS,EAAE,GAAG;YACd,mBAAmB,EAAE,GAAG;YACxB,aAAa,EAAE,GAAG;YAClB,kBAAkB,EAAE,GAAG;SACxB;KACF;IACD,mBAAmB,EAAE,OAAO;IAC5B,MAAM,EAAE;QACN,QAAQ,EAAE;YACR,aAAa,EAAE,MAAM,EAAE,YAAY;YACnC,aAAa,EAAE,OAAO,EAAE,aAAa;SACtC;KACF;IACD,WAAW,EAAE;QACX,QAAQ,EAAE;YACR,OAAO,EAAE,MAAM,EAAQ,YAAY;YACnC,SAAS,EAAE,OAAO,EAAK,aAAa;YACpC,MAAM,EAAE,QAAQ,EAAO,UAAU;SAClC;KACF;CACF,CAAC;AAEF,4DAA4D;AAC5D,SAAS,SAAS,CAChB,MAA+B,EAC/B,MAA+B;IAE/B,MAAM,MAAM,GAA4B,EAAE,GAAG,MAAM,EAAE,CAAC;IACtD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,SAAS,KAAK,SAAS;YAAE,SAAS;QACtC,IACE,SAAS,KAAK,IAAI;YAClB,OAAO,SAAS,KAAK,QAAQ;YAC7B,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;YACzB,SAAS,KAAK,IAAI;YAClB,OAAO,SAAS,KAAK,QAAQ;YAC7B,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EACzB,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CACrB,SAAoC,EACpC,SAAoC,CACrC,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,UAAkB;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IACvD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;IACD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1E,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,SAAS,CACd,cAAoD,EACpD,MAAiC,CACN,CAAC;AAChC,CAAC"}
@@ -134,6 +134,8 @@ function fetchBlackboard() {
134
134
  state.connected = true;
135
135
  updateConnectionIndicator();
136
136
  renderBlackboard();
137
+ renderActivityBreakdown();
138
+ renderRecentActivity();
137
139
  })
138
140
  .catch(function() {
139
141
  state.connected = false;
@@ -281,7 +283,8 @@ function fetchHandoffDetail(id) {
281
283
  function refreshData() {
282
284
  fetchStatus();
283
285
  var tab = state.activeTab;
284
- if (tab === "blackboard") fetchBlackboard();
286
+ if (tab === "stats") fetchBlackboard();
287
+ else if (tab === "blackboard") fetchBlackboard();
285
288
  else if (tab === "decisions") fetchDecisions();
286
289
  else if (tab === "graph") fetchGraph();
287
290
  else if (tab === "search" && state.search.query) fetchSearch();
@@ -457,6 +460,78 @@ function renderStatus() {
457
460
  if (msgEl) {
458
461
  msgEl.style.display = (s.initialized === false) ? "block" : "none";
459
462
  }
463
+
464
+ renderActivityBreakdown();
465
+ renderRecentActivity();
466
+ }
467
+
468
+ function renderActivityBreakdown() {
469
+ var container = document.getElementById('activity-breakdown');
470
+ if (!container) return;
471
+
472
+ var entries = state.blackboard.data || [];
473
+ var typeCounts = {};
474
+
475
+ for (var i = 0; i < entries.length; i++) {
476
+ var type = entries[i].entry_type || 'unknown';
477
+ typeCounts[type] = (typeCounts[type] || 0) + 1;
478
+ }
479
+
480
+ clearElement(container);
481
+
482
+ var types = Object.keys(typeCounts).sort(function(a, b) {
483
+ return typeCounts[b] - typeCounts[a];
484
+ });
485
+
486
+ for (var j = 0; j < types.length; j++) {
487
+ var type = types[j];
488
+ var count = typeCounts[type];
489
+
490
+ var item = el('div', 'activity-item');
491
+ var label = el('div', 'activity-item-label', type);
492
+ var countEl = el('div', 'activity-item-count', String(count));
493
+
494
+ item.appendChild(label);
495
+ item.appendChild(countEl);
496
+ container.appendChild(item);
497
+ }
498
+ }
499
+
500
+ function renderRecentActivity() {
501
+ var container = document.getElementById('recent-activity');
502
+ if (!container) return;
503
+
504
+ var entries = state.blackboard.data || [];
505
+ var sorted = entries.slice().sort(function(a, b) {
506
+ return new Date(b.timestamp) - new Date(a.timestamp);
507
+ });
508
+
509
+ var recent = sorted.slice(0, 10);
510
+ clearElement(container);
511
+
512
+ if (recent.length === 0) {
513
+ container.textContent = 'No recent activity';
514
+ return;
515
+ }
516
+
517
+ for (var i = 0; i < recent.length; i++) {
518
+ var entry = recent[i];
519
+
520
+ var entryDiv = el('div', 'activity-entry');
521
+
522
+ var header = el('div', 'activity-entry-header');
523
+ var typeSpan = el('div', 'activity-entry-type', entry.entry_type || 'unknown');
524
+ var timeSpan = el('div', 'activity-entry-time', formatTimestamp(entry.timestamp));
525
+
526
+ header.appendChild(typeSpan);
527
+ header.appendChild(timeSpan);
528
+
529
+ var summary = el('div', 'activity-entry-summary', truncate(entry.summary || '', 80));
530
+
531
+ entryDiv.appendChild(header);
532
+ entryDiv.appendChild(summary);
533
+ container.appendChild(entryDiv);
534
+ }
460
535
  }
461
536
 
462
537
  /* ========== Render: Blackboard ========== */
@@ -1841,7 +1916,9 @@ function initTimeline() {
1841
1916
  orientation: { axis: 'top' },
1842
1917
  selectable: true,
1843
1918
  tooltip: { followMouse: true },
1844
- margin: { item: 10 }
1919
+ margin: { item: { horizontal: 10, vertical: 20 } },
1920
+ stack: true,
1921
+ maxHeight: 600
1845
1922
  };
1846
1923
 
1847
1924
  window.timelineInstance = new vis.Timeline(container, window.timelineDataSet, options);
@@ -1938,12 +2015,14 @@ function buildGraphStyles() {
1938
2015
  'label': 'data(label)',
1939
2016
  'text-valign': 'bottom',
1940
2017
  'text-halign': 'center',
1941
- 'font-size': '10px',
1942
- 'width': 30,
1943
- 'height': 30,
2018
+ 'font-size': '11px',
2019
+ 'width': 40,
2020
+ 'height': 40,
1944
2021
  'color': textColor,
1945
- 'text-margin-y': 4,
1946
- 'background-color': '#6b7280'
2022
+ 'text-margin-y': 6,
2023
+ 'background-color': '#6b7280',
2024
+ 'text-wrap': 'wrap',
2025
+ 'text-max-width': '120px'
1947
2026
  }
1948
2027
  },
1949
2028
  {
@@ -2075,10 +2154,19 @@ function initGraphVis() {
2075
2154
  window.cyInstance = cytoscape({
2076
2155
  container: document.getElementById('graph-canvas'),
2077
2156
  elements: elements,
2078
- layout: { name: 'cose', animate: true, animationDuration: 500, nodeRepulsion: function() { return 8000; } },
2157
+ layout: {
2158
+ name: 'cose',
2159
+ animate: true,
2160
+ animationDuration: 500,
2161
+ nodeRepulsion: function() { return 12000; },
2162
+ idealEdgeLength: function() { return 100; },
2163
+ nodeOverlap: 20,
2164
+ padding: 40
2165
+ },
2079
2166
  style: buildGraphStyles(),
2080
2167
  minZoom: 0.2,
2081
- maxZoom: 5
2168
+ maxZoom: 5,
2169
+ wheelSensitivity: 0.2
2082
2170
  });
2083
2171
 
2084
2172
  // Click node to show detail and expand neighbors
@@ -2106,6 +2194,49 @@ function initGraphVis() {
2106
2194
  });
2107
2195
 
2108
2196
  renderGraphLegend();
2197
+ setupGraphControls();
2198
+ }
2199
+
2200
+ function setupGraphControls() {
2201
+ var zoomIn = document.getElementById('graph-zoom-in');
2202
+ var zoomOut = document.getElementById('graph-zoom-out');
2203
+ var fit = document.getElementById('graph-fit');
2204
+ var reset = document.getElementById('graph-reset');
2205
+
2206
+ if (zoomIn) {
2207
+ zoomIn.onclick = function() {
2208
+ if (window.cyInstance) window.cyInstance.zoom(window.cyInstance.zoom() * 1.2);
2209
+ };
2210
+ }
2211
+
2212
+ if (zoomOut) {
2213
+ zoomOut.onclick = function() {
2214
+ if (window.cyInstance) window.cyInstance.zoom(window.cyInstance.zoom() * 0.8);
2215
+ };
2216
+ }
2217
+
2218
+ if (fit) {
2219
+ fit.onclick = function() {
2220
+ if (window.cyInstance) window.cyInstance.fit(null, 40);
2221
+ };
2222
+ }
2223
+
2224
+ if (reset) {
2225
+ reset.onclick = function() {
2226
+ if (window.cyInstance) {
2227
+ var layout = window.cyInstance.layout({
2228
+ name: 'cose',
2229
+ animate: true,
2230
+ animationDuration: 500,
2231
+ nodeRepulsion: function() { return 12000; },
2232
+ idealEdgeLength: function() { return 100; },
2233
+ nodeOverlap: 20,
2234
+ padding: 40
2235
+ });
2236
+ layout.run();
2237
+ }
2238
+ };
2239
+ }
2109
2240
  }
2110
2241
 
2111
2242
  function expandNeighbors(nodeId) {
@@ -115,6 +115,17 @@
115
115
  <div class="stat-value" id="stat-total-handoffs">--</div>
116
116
  </div>
117
117
  </div>
118
+
119
+ <div class="stats-section">
120
+ <h2 class="stats-section-title">Activity Breakdown</h2>
121
+ <div id="activity-breakdown" class="activity-breakdown"></div>
122
+ </div>
123
+
124
+ <div class="stats-section">
125
+ <h2 class="stats-section-title">Recent Activity</h2>
126
+ <div id="recent-activity" class="recent-activity"></div>
127
+ </div>
128
+
118
129
  <div id="uninitialized-msg" style="display:none">No data yet. Twining will populate as agents use MCP tools.</div>
119
130
  </div>
120
131
 
@@ -213,7 +224,14 @@
213
224
  <div class="view-visual" id="graph-visual-view" style="display:none">
214
225
  <div class="content-area">
215
226
  <div class="list-panel">
216
- <div id="graph-canvas"></div>
227
+ <div id="graph-canvas">
228
+ <div class="graph-controls">
229
+ <button id="graph-zoom-in" title="Zoom in" aria-label="Zoom in">+</button>
230
+ <button id="graph-zoom-out" title="Zoom out" aria-label="Zoom out">−</button>
231
+ <button id="graph-fit" title="Fit to screen" aria-label="Fit to screen">⊡</button>
232
+ <button id="graph-reset" title="Reset layout" aria-label="Reset layout">↻</button>
233
+ </div>
234
+ </div>
217
235
  <div class="graph-legend" id="graph-legend"></div>
218
236
  </div>
219
237
  <div class="detail-panel" id="graph-visual-detail">