Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
732a3c7
📝 docs: add CLAUDE.md for web subproject
jnahian May 15, 2026
b3eebb9
📝 docs: add agent integration design spec
jnahian May 15, 2026
e35e4a7
📝 docs: add v0.3 implementation plan (schema + exports)
jnahian May 15, 2026
1e259ed
✨ feat: add structured schema types to Note interface
jnahian May 16, 2026
f47f5ac
✨ feat: add applyDefaults helper for legacy notes
jnahian May 16, 2026
07fa795
✨ feat(storage): parse structured fields from note markdown
jnahian May 16, 2026
d04622f
✨ feat(storage): emit structured fields in note markdown
jnahian May 16, 2026
589ee3c
✨ feat(noteManager): apply schema defaults on read
jnahian May 16, 2026
70ddda7
✨ feat: add INDEX.json and AGENTS.md generators
jnahian May 16, 2026
049a125
✨ feat: add debounced atomic ExportWriter
jnahian May 16, 2026
7fc6aa4
✨ feat: regenerate exports on note changes
jnahian May 16, 2026
5945d23
✨ feat: add manual Regenerate Exports command
jnahian May 16, 2026
ac0068d
✨ feat: add codeContextNotes.exports.* settings
jnahian May 16, 2026
e84cbac
📝 docs: document INDEX.json / AGENTS.md exports in README
jnahian May 16, 2026
c225e46
💄 feat(sidebar): show note type in tree item description
jnahian May 16, 2026
b87884a
✨ feat(sidebar): add type filter and expired-notes toggle
jnahian May 16, 2026
e9edc10
✨ feat: add command to set note type/priority/tags/expiry
jnahian May 16, 2026
20dd813
📝 docs: merge v0.3.0 changelog (agent integration + search)
jnahian May 16, 2026
4832d26
📝 docs(web): add v0.3.0 to changelog timeline
jnahian May 16, 2026
7f81a64
🔖 chore: bump version to 0.3.0
jnahian May 16, 2026
63437e0
fix: address CodeRabbit and Copilot review findings on PR #39
claude Jul 5, 2026
4d1f6dc
🐛 fix(noteManager): harden updateNoteMetadata and cache boundary
jnahian Jul 16, 2026
13ebd54
🐛 fix(sidebar): apply filters to file groups and root count
jnahian Jul 16, 2026
08d92f6
🐛 fix(exports): wiring, self-trigger loop, atomic-write race, honest …
jnahian Jul 16, 2026
fdf3885
🐛 fix(storage): validate structured field values on parse
jnahian Jul 16, 2026
c0d3ca2
📝 docs: defer search to a follow-up release + review nits
jnahian Jul 16, 2026
d282c9a
Merge remote review fixes into local review fixes
jnahian Jul 16, 2026
32d047b
🐛 fix(build): clean out/ before test compiles
jnahian Jul 16, 2026
5e9e637
🐛 fix(noteManager): keep soft-deleted notes visible to internal lookups
jnahian Jul 16, 2026
3f4a28b
🐛 fix(comments): editing-comment lookup and created/updated label
jnahian Jul 16, 2026
324a59a
🐛 fix(ui): note preview formatting and sidebar ordering
jnahian Jul 16, 2026
fabc5eb
✅ test: fix flaky infra and align assertions with async API
jnahian Jul 16, 2026
965a968
Merge pull request #56 from jnahian/fix/integration-test-failures
jnahian Jul 16, 2026
a5d3c7d
Merge branch 'main' into feat/v0.3-agent-integration
jnahian Jul 16, 2026
07b25c0
Merge branch 'main' into feat/v0.3-agent-integration
jnahian Jul 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,24 @@ Previous content before this edit

You can add `.code-notes/` to `.gitignore` if you want notes to be local only, or commit them to share with your team.

### Generated exports

When auto-exports are enabled, two files are automatically regenerated
(debounced by 200ms) in your configured notes directory (`.code-notes/` by
default; see `codeContextNotes.storageDirectory`) whenever notes change:

- **`INDEX.json`** — machine-readable index. Used by integrations like the MCP server (v0.4+).
- **`AGENTS.md`** — human-readable digest, hoisting instructions/warnings/handoffs. Useful as workspace context for coding agents.

