@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,10 +0,0 @@
1
- export function shouldShowStartupWelcome(reason: unknown, welcomeEnabled: boolean): boolean {
2
- return reason === "startup" && welcomeEnabled;
3
- }
4
-
5
- export function isStaleExtensionContextError(error: unknown): boolean {
6
- return error instanceof Error && (
7
- error.message.includes("This extension instance is stale")
8
- || error.message.includes("This extension ctx is stale")
9
- );
10
- }
@@ -1,49 +0,0 @@
1
- {
2
- "name": "pi-powerline-footer",
3
- "version": "0.13.0",
4
- "description": "Powerline-style status bar extension for pi coding agent",
5
- "type": "module",
6
- "files": [
7
- "*.ts",
8
- "*.md",
9
- "*.json",
10
- "!progress.md",
11
- "bash-mode/**/*.ts",
12
- "queue/**/*.ts"
13
- ],
14
- "keywords": [
15
- "pi-package",
16
- "pi",
17
- "coding-agent",
18
- "powerline",
19
- "status-bar",
20
- "extension"
21
- ],
22
- "author": "Nico Bailon",
23
- "license": "MIT",
24
- "repository": {
25
- "type": "git",
26
- "url": "git+https://github.com/nicobailon/pi-powerline-footer.git"
27
- },
28
- "scripts": {
29
- "typecheck": "tsc --noEmit",
30
- "test": "node --experimental-strip-types --test tests/**/*.test.ts"
31
- },
32
- "peerDependencies": {
33
- "@earendil-works/pi-ai": ">=0.84.1 <0.85.0",
34
- "@selesai/code": "*",
35
- "@earendil-works/pi-tui": ">=0.84.1 <0.85.0"
36
- },
37
- "devDependencies": {
38
- "@earendil-works/pi-ai": "^0.84.1",
39
- "@selesai/code": "^0.1.0",
40
- "@earendil-works/pi-tui": "^0.84.1",
41
- "@types/node": "24.13.3",
42
- "typescript": "5.9.3"
43
- },
44
- "pi": {
45
- "extensions": [
46
- "./index.ts"
47
- ]
48
- }
49
- }
@@ -1,22 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { homedir } from "node:os";
3
- import { join } from "node:path";
4
- import { CONFIG_DIR_NAME, getAgentDir } from "@selesai/code";
5
-
6
- export function getHomeDir(): string {
7
- return process.env.HOME || process.env.USERPROFILE || homedir();
8
- }
9
-
10
- export function getAgentPath(...segments: string[]): string {
11
- return join(getAgentDir(), ...segments);
12
- }
13
-
14
- export function getLegacyPiPath(...segments: string[]): string {
15
- return join(getHomeDir(), CONFIG_DIR_NAME, ...segments);
16
- }
17
-
18
- export function getAgentSessionDirs(): string[] {
19
- const primary = getAgentPath("sessions");
20
- const legacy = getLegacyPiPath("sessions");
21
- return existsSync(legacy) && legacy !== primary ? [primary, legacy] : [primary];
22
- }
@@ -1,446 +0,0 @@
1
- import { visibleWidth } from "@earendil-works/pi-tui";
2
- import { normalizeCostCurrency } from "./currency-rates.ts";
3
- import { BUILTIN_STATUS_LINE_SEGMENT_IDS } from "./types.ts";
4
- import type { ColorValue, CustomItemPosition, CustomStatusItem, PowerlinePlacement, PresetDef, StatusLineLayout, StatusLinePreset, StatusLineSegmentId, StatusLineSegmentOptions, StatusLineSeparatorStyle } from "./types.ts";
5
-
6
- export interface PowerlineConfig {
7
- preset: StatusLinePreset;
8
- customItems: CustomStatusItem[];
9
- fixedEditorPromptGlyph: string;
10
- disabledSegments: StatusLineSegmentId[];
11
- invalidDisabledSegments: string[];
12
- layout: StatusLineLayout | null;
13
- invalidLayoutSegments: string[];
14
- separator: StatusLineSeparatorStyle | null;
15
- segmentOptions: StatusLineSegmentOptions;
16
- placement: PowerlinePlacement;
17
- invalidPlacement: string | null;
18
- welcome: boolean;
19
- stashSharpSShortcut: boolean;
20
- }
21
-
22
- function isRecord(value: unknown): value is Record<string, unknown> {
23
- return typeof value === "object" && value !== null && !Array.isArray(value);
24
- }
25
-
26
- function normalizePreset(value: unknown, presets: readonly StatusLinePreset[]): StatusLinePreset | null {
27
- if (typeof value !== "string") return null;
28
- const normalized = value.trim().toLowerCase();
29
- return (presets as readonly string[]).includes(normalized) ? (normalized as StatusLinePreset) : null;
30
- }
31
-
32
- function normalizePlacement(value: unknown): { placement: PowerlinePlacement; invalidPlacement: string | null } {
33
- if (value === undefined) return { placement: "above", invalidPlacement: null };
34
-
35
- const normalized = typeof value === "string" ? value.trim().toLowerCase() : "";
36
- if (normalized === "above" || normalized === "below") {
37
- return { placement: normalized, invalidPlacement: null };
38
- }
39
-
40
- return {
41
- placement: "above",
42
- invalidPlacement: typeof value === "string" ? value.trim() : String(value),
43
- };
44
- }
45
-
46
- const SEPARATOR_STYLES = [
47
- "powerline",
48
- "powerline-thin",
49
- "slash",
50
- "pipe",
51
- "block",
52
- "none",
53
- "ascii",
54
- "dot",
55
- "chevron",
56
- "star",
57
- ] as const satisfies readonly StatusLineSeparatorStyle[];
58
-
59
- function normalizeSeparator(value: unknown): StatusLineSeparatorStyle | null {
60
- if (typeof value !== "string") return null;
61
- const normalized = value.trim().toLowerCase();
62
- return (SEPARATOR_STYLES as readonly string[]).includes(normalized)
63
- ? (normalized as StatusLineSeparatorStyle)
64
- : null;
65
- }
66
-
67
- function normalizeCustomItemId(value: unknown): string | null {
68
- if (typeof value !== "string") return null;
69
- const normalized = value.trim();
70
- if (!normalized) return null;
71
- return /^[a-zA-Z0-9_-]+$/.test(normalized) ? normalized : null;
72
- }
73
-
74
- function normalizeCustomItemPosition(value: unknown): CustomItemPosition {
75
- if (value === "left" || value === "right" || value === "secondary") return value;
76
- return "right";
77
- }
78
-
79
- function normalizeCustomColor(value: unknown): ColorValue | undefined {
80
- if (typeof value !== "string") return undefined;
81
- const normalized = value.trim();
82
- return normalized ? (normalized as ColorValue) : undefined;
83
- }
84
-
85
- function normalizeCustomPrefix(value: unknown): string | undefined {
86
- if (typeof value !== "string") return undefined;
87
- const normalized = value.trim();
88
- return normalized ? normalized : undefined;
89
- }
90
-
91
-
92
- function normalizeCustomStatusItem(raw: unknown, idOverride?: string): CustomStatusItem | null {
93
- if (!isRecord(raw)) return null;
94
- const id = normalizeCustomItemId(idOverride ?? raw.id);
95
- if (!id) return null;
96
-
97
- const statusKey = typeof raw.statusKey === "string" && raw.statusKey.trim() ? raw.statusKey.trim() : id;
98
-
99
- return {
100
- id,
101
- statusKey,
102
- position: normalizeCustomItemPosition(raw.position),
103
- color: normalizeCustomColor(raw.color),
104
- prefix: normalizeCustomPrefix(raw.prefix),
105
- hideWhenMissing: raw.hideWhenMissing !== false,
106
- excludeFromExtensionStatuses: raw.excludeFromExtensionStatuses !== false,
107
- };
108
- }
109
-
110
- function normalizeCustomItems(raw: unknown): CustomStatusItem[] {
111
- const normalized: CustomStatusItem[] = [];
112
-
113
- if (Array.isArray(raw)) {
114
- for (const entry of raw) {
115
- const item = normalizeCustomStatusItem(entry);
116
- if (item) normalized.push(item);
117
- }
118
- } else if (isRecord(raw)) {
119
- for (const [id, entry] of Object.entries(raw)) {
120
- const item = normalizeCustomStatusItem(entry, id);
121
- if (item) normalized.push(item);
122
- }
123
- }
124
-
125
- const deduped = new Map<string, CustomStatusItem>();
126
- for (const item of normalized) {
127
- deduped.set(item.id, item);
128
- }
129
-
130
- return [...deduped.values()];
131
- }
132
-
133
- const BUILTIN_STATUS_LINE_SEGMENT_ID_SET = new Set<string>(BUILTIN_STATUS_LINE_SEGMENT_IDS);
134
-
135
- function normalizeStatusLineSegmentId(value: unknown, customItemIds: ReadonlySet<string>): StatusLineSegmentId | null {
136
- if (typeof value !== "string") return null;
137
-
138
- const normalized = value.trim();
139
- if (BUILTIN_STATUS_LINE_SEGMENT_ID_SET.has(normalized)) {
140
- return normalized as StatusLineSegmentId;
141
- }
142
-
143
- const customId = normalized.startsWith("custom:")
144
- ? normalizeCustomItemId(normalized.slice("custom:".length))
145
- : null;
146
- return customId && customItemIds.has(customId) ? `custom:${customId}` : null;
147
- }
148
-
149
- function normalizeDisabledSegments(
150
- raw: unknown,
151
- customItems: readonly CustomStatusItem[],
152
- ): { disabledSegments: StatusLineSegmentId[]; invalidDisabledSegments: string[] } {
153
- if (!Array.isArray(raw)) return { disabledSegments: [], invalidDisabledSegments: [] };
154
-
155
- const disabledSegments: StatusLineSegmentId[] = [];
156
- const invalidDisabledSegments: string[] = [];
157
- const customItemIds = new Set(customItems.map((item) => item.id));
158
- const seen = new Set<StatusLineSegmentId>();
159
-
160
- for (const entry of raw) {
161
- const segmentId = normalizeStatusLineSegmentId(entry, customItemIds);
162
- if (!segmentId) {
163
- invalidDisabledSegments.push(typeof entry === "string" ? entry.trim() : String(entry));
164
- } else if (!seen.has(segmentId)) {
165
- seen.add(segmentId);
166
- disabledSegments.push(segmentId);
167
- }
168
- }
169
-
170
- return { disabledSegments, invalidDisabledSegments };
171
- }
172
-
173
- function normalizeLayout(
174
- raw: unknown,
175
- customItems: readonly CustomStatusItem[],
176
- ): { layout: StatusLineLayout | null; invalidLayoutSegments: string[] } {
177
- if (!isRecord(raw)) return { layout: null, invalidLayoutSegments: [] };
178
-
179
- const layout: StatusLineLayout = {};
180
- const invalidLayoutSegments: string[] = [];
181
- const customItemIds = new Set(customItems.map((item) => item.id));
182
- const globallyPlaced = new Set<StatusLineSegmentId>();
183
-
184
- for (const row of ["left", "right", "secondary"] as const) {
185
- const entries = raw[row];
186
- if (!Array.isArray(entries)) continue;
187
-
188
- const segments: StatusLineSegmentId[] = [];
189
- const seen = new Set<StatusLineSegmentId>();
190
- for (const entry of entries) {
191
- const segmentId = normalizeStatusLineSegmentId(entry, customItemIds);
192
- if (!segmentId) {
193
- invalidLayoutSegments.push(`${row}:${typeof entry === "string" ? entry.trim() : String(entry)}`);
194
- } else if (!seen.has(segmentId)) {
195
- seen.add(segmentId);
196
- if (globallyPlaced.has(segmentId)) {
197
- invalidLayoutSegments.push(`${row}:${segmentId}`);
198
- } else {
199
- globallyPlaced.add(segmentId);
200
- segments.push(segmentId);
201
- }
202
- }
203
- }
204
- layout[row] = segments;
205
- }
206
-
207
- return Object.keys(layout).length > 0
208
- ? { layout, invalidLayoutSegments }
209
- : { layout: null, invalidLayoutSegments };
210
- }
211
-
212
- function normalizeSegmentOptions(raw: Record<string, unknown>): StatusLineSegmentOptions {
213
- const options: StatusLineSegmentOptions = {};
214
-
215
- if (isRecord(raw.model)) {
216
- options.model = {
217
- ...(typeof raw.model.showThinkingLevel === "boolean" ? { showThinkingLevel: raw.model.showThinkingLevel } : {}),
218
- ...(raw.model.display === "name" || raw.model.display === "qualified" ? { display: raw.model.display } : {}),
219
- };
220
- }
221
-
222
- if (isRecord(raw.path)) {
223
- options.path = {
224
- ...(raw.path.mode === "basename" || raw.path.mode === "abbreviated" || raw.path.mode === "full" ? { mode: raw.path.mode } : {}),
225
- ...(typeof raw.path.maxLength === "number" && Number.isFinite(raw.path.maxLength) && raw.path.maxLength > 0
226
- ? { maxLength: Math.floor(raw.path.maxLength) }
227
- : {}),
228
- };
229
- }
230
-
231
- if (isRecord(raw.git)) {
232
- options.git = {
233
- ...(typeof raw.git.showBranch === "boolean" ? { showBranch: raw.git.showBranch } : {}),
234
- ...(typeof raw.git.showStaged === "boolean" ? { showStaged: raw.git.showStaged } : {}),
235
- ...(typeof raw.git.showUnstaged === "boolean" ? { showUnstaged: raw.git.showUnstaged } : {}),
236
- ...(typeof raw.git.showUntracked === "boolean" ? { showUntracked: raw.git.showUntracked } : {}),
237
- ...(raw.git.polling === "full" || raw.git.polling === "branch" || raw.git.polling === "off" ? { polling: raw.git.polling } : {}),
238
- ...(typeof raw.git.hostIcon === "boolean" ? { hostIcon: raw.git.hostIcon } : {}),
239
- };
240
- }
241
-
242
- if (isRecord(raw.time)) {
243
- options.time = {
244
- ...(raw.time.format === "12h" || raw.time.format === "24h" ? { format: raw.time.format } : {}),
245
- ...(typeof raw.time.showSeconds === "boolean" ? { showSeconds: raw.time.showSeconds } : {}),
246
- };
247
- }
248
-
249
- if (isRecord(raw.cost)) {
250
- const currency = normalizeCostCurrency(raw.cost.currency);
251
- options.cost = {
252
- ...(raw.cost.subscriptionDisplay === "subscription"
253
- || raw.cost.subscriptionDisplay === "reported-cost"
254
- || raw.cost.subscriptionDisplay === "both"
255
- ? { subscriptionDisplay: raw.cost.subscriptionDisplay }
256
- : {}),
257
- ...(currency ? { currency } : {}),
258
- };
259
- }
260
-
261
- if (isRecord(raw.context)) {
262
- options.context = {
263
- ...(raw.context.format === "full" || raw.context.format === "percent" ? { format: raw.context.format } : {}),
264
- };
265
- }
266
-
267
- if (isRecord(raw.cache_read)) {
268
- options.cache_read = {
269
- ...(raw.cache_read.format === "tokens" || raw.cache_read.format === "percent" || raw.cache_read.format === "both"
270
- ? { format: raw.cache_read.format }
271
- : {}),
272
- };
273
- }
274
-
275
- return options;
276
- }
277
-
278
- export function mergeSegmentOptions(
279
- defaults: StatusLineSegmentOptions = {},
280
- overrides: StatusLineSegmentOptions = {},
281
- ): StatusLineSegmentOptions {
282
- return {
283
- ...defaults,
284
- ...overrides,
285
- model: { ...defaults.model, ...overrides.model },
286
- path: { ...defaults.path, ...overrides.path },
287
- git: { ...defaults.git, ...overrides.git },
288
- time: { ...defaults.time, ...overrides.time },
289
- cost: { ...defaults.cost, ...overrides.cost },
290
- context: { ...defaults.context, ...overrides.context },
291
- cache_read: { ...defaults.cache_read, ...overrides.cache_read },
292
- };
293
- }
294
-
295
- export function parsePowerlineConfig(value: unknown, presets: readonly StatusLinePreset[]): PowerlineConfig {
296
- const defaultConfig: PowerlineConfig = {
297
- preset: "default",
298
- customItems: [],
299
- fixedEditorPromptGlyph: "",
300
- disabledSegments: [],
301
- invalidDisabledSegments: [],
302
- layout: null,
303
- invalidLayoutSegments: [],
304
- separator: null,
305
- segmentOptions: {},
306
- placement: "above",
307
- invalidPlacement: null,
308
- welcome: true,
309
- stashSharpSShortcut: false,
310
- };
311
-
312
- const directPreset = normalizePreset(value, presets);
313
- if (directPreset) return { ...defaultConfig, preset: directPreset };
314
-
315
- if (!isRecord(value)) return defaultConfig;
316
-
317
- const customItems = normalizeCustomItems(value.customItems);
318
- const { disabledSegments, invalidDisabledSegments } = normalizeDisabledSegments(value.disabledSegments, customItems);
319
- const { layout, invalidLayoutSegments } = normalizeLayout(value.layout, customItems);
320
- const { placement, invalidPlacement } = normalizePlacement(value.placement);
321
-
322
- return {
323
- preset: normalizePreset(value.preset, presets) ?? defaultConfig.preset,
324
- customItems,
325
- fixedEditorPromptGlyph: typeof value.fixedEditorPromptGlyph === "string" ? value.fixedEditorPromptGlyph : defaultConfig.fixedEditorPromptGlyph,
326
- disabledSegments,
327
- invalidDisabledSegments,
328
- layout,
329
- invalidLayoutSegments,
330
- separator: normalizeSeparator(value.separator),
331
- segmentOptions: normalizeSegmentOptions(value),
332
- placement,
333
- invalidPlacement,
334
- welcome: value.welcome !== false,
335
- stashSharpSShortcut: value.stashSharpSShortcut === true,
336
- };
337
- }
338
-
339
- export function mergeSegmentsWithCustomItems(
340
- presetDef: PresetDef,
341
- customItems: readonly CustomStatusItem[],
342
- options: {
343
- layout?: StatusLineLayout | null;
344
- disabledSegments?: readonly StatusLineSegmentId[];
345
- } = {},
346
- ): {
347
- leftSegments: StatusLineSegmentId[];
348
- rightSegments: StatusLineSegmentId[];
349
- secondarySegments: StatusLineSegmentId[];
350
- } {
351
- const layout = options.layout ?? null;
352
- const explicitlyPlaced = new Set([
353
- ...(layout?.left ?? []),
354
- ...(layout?.right ?? []),
355
- ...(layout?.secondary ?? []),
356
- ]);
357
- const disabled = new Set(options.disabledSegments ?? []);
358
-
359
- const buildRow = (
360
- position: CustomItemPosition,
361
- configured: StatusLineSegmentId[] | undefined,
362
- presetSegments: readonly StatusLineSegmentId[],
363
- ): StatusLineSegmentId[] => {
364
- const segments = configured !== undefined
365
- ? [...configured]
366
- : presetSegments.filter((id) => !explicitlyPlaced.has(id));
367
-
368
- if (configured === undefined) {
369
- for (const item of customItems) {
370
- const segmentId: StatusLineSegmentId = `custom:${item.id}`;
371
- if (item.position === position && !explicitlyPlaced.has(segmentId)) {
372
- segments.push(segmentId);
373
- }
374
- }
375
- }
376
-
377
- return segments.filter((id) => !disabled.has(id));
378
- };
379
-
380
- return {
381
- leftSegments: buildRow("left", layout?.left, presetDef.leftSegments),
382
- rightSegments: buildRow("right", layout?.right, presetDef.rightSegments),
383
- secondarySegments: buildRow("secondary", layout?.secondary, presetDef.secondarySegments ?? []),
384
- };
385
- }
386
-
387
- export function nextPowerlineSettingWithPreset(existingPowerlineSetting: unknown, preset: StatusLinePreset): unknown {
388
- if (!isRecord(existingPowerlineSetting)) {
389
- return preset;
390
- }
391
- return { ...existingPowerlineSetting, preset };
392
- }
393
-
394
- export function nextPowerlineSettingWithOptions(
395
- existingPowerlineSetting: unknown,
396
- updates: Partial<Pick<PowerlineConfig, "welcome" | "stashSharpSShortcut" | "placement">>,
397
- currentPreset: StatusLinePreset,
398
- ): unknown {
399
- if (!isRecord(existingPowerlineSetting)) {
400
- return { preset: currentPreset, ...updates };
401
- }
402
- return { ...existingPowerlineSetting, ...updates };
403
- }
404
-
405
- export function collectHiddenExtensionStatusKeys(customItems: readonly CustomStatusItem[]): Set<string> {
406
- const hidden = new Set<string>();
407
- for (const item of customItems) {
408
- if (item.excludeFromExtensionStatuses) hidden.add(item.statusKey);
409
- }
410
- return hidden;
411
- }
412
-
413
- export function isNotificationExtensionStatus(value: string): boolean {
414
- return value.trimStart().startsWith("[");
415
- }
416
-
417
- export function getNotificationExtensionStatuses(
418
- statuses: ReadonlyMap<string, string>,
419
- hiddenKeys: ReadonlySet<string>,
420
- ): string[] {
421
- const notifications: string[] = [];
422
- for (const [statusKey, value] of statuses.entries()) {
423
- if (hiddenKeys.has(statusKey) || !value || !isNotificationExtensionStatus(value)) {
424
- continue;
425
- }
426
- notifications.push(value);
427
- }
428
- return notifications;
429
- }
430
-
431
- export function normalizeExtensionStatusValue(value: string): string | null {
432
- if (!value || visibleWidth(value) <= 0) {
433
- return null;
434
- }
435
-
436
- const stripped = value.replace(/(\x1b\[[0-9;]*m|\s|·|[|])+$/, "");
437
- return visibleWidth(stripped) > 0 ? stripped : null;
438
- }
439
-
440
- export function normalizeCompactExtensionStatus(value: string): string | null {
441
- if (isNotificationExtensionStatus(value)) {
442
- return null;
443
- }
444
-
445
- return normalizeExtensionStatusValue(value);
446
- }
@@ -1,102 +0,0 @@
1
- import type { ColorScheme, PresetDef, StatusLinePreset } from "./types.ts";
2
- import { getDefaultColors } from "./theme.ts";
3
-
4
- // Get base colors from theme.ts (single source of truth)
5
- const DEFAULT_COLORS: ColorScheme = getDefaultColors();
6
-
7
- // Minimal - more muted, less colorful
8
- const MINIMAL_COLORS: ColorScheme = {
9
- ...DEFAULT_COLORS,
10
- model: "text",
11
- path: "text",
12
- gitClean: "dim",
13
- };
14
-
15
- // Nerd - vibrant colors
16
- const NERD_COLORS: ColorScheme = {
17
- ...DEFAULT_COLORS,
18
- model: "accent",
19
- path: "success",
20
- tokens: "muted",
21
- cost: "warning",
22
- };
23
-
24
- export const PRESETS: Record<StatusLinePreset, PresetDef> = {
25
- default: {
26
- leftSegments: ["model", "thinking", "shell_mode", "path", "git", "queue", "context_pct", "cache_read", "cost"],
27
- rightSegments: [],
28
- secondarySegments: ["extension_statuses"],
29
- separator: "powerline-thin",
30
- colors: DEFAULT_COLORS,
31
- segmentOptions: {
32
- model: { showThinkingLevel: false },
33
- path: { mode: "basename" },
34
- git: { showBranch: true, showStaged: true, showUnstaged: true, showUntracked: true },
35
- },
36
- },
37
-
38
- minimal: {
39
- leftSegments: ["shell_mode", "path", "git"],
40
- rightSegments: ["context_pct"],
41
- separator: "slash",
42
- colors: MINIMAL_COLORS,
43
- segmentOptions: {
44
- path: { mode: "basename" },
45
- git: { showBranch: true, showStaged: false, showUnstaged: false, showUntracked: false },
46
- },
47
- },
48
-
49
- compact: {
50
- leftSegments: ["model", "shell_mode", "git"],
51
- rightSegments: ["queue", "cost", "context_pct"],
52
- separator: "powerline-thin",
53
- colors: DEFAULT_COLORS,
54
- segmentOptions: {
55
- model: { showThinkingLevel: false },
56
- git: { showBranch: true, showStaged: true, showUnstaged: true, showUntracked: false },
57
- },
58
- },
59
-
60
- full: {
61
- leftSegments: ["hostname", "model", "thinking", "shell_mode", "path", "git", "queue", "subagents"],
62
- rightSegments: ["token_in", "token_out", "cache_read", "cost", "context_pct", "time_spent", "time", "extension_statuses"],
63
- separator: "powerline",
64
- colors: DEFAULT_COLORS,
65
- segmentOptions: {
66
- model: { showThinkingLevel: false },
67
- path: { mode: "abbreviated", maxLength: 50 },
68
- git: { showBranch: true, showStaged: true, showUnstaged: true, showUntracked: true },
69
- time: { format: "24h", showSeconds: false },
70
- },
71
- },
72
-
73
- nerd: {
74
- leftSegments: ["hostname", "model", "thinking", "shell_mode", "path", "git", "queue", "session", "subagents"],
75
- rightSegments: ["token_in", "token_out", "cache_read", "cache_write", "cost", "context_pct", "context_total", "time_spent", "time", "extension_statuses"],
76
- separator: "powerline",
77
- colors: NERD_COLORS,
78
- segmentOptions: {
79
- model: { showThinkingLevel: false },
80
- path: { mode: "abbreviated", maxLength: 60 },
81
- git: { showBranch: true, showStaged: true, showUnstaged: true, showUntracked: true },
82
- time: { format: "24h", showSeconds: true },
83
- },
84
- },
85
-
86
- ascii: {
87
- leftSegments: ["model", "shell_mode", "path", "git"],
88
- rightSegments: ["queue", "token_total", "cost", "context_pct"],
89
- separator: "ascii",
90
- colors: MINIMAL_COLORS,
91
- segmentOptions: {
92
- model: { showThinkingLevel: true },
93
- path: { mode: "abbreviated", maxLength: 40 },
94
- git: { showBranch: true, showStaged: true, showUnstaged: true, showUntracked: true },
95
- },
96
- },
97
-
98
- };
99
-
100
- export function getPreset(name: StatusLinePreset): PresetDef {
101
- return PRESETS[name] ?? PRESETS.default;
102
- }