sensemaking 0.7.2 → 0.9.0

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 (207) hide show
  1. package/README.md +90 -61
  2. package/dist/cjs/cli/check.js +367 -0
  3. package/dist/cjs/cli/check.js.map +1 -0
  4. package/dist/cjs/{commands → cli}/index.js +2 -2
  5. package/dist/cjs/cli/index.js.map +1 -0
  6. package/dist/cjs/{commands → cli}/init.js +3 -0
  7. package/dist/cjs/cli/init.js.map +1 -0
  8. package/dist/cjs/{commands → cli}/map.js +2 -2
  9. package/dist/cjs/cli/map.js.map +1 -0
  10. package/dist/cjs/{commands → cli}/named.d.cts +1 -1
  11. package/dist/cjs/{commands → cli}/named.d.ts +1 -1
  12. package/dist/cjs/cli/named.js +219 -0
  13. package/dist/cjs/cli/named.js.map +1 -0
  14. package/dist/cjs/{commands → cli}/peek.js +2 -2
  15. package/dist/cjs/cli/peek.js.map +1 -0
  16. package/dist/cjs/cli/query.js.map +1 -0
  17. package/dist/cjs/cli/rebuild.js.map +1 -0
  18. package/dist/cjs/cli/search.d.cts +3 -0
  19. package/dist/cjs/cli/search.d.ts +3 -0
  20. package/dist/cjs/{commands/find.js → cli/search.js} +9 -8
  21. package/dist/cjs/cli/search.js.map +1 -0
  22. package/dist/cjs/{commands → cli}/shared.d.cts +1 -0
  23. package/dist/{esm/commands → cjs/cli}/shared.d.ts +1 -0
  24. package/dist/cjs/{commands → cli}/shared.js +9 -0
  25. package/dist/cjs/cli/shared.js.map +1 -0
  26. package/dist/cjs/{commands → cli}/status.js +36 -13
  27. package/dist/cjs/cli/status.js.map +1 -0
  28. package/dist/cjs/{commands → cli}/types.d.cts +3 -1
  29. package/dist/{esm/commands → cjs/cli}/types.d.ts +3 -1
  30. package/dist/cjs/cli/watch.js.map +1 -0
  31. package/dist/cjs/cli.js +42 -17
  32. package/dist/cjs/cli.js.map +1 -1
  33. package/dist/{esm/verbs.d.ts → cjs/commands.d.cts} +15 -5
  34. package/dist/cjs/{verbs.d.cts → commands.d.ts} +15 -5
  35. package/dist/cjs/{verbs.js → commands.js} +329 -39
  36. package/dist/cjs/commands.js.map +1 -0
  37. package/dist/cjs/config.d.cts +45 -12
  38. package/dist/cjs/config.d.ts +45 -12
  39. package/dist/cjs/config.js +464 -125
  40. package/dist/cjs/config.js.map +1 -1
  41. package/dist/cjs/db.d.cts +1 -1
  42. package/dist/cjs/db.d.ts +1 -1
  43. package/dist/cjs/db.js +293 -76
  44. package/dist/cjs/db.js.map +1 -1
  45. package/dist/cjs/errors.d.cts +1 -1
  46. package/dist/cjs/errors.d.ts +1 -1
  47. package/dist/cjs/errors.js.map +1 -1
  48. package/dist/cjs/features/embed.js +19 -3
  49. package/dist/cjs/features/embed.js.map +1 -1
  50. package/dist/cjs/features/links.js +201 -24
  51. package/dist/cjs/features/links.js.map +1 -1
  52. package/dist/cjs/features/rank.js +8 -1
  53. package/dist/cjs/features/rank.js.map +1 -1
  54. package/dist/cjs/features/types.d.cts +12 -4
  55. package/dist/cjs/features/types.d.ts +12 -4
  56. package/dist/cjs/index.d.cts +3 -3
  57. package/dist/cjs/index.d.ts +3 -3
  58. package/dist/cjs/index.js +9 -6
  59. package/dist/cjs/index.js.map +1 -1
  60. package/dist/cjs/output.d.cts +16 -0
  61. package/dist/cjs/output.d.ts +16 -0
  62. package/dist/cjs/output.js +27 -5
  63. package/dist/cjs/output.js.map +1 -1
  64. package/dist/cjs/progress.d.cts +5 -0
  65. package/dist/cjs/progress.d.ts +5 -0
  66. package/dist/cjs/progress.js +54 -0
  67. package/dist/cjs/progress.js.map +1 -0
  68. package/dist/cjs/scan.d.cts +4 -0
  69. package/dist/cjs/scan.d.ts +4 -0
  70. package/dist/cjs/scan.js +87 -6
  71. package/dist/cjs/scan.js.map +1 -1
  72. package/dist/esm/{commands → cli}/check.js +41 -22
  73. package/dist/esm/cli/check.js.map +1 -0
  74. package/dist/esm/{commands → cli}/index.js +1 -1
  75. package/dist/esm/cli/index.js.map +1 -0
  76. package/dist/esm/{commands → cli}/init.js +3 -0
  77. package/dist/esm/cli/init.js.map +1 -0
  78. package/dist/esm/{commands → cli}/map.js +1 -1
  79. package/dist/esm/cli/map.js.map +1 -0
  80. package/dist/esm/{commands → cli}/named.d.ts +1 -1
  81. package/dist/esm/cli/named.js +41 -0
  82. package/dist/esm/cli/named.js.map +1 -0
  83. package/dist/esm/{commands → cli}/peek.js +1 -1
  84. package/dist/esm/cli/peek.js.map +1 -0
  85. package/dist/esm/cli/query.js.map +1 -0
  86. package/dist/esm/cli/rebuild.js.map +1 -0
  87. package/dist/esm/cli/search.d.ts +3 -0
  88. package/dist/esm/cli/search.js +16 -0
  89. package/dist/esm/cli/search.js.map +1 -0
  90. package/dist/{cjs/commands → esm/cli}/shared.d.ts +1 -0
  91. package/dist/esm/{commands → cli}/shared.js +9 -0
  92. package/dist/esm/cli/shared.js.map +1 -0
  93. package/dist/esm/{commands → cli}/status.js +17 -11
  94. package/dist/esm/cli/status.js.map +1 -0
  95. package/dist/{cjs/commands → esm/cli}/types.d.ts +3 -1
  96. package/dist/esm/cli/types.js.map +1 -0
  97. package/dist/esm/cli/watch.js.map +1 -0
  98. package/dist/esm/cli.js +24 -6
  99. package/dist/esm/cli.js.map +1 -1
  100. package/dist/{cjs/verbs.d.ts → esm/commands.d.ts} +15 -5
  101. package/dist/esm/commands.js +386 -0
  102. package/dist/esm/commands.js.map +1 -0
  103. package/dist/esm/config.d.ts +45 -12
  104. package/dist/esm/config.js +367 -93
  105. package/dist/esm/config.js.map +1 -1
  106. package/dist/esm/db.d.ts +1 -1
  107. package/dist/esm/db.js +126 -17
  108. package/dist/esm/db.js.map +1 -1
  109. package/dist/esm/errors.d.ts +1 -1
  110. package/dist/esm/errors.js.map +1 -1
  111. package/dist/esm/features/embed.js +18 -2
  112. package/dist/esm/features/embed.js.map +1 -1
  113. package/dist/esm/features/links.js +130 -20
  114. package/dist/esm/features/links.js.map +1 -1
  115. package/dist/esm/features/rank.js +8 -1
  116. package/dist/esm/features/rank.js.map +1 -1
  117. package/dist/esm/features/types.d.ts +12 -4
  118. package/dist/esm/features/types.js.map +1 -1
  119. package/dist/esm/index.d.ts +3 -3
  120. package/dist/esm/index.js +1 -1
  121. package/dist/esm/index.js.map +1 -1
  122. package/dist/esm/output.d.ts +16 -0
  123. package/dist/esm/output.js +20 -5
  124. package/dist/esm/output.js.map +1 -1
  125. package/dist/esm/progress.d.ts +5 -0
  126. package/dist/esm/progress.js +44 -0
  127. package/dist/esm/progress.js.map +1 -0
  128. package/dist/esm/scan.d.ts +4 -0
  129. package/dist/esm/scan.js +37 -6
  130. package/dist/esm/scan.js.map +1 -1
  131. package/package.json +12 -2
  132. package/schema.json +85 -50
  133. package/skills/sense/EXAMPLES.md +16 -12
  134. package/skills/sense/SKILL.md +74 -55
  135. package/skills/sense-setup/EXAMPLES.md +121 -0
  136. package/skills/sense-setup/SKILL.md +73 -54
  137. package/dist/cjs/commands/check.js +0 -143
  138. package/dist/cjs/commands/check.js.map +0 -1
  139. package/dist/cjs/commands/find.d.cts +0 -3
  140. package/dist/cjs/commands/find.d.ts +0 -3
  141. package/dist/cjs/commands/find.js.map +0 -1
  142. package/dist/cjs/commands/index.js.map +0 -1
  143. package/dist/cjs/commands/init.js.map +0 -1
  144. package/dist/cjs/commands/map.js.map +0 -1
  145. package/dist/cjs/commands/named.js +0 -23
  146. package/dist/cjs/commands/named.js.map +0 -1
  147. package/dist/cjs/commands/peek.js.map +0 -1
  148. package/dist/cjs/commands/query.js.map +0 -1
  149. package/dist/cjs/commands/rebuild.js.map +0 -1
  150. package/dist/cjs/commands/shared.js.map +0 -1
  151. package/dist/cjs/commands/status.js.map +0 -1
  152. package/dist/cjs/commands/watch.js.map +0 -1
  153. package/dist/cjs/verbs.js.map +0 -1
  154. package/dist/esm/commands/check.js.map +0 -1
  155. package/dist/esm/commands/find.d.ts +0 -3
  156. package/dist/esm/commands/find.js +0 -15
  157. package/dist/esm/commands/find.js.map +0 -1
  158. package/dist/esm/commands/index.js.map +0 -1
  159. package/dist/esm/commands/init.js.map +0 -1
  160. package/dist/esm/commands/map.js.map +0 -1
  161. package/dist/esm/commands/named.js +0 -12
  162. package/dist/esm/commands/named.js.map +0 -1
  163. package/dist/esm/commands/peek.js.map +0 -1
  164. package/dist/esm/commands/query.js.map +0 -1
  165. package/dist/esm/commands/rebuild.js.map +0 -1
  166. package/dist/esm/commands/shared.js.map +0 -1
  167. package/dist/esm/commands/status.js.map +0 -1
  168. package/dist/esm/commands/types.js.map +0 -1
  169. package/dist/esm/commands/watch.js.map +0 -1
  170. package/dist/esm/verbs.js +0 -190
  171. package/dist/esm/verbs.js.map +0 -1
  172. /package/dist/cjs/{commands → cli}/check.d.cts +0 -0
  173. /package/dist/cjs/{commands → cli}/check.d.ts +0 -0
  174. /package/dist/cjs/{commands → cli}/index.d.cts +0 -0
  175. /package/dist/cjs/{commands → cli}/index.d.ts +0 -0
  176. /package/dist/cjs/{commands → cli}/init.d.cts +0 -0
  177. /package/dist/cjs/{commands → cli}/init.d.ts +0 -0
  178. /package/dist/cjs/{commands → cli}/map.d.cts +0 -0
  179. /package/dist/cjs/{commands → cli}/map.d.ts +0 -0
  180. /package/dist/cjs/{commands → cli}/peek.d.cts +0 -0
  181. /package/dist/cjs/{commands → cli}/peek.d.ts +0 -0
  182. /package/dist/cjs/{commands → cli}/query.d.cts +0 -0
  183. /package/dist/cjs/{commands → cli}/query.d.ts +0 -0
  184. /package/dist/cjs/{commands → cli}/query.js +0 -0
  185. /package/dist/cjs/{commands → cli}/rebuild.d.cts +0 -0
  186. /package/dist/cjs/{commands → cli}/rebuild.d.ts +0 -0
  187. /package/dist/cjs/{commands → cli}/rebuild.js +0 -0
  188. /package/dist/cjs/{commands → cli}/status.d.cts +0 -0
  189. /package/dist/cjs/{commands → cli}/status.d.ts +0 -0
  190. /package/dist/cjs/{commands → cli}/types.js +0 -0
  191. /package/dist/cjs/{commands → cli}/types.js.map +0 -0
  192. /package/dist/cjs/{commands → cli}/watch.d.cts +0 -0
  193. /package/dist/cjs/{commands → cli}/watch.d.ts +0 -0
  194. /package/dist/cjs/{commands → cli}/watch.js +0 -0
  195. /package/dist/esm/{commands → cli}/check.d.ts +0 -0
  196. /package/dist/esm/{commands → cli}/index.d.ts +0 -0
  197. /package/dist/esm/{commands → cli}/init.d.ts +0 -0
  198. /package/dist/esm/{commands → cli}/map.d.ts +0 -0
  199. /package/dist/esm/{commands → cli}/peek.d.ts +0 -0
  200. /package/dist/esm/{commands → cli}/query.d.ts +0 -0
  201. /package/dist/esm/{commands → cli}/query.js +0 -0
  202. /package/dist/esm/{commands → cli}/rebuild.d.ts +0 -0
  203. /package/dist/esm/{commands → cli}/rebuild.js +0 -0
  204. /package/dist/esm/{commands → cli}/status.d.ts +0 -0
  205. /package/dist/esm/{commands → cli}/types.js +0 -0
  206. /package/dist/esm/{commands → cli}/watch.d.ts +0 -0
  207. /package/dist/esm/{commands → cli}/watch.js +0 -0
