@selesai/code 0.9.15 → 0.10.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 (269) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +6 -9
  3. package/dist/defaults/models.json +2 -2
  4. package/dist/defaults/settings.json +3 -7
  5. package/dist/extensions/package.json +2 -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/modes/interactive/components/settings-selector.d.ts +1 -1
  118. package/dist/modes/interactive/interactive-mode.js +1 -1
  119. package/dist/skills/design-references/SKILL.md +31 -0
  120. package/dist/skills/design-references/references/clickhouse/DESIGN.md +544 -0
  121. package/dist/themes/adventure.json +84 -0
  122. package/dist/themes/adwaita-dark.json +84 -0
  123. package/dist/themes/arcoiris.json +84 -0
  124. package/dist/themes/arthur.json +84 -0
  125. package/dist/themes/atom.json +84 -0
  126. package/dist/themes/aura.json +84 -0
  127. package/dist/themes/black-metal-bathory.json +84 -0
  128. package/dist/themes/black-metal-burzum.json +84 -0
  129. package/dist/themes/black-metal-khold.json +84 -0
  130. package/dist/themes/box.json +84 -0
  131. package/dist/themes/brogrammer.json +84 -0
  132. package/dist/themes/carbonfox.json +84 -0
  133. package/dist/themes/catppuccin-mocha.json +84 -0
  134. package/dist/themes/citruszest.json +84 -0
  135. package/dist/themes/cursor-dark.json +84 -0
  136. package/dist/themes/cutie-pro.json +84 -0
  137. package/dist/themes/dark-modern.json +84 -0
  138. package/dist/themes/dark-pastel.json +84 -0
  139. package/dist/themes/dimmed-monokai.json +84 -0
  140. package/dist/themes/doom-peacock.json +84 -0
  141. package/dist/themes/dracula-plus.json +84 -0
  142. package/dist/themes/dracula.json +80 -0
  143. package/dist/themes/earthsong.json +84 -0
  144. package/dist/themes/everforest-dark-hard.json +84 -0
  145. package/dist/themes/everforest-dark.json +80 -0
  146. package/dist/themes/fahrenheit.json +84 -0
  147. package/dist/themes/flatland.json +84 -0
  148. package/dist/themes/flexoki-dark.json +84 -0
  149. package/dist/themes/front-end-delight.json +84 -0
  150. package/dist/themes/fun-forrest.json +84 -0
  151. package/dist/themes/galizur.json +84 -0
  152. package/dist/themes/github-dark-colorblind.json +84 -0
  153. package/dist/themes/github-dark-high-contrast.json +84 -0
  154. package/dist/themes/glacier.json +84 -0
  155. package/dist/themes/gruber-darker.json +84 -0
  156. package/dist/themes/gruvbox-dark-hard.json +84 -0
  157. package/dist/themes/gruvbox-dark.json +84 -0
  158. package/dist/themes/gruvbox-material.json +84 -0
  159. package/dist/themes/guezwhoz.json +84 -0
  160. package/dist/themes/hacktober.json +84 -0
  161. package/dist/themes/hardcore.json +84 -0
  162. package/dist/themes/havn-skumring.json +84 -0
  163. package/dist/themes/ic-orange-ppl.json +84 -0
  164. package/dist/themes/iterm2-smoooooth.json +84 -0
  165. package/dist/themes/iterm2-tango-dark.json +84 -0
  166. package/dist/themes/japanesque.json +84 -0
  167. package/dist/themes/jellybeans.json +84 -0
  168. package/dist/themes/kanagawa-wave.json +84 -0
  169. package/dist/themes/kurokula.json +84 -0
  170. package/dist/themes/later-this-evening.json +84 -0
  171. package/dist/themes/lovelace.json +84 -0
  172. package/dist/themes/material-darker.json +84 -0
  173. package/dist/themes/matte-black.json +84 -0
  174. package/dist/themes/mellow.json +84 -0
  175. package/dist/themes/miasma.json +84 -0
  176. package/dist/themes/nord.json +80 -0
  177. package/dist/themes/nvim-dark.json +84 -0
  178. package/dist/themes/one-dark.json +80 -0
  179. package/dist/themes/popping-and-locking.json +84 -0
  180. package/dist/themes/rose-pine.json +80 -0
  181. package/dist/themes/sea-shells.json +84 -0
  182. package/dist/themes/sleepy-hollow.json +84 -0
  183. package/dist/themes/smyck.json +84 -0
  184. package/dist/themes/solarized-dark.json +80 -0
  185. package/dist/themes/tokyo-night.json +80 -0
  186. package/dist/themes/tomorrow-night-bright.json +84 -0
  187. package/dist/themes/tomorrow-night-burns.json +84 -0
  188. package/dist/themes/tomorrow-night.json +84 -0
  189. package/dist/themes/twilight.json +84 -0
  190. package/dist/themes/vague.json +84 -0
  191. package/dist/themes/vesper.json +84 -0
  192. package/dist/themes/xcode-dark-hc.json +84 -0
  193. package/docs/custom-provider.md +0 -1
  194. package/package.json +3 -3
  195. package/dist/extensions/auto-model/auto-model.test.ts +0 -18
  196. package/dist/extensions/auto-model/classifier.ts +0 -23
  197. package/dist/extensions/auto-model/config.ts +0 -51
  198. package/dist/extensions/auto-model/index.ts +0 -22
  199. package/dist/extensions/auto-model/lifecycle.test.ts +0 -24
  200. package/dist/extensions/pi-powerline-footer/.github/workflows/test.yml +0 -27
  201. package/dist/extensions/pi-powerline-footer/CHANGELOG.md +0 -687
  202. package/dist/extensions/pi-powerline-footer/CONTRIBUTING.md +0 -16
  203. package/dist/extensions/pi-powerline-footer/README.md +0 -513
  204. package/dist/extensions/pi-powerline-footer/banner.png +0 -0
  205. package/dist/extensions/pi-powerline-footer/bash-mode/completion.ts +0 -586
  206. package/dist/extensions/pi-powerline-footer/bash-mode/editor.ts +0 -583
  207. package/dist/extensions/pi-powerline-footer/bash-mode/history.ts +0 -204
  208. package/dist/extensions/pi-powerline-footer/bash-mode/shell-session.ts +0 -286
  209. package/dist/extensions/pi-powerline-footer/bash-mode/transcript.ts +0 -108
  210. package/dist/extensions/pi-powerline-footer/bash-mode/types.ts +0 -60
  211. package/dist/extensions/pi-powerline-footer/cd-command.ts +0 -190
  212. package/dist/extensions/pi-powerline-footer/colors.ts +0 -70
  213. package/dist/extensions/pi-powerline-footer/context-usage.ts +0 -156
  214. package/dist/extensions/pi-powerline-footer/currency-rates.ts +0 -142
  215. package/dist/extensions/pi-powerline-footer/editor-composition.ts +0 -32
  216. package/dist/extensions/pi-powerline-footer/editor-performance.ts +0 -99
  217. package/dist/extensions/pi-powerline-footer/git-status.ts +0 -329
  218. package/dist/extensions/pi-powerline-footer/guide.ts +0 -220
  219. package/dist/extensions/pi-powerline-footer/icons.ts +0 -190
  220. package/dist/extensions/pi-powerline-footer/index.ts +0 -3428
  221. package/dist/extensions/pi-powerline-footer/lifecycle.ts +0 -10
  222. package/dist/extensions/pi-powerline-footer/package.json +0 -49
  223. package/dist/extensions/pi-powerline-footer/paths.ts +0 -22
  224. package/dist/extensions/pi-powerline-footer/powerline-config.ts +0 -446
  225. package/dist/extensions/pi-powerline-footer/presets.ts +0 -102
  226. package/dist/extensions/pi-powerline-footer/queue/store.ts +0 -313
  227. package/dist/extensions/pi-powerline-footer/queue/types.ts +0 -53
  228. package/dist/extensions/pi-powerline-footer/render-scheduler.ts +0 -29
  229. package/dist/extensions/pi-powerline-footer/segments.ts +0 -570
  230. package/dist/extensions/pi-powerline-footer/separators.ts +0 -57
  231. package/dist/extensions/pi-powerline-footer/session-usage.ts +0 -44
  232. package/dist/extensions/pi-powerline-footer/shortcuts.ts +0 -61
  233. package/dist/extensions/pi-powerline-footer/tests/bash-mode.test.ts +0 -1905
  234. package/dist/extensions/pi-powerline-footer/tests/cd-command.test.ts +0 -144
  235. package/dist/extensions/pi-powerline-footer/tests/context-usage.test.ts +0 -156
  236. package/dist/extensions/pi-powerline-footer/tests/custom-items.test.ts +0 -344
  237. package/dist/extensions/pi-powerline-footer/tests/editor-composition.test.ts +0 -48
  238. package/dist/extensions/pi-powerline-footer/tests/editor-performance.test.ts +0 -43
  239. package/dist/extensions/pi-powerline-footer/tests/editor-responsiveness.test.ts +0 -136
  240. package/dist/extensions/pi-powerline-footer/tests/fixed-editor-border.test.ts +0 -39
  241. package/dist/extensions/pi-powerline-footer/tests/git-optional-locks.test.ts +0 -64
  242. package/dist/extensions/pi-powerline-footer/tests/git-status.test.ts +0 -92
  243. package/dist/extensions/pi-powerline-footer/tests/guide.test.ts +0 -129
  244. package/dist/extensions/pi-powerline-footer/tests/jump-shortcuts.test.ts +0 -116
  245. package/dist/extensions/pi-powerline-footer/tests/mode-aware-trigger.test.ts +0 -79
  246. package/dist/extensions/pi-powerline-footer/tests/paths.test.ts +0 -63
  247. package/dist/extensions/pi-powerline-footer/tests/queue-store.test.ts +0 -65
  248. package/dist/extensions/pi-powerline-footer/tests/quit-cursor.test.ts +0 -14
  249. package/dist/extensions/pi-powerline-footer/tests/remaining-regressions.test.ts +0 -173
  250. package/dist/extensions/pi-powerline-footer/tests/session-usage.test.ts +0 -47
  251. package/dist/extensions/pi-powerline-footer/tests/stash-shortcut.test.ts +0 -37
  252. package/dist/extensions/pi-powerline-footer/tests/thinking-segment.test.ts +0 -76
  253. package/dist/extensions/pi-powerline-footer/tests/token-stats.test.ts +0 -249
  254. package/dist/extensions/pi-powerline-footer/tests/tps.test.ts +0 -39
  255. package/dist/extensions/pi-powerline-footer/tests/usage-display.test.ts +0 -237
  256. package/dist/extensions/pi-powerline-footer/tests/welcome.test.ts +0 -199
  257. package/dist/extensions/pi-powerline-footer/tests/working-vibes.test.ts +0 -317
  258. package/dist/extensions/pi-powerline-footer/theme.example.json +0 -24
  259. package/dist/extensions/pi-powerline-footer/theme.json +0 -12
  260. package/dist/extensions/pi-powerline-footer/theme.ts +0 -241
  261. package/dist/extensions/pi-powerline-footer/token-stats.ts +0 -304
  262. package/dist/extensions/pi-powerline-footer/tsconfig.json +0 -13
  263. package/dist/extensions/pi-powerline-footer/types.ts +0 -235
  264. package/dist/extensions/pi-powerline-footer/welcome-dismiss.ts +0 -34
  265. package/dist/extensions/pi-powerline-footer/welcome.ts +0 -709
  266. package/dist/extensions/pi-powerline-footer/working-vibes.ts +0 -721
  267. package/dist/extensions/preview-tools-disabled.test.ts +0 -37
  268. package/dist/extensions/preview-tools-disabled.ts +0 -11
  269. package/dist/themes/powerline-footer/theme.json +0 -33
