@kolisachint/hoocode-agent 0.5.42 → 0.5.44

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 (40) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/dist/core/settings-defaults.d.ts +1 -0
  3. package/dist/core/settings-defaults.d.ts.map +1 -1
  4. package/dist/core/settings-defaults.js +1 -0
  5. package/dist/core/settings-defaults.js.map +1 -1
  6. package/dist/core/settings-manager.d.ts +14 -0
  7. package/dist/core/settings-manager.d.ts.map +1 -1
  8. package/dist/core/settings-manager.js +15 -0
  9. package/dist/core/settings-manager.js.map +1 -1
  10. package/dist/core/settings-types.d.ts +3 -0
  11. package/dist/core/settings-types.d.ts.map +1 -1
  12. package/dist/core/settings-types.js.map +1 -1
  13. package/dist/core/tools/webfetch.d.ts +9 -0
  14. package/dist/core/tools/webfetch.d.ts.map +1 -1
  15. package/dist/core/tools/webfetch.js +52 -5
  16. package/dist/core/tools/webfetch.js.map +1 -1
  17. package/dist/core/tools/websearch.d.ts.map +1 -1
  18. package/dist/core/tools/websearch.js +8 -0
  19. package/dist/core/tools/websearch.js.map +1 -1
  20. package/dist/core/tools/webtools-shared.d.ts +83 -2
  21. package/dist/core/tools/webtools-shared.d.ts.map +1 -1
  22. package/dist/core/tools/webtools-shared.js +60 -2
  23. package/dist/core/tools/webtools-shared.js.map +1 -1
  24. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  25. package/dist/modes/interactive/components/settings-selector.js +11 -0
  26. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  27. package/dist/modes/interactive/interactive-mode.d.ts +6 -0
  28. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  29. package/dist/modes/interactive/interactive-mode.js +16 -0
  30. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  31. package/dist/modes/interactive/websearch-warning.d.ts +35 -0
  32. package/dist/modes/interactive/websearch-warning.d.ts.map +1 -0
  33. package/dist/modes/interactive/websearch-warning.js +40 -0
  34. package/dist/modes/interactive/websearch-warning.js.map +1 -0
  35. package/docs/settings.md +69 -2
  36. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  37. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  38. package/examples/extensions/sandbox/package.json +1 -1
  39. package/examples/extensions/with-deps/package.json +1 -1
  40. package/package.json +4 -4
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The "websearch has no API key" startup notice.
3
+ *
4
+ * `websearch` works with no configuration at all, but the keyless default is
5
+ * scraped DuckDuckGo HTML: it is rate-limited hard and can fail outright, and
6
+ * the failure surfaces as a bad search rather than as a setup problem. So when
7
+ * the tool is active and no keyed backend is configured, the session says so
8
+ * once — the same shape as the Anthropic extra-usage notice, including the
9
+ * `/settings` switch that turns it off.
10
+ */
11
+ import type { WarningSettings } from "../../core/settings-types.js";
12
+ import { type WebtoolsSearchSettings } from "../../core/tools/webtools-shared.js";
13
+ export declare const WEBSEARCH_API_KEY_TITLE = "Web search has no API key";
14
+ export interface WebSearchApiKeyNoticeInput {
15
+ /** Tools the session actually exposes; the notice is pointless without `websearch`. */
16
+ activeToolNames: readonly string[];
17
+ /** Warning switches from settings (`warnings.websearchApiKey`). */
18
+ warnings: WarningSettings;
19
+ /** The `webtools.search` block, as the binary would read it. */
20
+ search?: WebtoolsSearchSettings;
21
+ }
22
+ export interface WebSearchApiKeyNotice {
23
+ title: string;
24
+ body: string[];
25
+ }
26
+ /**
27
+ * The notice to show, or undefined when there is nothing to say: the tool is
28
+ * off, a keyed backend is configured, the user pinned the keyless backend on
29
+ * purpose, or the warning is switched off.
30
+ *
31
+ * Pure, so the decision is testable without a TUI; the caller owns the
32
+ * once-per-session latch.
33
+ */
34
+ export declare function websearchApiKeyNotice(input: WebSearchApiKeyNoticeInput): WebSearchApiKeyNotice | undefined;
35
+ //# sourceMappingURL=websearch-warning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websearch-warning.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/websearch-warning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAA+B,KAAK,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAE/G,eAAO,MAAM,uBAAuB,8BAA8B,CAAC;AAEnE,MAAM,WAAW,0BAA0B;IAC1C,uFAAuF;IACvF,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,mEAAmE;IACnE,QAAQ,EAAE,eAAe,CAAC;IAC1B,gEAAgE;IAChE,MAAM,CAAC,EAAE,sBAAsB,CAAC;CAChC;AAED,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;CACf;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,GAAG,qBAAqB,GAAG,SAAS,CAiB1G","sourcesContent":["/**\n * The \"websearch has no API key\" startup notice.\n *\n * `websearch` works with no configuration at all, but the keyless default is\n * scraped DuckDuckGo HTML: it is rate-limited hard and can fail outright, and\n * the failure surfaces as a bad search rather than as a setup problem. So when\n * the tool is active and no keyed backend is configured, the session says so\n * once — the same shape as the Anthropic extra-usage notice, including the\n * `/settings` switch that turns it off.\n */\n\nimport type { WarningSettings } from \"../../core/settings-types.js\";\nimport { resolveWebSearchCredentials, type WebtoolsSearchSettings } from \"../../core/tools/webtools-shared.js\";\n\nexport const WEBSEARCH_API_KEY_TITLE = \"Web search has no API key\";\n\nexport interface WebSearchApiKeyNoticeInput {\n\t/** Tools the session actually exposes; the notice is pointless without `websearch`. */\n\tactiveToolNames: readonly string[];\n\t/** Warning switches from settings (`warnings.websearchApiKey`). */\n\twarnings: WarningSettings;\n\t/** The `webtools.search` block, as the binary would read it. */\n\tsearch?: WebtoolsSearchSettings;\n}\n\nexport interface WebSearchApiKeyNotice {\n\ttitle: string;\n\tbody: string[];\n}\n\n/**\n * The notice to show, or undefined when there is nothing to say: the tool is\n * off, a keyed backend is configured, the user pinned the keyless backend on\n * purpose, or the warning is switched off.\n *\n * Pure, so the decision is testable without a TUI; the caller owns the\n * once-per-session latch.\n */\nexport function websearchApiKeyNotice(input: WebSearchApiKeyNoticeInput): WebSearchApiKeyNotice | undefined {\n\tif (input.warnings.websearchApiKey === false) return undefined;\n\tif (!input.activeToolNames.includes(\"websearch\")) return undefined;\n\n\tconst credentials = resolveWebSearchCredentials(input.search);\n\tif (credentials.configured || credentials.explicitKeyless) return undefined;\n\n\treturn {\n\t\ttitle: WEBSEARCH_API_KEY_TITLE,\n\t\t// Two lines, like the Anthropic notice: what is wrong and the one setting\n\t\t// that fixes it. The other backends and the settings.json block are in\n\t\t// the docs — a startup notice is not the place to list them.\n\t\tbody: [\n\t\t\t\"Searching keyless DuckDuckGo, which is rate-limited. Set BRAVE_API_KEY or TAVILY_API_KEY.\",\n\t\t\t\"Turn off in /settings → Web search API key.\",\n\t\t],\n\t};\n}\n"]}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The "websearch has no API key" startup notice.
3
+ *
4
+ * `websearch` works with no configuration at all, but the keyless default is
5
+ * scraped DuckDuckGo HTML: it is rate-limited hard and can fail outright, and
6
+ * the failure surfaces as a bad search rather than as a setup problem. So when
7
+ * the tool is active and no keyed backend is configured, the session says so
8
+ * once — the same shape as the Anthropic extra-usage notice, including the
9
+ * `/settings` switch that turns it off.
10
+ */
11
+ import { resolveWebSearchCredentials } from "../../core/tools/webtools-shared.js";
12
+ export const WEBSEARCH_API_KEY_TITLE = "Web search has no API key";
13
+ /**
14
+ * The notice to show, or undefined when there is nothing to say: the tool is
15
+ * off, a keyed backend is configured, the user pinned the keyless backend on
16
+ * purpose, or the warning is switched off.
17
+ *
18
+ * Pure, so the decision is testable without a TUI; the caller owns the
19
+ * once-per-session latch.
20
+ */
21
+ export function websearchApiKeyNotice(input) {
22
+ if (input.warnings.websearchApiKey === false)
23
+ return undefined;
24
+ if (!input.activeToolNames.includes("websearch"))
25
+ return undefined;
26
+ const credentials = resolveWebSearchCredentials(input.search);
27
+ if (credentials.configured || credentials.explicitKeyless)
28
+ return undefined;
29
+ return {
30
+ title: WEBSEARCH_API_KEY_TITLE,
31
+ // Two lines, like the Anthropic notice: what is wrong and the one setting
32
+ // that fixes it. The other backends and the settings.json block are in
33
+ // the docs — a startup notice is not the place to list them.
34
+ body: [
35
+ "Searching keyless DuckDuckGo, which is rate-limited. Set BRAVE_API_KEY or TAVILY_API_KEY.",
36
+ "Turn off in /settings → Web search API key.",
37
+ ],
38
+ };
39
+ }
40
+ //# sourceMappingURL=websearch-warning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websearch-warning.js","sourceRoot":"","sources":["../../../src/modes/interactive/websearch-warning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,2BAA2B,EAA+B,MAAM,qCAAqC,CAAC;AAE/G,MAAM,CAAC,MAAM,uBAAuB,GAAG,2BAA2B,CAAC;AAgBnE;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAiC,EAAqC;IAC3G,IAAI,KAAK,CAAC,QAAQ,CAAC,eAAe,KAAK,KAAK;QAAE,OAAO,SAAS,CAAC;IAC/D,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,SAAS,CAAC;IAEnE,MAAM,WAAW,GAAG,2BAA2B,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9D,IAAI,WAAW,CAAC,UAAU,IAAI,WAAW,CAAC,eAAe;QAAE,OAAO,SAAS,CAAC;IAE5E,OAAO;QACN,KAAK,EAAE,uBAAuB;QAC9B,0EAA0E;QAC1E,uEAAuE;QACvE,+DAA6D;QAC7D,IAAI,EAAE;YACL,2FAA2F;YAC3F,+CAA6C;SAC7C;KACD,CAAC;AAAA,CACF","sourcesContent":["/**\n * The \"websearch has no API key\" startup notice.\n *\n * `websearch` works with no configuration at all, but the keyless default is\n * scraped DuckDuckGo HTML: it is rate-limited hard and can fail outright, and\n * the failure surfaces as a bad search rather than as a setup problem. So when\n * the tool is active and no keyed backend is configured, the session says so\n * once — the same shape as the Anthropic extra-usage notice, including the\n * `/settings` switch that turns it off.\n */\n\nimport type { WarningSettings } from \"../../core/settings-types.js\";\nimport { resolveWebSearchCredentials, type WebtoolsSearchSettings } from \"../../core/tools/webtools-shared.js\";\n\nexport const WEBSEARCH_API_KEY_TITLE = \"Web search has no API key\";\n\nexport interface WebSearchApiKeyNoticeInput {\n\t/** Tools the session actually exposes; the notice is pointless without `websearch`. */\n\tactiveToolNames: readonly string[];\n\t/** Warning switches from settings (`warnings.websearchApiKey`). */\n\twarnings: WarningSettings;\n\t/** The `webtools.search` block, as the binary would read it. */\n\tsearch?: WebtoolsSearchSettings;\n}\n\nexport interface WebSearchApiKeyNotice {\n\ttitle: string;\n\tbody: string[];\n}\n\n/**\n * The notice to show, or undefined when there is nothing to say: the tool is\n * off, a keyed backend is configured, the user pinned the keyless backend on\n * purpose, or the warning is switched off.\n *\n * Pure, so the decision is testable without a TUI; the caller owns the\n * once-per-session latch.\n */\nexport function websearchApiKeyNotice(input: WebSearchApiKeyNoticeInput): WebSearchApiKeyNotice | undefined {\n\tif (input.warnings.websearchApiKey === false) return undefined;\n\tif (!input.activeToolNames.includes(\"websearch\")) return undefined;\n\n\tconst credentials = resolveWebSearchCredentials(input.search);\n\tif (credentials.configured || credentials.explicitKeyless) return undefined;\n\n\treturn {\n\t\ttitle: WEBSEARCH_API_KEY_TITLE,\n\t\t// Two lines, like the Anthropic notice: what is wrong and the one setting\n\t\t// that fixes it. The other backends and the settings.json block are in\n\t\t// the docs — a startup notice is not the place to list them.\n\t\tbody: [\n\t\t\t\"Searching keyless DuckDuckGo, which is rate-limited. Set BRAVE_API_KEY or TAVILY_API_KEY.\",\n\t\t\t\"Turn off in /settings → Web search API key.\",\n\t\t],\n\t};\n}\n"]}
package/docs/settings.md CHANGED
@@ -74,15 +74,20 @@ Set `HOOCODE_SKIP_VERSION_CHECK=1` to disable the HooCode version update check.
74
74
  | Setting | Type | Default | Description |
