reasonix 0.7.5 → 0.8.0
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/{chunk-5DZMZCCW.js → chunk-DVBNMXA6.js} +37 -1
- package/dist/cli/{chunk-5DZMZCCW.js.map → chunk-DVBNMXA6.js.map} +1 -1
- package/dist/cli/index.js +345 -149
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{prompt-2OABSPAW.js → prompt-POARCKKR.js} +2 -2
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- /package/dist/cli/{prompt-2OABSPAW.js.map → prompt-POARCKKR.js.map} +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
memoryEnabled,
|
|
11
11
|
readProjectMemory,
|
|
12
12
|
sanitizeMemoryName
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-DVBNMXA6.js";
|
|
14
14
|
|
|
15
15
|
// src/cli/index.ts
|
|
16
16
|
import { Command } from "commander";
|
|
@@ -7111,7 +7111,7 @@ function formatLogSize(path = defaultUsageLogPath()) {
|
|
|
7111
7111
|
}
|
|
7112
7112
|
|
|
7113
7113
|
// src/cli/commands/chat.tsx
|
|
7114
|
-
import { existsSync as
|
|
7114
|
+
import { existsSync as existsSync13, statSync as statSync7 } from "fs";
|
|
7115
7115
|
import { render } from "ink";
|
|
7116
7116
|
import React26, { useState as useState12 } from "react";
|
|
7117
7117
|
|
|
@@ -7991,7 +7991,8 @@ function formatAllBlockDiffs(blocks, opts = {}) {
|
|
|
7991
7991
|
const added = countLines2(b.replace);
|
|
7992
7992
|
const tag = b.search === "" ? "NEW " : " ";
|
|
7993
7993
|
if (i > 0) out.push("");
|
|
7994
|
-
|
|
7994
|
+
const label = opts.numbered ? `[${i + 1}] ` : "";
|
|
7995
|
+
out.push(` ${label}${tag}${b.path} (-${removed} +${added} lines)`);
|
|
7995
7996
|
out.push(...formatEditBlockDiff(b, opts));
|
|
7996
7997
|
}
|
|
7997
7998
|
return out;
|
|
@@ -8401,17 +8402,41 @@ function parseCitationUrl(url) {
|
|
|
8401
8402
|
}
|
|
8402
8403
|
return { path: trimmed };
|
|
8403
8404
|
}
|
|
8405
|
+
var SIBLING_EXTENSIONS = /* @__PURE__ */ new Map([
|
|
8406
|
+
[".ts", [".tsx", ".mts", ".cts"]],
|
|
8407
|
+
[".tsx", [".ts"]],
|
|
8408
|
+
[".js", [".jsx", ".mjs", ".cjs"]],
|
|
8409
|
+
[".jsx", [".js"]],
|
|
8410
|
+
[".mjs", [".js", ".cjs"]],
|
|
8411
|
+
[".cjs", [".js", ".mjs"]],
|
|
8412
|
+
[".mts", [".ts"]],
|
|
8413
|
+
[".cts", [".ts"]]
|
|
8414
|
+
]);
|
|
8415
|
+
function extOf(p) {
|
|
8416
|
+
const m = /\.[^./\\]+$/.exec(p);
|
|
8417
|
+
return m ? m[0] : "";
|
|
8418
|
+
}
|
|
8404
8419
|
function validateCitation(url, projectRoot) {
|
|
8405
8420
|
const parts = parseCitationUrl(url);
|
|
8406
8421
|
if (!parts || !parts.path) return { ok: false, reason: "empty path" };
|
|
8407
8422
|
const normalized = parts.path.replace(/^[/\\]+/, "");
|
|
8408
|
-
const
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8423
|
+
const baseFullPath = isAbsolute4(normalized) ? normalized : join11(projectRoot, normalized);
|
|
8424
|
+
const siblings = SIBLING_EXTENSIONS.get(extOf(baseFullPath)) ?? [];
|
|
8425
|
+
const candidates = [
|
|
8426
|
+
baseFullPath,
|
|
8427
|
+
...siblings.map((ext) => baseFullPath.replace(/\.[^./\\]+$/, ext))
|
|
8428
|
+
];
|
|
8429
|
+
let fullPath = baseFullPath;
|
|
8430
|
+
let stat = null;
|
|
8431
|
+
for (const candidate of candidates) {
|
|
8432
|
+
try {
|
|
8433
|
+
stat = statSync6(candidate);
|
|
8434
|
+
fullPath = candidate;
|
|
8435
|
+
break;
|
|
8436
|
+
} catch {
|
|
8437
|
+
}
|
|
8414
8438
|
}
|
|
8439
|
+
if (!stat) return { ok: false, reason: "file not found" };
|
|
8415
8440
|
if (!stat.isFile()) return { ok: false, reason: "not a file" };
|
|
8416
8441
|
if (parts.startLine === void 0) return { ok: true };
|
|
8417
8442
|
let lineCount;
|
|
@@ -9840,8 +9865,11 @@ function processMultilineKey(value, cursor, keyIn) {
|
|
|
9840
9865
|
if (key.pageDown) {
|
|
9841
9866
|
return cursor === value.length ? NOOP : { next: null, cursor: value.length, submit: false };
|
|
9842
9867
|
}
|
|
9843
|
-
if (
|
|
9844
|
-
return { ...NOOP, historyHandoff:
|
|
9868
|
+
if (key.ctrl && key.input === "p") {
|
|
9869
|
+
return { ...NOOP, historyHandoff: "prev" };
|
|
9870
|
+
}
|
|
9871
|
+
if (key.ctrl && key.input === "n") {
|
|
9872
|
+
return { ...NOOP, historyHandoff: "next" };
|
|
9845
9873
|
}
|
|
9846
9874
|
if (key.leftArrow) {
|
|
9847
9875
|
return { next: null, cursor: Math.max(0, cursor - 1), submit: false };
|
|
@@ -9851,13 +9879,11 @@ function processMultilineKey(value, cursor, keyIn) {
|
|
|
9851
9879
|
}
|
|
9852
9880
|
if (key.upArrow) {
|
|
9853
9881
|
const moved = moveCursorUp(value, cursor);
|
|
9854
|
-
|
|
9855
|
-
return { next: null, cursor: moved, submit: false };
|
|
9882
|
+
return moved === cursor ? NOOP : { next: null, cursor: moved, submit: false };
|
|
9856
9883
|
}
|
|
9857
9884
|
if (key.downArrow) {
|
|
9858
9885
|
const moved = moveCursorDown(value, cursor);
|
|
9859
|
-
|
|
9860
|
-
return { next: null, cursor: moved, submit: false };
|
|
9886
|
+
return moved === cursor ? NOOP : { next: null, cursor: moved, submit: false };
|
|
9861
9887
|
}
|
|
9862
9888
|
if (key.ctrl && key.input === "a") {
|
|
9863
9889
|
return { next: null, cursor: startOfLine(value, cursor), submit: false };
|
|
@@ -10258,15 +10284,12 @@ function PromptInput({
|
|
|
10258
10284
|
const continuationIndent = BAR + " ".repeat(promptBody.length);
|
|
10259
10285
|
const prefixCells = promptPrefix.length;
|
|
10260
10286
|
const visibleCells = Math.max(8, cols - prefixCells - 3);
|
|
10261
|
-
const placeholderActive = narrow ? "type a message, or /command" : "type a message, or /command \xB7 [Ctrl+J] newline
|
|
10287
|
+
const placeholderActive = narrow ? "type a message, or /command" : "type a message, or /command \xB7 [Ctrl+J] newline \xB7 [Ctrl+P/N] history";
|
|
10262
10288
|
const effectivePlaceholder = disabled ? placeholder ?? "\u2026waiting for response\u2026" : placeholder ?? placeholderActive;
|
|
10263
10289
|
const lines = value.length > 0 ? value.split("\n") : [""];
|
|
10264
10290
|
const accentColor = disabled ? "gray" : "cyan";
|
|
10265
|
-
const
|
|
10266
|
-
const
|
|
10267
|
-
const barOffset = animate ? Math.floor(tick / 6) : 0;
|
|
10268
|
-
const barColorAt = (rowIdx) => disabled ? "gray" : GRADIENT[((rowIdx + barOffset) % GRADIENT.length + GRADIENT.length) % GRADIENT.length];
|
|
10269
|
-
const cursorVisible = animate ? Math.floor(tick / 4) % 2 === 0 : true;
|
|
10291
|
+
const barColorAt = (rowIdx) => disabled ? "gray" : GRADIENT[(rowIdx % GRADIENT.length + GRADIENT.length) % GRADIENT.length];
|
|
10292
|
+
const cursorVisible = true;
|
|
10270
10293
|
const { line: cursorLine, col: cursorCol } = lineAndColumn(value, cursor);
|
|
10271
10294
|
const renderItems = collapseLinesForDisplay(lines, cursorLine);
|
|
10272
10295
|
const showHugeBufferHints = lines.length > 20;
|
|
@@ -10599,14 +10622,11 @@ function SuggestionRow({ spec, isSelected }) {
|
|
|
10599
10622
|
import { Box as Box19, Text as Text17, useStdout as useStdout6 } from "ink";
|
|
10600
10623
|
import React21 from "react";
|
|
10601
10624
|
var WORDMARK_LETTERS = ["R", "E", "A", "S", "O", "N", "I", "X"];
|
|
10602
|
-
function Wordmark({
|
|
10603
|
-
|
|
10604
|
-
|
|
10605
|
-
|
|
10606
|
-
|
|
10607
|
-
const offset = animate ? Math.floor(tick / rotateEvery) : 0;
|
|
10608
|
-
const colorAt = (i) => GRADIENT[((i + offset) % GRADIENT.length + GRADIENT.length) % GRADIENT.length];
|
|
10609
|
-
return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: colorAt(0), bold: bright }, "\u25C8"), /* @__PURE__ */ React21.createElement(Text17, null, " "), WORDMARK_LETTERS.map((letter, i) => /* @__PURE__ */ React21.createElement(Text17, { key: letter, color: colorAt(i + 1), bold: true }, letter)));
|
|
10625
|
+
function Wordmark({
|
|
10626
|
+
busy: _busy,
|
|
10627
|
+
animate: _animate
|
|
10628
|
+
}) {
|
|
10629
|
+
return /* @__PURE__ */ React21.createElement(Text17, null, /* @__PURE__ */ React21.createElement(Text17, { color: GRADIENT[0], bold: true }, "\u25C8"), /* @__PURE__ */ React21.createElement(Text17, null, " "), WORDMARK_LETTERS.map((letter, i) => /* @__PURE__ */ React21.createElement(Text17, { key: letter, color: GRADIENT[i % GRADIENT.length], bold: true }, letter)));
|
|
10610
10630
|
}
|
|
10611
10631
|
var NARROW_BREAKPOINT = 120;
|
|
10612
10632
|
var COLD_START_TURNS = 3;
|
|
@@ -10632,73 +10652,44 @@ function StatsPanel({
|
|
|
10632
10652
|
const columns = stdout2?.columns ?? 80;
|
|
10633
10653
|
const narrow = columns < NARROW_BREAKPOINT;
|
|
10634
10654
|
const coldStart = summary.turns <= COLD_START_TURNS;
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
|
|
10639
|
-
|
|
10640
|
-
|
|
10641
|
-
|
|
10642
|
-
|
|
10643
|
-
|
|
10644
|
-
|
|
10645
|
-
|
|
10646
|
-
|
|
10647
|
-
|
|
10648
|
-
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
|
|
10652
|
-
|
|
10653
|
-
|
|
10654
|
-
|
|
10655
|
-
|
|
10656
|
-
|
|
10657
|
-
|
|
10658
|
-
|
|
10659
|
-
|
|
10660
|
-
|
|
10661
|
-
|
|
10662
|
-
|
|
10663
|
-
|
|
10664
|
-
|
|
10665
|
-
|
|
10666
|
-
|
|
10667
|
-
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
|
|
10673
|
-
InlineMetrics,
|
|
10674
|
-
{
|
|
10675
|
-
summary,
|
|
10676
|
-
ctxRatio,
|
|
10677
|
-
ctxMax,
|
|
10678
|
-
balance,
|
|
10679
|
-
coldStart
|
|
10680
|
-
}
|
|
10681
|
-
), /* @__PURE__ */ React21.createElement(Box19, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(GradientRule, { width: ruleWidth, thin: true, animate })))
|
|
10682
|
-
);
|
|
10683
|
-
}
|
|
10684
|
-
function GradientRule({
|
|
10685
|
-
width,
|
|
10686
|
-
thin,
|
|
10687
|
-
animate
|
|
10688
|
-
}) {
|
|
10689
|
-
const tick = useTick();
|
|
10690
|
-
const offset = animate ? Math.floor(tick / 6) : 0;
|
|
10691
|
-
const ch = thin ? "\u2581" : "\u2584";
|
|
10692
|
-
const len = GRADIENT.length;
|
|
10693
|
-
return /* @__PURE__ */ React21.createElement(Box19, null, Array.from({ length: width }, (_, i) => {
|
|
10694
|
-
const t = width === 1 ? 0 : i * (len - 1) / (width - 1);
|
|
10695
|
-
const idx = (Math.round(t) + offset) % len;
|
|
10696
|
-
const color = GRADIENT[(idx % len + len) % len];
|
|
10697
|
-
return (
|
|
10698
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-width gradient cells never reorder
|
|
10699
|
-
/* @__PURE__ */ React21.createElement(Text17, { key: `grule-${i}`, color }, ch)
|
|
10700
|
-
);
|
|
10701
|
-
}));
|
|
10655
|
+
return /* @__PURE__ */ React21.createElement(Box19, { flexDirection: "column", paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React21.createElement(
|
|
10656
|
+
Header,
|
|
10657
|
+
{
|
|
10658
|
+
model: model2,
|
|
10659
|
+
prefixHash,
|
|
10660
|
+
harvestOn,
|
|
10661
|
+
branchOn,
|
|
10662
|
+
branchBudget: branchBudget ?? 1,
|
|
10663
|
+
reasoningEffort,
|
|
10664
|
+
planMode,
|
|
10665
|
+
editMode,
|
|
10666
|
+
turns: summary.turns,
|
|
10667
|
+
updateAvailable,
|
|
10668
|
+
narrow,
|
|
10669
|
+
busy: busy ?? false,
|
|
10670
|
+
proArmed: proArmed ?? false,
|
|
10671
|
+
escalated: escalated ?? false,
|
|
10672
|
+
animate: false
|
|
10673
|
+
}
|
|
10674
|
+
), narrow ? /* @__PURE__ */ React21.createElement(
|
|
10675
|
+
StackedMetrics,
|
|
10676
|
+
{
|
|
10677
|
+
summary,
|
|
10678
|
+
ctxRatio,
|
|
10679
|
+
ctxMax,
|
|
10680
|
+
balance,
|
|
10681
|
+
coldStart
|
|
10682
|
+
}
|
|
10683
|
+
) : /* @__PURE__ */ React21.createElement(
|
|
10684
|
+
InlineMetrics,
|
|
10685
|
+
{
|
|
10686
|
+
summary,
|
|
10687
|
+
ctxRatio,
|
|
10688
|
+
ctxMax,
|
|
10689
|
+
balance,
|
|
10690
|
+
coldStart
|
|
10691
|
+
}
|
|
10692
|
+
));
|
|
10702
10693
|
}
|
|
10703
10694
|
function Header({
|
|
10704
10695
|
model: model2,
|
|
@@ -10827,9 +10818,9 @@ function WelcomeBanner({ inCodeMode }) {
|
|
|
10827
10818
|
const { stdout: stdout2 } = useStdout7();
|
|
10828
10819
|
const cols = stdout2?.columns ?? 80;
|
|
10829
10820
|
const ruleWidth = Math.min(60, Math.max(28, cols - 4));
|
|
10830
|
-
return /* @__PURE__ */ React22.createElement(Box20, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React22.createElement(
|
|
10821
|
+
return /* @__PURE__ */ React22.createElement(Box20, { flexDirection: "column", paddingX: 1, marginY: 1 }, /* @__PURE__ */ React22.createElement(GradientRule, { width: ruleWidth }), /* @__PURE__ */ React22.createElement(BarRow, null, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: COLOR.brand }, "\u25C8 welcome"), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, " \xB7 type a message to start")), /* @__PURE__ */ React22.createElement(BarRow, null), /* @__PURE__ */ React22.createElement(BarRow, null, /* @__PURE__ */ React22.createElement(Text18, { bold: true, color: COLOR.primary }, "quick start")), /* @__PURE__ */ React22.createElement(Hint, { cmd: "/help", desc: "every command + keyboard shortcut" }), /* @__PURE__ */ React22.createElement(Hint, { cmd: "/skill", desc: "invoke a stored playbook" }), inCodeMode ? /* @__PURE__ */ React22.createElement(React22.Fragment, null, /* @__PURE__ */ React22.createElement(Hint, { cmd: "@path", desc: "inline a file in your message" }), /* @__PURE__ */ React22.createElement(Hint, { cmd: "!cmd", desc: "run a shell command, output goes to context" })) : null, /* @__PURE__ */ React22.createElement(Hint, { cmd: "/exit", desc: "quit (Ctrl+C also works)" }), /* @__PURE__ */ React22.createElement(BarRow, null), /* @__PURE__ */ React22.createElement(BarRow, null, /* @__PURE__ */ React22.createElement(Text18, { dimColor: true, italic: true }, "tip:"), /* @__PURE__ */ React22.createElement(Text18, { dimColor: true }, " Ctrl+J inserts a newline \xB7 trailing \\ also continues")), /* @__PURE__ */ React22.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React22.createElement(GradientRule, { width: ruleWidth, thin: true })));
|
|
10831
10822
|
}
|
|
10832
|
-
function
|
|
10823
|
+
function GradientRule({ width, thin }) {
|
|
10833
10824
|
const cells = gradientCells(width, thin ? "\u2581" : "\u2584");
|
|
10834
10825
|
return /* @__PURE__ */ React22.createElement(Box20, null, cells.map((c, i) => (
|
|
10835
10826
|
// biome-ignore lint/suspicious/noArrayIndexKey: fixed-width gradient row, never reordered
|
|
@@ -10876,10 +10867,50 @@ function formatEditResults(results) {
|
|
|
10876
10867
|
return [header2, ...lines].join("\n");
|
|
10877
10868
|
}
|
|
10878
10869
|
function formatPendingPreview(blocks) {
|
|
10879
|
-
const
|
|
10880
|
-
const
|
|
10870
|
+
const partial = blocks.length > 1 ? " \xB7 /apply N or 1,3-4 for partial" : "";
|
|
10871
|
+
const header2 = `\u25B8 ${blocks.length} pending edit block(s) \u2014 /apply (or y) to commit \xB7 /discard (or n) to drop${partial}`;
|
|
10872
|
+
const diffLines = formatAllBlockDiffs(blocks, { numbered: blocks.length > 1 });
|
|
10881
10873
|
return [header2, ...diffLines].join("\n");
|
|
10882
10874
|
}
|
|
10875
|
+
function parseEditIndices(raw, max) {
|
|
10876
|
+
const trimmed = raw.trim();
|
|
10877
|
+
if (!trimmed) return { ok: [] };
|
|
10878
|
+
if (max <= 0) return { error: "no pending edits to address" };
|
|
10879
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10880
|
+
const tokens = trimmed.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
10881
|
+
if (tokens.length === 0) return { ok: [] };
|
|
10882
|
+
for (const tok of tokens) {
|
|
10883
|
+
const range = tok.match(/^(\d+)-(\d+)$/);
|
|
10884
|
+
if (range) {
|
|
10885
|
+
const a = Number.parseInt(range[1] ?? "", 10);
|
|
10886
|
+
const b = Number.parseInt(range[2] ?? "", 10);
|
|
10887
|
+
if (!Number.isFinite(a) || !Number.isFinite(b) || a < 1 || b < 1) {
|
|
10888
|
+
return { error: `invalid range: "${tok}"` };
|
|
10889
|
+
}
|
|
10890
|
+
const lo = Math.min(a, b);
|
|
10891
|
+
const hi = Math.max(a, b);
|
|
10892
|
+
if (hi > max) return { error: `index ${hi} out of range (max ${max})` };
|
|
10893
|
+
for (let i = lo; i <= hi; i++) seen.add(i);
|
|
10894
|
+
continue;
|
|
10895
|
+
}
|
|
10896
|
+
if (!/^\d+$/.test(tok)) return { error: `invalid index: "${tok}"` };
|
|
10897
|
+
const n = Number.parseInt(tok, 10);
|
|
10898
|
+
if (!Number.isFinite(n) || n < 1) return { error: `invalid index: "${tok}"` };
|
|
10899
|
+
if (n > max) return { error: `index ${n} out of range (max ${max})` };
|
|
10900
|
+
seen.add(n);
|
|
10901
|
+
}
|
|
10902
|
+
return { ok: [...seen].sort((a, b) => a - b) };
|
|
10903
|
+
}
|
|
10904
|
+
function partitionEdits(edits, indices1Based) {
|
|
10905
|
+
const picked = new Set(indices1Based);
|
|
10906
|
+
const selected = [];
|
|
10907
|
+
const remaining = [];
|
|
10908
|
+
for (let i = 0; i < edits.length; i++) {
|
|
10909
|
+
if (picked.has(i + 1)) selected.push(edits[i]);
|
|
10910
|
+
else remaining.push(edits[i]);
|
|
10911
|
+
}
|
|
10912
|
+
return { selected, remaining };
|
|
10913
|
+
}
|
|
10883
10914
|
function formatUndoRows(results) {
|
|
10884
10915
|
return results.map((r) => {
|
|
10885
10916
|
const mark = r.status === "applied" ? "\u2713" : "\u2717";
|
|
@@ -10895,6 +10926,45 @@ function describeRepair(repair) {
|
|
|
10895
10926
|
return parts.length ? `[repair] ${parts.join(", ")}` : "";
|
|
10896
10927
|
}
|
|
10897
10928
|
|
|
10929
|
+
// src/cli/ui/hash-memory.ts
|
|
10930
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
|
|
10931
|
+
import { join as join12 } from "path";
|
|
10932
|
+
var NEW_FILE_HEADER = `# Reasonix project memory
|
|
10933
|
+
|
|
10934
|
+
Notes the user pinned via the \`#\` prompt prefix. The whole file is
|
|
10935
|
+
loaded into the immutable system prefix every session \u2014 keep it terse.
|
|
10936
|
+
|
|
10937
|
+
`;
|
|
10938
|
+
function detectHashMemory(text) {
|
|
10939
|
+
if (text.startsWith("\\#")) {
|
|
10940
|
+
return { kind: "escape", text: text.slice(1) };
|
|
10941
|
+
}
|
|
10942
|
+
if (!text.startsWith("#")) return null;
|
|
10943
|
+
if (text.startsWith("##")) return null;
|
|
10944
|
+
const body = text.slice(1).trim();
|
|
10945
|
+
if (!body) return null;
|
|
10946
|
+
return { kind: "memory", note: body };
|
|
10947
|
+
}
|
|
10948
|
+
function appendProjectMemory(rootDir, note) {
|
|
10949
|
+
const path = join12(rootDir, PROJECT_MEMORY_FILE);
|
|
10950
|
+
const trimmed = note.trim();
|
|
10951
|
+
if (!trimmed) throw new Error("note body cannot be empty");
|
|
10952
|
+
const bullet = `- ${trimmed}
|
|
10953
|
+
`;
|
|
10954
|
+
if (!existsSync11(path)) {
|
|
10955
|
+
writeFileSync7(path, `${NEW_FILE_HEADER}${bullet}`, "utf8");
|
|
10956
|
+
return { path, created: true };
|
|
10957
|
+
}
|
|
10958
|
+
let prefix = "";
|
|
10959
|
+
try {
|
|
10960
|
+
const existing = readFileSync14(path, "utf8");
|
|
10961
|
+
if (existing.length > 0 && !existing.endsWith("\n")) prefix = "\n";
|
|
10962
|
+
} catch {
|
|
10963
|
+
}
|
|
10964
|
+
appendFileSync3(path, `${prefix}${bullet}`, "utf8");
|
|
10965
|
+
return { path, created: false };
|
|
10966
|
+
}
|
|
10967
|
+
|
|
10898
10968
|
// src/cli/ui/mcp-browse.ts
|
|
10899
10969
|
function formatResourceList(servers) {
|
|
10900
10970
|
const lines = [];
|
|
@@ -11202,8 +11272,18 @@ var SLASH_COMMANDS = [
|
|
|
11202
11272
|
{ cmd: "new", summary: "start a fresh conversation (clear context + scrollback)" },
|
|
11203
11273
|
{ cmd: "exit", summary: "quit the TUI" },
|
|
11204
11274
|
// Code-mode only
|
|
11205
|
-
{
|
|
11206
|
-
|
|
11275
|
+
{
|
|
11276
|
+
cmd: "apply",
|
|
11277
|
+
argsHint: "[N|N,M|N-M]",
|
|
11278
|
+
summary: "commit pending edit blocks to disk (no arg \u2192 all; `1`, `1,3`, or `1-4` \u2192 that subset, rest stay pending)",
|
|
11279
|
+
contextual: "code"
|
|
11280
|
+
},
|
|
11281
|
+
{
|
|
11282
|
+
cmd: "discard",
|
|
11283
|
+
argsHint: "[N|N,M|N-M]",
|
|
11284
|
+
summary: "drop pending edit blocks without writing (no arg \u2192 all; indices \u2192 that subset)",
|
|
11285
|
+
contextual: "code"
|
|
11286
|
+
},
|
|
11207
11287
|
{ cmd: "undo", summary: "roll back the last applied edit batch", contextual: "code" },
|
|
11208
11288
|
{
|
|
11209
11289
|
cmd: "history",
|
|
@@ -11292,7 +11372,7 @@ function parseSlash(text) {
|
|
|
11292
11372
|
}
|
|
11293
11373
|
|
|
11294
11374
|
// src/cli/commands/stats.ts
|
|
11295
|
-
import { existsSync as
|
|
11375
|
+
import { existsSync as existsSync12, readFileSync as readFileSync15 } from "fs";
|
|
11296
11376
|
function statsCommand(opts) {
|
|
11297
11377
|
if (opts.transcript) {
|
|
11298
11378
|
transcriptSummary(opts.transcript);
|
|
@@ -11301,11 +11381,11 @@ function statsCommand(opts) {
|
|
|
11301
11381
|
dashboard(opts);
|
|
11302
11382
|
}
|
|
11303
11383
|
function transcriptSummary(path) {
|
|
11304
|
-
if (!
|
|
11384
|
+
if (!existsSync12(path)) {
|
|
11305
11385
|
console.error(`no such transcript: ${path}`);
|
|
11306
11386
|
process.exit(1);
|
|
11307
11387
|
}
|
|
11308
|
-
const lines =
|
|
11388
|
+
const lines = readFileSync15(path, "utf8").split(/\r?\n/).filter(Boolean);
|
|
11309
11389
|
let assistantTurns = 0;
|
|
11310
11390
|
let toolCalls = 0;
|
|
11311
11391
|
let lastTurn = 0;
|
|
@@ -11569,6 +11649,8 @@ var keys = () => ({
|
|
|
11569
11649
|
" Trailing `@\u2026` opens a file picker; \u2191/\u2193 navigate, Tab/Enter pick.",
|
|
11570
11650
|
" !<cmd> run <cmd> as shell in the sandbox root; output goes into context",
|
|
11571
11651
|
" so the model sees it next turn. No allowlist gate.",
|
|
11652
|
+
" #<note> append <note> to REASONIX.md so it pins into every future session.",
|
|
11653
|
+
" Use `\\#literal` if you actually want a `#` heading sent to the model.",
|
|
11572
11654
|
"",
|
|
11573
11655
|
"Pickers (slash + @-mention):",
|
|
11574
11656
|
" \u2191 / \u2193 navigate the suggestion list",
|
|
@@ -11607,8 +11689,8 @@ var help = () => ({
|
|
|
11607
11689
|
" /skill [sub] list / run user skills (project/.reasonix/skills + ~/.reasonix/skills).",
|
|
11608
11690
|
" subs: list | show <name> | <name> [args] (injects skill body as user turn)",
|
|
11609
11691
|
" /retry truncate & resend your last message (fresh sample from the model)",
|
|
11610
|
-
" /apply
|
|
11611
|
-
" /discard
|
|
11692
|
+
" /apply [N|1,3|1-4] (code mode) commit pending edit blocks (no arg \u2192 all; index \u2192 subset)",
|
|
11693
|
+
" /discard [N|1,3|1-4] (code mode) drop pending edits (no arg \u2192 all; index \u2192 subset)",
|
|
11612
11694
|
" /undo (code mode) roll back the latest non-undone edit batch",
|
|
11613
11695
|
" /history (code mode) list every edit batch this session",
|
|
11614
11696
|
" /show [id] (code mode) dump a stored edit diff (newest when id omitted)",
|
|
@@ -11631,6 +11713,12 @@ var help = () => ({
|
|
|
11631
11713
|
" No allowlist gate \u2014 user-typed = explicit consent.",
|
|
11632
11714
|
" Example: !git status !ls src/ !npm test",
|
|
11633
11715
|
"",
|
|
11716
|
+
"Quick memory:",
|
|
11717
|
+
" #<note> append <note> to REASONIX.md (pinned into every",
|
|
11718
|
+
" future session's prefix). Faster than /memory for",
|
|
11719
|
+
" one-liners. Example: #always use pnpm not npm",
|
|
11720
|
+
" Use `\\#text` to send a literal `#text` to the model.",
|
|
11721
|
+
"",
|
|
11634
11722
|
"File references (code mode):",
|
|
11635
11723
|
" @path/to/file inline file content under [Referenced files] on send.",
|
|
11636
11724
|
" Type `@` to open the picker (\u2191\u2193 navigate, Tab/Enter pick).",
|
|
@@ -11800,22 +11888,33 @@ var show = (args, _loop, ctx) => {
|
|
|
11800
11888
|
}
|
|
11801
11889
|
return { info: ctx.codeShowEdit(args) };
|
|
11802
11890
|
};
|
|
11803
|
-
var apply = (
|
|
11891
|
+
var apply = (args, _loop, ctx) => {
|
|
11804
11892
|
if (!ctx.codeApply) {
|
|
11805
11893
|
return {
|
|
11806
11894
|
info: "/apply is only available inside `reasonix code` (nothing to apply here)."
|
|
11807
11895
|
};
|
|
11808
11896
|
}
|
|
11809
|
-
|
|
11897
|
+
const parsed = parseIndicesArg(args, ctx.pendingEditCount ?? 0);
|
|
11898
|
+
if ("error" in parsed) return { info: `/apply: ${parsed.error}` };
|
|
11899
|
+
return { info: ctx.codeApply(parsed.indices) };
|
|
11810
11900
|
};
|
|
11811
|
-
var discard = (
|
|
11901
|
+
var discard = (args, _loop, ctx) => {
|
|
11812
11902
|
if (!ctx.codeDiscard) {
|
|
11813
11903
|
return {
|
|
11814
11904
|
info: "/discard is only available inside `reasonix code`."
|
|
11815
11905
|
};
|
|
11816
11906
|
}
|
|
11817
|
-
|
|
11907
|
+
const parsed = parseIndicesArg(args, ctx.pendingEditCount ?? 0);
|
|
11908
|
+
if ("error" in parsed) return { info: `/discard: ${parsed.error}` };
|
|
11909
|
+
return { info: ctx.codeDiscard(parsed.indices) };
|
|
11818
11910
|
};
|
|
11911
|
+
function parseIndicesArg(args, max) {
|
|
11912
|
+
const raw = args.join(",").replace(/,+/g, ",").replace(/^,|,$/g, "");
|
|
11913
|
+
if (!raw) return { indices: [] };
|
|
11914
|
+
const parsed = parseEditIndices(raw, max);
|
|
11915
|
+
if ("error" in parsed) return { error: parsed.error };
|
|
11916
|
+
return { indices: parsed.ok };
|
|
11917
|
+
}
|
|
11819
11918
|
var plan = (args, _loop, ctx) => {
|
|
11820
11919
|
if (!ctx.setPlanMode) {
|
|
11821
11920
|
return {
|
|
@@ -13192,6 +13291,24 @@ function App({
|
|
|
13192
13291
|
stdout2.write("\x1B[>4m");
|
|
13193
13292
|
};
|
|
13194
13293
|
}, [stdout2]);
|
|
13294
|
+
const [isResizing, setIsResizing] = useState10(false);
|
|
13295
|
+
useEffect6(() => {
|
|
13296
|
+
if (!stdout2 || !stdout2.isTTY) return;
|
|
13297
|
+
let timer = null;
|
|
13298
|
+
const onResize = () => {
|
|
13299
|
+
setIsResizing(true);
|
|
13300
|
+
if (timer) clearTimeout(timer);
|
|
13301
|
+
timer = setTimeout(() => {
|
|
13302
|
+
setIsResizing(false);
|
|
13303
|
+
timer = null;
|
|
13304
|
+
}, 400);
|
|
13305
|
+
};
|
|
13306
|
+
stdout2.on("resize", onResize);
|
|
13307
|
+
return () => {
|
|
13308
|
+
stdout2.off("resize", onResize);
|
|
13309
|
+
if (timer) clearTimeout(timer);
|
|
13310
|
+
};
|
|
13311
|
+
}, [stdout2]);
|
|
13195
13312
|
const { activity: subagentActivity, sinkRef: subagentSinkRef } = useSubagent({
|
|
13196
13313
|
session,
|
|
13197
13314
|
setHistorical
|
|
@@ -13666,29 +13783,50 @@ function App({
|
|
|
13666
13783
|
tools.setToolInterceptor(null);
|
|
13667
13784
|
};
|
|
13668
13785
|
}, [tools, codeMode, session, recordEdit, armUndoBanner, syncPendingCount, setEditMode]);
|
|
13669
|
-
const codeApply = useCallback4(
|
|
13670
|
-
|
|
13671
|
-
|
|
13672
|
-
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13786
|
+
const codeApply = useCallback4(
|
|
13787
|
+
(indices) => {
|
|
13788
|
+
if (!codeMode) return "not in code mode";
|
|
13789
|
+
const blocks = pendingEdits.current;
|
|
13790
|
+
if (blocks.length === 0) {
|
|
13791
|
+
return "nothing pending \u2014 the model hasn't proposed edits since the last /apply or /discard.";
|
|
13792
|
+
}
|
|
13793
|
+
const useSubset = indices !== void 0 && indices.length > 0;
|
|
13794
|
+
const { selected, remaining } = useSubset ? partitionEdits(blocks, indices) : { selected: blocks, remaining: [] };
|
|
13795
|
+
if (selected.length === 0) {
|
|
13796
|
+
return "\u25B8 no edits matched those indices \u2014 nothing applied. Use /apply with no args to commit them all.";
|
|
13797
|
+
}
|
|
13798
|
+
const snaps = snapshotBeforeEdits(selected, codeMode.rootDir);
|
|
13799
|
+
const results = applyEditBlocks(selected, codeMode.rootDir);
|
|
13800
|
+
const anyApplied = results.some((r) => r.status === "applied" || r.status === "created");
|
|
13801
|
+
if (anyApplied) recordEdit("review-apply", selected, results, snaps);
|
|
13802
|
+
pendingEdits.current = remaining;
|
|
13803
|
+
if (remaining.length === 0) clearPendingEdits(session ?? null);
|
|
13804
|
+
else savePendingEdits(session ?? null, remaining);
|
|
13805
|
+
syncPendingCount();
|
|
13806
|
+
const tail = remaining.length > 0 ? `
|
|
13807
|
+
\u25B8 ${remaining.length} edit block(s) still pending \u2014 /apply or /discard to clear them.` : "";
|
|
13808
|
+
return formatEditResults(results) + tail;
|
|
13809
|
+
},
|
|
13810
|
+
[codeMode, session, syncPendingCount, recordEdit]
|
|
13811
|
+
);
|
|
13812
|
+
const codeDiscard = useCallback4(
|
|
13813
|
+
(indices) => {
|
|
13814
|
+
const blocks = pendingEdits.current;
|
|
13815
|
+
if (blocks.length === 0) return "nothing pending to discard.";
|
|
13816
|
+
const useSubset = indices !== void 0 && indices.length > 0;
|
|
13817
|
+
const { selected, remaining } = useSubset ? partitionEdits(blocks, indices) : { selected: blocks, remaining: [] };
|
|
13818
|
+
if (selected.length === 0) {
|
|
13819
|
+
return "\u25B8 no edits matched those indices \u2014 nothing discarded.";
|
|
13820
|
+
}
|
|
13821
|
+
pendingEdits.current = remaining;
|
|
13822
|
+
if (remaining.length === 0) clearPendingEdits(session ?? null);
|
|
13823
|
+
else savePendingEdits(session ?? null, remaining);
|
|
13824
|
+
syncPendingCount();
|
|
13825
|
+
const tail = remaining.length > 0 ? ` (${remaining.length} block(s) still pending)` : ". Nothing was written to disk.";
|
|
13826
|
+
return `\u25B8 discarded ${selected.length} pending edit block(s)${tail}`;
|
|
13827
|
+
},
|
|
13828
|
+
[session, syncPendingCount]
|
|
13829
|
+
);
|
|
13692
13830
|
const prefixHash = loop.prefix.fingerprint;
|
|
13693
13831
|
const writeTranscript = useCallback4(
|
|
13694
13832
|
(ev) => {
|
|
@@ -13743,6 +13881,36 @@ function App({
|
|
|
13743
13881
|
promptHistory.current.push(text);
|
|
13744
13882
|
return;
|
|
13745
13883
|
}
|
|
13884
|
+
const hashParse = detectHashMemory(text);
|
|
13885
|
+
if (hashParse?.kind === "memory") {
|
|
13886
|
+
const memRoot = codeMode?.rootDir ?? process.cwd();
|
|
13887
|
+
promptHistory.current.push(text);
|
|
13888
|
+
try {
|
|
13889
|
+
const result = appendProjectMemory(memRoot, hashParse.note);
|
|
13890
|
+
const verb = result.created ? "created" : "appended to";
|
|
13891
|
+
setHistorical((prev) => [
|
|
13892
|
+
...prev,
|
|
13893
|
+
{
|
|
13894
|
+
id: `hash-${Date.now()}`,
|
|
13895
|
+
role: "info",
|
|
13896
|
+
text: `\u25B8 noted \u2014 ${verb} ${result.path}`
|
|
13897
|
+
}
|
|
13898
|
+
]);
|
|
13899
|
+
} catch (err) {
|
|
13900
|
+
setHistorical((prev) => [
|
|
13901
|
+
...prev,
|
|
13902
|
+
{
|
|
13903
|
+
id: `hash-e-${Date.now()}`,
|
|
13904
|
+
role: "warning",
|
|
13905
|
+
text: `# memory write failed: ${err.message}`
|
|
13906
|
+
}
|
|
13907
|
+
]);
|
|
13908
|
+
}
|
|
13909
|
+
return;
|
|
13910
|
+
}
|
|
13911
|
+
if (hashParse?.kind === "escape") {
|
|
13912
|
+
text = hashParse.text;
|
|
13913
|
+
}
|
|
13746
13914
|
const bangCmd = detectBangCommand(text);
|
|
13747
13915
|
if (bangCmd !== null) {
|
|
13748
13916
|
const bangRoot = codeMode?.rootDir ?? process.cwd();
|
|
@@ -14768,7 +14936,7 @@ Continue executing from the next pending step. Call mark_step_complete after eac
|
|
|
14768
14936
|
return /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(
|
|
14769
14937
|
TickerProvider,
|
|
14770
14938
|
{
|
|
14771
|
-
disabled: PLAIN_UI || !!pendingPlan || !!pendingShell || !!pendingEditReview || !!pendingCheckpoint || !!stagedCheckpointRevise || !!pendingChoice || !!stagedChoiceCustom || !!pendingRevision
|
|
14939
|
+
disabled: PLAIN_UI || isResizing || !!pendingPlan || !!pendingShell || !!pendingEditReview || !!pendingCheckpoint || !!stagedCheckpointRevise || !!pendingChoice || !!stagedChoiceCustom || !!pendingRevision
|
|
14772
14940
|
},
|
|
14773
14941
|
/* @__PURE__ */ React23.createElement(Box21, { flexDirection: "column" }, /* @__PURE__ */ React23.createElement(
|
|
14774
14942
|
StatsPanel,
|
|
@@ -15131,15 +15299,12 @@ async function chatCommand(opts) {
|
|
|
15131
15299
|
const prior = loadSessionMessages(opts.session);
|
|
15132
15300
|
if (prior.length > 0) {
|
|
15133
15301
|
const p = sessionPath(opts.session);
|
|
15134
|
-
const mtime =
|
|
15302
|
+
const mtime = existsSync13(p) ? statSync7(p).mtime : /* @__PURE__ */ new Date();
|
|
15135
15303
|
sessionPreview = { messageCount: prior.length, lastActive: mtime };
|
|
15136
15304
|
}
|
|
15137
15305
|
} else if (opts.session && opts.forceNew) {
|
|
15138
15306
|
rewriteSession(opts.session, []);
|
|
15139
15307
|
}
|
|
15140
|
-
if (process.stdout.isTTY) {
|
|
15141
|
-
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
15142
|
-
}
|
|
15143
15308
|
const { waitUntilExit } = render(
|
|
15144
15309
|
/* @__PURE__ */ React26.createElement(
|
|
15145
15310
|
Root,
|
|
@@ -15167,7 +15332,7 @@ async function chatCommand(opts) {
|
|
|
15167
15332
|
// src/cli/commands/code.tsx
|
|
15168
15333
|
import { basename as basename2, resolve as resolve7 } from "path";
|
|
15169
15334
|
async function codeCommand(opts = {}) {
|
|
15170
|
-
const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-
|
|
15335
|
+
const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-POARCKKR.js");
|
|
15171
15336
|
const rootDir = resolve7(opts.dir ?? process.cwd());
|
|
15172
15337
|
const session = opts.noSession ? void 0 : `code-${sanitizeName(basename2(rootDir))}`;
|
|
15173
15338
|
const tools = new ToolRegistry();
|
|
@@ -15207,7 +15372,7 @@ async function codeCommand(opts = {}) {
|
|
|
15207
15372
|
}
|
|
15208
15373
|
|
|
15209
15374
|
// src/cli/commands/diff.ts
|
|
15210
|
-
import { writeFileSync as
|
|
15375
|
+
import { writeFileSync as writeFileSync8 } from "fs";
|
|
15211
15376
|
import { basename as basename3 } from "path";
|
|
15212
15377
|
import { render as render2 } from "ink";
|
|
15213
15378
|
import React29 from "react";
|
|
@@ -15354,7 +15519,7 @@ async function diffCommand(opts) {
|
|
|
15354
15519
|
if (wantMarkdown) {
|
|
15355
15520
|
console.log(renderSummaryTable(report));
|
|
15356
15521
|
const md = renderMarkdown(report);
|
|
15357
|
-
|
|
15522
|
+
writeFileSync8(opts.mdPath, md, "utf8");
|
|
15358
15523
|
console.log(`
|
|
15359
15524
|
markdown report written to ${opts.mdPath}`);
|
|
15360
15525
|
return;
|
|
@@ -16290,6 +16455,16 @@ function resolveSession(flag, configSession) {
|
|
|
16290
16455
|
if (typeof configSession === "string" && configSession.length > 0) return configSession;
|
|
16291
16456
|
return "default";
|
|
16292
16457
|
}
|
|
16458
|
+
function resolveContinueFlag(flag, fallbackSession, getLatestSession, warn = () => {
|
|
16459
|
+
}) {
|
|
16460
|
+
if (!flag) return { session: fallbackSession, forceResume: false };
|
|
16461
|
+
const latest = getLatestSession();
|
|
16462
|
+
if (!latest) {
|
|
16463
|
+
warn("\u25B8 -c/--continue: no saved sessions yet \u2014 starting a fresh one.");
|
|
16464
|
+
return { session: fallbackSession, forceResume: false };
|
|
16465
|
+
}
|
|
16466
|
+
return { session: latest.name, forceResume: true };
|
|
16467
|
+
}
|
|
16293
16468
|
|
|
16294
16469
|
// src/cli/index.ts
|
|
16295
16470
|
var DEFAULT_SYSTEM = `You are Reasonix, a helpful DeepSeek-powered assistant. Be concise and accurate. Use tools when available.
|
|
@@ -16314,21 +16489,32 @@ The signal isn't a topic list \u2014 it's: "if I'm wrong about this, is it becau
|
|
|
16314
16489
|
|
|
16315
16490
|
${ESCALATION_CONTRACT}`;
|
|
16316
16491
|
var program = new Command();
|
|
16317
|
-
program.name("reasonix").description("DeepSeek-native agent framework \u2014 built for cache hits and cheap tokens.").version(VERSION)
|
|
16318
|
-
|
|
16492
|
+
program.name("reasonix").description("DeepSeek-native agent framework \u2014 built for cache hits and cheap tokens.").version(VERSION).option(
|
|
16493
|
+
"-c, --continue",
|
|
16494
|
+
"Resume the most recently used chat session without showing the picker."
|
|
16495
|
+
);
|
|
16496
|
+
program.action(async (opts) => {
|
|
16319
16497
|
const cfg = readConfig();
|
|
16320
16498
|
if (!cfg.setupCompleted) {
|
|
16321
16499
|
await setupCommand({});
|
|
16322
16500
|
return;
|
|
16323
16501
|
}
|
|
16324
16502
|
const defaults = resolveDefaults({});
|
|
16503
|
+
const continueOpts = resolveContinueFlag(
|
|
16504
|
+
opts.continue,
|
|
16505
|
+
defaults.session,
|
|
16506
|
+
() => listSessions()[0],
|
|
16507
|
+
(msg) => process.stderr.write(`${msg}
|
|
16508
|
+
`)
|
|
16509
|
+
);
|
|
16325
16510
|
await chatCommand({
|
|
16326
16511
|
model: defaults.model,
|
|
16327
16512
|
system: applyMemoryStack(DEFAULT_SYSTEM, process.cwd()),
|
|
16328
16513
|
harvest: defaults.harvest,
|
|
16329
16514
|
branch: defaults.branch,
|
|
16330
|
-
session:
|
|
16331
|
-
mcp: defaults.mcp
|
|
16515
|
+
session: continueOpts.session,
|
|
16516
|
+
mcp: defaults.mcp,
|
|
16517
|
+
forceResume: continueOpts.forceResume
|
|
16332
16518
|
});
|
|
16333
16519
|
});
|
|
16334
16520
|
program.command("setup").description("Interactive wizard \u2014 API key, preset, MCP servers. Re-run any time to reconfigure.").action(async () => {
|
|
@@ -16360,7 +16546,10 @@ program.command("chat").description("Interactive Ink TUI with live cache/cost pa
|
|
|
16360
16546
|
"--branch <n>",
|
|
16361
16547
|
"Self-consistency: run N parallel samples per turn (N\xD7 cost). Manual only \u2014 never auto-enabled.",
|
|
16362
16548
|
(v) => Number.parseInt(v, 10)
|
|
16363
|
-
).option("--session <name>", "Use a named session (default: from config, usually 'default').").option("--no-session", "Disable session persistence for this run (ephemeral chat)").option("-r, --resume", "Skip the session picker \u2014 always continue prior messages").option(
|
|
16549
|
+
).option("--session <name>", "Use a named session (default: from config, usually 'default').").option("--no-session", "Disable session persistence for this run (ephemeral chat)").option("-r, --resume", "Skip the session picker \u2014 always continue prior messages").option(
|
|
16550
|
+
"-c, --continue",
|
|
16551
|
+
"Resume the most-recently-used session (any name) without showing the picker."
|
|
16552
|
+
).option("-n, --new", "Skip the session picker \u2014 always wipe prior messages and start fresh").option(
|
|
16364
16553
|
"--mcp <spec>",
|
|
16365
16554
|
'MCP server spec; repeatable. "name=cmd args...", "cmd args...", or a URL (http/https \u2192 SSE transport). Overrides config.mcp when provided.',
|
|
16366
16555
|
(value, previous = []) => [...previous, value],
|
|
@@ -16378,16 +16567,23 @@ program.command("chat").description("Interactive Ink TUI with live cache/cost pa
|
|
|
16378
16567
|
preset: opts.preset,
|
|
16379
16568
|
noConfig: opts.config === false
|
|
16380
16569
|
});
|
|
16570
|
+
const continueOpts = opts.resume ? { session: defaults.session, forceResume: true } : resolveContinueFlag(
|
|
16571
|
+
opts.continue,
|
|
16572
|
+
defaults.session,
|
|
16573
|
+
() => listSessions()[0],
|
|
16574
|
+
(msg) => process.stderr.write(`${msg}
|
|
16575
|
+
`)
|
|
16576
|
+
);
|
|
16381
16577
|
await chatCommand({
|
|
16382
16578
|
model: defaults.model,
|
|
16383
16579
|
system: applyMemoryStack(opts.system, process.cwd()),
|
|
16384
16580
|
transcript: opts.transcript,
|
|
16385
16581
|
harvest: defaults.harvest,
|
|
16386
16582
|
branch: defaults.branch,
|
|
16387
|
-
session:
|
|
16583
|
+
session: continueOpts.session,
|
|
16388
16584
|
mcp: defaults.mcp,
|
|
16389
16585
|
mcpPrefix: opts.mcpPrefix,
|
|
16390
|
-
forceResume:
|
|
16586
|
+
forceResume: continueOpts.forceResume,
|
|
16391
16587
|
forceNew: !!opts.new
|
|
16392
16588
|
});
|
|
16393
16589
|
});
|