@bussolabs/closeyourit-cli 0.21.0 → 0.23.1
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.
- package/README.md +45 -3
- package/dist/base.d.ts +23 -0
- package/dist/base.js +64 -4
- package/dist/commands/assistant/ask.d.ts +24 -0
- package/dist/commands/assistant/ask.js +112 -0
- package/dist/commands/assistant/conversations/create.d.ts +9 -0
- package/dist/commands/assistant/conversations/create.js +25 -0
- package/dist/commands/assistant/conversations/delete.d.ts +12 -0
- package/dist/commands/assistant/conversations/delete.js +25 -0
- package/dist/commands/assistant/conversations/list.d.ts +10 -0
- package/dist/commands/assistant/conversations/list.js +30 -0
- package/dist/commands/assistant/conversations/show.d.ts +9 -0
- package/dist/commands/assistant/conversations/show.js +25 -0
- package/dist/commands/errors/assign.d.ts +14 -0
- package/dist/commands/errors/assign.js +52 -0
- package/dist/commands/errors/bulk-triage.d.ts +11 -0
- package/dist/commands/errors/bulk-triage.js +41 -0
- package/dist/commands/errors/delete.d.ts +13 -0
- package/dist/commands/errors/delete.js +28 -0
- package/dist/commands/errors/grouping-rules/create.d.ts +15 -0
- package/dist/commands/errors/grouping-rules/create.js +44 -0
- package/dist/commands/errors/grouping-rules/delete.d.ts +13 -0
- package/dist/commands/errors/grouping-rules/delete.js +27 -0
- package/dist/commands/errors/grouping-rules/list.d.ts +10 -0
- package/dist/commands/errors/grouping-rules/list.js +28 -0
- package/dist/commands/errors/grouping-rules/update.d.ts +18 -0
- package/dist/commands/errors/grouping-rules/update.js +43 -0
- package/dist/commands/errors/merge.d.ts +14 -0
- package/dist/commands/errors/merge.js +39 -0
- package/dist/commands/errors/split.d.ts +13 -0
- package/dist/commands/errors/split.js +34 -0
- package/dist/commands/invitations/create.js +9 -2
- package/dist/commands/invitations/resend.js +8 -2
- package/dist/commands/kb/attach.d.ts +12 -0
- package/dist/commands/kb/attach.js +49 -0
- package/dist/commands/kb/attachment-download.d.ts +14 -0
- package/dist/commands/kb/attachment-download.js +38 -0
- package/dist/commands/kb/attachments.d.ts +9 -0
- package/dist/commands/kb/attachments.js +36 -0
- package/dist/commands/kb/create.d.ts +4 -1
- package/dist/commands/kb/create.js +41 -5
- package/dist/commands/kb/detach.d.ts +13 -0
- package/dist/commands/kb/detach.js +26 -0
- package/dist/commands/kb/show.js +3 -0
- package/dist/commands/kb/update.d.ts +4 -0
- package/dist/commands/kb/update.js +69 -21
- package/dist/commands/metrics/bulk-triage.d.ts +11 -0
- package/dist/commands/metrics/bulk-triage.js +44 -0
- package/dist/commands/seo-sites/show.d.ts +15 -0
- package/dist/commands/seo-sites/show.js +107 -0
- package/dist/commands/service-accounts/show.d.ts +9 -0
- package/dist/commands/service-accounts/show.js +26 -0
- package/dist/commands/service-accounts/tokens/list.d.ts +12 -0
- package/dist/commands/service-accounts/tokens/list.js +40 -0
- package/dist/commands/service-accounts/update.d.ts +31 -0
- package/dist/commands/service-accounts/update.js +105 -0
- package/dist/commands/shared/delete.d.ts +12 -0
- package/dist/commands/shared/delete.js +30 -0
- package/dist/commands/shared/list.d.ts +6 -0
- package/dist/commands/shared/list.js +45 -0
- package/dist/commands/shared/set.d.ts +14 -0
- package/dist/commands/shared/set.js +41 -0
- package/dist/commands/tickets/ask.d.ts +13 -0
- package/dist/commands/tickets/ask.js +81 -0
- package/dist/commands/tickets/dependencies/add.d.ts +15 -0
- package/dist/commands/tickets/dependencies/add.js +62 -0
- package/dist/commands/tickets/dependencies/list.d.ts +12 -0
- package/dist/commands/tickets/dependencies/list.js +37 -0
- package/dist/commands/tickets/dependencies/remove.d.ts +14 -0
- package/dist/commands/tickets/dependencies/remove.js +59 -0
- package/dist/commands/tickets/work-context.d.ts +15 -0
- package/dist/commands/tickets/work-context.js +130 -0
- package/dist/commands/vault/requests/approve.d.ts +9 -0
- package/dist/commands/vault/requests/approve.js +40 -0
- package/dist/commands/vault/requests/list.d.ts +6 -0
- package/dist/commands/vault/requests/list.js +29 -0
- package/dist/commands/vault/requests/reject.d.ts +12 -0
- package/dist/commands/vault/requests/reject.js +52 -0
- package/dist/commands/workload/create.d.ts +15 -0
- package/dist/commands/workload/create.js +45 -0
- package/dist/commands/workload/delete.d.ts +12 -0
- package/dist/commands/workload/delete.js +26 -0
- package/dist/commands/workload/list.d.ts +9 -0
- package/dist/commands/workload/list.js +29 -0
- package/dist/commands/workload/participant/add.d.ts +10 -0
- package/dist/commands/workload/participant/add.js +27 -0
- package/dist/commands/workload/participant/remove.d.ts +10 -0
- package/dist/commands/workload/participant/remove.js +23 -0
- package/dist/commands/workload/promote.d.ts +17 -0
- package/dist/commands/workload/promote.js +58 -0
- package/dist/commands/workload/show.d.ts +9 -0
- package/dist/commands/workload/show.js +24 -0
- package/dist/commands/workload/update.d.ts +17 -0
- package/dist/commands/workload/update.js +45 -0
- package/dist/errors/error-codes.d.ts +17 -0
- package/dist/errors/error-codes.js +36 -0
- package/dist/lib/api.d.ts +7 -1
- package/dist/lib/api.js +8 -0
- package/dist/lib/assistant.d.ts +29 -0
- package/dist/lib/assistant.js +76 -0
- package/dist/lib/bulk-triage.d.ts +35 -0
- package/dist/lib/bulk-triage.js +55 -0
- package/dist/lib/grouping-rules.d.ts +28 -0
- package/dist/lib/grouping-rules.js +39 -0
- package/dist/lib/knowledge.d.ts +15 -0
- package/dist/lib/knowledge.js +36 -0
- package/dist/lib/output.js +10 -0
- package/dist/lib/poll.d.ts +51 -0
- package/dist/lib/poll.js +59 -0
- package/dist/lib/service-accounts.d.ts +65 -0
- package/dist/lib/service-accounts.js +132 -0
- package/dist/lib/vault-requests.d.ts +38 -0
- package/dist/lib/vault-requests.js +125 -0
- package/dist/lib/workload.d.ts +37 -0
- package/dist/lib/workload.js +64 -0
- package/oclif.manifest.json +6830 -4502
- package/opencli.json +2177 -547
- package/package.json +27 -3
package/README.md
CHANGED
|
@@ -79,6 +79,15 @@ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
|
|
|
79
79
|
| `errors list --project <id\|key> [--status] [--page]` | List error groups. |
|
|
80
80
|
| `errors show <id> --project <id\|key>` | Show one error group. |
|
|
81
81
|
| `errors resolve\|reopen\|mute\|unmute <id> --project <id\|key>` | Triage an error group. |
|
|
82
|
+
| `errors bulk-triage --project <id\|key> --action resolve\|ignore\|reopen --group <id>…` | Triage several error groups in one call. Repeated ids are sent once. If the server does not return every group asked for — an id belonging to another project is dropped without a word — the command names the ones left out and exits non-zero: the rest were changed. |
|
|
83
|
+
| `errors assign <id> --project <id\|key> (--assignee <id\|email> \| --unassign)` | Put an error group in someone's hands, or take it out. An account outside the organization is refused by the server in silence: the command checks the answer and exits non-zero instead of reporting an error handed to nobody. |
|
|
84
|
+
| `errors merge <primary-id> --project <id\|key> --group <id>… --confirm` | Merge error groups into the primary: occurrences move, counters add up, the absorbed groups disappear. Irreversible. The ids travel raw, so one id the server cannot find in the project aborts the whole merge and nothing is half-done. |
|
|
85
|
+
| `errors split <id> --project <id\|key> --event <event-id>…` | Pull some occurrences out into a new group. All-or-nothing too: an occurrence that is not in this group stops the split. Splitting every occurrence is refused — that would be a deletion. |
|
|
86
|
+
| `errors delete <id> --project <id\|key> --confirm` | Delete an error group and every occurrence it holds (requires errors.destroy). Irreversible. |
|
|
87
|
+
| `errors grouping-rules list --project <id\|key> [--page]` | The project's custom grouping rules, in the order they are applied. |
|
|
88
|
+
| `errors grouping-rules create --project <id\|key> --field exception_type\|message\|culprit\|transaction --operator contains\|equals\|starts_with --value <text> --fingerprint-key <key> [--position] [--active\|--no-active]` | Add a rule: at ingest the first active rule that matches rewrites the fingerprint, and everything sharing a `--fingerprint-key` lands in one group. Matching is case-insensitive and never a regular expression. |
|
|
89
|
+
| `errors grouping-rules update <id> --project <id\|key> [--field] [--operator] [--value] [--fingerprint-key] [--position] [--active\|--no-active]` | Change a rule, or turn it off without deleting it. At least one field is required. |
|
|
90
|
+
| `errors grouping-rules delete <id> --project <id\|key> --confirm` | Delete a rule; the groups it already made stay where they are. |
|
|
82
91
|
| `vulnerabilities list [--project <id\|key>] [--severity] [--status] [--package] [--page]` | List known dependency vulnerabilities across every visible project, worst first. |
|
|
83
92
|
| `vulnerabilities show <id>` | Show one: advisory, package, manifest, fixing version. |
|
|
84
93
|
| `vulnerabilities ignore <id> [--note]` / `reopen <id>` | Accept living with the risk, or change your mind (requires vulnerabilities.triage). |
|
|
@@ -92,6 +101,7 @@ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
|
|
|
92
101
|
| `seo promote <id>` | Open a ticket from it, evidence included. |
|
|
93
102
|
| `seo rescan --site <id>` | Check a site now, without waiting for the scheduled run (requires seo.manage). |
|
|
94
103
|
| `seo-sites list [--project <id\|key>] [--page]` | The sites under SEO check, with cadence and open findings. |
|
|
104
|
+
| `seo-sites show <id>` | One site in full: setup, open findings, last run and vitals. |
|
|
95
105
|
| `seo-sites create --project <id\|key> --url <url> --environment <id> [--frequency] [--max-pages] [--no-sitemap]` | Declare a site to watch; the first check starts right away. |
|
|
96
106
|
| `seo-sites update <id> [--url] [--frequency] [--max-pages] [--sitemap\|--no-sitemap] [--enable\|--disable]` | Change how a site is checked. |
|
|
97
107
|
| `seo-sites delete <id>` | Stop watching a site and remove its pages and findings. |
|
|
@@ -107,11 +117,18 @@ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
|
|
|
107
117
|
| `secrets assets download <id> --project <id\|key> --output <path> [--version] [--force]` | Decrypt to an explicit `0600` file; refuses overwrite by default. |
|
|
108
118
|
| `secrets assets versions\|rollback\|archive\|purge …` | Manage immutable versions, restore, archive or owner-only permanent purge. |
|
|
109
119
|
| `secrets assets shared-list\|shared-upload\|delegate\|undelegate …` | Manage one organization-level ciphertext and delegate it to authorized projects. |
|
|
120
|
+
| `shared list` | List the organization shared secret variables (name, description, last update); automatically fetches all pages. Never prints values. |
|
|
121
|
+
| `shared set --environment <code\|id> NAME=VALUE [--description]` | Create or update a shared variable on one environment (`NAME --value <v>` also works). Projects delegated on that environment read the new value. Requires `shared_secrets.manage`. |
|
|
122
|
+
| `shared delete <name\|id> --confirm` | Delete a shared variable from **every** environment at once (there is no per-environment deletion). Irreversible. |
|
|
123
|
+
| `vault requests list` | List the secret changes waiting for a second approval, across every visible project (org-level, no `--project`). Shows the name and the intent, never the proposed value. |
|
|
124
|
+
| `vault requests approve <id>` | Apply a pending secret change. Four-eyes: whoever asked for it cannot approve it, and a service account never decides — only a person. |
|
|
125
|
+
| `vault requests reject <id> --reason <why>` | Freeze a pending secret change as rejected; nothing changes in the vault and the reason reaches whoever asked. `--reason` is required and cannot be blank. |
|
|
110
126
|
| `tickets list --project <id\|key> [--page]` | List tickets. |
|
|
111
127
|
| `tickets show <id> --project <id\|key>` | Show one ticket. |
|
|
112
128
|
| `tickets create --project <id\|key> --title <t> [--kind bug\|story\|task\|epic] [--parent-id] [--step-*] [--description] [--status <code\|label\|id>] [--priority <code\|label\|id>]` | Create a ticket. `--status` defaults to `open` and `--priority` to `medium`, and both take a code or a label (`in_progress`, `"In Progress"`), so no id lookup is needed. Length caps: title 255, description 4000, technical analysis 1500 characters — every field over the cap is listed at once, before the call. |
|
|
113
129
|
| `tickets statuses` | List the org ticket statuses (id, code, label) — any of the three works as `--status`. |
|
|
114
130
|
| `tickets priorities` | List the org ticket priorities (id, code, label) — any of the three works as `--priority`. |
|
|
131
|
+
| `tickets ask <question…> [--timeout <seconds>]` | Ask a natural-language question across every ticket you can see (no `--project`: it spans them all); the AI answers and cites the tickets it used. Waits for the answer, then gives up saying so. |
|
|
115
132
|
| `tickets report <id\|code> --project <id\|key> (--body <text> \| --body-file <path>)` | Write the work report — the long text a comment cannot hold (max 20000 characters). Each write adds a version, it never overwrites the previous one. |
|
|
116
133
|
| `tickets report-show <id\|code> --project <id\|key> [--version <n>]` | Show the current work report, or a past version. |
|
|
117
134
|
| `tickets report-versions <id\|code> --project <id\|key> [--page]` | List the versions of the work report (newest first). |
|
|
@@ -127,29 +144,40 @@ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
|
|
|
127
144
|
| `tickets lease claim <id\|code> --project <id\|key> [--ttl <seconds>] [--run-id <id>]` | Claim the working lease on a ticket (server default TTL: 8h). Exits non-zero on a 409, naming the current holder and its expiry. |
|
|
128
145
|
| `tickets lease renew <id\|code> --project <id\|key> [--ttl <seconds>] [--run-id <id>]` | Extend your own lease before it expires. |
|
|
129
146
|
| `tickets lease release <id\|code> --project <id\|key> [--run-id <id>]` | Release your own lease so someone else can claim the ticket. |
|
|
147
|
+
| `tickets work-context <id\|code> --project <id\|key> [--full]` | Show the work context frozen at claim time: the references and procedures actually delivered, never the project's current guidance. `--full` also prints their frozen text. The snapshot is taken only when an automation host claims the ticket from the queue, so a ticket claimed by hand has none: that case exits non-zero with `R404-TICKET-004`, spelling out why. Reading it needs `tickets.audit.view`. |
|
|
130
148
|
| `ideas delete <id> --project <id\|key> --confirm` | Delete an idea (author always allowed; others need ideas.delete). |
|
|
131
149
|
| `ideas archive\|unarchive <id> --project <id\|key>` | Archive an idea (open → archived) / reopen it. |
|
|
132
150
|
| `ideas case-update <idea-id> <case-id> --project <id\|key> [--title] [--description]` | Update a case (example) of an idea. |
|
|
133
151
|
| `ideas case-delete <idea-id> <case-id> --project <id\|key> --confirm` | Delete a case from an open idea. |
|
|
134
152
|
| `metrics list --project <id\|key> [--kind] [--page]` | List metric groups. |
|
|
135
153
|
| `metrics show <id> --project <id\|key>` | Show one metric group. |
|
|
154
|
+
| `metrics bulk-triage --project <id\|key> --action resolve\|ignore\|reopen --group <id>…` | Triage several metric groups in one call — same rules as `errors bulk-triage`, including the refusal to call a partial selection a success. |
|
|
136
155
|
| `logs list [--project <id\|key>] [--level] [--trace-id] [--environment] [--page]` | List structured log entries. Cross-app: omit `--project` for the full visible stream. |
|
|
137
156
|
| `logs show <id>` | Show a single log entry (attributes, trace id, correlation). |
|
|
138
157
|
| `logs link <id> --to <Errors::Group:uuid\|Ticketing::Ticket:uuid>` | Manually link a log entry to an error group or ticket. |
|
|
139
158
|
| `logs unlink <id> <link-id> --confirm` | Remove a manual log link. |
|
|
140
159
|
| `kb list [--project <id\|key>] [--kind] [--status] [--awaiting-consolidation] [--per] [--page]` | List knowledge pages. Cross-project: omit `--project` for every visible project. Published only unless `--status` says otherwise. |
|
|
141
160
|
| `kb search <query…> [--project <id\|key>] [--kind] [--per] [--page] [--with-related]` | Search knowledge pages (semantic when available, title ILIKE fallback). |
|
|
142
|
-
| `kb show <id> [--related] [--question <q>]` | Show one knowledge page: metadata header, raw markdown body, then the technical section. |
|
|
161
|
+
| `kb show <id> [--related] [--question <q>]` | Show one knowledge page: metadata header (every project it belongs to, its groups and tags), raw markdown body, then the technical section. |
|
|
143
162
|
| `kb related <id> [--question <q>] [--links-only]` | Pages to read next: linked with `[[wiki links]]` plus close matches by meaning. |
|
|
144
|
-
| `kb create --project <id\|key
|
|
163
|
+
| `kb create [--project <id\|key>…] [--group <id\|name>…] [--tag <tag>…] --title <t> [--kind note\|decision\|guide] (--body <md> \| --body-file <path>) [--tech-spec <md> \| --tech-spec-file <path>] [--in-review] [--review-note <line>] [--author-origin <name>]` | Create a knowledge page (optional technical section, kept separate from the body). `--project`, `--group` and `--tag` are repeatable — a page can belong to several projects and groups at once, and to groups alone; at least one project or group is required. Length caps: title 255, body 4000, technical section 1500, review note 240 characters — every field over the cap is listed at once, before the call. With `--in-review` the page waits for a human and stays out of search, answers and related panels. `--author-origin` declares the assistant or skill that wrote the text, which is not the owner of the token. |
|
|
145
164
|
| `kb publish --project <id\|key> --publication-key <key> --title <t> [--kind note\|decision\|guide] (--body <md> \| --body-file <path>)` | Create or update a knowledge page in one atomic call, keyed by a stable `--publication-key` (1-255 URL-safe characters). Safe to repeat: the same key always lands on the same page, and the output says whether it was `created` or `updated`. Exactly one body source is required. Omitting `--kind` keeps the kind the page already has (a new page is a `note`). Same title/body caps as `kb create`. |
|
|
146
165
|
| `kb consolidate <id> --path <doc-path>` | Mark an accepted page as written to the versioned docs, recording where the document lives. |
|
|
147
|
-
| `kb update <id> [--title] [--kind] [--body \| --body-file] [--tech-spec \| --tech-spec-file]` | Update a page (unpassed fields keep their current value). Same length caps as `kb create`; text already over the cap is refused only if it grows. |
|
|
166
|
+
| `kb update <id> [--title] [--kind] [--body \| --body-file] [--tech-spec \| --tech-spec-file] [--project <id\|key>…] [--group <id\|name>…] [--tag <tag>…] [--author-origin <name>]` | Update a page (unpassed fields keep their current value — including projects, groups, tags and attachments). Passing `--project`, `--group` or `--tag` **replaces** that list with what you name; `--tag ""` clears the tags. Changing only scope or tags never rewrites the text, so a concurrent edit is not overwritten. Same length caps as `kb create`; text already over the cap is refused only if it grows. |
|
|
148
167
|
| `kb delete <id> --confirm` | Delete a knowledge page (irreversible). |
|
|
168
|
+
| `kb attachments <id>` | List every file attached to a knowledge page — all pages, never truncated (`SCRIPT` says whether the server considers it executable). |
|
|
169
|
+
| `kb attach <id> --file <path>…` | Attach one or more local files to a page. All-or-nothing: an unreadable path or a file the server refuses leaves the page untouched. |
|
|
170
|
+
| `kb attachment-download <id> <attachment-id> [--out <dir>] [--filename <name>]` | Download an attachment to disk. The server always sends it as an inert file, never something a viewer would render. |
|
|
171
|
+
| `kb detach <id> --attachment <attachment-id> --confirm` | Remove an attachment from a page (irreversible). |
|
|
149
172
|
| `kb ask <question…>` | Ask a question; the AI answers from the knowledge base and cites the pages it used. |
|
|
150
173
|
| `kb book list [--project <id\|key>] [--q <text>] [--per] [--page]` | List knowledge books (ordered collections of pages). Cross-project: omit `--project` for every visible project. |
|
|
151
174
|
| `kb book show <id>` | Show a book: metadata, then the summary of the pages it collects (`#` is the 0-based position). |
|
|
152
175
|
| `kb book add-page <id> --page <page-id> [--position <n>]` | Add a page to a book's summary. `--page` takes a page **id** (alias: `--page-id`), not a page number; `--position` is 0-based (`0` = top, omitted = last), like the position the summary shows back. Idempotent: repeating it never lists the page twice. |
|
|
176
|
+
| `assistant ask <question…> [--conversation <id>] [--timeout <seconds>]` | Ask the assistant a question about your own data; it reads what you are allowed to see, answers, and lists the tools it used. Prints the conversation id so the next question can keep the context (`--conversation <id>`). |
|
|
177
|
+
| `assistant conversations list [--per] [--page]` | List your conversations with the assistant, most recently active first. |
|
|
178
|
+
| `assistant conversations create [--title]` | Open an empty conversation; without `--title` the server names it after its first question. |
|
|
179
|
+
| `assistant conversations show <id>` | Read one conversation: every question and answer, the tools each answer used, and why a reply failed. |
|
|
180
|
+
| `assistant conversations delete <id> --confirm` | Delete a conversation and all its messages (irreversible). |
|
|
153
181
|
| `servers list [--status] [--page]` | List the monitored servers (fleet snapshot: status, cpu/mem/disk, last seen). |
|
|
154
182
|
| `servers show <id>` | Show a monitored server (latest snapshot + machine details). |
|
|
155
183
|
| `servers rename <id> --name <name>` | Rename a server (display name only). |
|
|
@@ -164,8 +192,11 @@ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
|
|
|
164
192
|
| `agents tokens create <name>` | Create an org automator token (secret shown only once). |
|
|
165
193
|
| `agents tokens revoke <id> --confirm` | Revoke an org automator token. |
|
|
166
194
|
| `service-accounts list [--page]` | List the service accounts (AI members, CLI-only) in your org. |
|
|
195
|
+
| `service-accounts show <id>` | Show one service account: identity, active token count, and the environments it may read secrets in. |
|
|
167
196
|
| `service-accounts create --name [--handle] [--project <id\|key>…] [--group <id\|name>…] [--role <id\|name>…] [--grant-secrets] [--secret-environment <code>…]` | Create a service account (optionally granting read+write secrets, limited to environment codes). |
|
|
197
|
+
| `service-accounts update <id> --secret-environment <code>… \| --all-environments` | Replace the environments the account may read secrets in. An empty list means *every* environment, so it must be asked for with `--all-environments`; an unknown code is refused before the write, and the boundary actually applied is verified after it. |
|
|
168
198
|
| `service-accounts delete <id> --confirm` | Delete a service account (revokes tokens + removes access; secrets audit kept). |
|
|
199
|
+
| `service-accounts tokens list <account-id> [--page]` | List a service account's CLI tokens: prefix, active/revoked, last use. Never the secret. |
|
|
169
200
|
| `service-accounts tokens create <account-id> <name>` | Mint a CLI token (cyi_u_) for a service account (secret shown only once). |
|
|
170
201
|
| `service-accounts tokens revoke <account-id> <token-id> --confirm` | Revoke a service account token. |
|
|
171
202
|
| `monitors create --project <id\|key> --url <url> [--environment] [--http-method] [--interval-seconds] [--expected-status] [--timeout-seconds] [--expected-body-keyword] [--ssl-expiry-warn-days] [--group-id]` | Create an uptime monitor (one per environment). |
|
|
@@ -232,6 +263,13 @@ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
|
|
|
232
263
|
| `todos items add <list-id> --title <title> [--ticket] [--position]` | Add an item to a todo list. |
|
|
233
264
|
| `todos items update <list-id> <item-id> [--title] [--ticket] [--position]` | Update a todo item. |
|
|
234
265
|
| `todos items delete <list-id> <item-id> --confirm` | Delete a todo item. |
|
|
266
|
+
| `workload list [--page]` | List the workload actions (non-dev activities) of the teams you belong to. |
|
|
267
|
+
| `workload show <action-id>` | Show one workload action with its participants. |
|
|
268
|
+
| `workload create --team <id\|name> --title <title> [--description] [--status] [--scheduled-at] [--due-at] [--ticket <code\|id>]` | Create a workload action on one of your teams. |
|
|
269
|
+
| `workload update <action-id> [--title] [--description] [--status] [--scheduled-at] [--due-at] [--ticket]` | Update a workload action (`--ticket ""` unlinks the ticket; the team never changes). |
|
|
270
|
+
| `workload delete <action-id> --confirm` | Delete a workload action (a linked ticket survives, it only loses the link). |
|
|
271
|
+
| `workload participant add\|remove <action-id> <email\|id>` | Add/remove one participant (they must belong to the action team). |
|
|
272
|
+
| `workload promote <action-id> --project <id\|key> [--title] [--description] [--kind] [--status] [--priority]` | Generate a ticket from the action and link it back. |
|
|
235
273
|
|
|
236
274
|
Every command accepts `--json` for machine-readable output and `--help` for usage details.
|
|
237
275
|
`--project` accepts either a project UUID or its key (matched case-insensitively).
|
|
@@ -253,6 +291,10 @@ never a silent success:
|
|
|
253
291
|
missing `--confirm`) and `message` says what; `C500-SYS-001` is reserved for unexpected failures.
|
|
254
292
|
Codes starting with `R`/`G` come straight from the backend.
|
|
255
293
|
|
|
294
|
+
`C408-ASK-001` is not a failure: the AI answer did not arrive within `--timeout` and is still being
|
|
295
|
+
worked on — `assistant ask` says which conversation to read it from once it lands. `C502-ASK-002`
|
|
296
|
+
means the answer will not come, and the server gave no code of its own to explain why.
|
|
297
|
+
|
|
256
298
|
## Configuration
|
|
257
299
|
|
|
258
300
|
The CLI stores its state in:
|
package/dist/base.d.ts
CHANGED
|
@@ -45,6 +45,16 @@ export declare abstract class BaseCommand extends Command {
|
|
|
45
45
|
protected resolveTeamId(value: string): Promise<string>;
|
|
46
46
|
/** Resolve a member reference (UUID account id passes through; otherwise matched by email). */
|
|
47
47
|
protected resolveMemberId(value: string): Promise<string>;
|
|
48
|
+
/**
|
|
49
|
+
* Resolve a ticket reference: a UUID passes through, a human code ("DRFL-3", case-insensitive) is
|
|
50
|
+
* looked up inside its own project — the same identifier `tickets show` prints, so linking a
|
|
51
|
+
* ticket to a workload action never costs a UUID hunt first (CYCL-42).
|
|
52
|
+
*
|
|
53
|
+
* A reference that is neither is refused here instead of being sent: the workload endpoint drops
|
|
54
|
+
* a ticket id it cannot see (anti-BOLA) and stores "no ticket" without a word, so an unusable
|
|
55
|
+
* reference must fail loudly on this side.
|
|
56
|
+
*/
|
|
57
|
+
protected resolveTicketId(value: string): Promise<string>;
|
|
48
58
|
/**
|
|
49
59
|
* Resolve a ticket status/priority reference: a UUID passes through, anything else is matched
|
|
50
60
|
* against the organization lookup by code first, then by label (case-insensitive).
|
|
@@ -59,6 +69,19 @@ export declare abstract class BaseCommand extends Command {
|
|
|
59
69
|
protected resolveAll(values: string[], resolve: (value: string) => Promise<string>): Promise<string[]>;
|
|
60
70
|
/** Resolve an `{id, name}` reference by name (UUID passes through). */
|
|
61
71
|
private resolveByName;
|
|
72
|
+
/**
|
|
73
|
+
* Every row of an organization lookup (teams, roles, groups, members) — all its pages.
|
|
74
|
+
*
|
|
75
|
+
* The server serves ten per page: stopping at the first made the eleventh team or the eleventh
|
|
76
|
+
* person invisible, and a perfectly good name or email came back as "not found" (CYCL-42, the
|
|
77
|
+
* lesson `resolveProjectId` already learned on project keys in CYCL-1).
|
|
78
|
+
*
|
|
79
|
+
* A 403 here is not about the command being run: listing teams needs `permissions.manage` and
|
|
80
|
+
* listing members `members.view`, permissions that a team workload board never asks for. Left
|
|
81
|
+
* alone it would read as "Permesso negato" on an operation the caller is entitled to, so the
|
|
82
|
+
* refusal carries the way out instead — name the id, skip the lookup.
|
|
83
|
+
*/
|
|
84
|
+
private fetchLookupRows;
|
|
62
85
|
/**
|
|
63
86
|
* Surface API errors, then exit non-zero. In `--json` mode `logToStderr` is a no-op, so emit the
|
|
64
87
|
* structured `{ error: { code, message } }` envelope on stdout instead — otherwise the failure is
|
package/dist/base.js
CHANGED
|
@@ -82,13 +82,39 @@ class BaseCommand extends core_1.Command {
|
|
|
82
82
|
async resolveMemberId(value) {
|
|
83
83
|
if (exports.UUID_RE.test(value))
|
|
84
84
|
return value;
|
|
85
|
-
const
|
|
86
|
-
const match =
|
|
85
|
+
const rows = await this.fetchLookupRows('/cli/v1/members', 'Listing the organization members needs the members.view permission — pass the account id instead of the email.');
|
|
86
|
+
const match = rows.find((m) => (m.email ?? '').toLowerCase() === value.toLowerCase());
|
|
87
87
|
if (!match) {
|
|
88
88
|
throw new api_1.ApiRequestError(404, error_codes_1.ErrorCodes.Member.notFound, `Member not found: ${value}`);
|
|
89
89
|
}
|
|
90
90
|
return match.account_id;
|
|
91
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Resolve a ticket reference: a UUID passes through, a human code ("DRFL-3", case-insensitive) is
|
|
94
|
+
* looked up inside its own project — the same identifier `tickets show` prints, so linking a
|
|
95
|
+
* ticket to a workload action never costs a UUID hunt first (CYCL-42).
|
|
96
|
+
*
|
|
97
|
+
* A reference that is neither is refused here instead of being sent: the workload endpoint drops
|
|
98
|
+
* a ticket id it cannot see (anti-BOLA) and stores "no ticket" without a word, so an unusable
|
|
99
|
+
* reference must fail loudly on this side.
|
|
100
|
+
*/
|
|
101
|
+
async resolveTicketId(value) {
|
|
102
|
+
const ref = value.trim();
|
|
103
|
+
if (exports.UUID_RE.test(ref))
|
|
104
|
+
return ref;
|
|
105
|
+
// Stessa forma che il server accetta come code: chiave progetto (max 4) + numero.
|
|
106
|
+
const match = /^([a-z\d]{1,4})-\d+$/i.exec(ref);
|
|
107
|
+
if (!match) {
|
|
108
|
+
throw new api_1.ApiRequestError(404, error_codes_1.ErrorCodes.Ticket.notFound, `Ticket not found: ${value}. Pass a ticket id or its code (e.g. DRFL-3).`);
|
|
109
|
+
}
|
|
110
|
+
const projectId = await this.resolveProjectId(match[1]);
|
|
111
|
+
const res = await this.api.get(`/cli/v1/projects/${encodeURIComponent(projectId)}/tickets/${encodeURIComponent(ref)}`);
|
|
112
|
+
const id = res.data?.id;
|
|
113
|
+
if (typeof id !== 'string' || id === '') {
|
|
114
|
+
throw new api_1.ApiRequestError(404, error_codes_1.ErrorCodes.Ticket.notFound, `Ticket not found: ${value}`);
|
|
115
|
+
}
|
|
116
|
+
return id;
|
|
117
|
+
}
|
|
92
118
|
/**
|
|
93
119
|
* Resolve a ticket status/priority reference: a UUID passes through, anything else is matched
|
|
94
120
|
* against the organization lookup by code first, then by label (case-insensitive).
|
|
@@ -116,13 +142,47 @@ class BaseCommand extends core_1.Command {
|
|
|
116
142
|
async resolveByName(path, value, code, label) {
|
|
117
143
|
if (exports.UUID_RE.test(value))
|
|
118
144
|
return value;
|
|
119
|
-
const
|
|
120
|
-
const
|
|
145
|
+
const noun = label.toLowerCase();
|
|
146
|
+
const rows = await this.fetchLookupRows(path, `Listing the ${noun}s needs the permissions.manage permission — pass the ${noun} id instead of its name.`);
|
|
147
|
+
const match = rows.find((row) => (row.name ?? '').toLowerCase() === value.toLowerCase());
|
|
121
148
|
if (!match) {
|
|
122
149
|
throw new api_1.ApiRequestError(404, code, `${label} not found: ${value}`);
|
|
123
150
|
}
|
|
124
151
|
return match.id;
|
|
125
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Every row of an organization lookup (teams, roles, groups, members) — all its pages.
|
|
155
|
+
*
|
|
156
|
+
* The server serves ten per page: stopping at the first made the eleventh team or the eleventh
|
|
157
|
+
* person invisible, and a perfectly good name or email came back as "not found" (CYCL-42, the
|
|
158
|
+
* lesson `resolveProjectId` already learned on project keys in CYCL-1).
|
|
159
|
+
*
|
|
160
|
+
* A 403 here is not about the command being run: listing teams needs `permissions.manage` and
|
|
161
|
+
* listing members `members.view`, permissions that a team workload board never asks for. Left
|
|
162
|
+
* alone it would read as "Permesso negato" on an operation the caller is entitled to, so the
|
|
163
|
+
* refusal carries the way out instead — name the id, skip the lookup.
|
|
164
|
+
*/
|
|
165
|
+
async fetchLookupRows(path, hint) {
|
|
166
|
+
const rows = [];
|
|
167
|
+
let page = 1;
|
|
168
|
+
let totalPages = 1;
|
|
169
|
+
try {
|
|
170
|
+
do {
|
|
171
|
+
// eslint-disable-next-line no-await-in-loop
|
|
172
|
+
const res = await this.api.get(`${path}?page=${page}&per=100`);
|
|
173
|
+
rows.push(...(res.data ?? []));
|
|
174
|
+
totalPages = Number(res.meta?.total_pages ?? 1);
|
|
175
|
+
page += 1;
|
|
176
|
+
} while (page <= totalPages);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
if (error instanceof api_1.ApiRequestError && error.status === 403) {
|
|
180
|
+
throw new api_1.ApiRequestError(error.status, error.code, `${error.message}. ${hint}`);
|
|
181
|
+
}
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
return rows;
|
|
185
|
+
}
|
|
126
186
|
/**
|
|
127
187
|
* Surface API errors, then exit non-zero. In `--json` mode `logToStderr` is a no-op, so emit the
|
|
128
188
|
* structured `{ error: { code, message } }` envelope on stdout instead — otherwise the failure is
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base';
|
|
2
|
+
export default class AssistantAsk extends BaseCommand {
|
|
3
|
+
static strict: boolean;
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static args: {
|
|
7
|
+
question: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
8
|
+
};
|
|
9
|
+
static flags: {
|
|
10
|
+
conversation: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<unknown>;
|
|
14
|
+
/**
|
|
15
|
+
* Send the question, and if this very command opened the conversation for it, do not leave an
|
|
16
|
+
* empty one behind when the send is refused (AI switched off, question too long): the backend
|
|
17
|
+
* lists conversations without messages too, so the reader would find a shell with no questions
|
|
18
|
+
* in it until the retention job passes. Deleting it is best-effort — the refusal is the news,
|
|
19
|
+
* and a failed cleanup must never replace it.
|
|
20
|
+
*/
|
|
21
|
+
private sendQuestion;
|
|
22
|
+
/** Open the conversation this question will live in, and return its id. */
|
|
23
|
+
private openConversation;
|
|
24
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_1 = require("../../base");
|
|
5
|
+
const error_codes_1 = require("../../errors/error-codes");
|
|
6
|
+
const api_1 = require("../../lib/api");
|
|
7
|
+
const assistant_1 = require("../../lib/assistant");
|
|
8
|
+
const output_1 = require("../../lib/output");
|
|
9
|
+
const poll_1 = require("../../lib/poll");
|
|
10
|
+
class AssistantAsk extends base_1.BaseCommand {
|
|
11
|
+
// Variadic question: every positional word is joined into a single natural-language question.
|
|
12
|
+
static strict = false;
|
|
13
|
+
static description = 'Ask the assistant a question about your own data; it reads what you are allowed to see and answers (may take a while)';
|
|
14
|
+
static examples = [
|
|
15
|
+
'<%= config.bin %> assistant ask how many open tickets does acme-api have',
|
|
16
|
+
'<%= config.bin %> assistant ask "what changed in the last release?" --conversation <id>',
|
|
17
|
+
'<%= config.bin %> assistant ask "who is working on CYCL-43?" --timeout 60 --json',
|
|
18
|
+
];
|
|
19
|
+
// Non-required: with strict = false the arg validation is off, so we guard the empty case ourselves.
|
|
20
|
+
static args = {
|
|
21
|
+
question: core_1.Args.string({ description: 'The question (all positional words are joined)' }),
|
|
22
|
+
};
|
|
23
|
+
static flags = {
|
|
24
|
+
conversation: core_1.Flags.string({
|
|
25
|
+
char: 'c',
|
|
26
|
+
description: 'Ask inside an existing conversation (keeps the context of the previous questions)',
|
|
27
|
+
}),
|
|
28
|
+
timeout: core_1.Flags.integer({
|
|
29
|
+
description: 'Seconds to wait for the answer before giving up',
|
|
30
|
+
default: poll_1.DEFAULT_TIMEOUT_SECONDS,
|
|
31
|
+
}),
|
|
32
|
+
};
|
|
33
|
+
async run() {
|
|
34
|
+
const { argv, flags } = await this.parse(AssistantAsk);
|
|
35
|
+
const question = argv.join(' ').trim();
|
|
36
|
+
if (question === '') {
|
|
37
|
+
this.error('Provide a question (e.g. "assistant ask how many open tickets do I have").', { exit: 2 });
|
|
38
|
+
}
|
|
39
|
+
const invalidTimeout = (0, poll_1.timeoutError)(flags.timeout);
|
|
40
|
+
if (invalidTimeout)
|
|
41
|
+
this.error(invalidTimeout, { exit: 2 });
|
|
42
|
+
if (!this.jsonEnabled())
|
|
43
|
+
this.log('Asking the assistant, this may take a while…');
|
|
44
|
+
// A brand-new conversation is opened empty and titled by the server after this first question.
|
|
45
|
+
const opened = flags.conversation === undefined;
|
|
46
|
+
const conversationId = flags.conversation ?? (await this.openConversation());
|
|
47
|
+
const sent = await this.sendQuestion(conversationId, question, opened);
|
|
48
|
+
const reply = sent.data ?? {};
|
|
49
|
+
const messageId = reply.id;
|
|
50
|
+
if (typeof messageId !== 'string' || messageId === '') {
|
|
51
|
+
throw new api_1.ApiRequestError(502, error_codes_1.ErrorCodes.Ask.failed, 'The server accepted the question without an id for its answer: there is nothing to follow.');
|
|
52
|
+
}
|
|
53
|
+
const answered = await (0, poll_1.pollUntil)(async () => (await this.api.get(`/cli/v1/assistant/messages/${encodeURIComponent(messageId)}`)).data ?? {}, (message) => message.status !== 'streaming', {
|
|
54
|
+
initial: reply,
|
|
55
|
+
timeoutMs: flags.timeout * 1000,
|
|
56
|
+
timeoutMessage: `The assistant did not answer within ${flags.timeout}s and may still be working. ` +
|
|
57
|
+
`Read the answer later with "${this.config.bin} assistant conversations show ${conversationId}".`,
|
|
58
|
+
});
|
|
59
|
+
// A failed reply carries no text: exit non-zero saying which of the three failures it is, so a
|
|
60
|
+
// script never mistakes "no answer" for an empty answer.
|
|
61
|
+
if (answered.status === 'failed') {
|
|
62
|
+
const failure = (0, assistant_1.assistantFailure)(answered.error_code);
|
|
63
|
+
throw new api_1.ApiRequestError(502, failure.code, failure.message);
|
|
64
|
+
}
|
|
65
|
+
// Anything that is not `streaming` ended the wait, but only `complete` means there is an answer:
|
|
66
|
+
// a missing or unknown status would otherwise be printed as a successful empty reply, which is
|
|
67
|
+
// the one outcome a caller cannot tell apart from "the assistant had nothing to say".
|
|
68
|
+
if (answered.status !== 'complete') {
|
|
69
|
+
throw new api_1.ApiRequestError(502, error_codes_1.ErrorCodes.Ask.failed, `The assistant reported an answer state this CLI does not know ("${answered.status ?? 'none'}"): treat the reply as missing.`);
|
|
70
|
+
}
|
|
71
|
+
if (!this.jsonEnabled()) {
|
|
72
|
+
const content = String(answered.content ?? '').trim();
|
|
73
|
+
if (content !== '')
|
|
74
|
+
this.log((0, output_1.sanitizeMultiline)(answered.content));
|
|
75
|
+
const tools = (0, assistant_1.renderToolsUsed)(answered.tools_used, '\n');
|
|
76
|
+
if (tools !== '')
|
|
77
|
+
this.log(tools);
|
|
78
|
+
this.log(`\nConversation: ${conversationId} — keep asking with --conversation ${conversationId}`);
|
|
79
|
+
}
|
|
80
|
+
return { data: { ...answered, conversation_id: conversationId } };
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Send the question, and if this very command opened the conversation for it, do not leave an
|
|
84
|
+
* empty one behind when the send is refused (AI switched off, question too long): the backend
|
|
85
|
+
* lists conversations without messages too, so the reader would find a shell with no questions
|
|
86
|
+
* in it until the retention job passes. Deleting it is best-effort — the refusal is the news,
|
|
87
|
+
* and a failed cleanup must never replace it.
|
|
88
|
+
*/
|
|
89
|
+
async sendQuestion(conversationId, text, opened) {
|
|
90
|
+
try {
|
|
91
|
+
return await this.api.post(`/cli/v1/assistant/conversations/${encodeURIComponent(conversationId)}/messages`, { text });
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
if (opened) {
|
|
95
|
+
await this.api
|
|
96
|
+
.delete(`/cli/v1/assistant/conversations/${encodeURIComponent(conversationId)}`)
|
|
97
|
+
.catch(() => undefined);
|
|
98
|
+
}
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Open the conversation this question will live in, and return its id. */
|
|
103
|
+
async openConversation() {
|
|
104
|
+
const res = await this.api.post('/cli/v1/assistant/conversations', { title: undefined });
|
|
105
|
+
const id = res.data?.id;
|
|
106
|
+
if (typeof id !== 'string' || id === '') {
|
|
107
|
+
throw new api_1.ApiRequestError(502, error_codes_1.ErrorCodes.Ask.failed, 'The server opened a conversation without an id: there is nowhere to ask.');
|
|
108
|
+
}
|
|
109
|
+
return id;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.default = AssistantAsk;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base';
|
|
2
|
+
export default class AssistantConversationsCreate extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
title: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<unknown>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_1 = require("../../../base");
|
|
5
|
+
const output_1 = require("../../../lib/output");
|
|
6
|
+
class AssistantConversationsCreate extends base_1.BaseCommand {
|
|
7
|
+
static description = 'Open an empty conversation with the assistant (ask questions into it with `assistant ask --conversation`)';
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> assistant conversations create',
|
|
10
|
+
'<%= config.bin %> assistant conversations create --title "Stato dei rilasci"',
|
|
11
|
+
];
|
|
12
|
+
static flags = {
|
|
13
|
+
// Optional: without it the server titles the conversation after its first question, which is
|
|
14
|
+
// what makes a list of past conversations searchable at all.
|
|
15
|
+
title: core_1.Flags.string({ description: 'Conversation title (defaults to the first question asked)' }),
|
|
16
|
+
};
|
|
17
|
+
async run() {
|
|
18
|
+
const { flags } = await this.parse(AssistantConversationsCreate);
|
|
19
|
+
const res = await this.api.post('/cli/v1/assistant/conversations', { title: flags.title });
|
|
20
|
+
if (!this.jsonEnabled())
|
|
21
|
+
this.log((0, output_1.renderRecord)(res.data ?? {}));
|
|
22
|
+
return res;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.default = AssistantConversationsCreate;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base';
|
|
2
|
+
export default class AssistantConversationsDelete extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
confirm: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<unknown>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_1 = require("../../../base");
|
|
5
|
+
class AssistantConversationsDelete extends base_1.BaseCommand {
|
|
6
|
+
static description = 'Delete a conversation with the assistant, questions and answers included (irreversible)';
|
|
7
|
+
static examples = ['<%= config.bin %> assistant conversations delete <conversation-id> --confirm'];
|
|
8
|
+
static args = {
|
|
9
|
+
id: core_1.Args.string({ description: 'Conversation id', required: true }),
|
|
10
|
+
};
|
|
11
|
+
static flags = {
|
|
12
|
+
confirm: core_1.Flags.boolean({ description: 'Required: confirm the irreversible deletion' }),
|
|
13
|
+
};
|
|
14
|
+
async run() {
|
|
15
|
+
const { args, flags } = await this.parse(AssistantConversationsDelete);
|
|
16
|
+
if (!flags.confirm) {
|
|
17
|
+
this.error('Refusing to delete without --confirm (the action is irreversible).', { exit: 2 });
|
|
18
|
+
}
|
|
19
|
+
await this.api.delete(`/cli/v1/assistant/conversations/${encodeURIComponent(args.id)}`);
|
|
20
|
+
if (!this.jsonEnabled())
|
|
21
|
+
this.log(`Deleted conversation ${args.id}`);
|
|
22
|
+
return { deleted: args.id };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.default = AssistantConversationsDelete;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base';
|
|
2
|
+
export default class AssistantConversationsList extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
page: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
|
+
per: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<unknown>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_1 = require("../../../base");
|
|
5
|
+
const assistant_1 = require("../../../lib/assistant");
|
|
6
|
+
class AssistantConversationsList extends base_1.BaseCommand {
|
|
7
|
+
static description = 'List your conversations with the assistant (most recently active first)';
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> assistant conversations list',
|
|
10
|
+
'<%= config.bin %> assistant conversations list --per 50 --json',
|
|
11
|
+
];
|
|
12
|
+
static flags = {
|
|
13
|
+
per: core_1.Flags.integer({ description: 'Page size' }),
|
|
14
|
+
...base_1.pageFlag,
|
|
15
|
+
};
|
|
16
|
+
async run() {
|
|
17
|
+
const { flags } = await this.parse(AssistantConversationsList);
|
|
18
|
+
const invalid = (0, base_1.paginationError)(flags);
|
|
19
|
+
if (invalid)
|
|
20
|
+
this.error(invalid, { exit: 2 });
|
|
21
|
+
const query = new URLSearchParams({ page: String(flags.page) });
|
|
22
|
+
if (flags.per !== undefined)
|
|
23
|
+
query.set('per', String(flags.per));
|
|
24
|
+
const res = await this.api.get(`/cli/v1/assistant/conversations?${query.toString()}`);
|
|
25
|
+
if (!this.jsonEnabled())
|
|
26
|
+
this.log((0, assistant_1.renderConversationsTable)(res.data ?? []));
|
|
27
|
+
return res;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.default = AssistantConversationsList;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base';
|
|
2
|
+
export default class AssistantConversationsShow extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<unknown>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_1 = require("../../../base");
|
|
5
|
+
const assistant_1 = require("../../../lib/assistant");
|
|
6
|
+
const output_1 = require("../../../lib/output");
|
|
7
|
+
class AssistantConversationsShow extends base_1.BaseCommand {
|
|
8
|
+
static description = 'Read one conversation with the assistant: its questions, its answers and what they were based on';
|
|
9
|
+
static examples = ['<%= config.bin %> assistant conversations show <conversation-id>'];
|
|
10
|
+
static args = {
|
|
11
|
+
id: core_1.Args.string({ description: 'Conversation id', required: true }),
|
|
12
|
+
};
|
|
13
|
+
async run() {
|
|
14
|
+
const { args } = await this.parse(AssistantConversationsShow);
|
|
15
|
+
const res = await this.api.get(`/cli/v1/assistant/conversations/${encodeURIComponent(args.id)}`);
|
|
16
|
+
const data = res.data ?? {};
|
|
17
|
+
if (!this.jsonEnabled()) {
|
|
18
|
+
this.log((0, output_1.renderRecord)(data));
|
|
19
|
+
this.log((0, output_1.section)('Messages', '💬'));
|
|
20
|
+
this.log((0, assistant_1.renderMessages)(data.messages));
|
|
21
|
+
}
|
|
22
|
+
return res;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.default = AssistantConversationsShow;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base';
|
|
2
|
+
export default class ErrorsAssign extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
assignee: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
|
+
unassign: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<unknown>;
|
|
14
|
+
}
|