@dealdeploy/skl 0.1.6 → 0.1.8
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/.agents/skills/opentui/SKILL.md +198 -0
- package/.agents/skills/opentui/references/animation/REFERENCE.md +431 -0
- package/.agents/skills/opentui/references/components/REFERENCE.md +143 -0
- package/.agents/skills/opentui/references/components/code-diff.md +496 -0
- package/.agents/skills/opentui/references/components/containers.md +412 -0
- package/.agents/skills/opentui/references/components/inputs.md +531 -0
- package/.agents/skills/opentui/references/components/text-display.md +384 -0
- package/.agents/skills/opentui/references/core/REFERENCE.md +145 -0
- package/.agents/skills/opentui/references/core/api.md +506 -0
- package/.agents/skills/opentui/references/core/configuration.md +166 -0
- package/.agents/skills/opentui/references/core/gotchas.md +393 -0
- package/.agents/skills/opentui/references/core/patterns.md +448 -0
- package/.agents/skills/opentui/references/keyboard/REFERENCE.md +511 -0
- package/.agents/skills/opentui/references/layout/REFERENCE.md +337 -0
- package/.agents/skills/opentui/references/layout/patterns.md +444 -0
- package/.agents/skills/opentui/references/react/REFERENCE.md +174 -0
- package/.agents/skills/opentui/references/react/api.md +435 -0
- package/.agents/skills/opentui/references/react/configuration.md +301 -0
- package/.agents/skills/opentui/references/react/gotchas.md +443 -0
- package/.agents/skills/opentui/references/react/patterns.md +501 -0
- package/.agents/skills/opentui/references/solid/REFERENCE.md +201 -0
- package/.agents/skills/opentui/references/solid/api.md +543 -0
- package/.agents/skills/opentui/references/solid/configuration.md +315 -0
- package/.agents/skills/opentui/references/solid/gotchas.md +415 -0
- package/.agents/skills/opentui/references/solid/patterns.md +558 -0
- package/.agents/skills/opentui/references/testing/REFERENCE.md +614 -0
- package/.claude/settings.local.json +11 -0
- package/.claude/skills/opentui/SKILL.md +198 -0
- package/.claude/skills/opentui/references/animation/REFERENCE.md +431 -0
- package/.claude/skills/opentui/references/components/REFERENCE.md +143 -0
- package/.claude/skills/opentui/references/components/code-diff.md +496 -0
- package/.claude/skills/opentui/references/components/containers.md +412 -0
- package/.claude/skills/opentui/references/components/inputs.md +531 -0
- package/.claude/skills/opentui/references/components/text-display.md +384 -0
- package/.claude/skills/opentui/references/core/REFERENCE.md +145 -0
- package/.claude/skills/opentui/references/core/api.md +506 -0
- package/.claude/skills/opentui/references/core/configuration.md +166 -0
- package/.claude/skills/opentui/references/core/gotchas.md +393 -0
- package/.claude/skills/opentui/references/core/patterns.md +448 -0
- package/.claude/skills/opentui/references/keyboard/REFERENCE.md +511 -0
- package/.claude/skills/opentui/references/layout/REFERENCE.md +337 -0
- package/.claude/skills/opentui/references/layout/patterns.md +444 -0
- package/.claude/skills/opentui/references/react/REFERENCE.md +174 -0
- package/.claude/skills/opentui/references/react/api.md +435 -0
- package/.claude/skills/opentui/references/react/configuration.md +301 -0
- package/.claude/skills/opentui/references/react/gotchas.md +443 -0
- package/.claude/skills/opentui/references/react/patterns.md +501 -0
- package/.claude/skills/opentui/references/solid/REFERENCE.md +201 -0
- package/.claude/skills/opentui/references/solid/api.md +543 -0
- package/.claude/skills/opentui/references/solid/configuration.md +315 -0
- package/.claude/skills/opentui/references/solid/gotchas.md +415 -0
- package/.claude/skills/opentui/references/solid/patterns.md +558 -0
- package/.claude/skills/opentui/references/testing/REFERENCE.md +614 -0
- package/index.ts +429 -86
- package/package.json +2 -1
- package/update.ts +87 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# Core Gotchas
|
|
2
|
+
|
|
3
|
+
## Runtime Environment
|
|
4
|
+
|
|
5
|
+
### Use Bun, Not Node.js
|
|
6
|
+
|
|
7
|
+
OpenTUI is built for Bun. Always use Bun commands:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# CORRECT
|
|
11
|
+
bun install @opentui/core
|
|
12
|
+
bun run src/index.ts
|
|
13
|
+
bun test
|
|
14
|
+
|
|
15
|
+
# WRONG
|
|
16
|
+
npm install @opentui/core
|
|
17
|
+
node src/index.ts
|
|
18
|
+
npx jest
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Bun APIs to Use
|
|
22
|
+
|
|
23
|
+
Prefer Bun's built-in APIs:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
// CORRECT - Bun APIs
|
|
27
|
+
Bun.file("path").text() // Instead of fs.readFile
|
|
28
|
+
Bun.serve({ ... }) // Instead of express
|
|
29
|
+
Bun.$`ls -la` // Instead of execa
|
|
30
|
+
import { Database } from "bun:sqlite" // Instead of better-sqlite3
|
|
31
|
+
|
|
32
|
+
// WRONG - Node.js patterns
|
|
33
|
+
import fs from "node:fs"
|
|
34
|
+
import express from "express"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Avoid process.exit()
|
|
38
|
+
|
|
39
|
+
**Never use `process.exit()` directly** - it prevents proper terminal cleanup and can leave the terminal in a broken state (alternate screen mode, raw input mode, etc.).
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// WRONG - Terminal may be left in broken state
|
|
43
|
+
if (error) {
|
|
44
|
+
console.error("Fatal error")
|
|
45
|
+
process.exit(1)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// CORRECT - Use renderer.destroy() for cleanup
|
|
49
|
+
if (error) {
|
|
50
|
+
console.error("Fatal error")
|
|
51
|
+
await renderer.destroy()
|
|
52
|
+
process.exit(1) // Only after destroy
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// BETTER - Let destroy handle exit
|
|
56
|
+
const renderer = await createCliRenderer({
|
|
57
|
+
exitOnCtrlC: true, // Handles Ctrl+C properly
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// For programmatic exit
|
|
61
|
+
renderer.destroy() // Cleans up and exits
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`renderer.destroy()` restores the terminal to its original state before exiting.
|
|
65
|
+
|
|
66
|
+
### Environment Variables
|
|
67
|
+
|
|
68
|
+
Bun auto-loads `.env` files. Don't use dotenv:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// CORRECT
|
|
72
|
+
const apiKey = process.env.API_KEY
|
|
73
|
+
|
|
74
|
+
// WRONG
|
|
75
|
+
import dotenv from "dotenv"
|
|
76
|
+
dotenv.config()
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Debugging TUIs
|
|
80
|
+
|
|
81
|
+
### Cannot See console.log Output
|
|
82
|
+
|
|
83
|
+
OpenTUI captures console output for the debug overlay. You can't see logs in the terminal while the TUI is running.
|
|
84
|
+
|
|
85
|
+
**Solutions:**
|
|
86
|
+
|
|
87
|
+
1. **Use the console overlay:**
|
|
88
|
+
```typescript
|
|
89
|
+
const renderer = await createCliRenderer()
|
|
90
|
+
renderer.console.show()
|
|
91
|
+
console.log("This appears in the overlay")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
2. **Toggle with keyboard:**
|
|
95
|
+
```typescript
|
|
96
|
+
renderer.keyInput.on("keypress", (key) => {
|
|
97
|
+
if (key.name === "f12") {
|
|
98
|
+
renderer.console.toggle()
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
3. **Write to a file:**
|
|
104
|
+
```typescript
|
|
105
|
+
import { appendFileSync } from "node:fs"
|
|
106
|
+
function debugLog(msg: string) {
|
|
107
|
+
appendFileSync("debug.log", `${new Date().toISOString()} ${msg}\n`)
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
4. **Disable console capture:**
|
|
112
|
+
```bash
|
|
113
|
+
OTUI_USE_CONSOLE=false bun run src/index.ts
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Reproduce Issues in Tests
|
|
117
|
+
|
|
118
|
+
Don't guess at bugs. Create a reproducible test:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { test, expect } from "bun:test"
|
|
122
|
+
import { createTestRenderer } from "@opentui/core/testing"
|
|
123
|
+
|
|
124
|
+
test("reproduces the issue", async () => {
|
|
125
|
+
const { renderer, snapshot } = await createTestRenderer({
|
|
126
|
+
width: 40,
|
|
127
|
+
height: 10,
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
// Setup that reproduces the bug
|
|
131
|
+
const box = new BoxRenderable(renderer, { ... })
|
|
132
|
+
renderer.root.add(box)
|
|
133
|
+
|
|
134
|
+
// Verify with snapshot
|
|
135
|
+
expect(snapshot()).toMatchSnapshot()
|
|
136
|
+
})
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Focus Management
|
|
140
|
+
|
|
141
|
+
### Components Must Be Focused
|
|
142
|
+
|
|
143
|
+
Input components only receive keyboard input when focused:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const input = new InputRenderable(renderer, {
|
|
147
|
+
id: "input",
|
|
148
|
+
placeholder: "Type here...",
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
renderer.root.add(input)
|
|
152
|
+
|
|
153
|
+
// WRONG - input won't receive keystrokes
|
|
154
|
+
// (no focus call)
|
|
155
|
+
|
|
156
|
+
// CORRECT
|
|
157
|
+
input.focus()
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Focus in Nested Components
|
|
161
|
+
|
|
162
|
+
When a component is inside a container, focus the component directly:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
const container = new BoxRenderable(renderer, { id: "container" })
|
|
166
|
+
const input = new InputRenderable(renderer, { id: "input" })
|
|
167
|
+
container.add(input)
|
|
168
|
+
renderer.root.add(container)
|
|
169
|
+
|
|
170
|
+
// WRONG
|
|
171
|
+
container.focus()
|
|
172
|
+
|
|
173
|
+
// CORRECT
|
|
174
|
+
input.focus()
|
|
175
|
+
|
|
176
|
+
// Or use getRenderable
|
|
177
|
+
container.getRenderable("input")?.focus()
|
|
178
|
+
|
|
179
|
+
// Or use delegate (constructs)
|
|
180
|
+
const form = delegate(
|
|
181
|
+
{ focus: "input" },
|
|
182
|
+
Box({}, Input({ id: "input" })),
|
|
183
|
+
)
|
|
184
|
+
form.focus() // Routes to the input
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Build Requirements
|
|
188
|
+
|
|
189
|
+
### Zig is Required
|
|
190
|
+
|
|
191
|
+
Native code compilation requires Zig:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Install Zig first
|
|
195
|
+
# macOS
|
|
196
|
+
brew install zig
|
|
197
|
+
|
|
198
|
+
# Linux
|
|
199
|
+
# Download from https://ziglang.org/download/
|
|
200
|
+
|
|
201
|
+
# Then build
|
|
202
|
+
bun run build
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### When to Build
|
|
206
|
+
|
|
207
|
+
- **TypeScript changes**: NO build needed (Bun runs TS directly)
|
|
208
|
+
- **Native code changes**: Build required
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
# Only needed when changing native (Zig) code
|
|
212
|
+
cd packages/core
|
|
213
|
+
bun run build
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Common Errors
|
|
217
|
+
|
|
218
|
+
### "Cannot read properties of undefined"
|
|
219
|
+
|
|
220
|
+
Usually means a renderable wasn't added to the tree:
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
// WRONG - not added to tree
|
|
224
|
+
const text = new TextRenderable(renderer, { content: "Hello" })
|
|
225
|
+
// text.someMethod() // May fail
|
|
226
|
+
|
|
227
|
+
// CORRECT
|
|
228
|
+
const text = new TextRenderable(renderer, { content: "Hello" })
|
|
229
|
+
renderer.root.add(text)
|
|
230
|
+
text.someMethod()
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Layout Not Updating
|
|
234
|
+
|
|
235
|
+
Yoga layout is calculated lazily. Force a recalculation:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// After changing layout properties
|
|
239
|
+
box.setWidth(newWidth)
|
|
240
|
+
renderer.requestRender()
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Text Overflow/Clipping
|
|
244
|
+
|
|
245
|
+
Text doesn't wrap by default. Set explicit width:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// May overflow
|
|
249
|
+
const text = new TextRenderable(renderer, {
|
|
250
|
+
content: "Very long text that might overflow the terminal...",
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
// Contained within width
|
|
254
|
+
const text = new TextRenderable(renderer, {
|
|
255
|
+
content: "Very long text that might overflow the terminal...",
|
|
256
|
+
width: 40, // Will clip or wrap based on parent
|
|
257
|
+
})
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Colors Not Showing
|
|
261
|
+
|
|
262
|
+
Check terminal capability and color format:
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
// CORRECT formats
|
|
266
|
+
fg: "#FF0000" // Hex
|
|
267
|
+
fg: "red" // CSS color name
|
|
268
|
+
fg: RGBA.fromHex("#FF0000")
|
|
269
|
+
|
|
270
|
+
// WRONG
|
|
271
|
+
fg: "FF0000" // Missing #
|
|
272
|
+
fg: 0xFF0000 // Number (not supported)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Performance
|
|
276
|
+
|
|
277
|
+
### Avoid Frequent Re-renders
|
|
278
|
+
|
|
279
|
+
Batch updates when possible:
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
// WRONG - multiple render calls
|
|
283
|
+
item1.setContent("...")
|
|
284
|
+
item2.setContent("...")
|
|
285
|
+
item3.setContent("...")
|
|
286
|
+
|
|
287
|
+
// BETTER - single render after all updates
|
|
288
|
+
// (OpenTUI batches automatically, but be mindful)
|
|
289
|
+
items.forEach((item, i) => {
|
|
290
|
+
item.setContent(data[i])
|
|
291
|
+
})
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Minimize Tree Depth
|
|
295
|
+
|
|
296
|
+
Deep nesting impacts layout calculation:
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
// Avoid unnecessary wrappers
|
|
300
|
+
// WRONG
|
|
301
|
+
Box({}, Box({}, Box({}, Text({ content: "Hello" }))))
|
|
302
|
+
|
|
303
|
+
// CORRECT
|
|
304
|
+
Box({}, Text({ content: "Hello" }))
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Use display: none
|
|
308
|
+
|
|
309
|
+
Hide elements instead of removing/re-adding:
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
// For toggling visibility
|
|
313
|
+
element.setDisplay("none") // Hidden
|
|
314
|
+
element.setDisplay("flex") // Visible
|
|
315
|
+
|
|
316
|
+
// Instead of
|
|
317
|
+
parent.remove(element)
|
|
318
|
+
parent.add(element)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Testing
|
|
322
|
+
|
|
323
|
+
### Test Runner
|
|
324
|
+
|
|
325
|
+
Use Bun's test runner:
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
import { test, expect, beforeEach, afterEach } from "bun:test"
|
|
329
|
+
|
|
330
|
+
test("my test", () => {
|
|
331
|
+
expect(1 + 1).toBe(2)
|
|
332
|
+
})
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Test from Package Directories
|
|
336
|
+
|
|
337
|
+
Run tests from the specific package directory:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
# CORRECT
|
|
341
|
+
cd packages/core
|
|
342
|
+
bun test
|
|
343
|
+
|
|
344
|
+
# For native tests
|
|
345
|
+
cd packages/core
|
|
346
|
+
bun run test:native
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Filter Tests
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
# Bun test filter
|
|
353
|
+
bun test --filter "component name"
|
|
354
|
+
|
|
355
|
+
# Native test filter
|
|
356
|
+
bun run test:native -Dtest-filter="test name"
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Keyboard Handling
|
|
360
|
+
|
|
361
|
+
### Key Names
|
|
362
|
+
|
|
363
|
+
Common key names for `KeyEvent.name`:
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
// Letters/numbers
|
|
367
|
+
"a", "b", ..., "z"
|
|
368
|
+
"1", "2", ..., "0"
|
|
369
|
+
|
|
370
|
+
// Special keys
|
|
371
|
+
"escape", "enter", "return", "tab", "backspace", "delete"
|
|
372
|
+
"up", "down", "left", "right"
|
|
373
|
+
"home", "end", "pageup", "pagedown"
|
|
374
|
+
"f1", "f2", ..., "f12"
|
|
375
|
+
"space"
|
|
376
|
+
|
|
377
|
+
// Modifiers (check boolean properties)
|
|
378
|
+
key.ctrl // Ctrl held
|
|
379
|
+
key.shift // Shift held
|
|
380
|
+
key.meta // Alt held
|
|
381
|
+
key.option // Option held (macOS)
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Key Event Types
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
renderer.keyInput.on("keypress", (key) => {
|
|
388
|
+
// eventType: "press" | "release" | "repeat"
|
|
389
|
+
if (key.eventType === "repeat") {
|
|
390
|
+
// Key being held down
|
|
391
|
+
}
|
|
392
|
+
})
|
|
393
|
+
```
|