@kolisachint/hoocode-agent 0.4.102 → 0.4.104
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/CHANGELOG.md +20 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +1 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/keybindings.d.ts +5 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +4 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +2 -1
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +10 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +78 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/voice-transcribe.d.ts +33 -0
- package/dist/modes/interactive/voice-transcribe.d.ts.map +1 -0
- package/dist/modes/interactive/voice-transcribe.js +80 -0
- package/dist/modes/interactive/voice-transcribe.js.map +1 -0
- package/dist/utils/tools-manager.d.ts +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +23 -0
- package/dist/utils/tools-manager.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
|
@@ -60,6 +60,7 @@ import { TreeSelectorComponent } from "./components/tree-selector.js";
|
|
|
60
60
|
import { UserMessageComponent } from "./components/user-message.js";
|
|
61
61
|
import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
|
|
62
62
|
import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, initTheme, onThemeChange, setRegisteredThemes, setTheme, setThemeInstance, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
|
|
63
|
+
import { startVoiceTranscribe } from "./voice-transcribe.js";
|
|
63
64
|
function isExpandable(obj) {
|
|
64
65
|
return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
|
|
65
66
|
}
|
|
@@ -114,6 +115,9 @@ export class InteractiveMode {
|
|
|
114
115
|
defaultEditor;
|
|
115
116
|
editor;
|
|
116
117
|
editorComponentFactory;
|
|
118
|
+
voiceSession;
|
|
119
|
+
/** True while the voicetools binary is being resolved/downloaded before a session starts. */
|
|
120
|
+
voiceStarting = false;
|
|
117
121
|
autocompleteProvider;
|
|
118
122
|
autocompleteProviderWrappers = [];
|
|
119
123
|
fdPath;
|
|
@@ -2081,6 +2085,7 @@ export class InteractiveMode {
|
|
|
2081
2085
|
});
|
|
2082
2086
|
this.defaultEditor.onAction("app.team.focus", () => this.enterTeamFocus());
|
|
2083
2087
|
this.defaultEditor.onAction("app.editor.external", () => this.openExternalEditor());
|
|
2088
|
+
this.defaultEditor.onAction("app.input.voiceTranscribe", () => this.toggleVoiceTranscribe());
|
|
2084
2089
|
this.defaultEditor.onAction("app.message.followUp", () => this.handleFollowUp());
|
|
2085
2090
|
this.defaultEditor.onAction("app.message.dequeue", () => this.handleDequeue());
|
|
2086
2091
|
this.defaultEditor.onAction("app.session.new", () => this.commandExecutor.handleClear());
|
|
@@ -2756,6 +2761,74 @@ export class InteractiveMode {
|
|
|
2756
2761
|
* If multiple status messages are emitted back-to-back (without anything else being added to the chat),
|
|
2757
2762
|
* we update the previous status line instead of appending new ones to avoid log spam.
|
|
2758
2763
|
*/
|
|
2764
|
+
/**
|
|
2765
|
+
* Toggle voice-to-text capture. First press spawns `voicetools`, streams
|
|
2766
|
+
* decoded segments into the editor via bracketed paste, and reports state
|
|
2767
|
+
* through the status line. Pressing the shortcut again stops early.
|
|
2768
|
+
*/
|
|
2769
|
+
toggleVoiceTranscribe() {
|
|
2770
|
+
if (this.voiceSession?.running || this.voiceStarting) {
|
|
2771
|
+
this.voiceSession?.stop();
|
|
2772
|
+
this.voiceSession = undefined;
|
|
2773
|
+
this.voiceStarting = false;
|
|
2774
|
+
this.showStatus("Voice input cancelled");
|
|
2775
|
+
return;
|
|
2776
|
+
}
|
|
2777
|
+
const statusLabels = {
|
|
2778
|
+
recording: "Recording... speak now (press again to cancel)",
|
|
2779
|
+
transcribing: "Transcribing...",
|
|
2780
|
+
done: "Voice input done",
|
|
2781
|
+
};
|
|
2782
|
+
// Resolve the binary the same way as the other managed tools (webtools etc.):
|
|
2783
|
+
// an explicit VOICETOOLS_BIN wins, otherwise resolve from bin/PATH and download
|
|
2784
|
+
// from the published release on demand. This runs async, so guard re-entry with
|
|
2785
|
+
// `voiceStarting` and let a second press before it resolves cancel the start.
|
|
2786
|
+
this.voiceStarting = true;
|
|
2787
|
+
this.showStatus("Preparing voice input...");
|
|
2788
|
+
void this.resolveVoiceBin()
|
|
2789
|
+
.then((bin) => {
|
|
2790
|
+
// A second key press while resolving cleared the flag: honour the cancel.
|
|
2791
|
+
if (!this.voiceStarting)
|
|
2792
|
+
return;
|
|
2793
|
+
this.voiceStarting = false;
|
|
2794
|
+
if (!bin) {
|
|
2795
|
+
this.showError("Voice input failed: voicetools binary unavailable and could not be downloaded. " +
|
|
2796
|
+
"Install it, set VOICETOOLS_BIN, or ensure a published release exists for this platform.");
|
|
2797
|
+
return;
|
|
2798
|
+
}
|
|
2799
|
+
this.voiceSession = startVoiceTranscribe(bin, {
|
|
2800
|
+
onStatus: (status) => {
|
|
2801
|
+
this.showStatus(statusLabels[status] ?? status);
|
|
2802
|
+
if (status === "done") {
|
|
2803
|
+
this.voiceSession = undefined;
|
|
2804
|
+
}
|
|
2805
|
+
},
|
|
2806
|
+
onSegment: (text) => {
|
|
2807
|
+
// Inject via bracketed paste so the editor treats it as pasted text.
|
|
2808
|
+
this.editor.handleInput(`\x1b[200~${text} \x1b[201~`);
|
|
2809
|
+
},
|
|
2810
|
+
onError: (message) => {
|
|
2811
|
+
this.voiceSession = undefined;
|
|
2812
|
+
this.showError(`Voice input failed: ${message}`);
|
|
2813
|
+
},
|
|
2814
|
+
});
|
|
2815
|
+
})
|
|
2816
|
+
.catch((err) => {
|
|
2817
|
+
this.voiceStarting = false;
|
|
2818
|
+
this.showError(`Voice input failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2819
|
+
});
|
|
2820
|
+
}
|
|
2821
|
+
/**
|
|
2822
|
+
* Resolve the `voicetools` binary path. Prefers an explicit VOICETOOLS_BIN
|
|
2823
|
+
* override, otherwise resolves via the managed tools manager (bin dir / PATH /
|
|
2824
|
+
* download from the published release). Returns undefined when unavailable.
|
|
2825
|
+
*/
|
|
2826
|
+
async resolveVoiceBin() {
|
|
2827
|
+
const override = process.env.VOICETOOLS_BIN?.trim();
|
|
2828
|
+
if (override)
|
|
2829
|
+
return override;
|
|
2830
|
+
return ensureTool("voicetools", true);
|
|
2831
|
+
}
|
|
2759
2832
|
showStatus(message) {
|
|
2760
2833
|
const children = this.chatContainer.children;
|
|
2761
2834
|
const last = children.length > 0 ? children[children.length - 1] : undefined;
|
|
@@ -4430,6 +4503,11 @@ export class InteractiveMode {
|
|
|
4430
4503
|
}
|
|
4431
4504
|
stop() {
|
|
4432
4505
|
this.unregisterSignalHandlers();
|
|
4506
|
+
if (this.voiceSession?.running) {
|
|
4507
|
+
this.voiceSession.stop();
|
|
4508
|
+
this.voiceSession = undefined;
|
|
4509
|
+
}
|
|
4510
|
+
this.voiceStarting = false;
|
|
4433
4511
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
4434
4512
|
this.ui.terminal.setProgress(false);
|
|
4435
4513
|
}
|