devtorch-cli 3.0.1__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.
@@ -0,0 +1,41 @@
1
+ """S29 CLI handler for `devtorch pr-report`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ from devtorch_core.github.pr_reporter import run_pr_reporter
10
+
11
+
12
+ def cmd_pr_report(args: argparse.Namespace) -> int:
13
+ project_root = Path(args.path).resolve()
14
+ gcc_dir = project_root / ".GCC"
15
+ if not gcc_dir.exists():
16
+ print(f"error: {gcc_dir} not found. Run `devtorch init` first.", file=sys.stderr)
17
+ return 1
18
+
19
+ critical_concepts = [c.strip() for c in args.critical_concepts.split(",") if c.strip()] if args.critical_concepts else []
20
+ try:
21
+ result = run_pr_reporter(
22
+ gcc_repo_path=str(project_root),
23
+ base_branch=args.base,
24
+ head_branch=args.head,
25
+ repo_owner=args.repo_owner,
26
+ repo_name=args.repo_name,
27
+ pr_number=args.pr_number,
28
+ token=args.token,
29
+ critical_concepts=critical_concepts,
30
+ min_mcs=args.min_mcs,
31
+ )
32
+ except Exception as exc:
33
+ print(f"error: {exc}", file=sys.stderr)
34
+ return 1
35
+
36
+ print(f"Posted reasoning-delta comment: {result.comment_posted}")
37
+ print(f"Merge gate: {'ALLOWED' if result.merge_gate_allowed else 'BLOCKED'}")
38
+ if result.merge_gate_reasons:
39
+ for reason in result.merge_gate_reasons:
40
+ print(f" - {reason}")
41
+ return 0 if result.merge_gate_allowed else 1
@@ -0,0 +1,40 @@
1
+ """S29 CLI handlers for `devtorch pre-commit`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ from devtorch_core.hooks.pre_commit import (
10
+ install_pre_commit_hook,
11
+ run_pre_commit_checks,
12
+ )
13
+
14
+
15
+ def _project_root(args: argparse.Namespace) -> Path:
16
+ return Path(args.path).resolve()
17
+
18
+
19
+ def cmd_pre_commit_install(args: argparse.Namespace) -> int:
20
+ project_root = _project_root(args)
21
+ try:
22
+ path = install_pre_commit_hook(project_root)
23
+ except RuntimeError as exc:
24
+ print(f"error: {exc}", file=sys.stderr)
25
+ return 1
26
+ print(f"Installed pre-commit hook at {path}")
27
+ return 0
28
+
29
+
30
+ def cmd_pre_commit_run(args: argparse.Namespace) -> int:
31
+ project_root = _project_root(args)
32
+ result = run_pre_commit_checks(project_root)
33
+ for check in result.checks:
34
+ status = "✓" if check["passed"] else "✗"
35
+ print(f"{status} {check['name']} (exit={check['exit_code']})")
36
+ if result.passed:
37
+ print("Pre-commit checks passed.")
38
+ return 0
39
+ print("Pre-commit checks failed.", file=sys.stderr)
40
+ return 1
@@ -0,0 +1,282 @@
1
+ """S28 CLI handlers for `devtorch session` and `devtorch simulate`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import sys
8
+ from pathlib import Path
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ from devtorch_core.session import (
12
+ ACTIVE,
13
+ COMPLETED,
14
+ PENDING,
15
+ AgentAssignment,
16
+ DisagreementResolver,
17
+ SessionOrchestrator,
18
+ SubtaskPlanner,
19
+ WhatIfSimulator,
20
+ )
21
+
22
+
23
+ def _gcc_dir(args: argparse.Namespace) -> Path:
24
+ return Path(args.path).resolve() / ".GCC"
25
+
26
+
27
+ def _parse_agent_assignments(raw: list[str] | None) -> List[AgentAssignment]:
28
+ assignments: List[AgentAssignment] = []
29
+ for item in raw or []:
30
+ if "=" not in item:
31
+ print(f"error: --agent must be AGENT_ID=ROLE, got: {item}", file=sys.stderr)
32
+ return []
33
+ agent_id, role = item.split("=", 1)
34
+ assignments.append(AgentAssignment(agent_id=agent_id.strip(), role=role.strip()))
35
+ return assignments
36
+
37
+
38
+ def _parse_positions(raw: list[str] | None) -> List[Dict[str, Any]]:
39
+ positions: List[Dict[str, Any]] = []
40
+ for item in raw or []:
41
+ # Format: agent=position:confidence
42
+ if "=" not in item:
43
+ print(f"error: --position must be AGENT=POSITION:CONFIDENCE, got: {item}", file=sys.stderr)
44
+ continue
45
+ agent_id, rest = item.split("=", 1)
46
+ confidence = 0.5
47
+ position = rest
48
+ if ":" in rest:
49
+ position, conf_str = rest.rsplit(":", 1)
50
+ try:
51
+ confidence = float(conf_str)
52
+ except ValueError:
53
+ pass
54
+ positions.append({"agent_id": agent_id.strip(), "position": position.strip(), "confidence": confidence})
55
+ return positions
56
+
57
+
58
+ def cmd_session_start(args: argparse.Namespace) -> int:
59
+ gcc_dir = _gcc_dir(args)
60
+ if not gcc_dir.exists():
61
+ print(f"error: {gcc_dir} not found. Run `devtorch init` first.", file=sys.stderr)
62
+ return 1
63
+ agents = _parse_agent_assignments(getattr(args, "agents", []))
64
+ orchestrator = SessionOrchestrator(gcc_dir)
65
+ session = orchestrator.start_session(
66
+ name=args.name,
67
+ problem=args.problem,
68
+ agent_assignments=agents,
69
+ )
70
+ print(f"Started session {session.session_id}: {session.name}")
71
+ print(f" status: {session.status}")
72
+ if session.agent_roles:
73
+ print(" agents:")
74
+ for a in session.agent_roles:
75
+ print(f" {a.agent_id} -> {a.role}")
76
+ return 0
77
+
78
+
79
+ def cmd_session_list(args: argparse.Namespace) -> int:
80
+ gcc_dir = _gcc_dir(args)
81
+ if not gcc_dir.exists():
82
+ print(f"error: {gcc_dir} not found. Run `devtorch init` first.", file=sys.stderr)
83
+ return 1
84
+ orchestrator = SessionOrchestrator(gcc_dir)
85
+ sessions = orchestrator.list_sessions()
86
+ if not sessions:
87
+ print("No sessions.")
88
+ return 0
89
+ print(f"{'ID':<24} {'Name':<30} {'Status':<12} {'Subtasks':>10}")
90
+ print("-" * 80)
91
+ for s in sessions:
92
+ total = len(s.subtasks)
93
+ done = sum(1 for t in s.subtasks if t.status == COMPLETED)
94
+ print(f"{s.session_id:<24} {s.name:<30} {s.status:<12} {done}/{total}")
95
+ return 0
96
+
97
+
98
+ def cmd_session_show(args: argparse.Namespace) -> int:
99
+ gcc_dir = _gcc_dir(args)
100
+ if not gcc_dir.exists():
101
+ print(f"error: {gcc_dir} not found. Run `devtorch init` first.", file=sys.stderr)
102
+ return 1
103
+ orchestrator = SessionOrchestrator(gcc_dir)
104
+ try:
105
+ session = orchestrator.get_session(args.session_id)
106
+ except FileNotFoundError:
107
+ print(f"error: session {args.session_id} not found", file=sys.stderr)
108
+ return 1
109
+ print(f"Session {session.session_id}: {session.name}")
110
+ print(f" status: {session.status}")
111
+ print(f" problem: {session.problem}")
112
+ if session.assumptions:
113
+ print(" assumptions:")
114
+ for k, v in session.assumptions.items():
115
+ print(f" {k}: {v}")
116
+ if session.agent_roles:
117
+ print(" agents:")
118
+ for a in session.agent_roles:
119
+ print(f" {a.agent_id} -> {a.role}")
120
+ if session.subtasks:
121
+ print(" subtasks:")
122
+ for t in session.subtasks:
123
+ deps = f" (depends on {', '.join(t.dependencies)})" if t.dependencies else ""
124
+ print(f" [{t.status}] {t.subtask_id}: {t.description}{deps}")
125
+ return 0
126
+
127
+
128
+ def cmd_session_plan(args: argparse.Namespace) -> int:
129
+ gcc_dir = _gcc_dir(args)
130
+ if not gcc_dir.exists():
131
+ print(f"error: {gcc_dir} not found. Run `devtorch init` first.", file=sys.stderr)
132
+ return 1
133
+ orchestrator = SessionOrchestrator(gcc_dir)
134
+ try:
135
+ session = orchestrator.get_session(args.session_id)
136
+ except FileNotFoundError:
137
+ print(f"error: session {args.session_id} not found", file=sys.stderr)
138
+ return 1
139
+ problem = args.problem or session.problem
140
+ planner = SubtaskPlanner()
141
+ subtasks = planner.plan(args.session_id, problem, orchestrator)
142
+ print(f"Planned {len(subtasks)} subtask(s) for session {args.session_id}:")
143
+ for t in subtasks:
144
+ deps = f" (depends on {', '.join(t.dependencies)})" if t.dependencies else ""
145
+ print(f" {t.subtask_id}: {t.description}{deps}")
146
+ return 0
147
+
148
+
149
+ def cmd_session_next(args: argparse.Namespace) -> int:
150
+ gcc_dir = _gcc_dir(args)
151
+ if not gcc_dir.exists():
152
+ print(f"error: {gcc_dir} not found. Run `devtorch init` first.", file=sys.stderr)
153
+ return 1
154
+ orchestrator = SessionOrchestrator(gcc_dir)
155
+ planner = SubtaskPlanner()
156
+ subtask = planner.next_subtask(args.session_id, orchestrator)
157
+ if subtask is None:
158
+ print("No pending subtasks ready.")
159
+ return 0
160
+ print(f"Next subtask: {subtask.subtask_id}")
161
+ print(f" {subtask.description}")
162
+ return 0
163
+
164
+
165
+ def cmd_session_mark(args: argparse.Namespace) -> int:
166
+ gcc_dir = _gcc_dir(args)
167
+ if not gcc_dir.exists():
168
+ print(f"error: {gcc_dir} not found. Run `devtorch init` first.", file=sys.stderr)
169
+ return 1
170
+ orchestrator = SessionOrchestrator(gcc_dir)
171
+ planner = SubtaskPlanner()
172
+ subtask = planner.mark_subtask(args.session_id, args.subtask_id, args.status, orchestrator)
173
+ if subtask is None:
174
+ print(f"error: subtask {args.subtask_id} not found", file=sys.stderr)
175
+ return 1
176
+ print(f"Marked {subtask.subtask_id} as {subtask.status}")
177
+ return 0
178
+
179
+
180
+ def cmd_session_close(args: argparse.Namespace) -> int:
181
+ gcc_dir = _gcc_dir(args)
182
+ if not gcc_dir.exists():
183
+ print(f"error: {gcc_dir} not found. Run `devtorch init` first.", file=sys.stderr)
184
+ return 1
185
+ orchestrator = SessionOrchestrator(gcc_dir)
186
+ try:
187
+ session = orchestrator.close_session(args.session_id)
188
+ except FileNotFoundError:
189
+ print(f"error: session {args.session_id} not found", file=sys.stderr)
190
+ return 1
191
+ print(f"Closed session {session.session_id} (status={session.status})")
192
+ return 0
193
+
194
+
195
+ def cmd_session_disagree(args: argparse.Namespace) -> int:
196
+ gcc_dir = _gcc_dir(args)
197
+ if not gcc_dir.exists():
198
+ print(f"error: {gcc_dir} not found. Run `devtorch init` first.", file=sys.stderr)
199
+ return 1
200
+ positions = _parse_positions(getattr(args, "positions", []))
201
+ if not positions:
202
+ print("error: at least one --position required", file=sys.stderr)
203
+ return 1
204
+ resolver = DisagreementResolver(gcc_dir)
205
+ record = resolver.record_disagreement(args.session_id, args.concept, positions)
206
+ print(f"Recorded disagreement {record.disagreement_id} on '{record.concept}'")
207
+ print(f" state: {record.state}")
208
+ for p in record.positions:
209
+ print(f" {p['agent_id']}: {p['position']} (conf={p['confidence']})")
210
+ return 0
211
+
212
+
213
+ def cmd_session_resolve(args: argparse.Namespace) -> int:
214
+ gcc_dir = _gcc_dir(args)
215
+ if not gcc_dir.exists():
216
+ print(f"error: {gcc_dir} not found. Run `devtorch init` first.", file=sys.stderr)
217
+ return 1
218
+ resolver = DisagreementResolver(gcc_dir)
219
+ try:
220
+ record = resolver.resolve(
221
+ args.disagreement_id,
222
+ human_decision=args.decision,
223
+ )
224
+ except ValueError as exc:
225
+ print(f"error: {exc}", file=sys.stderr)
226
+ return 1
227
+ print(f"Resolved disagreement {record.disagreement_id}: {record.state}")
228
+ if record.resolution:
229
+ print(f" resolution: {record.resolution}")
230
+ return 0
231
+
232
+
233
+ def cmd_session_disagreements(args: argparse.Namespace) -> int:
234
+ gcc_dir = _gcc_dir(args)
235
+ if not gcc_dir.exists():
236
+ print(f"error: {gcc_dir} not found. Run `devtorch init` first.", file=sys.stderr)
237
+ return 1
238
+ resolver = DisagreementResolver(gcc_dir)
239
+ records = resolver.list_disagreements(session_id=getattr(args, "session_id", None))
240
+ if not records:
241
+ print("No disagreements.")
242
+ return 0
243
+ print(f"{'ID':<36} {'Session':<24} {'Concept':<20} {'State':<14} {'Resolution'}")
244
+ print("-" * 100)
245
+ for r in records:
246
+ print(f"{r.disagreement_id:<36} {r.session_id:<24} {r.concept:<20} {r.state:<14} {r.resolution}")
247
+ return 0
248
+
249
+
250
+ def cmd_simulate(args: argparse.Namespace) -> int:
251
+ gcc_dir = _gcc_dir(args)
252
+ if not gcc_dir.exists():
253
+ print(f"error: {gcc_dir} not found. Run `devtorch init` first.", file=sys.stderr)
254
+ return 1
255
+ assumptions: Dict[str, Any] = {}
256
+ for item in getattr(args, "assumptions", []) or []:
257
+ if "=" not in item:
258
+ print(f"error: --assume must be KEY=VALUE, got: {item}", file=sys.stderr)
259
+ return 1
260
+ k, v = item.split("=", 1)
261
+ assumptions[k.strip()] = v.strip()
262
+ simulator = WhatIfSimulator(gcc_dir)
263
+ try:
264
+ result = simulator.simulate(args.session_id, assumptions)
265
+ except ValueError as exc:
266
+ print(f"error: {exc}", file=sys.stderr)
267
+ return 1
268
+ print(f"Simulation {result.simulation_id} for session {result.session_id}")
269
+ print(" alternate assumptions:")
270
+ for k, v in result.alternate_assumptions.items():
271
+ print(f" {k}: {v}")
272
+ print(" affected concepts:")
273
+ if result.affected_concepts:
274
+ for c in result.affected_concepts:
275
+ print(f" - {c}")
276
+ else:
277
+ print(" (none)")
278
+ print(" predicted outcome:")
279
+ print(result.predicted_outcome)
280
+ if getattr(args, "json", False):
281
+ print(json.dumps(result.to_dict(), indent=2))
282
+ return 0
@@ -0,0 +1,60 @@
1
+ Metadata-Version: 2.4
2
+ Name: devtorch-cli
3
+ Version: 3.0.1
4
+ Summary: DevTorch — command-line interface for the devtorch-core governance SDK
5
+ Author-email: Hemant Joshi <hemant@flotorch.ai>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/hemantcgi/DevTorch
8
+ Project-URL: Repository, https://github.com/hemantcgi/DevTorch
9
+ Project-URL: Documentation, https://github.com/hemantcgi/DevTorch/blob/main/Implementation/README.md
10
+ Keywords: ai,agents,governance,audit,llm,reasoning,devtorch
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: devtorch-core>=3.0.1
23
+ Provides-Extra: cloud
24
+ Requires-Dist: devtorch-core[cloud]; extra == "cloud"
25
+ Provides-Extra: mcp
26
+ Requires-Dist: devtorch-core[mcp]; extra == "mcp"
27
+ Provides-Extra: audit
28
+ Requires-Dist: devtorch-core[audit]; extra == "audit"
29
+ Provides-Extra: proxy
30
+ Requires-Dist: devtorch-core[proxy]; extra == "proxy"
31
+ Provides-Extra: wrapper
32
+ Requires-Dist: devtorch-core[wrapper]; extra == "wrapper"
33
+ Provides-Extra: embeddings
34
+ Requires-Dist: devtorch-core[embeddings]; extra == "embeddings"
35
+ Provides-Extra: broadcast
36
+ Requires-Dist: devtorch-core[broadcast]; extra == "broadcast"
37
+ Provides-Extra: dev
38
+ Requires-Dist: devtorch-core[dev]; extra == "dev"
39
+ Provides-Extra: all
40
+ Requires-Dist: devtorch-core[all]; extra == "all"
41
+
42
+ # devtorch-cli
43
+
44
+ Command-line interface for [DevTorch](https://github.com/hemantcgi/DevTorch), a local-first AI governance platform.
45
+
46
+ This package installs the `devtorch` command and depends on `devtorch-core`, which provides the governance SDK.
47
+
48
+ ## Install
49
+
50
+ ```bash
51
+ pip install devtorch-cli
52
+ ```
53
+
54
+ For the full experience including cloud sync, MCP, and IDE wrappers:
55
+
56
+ ```bash
57
+ pip install devtorch-cli[all]
58
+ ```
59
+
60
+ See the main repository README for detailed setup instructions.
@@ -0,0 +1,13 @@
1
+ devtorch_cli/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
2
+ devtorch_cli/__main__.py,sha256=yOQ0W0lH4pSVd-goEkwkH24SCS405zHwDrhsCxQqCaA,171
3
+ devtorch_cli/audit_cmds.py,sha256=ZTVB7lmB7pYCCZpuZQscmeitfvs7-9VMe9K8wP5Fkwk,8605
4
+ devtorch_cli/capability_role_cmds.py,sha256=_j9rpresbPs496hBNGUVDszg2hq_qAq9JLGS4Bnf6nw,2975
5
+ devtorch_cli/main.py,sha256=dwb2Xr7OtBNJEYk8IyU8NGeEAPADlN3venV9e1ti_0o,174178
6
+ devtorch_cli/pr_reporter_cmd.py,sha256=wb9IRAWzWWXo7-esJDaIPHJTJS9y8WoTVlE1qepHgCU,1408
7
+ devtorch_cli/pre_commit_cmds.py,sha256=w3PeUr6z2NoP_7I98E6REuGCs_0bZjdrpsIMPNEEF-o,1113
8
+ devtorch_cli/session_cmds.py,sha256=hA6YhFkMwE0-an5LK4SswvVIaKuO4h-9V98RnUlqPGs,10280
9
+ devtorch_cli-3.0.1.dist-info/METADATA,sha256=tqHM3EQuI5YTAkkGm8ujbF4bA_5rmpcrvdwp3G-UD3A,2272
10
+ devtorch_cli-3.0.1.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
11
+ devtorch_cli-3.0.1.dist-info/entry_points.txt,sha256=iimCDbtjqjoEbpySI9sfLJAsZmPkz2_nHtWoHFgMvIk,52
12
+ devtorch_cli-3.0.1.dist-info/top_level.txt,sha256=FBW8lXo3q5SicN7Y27MikpGiBsjgQ_cWXE6mOUUQBPg,13
13
+ devtorch_cli-3.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ devtorch = devtorch_cli.main:main
@@ -0,0 +1 @@
1
+ devtorch_cli