@selesai/code 0.9.14 → 0.10.0

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