@ia-ccun/code-agent-claw 0.0.3 → 0.0.5

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/bin/cli.js CHANGED
@@ -2,13 +2,48 @@
2
2
 
3
3
  const { spawn } = require('child_process');
4
4
  const path = require('path');
5
+ const fs = require('fs');
6
+
7
+ const args = process.argv.slice(2);
8
+
9
+ // 获取版本号
10
+ if (args.includes('--version') || args.includes('-v')) {
11
+ const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
12
+ console.log(packageJson.version);
13
+ process.exit(0);
14
+ }
15
+
16
+ // 显示帮助
17
+ if (args.includes('--help') || args.includes('-h')) {
18
+ console.log('Usage: code-agent-claw [options]');
19
+ console.log('');
20
+ console.log('Options:');
21
+ console.log(' --version, -v Show version number');
22
+ console.log(' --port, -p <port> Specify server port (default: 8081)');
23
+ console.log(' --help, -h Show this help message');
24
+ process.exit(0);
25
+ }
26
+
27
+ // 解析端口参数
28
+ let port = null;
29
+ for (let i = 0; i < args.length; i++) {
30
+ if ((args[i] === '--port' || args[i] === '-p') && args[i + 1]) {
31
+ port = args[i + 1];
32
+ break;
33
+ }
34
+ }
5
35
 
6
36
  const distPath = path.join(__dirname, '..', 'dist', 'index.js');
7
37
 
38
+ const env = { ...process.env };
39
+ if (port) {
40
+ env.AICODE_UI_PORT = port;
41
+ }
42
+
8
43
  const child = spawn('node', [distPath], {
9
44
  stdio: 'inherit',
10
45
  cwd: process.cwd(),
11
- env: process.env
46
+ env
12
47
  });
13
48
 
