@taurgis/bonsai 1.0.4 → 1.0.5

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 (55) hide show
  1. package/README.md +28 -2
  2. package/agents/agents/salesforce-docs-researcher.agent.md +117 -0
  3. package/agents/hooks/README.md +62 -0
  4. package/agents/hooks/claude-code/hooks/bonsai-web-fetch.sh +22 -0
  5. package/agents/hooks/claude-code/settings.json +16 -0
  6. package/agents/hooks/codex/hooks/bonsai-user-prompt-context.sh +18 -0
  7. package/agents/hooks/codex/hooks/bonsai-web-fetch.sh +22 -0
  8. package/agents/hooks/codex/hooks.json +28 -0
  9. package/agents/hooks/cursor/hooks/bonsai-web-fetch.sh +21 -0
  10. package/agents/hooks/cursor/hooks.json +12 -0
  11. package/agents/hooks/github-copilot/bonsai-web-fetch.json +23 -0
  12. package/agents/hooks/github-copilot/bonsai-web-fetch.sh +19 -0
  13. package/agents/instructions/salesforce-research.instructions.md +57 -0
  14. package/agents/instructions/web-research.instructions.md +2 -1
  15. package/bin/cli.mjs +13 -3
  16. package/dist/base-command.d.ts +20 -0
  17. package/dist/base-command.js +27 -1
  18. package/dist/commands/config/get.js +2 -2
  19. package/dist/commands/config/list.js +2 -2
  20. package/dist/commands/config/set.js +2 -2
  21. package/dist/commands/config/unset.js +2 -2
  22. package/dist/commands/fetch.d.ts +5 -0
  23. package/dist/commands/fetch.js +81 -16
  24. package/dist/commands/import.d.ts +1 -0
  25. package/dist/commands/import.js +38 -6
  26. package/dist/commands/list.js +18 -3
  27. package/dist/commands/prune.js +22 -6
  28. package/dist/commands/search.js +21 -22
  29. package/dist/commands/status.js +10 -9
  30. package/dist/hooks/command-not-found/suggest.d.ts +9 -0
  31. package/dist/hooks/command-not-found/suggest.js +93 -0
  32. package/dist/lib/config/index.d.ts +1 -1
  33. package/dist/lib/config/index.js +1 -1
  34. package/dist/lib/config/resolve.d.ts +7 -0
  35. package/dist/lib/config/resolve.js +23 -0
  36. package/dist/lib/research/browser.d.ts +12 -0
  37. package/dist/lib/research/browser.js +40 -3
  38. package/dist/lib/research/docs/capabilities.d.ts +1 -1
  39. package/dist/lib/research/docs/discovery-index.d.ts +14 -0
  40. package/dist/lib/research/docs/discovery-index.js +112 -0
  41. package/dist/lib/research/docs/machine-readable.d.ts +2 -2
  42. package/dist/lib/research/docs/machine-readable.js +3 -7
  43. package/dist/lib/research/docs/remote-search-runner.js +61 -1
  44. package/dist/lib/research/docs/sections.d.ts +1 -0
  45. package/dist/lib/research/docs/sections.js +19 -1
  46. package/dist/lib/research/freshness.d.ts +9 -1
  47. package/dist/lib/research/freshness.js +24 -2
  48. package/dist/lib/research/keywords.d.ts +10 -3
  49. package/dist/lib/research/keywords.js +32 -5
  50. package/dist/lib/research/secret-scan.js +4 -2
  51. package/dist/lib/research/url.js +5 -2
  52. package/dist/lib/text.d.ts +33 -0
  53. package/dist/lib/text.js +63 -0
  54. package/oclif.manifest.json +8 -8
  55. package/package.json +17 -3
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Pick the singular or plural noun for a count so human-readable output stays grammatical
3
+ * ("1 entry" / "2 entries"). English has irregular plurals, so the plural is passed explicitly
4
+ * rather than derived.
5
+ */
6
+ export function pluralize(count, singular, plural) {
7
+ return count === 1 ? singular : plural;
8
+ }
9
+ /** Heading for a result listing; notes truncation inline when more matched than are shown. */
10
+ export function resultListHeading(total, shown, labels) {
11
+ const noun = `${labels.noun} ${pluralize(total, 'entry', 'entries')}`;
12
+ return total > shown
13
+ ? `Found ${total} ${noun} (showing ${labels.order} ${shown}; raise --limit to see more):`
14
+ : `Found ${total} ${noun}:`;
15
+ }
16
+ /**
17
+ * One-line truncation notice for stderr, or null when nothing was cut. Used under --json, where the
18
+ * stdout heading is suppressed and an agent would otherwise get no signal that results were capped.
19
+ */
20
+ export function truncationNotice(total, shown, labels) {
21
+ if (total <= shown)
22
+ return null;
23
+ return `${total} entries matched; returning the ${labels.order} ${shown}. Raise --limit (max ${labels.maxLimit}) to see more.`;
24
+ }
25
+ /**
26
+ * Levenshtein edit distance: the minimum number of single-character insertions, deletions, or
27
+ * substitutions to turn `s1` into `s2`. Shared by fuzzy search ranking and command-typo suggestion.
28
+ */
29
+ export function levenshtein(s1, s2) {
30
+ if (s1.length < s2.length)
31
+ return levenshtein(s2, s1);
32
+ if (s2.length === 0)
33
+ return s1.length;
34
+ let prevRow = Array.from({ length: s2.length + 1 }, (_, i) => i);
35
+ for (let i = 0; i < s1.length; i++) {
36
+ const currRow = [i + 1];
37
+ for (let j = 0; j < s2.length; j++) {
38
+ const deletions = prevRow[j + 1] + 1;
39
+ const insertions = currRow[j] + 1;
40
+ const substitutions = prevRow[j] + (s1[i] === s2[j] ? 0 : 1);
41
+ currRow.push(Math.min(deletions, insertions, substitutions));
42
+ }
43
+ prevRow = currRow;
44
+ }
45
+ return prevRow[s2.length];
46
+ }
47
+ /**
48
+ * The candidate nearest to `input` by edit distance, or null when even the closest is farther than
49
+ * `maxDistance`. The threshold keeps suggestions to plausible typos — input that resembles nothing
50
+ * gets no correction rather than an absurd one.
51
+ */
52
+ export function closestMatch(input, candidates, maxDistance) {
53
+ let best = null;
54
+ let bestDistance = Infinity;
55
+ for (const candidate of candidates) {
56
+ const distance = levenshtein(input, candidate);
57
+ if (distance < bestDistance) {
58
+ bestDistance = distance;
59
+ best = candidate;
60
+ }
61
+ }
62
+ return bestDistance <= maxDistance ? best : null;
63
+ }
@@ -9,7 +9,7 @@
9
9
  "required": true
