@selesai/code 0.9.14 → 0.10.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.
Files changed (263) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +6 -9
  3. package/dist/defaults/models.json +79 -29
  4. package/dist/defaults/settings.json +3 -7
  5. package/dist/extensions/package.json +3 -4
  6. package/dist/extensions/pi-zentui/.editorconfig +12 -0
  7. package/dist/extensions/pi-zentui/.github/CODEOWNERS +1 -0
  8. package/dist/extensions/pi-zentui/.github/ISSUE_TEMPLATE/bug_report.yml +110 -0
  9. package/dist/extensions/pi-zentui/.github/ISSUE_TEMPLATE/config.yml +8 -0
  10. package/dist/extensions/pi-zentui/.github/ISSUE_TEMPLATE/config_question.yml +56 -0
  11. package/dist/extensions/pi-zentui/.github/ISSUE_TEMPLATE/feature_request.yml +63 -0
  12. package/dist/extensions/pi-zentui/.github/ISSUE_TEMPLATE/rendering_issue.yml +106 -0
  13. package/dist/extensions/pi-zentui/.github/ISSUE_TEMPLATE/runtime_detection.yml +103 -0
  14. package/dist/extensions/pi-zentui/.github/dependabot.yml +47 -0
  15. package/dist/extensions/pi-zentui/.github/pull_request_template.md +34 -0
  16. package/dist/extensions/pi-zentui/.github/release.yml +18 -0
  17. package/dist/extensions/pi-zentui/.github/workflows/ci.yml +79 -0
  18. package/dist/extensions/pi-zentui/.github/workflows/publish.yml +63 -0
  19. package/dist/extensions/pi-zentui/AGENTS.md +107 -0
  20. package/dist/extensions/pi-zentui/CONTRIBUTING.md +68 -0
  21. package/dist/extensions/pi-zentui/LICENSE +21 -0
  22. package/dist/extensions/pi-zentui/README.md +188 -0
  23. package/dist/extensions/pi-zentui/SECURITY.md +18 -0
  24. package/dist/extensions/pi-zentui/assets/main-cover.png +0 -0
  25. package/dist/extensions/pi-zentui/assets/screenshots/editor-accent-rail.png +0 -0
  26. package/dist/extensions/pi-zentui/assets/screenshots/editor-minimalist.png +0 -0
  27. package/dist/extensions/pi-zentui/assets/screenshots/editor-opencode-copy-friendly.png +0 -0
  28. package/dist/extensions/pi-zentui/assets/screenshots/editor-opencode.png +0 -0
  29. package/dist/extensions/pi-zentui/assets/screenshots/user-message-compact.png +0 -0
  30. package/dist/extensions/pi-zentui/assets/screenshots/user-message-framed-copy-friendly.png +0 -0
  31. package/dist/extensions/pi-zentui/assets/screenshots/user-message-framed.png +0 -0
  32. package/dist/extensions/pi-zentui/assets/screenshots/user-message-labeled.png +0 -0
  33. package/dist/extensions/pi-zentui/assets/zentui.png +0 -0
  34. package/dist/extensions/pi-zentui/biome.json +31 -0
  35. package/dist/extensions/pi-zentui/docs/configuration.md +509 -0
  36. package/dist/extensions/pi-zentui/docs/footer-format.md +162 -0
  37. package/dist/extensions/pi-zentui/extensions/zentui/accent-rail-editor.ts +99 -0
  38. package/dist/extensions/pi-zentui/extensions/zentui/accent-rail-layout-patch.ts +457 -0
  39. package/dist/extensions/pi-zentui/extensions/zentui/completion-menu.ts +157 -0
  40. package/dist/extensions/pi-zentui/extensions/zentui/config.ts +2100 -0
  41. package/dist/extensions/pi-zentui/extensions/zentui/editor-metadata-format.ts +321 -0
  42. package/dist/extensions/pi-zentui/extensions/zentui/editor-transfer.ts +73 -0
  43. package/dist/extensions/pi-zentui/extensions/zentui/extension-status.ts +89 -0
  44. package/dist/extensions/pi-zentui/extensions/zentui/footer-format.ts +364 -0
  45. package/dist/extensions/pi-zentui/extensions/zentui/footer-layout.ts +122 -0
  46. package/dist/extensions/pi-zentui/extensions/zentui/footer.ts +812 -0
  47. package/dist/extensions/pi-zentui/extensions/zentui/format.ts +568 -0
  48. package/dist/extensions/pi-zentui/extensions/zentui/git.ts +384 -0
  49. package/dist/extensions/pi-zentui/extensions/zentui/icons.ts +252 -0
  50. package/dist/extensions/pi-zentui/extensions/zentui/index.ts +1406 -0
  51. package/dist/extensions/pi-zentui/extensions/zentui/interaction-summary.ts +1049 -0
  52. package/dist/extensions/pi-zentui/extensions/zentui/live-context.ts +75 -0
  53. package/dist/extensions/pi-zentui/extensions/zentui/minimalist-editor.ts +463 -0
  54. package/dist/extensions/pi-zentui/extensions/zentui/package-version.ts +651 -0
  55. package/dist/extensions/pi-zentui/extensions/zentui/project-refresh.ts +120 -0
  56. package/dist/extensions/pi-zentui/extensions/zentui/project-state.ts +59 -0
  57. package/dist/extensions/pi-zentui/extensions/zentui/prototype-patch-registry.ts +166 -0
  58. package/dist/extensions/pi-zentui/extensions/zentui/repository-root.ts +98 -0
  59. package/dist/extensions/pi-zentui/extensions/zentui/runtime.ts +841 -0
  60. package/dist/extensions/pi-zentui/extensions/zentui/selector-border.ts +93 -0
  61. package/dist/extensions/pi-zentui/extensions/zentui/session-lifecycle.ts +60 -0
  62. package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +1796 -0
  63. package/dist/extensions/pi-zentui/extensions/zentui/settings-previews.ts +128 -0
  64. package/dist/extensions/pi-zentui/extensions/zentui/state.ts +94 -0
  65. package/dist/extensions/pi-zentui/extensions/zentui/style.ts +424 -0
  66. package/dist/extensions/pi-zentui/extensions/zentui/telemetry.ts +82 -0
  67. package/dist/extensions/pi-zentui/extensions/zentui/ui.ts +1290 -0
  68. package/dist/extensions/pi-zentui/extensions/zentui/user-message-osc.ts +248 -0
  69. package/dist/extensions/pi-zentui/extensions/zentui/user-message-styles.ts +215 -0
  70. package/dist/extensions/pi-zentui/extensions/zentui/user-message.ts +206 -0
  71. package/dist/extensions/pi-zentui/extensions/zentui/working-line-messages.ts +24 -0
  72. package/dist/extensions/pi-zentui/extensions/zentui/working-line-spinners.ts +54 -0
  73. package/dist/extensions/pi-zentui/extensions/zentui/working-line.ts +1433 -0
  74. package/dist/extensions/pi-zentui/package-lock.json +5311 -0
  75. package/dist/extensions/pi-zentui/package.json +60 -0
  76. package/dist/extensions/pi-zentui/test/accent-rail-editor.test.ts +232 -0
  77. package/dist/extensions/pi-zentui/test/accent-rail-layout-patch.test.ts +669 -0
  78. package/dist/extensions/pi-zentui/test/completion-menu.test.ts +265 -0
  79. package/dist/extensions/pi-zentui/test/config.test.ts +3119 -0
  80. package/dist/extensions/pi-zentui/test/editor-metadata-format.test.ts +405 -0
  81. package/dist/extensions/pi-zentui/test/editor-transfer.test.ts +260 -0
  82. package/dist/extensions/pi-zentui/test/editor-viewport-indicators.test.ts +1286 -0
  83. package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +7196 -0
  84. package/dist/extensions/pi-zentui/test/extension-status.test.ts +182 -0
  85. package/dist/extensions/pi-zentui/test/fixtures/starship-nerd-font-symbols.toml +172 -0
  86. package/dist/extensions/pi-zentui/test/footer-format.test.ts +431 -0
  87. package/dist/extensions/pi-zentui/test/footer-layout.test.ts +113 -0
  88. package/dist/extensions/pi-zentui/test/footer-repository-path.test.ts +123 -0
  89. package/dist/extensions/pi-zentui/test/format.test.ts +865 -0
  90. package/dist/extensions/pi-zentui/test/git.test.ts +212 -0
  91. package/dist/extensions/pi-zentui/test/icons.test.ts +69 -0
  92. package/dist/extensions/pi-zentui/test/interaction-summary.test.ts +1402 -0
  93. package/dist/extensions/pi-zentui/test/live-context-integration.test.ts +378 -0
  94. package/dist/extensions/pi-zentui/test/live-context.test.ts +139 -0
  95. package/dist/extensions/pi-zentui/test/minimalist-editor.test.ts +811 -0
  96. package/dist/extensions/pi-zentui/test/package-version.test.ts +321 -0
  97. package/dist/extensions/pi-zentui/test/project-refresh.test.ts +250 -0
  98. package/dist/extensions/pi-zentui/test/project-state.test.ts +159 -0
  99. package/dist/extensions/pi-zentui/test/repository-root.test.ts +108 -0
  100. package/dist/extensions/pi-zentui/test/responsive-dependencies.test.ts +825 -0
  101. package/dist/extensions/pi-zentui/test/runtime.test.ts +183 -0
  102. package/dist/extensions/pi-zentui/test/session-lifecycle.test.ts +40 -0
  103. package/dist/extensions/pi-zentui/test/settings-command.test.ts +1381 -0
  104. package/dist/extensions/pi-zentui/test/settings-previews.test.ts +347 -0
  105. package/dist/extensions/pi-zentui/test/state.test.ts +84 -0
  106. package/dist/extensions/pi-zentui/test/telemetry-lifecycle-integration.test.ts +276 -0
  107. package/dist/extensions/pi-zentui/test/telemetry.test.ts +105 -0
  108. package/dist/extensions/pi-zentui/test/turn-summary-lifecycle.integration.test.ts +327 -0
  109. package/dist/extensions/pi-zentui/test/user-message-osc.test.ts +164 -0
  110. package/dist/extensions/pi-zentui/test/user-message-styles.test.ts +292 -0
  111. package/dist/extensions/pi-zentui/test/working-line-lifecycle.integration.test.ts +730 -0
  112. package/dist/extensions/pi-zentui/test/working-line-messages.test.ts +34 -0
  113. package/dist/extensions/pi-zentui/test/working-line.test.ts +1990 -0
  114. package/dist/extensions/pi-zentui/tsconfig.json +16 -0
  115. package/dist/extensions/tps.test.ts +38 -0
  116. package/dist/extensions/{pi-powerline-footer/tps.ts → tps.ts} +4 -0
  117. package/dist/skills/design-references/SKILL.md +31 -0
  118. package/dist/skills/design-references/references/clickhouse/DESIGN.md +544 -0
  119. package/dist/themes/adventure.json +84 -0
  120. package/dist/themes/adwaita-dark.json +84 -0
  121. package/dist/themes/arcoiris.json +84 -0
  122. package/dist/themes/arthur.json +84 -0
  123. package/dist/themes/atom.json +84 -0
  124. package/dist/themes/aura.json +84 -0
  125. package/dist/themes/black-metal-bathory.json +84 -0
  126. package/dist/themes/black-metal-burzum.json +84 -0
  127. package/dist/themes/black-metal-khold.json +84 -0
  128. package/dist/themes/box.json +84 -0
  129. package/dist/themes/brogrammer.json +84 -0
  130. package/dist/themes/carbonfox.json +84 -0
  131. package/dist/themes/catppuccin-mocha.json +84 -0
  132. package/dist/themes/citruszest.json +84 -0
  133. package/dist/themes/cursor-dark.json +84 -0
  134. package/dist/themes/cutie-pro.json +84 -0
  135. package/dist/themes/dark-modern.json +84 -0
  136. package/dist/themes/dark-pastel.json +84 -0
  137. package/dist/themes/dimmed-monokai.json +84 -0
  138. package/dist/themes/doom-peacock.json +84 -0
  139. package/dist/themes/dracula-plus.json +84 -0
  140. package/dist/themes/dracula.json +80 -0
  141. package/dist/themes/earthsong.json +84 -0
  142. package/dist/themes/everforest-dark-hard.json +84 -0
  143. package/dist/themes/everforest-dark.json +80 -0
  144. package/dist/themes/fahrenheit.json +84 -0
  145. package/dist/themes/flatland.json +84 -0
  146. package/dist/themes/flexoki-dark.json +84 -0
  147. package/dist/themes/front-end-delight.json +84 -0
  148. package/dist/themes/fun-forrest.json +84 -0
  149. package/dist/themes/galizur.json +84 -0
  150. package/dist/themes/github-dark-colorblind.json +84 -0
  151. package/dist/themes/github-dark-high-contrast.json +84 -0
  152. package/dist/themes/glacier.json +84 -0
  153. package/dist/themes/gruber-darker.json +84 -0
  154. package/dist/themes/gruvbox-dark-hard.json +84 -0
  155. package/dist/themes/gruvbox-dark.json +84 -0
  156. package/dist/themes/gruvbox-material.json +84 -0
  157. package/dist/themes/guezwhoz.json +84 -0
  158. package/dist/themes/hacktober.json +84 -0
  159. package/dist/themes/hardcore.json +84 -0
  160. package/dist/themes/havn-skumring.json +84 -0
  161. package/dist/themes/ic-orange-ppl.json +84 -0
  162. package/dist/themes/iterm2-smoooooth.json +84 -0
  163. package/dist/themes/iterm2-tango-dark.json +84 -0
  164. package/dist/themes/japanesque.json +84 -0
  165. package/dist/themes/jellybeans.json +84 -0
  166. package/dist/themes/kanagawa-wave.json +84 -0
  167. package/dist/themes/kurokula.json +84 -0
  168. package/dist/themes/later-this-evening.json +84 -0
  169. package/dist/themes/lovelace.json +84 -0
  170. package/dist/themes/material-darker.json +84 -0
  171. package/dist/themes/matte-black.json +84 -0
  172. package/dist/themes/mellow.json +84 -0
  173. package/dist/themes/miasma.json +84 -0
  174. package/dist/themes/nord.json +80 -0
  175. package/dist/themes/nvim-dark.json +84 -0
  176. package/dist/themes/one-dark.json +80 -0
  177. package/dist/themes/popping-and-locking.json +84 -0
  178. package/dist/themes/rose-pine.json +80 -0
  179. package/dist/themes/sea-shells.json +84 -0
  180. package/dist/themes/sleepy-hollow.json +84 -0
  181. package/dist/themes/smyck.json +84 -0
  182. package/dist/themes/solarized-dark.json +80 -0
  183. package/dist/themes/tokyo-night.json +80 -0
  184. package/dist/themes/tomorrow-night-bright.json +84 -0
  185. package/dist/themes/tomorrow-night-burns.json +84 -0
  186. package/dist/themes/tomorrow-night.json +84 -0
  187. package/dist/themes/twilight.json +84 -0
  188. package/dist/themes/vague.json +84 -0
  189. package/dist/themes/vesper.json +84 -0
  190. package/dist/themes/xcode-dark-hc.json +84 -0
  191. package/docs/custom-provider.md +0 -1
  192. package/docs/plans/auto-model-routing-extension.md +490 -0
  193. package/package.json +3 -3
  194. package/dist/extensions/pi-powerline-footer/.github/workflows/test.yml +0 -27
  195. package/dist/extensions/pi-powerline-footer/CHANGELOG.md +0 -687
  196. package/dist/extensions/pi-powerline-footer/CONTRIBUTING.md +0 -16
  197. package/dist/extensions/pi-powerline-footer/README.md +0 -513
  198. package/dist/extensions/pi-powerline-footer/banner.png +0 -0
  199. package/dist/extensions/pi-powerline-footer/bash-mode/completion.ts +0 -586
  200. package/dist/extensions/pi-powerline-footer/bash-mode/editor.ts +0 -583
  201. package/dist/extensions/pi-powerline-footer/bash-mode/history.ts +0 -204
  202. package/dist/extensions/pi-powerline-footer/bash-mode/shell-session.ts +0 -286
  203. package/dist/extensions/pi-powerline-footer/bash-mode/transcript.ts +0 -108
  204. package/dist/extensions/pi-powerline-footer/bash-mode/types.ts +0 -60
  205. package/dist/extensions/pi-powerline-footer/cd-command.ts +0 -190
  206. package/dist/extensions/pi-powerline-footer/colors.ts +0 -70
  207. package/dist/extensions/pi-powerline-footer/context-usage.ts +0 -156
  208. package/dist/extensions/pi-powerline-footer/currency-rates.ts +0 -142
  209. package/dist/extensions/pi-powerline-footer/editor-composition.ts +0 -32
  210. package/dist/extensions/pi-powerline-footer/editor-performance.ts +0 -99
  211. package/dist/extensions/pi-powerline-footer/git-status.ts +0 -329
  212. package/dist/extensions/pi-powerline-footer/guide.ts +0 -220
  213. package/dist/extensions/pi-powerline-footer/icons.ts +0 -190
  214. package/dist/extensions/pi-powerline-footer/index.ts +0 -3428
  215. package/dist/extensions/pi-powerline-footer/lifecycle.ts +0 -10
  216. package/dist/extensions/pi-powerline-footer/package.json +0 -49
  217. package/dist/extensions/pi-powerline-footer/paths.ts +0 -22
  218. package/dist/extensions/pi-powerline-footer/powerline-config.ts +0 -446
  219. package/dist/extensions/pi-powerline-footer/presets.ts +0 -102
  220. package/dist/extensions/pi-powerline-footer/queue/store.ts +0 -313
  221. package/dist/extensions/pi-powerline-footer/queue/types.ts +0 -53
  222. package/dist/extensions/pi-powerline-footer/render-scheduler.ts +0 -29
  223. package/dist/extensions/pi-powerline-footer/segments.ts +0 -570
  224. package/dist/extensions/pi-powerline-footer/separators.ts +0 -57
  225. package/dist/extensions/pi-powerline-footer/session-usage.ts +0 -44
  226. package/dist/extensions/pi-powerline-footer/shortcuts.ts +0 -61
  227. package/dist/extensions/pi-powerline-footer/tests/bash-mode.test.ts +0 -1905
  228. package/dist/extensions/pi-powerline-footer/tests/cd-command.test.ts +0 -144
  229. package/dist/extensions/pi-powerline-footer/tests/context-usage.test.ts +0 -156
  230. package/dist/extensions/pi-powerline-footer/tests/custom-items.test.ts +0 -344
  231. package/dist/extensions/pi-powerline-footer/tests/editor-composition.test.ts +0 -48
  232. package/dist/extensions/pi-powerline-footer/tests/editor-performance.test.ts +0 -43
  233. package/dist/extensions/pi-powerline-footer/tests/editor-responsiveness.test.ts +0 -136
  234. package/dist/extensions/pi-powerline-footer/tests/fixed-editor-border.test.ts +0 -39
  235. package/dist/extensions/pi-powerline-footer/tests/git-optional-locks.test.ts +0 -64
  236. package/dist/extensions/pi-powerline-footer/tests/git-status.test.ts +0 -92
  237. package/dist/extensions/pi-powerline-footer/tests/guide.test.ts +0 -129
  238. package/dist/extensions/pi-powerline-footer/tests/jump-shortcuts.test.ts +0 -116
  239. package/dist/extensions/pi-powerline-footer/tests/mode-aware-trigger.test.ts +0 -79
  240. package/dist/extensions/pi-powerline-footer/tests/paths.test.ts +0 -63
  241. package/dist/extensions/pi-powerline-footer/tests/queue-store.test.ts +0 -65
  242. package/dist/extensions/pi-powerline-footer/tests/quit-cursor.test.ts +0 -14
  243. package/dist/extensions/pi-powerline-footer/tests/remaining-regressions.test.ts +0 -173
  244. package/dist/extensions/pi-powerline-footer/tests/session-usage.test.ts +0 -47
  245. package/dist/extensions/pi-powerline-footer/tests/stash-shortcut.test.ts +0 -37
  246. package/dist/extensions/pi-powerline-footer/tests/thinking-segment.test.ts +0 -76
  247. package/dist/extensions/pi-powerline-footer/tests/token-stats.test.ts +0 -249
  248. package/dist/extensions/pi-powerline-footer/tests/tps.test.ts +0 -39
  249. package/dist/extensions/pi-powerline-footer/tests/usage-display.test.ts +0 -237
  250. package/dist/extensions/pi-powerline-footer/tests/welcome.test.ts +0 -199
  251. package/dist/extensions/pi-powerline-footer/tests/working-vibes.test.ts +0 -317
  252. package/dist/extensions/pi-powerline-footer/theme.example.json +0 -24
  253. package/dist/extensions/pi-powerline-footer/theme.json +0 -12
  254. package/dist/extensions/pi-powerline-footer/theme.ts +0 -241
  255. package/dist/extensions/pi-powerline-footer/token-stats.ts +0 -304
  256. package/dist/extensions/pi-powerline-footer/tsconfig.json +0 -13
  257. package/dist/extensions/pi-powerline-footer/types.ts +0 -235
  258. package/dist/extensions/pi-powerline-footer/welcome-dismiss.ts +0 -34
  259. package/dist/extensions/pi-powerline-footer/welcome.ts +0 -709
  260. package/dist/extensions/pi-powerline-footer/working-vibes.ts +0 -721
  261. package/dist/extensions/preview-tools-disabled.test.ts +0 -37
  262. package/dist/extensions/preview-tools-disabled.ts +0 -11
  263. package/dist/themes/powerline-footer/theme.json +0 -33
