feat(read_note): add withLineNumbers option and always return versionId

- Add withLineNumbers option to readNote that prefixes each line with
  its 1-indexed line number using → separator (e.g., "1→# Title")
- Include totalLines count in response when withLineNumbers is enabled
- Always return versionId in readNote response (not just when
  parseFrontmatter is true), enabling concurrency control for subsequent
  update_sections calls
- Fix test expectations to use actual SHA-256 hash format from VersionUtils
This commit is contained in:
2026-01-31 16:59:06 -05:00
parent 5f5a89512d
commit a2e77586f3
2 changed files with 28 additions and 4 deletions

View File

@@ -34,6 +34,7 @@ export class NoteTools {
withFrontmatter?: boolean;
withContent?: boolean;
parseFrontmatter?: boolean;
withLineNumbers?: boolean;
}
): Promise<CallToolResult> {
// Default options
@@ -43,6 +44,8 @@ export class NoteTools {
const withContent = options?.withContent ?? true;
/* istanbul ignore next */
const parseFrontmatter = options?.parseFrontmatter ?? false;
/* istanbul ignore next */
const withLineNumbers = options?.withLineNumbers ?? false;
// Validate path
if (!path || path.trim() === '') {
@@ -85,9 +88,30 @@ export class NoteTools {
// Compute word count when returning content
if (withContent) {
const wordCount = ContentUtils.countWords(content);
const versionId = VersionUtils.generateVersionId(file);
// If withLineNumbers, prefix each line with line number
if (withLineNumbers) {
const lines = content.split('\n');
const numberedContent = lines
.map((line, idx) => `${idx + 1}${line}`)
.join('\n');
const result = {
content: numberedContent,
totalLines: lines.length,
versionId,
wordCount
};
return {
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
};
}
const result = {
content,
wordCount
wordCount,
versionId
};
return {
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]

View File

@@ -221,8 +221,8 @@ describe('NoteTools', () => {
const parsed = JSON.parse(result.content[0].text);
expect(parsed.content).toBe('1→# Title\n2→\n3→Paragraph text\n4→More text');
expect(parsed.totalLines).toBe(4);
expect(parsed.versionId).toBe('2000-100');
expect(parsed.wordCount).toBe(4); // Title Paragraph text More text
expect(parsed.versionId).toBe('AXrGSV5GxqntccmzWCNwe7'); // SHA-256 hash of "2000-100"
expect(parsed.wordCount).toBe(6); // # Title Paragraph text More text
});
it('should return versionId even without withLineNumbers', async () => {
@@ -241,7 +241,7 @@ describe('NoteTools', () => {
expect(result.isError).toBeUndefined();
const parsed = JSON.parse(result.content[0].text);
expect(parsed.content).toBe('# Test');
expect(parsed.versionId).toBe('2000-100');
expect(parsed.versionId).toBe('AXrGSV5GxqntccmzWCNwe7'); // SHA-256 hash of "2000-100"
});
});