sensemaking 0.10.0 → 0.11.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 (95) hide show
  1. package/README.md +6 -7
  2. package/dist/cjs/cli/index.d.cts +1 -3
  3. package/dist/cjs/cli/index.d.ts +1 -3
  4. package/dist/cjs/cli/index.js +1 -13
  5. package/dist/cjs/cli/index.js.map +1 -1
  6. package/dist/cjs/cli/named.js +3 -1
  7. package/dist/cjs/cli/named.js.map +1 -1
  8. package/dist/cjs/cli/shared.d.cts +1 -1
  9. package/dist/cjs/cli/shared.d.ts +1 -1
  10. package/dist/cjs/cli/shared.js +21 -1
  11. package/dist/cjs/cli/shared.js.map +1 -1
  12. package/dist/cjs/cli/sql.js +30 -2
  13. package/dist/cjs/cli/sql.js.map +1 -1
  14. package/dist/cjs/cli/status.d.cts +1 -0
  15. package/dist/cjs/cli/status.d.ts +1 -0
  16. package/dist/cjs/cli/status.js +76 -13
  17. package/dist/cjs/cli/status.js.map +1 -1
  18. package/dist/cjs/commands.d.cts +2 -1
  19. package/dist/cjs/commands.d.ts +2 -1
  20. package/dist/cjs/commands.js +32 -12
  21. package/dist/cjs/commands.js.map +1 -1
  22. package/dist/cjs/db.d.cts +2 -2
  23. package/dist/cjs/db.d.ts +2 -2
  24. package/dist/cjs/db.js +11 -12
  25. package/dist/cjs/db.js.map +1 -1
  26. package/dist/cjs/errors.d.cts +1 -1
  27. package/dist/cjs/errors.d.ts +1 -1
  28. package/dist/cjs/errors.js.map +1 -1
  29. package/dist/cjs/features/embed.d.cts +1 -0
  30. package/dist/cjs/features/embed.d.ts +1 -0
  31. package/dist/cjs/features/embed.js +31 -9
  32. package/dist/cjs/features/embed.js.map +1 -1
  33. package/dist/cjs/index.d.cts +1 -1
  34. package/dist/cjs/index.d.ts +1 -1
  35. package/dist/cjs/index.js +3 -3
  36. package/dist/cjs/index.js.map +1 -1
  37. package/dist/cjs/output.d.cts +3 -0
  38. package/dist/cjs/output.d.ts +3 -0
  39. package/dist/cjs/output.js +6 -1
  40. package/dist/cjs/output.js.map +1 -1
  41. package/dist/cjs/scan.d.cts +1 -0
  42. package/dist/cjs/scan.d.ts +1 -0
  43. package/dist/cjs/scan.js +83 -12
  44. package/dist/cjs/scan.js.map +1 -1
  45. package/dist/esm/cli/index.d.ts +1 -3
  46. package/dist/esm/cli/index.js +1 -5
  47. package/dist/esm/cli/index.js.map +1 -1
  48. package/dist/esm/cli/named.js +3 -1
  49. package/dist/esm/cli/named.js.map +1 -1
  50. package/dist/esm/cli/shared.d.ts +1 -1
  51. package/dist/esm/cli/shared.js +21 -1
  52. package/dist/esm/cli/shared.js.map +1 -1
  53. package/dist/esm/cli/sql.js +5 -2
  54. package/dist/esm/cli/sql.js.map +1 -1
  55. package/dist/esm/cli/status.d.ts +1 -0
  56. package/dist/esm/cli/status.js +70 -13
  57. package/dist/esm/cli/status.js.map +1 -1
  58. package/dist/esm/commands.d.ts +2 -1
  59. package/dist/esm/commands.js +30 -10
  60. package/dist/esm/commands.js.map +1 -1
  61. package/dist/esm/db.d.ts +2 -2
  62. package/dist/esm/db.js +12 -10
  63. package/dist/esm/db.js.map +1 -1
  64. package/dist/esm/errors.d.ts +1 -1
  65. package/dist/esm/errors.js.map +1 -1
  66. package/dist/esm/features/embed.d.ts +1 -0
  67. package/dist/esm/features/embed.js +29 -9
  68. package/dist/esm/features/embed.js.map +1 -1
  69. package/dist/esm/index.d.ts +1 -1
  70. package/dist/esm/index.js +1 -1
  71. package/dist/esm/index.js.map +1 -1
  72. package/dist/esm/output.d.ts +3 -0
  73. package/dist/esm/output.js +6 -1
  74. package/dist/esm/output.js.map +1 -1
  75. package/dist/esm/scan.d.ts +1 -0
  76. package/dist/esm/scan.js +82 -13
  77. package/dist/esm/scan.js.map +1 -1
  78. package/package.json +1 -1
  79. package/schema.json +1 -1
  80. package/skills/sense/SKILL.md +16 -10
  81. package/skills/sense-setup/SKILL.md +2 -2
  82. package/dist/cjs/cli/check.d.cts +0 -3
  83. package/dist/cjs/cli/check.d.ts +0 -3
  84. package/dist/cjs/cli/check.js +0 -392
  85. package/dist/cjs/cli/check.js.map +0 -1
  86. package/dist/cjs/cli/rebuild.d.cts +0 -3
  87. package/dist/cjs/cli/rebuild.d.ts +0 -3
  88. package/dist/cjs/cli/rebuild.js +0 -50
  89. package/dist/cjs/cli/rebuild.js.map +0 -1
  90. package/dist/esm/cli/check.d.ts +0 -3
  91. package/dist/esm/cli/check.js +0 -88
  92. package/dist/esm/cli/check.js.map +0 -1
  93. package/dist/esm/cli/rebuild.d.ts +0 -3
  94. package/dist/esm/cli/rebuild.js +0 -13
  95. package/dist/esm/cli/rebuild.js.map +0 -1
package/README.md CHANGED
@@ -31,10 +31,11 @@ Every file becomes rows in these tables, plus whatever an enabled feature adds o
31
31
 
32
32
  | table | holds | for |
33
33
  |---|---|---|
34
- | `frontmatter` | one column per key, plus `path`, `_mtime`, `_size`, `_rank` | filtering |
34
+ | `frontmatter` | one column per key, plus `path`, `_mtime`, `_size`, `_rank`, `_parse_error` | filtering |
35
35
  | `content` | FTS5 index: `title`, `summary`, `text` | search and ranking |
36
- | `links` | `src`, `target` as written, `dst` resolved (`NULL` = dead link) | graph |
36
+ | `links` | `src`, `target` as written, `dst` resolved (`NULL` = dead link, but see the skill: a link to an attachment can never resolve) | graph |
37
37
  | `sections` | heading, `level`, `start_line`, `end_line`, `tokens` estimate | structure |
38
+ | `preset_files` | `path`, `preset` | which presets cover which files; `sql --preset` binds these as a `scope` table to join, since `sql` is otherwise index-wide |
38
39
 
39
40
  Results are references (path, title, summary, excerpt), never file contents. Reading happens afterward through the filesystem, scoped to the line ranges `peek` returns. This is the [just-in-time context pattern](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents): the agent holds lightweight identifiers and loads payloads only when needed.
40
41
 
@@ -57,12 +58,10 @@ ORDER BY bm25(content, 10.0, 5.0, 1.0) LIMIT 10
57
58
  | `peek <path> [--preset name] [--where "<sql>"]` | frontmatter + heading outline (`[L143-162, ~380t]`) + links both ways (first 20 per list, each with its total) |
58
59
  | `path <a> <b> [--max-depth n] [--preset name] [--where "<sql>"]` | shortest link chain between two notes, or none within the bound |
59
60
  | `related <note> [--k n] [--preset name] [--where "<sql>"]` | notes similar in meaning that `<note>` does not yet link to; reads vectors, so semantic-search cost |
60
- | `sql "<statement>" [params...]` | ad-hoc SQL over all the tables; `?` binds positional args |
61
+ | `sql "<statement>" [params...] [--preset name]` | ad-hoc SQL over all the tables; `?` binds positional args. Index-wide by default; `--preset` binds the preset's paths as a `scope` table the statement joins |
61
62
  | `<name> [params...]` | run a query saved in the config; `--list` names them |
62
63
  | `init` | write a starter `sense.config.json` |
63
64
  | `status` | index location, doc count, per-preset coverage, watcher heartbeat |
64
- | `check` | run every saved query, so a broken one fails here instead of mid-task |
65
- | `rebuild` | delete the cache and re-crawl |
66
65
  | `download` | fetch the embedding model named in the config (once per machine; nothing else downloads it) |
67
66
  | `watch` | keep the index warm in the background (optional; see [WATCH.md](WATCH.md)) |
68
67
 
@@ -93,7 +92,7 @@ ORDER BY bm25(content, 10.0, 5.0, 1.0) LIMIT 10
93
92
  |---|---|
94
93
  | `presets` | named bundles of `include`/`exclude` globs, `k` (result count), `semantic` (vectors for this scope, on unless `false`), `where` (a standing SQL filter). A file is indexed if any preset includes it, embedded if a model is named and some covering preset has `semantic` on; `status` shows each preset's coverage. |
95
94
  | `embed` | the model vectors are built with. Naming one gives the tree vectors; omitting the block means none at all, whatever the presets say. `sense download` fetches it. |
96
- | `queries` | entries runnable as `sense <name>`, each naming the verb it runs: `{ sql }` for SQL (`?` binds positional args) or `{ search }` for a ranked search with its settings baked in, so `sense hot` needs no flags. `sense check` runs them all, so a typo'd column fails at check time instead of mid-task. |
95
+ | `queries` | entries runnable as `sense <name>`, each naming the verb it runs: `{ sql }` for SQL (`?` binds positional args) or `{ search }` for a ranked search with its settings baked in, so `sense hot` needs no flags. Running an entry validates it: a typo'd column errors and exits nonzero, and a parameterised entry validates with any argument, since preparing precedes binding. |
97
96
  | `version` | schema version; older configs auto-migrate on load, noted on stderr. |
98
97
 
99
98
  Bare commands use the `default` preset; `--preset` names another; flags override single fields. Editing a preset rebuilds the cache and says which preset caused it.
@@ -108,7 +107,7 @@ Every query starts with a freshness check against the cache in `.sense/`; only c
108
107
 
109
108
  - **Work is linear in note count.** Crawl, reconcile, and the freshness check are what every invocation pays; that check is the floor cost of a query and the first thing to watch on a large tree.
110
109
  - **Output is flat.** `map`, `peek`, and a search row cost the same on a small tree as a large one: context cost is bounded by what you ask for, not by how much there is.
111
- - **Bulk changes are paid by whoever queries next.** `sense watch` moves that re-parse into the background ([WATCH.md](WATCH.md)): it changes latency, never answers, since every query reconciles for itself. `sense rebuild` starts the cache over.
110
+ - **Bulk changes are paid by whoever queries next.** `sense watch` moves that re-parse into the background ([WATCH.md](WATCH.md)): it changes latency, never answers, since every query reconciles for itself. To start the cache over, delete the directory `sense status` prints.
112
111
 
113
112
  These are release gates rather than hopes: every release regenerates the numbers on pinned corpora spanning a 4x range in note count plus a stress tree that packs the worst measured shapes into one place: a megabyte-scale note, heading-dense outlines, dense link graphs, hundreds of frontmatter fields. A row that grows faster than linearly, or a token count that grows at all, blocks the release. Current figures: [BENCHMARKING.md](BENCHMARKING.md).
114
113
 
