veryfront 0.0.93 → 0.0.95

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/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.0.93",
3
+ "version": "0.0.95",
4
4
  "nodeModulesDir": "auto",
5
5
  "exclude": [
6
6
  "npm/",
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/cli/app/index.ts"],"names":[],"mappings":"AAkCA,OAAO,EAEL,KAAK,QAAQ,EAcb,KAAK,YAAY,EAQlB,MAAM,YAAY,CAAC;AASpB,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,GAAG;IAClB,oBAAoB;IACpB,KAAK,IAAI,IAAI,CAAC;IACd,wCAAwC;IACxC,IAAI,IAAI,IAAI,CAAC;IACb,mBAAmB;IACnB,MAAM,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,wBAAwB;IACxB,QAAQ,IAAI,QAAQ,CAAC;IACrB,8BAA8B;IAC9B,MAAM,IAAI,IAAI,CAAC;IACf,uBAAuB;IACvB,cAAc,IAAI,IAAI,CAAC;IACvB,mBAAmB;IACnB,QAAQ,IAAI,IAAI,CAAC;IACjB,mBAAmB;IACnB,WAAW,IAAI,IAAI,CAAC;IACpB,uCAAuC;IACvC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvE,qDAAqD;IACrD,gBAAgB,IAAI,MAAM,IAAI,CAAC;CAChC;AAuMD;;GAEG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,GAAG,CA4mChD;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BhE;AAED,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/cli/app/index.ts"],"names":[],"mappings":"AAsCA,OAAO,EAEL,KAAK,QAAQ,EAcb,KAAK,YAAY,EAQlB,MAAM,YAAY,CAAC;AASpB,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,GAAG;IAClB,oBAAoB;IACpB,KAAK,IAAI,IAAI,CAAC;IACd,wCAAwC;IACxC,IAAI,IAAI,IAAI,CAAC;IACb,mBAAmB;IACnB,MAAM,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,wBAAwB;IACxB,QAAQ,IAAI,QAAQ,CAAC;IACrB,8BAA8B;IAC9B,MAAM,IAAI,IAAI,CAAC;IACf,uBAAuB;IACvB,cAAc,IAAI,IAAI,CAAC;IACvB,mBAAmB;IACnB,QAAQ,IAAI,IAAI,CAAC;IACjB,mBAAmB;IACnB,WAAW,IAAI,IAAI,CAAC;IACpB,uCAAuC;IACvC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvE,qDAAqD;IACrD,gBAAgB,IAAI,MAAM,IAAI,CAAC;CAChC;AAuMD;;GAEG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,GAAG,CAinChD;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BhE;AAED,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,6BAA6B,CAAC"}
@@ -9,7 +9,7 @@ import * as dntShim from "../../../_dnt.shims.js";
9
9
  import { cwd, exit, isInteractive, isStdoutTTY, writeStdout, } from "../../platform/compat/process.js";
10
10
  import { join } from "../../platform/compat/path/index.js";
11
11
  import { getRuntimeEnv } from "../../config/runtime-env.js";
12
- import { getStdinReader, setRawMode } from "../../platform/compat/stdin.js";
12
+ import { createEscapeBuffer, getStdinReader, setRawMode, } from "../../platform/compat/stdin.js";
13
13
  import { cursor, screen, SPINNER_FRAMES } from "../ui/ansi.js";
14
14
  import { brand, dim } from "../ui/colors.js";
15
15
  import { getTerminalWidth } from "../ui/layout.js";
@@ -481,15 +481,20 @@ export function createApp(config) {
481
481
  setRawMode(true);
482
482
  const reader = getStdinReader();
483
483
  const decoder = new TextDecoder();
484
+ // Buffer escape sequences (arrow keys like \x1b[A may arrive as separate reads)
485
+ const escapeBuffer = createEscapeBuffer((key) => handleKey(key));
484
486
  try {
485
487
  while (running) {
486
488
  const { value, done } = await reader.read();
487
489
  if (done)
488
490
  break;
489
- await handleKey(decoder.decode(value));
491
+ const key = escapeBuffer.push(decoder.decode(value));
492
+ if (key)
493
+ await handleKey(key);
490
494
  }
491
495
  }
492
496
  finally {
497
+ escapeBuffer.clear();
493
498
  reader.releaseLock();
494
499
  try {
495
500
  setRawMode(false);
@@ -1 +1 @@
1
- {"version":3,"file":"react-paths.d.ts","sourceRoot":"","sources":["../../../../src/src/platform/compat/react-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAmEH,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAa3D;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAO3D;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
1
+ {"version":3,"file":"react-paths.d.ts","sourceRoot":"","sources":["../../../../src/src/platform/compat/react-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAwEH,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAa3D;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAO3D;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
@@ -8,7 +8,8 @@
8
8
  *
9
9
  * @module
10
10
  */
11
- import { pathToFileURL } from "node:url";
11
+ import { fileURLToPath, pathToFileURL } from "node:url";
12
+ import { dirname } from "node:path";
12
13
  import { isBun, isDeno, isNode } from "./runtime.js";
13
14
  import { cwd } from "./process.js";
14
15
  let localReactPathsCache = null;
@@ -45,7 +46,11 @@ function resolveReactSpecifier(specifier) {
45
46
  return `file://${resolved}`;
46
47
  }
47
48
  if (isNode) {
48
- const parentUrl = pathToFileURL(`${cwd()}/`).href;
49
+ // Use import.meta.url (this module's location) as the parent URL.
50
+ // This ensures React is resolved from veryfront's node_modules,
51
+ // not from the cwd which may not have React installed.
52
+ const thisModuleDir = dirname(fileURLToPath(globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).url));
53
+ const parentUrl = pathToFileURL(`${thisModuleDir}/`).href;
49
54
  return resolveWithImportMeta(specifier, parentUrl) ?? undefined;
50
55
  }
51
56
  }
@@ -27,5 +27,18 @@ export declare function waitForKeypress(): Promise<void>;
27
27
  * Returns true if Enter was pressed (continue), false if Ctrl+C (exit).
28
28
  * Works in both Deno and Node.js.
29
29
  */
30
+ /**
31
+ * Buffer for escape sequences that may arrive in separate reads.
32
+ * Arrow keys (\x1b[A) can arrive as "\x1b" then "[A" - this combines them.
33
+ */
34
+ export interface EscapeBuffer {
35
+ push(input: string): string | null;
36
+ clear(): void;
37
+ }
38
+ /**
39
+ * Create an escape sequence buffer.
40
+ * @param onTimeout Called when a standalone Escape key times out
41
+ */
42
+ export declare function createEscapeBuffer(onTimeout: (key: string) => void): EscapeBuffer;
30
43
  export declare function waitForEnterOrExit(): Promise<boolean>;
31
44
  //# sourceMappingURL=stdin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stdin.d.ts","sourceRoot":"","sources":["../../../../src/src/platform/compat/stdin.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAUjD;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAClE,WAAW,IAAI,IAAI,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,WAAW,CA0D5C;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CA2B/C;AAOD;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,CA+DrD"}
1
+ {"version":3,"file":"stdin.d.ts","sourceRoot":"","sources":["../../../../src/src/platform/compat/stdin.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAUjD;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAClE,WAAW,IAAI,IAAI,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,WAAW,CA0D5C;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CA2B/C;AAOD;;;;GAIG;AACH;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACnC,KAAK,IAAI,IAAI,CAAC;CACf;AAKD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,YAAY,CAiCjF;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,CA+DrD"}
@@ -109,11 +109,42 @@ export function waitForKeypress() {
109
109
  const CTRL_C = 0x03;
110
110
  const ENTER_CR = 0x0d;
111
111
  const ENTER_LF = 0x0a;
112
+ const ESC = "\x1b";
113
+ const ESC_TIMEOUT_MS = 50;
112
114
  /**
113
- * Wait for Enter key or Ctrl+C.
114
- * Returns true if Enter was pressed (continue), false if Ctrl+C (exit).
115
- * Works in both Deno and Node.js.
115
+ * Create an escape sequence buffer.
116
+ * @param onTimeout Called when a standalone Escape key times out
116
117
  */
118
+ export function createEscapeBuffer(onTimeout) {
119
+ let pending = "";
120
+ let timeoutId = null;
121
+ function clear() {
122
+ if (timeoutId) {
123
+ clearTimeout(timeoutId);
124
+ timeoutId = null;
125
+ }
126
+ pending = "";
127
+ }
128
+ function push(input) {
129
+ if (pending) {
130
+ const result = pending + input;
131
+ clear();
132
+ return result;
133
+ }
134
+ if (input === ESC) {
135
+ pending = input;
136
+ timeoutId = dntShim.setTimeout(() => {
137
+ const key = pending;
138
+ clear();
139
+ if (key)
140
+ onTimeout(key);
141
+ }, ESC_TIMEOUT_MS);
142
+ return null;
143
+ }
144
+ return input;
145
+ }
146
+ return { push, clear };
147
+ }
117
148
  export function waitForEnterOrExit() {
118
149
  return new Promise((resolve) => {
119
150
  if (typeof dntShim.Deno !== "undefined" && dntShim.Deno.stdin) {
@@ -1 +1 @@
1
- {"version":3,"file":"http-cache.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/http-cache.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAezE,KAAK,YAAY,GAAG;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,eAAe,CAAC;IAC3B,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAoVF;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOvF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA8D9F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAClD,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,EAAE,CAAC,CAiInB"}
1
+ {"version":3,"file":"http-cache.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/http-cache.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAezE,KAAK,YAAY,GAAG;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,eAAe,CAAC;IAC3B,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAqVF;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOvF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA8D9F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAClD,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,EAAE,CAAC,CAiInB"}
@@ -108,9 +108,6 @@ function normalizeHttpUrl(raw) {
108
108
  return raw;
109
109
  }
110
110
  }
111
- function toEsmShUrlFromNpm(specifier) {
112
- return `https://esm.sh/${specifier.slice(4)}`;
113
- }
114
111
  function resolveBareSpecifier(specifier, importMap, reactVersion = REACT_VERSION) {
115
112
  // Use esm.sh URLs for React - NO npm: specifiers per plan requirements.
116
113
  // All packages use external=react to share the same React instance.
@@ -250,13 +247,18 @@ async function resolveSpecifier(specifier, baseUrl, options) {
250
247
  if (isExternalScheme(specifier) || isInternalBare(specifier))
251
248
  return null;
252
249
  // For Deno: Keep npm: specifiers as-is (Deno resolves them natively with auto-dedup)
253
- // For other runtimes: Convert to esm.sh and cache locally
250
+ // For other runtimes: Convert to esm.sh and cache locally (or return bare specifier for React)
254
251
  if (specifier.startsWith("npm:")) {
255
252
  if (isDeno) {
256
253
  return specifier; // Let Deno's native npm resolution handle it
257
254
  }
258
- const cached = await cacheHttpModule(toEsmShUrlFromNpm(specifier), options);
259
- return cached ? `file://${cached}` : null;
255
+ const bareSpecifier = specifier.slice(4); // Remove "npm:" prefix
256
+ const esmShUrl = `https://esm.sh/${bareSpecifier}`;
257
+ const cached = await cacheHttpModule(esmShUrl, options);
258
+ // For React packages, cacheHttpModule returns null to prevent multiple instances.
259
+ // Return the bare specifier so transformReactToLocalPaths can resolve it to a local file:// path.
260
+ // For non-React packages, return the cached file:// path.
261
+ return cached ? `file://${cached}` : bareSpecifier;
260
262
  }
261
263
  if (isHttpUrl(specifier)) {
262
264
  const cached = await cacheHttpModule(specifier, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.0.93",
3
+ "version": "0.0.95",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.0.93",
3
+ "version": "0.0.95",
4
4
  "nodeModulesDir": "auto",
5
5
  "exclude": [
6
6
  "npm/",
@@ -17,7 +17,11 @@ import {
17
17
  } from "../../platform/compat/process.js";
18
18
  import { join } from "../../platform/compat/path/index.js";
19
19
  import { getRuntimeEnv } from "../../config/runtime-env.js";
20
- import { getStdinReader, setRawMode } from "../../platform/compat/stdin.js";
20
+ import {
21
+ createEscapeBuffer,
22
+ getStdinReader,
23
+ setRawMode,
24
+ } from "../../platform/compat/stdin.js";
21
25
  import { cursor, screen, SPINNER_FRAMES } from "../ui/ansi.js";
22
26
  import { brand, dim } from "../ui/colors.js";
23
27
  import { getTerminalWidth } from "../ui/layout.js";
@@ -612,14 +616,19 @@ export function createApp(config: AppConfig): App {
612
616
  const reader = getStdinReader();
613
617
  const decoder = new TextDecoder();
614
618
 
619
+ // Buffer escape sequences (arrow keys like \x1b[A may arrive as separate reads)
620
+ const escapeBuffer = createEscapeBuffer((key) => handleKey(key));
621
+
615
622
  try {
616
623
  while (running) {
617
624
  const { value, done } = await reader.read();
618
625
  if (done) break;
619
626
 
620
- await handleKey(decoder.decode(value));
627
+ const key = escapeBuffer.push(decoder.decode(value));
628
+ if (key) await handleKey(key);
621
629
  }
622
630
  } finally {
631
+ escapeBuffer.clear();
623
632
  reader.releaseLock();
624
633
  try {
625
634
  setRawMode(false);
@@ -12,7 +12,8 @@
12
12
  // Bun global type declaration for cross-runtime compatibility
13
13
  declare const Bun: { resolveSync?: (specifier: string, dir: string) => string } | undefined;
14
14
 
15
- import { pathToFileURL } from "node:url";
15
+ import { fileURLToPath, pathToFileURL } from "node:url";
16
+ import { dirname } from "node:path";
16
17
  import { isBun, isDeno, isNode } from "./runtime.js";
17
18
  import { cwd } from "./process.js";
18
19
 
@@ -62,7 +63,11 @@ function resolveReactSpecifier(specifier: string): string | undefined {
62
63
  }
63
64
 
64
65
  if (isNode) {
65
- const parentUrl = pathToFileURL(`${cwd()}/`).href;
66
+ // Use import.meta.url (this module's location) as the parent URL.
67
+ // This ensures React is resolved from veryfront's node_modules,
68
+ // not from the cwd which may not have React installed.
69
+ const thisModuleDir = dirname(fileURLToPath(import.meta.url));
70
+ const parentUrl = pathToFileURL(`${thisModuleDir}/`).href;
66
71
  return resolveWithImportMeta(specifier, parentUrl) ?? undefined;
67
72
  }
68
73
  } catch (error) {
@@ -150,6 +150,57 @@ const ENTER_LF = 0x0a;
150
150
  * Returns true if Enter was pressed (continue), false if Ctrl+C (exit).
151
151
  * Works in both Deno and Node.js.
152
152
  */
153
+ /**
154
+ * Buffer for escape sequences that may arrive in separate reads.
155
+ * Arrow keys (\x1b[A) can arrive as "\x1b" then "[A" - this combines them.
156
+ */
157
+ export interface EscapeBuffer {
158
+ push(input: string): string | null;
159
+ clear(): void;
160
+ }
161
+
162
+ const ESC = "\x1b";
163
+ const ESC_TIMEOUT_MS = 50;
164
+
165
+ /**
166
+ * Create an escape sequence buffer.
167
+ * @param onTimeout Called when a standalone Escape key times out
168
+ */
169
+ export function createEscapeBuffer(onTimeout: (key: string) => void): EscapeBuffer {
170
+ let pending = "";
171
+ let timeoutId: ReturnType<typeof dntShim.setTimeout> | null = null;
172
+
173
+ function clear(): void {
174
+ if (timeoutId) {
175
+ clearTimeout(timeoutId);
176
+ timeoutId = null;
177
+ }
178
+ pending = "";
179
+ }
180
+
181
+ function push(input: string): string | null {
182
+ if (pending) {
183
+ const result = pending + input;
184
+ clear();
185
+ return result;
186
+ }
187
+
188
+ if (input === ESC) {
189
+ pending = input;
190
+ timeoutId = dntShim.setTimeout(() => {
191
+ const key = pending;
192
+ clear();
193
+ if (key) onTimeout(key);
194
+ }, ESC_TIMEOUT_MS);
195
+ return null;
196
+ }
197
+
198
+ return input;
199
+ }
200
+
201
+ return { push, clear };
202
+ }
203
+
153
204
  export function waitForEnterOrExit(): Promise<boolean> {
154
205
  return new Promise((resolve) => {
155
206
  if (typeof dntShim.Deno !== "undefined" && dntShim.Deno.stdin) {
@@ -136,10 +136,6 @@ function normalizeHttpUrl(raw: string): string {
136
136
  }
137
137
  }
138
138
 
139
- function toEsmShUrlFromNpm(specifier: string): string {
140
- return `https://esm.sh/${specifier.slice(4)}`;
141
- }
142
-
143
139
  function resolveBareSpecifier(
144
140
  specifier: string,
145
141
  importMap: ImportMapConfig,
@@ -310,13 +306,18 @@ async function resolveSpecifier(
310
306
  if (isExternalScheme(specifier) || isInternalBare(specifier)) return null;
311
307
 
312
308
  // For Deno: Keep npm: specifiers as-is (Deno resolves them natively with auto-dedup)
313
- // For other runtimes: Convert to esm.sh and cache locally
309
+ // For other runtimes: Convert to esm.sh and cache locally (or return bare specifier for React)
314
310
  if (specifier.startsWith("npm:")) {
315
311
  if (isDeno) {
316
312
  return specifier; // Let Deno's native npm resolution handle it
317
313
  }
318
- const cached = await cacheHttpModule(toEsmShUrlFromNpm(specifier), options);
319
- return cached ? `file://${cached}` : null;
314
+ const bareSpecifier = specifier.slice(4); // Remove "npm:" prefix
315
+ const esmShUrl = `https://esm.sh/${bareSpecifier}`;
316
+ const cached = await cacheHttpModule(esmShUrl, options);
317
+ // For React packages, cacheHttpModule returns null to prevent multiple instances.
318
+ // Return the bare specifier so transformReactToLocalPaths can resolve it to a local file:// path.
319
+ // For non-React packages, return the cached file:// path.
320
+ return cached ? `file://${cached}` : bareSpecifier;
320
321
  }
321
322
 
322
323
  if (isHttpUrl(specifier)) {