overmux 0.0.4 → 0.0.6
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.
- package/CHANGELOG.md +43 -0
- package/README.md +16 -2
- package/dist/bin.js +140 -127
- package/dist/bin.js.map +1 -1
- package/dist/docs/000-index.md +2 -4
- package/dist/docs/100-introduction/200-how-overmux-works.md +126 -2
- package/dist/docs/100-introduction/{300-why-overmux.md → 300-why-i-built-overmux.md} +1 -1
- package/dist/docs/200-getting-started/100-install-and-run-overmux.md +2 -2
- package/dist/docs/200-getting-started/400-secure-with-https/200-tailscale-serve.md +3 -3
- package/dist/docs/200-getting-started/400-secure-with-https/300-cloudflare-tunnel.md +2 -2
- package/dist/docs/200-getting-started/400-secure-with-https/400-self-hosted-reverse-proxy.md +2 -2
- package/dist/docs/200-getting-started/500-set-up-overmux-with-packages.md +42 -0
- package/dist/docs/400-reference/100-project-structure.md +83 -0
- package/dist/docs/400-reference/200-configuration.md +257 -0
- package/dist/docs/400-reference/300-storage-locations.md +46 -0
- package/dist/docs/400-reference/400-authentication-and-security.md +37 -0
- package/dist/docs/400-reference/500-server/000-index.md +13 -0
- package/dist/docs/400-reference/500-server/100-resources.md +191 -0
- package/dist/docs/400-reference/500-server/200-operations.md +111 -0
- package/dist/docs/400-reference/500-server/300-streams.md +140 -0
- package/dist/docs/400-reference/500-server/400-notifications.md +32 -0
- package/dist/docs/400-reference/500-server/500-api.md +118 -0
- package/dist/docs/400-reference/600-client/000-index.md +9 -0
- package/dist/docs/400-reference/600-client/005-setting-up-your-ui.md +137 -0
- package/dist/docs/400-reference/600-client/007-deep-links.md +87 -0
- package/dist/docs/400-reference/600-client/010-commands.md +189 -0
- package/dist/docs/400-reference/600-client/020-shortcuts.md +171 -0
- package/dist/docs/400-reference/600-client/100-api.md +370 -0
- package/dist/docs/400-reference/600-client/200-theming.md +209 -0
- package/dist/docs/400-reference/600-client/300-tech-stack-recommendations.md +12 -0
- package/dist/docs/400-reference/{400-cli → 700-cli}/050-init.md +2 -4
- package/{docs/400-reference/400-cli → dist/docs/400-reference/700-cli}/100-serve.md +9 -4
- package/{docs/400-reference/400-cli → dist/docs/400-reference/700-cli}/200-auth.md +1 -4
- package/dist/docs/400-reference/{400-cli → 700-cli}/300-call.md +1 -4
- package/dist/docs/400-reference/{400-cli → 700-cli}/350-instance.md +1 -4
- package/dist/docs/400-reference/700-cli/600-docs.md +128 -0
- package/dist/docs/400-reference/{400-cli → 700-cli}/700-desktop.md +1 -3
- package/dist/docs/500-hosted-pages.md +0 -1
- package/dist/exports/client.d.ts +5 -14
- package/dist/exports/client.d.ts.map +1 -1
- package/dist/exports/client.js +141 -46
- package/dist/exports/client.js.map +1 -1
- package/dist/exports/{index-DS70rKzo.d.ts → index-Cz3xkCa4.d.ts} +50 -36
- package/dist/exports/index-Cz3xkCa4.d.ts.map +1 -0
- package/dist/exports/index.d.ts +1 -1
- package/dist/exports/index.js +19 -5
- package/dist/exports/index.js.map +1 -1
- package/dist/exports/{notifications-av0FK0yZ.js → notifications-BFAD3QQl.js} +29 -4
- package/dist/exports/notifications-BFAD3QQl.js.map +1 -0
- package/dist/exports/server.d.ts +1 -44
- package/dist/exports/server.d.ts.map +1 -1
- package/dist/exports/server.js +9 -1061
- package/dist/exports/server.js.map +1 -1
- package/dist/internal/server/coordinator/server-child.js +47 -43
- package/dist/internal/server/coordinator/server-child.js.map +1 -1
- package/docs/000-index.md +2 -4
- package/docs/100-introduction/200-how-overmux-works.md +126 -2
- package/docs/100-introduction/{300-why-overmux.md → 300-why-i-built-overmux.md} +1 -1
- package/docs/200-getting-started/100-install-and-run-overmux.md +2 -2
- package/docs/200-getting-started/400-secure-with-https/200-tailscale-serve.md +3 -3
- package/docs/200-getting-started/400-secure-with-https/300-cloudflare-tunnel.md +2 -2
- package/docs/200-getting-started/400-secure-with-https/400-self-hosted-reverse-proxy.md +2 -2
- package/docs/200-getting-started/500-set-up-overmux-with-packages.md +42 -0
- package/docs/400-reference/100-project-structure.md +83 -0
- package/docs/400-reference/200-configuration.md +257 -0
- package/docs/400-reference/300-storage-locations.md +46 -0
- package/docs/400-reference/400-authentication-and-security.md +37 -0
- package/docs/400-reference/500-server/000-index.md +13 -0
- package/docs/400-reference/500-server/100-resources.md +191 -0
- package/docs/400-reference/500-server/200-operations.md +111 -0
- package/docs/400-reference/500-server/300-streams.md +140 -0
- package/docs/400-reference/500-server/400-notifications.md +32 -0
- package/docs/400-reference/500-server/500-api.md +118 -0
- package/docs/400-reference/600-client/000-index.md +9 -0
- package/docs/400-reference/600-client/005-setting-up-your-ui.md +137 -0
- package/docs/400-reference/600-client/007-deep-links.md +87 -0
- package/docs/400-reference/600-client/010-commands.md +189 -0
- package/docs/400-reference/600-client/020-shortcuts.md +171 -0
- package/docs/400-reference/600-client/100-api.md +370 -0
- package/docs/400-reference/600-client/200-theming.md +209 -0
- package/docs/400-reference/600-client/300-tech-stack-recommendations.md +12 -0
- package/docs/400-reference/{400-cli → 700-cli}/050-init.md +2 -4
- package/{dist/docs/400-reference/400-cli → docs/400-reference/700-cli}/100-serve.md +9 -4
- package/{dist/docs/400-reference/400-cli → docs/400-reference/700-cli}/200-auth.md +1 -4
- package/docs/400-reference/{400-cli → 700-cli}/300-call.md +1 -4
- package/docs/400-reference/{400-cli → 700-cli}/350-instance.md +1 -4
- package/docs/400-reference/700-cli/600-docs.md +128 -0
- package/docs/400-reference/{400-cli → 700-cli}/700-desktop.md +1 -3
- package/docs/500-hosted-pages.md +0 -1
- package/package.json +4 -3
- package/src/internal/cli/app.ts +3 -5
- package/src/internal/cli/commands/docs-ai-context.ts +33 -0
- package/src/internal/cli/commands/docs.ts +19 -2
- package/src/internal/cli/commands/init-template.ts +1 -1
- package/src/internal/cli/commands/serve.ts +3 -0
- package/src/internal/cli/login.ts +9 -9
- package/src/internal/client/client-definition.ts +6 -8
- package/src/internal/client/host/deep-link-navigation.ts +75 -0
- package/src/internal/client/host/overmux-host.tsx +9 -0
- package/src/internal/client/index.ts +0 -6
- package/src/internal/client/overmux-react.ts +71 -40
- package/src/internal/server/auth/auth-service.ts +2 -2
- package/src/internal/server/auth/instance-control.ts +65 -14
- package/src/internal/server/coordinator/ipc-protocol.ts +0 -1
- package/src/internal/server/runtime/create-runtime.ts +5 -3
- package/src/internal/server/runtime/runtime-instance.ts +5 -4
- package/src/internal/server/runtime/runtime-operations.ts +9 -3
- package/src/internal/server/runtime/runtime-resources.ts +12 -32
- package/src/internal/server/runtime/runtime-streams.ts +5 -6
- package/src/internal/server/server-logger.ts +5 -10
- package/src/internal/server/server-startup-options.ts +5 -10
- package/src/internal/server/start-application-server.ts +4 -7
- package/src/public/ai-context.ts +7 -29
- package/src/public/client.ts +0 -6
- package/src/public/config.ts +156 -31
- package/src/public/server.ts +1 -16
- package/dist/docs/100-introduction/100-what-is-overmux.md +0 -7
- package/dist/docs/300-fundamentals/100-project-structure.md +0 -23
- package/dist/docs/300-fundamentals/200-configuration.md +0 -3
- package/dist/docs/300-fundamentals/300-theming.md +0 -54
- package/dist/docs/300-fundamentals/400-server.md +0 -3
- package/dist/docs/300-fundamentals/500-client.md +0 -3
- package/dist/docs/300-fundamentals/600-operations.md +0 -3
- package/dist/docs/300-fundamentals/700-resources.md +0 -3
- package/dist/docs/300-fundamentals/800-streams.md +0 -3
- package/dist/docs/300-fundamentals/900-authentication-and-security.md +0 -3
- package/dist/docs/400-reference/100-configuration.md +0 -23
- package/dist/docs/400-reference/200-server-api.md +0 -21
- package/dist/docs/400-reference/300-client-api.md +0 -39
- package/dist/docs/400-reference/400-cli/400-check.md +0 -20
- package/dist/docs/400-reference/400-cli/500-ai-context.md +0 -102
- package/dist/docs/400-reference/400-cli/600-docs.md +0 -23
- package/dist/exports/index-DS70rKzo.d.ts.map +0 -1
- package/dist/exports/notifications-av0FK0yZ.js.map +0 -1
- package/docs/100-introduction/100-what-is-overmux.md +0 -7
- package/docs/300-fundamentals/100-project-structure.md +0 -23
- package/docs/300-fundamentals/200-configuration.md +0 -3
- package/docs/300-fundamentals/300-theming.md +0 -54
- package/docs/300-fundamentals/400-server.md +0 -3
- package/docs/300-fundamentals/500-client.md +0 -3
- package/docs/300-fundamentals/600-operations.md +0 -3
- package/docs/300-fundamentals/700-resources.md +0 -3
- package/docs/300-fundamentals/800-streams.md +0 -3
- package/docs/300-fundamentals/900-authentication-and-security.md +0 -3
- package/docs/400-reference/100-configuration.md +0 -23
- package/docs/400-reference/200-server-api.md +0 -21
- package/docs/400-reference/300-client-api.md +0 -39
- package/docs/400-reference/400-cli/400-check.md +0 -20
- package/docs/400-reference/400-cli/500-ai-context.md +0 -102
- package/docs/400-reference/400-cli/600-docs.md +0 -23
- package/src/internal/cli/commands/ai.ts +0 -44
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Setting up your UI
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Your Overmux UI is a React application served and built with Vite. You own its layout, components, and styles; `OvermuxHost` provides the runtime for Overmux’s client APIs.
|
|
6
|
+
|
|
7
|
+
Run `overmux init` to generate a starter project with the UI setup below.
|
|
8
|
+
|
|
9
|
+
## File layout
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
overmux.config.ts
|
|
13
|
+
vite.config.ts
|
|
14
|
+
src/ui/
|
|
15
|
+
index.html
|
|
16
|
+
main.tsx
|
|
17
|
+
app.tsx
|
|
18
|
+
styles.css
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Configure Vite
|
|
22
|
+
|
|
23
|
+
Set your UI directory as Vite’s root and enable React:
|
|
24
|
+
|
|
25
|
+
```ts title="vite.config.ts"
|
|
26
|
+
import react from "@vitejs/plugin-react";
|
|
27
|
+
import { defineConfig } from "vite";
|
|
28
|
+
|
|
29
|
+
export default defineConfig({
|
|
30
|
+
root: "src/ui",
|
|
31
|
+
plugins: [react()],
|
|
32
|
+
build: {
|
|
33
|
+
emptyOutDir: true,
|
|
34
|
+
outDir: "../../dist",
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Point your Overmux configuration at this file, keeping your existing server and authentication settings:
|
|
40
|
+
|
|
41
|
+
```ts title="overmux.config.ts"
|
|
42
|
+
import { defineOvermuxConfig } from "overmux";
|
|
43
|
+
import server from "./src/server/index";
|
|
44
|
+
|
|
45
|
+
export default defineOvermuxConfig({
|
|
46
|
+
server,
|
|
47
|
+
auth: { mode: "cli-login" },
|
|
48
|
+
vite: "./vite.config.ts",
|
|
49
|
+
productionWebAssetsDir: "./dist",
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Vite’s output directory is relative to its UI root; `productionWebAssetsDir` points to the same directory from your Overmux configuration.
|
|
54
|
+
|
|
55
|
+
## The HTML entry point
|
|
56
|
+
|
|
57
|
+
Provide a root element and load your React entry point:
|
|
58
|
+
|
|
59
|
+
```html title="src/ui/index.html"
|
|
60
|
+
<!doctype html>
|
|
61
|
+
<html lang="en">
|
|
62
|
+
<head>
|
|
63
|
+
<meta charset="UTF-8" />
|
|
64
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
65
|
+
<title>My Overmux</title>
|
|
66
|
+
</head>
|
|
67
|
+
<body>
|
|
68
|
+
<div id="root"></div>
|
|
69
|
+
<script type="module" src="/main.tsx"></script>
|
|
70
|
+
</body>
|
|
71
|
+
</html>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Mount OvermuxHost
|
|
75
|
+
|
|
76
|
+
Mount your client definition inside `OvermuxHost`. It supplies the runtime required by hooks such as `useCommand` and `useCommands`.
|
|
77
|
+
|
|
78
|
+
```tsx title="src/ui/main.tsx"
|
|
79
|
+
import { OvermuxHost } from "overmux/client";
|
|
80
|
+
import { createRoot } from "react-dom/client";
|
|
81
|
+
|
|
82
|
+
import { client } from "./app";
|
|
83
|
+
import "./styles.css";
|
|
84
|
+
|
|
85
|
+
const root = document.querySelector("#root");
|
|
86
|
+
if (!root) {
|
|
87
|
+
throw new Error("Missing root element");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
createRoot(root).render(<OvermuxHost definition={client} />);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Define your client
|
|
94
|
+
|
|
95
|
+
Use `defineOvermuxClient` to connect your root React component and command registry:
|
|
96
|
+
|
|
97
|
+
```tsx title="src/ui/app.tsx"
|
|
98
|
+
import { defineOvermuxClient } from "overmux/client";
|
|
99
|
+
|
|
100
|
+
const App = () => <main>My Overmux UI</main>;
|
|
101
|
+
|
|
102
|
+
export const client = defineOvermuxClient({
|
|
103
|
+
component: App,
|
|
104
|
+
commands: {},
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`App` is an ordinary React component. Add your own components, state, and layout, or compose components from ecosystem packages.
|
|
109
|
+
|
|
110
|
+
Start with an empty command registry. See [Commands](./commands) when you want named actions for menus, command palettes, or keyboard shortcuts.
|
|
111
|
+
|
|
112
|
+
## Add styles
|
|
113
|
+
|
|
114
|
+
Import your application CSS from `main.tsx`:
|
|
115
|
+
|
|
116
|
+
```css title="src/ui/styles.css"
|
|
117
|
+
body {
|
|
118
|
+
margin: 0;
|
|
119
|
+
font-family: system-ui, sans-serif;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
main {
|
|
123
|
+
padding: 1rem;
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Individual ecosystem components may require additional stylesheet imports.
|
|
128
|
+
|
|
129
|
+
## Run your Overmux server
|
|
130
|
+
|
|
131
|
+
Run your instance through Overmux so the UI has access to its server:
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
overmux serve --config ./overmux.config.ts
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Open the UI URL shown by the server. Vite updates the UI as you edit your React components and styles.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Deep links
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Your Overmux UI is a website, so each page has a URL. Deep links let you open those same routes in a specific Overmux instance using `overmux://` instead of an `http://` web address.
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
overmux://work-laptop/my-page?tab=logs
|
|
9
|
+
instance UI route
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Instances
|
|
13
|
+
|
|
14
|
+
An **instance** is one Overmux server. Its ID defaults to `<hostname>-<port>`. Set [`instanceId`](../200-configuration.md#instanceid) in `overmux.config.ts` to give it a stable identity.
|
|
15
|
+
|
|
16
|
+
The instance ID is not a network address. Desktop remembers how to reach an instance when you connect to it.
|
|
17
|
+
|
|
18
|
+
Run [`overmux instance --json`](../700-cli/350-instance.md) to get the running server’s `instanceId` and `deepLinkPrefix`.
|
|
19
|
+
|
|
20
|
+
## Creating links
|
|
21
|
+
|
|
22
|
+
Append your Overmux UI’s route to the instance’s deep-link prefix.
|
|
23
|
+
|
|
24
|
+
Server handlers receive `instance` through their context argument:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { defineOperation } from "overmux/server";
|
|
28
|
+
import { z } from "zod";
|
|
29
|
+
|
|
30
|
+
export const getPageLink = defineOperation({
|
|
31
|
+
input: z.void(),
|
|
32
|
+
output: z.string(),
|
|
33
|
+
handle: (_input, { instance }) =>
|
|
34
|
+
`${instance.getDeepLinkPrefix()}/my-page?tab=logs`,
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
In React, use `useInstance` from your `createOvermuxHooks` setup. It re-renders when the server’s identity becomes available or changes:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { useInstance } from "./overmux";
|
|
42
|
+
|
|
43
|
+
const PageLink = () => {
|
|
44
|
+
const instance = useInstance();
|
|
45
|
+
if (!instance) return null;
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<a href={`${instance.deepLinkPrefix}/my-page?tab=logs`}>
|
|
49
|
+
View logs
|
|
50
|
+
</a>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`useInstance()` returns `undefined` until the server identifies itself.
|
|
56
|
+
|
|
57
|
+
## Routing in your Overmux UI
|
|
58
|
+
|
|
59
|
+
Your Overmux UI owns routing. We recommend [TanStack Router](https://tanstack.com/router/latest) for routing with React. See [Tech stack recommendations](./300-tech-stack-recommendations.md).
|
|
60
|
+
|
|
61
|
+
Overmux passes the path, query, and fragment to your client’s `navigate` callback. Connect this callback to your router to navigate without reloading the page. Without that callback, Overmux loads the route normally.
|
|
62
|
+
|
|
63
|
+
With an existing TanStack Router instance exported from `./router`:
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
import { RouterProvider } from "@tanstack/react-router";
|
|
67
|
+
import { defineOvermuxClient } from "overmux/client";
|
|
68
|
+
import { router } from "./router";
|
|
69
|
+
|
|
70
|
+
const App = () => <RouterProvider router={router} />;
|
|
71
|
+
|
|
72
|
+
export const client = defineOvermuxClient({
|
|
73
|
+
commands: {},
|
|
74
|
+
component: App,
|
|
75
|
+
navigate: (route) => router.navigate({ href: route }),
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
For `overmux://work-laptop/my-page?tab=logs#latest`, `route` is `/my-page?tab=logs#latest`.
|
|
80
|
+
|
|
81
|
+
## Opening links
|
|
82
|
+
|
|
83
|
+
- **Inside your Overmux UI or PWA:** same-instance links navigate locally. No OS protocol handler is needed.
|
|
84
|
+
- **Desktop:** opening a link launches or focuses Desktop. Links can also switch to another known instance after confirmation. Connect to that instance first so Desktop knows its address.
|
|
85
|
+
- **Browser/PWA:** links to different or not-yet-discovered instances are blocked.
|
|
86
|
+
|
|
87
|
+
Installing the PWA does not register it as an OS-wide `overmux://` handler. Links clicked outside your Overmux UI require Overmux Desktop.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Commands
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Commands let you centralize a collection of named actions in your Overmux UI, such as “Close pane” or “Open settings”, so you can build a command palette, menu, or similar feature. They could also be triggered by [keyboard shortcuts](./shortcuts) or buttons.
|
|
6
|
+
|
|
7
|
+
Packages may also provide commands that you can use in your UI.
|
|
8
|
+
|
|
9
|
+
## Registering a command
|
|
10
|
+
|
|
11
|
+
Declare a command with `defineCommandRegistry`, then register its behavior inside a React component with `useCommand`.
|
|
12
|
+
|
|
13
|
+
### Basic registration
|
|
14
|
+
|
|
15
|
+
The handler can access the component’s state:
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { useState } from "react";
|
|
19
|
+
import {
|
|
20
|
+
defineCommandRegistry,
|
|
21
|
+
defineOvermuxClient,
|
|
22
|
+
useCommand,
|
|
23
|
+
} from "overmux/client";
|
|
24
|
+
import type { serverConfig } from "./server";
|
|
25
|
+
|
|
26
|
+
const commands = defineCommandRegistry<typeof serverConfig>()({
|
|
27
|
+
openSettings: {
|
|
28
|
+
title: "Open settings",
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const App = () => {
|
|
33
|
+
const [settingsOpen, setSettingsOpen] = useState(false);
|
|
34
|
+
|
|
35
|
+
useCommand(commands.openSettings, {
|
|
36
|
+
run: () => setSettingsOpen(true),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return settingsOpen ? <Settings /> : <Workspace />;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const client = defineOvermuxClient({
|
|
43
|
+
commands,
|
|
44
|
+
component: App,
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`openSettings` is the command’s ID; `title` is its display name. `Settings` and `Workspace` represent your own components.
|
|
49
|
+
|
|
50
|
+
The handler is registered while `App` is mounted and removed when it unmounts. Registration does not execute the command.
|
|
51
|
+
|
|
52
|
+
### Disabling a command
|
|
53
|
+
|
|
54
|
+
Set `enabled` to prevent execution while keeping the command registered and visible through `useCommands()`:
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
useCommand(commands.openSettings, {
|
|
58
|
+
enabled: !settingsOpen,
|
|
59
|
+
run: () => setSettingsOpen(true),
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`enabled` defaults to `true`.
|
|
64
|
+
|
|
65
|
+
### Passing parameters to a shared handler
|
|
66
|
+
|
|
67
|
+
Declare `params` with a Zod schema and provide `run` in the registry when the behavior can live outside React:
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
import { z } from "zod";
|
|
71
|
+
|
|
72
|
+
const commands = defineCommandRegistry<typeof serverConfig>()({
|
|
73
|
+
killTmuxPane: {
|
|
74
|
+
title: "Kill pane",
|
|
75
|
+
params: z.object({ paneId: z.string() }),
|
|
76
|
+
run: ({ params, overmuxServerApi }) =>
|
|
77
|
+
overmuxServerApi.executeOperation("killTmuxPane", params),
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
This assumes your server defines a `killTmuxPane` operation accepting `{ paneId: string }`. The handler runs client-side and calls that server operation.
|
|
83
|
+
|
|
84
|
+
The component supplies the current values:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
useCommand(commands.killTmuxPane, {
|
|
88
|
+
params: { paneId: pane.id },
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Parameters are type-checked and validated before execution. A registration can supply its own `run` to override the shared handler; that local handler takes no arguments and can read component state directly.
|
|
93
|
+
|
|
94
|
+
### Conditional registration
|
|
95
|
+
|
|
96
|
+
Pass `skipToken` when a parameterized command’s required context is missing:
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import { skipToken } from "overmux/client";
|
|
100
|
+
|
|
101
|
+
useCommand(
|
|
102
|
+
commands.killTmuxPane,
|
|
103
|
+
pane ? { params: { paneId: pane.id } } : skipToken,
|
|
104
|
+
);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Unlike `enabled: false`, this skips registration entirely. Without another registration, the command will not appear in `useCommands()`. Keep the hook call unconditional.
|
|
108
|
+
|
|
109
|
+
### Registering a command in multiple components
|
|
110
|
+
|
|
111
|
+
Use `element` to associate each registration with a UI region:
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
const paneRef = useRef<HTMLDivElement>(null);
|
|
115
|
+
|
|
116
|
+
useCommand(commands.killTmuxPane, {
|
|
117
|
+
params: { paneId: pane.id },
|
|
118
|
+
element: paneRef,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return <div ref={paneRef}>...</div>;
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Import `useRef` from React. When the command is triggered, Overmux prefers the registration whose element contains keyboard focus. For nested elements, the innermost wins.
|
|
125
|
+
|
|
126
|
+
If none contains focus, the most recently registered handler wins. `element` is a preference, not a restriction; use `enabled` to control availability. If the selected registration is disabled, nothing runs.
|
|
127
|
+
|
|
128
|
+
### Adding keyboard shortcuts
|
|
129
|
+
|
|
130
|
+
Set `defaultBindings` on a command declaration to give it keyboard triggers. See [Shortcuts](./shortcuts) for bindings and client overrides.
|
|
131
|
+
|
|
132
|
+
## Listing all registered commands
|
|
133
|
+
|
|
134
|
+
Use `useCommands()` to build a menu or command palette with all your registered commands.
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
import { useCommands } from "overmux/client";
|
|
138
|
+
|
|
139
|
+
const CommandMenu = () => {
|
|
140
|
+
const commands = useCommands();
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<div>
|
|
144
|
+
{commands.map((command) => (
|
|
145
|
+
<button
|
|
146
|
+
key={command.id}
|
|
147
|
+
disabled={!command.enabled}
|
|
148
|
+
onClick={() => void command.execute()}
|
|
149
|
+
>
|
|
150
|
+
{command.title}
|
|
151
|
+
</button>
|
|
152
|
+
))}
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
};
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Each entry exposes `id`, `title`, `bindings`, `enabled`, and `execute()`. The list includes disabled commands but excludes commands without a registration.
|
|
159
|
+
|
|
160
|
+
Each command appears once, even if multiple components register it. `execute()` selects the handler using the current focus and runs it only if enabled.
|
|
161
|
+
|
|
162
|
+
## Using commands from packages
|
|
163
|
+
|
|
164
|
+
Packages can export commands to include alongside your own:
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
import { sourceControlCommands } from "@overmux/git/react";
|
|
168
|
+
|
|
169
|
+
export const client = defineOvermuxClient({
|
|
170
|
+
commands: {
|
|
171
|
+
...commands,
|
|
172
|
+
...sourceControlCommands,
|
|
173
|
+
},
|
|
174
|
+
component: App,
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Adding commands to the registry does not register their handlers. For this package, pass the commands to `SourceControlView`:
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
<SourceControlView
|
|
182
|
+
{...sourceControlProps}
|
|
183
|
+
commandHandles={sourceControlCommands}
|
|
184
|
+
/>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The view registers handlers for navigating changed files and scrolling diffs. They then appear in `useCommands()` alongside your own registered commands.
|
|
188
|
+
|
|
189
|
+
Keep command IDs unique when combining registries, and pass the same command objects to the client and the component.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Shortcuts
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Shortcuts trigger [commands](./commands) from the keyboard. Define bindings on commands, then customize them in your client configuration.
|
|
6
|
+
|
|
7
|
+
## Adding shortcuts
|
|
8
|
+
|
|
9
|
+
Set `defaultBindings` on a command:
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
const commands = defineCommandRegistry<typeof serverConfig>()({
|
|
13
|
+
openSettings: {
|
|
14
|
+
title: "Open settings",
|
|
15
|
+
defaultBindings: ["Mod+,"],
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The command must have a registered, enabled handler. See [Registering a command](./commands#registering-a-command).
|
|
21
|
+
|
|
22
|
+
## Binding syntax
|
|
23
|
+
|
|
24
|
+
A binding combines optional modifiers with a key:
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
defaultBindings: ["Mod+K"]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Use `Control`, `Alt`, `Shift`, or `Meta` for explicit modifiers. `Mod` means `Meta` (Command) on macOS and `Control` elsewhere.
|
|
31
|
+
|
|
32
|
+
Key names include uppercase letters, digits, `F1`–`F12`, and named keys such as `Enter`, `Escape`, `Space`, `Tab`, and `ArrowLeft`. Supported punctuation includes `/`, `[`, `]`, `\`, `=`, `-`, `,`, `.`, `;`, `:`, backtick, `'`, and `§`.
|
|
33
|
+
|
|
34
|
+
Modifiers use a fixed order: `Control+Alt+Shift+Meta`. With `Mod`, use `Mod+Alt+Shift`. Omit modifiers you do not need.
|
|
35
|
+
|
|
36
|
+
Use `Shift` with letters, function keys, or named keys, not digits or punctuation. For a colon, use `":"`, not `"Shift+;"`.
|
|
37
|
+
|
|
38
|
+
Multiple bindings provide alternative ways to trigger the same command:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
defaultBindings: ["Mod+K", "F2"]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Bindings match the key reported by the keyboard layout, not a physical key position. Holding a key does not repeatedly execute its command.
|
|
45
|
+
|
|
46
|
+
## Key sequences (chords)
|
|
47
|
+
|
|
48
|
+
Nest an array to require keys pressed in order:
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
defaultBindings: [["F12", "X"]]
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Press F12, then X to trigger the command. Each step can include modifiers:
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
defaultBindings: [["Control+K", "Control+C"]]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Overmux waits up to one second between steps. Escape cancels the pending sequence. A nonmatching key ends it.
|
|
61
|
+
|
|
62
|
+
Avoid assigning a complete shortcut to another sequence’s prefix: the complete shortcut runs immediately rather than waiting for more keys.
|
|
63
|
+
|
|
64
|
+
## Overriding shortcuts
|
|
65
|
+
|
|
66
|
+
Use `shortcutOverrides` in your client configuration, keyed by command ID:
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
export const client = defineOvermuxClient({
|
|
70
|
+
commands,
|
|
71
|
+
component: App,
|
|
72
|
+
shortcutOverrides: {
|
|
73
|
+
openSettings: ["Mod+Shift+O"],
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
An override replaces all default bindings for that command. An empty array removes its keyboard shortcuts without disabling the command:
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
shortcutOverrides: {
|
|
82
|
+
openSettings: [],
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Conditional shortcuts
|
|
87
|
+
|
|
88
|
+
Wrap a binding with `when.media` to activate it only while a CSS media query matches:
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
defaultBindings: [
|
|
92
|
+
{
|
|
93
|
+
binding: "Mod+,",
|
|
94
|
+
when: { media: "(min-width: 800px)" },
|
|
95
|
+
},
|
|
96
|
+
]
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Conditional bindings work in both `defaultBindings` and `shortcutOverrides`, and update when the media query changes.
|
|
100
|
+
|
|
101
|
+
## Text inputs and terminals
|
|
102
|
+
|
|
103
|
+
Shortcuts do not run while an ordinary input, textarea, select, or editable text element has focus.
|
|
104
|
+
|
|
105
|
+
Terminals are an exception: modified keys, function keys, and multi-key sequences can trigger commands while typing. Plain single-key shortcuts are also allowed in terminal copy mode.
|
|
106
|
+
|
|
107
|
+
Matched shortcuts prevent the key’s normal browser or terminal behavior. Browser or operating-system shortcuts that never reach the page cannot be handled by Overmux.
|
|
108
|
+
|
|
109
|
+
### Replaying unmatched sequences
|
|
110
|
+
|
|
111
|
+
By default, keys intercepted for an incomplete sequence are discarded when it times out or fails to match.
|
|
112
|
+
|
|
113
|
+
Configure a prefix to replay those keys into a registered input instead. For example, suppose F12, then X closes a pane:
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
const commands = defineCommandRegistry<typeof serverConfig>()({
|
|
117
|
+
closePane: {
|
|
118
|
+
title: "Close pane",
|
|
119
|
+
defaultBindings: [["F12", "X"]],
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Enable replay for F12 in your client configuration:
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
export const client = defineOvermuxClient({
|
|
128
|
+
commands,
|
|
129
|
+
component: App,
|
|
130
|
+
chordPrefixes: [
|
|
131
|
+
{ binding: "F12", unmatched: "replay-to-focused-input" },
|
|
132
|
+
],
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
With the command’s handler registered and enabled, while a terminal has focus:
|
|
137
|
+
|
|
138
|
+
- **F12 → X:** closes the pane; neither key reaches the terminal.
|
|
139
|
+
- **F12 → Y:** no shortcut matches, so both F12 and Y are forwarded to the terminal.
|
|
140
|
+
- **F12 → wait one second:** F12 is forwarded to the terminal.
|
|
141
|
+
- **F12 → Escape:** cancels; neither key reaches the terminal.
|
|
142
|
+
|
|
143
|
+
This lets Overmux share a prefix with a terminal application rather than always swallowing it.
|
|
144
|
+
|
|
145
|
+
The tmux and Zellij terminal components already register replay targets. Custom terminal integrations can register one with:
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
import { useShortcutInputTarget } from "overmux/client";
|
|
149
|
+
|
|
150
|
+
useShortcutInputTarget({
|
|
151
|
+
container: containerRef,
|
|
152
|
+
input: inputRef,
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`container` identifies the focused UI region; `input` receives replayed keyboard events. If regions are nested, the innermost containing focus is selected when the sequence begins. Without a matching input target, intercepted keys cannot be replayed.
|
|
157
|
+
|
|
158
|
+
## Displaying bindings
|
|
159
|
+
|
|
160
|
+
Use `formatShortcutBinding` to format a binding for the current platform:
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
import { formatShortcutBinding } from "overmux/client";
|
|
164
|
+
|
|
165
|
+
formatShortcutBinding("Mod+K");
|
|
166
|
+
formatShortcutBinding(["F12", "X"]);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
On macOS, modifiers appear as symbols such as `⌘`; sequences display their steps separated by spaces.
|
|
170
|
+
|
|
171
|
+
Entries returned by [`useCommands()`](./commands#listing-all-registered-commands) expose their active, overridden bindings through `bindings`. Format those values to show shortcuts alongside command titles.
|