14
49
  child.on('exit', (code) => {
@@ -382,11 +382,22 @@
382
382
  animation: pulse 2s ease-in-out infinite;
383
383
  }
384
384
 
385
+ .status-dot.disconnected {
386
+ background: var(--error);
387
+ box-shadow: 0 0 8px rgba(201, 74, 74, 0.5);
388
+ animation: pulse-red 1.5s ease-in-out infinite;
389
+ }
390
+
385
391
  @keyframes pulse {
386
392
  0%, 100% { opacity: 1; }
387
393
  50% { opacity: 0.6; }
388
394
  }
389
395
 
396
+ @keyframes pulse-red {
397
+ 0%, 100% { opacity: 1; box-shadow: 0 0 8px rgba(201, 74, 74, 0.5); }
398
+ 50% { opacity: 0.5; box-shadow: 0 0 16px rgba(201, 74, 74, 0.8); }
399
+ }
400
+
390
401
  /* Action buttons */
391
402
  .action-btn {
392
403
  width: 36px;
@@ -855,8 +866,9 @@
855
866
  /* Quick questions */
856
867
  .quick-questions {
857
868
  display: flex;
858
- flex-wrap: wrap;
869
+ flex-wrap: nowrap;
859
870
  gap: var(--space-sm);
871
+ overflow-x: auto;
860
872
  }
861
873
 
862
874
  .quick-question {
@@ -869,6 +881,8 @@
869
881
  color: var(--text-secondary);
870
882
  cursor: pointer;
871
883
  transition: all 0.2s ease;
884
+ white-space: nowrap;
885
+ flex-shrink: 0;
872
886
  }
873
887
 
874
888
  .quick-question:hover {
@@ -1063,7 +1077,7 @@
1063
1077
  }
1064
1078
  </style>
1065
1079
  </head>
1066
- <body class="light">
1080
+ <body class="dark">
1067
1081
  <div class="container">
1068
1082
  <!-- Header -->
1069
1083
  <header class="header">
@@ -1184,7 +1198,7 @@
1184
1198
  <aside class="input-panel">
1185
1199
  <!-- Quick Questions Card -->
1186
1200
  <div class="card">
1187
- <div class="card-title">Quick Commands</div>
1201
+ <div class="card-title">快捷命令</div>
1188
1202
  <div class="quick-questions">
1189
1203
  <span class="quick-question" onclick="setPrompt('你好,请介绍一下你自己')">👋 自我介绍</span>
1190
1204
  <span class="quick-question" onclick="setPrompt('帮我写一个 Hello World')">Hello World</span>
@@ -1195,19 +1209,19 @@
1195
1209
 
1196
1210
  <!-- Message Type Card -->
1197
1211
  <div class="card">
1198
- <div class="card-title">Message Type</div>
1212
+ <div class="card-title">消息类型</div>
1199
1213
  <div class="msg-type-group">
1200
1214
  <input type="radio" id="type-prompt" name="msgType" value="prompt" checked onchange="onMsgTypeChange()">
1201
- <label for="type-prompt">Prompt</label>
1215
+ <label for="type-prompt" title="发送新的任务请求,AI 会从头开始处理">对话</label>
1202
1216
 
1203
1217
  <input type="radio" id="type-steer" name="msgType" value="steer" onchange="onMsgTypeChange()">
1204
- <label for="type-steer">Steer</label>
1218
+ <label for="type-steer" title="引导或干预当前正在执行的任务,AI 会中断并响应你的引导">引导</label>
1205
1219
 
1206
1220
  <input type="radio" id="type-follow" name="msgType" value="follow_up" onchange="onMsgTypeChange()">
1207
- <label for="type-follow">Follow</label>
1221
+ <label for="type-follow" title="在当前对话基础上继续交流,AI 记得之前的上下文">追问</label>
1208
1222
 
1209
1223
  <input type="radio" id="type-abort" name="msgType" value="abort" onchange="onMsgTypeChange()">
1210
- <label for="type-abort">Abort</label>
1224
+ <label for="type-abort" title="立即终止当前正在执行的任务">中止</label>
1211
1225
  </div>
1212
1226
  </div>
1213
1227
 
@@ -1246,9 +1260,9 @@
1246
1260
 
1247
1261
  // Toggle theme
1248
1262
  function toggleTheme() {
1249
- document.body.classList.toggle('light');
1263
+ document.body.classList.toggle('dark');
1250
1264
  const icon = document.getElementById('themeIcon');
1251
- icon.textContent = document.body.classList.contains('light') ? '' : '';
1265
+ icon.textContent = document.body.classList.contains('dark') ? '' : '';
1252
1266
  }
1253
1267
 
1254
1268
  // Toggle width
@@ -1439,11 +1453,12 @@
1439
1453
 
1440
1454
  if (data.success && data.data && data.data.running) {
1441
1455
  statusDot.classList.add('active');
1442
- statusText.textContent = 'Connected';
1456
+ statusDot.classList.remove('disconnected');
1457
+ statusText.textContent = '已连接';
1443
1458
  } else {
1444
1459
  statusDot.classList.remove('active');
1445
- statusText.textContent = 'Not Connected';
1446
- openConfigModal();
1460
+ statusDot.classList.add('disconnected');
1461
+ statusText.textContent = '未连接';
1447
1462
  }
1448
1463
  } catch (e) {
1449
1464
  console.error('Check status error:', e);
@@ -1471,13 +1486,19 @@
1471
1486
 
1472
1487
  if (data.running) {
1473
1488
  statusDot.classList.add('active');
1474
- statusText.textContent = 'Connected';
1489
+ statusDot.classList.remove('disconnected');
1490
+ statusText.textContent = '已连接';
1475
1491
  } else {
1476
1492
  statusDot.classList.remove('active');
1477
- statusText.textContent = 'Disconnected';
1493
+ statusDot.classList.add('disconnected');
1494
+ statusText.textContent = '未连接';
1478
1495
  }
1479
1496
  } catch (e) {
1480
- document.getElementById('statusText').textContent = 'Error';
1497
+ const statusDot = document.getElementById('statusDot');
1498
+ const statusText = document.getElementById('statusText');
1499
+ statusDot.classList.remove('active');
1500
+ statusDot.classList.add('disconnected');
1501
+ statusText.textContent = '连接错误';
1481
1502
  }
1482
1503
  }
1483
1504
 
@@ -1491,12 +1512,12 @@
1491
1512
  const msgType = getMsgType();
1492
1513
  const input = document.getElementById('promptInput');
1493
1514
  const placeholder = {
1494
- 'prompt': 'Enter your message...',
1495
- 'steer': 'Enter steer message (interrupts current operation)...',
1496
- 'follow_up': 'Enter follow-up message...',
1497
- 'abort': 'Confirm abort?'
1515
+ 'prompt': '输入你的任务描述,AI 会从头开始处理...',
1516
+ 'steer': '输入引导信息,干预当前正在执行的任务...',
1517
+ 'follow_up': '输入追问内容,AI 会基于之前的上下文继续...',
1518
+ 'abort': '点击发送即可立即终止当前任务'
1498
1519
  };
