arctx-cli 0.3.1b1__tar.gz → 0.3.1b2__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 (92) hide show
  1. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/.gitignore +2 -1
  2. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/PKG-INFO +2 -2
  3. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/pyproject.toml +2 -2
  4. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/serve.py +2 -4
  5. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/web.py +2 -4
  6. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/context.py +27 -0
  7. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/main.py +45 -3
  8. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/README.md +0 -0
  9. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/__init__.py +0 -0
  10. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/alias.py +0 -0
  11. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/append_batch.py +0 -0
  12. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/__init__.py +0 -0
  13. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/_targets.py +0 -0
  14. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/add.py +0 -0
  15. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/alias_cmd.py +0 -0
  16. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/asset.py +0 -0
  17. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/attach.py +0 -0
  18. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/current.py +0 -0
  19. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/cut.py +0 -0
  20. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/dump.py +0 -0
  21. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/export.py +0 -0
  22. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/ext.py +0 -0
  23. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/graph.py +0 -0
  24. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/guide.py +0 -0
  25. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/init.py +0 -0
  26. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/lane.py +0 -0
  27. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/list.py +0 -0
  28. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/log.py +0 -0
  29. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/migrate.py +0 -0
  30. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/node.py +0 -0
  31. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/outcomes.py +0 -0
  32. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/payload.py +0 -0
  33. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/pr.py +0 -0
  34. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/reachable.py +0 -0
  35. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/reparent.py +0 -0
  36. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/show.py +0 -0
  37. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/step.py +0 -0
  38. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/sync_cmd.py +0 -0
  39. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/trace.py +0 -0
  40. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/uncut.py +0 -0
  41. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/commands/use.py +0 -0
  42. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/__init__.py +0 -0
  43. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/command/__init__.py +0 -0
  44. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/git/__init__.py +0 -0
  45. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/git/branch.py +0 -0
  46. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/git/cherry_pick.py +0 -0
  47. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/git/commit.py +0 -0
  48. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/git/hook.py +0 -0
  49. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/git/merge.py +0 -0
  50. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/git/repo.py +0 -0
  51. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/git/reset.py +0 -0
  52. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/git/revert.py +0 -0
  53. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/git/verify.py +0 -0
  54. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext/git/worktree.py +0 -0
  55. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/ext_registry.py +0 -0
  56. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/paths.py +0 -0
  57. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/payload_builder.py +0 -0
  58. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/src/arctx_cli/workspace.py +0 -0
  59. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/__init__.py +0 -0
  60. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/__init__.py +0 -0
  61. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_alias_cli.py +0 -0
  62. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_alias_resolve.py +0 -0
  63. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_asset_extension_cli.py +0 -0
  64. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_basic.py +0 -0
  65. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_branch.py +0 -0
  66. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_cherry_pick.py +0 -0
  67. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_command_extension.py +0 -0
  68. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_commit.py +0 -0
  69. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_commit_guard.py +0 -0
  70. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_dag_core_cli.py +0 -0
  71. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_ext_cli.py +0 -0
  72. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_git_namespace_cli.py +0 -0
  73. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_git_repo.py +0 -0
  74. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_hook_install.py +0 -0
  75. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_hook_post_merge.py +0 -0
  76. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_hook_post_rewrite.py +0 -0
  77. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_init_extension.py +0 -0
  78. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_init_hooks.py +0 -0
  79. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_init_stag_id.py +0 -0
  80. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_lane.py +0 -0
  81. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_merge.py +0 -0
  82. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_migrate.py +0 -0
  83. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_paths.py +0 -0
  84. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_pr.py +0 -0
  85. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_reset.py +0 -0
  86. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_revert.py +0 -0
  87. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_serve_api.py +0 -0
  88. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_show_history.py +0 -0
  89. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_sync.py +0 -0
  90. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/cli/test_verify.py +0 -0
  91. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/fixtures/__init__.py +0 -0
  92. {arctx_cli-0.3.1b1 → arctx_cli-0.3.1b2}/tests/fixtures/dummy_ext.py +0 -0
@@ -6,6 +6,7 @@ __pycache__/
6
6
  .mypy_cache/
