@wspc/cli 0.0.13 → 0.0.15
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/dist/cli.js +242 -86
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/spec/openapi.json +812 -207
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command63 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/generated/cli/invite/accept.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -970,6 +970,11 @@ var emailDelete = (options) => (options.client ?? client).post({
|
|
|
970
970
|
...options.headers
|
|
971
971
|
}
|
|
972
972
|
});
|
|
973
|
+
var emailDomainDelete = (options) => (options.client ?? client).delete({
|
|
974
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
975
|
+
url: "/email/domains/{domain}",
|
|
976
|
+
...options
|
|
977
|
+
});
|
|
973
978
|
var emailDomainGet = (options) => (options.client ?? client).get({
|
|
974
979
|
security: [{ scheme: "bearer", type: "http" }],
|
|
975
980
|
url: "/email/domains/{domain}",
|
|
@@ -1175,6 +1180,7 @@ var V1_CRED_KEYS = [
|
|
|
1175
1180
|
function migrateEnv(raw) {
|
|
1176
1181
|
const api_base = typeof raw.api_base === "string" ? raw.api_base : "";
|
|
1177
1182
|
const env = { api_base, accounts: {} };
|
|
1183
|
+
if (typeof raw.consistency_bookmark === "string") env.consistency_bookmark = raw.consistency_bookmark;
|
|
1178
1184
|
if (typeof raw.client_id === "string") env.client_id = raw.client_id;
|
|
1179
1185
|
if (raw.accounts && typeof raw.accounts === "object") {
|
|
1180
1186
|
env.accounts = raw.accounts;
|
|
@@ -1252,10 +1258,79 @@ var ConfigStore = class {
|
|
|
1252
1258
|
}
|
|
1253
1259
|
};
|
|
1254
1260
|
|
|
1261
|
+
// src/handwritten/auth/consistency-fetch.ts
|
|
1262
|
+
var HEADER = "x-consistency-bookmark";
|
|
1263
|
+
var INVALID_BOOKMARK = "INVALID_CONSISTENCY_BOOKMARK";
|
|
1264
|
+
function normalizeBasePath(pathname) {
|
|
1265
|
+
const trimmed = pathname.replace(/\/+$/, "");
|
|
1266
|
+
return trimmed === "" ? "/" : trimmed;
|
|
1267
|
+
}
|
|
1268
|
+
function isUnderApiBase(url, apiBase) {
|
|
1269
|
+
const base = new URL(apiBase);
|
|
1270
|
+
const basePath = normalizeBasePath(base.pathname);
|
|
1271
|
+
return url.origin === base.origin && (basePath === "/" || url.pathname === basePath || url.pathname.startsWith(`${basePath}/`));
|
|
1272
|
+
}
|
|
1273
|
+
function isJsonContentType(contentType) {
|
|
1274
|
+
const mediaType = contentType.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
1275
|
+
return mediaType === "application/json" || mediaType.endsWith("+json");
|
|
1276
|
+
}
|
|
1277
|
+
async function responseHasInvalidBookmark(response) {
|
|
1278
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
1279
|
+
if (!isJsonContentType(contentType)) return false;
|
|
1280
|
+
try {
|
|
1281
|
+
const body = await response.clone().json();
|
|
1282
|
+
return body.error?.code === INVALID_BOOKMARK;
|
|
1283
|
+
} catch {
|
|
1284
|
+
return false;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
function createConsistencyFetch(opts) {
|
|
1288
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
1289
|
+
return async (input, init) => {
|
|
1290
|
+
const request = new Request(input, init);
|
|
1291
|
+
const url = new URL(request.url);
|
|
1292
|
+
const applies = isUnderApiBase(url, opts.apiBase);
|
|
1293
|
+
let outgoing = request;
|
|
1294
|
+
let injectedStoredBookmark = false;
|
|
1295
|
+
if (applies && !outgoing.headers.has(HEADER)) {
|
|
1296
|
+
const config2 = await opts.store.read();
|
|
1297
|
+
const bookmark = config2.envs[opts.envName]?.consistency_bookmark;
|
|
1298
|
+
if (bookmark) {
|
|
1299
|
+
const headers = new Headers(outgoing.headers);
|
|
1300
|
+
headers.set(HEADER, bookmark);
|
|
1301
|
+
outgoing = new Request(outgoing, { headers });
|
|
1302
|
+
injectedStoredBookmark = true;
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
if (!applies && outgoing.headers.has(HEADER)) {
|
|
1306
|
+
const headers = new Headers(outgoing.headers);
|
|
1307
|
+
headers.delete(HEADER);
|
|
1308
|
+
outgoing = new Request(outgoing, { headers });
|
|
1309
|
+
}
|
|
1310
|
+
const response = await fetchImpl(outgoing);
|
|
1311
|
+
if (!applies) return response;
|
|
1312
|
+
const nextBookmark = response.headers.get(HEADER);
|
|
1313
|
+
const shouldCheckInvalidBookmark = injectedStoredBookmark && !nextBookmark;
|
|
1314
|
+
const invalidBookmark = shouldCheckInvalidBookmark ? await responseHasInvalidBookmark(response) : false;
|
|
1315
|
+
const shouldClearBookmark = invalidBookmark;
|
|
1316
|
+
if (!nextBookmark && !shouldClearBookmark) return response;
|
|
1317
|
+
const config = await opts.store.read();
|
|
1318
|
+
const env = config.envs[opts.envName];
|
|
1319
|
+
if (!env) return response;
|
|
1320
|
+
if (nextBookmark) {
|
|
1321
|
+
env.consistency_bookmark = nextBookmark;
|
|
1322
|
+
} else if (shouldClearBookmark) {
|
|
1323
|
+
delete env.consistency_bookmark;
|
|
1324
|
+
}
|
|
1325
|
+
await opts.store.write(config);
|
|
1326
|
+
return response;
|
|
1327
|
+
};
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1255
1330
|
// src/version.ts
|
|
1256
|
-
var VERSION = "0.0.
|
|
1257
|
-
var SPEC_SHA = "
|
|
1258
|
-
var SPEC_FETCHED_AT = "2026-06-
|
|
1331
|
+
var VERSION = "0.0.15";
|
|
1332
|
+
var SPEC_SHA = "dac502bc";
|
|
1333
|
+
var SPEC_FETCHED_AT = "2026-06-15T16:41:41.264Z";
|
|
1259
1334
|
var API_BASE = "https://api.wspc.ai";
|
|
1260
1335
|
|
|
1261
1336
|
// src/index.ts
|
|
@@ -1271,6 +1346,7 @@ var WspcAuthExpiredError = class extends Error {
|
|
|
1271
1346
|
function createAuthInterceptor(mode) {
|
|
1272
1347
|
if ("apiKey" in mode) {
|
|
1273
1348
|
const apiKey = mode.apiKey;
|
|
1349
|
+
const fetchImpl2 = mode.fetchImpl ?? fetch;
|
|
1274
1350
|
return {
|
|
1275
1351
|
async onRequest(req) {
|
|
1276
1352
|
req.headers.set("authorization", `Bearer ${apiKey}`);
|
|
@@ -1278,7 +1354,7 @@ function createAuthInterceptor(mode) {
|
|
|
1278
1354
|
},
|
|
1279
1355
|
async execute(req) {
|
|
1280
1356
|
const out = await this.onRequest(req.clone());
|
|
1281
|
-
return
|
|
1357
|
+
return fetchImpl2(out);
|
|
1282
1358
|
}
|
|
1283
1359
|
};
|
|
1284
1360
|
}
|
|
@@ -1357,10 +1433,10 @@ function resolveAccount(config, opts = {}) {
|
|
|
1357
1433
|
}
|
|
1358
1434
|
|
|
1359
1435
|
// src/handwritten/auth/load-sdk-client.ts
|
|
1360
|
-
function buildInterceptor(store, resolved) {
|
|
1436
|
+
function buildInterceptor(store, resolved, fetchImpl) {
|
|
1361
1437
|
const { envName, apiBase, clientId, email, creds } = resolved;
|
|
1362
1438
|
if (creds.api_key) {
|
|
1363
|
-
return createAuthInterceptor({ apiKey: creds.api_key });
|
|
1439
|
+
return createAuthInterceptor({ apiKey: creds.api_key, fetchImpl });
|
|
1364
1440
|
}
|
|
1365
1441
|
if (!clientId) {
|
|
1366
1442
|
throw new Error(
|
|
@@ -1372,6 +1448,7 @@ function buildInterceptor(store, resolved) {
|
|
|
1372
1448
|
refreshToken: creds.refresh_token,
|
|
1373
1449
|
baseUrl: apiBase,
|
|
1374
1450
|
clientId,
|
|
1451
|
+
fetchImpl,
|
|
1375
1452
|
onTokenRefresh: async ({ accessToken, refreshToken, expiresAt }) => {
|
|
1376
1453
|
const cfg = await store.read();
|
|
1377
1454
|
const a = cfg.envs[envName]?.accounts?.[email];
|
|
@@ -1387,7 +1464,13 @@ async function loadSdkClient(opts = {}) {
|
|
|
1387
1464
|
const store = opts.store ?? new ConfigStore();
|
|
1388
1465
|
const config = await store.read();
|
|
1389
1466
|
const resolved = resolveAccount(config, { accountOverride: process.env.WSPC_ACCOUNT });
|
|
1390
|
-
const
|
|
1467
|
+
const consistencyFetch = createConsistencyFetch({
|
|
1468
|
+
store,
|
|
1469
|
+
envName: resolved.envName,
|
|
1470
|
+
apiBase: resolved.apiBase,
|
|
1471
|
+
fetchImpl: opts.fetchImpl
|
|
1472
|
+
});
|
|
1473
|
+
const interceptor = buildInterceptor(store, resolved, consistencyFetch);
|
|
1391
1474
|
const rawClient = createClient(
|
|
1392
1475
|
createConfig({
|
|
1393
1476
|
baseUrl: resolved.apiBase,
|
|
@@ -1400,7 +1483,13 @@ async function loadAuthedFetch(opts = {}) {
|
|
|
1400
1483
|
const store = opts.store ?? new ConfigStore();
|
|
1401
1484
|
const config = await store.read();
|
|
1402
1485
|
const resolved = resolveAccount(config, { accountOverride: process.env.WSPC_ACCOUNT });
|
|
1403
|
-
const
|
|
1486
|
+
const consistencyFetch = createConsistencyFetch({
|
|
1487
|
+
store,
|
|
1488
|
+
envName: resolved.envName,
|
|
1489
|
+
apiBase: resolved.apiBase,
|
|
1490
|
+
fetchImpl: opts.fetchImpl
|
|
1491
|
+
});
|
|
1492
|
+
const interceptor = buildInterceptor(store, resolved, consistencyFetch);
|
|
1404
1493
|
const authedFetch = (input, init) => interceptor.execute(new Request(input, init));
|
|
1405
1494
|
return { fetch: authedFetch, baseUrl: resolved.apiBase };
|
|
1406
1495
|
}
|
|
@@ -2416,7 +2505,7 @@ var eventGetCommand = new Command19("show").description("Get a calendar event by
|
|
|
2416
2505
|
|
|
2417
2506
|
// src/generated/cli/event/set.ts
|
|
2418
2507
|
import { Command as Command20 } from "commander";
|
|
2419
|
-
var eventUpdateCommand = new Command20("set").description("Update a calendar event").argument("<id>", "id").option("--expected-version <value>", "Optional optimistic lock. Omit to let the server use the current version; pass only to fail the call if someone else has mutated the event since you last read. On mismatch the server returns 409 `VERSION_CONFLICT`
|
|
2508
|
+
var eventUpdateCommand = new Command20("set").description("Update a calendar event").argument("<id>", "id").option("--expected-version <value>", "Optional optimistic lock. Omit to let the server use the current version; pass only to fail the call if someone else has mutated the event since you last read. On mismatch the server returns 409 `VERSION_CONFLICT` and includes the current and sent versions in the message.").option("--title <value>", "New event title. Omit to leave unchanged.").option("--description <value>", "New description. Markdown formatted (CommonMark + GFM tables, strikethrough, task lists). Pass an empty string to clear; omit to leave unchanged.").option("--start <value>", "Accepts ISO 8601 datetime with offset (e.g. `2026-06-01T12:30:00+08:00`) for timed events, or ISO date-only (e.g. `2026-06-01`) for all-day. The `wspc` CLI additionally accepts natural-language phrases (`tomorrow 12:30pm`, `next Monday 9am`) and resolves them to ISO before sending; the server itself only accepts ISO. All-day uses RFC 5545 exclusive end: a one-day event on 6/1 is `start=2026-06-01, end=2026-06-02`; both endpoints must be the same type.").option("--end <value>", "Accepts ISO 8601 datetime with offset (e.g. `2026-06-01T12:30:00+08:00`) for timed events, or ISO date-only (e.g. `2026-06-01`) for all-day. The `wspc` CLI additionally accepts natural-language phrases (`tomorrow 12:30pm`, `next Monday 9am`) and resolves them to ISO before sending; the server itself only accepts ISO. All-day uses RFC 5545 exclusive end: a one-day event on 6/1 is `start=2026-06-01, end=2026-06-02`; both endpoints must be the same type.").option("-l, --location <value>", "New location. Pass an empty string to clear; omit to leave unchanged.").option("-u, --url <value>", "New meeting link. Pass an empty string to clear; omit to leave unchanged.").option("--status <value>", "Lifecycle status. `confirmed`: the event will happen (default). `tentative`: organizer has not finalized; still visible in lists. `cancelled`: the event was called off but the record is kept so attendees can be notified and history audited; distinct from soft-delete (DELETE `/calendar/events/{id}`) which hides the event from default list responses.").option("--attendee <value>", "If provided, REPLACES the attendee list (after case-insensitive email dedupe, up to 50). Added attendees receive a fresh invitation, kept attendees receive an update email, removed attendees receive a cancellation.", (val, memo) => {
|
|
2420
2509
|
memo.push(val);
|
|
2421
2510
|
return memo;
|
|
2422
2511
|
}, []).option("--all-day", "all_day").option("--tz <zone>", "IANA timezone for relative time parsing").action(async (id, opts) => {
|
|
@@ -2614,9 +2703,30 @@ var emailDeleteCommand = new Command27("rm").description("Soft-delete inbound em
|
|
|
2614
2703
|
render({ kind: "email_delete", display: { "shape": "object", "format": {} } }, result.data);
|
|
2615
2704
|
});
|
|
2616
2705
|
|
|
2617
|
-
// src/generated/cli/domain/
|
|
2706
|
+
// src/generated/cli/domain/rm.ts
|
|
2618
2707
|
import { Command as Command28 } from "commander";
|
|
2619
|
-
var
|
|
2708
|
+
var emailDomainDeleteCommand = new Command28("rm").description("Delete a custom email domain").argument("<domain>", "domain").action(async (domain, opts) => {
|
|
2709
|
+
const client2 = await loadSdkClient();
|
|
2710
|
+
const result = await emailDomainDelete({
|
|
2711
|
+
client: client2._rawClient,
|
|
2712
|
+
path: {
|
|
2713
|
+
domain
|
|
2714
|
+
}
|
|
2715
|
+
});
|
|
2716
|
+
if (result.error || !result.response?.ok) {
|
|
2717
|
+
process.stderr.write(
|
|
2718
|
+
`HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
|
|
2719
|
+
`
|
|
2720
|
+
);
|
|
2721
|
+
process.exitCode = 1;
|
|
2722
|
+
return;
|
|
2723
|
+
}
|
|
2724
|
+
render({ kind: "email_domain_delete", display: void 0 }, result.data);
|
|
2725
|
+
});
|
|
2726
|
+
|
|
2727
|
+
// src/generated/cli/domain/show.ts
|
|
2728
|
+
import { Command as Command29 } from "commander";
|
|
2729
|
+
var emailDomainGetCommand = new Command29("show").description("Get one cached custom domain").argument("<domain>", "domain").action(async (domain, opts) => {
|
|
2620
2730
|
const client2 = await loadSdkClient();
|
|
2621
2731
|
const result = await emailDomainGet({
|
|
2622
2732
|
client: client2._rawClient,
|
|
@@ -2636,8 +2746,8 @@ var emailDomainGetCommand = new Command28("show").description("Get one cached cu
|
|
|
2636
2746
|
});
|
|
2637
2747
|
|
|
2638
2748
|
// src/generated/cli/email/show.ts
|
|
2639
|
-
import { Command as
|
|
2640
|
-
var emailGetCommand = new
|
|
2749
|
+
import { Command as Command30 } from "commander";
|
|
2750
|
+
var emailGetCommand = new Command30("show").description("Get an inbound email by id").argument("<id>", "id").option("--include-html <value>", "When `true`, fetch the HTML body from R2 and include it as `html_body` in the response. Costs an extra R2 read; omit if you only need text.").option("--include-deleted <value>", "When `true`, allow fetching a soft-deleted email. Defaults to `false` (returns 404 for soft-deleted rows).").action(async (id, opts) => {
|
|
2641
2751
|
const client2 = await loadSdkClient();
|
|
2642
2752
|
const result = await emailGet({
|
|
2643
2753
|
client: client2._rawClient,
|
|
@@ -2661,8 +2771,8 @@ var emailGetCommand = new Command29("show").description("Get an inbound email by
|
|
|
2661
2771
|
});
|
|
2662
2772
|
|
|
2663
2773
|
// src/generated/cli/email/ls.ts
|
|
2664
|
-
import { Command as
|
|
2665
|
-
var emailListCommand = new
|
|
2774
|
+
import { Command as Command31 } from "commander";
|
|
2775
|
+
var emailListCommand = new Command31("ls").description("List inbound emails").option("--limit <value>", "Max items to return (clamped to 1-100). Defaults to 20 server-side.").option("--alias-email <value>", "If set, only return emails received on this full alias email address.").option("--unread-only <value>", "When `true`, only return emails with `is_read=false`.").option("--since <value>", "Unix epoch milliseconds \u2014 only return emails with `received_at >= since`. Useful for incremental sync.").option("--cursor <value>", "Opaque pagination cursor returned in `next_cursor` of a previous response.").option("--include-deleted <value>", "When `true`, also return soft-deleted emails. Defaults to `false`.").action(async (opts) => {
|
|
2666
2776
|
const client2 = await loadSdkClient();
|
|
2667
2777
|
const result = await emailList({
|
|
2668
2778
|
client: client2._rawClient,
|
|
@@ -2687,8 +2797,8 @@ var emailListCommand = new Command30("ls").description("List inbound emails").op
|
|
|
2687
2797
|
});
|
|
2688
2798
|
|
|
2689
2799
|
// src/generated/cli/email/read.ts
|
|
2690
|
-
import { Command as
|
|
2691
|
-
var emailMarkReadCommand = new
|
|
2800
|
+
import { Command as Command32 } from "commander";
|
|
2801
|
+
var emailMarkReadCommand = new Command32("read").description("Mark inbound emails as read").argument("<id...>", "id").action(async (id, opts) => {
|
|
2692
2802
|
const idRaw = id;
|
|
2693
2803
|
const ids = idRaw.length > 0 ? idRaw : void 0;
|
|
2694
2804
|
const client2 = await loadSdkClient();
|
|
@@ -2710,8 +2820,8 @@ var emailMarkReadCommand = new Command31("read").description("Mark inbound email
|
|
|
2710
2820
|
});
|
|
2711
2821
|
|
|
2712
2822
|
// src/generated/cli/email/unread.ts
|
|
2713
|
-
import { Command as
|
|
2714
|
-
var emailMarkUnreadCommand = new
|
|
2823
|
+
import { Command as Command33 } from "commander";
|
|
2824
|
+
var emailMarkUnreadCommand = new Command33("unread").description("Mark inbound emails as unread").argument("<id...>", "id").action(async (id, opts) => {
|
|
2715
2825
|
const idRaw = id;
|
|
2716
2826
|
const ids = idRaw.length > 0 ? idRaw : void 0;
|
|
2717
2827
|
const client2 = await loadSdkClient();
|
|
@@ -2733,8 +2843,8 @@ var emailMarkUnreadCommand = new Command32("unread").description("Mark inbound e
|
|
|
2733
2843
|
});
|
|
2734
2844
|
|
|
2735
2845
|
// src/generated/cli/domain/verify.ts
|
|
2736
|
-
import { Command as
|
|
2737
|
-
var emailDomainVerifyCommand = new
|
|
2846
|
+
import { Command as Command34 } from "commander";
|
|
2847
|
+
var emailDomainVerifyCommand = new Command34("verify").description("Verify a custom domain with the provider").argument("<domain>", "domain").action(async (domain, opts) => {
|
|
2738
2848
|
const client2 = await loadSdkClient();
|
|
2739
2849
|
const result = await emailDomainVerify({
|
|
2740
2850
|
client: client2._rawClient,
|
|
@@ -2754,8 +2864,8 @@ var emailDomainVerifyCommand = new Command33("verify").description("Verify a cus
|
|
|
2754
2864
|
});
|
|
2755
2865
|
|
|
2756
2866
|
// src/generated/cli/push/config/rm.ts
|
|
2757
|
-
import { Command as
|
|
2758
|
-
var pushConfigDeleteCommand = new
|
|
2867
|
+
import { Command as Command35 } from "commander";
|
|
2868
|
+
var pushConfigDeleteCommand = new Command35("rm").description("Remove a push transport").argument("<transport>", "transport").action(async (transport, opts) => {
|
|
2759
2869
|
const client2 = await loadSdkClient();
|
|
2760
2870
|
const result = await pushConfigDelete({
|
|
2761
2871
|
client: client2._rawClient,
|
|
@@ -2775,8 +2885,8 @@ var pushConfigDeleteCommand = new Command34("rm").description("Remove a push tra
|
|
|
2775
2885
|
});
|
|
2776
2886
|
|
|
2777
2887
|
// src/generated/cli/push/config/set.ts
|
|
2778
|
-
import { Command as
|
|
2779
|
-
var pushConfigSetCommand = new
|
|
2888
|
+
import { Command as Command36 } from "commander";
|
|
2889
|
+
var pushConfigSetCommand = new Command36("set").description("Register or update a push transport").option("--transport <value>", "Transport discriminator. `telegram` is the only supported value today \u2014 push delivers via a Telegram bot DM. Future transports (web push, iOS/Android, generic webhook) will be added as additional discriminator values.").option("--target-bot-username <value>", "Telegram bot username (with leading `@`, 5\u201332 alphanumeric/underscore characters). This is the bot the user has already started a chat with \u2014 wspc DMs notifications to it via the Telegram Bot API.").action(async (opts) => {
|
|
2780
2890
|
const client2 = await loadSdkClient();
|
|
2781
2891
|
const result = await pushConfigSet({
|
|
2782
2892
|
client: client2._rawClient,
|
|
@@ -2799,8 +2909,8 @@ var pushConfigSetCommand = new Command35("set").description("Register or update
|
|
|
2799
2909
|
});
|
|
2800
2910
|
|
|
2801
2911
|
// src/generated/cli/push/config/show.ts
|
|
2802
|
-
import { Command as
|
|
2803
|
-
var pushConfigGetCommand = new
|
|
2912
|
+
import { Command as Command37 } from "commander";
|
|
2913
|
+
var pushConfigGetCommand = new Command37("show").description("List the caller's push transports").action(async (opts) => {
|
|
2804
2914
|
const client2 = await loadSdkClient();
|
|
2805
2915
|
const result = await pushConfigGet({
|
|
2806
2916
|
client: client2._rawClient
|
|
@@ -2817,8 +2927,8 @@ var pushConfigGetCommand = new Command36("show").description("List the caller's
|
|
|
2817
2927
|
});
|
|
2818
2928
|
|
|
2819
2929
|
// src/generated/cli/push/test.ts
|
|
2820
|
-
import { Command as
|
|
2821
|
-
var pushTestCommand = new
|
|
2930
|
+
import { Command as Command38 } from "commander";
|
|
2931
|
+
var pushTestCommand = new Command38("test").description("Send a test push notification").option("--transport <value>", "Which transport to send the test message through. Must match a transport the caller has already registered via `POST /push/config`; today only `telegram` is supported.").action(async (opts) => {
|
|
2822
2932
|
const client2 = await loadSdkClient();
|
|
2823
2933
|
const result = await pushTest({
|
|
2824
2934
|
client: client2._rawClient,
|
|
@@ -2841,8 +2951,8 @@ var pushTestCommand = new Command37("test").description("Send a test push notifi
|
|
|
2841
2951
|
});
|
|
2842
2952
|
|
|
2843
2953
|
// src/generated/cli/todo/comment/add.ts
|
|
2844
|
-
import { Command as
|
|
2845
|
-
var todoCommentCreateCommand = new
|
|
2954
|
+
import { Command as Command39 } from "commander";
|
|
2955
|
+
var todoCommentCreateCommand = new Command39("add").description("Add a comment to a todo").argument("<id>", "id").argument("<content>", "content").action(async (id, content, opts) => {
|
|
2846
2956
|
const client2 = await loadSdkClient();
|
|
2847
2957
|
const result = await todoCommentCreate({
|
|
2848
2958
|
client: client2._rawClient,
|
|
@@ -2865,8 +2975,8 @@ var todoCommentCreateCommand = new Command38("add").description("Add a comment t
|
|
|
2865
2975
|
});
|
|
2866
2976
|
|
|
2867
2977
|
// src/generated/cli/todo/comment/ls.ts
|
|
2868
|
-
import { Command as
|
|
2869
|
-
var todoCommentListCommand = new
|
|
2978
|
+
import { Command as Command40 } from "commander";
|
|
2979
|
+
var todoCommentListCommand = new Command40("ls").description("List comments on a todo").argument("<id>", "id").option("--order <value>", "order").option("--include-deleted <value>", "include_deleted").option("--limit <value>", "Max comments to return. Clamped to [1, 200]. Default 50 server-side.").option("--cursor <value>", "Opaque pagination cursor returned in `next_cursor` of a previous response.").action(async (id, opts) => {
|
|
2870
2980
|
const client2 = await loadSdkClient();
|
|
2871
2981
|
const result = await todoCommentList({
|
|
2872
2982
|
client: client2._rawClient,
|
|
@@ -2892,8 +3002,8 @@ var todoCommentListCommand = new Command39("ls").description("List comments on a
|
|
|
2892
3002
|
});
|
|
2893
3003
|
|
|
2894
3004
|
// src/generated/cli/todo/project/add.ts
|
|
2895
|
-
import { Command as
|
|
2896
|
-
var projectCreateCommand = new
|
|
3005
|
+
import { Command as Command41 } from "commander";
|
|
3006
|
+
var projectCreateCommand = new Command41("add").description("Create a project").argument("<name>", "name").option("--default-todo-type-id <value>", "default_todo_type_id").action(async (name, opts) => {
|
|
2897
3007
|
const client2 = await loadSdkClient();
|
|
2898
3008
|
const result = await projectCreate({
|
|
2899
3009
|
client: client2._rawClient,
|
|
@@ -2914,8 +3024,8 @@ var projectCreateCommand = new Command40("add").description("Create a project").
|
|
|
2914
3024
|
});
|
|
2915
3025
|
|
|
2916
3026
|
// src/generated/cli/todo/project/ls.ts
|
|
2917
|
-
import { Command as
|
|
2918
|
-
var projectListCommand = new
|
|
3027
|
+
import { Command as Command42 } from "commander";
|
|
3028
|
+
var projectListCommand = new Command42("ls").description("List projects").option("--include-deleted <value>", "Set to `true` to include soft-deleted projects in the response.").action(async (opts) => {
|
|
2919
3029
|
const client2 = await loadSdkClient();
|
|
2920
3030
|
const result = await projectList({
|
|
2921
3031
|
client: client2._rawClient,
|
|
@@ -2935,8 +3045,8 @@ var projectListCommand = new Command41("ls").description("List projects").option
|
|
|
2935
3045
|
});
|
|
2936
3046
|
|
|
2937
3047
|
// src/generated/cli/todo/rule/add.ts
|
|
2938
|
-
import { Command as
|
|
2939
|
-
var recurrenceRuleCreateCommand = new
|
|
3048
|
+
import { Command as Command43 } from "commander";
|
|
3049
|
+
var recurrenceRuleCreateCommand = new Command43("add").description("Create a recurring todo rule").argument("<title>", "title").option("--rrule <value>", "rrule").option("--dtstart <value>", "dtstart").option("--description <value>", "description").option("--parent-id <value>", "parent_id").option("-p, --project <value>", "Project for the recurrence rule, its template todo, and all materialized instances. Must be an active project in the caller's organization.").option("-t, --type <value>", "type_id").action(async (title, opts) => {
|
|
2940
3050
|
const client2 = await loadSdkClient();
|
|
2941
3051
|
const result = await recurrenceRuleCreate({
|
|
2942
3052
|
client: client2._rawClient,
|
|
@@ -2962,8 +3072,8 @@ var recurrenceRuleCreateCommand = new Command42("add").description("Create a rec
|
|
|
2962
3072
|
});
|
|
2963
3073
|
|
|
2964
3074
|
// src/generated/cli/todo/rule/ls.ts
|
|
2965
|
-
import { Command as
|
|
2966
|
-
var recurrenceRuleListCommand = new
|
|
3075
|
+
import { Command as Command44 } from "commander";
|
|
3076
|
+
var recurrenceRuleListCommand = new Command44("ls").description("List recurring todo rules").option("--project-id <value>", "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.").option("--user-id <value>", "user_id").action(async (opts) => {
|
|
2967
3077
|
const client2 = await loadSdkClient();
|
|
2968
3078
|
const result = await recurrenceRuleList({
|
|
2969
3079
|
client: client2._rawClient,
|
|
@@ -2984,7 +3094,7 @@ var recurrenceRuleListCommand = new Command43("ls").description("List recurring
|
|
|
2984
3094
|
});
|
|
2985
3095
|
|
|
2986
3096
|
// src/generated/cli/todo/add.ts
|
|
2987
|
-
import { Command as
|
|
3097
|
+
import { Command as Command45 } from "commander";
|
|
2988
3098
|
|
|
2989
3099
|
// src/handwritten/utils/parse-json-field.ts
|
|
2990
3100
|
function parseJsonField(raw, flag) {
|
|
@@ -2999,7 +3109,7 @@ function parseJsonField(raw, flag) {
|
|
|
2999
3109
|
}
|
|
3000
3110
|
|
|
3001
3111
|
// src/generated/cli/todo/add.ts
|
|
3002
|
-
var todoCreateCommand = new
|
|
3112
|
+
var todoCreateCommand = new Command45("add").description("Create a todo").argument("<title>", "title").option("-p, --project <value>", "Project id to assign this todo to. It must be an active project in the caller's organization.").option("--description <value>", "Free-form details about the todo. Fully supports GFM Markdown (tables, strikethrough, task lists). Stored verbatim; client applications are responsible for rendering. Optional. Passing `null` is strictly rejected.").option("--parent-id <value>", "Parent todo ID (`tod_<ULID>`) to attach this todo as a child under another todo. Omit or pass `null` to create a root-level todo. Nesting is limited to one level; attempting to set a child todo as a parent will trigger `PARENT_IS_CHILD`. To make a subtask appear on every occurrence of a recurring rule, set this to that rule's template todo id (the template id returned when the rule is created); the server re-materializes future occurrences so each carries the subtask.").option("--status <value>", "Initial status of the todo. Omit to default to `open`. Allowed values: `open`, `in_progress`, `done`, `cancelled`.").option("--due-at <value>", 'Optional calendar due date in ISO date-only format (`YYYY-MM-DD`). Stored without timezone offsets to represent the same local calendar day globally. Pass `""` or omit the field to skip setting a due date. Passing `null` is strictly rejected.').option("--type-id <value>", "Type id this todo belongs to. Omit to use the project's default type. When project_id is also supplied, the type must belong to the same project. New server-generated type ids use typ_<ULID>; legacy ids remain accepted.").option("--custom-fields <value>", "Custom field values keyed by the field's immutable `key` (not the human `label`). Each value must match the declared field type: string fields require string values, and string_array fields require string arrays. Providing a key that is not declared on the resolved todo type is strictly rejected with `UNDECLARED_FIELD`. Missing required fields that lack a default value are rejected with `FIELD_REQUIRED`. Defaults declared on the type are auto-applied at create time.").action(async (title, opts) => {
|
|
3003
3113
|
const client2 = await loadSdkClient();
|
|
3004
3114
|
const result = await todoCreate({
|
|
3005
3115
|
client: client2._rawClient,
|
|
@@ -3026,8 +3136,8 @@ var todoCreateCommand = new Command44("add").description("Create a todo").argume
|
|
|
3026
3136
|
});
|
|
3027
3137
|
|
|
3028
3138
|
// src/generated/cli/todo/ls.ts
|
|
3029
|
-
import { Command as
|
|
3030
|
-
var todoListCommand = new
|
|
3139
|
+
import { Command as Command46 } from "commander";
|
|
3140
|
+
var todoListCommand = new Command46("ls").description("List todos with filters").option("-p, --project <value>", "Filter by project. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.").option("--user-id <value>", "user_id").option("--parent-id <value>", "parent_id").option("-s, --status <value>", "status").option("--include-deleted <value>", "include_deleted").option("--include-templates <value>", "include_templates").option("--due-after <value>", "due_after").option("--due-before <value>", "due_before").option("--type-id <value>", "type_id").option("--sort-by <value>", "sort_by").option("--order <value>", "order").option("--include-orphan-fields <value>", "include_orphan_fields").option("--limit <value>", "Max todos to return. Clamped to [1, 200]. Default 50 server-side.").option("--cursor <value>", "Opaque pagination cursor returned in `next_cursor` of a previous response.").action(async (opts) => {
|
|
3031
3141
|
const client2 = await loadSdkClient();
|
|
3032
3142
|
const result = await todoList({
|
|
3033
3143
|
client: client2._rawClient,
|
|
@@ -3060,8 +3170,8 @@ var todoListCommand = new Command45("ls").description("List todos with filters")
|
|
|
3060
3170
|
});
|
|
3061
3171
|
|
|
3062
3172
|
// src/generated/cli/todo/type/ls.ts
|
|
3063
|
-
import { Command as
|
|
3064
|
-
var todoTypeListCommand = new
|
|
3173
|
+
import { Command as Command47 } from "commander";
|
|
3174
|
+
var todoTypeListCommand = new Command47("ls").description("List todo types").option("--project-id <value>", "Project id filter. Required. Unknown, cross-organization, or soft-deleted project ids return NOT_FOUND.").option("--user-id <value>", "user_id").option("--include-deleted <value>", "include_deleted").action(async (opts) => {
|
|
3065
3175
|
const client2 = await loadSdkClient();
|
|
3066
3176
|
const result = await todoTypeList({
|
|
3067
3177
|
client: client2._rawClient,
|
|
@@ -3083,8 +3193,8 @@ var todoTypeListCommand = new Command46("ls").description("List todo types").opt
|
|
|
3083
3193
|
});
|
|
3084
3194
|
|
|
3085
3195
|
// src/generated/cli/todo/comment/rm.ts
|
|
3086
|
-
import { Command as
|
|
3087
|
-
var todoCommentDeleteCommand = new
|
|
3196
|
+
import { Command as Command48 } from "commander";
|
|
3197
|
+
var todoCommentDeleteCommand = new Command48("rm").description("Soft-delete a comment").argument("<id>", "id").action(async (id, opts) => {
|
|
3088
3198
|
const client2 = await loadSdkClient();
|
|
3089
3199
|
const result = await todoCommentDelete({
|
|
3090
3200
|
client: client2._rawClient,
|
|
@@ -3104,8 +3214,8 @@ var todoCommentDeleteCommand = new Command47("rm").description("Soft-delete a co
|
|
|
3104
3214
|
});
|
|
3105
3215
|
|
|
3106
3216
|
// src/generated/cli/todo/comment/edit.ts
|
|
3107
|
-
import { Command as
|
|
3108
|
-
var todoCommentUpdateCommand = new
|
|
3217
|
+
import { Command as Command49 } from "commander";
|
|
3218
|
+
var todoCommentUpdateCommand = new Command49("edit").description("Edit a comment").argument("<id>", "id").argument("<content>", "content").action(async (id, content, opts) => {
|
|
3109
3219
|
const client2 = await loadSdkClient();
|
|
3110
3220
|
const result = await todoCommentUpdate({
|
|
3111
3221
|
client: client2._rawClient,
|
|
@@ -3128,8 +3238,8 @@ var todoCommentUpdateCommand = new Command48("edit").description("Edit a comment
|
|
|
3128
3238
|
});
|
|
3129
3239
|
|
|
3130
3240
|
// src/generated/cli/todo/rule/rm.ts
|
|
3131
|
-
import { Command as
|
|
3132
|
-
var recurrenceRuleDeleteCommand = new
|
|
3241
|
+
import { Command as Command50 } from "commander";
|
|
3242
|
+
var recurrenceRuleDeleteCommand = new Command50("rm").description("Delete a recurring todo rule").argument("<id>", "id").option("--expected-version <value>", "expected_version").action(async (id, opts) => {
|
|
3133
3243
|
const client2 = await loadSdkClient();
|
|
3134
3244
|
const result = await recurrenceRuleDelete({
|
|
3135
3245
|
client: client2._rawClient,
|
|
@@ -3152,8 +3262,8 @@ var recurrenceRuleDeleteCommand = new Command49("rm").description("Delete a recu
|
|
|
3152
3262
|
});
|
|
3153
3263
|
|
|
3154
3264
|
// src/generated/cli/todo/rule/show.ts
|
|
3155
|
-
import { Command as
|
|
3156
|
-
var recurrenceRuleGetCommand = new
|
|
3265
|
+
import { Command as Command51 } from "commander";
|
|
3266
|
+
var recurrenceRuleGetCommand = new Command51("show").description("Get a recurring todo rule").argument("<id>", "id").action(async (id, opts) => {
|
|
3157
3267
|
const client2 = await loadSdkClient();
|
|
3158
3268
|
const result = await recurrenceRuleGet({
|
|
3159
3269
|
client: client2._rawClient,
|
|
@@ -3173,8 +3283,8 @@ var recurrenceRuleGetCommand = new Command50("show").description("Get a recurrin
|
|
|
3173
3283
|
});
|
|
3174
3284
|
|
|
3175
3285
|
// src/generated/cli/todo/rm.ts
|
|
3176
|
-
import { Command as
|
|
3177
|
-
var todoDeleteCommand = new
|
|
3286
|
+
import { Command as Command52 } from "commander";
|
|
3287
|
+
var todoDeleteCommand = new Command52("rm").description("Soft-delete a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--cascade <value>", "cascade").action(async (id, opts) => {
|
|
3178
3288
|
const client2 = await loadSdkClient();
|
|
3179
3289
|
const result = await todoDelete({
|
|
3180
3290
|
client: client2._rawClient,
|
|
@@ -3198,8 +3308,8 @@ var todoDeleteCommand = new Command51("rm").description("Soft-delete a todo").ar
|
|
|
3198
3308
|
});
|
|
3199
3309
|
|
|
3200
3310
|
// src/generated/cli/todo/show.ts
|
|
3201
|
-
import { Command as
|
|
3202
|
-
var todoGetCommand = new
|
|
3311
|
+
import { Command as Command53 } from "commander";
|
|
3312
|
+
var todoGetCommand = new Command53("show").description("Get a todo by id").argument("<id>", "id").option("--include-deleted <value>", "include_deleted").option("--include-orphan-fields <value>", "include_orphan_fields").action(async (id, opts) => {
|
|
3203
3313
|
const client2 = await loadSdkClient();
|
|
3204
3314
|
const result = await todoGet({
|
|
3205
3315
|
client: client2._rawClient,
|
|
@@ -3224,8 +3334,8 @@ var todoGetCommand = new Command52("show").description("Get a todo by id").argum
|
|
|
3224
3334
|
});
|
|
3225
3335
|
|
|
3226
3336
|
// src/generated/cli/todo/update.ts
|
|
3227
|
-
import { Command as
|
|
3228
|
-
var todoUpdateCommand = new
|
|
3337
|
+
import { Command as Command54 } from "commander";
|
|
3338
|
+
var todoUpdateCommand = new Command54("update").description("Update a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--title <value>", "New title. Omit to leave the existing title unchanged. Must be non-empty when supplied.").option("--description <value>", 'New description. Markdown formatted (CommonMark + GFM tables, strikethrough, task lists). Pass empty string `""` explicitly to clear an existing description, or omit to leave unchanged. Passing `null` is strictly rejected.').option("--parent-id <value>", "Re-parent the todo. Pass a valid parent ID to attach under another todo, pass `null` to move it back to the root level, or omit to leave unchanged. Nesting is limited to one level; attempting to set a child todo as a parent will trigger `PARENT_IS_CHILD`.").option("--status <value>", "New status of the todo. Allowed transitions: `open` \u2794 `in_progress` \u2794 `done`. `cancelled` represents a terminal state. Transitioning to `done` automatically emits a `captureTodoCompleted` analytics event. Omit to leave the existing status unchanged.").option("--due-at <value>", 'Update calendar due date in ISO date-only format (`YYYY-MM-DD`). Pass `""` explicitly to clear an existing due date, or omit to leave it unchanged. Passing `null` is strictly rejected.').option("--type-id <value>", "Re-assign this todo to a different active type. The new type must belong to the todo's same project; otherwise the request fails with TYPE_PROJECT_MISMATCH. New server-generated type ids use typ_<ULID>; legacy ids remain accepted.").option("--custom-fields <value>", "PATCH semantics: only the keys present in this map change. Pass `null` for a key (e.g. `custom_fields: { priority: null }`) to explicitly delete that custom field value. Array values are replaced wholesale with no element-level diff. Providing a key that is not declared on the effective todo type is rejected with `UNDECLARED_FIELD`.").option("--user-id <value>", "Reassign the owner (assignee) user ID of this todo. Target user must belong to the same organization.").action(async (id, opts) => {
|
|
3229
3339
|
const client2 = await loadSdkClient();
|
|
3230
3340
|
const result = await todoUpdate({
|
|
3231
3341
|
client: client2._rawClient,
|
|
@@ -3291,6 +3401,7 @@ function registerGeneratedCommands(root) {
|
|
|
3291
3401
|
const root_domain = root.command("domain").description("domain commands");
|
|
3292
3402
|
root_domain.addCommand(emailDomainCreateCommand);
|
|
3293
3403
|
root_domain.addCommand(emailDomainListCommand);
|
|
3404
|
+
root_domain.addCommand(emailDomainDeleteCommand);
|
|
3294
3405
|
root_domain.addCommand(emailDomainGetCommand);
|
|
3295
3406
|
root_domain.addCommand(emailDomainVerifyCommand);
|
|
3296
3407
|
const root_email = root.command("email").description("email commands");
|
|
@@ -3329,12 +3440,17 @@ function registerGeneratedCommands(root) {
|
|
|
3329
3440
|
}
|
|
3330
3441
|
|
|
3331
3442
|
// src/handwritten/commands/login.ts
|
|
3332
|
-
import { Command as
|
|
3443
|
+
import { Command as Command55 } from "commander";
|
|
3333
3444
|
|
|
3334
3445
|
// src/handwritten/auth/device-flow.ts
|
|
3335
3446
|
var DEFAULT_SLEEP = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
3336
3447
|
async function runDeviceFlow(opts) {
|
|
3337
|
-
const fetchImpl = opts.
|
|
3448
|
+
const fetchImpl = opts.store && opts.envName ? createConsistencyFetch({
|
|
3449
|
+
store: opts.store,
|
|
3450
|
+
envName: opts.envName,
|
|
3451
|
+
apiBase: opts.baseUrl,
|
|
3452
|
+
fetchImpl: opts.fetchImpl
|
|
3453
|
+
}) : opts.fetchImpl ?? fetch;
|
|
3338
3454
|
const sleep = opts.sleepMs ?? DEFAULT_SLEEP;
|
|
3339
3455
|
const codeRes = await fetchImpl(`${opts.baseUrl}/auth/oauth/device`, {
|
|
3340
3456
|
method: "POST",
|
|
@@ -3390,10 +3506,19 @@ async function runDeviceFlow(opts) {
|
|
|
3390
3506
|
var DEFAULT_CLIENT_NAME = "wspc CLI";
|
|
3391
3507
|
var DEFAULT_REDIRECT_URI = "http://localhost";
|
|
3392
3508
|
async function ensureClientId(opts) {
|
|
3393
|
-
const fetchImpl =
|
|
3509
|
+
const fetchImpl = createConsistencyFetch({
|
|
3510
|
+
store: opts.store,
|
|
3511
|
+
envName: opts.envName,
|
|
3512
|
+
apiBase: opts.baseUrl,
|
|
3513
|
+
fetchImpl: opts.fetchImpl
|
|
3514
|
+
});
|
|
3394
3515
|
const c = await opts.store.read();
|
|
3395
3516
|
const existing = c.envs[opts.envName]?.client_id;
|
|
3396
3517
|
if (existing) return existing;
|
|
3518
|
+
const targetEnv = c.envs[opts.envName] ??= { api_base: opts.baseUrl, accounts: {} };
|
|
3519
|
+
targetEnv.api_base = opts.baseUrl;
|
|
3520
|
+
targetEnv.accounts ??= {};
|
|
3521
|
+
await opts.store.write(c);
|
|
3397
3522
|
const res = await fetchImpl(`${opts.baseUrl}/auth/oauth/register`, {
|
|
3398
3523
|
method: "POST",
|
|
3399
3524
|
headers: { "content-type": "application/json" },
|
|
@@ -3419,7 +3544,12 @@ async function ensureClientId(opts) {
|
|
|
3419
3544
|
|
|
3420
3545
|
// src/handwritten/auth/fetch-me.ts
|
|
3421
3546
|
async function fetchMe(opts) {
|
|
3422
|
-
const f = opts.
|
|
3547
|
+
const f = opts.store && opts.envName ? createConsistencyFetch({
|
|
3548
|
+
store: opts.store,
|
|
3549
|
+
envName: opts.envName,
|
|
3550
|
+
apiBase: opts.baseUrl,
|
|
3551
|
+
fetchImpl: opts.fetchImpl
|
|
3552
|
+
}) : opts.fetchImpl ?? fetch;
|
|
3423
3553
|
const res = await f(`${opts.baseUrl}/auth/me`, {
|
|
3424
3554
|
headers: { authorization: `Bearer ${opts.token}` }
|
|
3425
3555
|
});
|
|
@@ -3448,7 +3578,16 @@ async function runLogin(opts) {
|
|
|
3448
3578
|
const now = opts.now ?? Date.now;
|
|
3449
3579
|
const me = opts.fetchMe ?? ((o) => fetchMe(o));
|
|
3450
3580
|
if (opts.apiKey) {
|
|
3451
|
-
const
|
|
3581
|
+
const initial = await opts.store.read();
|
|
3582
|
+
getOrCreateEnv(initial, envName, opts.baseUrl);
|
|
3583
|
+
initial.current_env = envName;
|
|
3584
|
+
await opts.store.write(initial);
|
|
3585
|
+
const who2 = await me({
|
|
3586
|
+
baseUrl: opts.baseUrl,
|
|
3587
|
+
token: opts.apiKey,
|
|
3588
|
+
store: opts.store,
|
|
3589
|
+
envName
|
|
3590
|
+
});
|
|
3452
3591
|
const c2 = await opts.store.read();
|
|
3453
3592
|
const env2 = getOrCreateEnv(c2, envName, opts.baseUrl);
|
|
3454
3593
|
const prev2 = env2.accounts[who2.email] ?? { email: who2.email };
|
|
@@ -3474,6 +3613,8 @@ async function runLogin(opts) {
|
|
|
3474
3613
|
const result = await flow({
|
|
3475
3614
|
baseUrl: opts.baseUrl,
|
|
3476
3615
|
clientId,
|
|
3616
|
+
store: opts.store,
|
|
3617
|
+
envName,
|
|
3477
3618
|
onPrompt: (p) => {
|
|
3478
3619
|
const prompt = p;
|
|
3479
3620
|
opts.output.writeJson({ event: "device_code_issued", ...prompt });
|
|
@@ -3486,7 +3627,12 @@ async function runLogin(opts) {
|
|
|
3486
3627
|
`);
|
|
3487
3628
|
}
|
|
3488
3629
|
});
|
|
3489
|
-
const who = await me({
|
|
3630
|
+
const who = await me({
|
|
3631
|
+
baseUrl: opts.baseUrl,
|
|
3632
|
+
token: result.access_token,
|
|
3633
|
+
store: opts.store,
|
|
3634
|
+
envName
|
|
3635
|
+
});
|
|
3490
3636
|
const c = await opts.store.read();
|
|
3491
3637
|
const env = getOrCreateEnv(c, envName, opts.baseUrl);
|
|
3492
3638
|
const prev = env.accounts[who.email] ?? { email: who.email };
|
|
@@ -3508,9 +3654,18 @@ async function runLogin(opts) {
|
|
|
3508
3654
|
}
|
|
3509
3655
|
|
|
3510
3656
|
// src/handwritten/commands/login.ts
|
|
3511
|
-
|
|
3657
|
+
function resolveLoginTarget(opts, env) {
|
|
3658
|
+
const baseUrl = opts.apiBase ?? env.WSPC_API_BASE ?? API_BASE;
|
|
3659
|
+
const envName = opts.env ?? (baseUrl === API_BASE ? "prod" : "local");
|
|
3660
|
+
return { baseUrl, envName };
|
|
3661
|
+
}
|
|
3662
|
+
function wantsJson(opts, env) {
|
|
3663
|
+
return opts.json === true || env.WSPC_OUTPUT === "json";
|
|
3664
|
+
}
|
|
3665
|
+
var loginCommand = new Command55("login").description("Log in via OAuth device flow (default) or API key").option("--api-key <key>", "Log in with a wspc API key (escape hatch)").option("--api-base <url>", "Target API base URL (default: production)").option("--env <name>", "Config env name to store credentials under").option("--json", "Emit machine-readable events to stdout").action(async (opts) => {
|
|
3512
3666
|
const store = new ConfigStore();
|
|
3513
|
-
const
|
|
3667
|
+
const { baseUrl, envName } = resolveLoginTarget(opts, process.env);
|
|
3668
|
+
const output = wantsJson(opts, process.env) ? { write: () => {
|
|
3514
3669
|
}, writeJson: (e) => process.stdout.write(JSON.stringify(e) + "\n") } : {
|
|
3515
3670
|
write: (s) => process.stdout.write(s + "\n"),
|
|
3516
3671
|
writeJson: () => {
|
|
@@ -3518,14 +3673,15 @@ var loginCommand = new Command54("login").description("Log in via OAuth device f
|
|
|
3518
3673
|
};
|
|
3519
3674
|
await runLogin({
|
|
3520
3675
|
store,
|
|
3521
|
-
baseUrl
|
|
3676
|
+
baseUrl,
|
|
3677
|
+
envName,
|
|
3522
3678
|
apiKey: opts.apiKey,
|
|
3523
3679
|
output
|
|
3524
3680
|
});
|
|
3525
3681
|
});
|
|
3526
3682
|
|
|
3527
3683
|
// src/handwritten/commands/logout.ts
|
|
3528
|
-
import { Command as
|
|
3684
|
+
import { Command as Command56 } from "commander";
|
|
3529
3685
|
|
|
3530
3686
|
// src/handwritten/auth/logout.ts
|
|
3531
3687
|
async function runLogout(opts) {
|
|
@@ -3553,7 +3709,7 @@ async function runLogout(opts) {
|
|
|
3553
3709
|
}
|
|
3554
3710
|
|
|
3555
3711
|
// src/handwritten/commands/logout.ts
|
|
3556
|
-
var logoutCommand = new
|
|
3712
|
+
var logoutCommand = new Command56("logout").description("Log out an account (default: the active account in the current env)").argument("[email]", "Email of the account to log out").option("--all", "Log out every account in the current env").action(async (email, opts) => {
|
|
3557
3713
|
const res = await runLogout({ store: new ConfigStore(), email, all: opts.all });
|
|
3558
3714
|
if (res.removed.length === 0) {
|
|
3559
3715
|
process.stdout.write("nothing to log out\n");
|
|
@@ -3566,7 +3722,7 @@ var logoutCommand = new Command55("logout").description("Log out an account (def
|
|
|
3566
3722
|
});
|
|
3567
3723
|
|
|
3568
3724
|
// src/handwritten/commands/whoami.ts
|
|
3569
|
-
import { Command as
|
|
3725
|
+
import { Command as Command57 } from "commander";
|
|
3570
3726
|
var ENV_DISPLAY = {
|
|
3571
3727
|
shape: "object",
|
|
3572
3728
|
fields: ["name", "api_base", "account", "actor", "agent_label"]
|
|
@@ -3598,7 +3754,7 @@ async function backfillActiveEmail(store, envName, email, userId) {
|
|
|
3598
3754
|
await store.write(cfg);
|
|
3599
3755
|
}
|
|
3600
3756
|
}
|
|
3601
|
-
var whoamiCommand = new
|
|
3757
|
+
var whoamiCommand = new Command57("whoami").description("Show the active env, signed-in account, and organization").action(async () => {
|
|
3602
3758
|
const store = new ConfigStore();
|
|
3603
3759
|
const config = await store.read();
|
|
3604
3760
|
let resolved;
|
|
@@ -3651,8 +3807,8 @@ function printLoggedOut() {
|
|
|
3651
3807
|
}
|
|
3652
3808
|
|
|
3653
3809
|
// src/handwritten/commands/config.ts
|
|
3654
|
-
import { Command as
|
|
3655
|
-
var configCommand = new
|
|
3810
|
+
import { Command as Command58 } from "commander";
|
|
3811
|
+
var configCommand = new Command58("config").description("Manage wspc local config");
|
|
3656
3812
|
registerRenderer("config_show", (data) => {
|
|
3657
3813
|
const d = data;
|
|
3658
3814
|
if (d.envs.length === 0) {
|
|
@@ -3723,7 +3879,7 @@ configCommand.command("use <env>").description("Switch current_env").action(asyn
|
|
|
3723
3879
|
});
|
|
3724
3880
|
|
|
3725
3881
|
// src/handwritten/commands/account.ts
|
|
3726
|
-
import { Command as
|
|
3882
|
+
import { Command as Command59 } from "commander";
|
|
3727
3883
|
async function listAccounts(store) {
|
|
3728
3884
|
const c = await store.read();
|
|
3729
3885
|
const envName = c.current_env;
|
|
@@ -3764,7 +3920,7 @@ registerRenderer("account_ls", (data) => {
|
|
|
3764
3920
|
]);
|
|
3765
3921
|
process.stdout.write(table(headers, body));
|
|
3766
3922
|
});
|
|
3767
|
-
var accountCommand = new
|
|
3923
|
+
var accountCommand = new Command59("account").description("Manage logged-in accounts");
|
|
3768
3924
|
accountCommand.command("ls").description("List accounts in the current env (active marked with \u2713)").action(async () => {
|
|
3769
3925
|
const accounts = await listAccounts(new ConfigStore());
|
|
3770
3926
|
render({ kind: "account_ls" }, { accounts });
|
|
@@ -3776,7 +3932,7 @@ accountCommand.command("switch <email>").description("Set the active account for
|
|
|
3776
3932
|
});
|
|
3777
3933
|
|
|
3778
3934
|
// src/handwritten/commands/todo-done.ts
|
|
3779
|
-
import { Command as
|
|
3935
|
+
import { Command as Command60 } from "commander";
|
|
3780
3936
|
var TODO_UPDATE_DISPLAY = {
|
|
3781
3937
|
shape: "object",
|
|
3782
3938
|
format: {
|
|
@@ -3794,7 +3950,7 @@ var TODO_UPDATE_DISPLAY = {
|
|
|
3794
3950
|
deleted_at: "relative-time"
|
|
3795
3951
|
}
|
|
3796
3952
|
};
|
|
3797
|
-
var todoDoneCommand = new
|
|
3953
|
+
var todoDoneCommand = new Command60("done").description("Mark a todo done (sugar for `update <id> --status done`)").argument("<id>", "Todo id").action(async (id) => {
|
|
3798
3954
|
const client2 = await loadSdkClient();
|
|
3799
3955
|
const result = await todoUpdate({
|
|
3800
3956
|
client: client2._rawClient,
|
|
@@ -3813,7 +3969,7 @@ var todoDoneCommand = new Command59("done").description("Mark a todo done (sugar
|
|
|
3813
3969
|
});
|
|
3814
3970
|
|
|
3815
3971
|
// src/handwritten/commands/email/send.ts
|
|
3816
|
-
import { Command as
|
|
3972
|
+
import { Command as Command61 } from "commander";
|
|
3817
3973
|
import { readFile, stat } from "fs/promises";
|
|
3818
3974
|
import { basename } from "path";
|
|
3819
3975
|
|
|
@@ -3871,7 +4027,7 @@ async function resolveAttachment(input) {
|
|
|
3871
4027
|
`--attach ${input}: neither a readable file nor a valid <prefix>_<ulid>:<idx> reference.`
|
|
3872
4028
|
);
|
|
3873
4029
|
}
|
|
3874
|
-
var sendCommand = new
|
|
4030
|
+
var sendCommand = new Command61("send").description("Send an outbound email").requiredOption("--from <alias-email>", "alias email to send from").option("--to <addr...>", "recipient address (repeatable)", []).option("--subject <text>", "subject").option("--text <body>", "plain-text body").option("--text-file <path>", "read text body from file").option("--reply <id>", "inbound email id to reply to").option("--attach <path-or-ref...>", "attachment (file path or eml_xxx:idx)", []).requiredOption("--idempotency-key <key>", "idempotency key").action(async (opts) => {
|
|
3875
4031
|
const isReply = Boolean(opts.reply);
|
|
3876
4032
|
const to = opts.to;
|
|
3877
4033
|
const attachInputs = opts.attach;
|
|
@@ -3958,7 +4114,7 @@ var sendCommand = new Command60("send").description("Send an outbound email").re
|
|
|
3958
4114
|
});
|
|
3959
4115
|
|
|
3960
4116
|
// src/handwritten/commands/email/attachment.ts
|
|
3961
|
-
import { Command as
|
|
4117
|
+
import { Command as Command62 } from "commander";
|
|
3962
4118
|
import { createWriteStream } from "fs";
|
|
3963
4119
|
import { Readable } from "stream";
|
|
3964
4120
|
import { pipeline } from "stream/promises";
|
|
@@ -3975,7 +4131,7 @@ function parseContentDispositionFilename(header) {
|
|
|
3975
4131
|
}
|
|
3976
4132
|
|
|
3977
4133
|
// src/handwritten/commands/email/attachment.ts
|
|
3978
|
-
var attachmentCommand = new
|
|
4134
|
+
var attachmentCommand = new Command62("attachment").description("Download an inbound email attachment by index").argument("<email-id>").argument("<idx>").option("--output <path>", "output file path").option("--include-deleted", "allow downloads from soft-deleted parent emails").action(async (emailId, idxArg, opts) => {
|
|
3979
4135
|
const idx = Number(idxArg);
|
|
3980
4136
|
if (!Number.isInteger(idx) || idx < 0) {
|
|
3981
4137
|
process.stderr.write(`<idx> must be a non-negative integer (got "${idxArg}")
|
|
@@ -4008,7 +4164,7 @@ var attachmentCommand = new Command61("attachment").description("Download an inb
|
|
|
4008
4164
|
|
|
4009
4165
|
// src/cli.ts
|
|
4010
4166
|
function buildProgram() {
|
|
4011
|
-
const program = new
|
|
4167
|
+
const program = new Command63().name("wspc").description("Official CLI for wspc.ai").version(`wspc ${VERSION} (spec ${SPEC_SHA}, fetched ${SPEC_FETCHED_AT})`).option("--json", "Output raw JSON (machine-readable)").option("--account <email>", "Run as a specific account (overrides the active account)").hook("preAction", (_thisCommand, actionCommand) => {
|
|
4012
4168
|
const globals = actionCommand.optsWithGlobals();
|
|
4013
4169
|
if (globals.json) process.env.WSPC_OUTPUT = "json";
|
|
4014
4170
|
if (globals.account) process.env.WSPC_ACCOUNT = String(globals.account);
|