1499
- input.placeholder = placeholder[msgType] || 'Enter your message...';
1520
+ input.placeholder = placeholder[msgType] || '输入你的任务描述...';
1500
1521
 
1501
1522
  if (msgType === 'abort') {
1502
1523
  input.value = '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ia-ccun/code-agent-claw",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Code Agent Claw WebUI - Node.js implementation with frontend configuration",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/public/index.html CHANGED
@@ -382,11 +382,22 @@
382
382
  animation: pulse 2s ease-in-out infinite;
383
383
  }
384
384
 
385
+ .status-dot.disconnected {
386
+ background: var(--error);
387
+ box-shadow: 0 0 8px rgba(201, 74, 74, 0.5);
388
+ animation: pulse-red 1.5s ease-in-out infinite;
389
+ }
390
+
385
391
  @keyframes pulse {
386
392
  0%, 100% { opacity: 1; }
387
393
  50% { opacity: 0.6; }
388
394
  }
389
395
 
396
+ @keyframes pulse-red {
397
+ 0%, 100% { opacity: 1; box-shadow: 0 0 8px rgba(201, 74, 74, 0.5); }
398
+ 50% { opacity: 0.5; box-shadow: 0 0 16px rgba(201, 74, 74, 0.8); }
399
+ }
400
+
390
401
  /* Action buttons */
391
402
  .action-btn {
392
403
  width: 36px;
@@ -855,8 +866,9 @@
855
866
  /* Quick questions */
856
867
  .quick-questions {
857
868
  display: flex;
858
- flex-wrap: wrap;
869
+ flex-wrap: nowrap;
859
870
  gap: var(--space-sm);
871
+ overflow-x: auto;
860
872
  }
861
873
 
862
874
  .quick-question {
@@ -869,6 +881,8 @@
869
881
  color: var(--text-secondary);
870
882
  cursor: pointer;
871
883
  transition: all 0.2s ease;
884
+ white-space: nowrap;
885
+ flex-shrink: 0;
872
886
  }
873
887
 
874
888
  .quick-question:hover {
@@ -1063,7 +1077,7 @@
1063
1077
  }
1064
1078
  </style>
1065
1079
  </head>
1066
- <body class="light">
1080
+ <body class="dark">
1067
1081
  <div class="container">
1068
1082
  <!-- Header -->
1069
1083
  <header class="header">
@@ -1184,7 +1198,7 @@
1184
1198
  <aside class="input-panel">
1185
1199
  <!-- Quick Questions Card -->
1186
1200
  <div class="card">
1187
- <div class="card-title">Quick Commands</div>
1201
+ <div class="card-title">快捷命令</div>
1188
1202
  <div class="quick-questions">
1189
1203
  <span class="quick-question" onclick="setPrompt('你好,请介绍一下你自己')">👋 自我介绍</span>
1190
1204
  <span class="quick-question" onclick="setPrompt('帮我写一个 Hello World')">Hello World</span>
@@ -1195,19 +1209,19 @@
1195
1209
 
1196
1210
  <!-- Message Type Card -->
1197
1211
  <div class="card">
1198
- <div class="card-title">Message Type</div>
1212
+ <div class="card-title">消息类型</div>
1199
1213
  <div class="msg-type-group">
1200
1214
  <input type="radio" id="type-prompt" name="msgType" value="prompt" checked onchange="onMsgTypeChange()">
1201
- <label for="type-prompt">Prompt</label>
1215
+ <label for="type-prompt" title="发送新的任务请求,AI 会从头开始处理">对话</label>
1202
1216
 
1203
1217
  <input type="radio" id="type-steer" name="msgType" value="steer" onchange="onMsgTypeChange()">
1204
- <label for="type-steer">Steer</label>
1218
+ <label for="type-steer" title="引导或干预当前正在执行的任务,AI 会中断并响应你的引导">引导</label>
1205
1219
 
1206
1220
  <input type="radio" id="type-follow" name="msgType" value="follow_up" onchange="onMsgTypeChange()">
1207
- <label for="type-follow">Follow</label>
1221
+ <label for="type-follow" title="在当前对话基础上继续交流,AI 记得之前的上下文">追问</label>
1208
1222
 
1209
1223
  <input type="radio" id="type-abort" name="msgType" value="abort" onchange="onMsgTypeChange()">
1210
- <label for="type-abort">Abort</label>
1224
+ <label for="type-abort" title="立即终止当前正在执行的任务">中止</label>
1211
1225
  </div>
1212
1226
  </div>
1213
1227
 
@@ -1246,9 +1260,9 @@
1246
1260
 
1247
1261
  // Toggle theme
1248
1262
  function toggleTheme() {
1249
- document.body.classList.toggle('light');
1263
+ document.body.classList.toggle('dark');
1250
1264
  const icon = document.getElementById('themeIcon');
1251
- icon.textContent = document.body.classList.contains('light') ? '' : '';
1265
+ icon.textContent = document.body.classList.contains('dark') ? '' : '';
1252
1266
  }
1253
1267
 
1254
1268
  // Toggle width
@@ -1439,11 +1453,12 @@
1439
1453
 
1440
1454
  if (data.success && data.data && data.data.running) {
1441
1455
  statusDot.classList.add('active');
1442
- statusText.textContent = 'Connected';
1456
+ statusDot.classList.remove('disconnected');
1457
+ statusText.textContent = '已连接';
1443
1458
  } else {
1444
1459
  statusDot.classList.remove('active');
1445
- statusText.textContent = 'Not Connected';
1446
- openConfigModal();
1460
+ statusDot.classList.add('disconnected');
1461
+ statusText.textContent = '未连接';
1447
1462
  }
1448
1463
  } catch (e) {
1449
1464
  console.error('Check status error:', e);
@@ -1471,13 +1486,19 @@
1471
1486
 
1472
1487
  if (data.running) {
1473
1488
  statusDot.classList.add('active');
1474
- statusText.textContent = 'Connected';
1489
+ statusDot.classList.remove('disconnected');
1490
+ statusText.textContent = '已连接';
1475
1491
  } else {
1476
1492
  statusDot.classList.remove('active');
1477
- statusText.textContent = 'Disconnected';
1493
+ statusDot.classList.add('disconnected');
1494
+ statusText.textContent = '未连接';
1478
1495
  }
1479
1496
  } catch (e) {
1480
- document.getElementById('statusText').textContent = 'Error';
1497
+ const statusDot = document.getElementById('statusDot');
1498
+ const statusText = document.getElementById('statusText');
1499
+ statusDot.classList.remove('active');
1500
+ statusDot.classList.add('disconnected');
1501
+ statusText.textContent = '连接错误';
1481
1502
  }