@@ -5,31 +5,36 @@ description: Query a markdown tree with the sense CLI — filter notes by frontm
5
5
 
6
6
  # sense
7
7
 
8
- SQL over a markdown tree, kept fresh by a filesystem check on every query. Four tables per file:
9
- `frontmatter` (one column per key, plus `path`/`_mtime`/`_size`/`_rank`), `content` (FTS5:
10
- `title`, `summary`, `text`), `links` (`src`, `target`, `dst` — `NULL` dst = dead link),
11
- `sections` (heading outline with line ranges and token estimates).
8
+ SQL over a markdown tree, kept fresh by a filesystem check on every query. Every file becomes
9
+ rows in `frontmatter` (one column per key, plus `path`/`_mtime`/`_size`/`_rank`), `content`
10
+ (FTS5: `title`, `summary`, `text`), `links` (`src`, `target`, `dst` — `NULL` dst = dead link),
11
+ and `sections` (heading outline with line ranges and token estimates). Features add their own
12
+ storage; `map` and `status` report which are on.
12
13
 
13
14
  ## What each tool is for
14
15
 
15
16
  Every result is a reference (path, metadata, excerpt), never file contents; prose enters
16
- context only when you Read it. Costs: `map` is fixed-size, a `find` row ~30 tokens, `peek`
17
- ~17% of reading the file. Which tool fits is a property of the question:
17
+ context only when you Read it. Costs: `map` is fixed-size, a `search` row is tens of tokens,
18
+ and a `peek` stays flat however large the note is. Which tool fits is a property of the
19
+ question:
18
20
 
