seemore 1.12.17 → 1.12.20

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 CHANGED
@@ -2,11 +2,14 @@
2
2
 
3
3
  <p align="center">
4
4
  <img src="https://raw.githubusercontent.com/arifszn/seemore/main/assets/logo.png" alt="seemore" width="280">
5
- <h4 align="center">Let AI write the Markdown. Let seemore show it better — zero config documentation framework.</h4>
5
+ <h4 align="center">Zero config documentation tool - Let AI write the Markdown. Let seemore show it better.</h4>
6
6
  <p align="center">
7
7
  <a href="https://www.npmjs.com/package/seemore">
8
8
  <img src="https://img.shields.io/npm/v/seemore"/>
9
9
  </a>
10
+ <a href="https://arifszn.github.io/seemore/download">
11
+ <img src="https://img.shields.io/badge/Desktop-macOS%20%C2%B7%20Windows%20%C2%B7%20Linux-111111"/>
12
+ </a>
10
13
  <a href="https://open-vsx.org/extension/arifszn/seemore-vscode">
11
14
  <img src="https://img.shields.io/badge/Open_VSX-Registry-C160EF?logo=eclipseide&logoColor=white"/>
12
15
  </a>
@@ -34,16 +37,22 @@
34
37
 
35
38
  AI tools write Markdown fast. They write specs, notes, guides, READMEs, and whole folders of files. No person can read that much Markdown at that speed.
36
39
 
37
- A folder of `.md` files has no order. You cannot click a link between files. You cannot search across them.
38
-
39
40
  **seemore** points at that folder and renders it as a real site. Other docs frameworks need a project first: a scaffold, a config file, a `docs/` layout, and a build step in your repo. seemore needs only a folder that already exists. It does not move your files, and it does not need any code. If you stop using seemore, your files stay where they are.
40
41
 
41
42
  <p align="center">
42
- <img src="https://raw.githubusercontent.com/arifszn/seemore/main/packages/site/assets/home.png" alt="The seemore site: a terminal typing npx seemore to serve a folder of notes at localhost:4040, with an arrow pointing to the browser preview" width="640"/>
43
+ <video src="https://github.com/user-attachments/assets/10f105c9-924e-4a89-bcba-4d46eefe928d" width="640" controls muted></video>
43
44
  </p>
44
45
 
45
46
  ## Quick start
46
47
 
