omnish 1.6.6 → 2.0.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +26 -18
  3. package/config.example.json +1 -0
  4. package/dist/downloads/omnish-claude/install.sh +174 -0
  5. package/dist/downloads/omnish-claude/uninstall.sh +114 -0
  6. package/dist/downloads/omnish-claude.tar.gz +0 -0
  7. package/dist/downloads/omnish-cursor/install.sh +162 -0
  8. package/dist/downloads/omnish-cursor/uninstall.sh +107 -0
  9. package/dist/downloads/omnish-cursor.tar.gz +0 -0
  10. package/dist/index.js +424 -392
  11. package/dist/omnish-claude/README.md +80 -0
  12. package/dist/omnish-claude/hooks/omnish-notify.py +213 -0
  13. package/dist/omnish-claude/hooks/omnish-notify.sh +13 -0
  14. package/dist/omnish-claude/install.sh +174 -0
  15. package/dist/omnish-claude/omnish-notify.json.example +8 -0
  16. package/dist/omnish-claude/scripts/doctor.sh +99 -0
  17. package/dist/omnish-claude/skill/SKILL.md +39 -0
  18. package/dist/omnish-claude/skill/files-and-sharing.md +94 -0
  19. package/dist/omnish-claude/skill/notifications.md +113 -0
  20. package/dist/omnish-claude/skill/setup-paths.md +81 -0
  21. package/dist/omnish-claude/uninstall.sh +114 -0
  22. package/dist/omnish-cursor/README.md +176 -0
  23. package/dist/omnish-cursor/hooks/__pycache__/omnish-notify.cpython-313.pyc +0 -0
  24. package/dist/omnish-cursor/hooks/omnish-notify.py +563 -0
  25. package/dist/omnish-cursor/hooks/omnish-notify.sh +13 -0
  26. package/dist/omnish-cursor/hooks/omnish-session-start.sh +48 -0
  27. package/dist/omnish-cursor/install.sh +162 -0
  28. package/dist/omnish-cursor/omnish-notify.json.example +13 -0
  29. package/dist/omnish-cursor/rules/omnish-notify.mdc +45 -0
  30. package/dist/omnish-cursor/scripts/doctor.sh +126 -0
  31. package/dist/omnish-cursor/skill/SKILL.md +129 -0
  32. package/dist/omnish-cursor/skill/files-and-sharing.md +94 -0
  33. package/dist/omnish-cursor/skill/notifications.md +155 -0
  34. package/dist/omnish-cursor/skill/setup-paths.md +81 -0
  35. package/dist/omnish-cursor/uninstall.sh +107 -0
  36. package/dist/ui/assets/{index-aUJGrxrr.js → index-BwG51a2I.js} +10 -10
  37. package/dist/ui/index.html +16 -1
  38. package/package.json +12 -4
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env bash
2
+ # Install Omnish Cursor bundle: hooks + skill + rule into ~/.cursor
3
+ set -euo pipefail
4
+
5
+ OMNISH_CURSOR_BUNDLE_URL="${OMNISH_CURSOR_BUNDLE_URL:-https://omnish.dev/downloads/omnish-cursor.tar.gz}"
6
+ _TMP_BUNDLE_DIR=""
7
+
8
+ need() {
9
+ command -v "$1" >/dev/null 2>&1 || {
10
+ echo "error: required command not found: $1" >&2
11
+ exit 1
12
+ }
13
+ }
14
+
15
+ cleanup() {
16
+ if [[ -n "$_TMP_BUNDLE_DIR" && -d "$_TMP_BUNDLE_DIR" ]]; then
17
+ rm -rf "$_TMP_BUNDLE_DIR"
18
+ fi
19
+ }
20
+
21
+ _SCRIPT="${BASH_SOURCE[0]:-}"
22
+ if [[ -n "$_SCRIPT" && -f "$_SCRIPT" ]]; then
23
+ ROOT="$(cd "$(dirname "$_SCRIPT")" && pwd)"
24
+ else
25
+ need curl
26
+ need tar
27
+ _TMP_BUNDLE_DIR="$(mktemp -d "${TMPDIR:-/tmp}/omnish-cursor.XXXXXX")"
28
+ trap cleanup EXIT
29
+ echo "Downloading Omnish Cursor bundle..." >&2
30
+ curl -fsSL "$OMNISH_CURSOR_BUNDLE_URL" | tar -xzf - -C "$_TMP_BUNDLE_DIR"
31
+ if [[ ! -d "$_TMP_BUNDLE_DIR/omnish-cursor" ]]; then
32
+ echo "error: bundle missing omnish-cursor/ top-level directory" >&2
33
+ exit 1
34
+ fi
35
+ ROOT="$_TMP_BUNDLE_DIR/omnish-cursor"
36
+ fi
37
+
38
+ CURSOR_DIR="${CURSOR_DIR:-$HOME/.cursor}"
39
+ HOOKS_DIR="$CURSOR_DIR/hooks"
40
+ RULES_DIR="$CURSOR_DIR/rules"
41
+ SKILL_DIR="$CURSOR_DIR/skills/omnish"
42
+
43
+ INSTALL_HOOKS=1
44
+ INSTALL_SKILL=1
45
+
46
+ usage() {
47
+ cat <<EOF
48
+ Usage: $(basename "$0") [options]
49
+
50
+ Install Omnish Cursor integration (hooks, skill, rule, config).
51
+
52
+ Options:
53
+ --hooks-only Install only Cursor hooks + rule + notify config
54
+ --skill-only Install only the omnish Cursor skill (+ doctor script)
55
+ -h, --help Show this help
56
+ EOF
57
+ }
58
+
59
+ while [[ $# -gt 0 ]]; do
60
+ case "$1" in
61
+ --hooks-only)
62
+ INSTALL_HOOKS=1
63
+ INSTALL_SKILL=0
64
+ shift
65
+ ;;
66
+ --skill-only)
67
+ INSTALL_HOOKS=0
68
+ INSTALL_SKILL=1
69
+ shift
70
+ ;;
71
+ -h | --help)
72
+ usage
73
+ exit 0
74
+ ;;
75
+ *)
76
+ echo "error: unknown option: $1" >&2
77
+ usage >&2
78
+ exit 1
79
+ ;;
80
+ esac
81
+ done
82
+
83
+ if [[ "$INSTALL_HOOKS" -eq 1 ]]; then
84
+ need python3
85
+ need omnish
86
+ fi
87
+
88
+ if [[ "$INSTALL_HOOKS" -eq 1 ]]; then
89
+ mkdir -p "$HOOKS_DIR" "$RULES_DIR"
90
+
91
+ install -m 755 "$ROOT/hooks/omnish-notify.sh" "$HOOKS_DIR/omnish-notify.sh"
92
+ install -m 755 "$ROOT/hooks/omnish-session-start.sh" "$HOOKS_DIR/omnish-session-start.sh"
93
+ install -m 644 "$ROOT/hooks/omnish-notify.py" "$HOOKS_DIR/omnish-notify.py"
94
+ install -m 644 "$ROOT/rules/omnish-notify.mdc" "$RULES_DIR/omnish-notify.mdc"
95
+
96
+ if [[ ! -f "$CURSOR_DIR/omnish-notify.json" ]]; then
97
+ install -m 644 "$ROOT/omnish-notify.json.example" "$CURSOR_DIR/omnish-notify.json"
98
+ echo "created $CURSOR_DIR/omnish-notify.json"
99
+ else
100
+ echo "kept existing $CURSOR_DIR/omnish-notify.json"
101
+ fi
102
+
103
+ python3 - "$CURSOR_DIR/hooks.json" <<'PY'
104
+ import json
105
+ import sys
106
+ from pathlib import Path
107
+
108
+ hooks_path = Path(sys.argv[1])
109
+ desired = {
110
+ "sessionStart": [{"command": "./hooks/omnish-session-start.sh"}],
111
+ "stop": [{"command": "./hooks/omnish-notify.sh"}],
112
+ }
113
+
114
+ if hooks_path.exists():
115
+ try:
116
+ data = json.loads(hooks_path.read_text(encoding="utf-8"))
117
+ except json.JSONDecodeError:
118
+ data = {"version": 1, "hooks": {}}
119
+ else:
120
+ data = {"version": 1, "hooks": {}}
121
+
122
+ data.setdefault("version", 1)
123
+ hooks = data.setdefault("hooks", {})
124
+
125
+ for event, entries in desired.items():
126
+ existing = hooks.get(event) or []
127
+ commands = {entry.get("command") for entry in existing if isinstance(entry, dict)}
128
+ merged = list(existing)
129
+ for entry in entries:
130
+ if entry["command"] not in commands:
131
+ merged.append(entry)
132
+ hooks[event] = merged
133
+
134
+ hooks_path.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
135
+ print(f"updated {hooks_path}")
136
+ PY
137
+ fi
138
+
139
+ if [[ "$INSTALL_SKILL" -eq 1 ]]; then
140
+ mkdir -p "$SKILL_DIR/scripts"
141
+ install -m 644 "$ROOT/skill/SKILL.md" "$SKILL_DIR/SKILL.md"
142
+ install -m 644 "$ROOT/skill/setup-paths.md" "$SKILL_DIR/setup-paths.md"
143
+ install -m 644 "$ROOT/skill/files-and-sharing.md" "$SKILL_DIR/files-and-sharing.md"
144
+ install -m 644 "$ROOT/skill/notifications.md" "$SKILL_DIR/notifications.md"
145
+ install -m 755 "$ROOT/scripts/doctor.sh" "$SKILL_DIR/scripts/doctor.sh"
146
+ echo "installed skill to $SKILL_DIR"
147
+ fi
148
+
149
+ cat <<EOF
150
+
151
+ Installed Omnish Cursor bundle.
152
+
153
+ Next steps:
154
+ 1. Ensure omnish gateway is running: omnish run
155
+ 2. Platform attached: omnish config show platform
156
+ Local mode: omnish link && omnish allow +E164 (or tg:id)
157
+ 3. Restart Cursor (or reload Hooks in Settings)
158
+ 4. Run: bash $SKILL_DIR/scripts/doctor.sh
159
+
160
+ Config: $CURSOR_DIR/omnish-notify.json
161
+ Default peer: * (all allowlisted contacts)
162
+ EOF
@@ -0,0 +1,13 @@
1
+ {
2
+ "enabled": true,
3
+ "peer": "*",
4
+ "min_assistant_chars": 120,
5
+ "notify_on_error": true,
6
+ "skip_aborted": true,
7
+ "include_full_chat_id": true,
8
+ "summary_max_chars": 300,
9
+ "followup_max_chars": 1000,
10
+ "max_followup_messages": 0,
11
+ "send_followups": false,
12
+ "dedupe_minutes": 45
13
+ }
@@ -0,0 +1,45 @@
1
+ ---
2
+ description: Send curated Omnish brief notifications when Cursor agent work completes or needs attention
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Omnish agent notifications
7
+
8
+ When this session produces a **new** useful outcome, notify via Omnish with a clear title and structured brief.
9
+
10
+ ## Send when
11
+
12
+ - Files changed or a fix/feature was **delivered** in the repo
13
+ - Blocked and need a **new** human decision
14
+ - Major milestone on long-running tasks (sparingly — once per phase)
15
+
16
+ ## Skip when (important)
17
+
18
+ - Pure Q&A, troubleshooting advice, or repeated “redeploy / run this command” with **no new code change**
19
+ - User pastes the **same error again** — do not notify again unless you changed something
20
+ - Trivial lookups or one-line answers
21
+ - Mid-turn exploration with nothing to report yet
22
+ - **Automatic stop hook already sent Done** for this turn — never send a second manual Done
23
+
24
+ ## Do not flood
25
+
26
+ - One completion → at most **one** Done ping (hook handles it; do not also run `omnish i -c` for Done)
27
+ - Same chat + same user ask + same advice = **no notify**
28
+ - Long error dumps in chat are not “new work” unless you shipped a fix
29
+
30
+ ## Format
31
+
32
+ ```bash
33
+ omnish i -c '/sendto * -t <title> -- <brief>'
34
+ ```
35
+
36
+ Use labeled sections (Status, Chat, Workspace, You asked, Outcome). Include `conversation_id`.
37
+
38
+ ## Types
39
+
40
+ - **Done** — finished with concise outcome (file changes or verified fix)
41
+ - **Progress** — major phase change only
42
+ - **Question** — needs human decision
43
+ - **Blocked** — failure or dependency
44
+
45
+ Hook config: `~/.cursor/omnish-notify.json` — defaults skip read-only turns and dedupe repeats for 45 minutes.
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env bash
2
+ # Read-only Omnish + Cursor integration health check.
3
+ set -euo pipefail
4
+
5
+ CURSOR_DIR="${CURSOR_DIR:-$HOME/.cursor}"
6
+ WARN=0
7
+
8
+ ok() { printf ' OK %s\n' "$*"; }
9
+ warn() { printf ' WARN %s\n' "$*"; WARN=1; }
10
+ fail() { printf ' FAIL %s\n' "$*"; }
11
+
12
+ section() { printf '\n== %s ==\n' "$*"; }
13
+
14
+ section "Omnish CLI"
15
+ if command -v omnish >/dev/null 2>&1; then
16
+ ok "omnish on PATH: $(command -v omnish)"
17
+ omnish --version 2>/dev/null | sed 's/^/ /' || true
18
+ else
19
+ fail "omnish not found — run: npm install -g omnish"
20
+ exit 1
21
+ fi
22
+
23
+ section "Gateway status"
24
+ if omnish status 2>&1 | sed 's/^/ /'; then
25
+ if omnish status 2>&1 | grep -q 'gateway process: running'; then
26
+ ok "gateway running"
27
+ else
28
+ warn "gateway not running — run: omnish run (or omnish start)"
29
+ fi
30
+ else
31
+ warn "omnish status failed"
32
+ fi
33
+
34
+ section "Platform config"
35
+ STATUS_OUT="$(omnish status 2>&1 || true)"
36
+ echo "$STATUS_OUT" | sed 's/^/ /'
37
+ if echo "$STATUS_OUT" | grep -q 'platform'; then
38
+ if echo "$STATUS_OUT" | grep -q 'attached: yes'; then
39
+ ok "platform attached mode detected (see status above)"
40
+ elif echo "$STATUS_OUT" | grep -qi 'platformToken\|platform_token'; then
41
+ ok "platform token configured"
42
+ else
43
+ warn "no platform attachment — use standalone link or: omnish platform login --url … --token …"
44
+ fi
45
+ else
46
+ warn "could not read platform block from omnish status"
47
+ fi
48
+
49
+ section "Allowlist hint"
50
+ if omnish status 2>&1 | grep -A2 'Allowed' | grep -q '(none)'; then
51
+ warn "allowlist empty — add via platform dashboard or: omnish allow +E164 / omnish allow tg:id"
52
+ else
53
+ ok "allowlist entries detected (see omnish status above)"
54
+ fi
55
+
56
+ section "Cursor notify config"
57
+ CFG="$CURSOR_DIR/omnish-notify.json"
58
+ if [[ -f "$CFG" ]]; then
59
+ ok "found $CFG"
60
+ python3 - "$CFG" <<'PY'
61
+ import json, sys
62
+ cfg = json.load(open(sys.argv[1], encoding="utf-8"))
63
+ enabled = cfg.get("enabled", True)
64
+ peer = cfg.get("peer", "*")
65
+ print(f" enabled={enabled} peer={peer!r}")
66
+ PY
67
+ else
68
+ warn "missing $CFG — run: bash contrib/omnish-cursor/install.sh"
69
+ fi
70
+
71
+ section "Cursor hooks"
72
+ HOOKS_JSON="$CURSOR_DIR/hooks.json"
73
+ for f in omnish-notify.sh omnish-notify.py omnish-session-start.sh; do
74
+ if [[ -f "$CURSOR_DIR/hooks/$f" ]]; then
75
+ ok "hook file: hooks/$f"
76
+ else
77
+ warn "missing hooks/$f"
78
+ fi
79
+ done
80
+
81
+ if [[ -f "$HOOKS_JSON" ]]; then
82
+ python3 - "$HOOKS_JSON" <<'PY'
83
+ import json, sys
84
+ from pathlib import Path
85
+ data = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
86
+ hooks = data.get("hooks") or {}
87
+ want = {
88
+ "sessionStart": "./hooks/omnish-session-start.sh",
89
+ "stop": "./hooks/omnish-notify.sh",
90
+ }
91
+ for event, cmd in want.items():
92
+ entries = hooks.get(event) or []
93
+ found = any(isinstance(e, dict) and e.get("command") == cmd for e in entries)
94
+ print(f" {event}: {'registered' if found else 'MISSING ' + cmd}")
95
+ PY
96
+ else
97
+ warn "missing $HOOKS_JSON"
98
+ fi
99
+
100
+ section "Cursor skill"
101
+ SKILL="$CURSOR_DIR/skills/omnish/SKILL.md"
102
+ if [[ -f "$SKILL" ]]; then
103
+ ok "skill installed: skills/omnish/SKILL.md"
104
+ else
105
+ warn "skill not installed — run: bash contrib/omnish-cursor/install.sh"
106
+ fi
107
+
108
+ RULE="$CURSOR_DIR/rules/omnish-notify.mdc"
109
+ if [[ -f "$RULE" ]]; then
110
+ ok "rule: rules/omnish-notify.mdc"
111
+ else
112
+ warn "missing rules/omnish-notify.mdc"
113
+ fi
114
+
115
+ section "Suggested next steps"
116
+ if [[ $WARN -eq 0 ]]; then
117
+ echo " All checks passed. Test notify:"
118
+ echo " omnish i -c '/sendto * -t Omnish Test -- doctor ok'"
119
+ else
120
+ echo " Fix WARN items above, then:"
121
+ echo " omnish run"
122
+ echo " bash contrib/omnish-cursor/install.sh # if Cursor pieces missing"
123
+ echo " omnish i -c '/sendto * -t Omnish Test -- setup ok'"
124
+ fi
125
+
126
+ exit 0
@@ -0,0 +1,129 @@
1
+ ---
2
+ name: omnish
3
+ description: Install, configure, and use Omnish (WhatsApp/Telegram/platform shell gateway)—chat commands, file sharing (/send, /sendto, /receive), and mobile notifications. Use when setting up omnish, omnish run, platform token, file transfer, agent notify, or Cursor omnish hooks.
4
+ ---
5
+
6
+ # Omnish setup and usage
7
+
8
+ Help the user install, configure, and use **omnish** — a messaging-to-shell gateway (WhatsApp, Telegram, or platform attached mode). Chat is the primary UX; emphasize **file sharing** and **notifications** as high-value extras.
9
+
10
+ ## First step: triage
11
+
12
+ Run the bundled doctor (after install) or from the repo:
13
+
14
+ ```bash
15
+ bash ~/.cursor/skills/omnish/scripts/doctor.sh
16
+ # or: bash contrib/omnish-cursor/scripts/doctor.sh
17
+ ```
18
+
19
+ Interpret output: omnish on PATH, gateway running, allowlist/platform token, Cursor hooks/skill installed. Never echo secrets from config.
20
+
21
+ ## Setup paths
22
+
23
+ Pick one path — see [setup-paths.md](setup-paths.md):
24
+
25
+ | Path | When |
26
+ | ----------------------- | --------------------------------------------------------------- |
27
+ | **Platform attached** | User has `platform_url` + `platform_token`; messengers on relay |
28
+ | **Standalone WhatsApp** | Local `omnish link` + QR |
29
+ | **Standalone Telegram** | `omnish link --tg <token>` |
30
+
31
+ Platform attached (common for builders):
32
+
33
+ ```bash
34
+ npm install -g omnish
35
+ omnish platform login --url https://tunnel.omnish.dev --token YOUR_ACCOUNT_TOKEN
36
+ omnish platform status && omnish platform probe
37
+ omnish run
38
+ ```
39
+
40
+ Verify from allowlisted chat: `!pwd` or `!help`.
41
+
42
+ ## Configuration essentials
43
+
44
+ - **Data dir**: `omnish status` shows path (`~/.omnish` or legacy `~/.whatslive`; override `OMNISH_HOME`)
45
+ - **Inspect**: `omnish config show`, `omnish config show platform`, `omnish security`
46
+ - **Key keys**: `gatewayMode`, `allowFrom` / `telegramAllowFrom`, `fileSendMaxBytes`, `fileReceiveMaxBytes`, `fileReceiveRootMode`, `recipesNotifyEnabled`, `platformToken`
47
+
48
+ Edit via CLI or chat `/config show` (allowlisted). Restart gateway after changes (`/reload` or restart `omnish run`).
49
+
50
+ ## Chat usage (primary)
51
+
52
+ | Surface | Prefix / command | Purpose |
53
+ | ---------- | ---------------------- | --------------------------------------- |
54
+ | Sync shell | `!cmd` | Immediate command in chat cwd |
55
+ | Change cwd | `!cd path` | Per-chat working directory |
56
+ | Background | `/bg cmd` | Detached job; `/jobs`, `/tail`, `/kill` |
57
+ | PTY apps | `/apps start name cmd` | Interactive TUIs |
58
+ | Recipes | `/run name task` | Saved agent wrappers (`$OMNISH_TASK`) |
59
+ | Scheduled | `/cowork` | Saved tasks, logs, notify rules |
60
+
61
+ Full manual: omnish repo `docs/guides/user-guide.md` or `omnish search user guide`.
62
+
63
+ ## File sharing (high value)
64
+
65
+ See [files-and-sharing.md](files-and-sharing.md).
66
+
67
+ Quick reference:
68
+
69
+ ```text
70
+ /send ./report.pdf -- Summary # chat → mobile (current chat cwd)
71
+ /receive here # inbound saves to chat cwd
72
+ ```
73
+
74
+ From terminal (requires `omnish run`):
75
+
76
+ ```bash
77
+ omnish i -c '/sendto * ./report.pdf -- Summary'
78
+ omnish i -c '/sendto * -t Status -- deploy finished'
79
+ ```
80
+
81
+ `*` = all allowlisted peers (WhatsApp + Telegram). No channel-specific ids required.
82
+
83
+ ## Notifications
84
+
85
+ See [notifications.md](notifications.md).
86
+
87
+ - **Cursor auto**: install `contrib/omnish-cursor/install.sh` → stop hook sends Done briefs with chat id
88
+ - **Manual / agents**: `omnish i -c '/sendto * -t Title -- brief'`
89
+ - **Background jobs**: `/bg -N long-running-command`
90
+ - **Cowork**: `/cowork set name when always|failure|state-change`
91
+
92
+ Default destination: `*` (broadcast). Config: `~/.cursor/omnish-notify.json`.
93
+
94
+ ## Helping users: checklist
95
+
96
+ Copy and track:
97
+
98
+ ```
99
+ - [ ] omnish installed (npm i -g omnish)
100
+ - [ ] Setup path chosen (platform / WA / TG)
101
+ - [ ] Gateway running (omnish run)
102
+ - [ ] Allowlist configured (platform dashboard or omnish allow)
103
+ - [ ] Smoke test: !pwd from chat
104
+ - [ ] File test: /send or omnish i /sendto *
105
+ - [ ] Notify test: omnish i -c '/sendto * -t Test -- ok'
106
+ - [ ] Cursor bundle (optional): bash contrib/omnish-cursor/install.sh
107
+ - [ ] doctor.sh passes with no blockers
108
+ ```
109
+
110
+ ## Cursor bundle install
111
+
112
+ For users who want agent Done notifications + this skill globally:
113
+
114
+ ```bash
115
+ bash contrib/omnish-cursor/install.sh
116
+ # partial: --hooks-only | --skill-only
117
+ ```
118
+
119
+ Installs hooks, rule, skill to `~/.cursor/`, config with `"peer": "*"`. Restart Cursor after install.
120
+
121
+ ## Doc pointers
122
+
123
+ - Quick start: `docs/guides/quick-start.md`
124
+ - Platform: `docs/guides/platform-attached-mode.md`, `docs/guides/platform-reference.md`
125
+ - Files: `docs/files-send-receive.md`
126
+ - Interactive CLI: `docs/guides/interactive-cli.md`
127
+ - Offline search: `omnish search <topic>`
128
+
129
+ Do not paste platform tokens or webhook secrets into chat or commits.
@@ -0,0 +1,94 @@
1
+ # File sharing with Omnish
2
+
3
+ Omnish moves files **host ↔ chat**. Per-chat cwd applies (same as `!` commands). Use **`/sendto *`** for broadcast to all allowlisted peers unless the user needs one recipient.
4
+
5
+ ## Outbound: host → chat
6
+
7
+ ### From chat (`/send` or `/file`)
8
+
9
+ Works in the current chat's working directory:
10
+
11
+ ```text
12
+ /send ./photo.png
13
+ /send ./a.pdf,./b.png -- Two files
14
+ /send *.mp4
15
+ /send **/*.mp4
16
+ /send "/path with spaces/file.bin" -- Caption here
17
+ ```
18
+
19
+ Limits: `fileSendMaxBytes` in config (`0` = no omnish cap on standalone; platform hop may have separate relay limits).
20
+
21
+ ### From terminal (`omnish i` + `/sendto`)
22
+
23
+ Requires **`omnish run`** on the same machine.
24
+
25
+ ```bash
26
+ omnish i -c '/sendto * ./promo.mp4'
27
+ omnish i -c '/sendto * intro.png,deck.pdf -- Launch materials'
28
+ omnish i -c '/sendto wa ./photo.png' # all allowlisted WA
29
+ omnish i -c '/sendto tg **/*.mp4 -- Video batch' # all allowlisted TG
30
+ omnish i -c '/sendto +15551234567 ./file.pdf' # explicit E.164
31
+ omnish i -c '/sendto tg:123456789 ./report.pdf' # explicit Telegram id
32
+ ```
33
+
34
+ Plain text (not a file attachment):
35
+
36
+ ```bash
37
+ omnish i -c '/sendto * --text Deploy finished OK'
38
+ omnish i -c '/sendto * -t=Status OK'
39
+ ```
40
+
41
+ | Destination | Meaning |
42
+ | ----------- | ----------------------------------- |
43
+ | `*` | All allowlisted WhatsApp + Telegram |
44
+ | `wa` | All allowlisted WhatsApp |
45
+ | `tg` | All allowlisted Telegram |
46
+ | `+E164` | One WhatsApp number |
47
+ | `tg:<id>` | One Telegram chat id |
48
+
49
+ Change cwd in REPL: `!cd /path/to/project` before `/sendto`.
50
+
51
+ ## Inbound: chat → host
52
+
53
+ ```text
54
+ /receive # show current save mode
55
+ /receive here # save to this chat's cwd
56
+ /receive default # global default root
57
+ ```
58
+
59
+ Inbound paths appear as `Saved: …` on **your machine** (even in platform attached mode).
60
+
61
+ Config keys:
62
+
63
+ - `fileReceiveRootMode`: `downloads`, `cwd`, `fixed`, etc.
64
+ - `fileReceiveRootPath`: when mode is `fixed`
65
+ - `fileReceiveMaxBytes`: size cap (`0` = unlimited)
66
+ - `fileInboxSubdir`: subfolder under receive root
67
+
68
+ ## Platform attached mode differences
69
+
70
+ | Feature | Standalone | Platform attached |
71
+ | ---------------------------- | --------------------------- | ----------------------------------------------- |
72
+ | `/send` in chat | Direct to messenger on host | Device → platform WebSocket → relay → messenger |
73
+ | Inbound media | Saved locally | Relay forwards bytes; **device** saves locally |
74
+ | `omnish i /sendto` | Local control channel | Same, via platform WebSocket |
75
+ | Allowlists for `wa`/`tg`/`*` | Local config | Platform `GET /v1/me` when credentials set |
76
+
77
+ Explicit `+E164` / `tg:id` always work on both.
78
+
79
+ ## Agent workflow: file round-trip test
80
+
81
+ 1. Confirm gateway: `omnish status`
82
+ 2. In chat cwd, create test file: `!echo test > omnish-file-test.txt`
83
+ 3. Send: `/send ./omnish-file-test.txt -- omnish test`
84
+ 4. Or CLI: `omnish i -c '/sendto * ./omnish-file-test.txt -- omnish test'`
85
+ 5. User confirms receipt on mobile
86
+
87
+ ## Troubleshooting
88
+
89
+ - `No files matched` — wrong cwd; use `!pwd` or `!cd`
90
+ - `wa`/`tg`/`*` recipient error — empty allowlist; configure on platform or `omnish allow`
91
+ - File too large — raise `fileSendMaxBytes`; check platform `PLATFORM_REPLY_FILE_MAX_BYTES` if attached
92
+ - File named `--text` — use path `./--text`
93
+
94
+ Full reference: `docs/files-send-receive.md`, `docs/guides/interactive-cli.md`.