75
75
  |---------|------|---------|-------------|
76
76
  | `warnings.anthropicExtraUsage` | boolean | `true` | Show a warning when Anthropic subscription auth may use paid extra usage |
77
+ | `warnings.websearchApiKey` | boolean | `true` | Show a warning when `websearch` is enabled with no search API key, so it falls back to keyless DuckDuckGo |
77
78
 
78
79
  ```json
79
80
  {
80
81
  "warnings": {
81
- "anthropicExtraUsage": false
82
+ "anthropicExtraUsage": false,
83
+ "websearchApiKey": false
82
84
  }
83
85
  }
84
86
  ```
85
87
 
88
+ Both warnings are shown once per session in the TUI and can also be toggled from
89
+ `/settings` → Warnings.
90
+
86
91
  ### Compaction
87
92
 
88
93
  | Setting | Type | Default | Description |
@@ -329,6 +334,7 @@ there.
329
334
  |---------|------|---------|-------------|
330
335
  | `enableWebTools` | boolean | `false` | Enable `webfetch` + `websearch` (network access). Needs the `webtools` binary. |
331
336
  | `webtools.timeoutSecs` | number | `15` | Per-request timeout in seconds, clamped 1–120. Wins over `HOOCODE_WEBTOOLS_TIMEOUT`. |
