tmux-ide 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -9
- package/bin/cli.js +1024 -519
- package/bin/cli.ts +63 -6
- package/bunfig.toml +4 -0
- package/package.json +18 -7
- 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/dist/agent-explain.d.ts +8 -1
- package/packages/daemon/dist/agent-explain.js +19 -3
- package/packages/daemon/dist/lib/tui-binary.d.ts +57 -0
- package/packages/daemon/dist/lib/tui-binary.js +130 -0
- package/packages/daemon/dist/widgets/explorer/breadcrumbs.d.ts +1 -1
- package/packages/daemon/dist/widgets/explorer/footer.d.ts +1 -1
- package/packages/daemon/dist/widgets/explorer/tree.d.ts +1 -1
- package/packages/daemon/dist/widgets/lib/help-overlay.d.ts +1 -1
- package/packages/daemon/dist/widgets/setup/agent-naming.d.ts +1 -1
- package/packages/daemon/dist/widgets/setup/config-tree.d.ts +1 -1
- package/packages/daemon/dist/widgets/setup/detect-panel.d.ts +1 -1
- package/packages/daemon/dist/widgets/setup/field-editor.d.ts +1 -1
- package/packages/daemon/dist/widgets/setup/footer.d.ts +1 -1
- package/packages/daemon/dist/widgets/setup/layout-picker.d.ts +1 -1
- package/packages/daemon/src/agent-explain.ts +298 -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 +427 -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/tui-binary.ts +165 -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 +382 -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 +510 -0
- package/packages/daemon/src/tui/chrome/welcome.ts +124 -0
- package/packages/daemon/src/tui/compiled.ts +121 -0
- package/packages/daemon/src/tui/detect/classify.ts +208 -0
- package/packages/daemon/src/tui/detect/manifest-loader.ts +193 -0
- package/packages/daemon/src/tui/detect/manifest.ts +199 -0
- package/packages/daemon/src/tui/detect/manifests.ts +354 -0
- package/packages/daemon/src/tui/detect/process-tree.ts +217 -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 +82 -0
- package/packages/daemon/src/tui/mirror/ack-writer.ts +77 -0
- package/packages/daemon/src/tui/mirror/agent-chip.ts +97 -0
- package/packages/daemon/src/tui/mirror/agent-rows.ts +133 -0
- package/packages/daemon/src/tui/mirror/app-state.ts +179 -0
- package/packages/daemon/src/tui/mirror/app.tsx +5265 -0
- package/packages/daemon/src/tui/mirror/blit.ts +186 -0
- package/packages/daemon/src/tui/mirror/control-client.ts +214 -0
- package/packages/daemon/src/tui/mirror/control.ts +97 -0
- package/packages/daemon/src/tui/mirror/dialog-model.ts +298 -0
- package/packages/daemon/src/tui/mirror/dialog-stack.ts +354 -0
- package/packages/daemon/src/tui/mirror/diff-model.ts +112 -0
- package/packages/daemon/src/tui/mirror/editor-buffer.ts +117 -0
- package/packages/daemon/src/tui/mirror/file-tree.ts +97 -0
- package/packages/daemon/src/tui/mirror/focus-border.ts +57 -0
- package/packages/daemon/src/tui/mirror/folder-picker.ts +124 -0
- package/packages/daemon/src/tui/mirror/home-model.ts +174 -0
- package/packages/daemon/src/tui/mirror/input-coalescer.ts +105 -0
- package/packages/daemon/src/tui/mirror/menu-model.ts +187 -0
- package/packages/daemon/src/tui/mirror/palette.ts +274 -0
- package/packages/daemon/src/tui/mirror/pane-mirror.ts +561 -0
- package/packages/daemon/src/tui/mirror/pane-surface.tsx +415 -0
- package/packages/daemon/src/tui/mirror/perf-tap.ts +160 -0
- package/packages/daemon/src/tui/mirror/resize-model.ts +85 -0
- package/packages/daemon/src/tui/mirror/scrollbar-model.ts +88 -0
- package/packages/daemon/src/tui/mirror/search-model.ts +70 -0
- package/packages/daemon/src/tui/mirror/selection.ts +262 -0
- package/packages/daemon/src/tui/mirror/session-mirror.ts +443 -0
- package/packages/daemon/src/tui/mirror/settings-model.ts +345 -0
- package/packages/daemon/src/tui/mirror/size-truth.ts +77 -0
- package/packages/daemon/src/tui/mirror/spans.ts +46 -0
- package/packages/daemon/src/tui/mirror/status-grammar.ts +32 -0
- package/packages/daemon/src/tui/team/CONTROL.md +50 -0
- package/packages/daemon/src/tui/team/entry.ts +38 -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 +83 -0
- package/packages/daemon/src/tui/team/sessions.ts +433 -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/build-tui.mjs +11 -4
- package/scripts/perf-mirror.mjs +313 -0
- package/scripts/postinstall.js +26 -2
- package/skill/SKILL.md +22 -0
- package/templates/AGENTS.md +14 -7
- package/templates/agent-team-monorepo.yml +8 -0
- package/templates/agent-team-nextjs.yml +8 -0
- package/templates/agent-team.yml +10 -0
- package/templates/convex.yml +2 -0
- package/templates/default.yml +11 -5
- package/templates/go.yml +4 -0
- package/templates/missions.yml +6 -0
- package/templates/nextjs.yml +4 -0
- package/templates/python.yml +4 -0
- package/templates/skills/backend.md +5 -12
- package/templates/skills/frontend.md +5 -12
- package/templates/skills/general-worker.md +5 -12
- package/templates/skills/researcher.md +7 -12
- package/templates/skills/reviewer.md +7 -16
- package/templates/vite.yml +4 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tmux-ide widget PANELS — every widget is a floating app dialog.
|
|
3
|
+
*
|
|
4
|
+
* The one-app milestone: instead of living as dedicated tmux panes, each widget
|
|
5
|
+
* opens as a `display-popup -E` over your work, one root-table keystroke away,
|
|
6
|
+
* esc/q to close (the popup exits when the widget process does). This mirrors the
|
|
7
|
+
* chrome popups (switcher `M-p` / cheat sheet `M-k`) but points each key at
|
|
8
|
+
* `tmux-ide popup <widget>`, which execs the bun widget synchronously inside the
|
|
9
|
+
* popup's PTY (see the `popup` case in bin/cli.ts).
|
|
10
|
+
*
|
|
11
|
+
* {@link PANEL_POPUPS} is the single source of truth — the widget name (the
|
|
12
|
+
* `tmux-ide popup <widget>` arg AND the `keys.panels.<widget>` config key), a
|
|
13
|
+
* menu label, and per-widget popup sizing. The status bar's adopt binds one key
|
|
14
|
+
* per entry, the cheat sheet lists them, and the actions menu opens them — all
|
|
15
|
+
* derived from this list so they never drift.
|
|
16
|
+
*
|
|
17
|
+
* Only widgets that EXIST and stand alone are here: `preview` renders whatever
|
|
18
|
+
* the explorer selected (via a shared `@preview_file` tmux option — nothing to
|
|
19
|
+
* show on its own) and `setup` is the onboarding wizard, so neither is a panel.
|
|
20
|
+
* `tasks`/`warroom`/`costs` were removed in the v2.6.0 front-end trim.
|
|
21
|
+
*
|
|
22
|
+
* Every builder here is PURE (tested); the io (running the popup) is the CLI's.
|
|
23
|
+
*/
|
|
24
|
+
import type { AppPanelKeys } from "../../lib/app-config.ts";
|
|
25
|
+
|
|
26
|
+
/** A widget that can float as a panel popup. */
|
|
27
|
+
export interface PanelPopup {
|
|
28
|
+
/** Widget name — the `tmux-ide popup <widget>` arg + `keys.panels` field. */
|
|
29
|
+
widget: "explorer" | "changes" | "config";
|
|
30
|
+
/** Human label for the actions menu row. */
|
|
31
|
+
label: string;
|
|
32
|
+
/**
|
|
33
|
+
* `display-popup` size tokens (tmux `-w`/`-h`). Sized per widget: the explorer
|
|
34
|
+
* is a tall, narrower file column; changes is a wide diff surface; config is a
|
|
35
|
+
* roomy tree editor. All large — a panel floats OVER your work, so it should
|
|
36
|
+
* dominate while open, then vanish on esc.
|
|
37
|
+
*/
|
|
38
|
+
width: string;
|
|
39
|
+
height: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The panel registry — the widgets bound as floating popups, in menu order.
|
|
44
|
+
* Keys are configurable via `~/.tmux-ide/config.json` (`keys.panels.*`); the
|
|
45
|
+
* defaults live in {@link ../../lib/app-config.ts}. Sizing is fixed here (tuned,
|
|
46
|
+
* not configurable — a deliberate scope line).
|
|
47
|
+
*/
|
|
48
|
+
export const PANEL_POPUPS: PanelPopup[] = [
|
|
49
|
+
{ widget: "explorer", label: "⊞ Files", width: "60%", height: "85%" },
|
|
50
|
+
{ widget: "changes", label: "± Changes", width: "85%", height: "90%" },
|
|
51
|
+
{ widget: "config", label: "⚙ Config", width: "80%", height: "85%" },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
/** The widget names that `tmux-ide popup <widget>` accepts (the panel set). */
|
|
55
|
+
export const POPUP_WIDGETS: string[] = PANEL_POPUPS.map((p) => p.widget);
|
|
56
|
+
|
|
57
|
+
/** The CLI invocation a panel popup runs (`tmux-ide popup <widget>`). */
|
|
58
|
+
export function panelPopupCli(widget: string): string {
|
|
59
|
+
return `tmux-ide popup ${widget}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The configured root-table key for a panel. `AppPanelKeys` fields are named
|
|
64
|
+
* for the widgets, so this is a typed lookup — the panel registry and the config
|
|
65
|
+
* shape stay in lockstep.
|
|
66
|
+
*/
|
|
67
|
+
export function panelKey(panel: PanelPopup, keys: AppPanelKeys): string {
|
|
68
|
+
return keys[panel.widget];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* PURE — the `display-popup` command STRING that floats a panel (shared by the
|
|
73
|
+
* actions menu's Panels rows, so a menu pick opens an identical popup to the
|
|
74
|
+
* key bind). `-d '#{pane_current_path}'` opens the widget on the pane's cwd, so
|
|
75
|
+
* the explorer/changes/config land on the project you're looking at.
|
|
76
|
+
*/
|
|
77
|
+
export function panelPopupCommand(panel: PanelPopup, cli = panelPopupCli(panel.widget)): string {
|
|
78
|
+
return `display-popup -E -d '#{pane_current_path}' -w ${panel.width} -h ${panel.height} "${cli}"`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* PURE — the tmux argv that binds a panel's root-table key to its
|
|
83
|
+
* `display-popup`. Server-wide root-table bind (tmux has no per-session
|
|
84
|
+
* bind-key), mirroring the switcher's popup key — see the note on
|
|
85
|
+
* `unadoptSession`. Idempotent: re-binding a key overwrites it.
|
|
86
|
+
*/
|
|
87
|
+
export function panelPopupBindCommand(
|
|
88
|
+
panel: PanelPopup,
|
|
89
|
+
key: string,
|
|
90
|
+
cli = panelPopupCli(panel.widget),
|
|
91
|
+
): string[] {
|
|
92
|
+
return [
|
|
93
|
+
"bind-key",
|
|
94
|
+
"-n",
|
|
95
|
+
key,
|
|
96
|
+
"display-popup",
|
|
97
|
+
"-E",
|
|
98
|
+
"-d",
|
|
99
|
+
"#{pane_current_path}",
|
|
100
|
+
"-w",
|
|
101
|
+
panel.width,
|
|
102
|
+
"-h",
|
|
103
|
+
panel.height,
|
|
104
|
+
cli,
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** PURE — the tmux argv that removes a panel's key binding. */
|
|
109
|
+
export function panelPopupUnbindCommand(key: string): string[] {
|
|
110
|
+
return ["unbind-key", "-n", key];
|
|
111
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tmux-ide SIDEBAR — the app's persistent nav column.
|
|
3
|
+
*
|
|
4
|
+
* Unlike the widget PANELS (floating popups) this is a real, always-visible
|
|
5
|
+
* tmux pane: a narrow full-height left column that lists the fleet
|
|
6
|
+
* (project → session → window) with live status glyphs and jumps the viewing
|
|
7
|
+
* client anywhere on enter. It's summoned per-session with a toggle key
|
|
8
|
+
* (`keys.sidebar`, default `M-b`) that runs `tmux-ide sidebar-toggle`, so the
|
|
9
|
+
* app column appears wherever you call for it — in ANY adopted session.
|
|
10
|
+
*
|
|
11
|
+
* This module owns the tmux mechanics: the pure toggle-key bind builders (bound
|
|
12
|
+
* server-wide by `adoptSession`, like the other chrome keys) and the io that
|
|
13
|
+
* opens/finds/closes the column pane. The pane is marked with
|
|
14
|
+
* {@link SIDEBAR_PANE_OPTION} so the data layer excludes it from status rollups
|
|
15
|
+
* (see `../team/sessions.ts`) and the chip updater never labels it an agent.
|
|
16
|
+
*
|
|
17
|
+
* The command builders are PURE (tested); the io wrappers are thin.
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync } from "node:fs";
|
|
20
|
+
import { dirname, resolve } from "node:path";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
import { runTmux } from "@tmux-ide/tmux-bridge";
|
|
23
|
+
import type { ThemeConfig } from "../../types.ts";
|
|
24
|
+
import { shellEscape } from "../../lib/shell.ts";
|
|
25
|
+
import { SIDEBAR_PANE_OPTION } from "../team/sessions.ts";
|
|
26
|
+
import { resolveTuiLaunch, findCompiledTui, isBunAvailable } from "../compiled.ts";
|
|
27
|
+
|
|
28
|
+
export { SIDEBAR_PANE_OPTION };
|
|
29
|
+
|
|
30
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the sidebar widget's `.tsx` entry, robust across BOTH run modes. The
|
|
34
|
+
* widget sources ship uncompiled and are spawned by `bun`, so a bundled caller
|
|
35
|
+
* (this module inlined into `bin/cli.js`) must reach them via a bin-anchored
|
|
36
|
+
* path, while a dev caller (this module at `tui/chrome/`) reaches them relatively
|
|
37
|
+
* — the two differ, so we probe candidates and take the first that exists. Falls
|
|
38
|
+
* back to the dev path so the returned command is at least well-formed.
|
|
39
|
+
*/
|
|
40
|
+
export function sidebarWidgetScript(): string {
|
|
41
|
+
const candidates = [
|
|
42
|
+
resolve(__dirname, "../../widgets/sidebar/index.tsx"),
|
|
43
|
+
resolve(__dirname, "../packages/daemon/src/widgets/sidebar/index.tsx"),
|
|
44
|
+
];
|
|
45
|
+
return candidates.find((p) => existsSync(p)) ?? candidates[0]!;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* PURE — the shell command the sidebar pane runs. `cd`s into the project dir
|
|
50
|
+
* first so bun finds `bunfig.toml` (the @opentui/solid JSX preload), then boots
|
|
51
|
+
* the widget with the current session, dir, and (optional) theme. Mirrors
|
|
52
|
+
* `resolveWidgetCommand`'s shape but self-locates the script so it survives the
|
|
53
|
+
* bundle (see {@link sidebarWidgetScript}).
|
|
54
|
+
*/
|
|
55
|
+
export function sidebarWidgetCommand(
|
|
56
|
+
scriptPath: string,
|
|
57
|
+
session: string,
|
|
58
|
+
dir: string,
|
|
59
|
+
theme: ThemeConfig | null,
|
|
60
|
+
): string {
|
|
61
|
+
const args = [`--session=${session}`, `--dir=${dir}`];
|
|
62
|
+
if (theme) args.push(`--theme=${JSON.stringify(theme)}`);
|
|
63
|
+
|
|
64
|
+
const launch = resolveTuiLaunch({
|
|
65
|
+
surface: "sidebar",
|
|
66
|
+
scriptPath,
|
|
67
|
+
args,
|
|
68
|
+
checkoutExists: existsSync(scriptPath),
|
|
69
|
+
bunAvailable: isBunAvailable(),
|
|
70
|
+
compiledBinary: findCompiledTui(),
|
|
71
|
+
});
|
|
72
|
+
if (launch.mode === "unavailable") {
|
|
73
|
+
// Keep the pane command well-formed; the pane shows bun's own error. This
|
|
74
|
+
// path only trips on a broken install (no checkout, no bun, no binary).
|
|
75
|
+
return `cd ${shellEscape(dir)} && bun ${shellEscape(scriptPath)} ${args.map(shellEscape).join(" ")}`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const escaped = launch.argv.map(shellEscape).join(" ");
|
|
79
|
+
// Both modes cd into the project dir first: bun needs a nearby bunfig only in
|
|
80
|
+
// a checkout (which sits above dir); the binary is self-contained.
|
|
81
|
+
return `cd ${shellEscape(dir)} && ${shellEscape(launch.bin)} ${escaped}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Root-table key that toggles the sidebar: `M-b` (Alt+b). Like the other chrome
|
|
86
|
+
* keys it lives in the ROOT table so it fires without the prefix from any
|
|
87
|
+
* adopted session; Alt-letter keys are low-collision in terminal apps. Default
|
|
88
|
+
* for {@link sidebarToggleBindCommand}; overridable via `keys.sidebar`.
|
|
89
|
+
*/
|
|
90
|
+
export const SIDEBAR_KEY = "M-b";
|
|
91
|
+
|
|
92
|
+
/** Default sidebar column width in tmux columns — narrow enough to leave the
|
|
93
|
+
* work area room, wide enough for a glyph + a truncated name. */
|
|
94
|
+
export const DEFAULT_SIDEBAR_WIDTH = 30;
|
|
95
|
+
|
|
96
|
+
/** Normalized sidebar settings. */
|
|
97
|
+
export interface ResolvedSidebar {
|
|
98
|
+
enabled: boolean;
|
|
99
|
+
width: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* PURE — normalize the ide.yml `sidebar` sugar (`true` | `{ width }` | `false` |
|
|
104
|
+
* undefined) into `{ enabled, width }`. A missing/invalid width falls back to
|
|
105
|
+
* {@link DEFAULT_SIDEBAR_WIDTH}; width is clamped to a sane floor so a typo can't
|
|
106
|
+
* produce a zero-width column.
|
|
107
|
+
*/
|
|
108
|
+
export function resolveSidebarConfig(raw: unknown): ResolvedSidebar {
|
|
109
|
+
if (raw === true) return { enabled: true, width: DEFAULT_SIDEBAR_WIDTH };
|
|
110
|
+
if (!raw || typeof raw !== "object") return { enabled: false, width: DEFAULT_SIDEBAR_WIDTH };
|
|
111
|
+
const width = parseSidebarWidth((raw as { width?: unknown }).width);
|
|
112
|
+
return { enabled: true, width };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** PURE — parse a width value (string or number) to a positive int column count,
|
|
116
|
+
* falling back to the default and flooring at 10. */
|
|
117
|
+
export function parseSidebarWidth(value: unknown): number {
|
|
118
|
+
const n =
|
|
119
|
+
typeof value === "number" ? value : typeof value === "string" ? parseInt(value, 10) : NaN;
|
|
120
|
+
if (!Number.isFinite(n) || n <= 0) return DEFAULT_SIDEBAR_WIDTH;
|
|
121
|
+
return Math.max(10, Math.floor(n));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* PURE — the tmux argv that binds the sidebar toggle key. `run-shell`
|
|
126
|
+
* format-expands `#{session_name}` into `--session` (bind args themselves do NOT
|
|
127
|
+
* expand; run-shell DOES — the same trick the menu bind uses), so the CLI toggles
|
|
128
|
+
* the column in whichever session the client is viewing. Server-wide root-table
|
|
129
|
+
* bind, mirroring the switcher's M-p — see the note on `unadoptSession`.
|
|
130
|
+
*/
|
|
131
|
+
export function sidebarToggleBindCommand(
|
|
132
|
+
cli = "tmux-ide sidebar-toggle",
|
|
133
|
+
key = SIDEBAR_KEY,
|
|
134
|
+
): string[] {
|
|
135
|
+
return ["bind-key", "-n", key, "run-shell", `${cli} --session '#{session_name}'`];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** PURE — the tmux argv that removes the sidebar toggle binding. */
|
|
139
|
+
export function sidebarToggleUnbindCommand(key = SIDEBAR_KEY): string[] {
|
|
140
|
+
return ["unbind-key", "-n", key];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* PURE — the `split-window` argv that opens the sidebar column. `-h -b -f`
|
|
145
|
+
* creates a horizontal split placed BEFORE (left of) the target that spans the
|
|
146
|
+
* FULL window height (`-f`) regardless of which pane is active, `-l <width>`
|
|
147
|
+
* fixes its column width, and `-P -F '#{pane_id}'` prints the new pane id. The
|
|
148
|
+
* trailing `widgetCmd` runs the sidebar widget in the pane.
|
|
149
|
+
*/
|
|
150
|
+
export function sidebarSplitCommand(
|
|
151
|
+
session: string,
|
|
152
|
+
dir: string,
|
|
153
|
+
width: number,
|
|
154
|
+
widgetCmd: string,
|
|
155
|
+
): string[] {
|
|
156
|
+
return [
|
|
157
|
+
"split-window",
|
|
158
|
+
"-P",
|
|
159
|
+
"-F",
|
|
160
|
+
"#{pane_id}",
|
|
161
|
+
"-t",
|
|
162
|
+
session,
|
|
163
|
+
"-h",
|
|
164
|
+
"-b",
|
|
165
|
+
"-f",
|
|
166
|
+
"-l",
|
|
167
|
+
String(width),
|
|
168
|
+
"-c",
|
|
169
|
+
dir,
|
|
170
|
+
widgetCmd,
|
|
171
|
+
];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* io — the sidebar pane id already open in `session`, or null. Reads the
|
|
176
|
+
* {@link SIDEBAR_PANE_OPTION} marker off each pane so a toggle can find and close
|
|
177
|
+
* an existing column.
|
|
178
|
+
*/
|
|
179
|
+
export function findSidebarPane(session: string): string | null {
|
|
180
|
+
try {
|
|
181
|
+
const raw = runTmux(
|
|
182
|
+
["list-panes", "-t", session, "-F", `#{pane_id}\t#{${SIDEBAR_PANE_OPTION}}`],
|
|
183
|
+
{ encoding: "utf-8" },
|
|
184
|
+
)
|
|
185
|
+
.toString()
|
|
186
|
+
.trim();
|
|
187
|
+
for (const line of raw.split("\n").filter(Boolean)) {
|
|
188
|
+
const [id = "", flag = ""] = line.split("\t");
|
|
189
|
+
if (flag === "1" && id) return id;
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
// no such session / tmux unavailable — treat as "no sidebar"
|
|
193
|
+
}
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* io — open the sidebar column in `session` on `dir`, mark the pane so the data
|
|
199
|
+
* layer excludes it, title it "sidebar" (the pane-border chip falls back to the
|
|
200
|
+
* title for non-agent panes), and return the new pane id.
|
|
201
|
+
*/
|
|
202
|
+
export function openSidebarPane(
|
|
203
|
+
session: string,
|
|
204
|
+
dir: string,
|
|
205
|
+
width: number,
|
|
206
|
+
theme: ThemeConfig | null,
|
|
207
|
+
): string {
|
|
208
|
+
const widgetCmd = sidebarWidgetCommand(sidebarWidgetScript(), session, dir, theme);
|
|
209
|
+
const paneId = runTmux(sidebarSplitCommand(session, dir, width, widgetCmd), {
|
|
210
|
+
encoding: "utf-8",
|
|
211
|
+
})
|
|
212
|
+
.toString()
|
|
213
|
+
.trim();
|
|
214
|
+
runTmux(["set-option", "-pqt", paneId, SIDEBAR_PANE_OPTION, "1"]);
|
|
215
|
+
runTmux(["select-pane", "-t", paneId, "-T", "sidebar"]);
|
|
216
|
+
return paneId;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** io — close the sidebar column pane. */
|
|
220
|
+
export function closeSidebarPane(paneId: string): void {
|
|
221
|
+
runTmux(["kill-pane", "-t", paneId]);
|
|
222
|
+
}
|