claw-control-center 0.1.1 → 0.1.3
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.cjs +218 -37
- package/dist/index.d.cts +2 -0
- package/dist/install-qclaw.cjs +34 -2
- package/dist/install-qclaw.d.cts +2 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2238,7 +2238,7 @@ var require_websocket = __commonJS({
|
|
|
2238
2238
|
var http = require("http");
|
|
2239
2239
|
var net = require("net");
|
|
2240
2240
|
var tls = require("tls");
|
|
2241
|
-
var { randomBytes, createHash } = require("crypto");
|
|
2241
|
+
var { randomBytes, createHash: createHash2 } = require("crypto");
|
|
2242
2242
|
var { Duplex, Readable } = require("stream");
|
|
2243
2243
|
var { URL: URL2 } = require("url");
|
|
2244
2244
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -2898,7 +2898,7 @@ var require_websocket = __commonJS({
|
|
|
2898
2898
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
2899
2899
|
return;
|
|
2900
2900
|
}
|
|
2901
|
-
const digest =
|
|
2901
|
+
const digest = createHash2("sha1").update(key + GUID).digest("base64");
|
|
2902
2902
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
2903
2903
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
2904
2904
|
return;
|
|
@@ -3265,7 +3265,7 @@ var require_websocket_server = __commonJS({
|
|
|
3265
3265
|
var EventEmitter = require("events");
|
|
3266
3266
|
var http = require("http");
|
|
3267
3267
|
var { Duplex } = require("stream");
|
|
3268
|
-
var { createHash } = require("crypto");
|
|
3268
|
+
var { createHash: createHash2 } = require("crypto");
|
|
3269
3269
|
var extension2 = require_extension();
|
|
3270
3270
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
3271
3271
|
var subprotocol2 = require_subprotocol();
|
|
@@ -3566,7 +3566,7 @@ var require_websocket_server = __commonJS({
|
|
|
3566
3566
|
);
|
|
3567
3567
|
}
|
|
3568
3568
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
3569
|
-
const digest =
|
|
3569
|
+
const digest = createHash2("sha1").update(key + GUID).digest("base64");
|
|
3570
3570
|
const headers = [
|
|
3571
3571
|
"HTTP/1.1 101 Switching Protocols",
|
|
3572
3572
|
"Upgrade: websocket",
|
|
@@ -3666,7 +3666,7 @@ __export(index_exports, {
|
|
|
3666
3666
|
module.exports = __toCommonJS(index_exports);
|
|
3667
3667
|
var import_node_fs5 = require("fs");
|
|
3668
3668
|
var import_node_path7 = require("path");
|
|
3669
|
-
var
|
|
3669
|
+
var import_node_crypto5 = require("crypto");
|
|
3670
3670
|
|
|
3671
3671
|
// src/agent-event-probe.ts
|
|
3672
3672
|
var RECENT_EVENT_LIMIT = 200;
|
|
@@ -3850,6 +3850,7 @@ var DEFAULT_THINKING_MESSAGE = "\u6B63\u5728\u5904\u7406\u60A8\u7684\u8BF7\u6C42
|
|
|
3850
3850
|
var MAX_OUTBOX_FRAMES = 200;
|
|
3851
3851
|
var RUN_WAIT_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
3852
3852
|
var HUB_SESSION_TITLE_PREFIX = "53AI Hub-";
|
|
3853
|
+
var CONTROL_CENTER_SESSION_TITLE = "Claw Control Center";
|
|
3853
3854
|
var HUB_TITLE_SUMMARY_LENGTH = 40;
|
|
3854
3855
|
var HUB_RPC_ACTIONS = /* @__PURE__ */ new Set([
|
|
3855
3856
|
"sessions.list",
|
|
@@ -4069,10 +4070,11 @@ function createHub53AIBridge(input) {
|
|
|
4069
4070
|
async function resolveRPCRequest(request) {
|
|
4070
4071
|
if (request.action === "sessions.list") {
|
|
4071
4072
|
const pagination = readRPCPagination(request.data, 50);
|
|
4072
|
-
|
|
4073
|
+
const page = await input.gateway.listSessionPage({
|
|
4073
4074
|
limit: pagination.limit,
|
|
4074
4075
|
offset: pagination.offset
|
|
4075
4076
|
});
|
|
4077
|
+
return mergeKnownHubSessionTitles(page);
|
|
4076
4078
|
}
|
|
4077
4079
|
if (request.action === "sessions.current") {
|
|
4078
4080
|
return resolveCurrentSessionRPC(request.data);
|
|
@@ -4203,6 +4205,7 @@ function createHub53AIBridge(input) {
|
|
|
4203
4205
|
async function resolveCurrentSessionRPC(payload) {
|
|
4204
4206
|
const record = toRecord2(payload);
|
|
4205
4207
|
const userObject = toRecord2(record.user);
|
|
4208
|
+
const userName = stringOr(record.userName, record.user_name, userObject.name, userObject.userName, userObject.username);
|
|
4206
4209
|
const chatId = stringOr(
|
|
4207
4210
|
record.chat_id,
|
|
4208
4211
|
record.chatId,
|
|
@@ -4215,11 +4218,7 @@ function createHub53AIBridge(input) {
|
|
|
4215
4218
|
if (!chatId) {
|
|
4216
4219
|
throw new HubRPCError("PARAM_ERROR", "chat_id or user is required");
|
|
4217
4220
|
}
|
|
4218
|
-
|
|
4219
|
-
if (mappedSession) {
|
|
4220
|
-
return mappedSession;
|
|
4221
|
-
}
|
|
4222
|
-
return null;
|
|
4221
|
+
return restoreLatestHubSession(chatId, userName);
|
|
4223
4222
|
}
|
|
4224
4223
|
async function getMappedSession(chatId) {
|
|
4225
4224
|
const mappedId = state.mappings[chatId];
|
|
@@ -4227,13 +4226,55 @@ function createHub53AIBridge(input) {
|
|
|
4227
4226
|
return null;
|
|
4228
4227
|
}
|
|
4229
4228
|
try {
|
|
4230
|
-
|
|
4229
|
+
const session = await input.gateway.getSession(mappedId);
|
|
4230
|
+
if (!isHubManagedSessionTitle(session.title, chatId)) {
|
|
4231
|
+
delete state.mappings[chatId];
|
|
4232
|
+
await persistState();
|
|
4233
|
+
input.logger?.warn?.(
|
|
4234
|
+
`Ignored stale 53AIHub session mapping for ${chatId}: mapped session ${mappedId} is "${session.title}"`
|
|
4235
|
+
);
|
|
4236
|
+
return null;
|
|
4237
|
+
}
|
|
4238
|
+
return session;
|
|
4231
4239
|
} catch {
|
|
4232
4240
|
delete state.mappings[chatId];
|
|
4233
4241
|
await persistState();
|
|
4234
4242
|
return null;
|
|
4235
4243
|
}
|
|
4236
4244
|
}
|
|
4245
|
+
async function restoreLatestHubSession(chatId, userName) {
|
|
4246
|
+
const page = await input.gateway.listSessionPage({
|
|
4247
|
+
limit: 100,
|
|
4248
|
+
offset: 0
|
|
4249
|
+
});
|
|
4250
|
+
const knownSessions = await listKnownSessions();
|
|
4251
|
+
const sessions = mergeKnownHubSessions(page.sessions, knownSessions).filter((session2) => isRestorableHubSession(session2, chatId, userName)).sort((left, right) => toTime(right.updatedAt || right.createdAt) - toTime(left.updatedAt || left.createdAt));
|
|
4252
|
+
const session = sessions[0];
|
|
4253
|
+
if (!session) {
|
|
4254
|
+
return null;
|
|
4255
|
+
}
|
|
4256
|
+
return session;
|
|
4257
|
+
}
|
|
4258
|
+
async function mergeKnownHubSessionTitles(page) {
|
|
4259
|
+
const knownSessions = await listKnownSessions();
|
|
4260
|
+
if (!knownSessions.length) {
|
|
4261
|
+
return page;
|
|
4262
|
+
}
|
|
4263
|
+
return {
|
|
4264
|
+
...page,
|
|
4265
|
+
sessions: mergeKnownHubSessions(page.sessions, knownSessions)
|
|
4266
|
+
};
|
|
4267
|
+
}
|
|
4268
|
+
async function listKnownSessions() {
|
|
4269
|
+
try {
|
|
4270
|
+
return await input.callbacks.listKnownSessions?.() ?? [];
|
|
4271
|
+
} catch (error) {
|
|
4272
|
+
input.logger?.warn?.(
|
|
4273
|
+
`Failed to read known 53AIHub sessions: ${error instanceof Error ? error.message : String(error)}`
|
|
4274
|
+
);
|
|
4275
|
+
return [];
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4237
4278
|
async function buildFallbackStatus() {
|
|
4238
4279
|
const [gatewayHealth, runtimeInfo] = await Promise.allSettled([input.gateway.getHealth(), input.gateway.getRuntimeInfo()]);
|
|
4239
4280
|
return {
|
|
@@ -4405,7 +4446,7 @@ function createHub53AIBridge(input) {
|
|
|
4405
4446
|
if (event.kind === "tool.call" || event.kind === "tool.result") {
|
|
4406
4447
|
const summary = summarizeVisibleActivity(event);
|
|
4407
4448
|
if (summary && input.config.sendThinkingMessage) {
|
|
4408
|
-
await recordBridgeThinkingEvent(
|
|
4449
|
+
await recordBridgeThinkingEvent(sessionId, summary);
|
|
4409
4450
|
await sendReply({
|
|
4410
4451
|
reqId: message.reqId,
|
|
4411
4452
|
text: summary,
|
|
@@ -4478,9 +4519,6 @@ function createHub53AIBridge(input) {
|
|
|
4478
4519
|
const payload = toRecord2(event.payload);
|
|
4479
4520
|
return event.kind === "status.update" && String(payload.phase ?? payload.status ?? "") === "running";
|
|
4480
4521
|
}
|
|
4481
|
-
function resolveMappedSessionId(message) {
|
|
4482
|
-
return state.mappings[message.chatId] ?? message.chatId;
|
|
4483
|
-
}
|
|
4484
4522
|
async function recordBridgeThinkingEvent(sessionId, content) {
|
|
4485
4523
|
const normalized = content.trim();
|
|
4486
4524
|
if (!normalized || !input.callbacks.onBridgeThinkingEvent) {
|
|
@@ -4523,26 +4561,27 @@ function createHub53AIBridge(input) {
|
|
|
4523
4561
|
}
|
|
4524
4562
|
async function resolveSession(message) {
|
|
4525
4563
|
const desiredTitle = buildHubSessionTitle(message);
|
|
4526
|
-
const mappedId = state.mappings[message.chatId];
|
|
4527
|
-
if (mappedId) {
|
|
4528
|
-
const session2 = await input.gateway.getSession(mappedId);
|
|
4529
|
-
const nextSession = await renamePlaceholderSessionIfNeeded(session2, message, desiredTitle);
|
|
4530
|
-
await input.callbacks.onSessionUpsert(nextSession);
|
|
4531
|
-
return nextSession;
|
|
4532
|
-
}
|
|
4533
4564
|
if (isOpenClawSessionId(message.chatId)) {
|
|
4534
|
-
const session2 = await
|
|
4535
|
-
state.mappings[message.chatId] = session2.id;
|
|
4536
|
-
await persistState();
|
|
4565
|
+
const session2 = await getSessionWithKnownHubTitle(message.chatId, message.conversationTitle);
|
|
4537
4566
|
await input.callbacks.onSessionUpsert(session2);
|
|
4538
4567
|
return session2;
|
|
4539
4568
|
}
|
|
4569
|
+
const restoredSession = await restoreLatestHubSession(message.chatId, message.userName || message.userId);
|
|
4570
|
+
if (restoredSession) {
|
|
4571
|
+
const nextSession = await renamePlaceholderSessionIfNeeded(restoredSession, message, desiredTitle);
|
|
4572
|
+
await input.callbacks.onSessionUpsert(nextSession);
|
|
4573
|
+
return nextSession;
|
|
4574
|
+
}
|
|
4540
4575
|
const session = await createSessionWithUniqueTitle(desiredTitle);
|
|
4541
|
-
state.mappings[message.chatId] = session.id;
|
|
4542
|
-
await persistState();
|
|
4543
4576
|
await input.callbacks.onSessionUpsert(session);
|
|
4544
4577
|
return session;
|
|
4545
4578
|
}
|
|
4579
|
+
async function getSessionWithKnownHubTitle(sessionId, titleHint) {
|
|
4580
|
+
const session = await input.gateway.getSession(sessionId);
|
|
4581
|
+
const knownSessions = await listKnownSessions();
|
|
4582
|
+
const titleHintSession = applyHubTitleHint(session, titleHint);
|
|
4583
|
+
return mergeKnownHubSessions([titleHintSession], knownSessions)[0] ?? titleHintSession;
|
|
4584
|
+
}
|
|
4546
4585
|
async function createSessionWithUniqueTitle(baseTitle) {
|
|
4547
4586
|
let lastDuplicateError;
|
|
4548
4587
|
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
@@ -4708,6 +4747,7 @@ function parseIncomingMessage(rawJson) {
|
|
|
4708
4747
|
chatId: chatId2,
|
|
4709
4748
|
userId: userId2,
|
|
4710
4749
|
userName: extractUserName(openAIReq, metadata, userObject2, userMessage),
|
|
4750
|
+
conversationTitle: extractConversationTitle(openAIReq, metadata),
|
|
4711
4751
|
text: extractTextFromContent(content),
|
|
4712
4752
|
imageUrls: extractImagesFromContent(content),
|
|
4713
4753
|
fileUrls: extractFilesFromContent(content)
|
|
@@ -4727,6 +4767,7 @@ function parseIncomingMessage(rawJson) {
|
|
|
4727
4767
|
chatId,
|
|
4728
4768
|
userId,
|
|
4729
4769
|
userName: extractUserName(data, userObject),
|
|
4770
|
+
conversationTitle: extractConversationTitle(data),
|
|
4730
4771
|
text: stringOr(data.text, data.content, ""),
|
|
4731
4772
|
imageUrls: normalizeUrlList(data.imageUrls, data.images),
|
|
4732
4773
|
fileUrls: normalizeUrlList(data.fileUrls, data.files),
|
|
@@ -4866,6 +4907,23 @@ function extractUserName(...sources) {
|
|
|
4866
4907
|
}
|
|
4867
4908
|
return void 0;
|
|
4868
4909
|
}
|
|
4910
|
+
function extractConversationTitle(...sources) {
|
|
4911
|
+
const titleKeys = [
|
|
4912
|
+
"openclaw_conversation_title",
|
|
4913
|
+
"openclawConversationTitle",
|
|
4914
|
+
"conversation_title",
|
|
4915
|
+
"conversationTitle",
|
|
4916
|
+
"title"
|
|
4917
|
+
];
|
|
4918
|
+
for (const source of sources) {
|
|
4919
|
+
const record = toRecord2(source);
|
|
4920
|
+
const title = stringFromKeys(record, titleKeys);
|
|
4921
|
+
if (title) {
|
|
4922
|
+
return title;
|
|
4923
|
+
}
|
|
4924
|
+
}
|
|
4925
|
+
return void 0;
|
|
4926
|
+
}
|
|
4869
4927
|
function stringFromKeys(record, keys) {
|
|
4870
4928
|
for (const key of keys) {
|
|
4871
4929
|
const value = record[key];
|
|
@@ -4920,6 +4978,63 @@ function isOldHubPlaceholderTitle(title, chatId) {
|
|
|
4920
4978
|
const normalized = title.trim();
|
|
4921
4979
|
return [`53AIHub ${chatId}`, `53AIHub:${chatId}`, `53AIHub-${chatId}`, chatId].includes(normalized);
|
|
4922
4980
|
}
|
|
4981
|
+
function isHubManagedSessionTitle(title, chatId) {
|
|
4982
|
+
const normalized = title.trim();
|
|
4983
|
+
return normalized.startsWith(HUB_SESSION_TITLE_PREFIX) || isOldHubPlaceholderTitle(normalized, chatId);
|
|
4984
|
+
}
|
|
4985
|
+
function isRestorableHubSession(session, chatId, userName) {
|
|
4986
|
+
const normalized = session.title.trim();
|
|
4987
|
+
if (isOldHubPlaceholderTitle(normalized, chatId)) {
|
|
4988
|
+
return true;
|
|
4989
|
+
}
|
|
4990
|
+
if (!normalized.startsWith(HUB_SESSION_TITLE_PREFIX) || !userName) {
|
|
4991
|
+
return false;
|
|
4992
|
+
}
|
|
4993
|
+
return normalized.startsWith(`${HUB_SESSION_TITLE_PREFIX}${sanitizeTitlePart(userName)}\uFF1A`);
|
|
4994
|
+
}
|
|
4995
|
+
function mergeKnownHubSessions(gatewaySessions, knownSessions) {
|
|
4996
|
+
const knownHubById = new Map(
|
|
4997
|
+
knownSessions.filter((session) => isHubTitle(session.title)).map((session) => [session.id, session])
|
|
4998
|
+
);
|
|
4999
|
+
if (!knownHubById.size) {
|
|
5000
|
+
return gatewaySessions;
|
|
5001
|
+
}
|
|
5002
|
+
const merged = gatewaySessions.map((session) => {
|
|
5003
|
+
const knownSession = knownHubById.get(session.id);
|
|
5004
|
+
if (!knownSession || !shouldPreferKnownHubTitle(session.title, knownSession.title)) {
|
|
5005
|
+
return session;
|
|
5006
|
+
}
|
|
5007
|
+
return {
|
|
5008
|
+
...session,
|
|
5009
|
+
title: knownSession.title
|
|
5010
|
+
};
|
|
5011
|
+
});
|
|
5012
|
+
return merged;
|
|
5013
|
+
}
|
|
5014
|
+
function applyHubTitleHint(session, titleHint) {
|
|
5015
|
+
const normalizedTitle = titleHint?.trim();
|
|
5016
|
+
if (!normalizedTitle || !isHubTitle(normalizedTitle)) {
|
|
5017
|
+
return session;
|
|
5018
|
+
}
|
|
5019
|
+
return {
|
|
5020
|
+
...session,
|
|
5021
|
+
title: normalizedTitle
|
|
5022
|
+
};
|
|
5023
|
+
}
|
|
5024
|
+
function shouldPreferKnownHubTitle(gatewayTitle, knownTitle) {
|
|
5025
|
+
return isHubTitle(knownTitle) && (isControlCenterTitle(gatewayTitle) || !isHubTitle(gatewayTitle));
|
|
5026
|
+
}
|
|
5027
|
+
function isHubTitle(title) {
|
|
5028
|
+
return title.trim().startsWith(HUB_SESSION_TITLE_PREFIX);
|
|
5029
|
+
}
|
|
5030
|
+
function isControlCenterTitle(title) {
|
|
5031
|
+
return title.trim() === CONTROL_CENTER_SESSION_TITLE;
|
|
5032
|
+
}
|
|
5033
|
+
function toTime(value) {
|
|
5034
|
+
if (!value) return 0;
|
|
5035
|
+
const time = Date.parse(value);
|
|
5036
|
+
return Number.isFinite(time) ? time : 0;
|
|
5037
|
+
}
|
|
4923
5038
|
function isOpenClawSessionId(value) {
|
|
4924
5039
|
return value.startsWith("agent:");
|
|
4925
5040
|
}
|
|
@@ -5049,7 +5164,10 @@ function normalizeUrlList(primary, fallback) {
|
|
|
5049
5164
|
}).filter(Boolean);
|
|
5050
5165
|
}
|
|
5051
5166
|
function summarizeVisibleActivity(event) {
|
|
5052
|
-
const
|
|
5167
|
+
const data = toRecord2(event.payload?.data);
|
|
5168
|
+
const name = String(
|
|
5169
|
+
event.payload?.name ?? event.payload?.toolName ?? event.payload?.skillName ?? data.name ?? data.toolName ?? data.skillName ?? ""
|
|
5170
|
+
).trim();
|
|
5053
5171
|
if (event.kind === "tool.call") {
|
|
5054
5172
|
return name ? `Used tool ${name}` : "Used a tool";
|
|
5055
5173
|
}
|
|
@@ -5130,6 +5248,8 @@ function toRecord2(value) {
|
|
|
5130
5248
|
// src/file-store.ts
|
|
5131
5249
|
var import_promises2 = require("fs/promises");
|
|
5132
5250
|
var import_node_path2 = require("path");
|
|
5251
|
+
var HUB_SESSION_TITLE_PREFIX2 = "53AI Hub-";
|
|
5252
|
+
var CONTROL_CENTER_SESSION_TITLE2 = "Claw Control Center";
|
|
5133
5253
|
var FileSessionStore = class {
|
|
5134
5254
|
constructor(filePath, maxSessions) {
|
|
5135
5255
|
this.filePath = filePath;
|
|
@@ -5162,9 +5282,29 @@ var FileSessionStore = class {
|
|
|
5162
5282
|
return this.state.sessions[sessionId]?.hydrated ?? false;
|
|
5163
5283
|
}
|
|
5164
5284
|
async upsertSession(session) {
|
|
5285
|
+
this.mergeSession(session);
|
|
5286
|
+
this.trimSessions();
|
|
5287
|
+
await this.persist();
|
|
5288
|
+
}
|
|
5289
|
+
async replaceSessions(sessions) {
|
|
5290
|
+
const remoteIds = new Set(sessions.map((session) => session.id));
|
|
5291
|
+
for (const session of sessions) {
|
|
5292
|
+
this.mergeSession(session);
|
|
5293
|
+
}
|
|
5294
|
+
for (const sessionId of Object.keys(this.state.sessions)) {
|
|
5295
|
+
if (!remoteIds.has(sessionId)) {
|
|
5296
|
+
delete this.state.sessions[sessionId];
|
|
5297
|
+
}
|
|
5298
|
+
}
|
|
5299
|
+
this.trimSessions();
|
|
5300
|
+
await this.persist();
|
|
5301
|
+
}
|
|
5302
|
+
mergeSession(session) {
|
|
5165
5303
|
const existing = this.state.sessions[session.id];
|
|
5304
|
+
const title = preserveExistingHubTitle(existing?.session.title, session.title);
|
|
5166
5305
|
const mergedSession = {
|
|
5167
5306
|
...session,
|
|
5307
|
+
title,
|
|
5168
5308
|
lastEventSeq: Math.max(session.lastEventSeq, existing?.session.lastEventSeq ?? 0)
|
|
5169
5309
|
};
|
|
5170
5310
|
this.state.sessions[session.id] = {
|
|
@@ -5173,8 +5313,6 @@ var FileSessionStore = class {
|
|
|
5173
5313
|
events: existing?.events ?? [],
|
|
5174
5314
|
hydrated: existing?.hydrated ?? false
|
|
5175
5315
|
};
|
|
5176
|
-
this.trimSessions();
|
|
5177
|
-
await this.persist();
|
|
5178
5316
|
}
|
|
5179
5317
|
async renameSession(sessionId, title) {
|
|
5180
5318
|
const record = this.requireSession(sessionId);
|
|
@@ -5243,6 +5381,18 @@ var FileSessionStore = class {
|
|
|
5243
5381
|
await this.persistChain;
|
|
5244
5382
|
}
|
|
5245
5383
|
};
|
|
5384
|
+
function preserveExistingHubTitle(existingTitle, incomingTitle) {
|
|
5385
|
+
if (isHubTitle2(existingTitle) && isControlCenterTitle2(incomingTitle)) {
|
|
5386
|
+
return existingTitle;
|
|
5387
|
+
}
|
|
5388
|
+
return incomingTitle;
|
|
5389
|
+
}
|
|
5390
|
+
function isHubTitle2(title) {
|
|
5391
|
+
return typeof title === "string" && title.trim().startsWith(HUB_SESSION_TITLE_PREFIX2);
|
|
5392
|
+
}
|
|
5393
|
+
function isControlCenterTitle2(title) {
|
|
5394
|
+
return title.trim() === CONTROL_CENTER_SESSION_TITLE2;
|
|
5395
|
+
}
|
|
5246
5396
|
function dedupeMessages(messages) {
|
|
5247
5397
|
return Array.from(new Map(messages.map((message) => [message.id, message])).values()).sort(
|
|
5248
5398
|
(left, right) => left.createdAt.localeCompare(right.createdAt)
|
|
@@ -5588,6 +5738,7 @@ function createConsoleServer(input) {
|
|
|
5588
5738
|
broadcastSessionEvent(event.sessionId, event);
|
|
5589
5739
|
},
|
|
5590
5740
|
listSessionEvents: (sessionId) => store.getSession(sessionId)?.events ?? [],
|
|
5741
|
+
listKnownSessions: () => store.listSessions(),
|
|
5591
5742
|
onEnsureSessionStream: ensureSessionStream,
|
|
5592
5743
|
getLastEventSeq: (sessionId) => store.getLastEventSeq(sessionId),
|
|
5593
5744
|
onStatusChange: broadcastStatus
|
|
@@ -5929,9 +6080,7 @@ function createConsoleServer(input) {
|
|
|
5929
6080
|
const before = sessionListSignature(store.listSessions());
|
|
5930
6081
|
const remoteSessions = await input.gateway.listSessions(input.persistence.maxSessions);
|
|
5931
6082
|
lastGatewayError = null;
|
|
5932
|
-
|
|
5933
|
-
await store.upsertSession(session);
|
|
5934
|
-
}
|
|
6083
|
+
await store.replaceSessions(remoteSessions);
|
|
5935
6084
|
return before !== sessionListSignature(store.listSessions());
|
|
5936
6085
|
} catch (error) {
|
|
5937
6086
|
lastGatewayError = error instanceof Error ? error : new Error(String(error));
|
|
@@ -8617,11 +8766,13 @@ function toRecord3(value) {
|
|
|
8617
8766
|
}
|
|
8618
8767
|
|
|
8619
8768
|
// src/install-qclaw.ts
|
|
8769
|
+
var import_node_crypto4 = require("crypto");
|
|
8620
8770
|
var import_promises4 = require("fs/promises");
|
|
8621
8771
|
var import_node_fs4 = require("fs");
|
|
8622
8772
|
var import_node_os2 = require("os");
|
|
8623
8773
|
var import_node_path6 = require("path");
|
|
8624
8774
|
var PLUGIN_ID = "claw-control-center";
|
|
8775
|
+
var LEGACY_PLUGIN_ID = "53ai-openclaw";
|
|
8625
8776
|
var DEFAULT_QCLAW_HOME = (0, import_node_path6.resolve)((0, import_node_os2.homedir)(), ".qclaw");
|
|
8626
8777
|
var DEFAULT_OPENCLAW_HOME = (0, import_node_path6.resolve)((0, import_node_os2.homedir)(), ".openclaw");
|
|
8627
8778
|
var DEFAULT_EXTENSIONS_DIR = (0, import_node_path6.resolve)(
|
|
@@ -8681,10 +8832,18 @@ async function installIntoHost(input, hostLabel) {
|
|
|
8681
8832
|
const consolePort = normalizePort(input.consolePort);
|
|
8682
8833
|
const plugins = ensureObject(config, "plugins");
|
|
8683
8834
|
plugins.enabled = true;
|
|
8684
|
-
plugins.allow = dedupeStrings([
|
|
8835
|
+
plugins.allow = dedupeStrings([
|
|
8836
|
+
...Array.isArray(plugins.allow) ? plugins.allow.filter((entry) => entry !== LEGACY_PLUGIN_ID) : [],
|
|
8837
|
+
PLUGIN_ID
|
|
8838
|
+
]);
|
|
8685
8839
|
const load = ensureObject(plugins, "load");
|
|
8686
8840
|
load.paths = dedupeStrings([...Array.isArray(load.paths) ? load.paths : [], input.extensionsDir]);
|
|
8687
8841
|
const entries = ensureObject(plugins, "entries");
|
|
8842
|
+
const legacyEntry = entries[LEGACY_PLUGIN_ID] && typeof entries[LEGACY_PLUGIN_ID] === "object" && !Array.isArray(entries[LEGACY_PLUGIN_ID]) ? entries[LEGACY_PLUGIN_ID] : void 0;
|
|
8843
|
+
if (legacyEntry) {
|
|
8844
|
+
legacyEntry.enabled = false;
|
|
8845
|
+
entries[LEGACY_PLUGIN_ID] = legacyEntry;
|
|
8846
|
+
}
|
|
8688
8847
|
const previousEntry = ensureObject(entries, PLUGIN_ID);
|
|
8689
8848
|
const previousConfig = ensureObject(previousEntry, "config");
|
|
8690
8849
|
const previousGateway = ensureObject(previousConfig, "gateway");
|
|
@@ -8737,7 +8896,8 @@ async function installIntoHost(input, hostLabel) {
|
|
|
8737
8896
|
extensionsDir: input.extensionsDir,
|
|
8738
8897
|
destination,
|
|
8739
8898
|
gatewayBaseUrl,
|
|
8740
|
-
hub53aiConfigured: hubConfigured
|
|
8899
|
+
hub53aiConfigured: hubConfigured,
|
|
8900
|
+
pluginBuild: await readPluginBuildInfo(destination)
|
|
8741
8901
|
};
|
|
8742
8902
|
}
|
|
8743
8903
|
async function runInstallCommand(input) {
|
|
@@ -8777,6 +8937,7 @@ async function runInstallCommand(input) {
|
|
|
8777
8937
|
`Config: ${result.configPath}`,
|
|
8778
8938
|
`Gateway: ${result.gatewayBaseUrl}`,
|
|
8779
8939
|
`53AIHub: ${result.hub53aiConfigured ? "configured" : "not configured"}`,
|
|
8940
|
+
`Plugin build: ${result.pluginBuild}`,
|
|
8780
8941
|
`Restart ${targetInfo.label} to load the plugin.`
|
|
8781
8942
|
].join("\n") + "\n"
|
|
8782
8943
|
);
|
|
@@ -8818,6 +8979,26 @@ async function copyPublishablePackage(packageRoot, destination) {
|
|
|
8818
8979
|
await (0, import_promises4.cp)(source, target, { recursive: true, force: true });
|
|
8819
8980
|
}
|
|
8820
8981
|
}
|
|
8982
|
+
async function readPluginBuildInfo(destination) {
|
|
8983
|
+
const packagePath = (0, import_node_path6.join)(destination, "package.json");
|
|
8984
|
+
const entryPath = (0, import_node_path6.join)(destination, "dist", "index.cjs");
|
|
8985
|
+
let version = "unknown";
|
|
8986
|
+
try {
|
|
8987
|
+
const packageJson = JSON.parse(await (0, import_promises4.readFile)(packagePath, "utf8"));
|
|
8988
|
+
if (typeof packageJson.version === "string" && packageJson.version.trim()) {
|
|
8989
|
+
version = packageJson.version.trim();
|
|
8990
|
+
}
|
|
8991
|
+
} catch {
|
|
8992
|
+
version = "unknown";
|
|
8993
|
+
}
|
|
8994
|
+
try {
|
|
8995
|
+
const entry = await (0, import_promises4.readFile)(entryPath);
|
|
8996
|
+
const digest = (0, import_node_crypto4.createHash)("sha256").update(entry).digest("hex").slice(0, 12);
|
|
8997
|
+
return `${PLUGIN_ID}@${version} sha256:${digest}`;
|
|
8998
|
+
} catch {
|
|
8999
|
+
return `${PLUGIN_ID}@${version} sha256:missing`;
|
|
9000
|
+
}
|
|
9001
|
+
}
|
|
8821
9002
|
async function readOpenClawConfig(configPath) {
|
|
8822
9003
|
if (!(0, import_node_fs4.existsSync)(configPath)) {
|
|
8823
9004
|
return {};
|
|
@@ -8963,7 +9144,7 @@ async function createRuntime(input) {
|
|
|
8963
9144
|
configPath: input.configPath,
|
|
8964
9145
|
hostKind,
|
|
8965
9146
|
pluginVersion: input.version,
|
|
8966
|
-
token: (0,
|
|
9147
|
+
token: (0, import_node_crypto5.randomUUID)(),
|
|
8967
9148
|
gatewayConfig,
|
|
8968
9149
|
hub53aiConfig: config.hub53ai,
|
|
8969
9150
|
consoleConfig: config.console,
|
package/dist/index.d.cts
CHANGED
|
@@ -142,6 +142,7 @@ type Hub53AIIncomingMessage = {
|
|
|
142
142
|
imageUrls?: string[];
|
|
143
143
|
fileUrls?: string[];
|
|
144
144
|
quoteContent?: string;
|
|
145
|
+
conversationTitle?: string;
|
|
145
146
|
};
|
|
146
147
|
type Hub53AIOutgoingChunk = {
|
|
147
148
|
req_id: string;
|
|
@@ -187,6 +188,7 @@ type HubBridgeCallbacks = {
|
|
|
187
188
|
onSessionStatus(sessionId: string, status: SessionStatus): Promise<void>;
|
|
188
189
|
onBridgeThinkingEvent?(event: TimelineEvent): Promise<void>;
|
|
189
190
|
listSessionEvents?(sessionId: string): TimelineEvent[] | Promise<TimelineEvent[]>;
|
|
191
|
+
listKnownSessions?(): GatewaySession[] | Promise<GatewaySession[]>;
|
|
190
192
|
onEnsureSessionStream(sessionId: string): Promise<void>;
|
|
191
193
|
getLastEventSeq(sessionId: string): number;
|
|
192
194
|
onStatusChange(): void;
|
package/dist/install-qclaw.cjs
CHANGED
|
@@ -25,11 +25,13 @@ __export(install_qclaw_exports, {
|
|
|
25
25
|
runInstallCommand: () => runInstallCommand
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(install_qclaw_exports);
|
|
28
|
+
var import_node_crypto = require("crypto");
|
|
28
29
|
var import_promises = require("fs/promises");
|
|
29
30
|
var import_node_fs = require("fs");
|
|
30
31
|
var import_node_os = require("os");
|
|
31
32
|
var import_node_path = require("path");
|
|
32
33
|
var PLUGIN_ID = "claw-control-center";
|
|
34
|
+
var LEGACY_PLUGIN_ID = "53ai-openclaw";
|
|
33
35
|
var DEFAULT_QCLAW_HOME = (0, import_node_path.resolve)((0, import_node_os.homedir)(), ".qclaw");
|
|
34
36
|
var DEFAULT_OPENCLAW_HOME = (0, import_node_path.resolve)((0, import_node_os.homedir)(), ".openclaw");
|
|
35
37
|
var DEFAULT_EXTENSIONS_DIR = (0, import_node_path.resolve)(
|
|
@@ -89,10 +91,18 @@ async function installIntoHost(input, hostLabel) {
|
|
|
89
91
|
const consolePort = normalizePort(input.consolePort);
|
|
90
92
|
const plugins = ensureObject(config, "plugins");
|
|
91
93
|
plugins.enabled = true;
|
|
92
|
-
plugins.allow = dedupeStrings([
|
|
94
|
+
plugins.allow = dedupeStrings([
|
|
95
|
+
...Array.isArray(plugins.allow) ? plugins.allow.filter((entry) => entry !== LEGACY_PLUGIN_ID) : [],
|
|
96
|
+
PLUGIN_ID
|
|
97
|
+
]);
|
|
93
98
|
const load = ensureObject(plugins, "load");
|
|
94
99
|
load.paths = dedupeStrings([...Array.isArray(load.paths) ? load.paths : [], input.extensionsDir]);
|
|
95
100
|
const entries = ensureObject(plugins, "entries");
|
|
101
|
+
const legacyEntry = entries[LEGACY_PLUGIN_ID] && typeof entries[LEGACY_PLUGIN_ID] === "object" && !Array.isArray(entries[LEGACY_PLUGIN_ID]) ? entries[LEGACY_PLUGIN_ID] : void 0;
|
|
102
|
+
if (legacyEntry) {
|
|
103
|
+
legacyEntry.enabled = false;
|
|
104
|
+
entries[LEGACY_PLUGIN_ID] = legacyEntry;
|
|
105
|
+
}
|
|
96
106
|
const previousEntry = ensureObject(entries, PLUGIN_ID);
|
|
97
107
|
const previousConfig = ensureObject(previousEntry, "config");
|
|
98
108
|
const previousGateway = ensureObject(previousConfig, "gateway");
|
|
@@ -145,7 +155,8 @@ async function installIntoHost(input, hostLabel) {
|
|
|
145
155
|
extensionsDir: input.extensionsDir,
|
|
146
156
|
destination,
|
|
147
157
|
gatewayBaseUrl,
|
|
148
|
-
hub53aiConfigured: hubConfigured
|
|
158
|
+
hub53aiConfigured: hubConfigured,
|
|
159
|
+
pluginBuild: await readPluginBuildInfo(destination)
|
|
149
160
|
};
|
|
150
161
|
}
|
|
151
162
|
async function runInstallCommand(input) {
|
|
@@ -185,6 +196,7 @@ async function runInstallCommand(input) {
|
|
|
185
196
|
`Config: ${result.configPath}`,
|
|
186
197
|
`Gateway: ${result.gatewayBaseUrl}`,
|
|
187
198
|
`53AIHub: ${result.hub53aiConfigured ? "configured" : "not configured"}`,
|
|
199
|
+
`Plugin build: ${result.pluginBuild}`,
|
|
188
200
|
`Restart ${targetInfo.label} to load the plugin.`
|
|
189
201
|
].join("\n") + "\n"
|
|
190
202
|
);
|
|
@@ -226,6 +238,26 @@ async function copyPublishablePackage(packageRoot, destination) {
|
|
|
226
238
|
await (0, import_promises.cp)(source, target, { recursive: true, force: true });
|
|
227
239
|
}
|
|
228
240
|
}
|
|
241
|
+
async function readPluginBuildInfo(destination) {
|
|
242
|
+
const packagePath = (0, import_node_path.join)(destination, "package.json");
|
|
243
|
+
const entryPath = (0, import_node_path.join)(destination, "dist", "index.cjs");
|
|
244
|
+
let version = "unknown";
|
|
245
|
+
try {
|
|
246
|
+
const packageJson = JSON.parse(await (0, import_promises.readFile)(packagePath, "utf8"));
|
|
247
|
+
if (typeof packageJson.version === "string" && packageJson.version.trim()) {
|
|
248
|
+
version = packageJson.version.trim();
|
|
249
|
+
}
|
|
250
|
+
} catch {
|
|
251
|
+
version = "unknown";
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
const entry = await (0, import_promises.readFile)(entryPath);
|
|
255
|
+
const digest = (0, import_node_crypto.createHash)("sha256").update(entry).digest("hex").slice(0, 12);
|
|
256
|
+
return `${PLUGIN_ID}@${version} sha256:${digest}`;
|
|
257
|
+
} catch {
|
|
258
|
+
return `${PLUGIN_ID}@${version} sha256:missing`;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
229
261
|
async function readOpenClawConfig(configPath) {
|
|
230
262
|
if (!(0, import_node_fs.existsSync)(configPath)) {
|
|
231
263
|
return {};
|
package/dist/install-qclaw.d.cts
CHANGED
|
@@ -20,6 +20,7 @@ declare function installIntoQClaw(input: InstallInput): Promise<{
|
|
|
20
20
|
destination: string;
|
|
21
21
|
gatewayBaseUrl: string;
|
|
22
22
|
hub53aiConfigured: boolean;
|
|
23
|
+
pluginBuild: string;
|
|
23
24
|
}>;
|
|
24
25
|
declare function installIntoOpenClaw(input: InstallInput): Promise<{
|
|
25
26
|
configPath: string;
|
|
@@ -27,6 +28,7 @@ declare function installIntoOpenClaw(input: InstallInput): Promise<{
|
|
|
27
28
|
destination: string;
|
|
28
29
|
gatewayBaseUrl: string;
|
|
29
30
|
hub53aiConfigured: boolean;
|
|
31
|
+
pluginBuild: string;
|
|
30
32
|
}>;
|
|
31
33
|
declare function runInstallCommand(input: {
|
|
32
34
|
argv?: string[];
|