19
21
  - A deterministic, factual answer over known fields — counts, filters, "which notes have
20
- X" — is SQL: `sense query`, a named query, or `find --where`. Enumerates every match;
22
+ X" — is SQL: `sense query`, a named query, or `search --where`. Enumerates every match;
21
23
  same result regardless of phrasing.
22
- - Locating notes by words in their prose is `find` — ranked lexical match. Results shift as
23
- phrasing shifts, and bare words AND-join (one absent word = zero rows): write
24
- `a OR b OR c` for any-word matching.
25
- - A conceptual question the notes phrase in different words is `find --semantic` (exists only
26
- on trees whose config enables `embed`): adds meaning-based candidates labeled `via: vector`.
27
- Conceptual similarity, not typo-tolerance; false positives are expected, labeled, and
28
- bounded by `--k`.
24
+ - Locating notes about something is `search` — one text through every engine the scope
25
+ has: word match (bare words AND-join one absent word = zero lexical rows; write
26
+ `a OR b OR c` for any-word), link-graph expansion, and vector similarity, fused into one
27
+ ranked list. Read `via` per row: `match` rows contained your words; `vector`-only rows
28
+ did not they are the "these words aren't in the tree; this is what's near in meaning"
29
+ signal. Vector rows are conceptual similarity, not typo-tolerance; false positives are
30
+ expected, labeled, and bounded by `--k`. `--lexical` skips vectors for one command when
31
+ word-presence is the question.
29
32
  - `map` answers "what is this tree" — fields, hub notes, recent changes — when the tree is
30
33
  unfamiliar.
31
34
  - `peek <path>` prices a file before you pay for it: outline with `[L143-162, ~380t]`
32
- ranges, links both ways.
35
+ ranges, links both ways. Every list shows its first 20 with the true total; the
36
+ `sections` and `links` tables hold the rest, so a peek costs a few hundred tokens on any
37
+ note — heading-dense monsters included.
33
38
  - When you know the file and need its contents, `Read` it — sense adds nothing there. On
34
39
  large files peek's ranges let you read just one section; small files are often cheaper
35
40
  whole.
@@ -37,14 +42,15 @@ context only when you Read it. Costs: `map` is fixed-size, a `find` row ~30 toke
37
42
  Output defaults to a table, built for humans; `--format json` returns the same rows
38
43
  machine-parseable.
39
44
 
40
- ## Verbs
45
+ ## Commands
41
46
 
42
47
  ```
43
- sense find "pricing OR billing OR invoicing" --where "f.status = 'active'" --k 10
48
+ sense search "pricing OR billing OR invoicing" --where "f.status = 'active'" --k 10
49
+ sense search "sourcing quotes" --preset raw # a named settings bundle from the config
44
50
  sense peek notes/pricing-model.md # a unique basename also works
45
51
  sense map
46
52
  sense query "<sql>" [params...] # ad-hoc SQL; ? binds positional args, count-checked
47
- sense <name> [params...] # named query from sense.config.json
53
+ sense <name> [params...] # named query or saved search from sense.config.json
48
54
  sense --list | status | rebuild | check
49
55
  ```
50
56
 
@@ -54,44 +60,52 @@ sense --list | status | rebuild | check
54
60
  rules apply to search commands you write into subagent briefs.
