dblx 0.1.49 → 0.1.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +113 -37
  2. package/dist/index.js +442 -342
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -4,76 +4,152 @@ CLI for [dblebox](https://app.dblebox.com) — thread-first communication.
4
4
 
5
5
  ## Usage
6
6
 
7
+ The CLI uses a verb-first command structure:
8
+
9
+ ```bash
10
+ bunx dblx <verb> <noun> [options]
11
+ ```
12
+
13
+ Examples:
14
+
15
+ ```bash
16
+ dblx get threads
17
+ dblx get threads --q "planning"
18
+ dblx get today
19
+ dblx create thread --title "New thread"
20
+ dblx set thread 12345678 --title "Renamed"
21
+ ```
22
+
23
+ ## Command Model
24
+
25
+ Read operations use `get`:
26
+
27
+ ```bash
28
+ dblx get ...
7
29
  ```
8
- bunx dblx <command>
30
+
31
+ Write operations use `create`, `set`, and `invite`:
32
+
33
+ ```bash
34
+ dblx create ...
35
+ dblx set ...
36
+ dblx invite ...
9
37
  ```
10
38
 
39
+ This keeps permission boundaries clear for agents and automation. A tool can be granted `dblx get ...` without also gaining write access.
40
+
11
41
  ## Authentication
12
42
 
13
43
  Generate an API key from **Settings > API Keys** in the dblebox web app, then:
14
44
 
15
- ```
45
+ ```bash
16
46
  dblx auth login
17
47
  ```
18
48
 
19
49
  You'll be prompted for your key (starts with `dblx_`). Credentials are saved to `~/.config/dblx.json`.
20
50
 
21
- ```
22
- dblx auth whoami # show current user
23
- dblx auth logout # remove saved credentials
51
+ ```bash
52
+ dblx auth whoami
53
+ dblx auth logout
24
54
  ```
25
55
 
26
56
  You can also set `DBLEBOX_API_KEY` and `DBLEBOX_API_URL` environment variables instead of using `auth login`.
27
57
 
28
- ## Threads
58
+ ## Read Commands
59
+
60
+ ### Threads
61
+
62
+ ```bash
63
+ dblx get threads
64
+ dblx get threads --archived
65
+ dblx get threads --snoozed
66
+ dblx get threads --archived --snoozed
67
+ dblx get threads --q "plan"
68
+ dblx get threads --q "#dblebox" --archived --snoozed
69
+ ```
70
+
71
+ ### Today
72
+
73
+ ```bash
74
+ dblx get today
75
+ dblx get today --date 2026-03-01
76
+ ```
77
+
78
+ ### Notes
29
79
 
80
+ ```bash
81
+ dblx get thread-note <thread-id>
82
+ dblx get today-note
83
+ dblx get today-note --date 2026-03-01
30
84
  ```
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>
85
+
86
+ ### Comments
87
+
88
+ ```bash
89
+ dblx get comments --thread <thread-id>
45
90
  ```
46
91
 
47
- ## Comments
92
+ ### Members
48
93
 
94
+ ```bash
95
+ dblx get members <thread-id>
49
96
  ```
50
- dblx comments list --thread <id>
51
- dblx comments add --thread <id> --body "Hello"
52
- dblx comments edit <comment-id> --body "Updated text"
97
+
98
+ ## Write Commands
99
+
100
+ ### Threads
101
+
102
+ ```bash
103
+ dblx create thread --title "New thread"
104
+ dblx create thread --title "..." --comment "First message"
105
+ dblx create thread --title "..." --note "Draft spec..."
106
+
107
+ dblx set thread <thread-id> --title "New title"
108
+ dblx set thread <thread-id> --archived true
109
+ dblx set thread <thread-id> --archived false
110
+ dblx set thread <thread-id> --snoozed-until 2026-03-01T09:00:00
111
+ dblx set thread <thread-id> --snoozed-until none
53
112
  ```
54
113
 
55
- ## Members
114
+ ### Notes
56
115
 
116
+ Reading and writing notes are separate commands.
117
+
118
+ ```bash
119
+ dblx set thread-note <thread-id> --content "Updated note"
120
+ dblx set today-note --content "My note"
121
+ dblx set today-note --date 2026-03-01 --content "My note"
57
122
  ```
58
- dblx members list <thread-id>
59
- dblx members invite <thread-id> --user alice@example.com
123
+
124
+ ### Relationships
125
+
126
+ ```bash
127
+ dblx set thread-parent <thread-id> --parent <parent-id>
128
+ dblx set thread-today <thread-id> --date 2026-03-01
129
+ dblx set thread-today <thread-id> --remove
130
+ dblx set thread-today <thread-id> --date 2026-03-01 --remove
60
131
  ```
61
132
 
62
- ## Today
133
+ ### Comments
63
134
 
135
+ ```bash
136
+ dblx create comment --thread <thread-id> --body "Hello"
137
+ dblx set comment <comment-id> --body "Updated text"
64
138
  ```
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
139
+
140
+ ### Members
141
+
142
+ ```bash
143
+ dblx invite member <thread-id> --user alice@example.com
70
144
  ```
71
145
 
72
- ## JSON output
146
+ ## JSON Output
73
147
 
74
148
  All read commands support `--json` for machine-readable output:
75
149
 
76
- ```
77
- dblx threads list --json
78
- dblx today --json
150
+ ```bash
151
+ dblx get threads --json
152
+ dblx get threads --q "plan" --json
153
+ dblx get today --json
154
+ dblx get thread-note <thread-id> --json
79
155
  ```
package/dist/index.js CHANGED
@@ -2088,21 +2088,32 @@ function getConfigPath() {
2088
2088
  }
2089
2089
  function loadConfig() {
2090
2090
  const envKey = process.env.DBLEBOX_API_KEY;
2091
+ const envUrl = process.env.DBLEBOX_API_URL;
2091
2092
  if (envKey) {
2092
2093
  return {
2093
2094
  api_key: envKey,
2094
- api_url: process.env.DBLEBOX_API_URL || DEFAULT_API_URL
2095
+ api_url: envUrl || DEFAULT_API_URL
2095
2096
  };
2096
2097
  }
2097
- if (!existsSync(configPath)) {
2098
- return null;
2098
+ let fileConfig = null;
2099
+ if (existsSync(configPath)) {
2100
+ try {
2101
+ const raw = readFileSync(configPath, "utf-8");
2102
+ fileConfig = JSON.parse(raw);
2103
+ } catch {
2104
+ return null;
2105
+ }
2099
2106
  }
2100
- try {
2101
- const raw = readFileSync(configPath, "utf-8");
2102
- return JSON.parse(raw);
2103
- } catch {
2107
+ if (!fileConfig) {
2104
2108
  return null;
2105
2109
  }
2110
+ if (envUrl) {
2111
+ return {
2112
+ api_key: fileConfig.api_key,
2113
+ api_url: envUrl
2114
+ };
2115
+ }
2116
+ return fileConfig;
2106
2117
  }
2107
2118
  function saveConfig(config) {
2108
2119
  const dir = join(configPath, "..");
@@ -2116,62 +2127,64 @@ function deleteConfig() {
2116
2127
  }
2117
2128
  }
2118
2129
 
2119
- // ../node_modules/@elysiajs/eden/dist/chunk-QSLHAOSM.mjs
2120
- var s = class extends Error {
2121
- constructor(e, n) {
2122
- super(n + "");
2130
+ // ../node_modules/@elysiajs/eden/dist/chunk-I5KHAGLL.mjs
2131
+ var d = class extends Error {
2132
+ constructor(e, s) {
2133
+ super(s + "");
2123
2134
  this.status = e;
2124
- this.value = n;
2135
+ this.value = s;
2125
2136
  }
2126
2137
  };
2127
2138
  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
2139
  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")
2140
+ var u = /^(?:(?:(?:(?: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)?)?$/;
2141
+ var c = (t) => t.trim().length !== 0 && !Number.isNaN(Number(t));
2142
+ var a = (t, r) => {
2143
+ if (typeof t != "string" || r?.parseDate === false)
2133
2144
  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;
2145
+ let e = t.replace(/"/g, "");
2146
+ if (i.test(e) || o.test(e) || u.test(e)) {
2147
+ let s = new Date(e);
2148
+ if (!Number.isNaN(s.getTime()))
2149
+ return s;
2139
2150
  }
2140
2151
  return null;
2141
2152
  };
2142
- var a = (t) => {
2153
+ var p = (t) => {
2143
2154
  let r = t.charCodeAt(0), e = t.charCodeAt(t.length - 1);
2144
2155
  return r === 123 && e === 125 || r === 91 && e === 93;
2145
2156
  };
2146
- var p = (t) => JSON.parse(t, (r, e) => {
2147
- let n = d(e);
2148
- return n || e;
2157
+ var f = (t, r) => JSON.parse(t, (e, s) => {
2158
+ let n = a(s, r);
2159
+ return n || s;
2149
2160
  });
2150
- var g = (t) => {
2161
+ var g = (t, r) => {
2151
2162
  if (!t)
2152
2163
  return t;
2153
- if (u(t))
2164
+ if (c(t))
2154
2165
  return +t;
2155
2166
  if (t === "true")
2156
2167
  return true;
2157
2168
  if (t === "false")
2158
2169
  return false;
2159
- let r = d(t);
2160
- if (r)
2161
- return r;
2162
- if (a(t))
2170
+ if (r?.parseDate !== false) {
2171
+ let e = a(t, r);
2172
+ if (e)
2173
+ return e;
2174
+ }
2175
+ if (p(t))
2163
2176
  try {
2164
- return p(t);
2177
+ return f(t, r);
2165
2178
  } catch {}
2166
2179
  return t;
2167
2180
  };
2168
- var S = (t) => {
2169
- let r = t.data.toString();
2170
- return r === "null" ? null : g(r);
2181
+ var S = (t, r) => {
2182
+ let e = t.data.toString();
2183
+ return e === "null" ? null : g(e, r);
2171
2184
  };
2172
2185
 
2173
- // ../node_modules/@elysiajs/eden/dist/chunk-LJDYVDXQ.mjs
2174
- var F = class {
2186
+ // ../node_modules/@elysiajs/eden/dist/chunk-AB4FCYGG.mjs
2187
+ var W = class {
2175
2188
  constructor(t) {
2176
2189
  this.url = t;
2177
2190
  this.ws = new WebSocket(t);
@@ -2180,253 +2193,283 @@ var F = class {
2180
2193
  send(t) {
2181
2194
  return Array.isArray(t) ? (t.forEach((n) => this.send(n)), this) : (this.ws.send(typeof t == "object" ? JSON.stringify(t) : t.toString()), this);
2182
2195
  }
2183
- on(t, n, s2) {
2184
- return this.addEventListener(t, n, s2);
2196
+ on(t, n, r) {
2197
+ return this.addEventListener(t, n, r);
2185
2198
  }
2186
- off(t, n, s2) {
2187
- return this.ws.removeEventListener(t, n, s2), this;
2199
+ off(t, n, r) {
2200
+ return this.ws.removeEventListener(t, n, r), this;
2188
2201
  }
2189
2202
  subscribe(t, n) {
2190
2203
  return this.addEventListener("message", t, n);
2191
2204
  }
2192
- addEventListener(t, n, s2) {
2193
- return this.ws.addEventListener(t, (f) => {
2205
+ addEventListener(t, n, r) {
2206
+ return this.ws.addEventListener(t, (c2) => {
2194
2207
  if (t === "message") {
2195
- let o2 = S(f);
2196
- n({ ...f, data: o2 });
2208
+ let i2 = S(c2);
2209
+ n({ ...c2, data: i2 });
2197
2210
  } else
2198
- n(f);
2199
- }, s2), this;
2211
+ n(c2);
2212
+ }, r), this;
2200
2213
  }
2201
- removeEventListener(t, n, s2) {
2202
- return this.off(t, n, s2), this;
2214
+ removeEventListener(t, n, r) {
2215
+ return this.off(t, n, r), this;
2203
2216
  }
2204
2217
  close() {
2205
2218
  return this.ws.close(), this;
2206
2219
  }
2207
2220
  };
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) => {
2221
+ var Q = ["get", "post", "put", "delete", "patch", "options", "head", "connect", "subscribe"];
2222
+ var P = (e, t) => typeof t == "function" ? t(e) : t === true;
2223
+ var U = ["localhost", "127.0.0.1", "0.0.0.0"];
2224
+ var q = typeof FileList > "u";
2225
+ var H = (e) => q ? e instanceof Blob : e instanceof FileList || e instanceof File;
2226
+ var X = (e) => {
2213
2227
  if (!e)
2214
2228
  return false;
2215
2229
  for (let t in e)
2216
- if (I(e[t]) || Array.isArray(e[t]) && e[t].find(I))
2230
+ if (H(e[t]) || Array.isArray(e[t]) && e[t].find(H))
2217
2231
  return true;
2218
2232
  return false;
2219
2233
  };
2220
- var C = (e) => K ? e : new Promise((t) => {
2234
+ var K = (e) => q ? e : new Promise((t) => {
2221
2235
  let n = new FileReader;
2222
2236
  n.onload = () => {
2223
- let s2 = new File([n.result], e.name, { lastModified: e.lastModified, type: e.type });
2224
- t(s2);
2237
+ let r = new File([n.result], e.name, { lastModified: e.lastModified, type: e.type });
2238
+ t(r);
2225
2239
  }, n.readAsArrayBuffer(e);
2226
2240
  });
2227
- var b = (e, t, n = {}, s2 = {}) => {
2241
+ var A = async (e, t, n = {}, r = {}) => {
2228
2242
  if (Array.isArray(e)) {
2229
- for (let f of e)
2230
- if (!Array.isArray(f))
2231
- s2 = b(f, t, n, s2);
2243
+ for (let c2 of e)
2244
+ if (!Array.isArray(c2))
2245
+ r = await A(c2, t, n, r);
2232
2246
  else {
2233
- let o2 = f[0];
2234
- if (typeof o2 == "string")
2235
- s2[o2.toLowerCase()] = f[1];
2247
+ let i2 = c2[0];
2248
+ if (typeof i2 == "string")
2249
+ r[i2.toLowerCase()] = c2[1];
2236
2250
  else
2237
- for (let [i2, h] of o2)
2238
- s2[i2.toLowerCase()] = h;
2251
+ for (let [a2, l] of i2)
2252
+ r[a2.toLowerCase()] = l;
2239
2253
  }
2240
- return s2;
2254
+ return r;
2241
2255
  }
2242
2256
  if (!e)
2243
- return s2;
2257
+ return r;
2244
2258
  switch (typeof e) {
2245
2259
  case "function":
2246
2260
  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;
2261
+ return A(e, t, n, r);
2262
+ let c2 = await e(t, n);
2263
+ return c2 ? A(c2, t, n, r) : r;
2250
2264
  case "object":
2251
2265
  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;
2266
+ return e.forEach((i2, a2) => {
2267
+ r[a2.toLowerCase()] = i2;
2268
+ }), r;
2269
+ for (let [i2, a2] of Object.entries(e))
2270
+ r[i2.toLowerCase()] = a2;
2271
+ return r;
2258
2272
  default:
2259
- return s2;
2273
+ return r;
2260
2274
  }
2261
2275
  };
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
+ function _(e, t) {
2277
+ let n = e.split(`
2278
+ `), r = {};
2279
+ for (let c2 of n) {
2280
+ if (!c2 || c2.startsWith(":"))
2281
+ continue;
2282
+ let i2 = c2.indexOf(":");
2283
+ if (i2 > 0) {
2284
+ let a2 = c2.slice(0, i2).trim(), l = c2.slice(i2 + 1).replace(/^ /, "");
2285
+ r[a2] = l && g(l, t);
2276
2286
  }
2277
- } finally {
2278
- n.releaseLock();
2279
2287
  }
2288
+ return Object.keys(r).length > 0 ? r : null;
2280
2289
  }
2281
- function* _(e) {
2282
- let t = e.split(`
2290
+ function* B(e, t) {
2291
+ let n;
2292
+ for (;(n = e.value.indexOf(`
2283
2293
 
2284
- `);
2285
- for (let n of t) {
2286
- if (n.indexOf(":") <= 0) {
2287
- n && (yield g(n));
2288
- continue;
2294
+ `)) !== -1; ) {
2295
+ let r = e.value.slice(0, n);
2296
+ if (e.value = e.value.slice(n + 2), r.trim()) {
2297
+ let c2 = _(r, t);
2298
+ c2 && (yield c2);
2289
2299
  }
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
- }
2300
+ }
2301
+ }
2302
+ async function* Y(e, t) {
2303
+ let n = e.body;
2304
+ if (!n)
2305
+ return;
2306
+ let r = n.getReader(), c2 = new TextDecoder("utf-8"), i2 = { value: "" };
2307
+ try {
2308
+ for (;; ) {
2309
+ let { done: l, value: O } = await r.read();
2310
+ if (l)
2311
+ break;
2312
+ let k = typeof O == "string" ? O : c2.decode(O, { stream: true });
2313
+ i2.value += k, yield* B(i2, t);
2314
+ }
2315
+ let a2 = c2.decode();
2316
+ if (a2 && (i2.value += a2), yield* B(i2, t), i2.value.trim()) {
2317
+ let l = _(i2.value, t);
2318
+ l && (yield l);
2298
2319
  }
2299
- yield f;
2320
+ } finally {
2321
+ r.releaseLock();
2300
2322
  }
2301
2323
  }
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)}`;
2324
+ var F = (e, t, n = [], r) => new Proxy(() => {}, { get(c2, i2) {
2325
+ if (!(n.length === 0 && (i2 === "then" || i2 === "catch" || i2 === "finally")))
2326
+ return F(e, t, [...n, i2], r);
2327
+ }, apply(c2, i2, [a2, l]) {
2328
+ if (!a2 || l || typeof a2 == "object" && Object.keys(a2).length !== 1 || Q.includes(n.at(-1))) {
2329
+ let O = [...n], k = O.pop(), b = "/" + O.join("/"), { fetcher: V = fetch, headers: L, onRequest: g2, onResponse: R, fetch: G } = t, E = k === "get" || k === "head" || k === "subscribe", M = E ? a2?.query : l?.query, D = "";
2330
+ if (M) {
2331
+ let s = (m, d2) => {
2332
+ d2 != null && (d2 instanceof Date && (d2 = d2.toISOString()), D += (D ? "&" : "?") + `${encodeURIComponent(m)}=${encodeURIComponent(typeof d2 == "object" ? JSON.stringify(d2) : d2 + "")}`);
2312
2333
  };
2313
- for (let [w, u2] of Object.entries(T)) {
2314
- if (Array.isArray(u2)) {
2315
- for (let y of u2)
2316
- r(w, y);
2334
+ for (let [m, d2] of Object.entries(M)) {
2335
+ if (Array.isArray(d2)) {
2336
+ for (let T of d2)
2337
+ s(m, T);
2317
2338
  continue;
2318
2339
  }
2319
- if (u2 != null) {
2320
- if (typeof u2 == "object") {
2321
- r(w, JSON.stringify(u2));
2322
- continue;
2323
- }
2324
- r(w, `${u2}`);
2325
- }
2340
+ s(m, d2);
2326
2341
  }
2327
2342
  }
2328
2343
  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);
2344
+ let s = e.replace(/^([^]+):\/\//, e.startsWith("https://") ? "wss://" : e.startsWith("http://") || U.find((m) => e.includes(m)) ? "ws://" : "wss://") + b + D;
2345
+ return new W(s);
2331
2346
  }
2332
2347
  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) {
2348
+ L = await A(L, b, l);
2349
+ let s = { method: k?.toUpperCase(), body: a2, ...G, headers: L };
2350
+ s.headers = { ...L, ...await A(E ? a2?.headers : l?.headers, b, s) };
2351
+ let m = E && typeof a2 == "object" ? a2.fetch : l?.fetch, T = (E && typeof a2 == "object" ? a2.throwHttpError : l?.throwHttpError) ?? t.throwHttpError;
2352
+ if (s = { ...s, ...m }, E && delete s.body, g2) {
2337
2353
  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) } });
2354
+ for (let u2 of g2) {
2355
+ let o2 = await u2(b, s);
2356
+ typeof o2 == "object" && (s = { ...s, ...o2, headers: { ...s.headers, ...await A(o2.headers, b, s) } });
2341
2357
  }
2342
2358
  }
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
- }
2359
+ if (E && delete s.body, X(a2)) {
2360
+ let u2 = new FormData, o2 = (f2) => {
2361
+ if (typeof f2 == "string" || H(f2))
2362
+ return false;
2363
+ if (typeof f2 == "object") {
2364
+ if (f2 !== null)
2365
+ return true;
2366
+ if (f2 instanceof Date)
2367
+ return false;
2368
+ }
2369
+ return false;
2370
+ }, w = async (f2) => f2 instanceof File ? await K(f2) : o2(f2) ? JSON.stringify(f2) : f2;
2371
+ for (let [f2, p2] of Object.entries(s.body)) {
2372
+ if (Array.isArray(p2)) {
2373
+ if (p2.some((S2) => typeof S2 == "object" && S2 !== null && !H(S2)))
2374
+ u2.append(f2, JSON.stringify(p2));
2375
+ else
2376
+ for (let S2 = 0;S2 < p2.length; S2++) {
2377
+ let $ = p2[S2], z = await w($);
2378
+ u2.append(f2, z);
2379
+ }
2351
2380
  continue;
2352
2381
  }
2353
- if (K) {
2354
- if (Array.isArray(c2))
2355
- for (let d2 of c2)
2356
- l.append(a2, d2);
2382
+ if (q) {
2383
+ if (Array.isArray(p2))
2384
+ for (let x of p2)
2385
+ u2.append(f2, await w(x));
2357
2386
  else
2358
- l.append(a2, c2);
2387
+ u2.append(f2, await w(p2));
2359
2388
  continue;
2360
2389
  }
2361
- if (c2 instanceof File) {
2362
- l.append(a2, await C(c2));
2390
+ if (p2 instanceof File) {
2391
+ u2.append(f2, await K(p2));
2363
2392
  continue;
2364
2393
  }
2365
- if (c2 instanceof FileList) {
2366
- for (let d2 = 0;d2 < c2.length; d2++)
2367
- l.append(a2, await C(c2[d2]));
2394
+ if (p2 instanceof FileList) {
2395
+ for (let x = 0;x < p2.length; x++)
2396
+ u2.append(f2, await K(p2[x]));
2368
2397
  continue;
2369
2398
  }
2370
- l.append(a2, c2);
2399
+ u2.append(f2, await w(p2));
2371
2400
  }
2372
- r.body = l;
2401
+ s.body = u2;
2373
2402
  } 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) {
2403
+ typeof a2 == "object" ? (s.headers["content-type"] = "application/json", s.body = JSON.stringify(a2)) : a2 != null && (s.headers["content-type"] = "text/plain");
2404
+ if (E && delete s.body, g2) {
2376
2405
  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) } });
2406
+ for (let u2 of g2) {
2407
+ let o2 = await u2(b, s);
2408
+ typeof o2 == "object" && (s = { ...s, ...o2, headers: { ...s.headers, ...await A(o2.headers, b, s) } });
2380
2409
  }
2381
2410
  }
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)
2411
+ l?.headers?.["content-type"] && (s.headers["content-type"] = l?.headers["content-type"]);
2412
+ let I = e + b + D, y;
2413
+ try {
2414
+ y = await (r?.handle(new Request(I, s)) ?? V(I, s));
2415
+ } catch (u2) {
2416
+ let o2 = new d(503, u2);
2417
+ if (P(o2, T))
2418
+ throw o2;
2419
+ return { data: null, error: o2, response: undefined, status: 503, headers: undefined };
2420
+ }
2421
+ let h = null, v = null;
2422
+ if (R) {
2423
+ Array.isArray(R) || (R = [R]);
2424
+ for (let u2 of R)
2387
2425
  try {
2388
- let a2 = await l(y.clone());
2389
- if (a2 != null) {
2390
- p2 = a2;
2426
+ let o2 = await u2(y.clone());
2427
+ if (o2 != null) {
2428
+ h = o2;
2391
2429
  break;
2392
2430
  }
2393
- } catch (a2) {
2394
- a2 instanceof s ? S2 = a2 : S2 = new s(422, a2);
2431
+ } catch (o2) {
2432
+ o2 instanceof d ? v = o2 : v = new d(422, o2);
2395
2433
  break;
2396
2434
  }
2397
2435
  }
2398
- if (p2 !== null)
2399
- return { data: p2, error: S2, response: y, status: y.status, headers: y.headers };
2436
+ if (h !== null)
2437
+ return { data: h, error: v, response: y, status: y.status, headers: y.headers };
2400
2438
  switch (y.headers.get("Content-Type")?.split(";")[0]) {
2401
2439
  case "text/event-stream":
2402
- p2 = U(y);
2440
+ h = Y(y, { parseDate: t.parseDate });
2403
2441
  break;
2404
2442
  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;
2443
+ h = JSON.parse(await y.text(), (o2, w) => {
2444
+ if (typeof w != "string")
2445
+ return w;
2446
+ let f2 = a(w, { parseDate: t.parseDate });
2447
+ return f2 || w;
2410
2448
  });
2411
2449
  break;
2412
2450
  case "application/octet-stream":
2413
- p2 = await y.arrayBuffer();
2451
+ h = await y.arrayBuffer();
2414
2452
  break;
2415
2453
  case "multipart/form-data":
2416
- let l = await y.formData();
2417
- p2 = {}, l.forEach((a2, c2) => {
2418
- p2[c2] = a2;
2454
+ let u2 = await y.formData();
2455
+ h = {}, u2.forEach((o2, w) => {
2456
+ h[w] = o2;
2419
2457
  });
2420
2458
  break;
2421
2459
  default:
2422
- p2 = await y.text().then(g);
2460
+ h = await y.text().then((o2) => g(o2, { parseDate: t.parseDate }));
2423
2461
  }
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 };
2462
+ if (y.status >= 300 || y.status < 200) {
2463
+ if (v = new d(y.status, h), P(v, T))
2464
+ throw v;
2465
+ h = null;
2466
+ }
2467
+ return { data: h, error: v, response: y, status: y.status, headers: y.headers };
2425
2468
  })();
2426
2469
  }
2427
- return typeof i2 == "object" ? x(e, t, [...n, Object.values(i2)[0]], s2) : x(e, t, n);
2470
+ return typeof a2 == "object" ? F(e, t, [...n, Object.values(a2)[0]], r) : F(e, t, n);
2428
2471
  } });
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));
2472
+ var se = (e, t = {}) => typeof e == "string" ? (t.keepDomain || (e.includes("://") || (e = (U.find((n) => e.includes(n)) ? "http://" : "https://") + e), e.endsWith("/") && (e = e.slice(0, -1))), F(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."), F("http://e.ly", t, [], e));
2430
2473
 
2431
2474
  // src/api.ts
2432
2475
  function getApi() {
@@ -2434,14 +2477,16 @@ function getApi() {
2434
2477
  if (!config) {
2435
2478
  throw new Error("Not logged in. Run: dblx auth login");
2436
2479
  }
2437
- return Q(config.api_url, {
2480
+ return se(config.api_url, {
2481
+ parseDate: false,
2438
2482
  headers: {
2439
2483
  Authorization: `Bearer ${config.api_key}`
2440
2484
  }
2441
2485
  });
2442
2486
  }
2443
2487
  function getApiWith(apiKey, apiUrl) {
2444
- return Q(apiUrl, {
2488
+ return se(apiUrl, {
2489
+ parseDate: false,
2445
2490
  headers: {
2446
2491
  Authorization: `Bearer ${apiKey}`
2447
2492
  }
@@ -2532,11 +2577,39 @@ var authCommand = new Command("auth").description("Manage authentication").addCo
2532
2577
  console.log("Logged out. Config removed.");
2533
2578
  }));
2534
2579
 
2535
- // src/commands/threads.ts
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) => {
2580
+ // src/commands/helpers.ts
2581
+ function threadRows(threads) {
2582
+ return threads.map((t) => ({
2583
+ id: t.id.slice(0, 8),
2584
+ body: t.body.length > 60 ? t.body.slice(0, 57) + "..." : t.body,
2585
+ unread: t.unread ? "*" : "",
2586
+ archived: t.archived ? "archived" : "",
2587
+ snoozed: t.snoozed ? "snoozed" : ""
2588
+ }));
2589
+ }
2590
+ function localDate(dateArg) {
2591
+ if (dateArg)
2592
+ return dateArg;
2593
+ const now = new Date;
2594
+ const y = now.getFullYear();
2595
+ const m = String(now.getMonth() + 1).padStart(2, "0");
2596
+ const d2 = String(now.getDate()).padStart(2, "0");
2597
+ return `${y}-${m}-${d2}`;
2598
+ }
2599
+ function parseBooleanish(value) {
2600
+ if (value === "true")
2601
+ return true;
2602
+ if (value === "false")
2603
+ return false;
2604
+ throw new InvalidArgumentError('Expected "true" or "false".');
2605
+ }
2606
+
2607
+ // src/commands/get.ts
2608
+ var getCommand = new Command("get").description("Read data from dblebox").addCommand(new Command("threads").description("List or search your threads").option("--q <query>", "Filter by partial title/body text").option("--json", "Output as JSON").option("--archived", "Include archived threads").option("--snoozed", "Include snoozed threads").action(async (opts) => {
2537
2609
  const api = getApi();
2538
2610
  const { data, error } = await api.api.cli.v1.threads.get({
2539
2611
  query: {
2612
+ q: opts.q,
2540
2613
  archived: opts.archived ? "true" : undefined,
2541
2614
  snoozed: opts.snoozed ? "true" : undefined
2542
2615
  }
@@ -2547,99 +2620,69 @@ var threadsCommand = new Command("threads").description("Manage threads").addCom
2547
2620
  output(data.threads, { json: true });
2548
2621
  return;
2549
2622
  }
2550
- const rows = data.threads.map((t) => ({
2551
- id: t.id.slice(0, 8),
2552
- body: t.body.length > 60 ? t.body.slice(0, 57) + "..." : t.body,
2553
- unread: t.unread ? "*" : "",
2554
- archived: t.archived ? "archived" : "",
2555
- snoozed: t.snoozed ? "snoozed" : ""
2556
- }));
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) => {
2623
+ output(threadRows(data.threads), { json: false });
2624
+ })).addCommand(new Command("today").description("Show threads and note for a date").option("--date <date>", "Date (YYYY-MM-DD)").option("--json", "Output as JSON").action(async (opts) => {
2625
+ const date = localDate(opts.date);
2559
2626
  const api = getApi();
2560
- const { data, error } = await api.api.cli.v1.threads.post({
2561
- body: opts.title,
2562
- comment: opts.comment
2627
+ const { data, error } = await api.api.cli.v1.today.get({
2628
+ query: { date }
2563
2629
  });
2564
2630
  if (error)
2565
2631
  throw error;
2566
2632
  if (opts.json) {
2567
- output(data.thread, { json: true });
2633
+ output(data, { json: true });
2568
2634
  return;
2569
2635
  }
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) => {
2636
+ console.log(`Date: ${data.date}
2637
+ `);
2638
+ if (data.threads.length > 0) {
2639
+ console.log("Threads:");
2640
+ for (const t of data.threads) {
2641
+ console.log(` ${t.id.slice(0, 8)} ${t.body}`);
2642
+ }
2643
+ console.log();
2644
+ } else {
2645
+ console.log(`No threads for this date.
2646
+ `);
2647
+ }
2648
+ if (data.note) {
2649
+ console.log("Note:");
2650
+ console.log(data.note.content || "(empty)");
2651
+ } else {
2652
+ console.log("No daily note.");
2653
+ }
2654
+ })).addCommand(new Command("thread-note").description("Read a thread note").argument("<thread-id>", "Thread ID").option("--json", "Output as JSON").action(async (threadId, opts) => {
2572
2655
  const api = getApi();
2573
- const { data, error } = await api.api.cli.v1.threads({ id }).put({
2574
- body: opts.title
2575
- });
2656
+ const { data, error } = await api.api.cli.v1.threads({ id: threadId }).note.get();
2576
2657
  if (error)
2577
2658
  throw error;
2578
2659
  if (opts.json) {
2579
- output(data.thread, { json: true });
2660
+ output(data, { json: true });
2580
2661
  return;
2581
2662
  }
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) => {
2663
+ if (!data.note) {
2664
+ console.log("No thread note.");
2665
+ return;
2666
+ }
2667
+ console.log(data.note.content || "(empty)");
2668
+ })).addCommand(new Command("today-note").description("Read a daily note").option("--date <date>", "Date (YYYY-MM-DD)").option("--json", "Output as JSON").action(async (opts) => {
2669
+ const date = localDate(opts.date);
2632
2670
  const api = getApi();
2633
- const { error } = await api.api.cli.v1.threads({ id }).today.delete({
2634
- date: opts.date
2671
+ const { data, error } = await api.api.cli.v1.today.note.get({
2672
+ query: { date }
2635
2673
  });
2636
2674
  if (error)
2637
2675
  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) => {
2676
+ if (opts.json) {
2677
+ output(data, { json: true });
2678
+ return;
2679
+ }
2680
+ if (!data.note) {
2681
+ console.log("No daily note.");
2682
+ return;
2683
+ }
2684
+ console.log(data.note.content || "(empty)");
2685
+ })).addCommand(new Command("comments").description("List comments in a thread").requiredOption("--thread <id>", "Thread ID").option("--json", "Output as JSON").action(async (opts) => {
2643
2686
  const api = getApi();
2644
2687
  const { data, error } = await api.api.cli.v1.threads({ id: opts.thread }).comments.get();
2645
2688
  if (error)
@@ -2655,111 +2698,155 @@ var commentsCommand = new Command("comments").description("Manage comments").add
2655
2698
  created_at: c2.created_at
2656
2699
  }));
2657
2700
  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) => {
2701
+ })).addCommand(new Command("members").description("List members of a thread").argument("<thread-id>", "Thread ID").option("--json", "Output as JSON").action(async (threadId, opts) => {
2659
2702
  const api = getApi();
2660
- const { data, error } = await api.api.cli.v1.threads({ id: opts.thread }).comments.post({ body: opts.body });
2703
+ const { data, error } = await api.api.cli.v1.threads({ id: threadId }).members.get();
2661
2704
  if (error)
2662
2705
  throw error;
2663
2706
  if (opts.json) {
2664
- output(data.comment, { json: true });
2707
+ output(data.members, { json: true });
2665
2708
  return;
2666
2709
  }
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) => {
2710
+ const rows = data.members.filter((m) => !m.revoked_at).map((m) => ({
2711
+ username: m.username,
2712
+ email: m.email
2713
+ }));
2714
+ output(rows, { json: false });
2715
+ }));
2716
+
2717
+ // src/commands/create.ts
2718
+ var createCommand2 = new Command("create").description("Create new dblebox objects").addCommand(new Command("thread").description("Create a thread").requiredOption("--title <title>", "Thread title").option("--comment <text>", "Optional first comment").option("--note <content>", "Create and attach a block note with content").option("--json", "Output as JSON").action(async (opts) => {
2669
2719
  const api = getApi();
2670
- const { data, error } = await api.api.cli.v1.comments({ id }).put({ body: opts.body });
2720
+ const noteContent = opts.note !== undefined ? opts.note : undefined;
2721
+ const { data, error } = await api.api.cli.v1.threads.post({
2722
+ body: opts.title,
2723
+ comment: opts.comment,
2724
+ note_content: noteContent
2725
+ });
2726
+ if (error)
2727
+ throw error;
2728
+ if (opts.json) {
2729
+ output(data, { json: true });
2730
+ return;
2731
+ }
2732
+ const noteSuffix = data.note ? ` (note ${data.note.id.slice(0, 8)} attached)` : "";
2733
+ console.log(`Created thread ${data.thread.id.slice(0, 8)}: ${data.thread.body}${noteSuffix}`);
2734
+ })).addCommand(new Command("comment").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) => {
2735
+ const api = getApi();
2736
+ const { data, error } = await api.api.cli.v1.threads({ id: opts.thread }).comments.post({ body: opts.body });
2671
2737
  if (error)
2672
2738
  throw error;
2673
2739
  if (opts.json) {
2674
2740
  output(data.comment, { json: true });
2675
2741
  return;
2676
2742
  }
2677
- console.log(`Comment updated (${data.comment.id.slice(0, 8)}).`);
2743
+ console.log(`Comment added (${data.comment.id.slice(0, 8)}).`);
2678
2744
  }));
2679
2745
 
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) => {
2746
+ // src/commands/set.ts
2747
+ var setCommand = new Command("set").description("Update existing dblebox objects").addCommand(new Command("thread").description("Update thread title, archive state, or snooze state").argument("<thread-id>", "Thread ID").option("--title <title>", "New thread title").option("--archived <true|false>", "Set archived state", parseBooleanish).option("--snoozed-until <datetime-or-none>", 'Set snooze until (ISO datetime), or "none" to clear').option("--json", "Output as JSON").action(async (threadId, opts) => {
2682
2748
  const api = getApi();
2683
- const { data, error } = await api.api.cli.v1.threads({ id: threadId }).members.get();
2684
- if (error)
2685
- throw error;
2749
+ const result = {};
2750
+ const messages = [];
2751
+ if (opts.title !== undefined) {
2752
+ const { data, error } = await api.api.cli.v1.threads({ id: threadId }).put({
2753
+ body: opts.title
2754
+ });
2755
+ if (error)
2756
+ throw error;
2757
+ result.thread = data.thread;
2758
+ messages.push(`Updated thread ${data.thread.id.slice(0, 8)}: ${data.thread.body}`);
2759
+ }
2760
+ if (opts.archived !== undefined) {
2761
+ const { data, error } = await api.api.cli.v1.threads({ id: threadId }).archive.put({
2762
+ archived: opts.archived
2763
+ });
2764
+ if (error)
2765
+ throw error;
2766
+ result.archived = data.archived;
2767
+ messages.push(data.archived ? "Archived." : "Unarchived.");
2768
+ }
2769
+ if (opts.snoozedUntil !== undefined) {
2770
+ const until = opts.snoozedUntil === "none" ? null : opts.snoozedUntil;
2771
+ const { data, error } = await api.api.cli.v1.threads({ id: threadId }).snooze.put({
2772
+ until
2773
+ });
2774
+ if (error)
2775
+ throw error;
2776
+ result.snooze_until = data.snooze_until;
2777
+ messages.push(data.snooze_until ? `Snoozed until ${data.snooze_until}.` : "Unsnoozed.");
2778
+ }
2779
+ if (messages.length === 0) {
2780
+ throw new Error("No updates specified. Provide --title, --archived, or --snoozed-until.");
2781
+ }
2686
2782
  if (opts.json) {
2687
- output(data.members, { json: true });
2783
+ output(result, { json: true });
2688
2784
  return;
2689
2785
  }
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) => {
2786
+ for (const message of messages) {
2787
+ console.log(message);
2788
+ }
2789
+ })).addCommand(new Command("thread-note").description("Create or update a thread note").argument("<thread-id>", "Thread ID").requiredOption("--content <content>", "Note content").option("--json", "Output as JSON").action(async (threadId, opts) => {
2696
2790
  const api = getApi();
2697
- const { data, error } = await api.api.cli.v1.threads({ id: threadId }).members.post({ user: opts.user });
2791
+ const { data, error } = await api.api.cli.v1.threads({ id: threadId }).note.put({ content: opts.content });
2698
2792
  if (error)
2699
2793
  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.");
2794
+ if (opts.json) {
2795
+ output(data, { json: true });
2796
+ return;
2704
2797
  }
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").enablePositionalOptions().passThroughOptions().option("--date <date>", "Date (YYYY-MM-DD)").option("--json", "Output as JSON").action(async (opts) => {
2798
+ console.log("Note updated.");
2799
+ })).addCommand(new Command("today-note").description("Create or update a daily note").requiredOption("--content <content>", "Note content").option("--date <date>", "Date (YYYY-MM-DD)").option("--json", "Output as JSON").action(async (opts) => {
2718
2800
  const date = localDate(opts.date);
2719
2801
  const api = getApi();
2720
- const { data, error } = await api.api.cli.v1.today.get({
2721
- query: { date }
2722
- });
2802
+ const { data, error } = await api.api.cli.v1.today.note.put({ content: opts.content }, { query: { date } });
2723
2803
  if (error)
2724
2804
  throw error;
2725
2805
  if (opts.json) {
2726
2806
  output(data, { json: true });
2727
2807
  return;
2728
2808
  }
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
- `);
2809
+ console.log("Note updated.");
2810
+ })).addCommand(new Command("comment").description("Edit a comment").argument("<comment-id>", "Comment ID").requiredOption("--body <text>", "New comment text").option("--json", "Output as JSON").action(async (commentId, opts) => {
2811
+ const api = getApi();
2812
+ const { data, error } = await api.api.cli.v1.comments({ id: commentId }).put({ body: opts.body });
2813
+ if (error)
2814
+ throw error;
2815
+ if (opts.json) {
2816
+ output(data.comment, { json: true });
2817
+ return;
2740
2818
  }
2741
- if (data.note) {
2742
- console.log("Note:");
2743
- console.log(data.note.content || "(empty)");
2744
- } else {
2745
- console.log("No daily note.");
2819
+ console.log(`Comment updated (${data.comment.id.slice(0, 8)}).`);
2820
+ })).addCommand(new Command("thread-parent").description("Set a thread parent").argument("<thread-id>", "Thread ID").requiredOption("--parent <parent-id>", "Parent thread ID").option("--json", "Output as JSON").action(async (threadId, opts) => {
2821
+ const api = getApi();
2822
+ const { data, error } = await api.api.cli.v1.threads({ id: threadId }).parent.put({
2823
+ parent_id: opts.parent
2824
+ });
2825
+ if (error)
2826
+ throw error;
2827
+ if (opts.json) {
2828
+ output(data.thread, { json: true });
2829
+ return;
2746
2830
  }
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) => {
2831
+ console.log(`Parent set to ${opts.parent.slice(0, 8)}.`);
2832
+ })).addCommand(new Command("thread-today").description("Assign or remove a thread from a date").argument("<thread-id>", "Thread ID").option("--date <date>", "Date (YYYY-MM-DD)").option("--remove", "Remove instead of assign").option("--json", "Output as JSON").action(async (threadId, opts) => {
2748
2833
  const date = localDate(opts.date);
2749
2834
  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 } });
2835
+ if (opts.remove) {
2836
+ const { data: data2, error: error2 } = await api.api.cli.v1.threads({ id: threadId }).today.delete({
2837
+ date
2838
+ });
2752
2839
  if (error2)
2753
2840
  throw error2;
2754
2841
  if (opts.json) {
2755
2842
  output(data2, { json: true });
2756
2843
  return;
2757
2844
  }
2758
- console.log("Note updated.");
2845
+ console.log(`Removed from ${date}.`);
2759
2846
  return;
2760
2847
  }
2761
- const { data, error } = await api.api.cli.v1.today.note.get({
2762
- query: { date }
2848
+ const { data, error } = await api.api.cli.v1.threads({ id: threadId }).today.put({
2849
+ date
2763
2850
  });
2764
2851
  if (error)
2765
2852
  throw error;
@@ -2767,16 +2854,29 @@ var todayCommand = new Command("today").description("Today view — threads and
2767
2854
  output(data, { json: true });
2768
2855
  return;
2769
2856
  }
2770
- if (!data.note) {
2771
- console.log("No daily note.");
2857
+ console.log(`Assigned to ${date}.`);
2858
+ }));
2859
+
2860
+ // src/commands/invite.ts
2861
+ var inviteCommand = new Command("invite").description("Invite collaborators").addCommand(new Command("member").description("Invite a user to a thread").argument("<thread-id>", "Thread ID").requiredOption("--user <email-or-username>", "User email or username").option("--json", "Output as JSON").action(async (threadId, opts) => {
2862
+ const api = getApi();
2863
+ const { data, error } = await api.api.cli.v1.threads({ id: threadId }).members.post({ user: opts.user });
2864
+ if (error)
2865
+ throw error;
2866
+ if (opts.json) {
2867
+ output(data, { json: true });
2772
2868
  return;
2773
2869
  }
2774
- console.log(data.note.content || "(empty)");
2870
+ if (data.invited) {
2871
+ console.log(`Invited ${data.user?.username || opts.user}.`);
2872
+ } else {
2873
+ console.log(data.reason || "Could not invite user.");
2874
+ }
2775
2875
  }));
2776
2876
  // package.json
2777
2877
  var package_default = {
2778
2878
  name: "dblx",
2779
- version: "0.1.49",
2879
+ version: "0.1.63",
2780
2880
  description: "CLI for dblebox — thread-first communication",
2781
2881
  type: "module",
2782
2882
  bin: {
@@ -2803,10 +2903,10 @@ var package_default = {
2803
2903
  // src/index.ts
2804
2904
  var program2 = new Command().name("dblx").description("CLI for dblebox — thread-first communication").version(package_default.version).enablePositionalOptions();
2805
2905
  program2.addCommand(authCommand);
2806
- program2.addCommand(threadsCommand);
2807
- program2.addCommand(commentsCommand);
2808
- program2.addCommand(membersCommand);
2809
- program2.addCommand(todayCommand);
2906
+ program2.addCommand(getCommand);
2907
+ program2.addCommand(createCommand2);
2908
+ program2.addCommand(setCommand);
2909
+ program2.addCommand(inviteCommand);
2810
2910
  program2.parseAsync().catch((err) => {
2811
2911
  console.error(err.message);
2812
2912
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dblx",
3
- "version": "0.1.49",
3
+ "version": "0.1.63",
4
4
  "description": "CLI for dblebox — thread-first communication",
5
5
  "type": "module",
6
6
  "bin": {