@kolisachint/hoocode-agent 0.5.57 → 0.5.58
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 +163 -0
- package/dist/core/agent-session.d.ts +2 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +4 -3
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +4 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/keybindings.d.ts +162 -98
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +222 -106
- package/dist/core/keybindings.js.map +1 -1
- package/dist/modes/interactive/command-executor.d.ts.map +1 -1
- package/dist/modes/interactive/command-executor.js +95 -62
- package/dist/modes/interactive/command-executor.js.map +1 -1
- package/dist/modes/interactive/components/ask-options.d.ts +20 -6
- package/dist/modes/interactive/components/ask-options.d.ts.map +1 -1
- package/dist/modes/interactive/components/ask-options.js +35 -13
- package/dist/modes/interactive/components/ask-options.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts +9 -0
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +12 -0
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/task-panel.d.ts +2 -2
- package/dist/modes/interactive/components/task-panel.d.ts.map +1 -1
- package/dist/modes/interactive/components/task-panel.js +24 -11
- package/dist/modes/interactive/components/task-panel.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +29 -12
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +17 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +85 -31
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/model-controller.d.ts +3 -0
- package/dist/modes/interactive/model-controller.d.ts.map +1 -1
- package/dist/modes/interactive/model-controller.js +1 -1
- package/dist/modes/interactive/model-controller.js.map +1 -1
- package/docs/keybindings.md +247 -80
- package/docs/terminal-setup.md +8 -3
- 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
|
@@ -51,7 +51,7 @@ import { CustomEditor } from "./components/custom-editor.js";
|
|
|
51
51
|
import { CustomMessageComponent } from "./components/custom-message.js";
|
|
52
52
|
import { DynamicBorder } from "./components/dynamic-border.js";
|
|
53
53
|
import { FooterComponent } from "./components/footer.js";
|
|
54
|
-
import { keyHint, keyText, rawKeyHint } from "./components/keybinding-hints.js";
|
|
54
|
+
import { appKeyLabel, keyHint, keyText, rawKeyHint } from "./components/keybinding-hints.js";
|
|
55
55
|
import { renderSessionChip } from "./components/session-chip.js";
|
|
56
56
|
import { SessionColorSelectorComponent } from "./components/session-color-selector.js";
|
|
57
57
|
import { SessionSelectorComponent } from "./components/session-selector.js";
|
|
@@ -185,6 +185,8 @@ export class InteractiveMode {
|
|
|
185
185
|
startupNoticesShown = false;
|
|
186
186
|
// Status line tracking (for mutating immediately-sequential status updates)
|
|
187
187
|
lastStatusSpacer = undefined;
|
|
188
|
+
/** Dial reverses already named this session; see showDialStep. */
|
|
189
|
+
dialReverseTaught = new Set();
|
|
188
190
|
lastStatusText = undefined;
|
|
189
191
|
// Streaming message tracking
|
|
190
192
|
streamingComponent = undefined;
|
|
@@ -461,6 +463,7 @@ export class InteractiveMode {
|
|
|
461
463
|
},
|
|
462
464
|
showSelector: (create) => this.showSelector(create),
|
|
463
465
|
showStatus: (message) => this.showStatus(message),
|
|
466
|
+
showDialStep: (backward, message) => this.showDialStep(backward, message),
|
|
464
467
|
showError: (message) => this.showError(message),
|
|
465
468
|
showWarning: (message) => this.showWarning(message),
|
|
466
469
|
showNotice: (title, body) => this.showNotice(title, body),
|
|
@@ -709,33 +712,53 @@ export class InteractiveMode {
|
|
|
709
712
|
: theme.bold(theme.fg("accent", APP_NAME)) + theme.fg("dim", ` v${this.version}`);
|
|
710
713
|
// Build startup instructions using keybinding hint helpers
|
|
711
714
|
const hint = (keybinding, description) => keyHint(keybinding, description);
|
|
715
|
+
// A dial as one line in one shape: the key steps it forward, the same
|
|
716
|
+
// key with shift steps it back. The banner is where that rule is first
|
|
717
|
+
// read, and it is the rule covering the most-pressed keys in the app,
|
|
718
|
+
// so the dials are listed together rather than scattered by topic.
|
|
719
|
+
// appKeyLabel, not keyText: the thinking dial answers to shift+tab as well,
|
|
720
|
+
// and splicing that into the middle of `alt+t/shift+alt+t` would hide the
|
|
721
|
+
// one shape these six lines exist to show.
|
|
722
|
+
const dial = (forward, backward, subject) => rawKeyHint(`${appKeyLabel(forward)}/${appKeyLabel(backward)}`, `to step ${subject}`);
|
|
723
|
+
// Grouped the way the map itself is (see core/keybindings.ts): by what you
|
|
724
|
+
// are trying to do, not by what the widget is. A flat list of thirty
|
|
725
|
+
// hints is a wall nobody reads; five short groups with a heading each is
|
|
726
|
+
// something a person can skim once and place a key in later.
|
|
727
|
+
const group = (title) => theme.fg("dim", `\n${title}`);
|
|
712
728
|
const expandedInstructions = [
|
|
729
|
+
group("Compose — the message in your hands"),
|
|
730
|
+
hint("app.editor.external", "for external editor"),
|
|
731
|
+
hint("app.input.voiceTranscribe", "to speak instead of type"),
|
|
732
|
+
hint("app.clipboard.pasteImage", "to paste image"),
|
|
733
|
+
hint("app.message.followUp", "to queue follow-up"),
|
|
734
|
+
hint("app.message.dequeue", "to edit all queued messages"),
|
|
735
|
+
rawKeyHint("drop files", "to attach"),
|
|
736
|
+
rawKeyHint("/", "for commands"),
|
|
737
|
+
rawKeyHint("!", "to run bash"),
|
|
738
|
+
rawKeyHint("!!", "to run bash (no context)"),
|
|
739
|
+
group("Steer — what the agent is before it runs"),
|
|
740
|
+
dial("app.mode.cycleForward", "app.mode.cycleBackward", "agent mode (ask/plan/build/debug)"),
|
|
741
|
+
dial("app.model.cycleForward", "app.model.cycleBackward", "model — /model to pick one"),
|
|
742
|
+
dial("app.thinking.cycleForward", "app.thinking.cycleBackward", "thinking level"),
|
|
743
|
+
group("Read — what you see of what it did"),
|
|
744
|
+
dial("app.view.cycleForward", "app.view.cycleBackward", "tool output (radar/peek/full)"),
|
|
745
|
+
dial("app.tasks.cycleForward", "app.tasks.cycleBackward", "task panel view"),
|
|
746
|
+
hint("app.tools.expand", "to jump to full output and back"),
|
|
747
|
+
hint("app.thinking.toggle", "to show or hide thinking"),
|
|
748
|
+
...(this.teamFocus.connected ? [hint("app.team.focus", "to focus team roster")] : []),
|
|
749
|
+
group("Go — sessions and places"),
|
|
750
|
+
hint("app.session.resume", "to resume a session"),
|
|
751
|
+
hint("app.session.changeDirectory", "to change working directory"),
|
|
752
|
+
dial("app.session.color.cycleForward", "app.session.color.cycleBackward", "session colour"),
|
|
753
|
+
hint("app.settings.open", "for settings"),
|
|
754
|
+
hint("app.hotkeys.open", "for all shortcuts"),
|
|
755
|
+
group("Flow — getting out, getting back"),
|
|
713
756
|
hint("app.interrupt", "to interrupt"),
|
|
714
757
|
hint("app.clear", "to clear"),
|
|
715
758
|
rawKeyHint(`${keyText("app.clear")} twice`, "to exit"),
|
|
716
759
|
hint("app.exit", "to exit (empty)"),
|
|
717
760
|
hint("app.suspend", "to suspend"),
|
|
718
761
|
keyHint("tui.editor.deleteToLineEnd", "to delete to end"),
|
|
719
|
-
hint("app.thinking.cycle", "to cycle thinking level"),
|
|
720
|
-
rawKeyHint(`${keyText("app.model.cycleForward")}/${keyText("app.model.cycleBackward")}`, "to cycle models"),
|
|
721
|
-
hint("app.model.select", "to select model"),
|
|
722
|
-
hint("app.tools.expand", "to jump to full output and back"),
|
|
723
|
-
hint("app.view.cycleForward", "to cycle tool output (radar/peek/full)"),
|
|
724
|
-
hint("app.thinking.toggle", "to expand thinking"),
|
|
725
|
-
hint("app.tasks.cycleView", "to cycle task panel view"),
|
|
726
|
-
...(this.teamFocus.connected ? [hint("app.team.focus", "to focus team roster")] : []),
|
|
727
|
-
hint("app.mode.cycle", "to cycle agent mode"),
|
|
728
|
-
hint("app.session.changeDirectory", "to change working directory"),
|
|
729
|
-
hint("app.settings.open", "for settings"),
|
|
730
|
-
hint("app.hotkeys.open", "for all shortcuts"),
|
|
731
|
-
hint("app.editor.external", "for external editor"),
|
|
732
|
-
rawKeyHint("/", "for commands"),
|
|
733
|
-
rawKeyHint("!", "to run bash"),
|
|
734
|
-
rawKeyHint("!!", "to run bash (no context)"),
|
|
735
|
-
hint("app.message.followUp", "to queue follow-up"),
|
|
736
|
-
hint("app.message.dequeue", "to edit all queued messages"),
|
|
737
|
-
hint("app.clipboard.pasteImage", "to paste image"),
|
|
738
|
-
rawKeyHint("drop files", "to attach"),
|
|
739
762
|
].join("\n");
|
|
740
763
|
const onboarding = theme.fg("dim", `${APP_NAME} can explain its own features and look up its docs. Ask it how to use or extend ${APP_NAME}.`);
|
|
741
764
|
this.builtInHeader = new ExpandableText(() => logo(), () => `${logo()}\n${expandedInstructions}\n\n${onboarding}`, this.getStartupExpansionState(), 1, 0);
|
|
@@ -1510,7 +1533,8 @@ export class InteractiveMode {
|
|
|
1510
1533
|
this.defaultEditor.onAction("app.clear", () => this.handleCtrlC());
|
|
1511
1534
|
this.defaultEditor.onCtrlD = () => this.handleCtrlD();
|
|
1512
1535
|
this.defaultEditor.onAction("app.suspend", () => this.handleCtrlZ());
|
|
1513
|
-
this.defaultEditor.onAction("app.thinking.
|
|
1536
|
+
this.defaultEditor.onAction("app.thinking.cycleForward", () => this.cycleThinkingLevel("forward"));
|
|
1537
|
+
this.defaultEditor.onAction("app.thinking.cycleBackward", () => this.cycleThinkingLevel("backward"));
|
|
1514
1538
|
this.defaultEditor.onAction("app.model.cycleForward", () => this.modelController.cycleModel("forward"));
|
|
1515
1539
|
this.defaultEditor.onAction("app.model.cycleBackward", () => this.modelController.cycleModel("backward"));
|
|
1516
1540
|
// Global debug handler on TUI (works regardless of focus)
|
|
@@ -1520,8 +1544,11 @@ export class InteractiveMode {
|
|
|
1520
1544
|
this.defaultEditor.onAction("app.view.cycleForward", () => this.cycleToolOutputView("forward"));
|
|
1521
1545
|
this.defaultEditor.onAction("app.view.cycleBackward", () => this.cycleToolOutputView("backward"));
|
|
1522
1546
|
this.defaultEditor.onAction("app.thinking.toggle", () => this.toggleThinkingBlockVisibility());
|
|
1523
|
-
this.defaultEditor.onAction("app.tasks.
|
|
1524
|
-
this.taskPanel.cycleView();
|
|
1547
|
+
this.defaultEditor.onAction("app.tasks.cycleForward", () => {
|
|
1548
|
+
this.taskPanel.cycleView("forward");
|
|
1549
|
+
});
|
|
1550
|
+
this.defaultEditor.onAction("app.tasks.cycleBackward", () => {
|
|
1551
|
+
this.taskPanel.cycleView("backward");
|
|
1525
1552
|
});
|
|
1526
1553
|
this.defaultEditor.onAction("app.team.focus", () => this.teamFocus.enterFocus());
|
|
1527
1554
|
this.defaultEditor.onAction("app.editor.external", () => this.openExternalEditor());
|
|
@@ -1542,7 +1569,8 @@ export class InteractiveMode {
|
|
|
1542
1569
|
this.defaultEditor.onAction("app.session.color.cycleBackward", () => this.cycleSessionColor("backward"));
|
|
1543
1570
|
this.defaultEditor.onAction("app.settings.open", () => this.showSettingsSelector());
|
|
1544
1571
|
this.defaultEditor.onAction("app.hotkeys.open", () => this.commandExecutor.handleHotkeys());
|
|
1545
|
-
this.defaultEditor.onAction("app.mode.
|
|
1572
|
+
this.defaultEditor.onAction("app.mode.cycleForward", () => void this.cycleAgentMode("forward"));
|
|
1573
|
+
this.defaultEditor.onAction("app.mode.cycleBackward", () => void this.cycleAgentMode("backward"));
|
|
1546
1574
|
this.defaultEditor.onChange = (text) => {
|
|
1547
1575
|
const wasBashMode = this.isBashMode;
|
|
1548
1576
|
this.isBashMode = text.trimStart().startsWith("!");
|
|
@@ -2267,6 +2295,28 @@ export class InteractiveMode {
|
|
|
2267
2295
|
* If multiple status messages are emitted back-to-back (without anything else being added to the chat),
|
|
2268
2296
|
* we update the previous status line instead of appending new ones to avoid log spam.
|
|
2269
2297
|
*/
|
|
2298
|
+
/**
|
|
2299
|
+
* Report a dial step, and name the key that steps it back — once.
|
|
2300
|
+
*
|
|
2301
|
+
* The instant after someone moves a dial is the one moment they are primed to
|
|
2302
|
+
* learn its other half: they have just used one direction and can feel the
|
|
2303
|
+
* missing one. So the reverse rides along with the first step of each dial in
|
|
2304
|
+
* a session and never again. A hint that repeats forever stops being read,
|
|
2305
|
+
* and its cost falls entirely on the people who already know it.
|
|
2306
|
+
*
|
|
2307
|
+
* Only the three dials that announce their new value in the transcript come
|
|
2308
|
+
* through here. The other three announce themselves where they live — the
|
|
2309
|
+
* task panel prints its own key in its header, and the mode chip and view
|
|
2310
|
+
* glyph change in place in the footer.
|
|
2311
|
+
*/
|
|
2312
|
+
showDialStep(backward, message) {
|
|
2313
|
+
if (this.dialReverseTaught.has(backward)) {
|
|
2314
|
+
this.showStatus(message);
|
|
2315
|
+
return;
|
|
2316
|
+
}
|
|
2317
|
+
this.dialReverseTaught.add(backward);
|
|
2318
|
+
this.showStatus(theme.fg("dim", message) + theme.fg("halftone", ` ${keyText(backward)} steps back`));
|
|
2319
|
+
}
|
|
2270
2320
|
showStatus(message) {
|
|
2271
2321
|
const children = this.chatContainer.children;
|
|
2272
2322
|
const last = children.length > 0 ? children[children.length - 1] : undefined;
|
|
@@ -2650,15 +2700,15 @@ export class InteractiveMode {
|
|
|
2650
2700
|
}
|
|
2651
2701
|
this.ui.requestRender();
|
|
2652
2702
|
}
|
|
2653
|
-
cycleThinkingLevel() {
|
|
2654
|
-
const newLevel = this.session.cycleThinkingLevel();
|
|
2703
|
+
cycleThinkingLevel(direction) {
|
|
2704
|
+
const newLevel = this.session.cycleThinkingLevel(direction);
|
|
2655
2705
|
if (newLevel === undefined) {
|
|
2656
2706
|
this.showStatus("Current model does not support thinking");
|
|
2657
2707
|
}
|
|
2658
2708
|
else {
|
|
2659
2709
|
this.footer.invalidate();
|
|
2660
2710
|
this.updateEditorBorderColor();
|
|
2661
|
-
this.
|
|
2711
|
+
this.showDialStep("app.thinking.cycleBackward", `Thinking level: ${newLevel}`);
|
|
2662
2712
|
}
|
|
2663
2713
|
}
|
|
2664
2714
|
/**
|
|
@@ -2834,7 +2884,7 @@ export class InteractiveMode {
|
|
|
2834
2884
|
* is missing (a `--light` run strips the extension), the key says so instead
|
|
2835
2885
|
* of guessing.
|
|
2836
2886
|
*/
|
|
2837
|
-
async cycleAgentMode() {
|
|
2887
|
+
async cycleAgentMode(direction) {
|
|
2838
2888
|
const command = this.session.extensionRunner.getCommand("mode");
|
|
2839
2889
|
if (!command) {
|
|
2840
2890
|
this.showWarning("Modes are not available in this session");
|
|
@@ -2847,8 +2897,12 @@ export class InteractiveMode {
|
|
|
2847
2897
|
return;
|
|
2848
2898
|
}
|
|
2849
2899
|
const current = this.footerDataProvider.getActiveMode();
|
|
2900
|
+
// indexOf is -1 when the active mode is not in the list; stepping from
|
|
2901
|
+
// there lands on the first mode going forward and the last going back,
|
|
2902
|
+
// which is the useful answer either way.
|
|
2850
2903
|
const index = modes.indexOf(current);
|
|
2851
|
-
const
|
|
2904
|
+
const step = direction === "forward" ? 1 : -1;
|
|
2905
|
+
const next = modes[(index + step + modes.length) % modes.length];
|
|
2852
2906
|
await this.session.prompt(`/mode ${next}`);
|
|
2853
2907
|
}
|
|
2854
2908
|
/**
|
|
@@ -2865,7 +2919,7 @@ export class InteractiveMode {
|
|
|
2865
2919
|
const slot = cycleSessionColorSlot(this.sessionManager.getSessionColorSlot(), direction);
|
|
2866
2920
|
this.session.setSessionColor(slot);
|
|
2867
2921
|
const name = sessionColorName(slot);
|
|
2868
|
-
this.
|
|
2922
|
+
this.showDialStep("app.session.color.cycleBackward", `Session color: ${name ?? slot}`);
|
|
2869
2923
|
}
|
|
2870
2924
|
toggleThinkingBlockVisibility() {
|
|
2871
2925
|
this.hideThinkingBlock = !this.hideThinkingBlock;
|