chatccc 0.2.178 → 0.2.179
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.md +4 -4
- package/config.sample.json +3 -1
- package/package.json +1 -1
- package/src/__tests__/card-plain-text.test.ts +1 -1
- package/src/__tests__/config-reload.test.ts +29 -22
- package/src/__tests__/feishu-avatar.test.ts +219 -129
- package/src/__tests__/orchestrator.test.ts +163 -93
- package/src/cards.ts +6 -6
- package/src/config.ts +31 -2
- package/src/cursor-usage.ts +128 -0
- package/src/feishu-api.ts +65 -9
- package/src/index.ts +1 -1
- package/src/orchestrator.ts +217 -131
- package/src/web-ui.ts +95 -11
package/src/web-ui.ts
CHANGED
|
@@ -33,7 +33,15 @@ interface AppConfig {
|
|
|
33
33
|
gitTimeoutSeconds?: number;
|
|
34
34
|
claude?: { enabled?: boolean; defaultAgent?: boolean; model?: string; subagentModel?: string; effort?: string; apiKey?: string; baseUrl?: string; maxTurn?: number };
|
|
35
35
|
// `command` 是已废弃的旧字段名,保留只读以兼容升级前的 config.json
|
|
36
|
-
cursor?: {
|
|
36
|
+
cursor?: {
|
|
37
|
+
enabled?: boolean;
|
|
38
|
+
defaultAgent?: boolean;
|
|
39
|
+
path?: string;
|
|
40
|
+
command?: string;
|
|
41
|
+
model?: string;
|
|
42
|
+
avatarBatteryMode?: string;
|
|
43
|
+
onDemandMonthlyBudget?: number;
|
|
44
|
+
};
|
|
37
45
|
codex?: { enabled?: boolean; defaultAgent?: boolean; path?: string; command?: string; model?: string; effort?: string };
|
|
38
46
|
}
|
|
39
47
|
|
|
@@ -362,6 +370,12 @@ export function unflattenConfig(flat: Record<string, unknown>): Record<string, u
|
|
|
362
370
|
} else if (key === "CHATCCC_CURSOR_MODEL") {
|
|
363
371
|
result.cursor = result.cursor || {};
|
|
364
372
|
(result.cursor as Record<string, unknown>).model = val;
|
|
373
|
+
} else if (key === "CHATCCC_CURSOR_AVATAR_BATTERY_MODE") {
|
|
374
|
+
result.cursor = result.cursor || {};
|
|
375
|
+
(result.cursor as Record<string, unknown>).avatarBatteryMode = val;
|
|
376
|
+
} else if (key === "CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET") {
|
|
377
|
+
result.cursor = result.cursor || {};
|
|
378
|
+
(result.cursor as Record<string, unknown>).onDemandMonthlyBudget = Number(val);
|
|
365
379
|
} else if (key === "CHATCCC_CURSOR_ENABLED") {
|
|
366
380
|
result.cursor = result.cursor || {};
|
|
367
381
|
(result.cursor as Record<string, unknown>).enabled = val === true || val === "true";
|
|
@@ -480,7 +494,7 @@ async function handleForgetIlink(_req: IncomingMessage, res: ServerResponse): Pr
|
|
|
480
494
|
// HTML page (embedded template)
|
|
481
495
|
// ---------------------------------------------------------------------------
|
|
482
496
|
|
|
483
|
-
export const PAGE_HTML = `<!DOCTYPE html>
|
|
497
|
+
export const PAGE_HTML = `<!DOCTYPE html>
|
|
484
498
|
<html lang="zh-CN">
|
|
485
499
|
<head>
|
|
486
500
|
<meta charset="UTF-8">
|
|
@@ -697,6 +711,17 @@ header .badge{font-size:13px;padding:4px 12px;border-radius:12px;font-weight:500
|
|
|
697
711
|
<label>模型</label>
|
|
698
712
|
<input type="text" id="field-CHATCCC_CURSOR_MODEL" placeholder="留空表示不传 --model">
|
|
699
713
|
</div>
|
|
714
|
+
<div class="form-group">
|
|
715
|
+
<label>头像电池电量</label>
|
|
716
|
+
<select id="field-CHATCCC_CURSOR_AVATAR_BATTERY_MODE" onchange="onCursorBatteryModeChange('field-', this.value)" style="width:100%;padding:8px 12px;border:1px solid #cbd5e1;border-radius:8px;font-size:14px;outline:none">
|
|
717
|
+
<option value="apiPercent">API 使用比例</option>
|
|
718
|
+
<option value="onDemandUse">On demand use 金额</option>
|
|
719
|
+
</select>
|
|
720
|
+
</div>
|
|
721
|
+
<div class="form-group" id="field-cursor-on-demand-budget-row" style="display:none">
|
|
722
|
+
<label>每月On demand use预算</label>
|
|
723
|
+
<input type="number" id="field-CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET" min="1" step="1" placeholder="1000">
|
|
724
|
+
</div>
|
|
700
725
|
<button class="btn btn-outline" onclick="validateCli('cursor')" style="margin-bottom:12px">检测 Cursor CLI</button>
|
|
701
726
|
<div id="cursor-validate-result"></div>
|
|
702
727
|
</fieldset>
|
|
@@ -819,6 +844,8 @@ header .badge{font-size:13px;padding:4px 12px;border-radius:12px;font-weight:500
|
|
|
819
844
|
<div class="section-detail">
|
|
820
845
|
<div class="config-row"><span class="key">CLI 路径</span><span class="val" id="cfg-CURSOR_PATH">-</span></div>
|
|
821
846
|
<div class="config-row"><span class="key">模型</span><span class="val" id="cfg-CURSOR_MODEL">-</span></div>
|
|
847
|
+
<div class="config-row"><span class="key">头像电池电量</span><span class="val" id="cfg-CURSOR_AVATAR_BATTERY_MODE">-</span></div>
|
|
848
|
+
<div class="config-row" id="cfg-CURSOR_ON_DEMAND_MONTHLY_BUDGET_ROW"><span class="key">每月On demand use预算</span><span class="val" id="cfg-CURSOR_ON_DEMAND_MONTHLY_BUDGET">-</span></div>
|
|
822
849
|
<label class="agent-default-row" style="margin-top:10px"><input type="checkbox" id="dash-default-cursor" onchange="setDashboardDefaultAgent('cursor', this.checked)"> 设为默认 Agent</label>
|
|
823
850
|
<button class="btn btn-outline" style="margin-top:8px" onclick="editSection('cursor')">编辑</button>
|
|
824
851
|
</div>
|
|
@@ -876,11 +903,21 @@ var step2InputBound = false;
|
|
|
876
903
|
|
|
877
904
|
const AGENT_FIELDS = {
|
|
878
905
|
claude: ['CHATCCC_ANTHROPIC_MODEL','CHATCCC_ANTHROPIC_SUBAGENT_MODEL','CHATCCC_ANTHROPIC_EFFORT','CHATCCC_ANTHROPIC_API_KEY','CHATCCC_ANTHROPIC_BASE_URL','CHATCCC_ANTHROPIC_MAX_TURN'],
|
|
879
|
-
cursor: ['CHATCCC_CURSOR_PATH','CHATCCC_CURSOR_MODEL'],
|
|
906
|
+
cursor: ['CHATCCC_CURSOR_PATH','CHATCCC_CURSOR_MODEL','CHATCCC_CURSOR_AVATAR_BATTERY_MODE','CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET'],
|
|
880
907
|
codex: ['CHATCCC_CODEX_PATH','CHATCCC_CODEX_MODEL','CHATCCC_CODEX_EFFORT']
|
|
881
908
|
};
|
|
882
909
|
const FEISHU_FIELDS = ['CHATCCC_APP_ID','CHATCCC_APP_SECRET'];
|
|
883
910
|
|
|
911
|
+
function cursorBatteryModeLabel(value) {
|
|
912
|
+
return value === 'onDemandUse' ? 'On demand use 金额' : 'API 使用比例';
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
function onCursorBatteryModeChange(prefix, value) {
|
|
916
|
+
var rowId = prefix === 'edit-' ? 'edit-cursor-on-demand-budget-row' : 'field-cursor-on-demand-budget-row';
|
|
917
|
+
var row = document.getElementById(rowId);
|
|
918
|
+
if (row) row.style.display = value === 'onDemandUse' ? '' : 'none';
|
|
919
|
+
}
|
|
920
|
+
|
|
884
921
|
function onWizardPlatformToggle(platform, enabled) {
|
|
885
922
|
state.platformsEnabled[platform] = enabled;
|
|
886
923
|
// 飞书凭证字段跟随开关显示/隐藏
|
|
@@ -1127,7 +1164,18 @@ function renderStep2() {
|
|
|
1127
1164
|
if (c.cursor) {
|
|
1128
1165
|
prefillNested('field-CHATCCC_CURSOR_PATH', c.cursor.path || c.cursor.command);
|
|
1129
1166
|
prefillNested('field-CHATCCC_CURSOR_MODEL', c.cursor.model);
|
|
1167
|
+
var cursorMode = c.cursor.avatarBatteryMode || 'apiPercent';
|
|
1168
|
+
var cursorModeInput = document.getElementById('field-CHATCCC_CURSOR_AVATAR_BATTERY_MODE');
|
|
1169
|
+
if (cursorModeInput) cursorModeInput.value = cursorMode;
|
|
1170
|
+
prefillNested('field-CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET', c.cursor.onDemandMonthlyBudget || 1000);
|
|
1171
|
+
} else {
|
|
1172
|
+
var defaultCursorModeInput = document.getElementById('field-CHATCCC_CURSOR_AVATAR_BATTERY_MODE');
|
|
1173
|
+
if (defaultCursorModeInput) defaultCursorModeInput.value = 'apiPercent';
|
|
1174
|
+
prefillNested('field-CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET', 1000);
|
|
1130
1175
|
}
|
|
1176
|
+
var cursorBatteryModeEl = document.getElementById('field-CHATCCC_CURSOR_AVATAR_BATTERY_MODE');
|
|
1177
|
+
if (cursorBatteryModeEl && !cursorBatteryModeEl.value) cursorBatteryModeEl.value = 'apiPercent';
|
|
1178
|
+
onCursorBatteryModeChange('field-', cursorBatteryModeEl ? cursorBatteryModeEl.value : 'apiPercent');
|
|
1131
1179
|
if (c.codex) {
|
|
1132
1180
|
prefillNested('field-CHATCCC_CODEX_PATH', c.codex.path || c.codex.command);
|
|
1133
1181
|
prefillNested('field-CHATCCC_CODEX_MODEL', c.codex.model);
|
|
@@ -1256,6 +1304,10 @@ function renderStep3() {
|
|
|
1256
1304
|
lines.push('<h4 style="margin:10px 0 4px;color:#334155">Cursor</h4>');
|
|
1257
1305
|
if (vars.CHATCCC_CURSOR_PATH) lines.push('<div class="config-row"><span class="key">CLI 路径</span><span class="val">' + vars.CHATCCC_CURSOR_PATH + '</span></div>');
|
|
1258
1306
|
lines.push('<div class="config-row"><span class="key">模型</span><span class="val">' + (vars.CHATCCC_CURSOR_MODEL || '(留空)') + '</span></div>');
|
|
1307
|
+
lines.push('<div class="config-row"><span class="key">头像电池电量</span><span class="val">' + cursorBatteryModeLabel(vars.CHATCCC_CURSOR_AVATAR_BATTERY_MODE) + '</span></div>');
|
|
1308
|
+
if (vars.CHATCCC_CURSOR_AVATAR_BATTERY_MODE === 'onDemandUse') {
|
|
1309
|
+
lines.push('<div class="config-row"><span class="key">每月On demand use预算</span><span class="val">' + (vars.CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET || '1000') + '</span></div>');
|
|
1310
|
+
}
|
|
1259
1311
|
} else if (t === 'codex') {
|
|
1260
1312
|
lines.push('<h4 style="margin:10px 0 4px;color:#334155">Codex</h4>');
|
|
1261
1313
|
if (vars.CHATCCC_CODEX_PATH) lines.push('<div class="config-row"><span class="key">CLI 路径</span><span class="val">' + vars.CHATCCC_CODEX_PATH + '</span></div>');
|
|
@@ -1435,6 +1487,11 @@ function updateDashboardUI() {
|
|
|
1435
1487
|
document.getElementById('cfg-ANTHROPIC_MAX_TURN').textContent = (c.claude && c.claude.maxTurn != null) ? String(c.claude.maxTurn) : '0';
|
|
1436
1488
|
document.getElementById('cfg-CURSOR_PATH').textContent = (c.cursor && (c.cursor.path || c.cursor.command)) || '-';
|
|
1437
1489
|
document.getElementById('cfg-CURSOR_MODEL').textContent = (c.cursor && c.cursor.model) || '(留空)';
|
|
1490
|
+
var cursorBatteryMode = (c.cursor && c.cursor.avatarBatteryMode) || 'apiPercent';
|
|
1491
|
+
document.getElementById('cfg-CURSOR_AVATAR_BATTERY_MODE').textContent = cursorBatteryModeLabel(cursorBatteryMode);
|
|
1492
|
+
var cursorBudgetRow = document.getElementById('cfg-CURSOR_ON_DEMAND_MONTHLY_BUDGET_ROW');
|
|
1493
|
+
if (cursorBudgetRow) cursorBudgetRow.style.display = cursorBatteryMode === 'onDemandUse' ? '' : 'none';
|
|
1494
|
+
document.getElementById('cfg-CURSOR_ON_DEMAND_MONTHLY_BUDGET').textContent = String((c.cursor && c.cursor.onDemandMonthlyBudget) || 1000);
|
|
1438
1495
|
document.getElementById('cfg-CODEX_PATH').textContent = (c.codex && (c.codex.path || c.codex.command)) || 'codex';
|
|
1439
1496
|
document.getElementById('cfg-CODEX_MODEL').textContent = (c.codex && c.codex.model) || '(留空)';
|
|
1440
1497
|
document.getElementById('cfg-CODEX_EFFORT').textContent = (c.codex && c.codex.effort) || '(留空)';
|
|
@@ -1500,6 +1557,8 @@ function editSection(section) {
|
|
|
1500
1557
|
'CHATCCC_ANTHROPIC_MODEL': '模型', 'CHATCCC_ANTHROPIC_SUBAGENT_MODEL': 'Subagent 模型', 'CHATCCC_ANTHROPIC_EFFORT': 'Effort',
|
|
1501
1558
|
'CHATCCC_ANTHROPIC_API_KEY': 'API Key', 'CHATCCC_ANTHROPIC_BASE_URL': 'Base URL', 'CHATCCC_ANTHROPIC_MAX_TURN': 'Max Turns (0=无限制)',
|
|
1502
1559
|
'CHATCCC_CURSOR_PATH': 'CLI 路径', 'CHATCCC_CURSOR_MODEL': '模型',
|
|
1560
|
+
'CHATCCC_CURSOR_AVATAR_BATTERY_MODE': '头像电池电量',
|
|
1561
|
+
'CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET': '每月On demand use预算',
|
|
1503
1562
|
'CHATCCC_CODEX_PATH': 'CLI 路径', 'CHATCCC_CODEX_MODEL': '模型', 'CHATCCC_CODEX_EFFORT': 'Effort'
|
|
1504
1563
|
};
|
|
1505
1564
|
|
|
@@ -1520,6 +1579,8 @@ function editSection(section) {
|
|
|
1520
1579
|
} else if (section === 'cursor' && state.config.cursor) {
|
|
1521
1580
|
if (key === 'CHATCCC_CURSOR_PATH') val = state.config.cursor.path || state.config.cursor.command || '';
|
|
1522
1581
|
else if (key === 'CHATCCC_CURSOR_MODEL') val = state.config.cursor.model || '';
|
|
1582
|
+
else if (key === 'CHATCCC_CURSOR_AVATAR_BATTERY_MODE') val = state.config.cursor.avatarBatteryMode || 'apiPercent';
|
|
1583
|
+
else if (key === 'CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET') val = (state.config.cursor.onDemandMonthlyBudget != null) ? String(state.config.cursor.onDemandMonthlyBudget) : '1000';
|
|
1523
1584
|
} else if (section === 'codex' && state.config.codex) {
|
|
1524
1585
|
if (key === 'CHATCCC_CODEX_PATH') val = state.config.codex.path || state.config.codex.command || '';
|
|
1525
1586
|
else if (key === 'CHATCCC_CODEX_MODEL') val = state.config.codex.model || '';
|
|
@@ -1527,9 +1588,21 @@ function editSection(section) {
|
|
|
1527
1588
|
}
|
|
1528
1589
|
}
|
|
1529
1590
|
var isSecret = key.includes('SECRET') || key.includes('API_KEY');
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1591
|
+
if (key === 'CHATCCC_CURSOR_AVATAR_BATTERY_MODE') {
|
|
1592
|
+
var modeVal = val || 'apiPercent';
|
|
1593
|
+
html += '<div class="form-group"><label>' + (labelMap[key] || key) + '</label>';
|
|
1594
|
+
html += '<select id="edit-' + key + '" onchange="onCursorBatteryModeChange(\\'edit-\\', this.value)" style="width:100%;padding:8px 12px;border:1px solid #cbd5e1;border-radius:8px;font-size:14px;outline:none">';
|
|
1595
|
+
html += '<option value="apiPercent"' + (modeVal === 'apiPercent' ? ' selected' : '') + '>API 使用比例</option>';
|
|
1596
|
+
html += '<option value="onDemandUse"' + (modeVal === 'onDemandUse' ? ' selected' : '') + '>On demand use 金额</option>';
|
|
1597
|
+
html += '</select></div>';
|
|
1598
|
+
} else {
|
|
1599
|
+
var rowId = key === 'CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET' ? ' id="edit-cursor-on-demand-budget-row"' : '';
|
|
1600
|
+
var inputType = key === 'CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET' ? 'number' : (isSecret ? 'password' : 'text');
|
|
1601
|
+
var attrs = key === 'CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET' ? ' min="1" step="1"' : '';
|
|
1602
|
+
html += '<div class="form-group"' + rowId + '><label>' + (labelMap[key] || key) + '</label>';
|
|
1603
|
+
html += '<input type="' + inputType + '" id="edit-' + key + '"' + attrs + ' value="' + String(val).replace(/"/g,'"') + '">';
|
|
1604
|
+
html += '</div>';
|
|
1605
|
+
}
|
|
1533
1606
|
});
|
|
1534
1607
|
// 平台类型:feishu 编辑时额外渲染下拉选择框
|
|
1535
1608
|
if (section === 'feishu') {
|
|
@@ -1539,11 +1612,15 @@ function editSection(section) {
|
|
|
1539
1612
|
html += '<option value="feishu"' + (ptVal === 'feishu' ? ' selected' : '') + '>飞书 (open.feishu.cn)</option>';
|
|
1540
1613
|
html += '<option value="lark"' + (ptVal === 'lark' ? ' selected' : '') + '>Lark (open.larksuite.com)</option>';
|
|
1541
1614
|
html += '</select></div>';
|
|
1542
|
-
}
|
|
1543
|
-
document.getElementById('edit-modal-fields').innerHTML = html;
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1615
|
+
}
|
|
1616
|
+
document.getElementById('edit-modal-fields').innerHTML = html;
|
|
1617
|
+
if (section === 'cursor') {
|
|
1618
|
+
var editModeEl = document.getElementById('edit-CHATCCC_CURSOR_AVATAR_BATTERY_MODE');
|
|
1619
|
+
onCursorBatteryModeChange('edit-', editModeEl ? editModeEl.value : 'apiPercent');
|
|
1620
|
+
}
|
|
1621
|
+
document.getElementById('edit-modal').classList.remove('hidden');
|
|
1622
|
+
document.getElementById('edit-overlay').classList.remove('hidden');
|
|
1623
|
+
}
|
|
1547
1624
|
|
|
1548
1625
|
function closeEditModal() {
|
|
1549
1626
|
document.getElementById('edit-modal').classList.add('hidden');
|
|
@@ -1561,12 +1638,19 @@ async function saveEdit() {
|
|
|
1561
1638
|
var el = document.getElementById('edit-' + key);
|
|
1562
1639
|
if (el) vars[key] = el.value.trim();
|
|
1563
1640
|
});
|
|
1641
|
+
if (editSectionType === 'cursor' && vars.CHATCCC_CURSOR_AVATAR_BATTERY_MODE === 'onDemandUse' && !vars.CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET) {
|
|
1642
|
+
vars.CHATCCC_CURSOR_ON_DEMAND_MONTHLY_BUDGET = '1000';
|
|
1643
|
+
}
|
|
1564
1644
|
// 平台类型:feishu 编辑时额外采集下拉选择框的值
|
|
1565
1645
|
if (editSectionType === 'feishu') {
|
|
1566
1646
|
var ptEl = document.getElementById('edit-CHATCCC_FEISHU_PLATFORM_TYPE');
|
|
1567
1647
|
if (ptEl && ptEl.value.trim()) vars['CHATCCC_FEISHU_PLATFORM_TYPE'] = ptEl.value.trim();
|
|
1568
1648
|
}
|
|
1569
1649
|
await saveConfig(vars);
|
|
1650
|
+
try {
|
|
1651
|
+
var fresh = await api('/api/config');
|
|
1652
|
+
state.config = fresh.vars || state.config;
|
|
1653
|
+
} catch(e) {}
|
|
1570
1654
|
closeEditModal();
|
|
1571
1655
|
updateDashboardUI();
|
|
1572
1656
|
toast('修改已保存。若服务正在运行,需重启生效。');
|