claude-code-tools 1.16.1__tar.gz → 1.16.2__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 (114) hide show
  1. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/PKG-INFO +6 -5
  2. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/README.md +5 -4
  3. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/__init__.py +1 -1
  4. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/codex_server_models.py +16 -10
  5. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_cli.py +5 -5
  6. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_cli_contract.py +2 -0
  7. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_cli_rendering.py +31 -6
  8. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_cli_snapshots.py +21 -0
  9. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_validation.py +1 -0
  10. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/pyproject.toml +2 -2
  11. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/.gitignore +0 -0
  12. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/LICENSE +0 -0
  13. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/action_rpc.py +0 -0
  14. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/__init__.py +0 -0
  15. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/backends.py +0 -0
  16. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/cli.py +0 -0
  17. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/config.py +0 -0
  18. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/convert.py +0 -0
  19. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/discord_bot.py +0 -0
  20. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/locking.py +0 -0
  21. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/paths.py +0 -0
  22. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/registry.py +0 -0
  23. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/session.py +0 -0
  24. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/store.py +0 -0
  25. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/tmux.py +0 -0
  26. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/agent_tunnel/trust.py +0 -0
  27. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/aichat.py +0 -0
  28. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/claude_continue.py +0 -0
  29. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/codex_continue.py +0 -0
  30. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/codex_server.py +0 -0
  31. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/codex_server_cli.py +0 -0
  32. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/codex_server_fingerprint.py +0 -0
  33. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/codex_server_generation.py +0 -0
  34. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/codex_server_process.py +0 -0
  35. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/codex_server_reuse.py +0 -0
  36. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/codex_server_supervisor.py +0 -0
  37. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/codex_server_worker.py +0 -0
  38. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/config.py +0 -0
  39. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/csv2gsheet.py +0 -0
  40. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/delete_session.py +0 -0
  41. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/dotenv_vault.py +0 -0
  42. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/env_safe.py +0 -0
  43. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/export_all.py +0 -0
  44. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/export_claude_session.py +0 -0
  45. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/export_codex_session.py +0 -0
  46. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/export_session.py +0 -0
  47. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/find_claude_session.py +0 -0
  48. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/find_codex_session.py +0 -0
  49. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/find_original_session.py +0 -0
  50. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/find_session.py +0 -0
  51. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/find_trimmed_sessions.py +0 -0
  52. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/fix_session.py +0 -0
  53. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/gdoc2docx.py +0 -0
  54. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/gdoc2md.py +0 -0
  55. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/gsheet2csv.py +0 -0
  56. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/md2gdoc.py +0 -0
  57. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/msg/__init__.py +0 -0
  58. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/msg/cli.py +0 -0
  59. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/msg/hooks.py +0 -0
  60. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/msg/models.py +0 -0
  61. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/msg/prompt_detect.py +0 -0
  62. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/msg/store.py +0 -0
  63. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/msg/watcher.py +0 -0
  64. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/node_menu_ui.py +0 -0
  65. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/search_index.py +0 -0
  66. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/session_lineage.py +0 -0
  67. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/session_menu.py +0 -0
  68. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/session_menu_cli.py +0 -0
  69. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/session_utils.py +0 -0
  70. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/smart_trim.py +0 -0
  71. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/smart_trim_core.py +0 -0
  72. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/tmux_cli_controller.py +0 -0
  73. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/tmux_execution_helpers.py +0 -0
  74. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/tmux_remote_controller.py +0 -0
  75. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/trim_in_place.py +0 -0
  76. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/trim_session.py +0 -0
  77. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/trim_session_claude.py +0 -0
  78. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/trim_session_codex.py +0 -0
  79. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_cli_formatting.py +0 -0
  80. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_cli_identity_policy.py +0 -0
  81. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_cli_manifest.py +0 -0
  82. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_cli_projection.py +0 -0
  83. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_cli_store_backends.py +0 -0
  84. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_processes.py +0 -0
  85. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_runs.py +0 -0
  86. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/claude_code_tools/workflow_store_io.py +0 -0
  87. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/agent-tunnel-spec.md +0 -0
  88. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/ai-agent-writing-skills.md +0 -0
  89. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/cc-codex-instructions.md +0 -0
  90. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/claude-code-chutes.md +0 -0
  91. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/claude-code-tmux-tutorials.md +0 -0
  92. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/dot-zshrc.md +0 -0
  93. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/ensemble-ideas.md +0 -0
  94. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/example-with-images.md +0 -0
  95. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/find-claude-session.md +0 -0
  96. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/intercom-spec.md +0 -0
  97. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/linked-in-20260102.md +0 -0
  98. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/lmsh.md +0 -0
  99. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/local-llm-setup.md +0 -0
  100. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/msg-phase-a-plan.md +0 -0
  101. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/msg-plan-v2.md +0 -0
  102. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/paper-writing-style-transfer-tools.md +0 -0
  103. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/reddit-aichat-resume-v2.md +0 -0
  104. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/reddit-aichat-resume.md +0 -0
  105. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/reddit-aichat.md +0 -0
  106. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/reddit-post.md +0 -0
  107. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/rollover-details.md +0 -0
  108. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/tmux-cli-instructions.md +0 -0
  109. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/docs/vault-documentation.md +0 -0
  110. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/hatch_build.py +0 -0
  111. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/node_ui/action_config.js +0 -0
  112. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/node_ui/menu.js +0 -0
  113. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/node_ui/package-lock.json +0 -0
  114. {claude_code_tools-1.16.1 → claude_code_tools-1.16.2}/node_ui/package.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-code-tools
