sensemaking 0.14.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/cjs/commands/peek.js +3 -3
  2. package/dist/cjs/commands/peek.js.map +1 -1
  3. package/dist/cjs/commands/related.js +2 -2
  4. package/dist/cjs/commands/related.js.map +1 -1
  5. package/dist/cjs/db/open.d.cts +1 -1
  6. package/dist/cjs/db/open.d.ts +1 -1
  7. package/dist/cjs/db/open.js +1 -1
  8. package/dist/cjs/db/open.js.map +1 -1
  9. package/dist/cjs/features/embed.js +4 -6
  10. package/dist/cjs/features/embed.js.map +1 -1
  11. package/dist/cjs/features/links.js +100 -16
  12. package/dist/cjs/features/links.js.map +1 -1
  13. package/dist/cjs/features/sections.js +4 -6
  14. package/dist/cjs/features/sections.js.map +1 -1
  15. package/dist/cjs/features/tags.js +129 -11
  16. package/dist/cjs/features/tags.js.map +1 -1
  17. package/dist/cjs/fences.d.cts +12 -0
  18. package/dist/cjs/fences.d.ts +12 -0
  19. package/dist/cjs/fences.js +157 -0
  20. package/dist/cjs/fences.js.map +1 -0
  21. package/dist/esm/commands/peek.js +3 -3
  22. package/dist/esm/commands/peek.js.map +1 -1
  23. package/dist/esm/commands/related.js +2 -2
  24. package/dist/esm/commands/related.js.map +1 -1
  25. package/dist/esm/db/open.d.ts +1 -1
  26. package/dist/esm/db/open.js +1 -1
  27. package/dist/esm/db/open.js.map +1 -1
  28. package/dist/esm/features/embed.js +4 -6
  29. package/dist/esm/features/embed.js.map +1 -1
  30. package/dist/esm/features/links.js +63 -15
  31. package/dist/esm/features/links.js.map +1 -1
  32. package/dist/esm/features/sections.js +4 -6
  33. package/dist/esm/features/sections.js.map +1 -1
  34. package/dist/esm/features/tags.js +127 -9
  35. package/dist/esm/features/tags.js.map +1 -1
  36. package/dist/esm/fences.d.ts +12 -0
  37. package/dist/esm/fences.js +138 -0
  38. package/dist/esm/fences.js.map +1 -0
  39. package/package.json +1 -1
  40. package/skills/sense/SKILL.md +1 -1
