@jcode.labs/ragmir 2.7.0 → 2.8.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 (94) hide show
  1. package/dist/access-log.d.ts.map +1 -1
  2. package/dist/access-log.js +65 -8
  3. package/dist/access-log.js.map +1 -1
  4. package/dist/chunking.d.ts.map +1 -1
  5. package/dist/chunking.js +29 -3
  6. package/dist/chunking.js.map +1 -1
  7. package/dist/cli.js +81 -21
  8. package/dist/cli.js.map +1 -1
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/config.js +73 -29
  11. package/dist/config.js.map +1 -1
  12. package/dist/defaults.d.ts +1 -0
  13. package/dist/defaults.d.ts.map +1 -1
  14. package/dist/defaults.js +6 -1
  15. package/dist/defaults.js.map +1 -1
  16. package/dist/destroy.d.ts.map +1 -1
  17. package/dist/destroy.js +23 -1
  18. package/dist/destroy.js.map +1 -1
  19. package/dist/doctor.d.ts.map +1 -1
  20. package/dist/doctor.js +40 -9
  21. package/dist/doctor.js.map +1 -1
  22. package/dist/embeddings.d.ts +4 -1
  23. package/dist/embeddings.d.ts.map +1 -1
  24. package/dist/embeddings.js +62 -14
  25. package/dist/embeddings.js.map +1 -1
  26. package/dist/evaluate.d.ts.map +1 -1
  27. package/dist/evaluate.js +48 -4
  28. package/dist/evaluate.js.map +1 -1
  29. package/dist/files.d.ts +8 -1
  30. package/dist/files.d.ts.map +1 -1
  31. package/dist/files.js +44 -8
  32. package/dist/files.js.map +1 -1
  33. package/dist/index-diagnostics.d.ts +1 -1
  34. package/dist/index-diagnostics.d.ts.map +1 -1
  35. package/dist/index-diagnostics.js +8 -3
  36. package/dist/index-diagnostics.js.map +1 -1
  37. package/dist/index-policy.d.ts +3 -0
  38. package/dist/index-policy.d.ts.map +1 -0
  39. package/dist/index-policy.js +28 -0
  40. package/dist/index-policy.js.map +1 -0
  41. package/dist/index.d.ts +2 -1
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +1 -0
  44. package/dist/index.js.map +1 -1
  45. package/dist/ingest.d.ts.map +1 -1
  46. package/dist/ingest.js +112 -54
  47. package/dist/ingest.js.map +1 -1
  48. package/dist/init.d.ts.map +1 -1
  49. package/dist/init.js +15 -3
  50. package/dist/init.js.map +1 -1
  51. package/dist/limits.d.ts +9 -0
  52. package/dist/limits.d.ts.map +1 -0
  53. package/dist/limits.js +25 -0
  54. package/dist/limits.js.map +1 -0
  55. package/dist/mcp.d.ts +3 -1
  56. package/dist/mcp.d.ts.map +1 -1
  57. package/dist/mcp.js +71 -14
  58. package/dist/mcp.js.map +1 -1
  59. package/dist/parsing.d.ts.map +1 -1
  60. package/dist/parsing.js +124 -24
  61. package/dist/parsing.js.map +1 -1
  62. package/dist/permissions.d.ts +3 -0
  63. package/dist/permissions.d.ts.map +1 -0
  64. package/dist/permissions.js +13 -0
  65. package/dist/permissions.js.map +1 -0
  66. package/dist/query.d.ts +2 -2
  67. package/dist/query.d.ts.map +1 -1
  68. package/dist/query.js +198 -39
  69. package/dist/query.js.map +1 -1
  70. package/dist/research.d.ts.map +1 -1
  71. package/dist/research.js +33 -4
  72. package/dist/research.js.map +1 -1
  73. package/dist/security.d.ts.map +1 -1
  74. package/dist/security.js +110 -14
  75. package/dist/security.js.map +1 -1
  76. package/dist/store.d.ts +3 -0
  77. package/dist/store.d.ts.map +1 -1
  78. package/dist/store.js +71 -72
  79. package/dist/store.js.map +1 -1
  80. package/dist/text.d.ts.map +1 -1
  81. package/dist/text.js +13 -1
  82. package/dist/text.js.map +1 -1
  83. package/dist/types.d.ts +94 -0
  84. package/dist/types.d.ts.map +1 -1
  85. package/dist/version.d.ts +1 -1
  86. package/dist/version.js +1 -1
  87. package/examples/document-evidence-benchmark/.ragmir/config.json +2 -1
  88. package/examples/document-evidence-benchmark/README.md +5 -2
  89. package/examples/document-evidence-benchmark/golden-queries.json +6 -0
  90. package/examples/document-evidence-benchmark/raw/contracts/pdf-control-evidence.pdf +32 -0
  91. package/examples/sovereign-rag-demo/.ragmir/config.json +2 -1
  92. package/examples/sovereign-rag-demo/README.md +9 -1
  93. package/package.json +3 -3
  94. package/skills/ragmir/SKILL.md +11 -3
