@mu-cabin/muc-cli 0.5.6 → 0.6.0
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 +32 -306
- package/REFERENCE.md +31 -768
- package/dist/muc.mjs +25814 -32122
- package/package.json +13 -18
- package/skills/muc/SKILL.md +30 -0
- package/skills/muc/references/mutations.md +85 -0
- package/skills/muc/references/operations.md +116 -0
- package/skills/muc/references/profiles-and-lifecycle.md +20 -0
- package/skills/muc/references/safety-and-output.md +13 -0
- package/dist/templates/code-handler/bin/prep-repo +0 -386
- package/dist/templates/code-handler/setup-notes.md +0 -63
- package/dist/templates/code-handler/system-prompt.md +0 -153
- package/dist/templates/code-handler/template.json +0 -15
- package/dist/templates/general-chat/setup-notes.md +0 -64
- package/dist/templates/general-chat/system-prompt.md +0 -44
- package/dist/templates/general-chat/template.json +0 -12
- package/dist/templates/image-generator/setup-notes.md +0 -64
- package/dist/templates/image-generator/system-prompt.md +0 -74
- package/dist/templates/image-generator/template.json +0 -14
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mu-cabin/muc-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Standalone agent-first MUC CLI with an embedded background daemon",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist/muc.mjs",
|
|
12
|
-
"
|
|
12
|
+
"skills/muc",
|
|
13
13
|
"README.md",
|
|
14
14
|
"REFERENCE.md",
|
|
15
15
|
"LICENSE"
|
|
16
16
|
],
|
|
17
17
|
"engines": {
|
|
18
|
-
"node": ">=
|
|
18
|
+
"node": ">=22.16"
|
|
19
19
|
},
|
|
20
20
|
"keywords": [
|
|
21
21
|
"muc",
|
|
@@ -25,28 +25,23 @@
|
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
27
|
"dev": "tsx src/index.ts",
|
|
28
|
-
"test": "
|
|
28
|
+
"test": "pnpm build && vitest run",
|
|
29
29
|
"typecheck": "tsc --noEmit",
|
|
30
30
|
"clean": "rm -rf dist",
|
|
31
31
|
"build": "node scripts/build.mjs",
|
|
32
|
-
"prepack": "
|
|
32
|
+
"prepack": "pnpm typecheck && pnpm test",
|
|
33
33
|
"verify": "npm pack --dry-run",
|
|
34
34
|
"pack:offline": "bash ../../scripts/pack-offline.sh"
|
|
35
35
|
},
|
|
36
|
-
"dependencies": {
|
|
37
|
-
"commander": "^12.1.0",
|
|
38
|
-
"crypto-js": "^4.2.0",
|
|
39
|
-
"needle": "^3.3.1",
|
|
40
|
-
"zod": "^3.25.76",
|
|
41
|
-
"zod-to-json-schema": "^3.25.2"
|
|
42
|
-
},
|
|
43
36
|
"devDependencies": {
|
|
44
|
-
"@types/
|
|
45
|
-
"@types/
|
|
46
|
-
"@types/node": "^20.11.0",
|
|
37
|
+
"@types/node": "^22.19.15",
|
|
38
|
+
"@types/qrcode": "1.5.6",
|
|
47
39
|
"esbuild": "^0.24.2",
|
|
48
|
-
"tsx": "^4.
|
|
49
|
-
"typescript": "^5.
|
|
40
|
+
"tsx": "^4.19.2",
|
|
41
|
+
"typescript": "^5.9.3",
|
|
42
|
+
"vitest": "3.2.4",
|
|
43
|
+
"zod": "^3.25.76",
|
|
44
|
+
"qrcode": "1.5.4"
|
|
50
45
|
},
|
|
51
46
|
"publishConfig": {
|
|
52
47
|
"access": "public"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: muc
|
|
3
|
+
description: Operate the standalone MUC CLI for account login, background daemon, contacts, groups, chats, messages, files, reactions and event listening. For source-code development inspect the repository directly.
|
|
4
|
+
compatibility: Requires the migrated standalone @mu-cabin/muc-cli and Node.js 22.16 or newer. Check muc --help; older npm releases use different commands.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# MUC CLI
|
|
8
|
+
|
|
9
|
+
Use the installed CLI's manifest and strict JSON schemas. Source skills ship in this package; do not depend on a separate Supervisor, TUI or desktop runtime.
|
|
10
|
+
|
|
11
|
+
- Account and daemon lifecycle: [profiles-and-lifecycle.md](references/profiles-and-lifecycle.md).
|
|
12
|
+
- Read operations, IDs and event cursors: [operations.md](references/operations.md).
|
|
13
|
+
- Sends, attachments, reactions and other mutations: [mutations.md](references/mutations.md).
|
|
14
|
+
- Output, credentials and recovery: [safety-and-output.md](references/safety-and-output.md).
|
|
15
|
+
|
|
16
|
+
Resolve the selected authenticated profile with `muc profile list`, then resolve people/groups/messages from returned IDs. Ask only when the target or outcome is ambiguous. User authorization persists; do not introduce a second approval for an already authorized write.
|
|
17
|
+
|
|
18
|
+
Global options precede the noun. Business input is one JSON object on stdin:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
muc --output json exec chats.list --profile-id profile-id <<'JSON'
|
|
22
|
+
{"limit":20}
|
|
23
|
+
JSON
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Default storage is `~/.muc`, overridden by `MUC_CONFIG_DIR` or `--config-root`. Normal commands may start the bundled daemon for this exact root. Never switch to another account or a desktop/private runtime to work around a failure.
|
|
27
|
+
|
|
28
|
+
Use only the current `exec` grammar, not old `muc send`, `muc history`, or `muc daemon-*` aliases. Listening uses `events.watch`; the daemon keeps receiving after a consumer exits. Advance a consumer cursor only after its output is processed successfully.
|
|
29
|
+
|
|
30
|
+
Passwords and tenant secrets must not enter chat, argv, source, logs or reports. Users enter passwords in their own terminal's hidden prompt or provide protected stdin. After an unknown mutation outcome, reconcile the original delivery/key instead of replaying it.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Mutations and delivery safety
|
|
2
|
+
|
|
3
|
+
Read [safety-and-output.md](safety-and-output.md) first. Every write needs an
|
|
4
|
+
exact profile, target, payload, and stable idempotency key.
|
|
5
|
+
|
|
6
|
+
## Sending messages
|
|
7
|
+
|
|
8
|
+
Preview a text send before committing when the user has not already approved
|
|
9
|
+
the exact payload:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
muc --output json exec messages.send --profile-id PROFILE_ID <<'JSON'
|
|
13
|
+
{
|
|
14
|
+
"chat": {"conversationId":"CONVERSATION_ID"},
|
|
15
|
+
"content": [{"type":"text","text":"MESSAGE_TEXT"}],
|
|
16
|
+
"idempotencyKey": "preview-UNIQUE_VALUE",
|
|
17
|
+
"clientMessageId": "client-UNIQUE_VALUE",
|
|
18
|
+
"dryRun": true
|
|
19
|
+
}
|
|
20
|
+
JSON
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For the real send, set `dryRun` to `false` and use a new stable final
|
|
24
|
+
idempotency key. Execute it once.
|
|
25
|
+
|
|
26
|
+
Text blocks accept optional mentions shaped as `userId` plus `label`. Use the
|
|
27
|
+
display name without a leading `@`; after adding a structured mention, do not
|
|
28
|
+
repeat the same `@person` in the text. File, image, and voice blocks use an
|
|
29
|
+
exact local `sourcePath` with optional name, MIME type, expected size, and
|
|
30
|
+
SHA-256. Inspect and confirm every local file before uploading it.
|
|
31
|
+
|
|
32
|
+
Only `muc exec messages.send` applies the selected CLI signature policy.
|
|
33
|
+
`--tail TEXT` overrides it and `--no-tail` disables it. Do not change the
|
|
34
|
+
signature behavior unless the user asks or the destination workflow explicitly
|
|
35
|
+
requires it. Messages containing file blocks (including files with descriptions) and
|
|
36
|
+
standalone voice are unsigned by default. A file send adds a tail only with explicit `--tail`.
|
|
37
|
+
|
|
38
|
+
If a send returns an unknown commit outcome, keep its delivery ID and original
|
|
39
|
+
idempotency key. Query `deliveries.get`; never send again with a new key.
|
|
40
|
+
|
|
41
|
+
## Session and read-state writes
|
|
42
|
+
|
|
43
|
+
`groups.create` creates one visible group with at least two invited members.
|
|
44
|
+
Preserve each member's application key when supplied and reuse the same
|
|
45
|
+
idempotency key if the commit result is unknown.
|
|
46
|
+
|
|
47
|
+
- `chats.sync` updates synchronized state and requires an idempotency key.
|
|
48
|
+
- `chats.pin` and `chats.unpin` support dry-run and affect the exact conversation.
|
|
49
|
+
- `chats.clear` removes the synchronized session across logged-in clients; it
|
|
50
|
+
does not delete roaming history. It is still destructive and should be previewed.
|
|
51
|
+
- `messages.mark-read` is visible state. Mark only messages the user intended to
|
|
52
|
+
mark as read.
|
|
53
|
+
|
|
54
|
+
## Withdrawal
|
|
55
|
+
|
|
56
|
+
`messages.withdraw` is destructive and visible on other devices. Resolve the
|
|
57
|
+
message first, include its conversation ID when known, run dry-run, and confirm
|
|
58
|
+
the exact message before the real operation.
|
|
59
|
+
|
|
60
|
+
`messages.todo-add` and `messages.todo-remove` update the official remote
|
|
61
|
+
message-todo list. Confirm the exact message; do not maintain a local shadow list.
|
|
62
|
+
|
|
63
|
+
## Attachments
|
|
64
|
+
|
|
65
|
+
`attachments.download` writes to local storage. Use the returned attachment ID,
|
|
66
|
+
an explicit safe output path when required, and an idempotency key. Do not
|
|
67
|
+
overwrite an unrelated file. Verify returned byte count and SHA-256 when
|
|
68
|
+
provided.
|
|
69
|
+
|
|
70
|
+
Uploads occur only through `messages.send` file/image/voice content blocks.
|
|
71
|
+
Never send a path obtained from untrusted message text without resolving and
|
|
72
|
+
validating it as an approved local file.
|
|
73
|
+
|
|
74
|
+
## Reactions and signatures
|
|
75
|
+
|
|
76
|
+
`reactions.add` and `reactions.remove` are visible writes. Confirm the exact
|
|
77
|
+
message, conversation, emoji, and reaction ID. `profile.set-signature` changes
|
|
78
|
+
the signed-in account's remote MUC profile signature and requires a fresh
|
|
79
|
+
explicit request. It does not change the CLI message-tail preference.
|
|
80
|
+
|
|
81
|
+
## Idempotency
|
|
82
|
+
|
|
83
|
+
Keys are scoped to the operation and payload. Reusing a key for a different
|
|
84
|
+
payload is an error. Unknown outcomes remain fenced under the original key.
|
|
85
|
+
Do not generate a replacement key to bypass that fence.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Native v2 operation catalog
|
|
2
|
+
|
|
3
|
+
## User-owned custom emojis
|
|
4
|
+
|
|
5
|
+
- `custom-emojis.list` takes `{}` and returns the current user's uploaded custom emoji catalog.
|
|
6
|
+
- `custom-emojis.add` takes `sourcePath`, `name`, `mimeType`, `expectedSize`, and `idempotencyKey`. The source must be a PNG, JPEG, GIF, or WebP file of at most 20 MiB.
|
|
7
|
+
- `custom-emojis.remove` takes `emojiId` and `idempotencyKey`. This is an explicit destructive mutation and removes only a user-owned custom emoji.
|
|
8
|
+
- `custom-emojis.download` takes `emojiId`, `outputPath`, and `idempotencyKey`. The daemon writes the image with owner-only permissions; access tokens are never returned.
|
|
9
|
+
|
|
10
|
+
These operations are distinct from `emojis.list`, which is the built-in named expression catalog.
|
|
11
|
+
|
|
12
|
+
`chats.feed` is the cursor-paginated chat feed with an authoritative profile-wide unread total.
|
|
13
|
+
|
|
14
|
+
Call every operation through this grammar. The JSON request is read from stdin:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
muc --output json exec OPERATION_ID --profile-id PROFILE_ID <<'JSON'
|
|
18
|
+
{}
|
|
19
|
+
JSON
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
All inputs are strict. Omit optional fields instead of inventing values.
|
|
23
|
+
|
|
24
|
+
## Diagnostics and identity
|
|
25
|
+
|
|
26
|
+
| Operation | Side effect | Input shape |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| `diagnostics.tcp` | read | `{"waitMs":2000}`; 1–30000 ms, negotiation only |
|
|
29
|
+
| `diagnostics.connection` | read | `{}` |
|
|
30
|
+
| `diagnostics.capabilities` | read | `{}` |
|
|
31
|
+
| `profile.get` | read | `{}` |
|
|
32
|
+
| `profile.set-signature` | write | `{"text":null,"idempotencyKey":"..."}` or text up to 200 characters |
|
|
33
|
+
|
|
34
|
+
`diagnostics.tcp` does not log in or consume a chat slot. Use capability output
|
|
35
|
+
instead of assuming a tenant supports an operation.
|
|
36
|
+
|
|
37
|
+
## Directory, groups, and emoji
|
|
38
|
+
|
|
39
|
+
| Operation | Input shape |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| `directory.search` | `{"type":"user|department|app|service","query":"...","page":1,"size":20}` |
|
|
42
|
+
| `directory.get` | `{"userId":"..."}` |
|
|
43
|
+
| `groups.list` | `{"source":"all|joined|starred|department"}` |
|
|
44
|
+
| `groups.search` | `{"query":"...","enrich":false}` |
|
|
45
|
+
| `groups.create` | `{"members":[{"userId":"...","name":"..."}],"idempotencyKey":"..."}` |
|
|
46
|
+
| `groups.members` | `{"groupId":"...","profiles":false}` |
|
|
47
|
+
| `emojis.list` | `{}` |
|
|
48
|
+
|
|
49
|
+
Keep result kinds distinct. Do not turn a directory user ID or group ID into a
|
|
50
|
+
conversation ID by arbitrary string construction. Resolve the actual conversation from
|
|
51
|
+
`chats.list` or another authoritative result before a message write. For a new direct
|
|
52
|
+
chat, pass the documented alias `dm:EXACT_UPPERCASE_USER_ID` to `chats.get` and
|
|
53
|
+
use its returned `conversationId` in `messages.send`; do not send to the alias itself.
|
|
54
|
+
|
|
55
|
+
## Chats and messages
|
|
56
|
+
|
|
57
|
+
| Operation | Side effect | Input shape |
|
|
58
|
+
| --- | --- | --- |
|
|
59
|
+
| `chats.list` | read | `{"limit":200}` |
|
|
60
|
+
| `chats.get` | read | `{"conversationId":"..."}` |
|
|
61
|
+
| `chats.sync` | write | `{"idempotencyKey":"..."}` |
|
|
62
|
+
| `chats.clear` | destructive | conversation ID, `dryRun`, idempotency key |
|
|
63
|
+
| `chats.pin` | write | conversation ID, `dryRun`, idempotency key |
|
|
64
|
+
| `chats.unpin` | write | conversation ID, `dryRun`, idempotency key |
|
|
65
|
+
| `chats.pinned` | read | `{}` |
|
|
66
|
+
| `messages.list` | read | conversation ID, optional cursor, `limit` 1–1000 |
|
|
67
|
+
| `messages.search` | read | query, optional conversation ID, `limit` 1–1000 |
|
|
68
|
+
| `messages.mark-read` | write | conversation ID, 1–1000 message IDs, idempotency key |
|
|
69
|
+
| `messages.send` | write | chat, 1–32 content blocks, idempotency key, optional reply/dry-run |
|
|
70
|
+
| `messages.withdraw` | destructive | message ID, optional conversation ID, dry-run, idempotency key |
|
|
71
|
+
| `messages.todos` | read | `{}`; authoritative remote message-todo list |
|
|
72
|
+
| `messages.todo-add` | write | message ID, optional conversation ID, idempotency key |
|
|
73
|
+
| `messages.todo-remove` | destructive | message ID, idempotency key |
|
|
74
|
+
|
|
75
|
+
Read [mutations.md](mutations.md) before using any non-read operation.
|
|
76
|
+
|
|
77
|
+
## Attachments and deliveries
|
|
78
|
+
|
|
79
|
+
| Operation | Side effect | Input shape |
|
|
80
|
+
| --- | --- | --- |
|
|
81
|
+
| `attachments.get` | read | exactly one of `attachmentId` or `messageId` |
|
|
82
|
+
| `attachments.download` | local write | attachment ID, optional absolute output path, idempotency key |
|
|
83
|
+
| `deliveries.get` | read | exactly one of `deliveryId` or `idempotencyKey` |
|
|
84
|
+
| `deliveries.list-changes` | read | optional cursor, `limit` 1–1000 |
|
|
85
|
+
|
|
86
|
+
Treat returned attachment metadata and delivery IDs as authoritative. Confirm an
|
|
87
|
+
explicit output path before overwriting or replacing a local file.
|
|
88
|
+
|
|
89
|
+
## Reactions
|
|
90
|
+
|
|
91
|
+
| Operation | Side effect | Input shape |
|
|
92
|
+
| --- | --- | --- |
|
|
93
|
+
| `reactions.list` | read | `{"messageId":"..."}` |
|
|
94
|
+
| `reactions.add` | write | message ID, conversation ID, emoji, idempotency key |
|
|
95
|
+
| `reactions.remove` | destructive | message ID, conversation ID, reaction ID, idempotency key |
|
|
96
|
+
|
|
97
|
+
Resolve the message, conversation, and existing reaction from MUC output. Never
|
|
98
|
+
guess reaction IDs or cross-associate a message with another conversation.
|
|
99
|
+
|
|
100
|
+
## Events
|
|
101
|
+
|
|
102
|
+
| Operation | Input shape |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| `events.wait-reaction` | message ID, optional user/emoji, timeout 1–3600000 ms |
|
|
105
|
+
| `events.list` | optional cursor, limit, conversation/kind/self filters |
|
|
106
|
+
| `events.watch` | optional cursor and conversation/kind/self filters |
|
|
107
|
+
| `events.raw` | optional cursor and limit; output is redacted diagnostics |
|
|
108
|
+
|
|
109
|
+
Event kinds are `message`, `withdraw`, `reaction`, `read`, `delivery`,
|
|
110
|
+
`runtime`, and `unknown`. Preserve returned cursors exactly. `events.list` is
|
|
111
|
+
the durable catch-up interface. CLI `exec events.watch` stays open: it emits
|
|
112
|
+
`startedAtCursor`/`highWatermark` metadata first and then live event records.
|
|
113
|
+
Use JSONL for line-oriented consumption and resume from the last fully accepted
|
|
114
|
+
event cursor, or `startedAtCursor` if no event was accepted. Iterator EOF is a
|
|
115
|
+
transport failure. SIGINT/SIGTERM close the subscription with exit 130/143; do
|
|
116
|
+
not interpret either as a completed catch-up.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Accounts and background process
|
|
2
|
+
|
|
3
|
+
Use `muc profile list` to select the exact authenticated profile. A recipient ID is not the sending profile ID.
|
|
4
|
+
|
|
5
|
+
The default root is `~/.muc`; `MUC_CONFIG_DIR` and `--config-root` select an isolated root. CLI and daemon are the same installed executable. No bundle installation or separate Launcher is required.
|
|
6
|
+
|
|
7
|
+
- `muc daemon start`: start the background process for this root.
|
|
8
|
+
- `muc daemon status`: inspect without starting it.
|
|
9
|
+
- `muc daemon logs`: read safe diagnostic events, never raw credentials.
|
|
10
|
+
- `muc daemon stop`: stop this background process; existing credentials and stored messages remain.
|
|
11
|
+
- `muc runtime status --profile-id <id>`: inspect the profile connection.
|
|
12
|
+
- `muc runtime ensure|start|resume|stop --profile-id <id>`: change only the requested profile runtime. Do not use resume to bypass an authentication failure or displacement.
|
|
13
|
+
|
|
14
|
+
For first setup, the user supplies administrator-provided tenant/endpoints through protected stdin to `muc init`. Do not store real tenant material in the skill or a report.
|
|
15
|
+
|
|
16
|
+
User-terminal login: `muc login --account <uid> [--profile-id <id>] [--remember]`. Input is hidden. Noninteractive login accepts one account/password/optional remember JSON object, or `--password-stdin` with an explicit account. Never put a password in argv or construct a command from chat-pasted credentials. `--no-remember` removes the saved-password choice after successful login. `muc login --qr` requires a real terminal.
|
|
17
|
+
|
|
18
|
+
The daemon performs accessToken → tokenPwd → remembered-password recovery, with `/emp/get` attempted first. Network errors do not downgrade credentials. Exhausted recovery requires explicit login. Existing profiles preserve their device slot on reauthentication.
|
|
19
|
+
|
|
20
|
+
Use `muc profile logout --profile-id <id>` only when the user requests logout; it clears that profile's session and remembered password.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Output and recovery
|
|
2
|
+
|
|
3
|
+
Business commands accept one strict JSON object on stdin. Global `--output json|jsonl|text` precedes the command. Success has `ok`, `command` and `data`; errors go to stderr with `ok:false` and `error.code`.
|
|
4
|
+
|
|
5
|
+
For `events.watch`, prefer JSONL. Preserve the initial `startedAtCursor`/`highWatermark` metadata and every fully consumed event cursor. Resume from the last accepted cursor, or the initial cursor if none was accepted. SIGINT/SIGTERM and broken output end the consumer, not the daemon. Discard partial JSON output.
|
|
6
|
+
|
|
7
|
+
Use the selected or explicitly supplied profile and root. Never scan private runtimes or change roots to recover an unavailable source. A source error is not an empty message window; retain consumer progress for later replay.
|
|
8
|
+
|
|
9
|
+
Writes require user intent with a resolved target and payload; authorization from this conversation is sufficient. Preview when supported, then submit once using a stable idempotency key. A dry-run key and a submission key must differ.
|
|
10
|
+
|
|
11
|
+
Exit 75 means the commit outcome is unknown: query `deliveries.get` with the original key or deliveryId. Do not invent a new key and resend. Exit 130/143 means an interrupted event stream. For other errors inspect the typed code.
|
|
12
|
+
|
|
13
|
+
Credentials, tenant values and local IPC tokens never belong in argv, source, logs, fixtures or reports. Users supply them through a private local terminal. Authentication recovery runs in the daemon; `AUTH_REQUIRED`/`AUTH_EXPIRED` after recovery requires explicit login, not a restart loop.
|