claude-code-tools 1.21.0__tar.gz → 1.22.0__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.
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/PKG-INFO +1 -1
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/__init__.py +1 -1
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/aichat.py +9 -3
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/export_session.py +60 -2
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/node_menu_ui.py +103 -4
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/search_index.py +79 -15
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/tmux_cli_controller.py +5 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/pyproject.toml +2 -2
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/.gitignore +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/LICENSE +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/README.md +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/action_rpc.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/__init__.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/backends.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/cli.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/config.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/convert.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/discord_bot.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/locking.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/paths.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/registry.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/session.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/store.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/tmux.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/trust.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/claude_continue.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_continue.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_cli.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_fingerprint.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_generation.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_legacy.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_models.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_process.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_reservation.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_retry.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_reuse.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_state.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_supervisor.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_worker.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/config.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/csv2gsheet.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/delete_session.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/dotenv_vault.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/env_safe.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/export_all.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/export_claude_session.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/export_codex_session.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/find_claude_session.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/find_codex_session.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/find_original_session.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/find_session.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/find_trimmed_sessions.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/fix_session.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/gdoc2docx.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/gdoc2md.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/gsheet2csv.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/md2gdoc.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/msg/__init__.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/msg/cli.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/msg/hooks.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/msg/models.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/msg/prompt_detect.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/msg/store.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/msg/watcher.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/port_claude_noise.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/port_claude_to_codex.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/port_codex_flatten.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/port_codex_to_claude.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/port_service.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/resolve_session.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/resolve_session_names.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/resolve_session_render.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/session_lineage.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/session_menu.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/session_menu_cli.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/session_resolution.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/session_utils.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/smart_trim.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/smart_trim_core.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/tmux_execution_helpers.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/tmux_remote_controller.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/trim_in_place.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/trim_session.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/trim_session_claude.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/trim_session_codex.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_contract.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_formatting.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_identity_policy.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_manifest.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_projection.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_rendering.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_snapshots.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_store_backends.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_processes.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_runs.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_store_io.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_validation.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/docs/agent-tunnel-spec.md +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/docs/claude-code-tmux-tutorials.md +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/docs/dot-zshrc.md +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/docs/find-claude-session.md +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/docs/intercom-spec.md +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/docs/lmsh.md +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/docs/local-llm-setup.md +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/docs/msg-phase-a-plan.md +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/docs/msg-plan-v2.md +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/docs/tmux-cli-instructions.md +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/docs/vault-documentation.md +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/hatch_build.py +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/node_ui/action_config.js +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/node_ui/menu.js +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/node_ui/package-lock.json +0 -0
- {claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/node_ui/package.json +0 -0
|
@@ -2710,6 +2710,8 @@ def index_stats(index, cwd, claude_home, codex_home):
|
|
|
2710
2710
|
help='Limit number of results displayed')
|
|
2711
2711
|
@click.option('--no-original', is_flag=True, help='Exclude original sessions')
|
|
2712
2712
|
@click.option('--sub-agent', is_flag=True, help='Include sub-agent sessions (additive)')
|
|
2713
|
+
@click.option('--exec-runs', 'exec_runs', is_flag=True,
|
|
2714
|
+
help='Include headless `codex exec` runs (additive)')
|
|
2713
2715
|
@click.option('--no-trimmed', is_flag=True, help='Exclude trimmed sessions')
|
|
2714
2716
|
@click.option('--no-rollover', is_flag=True, help='Exclude rollover sessions')
|
|
2715
2717
|
@click.option('--live', is_flag=True, help='Show only currently running sessions')
|
|
@@ -2725,14 +2727,14 @@ def index_stats(index, cwd, claude_home, codex_home):
|
|
|
2725
2727
|
help='Output as JSONL for AI agents. Fields per line: session_id, '
|
|
2726
2728
|
'agent, project, branch, cwd, lines, created, modified, '
|
|
2727
2729
|
'first_msg, last_msg, file_path, derivation_type, '
|
|
2728
|
-
'is_sidechain, snippet')
|
|
2730
|
+
'is_sidechain, is_exec_run, snippet')
|
|
2729
2731
|
@click.option('--by-time', 'by_time', is_flag=True,
|
|
2730
2732
|
help='Sort results by last-modified time (default: sort by relevance)')
|
|
2731
2733
|
@click.argument('query', required=False)
|
|
2732
2734
|
def search(
|
|
2733
2735
|
claude_home_arg, codex_home_arg, global_search, filter_dir, filter_branch,
|
|
2734
|
-
num_results, no_original, sub_agent, no_trimmed, no_rollover, live,
|
|
2735
|
-
after, before, agent, json_output, by_time, query
|
|
2736
|
+
num_results, no_original, sub_agent, exec_runs, no_trimmed, no_rollover, live,
|
|
2737
|
+
min_lines, after, before, agent, json_output, by_time, query
|
|
2736
2738
|
):
|
|
2737
2739
|
"""Launch interactive TUI for full-text session search.
|
|
2738
2740
|
|
|
@@ -2828,6 +2830,8 @@ def search(
|
|
|
2828
2830
|
rust_args.append("--no-original")
|
|
2829
2831
|
if sub_agent:
|
|
2830
2832
|
rust_args.append("--sub-agent")
|
|
2833
|
+
if exec_runs:
|
|
2834
|
+
rust_args.append("--exec-runs")
|
|
2831
2835
|
if live:
|
|
2832
2836
|
rust_args.append("--live")
|
|
2833
2837
|
if no_trimmed:
|
|
@@ -3008,6 +3012,8 @@ def search(
|
|
|
3008
3012
|
rust_args.append("--no-original")
|
|
3009
3013
|
if filter_state.get("include_sub"):
|
|
3010
3014
|
rust_args.append("--sub-agent")
|
|
3015
|
+
if filter_state.get("include_exec"):
|
|
3016
|
+
rust_args.append("--exec-runs")
|
|
3011
3017
|
if filter_state.get("include_live_only"):
|
|
3012
3018
|
rust_args.append("--live")
|
|
3013
3019
|
if not filter_state.get("include_trimmed", True):
|
|
@@ -408,6 +408,45 @@ def extract_first_last_messages(
|
|
|
408
408
|
return first_msg, last_msg, first_user_msg
|
|
409
409
|
|
|
410
410
|
|
|
411
|
+
def _is_codex_subagent_payload(payload: dict[str, Any]) -> bool:
|
|
412
|
+
"""Return True when a Codex ``session_meta`` payload describes a sub-agent.
|
|
413
|
+
|
|
414
|
+
Codex names every thread ``rollout-*.jsonl``, so sub-agent threads can only
|
|
415
|
+
be told apart by their spawn metadata. A spawned thread records
|
|
416
|
+
``thread_source: "subagent"``, a ``source`` object keyed by ``subagent``,
|
|
417
|
+
and the id of the thread that spawned it.
|
|
418
|
+
|
|
419
|
+
Args:
|
|
420
|
+
payload: The ``payload`` object of a ``session_meta`` record.
|
|
421
|
+
|
|
422
|
+
Returns:
|
|
423
|
+
True when the payload carries any sub-agent spawn marker.
|
|
424
|
+
"""
|
|
425
|
+
if payload.get("thread_source") == "subagent":
|
|
426
|
+
return True
|
|
427
|
+
source = payload.get("source")
|
|
428
|
+
if isinstance(source, dict) and "subagent" in source:
|
|
429
|
+
return True
|
|
430
|
+
return _nonempty_str(payload.get("parent_thread_id"))
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def _is_codex_exec_payload(payload: dict[str, Any]) -> bool:
|
|
434
|
+
"""Return True when a Codex ``session_meta`` payload describes a headless run.
|
|
435
|
+
|
|
436
|
+
Codex records how a thread was launched: ``"exec"`` for a headless
|
|
437
|
+
``codex exec`` run (typically spawned by an orchestrating agent or script),
|
|
438
|
+
``"cli"`` for the interactive TUI. Sub-agent spawns carry an object here
|
|
439
|
+
instead, and are reported by :func:`_is_codex_subagent_payload`.
|
|
440
|
+
|
|
441
|
+
Args:
|
|
442
|
+
payload: The ``payload`` object of a ``session_meta`` record.
|
|
443
|
+
|
|
444
|
+
Returns:
|
|
445
|
+
True when the thread was launched headlessly.
|
|
446
|
+
"""
|
|
447
|
+
return payload.get("source") == "exec"
|
|
448
|
+
|
|
449
|
+
|
|
411
450
|
def extract_session_metadata(session_file: Path, agent: str) -> dict[str, Any]:
|
|
412
451
|
"""
|
|
413
452
|
Extract metadata from a session JSONL file.
|
|
@@ -425,9 +464,12 @@ def extract_session_metadata(session_file: Path, agent: str) -> dict[str, Any]:
|
|
|
425
464
|
Returns:
|
|
426
465
|
Dict with extracted metadata
|
|
427
466
|
"""
|
|
428
|
-
# Detect sidechain from filename pattern (agent-* prefix)
|
|
467
|
+
# Detect sidechain from filename pattern (agent-* prefix).
|
|
429
468
|
# This is more reliable than checking isSidechain field in JSON,
|
|
430
|
-
# which can be set on individual messages within main sessions
|
|
469
|
+
# which can be set on individual messages within main sessions.
|
|
470
|
+
# Claude sub-agent transcripts are written as agent-*.jsonl; Codex writes
|
|
471
|
+
# every thread as rollout-*.jsonl, so Codex sub-agents are detected from
|
|
472
|
+
# the session_meta record below instead.
|
|
431
473
|
is_sidechain = session_file.name.startswith("agent-")
|
|
432
474
|
|
|
433
475
|
metadata: dict[str, Any] = {
|
|
@@ -438,6 +480,7 @@ def extract_session_metadata(session_file: Path, agent: str) -> dict[str, Any]:
|
|
|
438
480
|
"branch": None,
|
|
439
481
|
"derivation_type": None,
|
|
440
482
|
"is_sidechain": is_sidechain,
|
|
483
|
+
"is_exec_run": False, # Codex: launched headlessly via `codex exec`
|
|
441
484
|
"session_type": None, # "helper" for SDK/headless sessions
|
|
442
485
|
"parent_session_id": None,
|
|
443
486
|
"parent_session_file": None,
|
|
@@ -451,6 +494,13 @@ def extract_session_metadata(session_file: Path, agent: str) -> dict[str, Any]:
|
|
|
451
494
|
# Track session start timestamp from JSON metadata
|
|
452
495
|
session_start_timestamp: str | None = None
|
|
453
496
|
|
|
497
|
+
# A forked Codex rollout replays its ancestors' session_meta records into
|
|
498
|
+
# the same file (1951 of 6880 real rollouts carry more than one, up to 29).
|
|
499
|
+
# Only the first one describes THIS session, so the launch-kind flags are
|
|
500
|
+
# taken from it alone -- otherwise an interactive fork of a headless
|
|
501
|
+
# ancestor inherits is_exec_run and vanishes from default search results.
|
|
502
|
+
codex_meta_seen = False
|
|
503
|
+
|
|
454
504
|
try:
|
|
455
505
|
with open(
|
|
456
506
|
session_file, "r", encoding="utf-8", errors="replace"
|
|
@@ -554,6 +604,12 @@ def extract_session_metadata(session_file: Path, agent: str) -> dict[str, Any]:
|
|
|
554
604
|
metadata["cwd"] = payload["cwd"]
|
|
555
605
|
if _nonempty_str(payload.get("id")):
|
|
556
606
|
metadata["session_id"] = payload["id"]
|
|
607
|
+
if not codex_meta_seen:
|
|
608
|
+
codex_meta_seen = True
|
|
609
|
+
if _is_codex_subagent_payload(payload):
|
|
610
|
+
metadata["is_sidechain"] = True
|
|
611
|
+
if _is_codex_exec_payload(payload):
|
|
612
|
+
metadata["is_exec_run"] = True
|
|
557
613
|
if session_start_timestamp is None and _nonempty_str(
|
|
558
614
|
data.get("timestamp")
|
|
559
615
|
):
|
|
@@ -701,6 +757,8 @@ def generate_yaml_frontmatter(metadata: dict[str, Any]) -> str:
|
|
|
701
757
|
yaml_data["derivation_type"] = metadata["derivation_type"]
|
|
702
758
|
if metadata.get("is_sidechain"):
|
|
703
759
|
yaml_data["is_sidechain"] = metadata["is_sidechain"]
|
|
760
|
+
if metadata.get("is_exec_run"):
|
|
761
|
+
yaml_data["is_exec_run"] = metadata["is_exec_run"]
|
|
704
762
|
if metadata.get("parent_session_id"):
|
|
705
763
|
yaml_data["parent_session_id"] = metadata["parent_session_id"]
|
|
706
764
|
if metadata.get("parent_session_file"):
|
|
@@ -9,6 +9,8 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
11
|
import os
|
|
12
|
+
import shlex
|
|
13
|
+
import shutil
|
|
12
14
|
import subprocess
|
|
13
15
|
import sys
|
|
14
16
|
import tempfile
|
|
@@ -17,11 +19,90 @@ from typing import Any, Callable, Dict, Iterable, List
|
|
|
17
19
|
|
|
18
20
|
SessionDict = Dict[str, Any]
|
|
19
21
|
|
|
22
|
+
#: Runtime npm packages ``menu.js`` imports directly. A checkout that is
|
|
23
|
+
#: missing any of them cannot render a menu, so we check before spawning Node
|
|
24
|
+
#: rather than letting Node print a raw ``ERR_MODULE_NOT_FOUND`` stack trace.
|
|
25
|
+
NODE_UI_REQUIRED_PACKAGES = (
|
|
26
|
+
"chalk",
|
|
27
|
+
"figures",
|
|
28
|
+
"ink",
|
|
29
|
+
"ink-select-input",
|
|
30
|
+
"meow",
|
|
31
|
+
"react",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _node_ui_dir() -> Path:
|
|
36
|
+
"""Return the directory holding the bundled Node UI."""
|
|
37
|
+
here = Path(__file__).resolve()
|
|
38
|
+
return here.parent.parent / "node_ui"
|
|
39
|
+
|
|
20
40
|
|
|
21
41
|
def _node_script_path() -> Path:
|
|
22
42
|
"""Return path to the bundled Node UI script."""
|
|
23
|
-
|
|
24
|
-
|
|
43
|
+
return _node_ui_dir() / "menu.js"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _missing_node_ui_packages(node_ui_dir: Path | None = None) -> List[str]:
|
|
47
|
+
"""Return the required Node UI packages that are not installed.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
node_ui_dir: Directory to inspect. Defaults to the bundled ``node_ui``.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Names of missing packages, empty when every requirement is present.
|
|
54
|
+
"""
|
|
55
|
+
root = node_ui_dir if node_ui_dir is not None else _node_ui_dir()
|
|
56
|
+
node_modules = root / "node_modules"
|
|
57
|
+
if not node_modules.is_dir():
|
|
58
|
+
return list(NODE_UI_REQUIRED_PACKAGES)
|
|
59
|
+
return [
|
|
60
|
+
name
|
|
61
|
+
for name in NODE_UI_REQUIRED_PACKAGES
|
|
62
|
+
if not (node_modules / name).is_dir()
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _quote_path(path: Path) -> str:
|
|
67
|
+
"""Quote a path for the shell the user is most likely pasting into.
|
|
68
|
+
|
|
69
|
+
``shlex.quote`` emits POSIX single quotes, which ``cmd.exe`` treats as
|
|
70
|
+
literal characters, so a Windows path containing spaces would be split.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
path: Path to embed in a suggested command line.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
The path, quoted only when it needs to be.
|
|
77
|
+
"""
|
|
78
|
+
text = str(path)
|
|
79
|
+
if os.name == "nt":
|
|
80
|
+
# cmd.exe splits on & | ^ < > as well as spaces, so always quote.
|
|
81
|
+
return f'"{text}"'
|
|
82
|
+
return shlex.quote(text)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _no_node_message() -> str:
|
|
86
|
+
"""Build the message shown when the Node runtime is unavailable."""
|
|
87
|
+
return (
|
|
88
|
+
"aichat could not start its interactive menu: 'node' was not found "
|
|
89
|
+
"on PATH.\nInstall Node.js (>=18) and try again."
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _node_ui_setup_message(missing: List[str], node_ui_dir: Path) -> str:
|
|
94
|
+
"""Build an actionable message for a Node UI with missing dependencies."""
|
|
95
|
+
return (
|
|
96
|
+
"aichat could not start its interactive menu: the Node UI "
|
|
97
|
+
f"dependencies are missing ({', '.join(missing)}).\n"
|
|
98
|
+
f"Expected them in: {node_ui_dir / 'node_modules'}\n"
|
|
99
|
+
"\n"
|
|
100
|
+
"This happens when aichat runs from a source checkout (an editable\n"
|
|
101
|
+
"install) whose Node dependencies were never installed. Install them\n"
|
|
102
|
+
"with either of:\n"
|
|
103
|
+
f" npm ci --prefix {_quote_path(node_ui_dir)} --omit=dev\n"
|
|
104
|
+
" make install # from that checkout (needs GNU make)\n"
|
|
105
|
+
)
|
|
25
106
|
|
|
26
107
|
|
|
27
108
|
def _write_payload(
|
|
@@ -63,15 +144,33 @@ def _write_payload(
|
|
|
63
144
|
def _run_node(data_path: Path, out_path: Path, stderr_mode: bool = False) -> int:
|
|
64
145
|
"""Invoke the Node UI process.
|
|
65
146
|
|
|
66
|
-
Returns the process return code.
|
|
147
|
+
Returns the process return code. A missing Node runtime or missing Node UI
|
|
148
|
+
dependencies are reported as an actionable message and return code 1.
|
|
67
149
|
"""
|
|
150
|
+
# Check the runtime before its packages: on a machine without Node, telling
|
|
151
|
+
# the user to run npm is useless advice.
|
|
152
|
+
if shutil.which("node") is None:
|
|
153
|
+
print(_no_node_message(), file=sys.stderr)
|
|
154
|
+
return 1
|
|
155
|
+
|
|
156
|
+
node_ui_dir = _node_ui_dir()
|
|
157
|
+
missing = _missing_node_ui_packages(node_ui_dir)
|
|
158
|
+
if missing:
|
|
159
|
+
print(_node_ui_setup_message(missing, node_ui_dir), file=sys.stderr)
|
|
160
|
+
return 1
|
|
161
|
+
|
|
68
162
|
script = _node_script_path()
|
|
69
163
|
cmd = ["node", str(script), "--data", str(data_path), "--out", str(out_path)]
|
|
70
164
|
env = os.environ.copy()
|
|
71
165
|
if stderr_mode:
|
|
72
166
|
env["NODE_UI_STDERR"] = "1"
|
|
73
167
|
|
|
74
|
-
|
|
168
|
+
try:
|
|
169
|
+
proc = subprocess.run(cmd, env=env)
|
|
170
|
+
except FileNotFoundError:
|
|
171
|
+
# Node disappeared between the check above and the spawn.
|
|
172
|
+
print(_no_node_message(), file=sys.stderr)
|
|
173
|
+
return 1
|
|
75
174
|
return proc.returncode
|
|
76
175
|
|
|
77
176
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import math
|
|
5
|
+
import os
|
|
5
6
|
import shutil
|
|
6
7
|
import sys
|
|
7
8
|
from dataclasses import dataclass
|
|
@@ -14,12 +15,26 @@ from claude_code_tools.export_session import _is_meta_user_message
|
|
|
14
15
|
from claude_code_tools.session_utils import is_valid_session
|
|
15
16
|
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
#: Revision of the indexing logic itself. Bump this whenever a change alters
|
|
19
|
+
#: what gets stored for a session (new field, corrected detection), so existing
|
|
20
|
+
#: indexes rebuild even when the package version has not changed -- an editable
|
|
21
|
+
#: install keeps the same version across every code change.
|
|
22
|
+
#: rev 2: Codex sub-agent (is_sidechain) detection.
|
|
23
|
+
#: rev 3: headless `codex exec` run (is_exec_run) detection.
|
|
24
|
+
#: rev 4: launch flags read from the session's own session_meta record only.
|
|
25
|
+
INDEX_LOGIC_REVISION = 4
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _get_index_version() -> str:
|
|
29
|
+
"""Return the index identity: package version plus indexing-logic revision.
|
|
30
|
+
|
|
31
|
+
A mismatch against the stored value triggers a full rebuild.
|
|
32
|
+
"""
|
|
19
33
|
try:
|
|
20
|
-
|
|
34
|
+
version = get_pkg_version("claude-code-tools")
|
|
21
35
|
except Exception:
|
|
22
|
-
|
|
36
|
+
version = "unknown"
|
|
37
|
+
return f"{version}+idx{INDEX_LOGIC_REVISION}"
|
|
23
38
|
|
|
24
39
|
# Lazy imports to allow module to load even if deps not installed
|
|
25
40
|
try:
|
|
@@ -129,9 +144,18 @@ class IndexState:
|
|
|
129
144
|
or stat.st_size != stored.get("size")
|
|
130
145
|
)
|
|
131
146
|
|
|
132
|
-
def mark_indexed(
|
|
133
|
-
|
|
134
|
-
|
|
147
|
+
def mark_indexed(
|
|
148
|
+
self, file_path: Path, stat_result: Optional[os.stat_result] = None
|
|
149
|
+
):
|
|
150
|
+
"""Mark file as indexed.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
file_path: Session file that was processed.
|
|
154
|
+
stat_result: File state to record. Pass the state captured BEFORE
|
|
155
|
+
reading the file, so content appended while it was being read
|
|
156
|
+
is not recorded as already indexed. Defaults to current state.
|
|
157
|
+
"""
|
|
158
|
+
stat = stat_result if stat_result is not None else file_path.stat()
|
|
135
159
|
self.indexed_files[str(file_path)] = {
|
|
136
160
|
"mtime": stat.st_mtime,
|
|
137
161
|
"size": stat.st_size,
|
|
@@ -183,6 +207,9 @@ class SessionIndex:
|
|
|
183
207
|
# Session type fields (for filtering in TUI)
|
|
184
208
|
self.schema_builder.add_text_field("derivation_type", stored=True)
|
|
185
209
|
self.schema_builder.add_text_field("is_sidechain", stored=True) # "true"/"false"
|
|
210
|
+
# Codex sessions launched headlessly via `codex exec` (agent-spawned
|
|
211
|
+
# workers). Excluded from results by default, like sub-agents.
|
|
212
|
+
self.schema_builder.add_text_field("is_exec_run", stored=True) # "true"/"false"
|
|
186
213
|
|
|
187
214
|
# Claude home field (for filtering by source Claude home directory)
|
|
188
215
|
# Use "raw" tokenizer so paths are indexed as single tokens for exact matching
|
|
@@ -201,7 +228,7 @@ class SessionIndex:
|
|
|
201
228
|
|
|
202
229
|
# Check index version - rebuild if package version changed
|
|
203
230
|
version_file = self.index_path / "VERSION"
|
|
204
|
-
current_version =
|
|
231
|
+
current_version = _get_index_version()
|
|
205
232
|
needs_rebuild = False
|
|
206
233
|
|
|
207
234
|
if version_file.exists():
|
|
@@ -209,17 +236,23 @@ class SessionIndex:
|
|
|
209
236
|
stored_version = version_file.read_text().strip()
|
|
210
237
|
if stored_version != current_version:
|
|
211
238
|
needs_rebuild = True
|
|
239
|
+
# stderr, not stdout: `aichat search --json` emits JSONL on
|
|
240
|
+
# stdout, and an upgrade notice there is invalid output.
|
|
212
241
|
print(
|
|
213
|
-
f"
|
|
214
|
-
"rebuilding index..."
|
|
242
|
+
f"Index version changed ({stored_version} -> {current_version}), "
|
|
243
|
+
"rebuilding index...",
|
|
244
|
+
file=sys.stderr,
|
|
215
245
|
)
|
|
216
246
|
except IOError:
|
|
217
247
|
needs_rebuild = True
|
|
218
|
-
print("Index version file corrupted, rebuilding...")
|
|
248
|
+
print("Index version file corrupted, rebuilding...", file=sys.stderr)
|
|
219
249
|
elif (self.index_path / "meta.json").exists():
|
|
220
250
|
# Index exists but no VERSION file - legacy index, rebuild
|
|
221
251
|
needs_rebuild = True
|
|
222
|
-
print(
|
|
252
|
+
print(
|
|
253
|
+
"Upgrading index to versioned format, rebuilding...",
|
|
254
|
+
file=sys.stderr,
|
|
255
|
+
)
|
|
223
256
|
|
|
224
257
|
if needs_rebuild:
|
|
225
258
|
# Clear index directory contents (but keep the directory itself)
|
|
@@ -336,6 +369,10 @@ class SessionIndex:
|
|
|
336
369
|
"is_sidechain",
|
|
337
370
|
"true" if metadata.get("is_sidechain") else "false"
|
|
338
371
|
)
|
|
372
|
+
doc.add_text(
|
|
373
|
+
"is_exec_run",
|
|
374
|
+
"true" if metadata.get("is_exec_run") else "false"
|
|
375
|
+
)
|
|
339
376
|
|
|
340
377
|
# Custom title (from /rename command)
|
|
341
378
|
doc.add_text("custom_title", metadata.get("customTitle", "") or "")
|
|
@@ -424,6 +461,10 @@ class SessionIndex:
|
|
|
424
461
|
"is_sidechain",
|
|
425
462
|
"true" if metadata.get("is_sidechain") else "false"
|
|
426
463
|
)
|
|
464
|
+
doc.add_text(
|
|
465
|
+
"is_exec_run",
|
|
466
|
+
"true" if metadata.get("is_exec_run") else "false"
|
|
467
|
+
)
|
|
427
468
|
|
|
428
469
|
# Custom title (from /rename command)
|
|
429
470
|
doc.add_text("custom_title", metadata.get("customTitle", "") or "")
|
|
@@ -685,6 +726,7 @@ class SessionIndex:
|
|
|
685
726
|
"created": metadata.get("created", "") or "",
|
|
686
727
|
"modified": metadata.get("modified", "") or "",
|
|
687
728
|
"is_sidechain": metadata.get("is_sidechain", False),
|
|
729
|
+
"is_exec_run": metadata.get("is_exec_run", False),
|
|
688
730
|
"derivation_type": metadata.get("derivation_type", "") or "",
|
|
689
731
|
"session_type": metadata.get("session_type"),
|
|
690
732
|
"customTitle": metadata.get("customTitle", "") or "",
|
|
@@ -753,11 +795,21 @@ class SessionIndex:
|
|
|
753
795
|
stats["skipped"] += 1
|
|
754
796
|
continue
|
|
755
797
|
|
|
798
|
+
# Snapshot the file state BEFORE reading it. A live session can
|
|
799
|
+
# append while we read; recording the post-read state would mark
|
|
800
|
+
# that new content as already indexed and hide the session until
|
|
801
|
+
# its next write.
|
|
802
|
+
try:
|
|
803
|
+
file_stat = jsonl_path.stat()
|
|
804
|
+
except OSError:
|
|
805
|
+
stats["skipped"] += 1
|
|
806
|
+
continue
|
|
807
|
+
|
|
756
808
|
# Skip invalid sessions (metadata-only files like file-history-snapshot)
|
|
757
809
|
if not is_valid_session(jsonl_path):
|
|
758
810
|
stats["skipped"] += 1
|
|
759
811
|
# Mark as indexed so we don't re-check next time
|
|
760
|
-
self.state.mark_indexed(jsonl_path)
|
|
812
|
+
self.state.mark_indexed(jsonl_path, file_stat)
|
|
761
813
|
continue
|
|
762
814
|
|
|
763
815
|
# Parse JSONL file
|
|
@@ -768,6 +820,10 @@ class SessionIndex:
|
|
|
768
820
|
reason = parsed.get("_skip_reason", "unknown")
|
|
769
821
|
if reason == "empty":
|
|
770
822
|
stats["empty"] += 1
|
|
823
|
+
# Mark as indexed so we don't re-parse it every launch.
|
|
824
|
+
# If the session later gains messages its mtime/size
|
|
825
|
+
# changes, which re-triggers indexing.
|
|
826
|
+
self.state.mark_indexed(jsonl_path, file_stat)
|
|
771
827
|
elif reason == "parse_error":
|
|
772
828
|
stats["parse_error"] += 1
|
|
773
829
|
continue
|
|
@@ -781,7 +837,7 @@ class SessionIndex:
|
|
|
781
837
|
if metadata.get("session_type") == "helper":
|
|
782
838
|
stats["skipped"] += 1
|
|
783
839
|
# Mark as indexed so we don't re-check next time
|
|
784
|
-
self.state.mark_indexed(jsonl_path)
|
|
840
|
+
self.state.mark_indexed(jsonl_path, file_stat)
|
|
785
841
|
continue
|
|
786
842
|
|
|
787
843
|
# Skip sessions run from inside claude_home or codex_home directories
|
|
@@ -791,6 +847,10 @@ class SessionIndex:
|
|
|
791
847
|
or (codex_home_str and cwd.startswith(codex_home_str))
|
|
792
848
|
):
|
|
793
849
|
stats["skipped"] += 1
|
|
850
|
+
# Deliberately NOT recorded in the index state: this exclusion
|
|
851
|
+
# depends on the claude_home/codex_home passed on the command
|
|
852
|
+
# line, so caching it would keep the session out of the index
|
|
853
|
+
# after a later run with different homes.
|
|
794
854
|
continue
|
|
795
855
|
|
|
796
856
|
try:
|
|
@@ -829,6 +889,10 @@ class SessionIndex:
|
|
|
829
889
|
"is_sidechain",
|
|
830
890
|
"true" if metadata.get("is_sidechain") else "false"
|
|
831
891
|
)
|
|
892
|
+
doc.add_text(
|
|
893
|
+
"is_exec_run",
|
|
894
|
+
"true" if metadata.get("is_exec_run") else "false"
|
|
895
|
+
)
|
|
832
896
|
|
|
833
897
|
# Custom title (from /rename command)
|
|
834
898
|
doc.add_text("custom_title", metadata.get("customTitle", "") or "")
|
|
@@ -846,7 +910,7 @@ class SessionIndex:
|
|
|
846
910
|
doc.add_text("content", parsed["content"])
|
|
847
911
|
|
|
848
912
|
writer.add_document(doc)
|
|
849
|
-
self.state.mark_indexed(jsonl_path)
|
|
913
|
+
self.state.mark_indexed(jsonl_path, file_stat)
|
|
850
914
|
stats["indexed"] += 1
|
|
851
915
|
except Exception:
|
|
852
916
|
stats["failed"] += 1
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/tmux_cli_controller.py
RENAMED
|
@@ -254,6 +254,11 @@ class TmuxCLIController:
|
|
|
254
254
|
for line in output.split('\n'):
|
|
255
255
|
if line:
|
|
256
256
|
parts = line.split('|')
|
|
257
|
+
# tmux emits six fields; anything shorter is not a pane line
|
|
258
|
+
# (an error string, a truncated read) and is skipped rather
|
|
259
|
+
# than indexed into.
|
|
260
|
+
if len(parts) < 5:
|
|
261
|
+
continue
|
|
257
262
|
pane_id = parts[0]
|
|
258
263
|
panes.append({
|
|
259
264
|
'id': pane_id,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "claude-code-tools"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.22.0"
|
|
4
4
|
description = "Collection of tools for working with Claude Code"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -111,7 +111,7 @@ markers = [
|
|
|
111
111
|
|
|
112
112
|
[tool.commitizen]
|
|
113
113
|
name = "cz_conventional_commits"
|
|
114
|
-
version = "1.
|
|
114
|
+
version = "1.22.0"
|
|
115
115
|
tag_format = "v$version"
|
|
116
116
|
version_files = [
|
|
117
117
|
"pyproject.toml:version",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/__init__.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/backends.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/config.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/convert.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/discord_bot.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/locking.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/paths.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/registry.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/session.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/store.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/tmux.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/agent_tunnel/trust.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_fingerprint.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_generation.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_legacy.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_models.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_process.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_reservation.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_retry.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_reuse.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_state.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_supervisor.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/codex_server_worker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/export_claude_session.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/export_codex_session.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/find_claude_session.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/find_codex_session.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/find_original_session.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/find_trimmed_sessions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/msg/prompt_detect.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/port_claude_noise.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/port_claude_to_codex.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/port_codex_flatten.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/port_codex_to_claude.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/resolve_session_names.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/resolve_session_render.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/session_resolution.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/tmux_execution_helpers.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/tmux_remote_controller.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/trim_session_claude.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/trim_session_codex.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_contract.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_formatting.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_manifest.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_projection.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_rendering.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_cli_snapshots.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_processes.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_store_io.py
RENAMED
|
File without changes
|
{claude_code_tools-1.21.0 → claude_code_tools-1.22.0}/claude_code_tools/workflow_validation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|