tmux-ide 2.6.0 → 2.6.1
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/bin/cli.js +13 -5
- package/bin/cli.ts +1 -1
- package/bunfig.toml +4 -0
- package/package.json +11 -3
- package/packages/contracts/package.json +22 -0
- package/packages/contracts/src/__tests__/ide-config.test.ts +46 -0
- package/packages/contracts/src/__tests__/terminals.test.ts +87 -0
- package/packages/contracts/src/actions-contract.ts +310 -0
- package/packages/contracts/src/actions-errors.ts +41 -0
- package/packages/contracts/src/domain.ts +36 -0
- package/packages/contracts/src/ide-config.ts +170 -0
- package/packages/contracts/src/index.ts +24 -0
- package/packages/contracts/src/lib-internal/auth.ts +13 -0
- package/packages/contracts/src/lib-internal/hq.ts +38 -0
- package/packages/contracts/src/terminals.ts +116 -0
- package/packages/contracts/src/tmux.ts +60 -0
- package/packages/contracts/src/workspace.ts +67 -0
- package/packages/daemon/src/agent-explain.ts +270 -0
- package/packages/daemon/src/attach.ts +20 -0
- package/packages/daemon/src/bin.ts +4 -0
- package/packages/daemon/src/canonical.ts +7 -0
- package/packages/daemon/src/cli.ts +499 -0
- package/packages/daemon/src/command-center/actions/contract.ts +2 -0
- package/packages/daemon/src/command-center/actions/dispatcher.ts +137 -0
- package/packages/daemon/src/command-center/actions/errors.ts +105 -0
- package/packages/daemon/src/command-center/actions/handlers/_project-context.ts +30 -0
- package/packages/daemon/src/command-center/actions/handlers/_resolve-project.ts +78 -0
- package/packages/daemon/src/command-center/actions/handlers/app-set-remote-access.ts +118 -0
- package/packages/daemon/src/command-center/actions/handlers/config-actions.ts +113 -0
- package/packages/daemon/src/command-center/actions/handlers/daemon-shutdown.ts +38 -0
- package/packages/daemon/src/command-center/actions/handlers/project-activate.ts +30 -0
- package/packages/daemon/src/command-center/actions/handlers/project-launch.ts +70 -0
- package/packages/daemon/src/command-center/actions/handlers/project-open-terminal.ts +87 -0
- package/packages/daemon/src/command-center/actions/handlers/project-restart.ts +38 -0
- package/packages/daemon/src/command-center/actions/handlers/project-stop.ts +62 -0
- package/packages/daemon/src/command-center/actions/handlers/terminal-respawn.ts +119 -0
- package/packages/daemon/src/command-center/actions/handlers/terminal-stop.ts +35 -0
- package/packages/daemon/src/command-center/actions/registry.ts +149 -0
- package/packages/daemon/src/command-center/discovery.ts +96 -0
- package/packages/daemon/src/command-center/index.ts +31 -0
- package/packages/daemon/src/command-center/schemas.ts +85 -0
- package/packages/daemon/src/command-center/server.ts +1260 -0
- package/packages/daemon/src/command-center/ws-events.ts +316 -0
- package/packages/daemon/src/config.ts +549 -0
- package/packages/daemon/src/detect.ts +248 -0
- package/packages/daemon/src/doctor.ts +242 -0
- package/packages/daemon/src/embed.ts +5 -0
- package/packages/daemon/src/index.ts +12 -0
- package/packages/daemon/src/init.ts +211 -0
- package/packages/daemon/src/inspect.ts +178 -0
- package/packages/daemon/src/js-yaml.d.ts +10 -0
- package/packages/daemon/src/launch.ts +349 -0
- package/packages/daemon/src/lib/active-projects.ts +49 -0
- package/packages/daemon/src/lib/agent-discovery.ts +121 -0
- package/packages/daemon/src/lib/app-config.ts +336 -0
- package/packages/daemon/src/lib/app-settings.ts +53 -0
- package/packages/daemon/src/lib/auth/auth-service.ts +227 -0
- package/packages/daemon/src/lib/auth/middleware.ts +56 -0
- package/packages/daemon/src/lib/auth/types.ts +2 -0
- package/packages/daemon/src/lib/auth-token.ts +5 -0
- package/packages/daemon/src/lib/authorship.ts +280 -0
- package/packages/daemon/src/lib/canonical-daemon.ts +122 -0
- package/packages/daemon/src/lib/cli-action-bridge.ts +216 -0
- package/packages/daemon/src/lib/daemon-embed.ts +782 -0
- package/packages/daemon/src/lib/daemon-watchdog.ts +111 -0
- package/packages/daemon/src/lib/daemon.ts +79 -0
- package/packages/daemon/src/lib/dot-path.ts +17 -0
- package/packages/daemon/src/lib/errors.ts +67 -0
- package/packages/daemon/src/lib/filesystem-browser.ts +292 -0
- package/packages/daemon/src/lib/launch-plan.ts +90 -0
- package/packages/daemon/src/lib/log.ts +134 -0
- package/packages/daemon/src/lib/output.ts +76 -0
- package/packages/daemon/src/lib/project-init-runner.ts +150 -0
- package/packages/daemon/src/lib/project-inspect.ts +80 -0
- package/packages/daemon/src/lib/project-onboard.ts +149 -0
- package/packages/daemon/src/lib/project-probe.ts +92 -0
- package/packages/daemon/src/lib/project-registry.ts +296 -0
- package/packages/daemon/src/lib/session-monitor.ts +122 -0
- package/packages/daemon/src/lib/session-options.ts +100 -0
- package/packages/daemon/src/lib/shell.ts +8 -0
- package/packages/daemon/src/lib/sizes.ts +36 -0
- package/packages/daemon/src/lib/skill-sync.ts +155 -0
- package/packages/daemon/src/lib/slugify.ts +10 -0
- package/packages/daemon/src/lib/terminals-store.ts +125 -0
- package/packages/daemon/src/lib/update-check.ts +298 -0
- package/packages/daemon/src/lib/update.ts +158 -0
- package/packages/daemon/src/lib/workspace-registry.ts +229 -0
- package/packages/daemon/src/lib/worktree.ts +289 -0
- package/packages/daemon/src/lib/yaml-io.ts +27 -0
- package/packages/daemon/src/ls.ts +40 -0
- package/packages/daemon/src/restart.ts +24 -0
- package/packages/daemon/src/restore.ts +514 -0
- package/packages/daemon/src/schemas/domain.ts +2 -0
- package/packages/daemon/src/schemas/filesystem.ts +34 -0
- package/packages/daemon/src/schemas/ide-config.ts +2 -0
- package/packages/daemon/src/schemas/index.ts +59 -0
- package/packages/daemon/src/schemas/inspect.ts +67 -0
- package/packages/daemon/src/schemas/registry.ts +55 -0
- package/packages/daemon/src/schemas/ws-events.ts +135 -0
- package/packages/daemon/src/send.ts +171 -0
- package/packages/daemon/src/server/README.md +15 -0
- package/packages/daemon/src/server/index.ts +74 -0
- package/packages/daemon/src/server/pty-bridge.ts +532 -0
- package/packages/daemon/src/server/standalone.ts +18 -0
- package/packages/daemon/src/server/ws-route.ts +483 -0
- package/packages/daemon/src/status.ts +59 -0
- package/packages/daemon/src/stop.ts +28 -0
- package/packages/daemon/src/terminal/NodePtyAdapter.ts +271 -0
- package/packages/daemon/src/terminal/PtyAdapter.ts +140 -0
- package/packages/daemon/src/terminal/README.md +92 -0
- package/packages/daemon/src/tui/chrome/cheatsheet.ts +260 -0
- package/packages/daemon/src/tui/chrome/chip.ts +30 -0
- package/packages/daemon/src/tui/chrome/events.ts +119 -0
- package/packages/daemon/src/tui/chrome/kitty-keys.ts +55 -0
- package/packages/daemon/src/tui/chrome/menu.ts +289 -0
- package/packages/daemon/src/tui/chrome/notify.ts +195 -0
- package/packages/daemon/src/tui/chrome/panels.ts +111 -0
- package/packages/daemon/src/tui/chrome/sidebar.ts +222 -0
- package/packages/daemon/src/tui/chrome/snapshot.ts +425 -0
- package/packages/daemon/src/tui/chrome/statusline.ts +595 -0
- package/packages/daemon/src/tui/chrome/updater.ts +428 -0
- package/packages/daemon/src/tui/chrome/welcome.ts +124 -0
- package/packages/daemon/src/tui/compiled.ts +113 -0
- package/packages/daemon/src/tui/detect/classify.ts +193 -0
- package/packages/daemon/src/tui/detect/manifest-loader.ts +192 -0
- package/packages/daemon/src/tui/detect/manifest.ts +184 -0
- package/packages/daemon/src/tui/detect/manifests.ts +226 -0
- package/packages/daemon/src/tui/detect/process-tree.ts +197 -0
- package/packages/daemon/src/tui/detect/snapshot.ts +70 -0
- package/packages/daemon/src/tui/integrations/claude.ts +176 -0
- package/packages/daemon/src/tui/integrations/offer.ts +145 -0
- package/packages/daemon/src/tui/main.ts +70 -0
- package/packages/daemon/src/tui/mirror/control-client.ts +143 -0
- package/packages/daemon/src/tui/mirror/control.ts +97 -0
- package/packages/daemon/src/tui/mirror/pane-mirror.ts +81 -0
- package/packages/daemon/src/tui/mirror/viewer.tsx +166 -0
- package/packages/daemon/src/tui/team/CONTROL.md +50 -0
- package/packages/daemon/src/tui/team/entry.ts +11 -0
- package/packages/daemon/src/tui/team/fuzzy.ts +133 -0
- package/packages/daemon/src/tui/team/home.ts +170 -0
- package/packages/daemon/src/tui/team/index.tsx +1521 -0
- package/packages/daemon/src/tui/team/input.ts +34 -0
- package/packages/daemon/src/tui/team/keymap.ts +127 -0
- package/packages/daemon/src/tui/team/mouse.ts +29 -0
- package/packages/daemon/src/tui/team/nav.ts +31 -0
- package/packages/daemon/src/tui/team/preview.ts +34 -0
- package/packages/daemon/src/tui/team/projects.ts +191 -0
- package/packages/daemon/src/tui/team/report.ts +73 -0
- package/packages/daemon/src/tui/team/sessions.ts +344 -0
- package/packages/daemon/src/tui/team/tree.ts +62 -0
- package/packages/daemon/src/types.ts +13 -0
- package/packages/daemon/src/ui/index.ts +32 -0
- package/packages/daemon/src/ui/terminal/index.ts +9 -0
- package/packages/daemon/src/ui/types.ts +91 -0
- package/packages/daemon/src/ui/web/base.css +80 -0
- package/packages/daemon/src/ui/web/components/Box.tsx +59 -0
- package/packages/daemon/src/ui/web/components/Input.tsx +32 -0
- package/packages/daemon/src/ui/web/components/ScrollBox.tsx +60 -0
- package/packages/daemon/src/ui/web/components/Text.tsx +28 -0
- package/packages/daemon/src/ui/web/hooks.ts +106 -0
- package/packages/daemon/src/ui/web/index.ts +27 -0
- package/packages/daemon/src/ui/web/render.ts +77 -0
- package/packages/daemon/src/ui/web/utils/color.ts +27 -0
- package/packages/daemon/src/validate.ts +217 -0
- package/packages/daemon/src/widgets/changes/README.md +3 -0
- package/packages/daemon/src/widgets/changes/index.tsx +691 -0
- package/packages/daemon/src/widgets/config/README.md +3 -0
- package/packages/daemon/src/widgets/config/index.tsx +481 -0
- package/packages/daemon/src/widgets/explorer/README.md +3 -0
- package/packages/daemon/src/widgets/explorer/breadcrumbs.tsx +77 -0
- package/packages/daemon/src/widgets/explorer/footer.tsx +20 -0
- package/packages/daemon/src/widgets/explorer/header.tsx +23 -0
- package/packages/daemon/src/widgets/explorer/index.tsx +456 -0
- package/packages/daemon/src/widgets/explorer/tree-model.ts +103 -0
- package/packages/daemon/src/widgets/explorer/tree.tsx +165 -0
- package/packages/daemon/src/widgets/lib/config-model.ts +116 -0
- package/packages/daemon/src/widgets/lib/files.ts +88 -0
- package/packages/daemon/src/widgets/lib/git.ts +88 -0
- package/packages/daemon/src/widgets/lib/grammar.ts +126 -0
- package/packages/daemon/src/widgets/lib/help-overlay.tsx +101 -0
- package/packages/daemon/src/widgets/lib/pane-comms.ts +209 -0
- package/packages/daemon/src/widgets/lib/theme.ts +194 -0
- package/packages/daemon/src/widgets/lib/watcher.ts +132 -0
- package/packages/daemon/src/widgets/preview/README.md +3 -0
- package/packages/daemon/src/widgets/preview/index.tsx +416 -0
- package/packages/daemon/src/widgets/resolve.ts +121 -0
- package/packages/daemon/src/widgets/setup/README.md +3 -0
- package/packages/daemon/src/widgets/setup/agent-naming.tsx +112 -0
- package/packages/daemon/src/widgets/setup/config-tree.tsx +246 -0
- package/packages/daemon/src/widgets/setup/detect-panel.tsx +72 -0
- package/packages/daemon/src/widgets/setup/field-editor.tsx +265 -0
- package/packages/daemon/src/widgets/setup/footer.tsx +107 -0
- package/packages/daemon/src/widgets/setup/index.tsx +341 -0
- package/packages/daemon/src/widgets/setup/layout-picker.tsx +96 -0
- package/packages/daemon/src/widgets/setup/orchestrator-panel.tsx +200 -0
- package/packages/daemon/src/widgets/setup/review-panel.tsx +140 -0
- package/packages/daemon/src/widgets/setup/setup-model.ts +188 -0
- package/packages/daemon/src/widgets/sidebar/index.tsx +527 -0
- package/packages/tmux-bridge/package.json +22 -0
- package/packages/tmux-bridge/src/errors.ts +28 -0
- package/packages/tmux-bridge/src/index.ts +31 -0
- package/packages/tmux-bridge/src/monitor.ts +77 -0
- package/packages/tmux-bridge/src/panes.ts +136 -0
- package/packages/tmux-bridge/src/runner.test.ts +501 -0
- package/packages/tmux-bridge/src/runner.ts +91 -0
- package/packages/tmux-bridge/src/sessions.ts +126 -0
- package/packages/tmux-bridge/src/targeting.test.ts +107 -0
- package/packages/tmux-bridge/src/targeting.ts +90 -0
- package/scripts/postinstall.js +26 -2
package/bin/cli.js
CHANGED
|
@@ -2340,7 +2340,7 @@ function resolveTuiLaunch(input) {
|
|
|
2340
2340
|
const reasons = [];
|
|
2341
2341
|
if (!input.checkoutExists) {
|
|
2342
2342
|
reasons.push(
|
|
2343
|
-
"the TUI widget sources are absent (
|
|
2343
|
+
"the TUI widget sources are absent (reinstall tmux-ide \u2014 releases since v2.6.1 ship them)"
|
|
2344
2344
|
);
|
|
2345
2345
|
}
|
|
2346
2346
|
if (!input.bunAvailable) {
|
|
@@ -10975,7 +10975,7 @@ var require_package = __commonJS({
|
|
|
10975
10975
|
"package.json"(exports, module) {
|
|
10976
10976
|
module.exports = {
|
|
10977
10977
|
name: "tmux-ide",
|
|
10978
|
-
version: "2.6.
|
|
10978
|
+
version: "2.6.1",
|
|
10979
10979
|
description: "Turn any project into a tmux-powered terminal IDE with a simple ide.yml",
|
|
10980
10980
|
type: "module",
|
|
10981
10981
|
bin: {
|
|
@@ -10987,7 +10987,13 @@ var require_package = __commonJS({
|
|
|
10987
10987
|
"skill",
|
|
10988
10988
|
"templates",
|
|
10989
10989
|
"packages/daemon/dist",
|
|
10990
|
-
"!packages/daemon/dist/tui"
|
|
10990
|
+
"!packages/daemon/dist/tui",
|
|
10991
|
+
"packages/daemon/src",
|
|
10992
|
+
"bunfig.toml",
|
|
10993
|
+
"packages/contracts/src",
|
|
10994
|
+
"packages/tmux-bridge/src",
|
|
10995
|
+
"packages/tmux-bridge/package.json",
|
|
10996
|
+
"packages/contracts/package.json"
|
|
10991
10997
|
],
|
|
10992
10998
|
scripts: {
|
|
10993
10999
|
build: "pnpm build:cli",
|
|
@@ -11035,7 +11041,6 @@ var require_package = __commonJS({
|
|
|
11035
11041
|
"@hono/node-server": "^1.19.11",
|
|
11036
11042
|
"@hono/zod-validator": "^0.7.6",
|
|
11037
11043
|
"@opentui/core": "^0.1.88",
|
|
11038
|
-
"@opentui/core-darwin-arm64": "^0.1.88",
|
|
11039
11044
|
"@opentui/solid": "^0.1.88",
|
|
11040
11045
|
"@parcel/watcher": "^2.5.6",
|
|
11041
11046
|
"@types/ws": "^8.18.1",
|
|
@@ -11068,6 +11073,9 @@ var require_package = __commonJS({
|
|
|
11068
11073
|
turbo: "^2.3.3",
|
|
11069
11074
|
typescript: "^5.9.3",
|
|
11070
11075
|
vitest: "^4.1.0"
|
|
11076
|
+
},
|
|
11077
|
+
optionalDependencies: {
|
|
11078
|
+
"@opentui/core-darwin-arm64": "^0.1.88"
|
|
11071
11079
|
}
|
|
11072
11080
|
};
|
|
11073
11081
|
}
|
|
@@ -12781,7 +12789,7 @@ function execBunWidget(surface, scriptPath, args, commandLabel, extraEnv = {}) {
|
|
|
12781
12789
|
if (launch2.mode === "unavailable") {
|
|
12782
12790
|
throw new IdeError(
|
|
12783
12791
|
`\`tmux-ide ${commandLabel}\` is unavailable because ${launch2.reasons.join(" and ")}.
|
|
12784
|
-
|
|
12792
|
+
Install bun (https://bun.sh) \u2014 the TUI surfaces run on it. Sources ship with the npm package since v2.6.1.`,
|
|
12785
12793
|
{ code: "USAGE", exitCode: 1 }
|
|
12786
12794
|
);
|
|
12787
12795
|
}
|
package/bin/cli.ts
CHANGED
|
@@ -264,7 +264,7 @@ function execBunWidget(
|
|
|
264
264
|
if (launch.mode === "unavailable") {
|
|
265
265
|
throw new IdeError(
|
|
266
266
|
`\`tmux-ide ${commandLabel}\` is unavailable because ${launch.reasons.join(" and ")}.\n` +
|
|
267
|
-
`
|
|
267
|
+
`Install bun (https://bun.sh) — the TUI surfaces run on it. Sources ship with the npm package since v2.6.1.`,
|
|
268
268
|
{ code: "USAGE", exitCode: 1 },
|
|
269
269
|
);
|
|
270
270
|
}
|
package/bunfig.toml
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tmux-ide",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"description": "Turn any project into a tmux-powered terminal IDE with a simple ide.yml",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,7 +12,13 @@
|
|
|
12
12
|
"skill",
|
|
13
13
|
"templates",
|
|
14
14
|
"packages/daemon/dist",
|
|
15
|
-
"!packages/daemon/dist/tui"
|
|
15
|
+
"!packages/daemon/dist/tui",
|
|
16
|
+
"packages/daemon/src",
|
|
17
|
+
"bunfig.toml",
|
|
18
|
+
"packages/contracts/src",
|
|
19
|
+
"packages/tmux-bridge/src",
|
|
20
|
+
"packages/tmux-bridge/package.json",
|
|
21
|
+
"packages/contracts/package.json"
|
|
16
22
|
],
|
|
17
23
|
"scripts": {
|
|
18
24
|
"build": "pnpm build:cli",
|
|
@@ -60,7 +66,6 @@
|
|
|
60
66
|
"@hono/node-server": "^1.19.11",
|
|
61
67
|
"@hono/zod-validator": "^0.7.6",
|
|
62
68
|
"@opentui/core": "^0.1.88",
|
|
63
|
-
"@opentui/core-darwin-arm64": "^0.1.88",
|
|
64
69
|
"@opentui/solid": "^0.1.88",
|
|
65
70
|
"@parcel/watcher": "^2.5.6",
|
|
66
71
|
"@types/ws": "^8.18.1",
|
|
@@ -93,5 +98,8 @@
|
|
|
93
98
|
"turbo": "^2.3.3",
|
|
94
99
|
"typescript": "^5.9.3",
|
|
95
100
|
"vitest": "^4.1.0"
|
|
101
|
+
},
|
|
102
|
+
"optionalDependencies": {
|
|
103
|
+
"@opentui/core-darwin-arm64": "^0.1.88"
|
|
96
104
|
}
|
|
97
105
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tmux-ide/contracts",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"lint": "eslint src",
|
|
12
|
+
"typecheck": "tsc --noEmit",
|
|
13
|
+
"test": "vitest run"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"zod": "^4.3.6"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"typescript": "^5.9.3",
|
|
20
|
+
"vitest": "^4.1.0"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema tests for the `sidebar` ide.yml sugar (M15.2).
|
|
3
|
+
*/
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { IdeConfigSchema, SidebarConfigSchema } from "../ide-config";
|
|
6
|
+
|
|
7
|
+
const base = { rows: [{ panes: [{ title: "shell" }] }] };
|
|
8
|
+
|
|
9
|
+
describe("SidebarConfigSchema", () => {
|
|
10
|
+
it("accepts the boolean form", () => {
|
|
11
|
+
expect(SidebarConfigSchema.parse(true)).toBe(true);
|
|
12
|
+
expect(SidebarConfigSchema.parse(false)).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("accepts the object form with an optional width", () => {
|
|
16
|
+
expect(SidebarConfigSchema.parse({ width: "30" })).toEqual({ width: "30" });
|
|
17
|
+
expect(SidebarConfigSchema.parse({})).toEqual({});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("rejects a bare number", () => {
|
|
21
|
+
expect(() => SidebarConfigSchema.parse(30)).toThrow();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe("IdeConfigSchema — sidebar", () => {
|
|
26
|
+
it("parses `sidebar: true`", () => {
|
|
27
|
+
const cfg = IdeConfigSchema.parse({ ...base, sidebar: true });
|
|
28
|
+
expect(cfg.sidebar).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("parses `sidebar: { width }`", () => {
|
|
32
|
+
const cfg = IdeConfigSchema.parse({ ...base, sidebar: { width: "40" } });
|
|
33
|
+
expect(cfg.sidebar).toEqual({ width: "40" });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("leaves sidebar undefined when omitted", () => {
|
|
37
|
+
expect(IdeConfigSchema.parse(base).sidebar).toBeUndefined();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("accepts a pane of type sidebar", () => {
|
|
41
|
+
const cfg = IdeConfigSchema.parse({
|
|
42
|
+
rows: [{ panes: [{ title: "nav", type: "sidebar" }] }],
|
|
43
|
+
});
|
|
44
|
+
expect(cfg.rows[0]!.panes[0]!.type).toBe("sidebar");
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createScriptTerminalId` determinism tests (G20-P1).
|
|
3
|
+
*
|
|
4
|
+
* The whole point of the script-derived id is determinism — two
|
|
5
|
+
* callers asking for "the run script for project X, scope Y, script
|
|
6
|
+
* Z" must collapse to one bridge. These tests pin that contract.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, expect, it } from "vitest";
|
|
10
|
+
import { createScriptTerminalId } from "../terminals";
|
|
11
|
+
|
|
12
|
+
describe("createScriptTerminalId", () => {
|
|
13
|
+
it("is deterministic for the same input", async () => {
|
|
14
|
+
const a = await createScriptTerminalId({
|
|
15
|
+
projectId: "proj",
|
|
16
|
+
scopeId: "feat-x",
|
|
17
|
+
kind: "run",
|
|
18
|
+
script: "pnpm dev",
|
|
19
|
+
});
|
|
20
|
+
const b = await createScriptTerminalId({
|
|
21
|
+
projectId: "proj",
|
|
22
|
+
scopeId: "feat-x",
|
|
23
|
+
kind: "run",
|
|
24
|
+
script: "pnpm dev",
|
|
25
|
+
});
|
|
26
|
+
expect(a).toBe(b);
|
|
27
|
+
expect(a).toHaveLength(32);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("changes when scopeId changes (same project + script)", async () => {
|
|
31
|
+
const a = await createScriptTerminalId({
|
|
32
|
+
projectId: "proj",
|
|
33
|
+
scopeId: "feat-x",
|
|
34
|
+
kind: "run",
|
|
35
|
+
script: "pnpm dev",
|
|
36
|
+
});
|
|
37
|
+
const b = await createScriptTerminalId({
|
|
38
|
+
projectId: "proj",
|
|
39
|
+
scopeId: "feat-y",
|
|
40
|
+
kind: "run",
|
|
41
|
+
script: "pnpm dev",
|
|
42
|
+
});
|
|
43
|
+
expect(a).not.toBe(b);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("changes when kind changes", async () => {
|
|
47
|
+
const run = await createScriptTerminalId({
|
|
48
|
+
projectId: "proj",
|
|
49
|
+
scopeId: "feat-x",
|
|
50
|
+
kind: "run",
|
|
51
|
+
script: "pnpm dev",
|
|
52
|
+
});
|
|
53
|
+
const setup = await createScriptTerminalId({
|
|
54
|
+
projectId: "proj",
|
|
55
|
+
scopeId: "feat-x",
|
|
56
|
+
kind: "setup",
|
|
57
|
+
script: "pnpm dev",
|
|
58
|
+
});
|
|
59
|
+
expect(run).not.toBe(setup);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("accepts taskId as a backward-compat alias for scopeId", async () => {
|
|
63
|
+
const viaScope = await createScriptTerminalId({
|
|
64
|
+
projectId: "proj",
|
|
65
|
+
scopeId: "feat-x",
|
|
66
|
+
kind: "run",
|
|
67
|
+
script: "pnpm dev",
|
|
68
|
+
});
|
|
69
|
+
const viaTask = await createScriptTerminalId({
|
|
70
|
+
projectId: "proj",
|
|
71
|
+
taskId: "feat-x",
|
|
72
|
+
kind: "run",
|
|
73
|
+
script: "pnpm dev",
|
|
74
|
+
});
|
|
75
|
+
expect(viaScope).toBe(viaTask);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("rejects calls without scope or task", async () => {
|
|
79
|
+
await expect(
|
|
80
|
+
createScriptTerminalId({
|
|
81
|
+
projectId: "proj",
|
|
82
|
+
kind: "run",
|
|
83
|
+
script: "pnpm dev",
|
|
84
|
+
}),
|
|
85
|
+
).rejects.toThrow(/scopeId/);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action contract for the v2 dispatcher.
|
|
3
|
+
*
|
|
4
|
+
* CLI and command-center clients import the schemas in this file — input +
|
|
5
|
+
* output Zod shapes for every action. The server-side dispatcher wires each
|
|
6
|
+
* name to a handler that consumes the input and returns the typed result.
|
|
7
|
+
*
|
|
8
|
+
* Adding a new action:
|
|
9
|
+
* 1. Define `<Name>InputSchemaZ` and `<Name>ResultSchemaZ` here
|
|
10
|
+
* 2. Add it to {@link ActionContractsZ} below
|
|
11
|
+
* 3. Add a handler in `handlers/` and register it in `registry.ts`
|
|
12
|
+
*
|
|
13
|
+
* Invariants:
|
|
14
|
+
* - Names are dot-namespaced (`<noun>.<verb>`)
|
|
15
|
+
* - Both schemas live here so the wire format never drifts between clients
|
|
16
|
+
* - Action names ARE the discriminator — keep them stable; never rename
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { z } from "zod";
|
|
20
|
+
import { IdeConfigSchema, PaneSchema } from "./ide-config.ts";
|
|
21
|
+
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// project.openTerminal
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
export const ProjectOpenTerminalInputZ = z.object({
|
|
27
|
+
name: z.string().min(1),
|
|
28
|
+
});
|
|
29
|
+
export const ProjectOpenTerminalResultZ = z.object({
|
|
30
|
+
sessionName: z.string(),
|
|
31
|
+
cwd: z.string().min(1),
|
|
32
|
+
terminalTabId: z.string(),
|
|
33
|
+
/**
|
|
34
|
+
* `true` when the dispatcher had to launch the tmux session as part of
|
|
35
|
+
* resolving the terminal. `false` when the session was already running.
|
|
36
|
+
*/
|
|
37
|
+
launched: z.boolean(),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// project.launch
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
export const ProjectLaunchInputZ = z.object({
|
|
45
|
+
name: z.string().min(1),
|
|
46
|
+
});
|
|
47
|
+
export const ProjectLaunchResultZ = z.object({
|
|
48
|
+
sessionName: z.string(),
|
|
49
|
+
/**
|
|
50
|
+
* `false` when the session was already running (idempotent no-op),
|
|
51
|
+
* `true` when this call started a fresh session.
|
|
52
|
+
*/
|
|
53
|
+
started: z.boolean(),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// project.stop
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
|
|
60
|
+
export const ProjectStopInputZ = z.object({
|
|
61
|
+
name: z.string().min(1),
|
|
62
|
+
});
|
|
63
|
+
export const ProjectStopResultZ = z.object({
|
|
64
|
+
sessionName: z.string(),
|
|
65
|
+
/**
|
|
66
|
+
* `false` when no session was running (idempotent no-op),
|
|
67
|
+
* `true` when this call killed a session.
|
|
68
|
+
*/
|
|
69
|
+
stopped: z.boolean(),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// project.restart
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
export const ProjectRestartInputZ = z.object({
|
|
77
|
+
name: z.string().min(1),
|
|
78
|
+
});
|
|
79
|
+
export const ProjectRestartResultZ = z.object({
|
|
80
|
+
sessionName: z.string(),
|
|
81
|
+
restarted: z.literal(true),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// project.activate
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
export const ProjectActivateInputZ = z.object({
|
|
89
|
+
name: z.string().min(1),
|
|
90
|
+
});
|
|
91
|
+
export const ProjectActivateResultZ = z.object({
|
|
92
|
+
active: z.boolean(),
|
|
93
|
+
projectName: z.string(),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// terminal.respawn
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
export const TerminalRespawnInputZ = z.object({
|
|
101
|
+
sessionName: z.string().min(1),
|
|
102
|
+
terminalId: z.string().min(1),
|
|
103
|
+
/**
|
|
104
|
+
* Optional cwd override. Omit to respawn at the bridge's current cwd
|
|
105
|
+
* (re-using the `lastCwd` recorded by the PTY bridge).
|
|
106
|
+
*/
|
|
107
|
+
cwd: z.string().min(1).optional(),
|
|
108
|
+
});
|
|
109
|
+
export const TerminalRespawnResultZ = z.object({
|
|
110
|
+
respawned: z.literal(true),
|
|
111
|
+
cwd: z.string().min(1),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
// terminal.stop
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
export const TerminalStopInputZ = z.object({
|
|
119
|
+
sessionName: z.string().min(1),
|
|
120
|
+
terminalId: z.string().min(1),
|
|
121
|
+
});
|
|
122
|
+
export const TerminalStopResultZ = z.object({
|
|
123
|
+
stopped: z.literal(true),
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
// config.*
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
|
|
130
|
+
export const ConfigSetInputZ = z.object({
|
|
131
|
+
projectName: z.string().min(1).optional(),
|
|
132
|
+
path: z.string().min(1),
|
|
133
|
+
value: z.unknown(),
|
|
134
|
+
});
|
|
135
|
+
export const ConfigResultZ = z.object({
|
|
136
|
+
config: IdeConfigSchema,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
export const ConfigAddPaneInputZ = PaneSchema.partial().extend({
|
|
140
|
+
projectName: z.string().min(1).optional(),
|
|
141
|
+
rowIndex: z.number().int().min(0),
|
|
142
|
+
});
|
|
143
|
+
export const ConfigAddPaneResultZ = ConfigResultZ;
|
|
144
|
+
|
|
145
|
+
export const ConfigRemovePaneInputZ = z.object({
|
|
146
|
+
projectName: z.string().min(1).optional(),
|
|
147
|
+
rowIndex: z.number().int().min(0),
|
|
148
|
+
paneIndex: z.number().int().min(0),
|
|
149
|
+
});
|
|
150
|
+
export const ConfigRemovePaneResultZ = ConfigResultZ;
|
|
151
|
+
|
|
152
|
+
export const ConfigAddRowInputZ = z.object({
|
|
153
|
+
projectName: z.string().min(1).optional(),
|
|
154
|
+
size: z.string().optional(),
|
|
155
|
+
});
|
|
156
|
+
export const ConfigAddRowResultZ = ConfigResultZ;
|
|
157
|
+
|
|
158
|
+
export const ConfigEnableTeamInputZ = z.object({
|
|
159
|
+
projectName: z.string().min(1).optional(),
|
|
160
|
+
name: z.string().min(1).optional(),
|
|
161
|
+
});
|
|
162
|
+
export const ConfigEnableTeamResultZ = ConfigResultZ;
|
|
163
|
+
|
|
164
|
+
export const ConfigDisableTeamInputZ = z.object({
|
|
165
|
+
projectName: z.string().min(1).optional(),
|
|
166
|
+
});
|
|
167
|
+
export const ConfigDisableTeamResultZ = ConfigResultZ;
|
|
168
|
+
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// app.*
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
export const AppSetRemoteAccessInputZ = z.object({
|
|
174
|
+
enabled: z.boolean(),
|
|
175
|
+
});
|
|
176
|
+
export const AppSetRemoteAccessResultZ = z.object({
|
|
177
|
+
enabled: z.boolean(),
|
|
178
|
+
url: z.string().nullable(),
|
|
179
|
+
token: z.string().nullable(),
|
|
180
|
+
qrPayload: z.string().nullable(),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
// daemon.*
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
|
|
187
|
+
export const DaemonShutdownInputZ = z.object({
|
|
188
|
+
reason: z.string().optional(),
|
|
189
|
+
});
|
|
190
|
+
export const DaemonShutdownResultZ = z.object({
|
|
191
|
+
stopping: z.literal(true),
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// ---------------------------------------------------------------------------
|
|
195
|
+
// Registry of action contracts (name → input/output schemas)
|
|
196
|
+
// ---------------------------------------------------------------------------
|
|
197
|
+
|
|
198
|
+
export const ActionContractsZ = {
|
|
199
|
+
"project.openTerminal": {
|
|
200
|
+
input: ProjectOpenTerminalInputZ,
|
|
201
|
+
result: ProjectOpenTerminalResultZ,
|
|
202
|
+
},
|
|
203
|
+
"project.launch": {
|
|
204
|
+
input: ProjectLaunchInputZ,
|
|
205
|
+
result: ProjectLaunchResultZ,
|
|
206
|
+
},
|
|
207
|
+
"project.stop": {
|
|
208
|
+
input: ProjectStopInputZ,
|
|
209
|
+
result: ProjectStopResultZ,
|
|
210
|
+
},
|
|
211
|
+
"project.restart": {
|
|
212
|
+
input: ProjectRestartInputZ,
|
|
213
|
+
result: ProjectRestartResultZ,
|
|
214
|
+
},
|
|
215
|
+
"project.activate": {
|
|
216
|
+
input: ProjectActivateInputZ,
|
|
217
|
+
result: ProjectActivateResultZ,
|
|
218
|
+
},
|
|
219
|
+
"terminal.respawn": {
|
|
220
|
+
input: TerminalRespawnInputZ,
|
|
221
|
+
result: TerminalRespawnResultZ,
|
|
222
|
+
},
|
|
223
|
+
"terminal.stop": {
|
|
224
|
+
input: TerminalStopInputZ,
|
|
225
|
+
result: TerminalStopResultZ,
|
|
226
|
+
},
|
|
227
|
+
"config.set": {
|
|
228
|
+
input: ConfigSetInputZ,
|
|
229
|
+
result: ConfigResultZ,
|
|
230
|
+
},
|
|
231
|
+
"config.addPane": {
|
|
232
|
+
input: ConfigAddPaneInputZ,
|
|
233
|
+
result: ConfigAddPaneResultZ,
|
|
234
|
+
},
|
|
235
|
+
"config.removePane": {
|
|
236
|
+
input: ConfigRemovePaneInputZ,
|
|
237
|
+
result: ConfigRemovePaneResultZ,
|
|
238
|
+
},
|
|
239
|
+
"config.addRow": {
|
|
240
|
+
input: ConfigAddRowInputZ,
|
|
241
|
+
result: ConfigAddRowResultZ,
|
|
242
|
+
},
|
|
243
|
+
"config.enableTeam": {
|
|
244
|
+
input: ConfigEnableTeamInputZ,
|
|
245
|
+
result: ConfigEnableTeamResultZ,
|
|
246
|
+
},
|
|
247
|
+
"config.disableTeam": {
|
|
248
|
+
input: ConfigDisableTeamInputZ,
|
|
249
|
+
result: ConfigDisableTeamResultZ,
|
|
250
|
+
},
|
|
251
|
+
"app.setRemoteAccess": {
|
|
252
|
+
input: AppSetRemoteAccessInputZ,
|
|
253
|
+
result: AppSetRemoteAccessResultZ,
|
|
254
|
+
},
|
|
255
|
+
"daemon.shutdown": {
|
|
256
|
+
input: DaemonShutdownInputZ,
|
|
257
|
+
result: DaemonShutdownResultZ,
|
|
258
|
+
},
|
|
259
|
+
} as const;
|
|
260
|
+
|
|
261
|
+
export type ActionName = keyof typeof ActionContractsZ;
|
|
262
|
+
|
|
263
|
+
export const ACTION_NAMES = Object.keys(ActionContractsZ) as ActionName[];
|
|
264
|
+
|
|
265
|
+
// ---------------------------------------------------------------------------
|
|
266
|
+
// Typed input / result helpers
|
|
267
|
+
// ---------------------------------------------------------------------------
|
|
268
|
+
|
|
269
|
+
export type ActionInput<N extends ActionName> = z.infer<(typeof ActionContractsZ)[N]["input"]>;
|
|
270
|
+
export type ActionResult<N extends ActionName> = z.infer<(typeof ActionContractsZ)[N]["result"]>;
|
|
271
|
+
|
|
272
|
+
// ---------------------------------------------------------------------------
|
|
273
|
+
// Wire envelope (what the HTTP endpoint actually returns)
|
|
274
|
+
// ---------------------------------------------------------------------------
|
|
275
|
+
|
|
276
|
+
export interface ActionErrorEnvelope {
|
|
277
|
+
ok: false;
|
|
278
|
+
error: {
|
|
279
|
+
code: string;
|
|
280
|
+
message: string;
|
|
281
|
+
details?: unknown;
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export interface ActionOkEnvelope<R> {
|
|
286
|
+
ok: true;
|
|
287
|
+
result: R;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export type ActionResponse<N extends ActionName> =
|
|
291
|
+
| ActionOkEnvelope<ActionResult<N>>
|
|
292
|
+
| ActionErrorEnvelope;
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Validate that a string is a known action name. Used by the dispatcher to
|
|
296
|
+
* narrow URL params before looking up the handler.
|
|
297
|
+
*/
|
|
298
|
+
export function isActionName(name: string): name is ActionName {
|
|
299
|
+
return name in ActionContractsZ;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Helper for a tagged WS broadcast frame so subscribers can decode without
|
|
304
|
+
* special-casing every action name.
|
|
305
|
+
*/
|
|
306
|
+
export interface ActionCompleteFrame<N extends ActionName = ActionName> {
|
|
307
|
+
type: "action.complete";
|
|
308
|
+
name: N;
|
|
309
|
+
result: ActionResult<N>;
|
|
310
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire codes for the v2 action dispatcher's error envelope. Codes are
|
|
3
|
+
* stable identifiers — never rename without a coordinated dashboard
|
|
4
|
+
* release. New codes go at the bottom of the union.
|
|
5
|
+
*
|
|
6
|
+
* The runtime class that throws these (`ActionError`, `TerminalCwdError`,
|
|
7
|
+
* etc.) lives in @tmux-ide/daemon's command-center/actions/errors.ts; the
|
|
8
|
+
* type lives here so dashboards and other UI clients can branch on the
|
|
9
|
+
* code without reaching into daemon-internal modules.
|
|
10
|
+
*/
|
|
11
|
+
export type ActionErrorCode =
|
|
12
|
+
| "project_not_found"
|
|
13
|
+
| "cwd_not_found"
|
|
14
|
+
| "cwd_not_directory"
|
|
15
|
+
| "cwd_stat_failed"
|
|
16
|
+
| "session_already_running"
|
|
17
|
+
| "session_not_running"
|
|
18
|
+
| "launch_failed"
|
|
19
|
+
| "stop_failed"
|
|
20
|
+
| "terminal_not_found"
|
|
21
|
+
| "validation_failed"
|
|
22
|
+
| "task_not_found"
|
|
23
|
+
| "goal_not_found"
|
|
24
|
+
| "milestone_not_found"
|
|
25
|
+
| "mission_not_set"
|
|
26
|
+
| "task_dependency_unmet"
|
|
27
|
+
| "task_already_assigned"
|
|
28
|
+
| "skill_invalid"
|
|
29
|
+
| "skill_not_found"
|
|
30
|
+
| "ide_yml_missing"
|
|
31
|
+
| "config_path_invalid"
|
|
32
|
+
| "config_validation_failed"
|
|
33
|
+
| "validation_assertion_not_found"
|
|
34
|
+
| "webhook_not_found"
|
|
35
|
+
| "webhook_test_failed"
|
|
36
|
+
| "remote_access_restart_failed"
|
|
37
|
+
| "shutdown_already_in_progress"
|
|
38
|
+
| "bad_request"
|
|
39
|
+
| "thread_not_found"
|
|
40
|
+
| "permission_request_not_found"
|
|
41
|
+
| "internal";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// PaneInfo — live tmux pane metadata (from src/command-center/discovery.ts)
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
export const PaneInfoSchemaZ = z.object({
|
|
8
|
+
id: z.string(),
|
|
9
|
+
index: z.number(),
|
|
10
|
+
title: z.string(),
|
|
11
|
+
currentCommand: z.string(),
|
|
12
|
+
width: z.number(),
|
|
13
|
+
height: z.number(),
|
|
14
|
+
active: z.boolean(),
|
|
15
|
+
role: z
|
|
16
|
+
.enum(["lead", "teammate", "planner", "validator", "researcher", "widget", "shell"])
|
|
17
|
+
.nullable(),
|
|
18
|
+
name: z.string().nullable(),
|
|
19
|
+
type: z.string().nullable(),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// SessionOverview — minimal session listing entry
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
export const SessionOverviewSchemaZ = z.object({
|
|
27
|
+
name: z.string(),
|
|
28
|
+
dir: z.string(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Inferred types
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
export type PaneInfo = z.infer<typeof PaneInfoSchemaZ>;
|
|
36
|
+
export type SessionOverview = z.infer<typeof SessionOverviewSchemaZ>;
|