reigncode-app 1.3.2

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 (300) hide show
  1. package/AGENTS.md +30 -0
  2. package/Dockerfile +21 -0
  3. package/README.md +51 -0
  4. package/bunfig.toml +3 -0
  5. package/create-effect-simplification-spec.md +515 -0
  6. package/e2e/AGENTS.md +226 -0
  7. package/e2e/actions.ts +1018 -0
  8. package/e2e/app/home.spec.ts +24 -0
  9. package/e2e/app/navigation.spec.ts +10 -0
  10. package/e2e/app/palette.spec.ts +20 -0
  11. package/e2e/app/server-default.spec.ts +58 -0
  12. package/e2e/app/session.spec.ts +16 -0
  13. package/e2e/app/titlebar-history.spec.ts +120 -0
  14. package/e2e/commands/input-focus.spec.ts +15 -0
  15. package/e2e/commands/panels.spec.ts +33 -0
  16. package/e2e/commands/tab-close.spec.ts +32 -0
  17. package/e2e/files/file-open.spec.ts +31 -0
  18. package/e2e/files/file-tree.spec.ts +56 -0
  19. package/e2e/files/file-viewer.spec.ts +156 -0
  20. package/e2e/fixtures.ts +154 -0
  21. package/e2e/models/model-picker.spec.ts +48 -0
  22. package/e2e/models/models-visibility.spec.ts +61 -0
  23. package/e2e/projects/project-edit.spec.ts +43 -0
  24. package/e2e/projects/projects-close.spec.ts +54 -0
  25. package/e2e/projects/projects-switch.spec.ts +116 -0
  26. package/e2e/projects/workspace-new-session.spec.ts +94 -0
  27. package/e2e/projects/workspaces.spec.ts +375 -0
  28. package/e2e/prompt/context.spec.ts +95 -0
  29. package/e2e/prompt/prompt-async.spec.ts +76 -0
  30. package/e2e/prompt/prompt-drop-file-uri.spec.ts +22 -0
  31. package/e2e/prompt/prompt-drop-file.spec.ts +30 -0
  32. package/e2e/prompt/prompt-history.spec.ts +184 -0
  33. package/e2e/prompt/prompt-mention.spec.ts +26 -0
  34. package/e2e/prompt/prompt-multiline.spec.ts +24 -0
  35. package/e2e/prompt/prompt-shell.spec.ts +62 -0
  36. package/e2e/prompt/prompt-slash-open.spec.ts +22 -0
  37. package/e2e/prompt/prompt-slash-share.spec.ts +64 -0
  38. package/e2e/prompt/prompt-slash-terminal.spec.ts +18 -0
  39. package/e2e/prompt/prompt.spec.ts +55 -0
  40. package/e2e/selectors.ts +75 -0
  41. package/e2e/session/session-child-navigation.spec.ts +37 -0
  42. package/e2e/session/session-composer-dock.spec.ts +530 -0
  43. package/e2e/session/session-model-persistence.spec.ts +359 -0
  44. package/e2e/session/session-review.spec.ts +426 -0
  45. package/e2e/session/session-undo-redo.spec.ts +233 -0
  46. package/e2e/session/session.spec.ts +174 -0
  47. package/e2e/settings/settings-keybinds.spec.ts +389 -0
  48. package/e2e/settings/settings-models.spec.ts +122 -0
  49. package/e2e/settings/settings-providers.spec.ts +136 -0
  50. package/e2e/settings/settings.spec.ts +519 -0
  51. package/e2e/sidebar/sidebar-popover-actions.spec.ts +118 -0
  52. package/e2e/sidebar/sidebar-session-links.spec.ts +30 -0
  53. package/e2e/sidebar/sidebar.spec.ts +40 -0
  54. package/e2e/status/status-popover.spec.ts +94 -0
  55. package/e2e/terminal/terminal-init.spec.ts +28 -0
  56. package/e2e/terminal/terminal-reconnect.spec.ts +46 -0
  57. package/e2e/terminal/terminal-tabs.spec.ts +168 -0
  58. package/e2e/terminal/terminal.spec.ts +18 -0
  59. package/e2e/thinking-level.spec.ts +25 -0
  60. package/e2e/tsconfig.json +9 -0
  61. package/e2e/utils.ts +63 -0
  62. package/happydom.ts +75 -0
  63. package/index.html +23 -0
  64. package/package.json +77 -0
  65. package/playwright.config.ts +45 -0
  66. package/public/_headers +17 -0
  67. package/public/oc-theme-preload.js +35 -0
  68. package/script/e2e-local.ts +180 -0
  69. package/src/addons/serialize.test.ts +319 -0
  70. package/src/addons/serialize.ts +634 -0
  71. package/src/app.tsx +308 -0
  72. package/src/components/debug-bar.tsx +443 -0
  73. package/src/components/dialog-connect-provider.tsx +617 -0
  74. package/src/components/dialog-custom-provider-form.ts +158 -0
  75. package/src/components/dialog-custom-provider.test.ts +80 -0
  76. package/src/components/dialog-custom-provider.tsx +329 -0
  77. package/src/components/dialog-edit-project.tsx +255 -0
  78. package/src/components/dialog-fork.tsx +108 -0
  79. package/src/components/dialog-manage-models.tsx +101 -0
  80. package/src/components/dialog-release-notes.tsx +144 -0
  81. package/src/components/dialog-select-directory.tsx +392 -0
  82. package/src/components/dialog-select-file.tsx +466 -0
  83. package/src/components/dialog-select-mcp.tsx +107 -0
  84. package/src/components/dialog-select-model-unpaid.tsx +137 -0
  85. package/src/components/dialog-select-model.tsx +220 -0
  86. package/src/components/dialog-select-provider.tsx +86 -0
  87. package/src/components/dialog-select-server.tsx +649 -0
  88. package/src/components/dialog-settings.tsx +73 -0
  89. package/src/components/file-tree.test.ts +78 -0
  90. package/src/components/file-tree.tsx +507 -0
  91. package/src/components/link.tsx +26 -0
  92. package/src/components/model-tooltip.tsx +91 -0
  93. package/src/components/prompt-input/attachments.test.ts +44 -0
  94. package/src/components/prompt-input/attachments.ts +201 -0
  95. package/src/components/prompt-input/build-request-parts.test.ts +312 -0
  96. package/src/components/prompt-input/build-request-parts.ts +175 -0
  97. package/src/components/prompt-input/context-items.tsx +88 -0
  98. package/src/components/prompt-input/drag-overlay.tsx +25 -0
  99. package/src/components/prompt-input/editor-dom.test.ts +99 -0
  100. package/src/components/prompt-input/editor-dom.ts +148 -0
  101. package/src/components/prompt-input/files.ts +66 -0
  102. package/src/components/prompt-input/history.test.ts +153 -0
  103. package/src/components/prompt-input/history.ts +256 -0
  104. package/src/components/prompt-input/image-attachments.tsx +58 -0
  105. package/src/components/prompt-input/paste.ts +24 -0
  106. package/src/components/prompt-input/placeholder.test.ts +48 -0
  107. package/src/components/prompt-input/placeholder.ts +15 -0
  108. package/src/components/prompt-input/slash-popover.tsx +141 -0
  109. package/src/components/prompt-input/submit.test.ts +346 -0
  110. package/src/components/prompt-input/submit.ts +579 -0
  111. package/src/components/prompt-input.tsx +1595 -0
  112. package/src/components/server/server-row.tsx +130 -0
  113. package/src/components/session/index.ts +5 -0
  114. package/src/components/session/session-context-breakdown.test.ts +61 -0
  115. package/src/components/session/session-context-breakdown.ts +132 -0
  116. package/src/components/session/session-context-format.ts +20 -0
  117. package/src/components/session/session-context-metrics.test.ts +101 -0
  118. package/src/components/session/session-context-metrics.ts +82 -0
  119. package/src/components/session/session-context-tab.tsx +339 -0
  120. package/src/components/session/session-header.tsx +486 -0
  121. package/src/components/session/session-new-view.tsx +91 -0
  122. package/src/components/session/session-sortable-tab.tsx +70 -0
  123. package/src/components/session/session-sortable-terminal-tab.tsx +193 -0
  124. package/src/components/session-context-usage.tsx +122 -0
  125. package/src/components/settings-general.tsx +585 -0
  126. package/src/components/settings-keybinds.tsx +453 -0
  127. package/src/components/settings-list.tsx +5 -0
  128. package/src/components/settings-models.tsx +137 -0
  129. package/src/components/settings-providers.tsx +251 -0
  130. package/src/components/status-popover.tsx +419 -0
  131. package/src/components/terminal.tsx +653 -0
  132. package/src/components/titlebar-history.test.ts +63 -0
  133. package/src/components/titlebar-history.ts +57 -0
  134. package/src/components/titlebar.tsx +312 -0
  135. package/src/constants/file-picker.ts +89 -0
  136. package/src/context/command-keybind.test.ts +69 -0
  137. package/src/context/command.test.ts +25 -0
  138. package/src/context/command.tsx +437 -0
  139. package/src/context/comments.test.ts +186 -0
  140. package/src/context/comments.tsx +243 -0
  141. package/src/context/file/content-cache.ts +88 -0
  142. package/src/context/file/path.test.ts +360 -0
  143. package/src/context/file/path.ts +151 -0
  144. package/src/context/file/tree-store.ts +170 -0
  145. package/src/context/file/types.ts +41 -0
  146. package/src/context/file/view-cache.ts +146 -0
  147. package/src/context/file/watcher.test.ts +149 -0
  148. package/src/context/file/watcher.ts +53 -0
  149. package/src/context/file-content-eviction-accounting.test.ts +65 -0
  150. package/src/context/file.tsx +280 -0
  151. package/src/context/global-sdk.tsx +232 -0
  152. package/src/context/global-sync/bootstrap.ts +206 -0
  153. package/src/context/global-sync/child-store.test.ts +38 -0
  154. package/src/context/global-sync/child-store.ts +281 -0
  155. package/src/context/global-sync/event-reducer.test.ts +552 -0
  156. package/src/context/global-sync/event-reducer.ts +359 -0
  157. package/src/context/global-sync/eviction.ts +28 -0
  158. package/src/context/global-sync/queue.ts +83 -0
  159. package/src/context/global-sync/session-cache.test.ts +102 -0
  160. package/src/context/global-sync/session-cache.ts +62 -0
  161. package/src/context/global-sync/session-load.ts +25 -0
  162. package/src/context/global-sync/session-prefetch.test.ts +96 -0
  163. package/src/context/global-sync/session-prefetch.ts +100 -0
  164. package/src/context/global-sync/session-trim.test.ts +59 -0
  165. package/src/context/global-sync/session-trim.ts +56 -0
  166. package/src/context/global-sync/types.ts +133 -0
  167. package/src/context/global-sync/utils.ts +25 -0
  168. package/src/context/global-sync.test.ts +122 -0
  169. package/src/context/global-sync.tsx +408 -0
  170. package/src/context/highlights.tsx +233 -0
  171. package/src/context/language.tsx +248 -0
  172. package/src/context/layout-scroll.test.ts +64 -0
  173. package/src/context/layout-scroll.ts +126 -0
  174. package/src/context/layout.test.ts +69 -0
  175. package/src/context/layout.tsx +937 -0
  176. package/src/context/local.tsx +422 -0
  177. package/src/context/model-variant.test.ts +86 -0
  178. package/src/context/model-variant.ts +52 -0
  179. package/src/context/models.tsx +163 -0
  180. package/src/context/notification.tsx +373 -0
  181. package/src/context/permission-auto-respond.test.ts +102 -0
  182. package/src/context/permission-auto-respond.ts +51 -0
  183. package/src/context/permission.tsx +277 -0
  184. package/src/context/platform.tsx +99 -0
  185. package/src/context/prompt.tsx +297 -0
  186. package/src/context/sdk.tsx +49 -0
  187. package/src/context/server.tsx +295 -0
  188. package/src/context/settings.tsx +241 -0
  189. package/src/context/sync-optimistic.test.ts +123 -0
  190. package/src/context/sync.tsx +618 -0
  191. package/src/context/terminal-title.ts +51 -0
  192. package/src/context/terminal.test.ts +82 -0
  193. package/src/context/terminal.tsx +437 -0
  194. package/src/entry.tsx +144 -0
  195. package/src/env.d.ts +18 -0
  196. package/src/hooks/use-providers.ts +44 -0
  197. package/src/i18n/ar.ts +855 -0
  198. package/src/i18n/br.ts +867 -0
  199. package/src/i18n/bs.ts +943 -0
  200. package/src/i18n/da.ts +937 -0
  201. package/src/i18n/de.ts +879 -0
  202. package/src/i18n/en.ts +948 -0
  203. package/src/i18n/es.ts +950 -0
  204. package/src/i18n/fr.ts +878 -0
  205. package/src/i18n/ja.ts +861 -0
  206. package/src/i18n/ko.ts +860 -0
  207. package/src/i18n/no.ts +944 -0
  208. package/src/i18n/parity.test.ts +32 -0
  209. package/src/i18n/pl.ts +865 -0
  210. package/src/i18n/ru.ts +946 -0
  211. package/src/i18n/th.ts +933 -0
  212. package/src/i18n/tr.ts +952 -0
  213. package/src/i18n/zh.ts +930 -0
  214. package/src/i18n/zht.ts +925 -0
  215. package/src/index.css +29 -0
  216. package/src/index.ts +6 -0
  217. package/src/pages/directory-layout.tsx +88 -0
  218. package/src/pages/error.tsx +327 -0
  219. package/src/pages/home.tsx +131 -0
  220. package/src/pages/layout/deep-links.ts +50 -0
  221. package/src/pages/layout/helpers.test.ts +211 -0
  222. package/src/pages/layout/helpers.ts +98 -0
  223. package/src/pages/layout/inline-editor.tsx +126 -0
  224. package/src/pages/layout/sidebar-items.tsx +437 -0
  225. package/src/pages/layout/sidebar-project.tsx +384 -0
  226. package/src/pages/layout/sidebar-shell.tsx +125 -0
  227. package/src/pages/layout/sidebar-workspace.tsx +504 -0
  228. package/src/pages/layout.tsx +2509 -0
  229. package/src/pages/session/composer/index.ts +2 -0
  230. package/src/pages/session/composer/session-composer-region.tsx +255 -0
  231. package/src/pages/session/composer/session-composer-state.test.ts +128 -0
  232. package/src/pages/session/composer/session-composer-state.ts +249 -0
  233. package/src/pages/session/composer/session-followup-dock.tsx +109 -0
  234. package/src/pages/session/composer/session-permission-dock.tsx +74 -0
  235. package/src/pages/session/composer/session-question-dock.tsx +449 -0
  236. package/src/pages/session/composer/session-request-tree.ts +52 -0
  237. package/src/pages/session/composer/session-revert-dock.tsx +99 -0
  238. package/src/pages/session/composer/session-todo-dock.tsx +330 -0
  239. package/src/pages/session/file-tab-scroll.test.ts +40 -0
  240. package/src/pages/session/file-tab-scroll.ts +67 -0
  241. package/src/pages/session/file-tabs.tsx +456 -0
  242. package/src/pages/session/handoff.ts +36 -0
  243. package/src/pages/session/helpers.test.ts +181 -0
  244. package/src/pages/session/helpers.ts +198 -0
  245. package/src/pages/session/message-gesture.test.ts +62 -0
  246. package/src/pages/session/message-gesture.ts +21 -0
  247. package/src/pages/session/message-id-from-hash.ts +6 -0
  248. package/src/pages/session/message-timeline.tsx +1013 -0
  249. package/src/pages/session/review-tab.tsx +170 -0
  250. package/src/pages/session/session-layout.ts +20 -0
  251. package/src/pages/session/session-model-helpers.test.ts +51 -0
  252. package/src/pages/session/session-model-helpers.ts +16 -0
  253. package/src/pages/session/session-side-panel.tsx +453 -0
  254. package/src/pages/session/terminal-label.ts +16 -0
  255. package/src/pages/session/terminal-panel.test.ts +25 -0
  256. package/src/pages/session/terminal-panel.tsx +326 -0
  257. package/src/pages/session/use-session-commands.tsx +495 -0
  258. package/src/pages/session/use-session-hash-scroll.test.ts +16 -0
  259. package/src/pages/session/use-session-hash-scroll.ts +197 -0
  260. package/src/pages/session.tsx +1841 -0
  261. package/src/sst-env.d.ts +12 -0
  262. package/src/testing/model-selection.ts +80 -0
  263. package/src/testing/prompt.ts +56 -0
  264. package/src/testing/session-composer.ts +84 -0
  265. package/src/testing/terminal.ts +118 -0
  266. package/src/theme-preload.test.ts +46 -0
  267. package/src/utils/agent.ts +23 -0
  268. package/src/utils/aim.ts +138 -0
  269. package/src/utils/base64.ts +10 -0
  270. package/src/utils/comment-note.ts +88 -0
  271. package/src/utils/id.ts +99 -0
  272. package/src/utils/notification-click.test.ts +27 -0
  273. package/src/utils/notification-click.ts +13 -0
  274. package/src/utils/persist.test.ts +115 -0
  275. package/src/utils/persist.ts +476 -0
  276. package/src/utils/prompt.test.ts +44 -0
  277. package/src/utils/prompt.ts +203 -0
  278. package/src/utils/runtime-adapters.test.ts +62 -0
  279. package/src/utils/runtime-adapters.ts +39 -0
  280. package/src/utils/same.ts +6 -0
  281. package/src/utils/scoped-cache.test.ts +69 -0
  282. package/src/utils/scoped-cache.ts +104 -0
  283. package/src/utils/server-errors.test.ts +131 -0
  284. package/src/utils/server-errors.ts +80 -0
  285. package/src/utils/server-health.test.ts +123 -0
  286. package/src/utils/server-health.ts +91 -0
  287. package/src/utils/server.ts +22 -0
  288. package/src/utils/solid-dnd.tsx +49 -0
  289. package/src/utils/sound.ts +117 -0
  290. package/src/utils/terminal-writer.test.ts +64 -0
  291. package/src/utils/terminal-writer.ts +65 -0
  292. package/src/utils/time.ts +22 -0
  293. package/src/utils/uuid.test.ts +78 -0
  294. package/src/utils/uuid.ts +12 -0
  295. package/src/utils/worktree.test.ts +46 -0
  296. package/src/utils/worktree.ts +73 -0
  297. package/sst-env.d.ts +10 -0
  298. package/tsconfig.json +26 -0
  299. package/vite.config.ts +15 -0
  300. package/vite.js +26 -0
