termcast 1.3.54 → 1.4.1

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.
Files changed (170) hide show
  1. package/dist/action-utils.d.ts.map +1 -1
  2. package/dist/action-utils.js +17 -132
  3. package/dist/action-utils.js.map +1 -1
  4. package/dist/apis/cache.d.ts +8 -30
  5. package/dist/apis/cache.d.ts.map +1 -1
  6. package/dist/apis/cache.js +9 -271
  7. package/dist/apis/cache.js.map +1 -1
  8. package/dist/apis/clipboard.d.ts +4 -2
  9. package/dist/apis/clipboard.d.ts.map +1 -1
  10. package/dist/apis/clipboard.js +18 -31
  11. package/dist/apis/clipboard.js.map +1 -1
  12. package/dist/apis/environment.d.ts.map +1 -1
  13. package/dist/apis/environment.js +14 -49
  14. package/dist/apis/environment.js.map +1 -1
  15. package/dist/apis/localstorage.d.ts +7 -12
  16. package/dist/apis/localstorage.d.ts.map +1 -1
  17. package/dist/apis/localstorage.js +7 -184
  18. package/dist/apis/localstorage.js.map +1 -1
  19. package/dist/app.d.ts.map +1 -1
  20. package/dist/app.js +16 -15
  21. package/dist/app.js.map +1 -1
  22. package/dist/cli.js +7 -6
  23. package/dist/cli.js.map +1 -1
  24. package/dist/components/actions.d.ts.map +1 -1
  25. package/dist/components/actions.js +13 -2
  26. package/dist/components/actions.js.map +1 -1
  27. package/dist/components/extension-preferences.d.ts.map +1 -1
  28. package/dist/components/extension-preferences.js +7 -8
  29. package/dist/components/extension-preferences.js.map +1 -1
  30. package/dist/components/form/file-autocomplete.js +2 -2
  31. package/dist/components/form/file-autocomplete.js.map +1 -1
  32. package/dist/components/list.d.ts.map +1 -1
  33. package/dist/components/list.js +242 -14
  34. package/dist/components/list.js.map +1 -1
  35. package/dist/e2e-node.d.ts.map +1 -1
  36. package/dist/e2e-node.js +5 -4
  37. package/dist/e2e-node.js.map +1 -1
  38. package/dist/extensions/dev.d.ts.map +1 -1
  39. package/dist/extensions/dev.js +5 -2
  40. package/dist/extensions/dev.js.map +1 -1
  41. package/dist/globals.d.ts.map +1 -1
  42. package/dist/globals.js +2 -1
  43. package/dist/globals.js.map +1 -1
  44. package/dist/internal/error-handler.d.ts.map +1 -1
  45. package/dist/internal/error-handler.js +21 -19
  46. package/dist/internal/error-handler.js.map +1 -1
  47. package/dist/internal/providers.d.ts.map +1 -1
  48. package/dist/internal/providers.js +41 -1
  49. package/dist/internal/providers.js.map +1 -1
  50. package/dist/logger.d.ts.map +1 -1
  51. package/dist/logger.js +40 -29
  52. package/dist/logger.js.map +1 -1
  53. package/dist/platform/browser/cache.d.ts +41 -0
  54. package/dist/platform/browser/cache.d.ts.map +1 -0
  55. package/dist/platform/browser/cache.js +262 -0
  56. package/dist/platform/browser/cache.js.map +1 -0
  57. package/dist/platform/browser/localstorage.d.ts +20 -0
  58. package/dist/platform/browser/localstorage.d.ts.map +1 -0
  59. package/dist/platform/browser/localstorage.js +102 -0
  60. package/dist/platform/browser/localstorage.js.map +1 -0
  61. package/dist/platform/browser/runtime.d.ts +51 -0
  62. package/dist/platform/browser/runtime.d.ts.map +1 -0
  63. package/dist/platform/browser/runtime.js +164 -0
  64. package/dist/platform/browser/runtime.js.map +1 -0
  65. package/dist/platform/bun/sqlite.d.ts +17 -0
  66. package/dist/platform/bun/sqlite.d.ts.map +1 -0
  67. package/dist/platform/bun/sqlite.js +6 -0
  68. package/dist/platform/bun/sqlite.js.map +1 -0
  69. package/dist/platform/node/cache.d.ts +35 -0
  70. package/dist/platform/node/cache.d.ts.map +1 -0
  71. package/dist/platform/node/cache.js +269 -0
  72. package/dist/platform/node/cache.js.map +1 -0
  73. package/dist/platform/node/localstorage.d.ts +17 -0
  74. package/dist/platform/node/localstorage.d.ts.map +1 -0
  75. package/dist/platform/node/localstorage.js +186 -0
  76. package/dist/platform/node/localstorage.js.map +1 -0
  77. package/dist/platform/node/runtime.d.ts +52 -0
  78. package/dist/platform/node/runtime.d.ts.map +1 -0
  79. package/dist/platform/node/runtime.js +230 -0
  80. package/dist/platform/node/runtime.js.map +1 -0
  81. package/dist/platform/node/sqlite.d.ts +27 -0
  82. package/dist/platform/node/sqlite.d.ts.map +1 -0
  83. package/dist/platform/node/sqlite.js +21 -0
  84. package/dist/platform/node/sqlite.js.map +1 -0
  85. package/dist/state.d.ts +5 -0
  86. package/dist/state.d.ts.map +1 -1
  87. package/dist/state.js +6 -28
  88. package/dist/state.js.map +1 -1
  89. package/dist/utils/file-system.d.ts.map +1 -1
  90. package/dist/utils/file-system.js +17 -22
  91. package/dist/utils/file-system.js.map +1 -1
  92. package/dist/utils.d.ts +1 -1
  93. package/dist/utils.d.ts.map +1 -1
  94. package/dist/utils.js +42 -47
  95. package/dist/utils.js.map +1 -1
  96. package/dist/vim-mode.d.ts +40 -0
  97. package/dist/vim-mode.d.ts.map +1 -0
  98. package/dist/vim-mode.js +135 -0
  99. package/dist/vim-mode.js.map +1 -0
  100. package/fonts/Inconsolata.otf +0 -0
  101. package/fonts/SIL Open Font License.txt +41 -0
  102. package/package.json +62 -10
  103. package/src/action-utils.tsx +27 -124
  104. package/src/apis/cache.test.ts +1 -1
  105. package/src/apis/cache.tsx +9 -373
  106. package/src/apis/clipboard.tsx +29 -38
  107. package/src/apis/environment.tsx +25 -52
  108. package/src/apis/localstorage.tsx +8 -214
  109. package/src/app.tsx +16 -15
  110. package/src/cli.tsx +14 -15
  111. package/src/compile.vitest.tsx +2 -2
  112. package/src/components/actions.tsx +19 -1
  113. package/src/components/extension-preferences.tsx +7 -8
  114. package/src/components/form/file-autocomplete.tsx +2 -2
  115. package/src/components/list.tsx +279 -14
  116. package/src/e2e-node.tsx +7 -7
  117. package/src/examples/action-shortcut.vitest.tsx +2 -2
  118. package/src/examples/actions-context.vitest.tsx +1 -1
  119. package/src/examples/bar-graph-weekly.vitest.tsx +10 -36
  120. package/src/examples/detail-metadata-showcase.vitest.tsx +37 -42
  121. package/src/examples/form-basic.vitest.tsx +45 -41
  122. package/src/examples/github.vitest.tsx +4 -4
  123. package/src/examples/graph-bar-chart.vitest.tsx +13 -11
  124. package/src/examples/graph-polymarket.vitest.tsx +2 -2
  125. package/src/examples/graph-row.vitest.tsx +66 -66
  126. package/src/examples/graph-styles.vitest.tsx +12 -12
  127. package/src/examples/internal/simple-scrollbox.vitest.tsx +14 -48
  128. package/src/examples/list-detail-metadata.vitest.tsx +5 -5
  129. package/src/examples/list-fetch-data.vitest.tsx +3 -3
  130. package/src/examples/list-item-accessories.vitest.tsx +2 -2
  131. package/src/examples/list-loading-empty-view.vitest.tsx +1 -1
  132. package/src/examples/list-no-actions.vitest.tsx +2 -2
  133. package/src/examples/list-scrollbox.vitest.tsx +5 -5
  134. package/src/examples/list-spacing-mode.vitest.tsx +3 -3
  135. package/src/examples/list-with-detail.vitest.tsx +68 -68
  136. package/src/examples/list-with-dropdown.vitest.tsx +5 -5
  137. package/src/examples/list-with-sections.vitest.tsx +27 -27
  138. package/src/examples/simple-candle-chart.vitest.tsx +7 -7
  139. package/src/examples/simple-detail-markdown.vitest.tsx +8 -8
  140. package/src/examples/simple-detail-table.vitest.tsx +8 -8
  141. package/src/examples/simple-graph.vitest.tsx +3 -3
  142. package/src/examples/simple-grid.vitest.tsx +14 -14
  143. package/src/examples/simple-heatmap.vitest.tsx +10 -10
  144. package/src/examples/simple-navigation.vitest.tsx +17 -17
  145. package/src/examples/simple-progress-bar.vitest.tsx +1 -1
  146. package/src/examples/store.vitest.tsx +1 -1
  147. package/src/examples/swift-extension.vitest.tsx +2 -2
  148. package/src/examples/table-edge-cases.vitest.tsx +18 -18
  149. package/src/examples/toast-action.vitest.tsx +2 -2
  150. package/src/examples/toast-variations.vitest.tsx +5 -5
  151. package/src/extensions/dev.tsx +5 -2
  152. package/src/extensions/dev.vitest.tsx +3 -3
  153. package/src/globals.ts +2 -1
  154. package/src/internal/error-handler.tsx +19 -21
  155. package/src/internal/providers.tsx +39 -0
  156. package/src/logger.tsx +48 -41
  157. package/src/platform/browser/cache.ts +327 -0
  158. package/src/platform/browser/localstorage.ts +119 -0
  159. package/src/platform/browser/runtime.ts +209 -0
  160. package/src/platform/bun/sqlite.ts +19 -0
  161. package/src/platform/node/cache.ts +372 -0
  162. package/src/platform/node/localstorage.ts +214 -0
  163. package/src/platform/node/runtime.ts +264 -0
  164. package/src/platform/node/sqlite.ts +43 -0
  165. package/src/state.tsx +17 -28
  166. package/src/utils/file-system.ts +17 -22
  167. package/src/utils.test.tsx +1 -1
  168. package/src/utils.tsx +56 -47
  169. package/src/vim-mode.tsx +153 -0
  170. package/src/apis/sqlite.ts +0 -14
