dailybot-cli 3.2.2__tar.gz → 3.4.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.
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/PKG-INFO +1 -1
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/api_client.py +20 -2
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/checkin.py +1 -1
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/conversation.py +21 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/form.py +53 -3
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/query_options.py +6 -1
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/status.py +12 -1
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/config.py +18 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/display.py +4 -1
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/main.py +10 -2
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli.egg-info/PKG-INFO +1 -1
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/pyproject.toml +1 -1
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/LICENSE +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/README.md +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/__init__.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/__init__.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/agent.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/ask.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/auth.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/authoring_helpers.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/channels.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/chat.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/config.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/hook.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/identity.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/interactive.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/interactive_chat.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/kudos.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/public_api_helpers.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/team.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/uninstall.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/update.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/upgrade.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/user.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/user_scoped_actions.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/version.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/commands/workflow.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/install_method.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/ledger.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/tui/__init__.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/tui/app.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/tui/commands.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/tui/conversation.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli/tui/intents.py +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli.egg-info/SOURCES.txt +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli.egg-info/dependency_links.txt +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli.egg-info/entry_points.txt +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli.egg-info/requires.txt +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/dailybot_cli.egg-info/top_level.txt +0 -0
- {dailybot_cli-3.2.2 → dailybot_cli-3.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dailybot-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.0
|
|
4
4
|
Summary: Dailybot CLI - The command-line bridge between humans and agents. Progress reports, observability, and workflow automation for modern teams across Slack, Google Chat, Discord, MS Teams, and more.
|
|
5
5
|
Author-email: Dailybot <support@dailybot.com>
|
|
6
6
|
License: MIT
|
|
@@ -19,6 +19,7 @@ DEFAULT_RETRY_AFTER_SECS: float = 1.0 # backoff floor when a 429 omits Retry-Af
|
|
|
19
19
|
FREE_PLAN_DAILY_LIMIT_CODE: str = "free_plan_daily_limit_exceeded"
|
|
20
20
|
|
|
21
21
|
MAX_FALLBACK_DETAIL_CHARS: int = 160 # cap for a non-JSON error body echoed to the user
|
|
22
|
+
MAX_SEARCH_QUERY_LENGTH: int = 256 # server rejects search queries longer than this
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
def _fallback_detail(response: httpx.Response) -> str:
|
|
@@ -67,8 +68,20 @@ def _merge_list_query(
|
|
|
67
68
|
start_date: str | None = None,
|
|
68
69
|
end_date: str | None = None,
|
|
69
70
|
) -> dict[str, Any]:
|
|
70
|
-
"""Merge the shared list query params (search / date range) into ``params``.
|
|
71
|
+
"""Merge the shared list query params (search / date range) into ``params``.
|
|
72
|
+
|
|
73
|
+
Raises :class:`APIError` with ``search_query_too_long`` if *search* exceeds
|
|
74
|
+
:data:`MAX_SEARCH_QUERY_LENGTH` — matching the server-side validation so the
|
|
75
|
+
user gets instant feedback instead of a round-trip 400.
|
|
76
|
+
"""
|
|
71
77
|
if search is not None:
|
|
78
|
+
normalized: str = " ".join(search.split())
|
|
79
|
+
if len(normalized) > MAX_SEARCH_QUERY_LENGTH:
|
|
80
|
+
raise APIError(
|
|
81
|
+
400,
|
|
82
|
+
"Search query is too long.",
|
|
83
|
+
code="search_query_too_long",
|
|
84
|
+
)
|
|
72
85
|
params["search"] = search
|
|
73
86
|
if start_date is not None:
|
|
74
87
|
params["start_date"] = start_date
|
|
@@ -1571,7 +1584,12 @@ class DailyBotClient:
|
|
|
1571
1584
|
)
|
|
1572
1585
|
if response.status_code >= 400:
|
|
1573
1586
|
self._handle_response(response)
|
|
1574
|
-
|
|
1587
|
+
data: Any = response.json()
|
|
1588
|
+
if isinstance(data, dict) and "results" in data:
|
|
1589
|
+
return data["results"]
|
|
1590
|
+
if isinstance(data, list):
|
|
1591
|
+
return data
|
|
1592
|
+
return []
|
|
1575
1593
|
|
|
1576
1594
|
def mark_agent_messages_read(
|
|
1577
1595
|
self,
|
|
@@ -468,7 +468,7 @@ def checkin_create(
|
|
|
468
468
|
"""Create a check-in with a schedule, participants, questions, and config.
|
|
469
469
|
|
|
470
470
|
\b
|
|
471
|
-
Creating check-ins is role-gated server-side
|
|
471
|
+
Creating check-ins is role-gated server-side. A check-in must
|
|
472
472
|
have at least one question at create time — seed them with --questions-file or
|
|
473
473
|
--interactive (add/edit/remove more later with `dailybot checkin questions`). The
|
|
474
474
|
scheduling/behavior flags (frequency, reminders, timezone mode, submission rules,
|
|
@@ -26,6 +26,7 @@ from dailybot_cli.display import (
|
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
GROUP_CHAT_TYPE: str = "group_chat"
|
|
29
|
+
MAX_CONVERSATION_PARTICIPANTS: int = 7 # Slack MPIM limit: 8 total, minus the bot
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
def _split_identifiers(values: tuple[str, ...]) -> list[str]:
|
|
@@ -67,6 +68,11 @@ def _exit_for_conversation_error(exc: APIError, json_mode: bool) -> NoReturn:
|
|
|
67
68
|
message = "One or more users were not found or aren't active in your organization."
|
|
68
69
|
elif code == "no_valid_users":
|
|
69
70
|
message = "The participant list contains invalid user UUIDs."
|
|
71
|
+
elif code == "conversation_too_many_participants":
|
|
72
|
+
message = (
|
|
73
|
+
f"Too many participants. Slack group DMs support at most "
|
|
74
|
+
f"{MAX_CONVERSATION_PARTICIPANTS} users plus the Dailybot bot (8 total)."
|
|
75
|
+
)
|
|
70
76
|
elif code == "conversation_can_not_be_opened":
|
|
71
77
|
message = "Slack rejected the request. A participant may be deactivated on the Slack side."
|
|
72
78
|
elif exc.status_code == 403:
|
|
@@ -147,6 +153,14 @@ def conversation_open(
|
|
|
147
153
|
print_error("Provide at least one participant with --user (UUID, email, or name).")
|
|
148
154
|
raise SystemExit(1)
|
|
149
155
|
|
|
156
|
+
if len(identifiers) > MAX_CONVERSATION_PARTICIPANTS:
|
|
157
|
+
print_error(
|
|
158
|
+
f"Too many participants ({len(identifiers)}). "
|
|
159
|
+
f"Slack group DMs support at most {MAX_CONVERSATION_PARTICIPANTS} "
|
|
160
|
+
"users plus the Dailybot bot (8 total)."
|
|
161
|
+
)
|
|
162
|
+
raise SystemExit(1)
|
|
163
|
+
|
|
150
164
|
client: DailyBotClient = require_auth()
|
|
151
165
|
try:
|
|
152
166
|
participants: list[tuple[str, str]] = _resolve_participants(client, identifiers)
|
|
@@ -155,6 +169,13 @@ def conversation_open(
|
|
|
155
169
|
raise SystemExit(1)
|
|
156
170
|
|
|
157
171
|
uuids: list[str] = [uuid for uuid, _name in participants]
|
|
172
|
+
if len(uuids) > MAX_CONVERSATION_PARTICIPANTS:
|
|
173
|
+
print_error(
|
|
174
|
+
f"Too many participants ({len(uuids)}). "
|
|
175
|
+
f"Slack group DMs support at most {MAX_CONVERSATION_PARTICIPANTS} "
|
|
176
|
+
"users plus the Dailybot bot (8 total)."
|
|
177
|
+
)
|
|
178
|
+
raise SystemExit(1)
|
|
158
179
|
try:
|
|
159
180
|
with console.status("Opening group conversation..."):
|
|
160
181
|
result: dict[str, Any] = client.open_conversation(uuids)
|
|
@@ -510,6 +510,47 @@ def form_update(
|
|
|
510
510
|
print_form_response_state(result, form_data)
|
|
511
511
|
|
|
512
512
|
|
|
513
|
+
def _resolve_workflow_state(client: DailyBotClient, form_uuid: str, user_input: str) -> str:
|
|
514
|
+
"""Resolve a user-provided state label or key to the canonical state key.
|
|
515
|
+
|
|
516
|
+
Fetches the form's workflow states and tries, in order:
|
|
517
|
+
1. Exact key match (e.g. ``"done"`` matches key ``"done"``).
|
|
518
|
+
2. Case-insensitive label match (e.g. ``"Done"`` matches label ``"Done"``
|
|
519
|
+
→ key ``"done"``).
|
|
520
|
+
3. Case-insensitive key match (e.g. ``"Done"`` matches key ``"done"``).
|
|
521
|
+
Falls back to the original input if no match, letting the API decide.
|
|
522
|
+
"""
|
|
523
|
+
try:
|
|
524
|
+
form_data: dict[str, Any] = client.get_form(form_uuid)
|
|
525
|
+
except APIError:
|
|
526
|
+
return user_input
|
|
527
|
+
|
|
528
|
+
workflow: dict[str, Any] | None = form_data.get("workflow")
|
|
529
|
+
if not workflow or not workflow.get("enabled"):
|
|
530
|
+
return user_input
|
|
531
|
+
|
|
532
|
+
states: list[dict[str, Any]] = workflow.get("states", [])
|
|
533
|
+
if not states:
|
|
534
|
+
return user_input
|
|
535
|
+
|
|
536
|
+
for state in states:
|
|
537
|
+
if state.get("key") == user_input:
|
|
538
|
+
return user_input
|
|
539
|
+
|
|
540
|
+
user_lower: str = user_input.lower()
|
|
541
|
+
for state in states:
|
|
542
|
+
label: str = state.get("label", "")
|
|
543
|
+
if label.lower() == user_lower:
|
|
544
|
+
return state["key"]
|
|
545
|
+
|
|
546
|
+
for state in states:
|
|
547
|
+
key: str = state.get("key", "")
|
|
548
|
+
if key.lower() == user_lower:
|
|
549
|
+
return key
|
|
550
|
+
|
|
551
|
+
return user_input
|
|
552
|
+
|
|
553
|
+
|
|
513
554
|
@form.command("transition")
|
|
514
555
|
@click.argument("form_uuid")
|
|
515
556
|
@click.argument("response_uuid")
|
|
@@ -527,6 +568,10 @@ def form_transition(
|
|
|
527
568
|
) -> None:
|
|
528
569
|
"""Advance a response to a new workflow state.
|
|
529
570
|
|
|
571
|
+
\b
|
|
572
|
+
Accepts either the state key (e.g. 'done') or its human label (e.g. 'Done')
|
|
573
|
+
— the CLI resolves labels to keys automatically (case-insensitive).
|
|
574
|
+
|
|
530
575
|
\b
|
|
531
576
|
The form's state_change_permission audience is the sole gate — there is no
|
|
532
577
|
response-author short-circuit. If you're not in the audience the API will
|
|
@@ -535,15 +580,20 @@ def form_transition(
|
|
|
535
580
|
\b
|
|
536
581
|
Examples:
|
|
537
582
|
dailybot form transition <form_uuid> <response_uuid> qa --note "QA assigned"
|
|
583
|
+
dailybot form transition <form_uuid> <response_uuid> Done
|
|
538
584
|
dailybot form transition <form_uuid> <response_uuid> released --json
|
|
539
585
|
"""
|
|
540
586
|
client = require_auth()
|
|
541
587
|
|
|
588
|
+
resolved_state: str = _resolve_workflow_state(client, form_uuid, to_state)
|
|
589
|
+
|
|
542
590
|
summary_lines: list[str] = [
|
|
543
591
|
f"Form UUID: {form_uuid}",
|
|
544
592
|
f"Response UUID: {response_uuid}",
|
|
545
|
-
f"To state: {
|
|
593
|
+
f"To state: {resolved_state}",
|
|
546
594
|
]
|
|
595
|
+
if resolved_state != to_state:
|
|
596
|
+
summary_lines.append(f" (resolved from label '{to_state}')")
|
|
547
597
|
if note:
|
|
548
598
|
summary_lines.append(f"Note: {note}")
|
|
549
599
|
confirm_write(summary_lines, assume_yes)
|
|
@@ -553,7 +603,7 @@ def form_transition(
|
|
|
553
603
|
result: dict[str, Any] = client.transition_form_response(
|
|
554
604
|
form_uuid=form_uuid,
|
|
555
605
|
response_uuid=response_uuid,
|
|
556
|
-
to_state=
|
|
606
|
+
to_state=resolved_state,
|
|
557
607
|
note=note,
|
|
558
608
|
)
|
|
559
609
|
except APIError as exc:
|
|
@@ -563,7 +613,7 @@ def form_transition(
|
|
|
563
613
|
emit_json(result)
|
|
564
614
|
return
|
|
565
615
|
|
|
566
|
-
print_success(f"Response {response_uuid} transitioned to '{
|
|
616
|
+
print_success(f"Response {response_uuid} transitioned to '{resolved_state}'.")
|
|
567
617
|
form_data: dict[str, Any] | None = _maybe_load_form(client, form_uuid)
|
|
568
618
|
print_form_response_state(result, form_data)
|
|
569
619
|
|
|
@@ -83,7 +83,12 @@ def build_query_params(
|
|
|
83
83
|
params: dict[str, Any] = {}
|
|
84
84
|
|
|
85
85
|
if search is not None:
|
|
86
|
-
|
|
86
|
+
normalized: str = " ".join(search.split())
|
|
87
|
+
if len(normalized) > MAX_SEARCH_LEN:
|
|
88
|
+
raise ValueError(
|
|
89
|
+
f"Search query is too long ({len(normalized)} chars, max {MAX_SEARCH_LEN})."
|
|
90
|
+
)
|
|
91
|
+
params["search"] = search
|
|
87
92
|
|
|
88
93
|
start: str | None = None
|
|
89
94
|
end: str | None = None
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Status command for Dailybot CLI."""
|
|
2
2
|
|
|
3
|
+
import json as json_mod
|
|
3
4
|
from typing import Any
|
|
4
5
|
|
|
5
6
|
import click
|
|
@@ -58,12 +59,19 @@ def _check_auth() -> None:
|
|
|
58
59
|
|
|
59
60
|
@click.command()
|
|
60
61
|
@click.option("--auth", is_flag=True, default=False, help="Check authentication status.")
|
|
61
|
-
|
|
62
|
+
@click.option(
|
|
63
|
+
"--json", "json_mode", is_flag=True, default=False, help="Emit machine-readable JSON to stdout."
|
|
64
|
+
)
|
|
65
|
+
def status(auth: bool, json_mode: bool) -> None:
|
|
62
66
|
"""Show pending check-ins for today.
|
|
63
67
|
|
|
64
68
|
\b
|
|
65
69
|
Use --auth to verify your credentials are valid:
|
|
66
70
|
dailybot status --auth
|
|
71
|
+
|
|
72
|
+
\b
|
|
73
|
+
Use --json for machine-readable output:
|
|
74
|
+
dailybot status --json
|
|
67
75
|
"""
|
|
68
76
|
if auth:
|
|
69
77
|
_check_auth()
|
|
@@ -77,6 +85,9 @@ def status(auth: bool) -> None:
|
|
|
77
85
|
try:
|
|
78
86
|
with console.status("Fetching pending check-ins..."):
|
|
79
87
|
data: dict[str, Any] = client.get_status()
|
|
88
|
+
if json_mode:
|
|
89
|
+
click.echo(json_mod.dumps(data))
|
|
90
|
+
return
|
|
80
91
|
checkins: list[dict[str, Any]] = data.get("pending_checkins", [])
|
|
81
92
|
print_pending_checkins(checkins)
|
|
82
93
|
except APIError as e:
|
|
@@ -6,7 +6,9 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
DEFAULT_API_URL: str = "https://api.dailybot.com"
|
|
9
|
+
DEFAULT_APP_URL: str = "https://app.dailybot.com"
|
|
9
10
|
_api_url_override: str | None = None
|
|
11
|
+
_app_url_override: str | None = None
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
def set_api_url_override(url: str) -> None:
|
|
@@ -15,6 +17,12 @@ def set_api_url_override(url: str) -> None:
|
|
|
15
17
|
_api_url_override = url.rstrip("/")
|
|
16
18
|
|
|
17
19
|
|
|
20
|
+
def set_app_url_override(url: str) -> None:
|
|
21
|
+
"""Set a CLI-level webapp URL override (from --app-url flag)."""
|
|
22
|
+
global _app_url_override
|
|
23
|
+
_app_url_override = url.rstrip("/")
|
|
24
|
+
|
|
25
|
+
|
|
18
26
|
CONFIG_DIR: Path = Path.home() / ".config" / "dailybot"
|
|
19
27
|
CREDENTIALS_FILE: Path = CONFIG_DIR / "credentials.json"
|
|
20
28
|
CONFIG_FILE: Path = CONFIG_DIR / "config.json"
|
|
@@ -108,6 +116,16 @@ def get_api_url() -> str:
|
|
|
108
116
|
return DEFAULT_API_URL
|
|
109
117
|
|
|
110
118
|
|
|
119
|
+
def get_app_url() -> str:
|
|
120
|
+
"""Return the webapp URL (--app-url flag > env var > default)."""
|
|
121
|
+
if _app_url_override:
|
|
122
|
+
return _app_url_override
|
|
123
|
+
env_url: str | None = os.environ.get("DAILYBOT_APP_URL")
|
|
124
|
+
if env_url:
|
|
125
|
+
return env_url.rstrip("/")
|
|
126
|
+
return DEFAULT_APP_URL
|
|
127
|
+
|
|
128
|
+
|
|
111
129
|
def get_token() -> str | None:
|
|
112
130
|
"""Return the stored auth token, or the DAILYBOT_CLI_TOKEN env var."""
|
|
113
131
|
env_token: str | None = os.environ.get("DAILYBOT_CLI_TOKEN")
|
|
@@ -327,7 +327,7 @@ def print_webhook_result(data: dict[str, Any]) -> None:
|
|
|
327
327
|
console.print(Panel(table, title="[bold]Webhook Registered[/bold]", border_style="green"))
|
|
328
328
|
|
|
329
329
|
|
|
330
|
-
def print_agent_messages(messages: list[
|
|
330
|
+
def print_agent_messages(messages: list[Any]) -> None:
|
|
331
331
|
"""Display a list of agent messages."""
|
|
332
332
|
if not messages:
|
|
333
333
|
print_info("No messages found.")
|
|
@@ -339,6 +339,9 @@ def print_agent_messages(messages: list[dict[str, Any]]) -> None:
|
|
|
339
339
|
table.add_column("Delivered")
|
|
340
340
|
table.add_column("Created", style="dim")
|
|
341
341
|
for msg in messages:
|
|
342
|
+
if not isinstance(msg, dict):
|
|
343
|
+
table.add_row("text", "", str(msg), "", "")
|
|
344
|
+
continue
|
|
342
345
|
delivered: bool = msg.get("delivered", False)
|
|
343
346
|
delivered_text: str = "[green]yes[/green]" if delivered else "[yellow]no[/yellow]"
|
|
344
347
|
sender_type: str = msg.get("sender_type", "")
|
|
@@ -27,7 +27,7 @@ from dailybot_cli.commands.upgrade import upgrade
|
|
|
27
27
|
from dailybot_cli.commands.user import user
|
|
28
28
|
from dailybot_cli.commands.version import version
|
|
29
29
|
from dailybot_cli.commands.workflow import workflow
|
|
30
|
-
from dailybot_cli.config import set_api_url_override
|
|
30
|
+
from dailybot_cli.config import set_api_url_override, set_app_url_override
|
|
31
31
|
|
|
32
32
|
# Format used by `dailybot --version`. Single line so it's friendly to scripts
|
|
33
33
|
# parsing the output. The richer multi-line panel lives in `dailybot version`.
|
|
@@ -42,8 +42,14 @@ _VERSION_MESSAGE: str = f"dailybot {__version__} (Python {platform.python_versio
|
|
|
42
42
|
envvar="DAILYBOT_API_URL",
|
|
43
43
|
help="Override the API base URL (e.g. staging).",
|
|
44
44
|
)
|
|
45
|
+
@click.option(
|
|
46
|
+
"--app-url",
|
|
47
|
+
default=None,
|
|
48
|
+
envvar="DAILYBOT_APP_URL",
|
|
49
|
+
help="Override the webapp/dashboard base URL (default: https://app.dailybot.com).",
|
|
50
|
+
)
|
|
45
51
|
@click.pass_context
|
|
46
|
-
def cli(ctx: click.Context, api_url: str | None) -> None:
|
|
52
|
+
def cli(ctx: click.Context, api_url: str | None, app_url: str | None) -> None:
|
|
47
53
|
"""Dailybot CLI - The command-line bridge between humans and agents.
|
|
48
54
|
|
|
49
55
|
\b
|
|
@@ -68,6 +74,8 @@ def cli(ctx: click.Context, api_url: str | None) -> None:
|
|
|
68
74
|
"""
|
|
69
75
|
if api_url:
|
|
70
76
|
set_api_url_override(api_url)
|
|
77
|
+
if app_url:
|
|
78
|
+
set_app_url_override(app_url)
|
|
71
79
|
if ctx.invoked_subcommand is None:
|
|
72
80
|
run_interactive()
|
|
73
81
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dailybot-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.0
|
|
4
4
|
Summary: Dailybot CLI - The command-line bridge between humans and agents. Progress reports, observability, and workflow automation for modern teams across Slack, Google Chat, Discord, MS Teams, and more.
|
|
5
5
|
Author-email: Dailybot <support@dailybot.com>
|
|
6
6
|
License: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dailybot-cli"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.4.0"
|
|
8
8
|
description = "Dailybot CLI - The command-line bridge between humans and agents. Progress reports, observability, and workflow automation for modern teams across Slack, Google Chat, Discord, MS Teams, and more."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
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
|