@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.
- package/README.md +28 -2
- package/agents/agents/salesforce-docs-researcher.agent.md +117 -0
- package/agents/hooks/README.md +62 -0
- package/agents/hooks/claude-code/hooks/bonsai-web-fetch.sh +22 -0
- package/agents/hooks/claude-code/settings.json +16 -0
- package/agents/hooks/codex/hooks/bonsai-user-prompt-context.sh +18 -0
- package/agents/hooks/codex/hooks/bonsai-web-fetch.sh +22 -0
- package/agents/hooks/codex/hooks.json +28 -0
- package/agents/hooks/cursor/hooks/bonsai-web-fetch.sh +21 -0
- package/agents/hooks/cursor/hooks.json +12 -0
- package/agents/hooks/github-copilot/bonsai-web-fetch.json +23 -0
- package/agents/hooks/github-copilot/bonsai-web-fetch.sh +19 -0
- package/agents/instructions/salesforce-research.instructions.md +57 -0
- package/agents/instructions/web-research.instructions.md +2 -1
- package/bin/cli.mjs +13 -3
- package/dist/base-command.d.ts +20 -0
- package/dist/base-command.js +27 -1
- package/dist/commands/config/get.js +2 -2
- package/dist/commands/config/list.js +2 -2
- package/dist/commands/config/set.js +2 -2
- package/dist/commands/config/unset.js +2 -2
- package/dist/commands/fetch.d.ts +5 -0
- package/dist/commands/fetch.js +81 -16
- package/dist/commands/import.d.ts +1 -0
- package/dist/commands/import.js +38 -6
- package/dist/commands/list.js +18 -3
- package/dist/commands/prune.js +22 -6
- package/dist/commands/search.js +21 -22
- package/dist/commands/status.js +10 -9
- package/dist/hooks/command-not-found/suggest.d.ts +9 -0
- package/dist/hooks/command-not-found/suggest.js +93 -0
- package/dist/lib/config/index.d.ts +1 -1
- package/dist/lib/config/index.js +1 -1
- package/dist/lib/config/resolve.d.ts +7 -0
- package/dist/lib/config/resolve.js +23 -0
- package/dist/lib/research/browser.d.ts +12 -0
- package/dist/lib/research/browser.js +40 -3
- package/dist/lib/research/docs/capabilities.d.ts +1 -1
- package/dist/lib/research/docs/discovery-index.d.ts +14 -0
- package/dist/lib/research/docs/discovery-index.js +112 -0
- package/dist/lib/research/docs/machine-readable.d.ts +2 -2
- package/dist/lib/research/docs/machine-readable.js +3 -7
- package/dist/lib/research/docs/remote-search-runner.js +61 -1
- package/dist/lib/research/docs/sections.d.ts +1 -0
- package/dist/lib/research/docs/sections.js +19 -1
- package/dist/lib/research/freshness.d.ts +9 -1
- package/dist/lib/research/freshness.js +24 -2
- package/dist/lib/research/keywords.d.ts +10 -3
- package/dist/lib/research/keywords.js +32 -5
- package/dist/lib/research/secret-scan.js +4 -2
- package/dist/lib/research/url.js +5 -2
- package/dist/lib/text.d.ts +33 -0
- package/dist/lib/text.js +63 -0
- package/oclif.manifest.json +8 -8
- package/package.json +17 -3
package/dist/lib/text.js
ADDED
|
@@ -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
|
+
}
|
package/oclif.manifest.json
CHANGED
|
@@ -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
|
|
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
|
|
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.
|
|
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.
|
|
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
|
-
"
|
|
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)"
|