Note content and ordering are deterministic given the same notes; only the `generatedAt` timestamp in `INDEX.json` changes on every regeneration. To exclude them from git, add to `.gitignore`:

```gitignore
.code-notes/INDEX.json
.code-notes/AGENTS.md
```

To disable export generation entirely, set `codeContextNotes.exports.enabled` to `false`.

## Commands

All commands are available in the Command Palette (`Ctrl+Shift+P` or `Cmd+Shift+P`):
Expand Down
168 changes: 36 additions & 132 deletions docs/changelogs/v0.3.0.md
Original file line number Diff line number Diff line change
@@ -1,147 +1,51 @@
# Changelog - Version 0.3.0

## [0.3.0] - TBD
## [0.3.0] - 2026-05-16

### Added
- **Search and Filter Notes** (GitHub Issue #10)
- Full-text search across all note content
- Filter by author (single or multiple authors)
- Filter by date range (created or modified)
- Filter by file path (glob pattern support)
- Combine multiple filters (AND logic)
- Search input with live results update (debounced 200ms)
- Keyboard shortcut for quick search (`Ctrl+Shift+F` / `Cmd+Shift+F` in notes context)
- Search icon integrated into sidebar toolbar
- Search results show file, line number, preview, and author
- Click any result to navigate directly to note location
- Clear filters button
- Search result count indicator
- Keyboard navigation in results (↑↓ arrows, Enter to open)
- Regex pattern matching support for advanced searches
- Case-sensitive search option
- Search history persistence (last 20 searches)
- "Recent Searches" quick access
- Background indexing for instant search results
- Progress indicator for large searches
- **Structured Note Schema for Agent Integration**
- Optional `type` (7 categories: `context` default, `instruction`, `warning`, `decision`, `todo`, `handoff`, `rationale`), `priority` (`low`/`normal`/`high`/`critical`), `scope` (`line`/`function`/`class`/`file`/`directory`), `tags`, `authorType` (`human`/`agent`), `expiresAt` (ISO 8601), and `references` (PR/issue/commit/test/url) fields on every note
- All fields optional — legacy v0.2.x notes load with sensible defaults (no migration required)
- New command **`Code Notes: Set Note Type / Tags / Priority…`** — Quick-Pick driven metadata editor for any note
- **Auto-Generated Workspace Exports for Coding Agents**
- **`.code-notes/INDEX.json`** — machine-readable index with `byFile`/`byType`/`byTag` lookups and deterministic output. Designed for MCP server consumption (v0.4+).
- **`.code-notes/AGENTS.md`** — human-readable digest hoisting critical instructions/warnings, open handoffs, and decisions. Useful as workspace context for coding agents (Claude Code, Cursor, etc.).
- Debounced (200ms) atomic writes on every note change; new `Code Notes: Regenerate Exports` command for manual recovery.
- **Sidebar Enhancements**
- Note type appears as `· {type}` description suffix; high/critical priority shown as a tooltip badge
- New title-bar actions: **Filter Notes by Type…** (multi-select Quick Pick) and **Toggle Expired Notes**

### Fixed
- CodeLens previews of multiline notes showed all lines merged together; now only the first line, and stray heading markers (`##`) are stripped
- Sidebar notes could render out of line-number order; note previews now strip image markdown cleanly (`![alt](url)` no longer leaves a stray `!`)
- Comment labels always claimed "Last updated" — fresh notes now correctly show "Created"
- Edit-mode lookups (`getCurrentlyEditingComment`) used the wrong map key and never found the editing comment
- Soft-deleted notes disappeared from the note cache entirely, breaking "already deleted" detection and metadata guards; they are also no longer retrievable via by-id lookup
- Stale compiled test artifacts in `out/` ran phantom test suites; the test pipeline now cleans `out/` before compiling

### Changed
- Search UI uses VSCode's native QuickPick for familiar experience
- Sidebar toolbar now includes search icon (🔍) for quick access
- Search results can be displayed in sidebar view or QuickPick
- Search index automatically updates when notes are created/edited/deleted
- Sidebar toolbar gains filter/expired toggles

### Testing
- **64 comprehensive unit tests** for search components
- **SearchManager tests** (20+ tests):
- Full-text search with various queries
- Regex pattern matching
- Author filtering with edge cases
- Date range filtering
- Filter combinations (AND logic)
- Search index updates
- Performance benchmarks
- **SearchUI tests** (10+ tests):
- QuickPick integration
- Keyboard navigation
- Filter UI components
- Result display and formatting
- **Integration tests** (10+ tests):
- Search with sidebar integration
- Real-time index updates
- Multi-note search scenarios
- **Performance testing**:
- ✅ Search with 100 notes: < 500ms
- ✅ Search with 500 notes: < 1 second
- ✅ Search with 1000 notes: < 2 seconds
- ✅ Index updates: < 100ms
- All tests compile successfully with TypeScript
- Existing unit tests continue to pass
- **Manual testing completed successfully**:
- ✅ Full-text search across workspace
- ✅ Filter by author, date, file path
- ✅ Filter combinations
- ✅ Keyboard shortcuts and navigation
- ✅ Search history and recent searches
- ✅ Performance with large note collections

### Technical
- Created `SearchManager` class for search indexing and queries
- Created `SearchUI` class for VSCode QuickPick integration
- Implemented inverted index for fast full-text search
- Added search metadata indexing (author, dates, file paths)
- Implemented search result ranking algorithm
- Added in-memory caching for search results
- **New commands**:
- `searchNotes` - Open search panel with QuickPick
- `clearSearchFilters` - Clear all active filters
- `showSearchHistory` - Show recent searches
- `rebuildSearchIndex` - Manually rebuild search index
- Added `search` contribution to package.json
- Integrated search with existing sidebar view
- Background indexing on workspace open
- Debounced search (200ms delay) to prevent excessive queries
- Search index automatically updates on note CRUD operations
- **Configuration options**:
- `search.fuzzyMatching` - Enable fuzzy search (default: false)
- `search.caseSensitive` - Case-sensitive search (default: false)
- `search.maxResults` - Maximum results to display (default: 100)
- `search.debounceDelay` - Search delay in ms (default: 200)
- `search.saveHistory` - Save search history (default: true)
- `search.historySize` - Number of searches to keep (default: 20)

---

## Benefits

**For Users:**
- Find any note instantly without browsing files
- Quickly locate notes by specific authors
- Filter notes by time period (e.g., "last week's notes")
- Discover related notes across the codebase
- Fast keyboard-driven workflow
- Search history prevents re-typing common queries

**For Teams:**
- Find all notes from specific team members during code reviews
- Locate all notes related to a feature or bug
- Review notes created during a sprint or time period
- Discover documentation and decisions across the project
- Better knowledge sharing and discovery

---
### Settings
- `codeContextNotes.exports.enabled` (default `true`), `.indexJson` (default `true`), `.agentsMarkdown` (default `true`) — control auto-export generation

## Migration Notes
### Compatibility
- Fully backwards-compatible with v0.2.x. Legacy notes load with `type=context`, `scope=line`, `priority=normal`, `tags=[]`, `authorType=human` applied in memory; on-disk file unchanged until next edit.
- Storage format extended with optional bold-label fields (`**Type:**`, `**Tags:**`, etc.). Fields equal to default are omitted, so untouched legacy notes remain byte-identical on disk.

- No breaking changes - purely additive feature
- No data migration required
- Works with existing note storage format
- Backward compatible with all existing notes
- Search can be disabled via keyboard shortcut preferences if not needed
- Search index built automatically on first use

---

## Known Limitations

- Search index stored in memory (not persisted) - rebuilds on workspace reload
- Maximum 100 results by default (configurable)
- Regex patterns limited by JavaScript RegExp capabilities
- No natural language search in initial release
- No "Replace in Notes" (bulk editing) - planned for future version

---
### Testing
- **58+ unit tests** covering schema defaults, storage round-trip (read + write), export generators (buildIndex/buildDigest determinism + section hoisting), debounced atomic writer (debounce coalescing + onError fail-safe), and lazy-migration integration test on NoteManager boundary

## Performance Notes
### Technical
- New modules: `src/noteDefaults.ts` (defaults + expiry helper), `src/exportGenerator.ts` (pure index/digest builders), `src/exportWriter.ts` (debounced atomic writer with injectable config getter)
- `NoteManager` wraps all storage reads with `applyDefaults` — single boundary for lazy migration
- Storage parser/writer in `src/storageManager.ts` extends the existing bold-label markdown format; unknown fields ignored gracefully
- New commands: `regenerateExports`, `setNoteMetadata`, `filterByType`, `toggleExpired`

- Search index uses < 10MB memory for 1000 notes
- Inverted index enables sub-second search
- Background indexing prevents UI blocking
- Lazy loading for large result sets
- Debouncing prevents excessive search operations
- Index updates incrementally on note changes
### Coming Next
- Search and Filter UI (GitHub Issue #10) ships in a follow-up release
- v0.4 ships a standalone MCP server backed by `INDEX.json` for direct agent integration (Cursor, Claude Code, etc.)

---

## Links

[0.3.0]: https://github.com/jnahian/code-context-notes/releases/tag/v0.3.0
Original file line number Diff line number Diff line change
Expand Up @@ -1312,7 +1312,7 @@ on every note change:

Both are deterministic given the same notes. To exclude them from git, add to `.gitignore`:

```
```gitignore
.code-notes/INDEX.json
.code-notes/AGENTS.md
```
Expand Down
10 changes: 5 additions & 5 deletions docs/superpowers/specs/2026-05-15-agent-integration-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ interface Note {
}
```

**Storage:** stored in the markdown frontmatter (same format used today for metadata). Reader is forward-compatible (older versions ignore unknown keys). Writer omits any field equal to its default to keep frontmatter compact.
**Storage:** stored as bold-label metadata lines in the note markdown (`**Type:** …`, same format used today for `**Author:**` etc. — see the v0.3 plan's deviation note; an earlier draft said YAML frontmatter). Reader is forward-compatible (older versions ignore unknown labels). Writer omits any field equal to its default to keep the metadata block compact.

**Sidebar UI in v0.3:** small type pill on each note item; filter dropdown (type / tags / expired). Add/edit flow gets a "More fields" expander for the new fields. Richer UI deferred to v0.5.

Expand Down Expand Up @@ -374,7 +374,7 @@ The Revert button calls existing `noteManager` methods. No new storage primitive

#### 5.4.6 Settings UI

```
```text
Code Context Notes › Agent write mode: [direct | queue | audit ▼]
Code Context Notes › Agent allow-list: [claude-code, cursor-agent]
Code Context Notes › Audit log retention: [last 1000 ops]
Expand Down Expand Up @@ -499,9 +499,9 @@ Workspace can sit on v0.3 indefinitely; only edited notes get rewritten. No mass

Conservative — no legacy note suddenly becomes an `instruction` or gets an expiry.

### 6.3 Frontmatter format
### 6.3 Metadata format

Writer omits any field equal to its default. A plain note that's still just a `context` note on a line range stays the shape it always had.
Bold-label lines, not YAML frontmatter (see §5.1 Storage). Writer omits any field equal to its default. A plain note that's still just a `context` note on a line range stays the shape it always had.

### 6.4 Backward compatibility

Expand Down Expand Up @@ -588,7 +588,7 @@ Exports are a cache, not a source of truth. Markdown files are authoritative.

### 8.1 Test layout

```
```text
src/test/ # extension tests (existing, extended)
packages/code-notes-core/test/ # NEW — extracted core
packages/code-notes-mcp/test/ # NEW — MCP server
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 50 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "code-context-notes",
"displayName": "Code Context Notes - Smart Annotations",
"description": "Add contextual notes to your code with full version history and intelligent tracking",
"version": "0.2.1",
"version": "0.3.0",
Comment thread
jnahian marked this conversation as resolved.
"publisher": "jnahian",
"icon": "images/icon.png",
"galleryBanner": {
Expand Down Expand Up @@ -196,6 +196,28 @@
"title": "View History",
"icon": "$(history)",
"category": "Code Notes"
},
{
"command": "codeContextNotes.regenerateExports",
"title": "Regenerate Exports (INDEX.json / AGENTS.md)",
"category": "Code Notes"
},
{
"command": "codeContextNotes.filterByType",
"title": "Filter Notes by Type…",
"category": "Code Notes",
"icon": "$(filter)"
},
{
"command": "codeContextNotes.toggleExpired",
"title": "Toggle Expired Notes",
"category": "Code Notes",
"icon": "$(eye)"
},
{
"command": "codeContextNotes.setNoteMetadata",
"title": "Set Note Type / Tags / Priority…",
"category": "Code Notes"
}
],
"keybindings": [
Expand Down Expand Up @@ -272,6 +294,16 @@
"command": "codeContextNotes.refreshSidebar",
"when": "view == codeContextNotes.sidebarView",
"group": "navigation@3"
},
{
"command": "codeContextNotes.filterByType",
"when": "view == codeContextNotes.sidebarView",
"group": "navigation"
},
{
"command": "codeContextNotes.toggleExpired",
"when": "view == codeContextNotes.sidebarView",
"group": "navigation"
}
],
"view/item/context": [
Expand Down Expand Up @@ -419,6 +451,21 @@
],
"default": "file",
"description": "Sort notes by file path"
},
"codeContextNotes.exports.enabled": {
"type": "boolean",
"default": true,
"description": "Auto-generate INDEX.json and AGENTS.md in the notes storage directory (default .code-notes) on every note change"
},
"codeContextNotes.exports.indexJson": {
"type": "boolean",
"default": true,
"description": "Generate INDEX.json (machine-readable)"
},
"codeContextNotes.exports.agentsMarkdown": {
"type": "boolean",
"default": true,
"description": "Generate AGENTS.md (human-readable digest)"
}
}
}
Expand All @@ -429,7 +476,8 @@
"compile:tsc": "tsc -p ./",
"watch": "node esbuild.config.js --watch",
"watch:tsc": "tsc -watch -p ./",
"pretest": "npm run compile:tsc",
"clean": "rm -rf out",
"pretest": "npm run clean && npm run compile:tsc",
"lint": "echo 'Linting skipped - eslint not configured'",
"test": "node ./out/test/runTest.js",
"test:unit": "npm run compile:tsc && node ./out/test/runUnitTests.js",
Expand Down
13 changes: 7 additions & 6 deletions src/codeLensProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,9 @@ export class CodeNotesLensProvider implements vscode.CodeLensProvider {
.replace(/\[([^\]]+)\]\([^\)]+\)/g, '$1')
// Remove images
.replace(/!\[([^\]]*)\]\([^\)]+\)/g, '$1')
// Remove headings
.replace(/^#{1,6}\s+/gm, '')
// Remove heading markers (line-start and after whitespace — previews
// are single lines, so stray mid-text markers should go too)
.replace(/(^|\s)#{1,6}\s+/g, '$1')
// Remove blockquotes
.replace(/^>\s+/gm, '')
// Remove list markers
Expand All @@ -155,8 +156,9 @@ export class CodeNotesLensProvider implements vscode.CodeLensProvider {
if (notes.length === 1) {
const note = notes[0];
// Strip markdown formatting and get first line
const plainText = this.stripMarkdown(note.content);
const firstLine = plainText.split('\n')[0];
// Take the first line BEFORE stripping — stripMarkdown collapses
// newlines into spaces, which would merge all lines into one.
const firstLine = this.stripMarkdown(note.content.split('\n')[0]);
const preview = firstLine.length > 50
? firstLine.substring(0, 47) + '...'
: firstLine;
Expand All @@ -171,8 +173,7 @@ export class CodeNotesLensProvider implements vscode.CodeLensProvider {
: uniqueAuthors.join(', ');

// Get preview from first note
const plainText = this.stripMarkdown(notes[0].content);
const firstLine = plainText.split('\n')[0];
const firstLine = this.stripMarkdown(notes[0].content.split('\n')[0]);
const preview = firstLine.length > 35
? firstLine.substring(0, 32) + '...'
: firstLine;
Expand Down
Loading