7
7
  .ruff_cache/
8
8
  .uv-cache/
9
+ .uv-tools/
9
10
  .venv/
10
11
  .coverage
11
12
  htmlcov/
@@ -25,9 +26,9 @@ run.json
25
26
  # Package build artifacts
26
27
  dist/
27
28
  *.egg-info/
29
+ packages/arctx/src/arctx/web/static/
28
30
 
29
31
  # IDE / Agent state directories
30
32
  .claude/
31
33
  .antigravitycli/
32
34
  .codex/
33
-
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arctx-cli
3
- Version: 0.3.1b1
3
+ Version: 0.3.1b2
4
4
  Summary: CLI for ARCTX — append-only DAG editing and refactoring
5
5
  Project-URL: Homepage, https://github.com/takumiecd/arctx
6
6
  Project-URL: Repository, https://github.com/takumiecd/arctx
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
18
  Classifier: Topic :: Utilities
19
19
  Requires-Python: >=3.10
20
- Requires-Dist: arctx>=0.3.1b1
20
+ Requires-Dist: arctx>=0.3.1b2
21
21
  Provides-Extra: dev
22
22
  Requires-Dist: black>=23.0; extra == 'dev'
23
23
  Requires-Dist: mypy>=1.0; extra == 'dev'
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "arctx-cli"
7
- version = "0.3.1b1"
7
+ version = "0.3.1b2"
8
8
  description = "CLI for ARCTX — append-only DAG editing and refactoring"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -25,7 +25,7 @@ classifiers = [
25
25
  "Topic :: Utilities",
26
26
  ]
27
27
  dependencies = [
28
- "arctx>=0.3.1b1",
28
+ "arctx>=0.3.1b2",
29
29
  ]
30
30
 
31
31
  [project.optional-dependencies]
@@ -13,7 +13,7 @@ import argparse
13
13
  from arctx.serve import serve
14
14
 
