jsmdcui 0.8.0 → 0.9.0
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/CHANGELOG.md +66 -0
- package/README.md +77 -1
- package/cdp-maze.js +141 -0
- package/demos/maze.md +6 -1
- package/llm-maze.txt +94 -0
- package/package.json +1 -1
- package/runtime/help/cdp.md +5 -0
- package/runtime/help/help.md +77 -1
- package/runtime/jsplugins/cdp/cdp-server.js +26 -2
- package/runtime/jsplugins/cdp/cdp.js +55 -49
- package/runtime/jsplugins/chapter/chapter.js +2 -1
- package/runtime/jsplugins/example/example.js +2 -0
- package/single-exe/README.md +223 -45
- package/single-exe/compiled.js +6 -3
- package/single-exe/entry.mjs +4 -3
- package/single-exe/packAssets.sh +1 -1
- package/src/cui/kitty-debug.mjs +1 -1
- package/src/index.js +46 -10
- package/src/lua/engine.js +1 -4
- package/src/plugins/js-bridge.js +43 -0
- package/tests/compiled-runtime.test.js +8 -0
- package/tests/demo.test.js +40 -0
- package/tests/kitty-demo.md +1 -1
- package/demo.resized.jpg +0 -0
- package/src/runtime/compiled.js +0 -25
package/src/plugins/js-bridge.js
CHANGED
|
@@ -4,6 +4,7 @@ import { dirname, join, basename, extname } from "node:path";
|
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { assetPath, hasInternalAssets, listInternalAssetDirs, listInternalAssetPaths, readInternalAssetBytes } from "../runtime/assets.js";
|
|
7
|
+
import { isMdcuiEncoding } from "../runtime/encodings.js";
|
|
7
8
|
import { newMessage, newMessageAtLine, MTError, MTWarning, MTInfo } from "../buffer/message.js";
|
|
8
9
|
import { Loc } from "../buffer/loc.js";
|
|
9
10
|
|
|
@@ -1405,6 +1406,48 @@ export function buildMicroGlobal(jsManager) {
|
|
|
1405
1406
|
return app?.buffer?.lines.join("\n") ?? "";
|
|
1406
1407
|
},
|
|
1407
1408
|
|
|
1409
|
+
// Returns the rendered ANSI document when available, otherwise plain text.
|
|
1410
|
+
getAllAnsiText() {
|
|
1411
|
+
const buffer = getApp()?.buffer;
|
|
1412
|
+
return typeof buffer?._mdcuiAnsiText === "string"
|
|
1413
|
+
? buffer._mdcuiAnsiText
|
|
1414
|
+
: buffer?.lines.join("\n") ?? "";
|
|
1415
|
+
},
|
|
1416
|
+
|
|
1417
|
+
// Activates a 1-based rendered-buffer cell in MDCUI; otherwise falls back to goto.
|
|
1418
|
+
async clickBufferCell(column = 1, line = 1) {
|
|
1419
|
+
const app = getApp();
|
|
1420
|
+
const buffer = app?.buffer;
|
|
1421
|
+
if (!app || !buffer) return false;
|
|
1422
|
+
|
|
1423
|
+
const targetLine = Math.max(1, Math.trunc(Number(line)) || 1);
|
|
1424
|
+
const targetColumn = Math.max(1, Math.trunc(Number(column)) || 1);
|
|
1425
|
+
if (!isMdcuiEncoding(buffer.encoding ?? buffer.Settings?.encoding)) {
|
|
1426
|
+
await app.handleCommand(`goto ${targetLine}:${targetColumn}`);
|
|
1427
|
+
app.render?.();
|
|
1428
|
+
return true;
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
const y = Math.min(targetLine - 1, Math.max(0, buffer.lines.length - 1));
|
|
1432
|
+
const x = Math.min(targetColumn - 1, String(buffer.lines[y] ?? "").length);
|
|
1433
|
+
buffer.cursor = { x, y };
|
|
1434
|
+
const handled = await app.handleMdcuiCellCallback(buffer, y, x, "mouse");
|
|
1435
|
+
app.render?.();
|
|
1436
|
+
return handled;
|
|
1437
|
+
},
|
|
1438
|
+
|
|
1439
|
+
// Sends terminal input through the App's normal parser and event pipeline.
|
|
1440
|
+
async _dispatchRawInput(raw) {
|
|
1441
|
+
const app = getApp();
|
|
1442
|
+
if (!app) return false;
|
|
1443
|
+
const bytes = typeof raw === "string"
|
|
1444
|
+
? new TextEncoder().encode(raw)
|
|
1445
|
+
: raw;
|
|
1446
|
+
await app._dispatchInput(bytes);
|
|
1447
|
+
app.render?.();
|
|
1448
|
+
return true;
|
|
1449
|
+
},
|
|
1450
|
+
|
|
1408
1451
|
// Replaces the entire buffer content with text (may contain newlines).
|
|
1409
1452
|
putAllText(text) {
|
|
1410
1453
|
const app = getApp();
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import { isCompiledBinary as isSingleExeCompiled } from "../single-exe/compiled.js";
|
|
3
|
+
|
|
4
|
+
test("single-exe recognizes Bun compiled virtual paths", () => {
|
|
5
|
+
expect(isSingleExeCompiled(["bun", "/$bunfs/root/app.js"])).toBe(true);
|
|
6
|
+
expect(isSingleExeCompiled(["bun", "B:/~BUN/root/app.js"])).toBe(true);
|
|
7
|
+
expect(isSingleExeCompiled(["bun", "/project/src/index.js"])).toBe(false);
|
|
8
|
+
});
|
package/tests/demo.test.js
CHANGED
|
@@ -21,6 +21,7 @@ test("--help describes the non-overwriting demo behavior", () => {
|
|
|
21
21
|
expect(output.match(/Open it in the TUI and write 5 generated files beside it/g)?.length).toBe(2);
|
|
22
22
|
expect(output).toContain("--demo-imgtool");
|
|
23
23
|
expect(output).toContain("--demo-imgtool-zh");
|
|
24
|
+
expect(output).toContain("--cdp-maze");
|
|
24
25
|
});
|
|
25
26
|
|
|
26
27
|
test("--demo-list lists root and automatically discovered demos", () => {
|
|
@@ -38,6 +39,27 @@ test("--demo-list lists root and automatically discovered demos", () => {
|
|
|
38
39
|
expect(output).toContain("--demo-imgtool --demo-image-processor");
|
|
39
40
|
});
|
|
40
41
|
|
|
42
|
+
test("--export-cdp-maze writes and overwrites the bundled solver", async () => {
|
|
43
|
+
const dir = await mkdtemp(join(tmpdir(), "jsmdcui-export-cdp-maze-"));
|
|
44
|
+
const outputPath = join(dir, "cdp-maze.js");
|
|
45
|
+
try {
|
|
46
|
+
await writeFile(outputPath, "old solver\n");
|
|
47
|
+
const result = Bun.spawnSync([bunBin, tui, "--export-cdp-maze"], {
|
|
48
|
+
cwd: dir,
|
|
49
|
+
stdout: "pipe",
|
|
50
|
+
stderr: "pipe",
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
expect(result.exitCode).toBe(0);
|
|
54
|
+
expect(result.stdout.toString()).toContain(`Wrote ${outputPath}`);
|
|
55
|
+
const exported = await readFile(outputPath, "utf8");
|
|
56
|
+
expect(exported).toContain("export async function runCdpMaze");
|
|
57
|
+
expect(exported).not.toContain("old solver");
|
|
58
|
+
} finally {
|
|
59
|
+
await rm(dir, { recursive: true, force: true });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
41
63
|
test("--demo writes bundled testapp.md to cwd before opening it", async () => {
|
|
42
64
|
const dir = await mkdtemp(join(tmpdir(), "jsmdcui-demo-"));
|
|
43
65
|
try {
|
|
@@ -94,6 +116,24 @@ test("--demo-<filename> automatically loads a matching demos file", async () =>
|
|
|
94
116
|
}
|
|
95
117
|
});
|
|
96
118
|
|
|
119
|
+
test("--cdp-maze loads the maze demo", async () => {
|
|
120
|
+
const dir = await mkdtemp(join(tmpdir(), "jsmdcui-cdp-maze-"));
|
|
121
|
+
try {
|
|
122
|
+
const result = Bun.spawnSync([bunBin, tui, "--cdp-maze", "-cat", "-encoding", "utf8"], {
|
|
123
|
+
cwd: dir,
|
|
124
|
+
stdout: "pipe",
|
|
125
|
+
stderr: "pipe",
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
expect(result.exitCode).toBe(0);
|
|
129
|
+
const written = await readFile(join(dir, "maze.md"), "utf8");
|
|
130
|
+
expect(written).toContain("Put the cursor here");
|
|
131
|
+
expect(Bun.stripANSI(result.stdout.toString())).toContain("Put the cursor here");
|
|
132
|
+
} finally {
|
|
133
|
+
await rm(dir, { recursive: true, force: true });
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
97
137
|
test("--demo-<filename> preserves an existing local copy", async () => {
|
|
98
138
|
const dir = await mkdtemp(join(tmpdir(), "jsmdcui-demo-generic-existing-"));
|
|
99
139
|
const existing = "# Keep my selector demo\n";
|
package/tests/kitty-demo.md
CHANGED
package/demo.resized.jpg
DELETED
|
Binary file
|
package/src/runtime/compiled.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { basename, dirname, resolve } from "node:path";
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
|
|
5
|
-
export function isCompiledBinary(argv = process.argv) {
|
|
6
|
-
return Boolean(argv?.[1]?.startsWith?.("/$bunfs/"));
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function resolveCompiledBaseDir({ argv = process.argv, execPath = process.execPath } = {}) {
|
|
10
|
-
const bn = basename(execPath);
|
|
11
|
-
if (bn.startsWith("ld") ||
|
|
12
|
-
bn.startsWith("libld") ||
|
|
13
|
-
bn.startsWith("linker") ) {
|
|
14
|
-
const realArgv = readFileSync("/proc/self/cmdline", "utf8").match(/[^\0]+/g);
|
|
15
|
-
return dirname(realArgv?.[1] ?? execPath);
|
|
16
|
-
}
|
|
17
|
-
return dirname(execPath) || process.cwd();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function resolveRepoRoot(importMetaUrl, options = {}) {
|
|
21
|
-
if (isCompiledBinary(options.argv)) {
|
|
22
|
-
return resolveCompiledBaseDir(options);
|
|
23
|
-
}
|
|
24
|
-
return resolve(dirname(fileURLToPath(importMetaUrl)), "..");
|
|
25
|
-
}
|