terminfo.dev 1.3.0 → 1.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminfo.dev",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Test your terminal's feature support and contribute to terminfo.dev",
5
5
  "keywords": [
6
6
  "ansi",
package/src/detect.ts CHANGED
@@ -52,15 +52,19 @@ export function detectTerminal(): TerminalInfo {
52
52
  let name = "unknown"
53
53
  let version = ""
54
54
 
55
- // Check specific env vars first
56
- for (const { env, name: n } of ENV_DETECTORS) {
57
- if (process.env[env]) {
58
- name = n
59
- break
55
+ // On macOS, __CFBundleIdentifier is the most reliable — set by the actual running app
56
+ const bundleId = process.env.__CFBundleIdentifier
57
+ if (bundleId && os === "macos") {
58
+ for (const [termName, bid] of Object.entries(BUNDLE_IDS)) {
59
+ if (bundleId === bid) { name = termName; break }
60
+ }
61
+ // If bundle ID didn't match known terminals, use it as-is
62
+ if (name === "unknown" && bundleId) {
63
+ name = bundleId.split(".").pop() ?? bundleId
60
64
  }
61
65
  }
62
66
 
63
- // Check $TERM_PROGRAM
67
+ // Check $TERM_PROGRAM (more reliable than env var detectors for cross-app scenarios)
64
68
  if (name === "unknown") {
65
69
  const termProgram = process.env.TERM_PROGRAM
66
70
  if (termProgram) {
@@ -69,6 +73,16 @@ export function detectTerminal(): TerminalInfo {
69
73
  }
70
74
  }
71
75
 
76
+ // Check specific env vars (may be inherited from parent, so lower priority)
77
+ if (name === "unknown") {
78
+ for (const { env, name: n } of ENV_DETECTORS) {
79
+ if (process.env[env]) {
80
+ name = n
81
+ break
82
+ }
83
+ }
84
+ }
85
+
72
86
  // Check $TERMINAL_EMULATOR (Linux)
73
87
  if (name === "unknown") {
74
88
  const termEmu = process.env.TERMINAL_EMULATOR
package/src/index.ts CHANGED
@@ -18,7 +18,7 @@ import { dirname, join } from "node:path"
18
18
  import { fileURLToPath } from "node:url"
19
19
  import { detectTerminal } from "./detect.ts"
20
20
  import { ALL_PROBES } from "./probes/index.ts"
21
- import { withRawMode } from "./tty.ts"
21
+ import { withRawMode, drainStdin } from "./tty.ts"
22
22
  import { submitResults } from "./submit.ts"
23
23
 
24
24
  const __dirname = dirname(fileURLToPath(import.meta.url))
@@ -76,6 +76,8 @@ async function runProbes(): Promise<ProbeResults> {
76
76
  notes[probe.id] = `error: ${err instanceof Error ? err.message : String(err)}`
77
77
  }
78
78
  }
79
+ // Drain all pending responses before exiting alt screen (still in raw mode)
80
+ await drainStdin(500)
79
81
  process.stdout.write("\x1b[?1049l")
80
82
  })
81
83
 
@@ -185,7 +187,7 @@ program
185
187
  notes: data.notes,
186
188
  responses: data.responses,
187
189
  generated: new Date().toISOString(),
188
- cliVersion: "1.3.0",
190
+ cliVersion: "1.5.0",
189
191
  probeCount: ALL_PROBES.length,
190
192
  })
191
193
  if (url) {
package/src/submit.ts CHANGED
@@ -23,7 +23,25 @@ interface SubmitData {
23
23
  probeCount?: number
24
24
  }
25
25
 
26
+ /** Drain any leftover bytes from stdin (e.g., late-arriving escape sequence responses) */
27
+ async function drainStdin(): Promise<void> {
28
+ return new Promise((resolve) => {
29
+ if (!process.stdin.readable) { resolve(); return }
30
+ process.stdin.resume()
31
+ const timer = setTimeout(() => {
32
+ process.stdin.pause()
33
+ process.stdin.removeAllListeners("readable")
34
+ resolve()
35
+ }, 200)
36
+ process.stdin.on("readable", () => {
37
+ while (process.stdin.read() !== null) {} // discard
38
+ })
39
+ timer.unref()
40
+ })
41
+ }
42
+
26
43
  async function prompt(question: string, defaultValue?: string): Promise<string> {
44
+ await drainStdin()
27
45
  const rl = createInterface({ input: process.stdin, output: process.stdout })
28
46
  const suffix = defaultValue ? ` [${defaultValue}]` : ""
29
47
  return new Promise((resolve) => {
package/src/tty.ts CHANGED
@@ -89,6 +89,28 @@ export async function queryMode(modeNumber: number): Promise<"set" | "reset" | "
89
89
  }
90
90
  }
91
91
 
92
+ /**
93
+ * Drain all pending bytes from stdin (late-arriving escape sequence responses).
94
+ * Waits up to `ms` milliseconds for bytes to stop arriving.
95
+ */
96
+ export async function drainStdin(ms = 300): Promise<void> {
97
+ return new Promise((resolve) => {
98
+ if (!process.stdin.readable) { resolve(); return }
99
+ process.stdin.resume()
100
+ let timer = setTimeout(done, ms)
101
+ function onData() {
102
+ while (process.stdin.read() !== null) {} // discard
103
+ clearTimeout(timer)
104
+ timer = setTimeout(done, ms) // reset timer on each new data
105
+ }
106
+ function done() {
107
+ process.stdin.removeListener("readable", onData)
108
+ resolve()
109
+ }
110
+ process.stdin.on("readable", onData)
111
+ })
112
+ }
113
+
92
114
  /**
93
115
  * Run a function with stdin in raw mode.
94
116
  * Restores original mode on exit.