xibecode 0.9.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +20 -0
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/resume.d.ts +7 -0
- package/dist/commands/resume.d.ts.map +1 -0
- package/dist/commands/resume.js +136 -0
- package/dist/commands/resume.js.map +1 -0
- package/dist/commands/run-pr.js +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +27 -15
- package/dist/commands/run.js.map +1 -1
- package/dist/core/agent.d.ts +2 -0
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +114 -31
- package/dist/core/agent.js.map +1 -1
- package/dist/core/history-manager.d.ts.map +1 -1
- package/dist/core/history-manager.js +23 -19
- package/dist/core/history-manager.js.map +1 -1
- package/dist/core/modes.d.ts.map +1 -1
- package/dist/core/modes.js +8 -7
- package/dist/core/modes.js.map +1 -1
- package/dist/core/plan-artifacts.d.ts.map +1 -1
- package/dist/core/plan-artifacts.js +12 -5
- package/dist/core/plan-artifacts.js.map +1 -1
- package/dist/core/plan-session.d.ts.map +1 -1
- package/dist/core/plan-session.js +14 -10
- package/dist/core/plan-session.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +17 -14
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/tool-orchestrator.d.ts +8 -0
- package/dist/core/tool-orchestrator.d.ts.map +1 -1
- package/dist/core/tool-orchestrator.js +34 -1
- package/dist/core/tool-orchestrator.js.map +1 -1
- package/dist/core/tools.d.ts +9 -0
- package/dist/core/tools.d.ts.map +1 -1
- package/dist/core/tools.js +114 -97
- package/dist/core/tools.js.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/ui/claude-style-chat.d.ts +5 -0
- package/dist/ui/claude-style-chat.d.ts.map +1 -1
- package/dist/ui/claude-style-chat.js +220 -13
- package/dist/ui/claude-style-chat.js.map +1 -1
- package/dist/webui/server.js +1 -1
- package/package.json +1 -1
|
@@ -16,7 +16,70 @@ import { formatToolArgs, formatToolOutcome, formatRunSwarmDetailLines } from '..
|
|
|
16
16
|
import { SPINNER_VERBS } from '../constants/spinnerVerbs.js';
|
|
17
17
|
import { extractAtReferences, splitAtReferences } from '../utils/at-references.js';
|
|
18
18
|
import { loadImageAttachment, mimeFromExtension } from '../utils/image-attachments.js';
|
|
19
|
-
|
|
19
|
+
import { SessionManager } from '../core/session-manager.js';
|
|
20
|
+
function isAbortLikeError(err) {
|
|
21
|
+
if (!err || typeof err !== 'object')
|
|
22
|
+
return false;
|
|
23
|
+
const anyErr = err;
|
|
24
|
+
return (anyErr.name === 'AbortError' ||
|
|
25
|
+
anyErr.type === 'aborted' ||
|
|
26
|
+
String(anyErr.message || '').toLowerCase().includes('aborted'));
|
|
27
|
+
}
|
|
28
|
+
function summarizeToolResultContent(content) {
|
|
29
|
+
const raw = typeof content === 'string' ? content : JSON.stringify(content ?? '');
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(raw);
|
|
32
|
+
if (parsed && typeof parsed === 'object') {
|
|
33
|
+
const record = parsed;
|
|
34
|
+
if (typeof record.path === 'string') {
|
|
35
|
+
const details = [
|
|
36
|
+
typeof record.lines === 'number' ? `${record.lines} lines` : null,
|
|
37
|
+
typeof record.count === 'number' ? `${record.count} entries` : null,
|
|
38
|
+
typeof record.total === 'number' ? `${record.total} result(s)` : null,
|
|
39
|
+
].filter(Boolean).join(', ');
|
|
40
|
+
return details ? `${record.path} (${details})` : record.path;
|
|
41
|
+
}
|
|
42
|
+
if (typeof record.message === 'string')
|
|
43
|
+
return record.message;
|
|
44
|
+
if (typeof record.stdout === 'string')
|
|
45
|
+
return record.stdout.slice(0, 300);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Fall through to plain text summary.
|
|
50
|
+
}
|
|
51
|
+
return raw.replace(/\s+/g, ' ').trim().slice(0, 300);
|
|
52
|
+
}
|
|
53
|
+
function transcriptLinesFromMessage(message) {
|
|
54
|
+
if (typeof message.content === 'string') {
|
|
55
|
+
const text = message.content.trim();
|
|
56
|
+
return text ? [{ type: message.role === 'assistant' ? 'assistant' : 'user', text }] : [];
|
|
57
|
+
}
|
|
58
|
+
if (!Array.isArray(message.content))
|
|
59
|
+
return [];
|
|
60
|
+
const lines = [];
|
|
61
|
+
for (const block of message.content) {
|
|
62
|
+
if (block?.type === 'text') {
|
|
63
|
+
const text = String(block.text || '').trim();
|
|
64
|
+
if (text)
|
|
65
|
+
lines.push({ type: message.role === 'assistant' ? 'assistant' : 'user', text });
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (block?.type === 'tool_use') {
|
|
69
|
+
const name = String(block.name || 'tool');
|
|
70
|
+
lines.push({ type: 'tool', text: `${name}${block.input ? ` — ${formatToolArgs(name, block.input)}` : ''}` });
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (block?.type === 'tool_result') {
|
|
74
|
+
lines.push({
|
|
75
|
+
type: 'tool_out',
|
|
76
|
+
text: `tool_result: ${summarizeToolResultContent(block.content)}`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return lines;
|
|
81
|
+
}
|
|
82
|
+
const APP_VERSION = '1.0.0';
|
|
20
83
|
const HERO_LOGO = [
|
|
21
84
|
'██╗ ██╗██╗██████╗ ███████╗',
|
|
22
85
|
'╚██╗██╔╝██║██╔══██╗██╔════╝',
|
|
@@ -167,27 +230,57 @@ function XibeCodeChatApp(props) {
|
|
|
167
230
|
const [workSpinnerFrame, setWorkSpinnerFrame] = useState(0);
|
|
168
231
|
const [workVerbIndex, setWorkVerbIndex] = useState(0);
|
|
169
232
|
const nextLineIdRef = useRef(1);
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
233
|
+
const initialMessagesRef = useRef(props.initialMessages);
|
|
234
|
+
const sessionIdRef = useRef(props.sessionId);
|
|
235
|
+
const buildInitialLines = useCallback(() => {
|
|
236
|
+
const base = [
|
|
237
|
+
{
|
|
238
|
+
kind: 'line',
|
|
239
|
+
id: nextLineIdRef.current++,
|
|
240
|
+
type: 'info',
|
|
241
|
+
text: 'XibeCode interactive session. Type /exit to quit, /clear to reset the transcript.',
|
|
242
|
+
},
|
|
243
|
+
{ kind: 'line', id: nextLineIdRef.current++, type: 'info', text: 'Type /help for shortcuts.' },
|
|
244
|
+
];
|
|
245
|
+
if (sessionIdRef.current) {
|
|
246
|
+
base.push({
|
|
247
|
+
kind: 'line',
|
|
248
|
+
id: nextLineIdRef.current++,
|
|
249
|
+
type: 'info',
|
|
250
|
+
text: `Resumed session: ${sessionIdRef.current}`,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
if (initialMessagesRef.current && initialMessagesRef.current.length > 0) {
|
|
254
|
+
for (const msg of initialMessagesRef.current) {
|
|
255
|
+
for (const line of transcriptLinesFromMessage(msg)) {
|
|
256
|
+
base.push({ kind: 'line', id: nextLineIdRef.current++, ...line });
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return base;
|
|
261
|
+
}, []);
|
|
262
|
+
const [lines, setLines] = useState(buildInitialLines);
|
|
179
263
|
const pushLine = useCallback((line) => {
|
|
180
264
|
const withId = { ...line, kind: 'line', id: nextLineIdRef.current++ };
|
|
181
265
|
props.onUiLine?.(line);
|
|
182
266
|
// Keep a much larger in-memory transcript so context doesn't vanish quickly.
|
|
183
267
|
setLines((prev) => [...prev.slice(-5000), withId]);
|
|
184
268
|
}, [props]);
|
|
269
|
+
useEffect(() => {
|
|
270
|
+
props.registerUiSink?.(pushLine);
|
|
271
|
+
}, [props, pushLine]);
|
|
272
|
+
useEffect(() => {
|
|
273
|
+
props.registerModeSink?.((nextMode) => {
|
|
274
|
+
setActiveMode(nextMode);
|
|
275
|
+
});
|
|
276
|
+
}, [props]);
|
|
185
277
|
const abortControllerRef = useRef(null);
|
|
186
278
|
const abortReasonRef = useRef('none');
|
|
187
279
|
const queuedPromptRef = useRef(null);
|
|
188
280
|
const lastVisibleOutputAtRef = useRef(Date.now());
|
|
189
281
|
const currentPromptRef = useRef(null);
|
|
190
282
|
const restartAttemptsRef = useRef(0);
|
|
283
|
+
const sessionMessagesRef = useRef(props.initialMessages || []);
|
|
191
284
|
const lastBgLineByTask = useRef(new Map());
|
|
192
285
|
useEffect(() => {
|
|
193
286
|
if (!isRunning)
|
|
@@ -486,6 +579,7 @@ function XibeCodeChatApp(props) {
|
|
|
486
579
|
}
|
|
487
580
|
}
|
|
488
581
|
if (resolvedInput === '/exit') {
|
|
582
|
+
props.onMessagesUpdate?.(props.getCurrentMessages?.() ?? sessionMessagesRef.current);
|
|
489
583
|
exit();
|
|
490
584
|
return;
|
|
491
585
|
}
|
|
@@ -618,6 +712,7 @@ function XibeCodeChatApp(props) {
|
|
|
618
712
|
lastVisibleOutputAtRef.current = Date.now();
|
|
619
713
|
abortControllerRef.current = new AbortController();
|
|
620
714
|
pushLine({ type: 'user', text: prompt });
|
|
715
|
+
sessionMessagesRef.current.push({ role: 'user', content: prompt });
|
|
621
716
|
setIsRunning(true);
|
|
622
717
|
try {
|
|
623
718
|
const startedAt = Date.now();
|
|
@@ -1104,9 +1199,9 @@ function XibeCodeChatApp(props) {
|
|
|
1104
1199
|
if (item.kind === 'hero') {
|
|
1105
1200
|
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [HERO_LOGO.map((line, idx) => (_jsx(React.Fragment, { children: _jsx(Text, { bold: true, color: idx < 6 ? 'claude' : 'suggestion', children: line }) }, `logo-${idx}`))), _jsx(Text, { color: "suggestion", children: "\u2726 Any model, Every tool, Zero limits. \u2726" }), _jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "claude", flexDirection: "column", paddingX: 1, children: [_jsxs(Text, { children: [_jsx(Text, { color: "inactive", children: "Provider " }), _jsx(Text, { color: "claude", bold: true, children: providerName })] }), _jsxs(Text, { children: [_jsx(Text, { color: "inactive", children: "Model " }), _jsx(Text, { children: activeModel })] }), _jsxs(Text, { children: [_jsx(Text, { color: "inactive", children: "Endpoint " }), _jsx(Text, { children: props.baseUrl || 'provider default' })] }), _jsxs(Text, { children: [_jsx(Text, { color: "inactive", children: "Format " }), _jsxs(Text, { children: [wireFormat, ' ', _jsxs(Text, { dimColor: true, children: ["(", isAnthropicWireFormat(wireFormat, props.provider, props.customProviderFormat)
|
|
1106
1201
|
? 'Anthropic Messages'
|
|
1107
|
-
: 'OpenAI chat', ")"] })] })] })] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "suggestion", children: "\u25C8 cloud" }), _jsx(Text, { color: "inactive", children: " Ready \u2014 type " }), _jsx(Text, { color: "claude", children: "/help" }), _jsx(Text, { color: "inactive", children: " to begin" })] }), _jsxs(Text, { color: "inactive", children: ["xibecode ", _jsxs(Text, { color: "claude", children: ["v", APP_VERSION] })] }), _jsx(Text, { color: "subtle", children: '─'.repeat(98) }), _jsx(Text, { color: "inactive", children: "Agent transcript" })] }));
|
|
1202
|
+
: 'OpenAI chat', ")"] })] })] })] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "suggestion", children: "\u25C8 cloud" }), _jsx(Text, { color: "inactive", children: " Ready \u2014 type " }), _jsx(Text, { color: "claude", children: "/help" }), _jsx(Text, { color: "inactive", children: " to begin" })] }), _jsxs(Text, { color: "inactive", children: ["xibecode ", _jsxs(Text, { color: "claude", children: ["v", APP_VERSION] })] }), _jsx(Text, { color: "subtle", children: '─'.repeat(98) }), _jsx(Text, { color: "inactive", children: "Agent transcript" })] }, item.id));
|
|
1108
1203
|
}
|
|
1109
|
-
return item.type === 'assistant' ? (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { bold: true, color: prefixColorKey('assistant'), children: [prefixForType('assistant'), ":"] }), _jsx(Box, { marginLeft: 2, flexDirection: "column", children: _jsx(AssistantMarkdown, { content: item.text }) })] })) : (_jsxs(Text, { children: [_jsxs(Text, { bold: true, color: prefixColorKey(item.type), children: [prefixForType(item.type), ":", ' '] }), _jsx(Text, { color: lineColorKey(item.type), children: item.text })] }));
|
|
1204
|
+
return (_jsx(React.Fragment, { children: item.type === 'assistant' ? (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { bold: true, color: prefixColorKey('assistant'), children: [prefixForType('assistant'), ":"] }), _jsx(Box, { marginLeft: 2, flexDirection: "column", children: _jsx(AssistantMarkdown, { content: item.text }) })] })) : (_jsxs(Text, { children: [_jsxs(Text, { bold: true, color: prefixColorKey(item.type), children: [prefixForType(item.type), ":", ' '] }), _jsx(Text, { color: lineColorKey(item.type), children: item.text })] })) }, item.id));
|
|
1110
1205
|
} }), !hasChatContent && (_jsx(Box, { marginTop: 1, flexDirection: "column", children: _jsx(Text, { color: "inactive", children: "(send a message to start)" }) })), _jsx(Text, { color: "subtle", children: divider }), isRunning && (_jsx(Box, { marginTop: 1, paddingX: 1, borderStyle: "round", borderColor: "claudeBlue_FOR_SYSTEM_SPINNER", flexDirection: "column", children: _jsxs(Text, { wrap: "wrap", children: [_jsxs(Text, { bold: true, color: "claudeBlue_FOR_SYSTEM_SPINNER", children: [WORK_SPINNER_FRAMES[workSpinnerFrame], ' '] }), _jsx(Text, { bold: true, color: "briefLabelClaude", children: workVerbPhrase })] }) })), _jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "claude", paddingX: 1, children: [_jsx(Text, { color: "claude", children: '> ' }), _jsx(TextInput, { value: input, onChange: setInput, onSubmit: onSubmit, placeholder: isRunning ? 'Waiting for response…' : 'Message XibeCode…' })] }), isSlashMode && (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "suggestion", flexDirection: "column", paddingX: 1, children: [_jsx(Text, { color: "suggestion", bold: true, children: "Commands" }), filteredCommands.length === 0 ? (_jsxs(Text, { color: "inactive", children: ["No commands match \"", input, "\""] })) : (filteredCommands.map((command, index) => (_jsx(React.Fragment, { children: _jsxs(Text, { children: [_jsx(Text, { color: index === selectedCommandIndex ? 'claude' : 'inactive', children: index === selectedCommandIndex ? '▸ ' : ' ' }), _jsx(Text, { bold: true, color: index === selectedCommandIndex ? 'claude' : 'text', children: command.name }), _jsxs(Text, { color: "inactive", children: [" \u2014 ", command.description] })] }) }, command.name)))), _jsx(Text, { color: "subtle", children: "Use \u2191/\u2193 to navigate, Tab to autocomplete." })] })), modelPickerOpen && (_jsxs(Box, { marginTop: 1, borderStyle: "round", borderColor: "claude", flexDirection: "column", paddingX: 1, children: [_jsx(Text, { bold: true, color: "claude", children: "Select model" }), isModelListLoading ? (_jsx(Text, { color: "inactive", children: "Loading models from provider..." })) : filteredModels.length === 0 ? (_jsx(Text, { color: "inactive", children: "No models matched current filter." })) : (visibleModelOptions.map((modelName, index) => {
|
|
1111
1206
|
const absoluteIndex = modelPickerStart + index;
|
|
1112
1207
|
const isSelected = absoluteIndex === selectedModelIndex;
|
|
@@ -1178,6 +1273,9 @@ export async function launchClaudeStyleChat(options) {
|
|
|
1178
1273
|
config.set('model', nextModel);
|
|
1179
1274
|
if (activeCreds.apiKey) {
|
|
1180
1275
|
activeAgent = createAgentForModel(nextModel, { apiKey: activeCreds.apiKey, baseUrl: activeCreds.baseUrl });
|
|
1276
|
+
if (currentSession?.messages?.length) {
|
|
1277
|
+
activeAgent.setMessages(currentSession.messages);
|
|
1278
|
+
}
|
|
1181
1279
|
activeAgent.setModeFromUser(activeMode, 'Preserve user-selected mode after model switch');
|
|
1182
1280
|
}
|
|
1183
1281
|
else {
|
|
@@ -1201,6 +1299,9 @@ export async function launchClaudeStyleChat(options) {
|
|
|
1201
1299
|
activeAgent?.removeAllListeners('event');
|
|
1202
1300
|
if (activeCreds.apiKey) {
|
|
1203
1301
|
activeAgent = createAgentForModel(activeModel, { apiKey: activeCreds.apiKey, baseUrl: activeCreds.baseUrl });
|
|
1302
|
+
if (currentSession?.messages?.length) {
|
|
1303
|
+
activeAgent.setMessages(currentSession.messages);
|
|
1304
|
+
}
|
|
1204
1305
|
activeAgent.setModeFromUser(activeMode, 'Preserve user-selected mode after format switch');
|
|
1205
1306
|
}
|
|
1206
1307
|
else {
|
|
@@ -1251,6 +1352,9 @@ export async function launchClaudeStyleChat(options) {
|
|
|
1251
1352
|
activeCreds.baseUrl !== currentBaseUrl) {
|
|
1252
1353
|
activeCreds = { apiKey: currentApiKey, baseUrl: currentBaseUrl };
|
|
1253
1354
|
activeAgent = createAgentForModel(activeModel, { apiKey: currentApiKey, baseUrl: currentBaseUrl });
|
|
1355
|
+
if (currentSession?.messages?.length) {
|
|
1356
|
+
activeAgent.setMessages(currentSession.messages);
|
|
1357
|
+
}
|
|
1254
1358
|
activeAgent.setModeFromUser(activeMode, 'Refresh agent after credential change');
|
|
1255
1359
|
toolExecutor.setMode(activeMode);
|
|
1256
1360
|
}
|
|
@@ -1312,6 +1416,9 @@ export async function launchClaudeStyleChat(options) {
|
|
|
1312
1416
|
onLine({ type: 'assistant', text: event.data?.text || '' });
|
|
1313
1417
|
break;
|
|
1314
1418
|
case 'error':
|
|
1419
|
+
if (isAbortLikeError(event.data?.message) || isAbortLikeError(event.data?.error)) {
|
|
1420
|
+
break;
|
|
1421
|
+
}
|
|
1315
1422
|
onLine({
|
|
1316
1423
|
type: 'error',
|
|
1317
1424
|
text: event.data?.message ||
|
|
@@ -1319,6 +1426,16 @@ export async function launchClaudeStyleChat(options) {
|
|
|
1319
1426
|
'Unknown error',
|
|
1320
1427
|
});
|
|
1321
1428
|
break;
|
|
1429
|
+
case 'mode_changed': {
|
|
1430
|
+
const next = String(event.data?.to ?? '');
|
|
1431
|
+
if (next) {
|
|
1432
|
+
activeMode = next;
|
|
1433
|
+
toolExecutor.setMode(next);
|
|
1434
|
+
modeSink?.(next);
|
|
1435
|
+
onLine({ type: 'info', text: `Mode changed to ${next}` });
|
|
1436
|
+
}
|
|
1437
|
+
break;
|
|
1438
|
+
}
|
|
1322
1439
|
default:
|
|
1323
1440
|
break;
|
|
1324
1441
|
}
|
|
@@ -1327,8 +1444,10 @@ export async function launchClaudeStyleChat(options) {
|
|
|
1327
1444
|
images: opts?.images,
|
|
1328
1445
|
signal: opts?.signal,
|
|
1329
1446
|
});
|
|
1447
|
+
await onMessagesUpdate(activeAgent.getMessages());
|
|
1330
1448
|
activeMode = activeAgent.getMode();
|
|
1331
1449
|
toolExecutor.setMode(activeMode);
|
|
1450
|
+
modeSink?.(activeMode);
|
|
1332
1451
|
return activeAgent.getStats();
|
|
1333
1452
|
};
|
|
1334
1453
|
const listBackgroundTasks = async () => {
|
|
@@ -1360,7 +1479,95 @@ export async function launchClaudeStyleChat(options) {
|
|
|
1360
1479
|
const rendered = formatUiLineForLog(line) + '\n';
|
|
1361
1480
|
logChain = logChain.then(() => fs.appendFile(chatLogPath, rendered, 'utf8')).catch(() => { });
|
|
1362
1481
|
};
|
|
1482
|
+
// Keep the chat UI alive even if something throws unexpectedly.
|
|
1483
|
+
// We surface errors as chat lines instead of crashing the whole process.
|
|
1484
|
+
let uiSink = null;
|
|
1485
|
+
const registerUiSink = (sink) => {
|
|
1486
|
+
uiSink = sink;
|
|
1487
|
+
};
|
|
1488
|
+
// Keep the UI's displayed mode in sync with the tool permission mode.
|
|
1489
|
+
let modeSink = null;
|
|
1490
|
+
const registerModeSink = (sink) => {
|
|
1491
|
+
modeSink = sink;
|
|
1492
|
+
};
|
|
1493
|
+
const formatUnknownError = (err) => {
|
|
1494
|
+
if (err instanceof Error)
|
|
1495
|
+
return err.stack || err.message;
|
|
1496
|
+
try {
|
|
1497
|
+
return typeof err === 'string' ? err : JSON.stringify(err);
|
|
1498
|
+
}
|
|
1499
|
+
catch {
|
|
1500
|
+
return String(err);
|
|
1501
|
+
}
|
|
1502
|
+
};
|
|
1503
|
+
const onUnhandledRejection = (reason) => {
|
|
1504
|
+
if (isAbortLikeError(reason))
|
|
1505
|
+
return;
|
|
1506
|
+
uiSink?.({ type: 'error', text: `Unhandled rejection:\n${formatUnknownError(reason)}` });
|
|
1507
|
+
};
|
|
1508
|
+
const onUncaughtException = (err) => {
|
|
1509
|
+
if (isAbortLikeError(err))
|
|
1510
|
+
return;
|
|
1511
|
+
uiSink?.({ type: 'error', text: `Uncaught exception:\n${formatUnknownError(err)}` });
|
|
1512
|
+
};
|
|
1513
|
+
process.on('unhandledRejection', onUnhandledRejection);
|
|
1514
|
+
process.on('uncaughtException', onUncaughtException);
|
|
1515
|
+
const sessionManager = new SessionManager();
|
|
1516
|
+
let currentSessionId = options.sessionId;
|
|
1517
|
+
let currentSession = null;
|
|
1518
|
+
if (!currentSessionId) {
|
|
1519
|
+
currentSession = await sessionManager.createSession({
|
|
1520
|
+
title: 'Untitled Session',
|
|
1521
|
+
model,
|
|
1522
|
+
cwd: process.cwd(),
|
|
1523
|
+
});
|
|
1524
|
+
currentSessionId = currentSession.id;
|
|
1525
|
+
if (options.initialMessages && options.initialMessages.length > 0) {
|
|
1526
|
+
currentSession.messages = options.initialMessages;
|
|
1527
|
+
await sessionManager.saveSession(currentSession);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
else {
|
|
1531
|
+
currentSession = await sessionManager.loadSession(currentSessionId);
|
|
1532
|
+
}
|
|
1533
|
+
if (currentSession?.messages?.length) {
|
|
1534
|
+
activeAgent?.setMessages(currentSession.messages);
|
|
1535
|
+
}
|
|
1536
|
+
else if (options.initialMessages && options.initialMessages.length > 0) {
|
|
1537
|
+
activeAgent?.setMessages(options.initialMessages);
|
|
1538
|
+
}
|
|
1539
|
+
const onSessionCreated = (sessionId) => {
|
|
1540
|
+
currentSessionId = sessionId;
|
|
1541
|
+
};
|
|
1542
|
+
const onMessagesUpdate = async (messages) => {
|
|
1543
|
+
if (currentSessionId && currentSession) {
|
|
1544
|
+
currentSession.messages = messages;
|
|
1545
|
+
if (messages.length > 0) {
|
|
1546
|
+
const firstUserMsg = messages.find((m) => m.role === 'user');
|
|
1547
|
+
if (firstUserMsg && typeof firstUserMsg.content === 'string') {
|
|
1548
|
+
const title = firstUserMsg.content.trim().slice(0, 60);
|
|
1549
|
+
if (title) {
|
|
1550
|
+
currentSession.title = title + (firstUserMsg.content.length > 60 ? '…' : '');
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
await sessionManager.saveSession(currentSession);
|
|
1555
|
+
}
|
|
1556
|
+
};
|
|
1363
1557
|
const root = createRoot({ exitOnCtrlC: true });
|
|
1364
|
-
|
|
1558
|
+
try {
|
|
1559
|
+
await renderAndRun(root, _jsx(XibeCodeChatApp, { model: model, initialMode: activeMode, provider: provider, baseUrl: baseUrl, needsFirstRunSetup: needsFirstRunSetup, defaultModel: model, modeOptions: modeOptions, initialRequestFormat: wireFormat, customProviderFormat: customProviderFormat, profile: options.profile, sessionId: currentSessionId, initialMessages: options.initialMessages, runPrompt: runPrompt, listBackgroundTasks: listBackgroundTasks, checkBackgroundTask: checkBackgroundTask, onUiLine: appendLogLine, registerUiSink: registerUiSink, registerModeSink: registerModeSink, loadModels: loadModels, onModelChange: onModelChange, onModeChange: onModeChange, onWireFormatChange: onWireFormatChange, onSessionCreated: onSessionCreated, onMessagesUpdate: onMessagesUpdate, getCurrentMessages: () => activeAgent?.getMessages() ?? currentSession?.messages ?? [] }));
|
|
1560
|
+
}
|
|
1561
|
+
finally {
|
|
1562
|
+
process.off('unhandledRejection', onUnhandledRejection);
|
|
1563
|
+
process.off('uncaughtException', onUncaughtException);
|
|
1564
|
+
if (currentSessionId) {
|
|
1565
|
+
console.log('\n');
|
|
1566
|
+
console.log('─'.repeat(60));
|
|
1567
|
+
console.log(`Session: ${currentSessionId}`);
|
|
1568
|
+
console.log(`To resume: xibecode resume ${currentSessionId}`);
|
|
1569
|
+
console.log('─'.repeat(60));
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1365
1572
|
}
|
|
1366
1573
|
//# sourceMappingURL=claude-style-chat.js.map
|