Skip to content

feat: support opening notes by title in bear-open-note#84

Open
vasylenko wants to merge 7 commits intomainfrom
feat/open-note-by-title
Open

feat: support opening notes by title in bear-open-note#84
vasylenko wants to merge 7 commits intomainfrom
feat/open-note-by-title

Conversation

@vasylenko
Copy link
Copy Markdown
Owner

@vasylenko vasylenko commented Mar 10, 2026

Summary

  • bear-open-note now accepts an optional title parameter as an alternative to id, enabling users to open a note by its title in a single tool call without searching first
  • When exactly one note matches the title, returns its full content directly
  • When multiple notes share the same title, returns a disambiguation list with note IDs and modification dates so the user can choose
  • When no note matches, returns a clear not-found response
  • Title matching is case-insensitive; all error responses use soft errors via createToolResponse() to avoid breaking agent flows

Why

Users frequently know the exact title of the note they want to open but currently must call bear-search-notes first to resolve the ID, then call bear-open-note with that ID. Accepting a title directly eliminates this two-step friction.

--
Closes #60

Add title parameter as an alternative to id for direct note lookup.
Case-insensitive matching with disambiguation when multiple notes
share the same title.

Created with Claude Code under the supervision of Serhii Vasylenko
- Return soft error via createToolResponse() instead of throwing when
  neither id nor title is provided (Pattern B consistency)
- Use COLLATE NOCASE instead of LOWER() for idiomatic SQLite case folding
- Improve not-found message to mention partial text match via bear-search-notes
- Add missing test cases: no-args validation and open-by-ID regression

Created with Claude Code under the supervision of Serhii Vasylenko
Ensure note ID is extracted successfully before proceeding to the
actual test step, consistent with the regression test case that
already had this guard.

Created with Claude Code under the supervision of Serhii Vasylenko
Copilot AI review requested due to automatic review settings March 10, 2026 21:36
@vasylenko vasylenko added the enhancement New feature or request label Mar 10, 2026
@vasylenko
Copy link
Copy Markdown
Owner Author

vasylenko commented Mar 10, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds direct title-based lookup to the existing bear-open-note tool so callers can open a note in one step without first running bear-search-notes, including a disambiguation response when multiple notes share a title.

Changes:

  • Extend bear-open-note to accept title (case-insensitive exact match) as an alternative to id, with not-found and multiple-match handling.
  • Add findNotesByTitle() database helper and a lightweight NoteTitleMatch type for disambiguation.
  • Add system tests covering open-by-title behavior, case-insensitive matching, disambiguation, and regression for open-by-id.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
tests/system/open-note-by-title.test.ts Adds end-to-end system coverage for opening notes by title and related edge cases.
src/types.ts Introduces NoteTitleMatch for lightweight title lookup/disambiguation results.
src/notes.ts Adds findNotesByTitle() SQL query helper for case-insensitive exact title matches.
src/main.ts Updates bear-open-note schema/handler to support title lookups and disambiguation responses.

You can also share your feedback on Copilot code review. Take the survey.

// Both IDs should appear in the disambiguation list
for (const id of noteIds) {
expect(openResult).toContain(id);
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The disambiguation test asserts IDs are present but doesn’t assert that modification dates are included, which is part of the acceptance criteria. Add an assertion that the response contains a "modified:" field (or matches a date/ISO pattern) to prevent regressions in the disambiguation output.

Suggested change
}
}
// Disambiguation entries should include modification metadata
expect(openResult).toMatch(/modified\s*:/);

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point — fixed in 43e2cf9. Added expect(openResult).toMatch(/modified:\s*\d{4}-\d{2}-\d{2}/) to verify date metadata is present in the disambiguation output.

src/main.ts Outdated
const matchList = matches
.map(
(m, i) =>
`${i + 1}. ID: ${m.identifier} (modified: ${new Date(m.modification_date).toLocaleDateString()})`
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The disambiguation output formats modification dates with toLocaleDateString(), which is locale/timezone dependent and drops the time component. This can produce inconsistent results across environments/agents. Prefer emitting the already-ISO modification_date string (or a fixed UTC/ISO format) for deterministic output.

Suggested change
`${i + 1}. ID: ${m.identifier} (modified: ${new Date(m.modification_date).toLocaleDateString()})`
`${i + 1}. ID: ${m.identifier} (modified: ${m.modification_date})`

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid catch — fixed in 43e2cf9. Now using the ISO modification_date string directly instead of toLocaleDateString(), which gives deterministic output across environments.

Replace toLocaleDateString() with the ISO modification_date string
for deterministic, locale-independent output. Add assertion that
disambiguation response includes modification date metadata.

Created with Claude Code under the supervision of Serhii Vasylenko
Regression guard for the ZTRASHED/ZARCHIVED/ZENCRYPTED filters in
findNotesByTitle — this filter class has regressed before (bf5fe71).

Created with Claude Code under the supervision of Serhii Vasylenko
Copilot AI review requested due to automatic review settings March 11, 2026 08:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.


You can also share your feedback on Copilot code review. Take the survey.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.


You can also share your feedback on Copilot code review. Take the survey.

Replace length check with Set-based uniqueness assertion to catch
the case where awaitNoteCreation returns the same ID twice.

Created with Claude Code under the supervision of Serhii Vasylenko
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.


You can also share your feedback on Copilot code review. Take the survey.

Created with Claude Code under the supervision of Serhii Vasylenko
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: open note by title

2 participants