@deepwhale/coding-agent 1.0.9 → 1.0.11
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/LICENSE +21 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/tui-ink-bundle.js +629 -109
- package/dist/util/index.d.ts +16 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +16 -0
- package/dist/util/index.js.map +1 -0
- package/dist/util/tui-history.d.ts +37 -0
- package/dist/util/tui-history.d.ts.map +1 -0
- package/dist/util/tui-history.js +93 -0
- package/dist/util/tui-history.js.map +1 -0
- package/dist/verify/verify-runner.d.ts +23 -0
- package/dist/verify/verify-runner.d.ts.map +1 -1
- package/dist/verify/verify-runner.js +26 -6
- package/dist/verify/verify-runner.js.map +1 -1
- package/package.json +2 -2
package/dist/tui-ink-bundle.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// @deepwhale/tui-ink — D-24 full Ink TUI container. Self-contained ESM bundle.
|
|
3
|
-
// Built 2026-06-
|
|
3
|
+
// Built 2026-06-07T09:33:55.188Z
|
|
4
4
|
import { createRequire as __cr } from 'node:module';
|
|
5
5
|
import { fileURLToPath as __fpath } from 'node:url';
|
|
6
6
|
const require = __cr(__fpath(import.meta.url));
|
|
@@ -37641,7 +37641,7 @@ var import_react32 = __toESM(require_react(), 1);
|
|
|
37641
37641
|
var import_react33 = __toESM(require_react(), 1);
|
|
37642
37642
|
|
|
37643
37643
|
// src/app.tsx
|
|
37644
|
-
var
|
|
37644
|
+
var import_react46 = __toESM(require_react(), 1);
|
|
37645
37645
|
|
|
37646
37646
|
// src/theme/index.ts
|
|
37647
37647
|
import { stderr } from "node:process";
|
|
@@ -37875,6 +37875,16 @@ function sealLastAssistant() {
|
|
|
37875
37875
|
$transcript.set([...entries.slice(0, -1), { ...last, streaming: false }]);
|
|
37876
37876
|
}
|
|
37877
37877
|
}
|
|
37878
|
+
function appendReasoningChunk(delta) {
|
|
37879
|
+
const entries = $transcript.get();
|
|
37880
|
+
const last = entries[entries.length - 1];
|
|
37881
|
+
if (last && last.kind === "assistant") {
|
|
37882
|
+
const newReasoning = (last.reasoning ?? "") + delta;
|
|
37883
|
+
$transcript.set([...entries.slice(0, -1), { ...last, reasoning: newReasoning }]);
|
|
37884
|
+
} else {
|
|
37885
|
+
$transcript.set([...entries, { kind: "assistant", text: "", reasoning: delta }]);
|
|
37886
|
+
}
|
|
37887
|
+
}
|
|
37878
37888
|
|
|
37879
37889
|
// src/components/StatusBar.tsx
|
|
37880
37890
|
import { formatUsageStatus } from "@deepwhale/coding-agent";
|
|
@@ -37905,38 +37915,297 @@ function StatusBar({ theme = THEMES.default, usage: usageOverride }) {
|
|
|
37905
37915
|
] });
|
|
37906
37916
|
}
|
|
37907
37917
|
|
|
37908
|
-
// src/components/
|
|
37918
|
+
// src/components/Markdown.tsx
|
|
37919
|
+
var import_react37 = __toESM(require_react(), 1);
|
|
37920
|
+
|
|
37921
|
+
// src/markdown/render.tsx
|
|
37922
|
+
var import_react36 = __toESM(require_react(), 1);
|
|
37909
37923
|
var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
|
|
37910
|
-
|
|
37924
|
+
var INLINE_RE = /(?:\[([^\]]+)\]\(([^)\s]+)\)|`([^`]+)`|\*\*([^*]+)\*\*|\*([^*]+)\*|~~([^~]+)~~)/g;
|
|
37925
|
+
var MEDIA_LINE_RE = /^\s*[`"']?MEDIA:\s*(\S+?)[`"']?\s*$/;
|
|
37926
|
+
var AUDIO_DIRECTIVE_RE = /^\s*\[\[audio_as_voice\]\]\s*$/;
|
|
37927
|
+
var FENCE_RE = /^(\s*)(`{3,}|~{3,})(.*)$/;
|
|
37928
|
+
var HEADING_RE = /^(#{1,6})\s+(.*)$/;
|
|
37929
|
+
var LIST_RE = /^(\s*)([-*+])\s+(.*)$/;
|
|
37930
|
+
var OLIST_RE = /^(\s*)(\d+)\.\s+(.*)$/;
|
|
37931
|
+
var BLOCKQUOTE_RE = /^>\s+(.*)$/;
|
|
37932
|
+
var HR_RE = /^[-*_]{3,}$/;
|
|
37933
|
+
function renderInline(line, theme, keyBase) {
|
|
37934
|
+
const out = [];
|
|
37935
|
+
let lastIdx = 0;
|
|
37936
|
+
let m;
|
|
37937
|
+
let counter = 0;
|
|
37938
|
+
INLINE_RE.lastIndex = 0;
|
|
37939
|
+
while ((m = INLINE_RE.exec(line)) !== null) {
|
|
37940
|
+
if (m.index > lastIdx) {
|
|
37941
|
+
out.push(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react36.Fragment, { children: line.slice(lastIdx, m.index) }, `${keyBase}-t-${counter++}`));
|
|
37942
|
+
}
|
|
37943
|
+
if (m[1] !== void 0 && m[2] !== void 0) {
|
|
37944
|
+
out.push(
|
|
37945
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: theme.toolName, underline: true, children: [
|
|
37946
|
+
m[1],
|
|
37947
|
+
" (",
|
|
37948
|
+
m[2],
|
|
37949
|
+
")"
|
|
37950
|
+
] }, `${keyBase}-l-${counter++}`)
|
|
37951
|
+
);
|
|
37952
|
+
} else if (m[3] !== void 0) {
|
|
37953
|
+
out.push(
|
|
37954
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: theme.model, children: `\`${m[3]}\`` }, `${keyBase}-c-${counter++}`)
|
|
37955
|
+
);
|
|
37956
|
+
} else if (m[4] !== void 0) {
|
|
37957
|
+
out.push(
|
|
37958
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { bold: true, children: m[4] }, `${keyBase}-b-${counter++}`)
|
|
37959
|
+
);
|
|
37960
|
+
} else if (m[5] !== void 0) {
|
|
37961
|
+
out.push(
|
|
37962
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { italic: true, children: m[5] }, `${keyBase}-i-${counter++}`)
|
|
37963
|
+
);
|
|
37964
|
+
} else if (m[6] !== void 0) {
|
|
37965
|
+
out.push(
|
|
37966
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { strikethrough: true, children: m[6] }, `${keyBase}-s-${counter++}`)
|
|
37967
|
+
);
|
|
37968
|
+
}
|
|
37969
|
+
lastIdx = m.index + m[0].length;
|
|
37970
|
+
}
|
|
37971
|
+
if (lastIdx < line.length) {
|
|
37972
|
+
out.push(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react36.Fragment, { children: line.slice(lastIdx) }, `${keyBase}-t-${counter++}`));
|
|
37973
|
+
}
|
|
37974
|
+
return out.length > 0 ? out : [/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react36.Fragment, { children: line }, `${keyBase}-raw`)];
|
|
37975
|
+
}
|
|
37976
|
+
function renderFence(content, lang, keyBase, theme) {
|
|
37977
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "column", borderStyle: "single", borderColor: theme.divider, paddingX: 1, marginY: 0, children: [
|
|
37978
|
+
lang && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: theme.model, dimColor: true, children: lang }, `${keyBase}-lang`),
|
|
37979
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: content }, `${keyBase}-body`)
|
|
37980
|
+
] }, keyBase);
|
|
37981
|
+
}
|
|
37982
|
+
function tryParseFence(lines, startLine) {
|
|
37983
|
+
const firstLine = lines[startLine];
|
|
37984
|
+
const m = firstLine.match(FENCE_RE);
|
|
37985
|
+
if (!m) return null;
|
|
37986
|
+
const fenceChar = m[2][0];
|
|
37987
|
+
const fenceLen = m[2].length;
|
|
37988
|
+
const lang = m[3].trim();
|
|
37989
|
+
const bodyLines = [];
|
|
37990
|
+
let i = startLine + 1;
|
|
37991
|
+
while (i < lines.length) {
|
|
37992
|
+
const line = lines[i];
|
|
37993
|
+
const closeMatch = line.match(new RegExp(`^\\s*\\${fenceChar}{${fenceLen},}\\s*$`));
|
|
37994
|
+
if (closeMatch) {
|
|
37995
|
+
return {
|
|
37996
|
+
type: "fence",
|
|
37997
|
+
lang,
|
|
37998
|
+
body: bodyLines.join("\n"),
|
|
37999
|
+
endLine: i
|
|
38000
|
+
};
|
|
38001
|
+
}
|
|
38002
|
+
bodyLines.push(line.replace(/^ {0,3}/, ""));
|
|
38003
|
+
i++;
|
|
38004
|
+
}
|
|
38005
|
+
return null;
|
|
38006
|
+
}
|
|
38007
|
+
function tryParseTable(lines, startLine) {
|
|
38008
|
+
const line0 = lines[startLine];
|
|
38009
|
+
const line1 = lines[startLine + 1];
|
|
38010
|
+
if (!line1) return null;
|
|
38011
|
+
if (!line0.includes("|") || !line1.includes("|")) return null;
|
|
38012
|
+
const cells1 = line1.split("|").map((c) => c.trim()).filter((c) => c.length > 0);
|
|
38013
|
+
if (cells1.length < 2) return null;
|
|
38014
|
+
if (!cells1.every((c) => /^:?-+:?\s*$/.test(c))) return null;
|
|
38015
|
+
const header = line0.split("|").map((c) => c.trim()).filter((c) => c.length > 0);
|
|
38016
|
+
if (header.length !== cells1.length) return null;
|
|
38017
|
+
const rows = [];
|
|
38018
|
+
let i = startLine + 2;
|
|
38019
|
+
while (i < lines.length) {
|
|
38020
|
+
const line = lines[i];
|
|
38021
|
+
if (!line.includes("|")) break;
|
|
38022
|
+
const row = line.split("|").map((c) => c.trim()).filter((c) => c.length > 0);
|
|
38023
|
+
rows.push(row);
|
|
38024
|
+
i++;
|
|
38025
|
+
}
|
|
38026
|
+
return { type: "table", header, rows, endLine: i - 1 };
|
|
38027
|
+
}
|
|
38028
|
+
function renderMarkdown(text, theme) {
|
|
38029
|
+
const lines = text.split("\n");
|
|
38030
|
+
const out = [];
|
|
38031
|
+
let i = 0;
|
|
38032
|
+
let blockCounter = 0;
|
|
38033
|
+
while (i < lines.length) {
|
|
38034
|
+
const line = lines[i];
|
|
38035
|
+
const blockKey = `md-${blockCounter++}`;
|
|
38036
|
+
if (MEDIA_LINE_RE.test(line)) {
|
|
38037
|
+
const path = line.match(MEDIA_LINE_RE)[1];
|
|
38038
|
+
out.push(
|
|
38039
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: theme.toolName, children: `[image: ${path}]` }, blockKey)
|
|
38040
|
+
);
|
|
38041
|
+
i++;
|
|
38042
|
+
continue;
|
|
38043
|
+
}
|
|
38044
|
+
if (AUDIO_DIRECTIVE_RE.test(line)) {
|
|
38045
|
+
out.push(
|
|
38046
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: theme.model, children: "\u{1F50A} audio: (TTS pending \u2014 D-28+ \u5347\u7EA7 mmx-cli TTS)" }, blockKey)
|
|
38047
|
+
);
|
|
38048
|
+
i++;
|
|
38049
|
+
continue;
|
|
38050
|
+
}
|
|
38051
|
+
const fence = tryParseFence(lines, i);
|
|
38052
|
+
if (fence) {
|
|
38053
|
+
out.push(renderFence(fence.body, fence.lang, blockKey, theme));
|
|
38054
|
+
i = fence.endLine + 1;
|
|
38055
|
+
continue;
|
|
38056
|
+
}
|
|
38057
|
+
const table = tryParseTable(lines, i);
|
|
38058
|
+
if (table) {
|
|
38059
|
+
out.push(
|
|
38060
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "column", marginY: 0, children: [
|
|
38061
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { children: table.header.map((cell, idx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { bold: true, color: theme.header, children: ` ${cell.padEnd(15)} ` }, `${blockKey}-h-${idx}`)) }, `${blockKey}-hr`),
|
|
38062
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: theme.divider, children: "\u2500".repeat(15 * table.header.length + 3) }, `${blockKey}-hr-sep`),
|
|
38063
|
+
table.rows.map((row, rowIdx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { children: row.map((cell, cellIdx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: ` ${cell.padEnd(15)} ` }, `${blockKey}-r-${rowIdx}-c-${cellIdx}`)) }, `${blockKey}-r-${rowIdx}`))
|
|
38064
|
+
] }, blockKey)
|
|
38065
|
+
);
|
|
38066
|
+
i = table.endLine + 1;
|
|
38067
|
+
continue;
|
|
38068
|
+
}
|
|
38069
|
+
const headingMatch = line.match(HEADING_RE);
|
|
38070
|
+
if (headingMatch) {
|
|
38071
|
+
const level = headingMatch[1].length;
|
|
38072
|
+
const text2 = headingMatch[2];
|
|
38073
|
+
out.push(
|
|
38074
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { bold: true, color: theme.header, children: "#".repeat(level) + " " + text2 }, blockKey)
|
|
38075
|
+
);
|
|
38076
|
+
i++;
|
|
38077
|
+
continue;
|
|
38078
|
+
}
|
|
38079
|
+
if (HR_RE.test(line)) {
|
|
38080
|
+
out.push(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: theme.divider, children: "\u2500".repeat(40) }, blockKey));
|
|
38081
|
+
i++;
|
|
38082
|
+
continue;
|
|
38083
|
+
}
|
|
38084
|
+
const listMatch = line.match(LIST_RE);
|
|
38085
|
+
if (listMatch) {
|
|
38086
|
+
out.push(
|
|
38087
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: ` ${listMatch[1]}\u2022 ${listMatch[3]}` }, blockKey)
|
|
38088
|
+
);
|
|
38089
|
+
i++;
|
|
38090
|
+
continue;
|
|
38091
|
+
}
|
|
38092
|
+
const olistMatch = line.match(OLIST_RE);
|
|
38093
|
+
if (olistMatch) {
|
|
38094
|
+
out.push(
|
|
38095
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: ` ${olistMatch[1]}${olistMatch[2]}. ${olistMatch[3]}` }, blockKey)
|
|
38096
|
+
);
|
|
38097
|
+
i++;
|
|
38098
|
+
continue;
|
|
38099
|
+
}
|
|
38100
|
+
const bqMatch = line.match(BLOCKQUOTE_RE);
|
|
38101
|
+
if (bqMatch) {
|
|
38102
|
+
out.push(
|
|
38103
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: theme.divider, children: `\u2502 ${bqMatch[1]}` }, blockKey)
|
|
38104
|
+
);
|
|
38105
|
+
i++;
|
|
38106
|
+
continue;
|
|
38107
|
+
}
|
|
38108
|
+
if (line.trim().length > 0) {
|
|
38109
|
+
out.push(
|
|
38110
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: renderInline(line, theme, blockKey) }, blockKey)
|
|
38111
|
+
);
|
|
38112
|
+
} else {
|
|
38113
|
+
out.push(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: " " }, blockKey));
|
|
38114
|
+
}
|
|
38115
|
+
i++;
|
|
38116
|
+
}
|
|
38117
|
+
return out;
|
|
38118
|
+
}
|
|
38119
|
+
|
|
38120
|
+
// src/components/Markdown.tsx
|
|
38121
|
+
var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
|
|
38122
|
+
function Markdown({ text, theme, inline = false }) {
|
|
38123
|
+
const nodes = renderMarkdown(text, theme);
|
|
38124
|
+
if (inline) {
|
|
38125
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { children: nodes.map((node, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react37.Fragment, { children: node }, `md-inline-${i}`)) });
|
|
38126
|
+
}
|
|
38127
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Box_default, { flexDirection: "column", children: nodes });
|
|
38128
|
+
}
|
|
38129
|
+
|
|
38130
|
+
// src/components/Thinking.tsx
|
|
38131
|
+
var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
|
|
38132
|
+
function Thinking({
|
|
38133
|
+
reasoning,
|
|
38134
|
+
theme,
|
|
38135
|
+
initialState = "collapsed"
|
|
38136
|
+
}) {
|
|
38137
|
+
if (!reasoning || reasoning.length === 0) return null;
|
|
38138
|
+
if (initialState === "hidden") return null;
|
|
38139
|
+
if (initialState === "collapsed") {
|
|
38140
|
+
const preview = reasoning.slice(0, 60).replace(/\n/g, " ");
|
|
38141
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { children: [
|
|
38142
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { children: colorize2("\u{1F4AD} ", "model", theme) }),
|
|
38143
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { dimColor: true, children: [
|
|
38144
|
+
preview,
|
|
38145
|
+
reasoning.length > 60 ? "..." : ""
|
|
38146
|
+
] }),
|
|
38147
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { children: colorize2(" (press to expand)", "divider", theme) })
|
|
38148
|
+
] });
|
|
38149
|
+
}
|
|
38150
|
+
const lines = reasoning.split("\n");
|
|
38151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: theme.divider, paddingX: 1, marginY: 0, children: [
|
|
38152
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { children: [
|
|
38153
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { children: colorize2("\u{1F4AD} thinking", "model", theme) }),
|
|
38154
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { children: colorize2(" (press to collapse)", "divider", theme) })
|
|
38155
|
+
] }),
|
|
38156
|
+
lines.map((line, idx) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { children: line }, `think-${idx}`))
|
|
38157
|
+
] });
|
|
38158
|
+
}
|
|
38159
|
+
|
|
38160
|
+
// src/components/Transcript.tsx
|
|
38161
|
+
var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
|
|
38162
|
+
function Transcript({ theme = THEMES.default, markdown = false, thinking = true }) {
|
|
37911
38163
|
const entries = useStore($transcript);
|
|
37912
38164
|
const lastStreaming = entries[entries.length - 1];
|
|
37913
38165
|
const isLastStreaming = lastStreaming?.kind === "assistant" && lastStreaming.streaming === true;
|
|
37914
38166
|
const sealedEntries = isLastStreaming ? entries.slice(0, -1) : entries;
|
|
37915
|
-
return /* @__PURE__ */ (0,
|
|
37916
|
-
/* @__PURE__ */ (0,
|
|
37917
|
-
isLastStreaming && lastStreaming ? /* @__PURE__ */ (0,
|
|
38167
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
38168
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Static, { items: sealedEntries, children: (entry, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TranscriptRow, { entry, theme, markdown, thinking }, `entry-${index}`) }),
|
|
38169
|
+
isLastStreaming && lastStreaming ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TranscriptRow, { entry: lastStreaming, theme, markdown, thinking }) : null
|
|
37918
38170
|
] });
|
|
37919
38171
|
}
|
|
37920
|
-
function TranscriptRow({
|
|
38172
|
+
function TranscriptRow({
|
|
38173
|
+
entry,
|
|
38174
|
+
theme,
|
|
38175
|
+
markdown,
|
|
38176
|
+
thinking
|
|
38177
|
+
}) {
|
|
37921
38178
|
switch (entry.kind) {
|
|
37922
38179
|
case "user":
|
|
37923
|
-
return /* @__PURE__ */ (0,
|
|
38180
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
|
|
37924
38181
|
colorize2("\u203A ", "prompt", theme),
|
|
37925
38182
|
entry.text
|
|
37926
38183
|
] });
|
|
37927
38184
|
case "assistant": {
|
|
37928
38185
|
const prefix = colorize2(" ", "model", theme);
|
|
37929
|
-
|
|
37930
|
-
|
|
37931
|
-
|
|
37932
|
-
|
|
38186
|
+
if (markdown) {
|
|
38187
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
38188
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
|
|
38189
|
+
prefix,
|
|
38190
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Markdown, { text: entry.text, theme, inline: true })
|
|
38191
|
+
] }),
|
|
38192
|
+
entry.streaming ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: colorize2("\u258C", "prompt", theme) }) : null
|
|
38193
|
+
] });
|
|
38194
|
+
}
|
|
38195
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
38196
|
+
thinking && entry.reasoning ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Thinking, { reasoning: entry.reasoning, theme }) : null,
|
|
38197
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
|
|
38198
|
+
prefix,
|
|
38199
|
+
entry.text,
|
|
38200
|
+
entry.streaming ? colorize2("\u258C", "prompt", theme) : ""
|
|
38201
|
+
] })
|
|
37933
38202
|
] });
|
|
37934
38203
|
}
|
|
37935
38204
|
case "tool": {
|
|
37936
38205
|
const statusGlyph = entry.status === "success" ? "\u2713" : "\u2717";
|
|
37937
38206
|
const statusColor = entry.status === "success" ? "success" : "error";
|
|
37938
38207
|
const nameColor = colorize2(entry.toolName ?? "tool", "toolName", theme);
|
|
37939
|
-
return /* @__PURE__ */ (0,
|
|
38208
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
|
|
37940
38209
|
" ",
|
|
37941
38210
|
colorize2(statusGlyph, statusColor, theme),
|
|
37942
38211
|
" ",
|
|
@@ -37950,17 +38219,17 @@ function TranscriptRow({ entry, theme }) {
|
|
|
37950
38219
|
}
|
|
37951
38220
|
|
|
37952
38221
|
// src/components/Prompt.tsx
|
|
37953
|
-
var
|
|
38222
|
+
var import_react40 = __toESM(require_react(), 1);
|
|
37954
38223
|
|
|
37955
|
-
// ../../node_modules/.pnpm/ink-text-input@6.0.0_ink@7.
|
|
37956
|
-
var
|
|
38224
|
+
// ../../node_modules/.pnpm/ink-text-input@6.0.0_ink@7._2a39186227fe1d31183ab83244021d5b/node_modules/ink-text-input/build/index.js
|
|
38225
|
+
var import_react39 = __toESM(require_react(), 1);
|
|
37957
38226
|
function TextInput({ value: originalValue, placeholder = "", focus = true, mask, highlightPastedText = false, showCursor = true, onChange, onSubmit }) {
|
|
37958
|
-
const [state, setState] = (0,
|
|
38227
|
+
const [state, setState] = (0, import_react39.useState)({
|
|
37959
38228
|
cursorOffset: (originalValue || "").length,
|
|
37960
38229
|
cursorWidth: 0
|
|
37961
38230
|
});
|
|
37962
38231
|
const { cursorOffset, cursorWidth } = state;
|
|
37963
|
-
(0,
|
|
38232
|
+
(0, import_react39.useEffect)(() => {
|
|
37964
38233
|
setState((previousState) => {
|
|
37965
38234
|
if (!focus || !showCursor) {
|
|
37966
38235
|
return previousState;
|
|
@@ -38038,12 +38307,12 @@ function TextInput({ value: originalValue, placeholder = "", focus = true, mask,
|
|
|
38038
38307
|
onChange(nextValue);
|
|
38039
38308
|
}
|
|
38040
38309
|
}, { isActive: focus });
|
|
38041
|
-
return
|
|
38310
|
+
return import_react39.default.createElement(Text, null, placeholder ? value.length > 0 ? renderedValue : renderedPlaceholder : renderedValue);
|
|
38042
38311
|
}
|
|
38043
38312
|
var build_default = TextInput;
|
|
38044
38313
|
|
|
38045
38314
|
// src/components/Prompt.tsx
|
|
38046
|
-
var
|
|
38315
|
+
var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
|
|
38047
38316
|
function Prompt({
|
|
38048
38317
|
theme = THEMES.default,
|
|
38049
38318
|
history,
|
|
@@ -38051,8 +38320,8 @@ function Prompt({
|
|
|
38051
38320
|
placeholder = "\u203A message (\\ to continue, empty \\ to cancel)",
|
|
38052
38321
|
disabled = false
|
|
38053
38322
|
}) {
|
|
38054
|
-
const [cont, setCont] = (0,
|
|
38055
|
-
const [value, setValue] = (0,
|
|
38323
|
+
const [cont, setCont] = (0, import_react40.useState)(null);
|
|
38324
|
+
const [value, setValue] = (0, import_react40.useState)("");
|
|
38056
38325
|
const handleSubmit = (line) => {
|
|
38057
38326
|
if (line.endsWith("\\\\")) {
|
|
38058
38327
|
const unescaped = line.slice(0, -1) + "\\\\";
|
|
@@ -38080,12 +38349,12 @@ ${line}` : line;
|
|
|
38080
38349
|
setValue("");
|
|
38081
38350
|
};
|
|
38082
38351
|
if (disabled) {
|
|
38083
|
-
return /* @__PURE__ */ (0,
|
|
38352
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: theme.divider, children: "(turn in flight, Ctrl+C to abort)" }) });
|
|
38084
38353
|
}
|
|
38085
38354
|
const prefix = cont ? colorize2(`... (${cont.lineNo + 1}) > `, "prompt", theme) : colorize2("\u203A ", "prompt", theme);
|
|
38086
|
-
return /* @__PURE__ */ (0,
|
|
38087
|
-
/* @__PURE__ */ (0,
|
|
38088
|
-
/* @__PURE__ */ (0,
|
|
38355
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { children: [
|
|
38356
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: prefix }),
|
|
38357
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
38089
38358
|
build_default,
|
|
38090
38359
|
{
|
|
38091
38360
|
value,
|
|
@@ -38099,16 +38368,16 @@ ${line}` : line;
|
|
|
38099
38368
|
}
|
|
38100
38369
|
|
|
38101
38370
|
// src/components/Confirm.tsx
|
|
38102
|
-
var
|
|
38371
|
+
var import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
|
|
38103
38372
|
function Confirm({ theme = THEMES.default, controller }) {
|
|
38104
38373
|
const ui = useStore($uiState);
|
|
38105
38374
|
if (!ui.pendingConfirm) return null;
|
|
38106
|
-
return /* @__PURE__ */ (0,
|
|
38107
|
-
/* @__PURE__ */ (0,
|
|
38375
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
38376
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { children: [
|
|
38108
38377
|
colorize2(" ? ", "prompt", theme),
|
|
38109
38378
|
colorize2(ui.pendingConfirm.prompt, "prompt", theme)
|
|
38110
38379
|
] }),
|
|
38111
|
-
/* @__PURE__ */ (0,
|
|
38380
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: theme.divider, children: [
|
|
38112
38381
|
" ",
|
|
38113
38382
|
"y/N: ",
|
|
38114
38383
|
controller.hasPending() ? "(waiting for input)" : ""
|
|
@@ -38117,41 +38386,21 @@ function Confirm({ theme = THEMES.default, controller }) {
|
|
|
38117
38386
|
}
|
|
38118
38387
|
|
|
38119
38388
|
// src/hooks/useHistory.ts
|
|
38120
|
-
var
|
|
38389
|
+
var import_react42 = __toESM(require_react(), 1);
|
|
38121
38390
|
|
|
38122
38391
|
// src/history/index.ts
|
|
38123
|
-
import {
|
|
38124
|
-
|
|
38125
|
-
|
|
38126
|
-
|
|
38127
|
-
|
|
38128
|
-
|
|
38129
|
-
}
|
|
38130
|
-
function tuiHistoryLoad() {
|
|
38131
|
-
const p = tuiHistoryPath();
|
|
38132
|
-
if (!existsSync2(p)) return [];
|
|
38133
|
-
try {
|
|
38134
|
-
const raw = readFileSync2(p, "utf8");
|
|
38135
|
-
const lines = raw.split(/\r?\n/).filter((l) => l.length > 0);
|
|
38136
|
-
return lines;
|
|
38137
|
-
} catch {
|
|
38138
|
-
return [];
|
|
38139
|
-
}
|
|
38140
|
-
}
|
|
38141
|
-
function tuiHistoryAppend(line) {
|
|
38142
|
-
if (!line || !line.trim()) return;
|
|
38143
|
-
const p = tuiHistoryPath();
|
|
38144
|
-
try {
|
|
38145
|
-
mkdirSync(dirname(p), { recursive: true });
|
|
38146
|
-
appendFileSync(p, line + "\n");
|
|
38147
|
-
} catch {
|
|
38148
|
-
}
|
|
38149
|
-
}
|
|
38392
|
+
import {
|
|
38393
|
+
tuiHistoryPath,
|
|
38394
|
+
tuiHistoryLoad,
|
|
38395
|
+
tuiHistoryAppend,
|
|
38396
|
+
tuiHistoryTruncate,
|
|
38397
|
+
TUI_HISTORY_MAX
|
|
38398
|
+
} from "@deepwhale/coding-agent";
|
|
38150
38399
|
|
|
38151
38400
|
// src/hooks/useHistory.ts
|
|
38152
38401
|
function useHistory() {
|
|
38153
|
-
const [history, setHistory] = (0,
|
|
38154
|
-
const append = (0,
|
|
38402
|
+
const [history, setHistory] = (0, import_react42.useState)(() => tuiHistoryLoad());
|
|
38403
|
+
const append = (0, import_react42.useCallback)((line) => {
|
|
38155
38404
|
if (!line || !line.trim()) return;
|
|
38156
38405
|
tuiHistoryAppend(line);
|
|
38157
38406
|
setHistory((prev) => {
|
|
@@ -38164,15 +38413,15 @@ function useHistory() {
|
|
|
38164
38413
|
}
|
|
38165
38414
|
|
|
38166
38415
|
// src/hooks/useAbortController.ts
|
|
38167
|
-
var
|
|
38416
|
+
var import_react43 = __toESM(require_react(), 1);
|
|
38168
38417
|
function useAbortController(onSigint) {
|
|
38169
|
-
const ref = (0,
|
|
38170
|
-
const abort = (0,
|
|
38418
|
+
const ref = (0, import_react43.useRef)(new AbortController());
|
|
38419
|
+
const abort = (0, import_react43.useCallback)(() => {
|
|
38171
38420
|
if (!ref.current.signal.aborted) {
|
|
38172
38421
|
ref.current.abort();
|
|
38173
38422
|
}
|
|
38174
38423
|
}, []);
|
|
38175
|
-
const reset = (0,
|
|
38424
|
+
const reset = (0, import_react43.useCallback)(() => {
|
|
38176
38425
|
if (!ref.current.signal.aborted) {
|
|
38177
38426
|
console.warn("[tui-ink] useAbortController.reset called without prior abort()");
|
|
38178
38427
|
}
|
|
@@ -38184,7 +38433,7 @@ function useAbortController(onSigint) {
|
|
|
38184
38433
|
onSigint();
|
|
38185
38434
|
}
|
|
38186
38435
|
});
|
|
38187
|
-
(0,
|
|
38436
|
+
(0, import_react43.useEffect)(() => {
|
|
38188
38437
|
const handler = () => {
|
|
38189
38438
|
abort();
|
|
38190
38439
|
};
|
|
@@ -38197,8 +38446,12 @@ function useAbortController(onSigint) {
|
|
|
38197
38446
|
}
|
|
38198
38447
|
|
|
38199
38448
|
// src/hooks/useRunToolLoop.ts
|
|
38200
|
-
var
|
|
38201
|
-
import {
|
|
38449
|
+
var import_react44 = __toESM(require_react(), 1);
|
|
38450
|
+
import {
|
|
38451
|
+
runToolLoop,
|
|
38452
|
+
persistToolLoopSteps,
|
|
38453
|
+
staticToolPolicy
|
|
38454
|
+
} from "@deepwhale/coding-agent";
|
|
38202
38455
|
|
|
38203
38456
|
// src/highlight/chunk.ts
|
|
38204
38457
|
import { stdout } from "node:process";
|
|
@@ -38240,10 +38493,10 @@ function collectRanges(text, re, role, out) {
|
|
|
38240
38493
|
|
|
38241
38494
|
// src/hooks/useRunToolLoop.ts
|
|
38242
38495
|
function useRunToolLoop(args) {
|
|
38243
|
-
const runTurn = (0,
|
|
38496
|
+
const runTurn = (0, import_react44.useCallback)(
|
|
38244
38497
|
async (userPrompt) => {
|
|
38245
|
-
const { options, theme, signal, writer, workingMessages } = args;
|
|
38246
|
-
const modelName = options.model ?? "model";
|
|
38498
|
+
const { options, theme, signal, writer, client, registry, workingMessages } = args;
|
|
38499
|
+
const modelName = options.model ?? client.model ?? "model";
|
|
38247
38500
|
pushEntry({ kind: "user", text: userPrompt });
|
|
38248
38501
|
$uiState.setKey("mode", "streaming");
|
|
38249
38502
|
$uiState.setKey("model", modelName);
|
|
@@ -38254,12 +38507,16 @@ function useRunToolLoop(args) {
|
|
|
38254
38507
|
{ role: "user", content: userPrompt }
|
|
38255
38508
|
];
|
|
38256
38509
|
try {
|
|
38257
|
-
const result = await runToolLoop(turnMessages, {
|
|
38510
|
+
const result = await runToolLoop(client, turnMessages, {
|
|
38511
|
+
registry,
|
|
38258
38512
|
onChunk: (chunk) => {
|
|
38259
38513
|
if (chunk.content) {
|
|
38260
38514
|
const colored = highlightChunk(chunk.content, theme, true);
|
|
38261
38515
|
appendToLastAssistant(colored);
|
|
38262
38516
|
}
|
|
38517
|
+
if (chunk.reasoning_content) {
|
|
38518
|
+
appendReasoningChunk(chunk.reasoning_content);
|
|
38519
|
+
}
|
|
38263
38520
|
},
|
|
38264
38521
|
maxSteps: options.maxSteps ?? 5,
|
|
38265
38522
|
policy: resolvedPolicy,
|
|
@@ -38309,19 +38566,248 @@ function useRunToolLoop(args) {
|
|
|
38309
38566
|
return { runTurn };
|
|
38310
38567
|
}
|
|
38311
38568
|
|
|
38569
|
+
// src/hooks/useSubmission.ts
|
|
38570
|
+
var import_react45 = __toESM(require_react(), 1);
|
|
38571
|
+
|
|
38572
|
+
// src/commands/core.ts
|
|
38573
|
+
var HELP_LINES = [
|
|
38574
|
+
["/help", "list 9 commands"],
|
|
38575
|
+
["/exit (q/quit)", "exit TUI"],
|
|
38576
|
+
["/clear", "clear transcript (no session close)"],
|
|
38577
|
+
["/verify", "run verify (build/lint/typecheck/test)"],
|
|
38578
|
+
["/status", "show model + session path + usage"],
|
|
38579
|
+
["/model <name>", "switch model"],
|
|
38580
|
+
["/resume", "list session paths (D-28 picker)"],
|
|
38581
|
+
["/personality <name>", "switch system prompt personality"],
|
|
38582
|
+
["/heapdump (mem)", "V8 heap snapshot + memory diagnostics"]
|
|
38583
|
+
];
|
|
38584
|
+
var coreCommands = [
|
|
38585
|
+
{
|
|
38586
|
+
name: "help",
|
|
38587
|
+
help: "list 9 commands + hotkeys",
|
|
38588
|
+
category: "core",
|
|
38589
|
+
run: (_arg, ctx) => {
|
|
38590
|
+
const lines = HELP_LINES.map(([cmd, desc]) => ` ${cmd.padEnd(24)} ${desc}`);
|
|
38591
|
+
const helpText = [
|
|
38592
|
+
" /help \u2014 9 commands",
|
|
38593
|
+
" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
38594
|
+
...lines,
|
|
38595
|
+
" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
38596
|
+
" (slash registry \u4E2D\u592E\u5316, \u8DDF Hermes ui-tui 1:1)"
|
|
38597
|
+
].join("\n");
|
|
38598
|
+
ctx.pushEntry({ kind: "assistant", text: `
|
|
38599
|
+
${helpText}
|
|
38600
|
+
` });
|
|
38601
|
+
}
|
|
38602
|
+
},
|
|
38603
|
+
{
|
|
38604
|
+
name: "exit",
|
|
38605
|
+
aliases: ["q", "quit"],
|
|
38606
|
+
help: "exit TUI (writer.close \u8D70 D-19.5 finish \u8DEF\u5F84)",
|
|
38607
|
+
category: "core",
|
|
38608
|
+
run: (_arg, ctx) => {
|
|
38609
|
+
ctx.exit({ exitCode: 0, reason: "user-exit" });
|
|
38610
|
+
}
|
|
38611
|
+
},
|
|
38612
|
+
{
|
|
38613
|
+
name: "clear",
|
|
38614
|
+
help: "clear transcript (0 \u5173 session, 0 \u5199 session event)",
|
|
38615
|
+
category: "core",
|
|
38616
|
+
run: (_arg, ctx) => {
|
|
38617
|
+
ctx.clearTranscript();
|
|
38618
|
+
ctx.pushEntry({ kind: "assistant", text: "\n transcript cleared\n" });
|
|
38619
|
+
}
|
|
38620
|
+
},
|
|
38621
|
+
{
|
|
38622
|
+
name: "verify",
|
|
38623
|
+
help: "run verify (build/lint/typecheck/test)",
|
|
38624
|
+
category: "core",
|
|
38625
|
+
run: async (_arg, ctx) => {
|
|
38626
|
+
const { runVerify } = await import("@deepwhale/coding-agent");
|
|
38627
|
+
ctx.pushEntry({ kind: "assistant", text: "\n /verify running...\n" });
|
|
38628
|
+
try {
|
|
38629
|
+
const report = await runVerify();
|
|
38630
|
+
const status = report.overallStatus;
|
|
38631
|
+
const summary = `
|
|
38632
|
+
/verify done: ${status} (${report.checks.length} checks)
|
|
38633
|
+
`;
|
|
38634
|
+
ctx.pushEntry({ kind: "assistant", text: summary });
|
|
38635
|
+
} catch (e) {
|
|
38636
|
+
const err = e instanceof Error ? e.message : String(e);
|
|
38637
|
+
ctx.pushEntry({ kind: "assistant", text: `
|
|
38638
|
+
/verify error: ${err}
|
|
38639
|
+
` });
|
|
38640
|
+
}
|
|
38641
|
+
}
|
|
38642
|
+
},
|
|
38643
|
+
{
|
|
38644
|
+
name: "status",
|
|
38645
|
+
help: "show model + session path + usage",
|
|
38646
|
+
category: "core",
|
|
38647
|
+
run: (_arg, ctx) => {
|
|
38648
|
+
const usage = ctx.ui.usage;
|
|
38649
|
+
const usageStr = usage ? `${usage.prompt_tokens ?? 0} prompt / ${usage.completion_tokens ?? 0} completion / ${usage.total_tokens ?? 0} total` : "(no usage yet)";
|
|
38650
|
+
const statusText = [
|
|
38651
|
+
" /status",
|
|
38652
|
+
" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
38653
|
+
` model: ${ctx.model}`,
|
|
38654
|
+
` mode: ${ctx.ui.mode}`,
|
|
38655
|
+
` session: ${ctx.sessionPath ?? "(no session file)"}`,
|
|
38656
|
+
` usage: ${usageStr}`,
|
|
38657
|
+
` transcript: ${ctx.transcript.length} entries`,
|
|
38658
|
+
" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
|
|
38659
|
+
].join("\n");
|
|
38660
|
+
ctx.pushEntry({ kind: "assistant", text: `
|
|
38661
|
+
${statusText}
|
|
38662
|
+
` });
|
|
38663
|
+
}
|
|
38664
|
+
}
|
|
38665
|
+
];
|
|
38666
|
+
|
|
38667
|
+
// src/commands/session.ts
|
|
38668
|
+
var sessionCommands = [
|
|
38669
|
+
{
|
|
38670
|
+
name: "model",
|
|
38671
|
+
help: "switch model (e.g. /model deepseek-v4-flash)",
|
|
38672
|
+
category: "session",
|
|
38673
|
+
run: (arg, ctx) => {
|
|
38674
|
+
const model = arg.trim();
|
|
38675
|
+
if (!model) {
|
|
38676
|
+
ctx.pushEntry({ kind: "assistant", text: "\n /model <name> requires a model name (e.g. /model deepseek-v4-flash)\n" });
|
|
38677
|
+
return;
|
|
38678
|
+
}
|
|
38679
|
+
const provider = model.startsWith("claude") ? "anthropic" : "deepseek";
|
|
38680
|
+
ctx.setModel(model, provider);
|
|
38681
|
+
ctx.pushEntry({ kind: "assistant", text: `
|
|
38682
|
+
/model set to ${model} (provider: ${provider})
|
|
38683
|
+
(note: D-26 \u62CD, \u5B9E\u9645 LLMClient \u91CD build \u7559 D-28+)
|
|
38684
|
+
` });
|
|
38685
|
+
}
|
|
38686
|
+
},
|
|
38687
|
+
{
|
|
38688
|
+
name: "resume",
|
|
38689
|
+
help: "list session paths (D-28 picker \u5347\u7EA7)",
|
|
38690
|
+
category: "session",
|
|
38691
|
+
run: (_arg, ctx) => {
|
|
38692
|
+
ctx.pushEntry({
|
|
38693
|
+
kind: "assistant",
|
|
38694
|
+
text: "\n /resume: D-28 picker \u5347\u7EA7 (\u8DDF Hermes sessionPicker 1:1)\n \u6682\u4E0D\u652F\u6301\u591A session \u5207\u6362, \u8DDF tui.ts \u5355 session 1:1\n"
|
|
38695
|
+
});
|
|
38696
|
+
}
|
|
38697
|
+
},
|
|
38698
|
+
{
|
|
38699
|
+
name: "personality",
|
|
38700
|
+
help: "switch system prompt personality (D-27 markdown \u6E32\u67D3\u63A5)",
|
|
38701
|
+
category: "session",
|
|
38702
|
+
run: (_arg, ctx) => {
|
|
38703
|
+
const name = _arg.trim();
|
|
38704
|
+
if (!name) {
|
|
38705
|
+
ctx.pushEntry({ kind: "assistant", text: "\n /personality <name> requires a name (D-27 \u5347\u7EA7)\n" });
|
|
38706
|
+
return;
|
|
38707
|
+
}
|
|
38708
|
+
ctx.pushEntry({
|
|
38709
|
+
kind: "assistant",
|
|
38710
|
+
text: `
|
|
38711
|
+
/personality set to ${name} (D-26 \u62CD placeholder, D-27 \u5347\u7EA7\u63A5)
|
|
38712
|
+
`
|
|
38713
|
+
});
|
|
38714
|
+
}
|
|
38715
|
+
}
|
|
38716
|
+
];
|
|
38717
|
+
|
|
38718
|
+
// src/commands/debug.ts
|
|
38719
|
+
function formatBytes(bytes) {
|
|
38720
|
+
const mb = bytes / 1024 / 1024;
|
|
38721
|
+
return mb < 1 ? `${(bytes / 1024).toFixed(1)}KB` : `${mb.toFixed(1)}MB`;
|
|
38722
|
+
}
|
|
38723
|
+
var debugCommands = [
|
|
38724
|
+
{
|
|
38725
|
+
name: "heapdump",
|
|
38726
|
+
aliases: ["mem"],
|
|
38727
|
+
help: "V8 heap snapshot + memory diagnostics (D-27 \u5347\u7EA7 full memory.ts)",
|
|
38728
|
+
category: "debug",
|
|
38729
|
+
run: (_arg, ctx) => {
|
|
38730
|
+
const mu = process.memoryUsage();
|
|
38731
|
+
const text = [
|
|
38732
|
+
" /heapdump \u2014 process.memoryUsage()",
|
|
38733
|
+
" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
38734
|
+
` rss: ${formatBytes(mu.rss)}`,
|
|
38735
|
+
` heapTotal: ${formatBytes(mu.heapTotal)}`,
|
|
38736
|
+
` heapUsed: ${formatBytes(mu.heapUsed)}`,
|
|
38737
|
+
` external: ${formatBytes(mu.external)}`,
|
|
38738
|
+
` arrayBuffers: ${formatBytes(mu.arrayBuffers)}`,
|
|
38739
|
+
" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
38740
|
+
" (D-27 \u5347\u7EA7: \u5199 v8.writeHeapSnapshot, D-29 \u5347\u7EA7: auto OOM \u9632\u62A4)"
|
|
38741
|
+
].join("\n");
|
|
38742
|
+
ctx.pushEntry({ kind: "assistant", text: `
|
|
38743
|
+
${text}
|
|
38744
|
+
` });
|
|
38745
|
+
}
|
|
38746
|
+
}
|
|
38747
|
+
];
|
|
38748
|
+
|
|
38749
|
+
// src/commands/registry.ts
|
|
38750
|
+
var SLASH_COMMANDS = [
|
|
38751
|
+
...coreCommands,
|
|
38752
|
+
...sessionCommands,
|
|
38753
|
+
...debugCommands
|
|
38754
|
+
];
|
|
38755
|
+
var byName = new Map(
|
|
38756
|
+
SLASH_COMMANDS.flatMap(
|
|
38757
|
+
(cmd) => [cmd.name, ...cmd.aliases ?? []].map((name) => [name.toLowerCase(), cmd])
|
|
38758
|
+
)
|
|
38759
|
+
);
|
|
38760
|
+
var findSlashCommand = (name) => byName.get(name.toLowerCase());
|
|
38761
|
+
var isSlashCommand = (input) => input.startsWith("/");
|
|
38762
|
+
|
|
38763
|
+
// src/hooks/useSubmission.ts
|
|
38764
|
+
function useSubmission(options) {
|
|
38765
|
+
const { slashContext, onChat } = options;
|
|
38766
|
+
const submit = (0, import_react45.useCallback)(
|
|
38767
|
+
(text) => {
|
|
38768
|
+
const trimmed = text.trim();
|
|
38769
|
+
if (!trimmed) return "empty";
|
|
38770
|
+
if (isSlashCommand(trimmed)) {
|
|
38771
|
+
const spaceIdx = trimmed.indexOf(" ");
|
|
38772
|
+
const cmdName = spaceIdx === -1 ? trimmed.slice(1) : trimmed.slice(1, spaceIdx);
|
|
38773
|
+
const arg = spaceIdx === -1 ? "" : trimmed.slice(spaceIdx + 1).trim();
|
|
38774
|
+
const cmd = findSlashCommand(cmdName);
|
|
38775
|
+
if (cmd) {
|
|
38776
|
+
cmd.run(arg, slashContext);
|
|
38777
|
+
return "slash";
|
|
38778
|
+
}
|
|
38779
|
+
slashContext.pushEntry({
|
|
38780
|
+
kind: "assistant",
|
|
38781
|
+
text: `
|
|
38782
|
+
unknown command: /${cmdName}
|
|
38783
|
+
(run /help for the 9 commands list)
|
|
38784
|
+
`
|
|
38785
|
+
});
|
|
38786
|
+
return "slash";
|
|
38787
|
+
}
|
|
38788
|
+
void onChat(trimmed);
|
|
38789
|
+
return "chat";
|
|
38790
|
+
},
|
|
38791
|
+
[slashContext, onChat]
|
|
38792
|
+
);
|
|
38793
|
+
return { submit };
|
|
38794
|
+
}
|
|
38795
|
+
|
|
38312
38796
|
// src/app.tsx
|
|
38313
|
-
var
|
|
38797
|
+
var import_jsx_runtime9 = __toESM(require_jsx_runtime(), 1);
|
|
38314
38798
|
import {
|
|
38315
38799
|
createReplConfirm,
|
|
38316
38800
|
staticToolPolicy as staticToolPolicy2,
|
|
38317
38801
|
SessionReader,
|
|
38318
38802
|
SessionWriter,
|
|
38319
|
-
loadSession
|
|
38803
|
+
loadSession,
|
|
38804
|
+
createDefaultClient,
|
|
38805
|
+
createDefaultRegistry
|
|
38320
38806
|
} from "@deepwhale/coding-agent";
|
|
38321
38807
|
import { stdout as stdout2 } from "node:process";
|
|
38322
38808
|
function App2({ options, onExit }) {
|
|
38323
38809
|
const { exit } = use_app_default();
|
|
38324
|
-
const theme = (0,
|
|
38810
|
+
const theme = (0, import_react46.useMemo)(
|
|
38325
38811
|
() => THEMES[resolveTuiTheme(options.theme)],
|
|
38326
38812
|
[options.theme]
|
|
38327
38813
|
);
|
|
@@ -38329,16 +38815,16 @@ function App2({ options, onExit }) {
|
|
|
38329
38815
|
const { history, append: appendHistory } = useHistory();
|
|
38330
38816
|
const { controller: turnAbortController } = useAbortController(() => {
|
|
38331
38817
|
});
|
|
38332
|
-
const [workingMessages, setWorkingMessages] = (0,
|
|
38818
|
+
const [workingMessages, setWorkingMessages] = (0, import_react46.useState)([]);
|
|
38333
38819
|
const sessionPath = options.sessionPath;
|
|
38334
|
-
const writerRef = (0,
|
|
38335
|
-
const readerRef = (0,
|
|
38820
|
+
const writerRef = (0, import_react46.useRef)(null);
|
|
38821
|
+
const readerRef = (0, import_react46.useRef)(null);
|
|
38336
38822
|
if (writerRef.current === null && sessionPath) {
|
|
38337
38823
|
writerRef.current = new SessionWriter(sessionPath);
|
|
38338
38824
|
readerRef.current = new SessionReader(sessionPath);
|
|
38339
38825
|
}
|
|
38340
|
-
const [sessionLoaded, setSessionLoaded] = (0,
|
|
38341
|
-
(0,
|
|
38826
|
+
const [sessionLoaded, setSessionLoaded] = (0, import_react46.useState)(false);
|
|
38827
|
+
(0, import_react46.useEffect)(() => {
|
|
38342
38828
|
if (sessionLoaded) return;
|
|
38343
38829
|
const writer = writerRef.current;
|
|
38344
38830
|
const reader = readerRef.current;
|
|
@@ -38365,21 +38851,40 @@ function App2({ options, onExit }) {
|
|
|
38365
38851
|
setSessionLoaded(true);
|
|
38366
38852
|
}
|
|
38367
38853
|
}, [sessionLoaded]);
|
|
38368
|
-
const confirmControllerRef = (0,
|
|
38854
|
+
const confirmControllerRef = (0, import_react46.useRef)(null);
|
|
38369
38855
|
if (confirmControllerRef.current === null) {
|
|
38370
38856
|
confirmControllerRef.current = createReplConfirm({ output: stdout2 });
|
|
38371
38857
|
}
|
|
38372
38858
|
const confirmController = confirmControllerRef.current;
|
|
38373
|
-
const [turnInFlight, setTurnInFlight] = (0,
|
|
38859
|
+
const [turnInFlight, setTurnInFlight] = (0, import_react46.useState)(false);
|
|
38860
|
+
const clientRef = (0, import_react46.useRef)(null);
|
|
38861
|
+
if (clientRef.current === null) {
|
|
38862
|
+
const providerNarrow = options.provider === "deepseek" || options.provider === "anthropic" ? options.provider : void 0;
|
|
38863
|
+
clientRef.current = createDefaultClient({
|
|
38864
|
+
...providerNarrow ? { provider: providerNarrow } : {},
|
|
38865
|
+
...options.model ? { model: options.model } : {}
|
|
38866
|
+
});
|
|
38867
|
+
}
|
|
38868
|
+
const client = clientRef.current;
|
|
38869
|
+
const registryRef = (0, import_react46.useRef)(null);
|
|
38870
|
+
if (registryRef.current === null) {
|
|
38871
|
+
registryRef.current = createDefaultRegistry();
|
|
38872
|
+
}
|
|
38873
|
+
const registry = registryRef.current;
|
|
38874
|
+
const [modelName, setModelName] = (0, import_react46.useState)(
|
|
38875
|
+
options.model ?? client.model ?? "model"
|
|
38876
|
+
);
|
|
38374
38877
|
const { runTurn } = useRunToolLoop({
|
|
38375
38878
|
options,
|
|
38376
38879
|
theme,
|
|
38377
38880
|
signal: turnAbortController.signal,
|
|
38378
38881
|
writer: writerRef.current,
|
|
38882
|
+
client,
|
|
38883
|
+
registry,
|
|
38379
38884
|
policy: staticToolPolicy2,
|
|
38380
38885
|
workingMessages
|
|
38381
38886
|
});
|
|
38382
|
-
(0,
|
|
38887
|
+
(0, import_react46.useEffect)(() => {
|
|
38383
38888
|
if (ui.mode === "idle" && turnInFlight) {
|
|
38384
38889
|
setTurnInFlight(false);
|
|
38385
38890
|
const entries = $transcript.get();
|
|
@@ -38395,38 +38900,53 @@ function App2({ options, onExit }) {
|
|
|
38395
38900
|
}
|
|
38396
38901
|
}
|
|
38397
38902
|
}, [ui.mode, turnInFlight]);
|
|
38398
|
-
const
|
|
38399
|
-
|
|
38400
|
-
|
|
38401
|
-
|
|
38903
|
+
const slashContext = (0, import_react46.useMemo)(() => ({
|
|
38904
|
+
theme,
|
|
38905
|
+
ui: $uiState.get(),
|
|
38906
|
+
// snapshot (每次 submit 拿最新, 见 D-29+ 优化)
|
|
38907
|
+
transcript: $transcript.get(),
|
|
38908
|
+
model: modelName,
|
|
38909
|
+
sessionPath,
|
|
38910
|
+
pushEntry,
|
|
38911
|
+
clearTranscript: () => {
|
|
38912
|
+
$transcript.set([]);
|
|
38913
|
+
},
|
|
38914
|
+
setModel: (model) => {
|
|
38915
|
+
setModelName(model);
|
|
38916
|
+
},
|
|
38917
|
+
exit: (result) => {
|
|
38402
38918
|
void writerRef.current?.close();
|
|
38403
|
-
onExit({ exitCode: 0, reason: "user-exit" });
|
|
38919
|
+
onExit(result ?? { exitCode: 0, reason: "user-exit" });
|
|
38404
38920
|
exit();
|
|
38405
|
-
return;
|
|
38406
38921
|
}
|
|
38407
|
-
|
|
38408
|
-
|
|
38409
|
-
|
|
38922
|
+
}), [theme, modelName, sessionPath, onExit, exit]);
|
|
38923
|
+
const { submit } = useSubmission({
|
|
38924
|
+
slashContext,
|
|
38925
|
+
onChat: (prompt) => {
|
|
38926
|
+
if (confirmController.hasPending()) {
|
|
38927
|
+
confirmController.offerLine(prompt);
|
|
38928
|
+
return;
|
|
38929
|
+
}
|
|
38930
|
+
if (turnInFlight) return;
|
|
38931
|
+
appendHistory(prompt);
|
|
38932
|
+
setTurnInFlight(true);
|
|
38933
|
+
void (async () => {
|
|
38934
|
+
await runTurn(prompt);
|
|
38935
|
+
})();
|
|
38410
38936
|
}
|
|
38411
|
-
|
|
38412
|
-
|
|
38413
|
-
|
|
38414
|
-
|
|
38415
|
-
|
|
38416
|
-
|
|
38417
|
-
|
|
38418
|
-
|
|
38419
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { color: theme.header, children: "\u232C deepwhale tui-ink v1.0.9" }),
|
|
38420
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Divider, { theme }),
|
|
38421
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatusBar, { theme }),
|
|
38422
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Transcript, { theme }),
|
|
38423
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Confirm, { theme, controller: confirmController }),
|
|
38424
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
38937
|
+
});
|
|
38938
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, children: [
|
|
38939
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.header, children: "\u232C deepwhale tui-ink v1.0.11" }),
|
|
38940
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Divider, { theme }),
|
|
38941
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StatusBar, { theme }),
|
|
38942
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Transcript, { theme }),
|
|
38943
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Confirm, { theme, controller: confirmController }),
|
|
38944
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
38425
38945
|
Prompt,
|
|
38426
38946
|
{
|
|
38427
38947
|
theme,
|
|
38428
38948
|
history,
|
|
38429
|
-
onSubmit:
|
|
38949
|
+
onSubmit: submit,
|
|
38430
38950
|
disabled: turnInFlight
|
|
38431
38951
|
}
|
|
38432
38952
|
)
|
|
@@ -38434,14 +38954,14 @@ function App2({ options, onExit }) {
|
|
|
38434
38954
|
}
|
|
38435
38955
|
|
|
38436
38956
|
// src/index.tsx
|
|
38437
|
-
var
|
|
38957
|
+
var import_jsx_runtime10 = __toESM(require_jsx_runtime(), 1);
|
|
38438
38958
|
async function runTuiInkMode(options = {}) {
|
|
38439
38959
|
if (!process.stdout.isTTY) {
|
|
38440
38960
|
return { exitCode: 0, reason: "not-tty" };
|
|
38441
38961
|
}
|
|
38442
38962
|
return new Promise((resolve) => {
|
|
38443
38963
|
const { waitUntilExit, unmount } = render_default(
|
|
38444
|
-
/* @__PURE__ */ (0,
|
|
38964
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
38445
38965
|
App2,
|
|
38446
38966
|
{
|
|
38447
38967
|
options,
|