package/happydom.ts ADDED
@@ -0,0 +1,75 @@
1
+ import { GlobalRegistrator } from "@happy-dom/global-registrator"
2
+
3
+ GlobalRegistrator.register()
4
+
5
+ const originalGetContext = HTMLCanvasElement.prototype.getContext
6
+ // @ts-expect-error - we're overriding with a simplified mock
7
+ HTMLCanvasElement.prototype.getContext = function (contextType: string, _options?: unknown) {
8
+ if (contextType === "2d") {
9
+ return {
10
+ canvas: this,
11
+ fillStyle: "#000000",
12
+ strokeStyle: "#000000",
13
+ font: "12px monospace",
14
+ textAlign: "start",
15
+ textBaseline: "alphabetic",
16
+ globalAlpha: 1,
17
+ globalCompositeOperation: "source-over",
18
+ imageSmoothingEnabled: true,
19
+ lineWidth: 1,
20
+ lineCap: "butt",
21
+ lineJoin: "miter",
22
+ miterLimit: 10,
23
+ shadowBlur: 0,
24
+ shadowColor: "rgba(0, 0, 0, 0)",
25
+ shadowOffsetX: 0,
26
+ shadowOffsetY: 0,
27
+ fillRect: () => {},
28
+ strokeRect: () => {},
29
+ clearRect: () => {},
30
+ fillText: () => {},
31
+ strokeText: () => {},
32
+ measureText: (text: string) => ({ width: text.length * 8 }),
33
+ drawImage: () => {},
34
+ save: () => {},
35
+ restore: () => {},
36
+ scale: () => {},
37
+ rotate: () => {},
38
+ translate: () => {},
39
+ transform: () => {},
40
+ setTransform: () => {},
41
+ resetTransform: () => {},
42
+ createLinearGradient: () => ({ addColorStop: () => {} }),
43
+ createRadialGradient: () => ({ addColorStop: () => {} }),
44
+ createPattern: () => null,
45
+ beginPath: () => {},
46
+ closePath: () => {},
47
+ moveTo: () => {},
48
+ lineTo: () => {},
49
+ bezierCurveTo: () => {},
50
+ quadraticCurveTo: () => {},
51
+ arc: () => {},
52
+ arcTo: () => {},
53
+ ellipse: () => {},
54
+ rect: () => {},
55
+ fill: () => {},
56
+ stroke: () => {},
57
+ clip: () => {},
58
+ isPointInPath: () => false,
59
+ isPointInStroke: () => false,
60
+ getTransform: () => ({}),
61
+ getImageData: () => ({
62
+ data: new Uint8ClampedArray(0),
63
+ width: 0,
64
+ height: 0,
65
+ }),
66
+ putImageData: () => {},
67
+ createImageData: () => ({
68
+ data: new Uint8ClampedArray(0),
69
+ width: 0,
70
+ height: 0,
71
+ }),
72
+ } as unknown as CanvasRenderingContext2D
73
+ }
74
+ return originalGetContext.call(this, contextType as "2d", _options)
75
+ }
package/index.html ADDED
@@ -0,0 +1,23 @@
1
+ <!doctype html>
2
+ <html lang="en" style="background-color: var(--background-base)">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>OpenCode</title>
7
+ <link rel="icon" type="image/png" href="/favicon-96x96-v3.png" sizes="96x96" />
8
+ <link rel="icon" type="image/svg+xml" href="/favicon-v3.svg" />
9
+ <link rel="shortcut icon" href="/favicon-v3.ico" />
10
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-v3.png" />
11
+ <link rel="manifest" href="/site.webmanifest" />
12
+ <meta name="theme-color" content="#F8F7F7" />
13
+ <meta name="theme-color" content="#131010" media="(prefers-color-scheme: dark)" />
14
+ <meta property="og:image" content="/social-share.png" />
15
+ <meta property="twitter:image" content="/social-share.png" />
16
+ <script id="oc-theme-preload-script" src="/oc-theme-preload.js"></script>
17
+ </head>
18
+ <body class="antialiased overscroll-none text-12-regular overflow-hidden">
19
+ <noscript>You need to enable JavaScript to run this app.</noscript>
20
+ <div id="root" class="flex flex-col h-dvh p-px"></div>
21
+ <script src="/src/entry.tsx" type="module"></script>
22
+ </body>
23
+ </html>
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "reigncode-app",
3
+ "version": "1.3.2",
4
+ "description": "",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./dist/index.js",
9
+ "types": "./dist/index.d.ts"
10
+ },
11
+ "./vite": "./vite.js",
12
+ "./index.css": "./src/index.css"
13
+ },
14
+ "scripts": {
15
+ "typecheck": "tsgo -b",
16
+ "start": "vite",
17
+ "dev": "vite",
18
+ "build": "vite build",
19
+ "serve": "vite preview",
20
+ "test": "bun run test:unit",
21
+ "test:unit": "bun test --preload ./happydom.ts ./src",
22
+ "test:unit:watch": "bun test --watch --preload ./happydom.ts ./src",
23
+ "test:e2e": "playwright test",
24
+ "test:e2e:local": "bun script/e2e-local.ts",
25
+ "test:e2e:ui": "playwright test --ui",
26
+ "test:e2e:report": "playwright show-report e2e/playwright-report"
27
+ },
28
+ "license": "MIT",
29
+ "devDependencies": {
30
+ "@happy-dom/global-registrator": "20.0.11",
31
+ "@playwright/test": "1.57.0",
32
+ "@tailwindcss/vite": "catalog:",
33
+ "@tsconfig/bun": "1.0.9",
34
+ "@types/bun": "catalog:",
35
+ "@types/luxon": "catalog:",
36
+ "@types/node": "catalog:",
37
+ "@typescript/native-preview": "catalog:",
38
+ "typescript": "catalog:",
39
+ "vite": "catalog:",
40
+ "vite-plugin-icons-spritesheet": "3.0.1",
41
+ "vite-plugin-solid": "catalog:"
42
+ },
43
+ "dependencies": {
44
+ "@kobalte/core": "catalog:",
45
+ "@shikijs/transformers": "3.9.2",
46
+ "@solid-primitives/active-element": "2.1.3",
47
+ "@solid-primitives/audio": "1.4.2",
48
+ "@solid-primitives/event-bus": "1.1.2",
49
+ "@solid-primitives/i18n": "2.2.1",
50
+ "@solid-primitives/media": "2.3.3",
51
+ "@solid-primitives/resize-observer": "2.1.3",
52
+ "@solid-primitives/scroll": "2.1.3",
53
+ "@solid-primitives/storage": "catalog:",
54
+ "@solid-primitives/timer": "1.4.4",
55
+ "@solid-primitives/websocket": "1.3.1",
56
+ "@solidjs/meta": "catalog:",
57
+ "@solidjs/router": "catalog:",
58
+ "@tanstack/solid-query": "5.91.4",
59
+ "@thisbeyond/solid-dnd": "0.7.5",
60
+ "diff": "catalog:",
61
+ "effect": "catalog:",
62
+ "fuzzysort": "catalog:",
63
+ "ghostty-web": "github:anomalyco/ghostty-web#main",
64
+ "luxon": "catalog:",
65
+ "marked": "catalog:",
66
+ "marked-shiki": "catalog:",
67
+ "remeda": "catalog:",
68
+ "shiki": "catalog:",
69
+ "solid-js": "catalog:",
70
+ "solid-list": "catalog:",
71
+ "tailwindcss": "catalog:",
72
+ "virtua": "catalog:",
73
+ "zod": "catalog:",
74
+ "reigncode-sdk": "1.3.2",
75
+ "reign-ui": "1.3.2"
76
+ }
77
+ }
@@ -0,0 +1,45 @@
1
+ import { defineConfig, devices } from "@playwright/test"
2
+
3
+ const port = Number(process.env.PLAYWRIGHT_PORT ?? 3000)
4
+ const baseURL = process.env.PLAYWRIGHT_BASE_URL ?? `http://127.0.0.1:${port}`
5
+ const serverHost = process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1"
6
+ const serverPort = process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"
7
+ const command = `bun run dev -- --host 0.0.0.0 --port ${port}`
8
+ const reuse = !process.env.CI
9
+ const workers = Number(process.env.PLAYWRIGHT_WORKERS ?? (process.env.CI ? 5 : 0)) || undefined
10
+
11
+ export default defineConfig({
12
+ testDir: "./e2e",
13
+ outputDir: "./e2e/test-results",
14
+ timeout: 60_000,
15
+ expect: {
16
+ timeout: 10_000,
17
+ },
18
+ fullyParallel: process.env.PLAYWRIGHT_FULLY_PARALLEL === "1",
19
+ forbidOnly: !!process.env.CI,
20
+ retries: process.env.CI ? 2 : 0,
21
+ workers,
22
+ reporter: [["html", { outputFolder: "e2e/playwright-report", open: "never" }], ["line"]],
23
+ webServer: {
24
+ command,
25
+ url: baseURL,
26
+ reuseExistingServer: reuse,
27
+ timeout: 120_000,
28
+ env: {
29
+ VITE_REIGNCODE_SERVER_HOST: serverHost,
30
+ VITE_REIGNCODE_SERVER_PORT: serverPort,
31
+ },
32
+ },
33
+ use: {
34
+ baseURL,
35
+ trace: "on-first-retry",
36
+ screenshot: "only-on-failure",
37
+ video: "retain-on-failure",
38
+ },
39
+ projects: [
40
+ {
41
+ name: "chromium",
42
+ use: { ...devices["Desktop Chrome"] },
43
+ },
44
+ ],
45
+ })
@@ -0,0 +1,17 @@
1
+ /assets/*.js
2
+ Content-Type: application/javascript
3
+
4
+ /assets/*.mjs
5
+ Content-Type: application/javascript
6
+
7
+ /assets/*.css
8
+ Content-Type: text/css
9
+
10
+ /*.js
11
+ Content-Type: application/javascript
12
+
13
+ /*.mjs
14
+ Content-Type: application/javascript
15
+
16
+ /*.css
17
+ Content-Type: text/css
@@ -0,0 +1,35 @@
1
+ ;(function () {
2
+ var key = "opencode-theme-id"
3
+ var themeId = localStorage.getItem(key) || "oc-2"
4
+
5
+ if (themeId === "oc-1") {
6
+ themeId = "oc-2"
7
+ localStorage.setItem(key, themeId)
8
+ localStorage.removeItem("opencode-theme-css-light")
9
+ localStorage.removeItem("opencode-theme-css-dark")
10
+ }
11
+
12
+ var scheme = localStorage.getItem("opencode-color-scheme") || "system"
13
+ var isDark = scheme === "dark" || (scheme === "system" && matchMedia("(prefers-color-scheme: dark)").matches)
14
+ var mode = isDark ? "dark" : "light"
15
+
16
+ document.documentElement.dataset.theme = themeId
17
+ document.documentElement.dataset.colorScheme = mode
18
+
19
+ if (themeId === "oc-2") return
20
+
21
+ var css = localStorage.getItem("opencode-theme-css-" + mode)
22
+ if (css) {
23
+ var style = document.createElement("style")
24
+ style.id = "oc-theme-preload"
25
+ style.textContent =
26
+ ":root{color-scheme:" +
27
+ mode +
28
+ ";--text-mix-blend-mode:" +
29
+ (isDark ? "plus-lighter" : "multiply") +
30
+ ";" +
31
+ css +
32
+ "}"
33
+ document.head.appendChild(style)
34
+ }
35
+ })()
@@ -0,0 +1,180 @@
1
+ import fs from "node:fs/promises"
2
+ import net from "node:net"
3
+ import os from "node:os"
4
+ import path from "node:path"
5
+
6
+ async function freePort() {
7
+ return await new Promise<number>((resolve, reject) => {
8
+ const server = net.createServer()
9
+ server.once("error", reject)
10
+ server.listen(0, () => {
11
+ const address = server.address()
12
+ if (!address || typeof address === "string") {
13
+ server.close(() => reject(new Error("Failed to acquire a free port")))
14
+ return
15
+ }
16
+ server.close((err) => {
17
+ if (err) {
18
+ reject(err)
19
+ return
20
+ }
21
+ resolve(address.port)
22
+ })
23
+ })
24
+ })
25
+ }
26
+
27
+ async function waitForHealth(url: string) {
28
+ const timeout = Date.now() + 120_000
29
+ const errors: string[] = []
30
+ while (Date.now() < timeout) {
31
+ const result = await fetch(url)
32
+ .then((r) => ({ ok: r.ok, error: undefined }))
33
+ .catch((error) => ({
34
+ ok: false,
35
+ error: error instanceof Error ? error.message : String(error),
36
+ }))
37
+ if (result.ok) return
38
+ if (result.error) errors.push(result.error)
39
+ await new Promise((r) => setTimeout(r, 250))
40
+ }
41
+ const last = errors.length ? ` (last error: ${errors[errors.length - 1]})` : ""
42
+ throw new Error(`Timed out waiting for server health: ${url}${last}`)
43
+ }
44
+
45
+ const appDir = process.cwd()
46
+ const repoDir = path.resolve(appDir, "../..")
47
+ const opencodeDir = path.join(repoDir, "packages", "opencode")
48
+
49
+ const extraArgs = (() => {
50
+ const args = process.argv.slice(2)
51
+ if (args[0] === "--") return args.slice(1)
52
+ return args
53
+ })()
54
+
55
+ const [serverPort, webPort] = await Promise.all([freePort(), freePort()])
56
+
57
+ const sandbox = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-e2e-"))
58
+ const keepSandbox = process.env.REIGNCODE_E2E_KEEP_SANDBOX === "1"
59
+
60
+ const serverEnv = {
61
+ ...process.env,
62
+ REIGNCODE_DISABLE_SHARE: process.env.REIGNCODE_DISABLE_SHARE ?? "true",
63
+ REIGNCODE_DISABLE_LSP_DOWNLOAD: "true",
64
+ REIGNCODE_DISABLE_DEFAULT_PLUGINS: "true",
65
+ REIGNCODE_EXPERIMENTAL_DISABLE_FILEWATCHER: "true",
66
+ REIGNCODE_TEST_HOME: path.join(sandbox, "home"),
67
+ XDG_DATA_HOME: path.join(sandbox, "share"),
68
+ XDG_CACHE_HOME: path.join(sandbox, "cache"),
69
+ XDG_CONFIG_HOME: path.join(sandbox, "config"),
70
+ XDG_STATE_HOME: path.join(sandbox, "state"),
71
+ REIGNCODE_E2E_PROJECT_DIR: repoDir,
72
+ REIGNCODE_E2E_SESSION_TITLE: "E2E Session",
73
+ REIGNCODE_E2E_MESSAGE: "Seeded for UI e2e",
74
+ REIGNCODE_E2E_MODEL: "opencode/gpt-5-nano",
75
+ REIGNCODE_CLIENT: "app",
76
+ REIGNCODE_STRICT_CONFIG_DEPS: "true",
77
+ } satisfies Record<string, string>
78
+
79
+ const runnerEnv = {
80
+ ...serverEnv,
81
+ PLAYWRIGHT_SERVER_HOST: "127.0.0.1",
82
+ PLAYWRIGHT_SERVER_PORT: String(serverPort),
83
+ VITE_REIGNCODE_SERVER_HOST: "127.0.0.1",
84
+ VITE_REIGNCODE_SERVER_PORT: String(serverPort),
85
+ PLAYWRIGHT_PORT: String(webPort),
86
+ } satisfies Record<string, string>
87
+
88
+ let seed: ReturnType<typeof Bun.spawn> | undefined
89
+ let runner: ReturnType<typeof Bun.spawn> | undefined
90
+ let server: { stop: () => Promise<void> | void } | undefined
91
+ let inst: { Instance: { disposeAll: () => Promise<void> | void } } | undefined
92
+ let cleaned = false
93
+
94
+ const cleanup = async () => {
95
+ if (cleaned) return
96
+ cleaned = true
97
+
98
+ if (seed && seed.exitCode === null) seed.kill("SIGTERM")
99
+ if (runner && runner.exitCode === null) runner.kill("SIGTERM")
100
+
101
+ const jobs = [
102
+ inst?.Instance.disposeAll(),
103
+ server?.stop(),
104
+ keepSandbox ? undefined : fs.rm(sandbox, { recursive: true, force: true }),
105
+ ].filter(Boolean)
106
+ await Promise.allSettled(jobs)
107
+ }
108
+
109
+ const shutdown = (code: number, reason: string) => {
110
+ process.exitCode = code
111
+ void cleanup().finally(() => {
112
+ console.error(`e2e-local shutdown: ${reason}`)
113
+ process.exit(code)
114
+ })
115
+ }
116
+
117
+ const reportInternalError = (reason: string, error: unknown) => {
118
+ console.warn(`e2e-local ignored server error: ${reason}`)
119
+ console.warn(error)
120
+ }
121
+
122
+ process.once("SIGINT", () => shutdown(130, "SIGINT"))
123
+ process.once("SIGTERM", () => shutdown(143, "SIGTERM"))
124
+ process.once("SIGHUP", () => shutdown(129, "SIGHUP"))
125
+ process.once("uncaughtException", (error) => {
126
+ reportInternalError("uncaughtException", error)
127
+ })
128
+ process.once("unhandledRejection", (error) => {
129
+ reportInternalError("unhandledRejection", error)
130
+ })
131
+
132
+ let code = 1
133
+
134
+ try {
135
+ seed = Bun.spawn(["bun", "script/seed-e2e.ts"], {
136
+ cwd: opencodeDir,
137
+ env: serverEnv,
138
+ stdout: "inherit",
139
+ stderr: "inherit",
140
+ })
141
+
142
+ const seedExit = await seed.exited
143
+ if (seedExit !== 0) {
144
+ code = seedExit
145
+ } else {
146
+ Object.assign(process.env, serverEnv)
147
+ process.env.AGENT = "1"
148
+ process.env.OPENCODE = "1"
149
+ process.env.REIGNCODE_PID = String(process.pid)
150
+
151
+ const log = await import("../../opencode/src/util/log")
152
+ const install = await import("../../opencode/src/installation")
153
+ await log.Log.init({
154
+ print: true,
155
+ dev: install.Installation.isLocal(),
156
+ level: "WARN",
157
+ })
158
+
159
+ const servermod = await import("../../opencode/src/server/server")
160
+ inst = await import("../../opencode/src/project/instance")
161
+ server = servermod.Server.listen({ port: serverPort, hostname: "127.0.0.1" })
162
+ console.log(`opencode server listening on http://127.0.0.1:${serverPort}`)
163
+
164
+ await waitForHealth(`http://127.0.0.1:${serverPort}/global/health`)
165
+ runner = Bun.spawn(["bun", "test:e2e", ...extraArgs], {
166
+ cwd: appDir,
167
+ env: runnerEnv,
168
+ stdout: "inherit",
169
+ stderr: "inherit",
170
+ })
171
+ code = await runner.exited
172
+ }
173
+ } catch (error) {
174
+ console.error(error)
175
+ code = 1
176
+ } finally {
177
+ await cleanup()
178
+ }
179
+
180
+ process.exit(code)