portacode 0.3.19.dev4__py3-none-any.whl → 1.4.11.dev1__py3-none-any.whl
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.
Potentially problematic release.
This version of portacode might be problematic. Click here for more details.
- portacode/_version.py +16 -3
- portacode/cli.py +143 -17
- portacode/connection/client.py +149 -10
- portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +824 -21
- portacode/connection/handlers/__init__.py +28 -1
- portacode/connection/handlers/base.py +78 -16
- portacode/connection/handlers/chunked_content.py +244 -0
- portacode/connection/handlers/diff_handlers.py +603 -0
- portacode/connection/handlers/file_handlers.py +902 -17
- portacode/connection/handlers/project_aware_file_handlers.py +226 -0
- portacode/connection/handlers/project_state/README.md +312 -0
- portacode/connection/handlers/project_state/__init__.py +92 -0
- portacode/connection/handlers/project_state/file_system_watcher.py +179 -0
- portacode/connection/handlers/project_state/git_manager.py +1502 -0
- portacode/connection/handlers/project_state/handlers.py +875 -0
- portacode/connection/handlers/project_state/manager.py +1331 -0
- portacode/connection/handlers/project_state/models.py +108 -0
- portacode/connection/handlers/project_state/utils.py +50 -0
- portacode/connection/handlers/project_state_handlers.py +45 -2185
- portacode/connection/handlers/proxmox_infra.py +361 -0
- portacode/connection/handlers/registry.py +15 -4
- portacode/connection/handlers/session.py +483 -32
- portacode/connection/handlers/system_handlers.py +147 -8
- portacode/connection/handlers/tab_factory.py +53 -46
- portacode/connection/handlers/terminal_handlers.py +21 -8
- portacode/connection/handlers/update_handler.py +61 -0
- portacode/connection/multiplex.py +60 -2
- portacode/connection/terminal.py +214 -24
- portacode/keypair.py +63 -1
- portacode/link_capture/__init__.py +38 -0
- portacode/link_capture/__pycache__/__init__.cpython-311.pyc +0 -0
- portacode/link_capture/bin/__pycache__/link_capture_wrapper.cpython-311.pyc +0 -0
- portacode/link_capture/bin/elinks +3 -0
- portacode/link_capture/bin/gio-open +3 -0
- portacode/link_capture/bin/gnome-open +3 -0
- portacode/link_capture/bin/gvfs-open +3 -0
- portacode/link_capture/bin/kde-open +3 -0
- portacode/link_capture/bin/kfmclient +3 -0
- portacode/link_capture/bin/link_capture_exec.sh +11 -0
- portacode/link_capture/bin/link_capture_wrapper.py +75 -0
- portacode/link_capture/bin/links +3 -0
- portacode/link_capture/bin/links2 +3 -0
- portacode/link_capture/bin/lynx +3 -0
- portacode/link_capture/bin/mate-open +3 -0
- portacode/link_capture/bin/netsurf +3 -0
- portacode/link_capture/bin/sensible-browser +3 -0
- portacode/link_capture/bin/w3m +3 -0
- portacode/link_capture/bin/x-www-browser +3 -0
- portacode/link_capture/bin/xdg-open +3 -0
- portacode/logging_categories.py +140 -0
- portacode/pairing.py +103 -0
- portacode/static/js/test-ntp-clock.html +63 -0
- portacode/static/js/utils/ntp-clock.js +232 -0
- portacode/utils/NTP_ARCHITECTURE.md +136 -0
- portacode/utils/__init__.py +1 -0
- portacode/utils/diff_apply.py +456 -0
- portacode/utils/diff_renderer.py +371 -0
- portacode/utils/ntp_clock.py +65 -0
- portacode-1.4.11.dev1.dist-info/METADATA +298 -0
- portacode-1.4.11.dev1.dist-info/RECORD +97 -0
- {portacode-0.3.19.dev4.dist-info → portacode-1.4.11.dev1.dist-info}/WHEEL +1 -1
- portacode-1.4.11.dev1.dist-info/top_level.txt +3 -0
- test_modules/README.md +296 -0
- test_modules/__init__.py +1 -0
- test_modules/test_device_online.py +44 -0
- test_modules/test_file_operations.py +743 -0
- test_modules/test_git_status_ui.py +370 -0
- test_modules/test_login_flow.py +50 -0
- test_modules/test_navigate_testing_folder.py +361 -0
- test_modules/test_play_store_screenshots.py +294 -0
- test_modules/test_terminal_buffer_performance.py +261 -0
- test_modules/test_terminal_interaction.py +80 -0
- test_modules/test_terminal_loading_race_condition.py +95 -0
- test_modules/test_terminal_start.py +56 -0
- testing_framework/.env.example +21 -0
- testing_framework/README.md +334 -0
- testing_framework/__init__.py +17 -0
- testing_framework/cli.py +326 -0
- testing_framework/core/__init__.py +1 -0
- testing_framework/core/base_test.py +336 -0
- testing_framework/core/cli_manager.py +177 -0
- testing_framework/core/hierarchical_runner.py +577 -0
- testing_framework/core/playwright_manager.py +520 -0
- testing_framework/core/runner.py +447 -0
- testing_framework/core/shared_cli_manager.py +234 -0
- testing_framework/core/test_discovery.py +112 -0
- testing_framework/requirements.txt +12 -0
- portacode-0.3.19.dev4.dist-info/METADATA +0 -241
- portacode-0.3.19.dev4.dist-info/RECORD +0 -30
- portacode-0.3.19.dev4.dist-info/top_level.txt +0 -1
- {portacode-0.3.19.dev4.dist-info → portacode-1.4.11.dev1.dist-info}/entry_points.txt +0 -0
- {portacode-0.3.19.dev4.dist-info → portacode-1.4.11.dev1.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,10 +1,38 @@
|
|
|
1
1
|
# WebSocket Communication Protocol
|
|
2
2
|
|
|
3
|
-
This document outlines the WebSocket communication protocol
|
|
3
|
+
This document outlines the WebSocket communication protocol used in Portacode. The protocol involves three main participants: client sessions, the Portacode server, and devices.
|
|
4
|
+
|
|
5
|
+
## Architecture Overview
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────┐ ┌──────────────────┐ ┌─────────────────────────┐
|
|
9
|
+
│ Client │ │ Portacode │ │ Device │
|
|
10
|
+
│ Session │◄────────►│ Server │◄────────►│ (Portacode CLI or │
|
|
11
|
+
│ │ │ │ │ Python package) │
|
|
12
|
+
└─────────────┘ └──────────────────┘ └─────────────────────────┘
|
|
13
|
+
│ │ │
|
|
14
|
+
│ │ │
|
|
15
|
+
Client-Side Acts as middleman Device-Side
|
|
16
|
+
Protocol - Routes messages Protocol
|
|
17
|
+
- Manages sessions
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The Portacode server acts as a **routing middleman** between client sessions and devices. It manages routing fields that are included in messages to specify routing destinations but are removed or transformed before reaching the final recipient:
|
|
21
|
+
|
|
22
|
+
**Routing Fields Behavior:**
|
|
23
|
+
|
|
24
|
+
- **`device_id`** (Client → Server): Client includes this to specify which device to route to. Server uses it for routing, then **removes it** before forwarding to the device (the device knows the message is for them). Server **adds it** when routing device responses back to clients (so clients know which device the message came from).
|
|
25
|
+
|
|
26
|
+
- **`client_sessions`** (Device → Server): Device includes this to specify which client session(s) to route to. Server uses it for routing, then **removes it** before forwarding to clients (clients just receive the message without seeing routing metadata).
|
|
27
|
+
|
|
28
|
+
- **`source_client_session`** (Server → Device): Server **adds this** when forwarding client commands to devices (so device knows which client sent the command and can target responses back). Clients never include this field.
|
|
29
|
+
|
|
30
|
+
This document describes the complete protocol for communicating with devices through the server, guiding app developers on how to get their client sessions to communicate with devices.
|
|
4
31
|
|
|
5
32
|
## Table of Contents
|
|
6
33
|
|
|
7
|
-
- [Raw Message Format](#raw-message-format)
|
|
34
|
+
- [Raw Message Format On Device Side](#raw-message-format-on-device-side)
|
|
35
|
+
- [Raw Message Format On Client Side](#raw-message-format-on-client-side)
|
|
8
36
|
- [Actions](#actions)
|
|
9
37
|
- [Terminal Actions](#terminal-actions)
|
|
10
38
|
- [`terminal_start`](#terminal_start)
|
|
@@ -13,12 +41,21 @@ This document outlines the WebSocket communication protocol between the Portacod
|
|
|
13
41
|
- [`terminal_list`](#terminal_list)
|
|
14
42
|
- [System Actions](#system-actions)
|
|
15
43
|
- [`system_info`](#system_info)
|
|
44
|
+
- [`update_portacode_cli`](#update_portacode_cli)
|
|
45
|
+
- [`clock_sync_request`](#clock_sync_request)
|
|
16
46
|
- [File Actions](#file-actions)
|
|
17
47
|
- [`file_read`](#file_read)
|
|
48
|
+
- [`file_search`](#file_search)
|
|
18
49
|
- [`file_write`](#file_write)
|
|
50
|
+
- [`file_apply_diff`](#file_apply_diff)
|
|
51
|
+
- [`file_preview_diff`](#file_preview_diff)
|
|
19
52
|
- [`directory_list`](#directory_list)
|
|
20
53
|
- [`file_info`](#file_info)
|
|
21
54
|
- [`file_delete`](#file_delete)
|
|
55
|
+
- [`file_create`](#file_create)
|
|
56
|
+
- [`folder_create`](#folder_create)
|
|
57
|
+
- [`file_rename`](#file_rename)
|
|
58
|
+
- [`content_request`](#content_request)
|
|
22
59
|
- [Project State Actions](#project-state-actions)
|
|
23
60
|
- [`project_state_folder_expand`](#project_state_folder_expand)
|
|
24
61
|
- [`project_state_folder_collapse`](#project_state_folder_collapse)
|
|
@@ -26,6 +63,11 @@ This document outlines the WebSocket communication protocol between the Portacod
|
|
|
26
63
|
- [`project_state_tab_close`](#project_state_tab_close)
|
|
27
64
|
- [`project_state_set_active_tab`](#project_state_set_active_tab)
|
|
28
65
|
- [`project_state_diff_open`](#project_state_diff_open)
|
|
66
|
+
- [`project_state_diff_content_request`](#project_state_diff_content_request)
|
|
67
|
+
- [`project_state_git_stage`](#project_state_git_stage)
|
|
68
|
+
- [`project_state_git_unstage`](#project_state_git_unstage)
|
|
69
|
+
- [`project_state_git_revert`](#project_state_git_revert)
|
|
70
|
+
- [`project_state_git_commit`](#project_state_git_commit)
|
|
29
71
|
- [Client Session Management](#client-session-management)
|
|
30
72
|
- [`client_sessions_update`](#client_sessions_update)
|
|
31
73
|
- [Events](#events)
|
|
@@ -41,12 +83,21 @@ This document outlines the WebSocket communication protocol between the Portacod
|
|
|
41
83
|
- [`terminal_list`](#terminal_list-event)
|
|
42
84
|
- [System Events](#system-events)
|
|
43
85
|
- [`system_info`](#system_info-event)
|
|
86
|
+
- [`update_portacode_response`](#update_portacode_response)
|
|
87
|
+
- [`clock_sync_response`](#clock_sync_response)
|
|
44
88
|
- [File Events](#file-events)
|
|
45
89
|
- [`file_read_response`](#file_read_response)
|
|
90
|
+
- [`file_search_response`](#file_search_response)
|
|
46
91
|
- [`file_write_response`](#file_write_response)
|
|
92
|
+
- [`file_apply_diff_response`](#file_apply_diff_response)
|
|
93
|
+
- [`file_preview_diff_response`](#file_preview_diff_response)
|
|
47
94
|
- [`directory_list_response`](#directory_list_response)
|
|
48
95
|
- [`file_info_response`](#file_info_response)
|
|
49
96
|
- [`file_delete_response`](#file_delete_response)
|
|
97
|
+
- [`file_create_response`](#file_create_response)
|
|
98
|
+
- [`folder_create_response`](#folder_create_response)
|
|
99
|
+
- [`file_rename_response`](#file_rename_response)
|
|
100
|
+
- [`content_response`](#content_response)
|
|
50
101
|
- [Project State Events](#project-state-events)
|
|
51
102
|
- [`project_state_initialized`](#project_state_initialized)
|
|
52
103
|
- [`project_state_update`](#project_state_update)
|
|
@@ -56,6 +107,11 @@ This document outlines the WebSocket communication protocol between the Portacod
|
|
|
56
107
|
- [`project_state_tab_close_response`](#project_state_tab_close_response)
|
|
57
108
|
- [`project_state_set_active_tab_response`](#project_state_set_active_tab_response)
|
|
58
109
|
- [`project_state_diff_open_response`](#project_state_diff_open_response)
|
|
110
|
+
- [`project_state_diff_content_response`](#project_state_diff_content_response)
|
|
111
|
+
- [`project_state_git_stage_response`](#project_state_git_stage_response)
|
|
112
|
+
- [`project_state_git_unstage_response`](#project_state_git_unstage_response)
|
|
113
|
+
- [`project_state_git_revert_response`](#project_state_git_revert_response)
|
|
114
|
+
- [`project_state_git_commit_response`](#project_state_git_commit_response)
|
|
59
115
|
- [Client Session Events](#client-session-events)
|
|
60
116
|
- [`request_client_sessions`](#request_client_sessions)
|
|
61
117
|
- [Terminal Data](#terminal-data)
|
|
@@ -64,11 +120,11 @@ This document outlines the WebSocket communication protocol between the Portacod
|
|
|
64
120
|
- [`device_status`](#device_status)
|
|
65
121
|
- [`devices`](#devices)
|
|
66
122
|
|
|
67
|
-
## Raw Message Format
|
|
123
|
+
## Raw Message Format On Device Side
|
|
68
124
|
|
|
69
|
-
|
|
125
|
+
Communication between the server and devices uses a [multiplexer](./multiplex.py) that wraps every message in a JSON object with a `channel` and a `payload`. This allows for multiple virtual communication channels over a single WebSocket connection.
|
|
70
126
|
|
|
71
|
-
**
|
|
127
|
+
**Device-Side Message Structure:**
|
|
72
128
|
|
|
73
129
|
```json
|
|
74
130
|
{
|
|
@@ -79,9 +135,99 @@ All communication over the WebSocket is managed by a [multiplexer](./multiplex.p
|
|
|
79
135
|
}
|
|
80
136
|
```
|
|
81
137
|
|
|
82
|
-
|
|
138
|
+
**Field Descriptions:**
|
|
139
|
+
|
|
140
|
+
* `channel` (string|integer, mandatory): Identifies the virtual channel the message is for. When sending control commands to the device, they should be sent to channel 0 and when the device responds to such control commands or sends system events, they will also be sent on the zero channel. When a terminal session is created in the device, it is assigned a uuid, the uuid becomes the channel for communicating to that specific terminal.
|
|
83
141
|
* `payload` (object, mandatory): The content of the message, which will be either an [Action](#actions) or an [Event](#events) object.
|
|
84
142
|
|
|
143
|
+
**Channel Types:**
|
|
144
|
+
- **Channel 0** (control channel): Used for system commands, terminal management, file operations, and project state management
|
|
145
|
+
- **Channel UUID** (terminal channel): Used for terminal I/O to a specific terminal session
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Raw Message Format On Client Side
|
|
150
|
+
|
|
151
|
+
Client sessions communicate with the server using a unified message format with the same field names as the device protocol, plus routing information.
|
|
152
|
+
|
|
153
|
+
**Client-Side Message Structure (Client → Server):**
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"device_id": <number>,
|
|
158
|
+
"channel": <number|string>,
|
|
159
|
+
"payload": {
|
|
160
|
+
"cmd": "<command_name>",
|
|
161
|
+
...command-specific fields
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Field Descriptions:**
|
|
167
|
+
|
|
168
|
+
* `device_id` (number, mandatory): Routing field - specifies which device to send the message to. The server validates that the client has access to this device before forwarding.
|
|
169
|
+
* `channel` (number|string, mandatory): Same as device protocol - the target channel (0 for control, UUID for terminal). Uses the same field name for consistency.
|
|
170
|
+
* `payload` (object, mandatory): Same as device protocol - the command payload. Uses the same field name for consistency.
|
|
171
|
+
|
|
172
|
+
**Server Transformation (Client → Device):**
|
|
173
|
+
|
|
174
|
+
When the server receives a client message, it:
|
|
175
|
+
1. Validates client has access to the specified `device_id`
|
|
176
|
+
2. **Removes** `device_id` from the message (device doesn't need to be told "this is for you")
|
|
177
|
+
3. **Adds** `source_client_session` to the payload (so device knows which client to respond to)
|
|
178
|
+
4. Forwards to device: `{channel, payload: {...payload, source_client_session}}`
|
|
179
|
+
|
|
180
|
+
**Server Transformation (Device → Client):**
|
|
181
|
+
|
|
182
|
+
When the server receives a device response, it:
|
|
183
|
+
1. **Adds** `device_id` to the message (so client knows which device it came from, based on authenticated device connection)
|
|
184
|
+
2. **Removes** `client_sessions` routing metadata (clients don't need to see routing info)
|
|
185
|
+
3. Routes to appropriate client session(s)
|
|
186
|
+
|
|
187
|
+
**Server Response Format (Server → Client):**
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"event": "<event_name>",
|
|
192
|
+
"device_id": <number>,
|
|
193
|
+
...event-specific fields
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Field Descriptions:**
|
|
198
|
+
|
|
199
|
+
* `event` (string, mandatory): The name of the event being sent.
|
|
200
|
+
* `device_id` (number, mandatory): Authenticated field - identifies which device the event came from (added by server based on authenticated device connection).
|
|
201
|
+
* Additional fields depend on the specific event type.
|
|
202
|
+
|
|
203
|
+
**Example Client Message:**
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"device_id": 42,
|
|
207
|
+
"channel": 0,
|
|
208
|
+
"payload": {
|
|
209
|
+
"cmd": "terminal_start",
|
|
210
|
+
"shell": "bash",
|
|
211
|
+
"cwd": "/home/user/project"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Example Server Response:**
|
|
217
|
+
```json
|
|
218
|
+
{
|
|
219
|
+
"event": "terminal_started",
|
|
220
|
+
"device_id": 42,
|
|
221
|
+
"terminal_id": "uuid-1234-5678",
|
|
222
|
+
"channel": "uuid-1234-5678",
|
|
223
|
+
"pid": 12345
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Note:** The server acts as a translator between the client-side and device-side protocols:
|
|
228
|
+
- When a client sends a command, the server transforms it from the client format to the device format
|
|
229
|
+
- When a device sends an event, the server adds the `device_id` and routes it to the appropriate client sessions
|
|
230
|
+
|
|
85
231
|
---
|
|
86
232
|
|
|
87
233
|
## Actions
|
|
@@ -92,18 +238,18 @@ Actions are messages sent from the server to the device, placed within the `payl
|
|
|
92
238
|
|
|
93
239
|
```json
|
|
94
240
|
{
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
|
|
98
|
-
"...": "..."
|
|
99
|
-
},
|
|
241
|
+
"cmd": "<command_name>",
|
|
242
|
+
"arg1": "value1",
|
|
243
|
+
"arg2": "value2",
|
|
100
244
|
"source_client_session": "channel.abc123"
|
|
101
245
|
}
|
|
102
246
|
```
|
|
103
247
|
|
|
104
|
-
|
|
105
|
-
|
|
248
|
+
**Field Descriptions:**
|
|
249
|
+
|
|
250
|
+
* `cmd` (string, mandatory): The name of the action to be executed (e.g., `terminal_start`, `file_read`, `system_info`).
|
|
106
251
|
* `source_client_session` (string, mandatory): The channel name of the client session that originated this command. This field is automatically added by the server and allows devices to identify which specific client sent the command.
|
|
252
|
+
* Additional fields depend on the specific command (see individual command documentation below).
|
|
107
253
|
|
|
108
254
|
**Note**: Actions do not require targeting information - responses are automatically routed using the client session management system.
|
|
109
255
|
|
|
@@ -174,6 +320,58 @@ This action does not require any payload fields.
|
|
|
174
320
|
|
|
175
321
|
* On success, the device will respond with a [`system_info`](#system_info-event) event.
|
|
176
322
|
|
|
323
|
+
### `setup_proxmox_infra`
|
|
324
|
+
|
|
325
|
+
Configures a Proxmox node for Portacode infrastructure usage (API token validation, automatic storage/template detection, bridge/NAT setup, and connectivity verification). Handled by [`ConfigureProxmoxInfraHandler`](./proxmox_infra.py).
|
|
326
|
+
|
|
327
|
+
**Payload Fields:**
|
|
328
|
+
|
|
329
|
+
* `token_identifier` (string, required): API token identifier in the form `user@realm!tokenid`.
|
|
330
|
+
* `token_value` (string, required): Secret value associated with the token.
|
|
331
|
+
* `verify_ssl` (boolean, optional): When true, the handler verifies SSL certificates; defaults to `false`.
|
|
332
|
+
|
|
333
|
+
**Responses:**
|
|
334
|
+
|
|
335
|
+
* On success, the device will emit a [`proxmox_infra_configured`](#proxmox_infra_configured-event) event with the persisted infra snapshot.
|
|
336
|
+
* On failure, the device will emit an [`error`](#error) event with details (e.g., permission issues, missing proxmoxer/dnsmasq, missing root privileges, or failed network verification).
|
|
337
|
+
|
|
338
|
+
### `revert_proxmox_infra`
|
|
339
|
+
|
|
340
|
+
Reverts the Proxmox infrastructure network changes and clears the stored API token. Handled by [`RevertProxmoxInfraHandler`](./proxmox_infra.py).
|
|
341
|
+
|
|
342
|
+
**Payload Fields:**
|
|
343
|
+
|
|
344
|
+
This action does not require any payload fields.
|
|
345
|
+
|
|
346
|
+
**Responses:**
|
|
347
|
+
|
|
348
|
+
* On success, the device will emit a [`proxmox_infra_reverted`](#proxmox_infra_reverted-event) event containing the cleared snapshot.
|
|
349
|
+
|
|
350
|
+
### `clock_sync_request`
|
|
351
|
+
|
|
352
|
+
Internal event that devices send to the gateway to request the authoritative server timestamp (used for adjusting `portacode.utils.ntp_clock`). The gateway responds immediately with [`clock_sync_response`](#clock_sync_response).
|
|
353
|
+
|
|
354
|
+
**Payload Fields:**
|
|
355
|
+
|
|
356
|
+
* `request_id` (string, optional): Correlates the response with the request.
|
|
357
|
+
|
|
358
|
+
**Responses:**
|
|
359
|
+
|
|
360
|
+
* The gateway responds with [`clock_sync_response`](#clock_sync_response) that includes the authoritative `server_time` (plus the optional `server_time_iso` mirror).
|
|
361
|
+
|
|
362
|
+
### `update_portacode_cli`
|
|
363
|
+
|
|
364
|
+
Updates the Portacode CLI package and restarts the process. Handled by [`update_portacode_cli`](./update_handler.py).
|
|
365
|
+
|
|
366
|
+
**Payload Fields:**
|
|
367
|
+
|
|
368
|
+
This action does not require any payload fields.
|
|
369
|
+
|
|
370
|
+
**Responses:**
|
|
371
|
+
|
|
372
|
+
* On success, the device will respond with an `update_portacode_response` event and then exit with code 42 to trigger restart.
|
|
373
|
+
* On error, an `update_portacode_response` event with error details is sent.
|
|
374
|
+
|
|
177
375
|
### `file_read`
|
|
178
376
|
|
|
179
377
|
Reads the content of a file. Handled by [`file_read`](./file_handlers.py).
|
|
@@ -181,12 +379,46 @@ Reads the content of a file. Handled by [`file_read`](./file_handlers.py).
|
|
|
181
379
|
**Payload Fields:**
|
|
182
380
|
|
|
183
381
|
* `path` (string, mandatory): The absolute path to the file to read.
|
|
382
|
+
* `start_line` (integer, optional): 1-based line number to start reading from. Defaults to `1`.
|
|
383
|
+
* `end_line` (integer, optional): 1-based line number to stop reading at (inclusive). When provided, limits the response to the range between `start_line` and `end_line`.
|
|
384
|
+
* `max_lines` (integer, optional): Maximum number of lines to return (capped at 2000). Useful for pagination when `end_line` is not specified.
|
|
385
|
+
* `encoding` (string, optional): Text encoding to use when reading the file. Defaults to `utf-8` with replacement for invalid bytes.
|
|
184
386
|
|
|
185
387
|
**Responses:**
|
|
186
388
|
|
|
187
389
|
* On success, the device will respond with a [`file_read_response`](#file_read_response) event.
|
|
188
390
|
* On error, a generic [`error`](#error) event is sent.
|
|
189
391
|
|
|
392
|
+
### `file_search`
|
|
393
|
+
|
|
394
|
+
Searches for text matches within files beneath a given root directory. Handled by [`file_search`](./file_handlers.py).
|
|
395
|
+
|
|
396
|
+
**Payload Fields:**
|
|
397
|
+
|
|
398
|
+
* `root_path` (string, mandatory): The absolute path that acts as the search root (typically a project folder).
|
|
399
|
+
* `query` (string, mandatory): The search query. Treated as plain text unless `regex=true`.
|
|
400
|
+
* `match_case` (boolean, optional): When `true`, performs a case-sensitive search. Defaults to `false`.
|
|
401
|
+
* `regex` (boolean, optional): When `true`, interprets `query` as a regular expression. Defaults to `false`.
|
|
402
|
+
* `whole_word` (boolean, optional): When `true`, matches only whole words. Works with both plain text and regex queries.
|
|
403
|
+
* `include_patterns` (array[string], optional): Glob patterns that files must match to be included (e.g., `["src/**/*.py"]`).
|
|
404
|
+
* `exclude_patterns` (array[string], optional): Glob patterns for files/directories to skip (e.g., `["**/tests/**"]`).
|
|
405
|
+
* `include_hidden` (boolean, optional): When `true`, includes hidden files and folders. Defaults to `false`.
|
|
406
|
+
* `max_results` (integer, optional): Maximum number of match entries to return (capped at 500). Defaults to `40`.
|
|
407
|
+
* `max_matches_per_file` (integer, optional): Maximum number of matches to return per file (capped at 50). Defaults to `5`.
|
|
408
|
+
* `max_file_size` (integer, optional): Maximum file size in bytes to scan (defaults to 1 MiB).
|
|
409
|
+
* `max_line_length` (integer, optional): Maximum number of characters to return per matching line (defaults to `200`).
|
|
410
|
+
|
|
411
|
+
**Default Behaviour:**
|
|
412
|
+
|
|
413
|
+
* Binary files and large vendor/static directories (e.g., `node_modules`, `dist`, `static`) are skipped automatically unless custom `exclude_patterns` are provided.
|
|
414
|
+
* Only common source/text extensions are scanned by default (override with `include_patterns` to widen the scope).
|
|
415
|
+
* Searches stop after 10 seconds, respecting both per-file and global match limits to avoid oversized responses.
|
|
416
|
+
|
|
417
|
+
**Responses:**
|
|
418
|
+
|
|
419
|
+
* On success, the device will respond with a [`file_search_response`](#file_search_response) event containing the matches.
|
|
420
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
421
|
+
|
|
190
422
|
### `file_write`
|
|
191
423
|
|
|
192
424
|
Writes content to a file. Handled by [`file_write`](./file_handlers.py).
|
|
@@ -199,6 +431,57 @@ Writes content to a file. Handled by [`file_write`](./file_handlers.py).
|
|
|
199
431
|
**Responses:**
|
|
200
432
|
|
|
201
433
|
* On success, the device will respond with a [`file_write_response`](#file_write_response) event.
|
|
434
|
+
|
|
435
|
+
### `file_apply_diff`
|
|
436
|
+
|
|
437
|
+
Apply one or more unified diff hunks to local files. Handled by [`file_apply_diff`](./diff_handlers.py).
|
|
438
|
+
|
|
439
|
+
**Request Payload:**
|
|
440
|
+
|
|
441
|
+
```json
|
|
442
|
+
{
|
|
443
|
+
"cmd": "file_apply_diff",
|
|
444
|
+
"diff": "<unified diff string>",
|
|
445
|
+
"base_path": "<optional base path for relative diff entries>",
|
|
446
|
+
"project_id": "<server project UUID>",
|
|
447
|
+
"source_client_session": "<originating session/channel>"
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**Behavior:**
|
|
452
|
+
|
|
453
|
+
* `diff` must be standard unified diff text (like `git diff` output). Multiple files per diff are supported.
|
|
454
|
+
* If `base_path` is omitted the handler will attempt to derive the active project root from `source_client_session`, falling back to the device working directory.
|
|
455
|
+
* Each file hunk is validated before writing; context mismatches or missing files return per-file errors without aborting the rest.
|
|
456
|
+
* `/dev/null` entries are interpreted as file creations/deletions.
|
|
457
|
+
* Inline directives are also supported on their own lines. Use `@@delete:relative/path.py@@` to delete a file directly or `@@move:old/path.py -> new/path.py@@` (alias `@@rename:...@@`) to move/rename a file without crafting a diff. Directives are evaluated before the diff hunks and must point to files inside the project base.
|
|
458
|
+
|
|
459
|
+
* On completion the device responds with [`file_apply_diff_response`](#file_apply_diff_response).
|
|
460
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
461
|
+
|
|
462
|
+
### `file_preview_diff`
|
|
463
|
+
|
|
464
|
+
Validate one or more unified diff hunks and render an HTML preview without mutating any files. Handled by [`file_preview_diff`](./diff_handlers.py).
|
|
465
|
+
|
|
466
|
+
**Request Payload:**
|
|
467
|
+
|
|
468
|
+
```json
|
|
469
|
+
{
|
|
470
|
+
"cmd": "file_preview_diff",
|
|
471
|
+
"diff": "<unified diff string>",
|
|
472
|
+
"base_path": "<optional base path for relative diff entries>",
|
|
473
|
+
"request_id": "req_123456"
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**Behavior:**
|
|
478
|
+
|
|
479
|
+
* Reuses the same parser as `file_apply_diff`, so invalid hunks surface the same errors.
|
|
480
|
+
* Produces HTML snippets per file using the device-side renderer. No files are modified.
|
|
481
|
+
* Inline directives (`@@delete:...@@`, `@@move:src -> dest@@`) use the same syntax as `file_apply_diff`. The handler validates them up front and includes them in the preview output so the user can see deletions or moves before clicking “Apply”.
|
|
482
|
+
* Returns immediately with an error payload if preview generation fails.
|
|
483
|
+
|
|
484
|
+
* On completion the device responds with [`file_preview_diff_response`](#file_preview_diff_response).
|
|
202
485
|
* On error, a generic [`error`](#error) event is sent.
|
|
203
486
|
|
|
204
487
|
### `directory_list`
|
|
@@ -209,6 +492,8 @@ Lists the contents of a directory. Handled by [`directory_list`](./file_handlers
|
|
|
209
492
|
|
|
210
493
|
* `path` (string, optional): The path to the directory to list. Defaults to the current directory.
|
|
211
494
|
* `show_hidden` (boolean, optional): Whether to include hidden files in the listing. Defaults to `false`.
|
|
495
|
+
* `limit` (integer, optional): Maximum number of entries to return (defaults to “all”). Values above 1000 are clamped to 1000.
|
|
496
|
+
* `offset` (integer, optional): Number of entries to skip before collecting results (defaults to `0`).
|
|
212
497
|
|
|
213
498
|
**Responses:**
|
|
214
499
|
|
|
@@ -241,6 +526,63 @@ Deletes a file or directory. Handled by [`file_delete`](./file_handlers.py).
|
|
|
241
526
|
* On success, the device will respond with a [`file_delete_response`](#file_delete_response) event.
|
|
242
527
|
* On error, a generic [`error`](#error) event is sent.
|
|
243
528
|
|
|
529
|
+
### `file_create`
|
|
530
|
+
|
|
531
|
+
Creates a new file. Handled by [`file_create`](./file_handlers.py).
|
|
532
|
+
|
|
533
|
+
**Payload Fields:**
|
|
534
|
+
|
|
535
|
+
* `parent_path` (string, mandatory): The absolute path to the parent directory where the file should be created.
|
|
536
|
+
* `file_name` (string, mandatory): The name of the file to create. Must not contain path separators or be special directories (`.`, `..`).
|
|
537
|
+
* `content` (string, optional): The initial content for the file. Defaults to empty string.
|
|
538
|
+
|
|
539
|
+
**Responses:**
|
|
540
|
+
|
|
541
|
+
* On success, the device will respond with a [`file_create_response`](#file_create_response) event.
|
|
542
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
543
|
+
|
|
544
|
+
### `folder_create`
|
|
545
|
+
|
|
546
|
+
Creates a new folder/directory. Handled by [`folder_create`](./file_handlers.py).
|
|
547
|
+
|
|
548
|
+
**Payload Fields:**
|
|
549
|
+
|
|
550
|
+
* `parent_path` (string, mandatory): The absolute path to the parent directory where the folder should be created.
|
|
551
|
+
* `folder_name` (string, mandatory): The name of the folder to create. Must not contain path separators or be special directories (`.`, `..`).
|
|
552
|
+
|
|
553
|
+
**Responses:**
|
|
554
|
+
|
|
555
|
+
* On success, the device will respond with a [`folder_create_response`](#folder_create_response) event.
|
|
556
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
557
|
+
|
|
558
|
+
### `file_rename`
|
|
559
|
+
|
|
560
|
+
Renames a file or folder. Handled by [`file_rename`](./file_handlers.py).
|
|
561
|
+
|
|
562
|
+
**Payload Fields:**
|
|
563
|
+
|
|
564
|
+
* `old_path` (string, mandatory): The absolute path to the file or folder to rename.
|
|
565
|
+
* `new_name` (string, mandatory): The new name (not full path) for the item. Must not contain path separators or be special directories (`.`, `..`).
|
|
566
|
+
|
|
567
|
+
**Responses:**
|
|
568
|
+
|
|
569
|
+
* On success, the device will respond with a [`file_rename_response`](#file_rename_response) event.
|
|
570
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
571
|
+
|
|
572
|
+
### `content_request`
|
|
573
|
+
|
|
574
|
+
Requests cached content by SHA-256 hash. This action is used to implement content caching for performance optimization, allowing clients to request large content (such as file content, HTML diffs, etc.) by hash instead of receiving it in every WebSocket message. For large content (>200KB), the response will be automatically chunked into multiple messages for reliable transmission. Handled by [`content_request`](./file_handlers.py).
|
|
575
|
+
|
|
576
|
+
**Payload Fields:**
|
|
577
|
+
|
|
578
|
+
* `content_hash` (string, mandatory): The SHA-256 hash of the content to retrieve (with "sha256:" prefix).
|
|
579
|
+
* `request_id` (string, mandatory): A unique identifier for this request, used to match with the response.
|
|
580
|
+
|
|
581
|
+
**Responses:**
|
|
582
|
+
|
|
583
|
+
* On success, the device will respond with one or more [`content_response`](#content_response) events containing the cached content. Large content is automatically chunked.
|
|
584
|
+
* On error (content not found), a [`content_response`](#content_response) event with `success: false` is sent.
|
|
585
|
+
|
|
244
586
|
## Project State Actions
|
|
245
587
|
|
|
246
588
|
Project state actions manage the state of project folders, including file structures, Git metadata, open files, and folder expansion states. These actions provide real-time synchronization between the client and server for project management functionality.
|
|
@@ -351,6 +693,113 @@ Opens a diff tab for comparing file versions at different points in the git time
|
|
|
351
693
|
* On success, the device will respond with a [`project_state_diff_open_response`](#project_state_diff_open_response) event, followed by a [`project_state_update`](#project_state_update) event.
|
|
352
694
|
* On error, a generic [`error`](#error) event is sent.
|
|
353
695
|
|
|
696
|
+
### `project_state_diff_content_request`
|
|
697
|
+
|
|
698
|
+
Requests the content for a specific diff tab identified by its diff parameters. This action is used to load the actual file content (original and modified) as well as HTML diff data for diff tabs after they have been created by [`project_state_diff_open`](#project_state_diff_open). For large content (>200KB), the response will be automatically chunked into multiple messages for reliable transmission.
|
|
699
|
+
|
|
700
|
+
**Content Types:** This action can request content for a diff:
|
|
701
|
+
- `original`: The original (from) content of the diff
|
|
702
|
+
- `modified`: The modified (to) content of the diff
|
|
703
|
+
- `html_diff`: The HTML diff versions for rich visual display
|
|
704
|
+
- `all`: All content types returned as a single JSON object (recommended for efficiency)
|
|
705
|
+
|
|
706
|
+
**Payload Fields:**
|
|
707
|
+
|
|
708
|
+
* `project_id` (string, mandatory): The project ID from the initialized project state.
|
|
709
|
+
* `file_path` (string, mandatory): The absolute path to the file the diff is for.
|
|
710
|
+
* `from_ref` (string, mandatory): The source reference point used in the diff. Must match the diff tab parameters.
|
|
711
|
+
* `to_ref` (string, mandatory): The target reference point used in the diff. Must match the diff tab parameters.
|
|
712
|
+
* `from_hash` (string, optional): The commit hash for `from_ref` if it was `"commit"`. Must match the diff tab parameters.
|
|
713
|
+
* `to_hash` (string, optional): The commit hash for `to_ref` if it was `"commit"`. Must match the diff tab parameters.
|
|
714
|
+
* `content_type` (string, mandatory): The type of content to request. Must be one of:
|
|
715
|
+
- `"original"`: Request the original (from) content
|
|
716
|
+
- `"modified"`: Request the modified (to) content
|
|
717
|
+
- `"html_diff"`: Request the HTML diff versions for visual display
|
|
718
|
+
- `"all"`: Request all content types as a single JSON object
|
|
719
|
+
* `request_id` (string, mandatory): Unique identifier for this request to match with the response.
|
|
720
|
+
|
|
721
|
+
**Responses:**
|
|
722
|
+
|
|
723
|
+
* On success, the device will respond with one or more [`project_state_diff_content_response`](#project_state_diff_content_response) events. Large content is automatically chunked.
|
|
724
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
725
|
+
|
|
726
|
+
### `project_state_git_stage`
|
|
727
|
+
|
|
728
|
+
Stages file(s) for commit in the project's git repository. Supports both single file and bulk operations. Handled by [`project_state_git_stage`](./project_state_handlers.py).
|
|
729
|
+
|
|
730
|
+
**Payload Fields:**
|
|
731
|
+
|
|
732
|
+
* `project_id` (string, mandatory): The project ID from the initialized project state.
|
|
733
|
+
* `file_path` (string, optional): The absolute path to a single file to stage. Used for backward compatibility.
|
|
734
|
+
* `file_paths` (array of strings, optional): Array of absolute paths to files to stage. Used for bulk operations.
|
|
735
|
+
* `stage_all` (boolean, optional): If true, stages all unstaged changes in the repository. Takes precedence over file_path/file_paths.
|
|
736
|
+
|
|
737
|
+
**Operation Modes:**
|
|
738
|
+
- Single file: Provide `file_path`
|
|
739
|
+
- Bulk operation: Provide `file_paths` array
|
|
740
|
+
- Stage all: Set `stage_all` to true
|
|
741
|
+
|
|
742
|
+
**Responses:**
|
|
743
|
+
|
|
744
|
+
* On success, the device will respond with a [`project_state_git_stage_response`](#project_state_git_stage_response) event, followed by a [`project_state_update`](#project_state_update) event with updated git status.
|
|
745
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
746
|
+
|
|
747
|
+
### `project_state_git_unstage`
|
|
748
|
+
|
|
749
|
+
Unstages file(s) (removes from staging area) in the project's git repository. Supports both single file and bulk operations. Handled by [`project_state_git_unstage`](./project_state_handlers.py).
|
|
750
|
+
|
|
751
|
+
**Payload Fields:**
|
|
752
|
+
|
|
753
|
+
* `project_id` (string, mandatory): The project ID from the initialized project state.
|
|
754
|
+
* `file_path` (string, optional): The absolute path to a single file to unstage. Used for backward compatibility.
|
|
755
|
+
* `file_paths` (array of strings, optional): Array of absolute paths to files to unstage. Used for bulk operations.
|
|
756
|
+
* `unstage_all` (boolean, optional): If true, unstages all staged changes in the repository. Takes precedence over file_path/file_paths.
|
|
757
|
+
|
|
758
|
+
**Operation Modes:**
|
|
759
|
+
- Single file: Provide `file_path`
|
|
760
|
+
- Bulk operation: Provide `file_paths` array
|
|
761
|
+
- Unstage all: Set `unstage_all` to true
|
|
762
|
+
|
|
763
|
+
**Responses:**
|
|
764
|
+
|
|
765
|
+
* On success, the device will respond with a [`project_state_git_unstage_response`](#project_state_git_unstage_response) event, followed by a [`project_state_update`](#project_state_update) event with updated git status.
|
|
766
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
767
|
+
|
|
768
|
+
### `project_state_git_revert`
|
|
769
|
+
|
|
770
|
+
Reverts file(s) to their HEAD version, discarding local changes in the project's git repository. Supports both single file and bulk operations. Handled by [`project_state_git_revert`](./project_state_handlers.py).
|
|
771
|
+
|
|
772
|
+
**Payload Fields:**
|
|
773
|
+
|
|
774
|
+
* `project_id` (string, mandatory): The project ID from the initialized project state.
|
|
775
|
+
* `file_path` (string, optional): The absolute path to a single file to revert. Used for backward compatibility.
|
|
776
|
+
* `file_paths` (array of strings, optional): Array of absolute paths to files to revert. Used for bulk operations.
|
|
777
|
+
* `revert_all` (boolean, optional): If true, reverts all unstaged changes in the repository. Takes precedence over file_path/file_paths.
|
|
778
|
+
|
|
779
|
+
**Operation Modes:**
|
|
780
|
+
- Single file: Provide `file_path`
|
|
781
|
+
- Bulk operation: Provide `file_paths` array
|
|
782
|
+
- Revert all: Set `revert_all` to true
|
|
783
|
+
|
|
784
|
+
**Responses:**
|
|
785
|
+
|
|
786
|
+
* On success, the device will respond with a [`project_state_git_revert_response`](#project_state_git_revert_response) event, followed by a [`project_state_update`](#project_state_update) event with updated git status.
|
|
787
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
788
|
+
|
|
789
|
+
### `project_state_git_commit`
|
|
790
|
+
|
|
791
|
+
Commits staged changes with a commit message in the project's git repository. Handled by [`project_state_git_commit`](./project_state_handlers.py).
|
|
792
|
+
|
|
793
|
+
**Payload Fields:**
|
|
794
|
+
|
|
795
|
+
* `project_id` (string, mandatory): The project ID from the initialized project state.
|
|
796
|
+
* `commit_message` (string, mandatory): The commit message for the changes being committed.
|
|
797
|
+
|
|
798
|
+
**Responses:**
|
|
799
|
+
|
|
800
|
+
* On success, the device will respond with a [`project_state_git_commit_response`](#project_state_git_commit_response) event, followed by a [`project_state_update`](#project_state_update) event with updated git status.
|
|
801
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
802
|
+
|
|
354
803
|
### Client Session Management
|
|
355
804
|
|
|
356
805
|
### `client_sessions_update`
|
|
@@ -450,6 +899,22 @@ The `data` field contains the exact bytes output by the terminal process, decode
|
|
|
450
899
|
|
|
451
900
|
**Security Note**: The `device_id` field is automatically injected by the server based on the authenticated connection - the device cannot and should not specify its own ID. The `project_id` and `client_sessions` fields are added by the device's terminal manager for proper routing and filtering.
|
|
452
901
|
|
|
902
|
+
### <a name="terminal_link_request"></a>`terminal_link_request`
|
|
903
|
+
|
|
904
|
+
Signals that the active terminal session attempted to open an external URL (e.g., via `xdg-open`). The terminal environment is instrumented with the `portacode/link_capture` helper, so CLI programs that try to open a browser are captured and forwarded to connected clients for confirmation.
|
|
905
|
+
|
|
906
|
+
**Event Fields:**
|
|
907
|
+
|
|
908
|
+
* `terminal_id` (string, mandatory): The UUID of the terminal session that triggered the request.
|
|
909
|
+
* `channel` (string, mandatory): Same as `terminal_id` (included for backward compatibility with raw channel routing).
|
|
910
|
+
* `url` (string, mandatory): The full URL the terminal tried to open. Clients must surface this text directly so users can verify it.
|
|
911
|
+
* `command` (string, optional): The command that attempted the navigation (e.g., `xdg-open`).
|
|
912
|
+
* `args` (array[string], optional): Arguments passed to the command, which may include safely-encoded paths or flags.
|
|
913
|
+
* `timestamp` (number, optional): UNIX epoch seconds when the capture occurred.
|
|
914
|
+
* `project_id` (string, optional): The project UUID in whose context the attempt was made.
|
|
915
|
+
|
|
916
|
+
Clients receiving this event should pause and ask the user for confirmation before opening the URL, and may throttle or suppress repeated events to prevent modal storms if a CLI tool loops on the same link.
|
|
917
|
+
|
|
453
918
|
### <a name="terminal_exit"></a>`terminal_exit`
|
|
454
919
|
|
|
455
920
|
Notifies the server that a terminal session has terminated. This can be due to the process ending or the session being stopped. Handled by [`terminal_start`](./terminal_handlers.py).
|
|
@@ -506,6 +971,87 @@ Provides system information in response to a `system_info` action. Handled by [`
|
|
|
506
971
|
* `memory` (object): Memory usage statistics.
|
|
507
972
|
* `disk` (object): Disk usage statistics.
|
|
508
973
|
* `os_info` (object): Operating system details, including `os_type`, `os_version`, `architecture`, `default_shell`, and `default_cwd`.
|
|
974
|
+
* `user_context` (object): Information about the user running the CLI, including:
|
|
975
|
+
* `username` (string): Resolved username (via `os.getlogin` or fallback).
|
|
976
|
+
* `username_source` (string): Which API resolved the username.
|
|
977
|
+
* `home` (string): Home directory detected for the CLI user.
|
|
978
|
+
* `uid` (integer|null): POSIX UID when available.
|
|
979
|
+
* `euid` (integer|null): Effective UID when available.
|
|
980
|
+
* `is_root` (boolean|null): True when running as root/administrator.
|
|
981
|
+
* `has_sudo` (boolean): Whether a `sudo` binary exists on the host.
|
|
982
|
+
* `sudo_user` (string|null): Value of `SUDO_USER` when set.
|
|
983
|
+
* `is_sudo_session` (boolean): True when the CLI was started via `sudo`.
|
|
984
|
+
* `playwright` (object): Optional Playwright runtime metadata when Playwright is installed:
|
|
985
|
+
* `installed` (boolean): True if Playwright is importable on the device.
|
|
986
|
+
* `version` (string|null): Exact package version when available.
|
|
987
|
+
* `browsers` (object): Browser-specific data keyed by Playwright browser names:
|
|
988
|
+
* `<browser>` (object): Per-browser info (variants: `chromium`, `firefox`, `webkit`).
|
|
989
|
+
* `available` (boolean): True when Playwright knows an executable path.
|
|
990
|
+
* `executable_path` (string|null): Absolute path to the browser binary when known.
|
|
991
|
+
* `error` (string|null): Any warning message captured while probing Playwright.
|
|
992
|
+
* `proxmox` (object): Detection hints for Proxmox VE nodes:
|
|
993
|
+
* `is_proxmox_node` (boolean): True when Proxmox artifacts (e.g., `/etc/proxmox-release`) exist.
|
|
994
|
+
* `version` (string|null): Raw contents of `/etc/proxmox-release` when readable.
|
|
995
|
+
* `infra` (object): Portacode infrastructure configuration snapshot:
|
|
996
|
+
* `configured` (boolean): True when `setup_proxmox_infra` stored an API token.
|
|
997
|
+
* `host` (string|null): Hostname used for the API client (usually `localhost`).
|
|
998
|
+
* `node` (string|null): Proxmox node name that was targeted.
|
|
999
|
+
* `user` (string|null): API token owner (e.g., `root@pam`).
|
|
1000
|
+
* `token_name` (string|null): API token identifier.
|
|
1001
|
+
* `default_storage` (string|null): Storage pool chosen for future containers.
|
|
1002
|
+
* `templates` (array[string]): Cached list of available LXC templates.
|
|
1003
|
+
* `last_verified` (string|null): ISO timestamp when the token was last validated.
|
|
1004
|
+
* `network` (object):
|
|
1005
|
+
* `applied` (boolean): True when the bridge/NAT services were successfully configured.
|
|
1006
|
+
* `message` (string|null): Informational text about the network setup attempt.
|
|
1007
|
+
* `bridge` (string): The bridge interface configured (typically `vmbr1`).
|
|
1008
|
+
* `health` (string|null): `"healthy"` when the connectivity verification succeeded.
|
|
1009
|
+
* `node_status` (object|null): Status response returned by the Proxmox API when validating the token.
|
|
1010
|
+
* `portacode_version` (string): Installed CLI version returned by `portacode.__version__`.
|
|
1011
|
+
|
|
1012
|
+
### `proxmox_infra_configured`
|
|
1013
|
+
|
|
1014
|
+
Emitted after a successful `setup_proxmox_infra` action. The event reports the stored API token metadata, template list, and network setup status.
|
|
1015
|
+
|
|
1016
|
+
**Event Fields:**
|
|
1017
|
+
|
|
1018
|
+
* `success` (boolean): True when the configuration completed.
|
|
1019
|
+
* `message` (string): User-facing summary (e.g., "Proxmox infrastructure configured").
|
|
1020
|
+
* `infra` (object): Same snapshot described under [`system_info`](#system_info-event) `proxmox.infra`.
|
|
1021
|
+
|
|
1022
|
+
### `proxmox_infra_reverted`
|
|
1023
|
+
|
|
1024
|
+
Emitted after a successful `revert_proxmox_infra` action. Indicates the infra config is no longer present and the network was restored.
|
|
1025
|
+
|
|
1026
|
+
**Event Fields:**
|
|
1027
|
+
|
|
1028
|
+
* `success` (boolean): True when the revert completed.
|
|
1029
|
+
* `message` (string): Summary (e.g., "Proxmox infrastructure configuration reverted").
|
|
1030
|
+
* `infra` (object): Snapshot with `configured=false` (matching [`system_info`](#system_info-event) `proxmox.infra`).
|
|
1031
|
+
|
|
1032
|
+
### <a name="clock_sync_response"></a>`clock_sync_response`
|
|
1033
|
+
|
|
1034
|
+
Reply sent by the gateway immediately after receiving a `clock_sync_request`. Devices use this event plus the measured round-trip time to keep their local `ntp_clock` offset accurate.
|
|
1035
|
+
|
|
1036
|
+
**Event Fields:**
|
|
1037
|
+
|
|
1038
|
+
* `event` (string): Always `clock_sync_response`.
|
|
1039
|
+
* `server_time` (integer): Server time in milliseconds.
|
|
1040
|
+
* `server_time_iso` (string, optional): ISO 8601 representation of `server_time`, useful for UI dashboards.
|
|
1041
|
+
* `server_receive_time` (integer, optional): Timestamp when the gateway received the sync request.
|
|
1042
|
+
* `server_send_time` (integer, optional): Timestamp when the gateway replied; used to compute a midpoint for latency compensation.
|
|
1043
|
+
* `request_id` (string, optional): Mirrors the request's `request_id`.
|
|
1044
|
+
|
|
1045
|
+
### `update_portacode_response`
|
|
1046
|
+
|
|
1047
|
+
Reports the result of an `update_portacode_cli` action. Handled by [`update_portacode_cli`](./update_handler.py).
|
|
1048
|
+
|
|
1049
|
+
**Event Fields:**
|
|
1050
|
+
|
|
1051
|
+
* `success` (boolean, mandatory): Whether the update operation was successful.
|
|
1052
|
+
* `message` (string, optional): Success message when update completes.
|
|
1053
|
+
* `error` (string, optional): Error message when update fails.
|
|
1054
|
+
* `restart_required` (boolean, optional): Indicates if process restart is required (always true for successful updates).
|
|
509
1055
|
|
|
510
1056
|
### <a name="file_read_response"></a>`file_read_response`
|
|
511
1057
|
|
|
@@ -514,8 +1060,39 @@ Returns the content of a file in response to a `file_read` action. Handled by [`
|
|
|
514
1060
|
**Event Fields:**
|
|
515
1061
|
|
|
516
1062
|
* `path` (string, mandatory): The path of the file that was read.
|
|
517
|
-
* `content` (string, mandatory): The content
|
|
518
|
-
* `size` (integer, mandatory): The size of the file in bytes.
|
|
1063
|
+
* `content` (string, mandatory): The file content returned (may be a slice when pagination parameters are used).
|
|
1064
|
+
* `size` (integer, mandatory): The total size of the file in bytes.
|
|
1065
|
+
* `total_lines` (integer, optional): Total number of lines detected in the file.
|
|
1066
|
+
* `returned_lines` (integer, optional): Number of lines included in `content`.
|
|
1067
|
+
* `start_line` (integer, optional): The first line number included in the response (if any lines were returned).
|
|
1068
|
+
* `requested_start_line` (integer, optional): The requested starting line supplied in the command.
|
|
1069
|
+
* `end_line` (integer, optional): The last line number included in the response.
|
|
1070
|
+
* `has_more_before` (boolean, optional): Whether there is additional content before the returned range.
|
|
1071
|
+
* `has_more_after` (boolean, optional): Whether there is additional content after the returned range.
|
|
1072
|
+
* `encoding` (string, optional): Encoding that was used while reading the file.
|
|
1073
|
+
|
|
1074
|
+
### <a name="file_search_response"></a>`file_search_response`
|
|
1075
|
+
|
|
1076
|
+
Returns aggregated search results in response to a `file_search` action. Handled by [`file_search`](./file_handlers.py).
|
|
1077
|
+
|
|
1078
|
+
**Event Fields:**
|
|
1079
|
+
|
|
1080
|
+
* `root_path` (string, mandatory): The root directory that was searched.
|
|
1081
|
+
* `query` (string, mandatory): The query string that was used.
|
|
1082
|
+
* `match_case` (boolean, mandatory): Indicates if the search was case sensitive.
|
|
1083
|
+
* `regex` (boolean, mandatory): Indicates if the query was interpreted as a regular expression.
|
|
1084
|
+
* `whole_word` (boolean, mandatory): Indicates if the search matched whole words only.
|
|
1085
|
+
* `include_patterns` (array[string], mandatory): Effective include glob patterns.
|
|
1086
|
+
* `exclude_patterns` (array[string], mandatory): Effective exclude glob patterns.
|
|
1087
|
+
* `matches` (array, mandatory): List of match objects containing `relative_path`, `path`, `line_number`, `line`, `match_spans` `[start, end]`, `match_count`, and `line_truncated` (boolean).
|
|
1088
|
+
* `matches_returned` (integer, mandatory): Number of match entries returned (length of `matches`).
|
|
1089
|
+
* `total_matches` (integer, mandatory): Total number of matches found while scanning.
|
|
1090
|
+
* `files_scanned` (integer, mandatory): Count of files inspected.
|
|
1091
|
+
* `truncated` (boolean, mandatory): Indicates if additional matches exist beyond those returned.
|
|
1092
|
+
* `truncated_count` (integer, optional): Number of matches that were omitted due to truncation limits.
|
|
1093
|
+
* `max_results` (integer, mandatory): Maximum number of matches requested.
|
|
1094
|
+
* `max_matches_per_file` (integer, mandatory): Maximum matches requested per file.
|
|
1095
|
+
* `errors` (array[string], optional): Non-fatal errors encountered during scanning (e.g., unreadable files).
|
|
519
1096
|
|
|
520
1097
|
### <a name="file_write_response"></a>`file_write_response`
|
|
521
1098
|
|
|
@@ -527,6 +1104,45 @@ Confirms that a file has been written successfully in response to a `file_write`
|
|
|
527
1104
|
* `bytes_written` (integer, mandatory): The number of bytes written to the file.
|
|
528
1105
|
* `success` (boolean, mandatory): Indicates whether the write operation was successful.
|
|
529
1106
|
|
|
1107
|
+
### <a name="file_apply_diff_response"></a>`file_apply_diff_response`
|
|
1108
|
+
|
|
1109
|
+
Reports the outcome of a [`file_apply_diff`](#file_apply_diff) action.
|
|
1110
|
+
|
|
1111
|
+
**Event Fields:**
|
|
1112
|
+
|
|
1113
|
+
* `event`: Always `"file_apply_diff_response"`.
|
|
1114
|
+
* `success`: Boolean indicating whether all hunks succeeded.
|
|
1115
|
+
* `status`: `"success"`, `"partial_failure"`, or `"failed"`.
|
|
1116
|
+
* `base_path`: Absolute base path used for relative diff entries.
|
|
1117
|
+
* `files_changed`: Number of files successfully updated.
|
|
1118
|
+
* `results`: Array containing one object per file with:
|
|
1119
|
+
* `path`: Absolute path on the device.
|
|
1120
|
+
* `status`: `"applied"` or `"error"`.
|
|
1121
|
+
* `action`: `"created"`, `"modified"`, or `"deleted"` (present for successes).
|
|
1122
|
+
* `bytes_written`: Bytes written for the file (0 for deletes).
|
|
1123
|
+
* `error`: Error text when the patch failed for that file.
|
|
1124
|
+
* `line`: Optional line number hint for mismatches.
|
|
1125
|
+
|
|
1126
|
+
The response is emitted even if some files fail so the caller can retry with corrected diffs.
|
|
1127
|
+
|
|
1128
|
+
### <a name="file_preview_diff_response"></a>`file_preview_diff_response`
|
|
1129
|
+
|
|
1130
|
+
Reports the outcome of a [`file_preview_diff`](#file_preview_diff) action.
|
|
1131
|
+
|
|
1132
|
+
**Event Fields:**
|
|
1133
|
+
|
|
1134
|
+
* `event`: Always `"file_preview_diff_response"`.
|
|
1135
|
+
* `success`: Boolean indicating whether all previews rendered successfully.
|
|
1136
|
+
* `status`: `"success"`, `"partial_failure"`, or `"failed"`.
|
|
1137
|
+
* `base_path`: Absolute base path used for relative paths.
|
|
1138
|
+
* `previews`: Array containing one entry per file with:
|
|
1139
|
+
* `path`: Absolute path hint (used for syntax highlighting).
|
|
1140
|
+
* `relative_path`: Relative project path if known.
|
|
1141
|
+
* `status`: `"ready"` or `"error"`.
|
|
1142
|
+
* `html`: Rendered diff snippet (when status is `"ready"`).
|
|
1143
|
+
* `error`: Error text (when status is `"error"`).
|
|
1144
|
+
* `error`: Optional top-level error string when the entire preview failed (e.g., diff parse error).
|
|
1145
|
+
|
|
530
1146
|
### <a name="directory_list_response"></a>`directory_list_response`
|
|
531
1147
|
|
|
532
1148
|
Returns the contents of a directory in response to a `directory_list` action. Handled by [`directory_list`](./file_handlers.py).
|
|
@@ -535,7 +1151,11 @@ Returns the contents of a directory in response to a `directory_list` action. Ha
|
|
|
535
1151
|
|
|
536
1152
|
* `path` (string, mandatory): The path of the directory that was listed.
|
|
537
1153
|
* `items` (array, mandatory): A list of objects, each representing a file or directory in the listed directory.
|
|
538
|
-
* `count` (integer, mandatory): The number of items in
|
|
1154
|
+
* `count` (integer, mandatory): The number of items returned in this response (honours `limit`/`offset`).
|
|
1155
|
+
* `total_count` (integer, mandatory): Total number of entries in the directory before pagination.
|
|
1156
|
+
* `offset` (integer, optional): Offset that was applied.
|
|
1157
|
+
* `limit` (integer, optional): Limit that was applied (or `null` if none).
|
|
1158
|
+
* `has_more` (boolean, optional): Indicates whether additional items remain beyond the returned slice.
|
|
539
1159
|
|
|
540
1160
|
### <a name="file_info_response"></a>`file_info_response`
|
|
541
1161
|
|
|
@@ -566,6 +1186,102 @@ Confirms that a file or directory has been deleted in response to a `file_delete
|
|
|
566
1186
|
* `deleted_type` (string, mandatory): The type of the deleted item ("file" or "directory").
|
|
567
1187
|
* `success` (boolean, mandatory): Indicates whether the deletion was successful.
|
|
568
1188
|
|
|
1189
|
+
### <a name="file_create_response"></a>`file_create_response`
|
|
1190
|
+
|
|
1191
|
+
Confirms that a file has been created successfully in response to a `file_create` action. Handled by [`file_create`](./file_handlers.py).
|
|
1192
|
+
|
|
1193
|
+
**Event Fields:**
|
|
1194
|
+
|
|
1195
|
+
* `parent_path` (string, mandatory): The path of the parent directory where the file was created.
|
|
1196
|
+
* `file_name` (string, mandatory): The name of the created file.
|
|
1197
|
+
* `file_path` (string, mandatory): The full absolute path to the created file.
|
|
1198
|
+
* `success` (boolean, mandatory): Indicates whether the creation was successful.
|
|
1199
|
+
|
|
1200
|
+
### <a name="folder_create_response"></a>`folder_create_response`
|
|
1201
|
+
|
|
1202
|
+
Confirms that a folder has been created successfully in response to a `folder_create` action. Handled by [`folder_create`](./file_handlers.py).
|
|
1203
|
+
|
|
1204
|
+
**Event Fields:**
|
|
1205
|
+
|
|
1206
|
+
* `parent_path` (string, mandatory): The path of the parent directory where the folder was created.
|
|
1207
|
+
* `folder_name` (string, mandatory): The name of the created folder.
|
|
1208
|
+
* `folder_path` (string, mandatory): The full absolute path to the created folder.
|
|
1209
|
+
* `success` (boolean, mandatory): Indicates whether the creation was successful.
|
|
1210
|
+
|
|
1211
|
+
### <a name="file_rename_response"></a>`file_rename_response`
|
|
1212
|
+
|
|
1213
|
+
Confirms that a file or folder has been renamed successfully in response to a `file_rename` action. Handled by [`file_rename`](./file_handlers.py).
|
|
1214
|
+
|
|
1215
|
+
**Event Fields:**
|
|
1216
|
+
|
|
1217
|
+
* `old_path` (string, mandatory): The original path of the renamed item.
|
|
1218
|
+
* `new_path` (string, mandatory): The new path of the renamed item.
|
|
1219
|
+
* `new_name` (string, mandatory): The new name of the item.
|
|
1220
|
+
* `is_directory` (boolean, mandatory): Indicates whether the renamed item is a directory.
|
|
1221
|
+
* `success` (boolean, mandatory): Indicates whether the rename was successful.
|
|
1222
|
+
|
|
1223
|
+
### <a name="content_response"></a>`content_response`
|
|
1224
|
+
|
|
1225
|
+
Returns cached content in response to a `content_request` action. This is part of the content caching system used for performance optimization. For large content (>200KB), the response is automatically chunked into multiple messages to ensure reliable transmission over WebSocket connections. Handled by [`content_request`](./file_handlers.py).
|
|
1226
|
+
|
|
1227
|
+
**Event Fields:**
|
|
1228
|
+
|
|
1229
|
+
* `request_id` (string, mandatory): The unique identifier from the corresponding request, used to match request and response.
|
|
1230
|
+
* `content_hash` (string, mandatory): The SHA-256 hash that was requested.
|
|
1231
|
+
* `content` (string, optional): The cached content or chunk content if found and `success` is true. Null if content was not found.
|
|
1232
|
+
* `success` (boolean, mandatory): Indicates whether the content was found and returned successfully.
|
|
1233
|
+
* `error` (string, optional): Error message if `success` is false (e.g., "Content not found in cache").
|
|
1234
|
+
* `chunked` (boolean, mandatory): Indicates whether this response is part of a chunked transfer. False for single responses, true for chunked responses.
|
|
1235
|
+
|
|
1236
|
+
**Chunked Transfer Fields (when `chunked` is true):**
|
|
1237
|
+
|
|
1238
|
+
* `transfer_id` (string, mandatory): Unique identifier for the chunked transfer session.
|
|
1239
|
+
* `chunk_index` (integer, mandatory): Zero-based index of this chunk in the sequence.
|
|
1240
|
+
* `chunk_count` (integer, mandatory): Total number of chunks in the transfer.
|
|
1241
|
+
* `chunk_size` (integer, mandatory): Size of this chunk in bytes.
|
|
1242
|
+
* `total_size` (integer, mandatory): Total size of the complete content in bytes.
|
|
1243
|
+
* `chunk_hash` (string, mandatory): SHA-256 hash of this chunk for verification.
|
|
1244
|
+
* `is_final_chunk` (boolean, mandatory): Indicates if this is the last chunk in the sequence.
|
|
1245
|
+
|
|
1246
|
+
**Chunked Transfer Process:**
|
|
1247
|
+
|
|
1248
|
+
1. **Size Check**: Content >200KB is automatically chunked into 64KB chunks
|
|
1249
|
+
2. **Sequential Delivery**: Chunks are sent in order with increasing `chunk_index`
|
|
1250
|
+
3. **Client Assembly**: Client collects all chunks and verifies integrity using hashes
|
|
1251
|
+
4. **Hash Verification**: Both individual chunk hashes and final content hash are verified
|
|
1252
|
+
5. **Error Handling**: Missing chunks or hash mismatches trigger request failure
|
|
1253
|
+
|
|
1254
|
+
**Example Non-Chunked Response:**
|
|
1255
|
+
```json
|
|
1256
|
+
{
|
|
1257
|
+
"event": "content_response",
|
|
1258
|
+
"request_id": "req_abc123",
|
|
1259
|
+
"content_hash": "sha256:...",
|
|
1260
|
+
"content": "Small content here",
|
|
1261
|
+
"success": true,
|
|
1262
|
+
"chunked": false
|
|
1263
|
+
}
|
|
1264
|
+
```
|
|
1265
|
+
|
|
1266
|
+
**Example Chunked Response (first chunk):**
|
|
1267
|
+
```json
|
|
1268
|
+
{
|
|
1269
|
+
"event": "content_response",
|
|
1270
|
+
"request_id": "req_abc123",
|
|
1271
|
+
"content_hash": "sha256:...",
|
|
1272
|
+
"content": "First chunk content...",
|
|
1273
|
+
"success": true,
|
|
1274
|
+
"chunked": true,
|
|
1275
|
+
"transfer_id": "transfer_xyz789",
|
|
1276
|
+
"chunk_index": 0,
|
|
1277
|
+
"chunk_count": 5,
|
|
1278
|
+
"chunk_size": 65536,
|
|
1279
|
+
"total_size": 300000,
|
|
1280
|
+
"chunk_hash": "chunk_sha256:...",
|
|
1281
|
+
"is_final_chunk": false
|
|
1282
|
+
}
|
|
1283
|
+
```
|
|
1284
|
+
|
|
569
1285
|
### Project State Events
|
|
570
1286
|
|
|
571
1287
|
### <a name="project_state_initialized"></a>`project_state_initialized`
|
|
@@ -574,6 +1290,7 @@ Confirms that project state has been successfully initialized for a client sessi
|
|
|
574
1290
|
|
|
575
1291
|
**Event Fields:**
|
|
576
1292
|
|
|
1293
|
+
* `project_id` (string, mandatory): The project ID for the initialized project state.
|
|
577
1294
|
* `project_folder_path` (string, mandatory): The absolute path to the project folder.
|
|
578
1295
|
* `is_git_repo` (boolean, mandatory): Whether the project folder is a Git repository.
|
|
579
1296
|
* `git_branch` (string, optional): The current Git branch name if available.
|
|
@@ -604,13 +1321,17 @@ Confirms that project state has been successfully initialized for a client sessi
|
|
|
604
1321
|
* `tab_type` (string, mandatory): Type of tab ("file", "diff", "untitled", "image", "audio", "video").
|
|
605
1322
|
* `title` (string, mandatory): Display title for the tab.
|
|
606
1323
|
* `file_path` (string, optional): Path for file-based tabs.
|
|
607
|
-
* `content` (string, optional): Text content or base64 for media.
|
|
608
|
-
* `original_content` (string, optional): For diff tabs - original content.
|
|
609
|
-
* `modified_content` (string, optional): For diff tabs - modified content.
|
|
1324
|
+
* `content` (string, optional): Text content or base64 for media. When content caching is enabled, this field may be excluded from project state events if the content is available via `content_hash`.
|
|
1325
|
+
* `original_content` (string, optional): For diff tabs - original content. When content caching is enabled, this field may be excluded from project state events if the content is available via `original_content_hash`.
|
|
1326
|
+
* `modified_content` (string, optional): For diff tabs - modified content. When content caching is enabled, this field may be excluded from project state events if the content is available via `modified_content_hash`.
|
|
610
1327
|
* `is_dirty` (boolean, mandatory): Whether the tab has unsaved changes.
|
|
611
1328
|
* `mime_type` (string, optional): MIME type for media files.
|
|
612
1329
|
* `encoding` (string, optional): Content encoding (base64, utf-8, etc.).
|
|
613
|
-
* `metadata` (object, optional): Additional metadata.
|
|
1330
|
+
* `metadata` (object, optional): Additional metadata. When content caching is enabled, large metadata such as `html_diff_versions` may be excluded from project state events if available via `html_diff_hash`.
|
|
1331
|
+
* `content_hash` (string, optional): SHA-256 hash of the tab content for content caching optimization. When present, the content can be retrieved via [`content_request`](#content_request) action.
|
|
1332
|
+
* `original_content_hash` (string, optional): SHA-256 hash of the original content for diff tabs. When present, the original content can be retrieved via [`content_request`](#content_request) action.
|
|
1333
|
+
* `modified_content_hash` (string, optional): SHA-256 hash of the modified content for diff tabs. When present, the modified content can be retrieved via [`content_request`](#content_request) action.
|
|
1334
|
+
* `html_diff_hash` (string, optional): SHA-256 hash of the HTML diff versions JSON for diff tabs. When present, the HTML diff data can be retrieved via [`content_request`](#content_request) action as a JSON string.
|
|
614
1335
|
* `active_tab` (object, optional): The currently active tab object, or null if no tab is active.
|
|
615
1336
|
* `items` (array, mandatory): Flattened array of all visible file/folder items. Always includes root level items and one level down from the project root (since the project root is treated as expanded by default). Also includes items within explicitly expanded folders and one level down from each expanded folder. Each item object contains the following fields:
|
|
616
1337
|
* `name` (string, mandatory): The file or directory name.
|
|
@@ -724,6 +1445,88 @@ Confirms the result of opening a diff tab with git timeline references.
|
|
|
724
1445
|
* `success` (boolean, mandatory): Whether the diff tab creation was successful.
|
|
725
1446
|
* `error` (string, optional): Error message if the operation failed.
|
|
726
1447
|
|
|
1448
|
+
### <a name="project_state_diff_content_response"></a>`project_state_diff_content_response`
|
|
1449
|
+
|
|
1450
|
+
Returns the requested content for a specific diff tab, sent in response to a [`project_state_diff_content_request`](#project_state_diff_content_request) action. For large content (>200KB), the response is automatically chunked into multiple messages to ensure reliable transmission over WebSocket connections.
|
|
1451
|
+
|
|
1452
|
+
**Event Fields:**
|
|
1453
|
+
|
|
1454
|
+
* `project_id` (string, mandatory): The project ID the operation was performed on.
|
|
1455
|
+
* `file_path` (string, mandatory): The path to the file the diff content is for.
|
|
1456
|
+
* `from_ref` (string, mandatory): The source reference point used in the diff.
|
|
1457
|
+
* `to_ref` (string, mandatory): The target reference point used in the diff.
|
|
1458
|
+
* `from_hash` (string, optional): The commit hash used for `from_ref` if it was `"commit"`.
|
|
1459
|
+
* `to_hash` (string, optional): The commit hash used for `to_ref` if it was `"commit"`.
|
|
1460
|
+
* `content_type` (string, mandatory): The type of content being returned (`"original"`, `"modified"`, `"html_diff"`, or `"all"`).
|
|
1461
|
+
* `request_id` (string, mandatory): The unique identifier from the request to match response with request.
|
|
1462
|
+
* `success` (boolean, mandatory): Whether the content retrieval was successful.
|
|
1463
|
+
* `content` (string, optional): The requested content or chunk content. For `html_diff` type, this is a JSON string containing the HTML diff versions object. For `all` type, this is a JSON string containing an object with `original_content`, `modified_content`, and `html_diff_versions` fields.
|
|
1464
|
+
* `error` (string, optional): Error message if the operation failed.
|
|
1465
|
+
* `chunked` (boolean, mandatory): Indicates whether this response is part of a chunked transfer. False for single responses, true for chunked responses.
|
|
1466
|
+
|
|
1467
|
+
**Chunked Transfer Fields (when `chunked` is true):**
|
|
1468
|
+
|
|
1469
|
+
* `transfer_id` (string, mandatory): Unique identifier for the chunked transfer session.
|
|
1470
|
+
* `chunk_index` (integer, mandatory): Zero-based index of this chunk in the sequence.
|
|
1471
|
+
* `chunk_count` (integer, mandatory): Total number of chunks in the transfer.
|
|
1472
|
+
* `chunk_size` (integer, mandatory): Size of this chunk in bytes.
|
|
1473
|
+
* `total_size` (integer, mandatory): Total size of the complete content in bytes.
|
|
1474
|
+
* `chunk_hash` (string, mandatory): SHA-256 hash of this chunk for verification.
|
|
1475
|
+
* `is_final_chunk` (boolean, mandatory): Indicates if this is the last chunk in the sequence.
|
|
1476
|
+
|
|
1477
|
+
**Note:** The chunked transfer process follows the same pattern as described in [`content_response`](#content_response), with content >200KB automatically split into 64KB chunks for reliable transmission.
|
|
1478
|
+
|
|
1479
|
+
### <a name="project_state_git_stage_response"></a>`project_state_git_stage_response`
|
|
1480
|
+
|
|
1481
|
+
Confirms the result of a git stage operation. Supports responses for both single file and bulk operations.
|
|
1482
|
+
|
|
1483
|
+
**Event Fields:**
|
|
1484
|
+
|
|
1485
|
+
* `project_id` (string, mandatory): The project ID the operation was performed on.
|
|
1486
|
+
* `file_path` (string, optional): The path to the file that was staged (for single file operations).
|
|
1487
|
+
* `file_paths` (array of strings, optional): Array of paths to files that were staged (for bulk operations).
|
|
1488
|
+
* `stage_all` (boolean, optional): Present if the operation was a "stage all" operation.
|
|
1489
|
+
* `success` (boolean, mandatory): Whether the stage operation was successful.
|
|
1490
|
+
* `error` (string, optional): Error message if the operation failed.
|
|
1491
|
+
|
|
1492
|
+
### <a name="project_state_git_unstage_response"></a>`project_state_git_unstage_response`
|
|
1493
|
+
|
|
1494
|
+
Confirms the result of a git unstage operation. Supports responses for both single file and bulk operations.
|
|
1495
|
+
|
|
1496
|
+
**Event Fields:**
|
|
1497
|
+
|
|
1498
|
+
* `project_id` (string, mandatory): The project ID the operation was performed on.
|
|
1499
|
+
* `file_path` (string, optional): The path to the file that was unstaged (for single file operations).
|
|
1500
|
+
* `file_paths` (array of strings, optional): Array of paths to files that were unstaged (for bulk operations).
|
|
1501
|
+
* `unstage_all` (boolean, optional): Present if the operation was an "unstage all" operation.
|
|
1502
|
+
* `success` (boolean, mandatory): Whether the unstage operation was successful.
|
|
1503
|
+
* `error` (string, optional): Error message if the operation failed.
|
|
1504
|
+
|
|
1505
|
+
### <a name="project_state_git_revert_response"></a>`project_state_git_revert_response`
|
|
1506
|
+
|
|
1507
|
+
Confirms the result of a git revert operation. Supports responses for both single file and bulk operations.
|
|
1508
|
+
|
|
1509
|
+
**Event Fields:**
|
|
1510
|
+
|
|
1511
|
+
* `project_id` (string, mandatory): The project ID the operation was performed on.
|
|
1512
|
+
* `file_path` (string, optional): The path to the file that was reverted (for single file operations).
|
|
1513
|
+
* `file_paths` (array of strings, optional): Array of paths to files that were reverted (for bulk operations).
|
|
1514
|
+
* `revert_all` (boolean, optional): Present if the operation was a "revert all" operation.
|
|
1515
|
+
* `success` (boolean, mandatory): Whether the revert operation was successful.
|
|
1516
|
+
* `error` (string, optional): Error message if the operation failed.
|
|
1517
|
+
|
|
1518
|
+
### <a name="project_state_git_commit_response"></a>`project_state_git_commit_response`
|
|
1519
|
+
|
|
1520
|
+
Confirms the result of a git commit operation.
|
|
1521
|
+
|
|
1522
|
+
**Event Fields:**
|
|
1523
|
+
|
|
1524
|
+
* `project_id` (string, mandatory): The project ID the operation was performed on.
|
|
1525
|
+
* `commit_message` (string, mandatory): The commit message that was used.
|
|
1526
|
+
* `success` (boolean, mandatory): Whether the commit operation was successful.
|
|
1527
|
+
* `error` (string, optional): Error message if the operation failed.
|
|
1528
|
+
* `commit_hash` (string, optional): The SHA hash of the new commit if successful.
|
|
1529
|
+
|
|
727
1530
|
### Client Session Events
|
|
728
1531
|
|
|
729
1532
|
### <a name="request_client_sessions"></a>`request_client_sessions`
|
|
@@ -794,4 +1597,4 @@ Sent by the server to clients to provide initial device list snapshot.
|
|
|
794
1597
|
|
|
795
1598
|
**Event Fields:**
|
|
796
1599
|
|
|
797
|
-
* `devices` (array, mandatory): Array of device objects with status information
|
|
1600
|
+
* `devices` (array, mandatory): Array of device objects with status information
|