48
+ You can use seemore in two ways.
49
+
50
+ ### Desktop app
51
+
52
+ Download the app for macOS, Windows or Linux from the [download page](https://arifszn.github.io/seemore/download). Open a folder or a `.md` file, and it opens as a site.
53
+
54
+ ### Command line
55
+
47
56
  seemore needs [Node.js](https://nodejs.org) 20 or newer.
48
57
 
49
58
  ```bash
@@ -59,7 +68,7 @@ The [seemore website](https://arifszn.github.io/seemore) is a folder of Markdown
59
68
  <summary><strong>Or ask an AI agent to set it up</strong></summary>
60
69
  <br/>
61
70
 
62
- If you do not want to use a terminal, use the [agent skill](https://github.com/arifszn/seemore-skill) instead. It does the setup for you.
71
+ If you work with an AI agent, the [agent skill](https://github.com/arifszn/seemore-skill) does the setup for you.
63
72
 
64
73
  ### Claude Code (Plugin Marketplace)
65
74
 
@@ -98,10 +107,6 @@ Or call the skill by name:
98
107
 
99
108
  </details>
100
109
 
101
- <p align="center">
102
- <video src="https://github.com/user-attachments/assets/dd8280d2-fc8a-47c9-b2db-b1a1ccde81ce" width="640" controls muted></video>
103
- </p>
104
-
105
110
  ## What you get
106
111
 
107
112
  Point seemore at any Markdown you already have: AI-written notes, project docs, RFCs, API references, specs, or an engineering handbook. You get:
@@ -109,6 +114,7 @@ Point seemore at any Markdown you already have: AI-written notes, project docs,
109
114
  - **Zero config**: no config file, no code, no files to move
110
115
  - **Live preview**: files appear, disappear and reorder as you edit them
111
116
  - **Edit in place**: double-click any block in the preview to fix its Markdown
117
+ - **Desktop app**: for macOS, Windows and Linux
112
118
  - **Editor integration**: one extension covers VS Code, Cursor, Antigravity and other VS Code-compatible editors, including remote workspaces
113
119
  - **Documentation framework**: `seemore build` renders the whole site to HTML, ready to deploy on any host
114
120
  - **Password protection**: protect the built site with one shared password, with no server required
@@ -128,6 +134,14 @@ The preview is also an editor. Double-click any paragraph, heading, list item, q
128
134
 
129
135
  Inline editing works only for local previews.
130
136
 
137
+ ## Open with the desktop app
138
+
139
+ Download the app from the [download page](https://arifszn.github.io/seemore/download). It opens a folder or a `.md` file as a site in its own window. You do not need a terminal or Node.js.
140
+
141
+ - **Open a folder**: use **File > Open Folder**, or drag the folder onto the app.
142
+ - **Open a file**: double-click a `.md` file, or use **File > Open File**.
143
+ - **Export and build**: use the **File** menu.
144
+
131
145
  ## View in your code editor
132
146
 
133
147
  Install **seemore** from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=arifszn.seemore-vscode) or [Open VSX](https://open-vsx.org/extension/arifszn/seemore-vscode). You get the same rendered site as a panel beside your editor, with no terminal and no browser tab to manage. The extension bundles the CLI, so nothing downloads and nothing goes on your PATH.
@@ -214,7 +228,7 @@ The [themes page](https://arifszn.github.io/seemore/themes) shows all twelve.
214
228
 
215
229
  ## Content
216
230
 
217
- Works with both `.md` and `.mdx`. **[Mermaid](https://mermaid.js.org)** and **[D2](https://d2lang.com)** diagrams render live in the browser, straight from a ` ```mermaid ` or ` ```d2 ` code fence:
231
+ Works with `.md`, `.markdown` and `.mdx`. **[Mermaid](https://mermaid.js.org)** and **[D2](https://d2lang.com)** diagrams render live in the browser, straight from a ` ```mermaid ` or ` ```d2 ` code fence:
218
232
 
219
233
  <p align="center">
220
234
  <img src="https://raw.githubusercontent.com/arifszn/seemore/main/packages/site/assets/diagrams.png" alt="A mermaid code fence on the Diagrams page, with the flowchart it produces below: folder of .md into seemore, then a live site and static HTML" width="640"/>
package/dist/cli/index.js CHANGED
@@ -201,7 +201,7 @@ function withBase(base, href) {
201
201
  // src/node/content/slug.ts
202
202
  import { slug as slugify } from "github-slugger";
203
203
  var INDEX_NAMES = /* @__PURE__ */ new Set(["index", "readme"]);
204
- var CONTENT_EXT = /\.mdx?$/i;
204
+ var CONTENT_EXT = /\.(?:mdx?|markdown)$/i;
205
205
  function toPosix(file) {
206
206
  return file.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
207
207
  }
@@ -672,6 +672,14 @@ function toMap(input) {
672
672
  return Object.fromEntries(set);
673
673
  }
674
674
 
675
+ // src/node/config/names.ts
676
+ var CONFIG_NAMES = [
677
+ "seemore.config.ts",
678
+ "seemore.config.mts",
679
+ "seemore.config.js",
680
+ "seemore.config.mjs"
681
+ ];
682
+
675
683
  // src/node/config/schema.ts
676
684
  import { z } from "zod";
677
685
  var THEMES = [
@@ -756,7 +764,6 @@ var configSchema = z.object({
756
764
  });
757
765
 
758
766
  // src/node/config/load.ts
759
- var CONFIG_NAMES = ["seemore.config.ts", "seemore.config.mts", "seemore.config.js", "seemore.config.mjs"];
760
767
  function resolveConfig(input, options) {
761
768
  const parsed = parseOrThrow(input, options.configFile);
762
769
  const search = parsed.search === "static" ? { provider: "static" } : parsed.search;
@@ -883,7 +890,7 @@ function explain(issue) {
883
890
 
884
891
  // src/node/content/links.ts
885
892
  import { slug as slugify2 } from "github-slugger";
886
- var CONTENT_EXT2 = /\.mdx?$/i;
893
+ var CONTENT_EXT2 = /\.(?:mdx?|markdown)$/i;
887
894
  function createLinkResolver(pages, base) {
888
895
  const byPath = /* @__PURE__ */ new Map();
889
896
  const byName = /* @__PURE__ */ new Map();
@@ -1050,7 +1057,7 @@ var metaSchema = z4.object({
1050
1057
  function scan(options) {
1051
1058
  const contentRoot = resolve3(options.contentRoot);
1052
1059
  const find = (patterns, keep) => findFiles(contentRoot, patterns, keep, options.exclude ?? [], options.include ?? []);
1053
- const contentFiles = find(["**/*.md", "**/*.mdx"], /\.mdx?$/);
1060
+ const contentFiles = find(["**/*.md", "**/*.markdown", "**/*.mdx"], /\.(?:mdx?|markdown)$/);
1054
1061
  const metaFiles = find(["**/meta.json"], /(?:^|\/)meta\.json$/);
1055
1062
  const { routes, errors, warnings } = resolveRoutes(contentFiles);
1056
1063
  const pages = [];
@@ -1121,7 +1128,7 @@ function synthesiseOrderMeta(pages, metaDirs) {
1121
1128
  for (const [dir, dirPages] of byDir) {
1122
1129
  if (metaDirs.has(dir)) continue;
1123
1130
  if (!dirPages.some((p) => typeof p.data.order === "number" || p.isIndex)) continue;
1124
- const ordered = [...dirPages].sort(compareForOrder).map((p) => basename(p.file).replace(/\.mdx?$/i, ""));
1131
+ const ordered = [...dirPages].sort(compareForOrder).map((p) => basename(p.file).replace(/\.(?:mdx?|markdown)$/i, ""));
1125
1132
  out.push({
1126
1133
  type: "meta",
1127
1134
  path: dir === "." ? "meta.json" : `${dir}/meta.json`,
@@ -1489,7 +1496,7 @@ function rehypeSeemoreRawHtml() {
1489
1496
  const transform = rehypeRaw({ passThrough: [...MDX_NODE_TYPES] });
1490
1497
  return (tree, file) => {
1491
1498
  const path = file.path ?? "";
1492
- if (!/\.md(?:$|\?)/.test(path)) return tree;
1499
+ if (!/\.(?:md|markdown)(?:$|\?)/.test(path)) return tree;
1493
1500
  return transform(tree, file);
1494
1501
  };
1495
1502
  }
@@ -1741,7 +1748,7 @@ function createRehypePlugins(options) {
1741
1748
  }
1742
1749
 
1743
1750
  // src/node/vite/plugin.ts
1744
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
1751
+ import { existsSync as existsSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
1745
1752
  import { createRequire as createRequire2 } from "module";
1746
1753
  import { dirname as dirname8 } from "path";
1747
1754
 
@@ -1936,6 +1943,28 @@ function seemorePlugin({ ctx, serveSearch = false }) {
1936
1943
  res.setHeader("Content-Type", "application/json");
1937
1944
  res.end(JSON.stringify({ url: withBase(ctx.config.base, page.url) }));
1938
1945
  });
1946
+ devServer.middlewares.use((req, res, next) => {
1947
+ const [path = "", query = ""] = (req.url ?? "").split("?");
1948
+ if (path !== "/__seemore/page") return next();
1949
+ const url = new URLSearchParams(query).get("url");
1950
+ if (url === null) return send(res, 400, { error: 'Missing "url" query parameter.' });
1951
+ const route = routeOf(url, ctx.config.base);
1952
+ const page = ctx.pages().find((p) => p.url === route);
1953
+ if (page === void 0) return send(res, 404, { error: `No page is served at ${url}.` });
1954
+ return send(res, 200, { file: page.absPath });
1955
+ });
1956
+ devServer.middlewares.use((req, res, next) => {
1957
+ const path = (req.url ?? "").split("?")[0] ?? "";
1958
+ if (path !== "/__seemore/site") return next();
1959
+ const configFile = ctx.config.configFile;
1960
+ void loadConfig({
1961
+ root: ctx.contentRoot,
1962
+ configPath: configFile !== void 0 && existsSync5(configFile) ? configFile : void 0
1963
+ }).then(
1964
+ ({ config }) => send(res, 200, { base: config.base, pageActions: config.pageActions, auth: config.auth !== void 0 }),
1965
+ (error) => send(res, 500, { error: error instanceof Error ? error.message : String(error) })
1966
+ );
1967
+ });
1939
1968
  if (ctx.config.features["content.edit"]) {
1940
1969
  devServer.middlewares.use((req, res, next) => {
1941
1970
  const path = (req.url ?? "").split("?")[0] ?? "";
@@ -1957,10 +1986,29 @@ function seemorePlugin({ ctx, serveSearch = false }) {
1957
1986
  }
1958
1987
  };
1959
1988
  }
1989
+ function routeOf(url, base) {
1990
+ let path;
1991
+ try {
1992
+ path = decodeURIComponent(new URL(url, "http://localhost").pathname);
1993
+ } catch {
1994
+ return url;
1995
+ }
1996
+ if (base !== "/") {
1997
+ if (path === base.slice(0, -1)) path = "/";
1998
+ else if (path.startsWith(base)) path = path.slice(base.length - 1);
1999
+ }
2000
+ return path.length > 1 ? path.replace(/\/+$/, "") : path;
2001
+ }
1960
2002
  var SOURCE_ENDPOINT = "/__seemore/source";
1961
2003
  async function handleSource(ctx, req, res) {
1962
2004
  if (req.method === "GET") return handleSourceRead(ctx, req, res);
1963
- if (req.method === "PUT") return handleSourceWrite(ctx, req, res);
2005
+ if (req.method === "PUT") {
2006
+ const origin = req.headers.origin;
2007
+ if (origin !== void 0 && origin !== `http://${req.headers.host ?? ""}`) {
2008
+ return send(res, 403, { error: "Writes are only accepted from this site's own pages." });
2009
+ }
2010
+ return handleSourceWrite(ctx, req, res);
2011
+ }
1964
2012
  res.setHeader("Allow", "GET, PUT");
