reasonix 0.7.0 → 0.7.1
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/dist/cli/index.js +651 -106
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +19 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2663,6 +2663,11 @@ var CacheFirstLoop = class {
|
|
|
2663
2663
|
};
|
|
2664
2664
|
}
|
|
2665
2665
|
if (repairedCalls.length === 0) {
|
|
2666
|
+
const allSuppressed = report.stormsBroken > 0 && toolCalls.length > 0;
|
|
2667
|
+
if (allSuppressed) {
|
|
2668
|
+
yield* this.forceSummaryAfterIterLimit({ reason: "stuck" });
|
|
2669
|
+
return;
|
|
2670
|
+
}
|
|
2666
2671
|
this.autoCompactToolResultsOnTurnEnd();
|
|
2667
2672
|
yield { turn: this._turn, role: "done", content: assistantContent };
|
|
2668
2673
|
return;
|
|
@@ -2931,11 +2936,15 @@ function reasonPrefixFor(reason, iterCap) {
|
|
|
2931
2936
|
if (reason === "context-guard") {
|
|
2932
2937
|
return "[context budget running low \u2014 summarizing before the next call would overflow]";
|
|
2933
2938
|
}
|
|
2939
|
+
if (reason === "stuck") {
|
|
2940
|
+
return "[stuck on a repeated tool call \u2014 explaining what was tried and what's blocking progress]";
|
|
2941
|
+
}
|
|
2934
2942
|
return `[tool-call budget (${iterCap}) reached \u2014 forcing summary from what I found]`;
|
|
2935
2943
|
}
|
|
2936
2944
|
function errorLabelFor(reason, iterCap) {
|
|
2937
2945
|
if (reason === "aborted") return "aborted by user";
|
|
2938
2946
|
if (reason === "context-guard") return "context-guard triggered (prompt > 80% of window)";
|
|
2947
|
+
if (reason === "stuck") return "stuck (repeated tool call suppressed by storm-breaker)";
|
|
2939
2948
|
return `tool-call budget (${iterCap}) reached`;
|
|
2940
2949
|
}
|
|
2941
2950
|
function summarizeBranch(chosen, samples) {
|
|
@@ -5035,7 +5044,15 @@ async function runCommand(cmd, opts) {
|
|
|
5035
5044
|
shell: false,
|
|
5036
5045
|
// no shell-expansion — see header comment
|
|
5037
5046
|
windowsHide: true,
|
|
5038
|
-
|
|
5047
|
+
// PYTHONIOENCODING + PYTHONUTF8 force any spawned Python child
|
|
5048
|
+
// (run_command running `python script.py`, etc.) to emit UTF-8
|
|
5049
|
+
// on stdout/stderr. Without this, Chinese-Windows defaults
|
|
5050
|
+
// Python's stdout encoder to GBK and `print("…")` raises
|
|
5051
|
+
// UnicodeEncodeError on emoji / non-GBK chars — the model then
|
|
5052
|
+
// sees a Python traceback instead of the script's real output
|
|
5053
|
+
// and goes around in circles trying to fix the wrong problem.
|
|
5054
|
+
// Harmless on non-Python processes (env vars they don't read).
|
|
5055
|
+
env: { ...process.env, PYTHONIOENCODING: "utf-8", PYTHONUTF8: "1" }
|
|
5039
5056
|
};
|
|
5040
5057
|
const { bin, args, spawnOverrides } = prepareSpawn(argv);
|
|
5041
5058
|
const effectiveSpawnOpts = { ...spawnOpts, ...spawnOverrides };
|
|
@@ -5484,7 +5501,7 @@ function registerWebTools(registry, opts = {}) {
|
|
|
5484
5501
|
const maxFetchChars = opts.maxFetchChars ?? DEFAULT_FETCH_MAX_CHARS;
|
|
5485
5502
|
registry.register({
|
|
5486
5503
|
name: "web_search",
|
|
5487
|
-
description: "Search the public web. Returns ranked results with title, url, and snippet.
|
|
5504
|
+
description: "Search the public web. Returns ranked results with title, url, and snippet. Call this when the answer's correctness depends on current state \u2014 anything that changes over time (events, prices, releases, status of a thing in the real world). Composing such answers from training memory invents stale numbers; search first, then ground the answer in the results. For evergreen / definitional questions you don't need this.",
|
|
5488
5505
|
readOnly: true,
|
|
5489
5506
|
parameters: {
|
|
5490
5507
|
type: "object",
|
|
@@ -7099,7 +7116,7 @@ import { render } from "ink";
|
|
|
7099
7116
|
import React23, { useState as useState12 } from "react";
|
|
7100
7117
|
|
|
7101
7118
|
// src/cli/ui/App.tsx
|
|
7102
|
-
import { Box as Box19, Static, useApp, useInput as useInput5 } from "ink";
|
|
7119
|
+
import { Box as Box19, Static, useApp, useInput as useInput5, useStdout as useStdout4 } from "ink";
|
|
7103
7120
|
import React20, { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo3, useRef as useRef5, useState as useState10 } from "react";
|
|
7104
7121
|
|
|
7105
7122
|
// src/code/pending-edits.ts
|
|
@@ -7853,13 +7870,136 @@ function toSubscript(s) {
|
|
|
7853
7870
|
return out;
|
|
7854
7871
|
}
|
|
7855
7872
|
function stripMath(s) {
|
|
7856
|
-
return s.replace(
|
|
7873
|
+
return s.replace(/\$\$([\s\S]+?)\$\$/g, (_m, c) => `
|
|
7874
|
+
|
|
7875
|
+
${c.trim()}
|
|
7876
|
+
|
|
7877
|
+
`).replace(/(?<!\$)\$(?!\s)([^$\n]+?)(?<!\s)\$(?!\$)/g, "$1").replace(/\\\(\s*/g, "").replace(/\s*\\\)/g, "").replace(/\\\[\s*/g, "\n").replace(/\s*\\\]/g, "\n").replace(
|
|
7857
7878
|
/\\[dt]?frac\s*\{((?:[^{}]|\{[^{}]*\})+)\}\s*\{((?:[^{}]|\{[^{}]*\})+)\}/g,
|
|
7858
7879
|
(_m, num, den) => `(${num.trim()})/(${den.trim()})`
|
|
7859
7880
|
).replace(
|
|
7860
7881
|
/\\binom\s*\{([^{}]+)\}\s*\{([^{}]+)\}/g,
|
|
7861
7882
|
(_m, n, k) => `C(${n.trim()},${k.trim()})`
|
|
7862
|
-
).replace(/\\sqrt\s*\{([^{}]+)\}/g, (_m, g) => `\u221A(${g.trim()})`).replace(/\\boxed\s*\{([^{}]+)\}/g, (_m, g) => `\u3010${g.trim()}\u3011`).replace(/\\text\s*\{([^{}]+)\}/g, (_m, g) => g.trim()).replace(/\\overline\s*\{([^{}]+)\}/g, (_m, g) => `${g.trim()}\u0304`).replace(/\\hat\s*\{([^{}]+)\}/g, (_m, g) => `${g.trim()}\u0302`).replace(/\\vec\s*\{([^{}]+)\}/g, (_m, g) => `\u2192${g.trim()}`).replace(/\\cdot/g, "\xB7").replace(/\\times/g, "\xD7").replace(/\\div/g, "\xF7").replace(/\\pm/g, "\xB1").replace(/\\mp/g, "\u2213").replace(/\\leq/g, "\u2264").replace(/\\geq/g, "\u2265").replace(/\\neq/g, "\u2260").replace(/\\approx/g, "\u2248").replace(/\\in
|
|
7883
|
+
).replace(/\\sqrt\s*\{([^{}]+)\}/g, (_m, g) => `\u221A(${g.trim()})`).replace(/\\boxed\s*\{([^{}]+)\}/g, (_m, g) => `\u3010${g.trim()}\u3011`).replace(/\\text\s*\{([^{}]+)\}/g, (_m, g) => g.trim()).replace(/\\overline\s*\{([^{}]+)\}/g, (_m, g) => `${g.trim()}\u0304`).replace(/\\hat\s*\{([^{}]+)\}/g, (_m, g) => `${g.trim()}\u0302`).replace(/\\vec\s*\{([^{}]+)\}/g, (_m, g) => `\u2192${g.trim()}`).replace(/\\cdot/g, "\xB7").replace(/\\times/g, "\xD7").replace(/\\div/g, "\xF7").replace(/\\pm/g, "\xB1").replace(/\\mp/g, "\u2213").replace(/\\leq/g, "\u2264").replace(/\\geq/g, "\u2265").replace(/\\neq/g, "\u2260").replace(/\\approx/g, "\u2248").replace(/\\in(?![a-zA-Z])/g, "\u2208").replace(/\\notin(?![a-zA-Z])/g, "\u2209").replace(/\\infty/g, "\u221E").replace(/\\sum(?![a-zA-Z])/g, "\u03A3").replace(/\\prod(?![a-zA-Z])/g, "\u03A0").replace(/\\int(?![a-zA-Z])/g, "\u222B").replace(/\\alpha/g, "\u03B1").replace(/\\beta/g, "\u03B2").replace(/\\gamma/g, "\u03B3").replace(/\\delta/g, "\u03B4").replace(/\\theta/g, "\u03B8").replace(/\\lambda/g, "\u03BB").replace(/\\mu/g, "\u03BC").replace(/\\pi/g, "\u03C0").replace(/\\sigma/g, "\u03C3").replace(/\\phi/g, "\u03C6").replace(/\\omega/g, "\u03C9").replace(/\\implies(?![a-zA-Z])/g, "\u21D2").replace(/\\iff(?![a-zA-Z])/g, "\u21D4").replace(/\\to(?![a-zA-Z])/g, "\u2192").replace(/\\rightarrow/g, "\u2192").replace(/\\Rightarrow/g, "\u21D2").replace(/\\leftarrow/g, "\u2190").replace(/\\Leftarrow/g, "\u21D0").replace(/\\ldots/g, "\u2026").replace(/\\cdots/g, "\u22EF").replace(/\\quad/g, " ").replace(/\\qquad/g, " ").replace(/\\,/g, " ").replace(/\\;/g, " ").replace(/\\!/g, "").replace(/\\\\/g, "\n").replace(/\^([A-Za-z0-9+\-]+)\^/g, (m, g) => {
|
|
7884
|
+
for (const c of g) if (SUPERSCRIPT[c] === void 0) return m;
|
|
7885
|
+
return toSuperscript(g);
|
|
7886
|
+
}).replace(/(?<!~)~(?!~)([A-Za-z0-9+\-]+)~(?!~)/g, (m, g) => {
|
|
7887
|
+
for (const c of g) if (SUBSCRIPT[c] === void 0) return m;
|
|
7888
|
+
return toSubscript(g);
|
|
7889
|
+
}).replace(/\^\{([\w+-]+)\}/g, (_m, g) => toSuperscript(g)).replace(/\^([0-9+\-n])/g, (_m, g) => toSuperscript(g)).replace(/_\{([\w+-]+)\}/g, (_m, g) => toSubscript(g)).replace(/_([0-9+\-])/g, (_m, g) => toSubscript(g)).replace(/\\[a-zA-Z]+\s*\{([^{}]+)\}\s*\{([^{}]+)\}/g, "($1)/($2)").replace(/\\[a-zA-Z]+\s*\{([^{}]+)\}/g, "$1").replace(/\\[a-zA-Z]+/g, "").replace(/[ \t]{2,}/g, " ");
|
|
7890
|
+
}
|
|
7891
|
+
var EMOJI_MAP = {
|
|
7892
|
+
// faces
|
|
7893
|
+
smile: "\u{1F604}",
|
|
7894
|
+
smiley: "\u{1F603}",
|
|
7895
|
+
grin: "\u{1F601}",
|
|
7896
|
+
grinning: "\u{1F600}",
|
|
7897
|
+
joy: "\u{1F602}",
|
|
7898
|
+
laughing: "\u{1F606}",
|
|
7899
|
+
heart_eyes: "\u{1F60D}",
|
|
7900
|
+
blush: "\u{1F60A}",
|
|
7901
|
+
sunglasses: "\u{1F60E}",
|
|
7902
|
+
thinking: "\u{1F914}",
|
|
7903
|
+
neutral_face: "\u{1F610}",
|
|
7904
|
+
confused: "\u{1F615}",
|
|
7905
|
+
cry: "\u{1F622}",
|
|
7906
|
+
sob: "\u{1F62D}",
|
|
7907
|
+
rage: "\u{1F621}",
|
|
7908
|
+
angry: "\u{1F620}",
|
|
7909
|
+
scream: "\u{1F631}",
|
|
7910
|
+
wink: "\u{1F609}",
|
|
7911
|
+
kissing_heart: "\u{1F618}",
|
|
7912
|
+
// hearts
|
|
7913
|
+
heart: "\u2764\uFE0F",
|
|
7914
|
+
orange_heart: "\u{1F9E1}",
|
|
7915
|
+
yellow_heart: "\u{1F49B}",
|
|
7916
|
+
green_heart: "\u{1F49A}",
|
|
7917
|
+
blue_heart: "\u{1F499}",
|
|
7918
|
+
purple_heart: "\u{1F49C}",
|
|
7919
|
+
black_heart: "\u{1F5A4}",
|
|
7920
|
+
white_heart: "\u{1F90D}",
|
|
7921
|
+
broken_heart: "\u{1F494}",
|
|
7922
|
+
sparkling_heart: "\u{1F496}",
|
|
7923
|
+
two_hearts: "\u{1F495}",
|
|
7924
|
+
// gestures
|
|
7925
|
+
"+1": "\u{1F44D}",
|
|
7926
|
+
"-1": "\u{1F44E}",
|
|
7927
|
+
thumbsup: "\u{1F44D}",
|
|
7928
|
+
thumbsdown: "\u{1F44E}",
|
|
7929
|
+
wave: "\u{1F44B}",
|
|
7930
|
+
clap: "\u{1F44F}",
|
|
7931
|
+
muscle: "\u{1F4AA}",
|
|
7932
|
+
ok_hand: "\u{1F44C}",
|
|
7933
|
+
pray: "\u{1F64F}",
|
|
7934
|
+
fist: "\u270A",
|
|
7935
|
+
point_up: "\u261D\uFE0F",
|
|
7936
|
+
raised_hands: "\u{1F64C}",
|
|
7937
|
+
handshake: "\u{1F91D}",
|
|
7938
|
+
// symbols / signals
|
|
7939
|
+
rocket: "\u{1F680}",
|
|
7940
|
+
fire: "\u{1F525}",
|
|
7941
|
+
star: "\u2B50",
|
|
7942
|
+
star2: "\u{1F31F}",
|
|
7943
|
+
sparkles: "\u2728",
|
|
7944
|
+
boom: "\u{1F4A5}",
|
|
7945
|
+
zap: "\u26A1",
|
|
7946
|
+
tada: "\u{1F389}",
|
|
7947
|
+
bulb: "\u{1F4A1}",
|
|
7948
|
+
warning: "\u26A0\uFE0F",
|
|
7949
|
+
x: "\u274C",
|
|
7950
|
+
white_check_mark: "\u2705",
|
|
7951
|
+
heavy_check_mark: "\u2714\uFE0F",
|
|
7952
|
+
ballot_box_with_check: "\u2611\uFE0F",
|
|
7953
|
+
no_entry: "\u26D4",
|
|
7954
|
+
question: "\u2753",
|
|
7955
|
+
exclamation: "\u2757",
|
|
7956
|
+
bangbang: "\u203C\uFE0F",
|
|
7957
|
+
bell: "\u{1F514}",
|
|
7958
|
+
mute: "\u{1F515}",
|
|
7959
|
+
hundred: "\u{1F4AF}",
|
|
7960
|
+
"100": "\u{1F4AF}",
|
|
7961
|
+
eyes: "\u{1F440}",
|
|
7962
|
+
// tech / productivity
|
|
7963
|
+
computer: "\u{1F4BB}",
|
|
7964
|
+
iphone: "\u{1F4F1}",
|
|
7965
|
+
hammer: "\u{1F528}",
|
|
7966
|
+
wrench: "\u{1F527}",
|
|
7967
|
+
gear: "\u2699\uFE0F",
|
|
7968
|
+
package: "\u{1F4E6}",
|
|
7969
|
+
floppy_disk: "\u{1F4BE}",
|
|
7970
|
+
key: "\u{1F511}",
|
|
7971
|
+
lock: "\u{1F512}",
|
|
7972
|
+
unlock: "\u{1F513}",
|
|
7973
|
+
mag: "\u{1F50D}",
|
|
7974
|
+
memo: "\u{1F4DD}",
|
|
7975
|
+
pencil: "\u270F\uFE0F",
|
|
7976
|
+
bookmark: "\u{1F516}",
|
|
7977
|
+
// charts / time
|
|
7978
|
+
chart_with_upwards_trend: "\u{1F4C8}",
|
|
7979
|
+
chart_with_downwards_trend: "\u{1F4C9}",
|
|
7980
|
+
bar_chart: "\u{1F4CA}",
|
|
7981
|
+
hourglass: "\u23F3",
|
|
7982
|
+
calendar: "\u{1F4C5}",
|
|
7983
|
+
// misc
|
|
7984
|
+
robot: "\u{1F916}",
|
|
7985
|
+
ghost: "\u{1F47B}",
|
|
7986
|
+
bug: "\u{1F41B}",
|
|
7987
|
+
coffee: "\u2615",
|
|
7988
|
+
beer: "\u{1F37A}",
|
|
7989
|
+
sun: "\u2600\uFE0F",
|
|
7990
|
+
cloud: "\u2601\uFE0F",
|
|
7991
|
+
rainbow: "\u{1F308}",
|
|
7992
|
+
speech_balloon: "\u{1F4AC}",
|
|
7993
|
+
thought_balloon: "\u{1F4AD}",
|
|
7994
|
+
construction: "\u{1F6A7}"
|
|
7995
|
+
};
|
|
7996
|
+
function expandAutolinks(s) {
|
|
7997
|
+
return s.replace(/<((?:https?|ftp|mailto):[^\s<>]+)>/g, "[$1]($1)");
|
|
7998
|
+
}
|
|
7999
|
+
function expandEmoji(s) {
|
|
8000
|
+
return s.replace(/:([a-z0-9_+-]+):/gi, (m, name) => {
|
|
8001
|
+
return EMOJI_MAP[name.toLowerCase()] ?? m;
|
|
8002
|
+
});
|
|
7863
8003
|
}
|
|
7864
8004
|
function isExternalUrl(url) {
|
|
7865
8005
|
return /^[a-z][a-z0-9+.-]*:\/\//i.test(url) || url.startsWith("mailto:") || url.startsWith("//");
|
|
@@ -7914,18 +8054,25 @@ function validateCitation(url, projectRoot) {
|
|
|
7914
8054
|
}
|
|
7915
8055
|
return { ok: true };
|
|
7916
8056
|
}
|
|
8057
|
+
function shouldValidateAsCitation(url) {
|
|
8058
|
+
if (url.startsWith("#")) return false;
|
|
8059
|
+
if (url === "/" || url === "\\" || url === "") return false;
|
|
8060
|
+
if (!/[/\\.]/.test(url)) return false;
|
|
8061
|
+
return true;
|
|
8062
|
+
}
|
|
7917
8063
|
function collectCitations(text, projectRoot) {
|
|
7918
8064
|
const map = /* @__PURE__ */ new Map();
|
|
7919
8065
|
const re = /\[([^\]\n]+)\]\(([^)\n]+)\)/g;
|
|
7920
8066
|
for (const m of text.matchAll(re)) {
|
|
7921
8067
|
const url = m[2] ?? "";
|
|
7922
8068
|
if (!url || isExternalUrl(url)) continue;
|
|
8069
|
+
if (!shouldValidateAsCitation(url)) continue;
|
|
7923
8070
|
if (map.has(url)) continue;
|
|
7924
8071
|
map.set(url, validateCitation(url, projectRoot));
|
|
7925
8072
|
}
|
|
7926
8073
|
return map;
|
|
7927
8074
|
}
|
|
7928
|
-
var INLINE_RE = /(\[([^\]\n]+)\]\(([^)\n]+)\)
|
|
8075
|
+
var INLINE_RE = /(\[([^\]\n]+)\]\(([^)\n]+)\)|\*\*\*([^*\n]+?)\*\*\*|\*\*([^*\n]+?)\*\*|```([^\n]+?)```|`([^`\n]+?)`|~~([^~\n]+?)~~|(?<![*\w])\*([^*\n]+?)\*(?!\w)|\\([*_~`[\](){}#+\-.!\\]))/g;
|
|
7929
8076
|
function InlineMd({
|
|
7930
8077
|
text,
|
|
7931
8078
|
padTo,
|
|
@@ -7960,21 +8107,31 @@ function InlineMd({
|
|
|
7960
8107
|
}
|
|
7961
8108
|
} else if (m[4] !== void 0) {
|
|
7962
8109
|
parts.push(
|
|
7963
|
-
/* @__PURE__ */ React7.createElement(Text7, { key: `
|
|
8110
|
+
/* @__PURE__ */ React7.createElement(Text7, { key: `bi${idx++}`, bold: true, italic: true }, m[4])
|
|
7964
8111
|
);
|
|
7965
8112
|
} else if (m[5] !== void 0) {
|
|
7966
|
-
const stripped = m[5].replace(/^(\w+)\s+/, "");
|
|
7967
8113
|
parts.push(
|
|
7968
|
-
/* @__PURE__ */ React7.createElement(Text7, { key: `
|
|
8114
|
+
/* @__PURE__ */ React7.createElement(Text7, { key: `b${idx++}`, bold: true }, m[5])
|
|
7969
8115
|
);
|
|
7970
8116
|
} else if (m[6] !== void 0) {
|
|
8117
|
+
const stripped = m[6].replace(/^(\w+)\s+/, "");
|
|
7971
8118
|
parts.push(
|
|
7972
|
-
/* @__PURE__ */ React7.createElement(Text7, { key: `c${idx++}`, color: "yellow" },
|
|
8119
|
+
/* @__PURE__ */ React7.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, stripped)
|
|
7973
8120
|
);
|
|
7974
8121
|
} else if (m[7] !== void 0) {
|
|
7975
8122
|
parts.push(
|
|
7976
|
-
/* @__PURE__ */ React7.createElement(Text7, { key: `
|
|
8123
|
+
/* @__PURE__ */ React7.createElement(Text7, { key: `c${idx++}`, color: "yellow" }, m[7])
|
|
8124
|
+
);
|
|
8125
|
+
} else if (m[8] !== void 0) {
|
|
8126
|
+
parts.push(
|
|
8127
|
+
/* @__PURE__ */ React7.createElement(Text7, { key: `s${idx++}`, strikethrough: true, dimColor: true }, m[8])
|
|
8128
|
+
);
|
|
8129
|
+
} else if (m[9] !== void 0) {
|
|
8130
|
+
parts.push(
|
|
8131
|
+
/* @__PURE__ */ React7.createElement(Text7, { key: `i${idx++}`, italic: true }, m[9])
|
|
7977
8132
|
);
|
|
8133
|
+
} else if (m[10] !== void 0) {
|
|
8134
|
+
parts.push(/* @__PURE__ */ React7.createElement(Text7, { key: `esc${idx++}` }, m[10]));
|
|
7978
8135
|
}
|
|
7979
8136
|
last = start + m[0].length;
|
|
7980
8137
|
}
|
|
@@ -7990,7 +8147,20 @@ function InlineMd({
|
|
|
7990
8147
|
return /* @__PURE__ */ React7.createElement(Text7, null, parts);
|
|
7991
8148
|
}
|
|
7992
8149
|
function stripInlineMarkup(s) {
|
|
7993
|
-
return s.replace(
|
|
8150
|
+
return s.replace(
|
|
8151
|
+
INLINE_RE,
|
|
8152
|
+
(match, _alt, linkText, _url, boldItalic, bold, code3, code1, strike, italic, escapeChar) => {
|
|
8153
|
+
if (linkText !== void 0) return linkText;
|
|
8154
|
+
if (boldItalic !== void 0) return boldItalic;
|
|
8155
|
+
if (bold !== void 0) return bold;
|
|
8156
|
+
if (code3 !== void 0) return code3.replace(/^(\w+)\s+/, "");
|
|
8157
|
+
if (code1 !== void 0) return code1;
|
|
8158
|
+
if (strike !== void 0) return strike;
|
|
8159
|
+
if (italic !== void 0) return italic;
|
|
8160
|
+
if (escapeChar !== void 0) return escapeChar;
|
|
8161
|
+
return match;
|
|
8162
|
+
}
|
|
8163
|
+
);
|
|
7994
8164
|
}
|
|
7995
8165
|
function visibleWidth(s) {
|
|
7996
8166
|
return displayWidth(stripInlineMarkup(s));
|
|
@@ -8005,10 +8175,16 @@ function parseBlocks(raw) {
|
|
|
8005
8175
|
let listBuf = null;
|
|
8006
8176
|
let codeFence = "";
|
|
8007
8177
|
const flushPara = () => {
|
|
8008
|
-
if (para.length)
|
|
8009
|
-
|
|
8010
|
-
|
|
8178
|
+
if (para.length === 0) return;
|
|
8179
|
+
let joined = "";
|
|
8180
|
+
for (let k = 0; k < para.length; k++) {
|
|
8181
|
+
joined += para[k].text;
|
|
8182
|
+
if (k < para.length - 1) {
|
|
8183
|
+
joined += para[k].hardBreak ? "\n" : " ";
|
|
8184
|
+
}
|
|
8011
8185
|
}
|
|
8186
|
+
out.push({ kind: "paragraph", text: joined });
|
|
8187
|
+
para = [];
|
|
8012
8188
|
};
|
|
8013
8189
|
const flushList = () => {
|
|
8014
8190
|
if (listBuf) {
|
|
@@ -8020,7 +8196,7 @@ function parseBlocks(raw) {
|
|
|
8020
8196
|
const rawLine = lines[i];
|
|
8021
8197
|
const line = rawLine.replace(/\s+$/g, "");
|
|
8022
8198
|
if (!inCode && /^<{7} SEARCH\s*$/.test(line)) {
|
|
8023
|
-
const filename = para.pop()?.trim();
|
|
8199
|
+
const filename = para.pop()?.text.trim();
|
|
8024
8200
|
if (filename) {
|
|
8025
8201
|
flushPara();
|
|
8026
8202
|
flushList();
|
|
@@ -8046,7 +8222,7 @@ function parseBlocks(raw) {
|
|
|
8046
8222
|
i = k;
|
|
8047
8223
|
continue;
|
|
8048
8224
|
}
|
|
8049
|
-
para.push(filename);
|
|
8225
|
+
para.push({ text: filename, hardBreak: false });
|
|
8050
8226
|
}
|
|
8051
8227
|
}
|
|
8052
8228
|
if (!inCode) {
|
|
@@ -8150,6 +8326,23 @@ function parseBlocks(raw) {
|
|
|
8150
8326
|
continue;
|
|
8151
8327
|
}
|
|
8152
8328
|
}
|
|
8329
|
+
const quoteMatch = line.match(/^\s*>\s?(.*)$/);
|
|
8330
|
+
if (quoteMatch) {
|
|
8331
|
+
flushPara();
|
|
8332
|
+
flushList();
|
|
8333
|
+
const innerLines = [quoteMatch[1] ?? ""];
|
|
8334
|
+
let j = i + 1;
|
|
8335
|
+
while (j < lines.length) {
|
|
8336
|
+
const nxt = lines[j].replace(/\s+$/g, "");
|
|
8337
|
+
const m = nxt.match(/^\s*>\s?(.*)$/);
|
|
8338
|
+
if (!m) break;
|
|
8339
|
+
innerLines.push(m[1] ?? "");
|
|
8340
|
+
j++;
|
|
8341
|
+
}
|
|
8342
|
+
out.push({ kind: "quote", children: parseBlocks(innerLines.join("\n")) });
|
|
8343
|
+
i = j - 1;
|
|
8344
|
+
continue;
|
|
8345
|
+
}
|
|
8153
8346
|
const bm = line.match(/^\s*[-*+]\s+(.+)$/);
|
|
8154
8347
|
if (bm) {
|
|
8155
8348
|
flushPara();
|
|
@@ -8157,7 +8350,7 @@ function parseBlocks(raw) {
|
|
|
8157
8350
|
flushList();
|
|
8158
8351
|
listBuf = { kind: "bullet", items: [], ordered: false, start: 1 };
|
|
8159
8352
|
}
|
|
8160
|
-
listBuf.items.push(bm[1]);
|
|
8353
|
+
listBuf.items.push(parseBulletItem(bm[1]));
|
|
8161
8354
|
continue;
|
|
8162
8355
|
}
|
|
8163
8356
|
const om = line.match(/^\s*(\d+)\.\s+(.+)$/);
|
|
@@ -8167,11 +8360,12 @@ function parseBlocks(raw) {
|
|
|
8167
8360
|
flushList();
|
|
8168
8361
|
listBuf = { kind: "bullet", items: [], ordered: true, start: Number(om[1]) };
|
|
8169
8362
|
}
|
|
8170
|
-
listBuf.items.push(om[2]);
|
|
8363
|
+
listBuf.items.push(parseBulletItem(om[2]));
|
|
8171
8364
|
continue;
|
|
8172
8365
|
}
|
|
8173
8366
|
flushList();
|
|
8174
|
-
|
|
8367
|
+
const hardBreak = / {2,}\r?$/.test(rawLine);
|
|
8368
|
+
para.push({ text: line, hardBreak });
|
|
8175
8369
|
}
|
|
8176
8370
|
if (inCode && codeBuf.length) {
|
|
8177
8371
|
out.push({ kind: "code", lang: codeLang, text: codeBuf.join("\n") });
|
|
@@ -8180,15 +8374,26 @@ function parseBlocks(raw) {
|
|
|
8180
8374
|
flushList();
|
|
8181
8375
|
return out;
|
|
8182
8376
|
}
|
|
8377
|
+
function parseBulletItem(raw) {
|
|
8378
|
+
const m = raw.match(/^\[([ xX])\]\s+(.*)$/);
|
|
8379
|
+
if (!m) return { text: raw };
|
|
8380
|
+
const done = m[1].toLowerCase() === "x";
|
|
8381
|
+
return { text: m[2] ?? "", task: done ? "done" : "todo" };
|
|
8382
|
+
}
|
|
8183
8383
|
function BlockView({ block, citations }) {
|
|
8184
8384
|
switch (block.kind) {
|
|
8185
8385
|
case "heading":
|
|
8186
8386
|
return /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "cyan" }, /* @__PURE__ */ React7.createElement(InlineMd, { text: block.text, citations }));
|
|
8187
8387
|
case "paragraph":
|
|
8188
|
-
return /* @__PURE__ */ React7.createElement(
|
|
8388
|
+
return /* @__PURE__ */ React7.createElement(ParagraphView, { text: block.text, citations });
|
|
8189
8389
|
case "bullet":
|
|
8190
|
-
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, block.items.map((item, i) => /* @__PURE__ */ React7.createElement(Box7, { key: `${i}-${item.slice(0, 24)}` }, /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, block.
|
|
8390
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, block.items.map((item, i) => /* @__PURE__ */ React7.createElement(Box7, { key: `${i}-${item.text.slice(0, 24)}` }, /* @__PURE__ */ React7.createElement(Text7, { color: item.task === "done" ? "green" : "cyan" }, bulletPrefix(block, i, item)), item.task === "done" ? /* @__PURE__ */ React7.createElement(Text7, { strikethrough: true, dimColor: true }, /* @__PURE__ */ React7.createElement(InlineMd, { text: item.text, citations })) : /* @__PURE__ */ React7.createElement(InlineMd, { text: item.text, citations }))));
|
|
8391
|
+
case "quote":
|
|
8392
|
+
return /* @__PURE__ */ React7.createElement(BlockquoteView, { block, citations });
|
|
8191
8393
|
case "code":
|
|
8394
|
+
if (DIAGRAM_LANGS.has(block.lang.toLowerCase())) {
|
|
8395
|
+
return /* @__PURE__ */ React7.createElement(DiagramCodeBlock, { lang: block.lang, text: block.text });
|
|
8396
|
+
}
|
|
8192
8397
|
return /* @__PURE__ */ React7.createElement(Box7, { borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "yellow" }, block.text));
|
|
8193
8398
|
case "edit-block":
|
|
8194
8399
|
return /* @__PURE__ */ React7.createElement(EditBlockRow, { block });
|
|
@@ -8198,6 +8403,42 @@ function BlockView({ block, citations }) {
|
|
|
8198
8403
|
return /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
8199
8404
|
}
|
|
8200
8405
|
}
|
|
8406
|
+
function ParagraphView({ text, citations }) {
|
|
8407
|
+
if (!text.includes("\n")) {
|
|
8408
|
+
return /* @__PURE__ */ React7.createElement(InlineMd, { text, citations });
|
|
8409
|
+
}
|
|
8410
|
+
const rows = text.split("\n");
|
|
8411
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, rows.map((row2, i) => (
|
|
8412
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: hard-break rows are source-ordered and never reorder
|
|
8413
|
+
/* @__PURE__ */ React7.createElement(InlineMd, { key: `ln-${i}`, text: row2, citations })
|
|
8414
|
+
)));
|
|
8415
|
+
}
|
|
8416
|
+
function bulletPrefix(block, i, item) {
|
|
8417
|
+
if (block.ordered) return ` ${block.start + i}. `;
|
|
8418
|
+
if (item.task === "done") return " \u2612 ";
|
|
8419
|
+
if (item.task === "todo") return " \u2610 ";
|
|
8420
|
+
return " \u2022 ";
|
|
8421
|
+
}
|
|
8422
|
+
function BlockquoteView({
|
|
8423
|
+
block,
|
|
8424
|
+
citations
|
|
8425
|
+
}) {
|
|
8426
|
+
return /* @__PURE__ */ React7.createElement(
|
|
8427
|
+
Box7,
|
|
8428
|
+
{
|
|
8429
|
+
borderStyle: "single",
|
|
8430
|
+
borderColor: "gray",
|
|
8431
|
+
borderDimColor: true,
|
|
8432
|
+
borderTop: false,
|
|
8433
|
+
borderRight: false,
|
|
8434
|
+
borderBottom: false,
|
|
8435
|
+
paddingLeft: 1,
|
|
8436
|
+
flexDirection: "column",
|
|
8437
|
+
gap: 1
|
|
8438
|
+
},
|
|
8439
|
+
block.children.map((child, i) => /* @__PURE__ */ React7.createElement(BlockView, { key: `q-${i}-${child.kind}`, block: child, citations }))
|
|
8440
|
+
);
|
|
8441
|
+
}
|
|
8201
8442
|
function splitTableRow(line) {
|
|
8202
8443
|
const SENTINEL = "\0";
|
|
8203
8444
|
const masked = line.replace(/\\\|/g, SENTINEL).replace(/│/g, "|");
|
|
@@ -8242,8 +8483,30 @@ function EditBlockRow({ block }) {
|
|
|
8242
8483
|
const replaceLines = block.replace.split("\n");
|
|
8243
8484
|
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "cyan" }, block.filename), isNewFile ? /* @__PURE__ */ React7.createElement(Text7, { color: "green", bold: true }, " (new file)") : null), isNewFile ? null : /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", marginTop: 1 }, searchLines.map((line, i) => /* @__PURE__ */ React7.createElement(Text7, { key: `s-${i}-${line.length}`, color: "red" }, `- ${line}`))), /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", marginTop: isNewFile ? 1 : 0 }, replaceLines.map((line, i) => /* @__PURE__ */ React7.createElement(Text7, { key: `r-${i}-${line.length}`, color: "green" }, `+ ${line}`))));
|
|
8244
8485
|
}
|
|
8486
|
+
var DIAGRAM_LANGS = /* @__PURE__ */ new Set([
|
|
8487
|
+
"mermaid",
|
|
8488
|
+
"dot",
|
|
8489
|
+
"graphviz",
|
|
8490
|
+
"plantuml",
|
|
8491
|
+
"puml",
|
|
8492
|
+
"flowchart",
|
|
8493
|
+
"sequencediagram",
|
|
8494
|
+
"gantt",
|
|
8495
|
+
"erdiagram"
|
|
8496
|
+
]);
|
|
8497
|
+
var DIAGRAM_VIEWER_HINT = {
|
|
8498
|
+
mermaid: "\u2192 paste at https://mermaid.live to view",
|
|
8499
|
+
plantuml: "\u2192 paste at https://www.plantuml.com/plantuml to view",
|
|
8500
|
+
puml: "\u2192 paste at https://www.plantuml.com/plantuml to view",
|
|
8501
|
+
dot: "\u2192 paste at https://dreampuf.github.io/GraphvizOnline to view",
|
|
8502
|
+
graphviz: "\u2192 paste at https://dreampuf.github.io/GraphvizOnline to view"
|
|
8503
|
+
};
|
|
8504
|
+
function DiagramCodeBlock({ lang, text }) {
|
|
8505
|
+
const hint = DIAGRAM_VIEWER_HINT[lang.toLowerCase()] ?? "\u2192 render with the matching viewer to view";
|
|
8506
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", borderStyle: "double", borderColor: "magenta", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "magenta" }, `\u25C7 ${lang} diagram (source \u2014 terminal can't draw the graph)`), /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "yellow" }, text)), /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, hint)));
|
|
8507
|
+
}
|
|
8245
8508
|
function Markdown({ text, projectRoot }) {
|
|
8246
|
-
const cleaned = stripMath(text);
|
|
8509
|
+
const cleaned = expandAutolinks(expandEmoji(stripMath(text)));
|
|
8247
8510
|
const root = projectRoot ?? process.cwd();
|
|
8248
8511
|
const citations = React7.useMemo(() => collectCitations(cleaned, root), [cleaned, root]);
|
|
8249
8512
|
const blocks = React7.useMemo(() => parseBlocks(cleaned), [cleaned]);
|
|
@@ -8910,12 +9173,27 @@ import React15, { useRef, useState as useState5 } from "react";
|
|
|
8910
9173
|
// src/cli/ui/multiline-keys.ts
|
|
8911
9174
|
var BACKSLASH_SUFFIX = /\\$/;
|
|
8912
9175
|
var NOOP = { next: null, cursor: null, submit: false };
|
|
8913
|
-
function
|
|
8914
|
-
if (key.
|
|
9176
|
+
function rewriteRawArrowEscape(key) {
|
|
9177
|
+
if (key.upArrow || key.downArrow || key.leftArrow || key.rightArrow) return key;
|
|
9178
|
+
if (key.input === "\x1B[A") return { ...key, upArrow: true, input: "" };
|
|
9179
|
+
if (key.input === "\x1B[B") return { ...key, downArrow: true, input: "" };
|
|
9180
|
+
if (key.input === "\x1B[C") return { ...key, rightArrow: true, input: "" };
|
|
9181
|
+
if (key.input === "\x1B[D") return { ...key, leftArrow: true, input: "" };
|
|
9182
|
+
return key;
|
|
9183
|
+
}
|
|
9184
|
+
function processMultilineKey(value, cursor, keyIn) {
|
|
9185
|
+
const key = rewriteRawArrowEscape(keyIn);
|
|
9186
|
+
if (key.tab || key.escape) {
|
|
8915
9187
|
return NOOP;
|
|
8916
9188
|
}
|
|
9189
|
+
if (key.pageUp) {
|
|
9190
|
+
return cursor === 0 ? NOOP : { next: null, cursor: 0, submit: false };
|
|
9191
|
+
}
|
|
9192
|
+
if (key.pageDown) {
|
|
9193
|
+
return cursor === value.length ? NOOP : { next: null, cursor: value.length, submit: false };
|
|
9194
|
+
}
|
|
8917
9195
|
if (value.length === 0 && (key.upArrow || key.downArrow)) {
|
|
8918
|
-
return NOOP;
|
|
9196
|
+
return { ...NOOP, historyHandoff: key.upArrow ? "prev" : "next" };
|
|
8919
9197
|
}
|
|
8920
9198
|
if (key.leftArrow) {
|
|
8921
9199
|
return { next: null, cursor: Math.max(0, cursor - 1), submit: false };
|
|
@@ -8925,11 +9203,13 @@ function processMultilineKey(value, cursor, key) {
|
|
|
8925
9203
|
}
|
|
8926
9204
|
if (key.upArrow) {
|
|
8927
9205
|
const moved = moveCursorUp(value, cursor);
|
|
8928
|
-
|
|
9206
|
+
if (moved === cursor) return { ...NOOP, historyHandoff: "prev" };
|
|
9207
|
+
return { next: null, cursor: moved, submit: false };
|
|
8929
9208
|
}
|
|
8930
9209
|
if (key.downArrow) {
|
|
8931
9210
|
const moved = moveCursorDown(value, cursor);
|
|
8932
|
-
|
|
9211
|
+
if (moved === cursor) return { ...NOOP, historyHandoff: "next" };
|
|
9212
|
+
return { next: null, cursor: moved, submit: false };
|
|
8933
9213
|
}
|
|
8934
9214
|
if (key.ctrl && key.input === "a") {
|
|
8935
9215
|
return { next: null, cursor: startOfLine(value, cursor), submit: false };
|
|
@@ -8937,6 +9217,29 @@ function processMultilineKey(value, cursor, key) {
|
|
|
8937
9217
|
if (key.ctrl && key.input === "e") {
|
|
8938
9218
|
return { next: null, cursor: endOfLine(value, cursor), submit: false };
|
|
8939
9219
|
}
|
|
9220
|
+
if (key.ctrl && key.input === "u") {
|
|
9221
|
+
return value.length === 0 ? NOOP : { next: "", cursor: 0, submit: false };
|
|
9222
|
+
}
|
|
9223
|
+
if (key.ctrl && key.input === "w") {
|
|
9224
|
+
if (cursor === 0) return NOOP;
|
|
9225
|
+
const wordStart = previousWordStart(value, cursor);
|
|
9226
|
+
return {
|
|
9227
|
+
next: value.slice(0, wordStart) + value.slice(cursor),
|
|
9228
|
+
cursor: wordStart,
|
|
9229
|
+
submit: false
|
|
9230
|
+
};
|
|
9231
|
+
}
|
|
9232
|
+
const stripped = key.input.replaceAll("\x1B[200~", "").replaceAll("\x1B[201~", "");
|
|
9233
|
+
const looksLikePaste = stripped.length > 1 && (stripped.includes("\n") || stripped.includes("\r"));
|
|
9234
|
+
if (looksLikePaste) {
|
|
9235
|
+
const normalized = stripped.replace(/\r\n?/g, "\n");
|
|
9236
|
+
return {
|
|
9237
|
+
next: null,
|
|
9238
|
+
cursor: null,
|
|
9239
|
+
submit: false,
|
|
9240
|
+
pasteRequest: { content: normalized }
|
|
9241
|
+
};
|
|
9242
|
+
}
|
|
8940
9243
|
if (key.input === "\n" || key.ctrl && key.input === "j") {
|
|
8941
9244
|
return insertAt(value, cursor, "\n");
|
|
8942
9245
|
}
|
|
@@ -8988,6 +9291,12 @@ function lineAndColumn(value, cursor) {
|
|
|
8988
9291
|
function startOfLine(value, cursor) {
|
|
8989
9292
|
return value.lastIndexOf("\n", cursor - 1) + 1;
|
|
8990
9293
|
}
|
|
9294
|
+
function previousWordStart(value, cursor) {
|
|
9295
|
+
let i = cursor;
|
|
9296
|
+
while (i > 0 && /\s/.test(value[i - 1] ?? "")) i--;
|
|
9297
|
+
while (i > 0 && !/\s/.test(value[i - 1] ?? "")) i--;
|
|
9298
|
+
return i;
|
|
9299
|
+
}
|
|
8991
9300
|
function endOfLine(value, cursor) {
|
|
8992
9301
|
const nl = value.indexOf("\n", cursor);
|
|
8993
9302
|
return nl === -1 ? value.length : nl;
|
|
@@ -9012,15 +9321,76 @@ function moveCursorDown(value, cursor) {
|
|
|
9012
9321
|
return nextStart + Math.min(col, nextLen);
|
|
9013
9322
|
}
|
|
9014
9323
|
|
|
9324
|
+
// src/cli/ui/paste-sentinels.ts
|
|
9325
|
+
var PASTE_SENTINEL_BASE = 57600;
|
|
9326
|
+
var PASTE_SENTINEL_RANGE = 256;
|
|
9327
|
+
var PASTE_SENTINEL_END = PASTE_SENTINEL_BASE + PASTE_SENTINEL_RANGE;
|
|
9328
|
+
function encodePasteSentinel(id) {
|
|
9329
|
+
if (id < 0 || id >= PASTE_SENTINEL_RANGE) {
|
|
9330
|
+
throw new Error(`paste sentinel id ${id} out of range [0, ${PASTE_SENTINEL_RANGE})`);
|
|
9331
|
+
}
|
|
9332
|
+
return String.fromCharCode(PASTE_SENTINEL_BASE + id);
|
|
9333
|
+
}
|
|
9334
|
+
function decodePasteSentinel(ch) {
|
|
9335
|
+
if (ch.length === 0) return null;
|
|
9336
|
+
const cp = ch.charCodeAt(0);
|
|
9337
|
+
if (cp < PASTE_SENTINEL_BASE || cp >= PASTE_SENTINEL_END) return null;
|
|
9338
|
+
return cp - PASTE_SENTINEL_BASE;
|
|
9339
|
+
}
|
|
9340
|
+
function makePasteEntry(id, content) {
|
|
9341
|
+
return {
|
|
9342
|
+
id,
|
|
9343
|
+
content,
|
|
9344
|
+
lineCount: content.split("\n").length,
|
|
9345
|
+
charCount: content.length
|
|
9346
|
+
};
|
|
9347
|
+
}
|
|
9348
|
+
function expandPasteSentinels(text, pastes) {
|
|
9349
|
+
let out = "";
|
|
9350
|
+
for (let i = 0; i < text.length; i++) {
|
|
9351
|
+
const ch = text[i];
|
|
9352
|
+
const id = decodePasteSentinel(ch);
|
|
9353
|
+
if (id === null) {
|
|
9354
|
+
out += ch;
|
|
9355
|
+
continue;
|
|
9356
|
+
}
|
|
9357
|
+
const entry = pastes.get(id);
|
|
9358
|
+
out += entry?.content ?? "";
|
|
9359
|
+
}
|
|
9360
|
+
return out;
|
|
9361
|
+
}
|
|
9362
|
+
function listPasteIdsInBuffer(text) {
|
|
9363
|
+
const ids = [];
|
|
9364
|
+
for (let i = 0; i < text.length; i++) {
|
|
9365
|
+
const id = decodePasteSentinel(text[i]);
|
|
9366
|
+
if (id !== null) ids.push(id);
|
|
9367
|
+
}
|
|
9368
|
+
return ids;
|
|
9369
|
+
}
|
|
9370
|
+
function formatBytesShort(n) {
|
|
9371
|
+
if (n < 1024) return `${n}B`;
|
|
9372
|
+
if (n < 1024 * 1024) return `${(n / 1024).toFixed(n < 1024 * 10 ? 1 : 0)}KB`;
|
|
9373
|
+
return `${(n / (1024 * 1024)).toFixed(1)}MB`;
|
|
9374
|
+
}
|
|
9375
|
+
|
|
9015
9376
|
// src/cli/ui/PromptInput.tsx
|
|
9377
|
+
var PASTE_START_MARKER = "\x1B[200~";
|
|
9378
|
+
var PASTE_END_MARKER = "\x1B[201~";
|
|
9379
|
+
var PASTE_MERGE_WINDOW_MS = 30;
|
|
9016
9380
|
function PromptInput({
|
|
9017
9381
|
value,
|
|
9018
9382
|
onChange,
|
|
9019
9383
|
onSubmit,
|
|
9020
9384
|
disabled,
|
|
9021
|
-
placeholder
|
|
9385
|
+
placeholder,
|
|
9386
|
+
onHistoryPrev,
|
|
9387
|
+
onHistoryNext
|
|
9022
9388
|
}) {
|
|
9023
9389
|
const [cursor, setCursor] = useState5(value.length);
|
|
9390
|
+
const pastesRef = useRef(/* @__PURE__ */ new Map());
|
|
9391
|
+
const nextPasteIdRef = useRef(0);
|
|
9392
|
+
const pasteAccumRef = useRef(null);
|
|
9393
|
+
const lastPasteRef = useRef(null);
|
|
9024
9394
|
const lastLocalValueRef = useRef(value);
|
|
9025
9395
|
if (value !== lastLocalValueRef.current) {
|
|
9026
9396
|
lastLocalValueRef.current = value;
|
|
@@ -9028,10 +9398,62 @@ function PromptInput({
|
|
|
9028
9398
|
setCursor(value.length);
|
|
9029
9399
|
}
|
|
9030
9400
|
}
|
|
9401
|
+
const cursorRef = useRef(cursor);
|
|
9402
|
+
cursorRef.current = cursor;
|
|
9031
9403
|
const tick = useTick();
|
|
9032
9404
|
const showCursor = disabled ? false : Math.floor(tick / 4) % 2 === 0;
|
|
9405
|
+
const registerPaste = (content) => {
|
|
9406
|
+
const v = lastLocalValueRef.current;
|
|
9407
|
+
const c = cursorRef.current;
|
|
9408
|
+
const now = Date.now();
|
|
9409
|
+
const last = lastPasteRef.current;
|
|
9410
|
+
const prevChar = c > 0 ? v[c - 1] : null;
|
|
9411
|
+
const prevId = prevChar ? decodePasteSentinel(prevChar) : null;
|
|
9412
|
+
const canMerge = last !== null && prevId === last.id && now - last.at < PASTE_MERGE_WINDOW_MS && pastesRef.current.has(last.id);
|
|
9413
|
+
if (canMerge && last) {
|
|
9414
|
+
const existing = pastesRef.current.get(last.id);
|
|
9415
|
+
if (existing) {
|
|
9416
|
+
const merged = existing.content + content;
|
|
9417
|
+
pastesRef.current.set(last.id, makePasteEntry(last.id, merged));
|
|
9418
|
+
lastPasteRef.current = { id: last.id, at: now };
|
|
9419
|
+
return;
|
|
9420
|
+
}
|
|
9421
|
+
}
|
|
9422
|
+
const id = nextPasteIdRef.current % PASTE_SENTINEL_RANGE;
|
|
9423
|
+
nextPasteIdRef.current = id + 1;
|
|
9424
|
+
pastesRef.current.set(id, makePasteEntry(id, content));
|
|
9425
|
+
const sentinel = encodePasteSentinel(id);
|
|
9426
|
+
const next = v.slice(0, c) + sentinel + v.slice(c);
|
|
9427
|
+
lastLocalValueRef.current = next;
|
|
9428
|
+
cursorRef.current = c + 1;
|
|
9429
|
+
onChange(next);
|
|
9430
|
+
setCursor(c + 1);
|
|
9431
|
+
lastPasteRef.current = { id, at: now };
|
|
9432
|
+
};
|
|
9033
9433
|
useInput4(
|
|
9034
9434
|
(input, key) => {
|
|
9435
|
+
if (pasteAccumRef.current !== null) {
|
|
9436
|
+
const endIdx = input.indexOf(PASTE_END_MARKER);
|
|
9437
|
+
if (endIdx === -1) {
|
|
9438
|
+
pasteAccumRef.current += input;
|
|
9439
|
+
return;
|
|
9440
|
+
}
|
|
9441
|
+
const content = pasteAccumRef.current + input.slice(0, endIdx);
|
|
9442
|
+
pasteAccumRef.current = null;
|
|
9443
|
+
registerPaste(content);
|
|
9444
|
+
return;
|
|
9445
|
+
}
|
|
9446
|
+
const startIdx = input.indexOf(PASTE_START_MARKER);
|
|
9447
|
+
if (startIdx !== -1) {
|
|
9448
|
+
const afterStart = input.slice(startIdx + PASTE_START_MARKER.length);
|
|
9449
|
+
const endIdx = afterStart.indexOf(PASTE_END_MARKER);
|
|
9450
|
+
if (endIdx !== -1) {
|
|
9451
|
+
registerPaste(afterStart.slice(0, endIdx));
|
|
9452
|
+
} else {
|
|
9453
|
+
pasteAccumRef.current = afterStart;
|
|
9454
|
+
}
|
|
9455
|
+
return;
|
|
9456
|
+
}
|
|
9035
9457
|
const ke = {
|
|
9036
9458
|
input,
|
|
9037
9459
|
return: key.return,
|
|
@@ -9050,6 +9472,10 @@ function PromptInput({
|
|
|
9050
9472
|
pageDown: key.pageDown
|
|
9051
9473
|
};
|
|
9052
9474
|
const action = processMultilineKey(value, cursor, ke);
|
|
9475
|
+
if (action.pasteRequest) {
|
|
9476
|
+
registerPaste(action.pasteRequest.content);
|
|
9477
|
+
return;
|
|
9478
|
+
}
|
|
9053
9479
|
if (action.next !== null) {
|
|
9054
9480
|
lastLocalValueRef.current = action.next;
|
|
9055
9481
|
onChange(action.next);
|
|
@@ -9057,7 +9483,17 @@ function PromptInput({
|
|
|
9057
9483
|
if (action.cursor !== null) {
|
|
9058
9484
|
setCursor(action.cursor);
|
|
9059
9485
|
}
|
|
9060
|
-
if (action.submit)
|
|
9486
|
+
if (action.submit) {
|
|
9487
|
+
const raw = action.submitValue ?? value;
|
|
9488
|
+
const expanded = expandPasteSentinels(raw, pastesRef.current);
|
|
9489
|
+
const reachable = new Set(listPasteIdsInBuffer(raw));
|
|
9490
|
+
for (const id of pastesRef.current.keys()) {
|
|
9491
|
+
if (!reachable.has(id)) pastesRef.current.delete(id);
|
|
9492
|
+
}
|
|
9493
|
+
onSubmit(expanded);
|
|
9494
|
+
}
|
|
9495
|
+
if (action.historyHandoff === "prev") onHistoryPrev?.();
|
|
9496
|
+
if (action.historyHandoff === "next") onHistoryNext?.();
|
|
9061
9497
|
},
|
|
9062
9498
|
{ isActive: !disabled }
|
|
9063
9499
|
);
|
|
@@ -9065,37 +9501,110 @@ function PromptInput({
|
|
|
9065
9501
|
const lines = value.length > 0 ? value.split("\n") : [""];
|
|
9066
9502
|
const borderColor = disabled ? "gray" : "cyan";
|
|
9067
9503
|
const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
|
|
9068
|
-
|
|
9504
|
+
const renderItems = collapseLinesForDisplay(lines, cursorLine);
|
|
9505
|
+
const showHugeBufferHints = lines.length > 20;
|
|
9506
|
+
return /* @__PURE__ */ React15.createElement(Box14, { borderStyle: "round", borderColor, paddingX: 1, flexDirection: "column" }, renderItems.map((item, renderIdx) => {
|
|
9507
|
+
if (item.kind === "skip") {
|
|
9508
|
+
return (
|
|
9509
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: stable — skip markers are derived from a fixed-size window over `lines`
|
|
9510
|
+
/* @__PURE__ */ React15.createElement(Box14, { key: `skip-${renderIdx}` }, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, " "), /* @__PURE__ */ React15.createElement(
|
|
9511
|
+
Text14,
|
|
9512
|
+
{
|
|
9513
|
+
dimColor: true
|
|
9514
|
+
},
|
|
9515
|
+
`[\u2026 ${item.linesHidden} line${item.linesHidden === 1 ? "" : "s"} hidden \u2014 full content kept, submitted on Enter \u2026]`
|
|
9516
|
+
))
|
|
9517
|
+
);
|
|
9518
|
+
}
|
|
9519
|
+
const line = item.line;
|
|
9520
|
+
const i = item.originalIndex;
|
|
9069
9521
|
const isFirst = i === 0;
|
|
9070
9522
|
const showPlaceholder = isFirst && value.length === 0;
|
|
9071
9523
|
const isCursorLine = i === cursorLine;
|
|
9072
|
-
return (
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9524
|
+
return /* @__PURE__ */ React15.createElement(Box14, { key: `ln-${i}` }, isFirst ? /* @__PURE__ */ React15.createElement(Text14, { bold: true, color: borderColor }, "you \u203A", " ") : /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, " "), showPlaceholder ? /* @__PURE__ */ React15.createElement(React15.Fragment, null, isCursorLine && !disabled ? /* @__PURE__ */ React15.createElement(Text14, { color: borderColor }, showCursor ? "\u258C" : " ") : null, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, effectivePlaceholder)) : isCursorLine && !disabled ? /* @__PURE__ */ React15.createElement(
|
|
9525
|
+
LineWithCursor,
|
|
9526
|
+
{
|
|
9527
|
+
line,
|
|
9528
|
+
col: cursorCol,
|
|
9529
|
+
showCursor,
|
|
9530
|
+
borderColor,
|
|
9531
|
+
pastes: pastesRef.current
|
|
9532
|
+
}
|
|
9533
|
+
) : /* @__PURE__ */ React15.createElement(RenderLine, { line, pastes: pastesRef.current }));
|
|
9534
|
+
}), showHugeBufferHints && !disabled ? /* @__PURE__ */ React15.createElement(Box14, null, /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, " "), /* @__PURE__ */ React15.createElement(Text14, { dimColor: true }, `[${lines.length} lines \xB7 PageUp/PageDown jump to top/bottom \xB7 Ctrl+U clear \xB7 Ctrl+W del word]`)) : null);
|
|
9535
|
+
}
|
|
9536
|
+
var COLLAPSE_THRESHOLD = 20;
|
|
9537
|
+
var COLLAPSE_HEAD_LINES = 3;
|
|
9538
|
+
var COLLAPSE_TAIL_LINES = 2;
|
|
9539
|
+
function collapseLinesForDisplay(lines, cursorLine) {
|
|
9540
|
+
if (lines.length <= COLLAPSE_THRESHOLD) {
|
|
9541
|
+
return lines.map((line, i) => ({ kind: "line", line, originalIndex: i }));
|
|
9542
|
+
}
|
|
9543
|
+
const keep = /* @__PURE__ */ new Set();
|
|
9544
|
+
for (let i = 0; i < COLLAPSE_HEAD_LINES && i < lines.length; i++) keep.add(i);
|
|
9545
|
+
for (let i = Math.max(0, lines.length - COLLAPSE_TAIL_LINES); i < lines.length; i++) keep.add(i);
|
|
9546
|
+
if (cursorLine >= 0 && cursorLine < lines.length) keep.add(cursorLine);
|
|
9547
|
+
const sorted = [...keep].sort((a, b) => a - b);
|
|
9548
|
+
const out = [];
|
|
9549
|
+
let prev = -1;
|
|
9550
|
+
for (const idx of sorted) {
|
|
9551
|
+
if (idx - prev > 1) {
|
|
9552
|
+
out.push({ kind: "skip", linesHidden: idx - prev - 1 });
|
|
9553
|
+
}
|
|
9554
|
+
out.push({ kind: "line", line: lines[idx] ?? "", originalIndex: idx });
|
|
9555
|
+
prev = idx;
|
|
9556
|
+
}
|
|
9557
|
+
return out;
|
|
9558
|
+
}
|
|
9559
|
+
function RenderLine({
|
|
9560
|
+
line,
|
|
9561
|
+
pastes,
|
|
9562
|
+
inverse
|
|
9563
|
+
}) {
|
|
9564
|
+
const segments = [];
|
|
9565
|
+
let buf = "";
|
|
9566
|
+
let segIdx = 0;
|
|
9567
|
+
const flushBuf = () => {
|
|
9568
|
+
if (buf.length === 0) return;
|
|
9569
|
+
segments.push(
|
|
9570
|
+
/* @__PURE__ */ React15.createElement(Text14, { key: `t-${segIdx++}`, inverse }, buf)
|
|
9083
9571
|
);
|
|
9084
|
-
|
|
9572
|
+
buf = "";
|
|
9573
|
+
};
|
|
9574
|
+
for (let i = 0; i < line.length; i++) {
|
|
9575
|
+
const ch = line[i];
|
|
9576
|
+
const id = decodePasteSentinel(ch);
|
|
9577
|
+
if (id === null) {
|
|
9578
|
+
buf += ch;
|
|
9579
|
+
continue;
|
|
9580
|
+
}
|
|
9581
|
+
flushBuf();
|
|
9582
|
+
const entry = pastes.get(id);
|
|
9583
|
+
const label = entry ? `[paste #${id + 1} \xB7 ${entry.lineCount}l \xB7 ${formatBytesShort(entry.charCount)}]` : `[paste #${id + 1} \xB7 (missing)]`;
|
|
9584
|
+
segments.push(
|
|
9585
|
+
/* @__PURE__ */ React15.createElement(Text14, { key: `p-${segIdx++}`, color: "magenta", bold: true, inverse }, label)
|
|
9586
|
+
);
|
|
9587
|
+
}
|
|
9588
|
+
flushBuf();
|
|
9589
|
+
if (segments.length === 0) {
|
|
9590
|
+
return /* @__PURE__ */ React15.createElement(Text14, null, " ");
|
|
9591
|
+
}
|
|
9592
|
+
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, segments);
|
|
9085
9593
|
}
|
|
9086
9594
|
function LineWithCursor({
|
|
9087
9595
|
line,
|
|
9088
9596
|
col,
|
|
9089
9597
|
showCursor,
|
|
9090
|
-
borderColor
|
|
9598
|
+
borderColor,
|
|
9599
|
+
pastes
|
|
9091
9600
|
}) {
|
|
9092
9601
|
const before = line.slice(0, col);
|
|
9093
9602
|
const atCursor = line.slice(col, col + 1);
|
|
9094
9603
|
const after = line.slice(col + 1);
|
|
9095
9604
|
if (atCursor.length === 0) {
|
|
9096
|
-
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
|
|
9605
|
+
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(RenderLine, { line: before, pastes }), /* @__PURE__ */ React15.createElement(Text14, { color: borderColor }, showCursor ? "\u258C" : " "));
|
|
9097
9606
|
}
|
|
9098
|
-
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
|
|
9607
|
+
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(RenderLine, { line: before, pastes }), /* @__PURE__ */ React15.createElement(RenderLine, { line: atCursor, pastes, inverse: showCursor }), /* @__PURE__ */ React15.createElement(RenderLine, { line: after, pastes }));
|
|
9099
9608
|
}
|
|
9100
9609
|
|
|
9101
9610
|
// src/cli/ui/ShellConfirm.tsx
|
|
@@ -9275,43 +9784,54 @@ function StatsPanel({
|
|
|
9275
9784
|
const columns = stdout2?.columns ?? 80;
|
|
9276
9785
|
const narrow = columns < NARROW_BREAKPOINT;
|
|
9277
9786
|
const coldStart = summary.turns <= COLD_START_TURNS;
|
|
9278
|
-
return
|
|
9279
|
-
|
|
9280
|
-
|
|
9281
|
-
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
|
|
9292
|
-
|
|
9293
|
-
|
|
9294
|
-
|
|
9295
|
-
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
|
|
9314
|
-
|
|
9787
|
+
return (
|
|
9788
|
+
// Explicit `width={columns}` pins the border frame to the exact
|
|
9789
|
+
// terminal width. Without this, Ink auto-flexes the Box to
|
|
9790
|
+
// container width, and on terminal resize the prior frame's
|
|
9791
|
+
// wrapped-overflow can leave tails in the scrollback (each
|
|
9792
|
+
// redraw stacks a slightly-wider-or-narrower frame). Fixing
|
|
9793
|
+
// width per-render doesn't eliminate the underlying Ink
|
|
9794
|
+
// limitation (eraseLines counts logical rows, not post-wrap
|
|
9795
|
+
// display rows) but makes each frame's dimensions exact so
|
|
9796
|
+
// there's no residual uncertainty in the erase.
|
|
9797
|
+
/* @__PURE__ */ React19.createElement(Box18, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1, width: columns }, /* @__PURE__ */ React19.createElement(
|
|
9798
|
+
Header,
|
|
9799
|
+
{
|
|
9800
|
+
model: model2,
|
|
9801
|
+
prefixHash,
|
|
9802
|
+
harvestOn,
|
|
9803
|
+
branchOn,
|
|
9804
|
+
branchBudget: branchBudget ?? 1,
|
|
9805
|
+
reasoningEffort,
|
|
9806
|
+
planMode,
|
|
9807
|
+
editMode,
|
|
9808
|
+
turns: summary.turns,
|
|
9809
|
+
updateAvailable,
|
|
9810
|
+
narrow,
|
|
9811
|
+
busy: busy ?? false,
|
|
9812
|
+
proArmed: proArmed ?? false,
|
|
9813
|
+
escalated: escalated ?? false
|
|
9814
|
+
}
|
|
9815
|
+
), narrow ? /* @__PURE__ */ React19.createElement(
|
|
9816
|
+
StackedMetrics,
|
|
9817
|
+
{
|
|
9818
|
+
summary,
|
|
9819
|
+
ctxRatio,
|
|
9820
|
+
ctxMax,
|
|
9821
|
+
balance,
|
|
9822
|
+
coldStart
|
|
9823
|
+
}
|
|
9824
|
+
) : /* @__PURE__ */ React19.createElement(
|
|
9825
|
+
InlineMetrics,
|
|
9826
|
+
{
|
|
9827
|
+
summary,
|
|
9828
|
+
ctxRatio,
|
|
9829
|
+
ctxMax,
|
|
9830
|
+
balance,
|
|
9831
|
+
coldStart
|
|
9832
|
+
}
|
|
9833
|
+
))
|
|
9834
|
+
);
|
|
9315
9835
|
}
|
|
9316
9836
|
function Header({
|
|
9317
9837
|
model: model2,
|
|
@@ -10117,7 +10637,7 @@ var handlers = {
|
|
|
10117
10637
|
var exit = () => ({ exit: true });
|
|
10118
10638
|
var clear = () => ({
|
|
10119
10639
|
clear: true,
|
|
10120
|
-
info: "\u25B8 cleared
|
|
10640
|
+
info: "\u25B8 terminal cleared (viewport + scrollback). Context (message log) is intact \u2014 next turn still sees everything. Use /new to start fresh, or /forget to delete the session entirely."
|
|
10121
10641
|
});
|
|
10122
10642
|
var resetLog = (_args, loop) => {
|
|
10123
10643
|
const { dropped } = loop.clearLog();
|
|
@@ -10133,8 +10653,11 @@ var keys = () => ({
|
|
|
10133
10653
|
" Enter submit the current prompt",
|
|
10134
10654
|
" Shift+Enter / Ctrl+J insert a newline (multi-line prompt)",
|
|
10135
10655
|
" \\<Enter> bash-style line continuation",
|
|
10136
|
-
" \u2190 \u2192 \u2191 \u2193 move cursor / recall history
|
|
10137
|
-
"
|
|
10656
|
+
" \u2190 \u2192 \u2191 \u2193 move cursor / recall history at buffer boundary",
|
|
10657
|
+
" PageUp / PageDown jump to top / bottom of the WHOLE buffer (handy after a big paste)",
|
|
10658
|
+
" Ctrl+A / Ctrl+E jump to start / end of the CURRENT line",
|
|
10659
|
+
" Ctrl+U clear the entire input buffer",
|
|
10660
|
+
" Ctrl+W delete the word before the cursor",
|
|
10138
10661
|
" Backspace delete left; Delete delete under cursor",
|
|
10139
10662
|
" Esc abort the in-flight turn",
|
|
10140
10663
|
" y / n accept / reject pending edits (code mode)",
|
|
@@ -10220,7 +10743,13 @@ var help = () => ({
|
|
|
10220
10743
|
"",
|
|
10221
10744
|
"Sessions (auto-enabled by default, named 'default'):",
|
|
10222
10745
|
" reasonix chat --session <name> use a different named session",
|
|
10223
|
-
" reasonix chat --no-session disable persistence for this run"
|
|
10746
|
+
" reasonix chat --no-session disable persistence for this run",
|
|
10747
|
+
"",
|
|
10748
|
+
"Known limitation:",
|
|
10749
|
+
" Resizing the terminal mid-session may stack ghost header frames in",
|
|
10750
|
+
" scrollback (Ink library's live-region clear doesn't account for line",
|
|
10751
|
+
" re-wrapping at the new width). Scroll-up history is unaffected; the",
|
|
10752
|
+
" artifact is purely visual and clears the next time you /clear."
|
|
10224
10753
|
].join("\n")
|
|
10225
10754
|
});
|
|
10226
10755
|
var setup = () => ({
|
|
@@ -11754,6 +12283,14 @@ function App({
|
|
|
11754
12283
|
const abortedThisTurn = useRef5(false);
|
|
11755
12284
|
const [ongoingTool, setOngoingTool] = useState10(null);
|
|
11756
12285
|
const [toolProgress, setToolProgress] = useState10(null);
|
|
12286
|
+
const { stdout: stdout2 } = useStdout4();
|
|
12287
|
+
useEffect5(() => {
|
|
12288
|
+
if (!stdout2 || !stdout2.isTTY) return;
|
|
12289
|
+
stdout2.write("\x1B[?2004h");
|
|
12290
|
+
return () => {
|
|
12291
|
+
stdout2.write("\x1B[?2004l");
|
|
12292
|
+
};
|
|
12293
|
+
}, [stdout2]);
|
|
11757
12294
|
const { activity: subagentActivity, sinkRef: subagentSinkRef } = useSubagent({
|
|
11758
12295
|
session,
|
|
11759
12296
|
setHistorical
|
|
@@ -12114,24 +12651,21 @@ function App({
|
|
|
12114
12651
|
return;
|
|
12115
12652
|
}
|
|
12116
12653
|
}
|
|
12117
|
-
if (input.length === 0) {
|
|
12118
|
-
const hist = promptHistory.current;
|
|
12119
|
-
if (key.upArrow) {
|
|
12120
|
-
if (hist.length === 0) return;
|
|
12121
|
-
const nextCursor = Math.min(historyCursor.current + 1, hist.length - 1);
|
|
12122
|
-
historyCursor.current = nextCursor;
|
|
12123
|
-
setInput(hist[hist.length - 1 - nextCursor] ?? "");
|
|
12124
|
-
return;
|
|
12125
|
-
}
|
|
12126
|
-
if (key.downArrow) {
|
|
12127
|
-
if (historyCursor.current < 0) return;
|
|
12128
|
-
const nextCursor = historyCursor.current - 1;
|
|
12129
|
-
historyCursor.current = nextCursor;
|
|
12130
|
-
setInput(nextCursor < 0 ? "" : hist[hist.length - 1 - nextCursor] ?? "");
|
|
12131
|
-
return;
|
|
12132
|
-
}
|
|
12133
|
-
}
|
|
12134
12654
|
});
|
|
12655
|
+
const recallPrev = useCallback4(() => {
|
|
12656
|
+
const hist = promptHistory.current;
|
|
12657
|
+
if (hist.length === 0) return;
|
|
12658
|
+
const nextCursor = Math.min(historyCursor.current + 1, hist.length - 1);
|
|
12659
|
+
historyCursor.current = nextCursor;
|
|
12660
|
+
setInput(hist[hist.length - 1 - nextCursor] ?? "");
|
|
12661
|
+
}, []);
|
|
12662
|
+
const recallNext = useCallback4(() => {
|
|
12663
|
+
if (historyCursor.current < 0) return;
|
|
12664
|
+
const hist = promptHistory.current;
|
|
12665
|
+
const nextCursor = historyCursor.current - 1;
|
|
12666
|
+
historyCursor.current = nextCursor;
|
|
12667
|
+
setInput(nextCursor < 0 ? "" : hist[hist.length - 1 - nextCursor] ?? "");
|
|
12668
|
+
}, []);
|
|
12135
12669
|
useEffect5(() => {
|
|
12136
12670
|
if (!tools || !codeMode) return;
|
|
12137
12671
|
tools.setToolInterceptor(async (name, args) => {
|
|
@@ -12392,6 +12926,7 @@ function App({
|
|
|
12392
12926
|
return;
|
|
12393
12927
|
}
|
|
12394
12928
|
if (result.clear && result.info) {
|
|
12929
|
+
stdout2?.write("\x1B[2J\x1B[3J\x1B[H");
|
|
12395
12930
|
setHistorical([
|
|
12396
12931
|
{
|
|
12397
12932
|
id: `sys-${Date.now()}`,
|
|
@@ -12407,6 +12942,7 @@ function App({
|
|
|
12407
12942
|
return;
|
|
12408
12943
|
}
|
|
12409
12944
|
if (result.clear) {
|
|
12945
|
+
stdout2?.write("\x1B[2J\x1B[3J\x1B[H");
|
|
12410
12946
|
setHistorical([]);
|
|
12411
12947
|
if (codeMode) {
|
|
12412
12948
|
pendingEdits.current = [];
|
|
@@ -12895,7 +13431,8 @@ function App({
|
|
|
12895
13431
|
refreshLatestVersion,
|
|
12896
13432
|
refreshModels,
|
|
12897
13433
|
proArmed,
|
|
12898
|
-
persistPlanState
|
|
13434
|
+
persistPlanState,
|
|
13435
|
+
stdout2
|
|
12899
13436
|
]
|
|
12900
13437
|
);
|
|
12901
13438
|
const handleShellConfirm = useCallback4(
|
|
@@ -13426,7 +13963,9 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
13426
13963
|
value: input,
|
|
13427
13964
|
onChange: setInput,
|
|
13428
13965
|
onSubmit: handleSubmit,
|
|
13429
|
-
disabled: busy
|
|
13966
|
+
disabled: busy,
|
|
13967
|
+
onHistoryPrev: recallPrev,
|
|
13968
|
+
onHistoryNext: recallNext
|
|
13430
13969
|
}
|
|
13431
13970
|
), /* @__PURE__ */ React20.createElement(SlashSuggestions, { matches: slashMatches, selectedIndex: slashSelected }), /* @__PURE__ */ React20.createElement(
|
|
13432
13971
|
AtMentionSuggestions,
|
|
@@ -14846,6 +15385,12 @@ Every factual claim about a codebase must be backed by evidence. Reasonix VALIDA
|
|
|
14846
15385
|
|
|
14847
15386
|
Asserting absence without checking is how evaluative answers go wrong. Treat the urge to write "missing" as a red flag in your own reasoning.
|
|
14848
15387
|
|
|
15388
|
+
# Don't invent what changes \u2014 search instead
|
|
15389
|
+
|
|
15390
|
+
Your training data has a cutoff. When an answer's correctness depends on something that changes over time (the user is asking what's happening, not what's true) and a search tool is available, search first. Inventing currently-correct values from training memory is the most common way these answers go wrong, and the user usually can't tell until much later.
|
|
15391
|
+
|
|
15392
|
+
The signal isn't a topic list \u2014 it's: "if I'm wrong about this, is it because reality moved on?". If yes, ground the answer in fresh evidence; if no (definitions, mechanisms, well-established APIs), answer from memory.
|
|
15393
|
+
|
|
14849
15394
|
${ESCALATION_CONTRACT}`;
|
|
14850
15395
|
var program = new Command();
|
|
14851
15396
|
program.name("reasonix").description("DeepSeek-native agent framework \u2014 built for cache hits and cheap tokens.").version(VERSION);
|