@moejay/wrightty 0.0.0 → 0.1.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.
Files changed (92) hide show
  1. package/dist/client.d.ts +14 -0
  2. package/dist/client.js +83 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.js +8 -0
  5. package/dist/terminal.d.ts +48 -0
  6. package/dist/terminal.js +210 -0
  7. package/dist/types.d.ts +90 -0
  8. package/dist/types.js +3 -0
  9. package/package.json +35 -15
  10. package/.github/workflows/ci.yml +0 -90
  11. package/.github/workflows/release.yml +0 -177
  12. package/Cargo.lock +0 -2662
  13. package/Cargo.toml +0 -38
  14. package/PROTOCOL.md +0 -1351
  15. package/README.md +0 -386
  16. package/agents/ceo/AGENTS.md +0 -24
  17. package/agents/ceo/HEARTBEAT.md +0 -72
  18. package/agents/ceo/SOUL.md +0 -33
  19. package/agents/ceo/TOOLS.md +0 -3
  20. package/agents/founding-engineer/AGENTS.md +0 -44
  21. package/crates/wrightty/Cargo.toml +0 -43
  22. package/crates/wrightty/src/client_cmds.rs +0 -366
  23. package/crates/wrightty/src/discover.rs +0 -78
  24. package/crates/wrightty/src/main.rs +0 -100
  25. package/crates/wrightty/src/server.rs +0 -100
  26. package/crates/wrightty/src/term.rs +0 -338
  27. package/crates/wrightty-bridge-ghostty/Cargo.toml +0 -27
  28. package/crates/wrightty-bridge-ghostty/src/ghostty.rs +0 -422
  29. package/crates/wrightty-bridge-ghostty/src/lib.rs +0 -2
  30. package/crates/wrightty-bridge-ghostty/src/main.rs +0 -146
  31. package/crates/wrightty-bridge-ghostty/src/rpc.rs +0 -307
  32. package/crates/wrightty-bridge-kitty/Cargo.toml +0 -26
  33. package/crates/wrightty-bridge-kitty/src/kitty.rs +0 -269
  34. package/crates/wrightty-bridge-kitty/src/lib.rs +0 -2
  35. package/crates/wrightty-bridge-kitty/src/main.rs +0 -124
  36. package/crates/wrightty-bridge-kitty/src/rpc.rs +0 -304
  37. package/crates/wrightty-bridge-tmux/Cargo.toml +0 -26
  38. package/crates/wrightty-bridge-tmux/src/lib.rs +0 -2
  39. package/crates/wrightty-bridge-tmux/src/main.rs +0 -119
  40. package/crates/wrightty-bridge-tmux/src/rpc.rs +0 -291
  41. package/crates/wrightty-bridge-tmux/src/tmux.rs +0 -215
  42. package/crates/wrightty-bridge-wezterm/Cargo.toml +0 -26
  43. package/crates/wrightty-bridge-wezterm/src/lib.rs +0 -2
  44. package/crates/wrightty-bridge-wezterm/src/main.rs +0 -119
  45. package/crates/wrightty-bridge-wezterm/src/rpc.rs +0 -339
  46. package/crates/wrightty-bridge-wezterm/src/wezterm.rs +0 -190
  47. package/crates/wrightty-bridge-zellij/Cargo.toml +0 -27
  48. package/crates/wrightty-bridge-zellij/src/lib.rs +0 -2
  49. package/crates/wrightty-bridge-zellij/src/main.rs +0 -125
  50. package/crates/wrightty-bridge-zellij/src/rpc.rs +0 -328
  51. package/crates/wrightty-bridge-zellij/src/zellij.rs +0 -199
  52. package/crates/wrightty-client/Cargo.toml +0 -16
  53. package/crates/wrightty-client/src/client.rs +0 -254
  54. package/crates/wrightty-client/src/lib.rs +0 -2
  55. package/crates/wrightty-core/Cargo.toml +0 -21
  56. package/crates/wrightty-core/src/input.rs +0 -212
  57. package/crates/wrightty-core/src/lib.rs +0 -4
  58. package/crates/wrightty-core/src/screen.rs +0 -325
  59. package/crates/wrightty-core/src/session.rs +0 -249
  60. package/crates/wrightty-core/src/session_manager.rs +0 -77
  61. package/crates/wrightty-protocol/Cargo.toml +0 -13
  62. package/crates/wrightty-protocol/src/error.rs +0 -8
  63. package/crates/wrightty-protocol/src/events.rs +0 -138
  64. package/crates/wrightty-protocol/src/lib.rs +0 -4
  65. package/crates/wrightty-protocol/src/methods.rs +0 -321
  66. package/crates/wrightty-protocol/src/types.rs +0 -201
  67. package/crates/wrightty-server/Cargo.toml +0 -23
  68. package/crates/wrightty-server/src/lib.rs +0 -2
  69. package/crates/wrightty-server/src/main.rs +0 -65
  70. package/crates/wrightty-server/src/rpc.rs +0 -455
  71. package/crates/wrightty-server/src/state.rs +0 -39
  72. package/examples/basic_command.py +0 -53
  73. package/examples/interactive_tui.py +0 -86
  74. package/examples/record_session.py +0 -96
  75. package/install.sh +0 -81
  76. package/sdks/node/package-lock.json +0 -85
  77. package/sdks/node/package.json +0 -44
  78. package/sdks/node/src/client.ts +0 -94
  79. package/sdks/node/src/index.ts +0 -19
  80. package/sdks/node/src/terminal.ts +0 -258
  81. package/sdks/node/src/types.ts +0 -105
  82. package/sdks/node/tsconfig.json +0 -17
  83. package/sdks/python/README.md +0 -96
  84. package/sdks/python/pyproject.toml +0 -42
  85. package/sdks/python/wrightty/__init__.py +0 -6
  86. package/sdks/python/wrightty/cli.py +0 -210
  87. package/sdks/python/wrightty/client.py +0 -136
  88. package/sdks/python/wrightty/mcp_server.py +0 -434
  89. package/sdks/python/wrightty/terminal.py +0 -333
  90. package/skills/wrightty/SKILL.md +0 -261
  91. package/src/lib.rs +0 -1
  92. package/tests/integration_test.rs +0 -618
