twining-mcp 1.8.2 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +20 -5
- package/dist/config.js.map +1 -1
- package/dist/dashboard/public/app.js +3 -1
- package/dist/engine/blackboard.d.ts +4 -0
- package/dist/engine/blackboard.d.ts.map +1 -1
- package/dist/engine/blackboard.js +9 -0
- package/dist/engine/blackboard.js.map +1 -1
- package/dist/engine/context-assembler.d.ts +14 -1
- package/dist/engine/context-assembler.d.ts.map +1 -1
- package/dist/engine/context-assembler.js +222 -42
- package/dist/engine/context-assembler.js.map +1 -1
- package/dist/engine/decisions.d.ts +1 -1
- package/dist/engine/decisions.d.ts.map +1 -1
- package/dist/engine/decisions.js +26 -42
- package/dist/engine/decisions.js.map +1 -1
- package/dist/engine/graph-auto-populator.d.ts +61 -0
- package/dist/engine/graph-auto-populator.d.ts.map +1 -0
- package/dist/engine/graph-auto-populator.js +283 -0
- package/dist/engine/graph-auto-populator.js.map +1 -0
- package/dist/engine/verify.d.ts.map +1 -1
- package/dist/engine/verify.js +34 -0
- package/dist/engine/verify.js.map +1 -1
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.d.ts.map +1 -1
- package/dist/instructions.js +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +23 -9
- package/dist/server.js.map +1 -1
- package/dist/tools/blackboard-tools.d.ts +1 -1
- package/dist/tools/blackboard-tools.d.ts.map +1 -1
- package/dist/tools/blackboard-tools.js +39 -38
- package/dist/tools/blackboard-tools.js.map +1 -1
- package/dist/tools/context-tools.d.ts +2 -2
- package/dist/tools/context-tools.d.ts.map +1 -1
- package/dist/tools/context-tools.js +30 -27
- package/dist/tools/context-tools.js.map +1 -1
- package/dist/tools/coordination-tools.d.ts +2 -1
- package/dist/tools/coordination-tools.d.ts.map +1 -1
- package/dist/tools/coordination-tools.js +160 -142
- package/dist/tools/coordination-tools.js.map +1 -1
- package/dist/tools/decision-tools.d.ts +1 -1
- package/dist/tools/decision-tools.d.ts.map +1 -1
- package/dist/tools/decision-tools.js +118 -113
- package/dist/tools/decision-tools.js.map +1 -1
- package/dist/tools/export-tools.d.ts +1 -1
- package/dist/tools/export-tools.d.ts.map +1 -1
- package/dist/tools/export-tools.js +4 -2
- package/dist/tools/export-tools.js.map +1 -1
- package/dist/tools/graph-tools.d.ts +1 -1
- package/dist/tools/graph-tools.d.ts.map +1 -1
- package/dist/tools/graph-tools.js +54 -52
- package/dist/tools/graph-tools.js.map +1 -1
- package/dist/tools/lifecycle-tools.d.ts.map +1 -1
- package/dist/tools/lifecycle-tools.js +34 -32
- package/dist/tools/lifecycle-tools.js.map +1 -1
- package/dist/tools/verify-tools.d.ts +1 -1
- package/dist/tools/verify-tools.d.ts.map +1 -1
- package/dist/tools/verify-tools.js +4 -1
- package/dist/tools/verify-tools.js.map +1 -1
- package/dist/utils/types.d.ts +14 -2
- package/dist/utils/types.d.ts.map +1 -1
- package/package.json +10 -2
- package/src/dashboard/public/app.js +3 -1
package/README.md
CHANGED
|
@@ -80,7 +80,7 @@ Agents self-select into work by reading the blackboard. No central bottleneck. N
|
|
|
80
80
|
/plugin install twining@twining-marketplace
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
Includes the MCP server,
|
|
83
|
+
Includes the MCP server, 8 skills, lifecycle hooks, coordinator subagent, and commands. Skills teach Claude when and how to use Twining — everything works automatically.
|
|
84
84
|
|
|
85
85
|
### Team Auto-Install
|
|
86
86
|
|
|
@@ -166,6 +166,7 @@ A web dashboard starts automatically at `http://localhost:24282` — browse deci
|
|
|
166
166
|
| `twining_trace` | Trace a decision's dependency chain upstream and downstream |
|
|
167
167
|
| `twining_reconsider` | Flag a decision for reconsideration with impact analysis |
|
|
168
168
|
| `twining_override` | Override a decision, optionally creating a replacement |
|
|
169
|
+
| `twining_promote` | Promote provisional decisions to active after validation |
|
|
169
170
|
| `twining_search_decisions` | Search decisions by keyword or semantic similarity |
|
|
170
171
|
| `twining_link_commit` | Link a git commit to a decision |
|
|
171
172
|
| `twining_commits` | Find decisions by git commit |
|
|
@@ -178,6 +179,7 @@ A web dashboard starts automatically at `http://localhost:24282` — browse deci
|
|
|
178
179
|
| `twining_read` | Read entries filtered by type, scope, or agent |
|
|
179
180
|
| `twining_query` | Semantic search across all entries |
|
|
180
181
|
| `twining_recent` | Get the latest entries |
|
|
182
|
+
| `twining_dismiss` | Remove resolved or false-positive entries by ID |
|
|
181
183
|
|
|
182
184
|
### Context Assembly
|
|
183
185
|
|
|
@@ -186,9 +188,6 @@ A web dashboard starts automatically at `http://localhost:24282` — browse deci
|
|
|
186
188
|
| `twining_assemble` | Build tailored context for a task within a token budget |
|
|
187
189
|
| `twining_summarize` | High-level summary of project state |
|
|
188
190
|
| `twining_what_changed` | What changed since a given point in time |
|
|
189
|
-
| `twining_status` | Health check — entry counts, warnings, agent status |
|
|
190
|
-
| `twining_archive` | Move stale entries to archive |
|
|
191
|
-
| `twining_export` | Export full state as markdown |
|
|
192
191
|
|
|
193
192
|
### Knowledge Graph
|
|
194
193
|
|
|
@@ -198,6 +197,7 @@ A web dashboard starts automatically at `http://localhost:24282` — browse deci
|
|
|
198
197
|
| `twining_add_relation` | Add a relation between entities |
|
|
199
198
|
| `twining_neighbors` | Traverse from an entity up to depth 3 |
|
|
200
199
|
| `twining_graph_query` | Search by name or property |
|
|
200
|
+
| `twining_prune_graph` | Remove orphaned entities with no relations |
|
|
201
201
|
|
|
202
202
|
Decisions auto-populate the graph: `twining_decide` creates file and function entities with `decided_by` relations for every affected file.
|
|
203
203
|
|
|
@@ -205,12 +205,22 @@ Decisions auto-populate the graph: `twining_decide` creates file and function en
|
|
|
205
205
|
|
|
206
206
|
| Tool | What It Does |
|
|
207
207
|
|------|-------------|
|
|
208
|
+
| `twining_register` | Register or update an agent in the coordination registry |
|
|
208
209
|
| `twining_agents` | List agents with capabilities and liveness |
|
|
209
210
|
| `twining_discover` | Find agents matching required capabilities |
|
|
210
211
|
| `twining_delegate` | Post a delegation request with capability requirements |
|
|
211
212
|
| `twining_handoff` | Hand off work with results and auto-assembled context |
|
|
212
213
|
| `twining_acknowledge` | Acknowledge receipt of a handoff |
|
|
213
214
|
|
|
215
|
+
### Verification & Lifecycle
|
|
216
|
+
|
|
217
|
+
| Tool | What It Does |
|
|
218
|
+
|------|-------------|
|
|
219
|
+
| `twining_verify` | Run verification checks — test coverage, warnings, assembly tracking |
|
|
220
|
+
| `twining_status` | Health check — entry counts, warnings, agent status |
|
|
221
|
+
| `twining_archive` | Move stale entries to archive |
|
|
222
|
+
| `twining_export` | Export full state as markdown |
|
|
223
|
+
|
|
214
224
|
## How It Works
|
|
215
225
|
|
|
216
226
|
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.
|
|
@@ -293,7 +303,7 @@ That's it — the PostHog project key is built into the source code. If you run
|
|
|
293
303
|
```bash
|
|
294
304
|
npm install # Install dependencies
|
|
295
305
|
npm run build # Build
|
|
296
|
-
npm test # Run tests (
|
|
306
|
+
npm test # Run tests (600+ tests)
|
|
297
307
|
npm run test:watch
|
|
298
308
|
```
|
|
299
309
|
|
package/dist/config.d.ts.map
CHANGED
|
@@ -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,
|
|
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,aAqD5B,CAAC;AA+BF;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CA0B5D"}
|
package/dist/config.js
CHANGED
|
@@ -16,11 +16,11 @@ export const DEFAULT_CONFIG = {
|
|
|
16
16
|
context_assembly: {
|
|
17
17
|
default_max_tokens: 4000,
|
|
18
18
|
priority_weights: {
|
|
19
|
-
recency: 0.
|
|
20
|
-
relevance: 0.
|
|
21
|
-
decision_confidence: 0.
|
|
19
|
+
recency: 0.2,
|
|
20
|
+
relevance: 0.2,
|
|
21
|
+
decision_confidence: 0.15,
|
|
22
22
|
warning_boost: 0.1,
|
|
23
|
-
|
|
23
|
+
graph_reachability: 0.35,
|
|
24
24
|
},
|
|
25
25
|
},
|
|
26
26
|
conflict_resolution: "human",
|
|
@@ -50,6 +50,13 @@ export const DEFAULT_CONFIG = {
|
|
|
50
50
|
instructions: {
|
|
51
51
|
auto_inject: true, // Include workflow instructions in MCP initialize response
|
|
52
52
|
},
|
|
53
|
+
tools: {
|
|
54
|
+
mode: "full", // "full" or "lite" — lite registers only core tools
|
|
55
|
+
full_surface: false, // when false, hide 16 rarely-used tools to reduce context noise
|
|
56
|
+
},
|
|
57
|
+
graph: {
|
|
58
|
+
auto_populate: false, // when false, skip auto-graph-population from tool calls
|
|
59
|
+
},
|
|
53
60
|
};
|
|
54
61
|
/** Deep merge source into target, returning a new object */
|
|
55
62
|
function deepMerge(target, source) {
|
|
@@ -87,6 +94,14 @@ export function loadConfig(twiningDir) {
|
|
|
87
94
|
if (parsed === null || parsed === undefined || typeof parsed !== "object") {
|
|
88
95
|
return { ...DEFAULT_CONFIG };
|
|
89
96
|
}
|
|
90
|
-
|
|
97
|
+
const config = deepMerge(DEFAULT_CONFIG, parsed);
|
|
98
|
+
// Validate priority weights sum to 1.0
|
|
99
|
+
const weights = config.context_assembly.priority_weights;
|
|
100
|
+
const weightSum = Object.values(weights).reduce((a, b) => (a ?? 0) + (b ?? 0), 0);
|
|
101
|
+
if (Math.abs(weightSum - 1.0) > 0.01) {
|
|
102
|
+
console.error(`[twining] Warning: priority_weights sum to ${weightSum}, expected 1.0. Using defaults.`);
|
|
103
|
+
config.context_assembly.priority_weights = { ...DEFAULT_CONFIG.context_assembly.priority_weights };
|
|
104
|
+
}
|
|
105
|
+
return config;
|
|
91
106
|
}
|
|
92
107
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -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,
|
|
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,IAAI;YACzB,aAAa,EAAE,GAAG;YAClB,kBAAkB,EAAE,IAAI;SACzB;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;IACD,SAAS,EAAE;QACT,OAAO,EAAE;YACP,OAAO,EAAE,IAAI,EAAU,8BAA8B;SACtD;QACD,SAAS,EAAE;YACT,OAAO,EAAE,KAAK,EAAS,cAAc;YACrC,eAAe,EAAE,EAAE;YACnB,YAAY,EAAE,0BAA0B;SACzC;KACF;IACD,YAAY,EAAE;QACZ,WAAW,EAAE,IAAI,EAAQ,2DAA2D;KACrF;IACD,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,EAAa,oDAAoD;QAC7E,YAAY,EAAE,KAAK,EAAM,gEAAgE;KAC1F;IACD,KAAK,EAAE;QACL,aAAa,EAAE,KAAK,EAAK,yDAAyD;KACnF;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,MAAM,MAAM,GAAG,SAAS,CACtB,cAAoD,EACpD,MAAiC,CACN,CAAC;IAE9B,uCAAuC;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,gBAAgB,CAAC,gBAAgB,CAAC;IACzD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAW,CAAC;IAC5F,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC;QACrC,OAAO,CAAC,KAAK,CACX,8CAA8C,SAAS,iCAAiC,CACzF,CAAC;QACF,MAAM,CAAC,gBAAgB,CAAC,gBAAgB,GAAG,EAAE,GAAG,cAAc,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,CAAC;IACrG,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -2238,7 +2238,9 @@ var ENTITY_COLORS = {
|
|
|
2238
2238
|
concept: '#f59e0b',
|
|
2239
2239
|
pattern: '#10b981',
|
|
2240
2240
|
dependency: '#ef4444',
|
|
2241
|
-
api_endpoint: '#ec4899'
|
|
2241
|
+
api_endpoint: '#ec4899',
|
|
2242
|
+
agent: '#14b8a6',
|
|
2243
|
+
commit: '#a855f7'
|
|
2242
2244
|
};
|
|
2243
2245
|
|
|
2244
2246
|
// Track which entity types are visible (null = all)
|
|
@@ -9,6 +9,7 @@ import type { Embedder } from "../embeddings/embedder.js";
|
|
|
9
9
|
import type { IndexManager } from "../embeddings/index-manager.js";
|
|
10
10
|
import type { SearchEngine, BlackboardSearchResult } from "../embeddings/search.js";
|
|
11
11
|
import type { Archiver } from "./archiver.js";
|
|
12
|
+
import type { GraphAutoPopulator } from "./graph-auto-populator.js";
|
|
12
13
|
export declare class BlackboardEngine {
|
|
13
14
|
private readonly store;
|
|
14
15
|
private readonly embedder;
|
|
@@ -16,9 +17,12 @@ export declare class BlackboardEngine {
|
|
|
16
17
|
private readonly searchEngine;
|
|
17
18
|
private archiver;
|
|
18
19
|
private archiveThreshold;
|
|
20
|
+
private graphPopulator;
|
|
19
21
|
constructor(store: BlackboardStore, embedder?: Embedder | null, indexManager?: IndexManager | null, searchEngine?: SearchEngine | null);
|
|
20
22
|
/** Inject archiver for threshold-based auto-archiving (spec §6.1.3). */
|
|
21
23
|
setArchiver(archiver: Archiver, config: TwiningConfig): void;
|
|
24
|
+
/** Inject graph auto-populator for relation extraction from posts. */
|
|
25
|
+
setGraphPopulator(populator: GraphAutoPopulator): void;
|
|
22
26
|
/** Post a new blackboard entry with validation and defaults. */
|
|
23
27
|
post(input: {
|
|
24
28
|
entry_type: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blackboard.d.ts","sourceRoot":"","sources":["../../src/engine/blackboard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEjE,OAAO,KAAK,EAAE,eAAe,EAAa,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEnF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACpF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"blackboard.d.ts","sourceRoot":"","sources":["../../src/engine/blackboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,6 +13,7 @@ export class BlackboardEngine {
|
|
|
13
13
|
searchEngine;
|
|
14
14
|
archiver = null;
|
|
15
15
|
archiveThreshold = null;
|
|
16
|
+
graphPopulator = null;
|
|
16
17
|
constructor(store, embedder, indexManager, searchEngine) {
|
|
17
18
|
this.store = store;
|
|
18
19
|
this.embedder = embedder ?? null;
|
|
@@ -24,6 +25,10 @@ export class BlackboardEngine {
|
|
|
24
25
|
this.archiver = archiver;
|
|
25
26
|
this.archiveThreshold = config.archive.max_blackboard_entries_before_archive;
|
|
26
27
|
}
|
|
28
|
+
/** Inject graph auto-populator for relation extraction from posts. */
|
|
29
|
+
setGraphPopulator(populator) {
|
|
30
|
+
this.graphPopulator = populator;
|
|
31
|
+
}
|
|
27
32
|
/** Post a new blackboard entry with validation and defaults. */
|
|
28
33
|
async post(input) {
|
|
29
34
|
// Validate entry_type
|
|
@@ -50,6 +55,10 @@ export class BlackboardEngine {
|
|
|
50
55
|
relates_to: input.relates_to,
|
|
51
56
|
agent_id: input.agent_id ?? "main",
|
|
52
57
|
});
|
|
58
|
+
// Auto-populate graph with scope/relation entities (best-effort)
|
|
59
|
+
if (this.graphPopulator) {
|
|
60
|
+
await this.graphPopulator.onPost(entry);
|
|
61
|
+
}
|
|
53
62
|
// Generate embedding (Phase 2) — never let embedding failure prevent the post
|
|
54
63
|
if (this.embedder && this.indexManager) {
|
|
55
64
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blackboard.js","sourceRoot":"","sources":["../../src/engine/blackboard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"blackboard.js","sourceRoot":"","sources":["../../src/engine/blackboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,6 +30,19 @@ export declare class ContextAssembler {
|
|
|
30
30
|
* Implements spec section 4.3 (twining_assemble).
|
|
31
31
|
*/
|
|
32
32
|
assemble(task: string, scope: string, maxTokens?: number, agentId?: string): Promise<AssembledContext>;
|
|
33
|
+
/**
|
|
34
|
+
* Assemble context and include a status summary inline.
|
|
35
|
+
* Combines assemble + summarize into one call (P5.1).
|
|
36
|
+
*/
|
|
37
|
+
assembleWithStatus(task: string, scope: string, maxTokens?: number, agentId?: string): Promise<{
|
|
38
|
+
context: AssembledContext;
|
|
39
|
+
status_summary: string;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Format assembled context as structured markdown for LLM consumption.
|
|
43
|
+
* Produces imperative sentences and numbered lists instead of raw JSON.
|
|
44
|
+
*/
|
|
45
|
+
static formatForLLM(ctx: AssembledContext, statusSummary?: string): string;
|
|
33
46
|
/**
|
|
34
47
|
* High-level summary of project or scope state.
|
|
35
48
|
* Implements spec section 4.3 (twining_summarize).
|
|
@@ -45,7 +58,7 @@ export declare class ContextAssembler {
|
|
|
45
58
|
* Decisions whose affected_files/symbols have more graph relations
|
|
46
59
|
* to the scope get a higher boost (0.0 to 1.0).
|
|
47
60
|
*/
|
|
48
|
-
private
|
|
61
|
+
private computeGraphReachability;
|
|
49
62
|
/**
|
|
50
63
|
* Populate related_entities from the knowledge graph.
|
|
51
64
|
* Finds entities matching the scope and gets their immediate neighbors.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-assembler.d.ts","sourceRoot":"","sources":["../../src/engine/context-assembler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EACV,gBAAgB,EAGhB,eAAe,EACf,aAAa,EACb,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAkB3B,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;IACvD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAE/C,qFAAqF;IACrF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;gBAGvD,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,YAAY,GAAG,IAAI,EACjC,MAAM,EAAE,aAAa,EACrB,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,EAChC,cAAc,CAAC,EAAE,cAAc,GAAG,IAAI,EACtC,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI,EAClC,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI;IAYhC,0EAA0E;IAC1E,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI3C;;;OAGG;IACG,QAAQ,CACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"context-assembler.d.ts","sourceRoot":"","sources":["../../src/engine/context-assembler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EACV,gBAAgB,EAGhB,eAAe,EACf,aAAa,EACb,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAkB3B,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;IACvD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAE/C,qFAAqF;IACrF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;gBAGvD,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,YAAY,GAAG,IAAI,EACjC,MAAM,EAAE,aAAa,EACrB,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,EAChC,cAAc,CAAC,EAAE,cAAc,GAAG,IAAI,EACtC,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI,EAClC,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI;IAYhC,0EAA0E;IAC1E,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI3C;;;OAGG;IACG,QAAQ,CACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,CAAC;IAqX5B;;;OAGG;IACG,kBAAkB,CACtB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,OAAO,EAAE,gBAAgB,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAajE;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,gBAAgB,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM;IAmH1E;;;OAGG;IACG,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IA8EzD;;;OAGG;IACG,WAAW,CACf,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;IAuD7B;;;;OAIG;YACW,wBAAwB;IAsHtC;;;;OAIG;YACW,kBAAkB;IA2ChC,qDAAqD;IACrD,OAAO,CAAC,YAAY;IAMpB,sDAAsD;IACtD,OAAO,CAAC,eAAe;CAYxB"}
|
|
@@ -103,22 +103,29 @@ export class ContextAssembler {
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
-
// 5. Compute graph
|
|
107
|
-
const
|
|
106
|
+
// 5. Compute graph reachability scores for decisions
|
|
107
|
+
const { scores: reachabilityScores, paths: reachabilityPaths } = await this.computeGraphReachability(scope, mergedDecisionMap);
|
|
108
108
|
// 6. Score each item
|
|
109
109
|
const scoredItems = [];
|
|
110
|
-
const graphWeight = weights.graph_connectivity ?? 0;
|
|
110
|
+
const graphWeight = weights.graph_reachability ?? weights.graph_connectivity ?? 0;
|
|
111
|
+
// Adaptive weight fallback: if graph returns 0 for all candidates,
|
|
112
|
+
// redistribute graph weight proportionally to other signals
|
|
113
|
+
const maxGraphScore = Math.max(0, ...Array.from(reachabilityScores.values()));
|
|
114
|
+
const effectiveGraphWeight = maxGraphScore === 0 ? 0 : graphWeight;
|
|
115
|
+
const weightScale = maxGraphScore === 0 && graphWeight > 0
|
|
116
|
+
? 1.0 / (1.0 - graphWeight)
|
|
117
|
+
: 1.0;
|
|
111
118
|
for (const [id, decision] of mergedDecisionMap) {
|
|
112
119
|
const recency = this.recencyScore(decision.timestamp, now);
|
|
113
120
|
const relevance = decisionRelevance.get(id) ?? 0.5;
|
|
114
121
|
const confidence = this.confidenceScore(decision.confidence);
|
|
115
122
|
const warningBoost = 0;
|
|
116
|
-
const
|
|
117
|
-
const score = recency * weights.recency +
|
|
118
|
-
relevance * weights.relevance +
|
|
119
|
-
confidence * weights.decision_confidence +
|
|
120
|
-
warningBoost * weights.warning_boost +
|
|
121
|
-
|
|
123
|
+
const reachability = reachabilityScores.get(id) ?? 0;
|
|
124
|
+
const score = recency * weights.recency * weightScale +
|
|
125
|
+
relevance * weights.relevance * weightScale +
|
|
126
|
+
confidence * weights.decision_confidence * weightScale +
|
|
127
|
+
warningBoost * weights.warning_boost * weightScale +
|
|
128
|
+
reachability * effectiveGraphWeight;
|
|
122
129
|
const text = `${decision.summary} ${decision.rationale} ${decision.confidence} ${decision.affected_files.join(", ")}`;
|
|
123
130
|
scoredItems.push({
|
|
124
131
|
type: "decision",
|
|
@@ -133,10 +140,10 @@ export class ContextAssembler {
|
|
|
133
140
|
const relevance = entryRelevance.get(id) ?? 0.5;
|
|
134
141
|
const confidence = 0.5; // Neutral for non-decisions
|
|
135
142
|
const warningBoost = entry.entry_type === "warning" ? 1.0 : 0.0;
|
|
136
|
-
const score = recency * weights.recency +
|
|
137
|
-
relevance * weights.relevance +
|
|
138
|
-
confidence * weights.decision_confidence +
|
|
139
|
-
warningBoost * weights.warning_boost;
|
|
143
|
+
const score = recency * weights.recency * weightScale +
|
|
144
|
+
relevance * weights.relevance * weightScale +
|
|
145
|
+
confidence * weights.decision_confidence * weightScale +
|
|
146
|
+
warningBoost * weights.warning_boost * weightScale;
|
|
140
147
|
const text = `${entry.summary} ${entry.detail}`;
|
|
141
148
|
scoredItems.push({
|
|
142
149
|
type: entry.entry_type,
|
|
@@ -196,13 +203,18 @@ export class ContextAssembler {
|
|
|
196
203
|
continue;
|
|
197
204
|
if (item.type === "decision") {
|
|
198
205
|
const d = item.data;
|
|
199
|
-
|
|
206
|
+
const decisionEntry = {
|
|
200
207
|
id: d.id,
|
|
201
208
|
summary: d.summary,
|
|
202
209
|
rationale: d.rationale,
|
|
203
210
|
confidence: d.confidence,
|
|
204
211
|
affected_files: d.affected_files,
|
|
205
|
-
}
|
|
212
|
+
};
|
|
213
|
+
const path = reachabilityPaths.get(d.id);
|
|
214
|
+
if (path) {
|
|
215
|
+
decisionEntry.relevance_path = path;
|
|
216
|
+
}
|
|
217
|
+
activeDecisionResults.push(decisionEntry);
|
|
206
218
|
}
|
|
207
219
|
else {
|
|
208
220
|
const e = item.data;
|
|
@@ -300,7 +312,9 @@ export class ContextAssembler {
|
|
|
300
312
|
if (this.handoffStore) {
|
|
301
313
|
const handoffEntries = await this.handoffStore.list({ scope, limit: 5 });
|
|
302
314
|
if (handoffEntries.length > 0) {
|
|
303
|
-
|
|
315
|
+
// Load full records to get individual results for detailed checklist
|
|
316
|
+
const fullHandoffs = await Promise.all(handoffEntries.map((h) => this.handoffStore.get(h.id)));
|
|
317
|
+
result.recent_handoffs = handoffEntries.map((h, i) => ({
|
|
304
318
|
id: h.id,
|
|
305
319
|
source_agent: h.source_agent,
|
|
306
320
|
target_agent: h.target_agent ?? "",
|
|
@@ -309,6 +323,7 @@ export class ContextAssembler {
|
|
|
309
323
|
result_status: h.result_status,
|
|
310
324
|
acknowledged: h.acknowledged,
|
|
311
325
|
created_at: h.created_at,
|
|
326
|
+
results: fullHandoffs[i]?.results,
|
|
312
327
|
}));
|
|
313
328
|
}
|
|
314
329
|
}
|
|
@@ -340,6 +355,125 @@ export class ContextAssembler {
|
|
|
340
355
|
this.assemblyLog.set(agentId ?? "main", result.assembled_at);
|
|
341
356
|
return result;
|
|
342
357
|
}
|
|
358
|
+
/**
|
|
359
|
+
* Assemble context and include a status summary inline.
|
|
360
|
+
* Combines assemble + summarize into one call (P5.1).
|
|
361
|
+
*/
|
|
362
|
+
async assembleWithStatus(task, scope, maxTokens, agentId) {
|
|
363
|
+
const context = await this.assemble(task, scope, maxTokens, agentId);
|
|
364
|
+
// Status summary is best-effort — don't let it break assembly
|
|
365
|
+
let statusSummary = "";
|
|
366
|
+
try {
|
|
367
|
+
const summary = await this.summarize(scope);
|
|
368
|
+
statusSummary = summary.recent_activity_summary;
|
|
369
|
+
}
|
|
370
|
+
catch {
|
|
371
|
+
// Non-fatal: skip status summary if summarize fails
|
|
372
|
+
}
|
|
373
|
+
return { context, status_summary: statusSummary };
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Format assembled context as structured markdown for LLM consumption.
|
|
377
|
+
* Produces imperative sentences and numbered lists instead of raw JSON.
|
|
378
|
+
*/
|
|
379
|
+
static formatForLLM(ctx, statusSummary) {
|
|
380
|
+
// Short-circuit: if there's nothing useful to say, return minimal output
|
|
381
|
+
const hasContent = ctx.active_warnings.length > 0 ||
|
|
382
|
+
ctx.active_decisions.length > 0 ||
|
|
383
|
+
ctx.recent_findings.length > 0 ||
|
|
384
|
+
ctx.open_needs.length > 0 ||
|
|
385
|
+
ctx.recent_questions.length > 0 ||
|
|
386
|
+
(ctx.recent_handoffs && ctx.recent_handoffs.length > 0) ||
|
|
387
|
+
ctx.planning_state != null;
|
|
388
|
+
if (!hasContent) {
|
|
389
|
+
return `No prior context for scope: ${ctx.scope}`;
|
|
390
|
+
}
|
|
391
|
+
const sections = [];
|
|
392
|
+
// Header
|
|
393
|
+
sections.push(`## Before You Start (scope: ${ctx.scope})`);
|
|
394
|
+
// 1. Warnings FIRST — "what not to do" is the most actionable signal
|
|
395
|
+
if (ctx.active_warnings.length > 0) {
|
|
396
|
+
sections.push("\n### STOP — READ THESE WARNINGS");
|
|
397
|
+
for (const w of ctx.active_warnings) {
|
|
398
|
+
sections.push(`- **${w.summary}**${w.detail ? `\n ${w.detail}` : ""}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
// 2. Continue from (handoffs) — second priority, provides continuation context
|
|
402
|
+
if (ctx.recent_handoffs && ctx.recent_handoffs.length > 0) {
|
|
403
|
+
sections.push("\n### CONTINUE FROM PREVIOUS WORK");
|
|
404
|
+
for (const h of ctx.recent_handoffs) {
|
|
405
|
+
const status = h.acknowledged ? "acknowledged" : "pending";
|
|
406
|
+
sections.push(`**${h.source_agent} → ${h.target_agent || "any"}** (${status}): ${h.summary}`);
|
|
407
|
+
// Detailed checklist of individual results
|
|
408
|
+
if (h.results && h.results.length > 0) {
|
|
409
|
+
for (const r of h.results) {
|
|
410
|
+
const icon = r.status === "completed" ? "[x]" : r.status === "blocked" ? "[BLOCKED]" : "[ ]";
|
|
411
|
+
sections.push(` - ${icon} ${r.description}${r.notes ? ` — ${r.notes}` : ""}`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
// 3. Decisions — imperative framing with files prominent
|
|
417
|
+
if (ctx.active_decisions.length > 0) {
|
|
418
|
+
sections.push("\n### DECISIONS TO RESPECT");
|
|
419
|
+
for (let i = 0; i < ctx.active_decisions.length; i++) {
|
|
420
|
+
const d = ctx.active_decisions[i];
|
|
421
|
+
const files = d.affected_files?.length > 0 ? `\n Files: ${d.affected_files.join(", ")}` : "";
|
|
422
|
+
sections.push(`${i + 1}. **${d.summary}** (${d.confidence})${files}`);
|
|
423
|
+
sections.push(` Why: ${d.rationale}`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
else {
|
|
427
|
+
sections.push("\nNo active decisions for this scope.");
|
|
428
|
+
}
|
|
429
|
+
// 4. Open needs — what still needs to be done
|
|
430
|
+
if (ctx.open_needs.length > 0) {
|
|
431
|
+
sections.push("\n### REMAINING WORK");
|
|
432
|
+
for (const n of ctx.open_needs) {
|
|
433
|
+
sections.push(`- [ ] ${n.summary}`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// 5. Recent findings (brief, only if not redundant with decisions)
|
|
437
|
+
if (ctx.recent_findings.length > 0) {
|
|
438
|
+
// Filter out findings whose summary is substantially duplicated by a decision
|
|
439
|
+
const decisionSummaries = ctx.active_decisions.map((d) => d.summary.toLowerCase());
|
|
440
|
+
const uniqueFindings = ctx.recent_findings.filter((f) => {
|
|
441
|
+
const fLower = f.summary.toLowerCase();
|
|
442
|
+
return !decisionSummaries.some((ds) => ds.includes(fLower.slice(0, 30)) || fLower.includes(ds.slice(0, 30)));
|
|
443
|
+
});
|
|
444
|
+
if (uniqueFindings.length > 0) {
|
|
445
|
+
sections.push("\n### FINDINGS");
|
|
446
|
+
for (const f of uniqueFindings) {
|
|
447
|
+
sections.push(`- ${f.summary}`);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
// 6. Quick reference section — compact metadata
|
|
452
|
+
const quickRef = ["\n---"];
|
|
453
|
+
// Status summary (P5.1)
|
|
454
|
+
if (statusSummary) {
|
|
455
|
+
quickRef.push(`Status: ${statusSummary}`);
|
|
456
|
+
}
|
|
457
|
+
// Questions
|
|
458
|
+
if (ctx.recent_questions.length > 0) {
|
|
459
|
+
quickRef.push(`Open questions: ${ctx.recent_questions.map((q) => q.summary).join("; ")}`);
|
|
460
|
+
}
|
|
461
|
+
// Planning state
|
|
462
|
+
if (ctx.planning_state) {
|
|
463
|
+
quickRef.push(`Planning: Phase ${ctx.planning_state.current_phase}, ${ctx.planning_state.progress}`);
|
|
464
|
+
if (ctx.planning_state.blockers.length > 0) {
|
|
465
|
+
quickRef.push(`Blockers: ${ctx.planning_state.blockers.join("; ")}`);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
// Suggested agents
|
|
469
|
+
if (ctx.suggested_agents && ctx.suggested_agents.length > 0) {
|
|
470
|
+
quickRef.push(`Suggested agents: ${ctx.suggested_agents.map((a) => `${a.agent_id} (${a.capabilities.join(", ")})`).join("; ")}`);
|
|
471
|
+
}
|
|
472
|
+
if (quickRef.length > 1) {
|
|
473
|
+
sections.push(quickRef.join("\n"));
|
|
474
|
+
}
|
|
475
|
+
return sections.join("\n");
|
|
476
|
+
}
|
|
343
477
|
/**
|
|
344
478
|
* High-level summary of project or scope state.
|
|
345
479
|
* Implements spec section 4.3 (twining_summarize).
|
|
@@ -443,45 +577,91 @@ export class ContextAssembler {
|
|
|
443
577
|
* Decisions whose affected_files/symbols have more graph relations
|
|
444
578
|
* to the scope get a higher boost (0.0 to 1.0).
|
|
445
579
|
*/
|
|
446
|
-
async
|
|
580
|
+
async computeGraphReachability(scope, decisions) {
|
|
447
581
|
const scores = new Map();
|
|
582
|
+
const paths = new Map();
|
|
448
583
|
if (!this.graphEngine)
|
|
449
|
-
return scores;
|
|
584
|
+
return { scores, paths };
|
|
450
585
|
try {
|
|
451
|
-
// Find entities matching
|
|
586
|
+
// 1. Find entities matching scope, filtered to scope prefix
|
|
452
587
|
const { entities: scopeEntities } = await this.graphEngine.query(scope, undefined, 20);
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
588
|
+
const filteredScopeEntities = scopeEntities.filter((e) => e.name.startsWith(scope) || scope.startsWith(e.name));
|
|
589
|
+
if (filteredScopeEntities.length === 0)
|
|
590
|
+
return { scores, paths };
|
|
591
|
+
// Relation types to follow during BFS
|
|
592
|
+
const followTypes = [
|
|
593
|
+
"depends_on", "decided_by", "implements", "affects", "produces", "challenged",
|
|
594
|
+
];
|
|
595
|
+
// Relation type scoring bonuses
|
|
596
|
+
const relationBonus = {
|
|
597
|
+
decided_by: 1.0,
|
|
598
|
+
affects: 1.0,
|
|
599
|
+
depends_on: 0.8,
|
|
600
|
+
implements: 0.8,
|
|
601
|
+
produces: 0.7,
|
|
602
|
+
challenged: 0.7,
|
|
603
|
+
supersedes: 0.6,
|
|
604
|
+
tested_by: 0.6,
|
|
605
|
+
related_to: 0.5,
|
|
606
|
+
};
|
|
607
|
+
// Path length scoring (indexed by hop count - 1)
|
|
608
|
+
const depthScore = [1.0, 0.7, 0.4];
|
|
609
|
+
// Build set of decision IDs for quick lookup
|
|
610
|
+
const decisionIds = new Set(decisions.keys());
|
|
611
|
+
// 2. For each scope entity, do typed BFS traversal (max depth 3)
|
|
612
|
+
for (const scopeEntity of filteredScopeEntities) {
|
|
613
|
+
try {
|
|
614
|
+
const { neighbors } = await this.graphEngine.neighbors(scopeEntity.id, 3, followTypes);
|
|
615
|
+
for (const neighbor of neighbors) {
|
|
616
|
+
// Check if this neighbor is a decision concept node
|
|
617
|
+
if (neighbor.entity.type === "concept" && decisionIds.has(neighbor.entity.name)) {
|
|
618
|
+
const decisionId = neighbor.entity.name;
|
|
619
|
+
// Determine hop depth from relation (approximate: use relation type)
|
|
620
|
+
// Since neighbors() returns flat results, we estimate depth from the BFS order
|
|
621
|
+
// The relation tells us the connection type
|
|
622
|
+
const relType = neighbor.relation.type;
|
|
623
|
+
const bonus = relationBonus[relType] ?? 0.5;
|
|
624
|
+
// Use depth 0 (1-hop) as default since neighbors are direct or via BFS
|
|
625
|
+
const pathScore = depthScore[0] * bonus;
|
|
626
|
+
// Keep max score across all paths
|
|
627
|
+
const existing = scores.get(decisionId) ?? 0;
|
|
628
|
+
if (pathScore > existing) {
|
|
629
|
+
scores.set(decisionId, pathScore);
|
|
630
|
+
paths.set(decisionId, `${scopeEntity.name} → ${relType} → ${neighbor.entity.name}`);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
// Also check if the neighbor's name matches affected_files of any decision
|
|
634
|
+
for (const [decisionId, decision] of decisions) {
|
|
635
|
+
if (decision.affected_files.includes(neighbor.entity.name) ||
|
|
636
|
+
decision.affected_symbols.includes(neighbor.entity.name)) {
|
|
637
|
+
const relType = neighbor.relation.type;
|
|
638
|
+
const bonus = relationBonus[relType] ?? 0.5;
|
|
639
|
+
const pathScore = depthScore[1] * bonus; // 2-hop equivalent
|
|
640
|
+
const existing = scores.get(decisionId) ?? 0;
|
|
641
|
+
if (pathScore > existing) {
|
|
642
|
+
scores.set(decisionId, pathScore);
|
|
643
|
+
paths.set(decisionId, `${scopeEntity.name} → ${relType} → ${neighbor.entity.name} → decided_by → ${decisionId}`);
|
|
644
|
+
}
|
|
471
645
|
}
|
|
472
646
|
}
|
|
473
647
|
}
|
|
474
648
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
649
|
+
catch {
|
|
650
|
+
// Skip entities that fail to traverse
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
// 3. Normalize scores to 0.0-1.0
|
|
654
|
+
const maxScore = Math.max(0, ...Array.from(scores.values()));
|
|
655
|
+
if (maxScore > 0 && maxScore !== 1.0) {
|
|
656
|
+
for (const [id, score] of scores) {
|
|
657
|
+
scores.set(id, score / maxScore);
|
|
658
|
+
}
|
|
479
659
|
}
|
|
480
660
|
}
|
|
481
661
|
catch {
|
|
482
662
|
// Graph errors should never break scoring
|
|
483
663
|
}
|
|
484
|
-
return scores;
|
|
664
|
+
return { scores, paths };
|
|
485
665
|
}
|
|
486
666
|
/**
|
|
487
667
|
* Populate related_entities from the knowledge graph.
|