dunsocial 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -111
- package/dist/index.js +2 -2
- package/package.json +3 -3
- package/skills/dunsocial/SKILL.md +42 -49
package/README.md
CHANGED
|
@@ -1,157 +1,102 @@
|
|
|
1
|
-
# DunSocial CLI
|
|
1
|
+
# DunSocial CLI
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Wraps the existing Mobile API (`apps/api`) — **no duplicate publish logic**.
|
|
6
|
-
Remote AI hosts (ChatGPT / Claude web) should keep using **MCP**. This CLI is for local agents (Claude Code, Codex), CI, and power users.
|
|
7
|
-
|
|
8
|
-
Linear: [DUN-262](https://linear.app/thisuxco/issue/DUN-262) · [DUN-263](https://linear.app/thisuxco/issue/DUN-263) · [DUN-264](https://linear.app/thisuxco/issue/DUN-264)
|
|
3
|
+
Post and schedule to your social accounts from the terminal.
|
|
9
4
|
|
|
10
5
|
## Install
|
|
11
6
|
|
|
12
|
-
### Monorepo (dev)
|
|
13
|
-
|
|
14
7
|
```bash
|
|
15
|
-
|
|
16
|
-
bun run dev:cli -- --help
|
|
17
|
-
bun apps/cli/src/index.ts auth status --json
|
|
8
|
+
npm install -g dunsocial
|
|
18
9
|
```
|
|
19
10
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
bun run --cwd apps/cli build
|
|
24
|
-
node apps/cli/dist/index.js --help
|
|
11
|
+
Then use the `dun` command (Node.js 20+).
|
|
25
12
|
|
|
26
|
-
|
|
27
|
-
npm i -g dunsocial
|
|
28
|
-
dun --help
|
|
29
|
-
```
|
|
13
|
+
---
|
|
30
14
|
|
|
31
|
-
|
|
15
|
+
## Get started
|
|
32
16
|
|
|
33
|
-
|
|
17
|
+
### 1. Sign in
|
|
34
18
|
|
|
35
19
|
```bash
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
export DUN_API_URL=https://api.dunsocial.com # optional
|
|
39
|
-
|
|
40
|
-
# 2. Pick a workspace
|
|
41
|
-
dun workspace list --json
|
|
42
|
-
dun workspace use <id-or-slug>
|
|
20
|
+
dun auth login
|
|
21
|
+
```
|
|
43
22
|
|
|
44
|
-
|
|
45
|
-
dun accounts list --json
|
|
23
|
+
A browser window opens so you can approve access. After that, you’re set on this machineأتى### 2. Choose your workspace
|
|
46
24
|
|
|
47
|
-
|
|
48
|
-
dun
|
|
49
|
-
|
|
50
|
-
--accounts <socialAccountId> \
|
|
51
|
-
--in 1h \
|
|
52
|
-
--json
|
|
25
|
+
```bash
|
|
26
|
+
dun workspace list
|
|
27
|
+
dun workspace use your-workspace
|
|
53
28
|
```
|
|
54
29
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
### Device login (default)
|
|
30
|
+
### 3. See connected accounts
|
|
58
31
|
|
|
59
32
|
```bash
|
|
60
|
-
dun
|
|
61
|
-
# opens app.dunsocial.com/cli/authorize — approve, CLI stores token
|
|
62
|
-
dun auth login --no-browser # print URL only
|
|
33
|
+
dun accounts list
|
|
63
34
|
```
|
|
64
35
|
|
|
65
|
-
|
|
36
|
+
Copy the **account id** you want to post with (not the @username).
|
|
66
37
|
|
|
67
|
-
|
|
38
|
+
### 4. Schedule a post
|
|
68
39
|
|
|
69
40
|
```bash
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
41
|
+
dun posts schedule \
|
|
42
|
+
--text "Hello from DunSocial" \
|
|
43
|
+
--accounts ACCOUNT_ID \
|
|
44
|
+
--in 1h
|
|
73
45
|
```
|
|
74
46
|
|
|
75
|
-
|
|
47
|
+
Post right away:
|
|
76
48
|
|
|
77
49
|
```bash
|
|
78
|
-
dun
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
dun auth logout
|
|
50
|
+
dun posts publish \
|
|
51
|
+
--text "Hello from DunSocial" \
|
|
52
|
+
--accounts ACCOUNT_ID
|
|
82
53
|
```
|
|
83
54
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
Env (wins over config):
|
|
55
|
+
---
|
|
87
56
|
|
|
88
|
-
|
|
89
|
-
|-----|---------|
|
|
90
|
-
| `DUN_TOKEN` | Bearer token |
|
|
91
|
-
| `DUN_WORKSPACE_ID` | Default workspace |
|
|
92
|
-
| `DUN_API_URL` | API base URL |
|
|
93
|
-
| `DUN_JSON=1` | Force JSON output |
|
|
94
|
-
| `DUN_DEBUG=1` | Log HTTP to stderr |
|
|
57
|
+
## Automated posting (CI)
|
|
95
58
|
|
|
96
|
-
|
|
59
|
+
1. In DunSocial, open **Settings → CLI**
|
|
60
|
+
2. Create an access token and copy it (shown once)
|
|
61
|
+
3. Add these secrets in your CI:
|
|
62
|
+
- `DUN_TOKEN` — your access token
|
|
63
|
+
- `DUN_WORKSPACE_ID` — your workspace id
|
|
97
64
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
| Area | Examples |
|
|
103
|
-
|------|----------|
|
|
104
|
-
| Workspaces | `workspace list\|use\|current` |
|
|
105
|
-
| Accounts | `accounts list [--platform x]` |
|
|
106
|
-
| Posts | `schedule`, `publish`, `list`, `get`, `reschedule`, `cancel`, `delete`, `x-cap`, `schedule-thread`, `publish-thread` |
|
|
107
|
-
| Drafts | `create`, `list`, `get`, `update`, `delete` |
|
|
108
|
-
| Media | `upload <file>`, `list`, `get`, `delete` |
|
|
109
|
-
| Memory | `collections list\|create`, `save`, `list`, `search`, `delete` |
|
|
110
|
-
| Skills | `skill install claude\|codex` |
|
|
111
|
-
|
|
112
|
-
### Global flags
|
|
65
|
+
```bash
|
|
66
|
+
export DUN_TOKEN=your_token
|
|
67
|
+
export DUN_WORKSPACE_ID=your_workspace_id
|
|
113
68
|
|
|
69
|
+
dun posts schedule \
|
|
70
|
+
--text "We just shipped a new release" \
|
|
71
|
+
--accounts ACCOUNT_ID \
|
|
72
|
+
--in 5m
|
|
114
73
|
```
|
|
115
|
-
--json --workspace <id> --api-url <url> --token <token>
|
|
116
|
-
--debug --quiet --yes --help --version
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
JSON is the default when stdout is not a TTY or `CI=1`.
|
|
120
|
-
|
|
121
|
-
### Exit codes
|
|
122
74
|
|
|
123
|
-
|
|
75
|
+
---
|
|
124
76
|
|
|
125
|
-
##
|
|
77
|
+
## Useful commands
|
|
126
78
|
|
|
127
79
|
```bash
|
|
128
|
-
dun
|
|
129
|
-
dun
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
```bash
|
|
135
|
-
bun run --cwd apps/cli test
|
|
136
|
-
bun run --cwd apps/cli type-check
|
|
137
|
-
bun run --cwd apps/cli build
|
|
138
|
-
bun run --cwd apps/cli release-check
|
|
80
|
+
dun --help
|
|
81
|
+
dun auth status
|
|
82
|
+
dun posts list
|
|
83
|
+
dun media upload ./photo.png
|
|
84
|
+
dun drafts create --text "Idea for later"
|
|
139
85
|
```
|
|
140
86
|
|
|
141
|
-
|
|
87
|
+
Tips:
|
|
142
88
|
|
|
143
|
-
|
|
89
|
+
- Help for any command: `dun posts --help`
|
|
90
|
+
- Structured output for scripts: add `--json`
|
|
91
|
+
- Prefer ChatGPT or Claude **in the browser**? Use [MCP](https://docs.dunsocial.com/mcp) instead of the CLI
|
|
144
92
|
|
|
145
|
-
|
|
146
|
-
2. Merge the **release-please** PR (version + `CHANGELOG.md`)
|
|
147
|
-
3. CI publishes `dunsocial` to npm (`NPM_TOKEN` secret)
|
|
93
|
+
---
|
|
148
94
|
|
|
149
|
-
|
|
95
|
+
## Links
|
|
150
96
|
|
|
151
|
-
|
|
97
|
+
- [dunsocial.com](https://dunsocial.com)
|
|
98
|
+
- [npm package](https://www.npmjs.com/package/dunsocial)
|
|
152
99
|
|
|
153
|
-
|
|
154
|
-
dun → HTTPS + Bearer + X-Workspace-Id → apps/api REST
|
|
155
|
-
```
|
|
100
|
+
## License
|
|
156
101
|
|
|
157
|
-
|
|
102
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{mkdir as dn,readFile as Ie,writeFile as rn,chmod as tn,unlink as mn}from"node:fs/promises";import{dirname as yn,join as ue}from"node:path";import{homedir as pe}from"node:os";var o={OK:0,USAGE:1,AUTH:2,FORBIDDEN:3,VALIDATION:4,NOT_FOUND:5,RATE_LIMITED:6,NETWORK:7};class w extends Error{code;details;constructor(e,n=o.USAGE,u){super(e);this.name="CliError",this.code=n,this.details=u}}function ne(e){if(e===401)return o.AUTH;if(e===403)return o.FORBIDDEN;if(e===404)return o.NOT_FOUND;if(e===429)return o.RATE_LIMITED;if(e>=400&&e<500)return o.VALIDATION;return o.NETWORK}var Ge="https://api.dunsocial.com",W="0.
|
|
3
|
+
import{mkdir as dn,readFile as Ie,writeFile as rn,chmod as tn,unlink as mn}from"node:fs/promises";import{dirname as yn,join as ue}from"node:path";import{homedir as pe}from"node:os";var o={OK:0,USAGE:1,AUTH:2,FORBIDDEN:3,VALIDATION:4,NOT_FOUND:5,RATE_LIMITED:6,NETWORK:7};class w extends Error{code;details;constructor(e,n=o.USAGE,u){super(e);this.name="CliError",this.code=n,this.details=u}}function ne(e){if(e===401)return o.AUTH;if(e===403)return o.FORBIDDEN;if(e===404)return o.NOT_FOUND;if(e===429)return o.RATE_LIMITED;if(e>=400&&e<500)return o.VALIDATION;return o.NETWORK}var Ge="https://api.dunsocial.com",W="0.3.1";function Ve(){if(process.env.DUN_CONFIG)return process.env.DUN_CONFIG;let e=process.env.XDG_CONFIG_HOME,n=e?e:ue(pe(),".config");return ue(n,"dunsocial","config.json")}async function _e(){let e=Ve();try{let n=await Ie(e,"utf8");return JSON.parse(n)}catch(n){if(n.code==="ENOENT")return{};throw new w(`Failed to read config at ${e}: ${n.message}`,o.USAGE)}}async function de(e){let n=await _e(),u=(e.apiUrl||process.env.DUN_API_URL||n.apiUrl||Ge).replace(/\/$/,""),t=e.token||process.env.DUN_TOKEN||n.token,y=e.workspace||process.env.DUN_WORKSPACE_ID||n.defaultWorkspaceId||void 0,d=process.env.DUN_JSON==="0",i=!process.stdout.isTTY,r=d?!1:e.json===!0||process.env.DUN_JSON==="1"||process.env.CI==="true"||process.env.CI==="1"||i;return{apiUrl:u,token:t,workspaceId:y,json:r,debug:e.debug===!0||process.env.DUN_DEBUG==="1",quiet:e.quiet===!0,yes:e.yes===!0||process.env.CI==="true"||process.env.CI==="1",config:n}}function re(e){let n={},u=[],t=0,y=!0;while(t<e.length){let O=e[t];if(y&&O==="--"){y=!1,t+=1;continue}if(y&&O.startsWith("--")){let A=O.indexOf("=");if(A!==-1){n[O.slice(2,A)]=O.slice(A+1),t+=1;continue}let T=O.slice(2),U=e[t+1];if(U!==void 0&&!U.startsWith("-"))n[T]=U,t+=2;else n[T]=!0,t+=1;continue}if(y&&O.startsWith("-")&&O.length>1&&O!=="-"){let A=O.slice(1);if(A.length>1&&!A.includes("=")){for(let V of A)n[V]=!0;t+=1;continue}let T=A,U=e[t+1];if(U!==void 0&&!U.startsWith("-"))n[T]=U,t+=2;else n[T]=!0,t+=1;continue}u.push(O),t+=1}let d=u[0],i,r,m=1;if(d==="memory"&&(u[1]==="collections"||u[1]==="collection"))r="collections",i=u[2],m=i?3:2;else i=u[1],m=i?2:1;return{group:d,action:i,nest:r,flags:n,positionals:u.slice(m)}}function M(e,...n){for(let u of n){let t=e[u];if(typeof t==="string"&&t.length>0)return t}return}function K(e,...n){for(let u of n){let t=e[u];if(t===!0)return!0;if(typeof t==="string"){let y=t.toLowerCase();if(y==="1"||y==="true"||y==="yes")return!0}}return!1}function F(e){return K(e,"help","h")}function q(e){return K(e,"version","v","V")}function s(e,n){if(n.quiet&&!n.json)return;if(n.json||!process.stdout.isTTY){process.stdout.write(`${JSON.stringify({ok:!0,data:e},null,2)}
|
|
4
4
|
`);return}if(e===void 0||e===null){process.stdout.write(`ok
|
|
5
5
|
`);return}if(typeof e==="string"){process.stdout.write(`${e}
|
|
6
6
|
`);return}process.stdout.write(`${Je(e)}
|
|
@@ -12,7 +12,7 @@ import{mkdir as dn,readFile as Ie,writeFile as rn,chmod as tn,unlink as mn}from"
|
|
|
12
12
|
${t}`:t}return Object.entries(n).map(([u,t])=>`${u}: ${P(t)}`).join(`
|
|
13
13
|
`)}return String(e)}function te(e){if(e.length===0)return"(empty)";let n=["id","name","slug","status","providerName","username","displayName","role","scheduledAt","content","text","originalFilename","score","collectionId"],u=new Set;for(let m of e)for(let O of Object.keys(m))u.add(O);let t=[...n.filter((m)=>u.has(m)),...[...u].filter((m)=>!n.includes(m)).slice(0,6)].slice(0,8),y=e.map((m)=>t.map((O)=>He(P(m[O]),O==="content"||O==="text"?48:28))),d=t.map((m,O)=>Math.max(m.length,...y.map((A)=>A[O]?.length??0))),i=t.map((m,O)=>m.padEnd(d[O])).join(" "),r=y.map((m)=>m.map((O,A)=>O.padEnd(d[A])).join(" ")).join(`
|
|
14
14
|
`);return`${i}
|
|
15
|
-
${r}`}function P(e){if(e===null||e===void 0)return"";if(typeof e==="string")return e.replace(/\s+/g," ").trim();if(typeof e==="number"||typeof e==="boolean")return String(e);if(e instanceof Date)return e.toISOString();if(typeof e==="object"){let n=e;if(typeof n.id==="string"&&typeof n.name==="string")return`${n.name} (${n.id})`;if(typeof n.status==="string")return n.status;return JSON.stringify(e)}return String(e)}function He(e,n){if(e.length<=n)return e;return`${e.slice(0,Math.max(0,n-1))}…`}var G={OK:0,USAGE:1,AUTH:2,FORBIDDEN:3,VALIDATION:4,NOT_FOUND:5,RATE_LIMITED:6,NETWORK:7};class S extends Error{code;details;constructor(e,n=G.USAGE,u){super(e);this.name="CliError",this.code=n,this.details=u}}import{mkdir as Ye,readFile as Rn,writeFile as ze,chmod as We,unlink as Me}from"node:fs/promises";import{dirname as Qe,join as me}from"node:path";import{homedir as Xe}from"node:os";var Q="0.
|
|
15
|
+
${r}`}function P(e){if(e===null||e===void 0)return"";if(typeof e==="string")return e.replace(/\s+/g," ").trim();if(typeof e==="number"||typeof e==="boolean")return String(e);if(e instanceof Date)return e.toISOString();if(typeof e==="object"){let n=e;if(typeof n.id==="string"&&typeof n.name==="string")return`${n.name} (${n.id})`;if(typeof n.status==="string")return n.status;return JSON.stringify(e)}return String(e)}function He(e,n){if(e.length<=n)return e;return`${e.slice(0,Math.max(0,n-1))}…`}var G={OK:0,USAGE:1,AUTH:2,FORBIDDEN:3,VALIDATION:4,NOT_FOUND:5,RATE_LIMITED:6,NETWORK:7};class S extends Error{code;details;constructor(e,n=G.USAGE,u){super(e);this.name="CliError",this.code=n,this.details=u}}import{mkdir as Ye,readFile as Rn,writeFile as ze,chmod as We,unlink as Me}from"node:fs/promises";import{dirname as Qe,join as me}from"node:path";import{homedir as Xe}from"node:os";var Q="0.3.1";function E(){if(process.env.DUN_CONFIG)return process.env.DUN_CONFIG;let e=process.env.XDG_CONFIG_HOME,n=e?e:me(Xe(),".config");return me(n,"dunsocial","config.json")}function L(){return E()}async function J(e){let n=E();await Ye(Qe(n),{recursive:!0});let u={...e,updatedAt:new Date().toISOString()};await ze(n,`${JSON.stringify(u,null,2)}
|
|
16
16
|
`,"utf8");try{await We(n,384)}catch{}}async function oe(){let e=E();try{await Me(e)}catch(n){if(n.code!=="ENOENT")throw new w(`Failed to clear config: ${n.message}`,o.USAGE)}}function R(e){if(!e.token)throw new w("Not authenticated. Run `dun auth login --token <token>` or set DUN_TOKEN.",o.AUTH);return e.token}function k(e){if(!e.workspaceId)throw new w("No workspace selected. Run `dun workspace use <id|slug>` or pass --workspace / DUN_WORKSPACE_ID.",o.VALIDATION);return e.workspaceId}var X=`dun — DunSocial agent-first CLI v${Q}
|
|
17
17
|
|
|
18
18
|
Usage:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dunsocial",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "DunSocial agent-first CLI — schedule and publish social posts from the terminal, CI, and coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"mcp"
|
|
23
23
|
],
|
|
24
24
|
"bin": {
|
|
25
|
-
"dun": "
|
|
26
|
-
"dunsocial": "
|
|
25
|
+
"dun": "dist/index.js",
|
|
26
|
+
"dunsocial": "dist/index.js"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"dist",
|
|
@@ -1,44 +1,53 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dunsocial
|
|
3
|
-
description: Schedule, publish, and manage DunSocial posts, drafts, media, and memory from the shell via the dun CLI. Use when the user wants to post or schedule to X/LinkedIn/Bluesky/Threads/Reddit/Pinterest/Instagram/YouTube through DunSocial, manage drafts or media uploads, search workspace memory, or wire social publishing into CI/agent workflows.
|
|
3
|
+
description: Schedule, publish, and manage DunSocial posts, drafts, media, and memory from the shell via the dun CLI (npm package dunsocial). Use when the user wants to post or schedule to X/LinkedIn/Bluesky/Threads/Reddit/Pinterest/Instagram/YouTube through DunSocial, manage drafts or media uploads, search workspace memory, or wire social publishing into CI/agent workflows.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# DunSocial CLI skill
|
|
7
7
|
|
|
8
|
-
Use the
|
|
8
|
+
Use the **`dun`** binary from the **`dunsocial`** npm package.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
```bash
|
|
11
|
+
npm install -g dunsocial
|
|
12
|
+
# or
|
|
13
|
+
npx dunsocial …
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Prefer **`--json`** on every command so output is machine-parseable.
|
|
17
|
+
|
|
18
|
+
Remote hosts (ChatGPT web, Claude web) should keep using DunSocial **MCP**. This CLI is for **local agents, terminals, and CI**.
|
|
11
19
|
|
|
12
20
|
## Auth + workspace
|
|
13
21
|
|
|
14
22
|
```bash
|
|
15
|
-
# Interactive (
|
|
23
|
+
# Interactive (browser approve at app.dunsocial.com/cli/authorize)
|
|
16
24
|
dun auth login
|
|
17
25
|
|
|
18
|
-
# CI / headless —
|
|
19
|
-
export DUN_TOKEN="
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
# CI / headless — PAT from app Settings → CLI (dun_pat_…)
|
|
27
|
+
export DUN_TOKEN="dun_pat_…"
|
|
28
|
+
export DUN_WORKSPACE_ID="…"
|
|
29
|
+
# optional:
|
|
30
|
+
export DUN_API_URL=https://api.dunsocial.com
|
|
22
31
|
|
|
23
32
|
dun auth status --json
|
|
24
33
|
dun workspace list --json
|
|
25
34
|
dun workspace use <id-or-slug> --json
|
|
26
35
|
```
|
|
27
36
|
|
|
28
|
-
Env overrides
|
|
37
|
+
Env overrides config file `~/.config/dunsocial/config.json`.
|
|
29
38
|
|
|
30
|
-
|
|
31
|
-
- `DUN_WORKSPACE_ID`
|
|
32
|
-
- `DUN_API_URL` (default `https://api.dunsocial.com`)
|
|
39
|
+
PAT notes:
|
|
33
40
|
|
|
34
|
-
|
|
41
|
+
- Workspace-bound; missing scope → exit `3` / forbidden
|
|
42
|
+
- Cannot manage other tokens, billing, or team
|
|
43
|
+
- Prefer PAT over full browser session tokens in CI
|
|
35
44
|
|
|
36
45
|
## Discovery order (always)
|
|
37
46
|
|
|
38
|
-
1. `dun auth status --json`
|
|
39
|
-
2. `dun workspace current --json` or `list` + `use`
|
|
47
|
+
1. `dun auth status --json`
|
|
48
|
+
2. `dun workspace current --json` (or `list` + `use`)
|
|
40
49
|
3. `dun accounts list --json` — capture social account **ids**
|
|
41
|
-
4. Act (schedule/publish/draft/media/memory)
|
|
50
|
+
4. Act (schedule / publish / draft / media / memory)
|
|
42
51
|
|
|
43
52
|
Do **not** invent account IDs. Do **not** treat `drafts create` as a successful publish.
|
|
44
53
|
|
|
@@ -46,17 +55,13 @@ Do **not** invent account IDs. Do **not** treat `drafts create` as a successful
|
|
|
46
55
|
|
|
47
56
|
```bash
|
|
48
57
|
dun posts schedule \
|
|
49
|
-
--text "Shipped the DunSocial CLI
|
|
58
|
+
--text "Shipped from the DunSocial CLI." \
|
|
50
59
|
--accounts acc_x,acc_li \
|
|
51
60
|
--in 1h \
|
|
52
61
|
--json
|
|
53
62
|
```
|
|
54
63
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
dun posts schedule --text "..." --accounts acc_x --at 2026-06-01T09:00:00Z --json
|
|
59
|
-
```
|
|
64
|
+
Absolute time: `--at 2026-06-01T09:00:00Z`.
|
|
60
65
|
|
|
61
66
|
## Publish now
|
|
62
67
|
|
|
@@ -68,36 +73,24 @@ dun posts publish --text "Hello from dun" --accounts acc_x --json
|
|
|
68
73
|
|
|
69
74
|
```bash
|
|
70
75
|
dun media upload ./shot.png --alt "Product screenshot" --json
|
|
71
|
-
|
|
72
|
-
dun posts schedule --text "..." --accounts acc_x --media <assetId> --in 30m --json
|
|
76
|
+
dun posts schedule --text "…" --accounts acc_x --media <assetId> --in 30m --json
|
|
73
77
|
```
|
|
74
78
|
|
|
75
|
-
## Drafts
|
|
76
|
-
|
|
77
|
-
```bash
|
|
78
|
-
dun drafts create --text "WIP idea" --platforms x,linkedin --json
|
|
79
|
-
dun drafts list --json
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Memory
|
|
79
|
+
## Drafts / memory / threads
|
|
83
80
|
|
|
84
81
|
```bash
|
|
82
|
+
dun drafts create --text "WIP" --platforms x,linkedin --json
|
|
85
83
|
dun memory collections list --json
|
|
86
|
-
dun memory save --collection <id> --text "
|
|
87
|
-
dun memory search --prompt "
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Threads (X)
|
|
84
|
+
dun memory save --collection <id> --text "…" --json
|
|
85
|
+
dun memory search --prompt "…" --collections <id> --json
|
|
91
86
|
|
|
92
|
-
|
|
93
|
-
# thread.json => [ {"content":"1"}, {"content":"2"} ] or { "tweets": [...] }
|
|
87
|
+
# thread.json: [ {"content":"1"}, {"content":"2"} ]
|
|
94
88
|
dun posts schedule-thread --account acc_x --file ./thread.json --in 2h --json
|
|
95
|
-
dun posts publish-thread --account acc_x --file ./thread.json --json
|
|
96
89
|
```
|
|
97
90
|
|
|
98
91
|
## Destructive ops
|
|
99
92
|
|
|
100
|
-
Require `--yes` (or `CI=1`) for `delete
|
|
93
|
+
Require `--yes` (or `CI=1`) for `delete`.
|
|
101
94
|
|
|
102
95
|
## Exit codes
|
|
103
96
|
|
|
@@ -106,25 +99,25 @@ Require `--yes` (or `CI=1`) for `delete` commands.
|
|
|
106
99
|
| 0 | ok |
|
|
107
100
|
| 1 | usage |
|
|
108
101
|
| 2 | auth |
|
|
109
|
-
| 3 | forbidden |
|
|
102
|
+
| 3 | forbidden / missing scope |
|
|
110
103
|
| 4 | validation |
|
|
111
104
|
| 5 | not found |
|
|
112
105
|
| 6 | rate limited |
|
|
113
106
|
| 7 | network |
|
|
114
107
|
|
|
115
|
-
|
|
108
|
+
Failure JSON:
|
|
116
109
|
|
|
117
110
|
```json
|
|
118
|
-
{ "ok": false, "error": { "code": "validation", "message": "
|
|
111
|
+
{ "ok": false, "error": { "code": "validation", "message": "…", "details": null } }
|
|
119
112
|
```
|
|
120
113
|
|
|
121
114
|
## Pitfalls
|
|
122
115
|
|
|
123
|
-
-
|
|
124
|
-
- `--accounts`
|
|
125
|
-
-
|
|
126
|
-
- Platform-specific
|
|
127
|
-
- MCP OAuth
|
|
116
|
+
- Need workspace: `workspace use` or `--workspace` / `DUN_WORKSPACE_ID`
|
|
117
|
+
- `--accounts` = DunSocial social account **ids**, not handles
|
|
118
|
+
- Upload local files with `media upload` before attaching
|
|
119
|
+
- Platform-specific options via `--meta '{"reddit":{…}}'` when needed
|
|
120
|
+
- MCP OAuth and CLI tokens are different systems
|
|
128
121
|
|
|
129
122
|
## Help
|
|
130
123
|
|