@unbound-app/debugger 0.8.0 → 0.10.1
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.mjs +106 -68
- package/package.json +7 -6
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { stripEscapeSequences, terminal } from "terminal-kit";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { parseMessage } from "@unbound-app/debugger-protocol";
|
|
4
|
+
import { CONTROLLER_ENDPOINT_MARKER, DEFAULT_BRIDGE_PORT, DEFAULT_EVAL_TIMEOUT_MS, MAX_EVAL_TIMEOUT_MS, parseMessage } from "@unbound-app/debugger-protocol";
|
|
5
5
|
import os from "node:os";
|
|
6
6
|
import { cli } from "cleye";
|
|
7
|
-
|
|
7
|
+
// src/lib/history.ts
|
|
8
8
|
const HISTORY_PATH = join(__dirname, "..", "..", ".history.json");
|
|
9
9
|
const HISTORY_FILE = Bun.file(HISTORY_PATH);
|
|
10
10
|
let history = [];
|
|
@@ -25,10 +25,10 @@ function addHistoryItem(item) {
|
|
|
25
25
|
function persistHistory() {
|
|
26
26
|
HISTORY_FILE.write(JSON.stringify(history, null, 2));
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
//#region src/lib/session.ts
|
|
28
|
+
// src/lib/session.ts
|
|
30
29
|
const state$2 = {
|
|
31
30
|
device: null,
|
|
31
|
+
deviceInfo: null,
|
|
32
32
|
controllers: /* @__PURE__ */ new Set()
|
|
33
33
|
};
|
|
34
34
|
const pending = /* @__PURE__ */ new Map();
|
|
@@ -38,20 +38,20 @@ const deviceListeners = /* @__PURE__ */ new Set();
|
|
|
38
38
|
const evalListeners = /* @__PURE__ */ new Set();
|
|
39
39
|
const resultListeners = /* @__PURE__ */ new Set();
|
|
40
40
|
const controllerListeners = /* @__PURE__ */ new Set();
|
|
41
|
-
/** How long to wait for a device to answer an eval before failing it. */
|
|
42
|
-
const EVAL_TIMEOUT_MS = 1e4;
|
|
43
41
|
const PLUGIN_PUSH_TIMEOUT_MS = 6e4;
|
|
44
42
|
/**
|
|
45
|
-
* @description Registers the connected device,
|
|
46
|
-
*
|
|
43
|
+
* @description Registers the connected device, replacing any earlier one so a relaunched or
|
|
44
|
+
* reconnecting app always takes over from a socket that died without closing.
|
|
47
45
|
* @param socket The device's socket.
|
|
48
|
-
* @returns Whether the device was accepted (false if one is already connected).
|
|
49
46
|
*/
|
|
50
47
|
function attachDevice(socket) {
|
|
51
|
-
|
|
48
|
+
const previous = state$2.device;
|
|
49
|
+
if (previous) {
|
|
50
|
+
detachDevice(previous);
|
|
51
|
+
previous.close();
|
|
52
|
+
}
|
|
52
53
|
state$2.device = socket;
|
|
53
54
|
broadcastDeviceStatus(true);
|
|
54
|
-
return true;
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
57
|
* @description Clears the device on disconnect, notifies controllers, and fails every in-flight eval
|
|
@@ -61,6 +61,7 @@ function attachDevice(socket) {
|
|
|
61
61
|
function detachDevice(socket) {
|
|
62
62
|
if (state$2.device !== socket) return;
|
|
63
63
|
state$2.device = null;
|
|
64
|
+
state$2.deviceInfo = null;
|
|
64
65
|
for (const [id, entry] of pending) {
|
|
65
66
|
clearTimeout(entry.timer);
|
|
66
67
|
entry.deliver({
|
|
@@ -113,18 +114,27 @@ function detachController(socket) {
|
|
|
113
114
|
* @description Runs code on the device on behalf of a controller socket, delivering the id-correlated
|
|
114
115
|
* result back over that same socket. Sends an error frame instead if no device is connected.
|
|
115
116
|
* @param socket The controller that issued the request.
|
|
116
|
-
* @param
|
|
117
|
-
* @param code The JavaScript to evaluate on the device.
|
|
117
|
+
* @param request The controller's eval, whose `id` correlates the result and whose `timeout` bounds the wait.
|
|
118
118
|
*/
|
|
119
|
-
function evaluateForController(socket,
|
|
119
|
+
function evaluateForController(socket, request) {
|
|
120
|
+
const { id, code } = request;
|
|
120
121
|
const deliver = getControllerDelivery(socket);
|
|
121
122
|
for (const listener of evalListeners) listener(code);
|
|
122
|
-
dispatch(id, code, (result) => {
|
|
123
|
+
dispatch(id, code, resolveEvalTimeout(request.timeout), (result) => {
|
|
123
124
|
for (const listener of resultListeners) listener(result);
|
|
124
125
|
deliver(result);
|
|
125
126
|
});
|
|
126
127
|
}
|
|
127
128
|
/**
|
|
129
|
+
* @description Picks how long an eval may run: the requested timeout when it is a positive number of
|
|
130
|
+
* milliseconds, capped at {@link MAX_EVAL_TIMEOUT_MS}, otherwise {@link DEFAULT_EVAL_TIMEOUT_MS}.
|
|
131
|
+
* @param requested The timeout the controller asked for, if any.
|
|
132
|
+
* @returns The timeout to apply, in milliseconds.
|
|
133
|
+
*/
|
|
134
|
+
function resolveEvalTimeout(requested) {
|
|
135
|
+
return typeof requested === "number" && requested > 0 ? Math.min(requested, MAX_EVAL_TIMEOUT_MS) : DEFAULT_EVAL_TIMEOUT_MS;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
128
138
|
* @description Forwards a controller's {@link PluginPushRequest} to the device and delivers the
|
|
129
139
|
* id-correlated {@link PluginPushResult} back over that same controller's socket. Replies with an
|
|
130
140
|
* error frame instead if no device is connected or it doesn't answer within {@link PLUGIN_PUSH_TIMEOUT_MS}.
|
|
@@ -161,16 +171,16 @@ function pushPluginForController(socket, request) {
|
|
|
161
171
|
/**
|
|
162
172
|
* @description Runs code on the device on behalf of an in-process caller (the terminal REPL),
|
|
163
173
|
* resolving with the device's answer. Rejects if no device is connected or it doesn't answer within
|
|
164
|
-
* {@link
|
|
174
|
+
* {@link DEFAULT_EVAL_TIMEOUT_MS}.
|
|
165
175
|
* @param code The JavaScript to evaluate on the device.
|
|
166
176
|
* @returns The device's {@link EvalResult}.
|
|
167
177
|
*/
|
|
168
178
|
function evaluate(code) {
|
|
169
179
|
return new Promise((resolve) => {
|
|
170
|
-
dispatch(crypto.randomUUID(), code, resolve);
|
|
180
|
+
dispatch(crypto.randomUUID(), code, DEFAULT_EVAL_TIMEOUT_MS, resolve);
|
|
171
181
|
});
|
|
172
182
|
}
|
|
173
|
-
function dispatch(id, code, deliver) {
|
|
183
|
+
function dispatch(id, code, timeout, deliver) {
|
|
174
184
|
if (!state$2.device) {
|
|
175
185
|
deliver({
|
|
176
186
|
type: "eval-result",
|
|
@@ -186,9 +196,9 @@ function dispatch(id, code, deliver) {
|
|
|
186
196
|
type: "eval-result",
|
|
187
197
|
id,
|
|
188
198
|
ok: false,
|
|
189
|
-
error: `Evaluation timed out after ${
|
|
199
|
+
error: `Evaluation timed out after ${timeout}ms.`
|
|
190
200
|
});
|
|
191
|
-
},
|
|
201
|
+
}, timeout);
|
|
192
202
|
pending.set(id, {
|
|
193
203
|
deliver,
|
|
194
204
|
timer
|
|
@@ -221,6 +231,11 @@ function handleDeviceMessage$1(message) {
|
|
|
221
231
|
entry.deliver(message);
|
|
222
232
|
return;
|
|
223
233
|
}
|
|
234
|
+
if (message.type === "hello") {
|
|
235
|
+
state$2.deviceInfo = message.device;
|
|
236
|
+
broadcastDeviceStatus(true);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
224
239
|
if (message.type !== "log") return;
|
|
225
240
|
for (const socket of state$2.controllers) socket.send(JSON.stringify(message));
|
|
226
241
|
for (const listener of logListeners) listener(message);
|
|
@@ -235,6 +250,15 @@ function onLog(listener) {
|
|
|
235
250
|
return () => void logListeners.delete(listener);
|
|
236
251
|
}
|
|
237
252
|
/**
|
|
253
|
+
* @description Subscribes to device connect/disconnect transitions.
|
|
254
|
+
* @param listener Called with whether a device is now connected.
|
|
255
|
+
* @returns An unsubscribe function.
|
|
256
|
+
*/
|
|
257
|
+
function onDevice(listener) {
|
|
258
|
+
deviceListeners.add(listener);
|
|
259
|
+
return () => void deviceListeners.delete(listener);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
238
262
|
* @description Subscribes to code a controller (e.g. the MCP) sends to evaluate.
|
|
239
263
|
* @param listener Called with each controller's code.
|
|
240
264
|
* @returns An unsubscribe function.
|
|
@@ -270,17 +294,21 @@ function getControllerDelivery(socket) {
|
|
|
270
294
|
return deliver;
|
|
271
295
|
}
|
|
272
296
|
function sendDeviceStatus(socket, connected) {
|
|
273
|
-
|
|
297
|
+
const status = connected ? {
|
|
298
|
+
type: "device-status",
|
|
299
|
+
connected,
|
|
300
|
+
device: state$2.deviceInfo ?? void 0
|
|
301
|
+
} : {
|
|
274
302
|
type: "device-status",
|
|
275
303
|
connected
|
|
276
|
-
}
|
|
304
|
+
};
|
|
305
|
+
socket.send(JSON.stringify(status));
|
|
277
306
|
}
|
|
278
307
|
function broadcastDeviceStatus(connected) {
|
|
279
308
|
for (const socket of state$2.controllers) sendDeviceStatus(socket, connected);
|
|
280
|
-
for (const listener of deviceListeners) listener(connected);
|
|
309
|
+
for (const listener of deviceListeners) listener(connected, state$2.deviceInfo);
|
|
281
310
|
}
|
|
282
|
-
|
|
283
|
-
//#region src/lib/repl.ts
|
|
311
|
+
// src/lib/repl.ts
|
|
284
312
|
const state$1 = {
|
|
285
313
|
repl: null,
|
|
286
314
|
currentInput: ""
|
|
@@ -322,8 +350,7 @@ function abortCurrentReplInput({ deletePrompt = false, deleteCurrentInput = fals
|
|
|
322
350
|
if (deletePrompt) terminal.deleteLine(-1);
|
|
323
351
|
if (deleteCurrentInput) state$1.currentInput = "";
|
|
324
352
|
}
|
|
325
|
-
|
|
326
|
-
//#region src/lib/format-log.ts
|
|
353
|
+
// src/lib/format-log.ts
|
|
327
354
|
/**
|
|
328
355
|
* @description Cleans a Hermes-joined console line into space-separated, unquoted output.
|
|
329
356
|
* @param message The raw `nativeLoggingHook` message string.
|
|
@@ -344,7 +371,7 @@ function splitTopLevel(input) {
|
|
|
344
371
|
let inString = false;
|
|
345
372
|
let start = 0;
|
|
346
373
|
for (let i = 0, len = input.length; i < len; i++) {
|
|
347
|
-
const char = input
|
|
374
|
+
const char = input.charAt(i);
|
|
348
375
|
if (inString) {
|
|
349
376
|
if (char === "\\") {
|
|
350
377
|
i++;
|
|
@@ -384,8 +411,7 @@ function unquoteSegment(segment) {
|
|
|
384
411
|
if (trimmed.length < 2 || trimmed[0] !== "'" || trimmed[trimmed.length - 1] !== "'") return trimmed;
|
|
385
412
|
return trimmed.slice(1, -1).replace(/\\'/g, "'");
|
|
386
413
|
}
|
|
387
|
-
|
|
388
|
-
//#region src/lib/banner.ts
|
|
414
|
+
// src/lib/banner.ts
|
|
389
415
|
/**
|
|
390
416
|
* Renders the debugger's startup banner: a pink rounded box sized to the terminal, capped on wide
|
|
391
417
|
* ones, falling back to plain starred lines when the terminal is too narrow for a box.
|
|
@@ -430,27 +456,27 @@ function rowText(line) {
|
|
|
430
456
|
function printBox(title, lines, inner) {
|
|
431
457
|
const pad = " ".repeat(PADDING);
|
|
432
458
|
const horizontal = "─".repeat(inner + 4);
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
459
|
+
terminal.colorRgbHex(PINK, `╭${horizontal}╮\n`);
|
|
460
|
+
terminal.colorRgbHex(PINK, `│${pad}`);
|
|
461
|
+
terminal.bold.colorRgbHex(PINK, center(title, inner));
|
|
462
|
+
terminal.colorRgbHex(PINK, `${pad}│\n`);
|
|
463
|
+
terminal.colorRgbHex(PINK, `├${horizontal}┤\n`);
|
|
438
464
|
for (const line of lines) {
|
|
439
465
|
const label = line.label.padEnd(8);
|
|
440
466
|
const filler = " ".repeat(Math.max(inner - rowText(line).length, 0));
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
467
|
+
terminal.colorRgbHex(PINK, `│${pad}`);
|
|
468
|
+
terminal.bold.colorRgbHex(PINK, label);
|
|
469
|
+
terminal.colorRgbHex(GREY, line.value);
|
|
444
470
|
terminal(filler);
|
|
445
|
-
|
|
471
|
+
terminal.colorRgbHex(PINK, `${pad}│\n`);
|
|
446
472
|
}
|
|
447
|
-
|
|
473
|
+
terminal.colorRgbHex(PINK, `╰${horizontal}╯\n`);
|
|
448
474
|
}
|
|
449
475
|
function printFallback(title, lines) {
|
|
450
|
-
|
|
476
|
+
terminal.bold.colorRgbHex(PINK, `✦ ${title}\n`);
|
|
451
477
|
for (const line of lines) {
|
|
452
|
-
|
|
453
|
-
|
|
478
|
+
terminal.colorRgbHex(PINK, ` ${line.label.padEnd(8)}`);
|
|
479
|
+
terminal.colorRgbHex(GREY, `${line.value}\n`);
|
|
454
480
|
}
|
|
455
481
|
}
|
|
456
482
|
/** The usable terminal width: terminal-kit's when it's a real TTY, else stdout's, else a default. */
|
|
@@ -466,24 +492,16 @@ function center(text, width) {
|
|
|
466
492
|
const left = Math.floor(total / 2);
|
|
467
493
|
return " ".repeat(left) + text + " ".repeat(total - left);
|
|
468
494
|
}
|
|
469
|
-
|
|
470
|
-
terminal.colorRgbHex(hex, text);
|
|
471
|
-
}
|
|
472
|
-
function boldRgb(hex, text) {
|
|
473
|
-
terminal.bold.colorRgbHex(hex, text);
|
|
474
|
-
}
|
|
475
|
-
//#endregion
|
|
476
|
-
//#region src/lib/cli.ts
|
|
495
|
+
// src/lib/cli.ts
|
|
477
496
|
const argv = cli({
|
|
478
497
|
name: "ub-debugger",
|
|
479
498
|
flags: { port: {
|
|
480
499
|
type: Number,
|
|
481
500
|
description: "The port number to host the debugger on.",
|
|
482
|
-
default:
|
|
501
|
+
default: DEFAULT_BRIDGE_PORT
|
|
483
502
|
} }
|
|
484
503
|
});
|
|
485
|
-
|
|
486
|
-
//#region src/lib/ws.ts
|
|
504
|
+
// src/lib/ws.ts
|
|
487
505
|
const state = { isInitialized: false };
|
|
488
506
|
const MESSAGE_LEVELS = {
|
|
489
507
|
1: terminal.gray,
|
|
@@ -505,7 +523,24 @@ const SYSTEM_COLORS = {
|
|
|
505
523
|
* @param text The line to print (the glyph is prepended and a trailing newline added).
|
|
506
524
|
*/
|
|
507
525
|
function system(color, text) {
|
|
508
|
-
terminal.bold.colorRgbHex(SYSTEM_COLORS[color], `${SYSTEM_GLYPH} ${text}\n`);
|
|
526
|
+
terminal.bold.colorRgbHex(SYSTEM_COLORS[color], `${timestamp()} ${SYSTEM_GLYPH} ${text}\n`);
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* @description Formats the current local time for the start of a bridge log line.
|
|
530
|
+
* @param now The moment to format.
|
|
531
|
+
* @returns The time as `HH:MM:SS.mmm`.
|
|
532
|
+
*/
|
|
533
|
+
function timestamp(now = /* @__PURE__ */ new Date()) {
|
|
534
|
+
const pad = (value, width = 2) => String(value).padStart(width, "0");
|
|
535
|
+
return `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}.${pad(now.getMilliseconds(), 3)}`;
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* @description Describes a device from its hello for the bridge log.
|
|
539
|
+
* @param device What the device reported.
|
|
540
|
+
* @returns A one-line summary such as `ios, Discord 351.0, loader 1.0.0, client 0.9.0`.
|
|
541
|
+
*/
|
|
542
|
+
function describeDevice(device) {
|
|
543
|
+
return `${device.platform}, Discord ${device.discordVersion}, loader ${device.loaderVersion}, client ${device.clientVersion}`;
|
|
509
544
|
}
|
|
510
545
|
/**
|
|
511
546
|
* @description Boots the bridge: the phone-facing WebSocket server, the shared session routing, and
|
|
@@ -518,11 +553,10 @@ function setupWebSocket() {
|
|
|
518
553
|
Bun.serve({
|
|
519
554
|
port: argv.flags.port,
|
|
520
555
|
fetch(request, server) {
|
|
521
|
-
if (new URL(request.url).searchParams.has(
|
|
556
|
+
if (new URL(request.url).searchParams.has(CONTROLLER_ENDPOINT_MARKER)) {
|
|
522
557
|
server.upgrade(request, { data: { role: "controller" } });
|
|
523
558
|
return;
|
|
524
559
|
}
|
|
525
|
-
if (state$2.device) return new Response(JSON.stringify({ error: "A device is already connected." }), { status: 503 });
|
|
526
560
|
server.upgrade(request, { data: { role: "device" } });
|
|
527
561
|
},
|
|
528
562
|
websocket: {
|
|
@@ -543,7 +577,7 @@ function setupWebSocket() {
|
|
|
543
577
|
handleControllerMessage(ws, message);
|
|
544
578
|
return;
|
|
545
579
|
}
|
|
546
|
-
handleDeviceMessage(message);
|
|
580
|
+
if (ws === state$2.device) handleDeviceMessage(message);
|
|
547
581
|
},
|
|
548
582
|
close(ws) {
|
|
549
583
|
if (ws.data.role === "controller") {
|
|
@@ -561,18 +595,24 @@ function setupWebSocket() {
|
|
|
561
595
|
});
|
|
562
596
|
onLog((log) => {
|
|
563
597
|
abortCurrentReplInput({ deletePrompt: true });
|
|
564
|
-
MESSAGE_LEVELS[log.level](
|
|
598
|
+
MESSAGE_LEVELS[log.level](`${timestamp()} « ${formatLog(stripEscapeSequences(log.message))}\n`);
|
|
565
599
|
takeReplInput();
|
|
566
600
|
});
|
|
567
601
|
onControllerEval((code) => {
|
|
568
602
|
abortCurrentReplInput({ deletePrompt: true });
|
|
569
|
-
terminal.magenta(
|
|
603
|
+
terminal.magenta(`${timestamp()} » [mcp] ${code}\n`);
|
|
570
604
|
takeReplInput();
|
|
571
605
|
});
|
|
572
606
|
onControllerResult((result) => {
|
|
573
607
|
abortCurrentReplInput({ deletePrompt: true });
|
|
574
|
-
if (result.ok) terminal.gray(
|
|
575
|
-
else terminal.red(
|
|
608
|
+
if (result.ok) terminal.gray(`${timestamp()} « ${result.value}\n`);
|
|
609
|
+
else terminal.red(`${timestamp()} « ${result.error}\n`);
|
|
610
|
+
takeReplInput();
|
|
611
|
+
});
|
|
612
|
+
onDevice((connected, device) => {
|
|
613
|
+
if (!connected || !device) return;
|
|
614
|
+
abortCurrentReplInput({ deletePrompt: true });
|
|
615
|
+
system("green", `Device identified: ${describeDevice(device)}`);
|
|
576
616
|
takeReplInput();
|
|
577
617
|
});
|
|
578
618
|
onController((connected, count) => {
|
|
@@ -581,12 +621,12 @@ function setupWebSocket() {
|
|
|
581
621
|
system("pink", connected ? `MCP connected - ${count} ${plural} attached` : `MCP disconnected - ${count} ${plural} attached`);
|
|
582
622
|
takeReplInput();
|
|
583
623
|
});
|
|
584
|
-
printBanner(`${getLocalAddress()}:${argv.flags.port}`, `ws://127.0.0.1:${argv.flags.port}
|
|
624
|
+
printBanner(`${getLocalAddress()}:${argv.flags.port}`, `ws://127.0.0.1:${argv.flags.port}?${CONTROLLER_ENDPOINT_MARKER}`);
|
|
585
625
|
}
|
|
586
626
|
function handleDeviceMessage(raw) {
|
|
587
627
|
const message = parseMessage(raw);
|
|
588
628
|
if (!message) {
|
|
589
|
-
system("red",
|
|
629
|
+
system("red", `Parsing failed on message from device: ${JSON.stringify(raw.slice(0, 200))}`);
|
|
590
630
|
return;
|
|
591
631
|
}
|
|
592
632
|
handleDeviceMessage$1(message);
|
|
@@ -594,7 +634,7 @@ function handleDeviceMessage(raw) {
|
|
|
594
634
|
function handleControllerMessage(ws, raw) {
|
|
595
635
|
const message = parseMessage(raw);
|
|
596
636
|
if (message?.type === "eval") {
|
|
597
|
-
evaluateForController(ws, message
|
|
637
|
+
evaluateForController(ws, message);
|
|
598
638
|
return;
|
|
599
639
|
}
|
|
600
640
|
if (message?.type === "plugin-push") pushPluginForController(ws, message);
|
|
@@ -610,9 +650,7 @@ function getLocalAddress() {
|
|
|
610
650
|
for (const iface of ifaces) if (iface.family === "IPv4" && !iface.internal) return iface.address;
|
|
611
651
|
}
|
|
612
652
|
}
|
|
613
|
-
|
|
614
|
-
//#region src/index.ts
|
|
653
|
+
// src/index.ts
|
|
615
654
|
await loadHistory();
|
|
616
655
|
setupWebSocket();
|
|
617
|
-
//#endregion
|
|
618
656
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unbound-app/debugger",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "A REPL debugger for @unbound-app/client runtime instances.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mario P.",
|
|
@@ -21,14 +21,15 @@
|
|
|
21
21
|
"type": "module",
|
|
22
22
|
"module": "./dist/index.mjs",
|
|
23
23
|
"scripts": {
|
|
24
|
-
"build": "tsdown"
|
|
24
|
+
"build": "tsdown",
|
|
25
|
+
"typecheck": "tsc --noEmit -p ."
|
|
25
26
|
},
|
|
26
27
|
"dependencies": {
|
|
27
|
-
"@unbound-app/debugger-protocol": "0.
|
|
28
|
-
"cleye": "^
|
|
29
|
-
"terminal-kit": "^3.1.
|
|
28
|
+
"@unbound-app/debugger-protocol": "0.11.0",
|
|
29
|
+
"cleye": "^2.7.0",
|
|
30
|
+
"terminal-kit": "^3.1.4"
|
|
30
31
|
},
|
|
31
32
|
"peerDependencies": {
|
|
32
|
-
"typescript": "^
|
|
33
|
+
"typescript": "^7.0.2"
|
|
33
34
|
}
|
|
34
35
|
}
|