mirror of
https://github.com/sdwolf4103/opencode-working-memory.git
synced 2026-07-17 12:56:42 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bb929fc578 | |||
| 98e5ecaa91 | |||
| c008fb860f | |||
| c743ddb331 | |||
| 0631286962 | |||
| 75c89747d8 |
@@ -18,11 +18,9 @@ Stop losing context across compactions. Stop watching your agent repeat the same
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### For Humans
|
**Option A: Let an AI agent do it**
|
||||||
|
|
||||||
**Option A: Let an LLM do it**
|
Paste this into any AI agent:
|
||||||
|
|
||||||
Paste this into Claude Code, Cursor, or any AI agent:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
Install opencode-working-memory plugin by following:
|
Install opencode-working-memory plugin by following:
|
||||||
@@ -31,7 +29,7 @@ https://raw.githubusercontent.com/sdwolf4103/opencode-working-memory/main/docs/i
|
|||||||
|
|
||||||
**Option B: Manual setup**
|
**Option B: Manual setup**
|
||||||
|
|
||||||
1. Add to your `~/.config/opencode/opencode.json`:
|
Add to your `~/.config/opencode/opencode.json`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -39,42 +37,33 @@ https://raw.githubusercontent.com/sdwolf4103/opencode-working-memory/main/docs/i
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Restart OpenCode
|
Restart OpenCode. The plugin is downloaded and installed automatically.
|
||||||
|
|
||||||
That's it! The plugin is now active.
|
|
||||||
|
|
||||||
### For LLM Agents
|
### For LLM Agents
|
||||||
|
|
||||||
1. Read the OpenCode configuration file at `~/.config/opencode/opencode.json`
|
1. Edit `~/.config/opencode/opencode.json`
|
||||||
2. Add `"opencode-working-memory"` to the `plugin` array
|
2. Add `"opencode-working-memory"` to the `plugin` array
|
||||||
3. Verify installation by checking the config file
|
3. Verify the config file was saved correctly
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
The plugin works automatically once installed. No configuration needed.
|
The plugin works automatically once installed. No configuration needed.
|
||||||
|
|
||||||
**Use the tools:**
|
**Try telling your agent:**
|
||||||
|
|
||||||
```bash
|
|
||||||
# Update persistent memory
|
|
||||||
opencode run "use core_memory_update to set my goal"
|
|
||||||
|
|
||||||
# Read current memory state
|
|
||||||
opencode run "use core_memory_read to show me what you remember"
|
|
||||||
|
|
||||||
# Add important items to working memory
|
|
||||||
opencode run "use working_memory_add to remember this file path"
|
|
||||||
```
|
```
|
||||||
|
Use core_memory_update to set my current goal
|
||||||
**The agent will automatically:**
|
```
|
||||||
- Track memory pressure and warn when approaching compaction
|
```
|
||||||
- Preserve important context during compaction
|
Use core_memory_read to show me what you remember
|
||||||
- Clean up old tool-output cache files every 20 tool calls
|
```
|
||||||
- Remove artifacts when sessions are deleted
|
```
|
||||||
|
Use working_memory_add to remember this file path
|
||||||
|
```
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### 🧠 Core Memory (Phase 1)
|
### 🧠 Core Memory
|
||||||
|
|
||||||
Persistent blocks that survive conversation resets:
|
Persistent blocks that survive conversation resets:
|
||||||
|
|
||||||
@@ -82,7 +71,7 @@ Persistent blocks that survive conversation resets:
|
|||||||
- **progress** (2000 chars) - What's done, in-progress, next steps
|
- **progress** (2000 chars) - What's done, in-progress, next steps
|
||||||
- **context** (1500 chars) - Key file paths, conventions, patterns
|
- **context** (1500 chars) - Key file paths, conventions, patterns
|
||||||
|
|
||||||
### 💡 Working Memory (Phase 3)
|
### 💡 Working Memory
|
||||||
|
|
||||||
Auto-extracts and ranks important information:
|
Auto-extracts and ranks important information:
|
||||||
|
|
||||||
@@ -91,7 +80,7 @@ Auto-extracts and ranks important information:
|
|||||||
- Exponential decay keeps memory fresh
|
- Exponential decay keeps memory fresh
|
||||||
- FIFO limits prevent bloat
|
- FIFO limits prevent bloat
|
||||||
|
|
||||||
### 🎯 Memory Pressure Monitoring (Phase 4)
|
### 🎯 Memory Pressure Monitoring
|
||||||
|
|
||||||
Real-time token tracking from session database:
|
Real-time token tracking from session database:
|
||||||
|
|
||||||
@@ -99,16 +88,15 @@ Real-time token tracking from session database:
|
|||||||
- Proactive intervention messages when pressure is high
|
- Proactive intervention messages when pressure is high
|
||||||
- Pressure-aware smart pruning (adapts compression based on pressure)
|
- Pressure-aware smart pruning (adapts compression based on pressure)
|
||||||
|
|
||||||
### 🧹 Storage Governance (Phase 5)
|
### 🧹 Storage Governance
|
||||||
|
|
||||||
Prevents unbounded disk growth:
|
Prevents unbounded disk growth:
|
||||||
|
|
||||||
- **Layer 1**: Auto-cleanup on session deletion (all artifacts removed)
|
- Auto-cleanup on session deletion (all artifacts removed)
|
||||||
- **Layer 2**: Active cache management (max 300 files/session, 7-day TTL)
|
- Active cache management (max 300 files/session, 7-day TTL)
|
||||||
- Triggers every 20 tool calls
|
|
||||||
- Silent background operation
|
- Silent background operation
|
||||||
|
|
||||||
### 📊 Smart Pruning (Phase 2)
|
### 📊 Smart Pruning
|
||||||
|
|
||||||
Intelligent tool output compression:
|
Intelligent tool output compression:
|
||||||
|
|
||||||
@@ -190,28 +178,7 @@ The plugin exposes these tools to your OpenCode agent:
|
|||||||
|
|
||||||
## Configuration (Optional)
|
## Configuration (Optional)
|
||||||
|
|
||||||
The plugin works great with zero configuration. But if you want to customize:
|
The plugin works great with zero configuration. To customize behavior, modify the constants at the top of `index.ts`. See the [Configuration Guide](docs/configuration.md) for all tunable options.
|
||||||
|
|
||||||
Create `~/.config/opencode/working-memory.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"storage_governance": {
|
|
||||||
"tool_output_max_files": 300,
|
|
||||||
"tool_output_max_age_ms": 604800000,
|
|
||||||
"sweep_interval": 20
|
|
||||||
},
|
|
||||||
"memory_pressure": {
|
|
||||||
"thresholds": {
|
|
||||||
"moderate": 0.75,
|
|
||||||
"high": 0.90,
|
|
||||||
"critical": 0.95
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
See [Configuration Guide](docs/configuration.md) for all options.
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
@@ -223,20 +190,17 @@ See [Configuration Guide](docs/configuration.md) for all options.
|
|||||||
|
|
||||||
MIT License - see [LICENSE](LICENSE) file for details.
|
MIT License - see [LICENSE](LICENSE) file for details.
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Contributions welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) first.
|
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
- 📖 [Documentation](docs/)
|
- 📖 [Documentation](docs/)
|
||||||
- 🐛 [Report Issues](https://github.com/sdwolf4103/opencode-working-memory/issues)
|
- 🐛 [Report Issues](https://github.com/sdwolf4103/opencode-working-memory/issues)
|
||||||
- 💬 [Discussions](https://github.com/sdwolf4103/opencode-working-memory/discussions)
|
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
Inspired by the needs of real-world OpenCode usage and built to solve actual pain points in AI-assisted development.
|
Inspired by the needs of real-world OpenCode usage and built to solve actual pain points in AI-assisted development.
|
||||||
|
|
||||||
|
> This project is not affiliated with or endorsed by the OpenCode team.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Made with ❤️ for the OpenCode community**
|
**Made with ❤️ for the OpenCode community**
|
||||||
|
|||||||
@@ -68,9 +68,8 @@ const POOL_MAX_ITEMS = 50; // Hard limit on pool size
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const PRESSURE_THRESHOLDS = {
|
const PRESSURE_THRESHOLDS = {
|
||||||
moderate: 70, // Warning appears in system prompt
|
moderate: 75, // Warning appears in system prompt
|
||||||
high: 85, // Aggressive pruning activates
|
high: 90, // Aggressive pruning activates + intervention sent
|
||||||
critical: 95, // Intervention sent to agent
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+22
-82
@@ -1,90 +1,34 @@
|
|||||||
# Installation Guide
|
# Installation Guide
|
||||||
|
|
||||||
## Prerequisites
|
## Quick Install
|
||||||
|
|
||||||
- **OpenCode** 1.0.0 or higher
|
Add to your `~/.config/opencode/opencode.json`:
|
||||||
- **Node.js** 18+ (for development only)
|
|
||||||
|
|
||||||
## Quick Install (For Users)
|
|
||||||
|
|
||||||
### Option 1: Install from npm (Recommended)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install opencode-working-memory
|
|
||||||
```
|
|
||||||
|
|
||||||
Then add to your `.opencode/package.json`:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"plugins": [
|
"plugin": ["opencode-working-memory"]
|
||||||
"opencode-working-memory"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Option 2: Install from GitHub
|
Restart OpenCode. The plugin is downloaded and installed automatically — no `npm install` needed.
|
||||||
|
|
||||||
Add to your `.opencode/package.json`:
|
> **Note**: The correct key is `plugin` (singular), not `plugins`.
|
||||||
|
|
||||||
```json
|
## For LLM Agents
|
||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"opencode-working-memory": "github:sdwolf4103/opencode-working-memory"
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
"opencode-working-memory"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then run:
|
1. Edit `~/.config/opencode/opencode.json`
|
||||||
|
2. Add `"opencode-working-memory"` to the `plugin` array
|
||||||
```bash
|
3. Verify the config file was saved correctly
|
||||||
cd .opencode
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option 3: Local Development Install
|
|
||||||
|
|
||||||
Clone the repository:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/sdwolf4103/opencode-working-memory.git
|
|
||||||
cd opencode-working-memory
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
Link to your OpenCode project:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /path/to/your/project/.opencode
|
|
||||||
npm link /path/to/opencode-working-memory
|
|
||||||
```
|
|
||||||
|
|
||||||
Add to `.opencode/package.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"plugins": [
|
|
||||||
"opencode-working-memory"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
After installation, start an OpenCode session and run:
|
After restarting OpenCode, ask your agent:
|
||||||
|
|
||||||
```
|
```
|
||||||
core_memory_update goal "Test installation"
|
Use core_memory_read to show me what you remember
|
||||||
```
|
```
|
||||||
|
|
||||||
You should see a success message. Check `.opencode/memory-core/` for the session file.
|
If the tool responds, the plugin is active.
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
The plugin works out-of-the-box with sensible defaults. For advanced configuration, see [configuration.md](./configuration.md).
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
@@ -92,10 +36,10 @@ The plugin works out-of-the-box with sensible defaults. For advanced configurati
|
|||||||
|
|
||||||
**Symptom**: No `core_memory_update` tool available
|
**Symptom**: No `core_memory_update` tool available
|
||||||
|
|
||||||
**Solution**:
|
**Solution**:
|
||||||
1. Check `.opencode/package.json` includes plugin in `"plugins": []` array
|
1. Check `~/.config/opencode/opencode.json` uses `"plugin"` (not `"plugins"`)
|
||||||
2. Verify `npm install` completed successfully
|
2. Restart OpenCode to trigger automatic installation
|
||||||
3. Restart OpenCode session
|
3. Check OpenCode logs for any download errors
|
||||||
|
|
||||||
### Memory Files Not Created
|
### Memory Files Not Created
|
||||||
|
|
||||||
@@ -103,26 +47,22 @@ The plugin works out-of-the-box with sensible defaults. For advanced configurati
|
|||||||
|
|
||||||
**Solution**:
|
**Solution**:
|
||||||
1. Ensure OpenCode has write permissions in project directory
|
1. Ensure OpenCode has write permissions in project directory
|
||||||
2. Check plugin hooks are registered (look for "Working Memory Plugin" in session logs)
|
2. Trigger memory operations (e.g., use `core_memory_update` tool)
|
||||||
3. Trigger memory operations (e.g., use `core_memory_update` tool)
|
|
||||||
|
|
||||||
### Type Errors During Development
|
### Type Errors During Development
|
||||||
|
|
||||||
**Symptom**: TypeScript errors when modifying plugin
|
**Symptom**: TypeScript errors when modifying the plugin source
|
||||||
|
|
||||||
**Solution**:
|
**Solution**:
|
||||||
1. Ensure `@opencode-ai/plugin` is installed: `npm install @opencode-ai/plugin`
|
1. Run `npm install` to install dev dependencies
|
||||||
2. Run type checking: `npx tsc --noEmit`
|
2. Run `npm run typecheck` to check for errors
|
||||||
3. See [AGENTS.md](../AGENTS.md) for code style guidelines
|
3. See [AGENTS.md](../AGENTS.md) for code style guidelines
|
||||||
|
|
||||||
## Uninstallation
|
## Uninstallation
|
||||||
|
|
||||||
```bash
|
Remove `"opencode-working-memory"` from the `plugin` array in `~/.config/opencode/opencode.json`.
|
||||||
cd .opencode
|
|
||||||
npm uninstall opencode-working-memory
|
|
||||||
```
|
|
||||||
|
|
||||||
Remove from `.opencode/package.json` plugins array. Memory files in `.opencode/memory-*` will persist unless manually deleted.
|
Memory files in `.opencode/memory-*` will persist unless manually deleted.
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* Working Memory Plugin for OpenCode
|
* Working Memory Plugin for OpenCode
|
||||||
*
|
*
|
||||||
* Provides a three-tier memory system to delay/avoid compaction:
|
* Four-tier memory architecture:
|
||||||
* 1. Core Memory - Persistent goal/progress/context blocks (always in-context)
|
* 1. Core Memory - Persistent goal/progress/context blocks (always in-context)
|
||||||
* 2. Working Memory - Auto-managed session-relevant information
|
* 2. Working Memory - Auto-managed session-relevant information
|
||||||
* 3. Smart Pruning - Content-aware tool output compression
|
* 3. Smart Pruning - Content-aware tool output compression
|
||||||
* 4. Memory Pressure Monitoring - Context usage tracking with adaptive warnings
|
* 4. Memory Pressure Monitoring - Context usage tracking with adaptive warnings
|
||||||
*
|
|
||||||
* Phase 1: Core Memory Foundation (MVP) - ✅ COMPLETED
|
|
||||||
* Phase 2: Smart Pruning System - ✅ COMPLETED
|
|
||||||
* Phase 3: Working Memory Auto-Management - ✅ COMPLETED
|
|
||||||
* Phase 4: Memory Pressure Monitoring - ✅ COMPLETED
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Plugin } from "@opencode-ai/plugin";
|
import type { Plugin } from "@opencode-ai/plugin";
|
||||||
import { tool } from "@opencode-ai/plugin";
|
import { tool } from "@opencode-ai/plugin/tool";
|
||||||
import { existsSync } from "fs";
|
import { existsSync } from "fs";
|
||||||
import { mkdir, readFile, writeFile, readdir, stat, unlink, rm } from "fs/promises";
|
import { mkdir, readFile, writeFile, readdir, stat, unlink, rm } from "fs/promises";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
@@ -46,7 +41,7 @@ const CORE_MEMORY_LIMITS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Phase 2: Smart Pruning Types
|
// Smart Pruning Types
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
type PruningStrategy =
|
type PruningStrategy =
|
||||||
@@ -72,7 +67,7 @@ type CachedToolOutput = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Phase 3: Working Memory Types (Slot-based Architecture)
|
// Working Memory Types (Slot-based Architecture)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
type WorkingMemory = {
|
type WorkingMemory = {
|
||||||
@@ -128,7 +123,7 @@ const WORKING_MEMORY_LIMITS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Storage Governance (Layer 1 + Layer 2)
|
// Storage Governance
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
const STORAGE_GOVERNANCE = {
|
const STORAGE_GOVERNANCE = {
|
||||||
@@ -138,7 +133,7 @@ const STORAGE_GOVERNANCE = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Phase 4: Memory Pressure Monitoring
|
// Memory Pressure Monitoring
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
type PressureLevel = "safe" | "moderate" | "high";
|
type PressureLevel = "safe" | "moderate" | "high";
|
||||||
@@ -169,7 +164,6 @@ type ModelPressureInfo = {
|
|||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Compaction tracking (preserved from Phase 4 initial work)
|
|
||||||
type CompactionLog = {
|
type CompactionLog = {
|
||||||
sessionID: string;
|
sessionID: string;
|
||||||
compactionCount: number;
|
compactionCount: number;
|
||||||
@@ -501,12 +495,11 @@ async function updateCoreMemoryBlock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Storage Governance Functions (Layer 1 + Layer 2)
|
// Storage Governance Functions
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layer 1: Clean up all artifacts for a deleted session
|
* Clean up all artifacts for a deleted session.
|
||||||
* Called when session.deleted event is received
|
|
||||||
*/
|
*/
|
||||||
async function cleanupSessionArtifacts(
|
async function cleanupSessionArtifacts(
|
||||||
directory: string,
|
directory: string,
|
||||||
@@ -532,9 +525,9 @@ async function cleanupSessionArtifacts(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layer 2: Sweep tool-output cache for a session
|
* Sweep tool-output cache for a session.
|
||||||
* Remove files older than TTL and enforce max file count
|
* Removes files older than TTL and enforces max file count.
|
||||||
* Returns number of files deleted
|
* Returns number of files deleted.
|
||||||
*/
|
*/
|
||||||
async function sweepToolOutputCache(
|
async function sweepToolOutputCache(
|
||||||
directory: string,
|
directory: string,
|
||||||
@@ -606,7 +599,7 @@ async function sweepToolOutputCache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Phase 2: Smart Pruning System
|
// Smart Pruning System
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -775,7 +768,7 @@ async function getCachedToolOutput(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Phase 3: Working Memory Auto-Management
|
// Working Memory Auto-Management
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1057,9 +1050,7 @@ function getTopItemsForPrompt(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compress file paths to save space in system prompt
|
* Compress file paths to save space in system prompt.
|
||||||
* /Users/sd_wo/opencode/packages/opencode/src/foo.ts → ~/opencode/pkg/opencode/src/foo.ts
|
|
||||||
* /Users/sd_wo/work/opencode-plugins/.opencode/plugins/foo.ts → ~/work/oc-plugins/.opencode/plugins/foo.ts
|
|
||||||
*/
|
*/
|
||||||
function compressPath(content: string): string {
|
function compressPath(content: string): string {
|
||||||
const homeDir = process.env.HOME || '/Users/' + (process.env.USER || 'user');
|
const homeDir = process.env.HOME || '/Users/' + (process.env.USER || 'user');
|
||||||
@@ -1145,7 +1136,7 @@ function getWorkingMemoryItemCount(memory: WorkingMemory): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Phase 4: Compaction Tracking and State Preservation
|
// Compaction Tracking
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1207,14 +1198,13 @@ async function recordCompaction(
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate usable tokens using OpenCode's exact compaction formula
|
* Calculate usable tokens using OpenCode's compaction formula.
|
||||||
* Reference: packages/opencode/src/session/compaction.ts:32-48
|
|
||||||
*/
|
*/
|
||||||
function calculateUsableTokens(model: {
|
function calculateUsableTokens(model: {
|
||||||
limit: { context: number; input?: number; output: number };
|
limit: { context: number; input?: number; output: number };
|
||||||
}): number {
|
}): number {
|
||||||
const OUTPUT_TOKEN_MAX = 32_000; // From transform.ts:21
|
const OUTPUT_TOKEN_MAX = 32_000;
|
||||||
const COMPACTION_BUFFER = 20_000; // From compaction.ts:33
|
const COMPACTION_BUFFER = 20_000;
|
||||||
|
|
||||||
const maxOutputTokens = Math.min(
|
const maxOutputTokens = Math.min(
|
||||||
model.limit.output || OUTPUT_TOKEN_MAX,
|
model.limit.output || OUTPUT_TOKEN_MAX,
|
||||||
@@ -1222,7 +1212,6 @@ function calculateUsableTokens(model: {
|
|||||||
);
|
);
|
||||||
const reserved = Math.min(COMPACTION_BUFFER, maxOutputTokens);
|
const reserved = Math.min(COMPACTION_BUFFER, maxOutputTokens);
|
||||||
|
|
||||||
// Match compaction.ts:42-47
|
|
||||||
const usable = model.limit.input
|
const usable = model.limit.input
|
||||||
? model.limit.input - reserved
|
? model.limit.input - reserved
|
||||||
: model.limit.context - maxOutputTokens;
|
: model.limit.context - maxOutputTokens;
|
||||||
@@ -1231,11 +1220,7 @@ function calculateUsableTokens(model: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate pressure level based on current tokens and usable limit
|
* Calculate pressure level based on current tokens and usable limit.
|
||||||
*
|
|
||||||
* Thresholds:
|
|
||||||
* - 0.75 (75%): moderate - show reminder in prompt
|
|
||||||
* - 0.9 (90%): high - send intervention message
|
|
||||||
*/
|
*/
|
||||||
function calculatePressureLevel(
|
function calculatePressureLevel(
|
||||||
currentTokens: number,
|
currentTokens: number,
|
||||||
@@ -1253,7 +1238,7 @@ function calculatePressureLevel(
|
|||||||
*/
|
*/
|
||||||
function calculateModelPressure(
|
function calculateModelPressure(
|
||||||
sessionID: string,
|
sessionID: string,
|
||||||
model: { id: string; provider: string; limit: { context: number; input?: number; output: number } },
|
model: { id: string; providerID: string; limit: { context: number; input?: number; output: number } },
|
||||||
totalTokens: number
|
totalTokens: number
|
||||||
): ModelPressureInfo {
|
): ModelPressureInfo {
|
||||||
const OUTPUT_TOKEN_MAX = 32_000;
|
const OUTPUT_TOKEN_MAX = 32_000;
|
||||||
@@ -1272,7 +1257,7 @@ function calculateModelPressure(
|
|||||||
return {
|
return {
|
||||||
sessionID,
|
sessionID,
|
||||||
modelID: model.id,
|
modelID: model.id,
|
||||||
providerID: model.provider,
|
providerID: model.providerID,
|
||||||
limits: {
|
limits: {
|
||||||
context: model.limit.context,
|
context: model.limit.context,
|
||||||
input: model.limit.input,
|
input: model.limit.input,
|
||||||
@@ -1334,18 +1319,14 @@ async function loadModelPressureInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate total tokens by querying OpenCode's session database
|
* Calculate total tokens by querying OpenCode's session database.
|
||||||
* This is more reliable than relying on hook-provided messages
|
|
||||||
*
|
|
||||||
* Note: Only looks at last 10 messages to avoid stale data from before compaction
|
|
||||||
*/
|
*/
|
||||||
async function calculateTotalTokensFromDB(sessionID: string): Promise<number> {
|
async function calculateTotalTokensFromDB(sessionID: string): Promise<number> {
|
||||||
try {
|
try {
|
||||||
const { execSync } = await import("child_process");
|
const { execSync } = await import("child_process");
|
||||||
const dbPath = join(process.env.HOME || "~", ".local/share/opencode/opencode.db");
|
const dbPath = join(process.env.HOME || "~", ".local/share/opencode/opencode.db");
|
||||||
|
|
||||||
// Get tokens.total from most recent assistant message (last 10 to be safe)
|
// Get tokens.total from most recent assistant message
|
||||||
// Use MAX to handle edge cases, but limit to recent messages to avoid stale pre-compaction data
|
|
||||||
const query = `
|
const query = `
|
||||||
SELECT json_extract(data, '$.tokens.total') as total
|
SELECT json_extract(data, '$.tokens.total') as total
|
||||||
FROM message
|
FROM message
|
||||||
@@ -1365,11 +1346,7 @@ async function calculateTotalTokensFromDB(sessionID: string): Promise<number> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate pressure warning text for system prompt injection
|
* Generate pressure warning text for system prompt injection.
|
||||||
*
|
|
||||||
* Design principles:
|
|
||||||
* - MODERATE (75%): gentle nudge, no interruption
|
|
||||||
* - HIGH (90%): actionable commands, pause and persist state
|
|
||||||
*/
|
*/
|
||||||
function generatePressureWarning(info: ModelPressureInfo): string {
|
function generatePressureWarning(info: ModelPressureInfo): string {
|
||||||
const { current, calculated } = info;
|
const { current, calculated } = info;
|
||||||
@@ -1387,13 +1364,8 @@ function generatePressureWarning(info: ModelPressureInfo): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send proactive intervention message when HIGH pressure detected (90%)
|
* Send a proactive intervention message when HIGH pressure (90%) is detected.
|
||||||
*
|
* Uses promptAsync() which returns immediately (non-blocking).
|
||||||
* This sends an independent system message to the session immediately, so the agent
|
|
||||||
* receives the task in the queue without interrupting current work. The agent will
|
|
||||||
* process it automatically when available.
|
|
||||||
*
|
|
||||||
* Design: Use promptAsync() which returns 204 immediately, non-blocking.
|
|
||||||
*/
|
*/
|
||||||
async function sendPressureInterventionMessage(
|
async function sendPressureInterventionMessage(
|
||||||
client: any,
|
client: any,
|
||||||
@@ -1421,17 +1393,14 @@ REQUIRED ACTIONS:
|
|||||||
After completing these actions, you may resume your current task.`;
|
After completing these actions, you may resume your current task.`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Use promptAsync to send message without waiting for response
|
|
||||||
await client.session.promptAsync({
|
await client.session.promptAsync({
|
||||||
path: { id: sessionID },
|
path: { id: sessionID },
|
||||||
body: {
|
body: {
|
||||||
parts: [{
|
parts: [{
|
||||||
type: "text",
|
type: "text",
|
||||||
// Send actionable content directly (not log-style placeholder)
|
|
||||||
text: systemPrompt,
|
text: systemPrompt,
|
||||||
}],
|
}],
|
||||||
// Keep system unset so the intervention is visible as a normal prompt
|
noReply: false,
|
||||||
noReply: false, // We want agent to respond with actions
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1440,36 +1409,32 @@ After completing these actions, you may resume your current task.`;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get pressure-aware pruning config based on current memory pressure
|
* Get pressure-aware pruning config based on current memory pressure.
|
||||||
* HYPER-AGGRESSIVE MODE: pressure >= 0.90 enforces strict limits
|
|
||||||
*/
|
*/
|
||||||
function getPressureAwarePruningConfig(pressure: number): {
|
function getPressureAwarePruningConfig(pressure: number): {
|
||||||
maxLines: number;
|
maxLines: number;
|
||||||
maxChars: number;
|
maxChars: number;
|
||||||
aggressiveTruncation: boolean;
|
aggressiveTruncation: boolean;
|
||||||
} {
|
} {
|
||||||
// HIGH (>= 90%): Hyper-Aggressive Mode
|
|
||||||
if (pressure >= 0.90) {
|
if (pressure >= 0.90) {
|
||||||
return {
|
return {
|
||||||
maxLines: 2000, // Hard limit: 2000 lines max
|
maxLines: 2000,
|
||||||
maxChars: 100_000, // ~25k tokens max per tool output
|
maxChars: 100_000,
|
||||||
aggressiveTruncation: true, // Force truncation, no exceptions
|
aggressiveTruncation: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// MODERATE (>= 75%): Aggressive Mode
|
if (pressure >= 0.75) {
|
||||||
if (pressure >= 0.75) {
|
return {
|
||||||
return {
|
maxLines: 5000,
|
||||||
maxLines: 5000,
|
maxChars: 200_000,
|
||||||
maxChars: 200_000, // ~50k tokens max
|
|
||||||
aggressiveTruncation: true,
|
aggressiveTruncation: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFE (< 75%): Normal Mode
|
|
||||||
return {
|
return {
|
||||||
maxLines: 10_000,
|
maxLines: 10_000,
|
||||||
maxChars: 400_000, // ~100k tokens max
|
maxChars: 400_000,
|
||||||
aggressiveTruncation: false,
|
aggressiveTruncation: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1524,34 +1489,14 @@ export default async function WorkingMemoryPlugin(
|
|||||||
const { directory, client } = input;
|
const { directory, client } = input;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// ========================================================================
|
// Inject core memory usage guidelines, pressure warnings, core memory,
|
||||||
// Phase 1: Inject Core Memory and Working Memory into System Prompt
|
// and working memory into the system prompt each turn.
|
||||||
// Phase 4: Inject Memory Pressure Warnings & Calculate Tokens from DB
|
|
||||||
// Phase 4.5: Proactive Pressure Intervention (NEW)
|
|
||||||
// Phase 5: Core Memory Usage Guidelines (AGENTS.md Enhancement)
|
|
||||||
//
|
|
||||||
// Dual-System Approach:
|
|
||||||
// 1. PASSIVE WARNING (existing): Injected into next turn's system prompt
|
|
||||||
// - Always present as reminder in system context
|
|
||||||
// - 1-turn delay but persistent
|
|
||||||
//
|
|
||||||
// 2. PROACTIVE INTERVENTION (new): Immediate async message sent to queue
|
|
||||||
// - No delay, sent immediately when HIGH (90%) detected
|
|
||||||
// - Agent processes when available (non-blocking)
|
|
||||||
// - Only sent when pressure level increases (avoids spam)
|
|
||||||
//
|
|
||||||
// 3. USAGE GUIDELINES (new): Injected after AGENTS.md, before core_memory
|
|
||||||
// - Teaches agent how to use core_memory blocks correctly
|
|
||||||
// - Prevents storing API docs/type definitions in memory
|
|
||||||
// - Ensures goal/progress/context stay focused on current task
|
|
||||||
// ========================================================================
|
|
||||||
"experimental.chat.system.transform": async (hookInput, output) => {
|
"experimental.chat.system.transform": async (hookInput, output) => {
|
||||||
const { sessionID, model } = hookInput;
|
const { sessionID, model } = hookInput;
|
||||||
if (!sessionID) return;
|
if (!sessionID) return;
|
||||||
|
|
||||||
// Phase 5: Inject Core Memory Usage Guidelines
|
// Inject core memory usage guidelines.
|
||||||
// This enhances AGENTS.md (if exists) with plugin-specific instructions
|
// Inserted before <core_memory> so the agent reads guidance first.
|
||||||
// Inserted early so it's read before agent sees <core_memory> block
|
|
||||||
const coreMemoryGuidelines = `
|
const coreMemoryGuidelines = `
|
||||||
# Core Memory Usage Guidelines
|
# Core Memory Usage Guidelines
|
||||||
|
|
||||||
@@ -1613,8 +1558,8 @@ The Working Memory Plugin provides persistent core_memory blocks. **USE THEM COR
|
|||||||
|
|
||||||
output.system.push(coreMemoryGuidelines);
|
output.system.push(coreMemoryGuidelines);
|
||||||
|
|
||||||
// Phase 4: Check for memory pressure and inject warning
|
// Check for memory pressure and inject warning into system prompt.
|
||||||
// Skip warning if model just changed (avoids false alarms with different limits)
|
// Skip if model just changed (avoids false alarms with different limits).
|
||||||
const prevPressure = await loadModelPressureInfo(directory, sessionID);
|
const prevPressure = await loadModelPressureInfo(directory, sessionID);
|
||||||
const modelChanged = model && prevPressure && prevPressure.modelID !== model.id;
|
const modelChanged = model && prevPressure && prevPressure.modelID !== model.id;
|
||||||
|
|
||||||
@@ -1625,7 +1570,7 @@ The Working Memory Plugin provides persistent core_memory blocks. **USE THEM COR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phase 4: Calculate current token usage from DB and update pressure
|
// Calculate current token usage from DB and update pressure info.
|
||||||
if (model) {
|
if (model) {
|
||||||
const totalTokens = await calculateTotalTokensFromDB(sessionID);
|
const totalTokens = await calculateTotalTokensFromDB(sessionID);
|
||||||
|
|
||||||
@@ -1634,20 +1579,18 @@ The Working Memory Plugin provides persistent core_memory blocks. **USE THEM COR
|
|||||||
sessionID,
|
sessionID,
|
||||||
{
|
{
|
||||||
id: model.id,
|
id: model.id,
|
||||||
provider: model.provider,
|
providerID: model.providerID,
|
||||||
limit: model.limit,
|
limit: model.limit,
|
||||||
},
|
},
|
||||||
totalTokens
|
totalTokens
|
||||||
);
|
);
|
||||||
|
|
||||||
// Save for next turn's warning injection
|
// Save for next turn's warning injection.
|
||||||
await saveModelPressureInfo(directory, updatedPressure);
|
await saveModelPressureInfo(directory, updatedPressure);
|
||||||
|
|
||||||
// Phase 4.5: Proactive Intervention - Send immediate message if HIGH (90%)
|
// Send proactive intervention if pressure just crossed into HIGH.
|
||||||
// This is better than waiting for next turn's passive warning
|
|
||||||
// The message goes into the queue and agent processes it when available
|
|
||||||
if (updatedPressure.current.level === "high") {
|
if (updatedPressure.current.level === "high") {
|
||||||
// Only send if pressure increased from previous level (avoid spam)
|
// Only send if pressure just escalated (avoid repeated spam).
|
||||||
const shouldSend = !prevPressure ||
|
const shouldSend = !prevPressure ||
|
||||||
prevPressure.current.level === "safe" ||
|
prevPressure.current.level === "safe" ||
|
||||||
prevPressure.current.level === "moderate";
|
prevPressure.current.level === "moderate";
|
||||||
@@ -1658,7 +1601,7 @@ The Working Memory Plugin provides persistent core_memory blocks. **USE THEM COR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phase 1: Core memory
|
// Core memory
|
||||||
const coreMemory = await loadCoreMemory(directory, sessionID);
|
const coreMemory = await loadCoreMemory(directory, sessionID);
|
||||||
if (coreMemory) {
|
if (coreMemory) {
|
||||||
const hasContent =
|
const hasContent =
|
||||||
@@ -1672,7 +1615,7 @@ The Working Memory Plugin provides persistent core_memory blocks. **USE THEM COR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phase 1: Working memory
|
// Working memory
|
||||||
const workingMemory = await loadWorkingMemory(directory, sessionID);
|
const workingMemory = await loadWorkingMemory(directory, sessionID);
|
||||||
if (workingMemory && getWorkingMemoryItemCount(workingMemory) > 0) {
|
if (workingMemory && getWorkingMemoryItemCount(workingMemory) > 0) {
|
||||||
const workingPrompt = renderWorkingMemoryPrompt(workingMemory);
|
const workingPrompt = renderWorkingMemoryPrompt(workingMemory);
|
||||||
@@ -1682,15 +1625,11 @@ The Working Memory Plugin provides persistent core_memory blocks. **USE THEM COR
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========================================================================
|
// Cache tool outputs, auto-extract to working memory, and sweep cache periodically.
|
||||||
// Phase 2 & 3: Cache Tool Outputs and Auto-Extract to Working Memory
|
|
||||||
// Storage Governance Layer 2: Tool Output Cache Sweep Trigger
|
|
||||||
// ========================================================================
|
|
||||||
"tool.execute.after": async (hookInput, hookOutput) => {
|
"tool.execute.after": async (hookInput, hookOutput) => {
|
||||||
const { sessionID, callID, tool: toolName, args } = hookInput;
|
const { sessionID, callID, tool: toolName, args } = hookInput;
|
||||||
const { output: toolOutput } = hookOutput;
|
const { output: toolOutput } = hookOutput;
|
||||||
|
|
||||||
// Phase 2: Cache the full output for later smart pruning
|
|
||||||
await cacheToolOutput(directory, {
|
await cacheToolOutput(directory, {
|
||||||
callID,
|
callID,
|
||||||
sessionID,
|
sessionID,
|
||||||
@@ -1699,22 +1638,19 @@ The Working Memory Plugin provides persistent core_memory blocks. **USE THEM COR
|
|||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Phase 3: Auto-extract to working memory
|
|
||||||
const extractedItems = extractFromToolOutput(toolName, toolOutput);
|
const extractedItems = extractFromToolOutput(toolName, toolOutput);
|
||||||
for (const item of extractedItems) {
|
for (const item of extractedItems) {
|
||||||
await addToWorkingMemory(directory, sessionID, item);
|
await addToWorkingMemory(directory, sessionID, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Storage Governance Layer 2: Sweep tool-output cache every N calls
|
// Sweep tool-output cache every N tool calls.
|
||||||
const memory = await loadWorkingMemory(directory, sessionID);
|
const memory = await loadWorkingMemory(directory, sessionID);
|
||||||
if (memory && memory.eventCounter % STORAGE_GOVERNANCE.sweepInterval === 0) {
|
if (memory && memory.eventCounter % STORAGE_GOVERNANCE.sweepInterval === 0) {
|
||||||
await sweepToolOutputCache(directory, sessionID);
|
await sweepToolOutputCache(directory, sessionID);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========================================================================
|
// Apply smart pruning to compacted tool outputs (pressure-aware).
|
||||||
// Phase 2: Apply Smart Pruning to Messages (Pressure-Aware)
|
|
||||||
// ========================================================================
|
|
||||||
"experimental.chat.messages.transform": async (hookInput, output) => {
|
"experimental.chat.messages.transform": async (hookInput, output) => {
|
||||||
const sessionID = output.messages[0]?.info?.sessionID || "";
|
const sessionID = output.messages[0]?.info?.sessionID || "";
|
||||||
|
|
||||||
@@ -1754,11 +1690,8 @@ The Working Memory Plugin provides persistent core_memory blocks. **USE THEM COR
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========================================================================
|
// Clean up all session artifacts on session deletion.
|
||||||
// Storage Governance Layer 1: Session Deletion Event Handler
|
|
||||||
// ========================================================================
|
|
||||||
event: async ({ event }) => {
|
event: async ({ event }) => {
|
||||||
// Listen for session.deleted events and cleanup all artifacts
|
|
||||||
if (event.type === "session.deleted") {
|
if (event.type === "session.deleted") {
|
||||||
const sessionID = event.properties?.info?.id;
|
const sessionID = event.properties?.info?.id;
|
||||||
if (sessionID) {
|
if (sessionID) {
|
||||||
@@ -1767,9 +1700,7 @@ The Working Memory Plugin provides persistent core_memory blocks. **USE THEM COR
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========================================================================
|
// Preserve working memory state before compaction.
|
||||||
// Phase 4: Preserve State Before Compaction
|
|
||||||
// ========================================================================
|
|
||||||
"experimental.session.compacting": async (hookInput, output) => {
|
"experimental.session.compacting": async (hookInput, output) => {
|
||||||
const { sessionID } = hookInput;
|
const { sessionID } = hookInput;
|
||||||
|
|
||||||
@@ -1808,7 +1739,7 @@ The Working Memory Plugin provides persistent core_memory blocks. **USE THEM COR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SSOT Bridge: Inject OpenCode native Todos from DB into compaction context
|
// Inject pending OpenCode todos into compaction context.
|
||||||
try {
|
try {
|
||||||
const { execSync } = await import("child_process");
|
const { execSync } = await import("child_process");
|
||||||
const dbPath = join(process.env.HOME || "~", ".local/share/opencode/opencode.db");
|
const dbPath = join(process.env.HOME || "~", ".local/share/opencode/opencode.db");
|
||||||
@@ -1849,9 +1780,7 @@ The Working Memory Plugin provides persistent core_memory blocks. **USE THEM COR
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// Tools
|
// Tools
|
||||||
// ========================================================================
|
|
||||||
tool: {
|
tool: {
|
||||||
core_memory_update: tool({
|
core_memory_update: tool({
|
||||||
description: `Update persistent core memory blocks that survive compaction.
|
description: `Update persistent core memory blocks that survive compaction.
|
||||||
@@ -1868,14 +1797,12 @@ Operations:
|
|||||||
These blocks are ALWAYS visible to you in every message, even after compaction.
|
These blocks are ALWAYS visible to you in every message, even after compaction.
|
||||||
Update them regularly to maintain continuity across long conversations.`,
|
Update them regularly to maintain continuity across long conversations.`,
|
||||||
args: {
|
args: {
|
||||||
block: tool.schema.enum(["goal", "progress", "context"], {
|
block: tool.schema.enum(["goal", "progress", "context"]).describe(
|
||||||
description:
|
"Which memory block to update (goal/progress/context)"
|
||||||
"Which memory block to update (goal/progress/context)",
|
),
|
||||||
}),
|
operation: tool.schema.enum(["replace", "append"]).describe(
|
||||||
operation: tool.schema.enum(["replace", "append"], {
|
"Whether to replace the entire block or append to it"
|
||||||
description:
|
),
|
||||||
"Whether to replace the entire block or append to it",
|
|
||||||
}),
|
|
||||||
content: tool.schema
|
content: tool.schema
|
||||||
.string()
|
.string()
|
||||||
.max(5000)
|
.max(5000)
|
||||||
|
|||||||
+10
-1
@@ -1,9 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "opencode-working-memory",
|
"name": "opencode-working-memory",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Advanced four-tier memory architecture for OpenCode with intelligent pressure monitoring and auto-storage governance",
|
"description": "Advanced four-tier memory architecture for OpenCode with intelligent pressure monitoring and auto-storage governance",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "index.ts",
|
"main": "index.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "node -e \"console.log('No build step required: OpenCode loads index.ts directly')\"",
|
||||||
|
"typecheck": "tsc --noEmit"
|
||||||
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"opencode",
|
"opencode",
|
||||||
"plugin",
|
"plugin",
|
||||||
@@ -25,6 +29,11 @@
|
|||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@opencode-ai/plugin": "^1.2.0"
|
"@opencode-ai/plugin": "^1.2.0"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^24.3.0",
|
||||||
|
"bun-types": "^1.2.21",
|
||||||
|
"typescript": "^5.9.2"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-11
@@ -1,21 +1,22 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"module": "ESNext",
|
"module": "NodeNext",
|
||||||
"lib": ["ES2022"],
|
"lib": ["ES2022"],
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "NodeNext",
|
||||||
|
"types": ["node", "bun-types"],
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": false,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": false,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": false,
|
||||||
"strictFunctionTypes": true,
|
"strictFunctionTypes": false,
|
||||||
"strictBindCallApply": true,
|
"strictBindCallApply": false,
|
||||||
"strictPropertyInitialization": true,
|
"strictPropertyInitialization": false,
|
||||||
"noImplicitThis": true,
|
"noImplicitThis": false,
|
||||||
"alwaysStrict": true,
|
"alwaysStrict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": false,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": false,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
|||||||
Reference in New Issue
Block a user