qodev-apollo-cli 1.4.0__tar.gz → 1.5.0__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.
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/CHANGELOG.md +12 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/PKG-INFO +5 -4
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/README.md +2 -1
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/pyproject.toml +2 -2
- qodev_apollo_cli-1.5.0/src/apollo_cli/commands/tasks.py +144 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/tests/test_commands.py +80 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/uv.lock +2 -2
- qodev_apollo_cli-1.4.0/src/apollo_cli/commands/tasks.py +0 -80
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/.github/workflows/ci.yml +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/.github/workflows/publish.yml +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/.gitignore +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/LICENSE +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/__init__.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/__main__.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/app.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/__init__.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/accounts.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/calls.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/contacts.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/conversations.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/custom_fields.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/deals.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/emails.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/enrich.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/install.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/jobs.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/notes.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/people.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/pipelines.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/commands/usage.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/context.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/formatters/__init__.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/formatters/accounts.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/formatters/contacts.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/formatters/conversations.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/formatters/deals.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/formatters/generic.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/formatters/people.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/help_reference.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/linkedin.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/output.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/skills/SKILL.md +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/skills/__init__.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/skills/references/__init__.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/skills/references/account-workflows.md +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/skills/references/contact-workflows.md +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/skills/references/deal-workflows.md +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/util.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/tests/conftest.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/tests/test_context.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/tests/test_conversations_formatter.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/tests/test_install.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/tests/test_linkedin.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/tests/test_output.py +0 -0
- {qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/tests/test_util.py +0 -0
|
@@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.5.0] - 2026-08-31
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `tasks create` accepts `--user-id`, `--due-at` and `--title`. Apollo rejects task
|
|
14
|
+
creation with `"Invalid user or creator id"` unless an owner is passed, and there
|
|
15
|
+
was previously no way to set a due date from the CLI at all.
|
|
16
|
+
- `tasks connect --contact-id` queues a LinkedIn connection request, **by default
|
|
17
|
+
without a message**. On a `linkedin_step_connect` task the note travels with the
|
|
18
|
+
invitation, so `--note` is omitted unless you pass one; internal context goes in
|
|
19
|
+
`--title`, which the contact never sees.
|
|
20
|
+
|
|
9
21
|
## [1.4.0] - 2026-07-10
|
|
10
22
|
|
|
11
23
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: qodev-apollo-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
4
4
|
Summary: Agent-friendly CLI for the Apollo API
|
|
5
5
|
Project-URL: Homepage, https://github.com/qodevai/apollo-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/qodevai/apollo-cli
|
|
@@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
19
19
|
Classifier: Typing :: Typed
|
|
20
20
|
Requires-Python: >=3.11
|
|
21
21
|
Requires-Dist: cyclopts>=3.0
|
|
22
|
-
Requires-Dist: qodev-apollo-api>=0.
|
|
22
|
+
Requires-Dist: qodev-apollo-api>=0.6.0
|
|
23
23
|
Requires-Dist: rich>=13.0
|
|
24
24
|
Provides-Extra: dev
|
|
25
25
|
Requires-Dist: mypy>=1.13.0; extra == 'dev'
|
|
@@ -111,7 +111,8 @@ $ qodev-apollo-cli usage
|
|
|
111
111
|
| **notes** | `search` | Search notes (`--contact-id`, `--account-id`, `--opportunity-id`) |
|
|
112
112
|
| | `create` | Create a note (`--contact-ids`, `--account-ids`, `--opportunity-ids`, `--content`) |
|
|
113
113
|
| **tasks** | `search` | Search tasks (`--type`, `--status`) |
|
|
114
|
-
| | `create` | Create a task (`--contact-ids`, `--note`, `--due-at`) |
|
|
114
|
+
| | `create` | Create a task (`--contact-ids`, `--note`, `--user-id`, `--due-at`, `--title`) |
|
|
115
|
+
| | `connect` | Queue a LinkedIn connection request, no message by default (`--contact-id`, `--note`, `--title`) |
|
|
115
116
|
| **calls** | `search` | Search call activities |
|
|
116
117
|
| **conversations** | `search` | Search recorded conversations (`--query`) |
|
|
117
118
|
| | `get` | Get a conversation with transcript and AI summary |
|
|
@@ -80,7 +80,8 @@ $ qodev-apollo-cli usage
|
|
|
80
80
|
| **notes** | `search` | Search notes (`--contact-id`, `--account-id`, `--opportunity-id`) |
|
|
81
81
|
| | `create` | Create a note (`--contact-ids`, `--account-ids`, `--opportunity-ids`, `--content`) |
|
|
82
82
|
| **tasks** | `search` | Search tasks (`--type`, `--status`) |
|
|
83
|
-
| | `create` | Create a task (`--contact-ids`, `--note`, `--due-at`) |
|
|
83
|
+
| | `create` | Create a task (`--contact-ids`, `--note`, `--user-id`, `--due-at`, `--title`) |
|
|
84
|
+
| | `connect` | Queue a LinkedIn connection request, no message by default (`--contact-id`, `--note`, `--title`) |
|
|
84
85
|
| **calls** | `search` | Search call activities |
|
|
85
86
|
| **conversations** | `search` | Search recorded conversations (`--query`) |
|
|
86
87
|
| | `get` | Get a conversation with transcript and AI summary |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "qodev-apollo-cli"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.5.0"
|
|
4
4
|
description = "Agent-friendly CLI for the Apollo API"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -20,7 +20,7 @@ classifiers = [
|
|
|
20
20
|
dependencies = [
|
|
21
21
|
"cyclopts>=3.0",
|
|
22
22
|
"rich>=13.0",
|
|
23
|
-
"qodev-apollo-api>=0.
|
|
23
|
+
"qodev-apollo-api>=0.6.0",
|
|
24
24
|
]
|
|
25
25
|
|
|
26
26
|
[project.optional-dependencies]
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""Tasks command group."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
from cyclopts import App, Parameter
|
|
8
|
+
|
|
9
|
+
from apollo_cli.context import ctx
|
|
10
|
+
from apollo_cli.formatters.generic import list_table
|
|
11
|
+
from apollo_cli.output import output, output_list
|
|
12
|
+
from apollo_cli.util import parse_comma_list
|
|
13
|
+
|
|
14
|
+
tasks_app = App(name="tasks", help="Task management.")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _task_extras(*, user_id: str | None, due_at: str | None, title: str | None) -> dict[str, str]:
|
|
18
|
+
"""Collect the optional task fields, omitting the ones left unset."""
|
|
19
|
+
extra: dict[str, str] = {}
|
|
20
|
+
if user_id is not None:
|
|
21
|
+
extra["user_id"] = user_id
|
|
22
|
+
if due_at is not None:
|
|
23
|
+
extra["due_at"] = due_at
|
|
24
|
+
if title is not None:
|
|
25
|
+
extra["title"] = title
|
|
26
|
+
return extra
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
TASK_LIST_COLUMNS = [
|
|
30
|
+
("ID", "id"),
|
|
31
|
+
("Subject", "subject"),
|
|
32
|
+
("Type", "type"),
|
|
33
|
+
("Priority", "priority"),
|
|
34
|
+
("Status", "status"),
|
|
35
|
+
("Due", "due_at"),
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@tasks_app.command
|
|
40
|
+
async def search(
|
|
41
|
+
*,
|
|
42
|
+
type: Annotated[str | None, Parameter(name="--type", help="Filter by task type (call, action_item, etc.)")] = None,
|
|
43
|
+
contact_id: Annotated[str | None, Parameter(name="--contact-id", help="Filter by contact ID")] = None,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Search tasks."""
|
|
46
|
+
filters: dict = {}
|
|
47
|
+
if type:
|
|
48
|
+
filters["task_type_cds"] = [type]
|
|
49
|
+
if contact_id:
|
|
50
|
+
filters["contact_ids"] = [contact_id]
|
|
51
|
+
|
|
52
|
+
async with ctx.client() as client:
|
|
53
|
+
result = await client.search_tasks(page=ctx.page, limit=ctx.limit, **filters)
|
|
54
|
+
|
|
55
|
+
output_list(
|
|
56
|
+
items=result.items,
|
|
57
|
+
total=result.total,
|
|
58
|
+
page=result.page,
|
|
59
|
+
limit=ctx.limit,
|
|
60
|
+
ctx=ctx,
|
|
61
|
+
format_fn=lambda items, **kw: list_table(items, TASK_LIST_COLUMNS, title="Tasks", **kw),
|
|
62
|
+
resource_name="Tasks",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@tasks_app.command
|
|
67
|
+
async def create(
|
|
68
|
+
*,
|
|
69
|
+
contact_ids: Annotated[str, Parameter(name="--contact-ids", help="Comma-separated contact IDs")],
|
|
70
|
+
note: Annotated[str | None, Parameter(name="--note", help="Task description")] = None,
|
|
71
|
+
type: Annotated[str, Parameter(name="--type", help="Task type")] = "action_item",
|
|
72
|
+
priority: Annotated[str, Parameter(name="--priority", help="Priority (high, medium, low)")] = "medium",
|
|
73
|
+
user_id: Annotated[
|
|
74
|
+
str | None,
|
|
75
|
+
Parameter(name="--user-id", help="Task owner. Apollo rejects creation without a valid owner"),
|
|
76
|
+
] = None,
|
|
77
|
+
due_at: Annotated[
|
|
78
|
+
str | None, Parameter(name="--due-at", help="Due date, ISO 8601 (e.g. 2026-09-22T08:00:00Z)")
|
|
79
|
+
] = None,
|
|
80
|
+
title: Annotated[
|
|
81
|
+
str | None, Parameter(name="--title", help="Task title shown in Apollo (internal, never sent)")
|
|
82
|
+
] = None,
|
|
83
|
+
) -> None:
|
|
84
|
+
"""Create a new task."""
|
|
85
|
+
ids = parse_comma_list(contact_ids)
|
|
86
|
+
extra = _task_extras(user_id=user_id, due_at=due_at, title=title)
|
|
87
|
+
|
|
88
|
+
async with ctx.client() as client:
|
|
89
|
+
result = await client.create_task(contact_ids=ids, note=note, type=type, priority=priority, **extra)
|
|
90
|
+
|
|
91
|
+
output(result, ctx=ctx)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@tasks_app.command
|
|
95
|
+
async def connect(
|
|
96
|
+
*,
|
|
97
|
+
contact_id: Annotated[str, Parameter(name="--contact-id", help="Contact to send the request to")],
|
|
98
|
+
note: Annotated[
|
|
99
|
+
str | None,
|
|
100
|
+
Parameter(name="--note", help="Text sent WITH the invitation. Omitted (default) = no message"),
|
|
101
|
+
] = None,
|
|
102
|
+
user_id: Annotated[
|
|
103
|
+
str | None,
|
|
104
|
+
Parameter(name="--user-id", help="Task owner. Apollo rejects creation without a valid owner"),
|
|
105
|
+
] = None,
|
|
106
|
+
due_at: Annotated[
|
|
107
|
+
str | None, Parameter(name="--due-at", help="Due date, ISO 8601 (e.g. 2026-09-22T08:00:00Z)")
|
|
108
|
+
] = None,
|
|
109
|
+
title: Annotated[
|
|
110
|
+
str | None, Parameter(name="--title", help="Task title shown in Apollo (internal, never sent)")
|
|
111
|
+
] = None,
|
|
112
|
+
priority: Annotated[str, Parameter(name="--priority", help="Priority (high, medium, low)")] = "high",
|
|
113
|
+
) -> None:
|
|
114
|
+
"""Queue a LinkedIn connection request, by default without a message.
|
|
115
|
+
|
|
116
|
+
On a linkedin_step_connect task the note travels with the invitation, so
|
|
117
|
+
--note is omitted by default and anything you pass there is seen by the
|
|
118
|
+
recipient. Put internal context in --title; the contact never sees it.
|
|
119
|
+
"""
|
|
120
|
+
extra = _task_extras(user_id=user_id, due_at=due_at, title=title)
|
|
121
|
+
|
|
122
|
+
async with ctx.client() as client:
|
|
123
|
+
result = await client.create_task(
|
|
124
|
+
contact_ids=[contact_id],
|
|
125
|
+
note=note,
|
|
126
|
+
type="linkedin_step_connect",
|
|
127
|
+
priority=priority,
|
|
128
|
+
**extra,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
output(result, ctx=ctx)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@tasks_app.command
|
|
135
|
+
async def complete(
|
|
136
|
+
id: Annotated[str, Parameter(help="Task ID")],
|
|
137
|
+
*,
|
|
138
|
+
note: Annotated[str | None, Parameter(name="--note", help="Completion note")] = None,
|
|
139
|
+
) -> None:
|
|
140
|
+
"""Mark a task as completed."""
|
|
141
|
+
async with ctx.client() as client:
|
|
142
|
+
result = await client.complete_task(id, note=note)
|
|
143
|
+
|
|
144
|
+
output(result, ctx=ctx)
|
|
@@ -726,3 +726,83 @@ class TestNotesCommands:
|
|
|
726
726
|
assert call_kwargs["contact_ids"] == ["c1"]
|
|
727
727
|
assert call_kwargs["account_ids"] == ["a1"]
|
|
728
728
|
assert call_kwargs["opportunity_ids"] == ["d1"]
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
class TestTasksCommands:
|
|
732
|
+
@pytest.mark.asyncio
|
|
733
|
+
async def test_create_passes_owner_due_and_title(self) -> None:
|
|
734
|
+
"""--user-id / --due-at / --title reach the client."""
|
|
735
|
+
mock_client = MagicMock()
|
|
736
|
+
mock_client.create_task = AsyncMock(return_value={"id": "t1"})
|
|
737
|
+
|
|
738
|
+
_ctx.ctx.configure(json_mode=True, api_key="test-key", limit=25, page=1)
|
|
739
|
+
|
|
740
|
+
with patch.object(_ctx.ctx, "client", return_value=MockAsyncContextManager(mock_client)):
|
|
741
|
+
from apollo_cli.commands.tasks import create
|
|
742
|
+
|
|
743
|
+
await create(
|
|
744
|
+
contact_ids="c1",
|
|
745
|
+
note="Follow up",
|
|
746
|
+
user_id="u1",
|
|
747
|
+
due_at="2026-09-22T08:00:00Z",
|
|
748
|
+
title="Internal title",
|
|
749
|
+
)
|
|
750
|
+
|
|
751
|
+
kwargs = mock_client.create_task.call_args.kwargs
|
|
752
|
+
assert kwargs["user_id"] == "u1"
|
|
753
|
+
assert kwargs["due_at"] == "2026-09-22T08:00:00Z"
|
|
754
|
+
assert kwargs["title"] == "Internal title"
|
|
755
|
+
|
|
756
|
+
@pytest.mark.asyncio
|
|
757
|
+
async def test_create_omits_unset_optionals(self) -> None:
|
|
758
|
+
"""Optional task fields stay out of the call when not given."""
|
|
759
|
+
mock_client = MagicMock()
|
|
760
|
+
mock_client.create_task = AsyncMock(return_value={"id": "t2"})
|
|
761
|
+
|
|
762
|
+
_ctx.ctx.configure(json_mode=True, api_key="test-key", limit=25, page=1)
|
|
763
|
+
|
|
764
|
+
with patch.object(_ctx.ctx, "client", return_value=MockAsyncContextManager(mock_client)):
|
|
765
|
+
from apollo_cli.commands.tasks import create
|
|
766
|
+
|
|
767
|
+
await create(contact_ids="c1")
|
|
768
|
+
|
|
769
|
+
kwargs = mock_client.create_task.call_args.kwargs
|
|
770
|
+
assert kwargs["note"] is None
|
|
771
|
+
assert "user_id" not in kwargs
|
|
772
|
+
assert "due_at" not in kwargs
|
|
773
|
+
assert "title" not in kwargs
|
|
774
|
+
|
|
775
|
+
@pytest.mark.asyncio
|
|
776
|
+
async def test_connect_sends_empty_note(self) -> None:
|
|
777
|
+
"""A connection request carries no message and defaults to high priority."""
|
|
778
|
+
mock_client = MagicMock()
|
|
779
|
+
mock_client.create_task = AsyncMock(return_value={"id": "t3"})
|
|
780
|
+
|
|
781
|
+
_ctx.ctx.configure(json_mode=True, api_key="test-key", limit=25, page=1)
|
|
782
|
+
|
|
783
|
+
with patch.object(_ctx.ctx, "client", return_value=MockAsyncContextManager(mock_client)):
|
|
784
|
+
from apollo_cli.commands.tasks import connect
|
|
785
|
+
|
|
786
|
+
await connect(contact_id="c1", user_id="u1", title="Connect Jane Doe")
|
|
787
|
+
|
|
788
|
+
kwargs = mock_client.create_task.call_args.kwargs
|
|
789
|
+
assert kwargs["contact_ids"] == ["c1"]
|
|
790
|
+
assert kwargs["note"] is None
|
|
791
|
+
assert kwargs["type"] == "linkedin_step_connect"
|
|
792
|
+
assert kwargs["priority"] == "high"
|
|
793
|
+
assert kwargs["title"] == "Connect Jane Doe"
|
|
794
|
+
|
|
795
|
+
@pytest.mark.asyncio
|
|
796
|
+
async def test_connect_forwards_a_note_when_given(self) -> None:
|
|
797
|
+
"""--note is supported; it travels with the invitation when supplied."""
|
|
798
|
+
mock_client = MagicMock()
|
|
799
|
+
mock_client.create_task = AsyncMock(return_value={"id": "t4"})
|
|
800
|
+
|
|
801
|
+
_ctx.ctx.configure(json_mode=True, api_key="test-key", limit=25, page=1)
|
|
802
|
+
|
|
803
|
+
with patch.object(_ctx.ctx, "client", return_value=MockAsyncContextManager(mock_client)):
|
|
804
|
+
from apollo_cli.commands.tasks import connect
|
|
805
|
+
|
|
806
|
+
await connect(contact_id="c1", note="Hi Jane, ...")
|
|
807
|
+
|
|
808
|
+
assert mock_client.create_task.call_args.kwargs["note"] == "Hi Jane, ..."
|
|
@@ -472,7 +472,7 @@ wheels = [
|
|
|
472
472
|
|
|
473
473
|
[[package]]
|
|
474
474
|
name = "qodev-apollo-api"
|
|
475
|
-
version = "0.
|
|
475
|
+
version = "0.6.0"
|
|
476
476
|
source = { directory = "../apollo-api" }
|
|
477
477
|
dependencies = [
|
|
478
478
|
{ name = "httpx" },
|
|
@@ -494,7 +494,7 @@ provides-extras = ["dev"]
|
|
|
494
494
|
|
|
495
495
|
[[package]]
|
|
496
496
|
name = "qodev-apollo-cli"
|
|
497
|
-
version = "1.
|
|
497
|
+
version = "1.5.0"
|
|
498
498
|
source = { editable = "." }
|
|
499
499
|
dependencies = [
|
|
500
500
|
{ name = "cyclopts" },
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
"""Tasks command group."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from typing import Annotated
|
|
6
|
-
|
|
7
|
-
from cyclopts import App, Parameter
|
|
8
|
-
|
|
9
|
-
from apollo_cli.context import ctx
|
|
10
|
-
from apollo_cli.formatters.generic import list_table
|
|
11
|
-
from apollo_cli.output import output, output_list
|
|
12
|
-
from apollo_cli.util import parse_comma_list
|
|
13
|
-
|
|
14
|
-
tasks_app = App(name="tasks", help="Task management.")
|
|
15
|
-
|
|
16
|
-
TASK_LIST_COLUMNS = [
|
|
17
|
-
("ID", "id"),
|
|
18
|
-
("Subject", "subject"),
|
|
19
|
-
("Type", "type"),
|
|
20
|
-
("Priority", "priority"),
|
|
21
|
-
("Status", "status"),
|
|
22
|
-
("Due", "due_at"),
|
|
23
|
-
]
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@tasks_app.command
|
|
27
|
-
async def search(
|
|
28
|
-
*,
|
|
29
|
-
type: Annotated[str | None, Parameter(name="--type", help="Filter by task type (call, action_item, etc.)")] = None,
|
|
30
|
-
contact_id: Annotated[str | None, Parameter(name="--contact-id", help="Filter by contact ID")] = None,
|
|
31
|
-
) -> None:
|
|
32
|
-
"""Search tasks."""
|
|
33
|
-
filters: dict = {}
|
|
34
|
-
if type:
|
|
35
|
-
filters["task_type_cds"] = [type]
|
|
36
|
-
if contact_id:
|
|
37
|
-
filters["contact_ids"] = [contact_id]
|
|
38
|
-
|
|
39
|
-
async with ctx.client() as client:
|
|
40
|
-
result = await client.search_tasks(page=ctx.page, limit=ctx.limit, **filters)
|
|
41
|
-
|
|
42
|
-
output_list(
|
|
43
|
-
items=result.items,
|
|
44
|
-
total=result.total,
|
|
45
|
-
page=result.page,
|
|
46
|
-
limit=ctx.limit,
|
|
47
|
-
ctx=ctx,
|
|
48
|
-
format_fn=lambda items, **kw: list_table(items, TASK_LIST_COLUMNS, title="Tasks", **kw),
|
|
49
|
-
resource_name="Tasks",
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
@tasks_app.command
|
|
54
|
-
async def create(
|
|
55
|
-
*,
|
|
56
|
-
contact_ids: Annotated[str, Parameter(name="--contact-ids", help="Comma-separated contact IDs")],
|
|
57
|
-
note: Annotated[str, Parameter(name="--note", help="Task description")],
|
|
58
|
-
type: Annotated[str, Parameter(name="--type", help="Task type")] = "action_item",
|
|
59
|
-
priority: Annotated[str, Parameter(name="--priority", help="Priority (high, medium, low)")] = "medium",
|
|
60
|
-
) -> None:
|
|
61
|
-
"""Create a new task."""
|
|
62
|
-
ids = parse_comma_list(contact_ids)
|
|
63
|
-
|
|
64
|
-
async with ctx.client() as client:
|
|
65
|
-
result = await client.create_task(contact_ids=ids, note=note, type=type, priority=priority)
|
|
66
|
-
|
|
67
|
-
output(result, ctx=ctx)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
@tasks_app.command
|
|
71
|
-
async def complete(
|
|
72
|
-
id: Annotated[str, Parameter(help="Task ID")],
|
|
73
|
-
*,
|
|
74
|
-
note: Annotated[str | None, Parameter(name="--note", help="Completion note")] = None,
|
|
75
|
-
) -> None:
|
|
76
|
-
"""Mark a task as completed."""
|
|
77
|
-
async with ctx.client() as client:
|
|
78
|
-
result = await client.complete_task(id, note=note)
|
|
79
|
-
|
|
80
|
-
output(result, ctx=ctx)
|
|
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
|
{qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/formatters/conversations.py
RENAMED
|
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
|
{qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/skills/references/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qodev_apollo_cli-1.4.0 → qodev_apollo_cli-1.5.0}/src/apollo_cli/skills/references/deal-workflows.md
RENAMED
|
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
|