dblx 0.1.46 → 0.1.48
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 +79 -0
- package/dist/index.js +577 -42
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# dblx
|
|
2
|
+
|
|
3
|
+
CLI for [dblebox](https://app.dblebox.com) — thread-first communication.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
bunx dblx <command>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Authentication
|
|
12
|
+
|
|
13
|
+
Generate an API key from **Settings > API Keys** in the dblebox web app, then:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
dblx auth login
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
You'll be prompted for your key (starts with `dblx_`). Credentials are saved to `~/.config/dblx.json`.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
dblx auth whoami # show current user
|
|
23
|
+
dblx auth logout # remove saved credentials
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
You can also set `DBLEBOX_API_KEY` and `DBLEBOX_API_URL` environment variables instead of using `auth login`.
|
|
27
|
+
|
|
28
|
+
## Threads
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
dblx threads list # list your threads
|
|
32
|
+
dblx threads list --archived # include archived
|
|
33
|
+
dblx threads list --snoozed # include snoozed
|
|
34
|
+
dblx threads create --title "New thread" # create a thread
|
|
35
|
+
dblx threads create --title "..." --comment "First message"
|
|
36
|
+
dblx threads update <id> --title "New title"
|
|
37
|
+
dblx threads archive <id>
|
|
38
|
+
dblx threads unarchive <id>
|
|
39
|
+
dblx threads snooze <id> --until 2026-03-01T09:00:00
|
|
40
|
+
dblx threads unsnooze <id>
|
|
41
|
+
dblx threads set-parent <id> --parent <parent-id>
|
|
42
|
+
dblx threads set-today <id> # assign to today
|
|
43
|
+
dblx threads set-today <id> --date 2026-03-01
|
|
44
|
+
dblx threads unset-today <id>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Comments
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
dblx comments list --thread <id>
|
|
51
|
+
dblx comments add --thread <id> --body "Hello"
|
|
52
|
+
dblx comments edit <comment-id> --body "Updated text"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Members
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
dblx members list <thread-id>
|
|
59
|
+
dblx members invite <thread-id> --user alice@example.com
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Today
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
dblx today # show today's threads and note
|
|
66
|
+
dblx today --date 2026-03-01 # show a specific date
|
|
67
|
+
dblx today note # read today's daily note
|
|
68
|
+
dblx today note --set "My note" # update today's daily note
|
|
69
|
+
dblx today note --date 2026-03-01
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## JSON output
|
|
73
|
+
|
|
74
|
+
All read commands support `--json` for machine-readable output:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
dblx threads list --json
|
|
78
|
+
dblx today --json
|
|
79
|
+
```
|
package/dist/index.js
CHANGED
|
@@ -2079,9 +2079,13 @@ import {
|
|
|
2079
2079
|
unlinkSync,
|
|
2080
2080
|
existsSync
|
|
2081
2081
|
} from "fs";
|
|
2082
|
-
var CONFIG_DIR = join(homedir(), ".config");
|
|
2083
|
-
var CONFIG_PATH = join(CONFIG_DIR, "dblx.json");
|
|
2084
2082
|
var DEFAULT_API_URL = "https://app.dblebox.com";
|
|
2083
|
+
var DEFAULT_CONFIG_DIR = join(homedir(), ".config");
|
|
2084
|
+
var DEFAULT_CONFIG_PATH = join(DEFAULT_CONFIG_DIR, "dblx.json");
|
|
2085
|
+
var configPath = DEFAULT_CONFIG_PATH;
|
|
2086
|
+
function getConfigPath() {
|
|
2087
|
+
return configPath;
|
|
2088
|
+
}
|
|
2085
2089
|
function loadConfig() {
|
|
2086
2090
|
const envKey = process.env.DBLEBOX_API_KEY;
|
|
2087
2091
|
if (envKey) {
|
|
@@ -2090,50 +2094,358 @@ function loadConfig() {
|
|
|
2090
2094
|
api_url: process.env.DBLEBOX_API_URL || DEFAULT_API_URL
|
|
2091
2095
|
};
|
|
2092
2096
|
}
|
|
2093
|
-
if (!existsSync(
|
|
2097
|
+
if (!existsSync(configPath)) {
|
|
2094
2098
|
return null;
|
|
2095
2099
|
}
|
|
2096
2100
|
try {
|
|
2097
|
-
const raw = readFileSync(
|
|
2101
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
2098
2102
|
return JSON.parse(raw);
|
|
2099
2103
|
} catch {
|
|
2100
2104
|
return null;
|
|
2101
2105
|
}
|
|
2102
2106
|
}
|
|
2103
2107
|
function saveConfig(config) {
|
|
2104
|
-
|
|
2105
|
-
|
|
2108
|
+
const dir = join(configPath, "..");
|
|
2109
|
+
mkdirSync(dir, { recursive: true });
|
|
2110
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + `
|
|
2106
2111
|
`, "utf-8");
|
|
2107
2112
|
}
|
|
2108
2113
|
function deleteConfig() {
|
|
2109
|
-
if (existsSync(
|
|
2110
|
-
unlinkSync(
|
|
2114
|
+
if (existsSync(configPath)) {
|
|
2115
|
+
unlinkSync(configPath);
|
|
2111
2116
|
}
|
|
2112
2117
|
}
|
|
2113
|
-
|
|
2114
|
-
|
|
2118
|
+
|
|
2119
|
+
// ../node_modules/@elysiajs/eden/dist/chunk-QSLHAOSM.mjs
|
|
2120
|
+
var s = class extends Error {
|
|
2121
|
+
constructor(e, n) {
|
|
2122
|
+
super(n + "");
|
|
2123
|
+
this.status = e;
|
|
2124
|
+
this.value = n;
|
|
2125
|
+
}
|
|
2126
|
+
};
|
|
2127
|
+
var i = /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/;
|
|
2128
|
+
var o = /(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)\s(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{2}\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT(?:\+|-)\d{4}\s\([^)]+\)/;
|
|
2129
|
+
var c = /^(?:(?:(?:(?:0?[1-9]|[12][0-9]|3[01])[/\s-](?:0?[1-9]|1[0-2])[/\s-](?:19|20)\d{2})|(?:(?:19|20)\d{2}[/\s-](?:0?[1-9]|1[0-2])[/\s-](?:0?[1-9]|[12][0-9]|3[01]))))(?:\s(?:1[012]|0?[1-9]):[0-5][0-9](?::[0-5][0-9])?(?:\s[AP]M)?)?$/;
|
|
2130
|
+
var u = (t) => t.trim().length !== 0 && !Number.isNaN(Number(t));
|
|
2131
|
+
var d = (t) => {
|
|
2132
|
+
if (typeof t != "string")
|
|
2133
|
+
return null;
|
|
2134
|
+
let r = t.replace(/"/g, "");
|
|
2135
|
+
if (i.test(r) || o.test(r) || c.test(r)) {
|
|
2136
|
+
let e = new Date(r);
|
|
2137
|
+
if (!Number.isNaN(e.getTime()))
|
|
2138
|
+
return e;
|
|
2139
|
+
}
|
|
2140
|
+
return null;
|
|
2141
|
+
};
|
|
2142
|
+
var a = (t) => {
|
|
2143
|
+
let r = t.charCodeAt(0), e = t.charCodeAt(t.length - 1);
|
|
2144
|
+
return r === 123 && e === 125 || r === 91 && e === 93;
|
|
2145
|
+
};
|
|
2146
|
+
var p = (t) => JSON.parse(t, (r, e) => {
|
|
2147
|
+
let n = d(e);
|
|
2148
|
+
return n || e;
|
|
2149
|
+
});
|
|
2150
|
+
var g = (t) => {
|
|
2151
|
+
if (!t)
|
|
2152
|
+
return t;
|
|
2153
|
+
if (u(t))
|
|
2154
|
+
return +t;
|
|
2155
|
+
if (t === "true")
|
|
2156
|
+
return true;
|
|
2157
|
+
if (t === "false")
|
|
2158
|
+
return false;
|
|
2159
|
+
let r = d(t);
|
|
2160
|
+
if (r)
|
|
2161
|
+
return r;
|
|
2162
|
+
if (a(t))
|
|
2163
|
+
try {
|
|
2164
|
+
return p(t);
|
|
2165
|
+
} catch {}
|
|
2166
|
+
return t;
|
|
2167
|
+
};
|
|
2168
|
+
var S = (t) => {
|
|
2169
|
+
let r = t.data.toString();
|
|
2170
|
+
return r === "null" ? null : g(r);
|
|
2171
|
+
};
|
|
2172
|
+
|
|
2173
|
+
// ../node_modules/@elysiajs/eden/dist/chunk-LJDYVDXQ.mjs
|
|
2174
|
+
var F = class {
|
|
2175
|
+
constructor(t) {
|
|
2176
|
+
this.url = t;
|
|
2177
|
+
this.ws = new WebSocket(t);
|
|
2178
|
+
}
|
|
2179
|
+
ws;
|
|
2180
|
+
send(t) {
|
|
2181
|
+
return Array.isArray(t) ? (t.forEach((n) => this.send(n)), this) : (this.ws.send(typeof t == "object" ? JSON.stringify(t) : t.toString()), this);
|
|
2182
|
+
}
|
|
2183
|
+
on(t, n, s2) {
|
|
2184
|
+
return this.addEventListener(t, n, s2);
|
|
2185
|
+
}
|
|
2186
|
+
off(t, n, s2) {
|
|
2187
|
+
return this.ws.removeEventListener(t, n, s2), this;
|
|
2188
|
+
}
|
|
2189
|
+
subscribe(t, n) {
|
|
2190
|
+
return this.addEventListener("message", t, n);
|
|
2191
|
+
}
|
|
2192
|
+
addEventListener(t, n, s2) {
|
|
2193
|
+
return this.ws.addEventListener(t, (f) => {
|
|
2194
|
+
if (t === "message") {
|
|
2195
|
+
let o2 = S(f);
|
|
2196
|
+
n({ ...f, data: o2 });
|
|
2197
|
+
} else
|
|
2198
|
+
n(f);
|
|
2199
|
+
}, s2), this;
|
|
2200
|
+
}
|
|
2201
|
+
removeEventListener(t, n, s2) {
|
|
2202
|
+
return this.off(t, n, s2), this;
|
|
2203
|
+
}
|
|
2204
|
+
close() {
|
|
2205
|
+
return this.ws.close(), this;
|
|
2206
|
+
}
|
|
2207
|
+
};
|
|
2208
|
+
var J = ["get", "post", "put", "delete", "patch", "options", "head", "connect", "subscribe"];
|
|
2209
|
+
var D = ["localhost", "127.0.0.1", "0.0.0.0"];
|
|
2210
|
+
var K = typeof FileList > "u";
|
|
2211
|
+
var I = (e) => K ? e instanceof Blob : e instanceof FileList || e instanceof File;
|
|
2212
|
+
var P = (e) => {
|
|
2213
|
+
if (!e)
|
|
2214
|
+
return false;
|
|
2215
|
+
for (let t in e)
|
|
2216
|
+
if (I(e[t]) || Array.isArray(e[t]) && e[t].find(I))
|
|
2217
|
+
return true;
|
|
2218
|
+
return false;
|
|
2219
|
+
};
|
|
2220
|
+
var C = (e) => K ? e : new Promise((t) => {
|
|
2221
|
+
let n = new FileReader;
|
|
2222
|
+
n.onload = () => {
|
|
2223
|
+
let s2 = new File([n.result], e.name, { lastModified: e.lastModified, type: e.type });
|
|
2224
|
+
t(s2);
|
|
2225
|
+
}, n.readAsArrayBuffer(e);
|
|
2226
|
+
});
|
|
2227
|
+
var b = (e, t, n = {}, s2 = {}) => {
|
|
2228
|
+
if (Array.isArray(e)) {
|
|
2229
|
+
for (let f of e)
|
|
2230
|
+
if (!Array.isArray(f))
|
|
2231
|
+
s2 = b(f, t, n, s2);
|
|
2232
|
+
else {
|
|
2233
|
+
let o2 = f[0];
|
|
2234
|
+
if (typeof o2 == "string")
|
|
2235
|
+
s2[o2.toLowerCase()] = f[1];
|
|
2236
|
+
else
|
|
2237
|
+
for (let [i2, h] of o2)
|
|
2238
|
+
s2[i2.toLowerCase()] = h;
|
|
2239
|
+
}
|
|
2240
|
+
return s2;
|
|
2241
|
+
}
|
|
2242
|
+
if (!e)
|
|
2243
|
+
return s2;
|
|
2244
|
+
switch (typeof e) {
|
|
2245
|
+
case "function":
|
|
2246
|
+
if (e instanceof Headers)
|
|
2247
|
+
return b(e, t, n, s2);
|
|
2248
|
+
let f = e(t, n);
|
|
2249
|
+
return f ? b(f, t, n, s2) : s2;
|
|
2250
|
+
case "object":
|
|
2251
|
+
if (e instanceof Headers)
|
|
2252
|
+
return e.forEach((o2, i2) => {
|
|
2253
|
+
s2[i2.toLowerCase()] = o2;
|
|
2254
|
+
}), s2;
|
|
2255
|
+
for (let [o2, i2] of Object.entries(e))
|
|
2256
|
+
s2[o2.toLowerCase()] = i2;
|
|
2257
|
+
return s2;
|
|
2258
|
+
default:
|
|
2259
|
+
return s2;
|
|
2260
|
+
}
|
|
2261
|
+
};
|
|
2262
|
+
async function* U(e) {
|
|
2263
|
+
let t = e.body;
|
|
2264
|
+
if (!t)
|
|
2265
|
+
return;
|
|
2266
|
+
let n = t.getReader(), s2 = new TextDecoder;
|
|
2267
|
+
try {
|
|
2268
|
+
for (;; ) {
|
|
2269
|
+
let { done: f, value: o2 } = await n.read();
|
|
2270
|
+
if (f)
|
|
2271
|
+
break;
|
|
2272
|
+
let i2 = typeof o2 == "string" ? o2 : s2.decode(o2);
|
|
2273
|
+
i2.includes(`
|
|
2274
|
+
|
|
2275
|
+
`) ? yield* _(i2) : yield g(i2);
|
|
2276
|
+
}
|
|
2277
|
+
} finally {
|
|
2278
|
+
n.releaseLock();
|
|
2279
|
+
}
|
|
2115
2280
|
}
|
|
2281
|
+
function* _(e) {
|
|
2282
|
+
let t = e.split(`
|
|
2283
|
+
|
|
2284
|
+
`);
|
|
2285
|
+
for (let n of t) {
|
|
2286
|
+
if (n.indexOf(":") <= 0) {
|
|
2287
|
+
n && (yield g(n));
|
|
2288
|
+
continue;
|
|
2289
|
+
}
|
|
2290
|
+
let s2 = n.split(`
|
|
2291
|
+
`), f = {};
|
|
2292
|
+
for (let o2 of s2) {
|
|
2293
|
+
let i2 = o2.indexOf(":");
|
|
2294
|
+
if (i2 > 0) {
|
|
2295
|
+
let h = o2.slice(0, i2).trim(), L = o2.slice(i2 + 1).trim();
|
|
2296
|
+
f[h] = g(L);
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
yield f;
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
var x = (e, t, n = [], s2) => new Proxy(() => {}, { get(f, o2) {
|
|
2303
|
+
return x(e, t, o2 === "index" ? n : [...n, o2], s2);
|
|
2304
|
+
}, apply(f, o2, [i2, h]) {
|
|
2305
|
+
if (!i2 || h || typeof i2 == "object" && Object.keys(i2).length !== 1 || J.includes(n.at(-1))) {
|
|
2306
|
+
let L = [...n], k = L.pop(), v = "/" + L.join("/"), { fetcher: N = fetch, headers: R, onRequest: g2, onResponse: E, fetch: H } = t, m = k === "get" || k === "head" || k === "subscribe";
|
|
2307
|
+
R = b(R, v, h);
|
|
2308
|
+
let T = m ? i2?.query : h?.query, O = "";
|
|
2309
|
+
if (T) {
|
|
2310
|
+
let r = (w, u2) => {
|
|
2311
|
+
O += (O ? "&" : "?") + `${encodeURIComponent(w)}=${encodeURIComponent(u2)}`;
|
|
2312
|
+
};
|
|
2313
|
+
for (let [w, u2] of Object.entries(T)) {
|
|
2314
|
+
if (Array.isArray(u2)) {
|
|
2315
|
+
for (let y of u2)
|
|
2316
|
+
r(w, y);
|
|
2317
|
+
continue;
|
|
2318
|
+
}
|
|
2319
|
+
if (u2 != null) {
|
|
2320
|
+
if (typeof u2 == "object") {
|
|
2321
|
+
r(w, JSON.stringify(u2));
|
|
2322
|
+
continue;
|
|
2323
|
+
}
|
|
2324
|
+
r(w, `${u2}`);
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
if (k === "subscribe") {
|
|
2329
|
+
let r = e.replace(/^([^]+):\/\//, e.startsWith("https://") ? "wss://" : e.startsWith("http://") || D.find((w) => e.includes(w)) ? "ws://" : "wss://") + v + O;
|
|
2330
|
+
return new F(r);
|
|
2331
|
+
}
|
|
2332
|
+
return (async () => {
|
|
2333
|
+
let r = { method: k?.toUpperCase(), body: i2, ...H, headers: R };
|
|
2334
|
+
r.headers = { ...R, ...b(m ? i2?.headers : h?.headers, v, r) };
|
|
2335
|
+
let w = m && typeof i2 == "object" ? i2.fetch : h?.fetch;
|
|
2336
|
+
if (r = { ...r, ...w }, m && delete r.body, g2) {
|
|
2337
|
+
Array.isArray(g2) || (g2 = [g2]);
|
|
2338
|
+
for (let l of g2) {
|
|
2339
|
+
let a2 = await l(v, r);
|
|
2340
|
+
typeof a2 == "object" && (r = { ...r, ...a2, headers: { ...r.headers, ...b(a2.headers, v, r) } });
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
if (m && delete r.body, P(i2)) {
|
|
2344
|
+
let l = new FormData;
|
|
2345
|
+
for (let [a2, c2] of Object.entries(r.body)) {
|
|
2346
|
+
if (Array.isArray(c2)) {
|
|
2347
|
+
for (let d2 = 0;d2 < c2.length; d2++) {
|
|
2348
|
+
let j = c2[d2];
|
|
2349
|
+
l.append(a2, j instanceof File ? await C(j) : j);
|
|
2350
|
+
}
|
|
2351
|
+
continue;
|
|
2352
|
+
}
|
|
2353
|
+
if (K) {
|
|
2354
|
+
if (Array.isArray(c2))
|
|
2355
|
+
for (let d2 of c2)
|
|
2356
|
+
l.append(a2, d2);
|
|
2357
|
+
else
|
|
2358
|
+
l.append(a2, c2);
|
|
2359
|
+
continue;
|
|
2360
|
+
}
|
|
2361
|
+
if (c2 instanceof File) {
|
|
2362
|
+
l.append(a2, await C(c2));
|
|
2363
|
+
continue;
|
|
2364
|
+
}
|
|
2365
|
+
if (c2 instanceof FileList) {
|
|
2366
|
+
for (let d2 = 0;d2 < c2.length; d2++)
|
|
2367
|
+
l.append(a2, await C(c2[d2]));
|
|
2368
|
+
continue;
|
|
2369
|
+
}
|
|
2370
|
+
l.append(a2, c2);
|
|
2371
|
+
}
|
|
2372
|
+
r.body = l;
|
|
2373
|
+
} else
|
|
2374
|
+
typeof i2 == "object" ? (r.headers["content-type"] = "application/json", r.body = JSON.stringify(i2)) : i2 != null && (r.headers["content-type"] = "text/plain");
|
|
2375
|
+
if (m && delete r.body, g2) {
|
|
2376
|
+
Array.isArray(g2) || (g2 = [g2]);
|
|
2377
|
+
for (let l of g2) {
|
|
2378
|
+
let a2 = await l(v, r);
|
|
2379
|
+
typeof a2 == "object" && (r = { ...r, ...a2, headers: { ...r.headers, ...b(a2.headers, v, r) } });
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
h?.headers?.["content-type"] && (r.headers["content-type"] = h?.headers["content-type"]);
|
|
2383
|
+
let u2 = e + v + O, y = await (s2?.handle(new Request(u2, r)) ?? N(u2, r)), p2 = null, S2 = null;
|
|
2384
|
+
if (E) {
|
|
2385
|
+
Array.isArray(E) || (E = [E]);
|
|
2386
|
+
for (let l of E)
|
|
2387
|
+
try {
|
|
2388
|
+
let a2 = await l(y.clone());
|
|
2389
|
+
if (a2 != null) {
|
|
2390
|
+
p2 = a2;
|
|
2391
|
+
break;
|
|
2392
|
+
}
|
|
2393
|
+
} catch (a2) {
|
|
2394
|
+
a2 instanceof s ? S2 = a2 : S2 = new s(422, a2);
|
|
2395
|
+
break;
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
if (p2 !== null)
|
|
2399
|
+
return { data: p2, error: S2, response: y, status: y.status, headers: y.headers };
|
|
2400
|
+
switch (y.headers.get("Content-Type")?.split(";")[0]) {
|
|
2401
|
+
case "text/event-stream":
|
|
2402
|
+
p2 = U(y);
|
|
2403
|
+
break;
|
|
2404
|
+
case "application/json":
|
|
2405
|
+
p2 = JSON.parse(await y.text(), (a2, c2) => {
|
|
2406
|
+
if (typeof c2 != "string")
|
|
2407
|
+
return c2;
|
|
2408
|
+
let d2 = d(c2);
|
|
2409
|
+
return d2 || c2;
|
|
2410
|
+
});
|
|
2411
|
+
break;
|
|
2412
|
+
case "application/octet-stream":
|
|
2413
|
+
p2 = await y.arrayBuffer();
|
|
2414
|
+
break;
|
|
2415
|
+
case "multipart/form-data":
|
|
2416
|
+
let l = await y.formData();
|
|
2417
|
+
p2 = {}, l.forEach((a2, c2) => {
|
|
2418
|
+
p2[c2] = a2;
|
|
2419
|
+
});
|
|
2420
|
+
break;
|
|
2421
|
+
default:
|
|
2422
|
+
p2 = await y.text().then(g);
|
|
2423
|
+
}
|
|
2424
|
+
return (y.status >= 300 || y.status < 200) && (S2 = new s(y.status, p2), p2 = null), { data: p2, error: S2, response: y, status: y.status, headers: y.headers };
|
|
2425
|
+
})();
|
|
2426
|
+
}
|
|
2427
|
+
return typeof i2 == "object" ? x(e, t, [...n, Object.values(i2)[0]], s2) : x(e, t, n);
|
|
2428
|
+
} });
|
|
2429
|
+
var Q = (e, t = {}) => typeof e == "string" ? (t.keepDomain || (e.includes("://") || (e = (D.find((n) => e.includes(n)) ? "http://" : "https://") + e), e.endsWith("/") && (e = e.slice(0, -1))), x(e, t)) : (typeof window < "u" && console.warn("Elysia instance server found on client side, this is not recommended for security reason. Use generic type instead."), x("http://e.ly", t, [], e));
|
|
2116
2430
|
|
|
2117
2431
|
// src/api.ts
|
|
2118
|
-
|
|
2432
|
+
function getApi() {
|
|
2119
2433
|
const config = loadConfig();
|
|
2120
2434
|
if (!config) {
|
|
2121
2435
|
throw new Error("Not logged in. Run: dblx auth login");
|
|
2122
2436
|
}
|
|
2123
|
-
|
|
2124
|
-
const res = await fetch(url, {
|
|
2125
|
-
...options,
|
|
2437
|
+
return Q(config.api_url, {
|
|
2126
2438
|
headers: {
|
|
2127
|
-
Authorization: `Bearer ${config.api_key}
|
|
2128
|
-
|
|
2129
|
-
|
|
2439
|
+
Authorization: `Bearer ${config.api_key}`
|
|
2440
|
+
}
|
|
2441
|
+
});
|
|
2442
|
+
}
|
|
2443
|
+
function getApiWith(apiKey, apiUrl) {
|
|
2444
|
+
return Q(apiUrl, {
|
|
2445
|
+
headers: {
|
|
2446
|
+
Authorization: `Bearer ${apiKey}`
|
|
2130
2447
|
}
|
|
2131
2448
|
});
|
|
2132
|
-
if (!res.ok) {
|
|
2133
|
-
const body = await res.json().catch(() => ({}));
|
|
2134
|
-
throw new Error(`API error (${res.status}): ${body.error || res.statusText}`);
|
|
2135
|
-
}
|
|
2136
|
-
return res.json();
|
|
2137
2449
|
}
|
|
2138
2450
|
|
|
2139
2451
|
// src/output.ts
|
|
@@ -2162,11 +2474,11 @@ function output(data, opts) {
|
|
|
2162
2474
|
function printTable(rows) {
|
|
2163
2475
|
const keys = Object.keys(rows[0]);
|
|
2164
2476
|
const widths = keys.map((k) => Math.max(k.length, ...rows.map((r) => String(r[k] ?? "").length)));
|
|
2165
|
-
const header = keys.map((k,
|
|
2477
|
+
const header = keys.map((k, i2) => k.padEnd(widths[i2])).join(" ");
|
|
2166
2478
|
console.log(header);
|
|
2167
2479
|
console.log(widths.map((w) => "-".repeat(w)).join(" "));
|
|
2168
2480
|
for (const row of rows) {
|
|
2169
|
-
const line = keys.map((k,
|
|
2481
|
+
const line = keys.map((k, i2) => String(row[k] ?? "").padEnd(widths[i2])).join(" ");
|
|
2170
2482
|
console.log(line);
|
|
2171
2483
|
}
|
|
2172
2484
|
}
|
|
@@ -2195,25 +2507,26 @@ var authCommand = new Command("auth").description("Manage authentication").addCo
|
|
|
2195
2507
|
console.error('Invalid API key format. Keys should start with "dblx_".');
|
|
2196
2508
|
process.exit(1);
|
|
2197
2509
|
}
|
|
2198
|
-
const
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
const me = await apiRequest("/api/cli/v1/me");
|
|
2202
|
-
console.log(`Logged in as ${me.username} (${me.email})`);
|
|
2203
|
-
console.log(`Config saved to ${getConfigPath()}`);
|
|
2204
|
-
} catch {
|
|
2205
|
-
deleteConfig();
|
|
2510
|
+
const api = getApiWith(apiKey, opts.apiUrl);
|
|
2511
|
+
const { data, error } = await api.api.cli.v1.me.get();
|
|
2512
|
+
if (error) {
|
|
2206
2513
|
console.error("Login failed. The API key may be invalid.");
|
|
2207
2514
|
process.exit(1);
|
|
2208
2515
|
}
|
|
2516
|
+
saveConfig({ api_key: apiKey, api_url: opts.apiUrl });
|
|
2517
|
+
console.log(`Logged in as ${data.username} (${data.email})`);
|
|
2518
|
+
console.log(`Config saved to ${getConfigPath()}`);
|
|
2209
2519
|
})).addCommand(new Command("whoami").description("Show the current authenticated user").option("--json", "Output as JSON").action(async (opts) => {
|
|
2210
2520
|
const config = loadConfig();
|
|
2211
2521
|
if (!config) {
|
|
2212
2522
|
console.error("Not logged in. Run: dblx auth login");
|
|
2213
2523
|
process.exit(1);
|
|
2214
2524
|
}
|
|
2215
|
-
const
|
|
2216
|
-
|
|
2525
|
+
const api = getApi();
|
|
2526
|
+
const { data, error } = await api.api.cli.v1.me.get();
|
|
2527
|
+
if (error)
|
|
2528
|
+
throw error;
|
|
2529
|
+
output(data, { json: opts.json });
|
|
2217
2530
|
})).addCommand(new Command("logout").description("Remove saved credentials").action(() => {
|
|
2218
2531
|
deleteConfig();
|
|
2219
2532
|
console.log("Logged out. Config removed.");
|
|
@@ -2221,13 +2534,15 @@ var authCommand = new Command("auth").description("Manage authentication").addCo
|
|
|
2221
2534
|
|
|
2222
2535
|
// src/commands/threads.ts
|
|
2223
2536
|
var threadsCommand = new Command("threads").description("Manage threads").addCommand(new Command("list").description("List your threads").option("--json", "Output as JSON").option("--archived", "Include archived threads").option("--snoozed", "Include snoozed threads").action(async (opts) => {
|
|
2224
|
-
const
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2537
|
+
const api = getApi();
|
|
2538
|
+
const { data, error } = await api.api.cli.v1.threads.get({
|
|
2539
|
+
query: {
|
|
2540
|
+
archived: opts.archived ? "true" : undefined,
|
|
2541
|
+
snoozed: opts.snoozed ? "true" : undefined
|
|
2542
|
+
}
|
|
2543
|
+
});
|
|
2544
|
+
if (error)
|
|
2545
|
+
throw error;
|
|
2231
2546
|
if (opts.json) {
|
|
2232
2547
|
output(data.threads, { json: true });
|
|
2233
2548
|
return;
|
|
@@ -2240,11 +2555,228 @@ var threadsCommand = new Command("threads").description("Manage threads").addCom
|
|
|
2240
2555
|
snoozed: t.snoozed ? "snoozed" : ""
|
|
2241
2556
|
}));
|
|
2242
2557
|
output(rows, { json: false });
|
|
2558
|
+
})).addCommand(new Command("create").description("Create a new thread").requiredOption("--title <title>", "Thread title").option("--comment <text>", "Optional first comment").option("--json", "Output as JSON").action(async (opts) => {
|
|
2559
|
+
const api = getApi();
|
|
2560
|
+
const { data, error } = await api.api.cli.v1.threads.post({
|
|
2561
|
+
body: opts.title,
|
|
2562
|
+
comment: opts.comment
|
|
2563
|
+
});
|
|
2564
|
+
if (error)
|
|
2565
|
+
throw error;
|
|
2566
|
+
if (opts.json) {
|
|
2567
|
+
output(data.thread, { json: true });
|
|
2568
|
+
return;
|
|
2569
|
+
}
|
|
2570
|
+
console.log(`Created thread ${data.thread.id.slice(0, 8)}: ${data.thread.body}`);
|
|
2571
|
+
})).addCommand(new Command("update").description("Update a thread title").argument("<id>", "Thread ID").requiredOption("--title <title>", "New title").option("--json", "Output as JSON").action(async (id, opts) => {
|
|
2572
|
+
const api = getApi();
|
|
2573
|
+
const { data, error } = await api.api.cli.v1.threads({ id }).put({
|
|
2574
|
+
body: opts.title
|
|
2575
|
+
});
|
|
2576
|
+
if (error)
|
|
2577
|
+
throw error;
|
|
2578
|
+
if (opts.json) {
|
|
2579
|
+
output(data.thread, { json: true });
|
|
2580
|
+
return;
|
|
2581
|
+
}
|
|
2582
|
+
console.log(`Updated thread ${data.thread.id.slice(0, 8)}: ${data.thread.body}`);
|
|
2583
|
+
})).addCommand(new Command("archive").description("Archive a thread").argument("<id>", "Thread ID").action(async (id) => {
|
|
2584
|
+
const api = getApi();
|
|
2585
|
+
const { error } = await api.api.cli.v1.threads({ id }).archive.put({
|
|
2586
|
+
archived: true
|
|
2587
|
+
});
|
|
2588
|
+
if (error)
|
|
2589
|
+
throw error;
|
|
2590
|
+
console.log("Archived.");
|
|
2591
|
+
})).addCommand(new Command("unarchive").description("Unarchive a thread").argument("<id>", "Thread ID").action(async (id) => {
|
|
2592
|
+
const api = getApi();
|
|
2593
|
+
const { error } = await api.api.cli.v1.threads({ id }).archive.put({
|
|
2594
|
+
archived: false
|
|
2595
|
+
});
|
|
2596
|
+
if (error)
|
|
2597
|
+
throw error;
|
|
2598
|
+
console.log("Unarchived.");
|
|
2599
|
+
})).addCommand(new Command("snooze").description("Snooze a thread").argument("<id>", "Thread ID").requiredOption("--until <datetime>", "Snooze until (ISO datetime)").action(async (id, opts) => {
|
|
2600
|
+
const api = getApi();
|
|
2601
|
+
const { error } = await api.api.cli.v1.threads({ id }).snooze.put({
|
|
2602
|
+
until: opts.until
|
|
2603
|
+
});
|
|
2604
|
+
if (error)
|
|
2605
|
+
throw error;
|
|
2606
|
+
console.log(`Snoozed until ${opts.until}.`);
|
|
2607
|
+
})).addCommand(new Command("unsnooze").description("Remove snooze from a thread").argument("<id>", "Thread ID").action(async (id) => {
|
|
2608
|
+
const api = getApi();
|
|
2609
|
+
const { error } = await api.api.cli.v1.threads({ id }).snooze.put({
|
|
2610
|
+
until: null
|
|
2611
|
+
});
|
|
2612
|
+
if (error)
|
|
2613
|
+
throw error;
|
|
2614
|
+
console.log("Unsnoozed.");
|
|
2615
|
+
})).addCommand(new Command("set-parent").description("Set a parent thread").argument("<id>", "Thread ID").requiredOption("--parent <parent-id>", "Parent thread ID").action(async (id, opts) => {
|
|
2616
|
+
const api = getApi();
|
|
2617
|
+
const { error } = await api.api.cli.v1.threads({ id }).parent.put({
|
|
2618
|
+
parent_id: opts.parent
|
|
2619
|
+
});
|
|
2620
|
+
if (error)
|
|
2621
|
+
throw error;
|
|
2622
|
+
console.log(`Parent set to ${opts.parent.slice(0, 8)}.`);
|
|
2623
|
+
})).addCommand(new Command("set-today").description("Assign thread to a date").argument("<id>", "Thread ID").option("--date <date>", "Date (YYYY-MM-DD)", new Date().toISOString().slice(0, 10)).action(async (id, opts) => {
|
|
2624
|
+
const api = getApi();
|
|
2625
|
+
const { error } = await api.api.cli.v1.threads({ id }).today.put({
|
|
2626
|
+
date: opts.date
|
|
2627
|
+
});
|
|
2628
|
+
if (error)
|
|
2629
|
+
throw error;
|
|
2630
|
+
console.log(`Assigned to ${opts.date}.`);
|
|
2631
|
+
})).addCommand(new Command("unset-today").description("Remove thread from a date").argument("<id>", "Thread ID").option("--date <date>", "Date (YYYY-MM-DD)", new Date().toISOString().slice(0, 10)).action(async (id, opts) => {
|
|
2632
|
+
const api = getApi();
|
|
2633
|
+
const { error } = await api.api.cli.v1.threads({ id }).today.delete({
|
|
2634
|
+
date: opts.date
|
|
2635
|
+
});
|
|
2636
|
+
if (error)
|
|
2637
|
+
throw error;
|
|
2638
|
+
console.log(`Removed from ${opts.date}.`);
|
|
2639
|
+
}));
|
|
2640
|
+
|
|
2641
|
+
// src/commands/comments.ts
|
|
2642
|
+
var commentsCommand = new Command("comments").description("Manage comments").addCommand(new Command("list").description("List comments in a thread").requiredOption("--thread <id>", "Thread ID").option("--json", "Output as JSON").action(async (opts) => {
|
|
2643
|
+
const api = getApi();
|
|
2644
|
+
const { data, error } = await api.api.cli.v1.threads({ id: opts.thread }).comments.get();
|
|
2645
|
+
if (error)
|
|
2646
|
+
throw error;
|
|
2647
|
+
if (opts.json) {
|
|
2648
|
+
output(data.comments, { json: true });
|
|
2649
|
+
return;
|
|
2650
|
+
}
|
|
2651
|
+
const rows = data.comments.map((c2) => ({
|
|
2652
|
+
id: c2.id.slice(0, 8),
|
|
2653
|
+
user: c2.creator_username,
|
|
2654
|
+
body: c2.body.length > 60 ? c2.body.slice(0, 57) + "..." : c2.body,
|
|
2655
|
+
created_at: c2.created_at
|
|
2656
|
+
}));
|
|
2657
|
+
output(rows, { json: false });
|
|
2658
|
+
})).addCommand(new Command("add").description("Add a comment to a thread").requiredOption("--thread <id>", "Thread ID").requiredOption("--body <text>", "Comment text").option("--json", "Output as JSON").action(async (opts) => {
|
|
2659
|
+
const api = getApi();
|
|
2660
|
+
const { data, error } = await api.api.cli.v1.threads({ id: opts.thread }).comments.post({ body: opts.body });
|
|
2661
|
+
if (error)
|
|
2662
|
+
throw error;
|
|
2663
|
+
if (opts.json) {
|
|
2664
|
+
output(data.comment, { json: true });
|
|
2665
|
+
return;
|
|
2666
|
+
}
|
|
2667
|
+
console.log(`Comment added (${data.comment.id.slice(0, 8)}).`);
|
|
2668
|
+
})).addCommand(new Command("edit").description("Edit a comment").argument("<id>", "Comment ID").requiredOption("--body <text>", "New comment text").option("--json", "Output as JSON").action(async (id, opts) => {
|
|
2669
|
+
const api = getApi();
|
|
2670
|
+
const { data, error } = await api.api.cli.v1.comments({ id }).put({ body: opts.body });
|
|
2671
|
+
if (error)
|
|
2672
|
+
throw error;
|
|
2673
|
+
if (opts.json) {
|
|
2674
|
+
output(data.comment, { json: true });
|
|
2675
|
+
return;
|
|
2676
|
+
}
|
|
2677
|
+
console.log(`Comment updated (${data.comment.id.slice(0, 8)}).`);
|
|
2678
|
+
}));
|
|
2679
|
+
|
|
2680
|
+
// src/commands/members.ts
|
|
2681
|
+
var membersCommand = new Command("members").description("Manage thread members").addCommand(new Command("list").description("List members of a thread").argument("<thread-id>", "Thread ID").option("--json", "Output as JSON").action(async (threadId, opts) => {
|
|
2682
|
+
const api = getApi();
|
|
2683
|
+
const { data, error } = await api.api.cli.v1.threads({ id: threadId }).members.get();
|
|
2684
|
+
if (error)
|
|
2685
|
+
throw error;
|
|
2686
|
+
if (opts.json) {
|
|
2687
|
+
output(data.members, { json: true });
|
|
2688
|
+
return;
|
|
2689
|
+
}
|
|
2690
|
+
const rows = data.members.filter((m) => !m.revoked_at).map((m) => ({
|
|
2691
|
+
username: m.username,
|
|
2692
|
+
email: m.email
|
|
2693
|
+
}));
|
|
2694
|
+
output(rows, { json: false });
|
|
2695
|
+
})).addCommand(new Command("invite").description("Invite a user to a thread").argument("<thread-id>", "Thread ID").requiredOption("--user <email-or-username>", "User email or username").action(async (threadId, opts) => {
|
|
2696
|
+
const api = getApi();
|
|
2697
|
+
const { data, error } = await api.api.cli.v1.threads({ id: threadId }).members.post({ user: opts.user });
|
|
2698
|
+
if (error)
|
|
2699
|
+
throw error;
|
|
2700
|
+
if (data.invited) {
|
|
2701
|
+
console.log(`Invited ${data.user?.username || opts.user}.`);
|
|
2702
|
+
} else {
|
|
2703
|
+
console.log(data.reason || "Could not invite user.");
|
|
2704
|
+
}
|
|
2705
|
+
}));
|
|
2706
|
+
|
|
2707
|
+
// src/commands/today.ts
|
|
2708
|
+
function localDate(dateArg) {
|
|
2709
|
+
if (dateArg)
|
|
2710
|
+
return dateArg;
|
|
2711
|
+
const now = new Date;
|
|
2712
|
+
const y = now.getFullYear();
|
|
2713
|
+
const m = String(now.getMonth() + 1).padStart(2, "0");
|
|
2714
|
+
const d2 = String(now.getDate()).padStart(2, "0");
|
|
2715
|
+
return `${y}-${m}-${d2}`;
|
|
2716
|
+
}
|
|
2717
|
+
var todayCommand = new Command("today").description("Today view — threads and daily note").option("--date <date>", "Date (YYYY-MM-DD)").option("--json", "Output as JSON").action(async (opts) => {
|
|
2718
|
+
const date = localDate(opts.date);
|
|
2719
|
+
const api = getApi();
|
|
2720
|
+
const { data, error } = await api.api.cli.v1.today.get({
|
|
2721
|
+
query: { date }
|
|
2722
|
+
});
|
|
2723
|
+
if (error)
|
|
2724
|
+
throw error;
|
|
2725
|
+
if (opts.json) {
|
|
2726
|
+
output(data, { json: true });
|
|
2727
|
+
return;
|
|
2728
|
+
}
|
|
2729
|
+
console.log(`Date: ${data.date}
|
|
2730
|
+
`);
|
|
2731
|
+
if (data.threads.length > 0) {
|
|
2732
|
+
console.log("Threads:");
|
|
2733
|
+
for (const t of data.threads) {
|
|
2734
|
+
console.log(` ${t.id.slice(0, 8)} ${t.body}`);
|
|
2735
|
+
}
|
|
2736
|
+
console.log();
|
|
2737
|
+
} else {
|
|
2738
|
+
console.log(`No threads for this date.
|
|
2739
|
+
`);
|
|
2740
|
+
}
|
|
2741
|
+
if (data.note) {
|
|
2742
|
+
console.log("Note:");
|
|
2743
|
+
console.log(data.note.content || "(empty)");
|
|
2744
|
+
} else {
|
|
2745
|
+
console.log("No daily note.");
|
|
2746
|
+
}
|
|
2747
|
+
}).addCommand(new Command("note").description("Read or update the daily note").option("--date <date>", "Date (YYYY-MM-DD)").option("--set <content>", "Set note content").option("--json", "Output as JSON").action(async (opts) => {
|
|
2748
|
+
const date = localDate(opts.date);
|
|
2749
|
+
const api = getApi();
|
|
2750
|
+
if (opts.set !== undefined) {
|
|
2751
|
+
const { data: data2, error: error2 } = await api.api.cli.v1.today.note.put({ content: opts.set }, { query: { date } });
|
|
2752
|
+
if (error2)
|
|
2753
|
+
throw error2;
|
|
2754
|
+
if (opts.json) {
|
|
2755
|
+
output(data2, { json: true });
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
console.log("Note updated.");
|
|
2759
|
+
return;
|
|
2760
|
+
}
|
|
2761
|
+
const { data, error } = await api.api.cli.v1.today.note.get({
|
|
2762
|
+
query: { date }
|
|
2763
|
+
});
|
|
2764
|
+
if (error)
|
|
2765
|
+
throw error;
|
|
2766
|
+
if (opts.json) {
|
|
2767
|
+
output(data, { json: true });
|
|
2768
|
+
return;
|
|
2769
|
+
}
|
|
2770
|
+
if (!data.note) {
|
|
2771
|
+
console.log("No daily note.");
|
|
2772
|
+
return;
|
|
2773
|
+
}
|
|
2774
|
+
console.log(data.note.content || "(empty)");
|
|
2243
2775
|
}));
|
|
2244
2776
|
// package.json
|
|
2245
2777
|
var package_default = {
|
|
2246
2778
|
name: "dblx",
|
|
2247
|
-
version: "0.1.
|
|
2779
|
+
version: "0.1.48",
|
|
2248
2780
|
description: "CLI for dblebox — thread-first communication",
|
|
2249
2781
|
type: "module",
|
|
2250
2782
|
bin: {
|
|
@@ -2272,6 +2804,9 @@ var package_default = {
|
|
|
2272
2804
|
var program2 = new Command().name("dblx").description("CLI for dblebox — thread-first communication").version(package_default.version);
|
|
2273
2805
|
program2.addCommand(authCommand);
|
|
2274
2806
|
program2.addCommand(threadsCommand);
|
|
2807
|
+
program2.addCommand(commentsCommand);
|
|
2808
|
+
program2.addCommand(membersCommand);
|
|
2809
|
+
program2.addCommand(todayCommand);
|
|
2275
2810
|
program2.parseAsync().catch((err) => {
|
|
2276
2811
|
console.error(err.message);
|
|
2277
2812
|
process.exit(1);
|