55
61
  - When a search misses, the recall levers are: OR-in synonyms and concrete instances (the
56
62
  index only knows the words in the files — a note about a specific tool rarely names its
57
- category), raise `--k` (a row costs ~30 tokens), and on embed-enabled trees `--semantic`
58
- (matches meaning where term overlap fails). Each widening adds candidates and dilutes
59
- ranking, so the noise trade-off runs both ways.
63
+ category), raise `--k` (a row costs tens of tokens), and widen the scope (`--preset`, or
64
+ `--include` for an ad-hoc glob). Vector rows already cover the meaning-over-words gap by
65
+ default. Each widening adds candidates and dilutes ranking, so the noise trade-off runs
66
+ both ways.
60
67
  - A frontmatter query enumerates its matches deterministically; search ranks by term overlap,
61
68
  so results shift as phrasing shifts. Trade-off: a query needs a known field, search doesn't.
62
- - `find` fuses BM25 with link-graph expansion; the `via` column says what produced each row —
63
- `match` (terms hit), `link` (connected to notes that hit), `match+link` (both). With
64
- `--semantic`, `vector` joins the composition and rows gain a `lines` column pointing at the
65
- best-matching section, a direct `Read` range.
66
- - `--where` takes any SQL condition against frontmatter alias `f` — not only field equality:
67
- `"f.status = 'active' AND has(f.tags, 'x')"`, `"f.path NOT LIKE 'generated/%'"`,
68
- `"f.created >= datetime(?)"`. A tree can declare a default scope in `sense.config.json`
69
- (`defaults.find.where`); an explicit `--where` replaces it, so `--where "1=1"` searches
70
- everything. `sense status` prints the active default.
69
+ - The `via` column says what produced each row — `match` (words hit), `link` (connected to
70
+ notes that hit), `vector` (near in meaning), and combinations. The `lines` column, when
71
+ set, points at the section that earned the row the best-matching chunk on vector rows,
72
+ the term cluster's section on large lexical notes — and is a direct `Read` range; null
73
+ means the whole note is the reference.
74
+ - Scope comes from presets: bare `search` uses the config's `default` preset; `--preset
75
+ <name>` picks another (unknown names error, listing what's declared); `--include <glob>`
76
+ is an ad-hoc scope that replaces the preset's globs for one command. `--where` takes any
77
+ SQL condition against frontmatter alias `f` not only field equality:
78
+ `"f.status = 'active' AND has(f.tags, 'x')"`, `"datetime(f.created) >= datetime(?)"` —
79
+ and filters within the scope. `sense status` shows every preset with its coverage.
71
80
  - `score` is a rank-fusion value: it ranks rows within one result set and is not comparable
72
- across queries, not a relevance magnitude — a perfect lexical hit and a weak vector-only
73
- hit can both read ~0.017, because the number encodes how many signals fired and at what
74
- rank. With `--semantic`, rows carry `similarity`: the cosine (-1 to 1) of the query
75
- against that file's best-matching chunk — the same chunk the `lines` range points at.
76
- It orders vector evidence within a result set; its absolute range depends on the corpus.
77
- Measured: on thousands of notes, unrelated queries ~0.2 and genuine matches ~0.6; on a
78
- few dozen notes the ranges compress and can overlap, because even a nonsense query has a
79
- moderately near neighbour somewhere. Compare similarities within a result set rather than
80
- against a fixed cutoff carried between trees.
81
- - Lexical `find` returns 0 rows when nothing matches, so it answers "is this in the tree at
82
- all". `--semantic` always returns up to `k` rows — nearest-neighbour search has a nearest
83
- neighbour for any input so absence is a lexical question; `similarity` and the snippet
84
- are the evidence for judging whether a vector row is a real hit.
85
- - `sense check` prepares every saved query (catching syntax and unknown-column errors), runs
86
- the ones taking no parameters, and prints row counts: a saved query returning 0 rows looks
87
- the same as a true empty result until something distinguishes them. For queries that
88
- encode invariants (a dead-link list, an unsupported-claims list rows are violations),
89
- `checks: { "<name>": "empty" }` in the config inverts the meaning: `check` fails when the
90
- query returns rows, making it usable as a test suite rather than a linter.
81
+ across queries, not a relevance magnitude — it encodes how many signals fired and at what
82
+ rank, so a perfect lexical hit and a weak vector-only hit can read the same number. With
83
+ vectors active, rows carry `similarity`: the cosine (-1 to 1) of the query against that
84
+ file's best-matching chunk — the same chunk the `lines` range points at. It orders vector
85
+ evidence within a result set; the range it spans depends on the corpus and the embedding
86
+ model, and compresses on small trees, where even a nonsense query has a moderately near
87
+ neighbour somewhere. Compare similarities within a result set rather than against a fixed
88
+ cutoff carried between trees.
89
+ - Absence evidence lives in the labels: `search --lexical` (or a semantic-off scope)
90
+ returns 0 rows when the words are nowhere in the tree. Default `search` always returns
91
+ up to `k` rows — nearest-neighbour search has a nearest neighbour for any input — so a
92
+ result of only `via: vector` rows IS the absence signal for the words themselves;
93
+ `similarity` and the snippet are the evidence for judging whether a vector row is a real
94
+ conceptual hit.
95
+ - Besides SQL strings, a config entry can save a whole search:
96
+ `"hot": { "search": "pricing OR billing", "preset": "raw", "k": 20 }` runs as
97
+ `sense hot` the scenario's settings ride along with the name, so repeat runs need no
98
+ flags. An invocation-level `--preset`, `--k`, `--where`, or `--lexical` overrides the
99
+ saved value; `--list` marks these entries `(search)`.
100
+ - `sense check` prepares every saved query and probes every saved search lexically with
101
+ k=1, so a typo'd column, stale SQL, bad FTS5 syntax, or unknown preset fails at check
102
+ time instead of silently mid-task. It reports row counts; whether an empty result is
103
+ good or bad is the reader's judgment — a dead-link query returning rows means broken
104
+ citations to fix, and the agent reads that directly.
91
105
 
92
106
  ## SQL
93
107
 
94
- The verbs are shorthands over the same four tables; anything they don't express, SQL does.
108
+ The commands are shorthands over those tables; anything they don't express, SQL does.
95
109
 
96
110
  ```
97
111
  sense query "SELECT name FROM pragma_table_info('frontmatter')" # what fields exist
@@ -108,7 +122,11 @@ sense query "SELECT j.value, COUNT(*) n FROM frontmatter, json_each(frontmatter.
108
122
  punctuation — bare `customer-facing` errors (`-` reads as a column filter), bare
