opencodekit 0.18.0 → 0.18.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/dist/index.js CHANGED
@@ -18,7 +18,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
18
18
 
19
19
  //#endregion
20
20
  //#region package.json
21
- var version = "0.18.0";
21
+ var version = "0.18.1";
22
22
 
23
23
  //#endregion
24
24
  //#region src/utils/errors.ts
@@ -220,3 +220,60 @@ Files over ~500 lines become hard to maintain and review. Extract helpers, split
220
220
  - Cite concrete file paths and line numbers for non-trivial claims
221
221
 
222
222
  _Complexity is the enemy. Minimize moving parts._
223
+
224
+ ---
225
+
226
+ ## Memory System
227
+
228
+ 4-tier automated knowledge pipeline backed by SQLite + FTS5 (porter stemming).
229
+
230
+ **Pipeline:** messages → capture → distillations (TF-IDF) → observations (curator) → LTM injection (system.transform)
231
+
232
+ ### Memory Tools
233
+
234
+ ```bash
235
+ # Search observations (FTS5)
236
+ memory-search({ query: "auth" })
237
+
238
+ # Get full observation details
239
+ memory-get({ ids: "42,45" })
240
+
241
+ # Create observation
242
+ observation({ type: "decision", title: "Use JWT", narrative: "..." })
243
+
244
+ # Update memory file
245
+ memory-update({ file: "research/findings", content: "..." })
246
+
247
+ # Read memory file
248
+ memory-read({ file: "research/findings" })
249
+
250
+ # Admin operations
251
+ memory-admin({ operation: "status" })
252
+ memory-admin({ operation: "capture-stats" })
253
+ memory-admin({ operation: "distill-now" })
254
+ memory-admin({ operation: "curate-now" })
255
+ ```
256
+
257
+ ### Session Tools
258
+
259
+ ```bash
260
+ # Search sessions by keyword
261
+ find_sessions({ query: "auth", limit: 5 })
262
+
263
+ # Read session messages
264
+ read_session({ session_id: "abc123" })
265
+ read_session({ session_id: "abc123", focus: "auth" })
266
+ ```
267
+
268
+ ### Directory Structure
269
+
270
+ ```
271
+ .opencode/memory/
272
+ ├── project/ # Tacit knowledge (auto-injected)
273
+ │ ├── user.md # User preferences
274
+ │ ├── tech-stack.md # Framework, constraints
275
+ │ └── gotchas.md # Footguns, warnings
276
+ ├── research/ # Research notes
277
+ ├── handoffs/ # Session handoffs
278
+ └── _templates/ # Document templates
279
+ ```
@@ -47,43 +47,6 @@ Find trustworthy external references quickly and return concise, cited guidance.
47
47
  - Cite every non-trivial claim
48
48
  - Prefer high-signal synthesis over long dumps
49
49
 
50
- ## Source Quality Hierarchy
51
-
52
- | Rank | Source Type | Tiebreaker |
53
- | ---- | ----------------------------------------------------- | ---------------------------------------------- |
54
- | 1 | Official docs/specifications/release notes | Use unless clearly outdated |
55
- | 2 | Library/framework source code and maintained examples | Prefer recent commits |
56
- | 3 | Maintainer-authored technical articles | Check date, prefer <1 year |
57
- | 4 | Community blogs/posts | Use only when higher-ranked sources are absent |
58
-
59
- ## Output
60
-
61
- - Summary (2-5 bullets)
62
- - Recommended approach
63
- - Sources
64
- - Risks/tradeoffs
65
-
66
- # Scout Agent
67
-
68
- **Purpose**: Knowledge seeker — you find the signal in the noise of external information.
69
-
70
- > _"Good research doesn't dump facts; it creates actionable clarity."_
71
-
72
- ## Identity
73
-
74
- You are a read-only research agent. You output concise recommendations backed by verifiable sources only.
75
-
76
- ## Task
77
-
78
- Find trustworthy external references quickly and return concise, cited guidance.
79
-
80
- ## Rules
81
-
82
- - Never modify project files
83
- - Never invent URLs; only use verified links
84
- - Cite every non-trivial claim
85
- - Prefer high-signal synthesis over long dumps
86
-
87
50
  ## Before You Scout
88
51
 
89
52
  - **Verify memory first**: Always check memory-search before external research
@@ -49,7 +49,7 @@ If a handoff exists, read the latest one. It tells you:
49
49
  Also search previous sessions:
