@autohq/cli 0.1.86 → 0.1.88
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/agent-bridge.js +21 -1
- package/dist/index.js +274 -169
- package/package.json +1 -1
package/dist/agent-bridge.js
CHANGED
|
@@ -21330,6 +21330,21 @@ var SessionApplyTriggersSchema = external_exports.array(
|
|
|
21330
21330
|
).transform(expandSessionApplyTriggerDefinitions).superRefine(validateAttributedRunsTriggerPairing);
|
|
21331
21331
|
var AVATAR_ASSET_EXTENSIONS = [".png", ".jpg", ".jpeg"];
|
|
21332
21332
|
var MAX_AVATAR_ASSET_BYTES = 2 * 1024 * 1024;
|
|
21333
|
+
var SESSION_IDENTITY_DESCRIPTION_MAX_LENGTH = 140;
|
|
21334
|
+
function sessionIdentityDescriptionLength(value2) {
|
|
21335
|
+
let length = 0;
|
|
21336
|
+
for (const char of value2) {
|
|
21337
|
+
const codePoint = char.codePointAt(0) ?? 0;
|
|
21338
|
+
if (codePoint < 32 || codePoint > 126) {
|
|
21339
|
+
length += 6 * char.length;
|
|
21340
|
+
} else if (char === '"' || char === "\\" || char === "/") {
|
|
21341
|
+
length += 2;
|
|
21342
|
+
} else {
|
|
21343
|
+
length += 1;
|
|
21344
|
+
}
|
|
21345
|
+
}
|
|
21346
|
+
return length;
|
|
21347
|
+
}
|
|
21333
21348
|
var SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/;
|
|
21334
21349
|
function isAvatarAssetPathShapeValid(asset) {
|
|
21335
21350
|
const normalized = asset.trim().replaceAll("\\", "/");
|
|
@@ -21353,7 +21368,12 @@ var SessionIdentitySchema = external_exports.object({
|
|
|
21353
21368
|
// overwritten, so it is never trusted input.
|
|
21354
21369
|
sha256: external_exports.string().regex(SHA256_HEX_PATTERN).optional()
|
|
21355
21370
|
}).strict().optional(),
|
|
21356
|
-
description: external_exports.string().trim().min(1).
|
|
21371
|
+
description: external_exports.string().trim().min(1).refine(
|
|
21372
|
+
(value2) => sessionIdentityDescriptionLength(value2) <= SESSION_IDENTITY_DESCRIPTION_MAX_LENGTH,
|
|
21373
|
+
{
|
|
21374
|
+
message: `description must be at most ${SESSION_IDENTITY_DESCRIPTION_MAX_LENGTH} characters as Slack counts them (a non-ASCII character like "\u2014" counts as 6)`
|
|
21375
|
+
}
|
|
21376
|
+
).optional()
|
|
21357
21377
|
}).strict().refine((identity) => Object.keys(identity).length > 0, {
|
|
21358
21378
|
message: "Session identity requires at least one field"
|
|
21359
21379
|
});
|
package/dist/index.js
CHANGED
|
@@ -16989,6 +16989,20 @@ var init_trigger_router = __esm({
|
|
|
16989
16989
|
});
|
|
16990
16990
|
|
|
16991
16991
|
// ../../packages/schemas/src/sessions.ts
|
|
16992
|
+
function sessionIdentityDescriptionLength(value) {
|
|
16993
|
+
let length = 0;
|
|
16994
|
+
for (const char of value) {
|
|
16995
|
+
const codePoint = char.codePointAt(0) ?? 0;
|
|
16996
|
+
if (codePoint < 32 || codePoint > 126) {
|
|
16997
|
+
length += 6 * char.length;
|
|
16998
|
+
} else if (char === '"' || char === "\\" || char === "/") {
|
|
16999
|
+
length += 2;
|
|
17000
|
+
} else {
|
|
17001
|
+
length += 1;
|
|
17002
|
+
}
|
|
17003
|
+
}
|
|
17004
|
+
return length;
|
|
17005
|
+
}
|
|
16992
17006
|
function isAvatarAssetPathShapeValid(asset) {
|
|
16993
17007
|
const normalized = asset.trim().replaceAll("\\", "/");
|
|
16994
17008
|
if (normalized.length === 0) return false;
|
|
@@ -17122,7 +17136,7 @@ function isChatMessageEvent(trigger) {
|
|
|
17122
17136
|
function hasFilterValue(trigger, path, expected) {
|
|
17123
17137
|
return trigger.where?.[path] === expected;
|
|
17124
17138
|
}
|
|
17125
|
-
var RESOURCE_KIND_SESSION, TriggerFilterScalarSchema, TriggerFilterPathSchema, TriggerFilterClauseSchema, TriggerFilterSchema, SessionTriggerCheckTimeoutSchema, TriggerEventSchema, TriggerEventsSchema, SessionTriggerSharedFields, SessionTriggerEventSourceFields, SessionTriggerBaseSchema, SessionTriggerDefinitionBaseSchema, SessionTriggerSchema, SessionApplyTriggerSchema, SessionHeartbeatTriggerBaseSchema, SessionHeartbeatTriggerSchema, SessionApplyHeartbeatTriggerSchema, SessionTriggerDefinitionSchema, SessionApplyTriggerDefinitionSchema, SessionTriggersSchema, SessionApplyTriggersSchema, AVATAR_ASSET_EXTENSIONS, MAX_AVATAR_ASSET_BYTES, SHA256_HEX_PATTERN, SessionIdentitySchema, SessionSpecSchema, SessionApplySpecSchema, SessionStatusSchema, SessionResourceSchema, SessionApplyRequestSchema, SessionApplyTriggerReceiptSchema, SessionApplyResponseSchema, SESSION_TELEGRAM_IDENTITY_STATUSES, SessionTelegramIdentityStatusSchema, SessionPresenceIdentitySchema, SessionPresenceResponseSchema, SessionPresenceConnectRequestSchema, SessionPresenceConnectPendingSchema, SessionPresenceConnectResponseSchema, SessionPresenceIconRequestSchema, SessionPresenceIconResponseSchema, SessionPresenceCompleteResponseSchema;
|
|
17139
|
+
var RESOURCE_KIND_SESSION, TriggerFilterScalarSchema, TriggerFilterPathSchema, TriggerFilterClauseSchema, TriggerFilterSchema, SessionTriggerCheckTimeoutSchema, TriggerEventSchema, TriggerEventsSchema, SessionTriggerSharedFields, SessionTriggerEventSourceFields, SessionTriggerBaseSchema, SessionTriggerDefinitionBaseSchema, SessionTriggerSchema, SessionApplyTriggerSchema, SessionHeartbeatTriggerBaseSchema, SessionHeartbeatTriggerSchema, SessionApplyHeartbeatTriggerSchema, SessionTriggerDefinitionSchema, SessionApplyTriggerDefinitionSchema, SessionTriggersSchema, SessionApplyTriggersSchema, AVATAR_ASSET_EXTENSIONS, MAX_AVATAR_ASSET_BYTES, SESSION_IDENTITY_DESCRIPTION_MAX_LENGTH, SHA256_HEX_PATTERN, SessionIdentitySchema, SessionSpecSchema, SessionApplySpecSchema, SessionStatusSchema, SessionResourceSchema, SessionApplyRequestSchema, SessionApplyTriggerReceiptSchema, SessionApplyResponseSchema, SESSION_TELEGRAM_IDENTITY_STATUSES, SessionTelegramIdentityStatusSchema, SessionPresenceIdentitySchema, SessionPresenceResponseSchema, SessionPresenceConnectRequestSchema, SessionPresenceConnectPendingSchema, SessionPresenceConnectResponseSchema, SessionPresenceIconRequestSchema, SessionPresenceIconResponseSchema, SessionPresenceCompleteResponseSchema;
|
|
17126
17140
|
var init_sessions = __esm({
|
|
17127
17141
|
"../../packages/schemas/src/sessions.ts"() {
|
|
17128
17142
|
"use strict";
|
|
@@ -17299,6 +17313,7 @@ var init_sessions = __esm({
|
|
|
17299
17313
|
).transform(expandSessionApplyTriggerDefinitions).superRefine(validateAttributedRunsTriggerPairing);
|
|
17300
17314
|
AVATAR_ASSET_EXTENSIONS = [".png", ".jpg", ".jpeg"];
|
|
17301
17315
|
MAX_AVATAR_ASSET_BYTES = 2 * 1024 * 1024;
|
|
17316
|
+
SESSION_IDENTITY_DESCRIPTION_MAX_LENGTH = 140;
|
|
17302
17317
|
SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/;
|
|
17303
17318
|
SessionIdentitySchema = external_exports.object({
|
|
17304
17319
|
displayName: external_exports.string().trim().min(1).max(80).optional(),
|
|
@@ -17312,7 +17327,12 @@ var init_sessions = __esm({
|
|
|
17312
17327
|
// overwritten, so it is never trusted input.
|
|
17313
17328
|
sha256: external_exports.string().regex(SHA256_HEX_PATTERN).optional()
|
|
17314
17329
|
}).strict().optional(),
|
|
17315
|
-
description: external_exports.string().trim().min(1).
|
|
17330
|
+
description: external_exports.string().trim().min(1).refine(
|
|
17331
|
+
(value) => sessionIdentityDescriptionLength(value) <= SESSION_IDENTITY_DESCRIPTION_MAX_LENGTH,
|
|
17332
|
+
{
|
|
17333
|
+
message: `description must be at most ${SESSION_IDENTITY_DESCRIPTION_MAX_LENGTH} characters as Slack counts them (a non-ASCII character like "\u2014" counts as 6)`
|
|
17334
|
+
}
|
|
17335
|
+
).optional()
|
|
17316
17336
|
}).strict().refine((identity) => Object.keys(identity).length > 0, {
|
|
17317
17337
|
message: "Session identity requires at least one field"
|
|
17318
17338
|
});
|
|
@@ -18138,20 +18158,42 @@ var init_active_project = __esm({
|
|
|
18138
18158
|
});
|
|
18139
18159
|
|
|
18140
18160
|
// src/lib/config/path.ts
|
|
18161
|
+
import { createHash } from "crypto";
|
|
18141
18162
|
import { homedir } from "os";
|
|
18142
|
-
import { join } from "path";
|
|
18163
|
+
import { join, normalize } from "path";
|
|
18143
18164
|
function defaultConfigPath() {
|
|
18144
18165
|
return process.env.AUTO_CLI_CONFIG ?? join(homedir(), ".auto", "config.yaml");
|
|
18145
18166
|
}
|
|
18167
|
+
function profilesDir(configPath = defaultConfigPath()) {
|
|
18168
|
+
return normalize(join(configPath, "..", PROFILES_DIR_NAME));
|
|
18169
|
+
}
|
|
18170
|
+
function profileFileName(input) {
|
|
18171
|
+
const key = `${input.userEmail.toLowerCase()}
|
|
18172
|
+
${serverHost(input.serverUrl)}`;
|
|
18173
|
+
const hash2 = createHash("sha256").update(key).digest("hex").slice(0, 8);
|
|
18174
|
+
return `${slug(input.userEmail)}--${slug(serverHost(input.serverUrl))}-${hash2}.yaml`;
|
|
18175
|
+
}
|
|
18176
|
+
function serverHost(serverUrl) {
|
|
18177
|
+
try {
|
|
18178
|
+
return new URL(serverUrl).host;
|
|
18179
|
+
} catch {
|
|
18180
|
+
return serverUrl;
|
|
18181
|
+
}
|
|
18182
|
+
}
|
|
18183
|
+
function slug(value) {
|
|
18184
|
+
return value.toLowerCase().replace(/[^a-z0-9._-]+/g, "_");
|
|
18185
|
+
}
|
|
18186
|
+
var PROFILES_DIR_NAME;
|
|
18146
18187
|
var init_path = __esm({
|
|
18147
18188
|
"src/lib/config/path.ts"() {
|
|
18148
18189
|
"use strict";
|
|
18190
|
+
PROFILES_DIR_NAME = "profiles";
|
|
18149
18191
|
}
|
|
18150
18192
|
});
|
|
18151
18193
|
|
|
18152
18194
|
// src/lib/config/file.ts
|
|
18153
18195
|
import { chmodSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
18154
|
-
import { dirname as dirname2 } from "path";
|
|
18196
|
+
import { basename, dirname as dirname2, join as join2 } from "path";
|
|
18155
18197
|
function readConfig(path = defaultConfigPath()) {
|
|
18156
18198
|
try {
|
|
18157
18199
|
const text = readFileSync2(path, "utf8");
|
|
@@ -18159,21 +18201,8 @@ function readConfig(path = defaultConfigPath()) {
|
|
|
18159
18201
|
for (const line of text.split(/\r?\n/)) {
|
|
18160
18202
|
const match = /^([A-Za-z0-9_]+):\s*(.*)$/.exec(line.trim());
|
|
18161
18203
|
if (!match) continue;
|
|
18162
|
-
const
|
|
18163
|
-
if (match[
|
|
18164
|
-
if (match[1] === "organizationId") config2.organizationId = value;
|
|
18165
|
-
if (match[1] === "projectId") config2.projectId = value;
|
|
18166
|
-
if (match[1] === "refreshToken") config2.refreshToken = value;
|
|
18167
|
-
if (match[1] === "accessToken") config2.accessToken = value;
|
|
18168
|
-
if (match[1] === "accessTokenExpiresAt") {
|
|
18169
|
-
config2.accessTokenExpiresAt = value;
|
|
18170
|
-
}
|
|
18171
|
-
if (match[1] === "accessTokenOrganizationId") {
|
|
18172
|
-
config2.accessTokenOrganizationId = value;
|
|
18173
|
-
}
|
|
18174
|
-
if (match[1] === "accessTokenProjectId") {
|
|
18175
|
-
config2.accessTokenProjectId = value;
|
|
18176
|
-
}
|
|
18204
|
+
const key = CONFIG_KEYS.find((candidate) => candidate === match[1]);
|
|
18205
|
+
if (key) config2[key] = match[2] ?? "";
|
|
18177
18206
|
}
|
|
18178
18207
|
return config2;
|
|
18179
18208
|
} catch (err) {
|
|
@@ -18182,17 +18211,26 @@ function readConfig(path = defaultConfigPath()) {
|
|
|
18182
18211
|
}
|
|
18183
18212
|
}
|
|
18184
18213
|
function writeConfig(config2, path = defaultConfigPath()) {
|
|
18214
|
+
writeConfigFile(config2, path);
|
|
18215
|
+
if (config2.userEmail && config2.serverUrl && basename(dirname2(path)) !== PROFILES_DIR_NAME) {
|
|
18216
|
+
writeConfigFile(
|
|
18217
|
+
config2,
|
|
18218
|
+
join2(
|
|
18219
|
+
dirname2(path),
|
|
18220
|
+
PROFILES_DIR_NAME,
|
|
18221
|
+
profileFileName({
|
|
18222
|
+
userEmail: config2.userEmail,
|
|
18223
|
+
serverUrl: config2.serverUrl
|
|
18224
|
+
})
|
|
18225
|
+
)
|
|
18226
|
+
);
|
|
18227
|
+
}
|
|
18228
|
+
}
|
|
18229
|
+
function writeConfigFile(config2, path) {
|
|
18185
18230
|
mkdirSync2(dirname2(path), { recursive: true });
|
|
18186
|
-
const lines = [
|
|
18187
|
-
|
|
18188
|
-
|
|
18189
|
-
["projectId", config2.projectId],
|
|
18190
|
-
["refreshToken", config2.refreshToken],
|
|
18191
|
-
["accessToken", config2.accessToken],
|
|
18192
|
-
["accessTokenExpiresAt", config2.accessTokenExpiresAt],
|
|
18193
|
-
["accessTokenOrganizationId", config2.accessTokenOrganizationId],
|
|
18194
|
-
["accessTokenProjectId", config2.accessTokenProjectId]
|
|
18195
|
-
].filter(([, value]) => value).map(([key, value]) => `${key}: ${value}`);
|
|
18231
|
+
const lines = CONFIG_KEYS.filter((key) => config2[key]).map(
|
|
18232
|
+
(key) => `${key}: ${config2[key]}`
|
|
18233
|
+
);
|
|
18196
18234
|
writeFileSync2(path, `${lines.join("\n")}
|
|
18197
18235
|
`, {
|
|
18198
18236
|
encoding: "utf8",
|
|
@@ -18200,10 +18238,23 @@ function writeConfig(config2, path = defaultConfigPath()) {
|
|
|
18200
18238
|
});
|
|
18201
18239
|
chmodSync(path, 384);
|
|
18202
18240
|
}
|
|
18241
|
+
var CONFIG_KEYS;
|
|
18203
18242
|
var init_file = __esm({
|
|
18204
18243
|
"src/lib/config/file.ts"() {
|
|
18205
18244
|
"use strict";
|
|
18206
18245
|
init_path();
|
|
18246
|
+
CONFIG_KEYS = [
|
|
18247
|
+
"serverUrl",
|
|
18248
|
+
"userId",
|
|
18249
|
+
"userEmail",
|
|
18250
|
+
"organizationId",
|
|
18251
|
+
"projectId",
|
|
18252
|
+
"refreshToken",
|
|
18253
|
+
"accessToken",
|
|
18254
|
+
"accessTokenExpiresAt",
|
|
18255
|
+
"accessTokenOrganizationId",
|
|
18256
|
+
"accessTokenProjectId"
|
|
18257
|
+
];
|
|
18207
18258
|
}
|
|
18208
18259
|
});
|
|
18209
18260
|
|
|
@@ -20193,7 +20244,7 @@ var init_connect = __esm({
|
|
|
20193
20244
|
});
|
|
20194
20245
|
|
|
20195
20246
|
// src/commands/apply/files.ts
|
|
20196
|
-
import { createHash } from "crypto";
|
|
20247
|
+
import { createHash as createHash2 } from "crypto";
|
|
20197
20248
|
import {
|
|
20198
20249
|
readFileSync as readFileSync3,
|
|
20199
20250
|
readdirSync,
|
|
@@ -20201,11 +20252,11 @@ import {
|
|
|
20201
20252
|
statSync
|
|
20202
20253
|
} from "fs";
|
|
20203
20254
|
import {
|
|
20204
|
-
basename,
|
|
20255
|
+
basename as basename2,
|
|
20205
20256
|
dirname as dirname3,
|
|
20206
20257
|
extname,
|
|
20207
20258
|
isAbsolute,
|
|
20208
|
-
join as
|
|
20259
|
+
join as join3,
|
|
20209
20260
|
resolve
|
|
20210
20261
|
} from "path";
|
|
20211
20262
|
import { parseAllDocuments as parseYamlDocuments } from "yaml";
|
|
@@ -20221,7 +20272,7 @@ function readProjectApplyRequest(options) {
|
|
|
20221
20272
|
);
|
|
20222
20273
|
return { ...request, assets: assets2 };
|
|
20223
20274
|
}
|
|
20224
|
-
const directory = options.directory ??
|
|
20275
|
+
const directory = options.directory ?? join3(process.cwd(), ".auto");
|
|
20225
20276
|
const files = applyFiles(directory);
|
|
20226
20277
|
if (files.length === 0) {
|
|
20227
20278
|
throw new Error(`No resource files found in ${directory}`);
|
|
@@ -20284,7 +20335,7 @@ function applyFiles(root) {
|
|
|
20284
20335
|
const files = [];
|
|
20285
20336
|
for (const kind of APPLY_RESOURCE_ORDER) {
|
|
20286
20337
|
const directory = APPLY_DIRECTORIES[kind];
|
|
20287
|
-
const path =
|
|
20338
|
+
const path = join3(root, directory);
|
|
20288
20339
|
let entries;
|
|
20289
20340
|
try {
|
|
20290
20341
|
entries = readdirSync(path, { withFileTypes: true });
|
|
@@ -20358,7 +20409,7 @@ function readApplyAssets(resources, projectRoot) {
|
|
|
20358
20409
|
});
|
|
20359
20410
|
const bytes = readFileSync3(resolvedPath);
|
|
20360
20411
|
assets[avatarAsset] = {
|
|
20361
|
-
sha256:
|
|
20412
|
+
sha256: createHash2("sha256").update(bytes).digest("hex"),
|
|
20362
20413
|
contentType: extname(resolvedPath).toLowerCase() === ".png" ? "image/png" : "image/jpeg",
|
|
20363
20414
|
dataBase64: bytes.toString("base64")
|
|
20364
20415
|
};
|
|
@@ -20422,12 +20473,12 @@ function validateSessionAvatarAsset(input) {
|
|
|
20422
20473
|
}
|
|
20423
20474
|
function applyProjectRoot(directory) {
|
|
20424
20475
|
const resolved = resolve(directory);
|
|
20425
|
-
return
|
|
20476
|
+
return basename2(resolved) === ".auto" ? dirname3(resolved) : resolved;
|
|
20426
20477
|
}
|
|
20427
20478
|
function applyFileProjectRoot(file2) {
|
|
20428
20479
|
let dir = dirname3(resolve(file2));
|
|
20429
20480
|
while (true) {
|
|
20430
|
-
if (
|
|
20481
|
+
if (basename2(dir) === ".auto") {
|
|
20431
20482
|
return dirname3(dir);
|
|
20432
20483
|
}
|
|
20433
20484
|
const parent = dirname3(dir);
|
|
@@ -20464,7 +20515,7 @@ function isRecord(value) {
|
|
|
20464
20515
|
function resourceApplyFiles(directory, entries) {
|
|
20465
20516
|
const files = [];
|
|
20466
20517
|
for (const entry of entries) {
|
|
20467
|
-
const path =
|
|
20518
|
+
const path = join3(directory, entry.name);
|
|
20468
20519
|
if (entry.isDirectory()) {
|
|
20469
20520
|
files.push(
|
|
20470
20521
|
...resourceApplyFiles(path, readdirSync(path, { withFileTypes: true }))
|
|
@@ -20613,13 +20664,49 @@ var init_actions = __esm({
|
|
|
20613
20664
|
}
|
|
20614
20665
|
});
|
|
20615
20666
|
|
|
20667
|
+
// src/lib/config/profiles.ts
|
|
20668
|
+
import { readdirSync as readdirSync2 } from "fs";
|
|
20669
|
+
import { join as join4 } from "path";
|
|
20670
|
+
function listProfiles(configPath = defaultConfigPath()) {
|
|
20671
|
+
const dir = profilesDir(configPath);
|
|
20672
|
+
let entries;
|
|
20673
|
+
try {
|
|
20674
|
+
entries = readdirSync2(dir);
|
|
20675
|
+
} catch (err) {
|
|
20676
|
+
if (err.code === "ENOENT") return [];
|
|
20677
|
+
throw err;
|
|
20678
|
+
}
|
|
20679
|
+
return entries.filter((entry) => entry.endsWith(".yaml")).sort().map((entry) => {
|
|
20680
|
+
const path = join4(dir, entry);
|
|
20681
|
+
return { path, config: readConfig(path) };
|
|
20682
|
+
}).filter((profile) => profile.config.userEmail);
|
|
20683
|
+
}
|
|
20684
|
+
function findAccountProfile(input) {
|
|
20685
|
+
const candidates = listProfiles(input.configPath).map((profile) => profile.config).filter((config2) => config2.serverUrl === input.serverUrl);
|
|
20686
|
+
return candidates.find(
|
|
20687
|
+
(config2) => input.userId && config2.userId === input.userId
|
|
20688
|
+
) ?? // Email is only a fallback for when a user id is missing on either side;
|
|
20689
|
+
// it must never override a known user-id mismatch (emails can be
|
|
20690
|
+
// reassigned to a different user).
|
|
20691
|
+
candidates.find(
|
|
20692
|
+
(config2) => input.userEmail && config2.userEmail?.toLowerCase() === input.userEmail.toLowerCase() && !(input.userId && config2.userId && config2.userId !== input.userId)
|
|
20693
|
+
);
|
|
20694
|
+
}
|
|
20695
|
+
var init_profiles2 = __esm({
|
|
20696
|
+
"src/lib/config/profiles.ts"() {
|
|
20697
|
+
"use strict";
|
|
20698
|
+
init_file();
|
|
20699
|
+
init_path();
|
|
20700
|
+
}
|
|
20701
|
+
});
|
|
20702
|
+
|
|
20616
20703
|
// src/commands/auth/pkce.ts
|
|
20617
|
-
import { createHash as
|
|
20704
|
+
import { createHash as createHash3, randomBytes as randomBytes2 } from "crypto";
|
|
20618
20705
|
function pkceVerifier() {
|
|
20619
20706
|
return randomBytes2(32).toString("base64url");
|
|
20620
20707
|
}
|
|
20621
20708
|
function pkceChallenge(verifier) {
|
|
20622
|
-
return
|
|
20709
|
+
return createHash3("sha256").update(verifier).digest("base64url");
|
|
20623
20710
|
}
|
|
20624
20711
|
var init_pkce = __esm({
|
|
20625
20712
|
"src/commands/auth/pkce.ts"() {
|
|
@@ -20630,7 +20717,6 @@ var init_pkce = __esm({
|
|
|
20630
20717
|
// src/commands/auth/login.ts
|
|
20631
20718
|
async function login(input) {
|
|
20632
20719
|
const serverUrl = resolveApiBaseUrl({ explicit: input.options.apiUrl });
|
|
20633
|
-
const previous = readConfig(input.configPath);
|
|
20634
20720
|
if (input.options.device) {
|
|
20635
20721
|
const device = await postJson(
|
|
20636
20722
|
input.fetch,
|
|
@@ -20648,194 +20734,158 @@ async function login(input) {
|
|
|
20648
20734
|
await sleep(Math.max(0, device.interval) * 1e3);
|
|
20649
20735
|
}
|
|
20650
20736
|
firstAttempt = false;
|
|
20737
|
+
let token3;
|
|
20651
20738
|
try {
|
|
20652
|
-
|
|
20739
|
+
token3 = await postJson(
|
|
20653
20740
|
input.fetch,
|
|
20654
20741
|
`${serverUrl}/api/v1/auth/cli/token`,
|
|
20655
20742
|
{
|
|
20656
20743
|
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
20657
|
-
device_code: device.device_code
|
|
20658
|
-
...previous.organizationId && previous.projectId ? {
|
|
20659
|
-
organization_id: previous.organizationId,
|
|
20660
|
-
project_id: previous.projectId
|
|
20661
|
-
} : {}
|
|
20744
|
+
device_code: device.device_code
|
|
20662
20745
|
}
|
|
20663
20746
|
);
|
|
20664
|
-
writeConfig(
|
|
20665
|
-
{
|
|
20666
|
-
...previous,
|
|
20667
|
-
serverUrl,
|
|
20668
|
-
refreshToken: token2.refresh_token,
|
|
20669
|
-
accessToken: token2.access_token,
|
|
20670
|
-
accessTokenExpiresAt: token2.access_token ? accessTokenExpiresAt(token2) : void 0,
|
|
20671
|
-
accessTokenOrganizationId: token2.access_token ? previous.organizationId : void 0,
|
|
20672
|
-
accessTokenProjectId: token2.access_token ? previous.projectId : void 0
|
|
20673
|
-
},
|
|
20674
|
-
input.configPath
|
|
20675
|
-
);
|
|
20676
|
-
input.writeOutput("Logged in.");
|
|
20677
|
-
return;
|
|
20678
20747
|
} catch (error51) {
|
|
20679
20748
|
if (error51 instanceof Error && error51.message === "authorization_pending") {
|
|
20680
20749
|
continue;
|
|
20681
20750
|
}
|
|
20682
20751
|
throw error51;
|
|
20683
20752
|
}
|
|
20753
|
+
await finishLogin({
|
|
20754
|
+
token: token3,
|
|
20755
|
+
serverUrl,
|
|
20756
|
+
fetch: input.fetch,
|
|
20757
|
+
configPath: input.configPath,
|
|
20758
|
+
writeOutput: input.writeOutput
|
|
20759
|
+
});
|
|
20760
|
+
return;
|
|
20684
20761
|
}
|
|
20685
20762
|
throw new Error("Device authorization expired before approval.");
|
|
20686
20763
|
}
|
|
20687
20764
|
const verifier = input.options.verifier ?? pkceVerifier();
|
|
20688
20765
|
if (!input.options.code) {
|
|
20689
|
-
const selectionDetails = await resolveLoginSelectionDetails({
|
|
20690
|
-
configPath: input.configPath,
|
|
20691
|
-
env: input.env ?? process.env,
|
|
20692
|
-
fetch: input.fetch,
|
|
20693
|
-
serverUrl,
|
|
20694
|
-
previous,
|
|
20695
|
-
writeError: input.writeError ?? (() => {
|
|
20696
|
-
})
|
|
20697
|
-
});
|
|
20698
20766
|
const callback = await createOAuthLoopbackCallback({
|
|
20699
|
-
successHtml: (
|
|
20767
|
+
successHtml: () => renderOAuthLoopbackPage({
|
|
20700
20768
|
status: "success",
|
|
20701
20769
|
eyebrow: "Auto CLI",
|
|
20702
20770
|
title: "Login authorized",
|
|
20703
20771
|
message: "Auto received the browser authorization. The CLI will finish signing you in from your terminal.",
|
|
20704
|
-
details: [
|
|
20705
|
-
{ label: "Server", value: serverUrl },
|
|
20706
|
-
{
|
|
20707
|
-
label: "Organization",
|
|
20708
|
-
value: result.organizationName ?? selectionDetails.organization
|
|
20709
|
-
},
|
|
20710
|
-
{
|
|
20711
|
-
label: "Project",
|
|
20712
|
-
value: result.projectName ?? selectionDetails.project
|
|
20713
|
-
}
|
|
20714
|
-
]
|
|
20772
|
+
details: [{ label: "Server", value: serverUrl }]
|
|
20715
20773
|
}),
|
|
20716
20774
|
failureHtml: () => renderOAuthLoopbackPage({
|
|
20717
20775
|
status: "failure",
|
|
20718
20776
|
eyebrow: "Auto CLI",
|
|
20719
20777
|
title: "Login failed",
|
|
20720
20778
|
message: "The browser authorization did not complete. Return to your terminal to retry or inspect the error.",
|
|
20721
|
-
details: [
|
|
20722
|
-
{ label: "Server", value: serverUrl },
|
|
20723
|
-
{ label: "Organization", value: selectionDetails.organization },
|
|
20724
|
-
{ label: "Project", value: selectionDetails.project }
|
|
20725
|
-
]
|
|
20779
|
+
details: [{ label: "Server", value: serverUrl }]
|
|
20726
20780
|
})
|
|
20727
20781
|
});
|
|
20728
20782
|
try {
|
|
20729
20783
|
const authorizeUrl = new URL("/auth/cli", serverUrl);
|
|
20730
20784
|
authorizeUrl.searchParams.set("pkce_challenge", pkceChallenge(verifier));
|
|
20731
20785
|
authorizeUrl.searchParams.set("redirect_uri", callback.redirectUri);
|
|
20732
|
-
if (previous.organizationId && previous.projectId) {
|
|
20733
|
-
authorizeUrl.searchParams.set(
|
|
20734
|
-
"organization_id",
|
|
20735
|
-
previous.organizationId
|
|
20736
|
-
);
|
|
20737
|
-
authorizeUrl.searchParams.set("project_id", previous.projectId);
|
|
20738
|
-
}
|
|
20739
20786
|
input.writeOutput(`Opening ${authorizeUrl.toString()}`);
|
|
20740
20787
|
input.writeOutput("Waiting for browser authorization...");
|
|
20741
20788
|
openBrowser(authorizeUrl.toString());
|
|
20742
20789
|
const { code } = await callback.result;
|
|
20743
|
-
await
|
|
20790
|
+
const token3 = await exchangeAuthorizationCode({
|
|
20744
20791
|
code,
|
|
20745
|
-
configPath: input.configPath,
|
|
20746
20792
|
fetch: input.fetch,
|
|
20747
|
-
previous,
|
|
20748
20793
|
redirectUri: callback.redirectUri,
|
|
20749
20794
|
serverUrl,
|
|
20750
20795
|
verifier
|
|
20751
20796
|
});
|
|
20752
|
-
|
|
20797
|
+
await finishLogin({
|
|
20798
|
+
token: token3,
|
|
20799
|
+
serverUrl,
|
|
20800
|
+
fetch: input.fetch,
|
|
20801
|
+
configPath: input.configPath,
|
|
20802
|
+
writeOutput: input.writeOutput
|
|
20803
|
+
});
|
|
20753
20804
|
return;
|
|
20754
20805
|
} finally {
|
|
20755
20806
|
callback.close();
|
|
20756
20807
|
}
|
|
20757
20808
|
}
|
|
20758
|
-
await
|
|
20809
|
+
const token2 = await exchangeAuthorizationCode({
|
|
20759
20810
|
code: input.options.code,
|
|
20760
|
-
configPath: input.configPath,
|
|
20761
20811
|
fetch: input.fetch,
|
|
20762
|
-
previous,
|
|
20763
20812
|
redirectUri: "http://127.0.0.1/callback",
|
|
20764
20813
|
serverUrl,
|
|
20765
20814
|
verifier
|
|
20766
20815
|
});
|
|
20767
|
-
|
|
20816
|
+
await finishLogin({
|
|
20817
|
+
token: token2,
|
|
20818
|
+
serverUrl,
|
|
20819
|
+
fetch: input.fetch,
|
|
20820
|
+
configPath: input.configPath,
|
|
20821
|
+
writeOutput: input.writeOutput
|
|
20822
|
+
});
|
|
20768
20823
|
}
|
|
20769
|
-
async function
|
|
20770
|
-
|
|
20824
|
+
async function exchangeAuthorizationCode(input) {
|
|
20825
|
+
return postJson(
|
|
20771
20826
|
input.fetch,
|
|
20772
20827
|
`${input.serverUrl}/api/v1/auth/cli/token`,
|
|
20773
20828
|
{
|
|
20774
20829
|
grant_type: "authorization_code",
|
|
20775
20830
|
code: input.code,
|
|
20776
20831
|
code_verifier: input.verifier,
|
|
20777
|
-
redirect_uri: input.redirectUri
|
|
20778
|
-
...input.previous.organizationId && input.previous.projectId ? {
|
|
20779
|
-
organization_id: input.previous.organizationId,
|
|
20780
|
-
project_id: input.previous.projectId
|
|
20781
|
-
} : {}
|
|
20832
|
+
redirect_uri: input.redirectUri
|
|
20782
20833
|
}
|
|
20783
20834
|
);
|
|
20784
|
-
writeConfig(
|
|
20785
|
-
{
|
|
20786
|
-
...input.previous,
|
|
20787
|
-
serverUrl: input.serverUrl,
|
|
20788
|
-
refreshToken: token2.refresh_token,
|
|
20789
|
-
accessToken: token2.access_token,
|
|
20790
|
-
accessTokenExpiresAt: token2.access_token ? accessTokenExpiresAt(token2) : void 0,
|
|
20791
|
-
accessTokenOrganizationId: token2.access_token ? input.previous.organizationId : void 0,
|
|
20792
|
-
accessTokenProjectId: token2.access_token ? input.previous.projectId : void 0
|
|
20793
|
-
},
|
|
20794
|
-
input.configPath
|
|
20795
|
-
);
|
|
20796
20835
|
}
|
|
20797
|
-
async function
|
|
20798
|
-
const
|
|
20799
|
-
|
|
20800
|
-
|
|
20801
|
-
};
|
|
20802
|
-
if (!input.previous.organizationId) {
|
|
20803
|
-
return fallback;
|
|
20804
|
-
}
|
|
20805
|
-
const client = createApiClient({
|
|
20836
|
+
async function finishLogin(input) {
|
|
20837
|
+
const { token: token2, serverUrl } = input;
|
|
20838
|
+
const previous = readConfig(input.configPath);
|
|
20839
|
+
const profile = token2.user ? findAccountProfile({
|
|
20806
20840
|
configPath: input.configPath,
|
|
20807
|
-
|
|
20808
|
-
|
|
20809
|
-
|
|
20810
|
-
});
|
|
20811
|
-
|
|
20812
|
-
|
|
20813
|
-
|
|
20814
|
-
|
|
20815
|
-
|
|
20816
|
-
|
|
20817
|
-
|
|
20841
|
+
serverUrl,
|
|
20842
|
+
userId: token2.user.id,
|
|
20843
|
+
userEmail: token2.user.email
|
|
20844
|
+
}) : void 0;
|
|
20845
|
+
const selectionSource = profile ?? previous;
|
|
20846
|
+
const selection = selectionSource.organizationId && selectionSource.projectId ? {
|
|
20847
|
+
organizationId: selectionSource.organizationId,
|
|
20848
|
+
projectId: selectionSource.projectId
|
|
20849
|
+
} : void 0;
|
|
20850
|
+
let config2 = {
|
|
20851
|
+
serverUrl,
|
|
20852
|
+
userId: token2.user?.id,
|
|
20853
|
+
userEmail: token2.user?.email,
|
|
20854
|
+
refreshToken: token2.refresh_token,
|
|
20855
|
+
accessToken: token2.access_token,
|
|
20856
|
+
accessTokenExpiresAt: token2.access_token ? accessTokenExpiresAt(token2) : void 0
|
|
20857
|
+
};
|
|
20858
|
+
if (selection) {
|
|
20859
|
+
try {
|
|
20860
|
+
const scoped = await postJson(
|
|
20861
|
+
input.fetch,
|
|
20862
|
+
`${serverUrl}/api/v1/auth/cli/token`,
|
|
20863
|
+
{
|
|
20864
|
+
grant_type: "refresh_token",
|
|
20865
|
+
refresh_token: token2.refresh_token,
|
|
20866
|
+
organization_id: selection.organizationId,
|
|
20867
|
+
project_id: selection.projectId
|
|
20868
|
+
}
|
|
20869
|
+
);
|
|
20870
|
+
config2 = {
|
|
20871
|
+
...config2,
|
|
20872
|
+
...selection,
|
|
20873
|
+
refreshToken: scoped.refresh_token,
|
|
20874
|
+
accessToken: scoped.access_token,
|
|
20875
|
+
accessTokenExpiresAt: scoped.access_token ? accessTokenExpiresAt(scoped) : void 0,
|
|
20876
|
+
accessTokenOrganizationId: scoped.access_token ? selection.organizationId : void 0,
|
|
20877
|
+
accessTokenProjectId: scoped.access_token ? selection.projectId : void 0
|
|
20878
|
+
};
|
|
20879
|
+
} catch {
|
|
20880
|
+
input.writeOutput(
|
|
20881
|
+
"The saved organization/project selection is not available for this account; run `auto orgs list` to pick a new one."
|
|
20818
20882
|
);
|
|
20819
|
-
if (project) {
|
|
20820
|
-
return {
|
|
20821
|
-
organization: project.organizationName,
|
|
20822
|
-
project: project.projectName
|
|
20823
|
-
};
|
|
20824
|
-
}
|
|
20825
20883
|
}
|
|
20826
|
-
const organizations = await client.listOrganizations({
|
|
20827
|
-
apiBaseUrl: input.serverUrl
|
|
20828
|
-
});
|
|
20829
|
-
const organization = organizations.organizations.find(
|
|
20830
|
-
(candidate) => candidate.organizationId === input.previous.organizationId
|
|
20831
|
-
);
|
|
20832
|
-
return {
|
|
20833
|
-
organization: organization?.organizationName ?? fallback.organization,
|
|
20834
|
-
project: fallback.project
|
|
20835
|
-
};
|
|
20836
|
-
} catch {
|
|
20837
|
-
return fallback;
|
|
20838
20884
|
}
|
|
20885
|
+
writeConfig(config2, input.configPath);
|
|
20886
|
+
input.writeOutput(
|
|
20887
|
+
token2.user ? `Logged in as ${token2.user.email}.` : "Logged in."
|
|
20888
|
+
);
|
|
20839
20889
|
}
|
|
20840
20890
|
async function sleep(ms) {
|
|
20841
20891
|
await new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
@@ -20844,11 +20894,11 @@ var init_login = __esm({
|
|
|
20844
20894
|
"src/commands/auth/login.ts"() {
|
|
20845
20895
|
"use strict";
|
|
20846
20896
|
init_base_url();
|
|
20847
|
-
init_client();
|
|
20848
20897
|
init_http();
|
|
20849
20898
|
init_tokens();
|
|
20850
20899
|
init_browser();
|
|
20851
20900
|
init_file();
|
|
20901
|
+
init_profiles2();
|
|
20852
20902
|
init_loopback();
|
|
20853
20903
|
init_pkce();
|
|
20854
20904
|
}
|
|
@@ -20858,7 +20908,7 @@ var init_login = __esm({
|
|
|
20858
20908
|
import { spawn as spawn2 } from "child_process";
|
|
20859
20909
|
import { mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
20860
20910
|
import { tmpdir } from "os";
|
|
20861
|
-
import { join as
|
|
20911
|
+
import { join as join5 } from "path";
|
|
20862
20912
|
import { parseAllDocuments as parseYamlDocuments2, stringify as stringify2 } from "yaml";
|
|
20863
20913
|
async function editResource(input) {
|
|
20864
20914
|
const reference = parseEditableResource(input.resource);
|
|
@@ -20873,8 +20923,8 @@ async function editResource(input) {
|
|
|
20873
20923
|
const document = editableResourceDocument(reference.kind, current);
|
|
20874
20924
|
const source = `${stringify2(document).trimEnd()}
|
|
20875
20925
|
`;
|
|
20876
|
-
const tempRoot = mkdtempSync(
|
|
20877
|
-
const filePath =
|
|
20926
|
+
const tempRoot = mkdtempSync(join5(tmpdir(), "auto-edit-"));
|
|
20927
|
+
const filePath = join5(tempRoot, `${reference.kind}-${reference.name}.yaml`);
|
|
20878
20928
|
writeFileSync3(filePath, source, "utf8");
|
|
20879
20929
|
let removeTempFile = false;
|
|
20880
20930
|
try {
|
|
@@ -21133,7 +21183,7 @@ var init_package = __esm({
|
|
|
21133
21183
|
"package.json"() {
|
|
21134
21184
|
package_default = {
|
|
21135
21185
|
name: "@autohq/cli",
|
|
21136
|
-
version: "0.1.
|
|
21186
|
+
version: "0.1.88",
|
|
21137
21187
|
license: "SEE LICENSE IN README.md",
|
|
21138
21188
|
publishConfig: {
|
|
21139
21189
|
access: "public"
|
|
@@ -27986,6 +28036,7 @@ init_login();
|
|
|
27986
28036
|
|
|
27987
28037
|
// src/commands/auth/profile.ts
|
|
27988
28038
|
init_file();
|
|
28039
|
+
init_profiles2();
|
|
27989
28040
|
async function handleAuthStatus(context) {
|
|
27990
28041
|
const result = await fetchAuthStatus(context);
|
|
27991
28042
|
context.io.writeResult(result, formatAuthStatusText);
|
|
@@ -28010,12 +28061,58 @@ function logout(context) {
|
|
|
28010
28061
|
);
|
|
28011
28062
|
context.writeOutput("Logged out.");
|
|
28012
28063
|
}
|
|
28064
|
+
function switchAccount(context, accountEmail, options = {}) {
|
|
28065
|
+
const profiles = listProfiles(context.configPath);
|
|
28066
|
+
if (profiles.length === 0) {
|
|
28067
|
+
throw new Error("No stored accounts. Run `auto auth login` first.");
|
|
28068
|
+
}
|
|
28069
|
+
const active = readConfig(context.configPath);
|
|
28070
|
+
if (!accountEmail) {
|
|
28071
|
+
for (const profile of profiles) {
|
|
28072
|
+
context.writeOutput(accountLine(profile.config, active));
|
|
28073
|
+
}
|
|
28074
|
+
return;
|
|
28075
|
+
}
|
|
28076
|
+
const matches = profiles.map((profile) => profile.config).filter(
|
|
28077
|
+
(config2) => config2.userEmail?.toLowerCase() === accountEmail.toLowerCase() && (!options.server || config2.serverUrl === options.server)
|
|
28078
|
+
);
|
|
28079
|
+
if (matches.length === 0) {
|
|
28080
|
+
throw new Error(
|
|
28081
|
+
`No stored account for ${accountEmail}. Run \`auto auth login\` to add it.`
|
|
28082
|
+
);
|
|
28083
|
+
}
|
|
28084
|
+
const match = matches.length === 1 ? matches[0] : matches.find((config2) => config2.serverUrl === active.serverUrl);
|
|
28085
|
+
if (!match) {
|
|
28086
|
+
throw new Error(
|
|
28087
|
+
`Multiple servers have a stored account for ${accountEmail}: ${matches.map((config2) => config2.serverUrl).join(
|
|
28088
|
+
", "
|
|
28089
|
+
)}. Pick one with \`auto auth switch ${accountEmail} --server <url>\`.`
|
|
28090
|
+
);
|
|
28091
|
+
}
|
|
28092
|
+
writeConfig(match, context.configPath);
|
|
28093
|
+
context.writeOutput(`Switched to ${match.userEmail} (${match.serverUrl}).`);
|
|
28094
|
+
if (!match.refreshToken) {
|
|
28095
|
+
context.writeOutput(
|
|
28096
|
+
"This account has no stored credentials; run `auto auth login`."
|
|
28097
|
+
);
|
|
28098
|
+
}
|
|
28099
|
+
}
|
|
28100
|
+
function accountLine(config2, active) {
|
|
28101
|
+
const isActive = Boolean(config2.userEmail) && config2.userEmail === active.userEmail && config2.serverUrl === active.serverUrl;
|
|
28102
|
+
return [
|
|
28103
|
+
config2.userEmail,
|
|
28104
|
+
`server=${config2.serverUrl ?? "(unset)"}`,
|
|
28105
|
+
config2.refreshToken ? void 0 : "logged_out",
|
|
28106
|
+
isActive ? "(active)" : void 0
|
|
28107
|
+
].filter(Boolean).join(" ");
|
|
28108
|
+
}
|
|
28013
28109
|
async function fetchAuthStatus(context) {
|
|
28014
28110
|
const config2 = readConfig(context.configPath);
|
|
28015
28111
|
const client = createContextApiClient(context);
|
|
28016
28112
|
const operator = client.getOperatorInfo();
|
|
28017
28113
|
const base = {
|
|
28018
28114
|
serverUrl: config2.serverUrl ?? context.env.AUTO_API_BASE_URL ?? null,
|
|
28115
|
+
account: config2.userEmail ?? null,
|
|
28019
28116
|
organizationId: config2.organizationId ?? null,
|
|
28020
28117
|
projectId: config2.projectId ?? null,
|
|
28021
28118
|
authSource: operator.authType
|
|
@@ -28057,6 +28154,9 @@ async function fetchAuthStatus(context) {
|
|
|
28057
28154
|
}
|
|
28058
28155
|
function formatAuthStatusText(result, writeLine) {
|
|
28059
28156
|
writeLine(`server: ${result.serverUrl ?? "(unset)"}`);
|
|
28157
|
+
if (result.account) {
|
|
28158
|
+
writeLine(`account: ${result.account}`);
|
|
28159
|
+
}
|
|
28060
28160
|
writeLine(`organization: ${result.organizationId ?? "(unset)"}`);
|
|
28061
28161
|
writeLine(`project: ${result.projectId ?? "(unset)"}`);
|
|
28062
28162
|
writeLine(
|
|
@@ -28169,6 +28269,11 @@ function registerAuthCommands(program, context) {
|
|
|
28169
28269
|
await handleWhoami(context);
|
|
28170
28270
|
});
|
|
28171
28271
|
auth.command("logout").description("Remove the local user refresh token.").action(() => logout(context));
|
|
28272
|
+
auth.command("switch").description(
|
|
28273
|
+
"Switch the active account to a stored profile, or list stored accounts."
|
|
28274
|
+
).argument("[email]", "Email of a stored account").option("--server <url>", "Auto web server URL of the stored account").action(
|
|
28275
|
+
(email3, options) => switchAccount(context, email3, options)
|
|
28276
|
+
);
|
|
28172
28277
|
}
|
|
28173
28278
|
|
|
28174
28279
|
// src/lib/stdio/readline.ts
|
|
@@ -30725,7 +30830,7 @@ init_resources2();
|
|
|
30725
30830
|
init_browser();
|
|
30726
30831
|
import { existsSync as existsSync2, mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
30727
30832
|
import { homedir as homedir2, tmpdir as tmpdir2 } from "os";
|
|
30728
|
-
import { join as
|
|
30833
|
+
import { join as join6 } from "path";
|
|
30729
30834
|
var POLL_INTERVAL_MS = 2e3;
|
|
30730
30835
|
var POLL_TIMEOUT_MS = 5 * 6e4;
|
|
30731
30836
|
var SLACK_APPS_URL = "https://api.slack.com/apps";
|
|
@@ -30886,7 +30991,7 @@ async function promptForIconUploads(input, options) {
|
|
|
30886
30991
|
}
|
|
30887
30992
|
}
|
|
30888
30993
|
function stagedLocationLabel(stagedPath) {
|
|
30889
|
-
return stagedPath.startsWith(`${
|
|
30994
|
+
return stagedPath.startsWith(`${join6(homedir2(), "Downloads")}/`) ? "Downloads" : "the printed path";
|
|
30890
30995
|
}
|
|
30891
30996
|
async function stageAvatarImage(input) {
|
|
30892
30997
|
try {
|
|
@@ -30898,9 +31003,9 @@ async function stageAvatarImage(input) {
|
|
|
30898
31003
|
}
|
|
30899
31004
|
const contentType = response.headers.get("content-type") ?? "";
|
|
30900
31005
|
const extension = contentType.includes("jpeg") ? ".jpg" : ".png";
|
|
30901
|
-
const downloads =
|
|
30902
|
-
const directory = existsSync2(downloads) ? downloads : mkdtempSync2(
|
|
30903
|
-
const path =
|
|
31006
|
+
const downloads = join6(homedir2(), "Downloads");
|
|
31007
|
+
const directory = existsSync2(downloads) ? downloads : mkdtempSync2(join6(tmpdir2(), "auto-avatar-"));
|
|
31008
|
+
const path = join6(directory, `${input.session}-avatar${extension}`);
|
|
30904
31009
|
writeFileSync4(path, Buffer.from(await response.arrayBuffer()));
|
|
30905
31010
|
return path;
|
|
30906
31011
|
} catch {
|