dunsocial 0.8.1 → 0.9.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 CHANGED
@@ -6,9 +6,17 @@ Post and schedule to your social accounts from the terminal.
6
6
 
7
7
  ```bash
8
8
  npm install -g dunsocial
9
+ # or: bun add -g dunsocial / pnpm add -g dunsocial
9
10
  ```
10
11
 
11
- Then use the `dun` command (Node.js 20+).
12
+ Then use the `dun` command (Node.js 20+ — Bun not required at runtime).
13
+
14
+ Upgrade later:
15
+
16
+ ```bash
17
+ dun update
18
+ # or: dun update --check
19
+ ```
12
20
 
13
21
  ---
14
22
 
package/dist/index.js CHANGED
@@ -1,23 +1,26 @@
1
- #!/usr/bin/env bun
2
- // @bun
3
- import{mkdir as M0,readFile as CU,writeFile as j0,chmod as b0,unlink as S0}from"node:fs/promises";import{dirname as h0,join as AU}from"node:path";import{homedir as pU}from"node:os";var z={OK:0,USAGE:1,AUTH:2,FORBIDDEN:3,VALIDATION:4,NOT_FOUND:5,RATE_LIMITED:6,NETWORK:7};class Q extends Error{code;details;constructor(U,D=z.USAGE,O){super(U);this.name="CliError",this.code=D,this.details=O}}function $U(U){if(U===401)return z.AUTH;if(U===403)return z.FORBIDDEN;if(U===404)return z.NOT_FOUND;if(U===429)return z.RATE_LIMITED;if(U>=400&&U<500)return z.VALIDATION;return z.NETWORK}var nU="https://api.dunsocial.com",v="0.4.0";function fU(){if(process.env.DUN_CONFIG)return process.env.DUN_CONFIG;let U=process.env.XDG_CONFIG_HOME,D=U?U:AU(pU(),".config");return AU(D,"dunsocial","config.json")}async function iU(){let U=fU();try{let D=await CU(U,"utf8");return JSON.parse(D)}catch(D){if(D.code==="ENOENT")return{};throw new Q(`Failed to read config at ${U}: ${D.message}`,z.USAGE)}}async function KU(U){let D=await iU(),O=(U.apiUrl||process.env.DUN_API_URL||D.apiUrl||nU).replace(/\/$/,""),A=U.token||process.env.DUN_TOKEN||D.token,G=U.workspace||process.env.DUN_WORKSPACE_ID||D.defaultWorkspaceId||void 0,$=process.env.DUN_JSON==="0",V=!process.stdout.isTTY,K=$?!1:U.json===!0||process.env.DUN_JSON==="1"||process.env.CI==="true"||process.env.CI==="1"||V;return{apiUrl:O,token:A,workspaceId:G,json:K,debug:U.debug===!0||process.env.DUN_DEBUG==="1",quiet:U.quiet===!0,yes:U.yes===!0||process.env.CI==="true"||process.env.CI==="1",config:D}}function VU(U){let D={},O=[],A=0,G=!0;while(A<U.length){let Z=U[A];if(G&&Z==="--"){G=!1,A+=1;continue}if(G&&Z.startsWith("--")){let J=Z.indexOf("=");if(J!==-1){D[Z.slice(2,J)]=Z.slice(J+1),A+=1;continue}let q=Z.slice(2),Y=U[A+1];if(Y!==void 0&&!Y.startsWith("-"))D[q]=Y,A+=2;else D[q]=!0,A+=1;continue}if(G&&Z.startsWith("-")&&Z.length>1&&Z!=="-"){let J=Z.slice(1);if(J.length>1&&!J.includes("=")){for(let H of J)D[H]=!0;A+=1;continue}let q=J,Y=U[A+1];if(Y!==void 0&&!Y.startsWith("-"))D[q]=Y,A+=2;else D[q]=!0,A+=1;continue}O.push(Z),A+=1}let $=O[0],V,K,X=1;if($==="memory"&&(O[1]==="collections"||O[1]==="collection"))K="collections",V=O[2],X=V?3:2;else V=O[1],X=V?2:1;return{group:$,action:V,nest:K,flags:D,positionals:O.slice(X)}}function m(U,...D){for(let O of D){let A=U[O];if(typeof A==="string"&&A.length>0)return A}return}function B(U,...D){for(let O of D){let A=U[O];if(A===!0)return!0;if(typeof A==="string"){let G=A.toLowerCase();if(G==="1"||G==="true"||G==="yes")return!0}}return!1}function n(U){return B(U,"help","h")}function f(U){return B(U,"version","v","V")}function x(U,D){if(D.quiet&&!D.json)return;if(D.json||!process.stdout.isTTY){process.stdout.write(`${JSON.stringify({ok:!0,data:U},null,2)}
1
+ #!/usr/bin/env node
2
+ import{readFileSync as IU}from"node:fs";import{mkdir as mU,readFile as _U,writeFile as MU,chmod as vU,unlink as hU}from"node:fs/promises";import{dirname as SU,join as n}from"node:path";import{homedir as pU}from"node:os";var Q={OK:0,USAGE:1,AUTH:2,FORBIDDEN:3,VALIDATION:4,NOT_FOUND:5,RATE_LIMITED:6,NETWORK:7};class Z extends Error{code;details;constructor(U,u=Q.USAGE,$){super(U);this.name="CliError",this.code=u,this.details=$}}function t(U){if(U===401)return Q.AUTH;if(U===403)return Q.FORBIDDEN;if(U===404)return Q.NOT_FOUND;if(U===429)return Q.RATE_LIMITED;if(U>=400&&U<500)return Q.VALIDATION;return Q.NETWORK}var nU="https://api.dunsocial.com",UU="0.9.0";function CU(){if(!UU.includes("@@"))return UU;try{let U=JSON.parse(IU(n(import.meta.dir,"..","package.json"),"utf8"));if(typeof U.version==="string"&&U.version.length>0)return U.version}catch{}return"0.0.0"}var B=CU();function v(){if(process.env.DUN_CONFIG)return process.env.DUN_CONFIG;let U=process.env.XDG_CONFIG_HOME,u=U?U:n(pU(),".config");return n(u,"dunsocial","config.json")}function j(){return v()}async function C(){let U=v();try{let u=await _U(U,"utf8");return JSON.parse(u)}catch(u){if(u.code==="ENOENT")return{};throw new Z(`Failed to read config at ${U}: ${u.message}`,Q.USAGE)}}async function I(U){let u=v();await mU(SU(u),{recursive:!0});let $={...U,updatedAt:new Date().toISOString()};await MU(u,`${JSON.stringify($,null,2)}
3
+ `,"utf8");try{await vU(u,384)}catch{}}async function $U(){let U=v();try{await hU(U)}catch(u){if(u.code!=="ENOENT")throw new Z(`Failed to clear config: ${u.message}`,Q.USAGE)}}async function uU(U){let u=await C(),$=(U.apiUrl||process.env.DUN_API_URL||u.apiUrl||nU).replace(/\/$/,""),z=U.token||process.env.DUN_TOKEN||u.token,X=U.workspace||process.env.DUN_WORKSPACE_ID||u.defaultWorkspaceId||void 0,D=process.env.DUN_JSON==="0",O=!process.stdout.isTTY,w=D?!1:U.json===!0||process.env.DUN_JSON==="1"||process.env.CI==="true"||process.env.CI==="1"||O;return{apiUrl:$,token:z,workspaceId:X,json:w,debug:U.debug===!0||process.env.DUN_DEBUG==="1",quiet:U.quiet===!0,yes:U.yes===!0||process.env.CI==="true"||process.env.CI==="1",config:u}}function F(U){if(!U.token)throw new Z("Not authenticated. Run `dun auth login` (or `dun auth login --token <token>` / set DUN_TOKEN).",Q.AUTH);return U.token}function T(U){if(!U.workspaceId)throw new Z("No workspace selected. Run `dun workspace use <id|slug>` or pass --workspace / DUN_WORKSPACE_ID.",Q.VALIDATION);return U.workspaceId}function DU(U){let u={},$=[],z=0,X=!0;while(z<U.length){let Y=U[z];if(X&&Y==="--"){X=!1,z+=1;continue}if(X&&Y.startsWith("--")){let q=Y.indexOf("=");if(q!==-1){u[Y.slice(2,q)]=Y.slice(q+1),z+=1;continue}let y=Y.slice(2),W=U[z+1];if(W!==void 0&&!W.startsWith("-"))u[y]=W,z+=2;else u[y]=!0,z+=1;continue}if(X&&Y.startsWith("-")&&Y.length>1&&Y!=="-"){let q=Y.slice(1);if(q.length>1&&!q.includes("=")){for(let N of q)u[N]=!0;z+=1;continue}let y=q,W=U[z+1];if(W!==void 0&&!W.startsWith("-"))u[y]=W,z+=2;else u[y]=!0,z+=1;continue}$.push(Y),z+=1}let D=$[0],O,w,J=1;if(D==="memory"&&($[1]==="collections"||$[1]==="collection"))w="collections",O=$[2],J=O?3:2;else O=$[1],J=O?2:1;return{group:D,action:O,nest:w,flags:u,positionals:$.slice(J)}}function K(U,...u){for(let $ of u){let z=U[$];if(typeof z==="string"&&z.length>0)return z}return}function G(U,...u){for(let $ of u){let z=U[$];if(z===!0)return!0;if(typeof z==="string"){let X=z.toLowerCase();if(X==="1"||X==="true"||X==="yes")return!0}}return!1}function d(U,...u){let $=K(U,...u);if($===void 0)return;let z=Number($);if(!Number.isFinite(z))throw Error(`Invalid number for --${u[0]}: ${$}`);return z}function L(U,...u){let $=K(U,...u);if($===void 0)return;return $.split(",").map((z)=>z.trim()).filter(Boolean)}function E(U){return G(U,"help","h")}function f(U){return G(U,"version","v","V")}function V(U,u){if(u.quiet&&!u.json)return;if(u.json||!process.stdout.isTTY){process.stdout.write(`${JSON.stringify({ok:!0,data:U},null,2)}
4
4
  `);return}if(U===void 0||U===null){process.stdout.write(`ok
5
5
  `);return}if(typeof U==="string"){process.stdout.write(`${U}
6
- `);return}process.stdout.write(`${oU(U,D.emptyMessage)}
7
- `)}function zU(U,D){let{message:O,code:A,details:G}=cU(U);if(D.json||!process.stdout.isTTY)process.stdout.write(`${JSON.stringify({ok:!1,error:{code:xU(A),message:O,details:G??null}},null,2)}
8
- `);else if(process.stderr.write(`error: ${O}
9
- `),G!==void 0&&process.env.DUN_DEBUG==="1")process.stderr.write(`${JSON.stringify(G,null,2)}
10
- `);return A}function xU(U){switch(U){case z.AUTH:return"auth";case z.FORBIDDEN:return"forbidden";case z.VALIDATION:return"validation";case z.NOT_FOUND:return"not_found";case z.RATE_LIMITED:return"rate_limited";case z.NETWORK:return"network";default:return"usage"}}function cU(U){if(U instanceof Q)return{message:U.message,code:U.code,details:U.details};if(U instanceof Error)return{message:U.message,code:z.USAGE};return{message:String(U),code:z.USAGE}}function oU(U,D){if(Array.isArray(U)){if(U.length===0)return D??"(empty)";if(U.every((O)=>O&&typeof O==="object"))return GU(U,D);return U.map((O)=>`- ${i(O)}`).join(`
11
- `)}if(U&&typeof U==="object"){let O=U;if(Array.isArray(O.items)){if(O.items.length===0&&D)return D;let A=typeof O.total==="number"?`total=${O.total} showing=${O.items.length}`:void 0,G=GU(O.items,D);return A?`${A}
12
- ${G}`:G}return Object.entries(O).map(([A,G])=>`${A}: ${i(G)}`).join(`
13
- `)}return String(U)}function GU(U,D){if(U.length===0)return D??"(empty)";let O=["id","name","slug","status","providerName","username","displayName","role","scheduledAt","content","text","originalFilename","score","collectionId"],A=new Set;for(let Z of U)for(let J of Object.keys(Z))A.add(J);let G=[...O.filter((Z)=>A.has(Z)),...[...A].filter((Z)=>!O.includes(Z)).slice(0,6)].slice(0,8),$=U.map((Z)=>G.map((J)=>eU(i(Z[J]),J==="content"||J==="text"?48:28))),V=G.map((Z,J)=>Math.max(Z.length,...$.map((q)=>q[J]?.length??0))),K=G.map((Z,J)=>Z.padEnd(V[J])).join(" "),X=$.map((Z)=>Z.map((J,q)=>J.padEnd(V[q])).join(" ")).join(`
14
- `);return`${K}
15
- ${X}`}function i(U){if(U===null||U===void 0)return"";if(typeof U==="string")return U.replace(/\s+/g," ").trim();if(typeof U==="number"||typeof U==="boolean")return String(U);if(U instanceof Date)return U.toISOString();if(typeof U==="object"){let D=U;if(typeof D.id==="string"&&typeof D.name==="string")return`${D.name} (${D.id})`;if(typeof D.status==="string")return D.status;return JSON.stringify(U)}return String(U)}function eU(U,D){if(U.length<=D)return U;return`${U.slice(0,Math.max(0,D-1))}...`}var I={OK:0,USAGE:1,AUTH:2,FORBIDDEN:3,VALIDATION:4,NOT_FOUND:5,RATE_LIMITED:6,NETWORK:7};class c extends Error{code;details;constructor(U,D=I.USAGE,O){super(U);this.name="CliError",this.code=D,this.details=O}}var QU=`dun - schedule & publish social posts
6
+ `);return}process.stdout.write(`${eU(U,u.emptyMessage)}
7
+ `)}function OU(U,u){let{message:$,code:z,details:X}=fU(U);if(u.json||!process.stdout.isTTY)process.stdout.write(`${JSON.stringify({ok:!1,error:{code:EU(z),message:$,details:X??null}},null,2)}
8
+ `);else if(process.stderr.write(`error: ${$}
9
+ `),X!==void 0&&process.env.DUN_DEBUG==="1")process.stderr.write(`${JSON.stringify(X,null,2)}
10
+ `);return z}function EU(U){switch(U){case Q.AUTH:return"auth";case Q.FORBIDDEN:return"forbidden";case Q.VALIDATION:return"validation";case Q.NOT_FOUND:return"not_found";case Q.RATE_LIMITED:return"rate_limited";case Q.NETWORK:return"network";default:return"usage"}}function fU(U){if(U instanceof Z)return{message:U.message,code:U.code,details:U.details};if(U instanceof Error)return{message:U.message,code:Q.USAGE};return{message:String(U),code:Q.USAGE}}function eU(U,u){if(Array.isArray(U)){if(U.length===0)return u??"(empty)";if(U.every(($)=>$&&typeof $==="object"))return wU(U,u);return U.map(($)=>`- ${e($)}`).join(`
11
+ `)}if(U&&typeof U==="object"){let $=U;if(Array.isArray($.items)){if($.items.length===0&&u)return u;let z=typeof $.total==="number"?`total=${$.total} showing=${$.items.length}`:void 0,X=wU($.items,u);return z?`${z}
12
+ ${X}`:X}return Object.entries($).map(([z,X])=>`${z}: ${e(X)}`).join(`
13
+ `)}return String(U)}function wU(U,u){if(U.length===0)return u??"(empty)";let $=["id","name","slug","status","providerName","username","displayName","role","scheduledAt","content","text","originalFilename","score","collectionId"],z=new Set;for(let Y of U)for(let q of Object.keys(Y))z.add(q);let X=[...$.filter((Y)=>z.has(Y)),...[...z].filter((Y)=>!$.includes(Y)).slice(0,6)].slice(0,8),D=U.map((Y)=>X.map((q)=>iU(e(Y[q]),q==="content"||q==="text"?48:28))),O=X.map((Y,q)=>Math.max(Y.length,...D.map((y)=>y[q]?.length??0))),w=X.map((Y,q)=>Y.padEnd(O[q])).join(" "),J=D.map((Y)=>Y.map((q,y)=>q.padEnd(O[y])).join(" ")).join(`
14
+ `);return`${w}
15
+ ${J}`}function e(U){if(U===null||U===void 0)return"";if(typeof U==="string")return U.replace(/\s+/g," ").trim();if(typeof U==="number"||typeof U==="boolean")return String(U);if(U instanceof Date)return U.toISOString();if(typeof U==="object"){let u=U;if(typeof u.id==="string"&&typeof u.name==="string")return`${u.name} (${u.id})`;if(typeof u.status==="string")return u.status;return JSON.stringify(U)}return String(U)}function iU(U,u){if(U.length<=u)return U;return`${U.slice(0,Math.max(0,u-1))}...`}function m(U,u,$){if(!U)return;if($!==void 0){process.stderr.write(`[debug] ${u} ${JSON.stringify($)}
16
+ `);return}process.stderr.write(`[debug] ${u}
17
+ `)}function P(U,u){let $=`${U} ${u}`,z="-".repeat(Math.max(12,$.length+4));return`${$}
18
+ ${z}`}var i=`dun - schedule & publish social posts
16
19
 
17
20
  Usage:
18
21
  dun <command> [flags]
19
22
 
20
- Auth:
23
+ ${P("\uD83D\uDD10","Auth")}
21
24
  dun auth login # device-code browser flow
22
25
  dun auth login --token <token> # CI / headless
23
26
  dun auth login --no-browser
@@ -25,15 +28,15 @@ Auth:
25
28
  dun auth whoami
26
29
  dun auth status
27
30
 
28
- Workspaces:
31
+ ${P("\uD83D\uDCC1","Workspaces")}
29
32
  dun workspace list
30
33
  dun workspace use <id|slug>
31
34
  dun workspace current
32
35
 
33
- Accounts:
36
+ ${P("\uD83D\uDD17","Accounts")}
34
37
  dun accounts list [--platform x]
35
38
 
36
- Posts:
39
+ ${P("\uD83D\uDCDD","Posts")}
37
40
  dun posts list [--status scheduled|published|failed|draft|cancelled]
38
41
  dun posts get <id>
39
42
  dun posts schedule --text "..." --accounts <id,id> (--at ISO | --in 2h) [--media id,id]
@@ -43,20 +46,20 @@ Posts:
43
46
  dun posts delete <id> [--yes]
44
47
  dun posts x-cap
45
48
 
46
- Drafts:
49
+ ${P("\uD83D\uDCC4","Drafts")}
47
50
  dun drafts list
48
51
  dun drafts get <id>
49
52
  dun drafts create --text "..." [--platforms x,linkedin] [--accounts id,id]
50
53
  dun drafts update <id> --text "..."
51
54
  dun drafts delete <id> [--yes]
52
55
 
53
- Media:
56
+ ${P("\uD83D\uDDBC️","Media")}
54
57
  dun media list
55
58
  dun media get <id>
56
59
  dun media upload <file> [--alt "..."]
57
60
  dun media delete <id> [--yes]
58
61
 
59
- Memory:
62
+ ${P("\uD83E\uDDE0","Memory")}
60
63
  dun memory collections list
61
64
  dun memory collections create --name "..." [--color blue] [--private]
62
65
  dun memory list --collection <id>
@@ -64,21 +67,29 @@ Memory:
64
67
  dun memory search --prompt "..." --collections <id,id> [--top-k 5]
65
68
  dun memory delete <id> --collection <id> [--yes]
66
69
 
67
- Personalization (workspace AI voice):
70
+ ${P("\uD83C\uDF99️","Personalization")}
71
+ # workspace AI voice
68
72
  dun personalization get
69
73
  dun personalization set --description "..."
70
74
  dun personalization set --file voice.md
71
75
  dun personalization set --clear
72
76
  # requires PAT scope workspace:write for set (owner/admin)
73
77
 
74
- Agent skills:
78
+ ${P("\uD83E\uDDE9","Agent skills")}
75
79
  dun skill install <agent|all>
76
80
  dun skill list
77
81
  dun skill path
78
82
  # agents: claude codex cursor pi opencode agents copilot windsurf
79
83
  # goose gemini amp grok continue antigravity
80
84
 
81
- Global flags:
85
+ ${P("⬆️","Update")}
86
+ dun update # upgrade to latest from npm
87
+ dun update --check # report only
88
+ dun update --force # reinstall latest even if current
89
+ # aliases: upgrade, self-update
90
+ # detects npm / bun / pnpm / yarn; prints command for npx
91
+
92
+ ${P("⚙️","Global flags")}
82
93
  --json Machine-readable output (default when non-TTY / CI)
83
94
  --workspace <id> Override workspace for this command
84
95
  --api-url <url> Override API base (default https://api.dunsocial.com)
@@ -89,14 +100,14 @@ Global flags:
89
100
  --help, -h Show help
90
101
  --version, -v Show version
91
102
 
92
- Env:
103
+ ${P("\uD83C\uDF31","Env")}
93
104
  DUN_TOKEN DUN_WORKSPACE_ID DUN_API_URL DUN_CONFIG DUN_JSON=1 DUN_DEBUG=1
94
105
 
95
- Exit codes:
106
+ ${P("\uD83D\uDEAA","Exit codes")}
96
107
  0 ok | 1 usage | 2 auth | 3 forbidden | 4 validation | 5 not found | 6 rate limit | 7 network
97
108
 
98
109
  Docs: https://dunsocial.com/docs/cli
99
- `;function o(U){return{auth:`dun auth
110
+ `;function g(U){return{auth:`dun auth
100
111
 
101
112
  login [--token] Device-code browser login (default) or --token for CI
102
113
  logout Clear local config
@@ -129,136 +140,48 @@ Workspace-scoped (not per-user). set requires owner/admin + PAT scope workspace:
129
140
  Alias: dun voice ...
130
141
  `,voice:"Alias of personalization",skill:`dun skill install <claude|codex|cursor|pi|opencode|agents|copilot|windsurf|goose|gemini|amp|grok|continue|antigravity|all>
131
142
  dun skill list
132
- dun skill path`}[U]??`dun - schedule & publish social posts
133
-
134
- Usage:
135
- dun <command> [flags]
136
-
137
- Auth:
138
- dun auth login # device-code browser flow
139
- dun auth login --token <token> # CI / headless
140
- dun auth login --no-browser
141
- dun auth logout
142
- dun auth whoami
143
- dun auth status
144
-
145
- Workspaces:
146
- dun workspace list
147
- dun workspace use <id|slug>
148
- dun workspace current
149
-
150
- Accounts:
151
- dun accounts list [--platform x]
152
-
153
- Posts:
154
- dun posts list [--status scheduled|published|failed|draft|cancelled]
155
- dun posts get <id>
156
- dun posts schedule --text "..." --accounts <id,id> (--at ISO | --in 2h) [--media id,id]
157
- dun posts publish --text "..." --accounts <id,id> [--media id,id] [--natural]
158
- dun posts reschedule <id> --at ISO|--in 2h [--text "..."]
159
- dun posts cancel <id>
160
- dun posts delete <id> [--yes]
161
- dun posts x-cap
143
+ dun skill path`,update:`dun update
162
144
 
163
- Drafts:
164
- dun drafts list
165
- dun drafts get <id>
166
- dun drafts create --text "..." [--platforms x,linkedin] [--accounts id,id]
167
- dun drafts update <id> --text "..."
168
- dun drafts delete <id> [--yes]
145
+ (no args) Check npm and upgrade via detected package manager
146
+ --check Report current vs latest only
147
+ --force Reinstall latest even if versions match
169
148
 
170
- Media:
171
- dun media list
172
- dun media get <id>
173
- dun media upload <file> [--alt "..."]
174
- dun media delete <id> [--yes]
175
-
176
- Memory:
177
- dun memory collections list
178
- dun memory collections create --name "..." [--color blue] [--private]
179
- dun memory list --collection <id>
180
- dun memory save --collection <id> --text "..."
181
- dun memory search --prompt "..." --collections <id,id> [--top-k 5]
182
- dun memory delete <id> --collection <id> [--yes]
183
-
184
- Personalization (workspace AI voice):
185
- dun personalization get
186
- dun personalization set --description "..."
187
- dun personalization set --file voice.md
188
- dun personalization set --clear
189
- # requires PAT scope workspace:write for set (owner/admin)
190
-
191
- Agent skills:
192
- dun skill install <agent|all>
193
- dun skill list
194
- dun skill path
195
- # agents: claude codex cursor pi opencode agents copilot windsurf
196
- # goose gemini amp grok continue antigravity
197
-
198
- Global flags:
199
- --json Machine-readable output (default when non-TTY / CI)
200
- --workspace <id> Override workspace for this command
201
- --api-url <url> Override API base (default https://api.dunsocial.com)
202
- --token <token> Override bearer token for this command
203
- --debug Log HTTP method/path/status to stderr
204
- --quiet Suppress human success output
205
- --yes Skip destructive confirmations
206
- --help, -h Show help
207
- --version, -v Show version
208
-
209
- Env:
210
- DUN_TOKEN DUN_WORKSPACE_ID DUN_API_URL DUN_CONFIG DUN_JSON=1 DUN_DEBUG=1
211
-
212
- Exit codes:
213
- 0 ok | 1 usage | 2 auth | 3 forbidden | 4 validation | 5 not found | 6 rate limit | 7 network
214
-
215
- Docs: https://dunsocial.com/docs/cli
216
- `}import{mkdir as gU,readFile as c0,writeFile as rU,chmod as lU,unlink as sU}from"node:fs/promises";import{dirname as tU,join as XU}from"node:path";import{homedir as aU}from"node:os";var M="0.4.0";function e(){if(process.env.DUN_CONFIG)return process.env.DUN_CONFIG;let U=process.env.XDG_CONFIG_HOME,D=U?U:XU(aU(),".config");return XU(D,"dunsocial","config.json")}function j(){return e()}async function b(U){let D=e();await gU(tU(D),{recursive:!0});let O={...U,updatedAt:new Date().toISOString()};await rU(D,`${JSON.stringify(O,null,2)}
217
- `,"utf8");try{await lU(D,384)}catch{}}async function ZU(){let U=e();try{await sU(U)}catch(D){if(D.code!=="ENOENT")throw new Q(`Failed to clear config: ${D.message}`,z.USAGE)}}function N(U){if(!U.token)throw new Q("Not authenticated. Run `dun auth login` (or `dun auth login --token <token>` / set DUN_TOKEN).",z.AUTH);return U.token}function P(U){if(!U.workspaceId)throw new Q("No workspace selected. Run `dun workspace use <id|slug>` or pass --workspace / DUN_WORKSPACE_ID.",z.VALIDATION);return U.workspaceId}var JU=["█▀▀▄ █ █ █▀▀▄ █▀▀▀ █▀▀█ █▀▀▀ ▀█▀ █▀▀█ █","█ █ █ █ █ █ ▀▀▀█ █ █ █ █ █▀▀█ █","▀▀▀▀ ▀▀▀▀ ▀ ▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀"].join(`
218
- `),RU=["█▀▀▄ █ █ █▀▀▄","█ █ █ █ █ █","▀▀▀▀ ▀▀▀▀ ▀ ▀",""," DunSocial"].join(`
219
- `),U0="DunSocial",O0=wU(JU),D0=wU(RU);function wU(U){return Math.max(...U.split(`
220
- `).map((D)=>D.length))}function g(U=process.stderr){if(!U.isTTY)return!1;if(process.env.CI==="true"||process.env.CI==="1")return!1;if(process.env.GITHUB_ACTIONS||process.env.TF_BUILD||process.env.GITLAB_CI)return!1;if(process.env.DUN_JSON==="1")return!1;return!0}function YU(U=process.stdout.columns??80){let D=U>0?U:80;if(D>=O0)return JU;if(D>=D0)return RU;return U0}function $0(U=process.stdout.columns??80){return`${YU(U)}
221
-
222
- Schedule & publish from the terminal | v${M}`}function qU(U=process.stderr,D={}){if(!g(U))return;let O=D.columns??U.columns??process.stdout.columns??80,A=D.tagline?$0(O):YU(O);U.write(`
223
- ${A}
224
-
225
- `)}function R(U,D){if(D.quiet&&!D.json)return;if(D.json||!process.stdout.isTTY){process.stdout.write(`${JSON.stringify({ok:!0,data:U},null,2)}
226
- `);return}if(U===void 0||U===null){process.stdout.write(`ok
227
- `);return}if(typeof U==="string"){process.stdout.write(`${U}
228
- `);return}process.stdout.write(`${A0(U,D.emptyMessage)}
229
- `)}function A0(U,D){if(Array.isArray(U)){if(U.length===0)return D??"(empty)";if(U.every((O)=>O&&typeof O==="object"))return TU(U,D);return U.map((O)=>`- ${r(O)}`).join(`
230
- `)}if(U&&typeof U==="object"){let O=U;if(Array.isArray(O.items)){if(O.items.length===0&&D)return D;let A=typeof O.total==="number"?`total=${O.total} showing=${O.items.length}`:void 0,G=TU(O.items,D);return A?`${A}
231
- ${G}`:G}return Object.entries(O).map(([A,G])=>`${A}: ${r(G)}`).join(`
232
- `)}return String(U)}function TU(U,D){if(U.length===0)return D??"(empty)";let O=["id","name","slug","status","providerName","username","displayName","role","scheduledAt","content","text","originalFilename","score","collectionId"],A=new Set;for(let Z of U)for(let J of Object.keys(Z))A.add(J);let G=[...O.filter((Z)=>A.has(Z)),...[...A].filter((Z)=>!O.includes(Z)).slice(0,6)].slice(0,8),$=U.map((Z)=>G.map((J)=>K0(r(Z[J]),J==="content"||J==="text"?48:28))),V=G.map((Z,J)=>Math.max(Z.length,...$.map((q)=>q[J]?.length??0))),K=G.map((Z,J)=>Z.padEnd(V[J])).join(" "),X=$.map((Z)=>Z.map((J,q)=>J.padEnd(V[q])).join(" ")).join(`
233
- `);return`${K}
234
- ${X}`}function r(U){if(U===null||U===void 0)return"";if(typeof U==="string")return U.replace(/\s+/g," ").trim();if(typeof U==="number"||typeof U==="boolean")return String(U);if(U instanceof Date)return U.toISOString();if(typeof U==="object"){let D=U;if(typeof D.id==="string"&&typeof D.name==="string")return`${D.name} (${D.id})`;if(typeof D.status==="string")return D.status;return JSON.stringify(U)}return String(U)}function K0(U,D){if(U.length<=D)return U;return`${U.slice(0,Math.max(0,D-1))}...`}function S(U,D,O){if(!U)return;if(O!==void 0){process.stderr.write(`[debug] ${D} ${JSON.stringify(O)}
235
- `);return}process.stderr.write(`[debug] ${D}
236
- `)}class NU{ctx;constructor(U){this.ctx=U}async request(U){let D=U.method??"GET",O=new URL(U.path.startsWith("http")?U.path:`${this.ctx.apiUrl}${U.path}`);if(U.query)for(let[X,Z]of Object.entries(U.query)){if(Z===void 0||Z===null||Z==="")continue;O.searchParams.set(X,String(Z))}let A={Accept:"application/json","User-Agent":`dunsocial-cli/${M}`,...U.headers??{}};if(U.auth!==!1)A.Authorization=`Bearer ${N(this.ctx)}`;if(U.workspace)A["X-Workspace-Id"]=P(this.ctx);let G;if(U.body!==void 0)A["Content-Type"]="application/json",G=JSON.stringify(U.body);S(this.ctx.debug,`${D} ${O.toString()}`);let $;try{$=await fetch(O,{method:D,headers:A,body:G})}catch(X){throw new Q(`Network error: ${X.message}`,z.NETWORK,{cause:String(X)})}let V=await $.text(),K=null;if(V)try{K=JSON.parse(V)}catch{K=null}if(S(this.ctx.debug,`<- ${$.status}`,{ok:$.ok,bodyPreview:V.slice(0,300)}),!$.ok){let X=K?.error||K?.message||(V?V.slice(0,300):`HTTP ${$.status}`);throw new Q(X,$U($.status),{status:$.status,body:K??V})}if(K&&typeof K==="object"&&"success"in K){if(K.success===!1)throw new Q(K.error||K.message||"Request failed",z.VALIDATION,K);return K.data}return K??void 0}get(U,D){return this.request({...D,method:"GET",path:U})}post(U,D,O){return this.request({...O,method:"POST",path:U,body:D})}patch(U,D,O){return this.request({...O,method:"PATCH",path:U,body:D})}delete(U,D,O){return this.request({...O,method:"DELETE",path:U,body:D})}}function T(U){return new NU(U)}function w(U,...D){for(let O of D){let A=U[O];if(typeof A==="string"&&A.length>0)return A}return}function u(U,...D){for(let O of D){let A=U[O];if(A===!0)return!0;if(typeof A==="string"){let G=A.toLowerCase();if(G==="1"||G==="true"||G==="yes")return!0}}return!1}function F(U,...D){let O=w(U,...D);if(O===void 0)return;let A=Number(O);if(!Number.isFinite(A))throw Error(`Invalid number for --${D[0]}: ${O}`);return A}function _(U,...D){let O=w(U,...D);if(O===void 0)return;return O.split(",").map((A)=>A.trim()).filter(Boolean)}var V0=["█▀▀▄ █ █ █▀▀▄ █▀▀▀ █▀▀█ █▀▀▀ ▀█▀ █▀▀█ █","█ █ █ █ █ █ ▀▀▀█ █ █ █ █ █▀▀█ █","▀▀▀▀ ▀▀▀▀ ▀ ▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀"].join(`
237
- `),WU=["█▀▀▄ █ █ █▀▀▄","█ █ █ █ █ █","▀▀▀▀ ▀▀▀▀ ▀ ▀",""," DunSocial"].join(`
238
- `);var VO=PU(V0),GO=PU(WU);function PU(U){return Math.max(...U.split(`
239
- `).map((D)=>D.length))}function d(U=process.stderr){if(!U.isTTY)return!1;if(process.env.CI==="true"||process.env.CI==="1")return!1;if(process.env.GITHUB_ACTIONS||process.env.TF_BUILD||process.env.GITLAB_CI)return!1;if(process.env.DUN_JSON==="1")return!1;return!0}function uU(){return WU}async function HU(U,D,O,A){switch(D){case"login":return G0(U,O);case"logout":return X0(U);case"whoami":return Z0(U);case"status":return J0(U);default:throw new Q(`Unknown auth command "${D??""}". Try: login, logout, whoami, status`,z.USAGE)}}async function G0(U,D){let O=w(D,"token")||process.env.DUN_TOKEN;if(O)return z0(U,O);return Q0(U,D)}function E(U){if(U)return"Logged in.";return`Logged in.
240
- Next: dun workspace list && dun workspace use <id|slug>`}async function z0(U,D){let O={...U,token:D},G=await T(O).get("/api/user/profile");if(await b({...U.config,apiUrl:U.apiUrl,token:D,defaultWorkspaceId:U.config.defaultWorkspaceId,defaultWorkspaceSlug:U.config.defaultWorkspaceSlug,defaultWorkspaceName:U.config.defaultWorkspaceName}),!U.json&&d(process.stdout)){R(E(Boolean(U.config.defaultWorkspaceId)),U);return}R({user:{id:G.id,name:G.name,email:G.email},configPath:j(),method:"token",message:E(Boolean(U.config.defaultWorkspaceId))},U)}async function Q0(U,D){let O=T({...U,token:void 0}),A=await O.post("/api/cli/auth/start",{clientName:"dun-cli"},{auth:!1}),G=!u(D,"no-browser");if(!U.json){if(d(process.stderr))process.stderr.write(`
241
- ${uU()}
149
+ Aliases: dun upgrade, dun self-update
150
+ `,upgrade:"Alias of update","self-update":"Alias of update"}[U]??i}var gU=["DunSocial","---------"].join(`
151
+ `),zU="DunSocial";var C$=QU(gU),E$=QU(zU);function QU(U){return Math.max(...U.split(`
152
+ `).map((u)=>u.length))}function A(U=process.stderr){if(!U.isTTY)return!1;if(process.env.CI==="true"||process.env.CI==="1")return!1;if(process.env.GITHUB_ACTIONS||process.env.TF_BUILD||process.env.GITLAB_CI)return!1;if(process.env.DUN_JSON==="1")return!1;return!0}function XU(){return`DunSocial CLI v${B}`}function ZU(){return`${zU}
153
+ CLI v${B}`}var oU="https://dunsocial.com/docs/cli";function xU(U){if(!U.token)return"signed_out";if(!U.workspaceId)return"needs_workspace";return"ready"}function JU(U){let u=xU(U),$=[`DunSocial CLI v${B}`,""];if(u==="signed_out")$.push("Not signed in.",""," Next: dun auth login");else if(u==="needs_workspace")$.push("Signed in — pick a workspace.",""," Next: dun workspace list"," dun workspace use <slug>");else{let z=U.config.defaultWorkspaceSlug||U.config.defaultWorkspaceName||U.workspaceId||"workspace";$.push(`Ready | workspace: ${z}`,""," Tip: dun accounts list"," dun posts list")}return $.push(""," dun --help all commands",` Docs ${oU}`,""),$.join(`
154
+ `)}import{spawn as cU}from"node:child_process";class VU{ctx;constructor(U){this.ctx=U}async request(U){let u=U.method??"GET",$=new URL(U.path.startsWith("http")?U.path:`${this.ctx.apiUrl}${U.path}`);if(U.query)for(let[J,Y]of Object.entries(U.query)){if(Y===void 0||Y===null||Y==="")continue;$.searchParams.set(J,String(Y))}let z={Accept:"application/json","User-Agent":`dunsocial-cli/${B}`,...U.headers??{}};if(U.auth!==!1)z.Authorization=`Bearer ${F(this.ctx)}`;if(U.workspace)z["X-Workspace-Id"]=T(this.ctx);let X;if(U.body!==void 0)z["Content-Type"]="application/json",X=JSON.stringify(U.body);m(this.ctx.debug,`${u} ${$.toString()}`);let D;try{D=await fetch($,{method:u,headers:z,body:X})}catch(J){throw new Z(`Network error: ${J.message}`,Q.NETWORK,{cause:String(J)})}let O=await D.text(),w=null;if(O)try{w=JSON.parse(O)}catch{w=null}if(m(this.ctx.debug,`<- ${D.status}`,{ok:D.ok,bodyPreview:O.slice(0,300)}),!D.ok){let J=w?.error||w?.message||(O?O.slice(0,300):`HTTP ${D.status}`);throw new Z(J,t(D.status),{status:D.status,body:w??O})}if(w&&typeof w==="object"&&"success"in w){if(w.success===!1)throw new Z(w.error||w.message||"Request failed",Q.VALIDATION,w);return w.data}return w??void 0}get(U,u){return this.request({...u,method:"GET",path:U})}post(U,u,$){return this.request({...$,method:"POST",path:U,body:u})}patch(U,u,$){return this.request({...$,method:"PATCH",path:U,body:u})}delete(U,u,$){return this.request({...$,method:"DELETE",path:U,body:u})}}function k(U){return new VU(U)}async function YU(U,u,$,z){switch(u){case"login":return rU(U,$);case"logout":return aU(U);case"whoami":return tU(U);case"status":return U$(U);default:throw new Z(`Unknown auth command "${u??""}". Try: login, logout, whoami, status`,Q.USAGE)}}async function rU(U,u){let $=K(u,"token")||process.env.DUN_TOKEN;if($)return sU(U,$);return lU(U,u)}function h(U){if(U)return"Logged in.";return`Logged in.
155
+ Next: dun workspace list && dun workspace use <id|slug>`}async function sU(U,u){let $={...U,token:u},X=await k($).get("/api/user/profile");if(await I({...U.config,apiUrl:U.apiUrl,token:u,defaultWorkspaceId:U.config.defaultWorkspaceId,defaultWorkspaceSlug:U.config.defaultWorkspaceSlug,defaultWorkspaceName:U.config.defaultWorkspaceName}),!U.json&&A(process.stdout)){V(h(Boolean(U.config.defaultWorkspaceId)),U);return}V({user:{id:X.id,name:X.name,email:X.email},configPath:j(),method:"token",message:h(Boolean(U.config.defaultWorkspaceId))},U)}async function lU(U,u){let $=k({...U,token:void 0}),z=await $.post("/api/cli/auth/start",{clientName:"dun-cli"},{auth:!1}),X=!G(u,"no-browser");if(!U.json){if(A(process.stderr))process.stderr.write(`
156
+ ${ZU()}
242
157
 
243
158
  `);else process.stderr.write(`
244
159
  DunSocial CLI login
245
160
  `),process.stderr.write(`───────────────────
246
161
  `);process.stderr.write(`In your browser, open:
247
- ${A.verificationUrlComplete}
162
+ ${z.verificationUrlComplete}
248
163
 
249
- `),process.stderr.write(`Or go to ${A.verificationUrl} and enter code:
250
- `),process.stderr.write(` ${A.userCode}
164
+ `),process.stderr.write(`Or go to ${z.verificationUrl} and enter code:
165
+ `),process.stderr.write(` ${z.userCode}
251
166
 
252
167
  `),process.stderr.write(`Waiting for approval...
253
- `)}else process.stderr.write(JSON.stringify({ok:!0,phase:"waiting",userCode:A.userCode,verificationUrlComplete:A.verificationUrlComplete})+`
254
- `);if(G&&process.stdout.isTTY)try{await w0(A.verificationUrlComplete)}catch{}let $=Math.max(3,A.interval||5)*1000,V=Date.now()+(A.expiresIn||900)*1000;while(Date.now()<V){await R0($);let K=await O.post("/api/cli/auth/poll",{deviceCode:A.deviceCode},{auth:!1});if(K.status==="pending")continue;if(K.status==="expired")throw new Q("Login expired. Run dun auth login again.",z.AUTH);if(K.status==="denied")throw new Q("Login was denied in the browser.",z.AUTH);if(K.status==="approved"){let X=K.token,Z={...U,token:X},J=T(Z),q=await J.get("/api/user/profile"),Y={...U.config,apiUrl:U.apiUrl,token:X,defaultWorkspaceId:K.workspaceId||U.config.defaultWorkspaceId,defaultWorkspaceSlug:U.config.defaultWorkspaceSlug,defaultWorkspaceName:U.config.defaultWorkspaceName};if(K.workspaceId)try{let L=(await J.get("/api/workspaces")).find((k)=>k.id===K.workspaceId);if(L)Y.defaultWorkspaceId=L.id,Y.defaultWorkspaceSlug=L.slug,Y.defaultWorkspaceName=L.name}catch{}await b(Y);let H=Boolean(Y.defaultWorkspaceId);if(!U.json&&d(process.stdout)){R(E(H),U);return}R({user:{id:q.id,name:q.name,email:q.email},workspaceId:Y.defaultWorkspaceId??null,configPath:j(),method:"device",message:E(H)},U);return}}throw new Q("Login timed out. Run dun auth login again.",z.AUTH)}async function X0(U){if(await ZU(),!U.json&&d(process.stdout)){R("Logged out. Config cleared.",U);return}R({message:"Logged out. Config cleared.",configPath:j()},U)}async function Z0(U){N(U);let O=await T(U).get("/api/user/profile");R({id:O.id,name:O.name,email:O.email,image:O.image??null,apiUrl:U.apiUrl,workspaceId:U.workspaceId??null},U)}async function J0(U){let D=Boolean(U.token),O=null,A=null;if(D)try{O=await T(U).get("/api/user/profile")}catch(G){A=G instanceof Error?G.message:String(G)}R({authenticated:Boolean(O),tokenPresent:D,apiUrl:U.apiUrl,workspaceId:U.workspaceId??null,workspaceSlug:U.config.defaultWorkspaceSlug??null,workspaceName:U.config.defaultWorkspaceName??null,configPath:j(),user:O?{id:O.id,name:O.name,email:O.email}:null,error:A},U)}function R0(U){return new Promise((D)=>setTimeout(D,U))}async function w0(U){let D=process.platform,O=D==="darwin"?["open",U]:D==="win32"?["cmd","/c","start","",U]:["xdg-open",U];await Bun.spawn(O,{stdout:"ignore",stderr:"ignore"}).exited}async function FU(U,D,O,A){N(U);let G=T(U);switch(D){case"list":case"ls":{let $=await G.get("/api/workspaces");R($.map((V)=>({id:V.id,name:V.name,slug:V.slug,role:V.role,timezone:V.timezone,plan:V.subscription?.planName??null,status:V.subscription?.status??null})),{...U,emptyMessage:"No workspaces yet."});return}case"use":{let $=A[0];if(!$)throw new Q("Usage: dun workspace use <id|slug>",z.USAGE);let K=(await G.get("/api/workspaces")).find((X)=>X.id===$||X.slug===$);if(!K)throw new Q(`Workspace not found: ${$}. Run dun workspace list`,z.NOT_FOUND);await b({...U.config,apiUrl:U.apiUrl,token:U.token,defaultWorkspaceId:K.id,defaultWorkspaceSlug:K.slug,defaultWorkspaceName:K.name}),R({id:K.id,name:K.name,slug:K.slug,role:K.role,message:`Default workspace set to ${K.name}`},U);return}case"current":{if(!U.workspaceId&&!U.config.defaultWorkspaceId)throw new Q("No workspace selected. Run dun workspace use <id|slug>",z.VALIDATION);let $=U.workspaceId||U.config.defaultWorkspaceId;try{let K=(await G.get("/api/workspaces")).find((X)=>X.id===$||X.slug===$);if(K){R({id:K.id,name:K.name,slug:K.slug,role:K.role,timezone:K.timezone},U);return}}catch{}R({id:$,name:U.config.defaultWorkspaceName??null,slug:U.config.defaultWorkspaceSlug??null},U);return}default:throw new Q(`Unknown workspace command "${D??""}". Try: list, use, current`,z.USAGE)}}async function _U(U,D,O,A){N(U),P(U);let G=T(U);switch(D){case void 0:case"list":case"ls":{let $=await G.get("/api/social-accounts",{workspace:!0}),V=w(O,"platform","p")?.toLowerCase(),K=V?$.filter((X)=>{let Z=(X.providerName||"").toLowerCase();return({x:["x","twitter"],twitter:["x","twitter"],linkedin:["linkedin"],"linkedin-business":["linkedin business","linkedin-business","linkedin_business"],bluesky:["bluesky"],threads:["threads"],reddit:["reddit"],pinterest:["pinterest"],instagram:["instagram"],youtube:["youtube"],tiktok:["tiktok"]}[V]??[V]).some((Y)=>Z.includes(Y))}):$;R(K.map((X)=>({id:X.id,providerName:X.providerName,username:X.username??null,displayName:X.displayName??null,isConnected:X.isConnected,expiresAt:X.expiresAt??null})),{...U,emptyMessage:V?`No ${V} accounts connected. Connect one in the DunSocial dashboard.`:"No accounts connected. Connect one in the DunSocial dashboard."});return}default:throw new Q(`Unknown accounts command "${D}". Try: list`,z.USAGE)}}var Y0=/^(\d+)\s*(s|sec|secs|second|seconds|m|min|mins|minute|minutes|h|hr|hrs|hour|hours|d|day|days|w|week|weeks)$/i;function l(U,D=new Date){let O=U.trim();if(!O)throw new Q("Empty time value",z.VALIDATION);let A=O.match(Y0);if(A){let V=Number(A[1]),K=A[2].toLowerCase(),X=q0(K)*V;return new Date(D.getTime()+X)}let G=O.match(/^in\s+(.+)$/i);if(G)return l(G[1],D);let $=new Date(O);if(Number.isNaN($.getTime()))throw new Q(`Invalid time "${U}". Use ISO-8601 (2026-06-01T09:00:00Z) or relative (2h, 30m, 1d).`,z.VALIDATION);return $}function q0(U){switch(U){case"s":case"sec":case"secs":case"second":case"seconds":return 1000;case"m":case"min":case"mins":case"minute":case"minutes":return 60000;case"h":case"hr":case"hrs":case"hour":case"hours":return 3600000;case"d":case"day":case"days":return 86400000;case"w":case"week":case"weeks":return 604800000;default:throw new Q(`Unknown time unit: ${U}`,z.VALIDATION)}}function C(U){if(U.at&&U.in)throw new Q("Pass only one of --at or --in",z.VALIDATION);if(U.at)return l(U.at).toISOString();if(U.in)return l(U.in).toISOString();throw new Q("Schedule time required. Pass --at <iso> or --in <duration> (e.g. 2h).",z.VALIDATION)}function yU(U){if(!U)return[];return U.split(",").map((D)=>D.trim()).filter(Boolean)}function IU(U){let D=w(U,"text","content","c","t");if(!D)throw new Q("Missing --text",z.VALIDATION);return D}function s(U){let D=_(U,"accounts","account","a")??yU(w(U,"accounts","account","a"));if(!D||D.length===0)throw new Q("Missing --accounts <id,id>",z.VALIDATION);return D}function t(U){return _(U,"media","media-urls")??yU(w(U,"media","media-urls"))}function h(U){let D=w(U,"meta","metadata","meta-json");if(!D)return;try{let O=JSON.parse(D);if(!O||typeof O!=="object"||Array.isArray(O))throw Error("metadata must be a JSON object");return O}catch(O){throw new Q(`Invalid --meta JSON: ${O.message}`,z.VALIDATION)}}async function BU(U,D,O,A){N(U),P(U);let G=T(U);switch(D){case"list":case"ls":{let $=await G.get("/api/posts",{workspace:!0,query:{status:w(O,"status","s"),socialAccountId:w(O,"account","social-account"),groupId:w(O,"group"),limit:F(O,"limit")??50,offset:F(O,"offset")??0}});R($,{...U,emptyMessage:"No posts yet. Schedule one with dun posts schedule."});return}case"get":{let $=A[0];if(!$)throw new Q("Usage: dun posts get <id>",z.USAGE);let V=await G.get(`/api/posts/${$}`,{workspace:!0});R(V,U);return}case"schedule":{let $=IU(O),V=s(O),K=C({at:w(O,"at"),in:w(O,"in")}),X=await G.post("/api/posts/schedule",{content:$,socialAccountIds:V,scheduledAt:K,mediaUrls:t(O),metadata:h(O)??{}},{workspace:!0});R(X,U);return}case"publish":case"publish-now":{let $=IU(O),V=s(O),K=await G.post("/api/posts/publish-now",{content:$,socialAccountIds:V,mediaUrls:t(O),metadata:h(O)??{},naturalPosting:u(O,"natural","natural-posting")},{workspace:!0});R(K,U);return}case"reschedule":{let $=A[0];if(!$)throw new Q("Usage: dun posts reschedule <id> --at|--in",z.USAGE);let K={scheduledAt:C({at:w(O,"at"),in:w(O,"in")})},X=w(O,"text","content","c","t");if(X)K.content=X;let Z=t(O);if(Z.length)K.mediaUrls=Z;let J=h(O);if(J)K.metadata=J;if(!K.content){let Y=await G.get(`/api/posts/${$}`,{workspace:!0});if(K.content=Y.content,!K.metadata&&Y.metadata)K.metadata=Y.metadata;if(!K.mediaUrls&&Y.mediaUrls)K.mediaUrls=Y.mediaUrls}let q=await G.post(`/api/posts/${$}/reschedule`,K,{workspace:!0});R(q,U);return}case"cancel":{let $=A[0];if(!$)throw new Q("Usage: dun posts cancel <id>",z.USAGE);let V=await G.post(`/api/posts/${$}/cancel`,void 0,{workspace:!0});R(V??{id:$,status:"cancelled"},U);return}case"delete":case"rm":{let $=A[0];if(!$)throw new Q("Usage: dun posts delete <id> [--yes]",z.USAGE);if(!U.yes&&!u(O,"yes","y"))throw new Q("Refusing to delete without --yes (or CI/yes mode)",z.VALIDATION);let V=await G.delete(`/api/posts/${$}`,void 0,{workspace:!0});R(V??{id:$,deleted:!0},U);return}case"x-cap":case"xcap":{let $=await G.get("/api/posts/x-cap-usage",{workspace:!0});R($,U);return}case"schedule-thread":case"publish-thread":case"publish-thread-now":{let $=w(O,"file","f"),V=w(O,"account","accounts","a")??s(O)[0];if(!V)throw new Q("Missing --account <xAccountId>",z.VALIDATION);let K;if($){let Z=await Bun.file($).text(),J=JSON.parse(Z);if(Array.isArray(J))K=J;else if(J&&typeof J==="object"&&Array.isArray(J.tweets))K=J.tweets;else throw new Q("Thread file must be an array of tweets or { tweets: [] }",z.VALIDATION)}else{let Z=w(O,"text","content");if(!Z)throw new Q("Provide --file thread.json (array of {content}) or informal --text with || separators is not enough alone for threads - use --file",z.VALIDATION);K=Z.split("||").map((J)=>({content:J.trim()})).filter((J)=>J.content)}if(K.length<2)throw new Q("Threads require at least 2 tweets",z.VALIDATION);if(D==="schedule-thread"){let Z=C({at:w(O,"at"),in:w(O,"in")}),J=await G.post("/api/posts/schedule-thread",{socialAccountId:V,tweets:K,scheduledAt:Z,metadata:h(O)??{}},{workspace:!0});R(J,U);return}let X=await G.post("/api/posts/publish-thread-now",{socialAccountId:V,tweets:K,metadata:h(O)??{}},{workspace:!0});R(X,U);return}default:throw new Q(`Unknown posts command "${D??""}". Try: list, get, schedule, publish, reschedule, cancel, delete, x-cap, schedule-thread, publish-thread`,z.USAGE)}}async function LU(U,D,O,A){N(U),P(U);let G=T(U);switch(D){case"list":case"ls":{let $=await G.get("/api/drafts",{workspace:!0,query:{limit:F(O,"limit")??50,offset:F(O,"offset")??0}});R($,{...U,emptyMessage:'No drafts yet. Create one with dun drafts create --text "..."'});return}case"get":{let $=A[0];if(!$)throw new Q("Usage: dun drafts get <id>",z.USAGE);let V=await G.get(`/api/drafts/${$}`,{workspace:!0});R(V,U);return}case"create":{let $=w(O,"text","content","c","t");if(!$)throw new Q("Missing --text",z.VALIDATION);let V=await G.post("/api/drafts",{content:$,name:w(O,"name","n"),socialAccountIds:_(O,"accounts","account","a")??[],selectedPlatforms:_(O,"platforms","platform","p")??[],mediaUrls:_(O,"media")??[]},{workspace:!0});R(V,U);return}case"update":{let $=A[0];if(!$)throw new Q("Usage: dun drafts update <id> --text ...",z.USAGE);let V={id:$},K=w(O,"text","content","c","t");if(K)V.content=K;let X=w(O,"name","n");if(X!==void 0)V.name=X;let Z=_(O,"accounts","account","a");if(Z)V.socialAccountIds=Z;let J=_(O,"platforms","platform","p");if(J)V.selectedPlatforms=J;let q=_(O,"media");if(q)V.mediaUrls=q;let Y=await G.patch(`/api/drafts/${$}`,V,{workspace:!0});R(Y,U);return}case"delete":case"rm":{let $=A[0];if(!$)throw new Q("Usage: dun drafts delete <id> [--yes]",z.USAGE);if(!U.yes&&!u(O,"yes","y"))throw new Q("Refusing to delete without --yes",z.VALIDATION);let V=await G.delete(`/api/drafts/${$}`,void 0,{workspace:!0});R(V??{id:$,deleted:!0},U);return}default:throw new Q(`Unknown drafts command "${D??""}". Try: list, get, create, update, delete`,z.USAGE)}}import{basename as T0}from"node:path";function N0(U){let D=U.split(".").pop()?.toLowerCase()??"";return{jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",mp4:"video/mp4",mov:"video/quicktime",webm:"video/webm"}[D]??"application/octet-stream"}async function kU(U,D,O,A){N(U),P(U);let G=T(U);switch(D){case"list":case"ls":{let $=await G.get("/api/media",{workspace:!0,query:{limit:F(O,"limit")??50,offset:F(O,"offset")??0}});R($,{...U,emptyMessage:"No media yet. Upload with dun media upload <file>."});return}case"get":{let $=A[0];if(!$)throw new Q("Usage: dun media get <id>",z.USAGE);let V=await G.get(`/api/media/${$}`,{workspace:!0});R(V,U);return}case"upload":{let $=A[0]||w(O,"file","f");if(!$)throw new Q('Usage: dun media upload <file> [--alt "..."]',z.USAGE);let V=Bun.file($);if(!await V.exists())throw new Q(`File not found: ${$}`,z.VALIDATION);let X=T0($),Z=w(O,"mime","type","content-type")||V.type||N0(X),J=V.size,q=w(O,"alt","alt-text"),Y=await G.post("/api/media/upload-url",{filename:X,mimeType:Z,fileSize:J},{workspace:!0});S(U.debug,`PUT ${Y.uploadUrl}`,{storageKey:Y.storageKey,fileSize:J});let H=await V.arrayBuffer(),y;try{y=await fetch(Y.uploadUrl,{method:"PUT",headers:{"Content-Type":Z,"Content-Length":String(J)},body:H})}catch(k){throw new Q(`Upload PUT failed: ${k.message}`,z.NETWORK)}if(!y.ok){let k=await y.text().catch(()=>"");throw new Q(`Upload PUT failed with HTTP ${y.status}${k?`: ${k.slice(0,200)}`:""}`,z.NETWORK)}let L=await G.post("/api/media/complete",{storageKey:Y.storageKey,originalFilename:X,mimeType:Z,fileSize:J,altText:q},{workspace:!0});R(L,U);return}case"delete":case"rm":{let $=A[0];if(!$)throw new Q("Usage: dun media delete <id> [--yes]",z.USAGE);if(!U.yes&&!u(O,"yes","y"))throw new Q("Refusing to delete without --yes",z.VALIDATION);let V=await G.delete(`/api/media/${$}`,void 0,{workspace:!0});R(V??{id:$,deleted:!0},U);return}default:throw new Q(`Unknown media command "${D??""}". Try: list, get, upload, delete`,z.USAGE)}}async function MU(U,D,O,A){N(U),P(U);let G=T(U),$=D[0];if($==="collections"||$==="collection"){let V=D[1]||"list";switch(V){case"list":case"ls":{let K=await G.get("/api/memory/collections",{workspace:!0});R(K,{...U,emptyMessage:'No memory collections yet. Create one with dun memory collections create --name "..."'});return}case"create":{let K=w(O,"name","n");if(!K)throw new Q("Missing --name",z.VALIDATION);let X=await G.post("/api/memory/collections",{name:K,color:w(O,"color")??"blue",isPrivate:u(O,"private")},{workspace:!0});R(X,U);return}case"get":{let K=D[2]||A[0];if(!K)throw new Q("Usage: dun memory collections get <id>",z.USAGE);let X=await G.get(`/api/memory/collections/${K}`,{workspace:!0});R(X,U);return}default:throw new Q(`Unknown memory collections command "${V}". Try: list, create, get`,z.USAGE)}}switch($){case"list":case"ls":{let V=w(O,"collection","collection-id","c");if(!V)throw new Q("Missing --collection <id>",z.VALIDATION);let K=await G.get("/api/memory",{workspace:!0,query:{collectionId:V,limit:F(O,"limit")??100}});R(K,{...U,emptyMessage:"No memories in this collection."});return}case"save":case"add":{let V=w(O,"collection","collection-id","c"),K=w(O,"text","t");if(!V)throw new Q("Missing --collection <id>",z.VALIDATION);if(!K)throw new Q("Missing --text",z.VALIDATION);let X=await G.post("/api/memory",{collectionId:V,text:K},{workspace:!0});R(X,U);return}case"search":{let V=w(O,"prompt","q","query","text"),K=_(O,"collections","collection","collection-ids","c")??[];if(!V)throw new Q("Missing --prompt",z.VALIDATION);if(K.length===0)throw new Q("Missing --collections <id,id>",z.VALIDATION);let X=await G.post("/api/memory/search",{prompt:V,collectionIds:K,topK:F(O,"top-k","topk","k")??5},{workspace:!0});R(X,U);return}case"delete":case"rm":{let V=D[1]||A[0],K=w(O,"collection","collection-id","c");if(!V)throw new Q("Usage: dun memory delete <id> --collection <id>",z.USAGE);if(!K)throw new Q("Missing --collection <id>",z.VALIDATION);if(!U.yes&&!u(O,"yes","y"))throw new Q("Refusing to delete without --yes",z.VALIDATION);let X=await G.delete(`/api/memory/${V}`,{collectionId:K,memoryId:V},{workspace:!0});R(X??{id:V,deleted:!0},U);return}default:throw new Q(`Unknown memory command "${$??""}". Try: collections, list, save, search, delete`,z.USAGE)}}import{readFileSync as W0}from"node:fs";async function jU(U,D,O,A){N(U);let G=P(U),$=T(U),V=`/api/workspaces/${G}/ai-voice-settings`;switch(D){case"get":case"show":case void 0:{let K=await $.get(V,{workspace:!0});R(K??{personalization:null,hint:'No personalization set. Use dun personalization set --description "..."'},U);return}case"set":case"update":{let K=u(O,"clear"),X=w(O,"description","d"),Z=w(O,"file","f");if([K,Boolean(X),Boolean(Z)].filter(Boolean).length!==1)throw new Q("Use exactly one of --description, --file, or --clear",z.VALIDATION);let q;if(K)q=null;else if(Z){let H;try{H=W0(Z,"utf8").trim()}catch(y){throw new Q(`Could not read file: ${y.message}`,z.VALIDATION)}if(!H)throw new Q("File is empty",z.VALIDATION);q={description:H}}else{let H=X.trim();if(!H)throw new Q("--description cannot be empty",z.VALIDATION);q={description:H}}let Y=await $.patch(V,q,{workspace:!0});R(Y,U);return}default:throw new Q(`Unknown personalization command "${D}". Try: get, set`,z.USAGE)}}import{existsSync as P0}from"node:fs";import{mkdir as dU,writeFile as hU,readFile as vU}from"node:fs/promises";import{dirname as OU,join as W}from"node:path";import{homedir as DU}from"node:os";import{fileURLToPath as u0}from"node:url";var p=[{id:"claude",label:"Claude Code",aliases:["claude-code"],dest:(U)=>W(U,".claude","skills","dunsocial","SKILL.md")},{id:"codex",label:"Codex",dest:(U)=>W(U,".codex","skills","dunsocial","SKILL.md"),afterInstall:async(U)=>{return{agentsPath:await I0(U)}}},{id:"cursor",label:"Cursor",dest:(U)=>W(U,".cursor","skills","dunsocial","SKILL.md")},{id:"pi",label:"Pi",dest:(U)=>W(U,".pi","agent","skills","dunsocial","SKILL.md")},{id:"opencode",label:"OpenCode",dest:(U)=>W(U,".config","opencode","skills","dunsocial","SKILL.md")},{id:"agents",label:"Universal (.agents)",aliases:["universal"],dest:(U)=>W(U,".agents","skills","dunsocial","SKILL.md")},{id:"copilot",label:"GitHub Copilot",aliases:["github-copilot","github"],dest:(U)=>W(U,".copilot","skills","dunsocial","SKILL.md")},{id:"windsurf",label:"Windsurf",dest:(U)=>W(U,".codeium","windsurf","skills","dunsocial","SKILL.md")},{id:"goose",label:"Goose",dest:(U)=>W(U,".config","goose","skills","dunsocial","SKILL.md")},{id:"gemini",label:"Gemini CLI",aliases:["gemini-cli"],dest:(U)=>W(U,".gemini","skills","dunsocial","SKILL.md")},{id:"amp",label:"Amp",dest:(U)=>W(U,".config","agents","skills","dunsocial","SKILL.md")},{id:"grok",label:"Grok Build",dest:(U)=>W(U,".grok","skills","dunsocial","SKILL.md")},{id:"continue",label:"Continue",dest:(U)=>W(U,".continue","skills","dunsocial","SKILL.md")},{id:"antigravity",label:"Antigravity",dest:(U)=>W(U,".gemini","antigravity","skills","dunsocial","SKILL.md")}],a=new Map;for(let U of p){a.set(U.id,U);for(let D of U.aliases??[])a.set(D,U)}var bU=`Usage: dun skill install <${p.map((U)=>U.id).join("|")}|all>`;function UU(){let U=OU(u0(import.meta.url)),D=W("skills","dunsocial","SKILL.md"),O=[W(U,"..",D),W(U,"..","..",D)];return O.find(P0)??O[0]}function H0(){let U=DU();return p.map((D)=>({id:D.id,label:D.label,path:D.dest(U),aliases:D.aliases??[]}))}async function F0(){try{return await vU(UU(),"utf8")}catch{throw new Q(`Bundled skill not found at ${UU()}. Reinstall dunsocial.`,z.USAGE)}}async function _0(U,D){await dU(OU(U),{recursive:!0}),await hU(U,D,"utf8")}async function I0(U){let D=W(DU(),".codex","AGENTS.md");await dU(OU(D),{recursive:!0});let O="";try{O=await vU(D,"utf8")}catch{O=""}let A=["<!-- BEGIN DUNSOCIAL CLI SKILL -->","## DunSocial CLI","","Use the `dun` CLI for DunSocial scheduling from the shell. Prefer `--json` output.",`Skill details: ${U}`,"","Common flow:","1. `dun auth status --json`","2. `dun workspace list --json` / `dun workspace use <id>`","3. `dun accounts list --json`",'4. `dun posts schedule --text "..." --accounts <id> --in 1h --json`',"<!-- END DUNSOCIAL CLI SKILL -->"].join(`
255
- `),G="<!-- BEGIN DUNSOCIAL CLI SKILL -->",$="<!-- END DUNSOCIAL CLI SKILL -->",V,K=O.indexOf(G),X=O.indexOf($);if(K!==-1&&X!==-1&&X>K)V=O.slice(0,K)+A+O.slice(X+$.length);else if(O.trim())V=`${O.trimEnd()}
256
-
257
- ${A}
258
- `;else V=`${A}
259
- `;return await hU(D,V,"utf8"),D}async function SU(U,D){let O=U.dest(DU());await _0(O,D);let A=U.afterInstall?await U.afterInstall(O):{};return{target:U.id,path:O,message:`Installed DunSocial skill for ${U.label}. Restart or open a new session if needed.`,...A}}async function mU(U,D,O,A){switch(D){case"path":{R({path:UU()},U);return}case"list":{R({targets:H0(),hint:"Install with: dun skill install <target|all>"},U);return}case"install":{let G=(A[0]||"").toLowerCase();if(!G)throw new Q(bU,z.USAGE);let $=await F0();if(G==="all"){let X=[];for(let Z of p){let J=await SU(Z,$);X.push({target:J.target,path:J.path})}R({target:"all",count:X.length,installed:X,message:`Installed DunSocial skill for ${X.length} agents.`},U);return}let V=a.get(G);if(!V)throw new Q(`Unknown agent "${G}". ${bU}
260
- Try: dun skill list`,z.USAGE);let K=await SU(V,$);R(K,U);return}default:throw new Q(`Unknown skill command "${D??""}". Try: install, list, path`,z.USAGE)}}function EU(){if(g(process.stdout))qU(process.stdout,{tagline:!0});process.stdout.write(`${QU}
261
- `)}async function y0(U){let D=VU(U),{group:O,action:A,nest:G,flags:$,positionals:V}=D;if(f($)&&!O)return process.stdout.write(`${v}
262
- `),I.OK;if(O==="help"||!O&&n($)){let X=O==="help"?A||V[0]:void 0;if(X)process.stdout.write(`${o(X)}
263
- `);else EU();return I.OK}if(!O)return EU(),I.OK;if(n($))return process.stdout.write(`${o(O)}
264
- `),I.OK;let K=await KU({apiUrl:m($,"api-url","apiUrl"),token:m($,"token"),workspace:m($,"workspace","w"),json:B($,"json","j")?!0:void 0,debug:B($,"debug"),quiet:B($,"quiet","q"),yes:B($,"yes","y")});if(f($))return x({version:v},K),I.OK;try{switch(O){case"auth":await HU(K,A,$,V);break;case"workspace":case"workspaces":await FU(K,A,$,V);break;case"account":case"accounts":await _U(K,A??"list",$,V);break;case"post":case"posts":await BU(K,A,$,V);break;case"draft":case"drafts":await LU(K,A,$,V);break;case"media":await kU(K,A,$,V);break;case"memory":{let X=G?[G,A].filter(Boolean):A?[A]:[];await MU(K,X,$,V);break}case"personalization":case"voice":await jU(K,A,$,V);break;case"skill":case"skills":await mU(K,A,$,V);break;case"version":x({version:v},K);break;default:throw new c(`Unknown command "${O}". Run dun --help`,I.USAGE)}return I.OK}catch(X){return zU(X,K)}}var B0=await y0(process.argv.slice(2));process.exit(B0);
168
+ `)}else process.stderr.write(JSON.stringify({ok:!0,phase:"waiting",userCode:z.userCode,verificationUrlComplete:z.verificationUrlComplete})+`
169
+ `);if(X&&process.stdout.isTTY)try{await u$(z.verificationUrlComplete)}catch{}let D=Math.max(3,z.interval||5)*1000,O=Date.now()+(z.expiresIn||900)*1000;while(Date.now()<O){await $$(D);let w=await $.post("/api/cli/auth/poll",{deviceCode:z.deviceCode},{auth:!1});if(w.status==="pending")continue;if(w.status==="expired")throw new Z("Login expired. Run dun auth login again.",Q.AUTH);if(w.status==="denied")throw new Z("Login was denied in the browser.",Q.AUTH);if(w.status==="approved"){let J=w.token,Y={...U,token:J},q=k(Y),y=await q.get("/api/user/profile"),W={...U.config,apiUrl:U.apiUrl,token:J,defaultWorkspaceId:w.workspaceId||U.config.defaultWorkspaceId,defaultWorkspaceSlug:U.config.defaultWorkspaceSlug,defaultWorkspaceName:U.config.defaultWorkspaceName};if(w.workspaceId)try{let M=(await q.get("/api/workspaces")).find((jU)=>jU.id===w.workspaceId);if(M)W.defaultWorkspaceId=M.id,W.defaultWorkspaceSlug=M.slug,W.defaultWorkspaceName=M.name}catch{}await I(W);let N=Boolean(W.defaultWorkspaceId);if(!U.json&&A(process.stdout)){V(h(N),U);return}V({user:{id:y.id,name:y.name,email:y.email},workspaceId:W.defaultWorkspaceId??null,configPath:j(),method:"device",message:h(N)},U);return}}throw new Z("Login timed out. Run dun auth login again.",Q.AUTH)}async function aU(U){if(await $U(),!U.json&&A(process.stdout)){V("Logged out. Config cleared.",U);return}V({message:"Logged out. Config cleared.",configPath:j()},U)}async function tU(U){F(U);let $=await k(U).get("/api/user/profile");V({id:$.id,name:$.name,email:$.email,image:$.image??null,apiUrl:U.apiUrl,workspaceId:U.workspaceId??null},U)}async function U$(U){let u=Boolean(U.token),$=null,z=null;if(u)try{$=await k(U).get("/api/user/profile")}catch(X){z=X instanceof Error?X.message:String(X)}V({authenticated:Boolean($),tokenPresent:u,apiUrl:U.apiUrl,workspaceId:U.workspaceId??null,workspaceSlug:U.config.defaultWorkspaceSlug??null,workspaceName:U.config.defaultWorkspaceName??null,configPath:j(),user:$?{id:$.id,name:$.name,email:$.email}:null,error:z},U)}function $$(U){return new Promise((u)=>setTimeout(u,U))}async function u$(U){let u=process.platform,$=u==="darwin"?["open",U]:u==="win32"?["cmd","/c","start","",U]:["xdg-open",U];await new Promise((z,X)=>{let D=cU($[0],$.slice(1),{stdio:"ignore",windowsHide:!0});D.on("error",X),D.on("close",()=>z())})}async function qU(U,u,$,z){F(U);let X=k(U);switch(u){case"list":case"ls":{let D=await X.get("/api/workspaces");V(D.map((O)=>({id:O.id,name:O.name,slug:O.slug,role:O.role,timezone:O.timezone,plan:O.subscription?.planName??null,status:O.subscription?.status??null})),{...U,emptyMessage:"No workspaces yet."});return}case"use":{let D=z[0];if(!D)throw new Z("Usage: dun workspace use <id|slug>",Q.USAGE);let w=(await X.get("/api/workspaces")).find((J)=>J.id===D||J.slug===D);if(!w)throw new Z(`Workspace not found: ${D}. Run dun workspace list`,Q.NOT_FOUND);await I({...U.config,apiUrl:U.apiUrl,token:U.token,defaultWorkspaceId:w.id,defaultWorkspaceSlug:w.slug,defaultWorkspaceName:w.name}),V({id:w.id,name:w.name,slug:w.slug,role:w.role,message:`Default workspace set to ${w.name}`},U);return}case"current":{if(!U.workspaceId&&!U.config.defaultWorkspaceId)throw new Z("No workspace selected. Run dun workspace use <id|slug>",Q.VALIDATION);let D=U.workspaceId||U.config.defaultWorkspaceId;try{let w=(await X.get("/api/workspaces")).find((J)=>J.id===D||J.slug===D);if(w){V({id:w.id,name:w.name,slug:w.slug,role:w.role,timezone:w.timezone},U);return}}catch{}V({id:D,name:U.config.defaultWorkspaceName??null,slug:U.config.defaultWorkspaceSlug??null},U);return}default:throw new Z(`Unknown workspace command "${u??""}". Try: list, use, current`,Q.USAGE)}}async function KU(U,u,$,z){F(U),T(U);let X=k(U);switch(u){case void 0:case"list":case"ls":{let D=await X.get("/api/social-accounts",{workspace:!0}),O=K($,"platform","p")?.toLowerCase(),w=O?D.filter((J)=>{let Y=(J.providerName||"").toLowerCase();return({x:["x","twitter"],twitter:["x","twitter"],linkedin:["linkedin"],"linkedin-business":["linkedin business","linkedin-business","linkedin_business"],bluesky:["bluesky"],threads:["threads"],reddit:["reddit"],pinterest:["pinterest"],instagram:["instagram"],youtube:["youtube"],tiktok:["tiktok"]}[O]??[O]).some((W)=>Y.includes(W))}):D;V(w.map((J)=>({id:J.id,providerName:J.providerName,username:J.username??null,displayName:J.displayName??null,isConnected:J.isConnected,expiresAt:J.expiresAt??null})),{...U,emptyMessage:O?`No ${O} accounts connected. Connect one in the DunSocial dashboard.`:"No accounts connected. Connect one in the DunSocial dashboard."});return}default:throw new Z(`Unknown accounts command "${u}". Try: list`,Q.USAGE)}}import{readFileSync as O$}from"node:fs";var D$=/^(\d+)\s*(s|sec|secs|second|seconds|m|min|mins|minute|minutes|h|hr|hrs|hour|hours|d|day|days|w|week|weeks)$/i;function o(U,u=new Date){let $=U.trim();if(!$)throw new Z("Empty time value",Q.VALIDATION);let z=$.match(D$);if(z){let O=Number(z[1]),w=z[2].toLowerCase(),J=w$(w)*O;return new Date(u.getTime()+J)}let X=$.match(/^in\s+(.+)$/i);if(X)return o(X[1],u);let D=new Date($);if(Number.isNaN(D.getTime()))throw new Z(`Invalid time "${U}". Use ISO-8601 (2026-06-01T09:00:00Z) or relative (2h, 30m, 1d).`,Q.VALIDATION);return D}function w$(U){switch(U){case"s":case"sec":case"secs":case"second":case"seconds":return 1000;case"m":case"min":case"mins":case"minute":case"minutes":return 60000;case"h":case"hr":case"hrs":case"hour":case"hours":return 3600000;case"d":case"day":case"days":return 86400000;case"w":case"week":case"weeks":return 604800000;default:throw new Z(`Unknown time unit: ${U}`,Q.VALIDATION)}}function S(U){if(U.at&&U.in)throw new Z("Pass only one of --at or --in",Q.VALIDATION);if(U.at)return o(U.at).toISOString();if(U.in)return o(U.in).toISOString();throw new Z("Schedule time required. Pass --at <iso> or --in <duration> (e.g. 2h).",Q.VALIDATION)}function WU(U){if(!U)return[];return U.split(",").map((u)=>u.trim()).filter(Boolean)}function yU(U){let u=K(U,"text","content","c","t");if(!u)throw new Z("Missing --text",Q.VALIDATION);return u}function x(U){let u=L(U,"accounts","account","a")??WU(K(U,"accounts","account","a"));if(!u||u.length===0)throw new Z("Missing --accounts <id,id>",Q.VALIDATION);return u}function c(U){return L(U,"media","media-urls")??WU(K(U,"media","media-urls"))}function _(U){let u=K(U,"meta","metadata","meta-json");if(!u)return;try{let $=JSON.parse(u);if(!$||typeof $!=="object"||Array.isArray($))throw Error("metadata must be a JSON object");return $}catch($){throw new Z(`Invalid --meta JSON: ${$.message}`,Q.VALIDATION)}}async function GU(U,u,$,z){F(U),T(U);let X=k(U);switch(u){case"list":case"ls":{let D=await X.get("/api/posts",{workspace:!0,query:{status:K($,"status","s"),socialAccountId:K($,"account","social-account"),groupId:K($,"group"),limit:d($,"limit")??50,offset:d($,"offset")??0}});V(D,{...U,emptyMessage:"No posts yet. Schedule one with dun posts schedule."});return}case"get":{let D=z[0];if(!D)throw new Z("Usage: dun posts get <id>",Q.USAGE);let O=await X.get(`/api/posts/${D}`,{workspace:!0});V(O,U);return}case"schedule":{let D=yU($),O=x($),w=S({at:K($,"at"),in:K($,"in")}),J=await X.post("/api/posts/schedule",{content:D,socialAccountIds:O,scheduledAt:w,mediaUrls:c($),metadata:_($)??{}},{workspace:!0});V(J,U);return}case"publish":case"publish-now":{let D=yU($),O=x($),w=await X.post("/api/posts/publish-now",{content:D,socialAccountIds:O,mediaUrls:c($),metadata:_($)??{},naturalPosting:G($,"natural","natural-posting")},{workspace:!0});V(w,U);return}case"reschedule":{let D=z[0];if(!D)throw new Z("Usage: dun posts reschedule <id> --at|--in",Q.USAGE);let w={scheduledAt:S({at:K($,"at"),in:K($,"in")})},J=K($,"text","content","c","t");if(J)w.content=J;let Y=c($);if(Y.length)w.mediaUrls=Y;let q=_($);if(q)w.metadata=q;if(!w.content){let W=await X.get(`/api/posts/${D}`,{workspace:!0});if(w.content=W.content,!w.metadata&&W.metadata)w.metadata=W.metadata;if(!w.mediaUrls&&W.mediaUrls)w.mediaUrls=W.mediaUrls}let y=await X.post(`/api/posts/${D}/reschedule`,w,{workspace:!0});V(y,U);return}case"cancel":{let D=z[0];if(!D)throw new Z("Usage: dun posts cancel <id>",Q.USAGE);let O=await X.post(`/api/posts/${D}/cancel`,void 0,{workspace:!0});V(O??{id:D,status:"cancelled"},U);return}case"delete":case"rm":{let D=z[0];if(!D)throw new Z("Usage: dun posts delete <id> [--yes]",Q.USAGE);if(!U.yes&&!G($,"yes","y"))throw new Z("Refusing to delete without --yes (or CI/yes mode)",Q.VALIDATION);let O=await X.delete(`/api/posts/${D}`,void 0,{workspace:!0});V(O??{id:D,deleted:!0},U);return}case"x-cap":case"xcap":{let D=await X.get("/api/posts/x-cap-usage",{workspace:!0});V(D,U);return}case"schedule-thread":case"publish-thread":case"publish-thread-now":{let D=K($,"file","f"),O=K($,"account","accounts","a")??x($)[0];if(!O)throw new Z("Missing --account <xAccountId>",Q.VALIDATION);let w;if(D){let Y;try{Y=O$(D,"utf8")}catch(y){throw new Z(`Could not read file: ${y.message}`,Q.VALIDATION)}let q=JSON.parse(Y);if(Array.isArray(q))w=q;else if(q&&typeof q==="object"&&Array.isArray(q.tweets))w=q.tweets;else throw new Z("Thread file must be an array of tweets or { tweets: [] }",Q.VALIDATION)}else{let Y=K($,"text","content");if(!Y)throw new Z("Provide --file thread.json (array of {content}) or informal --text with || separators is not enough alone for threads - use --file",Q.VALIDATION);w=Y.split("||").map((q)=>({content:q.trim()})).filter((q)=>q.content)}if(w.length<2)throw new Z("Threads require at least 2 tweets",Q.VALIDATION);if(u==="schedule-thread"){let Y=S({at:K($,"at"),in:K($,"in")}),q=await X.post("/api/posts/schedule-thread",{socialAccountId:O,tweets:w,scheduledAt:Y,metadata:_($)??{}},{workspace:!0});V(q,U);return}let J=await X.post("/api/posts/publish-thread-now",{socialAccountId:O,tweets:w,metadata:_($)??{}},{workspace:!0});V(J,U);return}default:throw new Z(`Unknown posts command "${u??""}". Try: list, get, schedule, publish, reschedule, cancel, delete, x-cap, schedule-thread, publish-thread`,Q.USAGE)}}async function kU(U,u,$,z){F(U),T(U);let X=k(U);switch(u){case"list":case"ls":{let D=await X.get("/api/drafts",{workspace:!0,query:{limit:d($,"limit")??50,offset:d($,"offset")??0}});V(D,{...U,emptyMessage:'No drafts yet. Create one with dun drafts create --text "..."'});return}case"get":{let D=z[0];if(!D)throw new Z("Usage: dun drafts get <id>",Q.USAGE);let O=await X.get(`/api/drafts/${D}`,{workspace:!0});V(O,U);return}case"create":{let D=K($,"text","content","c","t");if(!D)throw new Z("Missing --text",Q.VALIDATION);let O=await X.post("/api/drafts",{content:D,name:K($,"name","n"),socialAccountIds:L($,"accounts","account","a")??[],selectedPlatforms:L($,"platforms","platform","p")??[],mediaUrls:L($,"media")??[]},{workspace:!0});V(O,U);return}case"update":{let D=z[0];if(!D)throw new Z("Usage: dun drafts update <id> --text ...",Q.USAGE);let O={id:D},w=K($,"text","content","c","t");if(w)O.content=w;let J=K($,"name","n");if(J!==void 0)O.name=J;let Y=L($,"accounts","account","a");if(Y)O.socialAccountIds=Y;let q=L($,"platforms","platform","p");if(q)O.selectedPlatforms=q;let y=L($,"media");if(y)O.mediaUrls=y;let W=await X.patch(`/api/drafts/${D}`,O,{workspace:!0});V(W,U);return}case"delete":case"rm":{let D=z[0];if(!D)throw new Z("Usage: dun drafts delete <id> [--yes]",Q.USAGE);if(!U.yes&&!G($,"yes","y"))throw new Z("Refusing to delete without --yes",Q.VALIDATION);let O=await X.delete(`/api/drafts/${D}`,void 0,{workspace:!0});V(O??{id:D,deleted:!0},U);return}default:throw new Z(`Unknown drafts command "${u??""}". Try: list, get, create, update, delete`,Q.USAGE)}}import{readFileSync as z$,existsSync as Q$,statSync as X$}from"node:fs";import{basename as Z$}from"node:path";function J$(U){let u=U.split(".").pop()?.toLowerCase()??"";return{jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",mp4:"video/mp4",mov:"video/quicktime",webm:"video/webm"}[u]??"application/octet-stream"}async function FU(U,u,$,z){F(U),T(U);let X=k(U);switch(u){case"list":case"ls":{let D=await X.get("/api/media",{workspace:!0,query:{limit:d($,"limit")??50,offset:d($,"offset")??0}});V(D,{...U,emptyMessage:"No media yet. Upload with dun media upload <file>."});return}case"get":{let D=z[0];if(!D)throw new Z("Usage: dun media get <id>",Q.USAGE);let O=await X.get(`/api/media/${D}`,{workspace:!0});V(O,U);return}case"upload":{let D=z[0]||K($,"file","f");if(!D)throw new Z('Usage: dun media upload <file> [--alt "..."]',Q.USAGE);if(!Q$(D))throw new Z(`File not found: ${D}`,Q.VALIDATION);let O=Z$(D),w=X$(D).size,J=K($,"mime","type","content-type")||J$(O),Y=K($,"alt","alt-text"),q=await X.post("/api/media/upload-url",{filename:O,mimeType:J,fileSize:w},{workspace:!0});m(U.debug,`PUT ${q.uploadUrl}`,{storageKey:q.storageKey,fileSize:w});let y=z$(D),W;try{W=await fetch(q.uploadUrl,{method:"PUT",headers:{"Content-Type":J,"Content-Length":String(w)},body:y})}catch(b){throw new Z(`Upload PUT failed: ${b.message}`,Q.NETWORK)}if(!W.ok){let b=await W.text().catch(()=>"");throw new Z(`Upload PUT failed with HTTP ${W.status}${b?`: ${b.slice(0,200)}`:""}`,Q.NETWORK)}let N=await X.post("/api/media/complete",{storageKey:q.storageKey,originalFilename:O,mimeType:J,fileSize:w,altText:Y},{workspace:!0});V(N,U);return}case"delete":case"rm":{let D=z[0];if(!D)throw new Z("Usage: dun media delete <id> [--yes]",Q.USAGE);if(!U.yes&&!G($,"yes","y"))throw new Z("Refusing to delete without --yes",Q.VALIDATION);let O=await X.delete(`/api/media/${D}`,void 0,{workspace:!0});V(O??{id:D,deleted:!0},U);return}default:throw new Z(`Unknown media command "${u??""}". Try: list, get, upload, delete`,Q.USAGE)}}async function RU(U,u,$,z){F(U),T(U);let X=k(U),D=u[0];if(D==="collections"||D==="collection"){let O=u[1]||"list";switch(O){case"list":case"ls":{let w=await X.get("/api/memory/collections",{workspace:!0});V(w,{...U,emptyMessage:'No memory collections yet. Create one with dun memory collections create --name "..."'});return}case"create":{let w=K($,"name","n");if(!w)throw new Z("Missing --name",Q.VALIDATION);let J=await X.post("/api/memory/collections",{name:w,color:K($,"color")??"blue",isPrivate:G($,"private")},{workspace:!0});V(J,U);return}case"get":{let w=u[2]||z[0];if(!w)throw new Z("Usage: dun memory collections get <id>",Q.USAGE);let J=await X.get(`/api/memory/collections/${w}`,{workspace:!0});V(J,U);return}default:throw new Z(`Unknown memory collections command "${O}". Try: list, create, get`,Q.USAGE)}}switch(D){case"list":case"ls":{let O=K($,"collection","collection-id","c");if(!O)throw new Z("Missing --collection <id>",Q.VALIDATION);let w=await X.get("/api/memory",{workspace:!0,query:{collectionId:O,limit:d($,"limit")??100}});V(w,{...U,emptyMessage:"No memories in this collection."});return}case"save":case"add":{let O=K($,"collection","collection-id","c"),w=K($,"text","t");if(!O)throw new Z("Missing --collection <id>",Q.VALIDATION);if(!w)throw new Z("Missing --text",Q.VALIDATION);let J=await X.post("/api/memory",{collectionId:O,text:w},{workspace:!0});V(J,U);return}case"search":{let O=K($,"prompt","q","query","text"),w=L($,"collections","collection","collection-ids","c")??[];if(!O)throw new Z("Missing --prompt",Q.VALIDATION);if(w.length===0)throw new Z("Missing --collections <id,id>",Q.VALIDATION);let J=await X.post("/api/memory/search",{prompt:O,collectionIds:w,topK:d($,"top-k","topk","k")??5},{workspace:!0});V(J,U);return}case"delete":case"rm":{let O=u[1]||z[0],w=K($,"collection","collection-id","c");if(!O)throw new Z("Usage: dun memory delete <id> --collection <id>",Q.USAGE);if(!w)throw new Z("Missing --collection <id>",Q.VALIDATION);if(!U.yes&&!G($,"yes","y"))throw new Z("Refusing to delete without --yes",Q.VALIDATION);let J=await X.delete(`/api/memory/${O}`,{collectionId:w,memoryId:O},{workspace:!0});V(J??{id:O,deleted:!0},U);return}default:throw new Z(`Unknown memory command "${D??""}". Try: collections, list, save, search, delete`,Q.USAGE)}}import{readFileSync as V$}from"node:fs";async function TU(U,u,$,z){F(U);let X=T(U),D=k(U),O=`/api/workspaces/${X}/ai-voice-settings`;switch(u){case"get":case"show":case void 0:{let w=await D.get(O,{workspace:!0});V(w??{personalization:null,hint:'No personalization set. Use dun personalization set --description "..."'},U);return}case"set":case"update":{let w=G($,"clear"),J=K($,"description","d"),Y=K($,"file","f");if([w,Boolean(J),Boolean(Y)].filter(Boolean).length!==1)throw new Z("Use exactly one of --description, --file, or --clear",Q.VALIDATION);let y;if(w)y=null;else if(Y){let N;try{N=V$(Y,"utf8").trim()}catch(b){throw new Z(`Could not read file: ${b.message}`,Q.VALIDATION)}if(!N)throw new Z("File is empty",Q.VALIDATION);y={description:N}}else{let N=J.trim();if(!N)throw new Z("--description cannot be empty",Q.VALIDATION);y={description:N}}let W=await D.patch(O,y,{workspace:!0});V(W,U);return}default:throw new Z(`Unknown personalization command "${u}". Try: get, set`,Q.USAGE)}}import{existsSync as Y$}from"node:fs";import{mkdir as BU,writeFile as PU,readFile as dU}from"node:fs/promises";import{dirname as l,join as R}from"node:path";import{homedir as a}from"node:os";import{fileURLToPath as q$}from"node:url";var p=[{id:"claude",label:"Claude Code",aliases:["claude-code"],dest:(U)=>R(U,".claude","skills","dunsocial","SKILL.md")},{id:"codex",label:"Codex",dest:(U)=>R(U,".codex","skills","dunsocial","SKILL.md"),afterInstall:async(U)=>{return{agentsPath:await G$(U)}}},{id:"cursor",label:"Cursor",dest:(U)=>R(U,".cursor","skills","dunsocial","SKILL.md")},{id:"pi",label:"Pi",dest:(U)=>R(U,".pi","agent","skills","dunsocial","SKILL.md")},{id:"opencode",label:"OpenCode",dest:(U)=>R(U,".config","opencode","skills","dunsocial","SKILL.md")},{id:"agents",label:"Universal (.agents)",aliases:["universal"],dest:(U)=>R(U,".agents","skills","dunsocial","SKILL.md")},{id:"copilot",label:"GitHub Copilot",aliases:["github-copilot","github"],dest:(U)=>R(U,".copilot","skills","dunsocial","SKILL.md")},{id:"windsurf",label:"Windsurf",dest:(U)=>R(U,".codeium","windsurf","skills","dunsocial","SKILL.md")},{id:"goose",label:"Goose",dest:(U)=>R(U,".config","goose","skills","dunsocial","SKILL.md")},{id:"gemini",label:"Gemini CLI",aliases:["gemini-cli"],dest:(U)=>R(U,".gemini","skills","dunsocial","SKILL.md")},{id:"amp",label:"Amp",dest:(U)=>R(U,".config","agents","skills","dunsocial","SKILL.md")},{id:"grok",label:"Grok Build",dest:(U)=>R(U,".grok","skills","dunsocial","SKILL.md")},{id:"continue",label:"Continue",dest:(U)=>R(U,".continue","skills","dunsocial","SKILL.md")},{id:"antigravity",label:"Antigravity",dest:(U)=>R(U,".gemini","antigravity","skills","dunsocial","SKILL.md")}],r=new Map;for(let U of p){r.set(U.id,U);for(let u of U.aliases??[])r.set(u,U)}var HU=`Usage: dun skill install <${p.map((U)=>U.id).join("|")}|all>`;function s(){let U=l(q$(import.meta.url)),u=R("skills","dunsocial","SKILL.md"),$=[R(U,"..",u),R(U,"..","..",u)];return $.find(Y$)??$[0]}function K$(){let U=a();return p.map((u)=>({id:u.id,label:u.label,path:u.dest(U),aliases:u.aliases??[]}))}async function y$(){try{return await dU(s(),"utf8")}catch{throw new Z(`Bundled skill not found at ${s()}. Reinstall dunsocial.`,Q.USAGE)}}async function W$(U,u){await BU(l(U),{recursive:!0}),await PU(U,u,"utf8")}async function G$(U){let u=R(a(),".codex","AGENTS.md");await BU(l(u),{recursive:!0});let $="";try{$=await dU(u,"utf8")}catch{$=""}let z=["<!-- BEGIN DUNSOCIAL CLI SKILL -->","## DunSocial CLI","","Use the `dun` CLI for DunSocial scheduling from the shell. Prefer `--json` output.",`Skill details: ${U}`,"","Common flow:","1. `dun auth status --json`","2. `dun workspace list --json` / `dun workspace use <id>`","3. `dun accounts list --json`",'4. `dun posts schedule --text "..." --accounts <id> --in 1h --json`',"<!-- END DUNSOCIAL CLI SKILL -->"].join(`
170
+ `),X="<!-- BEGIN DUNSOCIAL CLI SKILL -->",D="<!-- END DUNSOCIAL CLI SKILL -->",O,w=$.indexOf(X),J=$.indexOf(D);if(w!==-1&&J!==-1&&J>w)O=$.slice(0,w)+z+$.slice(J+D.length);else if($.trim())O=`${$.trimEnd()}
171
+
172
+ ${z}
173
+ `;else O=`${z}
174
+ `;return await PU(u,O,"utf8"),u}async function NU(U,u){let $=U.dest(a());await W$($,u);let z=U.afterInstall?await U.afterInstall($):{};return{target:U.id,path:$,message:`Installed DunSocial skill for ${U.label}. Restart or open a new session if needed.`,...z}}async function LU(U,u,$,z){switch(u){case"path":{V({path:s()},U);return}case"list":{V({targets:K$(),hint:"Install with: dun skill install <target|all>"},U);return}case"install":{let X=(z[0]||"").toLowerCase();if(!X)throw new Z(HU,Q.USAGE);let D=await y$();if(X==="all"){let J=[];for(let Y of p){let q=await NU(Y,D);J.push({target:q.target,path:q.path})}V({target:"all",count:J.length,installed:J,message:`Installed DunSocial skill for ${J.length} agents.`},U);return}let O=r.get(X);if(!O)throw new Z(`Unknown agent "${X}". ${HU}
175
+ Try: dun skill list`,Q.USAGE);let w=await NU(O,D);V(w,U);return}default:throw new Z(`Unknown skill command "${u??""}". Try: install, list, path`,Q.USAGE)}}import{spawn as k$}from"node:child_process";import{realpathSync as F$}from"node:fs";var H="dunsocial",R$=`https://registry.npmjs.org/${H}/latest`;function T$(U=process.argv[1]??""){let u=U.replaceAll("\\","/");try{u=F$(U).replaceAll("\\","/")}catch{}if(u.includes("/.npm/_npx")||u.includes("/npm/_npx")||u.includes("/_npx/"))return{packageManager:"npx",manual:`npm install -g ${H}@latest`};if(u.includes("/.pnpm/")||u.includes("/pnpm/"))return{packageManager:"pnpm",command:"pnpm",args:["add","-g",`${H}@latest`],manual:`pnpm add -g ${H}@latest`};if(u.includes("/.yarn/")||u.includes("/yarn/global"))return{packageManager:"yarn",command:"yarn",args:["global","add",`${H}@latest`],manual:`yarn global add ${H}@latest`};if(u.includes("/.bun/")||u.includes("/bun/install/global"))return{packageManager:"bun",command:"bun",args:["add","-g",`${H}@latest`],manual:`bun add -g ${H}@latest`};if(u.includes(`/node_modules/${H}/`))return{packageManager:"npm",command:"npm",args:["install","-g",`${H}@latest`],manual:`npm install -g ${H}@latest`};return{packageManager:"unknown",manual:`npm install -g ${H}@latest`}}function H$(U,u){let $=U.replace(/^v/,"").split(".").map((D)=>Number.parseInt(D,10)||0),z=u.replace(/^v/,"").split(".").map((D)=>Number.parseInt(D,10)||0),X=Math.max($.length,z.length);for(let D=0;D<X;D++){let O=$[D]??0,w=z[D]??0;if(O>w)return 1;if(O<w)return-1}return 0}async function N$(U=fetch){let u=await U(R$,{headers:{Accept:"application/json"}});if(!u.ok)throw new Z(`Could not check npm for updates (HTTP ${u.status}). Try: npm install -g ${H}@latest`,Q.NETWORK);let $=await u.json();if(!$.version)throw new Z("npm registry response missing version",Q.NETWORK);return $.version}function B$(U,u){return new Promise(($,z)=>{let X=k$(U,u,{stdio:"inherit",env:process.env,windowsHide:!0,shell:process.platform==="win32"});X.on("error",(D)=>{z(new Z(`Failed to run ${U}: ${D.message}. Try manually: ${U} ${u.join(" ")}`,Q.NETWORK))}),X.on("close",(D)=>$(D??1))})}async function AU(U,u,$){let z=G($,"check"),X=G($,"force"),D=B,O=T$(),w;try{w=await N$()}catch(y){if(y instanceof Z)throw y;throw new Z(`Could not check npm for updates: ${y.message}`,Q.NETWORK)}let J=H$(w,D)>0,Y={current:D,latest:w,upToDate:!J,packageManager:O.packageManager,command:O.manual};if(!J&&!X){V(U.json?Y:`Already on the latest version (${D}).`,U);return}if(z){V(U.json?{...Y,updateAvailable:J}:`Update available: ${D} → ${w}
176
+ Run: dun update
177
+ Or: ${O.manual}`,U);return}if(!O.command||!O.args){V(U.json?{...Y,applied:!1,hint:O.manual}:`Update available: ${D} → ${w}
178
+ Cannot auto-update this install (${O.packageManager}).
179
+ Run: ${O.manual}`,U);return}if(!U.json&&!U.quiet)process.stderr.write(`Updating ${H}: ${D} ${w} via ${O.packageManager}...
180
+ `);let q=await B$(O.command,O.args);if(q!==0)throw new Z(`Update command failed (exit ${q}). Try: ${O.manual}`,Q.NETWORK);V(U.json?{...Y,applied:!0}:`Updated via ${O.packageManager}. Run dun --version to confirm.`,U)}function bU(){if(A(process.stdout))process.stdout.write(`${XU()}
181
+
182
+ `);process.stdout.write(`${i}
183
+ `)}async function P$(){let U=await C(),u=process.env.DUN_TOKEN||U.token,$=process.env.DUN_WORKSPACE_ID||U.defaultWorkspaceId;process.stdout.write(`${JU({token:u,workspaceId:$,config:U})}
184
+ `)}async function d$(U){let u=DU(U),{group:$,action:z,nest:X,flags:D,positionals:O}=u;if(f(D)&&!$)return process.stdout.write(`${B}
185
+ `),Q.OK;if($==="help"||!$&&E(D)){let J=$==="help"?z||O[0]:void 0;if(J)process.stdout.write(`${g(J)}
186
+ `);else bU();return Q.OK}if(!$){if(A(process.stdout))await P$();else bU();return Q.OK}if(E(D))return process.stdout.write(`${g($)}
187
+ `),Q.OK;let w=await uU({apiUrl:K(D,"api-url","apiUrl"),token:K(D,"token"),workspace:K(D,"workspace","w"),json:G(D,"json","j")?!0:void 0,debug:G(D,"debug"),quiet:G(D,"quiet","q"),yes:G(D,"yes","y")});if(f(D))return V({version:B},w),Q.OK;try{switch($){case"auth":await YU(w,z,D,O);break;case"workspace":case"workspaces":await qU(w,z,D,O);break;case"account":case"accounts":await KU(w,z??"list",D,O);break;case"post":case"posts":await GU(w,z,D,O);break;case"draft":case"drafts":await kU(w,z,D,O);break;case"media":await FU(w,z,D,O);break;case"memory":{let J=X?[X,z].filter(Boolean):z?[z]:[];await RU(w,J,D,O);break}case"personalization":case"voice":await TU(w,z,D,O);break;case"skill":case"skills":await LU(w,z,D,O);break;case"update":case"upgrade":case"self-update":await AU(w,z,D);break;case"version":V({version:B},w);break;default:throw new Z(`Unknown command "${$}". Run dun --help`,Q.USAGE)}return Q.OK}catch(J){return OU(J,w)}}var L$=await d$(process.argv.slice(2));process.exit(L$);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dunsocial",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
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",
@@ -1,30 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Gated install tip — silent in CI / non-TTY / agent installs.
4
- * Keep in sync with apps/cli/src/brand.ts OpenCode-style block art.
3
+ * Quiet install tip — silent in CI / non-TTY / agent / local deps.
4
+ * Max 2 lines; onboarding lives on bare `dun`, not here.
5
5
  */
6
6
  'use strict';
7
7
 
8
+ import { readFileSync } from 'node:fs';
8
9
  import path from 'node:path';
9
- import { pathToFileURL } from 'node:url';
10
-
11
- const BANNER_FULL = [
12
- '█▀▀▄ █ █ █▀▀▄ █▀▀▀ █▀▀█ █▀▀▀ ▀█▀ █▀▀█ █',
13
- '█ █ █ █ █ █ ▀▀▀█ █ █ █ █ █▀▀█ █',
14
- '▀▀▀▀ ▀▀▀▀ ▀ ▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀'
15
- ].join('\n');
16
-
17
- const BANNER_MINI = [
18
- '█▀▀▄ █ █ █▀▀▄',
19
- '█ █ █ █ █ █',
20
- '▀▀▀▀ ▀▀▀▀ ▀ ▀',
21
- '',
22
- ' DunSocial'
23
- ].join('\n');
10
+ import { fileURLToPath, pathToFileURL } from 'node:url';
24
11
 
25
12
  /** Keep in sync with apps/cli/src/commands/help.ts Docs line. */
26
13
  export const DOCS_URL = 'https://dunsocial.com/docs/cli';
27
14
 
15
+ function packageVersion() {
16
+ try {
17
+ const here = path.dirname(fileURLToPath(import.meta.url));
18
+ const pkg = JSON.parse(readFileSync(path.join(here, '..', 'package.json'), 'utf8'));
19
+ return typeof pkg.version === 'string' ? pkg.version : '0.0.0';
20
+ } catch {
21
+ return '0.0.0';
22
+ }
23
+ }
24
+
28
25
  function isCi() {
29
26
  const env = process.env;
30
27
  return (
@@ -38,29 +35,11 @@ function isCi() {
38
35
  );
39
36
  }
40
37
 
41
- function maxWidth(art) {
42
- return Math.max(...art.split('\n').map((line) => line.length));
43
- }
44
-
45
- export function renderBanner(columns) {
46
- const cols = columns > 0 ? columns : 80;
47
- if (cols >= maxWidth(BANNER_FULL)) return BANNER_FULL;
48
- if (cols >= maxWidth(BANNER_MINI)) return BANNER_MINI;
49
- return 'DunSocial';
50
- }
51
-
52
38
  /** Human tip lines after a global install (exported for tests). */
53
- export function gettingStartedTip() {
39
+ export function gettingStartedTip(version = packageVersion()) {
54
40
  return [
55
- 'Get started:',
56
- ' dun auth login',
57
- ' dun workspace list',
58
- ' dun workspace use <slug>',
59
- ' dun accounts list',
60
- ' dun posts publish --text "Hello from DunSocial" --accounts ACCOUNT_ID',
61
- '',
62
- ' dun --help',
63
- ` Docs: ${DOCS_URL}`,
41
+ `dunsocial ${version} installed`,
42
+ `Run \`dun\` to get started | docs: ${DOCS_URL}`,
64
43
  ''
65
44
  ].join('\n');
66
45
  }
@@ -73,11 +52,7 @@ function main() {
73
52
  process.env.npm_config_global === 'true' || process.env.DUN_POSTINSTALL_FORCE === '1';
74
53
  if (!globalInstall) return;
75
54
 
76
- const columns = process.stderr.columns || process.stdout.columns || 80;
77
- const banner = renderBanner(columns);
78
-
79
- process.stderr.write(`\n${banner}\n\n`);
80
- process.stderr.write(`${gettingStartedTip()}\n`);
55
+ process.stderr.write(`\n${gettingStartedTip()}\n`);
81
56
  }
82
57
 
83
58
  try {