@selesai/code 0.9.15 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +6 -9
  3. package/dist/defaults/models.json +2 -2
  4. package/dist/defaults/settings.json +3 -7
  5. package/dist/extensions/package.json +2 -4
  6. package/dist/extensions/pi-zentui/.editorconfig +12 -0
  7. package/dist/extensions/pi-zentui/.github/CODEOWNERS +1 -0
  8. package/dist/extensions/pi-zentui/.github/ISSUE_TEMPLATE/bug_report.yml +110 -0
  9. package/dist/extensions/pi-zentui/.github/ISSUE_TEMPLATE/config.yml +8 -0
  10. package/dist/extensions/pi-zentui/.github/ISSUE_TEMPLATE/config_question.yml +56 -0
  11. package/dist/extensions/pi-zentui/.github/ISSUE_TEMPLATE/feature_request.yml +63 -0
  12. package/dist/extensions/pi-zentui/.github/ISSUE_TEMPLATE/rendering_issue.yml +106 -0
  13. package/dist/extensions/pi-zentui/.github/ISSUE_TEMPLATE/runtime_detection.yml +103 -0
  14. package/dist/extensions/pi-zentui/.github/dependabot.yml +47 -0
  15. package/dist/extensions/pi-zentui/.github/pull_request_template.md +34 -0
  16. package/dist/extensions/pi-zentui/.github/release.yml +18 -0
  17. package/dist/extensions/pi-zentui/.github/workflows/ci.yml +79 -0
  18. package/dist/extensions/pi-zentui/.github/workflows/publish.yml +63 -0
  19. package/dist/extensions/pi-zentui/AGENTS.md +107 -0
  20. package/dist/extensions/pi-zentui/CONTRIBUTING.md +68 -0
  21. package/dist/extensions/pi-zentui/LICENSE +21 -0
  22. package/dist/extensions/pi-zentui/README.md +188 -0
  23. package/dist/extensions/pi-zentui/SECURITY.md +18 -0
  24. package/dist/extensions/pi-zentui/assets/main-cover.png +0 -0
  25. package/dist/extensions/pi-zentui/assets/screenshots/editor-accent-rail.png +0 -0
  26. package/dist/extensions/pi-zentui/assets/screenshots/editor-minimalist.png +0 -0
  27. package/dist/extensions/pi-zentui/assets/screenshots/editor-opencode-copy-friendly.png +0 -0
  28. package/dist/extensions/pi-zentui/assets/screenshots/editor-opencode.png +0 -0
  29. package/dist/extensions/pi-zentui/assets/screenshots/user-message-compact.png +0 -0
  30. package/dist/extensions/pi-zentui/assets/screenshots/user-message-framed-copy-friendly.png +0 -0
  31. package/dist/extensions/pi-zentui/assets/screenshots/user-message-framed.png +0 -0
  32. package/dist/extensions/pi-zentui/assets/screenshots/user-message-labeled.png +0 -0
  33. package/dist/extensions/pi-zentui/assets/zentui.png +0 -0
  34. package/dist/extensions/pi-zentui/biome.json +31 -0
  35. package/dist/extensions/pi-zentui/docs/configuration.md +509 -0
  36. package/dist/extensions/pi-zentui/docs/footer-format.md +162 -0
  37. package/dist/extensions/pi-zentui/extensions/zentui/accent-rail-editor.ts +99 -0
  38. package/dist/extensions/pi-zentui/extensions/zentui/accent-rail-layout-patch.ts +457 -0
  39. package/dist/extensions/pi-zentui/extensions/zentui/completion-menu.ts +157 -0
  40. package/dist/extensions/pi-zentui/extensions/zentui/config.ts +2100 -0
  41. package/dist/extensions/pi-zentui/extensions/zentui/editor-metadata-format.ts +321 -0
  42. package/dist/extensions/pi-zentui/extensions/zentui/editor-transfer.ts +73 -0
  43. package/dist/extensions/pi-zentui/extensions/zentui/extension-status.ts +89 -0
  44. package/dist/extensions/pi-zentui/extensions/zentui/footer-format.ts +364 -0
  45. package/dist/extensions/pi-zentui/extensions/zentui/footer-layout.ts +122 -0
  46. package/dist/extensions/pi-zentui/extensions/zentui/footer.ts +812 -0
  47. package/dist/extensions/pi-zentui/extensions/zentui/format.ts +568 -0
  48. package/dist/extensions/pi-zentui/extensions/zentui/git.ts +384 -0
  49. package/dist/extensions/pi-zentui/extensions/zentui/icons.ts +252 -0
  50. package/dist/extensions/pi-zentui/extensions/zentui/index.ts +1406 -0
  51. package/dist/extensions/pi-zentui/extensions/zentui/interaction-summary.ts +1049 -0
  52. package/dist/extensions/pi-zentui/extensions/zentui/live-context.ts +75 -0
  53. package/dist/extensions/pi-zentui/extensions/zentui/minimalist-editor.ts +463 -0
  54. package/dist/extensions/pi-zentui/extensions/zentui/package-version.ts +651 -0
  55. package/dist/extensions/pi-zentui/extensions/zentui/project-refresh.ts +120 -0
  56. package/dist/extensions/pi-zentui/extensions/zentui/project-state.ts +59 -0
  57. package/dist/extensions/pi-zentui/extensions/zentui/prototype-patch-registry.ts +166 -0
  58. package/dist/extensions/pi-zentui/extensions/zentui/repository-root.ts +98 -0
  59. package/dist/extensions/pi-zentui/extensions/zentui/runtime.ts +841 -0
  60. package/dist/extensions/pi-zentui/extensions/zentui/selector-border.ts +93 -0
  61. package/dist/extensions/pi-zentui/extensions/zentui/session-lifecycle.ts +60 -0
  62. package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +1796 -0
  63. package/dist/extensions/pi-zentui/extensions/zentui/settings-previews.ts +128 -0
  64. package/dist/extensions/pi-zentui/extensions/zentui/state.ts +94 -0
  65. package/dist/extensions/pi-zentui/extensions/zentui/style.ts +424 -0
  66. package/dist/extensions/pi-zentui/extensions/zentui/telemetry.ts +82 -0
  67. package/dist/extensions/pi-zentui/extensions/zentui/ui.ts +1290 -0
  68. package/dist/extensions/pi-zentui/extensions/zentui/user-message-osc.ts +248 -0
  69. package/dist/extensions/pi-zentui/extensions/zentui/user-message-styles.ts +215 -0
  70. package/dist/extensions/pi-zentui/extensions/zentui/user-message.ts +206 -0
  71. package/dist/extensions/pi-zentui/extensions/zentui/working-line-messages.ts +24 -0
  72. package/dist/extensions/pi-zentui/extensions/zentui/working-line-spinners.ts +54 -0
  73. package/dist/extensions/pi-zentui/extensions/zentui/working-line.ts +1433 -0
  74. package/dist/extensions/pi-zentui/package-lock.json +5311 -0
  75. package/dist/extensions/pi-zentui/package.json +60 -0
  76. package/dist/extensions/pi-zentui/test/accent-rail-editor.test.ts +232 -0
  77. package/dist/extensions/pi-zentui/test/accent-rail-layout-patch.test.ts +669 -0
  78. package/dist/extensions/pi-zentui/test/completion-menu.test.ts +265 -0
  79. package/dist/extensions/pi-zentui/test/config.test.ts +3119 -0
  80. package/dist/extensions/pi-zentui/test/editor-metadata-format.test.ts +405 -0
  81. package/dist/extensions/pi-zentui/test/editor-transfer.test.ts +260 -0
  82. package/dist/extensions/pi-zentui/test/editor-viewport-indicators.test.ts +1286 -0
  83. package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +7196 -0
  84. package/dist/extensions/pi-zentui/test/extension-status.test.ts +182 -0
  85. package/dist/extensions/pi-zentui/test/fixtures/starship-nerd-font-symbols.toml +172 -0
  86. package/dist/extensions/pi-zentui/test/footer-format.test.ts +431 -0
  87. package/dist/extensions/pi-zentui/test/footer-layout.test.ts +113 -0
  88. package/dist/extensions/pi-zentui/test/footer-repository-path.test.ts +123 -0
  89. package/dist/extensions/pi-zentui/test/format.test.ts +865 -0
  90. package/dist/extensions/pi-zentui/test/git.test.ts +212 -0
  91. package/dist/extensions/pi-zentui/test/icons.test.ts +69 -0
  92. package/dist/extensions/pi-zentui/test/interaction-summary.test.ts +1402 -0
  93. package/dist/extensions/pi-zentui/test/live-context-integration.test.ts +378 -0
  94. package/dist/extensions/pi-zentui/test/live-context.test.ts +139 -0
  95. package/dist/extensions/pi-zentui/test/minimalist-editor.test.ts +811 -0
  96. package/dist/extensions/pi-zentui/test/package-version.test.ts +321 -0
  97. package/dist/extensions/pi-zentui/test/project-refresh.test.ts +250 -0
  98. package/dist/extensions/pi-zentui/test/project-state.test.ts +159 -0
  99. package/dist/extensions/pi-zentui/test/repository-root.test.ts +108 -0
  100. package/dist/extensions/pi-zentui/test/responsive-dependencies.test.ts +825 -0
  101. package/dist/extensions/pi-zentui/test/runtime.test.ts +183 -0
  102. package/dist/extensions/pi-zentui/test/session-lifecycle.test.ts +40 -0
  103. package/dist/extensions/pi-zentui/test/settings-command.test.ts +1381 -0
  104. package/dist/extensions/pi-zentui/test/settings-previews.test.ts +347 -0
  105. package/dist/extensions/pi-zentui/test/state.test.ts +84 -0
  106. package/dist/extensions/pi-zentui/test/telemetry-lifecycle-integration.test.ts +276 -0
  107. package/dist/extensions/pi-zentui/test/telemetry.test.ts +105 -0
  108. package/dist/extensions/pi-zentui/test/turn-summary-lifecycle.integration.test.ts +327 -0
  109. package/dist/extensions/pi-zentui/test/user-message-osc.test.ts +164 -0
  110. package/dist/extensions/pi-zentui/test/user-message-styles.test.ts +292 -0
  111. package/dist/extensions/pi-zentui/test/working-line-lifecycle.integration.test.ts +730 -0
  112. package/dist/extensions/pi-zentui/test/working-line-messages.test.ts +34 -0
  113. package/dist/extensions/pi-zentui/test/working-line.test.ts +1990 -0
  114. package/dist/extensions/pi-zentui/tsconfig.json +16 -0
  115. package/dist/extensions/tps.test.ts +38 -0
  116. package/dist/extensions/{pi-powerline-footer/tps.ts → tps.ts} +4 -0
  117. package/dist/skills/design-references/SKILL.md +31 -0
  118. package/dist/skills/design-references/references/clickhouse/DESIGN.md +544 -0
  119. package/dist/themes/adventure.json +84 -0
  120. package/dist/themes/adwaita-dark.json +84 -0
  121. package/dist/themes/arcoiris.json +84 -0
  122. package/dist/themes/arthur.json +84 -0
  123. package/dist/themes/atom.json +84 -0
  124. package/dist/themes/aura.json +84 -0
  125. package/dist/themes/black-metal-bathory.json +84 -0
  126. package/dist/themes/black-metal-burzum.json +84 -0
  127. package/dist/themes/black-metal-khold.json +84 -0
  128. package/dist/themes/box.json +84 -0
  129. package/dist/themes/brogrammer.json +84 -0
  130. package/dist/themes/carbonfox.json +84 -0
  131. package/dist/themes/catppuccin-mocha.json +84 -0
  132. package/dist/themes/citruszest.json +84 -0
  133. package/dist/themes/cursor-dark.json +84 -0
  134. package/dist/themes/cutie-pro.json +84 -0
  135. package/dist/themes/dark-modern.json +84 -0
  136. package/dist/themes/dark-pastel.json +84 -0
  137. package/dist/themes/dimmed-monokai.json +84 -0
  138. package/dist/themes/doom-peacock.json +84 -0
  139. package/dist/themes/dracula-plus.json +84 -0
  140. package/dist/themes/dracula.json +80 -0
  141. package/dist/themes/earthsong.json +84 -0
  142. package/dist/themes/everforest-dark-hard.json +84 -0
  143. package/dist/themes/everforest-dark.json +80 -0
  144. package/dist/themes/fahrenheit.json +84 -0
  145. package/dist/themes/flatland.json +84 -0
  146. package/dist/themes/flexoki-dark.json +84 -0
  147. package/dist/themes/front-end-delight.json +84 -0
  148. package/dist/themes/fun-forrest.json +84 -0
  149. package/dist/themes/galizur.json +84 -0
  150. package/dist/themes/github-dark-colorblind.json +84 -0
  151. package/dist/themes/github-dark-high-contrast.json +84 -0
  152. package/dist/themes/glacier.json +84 -0
  153. package/dist/themes/gruber-darker.json +84 -0
  154. package/dist/themes/gruvbox-dark-hard.json +84 -0
  155. package/dist/themes/gruvbox-dark.json +84 -0
  156. package/dist/themes/gruvbox-material.json +84 -0
  157. package/dist/themes/guezwhoz.json +84 -0
  158. package/dist/themes/hacktober.json +84 -0
  159. package/dist/themes/hardcore.json +84 -0
  160. package/dist/themes/havn-skumring.json +84 -0
  161. package/dist/themes/ic-orange-ppl.json +84 -0
  162. package/dist/themes/iterm2-smoooooth.json +84 -0
  163. package/dist/themes/iterm2-tango-dark.json +84 -0
  164. package/dist/themes/japanesque.json +84 -0
  165. package/dist/themes/jellybeans.json +84 -0
  166. package/dist/themes/kanagawa-wave.json +84 -0
  167. package/dist/themes/kurokula.json +84 -0
  168. package/dist/themes/later-this-evening.json +84 -0
  169. package/dist/themes/lovelace.json +84 -0
  170. package/dist/themes/material-darker.json +84 -0
  171. package/dist/themes/matte-black.json +84 -0
  172. package/dist/themes/mellow.json +84 -0
  173. package/dist/themes/miasma.json +84 -0
  174. package/dist/themes/nord.json +80 -0
  175. package/dist/themes/nvim-dark.json +84 -0
  176. package/dist/themes/one-dark.json +80 -0
  177. package/dist/themes/popping-and-locking.json +84 -0
  178. package/dist/themes/rose-pine.json +80 -0
  179. package/dist/themes/sea-shells.json +84 -0
  180. package/dist/themes/sleepy-hollow.json +84 -0
  181. package/dist/themes/smyck.json +84 -0
  182. package/dist/themes/solarized-dark.json +80 -0
  183. package/dist/themes/tokyo-night.json +80 -0
  184. package/dist/themes/tomorrow-night-bright.json +84 -0
  185. package/dist/themes/tomorrow-night-burns.json +84 -0
  186. package/dist/themes/tomorrow-night.json +84 -0
  187. package/dist/themes/twilight.json +84 -0
  188. package/dist/themes/vague.json +84 -0
  189. package/dist/themes/vesper.json +84 -0
  190. package/dist/themes/xcode-dark-hc.json +84 -0
  191. package/docs/custom-provider.md +0 -1
  192. package/package.json +3 -3
  193. package/dist/extensions/auto-model/auto-model.test.ts +0 -18
  194. package/dist/extensions/auto-model/classifier.ts +0 -23
  195. package/dist/extensions/auto-model/config.ts +0 -51
  196. package/dist/extensions/auto-model/index.ts +0 -22
  197. package/dist/extensions/auto-model/lifecycle.test.ts +0 -24
  198. package/dist/extensions/pi-powerline-footer/.github/workflows/test.yml +0 -27
  199. package/dist/extensions/pi-powerline-footer/CHANGELOG.md +0 -687
  200. package/dist/extensions/pi-powerline-footer/CONTRIBUTING.md +0 -16
  201. package/dist/extensions/pi-powerline-footer/README.md +0 -513
  202. package/dist/extensions/pi-powerline-footer/banner.png +0 -0
  203. package/dist/extensions/pi-powerline-footer/bash-mode/completion.ts +0 -586
  204. package/dist/extensions/pi-powerline-footer/bash-mode/editor.ts +0 -583
  205. package/dist/extensions/pi-powerline-footer/bash-mode/history.ts +0 -204
  206. package/dist/extensions/pi-powerline-footer/bash-mode/shell-session.ts +0 -286
  207. package/dist/extensions/pi-powerline-footer/bash-mode/transcript.ts +0 -108
  208. package/dist/extensions/pi-powerline-footer/bash-mode/types.ts +0 -60
  209. package/dist/extensions/pi-powerline-footer/cd-command.ts +0 -190
  210. package/dist/extensions/pi-powerline-footer/colors.ts +0 -70
  211. package/dist/extensions/pi-powerline-footer/context-usage.ts +0 -156
  212. package/dist/extensions/pi-powerline-footer/currency-rates.ts +0 -142
  213. package/dist/extensions/pi-powerline-footer/editor-composition.ts +0 -32
  214. package/dist/extensions/pi-powerline-footer/editor-performance.ts +0 -99
  215. package/dist/extensions/pi-powerline-footer/git-status.ts +0 -329
  216. package/dist/extensions/pi-powerline-footer/guide.ts +0 -220
  217. package/dist/extensions/pi-powerline-footer/icons.ts +0 -190
  218. package/dist/extensions/pi-powerline-footer/index.ts +0 -3428
  219. package/dist/extensions/pi-powerline-footer/lifecycle.ts +0 -10
  220. package/dist/extensions/pi-powerline-footer/package.json +0 -49
  221. package/dist/extensions/pi-powerline-footer/paths.ts +0 -22
  222. package/dist/extensions/pi-powerline-footer/powerline-config.ts +0 -446
  223. package/dist/extensions/pi-powerline-footer/presets.ts +0 -102
  224. package/dist/extensions/pi-powerline-footer/queue/store.ts +0 -313
  225. package/dist/extensions/pi-powerline-footer/queue/types.ts +0 -53
  226. package/dist/extensions/pi-powerline-footer/render-scheduler.ts +0 -29
  227. package/dist/extensions/pi-powerline-footer/segments.ts +0 -570
  228. package/dist/extensions/pi-powerline-footer/separators.ts +0 -57
  229. package/dist/extensions/pi-powerline-footer/session-usage.ts +0 -44
  230. package/dist/extensions/pi-powerline-footer/shortcuts.ts +0 -61
  231. package/dist/extensions/pi-powerline-footer/tests/bash-mode.test.ts +0 -1905
  232. package/dist/extensions/pi-powerline-footer/tests/cd-command.test.ts +0 -144
  233. package/dist/extensions/pi-powerline-footer/tests/context-usage.test.ts +0 -156
  234. package/dist/extensions/pi-powerline-footer/tests/custom-items.test.ts +0 -344
  235. package/dist/extensions/pi-powerline-footer/tests/editor-composition.test.ts +0 -48
  236. package/dist/extensions/pi-powerline-footer/tests/editor-performance.test.ts +0 -43
  237. package/dist/extensions/pi-powerline-footer/tests/editor-responsiveness.test.ts +0 -136
  238. package/dist/extensions/pi-powerline-footer/tests/fixed-editor-border.test.ts +0 -39
  239. package/dist/extensions/pi-powerline-footer/tests/git-optional-locks.test.ts +0 -64
  240. package/dist/extensions/pi-powerline-footer/tests/git-status.test.ts +0 -92
  241. package/dist/extensions/pi-powerline-footer/tests/guide.test.ts +0 -129
  242. package/dist/extensions/pi-powerline-footer/tests/jump-shortcuts.test.ts +0 -116
  243. package/dist/extensions/pi-powerline-footer/tests/mode-aware-trigger.test.ts +0 -79
  244. package/dist/extensions/pi-powerline-footer/tests/paths.test.ts +0 -63
  245. package/dist/extensions/pi-powerline-footer/tests/queue-store.test.ts +0 -65
  246. package/dist/extensions/pi-powerline-footer/tests/quit-cursor.test.ts +0 -14
  247. package/dist/extensions/pi-powerline-footer/tests/remaining-regressions.test.ts +0 -173
  248. package/dist/extensions/pi-powerline-footer/tests/session-usage.test.ts +0 -47
  249. package/dist/extensions/pi-powerline-footer/tests/stash-shortcut.test.ts +0 -37
  250. package/dist/extensions/pi-powerline-footer/tests/thinking-segment.test.ts +0 -76
  251. package/dist/extensions/pi-powerline-footer/tests/token-stats.test.ts +0 -249
  252. package/dist/extensions/pi-powerline-footer/tests/tps.test.ts +0 -39
  253. package/dist/extensions/pi-powerline-footer/tests/usage-display.test.ts +0 -237
  254. package/dist/extensions/pi-powerline-footer/tests/welcome.test.ts +0 -199
  255. package/dist/extensions/pi-powerline-footer/tests/working-vibes.test.ts +0 -317
  256. package/dist/extensions/pi-powerline-footer/theme.example.json +0 -24
  257. package/dist/extensions/pi-powerline-footer/theme.json +0 -12
  258. package/dist/extensions/pi-powerline-footer/theme.ts +0 -241
  259. package/dist/extensions/pi-powerline-footer/token-stats.ts +0 -304
  260. package/dist/extensions/pi-powerline-footer/tsconfig.json +0 -13
  261. package/dist/extensions/pi-powerline-footer/types.ts +0 -235
  262. package/dist/extensions/pi-powerline-footer/welcome-dismiss.ts +0 -34
  263. package/dist/extensions/pi-powerline-footer/welcome.ts +0 -709
  264. package/dist/extensions/pi-powerline-footer/working-vibes.ts +0 -721
  265. package/dist/extensions/preview-tools-disabled.test.ts +0 -37
  266. package/dist/extensions/preview-tools-disabled.ts +0 -11
  267. package/dist/themes/powerline-footer/theme.json +0 -33
@@ -1,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
- }