overmux 0.0.1 → 0.0.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 (193) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +7 -0
  3. package/dist/auth/.vite/manifest.json +11 -0
  4. package/dist/auth/assets/index-Bx8JhwVi.css +1 -0
  5. package/dist/auth/assets/index-CHIE7qYj.js +72 -0
  6. package/dist/auth/index.html +14 -0
  7. package/dist/bin.js +4504 -7870
  8. package/dist/bin.js.map +1 -0
  9. package/dist/docs/000-index.md +21 -0
  10. package/dist/docs/100-introduction/100-what-is-overmux.md +7 -0
  11. package/dist/docs/100-introduction/200-how-overmux-works.md +7 -0
  12. package/dist/docs/100-introduction/300-why-overmux.md +22 -0
  13. package/dist/docs/200-getting-started/100-install-and-run-overmux.md +51 -0
  14. package/dist/docs/200-getting-started/200-install-overmux-desktop.md +41 -0
  15. package/dist/docs/200-getting-started/300-install-overmux-pwa.mdx +92 -0
  16. package/dist/docs/200-getting-started/400-secure-with-https/100-choose-an-https-setup.md +14 -0
  17. package/dist/docs/200-getting-started/400-secure-with-https/200-tailscale-serve.md +44 -0
  18. package/dist/docs/200-getting-started/400-secure-with-https/300-cloudflare-tunnel.md +59 -0
  19. package/dist/docs/200-getting-started/400-secure-with-https/400-self-hosted-reverse-proxy.md +32 -0
  20. package/dist/docs/300-fundamentals/100-project-structure.md +3 -0
  21. package/dist/docs/300-fundamentals/200-configuration.md +3 -0
  22. package/dist/docs/300-fundamentals/300-theming.md +3 -0
  23. package/dist/docs/300-fundamentals/400-server.md +3 -0
  24. package/dist/docs/300-fundamentals/500-client.md +3 -0
  25. package/dist/docs/300-fundamentals/600-operations.md +3 -0
  26. package/dist/docs/300-fundamentals/700-resources.md +3 -0
  27. package/dist/docs/300-fundamentals/800-streams.md +3 -0
  28. package/dist/docs/300-fundamentals/900-authentication-and-security.md +3 -0
  29. package/dist/docs/400-reference/100-configuration.md +3 -0
  30. package/dist/docs/400-reference/200-server-api.md +3 -0
  31. package/dist/docs/400-reference/300-client-api.md +3 -0
  32. package/dist/docs/400-reference/400-cli/100-serve.md +33 -0
  33. package/dist/docs/400-reference/400-cli/200-auth.md +52 -0
  34. package/dist/docs/400-reference/400-cli/300-call.md +28 -0
  35. package/dist/docs/400-reference/400-cli/400-check.md +20 -0
  36. package/dist/docs/400-reference/400-cli/500-ai-context.md +102 -0
  37. package/dist/docs/400-reference/400-cli/600-docs.md +23 -0
  38. package/dist/docs/400-reference/400-cli/700-desktop.md +35 -0
  39. package/dist/docs/500-hosted-pages.md +31 -0
  40. package/dist/exports/client.d.ts +237 -0
  41. package/dist/exports/client.d.ts.map +1 -0
  42. package/dist/exports/client.js +1643 -0
  43. package/dist/exports/client.js.map +1 -0
  44. package/dist/exports/index-D3_Dpy_T.d.ts +155 -0
  45. package/dist/exports/index-D3_Dpy_T.d.ts.map +1 -0
  46. package/dist/exports/index.d.ts +2 -0
  47. package/dist/exports/index.js +49 -0
  48. package/dist/exports/index.js.map +1 -0
  49. package/dist/exports/notifications-kDp16bU_.js +56 -0
  50. package/dist/exports/notifications-kDp16bU_.js.map +1 -0
  51. package/dist/exports/server.d.ts +63 -0
  52. package/dist/exports/server.d.ts.map +1 -0
  53. package/dist/exports/server.js +1120 -0
  54. package/dist/exports/server.js.map +1 -0
  55. package/dist/exports/style.css +368 -0
  56. package/dist/internal/server/coordinator/server-child.d.ts +1 -0
  57. package/dist/internal/server/coordinator/server-child.js +3299 -0
  58. package/dist/internal/server/coordinator/server-child.js.map +1 -0
  59. package/docs/000-index.md +21 -0
  60. package/docs/100-introduction/100-what-is-overmux.md +7 -0
  61. package/docs/100-introduction/200-how-overmux-works.md +7 -0
  62. package/docs/100-introduction/300-why-overmux.md +22 -0
  63. package/docs/200-getting-started/100-install-and-run-overmux.md +51 -0
  64. package/docs/200-getting-started/200-install-overmux-desktop.md +41 -0
  65. package/docs/200-getting-started/300-install-overmux-pwa.mdx +92 -0
  66. package/docs/200-getting-started/400-secure-with-https/100-choose-an-https-setup.md +14 -0
  67. package/docs/200-getting-started/400-secure-with-https/200-tailscale-serve.md +44 -0
  68. package/docs/200-getting-started/400-secure-with-https/300-cloudflare-tunnel.md +59 -0
  69. package/docs/200-getting-started/400-secure-with-https/400-self-hosted-reverse-proxy.md +32 -0
  70. package/docs/300-fundamentals/100-project-structure.md +3 -0
  71. package/docs/300-fundamentals/200-configuration.md +3 -0
  72. package/docs/300-fundamentals/300-theming.md +3 -0
  73. package/docs/300-fundamentals/400-server.md +3 -0
  74. package/docs/300-fundamentals/500-client.md +3 -0
  75. package/docs/300-fundamentals/600-operations.md +3 -0
  76. package/docs/300-fundamentals/700-resources.md +3 -0
  77. package/docs/300-fundamentals/800-streams.md +3 -0
  78. package/docs/300-fundamentals/900-authentication-and-security.md +3 -0
  79. package/docs/400-reference/100-configuration.md +3 -0
  80. package/docs/400-reference/200-server-api.md +3 -0
  81. package/docs/400-reference/300-client-api.md +3 -0
  82. package/docs/400-reference/400-cli/100-serve.md +33 -0
  83. package/docs/400-reference/400-cli/200-auth.md +52 -0
  84. package/docs/400-reference/400-cli/300-call.md +28 -0
  85. package/docs/400-reference/400-cli/400-check.md +20 -0
  86. package/docs/400-reference/400-cli/500-ai-context.md +102 -0
  87. package/docs/400-reference/400-cli/600-docs.md +23 -0
  88. package/docs/400-reference/400-cli/700-desktop.md +35 -0
  89. package/docs/500-hosted-pages.md +31 -0
  90. package/package.json +59 -18
  91. package/src/internal/cli/app.ts +72 -0
  92. package/src/internal/cli/bin.ts +3 -0
  93. package/src/internal/cli/commands/ai.ts +44 -0
  94. package/src/internal/cli/commands/auth.ts +195 -0
  95. package/src/internal/cli/commands/call.ts +128 -0
  96. package/src/internal/cli/commands/check.ts +48 -0
  97. package/src/internal/cli/commands/desktop-installer.ts +446 -0
  98. package/src/internal/cli/commands/desktop-release.ts +190 -0
  99. package/src/internal/cli/commands/desktop.ts +47 -0
  100. package/src/internal/cli/commands/docs.ts +34 -0
  101. package/src/internal/cli/commands/serve.ts +322 -0
  102. package/src/internal/cli/environment.ts +54 -0
  103. package/src/internal/cli/login.ts +46 -0
  104. package/src/internal/cli/managed-vite.ts +267 -0
  105. package/src/internal/cli/parse-port.ts +8 -0
  106. package/src/internal/client/auth/auth-api.ts +53 -0
  107. package/src/internal/client/auth/auth-shell.css +74 -0
  108. package/src/internal/client/auth/auth-shell.tsx +167 -0
  109. package/src/internal/client/auth/entry.tsx +26 -0
  110. package/src/internal/client/auth/index.html +13 -0
  111. package/src/internal/client/background-notifications.ts +194 -0
  112. package/src/internal/client/browser-api.ts +97 -0
  113. package/src/internal/client/client-definition.ts +184 -0
  114. package/src/internal/client/commands.tsx +260 -0
  115. package/src/internal/client/host/browser-log-forwarding.ts +149 -0
  116. package/src/internal/client/host/hosted-pages/browser-notification-settings.tsx +118 -0
  117. package/src/internal/client/host/hosted-pages/hosted-page.css +87 -0
  118. package/src/internal/client/host/hosted-pages/hosted-page.tsx +9 -0
  119. package/src/internal/client/host/hosted-pages/logout-page.tsx +75 -0
  120. package/src/internal/client/host/hosted-pages/settings-page.tsx +45 -0
  121. package/src/internal/client/host/notification-forwarding.ts +22 -0
  122. package/src/internal/client/host/overmux-host.tsx +200 -0
  123. package/src/internal/client/host/recovery-screen.css +75 -0
  124. package/src/internal/client/host/recovery-screen.tsx +17 -0
  125. package/src/internal/client/host/update-popover.css +82 -0
  126. package/src/internal/client/host/update-popover.tsx +166 -0
  127. package/src/internal/client/index.ts +45 -0
  128. package/src/internal/client/overmux-react.ts +283 -0
  129. package/src/internal/client/shortcuts.tsx +373 -0
  130. package/src/internal/client/theme-scope.css +114 -0
  131. package/src/internal/client/theme-scope.tsx +107 -0
  132. package/src/internal/client/transport.ts +69 -0
  133. package/src/internal/client/websocket.ts +441 -0
  134. package/src/internal/server/auth/auth-http.ts +414 -0
  135. package/src/internal/server/auth/auth-service.ts +627 -0
  136. package/src/internal/server/auth/auth-shell-http.ts +90 -0
  137. package/src/internal/server/auth/instance-control.ts +381 -0
  138. package/src/internal/server/check-overmux.ts +364 -0
  139. package/src/internal/server/coordinator/ipc-protocol.ts +44 -0
  140. package/src/internal/server/coordinator/server-child.ts +108 -0
  141. package/src/internal/server/coordinator/server-coordinator.ts +262 -0
  142. package/src/internal/server/coordinator/update-watcher.ts +54 -0
  143. package/src/internal/server/http/authenticated-http-app-test-helper.ts +45 -0
  144. package/src/internal/server/http/background-notification-handlers.ts +83 -0
  145. package/src/internal/server/http/control-handlers.ts +44 -0
  146. package/src/internal/server/http/create-http-app.ts +53 -0
  147. package/src/internal/server/http/development-web-backend.ts +83 -0
  148. package/src/internal/server/http/operation-handler.ts +93 -0
  149. package/src/internal/server/http/request-logging.ts +34 -0
  150. package/src/internal/server/http/routes.ts +241 -0
  151. package/src/internal/server/http/runtime-manifest-handler.ts +12 -0
  152. package/src/internal/server/index.ts +16 -0
  153. package/src/internal/server/notifications/background-notification-payload.ts +74 -0
  154. package/src/internal/server/notifications/background-notification-service.ts +139 -0
  155. package/src/internal/server/notifications/background-notification-store.ts +162 -0
  156. package/src/internal/server/notifications/notification-service.ts +70 -0
  157. package/src/internal/server/notifications/private-json-file.ts +84 -0
  158. package/src/internal/server/paths.ts +13 -0
  159. package/src/internal/server/rate-limiter.ts +58 -0
  160. package/src/internal/server/runtime/create-runtime.ts +87 -0
  161. package/src/internal/server/runtime/resource-dependency-graph.ts +128 -0
  162. package/src/internal/server/runtime/runtime-lifecycle.ts +95 -0
  163. package/src/internal/server/runtime/runtime-operations.ts +78 -0
  164. package/src/internal/server/runtime/runtime-resources.ts +201 -0
  165. package/src/internal/server/runtime/runtime-streams.ts +130 -0
  166. package/src/internal/server/server-logger.ts +110 -0
  167. package/src/internal/server/server-startup-options.ts +51 -0
  168. package/src/internal/server/start-application-server.ts +412 -0
  169. package/src/internal/server/start-overmux-server.ts +26 -0
  170. package/src/internal/server/test-port.ts +23 -0
  171. package/src/internal/server/vite-websocket-proxy.ts +201 -0
  172. package/src/internal/server/websocket-connection.ts +586 -0
  173. package/src/internal/server/websocket-limits.ts +2 -0
  174. package/src/internal/server/websocket-server.ts +311 -0
  175. package/src/internal/shared/background-notifications.ts +37 -0
  176. package/src/internal/shared/index.ts +2 -0
  177. package/src/internal/shared/protocol.ts +317 -0
  178. package/src/internal/shared/routes.ts +3 -0
  179. package/src/public/ai-context.ts +44 -0
  180. package/src/public/client.ts +53 -0
  181. package/src/public/config.ts +287 -0
  182. package/src/public/contracts.ts +55 -0
  183. package/src/public/index.ts +57 -0
  184. package/src/public/notifications.ts +10 -0
  185. package/src/public/server.ts +16 -0
  186. package/dist/public/core.ts +0 -119
  187. package/dist/public/protocol.ts +0 -51
  188. package/dist/public/terminal.ts +0 -23
  189. package/dist/web/assets/index-DC___IUw.css +0 -2
  190. package/dist/web/assets/index-DF9Cptse.js +0 -74
  191. package/dist/web/assets/terminal-component-BrP-ENHg.css +0 -1
  192. package/dist/web/assets/terminal-component-DyLEbMrx.js +0 -36
  193. package/dist/web/index.html +0 -14
