@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,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
- }