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/commands.js
CHANGED
|
@@ -4,16 +4,21 @@ import { ensureYouTubeCookies, resetCookieCheck, getCookieStatus } from './youtu
|
|
|
4
4
|
import { AgentMemory } from './memory.js';
|
|
5
5
|
import {
|
|
6
6
|
C, UI_ICONS, printSolidPanel, formatTerminalMarkdown, formatMarkdownLines, randomFanName, createProgressRunner, wrapText, getFullWidth, getWelcomeHeroLines, sanitizeTerminalText,
|
|
7
|
-
formatRichCardLines, printRichCard, printRichStatusCard, formatStatusBadge, formatRichTable, getStringDisplayWidth
|
|
7
|
+
formatRichCardLines, printRichCard, printRichStatusCard, formatStatusBadge, formatRichTable, getStringDisplayWidth,
|
|
8
|
+
formatCareerTimelineGraphic, formatDebateMatrix, formatWorkerProgressMatrix, formatExecutiveFindings, getCategoryBadge
|
|
8
9
|
} from './ui.js';
|
|
10
|
+
import { promptInteractiveSuggestion } from './suggestionTui.js';
|
|
11
|
+
import { DebateOrchestrator } from './debate.js';
|
|
12
|
+
import { timelineData } from '../../src/data/timelineData.js';
|
|
9
13
|
import { COMMAND_NAMES, getCommandDetails, findCommandDefinition } from './commandRegistry.js';
|
|
10
14
|
import { THEMES, THEME_NAMES, ansiBackground, ansiForeground, getThemeName, setTheme } from './theme.js';
|
|
11
15
|
import { getGpuMetrics, formatProgressBar } from './gpuMetrics.js';
|
|
12
16
|
import { PACKAGE_NAME, PACKAGE_VERSION } from './version.js';
|
|
13
|
-
import { UpdateError, UpdateManager, UPDATE_CHANNELS } from './updateManager.js';
|
|
14
17
|
import { QUIZ_QUESTIONS, QUIZ_I18N, LETTER_LABELS, shuffleQuizQuestions } from './quizData.js';
|
|
15
18
|
import crypto from 'node:crypto';
|
|
19
|
+
import { isAbortError } from './errors.js';
|
|
16
20
|
import { featureCommandHandlers, aiNarration, languageHint } from './commandFeatures.js';
|
|
21
|
+
import { startWebChatServer, stopWebChatServer, getWebChatServerStatus, openBrowser } from '../webChatServer.js';
|
|
17
22
|
|
|
18
23
|
function levenshteinDistance(a, b) {
|
|
19
24
|
const matrix = Array.from({ length: a.length + 1 }, () => Array(b.length + 1).fill(0));
|
|
@@ -138,8 +143,74 @@ export const handlers = {
|
|
|
138
143
|
return 'HANDLED';
|
|
139
144
|
},
|
|
140
145
|
|
|
146
|
+
'/web': async (ctx) => {
|
|
147
|
+
const rawAction = (ctx.sub || 'start').toLowerCase();
|
|
148
|
+
const extraPort = Number(ctx.extra || (ctx.sub && /^\d+$/.test(ctx.sub) ? ctx.sub : null)) || 3300;
|
|
149
|
+
|
|
150
|
+
if (rawAction === 'stop' || rawAction === 'close') {
|
|
151
|
+
const stopped = await stopWebChatServer();
|
|
152
|
+
const msg = stopped
|
|
153
|
+
? ` ${C.emerald}[OK] Standalone web chatbot server stopped.${C.reset}`
|
|
154
|
+
: ` ${C.slate}Standalone web chatbot server was not running.${C.reset}`;
|
|
155
|
+
if (ctx.tuiPrompt?.addViewportLines) ctx.tuiPrompt.addViewportLines(msg);
|
|
156
|
+
else console.log(`\n${msg}\n`);
|
|
157
|
+
return 'HANDLED';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (rawAction === 'status' || rawAction === 'info') {
|
|
161
|
+
const status = getWebChatServerStatus();
|
|
162
|
+
const lines = [
|
|
163
|
+
`• Status: ${status.running ? `${C.emerald}Running${C.reset}` : `${C.slate}Stopped${C.reset}`}`,
|
|
164
|
+
`• URL: ${status.running ? `${C.cyberCyan}${status.url}${C.reset}` : `${C.dim}${status.url}${C.reset}`}`,
|
|
165
|
+
`• Port: ${status.port}`,
|
|
166
|
+
`• Provider: ${status.provider || 'lmstudio'}`,
|
|
167
|
+
`• Model: ${status.model || 'google/gemma-4-e4b'}`,
|
|
168
|
+
];
|
|
169
|
+
printRichCard({
|
|
170
|
+
title: 'Standalone Web Chatbot Status',
|
|
171
|
+
status: status.running ? 'ok' : 'info',
|
|
172
|
+
lines,
|
|
173
|
+
});
|
|
174
|
+
return 'HANDLED';
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (rawAction === 'restart') {
|
|
178
|
+
await stopWebChatServer();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const port = extraPort >= 1000 ? extraPort : 3300;
|
|
182
|
+
const res = await startWebChatServer({ port, agent: ctx.agent });
|
|
183
|
+
openBrowser(res.url);
|
|
184
|
+
|
|
185
|
+
const lines = [
|
|
186
|
+
`• Dedicated Web Chatbot started on ${C.bold}${C.cyberCyan}${res.url}${C.reset}`,
|
|
187
|
+
`• Running as an independent web application on Port ${res.port}.`,
|
|
188
|
+
`• Browser opened automatically.`,
|
|
189
|
+
`• To stop the web server, type ${C.cyberCyan}/web stop${C.reset}`,
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
printRichCard({
|
|
193
|
+
title: 'Standalone Web Chatbot Launched',
|
|
194
|
+
status: 'ok',
|
|
195
|
+
lines,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
return 'HANDLED';
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
'/web-chat': async (ctx) => handlers['/web'](ctx),
|
|
202
|
+
|
|
141
203
|
'/details': async (ctx) => {
|
|
142
|
-
|
|
204
|
+
if (typeof ctx.printQueryDetails === 'function') {
|
|
205
|
+
ctx.printQueryDetails([ctx.sub, ctx.extra].filter(Boolean).join(' '));
|
|
206
|
+
return 'HANDLED';
|
|
207
|
+
}
|
|
208
|
+
const { formatQueryDetails, parseDetailsRequest } = await import('./queryDetails.js');
|
|
209
|
+
const reference = [ctx.sub, ctx.extra].filter(Boolean).join(' ');
|
|
210
|
+
const request = parseDetailsRequest(reference);
|
|
211
|
+
const details = ctx.agent?.lastQueryDetails || ctx.agent?._lastQueryDetails || null;
|
|
212
|
+
const formatted = formatQueryDetails(details, request, ctx.agent?.session);
|
|
213
|
+
console.log(`\n${formatted}\n`);
|
|
143
214
|
return 'HANDLED';
|
|
144
215
|
},
|
|
145
216
|
|
|
@@ -219,6 +290,7 @@ export const handlers = {
|
|
|
219
290
|
ctx.setIsProcessing?.(true, `Subagent: ${task.slice(0, 24)}`);
|
|
220
291
|
try {
|
|
221
292
|
const result = await ctx.agent.runSubagent(task, {
|
|
293
|
+
signal: ctx.signal,
|
|
222
294
|
onProgress: event => {
|
|
223
295
|
if (event.type === 'iteration') {
|
|
224
296
|
console.log(` ${C.dim}[ITERATION ${event.iteration}/${event.maxIterations}]...${C.reset}`);
|
|
@@ -231,6 +303,23 @@ export const handlers = {
|
|
|
231
303
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
232
304
|
ctx.agent._lastSubagentResult = result;
|
|
233
305
|
|
|
306
|
+
ctx.recordQueryDiagnostics?.({
|
|
307
|
+
prompt: task,
|
|
308
|
+
answer: result.answer,
|
|
309
|
+
thinking: result.thinking || '',
|
|
310
|
+
tools: result.toolCalls?.map((tc, idx) => ({
|
|
311
|
+
name: tc.name || 'tool',
|
|
312
|
+
args: tc.args || {},
|
|
313
|
+
result: tc.result || { status: 'ok' },
|
|
314
|
+
duration: tc.duration || 0,
|
|
315
|
+
})) || [],
|
|
316
|
+
status: 'complete',
|
|
317
|
+
iterations: result.iterations || (result.toolCalls?.length ? 1 : 0),
|
|
318
|
+
startedAt: startTime,
|
|
319
|
+
completedAt: Date.now(),
|
|
320
|
+
durationMs: Date.now() - startTime,
|
|
321
|
+
});
|
|
322
|
+
|
|
234
323
|
const lines = [
|
|
235
324
|
`${C.bold}${C.emerald}[DONE] Subagent completed in ${elapsed}s with ${result.toolCalls.length} tool calls.${C.reset}`,
|
|
236
325
|
''
|
|
@@ -257,7 +346,9 @@ export const handlers = {
|
|
|
257
346
|
lines,
|
|
258
347
|
});
|
|
259
348
|
} catch (error) {
|
|
260
|
-
|
|
349
|
+
if (!isAbortError(error)) {
|
|
350
|
+
console.log(`\n ${C.red}[SUBAGENT ERROR] ${error.message}${C.reset}\n`);
|
|
351
|
+
}
|
|
261
352
|
} finally {
|
|
262
353
|
ctx.setIsProcessing?.(false);
|
|
263
354
|
}
|
|
@@ -356,6 +447,7 @@ export const handlers = {
|
|
|
356
447
|
ctx.setIsProcessing?.(true, `Research: ${question.slice(0, 24)}`);
|
|
357
448
|
try {
|
|
358
449
|
const result = await ctx.agent.runResearch(question, {
|
|
450
|
+
signal: ctx.signal,
|
|
359
451
|
onProgress: event => {
|
|
360
452
|
if (event.type === 'worker-start') console.log(` ${C.dim}▸ Worker started: ${event.label}${C.reset}`);
|
|
361
453
|
if (event.type === 'worker-complete') console.log(` ${C.emerald}[OK] Worker finished: ${event.label}${C.reset}`);
|
|
@@ -363,6 +455,24 @@ export const handlers = {
|
|
|
363
455
|
});
|
|
364
456
|
|
|
365
457
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
458
|
+
const allWorkerTools = (result.reports || []).flatMap(r => r.toolCalls || []).map((tc, idx) => ({
|
|
459
|
+
name: typeof tc === 'string' ? tc : (tc.name || 'tool'),
|
|
460
|
+
args: typeof tc === 'object' && tc.args ? tc.args : {},
|
|
461
|
+
result: typeof tc === 'object' && tc.result ? tc.result : { status: 'ok' },
|
|
462
|
+
duration: typeof tc === 'object' && tc.duration ? tc.duration : 0,
|
|
463
|
+
}));
|
|
464
|
+
|
|
465
|
+
ctx.recordQueryDiagnostics?.({
|
|
466
|
+
prompt: question,
|
|
467
|
+
answer: result.answer,
|
|
468
|
+
tools: allWorkerTools,
|
|
469
|
+
status: 'complete',
|
|
470
|
+
iterations: (result.reports || []).length || 1,
|
|
471
|
+
startedAt: startTime,
|
|
472
|
+
completedAt: Date.now(),
|
|
473
|
+
durationMs: Date.now() - startTime,
|
|
474
|
+
});
|
|
475
|
+
|
|
366
476
|
const lines = [
|
|
367
477
|
`${C.bold}${C.emerald}[DONE] Research synthesis completed in ${elapsed}s across 3 workers.${C.reset}`,
|
|
368
478
|
'',
|
|
@@ -378,7 +488,9 @@ export const handlers = {
|
|
|
378
488
|
lines
|
|
379
489
|
});
|
|
380
490
|
} catch (error) {
|
|
381
|
-
|
|
491
|
+
if (!isAbortError(error)) {
|
|
492
|
+
console.log(`\n ${C.red}[RESEARCH ERROR] ${error.message}${C.reset}\n`);
|
|
493
|
+
}
|
|
382
494
|
} finally {
|
|
383
495
|
ctx.setIsProcessing?.(false);
|
|
384
496
|
}
|
|
@@ -416,10 +528,28 @@ export const handlers = {
|
|
|
416
528
|
const startTime = Date.now();
|
|
417
529
|
ctx.setIsProcessing?.(true, `Verifying: ${claim.slice(0, 24)}`);
|
|
418
530
|
try {
|
|
419
|
-
const result = await ctx.agent.runResearch(claim, { mode: 'verify' });
|
|
531
|
+
const result = await ctx.agent.runResearch(claim, { mode: 'verify', signal: ctx.signal });
|
|
420
532
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
421
533
|
const answerStr = String(result.answer || '');
|
|
422
534
|
|
|
535
|
+
const allWorkerTools = (result.reports || []).flatMap(r => r.toolCalls || []).map((tc, idx) => ({
|
|
536
|
+
name: typeof tc === 'string' ? tc : (tc.name || 'tool'),
|
|
537
|
+
args: typeof tc === 'object' && tc.args ? tc.args : {},
|
|
538
|
+
result: typeof tc === 'object' && tc.result ? tc.result : { status: 'ok' },
|
|
539
|
+
duration: typeof tc === 'object' && tc.duration ? tc.duration : 0,
|
|
540
|
+
}));
|
|
541
|
+
|
|
542
|
+
ctx.recordQueryDiagnostics?.({
|
|
543
|
+
prompt: `/verify ${claim}`,
|
|
544
|
+
answer: answerStr,
|
|
545
|
+
tools: allWorkerTools,
|
|
546
|
+
status: 'complete',
|
|
547
|
+
iterations: (result.reports || []).length || 1,
|
|
548
|
+
startedAt: startTime,
|
|
549
|
+
completedAt: Date.now(),
|
|
550
|
+
durationMs: Date.now() - startTime,
|
|
551
|
+
});
|
|
552
|
+
|
|
423
553
|
let verdictBadge = `${C.amber}[UNVERIFIED / AMBIGUOUS]`;
|
|
424
554
|
if (/VERIFIED|จริง|ถูกต้อง|ยืนยันแล้ว|CONFIRMED/i.test(answerStr) && !/UNVERIFIED|FALSE|เท็จ|ไม่จริง/i.test(answerStr.slice(0, 80))) {
|
|
425
555
|
verdictBadge = `${C.emerald}${C.bold}[VERIFIED / FACTUAL]${C.reset}`;
|
|
@@ -444,7 +574,9 @@ export const handlers = {
|
|
|
444
574
|
lines
|
|
445
575
|
});
|
|
446
576
|
} catch (error) {
|
|
447
|
-
|
|
577
|
+
if (!isAbortError(error)) {
|
|
578
|
+
console.log(`\n ${C.red}[VERIFY ERROR] ${error.message}${C.reset}\n`);
|
|
579
|
+
}
|
|
448
580
|
} finally {
|
|
449
581
|
ctx.setIsProcessing?.(false);
|
|
450
582
|
}
|
|
@@ -452,11 +584,152 @@ export const handlers = {
|
|
|
452
584
|
},
|
|
453
585
|
|
|
454
586
|
'/sources': async (ctx) => {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
587
|
+
if (ctx.agent?.lastCitations?.length > 0) {
|
|
588
|
+
const lines = ctx.agent.lastCitations.map(c => {
|
|
589
|
+
const meta = [c.category, c.year, c.tool].filter(Boolean).join(' • ');
|
|
590
|
+
const urlStr = c.url ? ` ${C.cyberCyan}${c.url}${C.reset}` : '';
|
|
591
|
+
return `${C.gold}[${c.id}]${C.reset} ${C.bold}${c.title}${C.reset} ${C.dim}(${meta})${C.reset}${urlStr}`;
|
|
592
|
+
});
|
|
593
|
+
printSolidPanel({
|
|
594
|
+
title: `Grounded Sources & Citations • ${ctx.agent.lastCitations.length} sources`,
|
|
595
|
+
lines
|
|
596
|
+
});
|
|
597
|
+
return 'HANDLED';
|
|
598
|
+
}
|
|
599
|
+
return handlers['/research']({ ...ctx, sub: 'sources' });
|
|
600
|
+
},
|
|
601
|
+
|
|
602
|
+
'/debate': async (ctx) => {
|
|
603
|
+
const rawAction = (ctx.sub || '').trim();
|
|
604
|
+
const extra = (ctx.extra || '').trim();
|
|
605
|
+
const fullQuery = `${rawAction} ${extra}`.trim();
|
|
606
|
+
|
|
607
|
+
if (!fullQuery || fullQuery === 'help') {
|
|
608
|
+
console.log(`\n ${C.bold}Usage:${C.reset} /debate <topic or claim> | /debate status | /debate last\n`);
|
|
609
|
+
return 'HANDLED';
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
if (rawAction.toLowerCase() === 'status') {
|
|
613
|
+
const status = ctx.agent?.debateOrchestrator?.getStatus?.() || { state: 'idle' };
|
|
614
|
+
printRichCard({
|
|
615
|
+
title: `Debate Status • ${status.state.toUpperCase()}`,
|
|
616
|
+
status: status.state === 'running' ? 'autostart' : 'info',
|
|
617
|
+
lines: [
|
|
618
|
+
status.state === 'running' ? `Active Topic: ${status.topic}` : 'No debate job is currently running.',
|
|
619
|
+
],
|
|
620
|
+
});
|
|
621
|
+
return 'HANDLED';
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
if (rawAction.toLowerCase() === 'last') {
|
|
625
|
+
const last = ctx.agent?.debateOrchestrator?.getStatus?.()?.lastResult;
|
|
626
|
+
if (!last) {
|
|
627
|
+
console.log(`\n ${C.amber}No previous debate results recorded.${C.reset}\n`);
|
|
628
|
+
return 'HANDLED';
|
|
629
|
+
}
|
|
630
|
+
const lines = formatDebateMatrix(last, getFullWidth());
|
|
631
|
+
console.log(`\n${lines.join('\n')}\n`);
|
|
632
|
+
return 'HANDLED';
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
if (rawAction.toLowerCase() === 'cancel' || rawAction.toLowerCase() === 'abort') {
|
|
636
|
+
const cancelled = ctx.agent?.debateOrchestrator?.cancel?.();
|
|
637
|
+
console.log(`\n ${cancelled ? C.emerald + '[OK] Cancelled active debate job.' : C.amber + 'No active debate job to cancel.'}${C.reset}\n`);
|
|
638
|
+
return 'HANDLED';
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
const debateOrchestrator = ctx.agent?.debateOrchestrator || new DebateOrchestrator({
|
|
642
|
+
client: ctx.agent?.client || ctx.agent?.llmClient,
|
|
643
|
+
executeTool: (name, args) => ctx.agent?.executeTool?.(name, args) || executeTool(name, args),
|
|
459
644
|
});
|
|
645
|
+
if (ctx.agent) ctx.agent.debateOrchestrator = debateOrchestrator;
|
|
646
|
+
|
|
647
|
+
printRichCard({
|
|
648
|
+
title: 'Initiating Adversarial Fact Debate',
|
|
649
|
+
status: 'autostart',
|
|
650
|
+
lines: [
|
|
651
|
+
`• Topic / Claim: "${fullQuery}"`,
|
|
652
|
+
'• Dispatching Advocate and Skeptic subagents with verified sources...',
|
|
653
|
+
],
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
const startTime = Date.now();
|
|
657
|
+
ctx.setIsProcessing?.(true, `Debating: ${fullQuery.slice(0, 24)}`);
|
|
658
|
+
|
|
659
|
+
try {
|
|
660
|
+
const result = await debateOrchestrator.run(fullQuery, {
|
|
661
|
+
signal: ctx.signal,
|
|
662
|
+
onProgress: event => {
|
|
663
|
+
if (event.type === 'worker-start') {
|
|
664
|
+
ctx.setAgentState?.(`Debating • ${event.id === 'advocate' ? 'Advocate' : 'Critic'}`);
|
|
665
|
+
if (ctx.tuiPrompt?.addViewportLines) {
|
|
666
|
+
ctx.tuiPrompt.addViewportLines(` ${C.cyberCyan}▸ Debate Worker Started:${C.reset} ${C.bold}${event.label}${C.reset}`);
|
|
667
|
+
}
|
|
668
|
+
} else if (event.type === 'synthesizing') {
|
|
669
|
+
ctx.setAgentState?.('Synthesizing Verdict…');
|
|
670
|
+
if (ctx.tuiPrompt?.addViewportLines) {
|
|
671
|
+
ctx.tuiPrompt.addViewportLines(` ${C.gold}✦ Synthesizing Neutral Judge Verdict...${C.reset}`);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
},
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
const lines = formatDebateMatrix(result, getFullWidth());
|
|
678
|
+
if (ctx.tuiPrompt?.addViewportLines) {
|
|
679
|
+
ctx.tuiPrompt.addViewportLines(lines);
|
|
680
|
+
} else {
|
|
681
|
+
console.log(`\n${lines.join('\n')}\n`);
|
|
682
|
+
}
|
|
683
|
+
} catch (error) {
|
|
684
|
+
if (!isAbortError(error)) {
|
|
685
|
+
if (ctx.tuiPrompt?.addViewportLines) {
|
|
686
|
+
ctx.tuiPrompt.addViewportLines(` ${C.red}[DEBATE ERROR] ${error.message}${C.reset}`);
|
|
687
|
+
} else {
|
|
688
|
+
console.log(`\n ${C.red}[DEBATE ERROR] ${error.message}${C.reset}\n`);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
} finally {
|
|
692
|
+
ctx.setIsProcessing?.(false);
|
|
693
|
+
}
|
|
694
|
+
return 'HANDLED';
|
|
695
|
+
},
|
|
696
|
+
|
|
697
|
+
'/timeline': async (ctx) => {
|
|
698
|
+
const rawFilter = `${ctx.sub || ''} ${ctx.extra || ''}`.trim().toLowerCase();
|
|
699
|
+
let items = [...timelineData];
|
|
700
|
+
|
|
701
|
+
if (rawFilter) {
|
|
702
|
+
if (/^\d{4}$/.test(rawFilter)) {
|
|
703
|
+
items = items.filter(t => t.year === rawFilter);
|
|
704
|
+
} else if (/^\d{4}-\d{4}$/.test(rawFilter)) {
|
|
705
|
+
const [startY, endY] = rawFilter.split('-').map(Number);
|
|
706
|
+
items = items.filter(t => {
|
|
707
|
+
const y = Number(t.year);
|
|
708
|
+
return !isNaN(y) && y >= startY && y <= endY;
|
|
709
|
+
});
|
|
710
|
+
} else {
|
|
711
|
+
items = items.filter(t =>
|
|
712
|
+
(t.era && t.era.toLowerCase().includes(rawFilter)) ||
|
|
713
|
+
(t.category && t.category.toLowerCase().includes(rawFilter)) ||
|
|
714
|
+
(t.title && t.title.toLowerCase().includes(rawFilter)) ||
|
|
715
|
+
(t.summary && t.summary.toLowerCase().includes(rawFilter))
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
if (items.length === 0) {
|
|
721
|
+
const msg = ` ${C.amber}No career timeline milestones found matching "${rawFilter}".${C.reset}`;
|
|
722
|
+
if (ctx.tuiPrompt?.addViewportLines) ctx.tuiPrompt.addViewportLines(msg);
|
|
723
|
+
else console.log(`\n${msg}\n`);
|
|
724
|
+
return 'HANDLED';
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const lines = formatCareerTimelineGraphic(items, getFullWidth());
|
|
728
|
+
if (ctx.tuiPrompt?.addViewportLines) {
|
|
729
|
+
ctx.tuiPrompt.addViewportLines(lines);
|
|
730
|
+
} else {
|
|
731
|
+
console.log(`\n${lines.join('\n')}\n`);
|
|
732
|
+
}
|
|
460
733
|
return 'HANDLED';
|
|
461
734
|
},
|
|
462
735
|
|
|
@@ -480,6 +753,7 @@ export const handlers = {
|
|
|
480
753
|
ctx.setIsProcessing?.(true, `Suggestions: ${targets.slice(0, 20)}`);
|
|
481
754
|
try {
|
|
482
755
|
const batchResult = await ctx.agent.runSuggestionBatch(targets, {
|
|
756
|
+
signal: ctx.signal,
|
|
483
757
|
onProgress: event => {
|
|
484
758
|
if (event.type === 'worker-start') {
|
|
485
759
|
console.log(` ${C.cyberCyan}▸ Worker ${event.index} Started:${C.reset} ${C.bold}${event.label}${C.reset} — ${C.dim}${event.question}${C.reset}`);
|
|
@@ -501,36 +775,41 @@ export const handlers = {
|
|
|
501
775
|
],
|
|
502
776
|
});
|
|
503
777
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
778
|
+
const allTools = (batchResult.results || []).flatMap(r => r.toolCalls || []).map(tc => ({
|
|
779
|
+
name: typeof tc === 'string' ? tc : (tc.name || 'tool'),
|
|
780
|
+
args: typeof tc === 'object' && tc.args ? tc.args : {},
|
|
781
|
+
result: typeof tc === 'object' && tc.result ? tc.result : { status: 'ok' },
|
|
782
|
+
duration: typeof tc === 'object' && tc.duration ? tc.duration : 0,
|
|
783
|
+
}));
|
|
784
|
+
|
|
785
|
+
const combinedAnswers = (batchResult.results || [])
|
|
786
|
+
.filter(r => Boolean(r.answer))
|
|
787
|
+
.map(r => `### [Worker ${r.index}] ${r.category} • ${r.question}\n${r.answer}`)
|
|
788
|
+
.join('\n\n') || '';
|
|
789
|
+
|
|
790
|
+
ctx.recordQueryDiagnostics?.({
|
|
791
|
+
prompt: `/suggestion run ${targets}`,
|
|
792
|
+
answer: combinedAnswers,
|
|
793
|
+
tools: allTools,
|
|
794
|
+
status: batchResult.successfulCount > 0 ? 'complete' : 'error',
|
|
795
|
+
iterations: batchResult.tasksCount || 1,
|
|
796
|
+
startedAt: startTime,
|
|
797
|
+
completedAt: Date.now(),
|
|
798
|
+
durationMs: Date.now() - startTime,
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
const findingLines = formatExecutiveFindings({ batchResult, termWidth: getFullWidth() });
|
|
802
|
+
for (const line of findingLines) {
|
|
803
|
+
console.log(line);
|
|
527
804
|
}
|
|
528
805
|
} catch (err) {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
806
|
+
if (!isAbortError(err)) {
|
|
807
|
+
printRichCard({
|
|
808
|
+
title: 'Batch Subagent Error',
|
|
809
|
+
status: 'error',
|
|
810
|
+
lines: [err.message],
|
|
811
|
+
});
|
|
812
|
+
}
|
|
534
813
|
} finally {
|
|
535
814
|
ctx.setIsProcessing?.(false);
|
|
536
815
|
}
|
|
@@ -558,14 +837,42 @@ export const handlers = {
|
|
|
558
837
|
topic: topicName,
|
|
559
838
|
limit: 5,
|
|
560
839
|
});
|
|
840
|
+
ctx.setIsProcessing?.(false);
|
|
561
841
|
|
|
842
|
+
|
|
843
|
+
const isInteractiveTty = Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.KIKU_PLAIN && ctx.readInput);
|
|
844
|
+
|
|
845
|
+
if (isInteractiveTty && !isTopic && (rawAction === 'list' || !rawAction)) {
|
|
846
|
+
const selected = await promptInteractiveSuggestion(suggestions, {
|
|
847
|
+
stdin: process.stdin,
|
|
848
|
+
stdout: process.stdout,
|
|
849
|
+
signal: ctx.signal,
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
if (selected.action === 'run' && selected.targets) {
|
|
853
|
+
return handlers['/suggestion']({ ...ctx, sub: 'run', extra: selected.targets });
|
|
854
|
+
}
|
|
855
|
+
if (selected.action === 'refresh') {
|
|
856
|
+
return handlers['/suggestion']({ ...ctx, sub: 'list', extra: '' });
|
|
857
|
+
}
|
|
858
|
+
if (selected.action === 'cancel') {
|
|
859
|
+
return 'HANDLED';
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
|
|
562
864
|
const cardLines = [
|
|
563
865
|
`${C.dim}Explore exciting Ju Jingyi topics with concurrent subagents:${C.reset}`,
|
|
564
866
|
'',
|
|
565
|
-
...suggestions.flatMap((s) =>
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
867
|
+
...suggestions.flatMap((s, idx) => {
|
|
868
|
+
const badge = getCategoryBadge(s.category);
|
|
869
|
+
return [
|
|
870
|
+
` ${C.bold}${C.gold}[${s.id}]${C.reset} ${badge.color}[${badge.icon} ${badge.label}]${C.reset} ${C.bold}${C.white}${s.question}${C.reset}`,
|
|
871
|
+
` ${C.dim}↳ ${s.description}${C.reset}`,
|
|
872
|
+
` ${C.slate}Tools: ${(s.tools || []).join(', ')} • Est: ~${s.estimatedSeconds || 2}s • Depth: ${s.depth || 'Standard'}${C.reset}`,
|
|
873
|
+
...(idx < suggestions.length - 1 ? [''] : []),
|
|
874
|
+
];
|
|
875
|
+
}),
|
|
569
876
|
'',
|
|
570
877
|
`${C.bold}${C.roseGlow}Quick Execution Tips:${C.reset}`,
|
|
571
878
|
` • Run one task: ${C.white}/suggestion run 1${C.reset}`,
|
|
@@ -927,19 +1234,22 @@ export const handlers = {
|
|
|
927
1234
|
let exported;
|
|
928
1235
|
if (format === 'json') {
|
|
929
1236
|
exported = await agent.session.exportToJson();
|
|
1237
|
+
} else if (format === 'html' || format === 'web') {
|
|
1238
|
+
exported = await agent.session.exportToHtml();
|
|
930
1239
|
} else if (format === 'text' || format === 'txt') {
|
|
931
1240
|
exported = await agent.session.exportToText();
|
|
932
1241
|
} else {
|
|
933
1242
|
exported = await agent.session.exportToMarkdown();
|
|
934
1243
|
}
|
|
935
1244
|
|
|
1245
|
+
const fmt = (exported?.format || (format === 'json' ? 'JSON' : format === 'html' || format === 'web' ? 'HTML' : format === 'text' || format === 'txt' ? 'TEXT' : 'MARKDOWN')).toUpperCase();
|
|
936
1246
|
printRichCard({
|
|
937
1247
|
title: 'Session Exported Successfully',
|
|
938
1248
|
status: 'ok',
|
|
939
1249
|
lines: [
|
|
940
|
-
`• Format: ${
|
|
941
|
-
`• File: ${exported
|
|
942
|
-
`• Size: ${(exported
|
|
1250
|
+
`• Format: ${fmt}`,
|
|
1251
|
+
`• File: ${exported?.filePath || 'Export generated'}`,
|
|
1252
|
+
`• Size: ${(exported?.size || 0).toLocaleString()} bytes`,
|
|
943
1253
|
],
|
|
944
1254
|
});
|
|
945
1255
|
return 'HANDLED';
|
|
@@ -1048,15 +1358,7 @@ export const handlers = {
|
|
|
1048
1358
|
ctx.tuiPrompt.render();
|
|
1049
1359
|
}
|
|
1050
1360
|
|
|
1051
|
-
|
|
1052
|
-
title: 'Theme Updated',
|
|
1053
|
-
lines: [
|
|
1054
|
-
`${C.emerald}[OK] Active theme: ${C.bold}${theme.label} (${requested})${C.reset}`,
|
|
1055
|
-
`${C.dim}${theme.description}${C.reset}`,
|
|
1056
|
-
`${C.sakura}Primary${C.reset} ${C.roseGlow}Accent${C.reset} ${C.cyberCyan}Info${C.reset} ${C.emerald}Success${C.reset} ${C.amber}Warning${C.reset} ${C.red}Error${C.reset}`,
|
|
1057
|
-
`${C.dim}Saved for future Kiku Agent sessions.${C.reset}`,
|
|
1058
|
-
],
|
|
1059
|
-
});
|
|
1361
|
+
console.log(`\n ${C.sakura}◆${C.reset} Active theme: ${C.bold}${theme.label}${C.reset} ${C.dim}(${requested})${C.reset}\n`);
|
|
1060
1362
|
return 'HANDLED';
|
|
1061
1363
|
},
|
|
1062
1364
|
|
|
@@ -1368,17 +1670,12 @@ export const handlers = {
|
|
|
1368
1670
|
},
|
|
1369
1671
|
|
|
1370
1672
|
'/save': async (ctx) => {
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
console.log(`\n ${C.emerald}[OK] Exported.${C.reset} ${C.white}${exported.filePath}${C.reset}\n`);
|
|
1374
|
-
} catch (err) {
|
|
1375
|
-
console.log(`\n ${C.red}[SAVE ERROR] ${err.message || String(err)}${C.reset}\n`);
|
|
1376
|
-
}
|
|
1377
|
-
return 'HANDLED';
|
|
1673
|
+
const fmt = ctx.sub || ctx.extra || 'markdown';
|
|
1674
|
+
return handlers['/session']({ ...ctx, sub: 'export', extra: fmt });
|
|
1378
1675
|
},
|
|
1379
1676
|
|
|
1380
1677
|
'/provider': async (ctx) => {
|
|
1381
|
-
const { CLOUD_PROVIDERS, getProvider, getRecommendedModels } = await import('./config.js');
|
|
1678
|
+
const { CLOUD_PROVIDERS, getProvider, getRecommendedModels, isProviderKeyPersistenceEnabled } = await import('./config.js');
|
|
1382
1679
|
const action = (ctx.sub || 'status').toLowerCase();
|
|
1383
1680
|
const parts = ctx.parts || [];
|
|
1384
1681
|
|
|
@@ -1574,7 +1871,10 @@ export const handlers = {
|
|
|
1574
1871
|
const masked = newKey.length > 8
|
|
1575
1872
|
? `${newKey.slice(0, 4)}...${newKey.slice(-4)}`
|
|
1576
1873
|
: '****';
|
|
1577
|
-
|
|
1874
|
+
const persistenceLabel = isProviderKeyPersistenceEnabled()
|
|
1875
|
+
? 'saved with encrypted persistence'
|
|
1876
|
+
: 'saved in memory only (set KIKU_PROVIDER_KEY_ENCRYPTION_KEY to persist)';
|
|
1877
|
+
console.log(`\n ${C.emerald}[OK] API key ${persistenceLabel} for ${targetProvider}${C.reset} (${masked})\n`);
|
|
1578
1878
|
return 'HANDLED';
|
|
1579
1879
|
}
|
|
1580
1880
|
|
|
@@ -1653,12 +1953,25 @@ export const handlers = {
|
|
|
1653
1953
|
: await ctx.client.checkConnection();
|
|
1654
1954
|
|
|
1655
1955
|
if (action === 'list') {
|
|
1656
|
-
const
|
|
1956
|
+
const activeLoaded = liveCheck.activeLoadedModel;
|
|
1957
|
+
const serverModels = (liveCheck.models || []).slice(0, 40).map(id => {
|
|
1958
|
+
const isCurrent = id === ctx.client.model;
|
|
1959
|
+
const isLoaded = id === activeLoaded || (liveCheck.loadedModels && liveCheck.loadedModels.includes(id));
|
|
1960
|
+
const badge = isCurrent ? `${C.gold}[x]${C.reset}` : `${C.dim}[ ]${C.reset}`;
|
|
1961
|
+
const loadTag = isLoaded ? ` ${C.emerald}(Loaded in VRAM)${C.reset}` : '';
|
|
1962
|
+
return `${badge} ${C.white}${id}${C.reset}${loadTag}`;
|
|
1963
|
+
});
|
|
1657
1964
|
const recs = getRecommendedModels(ctx.client.provider);
|
|
1658
1965
|
const recLines = recs.length > 0
|
|
1659
1966
|
? [
|
|
1660
|
-
`${C.bold}${C.lavender}Recommended Active Models:${C.reset}`,
|
|
1661
|
-
...recs.map(m =>
|
|
1967
|
+
`${C.bold}${C.lavender}Recommended Active Models / Quantizations:${C.reset}`,
|
|
1968
|
+
...recs.map(m => {
|
|
1969
|
+
const isCurrent = m.id === ctx.client.model || (ctx.client.model && ctx.client.model.includes(m.id.replace('google/', '')));
|
|
1970
|
+
const isLoaded = activeLoaded && activeLoaded.includes(m.id.replace('google/', ''));
|
|
1971
|
+
const marker = isCurrent ? `${C.gold}[x]${C.reset}` : `${C.dim}[ ]${C.reset}`;
|
|
1972
|
+
const loadTag = isLoaded ? ` ${C.emerald}● VRAM Ready${C.reset}` : '';
|
|
1973
|
+
return ` ${marker} ${C.white}${m.id.padEnd(28)}${C.reset} ${C.dim}(${m.cost} • ${m.tier})${C.reset}${loadTag}`;
|
|
1974
|
+
}),
|
|
1662
1975
|
''
|
|
1663
1976
|
]
|
|
1664
1977
|
: [];
|
|
@@ -1670,7 +1983,7 @@ export const handlers = {
|
|
|
1670
1983
|
`${C.bold}${C.lavender}Reported by Server:${C.reset}`,
|
|
1671
1984
|
...(serverModels.length ? serverModels.map(s => ` ${s}`) : [` ${C.dim}No live model list reported by ${providerName}.${C.reset}`]),
|
|
1672
1985
|
'',
|
|
1673
|
-
`${C.dim}Select model: /model use <model_id> or /model <
|
|
1986
|
+
`${C.dim}Select model: /model use <model_id> or /model use <Q8_0|Q6_K|Q4_K_M>${C.reset}`
|
|
1674
1987
|
],
|
|
1675
1988
|
});
|
|
1676
1989
|
return 'HANDLED';
|
|
@@ -1683,14 +1996,16 @@ export const handlers = {
|
|
|
1683
1996
|
try {
|
|
1684
1997
|
const lowerTarget = targetModel.toLowerCase();
|
|
1685
1998
|
|
|
1686
|
-
|
|
1687
1999
|
if (CLOUD_PROVIDERS[lowerTarget]) {
|
|
1688
2000
|
return await handlers['/provider']({ ...ctx, sub: 'use', extra: lowerTarget, parts: ['/provider', 'use', lowerTarget] });
|
|
1689
2001
|
}
|
|
1690
2002
|
|
|
1691
|
-
|
|
1692
2003
|
let matchedProvider = null;
|
|
1693
|
-
if (
|
|
2004
|
+
if (
|
|
2005
|
+
lowerTarget.includes('gemma') ||
|
|
2006
|
+
lowerTarget === 'google/gemma-4-e4b' ||
|
|
2007
|
+
/^(q[0-9]|8bit|6bit|4bit|fp16)/i.test(lowerTarget)
|
|
2008
|
+
) {
|
|
1694
2009
|
matchedProvider = 'lmstudio';
|
|
1695
2010
|
} else {
|
|
1696
2011
|
for (const [pId, pDef] of Object.entries(CLOUD_PROVIDERS)) {
|
|
@@ -1708,9 +2023,19 @@ export const handlers = {
|
|
|
1708
2023
|
|
|
1709
2024
|
if (ctx.modelManager) {
|
|
1710
2025
|
const selected = ctx.modelManager.select(targetModel, liveCheck.models || []);
|
|
2026
|
+
if (ctx.tuiPrompt) {
|
|
2027
|
+
ctx.tuiPrompt.modelName = selected;
|
|
2028
|
+
ctx.tuiPrompt.isConnected = true;
|
|
2029
|
+
ctx.tuiPrompt.render();
|
|
2030
|
+
}
|
|
1711
2031
|
console.log(`\n ${C.emerald}[OK] Active model changed to ${selected}.${C.reset}\n`);
|
|
1712
2032
|
} else {
|
|
1713
2033
|
ctx.client.setModel(targetModel);
|
|
2034
|
+
if (ctx.tuiPrompt) {
|
|
2035
|
+
ctx.tuiPrompt.modelName = targetModel;
|
|
2036
|
+
ctx.tuiPrompt.isConnected = true;
|
|
2037
|
+
ctx.tuiPrompt.render();
|
|
2038
|
+
}
|
|
1714
2039
|
console.log(`\n ${C.emerald}[OK] Active model changed to ${targetModel}.${C.reset}\n`);
|
|
1715
2040
|
}
|
|
1716
2041
|
} catch (error) {
|
|
@@ -2001,17 +2326,122 @@ export const handlers = {
|
|
|
2001
2326
|
return 'HANDLED';
|
|
2002
2327
|
},
|
|
2003
2328
|
|
|
2329
|
+
'/profile': async (ctx) => {
|
|
2330
|
+
const { listProfiles, getProfile, setActiveProfile, createOrUpdateProfile, deleteProfile, getActiveProfile } = await import('./profiles.js');
|
|
2331
|
+
const action = (ctx.sub || 'list').toLowerCase();
|
|
2332
|
+
const parts = ctx.parts || [];
|
|
2333
|
+
|
|
2334
|
+
if (action === 'list' || (action === 'show' && !ctx.extra)) {
|
|
2335
|
+
const profiles = listProfiles();
|
|
2336
|
+
const lines = profiles.map(p => {
|
|
2337
|
+
const marker = p.isActive ? `${C.emerald}* [ACTIVE]${C.reset}` : ` [ ]`;
|
|
2338
|
+
const nameCol = `${C.bold}${C.cyberCyan}${p.name.padEnd(16)}${C.reset}`;
|
|
2339
|
+
const provCol = `${C.white}${(p.provider || 'lmstudio').padEnd(12)}${C.reset}`;
|
|
2340
|
+
const modelCol = `${C.lavender}${(p.model || '').padEnd(26)}${C.reset}`;
|
|
2341
|
+
const thinkCol = p.thinking === 'show' ? `${C.emerald}think:on${C.reset}` : `${C.dim}think:off${C.reset}`;
|
|
2342
|
+
return `${marker} ${nameCol} ${provCol} ${modelCol} ${thinkCol}`;
|
|
2343
|
+
});
|
|
2344
|
+
|
|
2345
|
+
printSolidPanel({
|
|
2346
|
+
title: `Configuration Profiles (${profiles.length})`,
|
|
2347
|
+
lines: [
|
|
2348
|
+
...lines,
|
|
2349
|
+
'',
|
|
2350
|
+
`${C.dim}Usage: /profile use <name> | /profile show <name> | /profile save <name>${C.reset}`
|
|
2351
|
+
],
|
|
2352
|
+
});
|
|
2353
|
+
return 'HANDLED';
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
if (action === 'use' || action === 'switch') {
|
|
2357
|
+
const targetName = (parts[2] || ctx.extra || '').trim();
|
|
2358
|
+
if (!targetName) {
|
|
2359
|
+
console.log(`\n ${C.amber}Usage: /profile use <profile_name>${C.reset}\n`);
|
|
2360
|
+
return 'HANDLED';
|
|
2361
|
+
}
|
|
2362
|
+
try {
|
|
2363
|
+
const profile = setActiveProfile(targetName);
|
|
2364
|
+
if (ctx.client && profile.provider) {
|
|
2365
|
+
ctx.client.switchProvider(profile.provider, { model: profile.model });
|
|
2366
|
+
}
|
|
2367
|
+
if (ctx.agent) {
|
|
2368
|
+
if (profile.thinking) ctx.agent.session.thinkingMode = profile.thinking;
|
|
2369
|
+
}
|
|
2370
|
+
if (ctx.tuiPrompt) {
|
|
2371
|
+
ctx.tuiPrompt.modelName = profile.model;
|
|
2372
|
+
ctx.tuiPrompt.providerName = profile.provider;
|
|
2373
|
+
ctx.tuiPrompt.render();
|
|
2374
|
+
}
|
|
2375
|
+
console.log(`\n ${C.emerald}[OK] Switched to profile "${profile.name}" (${profile.provider} / ${profile.model})${C.reset}\n`);
|
|
2376
|
+
} catch (err) {
|
|
2377
|
+
console.log(`\n ${C.red}[PROFILE ERROR] ${err.message}${C.reset}\n`);
|
|
2378
|
+
}
|
|
2379
|
+
return 'HANDLED';
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
if (action === 'save') {
|
|
2383
|
+
const targetName = (parts[2] || ctx.extra || '').trim();
|
|
2384
|
+
if (!targetName) {
|
|
2385
|
+
console.log(`\n ${C.amber}Usage: /profile save <profile_name>${C.reset}\n`);
|
|
2386
|
+
return 'HANDLED';
|
|
2387
|
+
}
|
|
2388
|
+
try {
|
|
2389
|
+
const currentProvider = ctx.client?.provider || 'lmstudio';
|
|
2390
|
+
const currentModel = ctx.client?.model || 'google/gemma-4-e4b';
|
|
2391
|
+
const currentThinking = ctx.agent?.session?.thinkingMode || 'show';
|
|
2392
|
+
const saved = createOrUpdateProfile(targetName, {
|
|
2393
|
+
provider: currentProvider,
|
|
2394
|
+
model: currentModel,
|
|
2395
|
+
thinking: currentThinking,
|
|
2396
|
+
description: `Custom profile created from active session`
|
|
2397
|
+
});
|
|
2398
|
+
console.log(`\n ${C.emerald}[OK] Saved profile "${saved.name}" (${saved.provider} / ${saved.model})${C.reset}\n`);
|
|
2399
|
+
} catch (err) {
|
|
2400
|
+
console.log(`\n ${C.red}[PROFILE ERROR] ${err.message}${C.reset}\n`);
|
|
2401
|
+
}
|
|
2402
|
+
return 'HANDLED';
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
if (action === 'delete' || action === 'del') {
|
|
2406
|
+
const targetName = (parts[2] || ctx.extra || '').trim();
|
|
2407
|
+
if (!targetName) {
|
|
2408
|
+
console.log(`\n ${C.amber}Usage: /profile delete <profile_name>${C.reset}\n`);
|
|
2409
|
+
return 'HANDLED';
|
|
2410
|
+
}
|
|
2411
|
+
try {
|
|
2412
|
+
deleteProfile(targetName);
|
|
2413
|
+
console.log(`\n ${C.emerald}[OK] Deleted profile "${targetName}".${C.reset}\n`);
|
|
2414
|
+
} catch (err) {
|
|
2415
|
+
console.log(`\n ${C.red}[PROFILE ERROR] ${err.message}${C.reset}\n`);
|
|
2416
|
+
}
|
|
2417
|
+
return 'HANDLED';
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
return 'HANDLED';
|
|
2421
|
+
},
|
|
2422
|
+
|
|
2004
2423
|
'/config': async (ctx) => {
|
|
2005
|
-
const {
|
|
2424
|
+
const { getActiveProfile } = await import('./profiles.js');
|
|
2425
|
+
if (ctx.sub === 'list' || ctx.sub === 'profiles') {
|
|
2426
|
+
return handlers['/profile'](ctx);
|
|
2427
|
+
}
|
|
2428
|
+
if (ctx.sub === 'use') {
|
|
2429
|
+
return handlers['/profile'](ctx);
|
|
2430
|
+
}
|
|
2431
|
+
const activeProf = getActiveProfile();
|
|
2006
2432
|
printSolidPanel({
|
|
2007
2433
|
title: `Configuration`,
|
|
2008
2434
|
lines: [
|
|
2009
|
-
`${C.gold}
|
|
2435
|
+
`${C.gold}Profile:${C.reset} ${C.bold}${C.emerald}${activeProf.name}${C.reset} ${C.dim}(${activeProf.description || ''})${C.reset}`,
|
|
2436
|
+
`${C.gold}Provider:${C.reset} ${C.white}${ctx.client.providerName || ctx.client.provider || 'LM Studio'}${C.reset}`,
|
|
2010
2437
|
`${C.gold}Model:${C.reset} ${C.white}${ctx.client.model}${C.reset}`,
|
|
2438
|
+
`${C.gold}Thinking:${C.reset} ${C.white}${ctx.agent?.session?.thinkingMode || 'show'}${C.reset}`,
|
|
2011
2439
|
`${C.gold}Theme:${C.reset} ${C.white}${getThemeName()}${C.reset}`,
|
|
2012
|
-
`${C.gold}Max Iters:${C.reset} ${C.white}${ctx.agent
|
|
2013
|
-
`${C.gold}Window:${C.reset} ${C.white}${ctx.agent
|
|
2014
|
-
`${C.gold}Tools:${C.reset} ${C.cyberCyan}${toolsSchema.length}${C.reset}
|
|
2440
|
+
`${C.gold}Max Iters:${C.reset} ${C.white}${ctx.agent?.maxIterations ?? 5}${C.reset}`,
|
|
2441
|
+
`${C.gold}Window:${C.reset} ${C.white}${ctx.agent?.slidingWindowSize ?? 10}${C.reset}`,
|
|
2442
|
+
`${C.gold}Tools:${C.reset} ${C.cyberCyan}${toolsSchema.length}${C.reset}`,
|
|
2443
|
+
'',
|
|
2444
|
+
`${C.dim}Manage profiles: /profile list | /profile use <name> | /profile save <name>${C.reset}`
|
|
2015
2445
|
],
|
|
2016
2446
|
headerBg: '\x1b[48;2;48;54;70m', bg: '\x1b[48;2;36;40;52m'
|
|
2017
2447
|
});
|
|
@@ -2048,194 +2478,6 @@ export const handlers = {
|
|
|
2048
2478
|
return 'HANDLED';
|
|
2049
2479
|
},
|
|
2050
2480
|
|
|
2051
|
-
'/update': async (ctx) => {
|
|
2052
|
-
const manager = ctx.updateManager || new UpdateManager();
|
|
2053
|
-
const action = (ctx.sub || 'check').toLowerCase();
|
|
2054
|
-
const parts = ctx.parts || [];
|
|
2055
|
-
const allowMajor = parts.includes('--allow-major');
|
|
2056
|
-
const allowDeprecated = parts.includes('--allow-deprecated');
|
|
2057
|
-
const positional = parts.slice(2).filter(part => !part.startsWith('--'));
|
|
2058
|
-
const flags = parts.slice(2).filter(part => part.startsWith('--'));
|
|
2059
|
-
|
|
2060
|
-
const printUpdateHelp = () => printSolidPanel({
|
|
2061
|
-
title: 'Kiku Agent Update',
|
|
2062
|
-
lines: [
|
|
2063
|
-
`${C.bold}${C.white}/update${C.reset} ${C.dim}or /update check — check the configured channel${C.reset}`,
|
|
2064
|
-
`${C.bold}${C.white}/update install [latest|next|canary|x.y.z]${C.reset}`,
|
|
2065
|
-
`${C.bold}${C.white}/update channel [latest|next|canary]${C.reset}`,
|
|
2066
|
-
`${C.bold}${C.white}/update rollback${C.reset} ${C.dim}— reinstall the previously recorded version${C.reset}`,
|
|
2067
|
-
'',
|
|
2068
|
-
`${C.dim}Major releases require --allow-major. Deprecated releases require --allow-deprecated.${C.reset}`,
|
|
2069
|
-
],
|
|
2070
|
-
});
|
|
2071
|
-
|
|
2072
|
-
const statusLines = status => {
|
|
2073
|
-
const changeLabel = status.change === 'upgrade'
|
|
2074
|
-
? `${C.emerald}UPDATE AVAILABLE${C.reset}`
|
|
2075
|
-
: status.change === 'downgrade'
|
|
2076
|
-
? `${C.amber}OLDER RELEASE${C.reset}`
|
|
2077
|
-
: `${C.emerald}UP TO DATE${C.reset}`;
|
|
2078
|
-
const lines = [
|
|
2079
|
-
`${C.gold}Current:${C.reset} ${C.white}${status.currentVersion}${C.reset}`,
|
|
2080
|
-
`${C.gold}Target:${C.reset} ${C.white}${status.targetVersion}${C.reset} ${C.dim}(${status.target})${C.reset}`,
|
|
2081
|
-
`${C.gold}Status:${C.reset} ${changeLabel}`,
|
|
2082
|
-
`${C.gold}Installation:${C.reset} ${C.white}${status.installMode.label}${C.reset}`,
|
|
2083
|
-
`${C.gold}Node:${C.reset} ${status.nodeCompatible ? C.emerald + 'Compatible' : C.red + 'Incompatible'}${C.reset}${status.nodeRange ? ` ${C.dim}(requires ${status.nodeRange})${C.reset}` : ''}`,
|
|
2084
|
-
`${C.gold}Integrity:${C.reset} ${status.integrity ? C.emerald + 'Published with npm integrity metadata' : C.amber + 'Not reported'}${C.reset}`,
|
|
2085
|
-
];
|
|
2086
|
-
if (status.majorChange) lines.push(`${C.amber}[MAJOR] This release crosses a major-version boundary.${C.reset}`);
|
|
2087
|
-
if (status.deprecated) lines.push(`${C.red}[DEPRECATED] ${status.deprecated}${C.reset}`);
|
|
2088
|
-
lines.push('', `${C.bold}${C.lavender}What's new:${C.reset}`);
|
|
2089
|
-
if (status.releaseNotes.length > 0) {
|
|
2090
|
-
for (const note of status.releaseNotes) lines.push(` ${C.sakura}•${C.reset} ${C.white}${note}${C.reset}`);
|
|
2091
|
-
} else {
|
|
2092
|
-
lines.push(` ${C.dim}No release summary was published for this version.${C.reset}`);
|
|
2093
|
-
}
|
|
2094
|
-
if (status.releaseUrl) lines.push('', `${C.dim}Release: ${status.releaseUrl}${C.reset}`);
|
|
2095
|
-
return lines;
|
|
2096
|
-
};
|
|
2097
|
-
|
|
2098
|
-
try {
|
|
2099
|
-
const allowedFlags = action === 'install'
|
|
2100
|
-
? ['--allow-major', '--allow-deprecated']
|
|
2101
|
-
: action === 'rollback'
|
|
2102
|
-
? ['--allow-deprecated']
|
|
2103
|
-
: [];
|
|
2104
|
-
if (flags.some(flag => !allowedFlags.includes(flag))) {
|
|
2105
|
-
throw new UpdateError('Unknown option. Run /update help for supported arguments.', 'INVALID_OPTION');
|
|
2106
|
-
}
|
|
2107
|
-
if (positional.length > 1 || ((action === 'rollback' || action === 'help') && positional.length > 0)) {
|
|
2108
|
-
throw new UpdateError('Too many update arguments. Run /update help for usage.', 'INVALID_ARGUMENTS');
|
|
2109
|
-
}
|
|
2110
|
-
|
|
2111
|
-
if (action === 'help') {
|
|
2112
|
-
printUpdateHelp();
|
|
2113
|
-
return 'HANDLED';
|
|
2114
|
-
}
|
|
2115
|
-
|
|
2116
|
-
if (action === 'channel') {
|
|
2117
|
-
const requested = positional[0];
|
|
2118
|
-
if (!requested) {
|
|
2119
|
-
const channel = await manager.getChannel();
|
|
2120
|
-
printSolidPanel({
|
|
2121
|
-
title: 'Update Channel',
|
|
2122
|
-
lines: [
|
|
2123
|
-
`${C.gold}Current:${C.reset} ${C.white}${channel}${C.reset}`,
|
|
2124
|
-
`${C.dim}Available: ${UPDATE_CHANNELS.join(', ')}${C.reset}`,
|
|
2125
|
-
],
|
|
2126
|
-
});
|
|
2127
|
-
return 'HANDLED';
|
|
2128
|
-
}
|
|
2129
|
-
const channel = await manager.setChannel(requested);
|
|
2130
|
-
const lines = [
|
|
2131
|
-
`${C.emerald}[OK] Future /update checks will use ${C.bold}${channel}${C.reset}${C.emerald}.${C.reset}`,
|
|
2132
|
-
];
|
|
2133
|
-
if (channel !== 'latest') {
|
|
2134
|
-
lines.push(`${C.amber}[NOTE] The "${channel}" channel may not have published builds on npm yet.${C.reset}`);
|
|
2135
|
-
}
|
|
2136
|
-
lines.push(`${C.dim}This changes only the release channel; it does not install anything.${C.reset}`);
|
|
2137
|
-
printSolidPanel({
|
|
2138
|
-
title: 'Update Channel Changed',
|
|
2139
|
-
lines,
|
|
2140
|
-
});
|
|
2141
|
-
return 'HANDLED';
|
|
2142
|
-
}
|
|
2143
|
-
|
|
2144
|
-
if (action === 'install') {
|
|
2145
|
-
const target = positional[0];
|
|
2146
|
-
console.log(`\n ${C.cyberCyan}[UPDATE] Resolving and validating the requested npm release...${C.reset}\n`);
|
|
2147
|
-
const result = await manager.install(target, {
|
|
2148
|
-
allowMajor,
|
|
2149
|
-
allowDeprecated,
|
|
2150
|
-
onProgress: message => { if (message) console.log(` ${C.dim}${message}${C.reset}`); },
|
|
2151
|
-
});
|
|
2152
|
-
if (result.outcome === 'manual') {
|
|
2153
|
-
printSolidPanel({
|
|
2154
|
-
title: 'Manual Update Required',
|
|
2155
|
-
lines: [
|
|
2156
|
-
...statusLines(result),
|
|
2157
|
-
'',
|
|
2158
|
-
`${C.amber}This installation type is not modified automatically.${C.reset}`,
|
|
2159
|
-
`${C.gold}Run:${C.reset} ${C.white}${result.command}${C.reset}`,
|
|
2160
|
-
],
|
|
2161
|
-
});
|
|
2162
|
-
return 'HANDLED';
|
|
2163
|
-
}
|
|
2164
|
-
if (result.outcome === 'current') {
|
|
2165
|
-
printSolidPanel({ title: 'Kiku Agent Is Up to Date', lines: statusLines(result) });
|
|
2166
|
-
return 'HANDLED';
|
|
2167
|
-
}
|
|
2168
|
-
printSolidPanel({
|
|
2169
|
-
title: 'Update Installed Successfully',
|
|
2170
|
-
lines: [
|
|
2171
|
-
`${C.emerald}[OK] ${PACKAGE_NAME} ${result.installedVersion} was installed and verified.${C.reset}`,
|
|
2172
|
-
...(!result.historyRecorded ? [`${C.amber}[WARNING] Rollback history could not be saved.${C.reset}`] : []),
|
|
2173
|
-
`${C.dim}This session will close. Start kiku-agent again to load the new code.${C.reset}`,
|
|
2174
|
-
`${C.dim}Restart MCP hosts to load the matching kiku-mcp server version.${C.reset}`,
|
|
2175
|
-
],
|
|
2176
|
-
});
|
|
2177
|
-
try { await ctx.agent?.endSession?.(); } catch {}
|
|
2178
|
-
return 'EXIT';
|
|
2179
|
-
}
|
|
2180
|
-
|
|
2181
|
-
if (action === 'rollback') {
|
|
2182
|
-
console.log(`\n ${C.cyberCyan}[UPDATE] Resolving the previously installed version...${C.reset}\n`);
|
|
2183
|
-
const result = await manager.rollback({ allowDeprecated });
|
|
2184
|
-
if (result.outcome === 'manual') {
|
|
2185
|
-
printSolidPanel({
|
|
2186
|
-
title: 'Manual Rollback Required',
|
|
2187
|
-
lines: [
|
|
2188
|
-
`${C.amber}Run the following command outside Kiku Agent:${C.reset}`,
|
|
2189
|
-
`${C.white}${result.command}${C.reset}`,
|
|
2190
|
-
],
|
|
2191
|
-
});
|
|
2192
|
-
return 'HANDLED';
|
|
2193
|
-
}
|
|
2194
|
-
if (result.outcome === 'current') {
|
|
2195
|
-
printSolidPanel({ title: 'Rollback Not Needed', lines: statusLines(result) });
|
|
2196
|
-
return 'HANDLED';
|
|
2197
|
-
}
|
|
2198
|
-
printSolidPanel({
|
|
2199
|
-
title: 'Rollback Installed Successfully',
|
|
2200
|
-
lines: [
|
|
2201
|
-
`${C.emerald}[OK] Restored ${PACKAGE_NAME} ${result.installedVersion}.${C.reset}`,
|
|
2202
|
-
...(!result.historyRecorded ? [`${C.amber}[WARNING] Rollback history could not be saved.${C.reset}`] : []),
|
|
2203
|
-
`${C.dim}This session will close. Restart Kiku Agent and any MCP host.${C.reset}`,
|
|
2204
|
-
],
|
|
2205
|
-
});
|
|
2206
|
-
try { await ctx.agent?.endSession?.(); } catch {}
|
|
2207
|
-
return 'EXIT';
|
|
2208
|
-
}
|
|
2209
|
-
|
|
2210
|
-
if (action === 'check' || action === 'status') {
|
|
2211
|
-
const status = await manager.check(positional[0]);
|
|
2212
|
-
const lines = statusLines(status);
|
|
2213
|
-
if (status.updateAvailable) {
|
|
2214
|
-
lines.push('', `${C.cyberCyan}Run /update install${status.target === 'latest' ? '' : ` ${status.target}`} to update.${C.reset}`);
|
|
2215
|
-
}
|
|
2216
|
-
printSolidPanel({ title: 'Kiku Agent Update', lines });
|
|
2217
|
-
return 'HANDLED';
|
|
2218
|
-
}
|
|
2219
|
-
|
|
2220
|
-
printUpdateHelp();
|
|
2221
|
-
return 'HANDLED';
|
|
2222
|
-
} catch (error) {
|
|
2223
|
-
const safeMessage = error instanceof UpdateError ? error.message : 'The update operation failed unexpectedly.';
|
|
2224
|
-
const lines = [
|
|
2225
|
-
`${C.red}[${error.code || 'UPDATE_ERROR'}] ${safeMessage}${C.reset}`,
|
|
2226
|
-
];
|
|
2227
|
-
if (error.code === 'CHANNEL_NOT_FOUND') {
|
|
2228
|
-
lines.push(`${C.gold}Tip:${C.reset} ${C.white}Run ${C.bold}/update channel latest${C.reset}${C.white} to return to the active release channel.${C.reset}`);
|
|
2229
|
-
}
|
|
2230
|
-
lines.push(`${C.dim}No session, memory, or environment files were changed.${C.reset}`);
|
|
2231
|
-
printSolidPanel({
|
|
2232
|
-
title: 'Update Failed',
|
|
2233
|
-
lines,
|
|
2234
|
-
});
|
|
2235
|
-
return 'HANDLED';
|
|
2236
|
-
}
|
|
2237
|
-
},
|
|
2238
|
-
|
|
2239
2481
|
'/system': async () => {
|
|
2240
2482
|
const os = await import('node:os');
|
|
2241
2483
|
const mem = process.memoryUsage();
|
|
@@ -2451,13 +2693,13 @@ export const handlers = {
|
|
|
2451
2693
|
const { getCopyableContent, copyToClipboard, parseDetailsRequest } = await import('./queryDetails.js');
|
|
2452
2694
|
const reference = [ctx.sub, ctx.extra].filter(Boolean).join(' ');
|
|
2453
2695
|
const request = parseDetailsRequest(reference);
|
|
2454
|
-
const details = ctx.agent?.lastQueryDetails || null;
|
|
2696
|
+
const details = ctx.agent?.lastQueryDetails || ctx.agent?._lastQueryDetails || null;
|
|
2455
2697
|
const copyable = getCopyableContent(details, request, ctx.agent?.session);
|
|
2456
|
-
if (!copyable?.text) {
|
|
2698
|
+
if (!copyable?.text || !copyable.text.trim()) {
|
|
2457
2699
|
printRichCard({
|
|
2458
2700
|
title: 'Nothing to Copy',
|
|
2459
2701
|
status: 'warning',
|
|
2460
|
-
lines: ['The requested query or session section is empty.'],
|
|
2702
|
+
lines: ['The requested query or session section is empty or no query has been recorded.'],
|
|
2461
2703
|
});
|
|
2462
2704
|
return 'HANDLED';
|
|
2463
2705
|
}
|
|
@@ -2480,14 +2722,42 @@ export const handlers = {
|
|
|
2480
2722
|
},
|
|
2481
2723
|
|
|
2482
2724
|
'/gallery': async (ctx) => {
|
|
2483
|
-
const
|
|
2484
|
-
|
|
2725
|
+
const rawSub = String(ctx.sub || '').trim().toLowerCase();
|
|
2726
|
+
let renderOptions = { count: 2 };
|
|
2727
|
+
|
|
2728
|
+
if (rawSub === 'hd' || rawSub === 'single' || rawSub === 'card') {
|
|
2729
|
+
renderOptions = { count: 1, hd: true };
|
|
2730
|
+
} else if (!isNaN(Number(rawSub)) && Number(rawSub) > 0) {
|
|
2731
|
+
renderOptions = { index: Number(rawSub) - 1, hd: true };
|
|
2732
|
+
} else if (rawSub === 'all' || rawSub === 'pair') {
|
|
2733
|
+
renderOptions = { count: 2 };
|
|
2734
|
+
} else if (rawSub === 'list') {
|
|
2735
|
+
const { discoverImages, findGalleryMetadata } = await import('./terminalImage.js');
|
|
2736
|
+
const imgs = discoverImages();
|
|
2737
|
+
const lines = imgs.map((img, i) => {
|
|
2738
|
+
const meta = findGalleryMetadata(img);
|
|
2739
|
+
const title = meta?.titleCn || meta?.titleTh || path.basename(img);
|
|
2740
|
+
return ` ${C.cyan}${String(i + 1).padStart(2, ' ')}.${C.reset} ${C.bold}${title}${C.reset} ${meta?.date ? `${C.dim}(${meta.date})${C.reset}` : ''}`;
|
|
2741
|
+
});
|
|
2742
|
+
printSolidPanel({
|
|
2743
|
+
title: '🌸 Ju Jingyi Visual Photo Gallery Catalog',
|
|
2744
|
+
lines: [
|
|
2745
|
+
`${C.dim}Use /gallery <number> or /gallery hd to render in crystal-clear TrueColor:${C.reset}`,
|
|
2746
|
+
'',
|
|
2747
|
+
...lines,
|
|
2748
|
+
],
|
|
2749
|
+
bg: '\x1b[48;2;45;35;55m'
|
|
2750
|
+
});
|
|
2751
|
+
return 'HANDLED';
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
const displayed = typeof ctx.showTerminalImage === 'function' && ctx.showTerminalImage(renderOptions);
|
|
2485
2755
|
if (!displayed) {
|
|
2486
2756
|
printRichCard({
|
|
2487
2757
|
title: 'Terminal Gallery Unavailable',
|
|
2488
2758
|
status: 'warning',
|
|
2489
2759
|
lines: [
|
|
2490
|
-
'Images require an interactive color terminal and packaged files in src/assets/images.',
|
|
2760
|
+
'Images require an interactive color terminal and packaged files in public/images or src/assets/images.',
|
|
2491
2761
|
'Set KIKU_TUI_IMAGES=on to override terminal detection, or off to disable images.',
|
|
2492
2762
|
],
|
|
2493
2763
|
});
|
|
@@ -2608,7 +2878,7 @@ export const handlers = {
|
|
|
2608
2878
|
const selectedText = opts[idx];
|
|
2609
2879
|
if (idx === q.answer) {
|
|
2610
2880
|
answers.push({
|
|
2611
|
-
qIndex: i,
|
|
2881
|
+
qIndex: q.originalIndex ?? i,
|
|
2612
2882
|
answerIndex: q.optionOrder?.[idx] ?? idx,
|
|
2613
2883
|
});
|
|
2614
2884
|
score++;
|
|
@@ -2774,12 +3044,16 @@ const ALIASES = {
|
|
|
2774
3044
|
'/sponsor': '/ads', '/ad': '/ads',
|
|
2775
3045
|
'/image': '/gallery', '/photo': '/gallery',
|
|
2776
3046
|
'/cls': '/clear', '/reset': '/clear',
|
|
2777
|
-
'/export': '/save',
|
|
3047
|
+
'/export': '/save', '/markdown': '/save',
|
|
3048
|
+
'/src': '/sources', '/srcs': '/sources',
|
|
2778
3049
|
'/r': '/retry',
|
|
2779
3050
|
'/kvip': '/key',
|
|
2780
3051
|
'/switch': '/provider',
|
|
2781
3052
|
'/providers': '/provider',
|
|
2782
3053
|
'/fallback': '/provider',
|
|
3054
|
+
'/profiles': '/profile',
|
|
3055
|
+
'/preset': '/profile',
|
|
3056
|
+
'/presets': '/profile',
|
|
2783
3057
|
};
|
|
2784
3058
|
|
|
2785
3059
|
export async function routeCommand(rawInput, ctx) {
|