@antasphere/slideless 0.2.1 → 0.2.4
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/bin.js +371 -47
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -3042,7 +3042,7 @@ var {
|
|
|
3042
3042
|
Help
|
|
3043
3043
|
} = import_index.default;
|
|
3044
3044
|
|
|
3045
|
-
// ../../node_modules/.pnpm/@antasphere+cli-core@0.
|
|
3045
|
+
// ../../node_modules/.pnpm/@antasphere+cli-core@0.4.0/node_modules/@antasphere/cli-core/dist/config.js
|
|
3046
3046
|
import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3047
3047
|
import { dirname, join } from "node:path";
|
|
3048
3048
|
var HUB_TOOL = "hub";
|
|
@@ -3109,16 +3109,46 @@ function redactKey(key) {
|
|
|
3109
3109
|
return "****";
|
|
3110
3110
|
return `${key.slice(0, 13)}\u2026${key.slice(-4)}`;
|
|
3111
3111
|
}
|
|
3112
|
+
function lookupConnectKey(profile, hubProfileName) {
|
|
3113
|
+
return profile?.connectKeys?.[hubProfileName]?.apiKey;
|
|
3114
|
+
}
|
|
3115
|
+
function storeConnectKey(env, tool, profileName, hubProfileName, entry) {
|
|
3116
|
+
const config = loadConfig(env, tool);
|
|
3117
|
+
const profile = config.profiles[profileName] ?? {};
|
|
3118
|
+
config.profiles[profileName] = {
|
|
3119
|
+
...profile,
|
|
3120
|
+
connectKeys: { ...profile.connectKeys, [hubProfileName]: entry }
|
|
3121
|
+
};
|
|
3122
|
+
if (!config.activeProfile)
|
|
3123
|
+
config.activeProfile = profileName;
|
|
3124
|
+
return saveConfig(env, tool, config);
|
|
3125
|
+
}
|
|
3126
|
+
function removeConnectKey(env, tool, profileName, hubProfileName) {
|
|
3127
|
+
const config = loadConfig(env, tool);
|
|
3128
|
+
const profile = config.profiles[profileName];
|
|
3129
|
+
if (!profile?.connectKeys || !(hubProfileName in profile.connectKeys))
|
|
3130
|
+
return false;
|
|
3131
|
+
const { [hubProfileName]: _dropped, ...rest } = profile.connectKeys;
|
|
3132
|
+
if (Object.keys(rest).length === 0) {
|
|
3133
|
+
const { connectKeys: _empty, ...bare } = profile;
|
|
3134
|
+
config.profiles[profileName] = bare;
|
|
3135
|
+
} else {
|
|
3136
|
+
config.profiles[profileName] = { ...profile, connectKeys: rest };
|
|
3137
|
+
}
|
|
3138
|
+
saveConfig(env, tool, config);
|
|
3139
|
+
return true;
|
|
3140
|
+
}
|
|
3112
3141
|
|
|
3113
|
-
// ../../node_modules/.pnpm/@antasphere+cli-core@0.
|
|
3142
|
+
// ../../node_modules/.pnpm/@antasphere+cli-core@0.4.0/node_modules/@antasphere/cli-core/dist/io.js
|
|
3114
3143
|
function printJson(io, value) {
|
|
3115
3144
|
io.out.write(`${JSON.stringify(value, null, 2)}
|
|
3116
3145
|
`);
|
|
3117
3146
|
}
|
|
3118
3147
|
|
|
3119
|
-
// ../../node_modules/.pnpm/@antasphere+cli-core@0.
|
|
3148
|
+
// ../../node_modules/.pnpm/@antasphere+cli-core@0.4.0/node_modules/@antasphere/cli-core/dist/resolve.js
|
|
3120
3149
|
var CliUsageError = class extends Error {
|
|
3121
3150
|
};
|
|
3151
|
+
var DEFAULT_PROFILE = "default";
|
|
3122
3152
|
function resolveProfile(config, requested, opts = {}) {
|
|
3123
3153
|
if (requested) {
|
|
3124
3154
|
const profile2 = config.profiles[requested];
|
|
@@ -3142,7 +3172,7 @@ function resolveApiKey(opts) {
|
|
|
3142
3172
|
return opts.flag ?? opts.env[opts.envVar] ?? opts.profile?.apiKey;
|
|
3143
3173
|
}
|
|
3144
3174
|
|
|
3145
|
-
// ../../node_modules/.pnpm/@antasphere+cli-core@0.
|
|
3175
|
+
// ../../node_modules/.pnpm/@antasphere+cli-core@0.4.0/node_modules/@antasphere/cli-core/dist/auth.js
|
|
3146
3176
|
var CliAuthError = class extends Error {
|
|
3147
3177
|
status;
|
|
3148
3178
|
code;
|
|
@@ -3197,7 +3227,179 @@ var CliAuthClient = class {
|
|
|
3197
3227
|
}
|
|
3198
3228
|
};
|
|
3199
3229
|
|
|
3200
|
-
// ../../node_modules/.pnpm/@antasphere+cli-core@0.
|
|
3230
|
+
// ../../node_modules/.pnpm/@antasphere+cli-core@0.4.0/node_modules/@antasphere/cli-core/dist/connect.js
|
|
3231
|
+
var CliConnectError = class extends CliAuthError {
|
|
3232
|
+
stage;
|
|
3233
|
+
constructor(stage, status, code, message, details) {
|
|
3234
|
+
super(status, code, message, details);
|
|
3235
|
+
this.stage = stage;
|
|
3236
|
+
this.name = "CliConnectError";
|
|
3237
|
+
}
|
|
3238
|
+
/**
|
|
3239
|
+
* The hub rejected the key itself: invalid/revoked (401), or a key
|
|
3240
|
+
* minted before the `sso:exchange` scope existed (403 insufficient_scope
|
|
3241
|
+
* — old keys simply lack it). The fix is a fresh `antasphere login`.
|
|
3242
|
+
*/
|
|
3243
|
+
get needsHubLogin() {
|
|
3244
|
+
return this.stage === "hub" && (this.status === 401 || this.status === 403 && this.code === "insufficient_scope");
|
|
3245
|
+
}
|
|
3246
|
+
/** The tool rejected the JWT (expired/replayed) — run the exchange again. */
|
|
3247
|
+
get needsReExchange() {
|
|
3248
|
+
return this.stage === "tool" && this.status === 401;
|
|
3249
|
+
}
|
|
3250
|
+
};
|
|
3251
|
+
var CliConnectClient = class {
|
|
3252
|
+
hubBaseUrl;
|
|
3253
|
+
toolBaseUrl;
|
|
3254
|
+
fetchImpl;
|
|
3255
|
+
constructor(options) {
|
|
3256
|
+
this.hubBaseUrl = options.hubBaseUrl.replace(/\/+$/, "");
|
|
3257
|
+
this.toolBaseUrl = options.toolBaseUrl.replace(/\/+$/, "");
|
|
3258
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3259
|
+
}
|
|
3260
|
+
/** Step 1 — the hub mints the 120 s single-org JWT for the tool's resource. */
|
|
3261
|
+
toolToken(hubApiKey, body) {
|
|
3262
|
+
return this.call("hub", `${this.hubBaseUrl}/api/v1/sso/tool-token`, body, hubApiKey);
|
|
3263
|
+
}
|
|
3264
|
+
/**
|
|
3265
|
+
* Step 2 — the tool verifies the JWT (its only credential) and mints its
|
|
3266
|
+
* key. `hubRefreshToken` is the SAME response's offline grant, relayed so
|
|
3267
|
+
* the tool can store it (a grant-less connect is refused for users with
|
|
3268
|
+
* none already stored — `hub_grant_missing`).
|
|
3269
|
+
*/
|
|
3270
|
+
cliConnect(token, hubRefreshToken) {
|
|
3271
|
+
return this.call("tool", `${this.toolBaseUrl}/api/v1/sso/cli-connect`, {
|
|
3272
|
+
token,
|
|
3273
|
+
...hubRefreshToken ? { hubRefreshToken } : {}
|
|
3274
|
+
});
|
|
3275
|
+
}
|
|
3276
|
+
/** The full two-call exchange. The hub key goes to the hub ONLY; the
|
|
3277
|
+
* offline grant goes to the TOOL only — neither is ever persisted here. */
|
|
3278
|
+
async exchange(hubApiKey, body) {
|
|
3279
|
+
const minted = await this.toolToken(hubApiKey, body);
|
|
3280
|
+
const connected = await this.cliConnect(minted.token, minted.hubRefreshToken);
|
|
3281
|
+
return {
|
|
3282
|
+
key: connected.key,
|
|
3283
|
+
apiKey: connected.apiKey,
|
|
3284
|
+
user: connected.user,
|
|
3285
|
+
toolWorkspaceId: connected.workspaceId
|
|
3286
|
+
};
|
|
3287
|
+
}
|
|
3288
|
+
/** Mirrors CliAuthClient's parse: `{ error: { code, message, details } }` envelopes. */
|
|
3289
|
+
async call(stage, url, body, apiKey) {
|
|
3290
|
+
const headers = { "content-type": "application/json" };
|
|
3291
|
+
if (apiKey)
|
|
3292
|
+
headers["authorization"] = `Bearer ${apiKey}`;
|
|
3293
|
+
const res = await this.fetchImpl(url, { method: "POST", headers, body: JSON.stringify(body) });
|
|
3294
|
+
const json = await res.json().catch(() => null);
|
|
3295
|
+
if (!res.ok) {
|
|
3296
|
+
const errBody = json ?? {};
|
|
3297
|
+
throw new CliConnectError(stage, res.status, errBody.error?.code ?? "unknown_error", errBody.error?.message ?? `Request failed with ${res.status}`, errBody.error?.details);
|
|
3298
|
+
}
|
|
3299
|
+
return json;
|
|
3300
|
+
}
|
|
3301
|
+
};
|
|
3302
|
+
|
|
3303
|
+
// ../../node_modules/.pnpm/@antasphere+cli-core@0.4.0/node_modules/@antasphere/cli-core/dist/connect-on-demand.js
|
|
3304
|
+
async function probeToolInstance(toolBaseUrl, fetchImpl) {
|
|
3305
|
+
const f = fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
3306
|
+
try {
|
|
3307
|
+
const res = await f(`${toolBaseUrl.replace(/\/+$/, "")}/api/v1/instance`, {
|
|
3308
|
+
method: "GET",
|
|
3309
|
+
// Discovery is served cacheable for CLI/MCP clients, but the probe
|
|
3310
|
+
// must see live state (mirrors the tool SDKs' discovery call).
|
|
3311
|
+
cache: "no-store"
|
|
3312
|
+
});
|
|
3313
|
+
if (!res.ok)
|
|
3314
|
+
return null;
|
|
3315
|
+
const info = await res.json().catch(() => null);
|
|
3316
|
+
const methods = info?.auth?.methods;
|
|
3317
|
+
if (!Array.isArray(methods))
|
|
3318
|
+
return null;
|
|
3319
|
+
const authMethods = methods.filter((m) => typeof m === "string");
|
|
3320
|
+
const edition = typeof info?.edition === "string" ? info.edition : void 0;
|
|
3321
|
+
return { cloud: authMethods.includes("antasphere") || edition === "cloud", edition, authMethods };
|
|
3322
|
+
} catch {
|
|
3323
|
+
return null;
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
function activeHubProfile(env) {
|
|
3327
|
+
return resolveProfile(loadConfig(env, HUB_TOOL), void 0);
|
|
3328
|
+
}
|
|
3329
|
+
function defaultMissingHubLogin(tool) {
|
|
3330
|
+
const envVar = `${tool.replace(/-/g, "_").toUpperCase()}_API_KEY`;
|
|
3331
|
+
return `This ${tool} instance signs in through the Antasphere hub. Run \`antasphere login\` once, then retry \u2014 or pass --api-key / set ${envVar}.`;
|
|
3332
|
+
}
|
|
3333
|
+
var DEFAULT_HUB_LOGIN_REJECTED = "The stored Antasphere hub credential was rejected \u2014 run `antasphere login` again, then retry.";
|
|
3334
|
+
function defaultConnected(facts) {
|
|
3335
|
+
return `Connected to ${facts.toolBaseUrl} as ${facts.email} via Antasphere` + (facts.stored ? "" : ` \u2014 key NOT cached: profile '${facts.profileName}' points at ${facts.profileBaseUrl}`) + ".\n";
|
|
3336
|
+
}
|
|
3337
|
+
async function connectOnDemand(opts) {
|
|
3338
|
+
assertToolNamespace(opts.tool);
|
|
3339
|
+
const toolBaseUrl = opts.toolBaseUrl.replace(/\/+$/, "");
|
|
3340
|
+
const messages = opts.messages ?? {};
|
|
3341
|
+
const profileName = opts.profileName ?? DEFAULT_PROFILE;
|
|
3342
|
+
const hub = activeHubProfile(opts.env);
|
|
3343
|
+
const existing = loadConfig(opts.env, opts.tool).profiles[profileName];
|
|
3344
|
+
const pinnedHere = existing?.baseUrl?.replace(/\/+$/, "") === toolBaseUrl;
|
|
3345
|
+
if (pinnedHere && hub.name) {
|
|
3346
|
+
const cachedKey = lookupConnectKey(existing, hub.name);
|
|
3347
|
+
if (cachedKey)
|
|
3348
|
+
return { outcome: "connected", key: cachedKey, cached: true };
|
|
3349
|
+
}
|
|
3350
|
+
const probe = await probeToolInstance(toolBaseUrl, opts.fetch);
|
|
3351
|
+
if (!probe?.cloud)
|
|
3352
|
+
return { outcome: "not_cloud" };
|
|
3353
|
+
const hubKey = hub.profile?.apiKey;
|
|
3354
|
+
const hubBaseUrl = hub.profile?.baseUrl;
|
|
3355
|
+
if (!hubKey || !hubBaseUrl || !hub.name) {
|
|
3356
|
+
throw new CliUsageError(messages.missingHubLogin ?? defaultMissingHubLogin(opts.tool));
|
|
3357
|
+
}
|
|
3358
|
+
const resource = opts.resource ?? `${toolBaseUrl}/mcp`;
|
|
3359
|
+
const connect = new CliConnectClient({
|
|
3360
|
+
hubBaseUrl,
|
|
3361
|
+
toolBaseUrl,
|
|
3362
|
+
...opts.fetch ? { fetch: opts.fetch } : {}
|
|
3363
|
+
});
|
|
3364
|
+
const body = { resource };
|
|
3365
|
+
let result;
|
|
3366
|
+
try {
|
|
3367
|
+
result = await connect.exchange(hubKey, body);
|
|
3368
|
+
} catch (e) {
|
|
3369
|
+
if (e instanceof CliConnectError && e.needsReExchange) {
|
|
3370
|
+
result = await connect.exchange(hubKey, body);
|
|
3371
|
+
} else if (e instanceof CliConnectError && e.needsHubLogin) {
|
|
3372
|
+
throw new CliUsageError(messages.hubLoginRejected ?? DEFAULT_HUB_LOGIN_REJECTED);
|
|
3373
|
+
} else {
|
|
3374
|
+
throw e;
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
const stored = !existing?.baseUrl || pinnedHere;
|
|
3378
|
+
if (stored) {
|
|
3379
|
+
storeConnectKey(opts.env, opts.tool, profileName, hub.name, {
|
|
3380
|
+
apiKey: result.key,
|
|
3381
|
+
email: result.user.email,
|
|
3382
|
+
mintedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3383
|
+
});
|
|
3384
|
+
if (!existing?.baseUrl) {
|
|
3385
|
+
const cfg = loadConfig(opts.env, opts.tool);
|
|
3386
|
+
cfg.profiles[profileName] = { ...cfg.profiles[profileName], baseUrl: toolBaseUrl };
|
|
3387
|
+
saveConfig(opts.env, opts.tool, cfg);
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
const facts = {
|
|
3391
|
+
toolBaseUrl,
|
|
3392
|
+
email: result.user.email,
|
|
3393
|
+
stored,
|
|
3394
|
+
profileName,
|
|
3395
|
+
// `stored` is false only when the profile names another instance.
|
|
3396
|
+
...stored ? {} : { profileBaseUrl: existing?.baseUrl }
|
|
3397
|
+
};
|
|
3398
|
+
opts.notify?.((messages.connected ?? defaultConnected)(facts));
|
|
3399
|
+
return { outcome: "connected", key: result.key, result, cached: false, stored };
|
|
3400
|
+
}
|
|
3401
|
+
|
|
3402
|
+
// ../../node_modules/.pnpm/@antasphere+cli-core@0.4.0/node_modules/@antasphere/cli-core/dist/migrate.js
|
|
3201
3403
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
3202
3404
|
import { join as join2 } from "node:path";
|
|
3203
3405
|
function migrateLegacyConfig(env, spec) {
|
|
@@ -3315,6 +3517,14 @@ var PlatformClient = class {
|
|
|
3315
3517
|
me() {
|
|
3316
3518
|
return this.request("GET", "/me");
|
|
3317
3519
|
}
|
|
3520
|
+
/**
|
|
3521
|
+
* CLOUD EDITION only (404 on oss); sessions only (machines 403): record
|
|
3522
|
+
* the explicit first-run-welcome dismissal — flips /me's
|
|
3523
|
+
* `firstRunPending` to false, permanently. Idempotent.
|
|
3524
|
+
*/
|
|
3525
|
+
dismissOnboarding() {
|
|
3526
|
+
return this.request("POST", "/me/onboarding/dismiss");
|
|
3527
|
+
}
|
|
3318
3528
|
/** Better Auth session probe — null when signed out. */
|
|
3319
3529
|
async session() {
|
|
3320
3530
|
return this.request("GET", "/auth/get-session");
|
|
@@ -3337,6 +3547,15 @@ var PlatformClient = class {
|
|
|
3337
3547
|
cliAuthComplete(req) {
|
|
3338
3548
|
return this.request("POST", "/cli/auth/complete", req);
|
|
3339
3549
|
}
|
|
3550
|
+
/**
|
|
3551
|
+
* Revoke the PRESENTING API key (CLI logout). Self-revocation only: the
|
|
3552
|
+
* route names no key, so the credential can kill exactly itself. Requires
|
|
3553
|
+
* an API-key credential with presentations:write (sessions and OAuth
|
|
3554
|
+
* bearers are refused — the dashboard is their key-management surface).
|
|
3555
|
+
*/
|
|
3556
|
+
cliAuthRevoke() {
|
|
3557
|
+
return this.request("DELETE", "/cli/auth/key");
|
|
3558
|
+
}
|
|
3340
3559
|
/**
|
|
3341
3560
|
* Public, CLOUD EDITION only (404 on oss): exchange a hub-minted 120 s
|
|
3342
3561
|
* connect JWT (the hub's /sso/tool-token response) for an `slk_` API key
|
|
@@ -3346,6 +3565,17 @@ var PlatformClient = class {
|
|
|
3346
3565
|
ssoCliConnect(req) {
|
|
3347
3566
|
return this.request("POST", "/sso/cli-connect", req);
|
|
3348
3567
|
}
|
|
3568
|
+
/**
|
|
3569
|
+
* CLOUD EDITION only (404 on oss); sessions only (machines 403 — the
|
|
3570
|
+
* path is unlisted in the scope allowlist): single logout. The server
|
|
3571
|
+
* revokes the local session and clears the SSO hint cookie in this very
|
|
3572
|
+
* response; `url` is the hub end-session URL the browser must then VISIT
|
|
3573
|
+
* to end the hub anchor session (null = local signout only — go straight
|
|
3574
|
+
* to /login?signed_out=1).
|
|
3575
|
+
*/
|
|
3576
|
+
ssoLogout() {
|
|
3577
|
+
return this.request("POST", "/sso/logout");
|
|
3578
|
+
}
|
|
3349
3579
|
// ── Members ───────────────────────────────────────────────────────────────
|
|
3350
3580
|
members(params = {}) {
|
|
3351
3581
|
return this.request("GET", this.pathWithQuery("/members", params));
|
|
@@ -3418,15 +3648,6 @@ var PlatformClient = class {
|
|
|
3418
3648
|
acceptInvitation(req) {
|
|
3419
3649
|
return this.request("POST", "/invitations/accept", req);
|
|
3420
3650
|
}
|
|
3421
|
-
// ── OAuth consent ─────────────────────────────────────────────────────────
|
|
3422
|
-
/**
|
|
3423
|
-
* Park the workspace the upcoming OAuth consent should bind (ADR 014).
|
|
3424
|
-
* Sessions only; the consent page calls it right before approving when
|
|
3425
|
-
* the user picked a non-default workspace.
|
|
3426
|
-
*/
|
|
3427
|
-
oauthConsentWorkspace(workspaceId) {
|
|
3428
|
-
return this.request("POST", "/oauth/consent-workspace", { workspaceId });
|
|
3429
|
-
}
|
|
3430
3651
|
// ── Audit ─────────────────────────────────────────────────────────────────
|
|
3431
3652
|
audit(params = {}) {
|
|
3432
3653
|
return this.request("GET", this.pathWithQuery("/audit", params));
|
|
@@ -3657,6 +3878,9 @@ function saveConfig2(env, config) {
|
|
|
3657
3878
|
function clearConfig2(env) {
|
|
3658
3879
|
clearConfig(env, TOOL);
|
|
3659
3880
|
}
|
|
3881
|
+
function removeConnectKey2(env, profileName, hubProfileName) {
|
|
3882
|
+
return removeConnectKey(env, TOOL, profileName, hubProfileName);
|
|
3883
|
+
}
|
|
3660
3884
|
|
|
3661
3885
|
// src/context.ts
|
|
3662
3886
|
function resolveProfile2(config, requested) {
|
|
@@ -3676,7 +3900,11 @@ function resolveContext(cmd, io) {
|
|
|
3676
3900
|
profile,
|
|
3677
3901
|
missingMessage: "No instance configured. Pass --api-url <url>, set SLIDELESS_URL, or sign in once with `slideless auth login-request --api-url <url> --email <you>` to save a profile."
|
|
3678
3902
|
});
|
|
3679
|
-
|
|
3903
|
+
let apiKey = resolveApiKey({ flag: opts.apiKey, env: io.env, envVar: "SLIDELESS_API_KEY", profile });
|
|
3904
|
+
if (!apiKey && profile?.baseUrl?.replace(/\/+$/, "") === baseUrl) {
|
|
3905
|
+
const hub = activeHubProfile(io.env);
|
|
3906
|
+
if (hub.name) apiKey = lookupConnectKey(profile, hub.name);
|
|
3907
|
+
}
|
|
3680
3908
|
const fetchImpl = io.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3681
3909
|
return {
|
|
3682
3910
|
client: new PlatformClient({ baseUrl, ...apiKey ? { apiKey } : {}, fetch: fetchImpl }),
|
|
@@ -3688,13 +3916,29 @@ function resolveContext(cmd, io) {
|
|
|
3688
3916
|
config
|
|
3689
3917
|
};
|
|
3690
3918
|
}
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3919
|
+
var NO_KEY_MESSAGE = "An API key is required. Sign in (`slideless auth login-request --email <you>`), paste one (`slideless login`), pass --api-key, or set SLIDELESS_API_KEY.";
|
|
3920
|
+
var MISSING_HUB_LOGIN_MESSAGE = "This Slideless instance signs in through the Antasphere hub. Run `antasphere login` once, then retry \u2014 or pass --api-key <slk_\u2026> / set SLIDELESS_API_KEY.";
|
|
3921
|
+
async function requireApiKey(ctx) {
|
|
3922
|
+
if (ctx.apiKey) return ctx.apiKey;
|
|
3923
|
+
const { io } = ctx;
|
|
3924
|
+
const outcome = await connectOnDemand({
|
|
3925
|
+
tool: "slideless",
|
|
3926
|
+
toolBaseUrl: ctx.baseUrl,
|
|
3927
|
+
...ctx.profileName !== void 0 ? { profileName: ctx.profileName } : {},
|
|
3928
|
+
env: io.env,
|
|
3929
|
+
// Thread the injected fetch so the probe + exchange stay on the test
|
|
3930
|
+
// harness wire (and any proxying the runner set up).
|
|
3931
|
+
...io.fetch ? { fetch: io.fetch } : {},
|
|
3932
|
+
notify: (line) => io.err.write(line),
|
|
3933
|
+
messages: { missingHubLogin: MISSING_HUB_LOGIN_MESSAGE }
|
|
3934
|
+
});
|
|
3935
|
+
if (outcome.outcome === "not_cloud") {
|
|
3936
|
+
throw new CliUsageError(NO_KEY_MESSAGE);
|
|
3696
3937
|
}
|
|
3697
|
-
|
|
3938
|
+
ctx.apiKey = outcome.key;
|
|
3939
|
+
const fetchImpl = io.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3940
|
+
ctx.client = new PlatformClient({ baseUrl: ctx.baseUrl, apiKey: outcome.key, fetch: fetchImpl });
|
|
3941
|
+
return outcome.key;
|
|
3698
3942
|
}
|
|
3699
3943
|
function table(rows) {
|
|
3700
3944
|
if (rows.length === 0) return "";
|
|
@@ -3730,10 +3974,26 @@ async function readLineFromStdin() {
|
|
|
3730
3974
|
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
3731
3975
|
return Buffer.concat(chunks).toString("utf8").split("\n")[0]?.trim() ?? "";
|
|
3732
3976
|
}
|
|
3977
|
+
async function refuseOtpLoginOnCloud(baseUrl, io) {
|
|
3978
|
+
let cloud = false;
|
|
3979
|
+
try {
|
|
3980
|
+
const fetchImpl = io.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3981
|
+
const info = await new PlatformClient({ baseUrl, fetch: fetchImpl }).instance();
|
|
3982
|
+
cloud = info.auth.methods.includes("antasphere") || info.edition === "cloud";
|
|
3983
|
+
} catch {
|
|
3984
|
+
return;
|
|
3985
|
+
}
|
|
3986
|
+
if (cloud) {
|
|
3987
|
+
throw new CliUsageError(
|
|
3988
|
+
`${baseUrl} is an Antasphere-cloud instance \u2014 it signs in at the hub, not with its own email codes. Run \`antasphere login\` once; \`slideless\` then connects automatically (or pass --api-key <slk_\u2026> / set SLIDELESS_API_KEY).`
|
|
3989
|
+
);
|
|
3990
|
+
}
|
|
3991
|
+
}
|
|
3733
3992
|
function registerAuthCommands(program2, io) {
|
|
3734
3993
|
const auth = program2.command("auth").description("Sign in over email OTP (mints an API key)");
|
|
3735
3994
|
auth.command("login-request").description("Email a 6-digit sign-in code (existing accounts only \u2014 sign-up stays closed)").requiredOption("--email <email>", "account email on the instance").action(async (opts, cmd) => {
|
|
3736
3995
|
const baseUrl = resolveAuthUrl(cmd, io);
|
|
3996
|
+
await refuseOtpLoginOnCloud(baseUrl, io);
|
|
3737
3997
|
const client = new CliAuthClient({ baseUrl, ...io.fetch ? { fetch: io.fetch } : {} });
|
|
3738
3998
|
const result = await client.request({ email: opts.email });
|
|
3739
3999
|
const json = Boolean(cmd.optsWithGlobals().json);
|
|
@@ -3752,6 +4012,7 @@ Complete with: slideless auth login-complete --email ${opts.email} --code <code>
|
|
|
3752
4012
|
async (opts, cmd) => {
|
|
3753
4013
|
const globals = cmd.optsWithGlobals();
|
|
3754
4014
|
const baseUrl = resolveAuthUrl(cmd, io);
|
|
4015
|
+
await refuseOtpLoginOnCloud(baseUrl, io);
|
|
3755
4016
|
const client = new CliAuthClient({ baseUrl, ...io.fetch ? { fetch: io.fetch } : {} });
|
|
3756
4017
|
const result = await client.complete({
|
|
3757
4018
|
email: opts.email,
|
|
@@ -3800,7 +4061,9 @@ API key "${result.apiKey.name}" (${redactKey(result.key)}) saved to profile "${p
|
|
|
3800
4061
|
`
|
|
3801
4062
|
);
|
|
3802
4063
|
});
|
|
3803
|
-
program2.command("logout").description(
|
|
4064
|
+
program2.command("logout").description(
|
|
4065
|
+
"Forget the stored API key of the active (or named) profile; a hub-connected profile disconnects from Antasphere (revokes + evicts the cached user-scoped key)"
|
|
4066
|
+
).action(async (_opts, cmd) => {
|
|
3804
4067
|
const globals = cmd.optsWithGlobals();
|
|
3805
4068
|
const config2 = loadConfig2(io.env);
|
|
3806
4069
|
const profileName = globals.profile ?? config2.activeProfile;
|
|
@@ -3808,6 +4071,50 @@ API key "${result.apiKey.name}" (${redactKey(result.key)}) saved to profile "${p
|
|
|
3808
4071
|
if (!profileName || !profile) {
|
|
3809
4072
|
throw new CliUsageError("No profile to log out of.");
|
|
3810
4073
|
}
|
|
4074
|
+
const connectKeys = profile.connectKeys ?? {};
|
|
4075
|
+
const slots = Object.entries(connectKeys);
|
|
4076
|
+
if (!profile.apiKey && slots.length > 0) {
|
|
4077
|
+
const rawUrl = profile.baseUrl;
|
|
4078
|
+
let revoked = true;
|
|
4079
|
+
for (const [slot, entry] of slots) {
|
|
4080
|
+
if (rawUrl) {
|
|
4081
|
+
const baseUrl = rawUrl.replace(/\/+$/, "");
|
|
4082
|
+
try {
|
|
4083
|
+
const client = new CliAuthClient({ baseUrl, ...io.fetch ? { fetch: io.fetch } : {} });
|
|
4084
|
+
await client.revoke(entry.apiKey);
|
|
4085
|
+
} catch (e) {
|
|
4086
|
+
revoked = false;
|
|
4087
|
+
if (e instanceof CliAuthError && e.status === 401) {
|
|
4088
|
+
io.err.write("The cached key was already unusable \u2014 evicting it anyway.\n");
|
|
4089
|
+
} else if (e instanceof CliAuthError && e.status === 403) {
|
|
4090
|
+
io.err.write(
|
|
4091
|
+
`This instance refused the self-revoke (${e.code}) \u2014 the key STAYS VALID server-side; revoke it from the dashboard. Evicting the cached copy.
|
|
4092
|
+
`
|
|
4093
|
+
);
|
|
4094
|
+
} else {
|
|
4095
|
+
throw e;
|
|
4096
|
+
}
|
|
4097
|
+
}
|
|
4098
|
+
} else {
|
|
4099
|
+
revoked = false;
|
|
4100
|
+
io.err.write("No instance URL known for this profile \u2014 evicting the cached key locally only.\n");
|
|
4101
|
+
}
|
|
4102
|
+
removeConnectKey2(io.env, profileName, slot);
|
|
4103
|
+
}
|
|
4104
|
+
if (globals.json) {
|
|
4105
|
+
return printJson(io, {
|
|
4106
|
+
profile: profileName,
|
|
4107
|
+
hubProfiles: slots.map(([slot]) => slot),
|
|
4108
|
+
revoked,
|
|
4109
|
+
evicted: true
|
|
4110
|
+
});
|
|
4111
|
+
}
|
|
4112
|
+
io.out.write(
|
|
4113
|
+
`Disconnected from Antasphere on profile "${profileName}"${revoked ? " (key revoked server-side)" : ""}.
|
|
4114
|
+
`
|
|
4115
|
+
);
|
|
4116
|
+
return;
|
|
4117
|
+
}
|
|
3811
4118
|
delete profile.apiKey;
|
|
3812
4119
|
if (!profile.baseUrl) delete config2.profiles[profileName];
|
|
3813
4120
|
saveConfig2(io.env, config2);
|
|
@@ -3819,14 +4126,14 @@ API key "${result.apiKey.name}" (${redactKey(result.key)}) saved to profile "${p
|
|
|
3819
4126
|
});
|
|
3820
4127
|
program2.command("whoami").description("Show the identity behind the resolved API key").action(async (_opts, cmd) => {
|
|
3821
4128
|
const ctx = resolveContext(cmd, io);
|
|
3822
|
-
requireApiKey(ctx);
|
|
4129
|
+
await requireApiKey(ctx);
|
|
3823
4130
|
const me = await ctx.client.me();
|
|
3824
4131
|
if (ctx.json) return printJson(io, me);
|
|
3825
4132
|
io.out.write(
|
|
3826
4133
|
`${me.user.name} <${me.user.email}>
|
|
3827
4134
|
instance: ${ctx.baseUrl}
|
|
3828
|
-
workspace: ${me.workspace
|
|
3829
|
-
role: ${me.role} (via ${me.via})
|
|
4135
|
+
workspace: ${me.workspace?.name ?? "(none)"}
|
|
4136
|
+
role: ${me.role ?? "(none)"} (via ${me.via})
|
|
3830
4137
|
scopes: ${me.scopes ? me.scopes.join(", ") : "full (session)"}
|
|
3831
4138
|
` + (me.via === "api_key" ? ` key expires: ${me.apiKeyExpiresAt ?? "never"}
|
|
3832
4139
|
` : "")
|
|
@@ -3834,7 +4141,7 @@ API key "${result.apiKey.name}" (${redactKey(result.key)}) saved to profile "${p
|
|
|
3834
4141
|
});
|
|
3835
4142
|
program2.command("verify").description("Check that the resolved instance + key work (exit 0 = ok)").action(async (_opts, cmd) => {
|
|
3836
4143
|
const ctx = resolveContext(cmd, io);
|
|
3837
|
-
requireApiKey(ctx);
|
|
4144
|
+
await requireApiKey(ctx);
|
|
3838
4145
|
const me = await ctx.client.me();
|
|
3839
4146
|
if (ctx.json) return printJson(io, { ok: true, baseUrl: ctx.baseUrl, user: me.user });
|
|
3840
4147
|
io.out.write(`ok \u2014 ${me.user.email} (${me.role}) @ ${ctx.baseUrl}
|
|
@@ -3862,7 +4169,16 @@ API key "${result.apiKey.name}" (${redactKey(result.key)}) saved to profile "${p
|
|
|
3862
4169
|
profiles: Object.fromEntries(
|
|
3863
4170
|
names.map((n) => {
|
|
3864
4171
|
const p = config2.profiles[n];
|
|
3865
|
-
return [
|
|
4172
|
+
return [
|
|
4173
|
+
n,
|
|
4174
|
+
{
|
|
4175
|
+
baseUrl: p.baseUrl ?? null,
|
|
4176
|
+
apiKey: p.apiKey ? redactKey(p.apiKey) : null,
|
|
4177
|
+
// Hub profiles this tool profile is connected through
|
|
4178
|
+
// (one user-scoped key each, valid for every org).
|
|
4179
|
+
hubProfiles: Object.keys(p.connectKeys ?? {})
|
|
4180
|
+
}
|
|
4181
|
+
];
|
|
3866
4182
|
})
|
|
3867
4183
|
)
|
|
3868
4184
|
});
|
|
@@ -3877,11 +4193,12 @@ API key "${result.apiKey.name}" (${redactKey(result.key)}) saved to profile "${p
|
|
|
3877
4193
|
table(
|
|
3878
4194
|
names.map((n) => {
|
|
3879
4195
|
const p = config2.profiles[n];
|
|
4196
|
+
const hubProfiles = Object.keys(p.connectKeys ?? {});
|
|
3880
4197
|
return [
|
|
3881
4198
|
config2.activeProfile === n ? "*" : " ",
|
|
3882
4199
|
n,
|
|
3883
4200
|
p.baseUrl ?? "(no url)",
|
|
3884
|
-
p.apiKey ? redactKey(p.apiKey) : "(no key)"
|
|
4201
|
+
p.apiKey ? redactKey(p.apiKey) : hubProfiles.length > 0 ? `(hub: ${hubProfiles.join(", ")})` : "(no key)"
|
|
3885
4202
|
];
|
|
3886
4203
|
})
|
|
3887
4204
|
)
|
|
@@ -3898,7 +4215,14 @@ API key "${result.apiKey.name}" (${redactKey(result.key)}) saved to profile "${p
|
|
|
3898
4215
|
profiles: Object.fromEntries(
|
|
3899
4216
|
Object.entries(cfg.profiles).map(([n, p]) => [
|
|
3900
4217
|
n,
|
|
3901
|
-
{
|
|
4218
|
+
{
|
|
4219
|
+
baseUrl: p.baseUrl ?? null,
|
|
4220
|
+
apiKey: p.apiKey ? redactKey(p.apiKey) : null,
|
|
4221
|
+
// Hub-connected keys (one per hub profile), redacted like the rest.
|
|
4222
|
+
connectKeys: Object.fromEntries(
|
|
4223
|
+
Object.entries(p.connectKeys ?? {}).map(([slot, entry]) => [slot, redactKey(entry.apiKey)])
|
|
4224
|
+
)
|
|
4225
|
+
}
|
|
3902
4226
|
])
|
|
3903
4227
|
)
|
|
3904
4228
|
};
|
|
@@ -3920,7 +4244,7 @@ API key "${result.apiKey.name}" (${redactKey(result.key)}) saved to profile "${p
|
|
|
3920
4244
|
function registerDeckCommands(program2, io) {
|
|
3921
4245
|
program2.command("list").description("List presentations (newest first, cursor-paginated)").option("--cursor <cursor>", "resume from a previous nextCursor").option("--limit <n>", "page size (1-100)", (v) => parseInt(v, 10)).option("--all", "follow nextCursor until every page is fetched", false).action(async (opts, cmd) => {
|
|
3922
4246
|
const ctx = resolveContext(cmd, io);
|
|
3923
|
-
requireApiKey(ctx);
|
|
4247
|
+
await requireApiKey(ctx);
|
|
3924
4248
|
const params = {};
|
|
3925
4249
|
if (opts.cursor) params.cursor = opts.cursor;
|
|
3926
4250
|
if (opts.limit !== void 0) params.limit = opts.limit;
|
|
@@ -3948,7 +4272,7 @@ function registerDeckCommands(program2, io) {
|
|
|
3948
4272
|
});
|
|
3949
4273
|
program2.command("get <id>").description("Show one presentation (metadata + latest version)").action(async (id, _opts, cmd) => {
|
|
3950
4274
|
const ctx = resolveContext(cmd, io);
|
|
3951
|
-
requireApiKey(ctx);
|
|
4275
|
+
await requireApiKey(ctx);
|
|
3952
4276
|
const deck = await ctx.client.presentation(id);
|
|
3953
4277
|
if (ctx.json) return printJson(io, deck);
|
|
3954
4278
|
io.out.write(
|
|
@@ -3965,7 +4289,7 @@ function registerDeckCommands(program2, io) {
|
|
|
3965
4289
|
});
|
|
3966
4290
|
program2.command("delete <id>").description("Delete a presentation (soft delete; versions and share links stop resolving)").action(async (id, _opts, cmd) => {
|
|
3967
4291
|
const ctx = resolveContext(cmd, io);
|
|
3968
|
-
requireApiKey(ctx);
|
|
4292
|
+
await requireApiKey(ctx);
|
|
3969
4293
|
const deck = await ctx.client.deletePresentation(id);
|
|
3970
4294
|
if (ctx.json) return printJson(io, deck);
|
|
3971
4295
|
io.out.write(`Deleted "${deck.title}" (${deck.id}).
|
|
@@ -4316,7 +4640,7 @@ function registerContentCommands(program2, io) {
|
|
|
4316
4640
|
).option("--title <title>", "deck title (default: existing title, or the folder name)").option("--entry <path>", "entry document (default: index.html, or the only .html)").option("--kind <kind>", "presentation | app | plan (new decks only)", "presentation").option("--interactive", "mark the deck as embedding interactive content (new decks only)", false).option("--id <deckId>", "push a new version of this existing deck").option("--new", `force a NEW deck even when ${LINK_FILENAME} links one`, false).action(
|
|
4317
4641
|
async (path, opts, cmd) => {
|
|
4318
4642
|
const ctx = resolveContext(cmd, io);
|
|
4319
|
-
requireApiKey(ctx);
|
|
4643
|
+
await requireApiKey(ctx);
|
|
4320
4644
|
const target = path ?? ".";
|
|
4321
4645
|
const scan = await scanDeck(target);
|
|
4322
4646
|
const entryPath = detectEntry(scan, opts.entry);
|
|
@@ -4392,7 +4716,7 @@ function registerContentCommands(program2, io) {
|
|
|
4392
4716
|
`Download a deck version to a folder (id defaults to the ${LINK_FILENAME} link in the target)`
|
|
4393
4717
|
).option("--at <version>", "pull this version instead of the latest", (v) => parseInt(v, 10)).action(async (id, path, opts, cmd) => {
|
|
4394
4718
|
const ctx = resolveContext(cmd, io);
|
|
4395
|
-
requireApiKey(ctx);
|
|
4719
|
+
await requireApiKey(ctx);
|
|
4396
4720
|
let deckId = id ?? null;
|
|
4397
4721
|
let dest = path ?? null;
|
|
4398
4722
|
if (!deckId) {
|
|
@@ -4437,7 +4761,7 @@ function registerContentCommands(program2, io) {
|
|
|
4437
4761
|
program2.command("pull-annotations [id]").description(`List a deck's annotations (id defaults to the ${LINK_FILENAME} link in .)`).option("--version <n>", "only notes anchored to this version", (v) => parseInt(v, 10)).option("--status <status>", "open | resolved").option("--out <file>", "write the annotations as JSON to this file").action(
|
|
4438
4762
|
async (id, opts, cmd) => {
|
|
4439
4763
|
const ctx = resolveContext(cmd, io);
|
|
4440
|
-
requireApiKey(ctx);
|
|
4764
|
+
await requireApiKey(ctx);
|
|
4441
4765
|
let deckId = id ?? null;
|
|
4442
4766
|
if (!deckId) {
|
|
4443
4767
|
const link = await readLink(resolve3("."));
|
|
@@ -4550,7 +4874,7 @@ function registerSharingCommands(program2, io) {
|
|
|
4550
4874
|
program2.command("share <id>").description("Create a per-recipient share link (prints the viewer URL \u2014 shown once)").option("--name <name>", "owner-facing recipient label", "cli").option("--to-version <n>", "pin the recipient to this version", (v) => parseInt(v, 10)).option("--annotator", "let the recipient annotate", false).option("--expires <datetime>", "ISO expiry, e.g. 2026-12-31T23:59:59Z").option("--password <password>", "viewer password (min 4 chars)").action(
|
|
4551
4875
|
async (id, opts, cmd) => {
|
|
4552
4876
|
const ctx = resolveContext(cmd, io);
|
|
4553
|
-
requireApiKey(ctx);
|
|
4877
|
+
await requireApiKey(ctx);
|
|
4554
4878
|
const created = await ctx.client.createShareToken(id, shareOptionsOf(opts));
|
|
4555
4879
|
if (ctx.json) return printJson(io, created);
|
|
4556
4880
|
io.out.write(
|
|
@@ -4563,7 +4887,7 @@ function registerSharingCommands(program2, io) {
|
|
|
4563
4887
|
);
|
|
4564
4888
|
program2.command("unshare <id>").description("Revoke one share token (--token) or ALL active tokens of the deck").option("--token <tokenId>", "revoke only this token").action(async (id, opts, cmd) => {
|
|
4565
4889
|
const ctx = resolveContext(cmd, io);
|
|
4566
|
-
requireApiKey(ctx);
|
|
4890
|
+
await requireApiKey(ctx);
|
|
4567
4891
|
if (opts.token) {
|
|
4568
4892
|
const revoked2 = await ctx.client.revokeShareToken(id, opts.token);
|
|
4569
4893
|
if (ctx.json) return printJson(io, revoked2);
|
|
@@ -4592,7 +4916,7 @@ function registerSharingCommands(program2, io) {
|
|
|
4592
4916
|
program2.command("share-email <id>").description("Create a personal share link per recipient and email it (one token per address)").requiredOption("--to <email...>", "recipient email(s)").option("--to-version <n>", "pin recipients to this version", (v) => parseInt(v, 10)).option("--annotator", "let recipients annotate", false).option("--expires <datetime>", "ISO expiry").option("--password <password>", "viewer password (tell recipients separately)").option("--message <text>", "personal note included in the email").action(
|
|
4593
4917
|
async (id, opts, cmd) => {
|
|
4594
4918
|
const ctx = resolveContext(cmd, io);
|
|
4595
|
-
requireApiKey(ctx);
|
|
4919
|
+
await requireApiKey(ctx);
|
|
4596
4920
|
const results = [];
|
|
4597
4921
|
for (const email of opts.to) {
|
|
4598
4922
|
const created = await ctx.client.createShareToken(id, shareOptionsOf({ ...opts, name: email }));
|
|
@@ -4611,7 +4935,7 @@ function registerSharingCommands(program2, io) {
|
|
|
4611
4935
|
program2.command("pin <id> <tokenId>").description("Pin a share token to a version, or set it back to following the latest").option("--to-version <n>", "freeze the recipient on this version", (v) => parseInt(v, 10)).option("--latest", "follow the latest version again", false).action(
|
|
4612
4936
|
async (id, tokenId, opts, cmd) => {
|
|
4613
4937
|
const ctx = resolveContext(cmd, io);
|
|
4614
|
-
requireApiKey(ctx);
|
|
4938
|
+
await requireApiKey(ctx);
|
|
4615
4939
|
if (opts.latest === (opts.toVersion !== void 0)) {
|
|
4616
4940
|
throw new CliUsageError("Pass exactly one of --to-version <n> or --latest.");
|
|
4617
4941
|
}
|
|
@@ -4627,7 +4951,7 @@ function registerSharingCommands(program2, io) {
|
|
|
4627
4951
|
);
|
|
4628
4952
|
program2.command("invite <id>").description("Invite a dev collaborator to one deck (prints the claim link)").requiredOption("--email <email>", "invitee email").action(async (id, opts, cmd) => {
|
|
4629
4953
|
const ctx = resolveContext(cmd, io);
|
|
4630
|
-
requireApiKey(ctx);
|
|
4954
|
+
await requireApiKey(ctx);
|
|
4631
4955
|
const invited = await ctx.client.inviteCollaborator(id, { email: opts.email });
|
|
4632
4956
|
if (ctx.json) return printJson(io, invited);
|
|
4633
4957
|
io.out.write(
|
|
@@ -4639,7 +4963,7 @@ function registerSharingCommands(program2, io) {
|
|
|
4639
4963
|
});
|
|
4640
4964
|
program2.command("uninvite <id> <collaboratorId>").description("Revoke a collaborator grant (pending or active)").action(async (id, collaboratorId, _opts, cmd) => {
|
|
4641
4965
|
const ctx = resolveContext(cmd, io);
|
|
4642
|
-
requireApiKey(ctx);
|
|
4966
|
+
await requireApiKey(ctx);
|
|
4643
4967
|
const revoked = await ctx.client.removeCollaborator(id, collaboratorId);
|
|
4644
4968
|
if (ctx.json) return printJson(io, revoked);
|
|
4645
4969
|
io.out.write(`Revoked collaborator grant ${revoked.id} (${revoked.email}).
|
|
@@ -4672,7 +4996,7 @@ function registerFileCommands(program2, io) {
|
|
|
4672
4996
|
});
|
|
4673
4997
|
program2.command("export").description("Download the full workspace export as a zip (key needs data:export)").option("-o, --out <path>", "write to this path (defaults to export-<date>.zip)").action(async (opts, cmd) => {
|
|
4674
4998
|
const ctx = resolveContext(cmd, io);
|
|
4675
|
-
requireApiKey(ctx);
|
|
4999
|
+
await requireApiKey(ctx);
|
|
4676
5000
|
const res = await ctx.client.downloadExport();
|
|
4677
5001
|
if (!res.body) {
|
|
4678
5002
|
throw new Error("The export response carried no body");
|
|
@@ -4686,7 +5010,7 @@ function registerFileCommands(program2, io) {
|
|
|
4686
5010
|
const files = program2.command("files").description("Manage workspace files");
|
|
4687
5011
|
files.command("list").description("List files in the workspace (newest first, cursor-paginated)").option("--cursor <cursor>", "resume from a previous nextCursor").option("--limit <n>", "page size (1-100)", (v) => parseInt(v, 10)).option("--all", "follow nextCursor until every page is fetched", false).action(async (opts, cmd) => {
|
|
4688
5012
|
const ctx = resolveContext(cmd, io);
|
|
4689
|
-
requireApiKey(ctx);
|
|
5013
|
+
await requireApiKey(ctx);
|
|
4690
5014
|
const params = {};
|
|
4691
5015
|
if (opts.cursor) params.cursor = opts.cursor;
|
|
4692
5016
|
if (opts.limit !== void 0) params.limit = opts.limit;
|
|
@@ -4717,7 +5041,7 @@ function registerFileCommands(program2, io) {
|
|
|
4717
5041
|
});
|
|
4718
5042
|
files.command("upload <path>").description("Upload a local file").option("--name <name>", "stored file name (defaults to the local basename)").option("--content-type <type>", "content type", "application/octet-stream").action(async (path, opts, cmd) => {
|
|
4719
5043
|
const ctx = resolveContext(cmd, io);
|
|
4720
|
-
requireApiKey(ctx);
|
|
5044
|
+
await requireApiKey(ctx);
|
|
4721
5045
|
const bytes = await readFile4(path);
|
|
4722
5046
|
const name = opts.name ?? basename2(path);
|
|
4723
5047
|
const result = await ctx.client.uploadFile(name, new Uint8Array(bytes), opts.contentType);
|
|
@@ -4730,7 +5054,7 @@ function registerFileCommands(program2, io) {
|
|
|
4730
5054
|
});
|
|
4731
5055
|
files.command("download <id>").description("Download a file by id").option("--out <path>", "write to this path (defaults to the stored name)").action(async (id, opts, cmd) => {
|
|
4732
5056
|
const ctx = resolveContext(cmd, io);
|
|
4733
|
-
const apiKey = requireApiKey(ctx);
|
|
5057
|
+
const apiKey = await requireApiKey(ctx);
|
|
4734
5058
|
const meta = await ctx.client.file(id);
|
|
4735
5059
|
const fetchImpl = io.fetch ?? globalThis.fetch.bind(globalThis);
|
|
4736
5060
|
const res = await fetchImpl(ctx.client.fileContentUrl(id), {
|
|
@@ -4747,7 +5071,7 @@ function registerFileCommands(program2, io) {
|
|
|
4747
5071
|
});
|
|
4748
5072
|
files.command("rm <id>").description("Delete a file by id").action(async (id, _opts, cmd) => {
|
|
4749
5073
|
const ctx = resolveContext(cmd, io);
|
|
4750
|
-
requireApiKey(ctx);
|
|
5074
|
+
await requireApiKey(ctx);
|
|
4751
5075
|
await ctx.client.deleteFile(id);
|
|
4752
5076
|
if (ctx.json) return printJson(io, { deleted: id });
|
|
4753
5077
|
io.out.write(`Deleted ${id}
|
|
@@ -4833,7 +5157,7 @@ function registerCompletionCommand(program2, io) {
|
|
|
4833
5157
|
}
|
|
4834
5158
|
|
|
4835
5159
|
// src/index.ts
|
|
4836
|
-
var VERSION = "0.2.
|
|
5160
|
+
var VERSION = "0.2.4";
|
|
4837
5161
|
function buildProgram(io) {
|
|
4838
5162
|
const program2 = new Command();
|
|
4839
5163
|
program2.name("slideless").description("Command-line client for a Slideless instance (push, share, pull, preview)").version(VERSION).option("--api-url <url>", "instance base URL (or SLIDELESS_URL / profile baseUrl)").option("--url <url>", "alias of --api-url").option("--api-key <key>", "API key (or SLIDELESS_API_KEY / profile apiKey)").option("--profile <name>", "use this saved profile instead of the active one").option("--json", "machine-readable JSON output", false);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antasphere/slideless",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "The Slideless CLI — push, share, pull, and preview decks on a Slideless instance",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"test": "vitest run --passWithNoTests"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@antasphere/cli-core": "^0.
|
|
33
|
+
"@antasphere/cli-core": "^0.4.0",
|
|
34
34
|
"@slideless/contract": "workspace:*",
|
|
35
35
|
"@slideless/sdk": "workspace:*",
|
|
36
36
|
"@types/node": "^22.15.0",
|