1965
2013
  return send(res, 405, { error: `${req.method ?? "This method"} is not allowed here.` });
1966
2014
  }
@@ -2088,7 +2136,7 @@ function readIfExists(path) {
2088
2136
  // src/node/vite/watcher.ts
2089
2137
  import { relative as relative3 } from "path";
2090
2138
  import chokidar from "chokidar";
2091
- var CONTENT_FILE = /\.(?:mdx?|json)$/i;
2139
+ var CONTENT_FILE = /\.(?:mdx?|markdown|json)$/i;
2092
2140
  var EXCLUDED_DIR = /(?:^|\/)(?:node_modules|dist|build|out|vendor|target|venv|deps|Pods|bower_components|\.[^/]+)(?:$|\/)/;
2093
2141
  var ALWAYS_EXCLUDED_DIR = /(?:^|\/)(?:node_modules|\.git)(?:$|\/)/;
2094
2142
  var GLOB_CHAR = /[*?[\]{}()!]/;
@@ -2152,7 +2200,7 @@ async function handleContentChange(server, ctx, event, path) {
2152
2200
  ctx.warnings.flush((line) => server.config.logger.warn(line));
2153
2201
  await reloadVirtual(server, VIRTUAL.tree);
2154
2202
  await reloadVirtual(server, VIRTUAL.routes);
2155
- if (event === "change" && /\.mdx?$/i.test(path)) {
2203
+ if (event === "change" && /\.(?:mdx?|markdown)$/i.test(path)) {
2156
2204
  await reloadFile(server, path);
2157
2205
  }
2158
2206
  }
@@ -2261,6 +2309,9 @@ function createViteConfig({ ctx, mode, outDir, ssrOutDir, auth = false }) {
2261
2309
  conditions: mode === "dev" ? ["worker"] : void 0
2262
2310
  },
2263
2311
  server: {
2312
+ // Off rather than Vite's default, which admits every localhost origin: the dev server
2313
+ // has a write endpoint, and its own pages are the only callers it means to answer.
2314
+ cors: false,
2264
2315
  fs: {
2265
2316
  // The content root is normally *outside* the Vite root, and files outside `allow`
2266
2317
  // 404 silently — the single most likely cause of "the watcher does nothing".
@@ -2311,7 +2362,7 @@ function contentHmrPlugin() {
2311
2362
  name: "seemore:content-hmr",
2312
2363
  apply: "serve",
2313
2364
  transform(code, id) {
2314
- if (!/\.mdx?(?:$|\?)/.test(id)) return null;
2365
+ if (!/\.(?:mdx?|markdown)(?:$|\?)/.test(id)) return null;
2315
2366
  return { code: `${code}
2316
2367
  if (import.meta.hot) import.meta.hot.accept();
2317
2368
  `, map: null };
@@ -2568,8 +2619,8 @@ async function runDev(options) {
2568
2619
  }
2569
2620
 
2570
2621
  // src/cli/export.ts
2571
- import { existsSync as existsSync5, mkdtempSync as mkdtempSync2, readFileSync as readFileSync8, readdirSync as readdirSync2, rmSync as rmSync2, statSync, writeFileSync as writeFileSync8, mkdirSync as mkdirSync4 } from "fs";
2572
- import { basename as basename2, dirname as dirname10, extname, join as join13, relative as relative5, resolve as resolve7 } from "path";
2622
+ import { existsSync as existsSync6, mkdtempSync as mkdtempSync2, readFileSync as readFileSync8, readdirSync as readdirSync2, rmSync as rmSync2, statSync, writeFileSync as writeFileSync8, mkdirSync as mkdirSync4 } from "fs";
2623
+ import { basename as basename2, dirname as dirname10, extname, isAbsolute as isAbsolute3, join as join13, relative as relative5, resolve as resolve7, sep } from "path";
2573
2624
  import { tmpdir as tmpdir4 } from "os";
2574
2625
  import pc4 from "picocolors";
2575
2626
  import { build as viteBuild2 } from "vite";
@@ -2605,10 +2656,16 @@ var THEME_INIT = `<script>(function () {
2605
2656
  // src/cli/export.ts
2606
2657
  async function runExport(options) {
2607
2658
  const target = resolve7(options.cwd, options.file);
2608
- if (!existsSync5(target) || !statSync(target).isFile()) {
2659
+ if (!existsSync6(target) || !statSync(target).isFile()) {
2609
2660
  throw new Error(`No such file: ${options.file}`);
2610
2661
  }
2611
- const contentRoot = resolveContentRoot(options.cwd, dirname10(target));
2662
+ if (options.out !== void 0 && options.outFile !== void 0) {
2663
+ throw new Error("--out and --out-file cannot be combined: --out names a directory, --out-file the exact file.");
2664
+ }
2665
+ const contentRoot = resolveContentRoot(options.cwd, options.root ?? dirname10(target));
2666
+ if (options.root !== void 0 && !isInside(canonicalise(target), contentRoot)) {
2667
+ throw new Error(`${options.file} is not inside the root ${options.root}.`);
2668
+ }
2612
2669
  const loaded = await loadConfig({ root: contentRoot, configPath: resolveConfigPath(options) });
2613
2670
  const config = {
2614
2671
  ...loaded.config,
@@ -2640,9 +2697,9 @@ ${errors.join("\n\n")}`);
2640
2697
  const article = await prerender.renderArticle(page.url);
2641
2698
  const runtime = await bundleRuntime();
2642
2699
  const html = assemble({ article, css, runtime, config, outDir, contentRoot, template });
2643
- const filename = `${basename2(target).replace(/\.(?:md|mdx)$/i, "")}.html`;
2644
- const targetPath = options.out === void 0 ? join13(dirname10(target), filename) : join13(resolve7(options.cwd, options.out), filename);
2645
- if (existsSync5(targetPath)) {
2700
+ const filename = `${basename2(target).replace(/\.(?:md|markdown|mdx)$/i, "")}.html`;
2701
+ const targetPath = options.outFile !== void 0 ? resolve7(options.cwd, options.outFile) : options.out === void 0 ? join13(dirname10(target), filename) : join13(resolve7(options.cwd, options.out), filename);
2702
+ if (existsSync6(targetPath)) {
2646
2703
  console.log(pc4.yellow(`seemore replacing existing ${relative5(options.cwd, targetPath) || targetPath}`));
2647
2704
  }
2648
2705
  mkdirSync4(dirname10(targetPath), { recursive: true });
@@ -2654,9 +2711,13 @@ ${errors.join("\n\n")}`);
2654
2711
  rmSync2(ssrOutDir, { recursive: true, force: true });
2655
2712
  }
2656
2713
  }
2714
+ function isInside(file, dir) {
2715
+ const path = relative5(dir, file);
2716
+ return path !== "" && path !== ".." && !path.startsWith(`..${sep}`) && !isAbsolute3(path);
2717
+ }
2657
2718
  function readBuiltCss(outDir) {
2658
2719
  const assets = join13(outDir, "assets");
2659
- const files = existsSync5(assets) ? readdirSync2(assets).filter((file) => file.endsWith(".css")) : [];
2720
+ const files = existsSync6(assets) ? readdirSync2(assets).filter((file) => file.endsWith(".css")) : [];
2660
2721
  if (files.length === 0) throw new Error("The build produced no stylesheet \u2014 the export would be unstyled.");
2661
2722
  return files.map((file) => readFileSync8(join13(assets, file), "utf8")).join("\n");
2662
2723
  }
@@ -2747,7 +2808,7 @@ function resolveAsset(src, base, outDir, contentRoot) {
2747
2808
  const suffix = path.replace(/^\/+/, "");
2748
2809
  for (const root of [outDir, contentRoot]) {
2749
2810
  const candidate = join13(root, suffix);
2750
- if (existsSync5(candidate) && statSync(candidate).isFile()) return candidate;
2811
+ if (existsSync6(candidate) && statSync(candidate).isFile()) return candidate;
2751
2812
  }
2752
2813
  return void 0;
2753
2814
  }
@@ -2775,7 +2836,7 @@ function dataUriFor(file) {
2775
2836
  function faviconLink(config, contentRoot, template) {
2776
2837
  if (config.favicon !== void 0) {
2777
2838
  const file = join13(contentRoot, config.favicon);
2778
- if (existsSync5(file)) {
2839
+ if (existsSync6(file)) {
2779
2840
  try {
2780
2841
  return `<link rel="icon" href="${dataUriFor(file)}" />`;
2781
2842
  } catch {
@@ -2839,6 +2900,8 @@ Options
2839
2900
  --json print one machine-readable JSON line instead of the summary (dev only)
2840
2901
  --config <path> path to seemore.config.ts
2841
2902
  --out <dir> build output directory (default: dist); for export, where the HTML file is written
2903
+ --out-file <path> export only: the exact file to write, instead of --out
2904
+ --root <dir> export only: the site the file belongs to (default: the file's folder)
2842
2905
  --base <path> subpath the site is served from, e.g. /my-repo/
2843
2906
  -h, --help show this message
2844
2907
  -v, --version show the version
@@ -2850,6 +2913,7 @@ function normaliseHostFlag(argv) {
2850
2913
  if (next !== void 0 && !next.startsWith("-")) return argv;
2851
2914
  return [...argv.slice(0, index), "--host=", ...argv.slice(index + 1)];
2852
2915
  }
2916
+ var servesUntilKilled = false;
2853
2917
  async function main(argv = process.argv.slice(2)) {
2854
2918
  const { values, positionals } = parseArgs({
2855
2919
  args: normaliseHostFlag(argv),
@@ -2862,6 +2926,8 @@ async function main(argv = process.argv.slice(2)) {
2862
2926
  json: { type: "boolean" },
2863
2927
  config: { type: "string" },
2864
2928
  out: { type: "string" },
2929
+ "out-file": { type: "string" },
2930
+ root: { type: "string" },
2865
2931
  base: { type: "string" },
2866
2932
  help: { type: "boolean", short: "h" },
2867
2933
  version: { type: "boolean", short: "v" }
@@ -2891,9 +2957,18 @@ async function main(argv = process.argv.slice(2)) {
2891
2957
  if (isExport) {
2892
2958
  const file = rest[0];
2893
2959
  if (file === void 0) throw new Error("Usage: seemore export <file> \u2014 name the Markdown file to export.");
2894
- await runExport({ cwd: shared.cwd, file, out: values.out, configPath: values.config, base: values.base });
2960
+ await runExport({
2961
+ cwd: shared.cwd,
2962
+ file,
2963
+ out: values.out,
2964
+ outFile: values["out-file"],
2965
+ root: values.root,
2966
+ configPath: values.config,
2967
+ base: values.base
2968
+ });
2895
2969
  return;
2896
2970
  }
2971
+ servesUntilKilled = true;
2897
2972
  await runDev({
2898
2973
  ...shared,
2899
2974
  port: values.port === void 0 ? void 0 : Number(values.port),
@@ -2902,12 +2977,23 @@ async function main(argv = process.argv.slice(2)) {
2902
2977
  json: values.json === true
2903
2978
  });
2904
2979
  }
2905
- main().catch((error) => {
2906
- console.error(`
2980
+ function exitAfterFlush(code) {
2981
+ process.exitCode = code;
2982
+ process.stdout.write("", () => {
2983
+ process.stderr.write("", () => process.exit(code));
2984
+ });
2985
+ }
2986
+ main().then(
2987
+ () => {
2988
+ if (!servesUntilKilled) exitAfterFlush(0);
2989
+ },
2990
+ (error) => {
2991
+ console.error(`
2907
2992
  ${pc5.red("seemore")} ${error instanceof Error ? error.message : String(error)}
2908
2993
  `);
2909
- process.exitCode = 1;
2910
- });
2994
+ exitAfterFlush(1);
2995
+ }
2996
+ );
2911
2997
  export {
2912
2998
  main
2913
2999
  };