mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-11-14 06:57:51 +00:00
* bots, nodejs: document chat, connection, member contact and network commands, typed commands in library * bots, nodejs: restore apiConnect, wrap domain once, test all connect responses * nodejs: JSDoc for new methods * docs: plan for bot API commands and typed Node library methods * tests: channel prepared with a domain has a verified SimpleX name * docs: apply review fixes to the plan for bot API commands * docs: apply second review pass to the plan for bot API commands * docs: refer the bot API plan to the rewritten test commit * docs: record decisions in the plan for bot API commands * docs: plan tests of the generated Python command strings * python: test the generated strings of the documented commands * docs: plan for files, /leave and library methods in the MCP server * docs: wait at stop in the MCP plan * docs: library methods and /leave mechanics in the MCP plan * mcp: typed library methods for chat commands * docs: plan the message information command for bots * mcp: /leave CHAT owner command to leave a chat at once * docs: file servers, GIF and video choices decided in the MCP plan * docs: file mechanics in the MCP plan * mcp: files of received messages * bots, nodejs: message information with the file servers for bots * docs: plan the relay approval option of receiving files in Node * mcp: download of received files with owner approval * docs: name the xftp-server test helper in the files plan * nodejs: receive files without approving unknown relays * docs: plan the user servers command for bots * bots, nodejs: user servers and relays by operator for bots * nodejs: document the message information method * docs: plan the file upload progress event for bots * mcp: send files with owner approval, refusing private keys * bots: file upload progress event for bots * mcp: /leave template in the agent control chat menu * docs: sent copies are deleted for contacts too, at sndFileCompleteXFTP * bots: drop the file upload progress event * docs: drop the upload progress event plan * nodejs: document user servers and relay approval of received files * mcp: download cards name unknown file servers after the upload * docs: record the wait for the file description in the files plan * mcp: fixed wait at stop for cancelled cards, without /sql * docs: record decision C4, a fixed wait at stop, in the files plan * ci: test the MCP server package on pull requests * ci: state when the MCP workflow can be dispatched * ci: run the MCP server tests when its libraries change * mcp: log the errors of image previews and resizing * mcp: keep files in transfer in the data folder * mcp: restrict sent files by the real paths of refused folders * mcp: validate the file at the send by its inode and change time * mcp: limit ffmpeg and ffprobe to local files and no input commands * mcp: ask the owner for unknown file servers; read approvals at creation * mcp: name downloaded files by their ID; return paths of downloads only * mcp: end each download with a result for the agent and the card * mcp: show files above their sender's size limit as failed * mcp: refuse empty files, as without file and captions too long to send * mcp: tell the owner about failed uploads and unposted received files * mcp: delete resized copies left by the last run at start * mcp: name downloads and leaving in the help and greeting, align docs * mcp: compute the download path for received files only * mcp: send a /receive file to the owner under its name * mcp: keep files received without a download in the chat's folder * mcp: keep a left chat's files and delete them with /delete CHAT files * mcp: test that sent images are resized by the core * mcp: wait 30 minutes for a download's progress before cancelling it * mcp: end a download as deleted only when its message is not found * mcp: delete the copy of a /receive file whose post fails * mcp: count the quoted content in a message's length, as the core sends it * mcp: name received bytes, unknown-server downloads and left chat files plainly * mcp: test refused folders, file changes and download approvals * docs: align MCP server docs with refused folders, leaves and download waits * mcp: move received files only in full, delete partials only of downloads * mcp: report a received file missing from its folder as failed * mcp: move received files of a group's member chats into its folder * mcp: read a video's preview and duration as an MP4 or QuickTime file * mcp: 0.2.0 on simplex-chat 7.1.0-beta.10.1 * mcp: file folders by chat type, /delete cancels downloads, files reply * docs: MCP server specs and plan for 0.2.0 * mcp: /receive gives the agent a file, /forward sends it to the owner * docs: MCP server specs for /receive and /forward of download cards * docs: MCP plan records the temp folder command as a library exception * mcp: /delete cancels resumed downloads; /forward quote fits the limit * docs: MCP specs and plans for /forward quotes and resumed downloads * docs: MCP specs name the source commit they are checked against * docs: MCP PLAN states the /forward quote and move rules * mcp: a download moves its completed file whatever its size * mcp: /receive N all covers its card and later files, not pending ones * docs: MCP files approval scope, reply text and README server wording * mcp: a download approves relays only for a card naming unknown servers * mcp: files in member chats of a group are tracked as in the main chat * docs: MCP relay approval of downloads and files in member chats * mcp: a rejected file gets a card again under the files approval * docs: MCP rejected files under the files approval, README scope * mcp: an offered file without a description gets no card or action * docs: MCP a file without a description is not downloaded * mcp: 0.2.0 on simplex-chat 7.1.0-beta.10.2 * ci: test the MCP server as a scope of build-linux
724 lines
37 KiB
Markdown
724 lines
37 KiB
Markdown
# SimpleX MCP server: flows
|
||
|
||
> Sequence diagrams of the main flows, each with notes and source locations.
|
||
>
|
||
> Related specs: [README](README.md) | [Architecture](architecture.md) | [API](api.md)
|
||
|
||
Participants:
|
||
|
||
| Letter | Participant |
|
||
|---|---|
|
||
| P | the person at the terminal |
|
||
| A | the agent in Claude Code |
|
||
| H | the HTTP listener with the MCP SDK |
|
||
| T | `AgentTools` |
|
||
| X | `Actions` |
|
||
| K | `Control` |
|
||
| C | the SimpleX core behind `ChatApi` |
|
||
| O | the owner in the SimpleX app |
|
||
| D | a peer |
|
||
|
||
`#G` is the agent control chat, `USER` the agent's user ID, `DATA` the data folder. Calls to the core are shown as the `ChatApi` methods the server calls, with their arguments in short. Card and progress texts with a semicolon are shown with a comma in the diagrams; the exact texts are in [API](api.md).
|
||
|
||
---
|
||
|
||
## Table of contents
|
||
|
||
1. [First start and the owner joins](#1-first-start-and-the-owner-joins)
|
||
2. [`register`](#2-register)
|
||
3. [`connect` with approval](#3-connect-with-approval)
|
||
4. [`send` with responses](#4-send-with-responses)
|
||
5. [`receive` with `wait`](#5-receive-with-wait)
|
||
6. [`send` under a standing approval, and `/revoke`](#6-send-under-a-standing-approval-and-revoke)
|
||
7. [`leave`](#7-leave)
|
||
8. [Mode `host`](#8-mode-host)
|
||
9. [Expiry](#9-expiry)
|
||
10. [A lost call and its re-attachment](#10-a-lost-call-and-its-re-attachment)
|
||
11. [Shutdown with pending actions](#11-shutdown-with-pending-actions)
|
||
12. [`--owners` setup](#12---owners-setup)
|
||
13. [`download` with approval](#13-download-with-approval)
|
||
14. [`/forward`](#14-forward)
|
||
15. [`send` with a file](#15-send-with-a-file)
|
||
16. [`/leave` and `/delete CHAT files`](#16-leave-and-delete-chat-files)
|
||
|
||
---
|
||
|
||
## 1. First start and the owner joins
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant P as Person
|
||
participant S as serve.ts
|
||
participant C as Core
|
||
participant K as Control
|
||
participant O as Owner
|
||
P->>S: simplex-mcp serve my-agent --display-name "My Agent"
|
||
S->>S: DATA mode 0700, lock, token, headers.json
|
||
S->>C: ChatApi.init DATA/simplex
|
||
S->>P: version line, data folder, approval mode
|
||
S->>C: apiGetActiveUser (none)
|
||
S->>C: apiCreateActiveUser {displayName: "My Agent", fullName: "", peerType: agent}
|
||
S->>C: apiSetNetworkConfig smpProxyMode always, smpProxyFallback allowProtected
|
||
S->>C: /_temp_folder DATA/tmp
|
||
S->>S: DATA/files/sent deleted
|
||
S->>C: startChat, events buffered
|
||
S->>C: apiListGroups USER (no control marker)
|
||
S->>C: apiNewGroup USER {My Agent, history on, menu pending, list and leave}
|
||
S->>C: apiSetGroupCustomData #G {"simplexMcp":{"control":true,"nextAction":1}}
|
||
S->>P: Agent control chat "My Agent" created.
|
||
S->>K: load
|
||
K->>C: apiListMembers #G
|
||
S->>S: HTTP listens on 127.0.0.1:5226, /mcp answers 503 until the control chat is started
|
||
S->>S: server.json
|
||
K->>C: apiDeleteGroupLink #G (groupLinkNotFound ignored)
|
||
K->>C: apiCreateGroupLink #G member
|
||
K->>P: join line, QR code, link, QR hint, owner line
|
||
S->>P: Listening on http://127.0.0.1:5226/mcp
|
||
O->>C: joins by the link
|
||
C->>S: joinedGroupMember
|
||
S->>K: onEvent, queued
|
||
K->>C: apiListMembers #G
|
||
K->>C: apiDeleteGroupLink #G
|
||
K->>C: apiSetMembersRole #G [3] owner
|
||
K->>C: apiListMembers #G
|
||
K->>O: I'm your agent. I ask here before I connect, send, download a file or leave a chat.
|
||
K->>P: Alice joined (member 3) and is now an owner. The link is deleted.
|
||
K->>P: Add the agent to Claude Code: npx -y @simplex-chat/mcp register my-agent
|
||
```
|
||
|
||
Notes:
|
||
|
||
- At first use, libsimplex and the Node.js add-on are downloaded, with one `Downloading ...` line each on stderr ([libs.ts:114-135](../../simplex-chat-nodejs/src/libs.ts#L114-L135)).
|
||
- With `--data`, `--data <folder>` is appended to the register hint, shell-quoted ([serve.ts:185-187](../src/serve.ts#L185-L187)).
|
||
- With `--qr-code small`, the line `If the QR code does not scan, ...` is printed after the link ([control.ts:412](../src/control.ts#L412)).
|
||
- Events that arrive before the HTTP listener starts are buffered and handled in order ([serve.ts:234-248](../src/serve.ts#L234-L248)).
|
||
- The server runs `ownerJoined` for every `joinedGroupMember` event of a human without `--owners`, and the link is deleted in that handler ([control.ts:189-190](../src/control.ts#L189-L190), [:371-378](../src/control.ts#L371-L378)).
|
||
|
||
Source: [cli.ts:198-209](../src/cli.ts#L198-L209), [serve.ts:65-126](../src/serve.ts#L65-L126), [:205-223](../src/serve.ts#L205-L223), [files.ts:12-48](../src/files.ts#L12-L48), [http.ts:14-46](../src/http.ts#L14-L46), [control.ts:102-117](../src/control.ts#L102-L117), [:341-345](../src/control.ts#L341-L345), [:406-425](../src/control.ts#L406-L425), [:499-520](../src/control.ts#L499-L520).
|
||
|
||
---
|
||
|
||
## 2. `register`
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant P as Person
|
||
participant R as register.ts
|
||
participant L as claude CLI
|
||
participant CC as Claude Code
|
||
participant H as HTTP
|
||
P->>R: simplex-mcp register my-agent [--scope local] [--data DIR]
|
||
R->>R: read DATA/server.json
|
||
alt server.json missing
|
||
R->>P: Agent "my-agent" was never started. Start it with: ... (exit 1)
|
||
end
|
||
R->>L: claude mcp remove --scope user simplex-my-agent
|
||
R->>L: claude mcp add-json --scope user simplex-my-agent {"type":"http","url":"http://127.0.0.1:5226/mcp","headersHelper":"cat DATA/headers.json","timeout":169800000}
|
||
alt claude not found
|
||
R->>P: Add this entry under "mcpServers" in ~/.claude.json: {...} (exit 1)
|
||
else add-json exit status other than 0
|
||
R->>P: claude mcp add-json failed: STDERR (exit 1)
|
||
end
|
||
R->>P: Added to Claude Code: scope user, server simplex-my-agent.
|
||
CC->>CC: headersHelper: cat DATA/headers.json
|
||
CC->>H: POST /mcp with Authorization: Bearer TOKEN
|
||
```
|
||
|
||
Notes:
|
||
|
||
- `simplex-mcp` ignores the exit status of `claude mcp remove` and stops at that step only when the `claude` binary is missing ([register.ts:38-39](../src/register.ts#L38-L39)).
|
||
- On Windows, a missing `claude` is run again through `cmd.exe`, with each argument quoted for it ([register.ts:86-101](../src/register.ts#L86-L101)).
|
||
- `timeout` is `(expireHours + 24) × 3600000 + 600000` ms from `server.json` ([register.ts:51](../src/register.ts#L51)).
|
||
- With `--scope local`, the project folder in the manual entry is the git repository root, the main repository of a worktree, or the current folder outside a repository ([register.ts:56](../src/register.ts#L56), [:60-84](../src/register.ts#L60-L84)).
|
||
|
||
Source: [cli.ts:110-125](../src/cli.ts#L110-L125), [:207](../src/cli.ts#L207), [register.ts:33-58](../src/register.ts#L33-L58), [files.ts:50-53](../src/files.ts#L50-L53).
|
||
|
||
---
|
||
|
||
## 3. `connect` with approval
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as Agent
|
||
participant H as HTTP and SDK
|
||
participant T as AgentTools
|
||
participant X as Actions
|
||
participant K as Control
|
||
participant C as Core
|
||
participant O as Owner
|
||
participant D as Peer
|
||
A->>H: tools/call connect {target: "@directory.simplex", wait, idle}
|
||
H->>T: validated input, abort signal, progress token
|
||
T->>X: find(key): none
|
||
T->>C: apiConnectPlan USER @directory.simplex
|
||
C-->>T: contactAddress ok, planSimplexName
|
||
T->>T: classifyPlan: prepareContact with domain
|
||
T->>X: create(key, connect fields)
|
||
X->>K: refusal: none
|
||
X->>K: saveCounter: apiSetGroupCustomData #G
|
||
X->>K: postCard
|
||
K->>O: I want to connect to bot X (@directory.simplex), as myself. /'approve N' or /'reject N'
|
||
T->>X: decided(action, call)
|
||
X-->>A: progress: Action N waits for an approver until TIME.
|
||
O->>C: /approve N
|
||
C->>K: newChatItems
|
||
K->>X: approve(action, "Alice")
|
||
X->>T: performConnect
|
||
T->>C: apiConnectPlan USER @directory.simplex
|
||
T->>C: apiPrepareContact USER LINK linkData directory.simplex
|
||
T->>C: apiConnectPreparedContact @C incognito false
|
||
C-->>T: startedConnectionToContact
|
||
D->>C: accepts the request
|
||
C->>T: contactConnected: markConnected, collect @C
|
||
T-->>X: perform ends
|
||
X->>K: outcome
|
||
K->>O: card edited: I connected to bot X (@directory.simplex), as myself. Approved by Alice.
|
||
T->>C: apiGetChat @C count 50
|
||
T->>T: wait until idle or startedAt + wait
|
||
T->>C: apiChatItemsRead @C, new item IDs
|
||
T->>X: remove(action)
|
||
T-->>A: {action: N, status: done, chat: @C, connected: true, messages}
|
||
```
|
||
|
||
Notes:
|
||
|
||
- The plan is read again in the perform step ([tools.ts:690](../src/tools.ts#L690)).
|
||
- Join methods per plan ([tools.ts:719-747](../src/tools.ts#L719-L747), [:1260-1323](../src/tools.ts#L1260-L1323)):
|
||
|
||
| Plan | Methods |
|
||
|---|---|
|
||
| known prepared contact or group | `apiConnectPreparedContact(C, incognito, message)`<br>`apiConnectPreparedGroup(G, incognito, message)` |
|
||
| channel link (`direct` false, with link data) | `apiPrepareGroup(USER, LINK, false, linkData, domain)`<br>`apiConnectPreparedGroup(G, incognito)` |
|
||
| contact address with link data, and a SimpleX name or a message | `apiPrepareContact(USER, LINK, linkData, domain)`<br>`apiConnectPreparedContact(C, incognito, message)`, or `apiConnectPreparedGroup` for a business |
|
||
| `contactViaAddress` | `apiConnectContactViaAddress(USER, incognito, CONTACT_ID)` |
|
||
| other links | `apiConnectPreparedLink(USER, incognito, LINK)` |
|
||
|
||
- After a failed prepared connect, the server deletes the prepared chat without notifying ([tools.ts:749-756](../src/tools.ts#L749-L756)).
|
||
- The connection is matched by `contactConnected` or `userJoinedGroup`: by contact or group ID, or by the pending connection ID ([tools.ts:590-598](../src/tools.ts#L590-L598), [:758-763](../src/tools.ts#L758-L763)).
|
||
- In the perform step the server waits for the other side until `startedAt + wait`, at most until `created + 23 h 50 min`, and then reports `connected: false` ([tools.ts:143](../src/tools.ts#L143), [:689](../src/tools.ts#L689), [:713-716](../src/tools.ts#L713-L716)).
|
||
- Without `message`, the idle time is counted from the connection; with `message`, from the first reply ([tools.ts:769](../src/tools.ts#L769), [messages.ts:323-331](../src/messages.ts#L323-L331)).
|
||
- For a target the agent is connected to, the result is `status: known` with its chat fields, and no action is created ([tools.ts:622](../src/tools.ts#L622)).
|
||
- Exact progress texts: `Action N waits for an approver until TIME.`, then `Action N waits for the connection until TIME.`, then `K messages in CHAT; waiting until TIME.` ([actions.ts:343-354](../src/actions.ts#L343-L354), [tools.ts:658](../src/tools.ts#L658)).
|
||
|
||
Source: [tools.ts:617-672](../src/tools.ts#L617-L672), [:686-772](../src/tools.ts#L686-L772), [actions.ts:155-186](../src/actions.ts#L155-L186), [:206-223](../src/actions.ts#L206-L223), [control.ts:141-152](../src/control.ts#L141-L152).
|
||
|
||
---
|
||
|
||
## 4. `send` with responses
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as Agent
|
||
participant T as AgentTools
|
||
participant X as Actions
|
||
participant K as Control
|
||
participant C as Core
|
||
participant O as Owner
|
||
participant D as Peer
|
||
A->>T: send {chat: #15, text, reply_to, mention: [44], wait, idle, limit}
|
||
T->>C: apiGetChat #15 count 0
|
||
T->>C: apiGetChat #15 around REPLY_TO count 0
|
||
T->>C: apiListMembers #15
|
||
T->>C: apiGetChat #15 count 0
|
||
T->>K: standingApprover(chatInfo, messages): none
|
||
T->>X: create(key, send fields)
|
||
X->>K: card size check and approvers
|
||
K->>O: I want to send a message to group X: `text` replying to ... mentioning @Switchback /'approve #15 N', /'approve #15 all' or /'reject #15 N'
|
||
O->>C: /approve #15 N
|
||
K->>X: approve(action, "Alice")
|
||
X->>T: performSend
|
||
T->>T: collect #15 items with ID above the sent item
|
||
T->>C: apiSendMessages #15 [{msgContent, mentions, quotedItemId}]
|
||
C-->>T: sent item S
|
||
D->>C: replies S+1, S+2
|
||
C->>T: newChatItems: collected
|
||
X->>K: outcome
|
||
K->>O: card edited: I sent a message to group X: `text` ... Approved by Alice.
|
||
T->>T: wait until idle seconds after the last reply, or sentAt + wait
|
||
T->>C: apiChatItemsRead #15 [S+1, S+2]
|
||
T->>X: remove(action)
|
||
T-->>A: {action: N, status: done, chat: #15, item: S, responses, more: 0}
|
||
```
|
||
|
||
Notes:
|
||
|
||
- Checks before the action: `text` or `file`, the chat connected, role `observer` or `relay` refused, `reply_to` item a message, mentioned members present and the chat a group, and the message length with its quote ([tools.ts:779-792](../src/tools.ts#L779-L792)).
|
||
- The server starts collecting before the send and, after it, drops items with IDs up to the sent item ([tools.ts:825](../src/tools.ts#L825), [:838-840](../src/tools.ts#L838-L840)).
|
||
- Mentioned names missing from the text are prefixed as `@name` ([tools.ts:1424-1427](../src/tools.ts#L1424-L1427)).
|
||
- While a collected message is live, the server waits for its final update; live items are left out of `responses` and counted in `more` ([messages.ts:323-331](../src/messages.ts#L323-L331), [tools.ts:811](../src/tools.ts#L811), [:817](../src/tools.ts#L817)).
|
||
- At most 100 replies are kept per action; later ones are counted as overflow ([messages.ts:10](../src/messages.ts#L10), [:109-110](../src/messages.ts#L109-L110)).
|
||
|
||
Source: [tools.ts:774-846](../src/tools.ts#L774-L846), [messages.ts:99-114](../src/messages.ts#L99-L114), [:323-331](../src/messages.ts#L323-L331), [control.ts:583-589](../src/control.ts#L583-L589).
|
||
|
||
---
|
||
|
||
## 5. `receive` with `wait`
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as Agent
|
||
participant T as AgentTools
|
||
participant W as ChatItemsWatch
|
||
participant C as Core
|
||
participant D as Peer
|
||
A->>T: receive {chat: #12, wait: 3600, limit: 50}
|
||
T->>W: collect #12 into arrived
|
||
T->>C: apiGetChat #12 initial 1
|
||
C-->>T: chatStats.unreadCount 0
|
||
T-->>A: progress: No new messages in #12, waiting until TIME.
|
||
D->>C: post, item 40
|
||
C->>W: newChatItems: arrived
|
||
T->>C: apiChatItemsRead #12 [40]
|
||
T->>W: stop collecting
|
||
T-->>A: {chat: #12, messages: [40], more: 0}
|
||
```
|
||
|
||
Notes:
|
||
|
||
- With unread items the server reads `around` the first unread item, `count` 0, then pages of `after` the last item, `count` 100, until it holds `limit + 1` unread, non-live messages or a page is short ([messages.ts:285-299](../src/messages.ts#L285-L299)).
|
||
- Unread items other than messages in the read pages are marked read with the returned messages ([tools.ts:1125](../src/tools.ts#L1125), [:1142](../src/tools.ts#L1142)).
|
||
- `more`: the arrived messages not returned, the overflow and the unread items not read ([tools.ts:1144](../src/tools.ts#L1144)).
|
||
- Items received while the pages are read are returned once ([tools.ts:1124-1127](../src/tools.ts#L1124-L1127)).
|
||
- Exact progress text: `No new messages in CHAT; waiting until TIME.` ([tools.ts:1131](../src/tools.ts#L1131)).
|
||
|
||
Source: [tools.ts:1114-1148](../src/tools.ts#L1114-L1148), [messages.ts:285-331](../src/messages.ts#L285-L331).
|
||
|
||
---
|
||
|
||
## 6. `send` under a standing approval, and `/revoke`
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as Agent
|
||
participant T as AgentTools
|
||
participant X as Actions
|
||
participant K as Control
|
||
participant C as Core
|
||
participant O as Owner
|
||
O->>C: /approve #9 all (on a pending send card)
|
||
C->>K: newChatItems
|
||
K->>C: apiGetChat #9 count 0
|
||
K->>C: apiSetGroupCustomData #9 {"simplexMcp":{"approvedBy":"Alice","approvedById":3,"approvedAt":"..."}}
|
||
K->>X: approve each pending send to #9 with a card
|
||
K->>O: Approved for business X (#9) by Alice. /'revoke #9'
|
||
A->>T: send {chat: #9, text}
|
||
T->>C: apiGetChat #9 count 0
|
||
T->>K: standingApprover: Alice
|
||
T->>X: create(key, fields, "Alice"): performing, standing
|
||
X->>K: saveCounter (no card)
|
||
X->>T: performSend
|
||
T->>C: apiSendMessages #9 [...]
|
||
X->>K: outcome
|
||
K->>O: I sent a message to business X: `text` Approved for this chat by Alice. /'revoke #9'
|
||
T-->>A: {action, status: done, chat: #9, item, responses, more}
|
||
O->>C: /revoke #9
|
||
K->>C: apiGetChat #9 count 0
|
||
K->>C: apiSetGroupCustomData #9 {other keys}
|
||
K->>O: Messages to business X (#9) need approval again.
|
||
```
|
||
|
||
Notes:
|
||
|
||
- The approval is used in mode `requests` while member `approvedById` is an approver ([control.ts:130-133](../src/control.ts#L130-L133)).
|
||
- For sends that were pending at `/approve CHAT all`, the card ends with the plain `Approved by Alice.` ([control.ts:554](../src/control.ts#L554), [:563](../src/control.ts#L563)).
|
||
- `connect` and `leave` actions are created without the standing approver, so they stay pending ([tools.ts:628](../src/tools.ts#L628), [:942](../src/tools.ts#L942)).
|
||
- `/receive CHAT N all` and `/receive CHAT off` work the same way for downloads, with the key `simplexMcpFiles`, except that download N alone is performed, and the other pending downloads of the chat stay pending ([control.ts:22-25](../src/control.ts#L22-L25), [:251-253](../src/control.ts#L251-L253), [tools.ts:975](../src/tools.ts#L975)).
|
||
|
||
Source: [control.ts:243-263](../src/control.ts#L243-L263), [:337-339](../src/control.ts#L337-L339), [tools.ts:796-798](../src/tools.ts#L796-L798), [actions.ts:155-186](../src/actions.ts#L155-L186), [:265-283](../src/actions.ts#L265-L283).
|
||
|
||
---
|
||
|
||
## 7. `leave`
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as Agent
|
||
participant T as AgentTools
|
||
participant X as Actions
|
||
participant K as Control
|
||
participant C as Core
|
||
participant O as Owner
|
||
A->>T: leave {chat: #9}
|
||
T->>X: find(key): none
|
||
T->>C: apiGetChat #9 count 0
|
||
T->>X: create(key, leave fields)
|
||
K->>O: I want to leave business X (#9). /'approve #9 N' or /'reject #9 N'
|
||
O->>C: /approve #9 N
|
||
K->>X: approve(action, "Alice")
|
||
X->>T: leaveChat(#9)
|
||
T->>C: apiGetChat #9 count 0
|
||
T->>C: apiLeaveGroup #9 (membership current or pending)
|
||
T->>C: apiDeleteChat #9 full, notify
|
||
T->>T: DATA/forwarded/group-9 deleted
|
||
X->>K: outcome
|
||
K->>O: card edited: I left business X (#9). Approved by Alice.
|
||
K->>O: Files from business X (#9) are kept in `DATA/files/group-9`: K files, SIZE. /'delete #9 files' (when the folder has files)
|
||
T-->>A: {action: N, status: done, chat: #9}
|
||
```
|
||
|
||
Notes:
|
||
|
||
- For a contact, the card text is `I want to delete KIND NAME (@N).`, and the perform step calls `apiDeleteChat` for the contact, full, with notify ([control.ts:590-593](../src/control.ts#L590-L593), [tools.ts:951](../src/tools.ts#L951)).
|
||
- The delete notifies, so the core notifies the contact or the members ([tools.ts:951](../src/tools.ts#L951), [:954](../src/tools.ts#L954)).
|
||
- The server looks for an attached action before it reads the chat, so a repeated call after the deletion is attached to the done action ([tools.ts:937-940](../src/tools.ts#L937-L940)).
|
||
|
||
Source: [tools.ts:935-958](../src/tools.ts#L935-L958), [control.ts:145-152](../src/control.ts#L145-L152), [:299-302](../src/control.ts#L299-L302).
|
||
|
||
---
|
||
|
||
## 8. Mode `host`
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant P as Person
|
||
participant A as Agent
|
||
participant H as HTTP and SDK
|
||
participant T as AgentTools
|
||
participant X as Actions
|
||
participant K as Control
|
||
participant O as Owner
|
||
Note over P,H: the person started serve my-agent --approve host
|
||
A->>H: tools/list
|
||
H-->>A: connect, send, download, leave with _meta {"anthropic/requiresUserInteraction": true}
|
||
A->>A: Claude Code asks its user
|
||
A->>T: send {chat: @4, text}
|
||
T->>X: create: performing
|
||
X->>K: saveCounter (no card)
|
||
X->>T: performSend
|
||
X->>P: Action N: performed without approval (mode host).
|
||
X->>K: outcome
|
||
K->>O: I sent a message to bot X: `text` Performed without approval (mode host).
|
||
T-->>A: {action: N, status: done, ...}
|
||
```
|
||
|
||
Notes:
|
||
|
||
- New actions are still refused unless the control chat has an approver ([control.ts:124-127](../src/control.ts#L124-L127)).
|
||
- In mode `host`, `standingApprover` returns `undefined`, so standing approvals are ignored by `send`, `download`, `list` and `/list`, and `/approve CHAT all` stores nothing; downloads get no card, so `/receive CHAT N all` has no card to act on ([control.ts:132](../src/control.ts#L132), [:213](../src/control.ts#L213)).
|
||
- A download in mode `host` is received without the approval of unknown servers, and it gets no card and no outcome post ([tools.ts:545](../src/tools.ts#L545), [:1030](../src/tools.ts#L1030), [control.ts:495-497](../src/control.ts#L495-L497)).
|
||
- The kept-files message also follows a done `leave` in mode `host` ([control.ts:150-151](../src/control.ts#L150-L151)).
|
||
|
||
Source: [tools.ts:488-498](../src/tools.ts#L488-L498), [actions.ts:166](../src/actions.ts#L166), [:281](../src/actions.ts#L281), [control.ts:145-152](../src/control.ts#L145-L152), [:554](../src/control.ts#L554).
|
||
|
||
---
|
||
|
||
## 9. Expiry
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as Agent
|
||
participant X as Actions
|
||
participant K as Control
|
||
participant O as Owner
|
||
A->>X: send call creates pending action N at T
|
||
K->>O: card N
|
||
Note over X: expires = T + expireHours
|
||
loop every 60 s, and before each owner command
|
||
X->>X: expireDue
|
||
end
|
||
X->>X: pending and due: expired
|
||
X->>K: outcome
|
||
K->>O: card edited: ... Expired.
|
||
X-->>A: {action: N, status: expired}
|
||
X->>X: removed with the result
|
||
O->>K: /approve N
|
||
K->>O: Action N is not pending.
|
||
```
|
||
|
||
Notes:
|
||
|
||
- A decided action with an open count of 0 is removed at the first tick after its expiry time ([actions.ts:200-201](../src/actions.ts#L200-L201)).
|
||
- Expiry times are listed in the `/pending` reply ([control.ts:618-620](../src/control.ts#L618-L620)).
|
||
- The server ends the connect wait at `created + 23 h 50 min`, within the 24 hours in which a message can be edited ([tools.ts:143](../src/tools.ts#L143), [:689](../src/tools.ts#L689)).
|
||
|
||
Source: [actions.ts:129](../src/actions.ts#L129), [:163](../src/actions.ts#L163), [:193-204](../src/actions.ts#L193-L204), [control.ts:201](../src/control.ts#L201), [:227](../src/control.ts#L227).
|
||
|
||
---
|
||
|
||
## 10. A lost call and its re-attachment
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as Agent
|
||
participant H as HTTP and SDK
|
||
participant T as AgentTools
|
||
participant X as Actions
|
||
participant O as Owner
|
||
A->>H: send {chat: @4, text: "t"}
|
||
H->>T: call
|
||
T->>X: create: pending, open 1
|
||
A->>H: closes the response stream
|
||
H->>T: ctx.mcpReq.signal aborted
|
||
T->>X: decided: false, open 0
|
||
Note over H: result discarded by the SDK
|
||
A->>T: list
|
||
T-->>A: actions: [{action: N, tool: send, input, state: pending, open: false}]
|
||
O->>X: /approve N
|
||
X->>X: perform, done, replies collected
|
||
A->>T: send {chat: @4, text: "t"}
|
||
T->>X: find(key): action N
|
||
T->>T: doneAtCall: wait counted from now
|
||
T->>X: remove(action)
|
||
T-->>A: {action: N, status: done, item, responses, more}
|
||
```
|
||
|
||
Notes:
|
||
|
||
- The key is the tool name with the action fields: `target`, `incognito`, `message` for `connect`; `chat`, `text`, `file`, `as`, `reply_to`, `mention` for `send`; `chat`, `item` for `download`; `chat` for `leave` ([tools.ts:618](../src/tools.ts#L618), [:776](../src/tools.ts#L776), [:937](../src/tools.ts#L937), [:962](../src/tools.ts#L962), [:1554-1556](../src/tools.ts#L1554-L1556)).
|
||
- The `wait`, `idle` and `limit` of the attaching call are used ([tools.ts:805](../src/tools.ts#L805)).
|
||
- For a call aborted before `create`, the server returns before it creates an action ([tools.ts:627](../src/tools.ts#L627), [:797](../src/tools.ts#L797), [:941](../src/tools.ts#L941), [:976](../src/tools.ts#L976)).
|
||
- Abort path in the SDK: on `res` close the web request is aborted ([node index.cjs:299-303](../node_modules/@modelcontextprotocol/node/dist/index.cjs#L299-L303)); the per-request transport is closed ([server index.cjs:86-90](../node_modules/@modelcontextprotocol/server/dist/index.cjs#L86-L90)); the handler signal is aborted ([src-BhnGYybN.cjs:6425](../node_modules/@modelcontextprotocol/server/dist/src-BhnGYybN.cjs#L6425)).
|
||
|
||
Source: [tools.ts:636-648](../src/tools.ts#L636-L648), [:802-820](../src/tools.ts#L802-L820), [:1156](../src/tools.ts#L1156), [actions.ts:206-217](../src/actions.ts#L206-L217), [messages.ts:307-321](../src/messages.ts#L307-L321).
|
||
|
||
---
|
||
|
||
## 11. Shutdown with pending actions
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant P as Person
|
||
participant S as serve.ts
|
||
participant X as Actions
|
||
participant K as Control
|
||
participant H as HTTP
|
||
participant C as Core
|
||
participant O as Owner
|
||
P->>S: Ctrl-C (SIGINT)
|
||
S->>S: stopped: events ignored
|
||
par actions
|
||
S->>X: stop()
|
||
X->>X: stopping, timer cleared, cards being posted awaited
|
||
X->>X: pending and performing: interrupted, performs aborted
|
||
X->>K: outcome of each
|
||
K->>O: pending: ... Cancelled: the server stopped.
|
||
K->>O: performing: ... Approved by Alice, interrupted: the server stopped.
|
||
and HTTP
|
||
S->>H: close, closeAllConnections (open calls aborted)
|
||
end
|
||
S->>P: Cancelled 2 actions.
|
||
S->>P: Stopping: sending 2 cancelled cards, up to 10 s. Ctrl-C to stop now.
|
||
S->>S: wait 10 s, or until a second Ctrl-C
|
||
S->>C: close
|
||
S->>S: remove DATA/lock
|
||
S->>P: Stopped.
|
||
Note over P,O: next start: counter continues, /approve of an old number: Action N is not pending.
|
||
```
|
||
|
||
Notes:
|
||
|
||
- The interrupted card line is `DECIDER; interrupted: the server stopped.` ([control.ts:561](../src/control.ts#L561)).
|
||
- An action of mode `host` or of a standing approval whose counter is being written at the stop is set to `pending` and cancelled without a perform ([actions.ts:265-270](../src/actions.ts#L265-L270)).
|
||
- After a crash, the cards of that run are left with their commands; `/approve` of their numbers gets the reply `Action N is not pending.` ([control.ts:227](../src/control.ts#L227)).
|
||
- The stop signal of the performs is aborted after the actions are marked interrupted: a `connect` waiting for its connection ends, and an interrupted perform logs no line ([actions.ts:245-246](../src/actions.ts#L245-L246), [:280](../src/actions.ts#L280), [tools.ts:713-714](../src/tools.ts#L713-L714)).
|
||
- The wait applies only when cards were edited or posted at the stop, a `download` without a card excluded, and `--stop-wait` is above 0 ([serve.ts:177](../src/serve.ts#L177), [:189-203](../src/serve.ts#L189-L203)).
|
||
|
||
Source: [serve.ts:47-63](../src/serve.ts#L47-L63), [:171-181](../src/serve.ts#L171-L181), [:189-203](../src/serve.ts#L189-L203), [actions.ts:240-250](../src/actions.ts#L240-L250), [http.ts:48-52](../src/http.ts#L48-L52), [control.ts:552-571](../src/control.ts#L552-L571).
|
||
|
||
---
|
||
|
||
## 12. `--owners` setup
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant P as Person
|
||
participant K as Control
|
||
participant C as Core
|
||
participant O as Owner Alice
|
||
participant B as Member Bob
|
||
P->>K: serve my-agent --owners
|
||
K->>C: apiCreateGroupLink #G observer
|
||
K->>P: The link adds an observer. Its ID and name are printed when it joins.
|
||
O->>C: joins by the link
|
||
C->>K: joinedGroupMember
|
||
K->>C: apiDeleteGroupLink #G
|
||
K->>P: Alice joined (member 3). Restart the server with --owners 3:Alice
|
||
K->>O: Alice joined (member 3). Restart the server with `--owners 3:Alice`
|
||
P->>K: Ctrl-C, then serve my-agent --owners 3:Alice
|
||
K->>C: apiSetMembersRole #G [3] owner
|
||
K->>C: apiRemoveMembers #G [ID], for each other human
|
||
K->>C: apiDeleteGroupLink #G
|
||
K->>P: Owners: 3:Alice.
|
||
K->>P: Add the agent to Claude Code: ...
|
||
O->>C: adds Bob, makes Bob an owner
|
||
C->>K: memberRole
|
||
K->>P: Bob (member 7) is now an owner and can't approve actions yet. Restart ... --owners 3:Alice,7:Bob
|
||
K->>O: same line, the --owners part as code
|
||
B->>K: /approve N
|
||
K->>B: Only the owners listed in --owners approve actions.
|
||
```
|
||
|
||
Notes:
|
||
|
||
- Until the restart with a list, new actions are refused: `The agent has no approving owner. ...` ([control.ts:125-127](../src/control.ts#L125-L127)).
|
||
- An entry must match a human by member ID and display name, folded to one line as the restart line prints it, or the server exits with code 2 ([control.ts:354-358](../src/control.ts#L354-L358), [:758-760](../src/control.ts#L758-L760)).
|
||
- With `--reset-owners`, the server deletes the control chat for all members and creates a new one with the same counter; the CLI refuses the option with an `--owners` list ([control.ts:522-527](../src/control.ts#L522-L527), [serve.ts:222](../src/serve.ts#L222), [cli.ts:104-106](../src/cli.ts#L104-L106)).
|
||
- When a listed owner leaves and none remains: `... is no longer an owner. No owners remain: restart the server with --reset-owners --owners` ([control.ts:393-398](../src/control.ts#L393-L398)).
|
||
|
||
Source: [control.ts:347-369](../src/control.ts#L347-L369), [:380-399](../src/control.ts#L380-L399), [:406-416](../src/control.ts#L406-L416), [:758-784](../src/control.ts#L758-L784).
|
||
|
||
---
|
||
|
||
## 13. `download` with approval
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as Agent
|
||
participant T as AgentTools
|
||
participant X as Actions
|
||
participant K as Control
|
||
participant C as Core
|
||
participant O as Owner
|
||
A->>T: download {chat: #15, item: 30}
|
||
T->>X: find(key): none
|
||
T->>C: apiGetChat #15 count 0
|
||
T->>C: apiGetChat #15 around 30 count 0
|
||
T->>C: apiGetChatItemInfo #15 30: fileXftpServers
|
||
opt no servers yet
|
||
T-->>A: progress: The sender is uploading the file of item 30 in #15, waiting until TIME.
|
||
C->>T: rcvFileDescrReady
|
||
T->>C: apiGetChatItemInfo #15 30
|
||
end
|
||
T->>C: apiGetUserServers USER: no unknown servers
|
||
T->>C: apiGetChat #15 count 0
|
||
T->>K: standingApprover(chatInfo, files): none
|
||
T->>X: create(key, download fields)
|
||
K->>O: I want to download a file from Switchback in group Trail (#15): `report.pdf`, 2.4 MB, Servers: known. /'receive #15 N', /'receive #15 N all', /'forward #15 N' or /'reject #15 N'
|
||
O->>C: /receive #15 N
|
||
K->>X: approve(action, "Alice")
|
||
X->>T: performDownload: downloadFile
|
||
T->>C: apiGetChat #15 around 30 count 0
|
||
T->>C: apiReceiveFile 7 DATA/files/group-15/7.pdf
|
||
C->>T: rcvFileComplete
|
||
T->>T: a file at the download path: resolved
|
||
X->>K: outcome
|
||
K->>O: card edited: I downloaded a file from ... Approved by Alice.
|
||
T-->>A: {action: N, status: done, chat: #15, item: 30, path}
|
||
```
|
||
|
||
Notes:
|
||
|
||
- A check every 60 s reads the item: a deleted message or chat fails the download; 30 minutes without a rise of `rcvProgress` fail and cancel it ([tools.ts:1035-1062](../src/tools.ts#L1035-L1062)).
|
||
- A download still running `wait` seconds after the perform starts returns `status: performing`; the same call again attaches to the action ([tools.ts:1008-1011](../src/tools.ts#L1008-L1011)).
|
||
- `/approve #15 N` on a download card gets the reply `Action N is a download: ...` with the card's command line ([control.ts:234](../src/control.ts#L234)).
|
||
- A file on unknown servers gets a card that names their hosts and leaves out `/'receive CHAT N all'` ([control.ts:594-599](../src/control.ts#L594-L599), [:611-614](../src/control.ts#L611-L614), [:664-668](../src/control.ts#L664-L668)). Only such a card approves the relays; the core checks the complete description of every other download, which fails at the acceptance, or at the next check when the description completes later ([tools.ts:545](../src/tools.ts#L545), [:1043](../src/tools.ts#L1043)).
|
||
- The card of an image or video shows the sender's preview ([control.ts:441-461](../src/control.ts#L441-L461)).
|
||
- A file the core receives without a request, a short voice message, also in a member chat of a group, is moved into the chat's folder at `rcvFileComplete`; one whose transfer started before a restart, only when it has its full size. Its message then shows it as `offered`, and `download` returns its path after the approval ([tools.ts:551-571](../src/tools.ts#L551-L571), [:1082-1091](../src/tools.ts#L1082-L1091), [messages.ts:194-208](../src/messages.ts#L194-L208)).
|
||
|
||
Source: [tools.ts:960-1103](../src/tools.ts#L960-L1103), [control.ts:573-616](../src/control.ts#L573-L616), [serve.ts:139-155](../src/serve.ts#L139-L155).
|
||
|
||
---
|
||
|
||
## 14. `/forward`
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as Agent
|
||
participant T as AgentTools
|
||
participant K as Control
|
||
participant C as Core
|
||
participant O as Owner
|
||
O->>C: /forward #15 N (on a pending download card)
|
||
C->>K: newChatItems
|
||
K->>T: forwardFile(action N)
|
||
T->>C: apiReceiveFile 7 DATA/forwarded/group-15/7.pdf
|
||
C->>T: rcvFileComplete: resolved with the forwarded path
|
||
T->>T: copy for the post: DATA/files/sent/send-XXXXXX/report.pdf
|
||
K->>C: apiSendMessages #G [{fileSource: the copy, msgContent: file, quotedItemId: card N when the message fits}]
|
||
C->>T: sndFileCompleteXFTP: the copy's folder deleted
|
||
Note over K,O: the card stays pending; the agent's message shows the file as offered
|
||
O->>C: /receive #15 N
|
||
K->>T: performDownload: downloadFile
|
||
T->>T: the forwarded file moved to DATA/files/group-15/7.pdf
|
||
T-->>A: {action: N, status: done, chat: #15, item: 30, path}
|
||
```
|
||
|
||
Notes:
|
||
|
||
- `/forward` gets no reply; a download or post that fails is posted as ``Action N: the file was not received: `ERROR`.``, and a failed post deletes the copy ([control.ts:265-281](../src/control.ts#L265-L281)).
|
||
- The copy is named by the name the sender gave ([tools.ts:898-902](../src/tools.ts#L898-L902)).
|
||
- The post keeps the sender's preview of an image or video; it replies to the card when the message, with the card as its quote, is within 15602 bytes by the length rule of `send` ([control.ts:265-281](../src/control.ts#L265-L281), [tools.ts:1433-1449](../src/tools.ts#L1433-L1449)).
|
||
- The download is shared with the agent's: one download per file ID; the move to the download path waits for the copy of the post ([tools.ts:522-549](../src/tools.ts#L522-L549)).
|
||
- The forwarded path is outside `DATA/files/`, so `send` refuses the file there; it is deleted when the agent leaves the chat, and by `/delete CHAT files` ([tools.ts:871-876](../src/tools.ts#L871-L876), [:909-927](../src/tools.ts#L909-L927), [:950-958](../src/tools.ts#L950-L958)).
|
||
|
||
Source: [control.ts:221-239](../src/control.ts#L221-L239), [:265-281](../src/control.ts#L265-L281), [tools.ts:522-539](../src/tools.ts#L522-L539), [:848-858](../src/tools.ts#L848-L858), [:898-902](../src/tools.ts#L898-L902).
|
||
|
||
---
|
||
|
||
## 15. `send` with a file
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as Agent
|
||
participant T as AgentTools
|
||
participant X as Actions
|
||
participant K as Control
|
||
participant C as Core
|
||
participant O as Owner
|
||
A->>T: send {chat: #15, text: "trail map", file: "/home/alice/trail.jpg"}
|
||
T->>C: apiGetChat #15 count 0
|
||
T->>T: real path, size, inode, change time
|
||
T->>T: refused paths checked
|
||
T->>T: preview: core.resizeImage(file, MessagePreview)
|
||
T->>T: message length checked
|
||
T->>X: create(key, send fields with the file)
|
||
K->>O: image card with the preview: I want to send a message to group Trail: `trail map`, attaching image `/home/alice/trail.jpg`, SIZE /'approve #15 N', ...
|
||
O->>C: /approve #15 N
|
||
X->>T: performSend
|
||
T->>T: the file again: same real path, size, inode, change time
|
||
T->>T: core.resizeImage(file, Image): DATA/files/sent/send-XXXXXX/trail.jpg
|
||
T->>C: apiSendMessages #15 [{fileSource: the copy, msgContent: image with the preview}]
|
||
C->>T: sndFileCompleteXFTP: the copy's folder deleted
|
||
```
|
||
|
||
Notes:
|
||
|
||
- A refused file ends the call with an error, and the refusal is posted to the control chat and logged ([tools.ts:862-865](../src/tools.ts#L862-L865), [control.ts:154-158](../src/control.ts#L154-L158)).
|
||
- A video's preview is the first frame from `ffmpeg` and its duration comes from `ffprobe`; a GIF or WebP gets the fixed preview ([tools.ts:1512-1546](../src/tools.ts#L1512-L1546)).
|
||
- A changed file fails the perform: ``file: PATH changed after the request.`` ([tools.ts:878-883](../src/tools.ts#L878-L883)).
|
||
- `sndFileError` deletes the copy too, and the failure is posted to the control chat and logged ([serve.ts:158-160](../src/serve.ts#L158-L160), [control.ts:160-169](../src/control.ts#L160-L169)).
|
||
|
||
Source: [tools.ts:774-800](../src/tools.ts#L774-L800), [:822-896](../src/tools.ts#L822-L896), [control.ts:441-461](../src/control.ts#L441-L461), [:583-589](../src/control.ts#L583-L589).
|
||
|
||
---
|
||
|
||
## 16. `/leave` and `/delete CHAT files`
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant P as Person
|
||
participant T as AgentTools
|
||
participant X as Actions
|
||
participant K as Control
|
||
participant C as Core
|
||
participant O as Owner
|
||
participant D as Peer
|
||
O->>C: /leave #9
|
||
K->>T: knownChat #9
|
||
K->>T: leaveChat #9
|
||
T->>C: apiLeaveGroup #9, apiDeleteChat #9 full, notify
|
||
C->>D: the agent left the group
|
||
T->>T: DATA/forwarded/group-9 deleted
|
||
K->>P: Left business Ridgeline (#9), requested by Alice.
|
||
K->>X: reject each pending action of #9 with a card
|
||
K->>O: Left business Ridgeline (#9), requested by Alice.
|
||
K->>O: Files from business Ridgeline (#9) are kept in `DATA/files/group-9`: 3 files, 2.1 MB. /'delete #9 files'
|
||
O->>C: /delete #9 files
|
||
K->>T: deleteChatFiles #9
|
||
T->>T: each download of #9: failed, apiCancelFile, its partial file deleted
|
||
T->>C: apiGetChat #9 count 100, then before the first item, while a page has 100
|
||
T->>C: apiCancelFile for each other file in rcvAccepted, rcvTransfer or rcvWarning
|
||
T->>T: DATA/files/group-9 and DATA/forwarded/group-9 deleted
|
||
K->>O: Deleted 3 files from #9, 2.1 MB.
|
||
```
|
||
|
||
Notes:
|
||
|
||
- `/leave` acts at once in both modes, and works for a contact as `Deleted bot X (@4), requested by Alice.` ([control.ts:283-297](../src/control.ts#L283-L297)).
|
||
- The line `Left ...` goes to the log and to the owners; the members of #9 see only that the agent left.
|
||
- The files message is posted after the reply, and only when the folder has files ([control.ts:294-295](../src/control.ts#L294-L295), [:309-311](../src/control.ts#L309-L311)).
|
||
- `/delete CHAT files` works for a current or a left chat; the failed downloads return `Your owner deleted the files of this chat.`, and the reply counts the forwarded files too ([tools.ts:909-927](../src/tools.ts#L909-L927)).
|
||
- The paged reads find the downloads the core continues after a restart, which have no download in memory; for a left chat they find none ([messages.ts:271-279](../src/messages.ts#L271-L279), [tools.ts:916-922](../src/tools.ts#L916-L922)).
|
||
|
||
Source: [control.ts:283-307](../src/control.ts#L283-L307), [tools.ts:904-927](../src/tools.ts#L904-L927), [:950-958](../src/tools.ts#L950-L958).
|