cc-session-control 0.7.2__tar.gz → 0.7.4__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.
- {cc_session_control-0.7.2/src/cc_session_control.egg-info → cc_session_control-0.7.4}/PKG-INFO +7 -8
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/README.md +6 -7
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/__init__.py +1 -1
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/cli.py +26 -29
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/config.py +0 -37
- cc_session_control-0.7.4/src/cc_session_control/data/rc.py +456 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/tmux.py +43 -25
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/models.py +27 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_base.py +16 -3
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/rc.py +15 -9
- {cc_session_control-0.7.2 → cc_session_control-0.7.4/src/cc_session_control.egg-info}/PKG-INFO +7 -8
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control.egg-info/SOURCES.txt +1 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_data.py +58 -26
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_rc.py +77 -49
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_smoke.py +0 -7
- cc_session_control-0.7.4/tests/test_trust.py +260 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_views.py +22 -3
- cc_session_control-0.7.2/src/cc_session_control/data/rc.py +0 -324
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/LICENSE +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/pyproject.toml +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/setup.cfg +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/__main__.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/actions/__init__.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/actions/agent_ops.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/actions/resume_list.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/actions/session_ops.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/actions/skill_ops.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/app.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/clipboard.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/__init__.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/cleanup.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/environments.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/liveness.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/proc.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/registry.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/sessions.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/snapshot.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/skill/SKILL.md +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/theme.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/__init__.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_colspec.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_confirm.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_keytable.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_rows.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_session_row.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_sessions_cleanup.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/agents.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/sessions.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control.egg-info/dependency_links.txt +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control.egg-info/entry_points.txt +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control.egg-info/requires.txt +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control.egg-info/top_level.txt +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_agent_ops.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_agents.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_app.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_cleanup.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_cli.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_environments.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_liveness.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_proc.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_registry.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_resume_list.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_sessions.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_skill_ops.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_snapshot.py +0 -0
- {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_theme.py +0 -0
{cc_session_control-0.7.2/src/cc_session_control.egg-info → cc_session_control-0.7.4}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cc-session-control
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.4
|
|
4
4
|
Summary: TUI manager for Claude Code sessions and Remote Control
|
|
5
5
|
Author: dzshzx
|
|
6
6
|
License-Expression: MIT
|
|
@@ -66,8 +66,9 @@ uv tool install --reinstall git+https://github.com/dzshzx/cc-session-control.git
|
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
`csctl` manages the Claude Code state on the machine where it is installed: the
|
|
69
|
-
local `~/.claude`, local `tmux`, and
|
|
70
|
-
each machine whose sessions you want
|
|
69
|
+
local `~/.claude`, local `tmux`, and the projects recorded in the local
|
|
70
|
+
`~/.claude.json`. Install it separately on each machine whose sessions you want
|
|
71
|
+
to manage. For working *on* the code
|
|
71
72
|
instead of using it, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
72
73
|
|
|
73
74
|
## Usage
|
|
@@ -78,9 +79,9 @@ csctl
|
|
|
78
79
|
|
|
79
80
|
# Remote Control management (no TUI)
|
|
80
81
|
csctl rc status # Show all projects and RC status
|
|
81
|
-
csctl rc add . # Add current
|
|
82
|
-
csctl rc add
|
|
83
|
-
csctl rc rm
|
|
82
|
+
csctl rc add . # Add current directory to RC list and start
|
|
83
|
+
csctl rc add ~/code/app # Add by directory path
|
|
84
|
+
csctl rc rm ~/code/app # Remove and stop
|
|
84
85
|
csctl rc up # Start all listed projects
|
|
85
86
|
csctl rc stop all # Stop all RC servers
|
|
86
87
|
csctl rc list # Show auto-start list
|
|
@@ -103,7 +104,6 @@ csctl skill install --force # Replace an existing skill directory
|
|
|
103
104
|
csctl skill uninstall
|
|
104
105
|
|
|
105
106
|
# Options
|
|
106
|
-
csctl --workspace ~/projects # Override workspace root
|
|
107
107
|
csctl --theme light # Force the TUI palette (auto/dark/light)
|
|
108
108
|
csctl --version
|
|
109
109
|
```
|
|
@@ -112,7 +112,6 @@ csctl --version
|
|
|
112
112
|
|
|
113
113
|
| Environment Variable | Default | Description |
|
|
114
114
|
|---|---|---|
|
|
115
|
-
| `CSCTL_WORKSPACE` | `~/workspace` | Workspace root directory |
|
|
116
115
|
| `CSCTL_RC_SESSION` | `rc` | tmux session name for RC servers |
|
|
117
116
|
| `CSCTL_RC_STAGGER` | `2` | Seconds between starting RC servers |
|
|
118
117
|
| `CSCTL_THEME` | `auto` | TUI palette: `auto` (detect the terminal background via OSC 11 / `$COLORFGBG`) / `dark` / `light`. tmux typically doesn't answer the OSC 11 query, so inside tmux `auto` falls back to `dark` — set this (or `--theme`) explicitly for a light terminal |
|
|
@@ -43,8 +43,9 @@ uv tool install --reinstall git+https://github.com/dzshzx/cc-session-control.git
|
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
`csctl` manages the Claude Code state on the machine where it is installed: the
|
|
46
|
-
local `~/.claude`, local `tmux`, and
|
|
47
|
-
each machine whose sessions you want
|
|
46
|
+
local `~/.claude`, local `tmux`, and the projects recorded in the local
|
|
47
|
+
`~/.claude.json`. Install it separately on each machine whose sessions you want
|
|
48
|
+
to manage. For working *on* the code
|
|
48
49
|
instead of using it, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
49
50
|
|
|
50
51
|
## Usage
|
|
@@ -55,9 +56,9 @@ csctl
|
|
|
55
56
|
|
|
56
57
|
# Remote Control management (no TUI)
|
|
57
58
|
csctl rc status # Show all projects and RC status
|
|
58
|
-
csctl rc add . # Add current
|
|
59
|
-
csctl rc add
|
|
60
|
-
csctl rc rm
|
|
59
|
+
csctl rc add . # Add current directory to RC list and start
|
|
60
|
+
csctl rc add ~/code/app # Add by directory path
|
|
61
|
+
csctl rc rm ~/code/app # Remove and stop
|
|
61
62
|
csctl rc up # Start all listed projects
|
|
62
63
|
csctl rc stop all # Stop all RC servers
|
|
63
64
|
csctl rc list # Show auto-start list
|
|
@@ -80,7 +81,6 @@ csctl skill install --force # Replace an existing skill directory
|
|
|
80
81
|
csctl skill uninstall
|
|
81
82
|
|
|
82
83
|
# Options
|
|
83
|
-
csctl --workspace ~/projects # Override workspace root
|
|
84
84
|
csctl --theme light # Force the TUI palette (auto/dark/light)
|
|
85
85
|
csctl --version
|
|
86
86
|
```
|
|
@@ -89,7 +89,6 @@ csctl --version
|
|
|
89
89
|
|
|
90
90
|
| Environment Variable | Default | Description |
|
|
91
91
|
|---|---|---|
|
|
92
|
-
| `CSCTL_WORKSPACE` | `~/workspace` | Workspace root directory |
|
|
93
92
|
| `CSCTL_RC_SESSION` | `rc` | tmux session name for RC servers |
|
|
94
93
|
| `CSCTL_RC_STAGGER` | `2` | Seconds between starting RC servers |
|
|
95
94
|
| `CSCTL_THEME` | `auto` | TUI palette: `auto` (detect the terminal background via OSC 11 / `$COLORFGBG`) / `dark` / `light`. tmux typically doesn't answer the OSC 11 query, so inside tmux `auto` falls back to `dark` — set this (or `--theme`) explicitly for a light terminal |
|
|
@@ -5,7 +5,6 @@ from __future__ import annotations
|
|
|
5
5
|
import argparse
|
|
6
6
|
import os
|
|
7
7
|
import sys
|
|
8
|
-
from pathlib import Path
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
def _build_parser() -> argparse.ArgumentParser:
|
|
@@ -16,7 +15,6 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
16
15
|
description="TUI manager for Claude Code sessions and Remote Control",
|
|
17
16
|
)
|
|
18
17
|
parser.add_argument("--version", action="version", version=f"csctl {__version__}")
|
|
19
|
-
parser.add_argument("--workspace", type=Path, help="Override workspace root directory")
|
|
20
18
|
parser.add_argument(
|
|
21
19
|
"--theme", choices=("auto", "dark", "light"),
|
|
22
20
|
help="TUI palette (default: auto-detect the terminal background; env CSCTL_THEME)",
|
|
@@ -29,12 +27,12 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
29
27
|
rc_sub = rc_parser.add_subparsers(dest="rc_command")
|
|
30
28
|
rc_sub.add_parser("status", help="Show RC status for all projects")
|
|
31
29
|
rc_add = rc_sub.add_parser("add", help="Add project to RC list and start")
|
|
32
|
-
rc_add.add_argument("project", nargs="?", default=".", help="Project
|
|
30
|
+
rc_add.add_argument("project", nargs="?", default=".", help="Project directory (default: current dir)")
|
|
33
31
|
rc_rm = rc_sub.add_parser("rm", help="Remove project from RC list and stop")
|
|
34
|
-
rc_rm.add_argument("project", help="Project
|
|
32
|
+
rc_rm.add_argument("project", help="Project directory")
|
|
35
33
|
rc_sub.add_parser("up", help="Start all listed projects")
|
|
36
34
|
rc_stop = rc_sub.add_parser("stop", help="Stop RC for a project")
|
|
37
|
-
rc_stop.add_argument("target", help="Project
|
|
35
|
+
rc_stop.add_argument("target", help="Project directory or 'all'")
|
|
38
36
|
rc_sub.add_parser("list", help="Show enabled project list")
|
|
39
37
|
|
|
40
38
|
# prune subcommand
|
|
@@ -73,8 +71,6 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
73
71
|
|
|
74
72
|
def _apply_global_flags(args: argparse.Namespace) -> None:
|
|
75
73
|
from .config import cfg
|
|
76
|
-
if args.workspace:
|
|
77
|
-
cfg.workspace = args.workspace
|
|
78
74
|
if args.theme:
|
|
79
75
|
cfg.theme = args.theme
|
|
80
76
|
|
|
@@ -89,36 +85,36 @@ def _cmd_rc(args: argparse.Namespace) -> None:
|
|
|
89
85
|
sub = args.rc_command
|
|
90
86
|
|
|
91
87
|
if sub == "status":
|
|
92
|
-
|
|
88
|
+
from .data.sessions import scan as scan_sessions
|
|
89
|
+
|
|
90
|
+
# Same ordering as the 项目 tab (rc.order_by_activity — single
|
|
91
|
+
# source); costs one transcript scan, like `csctl resume`.
|
|
92
|
+
projects = rc.order_by_activity(rc.scan(), scan_sessions())
|
|
93
93
|
for p in projects:
|
|
94
94
|
icon = {"running": "[running]", "dead": "[dead ]", "stopped": "[stopped]"}.get(p.status, p.status)
|
|
95
95
|
auto = "auto" if p.auto_start else " "
|
|
96
96
|
missing = "" if p.dir_exists else " (directory missing)"
|
|
97
|
-
print(f" {icon} {auto} {p.name}{missing}")
|
|
97
|
+
print(f" {icon} {auto} {p.name} {p.directory}{missing}")
|
|
98
98
|
|
|
99
99
|
elif sub == "add":
|
|
100
|
-
|
|
101
|
-
if
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
else:
|
|
107
|
-
print(f"Current directory is not under {ws}. Specify project name explicitly.")
|
|
108
|
-
sys.exit(1)
|
|
109
|
-
if not rc.is_trusted(proj):
|
|
110
|
-
print(f"Not trusted: {proj} — run 'claude' in that directory first to accept the trust dialog")
|
|
100
|
+
path = os.path.abspath(args.project)
|
|
101
|
+
if not os.path.isdir(path):
|
|
102
|
+
print(f"No such directory: {path}")
|
|
103
|
+
sys.exit(1)
|
|
104
|
+
if not rc.is_trusted(path):
|
|
105
|
+
print(f"Not trusted: {path} — run 'claude' in that directory first to accept the trust dialog")
|
|
111
106
|
sys.exit(1)
|
|
112
|
-
rc.list_add(
|
|
113
|
-
print(f"Added to list: {
|
|
114
|
-
ok = rc.start_one(
|
|
107
|
+
rc.list_add(path)
|
|
108
|
+
print(f"Added to list: {path}")
|
|
109
|
+
ok = rc.start_one(path)
|
|
115
110
|
if ok:
|
|
116
|
-
print(f"Started
|
|
111
|
+
print(f"Started RC server for {path}")
|
|
117
112
|
|
|
118
113
|
elif sub == "rm":
|
|
119
|
-
|
|
120
|
-
rc.
|
|
121
|
-
|
|
114
|
+
path = os.path.abspath(args.project)
|
|
115
|
+
rc.list_rm(path)
|
|
116
|
+
rc.stop_one(path)
|
|
117
|
+
print(f"Removed and stopped: {path}")
|
|
122
118
|
|
|
123
119
|
elif sub == "up":
|
|
124
120
|
enabled = rc.list_enabled()
|
|
@@ -133,8 +129,9 @@ def _cmd_rc(args: argparse.Namespace) -> None:
|
|
|
133
129
|
rc.stop_all()
|
|
134
130
|
print("Stopped all")
|
|
135
131
|
else:
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
path = os.path.abspath(args.target)
|
|
133
|
+
ok = rc.stop_one(path)
|
|
134
|
+
print(f"Stopped {path}" if ok else f"Not running: {path}")
|
|
138
135
|
|
|
139
136
|
elif sub == "list":
|
|
140
137
|
for name in rc.list_enabled():
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import json
|
|
6
5
|
import os
|
|
7
6
|
from pathlib import Path
|
|
8
7
|
|
|
@@ -20,18 +19,6 @@ class Config:
|
|
|
20
19
|
self.cleanup_age_days: int = int(os.environ.get("CSCTL_CLEANUP_AGE_DAYS", "14"))
|
|
21
20
|
# TUI palette: "auto" (detect the terminal background) | "dark" | "light".
|
|
22
21
|
self.theme: str = os.environ.get("CSCTL_THEME", "auto")
|
|
23
|
-
self._workspace: Path | None = None
|
|
24
|
-
|
|
25
|
-
@property
|
|
26
|
-
def workspace(self) -> Path:
|
|
27
|
-
if self._workspace is not None:
|
|
28
|
-
return self._workspace
|
|
29
|
-
self._workspace = _detect_workspace(self.claude_json)
|
|
30
|
-
return self._workspace
|
|
31
|
-
|
|
32
|
-
@workspace.setter
|
|
33
|
-
def workspace(self, value: Path) -> None:
|
|
34
|
-
self._workspace = value
|
|
35
22
|
|
|
36
23
|
@property
|
|
37
24
|
def projects_root(self) -> Path:
|
|
@@ -108,28 +95,4 @@ class Config:
|
|
|
108
95
|
return self.claude_home / "skills"
|
|
109
96
|
|
|
110
97
|
|
|
111
|
-
def _detect_workspace(claude_json: Path) -> Path:
|
|
112
|
-
env = os.environ.get("CSCTL_WORKSPACE")
|
|
113
|
-
if env:
|
|
114
|
-
return Path(env)
|
|
115
|
-
|
|
116
|
-
default = Path.home() / "workspace"
|
|
117
|
-
if default.is_dir():
|
|
118
|
-
return default
|
|
119
|
-
|
|
120
|
-
try:
|
|
121
|
-
with open(claude_json) as f:
|
|
122
|
-
data = json.load(f)
|
|
123
|
-
dirs = [k for k in data.get("projects", {}) if "/" in k]
|
|
124
|
-
if dirs:
|
|
125
|
-
from os.path import commonpath
|
|
126
|
-
common = Path(commonpath(dirs))
|
|
127
|
-
if common.is_dir() and common != Path.home():
|
|
128
|
-
return common
|
|
129
|
-
except Exception:
|
|
130
|
-
pass
|
|
131
|
-
|
|
132
|
-
return Path.cwd()
|
|
133
|
-
|
|
134
|
-
|
|
135
98
|
cfg = Config()
|