@@ -1 +1 @@
1
- {"version":3,"file":"access-log.d.ts","sourceRoot":"","sources":["../src/access-log.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,MAAM,EACP,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,eAAe,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AA6BD,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAYvF;AA2BD,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,oBAAoB,CAAC,CAuD/B"}
1
+ {"version":3,"file":"access-log.d.ts","sourceRoot":"","sources":["../src/access-log.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,MAAM,EACP,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,eAAe,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAmCD,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBvF;AA2BD,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,oBAAoB,CAAC,CA2D/B"}
@@ -1,8 +1,9 @@
1
- import { createHash } from "node:crypto";
1
+ import { createHmac, randomBytes } from "node:crypto";
2
2
  import { existsSync } from "node:fs";
3
- import { appendFile, mkdir, readFile, stat, writeFile } from "node:fs/promises";
3
+ import { appendFile, readFile, stat, writeFile } from "node:fs/promises";
4
4
  import path from "node:path";
5
5
  import { loadConfig } from "./config.js";
6
+ import { ensurePrivateDirectory, hardenPrivateFile } from "./permissions.js";
6
7
  const ACCESS_LOG_ACTIONS = [
7
8
  "ingest",
8
9
  "search",
@@ -22,14 +23,19 @@ const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
22
23
  const MAX_ACCESS_LOG_BYTES = 10 * 1024 * 1024;
23
24
  /** Number of most recent lines retained when the log exceeds the byte cap. */
24
25
  const TRIMMED_ACCESS_LOG_LINES = 50_000;
26
+ const ACCESS_LOG_SALT_FILE = ".ragmir-access-log.salt";
25
27
  export async function recordAccess(config, event) {
26
28
  if (!config.accessLog) {
27
29
  return;
28
30
  }
29
31
  try {
30
- await mkdir(path.dirname(config.accessLogPath), { recursive: true });
32
+ await ensurePrivateDirectory(path.dirname(config.accessLogPath));
31
33
  await trimAccessLogIfNeeded(config.accessLogPath);
32
- await appendFile(config.accessLogPath, `${JSON.stringify(toLogLine(event))}\n`, "utf8");
34
+ await appendFile(config.accessLogPath, `${JSON.stringify(await toLogLine(config, event))}\n`, {
35
+ encoding: "utf8",
36
+ mode: 0o600,
37
+ });
38
+ await hardenPrivateFile(config.accessLogPath);
33
39
  }
34
40
  catch {
35
41
  // Access logging is best-effort so read-only workspaces do not block local use.
@@ -64,6 +70,7 @@ export async function accessLogUsageReport(options = {}) {
64
70
  const since = new Date(until.getTime() - days * MILLISECONDS_PER_DAY);
65
71
  const eventsByAction = emptyEventsByAction();
66
72
  const queryHashes = new Set();
73
+ const resultCountsByAction = emptyResultCountsByAction();
67
74
  let totalEvents = 0;
68
75
  let invalidLines = 0;
69
76
  let resultCountTotal = 0;
@@ -91,6 +98,8 @@ export async function accessLogUsageReport(options = {}) {
91
98
  if (typeof event.resultCount === "number") {
92
99
  resultCountTotal += event.resultCount;
93
100
  resultCountEvents += 1;
101
+ resultCountsByAction[event.action].total += event.resultCount;
102
+ resultCountsByAction[event.action].events += 1;
94
103
  }
95
104
  if (lastEventAt === null || event.timestamp > lastEventAt) {
96
105
  lastEventAt = event.timestamp;
@@ -106,21 +115,69 @@ export async function accessLogUsageReport(options = {}) {
106
115
  eventsByAction,
107
116
  uniqueQueryHashes: queryHashes.size,
108
117
  averageResultCount: resultCountEvents === 0 ? null : resultCountTotal / resultCountEvents,
118
+ averageResultCountByAction: averageResultCounts(resultCountsByAction),
109
119
  lastEventAt,
110
120
  };
111
121
  }
112
- function toLogLine(event) {
122
+ function emptyResultCountsByAction() {
123
+ return {
124
+ ingest: { total: 0, events: 0 },
125
+ search: { total: 0, events: 0 },
126
+ ask: { total: 0, events: 0 },
127
+ research: { total: 0, events: 0 },
128
+ evaluate: { total: 0, events: 0 },
129
+ "destroy-index": { total: 0, events: 0 },
130
+ };
131
+ }
132
+ function averageResultCounts(stats) {
133
+ return {
134
+ ingest: averageResultCount(stats.ingest),
135
+ search: averageResultCount(stats.search),
136
+ ask: averageResultCount(stats.ask),
137
+ research: averageResultCount(stats.research),
138
+ evaluate: averageResultCount(stats.evaluate),
139
+ "destroy-index": averageResultCount(stats["destroy-index"]),
140
+ };
141
+ }
142
+ function averageResultCount(stats) {
143
+ return stats.events === 0 ? null : stats.total / stats.events;
144
+ }
145
+ async function toLogLine(config, event) {
113
146
  return {
114
147
  timestamp: new Date().toISOString(),
115
148
  action: event.action,
116
- queryHash: event.query ? hashQuery(event.query) : undefined,
149
+ queryHash: event.query ? await hashQuery(config, event.query) : undefined,
117
150
  topK: event.topK,
118
151
  resultCount: event.resultCount,
119
152
  redactions: event.redactions,
120
153
  };
121
154
  }
122
- function hashQuery(query) {
123
- return createHash("sha256").update(query).digest("hex");
155
+ async function hashQuery(config, query) {
156
+ const salt = await accessLogSalt(config);
157
+ return createHmac("sha256", salt).update(query).digest("hex");
158
+ }
159
+ async function accessLogSalt(config) {
160
+ const saltPath = path.join(path.dirname(config.accessLogPath), ACCESS_LOG_SALT_FILE);
161
+ try {
162
+ return await readFile(saltPath);
163
+ }
164
+ catch (error) {
165
+ if (!isNodeError(error) || error.code !== "ENOENT") {
166
+ throw error;
167
+ }
168
+ }
169
+ const salt = randomBytes(32);
170
+ try {
171
+ await writeFile(saltPath, salt, { flag: "wx", mode: 0o600 });
172
+ await hardenPrivateFile(saltPath);
173
+ return salt;
174
+ }
175
+ catch (error) {
176
+ if (isNodeError(error) && error.code === "EEXIST") {
177
+ return readFile(saltPath);
178
+ }
179
+ throw error;
180
+ }
124
181
  }
125
182
  function emptyEventsByAction() {
126
183
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"access-log.js","sourceRoot":"","sources":["../src/access-log.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"access-log.js","sourceRoot":"","sources":["../src/access-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACxE,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AA4B5E,MAAM,kBAAkB,GAAsB;IAC5C,QAAQ;IACR,QAAQ;IACR,KAAK;IACL,UAAU;IACV,UAAU;IACV,eAAe;CAChB,CAAA;AACD,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAS,kBAAkB,CAAC,CAAA;AACjE,MAAM,yBAAyB,GAAG,CAAC,CAAA;AACnC,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;AAChD;;;;GAIG;AACH,MAAM,oBAAoB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;AAC7C,8EAA8E;AAC9E,MAAM,wBAAwB,GAAG,MAAM,CAAA;AACvC,MAAM,oBAAoB,GAAG,yBAAyB,CAAA;AAEtD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAc,EAAE,KAAqB;IACtE,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,OAAM;IACR,CAAC;IAED,IAAI,CAAC;QACH,MAAM,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAA;QAChE,MAAM,qBAAqB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;QACjD,MAAM,UAAU,CAAC,MAAM,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE;YAC5F,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,KAAK;SACZ,CAAC,CAAA;QACF,MAAM,iBAAiB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,gFAAgF;IAClF,CAAC;AACH,CAAC;AAED,KAAK,UAAU,qBAAqB,CAAC,aAAqB;IACxD,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAA;IACzC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAClD,OAAM;QACR,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;IAED,IAAI,IAAI,IAAI,oBAAoB,EAAE,CAAC;QACjC,OAAM;IACR,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,CAAA;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACnE,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,wBAAwB,CAAC,CAAC,CAAA;IAC9E,MAAM,SAAS,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;AAChE,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,CAAA;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,UAAiC,EAAE;IAEnC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;IACrE,MAAM,IAAI,GAAG,wBAAwB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAA;IACxB,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,IAAI,GAAG,oBAAoB,CAAC,CAAA;IACrE,MAAM,cAAc,GAAG,mBAAmB,EAAE,CAAA;IAC5C,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAA;IACrC,MAAM,oBAAoB,GAAG,yBAAyB,EAAE,CAAA;IACxD,IAAI,WAAW,GAAG,CAAC,CAAA;IACnB,IAAI,YAAY,GAAG,CAAC,CAAA;IACpB,IAAI,gBAAgB,GAAG,CAAC,CAAA;IACxB,IAAI,iBAAiB,GAAG,CAAC,CAAA;IACzB,IAAI,WAAW,GAAkB,IAAI,CAAA;IAErC,IAAI,UAAU,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,CAAC,MAAM,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QAC5F,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;YACtC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,YAAY,IAAI,CAAC,CAAA;gBACjB,SAAQ;YACV,CAAC;YACD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;YAC7C,IACE,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAC3B,SAAS,GAAG,KAAK,CAAC,OAAO,EAAE;gBAC3B,SAAS,GAAG,KAAK,CAAC,OAAO,EAAE,EAC3B,CAAC;gBACD,SAAQ;YACV,CAAC;YACD,WAAW,IAAI,CAAC,CAAA;YAChB,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YACjC,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;gBACpB,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;YAClC,CAAC;YACD,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;gBAC1C,gBAAgB,IAAI,KAAK,CAAC,WAAW,CAAA;gBACrC,iBAAiB,IAAI,CAAC,CAAA;gBACtB,oBAAoB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,WAAW,CAAA;gBAC7D,oBAAoB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,IAAI,CAAC,CAAA;YAChD,CAAC;YACD,IAAI,WAAW,KAAK,IAAI,IAAI,KAAK,CAAC,SAAS,GAAG,WAAW,EAAE,CAAC;gBAC1D,WAAW,GAAG,KAAK,CAAC,SAAS,CAAA;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,gBAAgB,EAAE,MAAM,CAAC,SAAS;QAClC,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE;QAC1B,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE;QAC1B,WAAW;QACX,YAAY;QACZ,cAAc;QACd,iBAAiB,EAAE,WAAW,CAAC,IAAI;QACnC,kBAAkB,EAAE,iBAAiB,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,GAAG,iBAAiB;QACzF,0BAA0B,EAAE,mBAAmB,CAAC,oBAAoB,CAAC;QACrE,WAAW;KACZ,CAAA;AACH,CAAC;AAED,SAAS,yBAAyB;IAChC,OAAO;QACL,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;QAC/B,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;QAC/B,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;QAC5B,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;QACjC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;QACjC,eAAe,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;KACzC,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB,CAC1B,KAAgD;IAEhD,OAAO;QACL,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC;QACxC,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC;QACxC,GAAG,EAAE,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC;QAClC,QAAQ,EAAE,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC;QAC5C,QAAQ,EAAE,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC;QAC5C,eAAe,EAAE,kBAAkB,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;KAC5D,CAAA;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAuB;IACjD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAA;AAC/D,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,MAAc,EAAE,KAAqB;IAC5D,OAAO;QACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;QACzE,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,CAAA;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,MAAc,EAAE,KAAa;IACpD,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAA;IACxC,OAAO,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC/D,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,MAAc;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,oBAAoB,CAAC,CAAA;IACpF,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAA;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACnD,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAA;IAC5B,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAC5D,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAA;QACjC,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAClD,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAA;QAC3B,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,OAAO;QACL,MAAM,EAAE,CAAC;QACT,MAAM,EAAE,CAAC;QACT,GAAG,EAAE,CAAC;QACN,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,CAAC;QACX,eAAe,EAAE,CAAC;KACnB,CAAA;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,IAAwB;IACxD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,yBAAyB,CAAA;IAClC,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY;IACtC,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACxC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,YAAY,CAAC,KAAK,CAAC;QACnB,SAAS,CAAC,KAAK,CAAC;QAChB,oBAAoB,CAAC,KAAK,CAAC;QAC3B,sBAAsB,CAAC,KAAK,CAAC,CAC9B,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,WAAW,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,CAAA;AACpE,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,CACL,QAAQ,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CACjG,CAAA;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAa;IACzC,OAAO,CAAC,CAAC,WAAW,IAAI,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,CAAA;AACvE,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAa;IAC3C,OAAO,CAAC,CAAC,aAAa,IAAI,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ,CAAA;AAC3E,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"chunking.d.ts","sourceRoot":"","sources":["../src/chunking.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAM3D,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,SAAS,EAAE,CA0Cb"}
1
+ {"version":3,"file":"chunking.d.ts","sourceRoot":"","sources":["../src/chunking.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAQ3D,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,SAAS,EAAE,CA2Cb"}
package/dist/chunking.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { createHash } from "node:crypto";
2
2
  const PARAGRAPH_BREAK_MIN_RATIO = 0.45;
3
3
  const SENTENCE_BREAK_MIN_RATIO = 0.55;
4
+ const LINE_BREAK_MIN_RATIO = 0.65;
4
5
  const WHITESPACE_BREAK_MIN_RATIO = 0.75;
6
+ const SENTENCE_BOUNDARIES = [". ", "? ", "! ", "。", "?", "!"];
5
7
  export function chunkDocument(document, chunkSize, chunkOverlap) {
6
8
  if (!document.text) {
7
9
  return [];
@@ -27,6 +29,7 @@ export function chunkDocument(document, chunkSize, chunkOverlap) {
27
29
  charEnd: span.end,
28
30
  lineStart: lineNumberForOffset(lineStarts, span.start),
29
31
  lineEnd: lineNumberForOffset(lineStarts, Math.max(span.start, span.end - 1)),
32
+ ...pageRangeForSpan(document, span.start, span.end),
30
33
  checksum: document.file.checksum,
31
34
  bytes: document.file.bytes,
32
35
  mtimeMs: document.file.mtimeMs,
@@ -40,6 +43,15 @@ export function chunkDocument(document, chunkSize, chunkOverlap) {
40
43
  }
41
44
  return chunks;
42
45
  }
46
+ function pageRangeForSpan(document, start, end) {
47
+ if (!document.pages || document.pages.length === 0) {
48
+ return {};
49
+ }
50
+ const overlapping = document.pages.filter((page) => page.charStart < end && page.charEnd > start);
51
+ const first = overlapping[0];
52
+ const last = overlapping.at(-1);
53
+ return first && last ? { pageStart: first.pageNumber, pageEnd: last.pageNumber } : {};
54
+ }
43
55
  function chooseChunkEnd(text, cursor, chunkSize) {
44
56
  const hardEnd = Math.min(cursor + chunkSize, text.length);
45
57
  if (hardEnd === text.length) {
@@ -50,9 +62,13 @@ function chooseChunkEnd(text, cursor, chunkSize) {
50
62
  if (paragraphBreak > chunkSize * PARAGRAPH_BREAK_MIN_RATIO) {
51
63
  return cursor + paragraphBreak;
52
64
  }
53
- const sentenceBreak = Math.max(window.lastIndexOf(". "), window.lastIndexOf("? "), window.lastIndexOf("! "));
54
- if (sentenceBreak > chunkSize * SENTENCE_BREAK_MIN_RATIO) {
55
- return cursor + sentenceBreak + 1;
65
+ const sentenceBreakEnd = lastSentenceBreakEnd(window);
66
+ if (sentenceBreakEnd > chunkSize * SENTENCE_BREAK_MIN_RATIO) {
67
+ return cursor + sentenceBreakEnd;
68
+ }
69
+ const lineBreak = window.lastIndexOf("\n");
70
+ if (lineBreak > chunkSize * LINE_BREAK_MIN_RATIO) {
71
+ return cursor + lineBreak;
56
72
  }
57
73
  const whitespace = window.lastIndexOf(" ");
58
74
  if (whitespace > chunkSize * WHITESPACE_BREAK_MIN_RATIO) {
@@ -60,6 +76,16 @@ function chooseChunkEnd(text, cursor, chunkSize) {
60
76
  }
61
77
  return hardEnd;
62
78
  }
79
+ function lastSentenceBreakEnd(text) {
80
+ let end = -1;
81
+ for (const boundary of SENTENCE_BOUNDARIES) {
82
+ const index = text.lastIndexOf(boundary);
83
+ if (index >= 0) {
84
+ end = Math.max(end, index + (boundary.endsWith(" ") ? boundary.length - 1 : boundary.length));
85
+ }
86
+ }
87
+ return end;
88
+ }
63
89
  function trimmedSpan(text, start, end) {
64
90
  let trimmedStart = start;
65
91
  let trimmedEnd = end;
@@ -1 +1 @@
1
- {"version":3,"file":"chunking.js","sourceRoot":"","sources":["../src/chunking.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chunking.js","sourceRoot":"","sources":["../src/chunking.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -14,6 +14,7 @@ import { countSkippedByReason } from "./files.js";
14
14
  import { getIndexFreshnessWarning, getLexicalScanWarning } from "./index-diagnostics.js";
15
15
  import { audit, ingest } from "./ingest.js";
16
16
  import { initProject } from "./init.js";
17
+ import { ingestionLimits } from "./limits.js";
17
18
  import { serveMcp } from "./mcp.js";
18
19
  import { rgrCommand } from "./package-manager.js";
19
20
  import { routePrompt } from "./prompt-routing.js";
@@ -217,7 +218,7 @@ program
217
218
  }
218
219
  return;
219
220
  }
220
- console.log(pc.green(`Done. discoveredFiles=${result.discoveredFiles} supportedFiles=${result.supportedFiles} indexedFiles=${result.indexedFiles} rebuiltFiles=${result.rebuiltFiles} reusedFiles=${result.reusedFiles} chunks=${result.chunks} skippedFiles=${result.skippedFiles} unsupportedFiles=${result.unsupportedFiles} oversizedFiles=${result.oversizedFiles} sensitiveFiles=${result.sensitiveFiles} emptyTextFiles=${result.emptyTextFiles.length} redactions=${result.redactions} errors=${result.errors.length}`));
221
+ console.log(pc.green(`Done. discoveredFiles=${result.discoveredFiles} supportedFiles=${result.supportedFiles} supportedBytes=${result.supportedBytes} largestFileBytes=${result.largestFileBytes} indexedFiles=${result.indexedFiles} rebuiltFiles=${result.rebuiltFiles} reusedFiles=${result.reusedFiles} chunks=${result.chunks} skippedFiles=${result.skippedFiles} unsupportedFiles=${result.unsupportedFiles} oversizedFiles=${result.oversizedFiles} sensitiveFiles=${result.sensitiveFiles} emptyTextFiles=${result.emptyTextFiles.length} redactions=${result.redactions} errors=${result.errors.length}`));
221
222
  printUnsupportedSummary(result.unsupportedExtensions);
222
223
  printEmptyTextFiles(result.emptyTextFiles);
223
224
  if (result.vectorIndexWarning) {
@@ -243,6 +244,8 @@ program
243
244
  .argument("<query>", "Search query.")
244
245
  .option("-k, --top-k <number>", "Number of passages to return.", parsePositiveInt)
245
246
  .option("--context-radius <number>", "Include neighboring chunks around each matched passage.", parseNonNegativeInt)
247
+ .option("--include-path <prefix>", "Search only indexed source paths under this prefix. Repeat for multiple prefixes.", collectOptionValue, [])
248
+ .option("--exclude-path <prefix>", "Exclude indexed source paths under this prefix. Repeat for multiple prefixes.", collectOptionValue, [])
246
249
  .option("--compact", "Return short snippets instead of full passages.")
247
250
  .option("--json", "Print machine-readable JSON.")
248
251
  .action(async (query, options, command) => {
@@ -275,6 +278,8 @@ program
275
278
  .argument("<query>", "Question to answer.")
276
279
  .option("-k, --top-k <number>", "Number of passages to use.", parsePositiveInt)
277
280
  .option("--context-radius <number>", "Include neighboring chunks around each matched passage.", parseNonNegativeInt)
281
+ .option("--include-path <prefix>", "Use only indexed source paths under this prefix. Repeat for multiple prefixes.", collectOptionValue, [])
282
+ .option("--exclude-path <prefix>", "Exclude indexed source paths under this prefix. Repeat for multiple prefixes.", collectOptionValue, [])
278
283
  .option("--json", "Print machine-readable JSON.")
279
284
  .action(async (query, options, command) => {
280
285
  const cwd = projectRoot(command);
@@ -303,6 +308,8 @@ program
303
308
  .argument("<query>", "Research question or topic.")
304
309
  .option("-k, --top-k <number>", "Maximum number of evidence passages to keep.", parsePositiveInt)
305
310
  .option("--no-code", "Skip the lightweight repository code search.")
311
+ .option("--include-path <prefix>", "Use only indexed source paths under this prefix. Repeat for multiple prefixes.", collectOptionValue, [])
312
+ .option("--exclude-path <prefix>", "Exclude indexed source paths under this prefix. Repeat for multiple prefixes.", collectOptionValue, [])
306
313
  .option("--compact", "Return snippets instead of full retrieved passages.")
307
314
  .option("--json", "Print machine-readable JSON.")
308
315
  .action(async (query, options, command) => {
@@ -310,6 +317,7 @@ program
310
317
  const researchOptions = { cwd };
311
318
  addOption(researchOptions, "topK", options.topK);
312
319
  addOption(researchOptions, "includeCode", options.code);
320
+ addPathFilters(researchOptions, options);
313
321
  const report = await research(query, researchOptions);
314
322
  const output = options.compact ? compactResearchReport(report) : report;
315
323
  if (options.json) {
@@ -367,25 +375,25 @@ program
367
375
  };
368
376
  addOption(evaluationOptions, "topK", options.topK);
369
377
  const result = await evaluateGoldenQueries(evaluationOptions);
370
- const minimumRecall = options.failUnder ?? 1;
371
- const passed = result.recall >= minimumRecall;
378
+ const minimumRecall = options.failUnder;
379
+ const passed = minimumRecall === undefined || result.recall >= minimumRecall;
372
380
  if (options.json) {
373
- const payload = options.failUnder === undefined ? result : { ...result, minimumRecall, passed };
381
+ const payload = minimumRecall === undefined ? result : { ...result, minimumRecall, passed };
374
382
  console.log(JSON.stringify(payload, null, 2));
375
383
  if (!passed) {
376
384
  process.exitCode = 1;
377
385
  }
378
386
  return;
379
387
  }
380
- const thresholdSummary = options.failUnder === undefined
388
+ const thresholdSummary = minimumRecall === undefined
381
389
  ? ""
382
390
  : ` minimumRecall=${minimumRecall.toFixed(3)} passed=${passed}`;
383
- console.log(`golden=${result.goldenPath} total=${result.total} hits=${result.hits} misses=${result.misses} recall=${result.recall.toFixed(3)} mrr=${result.meanReciprocalRank.toFixed(3)} ndcg=${result.ndcg.toFixed(3)}${thresholdSummary}`);
391
+ console.log(`golden=${result.goldenPath} total=${result.total} hits=${result.hits} misses=${result.misses} hitRate=${result.hitRate.toFixed(3)} recall=${result.recall.toFixed(3)} precision=${result.precision.toFixed(3)} mrr=${result.meanReciprocalRank.toFixed(3)} ndcg=${result.ndcg.toFixed(3)} p50Ms=${result.p50LatencyMs.toFixed(1)} p95Ms=${result.p95LatencyMs.toFixed(1)}${thresholdSummary}`);
384
392
  for (const testCase of result.cases) {
385
393
  const label = testCase.id ? `${testCase.id}: ${testCase.query}` : testCase.query;
386
394
  const status = testCase.hit ? pc.green("hit") : pc.red("miss");
387
395
  const rank = testCase.bestRank === null ? "n/a" : String(testCase.bestRank);
388
- console.log(`${status} rank=${rank} rr=${testCase.reciprocalRank.toFixed(3)} ndcg=${testCase.ndcg.toFixed(3)} topK=${testCase.topK} ${label}`);
396
+ console.log(`${status} rank=${rank} recall=${testCase.recall.toFixed(3)} precision=${testCase.precision.toFixed(3)} rr=${testCase.reciprocalRank.toFixed(3)} ndcg=${testCase.ndcg.toFixed(3)} latencyMs=${testCase.latencyMs.toFixed(1)} topK=${testCase.topK} ${label}`);
389
397
  if (!testCase.hit) {
390
398
  const expected = testCase.expectedCitations === undefined
391
399
  ? testCase.expectedPaths
@@ -413,9 +421,14 @@ program
413
421
  console.log(JSON.stringify(report, null, 2));
414
422
  return;
415
423
  }
424
+ console.log(`discoveredFiles=${report.discoveredFiles}`);
416
425
  console.log(`supportedFiles=${report.supportedFiles.length}`);
426
+ console.log(`supportedBytes=${report.supportedBytes}`);
427
+ console.log(`largestFileBytes=${report.largestFileBytes}`);
417
428
  console.log(`skippedFiles=${report.skippedFiles.length}`);
418
429
  console.log(`unsupportedFiles=${countSkippedByReason(report.skippedFiles, "unsupported-extension")}`);
430
+ console.log(`oversizedFiles=${countSkippedByReason(report.skippedFiles, "oversized")}`);
431
+ console.log(`sensitiveFiles=${countSkippedByReason(report.skippedFiles, "sensitive-name")}`);
419
432
  console.log(`indexedFiles=${report.indexedFiles.length}`);
420
433
  console.log(`totalChunks=${report.totalChunks}`);
421
434
  console.log(`emptyTextFiles=${report.emptyTextFiles.length}`);
@@ -475,6 +488,33 @@ program
475
488
  for (const [action, count] of Object.entries(report.eventsByAction)) {
476
489
  console.log(`events.${action}=${count}`);
477
490
  }
491
+ for (const [action, average] of Object.entries(report.averageResultCountByAction)) {
492
+ console.log(`averageResults.${action}=${average ?? "n/a"}`);
493
+ }
494
+ });
495
+ program
496
+ .command("limits")
497
+ .description("Show active ingestion limits and practical corpus scaling boundaries.")
498
+ .option("--json", "Print machine-readable JSON.")
499
+ .action(async (options, command) => {
500
+ const cwd = projectRoot(command);
501
+ const report = ingestionLimits(await loadConfig(cwd));
502
+ if (options.json) {
503
+ console.log(JSON.stringify(report, null, 2));
504
+ return;
505
+ }
506
+ console.log(`maxFileBytes=${report.maxFileBytes}`);
507
+ console.log(`maxFiles=${report.maxFiles ?? "unbounded"}`);
508
+ console.log(`maxCorpusBytes=${report.maxCorpusBytes ?? "unbounded"}`);
509
+ console.log(`maxPdfPages=${report.maxPdfPages}`);
510
+ console.log(`maxPdfTextCharacters=${report.maxPdfTextCharacters}`);
511
+ console.log(`maxOfficeTextEntries=${report.maxOfficeTextEntries}`);
512
+ console.log(`maxOfficeEntryBytes=${report.maxOfficeEntryBytes}`);
513
+ console.log(`maxOfficeTotalTextBytes=${report.maxOfficeTotalTextBytes}`);
514
+ console.log(`maxExternalTextOutputBytes=${report.maxExternalTextOutputBytes}`);
515
+ for (const note of report.notes) {
516
+ console.log(`note: ${note}`);
517
+ }
478
518
  });
479
519
  program
480
520
  .command("status")
@@ -594,16 +634,17 @@ program
594
634
  });
595
635
  program
596
636
  .command("chat")
597
- .description("Answer with a local Transformers.js chat model grounded in Ragmir citations.")
637
+ .description("Answer with a verified local model grounded in Ragmir citations.")
598
638
  .argument("[input...]", "Question to answer, or `setup` / `doctor`.")
599
639
  .option("-k, --top-k <number>", "Number of passages to retrieve.", parsePositiveInt)
600
- .option("--model <id>", "Transformers.js text-generation model ID.")
601
- .option("--model-path <path>", "Local model/cache path.")
602
- .option("--offline", "Disable remote model loading.")
603
- .option("--allow-remote-models", "Explicitly allow remote model downloads while answering.")
640
+ .option("--profile <profile>", "Local chat profile: lite, fast, or quality.")
641
+ .option("--thinking <mode>", "Thinking mode: off, standard, or deep.")
642
+ .option("--model-path <path>", "Local Gemma model root.")
643
+ .option("--offline", "Require an already verified local model.")
644
+ .option("--allow-remote-models", "Compatibility flag for explicit chat setup; normal answers stay local.")
645
+ .option("--verify", "Recompute the full model SHA256 during doctor.")
604
646
  .option("--max-new-tokens <number>", "Maximum generated tokens.", parsePositiveInt)
605
647
  .option("--context-limit <number>", "Maximum context characters sent to the model.", parsePositiveInt)
606
- .option("--dtype <dtype>", "Transformers.js dtype. Default q4.")
607
648
  .option("--json", "Print machine-readable JSON.")
608
649
  .action(async (input, options, command) => {
609
650
  const cwd = projectRoot(command);
@@ -611,17 +652,18 @@ program
611
652
  const mode = chatMode(input);
612
653
  if (mode === "doctor") {
613
654
  const doctorOptions = { cwd };
655
+ addOption(doctorOptions, "profile", options.profile);
614
656
  addOption(doctorOptions, "modelPath", options.modelPath);
657
+ addOption(doctorOptions, "verifyHash", options.verify);
615
658
  const report = await chat.doctor(doctorOptions);
616
659
  printMaybeJson(report, options.json);
617
660
  return;
618
661
  }
619
662
  if (mode === "setup") {
620
663
  const setupOptions = { cwd };
621
- addOption(setupOptions, "model", options.model);
664
+ addOption(setupOptions, "profile", options.profile);
622
665
  addOption(setupOptions, "modelPath", options.modelPath);
623
- addOption(setupOptions, "dtype", options.dtype);
624
- addOption(setupOptions, "allowRemoteModels", options.offline ? false : undefined);
666
+ addOption(setupOptions, "allowRemoteModels", options.offline ? false : options.allowRemoteModels);
625
667
  const result = await chat.setupChatModel(setupOptions);
626
668
  printMaybeJson(result, options.json);
627
669
  return;
@@ -638,9 +680,9 @@ program
638
680
  question,
639
681
  sources: sources.map(toChatSource),
640
682
  };
641
- addOption(chatOptions, "model", options.model);
683
+ addOption(chatOptions, "profile", options.profile);
684
+ addOption(chatOptions, "thinking", options.thinking);
642
685
  addOption(chatOptions, "modelPath", options.modelPath);
643
- addOption(chatOptions, "dtype", options.dtype);
644
686
  addOption(chatOptions, "allowRemoteModels", chatAllowRemoteModels(options));
645
687
  addOption(chatOptions, "maxNewTokens", options.maxNewTokens);
646
688
  addOption(chatOptions, "contextCharLimit", options.contextLimit);
@@ -653,9 +695,12 @@ program
653
695
  return;
654
696
  }
655
697
  console.log(`\n${result.answer}\n`);
656
- if (sources.length > 0) {
698
+ if (!result.emptyContext && result.citationStatus !== "valid") {
699
+ console.error(pc.yellow(`Citation status: ${result.citationStatus}. Review the answer against the retrieved passages.`));
700
+ }
701
+ if (result.sources.length > 0) {
657
702
  console.log(pc.dim("Sources:"));
658
- for (const [index, source] of sources.entries()) {
703
+ for (const [index, source] of result.sources.entries()) {
659
704
  console.log(` [${index + 1}] ${source.relativePath} chunk=${source.chunkIndex}`);
660
705
  }
661
706
  }
@@ -843,8 +888,17 @@ function withSearchOptions(cwd, options) {
843
888
  const result = { cwd };
844
889
  addOption(result, "topK", options.topK);
845
890
  addOption(result, "contextRadius", options.contextRadius);
891
+ addPathFilters(result, options);
846
892
  return result;
847
893
  }
894
+ function addPathFilters(target, options) {
895
+ if (options.includePath && options.includePath.length > 0) {
896
+ target.includePaths = options.includePath;
897
+ }
898
+ if (options.excludePath && options.excludePath.length > 0) {
899
+ target.excludePaths = options.excludePath;
900
+ }
901
+ }
848
902
  async function loadChat() {
849
903
  const module = await import(CHAT_PACKAGE_NAME);
850
904
  if (!isChatModule(module)) {
@@ -929,8 +983,14 @@ function printDoctor(report) {
929
983
  console.log(`redactionEnabled=${report.redactionEnabled}`);
930
984
  console.log(`accessLog=${report.accessLog}`);
931
985
  console.log(`supportedFiles=${report.supportedFiles}`);
986
+ console.log(`supportedBytes=${report.supportedBytes}`);
987
+ console.log(`largestFileBytes=${report.largestFileBytes}`);
988
+ console.log(`maxFileBytes=${report.maxFileBytes}`);
932
989
  console.log(`skippedFiles=${report.skippedFiles}`);
933
990
  console.log(`unsupportedFiles=${report.unsupportedFiles}`);
991
+ console.log(`oversizedFiles=${report.oversizedFiles}`);
992
+ console.log(`sensitiveFiles=${report.sensitiveFiles}`);
993
+ console.log(`emptyTextFiles=${report.emptyTextFiles}`);
934
994
  console.log(`indexedFiles=${report.indexedFiles}`);
935
995
  console.log(`chunksIndexed=${report.chunksIndexed}`);
936
996
  console.log(`missingFromIndex=${report.missingFromIndex}`);
@@ -954,7 +1014,7 @@ function printResearchReport(report) {
954
1014
  console.log(`query=${report.query}`);
955
1015
  console.log(`ready=${report.ready}`);
956
1016
  console.log(`generatedQueries=${report.generatedQueries.length}`);
957
- console.log(`audit.supportedFiles=${report.audit.supportedFiles} audit.indexedFiles=${report.audit.indexedFiles} audit.totalChunks=${report.audit.totalChunks} audit.skippedFiles=${report.audit.skippedFiles} audit.missingFromIndex=${report.audit.missingFromIndex} audit.staleInIndex=${report.audit.staleInIndex}`);
1017
+ console.log(`audit.supportedFiles=${report.audit.supportedFiles} audit.supportedBytes=${report.audit.supportedBytes} audit.largestFileBytes=${report.audit.largestFileBytes} audit.indexedFiles=${report.audit.indexedFiles} audit.totalChunks=${report.audit.totalChunks} audit.skippedFiles=${report.audit.skippedFiles} audit.oversizedFiles=${report.audit.oversizedFiles} audit.missingFromIndex=${report.audit.missingFromIndex} audit.staleInIndex=${report.audit.staleInIndex}`);
958
1018
  console.log(`securityWarnings=${report.securityWarnings.length}`);
959
1019
  console.log(`sourceDiagnostics.duplicates=${report.sourceDiagnostics.duplicateCandidates.length} sourceDiagnostics.archives=${report.sourceDiagnostics.archiveCandidates.length} sourceDiagnostics.mirrors=${report.sourceDiagnostics.mirrorCandidates.length}`);
960
1020
  if (report.sourceDiagnostics.duplicateCandidates.length > 0) {