337
+ | `webtools.search` | object | — | Search backend and credentials, read by the `webtools` binary itself. See [Web search providers](#web-search-providers). |
332
338
  | `enableEmbsearchTools` | boolean | `true` | Build and fuse the semantic index into `search`. Set false to run `search` lexical-only. `grep`/`find` are unaffected. |
333
339
  | `embsearchBinaryPath` | string | — | Explicit path to the `embsearch` binary. Default: resolve from `PATH`. |
334
340
  | `embsearchThresholdBytes` | number | `0` | Minimum indexable source bytes before a repo is embedded. `0` indexes every repo. |
@@ -346,6 +352,66 @@ Environment variables:
346
352
  On Android/Termux the published Linux builds do not run; install with
347
353
  `pkg install <name>` instead.
348
354
 
355
+ #### Reading a long page
356
+
357
+ `webfetch` budgets its output in tokens (`maxTokens`, default 4000, hard cap
358
+ 25000). When a page runs past that, the result says so — the budget it stopped
359
+ at, and the ways past it — so a long document reads as a first page rather than
360
+ a dead end. The TUI marks the same fetch `~4000 tokens (truncated at 4000)`.
361
+
362
+ When the `webtools` binary reports paging offsets, the note names the offset to
363
+ continue at; pass it back as `offset` to read the next window. Windows tile the
364
+ document exactly, so a long page costs one budget per window rather than one
365
+ copy of the page per attempt. Against an older binary the note falls back to
366
+ advising a larger `maxTokens`.
367
+
368
+ Prefer a more specific URL or `#anchor` over paging a whole document: extraction
369
+ has already dropped nav and boilerplate, so the first few thousand tokens are
370
+ usually the article itself.
371
+
372
+ #### Web search providers
373
+
374
+ `websearch` needs no configuration: it defaults to keyless DuckDuckGo Lite.
375
+ That backend is scraped HTML, though — rate-limited hard, and it can fail
376
+ outright — so when search reliability matters, point it at a backend with an
377
+ actual API contract. With none configured, the TUI says so once per session
378
+ (see [`warnings.websearchApiKey`](#warnings)).
379
+
380
+ The `webtools` binary reads its own `webtools` key out of the user-level
381
+ `~/.hoocode/settings.json`, using its own (snake_case) key names. HooCode never
382
+ writes this block; it only reads it to tell whether a keyed backend exists. Put
383
+ it in the user-level file — a project `.hoocode/settings.json` is not read by the
384
+ binary, and a file holding credentials is worth keeping out of a working tree.
385
+
386
+ ```json
387
+ {
388
+ "webtools": {
389
+ "search": {
390
+ "provider": "brave",
391
+ "fallback": "duckduckgo",
392
+ "providers": {
393
+ "brave": { "api_key": "..." },
394
+ "tavily": { "api_key": "..." },
395
+ "searxng": { "base_url": "https://searx.internal" }
396
+ }
397
+ }
398
+ }
399
+ }
400
+ ```
401
+
402
+ Environment variables win over the file, so a key can stay out of it entirely:
403
+
404
+ | Variable | Effect |
405
+ |---|---|
406
+ | `WEBTOOLS_SEARCH_PROVIDER` | Backend to use: `duckduckgo` (default), `brave`, `tavily`, `searxng`. Pin `duckduckgo` to accept the keyless backend and silence the warning. |
407
+ | `WEBTOOLS_SEARCH_FALLBACK` | Backend tried when the primary fails; `none` disables the fallback. |
408
+ | `WEBTOOLS_BRAVE_API_KEY`, `BRAVE_API_KEY` | Brave Search key. |
409
+ | `WEBTOOLS_TAVILY_API_KEY`, `TAVILY_API_KEY` | Tavily key. Returns cleaned page content, so a search often answers without a follow-up `webfetch`. |
410
+ | `WEBTOOLS_SEARXNG_URL`, `WEBTOOLS_SEARXNG_API_KEY` | Self-hosted SearXNG endpoint (and optional key), for networks where the public APIs are unreachable. |
411
+
412
+ Every result records the backend that answered it, so a fallback to the scraped
413
+ backend is never silent.
414
+
349
415
  ### Resources
350
416
 
351
417
  These settings define where to load extensions, skills, prompts, and themes from.
@@ -408,7 +474,8 @@ See [packages.md](packages.md) for package management details.
408
474
  },
409
475
  "enabledModels": ["claude-*", "gpt-4o"],
410
476
  "warnings": {
411
- "anthropicExtraUsage": true
477
+ "anthropicExtraUsage": true,
478
+ "websearchApiKey": true
412
479
  },
413
480
  "packages": ["hoocode-skills"]
414
481
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kolisachint/hoocode-extension-custom-provider-anthropic",
3
3
  "private": true,
4
- "version": "0.3.42",
4
+ "version": "0.3.44",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "bun": ">=1.0.0"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kolisachint/hoocode-extension-custom-provider-gitlab-duo",
3
3
  "private": true,
4
- "version": "0.3.42",
4
+ "version": "0.3.44",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "bun": ">=1.0.0"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kolisachint/hoocode-extension-sandbox",
3
3
  "private": true,
4
- "version": "0.3.42",
4
+ "version": "0.3.44",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "bun": ">=1.0.0"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kolisachint/hoocode-extension-with-deps",
3
3
  "private": true,
4
- "version": "0.3.42",
4
+ "version": "0.3.44",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "bun": ">=1.0.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolisachint/hoocode-agent",
3
- "version": "0.5.42",
3
+ "version": "0.5.44",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "hoocodeConfig": {
@@ -50,9 +50,9 @@
50
50
  "prepublishOnly": "npm run clean && npm run build"
51
51
  },
52
52
  "dependencies": {
53
- "@kolisachint/hoocode-agent-core": "^0.5.42",
54
- "@kolisachint/hoocode-ai": "^0.5.42",
55
- "@kolisachint/hoocode-tui": "^0.5.42",
53
+ "@kolisachint/hoocode-agent-core": "^0.5.44",
54
+ "@kolisachint/hoocode-ai": "^0.5.44",
55
+ "@kolisachint/hoocode-tui": "^0.5.44",
56
56
  "@silvia-odwyer/photon-node": "^0.3.4",
57
57
  "chalk": "^5.5.0",
58
58
  "cli-highlight": "^2.1.11",