@pan-sec/notebooklm-mcp 2026.3.2 → 2026.4.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 (466) hide show
  1. package/dist/auth/auth-manager.d.ts +0 -1
  2. package/dist/auth/auth-manager.js +0 -1
  3. package/dist/auth/mcp-auth.d.ts +0 -1
  4. package/dist/auth/mcp-auth.js +0 -1
  5. package/dist/compliance/alert-manager.d.ts +6 -2
  6. package/dist/compliance/alert-manager.js +40 -10
  7. package/dist/compliance/breach-detection.d.ts +0 -1
  8. package/dist/compliance/breach-detection.js +0 -1
  9. package/dist/compliance/change-log.d.ts +13 -1
  10. package/dist/compliance/change-log.js +82 -16
  11. package/dist/compliance/compliance-logger.d.ts +29 -3
  12. package/dist/compliance/compliance-logger.js +90 -27
  13. package/dist/compliance/compliance-tools.d.ts +0 -1
  14. package/dist/compliance/compliance-tools.js +0 -1
  15. package/dist/compliance/consent-manager.d.ts +0 -1
  16. package/dist/compliance/consent-manager.js +0 -1
  17. package/dist/compliance/dashboard.d.ts +4 -3
  18. package/dist/compliance/dashboard.js +11 -8
  19. package/dist/compliance/data-classification.d.ts +0 -1
  20. package/dist/compliance/data-classification.js +0 -1
  21. package/dist/compliance/data-erasure.d.ts +0 -1
  22. package/dist/compliance/data-erasure.js +0 -1
  23. package/dist/compliance/data-export.d.ts +0 -1
  24. package/dist/compliance/data-export.js +0 -1
  25. package/dist/compliance/data-inventory.d.ts +0 -1
  26. package/dist/compliance/data-inventory.js +0 -1
  27. package/dist/compliance/dsar-handler.d.ts +0 -1
  28. package/dist/compliance/dsar-handler.js +0 -1
  29. package/dist/compliance/evidence-collector.d.ts +0 -1
  30. package/dist/compliance/evidence-collector.js +4 -2
  31. package/dist/compliance/health-monitor.d.ts +0 -1
  32. package/dist/compliance/health-monitor.js +0 -1
  33. package/dist/compliance/incident-manager.d.ts +0 -1
  34. package/dist/compliance/incident-manager.js +0 -1
  35. package/dist/compliance/index.d.ts +0 -1
  36. package/dist/compliance/index.js +0 -1
  37. package/dist/compliance/policy-docs.d.ts +0 -1
  38. package/dist/compliance/policy-docs.js +0 -1
  39. package/dist/compliance/privacy-notice-text.d.ts +0 -1
  40. package/dist/compliance/privacy-notice-text.js +0 -1
  41. package/dist/compliance/privacy-notice.d.ts +0 -1
  42. package/dist/compliance/privacy-notice.js +0 -1
  43. package/dist/compliance/report-generator.d.ts +7 -1
  44. package/dist/compliance/report-generator.js +116 -34
  45. package/dist/compliance/retention-engine.d.ts +0 -1
  46. package/dist/compliance/retention-engine.js +0 -1
  47. package/dist/compliance/siem-exporter.d.ts +26 -2
  48. package/dist/compliance/siem-exporter.js +89 -24
  49. package/dist/compliance/types.d.ts +0 -1
  50. package/dist/compliance/types.js +0 -1
  51. package/dist/config.d.ts +0 -1
  52. package/dist/config.js +2 -3
  53. package/dist/errors.d.ts +0 -1
  54. package/dist/errors.js +0 -1
  55. package/dist/events/event-emitter.d.ts +9 -1
  56. package/dist/events/event-emitter.js +47 -8
  57. package/dist/events/event-types.d.ts +0 -1
  58. package/dist/events/event-types.js +8 -2
  59. package/dist/gemini/gemini-client.d.ts +0 -1
  60. package/dist/gemini/gemini-client.js +237 -45
  61. package/dist/gemini/index.d.ts +0 -1
  62. package/dist/gemini/index.js +0 -1
  63. package/dist/gemini/pdf-chunker.d.ts +0 -1
  64. package/dist/gemini/pdf-chunker.js +60 -35
  65. package/dist/gemini/types.d.ts +0 -1
  66. package/dist/gemini/types.js +0 -1
  67. package/dist/index.d.ts +0 -1
  68. package/dist/index.js +74 -10
  69. package/dist/library/notebook-library.d.ts +30 -2
  70. package/dist/library/notebook-library.js +345 -85
  71. package/dist/library/types.d.ts +0 -1
  72. package/dist/library/types.js +0 -1
  73. package/dist/logging/index.d.ts +0 -1
  74. package/dist/logging/index.js +0 -1
  75. package/dist/logging/query-logger.d.ts +20 -1
  76. package/dist/logging/query-logger.js +104 -21
  77. package/dist/notebook-creation/audio-manager.d.ts +0 -1
  78. package/dist/notebook-creation/audio-manager.js +111 -20
  79. package/dist/notebook-creation/browser-options.d.ts +0 -1
  80. package/dist/notebook-creation/browser-options.js +0 -1
  81. package/dist/notebook-creation/data-table-manager.d.ts +7 -1
  82. package/dist/notebook-creation/data-table-manager.js +59 -3
  83. package/dist/notebook-creation/dom-scripts.d.ts +0 -1
  84. package/dist/notebook-creation/dom-scripts.js +0 -1
  85. package/dist/notebook-creation/errors.d.ts +0 -1
  86. package/dist/notebook-creation/errors.js +0 -1
  87. package/dist/notebook-creation/index.d.ts +0 -1
  88. package/dist/notebook-creation/index.js +0 -1
  89. package/dist/notebook-creation/notebook-creator.d.ts +9 -1
  90. package/dist/notebook-creation/notebook-creator.js +50 -1
  91. package/dist/notebook-creation/notebook-nav.d.ts +0 -1
  92. package/dist/notebook-creation/notebook-nav.js +21 -6
  93. package/dist/notebook-creation/notebook-sync.d.ts +14 -2
  94. package/dist/notebook-creation/notebook-sync.js +124 -35
  95. package/dist/notebook-creation/selectors.d.ts +0 -1
  96. package/dist/notebook-creation/selectors.js +6 -4
  97. package/dist/notebook-creation/source-manager.d.ts +29 -2
  98. package/dist/notebook-creation/source-manager.js +0 -0
  99. package/dist/notebook-creation/types.d.ts +0 -1
  100. package/dist/notebook-creation/types.js +0 -1
  101. package/dist/notebook-creation/video-manager.d.ts +0 -1
  102. package/dist/notebook-creation/video-manager.js +91 -15
  103. package/dist/observability/metrics.d.ts +0 -1
  104. package/dist/observability/metrics.js +0 -1
  105. package/dist/quota/index.d.ts +0 -1
  106. package/dist/quota/index.js +0 -1
  107. package/dist/quota/quota-manager.d.ts +59 -4
  108. package/dist/quota/quota-manager.js +195 -46
  109. package/dist/resources/resource-handlers.d.ts +0 -1
  110. package/dist/resources/resource-handlers.js +33 -3
  111. package/dist/session/browser-session.d.ts +0 -1
  112. package/dist/session/browser-session.js +0 -1
  113. package/dist/session/session-manager.d.ts +0 -1
  114. package/dist/session/session-manager.js +0 -1
  115. package/dist/session/session-timeout.d.ts +0 -1
  116. package/dist/session/session-timeout.js +0 -1
  117. package/dist/session/shared-context-manager.d.ts +0 -1
  118. package/dist/session/shared-context-manager.js +0 -1
  119. package/dist/tools/annotations.d.ts +0 -1
  120. package/dist/tools/annotations.js +0 -1
  121. package/dist/tools/definitions/ask-question.d.ts +6 -3
  122. package/dist/tools/definitions/ask-question.js +12 -8
  123. package/dist/tools/definitions/chat-history.d.ts +0 -1
  124. package/dist/tools/definitions/chat-history.js +1 -1
  125. package/dist/tools/definitions/data-tables.d.ts +0 -1
  126. package/dist/tools/definitions/data-tables.js +4 -1
  127. package/dist/tools/definitions/gemini.d.ts +0 -1
  128. package/dist/tools/definitions/gemini.js +14 -7
  129. package/dist/tools/definitions/notebook-management.d.ts +0 -1
  130. package/dist/tools/definitions/notebook-management.js +7 -2
  131. package/dist/tools/definitions/query-history.d.ts +0 -1
  132. package/dist/tools/definitions/query-history.js +0 -1
  133. package/dist/tools/definitions/session-management.d.ts +0 -1
  134. package/dist/tools/definitions/session-management.js +0 -1
  135. package/dist/tools/definitions/system.d.ts +0 -1
  136. package/dist/tools/definitions/system.js +32 -12
  137. package/dist/tools/definitions/video.d.ts +0 -1
  138. package/dist/tools/definitions/video.js +6 -3
  139. package/dist/tools/definitions.d.ts +0 -1
  140. package/dist/tools/definitions.js +0 -1
  141. package/dist/tools/handlers/ask-question.d.ts +0 -1
  142. package/dist/tools/handlers/ask-question.js +47 -18
  143. package/dist/tools/handlers/audio-video.d.ts +0 -1
  144. package/dist/tools/handlers/audio-video.js +0 -1
  145. package/dist/tools/handlers/auth.d.ts +0 -1
  146. package/dist/tools/handlers/auth.js +0 -1
  147. package/dist/tools/handlers/error-utils.d.ts +0 -1
  148. package/dist/tools/handlers/error-utils.js +0 -1
  149. package/dist/tools/handlers/gemini.d.ts +0 -1
  150. package/dist/tools/handlers/gemini.js +0 -1
  151. package/dist/tools/handlers/index.d.ts +0 -1
  152. package/dist/tools/handlers/index.js +0 -1
  153. package/dist/tools/handlers/notebook-creation.d.ts +0 -1
  154. package/dist/tools/handlers/notebook-creation.js +16 -1
  155. package/dist/tools/handlers/notebook-management.d.ts +0 -1
  156. package/dist/tools/handlers/notebook-management.js +7 -2
  157. package/dist/tools/handlers/session-management.d.ts +0 -1
  158. package/dist/tools/handlers/session-management.js +0 -1
  159. package/dist/tools/handlers/system.d.ts +0 -1
  160. package/dist/tools/handlers/system.js +0 -1
  161. package/dist/tools/handlers/types.d.ts +0 -1
  162. package/dist/tools/handlers/types.js +0 -1
  163. package/dist/tools/handlers/webhooks.d.ts +0 -1
  164. package/dist/tools/handlers/webhooks.js +0 -1
  165. package/dist/tools/icons.d.ts +0 -1
  166. package/dist/tools/icons.js +0 -1
  167. package/dist/tools/index.d.ts +0 -1
  168. package/dist/tools/index.js +0 -1
  169. package/dist/types.d.ts +0 -1
  170. package/dist/types.js +0 -1
  171. package/dist/utils/audit-logger.d.ts +11 -1
  172. package/dist/utils/audit-logger.js +189 -21
  173. package/dist/utils/cleanup-manager.d.ts +0 -1
  174. package/dist/utils/cleanup-manager.js +0 -1
  175. package/dist/utils/cli-handler.d.ts +0 -1
  176. package/dist/utils/cli-handler.js +0 -1
  177. package/dist/utils/crypto.d.ts +18 -9
  178. package/dist/utils/crypto.js +93 -28
  179. package/dist/utils/file-lock.d.ts +15 -1
  180. package/dist/utils/file-lock.js +67 -59
  181. package/dist/utils/file-permissions.d.ts +0 -1
  182. package/dist/utils/file-permissions.js +35 -7
  183. package/dist/utils/logger.d.ts +0 -1
  184. package/dist/utils/logger.js +0 -1
  185. package/dist/utils/page-utils.d.ts +0 -1
  186. package/dist/utils/page-utils.js +32 -28
  187. package/dist/utils/response-validator.d.ts +0 -1
  188. package/dist/utils/response-validator.js +18 -15
  189. package/dist/utils/secrets-scanner.d.ts +0 -1
  190. package/dist/utils/secrets-scanner.js +32 -7
  191. package/dist/utils/secure-memory.d.ts +34 -16
  192. package/dist/utils/secure-memory.js +40 -25
  193. package/dist/utils/security.d.ts +0 -1
  194. package/dist/utils/security.js +66 -39
  195. package/dist/utils/settings-manager.d.ts +9 -1
  196. package/dist/utils/settings-manager.js +45 -2
  197. package/dist/utils/stealth-utils.d.ts +0 -1
  198. package/dist/utils/stealth-utils.js +11 -9
  199. package/dist/webhooks/index.d.ts +0 -1
  200. package/dist/webhooks/index.js +0 -1
  201. package/dist/webhooks/types.d.ts +0 -1
  202. package/dist/webhooks/types.js +0 -1
  203. package/dist/webhooks/webhook-dispatcher.d.ts +0 -1
  204. package/dist/webhooks/webhook-dispatcher.js +0 -1
  205. package/package.json +5 -4
  206. package/dist/auth/auth-manager.d.ts.map +0 -1
  207. package/dist/auth/auth-manager.js.map +0 -1
  208. package/dist/auth/mcp-auth.d.ts.map +0 -1
  209. package/dist/auth/mcp-auth.js.map +0 -1
  210. package/dist/compliance/alert-manager.d.ts.map +0 -1
  211. package/dist/compliance/alert-manager.js.map +0 -1
  212. package/dist/compliance/breach-detection.d.ts.map +0 -1
  213. package/dist/compliance/breach-detection.js.map +0 -1
  214. package/dist/compliance/change-log.d.ts.map +0 -1
  215. package/dist/compliance/change-log.js.map +0 -1
  216. package/dist/compliance/compliance-logger.d.ts.map +0 -1
  217. package/dist/compliance/compliance-logger.js.map +0 -1
  218. package/dist/compliance/compliance-tools.d.ts.map +0 -1
  219. package/dist/compliance/compliance-tools.js.map +0 -1
  220. package/dist/compliance/consent-manager.d.ts.map +0 -1
  221. package/dist/compliance/consent-manager.js.map +0 -1
  222. package/dist/compliance/dashboard.d.ts.map +0 -1
  223. package/dist/compliance/dashboard.js.map +0 -1
  224. package/dist/compliance/data-classification.d.ts.map +0 -1
  225. package/dist/compliance/data-classification.js.map +0 -1
  226. package/dist/compliance/data-erasure.d.ts.map +0 -1
  227. package/dist/compliance/data-erasure.js.map +0 -1
  228. package/dist/compliance/data-export.d.ts.map +0 -1
  229. package/dist/compliance/data-export.js.map +0 -1
  230. package/dist/compliance/data-inventory.d.ts.map +0 -1
  231. package/dist/compliance/data-inventory.js.map +0 -1
  232. package/dist/compliance/dsar-handler.d.ts.map +0 -1
  233. package/dist/compliance/dsar-handler.js.map +0 -1
  234. package/dist/compliance/evidence-collector.d.ts.map +0 -1
  235. package/dist/compliance/evidence-collector.js.map +0 -1
  236. package/dist/compliance/health-monitor.d.ts.map +0 -1
  237. package/dist/compliance/health-monitor.js.map +0 -1
  238. package/dist/compliance/incident-manager.d.ts.map +0 -1
  239. package/dist/compliance/incident-manager.js.map +0 -1
  240. package/dist/compliance/index.d.ts.map +0 -1
  241. package/dist/compliance/index.js.map +0 -1
  242. package/dist/compliance/policy-docs.d.ts.map +0 -1
  243. package/dist/compliance/policy-docs.js.map +0 -1
  244. package/dist/compliance/privacy-notice-text.d.ts.map +0 -1
  245. package/dist/compliance/privacy-notice-text.js.map +0 -1
  246. package/dist/compliance/privacy-notice.d.ts.map +0 -1
  247. package/dist/compliance/privacy-notice.js.map +0 -1
  248. package/dist/compliance/report-generator.d.ts.map +0 -1
  249. package/dist/compliance/report-generator.js.map +0 -1
  250. package/dist/compliance/retention-engine.d.ts.map +0 -1
  251. package/dist/compliance/retention-engine.js.map +0 -1
  252. package/dist/compliance/siem-exporter.d.ts.map +0 -1
  253. package/dist/compliance/siem-exporter.js.map +0 -1
  254. package/dist/compliance/types.d.ts.map +0 -1
  255. package/dist/compliance/types.js.map +0 -1
  256. package/dist/config.d.ts.map +0 -1
  257. package/dist/config.js.map +0 -1
  258. package/dist/errors.d.ts.map +0 -1
  259. package/dist/errors.js.map +0 -1
  260. package/dist/events/event-emitter.d.ts.map +0 -1
  261. package/dist/events/event-emitter.js.map +0 -1
  262. package/dist/events/event-types.d.ts.map +0 -1
  263. package/dist/events/event-types.js.map +0 -1
  264. package/dist/gemini/gemini-client.d.ts.map +0 -1
  265. package/dist/gemini/gemini-client.js.map +0 -1
  266. package/dist/gemini/index.d.ts.map +0 -1
  267. package/dist/gemini/index.js.map +0 -1
  268. package/dist/gemini/pdf-chunker.d.ts.map +0 -1
  269. package/dist/gemini/pdf-chunker.js.map +0 -1
  270. package/dist/gemini/types.d.ts.map +0 -1
  271. package/dist/gemini/types.js.map +0 -1
  272. package/dist/index.d.ts.map +0 -1
  273. package/dist/index.js.map +0 -1
  274. package/dist/library/notebook-library.d.ts.map +0 -1
  275. package/dist/library/notebook-library.js.map +0 -1
  276. package/dist/library/types.d.ts.map +0 -1
  277. package/dist/library/types.js.map +0 -1
  278. package/dist/logging/index.d.ts.map +0 -1
  279. package/dist/logging/index.js.map +0 -1
  280. package/dist/logging/query-logger.d.ts.map +0 -1
  281. package/dist/logging/query-logger.js.map +0 -1
  282. package/dist/notebook-creation/audio-manager.d.ts.map +0 -1
  283. package/dist/notebook-creation/audio-manager.js.map +0 -1
  284. package/dist/notebook-creation/browser-options.d.ts.map +0 -1
  285. package/dist/notebook-creation/browser-options.js.map +0 -1
  286. package/dist/notebook-creation/data-table-manager.d.ts.map +0 -1
  287. package/dist/notebook-creation/data-table-manager.js.map +0 -1
  288. package/dist/notebook-creation/discover-creation-flow.d.ts +0 -2
  289. package/dist/notebook-creation/discover-creation-flow.d.ts.map +0 -1
  290. package/dist/notebook-creation/discover-creation-flow.js +0 -177
  291. package/dist/notebook-creation/discover-creation-flow.js.map +0 -1
  292. package/dist/notebook-creation/discover-quota.d.ts +0 -2
  293. package/dist/notebook-creation/discover-quota.d.ts.map +0 -1
  294. package/dist/notebook-creation/discover-quota.js +0 -194
  295. package/dist/notebook-creation/discover-quota.js.map +0 -1
  296. package/dist/notebook-creation/discover-source-dialog.d.ts +0 -8
  297. package/dist/notebook-creation/discover-source-dialog.d.ts.map +0 -1
  298. package/dist/notebook-creation/discover-source-dialog.js +0 -134
  299. package/dist/notebook-creation/discover-source-dialog.js.map +0 -1
  300. package/dist/notebook-creation/discover-sources.d.ts +0 -8
  301. package/dist/notebook-creation/discover-sources.d.ts.map +0 -1
  302. package/dist/notebook-creation/discover-sources.js +0 -272
  303. package/dist/notebook-creation/discover-sources.js.map +0 -1
  304. package/dist/notebook-creation/discover-text-input.d.ts +0 -7
  305. package/dist/notebook-creation/discover-text-input.d.ts.map +0 -1
  306. package/dist/notebook-creation/discover-text-input.js +0 -135
  307. package/dist/notebook-creation/discover-text-input.js.map +0 -1
  308. package/dist/notebook-creation/dom-scripts.d.ts.map +0 -1
  309. package/dist/notebook-creation/dom-scripts.js.map +0 -1
  310. package/dist/notebook-creation/errors.d.ts.map +0 -1
  311. package/dist/notebook-creation/errors.js.map +0 -1
  312. package/dist/notebook-creation/index.d.ts.map +0 -1
  313. package/dist/notebook-creation/index.js.map +0 -1
  314. package/dist/notebook-creation/notebook-creator.d.ts.map +0 -1
  315. package/dist/notebook-creation/notebook-creator.js.map +0 -1
  316. package/dist/notebook-creation/notebook-nav.d.ts.map +0 -1
  317. package/dist/notebook-creation/notebook-nav.js.map +0 -1
  318. package/dist/notebook-creation/notebook-sync.d.ts.map +0 -1
  319. package/dist/notebook-creation/notebook-sync.js.map +0 -1
  320. package/dist/notebook-creation/run-discovery.d.ts +0 -11
  321. package/dist/notebook-creation/run-discovery.d.ts.map +0 -1
  322. package/dist/notebook-creation/run-discovery.js +0 -151
  323. package/dist/notebook-creation/run-discovery.js.map +0 -1
  324. package/dist/notebook-creation/selector-discovery.d.ts +0 -65
  325. package/dist/notebook-creation/selector-discovery.d.ts.map +0 -1
  326. package/dist/notebook-creation/selector-discovery.js +0 -414
  327. package/dist/notebook-creation/selector-discovery.js.map +0 -1
  328. package/dist/notebook-creation/selectors.d.ts.map +0 -1
  329. package/dist/notebook-creation/selectors.js.map +0 -1
  330. package/dist/notebook-creation/selectors.ts +0 -112
  331. package/dist/notebook-creation/source-manager.d.ts.map +0 -1
  332. package/dist/notebook-creation/source-manager.js.map +0 -1
  333. package/dist/notebook-creation/test-create.d.ts +0 -8
  334. package/dist/notebook-creation/test-create.d.ts.map +0 -1
  335. package/dist/notebook-creation/test-create.js +0 -72
  336. package/dist/notebook-creation/test-create.js.map +0 -1
  337. package/dist/notebook-creation/types.d.ts.map +0 -1
  338. package/dist/notebook-creation/types.js.map +0 -1
  339. package/dist/notebook-creation/video-manager.d.ts.map +0 -1
  340. package/dist/notebook-creation/video-manager.js.map +0 -1
  341. package/dist/observability/metrics.d.ts.map +0 -1
  342. package/dist/observability/metrics.js.map +0 -1
  343. package/dist/quota/index.d.ts.map +0 -1
  344. package/dist/quota/index.js.map +0 -1
  345. package/dist/quota/quota-manager.d.ts.map +0 -1
  346. package/dist/quota/quota-manager.js.map +0 -1
  347. package/dist/resources/resource-handlers.d.ts.map +0 -1
  348. package/dist/resources/resource-handlers.js.map +0 -1
  349. package/dist/session/browser-session.d.ts.map +0 -1
  350. package/dist/session/browser-session.js.map +0 -1
  351. package/dist/session/session-manager.d.ts.map +0 -1
  352. package/dist/session/session-manager.js.map +0 -1
  353. package/dist/session/session-timeout.d.ts.map +0 -1
  354. package/dist/session/session-timeout.js.map +0 -1
  355. package/dist/session/shared-context-manager.d.ts.map +0 -1
  356. package/dist/session/shared-context-manager.js.map +0 -1
  357. package/dist/tools/annotations.d.ts.map +0 -1
  358. package/dist/tools/annotations.js.map +0 -1
  359. package/dist/tools/definitions/ask-question.d.ts.map +0 -1
  360. package/dist/tools/definitions/ask-question.js.map +0 -1
  361. package/dist/tools/definitions/chat-history.d.ts.map +0 -1
  362. package/dist/tools/definitions/chat-history.js.map +0 -1
  363. package/dist/tools/definitions/data-tables.d.ts.map +0 -1
  364. package/dist/tools/definitions/data-tables.js.map +0 -1
  365. package/dist/tools/definitions/gemini.d.ts.map +0 -1
  366. package/dist/tools/definitions/gemini.js.map +0 -1
  367. package/dist/tools/definitions/notebook-management.d.ts.map +0 -1
  368. package/dist/tools/definitions/notebook-management.js.map +0 -1
  369. package/dist/tools/definitions/query-history.d.ts.map +0 -1
  370. package/dist/tools/definitions/query-history.js.map +0 -1
  371. package/dist/tools/definitions/session-management.d.ts.map +0 -1
  372. package/dist/tools/definitions/session-management.js.map +0 -1
  373. package/dist/tools/definitions/system.d.ts.map +0 -1
  374. package/dist/tools/definitions/system.js.map +0 -1
  375. package/dist/tools/definitions/video.d.ts.map +0 -1
  376. package/dist/tools/definitions/video.js.map +0 -1
  377. package/dist/tools/definitions.d.ts.map +0 -1
  378. package/dist/tools/definitions.js.map +0 -1
  379. package/dist/tools/handlers/ask-question.d.ts.map +0 -1
  380. package/dist/tools/handlers/ask-question.js.map +0 -1
  381. package/dist/tools/handlers/audio-video.d.ts.map +0 -1
  382. package/dist/tools/handlers/audio-video.js.map +0 -1
  383. package/dist/tools/handlers/auth.d.ts.map +0 -1
  384. package/dist/tools/handlers/auth.js.map +0 -1
  385. package/dist/tools/handlers/error-utils.d.ts.map +0 -1
  386. package/dist/tools/handlers/error-utils.js.map +0 -1
  387. package/dist/tools/handlers/gemini.d.ts.map +0 -1
  388. package/dist/tools/handlers/gemini.js.map +0 -1
  389. package/dist/tools/handlers/index.d.ts.map +0 -1
  390. package/dist/tools/handlers/index.js.map +0 -1
  391. package/dist/tools/handlers/notebook-creation.d.ts.map +0 -1
  392. package/dist/tools/handlers/notebook-creation.js.map +0 -1
  393. package/dist/tools/handlers/notebook-management.d.ts.map +0 -1
  394. package/dist/tools/handlers/notebook-management.js.map +0 -1
  395. package/dist/tools/handlers/session-management.d.ts.map +0 -1
  396. package/dist/tools/handlers/session-management.js.map +0 -1
  397. package/dist/tools/handlers/system.d.ts.map +0 -1
  398. package/dist/tools/handlers/system.js.map +0 -1
  399. package/dist/tools/handlers/types.d.ts.map +0 -1
  400. package/dist/tools/handlers/types.js.map +0 -1
  401. package/dist/tools/handlers/webhooks.d.ts.map +0 -1
  402. package/dist/tools/handlers/webhooks.js.map +0 -1
  403. package/dist/tools/handlers.d.ts +0 -666
  404. package/dist/tools/handlers.d.ts.map +0 -1
  405. package/dist/tools/handlers.js +0 -2929
  406. package/dist/tools/handlers.js.map +0 -1
  407. package/dist/tools/icons.d.ts.map +0 -1
  408. package/dist/tools/icons.js.map +0 -1
  409. package/dist/tools/index.d.ts.map +0 -1
  410. package/dist/tools/index.js.map +0 -1
  411. package/dist/types.d.ts.map +0 -1
  412. package/dist/types.js.map +0 -1
  413. package/dist/utils/audit-logger.d.ts.map +0 -1
  414. package/dist/utils/audit-logger.js.map +0 -1
  415. package/dist/utils/cert-pinning.d.ts +0 -97
  416. package/dist/utils/cert-pinning.d.ts.map +0 -1
  417. package/dist/utils/cert-pinning.js +0 -328
  418. package/dist/utils/cert-pinning.js.map +0 -1
  419. package/dist/utils/cleanup-manager.d.ts.map +0 -1
  420. package/dist/utils/cleanup-manager.js.map +0 -1
  421. package/dist/utils/cli-handler.d.ts.map +0 -1
  422. package/dist/utils/cli-handler.js.map +0 -1
  423. package/dist/utils/crypto.d.ts.map +0 -1
  424. package/dist/utils/crypto.js.map +0 -1
  425. package/dist/utils/file-lock.d.ts.map +0 -1
  426. package/dist/utils/file-lock.js.map +0 -1
  427. package/dist/utils/file-permissions.d.ts.map +0 -1
  428. package/dist/utils/file-permissions.js.map +0 -1
  429. package/dist/utils/logger.d.ts.map +0 -1
  430. package/dist/utils/logger.js.map +0 -1
  431. package/dist/utils/page-utils.d.ts.map +0 -1
  432. package/dist/utils/page-utils.js.map +0 -1
  433. package/dist/utils/response-validator.d.ts.map +0 -1
  434. package/dist/utils/response-validator.js.map +0 -1
  435. package/dist/utils/secrets-scanner.d.ts.map +0 -1
  436. package/dist/utils/secrets-scanner.js.map +0 -1
  437. package/dist/utils/secure-memory.d.ts.map +0 -1
  438. package/dist/utils/secure-memory.js.map +0 -1
  439. package/dist/utils/security.d.ts.map +0 -1
  440. package/dist/utils/security.js.map +0 -1
  441. package/dist/utils/settings-manager.d.ts.map +0 -1
  442. package/dist/utils/settings-manager.js.map +0 -1
  443. package/dist/utils/stealth-utils.d.ts.map +0 -1
  444. package/dist/utils/stealth-utils.js.map +0 -1
  445. package/dist/utils/tool-validation.d.ts +0 -93
  446. package/dist/utils/tool-validation.d.ts.map +0 -1
  447. package/dist/utils/tool-validation.js +0 -277
  448. package/dist/utils/tool-validation.js.map +0 -1
  449. package/dist/webhooks/index.d.ts.map +0 -1
  450. package/dist/webhooks/index.js.map +0 -1
  451. package/dist/webhooks/types.d.ts.map +0 -1
  452. package/dist/webhooks/types.js.map +0 -1
  453. package/dist/webhooks/webhook-dispatcher.d.ts.map +0 -1
  454. package/dist/webhooks/webhook-dispatcher.js.map +0 -1
  455. package/docs/COMPLIANCE-SPEC.md +0 -1452
  456. package/docs/MCP-DIRECTORY-LISTINGS.md +0 -91
  457. package/docs/SECURITY-FORK-OPPORTUNITIES.md +0 -79
  458. package/docs/SECURITY_IMPLEMENTATION_PLAN.md +0 -437
  459. package/docs/archive/ISSUES-legacy-2026-04-24.md +0 -644
  460. package/docs/configuration.md +0 -94
  461. package/docs/dependency-risk.md +0 -25
  462. package/docs/improvement-sprint-2026.2.10.md +0 -210
  463. package/docs/testing-runbook.md +0 -166
  464. package/docs/tools.md +0 -34
  465. package/docs/troubleshooting.md +0 -59
  466. package/docs/usage-guide.md +0 -246
