bookmark-research 0.6.0 → 0.7.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 (69) hide show
  1. package/.agents/plugins/marketplace.json +1 -1
  2. package/.codex-plugin/plugin.json +4 -1
  3. package/README.md +15 -9
  4. package/README.zh.md +16 -9
  5. package/config/providers.json +26 -0
  6. package/config/settings.example.json +36 -0
  7. package/docs/bookmark-research-architecture.md +2 -2
  8. package/docs/canvas-tree-reading-acceptance.md +98 -0
  9. package/docs/configuration.en.md +70 -0
  10. package/docs/configuration.md +70 -0
  11. package/docs/details.en.md +10 -6
  12. package/docs/details.md +3 -3
  13. package/docs/harness-compatibility.md +1 -1
  14. package/docs/installation.en.md +4 -2
  15. package/docs/installation.md +4 -2
  16. package/docs/instructions.en.md +1 -0
  17. package/docs/instructions.md +1 -0
  18. package/docs/user-guide.en.md +1 -1
  19. package/docs/user-guide.md +1 -1
  20. package/hosts/dsh/plugin.js +3 -0
  21. package/package.json +1 -1
  22. package/scripts/bench_sync.py +191 -0
  23. package/scripts/bench_tools_list.py +129 -0
  24. package/scripts/evaluate_ladder.py +149 -0
  25. package/scripts/export_bundle.py +2 -0
  26. package/scripts/host_install.py +4 -1
  27. package/scripts/install.py +120 -28
  28. package/skills/bookmark-research/SKILL.md +28 -9
  29. package/skills/bookmark-research/references/package-semantics.md +56 -6
  30. package/skills/bookmark-research/references/research-workflow.md +5 -2
  31. package/skills/bookmark-research/references/settings-and-archive.md +5 -3
  32. package/skills/bookmark-research/references/wiki.md +3 -1
  33. package/skills/bookmark-research/references/zh/package-semantics.md +56 -6
  34. package/skills/bookmark-research/references/zh/research-workflow.md +5 -2
  35. package/skills/bookmark-research/references/zh/settings-and-archive.md +5 -3
  36. package/skills/bookmark-research/references/zh/skill-guide.md +20 -8
  37. package/skills/bookmark-research/references/zh/wiki.md +3 -1
  38. package/src/archive.py +100 -0
  39. package/src/bookmark_index.py +808 -41
  40. package/src/browser_client.py +342 -0
  41. package/src/cli.py +298 -14
  42. package/src/credentials.py +2 -1
  43. package/src/fetch_cache.py +60 -0
  44. package/src/grok_search.py +272 -0
  45. package/src/jobs.py +349 -0
  46. package/src/junk.py +33 -0
  47. package/src/locate.py +862 -0
  48. package/src/mcp_dispatch.py +22 -6
  49. package/src/mcp_server.py +573 -23
  50. package/src/netscape.py +124 -0
  51. package/src/onboarding.py +59 -9
  52. package/src/perplexity.py +78 -0
  53. package/src/raw_library.py +183 -45
  54. package/src/readiness.py +40 -5
  55. package/src/ref_codec.py +70 -0
  56. package/src/research.py +125 -12
  57. package/src/research_plan.py +11 -1
  58. package/src/routing.py +5 -2
  59. package/src/search_results.py +80 -2
  60. package/src/settings.py +61 -16
  61. package/src/source_inputs.py +109 -3
  62. package/src/source_manager.py +71 -12
  63. package/src/source_versions.py +20 -2
  64. package/src/source_watcher.py +4 -2
  65. package/src/storage.py +60 -0
  66. package/src/url_classify.py +45 -0
  67. package/src/web_search.py +106 -10
  68. package/src/wiki.py +269 -18
  69. package/src/wiki_search.py +119 -27
@@ -1,5 +1,6 @@
1
1
  """Bounded network work; local SQLite handles stay on the transport thread."""
2
2
  import threading
3
+ import time
3
4
  from concurrent.futures import CancelledError, ThreadPoolExecutor
4
5
 
5
6
 
@@ -33,15 +34,30 @@ class StdioRequestQueue:
33
34
  except (BrokenPipeError, OSError):
34
35
  self.output_closed = True
35
36
 
36
- def _handle(self, request):
37
+ def _handle(self, request, submitted_ns=None):
38
+ started_ns = time.monotonic_ns()
37
39
  try:
38
- return self.server.handle(request)
40
+ response = self.server.handle(request)
39
41
  except Exception as error:
40
42
  self.server._log("Request handler failed (%s)" % type(error).__name__)
41
- return self._error(request.get("id") if isinstance(request, dict) else None,
42
- -32603, "Internal server error")
43
+ response = self._error(request.get("id") if isinstance(request, dict) else None,
44
+ -32603, "Internal server error")
45
+ if isinstance(request, dict) and request.get("method") == "tools/call":
46
+ params = request.get("params")
47
+ name = params.get("name") if isinstance(params, dict) else None
48
+ if not isinstance(name, str) or not name.isascii() or not name.replace("_", "").isalnum():
49
+ name = "invalid"
50
+ queue_ms = max(0, (started_ns - submitted_ns) // 1_000_000) if submitted_ns is not None else 0
51
+ handler_ms = max(0, (time.monotonic_ns() - started_ns) // 1_000_000)
52
+ result = response.get("result") if isinstance(response, dict) else None
53
+ outcome = "error" if isinstance(response, dict) and ("error" in response or
54
+ (isinstance(result, dict) and result.get("isError"))) else "ok"
55
+ self.server._log("tool_timing name=%s queue_ms=%d handler_ms=%d outcome=%s" %
56
+ (name[:64], queue_ms, handler_ms, outcome))
57
+ return response
43
58
 
44
59
  def submit(self, request):
60
+ submitted_ns = time.monotonic_ns()
45
61
  key, future, error = self._key(request), None, None
46
62
  with self.lock:
47
63
  if key is not None and key in self.pending:
@@ -50,14 +66,14 @@ class StdioRequestQueue:
50
66
  if len(self.pending) >= self.max_pending:
51
67
  error = self._error(key[1], -32000, "Network request queue is full; retry after an earlier response")
52
68
  else:
53
- future = self.pool.submit(self._handle, request)
69
+ future = self.pool.submit(self._handle, request, submitted_ns)
54
70
  self.pending[key] = future
55
71
  if error is not None:
56
72
  self.emit(error)
57
73
  elif future is not None:
58
74
  future.add_done_callback(lambda completed: self._done(key, completed))
59
75
  else:
60
- self.emit(self._handle(request))
76
+ self.emit(self._handle(request, submitted_ns))
61
77
 
62
78
  def _done(self, key, future):
63
79
  try: