miii-agent 0.1.19 → 0.1.20

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 (3) hide show
  1. package/README.md +78 -247
  2. package/dist/cli.js +885 -115
  3. package/package.json +4 -2
package/dist/cli.js CHANGED
@@ -34,7 +34,8 @@ function migrate(raw) {
34
34
  model: raw.model,
35
35
  provider: raw.provider,
36
36
  effort: raw.effort,
37
- providers
37
+ providers,
38
+ modelContexts: raw.modelContexts
38
39
  };
39
40
  }
40
41
  function readRawConfig() {
@@ -79,6 +80,10 @@ function setEffort(effort) {
79
80
  function setProvider(provider) {
80
81
  saveConfig({ ...readRawConfig(), provider });
81
82
  }
83
+ function setModelContexts(contexts) {
84
+ const raw = readRawConfig();
85
+ saveConfig({ ...raw, modelContexts: { ...raw.modelContexts, ...contexts } });
86
+ }
82
87
  var EFFORT_OPTIONS, CONFIG_DIR, CONFIG_PATH;
83
88
  var init_config = __esm({
84
89
  "src/config.ts"() {
@@ -211,9 +216,21 @@ async function* chat(entry, model, messages, tools, opts) {
211
216
  };
212
217
  if (opts?.format) req.format = opts.format;
213
218
  else if (tools) req.tools = tools;
214
- stream = await client.chat(
215
- req
216
- );
219
+ try {
220
+ stream = await client.chat(
221
+ req
222
+ );
223
+ } catch (err) {
224
+ const msg = err instanceof Error ? err.message : String(err);
225
+ if (!signal?.aborted && msg.toLowerCase().includes("does not support thinking")) {
226
+ delete req.think;
227
+ stream = await client.chat(
228
+ req
229
+ );
230
+ } else {
231
+ throw err;
232
+ }
233
+ }
217
234
  } catch (err) {
218
235
  if (signal?.aborted) return;
219
236
  if (isConnectionError(err)) {
@@ -243,6 +260,11 @@ async function* chat(entry, model, messages, tools, opts) {
243
260
  if (isConnectionError(err)) {
244
261
  throw new Error(NOT_RUNNING);
245
262
  }
263
+ const msg = err instanceof Error ? err.message : String(err);
264
+ if (msg.includes("Did not receive done or success response in stream")) {
265
+ yield { content: "", done: true, prompt_eval_count: 0, eval_count: 0 };
266
+ return;
267
+ }
246
268
  throw err;
247
269
  } finally {
248
270
  if (opts?.signal) opts.signal.removeEventListener("abort", onAbort);
@@ -1300,9 +1322,9 @@ After each tool result, answer silently: "Does this result move me toward GOAL?"
1300
1322
  This prevents drift. Each step attends to the original goal, not just the previous step.
1301
1323
 
1302
1324
  # Output format
1303
- - Always reply in plain text. Never use Markdown syntax: no \`#\` headings, no \`**bold**\`, no \`-\` bullet lists, no fenced \`\`\` code blocks, no inline backticks.
1304
- - This applies to your reasoning/thinking too. Write internal thoughts in plain text \u2014 no Markdown headings, bold, lists, or code fences there either.
1305
- - Quote code, paths, and identifiers inline as plain text. Do not wrap them.
1325
+ - Your reply is rendered as Markdown in the terminal. You may use the Markdown the renderer supports: \`#\` headings, \`**bold**\` / \`*italic*\`, \`-\` bullet and numbered lists, fenced \`\`\` code blocks (with a language tag for syntax highlighting), inline backticks, blockquotes, links, and tables.
1326
+ - Use it sparingly and only where it aids clarity. Wrap code, paths, commands, and identifiers in inline backticks; put multi-line code in fenced blocks with a language tag. Keep prose plain \u2014 no decorative formatting.
1327
+ - This does NOT apply to your reasoning/thinking. Write internal thoughts in plain text \u2014 no Markdown headings, bold, lists, or code fences there.
1306
1328
  - Keep prose terse.
1307
1329
 
1308
1330
  # Tone and voice
@@ -2159,7 +2181,7 @@ import { createElement } from "react";
2159
2181
  init_client();
2160
2182
  init_config();
2161
2183
  import { useState as useState5, useEffect as useEffect4, useRef as useRef2 } from "react";
2162
- import { Box as Box10, Text as Text10, useApp } from "ink";
2184
+ import { Box as Box13, Text as Text13, useApp } from "ink";
2163
2185
  import { homedir as homedir6 } from "os";
2164
2186
  import { sep as sep2 } from "path";
2165
2187
 
@@ -2201,7 +2223,7 @@ import { memo, useEffect, useState } from "react";
2201
2223
  import { Box as Box2, Text as Text2 } from "ink";
2202
2224
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
2203
2225
  var SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
2204
- var InputBar = memo(function InputBar2({ input, disabled, processingLabel }) {
2226
+ var InputBar = memo(function InputBar2({ input, caret, disabled, processingLabel }) {
2205
2227
  const [frame, setFrame] = useState(0);
2206
2228
  useEffect(() => {
2207
2229
  if (!disabled) return;
@@ -2224,8 +2246,17 @@ var InputBar = memo(function InputBar2({ input, disabled, processingLabel }) {
2224
2246
  /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " (esc to cancel)" })
2225
2247
  ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
2226
2248
  /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "> " }),
2227
- /* @__PURE__ */ jsx2(Text2, { children: input }),
2228
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u258C" })
2249
+ (() => {
2250
+ const pos = Math.max(0, Math.min(caret ?? input.length, input.length));
2251
+ const before = input.slice(0, pos);
2252
+ const at = input.slice(pos, pos + 1) || " ";
2253
+ const after = input.slice(pos + 1);
2254
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
2255
+ /* @__PURE__ */ jsx2(Text2, { children: before }),
2256
+ /* @__PURE__ */ jsx2(Text2, { inverse: true, children: at }),
2257
+ /* @__PURE__ */ jsx2(Text2, { children: after })
2258
+ ] });
2259
+ })()
2229
2260
  ] })
2230
2261
  }
2231
2262
  );
@@ -2634,10 +2665,566 @@ function FilePicker({ matches: matches2, cursor }) {
2634
2665
  }
2635
2666
 
2636
2667
  // src/ui/ChatView.tsx
2637
- import { memo as memo2, useState as useState3, useEffect as useEffect3 } from "react";
2638
- import { Box as Box9, Text as Text9 } from "ink";
2668
+ import { Box as Box12, Text as Text12, Static } from "ink";
2669
+
2670
+ // src/ui/markdown.ts
2671
+ import { Marked } from "marked";
2672
+ import { markedTerminal } from "marked-terminal";
2639
2673
  import { highlight } from "cli-highlight";
2640
2674
 
2675
+ // node_modules/chalk/source/vendor/ansi-styles/index.js
2676
+ var ANSI_BACKGROUND_OFFSET = 10;
2677
+ var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
2678
+ var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
2679
+ var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
2680
+ var styles = {
2681
+ modifier: {
2682
+ reset: [0, 0],
2683
+ // 21 isn't widely supported and 22 does the same thing
2684
+ bold: [1, 22],
2685
+ dim: [2, 22],
2686
+ italic: [3, 23],
2687
+ underline: [4, 24],
2688
+ overline: [53, 55],
2689
+ inverse: [7, 27],
2690
+ hidden: [8, 28],
2691
+ strikethrough: [9, 29]
2692
+ },
2693
+ color: {
2694
+ black: [30, 39],
2695
+ red: [31, 39],
2696
+ green: [32, 39],
2697
+ yellow: [33, 39],
2698
+ blue: [34, 39],
2699
+ magenta: [35, 39],
2700
+ cyan: [36, 39],
2701
+ white: [37, 39],
2702
+ // Bright color
2703
+ blackBright: [90, 39],
2704
+ gray: [90, 39],
2705
+ // Alias of `blackBright`
2706
+ grey: [90, 39],
2707
+ // Alias of `blackBright`
2708
+ redBright: [91, 39],
2709
+ greenBright: [92, 39],
2710
+ yellowBright: [93, 39],
2711
+ blueBright: [94, 39],
2712
+ magentaBright: [95, 39],
2713
+ cyanBright: [96, 39],
2714
+ whiteBright: [97, 39]
2715
+ },
2716
+ bgColor: {
2717
+ bgBlack: [40, 49],
2718
+ bgRed: [41, 49],
2719
+ bgGreen: [42, 49],
2720
+ bgYellow: [43, 49],
2721
+ bgBlue: [44, 49],
2722
+ bgMagenta: [45, 49],
2723
+ bgCyan: [46, 49],
2724
+ bgWhite: [47, 49],
2725
+ // Bright color
2726
+ bgBlackBright: [100, 49],
2727
+ bgGray: [100, 49],
2728
+ // Alias of `bgBlackBright`
2729
+ bgGrey: [100, 49],
2730
+ // Alias of `bgBlackBright`
2731
+ bgRedBright: [101, 49],
2732
+ bgGreenBright: [102, 49],
2733
+ bgYellowBright: [103, 49],
2734
+ bgBlueBright: [104, 49],
2735
+ bgMagentaBright: [105, 49],
2736
+ bgCyanBright: [106, 49],
2737
+ bgWhiteBright: [107, 49]
2738
+ }
2739
+ };
2740
+ var modifierNames = Object.keys(styles.modifier);
2741
+ var foregroundColorNames = Object.keys(styles.color);
2742
+ var backgroundColorNames = Object.keys(styles.bgColor);
2743
+ var colorNames = [...foregroundColorNames, ...backgroundColorNames];
2744
+ function assembleStyles() {
2745
+ const codes = /* @__PURE__ */ new Map();
2746
+ for (const [groupName, group] of Object.entries(styles)) {
2747
+ for (const [styleName, style] of Object.entries(group)) {
2748
+ styles[styleName] = {
2749
+ open: `\x1B[${style[0]}m`,
2750
+ close: `\x1B[${style[1]}m`
2751
+ };
2752
+ group[styleName] = styles[styleName];
2753
+ codes.set(style[0], style[1]);
2754
+ }
2755
+ Object.defineProperty(styles, groupName, {
2756
+ value: group,
2757
+ enumerable: false
2758
+ });
2759
+ }
2760
+ Object.defineProperty(styles, "codes", {
2761
+ value: codes,
2762
+ enumerable: false
2763
+ });
2764
+ styles.color.close = "\x1B[39m";
2765
+ styles.bgColor.close = "\x1B[49m";
2766
+ styles.color.ansi = wrapAnsi16();
2767
+ styles.color.ansi256 = wrapAnsi256();
2768
+ styles.color.ansi16m = wrapAnsi16m();
2769
+ styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
2770
+ styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
2771
+ styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
2772
+ Object.defineProperties(styles, {
2773
+ rgbToAnsi256: {
2774
+ value(red, green, blue) {
2775
+ if (red === green && green === blue) {
2776
+ if (red < 8) {
2777
+ return 16;
2778
+ }
2779
+ if (red > 248) {
2780
+ return 231;
2781
+ }
2782
+ return Math.round((red - 8) / 247 * 24) + 232;
2783
+ }
2784
+ return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
2785
+ },
2786
+ enumerable: false
2787
+ },
2788
+ hexToRgb: {
2789
+ value(hex) {
2790
+ const matches2 = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
2791
+ if (!matches2) {
2792
+ return [0, 0, 0];
2793
+ }
2794
+ let [colorString] = matches2;
2795
+ if (colorString.length === 3) {
2796
+ colorString = [...colorString].map((character) => character + character).join("");
2797
+ }
2798
+ const integer = Number.parseInt(colorString, 16);
2799
+ return [
2800
+ /* eslint-disable no-bitwise */
2801
+ integer >> 16 & 255,
2802
+ integer >> 8 & 255,
2803
+ integer & 255
2804
+ /* eslint-enable no-bitwise */
2805
+ ];
2806
+ },
2807
+ enumerable: false
2808
+ },
2809
+ hexToAnsi256: {
2810
+ value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
2811
+ enumerable: false
2812
+ },
2813
+ ansi256ToAnsi: {
2814
+ value(code) {
2815
+ if (code < 8) {
2816
+ return 30 + code;
2817
+ }
2818
+ if (code < 16) {
2819
+ return 90 + (code - 8);
2820
+ }
2821
+ let red;
2822
+ let green;
2823
+ let blue;
2824
+ if (code >= 232) {
2825
+ red = ((code - 232) * 10 + 8) / 255;
2826
+ green = red;
2827
+ blue = red;
2828
+ } else {
2829
+ code -= 16;
2830
+ const remainder = code % 36;
2831
+ red = Math.floor(code / 36) / 5;
2832
+ green = Math.floor(remainder / 6) / 5;
2833
+ blue = remainder % 6 / 5;
2834
+ }
2835
+ const value = Math.max(red, green, blue) * 2;
2836
+ if (value === 0) {
2837
+ return 30;
2838
+ }
2839
+ let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
2840
+ if (value === 2) {
2841
+ result += 60;
2842
+ }
2843
+ return result;
2844
+ },
2845
+ enumerable: false
2846
+ },
2847
+ rgbToAnsi: {
2848
+ value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
2849
+ enumerable: false
2850
+ },
2851
+ hexToAnsi: {
2852
+ value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
2853
+ enumerable: false
2854
+ }
2855
+ });
2856
+ return styles;
2857
+ }
2858
+ var ansiStyles = assembleStyles();
2859
+ var ansi_styles_default = ansiStyles;
2860
+
2861
+ // node_modules/chalk/source/vendor/supports-color/index.js
2862
+ import process2 from "process";
2863
+ import os from "os";
2864
+ import tty from "tty";
2865
+ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
2866
+ const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
2867
+ const position = argv.indexOf(prefix + flag);
2868
+ const terminatorPosition = argv.indexOf("--");
2869
+ return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
2870
+ }
2871
+ var { env } = process2;
2872
+ var flagForceColor;
2873
+ if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
2874
+ flagForceColor = 0;
2875
+ } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
2876
+ flagForceColor = 1;
2877
+ }
2878
+ function envForceColor() {
2879
+ if ("FORCE_COLOR" in env) {
2880
+ if (env.FORCE_COLOR === "true") {
2881
+ return 1;
2882
+ }
2883
+ if (env.FORCE_COLOR === "false") {
2884
+ return 0;
2885
+ }
2886
+ return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
2887
+ }
2888
+ }
2889
+ function translateLevel(level) {
2890
+ if (level === 0) {
2891
+ return false;
2892
+ }
2893
+ return {
2894
+ level,
2895
+ hasBasic: true,
2896
+ has256: level >= 2,
2897
+ has16m: level >= 3
2898
+ };
2899
+ }
2900
+ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
2901
+ const noFlagForceColor = envForceColor();
2902
+ if (noFlagForceColor !== void 0) {
2903
+ flagForceColor = noFlagForceColor;
2904
+ }
2905
+ const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
2906
+ if (forceColor === 0) {
2907
+ return 0;
2908
+ }
2909
+ if (sniffFlags) {
2910
+ if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
2911
+ return 3;
2912
+ }
2913
+ if (hasFlag("color=256")) {
2914
+ return 2;
2915
+ }
2916
+ }
2917
+ if ("TF_BUILD" in env && "AGENT_NAME" in env) {
2918
+ return 1;
2919
+ }
2920
+ if (haveStream && !streamIsTTY && forceColor === void 0) {
2921
+ return 0;
2922
+ }
2923
+ const min = forceColor || 0;
2924
+ if (env.TERM === "dumb") {
2925
+ return min;
2926
+ }
2927
+ if (process2.platform === "win32") {
2928
+ const osRelease = os.release().split(".");
2929
+ if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
2930
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
2931
+ }
2932
+ return 1;
2933
+ }
2934
+ if ("CI" in env) {
2935
+ if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
2936
+ return 3;
2937
+ }
2938
+ if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
2939
+ return 1;
2940
+ }
2941
+ return min;
2942
+ }
2943
+ if ("TEAMCITY_VERSION" in env) {
2944
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
2945
+ }
2946
+ if (env.COLORTERM === "truecolor") {
2947
+ return 3;
2948
+ }
2949
+ if (env.TERM === "xterm-kitty") {
2950
+ return 3;
2951
+ }
2952
+ if (env.TERM === "xterm-ghostty") {
2953
+ return 3;
2954
+ }
2955
+ if (env.TERM === "wezterm") {
2956
+ return 3;
2957
+ }
2958
+ if ("TERM_PROGRAM" in env) {
2959
+ const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
2960
+ switch (env.TERM_PROGRAM) {
2961
+ case "iTerm.app": {
2962
+ return version >= 3 ? 3 : 2;
2963
+ }
2964
+ case "Apple_Terminal": {
2965
+ return 2;
2966
+ }
2967
+ }
2968
+ }
2969
+ if (/-256(color)?$/i.test(env.TERM)) {
2970
+ return 2;
2971
+ }
2972
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
2973
+ return 1;
2974
+ }
2975
+ if ("COLORTERM" in env) {
2976
+ return 1;
2977
+ }
2978
+ return min;
2979
+ }
2980
+ function createSupportsColor(stream, options = {}) {
2981
+ const level = _supportsColor(stream, {
2982
+ streamIsTTY: stream && stream.isTTY,
2983
+ ...options
2984
+ });
2985
+ return translateLevel(level);
2986
+ }
2987
+ var supportsColor = {
2988
+ stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
2989
+ stderr: createSupportsColor({ isTTY: tty.isatty(2) })
2990
+ };
2991
+ var supports_color_default = supportsColor;
2992
+
2993
+ // node_modules/chalk/source/utilities.js
2994
+ function stringReplaceAll(string, substring, replacer) {
2995
+ let index = string.indexOf(substring);
2996
+ if (index === -1) {
2997
+ return string;
2998
+ }
2999
+ const substringLength = substring.length;
3000
+ let endIndex = 0;
3001
+ let returnValue = "";
3002
+ do {
3003
+ returnValue += string.slice(endIndex, index) + substring + replacer;
3004
+ endIndex = index + substringLength;
3005
+ index = string.indexOf(substring, endIndex);
3006
+ } while (index !== -1);
3007
+ returnValue += string.slice(endIndex);
3008
+ return returnValue;
3009
+ }
3010
+ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
3011
+ let endIndex = 0;
3012
+ let returnValue = "";
3013
+ do {
3014
+ const gotCR = string[index - 1] === "\r";
3015
+ returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
3016
+ endIndex = index + 1;
3017
+ index = string.indexOf("\n", endIndex);
3018
+ } while (index !== -1);
3019
+ returnValue += string.slice(endIndex);
3020
+ return returnValue;
3021
+ }
3022
+
3023
+ // node_modules/chalk/source/index.js
3024
+ var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
3025
+ var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
3026
+ var STYLER = /* @__PURE__ */ Symbol("STYLER");
3027
+ var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
3028
+ var levelMapping = [
3029
+ "ansi",
3030
+ "ansi",
3031
+ "ansi256",
3032
+ "ansi16m"
3033
+ ];
3034
+ var styles2 = /* @__PURE__ */ Object.create(null);
3035
+ var applyOptions = (object, options = {}) => {
3036
+ if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
3037
+ throw new Error("The `level` option should be an integer from 0 to 3");
3038
+ }
3039
+ const colorLevel = stdoutColor ? stdoutColor.level : 0;
3040
+ object.level = options.level === void 0 ? colorLevel : options.level;
3041
+ };
3042
+ var chalkFactory = (options) => {
3043
+ const chalk2 = (...strings) => strings.join(" ");
3044
+ applyOptions(chalk2, options);
3045
+ Object.setPrototypeOf(chalk2, createChalk.prototype);
3046
+ return chalk2;
3047
+ };
3048
+ function createChalk(options) {
3049
+ return chalkFactory(options);
3050
+ }
3051
+ Object.setPrototypeOf(createChalk.prototype, Function.prototype);
3052
+ for (const [styleName, style] of Object.entries(ansi_styles_default)) {
3053
+ styles2[styleName] = {
3054
+ get() {
3055
+ const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
3056
+ Object.defineProperty(this, styleName, { value: builder });
3057
+ return builder;
3058
+ }
3059
+ };
3060
+ }
3061
+ styles2.visible = {
3062
+ get() {
3063
+ const builder = createBuilder(this, this[STYLER], true);
3064
+ Object.defineProperty(this, "visible", { value: builder });
3065
+ return builder;
3066
+ }
3067
+ };
3068
+ var getModelAnsi = (model, level, type, ...arguments_) => {
3069
+ if (model === "rgb") {
3070
+ if (level === "ansi16m") {
3071
+ return ansi_styles_default[type].ansi16m(...arguments_);
3072
+ }
3073
+ if (level === "ansi256") {
3074
+ return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
3075
+ }
3076
+ return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
3077
+ }
3078
+ if (model === "hex") {
3079
+ return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
3080
+ }
3081
+ return ansi_styles_default[type][model](...arguments_);
3082
+ };
3083
+ var usedModels = ["rgb", "hex", "ansi256"];
3084
+ for (const model of usedModels) {
3085
+ styles2[model] = {
3086
+ get() {
3087
+ const { level } = this;
3088
+ return function(...arguments_) {
3089
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
3090
+ return createBuilder(this, styler, this[IS_EMPTY]);
3091
+ };
3092
+ }
3093
+ };
3094
+ const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
3095
+ styles2[bgModel] = {
3096
+ get() {
3097
+ const { level } = this;
3098
+ return function(...arguments_) {
3099
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
3100
+ return createBuilder(this, styler, this[IS_EMPTY]);
3101
+ };
3102
+ }
3103
+ };
3104
+ }
3105
+ var proto = Object.defineProperties(() => {
3106
+ }, {
3107
+ ...styles2,
3108
+ level: {
3109
+ enumerable: true,
3110
+ get() {
3111
+ return this[GENERATOR].level;
3112
+ },
3113
+ set(level) {
3114
+ this[GENERATOR].level = level;
3115
+ }
3116
+ }
3117
+ });
3118
+ var createStyler = (open, close, parent) => {
3119
+ let openAll;
3120
+ let closeAll;
3121
+ if (parent === void 0) {
3122
+ openAll = open;
3123
+ closeAll = close;
3124
+ } else {
3125
+ openAll = parent.openAll + open;
3126
+ closeAll = close + parent.closeAll;
3127
+ }
3128
+ return {
3129
+ open,
3130
+ close,
3131
+ openAll,
3132
+ closeAll,
3133
+ parent
3134
+ };
3135
+ };
3136
+ var createBuilder = (self, _styler, _isEmpty) => {
3137
+ const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
3138
+ Object.setPrototypeOf(builder, proto);
3139
+ builder[GENERATOR] = self;
3140
+ builder[STYLER] = _styler;
3141
+ builder[IS_EMPTY] = _isEmpty;
3142
+ return builder;
3143
+ };
3144
+ var applyStyle = (self, string) => {
3145
+ if (self.level <= 0 || !string) {
3146
+ return self[IS_EMPTY] ? "" : string;
3147
+ }
3148
+ let styler = self[STYLER];
3149
+ if (styler === void 0) {
3150
+ return string;
3151
+ }
3152
+ const { openAll, closeAll } = styler;
3153
+ if (string.includes("\x1B")) {
3154
+ while (styler !== void 0) {
3155
+ string = stringReplaceAll(string, styler.close, styler.open);
3156
+ styler = styler.parent;
3157
+ }
3158
+ }
3159
+ const lfIndex = string.indexOf("\n");
3160
+ if (lfIndex !== -1) {
3161
+ string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
3162
+ }
3163
+ return openAll + string + closeAll;
3164
+ };
3165
+ Object.defineProperties(createChalk.prototype, styles2);
3166
+ var chalk = createChalk();
3167
+ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
3168
+ var source_default = chalk;
3169
+
3170
+ // src/ui/markdown.ts
3171
+ var theme = {
3172
+ heading: source_default.hex("#7fa8d4").bold,
3173
+ // dusty blue
3174
+ firstHeading: source_default.hex("#9ab8de").bold,
3175
+ // slightly lighter for h1
3176
+ strong: source_default.hex("#d6c9a8").bold,
3177
+ // warm sand
3178
+ em: source_default.hex("#b59ec4").italic,
3179
+ // soft mauve
3180
+ del: source_default.hex("#6b7280").strikethrough,
3181
+ // dim gray
3182
+ codespan: source_default.hex("#c8a98a"),
3183
+ // muted clay
3184
+ link: source_default.hex("#83b3a6").underline,
3185
+ // sage teal
3186
+ href: source_default.hex("#83b3a6").underline,
3187
+ blockquote: source_default.hex("#8a9aa8").italic,
3188
+ // slate
3189
+ listitem: source_default.hex("#c4c9cf"),
3190
+ // off-white
3191
+ paragraph: source_default.hex("#c4c9cf"),
3192
+ // off-white body text
3193
+ hr: source_default.hex("#4b5563")
3194
+ // faint rule
3195
+ };
3196
+ function highlightCode(code, lang) {
3197
+ if (!lang) return code;
3198
+ try {
3199
+ return highlight(code, { language: lang, ignoreIllegals: true });
3200
+ } catch {
3201
+ return code;
3202
+ }
3203
+ }
3204
+ var md = new Marked();
3205
+ md.use(
3206
+ markedTerminal({
3207
+ // Drop the literal `#` prefix on headings; render them styled instead.
3208
+ showSectionPrefix: false,
3209
+ // marked-terminal calls this for ``` blocks; fall back to plain on unknown lang.
3210
+ code: (code, lang) => highlightCode(code, lang),
3211
+ ...theme
3212
+ })
3213
+ );
3214
+ function renderMarkdown(content) {
3215
+ try {
3216
+ const out = md.parse(content, { async: false });
3217
+ return out.replace(/\n+$/, "");
3218
+ } catch {
3219
+ return content;
3220
+ }
3221
+ }
3222
+ function renderMarkdownStreaming(content) {
3223
+ const fences = (content.match(/^```/gm) ?? []).length;
3224
+ const balanced = fences % 2 === 1 ? content + "\n```" : content;
3225
+ return renderMarkdown(balanced);
3226
+ }
3227
+
2641
3228
  // src/ui/ThinkingBlock.tsx
2642
3229
  import { useState as useState2, useEffect as useEffect2 } from "react";
2643
3230
  import { Box as Box8, Text as Text8 } from "ink";
@@ -2680,7 +3267,12 @@ function ThinkingBlock({ content }) {
2680
3267
  " thoughts"
2681
3268
  ] })
2682
3269
  ] }),
2683
- visible && content ? /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, italic: true, children: content }) }) : null
3270
+ visible && content ? (() => {
3271
+ const max = Math.max(4, (process.stdout.rows ?? 24) - 10);
3272
+ const lines = content.split("\n");
3273
+ const shown = lines.length > max ? lines.slice(-max) : lines;
3274
+ return /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, italic: true, children: shown.join("\n") }) });
3275
+ })() : null
2684
3276
  ] });
2685
3277
  }
2686
3278
 
@@ -2694,9 +3286,16 @@ var EMPTY_STATE_HINTS = [
2694
3286
  ];
2695
3287
  var EMPTY_STATE_TITLE = "Ask anything, or try:";
2696
3288
 
2697
- // src/ui/ChatView.tsx
2698
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
2699
- var COLLAPSED_LINES = 3;
3289
+ // src/ui/Message.tsx
3290
+ import { memo as memo2 } from "react";
3291
+ import { Box as Box10, Text as Text10 } from "ink";
3292
+
3293
+ // src/ui/ToolBlock.tsx
3294
+ import { Box as Box9, Text as Text9 } from "ink";
3295
+ import { highlight as highlight2 } from "cli-highlight";
3296
+
3297
+ // src/ui/toolExpand.ts
3298
+ import { useState as useState3, useEffect as useEffect3 } from "react";
2700
3299
  var globalToolExpanded = false;
2701
3300
  var toolExpandListeners = /* @__PURE__ */ new Set();
2702
3301
  function toggleToolExpanded() {
@@ -2714,6 +3313,8 @@ function useToolExpanded() {
2714
3313
  }, []);
2715
3314
  return expanded;
2716
3315
  }
3316
+
3317
+ // src/ui/layout.ts
2717
3318
  function formatTokens(n) {
2718
3319
  if (n >= 1e3) return (n / 1e3).toFixed(n >= 1e4 ? 0 : 1) + "k";
2719
3320
  return String(n);
@@ -2729,6 +3330,61 @@ function countLines(s) {
2729
3330
  if (!s) return 0;
2730
3331
  return s.split("\n").length;
2731
3332
  }
3333
+ function truncate2(s, max) {
3334
+ if (s.length <= max) return s;
3335
+ return s.slice(0, max - 1) + "\u2026";
3336
+ }
3337
+ function clipTail(rendered, max) {
3338
+ const lines = rendered.split("\n");
3339
+ if (lines.length <= max) return { text: rendered, clipped: 0 };
3340
+ return { text: lines.slice(-max).join("\n"), clipped: lines.length - max };
3341
+ }
3342
+ function liveFrameRows() {
3343
+ const rows = process.stdout.rows ?? 24;
3344
+ return Math.max(6, rows - 8);
3345
+ }
3346
+ var COLLAPSED_LINES = 3;
3347
+ function estimateToolRows(use, result) {
3348
+ const input = use.input ?? {};
3349
+ const noErr = !result?.is_error;
3350
+ if (use.name === "write_file" && noErr) {
3351
+ const total = countLines(String(input.content ?? ""));
3352
+ const shown = Math.min(total, COLLAPSED_LINES);
3353
+ return 2 + shown + (total > shown ? 1 : 0);
3354
+ }
3355
+ if (use.name === "edit_file" && noErr) {
3356
+ const total = countLines(String(input.old_str ?? "")) + countLines(String(input.new_str ?? ""));
3357
+ const shown = Math.min(total, COLLAPSED_LINES);
3358
+ return 2 + shown + (total > shown ? 1 : 0);
3359
+ }
3360
+ let rows = 1;
3361
+ if (result) {
3362
+ const lines = (result.content ?? "").split("\n");
3363
+ const multi = (use.name === "run_bash" || use.name === "grep" || use.name === "glob" || result.is_error) && lines.length > 1;
3364
+ if (multi) {
3365
+ const shown = Math.min(lines.length, COLLAPSED_LINES);
3366
+ rows += 1 + shown + (lines.length > shown ? 1 : 0);
3367
+ } else {
3368
+ rows += 1;
3369
+ }
3370
+ }
3371
+ return rows;
3372
+ }
3373
+ function contentWidth() {
3374
+ return Math.max(20, (process.stdout.columns ?? 80) - 4);
3375
+ }
3376
+
3377
+ // src/ui/ToolBlock.tsx
3378
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
3379
+ var COLLAPSED_LINES2 = 3;
3380
+ var TOOL_LABEL = {
3381
+ write_file: "Write",
3382
+ edit_file: "Update",
3383
+ read_file: "Read",
3384
+ run_bash: "Bash",
3385
+ glob: "Glob",
3386
+ grep: "Grep"
3387
+ };
2732
3388
  var EXT_LANG = {
2733
3389
  ts: "typescript",
2734
3390
  tsx: "typescript",
@@ -2773,7 +3429,7 @@ function langFromPath(path) {
2773
3429
  function highlightLine(text, lang) {
2774
3430
  if (!lang) return text;
2775
3431
  try {
2776
- return highlight(text, { language: lang, ignoreIllegals: true });
3432
+ return highlight2(text, { language: lang, ignoreIllegals: true });
2777
3433
  } catch {
2778
3434
  return text;
2779
3435
  }
@@ -2786,7 +3442,7 @@ function FileEditBlock({
2786
3442
  previewLines
2787
3443
  }) {
2788
3444
  const expanded = useToolExpanded();
2789
- const shown = expanded ? previewLines : previewLines.slice(0, COLLAPSED_LINES);
3445
+ const shown = expanded ? previewLines : previewLines.slice(0, COLLAPSED_LINES2);
2790
3446
  const extra = previewLines.length - shown.length;
2791
3447
  const lang = langFromPath(path);
2792
3448
  return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginLeft: 2, children: [
@@ -2829,18 +3485,6 @@ function FileEditBlock({
2829
3485
  ] }) })
2830
3486
  ] });
2831
3487
  }
2832
- var TOOL_LABEL = {
2833
- write_file: "Write",
2834
- edit_file: "Update",
2835
- read_file: "Read",
2836
- run_bash: "Bash",
2837
- glob: "Glob",
2838
- grep: "Grep"
2839
- };
2840
- function truncate2(s, max) {
2841
- if (s.length <= max) return s;
2842
- return s.slice(0, max - 1) + "\u2026";
2843
- }
2844
3488
  function toolHeader(use) {
2845
3489
  const label = TOOL_LABEL[use.name] ?? use.name;
2846
3490
  const input = use.input ?? {};
@@ -2902,7 +3546,7 @@ function ToolResultBlock({ result, toolName }) {
2902
3546
  ] }) });
2903
3547
  }
2904
3548
  const MAX_LINE_WIDTH = 200;
2905
- const visible = expanded ? lines : lines.slice(0, COLLAPSED_LINES);
3549
+ const visible = expanded ? lines : lines.slice(0, COLLAPSED_LINES2);
2906
3550
  const shown = visible.map((l) => truncate2(l, MAX_LINE_WIDTH));
2907
3551
  const extra = lines.length - shown.length;
2908
3552
  const header = toolName === "grep" || toolName === "glob" ? summarizeResult(result, toolName) : `${lines.length} line${lines.length === 1 ? "" : "s"}`;
@@ -2954,28 +3598,35 @@ function ToolUseLine({ use, result }) {
2954
3598
  result && /* @__PURE__ */ jsx9(ToolResultBlock, { result, toolName: use.name })
2955
3599
  ] });
2956
3600
  }
3601
+
3602
+ // src/ui/Message.tsx
3603
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
2957
3604
  var UserMessage = memo2(function UserMessage2({ msg }) {
2958
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", marginBottom: 1, children: [
2959
- /* @__PURE__ */ jsx9(Text9, { color: "gray", children: "\u276F " }),
2960
- /* @__PURE__ */ jsx9(Box9, { flexGrow: 1, children: /* @__PURE__ */ jsx9(Text9, { children: msg.content }) })
3605
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", marginBottom: 1, children: [
3606
+ /* @__PURE__ */ jsx10(Text10, { color: "gray", children: "\u276F " }),
3607
+ /* @__PURE__ */ jsx10(Box10, { flexGrow: 1, children: /* @__PURE__ */ jsx10(Text10, { children: msg.content }) })
2961
3608
  ] });
2962
3609
  });
2963
3610
  var AssistantMessage = memo2(function AssistantMessage2({ msg }) {
2964
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, children: [
2965
- msg.content && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", children: [
2966
- /* @__PURE__ */ jsx9(Text9, { color: "blue", children: "\u25CF " }),
2967
- /* @__PURE__ */ jsx9(Box9, { flexGrow: 1, children: /* @__PURE__ */ jsx9(Text9, { children: msg.content }) })
3611
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginBottom: 1, children: [
3612
+ msg.content && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", children: [
3613
+ /* @__PURE__ */ jsx10(Text10, { color: "blue", children: "\u25CF " }),
3614
+ /* @__PURE__ */ jsx10(Box10, { width: contentWidth(), children: /* @__PURE__ */ jsx10(Text10, { wrap: "wrap", children: renderMarkdown(msg.content) }) })
2968
3615
  ] }),
2969
3616
  msg.tool_uses?.map((u) => {
2970
3617
  const r = msg.tool_results?.find((x) => x.tool_use_id === u.id);
2971
- return /* @__PURE__ */ jsx9(ToolUseLine, { use: u, result: r }, u.id);
3618
+ return /* @__PURE__ */ jsx10(ToolUseLine, { use: u, result: r }, u.id);
2972
3619
  }),
2973
- msg.tokens && /* @__PURE__ */ jsx9(Box9, { marginLeft: 2, children: /* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
3620
+ msg.tokens && /* @__PURE__ */ jsx10(Box10, { marginLeft: 2, children: /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
2974
3621
  `\u21B3 Completed \xB7 ${formatTokens(msg.tokens.prompt_eval + msg.tokens.eval)} tokens`,
2975
3622
  msg.duration != null ? ` \xB7 ${formatDuration(msg.duration)}` : ""
2976
3623
  ] }) })
2977
3624
  ] });
2978
3625
  });
3626
+
3627
+ // src/ui/PermissionPrompt.tsx
3628
+ import { Box as Box11, Text as Text11 } from "ink";
3629
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
2979
3630
  function summarizeInput(input) {
2980
3631
  if (!input || typeof input !== "object") return "";
2981
3632
  const obj = input;
@@ -3002,15 +3653,15 @@ function PermissionPrompt({ req, cursor }) {
3002
3653
  { label: "No", key: "no" }
3003
3654
  ];
3004
3655
  const summary = summarizeInput(req.input);
3005
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
3006
- /* @__PURE__ */ jsx9(Text9, { color: "blue", bold: true, children: "Tool use" }),
3007
- /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text9, { children: [
3656
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginBottom: 1, borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
3657
+ /* @__PURE__ */ jsx11(Text11, { color: "blue", bold: true, children: "Tool use" }),
3658
+ /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text11, { children: [
3008
3659
  "Allow ",
3009
- /* @__PURE__ */ jsx9(Text9, { bold: true, children: label }),
3660
+ /* @__PURE__ */ jsx11(Text11, { bold: true, children: label }),
3010
3661
  "?"
3011
3662
  ] }) }),
3012
- summary && /* @__PURE__ */ jsx9(Box9, { marginLeft: 2, children: /* @__PURE__ */ jsx9(Text9, { wrap: "truncate", dimColor: true, children: summary }) }),
3013
- /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", marginTop: 1, children: options.map((opt, i) => /* @__PURE__ */ jsxs9(Text9, { color: i === cursor ? "blue" : void 0, children: [
3663
+ summary && /* @__PURE__ */ jsx11(Box11, { marginLeft: 2, children: /* @__PURE__ */ jsx11(Text11, { wrap: "truncate", dimColor: true, children: summary }) }),
3664
+ /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", marginTop: 1, children: options.map((opt, i) => /* @__PURE__ */ jsxs11(Text11, { color: i === cursor ? "blue" : void 0, children: [
3014
3665
  i === cursor ? "\u276F " : " ",
3015
3666
  i + 1,
3016
3667
  ". ",
@@ -3018,6 +3669,9 @@ function PermissionPrompt({ req, cursor }) {
3018
3669
  ] }, opt.key)) })
3019
3670
  ] });
3020
3671
  }
3672
+
3673
+ // src/ui/ChatView.tsx
3674
+ import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
3021
3675
  function ChatView({
3022
3676
  messages,
3023
3677
  streaming,
@@ -3028,33 +3682,70 @@ function ChatView({
3028
3682
  pendingPermission,
3029
3683
  permissionCursor = 0,
3030
3684
  activeToolUses,
3031
- activeToolResults
3685
+ activeToolResults,
3686
+ header
3032
3687
  }) {
3033
3688
  const empty = messages.length === 0 && !streaming && !thinking && !pendingPermission && !error;
3034
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginLeft: 1, marginBottom: 1, children: [
3035
- empty && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, children: [
3036
- /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: EMPTY_STATE_TITLE }),
3037
- EMPTY_STATE_HINTS.map((h, i) => /* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
3038
- " ",
3039
- h
3040
- ] }, i))
3041
- ] }),
3042
- messages.map(
3043
- (msg, i) => msg.role === "user" ? /* @__PURE__ */ jsx9(UserMessage, { msg }, i) : /* @__PURE__ */ jsx9(AssistantMessage, { msg }, i)
3044
- ),
3045
- thinking && /* @__PURE__ */ jsx9(ThinkingBlock, { content: thinkingContent }),
3046
- streaming && streamingContent && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", marginBottom: 1, children: [
3047
- /* @__PURE__ */ jsx9(Text9, { color: "white", children: "\u25CF " }),
3048
- /* @__PURE__ */ jsx9(Box9, { flexGrow: 1, children: /* @__PURE__ */ jsx9(Text9, { children: streamingContent }) })
3049
- ] }),
3050
- activeToolUses?.map((u) => {
3051
- const r = activeToolResults?.find((x) => x.tool_use_id === u.id);
3052
- return /* @__PURE__ */ jsx9(ToolUseLine, { use: u, result: r }, u.id);
3053
- }),
3054
- pendingPermission && /* @__PURE__ */ jsx9(PermissionPrompt, { req: pendingPermission, cursor: permissionCursor }),
3055
- error && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", marginBottom: 1, children: [
3056
- /* @__PURE__ */ jsx9(Text9, { color: "red", children: "\u25CF " }),
3057
- /* @__PURE__ */ jsx9(Text9, { color: "red", children: error })
3689
+ const log = [];
3690
+ if (header) log.push({ key: "header", node: header });
3691
+ messages.forEach((msg, i) => {
3692
+ log.push({
3693
+ key: `msg-${i}`,
3694
+ node: msg.role === "user" ? /* @__PURE__ */ jsx12(UserMessage, { msg }) : /* @__PURE__ */ jsx12(AssistantMessage, { msg })
3695
+ });
3696
+ });
3697
+ const liveBudget = liveFrameRows();
3698
+ let streamNode = null;
3699
+ let streamRows = 0;
3700
+ if (streaming && streamingContent) {
3701
+ const { text, clipped } = clipTail(renderMarkdownStreaming(streamingContent), liveBudget);
3702
+ streamRows = text.split("\n").length + (clipped > 0 ? 1 : 0);
3703
+ streamNode = /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginBottom: 1, children: [
3704
+ clipped > 0 && /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: `\u2191 ${clipped} more line${clipped === 1 ? "" : "s"} above \u2014 streaming\u2026` }),
3705
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
3706
+ /* @__PURE__ */ jsx12(Text12, { color: "blue", children: "\u25CF " }),
3707
+ /* @__PURE__ */ jsx12(Box12, { width: contentWidth(), children: /* @__PURE__ */ jsx12(Text12, { wrap: "wrap", children: text }) })
3708
+ ] })
3709
+ ] });
3710
+ }
3711
+ let toolNode = null;
3712
+ if (activeToolUses?.length) {
3713
+ const remaining = Math.max(4, liveBudget - streamRows);
3714
+ const resultById = new Map(activeToolResults?.map((r) => [r.tool_use_id, r]));
3715
+ const kept = [];
3716
+ let rows = 0;
3717
+ for (let i = activeToolUses.length - 1; i >= 0; i--) {
3718
+ const u = activeToolUses[i];
3719
+ const r = resultById.get(u.id);
3720
+ const h = estimateToolRows(u, r);
3721
+ if (rows + h > remaining && kept.length) break;
3722
+ rows += h;
3723
+ kept.unshift({ u, r });
3724
+ }
3725
+ const hidden = activeToolUses.length - kept.length;
3726
+ toolNode = /* @__PURE__ */ jsxs12(Fragment2, { children: [
3727
+ hidden > 0 && /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: `\u2191 ${hidden} earlier tool call${hidden === 1 ? "" : "s"} above` }),
3728
+ kept.map(({ u, r }) => /* @__PURE__ */ jsx12(ToolUseLine, { use: u, result: r }, u.id))
3729
+ ] });
3730
+ }
3731
+ return /* @__PURE__ */ jsxs12(Fragment2, { children: [
3732
+ /* @__PURE__ */ jsx12(Static, { items: log, children: (item) => item.key === "header" ? /* @__PURE__ */ jsx12(Box12, { children: item.node }, item.key) : /* @__PURE__ */ jsx12(Box12, { marginLeft: 1, children: item.node }, item.key) }),
3733
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginLeft: 1, marginBottom: 1, children: [
3734
+ empty && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginBottom: 1, children: [
3735
+ /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: EMPTY_STATE_TITLE }),
3736
+ EMPTY_STATE_HINTS.map((h, i) => /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
3737
+ " ",
3738
+ h
3739
+ ] }, i))
3740
+ ] }),
3741
+ thinking && /* @__PURE__ */ jsx12(ThinkingBlock, { content: thinkingContent }),
3742
+ streamNode,
3743
+ toolNode,
3744
+ pendingPermission && /* @__PURE__ */ jsx12(PermissionPrompt, { req: pendingPermission, cursor: permissionCursor }),
3745
+ error && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", marginBottom: 1, children: [
3746
+ /* @__PURE__ */ jsx12(Text12, { color: "red", children: "\u25CF " }),
3747
+ /* @__PURE__ */ jsx12(Text12, { color: "red", children: error })
3748
+ ] })
3058
3749
  ] })
3059
3750
  ] });
3060
3751
  }
@@ -3294,6 +3985,14 @@ function clearPasteStore() {
3294
3985
  pasteStore.clear();
3295
3986
  pasteCounter = 0;
3296
3987
  }