3
- Version: 1.16.1
3
+ Version: 1.16.2
4
4
  Summary: Collection of tools for working with Claude Code
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.11
@@ -115,10 +115,11 @@ codex-workflows show RUN_ID
115
115
  codex-workflows --all
116
116
  ```
117
117
 
118
- The default list contains only active workflows. Use `--all` to include
119
- completed and diagnostic history. The command reads durable workflow state and
120
- process metadata. It never changes a run, sends a signal, repairs state, or
121
- launches an agent. See the
118
+ The default list contains only active workflows and identifies the project
119
+ folder from which each workflow was launched. Use `show RUN_ID` for its full
120
+ working directory, or `--all` to include completed and diagnostic history. The
121
+ command reads durable workflow state and process metadata. It never changes a
122
+ run, sends a signal, repairs state, or launches an agent. See the
122
123
  [codex-workflows reference][codex-workflows-reference] for filters, JSON output,
123
124
  and the complete versioned schema.
124
125
 
@@ -89,10 +89,11 @@ codex-workflows show RUN_ID
89
89
  codex-workflows --all
90
90
  ```
91
91
 
92
- The default list contains only active workflows. Use `--all` to include
93
- completed and diagnostic history. The command reads durable workflow state and
94
- process metadata. It never changes a run, sends a signal, repairs state, or
95
- launches an agent. See the
92
+ The default list contains only active workflows and identifies the project
93
+ folder from which each workflow was launched. Use `show RUN_ID` for its full
94
+ working directory, or `--all` to include completed and diagnostic history. The
95
+ command reads durable workflow state and process metadata. It never changes a
96
+ run, sends a signal, repairs state, or launches an agent. See the
96
97
  [codex-workflows reference][codex-workflows-reference] for filters, JSON output,
97
98
  and the complete versioned schema.
98
99
 
@@ -1,3 +1,3 @@
1
1
  """Claude Code Tools - Collection of utilities for Claude Code."""
2
2
 
3
- __version__ = "1.16.1"
3
+ __version__ = "1.16.2"
@@ -444,7 +444,7 @@ def clear_current_generation(base: ServerPaths) -> None:
444
444
 
445
445
 
446
446
  def all_server_paths(base: ServerPaths) -> list[ServerPaths]:
447
- """Return bounded helper generations eligible for explicit cleanup."""
447
+ """Return bounded helper generations retaining state or a socket."""
448
448
  info = _lstat(base.runtime_dir)