@@ -1,199 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { mkdtempSync, mkdirSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
4
- import { tmpdir } from "node:os";
5
- import { join } from "node:path";
6
- import { discoverLoadedCounts, getRecentSessions, WelcomeHeader } from "../welcome.ts";
7
-
8
- const indexSource = readFileSync(new URL("../index.ts", import.meta.url), "utf8");
9
-
10
- test("discoverLoadedCounts ignores dangling skill symlinks", () => {
11
- const root = mkdtempSync(join(tmpdir(), "powerline-welcome-"));
12
- const home = join(root, "home");
13
- const project = join(root, "project");
14
- const skillsDir = join(home, ".selesai", "agent", "skills");
15
- const originalHome = process.env.HOME;
16
- const originalAgentDir = process.env.SELESAI_CODING_AGENT_DIR;
17
- const originalCwd = process.cwd();
18
- const originalDebug = console.debug;
19
- const debugCalls: unknown[][] = [];
20
-
21
- mkdirSync(join(skillsDir, "valid-skill"), { recursive: true });
22
- mkdirSync(project, { recursive: true });
23
- writeFileSync(join(skillsDir, "valid-skill", "SKILL.md"), "# Valid skill\n");
24
- symlinkSync(join(root, "missing-skill"), join(skillsDir, "pi-intercom"), "dir");
25
-
26
- console.debug = (...args: unknown[]) => {
27
- debugCalls.push(args);
28
- };
29
-
30
- try {
31
- process.env.HOME = home;
32
- delete process.env.SELESAI_CODING_AGENT_DIR;
33
- process.chdir(project);
34
-
35
- assert.equal(discoverLoadedCounts().skills, 1);
36
- assert.deepEqual(debugCalls, []);
37
- } finally {
38
- console.debug = originalDebug;
39
- process.chdir(originalCwd);
40
- if (originalHome === undefined) {
41
- delete process.env.HOME;
42
- } else {
43
- process.env.HOME = originalHome;
44
- }
45
- if (originalAgentDir === undefined) {
46
- delete process.env.SELESAI_CODING_AGENT_DIR;
47
- } else {
48
- process.env.SELESAI_CODING_AGENT_DIR = originalAgentDir;
49
- }
50
- rmSync(root, { recursive: true, force: true });
51
- }
52
- });
53
-
54
- function withTemporaryHome(run: (home: string) => void): void {
55
- const home = mkdtempSync(join(tmpdir(), "powerline-welcome-home-"));
56
- const originalHome = process.env.HOME;
57
- const originalAgentDir = process.env.SELESAI_CODING_AGENT_DIR;
58
-
59
- try {
60
- process.env.HOME = home;
61
- delete process.env.SELESAI_CODING_AGENT_DIR;
62
- run(home);
63
- } finally {
64
- if (originalHome === undefined) {
65
- delete process.env.HOME;
66
- } else {
67
- process.env.HOME = originalHome;
68
- }
69
- if (originalAgentDir === undefined) {
70
- delete process.env.SELESAI_CODING_AGENT_DIR;
71
- } else {
72
- process.env.SELESAI_CODING_AGENT_DIR = originalAgentDir;
73
- }
74
- rmSync(home, { recursive: true, force: true });
75
- }
76
- }
77
-
78
- test("welcome renders the initial system prompt token estimate", () => {
79
- const counts = { contextFiles: 1, extensions: 1, skills: 1, promptTemplates: 1 };
80
- const rendered = new WelcomeHeader("Model", "Provider", [], counts, "compact", [], 1900)
81
- .render(96)
82
- .join("\n")
83
- .replace(/\x1b\[[0-9;]*m/g, "");
84
- const withoutEstimate = [undefined, 0, Number.NaN].map((tokens) => new WelcomeHeader(
85
- "Model",
86
- "Provider",
87
- [],
88
- counts,
89
- "compact",
90
- [],
91
- tokens,
92
- ).render(96).join("\n").replace(/\x1b\[[0-9;]*m/g, ""));
93
-
94
- assert.match(rendered, /≈ 1\.9k initial prompt tokens/);
95
- for (const output of withoutEstimate) {
96
- assert.doesNotMatch(output, /initial prompt tokens/);
97
- }
98
- assert.match(indexSource, /new WelcomeHeader\(modelName, providerName, recentSessions, loadedCounts, "compact", newFeatures, initialContextTokens\)/);
99
-
100
- const overlayStart = indexSource.indexOf("function setupWelcomeOverlay");
101
- const delayStart = indexSource.indexOf("setTimeout(() => {", overlayStart);
102
- const activityGuardStart = indexSource.indexOf("if (hasActivity) {", delayStart);
103
- const estimateStart = indexSource.indexOf("const initialContextTokens = estimateInitialContextTokens(ctx);", overlayStart);
104
- const componentStart = indexSource.indexOf("new WelcomeComponent(", overlayStart);
105
- assert.ok(overlayStart >= 0);
106
- assert.ok(delayStart > overlayStart);
107
- assert.ok(activityGuardStart > delayStart);
108
- assert.ok(estimateStart > activityGuardStart);
109
- assert.ok(componentStart > estimateStart);
110
- });
111
-
112
- test("getRecentSessions prefers cwd basename from session header", () => {
113
- withTemporaryHome((home) => {
114
- const sessionsDir = join(home, ".selesai", "agent", "sessions", "--Users-nico-dev-encoded-name--");
115
- mkdirSync(sessionsDir, { recursive: true });
116
- writeFileSync(join(sessionsDir, "session.jsonl"), JSON.stringify({ cwd: "/Users/nico/dev/my-dashed-project" }) + "\n");
117
-
118
- assert.equal(getRecentSessions(1)[0]?.name, "my-dashed-project");
119
- });
120
- });
121
-
122
- test("getRecentSessions falls back to encoded directory when header cwd is unusable", () => {
123
- withTemporaryHome((home) => {
124
- const root = join(home, ".selesai", "agent", "sessions");
125
- const cases = [
126
- ["invalid-json", "not-json\n"],
127
- ["missing-cwd", JSON.stringify({ type: "session" }) + "\n"],
128
- ["non-string-cwd", JSON.stringify({ cwd: 123 }) + "\n"],
129
- ];
130
-
131
- for (const [name, content] of cases) {
132
- const sessionsDir = join(root, `--Users-nico-dev-${name}--`);
133
- mkdirSync(sessionsDir, { recursive: true });
134
- writeFileSync(join(sessionsDir, "session.jsonl"), content);
135
- }
136
-
137
- const names = getRecentSessions(10).map((session) => session.name);
138
- assert.ok(names.includes("json"));
139
- assert.ok(names.includes("cwd"));
140
- });
141
- });
142
-
143
- test("welcome discovery respects SELESAI_CODING_AGENT_DIR for agent-global files", () => {
144
- withTemporaryHome((home) => {
145
- const root = mkdtempSync(join(tmpdir(), "powerline-welcome-agent-dir-"));
146
- const project = join(root, "project");
147
- const agentDir = join(root, "agent-dir");
148
- const originalCwd = process.cwd();
149
-
150
- try {
151
- process.env.SELESAI_CODING_AGENT_DIR = agentDir;
152
- mkdirSync(project, { recursive: true });
153
- mkdirSync(join(agentDir, "extensions", "local-ext"), { recursive: true });
154
- mkdirSync(join(agentDir, "skills", "skill-a"), { recursive: true });
155
- mkdirSync(join(agentDir, "commands"), { recursive: true });
156
- mkdirSync(join(home, ".selesai", "agent"), { recursive: true });
157
- writeFileSync(join(agentDir, "AGENTS.md"), "# Agent instructions\n");
158
- writeFileSync(join(agentDir, "extensions", "local-ext", "index.ts"), "export default {};\n");
159
- writeFileSync(join(agentDir, "skills", "skill-a", "SKILL.md"), "# Skill\n");
160
- writeFileSync(join(agentDir, "commands", "hello.md"), "hello\n");
161
- writeFileSync(join(agentDir, "settings.json"), JSON.stringify({ packages: ["npm:pkg-one@1.0.0"] }));
162
- writeFileSync(join(home, ".selesai", "agent", "AGENTS.md"), "# Should not count\n");
163
- process.chdir(project);
164
-
165
- assert.deepEqual(discoverLoadedCounts(), {
166
- contextFiles: 1,
167
- extensions: 2,
168
- skills: 1,
169
- promptTemplates: 1,
170
- });
171
- } finally {
172
- process.chdir(originalCwd);
173
- rmSync(root, { recursive: true, force: true });
174
- }
175
- });
176
- });
177
-
178
- test("getRecentSessions reads custom agent sessions and existing legacy sessions", () => {
179
- withTemporaryHome((home) => {
180
- const root = mkdtempSync(join(tmpdir(), "powerline-welcome-sessions-"));
181
- const agentDir = join(root, "agent-dir");
182
-
183
- try {
184
- process.env.SELESAI_CODING_AGENT_DIR = agentDir;
185
- const customSessionDir = join(agentDir, "sessions", "--custom--");
186
- const legacySessionDir = join(home, ".selesai", "sessions", "--legacy--");
187
- mkdirSync(customSessionDir, { recursive: true });
188
- mkdirSync(legacySessionDir, { recursive: true });
189
- writeFileSync(join(customSessionDir, "session.jsonl"), JSON.stringify({ cwd: "/tmp/custom-project" }) + "\n");
190
- writeFileSync(join(legacySessionDir, "session.jsonl"), JSON.stringify({ cwd: "/tmp/legacy-project" }) + "\n");
191
-
192
- const names = getRecentSessions(10).map((session) => session.name);
193
- assert.ok(names.includes("custom-project"));
194
- assert.ok(names.includes("legacy-project"));
195
- } finally {
196
- rmSync(root, { recursive: true, force: true });
197
- }
198
- });
199
- });
@@ -1,317 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
- import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, symlinkSync } from "node:fs";
4
- import { tmpdir } from "node:os";
5
- import { join } from "node:path";
6
-
7
- import { parseVibeGenerateArgs } from "../working-vibes.ts";
8
-
9
- const FAUX_PROVIDER_PATH = new URL("../node_modules/@earendil-works/pi-ai/dist/providers/faux.js", import.meta.url).href;
10
-
11
- async function importFauxProviderTools() {
12
- try {
13
- return await import("@earendil-works/pi-ai/compat");
14
- } catch (error) {
15
- const code = error && typeof error === "object" ? Reflect.get(error, "code") : undefined;
16
- if (code !== "ERR_PACKAGE_PATH_NOT_EXPORTED" && code !== "ERR_MODULE_NOT_FOUND") {
17
- throw error;
18
- }
19
- return import(FAUX_PROVIDER_PATH);
20
- }
21
- }
22
-
23
- function ensurePiModuleLinks(): { cleanup: () => void } {
24
- const nodeModulesDir = join(process.cwd(), "node_modules", "@earendil-works");
25
- mkdirSync(nodeModulesDir, { recursive: true });
26
- const links = [
27
- {
28
- link: join(nodeModulesDir, "pi-coding-agent"),
29
- target: "/opt/homebrew/lib/node_modules/@selesai/code",
30
- },
31
- {
32
- link: join(nodeModulesDir, "pi-ai"),
33
- target: "/opt/homebrew/lib/node_modules/@selesai/code/node_modules/@earendil-works/pi-ai",
34
- },
35
- ];
36
-
37
- const createdLinks: string[] = [];
38
- for (const { link, target } of links) {
39
- if (!existsSync(link)) {
40
- symlinkSync(target, link);
41
- createdLinks.push(link);
42
- }
43
- }
44
-
45
- return {
46
- cleanup() {
47
- for (const link of createdLinks.reverse()) {
48
- if (existsSync(link)) {
49
- rmSync(link, { recursive: true, force: true });
50
- }
51
- }
52
- },
53
- };
54
- }
55
-
56
- test("parseVibeGenerateArgs supports multi-word themes", () => {
57
- assert.deepEqual(parseVibeGenerateArgs(["pirate", "200"]), { theme: "pirate", count: 200 });
58
- assert.deepEqual(parseVibeGenerateArgs(["star", "trek", "200"]), { theme: "star trek", count: 200 });
59
- assert.deepEqual(parseVibeGenerateArgs(["star", "trek"]), { theme: "star trek", count: 100 });
60
- assert.deepEqual(parseVibeGenerateArgs(["star", "trek", "abc"]), { theme: "star trek abc", count: 100 });
61
- assert.deepEqual(parseVibeGenerateArgs(["lord", "of", "rings", "999"]), { theme: "lord of rings", count: 500 });
62
- assert.equal(parseVibeGenerateArgs([]), null);
63
- });
64
-
65
- test("generateVibesBatch includes a system prompt so faux providers can return text", async () => {
66
- const links = ensurePiModuleLinks();
67
- const home = mkdtempSync(join(tmpdir(), "powerline-vibes-home-"));
68
- const previousHome = process.env.HOME;
69
- process.env.HOME = home;
70
-
71
- try {
72
- const { fauxAssistantMessage, fauxProvider } = await importFauxProviderTools();
73
- const { generateVibesBatch, initVibeManager, setVibeModel } = await import("../working-vibes.ts");
74
-
75
- const registration = fauxProvider({
76
- provider: "test-provider",
77
- models: [{ id: "test-model" }],
78
- });
79
-
80
- const model = registration.getModel("test-model");
81
- assert.ok(model);
82
-
83
- registration.setResponses([
84
- (context) => {
85
- assert.match(context.systemPrompt ?? "", /loading messages/i);
86
- return fauxAssistantMessage("Engaging warp drive...\nRunning diagnostics...");
87
- },
88
- ]);
89
-
90
- initVibeManager({
91
- modelRegistry: {
92
- find(provider: string, modelId: string) {
93
- return provider === "test-provider" && modelId === "test-model" ? model : undefined;
94
- },
95
- async getApiKeyAndHeaders() {
96
- return { ok: true, apiKey: "test-key", headers: {} };
97
- },
98
- getProvider(provider: string) {
99
- return provider === "test-provider" ? registration.provider : undefined;
100
- },
101
- async getProviderAuth() {
102
- return undefined;
103
- },
104
- },
105
- });
106
-
107
- assert.equal(setVibeModel("test-provider/test-model"), true);
108
-
109
- const result = await generateVibesBatch("star trek", 2);
110
-
111
- assert.equal(result.success, true);
112
- assert.equal(result.count, 2);
113
- assert.equal(existsSync(result.filePath), true);
114
- assert.deepEqual(readFileSync(result.filePath, "utf8").trim().split("\n"), [
115
- "Engaging warp drive...",
116
- "Running diagnostics...",
117
- ]);
118
- } finally {
119
- if (previousHome === undefined) {
120
- delete process.env.HOME;
121
- } else {
122
- process.env.HOME = previousHome;
123
- }
124
- rmSync(home, { recursive: true, force: true });
125
- links.cleanup();
126
- }
127
- });
128
-
129
- test("generateVibesBatch forwards resolved provider env and credential base URL", async () => {
130
- const links = ensurePiModuleLinks();
131
- const home = mkdtempSync(join(tmpdir(), "powerline-vibes-home-"));
132
- const previousHome = process.env.HOME;
133
- process.env.HOME = home;
134
-
135
- try {
136
- const { fauxAssistantMessage, fauxProvider } = await importFauxProviderTools();
137
- const { generateVibesBatch, initVibeManager, setVibeModel } = await import("../working-vibes.ts");
138
-
139
- const registration = fauxProvider({
140
- provider: "test-provider",
141
- models: [{ id: "test-model" }],
142
- });
143
-
144
- const model = registration.getModel("test-model");
145
- assert.ok(model);
146
-
147
- registration.setResponses([
148
- (_context, options, _state, requestModel) => {
149
- assert.deepEqual(options?.env, { AWS_PROFILE: "vibes" });
150
- assert.equal(requestModel.baseUrl, "https://credential.example/v1");
151
- return fauxAssistantMessage("Signing the request...");
152
- },
153
- ]);
154
-
155
- initVibeManager({
156
- modelRegistry: {
157
- find(provider: string, modelId: string) {
158
- return provider === "test-provider" && modelId === "test-model" ? model : undefined;
159
- },
160
- async getApiKeyAndHeaders() {
161
- return { ok: true, apiKey: "test-key", headers: {}, env: { AWS_PROFILE: "vibes" } };
162
- },
163
- getProvider(provider: string) {
164
- return provider === "test-provider" ? registration.provider : undefined;
165
- },
166
- async getProviderAuth() {
167
- return { auth: { apiKey: "test-key", baseUrl: "https://credential.example/v1" } };
168
- },
169
- },
170
- });
171
-
172
- assert.equal(setVibeModel("test-provider/test-model"), true);
173
-
174
- const result = await generateVibesBatch("bedrock", 1);
175
-
176
- assert.equal(result.success, true);
177
- assert.deepEqual(readFileSync(result.filePath, "utf8").trim().split("\n"), [
178
- "Signing the request...",
179
- ]);
180
- } finally {
181
- if (previousHome === undefined) {
182
- delete process.env.HOME;
183
- } else {
184
- process.env.HOME = previousHome;
185
- }
186
- rmSync(home, { recursive: true, force: true });
187
- links.cleanup();
188
- }
189
- });
190
-
191
- test("on-demand vibe generation includes a system prompt for providers that require instructions", async () => {
192
- const links = ensurePiModuleLinks();
193
- const home = mkdtempSync(join(tmpdir(), "powerline-vibes-home-"));
194
- const previousHome = process.env.HOME;
195
- process.env.HOME = home;
196
-
197
- try {
198
- const { fauxAssistantMessage, fauxProvider } = await importFauxProviderTools();
199
- const { initVibeManager, onVibeAgentStart, onVibeBeforeAgentStart, setVibeModel, setVibeTheme } = await import("../working-vibes.ts");
200
-
201
- const registration = fauxProvider({
202
- provider: "test-provider",
203
- models: [{ id: "test-model" }],
204
- });
205
-
206
- const model = registration.getModel("test-model");
207
- assert.ok(model);
208
-
209
- registration.setResponses([
210
- (context) => {
211
- assert.match(context.systemPrompt ?? "", /loading messages/i);
212
- return fauxAssistantMessage("Engaging warp drive...");
213
- },
214
- ]);
215
-
216
- initVibeManager({
217
- modelRegistry: {
218
- find(provider: string, modelId: string) {
219
- return provider === "test-provider" && modelId === "test-model" ? model : undefined;
220
- },
221
- async getApiKeyAndHeaders() {
222
- return { ok: true, apiKey: "test-key", headers: {} };
223
- },
224
- getProvider(provider: string) {
225
- return provider === "test-provider" ? registration.provider : undefined;
226
- },
227
- async getProviderAuth() {
228
- return undefined;
229
- },
230
- },
231
- });
232
-
233
- assert.equal(setVibeTheme("star trek"), true);
234
- assert.equal(setVibeModel("test-provider/test-model"), true);
235
-
236
- const updates: Array<string | undefined> = [];
237
- onVibeAgentStart();
238
- onVibeBeforeAgentStart("fix a bug", (message) => {
239
- updates.push(message);
240
- });
241
-
242
- const start = Date.now();
243
- while (!updates.includes("Engaging warp drive...") && Date.now() - start < 1000) {
244
- await new Promise((resolve) => setTimeout(resolve, 10));
245
- }
246
-
247
- assert.equal(updates[0], "Channeling star trek...");
248
- assert.ok(updates.includes("Engaging warp drive..."));
249
- } finally {
250
- if (previousHome === undefined) {
251
- delete process.env.HOME;
252
- } else {
253
- process.env.HOME = previousHome;
254
- }
255
- rmSync(home, { recursive: true, force: true });
256
- links.cleanup();
257
- }
258
- });
259
-
260
- test("generateVibesBatch preserves provider errors instead of reporting an empty response", async () => {
261
- const links = ensurePiModuleLinks();
262
- const home = mkdtempSync(join(tmpdir(), "powerline-vibes-home-"));
263
- const previousHome = process.env.HOME;
264
- process.env.HOME = home;
265
-
266
- try {
267
- const { fauxAssistantMessage, fauxProvider } = await importFauxProviderTools();
268
- const { generateVibesBatch, initVibeManager, setVibeModel } = await import("../working-vibes.ts");
269
-
270
- const registration = fauxProvider({
271
- provider: "test-provider",
272
- models: [{ id: "test-model" }],
273
- });
274
-
275
- const model = registration.getModel("test-model");
276
- assert.ok(model);
277
-
278
- registration.setResponses([
279
- fauxAssistantMessage([], {
280
- stopReason: "error",
281
- errorMessage: "Instructions are required",
282
- }),
283
- ]);
284
-
285
- initVibeManager({
286
- modelRegistry: {
287
- find(provider: string, modelId: string) {
288
- return provider === "test-provider" && modelId === "test-model" ? model : undefined;
289
- },
290
- async getApiKeyAndHeaders() {
291
- return { ok: true, apiKey: "test-key", headers: {} };
292
- },
293
- getProvider(provider: string) {
294
- return provider === "test-provider" ? registration.provider : undefined;
295
- },
296
- async getProviderAuth() {
297
- return undefined;
298
- },
299
- },
300
- });
301
-
302
- assert.equal(setVibeModel("test-provider/test-model"), true);
303
-
304
- const result = await generateVibesBatch("noir", 2);
305
-
306
- assert.equal(result.success, false);
307
- assert.equal(result.error, "Instructions are required");
308
- } finally {
309
- if (previousHome === undefined) {
310
- delete process.env.HOME;
311
- } else {
312
- process.env.HOME = previousHome;
313
- }
314
- rmSync(home, { recursive: true, force: true });
315
- links.cleanup();
316
- }
317
- });
@@ -1,24 +0,0 @@
1
- {
2
- "colors": {
3
- "model": "#d787af",
4
- "shellMode": "accent",
5
- "path": "#00afaf",
6
- "gitDirty": "warning",
7
- "gitClean": "success",
8
- "thinking": "thinkingOff",
9
- "thinkingMinimal": "thinkingMinimal",
10
- "thinkingLow": "thinkingLow",
11
- "thinkingMedium": "thinkingMedium",
12
- "context": "dim",
13
- "contextWarn": "warning",
14
- "contextError": "error",
15
- "cost": "text",
16
- "tokens": "muted",
17
- "separator": "dim",
18
- "border": "borderMuted"
19
- },
20
- "icons": {
21
- "auto": "↯",
22
- "warning": ""
23
- }
24
- }
@@ -1,12 +0,0 @@
1
- {
2
- "colors": {
3
- "context": "#00c853",
4
- "contextWarn": "#ff9800",
5
- "contextError": "#f44336"
6
- },
7
- "icons": {
8
- "folder": "",
9
- "context": "",
10
- "auto": ""
11
- }
12
- }