@siteboon/claude-code-ui 1.18.2 → 1.19.1
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.ja.md +1 -25
- package/README.ko.md +1 -25
- package/README.md +1 -25
- package/README.zh-CN.md +1 -25
- package/dist/assets/{index-Ukg3obwK.js → index-0DqtvI36.js} +237 -235
- package/dist/assets/index-BPHfv_yU.css +32 -0
- package/dist/index.html +2 -2
- package/package.json +6 -2
- package/scripts/fix-node-pty.js +67 -0
- package/server/claude-sdk.js +7 -1
- package/server/database/auth.db +0 -0
- package/server/index.js +5 -2
- package/server/projects.js +100 -12
- package/shared/modelConstants.js +1 -1
- package/dist/assets/index-CrvzRggA.css +0 -32
package/server/index.js
CHANGED
|
@@ -1886,6 +1886,9 @@ async function getFileTree(dirPath, maxDepth = 3, currentDepth = 0, showHidden =
|
|
|
1886
1886
|
}
|
|
1887
1887
|
|
|
1888
1888
|
const PORT = process.env.PORT || 3001;
|
|
1889
|
+
const HOST = process.env.HOST || '0.0.0.0';
|
|
1890
|
+
// Show localhost in URL when binding to all interfaces (0.0.0.0 isn't a connectable address)
|
|
1891
|
+
const DISPLAY_HOST = HOST === '0.0.0.0' ? 'localhost' : HOST;
|
|
1889
1892
|
|
|
1890
1893
|
// Initialize database and start server
|
|
1891
1894
|
async function startServer() {
|
|
@@ -1905,7 +1908,7 @@ async function startServer() {
|
|
|
1905
1908
|
console.log(`${c.warn('[WARN]')} Note: Requests will be proxied to Vite dev server at ${c.dim('http://localhost:' + (process.env.VITE_PORT || 5173))}`);
|
|
1906
1909
|
}
|
|
1907
1910
|
|
|
1908
|
-
server.listen(PORT,
|
|
1911
|
+
server.listen(PORT, HOST, async () => {
|
|
1909
1912
|
const appInstallPath = path.join(__dirname, '..');
|
|
1910
1913
|
|
|
1911
1914
|
console.log('');
|
|
@@ -1913,7 +1916,7 @@ async function startServer() {
|
|
|
1913
1916
|
console.log(` ${c.bright('Claude Code UI Server - Ready')}`);
|
|
1914
1917
|
console.log(c.dim('═'.repeat(63)));
|
|
1915
1918
|
console.log('');
|
|
1916
|
-
console.log(`${c.info('[INFO]')} Server URL: ${c.bright('http://
|
|
1919
|
+
console.log(`${c.info('[INFO]')} Server URL: ${c.bright('http://' + DISPLAY_HOST + ':' + PORT)}`);
|
|
1917
1920
|
console.log(`${c.info('[INFO]')} Installed at: ${c.dim(appInstallPath)}`);
|
|
1918
1921
|
console.log(`${c.tip('[TIP]')} Run "cloudcli status" for full configuration details`);
|
|
1919
1922
|
console.log('');
|
package/server/projects.js
CHANGED
|
@@ -889,22 +889,81 @@ async function parseJsonlSessions(filePath) {
|
|
|
889
889
|
}
|
|
890
890
|
}
|
|
891
891
|
|
|
892
|
+
// Parse an agent JSONL file and extract tool uses
|
|
893
|
+
async function parseAgentTools(filePath) {
|
|
894
|
+
const tools = [];
|
|
895
|
+
|
|
896
|
+
try {
|
|
897
|
+
const fileStream = fsSync.createReadStream(filePath);
|
|
898
|
+
const rl = readline.createInterface({
|
|
899
|
+
input: fileStream,
|
|
900
|
+
crlfDelay: Infinity
|
|
901
|
+
});
|
|
902
|
+
|
|
903
|
+
for await (const line of rl) {
|
|
904
|
+
if (line.trim()) {
|
|
905
|
+
try {
|
|
906
|
+
const entry = JSON.parse(line);
|
|
907
|
+
// Look for assistant messages with tool_use
|
|
908
|
+
if (entry.message?.role === 'assistant' && Array.isArray(entry.message?.content)) {
|
|
909
|
+
for (const part of entry.message.content) {
|
|
910
|
+
if (part.type === 'tool_use') {
|
|
911
|
+
tools.push({
|
|
912
|
+
toolId: part.id,
|
|
913
|
+
toolName: part.name,
|
|
914
|
+
toolInput: part.input,
|
|
915
|
+
timestamp: entry.timestamp
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
// Look for tool results
|
|
921
|
+
if (entry.message?.role === 'user' && Array.isArray(entry.message?.content)) {
|
|
922
|
+
for (const part of entry.message.content) {
|
|
923
|
+
if (part.type === 'tool_result') {
|
|
924
|
+
// Find the matching tool and add result
|
|
925
|
+
const tool = tools.find(t => t.toolId === part.tool_use_id);
|
|
926
|
+
if (tool) {
|
|
927
|
+
tool.toolResult = {
|
|
928
|
+
content: typeof part.content === 'string' ? part.content :
|
|
929
|
+
Array.isArray(part.content) ? part.content.map(c => c.text || '').join('\n') :
|
|
930
|
+
JSON.stringify(part.content),
|
|
931
|
+
isError: Boolean(part.is_error)
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
} catch (parseError) {
|
|
938
|
+
// Skip malformed lines
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
} catch (error) {
|
|
943
|
+
console.warn(`Error parsing agent file ${filePath}:`, error.message);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
return tools;
|
|
947
|
+
}
|
|
948
|
+
|
|
892
949
|
// Get messages for a specific session with pagination support
|
|
893
950
|
async function getSessionMessages(projectName, sessionId, limit = null, offset = 0) {
|
|
894
951
|
const projectDir = path.join(os.homedir(), '.claude', 'projects', projectName);
|
|
895
952
|
|
|
896
953
|
try {
|
|
897
954
|
const files = await fs.readdir(projectDir);
|
|
898
|
-
// agent-*.jsonl files contain
|
|
899
|
-
// periodically to make sure only accurate data is there and no new functionality is added there
|
|
955
|
+
// agent-*.jsonl files contain subagent tool history - we'll process them separately
|
|
900
956
|
const jsonlFiles = files.filter(file => file.endsWith('.jsonl') && !file.startsWith('agent-'));
|
|
901
|
-
|
|
957
|
+
const agentFiles = files.filter(file => file.endsWith('.jsonl') && file.startsWith('agent-'));
|
|
958
|
+
|
|
902
959
|
if (jsonlFiles.length === 0) {
|
|
903
960
|
return { messages: [], total: 0, hasMore: false };
|
|
904
961
|
}
|
|
905
|
-
|
|
962
|
+
|
|
906
963
|
const messages = [];
|
|
907
|
-
|
|
964
|
+
// Map of agentId -> tools for subagent tool grouping
|
|
965
|
+
const agentToolsCache = new Map();
|
|
966
|
+
|
|
908
967
|
// Process all JSONL files to find messages for this session
|
|
909
968
|
for (const file of jsonlFiles) {
|
|
910
969
|
const jsonlFile = path.join(projectDir, file);
|
|
@@ -913,7 +972,7 @@ async function getSessionMessages(projectName, sessionId, limit = null, offset =
|
|
|
913
972
|
input: fileStream,
|
|
914
973
|
crlfDelay: Infinity
|
|
915
974
|
});
|
|
916
|
-
|
|
975
|
+
|
|
917
976
|
for await (const line of rl) {
|
|
918
977
|
if (line.trim()) {
|
|
919
978
|
try {
|
|
@@ -927,26 +986,55 @@ async function getSessionMessages(projectName, sessionId, limit = null, offset =
|
|
|
927
986
|
}
|
|
928
987
|
}
|
|
929
988
|
}
|
|
930
|
-
|
|
989
|
+
|
|
990
|
+
// Collect agentIds from Task tool results
|
|
991
|
+
const agentIds = new Set();
|
|
992
|
+
for (const message of messages) {
|
|
993
|
+
if (message.toolUseResult?.agentId) {
|
|
994
|
+
agentIds.add(message.toolUseResult.agentId);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// Load agent tools for each agentId found
|
|
999
|
+
for (const agentId of agentIds) {
|
|
1000
|
+
const agentFileName = `agent-${agentId}.jsonl`;
|
|
1001
|
+
if (agentFiles.includes(agentFileName)) {
|
|
1002
|
+
const agentFilePath = path.join(projectDir, agentFileName);
|
|
1003
|
+
const tools = await parseAgentTools(agentFilePath);
|
|
1004
|
+
agentToolsCache.set(agentId, tools);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// Attach agent tools to their parent Task messages
|
|
1009
|
+
for (const message of messages) {
|
|
1010
|
+
if (message.toolUseResult?.agentId) {
|
|
1011
|
+
const agentId = message.toolUseResult.agentId;
|
|
1012
|
+
const agentTools = agentToolsCache.get(agentId);
|
|
1013
|
+
if (agentTools && agentTools.length > 0) {
|
|
1014
|
+
message.subagentTools = agentTools;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
931
1019
|
// Sort messages by timestamp
|
|
932
|
-
const sortedMessages = messages.sort((a, b) =>
|
|
1020
|
+
const sortedMessages = messages.sort((a, b) =>
|
|
933
1021
|
new Date(a.timestamp || 0) - new Date(b.timestamp || 0)
|
|
934
1022
|
);
|
|
935
|
-
|
|
1023
|
+
|
|
936
1024
|
const total = sortedMessages.length;
|
|
937
|
-
|
|
1025
|
+
|
|
938
1026
|
// If no limit is specified, return all messages (backward compatibility)
|
|
939
1027
|
if (limit === null) {
|
|
940
1028
|
return sortedMessages;
|
|
941
1029
|
}
|
|
942
|
-
|
|
1030
|
+
|
|
943
1031
|
// Apply pagination - for recent messages, we need to slice from the end
|
|
944
1032
|
// offset 0 should give us the most recent messages
|
|
945
1033
|
const startIndex = Math.max(0, total - offset - limit);
|
|
946
1034
|
const endIndex = total - offset;
|
|
947
1035
|
const paginatedMessages = sortedMessages.slice(startIndex, endIndex);
|
|
948
1036
|
const hasMore = startIndex > 0;
|
|
949
|
-
|
|
1037
|
+
|
|
950
1038
|
return {
|
|
951
1039
|
messages: paginatedMessages,
|
|
952
1040
|
total,
|
package/shared/modelConstants.js
CHANGED