devin-cli 1.1.9__tar.gz → 1.2.1__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.1.9 → devin_cli-1.2.1}/CHANGELOG.md +9 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/PKG-INFO +1 -1
- {devin_cli-1.1.9 → devin_cli-1.2.1}/pyproject.toml +1 -1
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v1/sessions.py +13 -8
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v3/sessions.py +3 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/cli.py +44 -8
- {devin_cli-1.1.9 → devin_cli-1.2.1}/.github/workflows/pypi-publish.yml +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/.gitignore +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/LICENSE +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/README.md +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/assets/logo.png +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/generate_facades.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/setup.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/__init__.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/__init__.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/attachments.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/client.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/consumption.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/knowledge.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/members.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/organizations.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/playbooks.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/repositories.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/schedules.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/secrets.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/sessions.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v1/__init__.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v1/attachments.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v1/knowledge.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v1/playbooks.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v1/secrets.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v3/__init__.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v3/attachments.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v3/consumption.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v3/knowledge.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v3/members.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v3/organizations.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v3/playbooks.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v3/repositories.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v3/schedules.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/api/v3/secrets.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/src/devin_cli/config.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/tests/__init__.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/tests/conftest.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/tests/test_api/test_attachments.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/tests/test_api/test_knowledge.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/tests/test_api/test_playbooks.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/tests/test_api/test_repositories.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/tests/test_api/test_schedules.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/tests/test_api/test_secrets.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/tests/test_api/test_sessions.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/tests/test_cli.py +0 -0
- {devin_cli-1.1.9 → devin_cli-1.2.1}/tests/test_config.py +0 -0
|
@@ -5,6 +5,15 @@ 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.2.0] - 2026-03-11
|
|
9
|
+
### Added
|
|
10
|
+
- `sessions create` / `create-session` now exposes all 8 previously missing v3 API parameters: `--playbook-id`, `--tag`, `--repo`, `--knowledge-id`, `--secret-id`, `--session-link`, `--attachment-url`, `--create-as-user-id`.
|
|
11
|
+
- Profile feedback on session create: prints which profile and API version is being used.
|
|
12
|
+
- Explicit warning when v3-only flags (`--advanced-mode`, `--playbook-id`, `--repo`, `--secret-id`, `--session-link`, `--attachment-url`, `--create-as-user-id`) are passed on a v1 profile — instead of silently ignored.
|
|
13
|
+
### Fixed
|
|
14
|
+
- Removed `**kwargs` anti-pattern from `v1/sessions.create_session`. Typos in keyword args now raise `TypeError` instead of silently vanishing.
|
|
15
|
+
- v3-only params added as explicit no-ops in v1 `create_session` so the shared CLI call site works without `TypeError`.
|
|
16
|
+
|
|
8
17
|
## [1.1.9] - 2026-03-11
|
|
9
18
|
### Fixed
|
|
10
19
|
- `devin watch` terminal status message was printed inside a `Live` context, causing output corruption. Now printed after the `Live` block exits.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devin-cli
|
|
3
|
-
Version: 1.1
|
|
3
|
+
Version: 1.2.1
|
|
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
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import List, Optional
|
|
2
2
|
from devin_cli.api.client import client
|
|
3
3
|
|
|
4
|
-
def list_sessions(limit: int = 100, offset: int = 0, tags: List[str] = None):
|
|
4
|
+
def list_sessions(limit: int = 100, offset: int = 0, tags: Optional[List[str]] = None):
|
|
5
5
|
params = {"limit": limit, "offset": offset}
|
|
6
6
|
if tags:
|
|
7
7
|
params["tags"] = tags
|
|
@@ -10,21 +10,26 @@ def list_sessions(limit: int = 100, offset: int = 0, tags: List[str] = None):
|
|
|
10
10
|
def create_session(
|
|
11
11
|
prompt: str,
|
|
12
12
|
idempotent: bool = False,
|
|
13
|
-
snapshot_id: str = None,
|
|
14
|
-
playbook_id: str = None,
|
|
13
|
+
snapshot_id: Optional[str] = None,
|
|
14
|
+
playbook_id: Optional[str] = None,
|
|
15
15
|
unlisted: bool = False,
|
|
16
|
-
tags: List[str] = None,
|
|
17
|
-
session_secrets: List[dict] = None,
|
|
16
|
+
tags: Optional[List[str]] = None,
|
|
17
|
+
session_secrets: Optional[List[dict]] = None,
|
|
18
18
|
title: Optional[str] = None,
|
|
19
19
|
knowledge_ids: Optional[List[str]] = None,
|
|
20
20
|
secret_ids: Optional[List[str]] = None,
|
|
21
21
|
max_acu_limit: Optional[int] = None,
|
|
22
|
-
|
|
22
|
+
advanced_mode: Optional[str] = None,
|
|
23
|
+
repos: Optional[List[str]] = None,
|
|
24
|
+
session_links: Optional[List[str]] = None,
|
|
25
|
+
attachment_urls: Optional[List[str]] = None,
|
|
26
|
+
create_as_user_id: Optional[str] = None,
|
|
27
|
+
child_playbook_id: Optional[str] = None,
|
|
23
28
|
):
|
|
24
29
|
data = {
|
|
25
30
|
"prompt": prompt,
|
|
26
31
|
"idempotent": idempotent,
|
|
27
|
-
"unlisted": unlisted
|
|
32
|
+
"unlisted": unlisted,
|
|
28
33
|
}
|
|
29
34
|
if snapshot_id:
|
|
30
35
|
data["snapshot_id"] = snapshot_id
|
|
@@ -42,7 +47,7 @@ def create_session(
|
|
|
42
47
|
data["secret_ids"] = secret_ids
|
|
43
48
|
if max_acu_limit:
|
|
44
49
|
data["max_acu_limit"] = max_acu_limit
|
|
45
|
-
|
|
50
|
+
|
|
46
51
|
return client.post("sessions", json=data)
|
|
47
52
|
|
|
48
53
|
def get_session(session_id: str):
|
|
@@ -15,6 +15,7 @@ def create_session(
|
|
|
15
15
|
knowledge_ids: Optional[List[str]] = None,
|
|
16
16
|
max_acu_limit: Optional[int] = None,
|
|
17
17
|
playbook_id: Optional[str] = None,
|
|
18
|
+
child_playbook_id: Optional[str] = None,
|
|
18
19
|
repos: Optional[List[str]] = None,
|
|
19
20
|
secret_ids: Optional[List[str]] = None,
|
|
20
21
|
session_links: Optional[List[str]] = None,
|
|
@@ -37,6 +38,8 @@ def create_session(
|
|
|
37
38
|
data["max_acu_limit"] = max_acu_limit
|
|
38
39
|
if playbook_id:
|
|
39
40
|
data["playbook_id"] = playbook_id
|
|
41
|
+
if child_playbook_id:
|
|
42
|
+
data["child_playbook_id"] = child_playbook_id
|
|
40
43
|
if repos:
|
|
41
44
|
data["repos"] = repos
|
|
42
45
|
if secret_ids:
|
|
@@ -155,13 +155,39 @@ def create_session_cmd(
|
|
|
155
155
|
title: Optional[str] = typer.Option(None, "--title", "-t", help="Custom session title"),
|
|
156
156
|
org: Optional[str] = typer.Option(None, "--org", help="Override organization ID"),
|
|
157
157
|
max_acu: Optional[int] = typer.Option(None, "--max-acu", help="Maximum ACU limit"),
|
|
158
|
-
advanced_mode: Optional[str] = typer.Option(None, "--advanced-mode", help="
|
|
158
|
+
advanced_mode: Optional[str] = typer.Option(None, "--advanced-mode", help="Advanced mode type: analyze | create_playbook | improve_playbook | batch | manage_knowledge"),
|
|
159
|
+
playbook_id: Optional[str] = typer.Option(None, "--playbook-id", help="Playbook ID to apply (v3 only)"),
|
|
160
|
+
child_playbook_id: Optional[str] = typer.Option(None, "--child-playbook-id", help="Playbook ID applied to each sub-session in batch mode (v3 only)"),
|
|
161
|
+
tags: Optional[List[str]] = typer.Option(None, "--tag", help="Session tags (repeatable)"),
|
|
162
|
+
repos: Optional[List[str]] = typer.Option(None, "--repo", help="Repository URLs to attach (v3 only, repeatable)"),
|
|
163
|
+
knowledge_ids: Optional[List[str]] = typer.Option(None, "--knowledge-id", help="Knowledge IDs to attach (repeatable)"),
|
|
164
|
+
secret_ids: Optional[List[str]] = typer.Option(None, "--secret-id", help="Secret IDs to inject (v3 only, repeatable)"),
|
|
165
|
+
session_links: Optional[List[str]] = typer.Option(None, "--session-link", help="Session URLs to link as context (v3 only, repeatable)"),
|
|
166
|
+
attachment_urls: Optional[List[str]] = typer.Option(None, "--attachment-url", help="Attachment URLs to attach (v3 only, repeatable)"),
|
|
167
|
+
create_as_user_id: Optional[str] = typer.Option(None, "--create-as-user-id", help="Enterprise: create session on behalf of this user ID (v3 only)"),
|
|
159
168
|
force: bool = typer.Option(False, "--force", help="Force creation even if duplicate prompt is detected"),
|
|
160
169
|
wait: bool = typer.Option(False, "--wait", "-w", help="Block until the session reaches a terminal status"),
|
|
161
170
|
interval: int = typer.Option(5, "--interval", help="Polling interval in seconds when --wait is used"),
|
|
162
171
|
):
|
|
163
172
|
"""Create a new Devin session."""
|
|
164
173
|
if org: config.temporary_org_id = org
|
|
174
|
+
|
|
175
|
+
api_ver = config.api_version
|
|
176
|
+
console.print(f"[dim]Using profile: {config.active_profile or 'default'} ({api_ver})[/dim]")
|
|
177
|
+
|
|
178
|
+
v3_only_used = [x for x, v in [
|
|
179
|
+
("--advanced-mode", advanced_mode),
|
|
180
|
+
("--playbook-id", playbook_id),
|
|
181
|
+
("--repos", repos),
|
|
182
|
+
("--secret-ids", secret_ids),
|
|
183
|
+
("--session-links", session_links),
|
|
184
|
+
("--attachment-urls", attachment_urls),
|
|
185
|
+
("--create-as-user-id", create_as_user_id),
|
|
186
|
+
] if v]
|
|
187
|
+
if api_ver == "v1" and v3_only_used:
|
|
188
|
+
console.print(f"[bold yellow]Warning:[/bold yellow] The following flags are v3-only and will be ignored on a v1 profile: {', '.join(v3_only_used)}")
|
|
189
|
+
console.print(" Run [bold cyan]devin configure[/bold cyan] to switch to a v3 profile.")
|
|
190
|
+
|
|
165
191
|
if file:
|
|
166
192
|
prompt_text = file.read_text()
|
|
167
193
|
elif prompt:
|
|
@@ -169,10 +195,10 @@ def create_session_cmd(
|
|
|
169
195
|
else:
|
|
170
196
|
console.print("[bold red]Error:[/bold red] Must provide prompt or --file")
|
|
171
197
|
raise typer.Exit(1)
|
|
172
|
-
|
|
198
|
+
|
|
173
199
|
prompt_hash = hashlib.sha256(prompt_text.encode('utf-8')).hexdigest()
|
|
174
200
|
existing_sid = config.get_session_by_prompt_hash(prompt_hash)
|
|
175
|
-
|
|
201
|
+
|
|
176
202
|
if existing_sid and not force:
|
|
177
203
|
console.print(f"[bold yellow]Duplicate Detected:[/bold yellow] You recently created a session with this exact prompt.")
|
|
178
204
|
console.print(f"Existing Session ID: [bold cyan]{existing_sid}[/bold cyan]")
|
|
@@ -182,13 +208,22 @@ def create_session_cmd(
|
|
|
182
208
|
|
|
183
209
|
with console.status("[bold green]Creating session...[/bold green]"):
|
|
184
210
|
resp = sessions.create_session(
|
|
185
|
-
prompt=prompt_text,
|
|
186
|
-
title=title,
|
|
211
|
+
prompt=prompt_text,
|
|
212
|
+
title=title,
|
|
187
213
|
max_acu_limit=max_acu,
|
|
188
|
-
advanced_mode=advanced_mode
|
|
214
|
+
advanced_mode=advanced_mode,
|
|
215
|
+
playbook_id=playbook_id,
|
|
216
|
+
child_playbook_id=child_playbook_id,
|
|
217
|
+
tags=tags or None,
|
|
218
|
+
repos=repos or None,
|
|
219
|
+
knowledge_ids=knowledge_ids or None,
|
|
220
|
+
secret_ids=secret_ids or None,
|
|
221
|
+
session_links=session_links or None,
|
|
222
|
+
attachment_urls=attachment_urls or None,
|
|
223
|
+
create_as_user_id=create_as_user_id,
|
|
189
224
|
)
|
|
190
225
|
sid = resp.get("session_id")
|
|
191
|
-
|
|
226
|
+
|
|
192
227
|
if "advanced_mode_url" in resp:
|
|
193
228
|
adv_url = resp["advanced_mode_url"]
|
|
194
229
|
console.print(f"[bold yellow]Advanced Mode Authorization Required![/bold yellow]")
|
|
@@ -197,7 +232,7 @@ def create_session_cmd(
|
|
|
197
232
|
if typer.confirm("Open browser now?"):
|
|
198
233
|
import webbrowser
|
|
199
234
|
webbrowser.open(adv_url)
|
|
200
|
-
|
|
235
|
+
|
|
201
236
|
if sid:
|
|
202
237
|
config.current_session_id = sid
|
|
203
238
|
config.save_prompt_hash(prompt_hash, sid)
|
|
@@ -219,6 +254,7 @@ def create_session_cmd(
|
|
|
219
254
|
else:
|
|
220
255
|
console.print("[yellow]Session created, but no ID returned immediately (awaiting advanced mode setup).[/yellow]")
|
|
221
256
|
|
|
257
|
+
|
|
222
258
|
@session_app.command("list")
|
|
223
259
|
@handle_api_error
|
|
224
260
|
def list_sessions_cmd(
|
|
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
|
|
File without changes
|
|
File without changes
|