@ian2018cs/agenthub 0.1.6 → 0.1.8
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/index.html
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
<!-- Prevent zoom on iOS -->
|
|
27
27
|
<meta name="format-detection" content="telephone=no" />
|
|
28
|
-
<script type="module" crossorigin src="/assets/index-
|
|
28
|
+
<script type="module" crossorigin src="/assets/index-BJ5g44kL.js"></script>
|
|
29
29
|
<link rel="modulepreload" crossorigin href="/assets/vendor-react-BeVl62c0.js">
|
|
30
30
|
<link rel="modulepreload" crossorigin href="/assets/vendor-codemirror-C_VWDoZS.js">
|
|
31
31
|
<link rel="modulepreload" crossorigin href="/assets/vendor-utils-00TdZexr.js">
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
<link rel="modulepreload" crossorigin href="/assets/vendor-markdown-VwNYkg_0.js">
|
|
35
35
|
<link rel="modulepreload" crossorigin href="/assets/vendor-syntax-CdGaPJRS.js">
|
|
36
36
|
<link rel="modulepreload" crossorigin href="/assets/vendor-xterm-CvdiG4-n.js">
|
|
37
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
37
|
+
<link rel="stylesheet" crossorigin href="/assets/index-B5iudMdK.css">
|
|
38
38
|
</head>
|
|
39
39
|
<body>
|
|
40
40
|
<div id="root"></div>
|
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -541,28 +541,39 @@ app.put('/api/projects/:projectName/file', authenticateToken, async (req, res) =
|
|
|
541
541
|
|
|
542
542
|
app.get('/api/projects/:projectName/files', authenticateToken, async (req, res) => {
|
|
543
543
|
try {
|
|
544
|
-
|
|
545
|
-
|
|
544
|
+
// Query parameters for lazy loading
|
|
545
|
+
const { dirPath, depth = '1' } = req.query;
|
|
546
|
+
const maxDepth = Math.min(parseInt(depth) || 1, 10); // Limit max depth to 10
|
|
546
547
|
|
|
547
548
|
// Use extractProjectDirectory to get the actual project path
|
|
548
|
-
let
|
|
549
|
+
let projectPath;
|
|
549
550
|
try {
|
|
550
|
-
|
|
551
|
+
projectPath = await extractProjectDirectory(req.params.projectName, req.user.uuid);
|
|
551
552
|
} catch (error) {
|
|
552
553
|
console.error('Error extracting project directory:', error);
|
|
553
554
|
// Fallback to simple dash replacement
|
|
554
|
-
|
|
555
|
+
projectPath = req.params.projectName.replace(/-/g, '/');
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Determine target path (project root or specific directory)
|
|
559
|
+
let targetPath = projectPath;
|
|
560
|
+
if (dirPath) {
|
|
561
|
+
// Ensure the requested path is within the project directory (security check)
|
|
562
|
+
const normalizedDirPath = path.normalize(dirPath);
|
|
563
|
+
if (!normalizedDirPath.startsWith(projectPath)) {
|
|
564
|
+
return res.status(403).json({ error: 'Access denied: path outside project directory' });
|
|
565
|
+
}
|
|
566
|
+
targetPath = normalizedDirPath;
|
|
555
567
|
}
|
|
556
568
|
|
|
557
569
|
// Check if path exists
|
|
558
570
|
try {
|
|
559
|
-
await fsPromises.access(
|
|
571
|
+
await fsPromises.access(targetPath);
|
|
560
572
|
} catch (e) {
|
|
561
|
-
return res.status(404).json({ error: `
|
|
573
|
+
return res.status(404).json({ error: `Path not found: ${targetPath}` });
|
|
562
574
|
}
|
|
563
575
|
|
|
564
|
-
const files = await getFileTree(
|
|
565
|
-
const hiddenFiles = files.filter(f => f.name.startsWith('.'));
|
|
576
|
+
const files = await getFileTree(targetPath, maxDepth, 0, true);
|
|
566
577
|
res.json(files);
|
|
567
578
|
} catch (error) {
|
|
568
579
|
console.error('[ERROR] File tree error:', error.message);
|
|
@@ -1555,7 +1566,24 @@ function permToRwx(perm) {
|
|
|
1555
1566
|
return r + w + x;
|
|
1556
1567
|
}
|
|
1557
1568
|
|
|
1558
|
-
|
|
1569
|
+
// List of directories to skip when building file tree
|
|
1570
|
+
const SKIP_DIRECTORIES = new Set([
|
|
1571
|
+
'node_modules', 'dist', 'build', '.git', '.svn', '.hg',
|
|
1572
|
+
'__pycache__', '.pytest_cache', '.venv', 'venv',
|
|
1573
|
+
'.next', '.nuxt', 'coverage', '.cache'
|
|
1574
|
+
]);
|
|
1575
|
+
|
|
1576
|
+
// Check if a directory has any visible children (for lazy loading indicator)
|
|
1577
|
+
async function hasDirectoryChildren(dirPath) {
|
|
1578
|
+
try {
|
|
1579
|
+
const entries = await fsPromises.readdir(dirPath, { withFileTypes: true });
|
|
1580
|
+
return entries.some(entry => !SKIP_DIRECTORIES.has(entry.name));
|
|
1581
|
+
} catch {
|
|
1582
|
+
return false;
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
async function getFileTree(dirPath, maxDepth = 1, currentDepth = 0, showHidden = true) {
|
|
1559
1587
|
// Using fsPromises from import
|
|
1560
1588
|
const items = [];
|
|
1561
1589
|
|
|
@@ -1563,16 +1591,8 @@ async function getFileTree(dirPath, maxDepth = 3, currentDepth = 0, showHidden =
|
|
|
1563
1591
|
const entries = await fsPromises.readdir(dirPath, { withFileTypes: true });
|
|
1564
1592
|
|
|
1565
1593
|
for (const entry of entries) {
|
|
1566
|
-
// Debug: log all entries including hidden files
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
1594
|
// Skip heavy build directories and VCS directories
|
|
1570
|
-
if (entry.name
|
|
1571
|
-
entry.name === 'dist' ||
|
|
1572
|
-
entry.name === 'build' ||
|
|
1573
|
-
entry.name === '.git' ||
|
|
1574
|
-
entry.name === '.svn' ||
|
|
1575
|
-
entry.name === '.hg') continue;
|
|
1595
|
+
if (SKIP_DIRECTORIES.has(entry.name)) continue;
|
|
1576
1596
|
|
|
1577
1597
|
const itemPath = path.join(dirPath, entry.name);
|
|
1578
1598
|
const item = {
|
|
@@ -1602,15 +1622,22 @@ async function getFileTree(dirPath, maxDepth = 3, currentDepth = 0, showHidden =
|
|
|
1602
1622
|
item.permissionsRwx = '---------';
|
|
1603
1623
|
}
|
|
1604
1624
|
|
|
1605
|
-
if (entry.isDirectory()
|
|
1606
|
-
//
|
|
1607
|
-
|
|
1608
|
-
//
|
|
1609
|
-
await
|
|
1610
|
-
item.children =
|
|
1611
|
-
}
|
|
1612
|
-
//
|
|
1613
|
-
|
|
1625
|
+
if (entry.isDirectory()) {
|
|
1626
|
+
// For lazy loading: check if directory has children without loading them
|
|
1627
|
+
if (currentDepth >= maxDepth) {
|
|
1628
|
+
// Don't load children, just check if they exist
|
|
1629
|
+
item.hasChildren = await hasDirectoryChildren(item.path);
|
|
1630
|
+
item.children = []; // Empty array, will be loaded on demand
|
|
1631
|
+
} else {
|
|
1632
|
+
// Load children up to maxDepth
|
|
1633
|
+
try {
|
|
1634
|
+
await fsPromises.access(item.path, fs.constants.R_OK);
|
|
1635
|
+
item.children = await getFileTree(item.path, maxDepth, currentDepth + 1, showHidden);
|
|
1636
|
+
item.hasChildren = item.children.length > 0;
|
|
1637
|
+
} catch (e) {
|
|
1638
|
+
item.children = [];
|
|
1639
|
+
item.hasChildren = false;
|
|
1640
|
+
}
|
|
1614
1641
|
}
|
|
1615
1642
|
}
|
|
1616
1643
|
|
|
@@ -81,43 +81,25 @@ async function scanCommandsDirectory(dir, baseDir, namespace) {
|
|
|
81
81
|
const builtInCommands = [
|
|
82
82
|
{
|
|
83
83
|
name: '/help',
|
|
84
|
-
description: '
|
|
85
|
-
namespace: 'builtin',
|
|
86
|
-
metadata: { type: 'builtin' }
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
name: '/clear',
|
|
90
|
-
description: 'Clear the conversation history',
|
|
84
|
+
description: '显示帮助文档',
|
|
91
85
|
namespace: 'builtin',
|
|
92
86
|
metadata: { type: 'builtin' }
|
|
93
87
|
},
|
|
94
88
|
{
|
|
95
89
|
name: '/model',
|
|
96
|
-
description: '
|
|
90
|
+
description: '切换或查看当前 AI 模型',
|
|
97
91
|
namespace: 'builtin',
|
|
98
92
|
metadata: { type: 'builtin' }
|
|
99
93
|
},
|
|
100
94
|
{
|
|
101
95
|
name: '/memory',
|
|
102
|
-
description: '
|
|
96
|
+
description: '编辑 CLAUDE.md 记忆文件',
|
|
103
97
|
namespace: 'builtin',
|
|
104
98
|
metadata: { type: 'builtin' }
|
|
105
99
|
},
|
|
106
100
|
{
|
|
107
101
|
name: '/config',
|
|
108
|
-
description: '
|
|
109
|
-
namespace: 'builtin',
|
|
110
|
-
metadata: { type: 'builtin' }
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
name: '/status',
|
|
114
|
-
description: 'Show system status and version information',
|
|
115
|
-
namespace: 'builtin',
|
|
116
|
-
metadata: { type: 'builtin' }
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
name: '/rewind',
|
|
120
|
-
description: 'Rewind the conversation to a previous state',
|
|
102
|
+
description: '打开设置和配置',
|
|
121
103
|
namespace: 'builtin',
|
|
122
104
|
metadata: { type: 'builtin' }
|
|
123
105
|
}
|
|
@@ -129,27 +111,27 @@ const builtInCommands = [
|
|
|
129
111
|
*/
|
|
130
112
|
const builtInHandlers = {
|
|
131
113
|
'/help': async (args, context) => {
|
|
132
|
-
const helpText = `# Claude Code
|
|
114
|
+
const helpText = `# Claude Code 命令
|
|
133
115
|
|
|
134
|
-
##
|
|
116
|
+
## 内置命令
|
|
135
117
|
|
|
136
118
|
${builtInCommands.map(cmd => `### ${cmd.name}
|
|
137
119
|
${cmd.description}
|
|
138
120
|
`).join('\n')}
|
|
139
121
|
|
|
140
|
-
##
|
|
122
|
+
## 自定义命令
|
|
141
123
|
|
|
142
|
-
|
|
143
|
-
-
|
|
144
|
-
-
|
|
124
|
+
自定义命令可以创建在:
|
|
125
|
+
- 项目级别:\`.claude/commands/\`(仅当前项目可用)
|
|
126
|
+
- 用户级别:\`~/.claude/commands/\`(所有项目可用)
|
|
145
127
|
|
|
146
|
-
###
|
|
128
|
+
### 命令语法
|
|
147
129
|
|
|
148
|
-
-
|
|
149
|
-
-
|
|
150
|
-
- **Bash
|
|
130
|
+
- **参数**:使用 \`$ARGUMENTS\` 获取所有参数,或 \`$1\`、\`$2\` 等获取位置参数
|
|
131
|
+
- **文件包含**:使用 \`@filename\` 包含文件内容
|
|
132
|
+
- **Bash 命令**:使用 \`!command\` 执行 bash 命令
|
|
151
133
|
|
|
152
|
-
###
|
|
134
|
+
### 示例
|
|
153
135
|
|
|
154
136
|
\`\`\`markdown
|
|
155
137
|
/mycommand arg1 arg2
|
|
@@ -166,16 +148,6 @@ Custom commands can be created in:
|
|
|
166
148
|
};
|
|
167
149
|
},
|
|
168
150
|
|
|
169
|
-
'/clear': async (args, context) => {
|
|
170
|
-
return {
|
|
171
|
-
type: 'builtin',
|
|
172
|
-
action: 'clear',
|
|
173
|
-
data: {
|
|
174
|
-
message: 'Conversation history cleared'
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
},
|
|
178
|
-
|
|
179
151
|
'/model': async (args, context) => {
|
|
180
152
|
// Read available models from centralized constants
|
|
181
153
|
const availableModels = {
|
|
@@ -201,43 +173,6 @@ Custom commands can be created in:
|
|
|
201
173
|
};
|
|
202
174
|
},
|
|
203
175
|
|
|
204
|
-
'/status': async (args, context) => {
|
|
205
|
-
// Read version from package.json
|
|
206
|
-
const packageJsonPath = path.join(path.dirname(__dirname), '..', 'package.json');
|
|
207
|
-
let version = 'unknown';
|
|
208
|
-
let packageName = 'claude-code-ui';
|
|
209
|
-
|
|
210
|
-
try {
|
|
211
|
-
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
212
|
-
version = packageJson.version;
|
|
213
|
-
packageName = packageJson.name;
|
|
214
|
-
} catch (err) {
|
|
215
|
-
console.error('Error reading package.json:', err);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const uptime = process.uptime();
|
|
219
|
-
const uptimeMinutes = Math.floor(uptime / 60);
|
|
220
|
-
const uptimeHours = Math.floor(uptimeMinutes / 60);
|
|
221
|
-
const uptimeFormatted = uptimeHours > 0
|
|
222
|
-
? `${uptimeHours}h ${uptimeMinutes % 60}m`
|
|
223
|
-
: `${uptimeMinutes}m`;
|
|
224
|
-
|
|
225
|
-
return {
|
|
226
|
-
type: 'builtin',
|
|
227
|
-
action: 'status',
|
|
228
|
-
data: {
|
|
229
|
-
version,
|
|
230
|
-
packageName,
|
|
231
|
-
uptime: uptimeFormatted,
|
|
232
|
-
uptimeSeconds: Math.floor(uptime),
|
|
233
|
-
model: context?.model || 'claude-sonnet-4.5',
|
|
234
|
-
provider: context?.provider || 'claude',
|
|
235
|
-
nodeVersion: process.version,
|
|
236
|
-
platform: process.platform
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
},
|
|
240
|
-
|
|
241
176
|
'/memory': async (args, context) => {
|
|
242
177
|
const projectPath = context?.projectPath;
|
|
243
178
|
|
|
@@ -284,30 +219,6 @@ Custom commands can be created in:
|
|
|
284
219
|
message: 'Opening settings...'
|
|
285
220
|
}
|
|
286
221
|
};
|
|
287
|
-
},
|
|
288
|
-
|
|
289
|
-
'/rewind': async (args, context) => {
|
|
290
|
-
const steps = args[0] ? parseInt(args[0]) : 1;
|
|
291
|
-
|
|
292
|
-
if (isNaN(steps) || steps < 1) {
|
|
293
|
-
return {
|
|
294
|
-
type: 'builtin',
|
|
295
|
-
action: 'rewind',
|
|
296
|
-
data: {
|
|
297
|
-
error: 'Invalid steps parameter',
|
|
298
|
-
message: 'Usage: /rewind [number] - Rewind conversation by N steps (default: 1)'
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return {
|
|
304
|
-
type: 'builtin',
|
|
305
|
-
action: 'rewind',
|
|
306
|
-
data: {
|
|
307
|
-
steps,
|
|
308
|
-
message: `Rewinding conversation by ${steps} step${steps > 1 ? 's' : ''}...`
|
|
309
|
-
}
|
|
310
|
-
};
|
|
311
222
|
}
|
|
312
223
|
|
|
313
224
|
};
|