portacode 1.3.32__py3-none-any.whl → 1.4.11.dev5__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 +2 -2
- portacode/cli.py +158 -14
- portacode/connection/client.py +127 -8
- portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +370 -4
- portacode/connection/handlers/__init__.py +16 -1
- portacode/connection/handlers/diff_handlers.py +603 -0
- portacode/connection/handlers/file_handlers.py +674 -17
- portacode/connection/handlers/project_aware_file_handlers.py +11 -0
- portacode/connection/handlers/project_state/file_system_watcher.py +31 -61
- portacode/connection/handlers/project_state/git_manager.py +139 -572
- portacode/connection/handlers/project_state/handlers.py +28 -14
- portacode/connection/handlers/project_state/manager.py +226 -101
- portacode/connection/handlers/proxmox_infra.py +790 -0
- portacode/connection/handlers/session.py +465 -84
- portacode/connection/handlers/system_handlers.py +181 -8
- portacode/connection/handlers/tab_factory.py +1 -47
- portacode/connection/handlers/update_handler.py +61 -0
- portacode/connection/terminal.py +55 -10
- 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/pairing.py +103 -0
- portacode/static/js/utils/ntp-clock.js +170 -79
- portacode/utils/diff_apply.py +456 -0
- portacode/utils/diff_renderer.py +371 -0
- portacode/utils/ntp_clock.py +45 -131
- {portacode-1.3.32.dist-info → portacode-1.4.11.dev5.dist-info}/METADATA +71 -3
- portacode-1.4.11.dev5.dist-info/RECORD +97 -0
- test_modules/test_device_online.py +1 -1
- test_modules/test_login_flow.py +8 -4
- test_modules/test_play_store_screenshots.py +294 -0
- testing_framework/.env.example +4 -1
- testing_framework/core/playwright_manager.py +63 -9
- portacode-1.3.32.dist-info/RECORD +0 -70
- {portacode-1.3.32.dist-info → portacode-1.4.11.dev5.dist-info}/WHEEL +0 -0
- {portacode-1.3.32.dist-info → portacode-1.4.11.dev5.dist-info}/entry_points.txt +0 -0
- {portacode-1.3.32.dist-info → portacode-1.4.11.dev5.dist-info}/licenses/LICENSE +0 -0
- {portacode-1.3.32.dist-info → portacode-1.4.11.dev5.dist-info}/top_level.txt +0 -0
|
@@ -41,9 +41,14 @@ This document describes the complete protocol for communicating with devices thr
|
|
|
41
41
|
- [`terminal_list`](#terminal_list)
|
|
42
42
|
- [System Actions](#system-actions)
|
|
43
43
|
- [`system_info`](#system_info)
|
|
44
|
+
- [`update_portacode_cli`](#update_portacode_cli)
|
|
45
|
+
- [`clock_sync_request`](#clock_sync_request)
|
|
44
46
|
- [File Actions](#file-actions)
|
|
45
47
|
- [`file_read`](#file_read)
|
|
48
|
+
- [`file_search`](#file_search)
|
|
46
49
|
- [`file_write`](#file_write)
|
|
50
|
+
- [`file_apply_diff`](#file_apply_diff)
|
|
51
|
+
- [`file_preview_diff`](#file_preview_diff)
|
|
47
52
|
- [`directory_list`](#directory_list)
|
|
48
53
|
- [`file_info`](#file_info)
|
|
49
54
|
- [`file_delete`](#file_delete)
|
|
@@ -78,9 +83,14 @@ This document describes the complete protocol for communicating with devices thr
|
|
|
78
83
|
- [`terminal_list`](#terminal_list-event)
|
|
79
84
|
- [System Events](#system-events)
|
|
80
85
|
- [`system_info`](#system_info-event)
|
|
86
|
+
- [`update_portacode_response`](#update_portacode_response)
|
|
87
|
+
- [`clock_sync_response`](#clock_sync_response)
|
|
81
88
|
- [File Events](#file-events)
|
|
82
89
|
- [`file_read_response`](#file_read_response)
|
|
90
|
+
- [`file_search_response`](#file_search_response)
|
|
83
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)
|
|
84
94
|
- [`directory_list_response`](#directory_list_response)
|
|
85
95
|
- [`file_info_response`](#file_info_response)
|
|
86
96
|
- [`file_delete_response`](#file_delete_response)
|
|
@@ -310,6 +320,91 @@ This action does not require any payload fields.
|
|
|
310
320
|
|
|
311
321
|
* On success, the device will respond with a [`system_info`](#system_info-event) event.
|
|
312
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
|
+
### `create_proxmox_container`
|
|
351
|
+
|
|
352
|
+
Creates a Portacode-managed LXC container, starts it, and bootstraps the Portacode service by running the commands from [`proxmox_management/setup_portacode.py`](../../proxmox_management/setup_portacode.py). Handled by [`CreateProxmoxContainerHandler`](./proxmox_infra.py).
|
|
353
|
+
|
|
354
|
+
**Payload Fields:**
|
|
355
|
+
|
|
356
|
+
* `template` (string, required): Template identifier to use for the CT (e.g., `local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst`).
|
|
357
|
+
* `disk_gib` (integer, optional): Rootfs size in GiB (defaults to 32).
|
|
358
|
+
* `ram_mib` (integer, optional): Memory size in MiB (defaults to 2048).
|
|
359
|
+
* `cpus` (integer, optional): Number of CPU cores (defaults to 1).
|
|
360
|
+
* `hostname` (string, optional): Desired hostname inside the container; defaults to `ct<vmid>`.
|
|
361
|
+
* `username` (string, optional): OS user to provision (defaults to `svcuser`).
|
|
362
|
+
* `password` (string, optional): Password for the user (used only during provisioning).
|
|
363
|
+
* `ssh_key` (string, optional): SSH public key to add to the user.
|
|
364
|
+
|
|
365
|
+
**Responses:**
|
|
366
|
+
|
|
367
|
+
* On success, the device will emit a [`proxmox_container_created`](#proxmox_container_created-event) event that includes the Portacode auth key produced inside the container.
|
|
368
|
+
* On failure, the device will emit an [`error`](#error) event.
|
|
369
|
+
|
|
370
|
+
### `proxmox_container_created`
|
|
371
|
+
|
|
372
|
+
Emitted after a successful `create_proxmox_container` action. Contains the new container ID, the Portacode public key produced inside the container, and the bootstrap logs.
|
|
373
|
+
|
|
374
|
+
**Event Fields:**
|
|
375
|
+
|
|
376
|
+
* `success` (boolean): True when the CT and Portacode bootstrap succeed.
|
|
377
|
+
* `message` (string): Human-readable summary (e.g., `Container 103 is ready`).
|
|
378
|
+
* `ctid` (string): The numeric CT ID.
|
|
379
|
+
* `public_key` (string): Portacode public auth key created inside the new container.
|
|
380
|
+
* `container` (object): Metadata such as `vmid`, `hostname`, `template`, `storage`, `disk_gib`, `ram_mib`, and `cpus`.
|
|
381
|
+
* `setup_steps` (array[object]): Detailed bootstrap step results (name, stdout/stderr, elapsed time, and status).
|
|
382
|
+
|
|
383
|
+
### `clock_sync_request`
|
|
384
|
+
|
|
385
|
+
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).
|
|
386
|
+
|
|
387
|
+
**Payload Fields:**
|
|
388
|
+
|
|
389
|
+
* `request_id` (string, optional): Correlates the response with the request.
|
|
390
|
+
|
|
391
|
+
**Responses:**
|
|
392
|
+
|
|
393
|
+
* The gateway responds with [`clock_sync_response`](#clock_sync_response) that includes the authoritative `server_time` (plus the optional `server_time_iso` mirror).
|
|
394
|
+
|
|
395
|
+
### `update_portacode_cli`
|
|
396
|
+
|
|
397
|
+
Updates the Portacode CLI package and restarts the process. Handled by [`update_portacode_cli`](./update_handler.py).
|
|
398
|
+
|
|
399
|
+
**Payload Fields:**
|
|
400
|
+
|
|
401
|
+
This action does not require any payload fields.
|
|
402
|
+
|
|
403
|
+
**Responses:**
|
|
404
|
+
|
|
405
|
+
* On success, the device will respond with an `update_portacode_response` event and then exit with code 42 to trigger restart.
|
|
406
|
+
* On error, an `update_portacode_response` event with error details is sent.
|
|
407
|
+
|
|
313
408
|
### `file_read`
|
|
314
409
|
|
|
315
410
|
Reads the content of a file. Handled by [`file_read`](./file_handlers.py).
|
|
@@ -317,12 +412,46 @@ Reads the content of a file. Handled by [`file_read`](./file_handlers.py).
|
|
|
317
412
|
**Payload Fields:**
|
|
318
413
|
|
|
319
414
|
* `path` (string, mandatory): The absolute path to the file to read.
|
|
415
|
+
* `start_line` (integer, optional): 1-based line number to start reading from. Defaults to `1`.
|
|
416
|
+
* `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`.
|
|
417
|
+
* `max_lines` (integer, optional): Maximum number of lines to return (capped at 2000). Useful for pagination when `end_line` is not specified.
|
|
418
|
+
* `encoding` (string, optional): Text encoding to use when reading the file. Defaults to `utf-8` with replacement for invalid bytes.
|
|
320
419
|
|
|
321
420
|
**Responses:**
|
|
322
421
|
|
|
323
422
|
* On success, the device will respond with a [`file_read_response`](#file_read_response) event.
|
|
324
423
|
* On error, a generic [`error`](#error) event is sent.
|
|
325
424
|
|
|
425
|
+
### `file_search`
|
|
426
|
+
|
|
427
|
+
Searches for text matches within files beneath a given root directory. Handled by [`file_search`](./file_handlers.py).
|
|
428
|
+
|
|
429
|
+
**Payload Fields:**
|
|
430
|
+
|
|
431
|
+
* `root_path` (string, mandatory): The absolute path that acts as the search root (typically a project folder).
|
|
432
|
+
* `query` (string, mandatory): The search query. Treated as plain text unless `regex=true`.
|
|
433
|
+
* `match_case` (boolean, optional): When `true`, performs a case-sensitive search. Defaults to `false`.
|
|
434
|
+
* `regex` (boolean, optional): When `true`, interprets `query` as a regular expression. Defaults to `false`.
|
|
435
|
+
* `whole_word` (boolean, optional): When `true`, matches only whole words. Works with both plain text and regex queries.
|
|
436
|
+
* `include_patterns` (array[string], optional): Glob patterns that files must match to be included (e.g., `["src/**/*.py"]`).
|
|
437
|
+
* `exclude_patterns` (array[string], optional): Glob patterns for files/directories to skip (e.g., `["**/tests/**"]`).
|
|
438
|
+
* `include_hidden` (boolean, optional): When `true`, includes hidden files and folders. Defaults to `false`.
|
|
439
|
+
* `max_results` (integer, optional): Maximum number of match entries to return (capped at 500). Defaults to `40`.
|
|
440
|
+
* `max_matches_per_file` (integer, optional): Maximum number of matches to return per file (capped at 50). Defaults to `5`.
|
|
441
|
+
* `max_file_size` (integer, optional): Maximum file size in bytes to scan (defaults to 1 MiB).
|
|
442
|
+
* `max_line_length` (integer, optional): Maximum number of characters to return per matching line (defaults to `200`).
|
|
443
|
+
|
|
444
|
+
**Default Behaviour:**
|
|
445
|
+
|
|
446
|
+
* Binary files and large vendor/static directories (e.g., `node_modules`, `dist`, `static`) are skipped automatically unless custom `exclude_patterns` are provided.
|
|
447
|
+
* Only common source/text extensions are scanned by default (override with `include_patterns` to widen the scope).
|
|
448
|
+
* Searches stop after 10 seconds, respecting both per-file and global match limits to avoid oversized responses.
|
|
449
|
+
|
|
450
|
+
**Responses:**
|
|
451
|
+
|
|
452
|
+
* On success, the device will respond with a [`file_search_response`](#file_search_response) event containing the matches.
|
|
453
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
454
|
+
|
|
326
455
|
### `file_write`
|
|
327
456
|
|
|
328
457
|
Writes content to a file. Handled by [`file_write`](./file_handlers.py).
|
|
@@ -335,6 +464,57 @@ Writes content to a file. Handled by [`file_write`](./file_handlers.py).
|
|
|
335
464
|
**Responses:**
|
|
336
465
|
|
|
337
466
|
* On success, the device will respond with a [`file_write_response`](#file_write_response) event.
|
|
467
|
+
|
|
468
|
+
### `file_apply_diff`
|
|
469
|
+
|
|
470
|
+
Apply one or more unified diff hunks to local files. Handled by [`file_apply_diff`](./diff_handlers.py).
|
|
471
|
+
|
|
472
|
+
**Request Payload:**
|
|
473
|
+
|
|
474
|
+
```json
|
|
475
|
+
{
|
|
476
|
+
"cmd": "file_apply_diff",
|
|
477
|
+
"diff": "<unified diff string>",
|
|
478
|
+
"base_path": "<optional base path for relative diff entries>",
|
|
479
|
+
"project_id": "<server project UUID>",
|
|
480
|
+
"source_client_session": "<originating session/channel>"
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
**Behavior:**
|
|
485
|
+
|
|
486
|
+
* `diff` must be standard unified diff text (like `git diff` output). Multiple files per diff are supported.
|
|
487
|
+
* 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.
|
|
488
|
+
* Each file hunk is validated before writing; context mismatches or missing files return per-file errors without aborting the rest.
|
|
489
|
+
* `/dev/null` entries are interpreted as file creations/deletions.
|
|
490
|
+
* 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.
|
|
491
|
+
|
|
492
|
+
* On completion the device responds with [`file_apply_diff_response`](#file_apply_diff_response).
|
|
493
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
494
|
+
|
|
495
|
+
### `file_preview_diff`
|
|
496
|
+
|
|
497
|
+
Validate one or more unified diff hunks and render an HTML preview without mutating any files. Handled by [`file_preview_diff`](./diff_handlers.py).
|
|
498
|
+
|
|
499
|
+
**Request Payload:**
|
|
500
|
+
|
|
501
|
+
```json
|
|
502
|
+
{
|
|
503
|
+
"cmd": "file_preview_diff",
|
|
504
|
+
"diff": "<unified diff string>",
|
|
505
|
+
"base_path": "<optional base path for relative diff entries>",
|
|
506
|
+
"request_id": "req_123456"
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
**Behavior:**
|
|
511
|
+
|
|
512
|
+
* Reuses the same parser as `file_apply_diff`, so invalid hunks surface the same errors.
|
|
513
|
+
* Produces HTML snippets per file using the device-side renderer. No files are modified.
|
|
514
|
+
* 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”.
|
|
515
|
+
* Returns immediately with an error payload if preview generation fails.
|
|
516
|
+
|
|
517
|
+
* On completion the device responds with [`file_preview_diff_response`](#file_preview_diff_response).
|
|
338
518
|
* On error, a generic [`error`](#error) event is sent.
|
|
339
519
|
|
|
340
520
|
### `directory_list`
|
|
@@ -345,6 +525,8 @@ Lists the contents of a directory. Handled by [`directory_list`](./file_handlers
|
|
|
345
525
|
|
|
346
526
|
* `path` (string, optional): The path to the directory to list. Defaults to the current directory.
|
|
347
527
|
* `show_hidden` (boolean, optional): Whether to include hidden files in the listing. Defaults to `false`.
|
|
528
|
+
* `limit` (integer, optional): Maximum number of entries to return (defaults to “all”). Values above 1000 are clamped to 1000.
|
|
529
|
+
* `offset` (integer, optional): Number of entries to skip before collecting results (defaults to `0`).
|
|
348
530
|
|
|
349
531
|
**Responses:**
|
|
350
532
|
|
|
@@ -750,6 +932,22 @@ The `data` field contains the exact bytes output by the terminal process, decode
|
|
|
750
932
|
|
|
751
933
|
**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.
|
|
752
934
|
|
|
935
|
+
### <a name="terminal_link_request"></a>`terminal_link_request`
|
|
936
|
+
|
|
937
|
+
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.
|
|
938
|
+
|
|
939
|
+
**Event Fields:**
|
|
940
|
+
|
|
941
|
+
* `terminal_id` (string, mandatory): The UUID of the terminal session that triggered the request.
|
|
942
|
+
* `channel` (string, mandatory): Same as `terminal_id` (included for backward compatibility with raw channel routing).
|
|
943
|
+
* `url` (string, mandatory): The full URL the terminal tried to open. Clients must surface this text directly so users can verify it.
|
|
944
|
+
* `command` (string, optional): The command that attempted the navigation (e.g., `xdg-open`).
|
|
945
|
+
* `args` (array[string], optional): Arguments passed to the command, which may include safely-encoded paths or flags.
|
|
946
|
+
* `timestamp` (number, optional): UNIX epoch seconds when the capture occurred.
|
|
947
|
+
* `project_id` (string, optional): The project UUID in whose context the attempt was made.
|
|
948
|
+
|
|
949
|
+
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.
|
|
950
|
+
|
|
753
951
|
### <a name="terminal_exit"></a>`terminal_exit`
|
|
754
952
|
|
|
755
953
|
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).
|
|
@@ -806,6 +1004,100 @@ Provides system information in response to a `system_info` action. Handled by [`
|
|
|
806
1004
|
* `memory` (object): Memory usage statistics.
|
|
807
1005
|
* `disk` (object): Disk usage statistics.
|
|
808
1006
|
* `os_info` (object): Operating system details, including `os_type`, `os_version`, `architecture`, `default_shell`, and `default_cwd`.
|
|
1007
|
+
* `user_context` (object): Information about the user running the CLI, including:
|
|
1008
|
+
* `username` (string): Resolved username (via `os.getlogin` or fallback).
|
|
1009
|
+
* `username_source` (string): Which API resolved the username.
|
|
1010
|
+
* `home` (string): Home directory detected for the CLI user.
|
|
1011
|
+
* `uid` (integer|null): POSIX UID when available.
|
|
1012
|
+
* `euid` (integer|null): Effective UID when available.
|
|
1013
|
+
* `is_root` (boolean|null): True when running as root/administrator.
|
|
1014
|
+
* `has_sudo` (boolean): Whether a `sudo` binary exists on the host.
|
|
1015
|
+
* `sudo_user` (string|null): Value of `SUDO_USER` when set.
|
|
1016
|
+
* `is_sudo_session` (boolean): True when the CLI was started via `sudo`.
|
|
1017
|
+
* `playwright` (object): Optional Playwright runtime metadata when Playwright is installed:
|
|
1018
|
+
* `installed` (boolean): True if Playwright is importable on the device.
|
|
1019
|
+
* `version` (string|null): Exact package version when available.
|
|
1020
|
+
* `browsers` (object): Browser-specific data keyed by Playwright browser names:
|
|
1021
|
+
* `<browser>` (object): Per-browser info (variants: `chromium`, `firefox`, `webkit`).
|
|
1022
|
+
* `available` (boolean): True when Playwright knows an executable path.
|
|
1023
|
+
* `executable_path` (string|null): Absolute path to the browser binary when known.
|
|
1024
|
+
* `error` (string|null): Any warning message captured while probing Playwright.
|
|
1025
|
+
* `proxmox` (object): Detection hints for Proxmox VE nodes:
|
|
1026
|
+
* `is_proxmox_node` (boolean): True when Proxmox artifacts (e.g., `/etc/proxmox-release`) exist.
|
|
1027
|
+
* `version` (string|null): Raw contents of `/etc/proxmox-release` when readable.
|
|
1028
|
+
* `infra` (object): Portacode infrastructure configuration snapshot:
|
|
1029
|
+
* `configured` (boolean): True when `setup_proxmox_infra` stored an API token.
|
|
1030
|
+
* `host` (string|null): Hostname used for the API client (usually `localhost`).
|
|
1031
|
+
* `node` (string|null): Proxmox node name that was targeted.
|
|
1032
|
+
* `user` (string|null): API token owner (e.g., `root@pam`).
|
|
1033
|
+
* `token_name` (string|null): API token identifier.
|
|
1034
|
+
* `default_storage` (string|null): Storage pool chosen for future containers.
|
|
1035
|
+
* `templates` (array[string]): Cached list of available LXC templates.
|
|
1036
|
+
* `last_verified` (string|null): ISO timestamp when the token was last validated.
|
|
1037
|
+
* `network` (object):
|
|
1038
|
+
* `applied` (boolean): True when the bridge/NAT services were successfully configured.
|
|
1039
|
+
* `message` (string|null): Informational text about the network setup attempt.
|
|
1040
|
+
* `bridge` (string): The bridge interface configured (typically `vmbr1`).
|
|
1041
|
+
* `health` (string|null): `"healthy"` when the connectivity verification succeeded.
|
|
1042
|
+
* `node_status` (object|null): Status response returned by the Proxmox API when validating the token.
|
|
1043
|
+
* `portacode_version` (string): Installed CLI version returned by `portacode.__version__`.
|
|
1044
|
+
|
|
1045
|
+
### `proxmox_infra_configured`
|
|
1046
|
+
|
|
1047
|
+
Emitted after a successful `setup_proxmox_infra` action. The event reports the stored API token metadata, template list, and network setup status.
|
|
1048
|
+
|
|
1049
|
+
**Event Fields:**
|
|
1050
|
+
|
|
1051
|
+
* `success` (boolean): True when the configuration completed.
|
|
1052
|
+
* `message` (string): User-facing summary (e.g., "Proxmox infrastructure configured").
|
|
1053
|
+
* `infra` (object): Same snapshot described under [`system_info`](#system_info-event) `proxmox.infra`.
|
|
1054
|
+
|
|
1055
|
+
### `proxmox_infra_reverted`
|
|
1056
|
+
|
|
1057
|
+
Emitted after a successful `revert_proxmox_infra` action. Indicates the infra config is no longer present and the network was restored.
|
|
1058
|
+
|
|
1059
|
+
**Event Fields:**
|
|
1060
|
+
|
|
1061
|
+
* `success` (boolean): True when the revert completed.
|
|
1062
|
+
* `message` (string): Summary (e.g., "Proxmox infrastructure configuration reverted").
|
|
1063
|
+
* `infra` (object): Snapshot with `configured=false` (matching [`system_info`](#system_info-event) `proxmox.infra`).
|
|
1064
|
+
|
|
1065
|
+
### `proxmox_container_created`
|
|
1066
|
+
|
|
1067
|
+
Emitted after a successful `create_proxmox_container` action to report the newly created CT, its Portacode public key, and the bootstrap logs.
|
|
1068
|
+
|
|
1069
|
+
**Event Fields:**
|
|
1070
|
+
|
|
1071
|
+
* `success` (boolean): True when the CT provisioning and `portacode connect` steps complete.
|
|
1072
|
+
* `message` (string): Human-readable summary (e.g., `Container 102 is ready`).
|
|
1073
|
+
* `ctid` (string): The container ID that was created.
|
|
1074
|
+
* `public_key` (string): Portacode public auth key discovered inside the container.
|
|
1075
|
+
* `container` (object): Metadata such as `vmid`, `hostname`, `template`, `storage`, `disk_gib`, `ram_mib`, and `cpus`.
|
|
1076
|
+
* `setup_steps` (array[object]): Detailed bootstrap step reports including stdout/stderr, elapsed time, and pass/fail status.
|
|
1077
|
+
|
|
1078
|
+
### <a name="clock_sync_response"></a>`clock_sync_response`
|
|
1079
|
+
|
|
1080
|
+
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.
|
|
1081
|
+
|
|
1082
|
+
**Event Fields:**
|
|
1083
|
+
|
|
1084
|
+
* `event` (string): Always `clock_sync_response`.
|
|
1085
|
+
* `server_time` (integer): Server time in milliseconds.
|
|
1086
|
+
* `server_time_iso` (string, optional): ISO 8601 representation of `server_time`, useful for UI dashboards.
|
|
1087
|
+
* `server_receive_time` (integer, optional): Timestamp when the gateway received the sync request.
|
|
1088
|
+
* `server_send_time` (integer, optional): Timestamp when the gateway replied; used to compute a midpoint for latency compensation.
|
|
1089
|
+
* `request_id` (string, optional): Mirrors the request's `request_id`.
|
|
1090
|
+
|
|
1091
|
+
### `update_portacode_response`
|
|
1092
|
+
|
|
1093
|
+
Reports the result of an `update_portacode_cli` action. Handled by [`update_portacode_cli`](./update_handler.py).
|
|
1094
|
+
|
|
1095
|
+
**Event Fields:**
|
|
1096
|
+
|
|
1097
|
+
* `success` (boolean, mandatory): Whether the update operation was successful.
|
|
1098
|
+
* `message` (string, optional): Success message when update completes.
|
|
1099
|
+
* `error` (string, optional): Error message when update fails.
|
|
1100
|
+
* `restart_required` (boolean, optional): Indicates if process restart is required (always true for successful updates).
|
|
809
1101
|
|
|
810
1102
|
### <a name="file_read_response"></a>`file_read_response`
|
|
811
1103
|
|
|
@@ -814,8 +1106,39 @@ Returns the content of a file in response to a `file_read` action. Handled by [`
|
|
|
814
1106
|
**Event Fields:**
|
|
815
1107
|
|
|
816
1108
|
* `path` (string, mandatory): The path of the file that was read.
|
|
817
|
-
* `content` (string, mandatory): The content
|
|
818
|
-
* `size` (integer, mandatory): The size of the file in bytes.
|
|
1109
|
+
* `content` (string, mandatory): The file content returned (may be a slice when pagination parameters are used).
|
|
1110
|
+
* `size` (integer, mandatory): The total size of the file in bytes.
|
|
1111
|
+
* `total_lines` (integer, optional): Total number of lines detected in the file.
|
|
1112
|
+
* `returned_lines` (integer, optional): Number of lines included in `content`.
|
|
1113
|
+
* `start_line` (integer, optional): The first line number included in the response (if any lines were returned).
|
|
1114
|
+
* `requested_start_line` (integer, optional): The requested starting line supplied in the command.
|
|
1115
|
+
* `end_line` (integer, optional): The last line number included in the response.
|
|
1116
|
+
* `has_more_before` (boolean, optional): Whether there is additional content before the returned range.
|
|
1117
|
+
* `has_more_after` (boolean, optional): Whether there is additional content after the returned range.
|
|
1118
|
+
* `encoding` (string, optional): Encoding that was used while reading the file.
|
|
1119
|
+
|
|
1120
|
+
### <a name="file_search_response"></a>`file_search_response`
|
|
1121
|
+
|
|
1122
|
+
Returns aggregated search results in response to a `file_search` action. Handled by [`file_search`](./file_handlers.py).
|
|
1123
|
+
|
|
1124
|
+
**Event Fields:**
|
|
1125
|
+
|
|
1126
|
+
* `root_path` (string, mandatory): The root directory that was searched.
|
|
1127
|
+
* `query` (string, mandatory): The query string that was used.
|
|
1128
|
+
* `match_case` (boolean, mandatory): Indicates if the search was case sensitive.
|
|
1129
|
+
* `regex` (boolean, mandatory): Indicates if the query was interpreted as a regular expression.
|
|
1130
|
+
* `whole_word` (boolean, mandatory): Indicates if the search matched whole words only.
|
|
1131
|
+
* `include_patterns` (array[string], mandatory): Effective include glob patterns.
|
|
1132
|
+
* `exclude_patterns` (array[string], mandatory): Effective exclude glob patterns.
|
|
1133
|
+
* `matches` (array, mandatory): List of match objects containing `relative_path`, `path`, `line_number`, `line`, `match_spans` `[start, end]`, `match_count`, and `line_truncated` (boolean).
|
|
1134
|
+
* `matches_returned` (integer, mandatory): Number of match entries returned (length of `matches`).
|
|
1135
|
+
* `total_matches` (integer, mandatory): Total number of matches found while scanning.
|
|
1136
|
+
* `files_scanned` (integer, mandatory): Count of files inspected.
|
|
1137
|
+
* `truncated` (boolean, mandatory): Indicates if additional matches exist beyond those returned.
|
|
1138
|
+
* `truncated_count` (integer, optional): Number of matches that were omitted due to truncation limits.
|
|
1139
|
+
* `max_results` (integer, mandatory): Maximum number of matches requested.
|
|
1140
|
+
* `max_matches_per_file` (integer, mandatory): Maximum matches requested per file.
|
|
1141
|
+
* `errors` (array[string], optional): Non-fatal errors encountered during scanning (e.g., unreadable files).
|
|
819
1142
|
|
|
820
1143
|
### <a name="file_write_response"></a>`file_write_response`
|
|
821
1144
|
|
|
@@ -827,6 +1150,45 @@ Confirms that a file has been written successfully in response to a `file_write`
|
|
|
827
1150
|
* `bytes_written` (integer, mandatory): The number of bytes written to the file.
|
|
828
1151
|
* `success` (boolean, mandatory): Indicates whether the write operation was successful.
|
|
829
1152
|
|
|
1153
|
+
### <a name="file_apply_diff_response"></a>`file_apply_diff_response`
|
|
1154
|
+
|
|
1155
|
+
Reports the outcome of a [`file_apply_diff`](#file_apply_diff) action.
|
|
1156
|
+
|
|
1157
|
+
**Event Fields:**
|
|
1158
|
+
|
|
1159
|
+
* `event`: Always `"file_apply_diff_response"`.
|
|
1160
|
+
* `success`: Boolean indicating whether all hunks succeeded.
|
|
1161
|
+
* `status`: `"success"`, `"partial_failure"`, or `"failed"`.
|
|
1162
|
+
* `base_path`: Absolute base path used for relative diff entries.
|
|
1163
|
+
* `files_changed`: Number of files successfully updated.
|
|
1164
|
+
* `results`: Array containing one object per file with:
|
|
1165
|
+
* `path`: Absolute path on the device.
|
|
1166
|
+
* `status`: `"applied"` or `"error"`.
|
|
1167
|
+
* `action`: `"created"`, `"modified"`, or `"deleted"` (present for successes).
|
|
1168
|
+
* `bytes_written`: Bytes written for the file (0 for deletes).
|
|
1169
|
+
* `error`: Error text when the patch failed for that file.
|
|
1170
|
+
* `line`: Optional line number hint for mismatches.
|
|
1171
|
+
|
|
1172
|
+
The response is emitted even if some files fail so the caller can retry with corrected diffs.
|
|
1173
|
+
|
|
1174
|
+
### <a name="file_preview_diff_response"></a>`file_preview_diff_response`
|
|
1175
|
+
|
|
1176
|
+
Reports the outcome of a [`file_preview_diff`](#file_preview_diff) action.
|
|
1177
|
+
|
|
1178
|
+
**Event Fields:**
|
|
1179
|
+
|
|
1180
|
+
* `event`: Always `"file_preview_diff_response"`.
|
|
1181
|
+
* `success`: Boolean indicating whether all previews rendered successfully.
|
|
1182
|
+
* `status`: `"success"`, `"partial_failure"`, or `"failed"`.
|
|
1183
|
+
* `base_path`: Absolute base path used for relative paths.
|
|
1184
|
+
* `previews`: Array containing one entry per file with:
|
|
1185
|
+
* `path`: Absolute path hint (used for syntax highlighting).
|
|
1186
|
+
* `relative_path`: Relative project path if known.
|
|
1187
|
+
* `status`: `"ready"` or `"error"`.
|
|
1188
|
+
* `html`: Rendered diff snippet (when status is `"ready"`).
|
|
1189
|
+
* `error`: Error text (when status is `"error"`).
|
|
1190
|
+
* `error`: Optional top-level error string when the entire preview failed (e.g., diff parse error).
|
|
1191
|
+
|
|
830
1192
|
### <a name="directory_list_response"></a>`directory_list_response`
|
|
831
1193
|
|
|
832
1194
|
Returns the contents of a directory in response to a `directory_list` action. Handled by [`directory_list`](./file_handlers.py).
|
|
@@ -835,7 +1197,11 @@ Returns the contents of a directory in response to a `directory_list` action. Ha
|
|
|
835
1197
|
|
|
836
1198
|
* `path` (string, mandatory): The path of the directory that was listed.
|
|
837
1199
|
* `items` (array, mandatory): A list of objects, each representing a file or directory in the listed directory.
|
|
838
|
-
* `count` (integer, mandatory): The number of items in
|
|
1200
|
+
* `count` (integer, mandatory): The number of items returned in this response (honours `limit`/`offset`).
|
|
1201
|
+
* `total_count` (integer, mandatory): Total number of entries in the directory before pagination.
|
|
1202
|
+
* `offset` (integer, optional): Offset that was applied.
|
|
1203
|
+
* `limit` (integer, optional): Limit that was applied (or `null` if none).
|
|
1204
|
+
* `has_more` (boolean, optional): Indicates whether additional items remain beyond the returned slice.
|
|
839
1205
|
|
|
840
1206
|
### <a name="file_info_response"></a>`file_info_response`
|
|
841
1207
|
|
|
@@ -1277,4 +1643,4 @@ Sent by the server to clients to provide initial device list snapshot.
|
|
|
1277
1643
|
|
|
1278
1644
|
**Event Fields:**
|
|
1279
1645
|
|
|
1280
|
-
* `devices` (array, mandatory): Array of device objects with status information
|
|
1646
|
+
* `devices` (array, mandatory): Array of device objects with status information
|
|
@@ -14,6 +14,7 @@ from .terminal_handlers import (
|
|
|
14
14
|
TerminalListHandler,
|
|
15
15
|
)
|
|
16
16
|
from .system_handlers import SystemInfoHandler
|
|
17
|
+
from .update_handler import UpdatePortacodeHandler
|
|
17
18
|
from .file_handlers import (
|
|
18
19
|
FileReadHandler,
|
|
19
20
|
FileWriteHandler,
|
|
@@ -23,8 +24,10 @@ from .file_handlers import (
|
|
|
23
24
|
FileCreateHandler,
|
|
24
25
|
FolderCreateHandler,
|
|
25
26
|
FileRenameHandler,
|
|
27
|
+
FileSearchHandler,
|
|
26
28
|
ContentRequestHandler,
|
|
27
29
|
)
|
|
30
|
+
from .diff_handlers import FileApplyDiffHandler, FilePreviewDiffHandler
|
|
28
31
|
from .project_state_handlers import (
|
|
29
32
|
ProjectStateFolderExpandHandler,
|
|
30
33
|
ProjectStateFolderCollapseHandler,
|
|
@@ -38,6 +41,11 @@ from .project_state_handlers import (
|
|
|
38
41
|
ProjectStateGitRevertHandler,
|
|
39
42
|
ProjectStateGitCommitHandler,
|
|
40
43
|
)
|
|
44
|
+
from .proxmox_infra import (
|
|
45
|
+
ConfigureProxmoxInfraHandler,
|
|
46
|
+
CreateProxmoxContainerHandler,
|
|
47
|
+
RevertProxmoxInfraHandler,
|
|
48
|
+
)
|
|
41
49
|
|
|
42
50
|
__all__ = [
|
|
43
51
|
"BaseHandler",
|
|
@@ -49,6 +57,8 @@ __all__ = [
|
|
|
49
57
|
"TerminalStopHandler",
|
|
50
58
|
"TerminalListHandler",
|
|
51
59
|
"SystemInfoHandler",
|
|
60
|
+
"ConfigureProxmoxInfraHandler",
|
|
61
|
+
"CreateProxmoxContainerHandler",
|
|
52
62
|
# File operation handlers (optional - register as needed)
|
|
53
63
|
"FileReadHandler",
|
|
54
64
|
"FileWriteHandler",
|
|
@@ -58,7 +68,10 @@ __all__ = [
|
|
|
58
68
|
"FileCreateHandler",
|
|
59
69
|
"FolderCreateHandler",
|
|
60
70
|
"FileRenameHandler",
|
|
71
|
+
"FileSearchHandler",
|
|
61
72
|
"ContentRequestHandler",
|
|
73
|
+
"FileApplyDiffHandler",
|
|
74
|
+
"FilePreviewDiffHandler",
|
|
62
75
|
# Project state handlers
|
|
63
76
|
"ProjectStateFolderExpandHandler",
|
|
64
77
|
"ProjectStateFolderCollapseHandler",
|
|
@@ -71,4 +84,6 @@ __all__ = [
|
|
|
71
84
|
"ProjectStateGitUnstageHandler",
|
|
72
85
|
"ProjectStateGitRevertHandler",
|
|
73
86
|
"ProjectStateGitCommitHandler",
|
|
74
|
-
|
|
87
|
+
"UpdatePortacodeHandler",
|
|
88
|
+
"RevertProxmoxInfraHandler",
|
|
89
|
+
]
|