devin-cli 1.1.8__tar.gz → 1.1.9__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.8 → devin_cli-1.1.9}/CHANGELOG.md +6 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/PKG-INFO +1 -1
- {devin_cli-1.1.8 → devin_cli-1.1.9}/pyproject.toml +1 -1
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/cli.py +44 -7
- {devin_cli-1.1.8 → devin_cli-1.1.9}/.github/workflows/pypi-publish.yml +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/.gitignore +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/LICENSE +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/README.md +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/assets/logo.png +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/generate_facades.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/setup.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/__init__.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/__init__.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/attachments.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/client.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/consumption.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/knowledge.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/members.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/organizations.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/playbooks.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/repositories.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/schedules.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/secrets.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/sessions.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v1/__init__.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v1/attachments.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v1/knowledge.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v1/playbooks.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v1/secrets.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v1/sessions.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v3/__init__.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v3/attachments.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v3/consumption.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v3/knowledge.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v3/members.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v3/organizations.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v3/playbooks.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v3/repositories.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v3/schedules.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v3/secrets.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/api/v3/sessions.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/src/devin_cli/config.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/tests/__init__.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/tests/conftest.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/tests/test_api/test_attachments.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/tests/test_api/test_knowledge.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/tests/test_api/test_playbooks.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/tests/test_api/test_repositories.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/tests/test_api/test_schedules.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/tests/test_api/test_secrets.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/tests/test_api/test_sessions.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/tests/test_cli.py +0 -0
- {devin_cli-1.1.8 → devin_cli-1.1.9}/tests/test_config.py +0 -0
|
@@ -5,6 +5,12 @@ 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.1.9] - 2026-03-11
|
|
9
|
+
### Fixed
|
|
10
|
+
- `devin watch` terminal status message was printed inside a `Live` context, causing output corruption. Now printed after the `Live` block exits.
|
|
11
|
+
- `update-playbook` was sending an empty string title when `--title` was not passed, overwriting the existing playbook title. Now only sends fields that are explicitly provided.
|
|
12
|
+
- `chain` used bare `resp["session_id"]` key access which would raise `KeyError` on unexpected API responses. Now uses `.get()` with an explicit error guard.
|
|
13
|
+
|
|
8
14
|
## [1.1.8] - 2026-03-11
|
|
9
15
|
### Added
|
|
10
16
|
- Restored all 0.1.x flat commands: `watch`, `status`, `open`, `message`, `terminate`, `list-sessions`, `create-session`, `upload`, `list-knowledge`, `attach`, `update-tags`, `history`, `messages`, `get-session`, `update-knowledge`, `update-playbook`, `delete-playbook`, `list-secrets`, `delete-secret`, `chain`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devin-cli
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.9
|
|
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
|
|
@@ -299,14 +299,25 @@ def session_cost_cmd(
|
|
|
299
299
|
@session_app.command("message")
|
|
300
300
|
@handle_api_error
|
|
301
301
|
def send_message_cmd(
|
|
302
|
-
text: str = typer.Argument(
|
|
302
|
+
text: Optional[str] = typer.Argument(None, help="Message text"),
|
|
303
|
+
file: Optional[Path] = typer.Option(None, "--file", "-f", help="Read message from file"),
|
|
303
304
|
session_id: Optional[str] = typer.Option(None, "--id"),
|
|
304
305
|
org: Optional[str] = typer.Option(None, "--org"),
|
|
305
306
|
):
|
|
306
307
|
"""Send a message to a session."""
|
|
307
308
|
if org: config.temporary_org_id = org
|
|
308
309
|
sid = session_id or get_current_session_id()
|
|
309
|
-
|
|
310
|
+
if file:
|
|
311
|
+
if not file.exists():
|
|
312
|
+
console.print(f"[bold red]Error:[/bold red] File not found: {file}")
|
|
313
|
+
raise typer.Exit(1)
|
|
314
|
+
msg_text = file.read_text()
|
|
315
|
+
elif text:
|
|
316
|
+
msg_text = text
|
|
317
|
+
else:
|
|
318
|
+
console.print("[bold red]Error:[/bold red] Provide message text or --file")
|
|
319
|
+
raise typer.Exit(1)
|
|
320
|
+
sessions.send_message(sid, msg_text)
|
|
310
321
|
console.print(f"[green]Message sent to {sid}[/green]")
|
|
311
322
|
|
|
312
323
|
@session_app.command("messages")
|
|
@@ -708,13 +719,15 @@ def watch_session_cmd(
|
|
|
708
719
|
|
|
709
720
|
if resp.get("status_enum", "").lower() in terminal_statuses:
|
|
710
721
|
live.update(build_status_panel(resp))
|
|
711
|
-
console.print(f"[bold green]Session {resp.get('status_enum')}![/bold green]")
|
|
712
722
|
break
|
|
713
723
|
|
|
714
724
|
time.sleep(min(backoff, 30))
|
|
715
725
|
backoff = min(backoff * 1.5, 30)
|
|
716
726
|
except KeyboardInterrupt:
|
|
717
727
|
console.print("\n[dim]Watch stopped.[/dim]")
|
|
728
|
+
return
|
|
729
|
+
|
|
730
|
+
console.print(f"[bold green]Session {resp.get('status_enum')}![/bold green]")
|
|
718
731
|
|
|
719
732
|
# --- Flat top-level aliases (backward compat with 0.1.x command structure) ---
|
|
720
733
|
|
|
@@ -730,12 +743,23 @@ def watch_cmd(
|
|
|
730
743
|
@app.command("message")
|
|
731
744
|
@handle_api_error
|
|
732
745
|
def message_cmd(
|
|
733
|
-
text: str = typer.Argument(
|
|
746
|
+
text: Optional[str] = typer.Argument(None, help="Message to send"),
|
|
747
|
+
file: Optional[Path] = typer.Option(None, "--file", "-f", help="Read message from file"),
|
|
734
748
|
session_id: Optional[str] = typer.Option(None, "--id"),
|
|
735
749
|
):
|
|
736
750
|
"""Send a message to the active session."""
|
|
737
751
|
sid = session_id or get_current_session_id()
|
|
738
|
-
|
|
752
|
+
if file:
|
|
753
|
+
if not file.exists():
|
|
754
|
+
console.print(f"[bold red]Error:[/bold red] File not found: {file}")
|
|
755
|
+
raise typer.Exit(1)
|
|
756
|
+
msg_text = file.read_text()
|
|
757
|
+
elif text:
|
|
758
|
+
msg_text = text
|
|
759
|
+
else:
|
|
760
|
+
console.print("[bold red]Error:[/bold red] Provide message text or --file")
|
|
761
|
+
raise typer.Exit(1)
|
|
762
|
+
sessions.send_message(sid, msg_text)
|
|
739
763
|
console.print(f"[green]Message sent to {sid}[/green]")
|
|
740
764
|
|
|
741
765
|
@app.command("terminate")
|
|
@@ -895,6 +919,16 @@ def update_playbook_top_cmd(
|
|
|
895
919
|
macro: Optional[str] = typer.Option(None, "--macro"),
|
|
896
920
|
):
|
|
897
921
|
"""Update an existing playbook."""
|
|
922
|
+
data: dict = {}
|
|
923
|
+
if title is not None:
|
|
924
|
+
data["title"] = title
|
|
925
|
+
if body is not None:
|
|
926
|
+
data["body"] = body
|
|
927
|
+
if macro is not None:
|
|
928
|
+
data["macro"] = macro
|
|
929
|
+
if not data:
|
|
930
|
+
console.print("[yellow]Nothing to update. Pass --title, --body, or --macro.[/yellow]")
|
|
931
|
+
return
|
|
898
932
|
playbooks.update_playbook(playbook_id, title=title or "", body=body, macro=macro)
|
|
899
933
|
console.print(f"[green]Playbook {playbook_id} updated.[/green]")
|
|
900
934
|
|
|
@@ -971,9 +1005,12 @@ def chain_cmd(
|
|
|
971
1005
|
console.print(f"[bold cyan]Step {i+1}/{len(steps)}:[/bold cyan] Playbook={step_pb}")
|
|
972
1006
|
|
|
973
1007
|
if i == 0:
|
|
974
|
-
with console.status(
|
|
1008
|
+
with console.status("Starting session..."):
|
|
975
1009
|
resp = sessions.create_session(prompt=step_prompt, playbook_id=step_pb)
|
|
976
|
-
current_sid = resp
|
|
1010
|
+
current_sid = resp.get("session_id")
|
|
1011
|
+
if not current_sid:
|
|
1012
|
+
console.print("[bold red]Error:[/bold red] No session ID returned from API.")
|
|
1013
|
+
raise typer.Exit(1)
|
|
977
1014
|
config.current_session_id = current_sid
|
|
978
1015
|
console.print(f"[green]Session started:[/green] {current_sid}")
|
|
979
1016
|
else:
|
|
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
|
|
File without changes
|
|
File without changes
|