xibecode 1.0.3 → 1.0.7

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.
Files changed (268) hide show
  1. package/dist/commands/chat.d.ts.map +1 -1
  2. package/dist/commands/chat.js +10 -7
  3. package/dist/commands/chat.js.map +1 -1
  4. package/dist/commands/diagnostics.js +1 -1
  5. package/dist/commands/diagnostics.js.map +1 -1
  6. package/dist/commands/mcp.js +1 -1
  7. package/dist/commands/mcp.js.map +1 -1
  8. package/dist/commands/resume.js +1 -1
  9. package/dist/commands/resume.js.map +1 -1
  10. package/dist/commands/run-pr.d.ts.map +1 -1
  11. package/dist/commands/run-pr.js +10 -9
  12. package/dist/commands/run-pr.js.map +1 -1
  13. package/dist/commands/run.d.ts.map +1 -1
  14. package/dist/commands/run.js +14 -13
  15. package/dist/commands/run.js.map +1 -1
  16. package/dist/commands/skills.d.ts.map +1 -1
  17. package/dist/commands/skills.js +3 -2
  18. package/dist/commands/skills.js.map +1 -1
  19. package/dist/components/AssistantMarkdown.js +1 -1
  20. package/dist/components/AssistantMarkdown.js.map +1 -1
  21. package/dist/ui/claude-style-chat.d.ts.map +1 -1
  22. package/dist/ui/claude-style-chat.js +12 -10
  23. package/dist/ui/claude-style-chat.js.map +1 -1
  24. package/dist/utils/built-in-skills-dir.d.ts +7 -0
  25. package/dist/utils/built-in-skills-dir.d.ts.map +1 -0
  26. package/dist/utils/built-in-skills-dir.js +11 -0
  27. package/dist/utils/built-in-skills-dir.js.map +1 -0
  28. package/dist/utils/config.d.ts +2 -119
  29. package/dist/utils/config.d.ts.map +1 -1
  30. package/dist/utils/config.js +3 -88
  31. package/dist/utils/config.js.map +1 -1
  32. package/package.json +11 -17
  33. package/dist/commands/punycode.d.ts +0 -5
  34. package/dist/commands/punycode.d.ts.map +0 -1
  35. package/dist/commands/punycode.js +0 -48
  36. package/dist/commands/punycode.js.map +0 -1
  37. package/dist/commands/tui.d.ts +0 -9
  38. package/dist/commands/tui.d.ts.map +0 -1
  39. package/dist/commands/tui.js +0 -83
  40. package/dist/commands/tui.js.map +0 -1
  41. package/dist/core/agent-tool-policies.d.ts +0 -5
  42. package/dist/core/agent-tool-policies.d.ts.map +0 -1
  43. package/dist/core/agent-tool-policies.js +0 -18
  44. package/dist/core/agent-tool-policies.js.map +0 -1
  45. package/dist/core/agent.d.ts +0 -181
  46. package/dist/core/agent.d.ts.map +0 -1
  47. package/dist/core/agent.js +0 -1777
  48. package/dist/core/agent.js.map +0 -1
  49. package/dist/core/background-agent.d.ts +0 -23
  50. package/dist/core/background-agent.d.ts.map +0 -1
  51. package/dist/core/background-agent.js +0 -175
  52. package/dist/core/background-agent.js.map +0 -1
  53. package/dist/core/code-graph.d.ts +0 -18
  54. package/dist/core/code-graph.d.ts.map +0 -1
  55. package/dist/core/code-graph.js +0 -105
  56. package/dist/core/code-graph.js.map +0 -1
  57. package/dist/core/conflict-solver.d.ts +0 -26
  58. package/dist/core/conflict-solver.d.ts.map +0 -1
  59. package/dist/core/conflict-solver.js +0 -108
  60. package/dist/core/conflict-solver.js.map +0 -1
  61. package/dist/core/context-compactor.d.ts +0 -10
  62. package/dist/core/context-compactor.d.ts.map +0 -1
  63. package/dist/core/context-compactor.js +0 -158
  64. package/dist/core/context-compactor.js.map +0 -1
  65. package/dist/core/context-pruner.d.ts +0 -19
  66. package/dist/core/context-pruner.d.ts.map +0 -1
  67. package/dist/core/context-pruner.js +0 -103
  68. package/dist/core/context-pruner.js.map +0 -1
  69. package/dist/core/context.d.ts +0 -82
  70. package/dist/core/context.d.ts.map +0 -1
  71. package/dist/core/context.js +0 -273
  72. package/dist/core/context.js.map +0 -1
  73. package/dist/core/conversation-recovery.d.ts +0 -9
  74. package/dist/core/conversation-recovery.d.ts.map +0 -1
  75. package/dist/core/conversation-recovery.js +0 -15
  76. package/dist/core/conversation-recovery.js.map +0 -1
  77. package/dist/core/debug-workflow.d.ts +0 -9
  78. package/dist/core/debug-workflow.d.ts.map +0 -1
  79. package/dist/core/debug-workflow.js +0 -19
  80. package/dist/core/debug-workflow.js.map +0 -1
  81. package/dist/core/docs-scraper.d.ts +0 -40
  82. package/dist/core/docs-scraper.d.ts.map +0 -1
  83. package/dist/core/docs-scraper.js +0 -386
  84. package/dist/core/docs-scraper.js.map +0 -1
  85. package/dist/core/editor.d.ts +0 -87
  86. package/dist/core/editor.d.ts.map +0 -1
  87. package/dist/core/editor.js +0 -377
  88. package/dist/core/editor.js.map +0 -1
  89. package/dist/core/export.d.ts +0 -11
  90. package/dist/core/export.d.ts.map +0 -1
  91. package/dist/core/export.js +0 -54
  92. package/dist/core/export.js.map +0 -1
  93. package/dist/core/history-manager.d.ts +0 -75
  94. package/dist/core/history-manager.d.ts.map +0 -1
  95. package/dist/core/history-manager.js +0 -146
  96. package/dist/core/history-manager.js.map +0 -1
  97. package/dist/core/marketplace-client.d.ts +0 -52
  98. package/dist/core/marketplace-client.d.ts.map +0 -1
  99. package/dist/core/marketplace-client.js +0 -71
  100. package/dist/core/marketplace-client.js.map +0 -1
  101. package/dist/core/mcp/mcp-config.d.ts +0 -10
  102. package/dist/core/mcp/mcp-config.d.ts.map +0 -1
  103. package/dist/core/mcp/mcp-config.js +0 -70
  104. package/dist/core/mcp/mcp-config.js.map +0 -1
  105. package/dist/core/mcp/mcp-policy.d.ts +0 -17
  106. package/dist/core/mcp/mcp-policy.d.ts.map +0 -1
  107. package/dist/core/mcp/mcp-policy.js +0 -56
  108. package/dist/core/mcp/mcp-policy.js.map +0 -1
  109. package/dist/core/mcp/oauth-flow.d.ts +0 -30
  110. package/dist/core/mcp/oauth-flow.d.ts.map +0 -1
  111. package/dist/core/mcp/oauth-flow.js +0 -230
  112. package/dist/core/mcp/oauth-flow.js.map +0 -1
  113. package/dist/core/mcp/oauth-store.d.ts +0 -13
  114. package/dist/core/mcp/oauth-store.d.ts.map +0 -1
  115. package/dist/core/mcp/oauth-store.js +0 -68
  116. package/dist/core/mcp/oauth-store.js.map +0 -1
  117. package/dist/core/mcp/resolve-mcp-servers.d.ts +0 -16
  118. package/dist/core/mcp/resolve-mcp-servers.d.ts.map +0 -1
  119. package/dist/core/mcp/resolve-mcp-servers.js +0 -83
  120. package/dist/core/mcp/resolve-mcp-servers.js.map +0 -1
  121. package/dist/core/mcp-client.d.ts +0 -99
  122. package/dist/core/mcp-client.d.ts.map +0 -1
  123. package/dist/core/mcp-client.js +0 -317
  124. package/dist/core/mcp-client.js.map +0 -1
  125. package/dist/core/memory-promotions.d.ts +0 -15
  126. package/dist/core/memory-promotions.d.ts.map +0 -1
  127. package/dist/core/memory-promotions.js +0 -38
  128. package/dist/core/memory-promotions.js.map +0 -1
  129. package/dist/core/memory.d.ts +0 -32
  130. package/dist/core/memory.d.ts.map +0 -1
  131. package/dist/core/memory.js +0 -121
  132. package/dist/core/memory.js.map +0 -1
  133. package/dist/core/modes.d.ts +0 -432
  134. package/dist/core/modes.d.ts.map +0 -1
  135. package/dist/core/modes.js +0 -1094
  136. package/dist/core/modes.js.map +0 -1
  137. package/dist/core/pattern-miner.d.ts +0 -43
  138. package/dist/core/pattern-miner.d.ts.map +0 -1
  139. package/dist/core/pattern-miner.js +0 -123
  140. package/dist/core/pattern-miner.js.map +0 -1
  141. package/dist/core/permission-store.d.ts +0 -15
  142. package/dist/core/permission-store.d.ts.map +0 -1
  143. package/dist/core/permission-store.js +0 -30
  144. package/dist/core/permission-store.js.map +0 -1
  145. package/dist/core/permissions.d.ts +0 -33
  146. package/dist/core/permissions.d.ts.map +0 -1
  147. package/dist/core/permissions.js +0 -141
  148. package/dist/core/permissions.js.map +0 -1
  149. package/dist/core/plan-artifacts.d.ts +0 -10
  150. package/dist/core/plan-artifacts.d.ts.map +0 -1
  151. package/dist/core/plan-artifacts.js +0 -60
  152. package/dist/core/plan-artifacts.js.map +0 -1
  153. package/dist/core/plan-session.d.ts +0 -25
  154. package/dist/core/plan-session.d.ts.map +0 -1
  155. package/dist/core/plan-session.js +0 -99
  156. package/dist/core/plan-session.js.map +0 -1
  157. package/dist/core/planMode.d.ts +0 -51
  158. package/dist/core/planMode.d.ts.map +0 -1
  159. package/dist/core/planMode.js +0 -245
  160. package/dist/core/planMode.js.map +0 -1
  161. package/dist/core/plugins.d.ts +0 -96
  162. package/dist/core/plugins.d.ts.map +0 -1
  163. package/dist/core/plugins.js +0 -204
  164. package/dist/core/plugins.js.map +0 -1
  165. package/dist/core/session-bridge.d.ts +0 -128
  166. package/dist/core/session-bridge.d.ts.map +0 -1
  167. package/dist/core/session-bridge.js +0 -328
  168. package/dist/core/session-bridge.js.map +0 -1
  169. package/dist/core/session-manager.d.ts +0 -80
  170. package/dist/core/session-manager.d.ts.map +0 -1
  171. package/dist/core/session-manager.js +0 -166
  172. package/dist/core/session-manager.js.map +0 -1
  173. package/dist/core/session-memory.d.ts +0 -45
  174. package/dist/core/session-memory.d.ts.map +0 -1
  175. package/dist/core/session-memory.js +0 -103
  176. package/dist/core/session-memory.js.map +0 -1
  177. package/dist/core/skill-selection.d.ts +0 -36
  178. package/dist/core/skill-selection.d.ts.map +0 -1
  179. package/dist/core/skill-selection.js +0 -172
  180. package/dist/core/skill-selection.js.map +0 -1
  181. package/dist/core/skills-sh-client.d.ts +0 -19
  182. package/dist/core/skills-sh-client.d.ts.map +0 -1
  183. package/dist/core/skills-sh-client.js +0 -75
  184. package/dist/core/skills-sh-client.js.map +0 -1
  185. package/dist/core/skills.d.ts +0 -97
  186. package/dist/core/skills.d.ts.map +0 -1
  187. package/dist/core/skills.js +0 -339
  188. package/dist/core/skills.js.map +0 -1
  189. package/dist/core/swarm.d.ts +0 -34
  190. package/dist/core/swarm.d.ts.map +0 -1
  191. package/dist/core/swarm.js +0 -111
  192. package/dist/core/swarm.js.map +0 -1
  193. package/dist/core/task-status.d.ts +0 -13
  194. package/dist/core/task-status.d.ts.map +0 -1
  195. package/dist/core/task-status.js +0 -17
  196. package/dist/core/task-status.js.map +0 -1
  197. package/dist/core/tool-orchestrator.d.ts +0 -30
  198. package/dist/core/tool-orchestrator.d.ts.map +0 -1
  199. package/dist/core/tool-orchestrator.js +0 -89
  200. package/dist/core/tool-orchestrator.js.map +0 -1
  201. package/dist/core/tools.d.ts +0 -462
  202. package/dist/core/tools.d.ts.map +0 -1
  203. package/dist/core/tools.js +0 -2916
  204. package/dist/core/tools.js.map +0 -1
  205. package/dist/core/transcript-cleanup.d.ts +0 -8
  206. package/dist/core/transcript-cleanup.d.ts.map +0 -1
  207. package/dist/core/transcript-cleanup.js +0 -52
  208. package/dist/core/transcript-cleanup.js.map +0 -1
  209. package/dist/core/visual-feedback.d.ts +0 -20
  210. package/dist/core/visual-feedback.d.ts.map +0 -1
  211. package/dist/core/visual-feedback.js +0 -117
  212. package/dist/core/visual-feedback.js.map +0 -1
  213. package/dist/tools/browser.d.ts +0 -120
  214. package/dist/tools/browser.d.ts.map +0 -1
  215. package/dist/tools/browser.js +0 -439
  216. package/dist/tools/browser.js.map +0 -1
  217. package/dist/tools/test-generator.d.ts +0 -157
  218. package/dist/tools/test-generator.d.ts.map +0 -1
  219. package/dist/tools/test-generator.js +0 -893
  220. package/dist/tools/test-generator.js.map +0 -1
  221. package/dist/tui/InkApp.d.ts +0 -21
  222. package/dist/tui/InkApp.d.ts.map +0 -1
  223. package/dist/tui/InkApp.js +0 -146
  224. package/dist/tui/InkApp.js.map +0 -1
  225. package/dist/tui/MarkdownMessage.d.ts +0 -16
  226. package/dist/tui/MarkdownMessage.d.ts.map +0 -1
  227. package/dist/tui/MarkdownMessage.js +0 -63
  228. package/dist/tui/MarkdownMessage.js.map +0 -1
  229. package/dist/tui/blessed-chat.d.ts +0 -9
  230. package/dist/tui/blessed-chat.d.ts.map +0 -1
  231. package/dist/tui/blessed-chat.js +0 -887
  232. package/dist/tui/blessed-chat.js.map +0 -1
  233. package/dist/tui/markdown-to-blessed.d.ts +0 -6
  234. package/dist/tui/markdown-to-blessed.d.ts.map +0 -1
  235. package/dist/tui/markdown-to-blessed.js +0 -26
  236. package/dist/tui/markdown-to-blessed.js.map +0 -1
  237. package/dist/ui/ink/App.d.ts +0 -25
  238. package/dist/ui/ink/App.d.ts.map +0 -1
  239. package/dist/ui/ink/App.js +0 -372
  240. package/dist/ui/ink/App.js.map +0 -1
  241. package/dist/utils/at-references.d.ts +0 -14
  242. package/dist/utils/at-references.d.ts.map +0 -1
  243. package/dist/utils/at-references.js +0 -47
  244. package/dist/utils/at-references.js.map +0 -1
  245. package/dist/utils/auto-memory.d.ts +0 -24
  246. package/dist/utils/auto-memory.d.ts.map +0 -1
  247. package/dist/utils/auto-memory.js +0 -153
  248. package/dist/utils/auto-memory.js.map +0 -1
  249. package/dist/utils/git.d.ts +0 -89
  250. package/dist/utils/git.d.ts.map +0 -1
  251. package/dist/utils/git.js +0 -444
  252. package/dist/utils/git.js.map +0 -1
  253. package/dist/utils/mcp-servers-file.d.ts +0 -46
  254. package/dist/utils/mcp-servers-file.d.ts.map +0 -1
  255. package/dist/utils/mcp-servers-file.js +0 -212
  256. package/dist/utils/mcp-servers-file.js.map +0 -1
  257. package/dist/utils/safety.d.ts +0 -60
  258. package/dist/utils/safety.d.ts.map +0 -1
  259. package/dist/utils/safety.js +0 -254
  260. package/dist/utils/safety.js.map +0 -1
  261. package/dist/utils/smithery.d.ts +0 -25
  262. package/dist/utils/smithery.d.ts.map +0 -1
  263. package/dist/utils/smithery.js +0 -50
  264. package/dist/utils/smithery.js.map +0 -1
  265. package/dist/utils/testRunner.d.ts +0 -44
  266. package/dist/utils/testRunner.d.ts.map +0 -1
  267. package/dist/utils/testRunner.js +0 -270
  268. package/dist/utils/testRunner.js.map +0 -1