1482
1503
  }
1483
1504
 
@@ -1491,12 +1512,12 @@
1491
1512
  const msgType = getMsgType();
1492
1513
  const input = document.getElementById('promptInput');
1493
1514
  const placeholder = {
1494
- 'prompt': 'Enter your message...',
1495
- 'steer': 'Enter steer message (interrupts current operation)...',
1496
- 'follow_up': 'Enter follow-up message...',
1497
- 'abort': 'Confirm abort?'
1515
+ 'prompt': '输入你的任务描述,AI 会从头开始处理...',
1516
+ 'steer': '输入引导信息,干预当前正在执行的任务...',
1517
+ 'follow_up': '输入追问内容,AI 会基于之前的上下文继续...',
1518
+ 'abort': '点击发送即可立即终止当前任务'
1498
1519
  };
1499
- input.placeholder = placeholder[msgType] || 'Enter your message...';
1520
+ input.placeholder = placeholder[msgType] || '输入你的任务描述...';
1500
1521
 
1501
1522
  if (msgType === 'abort') {
1502
1523
  input.value = '';
@@ -1750,7 +1771,19 @@
1750
1771
 
1751
1772
  // WebSocket
1752
1773
  let ws;
1774
+ let reconnectTimer;
1753
1775
  function connectWebSocket() {
1776
+ // 清除之前的重连定时器
1777
+ if (reconnectTimer) {
1778
+ clearTimeout(reconnectTimer);
1779
+ reconnectTimer = null;
1780
+ }
1781
+
1782
+ // 关闭旧的连接
1783
+ if (ws && ws.readyState === WebSocket.OPEN) {
1784
+ ws.close();
1785
+ }
1786
+
1754
1787
  const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
1755
1788
  const wsUrl = `${protocol}//${window.location.host}/ws/agent`;
1756
1789
 
@@ -1771,7 +1804,7 @@
1771
1804
  };
1772
1805
 
1773
1806
  ws.onclose = () => {
1774
- setTimeout(connectWebSocket, 3000);
1807
+ reconnectTimer = setTimeout(connectWebSocket, 3000);
1775
1808
  };
1776
1809
  }
1777
1810