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,244 @@
|
|
|
1
|
+
"""arctx CLI sync command."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from arctx_cli.context import resolve_run_id_from_args, resolve_store, resolve_user_id_from_args
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _sync_local():
|
|
14
|
+
from arctx.core.sync import local
|
|
15
|
+
|
|
16
|
+
return local
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def add_parser(subparsers) -> argparse.ArgumentParser:
|
|
20
|
+
parser = subparsers.add_parser(
|
|
21
|
+
"sync",
|
|
22
|
+
help="Synchronize a local run with a file-backed shared DAG",
|
|
23
|
+
)
|
|
24
|
+
commands = parser.add_subparsers(dest="sync_command", required=True)
|
|
25
|
+
|
|
26
|
+
init = commands.add_parser("init", help="Initialize sync for a local run")
|
|
27
|
+
_add_common_args(init)
|
|
28
|
+
init.add_argument("--shared-run", required=True, dest="shared_run_id")
|
|
29
|
+
init.add_argument("--workspace", default=None, dest="workspace_id")
|
|
30
|
+
init.add_argument("--user", default=None)
|
|
31
|
+
|
|
32
|
+
status = commands.add_parser("status", help="Show local/shared sync status")
|
|
33
|
+
_add_common_args(status)
|
|
34
|
+
status.add_argument("--shared-run", default=None, dest="shared_run_id")
|
|
35
|
+
|
|
36
|
+
push = commands.add_parser("push", help="Push local records to the shared DAG")
|
|
37
|
+
_add_common_args(push)
|
|
38
|
+
push.add_argument("--shared-run", default=None, dest="shared_run_id")
|
|
39
|
+
push.add_argument("--workspace", default=None, dest="workspace_id")
|
|
40
|
+
push.add_argument("--user", default=None)
|
|
41
|
+
|
|
42
|
+
pull = commands.add_parser("pull", help="Pull shared DAG records into the local run")
|
|
43
|
+
_add_common_args(pull)
|
|
44
|
+
pull.add_argument("--shared-run", default=None, dest="shared_run_id")
|
|
45
|
+
|
|
46
|
+
return parser
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _add_common_args(parser: argparse.ArgumentParser) -> None:
|
|
50
|
+
parser.add_argument("--run", default=None)
|
|
51
|
+
parser.add_argument("--store-dir", default=None)
|
|
52
|
+
parser.add_argument("--remote", default=None)
|
|
53
|
+
parser.add_argument("--remote-dir", default=None)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def run_sync_init_command(
|
|
57
|
+
*,
|
|
58
|
+
run_id: str,
|
|
59
|
+
shared_run_id: str,
|
|
60
|
+
store_dir: str,
|
|
61
|
+
remote: str = "local-shared",
|
|
62
|
+
remote_dir: str | None = None,
|
|
63
|
+
workspace_id: str | None = None,
|
|
64
|
+
actor_id: str = "user",
|
|
65
|
+
) -> dict:
|
|
66
|
+
store = resolve_store(store_dir)
|
|
67
|
+
if not store.run_path(run_id).exists():
|
|
68
|
+
raise KeyError(f"unknown run_id: {run_id}")
|
|
69
|
+
handle = store.load_run(run_id)
|
|
70
|
+
sync = _sync_local()
|
|
71
|
+
return sync.sync_init(
|
|
72
|
+
handle=handle,
|
|
73
|
+
run_path=store.run_path(run_id),
|
|
74
|
+
remote=remote,
|
|
75
|
+
shared_run_id=shared_run_id,
|
|
76
|
+
remote_dir=remote_dir or str(sync.default_remote_dir(store_dir)),
|
|
77
|
+
workspace_id=workspace_id or _default_workspace_id(),
|
|
78
|
+
actor_id=actor_id,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def run_sync_status_command(
|
|
83
|
+
*,
|
|
84
|
+
run_id: str,
|
|
85
|
+
store_dir: str,
|
|
86
|
+
shared_run_id: str | None = None,
|
|
87
|
+
remote: str | None = None,
|
|
88
|
+
remote_dir: str | None = None,
|
|
89
|
+
) -> dict:
|
|
90
|
+
store = resolve_store(store_dir)
|
|
91
|
+
if not store.run_path(run_id).exists():
|
|
92
|
+
raise KeyError(f"unknown run_id: {run_id}")
|
|
93
|
+
handle = store.load_run(run_id)
|
|
94
|
+
cfg = _resolve_sync_config(
|
|
95
|
+
run_path=store.run_path(run_id),
|
|
96
|
+
shared_run_id=shared_run_id,
|
|
97
|
+
remote=remote,
|
|
98
|
+
remote_dir=remote_dir,
|
|
99
|
+
store_dir=store_dir,
|
|
100
|
+
)
|
|
101
|
+
sync = _sync_local()
|
|
102
|
+
return sync.sync_status(
|
|
103
|
+
handle=handle,
|
|
104
|
+
remote=cfg["remote"],
|
|
105
|
+
shared_run_id=cfg["shared_run_id"],
|
|
106
|
+
remote_dir=cfg["remote_dir"],
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def run_sync_push_command(
|
|
111
|
+
*,
|
|
112
|
+
run_id: str,
|
|
113
|
+
store_dir: str,
|
|
114
|
+
shared_run_id: str | None = None,
|
|
115
|
+
remote: str | None = None,
|
|
116
|
+
remote_dir: str | None = None,
|
|
117
|
+
workspace_id: str | None = None,
|
|
118
|
+
actor_id: str = "user",
|
|
119
|
+
) -> dict:
|
|
120
|
+
store = resolve_store(store_dir)
|
|
121
|
+
if not store.run_path(run_id).exists():
|
|
122
|
+
raise KeyError(f"unknown run_id: {run_id}")
|
|
123
|
+
handle = store.load_run(run_id)
|
|
124
|
+
cfg = _resolve_sync_config(
|
|
125
|
+
run_path=store.run_path(run_id),
|
|
126
|
+
shared_run_id=shared_run_id,
|
|
127
|
+
remote=remote,
|
|
128
|
+
remote_dir=remote_dir,
|
|
129
|
+
store_dir=store_dir,
|
|
130
|
+
)
|
|
131
|
+
sync = _sync_local()
|
|
132
|
+
return sync.sync_push(
|
|
133
|
+
handle=handle,
|
|
134
|
+
remote=cfg["remote"],
|
|
135
|
+
shared_run_id=cfg["shared_run_id"],
|
|
136
|
+
remote_dir=cfg["remote_dir"],
|
|
137
|
+
workspace_id=workspace_id or cfg.get("workspace_id") or _default_workspace_id(),
|
|
138
|
+
actor_id=actor_id,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def run_sync_pull_command(
|
|
143
|
+
*,
|
|
144
|
+
run_id: str,
|
|
145
|
+
store_dir: str,
|
|
146
|
+
shared_run_id: str | None = None,
|
|
147
|
+
remote: str | None = None,
|
|
148
|
+
remote_dir: str | None = None,
|
|
149
|
+
) -> dict:
|
|
150
|
+
store = resolve_store(store_dir)
|
|
151
|
+
if not store.run_path(run_id).exists():
|
|
152
|
+
raise KeyError(f"unknown run_id: {run_id}")
|
|
153
|
+
handle = store.load_run(run_id)
|
|
154
|
+
cfg = _resolve_sync_config(
|
|
155
|
+
run_path=store.run_path(run_id),
|
|
156
|
+
shared_run_id=shared_run_id,
|
|
157
|
+
remote=remote,
|
|
158
|
+
remote_dir=remote_dir,
|
|
159
|
+
store_dir=store_dir,
|
|
160
|
+
)
|
|
161
|
+
sync = _sync_local()
|
|
162
|
+
result = sync.sync_pull(
|
|
163
|
+
handle=handle,
|
|
164
|
+
remote=cfg["remote"],
|
|
165
|
+
shared_run_id=cfg["shared_run_id"],
|
|
166
|
+
remote_dir=cfg["remote_dir"],
|
|
167
|
+
)
|
|
168
|
+
store.save_run(handle)
|
|
169
|
+
return result
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def cli_sync(args) -> int:
|
|
173
|
+
if args.sync_command == "init":
|
|
174
|
+
result = run_sync_init_command(
|
|
175
|
+
run_id=resolve_run_id_from_args(args),
|
|
176
|
+
shared_run_id=args.shared_run_id,
|
|
177
|
+
store_dir=args.store_dir,
|
|
178
|
+
remote=args.remote or "local-shared",
|
|
179
|
+
remote_dir=args.remote_dir,
|
|
180
|
+
workspace_id=args.workspace_id,
|
|
181
|
+
actor_id=resolve_user_id_from_args(args),
|
|
182
|
+
)
|
|
183
|
+
elif args.sync_command == "status":
|
|
184
|
+
result = run_sync_status_command(
|
|
185
|
+
run_id=resolve_run_id_from_args(args),
|
|
186
|
+
store_dir=args.store_dir,
|
|
187
|
+
shared_run_id=args.shared_run_id,
|
|
188
|
+
remote=args.remote,
|
|
189
|
+
remote_dir=args.remote_dir,
|
|
190
|
+
)
|
|
191
|
+
elif args.sync_command == "push":
|
|
192
|
+
result = run_sync_push_command(
|
|
193
|
+
run_id=resolve_run_id_from_args(args),
|
|
194
|
+
store_dir=args.store_dir,
|
|
195
|
+
shared_run_id=args.shared_run_id,
|
|
196
|
+
remote=args.remote,
|
|
197
|
+
remote_dir=args.remote_dir,
|
|
198
|
+
workspace_id=args.workspace_id,
|
|
199
|
+
actor_id=resolve_user_id_from_args(args),
|
|
200
|
+
)
|
|
201
|
+
elif args.sync_command == "pull":
|
|
202
|
+
result = run_sync_pull_command(
|
|
203
|
+
run_id=resolve_run_id_from_args(args),
|
|
204
|
+
store_dir=args.store_dir,
|
|
205
|
+
shared_run_id=args.shared_run_id,
|
|
206
|
+
remote=args.remote,
|
|
207
|
+
remote_dir=args.remote_dir,
|
|
208
|
+
)
|
|
209
|
+
else:
|
|
210
|
+
return 1
|
|
211
|
+
|
|
212
|
+
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
213
|
+
return 0
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _resolve_sync_config(
|
|
217
|
+
*,
|
|
218
|
+
run_path: Path,
|
|
219
|
+
shared_run_id: str | None,
|
|
220
|
+
remote: str | None,
|
|
221
|
+
remote_dir: str | None,
|
|
222
|
+
store_dir: str,
|
|
223
|
+
) -> dict[str, str]:
|
|
224
|
+
if shared_run_id is None or remote is None or remote_dir is None:
|
|
225
|
+
try:
|
|
226
|
+
cfg = _sync_local().load_sync_config(run_path)
|
|
227
|
+
except RuntimeError:
|
|
228
|
+
if shared_run_id is None:
|
|
229
|
+
raise
|
|
230
|
+
cfg = {}
|
|
231
|
+
else:
|
|
232
|
+
cfg = {}
|
|
233
|
+
return {
|
|
234
|
+
"shared_run_id": shared_run_id or cfg["shared_run_id"],
|
|
235
|
+
"remote": remote or cfg.get("remote", "local-shared"),
|
|
236
|
+
"remote_dir": remote_dir
|
|
237
|
+
or cfg.get("remote_dir", str(_sync_local().default_remote_dir(store_dir))),
|
|
238
|
+
"workspace_id": cfg.get("workspace_id", _default_workspace_id()),
|
|
239
|
+
"actor_id": cfg.get("actor_id", "user"),
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _default_workspace_id() -> str:
|
|
244
|
+
return os.environ.get("ARCTX_WORKSPACE_ID") or "local"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""arctx CLI trace command."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
from arctx_cli.context import resolve_store, resolve_run_id_from_args
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def add_parser(subparsers) -> argparse.ArgumentParser:
|
|
12
|
+
parser = subparsers.add_parser("trace", help="Trace observed history from a node")
|
|
13
|
+
parser.add_argument("--run", default=None)
|
|
14
|
+
parser.add_argument("--from-node", required=True)
|
|
15
|
+
parser.add_argument("--depth", type=int, default=None)
|
|
16
|
+
parser.add_argument("--store-dir", default=None)
|
|
17
|
+
return parser
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def run_trace_command(
|
|
21
|
+
*,
|
|
22
|
+
run_id: str,
|
|
23
|
+
from_node_id: str,
|
|
24
|
+
depth: int | None,
|
|
25
|
+
store_dir: str,
|
|
26
|
+
) -> dict:
|
|
27
|
+
store = resolve_store(store_dir)
|
|
28
|
+
if not store.run_path(run_id).exists():
|
|
29
|
+
raise KeyError(f"unknown run_id: {run_id}")
|
|
30
|
+
handle = store.load_run(run_id)
|
|
31
|
+
history = handle.trace(
|
|
32
|
+
from_node_id,
|
|
33
|
+
depth=depth,
|
|
34
|
+
)
|
|
35
|
+
return {"history": history.to_dict()}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def cli_trace(args) -> int:
|
|
39
|
+
result = run_trace_command(
|
|
40
|
+
run_id=resolve_run_id_from_args(args),
|
|
41
|
+
from_node_id=args.from_node,
|
|
42
|
+
depth=args.depth,
|
|
43
|
+
store_dir=args.store_dir,
|
|
44
|
+
)
|
|
45
|
+
print(json.dumps(result["history"], ensure_ascii=False, indent=2))
|
|
46
|
+
return 0
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""arctx CLI transition command."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from arctx_cli.commands.outcomes import run_outcomes_command
|
|
10
|
+
from arctx_cli.commands.show import run_show_command
|
|
11
|
+
from arctx_cli.context import (
|
|
12
|
+
resolve_run_id_from_args,
|
|
13
|
+
resolve_store,
|
|
14
|
+
resolve_user_id_from_args,
|
|
15
|
+
resolve_work_session_id_from_args,
|
|
16
|
+
)
|
|
17
|
+
from arctx_cli.append_batch import graph_counts, maybe_append_or_save
|
|
18
|
+
from arctx_cli.payload_builder import build_payload, parse_field_args, parse_json_object
|
|
19
|
+
from arctx.core.schema.payloads import TransitionPayload
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def add_parser(subparsers) -> argparse.ArgumentParser:
|
|
23
|
+
parser = subparsers.add_parser(
|
|
24
|
+
"transition",
|
|
25
|
+
help="Create and inspect transitions",
|
|
26
|
+
)
|
|
27
|
+
transition_sub = parser.add_subparsers(dest="transition_command", required=True)
|
|
28
|
+
|
|
29
|
+
sp_create = transition_sub.add_parser(
|
|
30
|
+
"create",
|
|
31
|
+
help="Create one Transition and one output Node from input nodes",
|
|
32
|
+
)
|
|
33
|
+
sp_create.add_argument("--run", default=None)
|
|
34
|
+
sp_create.add_argument(
|
|
35
|
+
"--from",
|
|
36
|
+
action="append",
|
|
37
|
+
required=True,
|
|
38
|
+
dest="input_nodes",
|
|
39
|
+
metavar="NODE_ID",
|
|
40
|
+
help="Input node (repeatable for multi-node transitions)",
|
|
41
|
+
)
|
|
42
|
+
sp_create.add_argument("--payload-type", default="transition_payload")
|
|
43
|
+
sp_create.add_argument("--field", action="append", default=None, help="Payload field as key=value")
|
|
44
|
+
sp_create.add_argument("--json", default=None, help="Payload fields as a JSON object")
|
|
45
|
+
sp_create.add_argument("--store-dir", default=None)
|
|
46
|
+
sp_create.add_argument("--user", default=None)
|
|
47
|
+
sp_create.add_argument("--work-session", default=None)
|
|
48
|
+
|
|
49
|
+
sp_show = transition_sub.add_parser("show", help="Show one transition")
|
|
50
|
+
sp_show.add_argument("transition_id")
|
|
51
|
+
sp_show.add_argument("--with-payloads", action="store_true")
|
|
52
|
+
sp_show.add_argument("--run", default=None)
|
|
53
|
+
sp_show.add_argument("--store-dir", default=None)
|
|
54
|
+
|
|
55
|
+
sp_output = transition_sub.add_parser("output", help="Show a transition output node")
|
|
56
|
+
sp_output.add_argument("transition_id")
|
|
57
|
+
sp_output.add_argument("--run", default=None)
|
|
58
|
+
sp_output.add_argument("--store-dir", default=None)
|
|
59
|
+
|
|
60
|
+
sp_inputs = transition_sub.add_parser("inputs", help="Show transition input nodes")
|
|
61
|
+
sp_inputs.add_argument("transition_id")
|
|
62
|
+
sp_inputs.add_argument("--run", default=None)
|
|
63
|
+
sp_inputs.add_argument("--store-dir", default=None)
|
|
64
|
+
|
|
65
|
+
sp_payloads = transition_sub.add_parser("payloads", help="Show transition payloads")
|
|
66
|
+
sp_payloads.add_argument("transition_id")
|
|
67
|
+
sp_payloads.add_argument("--run", default=None)
|
|
68
|
+
sp_payloads.add_argument("--store-dir", default=None)
|
|
69
|
+
return parser
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def run_transition_command(
|
|
73
|
+
*,
|
|
74
|
+
run_id: str,
|
|
75
|
+
input_node_ids: list[str],
|
|
76
|
+
payload_type: str,
|
|
77
|
+
content: dict,
|
|
78
|
+
store_dir: str,
|
|
79
|
+
user_id: str | None = None,
|
|
80
|
+
work_session_id: str | None = None,
|
|
81
|
+
) -> dict:
|
|
82
|
+
store = resolve_store(store_dir)
|
|
83
|
+
if not store.run_path(run_id).exists():
|
|
84
|
+
raise KeyError(f"unknown run_id: {run_id}")
|
|
85
|
+
handle = store.load_run(run_id)
|
|
86
|
+
payload = TransitionPayload(
|
|
87
|
+
payload_id="pending",
|
|
88
|
+
target_id="pending",
|
|
89
|
+
type=payload_type,
|
|
90
|
+
content=content,
|
|
91
|
+
)
|
|
92
|
+
before = graph_counts(handle)
|
|
93
|
+
transition = handle.transition(
|
|
94
|
+
input_node_ids,
|
|
95
|
+
payload,
|
|
96
|
+
user_id=user_id,
|
|
97
|
+
work_session_id=work_session_id,
|
|
98
|
+
)
|
|
99
|
+
maybe_append_or_save(
|
|
100
|
+
store=store,
|
|
101
|
+
handle=handle,
|
|
102
|
+
user_id=user_id,
|
|
103
|
+
work_session_id=work_session_id,
|
|
104
|
+
before=before,
|
|
105
|
+
)
|
|
106
|
+
return {"transition": transition.to_dict()}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def run_transition_create_command(
|
|
110
|
+
*,
|
|
111
|
+
run_id: str,
|
|
112
|
+
input_node_ids: list[str],
|
|
113
|
+
payload_type: str,
|
|
114
|
+
field_data: dict,
|
|
115
|
+
json_data: dict,
|
|
116
|
+
store_dir: str,
|
|
117
|
+
user_id: str | None = None,
|
|
118
|
+
work_session_id: str | None = None,
|
|
119
|
+
) -> dict:
|
|
120
|
+
store = resolve_store(store_dir)
|
|
121
|
+
if not store.run_path(run_id).exists():
|
|
122
|
+
raise KeyError(f"unknown run_id: {run_id}")
|
|
123
|
+
handle = store.load_run(run_id)
|
|
124
|
+
payload = build_payload(
|
|
125
|
+
payload_type=payload_type,
|
|
126
|
+
target_kind="transition",
|
|
127
|
+
target_id="pending",
|
|
128
|
+
payload_id="pending",
|
|
129
|
+
json_data=json_data,
|
|
130
|
+
field_data=field_data,
|
|
131
|
+
)
|
|
132
|
+
before = graph_counts(handle)
|
|
133
|
+
transition = handle.transition(
|
|
134
|
+
input_node_ids,
|
|
135
|
+
payload,
|
|
136
|
+
user_id=user_id,
|
|
137
|
+
work_session_id=work_session_id,
|
|
138
|
+
)
|
|
139
|
+
maybe_append_or_save(
|
|
140
|
+
store=store,
|
|
141
|
+
handle=handle,
|
|
142
|
+
user_id=user_id,
|
|
143
|
+
work_session_id=work_session_id,
|
|
144
|
+
before=before,
|
|
145
|
+
)
|
|
146
|
+
return {"transition": transition.to_dict()}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def cli_transition(args) -> int:
|
|
150
|
+
try:
|
|
151
|
+
if args.transition_command == "create":
|
|
152
|
+
result = run_transition_create_command(
|
|
153
|
+
run_id=resolve_run_id_from_args(args),
|
|
154
|
+
input_node_ids=args.input_nodes,
|
|
155
|
+
payload_type=args.payload_type,
|
|
156
|
+
field_data=parse_field_args(args.field),
|
|
157
|
+
json_data=parse_json_object(args.json),
|
|
158
|
+
store_dir=args.store_dir,
|
|
159
|
+
user_id=resolve_user_id_from_args(args),
|
|
160
|
+
work_session_id=resolve_work_session_id_from_args(args),
|
|
161
|
+
)
|
|
162
|
+
print(json.dumps(result["transition"], ensure_ascii=False, indent=2))
|
|
163
|
+
return 0
|
|
164
|
+
if args.transition_command == "show":
|
|
165
|
+
result = run_show_command(
|
|
166
|
+
run_id=resolve_run_id_from_args(args),
|
|
167
|
+
node_id=None,
|
|
168
|
+
transition_id=args.transition_id,
|
|
169
|
+
payload_id=None,
|
|
170
|
+
with_payloads=args.with_payloads,
|
|
171
|
+
outputs=True,
|
|
172
|
+
store_dir=args.store_dir,
|
|
173
|
+
)
|
|
174
|
+
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
175
|
+
return 0
|
|
176
|
+
if args.transition_command == "output":
|
|
177
|
+
result = run_outcomes_command(
|
|
178
|
+
run_id=resolve_run_id_from_args(args),
|
|
179
|
+
transition_id=args.transition_id,
|
|
180
|
+
include_payloads=False,
|
|
181
|
+
store_dir=args.store_dir,
|
|
182
|
+
)
|
|
183
|
+
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
184
|
+
return 0
|
|
185
|
+
if args.transition_command == "inputs":
|
|
186
|
+
result = run_show_command(
|
|
187
|
+
run_id=resolve_run_id_from_args(args),
|
|
188
|
+
node_id=None,
|
|
189
|
+
transition_id=args.transition_id,
|
|
190
|
+
payload_id=None,
|
|
191
|
+
with_payloads=False,
|
|
192
|
+
outputs=False,
|
|
193
|
+
store_dir=args.store_dir,
|
|
194
|
+
)
|
|
195
|
+
print(json.dumps({"input_node_ids": result["input_node_ids"]}, ensure_ascii=False, indent=2))
|
|
196
|
+
return 0
|
|
197
|
+
if args.transition_command == "payloads":
|
|
198
|
+
result = run_show_command(
|
|
199
|
+
run_id=resolve_run_id_from_args(args),
|
|
200
|
+
node_id=None,
|
|
201
|
+
transition_id=args.transition_id,
|
|
202
|
+
payload_id=None,
|
|
203
|
+
with_payloads=True,
|
|
204
|
+
outputs=False,
|
|
205
|
+
store_dir=args.store_dir,
|
|
206
|
+
)
|
|
207
|
+
print(json.dumps(result["payloads"], ensure_ascii=False, indent=2))
|
|
208
|
+
return 0
|
|
209
|
+
except (KeyError, ValueError, json.JSONDecodeError) as exc:
|
|
210
|
+
print(f"error: {exc}", file=sys.stderr)
|
|
211
|
+
return 1
|
|
212
|
+
return 0
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""arctx CLI use command."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
|
|
7
|
+
from arctx_cli.context import resolve_store
|
|
8
|
+
from arctx_cli.paths import find_repo_root, resolve_store_dir, arctx_id_path, write_arctx_id
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def add_parser(subparsers) -> argparse.ArgumentParser:
|
|
12
|
+
"""Register the ``use`` subcommand parser."""
|
|
13
|
+
parser = subparsers.add_parser(
|
|
14
|
+
"use", help="Set the current run (writes <gitdir>/arctx-id)"
|
|
15
|
+
)
|
|
16
|
+
parser.add_argument("run_id", help="Run identifier")
|
|
17
|
+
parser.add_argument(
|
|
18
|
+
"--store-dir",
|
|
19
|
+
default=None,
|
|
20
|
+
help="Directory where runs are stored (default: <ARCTX_HOME>/runs)",
|
|
21
|
+
)
|
|
22
|
+
return parser
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def run_use_command(
|
|
26
|
+
*,
|
|
27
|
+
run_id: str,
|
|
28
|
+
store_dir: str | None,
|
|
29
|
+
) -> dict:
|
|
30
|
+
"""Set the current run by writing its id to ``<gitdir>/arctx-id``.
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
run_id:
|
|
35
|
+
Identifier of the run.
|
|
36
|
+
store_dir:
|
|
37
|
+
Directory where runs are stored.
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
dict with ``run_id`` and ``arctx_id_path`` keys.
|
|
42
|
+
|
|
43
|
+
Raises
|
|
44
|
+
------
|
|
45
|
+
KeyError
|
|
46
|
+
If the run_id does not exist in the store.
|
|
47
|
+
RuntimeError
|
|
48
|
+
If not inside a git repository.
|
|
49
|
+
"""
|
|
50
|
+
resolved_store_dir = store_dir if store_dir is not None else resolve_store_dir()
|
|
51
|
+
store = resolve_store(resolved_store_dir)
|
|
52
|
+
run_path = store.run_path(run_id)
|
|
53
|
+
if not run_path.exists():
|
|
54
|
+
raise KeyError(f"unknown run_id: {run_id}")
|
|
55
|
+
repo_root = find_repo_root()
|
|
56
|
+
write_arctx_id(repo_root, run_id)
|
|
57
|
+
return {"run_id": run_id, "arctx_id_path": str(arctx_id_path(repo_root))}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def cli_use(args) -> int:
|
|
61
|
+
"""Entry point for ``arctx use`` subcommand."""
|
|
62
|
+
result = run_use_command(
|
|
63
|
+
run_id=args.run_id,
|
|
64
|
+
store_dir=args.store_dir,
|
|
65
|
+
)
|
|
66
|
+
print(result["run_id"])
|
|
67
|
+
return 0
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""arctx CLI view subcommands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
from arctx_cli.append_batch import graph_counts, maybe_append_or_save
|
|
9
|
+
from arctx_cli.context import (
|
|
10
|
+
resolve_run_id_from_args,
|
|
11
|
+
resolve_store,
|
|
12
|
+
resolve_user_id_from_args,
|
|
13
|
+
resolve_work_session_id_from_args,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def add_parser(subparsers) -> argparse.ArgumentParser:
|
|
18
|
+
parser = subparsers.add_parser("view", help="Manage GraphViews")
|
|
19
|
+
view_sub = parser.add_subparsers(dest="view_command", required=True)
|
|
20
|
+
|
|
21
|
+
# view create
|
|
22
|
+
create = view_sub.add_parser("create", help="Create a new GraphView")
|
|
23
|
+
create.add_argument("--name", required=True)
|
|
24
|
+
create.add_argument("--root-node", required=True, dest="root_node")
|
|
25
|
+
create.add_argument("--run", default=None)
|
|
26
|
+
create.add_argument("--store-dir", default=None)
|
|
27
|
+
create.add_argument("--user", default=None)
|
|
28
|
+
create.add_argument("--work-session", default=None)
|
|
29
|
+
|
|
30
|
+
# view list
|
|
31
|
+
lst = view_sub.add_parser("list", help="List all GraphViews")
|
|
32
|
+
lst.add_argument("--run", default=None)
|
|
33
|
+
lst.add_argument("--store-dir", default=None)
|
|
34
|
+
|
|
35
|
+
# view show
|
|
36
|
+
show = view_sub.add_parser("show", help="Show a GraphView")
|
|
37
|
+
show.add_argument("view_name")
|
|
38
|
+
show.add_argument("--run", default=None)
|
|
39
|
+
show.add_argument("--store-dir", default=None)
|
|
40
|
+
|
|
41
|
+
return parser
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def cli_view(args) -> int:
|
|
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}")
|
|
49
|
+
handle = store.load_run(run_id)
|
|
50
|
+
|
|
51
|
+
if args.view_command == "create":
|
|
52
|
+
user_id = resolve_user_id_from_args(args)
|
|
53
|
+
work_session_id = resolve_work_session_id_from_args(args)
|
|
54
|
+
before = graph_counts(handle)
|
|
55
|
+
view = handle.view_create(args.name, root_node_id=args.root_node)
|
|
56
|
+
handle.record_work_event(
|
|
57
|
+
user_id=user_id,
|
|
58
|
+
work_session_id=work_session_id,
|
|
59
|
+
event_type="view_created",
|
|
60
|
+
target_kind="view",
|
|
61
|
+
target_id=view.view_id,
|
|
62
|
+
created_records=(view.view_id,),
|
|
63
|
+
summary=view.name,
|
|
64
|
+
)
|
|
65
|
+
maybe_append_or_save(
|
|
66
|
+
store=store,
|
|
67
|
+
handle=handle,
|
|
68
|
+
user_id=user_id,
|
|
69
|
+
work_session_id=work_session_id,
|
|
70
|
+
before=before,
|
|
71
|
+
)
|
|
72
|
+
print(json.dumps(view.to_dict(), ensure_ascii=False, indent=2))
|
|
73
|
+
|
|
74
|
+
elif args.view_command == "list":
|
|
75
|
+
views = handle.view_list()
|
|
76
|
+
print(json.dumps([v.to_dict() for v in views], ensure_ascii=False, indent=2))
|
|
77
|
+
|
|
78
|
+
elif args.view_command == "show":
|
|
79
|
+
view = handle.view_show(args.view_name)
|
|
80
|
+
print(json.dumps(view.to_dict(), ensure_ascii=False, indent=2))
|
|
81
|
+
|
|
82
|
+
return 0
|