@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,313 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
2
- import { dirname, resolve } from "node:path";
3
- import { randomUUID } from "node:crypto";
4
- import { getAgentPath } from "../paths.ts";
5
- import type {
6
- CreateQueueItemInput,
7
- PowerlineQueueItem,
8
- QueueAliasMap,
9
- QueueContext,
10
- QueueIntent,
11
- QueueStatus,
12
- QueueSummary,
13
- QueueTarget,
14
- } from "./types.ts";
15
- import { ACTIVE_QUEUE_STATUSES } from "./types.ts";
16
-
17
- const STORE_DIR = "powerline-footer";
18
- const INBOX_FILE = "inbox.jsonl";
19
- const ALIASES_FILE = "projects.json";
20
- const LOCK_RETRY_MS = 25;
21
- const LOCK_TIMEOUT_MS = 2000;
22
-
23
- function isRecord(value: unknown): value is Record<string, unknown> {
24
- return typeof value === "object" && value !== null && !Array.isArray(value);
25
- }
26
-
27
- function normalizeCwd(cwd: string): string {
28
- return resolve(cwd);
29
- }
30
-
31
- function normalizeOptionalString(value: unknown): string | undefined {
32
- return typeof value === "string" && value.trim() ? value.trim() : undefined;
33
- }
34
-
35
- function normalizeTarget(value: unknown): QueueTarget | null {
36
- if (!isRecord(value)) return null;
37
- if (value.kind === "current-session") return { kind: "current-session" };
38
- if (value.kind === "global") return { kind: "global" };
39
- if (value.kind === "project" && typeof value.cwd === "string" && value.cwd.trim()) {
40
- const alias = normalizeOptionalString(value.alias);
41
- return alias
42
- ? { kind: "project", cwd: normalizeCwd(value.cwd), alias }
43
- : { kind: "project", cwd: normalizeCwd(value.cwd) };
44
- }
45
- return null;
46
- }
47
-
48
- function normalizeIntent(value: unknown): QueueIntent | null {
49
- return value === "steer" || value === "follow-up" || value === "post-compact"
50
- ? value
51
- : null;
52
- }
53
-
54
- function normalizeStatus(value: unknown): QueueStatus | null {
55
- return value === "queued" || value === "blocked" || value === "delivering" || value === "sent" || value === "failed"
56
- ? value
57
- : null;
58
- }
59
-
60
- function normalizeItem(value: unknown): PowerlineQueueItem | null {
61
- if (!isRecord(value)) return null;
62
- if (typeof value.id !== "string" || !value.id.trim()) return null;
63
- if (typeof value.text !== "string" || !value.text.trim()) return null;
64
- if (typeof value.createdAt !== "number" || !Number.isFinite(value.createdAt)) return null;
65
- if (typeof value.updatedAt !== "number" || !Number.isFinite(value.updatedAt)) return null;
66
- if (!isRecord(value.source) || typeof value.source.cwd !== "string" || !value.source.cwd.trim()) return null;
67
-
68
- const target = normalizeTarget(value.target);
69
- const intent = normalizeIntent(value.intent);
70
- const status = normalizeStatus(value.status);
71
- if (!target || !intent || !status) return null;
72
-
73
- const sessionId = normalizeOptionalString(value.source.sessionId);
74
- const error = normalizeOptionalString(value.error);
75
-
76
- return {
77
- id: value.id.trim(),
78
- text: value.text,
79
- createdAt: value.createdAt,
80
- updatedAt: value.updatedAt,
81
- source: sessionId
82
- ? { cwd: normalizeCwd(value.source.cwd), sessionId }
83
- : { cwd: normalizeCwd(value.source.cwd) },
84
- target,
85
- intent,
86
- status,
87
- ...(error ? { error } : {}),
88
- };
89
- }
90
-
91
- function readJsonObject(path: string): Record<string, unknown> {
92
- if (!existsSync(path)) return {};
93
- const parsed = JSON.parse(readFileSync(path, "utf-8"));
94
- return isRecord(parsed) ? parsed : {};
95
- }
96
-
97
- function sleepSync(ms: number): void {
98
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
99
- }
100
-
101
- export function getQueueStorePaths(): { inboxPath: string; aliasesPath: string } {
102
- return {
103
- inboxPath: getAgentPath(STORE_DIR, INBOX_FILE),
104
- aliasesPath: getAgentPath(STORE_DIR, ALIASES_FILE),
105
- };
106
- }
107
-
108
- export function createQueueItem(input: CreateQueueItemInput): PowerlineQueueItem {
109
- const now = input.now ?? Date.now();
110
- const sourceSessionId = input.source.sessionId?.trim();
111
- return {
112
- id: randomUUID().slice(0, 8),
113
- text: input.text,
114
- createdAt: now,
115
- updatedAt: now,
116
- source: sourceSessionId
117
- ? { cwd: normalizeCwd(input.source.cwd), sessionId: sourceSessionId }
118
- : { cwd: normalizeCwd(input.source.cwd) },
119
- target: normalizeTarget(input.target) ?? input.target,
120
- intent: input.intent,
121
- status: input.status ?? "queued",
122
- };
123
- }
124
-
125
- export class PowerlineQueueStore {
126
- private readonly inboxPath: string;
127
- private readonly aliasesPath: string;
128
-
129
- constructor(inboxPath: string = getQueueStorePaths().inboxPath, aliasesPath: string = getQueueStorePaths().aliasesPath) {
130
- this.inboxPath = inboxPath;
131
- this.aliasesPath = aliasesPath;
132
- }
133
-
134
- list(): PowerlineQueueItem[] {
135
- if (!existsSync(this.inboxPath)) return [];
136
- const lines = readFileSync(this.inboxPath, "utf-8").split("\n");
137
- const items: PowerlineQueueItem[] = [];
138
- for (const line of lines) {
139
- const trimmed = line.trim();
140
- if (!trimmed) continue;
141
- try {
142
- const item = normalizeItem(JSON.parse(trimmed));
143
- if (item) items.push(item);
144
- } catch {
145
- // Ignore malformed internal lines rather than breaking the footer during startup.
146
- }
147
- }
148
- return items.sort((a, b) => a.createdAt - b.createdAt);
149
- }
150
-
151
- add(input: CreateQueueItemInput): PowerlineQueueItem {
152
- const item = createQueueItem(input);
153
- return this.withStoreLock(() => {
154
- this.writeItems([...this.list(), item]);
155
- return item;
156
- });
157
- }
158
-
159
- get(idPrefix: string): PowerlineQueueItem | null {
160
- const normalized = idPrefix.trim();
161
- if (!normalized) return null;
162
- const matches = this.list().filter((item) => item.id === normalized || item.id.startsWith(normalized));
163
- return matches.length === 1 ? matches[0] : null;
164
- }
165
-
166
- update(id: string, updates: Partial<Omit<PowerlineQueueItem, "id" | "createdAt">>): PowerlineQueueItem | null {
167
- return this.withStoreLock(() => {
168
- let updated: PowerlineQueueItem | null = null;
169
- const next = this.list().map((item) => {
170
- if (item.id !== id) return item;
171
- updated = {
172
- ...item,
173
- ...updates,
174
- updatedAt: updates.updatedAt ?? Date.now(),
175
- };
176
- return updated;
177
- });
178
- if (updated) this.writeItems(next);
179
- return updated;
180
- });
181
- }
182
-
183
- clear(id: string): PowerlineQueueItem | null {
184
- return this.update(id, { status: "sent", error: undefined });
185
- }
186
-
187
- activeItems(context: QueueContext): PowerlineQueueItem[] {
188
- return this.list().filter((item) => isActiveForContext(item, context));
189
- }
190
-
191
- queuedDeliveryItems(context: QueueContext, intent?: QueueIntent): PowerlineQueueItem[] {
192
- return this.activeItems(context).filter((item) => (
193
- item.status === "queued" && (intent ? item.intent === intent : true)
194
- ));
195
- }
196
-
197
- summarize(context: QueueContext, compacting: boolean): QueueSummary {
198
- const queueItems = this.activeItems(context);
199
- const blockedItems = queueItems.filter((item) => item.status === "blocked" || item.status === "failed");
200
- const leading = [...blockedItems, ...queueItems][0] ?? null;
201
-
202
- return {
203
- queueCount: queueItems.length,
204
- blockedCount: blockedItems.length,
205
- compacting,
206
- leadingText: leading?.text ?? null,
207
- leadingIntent: leading?.intent ?? null,
208
- leadingStatus: leading?.status ?? null,
209
- };
210
- }
211
-
212
- readAliases(): QueueAliasMap {
213
- const parsed = readJsonObject(this.aliasesPath);
214
- const aliases: QueueAliasMap = {};
215
- for (const [alias, cwd] of Object.entries(parsed)) {
216
- if (/^[a-zA-Z0-9_-]+$/.test(alias) && typeof cwd === "string" && cwd.trim()) {
217
- aliases[alias] = normalizeCwd(cwd);
218
- }
219
- }
220
- return aliases;
221
- }
222
-
223
- setAlias(alias: string, cwd: string): QueueAliasMap {
224
- const normalizedAlias = alias.trim();
225
- if (!/^[a-zA-Z0-9_-]+$/.test(normalizedAlias)) {
226
- throw new Error("Alias must contain only letters, numbers, dashes, or underscores");
227
- }
228
- return this.withStoreLock(() => {
229
- const aliases = { ...this.readAliases(), [normalizedAlias]: normalizeCwd(cwd) };
230
- this.writeJson(this.aliasesPath, aliases);
231
- return aliases;
232
- });
233
- }
234
-
235
- resolveAlias(alias: string): string | null {
236
- return this.readAliases()[alias] ?? null;
237
- }
238
-
239
- private withStoreLock<T>(fn: () => T): T {
240
- mkdirSync(dirname(this.inboxPath), { recursive: true });
241
- const lockPath = `${this.inboxPath}.lock`;
242
- const startedAt = Date.now();
243
-
244
- while (true) {
245
- try {
246
- mkdirSync(lockPath);
247
- break;
248
- } catch (error) {
249
- const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
250
- if (code !== "EEXIST") throw error;
251
-
252
- if (Date.now() - startedAt >= LOCK_TIMEOUT_MS) {
253
- throw new Error("Timed out waiting for Powerline queue store lock");
254
- }
255
- sleepSync(LOCK_RETRY_MS);
256
- }
257
- }
258
-
259
- try {
260
- return fn();
261
- } finally {
262
- rmSync(lockPath, { recursive: true, force: true });
263
- }
264
- }
265
-
266
- private writeItems(items: readonly PowerlineQueueItem[]): void {
267
- mkdirSync(dirname(this.inboxPath), { recursive: true });
268
- const activeOrRecent = items
269
- .filter((item) => item.status !== "sent" || Date.now() - item.updatedAt < 24 * 60 * 60 * 1000)
270
- .map((item) => JSON.stringify(item))
271
- .join("\n");
272
- this.writeAtomic(this.inboxPath, activeOrRecent ? `${activeOrRecent}\n` : "");
273
- }
274
-
275
- private writeJson(path: string, value: unknown): void {
276
- mkdirSync(dirname(path), { recursive: true });
277
- this.writeAtomic(path, `${JSON.stringify(value, null, 2)}\n`);
278
- }
279
-
280
- private writeAtomic(path: string, content: string): void {
281
- const tempPath = `${path}.${process.pid}.${Date.now()}.tmp`;
282
- writeFileSync(tempPath, content, "utf-8");
283
- renameSync(tempPath, path);
284
- }
285
- }
286
-
287
- export function currentQueueContext(cwd: string, sessionId?: string): QueueContext {
288
- return sessionId?.trim()
289
- ? { cwd: normalizeCwd(cwd), sessionId: sessionId.trim() }
290
- : { cwd: normalizeCwd(cwd) };
291
- }
292
-
293
- export function isActiveForContext(item: PowerlineQueueItem, context: QueueContext): boolean {
294
- if (!ACTIVE_QUEUE_STATUSES.has(item.status)) return false;
295
- const currentCwd = normalizeCwd(context.cwd);
296
- if (item.target.kind === "global") return true;
297
- if (item.target.kind === "project") return normalizeCwd(item.target.cwd) === currentCwd;
298
- if (item.source.sessionId) return context.sessionId === item.source.sessionId;
299
- return item.source.cwd === currentCwd;
300
- }
301
-
302
- export function formatQueueDeliveryText(item: PowerlineQueueItem): string {
303
- return item.text;
304
- }
305
-
306
- export function parseCompactQueuedPrompt(text: string): string | null {
307
- const trimmed = text.trim();
308
- const match = /^\/compact\s+(.+)$/.exec(trimmed);
309
- if (!match) return null;
310
-
311
- const prompt = match[1].trim();
312
- return prompt ? prompt : null;
313
- }
@@ -1,53 +0,0 @@
1
- export type QueueIntent = "steer" | "follow-up" | "post-compact";
2
- export type QueueStatus = "queued" | "blocked" | "delivering" | "sent" | "failed";
3
-
4
- export type QueueTarget =
5
- | { kind: "current-session" }
6
- | { kind: "project"; cwd: string; alias?: string }
7
- | { kind: "global" };
8
-
9
- export interface QueueSource {
10
- cwd: string;
11
- sessionId?: string;
12
- }
13
-
14
- export interface PowerlineQueueItem {
15
- id: string;
16
- text: string;
17
- createdAt: number;
18
- updatedAt: number;
19
- source: QueueSource;
20
- target: QueueTarget;
21
- intent: QueueIntent;
22
- status: QueueStatus;
23
- error?: string;
24
- }
25
-
26
- export interface QueueAliasMap {
27
- [alias: string]: string;
28
- }
29
-
30
- export interface QueueSummary {
31
- queueCount: number;
32
- blockedCount: number;
33
- compacting: boolean;
34
- leadingText: string | null;
35
- leadingIntent: QueueIntent | null;
36
- leadingStatus: QueueStatus | null;
37
- }
38
-
39
- export interface CreateQueueItemInput {
40
- text: string;
41
- source: QueueSource;
42
- target: QueueTarget;
43
- intent: QueueIntent;
44
- status?: QueueStatus;
45
- now?: number;
46
- }
47
-
48
- export interface QueueContext {
49
- cwd: string;
50
- sessionId?: string;
51
- }
52
-
53
- export const ACTIVE_QUEUE_STATUSES = new Set<QueueStatus>(["queued", "blocked", "delivering", "failed"]);
@@ -1,29 +0,0 @@
1
- export interface RenderScheduler {
2
- schedule(delayMs?: number): void;
3
- cancel(): void;
4
- }
5
-
6
- export function createRenderScheduler(render: () => void, defaultDelayMs: number): RenderScheduler {
7
- let pending: { timer: ReturnType<typeof setTimeout>; deadline: number } | null = null;
8
-
9
- return {
10
- schedule(delayMs = defaultDelayMs) {
11
- const deadline = Date.now() + delayMs;
12
- if (pending) {
13
- if (deadline >= pending.deadline) return;
14
- clearTimeout(pending.timer);
15
- }
16
-
17
- const timer = setTimeout(() => {
18
- pending = null;
19
- render();
20
- }, delayMs);
21
- pending = { timer, deadline };
22
- },
23
- cancel() {
24
- if (!pending) return;
25
- clearTimeout(pending.timer);
26
- pending = null;
27
- },
28
- };
29
- }