@@ -3,10 +3,8 @@ export declare const USAGE: {
3
3
  readonly init: "init";
4
4
  readonly watch: "watch [--force] [--config path]";
5
5
  readonly status: "status [--format table|json] [--config path]";
6
- readonly check: "check [--format table|json] [--config path]";
7
- readonly rebuild: "rebuild [--config path]";
8
6
  readonly download: "download [--config path]";
9
- readonly sql: "sql \"<statement>\" [params...] [--format table|json] [--config path]";
7
+ readonly sql: "sql \"<statement>\" [params...] [--preset name] [--format table|json] [--config path]";
10
8
  readonly search: "search \"<terms>\" [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where \"<sql>\"] [--k n] [--format table|json] [--config path]";
11
9
  readonly map: "map [--format table|json] [--config path]";
12
10
  readonly peek: "peek <path> [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where \"<sql>\"] [--format table|json] [--config path]";
@@ -3,10 +3,8 @@ export declare const USAGE: {
3
3
  readonly init: "init";
4
4
  readonly watch: "watch [--force] [--config path]";
5
5
  readonly status: "status [--format table|json] [--config path]";
6
- readonly check: "check [--format table|json] [--config path]";
7
- readonly rebuild: "rebuild [--config path]";
8
6
  readonly download: "download [--config path]";
9
- readonly sql: "sql \"<statement>\" [params...] [--format table|json] [--config path]";
7
+ readonly sql: "sql \"<statement>\" [params...] [--preset name] [--format table|json] [--config path]";
10
8
  readonly search: "search \"<terms>\" [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where \"<sql>\"] [--k n] [--format table|json] [--config path]";
11
9
  readonly map: "map [--format table|json] [--config path]";
12
10
  readonly peek: "peek <path> [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where \"<sql>\"] [--format table|json] [--config path]";
@@ -61,10 +61,8 @@ var USAGE = {
61
61
  init: 'init',
62
62
  watch: 'watch [--force] [--config path]',
63
63
  status: 'status [--format table|json] [--config path]',
64
- check: 'check [--format table|json] [--config path]',
65
- rebuild: 'rebuild [--config path]',
66
64
  download: 'download [--config path]',
67
- sql: 'sql "<statement>" [params...] [--format table|json] [--config path]',
65
+ sql: 'sql "<statement>" [params...] [--preset name] [--format table|json] [--config path]',
68
66
  search: 'search "<terms>" [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where "<sql>"] [--k n] [--format table|json] [--config path]',
69
67
  map: 'map [--format table|json] [--config path]',
70
68
  peek: 'peek <path> [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where "<sql>"] [--format table|json] [--config path]',
@@ -87,16 +85,6 @@ var COMMANDS = {
87
85
  return /*#__PURE__*/ _interop_require_wildcard(require("./status.js"));
88
86
  });
89
87
  },
90
- check: function check() {
91
- return Promise.resolve().then(function() {
92
- return /*#__PURE__*/ _interop_require_wildcard(require("./check.js"));
93
- });
94
- },
95
- rebuild: function rebuild() {
96
- return Promise.resolve().then(function() {
97
- return /*#__PURE__*/ _interop_require_wildcard(require("./rebuild.js"));
98
- });
99
- },
100
88
  download: function download() {
101
89
  return Promise.resolve().then(function() {
102
90
  return /*#__PURE__*/ _interop_require_wildcard(require("./download.js"));
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/index.ts"],"sourcesContent":["import type { Command } from './types.ts';\n\n// Each command's usage line, minus the leading \"usage: <name> \" -- shared by cli.ts's\n// top-level usage() and the command's own parse() error/--help output, so there is one\n// copy of each line, not two that can drift.\nexport const USAGE = {\n init: 'init',\n watch: 'watch [--force] [--config path]',\n status: 'status [--format table|json] [--config path]',\n check: 'check [--format table|json] [--config path]',\n rebuild: 'rebuild [--config path]',\n download: 'download [--config path]',\n sql: 'sql \"<statement>\" [params...] [--format table|json] [--config path]',\n search: 'search \"<terms>\" [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where \"<sql>\"] [--k n] [--format table|json] [--config path]',\n map: 'map [--format table|json] [--config path]',\n peek: 'peek <path> [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where \"<sql>\"] [--format table|json] [--config path]',\n path: 'path <a> <b> [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where \"<sql>\"] [--max-depth n] [--format table|json] [--config path]',\n related: 'related <note> [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where \"<sql>\"] [--k n] [--format table|json] [--config path]',\n} as const;\n\n// Lazy registry: a command's imports load only when it runs, so a heavy dependency in one\n// command never taxes the others (or --version/--help). These names are reserved: a saved\n// entry in config can never shadow them.\nexport const COMMANDS: Record<string, () => Promise<{ default: Command }>> = {\n init: () => import('./init.ts'),\n watch: () => import('./watch.ts'),\n status: () => import('./status.ts'),\n check: () => import('./check.ts'),\n rebuild: () => import('./rebuild.ts'),\n download: () => import('./download.ts'),\n sql: () => import('./sql.ts'),\n search: () => import('./search.ts'),\n map: () => import('./map.ts'),\n peek: () => import('./peek.ts'),\n path: () => import('./path.ts'),\n related: () => import('./related.ts'),\n};\n\nexport type { Command, Ctx } from './types.ts';\n"],"names":["COMMANDS","USAGE","init","watch","status","check","rebuild","download","sql","search","map","peek","path","related"],"mappings":";;;;;;;;;;;QAuBaA;eAAAA;;QAlBAC;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAN,IAAMA,QAAQ;IACnBC,MAAM;IACNC,OAAO;IACPC,QAAQ;IACRC,OAAO;IACPC,SAAS;IACTC,UAAU;IACVC,KAAK;IACLC,QAAQ;IACRC,KAAK;IACLC,MAAM;IACNC,MAAM;IACNC,SAAS;AACX;AAKO,IAAMb,WAAgE;IAC3EE,MAAM,SAANA;eAAY;2DAAA,QAAO;;;IACnBC,OAAO,SAAPA;eAAa;2DAAA,QAAO;;;IACpBC,QAAQ,SAARA;eAAc;2DAAA,QAAO;;;IACrBC,OAAO,SAAPA;eAAa;2DAAA,QAAO;;;IACpBC,SAAS,SAATA;eAAe;2DAAA,QAAO;;;IACtBC,UAAU,SAAVA;eAAgB;2DAAA,QAAO;;;IACvBC,KAAK,SAALA;eAAW;2DAAA,QAAO;;;IAClBC,QAAQ,SAARA;eAAc;2DAAA,QAAO;;;IACrBC,KAAK,SAALA;eAAW;2DAAA,QAAO;;;IAClBC,MAAM,SAANA;eAAY;2DAAA,QAAO;;;IACnBC,MAAM,SAANA;eAAY;2DAAA,QAAO;;;IACnBC,SAAS,SAATA;eAAe;2DAAA,QAAO;;;AACxB"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/index.ts"],"sourcesContent":["import type { Command } from './types.ts';\n\n// Each command's usage line, minus the leading \"usage: <name> \" -- shared by cli.ts's\n// top-level usage() and the command's own parse() error/--help output, so there is one\n// copy of each line, not two that can drift.\nexport const USAGE = {\n init: 'init',\n watch: 'watch [--force] [--config path]',\n status: 'status [--format table|json] [--config path]',\n download: 'download [--config path]',\n sql: 'sql \"<statement>\" [params...] [--preset name] [--format table|json] [--config path]',\n search: 'search \"<terms>\" [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where \"<sql>\"] [--k n] [--format table|json] [--config path]',\n map: 'map [--format table|json] [--config path]',\n peek: 'peek <path> [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where \"<sql>\"] [--format table|json] [--config path]',\n path: 'path <a> <b> [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where \"<sql>\"] [--max-depth n] [--format table|json] [--config path]',\n related: 'related <note> [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude] [--where \"<sql>\"] [--k n] [--format table|json] [--config path]',\n} as const;\n\n// Lazy registry: a command's imports load only when it runs, so a heavy dependency in one\n// command never taxes the others (or --version/--help). These names are reserved: a saved\n// entry in config can never shadow them.\nexport const COMMANDS: Record<string, () => Promise<{ default: Command }>> = {\n init: () => import('./init.ts'),\n watch: () => import('./watch.ts'),\n status: () => import('./status.ts'),\n download: () => import('./download.ts'),\n sql: () => import('./sql.ts'),\n search: () => import('./search.ts'),\n map: () => import('./map.ts'),\n peek: () => import('./peek.ts'),\n path: () => import('./path.ts'),\n related: () => import('./related.ts'),\n};\n\nexport type { Command, Ctx } from './types.ts';\n"],"names":["COMMANDS","USAGE","init","watch","status","download","sql","search","map","peek","path","related"],"mappings":";;;;;;;;;;;QAqBaA;eAAAA;;QAhBAC;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAN,IAAMA,QAAQ;IACnBC,MAAM;IACNC,OAAO;IACPC,QAAQ;IACRC,UAAU;IACVC,KAAK;IACLC,QAAQ;IACRC,KAAK;IACLC,MAAM;IACNC,MAAM;IACNC,SAAS;AACX;AAKO,IAAMX,WAAgE;IAC3EE,MAAM,SAANA;eAAY;2DAAA,QAAO;;;IACnBC,OAAO,SAAPA;eAAa;2DAAA,QAAO;;;IACpBC,QAAQ,SAARA;eAAc;2DAAA,QAAO;;;IACrBC,UAAU,SAAVA;eAAgB;2DAAA,QAAO;;;IACvBC,KAAK,SAALA;eAAW;2DAAA,QAAO;;;IAClBC,QAAQ,SAARA;eAAc;2DAAA,QAAO;;;IACrBC,KAAK,SAALA;eAAW;2DAAA,QAAO;;;IAClBC,MAAM,SAANA;eAAY;2DAAA,QAAO;;;IACnBC,MAAM,SAANA;eAAY;2DAAA,QAAO;;;IACnBC,SAAS,SAATA;eAAe;2DAAA,QAAO;;;AACxB"}
@@ -187,7 +187,9 @@ function named(ctx, queryName) {
187
187
  process.exit(2);
188
188
  }
189
189
  if ('sql' in entry) {
190
- (0, _sharedts.runSql)(cfg, entry.sql, params, format, 'query "'.concat(queryName, '"'));
190
+ // A saved statement written against `scope` is preset-agnostic, so the same entry can be
191
+ // re-pointed at another layer from the command line instead of being copied per preset.
192
+ (0, _sharedts.runSql)(cfg, entry.sql, params, format, 'query "'.concat(queryName, '"'), values.preset);
191
193
  return [
192
194
  2
193
195
  ];
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/named.ts"],"sourcesContent":["import { search } from '../commands.ts';\nimport { printRows } from '../output.ts';\nimport { CONFIG, FORMAT, formatOf, parse, parseK, runSql, SEARCH_FLAGS, withDb } from './shared.ts';\nimport type { Ctx } from './types.ts';\n\n// Fallback when the first positional is not a command: a saved query, { sql } or { search }.\n// SEARCH_FLAGS override a saved search's fields the same way they override a preset's.\nexport default async function named(ctx: Ctx, queryName: string): Promise<void> {\n const usage = `usage: ${ctx.name} ${queryName} [params...] [--format table|json] [--config path] [--where \"<sql>\"] [--k n] [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude]`;\n const { values, positionals: params } = parse(ctx.argv, usage, { ...SEARCH_FLAGS, ...FORMAT, ...CONFIG });\n const format = formatOf(values);\n const configPath = values.config as string | undefined;\n\n const cfg = ctx.resolveConfig(configPath);\n const entry = cfg.queries[queryName];\n if (entry === undefined) {\n console.error(`unknown command or saved entry: \"${queryName}\"`);\n console.error(`saved queries: ${Object.keys(cfg.queries).sort().join(', ')}`);\n process.exit(2);\n }\n\n if ('sql' in entry) {\n runSql(cfg, entry.sql, params, format, `query \"${queryName}\"`);\n return;\n }\n\n // A saved search's text is fixed in config; there is nowhere for a positional to bind.\n if (params.length > 0) {\n ctx.usageError(`\"${queryName}\" is a saved search and takes no positional parameters; edit its \"search\" in sense.config.json, or use \"${ctx.name} search\" directly`);\n }\n const k = parseK(values.k as string | undefined, ctx.usageError) ?? entry.k;\n const where = (values.where as string | undefined) ?? entry.where;\n const preset = (values.preset as string | undefined) ?? entry.preset;\n const include = (values.include as string[] | undefined) ?? entry.include;\n const exclude = (values.exclude as string[] | undefined) ?? entry.exclude;\n const noExclude = values['no-exclude'] === true;\n await withDb(ctx, configPath, async (db, resolvedCfg) => printRows(await search(db, resolvedCfg, entry.search, { k, where, preset, include, exclude, noExclude }), format));\n}\n"],"names":["named","ctx","queryName","parseK","values","usage","parse","params","format","configPath","cfg","entry","k","where","preset","include","exclude","noExclude","name","argv","SEARCH_FLAGS","FORMAT","CONFIG","positionals","formatOf","config","resolveConfig","queries","undefined","console","error","Object","keys","sort","join","process","exit","runSql","sql","length","usageError","withDb","db","resolvedCfg","search","printRows"],"mappings":";;;;+BAKA,6FAA6F;AAC7F,uFAAuF;AACvF;;;eAA8BA;;;0BAPP;wBACG;wBAC4D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKvE,SAAeA,MAAMC,GAAQ,EAAEC,SAAiB;;YAuBnDC,SACKC,eACCA,gBACCA,iBACAA,iBA1BXC,OACkCC,QAAhCF,QAAqBG,QACvBC,QACAC,YAEAC,KACAC,OAgBAC,GACAC,OACAC,QACAC,SACAC,SACAC;;;;oBA3BAZ,QAAQ,AAAC,UAAqBH,OAAZD,IAAIiB,IAAI,EAAC,KAAa,OAAVhB,WAAU;oBACNI,SAAAA,IAAAA,eAAK,EAACL,IAAIkB,IAAI,EAAEd,OAAO,mBAAKe,sBAAY,EAAKC,gBAAM,EAAKC,gBAAM,IAA9FlB,SAAgCE,OAAhCF,QAAqBG,SAAWD,OAAxBiB;oBACVf,SAASgB,IAAAA,kBAAQ,EAACpB;oBAClBK,aAAaL,OAAOqB,MAAM;oBAE1Bf,MAAMT,IAAIyB,aAAa,CAACjB;oBACxBE,QAAQD,IAAIiB,OAAO,CAACzB,UAAU;oBACpC,IAAIS,UAAUiB,WAAW;wBACvBC,QAAQC,KAAK,CAAC,AAAC,oCAA6C,OAAV5B,WAAU;wBAC5D2B,QAAQC,KAAK,CAAC,AAAC,kBAA4D,OAA3CC,OAAOC,IAAI,CAACtB,IAAIiB,OAAO,EAAEM,IAAI,GAAGC,IAAI,CAAC;wBACrEC,QAAQC,IAAI,CAAC;oBACf;oBAEA,IAAI,SAASzB,OAAO;wBAClB0B,IAAAA,gBAAM,EAAC3B,KAAKC,MAAM2B,GAAG,EAAE/B,QAAQC,QAAQ,AAAC,UAAmB,OAAVN,WAAU;wBAC3D;;;oBACF;oBAEA,uFAAuF;oBACvF,IAAIK,OAAOgC,MAAM,GAAG,GAAG;wBACrBtC,IAAIuC,UAAU,CAAC,AAAC,IAAuHvC,OAApHC,WAAU,4GAAmH,OAATD,IAAIiB,IAAI,EAAC;oBAClJ;oBACMN,KAAIT,UAAAA,IAAAA,gBAAM,EAACC,OAAOQ,CAAC,EAAwBX,IAAIuC,UAAU,eAArDrC,qBAAAA,UAA0DQ,MAAMC,CAAC;oBACrEC,SAAST,gBAAAA,OAAOS,KAAK,cAAZT,2BAAAA,gBAAuCO,MAAME,KAAK;oBAC3DC,UAAUV,iBAAAA,OAAOU,MAAM,cAAbV,4BAAAA,iBAAwCO,MAAMG,MAAM;oBAC9DC,WAAWX,kBAAAA,OAAOW,OAAO,cAAdX,6BAAAA,kBAA2CO,MAAMI,OAAO;oBACnEC,WAAWZ,kBAAAA,OAAOY,OAAO,cAAdZ,6BAAAA,kBAA2CO,MAAMK,OAAO;oBACnEC,YAAYb,MAAM,CAAC,aAAa,KAAK;oBAC3C;;wBAAMqC,IAAAA,gBAAM,EAACxC,KAAKQ,YAAY,SAAOiC,IAAIC;;;;;4CAA0B;;gDAAMC,IAAAA,kBAAM,EAACF,IAAIC,aAAahC,MAAMiC,MAAM,EAAE;oDAAEhC,GAAAA;oDAAGC,OAAAA;oDAAOC,QAAAA;oDAAQC,SAAAA;oDAASC,SAAAA;oDAASC,WAAAA;gDAAU;;;;;gDAAtG4B,mBAAS;oDAAC;oDAAgGrC;;;;;;;;;oBAAnK;;;;;;IACF"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/named.ts"],"sourcesContent":["import { search } from '../commands.ts';\nimport { printRows } from '../output.ts';\nimport { CONFIG, FORMAT, formatOf, parse, parseK, runSql, SEARCH_FLAGS, withDb } from './shared.ts';\nimport type { Ctx } from './types.ts';\n\n// Fallback when the first positional is not a command: a saved query, { sql } or { search }.\n// SEARCH_FLAGS override a saved search's fields the same way they override a preset's.\nexport default async function named(ctx: Ctx, queryName: string): Promise<void> {\n const usage = `usage: ${ctx.name} ${queryName} [params...] [--format table|json] [--config path] [--where \"<sql>\"] [--k n] [--preset name] [--include glob ...] [--exclude glob ...] [--no-exclude]`;\n const { values, positionals: params } = parse(ctx.argv, usage, { ...SEARCH_FLAGS, ...FORMAT, ...CONFIG });\n const format = formatOf(values);\n const configPath = values.config as string | undefined;\n\n const cfg = ctx.resolveConfig(configPath);\n const entry = cfg.queries[queryName];\n if (entry === undefined) {\n console.error(`unknown command or saved entry: \"${queryName}\"`);\n console.error(`saved queries: ${Object.keys(cfg.queries).sort().join(', ')}`);\n process.exit(2);\n }\n\n if ('sql' in entry) {\n // A saved statement written against `scope` is preset-agnostic, so the same entry can be\n // re-pointed at another layer from the command line instead of being copied per preset.\n runSql(cfg, entry.sql, params, format, `query \"${queryName}\"`, values.preset as string | undefined);\n return;\n }\n\n // A saved search's text is fixed in config; there is nowhere for a positional to bind.\n if (params.length > 0) {\n ctx.usageError(`\"${queryName}\" is a saved search and takes no positional parameters; edit its \"search\" in sense.config.json, or use \"${ctx.name} search\" directly`);\n }\n const k = parseK(values.k as string | undefined, ctx.usageError) ?? entry.k;\n const where = (values.where as string | undefined) ?? entry.where;\n const preset = (values.preset as string | undefined) ?? entry.preset;\n const include = (values.include as string[] | undefined) ?? entry.include;\n const exclude = (values.exclude as string[] | undefined) ?? entry.exclude;\n const noExclude = values['no-exclude'] === true;\n await withDb(ctx, configPath, async (db, resolvedCfg) => printRows(await search(db, resolvedCfg, entry.search, { k, where, preset, include, exclude, noExclude }), format));\n}\n"],"names":["named","ctx","queryName","parseK","values","usage","parse","params","format","configPath","cfg","entry","k","where","preset","include","exclude","noExclude","name","argv","SEARCH_FLAGS","FORMAT","CONFIG","positionals","formatOf","config","resolveConfig","queries","undefined","console","error","Object","keys","sort","join","process","exit","runSql","sql","length","usageError","withDb","db","resolvedCfg","search","printRows"],"mappings":";;;;+BAKA,6FAA6F;AAC7F,uFAAuF;AACvF;;;eAA8BA;;;0BAPP;wBACG;wBAC4D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKvE,SAAeA,MAAMC,GAAQ,EAAEC,SAAiB;;YAyBnDC,SACKC,eACCA,gBACCA,iBACAA,iBA5BXC,OACkCC,QAAhCF,QAAqBG,QACvBC,QACAC,YAEAC,KACAC,OAkBAC,GACAC,OACAC,QACAC,SACAC,SACAC;;;;oBA7BAZ,QAAQ,AAAC,UAAqBH,OAAZD,IAAIiB,IAAI,EAAC,KAAa,OAAVhB,WAAU;oBACNI,SAAAA,IAAAA,eAAK,EAACL,IAAIkB,IAAI,EAAEd,OAAO,mBAAKe,sBAAY,EAAKC,gBAAM,EAAKC,gBAAM,IAA9FlB,SAAgCE,OAAhCF,QAAqBG,SAAWD,OAAxBiB;oBACVf,SAASgB,IAAAA,kBAAQ,EAACpB;oBAClBK,aAAaL,OAAOqB,MAAM;oBAE1Bf,MAAMT,IAAIyB,aAAa,CAACjB;oBACxBE,QAAQD,IAAIiB,OAAO,CAACzB,UAAU;oBACpC,IAAIS,UAAUiB,WAAW;wBACvBC,QAAQC,KAAK,CAAC,AAAC,oCAA6C,OAAV5B,WAAU;wBAC5D2B,QAAQC,KAAK,CAAC,AAAC,kBAA4D,OAA3CC,OAAOC,IAAI,CAACtB,IAAIiB,OAAO,EAAEM,IAAI,GAAGC,IAAI,CAAC;wBACrEC,QAAQC,IAAI,CAAC;oBACf;oBAEA,IAAI,SAASzB,OAAO;wBAClB,yFAAyF;wBACzF,wFAAwF;wBACxF0B,IAAAA,gBAAM,EAAC3B,KAAKC,MAAM2B,GAAG,EAAE/B,QAAQC,QAAQ,AAAC,UAAmB,OAAVN,WAAU,MAAIE,OAAOU,MAAM;wBAC5E;;;oBACF;oBAEA,uFAAuF;oBACvF,IAAIP,OAAOgC,MAAM,GAAG,GAAG;wBACrBtC,IAAIuC,UAAU,CAAC,AAAC,IAAuHvC,OAApHC,WAAU,4GAAmH,OAATD,IAAIiB,IAAI,EAAC;oBAClJ;oBACMN,KAAIT,UAAAA,IAAAA,gBAAM,EAACC,OAAOQ,CAAC,EAAwBX,IAAIuC,UAAU,eAArDrC,qBAAAA,UAA0DQ,MAAMC,CAAC;oBACrEC,SAAST,gBAAAA,OAAOS,KAAK,cAAZT,2BAAAA,gBAAuCO,MAAME,KAAK;oBAC3DC,UAAUV,iBAAAA,OAAOU,MAAM,cAAbV,4BAAAA,iBAAwCO,MAAMG,MAAM;oBAC9DC,WAAWX,kBAAAA,OAAOW,OAAO,cAAdX,6BAAAA,kBAA2CO,MAAMI,OAAO;oBACnEC,WAAWZ,kBAAAA,OAAOY,OAAO,cAAdZ,6BAAAA,kBAA2CO,MAAMK,OAAO;oBACnEC,YAAYb,MAAM,CAAC,aAAa,KAAK;oBAC3C;;wBAAMqC,IAAAA,gBAAM,EAACxC,KAAKQ,YAAY,SAAOiC,IAAIC;;;;;4CAA0B;;gDAAMC,IAAAA,kBAAM,EAACF,IAAIC,aAAahC,MAAMiC,MAAM,EAAE;oDAAEhC,GAAAA;oDAAGC,OAAAA;oDAAOC,QAAAA;oDAAQC,SAAAA;oDAASC,SAAAA;oDAASC,WAAAA;gDAAU;;;;;gDAAtG4B,mBAAS;oDAAC;oDAAgGrC;;;;;;;;;oBAAnK;;;;;;IACF"}
@@ -16,5 +16,5 @@ export declare function parse(argv: string[], usage: string, options: ParseArgsO
16
16
  export declare function parseK(k: string | undefined, usageError: (message: string) => never): number | undefined;
17
17
  export declare function printWarnings(warnings: string[]): void;
18
18
  export declare function withDb(ctx: Ctx, configPath: string | undefined, fn: (db: OpenResult['db'], cfg: ResolvedConfig) => void | Promise<void>): Promise<void>;
19
- export declare function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: 'table' | 'json', label: string): void;
19
+ export declare function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: 'table' | 'json', label: string, preset?: string): void;
20
20
  export {};
@@ -16,5 +16,5 @@ export declare function parse(argv: string[], usage: string, options: ParseArgsO
16
16
  export declare function parseK(k: string | undefined, usageError: (message: string) => never): number | undefined;
17
17
  export declare function printWarnings(warnings: string[]): void;
18
18
  export declare function withDb(ctx: Ctx, configPath: string | undefined, fn: (db: OpenResult['db'], cfg: ResolvedConfig) => void | Promise<void>): Promise<void>;
19
- export declare function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: 'table' | 'json', label: string): void;
19
+ export declare function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: 'table' | 'json', label: string, preset?: string): void;
20
20
  export {};
@@ -44,6 +44,7 @@ _export(exports, {
44
44
  }
45
45
  });
46
46
  var _nodeutil = require("node:util");
47
+ var _configts = require("../config.js");
47
48
  var _dbts = require("../db.js");
48
49
  var _outputts = require("../output.js");
49
50
  var _searcherrorts = require("../search-error.js");
@@ -401,15 +402,34 @@ function withDb(ctx, configPath, fn) {
401
402
  });
402
403
  })();
