kiku-agent 1.0.11 → 1.2.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/README.md +300 -495
- package/package.json +12 -11
- package/public/fonts/GoogleSans-Bold.ttf +0 -0
- package/public/fonts/GoogleSans-Bold.woff2 +0 -0
- package/public/fonts/GoogleSans-BoldItalic.ttf +0 -0
- package/public/fonts/GoogleSans-Italic.ttf +0 -0
- package/public/fonts/GoogleSans-Latin-400.woff2 +0 -0
- package/public/fonts/GoogleSans-Latin-500.woff2 +0 -0
- package/public/fonts/GoogleSans-Latin-600.woff2 +0 -0
- package/public/fonts/GoogleSans-Latin-700.woff2 +0 -0
- package/public/fonts/GoogleSans-Medium.ttf +0 -0
- package/public/fonts/GoogleSans-Medium.woff2 +0 -0
- package/public/fonts/GoogleSans-Regular.ttf +0 -0
- package/public/fonts/GoogleSans-Regular.woff2 +0 -0
- package/public/fonts/GoogleSans-Thai-400.woff2 +0 -0
- package/public/fonts/GoogleSans-Thai-500.woff2 +0 -0
- package/public/fonts/GoogleSans-Thai-600.woff2 +0 -0
- package/public/fonts/GoogleSans-Thai-700.woff2 +0 -0
- package/public/fonts/NotoSansThai-Bold.woff2 +0 -0
- package/public/fonts/NotoSansThai-Regular.woff2 +0 -0
- package/public/fonts/google-sans-official.css +900 -0
- package/public/images/0040jbadgy1id6am4yxqfj61s82dn1kx02.jpg +0 -0
- package/public/images/0040jbadgy1id6am708pbj62c0340qv602.jpg +0 -0
- package/public/images/0040jbadgy1id6amb81uqj62c0340x6q02.jpg +0 -0
- package/public/images/0040jbadgy1id6amcqte3j62c0340qv602.jpg +0 -0
- package/public/images/0040jbadgy1id6amdg3xcj62b232wqv502.jpg +0 -0
- package/public/images/0040jbadgy1id6amexv23j620v2pau0x02.jpg +0 -0
- package/public/images/0040jbadly8icq3if7twwj60qy0qy0uc02.jpg +0 -0
- package/public/images/008ET7Legy1ig9s89nri5j30i20n1gn4.jpg +0 -0
- package/public/images/008ET7Legy1ig9s8a2lmlj30i20ny409.jpg +0 -0
- package/public/images/008ET7Legy1ig9s8ay1hsj30i20nk3zv.jpg +0 -0
- package/public/images/008ET7Legy1ig9s8bab6sj30i20o7go1.jpg +0 -0
- package/public/images/008ET7Legy1ig9s8blqsxj30i20oiq4r.jpg +0 -0
- package/public/images/008ET7Legy1ig9s8cbxkzj30i20mxmzh.jpg +0 -0
- package/public/images/douyin-update/thumbs//346/212/226/351/237/2632026820-399915.jpg +0 -0
- package/public/images/douyin-update/thumbs//346/212/226/351/237/2632026820-424041.jpg +0 -0
- package/public/images/douyin-update/thumbs//346/212/226/351/237/2632026820-588166.jpg +0 -0
- package/public/images/douyin-update/thumbs//346/212/226/351/237/2632026820-672198.jpg +0 -0
- package/public/images/douyin-update/thumbs//346/212/226/351/237/2632026820-700522.jpg +0 -0
- package/public/images/douyin-update/thumbs//346/212/226/351/237/2632026820-839722.jpg +0 -0
- package/public/images/douyin-update/thumbs//346/212/226/351/237/2632026825-460586.jpg +0 -0
- package/public/images/douyin-update/thumbs//346/212/226/351/237/263202694-689407.jpg +0 -0
- package/public/images/douyin-update//346/212/226/351/237/2632026820-399915.mp4 +0 -0
- package/public/images/douyin-update//346/212/226/351/237/2632026820-424041.mp4 +0 -0
- package/public/images/douyin-update//346/212/226/351/237/2632026820-588166.mp4 +0 -0
- package/public/images/douyin-update//346/212/226/351/237/2632026820-672198.mp4 +0 -0
- package/public/images/douyin-update//346/212/226/351/237/2632026820-700522.mp4 +0 -0
- package/public/images/douyin-update//346/212/226/351/237/2632026820-839722.mp4 +0 -0
- package/public/images/douyin-update//346/212/226/351/237/2632026825-460586.mp4 +0 -0
- package/public/images/douyin-update//346/212/226/351/237/263202694-689407.mp4 +0 -0
- package/public/images/general/0040jbadgy1id6am4yxqfj61s82dn1kx02.jpg +0 -0
- package/public/images/general/0040jbadgy1id6am708pbj62c0340qv602.jpg +0 -0
- package/public/images/general/0040jbadgy1id6amb81uqj62c0340x6q02.jpg +0 -0
- package/public/images/general/0040jbadgy1id6amcqte3j62c0340qv602.jpg +0 -0
- package/public/images/general/0040jbadgy1id6amdg3xcj62b232wqv502.jpg +0 -0
- package/public/images/general/0040jbadgy1id6amexv23j620v2pau0x02.jpg +0 -0
- package/public/images/general/0040jbadly8icq3if7twwj60qy0qy0uc02.jpg +0 -0
- package/public/images/general/008ET7Legy1ig9s89nri5j30i20n1gn4.jpg +0 -0
- package/public/images/general/008ET7Legy1ig9s8a2lmlj30i20ny409.jpg +0 -0
- package/public/images/general/008ET7Legy1ig9s8ay1hsj30i20nk3zv.jpg +0 -0
- package/public/images/general/008ET7Legy1ig9s8bab6sj30i20o7go1.jpg +0 -0
- package/public/images/general/008ET7Legy1ig9s8blqsxj30i20oiq4r.jpg +0 -0
- package/public/images/general/008ET7Legy1ig9s8cbxkzj30i20mxmzh.jpg +0 -0
- package/public/images/general/jujingyi_portrait.jpg +0 -0
- package/public/images/jujingyi_portrait.jpg +0 -0
- package/public/images/series/a-millenniums-wait/poster.jpg +0 -0
- package/public/images/series/beauty-of-resilience/poster.jpg +0 -0
- package/public/images/series/detective-samoyeds/poster.jpg +0 -0
- package/public/images/series/everyday/poster.jpg +0 -0
- package/public/images/series/fu-rong-ancient-painting/poster.jpg +0 -0
- package/public/images/series/in-a-class-of-her-own/poster.jpg +0 -0
- package/public/images/series/in-blossom/poster.jpg +0 -0
- package/public/images/series/legend-of-yunxi/poster.jpg +0 -0
- package/public/images/series/lets-fight/poster-2.jpg +0 -0
- package/public/images/series/lets-fight/poster.jpg +0 -0
- package/public/images/series/love-emergency/poster.jpg +0 -0
- package/public/images/series/love-under-the-full-moon/poster.jpg +0 -0
- package/public/images/series/money-bastion/poster.jpg +0 -0
- package/public/images/series/mr-swimmer/poster.jpg +0 -0
- package/public/images/series/novoland-castle-in-the-sky/poster.jpg +0 -0
- package/public/images/series/please-give-me-a-pair-of-wings/poster.jpg +0 -0
- package/public/images/series/rebirth-for-you/poster.jpg +0 -0
- package/public/images/series/sword-and-fairy-4/poster.jpg +0 -0
- package/public/images/series/the-blooms-at-ruyi-pavilion/poster.jpg +0 -0
- package/public/images/series/the-eternal-fragrance/poster-2.jpg +0 -0
- package/public/images/series/the-eternal-fragrance/poster.jpg +0 -0
- package/public/images/series/the-fallen-flowers/poster.jpg +0 -0
- package/public/images/series/the-legend-of-white-snake/poster.jpg +0 -0
- package/public/images/series/veil-of-shadows/poster.jpg +0 -0
- package/public/images/series/wanhua-sin/poster-2.jpg +0 -0
- package/public/images/series/wanhua-sin/poster.jpg +0 -0
- package/public/images/weibo-update/41/345/210/206/351/222/237/345/211/215/0040jbadgy1igrkj10yogj62u03s0npe02.jpg +0 -0
- package/public/images/weibo-update/41/345/210/206/351/222/237/345/211/215/0040jbadgy1igrkj2pdvyj61li25jkjl02.jpg +0 -0
- package/public/images/weibo-update/41/345/210/206/351/222/237/345/211/215/0040jbadgy1igrkj71177j62672w9e8302.jpg +0 -0
- package/public/images/weibo-update/41/345/210/206/351/222/237/345/211/215/0040jbadgy1igrkj7twpfj62192197rw02.jpg +0 -0
- package/public/images/weibo-update/41/345/210/206/351/222/237/345/211/215/0040jbadgy1igrkj8jfu8j62c03401kx02.jpg +0 -0
- package/public/images/weibo-update/41/345/210/206/351/222/237/345/211/215/0040jbadgy1igrkj9dhdsj622k2l77wh02.jpg +0 -0
- package/public/images/weibo-update/41/345/210/206/351/222/237/345/211/215/0040jbadgy1igrkja31s4j62bw3407r802.jpg +0 -0
- package/public/images/weibo-update/41/345/210/206/351/222/237/345/211/215/0040jbadgy1igrkjcf331j61402ey1kx02.jpg +0 -0
- package/public/images/weibo-update/41/345/210/206/351/222/237/345/211/215/0040jbadgy1igrkjdx8gqj62602pihdt02.jpg +0 -0
- package/public/images/weibo-update/41/345/210/206/351/222/237/345/211/215/0040jbadgy1igrkjfvxnzj62432n57wh02.jpg +0 -0
- package/public/images/weibo-update/8-14-17-16/0040jbadgy1ig3ixniv2yj627y4fxb2b02.jpg +0 -0
- package/public/images/weibo-update/8-14-17-16/0040jbadgy1ig3ixsvbdaj625k2vfu1102.jpg +0 -0
- package/public/images/weibo-update/8-14-17-16/0040jbadgy1ig3ixxxdaoj62c03501l202.jpg +0 -0
- package/public/images/weibo-update/8-14-17-16/0040jbadgy1ig3ixzeef9j62c0340npd02.jpg +0 -0
- package/public/images/weibo-update/8-14-17-16/0040jbadgy1ig3iy0vs6tj626t4rbhdu02.jpg +0 -0
- package/public/images/weibo-update/8-14-17-16/0040jbadgy1ig3iy21wwuj62bt34hx6q02.jpg +0 -0
- package/public/images/weibo-update/8-8-17-39/0040jbadgy1ifwly4wr85j62z629y7wh02.jpg +0 -0
- package/public/images/weibo-update/8-8-17-39/0040jbadgy1ifwly67oilj623u2t5npd02.jpg +0 -0
- package/public/images/weibo-update/8-8-17-39/0040jbadgy1ifwly9qtw8j62c0340u0x02.jpg +0 -0
- package/public/images/weibo-update/8-8-17-39/0040jbadgy1ifwlyem4m4j63402c01kz02.jpg +0 -0
- package/public/images/weibo-update/8-8-17-39/0040jbadgy1ifwlygkoq4j627s2yeavd02.jpg +0 -0
- package/public/images/weibo-update/8-8-17-39/0040jbadgy1ifwlyjh0daj62bw340nm102.jpg +0 -0
- package/public/images/weibo-update/8-8-17-39/0040jbadgy1ifwlylejlhj62bw3401kx02.jpg +0 -0
- package/public/images/weibo-update/today/0040jbadgy1igaiaa8b7fj627j2y67wh02.jpg +0 -0
- package/public/images/weibo-update/today/0040jbadgy1igaiagw3ezj61s02ebu0x02.jpg +0 -0
- package/public/images/weibo-update/today/0040jbadgy1igaiaivng3j61rv2ebx6p02.jpg +0 -0
- package/public/images/weibo-update/today/0040jbadgy1igaiajuixvj62bw340qv502.jpg +0 -0
- package/public/images/weibo-update/today/0040jbadgy1igaiapyartj62bw340hdt02.jpg +0 -0
- package/public/images/weibo-update/today/0040jbadgy1igaibkwu4ij61vy2iq1kx02.jpg +0 -0
- package/public/images/weibo-update/today/0040jbadgy1igaic1fvkpj61u92eo1ky02.jpg +0 -0
- package/public/images/weibo-update/today/0040jbadgy1igaic3cruhj62822ywb2902.jpg +0 -0
- package/public/manifest.json +25 -0
- package/public/mcp-logo-128.png +0 -0
- package/public/mcp-logo-64.png +0 -0
- package/public/mcp-logo.svg +16 -0
- package/server/agent/agentCore.js +542 -74
- package/server/agent/appPaths.js +1 -0
- package/server/agent/audioPlayer.js +4 -2
- package/server/agent/citations.js +294 -0
- package/server/agent/clarificationAnalytics.js +477 -0
- package/server/agent/clarifyingQuestions.js +1089 -0
- package/server/agent/cli.js +549 -125
- package/server/agent/commandFeatures.js +1 -0
- package/server/agent/commandRegistry.js +946 -879
- package/server/agent/commands.js +546 -272
- package/server/agent/config.js +581 -412
- package/server/agent/contextCompactor.js +2 -2
- package/server/agent/debate.js +235 -0
- package/server/agent/eventBus.js +3 -0
- package/server/agent/feedbackLearning.js +217 -0
- package/server/agent/llmClient.js +512 -394
- package/server/agent/mcpClient.js +182 -32
- package/server/agent/memory.js +283 -224
- package/server/agent/modelManager.js +79 -39
- package/server/agent/profiles.js +178 -0
- package/server/agent/publicTools.js +22 -0
- package/server/agent/queryDetails.js +68 -8
- package/server/agent/quizData.js +398 -384
- package/server/agent/research.js +121 -79
- package/server/agent/sanitizer.js +104 -13
- package/server/agent/session.js +319 -11
- package/server/agent/subagent.js +8 -3
- package/server/agent/suggestionTui.js +294 -0
- package/server/agent/suggestions.js +69 -3
- package/server/agent/telemetry.js +119 -0
- package/server/agent/terminalImage.js +146 -27
- package/server/agent/theme.js +17 -0
- package/server/agent/toolRouter.js +16 -1
- package/server/agent/tools.js +424 -225
- package/server/agent/ui.js +486 -64
- package/server/agent/version.js +2 -4
- package/server/agent/webSearch.js +111 -11
- package/server/agent/youtubeAuth.js +24 -6
- package/server/apiRouter.js +4222 -0
- package/server/mcp/data/discography.js +25 -16
- package/server/mcp/data/gallery.js +308 -20
- package/server/mcp/data/profile.js +74 -44
- package/server/mcp/data/timeline.js +1 -1
- package/server/mcp/data/works.js +51 -17
- package/server/mcp/dataAdapter.js +5 -3
- package/server/mcp/handler.js +5 -11
- package/server/mcp/prompts.js +86 -0
- package/server/mcp/security.js +18 -15
- package/server/mcp/server.js +7 -2
- package/server/mcp/tools.js +66 -2
- package/server/web-chat/core/browserLauncher.js +18 -0
- package/server/web-chat/core/connection.js +194 -0
- package/server/web-chat/core/conversationContext.js +82 -0
- package/server/web-chat/core/directCatalogEngine.js +196 -0
- package/server/web-chat/core/dramaKnowledge.js +142 -0
- package/server/web-chat/core/errorHandler.js +51 -0
- package/server/web-chat/core/followUpEngine.js +182 -0
- package/server/web-chat/core/futureEventGuard.js +80 -0
- package/server/web-chat/core/memorySnapshot.js +12 -0
- package/server/web-chat/core/security.js +146 -0
- package/server/web-chat/core/toolInspector.js +52 -0
- package/server/web-chat/router.js +120 -0
- package/server/web-chat/routes/chatRoute.js +397 -0
- package/server/web-chat/routes/clarifyConfigRoute.js +98 -0
- package/server/web-chat/routes/clarifyRoute.js +83 -0
- package/server/web-chat/routes/compareRoute.js +79 -0
- package/server/web-chat/routes/exportRoute.js +59 -0
- package/server/web-chat/routes/feedbackRoute.js +57 -0
- package/server/web-chat/routes/newsRoute.js +33 -0
- package/server/web-chat/routes/quizRoute.js +11 -0
- package/server/web-chat/routes/staticRoute.js +103 -0
- package/server/web-chat/routes/statusRoute.js +52 -0
- package/server/web-chat/routes/suggestRoute.js +77 -0
- package/server/web-chat/routes/timelineRoute.js +34 -0
- package/server/web-chat/routes/verifyRoute.js +57 -0
- package/server/web-chat/server.js +116 -0
- package/server/web-chat/ui/htmlBuilder.js +91 -0
- package/server/web-chat/ui/previews/agentBubble.preview.html +134 -0
- package/server/web-chat/ui/scripts/agentBubbleSystem.js +320 -0
- package/server/web-chat/ui/scripts/client.js +8397 -0
- package/server/web-chat/ui/scripts/kikuDb.js +177 -0
- package/server/web-chat/ui/scripts/suggestionsData.js +118 -0
- package/server/web-chat/ui/scripts/webchatI18n.js +291 -0
- package/server/web-chat/ui/styles/main.css +8568 -0
- package/server/web-chat/ui/templates/body.html +796 -0
- package/server/webChatHtml.js +1 -0
- package/server/webChatServer.js +6 -0
- package/src/data/discographyData.js +892 -866
- package/src/data/galleryData.js +1805 -561
- package/src/data/profileData.js +79 -2
- package/src/data/socialUpdatesData.js +106 -47
- package/src/data/timelineData.js +1 -1
- package/src/data/worksData.js +25 -4
- package/tokens.css +97 -0
- package/server/agent/updateManager.js +0 -456
package/server/agent/ui.js
CHANGED
|
@@ -2,15 +2,15 @@ import readline from 'node:readline';
|
|
|
2
2
|
import { stdin as input, stdout as output } from 'node:process';
|
|
3
3
|
import { eventBus, Events } from './eventBus.js';
|
|
4
4
|
import { AgentStates } from './agentState.js';
|
|
5
|
-
import { ansiBackground, ansiForeground, getThemePalette } from './theme.js';
|
|
5
|
+
import { ansiBackground, ansiForeground, getThemePalette, isColorDisabled } from './theme.js';
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
export const C = Object.freeze({
|
|
9
|
-
reset: '\x1b[0m',
|
|
10
|
-
bold: '\x1b[1m',
|
|
11
|
-
dim: '\x1b[2m',
|
|
12
|
-
italic: '\x1b[3m',
|
|
13
|
-
underline: '\x1b[4m',
|
|
9
|
+
get reset() { return isColorDisabled() ? '' : '\x1b[0m'; },
|
|
10
|
+
get bold() { return isColorDisabled() ? '' : '\x1b[1m'; },
|
|
11
|
+
get dim() { return isColorDisabled() ? '' : '\x1b[2m'; },
|
|
12
|
+
get italic() { return isColorDisabled() ? '' : '\x1b[3m'; },
|
|
13
|
+
get underline() { return isColorDisabled() ? '' : '\x1b[4m'; },
|
|
14
14
|
|
|
15
15
|
get sakura() { return ansiForeground(getThemePalette().primary); },
|
|
16
16
|
get roseGlow() { return ansiForeground(getThemePalette().secondary); },
|
|
@@ -221,6 +221,105 @@ export function sliceLineForDisplay(str, cursor, maxWidth) {
|
|
|
221
221
|
return { displayLine, cursorVisualOffset };
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
export function getMultilinePromptLayout(text, cursor = 0, maxWidth = 80, maxRows = 6) {
|
|
225
|
+
const safeWidth = Math.max(10, Number(maxWidth) || 80);
|
|
226
|
+
const safeMaxRows = Math.max(1, Math.min(10, Number(maxRows) || 6));
|
|
227
|
+
const rawParagraphs = String(text || '').split('\n');
|
|
228
|
+
const lines = [];
|
|
229
|
+
let cursorRow = 0;
|
|
230
|
+
let cursorCol = 0;
|
|
231
|
+
let runningCharCount = 0;
|
|
232
|
+
|
|
233
|
+
for (let pIdx = 0; pIdx < rawParagraphs.length; pIdx++) {
|
|
234
|
+
const paragraph = rawParagraphs[pIdx];
|
|
235
|
+
const segments = getGraphemeSegments(paragraph);
|
|
236
|
+
let currentLineSegments = [];
|
|
237
|
+
let currentLineWidth = 0;
|
|
238
|
+
let lineStartIndex = runningCharCount;
|
|
239
|
+
|
|
240
|
+
for (let sIdx = 0; sIdx < segments.length; sIdx++) {
|
|
241
|
+
const seg = segments[sIdx];
|
|
242
|
+
const segWidth = getStringDisplayWidth(seg.segment);
|
|
243
|
+
|
|
244
|
+
if (currentLineWidth + segWidth > safeWidth && currentLineSegments.length > 0) {
|
|
245
|
+
const lineText = currentLineSegments.map(s => s.segment).join('');
|
|
246
|
+
lines.push({
|
|
247
|
+
text: lineText,
|
|
248
|
+
width: currentLineWidth,
|
|
249
|
+
start: lineStartIndex,
|
|
250
|
+
end: lineStartIndex + lineText.length,
|
|
251
|
+
});
|
|
252
|
+
lineStartIndex += lineText.length;
|
|
253
|
+
currentLineSegments = [];
|
|
254
|
+
currentLineWidth = 0;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
currentLineSegments.push(seg);
|
|
258
|
+
currentLineWidth += segWidth;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const lineText = currentLineSegments.map(s => s.segment).join('');
|
|
262
|
+
lines.push({
|
|
263
|
+
text: lineText,
|
|
264
|
+
width: currentLineWidth,
|
|
265
|
+
start: lineStartIndex,
|
|
266
|
+
end: lineStartIndex + lineText.length,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
runningCharCount += paragraph.length;
|
|
270
|
+
if (pIdx < rawParagraphs.length - 1) {
|
|
271
|
+
runningCharCount += 1;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const safeCursor = Math.max(0, Math.min((text || '').length, cursor));
|
|
276
|
+
let foundCursor = false;
|
|
277
|
+
|
|
278
|
+
for (let i = 0; i < lines.length; i++) {
|
|
279
|
+
const line = lines[i];
|
|
280
|
+
const isLastLine = i === lines.length - 1;
|
|
281
|
+
if (safeCursor >= line.start && (safeCursor <= line.end || isLastLine)) {
|
|
282
|
+
cursorRow = i;
|
|
283
|
+
const textBeforeCursorInLine = (text || '').slice(line.start, safeCursor);
|
|
284
|
+
cursorCol = getStringDisplayWidth(textBeforeCursorInLine);
|
|
285
|
+
foundCursor = true;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (!foundCursor) {
|
|
291
|
+
cursorRow = Math.max(0, lines.length - 1);
|
|
292
|
+
cursorCol = lines[cursorRow] ? lines[cursorRow].width : 0;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let visibleStart = 0;
|
|
296
|
+
let visibleEnd = lines.length;
|
|
297
|
+
|
|
298
|
+
if (lines.length > safeMaxRows) {
|
|
299
|
+
if (cursorRow >= safeMaxRows) {
|
|
300
|
+
visibleStart = cursorRow - safeMaxRows + 1;
|
|
301
|
+
visibleEnd = cursorRow + 1;
|
|
302
|
+
} else {
|
|
303
|
+
visibleStart = 0;
|
|
304
|
+
visibleEnd = safeMaxRows;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const visibleLines = lines.slice(visibleStart, visibleEnd);
|
|
309
|
+
const displayCursorRow = cursorRow - visibleStart;
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
lines,
|
|
313
|
+
visibleLines: visibleLines.map(l => l.text),
|
|
314
|
+
visibleStart,
|
|
315
|
+
totalLines: lines.length,
|
|
316
|
+
cursorRow: displayCursorRow,
|
|
317
|
+
cursorCol,
|
|
318
|
+
hasMoreAbove: visibleStart > 0,
|
|
319
|
+
hasMoreBelow: visibleEnd < lines.length,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
224
323
|
export function getFullWidth() {
|
|
225
324
|
return process.stdout.columns || 80;
|
|
226
325
|
}
|
|
@@ -232,61 +331,86 @@ export function wrapText(text, maxWidth = 72) {
|
|
|
232
331
|
const lines = [];
|
|
233
332
|
const rawParagraphs = text.split('\n');
|
|
234
333
|
|
|
235
|
-
const tokenize = para => {
|
|
236
|
-
const raw = para.split(/\s+/).filter(Boolean);
|
|
237
|
-
const tokens = [];
|
|
238
|
-
for (let i = 0; i < raw.length; i++) {
|
|
239
|
-
if (raw[i] === '•' && i + 1 < raw.length) {
|
|
240
|
-
tokens.push('• ' + raw[i + 1]);
|
|
241
|
-
i++;
|
|
242
|
-
} else {
|
|
243
|
-
tokens.push(raw[i]);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
return tokens;
|
|
247
|
-
};
|
|
248
|
-
|
|
249
334
|
for (const para of rawParagraphs) {
|
|
250
335
|
if (!para.trim()) {
|
|
251
336
|
lines.push('');
|
|
252
337
|
continue;
|
|
253
338
|
}
|
|
254
339
|
|
|
255
|
-
const
|
|
340
|
+
const plainPara = stripAnsi(para);
|
|
341
|
+
const spaceMatch = plainPara.match(/^(\s+)/);
|
|
342
|
+
const initialIndent = spaceMatch ? spaceMatch[1] : '';
|
|
343
|
+
|
|
344
|
+
let continuationIndent = initialIndent;
|
|
345
|
+
const bulletMatch = plainPara.match(/^(\s*)([↳•\-\*]|\[\d+\])\s+/);
|
|
346
|
+
if (bulletMatch) {
|
|
347
|
+
continuationIndent = ' '.repeat(Math.min(12, getStringDisplayWidth(bulletMatch[0])));
|
|
348
|
+
} else if (initialIndent) {
|
|
349
|
+
continuationIndent = initialIndent;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const rawWords = para.trim().split(/\s+/).filter(Boolean);
|
|
353
|
+
const words = [];
|
|
354
|
+
for (let i = 0; i < rawWords.length; i++) {
|
|
355
|
+
if (rawWords[i] === '•' && i + 1 < rawWords.length) {
|
|
356
|
+
words.push('• ' + rawWords[i + 1]);
|
|
357
|
+
i++;
|
|
358
|
+
} else {
|
|
359
|
+
words.push(rawWords[i]);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
256
363
|
const paraLines = [];
|
|
257
|
-
let currentLine =
|
|
364
|
+
let currentLine = initialIndent;
|
|
365
|
+
let activeAnsi = '';
|
|
258
366
|
|
|
259
367
|
for (const word of words) {
|
|
260
368
|
if (!word) continue;
|
|
261
|
-
const testLine = currentLine ? (currentLine + ' ' + word) : word;
|
|
369
|
+
const testLine = currentLine.trim() ? (currentLine + ' ' + word) : (currentLine + word);
|
|
262
370
|
const testWidth = getStringDisplayWidth(testLine);
|
|
263
371
|
|
|
264
372
|
if (testWidth <= maxWidth) {
|
|
265
373
|
currentLine = testLine;
|
|
266
374
|
} else {
|
|
267
|
-
if (currentLine) {
|
|
268
|
-
paraLines.push(currentLine);
|
|
269
|
-
currentLine = word;
|
|
375
|
+
if (currentLine.trim()) {
|
|
376
|
+
paraLines.push(currentLine + (activeAnsi && !currentLine.endsWith('\x1b[0m') ? '\x1b[0m' : ''));
|
|
377
|
+
currentLine = continuationIndent + activeAnsi + word;
|
|
270
378
|
} else {
|
|
271
|
-
let chunk =
|
|
379
|
+
let chunk = continuationIndent + activeAnsi;
|
|
272
380
|
for (const ch of word) {
|
|
273
381
|
if (getStringDisplayWidth(chunk + ch) <= maxWidth) {
|
|
274
382
|
chunk += ch;
|
|
275
383
|
} else {
|
|
276
|
-
|
|
277
|
-
|
|
384
|
+
if (chunk.trim()) {
|
|
385
|
+
paraLines.push(chunk + (activeAnsi && !chunk.endsWith('\x1b[0m') ? '\x1b[0m' : ''));
|
|
386
|
+
}
|
|
387
|
+
chunk = continuationIndent + activeAnsi + ch;
|
|
278
388
|
}
|
|
279
389
|
}
|
|
280
390
|
currentLine = chunk;
|
|
281
391
|
}
|
|
282
392
|
}
|
|
393
|
+
|
|
394
|
+
const ansiMatches = word.match(/\x1b\[[0-9;]*[a-zA-Z]/g);
|
|
395
|
+
if (ansiMatches) {
|
|
396
|
+
for (const m of ansiMatches) {
|
|
397
|
+
if (m === '\x1b[0m' || m === '\x1b[m') {
|
|
398
|
+
activeAnsi = '';
|
|
399
|
+
} else {
|
|
400
|
+
activeAnsi += m;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (currentLine.trim()) {
|
|
407
|
+
paraLines.push(currentLine);
|
|
283
408
|
}
|
|
284
|
-
if (currentLine) paraLines.push(currentLine);
|
|
285
409
|
|
|
286
|
-
if (paraLines.length >= 2 && !/\s/.test(paraLines[paraLines.length - 1].trim())) {
|
|
410
|
+
if (paraLines.length >= 2 && !/\s/.test(stripAnsi(paraLines[paraLines.length - 1]).trim())) {
|
|
287
411
|
const last = paraLines[paraLines.length - 1];
|
|
288
412
|
const prev = paraLines[paraLines.length - 2];
|
|
289
|
-
const candidate = prev + ' ' + last;
|
|
413
|
+
const candidate = prev + ' ' + last.trim();
|
|
290
414
|
if (getStringDisplayWidth(candidate) <= maxWidth) {
|
|
291
415
|
paraLines[paraLines.length - 2] = candidate;
|
|
292
416
|
paraLines.pop();
|
|
@@ -300,6 +424,7 @@ export function wrapText(text, maxWidth = 72) {
|
|
|
300
424
|
|
|
301
425
|
|
|
302
426
|
|
|
427
|
+
|
|
303
428
|
export function stripAnsi(str) {
|
|
304
429
|
return String(str ?? '').replace(/\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1b\\))/g, '');
|
|
305
430
|
}
|
|
@@ -340,13 +465,13 @@ export function fitStyledText(styledText, maxWidth) {
|
|
|
340
465
|
|
|
341
466
|
export function printSolidBannerRow(styledText, targetWidth, requestedBg = C.bgPanel, indent = '') {
|
|
342
467
|
const terminalWidth = getFullWidth();
|
|
343
|
-
const rowWidth = Math.max(1,
|
|
344
|
-
const
|
|
345
|
-
const
|
|
346
|
-
const background = requestedBg === C.bgPanelHeader ? C.bgPanelHeader : C.bgPanel;
|
|
468
|
+
const rowWidth = Math.max(1, (targetWidth || terminalWidth) - getStringDisplayWidth(indent));
|
|
469
|
+
const fitted = fitStyledText(styledText, rowWidth);
|
|
470
|
+
const pad = Math.max(0, rowWidth - getStringDisplayWidth(fitted));
|
|
471
|
+
const background = requestedBg === C.bgPanelHeader ? C.bgPanelHeader : (requestedBg || C.bgPanel);
|
|
347
472
|
const fixedStyled = fitted.replace(/\x1b\[0m/g, C.reset + background + C.white);
|
|
348
473
|
|
|
349
|
-
console.log(indent + background + C.white + fixedStyled + '
|
|
474
|
+
console.log(indent + background + C.white + fixedStyled + ' '.repeat(pad) + C.reset);
|
|
350
475
|
}
|
|
351
476
|
|
|
352
477
|
let activeTuiPrompt = null;
|
|
@@ -464,11 +589,11 @@ export function formatSolidPanelLines({ title, lines, width, indent = '', header
|
|
|
464
589
|
const text = typeof raw === 'string' ? raw : (raw?.text ?? '');
|
|
465
590
|
const sublines = String(text).split('\n');
|
|
466
591
|
for (const subline of sublines) {
|
|
467
|
-
const isBoxTable = /^\s*
|
|
592
|
+
const isBoxTable = /^\s*(\x1b\[[0-9;]*[a-zA-Z])*[┌├└│]/.test(subline) || /^[┌├└│]/.test(stripAnsi(subline).trimStart());
|
|
468
593
|
const wrappedSublines = isBoxTable ? [subline] : wrapText(subline, maxContentWidth);
|
|
469
594
|
for (const wrapped of (wrappedSublines.length > 0 ? wrappedSublines : [''])) {
|
|
470
595
|
const rowText = isBoxTable ? (wrapped.startsWith(indent) ? wrapped : `${indent}${wrapped}`) : `${indent} ${wrapped}`;
|
|
471
|
-
const fitted = fitStyledText(rowText, w);
|
|
596
|
+
const fitted = isBoxTable ? rowText : fitStyledText(rowText, w);
|
|
472
597
|
const pad = Math.max(0, w - getStringDisplayWidth(fitted));
|
|
473
598
|
const themed = fitted.replace(/\x1b\[0m/g, C.reset + bodyBg + C.white);
|
|
474
599
|
rows.push(`${bodyBg}${C.white}${themed}${' '.repeat(pad)}${C.reset}`);
|
|
@@ -642,7 +767,7 @@ export function formatRichCardLines({
|
|
|
642
767
|
const normStatus = String(status || 'info').toLowerCase();
|
|
643
768
|
const st = STATUS_THEMES[normStatus] || STATUS_THEMES.info;
|
|
644
769
|
const termWidth = width || getFullWidth();
|
|
645
|
-
const blockWidth = Math.max(30,
|
|
770
|
+
const blockWidth = Math.max(30, termWidth - (indent ? getStringDisplayWidth(indent) : 0));
|
|
646
771
|
const rows = [];
|
|
647
772
|
|
|
648
773
|
const icon = st.icon;
|
|
@@ -695,15 +820,32 @@ export function printRichStatusCard({ status, title, lines = [], footer = '', wi
|
|
|
695
820
|
console.log(`\n${rows.join('\n')}\n`);
|
|
696
821
|
}
|
|
697
822
|
|
|
823
|
+
export function cleanTableCell(raw) {
|
|
824
|
+
if (!raw) return '';
|
|
825
|
+
return String(raw)
|
|
826
|
+
.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, (m, text, url) => {
|
|
827
|
+
const t = text.trim();
|
|
828
|
+
const u = url.trim();
|
|
829
|
+
return t === u ? u : `${t} (${u})`;
|
|
830
|
+
})
|
|
831
|
+
.replace(/\*\*/g, '')
|
|
832
|
+
.replace(/`/g, '')
|
|
833
|
+
.replace(/\s+/g, ' ')
|
|
834
|
+
.trim();
|
|
835
|
+
}
|
|
836
|
+
|
|
698
837
|
export function formatRichTable(headers = [], rows = [], maxWidth = getFullWidth() - 4) {
|
|
699
838
|
if (!headers.length && !rows.length) return [];
|
|
700
839
|
const colCount = Math.max(headers.length, ...rows.map(r => r.length));
|
|
701
|
-
const colWidths = new Array(colCount).fill(
|
|
840
|
+
const colWidths = new Array(colCount).fill(4);
|
|
841
|
+
|
|
842
|
+
const cleanHeaders = headers.map(cleanTableCell);
|
|
843
|
+
const cleanRows = rows.map(r => r.map(cleanTableCell));
|
|
702
844
|
|
|
703
845
|
for (let c = 0; c < colCount; c++) {
|
|
704
|
-
const headerLen = getStringDisplayWidth(
|
|
846
|
+
const headerLen = getStringDisplayWidth(cleanHeaders[c] || '');
|
|
705
847
|
colWidths[c] = Math.max(colWidths[c], headerLen);
|
|
706
|
-
for (const row of
|
|
848
|
+
for (const row of cleanRows) {
|
|
707
849
|
const cellLen = getStringDisplayWidth(row[c] || '');
|
|
708
850
|
colWidths[c] = Math.max(colWidths[c], cellLen);
|
|
709
851
|
}
|
|
@@ -725,10 +867,14 @@ export function formatRichTable(headers = [], rows = [], maxWidth = getFullWidth
|
|
|
725
867
|
|
|
726
868
|
output.push(`${C.slate}${topBorder}${C.reset}`);
|
|
727
869
|
|
|
728
|
-
if (
|
|
870
|
+
if (cleanHeaders.length > 0) {
|
|
729
871
|
const headerCells = [];
|
|
730
872
|
for (let c = 0; c < colCount; c++) {
|
|
731
|
-
const
|
|
873
|
+
const rawText = cleanHeaders[c] || '';
|
|
874
|
+
const textLen = getStringDisplayWidth(rawText);
|
|
875
|
+
const text = textLen > colWidths[c] && colWidths[c] > 3
|
|
876
|
+
? fitStyledText(rawText, colWidths[c] - 1) + '…'
|
|
877
|
+
: fitStyledText(rawText, colWidths[c]);
|
|
732
878
|
const pad = Math.max(0, colWidths[c] - getStringDisplayWidth(text));
|
|
733
879
|
headerCells.push(`${C.bold}${C.gold}${text}${C.reset}${' '.repeat(pad)}`);
|
|
734
880
|
}
|
|
@@ -736,11 +882,14 @@ export function formatRichTable(headers = [], rows = [], maxWidth = getFullWidth
|
|
|
736
882
|
output.push(`${C.slate}${midBorder}${C.reset}`);
|
|
737
883
|
}
|
|
738
884
|
|
|
739
|
-
for (const row of
|
|
885
|
+
for (const row of cleanRows) {
|
|
740
886
|
const rowCells = [];
|
|
741
887
|
for (let c = 0; c < colCount; c++) {
|
|
742
888
|
const cellRaw = row[c] || '—';
|
|
743
|
-
const
|
|
889
|
+
const cellLen = getStringDisplayWidth(cellRaw);
|
|
890
|
+
const text = cellLen > colWidths[c] && colWidths[c] > 3
|
|
891
|
+
? fitStyledText(cellRaw, colWidths[c] - 1) + '…'
|
|
892
|
+
: fitStyledText(cellRaw, colWidths[c]);
|
|
744
893
|
const pad = Math.max(0, colWidths[c] - getStringDisplayWidth(text));
|
|
745
894
|
rowCells.push(`${C.white}${text}${C.reset}${' '.repeat(pad)}`);
|
|
746
895
|
}
|
|
@@ -754,6 +903,8 @@ export function formatRichTable(headers = [], rows = [], maxWidth = getFullWidth
|
|
|
754
903
|
export function formatTerminalMarkdown(text) {
|
|
755
904
|
if (!text) return '';
|
|
756
905
|
return text
|
|
906
|
+
.replace(/^#####?\s*(.+)$/gm, ` ${C.bold}${C.lavender}• $1${C.reset}`)
|
|
907
|
+
.replace(/^####\s*(.+)$/gm, `${C.bold}${C.cyberCyan}▸ $1${C.reset}`)
|
|
757
908
|
.replace(/^###\s*(.+)$/gm, `${C.bold}${C.gold}✦ $1${C.reset}`)
|
|
758
909
|
.replace(/^##\s*(.+)$/gm, `${C.bold}${C.roseGlow}■ $1${C.reset}`)
|
|
759
910
|
.replace(/^#\s*(.+)$/gm, `${C.bold}${C.sakura}━━━ $1 ━━━${C.reset}`)
|
|
@@ -763,7 +914,8 @@ export function formatTerminalMarkdown(text) {
|
|
|
763
914
|
.replace(/\*\*([^*]+)\*\*/g, `${C.bold}${C.white}$1${C.reset}`)
|
|
764
915
|
.replace(/(?<!\*)\*([^\*\n]+)\*(?!\*)/g, `${C.italic}${C.white}$1${C.reset}`)
|
|
765
916
|
.replace(/`([^`]+)`/g, `${C.cyberCyan}$1${C.reset}`)
|
|
766
|
-
.replace(/^(\s*)
|
|
917
|
+
.replace(/^(\s*)(\d+)\.\s+/gm, `$1 ${C.gold}$2.${C.reset} `)
|
|
918
|
+
.replace(/^(\s*)[*•+-]\s+/gm, `$1 ${C.sakura}•${C.reset} `)
|
|
767
919
|
.replace(/^\s*[-*_]{3,}\s*$/gm, ` ${C.slate}${'─'.repeat(Math.max(20, getFullWidth() - 6))}${C.reset}`);
|
|
768
920
|
}
|
|
769
921
|
|
|
@@ -784,7 +936,7 @@ export function parseMarkdownTableRow(text) {
|
|
|
784
936
|
export function isMarkdownTableSeparator(cells) {
|
|
785
937
|
return Array.isArray(cells)
|
|
786
938
|
&& cells.length > 0
|
|
787
|
-
&& cells.every(cell =>
|
|
939
|
+
&& cells.every(cell => /^:?-+:?$/.test(cell.replace(/\s+/g, '')));
|
|
788
940
|
}
|
|
789
941
|
|
|
790
942
|
export function expandMarkdownLinks(text) {
|
|
@@ -821,8 +973,8 @@ export function formatMarkdownLines(text, maxWidth = getFullWidth() - 8) {
|
|
|
821
973
|
const cells = parseMarkdownTableRow(rawLine);
|
|
822
974
|
|
|
823
975
|
if (pendingHeader) {
|
|
824
|
-
if (cells &&
|
|
825
|
-
tableHeaders = pendingHeader.map(
|
|
976
|
+
if (cells && isMarkdownTableSeparator(cells)) {
|
|
977
|
+
tableHeaders = pendingHeader.map(cleanTableCell);
|
|
826
978
|
pendingHeader = null;
|
|
827
979
|
tableRows = [];
|
|
828
980
|
continue;
|
|
@@ -833,8 +985,12 @@ export function formatMarkdownLines(text, maxWidth = getFullWidth() - 8) {
|
|
|
833
985
|
}
|
|
834
986
|
|
|
835
987
|
if (tableHeaders) {
|
|
836
|
-
if (cells &&
|
|
837
|
-
|
|
988
|
+
if (cells && !isMarkdownTableSeparator(cells)) {
|
|
989
|
+
const normalizedRow = new Array(tableHeaders.length).fill('');
|
|
990
|
+
for (let c = 0; c < tableHeaders.length; c++) {
|
|
991
|
+
normalizedRow[c] = cleanTableCell(cells[c] || '');
|
|
992
|
+
}
|
|
993
|
+
tableRows.push(normalizedRow);
|
|
838
994
|
continue;
|
|
839
995
|
} else {
|
|
840
996
|
flushTable();
|
|
@@ -914,7 +1070,7 @@ export function getWelcomeHeroLines() {
|
|
|
914
1070
|
padItem(c + '◆', 'Music & OST', '"OSTs from In Blossom & Ruyi Pavilion, /play Ginkgo"'),
|
|
915
1071
|
padItem(e + '◆', 'Endorsements', '"Versace Global Ambassador & fashion partnerships"'),
|
|
916
1072
|
padItem(l + '◆', 'Tools / MCP', '"@search_works 2026, /mcp list, /stats, /help"'),
|
|
917
|
-
` ${s}╰${'─'.repeat(
|
|
1073
|
+
` ${s}╰${'─'.repeat(innerWidth)}╯${rst}`,
|
|
918
1074
|
'',
|
|
919
1075
|
...shortcutLines,
|
|
920
1076
|
'',
|
|
@@ -961,12 +1117,11 @@ export function setupOutputInterception(tuiPrompt, _isProcessingFn) {
|
|
|
961
1117
|
if (tuiPrompt && tuiPrompt.screenBuffer && !tuiPrompt.isDisposed && !isTuiWriting) {
|
|
962
1118
|
const str = String(chunk);
|
|
963
1119
|
if (
|
|
964
|
-
str.startsWith('\x1b[H') ||
|
|
965
1120
|
str.startsWith('\x1b[?1049') ||
|
|
966
|
-
str.startsWith('\x1b[?25') ||
|
|
967
1121
|
str.startsWith('\x1b[?1000') ||
|
|
968
1122
|
str.startsWith('\x1b[?1002') ||
|
|
969
|
-
str.startsWith('\x1b[?1006')
|
|
1123
|
+
str.startsWith('\x1b[?1006') ||
|
|
1124
|
+
str.startsWith('\x1b[?1015')
|
|
970
1125
|
) {
|
|
971
1126
|
return _rawStdoutWrite(chunk, encoding, callback);
|
|
972
1127
|
}
|
|
@@ -1025,7 +1180,7 @@ export function formatTaskPlanBanner(plan) {
|
|
|
1025
1180
|
const barEmpty = 10 - barFilled;
|
|
1026
1181
|
const progressBar = `[${'█'.repeat(barFilled)}${'░'.repeat(barEmpty)}] ${pct}%`;
|
|
1027
1182
|
|
|
1028
|
-
const termWidth = Math.
|
|
1183
|
+
const termWidth = Math.max(20, getFullWidth());
|
|
1029
1184
|
const bg = C.bgPanel;
|
|
1030
1185
|
const bgHeader = C.bgPanelHeader;
|
|
1031
1186
|
|
|
@@ -1077,6 +1232,7 @@ export function formatTaskPlanBanner(plan) {
|
|
|
1077
1232
|
let isAlternateScreenActive = false;
|
|
1078
1233
|
|
|
1079
1234
|
export function enterAlternateScreen() {
|
|
1235
|
+
if (isColorDisabled()) return;
|
|
1080
1236
|
if (process.stdout.isTTY && !isAlternateScreenActive) {
|
|
1081
1237
|
isAlternateScreenActive = true;
|
|
1082
1238
|
_rawStdoutWrite('\x1b[?1049h\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1005l\x1b[?1006l\x1b[?1015l\x1b[?25l\x1b[H\x1b[2J');
|
|
@@ -1090,20 +1246,27 @@ export function exitAlternateScreen() {
|
|
|
1090
1246
|
}
|
|
1091
1247
|
}
|
|
1092
1248
|
|
|
1093
|
-
export function getTuiViewportLayout(termRows = 24) {
|
|
1249
|
+
export function getTuiViewportLayout(termRows = 24, promptLinesCount = 1) {
|
|
1094
1250
|
const parsedRows = Number(termRows);
|
|
1095
1251
|
const rows = Math.max(10, Number.isFinite(parsedRows) ? Math.floor(parsedRows) : 24);
|
|
1096
|
-
const
|
|
1097
|
-
const
|
|
1098
|
-
const promptRow = rows - 2;
|
|
1252
|
+
const extraPromptRows = Math.max(0, Math.min(Math.floor(rows / 3), (Number(promptLinesCount) || 1) - 1));
|
|
1253
|
+
const promptHeight = 1 + extraPromptRows;
|
|
1099
1254
|
const separatorRow = rows - 1;
|
|
1255
|
+
const promptStartRow = (rows - 2) - extraPromptRows;
|
|
1256
|
+
const promptEndRow = promptStartRow + promptHeight - 1;
|
|
1257
|
+
const statusBarRow = (rows - 4) - extraPromptRows;
|
|
1258
|
+
const viewportStartRow = 1;
|
|
1259
|
+
const viewportHeight = Math.max(1, statusBarRow - viewportStartRow);
|
|
1100
1260
|
|
|
1101
1261
|
return {
|
|
1102
1262
|
termRows: rows,
|
|
1103
1263
|
viewportStartRow,
|
|
1104
|
-
viewportHeight
|
|
1264
|
+
viewportHeight,
|
|
1105
1265
|
statusBarRow,
|
|
1106
|
-
promptRow,
|
|
1266
|
+
promptRow: promptStartRow,
|
|
1267
|
+
promptStartRow,
|
|
1268
|
+
promptEndRow,
|
|
1269
|
+
promptHeight,
|
|
1107
1270
|
separatorRow,
|
|
1108
1271
|
};
|
|
1109
1272
|
}
|
|
@@ -1215,4 +1378,263 @@ export class VirtualScreenBuffer {
|
|
|
1215
1378
|
}
|
|
1216
1379
|
}
|
|
1217
1380
|
|
|
1381
|
+
function getMilestonePalette(era = '', year = '') {
|
|
1382
|
+
if (isColorDisabled()) {
|
|
1383
|
+
return {
|
|
1384
|
+
yearBg: '',
|
|
1385
|
+
yearFg: '',
|
|
1386
|
+
badgeBg: '',
|
|
1387
|
+
badgeFg: '',
|
|
1388
|
+
tagBg: '',
|
|
1389
|
+
tagFg: '',
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
const eraLower = String(era || '').toLowerCase();
|
|
1394
|
+
const yearNum = parseInt(year, 10) || 0;
|
|
1395
|
+
|
|
1396
|
+
|
|
1397
|
+
if (eraLower.includes('snh') || (yearNum >= 2013 && yearNum <= 2017)) {
|
|
1398
|
+
return {
|
|
1399
|
+
yearBg: '\x1b[48;2;180;36;85m',
|
|
1400
|
+
yearFg: '\x1b[38;2;255;255;255m',
|
|
1401
|
+
badgeBg: '\x1b[48;2;60;25;40m',
|
|
1402
|
+
badgeFg: '\x1b[38;2;255;185;210m',
|
|
1403
|
+
tagBg: '\x1b[48;2;40;22;32m',
|
|
1404
|
+
tagFg: '\x1b[38;2;230;170;190m',
|
|
1405
|
+
};
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
|
|
1409
|
+
if (eraLower.includes('solo') || eraLower.includes('star48') || (yearNum >= 2018 && yearNum <= 2023)) {
|
|
1410
|
+
return {
|
|
1411
|
+
yearBg: '\x1b[48;2;115;45;160m',
|
|
1412
|
+
yearFg: '\x1b[38;2;255;255;255m',
|
|
1413
|
+
badgeBg: '\x1b[48;2;55;30;70m',
|
|
1414
|
+
badgeFg: '\x1b[38;2;225;175;255m',
|
|
1415
|
+
tagBg: '\x1b[48;2;38;22;48m',
|
|
1416
|
+
tagFg: '\x1b[38;2;200;160;230m',
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
|
|
1421
|
+
return {
|
|
1422
|
+
yearBg: '\x1b[48;2;18;110;120m',
|
|
1423
|
+
yearFg: '\x1b[38;2;255;255;255m',
|
|
1424
|
+
badgeBg: '\x1b[48;2;20;50;55m',
|
|
1425
|
+
badgeFg: '\x1b[38;2;130;240;250m',
|
|
1426
|
+
tagBg: '\x1b[48;2;16;35;40m',
|
|
1427
|
+
tagFg: '\x1b[38;2;110;200;210m',
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
export function formatCareerTimelineGraphic(items = [], width = getFullWidth()) {
|
|
1432
|
+
const termWidth = Math.max(40, width);
|
|
1433
|
+
const rows = [];
|
|
1434
|
+
|
|
1435
|
+
const headerBg = isColorDisabled() ? '' : '\x1b[48;2;65;20;42m';
|
|
1436
|
+
const headerFg = isColorDisabled() ? '' : '\x1b[38;2;255;220;235m';
|
|
1437
|
+
|
|
1438
|
+
rows.push(`${headerBg}${headerFg}${C.bold} ◆ JU JINGYI • 鞠婧祎 CAREER MILESTONES TIMELINE ${C.reset}`);
|
|
1439
|
+
rows.push(`${C.dim} Artistic eras, breakthrough performances, and landmark milestones${C.reset}`);
|
|
1440
|
+
rows.push('');
|
|
1441
|
+
|
|
1442
|
+
for (let i = 0; i < items.length; i++) {
|
|
1443
|
+
const item = items[i];
|
|
1444
|
+
const pal = getMilestonePalette(item.era, item.year);
|
|
1445
|
+
|
|
1446
|
+
const yearStr = item.year ? ` ${item.year} ` : ' ERA ';
|
|
1447
|
+
const yearBadge = `${pal.yearBg}${pal.yearFg}${C.bold}${yearStr}${C.reset}`;
|
|
1448
|
+
|
|
1449
|
+
const titleText = `${C.white}${C.bold}${item.title || item.titleEn || ''}${C.reset}`;
|
|
1450
|
+
const cnText = item.titleCn ? ` ${C.slate}(${item.titleCn})${C.reset}` : '';
|
|
1451
|
+
const badgeText = item.badge
|
|
1452
|
+
? ` ${pal.badgeBg}${pal.badgeFg}${C.bold} ✨ ${item.badge} ${C.reset}`
|
|
1453
|
+
: '';
|
|
1454
|
+
|
|
1455
|
+
rows.push(` ${yearBadge} ${titleText}${cnText}${badgeText}`);
|
|
1456
|
+
|
|
1457
|
+
const metaParts = [];
|
|
1458
|
+
if (item.category) metaParts.push(item.category);
|
|
1459
|
+
if (item.date) metaParts.push(item.date);
|
|
1460
|
+
if (metaParts.length > 0) {
|
|
1461
|
+
const metaText = metaParts.join(' • ');
|
|
1462
|
+
rows.push(` ${pal.tagBg}${pal.tagFg} ${metaText} ${C.reset}`);
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
if (item.summary) {
|
|
1466
|
+
const wrapped = wrapText(item.summary, termWidth - 8);
|
|
1467
|
+
for (const wLine of wrapped) {
|
|
1468
|
+
rows.push(` ${C.slate}${wLine}${C.reset}`);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
if (Array.isArray(item.highlights) && item.highlights.length > 0) {
|
|
1473
|
+
for (const h of item.highlights) {
|
|
1474
|
+
const cleanH = String(h || '').replace(/^[•\-\*]\s*/, '');
|
|
1475
|
+
const wrappedH = wrapText(cleanH, termWidth - 10);
|
|
1476
|
+
for (let hi = 0; hi < wrappedH.length; hi++) {
|
|
1477
|
+
if (hi === 0) {
|
|
1478
|
+
rows.push(` ${C.sakura}•${C.reset} ${C.white}${wrappedH[hi]}${C.reset}`);
|
|
1479
|
+
} else {
|
|
1480
|
+
rows.push(` ${C.slate}${wrappedH[hi]}${C.reset}`);
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
if (i < items.length - 1) {
|
|
1487
|
+
rows.push('');
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
return rows;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
|
|
1495
|
+
export function formatDebateMatrix(debateResult, width = getFullWidth()) {
|
|
1496
|
+
const termWidth = Math.max(40, width);
|
|
1497
|
+
const rows = [];
|
|
1498
|
+
const r = debateResult || {};
|
|
1499
|
+
|
|
1500
|
+
rows.push(`${C.bold}${C.sakura}◆ MULTI-AGENT ADVERSARIAL DEBATE MATRIX${C.reset}`);
|
|
1501
|
+
rows.push(`${C.slate}${'═'.repeat(Math.min(termWidth - 2, 70))}${C.reset}`);
|
|
1502
|
+
rows.push(`${C.bold}${C.gold}Topic / Claim:${C.reset} ${C.white}${r.topic || 'N/A'}${C.reset}`);
|
|
1503
|
+
rows.push('');
|
|
1504
|
+
|
|
1505
|
+
rows.push(`${C.bold}${C.emerald}┌── ADVOCATE (Corroborating Primary Evidence) ────────────────────┐${C.reset}`);
|
|
1506
|
+
const advLines = formatMarkdownLines(r.advocate || 'No evidence provided.', termWidth - 8);
|
|
1507
|
+
for (const al of advLines) {
|
|
1508
|
+
rows.push(` ${C.slate}│${C.reset} ${al}`);
|
|
1509
|
+
}
|
|
1510
|
+
rows.push(`${C.bold}${C.emerald}└──${'─'.repeat(Math.min(termWidth - 6, 62))}┘${C.reset}`);
|
|
1511
|
+
rows.push('');
|
|
1512
|
+
|
|
1513
|
+
rows.push(`${C.bold}${C.roseGlow}┌── CRITIC (Counter-Evidence & Skeptic Findings) ─────────────────┐${C.reset}`);
|
|
1514
|
+
const critLines = formatMarkdownLines(r.critic || 'No counter-evidence provided.', termWidth - 8);
|
|
1515
|
+
for (const cl of critLines) {
|
|
1516
|
+
rows.push(` ${C.slate}│${C.reset} ${cl}`);
|
|
1517
|
+
}
|
|
1518
|
+
rows.push(`${C.bold}${C.roseGlow}└──${'─'.repeat(Math.min(termWidth - 6, 62))}┘${C.reset}`);
|
|
1519
|
+
rows.push('');
|
|
1520
|
+
|
|
1521
|
+
rows.push(`${C.bold}${C.cyberCyan}┌── NEUTRAL JUDGE SYNTHESIS & VERDICT ────────────────────────────┐${C.reset}`);
|
|
1522
|
+
const judgeLines = formatMarkdownLines(r.verdict || 'Synthesis unavailable.', termWidth - 8);
|
|
1523
|
+
for (const jl of judgeLines) {
|
|
1524
|
+
rows.push(` ${C.slate}│${C.reset} ${jl}`);
|
|
1525
|
+
}
|
|
1526
|
+
rows.push(`${C.bold}${C.cyberCyan}└──${'─'.repeat(Math.min(termWidth - 6, 62))}┘${C.reset}`);
|
|
1527
|
+
|
|
1528
|
+
return rows;
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
export function getCategoryBadge(category = '') {
|
|
1532
|
+
const norm = String(category || '').trim().toUpperCase();
|
|
1533
|
+
switch (norm) {
|
|
1534
|
+
case 'DRAMA':
|
|
1535
|
+
return { icon: '🌸', label: 'DRAMA', color: C.lavender, bg: '\x1b[48;2;48;32;72m' };
|
|
1536
|
+
case 'MUSIC':
|
|
1537
|
+
return { icon: '🎵', label: 'MUSIC', color: C.sakura, bg: '\x1b[48;2;72;32;56m' };
|
|
1538
|
+
case 'FASHION':
|
|
1539
|
+
return { icon: '✨', label: 'FASHION', color: C.cyberCyan, bg: '\x1b[48;2;24;48;64m' };
|
|
1540
|
+
case 'MILESTONE':
|
|
1541
|
+
case 'AWARDS':
|
|
1542
|
+
return { icon: '🌸', label: 'AWARDS', color: C.gold, bg: '\x1b[48;2;64;52;24m' };
|
|
1543
|
+
case 'ANALYSIS':
|
|
1544
|
+
return { icon: '📖', label: 'ANALYSIS', color: C.emerald, bg: '\x1b[48;2;24;56;36m' };
|
|
1545
|
+
case 'TRIVIA':
|
|
1546
|
+
return { icon: '💬', label: 'TRIVIA', color: C.amber, bg: '\x1b[48;2;64;40;20m' };
|
|
1547
|
+
default:
|
|
1548
|
+
return { icon: '✨', label: norm || 'TOPIC', color: C.white, bg: '\x1b[48;2;40;40;48m' };
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
export function formatWorkerProgressMatrix({ workers = [], batchId = '', elapsed = '0.0', termWidth = getFullWidth() } = {}) {
|
|
1553
|
+
const rows = [];
|
|
1554
|
+
const headerBg = isColorDisabled() ? '' : '\x1b[48;2;65;20;42m';
|
|
1555
|
+
const headerFg = isColorDisabled() ? '' : '\x1b[38;2;255;220;235m';
|
|
1556
|
+
|
|
1557
|
+
rows.push(` ${headerBg}${headerFg}${C.bold} 🌸 CONCURRENT RESEARCH SUBAGENTS [${workers.length} Workers • ${elapsed}s] ${C.reset}`);
|
|
1558
|
+
rows.push('');
|
|
1559
|
+
|
|
1560
|
+
for (const w of workers) {
|
|
1561
|
+
const badge = getCategoryBadge(w.category);
|
|
1562
|
+
let statePill = '';
|
|
1563
|
+
let stateText = 'Working';
|
|
1564
|
+
if (w.state === 'complete' || w.state === 'done') {
|
|
1565
|
+
stateText = 'Done';
|
|
1566
|
+
statePill = isColorDisabled() ? '[Done]' : '\x1b[48;2;20;65;35m\x1b[38;2;80;240;140m\x1b[1m Done \x1b[0m';
|
|
1567
|
+
} else if (w.state === 'error' || w.state === 'failed') {
|
|
1568
|
+
stateText = 'Error';
|
|
1569
|
+
statePill = isColorDisabled() ? '[Error]' : '\x1b[48;2;70;20;25m\x1b[38;2;255;120;120m\x1b[1m Error \x1b[0m';
|
|
1570
|
+
} else {
|
|
1571
|
+
stateText = 'Working';
|
|
1572
|
+
statePill = isColorDisabled() ? '[Working]' : '\x1b[48;2;20;45;65m\x1b[38;2;80;210;255m\x1b[1m Working \x1b[0m';
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
const catPill = isColorDisabled()
|
|
1576
|
+
? `[${badge.icon} ${badge.label}]`
|
|
1577
|
+
: `${badge.bg}${badge.color}${C.bold} ${badge.icon} ${badge.label} ${C.reset}`;
|
|
1578
|
+
const toolLabel = w.currentTool ? `> ${w.currentTool}` : (w.statusMessage || w.question || '');
|
|
1579
|
+
const cleanTool = stripAnsi(toolLabel).slice(0, 32);
|
|
1580
|
+
|
|
1581
|
+
rows.push(` ${statePill} ${C.bold}W${w.index || 1} [${badge.icon} ${badge.label}]${C.reset} ${C.white}${cleanTool}${C.reset} ${C.dim}${stateText}${C.reset}`);
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
rows.push('');
|
|
1585
|
+
return rows;
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
export function formatExecutiveFindings({ batchResult, termWidth = getFullWidth() } = {}) {
|
|
1589
|
+
const width = Math.max(50, termWidth - 4);
|
|
1590
|
+
const rows = [];
|
|
1591
|
+
const results = batchResult?.results || [];
|
|
1592
|
+
const total = batchResult?.tasksCount || results.length;
|
|
1593
|
+
const succeeded = batchResult?.successfulCount ?? results.filter(r => Boolean(r.answer)).length;
|
|
1594
|
+
const elapsed = batchResult?.elapsed || '0.0';
|
|
1595
|
+
|
|
1596
|
+
const headerBg = isColorDisabled() ? '' : '\x1b[48;2;65;20;42m';
|
|
1597
|
+
const headerFg = isColorDisabled() ? '' : '\x1b[38;2;255;220;235m';
|
|
1598
|
+
|
|
1599
|
+
rows.push('');
|
|
1600
|
+
rows.push(` ${headerBg}${headerFg}${C.bold} 🌸 KIKU EXECUTIVE RESEARCH FINDINGS [${succeeded}/${total} Succeeded • ${elapsed}s] ${C.reset}`);
|
|
1601
|
+
rows.push('');
|
|
1602
|
+
|
|
1603
|
+
for (const r of results) {
|
|
1604
|
+
const badge = getCategoryBadge(r.category);
|
|
1605
|
+
const catPill = isColorDisabled()
|
|
1606
|
+
? `[${badge.icon} ${badge.label}]`
|
|
1607
|
+
: `${badge.bg}${badge.color}${C.bold} ${badge.icon} ${badge.label} ${C.reset}`;
|
|
1608
|
+
const workerTag = isColorDisabled()
|
|
1609
|
+
? `[Worker ${r.index || 1}]`
|
|
1610
|
+
: `\x1b[48;2;38;30;46m\x1b[38;2;220;200;240m [Worker ${r.index || 1}] \x1b[0m`;
|
|
1611
|
+
|
|
1612
|
+
rows.push(` ${workerTag} ${catPill} ${C.bold}${C.white}[Worker ${r.index || 1}] ${badge.label}: ${r.question}${C.reset}`);
|
|
1613
|
+
|
|
1614
|
+
if (r.answer) {
|
|
1615
|
+
const formattedLines = formatMarkdownLines(r.answer, width - 8);
|
|
1616
|
+
for (const line of formattedLines) {
|
|
1617
|
+
rows.push(` ${line}`);
|
|
1618
|
+
}
|
|
1619
|
+
if (r.toolCalls?.length > 0) {
|
|
1620
|
+
const evidencePill = isColorDisabled()
|
|
1621
|
+
? '📖 Grounded Evidence:'
|
|
1622
|
+
: '\x1b[48;2;22;42;30m\x1b[38;2;120;230;160m 📖 Grounded Evidence \x1b[0m';
|
|
1623
|
+
rows.push(` ${evidencePill} ${C.dim}Grounded Evidence: ${r.toolCalls.length} tool calls executed successfully.${C.reset}`);
|
|
1624
|
+
}
|
|
1625
|
+
} else {
|
|
1626
|
+
const errorPill = isColorDisabled()
|
|
1627
|
+
? '[x] Research failed:'
|
|
1628
|
+
: '\x1b[48;2;60;18;22m\x1b[38;2;255;120;120m [x] Research failed \x1b[0m';
|
|
1629
|
+
rows.push(` ${errorPill} ${C.red}${r.error || 'No answer generated'}${C.reset}`);
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
rows.push('');
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
rows.push(` ${C.dim}Tips: Use /sources to review citations • Type /session export to save report as markdown/HTML${C.reset}`);
|
|
1636
|
+
return rows;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1218
1639
|
export { _rawStdoutWrite as rawWrite, _rawConsoleLog as rawLog };
|
|
1640
|
+
|