@@ -1,43 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { EditorPerfProfiler, readEditorPerfOptions } from "../editor-performance.ts";
4
-
5
- test("editor profiling and A/B switches are opt-in", () => {
6
- assert.deepEqual(readEditorPerfOptions({}), {
7
- enabled: false,
8
- fastRender: true,
9
- editorChrome: true,
10
- widgets: true,
11
- bashWidgets: true,
12
- lastPrompt: true,
13
- });
14
-
15
- assert.deepEqual(readEditorPerfOptions({
16
- POWERLINE_DEBUG_PERF: "1",
17
- POWERLINE_PERF_FAST_RENDER: "0",
18
- POWERLINE_PERF_EDITOR_CHROME: "0",
19
- POWERLINE_PERF_WIDGETS: "0",
20
- POWERLINE_PERF_BASH_WIDGETS: "0",
21
- POWERLINE_PERF_LAST_PROMPT: "0",
22
- }), {
23
- enabled: true,
24
- fastRender: false,
25
- editorChrome: false,
26
- widgets: false,
27
- bashWidgets: false,
28
- lastPrompt: false,
29
- });
30
- });
31
-
32
- test("editor profiler reports timings, counts, and draft size", () => {
33
- const profiler = new EditorPerfProfiler(readEditorPerfOptions({ POWERLINE_DEBUG_PERF: "1" }));
34
-
35
- profiler.measure("input.total", () => 42);
36
- profiler.count("editor.render.fast-hit");
37
- profiler.observeDraft(["hello", "world"]);
38
-
39
- const report = profiler.report();
40
- assert.match(report, /inputs=1, editor-renders=0, renders\/input=0\.00, max-draft=11/);
41
- assert.match(report, /editor\.render\.fast-hit: n=1/);
42
- assert.match(report, /input\.total: n=1, avg=/);
43
- });
@@ -1,136 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { createRenderScheduler } from "../render-scheduler.ts";
4
-
5
- test("render scheduler coalesces pending status renders", () => {
6
- const originalSetTimeout = globalThis.setTimeout;
7
- const callbacks: Array<() => void> = [];
8
- const delays: number[] = [];
9
- let renderCount = 0;
10
-
11
- globalThis.setTimeout = ((callback: () => void, delay?: number) => {
12
- callbacks.push(callback);
13
- delays.push(delay ?? 0);
14
- return { id: callbacks.length } as ReturnType<typeof setTimeout>;
15
- }) as typeof setTimeout;
16
-
17
- try {
18
- const scheduler = createRenderScheduler(() => { renderCount += 1; }, 33);
19
-
20
- scheduler.schedule();
21
- scheduler.schedule(150);
22
- scheduler.schedule();
23
-
24
- assert.equal(callbacks.length, 1);
25
- assert.equal(delays[0], 33);
26
- callbacks[0]?.();
27
- assert.equal(renderCount, 1);
28
-
29
- scheduler.schedule(150);
30
- assert.equal(callbacks.length, 2);
31
- assert.equal(delays[1], 150);
32
- } finally {
33
- globalThis.setTimeout = originalSetTimeout;
34
- }
35
- });
36
-
37
- test("render scheduler pulls pending work forward for an earlier deadline", () => {
38
- const originalSetTimeout = globalThis.setTimeout;
39
- const originalClearTimeout = globalThis.clearTimeout;
40
- const callbacks: Array<() => void> = [];
41
- const delays: number[] = [];
42
- const cleared = new Set<object>();
43
- let renderCount = 0;
44
-
45
- globalThis.setTimeout = ((callback: () => void, delay?: number) => {
46
- const handle = { id: callbacks.length + 1 };
47
- callbacks.push(callback);
48
- delays.push(delay ?? 0);
49
- return handle as ReturnType<typeof setTimeout>;
50
- }) as typeof setTimeout;
51
- globalThis.clearTimeout = ((handle?: ReturnType<typeof setTimeout>) => {
52
- if (handle && typeof handle === "object") cleared.add(handle);
53
- }) as typeof clearTimeout;
54
-
55
- try {
56
- const scheduler = createRenderScheduler(() => { renderCount += 1; }, 33);
57
-
58
- scheduler.schedule(250);
59
- scheduler.schedule(33);
60
-
61
- assert.deepEqual(delays, [250, 33]);
62
- assert.equal(cleared.size, 1);
63
- callbacks[1]?.();
64
- assert.equal(renderCount, 1);
65
- } finally {
66
- globalThis.setTimeout = originalSetTimeout;
67
- globalThis.clearTimeout = originalClearTimeout;
68
- }
69
- });
70
-
71
- test("render scheduler allows callbacks to schedule follow-up renders", () => {
72
- const originalSetTimeout = globalThis.setTimeout;
73
- const callbacks: Array<() => void> = [];
74
- const delays: number[] = [];
75
- let renderCount = 0;
76
- let scheduler: ReturnType<typeof createRenderScheduler>;
77
-
78
- globalThis.setTimeout = ((callback: () => void, delay?: number) => {
79
- callbacks.push(callback);
80
- delays.push(delay ?? 0);
81
- return { id: callbacks.length } as ReturnType<typeof setTimeout>;
82
- }) as typeof setTimeout;
83
-
84
- try {
85
- scheduler = createRenderScheduler(() => {
86
- renderCount += 1;
87
- if (renderCount === 1) {
88
- scheduler.schedule(150);
89
- }
90
- }, 33);
91
-
92
- scheduler.schedule();
93
- callbacks[0]?.();
94
-
95
- assert.equal(renderCount, 1);
96
- assert.equal(callbacks.length, 2);
97
- assert.equal(delays[1], 150);
98
-
99
- callbacks[1]?.();
100
- assert.equal(renderCount, 2);
101
- } finally {
102
- globalThis.setTimeout = originalSetTimeout;
103
- }
104
- });
105
-
106
- test("render scheduler cancels pending status renders", () => {
107
- const originalSetTimeout = globalThis.setTimeout;
108
- const originalClearTimeout = globalThis.clearTimeout;
109
- const callbacks: Array<() => void> = [];
110
- const cleared = new Set<object>();
111
- let renderCount = 0;
112
-
113
- globalThis.setTimeout = ((callback: () => void) => {
114
- const handle = { id: callbacks.length + 1 };
115
- callbacks.push(callback);
116
- return handle as ReturnType<typeof setTimeout>;
117
- }) as typeof setTimeout;
118
- globalThis.clearTimeout = ((handle?: ReturnType<typeof setTimeout>) => {
119
- if (handle && typeof handle === "object") {
120
- cleared.add(handle);
121
- }
122
- }) as typeof clearTimeout;
123
-
124
- try {
125
- const scheduler = createRenderScheduler(() => { renderCount += 1; }, 33);
126
-
127
- scheduler.schedule();
128
- scheduler.cancel();
129
-
130
- assert.equal(cleared.size, 1);
131
- assert.equal(renderCount, 0);
132
- } finally {
133
- globalThis.setTimeout = originalSetTimeout;
134
- globalThis.clearTimeout = originalClearTimeout;
135
- }
136
- });
@@ -1,39 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { initTheme, theme } from "../../../modes/interactive/theme/theme.ts";
3
-
4
- /**
5
- * The powerline editor render draws its own border. It must respect the
6
- * editor's `borderColor` (set by interactive-mode to the bash-mode / thinking
7
- * color) instead of always using the gray "sep" color, so typing `!` visibly
8
- * switches the input field to bash mode.
9
- */
10
- function powerlineBorderColor(editor: { borderColor: unknown }, s: string): string {
11
- return typeof editor.borderColor === "function"
12
- ? (editor.borderColor as (str: string) => string)(s)
13
- : `\x1b[38;5;244m${s}\x1b[0m`;
14
- }
15
-
16
- describe("powerline editor border respects editor.borderColor", () => {
17
- it("uses the bash-mode color when interactive-mode sets it (typing !)", () => {
18
- initTheme("dark");
19
- const editorWithBashBorder = {
20
- borderColor: theme.getBashModeBorderColor(),
21
- };
22
- const border = powerlineBorderColor(editorWithBashBorder, "─".repeat(5));
23
- // Bash mode is green in the theme; the border must carry a color code.
24
- expect(border).toContain("\x1b[");
25
- expect(border).toMatch(/[0-9]+;[0-9]+;[0-9]+m/);
26
- // And it must NOT be the plain gray "sep" code.
27
- expect(border).not.toContain("\x1b[38;5;244m");
28
- });
29
-
30
- it("falls back to the gray sep color when borderColor is not a function", () => {
31
- const border = powerlineBorderColor({ borderColor: "x" }, "─".repeat(5));
32
- expect(border).toBe("\x1b[38;5;244m─────\x1b[0m");
33
- });
34
- });
35
-
36
- function getBashModeBorderColor(): (str: string) => string {
37
- // Mirrors theme.getBashModeBorderColor(): colors with the theme's "bashMode" color.
38
- return (str: string) => `\x1b[38;5;34m${str}\x1b[39m`;
39
- }
@@ -1,64 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { mkdtempSync, mkdirSync, readFileSync, writeFileSync, existsSync } from "node:fs";
4
- import { tmpdir } from "node:os";
5
- import { join } from "node:path";
6
-
7
- import { readOnlyGitEnv } from "../git-status.ts";
8
-
9
- const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
10
-
11
- // Background fetches spawn git with up to 500ms timeouts; give them room.
12
- const FETCH_SETTLE_MS = 1200;
13
-
14
- test("read-only git commands opt out of git's optional index lock", () => {
15
- const env = readOnlyGitEnv({ PATH: "/usr/bin" });
16
- assert.equal(env.GIT_OPTIONAL_LOCKS, "0");
17
- assert.equal(env.PATH, "/usr/bin", "must extend the ambient environment, not replace it");
18
- });
19
-
20
- test("readOnlyGitEnv overrides an inherited GIT_OPTIONAL_LOCKS=1", () => {
21
- assert.equal(readOnlyGitEnv({ GIT_OPTIONAL_LOCKS: "1" }).GIT_OPTIONAL_LOCKS, "0");
22
- });
23
-
24
- // Guards the regression end to end, via a `git` shim on PATH: the footer polls
25
- // every repo the user visits, so it must never take `.git/index.lock`.
26
- test("the git process the footer spawns receives GIT_OPTIONAL_LOCKS=0", { skip: process.platform === "win32" ? "POSIX shim" : false }, async () => {
27
- const dir = mkdtempSync(join(tmpdir(), "powerline-git-locks-"));
28
- const bin = join(dir, "bin");
29
- mkdirSync(bin);
30
- const log = join(dir, "calls.log");
31
-
32
- writeFileSync(
33
- join(bin, "git"),
34
- `#!/bin/sh\necho "GIT_OPTIONAL_LOCKS=\${GIT_OPTIONAL_LOCKS-unset} ARGS=$*" >> ${JSON.stringify(log)}\nexit 0\n`,
35
- { mode: 0o755 },
36
- );
37
-
38
- const originalPath = process.env.PATH;
39
- const originalOptionalLocks = process.env.GIT_OPTIONAL_LOCKS;
40
- process.env.PATH = `${bin}:${originalPath ?? ""}`;
41
- // Some environments export GIT_OPTIONAL_LOCKS=0 as a machine-wide workaround
42
- // for this bug; force the opposite so we can't inherit a false pass.
43
- process.env.GIT_OPTIONAL_LOCKS = "1";
44
- try {
45
- // Imported here so the module reads the shimmed PATH when it spawns.
46
- const { getGitStatus, invalidateGitStatus, invalidateGitBranch } = await import("../git-status.ts");
47
- invalidateGitStatus();
48
- invalidateGitBranch();
49
- getGitStatus("main");
50
- await sleep(FETCH_SETTLE_MS);
51
- } finally {
52
- process.env.PATH = originalPath;
53
- if (originalOptionalLocks === undefined) delete process.env.GIT_OPTIONAL_LOCKS;
54
- else process.env.GIT_OPTIONAL_LOCKS = originalOptionalLocks;
55
- }
56
-
57
- assert.ok(existsSync(log), "expected the footer to spawn git");
58
- const calls = readFileSync(log, "utf8").trim().split("\n");
59
- const status = calls.filter((line) => line.includes("ARGS=status --porcelain"));
60
- assert.ok(status.length > 0, `expected a status call, got:\n${calls.join("\n")}`);
61
- for (const call of calls) {
62
- assert.match(call, /GIT_OPTIONAL_LOCKS=0/, `git spawned without the lock opt-out: ${call}`);
63
- }
64
- });
@@ -1,92 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { detectGitHost, getCurrentBranch, getGitStatus, invalidateGitBranch, invalidateGitStatus, subscribeGitUpdates } from "../git-status.ts";
4
-
5
- const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
6
-
7
- // Background fetches spawn git with up to 500ms timeouts; give them room.
8
- const FETCH_SETTLE_MS = 1200;
9
-
10
- test("git status supports disabling extension git polling", () => {
11
- assert.deepEqual(getGitStatus("main", "off"), {
12
- branch: "main",
13
- staged: 0,
14
- unstaged: 0,
15
- untracked: 0,
16
- });
17
- });
18
-
19
- test("invalidateGitStatus serves stale counts while refreshing (no flicker to zeros)", async () => {
20
- getGitStatus("provider-branch"); // kick off the initial background fetch
21
- await sleep(FETCH_SETTLE_MS);
22
-
23
- const seeded = getGitStatus("provider-branch");
24
-
25
- invalidateGitStatus();
26
- const afterInvalidate = getGitStatus("provider-branch");
27
- assert.deepEqual(
28
- { staged: afterInvalidate.staged, unstaged: afterInvalidate.unstaged, untracked: afterInvalidate.untracked },
29
- { staged: seeded.staged, unstaged: seeded.unstaged, untracked: seeded.untracked },
30
- );
31
-
32
- // The background refresh converges to real data again (repo is unchanged).
33
- await sleep(FETCH_SETTLE_MS);
34
- const refreshed = getGitStatus("provider-branch");
35
- assert.deepEqual(
36
- { staged: refreshed.staged, unstaged: refreshed.unstaged, untracked: refreshed.untracked },
37
- { staged: seeded.staged, unstaged: seeded.unstaged, untracked: seeded.untracked },
38
- );
39
- });
40
-
41
- test("invalidateGitBranch keeps serving the last known branch while refreshing", async () => {
42
- getGitStatus("provider-fallback"); // seed branch cache
43
- await sleep(FETCH_SETTLE_MS);
44
-
45
- const realBranch = getCurrentBranch("provider-fallback");
46
- // Once fetched, the cached branch no longer falls back to the provider
47
- // (null in non-git directories, the actual branch name inside a repo).
48
- assert.notEqual(realBranch, "provider-fallback");
49
-
50
- invalidateGitBranch();
51
- assert.equal(getCurrentBranch("provider-fallback"), realBranch);
52
- });
53
-
54
- test("git cache completion notifies active footer subscribers", async () => {
55
- let updates = 0;
56
- const unsubscribe = subscribeGitUpdates(() => { updates += 1; });
57
- try {
58
- invalidateGitStatus();
59
- invalidateGitBranch();
60
- getGitStatus("provider-fallback");
61
- await sleep(FETCH_SETTLE_MS);
62
- assert.ok(updates > 0);
63
- } finally {
64
- unsubscribe();
65
- }
66
- });
67
-
68
- test("detectGitHost recognizes known hosts over SSH and HTTPS", () => {
69
- assert.equal(detectGitHost("git@github.com:owner/repo.git"), "github");
70
- assert.equal(detectGitHost("https://github.com/owner/repo.git"), "github");
71
- assert.equal(detectGitHost("ssh://git@gitlab.com/owner/repo.git"), "gitlab");
72
- assert.equal(detectGitHost("https://gitlab.com/owner/repo"), "gitlab");
73
- assert.equal(detectGitHost("git@bitbucket.org:owner/repo.git"), "bitbucket");
74
- assert.equal(detectGitHost("https://user@bitbucket.org/owner/repo.git"), "bitbucket");
75
- });
76
-
77
- test("detectGitHost normalizes www and sub-domains", () => {
78
- assert.equal(detectGitHost("https://www.github.com/owner/repo"), "github");
79
- assert.equal(detectGitHost("git@ssh.github.com:owner/repo.git"), "github");
80
- });
81
-
82
- test("detectGitHost treats unknown or self-hosted remotes as a generic host", () => {
83
- assert.equal(detectGitHost("git@git.example.com:owner/repo.git"), "other");
84
- assert.equal(detectGitHost("https://gitea.mycorp.dev/owner/repo.git"), "other");
85
- assert.equal(detectGitHost("/srv/git/local.git"), "other");
86
- });
87
-
88
- test("detectGitHost returns null when there is no remote", () => {
89
- assert.equal(detectGitHost(null), null);
90
- assert.equal(detectGitHost(""), null);
91
- assert.equal(detectGitHost(" "), null);
92
- });
@@ -1,129 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { mkdtempSync, readFileSync, rmSync } from "node:fs";
4
- import { tmpdir } from "node:os";
5
- import { join } from "node:path";
6
- import {
7
- GUIDE_COMPACT_LINES,
8
- GUIDE_DISMISS_HINT,
9
- GUIDE_FEATURES,
10
- getGuideFeatureLines,
11
- getGuidePreferences,
12
- getNewGuideFeatures,
13
- markGuideVersionSeen,
14
- resolveGuideDisplayMode,
15
- saveGuidePreferences,
16
- type GuideFeature,
17
- } from "../guide.ts";
18
-
19
- const features: GuideFeature[] = [
20
- { id: "old", title: "Old", example: "/old", introducedIn: "0.5.0" },
21
- { id: "new", title: "New", example: "/new", introducedIn: "0.5.3" },
22
- { id: "future", title: "Future", example: "/future", introducedIn: "0.6.0" },
23
- ];
24
-
25
-
26
- test("explicit full guide opens for each real session start", () => {
27
- for (const reason of ["startup", "new", "resume", "fork"]) {
28
- assert.equal(resolveGuideDisplayMode({ reason, hasUI: true, guideMode: "full" }), "full");
29
- }
30
- });
31
-
32
- test("guide dismissal and compact preferences change automatic display", () => {
33
- assert.equal(resolveGuideDisplayMode({ reason: "startup", hasUI: true, guideMode: "compact" }), "compact");
34
- assert.equal(resolveGuideDisplayMode({ reason: "startup", hasUI: true, guideMode: "off" }), "none");
35
- assert.equal(resolveGuideDisplayMode({ reason: "reload", hasUI: true, guideMode: "full" }), "none");
36
- assert.equal(resolveGuideDisplayMode({ reason: "startup", hasUI: false, guideMode: "full" }), "none");
37
- });
38
-
39
- test("guide defaults to a compact header so the native dock stays uncluttered", () => {
40
- const preferences = getGuidePreferences({});
41
- assert.equal(preferences.mode, "compact");
42
- assert.equal(resolveGuideDisplayMode({ reason: "startup", hasUI: true, guideMode: preferences.mode }), "compact");
43
- });
44
-
45
- test("full and compact guide content expose README commands and examples", () => {
46
- const full = getGuideFeatureLines()
47
- .map((line) => line.kind === "section" ? line.text : `${line.feature.title}: ${line.feature.example}`)
48
- .join("\n");
49
- const compact = GUIDE_COMPACT_LINES.join("\n");
50
-
51
- assert.match(full, /\/settings/);
52
- assert.match(full, /\$workflow/);
53
- assert.match(full, /Ask the architect to challenge this plan/);
54
- assert.match(full, /Ask the researcher to research <topic> and cite sources/);
55
- assert.match(full, /\/skill:\*/);
56
- assert.match(full, /\/handoff-new Next: fix <problem>; start with a coding plan/);
57
- assert.doesNotMatch(full, /question\(|\/intercom|powerline/);
58
- assert.match(compact, /\/settings/);
59
- assert.match(compact, /\$workflow/);
60
- assert.match(compact, /Ask the researcher to research <topic>/);
61
- });
62
-
63
- test("blocking guide dismisses only from its overlay input handler", () => {
64
- const source = readFileSync(new URL("../index.ts", import.meta.url), "utf8");
65
-
66
- assert.equal(GUIDE_DISMISS_HINT, "Press any key to continue");
67
- assert.match(source, /guideOverlayBlocking = true;[\s\S]*handleInput: \(\) => dismiss\(\),/);
68
- // The blocking guide cannot be dismissed by the welcome scheduler: dismissWelcome
69
- // bails while guideOverlayBlocking is set, so only the overlay's input handler
70
- // (which clears the flag first) can close it.
71
- assert.match(source, /function dismissWelcome\(ctx: any\) \{[\s\S]*?if \(guideOverlayBlocking\) return;/);
72
- });
73
-
74
- test("README-derived guide entries stay in the feature map", () => {
75
- assert.deepEqual(
76
- GUIDE_FEATURES.filter((feature) => feature.id === "settings" || feature.id === "handoff").map((feature) => feature.example),
77
- ["/settings · /guide compact|off|reset · /reload", "/handoff-new Next: fix <problem>; start with a coding plan."],
78
- );
79
- });
80
-
81
- test("new feature detection is version bounded and empty on first install", () => {
82
- assert.deepEqual(getNewGuideFeatures(undefined, "0.5.3", features), []);
83
- assert.deepEqual(getNewGuideFeatures("0.5.0", "0.5.3", features).map((feature) => feature.id), ["new"]);
84
- assert.deepEqual(getNewGuideFeatures("0.5.3", "0.5.3", features), []);
85
- assert.deepEqual(getNewGuideFeatures("0.5.0", "0.5.2", features), []);
86
- });
87
-
88
- test("guide dismissal persists only the mode and version marker", () => {
89
- const dir = mkdtempSync(join(tmpdir(), "selesai-guide-"));
90
- const settingsPath = join(dir, "settings.json");
91
-
92
- try {
93
- assert.equal(saveGuidePreferences({ mode: "off", lastSeenVersion: "0.5.3" }, settingsPath), true);
94
- const settings = JSON.parse(readFileSync(settingsPath, "utf8")) as Record<string, unknown>;
95
- assert.deepEqual(settings.selesaiGuide, { mode: "off", lastSeenVersion: "0.5.3" });
96
- assert.equal(getGuidePreferences(settings).mode, "off");
97
- } finally {
98
- rmSync(dir, { recursive: true, force: true });
99
- }
100
- });
101
-
102
- test("version marking never persists an implicit guide mode", () => {
103
- const dir = mkdtempSync(join(tmpdir(), "selesai-guide-"));
104
- const settingsPath = join(dir, "settings.json");
105
-
106
- try {
107
- // markGuideVersionSeen writes only the version marker; the mode stays
108
- // unset so the default (compact) applies instead of being locked in.
109
- assert.equal(markGuideVersionSeen("0.5.3", settingsPath), true);
110
- const settings = JSON.parse(readFileSync(settingsPath, "utf8")) as Record<string, unknown>;
111
- assert.deepEqual(settings.selesaiGuide, { lastSeenVersion: "0.5.3" });
112
- assert.equal(getGuidePreferences(settings).mode, "compact");
113
-
114
- // An explicitly chosen mode is preserved across version-only writes.
115
- assert.equal(saveGuidePreferences({ mode: "off" }, settingsPath), true);
116
- assert.equal(saveGuidePreferences({ lastSeenVersion: "0.6.0" }, settingsPath), true);
117
- const after = JSON.parse(readFileSync(settingsPath, "utf8")) as Record<string, unknown>;
118
- assert.deepEqual(after.selesaiGuide, { mode: "off", lastSeenVersion: "0.6.0" });
119
- } finally {
120
- rmSync(dir, { recursive: true, force: true });
121
- }
122
- });
123
-
124
- test("invalid persisted guide settings fall back to the compact guide", () => {
125
- assert.deepEqual(getGuidePreferences({ selesaiGuide: { mode: "unexpected", lastSeenVersion: 42 } }), {
126
- mode: "compact",
127
- lastSeenVersion: undefined,
128
- });
129
- });
@@ -1,116 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { CURSOR_MARKER } from "@earendil-works/pi-tui";
4
- import { isSupportedSuperShortcut, matchesConfiguredShortcut, shortcutConflictKey } from "../shortcuts.ts";
5
- import { parseBashModeSettings, renderFastPowerlineEditor, resolveShortcutConfig } from "../index.ts";
6
-
7
- test("surviving editor shortcuts resolve without app-owned chat scrolling", () => {
8
- const resolved = resolveShortcutConfig({});
9
- assert.equal(resolved.stashHistory, "ctrl+alt+h");
10
- assert.equal(resolved.copyEditor, "ctrl+alt+c");
11
- assert.equal(resolved.cutEditor, "ctrl+alt+x");
12
- assert.equal(resolved.editorStart, "super+shift+up");
13
- assert.equal(resolved.editorEnd, "super+shift+down");
14
- assert.equal(Object.keys(resolved).some((key) => key.startsWith("scroll")), false);
15
- assert.equal(Object.keys(resolved).some((key) => key.startsWith("jump")), false);
16
- });
17
-
18
- test("super shortcut matching and conflict normalization remain supported", () => {
19
- assert.equal(matchesConfiguredShortcut("\x1b[1;9A", "super+up"), true);
20
- assert.equal(matchesConfiguredShortcut("c", "super+c"), false);
21
- assert.equal(isSupportedSuperShortcut("super+up"), true);
22
- assert.equal(isSupportedSuperShortcut("super+z"), false);
23
- assert.equal(shortcutConflictKey("super+home"), "super+up");
24
- });
25
-
26
-
27
- test("editor boundary shortcuts remain configurable", () => {
28
- const resolved = resolveShortcutConfig({
29
- powerlineShortcuts: {
30
- editorStart: "ctrl+shift+u",
31
- editorEnd: "ctrl+shift+d",
32
- },
33
- });
34
-
35
- assert.equal(resolved.editorStart, "ctrl+shift+u");
36
- assert.equal(resolved.editorEnd, "ctrl+shift+d");
37
- });
38
-
39
- test("bash completions are opt-in", () => {
40
- assert.equal(parseBashModeSettings({}).completions, false);
41
- assert.equal(parseBashModeSettings({ bashMode: { completions: true } }).completions, true);
42
- assert.equal(parseBashModeSettings({ bashMode: { completions: false } }).completions, false);
43
- });
44
-
45
- test("fast editor render keeps Powerline chrome for large drafts", () => {
46
- const editor = {
47
- focused: true,
48
- isShowingAutocomplete: () => false,
49
- tui: { terminal: { rows: 24 } },
50
- };
51
- Reflect.set(editor, "state", {
52
- lines: ["intro", "x".repeat(5000)],
53
- cursorLine: 1,
54
- cursorCol: 5000,
55
- });
56
-
57
- const rendered = renderFastPowerlineEditor(editor, 80, {
58
- bashModeActive: false,
59
- completionsEnabled: false,
60
- });
61
-
62
- assert.ok(rendered);
63
- assert.ok(rendered[0]?.includes("↑"));
64
- assert.ok(rendered.some((line) => line.includes(CURSOR_MARKER)));
65
- // Selesai defaults to an empty editor prompt glyph, so no ">" is injected.
66
- });
67
-
68
- test("fast editor render falls back for short drafts and enabled completions", () => {
69
- const editor = {
70
- focused: true,
71
- isShowingAutocomplete: () => false,
72
- tui: { terminal: { rows: 24 } },
73
- };
74
- Reflect.set(editor, "state", { lines: ["short"], cursorLine: 0, cursorCol: 5 });
75
-
76
- assert.equal(renderFastPowerlineEditor(editor, 80, {
77
- bashModeActive: false,
78
- completionsEnabled: false,
79
- }), null);
80
-
81
- Reflect.set(editor, "state", { lines: ["x".repeat(5000)], cursorLine: 0, cursorCol: 5000 });
82
- assert.equal(renderFastPowerlineEditor(editor, 80, {
83
- bashModeActive: false,
84
- completionsEnabled: true,
85
- }), null);
86
- });
87
-
88
- test("fast editor render falls back for wide characters", () => {
89
- const editor = {
90
- focused: true,
91
- isShowingAutocomplete: () => false,
92
- tui: { terminal: { rows: 24 } },
93
- };
94
- Reflect.set(editor, "state", { lines: ["漢".repeat(1300)], cursorLine: 0, cursorCol: 1291 });
95
-
96
- assert.equal(renderFastPowerlineEditor(editor, 80, {
97
- bashModeActive: false,
98
- completionsEnabled: false,
99
- }), null);
100
- });
101
-
102
- test("fast editor render updates the editor navigation width", () => {
103
- const editor = {
104
- focused: true,
105
- isShowingAutocomplete: () => false,
106
- lastWidth: 12,
107
- tui: { terminal: { rows: 24 } },
108
- };
109
- Reflect.set(editor, "state", { lines: ["x".repeat(5000)], cursorLine: 0, cursorCol: 5000 });
110
-
111
- assert.ok(renderFastPowerlineEditor(editor, 80, {
112
- bashModeActive: false,
113
- completionsEnabled: false,
114
- }));
115
- assert.equal(Reflect.get(editor, "lastWidth"), 76);
116
- });