cursorconnect 0.1.2 → 0.1.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/README.md +6 -5
- package/bridge-runtime/dist/agent-title-match.js +16 -0
- package/bridge-runtime/dist/chat-display-store.d.ts +13 -0
- package/bridge-runtime/dist/chat-display-store.js +29 -0
- package/bridge-runtime/dist/chat-display.d.ts +11 -0
- package/bridge-runtime/dist/chat-display.js +290 -0
- package/bridge-runtime/dist/chat-sync.d.ts +6 -0
- package/bridge-runtime/dist/chat-sync.js +88 -0
- package/bridge-runtime/dist/extract-page.js +99 -3
- package/bridge-runtime/dist/history-pipeline-log.d.ts +16 -0
- package/bridge-runtime/dist/history-pipeline-log.js +29 -0
- package/bridge-runtime/dist/jsonl-index.d.ts +15 -3
- package/bridge-runtime/dist/jsonl-index.js +48 -12
- package/bridge-runtime/dist/message-filter.d.ts +10 -0
- package/bridge-runtime/dist/message-filter.js +65 -5
- package/bridge-runtime/dist/pairing-code.d.ts +3 -0
- package/bridge-runtime/dist/pairing-code.js +17 -0
- package/bridge-runtime/dist/pairing-identity.js +4 -7
- package/bridge-runtime/dist/relay.d.ts +8 -0
- package/bridge-runtime/dist/relay.js +254 -25
- package/bridge-runtime/dist/sidebar-merge.js +2 -2
- package/bridge-runtime/dist/types.d.ts +9 -1
- package/config.env.defaults +3 -0
- package/dist/big-code.js +36 -5
- package/dist/bridge-dir.js +6 -1
- package/dist/cli-version.js +13 -0
- package/dist/diagnose.js +224 -0
- package/dist/index.js +56 -92
- package/dist/launch.js +52 -14
- package/dist/pairing-code.js +18 -0
- package/dist/pairing-identity.js +6 -8
- package/dist/pairing-ttl.js +3 -0
- package/dist/print-pairing.js +18 -25
- package/dist/relay-config.js +49 -0
- package/dist/repo-root.js +2 -2
- package/dist/semver.js +21 -0
- package/dist/version-check.js +31 -0
- package/package.json +7 -3
- package/version-policy.json +8 -0
|
@@ -4,10 +4,14 @@ import { randomBytes, timingSafeEqual } from 'crypto';
|
|
|
4
4
|
import { basename } from 'path';
|
|
5
5
|
import { readAllowedMediaFile, resolveMediaPathParam } from './media-path.js';
|
|
6
6
|
import { Server as SocketServer } from 'socket.io';
|
|
7
|
+
import { ChatDisplayStore } from './chat-display-store.js';
|
|
8
|
+
import { filterClientDisplayList, prepareChatMessagesForDisplay, } from './chat-display.js';
|
|
9
|
+
import { isChatSyncedWithCursor } from './chat-sync.js';
|
|
7
10
|
import { mergeSidebarWithJsonl } from './sidebar-merge.js';
|
|
8
11
|
import { transcribeAudioBuffer } from './openai-transcribe.js';
|
|
9
12
|
import { extensionForMime, saveUploadedImage } from './image-upload-store.js';
|
|
10
13
|
import { RelayUpstream } from './relay-upstream.js';
|
|
14
|
+
import { bridgePipelineLog, bridgePipelineReportLines, bridgePipelineSnapshot, } from './history-pipeline-log.js';
|
|
11
15
|
export class Relay {
|
|
12
16
|
stateManager;
|
|
13
17
|
commandExecutor;
|
|
@@ -16,12 +20,17 @@ export class Relay {
|
|
|
16
20
|
messageDebugStore;
|
|
17
21
|
domExtractor;
|
|
18
22
|
lastJsonlIndex = { repos: [], updatedAt: 0 };
|
|
23
|
+
indexEmitTimer = null;
|
|
24
|
+
lastIndexBroadcastAt = 0;
|
|
25
|
+
lastSidebarIndexKey = '';
|
|
26
|
+
lastJsonlIndexKey = '';
|
|
19
27
|
config;
|
|
20
28
|
app = express();
|
|
21
29
|
httpServer = createServer(this.app);
|
|
22
30
|
io;
|
|
23
31
|
tokens = new Set();
|
|
24
32
|
upstream = null;
|
|
33
|
+
chatDisplay = new ChatDisplayStore();
|
|
25
34
|
constructor(config, stateManager, commandExecutor, cdpBridge, jsonlIndex, messageDebugStore, domExtractor) {
|
|
26
35
|
this.stateManager = stateManager;
|
|
27
36
|
this.commandExecutor = commandExecutor;
|
|
@@ -32,6 +41,7 @@ export class Relay {
|
|
|
32
41
|
this.config = config;
|
|
33
42
|
this.io = new SocketServer(this.httpServer, {
|
|
34
43
|
cors: { origin: true, credentials: true },
|
|
44
|
+
maxHttpBufferSize: 20e6,
|
|
35
45
|
});
|
|
36
46
|
this.setupHttp();
|
|
37
47
|
this.setupSocket();
|
|
@@ -82,6 +92,91 @@ export class Relay {
|
|
|
82
92
|
lastError: state.lastError,
|
|
83
93
|
});
|
|
84
94
|
});
|
|
95
|
+
this.app.get('/api/agents/index', async (req, res) => {
|
|
96
|
+
if (!this.checkMediaAuth(req)) {
|
|
97
|
+
res.status(401).json({ error: 'Unauthorized' });
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const stale = Date.now() - (this.lastJsonlIndex.updatedAt ?? 0) > 60_000;
|
|
102
|
+
const index = this.lastJsonlIndex.repos.length && !stale
|
|
103
|
+
? this.lastJsonlIndex
|
|
104
|
+
: await this.jsonlIndex.rebuild({ broadcast: false });
|
|
105
|
+
this.lastJsonlIndex = index;
|
|
106
|
+
const merged = mergeSidebarWithJsonl(this.stateManager.getState().sidebarRepos, index, this.stateManager.getState().composerIdByTitle);
|
|
107
|
+
const bytes = JSON.stringify(merged).length;
|
|
108
|
+
bridgePipelineLog({
|
|
109
|
+
dir: 'out',
|
|
110
|
+
event: 'http:agents:index',
|
|
111
|
+
bytes,
|
|
112
|
+
detail: `repos=${merged.repos?.length ?? 0}`,
|
|
113
|
+
});
|
|
114
|
+
res.json(merged);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
res.status(500).json({ error: err.message });
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
this.app.get('/api/agents/history', async (req, res) => {
|
|
121
|
+
if (!this.checkMediaAuth(req)) {
|
|
122
|
+
res.status(401).json({ error: 'Unauthorized' });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const agentId = String(req.query.agentId ?? '').trim();
|
|
126
|
+
const title = typeof req.query.title === 'string' ? req.query.title.trim() : undefined;
|
|
127
|
+
const limitRaw = Number(req.query.limit ?? 0);
|
|
128
|
+
const limit = Number.isFinite(limitRaw) && limitRaw > 0 ? limitRaw : undefined;
|
|
129
|
+
const requestId = typeof req.query.requestId === 'string' ? req.query.requestId.trim() : undefined;
|
|
130
|
+
if (!agentId) {
|
|
131
|
+
res.status(400).json({ error: 'agentId required' });
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
bridgePipelineLog({
|
|
135
|
+
dir: 'in',
|
|
136
|
+
event: 'http:agents:history',
|
|
137
|
+
requestId,
|
|
138
|
+
agentId,
|
|
139
|
+
detail: `limit=${limit ?? 'all'} title=${title?.slice(0, 32) ?? '-'}`,
|
|
140
|
+
});
|
|
141
|
+
try {
|
|
142
|
+
const history = await this.jsonlIndex.loadHistory(agentId, {
|
|
143
|
+
title,
|
|
144
|
+
composerIdByTitle: this.stateManager.getState().composerIdByTitle,
|
|
145
|
+
limit,
|
|
146
|
+
});
|
|
147
|
+
const messages = this.chatDisplay.applyHistory(agentId, history.messages);
|
|
148
|
+
const body = { ...history, messages, requestId, updatedAt: Date.now() };
|
|
149
|
+
const bytes = JSON.stringify(body).length;
|
|
150
|
+
bridgePipelineLog({
|
|
151
|
+
dir: 'out',
|
|
152
|
+
event: 'http:agents:history',
|
|
153
|
+
requestId,
|
|
154
|
+
agentId,
|
|
155
|
+
bytes,
|
|
156
|
+
msgs: history.messages?.length ?? 0,
|
|
157
|
+
detail: `total=${history.totalMessages ?? '?'}`,
|
|
158
|
+
});
|
|
159
|
+
res.json(body);
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
bridgePipelineLog({
|
|
163
|
+
dir: 'internal',
|
|
164
|
+
event: 'http:agents:history:ERR',
|
|
165
|
+
requestId,
|
|
166
|
+
agentId,
|
|
167
|
+
detail: err.message,
|
|
168
|
+
});
|
|
169
|
+
res.status(500).json({ error: err.message });
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
this.app.get('/api/debug/history-pipeline', (_req, res) => {
|
|
173
|
+
res.json({
|
|
174
|
+
ok: true,
|
|
175
|
+
at: Date.now(),
|
|
176
|
+
lines: bridgePipelineReportLines(),
|
|
177
|
+
entries: bridgePipelineSnapshot(),
|
|
178
|
+
});
|
|
179
|
+
});
|
|
85
180
|
this.app.get('/media/file', (req, res) => {
|
|
86
181
|
if (!this.checkMediaAuth(req)) {
|
|
87
182
|
res.status(401).json({ error: 'Unauthorized' });
|
|
@@ -212,37 +307,108 @@ export class Relay {
|
|
|
212
307
|
this.io.on('connection', (socket) => this.onConnect(socket));
|
|
213
308
|
}
|
|
214
309
|
broadcast(event, payload) {
|
|
310
|
+
if (event === 'agents:history' || event === 'agent:history') {
|
|
311
|
+
const h = payload;
|
|
312
|
+
const bytes = JSON.stringify(payload ?? {}).length;
|
|
313
|
+
bridgePipelineLog({
|
|
314
|
+
dir: 'out',
|
|
315
|
+
event: `broadcast:${event}`,
|
|
316
|
+
requestId: h?.requestId,
|
|
317
|
+
agentId: h?.agentId,
|
|
318
|
+
bytes,
|
|
319
|
+
msgs: h?.messages?.length ?? 0,
|
|
320
|
+
detail: `upstream=${this.upstream?.connected ?? false}`,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
215
323
|
this.io.emit(event, payload);
|
|
216
324
|
this.upstream?.emit(event, payload);
|
|
217
325
|
}
|
|
326
|
+
prepareStateMessages(raw, patch) {
|
|
327
|
+
const state = { ...this.stateManager.getState(), ...patch };
|
|
328
|
+
for (const [agentId, meta] of this.jsonlIndex.getSubscribedAgents()) {
|
|
329
|
+
if (isChatSyncedWithCursor(agentId, meta.title, state)) {
|
|
330
|
+
return this.chatDisplay.mergeLiveForAgent(agentId, raw);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return filterClientDisplayList(prepareChatMessagesForDisplay(raw));
|
|
334
|
+
}
|
|
335
|
+
withDisplayState(payload) {
|
|
336
|
+
if (!payload.messages?.length)
|
|
337
|
+
return payload;
|
|
338
|
+
return {
|
|
339
|
+
...payload,
|
|
340
|
+
messages: this.prepareStateMessages(payload.messages, payload),
|
|
341
|
+
};
|
|
342
|
+
}
|
|
218
343
|
wireEvents() {
|
|
219
344
|
this.stateManager.on('state:full', (state) => {
|
|
220
|
-
this.broadcast('state:full', state);
|
|
345
|
+
this.broadcast('state:full', this.withDisplayState(state));
|
|
221
346
|
this.emitAgentsIndex();
|
|
222
347
|
});
|
|
223
348
|
this.stateManager.on('state:patch', (patch) => {
|
|
224
|
-
this.broadcast('state:patch', patch);
|
|
225
|
-
if (patch.sidebarRepos || patch.composerIdByTitle)
|
|
226
|
-
|
|
349
|
+
this.broadcast('state:patch', this.withDisplayState(patch));
|
|
350
|
+
if (patch.sidebarRepos || patch.composerIdByTitle) {
|
|
351
|
+
const key = JSON.stringify([patch.sidebarRepos, patch.composerIdByTitle]);
|
|
352
|
+
if (key !== this.lastSidebarIndexKey) {
|
|
353
|
+
this.lastSidebarIndexKey = key;
|
|
354
|
+
this.emitAgentsIndex();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
227
357
|
});
|
|
228
358
|
this.jsonlIndex.on('agents:index', (index) => {
|
|
359
|
+
const key = JSON.stringify(index.repos?.map((r) => [r.id, r.agents.length]));
|
|
360
|
+
if (key === this.lastJsonlIndexKey)
|
|
361
|
+
return;
|
|
362
|
+
this.lastJsonlIndexKey = key;
|
|
229
363
|
this.lastJsonlIndex = index;
|
|
230
364
|
this.emitAgentsIndex();
|
|
231
365
|
});
|
|
232
|
-
this.jsonlIndex.on('agent:history', (history) =>
|
|
366
|
+
this.jsonlIndex.on('agent:history', (history) => {
|
|
367
|
+
const messages = this.chatDisplay.applyHistory(history.agentId, history.messages, {
|
|
368
|
+
mergeWithCache: true,
|
|
369
|
+
});
|
|
370
|
+
this.broadcast('agent:history', { ...history, messages });
|
|
371
|
+
});
|
|
233
372
|
}
|
|
234
|
-
emitAgentsIndex() {
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
373
|
+
emitAgentsIndex(force = false) {
|
|
374
|
+
const send = () => {
|
|
375
|
+
const merged = mergeSidebarWithJsonl(this.stateManager.getState().sidebarRepos, this.lastJsonlIndex, this.stateManager.getState().composerIdByTitle);
|
|
376
|
+
this.broadcast('agents:index', merged);
|
|
377
|
+
this.lastIndexBroadcastAt = Date.now();
|
|
378
|
+
};
|
|
379
|
+
if (force) {
|
|
380
|
+
if (this.indexEmitTimer)
|
|
381
|
+
clearTimeout(this.indexEmitTimer);
|
|
382
|
+
this.indexEmitTimer = null;
|
|
383
|
+
send();
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const elapsed = Date.now() - this.lastIndexBroadcastAt;
|
|
387
|
+
if (elapsed >= 60_000) {
|
|
388
|
+
send();
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
if (this.indexEmitTimer)
|
|
392
|
+
return;
|
|
393
|
+
this.indexEmitTimer = setTimeout(() => {
|
|
394
|
+
this.indexEmitTimer = null;
|
|
395
|
+
send();
|
|
396
|
+
}, 60_000 - elapsed);
|
|
238
397
|
}
|
|
239
|
-
|
|
240
|
-
this.broadcast
|
|
241
|
-
void this.jsonlIndex.rebuild().then((index) => {
|
|
398
|
+
refreshAgentsIndex(force = false) {
|
|
399
|
+
void this.jsonlIndex.rebuild({ broadcast: false }).then((index) => {
|
|
242
400
|
this.lastJsonlIndex = index;
|
|
243
|
-
this.
|
|
401
|
+
this.emitAgentsIndex(force);
|
|
244
402
|
});
|
|
245
403
|
}
|
|
404
|
+
pushFullStateToRemote() {
|
|
405
|
+
this.broadcast('state:full', this.withDisplayState(this.stateManager.getState()));
|
|
406
|
+
if (this.lastJsonlIndex.updatedAt > 0) {
|
|
407
|
+
this.emitAgentsIndex(true);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
this.refreshAgentsIndex(true);
|
|
411
|
+
}
|
|
246
412
|
async trySwitchWindowForAgent(agentId) {
|
|
247
413
|
const projectDir = this.jsonlIndex.findProjectDirForAgent(agentId);
|
|
248
414
|
if (!projectDir)
|
|
@@ -273,11 +439,19 @@ export class Relay {
|
|
|
273
439
|
this.dispatchClientEvent(event, args, reply);
|
|
274
440
|
}
|
|
275
441
|
onConnect(socket) {
|
|
276
|
-
socket.emit('state:full', this.stateManager.getState());
|
|
277
|
-
|
|
278
|
-
this.lastJsonlIndex = index;
|
|
442
|
+
socket.emit('state:full', this.withDisplayState(this.stateManager.getState()));
|
|
443
|
+
const sendIndex = (index) => {
|
|
279
444
|
socket.emit('agents:index', mergeSidebarWithJsonl(this.stateManager.getState().sidebarRepos, index, this.stateManager.getState().composerIdByTitle));
|
|
280
|
-
}
|
|
445
|
+
};
|
|
446
|
+
if (this.lastJsonlIndex.updatedAt > 0) {
|
|
447
|
+
sendIndex(this.lastJsonlIndex);
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
void this.jsonlIndex.rebuild({ broadcast: false }).then((index) => {
|
|
451
|
+
this.lastJsonlIndex = index;
|
|
452
|
+
sendIndex(index);
|
|
453
|
+
});
|
|
454
|
+
}
|
|
281
455
|
const reply = (ev, payload) => {
|
|
282
456
|
socket.emit(ev, payload);
|
|
283
457
|
};
|
|
@@ -297,7 +471,7 @@ export class Relay {
|
|
|
297
471
|
await this.runAgentsFocus(data, reply);
|
|
298
472
|
});
|
|
299
473
|
socket.on('agents:refresh', () => {
|
|
300
|
-
|
|
474
|
+
this.refreshAgentsIndex(true);
|
|
301
475
|
});
|
|
302
476
|
socket.on('disconnect', () => {
|
|
303
477
|
/* subscriptions stay global — one phone session typical */
|
|
@@ -325,7 +499,7 @@ export class Relay {
|
|
|
325
499
|
return;
|
|
326
500
|
}
|
|
327
501
|
if (event === 'agents:refresh') {
|
|
328
|
-
|
|
502
|
+
this.refreshAgentsIndex(true);
|
|
329
503
|
}
|
|
330
504
|
}
|
|
331
505
|
async runCommand(payload, reply) {
|
|
@@ -353,12 +527,65 @@ export class Relay {
|
|
|
353
527
|
this.domExtractor.pollNow();
|
|
354
528
|
}
|
|
355
529
|
}
|
|
356
|
-
async runAgentsHistory({ agentId, title }, reply) {
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
530
|
+
async runAgentsHistory({ agentId, title, requestId, limit, }, reply) {
|
|
531
|
+
const t0 = Date.now();
|
|
532
|
+
const viaUpstream = this.upstream?.connected ?? false;
|
|
533
|
+
const socketLimit = limit && limit > 0 ? limit : 15;
|
|
534
|
+
console.log(`[relay] agents:history req agentId=${agentId} title=${title?.slice(0, 48) ?? '-'} limit=${socketLimit} rid=${requestId ?? '-'} upstream=${viaUpstream}`);
|
|
535
|
+
this.jsonlIndex.historyReplyInFlight.add(agentId);
|
|
536
|
+
bridgePipelineLog({
|
|
537
|
+
dir: 'in',
|
|
538
|
+
event: 'agents:history:req',
|
|
539
|
+
requestId,
|
|
540
|
+
agentId,
|
|
541
|
+
detail: `limit=${socketLimit} title=${title?.slice(0, 32) ?? '-'} upstream=${viaUpstream}`,
|
|
360
542
|
});
|
|
361
|
-
|
|
543
|
+
try {
|
|
544
|
+
const history = await this.jsonlIndex.loadHistory(agentId, {
|
|
545
|
+
title,
|
|
546
|
+
composerIdByTitle: this.stateManager.getState().composerIdByTitle,
|
|
547
|
+
limit: socketLimit,
|
|
548
|
+
});
|
|
549
|
+
const messages = this.chatDisplay.applyHistory(agentId, history.messages);
|
|
550
|
+
const ms = Date.now() - t0;
|
|
551
|
+
const bytes = JSON.stringify(messages).length;
|
|
552
|
+
console.log(`[relay] agents:history ok agentId=${history.agentId} msgs=${history.messages?.length ?? 0}/${history.totalMessages ?? '?'} bytes=${bytes} ms=${ms} rid=${requestId ?? '-'}`);
|
|
553
|
+
bridgePipelineLog({
|
|
554
|
+
dir: 'out',
|
|
555
|
+
event: 'agents:history:reply',
|
|
556
|
+
requestId,
|
|
557
|
+
agentId: history.agentId,
|
|
558
|
+
bytes,
|
|
559
|
+
msgs: history.messages?.length ?? 0,
|
|
560
|
+
detail: `total=${history.totalMessages ?? '?'} ms=${ms}`,
|
|
561
|
+
});
|
|
562
|
+
reply('agents:history', {
|
|
563
|
+
...history,
|
|
564
|
+
messages,
|
|
565
|
+
requestId,
|
|
566
|
+
updatedAt: Date.now(),
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
catch (err) {
|
|
570
|
+
console.error(`[relay] agents:history fail agentId=${agentId} ms=${Date.now() - t0} rid=${requestId ?? '-'}:`, err.message);
|
|
571
|
+
bridgePipelineLog({
|
|
572
|
+
dir: 'internal',
|
|
573
|
+
event: 'agents:history:fail',
|
|
574
|
+
requestId,
|
|
575
|
+
agentId,
|
|
576
|
+
detail: err.message,
|
|
577
|
+
});
|
|
578
|
+
reply('agents:history', {
|
|
579
|
+
agentId,
|
|
580
|
+
messages: [],
|
|
581
|
+
totalMessages: 0,
|
|
582
|
+
requestId,
|
|
583
|
+
updatedAt: Date.now(),
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
finally {
|
|
587
|
+
this.jsonlIndex.historyReplyInFlight.delete(agentId);
|
|
588
|
+
}
|
|
362
589
|
}
|
|
363
590
|
async runAgentsSubscribe({ agentId, title, focus, }) {
|
|
364
591
|
if (!agentId)
|
|
@@ -379,8 +606,10 @@ export class Relay {
|
|
|
379
606
|
}
|
|
380
607
|
}
|
|
381
608
|
runAgentsUnsubscribe({ agentId }) {
|
|
382
|
-
if (agentId)
|
|
609
|
+
if (agentId) {
|
|
383
610
|
this.jsonlIndex.unsubscribe(agentId);
|
|
611
|
+
this.chatDisplay.clearAgent(agentId);
|
|
612
|
+
}
|
|
384
613
|
}
|
|
385
614
|
async runAgentsFocus({ agentId, title }, reply) {
|
|
386
615
|
if (!agentId)
|
|
@@ -3,7 +3,7 @@ export { normalizeAgentTitle } from './agent-title-match.js';
|
|
|
3
3
|
/** Prefer Cursor DOM sidebar order/names; attach JSONL ids when titles match. */
|
|
4
4
|
export function mergeSidebarWithJsonl(sidebarRepos, jsonl, composerIdByTitle) {
|
|
5
5
|
if (!sidebarRepos?.length)
|
|
6
|
-
return jsonl;
|
|
6
|
+
return { ...jsonl, listSource: 'jsonl' };
|
|
7
7
|
const byTitle = new Map();
|
|
8
8
|
for (const repo of jsonl.repos) {
|
|
9
9
|
for (const agent of repo.agents) {
|
|
@@ -43,5 +43,5 @@ export function mergeSidebarWithJsonl(sidebarRepos, jsonl, composerIdByTitle) {
|
|
|
43
43
|
};
|
|
44
44
|
}),
|
|
45
45
|
}));
|
|
46
|
-
return { repos, updatedAt: Date.now() };
|
|
46
|
+
return { repos, updatedAt: Date.now(), listSource: 'sidebar' };
|
|
47
47
|
}
|
|
@@ -229,15 +229,23 @@ export interface RepoGroup {
|
|
|
229
229
|
export interface AgentsIndex {
|
|
230
230
|
repos: RepoGroup[];
|
|
231
231
|
updatedAt: number;
|
|
232
|
+
/** `sidebar` = порядок/названия из CDP; `jsonl` = архив на диске (не как в Cursor). */
|
|
233
|
+
listSource?: 'sidebar' | 'jsonl';
|
|
232
234
|
}
|
|
233
235
|
export interface HistoryMessage {
|
|
234
236
|
role: 'user' | 'assistant' | 'system';
|
|
235
237
|
text: string;
|
|
238
|
+
html?: string;
|
|
239
|
+
/** Absolute paths from JSONL `<image_files>` (served via GET /media/file). */
|
|
240
|
+
images?: string[];
|
|
236
241
|
ts?: number;
|
|
237
242
|
}
|
|
238
243
|
export interface AgentHistory {
|
|
239
244
|
agentId: string;
|
|
240
|
-
|
|
245
|
+
/** Display-ready chat rows (normalized, deduped, filtered on bridge). */
|
|
246
|
+
messages: ChatMessage[];
|
|
241
247
|
updatedAt?: number;
|
|
248
|
+
requestId?: string;
|
|
249
|
+
totalMessages?: number;
|
|
242
250
|
}
|
|
243
251
|
export type ExtractedPageState = Omit<CursorState, 'connected' | 'windows' | 'activeWindowId' | 'windowSnapshots' | 'updatedAt'>;
|
package/dist/big-code.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** 5×5 block
|
|
2
|
-
const
|
|
1
|
+
/** 5×5 block glyphs (█) for pairing code — A–Z and 0–9. */
|
|
2
|
+
const GLYPHS = {
|
|
3
3
|
'0': ['█████', '█ █', '█ █', '█ █', '█████'],
|
|
4
4
|
'1': [' █ ', ' ██ ', ' █ ', ' █ ', ' ███ '],
|
|
5
5
|
'2': ['█████', ' █', '█████', '█ ', '█████'],
|
|
@@ -10,13 +10,44 @@ const DIGITS = {
|
|
|
10
10
|
'7': ['█████', ' █', ' █ ', ' █ ', ' █ '],
|
|
11
11
|
'8': ['█████', '█ █', '█████', '█ █', '█████'],
|
|
12
12
|
'9': ['█████', '█ █', '█████', ' █', '█████'],
|
|
13
|
+
A: [' ███ ', '█ █', '█████', '█ █', '█ █'],
|
|
14
|
+
B: ['████ ', '█ █', '████ ', '█ █', '████ '],
|
|
15
|
+
C: [' ████', '█ ', '█ ', '█ ', ' ████'],
|
|
16
|
+
D: ['████ ', '█ █', '█ █', '█ █', '████ '],
|
|
17
|
+
E: ['█████', '█ ', '████ ', '█ ', '█████'],
|
|
18
|
+
F: ['█████', '█ ', '████ ', '█ ', '█ '],
|
|
19
|
+
G: [' ████', '█ ', '█ ██', '█ █', ' ████'],
|
|
20
|
+
H: ['█ █', '█ █', '█████', '█ █', '█ █'],
|
|
21
|
+
I: [' ███ ', ' █ ', ' █ ', ' █ ', ' ███ '],
|
|
22
|
+
J: [' ███', ' █', ' █', '█ █', ' ███ '],
|
|
23
|
+
K: ['█ █', '█ █ ', '███ ', '█ █ ', '█ █'],
|
|
24
|
+
L: ['█ ', '█ ', '█ ', '█ ', '█████'],
|
|
25
|
+
M: ['█ █', '██ ██', '█ █ █', '█ █', '█ █'],
|
|
26
|
+
N: ['█ █', '██ █', '█ █ █', '█ ██', '█ █'],
|
|
27
|
+
O: [' ███ ', '█ █', '█ █', '█ █', ' ███ '],
|
|
28
|
+
P: ['████ ', '█ █', '████ ', '█ ', '█ '],
|
|
29
|
+
Q: [' ███ ', '█ █', '█ █', '█ ██', ' ████'],
|
|
30
|
+
R: ['████ ', '█ █', '████ ', '█ █ ', '█ █'],
|
|
31
|
+
S: [' ████', '█ ', ' ███ ', ' █', '████ '],
|
|
32
|
+
T: ['█████', ' █ ', ' █ ', ' █ ', ' █ '],
|
|
33
|
+
U: ['█ █', '█ █', '█ █', '█ █', ' ███ '],
|
|
34
|
+
V: ['█ █', '█ █', '█ █', ' █ █ ', ' █ '],
|
|
35
|
+
W: ['█ █', '█ █', '█ █ █', '██ ██', '█ █'],
|
|
36
|
+
X: ['█ █', ' █ █ ', ' █ ', ' █ █ ', '█ █'],
|
|
37
|
+
Y: ['█ █', ' █ █ ', ' █ ', ' █ ', ' █ '],
|
|
38
|
+
Z: ['█████', ' █ ', ' █ ', ' █ ', '█████'],
|
|
13
39
|
};
|
|
40
|
+
const FALLBACK = GLYPHS['8'];
|
|
14
41
|
const GAP = ' ';
|
|
15
42
|
export function renderBigCode(code) {
|
|
16
|
-
const
|
|
43
|
+
const chars = code
|
|
44
|
+
.toUpperCase()
|
|
45
|
+
.replace(/[^A-Z0-9]/g, '')
|
|
46
|
+
.slice(0, 6)
|
|
47
|
+
.split('');
|
|
17
48
|
const rows = ['', '', '', '', ''];
|
|
18
|
-
for (const ch of
|
|
19
|
-
const art =
|
|
49
|
+
for (const ch of chars) {
|
|
50
|
+
const art = GLYPHS[ch] ?? FALLBACK;
|
|
20
51
|
for (let i = 0; i < 5; i++) {
|
|
21
52
|
rows[i] += art[i] + GAP;
|
|
22
53
|
}
|
package/dist/bridge-dir.js
CHANGED
|
@@ -51,7 +51,7 @@ export function resolveBridgeDir() {
|
|
|
51
51
|
if (isValidBridgeDir(bridge))
|
|
52
52
|
return bridge;
|
|
53
53
|
}
|
|
54
|
-
throw new Error('Не найден bridge.\n' +
|
|
54
|
+
throw new Error('Не найден Cursor Connect (bridge).\n' +
|
|
55
55
|
' npm install -g cursorconnect && cursorconnect start\n' +
|
|
56
56
|
' (для разработки: клон репо + npm install в корне)');
|
|
57
57
|
}
|
|
@@ -65,6 +65,11 @@ export function ensureUserConfig() {
|
|
|
65
65
|
copyFileSync(devEnv, USER_CONFIG_ENV);
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
68
|
+
const bundled = join(resolvePackageRoot(), 'config.env.defaults');
|
|
69
|
+
if (existsSync(bundled)) {
|
|
70
|
+
copyFileSync(bundled, USER_CONFIG_ENV);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
68
73
|
const template = join(resolvePackageRoot(), 'bridge-runtime', '.env.example');
|
|
69
74
|
if (existsSync(template)) {
|
|
70
75
|
copyFileSync(template, USER_CONFIG_ENV);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
const pkgPath = join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');
|
|
5
|
+
export const CLI_VERSION = (() => {
|
|
6
|
+
try {
|
|
7
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
8
|
+
return pkg.version?.trim() || '0.0.0';
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return '0.0.0';
|
|
12
|
+
}
|
|
13
|
+
})();
|