dailybot-cli 3.19.0__tar.gz → 3.20.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.19.0 → dailybot_cli-3.20.0}/PKG-INFO +21 -19
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/README.md +20 -18
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/api_client.py +1 -1
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/board.py +4 -37
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/goal.py +3 -12
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/project.py +10 -61
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/public_api_helpers.py +17 -51
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/task.py +2 -24
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli.egg-info/PKG-INFO +21 -19
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/pyproject.toml +1 -1
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/LICENSE +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/__init__.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/__init__.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/_attachments.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/_beta.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/_briefing.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/_destructive.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/_favorites.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/_rollups.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/_writes.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/agent.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/ask.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/auth.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/authoring_helpers.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/channels.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/chat.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/checkin.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/config.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/conversation.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/env.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/featured.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/form.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/hook.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/identity.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/interactive.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/interactive_chat.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/kudos.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/label.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/query_options.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/status.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/tasks.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/team.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/uninstall.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/update.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/upgrade.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/user.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/user_scoped_actions.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/version.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/commands/workflow.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/config.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/display.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/install_method.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/ledger.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/main.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/tui/__init__.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/tui/app.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/tui/commands.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/tui/conversation.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli/tui/intents.py +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli.egg-info/SOURCES.txt +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli.egg-info/dependency_links.txt +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli.egg-info/entry_points.txt +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli.egg-info/requires.txt +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.0}/dailybot_cli.egg-info/top_level.txt +0 -0
- {dailybot_cli-3.19.0 → dailybot_cli-3.20.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.20.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
|
|
@@ -905,11 +905,13 @@ Replies to agent emails land as messages retrievable via `dailybot agent message
|
|
|
905
905
|
Projects, boards and tasks. Two groups: **`dailybot tasks`** answers questions about the
|
|
906
906
|
workspace, **`dailybot task`** reads or changes one task.
|
|
907
907
|
|
|
908
|
-
**
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
908
|
+
**Your personal API key is you.** A login session (`dailybot login`) and a personal API key
|
|
909
|
+
(one bound to you) can do everything you can do in the web app: create, update, archive and
|
|
910
|
+
restore boards, columns, projects, goals and milestones, manage board and project
|
|
911
|
+
membership, link goals to projects, and work every task. That is every non-guest member, no
|
|
912
|
+
organization-admin prerequisite. Only an agent or organization key, with nobody behind it,
|
|
913
|
+
cannot act as a person: the server refuses it (`actor_required` exit 3, `insufficient_scope`
|
|
914
|
+
exit 4). Guests stay limited by their role.
|
|
913
915
|
**Privacy is membership**, not org role: a `members` project or board is 404 (not visible)
|
|
914
916
|
to anyone without a grant; invite a person or a team to close it.
|
|
915
917
|
A board inside a `members` project follows the project's membership: whoever the project
|
|
@@ -954,9 +956,9 @@ humans who own them.
|
|
|
954
956
|
| `dailybot task comments <uuid>` | List a task's comments |
|
|
955
957
|
| `dailybot task link <a> <b> --type <rel>` | Relate two tasks (`blocks`, `relates_to`, `duplicates`) |
|
|
956
958
|
| `dailybot task labels <uuid> --mode add\|remove\|replace` | Change a task's labels |
|
|
957
|
-
| `dailybot task participants add\|list\|remove <task>` | Who is on a task (`--role participant\|watcher`); `
|
|
959
|
+
| `dailybot task participants add\|list\|remove <task>` | Who is on a task (`--role participant\|watcher`); all need a person: `dailybot login` or a personal API key |
|
|
958
960
|
| `dailybot task watch\|unwatch <task>` | Follow a task privately — **needs a person: `dailybot login` or a personal API key** |
|
|
959
|
-
| `dailybot task mute\|unmute <task>` | Silence a task and stay on it (leaving is `participants remove`) — **needs `dailybot login
|
|
961
|
+
| `dailybot task mute\|unmute <task>` | Silence a task and stay on it (leaving is `participants remove`) — **needs a person: `dailybot login` or a personal API key** |
|
|
960
962
|
| `dailybot task relations <task>` · `task unlink <task> <relation>` | List links (direction included) / remove one; `unlink` confirms and has `--dry-run` |
|
|
961
963
|
| `dailybot task comment-edit\|comment-delete <task> <comment>` | Edit (`-` reads stdin) or delete a comment; delete blanks the text and keeps the entry |
|
|
962
964
|
| `dailybot task children <task>` · `task events <task>` · `task activity <task>` | Sub-tasks, raw event history, and the readable activity feed (`--updated-since`, `--type`) |
|
|
@@ -978,12 +980,12 @@ humans who own them.
|
|
|
978
980
|
| `dailybot board labels <uuid>` | Labels available on the board — **needs a person: `dailybot login` or a personal API key** |
|
|
979
981
|
| `dailybot board views <uuid>` | Your saved views on the board, plus the ETag a save needs (`--etag` prints only that) |
|
|
980
982
|
| `dailybot board state create\|update\|archive\|restore\|reorder` | Manage columns. `archive` previews first and takes `--migrate-to <state>` to move the column's cards |
|
|
981
|
-
| `dailybot board member add <board> <user>` (or `--team <team>`) · `board member remove <board> <user>` | Who can see the board — **needs `dailybot login
|
|
983
|
+
| `dailybot board member add <board> <user>` (or `--team <team>`) · `board member remove <board> <user>` | Who can see the board — **needs a person: `dailybot login` or a personal API key**. Membership is the privacy control (not org role). A team grant follows the team live. Last grant on a private board stays (`last_grant_cannot_be_removed`) |
|
|
982
984
|
| `dailybot board label create <board> -n <name>` | Create an organization label from the board — **needs a person: `dailybot login` or a personal API key** |
|
|
983
985
|
| `dailybot board view save <board> -f views.json --if-match <etag>` | Replace your saved views (the whole list) — **needs a person: `dailybot login` or a personal API key** |
|
|
984
986
|
| `dailybot board snapshot <uuid>` | The whole board in one request; carries the `delta_cursor` that `tasks changes` consumes |
|
|
985
987
|
| `dailybot board update <uuid>` | Name, key (the old key stays reserved), visibility, estimate scale, auto-archive, project |
|
|
986
|
-
| `dailybot board create --name <n> --project <uuid> --key <KEY>` | Create a board in a project; the key prefixes its tasks (`DSN-1`) — **needs `dailybot login
|
|
988
|
+
| `dailybot board create --name <n> --project <uuid> --key <KEY>` | Create a board in a project; the key prefixes its tasks (`DSN-1`) — **needs a person: `dailybot login` or a personal API key** (any non-guest member) |
|
|
987
989
|
| `dailybot board archive <uuid>` | Archive a board. **Cascade-archives its live tasks**, and restoring does not bring them back |
|
|
988
990
|
| `dailybot board restore <uuid>` | Restore a board (cascaded tasks stay archived) |
|
|
989
991
|
| `dailybot project list` | List projects (`--include progress`) |
|
|
@@ -993,28 +995,28 @@ humans who own them.
|
|
|
993
995
|
| `dailybot project milestones [<uuid>]` | List milestones |
|
|
994
996
|
| `dailybot project milestone-complete <p> <m>` | Complete a milestone. **Its open tasks stay open** |
|
|
995
997
|
| `dailybot project milestone-reopen <p> <m>` | Reopen a milestone |
|
|
996
|
-
| `dailybot project create --name <n>` | Create a project — **needs `dailybot login
|
|
998
|
+
| `dailybot project create --name <n>` | Create a project — **needs a person: `dailybot login` or a personal API key** |
|
|
997
999
|
| `dailybot project update <uuid>` | Name, description, lead, health, dates, visibility |
|
|
998
1000
|
| `dailybot project restore <uuid>` | Restore an archived project (its boards and tasks stay archived) |
|
|
999
|
-
| `dailybot project members <uuid>` · `project member add\|remove` | Who can see the project — people or whole teams (`--team`) — `members` works with a personal API key; `member add\|remove` **needs `dailybot login
|
|
1000
|
-
| `dailybot project views <uuid>` · `project view save` | Your saved views; save replaces the list and requires the ETag — **needs `dailybot login
|
|
1001
|
+
| `dailybot project members <uuid>` · `project member add\|remove` | Who can see the project — people or whole teams (`--team`) — `members` works with a personal API key; `member add\|remove` **needs a person: `dailybot login` or a personal API key** |
|
|
1002
|
+
| `dailybot project views <uuid>` · `project view save` | Your saved views; save replaces the list and requires the ETag — **needs a person: `dailybot login` or a personal API key** |
|
|
1001
1003
|
| `dailybot project milestone-create\|milestone-update\|milestone-delete` | Dated milestones; delete retires it (tasks keep pointing at it) |
|
|
1002
1004
|
| `dailybot project archive <uuid>` | Archive a project |
|
|
1003
|
-
| `dailybot project attach <uuid> <file>` · `project attachments` · `project attachment get\|delete` | Files on a project (≤5 MiB, one request). Attaching and deleting need `dailybot login` |
|
|
1005
|
+
| `dailybot project attach <uuid> <file>` · `project attachments` · `project attachment get\|delete` | Files on a project (≤5 MiB, one request). Attaching and deleting need a person (`dailybot login` or a personal API key) |
|
|
1004
1006
|
| `dailybot goal list` | List goals (`--include` is repeatable: `--include progress --include projects`) |
|
|
1005
1007
|
| `dailybot goal get <uuid>` | Show one goal, with its progress and linked projects (always included) |
|
|
1006
|
-
| `dailybot goal create --name <n> --period-start <d> --period-end <d>` | Create a goal (a dated commitment) — **needs `dailybot login
|
|
1008
|
+
| `dailybot goal create --name <n> --period-start <d> --period-end <d>` | Create a goal (a dated commitment) — **needs a person: `dailybot login` or a personal API key** |
|
|
1007
1009
|
| `dailybot goal update <uuid>` | Name, period, owner, team, and the declared `--status` (not_started, on_track, at_risk, off_track, achieved, missed) |
|
|
1008
1010
|
| `dailybot goal restore <uuid>` | Restore an archived goal |
|
|
1009
1011
|
| `dailybot goal link\|unlink <goal> <project>` | Make a project count toward a goal (or stop it) |
|
|
1010
1012
|
| `dailybot goal archive <uuid>` | Archive a goal (its projects are not archived) |
|
|
1011
|
-
| `dailybot goal attach <uuid> <file>` · `goal attachments` · `goal attachment get\|delete` | Files on a goal (≤5 MiB, one request). Attaching and deleting need `dailybot login` |
|
|
1013
|
+
| `dailybot goal attach <uuid> <file>` · `goal attachments` · `goal attachment get\|delete` | Files on a goal (≤5 MiB, one request). Attaching and deleting need a person (`dailybot login` or a personal API key) |
|
|
1012
1014
|
|
|
1013
1015
|
**Three things worth knowing before you script against this:**
|
|
1014
1016
|
|
|
1015
|
-
- **Some doors need a person.**
|
|
1016
|
-
"my inbox", can never hold
|
|
1017
|
-
|
|
1017
|
+
- **Some doors need a person.** A login session or a personal API key is a person; an agent
|
|
1018
|
+
or organization key has no answer for "my tasks" or "my inbox", can never hold
|
|
1019
|
+
`tasks:admin`, and cannot change membership or participants. A 404 means
|
|
1018
1020
|
not visible (wrong id, private without a grant, or another org) — never "not allowed".
|
|
1019
1021
|
- **Roll-ups are opt-in.** A field you did not request with `--include` is **absent** from
|
|
1020
1022
|
the payload. Absent, `null` and `0` are three different answers, and the CLI renders them
|
|
@@ -866,11 +866,13 @@ Replies to agent emails land as messages retrievable via `dailybot agent message
|
|
|
866
866
|
Projects, boards and tasks. Two groups: **`dailybot tasks`** answers questions about the
|
|
867
867
|
workspace, **`dailybot task`** reads or changes one task.
|
|
868
868
|
|
|
869
|
-
**
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
869
|
+
**Your personal API key is you.** A login session (`dailybot login`) and a personal API key
|
|
870
|
+
(one bound to you) can do everything you can do in the web app: create, update, archive and
|
|
871
|
+
restore boards, columns, projects, goals and milestones, manage board and project
|
|
872
|
+
membership, link goals to projects, and work every task. That is every non-guest member, no
|
|
873
|
+
organization-admin prerequisite. Only an agent or organization key, with nobody behind it,
|
|
874
|
+
cannot act as a person: the server refuses it (`actor_required` exit 3, `insufficient_scope`
|
|
875
|
+
exit 4). Guests stay limited by their role.
|
|
874
876
|
**Privacy is membership**, not org role: a `members` project or board is 404 (not visible)
|
|
875
877
|
to anyone without a grant; invite a person or a team to close it.
|
|
876
878
|
A board inside a `members` project follows the project's membership: whoever the project
|
|
@@ -915,9 +917,9 @@ humans who own them.
|
|
|
915
917
|
| `dailybot task comments <uuid>` | List a task's comments |
|
|
916
918
|
| `dailybot task link <a> <b> --type <rel>` | Relate two tasks (`blocks`, `relates_to`, `duplicates`) |
|
|
917
919
|
| `dailybot task labels <uuid> --mode add\|remove\|replace` | Change a task's labels |
|
|
918
|
-
| `dailybot task participants add\|list\|remove <task>` | Who is on a task (`--role participant\|watcher`); `
|
|
920
|
+
| `dailybot task participants add\|list\|remove <task>` | Who is on a task (`--role participant\|watcher`); all need a person: `dailybot login` or a personal API key |
|
|
919
921
|
| `dailybot task watch\|unwatch <task>` | Follow a task privately — **needs a person: `dailybot login` or a personal API key** |
|
|
920
|
-
| `dailybot task mute\|unmute <task>` | Silence a task and stay on it (leaving is `participants remove`) — **needs `dailybot login
|
|
922
|
+
| `dailybot task mute\|unmute <task>` | Silence a task and stay on it (leaving is `participants remove`) — **needs a person: `dailybot login` or a personal API key** |
|
|
921
923
|
| `dailybot task relations <task>` · `task unlink <task> <relation>` | List links (direction included) / remove one; `unlink` confirms and has `--dry-run` |
|
|
922
924
|
| `dailybot task comment-edit\|comment-delete <task> <comment>` | Edit (`-` reads stdin) or delete a comment; delete blanks the text and keeps the entry |
|
|
923
925
|
| `dailybot task children <task>` · `task events <task>` · `task activity <task>` | Sub-tasks, raw event history, and the readable activity feed (`--updated-since`, `--type`) |
|
|
@@ -939,12 +941,12 @@ humans who own them.
|
|
|
939
941
|
| `dailybot board labels <uuid>` | Labels available on the board — **needs a person: `dailybot login` or a personal API key** |
|
|
940
942
|
| `dailybot board views <uuid>` | Your saved views on the board, plus the ETag a save needs (`--etag` prints only that) |
|
|
941
943
|
| `dailybot board state create\|update\|archive\|restore\|reorder` | Manage columns. `archive` previews first and takes `--migrate-to <state>` to move the column's cards |
|
|
942
|
-
| `dailybot board member add <board> <user>` (or `--team <team>`) · `board member remove <board> <user>` | Who can see the board — **needs `dailybot login
|
|
944
|
+
| `dailybot board member add <board> <user>` (or `--team <team>`) · `board member remove <board> <user>` | Who can see the board — **needs a person: `dailybot login` or a personal API key**. Membership is the privacy control (not org role). A team grant follows the team live. Last grant on a private board stays (`last_grant_cannot_be_removed`) |
|
|
943
945
|
| `dailybot board label create <board> -n <name>` | Create an organization label from the board — **needs a person: `dailybot login` or a personal API key** |
|
|
944
946
|
| `dailybot board view save <board> -f views.json --if-match <etag>` | Replace your saved views (the whole list) — **needs a person: `dailybot login` or a personal API key** |
|
|
945
947
|
| `dailybot board snapshot <uuid>` | The whole board in one request; carries the `delta_cursor` that `tasks changes` consumes |
|
|
946
948
|
| `dailybot board update <uuid>` | Name, key (the old key stays reserved), visibility, estimate scale, auto-archive, project |
|
|
947
|
-
| `dailybot board create --name <n> --project <uuid> --key <KEY>` | Create a board in a project; the key prefixes its tasks (`DSN-1`) — **needs `dailybot login
|
|
949
|
+
| `dailybot board create --name <n> --project <uuid> --key <KEY>` | Create a board in a project; the key prefixes its tasks (`DSN-1`) — **needs a person: `dailybot login` or a personal API key** (any non-guest member) |
|
|
948
950
|
| `dailybot board archive <uuid>` | Archive a board. **Cascade-archives its live tasks**, and restoring does not bring them back |
|
|
949
951
|
| `dailybot board restore <uuid>` | Restore a board (cascaded tasks stay archived) |
|
|
950
952
|
| `dailybot project list` | List projects (`--include progress`) |
|
|
@@ -954,28 +956,28 @@ humans who own them.
|
|
|
954
956
|
| `dailybot project milestones [<uuid>]` | List milestones |
|
|
955
957
|
| `dailybot project milestone-complete <p> <m>` | Complete a milestone. **Its open tasks stay open** |
|
|
956
958
|
| `dailybot project milestone-reopen <p> <m>` | Reopen a milestone |
|
|
957
|
-
| `dailybot project create --name <n>` | Create a project — **needs `dailybot login
|
|
959
|
+
| `dailybot project create --name <n>` | Create a project — **needs a person: `dailybot login` or a personal API key** |
|
|
958
960
|
| `dailybot project update <uuid>` | Name, description, lead, health, dates, visibility |
|
|
959
961
|
| `dailybot project restore <uuid>` | Restore an archived project (its boards and tasks stay archived) |
|
|
960
|
-
| `dailybot project members <uuid>` · `project member add\|remove` | Who can see the project — people or whole teams (`--team`) — `members` works with a personal API key; `member add\|remove` **needs `dailybot login
|
|
961
|
-
| `dailybot project views <uuid>` · `project view save` | Your saved views; save replaces the list and requires the ETag — **needs `dailybot login
|
|
962
|
+
| `dailybot project members <uuid>` · `project member add\|remove` | Who can see the project — people or whole teams (`--team`) — `members` works with a personal API key; `member add\|remove` **needs a person: `dailybot login` or a personal API key** |
|
|
963
|
+
| `dailybot project views <uuid>` · `project view save` | Your saved views; save replaces the list and requires the ETag — **needs a person: `dailybot login` or a personal API key** |
|
|
962
964
|
| `dailybot project milestone-create\|milestone-update\|milestone-delete` | Dated milestones; delete retires it (tasks keep pointing at it) |
|
|
963
965
|
| `dailybot project archive <uuid>` | Archive a project |
|
|
964
|
-
| `dailybot project attach <uuid> <file>` · `project attachments` · `project attachment get\|delete` | Files on a project (≤5 MiB, one request). Attaching and deleting need `dailybot login` |
|
|
966
|
+
| `dailybot project attach <uuid> <file>` · `project attachments` · `project attachment get\|delete` | Files on a project (≤5 MiB, one request). Attaching and deleting need a person (`dailybot login` or a personal API key) |
|
|
965
967
|
| `dailybot goal list` | List goals (`--include` is repeatable: `--include progress --include projects`) |
|
|
966
968
|
| `dailybot goal get <uuid>` | Show one goal, with its progress and linked projects (always included) |
|
|
967
|
-
| `dailybot goal create --name <n> --period-start <d> --period-end <d>` | Create a goal (a dated commitment) — **needs `dailybot login
|
|
969
|
+
| `dailybot goal create --name <n> --period-start <d> --period-end <d>` | Create a goal (a dated commitment) — **needs a person: `dailybot login` or a personal API key** |
|
|
968
970
|
| `dailybot goal update <uuid>` | Name, period, owner, team, and the declared `--status` (not_started, on_track, at_risk, off_track, achieved, missed) |
|
|
969
971
|
| `dailybot goal restore <uuid>` | Restore an archived goal |
|
|
970
972
|
| `dailybot goal link\|unlink <goal> <project>` | Make a project count toward a goal (or stop it) |
|
|
971
973
|
| `dailybot goal archive <uuid>` | Archive a goal (its projects are not archived) |
|
|
972
|
-
| `dailybot goal attach <uuid> <file>` · `goal attachments` · `goal attachment get\|delete` | Files on a goal (≤5 MiB, one request). Attaching and deleting need `dailybot login` |
|
|
974
|
+
| `dailybot goal attach <uuid> <file>` · `goal attachments` · `goal attachment get\|delete` | Files on a goal (≤5 MiB, one request). Attaching and deleting need a person (`dailybot login` or a personal API key) |
|
|
973
975
|
|
|
974
976
|
**Three things worth knowing before you script against this:**
|
|
975
977
|
|
|
976
|
-
- **Some doors need a person.**
|
|
977
|
-
"my inbox", can never hold
|
|
978
|
-
|
|
978
|
+
- **Some doors need a person.** A login session or a personal API key is a person; an agent
|
|
979
|
+
or organization key has no answer for "my tasks" or "my inbox", can never hold
|
|
980
|
+
`tasks:admin`, and cannot change membership or participants. A 404 means
|
|
979
981
|
not visible (wrong id, private without a grant, or another org) — never "not allowed".
|
|
980
982
|
- **Roll-ups are opt-in.** A field you did not request with `--include` is **absent** from
|
|
981
983
|
the payload. Absent, `null` and `0` are three different answers, and the CLI renders them
|
|
@@ -2885,7 +2885,7 @@ class DailyBotClient:
|
|
|
2885
2885
|
return self._tasks_write(
|
|
2886
2886
|
"POST",
|
|
2887
2887
|
f"tasks/{_path_segment(task_uuid)}/labels/batch/",
|
|
2888
|
-
json={"mode": mode, "
|
|
2888
|
+
json={"mode": mode, "label_uuids": labels},
|
|
2889
2889
|
idempotent=True,
|
|
2890
2890
|
idempotency_key=idempotency_key,
|
|
2891
2891
|
)
|
|
@@ -21,7 +21,6 @@ from dailybot_cli.commands.public_api_helpers import (
|
|
|
21
21
|
emit_json,
|
|
22
22
|
exit_for_tasks_error,
|
|
23
23
|
load_json_input,
|
|
24
|
-
refuse_without_person,
|
|
25
24
|
require_auth,
|
|
26
25
|
rows_of,
|
|
27
26
|
)
|
|
@@ -32,7 +31,6 @@ from dailybot_cli.commands.query_options import (
|
|
|
32
31
|
query_options,
|
|
33
32
|
resolve_fetch_all,
|
|
34
33
|
)
|
|
35
|
-
from dailybot_cli.config import get_person_token
|
|
36
34
|
from dailybot_cli.display import (
|
|
37
35
|
console,
|
|
38
36
|
print_board_snapshot,
|
|
@@ -479,7 +477,6 @@ def board_state_create(
|
|
|
479
477
|
dailybot board state create <board-uuid> -n "In review" --category in_progress
|
|
480
478
|
dailybot board state create <board-uuid> -n Blocked --category todo --position 2 --json
|
|
481
479
|
"""
|
|
482
|
-
_require_person_for_admin("board state create", json_mode=json_mode)
|
|
483
480
|
client = require_auth()
|
|
484
481
|
try:
|
|
485
482
|
with console.status("Adding the column..."):
|
|
@@ -528,7 +525,6 @@ def board_state_update(
|
|
|
528
525
|
dailybot board state update <board-uuid> <state-uuid> --name "Shipped"
|
|
529
526
|
dailybot board state update <board-uuid> <state-uuid> --position 1 --json
|
|
530
527
|
"""
|
|
531
|
-
_require_person_for_admin("board state update", json_mode=json_mode)
|
|
532
528
|
fields: dict[str, Any] = {
|
|
533
529
|
k: v
|
|
534
530
|
for k, v in {"name": name, "color": color, "position": position}.items()
|
|
@@ -578,7 +574,6 @@ def board_state_archive(
|
|
|
578
574
|
dailybot board state archive <board-uuid> <state-uuid> --dry-run
|
|
579
575
|
dailybot board state archive <board-uuid> <state-uuid> --migrate-to <other-state> --yes
|
|
580
576
|
"""
|
|
581
|
-
_require_person_for_admin("board state archive", json_mode=json_mode)
|
|
582
577
|
client = require_auth()
|
|
583
578
|
if not preview_then_confirm(
|
|
584
579
|
lambda: client.archive_board_state(
|
|
@@ -613,7 +608,6 @@ def board_state_restore(board_uuid: str, state_uuid: str, json_mode: bool) -> No
|
|
|
613
608
|
Examples:
|
|
614
609
|
dailybot board state restore <board-uuid> <state-uuid>
|
|
615
610
|
"""
|
|
616
|
-
_require_person_for_admin("board state restore", json_mode=json_mode)
|
|
617
611
|
client = require_auth()
|
|
618
612
|
try:
|
|
619
613
|
with console.status("Restoring the column..."):
|
|
@@ -642,7 +636,6 @@ def board_state_reorder(board_uuid: str, state_uuids: tuple[str, ...], json_mode
|
|
|
642
636
|
Examples:
|
|
643
637
|
dailybot board state reorder <board-uuid> <backlog> <todo> <doing> <done>
|
|
644
638
|
"""
|
|
645
|
-
_require_person_for_admin("board state reorder", json_mode=json_mode)
|
|
646
639
|
if len(set(state_uuids)) != len(state_uuids):
|
|
647
640
|
raise click.UsageError("A column appears twice. List each live column exactly once.")
|
|
648
641
|
client = require_auth()
|
|
@@ -669,7 +662,7 @@ _MEMBER_WRITE_REASON: str = (
|
|
|
669
662
|
|
|
670
663
|
@board.group("member")
|
|
671
664
|
def board_member() -> None:
|
|
672
|
-
"""Invite or remove who can see a board. Needs `dailybot login
|
|
665
|
+
"""Invite or remove who can see a board. Needs a person: `dailybot login` or a personal API key.
|
|
673
666
|
|
|
674
667
|
\b
|
|
675
668
|
Membership is the privacy control: a `members` board is invisible (404) to
|
|
@@ -713,7 +706,6 @@ def board_member_add(
|
|
|
713
706
|
dailybot board member add <board-uuid> <user-uuid>
|
|
714
707
|
dailybot board member add <board-uuid> --team <team-uuid> --json
|
|
715
708
|
"""
|
|
716
|
-
_require_person_for_admin("board member add", json_mode=json_mode)
|
|
717
709
|
if (user_uuid is None) == (team_uuid is None):
|
|
718
710
|
raise click.UsageError("Pass exactly one of USER or --team.")
|
|
719
711
|
client = require_auth()
|
|
@@ -751,7 +743,6 @@ def board_member_remove(
|
|
|
751
743
|
dailybot board member remove <board-uuid> <user-uuid> --dry-run
|
|
752
744
|
dailybot board member remove <board-uuid> <user-uuid> --yes
|
|
753
745
|
"""
|
|
754
|
-
_require_person_for_admin("board member remove", json_mode=json_mode)
|
|
755
746
|
if not confirm_without_preview(
|
|
756
747
|
f"remove user {user_uuid} from board {board_uuid}; they lose sight of it if it is private.",
|
|
757
748
|
assume_yes=assume_yes,
|
|
@@ -930,26 +921,6 @@ def board_snapshot(board_uuid: str, json_mode: bool) -> None:
|
|
|
930
921
|
print_board_snapshot(data)
|
|
931
922
|
|
|
932
923
|
|
|
933
|
-
def _require_person_for_admin(action: str, *, json_mode: bool) -> None:
|
|
934
|
-
"""Refuse an organization API key on a structure or membership door.
|
|
935
|
-
|
|
936
|
-
Open-org Tasks: every non-guest member holds `tasks:admin` on a person session,
|
|
937
|
-
so the CLI never asks for an organization-admin role. An organization API key
|
|
938
|
-
still cannot store that scope (or change membership / participants), so the
|
|
939
|
-
message blames the **credential kind** — run `dailybot login` as a member.
|
|
940
|
-
"""
|
|
941
|
-
# Gate on the absence of a person token, not on the presence of a key: both
|
|
942
|
-
# can be configured at once, and Bearer is sent first when it exists.
|
|
943
|
-
if get_person_token() is None:
|
|
944
|
-
refuse_without_person(
|
|
945
|
-
f"`{action}` needs a signed-in person. An organization API key can never hold "
|
|
946
|
-
"the `tasks:admin` scope (it cannot even be stored on one), and keys cannot "
|
|
947
|
-
"change membership. Run `dailybot login` and retry as a non-guest member.",
|
|
948
|
-
json_mode=json_mode,
|
|
949
|
-
admin=True,
|
|
950
|
-
)
|
|
951
|
-
|
|
952
|
-
|
|
953
924
|
@board.command("create")
|
|
954
925
|
@click.option("-n", "--name", required=True, help="Board name.")
|
|
955
926
|
# Boards have no description field (BoardWrite declares none), so the flag the CLI
|
|
@@ -977,11 +948,11 @@ def board_create(
|
|
|
977
948
|
idempotency_key: str | None,
|
|
978
949
|
json_mode: bool,
|
|
979
950
|
) -> None:
|
|
980
|
-
"""Create a board in a project. Needs a
|
|
951
|
+
"""Create a board in a project. Needs a person (any non-guest member): `dailybot login` or a personal API key.
|
|
981
952
|
|
|
982
953
|
\b
|
|
983
|
-
An organization
|
|
984
|
-
|
|
954
|
+
An agent or organization key cannot do this. Visibility and who can see the
|
|
955
|
+
board are controlled by invite/remove, not by org role.
|
|
985
956
|
|
|
986
957
|
\b
|
|
987
958
|
Examples:
|
|
@@ -992,7 +963,6 @@ def board_create(
|
|
|
992
963
|
"Boards have no description. Put the context in a project "
|
|
993
964
|
"(`dailybot project create -d ...`) and create the board under it."
|
|
994
965
|
)
|
|
995
|
-
_require_person_for_admin("board create", json_mode=json_mode)
|
|
996
966
|
client = require_auth()
|
|
997
967
|
try:
|
|
998
968
|
with console.status("Creating the board..."):
|
|
@@ -1054,7 +1024,6 @@ def board_update(
|
|
|
1054
1024
|
dailybot board update <board-uuid> --name "Design (Q4)"
|
|
1055
1025
|
dailybot board update <board-uuid> --key DSN --visibility members --json
|
|
1056
1026
|
"""
|
|
1057
|
-
_require_person_for_admin("board update", json_mode=json_mode)
|
|
1058
1027
|
fields: dict[str, Any] = {
|
|
1059
1028
|
k: v
|
|
1060
1029
|
for k, v in {
|
|
@@ -1105,7 +1074,6 @@ def board_archive(
|
|
|
1105
1074
|
Examples:
|
|
1106
1075
|
dailybot board archive <board-uuid> --dry-run
|
|
1107
1076
|
"""
|
|
1108
|
-
_require_person_for_admin("board archive", json_mode=json_mode)
|
|
1109
1077
|
client = require_auth()
|
|
1110
1078
|
if not preview_then_confirm(
|
|
1111
1079
|
lambda: client.archive_board(board_uuid, dry_run=True),
|
|
@@ -1146,7 +1114,6 @@ def board_restore(board_uuid: str, idempotency_key: str | None, json_mode: bool)
|
|
|
1146
1114
|
Examples:
|
|
1147
1115
|
dailybot board restore <board-uuid>
|
|
1148
1116
|
"""
|
|
1149
|
-
_require_person_for_admin("board restore", json_mode=json_mode)
|
|
1150
1117
|
client = require_auth()
|
|
1151
1118
|
try:
|
|
1152
1119
|
with console.status("Restoring the board..."):
|
|
@@ -16,7 +16,6 @@ from dailybot_cli.commands.project import (
|
|
|
16
16
|
GOAL_INCLUDE_VALUES,
|
|
17
17
|
_envelope,
|
|
18
18
|
_include_list,
|
|
19
|
-
_require_person_for_admin,
|
|
20
19
|
)
|
|
21
20
|
from dailybot_cli.commands.public_api_helpers import (
|
|
22
21
|
emit_json,
|
|
@@ -186,7 +185,7 @@ def goal_create(
|
|
|
186
185
|
idempotency_key: str | None,
|
|
187
186
|
json_mode: bool,
|
|
188
187
|
) -> None:
|
|
189
|
-
"""Create a goal. Needs a
|
|
188
|
+
"""Create a goal. Needs a person (any non-guest member): `dailybot login` or a personal API key.
|
|
190
189
|
|
|
191
190
|
\b
|
|
192
191
|
A goal is a dated commitment, so both ends of its period are required. It starts
|
|
@@ -198,7 +197,6 @@ def goal_create(
|
|
|
198
197
|
"""
|
|
199
198
|
if period_end < period_start:
|
|
200
199
|
raise click.UsageError("--period-end is before --period-start.")
|
|
201
|
-
_require_person_for_admin("goal create", json_mode=json_mode)
|
|
202
200
|
client = require_auth()
|
|
203
201
|
try:
|
|
204
202
|
with console.status("Creating the goal..."):
|
|
@@ -234,7 +232,6 @@ def goal_archive(
|
|
|
234
232
|
Examples:
|
|
235
233
|
dailybot goal archive <goal-uuid> --dry-run
|
|
236
234
|
"""
|
|
237
|
-
_require_person_for_admin("goal archive", json_mode=json_mode)
|
|
238
235
|
client = require_auth()
|
|
239
236
|
if not preview_then_confirm(
|
|
240
237
|
lambda: client.archive_goal(goal_uuid, dry_run=True),
|
|
@@ -305,7 +302,6 @@ def goal_update(
|
|
|
305
302
|
dailybot goal update <goal-uuid> --status at_risk
|
|
306
303
|
dailybot goal update <goal-uuid> --period-end 2027-01-31 --owner <user-uuid> --json
|
|
307
304
|
"""
|
|
308
|
-
_require_person_for_admin("goal update", json_mode=json_mode)
|
|
309
305
|
if period_start and period_end and period_end < period_start:
|
|
310
306
|
raise click.UsageError("--period-end is before --period-start.")
|
|
311
307
|
fields: dict[str, Any] = {
|
|
@@ -349,7 +345,6 @@ def goal_restore(goal_uuid: str, json_mode: bool) -> None:
|
|
|
349
345
|
Examples:
|
|
350
346
|
dailybot goal restore <goal-uuid>
|
|
351
347
|
"""
|
|
352
|
-
_require_person_for_admin("goal restore", json_mode=json_mode)
|
|
353
348
|
client = require_auth()
|
|
354
349
|
try:
|
|
355
350
|
with console.status("Restoring the goal..."):
|
|
@@ -377,7 +372,6 @@ def goal_link(goal_uuid: str, project_uuid: str, json_mode: bool) -> None:
|
|
|
377
372
|
Examples:
|
|
378
373
|
dailybot goal link <goal-uuid> <project-uuid>
|
|
379
374
|
"""
|
|
380
|
-
_require_person_for_admin("goal link", json_mode=json_mode)
|
|
381
375
|
client = require_auth()
|
|
382
376
|
try:
|
|
383
377
|
with console.status("Linking the project..."):
|
|
@@ -406,7 +400,6 @@ def goal_unlink(
|
|
|
406
400
|
dailybot goal unlink <goal-uuid> <project-uuid> --dry-run
|
|
407
401
|
dailybot goal unlink <goal-uuid> <project-uuid> --yes
|
|
408
402
|
"""
|
|
409
|
-
_require_person_for_admin("goal unlink", json_mode=json_mode)
|
|
410
403
|
if not confirm_without_preview(
|
|
411
404
|
f"unlink project {project_uuid} from goal {goal_uuid}; its work stops counting toward "
|
|
412
405
|
"the goal.",
|
|
@@ -443,7 +436,7 @@ def goal_unlink(
|
|
|
443
436
|
@click.option("--caption", default=None, help="Short caption shown with the file.")
|
|
444
437
|
@click.option("--json", "json_mode", is_flag=True, help="Emit machine-readable JSON to stdout.")
|
|
445
438
|
def goal_attach(goal_uuid: str, file_path: Path, caption: str | None, json_mode: bool) -> None:
|
|
446
|
-
"""Attach a file to a goal. Needs a
|
|
439
|
+
"""Attach a file to a goal. Needs a person (any non-guest member): `dailybot login` or a personal API key.
|
|
447
440
|
|
|
448
441
|
\b
|
|
449
442
|
One request, up to 5 MiB. Your Dailybot credentials go only to the API.
|
|
@@ -453,7 +446,6 @@ def goal_attach(goal_uuid: str, file_path: Path, caption: str | None, json_mode:
|
|
|
453
446
|
dailybot goal attach <goal-uuid> ./plan.pdf
|
|
454
447
|
dailybot goal attach <goal-uuid> ./roadmap.png --caption "Q4 roadmap" --json
|
|
455
448
|
"""
|
|
456
|
-
_require_person_for_admin("goal attach", json_mode=json_mode)
|
|
457
449
|
run_attach(
|
|
458
450
|
lambda client, **file: client.upload_goal_attachment(goal_uuid, **file),
|
|
459
451
|
file_path,
|
|
@@ -535,14 +527,13 @@ def goal_attachment_get(
|
|
|
535
527
|
def goal_attachment_delete(
|
|
536
528
|
goal_uuid: str, attachment_uuid: str, dry_run: bool, assume_yes: bool, json_mode: bool
|
|
537
529
|
) -> None:
|
|
538
|
-
"""Remove an attachment from a goal. This cannot be undone. Needs a
|
|
530
|
+
"""Remove an attachment from a goal. This cannot be undone. Needs a person: `dailybot login` or a personal API key.
|
|
539
531
|
|
|
540
532
|
\b
|
|
541
533
|
Examples:
|
|
542
534
|
dailybot goal attachment delete <goal-uuid> <attachment-uuid> --dry-run
|
|
543
535
|
dailybot goal attachment delete <goal-uuid> <attachment-uuid> --yes
|
|
544
536
|
"""
|
|
545
|
-
_require_person_for_admin("goal attachment delete", json_mode=json_mode)
|
|
546
537
|
run_delete(
|
|
547
538
|
lambda client: client.delete_goal_attachment(goal_uuid, attachment_uuid),
|
|
548
539
|
f"delete attachment {attachment_uuid} from goal {goal_uuid}.",
|
|
@@ -16,12 +16,10 @@ from dailybot_cli.commands.public_api_helpers import (
|
|
|
16
16
|
emit_json,
|
|
17
17
|
exit_for_tasks_error,
|
|
18
18
|
load_json_input,
|
|
19
|
-
refuse_without_person,
|
|
20
19
|
require_auth,
|
|
21
20
|
rows_of,
|
|
22
21
|
)
|
|
23
22
|
from dailybot_cli.commands.query_options import build_query_params, query_options, resolve_fetch_all
|
|
24
|
-
from dailybot_cli.config import get_person_token
|
|
25
23
|
from dailybot_cli.display import (
|
|
26
24
|
console,
|
|
27
25
|
present_untrusted,
|
|
@@ -381,24 +379,6 @@ def project_milestone_reopen(
|
|
|
381
379
|
report_write(data, "Milestone reopened")
|
|
382
380
|
|
|
383
381
|
|
|
384
|
-
def _require_person_for_admin(action: str, *, json_mode: bool) -> None:
|
|
385
|
-
"""Refuse an organization API key on a structure or membership door.
|
|
386
|
-
|
|
387
|
-
See board.py: open-org Tasks gives every non-guest member structure access on
|
|
388
|
-
a person session; keys still cannot store `tasks:admin` or change membership.
|
|
389
|
-
"""
|
|
390
|
-
# Gate on the absence of a person token, not on the presence of a key: both
|
|
391
|
-
# can be configured at once, and Bearer is sent first when it exists.
|
|
392
|
-
if get_person_token() is None:
|
|
393
|
-
refuse_without_person(
|
|
394
|
-
f"`{action}` needs a signed-in person. An organization API key can never hold "
|
|
395
|
-
"the `tasks:admin` scope (it cannot even be stored on one), and keys cannot "
|
|
396
|
-
"change membership. Run `dailybot login` and retry as a non-guest member.",
|
|
397
|
-
json_mode=json_mode,
|
|
398
|
-
admin=True,
|
|
399
|
-
)
|
|
400
|
-
|
|
401
|
-
|
|
402
382
|
def _project_fields(
|
|
403
383
|
visibility: str | None,
|
|
404
384
|
lead: str | None,
|
|
@@ -461,7 +441,7 @@ def project_create(
|
|
|
461
441
|
idempotency_key: str | None,
|
|
462
442
|
json_mode: bool,
|
|
463
443
|
) -> None:
|
|
464
|
-
"""Create a project. Needs a
|
|
444
|
+
"""Create a project. Needs a person (any non-guest member): `dailybot login` or a personal API key.
|
|
465
445
|
|
|
466
446
|
\b
|
|
467
447
|
Examples:
|
|
@@ -469,7 +449,6 @@ def project_create(
|
|
|
469
449
|
dailybot project create -n "Apollo" --lead <user-uuid> --target-date 2026-12-15 --json
|
|
470
450
|
"""
|
|
471
451
|
extra: dict[str, Any] = _project_fields(visibility, lead, health, start_date, target_date)
|
|
472
|
-
_require_person_for_admin("project create", json_mode=json_mode)
|
|
473
452
|
client = require_auth()
|
|
474
453
|
try:
|
|
475
454
|
with console.status("Creating the project..."):
|
|
@@ -499,7 +478,6 @@ def project_archive(
|
|
|
499
478
|
Examples:
|
|
500
479
|
dailybot project archive <project-uuid> --dry-run
|
|
501
480
|
"""
|
|
502
|
-
_require_person_for_admin("project archive", json_mode=json_mode)
|
|
503
481
|
client = require_auth()
|
|
504
482
|
if not preview_then_confirm(
|
|
505
483
|
lambda: client.archive_project(project_uuid, dry_run=True),
|
|
@@ -543,8 +521,8 @@ def project_update(
|
|
|
543
521
|
"""Change a project's name, lead, health, dates or visibility.
|
|
544
522
|
|
|
545
523
|
\b
|
|
546
|
-
Only the fields you pass are sent. Any
|
|
547
|
-
|
|
524
|
+
Only the fields you pass are sent. Any non-guest member can update, with
|
|
525
|
+
`dailybot login` or a personal API key; an agent or organization key cannot. Setting `--visibility members` privatizes the
|
|
548
526
|
project and auto-grants you; invite others with `project member add`. To post
|
|
549
527
|
a status note for the team, use `dailybot project update-post` instead.
|
|
550
528
|
|
|
@@ -553,7 +531,6 @@ def project_update(
|
|
|
553
531
|
dailybot project update <project-uuid> --health at_risk
|
|
554
532
|
dailybot project update <project-uuid> --target-date 2027-01-15 --lead <user-uuid> --json
|
|
555
533
|
"""
|
|
556
|
-
_require_person_for_admin("project update", json_mode=json_mode)
|
|
557
534
|
fields: dict[str, Any] = _project_fields(visibility, lead, health, start_date, target_date)
|
|
558
535
|
if name is not None:
|
|
559
536
|
fields["name"] = name
|
|
@@ -590,7 +567,6 @@ def project_restore(project_uuid: str, idempotency_key: str | None, json_mode: b
|
|
|
590
567
|
Examples:
|
|
591
568
|
dailybot project restore <project-uuid>
|
|
592
569
|
"""
|
|
593
|
-
_require_person_for_admin("project restore", json_mode=json_mode)
|
|
594
570
|
client = require_auth()
|
|
595
571
|
try:
|
|
596
572
|
with console.status("Restoring the project..."):
|
|
@@ -606,13 +582,9 @@ def project_restore(project_uuid: str, idempotency_key: str | None, json_mode: b
|
|
|
606
582
|
|
|
607
583
|
|
|
608
584
|
# ---------------------------------------------------------------------------
|
|
609
|
-
# Members and saved views
|
|
585
|
+
# Members and saved views
|
|
610
586
|
# ---------------------------------------------------------------------------
|
|
611
587
|
|
|
612
|
-
_MEMBER_REASON: str = (
|
|
613
|
-
"changes or reveals who can see a private project, and no organization API key may do "
|
|
614
|
-
"that — there is no person behind it to be accountable."
|
|
615
|
-
)
|
|
616
588
|
_MEMBER_COLUMNS: list[tuple[str, str, bool]] = [
|
|
617
589
|
("Kind", "subject_type", True),
|
|
618
590
|
("Name", "name", False),
|
|
@@ -627,15 +599,6 @@ _VIEW_COLUMNS: list[tuple[str, str, bool]] = [
|
|
|
627
599
|
]
|
|
628
600
|
|
|
629
601
|
|
|
630
|
-
def _require_person(action: str, reason: str, *, json_mode: bool) -> None:
|
|
631
|
-
"""Refuse an API key on a person-only project door, before any request."""
|
|
632
|
-
if get_person_token() is None:
|
|
633
|
-
refuse_without_person(
|
|
634
|
-
f"`{action}` {reason} Run `dailybot login` and retry as a signed-in person.",
|
|
635
|
-
json_mode=json_mode,
|
|
636
|
-
)
|
|
637
|
-
|
|
638
|
-
|
|
639
602
|
@project.command("members")
|
|
640
603
|
@click.argument("project_uuid", metavar="PROJECT")
|
|
641
604
|
@click.option("--json", "json_mode", is_flag=True, help="Emit machine-readable JSON to stdout.")
|
|
@@ -660,14 +623,14 @@ def project_members(project_uuid: str, json_mode: bool) -> None:
|
|
|
660
623
|
|
|
661
624
|
@project.group("member")
|
|
662
625
|
def project_member() -> None:
|
|
663
|
-
"""Invite or remove people and teams on a project. Needs `dailybot login
|
|
626
|
+
"""Invite or remove people and teams on a project. Needs a person: `dailybot login` or a personal API key.
|
|
664
627
|
|
|
665
628
|
\b
|
|
666
629
|
Membership is the privacy control: a `members` project is not visible (404)
|
|
667
630
|
to anyone without a grant. Org-wide projects are a shared workspace. Invite a
|
|
668
631
|
person or a team to close a private project; the last grant cannot be removed
|
|
669
|
-
(`last_grant_cannot_be_removed`). There is no project role to edit. An
|
|
670
|
-
organization
|
|
632
|
+
(`last_grant_cannot_be_removed`). There is no project role to edit. An agent or
|
|
633
|
+
organization key cannot change membership.
|
|
671
634
|
|
|
672
635
|
\b
|
|
673
636
|
Examples:
|
|
@@ -696,7 +659,6 @@ def project_member_add(
|
|
|
696
659
|
dailybot project member add <project-uuid> --user <user-uuid>
|
|
697
660
|
dailybot project member add <project-uuid> --team <team-uuid> --json
|
|
698
661
|
"""
|
|
699
|
-
_require_person_for_admin("project member add", json_mode=json_mode)
|
|
700
662
|
if (user_uuid is None) == (team_uuid is None):
|
|
701
663
|
raise click.UsageError("Pass exactly one of --user or --team.")
|
|
702
664
|
client = require_auth()
|
|
@@ -729,7 +691,6 @@ def project_member_remove(
|
|
|
729
691
|
dailybot project member remove <project-uuid> <user-uuid> --dry-run
|
|
730
692
|
dailybot project member remove <project-uuid> <user-uuid> --yes
|
|
731
693
|
"""
|
|
732
|
-
_require_person_for_admin("project member remove", json_mode=json_mode)
|
|
733
694
|
if not confirm_without_preview(
|
|
734
695
|
f"remove user {user_uuid} from project {project_uuid}; they lose sight of it if it "
|
|
735
696
|
"is private.",
|
|
@@ -767,11 +728,6 @@ def project_views(project_uuid: str, etag_only: bool, json_mode: bool) -> None:
|
|
|
767
728
|
dailybot project views <project-uuid>
|
|
768
729
|
ETAG=$(dailybot project views <project-uuid> --etag)
|
|
769
730
|
"""
|
|
770
|
-
_require_person(
|
|
771
|
-
"project views",
|
|
772
|
-
"lists saved views, which belong to a person, and an organization API key is not one.",
|
|
773
|
-
json_mode=json_mode,
|
|
774
|
-
)
|
|
775
731
|
client = require_auth()
|
|
776
732
|
try:
|
|
777
733
|
with console.status("Reading the views..."):
|
|
@@ -791,7 +747,7 @@ def project_views(project_uuid: str, etag_only: bool, json_mode: bool) -> None:
|
|
|
791
747
|
|
|
792
748
|
@project.group("view")
|
|
793
749
|
def project_view() -> None:
|
|
794
|
-
"""Save your views of a project. Needs `dailybot login
|
|
750
|
+
"""Save your views of a project. Needs a person: `dailybot login` or a personal API key.
|
|
795
751
|
|
|
796
752
|
\b
|
|
797
753
|
Examples:
|
|
@@ -834,11 +790,6 @@ def project_view_save(
|
|
|
834
790
|
raise click.BadParameter(f"not valid JSON: {exc}", param_hint="--file") from exc
|
|
835
791
|
if not isinstance(views, list):
|
|
836
792
|
raise click.BadParameter("must be a JSON array of views.", param_hint="--file")
|
|
837
|
-
_require_person(
|
|
838
|
-
"project view save",
|
|
839
|
-
"saves views that belong to a person, and an organization API key is not one.",
|
|
840
|
-
json_mode=json_mode,
|
|
841
|
-
)
|
|
842
793
|
client = require_auth()
|
|
843
794
|
try:
|
|
844
795
|
etag: str | None = if_match
|
|
@@ -995,7 +946,7 @@ def project_milestone_delete(
|
|
|
995
946
|
def project_attach(
|
|
996
947
|
project_uuid: str, file_path: Path, caption: str | None, json_mode: bool
|
|
997
948
|
) -> None:
|
|
998
|
-
"""Attach a file to a project. Needs a
|
|
949
|
+
"""Attach a file to a project. Needs a person (any non-guest member): `dailybot login` or a personal API key.
|
|
999
950
|
|
|
1000
951
|
\b
|
|
1001
952
|
One request, up to 5 MiB. Your Dailybot credentials go only to the API.
|
|
@@ -1005,7 +956,6 @@ def project_attach(
|
|
|
1005
956
|
dailybot project attach <project-uuid> ./plan.pdf
|
|
1006
957
|
dailybot project attach <project-uuid> ./roadmap.png --caption "Q4 roadmap" --json
|
|
1007
958
|
"""
|
|
1008
|
-
_require_person_for_admin("project attach", json_mode=json_mode)
|
|
1009
959
|
run_attach(
|
|
1010
960
|
lambda client, **file: client.upload_project_attachment(project_uuid, **file),
|
|
1011
961
|
file_path,
|
|
@@ -1087,14 +1037,13 @@ def project_attachment_get(
|
|
|
1087
1037
|
def project_attachment_delete(
|
|
1088
1038
|
project_uuid: str, attachment_uuid: str, dry_run: bool, assume_yes: bool, json_mode: bool
|
|
1089
1039
|
) -> None:
|
|
1090
|
-
"""Remove an attachment from a project. This cannot be undone. Needs a
|
|
1040
|
+
"""Remove an attachment from a project. This cannot be undone. Needs a person: `dailybot login` or a personal API key.
|
|
1091
1041
|
|
|
1092
1042
|
\b
|
|
1093
1043
|
Examples:
|
|
1094
1044
|
dailybot project attachment delete <project-uuid> <attachment-uuid> --dry-run
|
|
1095
1045
|
dailybot project attachment delete <project-uuid> <attachment-uuid> --yes
|
|
1096
1046
|
"""
|
|
1097
|
-
_require_person_for_admin("project attachment delete", json_mode=json_mode)
|
|
1098
1047
|
run_delete(
|
|
1099
1048
|
lambda client: client.delete_project_attachment(project_uuid, attachment_uuid),
|
|
1100
1049
|
f"delete attachment {attachment_uuid} from project {project_uuid}.",
|
|
@@ -58,10 +58,11 @@ ERROR_CODE_MESSAGES: dict[str, str] = {
|
|
|
58
58
|
#
|
|
59
59
|
# Agent attribution (--agent-name / DAILYBOT_AGENT_NAME)
|
|
60
60
|
"invalid_agent_attribution": (
|
|
61
|
-
"The agent name was refused.
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
61
|
+
"The agent name was refused. Use a plain name of 128 characters or fewer: "
|
|
62
|
+
"letters, numbers, spaces and . - _ ( ) ' # + / & , : only. The name must "
|
|
63
|
+
"not belong to a deactivated agent, and it only works with a credential that "
|
|
64
|
+
"belongs to a person (a login session or a personal API key), not an agent "
|
|
65
|
+
"key. Fix --agent-name / DAILYBOT_AGENT_NAME, or drop it."
|
|
65
66
|
),
|
|
66
67
|
# Auth taxonomy
|
|
67
68
|
"credential_absent": (
|
|
@@ -592,54 +593,18 @@ _PERSON_SHAPED_GUIDANCE: str = (
|
|
|
592
593
|
"that belongs to you, and retry."
|
|
593
594
|
)
|
|
594
595
|
|
|
595
|
-
#
|
|
596
|
-
#
|
|
597
|
-
#
|
|
596
|
+
# Every non-guest member holds `tasks:admin`, on a login session and on their own
|
|
597
|
+
# personal API key alike. Only a credential with nobody behind it (an agent or
|
|
598
|
+
# organization key) cannot — so the fix is a person, never an admin grant.
|
|
598
599
|
_ADMIN_SCOPE_GUIDANCE: str = (
|
|
599
|
-
"This
|
|
600
|
-
"`tasks:admin`
|
|
601
|
-
"
|
|
600
|
+
"This key cannot change Tasks structure. Either it is an agent or organization key, "
|
|
601
|
+
"which can never hold `tasks:admin` (use `dailybot login` or a personal API key that "
|
|
602
|
+
"belongs to you), or it is a personal key whose own scopes are narrower (for example "
|
|
603
|
+
"read-only); widen or remove that key's Tasks scopes, or use `dailybot login`. Guests are "
|
|
604
|
+
"refused either way; that is a role limit."
|
|
602
605
|
)
|
|
603
606
|
|
|
604
607
|
|
|
605
|
-
# Machine-readable codes for the two client-side preflight refusals. They match
|
|
606
|
-
# what the server would answer for the same condition, so a caller branching on
|
|
607
|
-
# `code` cannot tell whether the request was spent — and does not need to.
|
|
608
|
-
PREFLIGHT_ACTOR_REQUIRED_CODE: str = "actor_required"
|
|
609
|
-
PREFLIGHT_ADMIN_SCOPE_CODE: str = "insufficient_scope"
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
def refuse_without_person(message: str, *, json_mode: bool, admin: bool = False) -> NoReturn:
|
|
613
|
-
"""End a command that a bare API key can never satisfy.
|
|
614
|
-
|
|
615
|
-
One helper, four call sites. Each module used to carry its own copy, and every
|
|
616
|
-
copy ignored ``--json`` — so `dailybot board create --json` with a key-only
|
|
617
|
-
session exited 3 with **empty stdout** while `exit_for_tasks_error` promised a
|
|
618
|
-
parseable document on every refusal path. A caller that parses stdout on any
|
|
619
|
-
non-zero exit read that as a crash rather than a credential problem.
|
|
620
|
-
|
|
621
|
-
``admin`` selects the code the server would have used for the same condition.
|
|
622
|
-
"""
|
|
623
|
-
if json_mode:
|
|
624
|
-
emit_json(
|
|
625
|
-
{
|
|
626
|
-
"status": "error",
|
|
627
|
-
"code": (PREFLIGHT_ADMIN_SCOPE_CODE if admin else PREFLIGHT_ACTOR_REQUIRED_CODE),
|
|
628
|
-
"detail": message,
|
|
629
|
-
"message": message,
|
|
630
|
-
}
|
|
631
|
-
)
|
|
632
|
-
else:
|
|
633
|
-
print_error(message)
|
|
634
|
-
# The exit must match what the SERVER would return for the same condition, or
|
|
635
|
-
# the pre-flight becomes observable: an agent branching "3 → re-login,
|
|
636
|
-
# 4 → permission" saw 3 from the pre-flight and 4 from the server for one
|
|
637
|
-
# condition. A `tasks:admin` refusal is a 403 on the wire, so it is 4 here too;
|
|
638
|
-
# a person-shaped door answers `actor_required`, which is a credential problem
|
|
639
|
-
# and stays 3.
|
|
640
|
-
raise SystemExit(EXIT_PERMISSION_DENIED if admin else EXIT_NOT_AUTHENTICATED)
|
|
641
|
-
|
|
642
|
-
|
|
643
608
|
def is_person_shaped_refusal(exc: APIError, *, door: str | None = None) -> bool:
|
|
644
609
|
"""Is this refusal the "you are not a person" condition, in either shape?
|
|
645
610
|
|
|
@@ -658,9 +623,10 @@ def is_person_shaped_refusal(exc: APIError, *, door: str | None = None) -> bool:
|
|
|
658
623
|
# New organization API keys start with no Tasks scopes; they are granted to the key
|
|
659
624
|
# itself. Said once here so every Tasks refusal on a key reads the same.
|
|
660
625
|
_KEY_WITHOUT_TASKS_SCOPES_GUIDANCE: str = (
|
|
661
|
-
"This API key has no Tasks scopes for this action{scope}
|
|
662
|
-
"
|
|
663
|
-
"
|
|
626
|
+
"This API key has no Tasks scopes for this action{scope}. A personal API key acts as "
|
|
627
|
+
"you and needs no grant; an agent or organization key starts with none, and an "
|
|
628
|
+
"organization admin grants them to the key (or write to support@dailybot.com). Signing "
|
|
629
|
+
"in with `dailybot login` also works for your own account."
|
|
664
630
|
)
|
|
665
631
|
|
|
666
632
|
|
|
@@ -49,7 +49,6 @@ from dailybot_cli.commands.public_api_helpers import (
|
|
|
49
49
|
emit_json,
|
|
50
50
|
exit_for_tasks_error,
|
|
51
51
|
load_json_input,
|
|
52
|
-
refuse_without_person,
|
|
53
52
|
require_auth,
|
|
54
53
|
rows_of,
|
|
55
54
|
)
|
|
@@ -60,7 +59,6 @@ from dailybot_cli.commands.query_options import (
|
|
|
60
59
|
query_options,
|
|
61
60
|
resolve_fetch_all,
|
|
62
61
|
)
|
|
63
|
-
from dailybot_cli.config import get_person_token
|
|
64
62
|
from dailybot_cli.display import (
|
|
65
63
|
console,
|
|
66
64
|
error_console,
|
|
@@ -724,22 +722,6 @@ def task_assign(task_ref: str, owner: str, idempotency_key: str | None, json_mod
|
|
|
724
722
|
_set_owner(task_ref, owner, idempotency_key, json_mode)
|
|
725
723
|
|
|
726
724
|
|
|
727
|
-
def _require_person_for(action: str, *, json_mode: bool) -> None:
|
|
728
|
-
"""Refuse a key on a person-only door.
|
|
729
|
-
|
|
730
|
-
Published policy: two writes no organization API key may ever make — changing
|
|
731
|
-
who can see, and changing who is notified. Participants are the second.
|
|
732
|
-
"""
|
|
733
|
-
# Gate on the absence of a person token, not on the presence of a key: both
|
|
734
|
-
# can be configured at once, and Bearer is sent first when it exists.
|
|
735
|
-
if get_person_token() is None:
|
|
736
|
-
refuse_without_person(
|
|
737
|
-
f"`{action}` changes who is notified, and no organization API key may do that — "
|
|
738
|
-
"there is no person behind it to be accountable. Run `dailybot login` and retry.",
|
|
739
|
-
json_mode=json_mode,
|
|
740
|
-
)
|
|
741
|
-
|
|
742
|
-
|
|
743
725
|
def _read_body(value: str) -> str:
|
|
744
726
|
"""Read a body argument, or stdin when it is `-`."""
|
|
745
727
|
if value == "-":
|
|
@@ -928,7 +910,6 @@ def participants_add(
|
|
|
928
910
|
Examples:
|
|
929
911
|
dailybot task participants add ENG-142 --user <user-uuid>
|
|
930
912
|
"""
|
|
931
|
-
_require_person_for("task participants add", json_mode=json_mode)
|
|
932
913
|
client = require_auth()
|
|
933
914
|
try:
|
|
934
915
|
with console.status("Adding the participant..."):
|
|
@@ -1003,7 +984,6 @@ def participants_remove(
|
|
|
1003
984
|
dailybot task participants remove ENG-142 <user-uuid> --dry-run
|
|
1004
985
|
dailybot task participants remove ENG-142 <user-uuid> --yes
|
|
1005
986
|
"""
|
|
1006
|
-
_require_person_for("task participants remove", json_mode=json_mode)
|
|
1007
987
|
if not confirm_without_preview(
|
|
1008
988
|
f"take user {user_uuid} off task {task_uuid}; they stop being notified about it.",
|
|
1009
989
|
assume_yes=assume_yes,
|
|
@@ -1025,8 +1005,6 @@ def participants_remove(
|
|
|
1025
1005
|
|
|
1026
1006
|
def _set_own_mute(task_uuid: str, muted: bool, json_mode: bool) -> None:
|
|
1027
1007
|
"""Record the caller's mute on a task: POST participants/ for yourself with `is_muted`."""
|
|
1028
|
-
action: str = "task mute" if muted else "task unmute"
|
|
1029
|
-
_require_person_for(action, json_mode=json_mode)
|
|
1030
1008
|
client = require_auth()
|
|
1031
1009
|
try:
|
|
1032
1010
|
with console.status("Reading who you are..."):
|
|
@@ -1050,7 +1028,7 @@ def _set_own_mute(task_uuid: str, muted: bool, json_mode: bool) -> None:
|
|
|
1050
1028
|
@click.argument("task_uuid", metavar="TASK")
|
|
1051
1029
|
@click.option("--json", "json_mode", is_flag=True, help="Emit machine-readable JSON to stdout.")
|
|
1052
1030
|
def task_mute(task_uuid: str, json_mode: bool) -> None:
|
|
1053
|
-
"""Stop notifications from a task while staying on it. Needs `dailybot login
|
|
1031
|
+
"""Stop notifications from a task while staying on it. Needs a person: `dailybot login` or a personal API key.
|
|
1054
1032
|
|
|
1055
1033
|
\b
|
|
1056
1034
|
Examples:
|
|
@@ -1063,7 +1041,7 @@ def task_mute(task_uuid: str, json_mode: bool) -> None:
|
|
|
1063
1041
|
@click.argument("task_uuid", metavar="TASK")
|
|
1064
1042
|
@click.option("--json", "json_mode", is_flag=True, help="Emit machine-readable JSON to stdout.")
|
|
1065
1043
|
def task_unmute(task_uuid: str, json_mode: bool) -> None:
|
|
1066
|
-
"""Resume notifications from a task you muted. Needs `dailybot login
|
|
1044
|
+
"""Resume notifications from a task you muted. Needs a person: `dailybot login` or a personal API key.
|
|
1067
1045
|
|
|
1068
1046
|
\b
|
|
1069
1047
|
Examples:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dailybot-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.20.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
|
|
@@ -905,11 +905,13 @@ Replies to agent emails land as messages retrievable via `dailybot agent message
|
|
|
905
905
|
Projects, boards and tasks. Two groups: **`dailybot tasks`** answers questions about the
|
|
906
906
|
workspace, **`dailybot task`** reads or changes one task.
|
|
907
907
|
|
|
908
|
-
**
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
908
|
+
**Your personal API key is you.** A login session (`dailybot login`) and a personal API key
|
|
909
|
+
(one bound to you) can do everything you can do in the web app: create, update, archive and
|
|
910
|
+
restore boards, columns, projects, goals and milestones, manage board and project
|
|
911
|
+
membership, link goals to projects, and work every task. That is every non-guest member, no
|
|
912
|
+
organization-admin prerequisite. Only an agent or organization key, with nobody behind it,
|
|
913
|
+
cannot act as a person: the server refuses it (`actor_required` exit 3, `insufficient_scope`
|
|
914
|
+
exit 4). Guests stay limited by their role.
|
|
913
915
|
**Privacy is membership**, not org role: a `members` project or board is 404 (not visible)
|
|
914
916
|
to anyone without a grant; invite a person or a team to close it.
|
|
915
917
|
A board inside a `members` project follows the project's membership: whoever the project
|
|
@@ -954,9 +956,9 @@ humans who own them.
|
|
|
954
956
|
| `dailybot task comments <uuid>` | List a task's comments |
|
|
955
957
|
| `dailybot task link <a> <b> --type <rel>` | Relate two tasks (`blocks`, `relates_to`, `duplicates`) |
|
|
956
958
|
| `dailybot task labels <uuid> --mode add\|remove\|replace` | Change a task's labels |
|
|
957
|
-
| `dailybot task participants add\|list\|remove <task>` | Who is on a task (`--role participant\|watcher`); `
|
|
959
|
+
| `dailybot task participants add\|list\|remove <task>` | Who is on a task (`--role participant\|watcher`); all need a person: `dailybot login` or a personal API key |
|
|
958
960
|
| `dailybot task watch\|unwatch <task>` | Follow a task privately — **needs a person: `dailybot login` or a personal API key** |
|
|
959
|
-
| `dailybot task mute\|unmute <task>` | Silence a task and stay on it (leaving is `participants remove`) — **needs `dailybot login
|
|
961
|
+
| `dailybot task mute\|unmute <task>` | Silence a task and stay on it (leaving is `participants remove`) — **needs a person: `dailybot login` or a personal API key** |
|
|
960
962
|
| `dailybot task relations <task>` · `task unlink <task> <relation>` | List links (direction included) / remove one; `unlink` confirms and has `--dry-run` |
|
|
961
963
|
| `dailybot task comment-edit\|comment-delete <task> <comment>` | Edit (`-` reads stdin) or delete a comment; delete blanks the text and keeps the entry |
|
|
962
964
|
| `dailybot task children <task>` · `task events <task>` · `task activity <task>` | Sub-tasks, raw event history, and the readable activity feed (`--updated-since`, `--type`) |
|
|
@@ -978,12 +980,12 @@ humans who own them.
|
|
|
978
980
|
| `dailybot board labels <uuid>` | Labels available on the board — **needs a person: `dailybot login` or a personal API key** |
|
|
979
981
|
| `dailybot board views <uuid>` | Your saved views on the board, plus the ETag a save needs (`--etag` prints only that) |
|
|
980
982
|
| `dailybot board state create\|update\|archive\|restore\|reorder` | Manage columns. `archive` previews first and takes `--migrate-to <state>` to move the column's cards |
|
|
981
|
-
| `dailybot board member add <board> <user>` (or `--team <team>`) · `board member remove <board> <user>` | Who can see the board — **needs `dailybot login
|
|
983
|
+
| `dailybot board member add <board> <user>` (or `--team <team>`) · `board member remove <board> <user>` | Who can see the board — **needs a person: `dailybot login` or a personal API key**. Membership is the privacy control (not org role). A team grant follows the team live. Last grant on a private board stays (`last_grant_cannot_be_removed`) |
|
|
982
984
|
| `dailybot board label create <board> -n <name>` | Create an organization label from the board — **needs a person: `dailybot login` or a personal API key** |
|
|
983
985
|
| `dailybot board view save <board> -f views.json --if-match <etag>` | Replace your saved views (the whole list) — **needs a person: `dailybot login` or a personal API key** |
|
|
984
986
|
| `dailybot board snapshot <uuid>` | The whole board in one request; carries the `delta_cursor` that `tasks changes` consumes |
|
|
985
987
|
| `dailybot board update <uuid>` | Name, key (the old key stays reserved), visibility, estimate scale, auto-archive, project |
|
|
986
|
-
| `dailybot board create --name <n> --project <uuid> --key <KEY>` | Create a board in a project; the key prefixes its tasks (`DSN-1`) — **needs `dailybot login
|
|
988
|
+
| `dailybot board create --name <n> --project <uuid> --key <KEY>` | Create a board in a project; the key prefixes its tasks (`DSN-1`) — **needs a person: `dailybot login` or a personal API key** (any non-guest member) |
|
|
987
989
|
| `dailybot board archive <uuid>` | Archive a board. **Cascade-archives its live tasks**, and restoring does not bring them back |
|
|
988
990
|
| `dailybot board restore <uuid>` | Restore a board (cascaded tasks stay archived) |
|
|
989
991
|
| `dailybot project list` | List projects (`--include progress`) |
|
|
@@ -993,28 +995,28 @@ humans who own them.
|
|
|
993
995
|
| `dailybot project milestones [<uuid>]` | List milestones |
|
|
994
996
|
| `dailybot project milestone-complete <p> <m>` | Complete a milestone. **Its open tasks stay open** |
|
|
995
997
|
| `dailybot project milestone-reopen <p> <m>` | Reopen a milestone |
|
|
996
|
-
| `dailybot project create --name <n>` | Create a project — **needs `dailybot login
|
|
998
|
+
| `dailybot project create --name <n>` | Create a project — **needs a person: `dailybot login` or a personal API key** |
|
|
997
999
|
| `dailybot project update <uuid>` | Name, description, lead, health, dates, visibility |
|
|
998
1000
|
| `dailybot project restore <uuid>` | Restore an archived project (its boards and tasks stay archived) |
|
|
999
|
-
| `dailybot project members <uuid>` · `project member add\|remove` | Who can see the project — people or whole teams (`--team`) — `members` works with a personal API key; `member add\|remove` **needs `dailybot login
|
|
1000
|
-
| `dailybot project views <uuid>` · `project view save` | Your saved views; save replaces the list and requires the ETag — **needs `dailybot login
|
|
1001
|
+
| `dailybot project members <uuid>` · `project member add\|remove` | Who can see the project — people or whole teams (`--team`) — `members` works with a personal API key; `member add\|remove` **needs a person: `dailybot login` or a personal API key** |
|
|
1002
|
+
| `dailybot project views <uuid>` · `project view save` | Your saved views; save replaces the list and requires the ETag — **needs a person: `dailybot login` or a personal API key** |
|
|
1001
1003
|
| `dailybot project milestone-create\|milestone-update\|milestone-delete` | Dated milestones; delete retires it (tasks keep pointing at it) |
|
|
1002
1004
|
| `dailybot project archive <uuid>` | Archive a project |
|
|
1003
|
-
| `dailybot project attach <uuid> <file>` · `project attachments` · `project attachment get\|delete` | Files on a project (≤5 MiB, one request). Attaching and deleting need `dailybot login` |
|
|
1005
|
+
| `dailybot project attach <uuid> <file>` · `project attachments` · `project attachment get\|delete` | Files on a project (≤5 MiB, one request). Attaching and deleting need a person (`dailybot login` or a personal API key) |
|
|
1004
1006
|
| `dailybot goal list` | List goals (`--include` is repeatable: `--include progress --include projects`) |
|
|
1005
1007
|
| `dailybot goal get <uuid>` | Show one goal, with its progress and linked projects (always included) |
|
|
1006
|
-
| `dailybot goal create --name <n> --period-start <d> --period-end <d>` | Create a goal (a dated commitment) — **needs `dailybot login
|
|
1008
|
+
| `dailybot goal create --name <n> --period-start <d> --period-end <d>` | Create a goal (a dated commitment) — **needs a person: `dailybot login` or a personal API key** |
|
|
1007
1009
|
| `dailybot goal update <uuid>` | Name, period, owner, team, and the declared `--status` (not_started, on_track, at_risk, off_track, achieved, missed) |
|
|
1008
1010
|
| `dailybot goal restore <uuid>` | Restore an archived goal |
|
|
1009
1011
|
| `dailybot goal link\|unlink <goal> <project>` | Make a project count toward a goal (or stop it) |
|
|
1010
1012
|
| `dailybot goal archive <uuid>` | Archive a goal (its projects are not archived) |
|
|
1011
|
-
| `dailybot goal attach <uuid> <file>` · `goal attachments` · `goal attachment get\|delete` | Files on a goal (≤5 MiB, one request). Attaching and deleting need `dailybot login` |
|
|
1013
|
+
| `dailybot goal attach <uuid> <file>` · `goal attachments` · `goal attachment get\|delete` | Files on a goal (≤5 MiB, one request). Attaching and deleting need a person (`dailybot login` or a personal API key) |
|
|
1012
1014
|
|
|
1013
1015
|
**Three things worth knowing before you script against this:**
|
|
1014
1016
|
|
|
1015
|
-
- **Some doors need a person.**
|
|
1016
|
-
"my inbox", can never hold
|
|
1017
|
-
|
|
1017
|
+
- **Some doors need a person.** A login session or a personal API key is a person; an agent
|
|
1018
|
+
or organization key has no answer for "my tasks" or "my inbox", can never hold
|
|
1019
|
+
`tasks:admin`, and cannot change membership or participants. A 404 means
|
|
1018
1020
|
not visible (wrong id, private without a grant, or another org) — never "not allowed".
|
|
1019
1021
|
- **Roll-ups are opt-in.** A field you did not request with `--include` is **absent** from
|
|
1020
1022
|
the payload. Absent, `null` and `0` are three different answers, and the CLI renders them
|
|
@@ -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.20.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
|
|
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
|