@@ -1,254 +0,0 @@
1
- use jsonrpsee::core::client::ClientT;
2
- use jsonrpsee::core::params::ObjectParams;
3
- use jsonrpsee::core::traits::ToRpcParams;
4
- use jsonrpsee::ws_client::{WsClient, WsClientBuilder};
5
- use serde::Serialize;
6
-
7
- use wrightty_protocol::methods::*;
8
- use wrightty_protocol::types::*;
9
-
10
- pub struct WrighttyClient {
11
- client: WsClient,
12
- }
13
-
14
- /// Wrapper to serialize a struct as named JSON-RPC params (object).
15
- struct NamedParams(serde_json::Value);
16
-
17
- impl ToRpcParams for NamedParams {
18
- fn to_rpc_params(
19
- self,
20
- ) -> Result<Option<Box<serde_json::value::RawValue>>, serde_json::Error> {
21
- let s = serde_json::to_string(&self.0)?;
22
- let raw = serde_json::value::RawValue::from_string(s)?;
23
- Ok(Some(raw))
24
- }
25
- }
26
-
27
- fn to_params<T: Serialize>(val: &T) -> Result<NamedParams, Box<dyn std::error::Error>> {
28
- Ok(NamedParams(serde_json::to_value(val)?))
29
- }
30
-
31
- impl WrighttyClient {
32
- pub async fn connect(url: &str) -> Result<Self, Box<dyn std::error::Error>> {
33
- let client = WsClientBuilder::default().build(url).await?;
34
- Ok(Self { client })
35
- }
36
-
37
- pub async fn get_info(&self) -> Result<ServerInfo, Box<dyn std::error::Error>> {
38
- let result: GetInfoResult = self
39
- .client
40
- .request("Wrightty.getInfo", ObjectParams::new())
41
- .await?;
42
- Ok(result.info)
43
- }
44
-
45
- pub async fn session_create(
46
- &self,
47
- params: SessionCreateParams,
48
- ) -> Result<String, Box<dyn std::error::Error>> {
49
- let result: SessionCreateResult = self
50
- .client
51
- .request("Session.create", to_params(&params)?)
52
- .await?;
53
- Ok(result.session_id)
54
- }
55
-
56
- pub async fn session_destroy(
57
- &self,
58
- session_id: &str,
59
- ) -> Result<(), Box<dyn std::error::Error>> {
60
- let params = SessionDestroyParams {
61
- session_id: session_id.to_string(),
62
- signal: None,
63
- };
64
- let _: SessionDestroyResult = self
65
- .client
66
- .request("Session.destroy", to_params(&params)?)
67
- .await?;
68
- Ok(())
69
- }
70
-
71
- pub async fn session_list(&self) -> Result<Vec<SessionInfo>, Box<dyn std::error::Error>> {
72
- let result: SessionListResult = self
73
- .client
74
- .request("Session.list", ObjectParams::new())
75
- .await?;
76
- Ok(result.sessions)
77
- }
78
-
79
- pub async fn send_keys(
80
- &self,
81
- session_id: &str,
82
- keys: Vec<KeyInput>,
83
- ) -> Result<(), Box<dyn std::error::Error>> {
84
- let params = InputSendKeysParams {
85
- session_id: session_id.to_string(),
86
- keys,
87
- };
88
- let _: serde_json::Value = self
89
- .client
90
- .request("Input.sendKeys", to_params(&params)?)
91
- .await?;
92
- Ok(())
93
- }
94
-
95
- pub async fn send_text(
96
- &self,
97
- session_id: &str,
98
- text: &str,
99
- ) -> Result<(), Box<dyn std::error::Error>> {
100
- let params = InputSendTextParams {
101
- session_id: session_id.to_string(),
102
- text: text.to_string(),
103
- };
104
- let _: serde_json::Value = self
105
- .client
106
- .request("Input.sendText", to_params(&params)?)
107
- .await?;
108
- Ok(())
109
- }
110
-
111
- pub async fn get_text(
112
- &self,
113
- session_id: &str,
114
- ) -> Result<String, Box<dyn std::error::Error>> {
115
- let params = ScreenGetTextParams {
116
- session_id: session_id.to_string(),
117
- region: None,
118
- trim_trailing_whitespace: true,
119
- };
120
- let result: ScreenGetTextResult = self
121
- .client
122
- .request("Screen.getText", to_params(&params)?)
123
- .await?;
124
- Ok(result.text)
125
- }
126
-
127
- pub async fn resize(
128
- &self,
129
- session_id: &str,
130
- cols: u16,
131
- rows: u16,
132
- ) -> Result<(), Box<dyn std::error::Error>> {
133
- let params = TerminalResizeParams {
134
- session_id: session_id.to_string(),
135
- cols,
136
- rows,
137
- };
138
- let _: serde_json::Value = self
139
- .client
140
- .request("Terminal.resize", to_params(&params)?)
141
- .await?;
142
- Ok(())
143
- }
144
-
145
- pub async fn get_contents(
146
- &self,
147
- session_id: &str,
148
- ) -> Result<ScreenGetContentsResult, Box<dyn std::error::Error>> {
149
- let params = ScreenGetContentsParams {
150
- session_id: session_id.to_string(),
151
- region: None,
152
- };
153
- let result: ScreenGetContentsResult = self
154
- .client
155
- .request("Screen.getContents", to_params(&params)?)
156
- .await?;
157
- Ok(result)
158
- }
159
-
160
- pub async fn get_scrollback(
161
- &self,
162
- session_id: &str,
163
- lines: u32,
164
- offset: u32,
165
- ) -> Result<ScreenGetScrollbackResult, Box<dyn std::error::Error>> {
166
- let params = ScreenGetScrollbackParams {
167
- session_id: session_id.to_string(),
168
- lines,
169
- offset,
170
- };
171
- let result: ScreenGetScrollbackResult = self
172
- .client
173
- .request("Screen.getScrollback", to_params(&params)?)
174
- .await?;
175
- Ok(result)
176
- }
177
-
178
- pub async fn screenshot(
179
- &self,
180
- session_id: &str,
181
- format: ScreenshotFormat,
182
- ) -> Result<ScreenScreenshotResult, Box<dyn std::error::Error>> {
183
- let params = ScreenScreenshotParams {
184
- session_id: session_id.to_string(),
185
- format,
186
- theme: None,
187
- font: None,
188
- };
189
- let result: ScreenScreenshotResult = self
190
- .client
191
- .request("Screen.screenshot", to_params(&params)?)
192
- .await?;
193
- Ok(result)
194
- }
195
-
196
- pub async fn wait_for_text(
197
- &self,
198
- session_id: &str,
199
- pattern: &str,
200
- is_regex: bool,
201
- timeout_ms: u64,
202
- ) -> Result<ScreenWaitForTextResult, Box<dyn std::error::Error>> {
203
- let params = ScreenWaitForTextParams {
204
- session_id: session_id.to_string(),
205
- pattern: pattern.to_string(),
206
- is_regex,
207
- region: None,
208
- timeout: timeout_ms,
209
- interval: 50,
210
- };
211
- let result: ScreenWaitForTextResult = self
212
- .client
213
- .request("Screen.waitForText", to_params(&params)?)
214
- .await?;
215
- Ok(result)
216
- }
217
-
218
- pub async fn send_mouse(
219
- &self,
220
- session_id: &str,
221
- event: &str,
222
- button: &str,
223
- row: u32,
224
- col: u32,
225
- ) -> Result<(), Box<dyn std::error::Error>> {
226
- let params = InputSendMouseParams {
227
- session_id: session_id.to_string(),
228
- event: event.to_string(),
229
- button: button.to_string(),
230
- row,
231
- col,
232
- modifiers: vec![],
233
- };
234
- let _: serde_json::Value = self
235
- .client
236
- .request("Input.sendMouse", to_params(&params)?)
237
- .await?;
238
- Ok(())
239
- }
240
-
241
- pub async fn get_size(
242
- &self,
243
- session_id: &str,
244
- ) -> Result<(u16, u16), Box<dyn std::error::Error>> {
245
- let params = TerminalGetSizeParams {
246
- session_id: session_id.to_string(),
247
- };
248
- let result: TerminalGetSizeResult = self
249
- .client
250
- .request("Terminal.getSize", to_params(&params)?)
251
- .await?;
252
- Ok((result.cols, result.rows))
253
- }
254
- }
@@ -1,2 +0,0 @@
1
- pub mod client;
2
- pub use client::WrighttyClient;
@@ -1,21 +0,0 @@
1
- [package]
2
- name = "wrightty-core"
3
- version.workspace = true
4
- edition.workspace = true
5
- license.workspace = true
6
- authors.workspace = true
7
- repository.workspace = true
8
- homepage.workspace = true
9
- description = "Core terminal engine for Wrightty"
10
-
11
- [dependencies]
12
- wrightty-protocol = { version = "0.1.0", path = "../wrightty-protocol" }
13
- alacritty_terminal = "0.25.1"
14
- vte = { version = "0.15", features = ["ansi"] }
15
- portable-pty = "0.9"
16
- tokio = { version = "1", features = ["full"] }
17
- uuid = { version = "1", features = ["v4"] }
18
- regex = "1"
19
- log = "0.4"
20
- thiserror = "2"
21
- base64 = "0.22"
@@ -1,212 +0,0 @@
1
- use wrightty_protocol::types::{KeyEvent, KeyInput, KeyType, Modifier};
2
-
3
- /// Encode a sequence of KeyInput values into bytes to write to a PTY.
4
- pub fn encode_keys(keys: &[KeyInput]) -> Vec<u8> {
5
- let mut out = Vec::new();
6
- for key in keys {
7
- match key {
8
- KeyInput::Shorthand(s) => encode_shorthand(s, &mut out),
9
- KeyInput::Structured(event) => encode_key_event(event, &mut out),
10
- }
11
- }
12
- out
13
- }
14
-
15
- fn encode_shorthand(s: &str, out: &mut Vec<u8>) {
16
- // Check for modifier combos like "Ctrl+c"
17
- if let Some((modifier_str, key_str)) = s.split_once('+') {
18
- let modifier = match modifier_str {
19
- "Ctrl" => Some(Modifier::Ctrl),
20
- "Alt" => Some(Modifier::Alt),
21
- "Shift" => Some(Modifier::Shift),
22
- "Meta" => Some(Modifier::Meta),
23
- _ => None,
24
- };
25
-
26
- if let Some(m) = modifier {
27
- // Try to parse the key part as a named key or single char
28
- if key_str.len() == 1 {
29
- let event = KeyEvent {
30
- key: KeyType::Char,
31
- char: Some(key_str.to_string()),
32
- n: None,
33
- modifiers: vec![m],
34
- };
35
- encode_key_event(&event, out);
36
- return;
37
- }
38
- // Named key with modifier
39
- if let Some(key_type) = parse_named_key(key_str) {
40
- let event = KeyEvent {
41
- key: key_type,
42
- char: None,
43
- n: None,
44
- modifiers: vec![m],
45
- };
46
- encode_key_event(&event, out);
47
- return;
48
- }
49
- }
50
- }
51
-
52
- // Check named keys
53
- if let Some(key_type) = parse_named_key(s) {
54
- let event = KeyEvent {
55
- key: key_type,
56
- char: None,
57
- n: None,
58
- modifiers: vec![],
59
- };
60
- encode_key_event(&event, out);
61
- return;
62
- }
63
-
64
- // Single character
65
- if s.len() == 1 {
66
- out.extend_from_slice(s.as_bytes());
67
- return;
68
- }
69
-
70
- // Function keys like "F5"
71
- if let Some(rest) = s.strip_prefix('F') && let Ok(n) = rest.parse::<u8>() {
72
- let event = KeyEvent {
73
- key: KeyType::F,
74
- char: None,
75
- n: Some(n),
76
- modifiers: vec![],
77
- };
78
- encode_key_event(&event, out);
79
- return;
80
- }
81
-
82
- // Fallback: send as raw text
83
- out.extend_from_slice(s.as_bytes());
84
- }
85
-
86
- fn parse_named_key(s: &str) -> Option<KeyType> {
87
- match s {
88
- "Enter" => Some(KeyType::Enter),
89
- "Tab" => Some(KeyType::Tab),
90
- "Backspace" => Some(KeyType::Backspace),
91
- "Delete" => Some(KeyType::Delete),
92
- "Escape" => Some(KeyType::Escape),
93
- "ArrowUp" => Some(KeyType::ArrowUp),
94
- "ArrowDown" => Some(KeyType::ArrowDown),
95
- "ArrowLeft" => Some(KeyType::ArrowLeft),
96
- "ArrowRight" => Some(KeyType::ArrowRight),
97
- "Home" => Some(KeyType::Home),
98
- "End" => Some(KeyType::End),
99
- "PageUp" => Some(KeyType::PageUp),
100
- "PageDown" => Some(KeyType::PageDown),
101
- "Insert" => Some(KeyType::Insert),
102
- _ => None,
103
- }
104
- }
105
-
106
- fn encode_key_event(event: &KeyEvent, out: &mut Vec<u8>) {
107
- let has_ctrl = event.modifiers.iter().any(|m| matches!(m, Modifier::Ctrl));
108
- let has_alt = event.modifiers.iter().any(|m| matches!(m, Modifier::Alt));
109
-
110
- match &event.key {
111
- KeyType::Char => {
112
- if let Some(ref ch) = event.char && let Some(c) = ch.chars().next() {
113
- if has_ctrl {
114
- // Ctrl+letter = letter & 0x1f
115
- let ctrl_byte = (c.to_ascii_lowercase() as u8) & 0x1f;
116
- if has_alt {
117
- out.push(0x1b);
118
- }
119
- out.push(ctrl_byte);
120
- } else if has_alt {
121
- out.push(0x1b);
122
- out.extend_from_slice(ch.as_bytes());
123
- } else {
124
- out.extend_from_slice(ch.as_bytes());
125
- }
126
- }
127
- }
128
- KeyType::Enter => {
129
- if has_alt {
130
- out.push(0x1b);
131
- }
132
- out.push(b'\r');
133
- }
134
- KeyType::Tab => {
135
- if has_alt {
136
- out.push(0x1b);
137
- }
138
- out.push(b'\t');
139
- }
140
- KeyType::Backspace => {
141
- if has_alt {
142
- out.push(0x1b);
143
- }
144
- out.push(0x7f);
145
- }
146
- KeyType::Escape => {
147
- out.push(0x1b);
148
- }
149
- KeyType::Delete => {
150
- if has_alt {
151
- out.push(0x1b);
152
- }
153
- out.extend_from_slice(b"\x1b[3~");
154
- }
155
- // Arrow keys — normal mode (not application mode for now)
156
- KeyType::ArrowUp => encode_csi_key(b'A', has_alt, out),
157
- KeyType::ArrowDown => encode_csi_key(b'B', has_alt, out),
158
- KeyType::ArrowRight => encode_csi_key(b'C', has_alt, out),
159
- KeyType::ArrowLeft => encode_csi_key(b'D', has_alt, out),
160
- KeyType::Home => encode_csi_key(b'H', has_alt, out),
161
- KeyType::End => encode_csi_key(b'F', has_alt, out),
162
- KeyType::PageUp => {
163
- if has_alt {
164
- out.push(0x1b);
165
- }
166
- out.extend_from_slice(b"\x1b[5~");
167
- }
168
- KeyType::PageDown => {
169
- if has_alt {
170
- out.push(0x1b);
171
- }
172
- out.extend_from_slice(b"\x1b[6~");
173
- }
174
- KeyType::Insert => {
175
- if has_alt {
176
- out.push(0x1b);
177
- }
178
- out.extend_from_slice(b"\x1b[2~");
179
- }
180
- KeyType::F => {
181
- let n = event.n.unwrap_or(1);
182
- let seq = match n {
183
- 1 => b"\x1bOP".as_slice(),
184
- 2 => b"\x1bOQ",
185
- 3 => b"\x1bOR",
186
- 4 => b"\x1bOS",
187
- 5 => b"\x1b[15~",
188
- 6 => b"\x1b[17~",
189
- 7 => b"\x1b[18~",
190
- 8 => b"\x1b[19~",
191
- 9 => b"\x1b[20~",
192
- 10 => b"\x1b[21~",
193
- 11 => b"\x1b[23~",
194
- 12 => b"\x1b[24~",
195
- _ => return,
196
- };
197
- if has_alt {
198
- out.push(0x1b);
199
- }
200
- out.extend_from_slice(seq);
201
- }
202
- }
203
- }
204
-
205
- fn encode_csi_key(code: u8, alt: bool, out: &mut Vec<u8>) {
206
- if alt {
207
- out.push(0x1b);
208
- }
209
- out.push(0x1b);
210
- out.push(b'[');
211
- out.push(code);
212
- }
@@ -1,4 +0,0 @@
1
- pub mod session;
2
- pub mod session_manager;
3
- pub mod screen;
4
- pub mod input;