403
404
  }
404
- function runSql(cfg, sql, params, format, label) {
405
+ // `--preset` on SQL binds the scope rather than applying it: the statement joins `scope`
406
+ // itself. Filtering behind the query's back is not available -- the obvious version, temp views
407
+ // shadowing the base tables, cannot cover `content`, because FTS5 `MATCH` uses the table name
408
+ // as a hidden column and a view has none. A flag that silently scoped three tables of four
409
+ // would look scoped and not be. See plans/vault-field-report-fixes.md item F.
410
+ function bindScope(db, cfg, preset) {
411
+ var name = (0, _configts.resolvePreset)(cfg, preset).name; // unknown names throw, listing what is declared
412
+ db.exec('DROP TABLE IF EXISTS temp.scope');
413
+ db.exec('CREATE TEMP TABLE scope ("path" TEXT PRIMARY KEY)');
414
+ db.prepare('INSERT INTO temp.scope ("path") SELECT "path" FROM preset_files WHERE preset = ?').run(name);
415
+ }
416
+ function runSql(cfg, sql, params, format, label, preset) {
405
417
  var _sql_match;
406
418
  var placeholderCount = ((_sql_match = sql.match(/\?/g)) !== null && _sql_match !== void 0 ? _sql_match : []).length;
407
419
  if (params.length !== placeholderCount) {
408
420
  console.error("".concat(label, " expects ").concat(placeholderCount, " parameter(s), got ").concat(params.length));
409
421
  process.exit(2);
410
422
  }
423
+ // Naming a preset and never joining it would return the whole index while reading as scoped,
424
+ // which is the one hazard of binding rather than applying. Refuse instead.
425
+ if (preset !== undefined && !/\bscope\b/i.test(sql)) {
426
+ console.error('--preset binds a temporary "scope" table of the preset\'s paths, and '.concat(label, " never joins it, so the preset would have no effect"));
427
+ console.error('add: JOIN scope ON scope."path" = <table>."path"');
428
+ process.exit(2);
429
+ }
411
430
  var _open = (0, _dbts.open)(cfg), db = _open.db, warnings = _open.warnings;
412
431
  printWarnings(warnings);
432
+ if (preset !== undefined) bindScope(db, cfg, preset);
413
433
  var rows;
414
434
  try {
415
435
  var _db_prepare;
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/shared.ts"],"sourcesContent":["import type { ParseArgsOptionsConfig } from 'node:util';\nimport { parseArgs } from 'node:util';\nimport type { ResolvedConfig, SearchOverrides } from '../config.ts';\nimport type { OpenResult } from '../db.ts';\nimport { open } from '../db.ts';\nimport type { Row } from '../output.ts';\nimport { printRows } from '../output.ts';\nimport { searchError } from '../search-error.ts';\nimport type { Ctx } from './types.ts';\n\n// Spreadable option fragments -- one flag name keeps one meaning across every command's table.\nexport const FORMAT: ParseArgsOptionsConfig = { format: { type: 'string', default: 'table' } };\nexport const CONFIG: ParseArgsOptionsConfig = { config: { type: 'string' } };\n// The scope vocabulary every scoped command shares: named preset, ad hoc include/exclude\n// globs, a where SQL condition. search adds k on top.\nexport const SCOPE: ParseArgsOptionsConfig = {\n where: { type: 'string' },\n preset: { type: 'string' },\n include: { type: 'string', multiple: true },\n exclude: { type: 'string', multiple: true },\n // Widening, which no other flag can express: --include and --exclude each override their\n // own side of the preset, so neither can drop an exclusion the preset declares.\n 'no-exclude': { type: 'boolean', default: false },\n};\nexport const SEARCH_FLAGS: ParseArgsOptionsConfig = { ...SCOPE, k: { type: 'string' } };\n\ntype Values = Record<string, string | boolean | string[] | undefined>;\n\n// The SCOPE fragment's parsed values as the overrides every scoped command passes down. One\n// place to read them, so a new scope field is added to the fragment and here, not in each\n// command's call.\nexport function scopeOf(values: Values): SearchOverrides {\n return {\n preset: values.preset as string | undefined,\n include: values.include as string[] | undefined,\n exclude: values.exclude as string[] | undefined,\n where: values.where as string | undefined,\n noExclude: values['no-exclude'] === true,\n };\n}\n\nexport function formatOf(values: Values): 'table' | 'json' {\n return values.format === 'json' ? 'json' : 'table';\n}\n\n// Per-command parseArgs: strict (a foreign flag exits 2), and every table gets --help for free.\nexport function parse(argv: string[], usage: string, options: ParseArgsOptionsConfig): { values: Values; positionals: string[] } {\n let values: Values;\n let positionals: string[];\n try {\n ({ values, positionals } = parseArgs({\n args: argv,\n options: { ...options, help: { type: 'boolean', default: false, short: 'h' } },\n strict: true,\n allowPositionals: true,\n }));\n } catch (err) {\n console.error((err as Error).message);\n console.error(usage);\n process.exit(2);\n }\n if (values.help) {\n console.log(usage);\n process.exit(0);\n }\n return { values, positionals };\n}\n\n// --k must be a positive integer: SQLite reads a bound LIMIT of -1 as \"unlimited\" and 0 as\n// \"nothing\", and parseInt would silently truncate \"5.9\" -- all three are caller mistakes\n// worth a usage error, matching the config-level SavedSearch validation.\nexport function parseK(k: string | undefined, usageError: (message: string) => never): number | undefined {\n if (k === undefined) return undefined;\n const parsed = Number(k);\n if (!Number.isInteger(parsed) || parsed <= 0) usageError(`--k expects a positive integer, got \"${k}\"`);\n return parsed;\n}\n\n// Shared open-query-close envelope for commands that touch the tree.\n\nexport function printWarnings(warnings: string[]): void {\n for (const w of warnings) console.warn(w);\n}\n\nexport async function withDb(ctx: Ctx, configPath: string | undefined, fn: (db: OpenResult['db'], cfg: ResolvedConfig) => void | Promise<void>): Promise<void> {\n const cfg = ctx.resolveConfig(configPath);\n const { db, warnings } = open(cfg);\n printWarnings(warnings);\n try {\n await fn(db, cfg);\n } finally {\n db.close();\n }\n}\n\n// An unbound `?` silently binds NULL, so mismatched param counts fail loudly instead.\nexport function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: 'table' | 'json', label: string): void {\n const placeholderCount = (sql.match(/\\?/g) ?? []).length;\n if (params.length !== placeholderCount) {\n console.error(`${label} expects ${placeholderCount} parameter(s), got ${params.length}`);\n process.exit(2);\n }\n const { db, warnings } = open(cfg);\n printWarnings(warnings);\n let rows: Row[];\n try {\n rows = db.prepare(sql).all(...params) as Row[];\n } catch (err) {\n db.close();\n // A saved query or ad-hoc SQL can carry `content MATCH ?` too, so the same FTS5\n // punctuation trap applies -- the bound parameters are the search terms there. SQL\n // without MATCH gets its error verbatim; search advice on a plain typo would mislead.\n if (/\\bMATCH\\b/i.test(sql)) throw searchError(err as Error, params.join(' '));\n throw err;\n }\n printRows(rows, format);\n db.close();\n}\n"],"names":["CONFIG","FORMAT","SCOPE","SEARCH_FLAGS","formatOf","parse","parseK","printWarnings","runSql","scopeOf","withDb","format","type","default","config","where","preset","include","multiple","exclude","k","values","noExclude","argv","usage","options","positionals","parseArgs","args","help","short","strict","allowPositionals","err","console","error","message","process","exit","log","usageError","undefined","parsed","Number","isInteger","warnings","w","warn","ctx","configPath","fn","cfg","open","db","resolveConfig","close","sql","params","label","placeholderCount","match","length","rows","prepare","all","test","searchError","join","printRows"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/shared.ts"],"sourcesContent":["import type { ParseArgsOptionsConfig } from 'node:util';\nimport { parseArgs } from 'node:util';\nimport type { ResolvedConfig, SearchOverrides } from '../config.ts';\nimport { resolvePreset } from '../config.ts';\nimport type { OpenResult } from '../db.ts';\nimport { open } from '../db.ts';\nimport type { Row } from '../output.ts';\nimport { printRows } from '../output.ts';\nimport { searchError } from '../search-error.ts';\nimport type { Ctx } from './types.ts';\n\n// Spreadable option fragments -- one flag name keeps one meaning across every command's table.\nexport const FORMAT: ParseArgsOptionsConfig = { format: { type: 'string', default: 'table' } };\nexport const CONFIG: ParseArgsOptionsConfig = { config: { type: 'string' } };\n// The scope vocabulary every scoped command shares: named preset, ad hoc include/exclude\n// globs, a where SQL condition. search adds k on top.\nexport const SCOPE: ParseArgsOptionsConfig = {\n where: { type: 'string' },\n preset: { type: 'string' },\n include: { type: 'string', multiple: true },\n exclude: { type: 'string', multiple: true },\n // Widening, which no other flag can express: --include and --exclude each override their\n // own side of the preset, so neither can drop an exclusion the preset declares.\n 'no-exclude': { type: 'boolean', default: false },\n};\nexport const SEARCH_FLAGS: ParseArgsOptionsConfig = { ...SCOPE, k: { type: 'string' } };\n\ntype Values = Record<string, string | boolean | string[] | undefined>;\n\n// The SCOPE fragment's parsed values as the overrides every scoped command passes down. One\n// place to read them, so a new scope field is added to the fragment and here, not in each\n// command's call.\nexport function scopeOf(values: Values): SearchOverrides {\n return {\n preset: values.preset as string | undefined,\n include: values.include as string[] | undefined,\n exclude: values.exclude as string[] | undefined,\n where: values.where as string | undefined,\n noExclude: values['no-exclude'] === true,\n };\n}\n\nexport function formatOf(values: Values): 'table' | 'json' {\n return values.format === 'json' ? 'json' : 'table';\n}\n\n// Per-command parseArgs: strict (a foreign flag exits 2), and every table gets --help for free.\nexport function parse(argv: string[], usage: string, options: ParseArgsOptionsConfig): { values: Values; positionals: string[] } {\n let values: Values;\n let positionals: string[];\n try {\n ({ values, positionals } = parseArgs({\n args: argv,\n options: { ...options, help: { type: 'boolean', default: false, short: 'h' } },\n strict: true,\n allowPositionals: true,\n }));\n } catch (err) {\n console.error((err as Error).message);\n console.error(usage);\n process.exit(2);\n }\n if (values.help) {\n console.log(usage);\n process.exit(0);\n }\n return { values, positionals };\n}\n\n// --k must be a positive integer: SQLite reads a bound LIMIT of -1 as \"unlimited\" and 0 as\n// \"nothing\", and parseInt would silently truncate \"5.9\" -- all three are caller mistakes\n// worth a usage error, matching the config-level SavedSearch validation.\nexport function parseK(k: string | undefined, usageError: (message: string) => never): number | undefined {\n if (k === undefined) return undefined;\n const parsed = Number(k);\n if (!Number.isInteger(parsed) || parsed <= 0) usageError(`--k expects a positive integer, got \"${k}\"`);\n return parsed;\n}\n\n// Shared open-query-close envelope for commands that touch the tree.\n\nexport function printWarnings(warnings: string[]): void {\n for (const w of warnings) console.warn(w);\n}\n\nexport async function withDb(ctx: Ctx, configPath: string | undefined, fn: (db: OpenResult['db'], cfg: ResolvedConfig) => void | Promise<void>): Promise<void> {\n const cfg = ctx.resolveConfig(configPath);\n const { db, warnings } = open(cfg);\n printWarnings(warnings);\n try {\n await fn(db, cfg);\n } finally {\n db.close();\n }\n}\n\n// `--preset` on SQL binds the scope rather than applying it: the statement joins `scope`\n// itself. Filtering behind the query's back is not available -- the obvious version, temp views\n// shadowing the base tables, cannot cover `content`, because FTS5 `MATCH` uses the table name\n// as a hidden column and a view has none. A flag that silently scoped three tables of four\n// would look scoped and not be. See plans/vault-field-report-fixes.md item F.\nfunction bindScope(db: OpenResult['db'], cfg: ResolvedConfig, preset: string): void {\n const { name } = resolvePreset(cfg, preset); // unknown names throw, listing what is declared\n db.exec('DROP TABLE IF EXISTS temp.scope');\n db.exec('CREATE TEMP TABLE scope (\"path\" TEXT PRIMARY KEY)');\n db.prepare('INSERT INTO temp.scope (\"path\") SELECT \"path\" FROM preset_files WHERE preset = ?').run(name);\n}\n\n// An unbound `?` silently binds NULL, so mismatched param counts fail loudly instead.\nexport function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: 'table' | 'json', label: string, preset?: string): void {\n const placeholderCount = (sql.match(/\\?/g) ?? []).length;\n if (params.length !== placeholderCount) {\n console.error(`${label} expects ${placeholderCount} parameter(s), got ${params.length}`);\n process.exit(2);\n }\n // Naming a preset and never joining it would return the whole index while reading as scoped,\n // which is the one hazard of binding rather than applying. Refuse instead.\n if (preset !== undefined && !/\\bscope\\b/i.test(sql)) {\n console.error(`--preset binds a temporary \"scope\" table of the preset's paths, and ${label} never joins it, so the preset would have no effect`);\n console.error(`add: JOIN scope ON scope.\"path\" = <table>.\"path\"`);\n process.exit(2);\n }\n const { db, warnings } = open(cfg);\n printWarnings(warnings);\n if (preset !== undefined) bindScope(db, cfg, preset);\n let rows: Row[];\n try {\n rows = db.prepare(sql).all(...params) as Row[];\n } catch (err) {\n db.close();\n // A saved query or ad-hoc SQL can carry `content MATCH ?` too, so the same FTS5\n // punctuation trap applies -- the bound parameters are the search terms there. SQL\n // without MATCH gets its error verbatim; search advice on a plain typo would mislead.\n if (/\\bMATCH\\b/i.test(sql)) throw searchError(err as Error, params.join(' '));\n throw err;\n }\n printRows(rows, format);\n db.close();\n}\n"],"names":["CONFIG","FORMAT","SCOPE","SEARCH_FLAGS","formatOf","parse","parseK","printWarnings","runSql","scopeOf","withDb","format","type","default","config","where","preset","include","multiple","exclude","k","values","noExclude","argv","usage","options","positionals","parseArgs","args","help","short","strict","allowPositionals","err","console","error","message","process","exit","log","usageError","undefined","parsed","Number","isInteger","warnings","w","warn","ctx","configPath","fn","cfg","open","db","resolveConfig","close","bindScope","name","resolvePreset","exec","prepare","run","sql","params","label","placeholderCount","match","length","test","rows","all","searchError","join","printRows"],"mappings":"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"}
@@ -52,6 +52,30 @@ function _object_spread(target) {
52
52
  }
53
53
  return target;
54
54
  }
55
+ function ownKeys(object, enumerableOnly) {
56
+ var keys = Object.keys(object);
57
+ if (Object.getOwnPropertySymbols) {
58
+ var symbols = Object.getOwnPropertySymbols(object);
59
+ if (enumerableOnly) {
60
+ symbols = symbols.filter(function(sym) {
61
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
62
+ });
63
+ }
64
+ keys.push.apply(keys, symbols);
65
+ }
66
+ return keys;
67
+ }
68
+ function _object_spread_props(target, source) {
69
+ source = source != null ? source : {};
70
+ if (Object.getOwnPropertyDescriptors) {
71
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
72
+ } else {
73
+ ownKeys(Object(source)).forEach(function(key) {
74
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
75
+ });
76
+ }
77
+ return target;
78
+ }
55
79
  function _to_array(arr) {
56
80
  return _array_with_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_rest();
57
81
  }
@@ -65,11 +89,15 @@ function _unsupported_iterable_to_array(o, minLen) {
65
89
  }
66
90
  var sqlCmd = function sqlCmd(ctx) {
67
91
  var usage = "usage: ".concat(ctx.name, " ").concat(_indexts.USAGE.sql);
68
- var _parse = (0, _sharedts.parse)(ctx.argv, usage, _object_spread({}, _sharedts.FORMAT, _sharedts.CONFIG)), values = _parse.values, positionals = _parse.positionals;
92
+ var _parse = (0, _sharedts.parse)(ctx.argv, usage, _object_spread_props(_object_spread({}, _sharedts.FORMAT, _sharedts.CONFIG), {
93
+ preset: {
94
+ type: 'string'
95
+ }
96
+ })), values = _parse.values, positionals = _parse.positionals;
69
97
  var _positionals = _to_array(positionals), sql = _positionals[0], params = _positionals.slice(1);
70
98
  if (!sql) ctx.usageError(usage);
71
99
  var format = (0, _sharedts.formatOf)(values);
72
- (0, _sharedts.runSql)(ctx.resolveConfig(values.config), sql, params, format, 'ad-hoc statement');
100
+ (0, _sharedts.runSql)(ctx.resolveConfig(values.config), sql, params, format, 'ad-hoc statement', values.preset);
73
101
  };
74
102
  var _default = sqlCmd;
75
103
  /* 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; }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/sql.ts"],"sourcesContent":["import { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, formatOf, parse, runSql } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst sqlCmd: Command = (ctx) => {\n const usage = `usage: ${ctx.name} ${USAGE.sql}`;\n const { values, positionals } = parse(ctx.argv, usage, { ...FORMAT, ...CONFIG });\n const [sql, ...params] = positionals;\n if (!sql) ctx.usageError(usage);\n const format = formatOf(values);\n runSql(ctx.resolveConfig(values.config as string | undefined), sql, params, format, 'ad-hoc statement');\n};\nexport default sqlCmd;\n"],"names":["sqlCmd","ctx","usage","USAGE","name","sql","parse","argv","FORMAT","CONFIG","values","positionals","params","usageError","format","formatOf","runSql","resolveConfig","config"],"mappings":";;;;+BAYA;;;eAAA;;;uBAZsB;wBACkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGxD,IAAMA,SAAkB,gBAACC;IACvB,IAAMC,QAAQ,AAAC,UAAqBC,OAAZF,IAAIG,IAAI,EAAC,KAAa,OAAVD,cAAK,CAACE,GAAG;IAC7C,IAAgCC,SAAAA,IAAAA,eAAK,EAACL,IAAIM,IAAI,EAAEL,OAAO,mBAAKM,gBAAM,EAAKC,gBAAM,IAArEC,SAAwBJ,OAAxBI,QAAQC,cAAgBL,OAAhBK;IAChB,IAAyBA,yBAAAA,cAAlBN,MAAkBM,iBAAb,AAAGC,SAAUD,mBAAb;IACZ,IAAI,CAACN,KAAKJ,IAAIY,UAAU,CAACX;IACzB,IAAMY,SAASC,IAAAA,kBAAQ,EAACL;IACxBM,IAAAA,gBAAM,EAACf,IAAIgB,aAAa,CAACP,OAAOQ,MAAM,GAAyBb,KAAKO,QAAQE,QAAQ;AACtF;IACA,WAAed"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/sql.ts"],"sourcesContent":["import { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, formatOf, parse, runSql } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst sqlCmd: Command = (ctx) => {\n const usage = `usage: ${ctx.name} ${USAGE.sql}`;\n const { values, positionals } = parse(ctx.argv, usage, { ...FORMAT, ...CONFIG, preset: { type: 'string' } });\n const [sql, ...params] = positionals;\n if (!sql) ctx.usageError(usage);\n const format = formatOf(values);\n runSql(ctx.resolveConfig(values.config as string | undefined), sql, params, format, 'ad-hoc statement', values.preset as string | undefined);\n};\nexport default sqlCmd;\n"],"names":["sqlCmd","ctx","usage","USAGE","name","sql","parse","argv","FORMAT","CONFIG","preset","type","values","positionals","params","usageError","format","formatOf","runSql","resolveConfig","config"],"mappings":";;;;+BAYA;;;eAAA;;;uBAZsB;wBACkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGxD,IAAMA,SAAkB,gBAACC;IACvB,IAAMC,QAAQ,AAAC,UAAqBC,OAAZF,IAAIG,IAAI,EAAC,KAAa,OAAVD,cAAK,CAACE,GAAG;IAC7C,IAAgCC,SAAAA,IAAAA,eAAK,EAACL,IAAIM,IAAI,EAAEL,OAAO,wCAAKM,gBAAM,EAAKC,gBAAM;QAAEC,QAAQ;YAAEC,MAAM;QAAS;SAAhGC,SAAwBN,OAAxBM,QAAQC,cAAgBP,OAAhBO;IAChB,IAAyBA,yBAAAA,cAAlBR,MAAkBQ,iBAAb,AAAGC,SAAUD,mBAAb;IACZ,IAAI,CAACR,KAAKJ,IAAIc,UAAU,CAACb;IACzB,IAAMc,SAASC,IAAAA,kBAAQ,EAACL;IACxBM,IAAAA,gBAAM,EAACjB,IAAIkB,aAAa,CAACP,OAAOQ,MAAM,GAAyBf,KAAKS,QAAQE,QAAQ,oBAAoBJ,OAAOF,MAAM;AACvH;IACA,WAAeV"}
@@ -1,3 +1,4 @@
1
1
  import type { Command } from './types.js';
2
+ export declare function redactUrl(url: string): string;
2
3
  declare const status: Command;
3
4
  export default status;
@@ -1,3 +1,4 @@
1
1
  import type { Command } from './types.js';
2
+ export declare function redactUrl(url: string): string;
2
3
  declare const status: Command;
3
4
  export default status;
@@ -2,12 +2,21 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- Object.defineProperty(exports, "default", {
6
- enumerable: true,
7
- get: function() {
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get default () {
8
13
  return _default;
14
+ },
15
+ get redactUrl () {
16
+ return redactUrl;
9
17
  }
10
18
  });
19
+ var _nodepath = require("node:path");
11
20
  var _commandsts = require("../commands.js");
12
21
  var _configts = require("../config.js");
13
22
  var _dbts = require("../db.js");
@@ -43,8 +52,12 @@ function _object_spread(target) {
43
52
  }
44
53
  return target;
45
54
  }
55
+ // status names what you cannot read off the config file: locations sense chose, values it
56
+ // derived, state it stored. Config content is not echoed -- the config line says which file to
57
+ // read, and duplicating its globs here would create two places that disagree after an edit.
58
+ // The exception is the embed block's url and key, whose effect is remote and otherwise invisible.
46
59
  // Vectors are computed on the first semantic query, not at reconcile, so a tree can have a
47
- // semantic-on preset with nothing embedded yet -- reported here because a fast `rebuild` on
60
+ // semantic-on preset with nothing embedded yet -- reported here because a fast reconcile on
48
61
  // such a tree otherwise reads as "the feature isn't on".
49
62
  function vectorState(db) {
50
63
  try {
@@ -54,7 +67,23 @@ function vectorState(db) {
54
67
  return null;
55
68
  }
56
69
  }
70
+ function parseErrorCount(db) {
71
+ var row = db.prepare('SELECT COUNT(*) AS n FROM frontmatter WHERE "_parse_error" IS NOT NULL').get();
72
+ return row.n;
73
+ }
74
+ function redactUrl(url) {
75
+ try {
76
+ var parsed = new URL(url);
77
+ if (!parsed.username && !parsed.password) return url;
78
+ parsed.username = '';
79
+ parsed.password = '';
80
+ return "".concat(parsed.toString().replace(/\/$/, ''), " (credentials redacted)");
81
+ } catch (unused) {
82
+ return url;
83
+ }
84
+ }
57
85
  var status = function status(ctx) {
86
+ var _process_env_e_key, _cfg_migratedFrom, _cfg_unknownKeys, _cfg_queries;
58
87
  var values = (0, _sharedts.parse)(ctx.argv, "usage: ".concat(ctx.name, " ").concat(_indexts.USAGE.status), _object_spread({}, _sharedts.FORMAT, _sharedts.CONFIG)).values;
59
88
  var format = (0, _sharedts.formatOf)(values);
60
89
  var cfg = ctx.resolveConfig(values.config);
@@ -70,31 +99,62 @@ var status = function status(ctx) {
70
99
  // transaction for, floored at 30s -- read back from the connection rather than
71
100
  // recomputed here, so this always reports what open() actually set.
72
101
  var busyTimeoutMs = db.prepare('PRAGMA busy_timeout').get().timeout;
102
+ // The env var holds the token; only its name and whether it is set are ever reported.
103
+ var keyEnv = (e === null || e === void 0 ? void 0 : e.key) ? {
104
+ name: e.key,
105
+ set: ((_process_env_e_key = process.env[e.key]) !== null && _process_env_e_key !== void 0 ? _process_env_e_key : '') !== ''
106
+ } : null;
73
107
  var result = {
108
+ config: cfg.configPath,
109
+ configVersion: _configts.SUPPORTED_CONFIG_VERSION,
110
+ migratedFrom: (_cfg_migratedFrom = cfg.migratedFrom) !== null && _cfg_migratedFrom !== void 0 ? _cfg_migratedFrom : null,
111
+ unknownConfigKeys: (_cfg_unknownKeys = cfg.unknownKeys) !== null && _cfg_unknownKeys !== void 0 ? _cfg_unknownKeys : null,
112
+ tree: cfg.baseDir,
113
+ cache: (0, _nodepath.dirname)(dbPath),
74
114
  db: dbPath,
115
+ cacheSchema: _dbts.SCHEMA_VERSION,
75
116
  docs: (0, _dbts.docCount)(db),
117
+ unparseableFrontmatter: parseErrorCount(db),
76
118
  features: features.on,
77
119
  featuresOff: features.off,
78
120
  embed: e ? _object_spread({
79
121
  type: e.type,
80
122
  model: e.model,
123
+ dir: e.type === 'static' ? (0, _embedts.modelDir)(e.model) : null,
124
+ url: e.url ? redactUrl(e.url) : null,
125
+ keyEnv: keyEnv,
81
126
  downloaded: hasModel
82
127
  }, vectors !== null && vectors !== void 0 ? vectors : {}) : null,
83
128
  presets: presets,
129
+ queries: Object.keys((_cfg_queries = cfg.queries) !== null && _cfg_queries !== void 0 ? _cfg_queries : {}).length,
130
+ watcherPid: (0, _dbts.getMeta)(db, 'watch_pid'),
84
131
  watcherHeartbeatSecondsAgo: heartbeat ? Math.round((Date.now() - Date.parse(heartbeat)) / 1000) : null,
85
132
  busyTimeoutMs: busyTimeoutMs
86
133
  };
87
134
  if (format === 'json') {
88
135
  console.log(JSON.stringify(result, null, 2));
89
136
  } else {
90
- console.log("db: ".concat(result.db));
91
- console.log("docs: ".concat(result.docs));
137
+ var migrated = cfg.migratedFrom !== undefined ? ", migrated from v".concat(cfg.migratedFrom, " on this run") : '';
138
+ console.log("config: ".concat(result.config, " (v").concat(_configts.SUPPORTED_CONFIG_VERSION).concat(migrated, ")"));
139
+ // A load-time stderr warning has scrolled away by the time anyone looks here.
140
+ if (cfg.unknownKeys) console.log(" unknown keys, ignored: ".concat(cfg.unknownKeys.join(', ')));
141
+ console.log("tree: ".concat(result.tree));
142
+ console.log("cache: ".concat(result.cache, " (schema ").concat(_dbts.SCHEMA_VERSION, "; delete this directory to reset)"));
143
+ console.log("docs: ".concat(result.docs).concat(result.unparseableFrontmatter > 0 ? " (".concat(result.unparseableFrontmatter, " with unparseable frontmatter: WHERE _parse_error IS NOT NULL)") : ''));
144
+ console.log('');
92
145
  console.log((0, _outputts.featuresLine)(features));
93
- // One authoritative line, off states included: an absent model reads as a degraded
94
- // search, not as an empty corpus.
95
- if (!e) console.log('embed: off (no preset asks for vectors)');
96
- else if (!hasModel) console.log("embed: ".concat(e.type, " ").concat(e.model, " — unavailable, so search runs on words and links only (").concat((0, _embedts.isDownloadable)(e.model) ? "run `".concat(ctx.name, " download`") : "no ".concat(_embedts.MODEL_FILENAMES, " in that directory"), ")"));
97
- else console.log("embed: ".concat(e.type, " ").concat(e.model).concat(vectors ? " (vectors: ".concat(vectors.embedded, " embedded, ").concat(vectors.pending, " pending — embedded on the first semantic search)") : ''));
146
+ // One authoritative block, off states included: an absent model reads as a degraded search,
147
+ // not as an empty corpus.
148
+ if (!e) console.log('embed: off (no preset asks for vectors)');
149
+ else {
150
+ console.log("embed: ".concat(e.type, " ").concat(e.model));
151
+ if (e.type === 'static') console.log(" model: ".concat((0, _embedts.modelDir)(e.model), " (").concat(hasModel ? 'present' : "missing, ".concat((0, _embedts.isDownloadable)(e.model) ? "run `".concat(ctx.name, " download`") : "no ".concat(_embedts.MODEL_FILENAMES, " in that directory")), ")"));
152
+ if (e.url) console.log(" url: ".concat(redactUrl(e.url)));
153
+ if (keyEnv) console.log(" key: env ".concat(keyEnv.name, " (").concat(keyEnv.set ? 'set' : 'NOT SET', ")"));
154
+ if (!hasModel) console.log(' vectors: off until the model is present; search runs on words and links');
155
+ else if (vectors) console.log(" vectors: ".concat(vectors.embedded, " embedded, ").concat(vectors.pending, " pending (embedded on the first semantic search)"));
156
+ }
157
+ console.log('');
98
158
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
99
159
  try {
100
160
  for(var _iterator = (0, _outputts.presetsLines)(presets)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -115,8 +175,11 @@ var status = function status(ctx) {
115
175
  }
116
176
  }
117
177
  }
118
- console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: no watcher' : "watcher: last heartbeat ".concat(result.watcherHeartbeatSecondsAgo, "s ago"));
119
- console.log("busy_timeout: ".concat(result.busyTimeoutMs, "ms (derived: 3x the largest reconcile this cache has recorded, floored at 30000ms)"));
178
+ console.log('');
179
+ console.log("queries: ".concat(result.queries, " saved (").concat(ctx.name, " --list)"));
180
+ var pid = result.watcherPid ? "pid ".concat(result.watcherPid, ", ") : '';
181
+ console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: none' : "watcher: ".concat(pid, "last heartbeat ").concat(result.watcherHeartbeatSecondsAgo, "s ago"));
182
+ console.log("sqlite: busy_timeout ".concat(result.busyTimeoutMs, "ms (derived: 3x the largest reconcile this cache has recorded, floored at 30000ms)"));
120
183
  }
121
184
  db.close();
122
185
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/status.ts"],"sourcesContent":["import { presetCoverage } from '../commands.ts';\nimport { embedConfig, featureStates } from '../config.ts';\nimport { docCount, getMeta, open } from '../db.ts';\nimport { isDownloadable, MODEL_FILENAMES, modelPresent } from '../features/embed.ts';\nimport { featuresLine, presetsLines } from '../output.ts';\nimport { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, formatOf, parse, printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\n// Vectors are computed on the first semantic query, not at reconcile, so a tree can have a\n// semantic-on preset with nothing embedded yet -- reported here because a fast `rebuild` on\n// such a tree otherwise reads as \"the feature isn't on\".\nfunction vectorState(db: ReturnType<typeof open>['db']): { embedded: number; pending: number } | null {\n try {\n const row = db.prepare('SELECT COUNT(vector) AS embedded, COUNT(*) - COUNT(vector) AS pending FROM embeddings').get() as { embedded: number; pending: number };\n return row;\n } catch {\n return null;\n }\n}\n\nconst status: Command = (ctx) => {\n const { values } = parse(ctx.argv, `usage: ${ctx.name} ${USAGE.status}`, { ...FORMAT, ...CONFIG });\n const format = formatOf(values);\n const cfg = ctx.resolveConfig(values.config as string | undefined);\n const { db, dbPath, warnings } = open(cfg);\n printWarnings(warnings);\n\n const features = featureStates(cfg);\n const e = embedConfig(cfg);\n const hasModel = e ? modelPresent(cfg) : false;\n const vectors = e ? vectorState(db) : null;\n const presets = presetCoverage(db, cfg);\n const heartbeat = getMeta(db, 'watch_heartbeat');\n // Derived at open() (F): 3x the largest reconcile this cache has ever held its write\n // transaction for, floored at 30s -- read back from the connection rather than\n // recomputed here, so this always reports what open() actually set.\n const busyTimeoutMs = (db.prepare('PRAGMA busy_timeout').get() as { timeout: number }).timeout;\n const result = {\n db: dbPath,\n docs: docCount(db),\n features: features.on,\n featuresOff: features.off,\n embed: e ? { type: e.type, model: e.model, downloaded: hasModel, ...(vectors ?? {}) } : null,\n presets,\n watcherHeartbeatSecondsAgo: heartbeat ? Math.round((Date.now() - Date.parse(heartbeat)) / 1000) : null,\n busyTimeoutMs,\n };\n\n if (format === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(`db: ${result.db}`);\n console.log(`docs: ${result.docs}`);\n console.log(featuresLine(features));\n // One authoritative line, off states included: an absent model reads as a degraded\n // search, not as an empty corpus.\n if (!e) console.log('embed: off (no preset asks for vectors)');\n else if (!hasModel) console.log(`embed: ${e.type} ${e.model} — unavailable, so search runs on words and links only (${isDownloadable(e.model) ? `run \\`${ctx.name} download\\`` : `no ${MODEL_FILENAMES} in that directory`})`);\n else console.log(`embed: ${e.type} ${e.model}${vectors ? ` (vectors: ${vectors.embedded} embedded, ${vectors.pending} pending — embedded on the first semantic search)` : ''}`);\n for (const line of presetsLines(presets)) console.log(line);\n console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: no watcher' : `watcher: last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);\n console.log(`busy_timeout: ${result.busyTimeoutMs}ms (derived: 3x the largest reconcile this cache has recorded, floored at 30000ms)`);\n }\n db.close();\n};\nexport default status;\n"],"names":["vectorState","db","row","prepare","get","status","ctx","values","parse","argv","USAGE","name","FORMAT","CONFIG","format","formatOf","cfg","resolveConfig","config","open","dbPath","warnings","printWarnings","features","featureStates","e","embedConfig","hasModel","modelPresent","vectors","presets","presetCoverage","heartbeat","getMeta","busyTimeoutMs","timeout","result","docs","docCount","on","featuresOff","off","embed","type","model","downloaded","watcherHeartbeatSecondsAgo","Math","round","Date","now","console","log","JSON","stringify","featuresLine","isDownloadable","MODEL_FILENAMES","embedded","pending","presetsLines","line","close"],"mappings":";;;;+BAkEA;;;eAAA;;;0BAlE+B;wBACY;oBACH;uBACsB;wBACnB;uBACrB;wBACyC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAG/D,2FAA2F;AAC3F,4FAA4F;AAC5F,yDAAyD;AACzD,SAASA,YAAYC,EAAiC;IACpD,IAAI;QACF,IAAMC,MAAMD,GAAGE,OAAO,CAAC,yFAAyFC,GAAG;QACnH,OAAOF;IACT,EAAE,eAAM;QACN,OAAO;IACT;AACF;AAEA,IAAMG,SAAkB,gBAACC;IACvB,IAAM,AAAEC,SAAWC,IAAAA,eAAK,EAACF,IAAIG,IAAI,EAAE,AAAC,UAAqBC,OAAZJ,IAAIK,IAAI,EAAC,KAAgB,OAAbD,cAAK,CAACL,MAAM,GAAI,mBAAKO,gBAAM,EAAKC,gBAAM,GAAvFN;IACR,IAAMO,SAASC,IAAAA,kBAAQ,EAACR;IACxB,IAAMS,MAAMV,IAAIW,aAAa,CAACV,OAAOW,MAAM;IAC3C,IAAiCC,QAAAA,IAAAA,UAAI,EAACH,MAA9Bf,KAAyBkB,MAAzBlB,IAAImB,SAAqBD,MAArBC,QAAQC,WAAaF,MAAbE;IACpBC,IAAAA,uBAAa,EAACD;IAEd,IAAME,WAAWC,IAAAA,uBAAa,EAACR;IAC/B,IAAMS,IAAIC,IAAAA,qBAAW,EAACV;IACtB,IAAMW,WAAWF,IAAIG,IAAAA,qBAAY,EAACZ,OAAO;IACzC,IAAMa,UAAUJ,IAAIzB,YAAYC,MAAM;IACtC,IAAM6B,UAAUC,IAAAA,0BAAc,EAAC9B,IAAIe;IACnC,IAAMgB,YAAYC,IAAAA,aAAO,EAAChC,IAAI;IAC9B,qFAAqF;IACrF,+EAA+E;IAC/E,oEAAoE;IACpE,IAAMiC,gBAAgB,AAACjC,GAAGE,OAAO,CAAC,uBAAuBC,GAAG,GAA2B+B,OAAO;IAC9F,IAAMC,SAAS;QACbnC,IAAImB;QACJiB,MAAMC,IAAAA,cAAQ,EAACrC;QACfsB,UAAUA,SAASgB,EAAE;QACrBC,aAAajB,SAASkB,GAAG;QACzBC,OAAOjB,IAAI;YAAEkB,MAAMlB,EAAEkB,IAAI;YAAEC,OAAOnB,EAAEmB,KAAK;YAAEC,YAAYlB;WAAcE,oBAAAA,qBAAAA,UAAW,CAAC,KAAO;QACxFC,SAAAA;QACAgB,4BAA4Bd,YAAYe,KAAKC,KAAK,CAAC,AAACC,CAAAA,KAAKC,GAAG,KAAKD,KAAKzC,KAAK,CAACwB,UAAS,IAAK,QAAQ;QAClGE,eAAAA;IACF;IAEA,IAAIpB,WAAW,QAAQ;QACrBqC,QAAQC,GAAG,CAACC,KAAKC,SAAS,CAAClB,QAAQ,MAAM;IAC3C,OAAO;QACLe,QAAQC,GAAG,CAAC,AAAC,OAAgB,OAAVhB,OAAOnC,EAAE;QAC5BkD,QAAQC,GAAG,CAAC,AAAC,SAAoB,OAAZhB,OAAOC,IAAI;QAChCc,QAAQC,GAAG,CAACG,IAAAA,sBAAY,EAAChC;QACzB,mFAAmF;QACnF,kCAAkC;QAClC,IAAI,CAACE,GAAG0B,QAAQC,GAAG,CAAC;aACf,IAAI,CAACzB,UAAUwB,QAAQC,GAAG,CAAC,AAAC,UAAmB3B,OAAVA,EAAEkB,IAAI,EAAC,KAAqEa,OAAlE/B,EAAEmB,KAAK,EAAC,4DAA+J,OAArGY,IAAAA,uBAAc,EAAC/B,EAAEmB,KAAK,IAAI,AAAC,QAAiB,OAATtC,IAAIK,IAAI,EAAC,gBAAe,AAAC,MAAqB,OAAhB8C,wBAAe,EAAC,uBAAoB;aACtNN,QAAQC,GAAG,CAAC,AAAC,UAAmB3B,OAAVA,EAAEkB,IAAI,EAAC,KAAad,OAAVJ,EAAEmB,KAAK,EAAiI,OAA9Hf,UAAU,AAAC,cAA2CA,OAA9BA,QAAQ6B,QAAQ,EAAC,eAA6B,OAAhB7B,QAAQ8B,OAAO,EAAC,uDAAqD;YACrK,kCAAA,2BAAA;;YAAL,QAAK,YAAcC,IAAAA,sBAAY,EAAC9B,6BAA3B,SAAA,6BAAA,QAAA,yBAAA;gBAAA,IAAM+B,OAAN;gBAAqCV,QAAQC,GAAG,CAACS;;;YAAjD;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;QACLV,QAAQC,GAAG,CAAChB,OAAOU,0BAA0B,KAAK,OAAO,wBAAwB,AAAC,2BAA4D,OAAlCV,OAAOU,0BAA0B,EAAC;QAC9IK,QAAQC,GAAG,CAAC,AAAC,iBAAqC,OAArBhB,OAAOF,aAAa,EAAC;IACpD;IACAjC,GAAG6D,KAAK;AACV;IACA,WAAezD"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/status.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { presetCoverage } from '../commands.ts';\nimport { embedConfig, featureStates, SUPPORTED_CONFIG_VERSION } from '../config.ts';\nimport { docCount, getMeta, open, SCHEMA_VERSION } from '../db.ts';\nimport { isDownloadable, MODEL_FILENAMES, modelDir, modelPresent } from '../features/embed.ts';\nimport { featuresLine, presetsLines } from '../output.ts';\nimport { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, formatOf, parse, printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\n// status names what you cannot read off the config file: locations sense chose, values it\n// derived, state it stored. Config content is not echoed -- the config line says which file to\n// read, and duplicating its globs here would create two places that disagree after an edit.\n// The exception is the embed block's url and key, whose effect is remote and otherwise invisible.\n\n// Vectors are computed on the first semantic query, not at reconcile, so a tree can have a\n// semantic-on preset with nothing embedded yet -- reported here because a fast reconcile on\n// such a tree otherwise reads as \"the feature isn't on\".\nfunction vectorState(db: ReturnType<typeof open>['db']): { embedded: number; pending: number } | null {\n try {\n const row = db.prepare('SELECT COUNT(vector) AS embedded, COUNT(*) - COUNT(vector) AS pending FROM embeddings').get() as { embedded: number; pending: number };\n return row;\n } catch {\n return null;\n }\n}\n\nfunction parseErrorCount(db: ReturnType<typeof open>['db']): number {\n const row = db.prepare(`SELECT COUNT(*) AS n FROM frontmatter WHERE \"_parse_error\" IS NOT NULL`).get() as { n: number };\n return row.n;\n}\n\n// A URL can carry credentials in its userinfo (https://user:pass@host/v1). status output gets\n// pasted into issues and transcripts, so it is always safe to paste.\nexport function redactUrl(url: string): string {\n try {\n const parsed = new URL(url);\n if (!parsed.username && !parsed.password) return url;\n parsed.username = '';\n parsed.password = '';\n return `${parsed.toString().replace(/\\/$/, '')} (credentials redacted)`;\n } catch {\n return url;\n }\n}\n\nconst status: Command = (ctx) => {\n const { values } = parse(ctx.argv, `usage: ${ctx.name} ${USAGE.status}`, { ...FORMAT, ...CONFIG });\n const format = formatOf(values);\n const cfg = ctx.resolveConfig(values.config as string | undefined);\n const { db, dbPath, warnings } = open(cfg);\n printWarnings(warnings);\n\n const features = featureStates(cfg);\n const e = embedConfig(cfg);\n const hasModel = e ? modelPresent(cfg) : false;\n const vectors = e ? vectorState(db) : null;\n const presets = presetCoverage(db, cfg);\n const heartbeat = getMeta(db, 'watch_heartbeat');\n // Derived at open() (F): 3x the largest reconcile this cache has ever held its write\n // transaction for, floored at 30s -- read back from the connection rather than\n // recomputed here, so this always reports what open() actually set.\n const busyTimeoutMs = (db.prepare('PRAGMA busy_timeout').get() as { timeout: number }).timeout;\n // The env var holds the token; only its name and whether it is set are ever reported.\n const keyEnv = e?.key ? { name: e.key, set: (process.env[e.key] ?? '') !== '' } : null;\n const result = {\n config: cfg.configPath,\n configVersion: SUPPORTED_CONFIG_VERSION,\n migratedFrom: cfg.migratedFrom ?? null,\n unknownConfigKeys: cfg.unknownKeys ?? null,\n tree: cfg.baseDir,\n cache: dirname(dbPath),\n db: dbPath,\n cacheSchema: SCHEMA_VERSION,\n docs: docCount(db),\n unparseableFrontmatter: parseErrorCount(db),\n features: features.on,\n featuresOff: features.off,\n embed: e ? { type: e.type, model: e.model, dir: e.type === 'static' ? modelDir(e.model) : null, url: e.url ? redactUrl(e.url) : null, keyEnv, downloaded: hasModel, ...(vectors ?? {}) } : null,\n presets,\n queries: Object.keys(cfg.queries ?? {}).length,\n watcherPid: getMeta(db, 'watch_pid'),\n watcherHeartbeatSecondsAgo: heartbeat ? Math.round((Date.now() - Date.parse(heartbeat)) / 1000) : null,\n busyTimeoutMs,\n };\n\n if (format === 'json') {\n console.log(JSON.stringify(result, null, 2));\n } else {\n const migrated = cfg.migratedFrom !== undefined ? `, migrated from v${cfg.migratedFrom} on this run` : '';\n console.log(`config: ${result.config} (v${SUPPORTED_CONFIG_VERSION}${migrated})`);\n // A load-time stderr warning has scrolled away by the time anyone looks here.\n if (cfg.unknownKeys) console.log(` unknown keys, ignored: ${cfg.unknownKeys.join(', ')}`);\n console.log(`tree: ${result.tree}`);\n console.log(`cache: ${result.cache} (schema ${SCHEMA_VERSION}; delete this directory to reset)`);\n console.log(`docs: ${result.docs}${result.unparseableFrontmatter > 0 ? ` (${result.unparseableFrontmatter} with unparseable frontmatter: WHERE _parse_error IS NOT NULL)` : ''}`);\n console.log('');\n console.log(featuresLine(features));\n // One authoritative block, off states included: an absent model reads as a degraded search,\n // not as an empty corpus.\n if (!e) console.log('embed: off (no preset asks for vectors)');\n else {\n console.log(`embed: ${e.type} ${e.model}`);\n if (e.type === 'static') console.log(` model: ${modelDir(e.model)} (${hasModel ? 'present' : `missing, ${isDownloadable(e.model) ? `run \\`${ctx.name} download\\`` : `no ${MODEL_FILENAMES} in that directory`}`})`);\n if (e.url) console.log(` url: ${redactUrl(e.url)}`);\n if (keyEnv) console.log(` key: env ${keyEnv.name} (${keyEnv.set ? 'set' : 'NOT SET'})`);\n if (!hasModel) console.log(' vectors: off until the model is present; search runs on words and links');\n else if (vectors) console.log(` vectors: ${vectors.embedded} embedded, ${vectors.pending} pending (embedded on the first semantic search)`);\n }\n console.log('');\n for (const line of presetsLines(presets)) console.log(line);\n console.log('');\n console.log(`queries: ${result.queries} saved (${ctx.name} --list)`);\n const pid = result.watcherPid ? `pid ${result.watcherPid}, ` : '';\n console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: none' : `watcher: ${pid}last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);\n console.log(`sqlite: busy_timeout ${result.busyTimeoutMs}ms (derived: 3x the largest reconcile this cache has recorded, floored at 30000ms)`);\n }\n db.close();\n};\nexport default status;\n"],"names":["redactUrl","vectorState","db","row","prepare","get","parseErrorCount","n","url","parsed","URL","username","password","toString","replace","status","ctx","process","cfg","values","parse","argv","USAGE","name","FORMAT","CONFIG","format","formatOf","resolveConfig","config","open","dbPath","warnings","printWarnings","features","featureStates","e","embedConfig","hasModel","modelPresent","vectors","presets","presetCoverage","heartbeat","getMeta","busyTimeoutMs","timeout","keyEnv","key","set","env","result","configPath","configVersion","SUPPORTED_CONFIG_VERSION","migratedFrom","unknownConfigKeys","unknownKeys","tree","baseDir","cache","dirname","cacheSchema","SCHEMA_VERSION","docs","docCount","unparseableFrontmatter","on","featuresOff","off","embed","type","model","dir","modelDir","downloaded","queries","Object","keys","length","watcherPid","watcherHeartbeatSecondsAgo","Math","round","Date","now","console","log","JSON","stringify","migrated","undefined","join","featuresLine","isDownloadable","MODEL_FILENAMES","embedded","pending","presetsLines","line","pid","close"],"mappings":";;;;;;;;;;;QAuHA;eAAA;;QArFgBA;eAAAA;;;wBAlCQ;0BACO;wBACsC;oBACb;uBACgB;wBAC7B;uBACrB;wBACyC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAG/D,0FAA0F;AAC1F,+FAA+F;AAC/F,4FAA4F;AAC5F,kGAAkG;AAElG,2FAA2F;AAC3F,4FAA4F;AAC5F,yDAAyD;AACzD,SAASC,YAAYC,EAAiC;IACpD,IAAI;QACF,IAAMC,MAAMD,GAAGE,OAAO,CAAC,yFAAyFC,GAAG;QACnH,OAAOF;IACT,EAAE,eAAM;QACN,OAAO;IACT;AACF;AAEA,SAASG,gBAAgBJ,EAAiC;IACxD,IAAMC,MAAMD,GAAGE,OAAO,CAAC,0EAA0EC,GAAG;IACpG,OAAOF,IAAII,CAAC;AACd;AAIO,SAASP,UAAUQ,GAAW;IACnC,IAAI;QACF,IAAMC,SAAS,IAAIC,IAAIF;QACvB,IAAI,CAACC,OAAOE,QAAQ,IAAI,CAACF,OAAOG,QAAQ,EAAE,OAAOJ;QACjDC,OAAOE,QAAQ,GAAG;QAClBF,OAAOG,QAAQ,GAAG;QAClB,OAAO,AAAC,GAAuC,OAArCH,OAAOI,QAAQ,GAAGC,OAAO,CAAC,OAAO,KAAI;IACjD,EAAE,eAAM;QACN,OAAON;IACT;AACF;AAEA,IAAMO,SAAkB,gBAACC;QAkBsBC,oBAI7BC,mBACKA,kBAWEA;IAjCvB,IAAM,AAAEC,SAAWC,IAAAA,eAAK,EAACJ,IAAIK,IAAI,EAAE,AAAC,UAAqBC,OAAZN,IAAIO,IAAI,EAAC,KAAgB,OAAbD,cAAK,CAACP,MAAM,GAAI,mBAAKS,gBAAM,EAAKC,gBAAM,GAAvFN;IACR,IAAMO,SAASC,IAAAA,kBAAQ,EAACR;IACxB,IAAMD,MAAMF,IAAIY,aAAa,CAACT,OAAOU,MAAM;IAC3C,IAAiCC,QAAAA,IAAAA,UAAI,EAACZ,MAA9BhB,KAAyB4B,MAAzB5B,IAAI6B,SAAqBD,MAArBC,QAAQC,WAAaF,MAAbE;IACpBC,IAAAA,uBAAa,EAACD;IAEd,IAAME,WAAWC,IAAAA,uBAAa,EAACjB;IAC/B,IAAMkB,IAAIC,IAAAA,qBAAW,EAACnB;IACtB,IAAMoB,WAAWF,IAAIG,IAAAA,qBAAY,EAACrB,OAAO;IACzC,IAAMsB,UAAUJ,IAAInC,YAAYC,MAAM;IACtC,IAAMuC,UAAUC,IAAAA,0BAAc,EAACxC,IAAIgB;IACnC,IAAMyB,YAAYC,IAAAA,aAAO,EAAC1C,IAAI;IAC9B,qFAAqF;IACrF,+EAA+E;IAC/E,oEAAoE;IACpE,IAAM2C,gBAAgB,AAAC3C,GAAGE,OAAO,CAAC,uBAAuBC,GAAG,GAA2ByC,OAAO;IAC9F,sFAAsF;IACtF,IAAMC,SAASX,CAAAA,cAAAA,wBAAAA,EAAGY,GAAG,IAAG;QAAEzB,MAAMa,EAAEY,GAAG;QAAEC,KAAK,EAAChC,qBAAAA,QAAQiC,GAAG,CAACd,EAAEY,GAAG,CAAC,cAAlB/B,gCAAAA,qBAAsB,QAAQ;IAAG,IAAI;IAClF,IAAMkC,SAAS;QACbtB,QAAQX,IAAIkC,UAAU;QACtBC,eAAeC,kCAAwB;QACvCC,YAAY,GAAErC,oBAAAA,IAAIqC,YAAY,cAAhBrC,+BAAAA,oBAAoB;QAClCsC,iBAAiB,GAAEtC,mBAAAA,IAAIuC,WAAW,cAAfvC,8BAAAA,mBAAmB;QACtCwC,MAAMxC,IAAIyC,OAAO;QACjBC,OAAOC,IAAAA,iBAAO,EAAC9B;QACf7B,IAAI6B;QACJ+B,aAAaC,oBAAc;QAC3BC,MAAMC,IAAAA,cAAQ,EAAC/D;QACfgE,wBAAwB5D,gBAAgBJ;QACxCgC,UAAUA,SAASiC,EAAE;QACrBC,aAAalC,SAASmC,GAAG;QACzBC,OAAOlC,IAAI;YAAEmC,MAAMnC,EAAEmC,IAAI;YAAEC,OAAOpC,EAAEoC,KAAK;YAAEC,KAAKrC,EAAEmC,IAAI,KAAK,WAAWG,IAAAA,iBAAQ,EAACtC,EAAEoC,KAAK,IAAI;YAAMhE,KAAK4B,EAAE5B,GAAG,GAAGR,UAAUoC,EAAE5B,GAAG,IAAI;YAAMuC,QAAAA;YAAQ4B,YAAYrC;WAAcE,oBAAAA,qBAAAA,UAAW,CAAC,KAAO;QAC3LC,SAAAA;QACAmC,SAASC,OAAOC,IAAI,EAAC5D,eAAAA,IAAI0D,OAAO,cAAX1D,0BAAAA,eAAe,CAAC,GAAG6D,MAAM;QAC9CC,YAAYpC,IAAAA,aAAO,EAAC1C,IAAI;QACxB+E,4BAA4BtC,YAAYuC,KAAKC,KAAK,CAAC,AAACC,CAAAA,KAAKC,GAAG,KAAKD,KAAKhE,KAAK,CAACuB,UAAS,IAAK,QAAQ;QAClGE,eAAAA;IACF;IAEA,IAAInB,WAAW,QAAQ;QACrB4D,QAAQC,GAAG,CAACC,KAAKC,SAAS,CAACtC,QAAQ,MAAM;IAC3C,OAAO;QACL,IAAMuC,WAAWxE,IAAIqC,YAAY,KAAKoC,YAAY,AAAC,oBAAoC,OAAjBzE,IAAIqC,YAAY,EAAC,kBAAgB;QACvG+B,QAAQC,GAAG,CAAC,AAAC,aAA+BjC,OAAnBH,OAAOtB,MAAM,EAAC,OAAgC6D,OAA3BpC,kCAAwB,EAAY,OAAToC,UAAS;QAChF,8EAA8E;QAC9E,IAAIxE,IAAIuC,WAAW,EAAE6B,QAAQC,GAAG,CAAC,AAAC,oCAA8D,OAA3BrE,IAAIuC,WAAW,CAACmC,IAAI,CAAC;QAC1FN,QAAQC,GAAG,CAAC,AAAC,aAAwB,OAAZpC,OAAOO,IAAI;QACpC4B,QAAQC,GAAG,CAAC,AAAC,aAAoCxB,OAAxBZ,OAAOS,KAAK,EAAC,aAA0B,OAAfG,oBAAc,EAAC;QAChEuB,QAAQC,GAAG,CAAC,AAAC,aAA0BpC,OAAdA,OAAOa,IAAI,EAAgJ,OAA7Ib,OAAOe,sBAAsB,GAAG,IAAI,AAAC,MAAmC,OAA9Bf,OAAOe,sBAAsB,EAAC,oEAAkE;QACjLoB,QAAQC,GAAG,CAAC;QACZD,QAAQC,GAAG,CAACM,IAAAA,sBAAY,EAAC3D;QACzB,4FAA4F;QAC5F,0BAA0B;QAC1B,IAAI,CAACE,GAAGkD,QAAQC,GAAG,CAAC;aACf;YACHD,QAAQC,GAAG,CAAC,AAAC,aAAsBnD,OAAVA,EAAEmC,IAAI,EAAC,KAAW,OAARnC,EAAEoC,KAAK;YAC1C,IAAIpC,EAAEmC,IAAI,KAAK,UAAUe,QAAQC,GAAG,CAAC,AAAC,sBAA2CjD,OAAtBoC,IAAAA,iBAAQ,EAACtC,EAAEoC,KAAK,GAAE,MAA8I,OAA1IlC,WAAW,YAAY,AAAC,YAAgH,OAArGwD,IAAAA,uBAAc,EAAC1D,EAAEoC,KAAK,IAAI,AAAC,QAAiB,OAATxD,IAAIO,IAAI,EAAC,gBAAe,AAAC,MAAqB,OAAhBwE,wBAAe,EAAC,wBAAsB;YAC3N,IAAI3D,EAAE5B,GAAG,EAAE8E,QAAQC,GAAG,CAAC,AAAC,sBAAsC,OAAjBvF,UAAUoC,EAAE5B,GAAG;YAC5D,IAAIuC,QAAQuC,QAAQC,GAAG,CAAC,AAAC,0BAAyCxC,OAAhBA,OAAOxB,IAAI,EAAC,MAAmC,OAA/BwB,OAAOE,GAAG,GAAG,QAAQ,WAAU;YACjG,IAAI,CAACX,UAAUgD,QAAQC,GAAG,CAAC;iBACtB,IAAI/C,SAAS8C,QAAQC,GAAG,CAAC,AAAC,sBAAmD/C,OAA9BA,QAAQwD,QAAQ,EAAC,eAA6B,OAAhBxD,QAAQyD,OAAO,EAAC;QACpG;QACAX,QAAQC,GAAG,CAAC;YACP,kCAAA,2BAAA;;YAAL,QAAK,YAAcW,IAAAA,sBAAY,EAACzD,6BAA3B,SAAA,6BAAA,QAAA,yBAAA;gBAAA,IAAM0D,OAAN;gBAAqCb,QAAQC,GAAG,CAACY;;;YAAjD;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;QACLb,QAAQC,GAAG,CAAC;QACZD,QAAQC,GAAG,CAAC,AAAC,aAAqCvE,OAAzBmC,OAAOyB,OAAO,EAAC,YAAmB,OAAT5D,IAAIO,IAAI,EAAC;QAC3D,IAAM6E,MAAMjD,OAAO6B,UAAU,GAAG,AAAC,OAAwB,OAAlB7B,OAAO6B,UAAU,EAAC,QAAM;QAC/DM,QAAQC,GAAG,CAACpC,OAAO8B,0BAA0B,KAAK,OAAO,mBAAmB,AAAC,aAAiC9B,OAArBiD,KAAI,mBAAmD,OAAlCjD,OAAO8B,0BAA0B,EAAC;QAChJK,QAAQC,GAAG,CAAC,AAAC,0BAA8C,OAArBpC,OAAON,aAAa,EAAC;IAC7D;IACA3C,GAAGmG,KAAK;AACV;IACA,WAAetF"}
@@ -8,7 +8,6 @@ export interface SearchOptions {
8
8
  include?: string[];
9
9
  exclude?: string[];
10
10
  noExclude?: boolean;
11
- probe?: boolean;
12
11
  }
13
12
  export declare function search(db: DatabaseSync, cfg: ResolvedConfig, terms: string, opts?: SearchOptions): Promise<Row[]>;
14
13
  export declare function scopedPaths(db: DatabaseSync, cfg: ResolvedConfig, overrides: SearchOverrides): Set<string>;
@@ -16,6 +15,7 @@ export interface PresetCoverage {
16
15
  name: string;
17
16
  files: number;
18
17
  embedded: number;
18
+ semantic: boolean;
19
19
  }
20
20
  export declare function presetCoverage(db: DatabaseSync, cfg: ResolvedConfig): PresetCoverage[];
21
21
  export interface TreeMap {
@@ -39,6 +39,7 @@ export interface Peek {
39
39
  path: string;
40
40
  tokens: number;
41
41
  frontmatter: Row;
42
+ parseError: string | null;
42
43
  sections: Row[];
43
44
  outbound: string[];
44
45
  backlinks: string[];
@@ -8,7 +8,6 @@ export interface SearchOptions {
8
8
  include?: string[];
9
9
  exclude?: string[];
10
10
  noExclude?: boolean;
11
- probe?: boolean;
12
11
  }
13
12
  export declare function search(db: DatabaseSync, cfg: ResolvedConfig, terms: string, opts?: SearchOptions): Promise<Row[]>;
14
13
  export declare function scopedPaths(db: DatabaseSync, cfg: ResolvedConfig, overrides: SearchOverrides): Set<string>;
@@ -16,6 +15,7 @@ export interface PresetCoverage {
16
15
  name: string;
17
16
  files: number;
18
17
  embedded: number;
18
+ semantic: boolean;
19
19
  }
20
20
  export declare function presetCoverage(db: DatabaseSync, cfg: ResolvedConfig): PresetCoverage[];
21
21
  export interface TreeMap {
@@ -39,6 +39,7 @@ export interface Peek {
39
39
  path: string;
40
40
  tokens: number;
41
41
  frontmatter: Row;
42
+ parseError: string | null;
42
43
  sections: Row[];
43
44
  outbound: string[];
44
45
  backlinks: string[];