Skip to content

feat: add inject mode, repeat_every interval, and content-based dedup - #17

Open
aorizondo wants to merge 59 commits into
frap129:devfrom
aorizondo:main
Open

feat: add inject mode, repeat_every interval, and content-based dedup#17
aorizondo wants to merge 59 commits into
frap129:devfrom
aorizondo:main

Conversation

@aorizondo

Copy link
Copy Markdown

Summary

Adds three complementary features to give users fine-grained control over how and when rules are injected into agent prompts.

Changes

  • inject metadata field (system | user | both): Controls whether a rule is injected into the system prompt, prepended to user messages, or both. Defaults to system for backward compatibility.
  • repeat_every metadata field: Configures the minimum number of user turns between user-prompt injections. Accepts a number or a model-pattern map ({ "gpt-4*": 3, "default": 1 }).
  • Content-based dedup: Before injecting into the system prompt, each rule content is checked against the current system prompt text. Duplicate content is skipped, preventing accumulation across sessions or from multiple sources.
  • Raw injection mode: System and user injections use raw: true — no preamble (# OpenCode Rules\n\nPlease follow...) or header ([Reinforcement Instructions]) is added. Only the stripped rule content is injected.
  • Single-message user injection: Simplified from chunked multi-message injection to a single synthetic: true user message.
  • Removes MAX_CHUNK_CHARS and splitContentIntoChunks (dead code after single-message simplification).

Testing

  • All 319 tests pass
  • Lint clean
  • TypeScript compilation clean

Documentation

  • README updated with inject and repeat_every metadata field docs
  • How It Works section updated with dedup and user-prompt injection steps

frap129 added 30 commits March 5, 2026 11:39
…types

- Remove unused writeRuleFile function and writeFileSync import
- Convert TestDirs, MockPluginInput interfaces to internal
- Remove CI_ENV_VARS export (only used internally)
- Remove dead message part builders (textPart, readToolPart, globToolPart, mockMessage)
- Remove unused type exports (TextPart, ToolInvocationPart, MessagePart, MockMessage)

Raises desloppify objective score to 95.8%.
- Restore state file from 2ac31d8 (0 open findings, 24 wontfix)
- Merge subjective review scores from 288d6aa
- Remove runtime artifacts (review sessions, packets, subagent logs)
- Add .gitignore entries for desloppify runtime dirs
- Final: open=0, strict=97.5%, overall=98.7%
…ices

Consolidate 3 field reference tables into 1 unified table with Category
column. Compress keyword selection from ~30 to ~18 lines. Trim examples
from 6 to 4. Add Overview section and Common Mistakes section. Reorder
sections per writing-skills template. Fix CSO description to remove
workflow summary.
Remove card styling (background, border, padding) and palette abstraction.
Add collapsible Project/Global sections with collapse-by-default behavior,
bold 'Rules' header, and arrow toggle indicators matching MCP/LSP sections.
Filesystem-based IPC for TUI sidebar to know which rules are active.
Provides atomic writes with per-session serialization and fire-and-forget API.
- Validate sessionId against /^[A-Za-z0-9_-]+$/ to prevent path traversal
- Add proper type guard for ActiveRulesState with full type checks
- Reject invalid sessionIds early with debug logging
- Change readAndFormatRules() return from string to FilterResult object
- Add matchedPaths array tracking which rule files were included
- Update runtime.ts to call writeActiveRulesState before early return
- Re-export FilterResult from utils.ts
- Update all test call sites to destructure new return type
- Add tests verifying matchedPaths behavior
…fect

- Test that matching rules populate matchedRulePaths in state file
- Test that no-match case writes empty matchedPaths array
- Test that missing sessionID skips state write
- Use _setStateDirForTesting for test isolation
Use readdirSync to assert state directory has no .json files instead
of only checking readActiveRulesState for a specific key.
- Add isActive (boolean | null) to SidebarRuleEntry for UI state display
- Add hasEvaluationState to LoadSidebarRulesResult
- Update loadSidebarRules() with optional sessionId parameter to read state
- Extend TuiPluginApi type shim with TuiEventBus interface and event property
- Add comprehensive tests for isActive behavior with/without state file
- Subscribe to message.updated and session.status events via TuiEventBus
- Debounce 150ms before re-reading rules on events
- Verify sessionId/projectDir match before committing async results
- Separate initial-load effect (resets UI state) from refresh effect
- Add hasEvaluationState prop to RuleSection for header count format
- Green bullet for isActive === true, grey for false/null
- Header count shows (active/total) when hasEvaluationState, else (total)
- Unsubscribe from events on cleanup via onCleanup
Check event payload for sessionId property at receipt time. If the
event has a sessionId that doesn't match the current session, skip
it immediately rather than waiting for the post-load staleness check.
- Add monotonic requestId counter to detect out-of-order async completions
- Call setStatus('loaded') in loadRulesRefresh to recover from error state
- Clear debounceTimer on session/directory change to prevent stale events
frap129 and others added 27 commits March 31, 2026 18:04
OpenCode SDK events nest sessionID inside properties object with
capital D (event.properties.sessionID), not event.sessionId. Also
improves vendored TuiEventBus type to match real event structure.
…h, and state persistence

- Add TUI sidebar to Features list
- Add active-rules-state.ts to Project Structure and Key Module Responsibilities
- Update rule-filter.ts description to mention FilterResult return type
- Replace inaccurate [P]/[G] prefix claim with collapsible section groups
- Document active/inactive indicators, sort-to-top, and event-driven refresh
- Add State Persistence step to How It Works flow
Add OPENCODE_CONFIG_DIR as highest-priority source for global rules,
followed by XDG_CONFIG_HOME, then ~/.config fallback.
OpenCode's plugin loader now uses @npmcli/arborist for isolated
installs, which does not resolve optional peer dependencies from the
host. Moving @opentui/solid, @opentui/core, and solid-js to direct
dependencies ensures the JSX runtime is available in the plugin's
isolated node_modules directory.
Bun's module linker in OpenCode's TUI process treats the yaml CJS
package as async. Static ESM imports, default imports, and
createRequire all fail. Use await import() which is the only
supported path for async CJS modules in Bun.
The ./tui export referenced raw source (./tui/index.tsx) which caused
Bun's module resolver to fail on .js import specifiers that only exist
in the dist directory.
- Add rulesInjected and lastInjectedAt to SessionState
- Skip injection if rulesInjected is true
- Reset rulesInjected when new user prompt arrives
- Add test cases for the new state tracking
- All 145 tests pass
Update NOTEs to github markdown syntax for proper rendering.
- Inject mode (`inject: system | user | both`) to control injection target
- `repeat_every` metadata for configurable user-prompt injection intervals
- Content-based dedup: skip rule contents already present in system prompt
- Raw mode: zero-header injection (no preamble, no [Reinforcement Instructions])
- Remove chunking: single-message user injection with synthetic flag
- Track individual rule contents in FilterResult for accurate dedup
- Update tests for raw-mode system prompt injection
- Update README with new metadata fields and behavior docs
@frap129

frap129 commented May 14, 2026

Copy link
Copy Markdown
Owner

Please rebase this onto the dev branch.

@frap129
frap129 changed the base branch from main to dev August 12, 2026 18:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants