@kolisachint/hoocode-agent 0.4.152 → 0.4.154

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 (62) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/core/agent-session.d.ts.map +1 -1
  3. package/dist/core/agent-session.js +3 -0
  4. package/dist/core/agent-session.js.map +1 -1
  5. package/dist/core/embsearch/embsearch-progress.d.ts +33 -0
  6. package/dist/core/embsearch/embsearch-progress.d.ts.map +1 -0
  7. package/dist/core/embsearch/embsearch-progress.js +86 -0
  8. package/dist/core/embsearch/embsearch-progress.js.map +1 -0
  9. package/dist/core/embsearch/embsearch-service.d.ts +4 -0
  10. package/dist/core/embsearch/embsearch-service.d.ts.map +1 -1
  11. package/dist/core/embsearch/embsearch-service.js +6 -1
  12. package/dist/core/embsearch/embsearch-service.js.map +1 -1
  13. package/dist/core/settings-defaults.d.ts +6 -0
  14. package/dist/core/settings-defaults.d.ts.map +1 -1
  15. package/dist/core/settings-defaults.js +6 -0
  16. package/dist/core/settings-defaults.js.map +1 -1
  17. package/dist/core/settings-manager.d.ts +12 -1
  18. package/dist/core/settings-manager.d.ts.map +1 -1
  19. package/dist/core/settings-manager.js +44 -0
  20. package/dist/core/settings-manager.js.map +1 -1
  21. package/dist/core/settings-types.d.ts +8 -0
  22. package/dist/core/settings-types.d.ts.map +1 -1
  23. package/dist/core/settings-types.js.map +1 -1
  24. package/dist/core/startup-progress.d.ts +48 -0
  25. package/dist/core/startup-progress.d.ts.map +1 -0
  26. package/dist/core/startup-progress.js +50 -0
  27. package/dist/core/startup-progress.js.map +1 -0
  28. package/dist/core/tools/webfetch.d.ts +2 -0
  29. package/dist/core/tools/webfetch.d.ts.map +1 -1
  30. package/dist/core/tools/webfetch.js +5 -4
  31. package/dist/core/tools/webfetch.js.map +1 -1
  32. package/dist/core/tools/websearch.d.ts +2 -0
  33. package/dist/core/tools/websearch.d.ts.map +1 -1
  34. package/dist/core/tools/websearch.js +5 -4
  35. package/dist/core/tools/websearch.js.map +1 -1
  36. package/dist/core/tools/webtools-shared.d.ts +9 -0
  37. package/dist/core/tools/webtools-shared.d.ts.map +1 -1
  38. package/dist/core/tools/webtools-shared.js +28 -0
  39. package/dist/core/tools/webtools-shared.js.map +1 -1
  40. package/dist/main.d.ts.map +1 -1
  41. package/dist/main.js +4 -48
  42. package/dist/main.js.map +1 -1
  43. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  44. package/dist/modes/interactive/components/footer.js +44 -0
  45. package/dist/modes/interactive/components/footer.js.map +1 -1
  46. package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
  47. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  48. package/dist/modes/interactive/components/settings-selector.js +27 -1
  49. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  50. package/dist/modes/interactive/interactive-mode.d.ts +3 -0
  51. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  52. package/dist/modes/interactive/interactive-mode.js +65 -5
  53. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  54. package/dist/modes/interactive/voice/voice-controller.d.ts +18 -0
  55. package/dist/modes/interactive/voice/voice-controller.d.ts.map +1 -1
  56. package/dist/modes/interactive/voice/voice-controller.js +16 -10
  57. package/dist/modes/interactive/voice/voice-controller.js.map +1 -1
  58. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  59. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  60. package/examples/extensions/sandbox/package.json +1 -1
  61. package/examples/extensions/with-deps/package.json +1 -1
  62. package/package.json +4 -4
@@ -16,6 +16,7 @@ import { KeybindingsManager } from "../../core/keybindings.js";
16
16
  import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
17
17
  import { SessionManager } from "../../core/session-manager.js";
18
18
  import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
19
+ import { startupProgress } from "../../core/startup-progress.js";
19
20
  import { taskStore } from "../../core/task-store.js";
20
21
  import { buildCompactWordmark } from "../../core/wordmark.js";
21
22
  import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
@@ -56,6 +57,22 @@ import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMar
56
57
  import { VoiceController } from "./voice/voice-controller.js";
57
58
  /** Interface for components that can be expanded/collapsed */
58
59
  const DEAD_TERMINAL_ERROR_CODES = new Set(["EIO", "EPIPE", "ENOTCONN"]);
60
+ /**
61
+ * Resolve the effective voice trailing-silence window (ms): env
62
+ * `VOICETOOLS_SILENCE_MS` wins (like `VOICETOOLS_BIN`), otherwise the settings
63
+ * value. Both paths are clamped to 300-10000; a malformed env value falls back to
64
+ * the settings value.
65
+ */
66
+ function resolveVoiceSilenceMs(settingsManager) {
67
+ const envRaw = process.env.VOICETOOLS_SILENCE_MS?.trim();
68
+ if (envRaw) {
69
+ const envValue = Number(envRaw);
70
+ if (Number.isFinite(envValue) && envValue > 0) {
71
+ return Math.min(10000, Math.max(300, Math.floor(envValue)));
72
+ }
73
+ }
74
+ return settingsManager.getVoiceSilenceMs();
75
+ }
59
76
  function isDeadTerminalError(error) {
60
77
  if (!error || typeof error !== "object" || !("code" in error)) {
61
78
  return false;
@@ -165,6 +182,8 @@ export class InteractiveMode {
165
182
  unsubscribe;
166
183
  // Task store subscription unsubscribe function (task panel)
167
184
  taskStoreUnsubscribe;
185
+ // Startup-progress subscription unsubscribe function (footer download/index bars)
186
+ startupProgressUnsubscribe;
168
187
  signalCleanupHandlers = [];
169
188
  // Track if editor is in bash mode (text starts with !)
170
189
  isBashMode = false;
@@ -352,6 +371,7 @@ export class InteractiveMode {
352
371
  statusContainer: this.statusContainer,
353
372
  sendEditorInput: (data) => this.editor.handleInput(data),
354
373
  showError: (message) => this.showError(message),
374
+ silenceMs: resolveVoiceSilenceMs(this.settingsManager),
355
375
  });
356
376
  const self = this;
357
377
  this.bashExecution = new BashExecutionController({
@@ -556,6 +576,10 @@ export class InteractiveMode {
556
576
  }
557
577
  this.chatContainer.addChild(new DynamicBorder());
558
578
  }
579
+ /** Feed a first-run tool-binary download into the footer's startup-progress line. */
580
+ reportToolDownload(key, label, receivedBytes, totalBytes) {
581
+ startupProgress.set({ key, kind: "download", label, receivedBytes, totalBytes });
582
+ }
559
583
  async init() {
560
584
  if (this.isInitialized)
561
585
  return;
@@ -569,18 +593,30 @@ export class InteractiveMode {
569
593
  // Both help — fd for autocomplete, rg for the grep tool — but neither is required
570
594
  // to start: resolving them can hit a slow or failing network in restricted
571
595
  // environments, and awaiting here froze first paint. Resolve in the background
572
- // (silently, so download notices never corrupt the TUI) and wire fd in when ready;
573
- // the grep/find tools resolve rg/fd on demand with a native fallback regardless.
596
+ // (never awaited, so a first-run download never blocks first paint) and wire fd
597
+ // in when ready; the grep/find tools resolve rg/fd on demand with a native
598
+ // fallback regardless. embsearch is intentionally NOT preloaded here: when the
599
+ // semantic index is enabled, EmbsearchService (main.ts) owns its download and
600
+ // build, reporting through the same startupProgress channel — preloading it too
601
+ // would fetch the binary twice and race.
602
+ //
603
+ // First-run download progress streams into the footer's startupProgress line
604
+ // via ensureTool's byte-count callback; the line clears when the download
605
+ // settles (path resolved) or is dropped if it fails.
574
606
  void Promise.all([
575
- ensureTool("fd", true),
576
- ensureTool("rg", true),
577
- this.settingsManager.getEnableEmbsearchTools() ? ensureTool("embsearch", true) : Promise.resolve(null),
607
+ ensureTool("fd", true, (received, total) => this.reportToolDownload("fd", "fd", received, total)),
608
+ ensureTool("rg", true, (received, total) => this.reportToolDownload("rg", "ripgrep", received, total)),
578
609
  ])
579
610
  .then(([fdPath]) => {
580
611
  this.fdPath = fdPath;
581
612
  })
582
613
  .catch(() => {
583
614
  // Non-fatal: autocomplete simply stays disabled until/unless fd resolves.
615
+ })
616
+ .finally(() => {
617
+ // Downloads settled (resolved or failed): drop any lingering bars.
618
+ startupProgress.remove("fd");
619
+ startupProgress.remove("rg");
584
620
  });
585
621
  // Add header container as first child
586
622
  this.ui.addChild(this.headerContainer);
@@ -669,6 +705,12 @@ export class InteractiveMode {
669
705
  this.taskStoreUnsubscribe = taskStore.subscribe(throttled(TASK_RENDER_THROTTLE_MS, () => {
670
706
  this.ui.requestRender();
671
707
  }));
708
+ // Re-render the footer as startup progress updates (tool downloads stream
709
+ // byte counts in bursts, the index build ticks per batch). Throttled like the
710
+ // task panel so a fast download doesn't drive a render per chunk.
711
+ this.startupProgressUnsubscribe = startupProgress.subscribe(throttled(TASK_RENDER_THROTTLE_MS, () => {
712
+ this.ui.requestRender();
713
+ }));
672
714
  // Initialize available provider count for footer display
673
715
  await this.modelController.updateAvailableProviderCount();
674
716
  }
@@ -1650,6 +1692,10 @@ export class InteractiveMode {
1650
1692
  // glanceable for the whole turn. Active tasks are kept: a follow-up/steer
1651
1693
  // message can arrive while a subagent is still running.
1652
1694
  taskStore.reset();
1695
+ // Startup progress is transient startup status: once the user starts a
1696
+ // turn, drop any lingering bars/notices (e.g. an unavailable-index line)
1697
+ // so they don't sit in the footer for the rest of the session.
1698
+ startupProgress.clear();
1653
1699
  this.chimeTurnAborted = false;
1654
1700
  this.addMessageToChat(event.message);
1655
1701
  this.messageQueue.updatePendingMessagesDisplay();
@@ -2132,6 +2178,7 @@ export class InteractiveMode {
2132
2178
  // This prevents escape sequences from leaking to the parent shell over slow SSH.
2133
2179
  await this.ui.terminal.drainInput(1000);
2134
2180
  this.taskStoreUnsubscribe?.();
2181
+ this.startupProgressUnsubscribe?.();
2135
2182
  this.teamFocus.closeAttach();
2136
2183
  this.taskPanel.dispose();
2137
2184
  this.stop();
@@ -2501,6 +2548,10 @@ export class InteractiveMode {
2501
2548
  clearOnShrink: this.settingsManager.getClearOnShrink(),
2502
2549
  showTerminalProgress: this.settingsManager.getShowTerminalProgress(),
2503
2550
  warnings: this.settingsManager.getWarnings(),
2551
+ // Show the effective value: env VOICETOOLS_SILENCE_MS wins for voice;
2552
+ // getWebtoolsTimeoutSecs already folds in HOOCODE_WEBTOOLS_TIMEOUT.
2553
+ voiceSilenceMs: resolveVoiceSilenceMs(this.settingsManager),
2554
+ webtoolsTimeoutSecs: this.settingsManager.getWebtoolsTimeoutSecs(),
2504
2555
  }, {
2505
2556
  onAutoCompactChange: (enabled) => {
2506
2557
  this.session.setAutoCompactionEnabled(enabled);
@@ -2684,6 +2735,15 @@ export class InteractiveMode {
2684
2735
  onWarningsChange: (warnings) => {
2685
2736
  this.settingsManager.setWarnings(warnings);
2686
2737
  },
2738
+ onVoiceSilenceMsChange: (ms) => {
2739
+ this.settingsManager.setVoiceSilenceMs(ms);
2740
+ // Env override still wins; re-resolve so the live value stays consistent.
2741
+ this.voice.setSilenceMs(resolveVoiceSilenceMs(this.settingsManager));
2742
+ },
2743
+ onWebtoolsTimeoutSecsChange: (secs) => {
2744
+ // Persisted; webfetch/websearch pick it up when tools rebuild next session.
2745
+ this.settingsManager.setWebtoolsTimeoutSecs(secs);
2746
+ },
2687
2747
  onCancel: () => {
2688
2748
  done();
2689
2749
  this.ui.requestRender();