50
50
 
51
51
  ```typescript
52
- search_session({ query: "$ARGUMENTS" });
52
+ find_sessions({ query: "$ARGUMENTS" });
53
53
  ```
54
54
 
55
55
  ## Phase 4: Load Artifacts
@@ -40,12 +40,11 @@ skill({ name: "beads" });
40
40
 
41
41
  ## Available Tools
42
42
 
43
- | Tool | Use When |
44
- | --------------- | --------------------------------- |
45
- | `br` | Task status and stats |
46
- | `git` | Git state and history |
47
- | `list_sessions` | Recent sessions |
48
- | `action-queue` | Pending approvals and ready tasks |
43
+ | Tool | Use When |
44
+ | --------------- | --------------------- |
45
+ | `br` | Task status and stats |
46
+ | `git` | Git state and history |
47
+ | `find_sessions` | Recent sessions |
49
48
 
50
49
  ## Phase 1: Gather State (Parallel)
51
50
 
@@ -64,8 +63,7 @@ git log --oneline -5
64
63
  ```
65
64
 
66
65
  ```typescript
67
- list_sessions({ since: "today", limit: 5 });
68
- action - queue({ op: "status" });
66
+ find_sessions({ query: "today", limit: 5 });
69
67
  ```
70
68
 
71
69
  ---
@@ -89,12 +87,7 @@ GIT
89
87
  Recent: [from git log]
90
88
 
91
89
  SESSIONS TODAY
92
- [from list_sessions]
93
-
94
- ACTION QUEUE
95
- Pending approvals: [from action-queue pending_approvals]
96
- Ready tasks: [from action-queue ready_tasks]
97
- Idle workers: [from action-queue idle_workers]
90
+ [from find_sessions]
98
91
  ```
99
92
 
100
93
  ---
Binary file
@@ -6,36 +6,48 @@ Plugins in this directory extend OpenCode with project-specific behavior and too
6
6
 
7
7
  ```text
8
8
  plugin/
9
- ├── memory.ts # Memory DB maintenance + observation toasts
10
- ├── sessions.ts # Session tools (list/read/search/summarize)
11
- ├── compaction.ts # Compaction-time context recovery injection
12
- ├── swarm-enforcer.ts # Beads workflow enforcement and reminders
13
- ├── skill-mcp.ts # Skill-scoped MCP bridge (skill_mcp tools)
9
+ ├── memory.ts # 4-tier automated memory system (capture → distill → curate → inject)
10
+ ├── sessions.ts # Session search tools (find/read)
14
11
  ├── copilot-auth.ts # GitHub Copilot provider/auth integration
15
- ├── lib/
16
- │ ├── memory-db.ts # SQLite + FTS5 memory backend
17
- │ └── notify.ts # Shared notification helpers
18
- └── sdk/ # Copilot SDK adaptation code
12
+ ├── skill-mcp.ts # Skill-scoped MCP bridge (skill_mcp tools)
13
+ └── lib/
14
+ ├── memory-tools.ts # 6 core memory tools (observation, search, get, read, update, timeline)
15
+ ├── memory-admin-tools.ts # Admin tool (memory-admin: 9 operations)
16
+ ├── memory-hooks.ts # All hooks (event, idle, transforms, compaction)
17
+ ├── memory-helpers.ts # Constants, compaction utilities, formatting
18
+ ├── memory-db.ts # Barrel re-export for db/ modules
19
+ ├── capture.ts # message.part.updated → temporal_messages
20
+ ├── distill.ts # TF-IDF extraction, key sentence selection
21
+ ├── curator.ts # Pattern-based knowledge extraction
22
+ ├── context.ts # Token budget enforcement via messages.transform
23
+ ├── inject.ts # Relevance-scored LTM injection via system.transform
24
+ ├── notify.ts # Cross-platform notification helpers
25
+ └── db/
26
+ ├── types.ts # All types + MEMORY_CONFIG
27
+ ├── schema.ts # SQL schema, migrations, DB singleton
28
+ ├── observations.ts # Observation CRUD + FTS5 search
29
+ ├── pipeline.ts # Temporal messages + distillations + relevance scoring
30
+ └── maintenance.ts # Memory files, FTS5, archiving, vacuum
19
31
  ```
20
32
 
21
33
  ## Plugin Responsibilities
22
34
 
23
35
  - `memory.ts`
