arctx-cli 0.2.0b2__py3-none-any.whl
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.
- arctx_cli/__init__.py +1 -0
- arctx_cli/alias.py +238 -0
- arctx_cli/append_batch.py +90 -0
- arctx_cli/commands/__init__.py +85 -0
- arctx_cli/commands/alias_cmd.py +174 -0
- arctx_cli/commands/anchor.py +82 -0
- arctx_cli/commands/current.py +69 -0
- arctx_cli/commands/cut.py +89 -0
- arctx_cli/commands/dump.py +72 -0
- arctx_cli/commands/ext.py +236 -0
- arctx_cli/commands/git.py +216 -0
- arctx_cli/commands/graph.py +73 -0
- arctx_cli/commands/guide.py +360 -0
- arctx_cli/commands/init.py +223 -0
- arctx_cli/commands/list.py +45 -0
- arctx_cli/commands/migrate.py +135 -0
- arctx_cli/commands/node.py +55 -0
- arctx_cli/commands/outcomes.py +58 -0
- arctx_cli/commands/payload.py +192 -0
- arctx_cli/commands/reachable.py +75 -0
- arctx_cli/commands/show.py +113 -0
- arctx_cli/commands/sync.py +244 -0
- arctx_cli/commands/trace.py +46 -0
- arctx_cli/commands/transition.py +212 -0
- arctx_cli/commands/use.py +67 -0
- arctx_cli/commands/view.py +82 -0
- arctx_cli/commands/work_session.py +330 -0
- arctx_cli/context.py +38 -0
- arctx_cli/ext/__init__.py +1 -0
- arctx_cli/ext/command/__init__.py +110 -0
- arctx_cli/ext/git/__init__.py +1 -0
- arctx_cli/ext/git/branch.py +140 -0
- arctx_cli/ext/git/cherry_pick.py +144 -0
- arctx_cli/ext/git/commit.py +205 -0
- arctx_cli/ext/git/hook.py +758 -0
- arctx_cli/ext/git/merge.py +204 -0
- arctx_cli/ext/git/reset.py +138 -0
- arctx_cli/ext/git/revert.py +157 -0
- arctx_cli/ext/git/verify.py +140 -0
- arctx_cli/ext/git/worktree.py +173 -0
- arctx_cli/ext_registry.py +34 -0
- arctx_cli/main.py +133 -0
- arctx_cli/paths.py +27 -0
- arctx_cli/payload_builder.py +23 -0
- arctx_cli/workspace.py +64 -0
- arctx_cli-0.2.0b2.dist-info/METADATA +48 -0
- arctx_cli-0.2.0b2.dist-info/RECORD +49 -0
- arctx_cli-0.2.0b2.dist-info/WHEEL +4 -0
- arctx_cli-0.2.0b2.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""arctx CLI cherry-pick command.
|
|
2
|
+
|
|
3
|
+
Drives a ``git cherry-pick`` and records the corresponding arctx Transition with
|
|
4
|
+
BranchPayload, GitChangePayload, CherryPickPayload, BranchTipEvent, and
|
|
5
|
+
SessionPointerEvent.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
import json
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
from arctx_cli.append_batch import graph_counts, maybe_append_or_save
|
|
15
|
+
from arctx_cli.context import (
|
|
16
|
+
resolve_run_id_from_args,
|
|
17
|
+
resolve_store,
|
|
18
|
+
resolve_user_id_from_args,
|
|
19
|
+
resolve_work_session_id_from_args,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def add_parser(subparsers) -> argparse.ArgumentParser:
|
|
24
|
+
"""Register the ``cherry-pick`` subcommand parser."""
|
|
25
|
+
p = subparsers.add_parser(
|
|
26
|
+
"cherry-pick",
|
|
27
|
+
help="Cherry-pick a commit and record a arctx transition",
|
|
28
|
+
)
|
|
29
|
+
p.add_argument("--sha", required=True, help="Commit sha to cherry-pick")
|
|
30
|
+
p.add_argument("--branch", default=None, help="Override branch name")
|
|
31
|
+
p.add_argument("--run", default=None, help="Explicit run id")
|
|
32
|
+
p.add_argument("--store-dir", default=None, help="Store directory")
|
|
33
|
+
p.add_argument("--user", default=None, help="User id for attribution")
|
|
34
|
+
p.add_argument("--work-session", default=None, help="Work session id")
|
|
35
|
+
return p
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def run_cherry_pick_command(
|
|
39
|
+
*,
|
|
40
|
+
source_sha: str,
|
|
41
|
+
branch: str | None,
|
|
42
|
+
run_id: str | None,
|
|
43
|
+
store_dir: str | None,
|
|
44
|
+
user_id: str | None,
|
|
45
|
+
work_session_id: str | None,
|
|
46
|
+
) -> dict:
|
|
47
|
+
"""Execute a cherry-pick and persist the resulting graph records.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
source_sha:
|
|
52
|
+
Commit SHA to cherry-pick.
|
|
53
|
+
branch:
|
|
54
|
+
Branch name override.
|
|
55
|
+
run_id:
|
|
56
|
+
Explicit run id.
|
|
57
|
+
store_dir:
|
|
58
|
+
Store directory.
|
|
59
|
+
user_id:
|
|
60
|
+
User id for work event attribution.
|
|
61
|
+
work_session_id:
|
|
62
|
+
Work session id.
|
|
63
|
+
|
|
64
|
+
Returns
|
|
65
|
+
-------
|
|
66
|
+
dict with transition_id, output_node_id, branch, head_commit,
|
|
67
|
+
source_transition, source_commit.
|
|
68
|
+
"""
|
|
69
|
+
store = resolve_store(store_dir)
|
|
70
|
+
handle = store.load_run(run_id)
|
|
71
|
+
|
|
72
|
+
before = graph_counts(handle)
|
|
73
|
+
|
|
74
|
+
transition = handle.git.cherry_pick(
|
|
75
|
+
source_sha=source_sha,
|
|
76
|
+
branch=branch,
|
|
77
|
+
user_id=user_id,
|
|
78
|
+
work_session_id=work_session_id,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
maybe_append_or_save(
|
|
82
|
+
store=store,
|
|
83
|
+
handle=handle,
|
|
84
|
+
user_id=user_id,
|
|
85
|
+
work_session_id=work_session_id,
|
|
86
|
+
before=before,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Extract payload info for the result.
|
|
90
|
+
git_payloads = handle.run_graph.payloads_for_transition(
|
|
91
|
+
transition.transition_id, payload_type="git_change"
|
|
92
|
+
)
|
|
93
|
+
head_commit = git_payloads[-1].head_commit if git_payloads else ""
|
|
94
|
+
branch_payloads = handle.run_graph.payloads_for_transition(
|
|
95
|
+
transition.transition_id, payload_type="branch"
|
|
96
|
+
)
|
|
97
|
+
resolved_branch = branch_payloads[-1].branch if branch_payloads else ""
|
|
98
|
+
cp_payloads = handle.run_graph.payloads_for_transition(
|
|
99
|
+
transition.transition_id, payload_type="cherry_pick"
|
|
100
|
+
)
|
|
101
|
+
source_transition = cp_payloads[-1].source_transition if cp_payloads else None
|
|
102
|
+
source_commit = cp_payloads[-1].source_commit if cp_payloads else ""
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
"transition_id": transition.transition_id,
|
|
106
|
+
"output_node_id": transition.output_node_id,
|
|
107
|
+
"branch": resolved_branch,
|
|
108
|
+
"head_commit": head_commit,
|
|
109
|
+
"source_transition": source_transition,
|
|
110
|
+
"source_commit": source_commit,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def cli_cherry_pick(args) -> int:
|
|
115
|
+
"""Entry point for ``arctx cherry-pick`` subcommand."""
|
|
116
|
+
from arctx.ext.git.verbs._forward_transition import ParallelSessionConflict # noqa: PLC0415
|
|
117
|
+
|
|
118
|
+
run_id = resolve_run_id_from_args(args)
|
|
119
|
+
user_id = resolve_user_id_from_args(args)
|
|
120
|
+
work_session_id = resolve_work_session_id_from_args(args)
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
result = run_cherry_pick_command(
|
|
124
|
+
source_sha=args.sha,
|
|
125
|
+
branch=args.branch,
|
|
126
|
+
run_id=run_id,
|
|
127
|
+
store_dir=args.store_dir,
|
|
128
|
+
user_id=user_id,
|
|
129
|
+
work_session_id=work_session_id,
|
|
130
|
+
)
|
|
131
|
+
except ParallelSessionConflict as exc:
|
|
132
|
+
print(f"error: {exc}", file=sys.stderr)
|
|
133
|
+
print(
|
|
134
|
+
"hint: another session has advanced this branch. "
|
|
135
|
+
"Rebase / pull before committing.",
|
|
136
|
+
file=sys.stderr,
|
|
137
|
+
)
|
|
138
|
+
return 2
|
|
139
|
+
except Exception as exc: # noqa: BLE001
|
|
140
|
+
print(f"error: {exc}", file=sys.stderr)
|
|
141
|
+
return 1
|
|
142
|
+
|
|
143
|
+
print(json.dumps(result, indent=2))
|
|
144
|
+
return 0
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""arctx CLI commit command.
|
|
2
|
+
|
|
3
|
+
Drives a git commit and records the corresponding arctx Transition with
|
|
4
|
+
BranchPayload, GitChangePayload, BranchTipEvent, and SessionPointerEvent.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import json
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
from arctx_cli.append_batch import graph_counts, maybe_append_or_save
|
|
14
|
+
from arctx_cli.context import (
|
|
15
|
+
resolve_run_id_from_args,
|
|
16
|
+
resolve_store,
|
|
17
|
+
resolve_user_id_from_args,
|
|
18
|
+
resolve_work_session_id_from_args,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def add_parser(subparsers) -> argparse.ArgumentParser:
|
|
23
|
+
"""Register the ``commit`` subcommand parser."""
|
|
24
|
+
p = subparsers.add_parser(
|
|
25
|
+
"commit",
|
|
26
|
+
help="Drive a git commit and record a arctx transition",
|
|
27
|
+
)
|
|
28
|
+
p.add_argument("-m", "--message", required=True, help="Commit message")
|
|
29
|
+
p.add_argument(
|
|
30
|
+
"--branch",
|
|
31
|
+
default=None,
|
|
32
|
+
help="Override branch name (default: current git branch)",
|
|
33
|
+
)
|
|
34
|
+
p.add_argument(
|
|
35
|
+
"--merge",
|
|
36
|
+
default=None,
|
|
37
|
+
metavar="REF",
|
|
38
|
+
help=(
|
|
39
|
+
"Merge target. Format: 'branch:<name>', 'node:<id>', or just '<name>' "
|
|
40
|
+
"(auto-detected as branch name). Drives git merge and records a "
|
|
41
|
+
"multi-input transition with MergePayload."
|
|
42
|
+
),
|
|
43
|
+
)
|
|
44
|
+
p.add_argument(
|
|
45
|
+
"--join",
|
|
46
|
+
action="store_true",
|
|
47
|
+
help=(
|
|
48
|
+
"Treat the merge as a arctx-only join (no common ancestor). "
|
|
49
|
+
"Records JoinPayload instead of MergePayload. Only valid with --merge."
|
|
50
|
+
),
|
|
51
|
+
)
|
|
52
|
+
p.add_argument("--run", default=None, help="Explicit run id")
|
|
53
|
+
p.add_argument("--store-dir", default=None, help="Store directory")
|
|
54
|
+
p.add_argument("--user", default=None, help="User id for attribution")
|
|
55
|
+
p.add_argument("--work-session", default=None, help="Work session id")
|
|
56
|
+
return p
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _parse_merge_ref(ref: str) -> tuple[str | None, str | None]:
|
|
60
|
+
"""Parse a merge ref string into (other_branch, other_node_id).
|
|
61
|
+
|
|
62
|
+
Formats accepted:
|
|
63
|
+
- "branch:<name>" → branch name
|
|
64
|
+
- "node:<id>" → node id
|
|
65
|
+
- "<anything>" → treated as branch name (auto-detect)
|
|
66
|
+
"""
|
|
67
|
+
if ref.startswith("branch:"):
|
|
68
|
+
return ref[len("branch:"):], None
|
|
69
|
+
if ref.startswith("node:"):
|
|
70
|
+
return None, ref[len("node:"):]
|
|
71
|
+
# Auto-detect: treat as branch name.
|
|
72
|
+
return ref, None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def run_commit_command(
|
|
76
|
+
*,
|
|
77
|
+
message: str,
|
|
78
|
+
branch: str | None,
|
|
79
|
+
run_id: str | None,
|
|
80
|
+
store_dir: str | None,
|
|
81
|
+
user_id: str | None,
|
|
82
|
+
work_session_id: str | None,
|
|
83
|
+
merge: str | None = None,
|
|
84
|
+
join: bool = False,
|
|
85
|
+
# Test-only parameters; not exposed in the CLI parser.
|
|
86
|
+
dry_run: bool = False,
|
|
87
|
+
head_commit: str | None = None,
|
|
88
|
+
) -> dict:
|
|
89
|
+
"""Execute a commit (or merge) and persist the resulting graph records.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
message:
|
|
94
|
+
Git commit message.
|
|
95
|
+
branch:
|
|
96
|
+
Branch name override (None → infer from git).
|
|
97
|
+
run_id:
|
|
98
|
+
Explicit run id. If None, resolved from env / <gitdir>/arctx-id.
|
|
99
|
+
store_dir:
|
|
100
|
+
Store directory. If None, resolved from ARCTX_HOME.
|
|
101
|
+
user_id:
|
|
102
|
+
User id for work event attribution.
|
|
103
|
+
work_session_id:
|
|
104
|
+
Work session id.
|
|
105
|
+
merge:
|
|
106
|
+
If set, drive a merge instead of a plain commit. Format:
|
|
107
|
+
'branch:<name>', 'node:<id>', or '<name>' (branch auto-detect).
|
|
108
|
+
join:
|
|
109
|
+
If True and merge is set, use JoinPayload instead of MergePayload.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
dict with transition_id, output_node_id, branch, head_commit.
|
|
114
|
+
"""
|
|
115
|
+
store = resolve_store(store_dir)
|
|
116
|
+
handle = store.load_run(run_id)
|
|
117
|
+
|
|
118
|
+
before = graph_counts(handle)
|
|
119
|
+
|
|
120
|
+
if merge is not None:
|
|
121
|
+
other_branch, other_node_id = _parse_merge_ref(merge)
|
|
122
|
+
transition = handle.git.merge(
|
|
123
|
+
other_branch=other_branch,
|
|
124
|
+
other_node_id=other_node_id,
|
|
125
|
+
message=message,
|
|
126
|
+
branch=branch,
|
|
127
|
+
user_id=user_id,
|
|
128
|
+
work_session_id=work_session_id,
|
|
129
|
+
join=join,
|
|
130
|
+
dry_run=dry_run,
|
|
131
|
+
head_commit=head_commit,
|
|
132
|
+
)
|
|
133
|
+
else:
|
|
134
|
+
transition = handle.git.commit(
|
|
135
|
+
message=message,
|
|
136
|
+
branch=branch,
|
|
137
|
+
user_id=user_id,
|
|
138
|
+
work_session_id=work_session_id,
|
|
139
|
+
dry_run=dry_run,
|
|
140
|
+
head_commit=head_commit,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
maybe_append_or_save(
|
|
144
|
+
store=store,
|
|
145
|
+
handle=handle,
|
|
146
|
+
user_id=user_id,
|
|
147
|
+
work_session_id=work_session_id,
|
|
148
|
+
before=before,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Extract GitChangePayload info for the result.
|
|
152
|
+
git_payloads = handle.run_graph.payloads_for_transition(
|
|
153
|
+
transition.transition_id, payload_type="git_change"
|
|
154
|
+
)
|
|
155
|
+
head_commit = git_payloads[-1].head_commit if git_payloads else ""
|
|
156
|
+
branch_payloads = handle.run_graph.payloads_for_transition(
|
|
157
|
+
transition.transition_id, payload_type="branch"
|
|
158
|
+
)
|
|
159
|
+
resolved_branch = branch_payloads[-1].branch if branch_payloads else ""
|
|
160
|
+
|
|
161
|
+
result: dict = {
|
|
162
|
+
"transition_id": transition.transition_id,
|
|
163
|
+
"output_node_id": transition.output_node_id,
|
|
164
|
+
"branch": resolved_branch,
|
|
165
|
+
"head_commit": head_commit,
|
|
166
|
+
}
|
|
167
|
+
if merge is not None:
|
|
168
|
+
result["merge"] = merge
|
|
169
|
+
result["join"] = join
|
|
170
|
+
return result
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def cli_commit(args) -> int:
|
|
174
|
+
"""Entry point for ``arctx commit`` subcommand."""
|
|
175
|
+
from arctx.ext.git.verbs._forward_transition import ParallelSessionConflict # noqa: PLC0415
|
|
176
|
+
|
|
177
|
+
run_id = resolve_run_id_from_args(args)
|
|
178
|
+
user_id = resolve_user_id_from_args(args)
|
|
179
|
+
work_session_id = resolve_work_session_id_from_args(args)
|
|
180
|
+
|
|
181
|
+
try:
|
|
182
|
+
result = run_commit_command(
|
|
183
|
+
message=args.message,
|
|
184
|
+
branch=args.branch,
|
|
185
|
+
run_id=run_id,
|
|
186
|
+
store_dir=args.store_dir,
|
|
187
|
+
user_id=user_id,
|
|
188
|
+
work_session_id=work_session_id,
|
|
189
|
+
merge=getattr(args, "merge", None),
|
|
190
|
+
join=getattr(args, "join", False),
|
|
191
|
+
)
|
|
192
|
+
except ParallelSessionConflict as exc:
|
|
193
|
+
print(f"error: {exc}", file=sys.stderr)
|
|
194
|
+
print(
|
|
195
|
+
"hint: another session has advanced this branch. "
|
|
196
|
+
"Rebase / pull before committing.",
|
|
197
|
+
file=sys.stderr,
|
|
198
|
+
)
|
|
199
|
+
return 2
|
|
200
|
+
except Exception as exc: # noqa: BLE001
|
|
201
|
+
print(f"error: {exc}", file=sys.stderr)
|
|
202
|
+
return 1
|
|
203
|
+
|
|
204
|
+
print(json.dumps(result, indent=2))
|
|
205
|
+
return 0
|