tmux-ide 2.6.1 → 2.8.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 +36 -14
- package/bin/cli.js +4174 -1235
- package/bin/cli.ts +426 -72
- package/package.json +10 -6
- package/packages/contracts/src/__tests__/control.test.ts +154 -0
- package/packages/contracts/src/control.ts +217 -0
- package/packages/contracts/src/index.ts +1 -0
- package/packages/daemon/dist/agent-explain.d.ts +8 -1
- package/packages/daemon/dist/agent-explain.js +19 -3
- package/packages/daemon/dist/control/client.d.ts +23 -0
- package/packages/daemon/dist/control/client.js +105 -0
- package/packages/daemon/dist/control/dispatch.d.ts +34 -0
- package/packages/daemon/dist/control/dispatch.js +83 -0
- package/packages/daemon/dist/control/fanout.d.ts +19 -0
- package/packages/daemon/dist/control/fanout.js +37 -0
- package/packages/daemon/dist/control/frames.d.ts +23 -0
- package/packages/daemon/dist/control/frames.js +37 -0
- package/packages/daemon/dist/control/lifecycle.d.ts +45 -0
- package/packages/daemon/dist/control/lifecycle.js +114 -0
- package/packages/daemon/dist/control/server.d.ts +16 -0
- package/packages/daemon/dist/control/server.js +214 -0
- package/packages/daemon/dist/control/verbs.d.ts +11 -0
- package/packages/daemon/dist/control/verbs.js +91 -0
- package/packages/daemon/dist/doctor.d.ts +18 -0
- package/packages/daemon/dist/doctor.js +105 -15
- package/packages/daemon/dist/lib/agent-discovery.d.ts +27 -2
- package/packages/daemon/dist/lib/agent-discovery.js +29 -14
- package/packages/daemon/dist/lib/app-config.d.ts +106 -0
- package/packages/daemon/dist/lib/app-config.js +104 -5
- package/packages/daemon/dist/lib/manifest-pack.d.ts +79 -0
- package/packages/daemon/dist/lib/manifest-pack.js +232 -0
- package/packages/daemon/dist/lib/state-home.d.ts +2 -0
- package/packages/daemon/dist/lib/state-home.js +12 -0
- 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/lib/update-check.js +5 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Info.plist +34 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/MacOS/tmux-ide-notifier +0 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/PkgInfo +1 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Resources/AppIcon.icns +0 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/Resources/Assets.car +0 -0
- package/packages/daemon/dist/native/TmuxIdeNotifier.app/Contents/_CodeSignature/CodeResources +139 -0
- package/packages/daemon/dist/restore.d.ts +35 -8
- package/packages/daemon/dist/restore.js +52 -15
- package/packages/daemon/dist/send.d.ts +33 -1
- package/packages/daemon/dist/send.js +32 -19
- 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 +34 -6
- package/packages/daemon/src/control/client.ts +128 -0
- package/packages/daemon/src/control/dispatch.ts +107 -0
- package/packages/daemon/src/control/fanout.ts +44 -0
- package/packages/daemon/src/control/frames.ts +40 -0
- package/packages/daemon/src/control/lifecycle.ts +151 -0
- package/packages/daemon/src/control/server.ts +237 -0
- package/packages/daemon/src/control/verbs.ts +118 -0
- package/packages/daemon/src/doctor.ts +113 -28
- package/packages/daemon/src/lib/agent-discovery.ts +53 -13
- package/packages/daemon/src/lib/app-config.ts +194 -5
- package/packages/daemon/src/lib/manifest-pack.ts +255 -0
- package/packages/daemon/src/lib/state-home.ts +13 -0
- package/packages/daemon/src/lib/tui-binary.ts +165 -0
- package/packages/daemon/src/lib/update-check.ts +5 -0
- package/packages/daemon/src/restore.ts +53 -15
- package/packages/daemon/src/send.ts +55 -21
- package/packages/daemon/src/tui/chrome/events.ts +4 -4
- package/packages/daemon/src/tui/chrome/front-door.ts +39 -0
- package/packages/daemon/src/tui/chrome/notify-prefs.ts +58 -0
- package/packages/daemon/src/tui/chrome/notify-state.ts +76 -0
- package/packages/daemon/src/tui/chrome/notify.ts +737 -52
- package/packages/daemon/src/tui/chrome/updater.ts +318 -30
- package/packages/daemon/src/tui/compiled.ts +11 -3
- package/packages/daemon/src/tui/detect/classify.ts +49 -0
- package/packages/daemon/src/tui/detect/manifest-loader.ts +56 -6
- package/packages/daemon/src/tui/detect/manifest.ts +39 -3
- package/packages/daemon/src/tui/detect/manifests.ts +395 -33
- package/packages/daemon/src/tui/detect/process-tree.ts +33 -3
- package/packages/daemon/src/tui/detect/session-id.ts +503 -0
- package/packages/daemon/src/tui/integrations/opencode.ts +121 -0
- package/packages/daemon/src/tui/main.ts +13 -1
- package/packages/daemon/src/tui/mirror/ack-writer.ts +77 -0
- package/packages/daemon/src/tui/mirror/agent-chip.ts +126 -0
- package/packages/daemon/src/tui/mirror/agent-lifecycle.ts +437 -0
- package/packages/daemon/src/tui/mirror/agent-rows.ts +155 -0
- package/packages/daemon/src/tui/mirror/app-state.ts +342 -0
- package/packages/daemon/src/tui/mirror/app.tsx +7048 -0
- package/packages/daemon/src/tui/mirror/attention.ts +110 -0
- package/packages/daemon/src/tui/mirror/blit.ts +186 -0
- package/packages/daemon/src/tui/mirror/control-client.ts +80 -9
- package/packages/daemon/src/tui/mirror/dialog-model.ts +298 -0
- package/packages/daemon/src/tui/mirror/dialog-stack.ts +367 -0
- package/packages/daemon/src/tui/mirror/diff-model.ts +387 -0
- package/packages/daemon/src/tui/mirror/editor-buffer.ts +117 -0
- package/packages/daemon/src/tui/mirror/file-tree.ts +322 -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/host-terminal.ts +49 -0
- package/packages/daemon/src/tui/mirror/hosted.ts +205 -0
- package/packages/daemon/src/tui/mirror/input-coalescer.ts +105 -0
- package/packages/daemon/src/tui/mirror/layout-parse.ts +154 -0
- package/packages/daemon/src/tui/mirror/menu-model.ts +210 -0
- package/packages/daemon/src/tui/mirror/palette.ts +564 -0
- package/packages/daemon/src/tui/mirror/pane-mirror.ts +578 -20
- package/packages/daemon/src/tui/mirror/pane-surface.tsx +422 -0
- package/packages/daemon/src/tui/mirror/perf-tap.ts +186 -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 +376 -0
- package/packages/daemon/src/tui/mirror/session-mirror.ts +724 -0
- package/packages/daemon/src/tui/mirror/settings-model.ts +425 -0
- package/packages/daemon/src/tui/mirror/sidebar.tsx +218 -0
- package/packages/daemon/src/tui/mirror/size-truth.ts +130 -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/mirror/theme.ts +45 -0
- package/packages/daemon/src/tui/team/entry.ts +34 -7
- package/packages/daemon/src/tui/team/fuzzy.ts +20 -0
- package/packages/daemon/src/tui/team/report.ts +11 -1
- package/packages/daemon/src/tui/team/sessions.ts +184 -17
- package/packages/daemon/src/tui/team/wait.ts +144 -0
- package/scripts/build-macos-notifier.mjs +160 -0
- package/scripts/build-tui.mjs +11 -4
- package/scripts/perf-mirror.mjs +313 -0
- package/scripts/postinstall.js +8 -1
- package/scripts/prepublish-check.mjs +37 -1
- package/scripts/publish-tap.sh +55 -0
- package/skill/SKILL.md +110 -2
- 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
- package/packages/daemon/src/tui/mirror/viewer.tsx +0 -166
package/templates/convex.yml
CHANGED
package/templates/default.yml
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
name: my-project
|
|
2
2
|
|
|
3
|
-
# before: npm install
|
|
3
|
+
# before: npm install # optional pre-launch hook (runs once, before panes start)
|
|
4
|
+
|
|
5
|
+
# sidebar: true # inject the fleet nav column (prefix b toggles it live)
|
|
4
6
|
|
|
5
7
|
rows:
|
|
6
8
|
- size: 70%
|
|
@@ -11,10 +13,14 @@ rows:
|
|
|
11
13
|
command: claude
|
|
12
14
|
|
|
13
15
|
- panes:
|
|
16
|
+
# Widget panes render native UI instead of a command:
|
|
17
|
+
# type: explorer | changes | preview | config | sidebar
|
|
18
|
+
- title: Changes
|
|
19
|
+
type: changes # live git changes — no command, tmux-ide draws it
|
|
14
20
|
- title: Dev Server
|
|
15
21
|
# command: npm run dev
|
|
16
|
-
# dir: apps/web
|
|
17
|
-
# env:
|
|
18
|
-
# PORT: 3000
|
|
22
|
+
# dir: apps/web # per-pane working directory
|
|
23
|
+
# env: # per-pane environment variables
|
|
24
|
+
# PORT: "3000"
|
|
19
25
|
- title: Shell
|
|
20
|
-
|
|
26
|
+
focus: true # give this pane initial focus
|
package/templates/go.yml
CHANGED
package/templates/missions.yml
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
name: project-name
|
|
2
2
|
|
|
3
|
+
# Ground-truth agent status (working/blocked/done glyphs on the fleet tabs)
|
|
4
|
+
# comes from Claude Code's lifecycle hooks. Wire them once with:
|
|
5
|
+
# tmux-ide integration install claude
|
|
6
|
+
|
|
3
7
|
team:
|
|
4
8
|
name: missions
|
|
5
9
|
|
|
10
|
+
sidebar: true # fleet nav column — jump between agents (toggle: prefix b)
|
|
11
|
+
|
|
6
12
|
rows:
|
|
7
13
|
- size: 70%
|
|
8
14
|
panes:
|
package/templates/nextjs.yml
CHANGED
package/templates/python.yml
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
name: my-app
|
|
2
2
|
|
|
3
|
+
# before: pip install -r requirements.txt # or: uv sync / poetry install
|
|
4
|
+
|
|
3
5
|
rows:
|
|
4
6
|
- size: 70%
|
|
5
7
|
panes:
|
|
@@ -11,5 +13,7 @@ rows:
|
|
|
11
13
|
- panes:
|
|
12
14
|
- title: Server
|
|
13
15
|
# command: uvicorn main:app --reload
|
|
16
|
+
- title: Changes
|
|
17
|
+
type: changes # live git changes widget
|
|
14
18
|
- title: Shell
|
|
15
19
|
focus: true
|
|
@@ -25,19 +25,12 @@ You are a backend development specialist.
|
|
|
25
25
|
|
|
26
26
|
Your dispatch prompt includes relevant excerpts from the knowledge library (.tmux-ide/library/) and AGENTS.md. Use these for architectural decisions.
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Reporting
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Self-report your state — this drives the fleet status glyphs (see AGENTS.md):
|
|
31
31
|
|
|
32
|
-
-
|
|
33
|
-
- Run any configured after-run hooks (e.g., linting)
|
|
34
|
-
- Auto-dispatch the next available task
|
|
35
|
-
- Append your summary to the learnings library
|
|
32
|
+
tmux set-option -p @agent_state "done:$(date +%s)" # working|blocked|done|idle
|
|
36
33
|
|
|
37
|
-
|
|
34
|
+
Then report the result to the lead, and flag anything out of scope:
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
tmux-ide task done <TASK_ID> --proof "what changed and how you verified it" --summary "backend outcome"
|
|
41
|
-
|
|
42
|
-
If you find out-of-scope issues, report them:
|
|
43
|
-
tmux-ide task update <TASK_ID> --discovered-issues "description of issue"
|
|
36
|
+
tmux-ide send <lead-pane> "what changed, how you verified it, operational concerns"
|
|
@@ -25,19 +25,12 @@ You are a frontend development specialist.
|
|
|
25
25
|
|
|
26
26
|
Your dispatch prompt includes relevant excerpts from the knowledge library (.tmux-ide/library/) and AGENTS.md. Use these for architectural decisions.
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Reporting
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Self-report your state — this drives the fleet status glyphs (see AGENTS.md):
|
|
31
31
|
|
|
32
|
-
-
|
|
33
|
-
- Run any configured after-run hooks (e.g., linting)
|
|
34
|
-
- Auto-dispatch the next available task
|
|
35
|
-
- Append your summary to the learnings library
|
|
32
|
+
tmux set-option -p @agent_state "done:$(date +%s)" # working|blocked|done|idle
|
|
36
33
|
|
|
37
|
-
|
|
34
|
+
Then report the result to the lead, and flag anything out of scope:
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
tmux-ide task done <TASK_ID> --proof "what changed and how you verified it" --summary "frontend outcome"
|
|
41
|
-
|
|
42
|
-
If you find out-of-scope issues, report them:
|
|
43
|
-
tmux-ide task update <TASK_ID> --discovered-issues "description of issue"
|
|
36
|
+
tmux-ide send <lead-pane> "what changed, what you verified, any follow-up risks"
|
|
@@ -25,19 +25,12 @@ You are a general-purpose development agent.
|
|
|
25
25
|
|
|
26
26
|
You are a general-purpose agent. Your dispatch prompt includes mission, goal, and task context along with relevant library excerpts. Follow the task description closely.
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Reporting
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Self-report your state — this drives the fleet status glyphs (see AGENTS.md):
|
|
31
31
|
|
|
32
|
-
-
|
|
33
|
-
- Run any configured after-run hooks (e.g., linting)
|
|
34
|
-
- Auto-dispatch the next available task
|
|
35
|
-
- Append your summary to the learnings library
|
|
32
|
+
tmux set-option -p @agent_state "done:$(date +%s)" # working|blocked|done|idle
|
|
36
33
|
|
|
37
|
-
|
|
34
|
+
Then report the result to the lead, and flag anything out of scope:
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
tmux-ide task done <TASK_ID> --proof "what you accomplished" --summary "key learnings for future tasks"
|
|
41
|
-
|
|
42
|
-
If you discover out-of-scope issues, note them:
|
|
43
|
-
tmux-ide task update <TASK_ID> --discovered-issues "description of issue"
|
|
36
|
+
tmux-ide send <lead-pane> "what you accomplished, how you verified it, follow-ups"
|
|
@@ -57,22 +57,17 @@ Surface useful findings early without stalling delivery. Prefer high-signal obse
|
|
|
57
57
|
|
|
58
58
|
## Reporting Protocol
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
Self-report your state — this drives the fleet status glyphs (see AGENTS.md):
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
tmux set-option -p @agent_state "done:$(date +%s)" # working|blocked|done|idle
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
Then send your findings to the lead:
|
|
65
|
+
|
|
66
|
+
tmux-ide send <lead-pane> "findings, evidence, severity, next actions"
|
|
67
|
+
|
|
68
|
+
Your report should include:
|
|
65
69
|
|
|
66
70
|
- What you inspected
|
|
67
71
|
- The most important findings
|
|
68
72
|
- Why they matter
|
|
69
73
|
- The exact next action you recommend
|
|
70
|
-
|
|
71
|
-
## After Completion
|
|
72
|
-
|
|
73
|
-
When you finish, the orchestrator will:
|
|
74
|
-
|
|
75
|
-
- Notify the lead with your proof and summary
|
|
76
|
-
- Run any configured after-run hooks
|
|
77
|
-
- Auto-dispatch the next available task
|
|
78
|
-
- Append your summary to the learnings library
|
|
@@ -20,23 +20,14 @@ You are a code review and validation agent.
|
|
|
20
20
|
3. Run relevant tests or manual checks
|
|
21
21
|
4. Report each assertion's status
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Reporting
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
tmux-ide validate assert <ASSERT_ID> --status passing --evidence "what you verified"
|
|
27
|
-
tmux-ide validate assert <ASSERT_ID> --status failing --evidence "what's wrong"
|
|
28
|
-
tmux-ide validate assert <ASSERT_ID> --status blocked --evidence "why it's blocked"
|
|
25
|
+
Self-report your state — this drives the fleet status glyphs (see AGENTS.md):
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+
tmux set-option -p @agent_state "done:$(date +%s)" # working|blocked|done|idle
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
Then report the verdict to the lead: for each assertion give its status
|
|
30
|
+
(passing / failing / blocked) and the evidence, plus any issues you found beyond
|
|
31
|
+
the validation contract:
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
When you finish, the orchestrator will:
|
|
38
|
-
|
|
39
|
-
- Notify the lead with your proof and summary
|
|
40
|
-
- Run any configured after-run hooks (e.g., linting)
|
|
41
|
-
- Auto-dispatch the next available task
|
|
42
|
-
- Append your summary to the learnings library
|
|
33
|
+
tmux-ide send <lead-pane> "assertion results with evidence, plus out-of-scope issues"
|
package/templates/vite.yml
CHANGED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SPIKE viewer — renders ONE live tmux pane inside an OpenTUI app.
|
|
3
|
-
*
|
|
4
|
-
* The proof for the unified-TUI architecture: a control-mode client streams
|
|
5
|
-
* the pane's bytes into a headless terminal (PaneMirror), this app draws the
|
|
6
|
-
* grid, and keystrokes are forwarded back through `send-keys`. tmux stays the
|
|
7
|
-
* multiplexer underneath; tmux-ide owns the screen.
|
|
8
|
-
*
|
|
9
|
-
* Run (needs the repo-root bunfig preload):
|
|
10
|
-
* bun packages/daemon/src/tui/mirror/viewer.tsx --target <session>
|
|
11
|
-
* Exit with ctrl+q (everything else is forwarded to the pane).
|
|
12
|
-
*/
|
|
13
|
-
import { parseArgs } from "node:util";
|
|
14
|
-
import { render, useKeyboard, useTerminalDimensions } from "@opentui/solid";
|
|
15
|
-
import { RGBA } from "@opentui/core";
|
|
16
|
-
import { createSignal, onMount, onCleanup, For } from "solid-js";
|
|
17
|
-
import { ControlModeClient } from "./control-client.ts";
|
|
18
|
-
import { PaneMirror, type MirrorSnapshot } from "./pane-mirror.ts";
|
|
19
|
-
|
|
20
|
-
const { values } = parseArgs({ options: { target: { type: "string" } } });
|
|
21
|
-
const target = values.target ?? "_spike-target";
|
|
22
|
-
|
|
23
|
-
// The 16 base ANSI palette colors, mapped for OpenTUI. Higher palette
|
|
24
|
-
// entries fall back to the default foreground — fine for a spike.
|
|
25
|
-
const PALETTE: Array<[number, number, number]> = [
|
|
26
|
-
[40, 40, 48],
|
|
27
|
-
[220, 90, 90],
|
|
28
|
-
[110, 200, 130],
|
|
29
|
-
[220, 200, 100],
|
|
30
|
-
[110, 150, 240],
|
|
31
|
-
[190, 120, 220],
|
|
32
|
-
[100, 200, 210],
|
|
33
|
-
[200, 200, 210],
|
|
34
|
-
[120, 120, 140],
|
|
35
|
-
[250, 120, 120],
|
|
36
|
-
[140, 230, 160],
|
|
37
|
-
[240, 220, 130],
|
|
38
|
-
[140, 180, 250],
|
|
39
|
-
[220, 150, 250],
|
|
40
|
-
[130, 230, 240],
|
|
41
|
-
[240, 240, 250],
|
|
42
|
-
];
|
|
43
|
-
|
|
44
|
-
/** Map named OpenTUI key events to tmux send-keys names. */
|
|
45
|
-
const KEYMAP: Record<string, string> = {
|
|
46
|
-
return: "Enter",
|
|
47
|
-
backspace: "BSpace",
|
|
48
|
-
tab: "Tab",
|
|
49
|
-
escape: "Escape",
|
|
50
|
-
up: "Up",
|
|
51
|
-
down: "Down",
|
|
52
|
-
left: "Left",
|
|
53
|
-
right: "Right",
|
|
54
|
-
pageup: "PgUp",
|
|
55
|
-
pagedown: "PgDn",
|
|
56
|
-
home: "Home",
|
|
57
|
-
end: "End",
|
|
58
|
-
delete: "DC",
|
|
59
|
-
space: "Space",
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
render(() => {
|
|
63
|
-
const dims = useTerminalDimensions();
|
|
64
|
-
const cols = Math.max(20, dims().width - 2);
|
|
65
|
-
const rows = Math.max(5, dims().height - 3);
|
|
66
|
-
|
|
67
|
-
const mirror = new PaneMirror(cols, rows);
|
|
68
|
-
const [snap, setSnap] = createSignal<MirrorSnapshot>(mirror.snapshot());
|
|
69
|
-
const [status, setStatus] = createSignal(`attaching to ${target}…`);
|
|
70
|
-
let pane = "";
|
|
71
|
-
let dirty = false;
|
|
72
|
-
|
|
73
|
-
const client = new ControlModeClient({
|
|
74
|
-
attachTarget: target,
|
|
75
|
-
onOutput: (p, data) => {
|
|
76
|
-
if (p === pane || pane === "") {
|
|
77
|
-
mirror.write(data);
|
|
78
|
-
dirty = true;
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
onExit: () => {
|
|
82
|
-
setStatus("control client exited");
|
|
83
|
-
},
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
onMount(() => {
|
|
87
|
-
(async () => {
|
|
88
|
-
try {
|
|
89
|
-
await client.start();
|
|
90
|
-
// Pin our control client's size so tmux lays the window out to match
|
|
91
|
-
// the mirror grid, then seed with the pane's current content (-e keeps
|
|
92
|
-
// colors) so we don't start from a blank screen.
|
|
93
|
-
await client.command(`refresh-client -C ${cols}x${rows}`);
|
|
94
|
-
const panes = await client.command(`list-panes -t ${target} -F "#{pane_id}"`);
|
|
95
|
-
pane = panes[0] ?? "";
|
|
96
|
-
const seed = await client.command(`capture-pane -p -e -t ${pane}`);
|
|
97
|
-
mirror.write(seed.join("\r\n") + "\r\n");
|
|
98
|
-
dirty = true;
|
|
99
|
-
setStatus(`live: ${target} ${pane} (ctrl+q to quit)`);
|
|
100
|
-
} catch (e) {
|
|
101
|
-
setStatus(`error: ${(e as Error).message}`);
|
|
102
|
-
}
|
|
103
|
-
})();
|
|
104
|
-
|
|
105
|
-
// Coalesce bursts: redraw at most ~30fps instead of per %output event.
|
|
106
|
-
const timer = setInterval(() => {
|
|
107
|
-
if (!dirty) return;
|
|
108
|
-
dirty = false;
|
|
109
|
-
setSnap(mirror.snapshot());
|
|
110
|
-
}, 33);
|
|
111
|
-
onCleanup(() => {
|
|
112
|
-
clearInterval(timer);
|
|
113
|
-
client.dispose();
|
|
114
|
-
mirror.dispose();
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
useKeyboard((evt) => {
|
|
119
|
-
if (evt.ctrl && evt.name === "q") {
|
|
120
|
-
client.dispose();
|
|
121
|
-
process.exit(0);
|
|
122
|
-
}
|
|
123
|
-
if (!pane) return;
|
|
124
|
-
if (evt.ctrl && evt.name.length === 1) {
|
|
125
|
-
void client.sendKey(pane, `C-${evt.name}`).catch(() => {});
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
const named = KEYMAP[evt.name];
|
|
129
|
-
if (named) {
|
|
130
|
-
void client.sendKey(pane, named).catch(() => {});
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (evt.name.length === 1 && !evt.meta && !evt.alt) {
|
|
134
|
-
void client.sendText(pane, evt.name).catch(() => {});
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
const fgFor = (idx: number | null): RGBA => {
|
|
139
|
-
if (idx === null || idx < 0 || idx > 15) return RGBA.fromInts(200, 200, 210, 255);
|
|
140
|
-
const [r, g, b] = PALETTE[idx]!;
|
|
141
|
-
return RGBA.fromInts(r, g, b, 255);
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
return (
|
|
145
|
-
<box flexDirection="column" flexGrow={1} backgroundColor={RGBA.fromInts(18, 18, 24, 255)}>
|
|
146
|
-
<box paddingLeft={1} flexDirection="row" gap={1}>
|
|
147
|
-
<text fg={RGBA.fromInts(130, 170, 255, 255)}>tmux-ide mirror</text>
|
|
148
|
-
<text fg={RGBA.fromInts(120, 120, 140, 255)}>{status()}</text>
|
|
149
|
-
</box>
|
|
150
|
-
<box flexDirection="column" flexGrow={1} paddingLeft={1}>
|
|
151
|
-
<For each={snap().rows}>
|
|
152
|
-
{(runs) => (
|
|
153
|
-
<box flexDirection="row">
|
|
154
|
-
<For each={runs}>{(run) => <text fg={fgFor(run.fg)}>{run.text}</text>}</For>
|
|
155
|
-
</box>
|
|
156
|
-
)}
|
|
157
|
-
</For>
|
|
158
|
-
</box>
|
|
159
|
-
<box paddingLeft={1}>
|
|
160
|
-
<text fg={RGBA.fromInts(120, 120, 140, 255)}>
|
|
161
|
-
{`cursor ${snap().cursorX},${snap().cursorY} · keys forwarded · ctrl+q quits`}
|
|
162
|
-
</text>
|
|
163
|
-
</box>
|
|
164
|
-
</box>
|
|
165
|
-
);
|
|
166
|
-
});
|