24
- - Optimizes FTS5 index on idle sessions
25
- - Checkpoints WAL when needed
26
- - Shows toast feedback for observation saves and session errors
36
+ - 4-tier automated knowledge system: temporal_messages → distillations → observations → memory_files
37
+ - Captures messages automatically via `message.part.updated` events
38
+ - Distills sessions on idle (TF-IDF, key sentence extraction)
39
+ - Curates observations from distillations via pattern matching
40
+ - Injects relevant knowledge into system prompt (BM25 _ recency _ confidence scoring)
41
+ - Manages context window via messages.transform (token budget enforcement)
42
+ - Merges compaction logic (beads, handoffs, project memory, knowledge)
43
+ - Provides 7 tools: observation, memory-search, memory-get, memory-read, memory-update, memory-timeline, memory-admin
27
44
 
28
45
  - `sessions.ts`
29
- - Provides custom tools: `list_sessions`, `read_session`, `search_session`, `summarize_session`
30
-
31
- - `compaction.ts`
32
- - Injects session continuity context during compaction
33
- - Pulls memory/project/handoff context and recovery instructions
34
-
35
- - `swarm-enforcer.ts`
36
- - Injects bead state and stage labels into system context
37
- - Warns when implementation starts without a properly started bead
38
- - Reminds to close/sync in-progress work on session idle
46
+ - Provides tools: `find_sessions`, `read_session`
47
+ - Direct SQLite access to OpenCode's session DB
48
+ - Multi-word AND search with relevance ranking
49
+ - 180-day time-bounded search
50
+ - Agentic `nextStep` guidance in results
39
51
 
40
52
  - `skill-mcp.ts`
41
53
  - Loads MCP configs from skills
@@ -48,9 +60,9 @@ plugin/
48
60
 
49
61
  ## Notes
50
62
 
51
- - `notification.ts.bak` is a backup file and not part of the active plugin set.
52
- - Keep plugin documentation aligned with actual files in this directory.
53
- - Prefer shared helpers in `lib/` over duplicated utilities across plugins.
63
+ - OpenCode auto-discovers every `.ts` file in `plugin/` as a plugin keep helper modules in `lib/`
64
+ - Keep plugin documentation aligned with actual files in this directory
65
+ - Prefer shared helpers in `lib/` over duplicated utilities across plugins
54
66
 
55
67
  ## References
56
68
 
@@ -5,7 +5,29 @@ description: Use when persisting learnings, loading previous context, or searchi
5
5
 
6
6
  # Memory System Best Practices
7
7
 
8
- Persistent context that survives across sessions. Uses **SQLite + FTS5** for searchable observations.
8
+ Persistent context that survives across sessions. Uses **4-tier automated knowledge pipeline** backed by SQLite + FTS5.
9
+
10
+ ## Architecture
11
+
12
+ ```
13
+ message.part.updated → capture.ts → temporal_messages
14
+ ↓ (session.idle, 10+ messages)
15
+ distill.ts → distillations (TF-IDF + key sentences)
16
+ ↓ (session.idle)
17
+ curator.ts → observations (pattern-matched)
18
+
19
+ system.transform ← inject.ts ← FTS5 search → scored + packed → system prompt
20
+ messages.transform ← context.ts → token budget enforcement
21
+ ```
22
+
23
+ ### 4 Tiers
24
+
25
+ | Tier | Storage | Populated By | Purpose |
26
+ | ----------------- | ------------- | ------------------- | ------------------------------- |
27
+ | temporal_messages | SQLite | Automatic (capture) | Raw message text, 180-day TTL |
28
+ | distillations | SQLite + FTS5 | Automatic (idle) | TF-IDF compressed sessions |
29
+ | observations | SQLite + FTS5 | Manual + curator | Decisions, bugs, patterns, etc. |
30
+ | memory_files | SQLite | Manual | Static docs, handoffs, research |
9
31
 
10
32
  ## Core Principle
11
33
 
@@ -23,11 +45,11 @@ Always search memory first.
23
45
 
24
46
  ```typescript
25
47
  // Search for relevant past work
26
- memory_search({ query: "<task keywords>", limit: 5 });
27
- memory_search({ query: "bugfix <component>", type: "observations" });
48
+ memory - search({ query: "<task keywords>", limit: 5 });
49
+ memory - search({ query: "bugfix <component>", type: "observations" });
28
50
 
29
51
  // Check recent handoffs
30
- memory_search({ query: "handoff", type: "handoffs", limit: 3 });
52
+ memory - search({ query: "handoff", type: "handoffs", limit: 3 });
31
53
  ```
