opencode-orchestrator 1.2.71 β†’ 1.3.3

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 CHANGED
@@ -9,7 +9,7 @@
9
9
  [![MIT License](https://img.shields.io/badge/license-MIT-red.svg)](LICENSE)
10
10
  [![npm](https://img.shields.io/npm/v/opencode-orchestrator.svg)](https://www.npmjs.com/package/opencode-orchestrator)
11
11
  <!-- VERSION:START -->
12
- **Version:** `1.2.71`
12
+ **Version:** `1.3.3`
13
13
  <!-- VERSION:END -->
14
14
  </div>
15
15
 
@@ -238,6 +238,42 @@ Maintains focus across thousands of conversation turns using a 4-tier memory str
238
238
  - **Diagnostic Intervention**: Forces "Diagnostic Mode" mandating log audits and strategy pivots
239
239
  - **Proactive Agency**: Mandates Speculative Planning during background task execution
240
240
 
241
+ ### 🧬 Knowledge Graph RAG (Second Brain)
242
+ An autonomous **Obsidian-style evolutionary memory system** that gives agents persistent, searchable knowledge across sessions.
243
+
244
+ Runtime context injection is active for orchestrated sessions through `experimental.chat.system.transform`, indexing `docs/**/*.md` and `.opencode/docs/**/*.md` with BM25/tag/graph fusion before prompt injection.
245
+
246
+ ```
247
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
248
+ β”‚ πŸ“ Ingest │────▢│ πŸ” Search │────▢│ 🧠 Recall β”‚
249
+ β”‚ ────────── β”‚ β”‚ ────────── β”‚ β”‚ ────────── β”‚
250
+ β”‚ YAML Parser β”‚ β”‚ BM25 Lexicalβ”‚ β”‚ RRF-Ranked β”‚
251
+ β”‚ Tag HashMap β”‚ β”‚ Tag Index β”‚ β”‚ Top-K Notes β”‚
252
+ β”‚ Wiki-Links β”‚ β”‚ 2-Hop Graph β”‚ β”‚ β†’ Context β”‚
253
+ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
254
+ β”‚
255
+ β–Ό
256
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
257
+ β”‚ πŸ”„ Evolve │────▢│ πŸ›‘οΈ Guard │────▢│ πŸ“¦ Archive β”‚
258
+ β”‚ ────────── β”‚ β”‚ ────────── β”‚ β”‚ ────────── β”‚
259
+ β”‚ Fission β”‚ β”‚ Cycle DFS β”‚ β”‚ Orphan GC β”‚
260
+ β”‚ Fusion β”‚ β”‚ Write FIFO β”‚ β”‚ MOC Hubs β”‚
261
+ β”‚ (Auto-Split β”‚ β”‚ Keep-Pin β”‚ β”‚ MD Export β”‚
262
+ β”‚ & Merge) β”‚ β”‚ Shield β”‚ β”‚ β”‚
263
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
264
+ ```
265
+
266
+ **Six integrated modules** power the knowledge pipeline:
267
+
268
+ | Module | Purpose |
269
+ |:-------|:--------|
270
+ | **TagIndexer** | O(1) YAML frontmatter parsing β†’ tag-to-file HashMap |
271
+ | **GraphParser** | `[[wiki-link]]` extraction, bi-directional adjacency graph |
272
+ | **HybridSearch** | BM25 + Tag + 2-Hop Graph β†’ **Reciprocal Rank Fusion** (k=60) |
273
+ | **Scratchpad** | LRU register cache (64 slots, 4KB max) with markdown persistence |
274
+ | **SafetyGuards** | Circular link DFS, async FIFO write queue, keep-pin shield |
275
+ | **MemoryConsolidation** | Fission/Fusion/GC/MOC β€” pure functional analysis |
276
+
241
277
  ---
242
278
 
243
279
  ## βš™οΈ Performance Benchmarks
@@ -276,6 +312,7 @@ Maintains focus across thousands of conversation turns using a 4-tier memory str
276
312
  - **Memory**: Object pooling + string interning + buffer pooling
277
313
  - **State Management**: MVCC + Mutex
278
314
  - **Safety**: RAII + circuit breaker + resource pressure detection
315
+ - **Knowledge**: In-memory graph RAG with BM25/Tag/Graph search fusion
279
316
 
280
317
  ---
281
318
 
@@ -342,6 +379,7 @@ const task = createParallelTask({ description: "Test" });
342
379
 
343
380
  - [System Architecture Deep-Dive β†’](docs/SYSTEM_ARCHITECTURE.md)
344
381
  - [Developer Notes β†’](docs/DEVELOPERS_NOTE.md)
382
+ - [Knowledge RAG Roadmap β†’](docs/histories/2026/05/31/PLAN_SecondBrainOrchestration_2026-05-31.md)
345
383
 
346
384
  ---
347
385
 
@@ -0,0 +1,8 @@
1
+ export declare class KnowledgeContextProvider {
2
+ buildPrompt(directory: string, query: string): string | null;
3
+ private collectMarkdownFiles;
4
+ private walkDirectory;
5
+ private indexKnowledge;
6
+ private buildSnippet;
7
+ private formatPrompt;
8
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * GraphParser - Bi-directional Obsidian Wiki-Link & Markdown Link Knowledge Graph Parser
3
+ */
4
+ export declare class GraphParser {
5
+ /** Heading marker used for the auto-generated backlinks section */
6
+ static readonly BACKLINKS_HEADING = "## \uD83D\uDD17 Backlinks";
7
+ private forwardLinks;
8
+ private backlinks;
9
+ private noteToPath;
10
+ private pathToNote;
11
+ /**
12
+ * Resolve file path or relative link to a note name (basename without extension).
13
+ */
14
+ getNoteName(filePath: string): string;
15
+ /**
16
+ * Parse content and extract all unique referenced target note names.
17
+ */
18
+ parseLinks(content: string): string[];
19
+ /**
20
+ * Index file and register its bi-directional links.
21
+ */
22
+ indexFile(filePath: string, content: string): void;
23
+ /**
24
+ * Retrieve backlinks for a note name or file path.
25
+ */
26
+ getBacklinks(noteOrPath: string): string[];
27
+ /**
28
+ * Retrieve forward links for a note name or file path.
29
+ */
30
+ getForwardLinks(noteOrPath: string): string[];
31
+ /**
32
+ * Synchronize the ## πŸ”— Backlinks section in a file's content.
33
+ */
34
+ syncBacklinksSection(content: string, backlinksList: string[]): string;
35
+ /**
36
+ * Clear all indexes for a note.
37
+ */
38
+ private clearIndexForNote;
39
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * HybridSearch - Combines lexical (BM25-inspired), tag, and graph search
3
+ * with Reciprocal Rank Fusion to surface the most relevant notes.
4
+ */
5
+ import type { TagIndexer } from "./tag-indexer.js";
6
+ import type { GraphParser } from "./graph-parser.js";
7
+ /** Unified search result with provenance tracking. */
8
+ export interface SearchResult {
9
+ noteName: string;
10
+ score: number;
11
+ matchType: "lexical" | "tag" | "graph";
12
+ }
13
+ export declare class HybridSearch {
14
+ private readonly tagIndexer;
15
+ private readonly graphParser;
16
+ /** Stores indexed note content keyed by note name. */
17
+ private contentMap;
18
+ constructor(tagIndexer: TagIndexer, graphParser: GraphParser);
19
+ /**
20
+ * Register note content for lexical search.
21
+ * Must be called after TagIndexer.indexFile / GraphParser.indexFile.
22
+ */
23
+ indexContent(noteName: string, content: string): void;
24
+ /**
25
+ * Fuse lexical, tag, and graph rankings via RRF to produce a single list.
26
+ */
27
+ search(query: string, maxResults?: number): SearchResult[];
28
+ /**
29
+ * BM25-inspired term-frequency scoring across all indexed documents.
30
+ * Approximates IDF via corpus size and document frequency.
31
+ */
32
+ private lexicalSearch;
33
+ /**
34
+ * Match query terms against the tag index to find tagged notes.
35
+ */
36
+ private tagSearch;
37
+ /**
38
+ * 2-hop graph traversal from tag-matched seed notes to discover related notes.
39
+ */
40
+ private graphSearch;
41
+ /**
42
+ * Depth-limited BFS from a seed note, scoring neighbors by proximity.
43
+ */
44
+ private traverseGraph;
45
+ /**
46
+ * Reciprocal Rank Fusion: combine three ranked lists into a single ranking.
47
+ * Formula: score(d) = Ξ£ 1/(k + rank_i) for each list where d appears.
48
+ */
49
+ private fuseResults;
50
+ /**
51
+ * Accumulate RRF scores from a single ranked list into the fused map.
52
+ * The matchType is set to the source with the highest individual contribution.
53
+ */
54
+ private addRrfScores;
55
+ /** Split query into lowercase tokens for matching. */
56
+ private tokenize;
57
+ /** Count non-overlapping occurrences of a term in text. */
58
+ private countOccurrences;
59
+ /** Average document length across the corpus (character-based). */
60
+ private computeAverageLength;
61
+ /** Number of documents containing the given term. */
62
+ private documentFrequency;
63
+ /** Sort entries by descending score and return the keys in order. */
64
+ private sortByScore;
65
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Knowledge Module - Barrel Export
3
+ *
4
+ * Re-exports all knowledge graph modules (Phase 1-7)
5
+ * for clean module boundary access from the rest of the framework.
6
+ */
7
+ export { TagIndexer } from "./tag-indexer.js";
8
+ export type { FrontmatterData } from "./tag-indexer.js";
9
+ export { GraphParser } from "./graph-parser.js";
10
+ export { HybridSearch } from "./hybrid-search.js";
11
+ export type { SearchResult } from "./hybrid-search.js";
12
+ export { Scratchpad } from "./scratchpad.js";
13
+ export { SafetyGuards } from "./safety-guards.js";
14
+ export type { WriteQueue } from "./safety-guards.js";
15
+ export { MemoryConsolidation } from "./memory-consolidation.js";
@@ -0,0 +1,38 @@
1
+ /**
2
+ * MemoryConsolidation - Pure analysis functions for knowledge-graph maintenance.
3
+ * All methods are side-effect-free: they read from indexes but never mutate state or files.
4
+ */
5
+ import type { TagIndexer } from "./tag-indexer.js";
6
+ import type { GraphParser } from "./graph-parser.js";
7
+ export declare class MemoryConsolidation {
8
+ private readonly tagIndexer;
9
+ private readonly graphParser;
10
+ constructor(tagIndexer: TagIndexer, graphParser: GraphParser);
11
+ /**
12
+ * Find notes whose content exceeds the line-count ceiling.
13
+ * These are candidates for splitting to improve navigability.
14
+ */
15
+ identifyOversizedNotes(contentMap: Map<string, string>, maxLines?: number): string[];
16
+ /**
17
+ * Find notes that have zero forward links AND zero backlinks.
18
+ * Orphan notes are disconnected from the graph and may need linking or removal.
19
+ */
20
+ identifyOrphanNotes(allNotes: string[]): string[];
21
+ /**
22
+ * Find pairs of notes sharing enough tags to warrant merging.
23
+ * Uses TagIndexer.getAllTags() and getFilesWithTag() to build the full picture.
24
+ */
25
+ suggestMerges(threshold?: number): Array<[string, string]>;
26
+ /**
27
+ * Generate a Map of Content markdown listing all notes tagged with the given tag.
28
+ * MOCs serve as navigational hubs in the knowledge graph.
29
+ */
30
+ generateMOC(tag: string): string;
31
+ /**
32
+ * Build a lookup from note name to its set of tags by iterating
33
+ * all known tags in the index and collecting their associated files.
34
+ */
35
+ private buildNoteTagMap;
36
+ /** Count how many tags two sets share. */
37
+ private countSharedTags;
38
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * SafetyGuards - Graph integrity checks and concurrency primitives.
3
+ * Protects knowledge-graph mutations from cycles, races, and accidental deletes.
4
+ */
5
+ import type { GraphParser } from "./graph-parser.js";
6
+ import type { FrontmatterData } from "./tag-indexer.js";
7
+ /**
8
+ * FIFO async write queue that serializes concurrent write operations
9
+ * to prevent data corruption from overlapping file mutations.
10
+ */
11
+ export interface WriteQueue {
12
+ /** Enqueue a write operation; resolves when the operation completes. */
13
+ enqueue(fn: () => Promise<void>): Promise<void>;
14
+ /** Wait for all queued operations to finish. */
15
+ drain(): Promise<void>;
16
+ }
17
+ export declare class SafetyGuards {
18
+ /**
19
+ * Detect circular links from a starting note via depth-limited DFS.
20
+ * Returns true if the start note is reachable from itself within maxDepth hops.
21
+ */
22
+ static checkCircularLinks(graph: GraphParser, startNote: string, maxDepth?: number): boolean;
23
+ /**
24
+ * Create a FIFO write queue that ensures only one write runs at a time.
25
+ * Each enqueued function waits for all prior functions to complete first.
26
+ */
27
+ static createWriteQueue(): WriteQueue;
28
+ /**
29
+ * Check whether a note's frontmatter marks it as pinned (keep: true).
30
+ * Pinned notes should be excluded from pruning and consolidation.
31
+ */
32
+ static isPinned(metadata: FrontmatterData): boolean;
33
+ /**
34
+ * Recursive DFS that returns true when the start note is revisited.
35
+ * Bounded by maxDepth to prevent runaway traversal in dense graphs.
36
+ * Always checks direct neighbors for the start note before applying depth limit.
37
+ */
38
+ private static dfsDetectCycle;
39
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Scratchpad - Volatile key-value register cache for agent working memory.
3
+ * Implements LRU eviction and markdown-based serialization for persistence.
4
+ */
5
+ export declare class Scratchpad {
6
+ /**
7
+ * Ordered map where the most-recently-accessed key moves to the end.
8
+ * Eviction removes from the beginning (least recently used).
9
+ */
10
+ private registers;
11
+ /**
12
+ * Store a value, evicting the least-recently-used entry if at capacity.
13
+ * Values exceeding 4 KB are truncated to enforce size constraints.
14
+ */
15
+ set(key: string, value: string): void;
16
+ /**
17
+ * Retrieve a register value, refreshing its LRU position on access.
18
+ */
19
+ get(key: string): string | undefined;
20
+ /** Return a snapshot copy of all registers. */
21
+ getAll(): Map<string, string>;
22
+ /** Remove a specific register entry. */
23
+ delete(key: string): boolean;
24
+ /** Wipe all register entries. */
25
+ clear(): void;
26
+ /**
27
+ * Export all registers as a markdown document for persistence.
28
+ * Each register becomes a level-2 heading with its value as content.
29
+ */
30
+ serialize(): string;
31
+ /**
32
+ * Import registers from a previously serialized markdown document.
33
+ * Clears existing state before importing to ensure idempotent loads.
34
+ */
35
+ deserialize(content: string): void;
36
+ /** Evict the least-recently-used entry (first key in insertion order). */
37
+ private evictLru;
38
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Interface representing standard Obsidian-style Frontmatter metadata.
3
+ */
4
+ export interface FrontmatterData {
5
+ tags?: string[];
6
+ title?: string;
7
+ keep?: boolean;
8
+ [key: string]: unknown;
9
+ }
10
+ /**
11
+ * Metadata extractor with regular expression fallback when standard parser crashes.
12
+ */
13
+ export declare class TagIndexer {
14
+ private tagMap;
15
+ private fileCache;
16
+ /**
17
+ * Parse frontmatter using regular expressions as a primary safe parser.
18
+ * This avoids library dependencies and provides deterministic error recovery.
19
+ */
20
+ parseFrontmatter(content: string): {
21
+ data: FrontmatterData;
22
+ body: string;
23
+ };
24
+ /**
25
+ * Parse a single YAML line and update data object in-place.
26
+ * Returns the currently active key for block list continuation.
27
+ */
28
+ private parseYamlLine;
29
+ /**
30
+ * Index a single markdown file content dynamically.
31
+ */
32
+ indexFile(filePath: string, fileContent: string): void;
33
+ /**
34
+ * Index a file directly from the filesystem.
35
+ */
36
+ indexFileFromDisk(filePath: string): void;
37
+ /**
38
+ * Get all files associated with a specific tag O(1).
39
+ */
40
+ getFilesWithTag(tag: string): Set<string>;
41
+ /**
42
+ * Get intersection of files containing all specified tags.
43
+ */
44
+ getFilesWithAllTags(tags: string[]): Set<string>;
45
+ /**
46
+ * Get union of files containing any of the specified tags.
47
+ */
48
+ getFilesWithAnyTags(tags: string[]): Set<string>;
49
+ /**
50
+ * Get the cached frontmatter metadata of a file.
51
+ */
52
+ getMetadata(filePath: string): FrontmatterData | undefined;
53
+ /**
54
+ * Return all file paths that have been indexed.
55
+ */
56
+ getIndexedFiles(): string[];
57
+ /**
58
+ * Return all distinct tags currently present across all indexed files.
59
+ */
60
+ getAllTags(): string[];
61
+ /**
62
+ * Remove file references cleanly from tag mappings and metadata cache.
63
+ */
64
+ private clearIndexForFile;
65
+ /**
66
+ * Helper to insert tags atomically.
67
+ */
68
+ private addTagEntry;
69
+ /**
70
+ * Basic scalar value parser for YAML frontmatter fields.
71
+ */
72
+ private parseScalar;
73
+ }