@@ -1,887 +0,0 @@
1
- import blessed from 'blessed';
2
- import chalk from 'chalk';
3
- import * as fs from 'fs/promises';
4
- import * as path from 'path';
5
- import { createRequire } from 'module';
6
- import { EnhancedAgent } from '../core/agent.js';
7
- import { CodingToolExecutor } from '../core/tools.js';
8
- import { MCPClientManager } from '../core/mcp-client.js';
9
- import { ConfigManager } from '../utils/config.js';
10
- import { SessionManager } from '../core/session-manager.js';
11
- import { ContextManager } from '../core/context.js';
12
- import { isThemeName, THEME_NAMES } from '../ui/themes.js';
13
- import { renderMarkdownToAnsi } from './markdown-to-blessed.js';
14
- import { getAllModes } from '../core/modes.js';
15
- import { exportSessionToMarkdown } from '../core/export.js';
16
- export async function runBlessedChat(options) {
17
- const config = new ConfigManager();
18
- const preferredTheme = (options.theme || config.getTheme());
19
- const themeName = isThemeName(preferredTheme) ? preferredTheme : 'default';
20
- const apiKey = options.apiKey || config.getApiKey();
21
- if (!apiKey) {
22
- // Use plain console output before blessed is initialised.
23
- // eslint-disable-next-line no-console
24
- console.error('No API key found!');
25
- // eslint-disable-next-line no-console
26
- console.log(' Set your API key:\n');
27
- // eslint-disable-next-line no-console
28
- console.log(' xibecode config --set-key YOUR_KEY\n');
29
- process.exit(1);
30
- }
31
- const model = options.model || config.getModel();
32
- const baseUrl = options.baseUrl || config.getBaseUrl();
33
- const sessionManager = new SessionManager(config.getSessionDirectory());
34
- const contextManager = new ContextManager(process.cwd());
35
- const mcpClientManager = new MCPClientManager();
36
- const mcpServers = await config.getMCPServers();
37
- const serverNames = Object.keys(mcpServers);
38
- // Connect MCP servers before launching TUI so we can show status.
39
- for (const serverName of serverNames) {
40
- const serverConfig = mcpServers[serverName];
41
- try {
42
- await mcpClientManager.connect(serverName, serverConfig);
43
- }
44
- catch {
45
- // Ignore connection failures here; they will be visible via /mcp later.
46
- }
47
- }
48
- const toolExecutor = new CodingToolExecutor(process.cwd(), { mcpClientManager });
49
- let agent = new EnhancedAgent({
50
- apiKey: apiKey,
51
- baseUrl,
52
- model,
53
- maxIterations: 150,
54
- verbose: false,
55
- });
56
- let currentMode = agent.getMode();
57
- const allModes = getAllModes();
58
- let enableTools = true;
59
- let currentSession;
60
- if (options.session) {
61
- const loaded = await sessionManager.loadSession(options.session);
62
- if (loaded) {
63
- currentSession = loaded;
64
- }
65
- else {
66
- currentSession = await sessionManager.createSession({ model, cwd: process.cwd() });
67
- }
68
- }
69
- else {
70
- currentSession = await sessionManager.createSession({ model, cwd: process.cwd() });
71
- }
72
- agent.setMessages(currentSession.messages || []);
73
- // ─── Blessed screen & layout ─────────────────────────────
74
- const screen = blessed.screen({
75
- smartCSR: true,
76
- title: 'XibeCode',
77
- });
78
- // Node ESM-safe require for reading package.json at runtime
79
- const require = createRequire(import.meta.url);
80
- const pkg = require('../../package.json');
81
- // ─── Big XibeCode banner (gradient ASCII, similar to classic UI) ───
82
- const logoLines = [
83
- '██╗ ██╗██╗██████╗ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗',
84
- '╚██╗██╔╝██║██╔══██╗██╔════╝██╔════╝██╔═══██╗██╔══██╗██╔════╝',
85
- ' ╚███╔╝ ██║██████╔╝█████╗ ██║ ██║ ██║██║ ██║█████╗ ',
86
- ' ██╔██╗ ██║██╔══██╗██╔══╝ ██║ ██║ ██║██╔══██╗██╔══╝ ',
87
- '██╔╝ ██╗██║██████╔╝███████╗╚██████╗╚██████╔╝██████╔╝███████╗',
88
- '╚═╝ ╚═╝╚═╝╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝',
89
- ];
90
- function buildGradientBanner(lines) {
91
- const start = { r: 89, g: 149, b: 235 };
92
- const end = { r: 224, g: 108, b: 117 };
93
- const out = [];
94
- for (const line of lines) {
95
- let coloredLine = '';
96
- const len = line.length;
97
- for (let i = 0; i < len; i++) {
98
- const ratio = i / len;
99
- const r = Math.floor(start.r + (end.r - start.r) * ratio);
100
- const g = Math.floor(start.g + (end.g - start.g) * ratio);
101
- const b = Math.floor(start.b + (end.b - start.b) * ratio);
102
- coloredLine += `\x1b[38;2;${r};${g};${b}m${line[i]}`;
103
- }
104
- out.push(coloredLine + '\x1b[0m');
105
- }
106
- out.push('');
107
- out.push(chalk.hex('#00D4FF').bold('XibeCode'));
108
- out.push(chalk.gray('AI-powered autonomous coding assistant') + chalk.gray(` · v${pkg.version ?? 'dev'}`));
109
- return out.join('\n');
110
- }
111
- const bannerHeight = logoLines.length + 4;
112
- const banner = blessed.box({
113
- top: 0,
114
- left: 0,
115
- right: 0,
116
- height: bannerHeight,
117
- tags: false, // use raw ANSI colors
118
- content: buildGradientBanner(logoLines),
119
- });
120
- const header = blessed.box({
121
- top: bannerHeight,
122
- left: 0,
123
- right: 0,
124
- height: 1,
125
- tags: true,
126
- style: {
127
- fg: 'white',
128
- bg: 'black',
129
- },
130
- });
131
- const messagesBox = blessed.box({
132
- top: bannerHeight + 1,
133
- left: 0,
134
- right: 0,
135
- bottom: 3,
136
- scrollable: true,
137
- alwaysScroll: true,
138
- scrollbar: { ch: ' ' },
139
- keys: true,
140
- mouse: true,
141
- tags: false,
142
- border: { type: 'line' },
143
- label: ' Conversation ',
144
- style: {
145
- border: { fg: 'grey' },
146
- },
147
- });
148
- const statusBar = blessed.box({
149
- bottom: 3,
150
- left: 0,
151
- right: 0,
152
- height: 2,
153
- tags: true,
154
- style: {
155
- fg: 'grey',
156
- bg: 'black',
157
- },
158
- });
159
- const thinkingBox = blessed.box({
160
- bottom: 3,
161
- right: 2,
162
- width: 20,
163
- height: 1,
164
- tags: true,
165
- style: {
166
- fg: 'cyan',
167
- bg: 'black',
168
- },
169
- });
170
- const input = blessed.textbox({
171
- bottom: 0,
172
- left: 0,
173
- right: 0,
174
- height: 3,
175
- inputOnFocus: true,
176
- keys: true,
177
- mouse: true,
178
- border: { type: 'line' },
179
- label: ' Type your message or @path/to/file ',
180
- style: {
181
- fg: 'white',
182
- bg: 'black',
183
- border: { fg: 'gray' },
184
- focus: {
185
- border: { fg: 'cyan' },
186
- },
187
- },
188
- });
189
- screen.append(banner);
190
- screen.append(header);
191
- screen.append(messagesBox);
192
- screen.append(statusBar);
193
- screen.append(thinkingBox);
194
- screen.append(input);
195
- const lines = [];
196
- let showDetails = config.getShowDetails();
197
- let showThinking = config.getShowThinking();
198
- let thinkingInterval = null;
199
- let thinkingFrame = 0;
200
- const thinkingFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
201
- function getToolIcon(name) {
202
- const icons = {
203
- read_file: '📄',
204
- read_multiple_files: '📚',
205
- write_file: '✍️',
206
- edit_file: '✏️',
207
- edit_lines: '🔧',
208
- delete_file: '🗑️',
209
- run_command: '⚡',
210
- search_files: '🔎',
211
- list_directory: '📂',
212
- create_directory: '📁',
213
- move_file: '📦',
214
- get_context: '🧠',
215
- revert_file: '↩️',
216
- insert_at_line: '➕',
217
- };
218
- return icons[name] || '🔧';
219
- }
220
- function summarizeToolInput(name, input) {
221
- if (!input)
222
- return null;
223
- switch (name) {
224
- case 'read_file':
225
- return input.start_line
226
- ? `${input.path} (${input.start_line}-${input.end_line})`
227
- : input.path || null;
228
- case 'read_multiple_files':
229
- return Array.isArray(input.paths) ? `${input.paths.length} files` : null;
230
- case 'write_file':
231
- case 'edit_file':
232
- case 'edit_lines':
233
- return input.path || null;
234
- case 'run_command':
235
- if (!input.command)
236
- return null;
237
- return input.command.length > 60 ? `${input.command.slice(0, 57)}...` : input.command;
238
- case 'search_files':
239
- return input.pattern || null;
240
- case 'list_directory':
241
- return input.path || '.';
242
- default:
243
- return null;
244
- }
245
- }
246
- function summarizeToolResult(name, result) {
247
- if (!result)
248
- return null;
249
- if (result.error || result.success === false) {
250
- return result.message || 'failed';
251
- }
252
- switch (name) {
253
- case 'read_file':
254
- return result.lines !== undefined ? `${result.lines} lines` : null;
255
- case 'read_multiple_files':
256
- return result.files ? `${result.files.length} files read` : null;
257
- case 'write_file':
258
- return result.lines ? `${result.lines} lines written` : 'written';
259
- case 'edit_file':
260
- return result.linesChanged ? `${result.linesChanged} lines changed` : 'edited';
261
- case 'run_command':
262
- return result.success ? 'ok' : 'failed';
263
- case 'search_files':
264
- return `${result.count ?? 0} matches`;
265
- case 'list_directory':
266
- return `${result.count ?? 0} items`;
267
- default:
268
- return 'ok';
269
- }
270
- }
271
- function formatToolCall(name, input) {
272
- const icon = getToolIcon(name);
273
- const summary = summarizeToolInput(name, input);
274
- let header = `${chalk.gray('╭─')} ${icon} ${chalk.cyan(name)}`;
275
- if (summary) {
276
- header += ' ' + chalk.dim(summary);
277
- }
278
- if (!showDetails || !input)
279
- return header;
280
- const json = JSON.stringify(input, null, 2)
281
- .split('\n')
282
- .slice(0, 20)
283
- .map(line => `${chalk.gray('│')} ${chalk.dim(line)}`)
284
- .join('\n');
285
- return `${header}\n${json}`;
286
- }
287
- function formatToolResult(name, result, success) {
288
- const icon = success ? chalk.green('✔') : chalk.red('✘');
289
- const summary = summarizeToolResult(name, result);
290
- let header = `${chalk.gray('╰─')} ${icon}`;
291
- if (summary) {
292
- header += ' ' + chalk.dim(summary);
293
- }
294
- if (!showDetails || !result || !success)
295
- return header;
296
- const bodyStr = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
297
- const json = bodyStr
298
- .split('\n')
299
- .slice(0, 30)
300
- .map(line => ` ${chalk.dim(line)}`)
301
- .join('\n');
302
- return `${header}\n${json}`;
303
- }
304
- function pushLine(line) {
305
- lines.push(line);
306
- renderMessages();
307
- }
308
- function renderMessages() {
309
- const rendered = [];
310
- for (const line of lines) {
311
- if (line.role === 'user') {
312
- rendered.push(chalk.green('You: ') + line.text);
313
- }
314
- else if (line.role === 'assistant') {
315
- const body = renderMarkdownToAnsi(line.text);
316
- rendered.push(chalk.cyan('Assistant:') + '\n' + body);
317
- }
318
- else if (line.role === 'tool') {
319
- rendered.push(line.text);
320
- }
321
- else {
322
- rendered.push(chalk.yellow(line.text));
323
- }
324
- rendered.push('');
325
- }
326
- messagesBox.setContent(rendered.join('\n'));
327
- messagesBox.setScrollPerc(100);
328
- updateStatus();
329
- screen.render();
330
- }
331
- function updateStatus() {
332
- const parts = [];
333
- parts.push(`model: ${model}`);
334
- parts.push(`mode: ${currentMode}`);
335
- if (currentSession?.title)
336
- parts.push(`session: ${currentSession.title}`);
337
- parts.push(`tools: ${enableTools ? 'on' : 'off'}`);
338
- parts.push(`theme: ${themeName}`);
339
- const cwd = process.cwd();
340
- statusBar.setContent(`${chalk.gray(cwd)}\n${chalk.gray(parts.join(' | '))}`);
341
- }
342
- function updateHeader() {
343
- header.setContent(` Tab: {green-fg}mode{/green-fg} (${currentMode}) | /help: {green-fg}commands{/green-fg} | {red-fg}q{/red-fg}: quit`);
344
- }
345
- function startThinking(label = 'Thinking') {
346
- if (!showThinking)
347
- return;
348
- if (thinkingInterval)
349
- clearInterval(thinkingInterval);
350
- thinkingInterval = setInterval(() => {
351
- const frame = thinkingFrames[thinkingFrame % thinkingFrames.length];
352
- thinkingFrame += 1;
353
- thinkingBox.setContent(` {cyan-fg}${label} ${frame}{/cyan-fg}`);
354
- screen.render();
355
- }, 120);
356
- }
357
- function stopThinking() {
358
- if (thinkingInterval) {
359
- clearInterval(thinkingInterval);
360
- thinkingInterval = null;
361
- }
362
- thinkingBox.setContent('');
363
- }
364
- function cycleMode() {
365
- const idx = allModes.indexOf(currentMode);
366
- const next = allModes[(idx + 1) % allModes.length];
367
- agent.setModeFromUser(next, 'User pressed Tab to cycle mode');
368
- currentMode = next;
369
- updateHeader();
370
- pushLine({
371
- role: 'system',
372
- text: `Mode changed to ${next}`,
373
- });
374
- }
375
- async function runUserMessage(raw) {
376
- const trimmed = raw.trim();
377
- if (!trimmed)
378
- return;
379
- // Slash commands
380
- if (trimmed === '/help') {
381
- pushLine({
382
- role: 'system',
383
- text: 'Commands: /help, /new, /sessions, /models, /themes, /export, /compact, /details, /thinking, /mcp\n' +
384
- 'Use !<cmd> to run shell commands. Tab to cycle modes.',
385
- });
386
- return;
387
- }
388
- if (trimmed === '/new') {
389
- currentSession = await sessionManager.createSession({ model, cwd: process.cwd() });
390
- agent = new EnhancedAgent({
391
- apiKey: apiKey,
392
- baseUrl,
393
- model,
394
- maxIterations: 150,
395
- verbose: false,
396
- });
397
- lines.length = 0;
398
- setupAgentHandlers();
399
- currentMode = agent.getMode();
400
- pushLine({ role: 'system', text: 'Started new session.' });
401
- renderMessages();
402
- return;
403
- }
404
- if (trimmed === '/sessions') {
405
- const sessions = await sessionManager.listSessions();
406
- if (!sessions.length) {
407
- pushLine({ role: 'system', text: 'No saved sessions.' });
408
- return;
409
- }
410
- const items = sessions.map((s, i) => `${i + 1}. ${s.title} · ${s.model} · ${s.updated} [${s.id}]`);
411
- const list = blessed.list({
412
- parent: screen,
413
- top: 'center',
414
- left: 'center',
415
- width: '70%',
416
- height: '60%',
417
- border: 'line',
418
- label: ' Sessions ',
419
- keys: true,
420
- mouse: true,
421
- items,
422
- style: {
423
- selected: { bg: 'blue', fg: 'white' },
424
- },
425
- });
426
- list.focus();
427
- list.key(['escape', 'q'], () => {
428
- list.destroy();
429
- input.focus();
430
- screen.render();
431
- });
432
- list.on('select', async (item, index) => {
433
- const session = sessions[index];
434
- const loaded = await sessionManager.loadSession(session.id);
435
- if (loaded) {
436
- currentSession = loaded;
437
- agent.setMessages(loaded.messages || []);
438
- lines.length = 0;
439
- pushLine({ role: 'system', text: `Switched to session: ${loaded.title}` });
440
- renderMessages();
441
- }
442
- else {
443
- pushLine({ role: 'system', text: `Failed to load session ${session.id}` });
444
- }
445
- list.destroy();
446
- input.focus();
447
- screen.render();
448
- });
449
- screen.render();
450
- return;
451
- }
452
- if (trimmed === '/models') {
453
- const current = model;
454
- const candidates = [
455
- current,
456
- 'claude-sonnet-4-5-20250929',
457
- 'claude-opus-4-5-20251101',
458
- 'claude-haiku-4-5-20251015',
459
- ];
460
- const unique = Array.from(new Set(candidates));
461
- const list = blessed.list({
462
- parent: screen,
463
- top: 'center',
464
- left: 'center',
465
- width: '60%',
466
- height: '50%',
467
- border: 'line',
468
- label: ' Models ',
469
- keys: true,
470
- mouse: true,
471
- items: unique.map(m => (m === current ? `${m} (current)` : m)),
472
- style: {
473
- selected: { bg: 'blue', fg: 'white' },
474
- },
475
- });
476
- list.focus();
477
- list.key(['escape', 'q'], () => {
478
- list.destroy();
479
- input.focus();
480
- screen.render();
481
- });
482
- list.on('select', async (item) => {
483
- const text = item.getText().replace(' (current)', '');
484
- config.set('model', text);
485
- pushLine({ role: 'system', text: `Model set to ${text}. Restart chat to apply.` });
486
- list.destroy();
487
- input.focus();
488
- screen.render();
489
- });
490
- screen.render();
491
- return;
492
- }
493
- if (trimmed === '/themes') {
494
- const current = themeName;
495
- const list = blessed.list({
496
- parent: screen,
497
- top: 'center',
498
- left: 'center',
499
- width: '60%',
500
- height: '50%',
501
- border: 'line',
502
- label: ' Themes ',
503
- keys: true,
504
- mouse: true,
505
- items: THEME_NAMES.map((name) => (name === current ? `${name} (current)` : name)),
506
- style: {
507
- selected: { bg: 'blue', fg: 'white' },
508
- },
509
- });
510
- list.focus();
511
- list.key(['escape', 'q'], () => {
512
- list.destroy();
513
- input.focus();
514
- screen.render();
515
- });
516
- list.on('select', item => {
517
- const text = item.getText().replace(' (current)', '');
518
- config.set('theme', text);
519
- pushLine({ role: 'system', text: `Theme set to ${text}. Restart chat to apply.` });
520
- list.destroy();
521
- input.focus();
522
- screen.render();
523
- });
524
- screen.render();
525
- return;
526
- }
527
- if (trimmed === '/export') {
528
- const session = {
529
- ...currentSession,
530
- messages: agent.getMessages(),
531
- };
532
- const markdown = exportSessionToMarkdown(session);
533
- const exportsDir = path.join(config['getConfigPath'], '..', 'sessions');
534
- const fileName = `${session.id}.md`;
535
- const fullPath = path.join(exportsDir, fileName);
536
- await fs.mkdir(exportsDir, { recursive: true });
537
- await fs.writeFile(fullPath, markdown, 'utf-8');
538
- pushLine({ role: 'system', text: `Session exported to ${fullPath}` });
539
- return;
540
- }
541
- if (trimmed === '/compact') {
542
- const messages = agent.getMessages();
543
- if (messages.length <= 10) {
544
- pushLine({ role: 'system', text: 'Conversation is short; no compaction needed.' });
545
- return;
546
- }
547
- const preserved = messages.slice(-6);
548
- const summaryMessage = {
549
- role: 'assistant',
550
- content: 'Earlier conversation has been compacted to save context. Key details from the last messages are preserved.',
551
- };
552
- const compacted = [summaryMessage, ...preserved];
553
- agent.setMessages(compacted);
554
- await sessionManager.saveMessagesAndStats({
555
- id: currentSession.id,
556
- messages: compacted,
557
- stats: agent.getStats(),
558
- });
559
- lines.length = 0;
560
- pushLine({ role: 'system', text: 'Conversation compacted.' });
561
- renderMessages();
562
- return;
563
- }
564
- if (trimmed === '/details') {
565
- showDetails = !showDetails;
566
- config.set('showDetails', showDetails);
567
- pushLine({ role: 'system', text: `Details ${showDetails ? 'enabled' : 'disabled'}.` });
568
- return;
569
- }
570
- if (trimmed === '/thinking') {
571
- showThinking = !showThinking;
572
- config.set('showThinking', showThinking);
573
- if (!showThinking)
574
- stopThinking();
575
- pushLine({ role: 'system', text: `Thinking display ${showThinking ? 'enabled' : 'disabled'}.` });
576
- return;
577
- }
578
- if (trimmed === '/mcp') {
579
- const connectedServers = mcpClientManager.getConnectedServers();
580
- if (!connectedServers.length) {
581
- pushLine({
582
- role: 'system',
583
- text: 'No MCP servers connected. Configure with: xibecode config --add-mcp-server or xibecode mcp add',
584
- });
585
- return;
586
- }
587
- const serverLines = [];
588
- for (const serverName of connectedServers) {
589
- const serverTools = mcpClientManager.getAvailableTools().filter(t => t.serverName === serverName);
590
- const serverResources = mcpClientManager.getAvailableResources().filter(r => r.serverName === serverName);
591
- const serverPrompts = mcpClientManager.getAvailablePrompts().filter(p => p.serverName === serverName);
592
- serverLines.push(`${serverName} — tools: ${serverTools.length}, resources: ${serverResources.length}, prompts: ${serverPrompts.length}`);
593
- }
594
- pushLine({ role: 'system', text: serverLines.join('\n') });
595
- return;
596
- }
597
- if (trimmed.startsWith('@')) {
598
- await handleAtPathFuzzy(trimmed);
599
- return;
600
- }
601
- if (trimmed.startsWith('!')) {
602
- await handleShellBang(trimmed);
603
- return;
604
- }
605
- // Regular user message
606
- lines.push({ role: 'user', text: trimmed });
607
- renderMessages();
608
- try {
609
- const tools = enableTools ? toolExecutor.getTools() : [];
610
- await agent.run(trimmed, tools, toolExecutor);
611
- const stats = agent.getStats();
612
- await sessionManager.saveMessagesAndStats({
613
- id: currentSession.id,
614
- messages: agent.getMessages(),
615
- stats,
616
- });
617
- }
618
- catch (error) {
619
- pushLine({ role: 'system', text: `Error: ${error.message || String(error)}` });
620
- }
621
- }
622
- async function handleShellBang(inputText) {
623
- const cmd = inputText.slice(1).trim();
624
- if (!cmd) {
625
- pushLine({ role: 'system', text: 'No command provided after \"!\". Example: !ls -la' });
626
- return;
627
- }
628
- pushLine({ role: 'system', text: `Running shell command: ${cmd}` });
629
- const result = await toolExecutor.execute('run_command', { command: cmd, cwd: process.cwd(), timeout: 300 });
630
- const stdout = result.stdout || '';
631
- const stderr = result.stderr || '';
632
- if (stdout) {
633
- pushLine({ role: 'system', text: stdout });
634
- }
635
- if (stderr) {
636
- pushLine({ role: 'system', text: `STDERR:\n${stderr}` });
637
- }
638
- }
639
- async function handleAtPathFuzzy(raw) {
640
- const inputText = raw.trim().slice(1).trim();
641
- const pattern = inputText ? `**/*${inputText}*` : '**/*';
642
- try {
643
- const files = await contextManager.searchFiles(pattern, { maxResults: 100 });
644
- if (!files.length) {
645
- pushLine({ role: 'system', text: `No matches for pattern ${pattern}` });
646
- return;
647
- }
648
- const text = files.map(f => `- ${f}`).join('\n');
649
- pushLine({ role: 'system', text: `Matches for ${pattern}:\n${text}` });
650
- }
651
- catch (error) {
652
- pushLine({ role: 'system', text: `Failed to search files: ${error.message || String(error)}` });
653
- }
654
- }
655
- function setupInput() {
656
- // Slash and @ suggestion popups
657
- let slashList = null;
658
- let atList = null;
659
- function closeSlashList() {
660
- if (slashList) {
661
- slashList.destroy();
662
- slashList = null;
663
- screen.render();
664
- }
665
- }
666
- function closeAtList() {
667
- if (atList) {
668
- atList.destroy();
669
- atList = null;
670
- screen.render();
671
- }
672
- }
673
- const slashCommands = [
674
- '/help',
675
- '/new',
676
- '/sessions',
677
- '/models',
678
- '/themes',
679
- '/export',
680
- '/compact',
681
- '/details',
682
- '/thinking',
683
- '/mcp',
684
- ];
685
- // Use change event instead of keypress to avoid interfering with typing
686
- input.on('change', async () => {
687
- const current = (input.getValue() || '');
688
- // Slash suggestions only when input is exactly "/"
689
- if (current === '/') {
690
- if (!slashList) {
691
- slashList = blessed.list({
692
- parent: screen,
693
- bottom: 6,
694
- left: 2,
695
- width: 24,
696
- height: 10,
697
- border: 'line',
698
- label: ' Commands ',
699
- keys: true,
700
- mouse: true,
701
- items: slashCommands,
702
- style: {
703
- selected: { bg: 'blue', fg: 'white' },
704
- },
705
- });
706
- slashList.focus();
707
- slashList.key(['up', 'k'], () => {
708
- slashList?.up(1);
709
- screen.render();
710
- });
711
- slashList.key(['down', 'j'], () => {
712
- slashList?.down(1);
713
- screen.render();
714
- });
715
- slashList.on('select', item => {
716
- const text = item.getText();
717
- input.setValue(text + ' ');
718
- closeSlashList();
719
- input.focus();
720
- screen.render();
721
- });
722
- slashList.key(['escape', 'q'], () => {
723
- closeSlashList();
724
- input.focus();
725
- });
726
- screen.render();
727
- }
728
- }
729
- else {
730
- closeSlashList();
731
- }
732
- // File suggestions when starting with '@'
733
- if (current.startsWith('@')) {
734
- const patternText = current.slice(1).trim();
735
- const pattern = patternText ? `**/*${patternText}*` : '**/*';
736
- try {
737
- const files = await contextManager.searchFiles(pattern, { maxResults: 30 });
738
- if (!files.length) {
739
- closeAtList();
740
- }
741
- else {
742
- if (!atList) {
743
- atList = blessed.list({
744
- parent: screen,
745
- bottom: 6,
746
- left: 28,
747
- width: 40,
748
- height: 12,
749
- border: 'line',
750
- label: ' Files ',
751
- keys: true,
752
- mouse: true,
753
- style: {
754
- selected: { bg: 'blue', fg: 'white' },
755
- },
756
- });
757
- atList.key(['up', 'k'], () => {
758
- atList?.up(1);
759
- screen.render();
760
- });
761
- atList.key(['down', 'j'], () => {
762
- atList?.down(1);
763
- screen.render();
764
- });
765
- atList.on('select', item => {
766
- const text = item.getText();
767
- input.setValue('@' + text);
768
- closeAtList();
769
- input.focus();
770
- screen.render();
771
- });
772
- atList.key(['escape', 'q'], () => {
773
- closeAtList();
774
- input.focus();
775
- });
776
- }
777
- atList.setItems(files);
778
- screen.render();
779
- }
780
- }
781
- catch {
782
- // ignore search errors in suggestions
783
- }
784
- }
785
- else {
786
- closeAtList();
787
- }
788
- });
789
- input.on('submit', async (value) => {
790
- input.clearValue();
791
- screen.render();
792
- await runUserMessage(value);
793
- input.focus();
794
- });
795
- input.key(['C-c', 'escape'], () => {
796
- shutdown();
797
- });
798
- // Tab should work even when textbox is focused
799
- input.key(['tab'], () => {
800
- cycleMode();
801
- });
802
- screen.key(['tab'], () => {
803
- cycleMode();
804
- });
805
- screen.key(['C-n'], async () => {
806
- await runUserMessage('/new');
807
- });
808
- screen.key(['q', 'C-c'], () => {
809
- shutdown();
810
- });
811
- }
812
- async function shutdown() {
813
- try {
814
- if (serverNames.length > 0) {
815
- await mcpClientManager.disconnectAll();
816
- }
817
- }
818
- finally {
819
- screen.destroy();
820
- process.exit(0);
821
- }
822
- }
823
- function setupAgentHandlers() {
824
- agent.removeAllListeners('event');
825
- agent.on('event', (event) => {
826
- switch (event.type) {
827
- case 'thinking':
828
- startThinking('Thinking');
829
- break;
830
- case 'stream_start':
831
- startThinking('Thinking');
832
- lines.push({ role: 'assistant', text: '' });
833
- break;
834
- case 'stream_text': {
835
- const last = lines[lines.length - 1];
836
- if (last && last.role === 'assistant') {
837
- last.text += event.data.text;
838
- renderMessages();
839
- }
840
- break;
841
- }
842
- case 'stream_end':
843
- stopThinking();
844
- renderMessages();
845
- break;
846
- case 'response':
847
- stopThinking();
848
- lines.push({ role: 'assistant', text: event.data.text });
849
- renderMessages();
850
- break;
851
- case 'tool_call':
852
- if (enableTools) {
853
- const text = formatToolCall(event.data.name, event.data.input);
854
- lines.push({ role: 'tool', text });
855
- renderMessages();
856
- }
857
- break;
858
- case 'tool_result':
859
- if (enableTools) {
860
- const text = formatToolResult(event.data.name, event.data.result, event.data.success !== false);
861
- lines.push({ role: 'tool', text });
862
- renderMessages();
863
- }
864
- break;
865
- case 'mode_changed':
866
- currentMode = event.data.to;
867
- updateHeader();
868
- pushLine({ role: 'system', text: `Mode changed to ${currentMode}` });
869
- break;
870
- case 'error':
871
- stopThinking();
872
- pushLine({ role: 'system', text: `Error: ${event.data.message || event.data.error}` });
873
- break;
874
- case 'warning':
875
- pushLine({ role: 'system', text: `Warning: ${event.data.message}` });
876
- break;
877
- }
878
- });
879
- }
880
- setupAgentHandlers();
881
- setupInput();
882
- input.focus();
883
- updateHeader();
884
- updateStatus();
885
- screen.render();
886
- }
887
- //# sourceMappingURL=blessed-chat.js.map