32
54
 
33
55
  **Why:** Past you already solved this. Don't rediscover.
@@ -38,14 +60,14 @@ Don't fetch full content until you know you need it.
38
60
 
39
61
  ```typescript
40
62
  // 1. Search returns compact index (50-100 tokens per result)
41
- const results = memory_search({ query: "auth patterns" });
63
+ const results = memory - search({ query: "auth patterns" });
42
64
  // Returns: [{id: 42, title: "Auth bug fixed", ...}]
43
65
 
44
66
  // 2. Fetch full details ONLY for relevant IDs
45
- memory_get({ ids: "42,45" });
67
+ memory - get({ ids: "42,45" });
46
68
 
47
69
  // 3. See what led to this decision
48
- memory_timeline({ anchor_id: 42, depth_before: 3 });
70
+ memory - timeline({ anchor_id: 42, depth_before: 3 });
49
71
  ```
50
72
 
51
73
  **Why:** Prevents context bloat. High signal, low noise.
@@ -56,12 +78,13 @@ Create observations for anything non-obvious. Don't wait until the end.
56
78
 
57
79
  ```typescript
58
80
  observation({
59
- type: "pattern", // decision | bugfix | pattern | discovery | warning
81
+ type: "pattern", // decision | bugfix | pattern | discovery | warning | learning
60
82
  title: "Brief description",
61
83
  narrative: "Context and reasoning...",
62
84
  facts: "key, facts, here",
63
85
  concepts: "searchable, keywords",
64
86
  files_modified: "src/file.ts",
87
+ source: "manual", // manual (default) | curator | imported
65
88
  });
66
89
  ```
67
90
 
@@ -79,9 +102,10 @@ observation({
79
102
  Document completion state for future you.
80
103
 
81
104
  ```typescript
82
- memory_update({
83
- file: "handoffs/YYYY-MM-DD-task",
84
- content: `## Completed
105
+ memory -
106
+ update({
107
+ file: "handoffs/YYYY-MM-DD-task",
108
+ content: `## Completed
85
109
  - X
86
110
 
87
111
  ## Blockers
@@ -89,8 +113,8 @@ memory_update({
89
113
 
90
114
  ## Next
91
115
  - Z`,
92
- mode: "append",
93
- });
116
+ mode: "append",
117
+ });
94
118
  ```
95
119
 
96
120
  ---
@@ -99,18 +123,18 @@ memory_update({
99
123
 
100
124
  ### memory-search (Start Here)
101
125
 
102
- Fast FTS5 full-text search. Returns **compact index** for progressive disclosure.
126
+ Fast FTS5 full-text search with porter stemming. Returns **compact index** for progressive disclosure.
103
127
 
104
128
  ```typescript
105
- memory_search({ query: "authentication" });
106
- memory_search({ query: "bugfix", type: "observations", limit: 5 });
107
- memory_search({ query: "session", type: "handoffs" });
108
- memory_search({ query: "patterns", type: "all" }); // Search everything
129
+ memory - search({ query: "authentication" });
130
+ memory - search({ query: "bugfix", type: "observations", limit: 5 });
131
+ memory - search({ query: "session", type: "handoffs" });
132
+ memory - search({ query: "patterns", type: "all" }); // Search everything
109
133
  ```
110
134
 
111
135
  **Search modes:**
112
136
 
113
- - `observations` (default): Search SQLite with FTS5 ranking
137
+ - `observations` (default): Search SQLite with FTS5 BM25 ranking
114
138
  - `handoffs`, `research`, `templates`: Search specific directories
115
139
  - `beads`: Search .beads/artifacts
116
140
  - `all`: Search everything
@@ -120,8 +144,8 @@ memory_search({ query: "patterns", type: "all" }); // Search everything
120
144
  Fetch full observation details after identifying relevant IDs:
121
145
 
122
146
  ```typescript
123
- memory_get({ ids: "42" }); // Single observation
124
- memory_get({ ids: "1,5,10" }); // Multiple observations
147
+ memory - get({ ids: "42" }); // Single observation
148
+ memory - get({ ids: "1,5,10" }); // Multiple observations
125
149
  ```
126
150
 
127
151
  ### memory-timeline (Chronological Context)
@@ -129,7 +153,7 @@ memory_get({ ids: "1,5,10" }); // Multiple observations
129
153
  See what happened before/after a specific observation:
130
154
 
131
155
  ```typescript
