From 8303cbce4e18f376623564df32051525c4c1a7eb Mon Sep 17 00:00:00 2001 From: Valera Date: Wed, 15 Apr 2026 15:01:04 +0300 Subject: [PATCH] feat: add Eppie Email CLI skill --- skills/.curated/eppie-email-cli/LICENSE.txt | 176 +++++ skills/.curated/eppie-email-cli/SKILL.md | 634 ++++++++++++++++++ .../eppie-email-cli/agents/openai.yaml | 6 + .../assets/eppie-email-cli-small.svg | 11 + .../assets/eppie-email-cli.png | Bin 0 -> 2275 bytes 5 files changed, 827 insertions(+) create mode 100644 skills/.curated/eppie-email-cli/LICENSE.txt create mode 100644 skills/.curated/eppie-email-cli/SKILL.md create mode 100644 skills/.curated/eppie-email-cli/agents/openai.yaml create mode 100644 skills/.curated/eppie-email-cli/assets/eppie-email-cli-small.svg create mode 100644 skills/.curated/eppie-email-cli/assets/eppie-email-cli.png diff --git a/skills/.curated/eppie-email-cli/LICENSE.txt b/skills/.curated/eppie-email-cli/LICENSE.txt new file mode 100644 index 00000000..d9a10c0d --- /dev/null +++ b/skills/.curated/eppie-email-cli/LICENSE.txt @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/skills/.curated/eppie-email-cli/SKILL.md b/skills/.curated/eppie-email-cli/SKILL.md new file mode 100644 index 00000000..b66167be --- /dev/null +++ b/skills/.curated/eppie-email-cli/SKILL.md @@ -0,0 +1,634 @@ +--- +name: eppie-email-cli +description: Use this skill when the task requires running eppie-console to work with email. Covers Gmail, Outlook, Proton Mail, IMAP/SMTP, and decentralized Eppie mail. Trigger when the user asks to read, send, or delete email messages; check an inbox or mail folder; sync a mailbox; add or list email accounts; initialize or reset the local vault; or automate any email workflow through the eppie-console CLI. Do not use for conceptual explanations without running commands. +--- + +# Eppie CLI agent skill + +Use this skill when an autonomous or semi-autonomous agent must operate `eppie-console` directly. + +`eppie-console` is a console mail client that can work with: +- Gmail, +- Outlook, +- Proton Mail, +- regular IMAP/SMTP email services, +- decentralized peer-to-peer Eppie mail. + +## Purpose + +Use `eppie-console` in a predictable, automation-friendly way to: +- inspect accounts, +- inspect folders, +- read messages, +- send messages, +- sync folders, +- initialize, unlock, and reset the local vault when needed by the task. + +This skill focuses on deterministic command execution, structured output handling, and explicit standard-input contracts. + +## How to use this file + +Treat sections marked `Normative` as the required contract for agent execution. +Treat sections marked `Reference` as supporting material, examples, or quick navigation aids. + +Normative sections in this file: +- `Normative defaults for agents` +- `Normative rules` +- `Normative command patterns for agents` +- `Normative stdin contracts` +- `Normative execution policy for autonomous agents` +- `Normative error handling` + +Reference sections in this file: +- `Reference: preferred installation` +- `Reference: required inputs` +- `Reference: launch modes` +- `Reference: decision guide` +- `Reference: end-to-end agent scenarios` +- `Reference: command-specific notes and examples` +- `Reference: recommended agent workflow` +- `Reference: known limitations` +- `Reference: contributing` + +## Normative defaults for agents + +When the task requires executing `eppie-console`, use these defaults unless the task explicitly requires otherwise: + +1. use `--non-interactive=true` +2. use `--output=json` for agent automation unless text output is explicitly required +3. use `--unlock-password-stdin=true` for stateful commands that need an existing vault +4. use `--assume-yes=true` for destructive automation +5. provide `stdin` exactly in the required order +6. use one consistent working directory per vault + +Canonical command patterns and exact `stdin` contracts are defined later in this file. Use those sections as the single source of truth for agent execution. + +## Use this skill when + +- the task requires executing `eppie-console` +- the agent must inspect accounts, folders, messages, or contacts +- the agent must send a message +- the agent must synchronize a folder +- the agent must initialize or reset the local vault +- the agent must work with machine-readable CLI output + +## Do not use this skill when + +- the task does not require calling `eppie-console` +- the task is only to explain behavior conceptually without running commands +- the task is primarily about test coverage or validation workflows +- an interactive REPL session is not explicitly required but would be the only execution path +- the required executable or working directory is unavailable + +## Reference: preferred installation + +Prefer the executable published in GitHub Releases. +You can also build from source. + +Latest release page: +- https://github.com/Eppie-io/Eppie-CLI/releases/latest + +Direct download links: + +### Linux +- https://github.com/Eppie-io/Eppie-CLI/releases/latest/download/Eppie.CLI-linux-x64.tar.gz +- https://github.com/Eppie-io/Eppie-CLI/releases/latest/download/Eppie.CLI-linux-arm64.tar.gz + +### macOS +- https://github.com/Eppie-io/Eppie-CLI/releases/latest/download/Eppie.CLI-osx-x64.tar.gz +- https://github.com/Eppie-io/Eppie-CLI/releases/latest/download/Eppie.CLI-osx-arm64.tar.gz + +### Windows +- https://github.com/Eppie-io/Eppie-CLI/releases/latest/download/Eppie.CLI-win-x64.zip +- https://github.com/Eppie-io/Eppie-CLI/releases/latest/download/Eppie.CLI-win-arm64.zip + +After extracting the archive, use the `eppie-console` executable directly. + +## Reference: required inputs + +### Common inputs +- path to `eppie-console` +- working directory +- whether the task requires stateful access to an existing vault +- whether structured JSON output is required + +### Vault access inputs +- vault password +- whether the vault must be initialized first + +### Reading inputs +- account identifier for `-a`; for agent workflows, use the account address string returned by `list-accounts` in `data[].address` +- folder name when folder-specific access is needed +- message `id` +- message `pk` +- page size and total limit for paged commands + +### Sending inputs +- sender address +- receiver address +- subject +- message body + +### Account creation inputs +- account type +- vault password +- structured JSON payload when required +- provider-specific secrets only through standard input when supported + +## Reference: launch modes + +### Interactive mode +Use only when a REPL session is explicitly needed. + +Example: +- `eppie-console` + +Typical sequence: +- `open` +- vault password +- `list-accounts` +- `exit` + +`open` is useful in interactive mode to open the local vault inside the current process. + +### Non-interactive mode +Prefer this mode for agents. + +Use: +- `eppie-console --non-interactive=true [command options]` + +To avoid passing the same startup flags on every call, you can put them in `appsettings.json` next to `eppie-console`, for example: +- `{ "non-interactive": true, "output": "json", "unlock-password-stdin": true }` + +`eppie-console` also reads configuration from environment variables. + +When the default .NET host configuration pipeline is used, environment variables override `appsettings.json`. Command-line arguments override both. + +For structured machine-readable output, also use: +- `--output=json` + +JSON responses use a normalized envelope: +- `type`: `result`, `status`, `warning`, or `error` +- `code`: stable machine-readable outcome code +- `data`: payload for `result` and `status` responses +- `meta`: optional metadata for `result` responses; usually `null`, but paged read commands can return objects such as `{"header":"All messages:","returned":5,"hasMore":true}` +- `message`: human-readable warning/error text + +In `--non-interactive=true --output=json` mode, structured responses are emitted on `stdout` without a preceding stack trace on `stderr` for handled command failures such as `unhandledException`. + +In non-interactive mode, do not use `open` as part of the agent workflow. It does not establish reusable state for later process launches. For stateful non-interactive commands, use `--unlock-password-stdin=true` instead. + +For all agent examples in this file, `` means the account address returned by `list-accounts` in `data[].address`. Prefer that address string for `-a` instead of the numeric `id`, unless a command explicitly documents another identifier format. + +Common success-output examples: +- `--non-interactive=true --output=json list-accounts` (with accounts): + - `{"type":"result","code":"accounts","data":[{"id":1,"address":"
","accountType":"Dec"}],"meta":null}` +- `--non-interactive=true --assume-yes=true --output=json reset`: + - `{"type":"status","code":"reset","data":null}` +- `--non-interactive=true --unlock-password-stdin=true --output=json send ...`: + - `{"type":"status","code":"messageSent","data":{"subject":"","to":"","from":""}}` +- `--non-interactive=true --unlock-password-stdin=true --output=json sync-folder ...`: + - `{"type":"status","code":"folderSynced","data":{"account":"","folder":"Inbox"}}` +- `--non-interactive=true --unlock-password-stdin=true --output=json show-all-messages ...`: + - `{"type":"result","code":"messages","data":[{"id":1,"pk":1,"to":[""],"from":[""],"folder":"Inbox","subject":""}],"meta":{"header":"All messages:","returned":1,"hasMore":false}}` + +Additional command-specific JSON result shapes are documented later in `Reference: command-specific notes and examples`. + +Common text success-output examples: +- `open`: + - `The application was opened successfully.` +- `reset`: + - `The application has just been reset.` +- `add-account -t dec`: + - `Account added (Dec).` +- `send`: + - `Message sent from to . Subject: ` +- `sync-folder -f Inbox`: + - `Folder 'Inbox' for account synchronized.` + +## Normative rules + +- Treat `Normative command patterns for agents` and `Normative stdin contracts` as normative for agent workflows. +- Put global launch options before `--` and put the startup command after `--`. +- Do not assume `open` creates a reusable session for future process launches. +- Synchronize the relevant folder before reading when the task requires newly arrived messages. +- Do not guess provider-specific folder names; call `list-folders` first. +- Use `-l` / `--limit` when predictable payload size matters. +- Do not pass account secrets in command-line arguments when structured standard input is supported. + +`eppie-console open` only opens the vault inside the current process. +It does **not** create a reusable session for future process launches. + +## Normative command patterns for agents + +Use this section as the single source of truth for agent command lines. Unless text output is explicitly required, all agent examples below use `--output=json`. + +| Task | Canonical command | +| --- | --- | +| Initialize a vault | `--non-interactive=true --output=json -- init` | +| List accounts | `--non-interactive=true --unlock-password-stdin=true --output=json -- list-accounts` | +| List folders | `--non-interactive=true --unlock-password-stdin=true --output=json -- list-folders -a ` | +| Show all messages | `--non-interactive=true --unlock-password-stdin=true --output=json -- show-all-messages -s 10 -l 10` | +| Show one message | `--non-interactive=true --unlock-password-stdin=true --output=json -- show-message -a -f -i -k ` | +| Delete one message | `--non-interactive=true --unlock-password-stdin=true --output=json -- delete-message -a -f -i -k ` | +| List contacts | `--non-interactive=true --unlock-password-stdin=true --output=json -- list-contacts -s 10 -l 10` | +| Show contact messages | `--non-interactive=true --unlock-password-stdin=true --output=json -- show-contact-messages -c -s 10 -l 10` | +| Show folder messages | `--non-interactive=true --unlock-password-stdin=true --output=json -- show-folder-messages -a -f -s 10 -l 10` | +| Sync a folder | `--non-interactive=true --unlock-password-stdin=true --output=json -- sync-folder -a -f ` | +| Send a message | `--non-interactive=true --unlock-password-stdin=true --output=json -- send -s -r -t ""` | +| Reset local data | `--non-interactive=true --assume-yes=true --output=json -- reset` | +| Add a DEC account | `--non-interactive=true --unlock-password-stdin=true --output=json -- add-account -t dec` | +| Add a regular IMAP/SMTP account | `--non-interactive=true --unlock-password-stdin=true --output=json -- add-account -t email --input-json-stdin` | +| Add a Proton Mail account | `--non-interactive=true --unlock-password-stdin=true --output=json -- add-account -t proton --input-json-stdin` | + +## Normative stdin contracts + +Provide `stdin` exactly in the documented order. Unless a command explicitly reads until end-of-stream, stop after the documented input has been written. + +| Command | Exact `stdin` contract | EOF required | +| --- | --- | --- | +| `--non-interactive=true --output=json -- init` | line 1: new vault password | no | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- list-accounts` | line 1: vault password | no | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- list-folders -a ` | line 1: vault password | no | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- show-all-messages -s -l ` | line 1: vault password | no | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- show-message -a -f -i -k ` | line 1: vault password | no | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- delete-message -a -f -i -k ` | line 1: vault password | no | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- list-contacts -s -l ` | line 1: vault password | no | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- show-contact-messages -c -s -l ` | line 1: vault password | no | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- show-folder-messages -a -f -s -l ` | line 1: vault password | no | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- sync-folder -a -f ` | line 1: vault password | no | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- send -s -r -t ""` | line 1: vault password; line 2 and later: message body; then close `stdin` | yes | +| `--non-interactive=true --assume-yes=true --output=json -- reset` | no `stdin` | no | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- add-account -t dec` | line 1: vault password | no | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- add-account -t email --input-json-stdin` | line 1: vault password; remaining bytes: one JSON object | yes | +| `--non-interactive=true --unlock-password-stdin=true --output=json -- add-account -t proton --input-json-stdin` | line 1: vault password; remaining bytes: one JSON object | yes | + +### Command summary + +| Command group | Needs existing vault | Use `--unlock-password-stdin=true` | Prefer `--output=json` | Notes | +| --- | --- | --- | --- | --- | +| `init` | no | no | yes for agent workflows | writes a new local vault password from `stdin` | +| `reset` | no | no | yes | destructive; also use `--assume-yes=true` | +| `list-accounts`, `list-folders` | yes | yes | yes | inspect vault content | +| `show-all-messages`, `show-message`, `show-folder-messages`, `show-contact-messages` | yes | yes | yes | use `-l` when payload size matters | +| `sync-folder` | yes | yes | yes | call before reading when fresh messages are required | +| `send` | yes | yes | yes | password first in `stdin`, then body until EOF | +| `add-account -t dec` | yes | yes | yes | simple vault-backed account creation | +| `add-account -t email`, `add-account -t proton` | yes | yes | yes | use `--input-json-stdin`; do not pass secrets in arguments | + +### Avoid these mistakes + +- Do not use `open` in a non-interactive workflow. +- Do not guess provider-specific folder names; call `list-folders` first. +- Do not rely only on process exit code when JSON output is available. +- Do not omit `-l` when an agent needs a predictable maximum payload size. +- Do not pass secrets in command-line arguments when structured standard input is supported. + +## Normative execution policy for autonomous agents + +### Output handling +- Follow the `Normative defaults for agents` defaults unless the task explicitly requires otherwise. +- Parse `type`, `code`, `data`, `meta`, and `message` from the normalized envelope. +- Do not rely only on process exit code when structured output is available. +- Treat `warning` and `error` responses as non-success outcomes even when the process exits cleanly. + +### Standard input handling +- Follow `Normative stdin contracts` exactly. +- For `send`, close `stdin` after the last body line. +- For commands using `--input-json-stdin`, pass the password first when required, then the JSON payload. +- Do not prepend labels, prompts, or extra blank lines to the documented `stdin` contract. + +### Working directory handling +- Use one consistent working directory for related commands that operate on the same local vault. +- Use an isolated working directory when the run is disposable or destructive. + +### Account identifier handling +- For agent workflows, pass the account address from `list-accounts` `data[].address` to `-a`. +- Do not assume the numeric `id` is accepted interchangeably by all commands. +- Re-read the current address from `list-accounts` when a workflow depends on a newly created account. + +### Pagination handling +- Use both `-s` / `--page-size` and `-l` / `--limit` in agent workflows when payload size must be predictable. +- Treat `-s` as page size only. Treat `-l` as the total maximum number of records returned by the command. +- If `-l` is omitted, paged read commands return up to 20 records by default. +- Use `meta.returned` to confirm how many records were actually returned. +- Use `meta.hasMore` to decide whether another read with a higher `-l` or a narrower filter is needed. +- Do not assume provider folders or message volume are small enough to omit `-l`. + +## Reference: decision guide + +Use `Normative command patterns for agents` for the exact command line. This guide is only for choosing the next command. + +- inspect available accounts → `list-accounts` +- inspect available folders for an account → `list-folders` +- inspect recent messages across folders → sync the relevant folders when new messages are required, then use `show-all-messages` +- inspect messages in a specific folder → `list-folders`, then `sync-folder`, then `show-folder-messages` when new messages are required +- inspect one message → `show-message` +- delete one message → `delete-message` +- inspect contacts → `list-contacts` +- inspect messages for one contact → `show-contact-messages` +- send a message → `send` +- sync one folder → `list-folders`, then `sync-folder` +- initialize a vault → `init` +- reset local data → `reset` + +## Reference: end-to-end agent scenarios + +This section is informative. Use `Normative command patterns for agents` for the exact command line and `Normative stdin contracts` for the exact `stdin` shape. + +### Initialize a new vault, add an account, then verify it + +Use this flow when the working directory does not yet contain the required local vault. + +1. initialize the vault with `init` +2. add the required account with `add-account` +3. verify the created account with `list-accounts` +4. use the returned `data[].address` as `` in later commands + +Typical sequences: +- DEC account: `init` → `add-account -t dec` → `list-accounts` +- regular IMAP/SMTP account: `init` → `add-account -t email` → `list-accounts` +- Proton Mail account: `init` → `add-account -t proton` → `list-accounts` + +Agent notes: +- keep one consistent working directory across the whole sequence so all commands operate on the same local vault +- for `add-account -t email` and `add-account -t proton`, provide the structured payload through standard input after the vault password as documented in `Normative stdin contracts` +- after account creation, re-read the current address from `list-accounts` instead of assuming another identifier format + +### Read the latest message from a specific folder + +Use this flow when the task requires a concrete folder such as inbox or sent mail and the messages may have changed since the last sync. + +1. inspect accounts with `list-accounts` +2. inspect folders for the chosen account with `list-folders` +3. choose the correct folder name from `data[].fullName` or `data[].roles` +4. synchronize that folder with `sync-folder` +5. read a bounded message list with `show-folder-messages` +6. open one returned message with `show-message` using its `id` and `pk` + +Typical sequence: +- `list-accounts` → `list-folders` → `sync-folder` → `show-folder-messages` → `show-message` + +Agent notes: +- do not guess the folder name; use the `fullName` returned by `list-folders` +- use `-s` and `-l` on `show-folder-messages` when predictable payload size matters +- when `meta.hasMore` is `true`, treat the result as partial and increase `-l` only if the task requires a larger set + +### Send a message from an existing account + +Use this flow when the local vault already contains the sender account and the task is to deliver one message deterministically. + +1. inspect accounts with `list-accounts` +2. choose the sender address from `data[].address` +3. call `send` with the sender, receiver, and subject +4. pass the vault password on the first `stdin` line +5. pass the message body starting from line 2, then close `stdin` + +Typical sequence: +- `list-accounts` → `send` + +Agent notes: +- if the sender is unknown or the workflow depends on a newly created account, refresh the account list before sending +- in `--non-interactive=true` mode, `send` reads the body until end-of-stream, so the agent should close `stdin` after the last body line +- prefer `--output=json` and verify the `messageSent` status response instead of relying only on the process exit code + +## Reference: command-specific notes and examples + +The canonical command lines are defined in `Normative command patterns for agents`, and the exact inputs are defined in `Normative stdin contracts`. This section keeps only command-specific notes, result shapes, and examples that are easy to reference during agent execution. + +### Init local vault +Notes: +- writes a new local vault password from `stdin` + +### Show all messages +Notes: +- `-s` / `--page-size` controls only the page size +- `-l` / `--limit` caps the total number of returned records and should be used by agents to keep payload size predictable +- if `-l` is omitted, paged read commands return up to 20 records by default +- message items use the same address shape as `show-message`: `to` and `from` are arrays +- paged result metadata can include `returned` and `hasMore` +- agents should check `meta.hasMore` before assuming the returned list is complete + +### List folders +Expected result shape: +- `{"type":"result","code":"folders","data":[{"fullName":"Inbox","unreadCount":0,"totalCount":0,"roles":["inbox"]}],"meta":{"account":""}}` + +Notes: +- `` should be the account address from `list-accounts` `data[].address` +- use this command before `show-folder-messages` or `sync-folder` instead of guessing provider-specific folder names +- Proton may expose names such as `All Sent`; rely on the returned `fullName` +- use `roles` when you need a machine-readable way to find folders such as inbox or sent mail + +### Delete one message +Notes: +- when called for a message outside `Trash`, the command moves the message to `Trash` +- when called for a message already in `Trash`, the command deletes it permanently + +### Show contact messages +Notes: +- paged result metadata can include `returned` and `hasMore` + +### Show folder messages +Notes: +- paged result metadata can include `returned` and `hasMore` + +### Sync folder +Expected result shape: +- `{"type":"status","code":"folderSynced","data":{"account":"","folder":"Inbox"}}` + +### Send message +Examples: +- `vault password` +- `Hello from automation` +- `Second body line` +- close `stdin` + +Notes: +- in `--non-interactive=true` mode, `send` reads the message body until end-of-stream +- JSON success shape: `{"type":"status","code":"messageSent","data":{"subject":"","to":"","from":""}}` + +PowerShell example with the command line and exact `stdin` in one block: + +```powershell +@" +vault password +Hello from automation +Second body line +"@ | .\eppie-console --non-interactive=true --unlock-password-stdin=true --output=json -- send -s sender@example.com -r receiver@example.com -t "Hello from automation" +``` + +Linux / bash example with the command line and exact `stdin` in one block: + +```bash +cat <<'EOF_INPUT' | ./eppie-console --non-interactive=true --unlock-password-stdin=true --output=json -- send -s sender@example.com -r receiver@example.com -t "Hello from automation" +vault password +Hello from automation +Second body line +EOF_INPUT +``` + +Notes: +- on Linux and macOS, use `./eppie-console` after extracting the archive and making sure the file is executable. + +### Open local vault +Use `open` only in interactive mode when the agent is already inside a REPL session and must open the local vault in that same process. + +Notes: +- do not use `open` as part of the non-interactive agent workflow + +### Reset local data +Notes: +- `reset` is a destructive command and should be called with `--assume-yes=true` in automation or other non-interactive scripts. + +### Add DEC account +Expected result shape: +- `{"type":"result","code":"accountAdded","data":{"address":"","accountType":"Dec"},"meta":null}` + +### Add regular IMAP/SMTP account +Examples: + +JSON object: + +```json +{ + "email": "user@example.com", + "accountPassword": "account password", + "imapServer": "imap.example.com", + "imapPort": 993, + "smtpServer": "smtp.example.com", + "smtpPort": 465 +} +``` + +`stdin` shape: +- first line: `vault password` +- remaining bytes: + +```json +{"email":"user@example.com","accountPassword":"account password","imapServer":"imap.example.com","imapPort":993,"smtpServer":"smtp.example.com","smtpPort":465} +``` + +Notes: +- use this mode for regular IMAP/SMTP providers when browser-based OAuth is not needed +- do not pass account secrets in command-line arguments +- required structured properties are `email`, `accountPassword`, `imapServer`, `imapPort`, `smtpServer`, and `smtpPort` +- invalid structured input returns one of these machine-readable errors: + - `structuredStandardInputInvalidJson` + - `structuredStandardInputMissingProperty` + +### Add Proton Mail account +Examples: + +JSON object: + +```json +{ + "email": "user@proton.me", + "accountPassword": "account password", + "mailboxPassword": "mailbox password", + "twoFactorCode": "123456" +} +``` + +`stdin` shape: +- first line: `vault password` +- remaining bytes: + +```json +{"email":"user@proton.me","accountPassword":"account password","mailboxPassword":"mailbox password"} +``` + +Notes: +- do not pass Proton secrets in command-line arguments +- `email` and `accountPassword` are required in structured input +- `mailboxPassword` is required only if the Proton flow asks for it +- `twoFactorCode` is required only if the Proton flow asks for it +- if the mailbox password is the same as the account password, repeat the same value in `mailboxPassword` +- invalid structured input returns one of these machine-readable errors: + - `structuredStandardInputInvalidJson` + - `structuredStandardInputMissingProperty` + +## Reference: recommended agent workflow + +1. Start from the defaults in `Normative defaults for agents`. +2. Choose the exact command line from `Normative command patterns for agents`. +3. Provide `stdin` in the exact shape defined in `Normative stdin contracts`. +4. Use the account address from `list-accounts` `data[].address` for `-a`. +5. Use an isolated working directory when the run is disposable or destructive. +6. For message reading: + - start with `list-folders` if the next step requires a specific folder name, + - synchronize the relevant folder before reading when you need newly arrived messages, + - then use `show-all-messages` when you need recent messages across all folders, + - then call `show-message` or `delete-message` with the returned `id` and `pk`. +7. In `--non-interactive=true` mode text output stops after the first page instead of prompting. +8. For common task chains, use `Reference: end-to-end agent scenarios` as a quick reference. + +## Reference: known limitations + +### Some commands still require explicit non-interactive inputs +`--non-interactive=true` suppresses interactive prompts, but it does not invent missing data. + +Commands that normally ask follow-up questions still need explicit arguments or `stdin` data. +The main examples are already covered above: +- `send` reads the message body until end-of-stream in `--non-interactive=true` mode +- `add-account -t email` and `add-account -t proton` should use `--input-json-stdin` +- destructive commands such as `reset` still need `--assume-yes=true` +- paged read commands still default to 20 records when `-l` is omitted + +## Normative error handling + +For agent automation, prefer deterministic handling over implicit retries. + +### Interpret the normalized envelope + +When `--output=json` is enabled, handle responses by `type` first: + +| `type` | Meaning | Agent action | +| --- | --- | --- | +| `result` | command returned data | parse `data` and `meta` | +| `status` | command completed successfully without a list-style result | read `data` when present | +| `warning` | handled problem or non-success condition | inspect `code`; do not assume success; stop unless the workflow explicitly defines a recovery step | +| `error` | handled failure | inspect `code`, `message`, and `data`; stop unless the input can be corrected deterministically | + +### Common machine-readable codes + +| `code` | Meaning | Typical agent response | +| --- | --- | --- | +| `invalidPassword` | vault password was rejected | stop; do not retry automatically with the same password | +| `structuredStandardInputInvalidJson` | structured payload is not valid JSON | fix serialization and retry once with corrected JSON | +| `structuredStandardInputMissingProperty` | required JSON property is missing or empty | provide the missing property and retry once | +| `unhandledException` | command failed and returned exception details | inspect `data.exceptionType` and command context; do not retry blindly | + +### Agent response rules + +- Parse `type` first, then `code`. +- Do not treat `warning` as success. +- Do not retry `invalidPassword` automatically. +- Retry only when the failure is deterministic and local to the request, such as malformed JSON or a missing structured property. +- When retrying after `structuredStandardInputInvalidJson` or `structuredStandardInputMissingProperty`, change only the invalid input and keep the command line unchanged. +- For `unhandledException`, record the command, the parsed `code`, and `data.exceptionType` when present. +- When a paged read returns `meta.hasMore: true`, treat that as an incomplete result set rather than an error. + +### Error-output examples + +Invalid password example: +- `{"type":"warning","code":"invalidPassword","message":"Warning: Invalid password.","data":null}` + +Unknown sender account example for `send`: +- `{"type":"error","code":"unhandledException","message":"An error has occurred: ...","data":{"exceptionType":"Tuvi.Core.Entities.AccountIsNotExistInDatabaseException"}}` + +Invalid Proton structured input example: +- `{"type":"error","code":"structuredStandardInputInvalidJson","message":"Error: The remaining standard input for the 'add-account' command is not valid JSON.","data":{"commandName":"add-account"}}` + +Missing Proton structured property example: +- `{"type":"error","code":"structuredStandardInputMissingProperty","message":"Error: The structured standard input for the 'add-account' command must contain a non-empty 'email' property.","data":{"commandName":"add-account","propertyName":"email"}}` + +## Reference: contributing + +Contributions are welcome. + +Please open issues for bugs, UX problems, and feature ideas. +Pull requests on GitHub are also welcome. + +Repository: +- https://github.com/Eppie-io/Eppie-CLI diff --git a/skills/.curated/eppie-email-cli/agents/openai.yaml b/skills/.curated/eppie-email-cli/agents/openai.yaml new file mode 100644 index 00000000..03dfae78 --- /dev/null +++ b/skills/.curated/eppie-email-cli/agents/openai.yaml @@ -0,0 +1,6 @@ +interface: + display_name: "Eppie Email CLI" + short_description: "Read, send, and manage email via eppie-console" + icon_small: "./assets/eppie-email-cli-small.svg" + icon_large: "./assets/eppie-email-cli.png" + default_prompt: "Use $eppie-email-cli to read, send, or manage email through the eppie-console CLI." diff --git a/skills/.curated/eppie-email-cli/assets/eppie-email-cli-small.svg b/skills/.curated/eppie-email-cli/assets/eppie-email-cli-small.svg new file mode 100644 index 00000000..6bd8a636 --- /dev/null +++ b/skills/.curated/eppie-email-cli/assets/eppie-email-cli-small.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/skills/.curated/eppie-email-cli/assets/eppie-email-cli.png b/skills/.curated/eppie-email-cli/assets/eppie-email-cli.png new file mode 100644 index 0000000000000000000000000000000000000000..80c438b353d5a258067b6e06b5e6a3f0e0385434 GIT binary patch literal 2275 zcmds(={FnN8pgw+hjVJGsaH=>TJz8rRWuH5Qjs8tsIiJttucrxLJc*A($bp65c8N) ziMh9ms(GHdri&;kLPC|Bv({bfe!G9bS?l-iXMflqp0)S;K5NIDni%l>CiWWu0N^o% zg3Vd_<*(wpz*?)VYVugZ?E|&;0|2gV{#9&|&YXV$09EK08ulX;b1F8<~(Or1a4Kag7(r2p% zH#17mp3^wvjJYTMhnDX(yOscD#!&gCh_yP8nfE?N-)72aKv0N3#djS>2|jS0?g$TG zcMd*fqA#nt8jUkv0d*P~u2Vt0Ky8a-D<{hI8@FGGdJScmt)4{(7+G;DhFBNUlsu5_G^~OM4Rnqk%jyL-7gQ+TO zJ`NHNLyOIWdmB+ z)_Z)g(aAEV5Wb_%VLm)W__Gr)sv7d}Ox8F{$g=hkFox&KyW`e$RfibsdRLUTNbc}r zlb>wp*{PP29py%Urkd_z1TXRDgnW$@OxgboHeIrpn7UhusQ1P9J!W(@LczoOL-tmU|Hbv+Za^Vc*S}U z+4k-~)3-L0j=nEK?d0D z26RW*&*s-{ToGUN$MM2MrF04>05P`2_P>s zj!TZLzJHllDmc=hHy`f?R0m}Rc%=nY5z=*96<|nK|4$B$Jt#BbcvJAT=~O=$k%GDC zVDY-MNnzsVP9im?n@t+N9T9@=d60P-B!m^R}l=`P3l1-WtPsE9{hM^N8%pVP5~R_EE9!ZRhU9 z3kK%2<(2S5J7FRbbB}9CFpKi`Vyu z$z4t1f{2O)^zN03cn>9PI5!( z*+@cYkNrFDC$;Rx^RmaMVH~>ht7yt0Dg`=Jy6aHA3Y>wuV?0o@1zxCT4phdY165KK zXmUo#C-9P%HM;PD-45E{%2KrYAyV>YM`;x#5~WI*dLO*NlL02IV$RQgmQ9RgnGW}y z5l3kG+_}FKx9Kr0KFjx3BoGob!Fp!hx1Gkqwz%#>&9!Vz?=bA?csbIsD?vE3w&+S- z1(CFw_2qNCprFK5#}tKiM;XilpJp%OQmvD3md!9slG9_Zv6_L3*1e{$$%eY_=?*NS z@+EJMiA%W;74sy{-M>TjUQ(gAN^ub#F-x;zaBmZw7|h~2OEDa0=JwUadTeOXzR@IW|OPwJ2ycOprh#yetgKA3PN?U5vq=qM)rR-eV! z>1K>OjbN>YH1t=+Ws5$u2&?R=@$9!>2V3(FWMJ|6Eti`Zz3Jsz~EIlH`~g^8v(fRccGi`qrX^tMUQ`m^=knbLQKFl I_Z~<72gYXw5dZ)H literal 0 HcmV?d00001