aicq-openclaw-plugin 1.0.6 → 1.0.7
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.js +320 -77
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7826,12 +7826,12 @@ var v4_default = v4;
|
|
|
7826
7826
|
|
|
7827
7827
|
// dist/config.js
|
|
7828
7828
|
var __filename = fileURLToPath(import.meta.url);
|
|
7829
|
-
var
|
|
7829
|
+
var __dirname2 = path.dirname(__filename);
|
|
7830
7830
|
var SERVER_URL = process.env.AICQ_SERVER_URL || "https://aicq.online:61018";
|
|
7831
7831
|
function loadConfig(overrides) {
|
|
7832
7832
|
let schemaDefaults = {};
|
|
7833
7833
|
try {
|
|
7834
|
-
const manifestPath = path.resolve(
|
|
7834
|
+
const manifestPath = path.resolve(__dirname2, "..", "openclaw.plugin.json");
|
|
7835
7835
|
const manifestRaw = fs.readFileSync(manifestPath, "utf-8");
|
|
7836
7836
|
const manifest = JSON.parse(manifestRaw);
|
|
7837
7837
|
const schema = manifest.configSchema;
|
|
@@ -10192,91 +10192,86 @@ function loadPage(page) {
|
|
|
10192
10192
|
}
|
|
10193
10193
|
|
|
10194
10194
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
10195
|
-
// PAGE: Dashboard
|
|
10195
|
+
// PAGE: Dashboard \u2014 render skeleton immediately, load data async
|
|
10196
10196
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
10197
10197
|
async function loadDashboard() {
|
|
10198
10198
|
const el = $('#dashboard-content');
|
|
10199
|
-
|
|
10199
|
+
// Render skeleton immediately \u2014 never show spinner that blocks UI
|
|
10200
|
+
html(el, \\\`
|
|
10201
|
+
<div class="stats-grid">
|
|
10202
|
+
<div class="stat-card"><div class="stat-icon" style="background:var(--accent-bg)">\u{1F4E1}</div><div class="stat-label">Server Status</div><div class="stat-value" style="font-size:16px"><div class="spinner" style="width:16px;height:16px;border-width:2px;margin:0 auto"></div></div><div class="stat-sub" id="dash-server-url">Loading...</div></div>
|
|
10203
|
+
<div class="stat-card"><div class="stat-icon" style="background:var(--ok-bg)">\u{1F465}</div><div class="stat-label">Total Friends</div><div class="stat-value" id="dash-friend-count"><div class="spinner" style="width:16px;height:16px;border-width:2px;margin:0 auto"></div></div><div class="stat-sub" id="dash-friend-sub">loading...</div></div>
|
|
10204
|
+
<div class="stat-card"><div class="stat-icon" style="background:var(--info-bg)">\u{1F517}</div><div class="stat-label">Active Sessions</div><div class="stat-value" id="dash-sessions"><div class="spinner" style="width:16px;height:16px;border-width:2px;margin:0 auto"></div></div><div class="stat-sub">Encrypted sessions</div></div>
|
|
10205
|
+
<div class="stat-card"><div class="stat-icon" style="background:var(--warn-bg)">\u{1F511}</div><div class="stat-label">Agent ID</div><div class="stat-value mono" style="font-size:13px" id="dash-agent-id">\u2014</div><div class="stat-sub" id="dash-fingerprint">\u2014</div></div>
|
|
10206
|
+
</div>
|
|
10207
|
+
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px">
|
|
10208
|
+
<div class="card"><div class="card-header"><div class="card-title">\u{1F4CB} Friends</div><button class="btn btn-sm btn-ghost" onclick="navigate('friends')">View All \u2192</button></div><div id="dash-friends-list"><div class="loading-mask" style="padding:20px"><div class="spinner"></div>Loading friends...</div></div></div>
|
|
10209
|
+
<div class="card"><div class="card-header"><div class="card-title">\u{1F916} Identity Info</div></div><div id="dash-identity"><div class="loading-mask" style="padding:20px"><div class="spinner"></div>Loading...</div></div></div>
|
|
10210
|
+
</div>
|
|
10211
|
+
\\\`);
|
|
10200
10212
|
|
|
10201
|
-
// Load
|
|
10202
|
-
const
|
|
10213
|
+
// Load each data source independently \u2014 no await blocking between them
|
|
10214
|
+
const statusRes = await safeApi('/status', { _timeout: 5000 });
|
|
10203
10215
|
const status = statusRes.data || {};
|
|
10204
|
-
const identity = identityRes.data || {};
|
|
10205
|
-
|
|
10206
|
-
// Friends is remote \u2014 load independently, don't block
|
|
10207
|
-
const friendsRes = await safeApi('/friends', { _timeout: 10000 });
|
|
10208
|
-
const friendList = (friendsRes.data?.friends) || [];
|
|
10209
|
-
const friendsError = friendsRes.error;
|
|
10210
10216
|
|
|
10217
|
+
// Update status card immediately
|
|
10211
10218
|
const connCls = status.connected ? 'dot-ok' : 'dot-err';
|
|
10212
10219
|
const connText = status.connected ? 'Connected' : 'Disconnected';
|
|
10213
|
-
const
|
|
10214
|
-
|
|
10220
|
+
const connEl = $('#dash-server-url');
|
|
10221
|
+
if (connEl) connEl.textContent = status.serverUrl || '\u2014';
|
|
10222
|
+
const statusValEl = el.querySelector('.stat-value');
|
|
10223
|
+
if (statusValEl) statusValEl.innerHTML = '<span class="dot ' + connCls + '" style="display:inline-block;width:8px;height:8px;vertical-align:middle"></span> <span style="font-size:16px">' + connText + '</span>';
|
|
10215
10224
|
|
|
10216
|
-
// Update header
|
|
10225
|
+
// Update header dot
|
|
10217
10226
|
const hDot = $('#header-dot');
|
|
10218
|
-
if (hDot) hDot.className = 'dot ' +
|
|
10227
|
+
if (hDot) hDot.className = 'dot ' + connCls;
|
|
10219
10228
|
const hTxt = $('#header-status');
|
|
10220
|
-
if (hTxt) hTxt.textContent =
|
|
10221
|
-
|
|
10222
|
-
//
|
|
10223
|
-
|
|
10224
|
-
if (
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
//
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
10234
|
-
|
|
10235
|
-
|
|
10229
|
+
if (hTxt) hTxt.textContent = connText;
|
|
10230
|
+
|
|
10231
|
+
// Agent ID card
|
|
10232
|
+
const agentEl = $('#dash-agent-id');
|
|
10233
|
+
if (agentEl) agentEl.textContent = status.agentId || '\u2014';
|
|
10234
|
+
const fpEl = $('#dash-fingerprint');
|
|
10235
|
+
if (fpEl) fpEl.textContent = 'Fingerprint: ' + (status.fingerprint || '\u2014');
|
|
10236
|
+
const sessEl = $('#dash-sessions');
|
|
10237
|
+
if (sessEl) sessEl.textContent = status.sessionCount || 0;
|
|
10238
|
+
|
|
10239
|
+
// Identity \u2014 load independently
|
|
10240
|
+
safeApi('/identity', { _timeout: 5000 }).then(identityRes => {
|
|
10241
|
+
const identityEl = $('#dash-identity');
|
|
10242
|
+
if (!identityEl) return;
|
|
10243
|
+
if (identityRes.error) {
|
|
10244
|
+
identityEl.innerHTML = errorBlock('Identity Unavailable', identityRes.error + ' <button class="btn btn-sm btn-default" style="margin-top:8px" onclick="loadDashboard()">\u{1F504} Retry</button>');
|
|
10245
|
+
return;
|
|
10246
|
+
}
|
|
10247
|
+
const identity = identityRes.data || {};
|
|
10248
|
+
identityEl.innerHTML = \\\`
|
|
10236
10249
|
<div class="detail-row"><div class="detail-key">Agent ID</div><div class="detail-val mono" style="cursor:pointer" onclick="copyText('\${escHtml(identity.agentId || '')}')">\${escHtml(identity.agentId || '\u2014')} \u{1F4CB}</div></div>
|
|
10237
10250
|
<div class="detail-row"><div class="detail-key">Fingerprint</div><div class="detail-val mono">\${escHtml(identity.publicKeyFingerprint || '\u2014')}</div></div>
|
|
10238
10251
|
<div class="detail-row"><div class="detail-key">Server URL</div><div class="detail-val mono" style="cursor:pointer" onclick="copyText('\${escHtml(identity.serverUrl || '')}')">\${escHtml(identity.serverUrl || '\u2014')} \u{1F4CB}</div></div>
|
|
10239
10252
|
<div class="detail-row"><div class="detail-key">Connection</div><div class="detail-val"><span class="badge badge-\${identity.connected ? 'ok' : 'danger'}">\${identity.connected ? 'Online' : 'Offline'}</span></div></div>
|
|
10240
10253
|
\\\`;
|
|
10241
|
-
}
|
|
10254
|
+
});
|
|
10242
10255
|
|
|
10243
|
-
|
|
10244
|
-
|
|
10245
|
-
|
|
10246
|
-
|
|
10247
|
-
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
|
|
10251
|
-
|
|
10252
|
-
|
|
10253
|
-
|
|
10254
|
-
|
|
10255
|
-
|
|
10256
|
-
|
|
10257
|
-
|
|
10258
|
-
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
<div class="stat-value">\${status.sessionCount || 0}</div>
|
|
10263
|
-
<div class="stat-sub">Encrypted sessions</div>
|
|
10264
|
-
</div>
|
|
10265
|
-
<div class="stat-card">
|
|
10266
|
-
<div class="stat-icon" style="background:var(--warn-bg)">\u{1F511}</div>
|
|
10267
|
-
<div class="stat-label">Agent ID</div>
|
|
10268
|
-
<div class="stat-value mono" style="font-size:13px">\${escHtml(status.agentId || '\u2014')}</div>
|
|
10269
|
-
<div class="stat-sub">Fingerprint: \${escHtml(status.fingerprint || '\u2014')}</div>
|
|
10270
|
-
</div>
|
|
10271
|
-
</div>
|
|
10272
|
-
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px">
|
|
10273
|
-
\${friendsSection}
|
|
10274
|
-
<div class="card">
|
|
10275
|
-
<div class="card-header"><div class="card-title">\u{1F916} Identity Info</div></div>
|
|
10276
|
-
\${identitySection}
|
|
10277
|
-
</div>
|
|
10278
|
-
</div>
|
|
10279
|
-
\\\`);
|
|
10256
|
+
// Friends \u2014 load independently from remote server
|
|
10257
|
+
safeApi('/friends', { _timeout: 10000 }).then(friendsRes => {
|
|
10258
|
+
const fcEl = $('#dash-friend-count');
|
|
10259
|
+
const fsEl = $('#dash-friend-sub');
|
|
10260
|
+
const flEl = $('#dash-friends-list');
|
|
10261
|
+
if (friendsRes.error) {
|
|
10262
|
+
if (fcEl) fcEl.textContent = '\u2014';
|
|
10263
|
+
if (fsEl) fsEl.textContent = 'unavailable';
|
|
10264
|
+
if (flEl) flEl.innerHTML = errorBlock('Friend List Unavailable', friendsRes.error + ' \u2014 Remote server unreachable. <button class="btn btn-sm btn-default" style="margin-top:8px" onclick="loadDashboard()">\u{1F504} Retry</button>');
|
|
10265
|
+
toast('Cannot load friends: ' + friendsRes.error, 'warn');
|
|
10266
|
+
return;
|
|
10267
|
+
}
|
|
10268
|
+
const friendList = friendsRes.data?.friends || [];
|
|
10269
|
+
const aiFriends = friendList.filter(f => f.friendType === 'ai').length;
|
|
10270
|
+
const humanFriends = friendList.filter(f => f.friendType !== 'ai').length;
|
|
10271
|
+
if (fcEl) fcEl.textContent = friendList.length;
|
|
10272
|
+
if (fsEl) fsEl.textContent = aiFriends + ' AI \xB7 ' + humanFriends + ' Human';
|
|
10273
|
+
if (flEl) flEl.innerHTML = renderMiniFriendList(friendList.slice(0, 5));
|
|
10274
|
+
});
|
|
10280
10275
|
}
|
|
10281
10276
|
|
|
10282
10277
|
function renderMiniFriendList(friends) {
|
|
@@ -10678,14 +10673,66 @@ async function saveModelConfig() {
|
|
|
10678
10673
|
}
|
|
10679
10674
|
|
|
10680
10675
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
10681
|
-
// PAGE: Settings
|
|
10676
|
+
// PAGE: Settings \u2014 with Update button
|
|
10682
10677
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
10678
|
+
let _updating = false;
|
|
10679
|
+
|
|
10683
10680
|
async function loadSettings() {
|
|
10684
10681
|
const el = $('#settings-content');
|
|
10685
|
-
|
|
10686
|
-
|
|
10682
|
+
// Render skeleton immediately
|
|
10683
|
+
html(el, \\\`
|
|
10684
|
+
<p class="section-desc">AICQ plugin runtime configuration and system information.</p>
|
|
10685
|
+
<div class="card" id="settings-update-card"><div class="loading-mask" style="padding:20px"><div class="spinner"></div>Loading...</div></div>
|
|
10686
|
+
<div id="settings-rest"></div>
|
|
10687
|
+
\\\`);
|
|
10687
10688
|
|
|
10688
|
-
|
|
10689
|
+
// Load update check, status, identity, config \u2014 all independently
|
|
10690
|
+
const [updateRes, statusRes, identityRes, configRes, pluginRes] = await Promise.all([
|
|
10691
|
+
safeApi('/update/check', { _timeout: 15000 }),
|
|
10692
|
+
safeApi('/status', { _timeout: 5000 }),
|
|
10693
|
+
safeApi('/identity', { _timeout: 5000 }),
|
|
10694
|
+
safeApi('/config', { _timeout: 5000 }),
|
|
10695
|
+
safeApi('/plugin-info', { _timeout: 5000 }),
|
|
10696
|
+
]);
|
|
10697
|
+
|
|
10698
|
+
// \u2500\u2500 Update Card \u2500\u2500
|
|
10699
|
+
const updateCard = $('#settings-update-card');
|
|
10700
|
+
if (updateCard) {
|
|
10701
|
+
const upd = updateRes.data || {};
|
|
10702
|
+
const pInfo = pluginRes.data || {};
|
|
10703
|
+
const currentVer = pInfo.version || upd.currentVersion || 'unknown';
|
|
10704
|
+
const latestVer = upd.latestVersion || currentVer;
|
|
10705
|
+
const hasUpdate = upd.updateAvailable;
|
|
10706
|
+
|
|
10707
|
+
updateCard.innerHTML = \\\`
|
|
10708
|
+
<div class="card-header">
|
|
10709
|
+
<div class="card-title">\u{1F504} Plugin Update</div>
|
|
10710
|
+
<div style="display:flex;gap:6px;align-items:center">
|
|
10711
|
+
<span class="badge badge-\${hasUpdate ? 'warn' : 'ok'}">\${hasUpdate ? 'Update Available!' : 'Up to date'}</span>
|
|
10712
|
+
</div>
|
|
10713
|
+
</div>
|
|
10714
|
+
<div class="detail-row"><div class="detail-key">Current Version</div><div class="detail-val mono">\${escHtml(currentVer)}</div></div>
|
|
10715
|
+
<div class="detail-row"><div class="detail-key">Latest Version</div><div class="detail-val mono">\${escHtml(latestVer)}</div></div>
|
|
10716
|
+
<div class="detail-row"><div class="detail-key">Package</div><div class="detail-val mono">aicq-openclaw-plugin</div></div>
|
|
10717
|
+
\${pluginRes.error ? '' : \\\`
|
|
10718
|
+
<div class="detail-row"><div class="detail-key">Node.js</div><div class="detail-val mono">\${escHtml(pInfo.nodeVersion || '\u2014')}</div></div>
|
|
10719
|
+
<div class="detail-row"><div class="detail-key">Uptime</div><div class="detail-val">\${pInfo.uptime ? Math.floor(pInfo.uptime / 3600) + 'h ' + Math.floor((pInfo.uptime % 3600) / 60) + 'm' : '\u2014'}</div></div>
|
|
10720
|
+
\\\`}
|
|
10721
|
+
<div style="margin-top:16px;display:flex;gap:8px;flex-wrap:wrap">
|
|
10722
|
+
<button class="btn btn-primary" id="btn-check-update" onclick="checkForUpdates()">\u{1F50D} Check for Updates</button>
|
|
10723
|
+
<button class="btn btn-ok \${hasUpdate ? '' : 'btn-ghost'}" id="btn-do-update" onclick="doUpdate(false)">\u{1F4E5} \${hasUpdate ? 'Update to v' + escHtml(latestVer) : 'Incremental Update'}</button>
|
|
10724
|
+
<button class="btn btn-warn" id="btn-force-update" onclick="doUpdate(true)">\u{1F503} Force Reinstall</button>
|
|
10725
|
+
</div>
|
|
10726
|
+
<div id="update-output" style="display:none;margin-top:12px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);padding:12px;max-height:300px;overflow-y:auto">
|
|
10727
|
+
<pre style="font-size:12px;color:var(--text2);white-space:pre-wrap;margin:0" id="update-log"></pre>
|
|
10728
|
+
</div>
|
|
10729
|
+
\\\`;
|
|
10730
|
+
}
|
|
10731
|
+
|
|
10732
|
+
// \u2500\u2500 Rest of settings \u2500\u2500
|
|
10733
|
+
const restEl = $('#settings-rest');
|
|
10734
|
+
if (!restEl) return;
|
|
10735
|
+
let out = '';
|
|
10689
10736
|
|
|
10690
10737
|
// Connection section
|
|
10691
10738
|
if (statusRes.error) {
|
|
@@ -10737,12 +10784,67 @@ async function loadSettings() {
|
|
|
10737
10784
|
<div class="card-header"><div class="card-title">\u{1F4CA} Statistics</div></div>
|
|
10738
10785
|
<div class="detail-row"><div class="detail-key">Friends Count</div><div class="detail-val">\${s.friendCount || 0}</div></div>
|
|
10739
10786
|
<div class="detail-row"><div class="detail-key">Active Sessions</div><div class="detail-val">\${s.sessionCount || 0}</div></div>
|
|
10740
|
-
<div class="detail-row"><div class="detail-key">Plugin Version</div><div class="detail-val"
|
|
10787
|
+
<div class="detail-row"><div class="detail-key">Plugin Version</div><div class="detail-val">\${escHtml(pluginRes.data?.version || 'unknown')}</div></div>
|
|
10741
10788
|
</div>
|
|
10742
10789
|
\\\`;
|
|
10743
10790
|
}
|
|
10744
10791
|
|
|
10745
|
-
|
|
10792
|
+
restEl.innerHTML = out;
|
|
10793
|
+
}
|
|
10794
|
+
|
|
10795
|
+
async function checkForUpdates() {
|
|
10796
|
+
const btn = $('#btn-check-update');
|
|
10797
|
+
if (btn) { btn.disabled = true; btn.textContent = '\u{1F50D} Checking...'; }
|
|
10798
|
+
toast('Checking for updates...', 'info');
|
|
10799
|
+
const data = await api('/update/check', { _timeout: 15000 });
|
|
10800
|
+
if (data.error) { toast('Check failed: ' + data.error, 'err'); }
|
|
10801
|
+
else if (data.updateAvailable) { toast('New version available: v' + data.latestVersion, 'ok'); }
|
|
10802
|
+
else { toast('Plugin is up to date (v' + data.currentVersion + ')', 'ok'); }
|
|
10803
|
+
if (btn) { btn.disabled = false; btn.textContent = '\u{1F50D} Check for Updates'; }
|
|
10804
|
+
loadSettings();
|
|
10805
|
+
}
|
|
10806
|
+
|
|
10807
|
+
async function doUpdate(force) {
|
|
10808
|
+
if (_updating) { toast('Update already in progress...', 'warn'); return; }
|
|
10809
|
+
const label = force ? 'Force reinstall' : 'Incremental update';
|
|
10810
|
+
if (!confirm(label + ' aicq-openclaw-plugin? This will download and install the latest version from npm.')) return;
|
|
10811
|
+
|
|
10812
|
+
_updating = true;
|
|
10813
|
+
const btnDo = $('#btn-do-update');
|
|
10814
|
+
const btnForce = $('#btn-force-update');
|
|
10815
|
+
if (btnDo) btnDo.disabled = true;
|
|
10816
|
+
if (btnForce) btnForce.disabled = true;
|
|
10817
|
+
|
|
10818
|
+
const outputEl = $('#update-output');
|
|
10819
|
+
const logEl = $('#update-log');
|
|
10820
|
+
if (outputEl) outputEl.style.display = 'block';
|
|
10821
|
+
if (logEl) logEl.textContent = 'Starting ' + label.toLowerCase() + '...
|
|
10822
|
+
';
|
|
10823
|
+
toast(label + ' starting...', 'info');
|
|
10824
|
+
|
|
10825
|
+
const r = await api('/update', {
|
|
10826
|
+
method: 'POST',
|
|
10827
|
+
body: JSON.stringify({ force }),
|
|
10828
|
+
_timeout: 120000,
|
|
10829
|
+
});
|
|
10830
|
+
|
|
10831
|
+
if (logEl) logEl.textContent = r.output || r.message || (r.success ? 'Done!' : 'Failed.');
|
|
10832
|
+
if (r.success) {
|
|
10833
|
+
toast('Update successful! Restart the service to apply.', 'ok');
|
|
10834
|
+
if (logEl) logEl.textContent += '
|
|
10835
|
+
|
|
10836
|
+
\u2705 ' + (r.message || 'Done! Please restart the service.');
|
|
10837
|
+
} else {
|
|
10838
|
+
toast('Update failed: ' + (r.message || 'Unknown error'), 'err');
|
|
10839
|
+
if (logEl) logEl.textContent += '
|
|
10840
|
+
|
|
10841
|
+
\u274C ' + (r.message || 'Failed.');
|
|
10842
|
+
}
|
|
10843
|
+
|
|
10844
|
+
_updating = false;
|
|
10845
|
+
if (btnDo) btnDo.disabled = false;
|
|
10846
|
+
if (btnForce) btnForce.disabled = false;
|
|
10847
|
+
loadSettings();
|
|
10746
10848
|
}
|
|
10747
10849
|
|
|
10748
10850
|
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
@@ -10823,7 +10925,7 @@ var HTML = `<!DOCTYPE html>
|
|
|
10823
10925
|
<div class="main-content">
|
|
10824
10926
|
|
|
10825
10927
|
<!-- Dashboard -->
|
|
10826
|
-
<div class="page active" id="page-dashboard"><div id="dashboard-content"
|
|
10928
|
+
<div class="page active" id="page-dashboard"><div id="dashboard-content"></div></div>
|
|
10827
10929
|
|
|
10828
10930
|
<!-- Agents -->
|
|
10829
10931
|
<div class="page" id="page-agents"><div id="agents-content"></div></div>
|
|
@@ -10928,6 +11030,7 @@ function getManagementHTML() {
|
|
|
10928
11030
|
import * as fs5 from "fs";
|
|
10929
11031
|
import * as path5 from "path";
|
|
10930
11032
|
import * as os from "os";
|
|
11033
|
+
import { execSync, exec } from "child_process";
|
|
10931
11034
|
var MODEL_PROVIDERS = [
|
|
10932
11035
|
{ id: "openai", name: "OpenAI", description: "GPT-4o, GPT-4, GPT-3.5, o1, o3", apiKeyHint: "sk-...", modelHint: "gpt-4o", baseUrlHint: "https://api.openai.com/v1", configKey: "openai" },
|
|
10933
11036
|
{ id: "anthropic", name: "Anthropic", description: "Claude 4, Claude 3.5 Sonnet, Haiku, Opus", apiKeyHint: "sk-ant-...", modelHint: "claude-sonnet-4-20250514", baseUrlHint: "https://api.anthropic.com", configKey: "anthropic" },
|
|
@@ -11412,6 +11515,146 @@ function createManagementHandler(ctx) {
|
|
|
11412
11515
|
logger.info("[API] Model config saved for provider: " + providerId);
|
|
11413
11516
|
return json(res, { success: true, message: "Model configuration saved for " + provider.name });
|
|
11414
11517
|
}
|
|
11518
|
+
if (apiPath === "/update/check" && method === "GET") {
|
|
11519
|
+
try {
|
|
11520
|
+
const pkgPath = path5.join(__dirname, "..", "package.json");
|
|
11521
|
+
let currentVersion = "unknown";
|
|
11522
|
+
try {
|
|
11523
|
+
const pkgRaw = fs5.readFileSync(pkgPath, "utf-8");
|
|
11524
|
+
const pkg = JSON.parse(pkgRaw);
|
|
11525
|
+
currentVersion = pkg.version || "unknown";
|
|
11526
|
+
} catch {
|
|
11527
|
+
}
|
|
11528
|
+
if (currentVersion === "unknown") {
|
|
11529
|
+
const altPkgPath = path5.join(process.cwd(), "plugin", "package.json");
|
|
11530
|
+
try {
|
|
11531
|
+
const pkg = JSON.parse(fs5.readFileSync(altPkgPath, "utf-8"));
|
|
11532
|
+
currentVersion = pkg.version || "unknown";
|
|
11533
|
+
} catch {
|
|
11534
|
+
}
|
|
11535
|
+
}
|
|
11536
|
+
let latestVersion = currentVersion;
|
|
11537
|
+
let updateAvailable = false;
|
|
11538
|
+
try {
|
|
11539
|
+
const npmView = execSync("npm view aicq-openclaw-plugin version --registry https://registry.npmjs.org 2>/dev/null", {
|
|
11540
|
+
timeout: 15e3,
|
|
11541
|
+
encoding: "utf-8"
|
|
11542
|
+
}).trim();
|
|
11543
|
+
if (npmView) {
|
|
11544
|
+
latestVersion = npmView.replace(/^\^|~|\s+.*$/g, "").trim();
|
|
11545
|
+
updateAvailable = latestVersion !== currentVersion;
|
|
11546
|
+
}
|
|
11547
|
+
} catch (npmErr) {
|
|
11548
|
+
logger.warn("[API] npm view failed: " + (npmErr instanceof Error ? npmErr.message : String(npmErr)));
|
|
11549
|
+
}
|
|
11550
|
+
return json(res, {
|
|
11551
|
+
currentVersion,
|
|
11552
|
+
latestVersion,
|
|
11553
|
+
updateAvailable,
|
|
11554
|
+
packageName: "aicq-openclaw-plugin"
|
|
11555
|
+
});
|
|
11556
|
+
} catch (err) {
|
|
11557
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
11558
|
+
return json(res, { error: "Failed to check for updates: " + msg }, 500);
|
|
11559
|
+
}
|
|
11560
|
+
}
|
|
11561
|
+
if (apiPath === "/update" && method === "POST") {
|
|
11562
|
+
const body = await readBody(req);
|
|
11563
|
+
const force = body.force;
|
|
11564
|
+
try {
|
|
11565
|
+
logger.info("[API] Starting npm update for aicq-openclaw-plugin...");
|
|
11566
|
+
const pluginDir = __dirname;
|
|
11567
|
+
let npmRoot = pluginDir;
|
|
11568
|
+
for (let i = 0; i < 5; i++) {
|
|
11569
|
+
if (npmRoot.endsWith("node_modules"))
|
|
11570
|
+
break;
|
|
11571
|
+
npmRoot = path5.dirname(npmRoot);
|
|
11572
|
+
}
|
|
11573
|
+
const parentDir = path5.dirname(npmRoot);
|
|
11574
|
+
let installDir = parentDir;
|
|
11575
|
+
const candidates = [
|
|
11576
|
+
parentDir,
|
|
11577
|
+
path5.join(os.homedir(), ".openclaw", "plugins"),
|
|
11578
|
+
path5.join(os.homedir(), ".config", "openclaw", "plugins")
|
|
11579
|
+
];
|
|
11580
|
+
let updateCmd;
|
|
11581
|
+
if (force) {
|
|
11582
|
+
updateCmd = `npm install aicq-openclaw-plugin@latest --dangerously-force-unsafe-install --registry https://registry.npmjs.org`;
|
|
11583
|
+
} else {
|
|
11584
|
+
updateCmd = `npm update aicq-openclaw-plugin --dangerously-force-unsafe-install --registry https://registry.npmjs.org`;
|
|
11585
|
+
}
|
|
11586
|
+
let installPath = parentDir;
|
|
11587
|
+
try {
|
|
11588
|
+
const pkgJsonPath = path5.join(pluginDir, "package.json");
|
|
11589
|
+
const realPkgDir = fs5.realpathSync(path5.dirname(pkgJsonPath));
|
|
11590
|
+
if (realPkgDir.includes("node_modules")) {
|
|
11591
|
+
const nmIdx = realPkgDir.lastIndexOf("node_modules");
|
|
11592
|
+
installPath = realPkgDir.substring(0, nmIdx + 13);
|
|
11593
|
+
}
|
|
11594
|
+
} catch {
|
|
11595
|
+
}
|
|
11596
|
+
logger.info("[API] Running: " + updateCmd + " in " + installPath);
|
|
11597
|
+
const result = await new Promise((resolve3) => {
|
|
11598
|
+
const child = exec(updateCmd, {
|
|
11599
|
+
cwd: installPath,
|
|
11600
|
+
timeout: 12e4,
|
|
11601
|
+
encoding: "utf-8",
|
|
11602
|
+
env: { ...process.env, NODE_NO_WARNINGS: "1" }
|
|
11603
|
+
}, (error, stdout, stderr) => {
|
|
11604
|
+
if (error) {
|
|
11605
|
+
resolve3("ERROR: " + (error.message || String(error)) + "\n\n" + (stderr || ""));
|
|
11606
|
+
} else {
|
|
11607
|
+
resolve3(stdout || stderr || "Update completed (no output)");
|
|
11608
|
+
}
|
|
11609
|
+
});
|
|
11610
|
+
child.stdout?.on("data", (d) => {
|
|
11611
|
+
});
|
|
11612
|
+
child.stderr?.on("data", (d) => {
|
|
11613
|
+
});
|
|
11614
|
+
});
|
|
11615
|
+
let newVersion = "unknown";
|
|
11616
|
+
try {
|
|
11617
|
+
const pkgRaw = fs5.readFileSync(path5.join(__dirname, "..", "package.json"), "utf-8");
|
|
11618
|
+
newVersion = JSON.parse(pkgRaw).version || "unknown";
|
|
11619
|
+
} catch {
|
|
11620
|
+
}
|
|
11621
|
+
const success = !result.startsWith("ERROR");
|
|
11622
|
+
logger.info("[API] Update " + (success ? "succeeded" : "failed") + ": " + result.substring(0, 200));
|
|
11623
|
+
return json(res, {
|
|
11624
|
+
success,
|
|
11625
|
+
message: success ? "Plugin updated successfully! Restart the service to apply changes." : "Update failed.",
|
|
11626
|
+
output: result.substring(0, 2e3),
|
|
11627
|
+
newVersion,
|
|
11628
|
+
needsRestart: success
|
|
11629
|
+
});
|
|
11630
|
+
} catch (err) {
|
|
11631
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
11632
|
+
logger.error("[API] Update error: " + msg);
|
|
11633
|
+
return json(res, { success: false, message: "Update failed: " + msg }, 500);
|
|
11634
|
+
}
|
|
11635
|
+
}
|
|
11636
|
+
if (apiPath === "/plugin-info" && method === "GET") {
|
|
11637
|
+
let pkgVersion = "unknown";
|
|
11638
|
+
try {
|
|
11639
|
+
const pkgPath = path5.join(__dirname, "..", "package.json");
|
|
11640
|
+
const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
|
|
11641
|
+
pkgVersion = pkg.version || "unknown";
|
|
11642
|
+
} catch {
|
|
11643
|
+
const altPkgPath = path5.join(process.cwd(), "plugin", "package.json");
|
|
11644
|
+
try {
|
|
11645
|
+
pkgVersion = JSON.parse(fs5.readFileSync(altPkgPath, "utf-8")).version || "unknown";
|
|
11646
|
+
} catch {
|
|
11647
|
+
}
|
|
11648
|
+
}
|
|
11649
|
+
return json(res, {
|
|
11650
|
+
version: pkgVersion,
|
|
11651
|
+
name: "aicq-openclaw-plugin",
|
|
11652
|
+
uptime: process.uptime(),
|
|
11653
|
+
nodeVersion: process.version,
|
|
11654
|
+
platform: process.platform,
|
|
11655
|
+
pid: process.pid
|
|
11656
|
+
});
|
|
11657
|
+
}
|
|
11415
11658
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
11416
11659
|
res.end(JSON.stringify({ error: "Not found: " + apiPath }));
|
|
11417
11660
|
} catch (err) {
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "aicq-chat",
|
|
3
3
|
"name": "AICQ Encrypted Chat",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.7",
|
|
5
5
|
"description": "End-to-end encrypted chat plugin supporting AI-AI, Human-AI communication with P2P messaging via Noise-XK handshake, Ed25519/X25519/AES-256-GCM encryption",
|
|
6
6
|
"enabledByDefault": false,
|
|
7
7
|
"channels": ["encrypted-chat"],
|