109
123
  apostrophes are syntax errors: write `"customer-facing"`, `"founder's"`.
110
124
  - Rank with `ORDER BY bm25(content, 10.0, 5.0, 1.0)` (title > summary > body); excerpt with
111
- `snippet(content, -1, '«', '»', '…', 10)`.
125
+ `snippet(content, -1, '«', '»', '…', 10)`. snippet() re-tokenizes each matched doc and its
126
+ cost grows superlinearly with doc size — measured ~10 s per query on a tree holding one
127
+ 1 MB note. `search` bounds this itself (docs past 16 KB get an equivalent excerpt another
128
+ way); in hand-written SQL, guard it: `CASE WHEN length(text) <= 16384 THEN snippet(...)
129
+ END`, or select `title`/`summary` instead of an excerpt.
112
130
  - Select `content.title`/`content.summary` (always exist, empty when absent) rather than
113
131
  `f.title`/`f.summary` (discovered columns — error on trees that never declare them).
114
132
  - Frontmatter values keep their YAML type: strings are TEXT, whole numbers and booleans are
@@ -136,10 +154,11 @@ Worked traces: [EXAMPLES.md](EXAMPLES.md).
136
154
 
137
155
  - Missing CLI: `npm install -g sensemaking`. Missing config: `sense init` at the tree root.
138
156
  Discovery walks up from cwd; `--config <path>` overrides. Setting up or restructuring a
139
- tree (features, frontmatter conventions, note design) is the `sense-setup` skill.
140
- - `map` and `status` report feature state (`features: links, sections, rank · off: embed
141
- (features.embed)`). Invoking a capability whose feature is off is an error naming the
142
- config key to enable nothing silently falls back.
157
+ tree (presets, frontmatter conventions, note design) is the `sense-setup` skill.
158
+ - `map` and `status` report each preset's coverage (files matched, embedded count)
159
+ indexing derives from presets, so the coverage numbers are how you see what a config
160
+ actually indexes and embeds. A scope with fewer signals just uses fewer (a semantic-off
161
+ preset searches lexically); a saved search naming an unknown preset errors at `check`.
143
162
  - Save a query into `sense.config.json` only when it will be reused; run ad-hoc otherwise.
144
163
  - A one-line `summary:` per note is optional and pays twice: it appears in result rows and is a
