@selesai/code 0.9.15 → 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 (267) hide show
  1. package/CHANGELOG.md +22 -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/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/package.json +3 -3
  193. package/dist/extensions/auto-model/auto-model.test.ts +0 -18
  194. package/dist/extensions/auto-model/classifier.ts +0 -23
  195. package/dist/extensions/auto-model/config.ts +0 -51
  196. package/dist/extensions/auto-model/index.ts +0 -22
  197. package/dist/extensions/auto-model/lifecycle.test.ts +0 -24
  198. package/dist/extensions/pi-powerline-footer/.github/workflows/test.yml +0 -27
  199. package/dist/extensions/pi-powerline-footer/CHANGELOG.md +0 -687
  200. package/dist/extensions/pi-powerline-footer/CONTRIBUTING.md +0 -16
  201. package/dist/extensions/pi-powerline-footer/README.md +0 -513
  202. package/dist/extensions/pi-powerline-footer/banner.png +0 -0
  203. package/dist/extensions/pi-powerline-footer/bash-mode/completion.ts +0 -586
  204. package/dist/extensions/pi-powerline-footer/bash-mode/editor.ts +0 -583
  205. package/dist/extensions/pi-powerline-footer/bash-mode/history.ts +0 -204
  206. package/dist/extensions/pi-powerline-footer/bash-mode/shell-session.ts +0 -286
  207. package/dist/extensions/pi-powerline-footer/bash-mode/transcript.ts +0 -108
  208. package/dist/extensions/pi-powerline-footer/bash-mode/types.ts +0 -60
  209. package/dist/extensions/pi-powerline-footer/cd-command.ts +0 -190
  210. package/dist/extensions/pi-powerline-footer/colors.ts +0 -70
  211. package/dist/extensions/pi-powerline-footer/context-usage.ts +0 -156
  212. package/dist/extensions/pi-powerline-footer/currency-rates.ts +0 -142
  213. package/dist/extensions/pi-powerline-footer/editor-composition.ts +0 -32
  214. package/dist/extensions/pi-powerline-footer/editor-performance.ts +0 -99
  215. package/dist/extensions/pi-powerline-footer/git-status.ts +0 -329
  216. package/dist/extensions/pi-powerline-footer/guide.ts +0 -220
  217. package/dist/extensions/pi-powerline-footer/icons.ts +0 -190
  218. package/dist/extensions/pi-powerline-footer/index.ts +0 -3428
  219. package/dist/extensions/pi-powerline-footer/lifecycle.ts +0 -10
  220. package/dist/extensions/pi-powerline-footer/package.json +0 -49
  221. package/dist/extensions/pi-powerline-footer/paths.ts +0 -22
  222. package/dist/extensions/pi-powerline-footer/powerline-config.ts +0 -446
  223. package/dist/extensions/pi-powerline-footer/presets.ts +0 -102
  224. package/dist/extensions/pi-powerline-footer/queue/store.ts +0 -313
  225. package/dist/extensions/pi-powerline-footer/queue/types.ts +0 -53
  226. package/dist/extensions/pi-powerline-footer/render-scheduler.ts +0 -29
  227. package/dist/extensions/pi-powerline-footer/segments.ts +0 -570
  228. package/dist/extensions/pi-powerline-footer/separators.ts +0 -57
  229. package/dist/extensions/pi-powerline-footer/session-usage.ts +0 -44
  230. package/dist/extensions/pi-powerline-footer/shortcuts.ts +0 -61
  231. package/dist/extensions/pi-powerline-footer/tests/bash-mode.test.ts +0 -1905
  232. package/dist/extensions/pi-powerline-footer/tests/cd-command.test.ts +0 -144
  233. package/dist/extensions/pi-powerline-footer/tests/context-usage.test.ts +0 -156
  234. package/dist/extensions/pi-powerline-footer/tests/custom-items.test.ts +0 -344
  235. package/dist/extensions/pi-powerline-footer/tests/editor-composition.test.ts +0 -48
  236. package/dist/extensions/pi-powerline-footer/tests/editor-performance.test.ts +0 -43
  237. package/dist/extensions/pi-powerline-footer/tests/editor-responsiveness.test.ts +0 -136
  238. package/dist/extensions/pi-powerline-footer/tests/fixed-editor-border.test.ts +0 -39
  239. package/dist/extensions/pi-powerline-footer/tests/git-optional-locks.test.ts +0 -64
  240. package/dist/extensions/pi-powerline-footer/tests/git-status.test.ts +0 -92
  241. package/dist/extensions/pi-powerline-footer/tests/guide.test.ts +0 -129
  242. package/dist/extensions/pi-powerline-footer/tests/jump-shortcuts.test.ts +0 -116
  243. package/dist/extensions/pi-powerline-footer/tests/mode-aware-trigger.test.ts +0 -79
  244. package/dist/extensions/pi-powerline-footer/tests/paths.test.ts +0 -63
  245. package/dist/extensions/pi-powerline-footer/tests/queue-store.test.ts +0 -65
  246. package/dist/extensions/pi-powerline-footer/tests/quit-cursor.test.ts +0 -14
  247. package/dist/extensions/pi-powerline-footer/tests/remaining-regressions.test.ts +0 -173
  248. package/dist/extensions/pi-powerline-footer/tests/session-usage.test.ts +0 -47
  249. package/dist/extensions/pi-powerline-footer/tests/stash-shortcut.test.ts +0 -37
  250. package/dist/extensions/pi-powerline-footer/tests/thinking-segment.test.ts +0 -76
  251. package/dist/extensions/pi-powerline-footer/tests/token-stats.test.ts +0 -249
  252. package/dist/extensions/pi-powerline-footer/tests/tps.test.ts +0 -39
  253. package/dist/extensions/pi-powerline-footer/tests/usage-display.test.ts +0 -237
  254. package/dist/extensions/pi-powerline-footer/tests/welcome.test.ts +0 -199
  255. package/dist/extensions/pi-powerline-footer/tests/working-vibes.test.ts +0 -317
  256. package/dist/extensions/pi-powerline-footer/theme.example.json +0 -24
  257. package/dist/extensions/pi-powerline-footer/theme.json +0 -12
  258. package/dist/extensions/pi-powerline-footer/theme.ts +0 -241
  259. package/dist/extensions/pi-powerline-footer/token-stats.ts +0 -304
  260. package/dist/extensions/pi-powerline-footer/tsconfig.json +0 -13
  261. package/dist/extensions/pi-powerline-footer/types.ts +0 -235
  262. package/dist/extensions/pi-powerline-footer/welcome-dismiss.ts +0 -34
  263. package/dist/extensions/pi-powerline-footer/welcome.ts +0 -709
  264. package/dist/extensions/pi-powerline-footer/working-vibes.ts +0 -721
  265. package/dist/extensions/preview-tools-disabled.test.ts +0 -37
  266. package/dist/extensions/preview-tools-disabled.ts +0 -11
  267. 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
- }