10
10
  }
11
11
  },
12
- "description": "Scrapes the specified URL, strips HTML boilerplate, converts the semantic payload into clean Markdown format, and caches the result locally using dynamic TTL rules.",
12
+ "description": "Scrapes the specified URL, strips HTML boilerplate, converts the semantic payload into clean Markdown format, and caches the result locally using dynamic TTL rules.\n\nUsually invoked via the shorthand `bonsai <url>` rather than `bonsai fetch <url>`.",
13
13
  "examples": [
14
14
  {
15
15
  "description": "Research a URL with detailed output, tagged with topic and tags",
@@ -72,7 +72,7 @@
72
72
  },
73
73
  "ttl": {
74
74
  "char": "l",
75
- "description": "Predicted lifespan of the data (e.g., \"2h\", \"7d\", \"3m\").",
75
+ "description": "Predicted lifespan: number + h/d/w/m/y (m = months), e.g. \"2h\", \"7d\", \"6m\".",
76
76
  "name": "ttl",
77
77
  "hasDynamicHelp": false,
78
78
  "multiple": false,
@@ -525,7 +525,7 @@
525
525
  "type": "option"
526
526
  },
527
527
  "remote": {
528
- "description": "Discover uncached docs via a site’s public search (Algolia DocSearch, MkDocs/Sphinx/Just-the-Docs index). Pass a docs page URL; falls back to local cache search if no connector applies.",
528
+ "description": "Discover uncached docs via a site’s public search or index (Algolia DocSearch, MkDocs/Sphinx/Just-the-Docs, llms.txt, sitemap.xml). Pass a docs page URL; falls back to local cache search if no connector applies.",
529
529
  "name": "remote",
530
530
  "hasDynamicHelp": false,
531
531
  "multiple": false,
@@ -610,7 +610,7 @@
610
610
  "required": true
611
611
  }
612
612
  },