145
164
  weighted search field. Date comparisons work for dates written as ISO 8601 (`2026-08-12`, or
@@ -0,0 +1,121 @@
1
+ # sense-setup: worked configurations
2
+
3
+ Four tree shapes, each with its config and the commands an agent actually runs. Field
4
+ names and folder names are illustrative — your tree defines its own.
5
+
6
+ ## A. Compiled wiki over immutable sources (the llm-wiki pattern)
7
+
8
+ `raw/` holds ingested sources — big, never hand-edited. `wiki/` holds agent-compiled
9
+ pages — linked, curated. The human drops sources and asks questions; the agent compiles
10
+ and cites.
11
+
12
+ ```json
13
+ {
14
+ "version": 3,
15
+ "presets": {
16
+ "default": { "include": ["wiki/**/*.md"], "k": 10 },
17
+ "raw": { "include": ["raw/**/*.md"], "k": 5, "semantic": false }
18
+ },
19
+ "queries": {
20
+ "uncompiled": "SELECT path, _mtime FROM frontmatter WHERE path LIKE 'raw/%' AND path NOT IN (SELECT dst FROM links WHERE dst IS NOT NULL) ORDER BY _mtime DESC",
21
+ "stubs": "SELECT path, _size FROM frontmatter WHERE path LIKE 'wiki/%' AND _size < 500 ORDER BY _size",
22
+ "dead-links": "SELECT src, target FROM links WHERE dst IS NULL ORDER BY src"
23
+ }
24
+ }
25
+ ```
26
+
27
+ ```
28
+ sense uncompiled # compile queue: raw files nothing cites yet
29
+ sense search "how does attention scale" # wiki only (default preset), vectors on
30
+ sense search "rotary embeddings" --preset raw # cite from sources; lexical, k=5
31
+ sense dead-links # rows are broken citations to fix
32
+ ```
33
+
34
+ What the shape buys: bare search never ranks raw noise above compiled pages; raw pays no
35
+ vector/link cost; the compile queue, stub list, and citation integrity are one saved
36
+ query each. The maintenance loop is `uncompiled` → write the wiki page citing its sources
37
+ → `dead-links` stays empty.
38
+
39
+ ## B. Nightly agent memory, consolidated (the dreaming pattern)
40
+
41
+ `memory/` accumulates small notes written at session end, each with `project`,
42
+ `created`, and `kind` (observation / steer / decision) frontmatter. A consolidation agent
43
+ runs periodically: prune, merge, surface contradictions for the human. Retired notes move
44
+ to `archive/` — still queryable, no longer embedded or ranked.
45
+
46
+ ```json
47
+ {
48
+ "version": 3,
49
+ "presets": {
50
+ "default": { "include": ["memory/**/*.md"], "k": 10 },
51
+ "archive": { "include": ["archive/**/*.md"], "k": 10, "semantic": false }
52
+ },
53
+ "queries": {
54
+ "project": "SELECT path, kind, created, title FROM frontmatter WHERE project = ? ORDER BY created DESC",
55
+ "steers": "SELECT path, created, title FROM frontmatter WHERE kind = 'steer' AND project = ? ORDER BY created",
56
+ "retirement": "SELECT path, project, created FROM frontmatter WHERE datetime(created) < datetime('now','-90 day') AND path NOT IN (SELECT dst FROM links WHERE dst IS NOT NULL)",
57
+ "unfiled": "SELECT path FROM frontmatter WHERE project IS NULL"
58
+ }
59
+ }
60
+ ```
61
+
62
+ ```
63
+ sense project acme-app # one project's notes, newest first
64
+ sense search "prefers terse commit messages" --k 5
65
+ → memory/acme-app/2026-08-02-commits.md via: match
66
+ → memory/acme-app/2026-06-11-style.md via: vector similarity: 0.71 # near-duplicate → merge candidate
67
+ sense steers acme-app # oldest first: does a new steer override an old one?
68
+ sense retirement # old + uncited → move to archive/
69
+ sense unfiled # rows are notes missing a project — file them
70
+ ```
71
+
72
+ Presets are structural (live vs archived); per-project filtering is metadata (`project = ?`)
73
+ — one tree serves every project. Semantic search over the memory preset is the
74
+ near-duplicate detector: search a new note's own summary and read `similarity` within the
75
+ results. Whether an old steer was overridden is a question for the human — found by
76
+ search, never decided by it.
77
+
78
+ ## C. Evidence corpus: claims trace to sources
79
+
80
+ `sources/` (immutable imports), `notes/` (one reading note per source), `reviews/`
81
+ (synthesis whose claims must cite notes). The same shape fits incident reports and
82
+ postmortems, user research and findings, due diligence and memos.
83
+
84
+ ```json
85
+ {
86
+ "version": 3,
87
+ "presets": {
88
+ "default": { "include": ["reviews/**/*.md", "notes/**/*.md"], "k": 10 },
89
+ "source": { "include": ["sources/**/*.md"], "k": 5, "semantic": false }
90
+ },
91
+ "queries": {
92
+ "unsupported": "SELECT path, title FROM frontmatter WHERE path LIKE 'reviews/%' AND path NOT IN (SELECT src FROM links WHERE dst LIKE 'notes/%')",
93
+ "unread": "SELECT path FROM frontmatter WHERE path LIKE 'sources/%' AND path NOT IN (SELECT dst FROM links WHERE dst IS NOT NULL)",
94
+ "by-topic": "SELECT path, title FROM frontmatter WHERE path NOT LIKE 'sources/%' AND has(topics, ?) ORDER BY path"
95
+ }
96
+ }
97
+ ```
98
+
99
+ ```
100
+ sense search "replication failures in priming studies" # reviews + notes; sources never dilute
101
+ sense search "the claim's exact phrasing" --preset source # citation pull on demand
102
+ sense unsupported # rows are synthesis claims with no note behind them
103
+ sense unread # the reading queue: sources no note cites
104
+ ```
105
+
106
+ ## D. A plain vault: zero configuration
107
+
108
+ Someone else's Obsidian vault, heterogeneous, no structure worth declaring — the
109
+ `sense init` starter untouched. The workflow is discovery:
110
+
111
+ ```
112
+ sense map # fields in use, hub notes, recent changes
113
+ sense search "dataview queries" # words + links + meaning, one ranked list
114
+ sense query "SELECT j.value AS tag, COUNT(*) n FROM frontmatter, json_each(frontmatter.tags) j GROUP BY j.value ORDER BY n DESC LIMIT 20"
115
+ sense peek "Plugins/dataview.md" # outline + links before reading
116
+ ```
117
+
118
+ Presets earn their place only when a tree has parts deserving different treatment; a tree
119
+ that is one kind of thing needs none of the vocabulary above. On a big vault, raise
120
+ `default`'s `k` and read `lines` ranges instead of whole files — or start from the
121
+ starter's `large` preset.
@@ -1,73 +1,91 @@
1
1
  ---
2
2
  name: sense-setup
3
- description: Set up the sense CLI on a markdown tree and make the tree-design decisions that shape it — sense init, enabling features (links, sections, rank, embed), and the trade-offs of frontmatter conventions, summaries, folder layout, and note size. Use when creating or restructuring a markdown knowledge base, running sense init, editing sense.config.json, enabling semantic search, or deciding how notes should be written for an agent to query later.
3
+ description: Set up the sense CLI on a markdown tree and make the tree-design decisions that shape it — sense init, presets (which files, which settings, vectors on or off), and the trade-offs of frontmatter conventions, summaries, folder layout, and note size. Use when creating or restructuring a markdown knowledge base, running sense init, editing sense.config.json, configuring search scope or vectors, or deciding how notes should be written for an agent to query later.
4
4
  ---
5
5
 
6
6
  # sense: setup and tree design
7
7
 
8
8
  Querying an existing tree is the `sense` skill. This one covers making a tree:
9
- installing, configuring features, and the design decisions a tree owner faces.
9
+ installing, writing presets, and the design decisions a tree owner faces.
10
+ Worked configurations for common tree shapes: [EXAMPLES.md](EXAMPLES.md).
10
11
 
11
12
  ## Setup
12
13
 
13
14
  - `npm install -g sensemaking`, then `sense init` at the tree root writes
14
- `sense.config.json` (all opt-out features on, `embed` off). Config discovery
15
- walks up from cwd; `--config <path>` overrides.
16
- - `scan.include` globs resolve relative to the config file, never the cwd.
17
- - `sense map` and `sense status` report feature state
18
- (`features: links, sections, rank · off: embed (features.embed)`), so the
19
- current config is always discoverable from output.
15
+ `sense.config.json` two presets (`default`, and `large` showing what a big
16
+ vault tunes), everything on. Config discovery walks up from cwd;
17
+ `--config <path>` overrides.
18
+ - Globs resolve relative to the config file, never the cwd.
19
+ - `sense status` and `sense map` show each preset's coverage (files matched,
20
+ embedded count), so what a config actually indexes is always visible in
21
+ output. A config edit that changes coverage rebuilds the cache and names the
22
+ preset that caused it on stderr.
20
23
 
21
- ## Features
24
+ ## Presets
22
25
 
23
- | feature | powers | cost when on | config key |
24
- |---|---|---|---|
25
- | `links` | backlinks, dead-link queries, `find`'s link expansion, `peek`'s link lists | link re-resolution at reconcile | `features.links` (default on) |
26
- | `sections` | `peek`'s outline, line-range reads, per-section token estimates | heading extraction at parse | `features.sections` (default on) |
27
- | `rank` | `map`'s hubs, `_rank` in any ORDER BY | PageRank pass at reconcile; requires `links` | `features.rank` (default on) |
28
- | `embed` | `find --semantic` (meaning-based expansion) | vectors computed at reconcile; model download to `~/.cache/sensemaking` on first use; ~40 ms model load per semantic invocation | `features.embed` (default off) |
26
+ A preset is a named, self-contained bundle of settings. `default` (required) is
27
+ what bare commands use; every other preset is addressed by name
28
+ (`sense search "..." --preset raw`, or `"preset": "raw"` in a saved search).
29
+ No inheritance: what a preset states is all it does.
29
30
 
