reasonix 0.7.12 → 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 +241 -50
- 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;
|
|
@@ -10866,10 +10867,50 @@ function formatEditResults(results) {
|
|
|
10866
10867
|
return [header2, ...lines].join("\n");
|
|
10867
10868
|
}
|
|
10868
10869
|
function formatPendingPreview(blocks) {
|
|
10869
|
-
const
|
|
10870
|
-
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 });
|
|
10871
10873
|
return [header2, ...diffLines].join("\n");
|
|
10872
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
|
+
}
|
|
10873
10914
|
function formatUndoRows(results) {
|
|
10874
10915
|
return results.map((r) => {
|
|
10875
10916
|
const mark = r.status === "applied" ? "\u2713" : "\u2717";
|
|
@@ -10885,6 +10926,45 @@ function describeRepair(repair) {
|
|
|
10885
10926
|
return parts.length ? `[repair] ${parts.join(", ")}` : "";
|
|
10886
10927
|
}
|
|
10887
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
|
+
|
|
10888
10968
|
// src/cli/ui/mcp-browse.ts
|
|
10889
10969
|
function formatResourceList(servers) {
|
|
10890
10970
|
const lines = [];
|
|
@@ -11192,8 +11272,18 @@ var SLASH_COMMANDS = [
|
|
|
11192
11272
|
{ cmd: "new", summary: "start a fresh conversation (clear context + scrollback)" },
|
|
11193
11273
|
{ cmd: "exit", summary: "quit the TUI" },
|
|
11194
11274
|
// Code-mode only
|
|
11195
|
-
{
|
|
11196
|
-
|
|
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
|
+
},
|
|
11197
11287
|
{ cmd: "undo", summary: "roll back the last applied edit batch", contextual: "code" },
|
|
11198
11288
|
{
|
|
11199
11289
|
cmd: "history",
|
|
@@ -11282,7 +11372,7 @@ function parseSlash(text) {
|
|
|
11282
11372
|
}
|
|
11283
11373
|
|
|
11284
11374
|
// src/cli/commands/stats.ts
|
|
11285
|
-
import { existsSync as
|
|
11375
|
+
import { existsSync as existsSync12, readFileSync as readFileSync15 } from "fs";
|
|
11286
11376
|
function statsCommand(opts) {
|
|
11287
11377
|
if (opts.transcript) {
|
|
11288
11378
|
transcriptSummary(opts.transcript);
|
|
@@ -11291,11 +11381,11 @@ function statsCommand(opts) {
|
|
|
11291
11381
|
dashboard(opts);
|
|
11292
11382
|
}
|
|
11293
11383
|
function transcriptSummary(path) {
|
|
11294
|
-
if (!
|
|
11384
|
+
if (!existsSync12(path)) {
|
|
11295
11385
|
console.error(`no such transcript: ${path}`);
|
|
11296
11386
|
process.exit(1);
|
|
11297
11387
|
}
|
|
11298
|
-
const lines =
|
|
11388
|
+
const lines = readFileSync15(path, "utf8").split(/\r?\n/).filter(Boolean);
|
|
11299
11389
|
let assistantTurns = 0;
|
|
11300
11390
|
let toolCalls = 0;
|
|
11301
11391
|
let lastTurn = 0;
|
|
@@ -11559,6 +11649,8 @@ var keys = () => ({
|
|
|
11559
11649
|
" Trailing `@\u2026` opens a file picker; \u2191/\u2193 navigate, Tab/Enter pick.",
|
|
11560
11650
|
" !<cmd> run <cmd> as shell in the sandbox root; output goes into context",
|
|
11561
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.",
|
|
11562
11654
|
"",
|
|
11563
11655
|
"Pickers (slash + @-mention):",
|
|
11564
11656
|
" \u2191 / \u2193 navigate the suggestion list",
|
|
@@ -11597,8 +11689,8 @@ var help = () => ({
|
|
|
11597
11689
|
" /skill [sub] list / run user skills (project/.reasonix/skills + ~/.reasonix/skills).",
|
|
11598
11690
|
" subs: list | show <name> | <name> [args] (injects skill body as user turn)",
|
|
11599
11691
|
" /retry truncate & resend your last message (fresh sample from the model)",
|
|
11600
|
-
" /apply
|
|
11601
|
-
" /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)",
|
|
11602
11694
|
" /undo (code mode) roll back the latest non-undone edit batch",
|
|
11603
11695
|
" /history (code mode) list every edit batch this session",
|
|
11604
11696
|
" /show [id] (code mode) dump a stored edit diff (newest when id omitted)",
|
|
@@ -11621,6 +11713,12 @@ var help = () => ({
|
|
|
11621
11713
|
" No allowlist gate \u2014 user-typed = explicit consent.",
|
|
11622
11714
|
" Example: !git status !ls src/ !npm test",
|
|
11623
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
|
+
"",
|
|
11624
11722
|
"File references (code mode):",
|
|
11625
11723
|
" @path/to/file inline file content under [Referenced files] on send.",
|
|
11626
11724
|
" Type `@` to open the picker (\u2191\u2193 navigate, Tab/Enter pick).",
|
|
@@ -11790,22 +11888,33 @@ var show = (args, _loop, ctx) => {
|
|
|
11790
11888
|
}
|
|
11791
11889
|
return { info: ctx.codeShowEdit(args) };
|
|
11792
11890
|
};
|
|
11793
|
-
var apply = (
|
|
11891
|
+
var apply = (args, _loop, ctx) => {
|
|
11794
11892
|
if (!ctx.codeApply) {
|
|
11795
11893
|
return {
|
|
11796
11894
|
info: "/apply is only available inside `reasonix code` (nothing to apply here)."
|
|
11797
11895
|
};
|
|
11798
11896
|
}
|
|
11799
|
-
|
|
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) };
|
|
11800
11900
|
};
|
|
11801
|
-
var discard = (
|
|
11901
|
+
var discard = (args, _loop, ctx) => {
|
|
11802
11902
|
if (!ctx.codeDiscard) {
|
|
11803
11903
|
return {
|
|
11804
11904
|
info: "/discard is only available inside `reasonix code`."
|
|
11805
11905
|
};
|
|
11806
11906
|
}
|
|
11807
|
-
|
|
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) };
|
|
11808
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
|
+
}
|
|
11809
11918
|
var plan = (args, _loop, ctx) => {
|
|
11810
11919
|
if (!ctx.setPlanMode) {
|
|
11811
11920
|
return {
|
|
@@ -13674,29 +13783,50 @@ function App({
|
|
|
13674
13783
|
tools.setToolInterceptor(null);
|
|
13675
13784
|
};
|
|
13676
13785
|
}, [tools, codeMode, session, recordEdit, armUndoBanner, syncPendingCount, setEditMode]);
|
|
13677
|
-
const codeApply = useCallback4(
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
|
|
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
|
+
);
|
|
13700
13830
|
const prefixHash = loop.prefix.fingerprint;
|
|
13701
13831
|
const writeTranscript = useCallback4(
|
|
13702
13832
|
(ev) => {
|
|
@@ -13751,6 +13881,36 @@ function App({
|
|
|
13751
13881
|
promptHistory.current.push(text);
|
|
13752
13882
|
return;
|
|
13753
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
|
+
}
|
|
13754
13914
|
const bangCmd = detectBangCommand(text);
|
|
13755
13915
|
if (bangCmd !== null) {
|
|
13756
13916
|
const bangRoot = codeMode?.rootDir ?? process.cwd();
|
|
@@ -15139,7 +15299,7 @@ async function chatCommand(opts) {
|
|
|
15139
15299
|
const prior = loadSessionMessages(opts.session);
|
|
15140
15300
|
if (prior.length > 0) {
|
|
15141
15301
|
const p = sessionPath(opts.session);
|
|
15142
|
-
const mtime =
|
|
15302
|
+
const mtime = existsSync13(p) ? statSync7(p).mtime : /* @__PURE__ */ new Date();
|
|
15143
15303
|
sessionPreview = { messageCount: prior.length, lastActive: mtime };
|
|
15144
15304
|
}
|
|
15145
15305
|
} else if (opts.session && opts.forceNew) {
|
|
@@ -15172,7 +15332,7 @@ async function chatCommand(opts) {
|
|
|
15172
15332
|
// src/cli/commands/code.tsx
|
|
15173
15333
|
import { basename as basename2, resolve as resolve7 } from "path";
|
|
15174
15334
|
async function codeCommand(opts = {}) {
|
|
15175
|
-
const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-
|
|
15335
|
+
const { codeSystemPrompt: codeSystemPrompt2 } = await import("./prompt-POARCKKR.js");
|
|
15176
15336
|
const rootDir = resolve7(opts.dir ?? process.cwd());
|
|
15177
15337
|
const session = opts.noSession ? void 0 : `code-${sanitizeName(basename2(rootDir))}`;
|
|
15178
15338
|
const tools = new ToolRegistry();
|
|
@@ -15212,7 +15372,7 @@ async function codeCommand(opts = {}) {
|
|
|
15212
15372
|
}
|
|
15213
15373
|
|
|
15214
15374
|
// src/cli/commands/diff.ts
|
|
15215
|
-
import { writeFileSync as
|
|
15375
|
+
import { writeFileSync as writeFileSync8 } from "fs";
|
|
15216
15376
|
import { basename as basename3 } from "path";
|
|
15217
15377
|
import { render as render2 } from "ink";
|
|
15218
15378
|
import React29 from "react";
|
|
@@ -15359,7 +15519,7 @@ async function diffCommand(opts) {
|
|
|
15359
15519
|
if (wantMarkdown) {
|
|
15360
15520
|
console.log(renderSummaryTable(report));
|
|
15361
15521
|
const md = renderMarkdown(report);
|
|
15362
|
-
|
|
15522
|
+
writeFileSync8(opts.mdPath, md, "utf8");
|
|
15363
15523
|
console.log(`
|
|
15364
15524
|
markdown report written to ${opts.mdPath}`);
|
|
15365
15525
|
return;
|
|
@@ -16295,6 +16455,16 @@ function resolveSession(flag, configSession) {
|
|
|
16295
16455
|
if (typeof configSession === "string" && configSession.length > 0) return configSession;
|
|
16296
16456
|
return "default";
|
|
16297
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
|
+
}
|
|
16298
16468
|
|
|
16299
16469
|
// src/cli/index.ts
|
|
16300
16470
|
var DEFAULT_SYSTEM = `You are Reasonix, a helpful DeepSeek-powered assistant. Be concise and accurate. Use tools when available.
|
|
@@ -16319,21 +16489,32 @@ The signal isn't a topic list \u2014 it's: "if I'm wrong about this, is it becau
|
|
|
16319
16489
|
|
|
16320
16490
|
${ESCALATION_CONTRACT}`;
|
|
16321
16491
|
var program = new Command();
|
|
16322
|
-
program.name("reasonix").description("DeepSeek-native agent framework \u2014 built for cache hits and cheap tokens.").version(VERSION)
|
|
16323
|
-
|
|
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) => {
|
|
16324
16497
|
const cfg = readConfig();
|
|
16325
16498
|
if (!cfg.setupCompleted) {
|
|
16326
16499
|
await setupCommand({});
|
|
16327
16500
|
return;
|
|
16328
16501
|
}
|
|
16329
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
|
+
);
|
|
16330
16510
|
await chatCommand({
|
|
16331
16511
|
model: defaults.model,
|
|
16332
16512
|
system: applyMemoryStack(DEFAULT_SYSTEM, process.cwd()),
|
|
16333
16513
|
harvest: defaults.harvest,
|
|
16334
16514
|
branch: defaults.branch,
|
|
16335
|
-
session:
|
|
16336
|
-
mcp: defaults.mcp
|
|
16515
|
+
session: continueOpts.session,
|
|
16516
|
+
mcp: defaults.mcp,
|
|
16517
|
+
forceResume: continueOpts.forceResume
|
|
16337
16518
|
});
|
|
16338
16519
|
});
|
|
16339
16520
|
program.command("setup").description("Interactive wizard \u2014 API key, preset, MCP servers. Re-run any time to reconfigure.").action(async () => {
|
|
@@ -16365,7 +16546,10 @@ program.command("chat").description("Interactive Ink TUI with live cache/cost pa
|
|
|
16365
16546
|
"--branch <n>",
|
|
16366
16547
|
"Self-consistency: run N parallel samples per turn (N\xD7 cost). Manual only \u2014 never auto-enabled.",
|
|
16367
16548
|
(v) => Number.parseInt(v, 10)
|
|
16368
|
-
).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(
|
|
16369
16553
|
"--mcp <spec>",
|
|
16370
16554
|
'MCP server spec; repeatable. "name=cmd args...", "cmd args...", or a URL (http/https \u2192 SSE transport). Overrides config.mcp when provided.',
|
|
16371
16555
|
(value, previous = []) => [...previous, value],
|
|
@@ -16383,16 +16567,23 @@ program.command("chat").description("Interactive Ink TUI with live cache/cost pa
|
|
|
16383
16567
|
preset: opts.preset,
|
|
16384
16568
|
noConfig: opts.config === false
|
|
16385
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
|
+
);
|
|
16386
16577
|
await chatCommand({
|
|
16387
16578
|
model: defaults.model,
|
|
16388
16579
|
system: applyMemoryStack(opts.system, process.cwd()),
|
|
16389
16580
|
transcript: opts.transcript,
|
|
16390
16581
|
harvest: defaults.harvest,
|
|
16391
16582
|
branch: defaults.branch,
|
|
16392
|
-
session:
|
|
16583
|
+
session: continueOpts.session,
|
|
16393
16584
|
mcp: defaults.mcp,
|
|
16394
16585
|
mcpPrefix: opts.mcpPrefix,
|
|
16395
|
-
forceResume:
|
|
16586
|
+
forceResume: continueOpts.forceResume,
|
|
16396
16587
|
forceNew: !!opts.new
|
|
16397
16588
|
});
|
|
16398
16589
|
});
|