@@ -0,0 +1,102 @@
1
+ ---
2
+ title: "overmux ai context"
3
+ description: "Set up your coding agent and configure its Overmux context"
4
+ ---
5
+
6
+ # `overmux ai context`
7
+
8
+ Print version-aware Overmux guidance for coding agents as Markdown.
9
+
10
+ ## Usage
11
+
12
+ ```text
13
+ overmux ai context [--config path]
14
+ ```
15
+
16
+ ## Set up your coding agent
17
+
18
+ Add a short instruction that tells your agent how to load the context when it needs Overmux guidance:
19
+
20
+ <CodeBlockTabs defaultValue="agents">
21
+ <CodeBlockTabsList>
22
+ <CodeBlockTabsTrigger value="agents">AGENTS.md</CodeBlockTabsTrigger>
23
+ <CodeBlockTabsTrigger value="claude">CLAUDE.md</CodeBlockTabsTrigger>
24
+ </CodeBlockTabsList>
25
+ <CodeBlockTab value="agents">
26
+
27
+ ```bash
28
+ echo 'Run `overmux ai context` for help configuring Overmux.' >> AGENTS.md
29
+ ```
30
+
31
+ </CodeBlockTab>
32
+ <CodeBlockTab value="claude">
33
+
34
+ ```bash
35
+ echo 'Run `overmux ai context` for help configuring Overmux.' >> CLAUDE.md
36
+ ```
37
+
38
+ </CodeBlockTab>
39
+ </CodeBlockTabs>
40
+
41
+ ## Configure context snippets
42
+
43
+ Set `aiContextSnippets` in `$XDG_CONFIG_HOME/overmux/overmux.config.ts` to choose the guidance included in the command output:
44
+
45
+ ```ts
46
+ import {
47
+ coreAiContextSnippets,
48
+ defineOvermuxConfig,
49
+ } from "overmux";
50
+
51
+ export default defineOvermuxConfig({
52
+ aiContextSnippets: coreAiContextSnippets,
53
+ // ...
54
+ });
55
+ ```
56
+
57
+ When `aiContextSnippets` is omitted, Overmux uses `defaultAiContextSnippets`. Set it to an empty array to emit no context.
58
+
59
+ ## Options
60
+
61
+ | Flag | Description | Default |
62
+ | --- | --- | --- |
63
+ | `--config <path>, -c <path>` | Configuration file | `$XDG_CONFIG_HOME/overmux/overmux.config.ts` |
64
+
65
+ ## Preset groups
66
+
67
+ | Export | Included snippets |
68
+ | --- | --- |
69
+ | `defaultAiContextSnippets` | `package-source`, `tech-stack-recommendations` |
70
+ | `coreAiContextSnippets` | `package-source` |
71
+
72
+ ## Snippet reference
73
+
74
+ ### `package-source`
75
+
76
+ Export: `packageSourceSnippet`
77
+
78
+ Included in the core and default presets. Tells agents to inspect the documentation and TypeScript source shipped in installed Overmux packages so their guidance matches the versions used by the application.
79
+
80
+ ### `tech-stack-recommendations`
81
+
82
+ Export: `techStackRecommendationsSnippet`
83
+
84
+ Included in the default preset. Recommends pnpm, TanStack Router, shadcn/ui, and Zod while deferring to the application's established stack.
85
+
86
+ You can compose an explicit selection from the individual exports:
87
+
88
+ ```ts
89
+ import {
90
+ defineOvermuxConfig,
91
+ packageSourceSnippet,
92
+ techStackRecommendationsSnippet,
93
+ } from "overmux";
94
+
95
+ export default defineOvermuxConfig({
96
+ aiContextSnippets: [
97
+ packageSourceSnippet,
98
+ techStackRecommendationsSnippet,
99
+ ],
100
+ // ...
101
+ });
102
+ ```
@@ -0,0 +1,23 @@
1
+ ---
2
+ title: "overmux docs"
3
+ description: "Print the installed documentation directory"
4
+ ---
5
+
6
+ # `overmux docs`
7
+
8
+ Print the installed documentation directory.
9
+
10
+ ## Usage
11
+
12
+ ```text
13
+ overmux docs
14
+ ```
15
+
16
+ ## Example
17
+
18
+ ```console
19
+ $ overmux docs
20
+ /path/to/project/node_modules/overmux/docs
21
+ ```
22
+
23
+ The command prints the absolute path to the documentation shipped with the installed `overmux` package.
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: "overmux desktop"
3
+ ---
4
+
5
+ # `overmux desktop`
6
+
7
+ Install or upgrade the experimental macOS desktop preview. The desktop version is independent from the `overmux` npm package version.
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ overmux desktop install
13
+ ```
14
+
15
+ This command is available only on macOS arm64 and x64. It selects the newest stable `desktop-v*` GitHub release supporting the current architecture and installs it only at `~/Applications/Overmux.app`. It refuses to overwrite an existing bundle; use `upgrade` instead.
16
+
17
+ The macOS application is an **experimental unsigned, non-notarized preview**. macOS cannot verify its publisher, compatibility is not guaranteed, and no DMG is published. First install requires interactive confirmation:
18
+
19
+ ```sh
20
+ overmux desktop install --yes
21
+ ```
22
+
23
+ Use `--yes` only when automation has explicitly accepted the unsigned application risk.
24
+
25
+ ## Upgrade
26
+
27
+ ```sh
28
+ overmux desktop upgrade
29
+ ```
30
+
31
+ Upgrade verifies that the existing app has the `com.overmux.desktop` bundle identity before replacing it. A running app is asked to quit; an app that is not running is upgraded normally. The new app is launched, and the previous bundle is restored when replacement or launch fails where practical.
32
+
33
+ Both commands accept release assets only from the fixed official GitHub repository over HTTPS, verify asset size and `SHA256SUMS`, reject unsafe ZIP paths, validate the staged bundle, ad-hoc sign it if needed, and remove quarantine only from that bundle. They never use `sudo` or write to `/Applications`.
34
+
35
+ Checksums detect accidental corruption but are not independent publisher authentication because they are hosted with the artifacts. There is no cryptographically signed release manifest in this experimental distribution.
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Hosted pages
3
+ description: Link to Overmux-owned settings and logout pages.
4
+ ---
5
+
6
+ # Hosted pages
7
+
8
+ Overmux reserves two authenticated client paths above the user application router:
9
+
10
+ - `/_overmux/settings` provides notification and session settings.
11
+ - `/_overmux/logout` ends the current session and returns to login.
12
+
13
+ Use the neutral public constants when linking from userland or host integrations:
14
+
15
+ ```tsx
16
+ import {
17
+ createOvermuxSettingsPath,
18
+ overmuxLogoutPath,
19
+ } from "overmux";
20
+
21
+ const returnTo = `${location.pathname}${location.search}${location.hash}`;
22
+
23
+ <a href={createOvermuxSettingsPath(returnTo)}>Overmux settings</a>
24
+ <a href={overmuxLogoutPath}>Log out</a>
25
+ ```
26
+
27
+ These are full-document destinations. Do not send them through a userland client router.
28
+
29
+ `createOvermuxSettingsPath(returnTo)` includes a same-origin application path for **Back to Overmux**. Absolute URLs, protocol-relative URLs, login and API paths, and reserved `/_overmux` paths are discarded. Use `resolveOvermuxReturnTo()` when the validated return path is needed separately.
30
+
31
+ Browser notification controls live on the settings page. In the Electron desktop app, settings instead explains that delivery uses the desktop app and notification permissions are managed by the operating system.
package/package.json CHANGED
@@ -1,48 +1,89 @@
1
1
  {
2
2
  "name": "overmux",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "homepage": "https://github.com/richardgill/overmux",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/richardgill/overmux",
8
- "directory": "packages/overmux"
8
+ "directory": "packages/runtime/overmux"
9
9
  },
10
10
  "type": "module",
11
11
  "bin": {
12
12
  "overmux": "./dist/bin.js"
13
13
  },
14
+ "imports": {
15
+ "#server-child": "./dist/internal/server/coordinator/server-child.js"
16
+ },
14
17
  "exports": {
15
- ".": "./dist/public/core.ts",
16
- "./config": "./dist/public/core.ts",
17
- "./protocol": "./dist/public/protocol.ts",
18
- "./tabs/terminal": "./dist/public/terminal.ts"
18
+ ".": {
19
+ "types": "./dist/exports/index.d.ts",
20
+ "import": "./dist/exports/index.js"
21
+ },
22
+ "./client": {
23
+ "types": "./dist/exports/client.d.ts",
24
+ "import": "./dist/exports/client.js"
25
+ },
26
+ "./server": {
27
+ "types": "./dist/exports/server.d.ts",
28
+ "import": "./dist/exports/server.js"
29
+ }
19
30
  },
20
31
  "files": [
21
- "dist"
32
+ "dist",
33
+ "docs",
34
+ "src",
35
+ "!src/**/*.test.*",
36
+ "!src/**/fixtures",
37
+ "!src/**/testing",
38
+ "README.md",
39
+ "CHANGELOG.md"
22
40
  ],
23
41
  "dependencies": {
42
+ "@hono/node-server": "2.1.1",
43
+ "@stricli/core": "1.3.0",
44
+ "@tanstack/react-query": "5.90.12",
45
+ "@vercel/detect-agent": "1.2.5",
46
+ "ci-info": "4.4.0",
47
+ "es-module-lexer": "1.7.0",
48
+ "hono": "4.12.23",
49
+ "httpxy": "0.5.5",
24
50
  "jiti": "2.7.0",
25
- "zod": "4.4.3"
51
+ "typescript": "5.9.3",
52
+ "web-push": "3.6.7",
53
+ "ws": "8.21.3",
54
+ "zod": "4.4.3",
55
+ "@overmux/keybindings": "0.0.2"
26
56
  },
27
57
  "devDependencies": {
58
+ "@playwright/test": "1.58.0",
28
59
  "@types/node": "22.19.20",
29
- "tsx": "4.22.4",
30
- "vite": "8.0.0",
60
+ "@types/react": "19.2.17",
61
+ "@types/react-dom": "19.2.3",
62
+ "@types/web-push": "3.6.4",
63
+ "@types/ws": "8.18.1",
64
+ "react": "19.2.3",
65
+ "react-dom": "19.2.3",
66
+ "vite": "8.2.2",
31
67
  "vitest": "4.1.10",
32
- "@overmux/core": "0.0.0",
33
- "@overmux/tabs": "0.0.0",
34
- "@overmux/server": "0.0.0",
35
- "@overmux/web": "0.0.0",
36
- "@overmux/tsconfig": "0.0.0"
68
+ "@overmux/lib": "0.0.1",
69
+ "@overmux/shared": "0.0.1",
70
+ "@overmux/tsconfig": "0.0.1"
71
+ },
72
+ "peerDependencies": {
73
+ "react": "^19.0.0",
74
+ "react-dom": "^19.0.0",
75
+ "vite": "^8.2.1"
37
76
  },
38
77
  "publishConfig": {
39
78
  "access": "public"
40
79
  },
41
80
  "scripts": {
42
- "build": "vite build && tsx scripts/copy-web-assets.ts && tsx scripts/copy-public-api.ts",
43
- "dev": "tsx src/bin.ts --config ../../fixtures/overmux.config.ts",
44
- "start": "node dist/bin.js",
81
+ "build": "rm -rf dist && vite build && vite build --config vite.auth.config.ts && vp pack && node scripts/clean-declarations.ts && node scripts/add-client-styles.mjs && cp -R docs dist/docs",
82
+ "dev": "pnpm run dev:cli",
83
+ "dev:cli": "node --import jiti/register src/internal/cli/bin.ts serve",
84
+ "serve": "node dist/bin.js serve",
45
85
  "test": "vitest run",
86
+ "test:e2e": "node --import jiti/register scripts/run-playwright.ts",
46
87
  "typecheck": "tsc --noEmit"
47
88
  }
48
89
  }
@@ -0,0 +1,72 @@
1
+ import {
2
+ buildApplication,
3
+ buildRouteMap,
4
+ help,
5
+ run,
6
+ text_en,
7
+ } from "@stricli/core";
8
+
9
+ import { createAiRoute } from "./commands/ai";
10
+ import { authRoute } from "./commands/auth";
11
+ import { checkCommand } from "./commands/check";
12
+ import { callCommand } from "./commands/call";
13
+ import { desktopRoute } from "./commands/desktop";
14
+ import { createDocsCommand, resolveInstalledDocsRoot } from "./commands/docs";
15
+ import { serveCommand } from "./commands/serve";
16
+ import { detectCliEnvironment, type CliCommandContext } from "./environment";
17
+
18
+ export const createCliApp = (process = globalThis.process) =>
19
+ buildApplication<CliCommandContext>(
20
+ buildRouteMap<string, CliCommandContext>({
21
+ docs: { brief: "Serve, validate, or invoke Overmux operations" },
22
+ routes: {
23
+ ai: createAiRoute(process),
24
+ auth: authRoute,
25
+ check: checkCommand,
26
+ call: callCommand,
27
+ desktop: desktopRoute,
28
+ docs: createDocsCommand({
29
+ docsRoot: resolveInstalledDocsRoot(import.meta.url),
30
+ output: process.stdout,
31
+ }),
32
+ serve: serveCommand,
33
+ },
34
+ }),
35
+ {
36
+ name: "overmux",
37
+ localization: {
38
+ text: {
39
+ ...text_en,
40
+ commandErrorResult: (error) => error.message,
41
+ exceptionWhileRunningCommand: (error) =>
42
+ error instanceof Error ? error.message : String(error),
43
+ },
44
+ },
45
+ scanner: {
46
+ allowArgumentEscapeSequence: true,
47
+ caseStyle: "allow-kebab-for-camel",
48
+ },
49
+ },
50
+ {
51
+ help: help({
52
+ brief: "Show this help",
53
+ defaultForRouteMap: true,
54
+ formatting: {
55
+ caseStyle: "convert-camel-to-kebab",
56
+ onlyRequiredInUsageLine: false,
57
+ useAliasInUsageLine: false,
58
+ },
59
+ }),
60
+ },
61
+ );
62
+
63
+ export const runCli = async (
64
+ args: readonly string[],
65
+ process = globalThis.process,
66
+ ) => {
67
+ const environment = await detectCliEnvironment(process);
68
+ return run(createCliApp(process), args[0] === "--" ? args.slice(1) : args, {
69
+ environment,
70
+ process,
71
+ });
72
+ };
@@ -0,0 +1,3 @@
1
+ import { runCli } from "./app";
2
+
3
+ await runCli(process.argv.slice(2));
@@ -0,0 +1,44 @@
1
+ import { loadOvermuxConfig } from "@overmux/shared/node";
2
+ import { buildCommand, buildRouteMap } from "@stricli/core";
3
+
4
+ import {
5
+ composeAiContext,
6
+ defaultAiContextSnippets,
7
+ } from "../../../public/ai-context";
8
+ import { getDefaultConfigPath } from "../../server/paths";
9
+
10
+ type AiContextFlags = { config: string };
11
+
12
+ const printAiContext = async (
13
+ flags: AiContextFlags,
14
+ process: NodeJS.Process,
15
+ ) => {
16
+ const { config } = await loadOvermuxConfig({ configPath: flags.config });
17
+ process.stdout.write(
18
+ composeAiContext(config.aiContextSnippets ?? defaultAiContextSnippets),
19
+ );
20
+ };
21
+
22
+ const createAiContextCommand = (process: NodeJS.Process) =>
23
+ buildCommand({
24
+ func: (flags: AiContextFlags) => printAiContext(flags, process),
25
+ parameters: {
26
+ aliases: { c: "config" },
27
+ flags: {
28
+ config: {
29
+ brief: "Configuration file",
30
+ default: getDefaultConfigPath(),
31
+ kind: "parsed",
32
+ parse: String,
33
+ placeholder: "path",
34
+ },
35
+ },
36
+ },
37
+ docs: { brief: "Print the configured Overmux AI context" },
38
+ });
39
+
40
+ export const createAiRoute = (process: NodeJS.Process) =>
41
+ buildRouteMap({
42
+ docs: { brief: "Print Overmux AI context" },
43
+ routes: { context: createAiContextCommand(process) },
44
+ });
@@ -0,0 +1,195 @@
1
+ import { buildCommand, buildRouteMap } from "@stricli/core";
2
+
3
+ import {
4
+ discoverInstance,
5
+ sendControlRequest,
6
+ } from "../../server/auth/instance-control";
7
+ import type { CliCommandContext } from "../environment";
8
+ import { issueLoginGrant, printLoginGrant } from "../login";
9
+ import { parsePort } from "../parse-port";
10
+
11
+ type InstanceFlags = { port?: string };
12
+ type JsonInstanceFlags = InstanceFlags & { json?: boolean };
13
+ type LoginFlags = JsonInstanceFlags & { code?: boolean; url?: boolean };
14
+ type RevokeFlags = JsonInstanceFlags & { all?: boolean };
15
+
16
+ const selectedPort = (portValue?: string) => {
17
+ const port = portValue === undefined ? undefined : parsePort(portValue);
18
+ if (port instanceof Error) {
19
+ throw port;
20
+ }
21
+ return port;
22
+ };
23
+
24
+ const selectedInstance = (portValue?: string) =>
25
+ discoverInstance(selectedPort(portValue));
26
+
27
+ const printJson = (value: unknown) =>
28
+ process.stdout.write(`${JSON.stringify(value)}\n`);
29
+
30
+ const runLogin = async (flags: LoginFlags, process: NodeJS.Process) => {
31
+ const formats = [flags.code, flags.url, flags.json].filter(Boolean).length;
32
+ if (formats > 1) {
33
+ throw new Error("Only set one of: --code, --url, and --json");
34
+ }
35
+ const issued = await issueLoginGrant(selectedPort(flags.port));
36
+ if (flags.json) {
37
+ process.stdout.write(`${JSON.stringify(issued.login)}\n`);
38
+ return;
39
+ }
40
+ if (flags.code) {
41
+ process.stdout.write(`${issued.login.code}\n`);
42
+ return;
43
+ }
44
+ if (flags.url) {
45
+ process.stdout.write(`${issued.login.urls[0]}\n`);
46
+ return;
47
+ }
48
+ printLoginGrant({ ...issued, output: process });
49
+ };
50
+
51
+ function runLoginCommand(this: CliCommandContext, flags: LoginFlags) {
52
+ return runLogin(flags, this.process);
53
+ }
54
+
55
+ const instanceFlags = {
56
+ port: {
57
+ brief: "Running local server port",
58
+ kind: "parsed" as const,
59
+ optional: true as const,
60
+ parse: String,
61
+ },
62
+ };
63
+
64
+ export const authLoginCommand = buildCommand({
65
+ func: runLoginCommand,
66
+ parameters: {
67
+ flags: {
68
+ code: {
69
+ brief: "Print only the login code",
70
+ kind: "boolean",
71
+ optional: true,
72
+ },
73
+ json: {
74
+ brief: "Print machine-readable JSON",
75
+ kind: "boolean",
76
+ optional: true,
77
+ },
78
+ ...instanceFlags,
79
+ url: {
80
+ brief: "Print only the login URL",
81
+ kind: "boolean",
82
+ optional: true,
83
+ },
84
+ },
85
+ positional: { kind: "tuple", parameters: [] },
86
+ },
87
+ docs: { brief: "Create a single-use browser login grant" },
88
+ });
89
+
90
+ const runList = async (flags: JsonInstanceFlags) => {
91
+ const instance = await selectedInstance(flags.port);
92
+ const response = await sendControlRequest(instance, {
93
+ type: "list-sessions",
94
+ });
95
+ if (flags.json) {
96
+ printJson({ sessions: response.sessions });
97
+ return;
98
+ }
99
+ if (response.sessions.length === 0) {
100
+ process.stdout.write("No active sessions.\n");
101
+ return;
102
+ }
103
+ process.stdout.write("ID\tORIGIN\tCREATED\tLAST SEEN\tEXPIRES\n");
104
+ response.sessions.forEach((session) => {
105
+ process.stdout.write(
106
+ `${session.id}\t${session.origin ?? "unknown"}\t${session.createdAt}\t${session.lastSeenAt}\t${session.expiresAt ?? "never"}\n`,
107
+ );
108
+ });
109
+ };
110
+
111
+ export const authListCommand = buildCommand({
112
+ func: runList,
113
+ parameters: {
114
+ flags: {
115
+ json: {
116
+ brief: "Print machine-readable JSON",
117
+ kind: "boolean",
118
+ optional: true,
119
+ },
120
+ ...instanceFlags,
121
+ },
122
+ positional: { kind: "tuple", parameters: [] },
123
+ },
124
+ docs: { brief: "List active browser sessions" },
125
+ });
126
+
127
+ const runRevoke = async (flags: RevokeFlags, id?: string) => {
128
+ if (Boolean(id) === Boolean(flags.all)) {
129
+ throw new Error("Specify exactly one session ID or --all");
130
+ }
131
+ const instance = await selectedInstance(flags.port);
132
+ if (id) {
133
+ const response = await sendControlRequest(instance, {
134
+ id,
135
+ type: "revoke-session",
136
+ });
137
+ if (!response.revoked) {
138
+ throw new Error(`Session not found: ${id}`);
139
+ }
140
+ if (flags.json) {
141
+ printJson({ revoked: 1 });
142
+ return;
143
+ }
144
+ process.stdout.write(`Revoked session ${id}.\n`);
145
+ return;
146
+ }
147
+ const response = await sendControlRequest(instance, { type: "revoke-all" });
148
+ if (flags.json) {
149
+ printJson({ revoked: response.count });
150
+ return;
151
+ }
152
+ process.stdout.write(
153
+ `Revoked ${response.count} session${response.count === 1 ? "" : "s"}.\n`,
154
+ );
155
+ };
156
+
157
+ export const authRevokeCommand = buildCommand({
158
+ func: runRevoke,
159
+ parameters: {
160
+ flags: {
161
+ all: {
162
+ brief: "Revoke every active session",
163
+ kind: "boolean",
164
+ optional: true,
165
+ },
166
+ json: {
167
+ brief: "Print machine-readable JSON",
168
+ kind: "boolean",
169
+ optional: true,
170
+ },
171
+ ...instanceFlags,
172
+ },
173
+ positional: {
174
+ kind: "tuple",
175
+ parameters: [
176
+ {
177
+ brief: "Session ID",
178
+ optional: true,
179
+ parse: String,
180
+ placeholder: "id",
181
+ },
182
+ ],
183
+ },
184
+ },
185
+ docs: { brief: "Revoke browser authentication sessions" },
186
+ });
187
+
188
+ export const authRoute = buildRouteMap({
189
+ docs: { brief: "Manage CLI-issued browser authentication" },
190
+ routes: {
191
+ list: authListCommand,
192
+ login: authLoginCommand,
193
+ revoke: authRevokeCommand,
194
+ },
195
+ });