30
- - `embed` accepts `true` (built-in static model) or an object: `model` (Hugging
31
- Face id or local path), `type` (`static` pure-JS built-in, or `api` for any
32
- OpenAI-compatible `/v1/embeddings` endpoint Ollama, LM Studio, llama.cpp,
33
- hosted), `url`, `key` (env var name). A local `model` path is fully offline.
34
- - The two types differ in what they match, not only in cost: `static` is a
35
- context-free distilled model that handles paraphrase and reworded concepts
36
- (a query like "delegating without micromanaging" can reach a note that uses
37
- neither word); tight near-synonyms and domain jargon ("heart attack" for
38
- "myocardial infarction") are where it misses and an `api` transformer model
39
- tends to succeed. The gain concentrates where the searcher's vocabulary
40
- differs from the notes' — measured in the retrieval eval (BENCHMARKING.md,
41
- "Retrieval quality"): on a vocabulary-gap corpus semantic expansion adds
42
- recall; where vocabulary overlaps, BM25 plus link expansion already answers
43
- most queries and vectors mostly reorder.
44
- - Enabling `embed` changes no default `find` result expansion runs only when
45
- a query passes `--semantic`. Invoking `--semantic` on a tree without `embed`
46
- is an error naming the config key.
47
- - Toggling any feature rebuilds the cache on the next query (safe, automatic).
48
- - Disabled features degrade output, visibly: `peek` prints
49
- `sections: off (features.sections)` rather than an empty outline.
31
+ | field | means | default |
32
+ |---|---|---|
33
+ | `include` / `exclude` | which files this preset covers (globs) | required |
34
+ | `k` | how many results a search returns | 10 |
35
+ | `semantic` | vectors for this preset's files and searches | on; only ever written as `false` |
36
+ | `where` | a standing SQL filter on frontmatter | none |
37
+
38
+ **Indexing derives from presets.** A file is indexed if any preset includes it;
39
+ it is embedded if any covering preset has semantic on. Consequences worth
40
+ designing around:
41
+
42
+ - A layer of the tree covered only by a `semantic: false` preset (raw sources,
43
+ archives, generated output) is fully searchable lexically and by SQL but
44
+ costs no vector work the main scale lever.
45
+ - Files no preset includes are not indexed at all.
46
+ - Presets may overlap; they are views, not partitions.
47
+ - The first semantic search embeds everything covered (progress on stderr;
48
+ minutes on tens of thousands of notes, seconds on small trees). Vectors use
49
+ the built-in static model unless a top-level
50
+ `"embed": { "model", "type": "static"|"api", "url", "key" }` block points at
51
+ a Model2Vec model, local path, or OpenAI-compatible endpoint. `static`
52
+ handles paraphrase and reworded concepts; tight domain jargon ("heart
53
+ attack" for "myocardial infarction") is where an `api` transformer model
54
+ tends to do better — measured in BENCHMARKING.md, "Retrieval quality".
55
+ - Global `features` (`links`, `sections`, `rank`) still toggle tree-wide;
56
+ most trees never touch them.
57
+
58
+ **Large vaults**: everything except the vector build is measured linear to
59
+ 100k notes with no tuning (BENCHMARKING.md). The knobs that matter are `k`
60
+ (more, smaller results — rows carry `lines` section ranges, so agents read
61
+ sections, not files) and `semantic: false` on the layers that don't earn
62
+ vectors.
50
63
 
51
64
  ## Tree design decisions
52
65
 
53
66
  These belong to the tree's owner. sense works with any of them and reads no
54
- instruction files of its own; each choice below only changes what queries can
55
- do, and every consequence is listed so the choice can be made deliberately.
67
+ instruction files of its own; each choice only changes what queries can do.
56
68
 
57
69
  - **Frontmatter fields.** Columns are discovered per tree — whatever keys notes
58
70
  declare become queryable. Consistent fields across notes make SQL filters
59
- and named queries possible (`WHERE status = 'active'`). Reserved keys
71
+ and named queries possible (`WHERE status = 'active'`). SQLite's compiled
72
+ column limit (2,000; sqlite.org/limits.html) bounds distinct keys per tree —
73
+ the crawl stops with an error naming the count and the levers. Reserved keys
60
74
  (dropped with a warning): `path`, `_mtime`, `_size`, `_rank`, `content`,
61
75
  `links`, `sections`. Values keep their YAML type: strings TEXT, whole numbers
62
76
  and booleans INTEGER (`true` is 1), fractions REAL, lists and maps JSON text;
63
77
  `map` prints the observed type per field.
78
+ - **Presets are path-shaped; frontmatter is state-shaped.** A preset's coverage
79
+ must be computable from the path alone (it decides indexing, baked into the
80
+ cache). Volatile state (`status`, `project`, dates) lives in frontmatter and
81
+ filters at query time (`where`, `has()`, `datetime()`). A state worth
82
+ different *indexing* (retired memory, superseded sources) is a state worth
83
+ moving the file — the archive-folder pattern in EXAMPLES.md.
64
84
  - **What a note omits is also a filter.** A layer that deliberately carries none
65
85
  of the fields the saved views filter on is excluded from all of them without
66
- any view naming the layer; only a view filtering solely on a field the layer
67
- does share needs an explicit condition (`AND type != 'raw'`). Sparse fields cut
68
- both ways: less of the tree filters when you want breadth, and exactly this
69
- separation when layers differ in authority — source extractions vs.
70
- conclusions, generated output vs. notes.
86
+ any view naming the layer. Sparse fields cut both ways: less of the tree
87
+ filters when you want breadth, and exactly this separation when layers
88
+ differ in authority.
71
89
  - **Dates.** `datetime()` comparisons work for dates written as ISO 8601 —
72
90
  the only format it parses. A tree that mixes date formats can store them,
73
91
  but can't compare them in SQL.
@@ -75,17 +93,18 @@ do, and every consequence is listed so the choice can be made deliberately.
75
93
  every result row (often answering a question with no file read) and is a
76
94
  weighted search field ranked above body text. The cost is writing and
77
95
  maintaining the line as notes change.
78
- - **Folder shape.** sense is structure-indifferent: globs find the files,
79
- paths are queryable text, links resolve by basename at any depth. Folders
80
- are for the humans and agents navigating the tree, not for the index —
81
- flat and nested trees query identically.
82
- - **Note size.** Many small notes: precise `find` hits, whole-file reads stay
83
- cheap, more links to maintain. Fewer large notes: `sections` and `peek`
84
- carry the cost down to line-range reads. Both work; per-section token
85
- estimates exist either way.
96
+ - **Folder shape.** Globs find the files, paths are queryable text, links
97
+ resolve by basename at any depth — but presets make folders meaningful:
98
+ a folder is the natural unit that gets its own coverage and settings.
99
+ - **Note size.** Many small notes: precise search hits, whole-file reads stay
100
+ cheap, more links to maintain. Fewer large notes: `sections`, `peek`, and
101
+ the `lines` column carry the cost down to line-range reads. Both work.
102
+ - **Recurring questions.** Save a scenario an agent will repeat: a SQL string
103
+ for filters and reports, or a saved search
104
+ (`"hot": { "search": "...", "preset": "raw", "k": 5 }`). Either runs as
105
+ `sense <name>`, and `sense check` validates both kinds against the real
106
+ tree, so a broken saved scenario fails at check time, not mid-task.
86
107
  - **Where decisions live.** Choices that should outlive one conversation can
87
108
  be recorded in the agent's own instruction or skill files, or in a note in
88
109
  the tree itself; a one-off search over an existing corpus needs none of
89
- that. Whether to settle a choice with the user or proceed on the corpus as
90
- found depends on whether the agent is only querying or also authoring —
91
- an authoring agent's choices compound; a querying agent's don't.
110
+ that.
@@ -1,143 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "default", {
6
- enumerable: true,
7
- get: function() {
8
- return _default;
9
- }
10
- });
11
- var _dbts = require("../db.js");
12
- var _outputts = require("../output.js");
13
- var _sharedts = require("./shared.js");
14
- function _array_like_to_array(arr, len) {
15
- if (len == null || len > arr.length) len = arr.length;
16
- for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
17
- return arr2;
18
- }
19
- function _array_with_holes(arr) {
20
- if (Array.isArray(arr)) return arr;
21
- }
22
- function _iterable_to_array_limit(arr, i) {
23
- var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
24
- if (_i == null) return;
25
- var _arr = [];
26
- var _n = true;
27
- var _d = false;
28
- var _s, _e;
29
- try {
30
- for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
31
- _arr.push(_s.value);
32
- if (i && _arr.length === i) break;
33
- }
34
- } catch (err) {
35
- _d = true;
36
- _e = err;
37
- } finally{
38
- try {
39
- if (!_n && _i["return"] != null) _i["return"]();
40
- } finally{
41
- if (_d) throw _e;
42
- }
43
- }
44
- return _arr;
45
- }
46
- function _non_iterable_rest() {
47
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
48
- }
49
- function _sliced_to_array(arr, i) {
50
- return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
51
- }
52
- function _unsupported_iterable_to_array(o, minLen) {
53
- if (!o) return;
54
- if (typeof o === "string") return _array_like_to_array(o, minLen);
55
- var n = Object.prototype.toString.call(o).slice(8, -1);
56
- if (n === "Object" && o.constructor) n = o.constructor.name;
57
- if (n === "Map" || n === "Set") return Array.from(n);
58
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
59
- }
60
- // A saved query that returns zero rows looks identical to a true empty result, so a broken
61
- // one can sit unnoticed -- one field report had `WHERE flag = 'true'` against a numeric
62
- // column reading as "nothing tagged yet" for hours. Preparing each query catches syntax and
63
- // unknown-column errors without executing it; queries that take no parameters are also run
64
- // for a row count. Parameterised queries are validated but not counted: inventing arguments
65
- // would report a count for a query nobody ran.
66
- var check = function check(ctx) {
67
- var _cfg_queries;
68
- var cfg = ctx.resolveConfig();
69
- var _open = (0, _dbts.open)(cfg), db = _open.db, warnings = _open.warnings;
70
- (0, _sharedts.printWarnings)(warnings);
71
- var rows = [];
72
- var failed = 0;
73
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
74
- try {
75
- for(var _iterator = Object.entries((_cfg_queries = cfg.queries) !== null && _cfg_queries !== void 0 ? _cfg_queries : {})[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
76
- var _step_value = _sliced_to_array(_step.value, 2), name = _step_value[0], sql = _step_value[1];
77
- var _sql_match;
78
- var _cfg_checks;
79
- var params = ((_sql_match = sql.match(/\?/g)) !== null && _sql_match !== void 0 ? _sql_match : []).length;
80
- var expectEmpty = ((_cfg_checks = cfg.checks) === null || _cfg_checks === void 0 ? void 0 : _cfg_checks[name]) === 'empty';
81
- try {
82
- var statement = db.prepare(sql);
83
- if (params > 0) {
84
- rows.push({
85
- query: name,
86
- params: params,
87
- rows: '—',
88
- status: 'ok (not run: needs parameters)'
89
- });
90
- continue;
91
- }
92
- var count = statement.all().length;
93
- if (expectEmpty) {
94
- // An invariant query: rows are violations, so 0 is the pass, anything else fails.
95
- if (count > 0) failed++;
96
- rows.push({
97
- query: name,
98
- params: params,
99
- rows: count,
100
- status: count === 0 ? 'ok (empty, as asserted)' : "FAILED: expected empty, returned ".concat(count, " row(s)")
101
- });
102
- } else {
103
- rows.push({
104
- query: name,
105
- params: params,
106
- rows: count,
107
- status: count === 0 ? 'ok, but returns 0 rows' : 'ok'
108
- });
109
- }
110
- } catch (err) {
111
- failed++;
112
- rows.push({
113
- query: name,
114
- params: params,
115
- rows: '—',
116
- status: "FAILED: ".concat(err.message)
117
- });
118
- }
119
- }
120
- } catch (err) {
121
- _didIteratorError = true;
122
- _iteratorError = err;
123
- } finally{
124
- try {
125
- if (!_iteratorNormalCompletion && _iterator.return != null) {
126
- _iterator.return();
127
- }
128
- } finally{
129
- if (_didIteratorError) {
130
- throw _iteratorError;
131
- }
132
- }
133
- }
134
- db.close();
135
- if (rows.length === 0) {
136
- console.log('no saved queries in config');
137
- return;
138
- }
139
- (0, _outputts.printRows)(rows, ctx.format);
140
- if (failed > 0) process.exit(1);
141
- };
142
- var _default = check;
143
- /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }