dsh-vscode-workbench 0.2.3 → 0.2.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/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createRequire } from "node:module";
2
- import { chmodSync, constants, createReadStream, realpathSync, statSync } from "node:fs";
2
+ import { constants, createReadStream } from "node:fs";
3
3
  import { access, lstat, mkdir, open, readFile, readdir, realpath, rename, rm, stat } from "node:fs/promises";
4
4
  import { basename, delimiter, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
5
5
  import { execFile, spawn } from "node:child_process";
@@ -9,7 +9,6 @@ import { createHash, randomUUID } from "node:crypto";
9
9
  import { homedir, tmpdir } from "node:os";
10
10
  import { pathToFileURL } from "node:url";
11
11
  import { promisify } from "node:util";
12
- import * as pty from "node-pty";
13
12
  //#region src/commit-message.ts
14
13
  const DEFAULT_COMMIT_PREFERENCES = {
15
14
  detail: "standard",
@@ -284,7 +283,7 @@ function authorize(req, res, connection) {
284
283
  }
285
284
  //#endregion
286
285
  //#region src/host.ts
287
- const require$1 = createRequire(import.meta.url);
286
+ const require = createRequire(import.meta.url);
288
287
  const TEXT_LIMIT = 5242880;
289
288
  const PROCESS_TIMEOUT = 3e4;
290
289
  function cwdFor(ctx, sessionId) {
@@ -577,7 +576,7 @@ async function workspaceDownloadFile(cwd, path) {
577
576
  /** Resolve the PDF.js worker shipped with this plugin's runtime dependency. */
578
577
  function pdfWorkerAsset() {
579
578
  return {
580
- path: require$1.resolve("pdfjs-dist/legacy/build/pdf.worker.min.mjs"),
579
+ path: require.resolve("pdfjs-dist/legacy/build/pdf.worker.min.mjs"),
581
580
  type: "text/javascript; charset=utf-8"
582
581
  };
583
582
  }
@@ -638,7 +637,7 @@ async function searchWorkspace(cwd, request, signal) {
638
637
  limited: false
639
638
  };
640
639
  const root = await canonicalRoot(cwd);
641
- const rg = require$1("@vscode/ripgrep").rgPath;
640
+ const rg = require("@vscode/ripgrep").rgPath;
642
641
  const args = [
643
642
  "--json",
644
643
  "--line-number",
@@ -1138,7 +1137,7 @@ async function gitAction(cwd, action, path, value) {
1138
1137
  }
1139
1138
  /** Resolve the official VS Code Codicon font shipped by @vscode/codicons. */
1140
1139
  function codiconAsset() {
1141
- const packageRoot = dirname(require$1.resolve("@vscode/codicons/package.json"));
1140
+ const packageRoot = dirname(require.resolve("@vscode/codicons/package.json"));
1142
1141
  return {
1143
1142
  path: resolve(packageRoot, "dist", "codicon.ttf"),
1144
1143
  type: "font/ttf"
@@ -1146,14 +1145,14 @@ function codiconAsset() {
1146
1145
  }
1147
1146
  /** Browser build of SheetJS served as an asset so the client bundle stays free of Node builtins. */
1148
1147
  function xlsxAsset() {
1149
- const packageRoot = dirname(require$1.resolve("xlsx/package.json"));
1148
+ const packageRoot = dirname(require.resolve("xlsx/package.json"));
1150
1149
  return {
1151
1150
  path: resolve(packageRoot, "dist", "xlsx.full.min.js"),
1152
1151
  type: "text/javascript; charset=utf-8"
1153
1152
  };
1154
1153
  }
1155
1154
  function monacoAsset(raw) {
1156
- const packageRoot = dirname(require$1.resolve("monaco-editor/package.json"));
1155
+ const packageRoot = dirname(require.resolve("monaco-editor/package.json"));
1157
1156
  const path = resolve(packageRoot, "min", raw);
1158
1157
  if (!inside(resolve(packageRoot, "min"), path)) throw new WorkbenchError("asset-invalid", "invalid Monaco asset path", 403);
1159
1158
  return {
@@ -1164,7 +1163,7 @@ function monacoAsset(raw) {
1164
1163
  /** Resolve a vscode-icons SVG shipped by @vscode-icons/vscode-icons-api. */
1165
1164
  function fileIconAsset(raw) {
1166
1165
  if (!/^[a-z0-9_-]+\.svg$/i.test(raw)) throw new WorkbenchError("asset-invalid", "invalid file icon path", 403);
1167
- const packageRoot = dirname(require$1.resolve("@vscode-icons/vscode-icons-api/package.json"));
1166
+ const packageRoot = dirname(require.resolve("@vscode-icons/vscode-icons-api/package.json"));
1168
1167
  return {
1169
1168
  path: resolve(packageRoot, "icons", raw),
1170
1169
  type: "image/svg+xml"
@@ -1400,7 +1399,12 @@ async function exists$1(path) {
1400
1399
  */
1401
1400
  function lspSearchDirs(env = process.env, home = homedir()) {
1402
1401
  const fromPath = (env.PATH ?? env.Path ?? "").split(delimiter).filter(Boolean);
1403
- const extras = [
1402
+ const extras = process.platform === "win32" ? [
1403
+ join(home, "go", "bin"),
1404
+ join(home, ".cargo", "bin"),
1405
+ join(home, ".dotnet", "tools"),
1406
+ join(home, "bin")
1407
+ ] : [
1404
1408
  join(home, "go", "bin"),
1405
1409
  join(home, ".cargo", "bin"),
1406
1410
  join(home, ".dotnet", "tools"),
@@ -1420,7 +1424,7 @@ async function executableIn(directory, command) {
1420
1424
  `${command}.exe`,
1421
1425
  `${command}.cmd`,
1422
1426
  `${command}.bat`,
1423
- command
1427
+ `${command}.com`
1424
1428
  ] : [command];
1425
1429
  for (const name of names) {
1426
1430
  const file = join(directory, name);
@@ -1689,243 +1693,6 @@ async function officePdf(cwd, path) {
1689
1693
  }
1690
1694
  }
1691
1695
  //#endregion
1692
- //#region src/terminal.ts
1693
- const require = createRequire(import.meta.url);
1694
- const SENSITIVE = /(api[_-]?key|token|credential|secret|password|passwd|private[_-]?key|^dsh_.*(?:key|token|secret))/i;
1695
- const MAX_TERMINALS = 8;
1696
- const REPLAY_BYTES = 2097152;
1697
- /** Remove credentials while retaining ordinary interactive-shell variables. */
1698
- function sanitizedTerminalEnv(env) {
1699
- return Object.fromEntries(Object.entries(env).filter(([key, value]) => value !== void 0 && !SENSITIVE.test(key)));
1700
- }
1701
- /** Select the user's interactive shell with platform-specific fallbacks. */
1702
- function defaultTerminalShell(platform = process.platform, env = process.env) {
1703
- if (platform === "win32") return {
1704
- shell: env.COMSPEC?.toLowerCase().includes("powershell") ? env.COMSPEC : "powershell.exe",
1705
- args: ["-NoLogo"]
1706
- };
1707
- return {
1708
- shell: env.SHELL || (platform === "darwin" ? "/bin/zsh" : "/bin/bash"),
1709
- args: ["-l"]
1710
- };
1711
- }
1712
- /** Add execute bits when a registry package extracted a native helper without them. */
1713
- function ensureExecutable(path) {
1714
- if (process.platform === "win32") return true;
1715
- try {
1716
- const mode = statSync(path).mode;
1717
- if ((mode & 73) === 0) chmodSync(path, mode | 73);
1718
- return true;
1719
- } catch {
1720
- return false;
1721
- }
1722
- }
1723
- /** Repair node-pty's macOS/Linux helper, whose npm package currently loses its execute bit. */
1724
- function repairNodePtyHelper() {
1725
- if (process.platform === "win32") return;
1726
- const packageDirectory = dirname(require.resolve("node-pty/package.json"));
1727
- ensureExecutable(join(packageDirectory, "build", "Release", "spawn-helper"));
1728
- ensureExecutable(join(packageDirectory, "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper"));
1729
- }
1730
- /** Own interactive terminals by their canonical workspace directory. */
1731
- var TerminalManager = class {
1732
- workspaces = /* @__PURE__ */ new Map();
1733
- constructor() {
1734
- repairNodePtyHelper();
1735
- }
1736
- workspace(cwd) {
1737
- return realpathSync(cwd);
1738
- }
1739
- list(cwd) {
1740
- return [...this.workspaces.get(this.workspace(cwd))?.values() ?? []].map((handle) => ({ ...handle.info }));
1741
- }
1742
- create(cwd, title) {
1743
- const key = this.workspace(cwd);
1744
- const terminals = this.workspaces.get(key) ?? /* @__PURE__ */ new Map();
1745
- this.workspaces.set(key, terminals);
1746
- if (terminals.size >= MAX_TERMINALS) throw new Error(`terminal limit reached (${MAX_TERMINALS})`);
1747
- const { shell, args } = defaultTerminalShell();
1748
- const child = pty.spawn(shell, args, {
1749
- name: "xterm-256color",
1750
- cols: 80,
1751
- rows: 24,
1752
- cwd: key,
1753
- env: sanitizedTerminalEnv(process.env)
1754
- });
1755
- const info = {
1756
- id: randomUUID(),
1757
- title: title || basename(shell),
1758
- cwd: key,
1759
- running: true,
1760
- sequence: 0
1761
- };
1762
- const handle = {
1763
- info,
1764
- process: child,
1765
- replay: "",
1766
- listeners: /* @__PURE__ */ new Set()
1767
- };
1768
- terminals.set(info.id, handle);
1769
- child.onData((data) => {
1770
- info.sequence++;
1771
- handle.replay += data;
1772
- if (Buffer.byteLength(handle.replay) > REPLAY_BYTES) handle.replay = handle.replay.slice(-2097152);
1773
- for (const listener of handle.listeners) listener({
1774
- sequence: info.sequence,
1775
- data
1776
- });
1777
- });
1778
- child.onExit(({ exitCode }) => {
1779
- info.running = false;
1780
- info.exitCode = exitCode;
1781
- info.sequence++;
1782
- const data = `\r\n[process exited with code ${exitCode}]\r\n`;
1783
- for (const listener of handle.listeners) listener({
1784
- sequence: info.sequence,
1785
- data
1786
- });
1787
- });
1788
- return { ...info };
1789
- }
1790
- get(cwd, id) {
1791
- return this.workspaces.get(this.workspace(cwd))?.get(id);
1792
- }
1793
- close(cwd, id) {
1794
- const key = this.workspace(cwd);
1795
- const terminals = this.workspaces.get(key);
1796
- const handle = terminals?.get(id);
1797
- if (handle === void 0 || terminals === void 0) return;
1798
- terminals.delete(id);
1799
- try {
1800
- handle.process.kill();
1801
- } catch {}
1802
- if (terminals.size === 0) this.workspaces.delete(key);
1803
- }
1804
- rename(cwd, id, title) {
1805
- const handle = this.get(cwd, id);
1806
- if (handle === void 0) throw new Error("terminal not found");
1807
- handle.info.title = title;
1808
- return { ...handle.info };
1809
- }
1810
- dispose() {
1811
- for (const [cwd, terminals] of this.workspaces) for (const id of terminals.keys()) this.close(cwd, id);
1812
- }
1813
- };
1814
- function terminalRequestAllowed(req) {
1815
- const host = req.headers.host;
1816
- if (host === void 0 || req.headers["sec-fetch-site"] === "cross-site") return false;
1817
- let hostname;
1818
- try {
1819
- hostname = new URL(`http://${host}`).hostname;
1820
- } catch {
1821
- return false;
1822
- }
1823
- if (hostname !== "localhost" && hostname !== "[::1]" && !hostname.startsWith("127.")) return false;
1824
- const origin = req.headers.origin;
1825
- try {
1826
- return origin === void 0 || new URL(origin).host === host;
1827
- } catch {
1828
- return false;
1829
- }
1830
- }
1831
- /** Register the private local terminal API and WebSocket transport. */
1832
- function installTerminal(ctx) {
1833
- const manager = new TerminalManager();
1834
- ctx.effect(() => ctx.webServer.register({
1835
- kind: "prefix",
1836
- path: "/dsh-vscode-terminal/api",
1837
- handler: async (req, res) => {
1838
- if (!authorize(req, res, ctx.connection)) return;
1839
- if (!terminalRequestAllowed(req)) return send(res, 403, {
1840
- ok: false,
1841
- error: { message: "forbidden" }
1842
- });
1843
- if (req.method !== "POST") return send(res, 405, {
1844
- ok: false,
1845
- error: { message: "POST required" }
1846
- });
1847
- try {
1848
- const body = await readBody(req);
1849
- const sessionId = typeof body.sessionId === "string" ? body.sessionId : "";
1850
- if (sessionId === "") throw new Error("sessionId required");
1851
- const cwd = cwdFor(ctx, sessionId);
1852
- const method = new URL(req.url ?? "/", "http://dsh.local").pathname.slice(25);
1853
- let value;
1854
- if (method === "list") value = manager.list(cwd);
1855
- else if (method === "create") value = manager.create(cwd, typeof body.title === "string" ? body.title : void 0);
1856
- else if (method === "close") {
1857
- manager.close(cwd, typeof body.id === "string" ? body.id : "");
1858
- value = manager.list(cwd);
1859
- } else if (method === "rename") value = manager.rename(cwd, typeof body.id === "string" ? body.id : "", typeof body.title === "string" ? body.title : "");
1860
- else throw new Error("unknown terminal method");
1861
- send(res, 200, {
1862
- ok: true,
1863
- value
1864
- });
1865
- } catch (error) {
1866
- sendError(res, error);
1867
- }
1868
- }
1869
- }), "dsh-vscode-workbench: terminal API");
1870
- const webSocket = new WebSocketServer({ noServer: true });
1871
- ctx.effect(() => ctx.webServer.registerUpgrade({
1872
- path: "/dsh-vscode-terminal/ws",
1873
- handler(req, socket, head) {
1874
- if (ctx.connection.requestRejection(req) !== void 0 || !terminalRequestAllowed(req)) {
1875
- socket.destroy();
1876
- return;
1877
- }
1878
- webSocket.handleUpgrade(req, socket, head, (connection) => {
1879
- const url = new URL(req.url ?? "/", "http://dsh.local");
1880
- const sessionId = url.searchParams.get("sessionId");
1881
- const id = url.searchParams.get("id");
1882
- if (sessionId === null || id === null) {
1883
- connection.close(1008, "sessionId and id required");
1884
- return;
1885
- }
1886
- let handle;
1887
- try {
1888
- handle = manager.get(cwdFor(ctx, sessionId), id);
1889
- } catch {
1890
- connection.close(1008, "session workspace unavailable");
1891
- return;
1892
- }
1893
- if (handle === void 0) {
1894
- connection.close(1008, "terminal not found");
1895
- return;
1896
- }
1897
- if (handle.replay !== "") connection.send(JSON.stringify({
1898
- type: "replay",
1899
- sequence: handle.info.sequence,
1900
- data: handle.replay
1901
- }));
1902
- const listener = (output) => {
1903
- if (connection.readyState === WebSocket.OPEN) connection.send(JSON.stringify({
1904
- type: "output",
1905
- ...output
1906
- }));
1907
- };
1908
- handle.listeners.add(listener);
1909
- connection.on("message", (raw) => {
1910
- const text = raw.toString();
1911
- try {
1912
- const message = JSON.parse(text);
1913
- if (message !== null && typeof message === "object" && "type" in message && message.type === "input" && "data" in message && typeof message.data === "string") handle.process.write(message.data);
1914
- else if (message !== null && typeof message === "object" && "type" in message && message.type === "resize" && "cols" in message && "rows" in message && typeof message.cols === "number" && typeof message.rows === "number") handle.process.resize(Math.max(2, Math.floor(message.cols)), Math.max(2, Math.floor(message.rows)));
1915
- } catch {
1916
- handle.process.write(text);
1917
- }
1918
- });
1919
- connection.on("close", () => handle.listeners.delete(listener));
1920
- });
1921
- }
1922
- }), "dsh-vscode-workbench: terminal WebSocket");
1923
- ctx.effect(() => () => {
1924
- webSocket.close();
1925
- manager.dispose();
1926
- }, "dsh-vscode-workbench: terminal teardown");
1927
- }
1928
- //#endregion
1929
1696
  //#region src/watch-ignore.ts
1930
1697
  /** Exclusion rules for the recursive workspace file watcher. */
1931
1698
  /** Directory names skipped by default; large dependency and build trees exhaust inotify watches. */
@@ -2082,7 +1849,6 @@ function apply(ctx) {
2082
1849
  fiber.dispose?.();
2083
1850
  };
2084
1851
  }, "dsh-vscode-workbench: optional DSH services");
2085
- installTerminal(ctx);
2086
1852
  ctx.effect(() => ctx.webServer.register({
2087
1853
  kind: "exact",
2088
1854
  path: "/dsh-vscode/codicons/codicon.ttf",