132
- memory_timeline({ anchor_id: 42, depth_before: 5, depth_after: 5 });
156
+ memory - timeline({ anchor_id: 42, depth_before: 5, depth_after: 5 });
133
157
  ```
134
158
 
135
159
  ### memory-read (Files)
@@ -137,9 +161,9 @@ memory_timeline({ anchor_id: 42, depth_before: 5, depth_after: 5 });
137
161
  Load project files, handoffs, or templates:
138
162
 
139
163
  ```typescript
140
- memory_read({ file: "project/gotchas" });
141
- memory_read({ file: "handoffs/2024-01-20-phase-1" });
142
- memory_read({ file: "research/auth-patterns" });
164
+ memory - read({ file: "project/gotchas" });
165
+ memory - read({ file: "handoffs/2024-01-20-phase-1" });
166
+ memory - read({ file: "research/auth-patterns" });
143
167
  ```
144
168
 
145
169
  ### memory-update (Files)
@@ -147,13 +171,40 @@ memory_read({ file: "research/auth-patterns" });
147
171
  Save to project files or handoffs:
148
172
 
149
173
  ```typescript
150
- memory_update({
151
- file: "project/gotchas",
152
- content: "### New Gotcha\n\nDescription...",
153
- mode: "append", // or "replace"
154
- });
174
+ memory -
175
+ update({
176
+ file: "project/gotchas",
177
+ content: "### New Gotcha\n\nDescription...",
178
+ mode: "append", // or "replace"
179
+ });
180
+ ```
181
+
182
+ ### memory-admin (Maintenance)
183
+
184
+ ```typescript
185
+ // Check current status (schema, FTS5, counts, DB size)
186
+ memory - admin({ operation: "status" });
187
+
188
+ // Full maintenance (archive >90 days, checkpoint WAL, vacuum)
189
+ memory - admin({ operation: "full" });
190
+
191
+ // Preview what would be archived
192
+ memory - admin({ operation: "archive", older_than_days: 60, dry_run: true });
193
+
194
+ // Capture pipeline stats (temporal messages, distillations, compression)
195
+ memory - admin({ operation: "capture-stats" });
196
+
197
+ // Force distillation for current session
198
+ memory - admin({ operation: "distill-now" });
199
+
200
+ // Force curator run (extract observations from distillations)
201
+ memory - admin({ operation: "curate-now" });
155
202
  ```
156
203
 
204
+ **Automatic:** On session idle — distillation, curation, FTS5 optimize, WAL checkpoint.
205
+
206
+ **Manual:** Run `memory-admin({ operation: "status" })` to check health.
207
+
157
208
  ---
158
209
 
159
210
  ## What Goes Where
@@ -161,24 +212,34 @@ memory_update({
161
212
  ### SQLite (observations)
162
213
 
163
214
  - Events: decisions, bugfixes, patterns discovered
164
- - Searchable via FTS5
215
+ - Searchable via FTS5 with porter stemming
216
+ - Created manually via `observation()` or automatically by curator
165
217
  - Use `observation()` to create
166
218
 
219
+ ### SQLite (distillations — automatic)
220
+
221
+ - Compressed session summaries with TF-IDF terms
222
+ - Created automatically when 10+ messages accumulate
223
+ - Searchable via FTS5
224
+ - Used for relevance-scored LTM injection
225
+
167
226
  ### Markdown Files
168
227
 
169
228
  - Static knowledge: user preferences, tech stack
170
229
  - Handoffs: session summaries
171
230
  - Research: deep-dive documents
172
- - Use `memory_read()` / `memory_update()`
173
-
174
- | Location | Content | Tool |
175
- | -------------------------- | -------------------------- | --------------------------------- |
176
- | `project/user.md` | User identity, preferences | `memory_read()` |
177
- | `project/tech-stack.md` | Frameworks, constraints | `memory_read()` |
178
- | `project/gotchas.md` | Footguns, warnings | `memory_update({mode: "append"})` |
179
- | `handoffs/YYYY-MM-DD-*.md` | Session summaries | `memory_update()` |
180
- | `research/*.md` | Deep-dive analysis | `memory_update()` |
181
- | SQLite | Observations, events | `observation()` |
231
+ - Use `memory-read()` / `memory-update()`
232
+
233
+ | Location | Content | Tool |
234
+ | -------------------------- | -------------------------- | ----------------------------------- |
235
+ | `project/user.md` | User identity, preferences | `memory-read()` |
236
+ | `project/tech-stack.md` | Frameworks, constraints | `memory-read()` |
237
+ | `project/gotchas.md` | Footguns, warnings | `memory-update({ mode: "append" })` |
238
+ | `handoffs/YYYY-MM-DD-*.md` | Session summaries | `memory-update()` |
239
+ | `research/*.md` | Deep-dive analysis | `memory-update()` |
240
+ | SQLite observations | Events, decisions | `observation()` |
241
+ | SQLite distillations | Session summaries | Automatic (idle) or `distill-now` |
242
+ | SQLite temporal_messages | Raw captured text | Automatic (message events) |
182
243
 
183
244
  ---
184
245
 
@@ -195,6 +256,7 @@ observation({
195
256
  files_read: "src/auth.ts, src/middleware.ts",
196
257
  files_modified: "src/auth.ts",
197
258
  bead_id: "br-abc123", // Link to task (optional)
259
+ source: "manual", // manual (default), curator, imported
198
260
  });
199
261
  ```
200
262
 
@@ -213,25 +275,6 @@ observation({
213
275
 
214
276
  ---
215
277
 
216
- ## Maintenance
217
-
218
- ```typescript
219
- // Check current status
220
- memory_admin({ operation: "status" });
221
-
222
- // Full maintenance (archive >90 days, checkpoint WAL, vacuum)
223
- memory_admin({ operation: "full" });
224
-
225
- // Preview what would be archived
226
- memory_admin({ operation: "archive", older_than_days: 60, dry_run: true });
227
- ```
228
-
229
- **Automatic:** Runs at session end (FTS5 optimize, WAL checkpoint if >1MB)
230
-
231
- **Manual:** Run monthly or when storage grows
232
-
233
- ---
234
-
235
278
  ## Philosophy
236
279
 
237
280
  **Memory is not a dumping ground. It's curated signal.**
@@ -19,48 +19,35 @@ The environment monitors context usage and warns at these thresholds:
19
19
 
20
20
  ## Session Tools
21
21
 
22
- ### list_sessions
22
+ ### find_sessions
23
23
 
24
- Discover available sessions before reading:
24
+ Search and discover sessions by keyword. Returns ranked results with match counts and snippets.
25
25
 
26
26
  ```typescript
27
- list_sessions({ limit: 10, project: "current" }); // Current project
28
- list_sessions({ since: "today" }); // Today's sessions
29
- list_sessions({ project: "all", since: "yesterday" }); // Cross-project
27
+ find_sessions({ query: "auth bug", limit: 5 }); // Search by keyword
28
+ find_sessions({ query: "refactor" }); // Default limit
30
29
  ```
31
30
 
32
- ### read_session
31
+ **Parameters:**
33
32
 
34
- Pull context from previous session:
33
+ - `query` (required): Search keywords — multi-word queries use AND matching
34
+ - `limit` (optional): Max results to return
35
35
 
36
- ```typescript
37
- read_session("last"); // Most recent
38
- read_session("2 ago", { project: "current" }); // 2nd most recent
39
- read_session("today"); // Today's first session
40
- read_session("ses_abc123", { focus: "file changes" }); // Specific aspect
41
- ```
36
+ **Returns:** Ranked sessions with match count, snippets, and suggested next steps.
42
37
 
43
- ### search_session
38
+ ### read_session
44
39
 
45
- Full-text search across sessions:
40
+ Read messages from a specific session. Supports optional focus filtering.
46
41
 
47
42
  ```typescript
48
- search_session({ query: "auth bug" }); // Search all sessions
49
- search_session({ query: "OAuth", session_id: "ses_abc" }); // Specific session
50
- search_session({ query: "error", limit: 10 }); // Limit results
43
+ read_session({ session_id: "ses_abc123" }); // Full session
44
+ read_session({ session_id: "ses_abc123", focus: "auth" }); // Filter to relevant messages
51
45
  ```
52
46
 
53
- Use to find past discussions, decisions, or work on a topic before starting new work.
54
-
55
- ### summarize_session
56
-
57
- Generate AI summary of a session:
58
-
59
- ```typescript
60
- summarize_session("ses_abc123"); // Trigger AI summarization
61
- ```
47
+ **Parameters:**
62
48
 
63
- Use before `read_session` to get a quick overview of what happened in a past session without loading full context.
49
+ - `session_id` (required): Session ID from find_sessions results
50
+ - `focus` (optional): Keyword to filter messages within the session
64
51
 
65
52
  ## When to Start New Session
66
53
 
@@ -74,11 +61,11 @@ Use before `read_session` to get a quick overview of what happened in a past ses
74
61
  ```
75
62
  Session 1: Implement feature X (80k tokens)
76
63
  ↓ close, update memory
77
- Session 2: list_sessions() → read_session("last") → Refactor (60k tokens)
64
+ Session 2: find_sessions({ query: "feature X" }) → read_session(...) → Refactor (60k tokens)
78
65
 
79
- Session 3: read_session("previous") → Add tests (90k tokens)
66
+ Session 3: find_sessions({ query: "feature X" }) → Add tests (90k tokens)
80
67
 
81
- Session 4: read_session refs → Final review (100k tokens)
68
+ Session 4: read_session(...) → Final review (100k tokens)
82
69
  ```
83
70
 
84
71
  **Result**: 4 fresh contexts vs 1 degraded 330k context. Better performance, lower cost.
@@ -87,10 +74,10 @@ Session 4: read_session refs → Final review (100k tokens)
87
74
 
88
75
  Use all available sources:
89
76
 
90
- 1. `read_session("last")` - Previous session work
91
- 2. Git state - `git diff`, `git log` - Code changes
92
- 3. Memory files - `.opencode/memory/*` - Persistent context
93
- 4. Beads - `br show <id>` - Task specs
77
+ 1. `find_sessions` + `read_session` Previous session work
78
+ 2. Git state `git diff`, `git log` Code changes
79
+ 3. Memory files `.opencode/memory/*` Persistent context
80
+ 4. Beads `br show <id>` Task specs
94
81
 
95
82
  **Don't**: Carry everything forward. Extract what's needed, discard the rest.
96
83
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencodekit",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "description": "CLI tool for bootstrapping and managing OpenCodeKit projects",
5
5
  "keywords": ["agents", "cli", "mcp", "opencode", "opencodekit", "template"],
6
6
  "license": "MIT",
@@ -1,190 +0,0 @@
1
- /**
2
- * Session Continuity Plugin (compaction-time context injection)
3
- *
4
- * Purpose:
5
- * - Provide compact, bounded state needed to resume work after compaction.
6
- * - Keep injected prompt guidance minimal and deterministic.
7
- *
8
- * Non-goals:
9
- * - Replace DCP policy/rules management.
10
- * - Inject large free-form manuals into the prompt.
11
- */
12
-
13
- import { Database } from "bun:sqlite";
14
- import { readFile, readdir, stat } from "node:fs/promises";
15
- import path from "node:path";
16
- import type { Plugin } from "@opencode-ai/plugin";
17
-
18
- const MAX_SESSION_CONTEXT_CHARS = 3000;
19
- const MAX_PROJECT_FILES = 3;
20
- const MAX_PROJECT_FILE_CHARS = 900;
21
- const MAX_HANDOFF_CHARS = 2500;
22
- const MAX_BEADS = 8;
23
- const MAX_COMBINED_CONTEXT_CHARS = 9000;
24
-
25
- interface BeadRow {
26
- id: string;
27
- title: string;
28
- }
29
-
30
- function truncate(text: string, maxChars: number): string {
31
- if (text.length <= maxChars) return text;
32
- return `${text.slice(0, maxChars)}\n...[truncated]`;
33
- }
34
-
35
- async function safeReadFile(filePath: string): Promise<string> {
36
- try {
37
- return await readFile(filePath, "utf-8");
38
- } catch {
39
- return "";
40
- }
41
- }
42
-
43
- function renderSection(title: string, body: string): string {
44
- if (!body.trim()) return "";
45
- return `## ${title}\n${body.trim()}`;
46
- }
47
-
48
- async function readProjectMemoryContext(memoryDir: string): Promise<string> {
49
- const projectDir = path.join(memoryDir, "project");
50
- let names: string[] = [];
51
- try {
52
- names = (await readdir(projectDir))
53
- .filter((name) => name.endsWith(".md"))
54
- .sort()
55
- .slice(0, MAX_PROJECT_FILES);
56
- } catch {
57
- return "";
58
- }
59
-
60
- const chunks: string[] = [];
61
- for (const name of names) {
62
- const fullPath = path.join(projectDir, name);
63
- const content = (await safeReadFile(fullPath)).trim();
64
- if (!content) continue;
65
- chunks.push(
66
- `### ${name.replace(/\.md$/, "")}\n${truncate(content, MAX_PROJECT_FILE_CHARS)}`,
67
- );
68
- }
69
-
70
- return chunks.join("\n\n");
71
- }
72
-
73
- async function readLatestHandoff(handoffDir: string): Promise<string> {
74
- let names: string[] = [];
75
- try {
76
- names = (await readdir(handoffDir)).filter((name) => name.endsWith(".md"));
77
- } catch {
78
- return "";
79
- }
80
-
81
- if (names.length === 0) return "";
82
-
83
- const withMtime = await Promise.all(
84
- names.map(async (name) => {
85
- const fullPath = path.join(handoffDir, name);
86
- try {
87
- const info = await stat(fullPath);
88
- return { name, fullPath, mtimeMs: info.mtimeMs };
89
- } catch {
90
- return { name, fullPath, mtimeMs: 0 };
91
- }
92
- }),
93
- );
94
-
95
- withMtime.sort((a, b) => b.mtimeMs - a.mtimeMs);
96
- const latest = withMtime[0];
97
- const content = (await safeReadFile(latest.fullPath)).trim();
98
- if (!content) return "";
99
-
100
- return `Source: ${latest.name}\n${truncate(content, MAX_HANDOFF_CHARS)}`;
101
- }
102
-
103
- /**
104
- * Read in-progress beads directly from SQLite database.
105
- * Cross-platform alternative to shell command execution.
106
- */
107
- function readInProgressBeads(directory: string): string {
108
- const dbPath = path.join(directory, ".beads", "beads.db");
109
- let db: Database | undefined;
110
-
111
- try {
112
- db = new Database(dbPath, { readonly: true });
113
-
114
- const rows = db
115
- .query<BeadRow, [number]>(
116
- "SELECT id, title FROM issues WHERE status = 'in_progress' ORDER BY updated_at DESC LIMIT ?",
117
- )
118
- .all(MAX_BEADS);
119
-
120
- if (rows.length === 0) return "";
121
-
122
- return rows.map((row) => `- ${row.id}: ${row.title}`).join("\n");
123
- } catch {
124
- // Database may not exist, be locked, or have different schema
125
- // Return empty string to allow graceful degradation
126
- return "";
127
- } finally {
128
- db?.close();
129
- }
130
- }
131
-
132
- export const CompactionPlugin: Plugin = async ({ directory }) => {
133
- const memoryDir = path.join(directory, ".opencode", "memory");
134
- const handoffDir = path.join(memoryDir, "handoffs");
135
-
136
- return {
137
- "experimental.session.compacting": async (_input, output) => {
138
- const sessionContext = truncate(
139
- (await safeReadFile(path.join(memoryDir, "session-context.md"))).trim(),
140
- MAX_SESSION_CONTEXT_CHARS,
141
- );
142
-
143
- const [projectContext, handoffContext] = await Promise.all([
144
- readProjectMemoryContext(memoryDir),
145
- readLatestHandoff(handoffDir),
146
- ]);
147
-
148
- // Synchronous SQLite query - no async/await needed
149
- const beadsContext = readInProgressBeads(directory);
150
-
151
- const combined = [
152
- renderSection("Session Continuity", sessionContext),
153
- renderSection("Active Beads", beadsContext),
154
- renderSection("Previous Handoff", handoffContext),
155
- renderSection("Project Memory", projectContext),
156
- ]
157
- .filter(Boolean)
158
- .join("\n\n");
159
-
160
- if (combined) {
161
- output.context.push(
162
- `## Session Context\n${truncate(combined, MAX_COMBINED_CONTEXT_CHARS)}\n`,
163
- );
164
- }
165
-
166
- output.prompt = `${output.prompt}
167
-
168
- <compaction_task>
169
- Summarize conversation state for reliable continuation after compaction.
170
- </compaction_task>
171
-
172
- <compaction_rules>
173
- - Preserve exact IDs, file paths, and unresolved constraints.
174
- - Distinguish completed work from current in-progress work.
175
- - Keep summary concise and execution-focused.
176
- - If critical context is missing, state uncertainty explicitly.
177
- </compaction_rules>
178
-
179
- <compaction_output>
180
- Include:
181
- - What was done
182
- - What is being worked on now
183
- - Files currently in play
184
- - Next actions
185
- - Persistent user constraints/preferences
186
- </compaction_output>
187
- `;
188
- },
189
- };
190
- };