3988
+ var inputHistory = [];
3989
+ var historyIndex = -1;
3990
+ var historyDraft = "";
3991
+ function pushHistory(line) {
3992
+ if (!line) return;
3993
+ if (inputHistory[inputHistory.length - 1] === line) return;
3994
+ inputHistory.push(line);
3995
+ }
3297
3996
  function expandPastes(text) {
3298
3997
  let out = text;
3299
3998
  for (const [chip, full] of pasteStore) out = out.split(chip).join(full);
@@ -3331,6 +4030,8 @@ function useKeyboard(opts) {
3331
4030
  agent,
3332
4031
  input,
3333
4032
  setInput,
4033
+ caret,
4034
+ setCaret,
3334
4035
  paletteCursor,
3335
4036
  setPaletteCursor,
3336
4037
  filePickerCursor,
@@ -3538,36 +4239,43 @@ function useKeyboard(opts) {
3538
4239
  const mention = !paletteOpen ? parseMention(input) : null;
3539
4240
  const fileMatches = mention ? searchFiles(process.cwd(), mention.query) : [];
3540
4241
  const fileOpen = mention !== null && fileMatches.length > 0;
3541
- if (paletteOpen && key.upArrow) {
4242
+ if (paletteOpen && historyIndex === -1 && key.upArrow) {
3542
4243
  setPaletteCursor((i) => Math.max(0, i - 1));
3543
4244
  return;
3544
4245
  }
3545
- if (paletteOpen && key.downArrow) {
4246
+ if (paletteOpen && historyIndex === -1 && key.downArrow) {
3546
4247
  setPaletteCursor((i) => Math.min(matches2.length - 1, i + 1));
3547
4248
  return;
3548
4249
  }
3549
4250
  if (paletteOpen && (key.tab || key.return) && matches2[paletteCursor] && input !== matches2[paletteCursor].name) {
3550
- setInput(() => matches2[paletteCursor].name);
4251
+ const name = matches2[paletteCursor].name;
4252
+ setInput(() => name);
4253
+ setCaret(() => name.length);
3551
4254
  setPaletteCursor(() => 0);
3552
4255
  return;
3553
4256
  }
3554
4257
  if (paletteOpen && key.escape) {
3555
4258
  clearPasteStore();
3556
4259
  setInput(() => "");
4260
+ setCaret(() => 0);
3557
4261
  setPaletteCursor(() => 0);
3558
4262
  return;
3559
4263
  }
3560
- if (fileOpen && key.upArrow) {
4264
+ if (fileOpen && historyIndex === -1 && key.upArrow) {
3561
4265
  setFilePickerCursor((i) => Math.max(0, i - 1));
3562
4266
  return;
3563
4267
  }
3564
- if (fileOpen && key.downArrow) {
4268
+ if (fileOpen && historyIndex === -1 && key.downArrow) {
3565
4269
  setFilePickerCursor((i) => Math.min(fileMatches.length - 1, i + 1));
3566
4270
  return;
3567
4271
  }
3568
4272
  if (fileOpen && key.tab && fileMatches[filePickerCursor]) {
3569
4273
  const picked = fileMatches[filePickerCursor];
3570
- setInput((s) => s.slice(0, mention.start) + "@" + picked + " ");
4274
+ setInput((s) => {
4275
+ const next = s.slice(0, mention.start) + "@" + picked + " ";
4276
+ setCaret(() => next.length);
4277
+ return next;
4278
+ });
3571
4279
  setFilePickerCursor(() => 0);
3572
4280
  return;
3573
4281
  }
@@ -3575,8 +4283,36 @@ function useKeyboard(opts) {
3575
4283
  setFilePickerCursor(() => 0);
3576
4284
  return;
3577
4285
  }
4286
+ if ((historyIndex !== -1 || !paletteOpen && !fileOpen) && key.upArrow) {
4287
+ if (inputHistory.length === 0) return;
4288
+ if (historyIndex === -1) {
4289
+ historyDraft = input;
4290
+ historyIndex = inputHistory.length - 1;
4291
+ } else if (historyIndex > 0) historyIndex--;
4292
+ const val = inputHistory[historyIndex];
4293
+ setInput(() => val);
4294
+ setCaret(() => val.length);
4295
+ return;
4296
+ }
4297
+ if ((historyIndex !== -1 || !paletteOpen && !fileOpen) && key.downArrow) {
4298
+ if (historyIndex === -1) return;
4299
+ if (historyIndex < inputHistory.length - 1) {
4300
+ historyIndex++;
4301
+ const val = inputHistory[historyIndex];
4302
+ setInput(() => val);
4303
+ setCaret(() => val.length);
4304
+ } else {
4305
+ historyIndex = -1;
4306
+ setInput(() => historyDraft);
4307
+ setCaret(() => historyDraft.length);
4308
+ }
4309
+ return;
4310
+ }
3578
4311
  if (key.return) {
3579
4312
  const trimmed = input.trim();
4313
+ pushHistory(trimmed);
4314
+ historyIndex = -1;
4315
+ historyDraft = "";
3580
4316
  if (trimmed === "/models") {
3581
4317
  setPickerQuery("");
3582
4318
  setCursor(() => Math.max(0, models.findIndex((m) => m === cfg.model)));
@@ -3613,30 +4349,49 @@ function useKeyboard(opts) {
3613
4349
  }
3614
4350
  clearPasteStore();
3615
4351
  setInput(() => "");
4352
+ setCaret(() => 0);
3616
4353
  setPaletteCursor(() => 0);
3617
4354
  return;
3618
4355
  }
4356
+ if (key.leftArrow) {
4357
+ setCaret((i) => Math.max(0, i - 1));
4358
+ return;
4359
+ }
4360
+ if (key.rightArrow) {
4361
+ setCaret((i) => Math.min(input.length, i + 1));
4362
+ return;
4363
+ }
4364
+ if (key.ctrl && char === "a") {
4365
+ setCaret(() => 0);
4366
+ return;
4367
+ }
4368
+ if (key.ctrl && char === "e") {
4369
+ setCaret(() => input.length);
4370
+ return;
4371
+ }
3619
4372
  if (key.backspace || key.delete) {
3620
- setInput((s) => {
3621
- setPaletteCursor(() => 0);
3622
- setFilePickerCursor(() => 0);
3623
- let match = "";
3624
- for (const chip of pasteStore.keys()) {
3625
- if (s.endsWith(chip) && chip.length > match.length) match = chip;
3626
- }
3627
- if (match) {
3628
- pasteStore.delete(match);
3629
- return s.slice(0, -match.length);
3630
- }
3631
- return s.slice(0, -1);
3632
- });
4373
+ historyIndex = -1;
4374
+ setPaletteCursor(() => 0);
4375
+ setFilePickerCursor(() => 0);
4376
+ if (caret <= 0) return;
4377
+ const before = input.slice(0, caret);
4378
+ let match = "";
4379
+ for (const chip of pasteStore.keys()) {
4380
+ if (before.endsWith(chip) && chip.length > match.length) match = chip;
4381
+ }
4382
+ const cut = match ? match.length : 1;
4383
+ if (match) pasteStore.delete(match);
4384
+ setInput((s) => s.slice(0, caret - cut) + s.slice(caret));
4385
+ setCaret((i) => Math.max(0, i - cut));
3633
4386
  } else if (char && !key.ctrl && !key.meta && !key.tab) {
3634
4387
  const text = sanitizePaste(char);
3635
- if (text) setInput((s) => {
4388
+ if (text) {
4389
+ historyIndex = -1;
3636
4390
  setPaletteCursor(() => 0);
3637
4391
  setFilePickerCursor(() => 0);
3638
- return s + text;
3639
- });
4392
+ setInput((s) => s.slice(0, caret) + text + s.slice(caret));
4393
+ setCaret((i) => i + text.length);
4394
+ }
3640
4395
  }
3641
4396
  }
3642
4397
  });
@@ -3678,14 +4433,16 @@ async function checkForUpdate() {
3678
4433
  }
3679
4434
 
3680
4435
  // src/ui/App.tsx
3681
- import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
4436
+ import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
3682
4437
  function App() {
3683
4438
  const { exit } = useApp();
3684
4439
  const cwd = process.cwd().replace(homedir6(), "~").split(sep2).join("/");
3685
4440
  const [cfg, setCfg] = useState5(loadConfig());
3686
4441
  const [models, setModels] = useState5([]);
3687
- const [contexts, setContexts] = useState5({});
3688
- const [activeCtx, setActiveCtx] = useState5(null);
4442
+ const [contexts, setContexts] = useState5(() => cfg.modelContexts ?? {});
4443
+ const [activeCtx, setActiveCtx] = useState5(
4444
+ () => cfg.model ? cfg.modelContexts?.[cfg.model] ?? null : null
4445
+ );
3689
4446
  const [state, setState] = useState5("loading");
3690
4447
  const [cursor, setCursor] = useState5(0);
3691
4448
  const [pickerQuery, setPickerQuery] = useState5("");
@@ -3695,6 +4452,7 @@ function App() {
3695
4452
  const [sessions, setSessions] = useState5([]);
3696
4453
  const [notice, setNotice] = useState5(null);
3697
4454
  const [input, setInput] = useState5("");
4455
+ const [caret, setCaret] = useState5(0);
3698
4456
  const [paletteCursor, setPaletteCursor] = useState5(0);
3699
4457
  const [filePickerCursor, setFilePickerCursor] = useState5(0);
3700
4458
  const agent = useAgentRunner(cfg.model, activeCtx);
@@ -3736,12 +4494,20 @@ function App() {
3736
4494
  } else {
3737
4495
  setState(hasModel ? "ready" : "select-model");
3738
4496
  }
3739
- Promise.all(m.map((name) => modelContext3(name).then((ctx) => [name, ctx]))).then((pairs) => {
4497
+ Promise.all(
4498
+ m.map(
4499
+ (name) => modelContext3(name).then((ctx) => [name, ctx]).catch(() => [name, null])
4500
+ )
4501
+ ).then((pairs) => {
3740
4502
  if (stale()) return;
3741
4503
  const map = Object.fromEntries(pairs);
3742
4504
  setContexts(map);
4505
+ const resolved = Object.fromEntries(
4506
+ pairs.filter((p) => p[1] != null)
4507
+ );
4508
+ if (Object.keys(resolved).length) setModelContexts(resolved);
3743
4509
  const active2 = (hasModel ? cfg.model : void 0) ?? m[0];
3744
- if (active2 && map[active2]) setActiveCtx(map[active2]);
4510
+ if (active2 && map[active2] != null) setActiveCtx(map[active2]);
3745
4511
  }).catch(() => {
3746
4512
  });
3747
4513
  }).catch((err) => {
@@ -3786,6 +4552,8 @@ function App() {
3786
4552
  agent,
3787
4553
  input,
3788
4554
  setInput,
4555
+ caret,
4556
+ setCaret,
3789
4557
  paletteCursor,
3790
4558
  setPaletteCursor,
3791
4559
  filePickerCursor,
@@ -3806,10 +4574,10 @@ function App() {
3806
4574
  if (used < activeCtx * 0.7) return null;
3807
4575
  return Math.round(used / activeCtx * 100);
3808
4576
  })();
3809
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingX: 1, children: [
3810
- /* @__PURE__ */ jsx10(WelcomeBlock, { model: cfg.model, activeCtx, effort, cwd, error: agent.error, updateAvailable }),
3811
- state === "loading" && !agent.error && /* @__PURE__ */ jsx10(Box10, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: `connecting to ${provName}\u2026` }) }),
3812
- agent.error && state !== "ready" && /* @__PURE__ */ jsx10(
4577
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingX: 1, children: [
4578
+ state !== "ready" && /* @__PURE__ */ jsx13(WelcomeBlock, { model: cfg.model, activeCtx, effort, cwd, error: agent.error, updateAvailable }),
4579
+ state === "loading" && !agent.error && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: `connecting to ${provName}\u2026` }) }),
4580
+ agent.error && state !== "ready" && /* @__PURE__ */ jsx13(
3813
4581
  ChatView,
3814
4582
  {
3815
4583
  messages: [],
@@ -3819,7 +4587,7 @@ function App() {
3819
4587
  error: agent.error
3820
4588
  }
3821
4589
  ),
3822
- (state === "select-model" || state === "models") && /* @__PURE__ */ jsx10(
4590
+ (state === "select-model" || state === "models") && /* @__PURE__ */ jsx13(
3823
4591
  ModelsView,
3824
4592
  {
3825
4593
  models: filteredModels,
@@ -3832,7 +4600,7 @@ function App() {
3832
4600
  requireSelection: state === "select-model"
3833
4601
  }
3834
4602
  ),
3835
- state === "providers" && /* @__PURE__ */ jsx10(
4603
+ state === "providers" && /* @__PURE__ */ jsx13(
3836
4604
  ProviderPicker,
3837
4605
  {
3838
4606
  entries: filteredProviders,
@@ -3841,10 +4609,10 @@ function App() {
3841
4609
  query: pickerQuery
3842
4610
  }
3843
4611
  ),
3844
- state === "sessions" && /* @__PURE__ */ jsx10(SessionsView, { sessions, cursor }),
3845
- state === "ready" && /* @__PURE__ */ jsxs10(Fragment2, { children: [
3846
- notice && /* @__PURE__ */ jsx10(Box10, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx10(Text10, { color: "green", children: `\u2713 ${notice}` }) }),
3847
- /* @__PURE__ */ jsx10(
4612
+ state === "sessions" && /* @__PURE__ */ jsx13(SessionsView, { sessions, cursor }),
4613
+ state === "ready" && /* @__PURE__ */ jsxs13(Fragment3, { children: [
4614
+ notice && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: "green", children: `\u2713 ${notice}` }) }),
4615
+ /* @__PURE__ */ jsx13(
3848
4616
  ChatView,
3849
4617
  {
3850
4618
  messages: agent.messages,
@@ -3856,18 +4624,20 @@ function App() {
3856
4624
  pendingPermission: agent.pendingPermission,
3857
4625
  permissionCursor: agent.permissionCursor,
3858
4626
  activeToolUses: agent.activeToolUses,
3859
- activeToolResults: agent.activeToolResults
4627
+ activeToolResults: agent.activeToolResults,
4628
+ header: /* @__PURE__ */ jsx13(WelcomeBlock, { model: cfg.model, activeCtx, effort, cwd })
3860
4629
  }
3861
4630
  ),
3862
- input.startsWith("/") && /* @__PURE__ */ jsx10(CommandPalette, { filter: input, cursor: paletteCursor }),
3863
- contextWarning !== null && /* @__PURE__ */ jsx10(Box10, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx10(Text10, { color: "yellow", children: `\u26A0 context ${contextWarning}% full \u2014 run /clear and start fresh` }) }),
4631
+ updateAvailable && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: "yellow", children: `\u2191 update available: v${updateAvailable} \u2014 run: miii --update` }) }),
4632
+ input.startsWith("/") && /* @__PURE__ */ jsx13(CommandPalette, { filter: input, cursor: paletteCursor }),
4633
+ contextWarning !== null && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: "yellow", children: `\u26A0 context ${contextWarning}% full \u2014 run /clear and start fresh` }) }),
3864
4634
  !input.startsWith("/") && (() => {
3865
4635
  const m = parseMention(input);
3866
4636
  if (!m) return null;
3867
- return /* @__PURE__ */ jsx10(FilePicker, { matches: searchFiles(process.cwd(), m.query), cursor: filePickerCursor });
4637
+ return /* @__PURE__ */ jsx13(FilePicker, { matches: searchFiles(process.cwd(), m.query), cursor: filePickerCursor });
3868
4638
  })(),
3869
- /* @__PURE__ */ jsx10(InputBar, { input, disabled: agent.busy, processingLabel: agent.processingLabel }),
3870
- !agent.busy && /* @__PURE__ */ jsx10(Box10, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: providerDown ? "provider unavailable \u2014 /provider to switch \xB7 /models to pick a model" : "type / to see commands" }) })
4639
+ /* @__PURE__ */ jsx13(InputBar, { input, caret, disabled: agent.busy, processingLabel: agent.processingLabel }),
4640
+ !agent.busy && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: providerDown ? "provider unavailable \u2014 /provider to switch \xB7 /models to pick a model" : "type / to see commands" }) })
3871
4641
  ] })
3872
4642
  ] });
3873
4643
  }