@@ -0,0 +1,138 @@
1
+ // Shared line-fence tracker for tags/sections/embed. Opener: >=3 backticks or tildes at column
2
+ // 0 -- no indent allowance, a deliberate divergence from CommonMark's up-to-3-space rule (see
3
+ // test/unit/fences.test.ts DIVERGENCES table). A backtick opener's info string must not itself
4
+ // contain a backtick (spec rule). A closer is a run of the SAME character, length >= the
5
+ // opener's, holding nothing but trailing spaces after the run.
6
+ const BACKTICK_OPEN = /^(`{3,})(.*)$/;
7
+ const TILDE_OPEN = /^(~{3,})(.*)$/;
8
+ export function fenceTracker() {
9
+ let inFence = false;
10
+ let fenceChar = '';
11
+ let fenceLen = 0;
12
+ return {
13
+ feed (line) {
14
+ if (!inFence) {
15
+ const bt = BACKTICK_OPEN.exec(line);
16
+ if (bt && !bt[2].includes('`')) {
17
+ inFence = true;
18
+ fenceChar = '`';
19
+ fenceLen = bt[1].length;
20
+ return true;
21
+ }
22
+ const td = TILDE_OPEN.exec(line);
23
+ if (td) {
24
+ inFence = true;
25
+ fenceChar = '~';
26
+ fenceLen = td[1].length;
27
+ return true;
28
+ }
29
+ return false;
30
+ }
31
+ const run = fenceChar === '`' ? /^(`+)(.*)$/ : /^(~+)(.*)$/;
32
+ const m = run.exec(line);
33
+ if (m && m[1].length >= fenceLen && m[2].trim() === '') {
34
+ inFence = false;
35
+ return true;
36
+ }
37
+ return false;
38
+ },
39
+ get inFence () {
40
+ return inFence;
41
+ }
42
+ };
43
+ }
44
+ export function commentTracker() {
45
+ let inComment = false;
46
+ return {
47
+ mask (line) {
48
+ let out = '';
49
+ let i = 0;
50
+ while(i < line.length){
51
+ if (inComment) {
52
+ const end = line.indexOf('-->', i);
53
+ if (end === -1) {
54
+ out += ' '.repeat(line.length - i);
55
+ i = line.length;
56
+ } else {
57
+ out += ' '.repeat(end + 3 - i);
58
+ i = end + 3;
59
+ inComment = false;
60
+ }
61
+ continue;
62
+ }
63
+ const start = line.indexOf('<!--', i);
64
+ if (start === -1) {
65
+ out += line.slice(i);
66
+ i = line.length;
67
+ } else {
68
+ out += `${line.slice(i, start)} `;
69
+ i = start + 4;
70
+ inComment = true;
71
+ }
72
+ }
73
+ return out;
74
+ },
75
+ get inComment () {
76
+ return inComment;
77
+ }
78
+ };
79
+ }
80
+ // Body with fenced-code regions (delimiter and content lines) and <!-- --> comment spans
81
+ // replaced by spaces, newlines preserved so line numbers and offsets survive. Bodies without a
82
+ // backtick/tilde/`<!--` fast-path out untouched.
83
+ export function maskRegions(body) {
84
+ if (!/[`~]/.test(body) && !body.includes('<!--')) return body;
85
+ const fence = fenceTracker();
86
+ const comment = commentTracker();
87
+ return body.split('\n').map((line)=>{
88
+ if (!comment.inComment) {
89
+ const isDelim = fence.feed(line);
90
+ if (isDelim || fence.inFence) return ' '.repeat(line.length);
91
+ }
92
+ const uncommented = comment.mask(line);
93
+ // Inline code spans hide their content too: `[[x]]` in prose is not a link.
94
+ return uncommented.includes('`') ? maskCodeSpans(uncommented) : uncommented;
95
+ }).join('\n');
96
+ }
97
+ // A code span opens on a run of N backticks and closes at the next run of exactly N -- a
98
+ // shorter or longer run in between is literal text, not a delimiter (CommonMark code spans).
99
+ // Masked with spaces so column positions and tag-boundary whitespace are unaffected.
100
+ export function maskCodeSpans(line) {
101
+ let out = '';
102
+ let i = 0;
103
+ while(i < line.length){
104
+ if (line[i] !== '`') {
105
+ out += line[i];
106
+ i++;
107
+ continue;
108
+ }
109
+ let j = i;
110
+ while(line[j] === '`')j++;
111
+ const n = j - i;
112
+ let k = j;
113
+ let closeStart = -1;
114
+ let closeEnd = -1;
115
+ while(k < line.length){
116
+ if (line[k] !== '`') {
117
+ k++;
118
+ continue;
119
+ }
120
+ let m = k;
121
+ while(line[m] === '`')m++;
122
+ if (m - k === n) {
123
+ closeStart = k;
124
+ closeEnd = m;
125
+ break;
126
+ }
127
+ k = m;
128
+ }
129
+ if (closeStart >= 0) {
130
+ out += ' '.repeat(closeEnd - i);
131
+ i = closeEnd;
132
+ } else {
133
+ out += line.slice(i, j);
134
+ i = j;
135
+ }
136
+ }
137
+ return out;
138
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/fences.ts"],"sourcesContent":["// Shared line-fence tracker for tags/sections/embed. Opener: >=3 backticks or tildes at column\n// 0 -- no indent allowance, a deliberate divergence from CommonMark's up-to-3-space rule (see\n// test/unit/fences.test.ts DIVERGENCES table). A backtick opener's info string must not itself\n// contain a backtick (spec rule). A closer is a run of the SAME character, length >= the\n// opener's, holding nothing but trailing spaces after the run.\n\nexport interface FenceTracker {\n feed(line: string): boolean; // true iff this line is a fence delimiter (open or close)\n readonly inFence: boolean;\n}\n\nconst BACKTICK_OPEN = /^(`{3,})(.*)$/;\nconst TILDE_OPEN = /^(~{3,})(.*)$/;\n\nexport function fenceTracker(): FenceTracker {\n let inFence = false;\n let fenceChar = '';\n let fenceLen = 0;\n return {\n feed(line: string): boolean {\n if (!inFence) {\n const bt = BACKTICK_OPEN.exec(line);\n if (bt && !bt[2].includes('`')) {\n inFence = true;\n fenceChar = '`';\n fenceLen = bt[1].length;\n return true;\n }\n const td = TILDE_OPEN.exec(line);\n if (td) {\n inFence = true;\n fenceChar = '~';\n fenceLen = td[1].length;\n return true;\n }\n return false;\n }\n const run = fenceChar === '`' ? /^(`+)(.*)$/ : /^(~+)(.*)$/;\n const m = run.exec(line);\n if (m && m[1].length >= fenceLen && m[2].trim() === '') {\n inFence = false;\n return true;\n }\n return false;\n },\n get inFence() {\n return inFence;\n },\n };\n}\n\n// Masks <!-- ... --> spans that may cross line boundaries, one line at a time so callers can\n// interleave it with their own per-line state. An unclosed <!-- masks to end of input, matching\n// CommonMark type-2 HTML comments' practical effect (everything after is swallowed).\nexport interface CommentTracker {\n mask(line: string): string;\n readonly inComment: boolean;\n}\n\nexport function commentTracker(): CommentTracker {\n let inComment = false;\n return {\n mask(line: string): string {\n let out = '';\n let i = 0;\n while (i < line.length) {\n if (inComment) {\n const end = line.indexOf('-->', i);\n if (end === -1) {\n out += ' '.repeat(line.length - i);\n i = line.length;\n } else {\n out += ' '.repeat(end + 3 - i);\n i = end + 3;\n inComment = false;\n }\n continue;\n }\n const start = line.indexOf('<!--', i);\n if (start === -1) {\n out += line.slice(i);\n i = line.length;\n } else {\n out += `${line.slice(i, start)} `;\n i = start + 4;\n inComment = true;\n }\n }\n return out;\n },\n get inComment() {\n return inComment;\n },\n };\n}\n\n// Body with fenced-code regions (delimiter and content lines) and <!-- --> comment spans\n// replaced by spaces, newlines preserved so line numbers and offsets survive. Bodies without a\n// backtick/tilde/`<!--` fast-path out untouched.\nexport function maskRegions(body: string): string {\n if (!/[`~]/.test(body) && !body.includes('<!--')) return body;\n const fence = fenceTracker();\n const comment = commentTracker();\n return body\n .split('\\n')\n .map((line) => {\n if (!comment.inComment) {\n const isDelim = fence.feed(line);\n if (isDelim || fence.inFence) return ' '.repeat(line.length);\n }\n const uncommented = comment.mask(line);\n // Inline code spans hide their content too: `[[x]]` in prose is not a link.\n return uncommented.includes('`') ? maskCodeSpans(uncommented) : uncommented;\n })\n .join('\\n');\n}\n\n// A code span opens on a run of N backticks and closes at the next run of exactly N -- a\n// shorter or longer run in between is literal text, not a delimiter (CommonMark code spans).\n// Masked with spaces so column positions and tag-boundary whitespace are unaffected.\nexport function maskCodeSpans(line: string): string {\n let out = '';\n let i = 0;\n while (i < line.length) {\n if (line[i] !== '`') {\n out += line[i];\n i++;\n continue;\n }\n let j = i;\n while (line[j] === '`') j++;\n const n = j - i;\n let k = j;\n let closeStart = -1;\n let closeEnd = -1;\n while (k < line.length) {\n if (line[k] !== '`') {\n k++;\n continue;\n }\n let m = k;\n while (line[m] === '`') m++;\n if (m - k === n) {\n closeStart = k;\n closeEnd = m;\n break;\n }\n k = m;\n }\n if (closeStart >= 0) {\n out += ' '.repeat(closeEnd - i);\n i = closeEnd;\n } else {\n out += line.slice(i, j);\n i = j;\n }\n }\n return out;\n}\n"],"names":["BACKTICK_OPEN","TILDE_OPEN","fenceTracker","inFence","fenceChar","fenceLen","feed","line","bt","exec","includes","length","td","run","m","trim","commentTracker","inComment","mask","out","i","end","indexOf","repeat","start","slice","maskRegions","body","test","fence","comment","split","map","isDelim","uncommented","maskCodeSpans","join","j","n","k","closeStart","closeEnd"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sensemaking",
3
- "version": "0.14.0",
3
+ "version": "0.15.1",
4
4
  "description": "Query and search your markdown notes with context-aware progressive disclosure: SQL over frontmatter, links, and text, plus semantic search and link-graph ranking. No server, no build step",
5
5
  "keywords": [
6
6
  "markdown",
@@ -5,7 +5,7 @@ description: "Query a markdown tree with the sense CLI: filter notes by frontmat
5
5
 
6
6
  # sense
7
7
 
8
- SQL over a markdown tree, kept fresh by a filesystem check on every query. Every file becomes rows in `frontmatter` (one column per key, plus `path`/`_mtime`/`_ctime`/`_size`/`_rank`/`_parse_error`; `_ctime` is filesystem birthtime, which a clone or copy resets just like `_mtime`), `content` (FTS5: `title`, `summary`, `text`, `path`, plus machine-written `title_seg`/`summary_seg`/`text_seg` sidecars used for matching Chinese, Japanese, Thai, Khmer, Lao, and Burmese text, not for reading), `links` (`src`, `target`, `dst`, `embed`; `NULL` dst = dead link; `embed` 1 for `![[...]]` embeds, 0 for links; one row per distinct written target and kind with alias and anchor stripped, so `[[Foo]]` and `[[Foo|alias]]` are one row while `[[Foo]]` and `[[notes/Foo]]` are two rows that can share a `dst`, and a target both linked and embedded is a row of each kind), `tags` (`path`, `tag`: frontmatter and inline `#tags` merged and deduplicated; nested tags stored full, so `book/scifi` matches `tag = 'book' OR tag LIKE 'book/%'`), `sections` (heading outline with line ranges and token estimates), and `preset_files` (`path`, `preset`: which presets cover which files). Features add their own storage; `map` and `status` report which are on.
8
+ SQL over a markdown tree, kept fresh by a filesystem check on every query. Every file becomes rows in `frontmatter` (one column per key, plus `path`/`_mtime`/`_ctime`/`_size`/`_rank`/`_parse_error`; `_ctime` is filesystem birthtime, which a clone or copy resets just like `_mtime`), `content` (FTS5: `title`, `summary`, `text`, `path`, plus machine-written `title_seg`/`summary_seg`/`text_seg` sidecars used for matching Chinese, Japanese, Thai, Khmer, Lao, and Burmese text, not for reading), `links` (`src`, `target`, `dst`, `embed`; `NULL` dst = dead link; `embed` 1 for `![[...]]` embeds, 0 for links; one row per distinct written target and kind with alias and anchor stripped, so `[[Foo]]` and `[[Foo|alias]]` are one row while `[[Foo]]` and `[[notes/Foo]]` are two rows that can share a `dst`, and a target both linked and embedded is a row of each kind; extraction matches Obsidian's own graph: comments, code, and link-syntax text yield no rows, `[[#Anchor]]` is a self-edge, a frontmatter value that is exactly `[[X]]` is a link, and a basename collision resolves to the linking note itself, else the shortest path), `tags` (`path`, `tag`: frontmatter and inline `#tags` merged and deduplicated; nested tags stored full, so `book/scifi` matches `tag = 'book' OR tag LIKE 'book/%'`), `sections` (heading outline with line ranges and token estimates), and `preset_files` (`path`, `preset`: which presets cover which files). Features add their own storage; `map` and `status` report which are on.
9
9
 
10
10
  ## What each tool is for
11
11