@@ -16,6 +16,29 @@
16
16
  */
17
17
  import { log } from "../utils/logger.js";
18
18
  import { randomDelay } from "../utils/stealth-utils.js";
19
+ /**
20
+ * Allowlisted style values. Single source of truth used to validate untrusted
21
+ * input before it is passed into the page context (prevents attribute-selector
22
+ * injection in selectStyle).
23
+ */
24
+ const VALID_VIDEO_STYLES = [
25
+ "auto-select",
26
+ "custom",
27
+ "classic",
28
+ "whiteboard",
29
+ "kawaii",
30
+ "anime",
31
+ "watercolour",
32
+ "retro-print",
33
+ "heritage",
34
+ "paper-craft",
35
+ ];
36
+ /**
37
+ * Allowlisted format values. Single source of truth used to validate untrusted
38
+ * input before it is passed into the page context (prevents attribute-selector
39
+ * injection in selectFormat).
40
+ */
41
+ const VALID_VIDEO_FORMATS = ["explainer", "brief"];
19
42
  export class VideoManager {
20
43
  authManager;
21
44
  contextManager;
@@ -117,6 +140,18 @@ export class VideoManager {
117
140
  item.classList?.contains("shimmer-green")) {
118
141
  return { status: "generating", progress: 0 };
119
142
  }
143
+ // Detect an explicit failure state on THIS artifact before assuming ready.
144
+ // A failed generation leaves a non-shimmer artifact, which would otherwise be
145
+ // misreported as "ready". Scope the check to the matched item only — a page-global
146
+ // alert query could match unrelated UI. Class names are best-effort (unconfirmed
147
+ // by live inspection); [role="alert"]/error child is the locale-independent signal.
148
+ const hasErrorChild = !!item.querySelector('[role="alert"], .error-state, .artifact-error');
149
+ if (hasErrorChild ||
150
+ item.classList?.contains("error-state") ||
151
+ item.classList?.contains("artifact-error") ||
152
+ item.classList?.contains("failed")) {
153
+ return { status: "failed" };
154
+ }
120
155
  // Otherwise it's ready
121
156
  return { status: "ready" };
122
157
  }
