terminfo.dev 1.4.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.4.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,21 +76,11 @@ 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
 
82
- // Drain any late-arriving escape sequence responses before output
83
- await new Promise<void>((resolve) => {
84
- process.stdin.resume()
85
- const timer = setTimeout(() => {
86
- process.stdin.pause()
87
- process.stdin.removeAllListeners("readable")
88
- resolve()
89
- }, 100)
90
- process.stdin.on("readable", () => { while (process.stdin.read() !== null) {} })
91
- timer.unref()
92
- })
93
-
94
84
  return { terminal, results, notes, responses, passed, total: ALL_PROBES.length }
95
85
  }
96
86
 
@@ -197,7 +187,7 @@ program
197
187
  notes: data.notes,
198
188
  responses: data.responses,
199
189
  generated: new Date().toISOString(),
200
- cliVersion: "1.3.0",
190
+ cliVersion: "1.5.0",
201
191
  probeCount: ALL_PROBES.length,
202
192
  })
203
193
  if (url) {
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.