15
15
  from arctx_cli.context import (
16
- resolve_run_id_from_args,
16
+ require_existing_run_from_args,
17
17
  resolve_store,
18
18
  resolve_user_id_from_args,
19
19
  resolve_lane_id_from_args,
@@ -40,9 +40,7 @@ def add_parser(subparsers) -> argparse.ArgumentParser:
40
40
 
41
41
  def cli_serve(args) -> int:
42
42
  store = resolve_store(args.store_dir)
43
- run_id = resolve_run_id_from_args(args)
44
- if not store.run_path(run_id).exists():
45
- raise KeyError(f"unknown run_id: {run_id}")
43
+ run_id = require_existing_run_from_args(args, store)
46
44
  serve(
47
45
  store,
48
46
  run_id,
@@ -11,8 +11,8 @@ from arctx.web.extensions import load_enabled_routes, load_enabled_scripts
11
11
  from arctx.web.server import serve_gui
12
12
 
13
13
  from arctx_cli.context import (
14
+ require_existing_run_from_args,
14
15
  resolve_lane_id_from_args,
15
- resolve_run_id_from_args,
16
16
  resolve_store,
17
17
  resolve_user_id_from_args,
18
18
  )
@@ -43,9 +43,7 @@ def cli_web(args) -> int:
43
43
  return 1
44
44
 
45
45
  store = resolve_store(args.store_dir)
46
- run_id = resolve_run_id_from_args(args)
47
- if not store.run_path(run_id).exists():
48
- raise KeyError(f"unknown run_id: {run_id}")
46
+ run_id = require_existing_run_from_args(args, store)
49
47
 
50
48
  extension_scripts = load_enabled_scripts(store.run_path(run_id))
51
49
  extension_routes = load_enabled_routes(store.run_path(run_id))
@@ -8,6 +8,8 @@ code keeps working, and adds the argparse-Namespace helpers that belong here.
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
+ import os
12
+
11
13
  from arctx.session import ( # noqa: F401
12
14
  ExtensionAwareStore,
13
15
  RunHandleProxy,
@@ -28,6 +30,31 @@ def resolve_run_id_from_args(args) -> str:
28
30
  return resolve_run_id(getattr(args, "run", None))
29
31
 
30
32
 
33
+ def require_existing_run_from_args(args, store) -> str:
34
+ """Resolve a run_id and verify the run actually exists on disk.
35
+
36
+ Raises a friendly :class:`RuntimeError` (rendered by the CLI as a clean
37
+ ``arctx: ...`` line) when the resolved run is missing. The message
38
+ distinguishes a stale current-run pointer from an explicit bad ``--run`` so
39
+ the user knows how to recover.
40
+ """
41
+ run_id = resolve_run_id_from_args(args)
42
+ if store.run_path(run_id).exists():
43
+ return run_id
44
+
45
+ explicit = getattr(args, "run", None) or os.environ.get("ARCTX_RUN_ID")
46
+ if explicit:
47
+ raise RuntimeError(
48
+ f"unknown run: {run_id!r}. See 'arctx list' for available runs."
49
+ )
50
+ # No --run / env: the id came from the <gitdir>/arctx-id current-run pointer.
51
+ raise RuntimeError(
52
+ f"current run {run_id!r} no longer exists (set in <gitdir>/arctx-id). "
53
+ "Point it at an existing run with 'arctx use <run_id>', "
54
+ "or see 'arctx list'."
55
+ )
56
+
57
+
31
58
  def resolve_user_id_from_args(args) -> str:
32
59
  """Resolve user attribution from parsed CLI args."""
33
60
  return resolve_user_id(getattr(args, "user", None))
@@ -3,11 +3,42 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import argparse
6
+ import errno
7
+ import os
6
8
  import sys
7
9
 
8
10
  from arctx_cli.commands import core_cli_commands, register_cli_commands
9
11
 
10
12
 
13
+ def _user_error(message: str) -> int:
14
+ """Print a clean ``arctx: <message>`` to stderr and return exit code 1."""
15
+ print(f"arctx: {message}", file=sys.stderr)
16
+ return 1
17
+
18
+
19
+ def _format_user_error(exc: BaseException, args) -> str | None:
20
+ """Turn an expected, user-facing exception into a friendly message.
21
+
22
+ Returns ``None`` for exceptions that should keep their traceback (genuine
23
+ bugs), so they propagate unchanged.
24
+ """
25
+ if isinstance(exc, OSError) and exc.errno == errno.EADDRINUSE:
26
+ host = getattr(args, "host", "127.0.0.1")
27
+ port = getattr(args, "port", None)
28
+ where = f"{host}:{port}" if port is not None else "the requested address"
29
+ return (
30
+ f"address already in use ({where}). "
31
+ "Another server is probably already running there — "
32
+ "stop it, or pick a different port with --port <N>."
33
+ )
34
+ if isinstance(exc, KeyError):
35
+ # KeyError stringifies with quotes; unwrap to the bare message.
36
+ return str(exc.args[0]) if exc.args else str(exc)
37
+ if isinstance(exc, (RuntimeError, FileNotFoundError, ValueError)):
38
+ return str(exc) or exc.__class__.__name__
39
+ return None
40
+
41
+
11
42
  def _build_parser(*, run_dir: str | None = None) -> argparse.ArgumentParser:
12
43
  parser = argparse.ArgumentParser(
13
44
  prog="arctx",
@@ -128,10 +159,21 @@ def main(argv: list[str] | None = None) -> int:
128
159
  parser = _build_parser(run_dir=run_dir)
129
160
  args = parser.parse_args(tokens)
130
161
  handler = getattr(args, "_arctx_handler", None)
131
- if handler is not None:
132
- return handler(args)
162
+ if handler is None:
163
+ return 1
133
164
 
134
- return 1
165
+ if os.environ.get("ARCTX_DEBUG"):
166
+ # Opt back into full tracebacks for debugging.
167
+ return handler(args)
168
+ try:
169
+ return handler(args)
170
+ except KeyboardInterrupt:
171
+ return 130
172
+ except BaseException as exc: # noqa: BLE001 — re-raise anything unexpected
173
+ message = _format_user_error(exc, args)
174
+ if message is None:
175
+ raise
176
+ return _user_error(message)
135
177
 
136
178
 
137
179
  if __name__ == "__main__":
File without changes