613
- "description": "Print a config value. Without --global/--local, shows the merged effective value (flag > env > project > user > default).\n\nValid keys: storage.",
613
+ "description": "Print a config value. Without --global/--local, shows the merged effective value (flag > env > project > user > default).\n\nValid keys: storage, summary.",
614
614
  "examples": [
615
615
  {
616
616
  "description": "Get the effective storage mode",
@@ -662,7 +662,7 @@
662
662
  "config:list": {
663
663
  "aliases": [],
664
664
  "args": {},
665
- "description": "Show every configuration key with its current value. Use --global/--local to show a single scope.\n\nValid keys: storage.",
665
+ "description": "Show every configuration key with its current value. Use --global/--local to show a single scope.\n\nValid keys: storage, summary.",
666
666
  "examples": [
667
667
  {
668
668
  "description": "Show all effective config values",
@@ -725,7 +725,7 @@
725
725
  "required": false
726
726
  }
727
727
  },
728
- "description": "Persist a configuration value. Writes user-level config by default; pass --local to write the project-level config (.bonsai.json in cwd).\n\nValid keys: storage. The inline form `<key>=<value>` is also accepted.",
728
+ "description": "Persist a configuration value. Writes user-level config by default; pass --local to write the project-level config (.bonsai.json in cwd).\n\nValid keys: storage, summary. The inline form `<key>=<value>` is also accepted.",
729
729
  "examples": [
730
730
  {
731
731
  "description": "Store research cache inside the current project",
@@ -789,7 +789,7 @@
789
789
  "required": true
790
790
  }
791
791
  },
792
- "description": "Delete a key from user-level config (default) or project-level config (--local), restoring the built-in default.\n\nValid keys: storage.",
792
+ "description": "Delete a key from user-level config (default) or project-level config (--local), restoring the built-in default.\n\nValid keys: storage, summary.",
793
793
  "examples": [
794
794
  {
795
795
  "description": "Remove the user-level storage setting",
@@ -845,5 +845,5 @@
845
845
  "stdoutIsPrimaryData": true
846
846
  }
847
847
  },
848
- "version": "1.0.4"
848
+ "version": "1.0.5"
849
849
  }
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "@taurgis/bonsai",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Bonsai is a standalone local research cache CLI for AI agents",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/taurgis/bonsai.git"
8
+ },
9
+ "homepage": "https://bonsai.rhino-inquisitor.com/",
5
10
  "type": "module",
6
11
  "main": "./dist/index.js",
7
12
  "bin": {
@@ -29,7 +34,10 @@
29
34
  "nexus:sync": "npx forward-nexus update && npx forward-nexus sync",
30
35
  "test": "vitest",
31
36
  "test:coverage": "vitest run --coverage",
32
- "type-check": "tsc --noEmit"
37
+ "type-check": "tsc --noEmit",
38
+ "docs:dev": "vitepress dev docs",
39
+ "docs:build": "vitepress build docs",
40
+ "docs:preview": "vitepress preview docs"
33
41
  },
34
42
  "lint-staged": {
35
43
  "src/**/*.ts": "prettier --write",
@@ -55,7 +63,9 @@
55
63
  "oclif": "^4.23.21",
56
64
  "prettier": "^3.8.1",
57
65
  "typescript": "^5.9.3",
58
- "vitest": "^4.0.17"
66
+ "vitepress": "^1.6.4",
67
+ "vitest": "^4.0.17",
68
+ "vue": "^3.5.39"
59
69
  },
60
70
  "engines": {
61
71
  "node": ">=22"
@@ -64,12 +74,16 @@
64
74
  "oclif": {
65
75
  "bin": "bonsai",
66
76
  "dirname": "bonsai",
77
+ "description": "Bonsai is a standalone local research cache CLI for AI agents.\nResearch and cache a web page by passing its URL directly:\n\n $ bonsai https://nodejs.org/api/url.html\n\nThe URL form is shorthand for fetching and caching the page. The commands listed below search, inspect, list, import, and prune the local research cache.",
67
78
  "commands": {
68
79
  "strategy": "explicit",
69
80
  "target": "./dist/commands.js",
70
81
  "identifier": "commands"
71
82
  },
72
83
  "topicSeparator": " ",
84
+ "hooks": {
85
+ "command_not_found": "./dist/hooks/command-not-found/suggest.js"
86
+ },
73
87
  "topics": {
74
88
  "config": {
75
89
  "description": "Manage research cache storage configuration (global vs project)"