devin-cli 1.3.2__tar.gz → 1.3.4__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.
- {devin_cli-1.3.2 → devin_cli-1.3.4}/CHANGELOG.md +10 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/PKG-INFO +1 -1
- {devin_cli-1.3.2 → devin_cli-1.3.4}/pyproject.toml +1 -1
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v3/schedules.py +7 -7
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v3/sessions.py +3 -3
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/cli.py +9 -5
- {devin_cli-1.3.2 → devin_cli-1.3.4}/tests/test_api/test_schedules.py +2 -1
- {devin_cli-1.3.2 → devin_cli-1.3.4}/tests/test_api/test_sessions.py +1 -1
- {devin_cli-1.3.2 → devin_cli-1.3.4}/.github/workflows/pypi-publish.yml +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/.gitignore +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/LICENSE +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/README.md +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/assets/logo.png +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/generate_facades.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/setup.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/__init__.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/__init__.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/attachments.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/client.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/consumption.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/knowledge.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/members.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/organizations.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/playbooks.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/repositories.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/schedules.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/secrets.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/sessions.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v1/__init__.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v1/attachments.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v1/knowledge.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v1/playbooks.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v1/secrets.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v1/sessions.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v3/__init__.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v3/attachments.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v3/consumption.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v3/knowledge.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v3/members.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v3/organizations.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v3/playbooks.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v3/repositories.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/api/v3/secrets.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/src/devin_cli/config.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/tests/__init__.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/tests/conftest.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/tests/test_api/test_attachments.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/tests/test_api/test_knowledge.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/tests/test_api/test_playbooks.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/tests/test_api/test_repositories.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/tests/test_api/test_secrets.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/tests/test_cli.py +0 -0
- {devin_cli-1.3.2 → devin_cli-1.3.4}/tests/test_config.py +0 -0
|
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.3.4] - 2026-05-03
|
|
9
|
+
### Fixed
|
|
10
|
+
- **Scheduled Sessions API**: Updated the `schedules create` and `schedules update` commands to map the old `cron` and `title` fields to the new `frequency` and `name` properties required by the API. Added `schedule_type="recurring"` and fixed the update method to correctly use `PATCH`.
|
|
11
|
+
- CLI commands now properly read `name`, `frequency`, and `scheduled_session_id` from the API response instead of erroring out.
|
|
12
|
+
|
|
13
|
+
## [1.3.3] - 2026-04-21
|
|
14
|
+
### Fixed
|
|
15
|
+
- **ModuleNotFoundError: requests**: Replaced the leftover `requests` import and exception handling in `cli.py` with `httpx` to match project dependencies. This fixes installation errors via Homebrew and pipx.
|
|
16
|
+
- **Test Matrix**: Fixed `test_terminate_session` mock to correctly expect a `POST` request to the `/terminate` endpoint instead of `DELETE`.
|
|
17
|
+
|
|
8
18
|
## [1.3.2] - 2026-03-23
|
|
9
19
|
### Fixed
|
|
10
20
|
- **Service Token 403s**: `sessions get` and `sessions cost` now seamlessly fall back to the `list` endpoint with a `session_ids` filter to cleanly bypass 403 Forbidden errors for `cog_` Service Tokens.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devin-cli
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.4
|
|
4
4
|
Summary: Unofficial CLI for Devin AI - The first AI Software Engineer
|
|
5
5
|
Project-URL: Homepage, https://github.com/revanthpobala/devin-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/revanthpobala/devin-cli.git
|
|
@@ -19,12 +19,12 @@ def create_schedule(
|
|
|
19
19
|
):
|
|
20
20
|
data = {
|
|
21
21
|
"prompt": prompt,
|
|
22
|
-
"
|
|
22
|
+
"frequency": cron,
|
|
23
|
+
"schedule_type": "recurring",
|
|
24
|
+
"agent": "advanced" if advanced_mode else "devin",
|
|
23
25
|
}
|
|
24
26
|
if title:
|
|
25
|
-
data["
|
|
26
|
-
if advanced_mode:
|
|
27
|
-
data["advanced_mode"] = advanced_mode
|
|
27
|
+
data["name"] = title
|
|
28
28
|
if playbook_id:
|
|
29
29
|
data["playbook_id"] = playbook_id
|
|
30
30
|
if repos:
|
|
@@ -48,13 +48,13 @@ def update_schedule(
|
|
|
48
48
|
if prompt:
|
|
49
49
|
data["prompt"] = prompt
|
|
50
50
|
if cron:
|
|
51
|
-
data["
|
|
51
|
+
data["frequency"] = cron
|
|
52
52
|
if title:
|
|
53
|
-
data["
|
|
53
|
+
data["name"] = title
|
|
54
54
|
if enabled is not None:
|
|
55
55
|
data["enabled"] = enabled
|
|
56
56
|
|
|
57
|
-
return client.
|
|
57
|
+
return client.patch(f"schedules/{schedule_id}", json=data)
|
|
58
58
|
|
|
59
59
|
def delete_schedule(schedule_id: str):
|
|
60
60
|
return client.delete(f"schedules/{schedule_id}")
|
|
@@ -62,11 +62,11 @@ def create_session(
|
|
|
62
62
|
return client.post("sessions", json=data)
|
|
63
63
|
|
|
64
64
|
def get_session(session_id: str):
|
|
65
|
+
from devin_cli.api.client import APIError
|
|
65
66
|
try:
|
|
66
67
|
return client.get(f"sessions/{session_id}")
|
|
67
|
-
except
|
|
68
|
-
|
|
69
|
-
if isinstance(e, APIError) and e.status_code in (403, 404):
|
|
68
|
+
except APIError as e:
|
|
69
|
+
if e.status_code in (403, 404):
|
|
70
70
|
# Fallback to list endpoint with session_ids filter (especially for cog_ tokens)
|
|
71
71
|
res = client.get("sessions", params={"session_ids": [session_id]})
|
|
72
72
|
items = res.get("items", [])
|
|
@@ -10,7 +10,7 @@ if "--json" in sys.argv or os.environ.get("DEVIN_OUTPUT_FORMAT") == "json":
|
|
|
10
10
|
import typer
|
|
11
11
|
import time
|
|
12
12
|
import json
|
|
13
|
-
import
|
|
13
|
+
import httpx
|
|
14
14
|
import functools
|
|
15
15
|
import yaml
|
|
16
16
|
import asyncio
|
|
@@ -131,7 +131,7 @@ def handle_api_error(func):
|
|
|
131
131
|
console.print = original_print
|
|
132
132
|
if isinstance(e, typer.Exit):
|
|
133
133
|
raise e
|
|
134
|
-
elif isinstance(e,
|
|
134
|
+
elif isinstance(e, httpx.RequestError):
|
|
135
135
|
if is_json:
|
|
136
136
|
print(json.dumps({"error": "Connection error", "details": str(e)}, indent=2))
|
|
137
137
|
else:
|
|
@@ -142,7 +142,7 @@ def handle_api_error(func):
|
|
|
142
142
|
if is_json:
|
|
143
143
|
try:
|
|
144
144
|
err_json = e.response.json()
|
|
145
|
-
except:
|
|
145
|
+
except Exception:
|
|
146
146
|
err_json = {"error": str(e)}
|
|
147
147
|
print(json.dumps(err_json, indent=2))
|
|
148
148
|
else:
|
|
@@ -664,7 +664,10 @@ def list_schedules_cmd(org: Optional[str] = typer.Option(None, "--org")):
|
|
|
664
664
|
table.add_column("Title")
|
|
665
665
|
table.add_column("Cron")
|
|
666
666
|
for item in items:
|
|
667
|
-
|
|
667
|
+
schedule_id = str(item.get("id") or item.get("scheduled_session_id") or "")
|
|
668
|
+
title = str(item.get("name") or item.get("title") or "")
|
|
669
|
+
cron = str(item.get("frequency") or item.get("cron") or "")
|
|
670
|
+
table.add_row(schedule_id, title, cron)
|
|
668
671
|
console.print(table)
|
|
669
672
|
|
|
670
673
|
|
|
@@ -680,7 +683,8 @@ def create_schedule_cmd(
|
|
|
680
683
|
"""Create a recurring schedule."""
|
|
681
684
|
if org: config.temporary_org_id = org
|
|
682
685
|
resp = schedules.create_schedule(prompt=prompt, cron=cron, title=title)
|
|
683
|
-
|
|
686
|
+
schedule_id = resp.get('id') or resp.get('scheduled_session_id')
|
|
687
|
+
console.print(f"[green]Created schedule:[/green] {schedule_id}")
|
|
684
688
|
|
|
685
689
|
return resp
|
|
686
690
|
|
|
@@ -27,7 +27,8 @@ def test_create_schedule():
|
|
|
27
27
|
import json
|
|
28
28
|
body = json.loads(route.calls.last.request.read())
|
|
29
29
|
assert body["prompt"] == "test prompt"
|
|
30
|
-
assert body["
|
|
30
|
+
assert body["frequency"] == "0 0 * * *"
|
|
31
|
+
assert body["schedule_type"] == "recurring"
|
|
31
32
|
|
|
32
33
|
@respx.mock
|
|
33
34
|
def test_delete_schedule():
|
|
@@ -52,7 +52,7 @@ def test_send_message():
|
|
|
52
52
|
|
|
53
53
|
@respx.mock
|
|
54
54
|
def test_terminate_session():
|
|
55
|
-
route = respx.
|
|
55
|
+
route = respx.post("https://api.devin.ai/v3/organizations/test_org/sessions/sess_123/terminate").mock(
|
|
56
56
|
return_value=Response(204)
|
|
57
57
|
)
|
|
58
58
|
|
|
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
|
|
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
|
|
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
|