portacode 0.3.22__tar.gz → 0.3.24__tar.gz
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-0.3.22 → portacode-0.3.24}/PKG-INFO +13 -2
- {portacode-0.3.22 → portacode-0.3.24}/docker-compose.yaml +29 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/_version.py +16 -3
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/WEBSOCKET_PROTOCOL.md +188 -16
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/__init__.py +4 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/base.py +9 -5
- portacode-0.3.24/portacode/connection/handlers/chunked_content.py +244 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/file_handlers.py +68 -2
- portacode-0.3.24/portacode/connection/handlers/project_aware_file_handlers.py +215 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/project_state/git_manager.py +326 -66
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/project_state/handlers.py +307 -31
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/project_state/manager.py +44 -1
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/project_state/models.py +7 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/project_state/utils.py +17 -1
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/project_state_handlers.py +1 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/tab_factory.py +60 -7
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/terminal.py +13 -7
- {portacode-0.3.22 → portacode-0.3.24}/portacode.egg-info/PKG-INFO +13 -2
- {portacode-0.3.22 → portacode-0.3.24}/portacode.egg-info/SOURCES.txt +1 -0
- {portacode-0.3.22 → portacode-0.3.24}/test.sh +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/test_modules/test_git_status_ui.py +24 -66
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/core/playwright_manager.py +23 -0
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/core/runner.py +10 -2
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/core/test_discovery.py +7 -3
- portacode-0.3.22/portacode/connection/handlers/project_aware_file_handlers.py +0 -73
- {portacode-0.3.22 → portacode-0.3.24}/.claude/agents/communication-manager.md +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/.claude/settings.local.json +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/.gitignore +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/.gitmodules +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/LICENSE +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/MANIFEST.in +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/Makefile +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/README.md +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/backup.sh +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/connect.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/connect.sh +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/README.md +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/__init__.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/__main__.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/cli.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/README.md +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/__init__.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/client.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/README.md +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/project_state/README.md +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/project_state/__init__.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/project_state/file_system_watcher.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/registry.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/session.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/system_handlers.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/handlers/terminal_handlers.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/connection/multiplex.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/data.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/keypair.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/logging_categories.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode/service.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode.egg-info/dependency_links.txt +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode.egg-info/entry_points.txt +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode.egg-info/requires.txt +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/portacode.egg-info/top_level.txt +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/pyproject.toml +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/restore.sh +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/run_tests.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/setup.cfg +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/setup.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/test_modules/README.md +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/test_modules/__init__.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/test_modules/test_device_online.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/test_modules/test_file_operations.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/test_modules/test_login_flow.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/test_modules/test_navigate_testing_folder.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/test_modules/test_terminal_buffer_performance.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/test_modules/test_terminal_interaction.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/test_modules/test_terminal_loading_race_condition.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/test_modules/test_terminal_start.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/.env.example +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/README.md +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/__init__.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/cli.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/core/__init__.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/core/base_test.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/core/cli_manager.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/core/hierarchical_runner.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/core/shared_cli_manager.py +0 -0
- {portacode-0.3.22 → portacode-0.3.24}/testing_framework/requirements.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: portacode
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.24
|
|
4
4
|
Summary: Portacode CLI client and SDK
|
|
5
5
|
Home-page: https://github.com/portacode/portacode
|
|
6
6
|
Author: Meena Erian
|
|
@@ -27,6 +27,17 @@ Provides-Extra: dev
|
|
|
27
27
|
Requires-Dist: black; extra == "dev"
|
|
28
28
|
Requires-Dist: flake8; extra == "dev"
|
|
29
29
|
Requires-Dist: pytest; extra == "dev"
|
|
30
|
+
Dynamic: author
|
|
31
|
+
Dynamic: author-email
|
|
32
|
+
Dynamic: classifier
|
|
33
|
+
Dynamic: description
|
|
34
|
+
Dynamic: description-content-type
|
|
35
|
+
Dynamic: home-page
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
Dynamic: provides-extra
|
|
38
|
+
Dynamic: requires-dist
|
|
39
|
+
Dynamic: requires-python
|
|
40
|
+
Dynamic: summary
|
|
30
41
|
|
|
31
42
|
# Portacode
|
|
32
43
|
|
|
@@ -32,6 +32,35 @@ services:
|
|
|
32
32
|
volumes:
|
|
33
33
|
- ./server/portacode_django:/app
|
|
34
34
|
|
|
35
|
+
unibot-worker:
|
|
36
|
+
build:
|
|
37
|
+
context: ./server/portacode_django
|
|
38
|
+
dockerfile: Dockerfile
|
|
39
|
+
container_name: portacode-unibot-worker
|
|
40
|
+
restart: unless-stopped
|
|
41
|
+
command: ["python", "manage.py", "run_worker"]
|
|
42
|
+
env_file:
|
|
43
|
+
- main.env
|
|
44
|
+
depends_on:
|
|
45
|
+
db:
|
|
46
|
+
condition: service_healthy
|
|
47
|
+
volumes:
|
|
48
|
+
- ./server/portacode_django:/app
|
|
49
|
+
|
|
50
|
+
imap-worker:
|
|
51
|
+
build:
|
|
52
|
+
context: ./server/portacode_django
|
|
53
|
+
dockerfile: Dockerfile
|
|
54
|
+
container_name: portacode-imap-worker
|
|
55
|
+
restart: unless-stopped
|
|
56
|
+
command: ["python", "manage.py", "start_imap_listeners"]
|
|
57
|
+
env_file:
|
|
58
|
+
- main.env
|
|
59
|
+
depends_on:
|
|
60
|
+
db:
|
|
61
|
+
condition: service_healthy
|
|
62
|
+
volumes:
|
|
63
|
+
- ./server/portacode_django:/app
|
|
35
64
|
|
|
36
65
|
volumes:
|
|
37
66
|
pgdata:
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
3
|
|
|
4
|
-
__all__ = [
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
5
12
|
|
|
6
13
|
TYPE_CHECKING = False
|
|
7
14
|
if TYPE_CHECKING:
|
|
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
|
|
|
9
16
|
from typing import Union
|
|
10
17
|
|
|
11
18
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
12
20
|
else:
|
|
13
21
|
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
14
23
|
|
|
15
24
|
version: str
|
|
16
25
|
__version__: str
|
|
17
26
|
__version_tuple__: VERSION_TUPLE
|
|
18
27
|
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
19
30
|
|
|
20
|
-
__version__ = version = '0.3.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 3,
|
|
31
|
+
__version__ = version = '0.3.24'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 24)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
|
@@ -22,6 +22,7 @@ This document outlines the WebSocket communication protocol between the Portacod
|
|
|
22
22
|
- [`file_create`](#file_create)
|
|
23
23
|
- [`folder_create`](#folder_create)
|
|
24
24
|
- [`file_rename`](#file_rename)
|
|
25
|
+
- [`content_request`](#content_request)
|
|
25
26
|
- [Project State Actions](#project-state-actions)
|
|
26
27
|
- [`project_state_folder_expand`](#project_state_folder_expand)
|
|
27
28
|
- [`project_state_folder_collapse`](#project_state_folder_collapse)
|
|
@@ -29,6 +30,7 @@ This document outlines the WebSocket communication protocol between the Portacod
|
|
|
29
30
|
- [`project_state_tab_close`](#project_state_tab_close)
|
|
30
31
|
- [`project_state_set_active_tab`](#project_state_set_active_tab)
|
|
31
32
|
- [`project_state_diff_open`](#project_state_diff_open)
|
|
33
|
+
- [`project_state_diff_content_request`](#project_state_diff_content_request)
|
|
32
34
|
- [`project_state_git_stage`](#project_state_git_stage)
|
|
33
35
|
- [`project_state_git_unstage`](#project_state_git_unstage)
|
|
34
36
|
- [`project_state_git_revert`](#project_state_git_revert)
|
|
@@ -57,6 +59,7 @@ This document outlines the WebSocket communication protocol between the Portacod
|
|
|
57
59
|
- [`file_create_response`](#file_create_response)
|
|
58
60
|
- [`folder_create_response`](#folder_create_response)
|
|
59
61
|
- [`file_rename_response`](#file_rename_response)
|
|
62
|
+
- [`content_response`](#content_response)
|
|
60
63
|
- [Project State Events](#project-state-events)
|
|
61
64
|
- [`project_state_initialized`](#project_state_initialized)
|
|
62
65
|
- [`project_state_update`](#project_state_update)
|
|
@@ -66,6 +69,7 @@ This document outlines the WebSocket communication protocol between the Portacod
|
|
|
66
69
|
- [`project_state_tab_close_response`](#project_state_tab_close_response)
|
|
67
70
|
- [`project_state_set_active_tab_response`](#project_state_set_active_tab_response)
|
|
68
71
|
- [`project_state_diff_open_response`](#project_state_diff_open_response)
|
|
72
|
+
- [`project_state_diff_content_response`](#project_state_diff_content_response)
|
|
69
73
|
- [`project_state_git_stage_response`](#project_state_git_stage_response)
|
|
70
74
|
- [`project_state_git_unstage_response`](#project_state_git_unstage_response)
|
|
71
75
|
- [`project_state_git_revert_response`](#project_state_git_revert_response)
|
|
@@ -298,6 +302,20 @@ Renames a file or folder. Handled by [`file_rename`](./file_handlers.py).
|
|
|
298
302
|
* On success, the device will respond with a [`file_rename_response`](#file_rename_response) event.
|
|
299
303
|
* On error, a generic [`error`](#error) event is sent.
|
|
300
304
|
|
|
305
|
+
### `content_request`
|
|
306
|
+
|
|
307
|
+
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).
|
|
308
|
+
|
|
309
|
+
**Payload Fields:**
|
|
310
|
+
|
|
311
|
+
* `content_hash` (string, mandatory): The SHA-256 hash of the content to retrieve (with "sha256:" prefix).
|
|
312
|
+
* `request_id` (string, mandatory): A unique identifier for this request, used to match with the response.
|
|
313
|
+
|
|
314
|
+
**Responses:**
|
|
315
|
+
|
|
316
|
+
* On success, the device will respond with one or more [`content_response`](#content_response) events containing the cached content. Large content is automatically chunked.
|
|
317
|
+
* On error (content not found), a [`content_response`](#content_response) event with `success: false` is sent.
|
|
318
|
+
|
|
301
319
|
## Project State Actions
|
|
302
320
|
|
|
303
321
|
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.
|
|
@@ -408,14 +426,51 @@ Opens a diff tab for comparing file versions at different points in the git time
|
|
|
408
426
|
* 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.
|
|
409
427
|
* On error, a generic [`error`](#error) event is sent.
|
|
410
428
|
|
|
429
|
+
### `project_state_diff_content_request`
|
|
430
|
+
|
|
431
|
+
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.
|
|
432
|
+
|
|
433
|
+
**Content Types:** This action can request content for a diff:
|
|
434
|
+
- `original`: The original (from) content of the diff
|
|
435
|
+
- `modified`: The modified (to) content of the diff
|
|
436
|
+
- `html_diff`: The HTML diff versions for rich visual display
|
|
437
|
+
- `all`: All content types returned as a single JSON object (recommended for efficiency)
|
|
438
|
+
|
|
439
|
+
**Payload Fields:**
|
|
440
|
+
|
|
441
|
+
* `project_id` (string, mandatory): The project ID from the initialized project state.
|
|
442
|
+
* `file_path` (string, mandatory): The absolute path to the file the diff is for.
|
|
443
|
+
* `from_ref` (string, mandatory): The source reference point used in the diff. Must match the diff tab parameters.
|
|
444
|
+
* `to_ref` (string, mandatory): The target reference point used in the diff. Must match the diff tab parameters.
|
|
445
|
+
* `from_hash` (string, optional): The commit hash for `from_ref` if it was `"commit"`. Must match the diff tab parameters.
|
|
446
|
+
* `to_hash` (string, optional): The commit hash for `to_ref` if it was `"commit"`. Must match the diff tab parameters.
|
|
447
|
+
* `content_type` (string, mandatory): The type of content to request. Must be one of:
|
|
448
|
+
- `"original"`: Request the original (from) content
|
|
449
|
+
- `"modified"`: Request the modified (to) content
|
|
450
|
+
- `"html_diff"`: Request the HTML diff versions for visual display
|
|
451
|
+
- `"all"`: Request all content types as a single JSON object
|
|
452
|
+
* `request_id` (string, mandatory): Unique identifier for this request to match with the response.
|
|
453
|
+
|
|
454
|
+
**Responses:**
|
|
455
|
+
|
|
456
|
+
* 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.
|
|
457
|
+
* On error, a generic [`error`](#error) event is sent.
|
|
458
|
+
|
|
411
459
|
### `project_state_git_stage`
|
|
412
460
|
|
|
413
|
-
Stages
|
|
461
|
+
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).
|
|
414
462
|
|
|
415
463
|
**Payload Fields:**
|
|
416
464
|
|
|
417
465
|
* `project_id` (string, mandatory): The project ID from the initialized project state.
|
|
418
|
-
* `file_path` (string,
|
|
466
|
+
* `file_path` (string, optional): The absolute path to a single file to stage. Used for backward compatibility.
|
|
467
|
+
* `file_paths` (array of strings, optional): Array of absolute paths to files to stage. Used for bulk operations.
|
|
468
|
+
* `stage_all` (boolean, optional): If true, stages all unstaged changes in the repository. Takes precedence over file_path/file_paths.
|
|
469
|
+
|
|
470
|
+
**Operation Modes:**
|
|
471
|
+
- Single file: Provide `file_path`
|
|
472
|
+
- Bulk operation: Provide `file_paths` array
|
|
473
|
+
- Stage all: Set `stage_all` to true
|
|
419
474
|
|
|
420
475
|
**Responses:**
|
|
421
476
|
|
|
@@ -424,12 +479,19 @@ Stages a file for commit in the project's git repository. Handled by [`project_s
|
|
|
424
479
|
|
|
425
480
|
### `project_state_git_unstage`
|
|
426
481
|
|
|
427
|
-
Unstages
|
|
482
|
+
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).
|
|
428
483
|
|
|
429
484
|
**Payload Fields:**
|
|
430
485
|
|
|
431
486
|
* `project_id` (string, mandatory): The project ID from the initialized project state.
|
|
432
|
-
* `file_path` (string,
|
|
487
|
+
* `file_path` (string, optional): The absolute path to a single file to unstage. Used for backward compatibility.
|
|
488
|
+
* `file_paths` (array of strings, optional): Array of absolute paths to files to unstage. Used for bulk operations.
|
|
489
|
+
* `unstage_all` (boolean, optional): If true, unstages all staged changes in the repository. Takes precedence over file_path/file_paths.
|
|
490
|
+
|
|
491
|
+
**Operation Modes:**
|
|
492
|
+
- Single file: Provide `file_path`
|
|
493
|
+
- Bulk operation: Provide `file_paths` array
|
|
494
|
+
- Unstage all: Set `unstage_all` to true
|
|
433
495
|
|
|
434
496
|
**Responses:**
|
|
435
497
|
|
|
@@ -438,12 +500,19 @@ Unstages a file (removes from staging area) in the project's git repository. Han
|
|
|
438
500
|
|
|
439
501
|
### `project_state_git_revert`
|
|
440
502
|
|
|
441
|
-
Reverts
|
|
503
|
+
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).
|
|
442
504
|
|
|
443
505
|
**Payload Fields:**
|
|
444
506
|
|
|
445
507
|
* `project_id` (string, mandatory): The project ID from the initialized project state.
|
|
446
|
-
* `file_path` (string,
|
|
508
|
+
* `file_path` (string, optional): The absolute path to a single file to revert. Used for backward compatibility.
|
|
509
|
+
* `file_paths` (array of strings, optional): Array of absolute paths to files to revert. Used for bulk operations.
|
|
510
|
+
* `revert_all` (boolean, optional): If true, reverts all unstaged changes in the repository. Takes precedence over file_path/file_paths.
|
|
511
|
+
|
|
512
|
+
**Operation Modes:**
|
|
513
|
+
- Single file: Provide `file_path`
|
|
514
|
+
- Bulk operation: Provide `file_paths` array
|
|
515
|
+
- Revert all: Set `revert_all` to true
|
|
447
516
|
|
|
448
517
|
**Responses:**
|
|
449
518
|
|
|
@@ -713,6 +782,68 @@ Confirms that a file or folder has been renamed successfully in response to a `f
|
|
|
713
782
|
* `is_directory` (boolean, mandatory): Indicates whether the renamed item is a directory.
|
|
714
783
|
* `success` (boolean, mandatory): Indicates whether the rename was successful.
|
|
715
784
|
|
|
785
|
+
### <a name="content_response"></a>`content_response`
|
|
786
|
+
|
|
787
|
+
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).
|
|
788
|
+
|
|
789
|
+
**Event Fields:**
|
|
790
|
+
|
|
791
|
+
* `request_id` (string, mandatory): The unique identifier from the corresponding request, used to match request and response.
|
|
792
|
+
* `content_hash` (string, mandatory): The SHA-256 hash that was requested.
|
|
793
|
+
* `content` (string, optional): The cached content or chunk content if found and `success` is true. Null if content was not found.
|
|
794
|
+
* `success` (boolean, mandatory): Indicates whether the content was found and returned successfully.
|
|
795
|
+
* `error` (string, optional): Error message if `success` is false (e.g., "Content not found in cache").
|
|
796
|
+
* `chunked` (boolean, mandatory): Indicates whether this response is part of a chunked transfer. False for single responses, true for chunked responses.
|
|
797
|
+
|
|
798
|
+
**Chunked Transfer Fields (when `chunked` is true):**
|
|
799
|
+
|
|
800
|
+
* `transfer_id` (string, mandatory): Unique identifier for the chunked transfer session.
|
|
801
|
+
* `chunk_index` (integer, mandatory): Zero-based index of this chunk in the sequence.
|
|
802
|
+
* `chunk_count` (integer, mandatory): Total number of chunks in the transfer.
|
|
803
|
+
* `chunk_size` (integer, mandatory): Size of this chunk in bytes.
|
|
804
|
+
* `total_size` (integer, mandatory): Total size of the complete content in bytes.
|
|
805
|
+
* `chunk_hash` (string, mandatory): SHA-256 hash of this chunk for verification.
|
|
806
|
+
* `is_final_chunk` (boolean, mandatory): Indicates if this is the last chunk in the sequence.
|
|
807
|
+
|
|
808
|
+
**Chunked Transfer Process:**
|
|
809
|
+
|
|
810
|
+
1. **Size Check**: Content >200KB is automatically chunked into 64KB chunks
|
|
811
|
+
2. **Sequential Delivery**: Chunks are sent in order with increasing `chunk_index`
|
|
812
|
+
3. **Client Assembly**: Client collects all chunks and verifies integrity using hashes
|
|
813
|
+
4. **Hash Verification**: Both individual chunk hashes and final content hash are verified
|
|
814
|
+
5. **Error Handling**: Missing chunks or hash mismatches trigger request failure
|
|
815
|
+
|
|
816
|
+
**Example Non-Chunked Response:**
|
|
817
|
+
```json
|
|
818
|
+
{
|
|
819
|
+
"event": "content_response",
|
|
820
|
+
"request_id": "req_abc123",
|
|
821
|
+
"content_hash": "sha256:...",
|
|
822
|
+
"content": "Small content here",
|
|
823
|
+
"success": true,
|
|
824
|
+
"chunked": false
|
|
825
|
+
}
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
**Example Chunked Response (first chunk):**
|
|
829
|
+
```json
|
|
830
|
+
{
|
|
831
|
+
"event": "content_response",
|
|
832
|
+
"request_id": "req_abc123",
|
|
833
|
+
"content_hash": "sha256:...",
|
|
834
|
+
"content": "First chunk content...",
|
|
835
|
+
"success": true,
|
|
836
|
+
"chunked": true,
|
|
837
|
+
"transfer_id": "transfer_xyz789",
|
|
838
|
+
"chunk_index": 0,
|
|
839
|
+
"chunk_count": 5,
|
|
840
|
+
"chunk_size": 65536,
|
|
841
|
+
"total_size": 300000,
|
|
842
|
+
"chunk_hash": "chunk_sha256:...",
|
|
843
|
+
"is_final_chunk": false
|
|
844
|
+
}
|
|
845
|
+
```
|
|
846
|
+
|
|
716
847
|
### Project State Events
|
|
717
848
|
|
|
718
849
|
### <a name="project_state_initialized"></a>`project_state_initialized`
|
|
@@ -752,13 +883,17 @@ Confirms that project state has been successfully initialized for a client sessi
|
|
|
752
883
|
* `tab_type` (string, mandatory): Type of tab ("file", "diff", "untitled", "image", "audio", "video").
|
|
753
884
|
* `title` (string, mandatory): Display title for the tab.
|
|
754
885
|
* `file_path` (string, optional): Path for file-based tabs.
|
|
755
|
-
* `content` (string, optional): Text content or base64 for media.
|
|
756
|
-
* `original_content` (string, optional): For diff tabs - original content.
|
|
757
|
-
* `modified_content` (string, optional): For diff tabs - modified content.
|
|
886
|
+
* `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`.
|
|
887
|
+
* `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`.
|
|
888
|
+
* `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`.
|
|
758
889
|
* `is_dirty` (boolean, mandatory): Whether the tab has unsaved changes.
|
|
759
890
|
* `mime_type` (string, optional): MIME type for media files.
|
|
760
891
|
* `encoding` (string, optional): Content encoding (base64, utf-8, etc.).
|
|
761
|
-
* `metadata` (object, optional): Additional metadata.
|
|
892
|
+
* `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`.
|
|
893
|
+
* `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.
|
|
894
|
+
* `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.
|
|
895
|
+
* `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.
|
|
896
|
+
* `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.
|
|
762
897
|
* `active_tab` (object, optional): The currently active tab object, or null if no tab is active.
|
|
763
898
|
* `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:
|
|
764
899
|
* `name` (string, mandatory): The file or directory name.
|
|
@@ -872,36 +1007,73 @@ Confirms the result of opening a diff tab with git timeline references.
|
|
|
872
1007
|
* `success` (boolean, mandatory): Whether the diff tab creation was successful.
|
|
873
1008
|
* `error` (string, optional): Error message if the operation failed.
|
|
874
1009
|
|
|
1010
|
+
### <a name="project_state_diff_content_response"></a>`project_state_diff_content_response`
|
|
1011
|
+
|
|
1012
|
+
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.
|
|
1013
|
+
|
|
1014
|
+
**Event Fields:**
|
|
1015
|
+
|
|
1016
|
+
* `project_id` (string, mandatory): The project ID the operation was performed on.
|
|
1017
|
+
* `file_path` (string, mandatory): The path to the file the diff content is for.
|
|
1018
|
+
* `from_ref` (string, mandatory): The source reference point used in the diff.
|
|
1019
|
+
* `to_ref` (string, mandatory): The target reference point used in the diff.
|
|
1020
|
+
* `from_hash` (string, optional): The commit hash used for `from_ref` if it was `"commit"`.
|
|
1021
|
+
* `to_hash` (string, optional): The commit hash used for `to_ref` if it was `"commit"`.
|
|
1022
|
+
* `content_type` (string, mandatory): The type of content being returned (`"original"`, `"modified"`, `"html_diff"`, or `"all"`).
|
|
1023
|
+
* `request_id` (string, mandatory): The unique identifier from the request to match response with request.
|
|
1024
|
+
* `success` (boolean, mandatory): Whether the content retrieval was successful.
|
|
1025
|
+
* `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.
|
|
1026
|
+
* `error` (string, optional): Error message if the operation failed.
|
|
1027
|
+
* `chunked` (boolean, mandatory): Indicates whether this response is part of a chunked transfer. False for single responses, true for chunked responses.
|
|
1028
|
+
|
|
1029
|
+
**Chunked Transfer Fields (when `chunked` is true):**
|
|
1030
|
+
|
|
1031
|
+
* `transfer_id` (string, mandatory): Unique identifier for the chunked transfer session.
|
|
1032
|
+
* `chunk_index` (integer, mandatory): Zero-based index of this chunk in the sequence.
|
|
1033
|
+
* `chunk_count` (integer, mandatory): Total number of chunks in the transfer.
|
|
1034
|
+
* `chunk_size` (integer, mandatory): Size of this chunk in bytes.
|
|
1035
|
+
* `total_size` (integer, mandatory): Total size of the complete content in bytes.
|
|
1036
|
+
* `chunk_hash` (string, mandatory): SHA-256 hash of this chunk for verification.
|
|
1037
|
+
* `is_final_chunk` (boolean, mandatory): Indicates if this is the last chunk in the sequence.
|
|
1038
|
+
|
|
1039
|
+
**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.
|
|
1040
|
+
|
|
875
1041
|
### <a name="project_state_git_stage_response"></a>`project_state_git_stage_response`
|
|
876
1042
|
|
|
877
|
-
Confirms the result of a git stage operation.
|
|
1043
|
+
Confirms the result of a git stage operation. Supports responses for both single file and bulk operations.
|
|
878
1044
|
|
|
879
1045
|
**Event Fields:**
|
|
880
1046
|
|
|
881
1047
|
* `project_id` (string, mandatory): The project ID the operation was performed on.
|
|
882
|
-
* `file_path` (string,
|
|
1048
|
+
* `file_path` (string, optional): The path to the file that was staged (for single file operations).
|
|
1049
|
+
* `file_paths` (array of strings, optional): Array of paths to files that were staged (for bulk operations).
|
|
1050
|
+
* `stage_all` (boolean, optional): Present if the operation was a "stage all" operation.
|
|
883
1051
|
* `success` (boolean, mandatory): Whether the stage operation was successful.
|
|
884
1052
|
* `error` (string, optional): Error message if the operation failed.
|
|
885
1053
|
|
|
886
1054
|
### <a name="project_state_git_unstage_response"></a>`project_state_git_unstage_response`
|
|
887
1055
|
|
|
888
|
-
Confirms the result of a git unstage operation.
|
|
1056
|
+
Confirms the result of a git unstage operation. Supports responses for both single file and bulk operations.
|
|
889
1057
|
|
|
890
1058
|
**Event Fields:**
|
|
891
1059
|
|
|
892
1060
|
* `project_id` (string, mandatory): The project ID the operation was performed on.
|
|
893
|
-
* `file_path` (string,
|
|
1061
|
+
* `file_path` (string, optional): The path to the file that was unstaged (for single file operations).
|
|
1062
|
+
* `file_paths` (array of strings, optional): Array of paths to files that were unstaged (for bulk operations).
|
|
1063
|
+
* `unstage_all` (boolean, optional): Present if the operation was an "unstage all" operation.
|
|
894
1064
|
* `success` (boolean, mandatory): Whether the unstage operation was successful.
|
|
895
1065
|
* `error` (string, optional): Error message if the operation failed.
|
|
896
1066
|
|
|
897
1067
|
### <a name="project_state_git_revert_response"></a>`project_state_git_revert_response`
|
|
898
1068
|
|
|
899
|
-
Confirms the result of a git revert operation.
|
|
1069
|
+
Confirms the result of a git revert operation. Supports responses for both single file and bulk operations.
|
|
900
1070
|
|
|
901
1071
|
**Event Fields:**
|
|
902
1072
|
|
|
903
1073
|
* `project_id` (string, mandatory): The project ID the operation was performed on.
|
|
904
|
-
* `file_path` (string,
|
|
1074
|
+
* `file_path` (string, optional): The path to the file that was reverted (for single file operations).
|
|
1075
|
+
* `file_paths` (array of strings, optional): Array of paths to files that were reverted (for bulk operations).
|
|
1076
|
+
* `revert_all` (boolean, optional): Present if the operation was a "revert all" operation.
|
|
905
1077
|
* `success` (boolean, mandatory): Whether the revert operation was successful.
|
|
906
1078
|
* `error` (string, optional): Error message if the operation failed.
|
|
907
1079
|
|
|
@@ -23,6 +23,7 @@ from .file_handlers import (
|
|
|
23
23
|
FileCreateHandler,
|
|
24
24
|
FolderCreateHandler,
|
|
25
25
|
FileRenameHandler,
|
|
26
|
+
ContentRequestHandler,
|
|
26
27
|
)
|
|
27
28
|
from .project_state_handlers import (
|
|
28
29
|
ProjectStateFolderExpandHandler,
|
|
@@ -31,6 +32,7 @@ from .project_state_handlers import (
|
|
|
31
32
|
ProjectStateTabCloseHandler,
|
|
32
33
|
ProjectStateSetActiveTabHandler,
|
|
33
34
|
ProjectStateDiffOpenHandler,
|
|
35
|
+
ProjectStateDiffContentHandler,
|
|
34
36
|
ProjectStateGitStageHandler,
|
|
35
37
|
ProjectStateGitUnstageHandler,
|
|
36
38
|
ProjectStateGitRevertHandler,
|
|
@@ -56,6 +58,7 @@ __all__ = [
|
|
|
56
58
|
"FileCreateHandler",
|
|
57
59
|
"FolderCreateHandler",
|
|
58
60
|
"FileRenameHandler",
|
|
61
|
+
"ContentRequestHandler",
|
|
59
62
|
# Project state handlers
|
|
60
63
|
"ProjectStateFolderExpandHandler",
|
|
61
64
|
"ProjectStateFolderCollapseHandler",
|
|
@@ -63,6 +66,7 @@ __all__ = [
|
|
|
63
66
|
"ProjectStateTabCloseHandler",
|
|
64
67
|
"ProjectStateSetActiveTabHandler",
|
|
65
68
|
"ProjectStateDiffOpenHandler",
|
|
69
|
+
"ProjectStateDiffContentHandler",
|
|
66
70
|
"ProjectStateGitStageHandler",
|
|
67
71
|
"ProjectStateGitUnstageHandler",
|
|
68
72
|
"ProjectStateGitRevertHandler",
|
|
@@ -114,11 +114,15 @@ class AsyncHandler(BaseHandler):
|
|
|
114
114
|
response = await self.execute(message)
|
|
115
115
|
logger.info("handler: Command %s executed successfully", self.command_name)
|
|
116
116
|
|
|
117
|
-
#
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
# Handle cases where execute() sends responses directly and returns None
|
|
118
|
+
if response is not None:
|
|
119
|
+
# Extract project_id from response for session targeting
|
|
120
|
+
project_id = response.get("project_id")
|
|
121
|
+
logger.info("handler: %s response project_id=%s, response=%s",
|
|
122
|
+
self.command_name, project_id, response)
|
|
123
|
+
await self.send_response(response, reply_channel, project_id)
|
|
124
|
+
else:
|
|
125
|
+
logger.info("handler: %s handled response transmission directly", self.command_name)
|
|
122
126
|
except Exception as exc:
|
|
123
127
|
logger.exception("handler: Error in async handler %s: %s", self.command_name, exc)
|
|
124
128
|
# Extract project_id from original message for error targeting
|