@clawlabz/clawskin 1.0.1 → 1.0.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/package.json +1 -1
- package/public/app.html +10 -5
- package/public/js/app/ClawSkinApp.js +50 -41
- package/public/js/app/GatewayClient.js +12 -6
- package/serve.cjs +5 -0
package/package.json
CHANGED
package/public/app.html
CHANGED
|
@@ -319,11 +319,16 @@
|
|
|
319
319
|
let app, editingSlot = null;
|
|
320
320
|
|
|
321
321
|
// ── Fullscreen canvas sizing ──
|
|
322
|
+
// Fixed logical resolution — CSS scales it up with pixelated rendering.
|
|
323
|
+
// This keeps pixel characters proportional on any screen size.
|
|
324
|
+
const LOGICAL_W = 960;
|
|
325
|
+
const LOGICAL_H = 600;
|
|
326
|
+
|
|
322
327
|
function resizeCanvas() {
|
|
323
328
|
const c = document.getElementById('app-canvas');
|
|
324
|
-
c.width =
|
|
325
|
-
c.height =
|
|
326
|
-
if (app) { app.width =
|
|
329
|
+
c.width = LOGICAL_W;
|
|
330
|
+
c.height = LOGICAL_H;
|
|
331
|
+
if (app) { app.width = LOGICAL_W; app.height = LOGICAL_H; }
|
|
327
332
|
}
|
|
328
333
|
window.addEventListener('resize', resizeCanvas);
|
|
329
334
|
resizeCanvas();
|
|
@@ -533,8 +538,8 @@
|
|
|
533
538
|
document.addEventListener('DOMContentLoaded', () => {
|
|
534
539
|
try {
|
|
535
540
|
app = new ClawSkinApp('app-canvas', {
|
|
536
|
-
width:
|
|
537
|
-
height:
|
|
541
|
+
width: LOGICAL_W,
|
|
542
|
+
height: LOGICAL_H,
|
|
538
543
|
});
|
|
539
544
|
app.init();
|
|
540
545
|
window._app = app;
|
|
@@ -168,17 +168,19 @@ class ClawSkinApp {
|
|
|
168
168
|
const res = await fetch('/api/config', { signal: AbortSignal.timeout(2000) });
|
|
169
169
|
if (res.ok) {
|
|
170
170
|
const config = await res.json();
|
|
171
|
+
console.log('[ClawSkin] /api/config →', JSON.stringify(config));
|
|
171
172
|
if (config?.gatewayUrl) {
|
|
172
173
|
const saved = this.settings.load();
|
|
174
|
+
const token = config.token || saved.token || '';
|
|
175
|
+
this._configAgents = config.agents || [];
|
|
173
176
|
this.settings.update({
|
|
174
177
|
gatewayUrl: config.gatewayUrl,
|
|
178
|
+
token: token,
|
|
175
179
|
autoConnect: true,
|
|
176
180
|
});
|
|
177
181
|
if (window._connPanel) {
|
|
178
182
|
window._connPanel.render(this.settings.load());
|
|
179
183
|
}
|
|
180
|
-
// Use token from local config, fall back to previously saved token
|
|
181
|
-
const token = config.token || saved.token || '';
|
|
182
184
|
this.gateway.connect(config.gatewayUrl, token);
|
|
183
185
|
return;
|
|
184
186
|
}
|
|
@@ -266,55 +268,62 @@ class ClawSkinApp {
|
|
|
266
268
|
// ──── Multi-Agent Management ────
|
|
267
269
|
|
|
268
270
|
async _discoverAgents() {
|
|
271
|
+
// Start with agents from config file (all agents, regardless of activity)
|
|
272
|
+
const configAgents = this._configAgents || [];
|
|
273
|
+
const knownAgentIds = new Set();
|
|
274
|
+
|
|
275
|
+
// Phase 1: Create slots for all agents from config file
|
|
276
|
+
for (const agent of configAgents) {
|
|
277
|
+
if (!agent.id) continue;
|
|
278
|
+
knownAgentIds.add(agent.id);
|
|
279
|
+
this._addAgent({
|
|
280
|
+
agentId: agent.id,
|
|
281
|
+
name: agent.name || agent.id,
|
|
282
|
+
label: agent.name || agent.id,
|
|
283
|
+
sessionKeys: [],
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Phase 2: Discover active sessions from Gateway and attach to slots
|
|
269
288
|
try {
|
|
270
289
|
const result = await this.gateway.getSessionsList({ activeMinutes: 1440 });
|
|
271
290
|
const sessions = result?.sessions || result || [];
|
|
272
291
|
|
|
273
|
-
if (
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
// Group sessions by agentId
|
|
279
|
-
// Session keys look like: "agent:main:main", "agent:ifig:discord:channel:123", "agent:xhs:main"
|
|
280
|
-
// The agentId is either session.agentId or extracted from the key pattern "agent:<agentId>:..."
|
|
281
|
-
const agentMap = new Map();
|
|
282
|
-
|
|
283
|
-
for (const session of sessions) {
|
|
284
|
-
const key = session.key || session.sessionKey;
|
|
285
|
-
if (!key) continue;
|
|
292
|
+
if (Array.isArray(sessions)) {
|
|
293
|
+
for (const session of sessions) {
|
|
294
|
+
const key = session.key || session.sessionKey;
|
|
295
|
+
if (!key) continue;
|
|
286
296
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
}
|
|
297
|
+
let agentId = session.agentId || null;
|
|
298
|
+
if (!agentId) {
|
|
299
|
+
const match = key.match(/^agent:([^:]+):/);
|
|
300
|
+
agentId = match ? match[1] : 'main';
|
|
301
|
+
}
|
|
293
302
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
agentId
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
303
|
+
// If this agent wasn't in config, create a slot for it
|
|
304
|
+
if (!knownAgentIds.has(agentId)) {
|
|
305
|
+
knownAgentIds.add(agentId);
|
|
306
|
+
this._addAgent({
|
|
307
|
+
agentId,
|
|
308
|
+
label: session.label || agentId,
|
|
309
|
+
sessionKeys: [key],
|
|
310
|
+
});
|
|
311
|
+
} else {
|
|
312
|
+
// Attach session key to existing slot
|
|
313
|
+
const slot = this.agents.find(a => a.agentId === agentId);
|
|
314
|
+
if (slot && !slot.sessionKeys.includes(key)) {
|
|
315
|
+
slot.sessionKeys.push(key);
|
|
316
|
+
slot.stateMapper.addSessionKey(key);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
300
319
|
}
|
|
301
|
-
agentMap.get(agentId).sessionKeys.push(key);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// Create one AgentSlot per unique agentId
|
|
305
|
-
for (const [agentId, info] of agentMap) {
|
|
306
|
-
this._addAgent({
|
|
307
|
-
agentId,
|
|
308
|
-
label: info.label,
|
|
309
|
-
sessionKeys: info.sessionKeys,
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (this.agents.length === 0) {
|
|
314
|
-
this._addAgent({ agentId: 'main', label: 'Main Agent', sessionKeys: ['main'] });
|
|
315
320
|
}
|
|
316
321
|
} catch (e) {
|
|
317
322
|
console.warn('[ClawSkinApp] session discovery failed:', e);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Phase 3: Fallback — ensure at least one agent exists
|
|
326
|
+
if (this.agents.length === 0) {
|
|
318
327
|
this._addAgent({ agentId: 'main', label: 'Main Agent', sessionKeys: ['main'] });
|
|
319
328
|
}
|
|
320
329
|
|
|
@@ -46,8 +46,15 @@ class GatewayClient {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
_setState(state, detail) {
|
|
49
|
-
if (state === 'error')
|
|
50
|
-
|
|
49
|
+
if (state === 'error') {
|
|
50
|
+
this.lastError = detail || 'Unknown error';
|
|
51
|
+
console.warn('[GatewayClient]', state, detail || '');
|
|
52
|
+
} else if (state === 'connected') {
|
|
53
|
+
this.lastError = null;
|
|
54
|
+
console.log('[GatewayClient] connected');
|
|
55
|
+
} else {
|
|
56
|
+
console.log('[GatewayClient]', state, detail || '');
|
|
57
|
+
}
|
|
51
58
|
if (this.onStateChange) this.onStateChange(state, detail);
|
|
52
59
|
}
|
|
53
60
|
|
|
@@ -200,10 +207,9 @@ class GatewayClient {
|
|
|
200
207
|
params.auth.token = this.token;
|
|
201
208
|
}
|
|
202
209
|
|
|
203
|
-
// Device identity —
|
|
204
|
-
// The
|
|
205
|
-
|
|
206
|
-
if (typeof DeviceIdentity !== 'undefined') {
|
|
210
|
+
// Device identity — only needed for clients that require Ed25519 pairing
|
|
211
|
+
// (e.g. webchat-ui, control-ui). The 'webchat' client type works without it.
|
|
212
|
+
if (typeof DeviceIdentity !== 'undefined' && this.clientId !== 'webchat') {
|
|
207
213
|
try {
|
|
208
214
|
const identity = await DeviceIdentity.getOrCreate();
|
|
209
215
|
const device = await DeviceIdentity.sign(identity, {
|
package/serve.cjs
CHANGED
|
@@ -44,11 +44,16 @@ function getLocalGatewayConfig() {
|
|
|
44
44
|
const config = JSON.parse(raw);
|
|
45
45
|
const gw = config.gateway || {};
|
|
46
46
|
const port = gw.port || 18789;
|
|
47
|
+
const agentsList = (config.agents?.list || []).map(a => ({
|
|
48
|
+
id: a.id,
|
|
49
|
+
name: a.identity?.name || a.name || a.id,
|
|
50
|
+
}));
|
|
47
51
|
return {
|
|
48
52
|
gatewayUrl: `ws://localhost:${port}`,
|
|
49
53
|
// Safe to expose token on localhost — serve.cjs binds to 127.0.0.1 by default.
|
|
50
54
|
// The token never leaves the local machine.
|
|
51
55
|
token: (gw.auth && gw.auth.token) || '',
|
|
56
|
+
agents: agentsList,
|
|
52
57
|
};
|
|
53
58
|
} catch { continue; }
|
|
54
59
|
}
|