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.
Files changed (66) hide show
  1. {cc_session_control-0.7.2/src/cc_session_control.egg-info → cc_session_control-0.7.4}/PKG-INFO +7 -8
  2. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/README.md +6 -7
  3. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/__init__.py +1 -1
  4. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/cli.py +26 -29
  5. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/config.py +0 -37
  6. cc_session_control-0.7.4/src/cc_session_control/data/rc.py +456 -0
  7. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/tmux.py +43 -25
  8. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/models.py +27 -0
  9. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_base.py +16 -3
  10. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/rc.py +15 -9
  11. {cc_session_control-0.7.2 → cc_session_control-0.7.4/src/cc_session_control.egg-info}/PKG-INFO +7 -8
  12. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control.egg-info/SOURCES.txt +1 -0
  13. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_data.py +58 -26
  14. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_rc.py +77 -49
  15. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_smoke.py +0 -7
  16. cc_session_control-0.7.4/tests/test_trust.py +260 -0
  17. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_views.py +22 -3
  18. cc_session_control-0.7.2/src/cc_session_control/data/rc.py +0 -324
  19. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/LICENSE +0 -0
  20. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/pyproject.toml +0 -0
  21. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/setup.cfg +0 -0
  22. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/__main__.py +0 -0
  23. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/actions/__init__.py +0 -0
  24. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/actions/agent_ops.py +0 -0
  25. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/actions/resume_list.py +0 -0
  26. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/actions/session_ops.py +0 -0
  27. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/actions/skill_ops.py +0 -0
  28. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/app.py +0 -0
  29. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/clipboard.py +0 -0
  30. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/__init__.py +0 -0
  31. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/cleanup.py +0 -0
  32. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/environments.py +0 -0
  33. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/liveness.py +0 -0
  34. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/proc.py +0 -0
  35. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/registry.py +0 -0
  36. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/sessions.py +0 -0
  37. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/data/snapshot.py +0 -0
  38. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/skill/SKILL.md +0 -0
  39. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/theme.py +0 -0
  40. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/__init__.py +0 -0
  41. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_colspec.py +0 -0
  42. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_confirm.py +0 -0
  43. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_keytable.py +0 -0
  44. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_rows.py +0 -0
  45. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_session_row.py +0 -0
  46. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/_sessions_cleanup.py +0 -0
  47. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/agents.py +0 -0
  48. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control/views/sessions.py +0 -0
  49. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control.egg-info/dependency_links.txt +0 -0
  50. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control.egg-info/entry_points.txt +0 -0
  51. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control.egg-info/requires.txt +0 -0
  52. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/src/cc_session_control.egg-info/top_level.txt +0 -0
  53. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_agent_ops.py +0 -0
  54. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_agents.py +0 -0
  55. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_app.py +0 -0
  56. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_cleanup.py +0 -0
  57. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_cli.py +0 -0
  58. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_environments.py +0 -0
  59. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_liveness.py +0 -0
  60. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_proc.py +0 -0
  61. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_registry.py +0 -0
  62. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_resume_list.py +0 -0
  63. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_sessions.py +0 -0
  64. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_skill_ops.py +0 -0
  65. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_snapshot.py +0 -0
  66. {cc_session_control-0.7.2 → cc_session_control-0.7.4}/tests/test_theme.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cc-session-control
3
- Version: 0.7.2
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 local workspace. Install it separately on
70
- each machine whose sessions you want to manage. For working *on* the code
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 project to RC list and start
82
- csctl rc add myproject # Add by name
83
- csctl rc rm myproject # Remove and stop
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 local workspace. Install it separately on
47
- each machine whose sessions you want to manage. For working *on* the code
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 project to RC list and start
59
- csctl rc add myproject # Add by name
60
- csctl rc rm myproject # Remove and stop
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 |
@@ -1,3 +1,3 @@
1
1
  """cc-session-control — TUI manager for Claude Code sessions and Remote Control."""
2
2
 
3
- __version__ = "0.7.2"
3
+ __version__ = "0.7.4"
@@ -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 name or '.' for current dir")
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 name")
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 name or 'all'")
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
- projects = rc.scan()
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
- proj = args.project
101
- if proj == ".":
102
- ws = str(rc.cfg.workspace)
103
- cwd = os.getcwd()
104
- if cwd.startswith(ws + "/"):
105
- proj = cwd[len(ws) + 1:].split("/")[0]
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(proj)
113
- print(f"Added to list: {proj}")
114
- ok = rc.start_one(proj)
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: ws/{proj}")
111
+ print(f"Started RC server for {path}")
117
112
 
118
113
  elif sub == "rm":
119
- rc.list_rm(args.project)
120
- rc.stop_one(args.project)
121
- print(f"Removed and stopped: {args.project}")
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
- ok = rc.stop_one(args.target)
137
- print(f"Stopped {args.target}" if ok else f"Not running: {args.target}")
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()