@@ -46,7 +46,7 @@ test('navigation between main and detail views', async () => {
46
46
 
47
47
 
48
48
 
49
- ↵ open details ↑↓ navigate ^k actions
49
+ ↵ open details ↑↓ navigate ^k actions :vim
50
50
 
51
51
 
52
52
 
@@ -80,7 +80,7 @@ test('navigation between main and detail views', async () => {
80
80
 
81
81
 
82
82
 
83
- ↵ open details ↑↓ navigate ^k actions
83
+ ↵ open details ↑↓ navigate ^k actions :vim
84
84
 
85
85
 
86
86
 
@@ -118,7 +118,7 @@ test('navigation between main and detail views', async () => {
118
118
 
119
119
 
120
120
 
121
- ↵ go back ↑↓ navigate ^k actions
121
+ ↵ go back ↑↓ navigate ^k actions :vim
122
122
 
123
123
 
124
124
 
@@ -160,7 +160,7 @@ test('navigation between main and detail views', async () => {
160
160
 
161
161
 
162
162
 
163
- ↵ open details ↑↓ navigate ^k actions
163
+ ↵ open details ↑↓ navigate ^k actions :vim
164
164
 
165
165
 
166
166
 
@@ -194,7 +194,7 @@ test('navigation between main and detail views', async () => {
194
194
 
195
195
 
196
196
 
197
- ↵ open details ↑↓ navigate ^k actions
197
+ ↵ open details ↑↓ navigate ^k actions :vim
198
198
 
199
199
 
200
200
 
@@ -227,7 +227,7 @@ test('navigation between main and detail views', async () => {
227
227
 
228
228
 
229
229
 
230
- ↵ go back ↑↓ navigate ^k actions
230
+ ↵ go back ↑↓ navigate ^k actions :vim
231
231
 
232
232
 
233
233
 
@@ -266,7 +266,7 @@ test('navigation between main and detail views', async () => {
266
266
 
267
267
 
268
268
 
269
- ↵ open details ↑↓ navigate ^k actions
269
+ ↵ open details ↑↓ navigate ^k actions :vim
270
270
 
271
271
 
272
272
 
@@ -306,12 +306,12 @@ test('navigation with actions panel', async () => {
306
306
  │ │
307
307
  │ Settings │
308
308
  │ Change Theme... │
309
+ │ Enable Vim Mode │
309
310
  │ Toggle Console Logs │
310
311
  │ │
311
312
  │ │
312
313
  │ │
313
314
  │ │
314
- │ │
315
315
  │ ↵ select ↑↓ navigate │
316
316
  │ │
317
317
  ╰────────────────────────────────────────────────────────────────╯
@@ -339,12 +339,12 @@ test('navigation with actions panel', async () => {
339
339
  │ │
340
340
  │ Settings │
341
341
  │ Change Theme... │
342
+ │ Enable Vim Mode │
342
343
  │ Toggle Console Logs │
343
344
  │ │
344
345
  │ │
345
346
  │ │
346
347
  │ │
347
- │ │
348
348
  │ ↵ select ↑↓ navigate │
349
349
  │ │
350
350
  ╰────────────────────────────────────────────────────────────────╯
@@ -419,7 +419,7 @@ test('navigation with actions panel', async () => {
419
419
 
420
420
 
421
421
 
422
- ↵ go back ↑↓ navigate ^k actions
422
+ ↵ go back ↑↓ navigate ^k actions :vim
423
423
 
424
424
 
425
425
 
@@ -450,12 +450,12 @@ test('navigation with actions panel', async () => {
450
450
  │ │
451
451
  │ Settings │
452
452
  │ Change Theme... │
453
+ │ Enable Vim Mode │
453
454
  │ Toggle Console Logs │
454
455
  │ │
455
456
  │ │
456
457
  │ │
457
458
  │ │
458
- │ │
459
459
  │ ↵ select ↑↓ navigate │
460
460
  │ │
461
461
  ╰────────────────────────────────────────────────────────────────╯
@@ -489,7 +489,7 @@ test('navigation with actions panel', async () => {
489
489
 
490
490
 
491
491
 
492
- ↵ open details ↑↓ navigate ^k actions
492
+ ↵ open details ↑↓ navigate ^k actions :vim
493
493
 
494
494
 
495
495
 
@@ -535,7 +535,7 @@ test('search functionality in main and detail views', async () => {
535
535
 
536
536
 
537
537
 
538
- ↵ open details ↑↓ navigate ^k actions
538
+ ↵ open details ↑↓ navigate ^k actions :vim
539
539
 
540
540
 
541
541
 
@@ -573,7 +573,7 @@ test('search functionality in main and detail views', async () => {
573
573
 
574
574
 
575
575
 
576
- ↵ open details ↑↓ navigate ^k actions
576
+ ↵ open details ↑↓ navigate ^k actions :vim
577
577
 
578
578
 
579
579
 
@@ -613,7 +613,7 @@ test('search functionality in main and detail views', async () => {
613
613
 
614
614
 
615
615
 
616
- ↵ go back ↑↓ navigate ^k actions
616
+ ↵ go back ↑↓ navigate ^k actions :vim
617
617
 
618
618
 
619
619
 
@@ -650,7 +650,7 @@ test('search functionality in main and detail views', async () => {
650
650
 
651
651
 
652
652
 
653
- ↵ go back ↑↓ navigate ^k actions
653
+ ↵ go back ↑↓ navigate ^k actions :vim
654
654
 
655
655
 
656
656
 
@@ -687,7 +687,7 @@ test('search functionality in main and detail views', async () => {
687
687
 
688
688
 
689
689
 
690
- ↵ open details ↑↓ navigate ^k actions
690
+ ↵ open details ↑↓ navigate ^k actions :vim
691
691
 
692
692
 
693
693
 
@@ -43,7 +43,7 @@ test('progress bars render in detail metadata and update on selection', async ()
43
43
  │ ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ 7% used
44
44
  │ Resets Feb 27, 1pm (Asia/Bangkok)
45
45
 
46
- ↑↓ navigate ^k actions
46
+ ↑↓ navigate ^k actions :vim
47
47
 
48
48
 
49
49
 
@@ -58,7 +58,7 @@ test('Store extension - searching for spiceblow shows Database', async () => {
58
58
 
59
59
 
60
60
 
61
- ↵ view details ↑↓ navigate ^k actions powered by termcast.app
61
+ ↵ view details ↑↓ navigate ^k actions :vim powered by termcast.app
62
62
 
63
63
 
64
64
 
@@ -102,7 +102,7 @@ test.skipIf(isLinux)('swift extension dev mode shows command list', async () =>
102
102
 
103
103
 
104
104
 
105
- ↵ run command ↑↓ navigate ^k actions
105
+ ↵ run command ↑↓ navigate ^k actions :vim
106
106
 
107
107
 
108
108
 
@@ -153,7 +153,7 @@ test.skipIf(isLinux)('swift extension runs Swift List command and shows items',
153
153
 
154
154
 
155
155
 
156
- ↑↓ navigate ^k actions
156
+ ↑↓ navigate ^k actions :vim
157
157
 
158
158
 
159
159
 
@@ -35,8 +35,10 @@ test('inline formatting table renders all rows', async () => {
35
35
 
36
36
  Table Edge Cases
37
37
 
38
+
38
39
  Inline Formatting
39
40
 
41
+
40
42
  Feature Syntax Result
41
43
  Bold text bold text
42
44
  Italic text italic text
@@ -46,6 +48,7 @@ test('inline formatting table renders all rows', async () => {
46
48
 
47
49
  Single Column
48
50
 
51
+
49
52
  Name
50
53
  Alice
51
54
  Bob
@@ -53,11 +56,13 @@ test('inline formatting table renders all rows', async () => {
53
56
 
54
57
  Single Row
55
58
 
59
+
56
60
  A B C D E
57
61
  1 2 3 4 5
58
62
 
59
63
  Empty Cells
60
64
 
65
+
61
66
  Key Value Notes
62
67
  host localhost
63
68
  8080 default port
@@ -65,12 +70,14 @@ test('inline formatting table renders all rows', async () => {
65
70
 
66
71
  Wide Table
67
72
 
73
+
68
74
  ID Name Email Role Department Location
69
75
  1 Alice Johnson alice@example.com Engineer Engineering SF
70
76
  2 Bob Smith bob@example.com Designer Design NYC
71
77
 
72
78
  Two Columns
73
79
 
80
+
74
81
  Key Value
75
82
  version 2.1.0
76
83
  license MIT
@@ -78,6 +85,7 @@ test('inline formatting table renders all rows', async () => {
78
85
 
79
86
  Numeric Data
80
87
 
88
+
81
89
  Metric Q1 Q2 Q3 Q4
82
90
  Revenue 100 150 200 250
83
91
  Users 1000 1500 2000 3000
@@ -86,16 +94,8 @@ test('inline formatting table renders all rows', async () => {
86
94
  Done.
87
95
 
88
96
 
89
- esc go back ^k actions powered by termcast.app
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
97
 
98
+ esc go back ^k actions powered by termcast.app
99
99
 
100
100
 
101
101
 
@@ -219,8 +219,10 @@ test('all tables render without crash - full page snapshot', async () => {
219
219
 
220
220
  Table Edge Cases
221
221
 
222
+
222
223
  Inline Formatting
223
224
 
225
+
224
226
  Feature Syntax Result
225
227
  Bold text bold text
226
228
  Italic text italic text
@@ -230,6 +232,7 @@ test('all tables render without crash - full page snapshot', async () => {
230
232
 
231
233
  Single Column
232
234
 
235
+
233
236
  Name
234
237
  Alice
235
238
  Bob
@@ -237,11 +240,13 @@ test('all tables render without crash - full page snapshot', async () => {
237
240
 
238
241
  Single Row
239
242
 
243
+
240
244
  A B C D E
241
245
  1 2 3 4 5
242
246
 
243
247
  Empty Cells
244
248
 
249
+
245
250
  Key Value Notes
246
251
  host localhost
247
252
  8080 default port
@@ -249,12 +254,14 @@ test('all tables render without crash - full page snapshot', async () => {
249
254
 
250
255
  Wide Table
251
256
 
257
+
252
258
  ID Name Email Role Department Location
253
259
  1 Alice Johnson alice@example.com Engineer Engineering SF
254
260
  2 Bob Smith bob@example.com Designer Design NYC
255
261
 
256
262
  Two Columns
257
263
 
264
+
258
265
  Key Value
259
266
  version 2.1.0
260
267
  license MIT
@@ -262,6 +269,7 @@ test('all tables render without crash - full page snapshot', async () => {
262
269
 
263
270
  Numeric Data
264
271
 
272
+
265
273
  Metric Q1 Q2 Q3 Q4
266
274
  Revenue 100 150 200 250
267
275
  Users 1000 1500 2000 3000
@@ -270,16 +278,8 @@ test('all tables render without crash - full page snapshot', async () => {
270
278
  Done.
271
279
 
272
280
 
273
- esc go back ^k actions powered by termcast.app
274
-
275
-
276
-
277
-
278
-
279
-
280
-
281
-
282
281
 
282
+ esc go back ^k actions powered by termcast.app
283
283
 
284
284
 
285
285
 
@@ -124,7 +124,7 @@ test('pressing escape hides the toast', async () => {
124
124
 
125
125
 
126
126
 
127
- ↵ show toast ↑↓ navigate ^k actions
127
+ ↵ show toast ↑↓ navigate ^k actions :vim
128
128
 
129
129
 
130
130
 
@@ -238,7 +238,7 @@ test('form toast: pressing enter triggers primary action (navigation)', async ()
238
238
 
239
239
 
240
240
 
241
- ↑↓ navigate ^k actions
241
+ ↑↓ navigate ^k actions :vim
242
242
 
243
243
 
244
244
 
@@ -137,7 +137,7 @@ test('toast variations display correctly', async () => {
137
137
  Error with Retry
138
138
 
139
139
 
140
- ✗ Error This is a very long error message that should wrap to multiple line
140
+ ✗ Error This is a very long error message that should wrap to multiple li
141
141
  "
142
142
  `)
143
143
 
@@ -167,7 +167,7 @@ test('toast variations display correctly', async () => {
167
167
  Error with Retry
168
168
 
169
169
 
170
- ✗ Warning Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do e
170
+ ✗ Warning Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
171
171
  "
172
172
  `)
173
173
 
@@ -227,7 +227,7 @@ test('toast variations display correctly', async () => {
227
227
  Error with Retry
228
228
 
229
229
 
230
- ✓ Update Available Version 2.0 is ready to install Install ctrl t Later ct
230
+ ✓ Update Available Version 2.0 is ready to ins Install ctrl t Later ctrl g
231
231
  "
232
232
  `)
233
233
 
@@ -257,7 +257,7 @@ test('toast variations display correctly', async () => {
257
257
  Error with Retry
258
258
 
259
259
 
260
- ✓ Operation Completed Successfully All files have been processed View Resu
260
+ ✓ Operation Completed Successfully All View Results ctrl t Dismiss ctrl g
261
261
  "
262
262
  `)
263
263
 
@@ -319,7 +319,7 @@ test('toast variations display correctly', async () => {
319
319
  ›Error with Retry
320
320
 
321
321
 
322
- ✗ Connection Failed Unable to connect to the server. Please check your inte
322
+ ✗ Connection Failed Unable to connect to the server. Please c Retry ctrl t
323
323
  "
324
324
  `)
325
325
  }, 30000)
@@ -15,6 +15,7 @@ import { TermcastProvider } from 'termcast/src/internal/providers'
15
15
  import { showToast, Toast } from 'termcast/src/apis/toast'
16
16
  import { Icon } from 'termcast'
17
17
  import { useTheme, initializeTheme } from 'termcast/src/theme'
18
+ import { initializeVimMode } from 'termcast/src/vim-mode'
18
19
  import { logger } from '../logger'
19
20
  import { getCommandsWithFiles, CommandWithFile, RaycastPackageJson } from '../package-json'
20
21
  import { buildExtensionCommands } from '../build'
@@ -226,8 +227,9 @@ export async function startDevMode({
226
227
  devRebuildCount: 1,
227
228
  })
228
229
 
229
- // Load theme after state reset — extensionPath is now set so it reads from the correct DB
230
+ // Load theme and vim mode after state reset — extensionPath is now set so it reads from the correct DB
230
231
  initializeTheme()
232
+ initializeVimMode()
231
233
 
232
234
  function App(): any {
233
235
  const devElement = useStore((state) => state.devElement)
@@ -299,8 +301,9 @@ export async function startCompiledExtension({
299
301
  devRebuildCount: 1,
300
302
  })
301
303
 
302
- // Load theme after state reset — extensionPath is now set so it reads from the correct DB
304
+ // Load theme and vim mode after state reset — extensionPath is now set so it reads from the correct DB
303
305
  initializeTheme()
306
+ initializeVimMode()
304
307
 
305
308
  function App(): any {
306
309
  const devElement = useStore((state) => state.devElement)
@@ -65,7 +65,7 @@ test('dev command shows extension commands list', async () => {
65
65
  Show State Shows the current application state in view
66
66
 
67
67
 
68
- ↵ run command ↑↓ navigate ^k actions
68
+ ↵ run command ↑↓ navigate ^k actions :vim
69
69
  "
70
70
  `)
71
71
  }, 30000)
@@ -101,7 +101,7 @@ test('selecting command with arguments shows arguments form', async () => {
101
101
 
102
102
 
103
103
 
104
- ↵ run command ↑↓ navigate ^k actions
104
+ ↵ run command ↑↓ navigate ^k actions :vim
105
105
  "
106
106
  `)
107
107
 
@@ -217,7 +217,7 @@ test('can fill arguments and run command', async () => {
217
217
 
218
218
 
219
219
 
220
- ↵ copy value ↑↓ navigate ^k actions
220
+ ↵ copy value ↑↓ navigate ^k actions :vim
221
221
  "
222
222
  `)
223
223
  }, 30000)
package/src/globals.ts CHANGED
@@ -2,8 +2,9 @@
2
2
  // Set up global references for external packages
3
3
  //
4
4
  import { logger } from './logger'
5
+ import { setEnv } from '#platform/runtime'
5
6
 
6
- process.env.TERMCAST = 'true'
7
+ setEnv('TERMCAST', 'true')
7
8
 
8
9
  import * as opentuiCore from '@opentui/core'
9
10
  import * as opentuiReact from '@opentui/react'
@@ -1,5 +1,6 @@
1
1
  import { showFailureToast } from 'termcast/src/apis/toast'
2
2
  import { logger } from 'termcast/src/logger'
3
+ import { setupErrorHandlers } from '#platform/runtime'
3
4
 
4
5
  let initialized = false
5
6
 
@@ -7,26 +8,23 @@ export function initializeErrorHandlers(): void {
7
8
  if (initialized) return
8
9
  initialized = true
9
10
 
10
- process.on('unhandledRejection', (reason) => {
11
- const err = reason instanceof Error ? reason : new Error(String(reason))
12
- logger.error('Unhandled rejection:', err)
13
- showFailureToast(err, {
14
- title: 'Unhandled Promise Rejection',
15
- }).catch((toastErr) => {
16
- logger.error('Failed to show toast for unhandled rejection:', toastErr)
17
- })
18
- })
19
-
20
- process.on('uncaughtException', (err) => {
21
- logger.error('Uncaught exception:', err)
22
- showFailureToast(err, {
23
- title: 'Uncaught Exception',
24
- }).catch((toastErr) => {
25
- logger.error('Failed to show toast for uncaught exception:', toastErr)
26
- })
27
- })
28
-
29
- process.on('uncaughtExceptionMonitor', (err, origin) => {
30
- logger.error(`Uncaught exception from ${origin}:`, err)
11
+ setupErrorHandlers((err, type) => {
12
+ if (type === 'unhandledRejection') {
13
+ logger.error('Unhandled rejection:', err)
14
+ showFailureToast(err, {
15
+ title: 'Unhandled Promise Rejection',
16
+ }).catch((toastErr) => {
17
+ logger.error('Failed to show toast for unhandled rejection:', toastErr)
18
+ })
19
+ } else if (type === 'uncaughtException') {
20
+ logger.error('Uncaught exception:', err)
21
+ showFailureToast(err, {
22
+ title: 'Uncaught Exception',
23
+ }).catch((toastErr) => {
24
+ logger.error('Failed to show toast for uncaught exception:', toastErr)
25
+ })
26
+ } else {
27
+ logger.error(`Uncaught exception from ${type}:`, err)
28
+ }
31
29
  })
32
30
  }
@@ -15,6 +15,7 @@ import { useTheme } from 'termcast/src/theme'
15
15
  import { useStore } from 'termcast/src/state'
16
16
  import { useKeyboard, useRenderer } from '@opentui/react'
17
17
  import { initializeErrorHandlers } from 'termcast/src/internal/error-handler'
18
+ import { stdoutWrite } from '#platform/runtime'
18
19
 
19
20
  import { InFocus } from './focus-context'
20
21
  import { Clipboard } from '../apis/clipboard'
@@ -150,6 +151,44 @@ export function TermcastProvider(props: ProvidersProps): any {
150
151
  const theme = useTheme()
151
152
  const renderer = useRenderer()
152
153
 
154
+ // TODO: Remove this when opentui adds { name: "backspace", super: true, action: "delete-to-line-start" }
155
+ // to defaultTextareaKeybindings in packages/core/src/renderables/Textarea.ts
156
+ // Translate Cmd+Backspace (kitty CSI \x1b[127;9u) to Ctrl+U (\x15) so opentui's
157
+ // textarea keybinding for delete-to-line-start handles it. opentui doesn't have a
158
+ // super+backspace binding, so we remap at the input level before key dispatch.
159
+ React.useLayoutEffect(() => {
160
+ if (!renderer) return
161
+ const handler = (sequence: string) => {
162
+ if (sequence === '\x1b[127;9u') {
163
+ renderer.stdin.emit('data', '\x15')
164
+ return true
165
+ }
166
+ return false
167
+ }
168
+ renderer.prependInputHandler(handler)
169
+ return () => {
170
+ renderer.removeInputHandler(handler)
171
+ }
172
+ }, [renderer])
173
+
174
+ // Sync terminal background with the active termcast theme via OSC 11 (standard escape
175
+ // sequence to set terminal background color). This works on WezTerm, iTerm2, kitty, etc.
176
+ // WezTerm's set_config_overrides for colors has a bug (#5451) where it only hot-reloads
177
+ // non-focused windows, so we use OSC 11 instead which updates immediately.
178
+ // Uses renderer's realStdoutWrite to bypass opentui's stdout interception.
179
+ React.useLayoutEffect(() => {
180
+ if (!renderer) return
181
+ // OSC 11 ; color ST — sets terminal default background color
182
+ const sequence = `\x1b]11;${theme.background}\x07`
183
+ const realWrite = (renderer as any).realStdoutWrite as typeof process.stdout.write | undefined
184
+ if (realWrite) {
185
+ // realStdoutWrite needs process.stdout as `this` context
186
+ realWrite.call(process.stdout, sequence)
187
+ } else {
188
+ stdoutWrite(sequence)
189
+ }
190
+ }, [renderer, theme.background])
191
+
153
192
  useKeyboard((key) => {
154
193
  if (!renderer) return
155
194
  if (key.ctrl && key.name === 'd') {