@@ -181,17 +216,28 @@ export class VideoManager {
181
216
  * Select a video format in the dialog (Explainer or Brief)
182
217
  */
183
218
  async selectFormat(page, format) {
219
+ // Validate against the allowlist BEFORE the value crosses into the page
220
+ // context. Without this, a value containing `"]` could break out of the
221
+ // attribute selector below (selector injection).
222
+ if (!VALID_VIDEO_FORMATS.includes(format)) {
223
+ log.warning(`video-manager: ignoring non-allowlisted format "${format}"`);
224
+ return false;
225
+ }
184
226
  return await page.evaluate((fmt) => {
185
227
  const browser = globalThis;
186
228
  // Format is in mat-radio-group.tile-group
187
229
  const radioGroup = browser.document.querySelector("mat-radio-group.tile-group");
188
230
  if (!radioGroup)
189
231
  return false;
190
- // Primary: value attribute (locale-independent if Angular Material uses stable values)
191
- const byValue = radioGroup.querySelector(`[value="${fmt}"]`);
192
- if (byValue) {
193
- byValue.click();
194
- return true;
232
+ // Primary: value attribute (locale-independent if Angular Material uses stable values).
233
+ // Iterate radio options and compare values with === rather than building a
234
+ // selector from the value, so untrusted text can never alter the selector.
235
+ const options = Array.from(radioGroup.querySelectorAll("[value]"));
236
+ for (const option of options) {
237
+ if (option.getAttribute?.("value") === fmt) {
238
+ option.click();
239
+ return true;
240
+ }
195
241
  }
196
242
  // Fallback: text match (English only — may not work in non-English locales,
197
243
  // but selectFormat is best-effort; generation will use default format if this fails)
@@ -210,17 +256,28 @@ export class VideoManager {
210
256
  * Select a video style in the dialog carousel
211
257
  */
212
258
  async selectStyle(page, style) {
259
+ // Validate against the allowlist BEFORE the value crosses into the page
260
+ // context. Without this, a value containing `"]` could break out of the
261
+ // attribute selector below (selector injection).
262
+ if (!VALID_VIDEO_STYLES.includes(style)) {
263
+ log.warning(`video-manager: ignoring non-allowlisted style "${style}"`);
264
+ return false;
265
+ }
213
266
  return await page.evaluate((styleName) => {
214
267
  const browser = globalThis;
215
268
  // Style is in mat-radio-group.carousel-group
216
269
  const radioGroup = browser.document.querySelector("mat-radio-group.carousel-group");
217
270
  if (!radioGroup)
218
271
  return false;
219
- // Primary: value attribute (locale-independent)
220
- const byValue = radioGroup.querySelector(`[value="${styleName}"]`);
221
- if (byValue) {
222
- byValue.click();
223
- return true;
272
+ // Primary: value attribute (locale-independent).
273
+ // Iterate radio options and compare values with === rather than building a
274
+ // selector from the value, so untrusted text can never alter the selector.
275
+ const options = Array.from(radioGroup.querySelectorAll("[value]"));
276
+ for (const option of options) {
277
+ if (option.getAttribute?.("value") === styleName) {
278
+ option.click();
279
+ return true;
280
+ }
224
281
  }
225
282
  // Fallback: text match (English only — style labels are translated in non-English UIs,
226
283
  // but selectStyle is best-effort; generation will use default style if this fails)
@@ -243,14 +300,26 @@ export class VideoManager {
243
300
  async clickDialogGenerate(page) {
244
301
  return await page.evaluate(() => {
245
302
  const browser = globalThis;
246
- // Primary: button in mat-dialog-actions
303
+ // Primary: the primary-color action button inside mat-dialog-actions.
304
+ // NEVER blindly click the FIRST button — Material dialogs conventionally place
305
+ // Cancel/Close first and the primary action last, so clicking [0] can hit Cancel
306
+ // and silently abort generation. Match the primary-color class/attribute first,
307
+ // then fall back to the LAST enabled button within the actions container.
247
308
  const dialogActions = browser.document.querySelector("mat-dialog-actions");
248
309
  if (dialogActions) {
249
- const btn = dialogActions.querySelector("button");
250
- if (btn) {
251
- btn.click();
310
+ const primaryInActions = dialogActions.querySelector('button.button-color--primary, button[color="primary"]');
311
+ if (primaryInActions) {
312
+ primaryInActions.click();
252
313
  return true;
253
314
  }
315
+ const actionButtons = Array.from(dialogActions.querySelectorAll("button"));
316
+ for (let i = actionButtons.length - 1; i >= 0; i--) {
317
+ const button = actionButtons[i];
318
+ if (!button.disabled) {
319
+ button.click();
320
+ return true;
321
+ }
322
+ }
254
323
  }
255
324
  // Fallback: button with primary color in any dialog
256
325
  const primaryBtn = browser.document.querySelector('.dialog-actions button, button.button-color--primary');
@@ -341,6 +410,14 @@ export class VideoManager {
341
410
  await randomDelay(500, 800);
342
411
  // Check if generation started
343
412
  const newStatus = await this.checkVideoStatusInternal(page);
413
+ if (newStatus.status === "failed") {
414
+ log.warning(" Video generation reported a failed state");
415
+ return {
416
+ success: false,
417
+ status: newStatus,
418
+ error: "Video generation failed.",
419
+ };
420
+ }
344
421
  if (newStatus.status === "generating" || newStatus.status === "ready") {
345
422
  log.success(` Video generation ${newStatus.status === "ready" ? "completed" : "started"}`);
346
423
  return { success: true, status: newStatus };
@@ -388,4 +465,3 @@ export class VideoManager {
388
465
  }
389
466
  }
390
467
  }
391
- //# sourceMappingURL=video-manager.js.map
@@ -16,4 +16,3 @@ export declare class MetricsRegistry {
16
16
  reset(): void;
17
17
  }
18
18
  export declare function getMetricsRegistry(): MetricsRegistry;
19
- //# sourceMappingURL=metrics.d.ts.map
@@ -32,4 +32,3 @@ const metrics = new MetricsRegistry();
32
32
  export function getMetricsRegistry() {
33
33
  return metrics;
34
34
  }
35
- //# sourceMappingURL=metrics.js.map
@@ -5,4 +5,3 @@
5
5
  * usage tracking, and limit enforcement.
6
6
  */
7
7
  export { QuotaManager, getQuotaManager, type LicenseTier, type QuotaLimits, type QuotaUsage, type QuotaSettings, } from "./quota-manager.js";
8
- //# sourceMappingURL=index.d.ts.map
@@ -5,4 +5,3 @@
5
5
  * usage tracking, and limit enforcement.
6
6
  */
7
7
  export { QuotaManager, getQuotaManager, } from "./quota-manager.js";
8
- //# sourceMappingURL=index.js.map
@@ -31,6 +31,17 @@ export declare class QuotaManager {
31
31
  * Load settings from disk or create defaults
32
32
  */
33
33
  private loadSettings;
34
+ /**
35
+ * Validate and sanitise an untrusted (user-writable) settings object.
36
+ *
37
+ * The quota.json file is user-writable, so a tampered or stale file must not
38
+ * be able to disable enforcement (e.g. by setting limits to 1e12/0/strings or
39
+ * omitting usage fields, which would otherwise yield NaN comparisons). Tier is
40
+ * constrained to a known key (falls back to "unknown"); limits are ALWAYS
41
+ * derived from TIER_LIMITS[tier] and never trusted from disk; usage fields are
42
+ * coerced to finite numbers and defaulted when missing.
43
+ */
44
+ private validateSettings;
34
45
  /**
35
46
  * Get default settings
36
47
  */
@@ -40,9 +51,17 @@ export declare class QuotaManager {
40
51
  */
41
52
  private saveSettings;
42
53
  /**
43
- * Reset daily query counters when the date changes and persist the rollover.
44
- */
45
- private rolloverIfNeeded;
54
+ * Effective (rolled-over) query count for TODAY, computed WITHOUT mutating or
55
+ * persisting settings. If the stored lastQueryDate is not today, the count is
56
+ * treated as 0 (the day has rolled over) but no write occurs — persisting the
57
+ * rollover is the exclusive responsibility of incrementQueryCountAtomic /
58
+ * checkAndReserveQuery (see I285). Shared by all readers (getStatus,
59
+ * getDetailedStatus, updateQuotaMetrics, canMakeQuery) so they never report a
60
+ * stale pre-rollover count.
61
+ */
62
+ private effectiveQueriesUsedToday;
63
+ /** Percentage guard: avoid NaN/Infinity when the limit is zero or invalid. */
64
+ private static safePercent;
46
65
  private evaluateWithTimeout;
47
66
  /**
48
67
  * Detect license tier from NotebookLM UI
@@ -106,6 +125,16 @@ export declare class QuotaManager {
106
125
  getUsage(): QuotaUsage;
107
126
  /**
108
127
  * Increment notebook count
128
+ *
129
+ * Uses the same withLock(settingsPath) transaction as
130
+ * incrementQueryCountAtomic (reload-under-lock → increment → persist) so the
131
+ * notebook counter shares ONE concurrency mechanism with the query counters
132
+ * (no separate ad-hoc promise queue). The lock provides mutual exclusion and
133
+ * the reload-under-lock prevents lost updates across concurrent callers;
134
+ * strict FIFO ordering is not required for a counter.
135
+ *
136
+ * Fail-soft contract preserved: this method logs and resolves on error rather
137
+ * than rejecting, since external callers may not catch.
109
138
  */
110
139
  incrementNotebookCount(): Promise<void>;
111
140
  /**
@@ -120,6 +149,33 @@ export declare class QuotaManager {
120
149
  * It reloads settings from disk before incrementing to ensure accuracy.
121
150
  */
122
151
  incrementQueryCountAtomic(): Promise<void>;
152
+ /**
153
+ * Atomically check the daily quota and reserve (increment) a slot in a single
154
+ * locked, disk-reloaded transaction.
155
+ *
156
+ * This closes the TOCTOU window where concurrent sessions/processes all pass a
157
+ * stale in-memory check (canMakeQuery) and then increment only after the slow
158
+ * browser query completes, collectively exceeding the daily limit. The slot is
159
+ * reserved up front, BEFORE the query runs.
160
+ *
161
+ * Returns { allowed, reason? }. Callers MUST run the query only when allowed,
162
+ * and call releaseReservation() if the query subsequently fails.
163
+ */
164
+ checkAndReserveQuery(): Promise<{
165
+ allowed: boolean;
166
+ reason?: string;
167
+ }>;
168
+ /**
169
+ * Release a previously reserved query slot (e.g. when the query failed after
170
+ * reservation in checkAndReserveQuery). Atomic and floored at zero so it can
171
+ * never underflow.
172
+ */
173
+ releaseReservation(): Promise<void>;
174
+ /**
175
+ * Persist current settings to disk while a file lock is already held.
176
+ * Mirrors the write performed inside incrementQueryCountAtomic.
177
+ */
178
+ private persistWithLockHeld;
123
179
  /**
124
180
  * Refresh settings from disk with file locking
125
181
  *
@@ -194,4 +250,3 @@ export declare class QuotaManager {
194
250
  };
195
251
  }
196
252
  export declare function getQuotaManager(): QuotaManager;
197
- //# sourceMappingURL=quota-manager.d.ts.map
@@ -39,8 +39,16 @@ const TIER_LIMITS = {
39
39
  },
40
40
  };
41
41
  const MAX_REASONABLE_QUERIES = 10000;
42
+ const MAX_REASONABLE_NOTEBOOKS = 100000;
42
43
  const PAGE_EVALUATE_TIMEOUT_MS = 30000;
43
- let notebookIncrementQueue = Promise.resolve();
44
+ /** Type guard: is the given string a known license tier? */
45
+ function isKnownTier(tier) {
46
+ return typeof tier === "string" && Object.prototype.hasOwnProperty.call(TIER_LIMITS, tier);
47
+ }
48
+ /** Always derive limits from the authoritative tier table (never trust on-disk limits). */
49
+ function deriveLimitsForTier(tier) {
50
+ return { ...TIER_LIMITS[tier] };
51
+ }
44
52
  export class QuotaManager {
45
53
  settings;
46
54
  settingsPath;
@@ -55,9 +63,10 @@ export class QuotaManager {
55
63
  try {
56
64
  if (fs.existsSync(this.settingsPath)) {
57
65
  const data = fs.readFileSync(this.settingsPath, "utf-8");
58
- const loaded = JSON.parse(data);
59
- log.info(`📊 Loaded quota settings (tier: ${loaded.tier})`);
60
- return loaded;
66
+ const parsed = JSON.parse(data);
67
+ const validated = this.validateSettings(parsed);
68
+ log.info(`📊 Loaded quota settings (tier: ${validated.tier})`);
69
+ return validated;
61
70
  }
62
71
  }
63
72
  catch (error) {
@@ -66,6 +75,57 @@ export class QuotaManager {
66
75
  // Return defaults
67
76
  return this.getDefaultSettings();
68
77
  }
78
+ /**
79
+ * Validate and sanitise an untrusted (user-writable) settings object.
80
+ *
81
+ * The quota.json file is user-writable, so a tampered or stale file must not
82
+ * be able to disable enforcement (e.g. by setting limits to 1e12/0/strings or
83
+ * omitting usage fields, which would otherwise yield NaN comparisons). Tier is
84
+ * constrained to a known key (falls back to "unknown"); limits are ALWAYS
85
+ * derived from TIER_LIMITS[tier] and never trusted from disk; usage fields are
86
+ * coerced to finite numbers and defaulted when missing.
87
+ */
88
+ validateSettings(parsed) {
89
+ if (!parsed || typeof parsed !== "object") {
90
+ log.warning("⚠️ Quota settings file is not an object; using defaults");
91
+ return this.getDefaultSettings();
92
+ }
93
+ const obj = parsed;
94
+ const defaults = this.getDefaultSettings();
95
+ // Tier must be a known key, otherwise fall back to a safe default.
96
+ let tier = "unknown";
97
+ if (isKnownTier(obj.tier)) {
98
+ tier = obj.tier;
99
+ }
100
+ else if (obj.tier !== undefined) {
101
+ log.warning(`⚠️ Unknown tier "${String(obj.tier)}" in quota settings; falling back to "unknown"`);
102
+ }
103
+ // CRUCIAL: derive limits from the tier table, never trust on-disk values.
104
+ const limits = deriveLimitsForTier(tier);
105
+ const rawUsage = obj.usage && typeof obj.usage === "object"
106
+ ? obj.usage
107
+ : {};
108
+ const coerceCount = (value, max) => {
109
+ const n = Number(value);
110
+ if (!Number.isFinite(n) || n < 0)
111
+ return 0;
112
+ return Math.min(Math.floor(n), max);
113
+ };
114
+ const queriesUsedToday = coerceCount(rawUsage.queriesUsedToday, MAX_REASONABLE_QUERIES);
115
+ const notebooks = coerceCount(rawUsage.notebooks, MAX_REASONABLE_NOTEBOOKS);
116
+ const lastQueryDate = typeof rawUsage.lastQueryDate === "string" && rawUsage.lastQueryDate.length > 0
117
+ ? rawUsage.lastQueryDate
118
+ : defaults.usage.lastQueryDate;
119
+ const lastUpdated = typeof rawUsage.lastUpdated === "string" && rawUsage.lastUpdated.length > 0
120
+ ? rawUsage.lastUpdated
121
+ : defaults.usage.lastUpdated;
122
+ return {
123
+ tier,
124
+ limits,
125
+ usage: { notebooks, queriesUsedToday, lastQueryDate, lastUpdated },
126
+ autoDetected: typeof obj.autoDetected === "boolean" ? obj.autoDetected : false,
127
+ };
128
+ }
69
129
  /**
70
130
  * Get default settings
71
131
  */
@@ -100,18 +160,25 @@ export class QuotaManager {
100
160
  }
101
161
  }
102
162
  /**
103
- * Reset daily query counters when the date changes and persist the rollover.
163
+ * Effective (rolled-over) query count for TODAY, computed WITHOUT mutating or
164
+ * persisting settings. If the stored lastQueryDate is not today, the count is
165
+ * treated as 0 (the day has rolled over) but no write occurs — persisting the
166
+ * rollover is the exclusive responsibility of incrementQueryCountAtomic /
167
+ * checkAndReserveQuery (see I285). Shared by all readers (getStatus,
168
+ * getDetailedStatus, updateQuotaMetrics, canMakeQuery) so they never report a
169
+ * stale pre-rollover count.
104
170
  */
105
- rolloverIfNeeded() {
171
+ effectiveQueriesUsedToday() {
106
172
  const today = new Date().toISOString().split("T")[0];
107
- if (this.settings.usage.lastQueryDate === today) {
108
- return false;
109
- }
110
- this.settings.usage.queriesUsedToday = 0;
111
- this.settings.usage.lastQueryDate = today;
112
- this.settings.usage.lastUpdated = new Date().toISOString();
113
- this.saveSettings();
114
- return true;
173
+ return this.settings.usage.lastQueryDate === today
174
+ ? this.settings.usage.queriesUsedToday
175
+ : 0;
176
+ }
177
+ /** Percentage guard: avoid NaN/Infinity when the limit is zero or invalid. */
178
+ static safePercent(used, limit) {
179
+ if (!Number.isFinite(limit) || limit <= 0)
180
+ return 0;
181
+ return Math.round((used / limit) * 100);
115
182
  }
116
183
  async evaluateWithTimeout(page, fn, timeoutMs = PAGE_EVALUATE_TIMEOUT_MS) {
117
184
  let timeout;
@@ -203,11 +270,15 @@ export class QuotaManager {
203
270
  async extractSourceLimitFromDialog(page) {
204
271
  const limitInfo = await this.evaluateWithTimeout(page, () => {
205
272
  const browser = globalThis;
206
- // Look for X/Y pattern
273
+ // Look for the "X / Y" source-count pattern, but ONLY accept a KNOWN
274
+ // source limit (50/300/600). A broad /\d+\/\d+/ matches any unrelated
275
+ // fraction on the page (timestamps, "3/5 steps", etc.), which previously
276
+ // let an arbitrary number through as the source limit and misdetected the
277
+ // tier upward. Mirror the whitelist used by detectTierFromPage.
207
278
  const allText = browser.document.body.innerText;
208
- const match = allText.match(/(\d+)\s*\/\s*(\d+)/);
279
+ const match = allText.match(/\b(\d+)\s*\/\s*(50|300|600)\b/);
209
280
  if (match) {
210
- return parseInt(match[2], 10); // Return the limit (Y in X/Y)
281
+ return parseInt(match[2], 10); // Return the whitelisted limit (Y in X/Y)
211
282
  }
212
283
  return null;
213
284
  });
@@ -381,11 +452,16 @@ export class QuotaManager {
381
452
  // Try to extract query usage from UI
382
453
  const queryUsage = await this.extractQueryUsageFromUI(page);
383
454
  if (queryUsage) {
384
- // Update local tracking with Google's numbers
455
+ // Update local tracking with Google's numbers.
385
456
  this.settings.usage.queriesUsedToday = Math.min(queryUsage.used, MAX_REASONABLE_QUERIES);
386
- this.settings.limits.queriesPerDay = queryUsage.limit;
457
+ // Scraped page numbers are untrusted: a spoofed/injected page (e.g.
458
+ // "0/999999") must never raise the enforced daily limit above the
459
+ // documented value for the detected tier. Treat the scraped limit only as
460
+ // a hint and clamp it to the tier's authoritative ceiling.
461
+ const tierCeiling = deriveLimitsForTier(this.settings.tier).queriesPerDay;
462
+ this.settings.limits.queriesPerDay = Math.min(Math.max(1, queryUsage.limit), tierCeiling);
387
463
  this.settings.usage.lastQueryDate = new Date().toISOString().split("T")[0];
388
- log.info(` Synced query usage from Google: ${this.settings.usage.queriesUsedToday}/${queryUsage.limit}`);
464
+ log.info(` Synced query usage from Google: ${this.settings.usage.queriesUsedToday}/${this.settings.limits.queriesPerDay}`);
389
465
  }
390
466
  // Check for rate limit
391
467
  const rateLimitDetected = await this.checkForRateLimitError(page);
@@ -451,24 +527,29 @@ export class QuotaManager {
451
527
  }
452
528
  /**
453
529
  * Increment notebook count
530
+ *
531
+ * Uses the same withLock(settingsPath) transaction as
532
+ * incrementQueryCountAtomic (reload-under-lock → increment → persist) so the
533
+ * notebook counter shares ONE concurrency mechanism with the query counters
534
+ * (no separate ad-hoc promise queue). The lock provides mutual exclusion and
535
+ * the reload-under-lock prevents lost updates across concurrent callers;
536
+ * strict FIFO ordering is not required for a counter.
537
+ *
538
+ * Fail-soft contract preserved: this method logs and resolves on error rather
539
+ * than rejecting, since external callers may not catch.
454
540
  */
455
- incrementNotebookCount() {
456
- notebookIncrementQueue = notebookIncrementQueue
457
- .catch((error) => {
458
- log.error(`❌ Notebook increment queue recovered from prior failure: ${error}`);
459
- })
460
- .then(async () => {
541
+ async incrementNotebookCount() {
542
+ try {
461
543
  await withLock(this.settingsPath, async () => {
462
544
  this.settings = this.loadSettings();
463
545
  this.settings.usage.notebooks++;
464
546
  this.settings.usage.lastUpdated = new Date().toISOString();
465
547
  this.saveSettings();
466
548
  });
467
- })
468
- .catch((error) => {
549
+ }
550
+ catch (error) {
469
551
  log.error(`❌ Could not increment notebook count: ${error}`);
470
- });
471
- return notebookIncrementQueue;
552
+ }
472
553
  }
473
554
  /**
474
555
  * Increment query count (synchronous, for backwards compatibility)
@@ -520,6 +601,71 @@ export class QuotaManager {
520
601
  }
521
602
  });
522
603
  }
604
+ /**
605
+ * Atomically check the daily quota and reserve (increment) a slot in a single
606
+ * locked, disk-reloaded transaction.
607
+ *
608
+ * This closes the TOCTOU window where concurrent sessions/processes all pass a
609
+ * stale in-memory check (canMakeQuery) and then increment only after the slow
610
+ * browser query completes, collectively exceeding the daily limit. The slot is
611
+ * reserved up front, BEFORE the query runs.
612
+ *
613
+ * Returns { allowed, reason? }. Callers MUST run the query only when allowed,
614
+ * and call releaseReservation() if the query subsequently fails.
615
+ */
616
+ async checkAndReserveQuery() {
617
+ return await withLock(this.settingsPath, async () => {
618
+ // Reload latest settings from disk (another process may have updated).
619
+ this.settings = this.loadSettings();
620
+ const today = new Date().toISOString().split("T")[0];
621
+ // Reset if new day (mirror incrementQueryCountAtomic rollover idiom).
622
+ if (this.settings.usage.lastQueryDate !== today) {
623
+ this.settings.usage.queriesUsedToday = 0;
624
+ this.settings.usage.lastQueryDate = today;
625
+ }
626
+ // CRUCIAL: derive the limit from the tier table, never trust on-disk limit.
627
+ const limit = deriveLimitsForTier(this.settings.tier).queriesPerDay;
628
+ if (this.settings.usage.queriesUsedToday >= limit) {
629
+ getMetricsRegistry().increment("quota_query_denials_total", { tier: this.settings.tier });
630
+ this.updateQuotaMetrics();
631
+ return {
632
+ allowed: false,
633
+ reason: `Daily query limit reached (${this.settings.usage.queriesUsedToday}/${limit}). Try again tomorrow or upgrade your plan.`,
634
+ };
635
+ }
636
+ // Reserve the slot now, before the query runs.
637
+ this.settings.usage.queriesUsedToday += 1;
638
+ this.settings.usage.lastUpdated = new Date().toISOString();
639
+ this.updateQuotaMetrics();
640
+ this.persistWithLockHeld();
641
+ return { allowed: true };
642
+ });
643
+ }
644
+ /**
645
+ * Release a previously reserved query slot (e.g. when the query failed after
646
+ * reservation in checkAndReserveQuery). Atomic and floored at zero so it can
647
+ * never underflow.
648
+ */
649
+ async releaseReservation() {
650
+ await withLock(this.settingsPath, async () => {
651
+ this.settings = this.loadSettings();
652
+ this.settings.usage.queriesUsedToday = Math.max(0, this.settings.usage.queriesUsedToday - 1);
653
+ this.settings.usage.lastUpdated = new Date().toISOString();
654
+ this.updateQuotaMetrics();
655
+ this.persistWithLockHeld();
656
+ });
657
+ }
658
+ /**
659
+ * Persist current settings to disk while a file lock is already held.
660
+ * Mirrors the write performed inside incrementQueryCountAtomic.
661
+ */
662
+ persistWithLockHeld() {
663
+ const dir = path.dirname(this.settingsPath);
664
+ if (!fs.existsSync(dir)) {
665
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
666
+ }
667
+ fs.writeFileSync(this.settingsPath, JSON.stringify(this.settings, null, 2), { mode: 0o600 });
668
+ }
523
669
  /**
524
670
  * Refresh settings from disk with file locking
525
671
  *
@@ -568,10 +714,7 @@ export class QuotaManager {
568
714
  canMakeQuery() {
569
715
  // Pure read: determine effective count without mutating settings.
570
716
  // Rollover mutation is handled exclusively in incrementQueryCountAtomic (I285).
571
- const today = new Date().toISOString().split("T")[0];
572
- const queriesUsedToday = this.settings.usage.lastQueryDate === today
573
- ? this.settings.usage.queriesUsedToday
574
- : 0; // New day — treat count as 0 without persisting
717
+ const queriesUsedToday = this.effectiveQueriesUsedToday();
575
718
  const { queriesPerDay: limit } = this.settings.limits;
576
719
  if (queriesUsedToday >= limit) {
577
720
  getMetricsRegistry().increment("quota_query_denials_total", { tier: this.settings.tier });
@@ -588,32 +731,35 @@ export class QuotaManager {
588
731
  this.updateQuotaMetrics(queriesUsedToday);
589
732
  return { allowed: true };
590
733
  }
591
- updateQuotaMetrics(queriesUsedToday = this.settings.usage.queriesUsedToday) {
734
+ updateQuotaMetrics(queriesUsedToday = this.effectiveQueriesUsedToday()) {
592
735
  const { tier, limits } = this.settings;
593
736
  const registry = getMetricsRegistry();
594
737
  registry.setGauge("quota_queries_used", queriesUsedToday, { tier });
595
738
  registry.setGauge("quota_queries_limit", limits.queriesPerDay, { tier });
596
- registry.setGauge("quota_queries_percent", Math.round((queriesUsedToday / limits.queriesPerDay) * 100), { tier });
739
+ registry.setGauge("quota_queries_percent", QuotaManager.safePercent(queriesUsedToday, limits.queriesPerDay), { tier });
597
740
  }
598
741
  /**
599
742
  * Get quota status summary
600
743
  */
601
744
  getStatus() {
602
745
  const { tier, limits, usage } = this.settings;
746
+ // Use the effective (rolled-over) count so getStatus never reports a stale
747
+ // pre-rollover figure; guard all percentages against a zero/invalid limit.
748
+ const queriesUsedToday = this.effectiveQueriesUsedToday();
603
749
  return {
604
750
  tier,
605
751
  notebooks: {
606
752
  used: usage.notebooks,
607
753
  limit: limits.notebooks,
608
- percent: Math.round((usage.notebooks / limits.notebooks) * 100),
754
+ percent: QuotaManager.safePercent(usage.notebooks, limits.notebooks),
609
755
  },
610
756
  sources: {
611
757
  limit: limits.sourcesPerNotebook,
612
758
  },
613
759
  queries: {
614
- used: usage.queriesUsedToday,
760
+ used: queriesUsedToday,
615
761
  limit: limits.queriesPerDay,
616
- percent: Math.round((usage.queriesUsedToday / limits.queriesPerDay) * 100),
762
+ percent: QuotaManager.safePercent(queriesUsedToday, limits.queriesPerDay),
617
763
  },
618
764
  };
619
765
  }
@@ -622,12 +768,16 @@ export class QuotaManager {
622
768
  * Used to provide visibility to users about when to stop querying for the day
623
769
  */
624
770
  getDetailedStatus() {
625
- this.rolloverIfNeeded();
771
+ // Pure read of the effective (rolled-over) count — consistent with
772
+ // getStatus/canMakeQuery. Rollover is NOT persisted here; that is the
773
+ // exclusive responsibility of incrementQueryCountAtomic/checkAndReserveQuery
774
+ // (I285), so this reader no longer mutates+persists the rollover.
626
775
  const { tier, limits, usage } = this.settings;
627
- const queriesRemaining = limits.queriesPerDay - usage.queriesUsedToday;
628
- const queriesPercentUsed = Math.round((usage.queriesUsedToday / limits.queriesPerDay) * 100);
776
+ const queriesUsedToday = this.effectiveQueriesUsedToday();
777
+ const queriesRemaining = limits.queriesPerDay - queriesUsedToday;
778
+ const queriesPercentUsed = QuotaManager.safePercent(queriesUsedToday, limits.queriesPerDay);
629
779
  const notebooksRemaining = limits.notebooks - usage.notebooks;
630
- const notebooksPercentUsed = Math.round((usage.notebooks / limits.notebooks) * 100);
780
+ const notebooksPercentUsed = QuotaManager.safePercent(usage.notebooks, limits.notebooks);
631
781
  // Calculate next reset time (midnight local time)
632
782
  const tomorrow = new Date();
633
783
  tomorrow.setDate(tomorrow.getDate() + 1);
@@ -635,7 +785,7 @@ export class QuotaManager {
635
785
  // Build warnings list
636
786
  const warnings = [];
637
787
  if (queriesRemaining <= 0) {
638
- warnings.push(`CRITICAL: Daily query limit reached (${usage.queriesUsedToday}/${limits.queriesPerDay}). Wait until tomorrow or upgrade your plan.`);
788
+ warnings.push(`CRITICAL: Daily query limit reached (${queriesUsedToday}/${limits.queriesPerDay}). Wait until tomorrow or upgrade your plan.`);
639
789
  }
640
790
  else if (queriesRemaining <= 5) {
641
791
  warnings.push(`CRITICAL: Only ${queriesRemaining} queries remaining today! Consider stopping soon.`);
@@ -652,7 +802,7 @@ export class QuotaManager {
652
802
  return {
653
803
  tier,
654
804
  queries: {
655
- used: usage.queriesUsedToday,
805
+ used: queriesUsedToday,
656
806
  limit: limits.queriesPerDay,
657
807
  remaining: queriesRemaining,
658
808
  percentUsed: queriesPercentUsed,
@@ -680,4 +830,3 @@ export function getQuotaManager() {
680
830
  }
681
831
  return quotaManagerInstance;
682
832
  }
683
- //# sourceMappingURL=quota-manager.js.map
@@ -19,4 +19,3 @@ export declare class ResourceHandlers {
19
19
  */
20
20
  private buildCompletion;
21
21
  }
22
- //# sourceMappingURL=resource-handlers.d.ts.map