449
449
  if info is None:
450
450
  return [base]
@@ -474,12 +474,12 @@ def all_server_paths(base: ServerPaths) -> list[ServerPaths]:
474
474
  raise CodexServerError("app-server runtime changed during inspection")
475
475
  with os.scandir(directory_fd) as entries:
476
476
  for entry in entries:
477
- scanned += 1
478
- if scanned > MAX_SERVER_DIRECTORY_ENTRIES:
479
- raise CodexServerError("too many app-server runtime entries")
480
477
  try:
481
478
  generation = validate_generation(entry.name)
482
479
  except ValueError:
480
+ scanned += 1
481
+ if scanned > MAX_SERVER_DIRECTORY_ENTRIES:
482
+ raise CodexServerError("too many app-server runtime entries")
483
483
  continue
484
484
  try:
485
485
  entry_info = entry.stat(follow_symlinks=False)
@@ -497,6 +497,15 @@ def all_server_paths(base: ServerPaths) -> list[ServerPaths]:
497
497
  raise CodexServerError(
498
498
  f"app-server generation is owned by another user: {entry.name}"
499
499
  )
500
+ paths = paths_for_generation(base, generation)
501
+ if (
502
+ _lstat(paths.state_path) is None
503
+ and _lstat(paths.socket_path) is None
504
+ ):
505
+ continue
506
+ scanned += 1
507
+ if scanned > MAX_SERVER_DIRECTORY_ENTRIES:
508
+ raise CodexServerError("too many app-server runtime entries")
500
509
  generations.append(generation)
501
510
  if len(generations) > MAX_SERVER_GENERATION_DIRECTORIES:
502
511
  raise CodexServerError(
@@ -510,13 +519,10 @@ def all_server_paths(base: ServerPaths) -> list[ServerPaths]:
510
519
  def require_generation_capacity(base: ServerPaths, generation: str) -> None:
511
520
  """Bound retained servers before creating another generation."""
512
521
  target = paths_for_generation(base, generation)
513
- if _lstat(target.runtime_dir) is not None:
522
+ retained = all_server_paths(base)[1:]
523
+ if any(paths.generation == target.generation for paths in retained):
514
524
  return
515
- retained = sum(
516
- _lstat(paths.state_path) is not None or _lstat(paths.socket_path) is not None
517
- for paths in all_server_paths(base)[1:]
518
- )
519
- if retained >= MAX_SERVER_GENERATIONS:
525
+ if len(retained) >= MAX_SERVER_GENERATIONS:
520
526
  raise CodexServerError(
521
527
  "app-server generation limit reached; exit callback-ready sessions "
522
528
  "and run `codex-server stop --force` before launching another"
@@ -570,7 +570,7 @@ def _finite_refresh(
570
570
  help=(
571
571
  "Observe durable dynamic-workflow runs in the global cross-project "
572
572
  "store without changing them. With no subcommand, list active runs, "
573
- "including unverifiable nonterminal runs."
573
+ "including their launch projects and unverifiable nonterminal runs."
574
574
  ),
575
575
  )
576
576
  @_status_option
@@ -580,7 +580,7 @@ def _finite_refresh(
580
580
  "--json",
581
581
  "json_output",
582
582
  is_flag=True,
583
- help="Emit versioned list JSON.",
583
+ help="Emit versioned list JSON, including each launch directory.",
584
584
  )
585
585
  @click.option(
586
586
  "--no-color",
@@ -754,8 +754,8 @@ def watch(
754
754
 
755
755
  @cli.command(
756
756
  help=(
757
- "Show detailed state for RUN_ID from the global store. Put --no-color "
758
- "before show when needed."
757
+ "Show detailed state and the full launch directory for RUN_ID from "
758
+ "the global store. Put --no-color before show when needed."
759
759
  )
760
760
  )
761
761
  @click.argument("run_id")
@@ -763,7 +763,7 @@ def watch(
763
763
  "--json",
764
764
  "json_output",
765
765
  is_flag=True,
766
- help="Emit complete versioned JSON.",
766
+ help="Emit complete versioned JSON, including the launch directory.",
767
767
  )
768
768
  @click.option(
769
769
  "--full",
@@ -40,6 +40,7 @@ RUN_KEYS = frozenset(
40
40
  "status",
41
41
  "agentProgress",
42
42
  "activeWorkers",
43
+ "cwd",
43
44
  "createdAt",
44
45
  "startedAt",
45
46
  "completedAt",
@@ -212,6 +213,7 @@ def run_payload(
212
213
  "status": run.status,
213
214
  "agentProgress": run.progress,
214
215
  "activeWorkers": run.active_workers,
216
+ "cwd": run.cwd,
215
217
  "createdAt": run.created_at,
216
218
  "startedAt": run.started_at,
217
219
  "completedAt": run.completed_at,
@@ -64,6 +64,7 @@ MAX_SHOW_STEPS = 50
64
64
  NARROW_DETAIL_WIDTH = 64
65
65
  ULTRA_NARROW_WIDTH = 4
66
66
  PLAIN_SHOW_MAX_WIDTH = 7
67
+ WIDE_LIST_WIDTH = 140
67
68
 
68
69
 
69
70
  @dataclass(frozen=True)
@@ -74,6 +75,7 @@ class RunRowView:
74
75
  abbreviated_id: str
75
76
  abbreviation_ambiguous: bool
76
77
  workflow_name: str
78
+ project_name: str
77
79
  status: str
78
80
  agents: str
79
81
  agents_with_workers: str
@@ -100,6 +102,11 @@ class RunRowView:
100
102
  maximum=MAX_LIST_NAME_CHARS,
101
103
  full=False,
102
104
  )[0],
105
+ project_name=bounded_text(
106
+ run.project_name,
107
+ maximum=MAX_LIST_NAME_CHARS,
108
+ full=False,
109
+ )[0],
103
110
  status=sanitize(run.status),
104
111
  agents=agents,
105
112
  agents_with_workers=f"{agents} · {active_workers} {worker_label}",
@@ -198,6 +205,7 @@ def _build_runs_table_from_views(
198
205
  records.extend(
199
206
  [
200
207
  Text(view.workflow_name, style="bold"),
208
+ Text(view.project_name, style="cyan"),
201
209
  Text(display_id, style="bright_black"),
202
210
  _compact_run_details(
203
211
  view,
@@ -220,7 +228,11 @@ def _build_runs_table_from_views(
220
228
  identity = Text()
221
229
  identity.append(view.workflow_name, style="bold")
222
230
  identity.append(
223
- f" · {display_id}",
231
+ f"\n{view.project_name}",
232
+ style="cyan",
233
+ )
234
+ identity.append(
235
+ f"\n{display_id}",
224
236
  style="bright_black",
225
237
  )
226
238
  table.add_row(
@@ -234,16 +246,20 @@ def _build_runs_table_from_views(
234
246
  )
235
247
  )
236
248
  return table
237
- if width < 118:
249
+ if width < WIDE_LIST_WIDTH:
238
250
  table.add_column(
239
- "Workflow / run",
240
- width=17,
251
+ "Workflow / project / run",
252
+ width=30,
241
253
  overflow="ellipsis",
242
254
  )
243
255
  table.add_column("State / activity", min_width=20, ratio=3)
244
256
  for view, display_id in zip(views, display_ids, strict=True):
245
257
  identity = Text()
246
258
  identity.append(view.workflow_name, style="bold")
259
+ identity.append(
260
+ f"\n{view.project_name}",
261
+ style="cyan",
262
+ )
247
263
  identity.append(
248
264
  f"\n{display_id}",
249
265
  style="bright_black",
@@ -258,7 +274,12 @@ def _build_runs_table_from_views(
258
274
  )
259
275
  return table
260
276
 
261
- table.add_column("Workflow", ratio=2, max_width=26, overflow="ellipsis")
277
+ table.add_column(
278
+ "Workflow / Project",
279
+ ratio=4,
280
+ max_width=48,
281
+ overflow="ellipsis",
282
+ )
262
283
  table.add_column("Run", width=17, no_wrap=True)
263
284
  table.add_column("Status", width=12, no_wrap=True)
264
285
  table.add_column("Agents", width=8, no_wrap=True)
@@ -268,8 +289,10 @@ def _build_runs_table_from_views(
268
289
  table.add_column("Callback", width=10, no_wrap=True)
269
290
  table.add_column("Error / activity", ratio=3, overflow="ellipsis")
270
291
  for view, display_id in zip(views, display_ids, strict=True):
292
+ identity = Text(view.workflow_name, style="bold")
293
+ identity.append(f"\n{view.project_name}", style="cyan")
271
294
  row: list[RenderableType] = [
272
- Text(view.workflow_name, style="bold"),
295
+ identity,
273
296
  Text(display_id),
274
297
  _status_renderable(view, live),
275
298
  Text(view.agents),
@@ -317,6 +340,8 @@ def _summary_grid(run: RunRecord, now: datetime, width: int, full: bool) -> Tabl
317
340
  values = (
318
341
  ("Run ID", run.run_id),
319
342
  ("Workflow", run.workflow_name),
343
+ ("Project", run.project_name),
344
+ ("Working directory", run.cwd or "—"),
320
345
  ("Workflow path", run.workflow_path or "—"),
321
346
  ("Status", run.status),
322
347
  ("Recorded status", run.recorded_status),
@@ -68,6 +68,7 @@ class RunState:
68
68
 
69
69
  run_id: str | None = None
70
70
  status: str | None = None
71
+ cwd: str | None = None
71
72
  workflow_path: str | None = None
72
73
  created_at: str | None = None
73
74
  updated_at: str | None = None
@@ -113,6 +114,16 @@ def _workflow_name(workflow_path: str | None) -> str:
113
114
  return name[:-3] if name.endswith(".js") else name
114
115
 
115
116
 
117
+ def _project_name(cwd: str | None) -> str:
118
+ """Derive a cross-platform project label from a persisted directory."""
119
+ if not cwd:
120
+ return "unknown"
121
+ normalized = cwd.replace("\\", "/").rstrip("/")
122
+ if not normalized:
123
+ return cwd
124
+ return normalized.rsplit("/", maxsplit=1)[-1]
125
+
126
+
116
127
  @dataclass(frozen=True)
117
128
  class RunRecord:
118
129
  """Immutable typed snapshot plus observational classifications."""
@@ -176,6 +187,16 @@ class RunRecord:
176
187
  """Return a display name derived from the workflow path."""
177
188
  return _workflow_name(self.workflow_path)
178
189
 
190
+ @property
191
+ def cwd(self) -> str | None:
192
+ """Return the persisted workflow launch directory."""
193
+ return self.state.cwd
194
+
195
+ @property
196
+ def project_name(self) -> str:
197
+ """Return a compact project label derived from the launch directory."""
198
+ return _project_name(self.cwd)
199
+
179
200
  @property
180
201
  def created_at(self) -> str | None:
181
202
  """Return the creation timestamp."""
@@ -478,6 +478,7 @@ def parse_state(
478
478
  typed = RunState(
479
479
  run_id=run_id,
480
480
  status=status,
481
+ cwd=string(state, "cwd"),
481
482
  workflow_path=string(state, "workflowPath"),
482
483
  created_at=string(state, "createdAt"),
483
484
  updated_at=string(state, "updatedAt"),
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "claude-code-tools"
3
- version = "1.16.1"
3
+ version = "1.16.2"
4
4
  description = "Collection of tools for working with Claude Code"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -102,7 +102,7 @@ markers = [
102
102
 
103
103
  [tool.commitizen]
104
104
  name = "cz_conventional_commits"
105
- version = "1.16.1"
105
+ version = "1.16.2"
106
106
  tag_format = "v$version"
107
107
  version_files = [
108
108
  "pyproject.toml:version",