sim 2.1.13 → 2.1.14-preview.117.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -4
- package/dist/index.js +1054 -402
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -6946,35 +6946,588 @@ var {
|
|
|
6946
6946
|
safeDump
|
|
6947
6947
|
} = yaml;
|
|
6948
6948
|
|
|
6949
|
+
// src/update/install.ts
|
|
6950
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
6951
|
+
import { readFileSync as readFileSync2, realpathSync } from "node:fs";
|
|
6952
|
+
import { homedir as homedir2 } from "node:os";
|
|
6953
|
+
import { dirname as dirname2, isAbsolute, join as join2 } from "node:path";
|
|
6954
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
6955
|
+
|
|
6956
|
+
// ../utils/src/errors.ts
|
|
6957
|
+
function getErrorMessage(value, fallback) {
|
|
6958
|
+
if (value instanceof Error)
|
|
6959
|
+
return value.message;
|
|
6960
|
+
if (typeof value === "string" && value.length > 0)
|
|
6961
|
+
return value;
|
|
6962
|
+
return fallback ?? String(value);
|
|
6963
|
+
}
|
|
6964
|
+
|
|
6965
|
+
// ../utils/src/object.ts
|
|
6966
|
+
function omit(obj, keys) {
|
|
6967
|
+
const result = { ...obj };
|
|
6968
|
+
for (const key of keys) {
|
|
6969
|
+
delete result[key];
|
|
6970
|
+
}
|
|
6971
|
+
return result;
|
|
6972
|
+
}
|
|
6973
|
+
|
|
6974
|
+
// src/update/install.ts
|
|
6975
|
+
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
6976
|
+
|
|
6977
|
+
// src/update/check.ts
|
|
6978
|
+
import { spawn } from "node:child_process";
|
|
6979
|
+
import { fileURLToPath } from "node:url";
|
|
6980
|
+
|
|
6981
|
+
// src/config/json-file.ts
|
|
6982
|
+
import {
|
|
6983
|
+
closeSync,
|
|
6984
|
+
constants,
|
|
6985
|
+
fstatSync,
|
|
6986
|
+
lstatSync,
|
|
6987
|
+
mkdirSync,
|
|
6988
|
+
openSync,
|
|
6989
|
+
readSync,
|
|
6990
|
+
renameSync,
|
|
6991
|
+
unlinkSync,
|
|
6992
|
+
writeFileSync
|
|
6993
|
+
} from "node:fs";
|
|
6994
|
+
import { dirname } from "node:path";
|
|
6995
|
+
var writeSequence = 0;
|
|
6996
|
+
function readJsonFile(path, maxBytes) {
|
|
6997
|
+
let descriptor = null;
|
|
6998
|
+
try {
|
|
6999
|
+
if (!lstatSync(path).isFile())
|
|
7000
|
+
return null;
|
|
7001
|
+
descriptor = openSync(path, constants.O_RDONLY | constants.O_NONBLOCK | constants.O_NOFOLLOW);
|
|
7002
|
+
const stats = fstatSync(descriptor);
|
|
7003
|
+
if (!stats.isFile() || stats.size > maxBytes)
|
|
7004
|
+
return null;
|
|
7005
|
+
const buffer = Buffer.allocUnsafe(maxBytes + 1);
|
|
7006
|
+
let bytesRead = 0;
|
|
7007
|
+
while (bytesRead < buffer.byteLength) {
|
|
7008
|
+
const count = readSync(descriptor, buffer, bytesRead, buffer.byteLength - bytesRead, bytesRead);
|
|
7009
|
+
if (count === 0)
|
|
7010
|
+
break;
|
|
7011
|
+
bytesRead += count;
|
|
7012
|
+
}
|
|
7013
|
+
if (bytesRead > maxBytes)
|
|
7014
|
+
return null;
|
|
7015
|
+
return JSON.parse(buffer.subarray(0, bytesRead).toString("utf8"));
|
|
7016
|
+
} catch {
|
|
7017
|
+
return null;
|
|
7018
|
+
} finally {
|
|
7019
|
+
if (descriptor !== null) {
|
|
7020
|
+
try {
|
|
7021
|
+
closeSync(descriptor);
|
|
7022
|
+
} catch {}
|
|
7023
|
+
}
|
|
7024
|
+
}
|
|
7025
|
+
}
|
|
7026
|
+
function writeJsonFile(path, value, mode = 420) {
|
|
7027
|
+
let descriptor = null;
|
|
7028
|
+
let temporaryCreated = false;
|
|
7029
|
+
const temporaryPath = `${path}.${process.pid}.${Date.now()}.${writeSequence++}.tmp`;
|
|
7030
|
+
try {
|
|
7031
|
+
mkdirSync(dirname(path), { recursive: true, mode: 448 });
|
|
7032
|
+
descriptor = openSync(temporaryPath, "wx", mode);
|
|
7033
|
+
temporaryCreated = true;
|
|
7034
|
+
writeFileSync(descriptor, `${JSON.stringify(value, null, 2)}
|
|
7035
|
+
`);
|
|
7036
|
+
closeSync(descriptor);
|
|
7037
|
+
descriptor = null;
|
|
7038
|
+
renameSync(temporaryPath, path);
|
|
7039
|
+
temporaryCreated = false;
|
|
7040
|
+
} catch {} finally {
|
|
7041
|
+
if (descriptor !== null) {
|
|
7042
|
+
try {
|
|
7043
|
+
closeSync(descriptor);
|
|
7044
|
+
} catch {}
|
|
7045
|
+
}
|
|
7046
|
+
if (temporaryCreated) {
|
|
7047
|
+
try {
|
|
7048
|
+
unlinkSync(temporaryPath);
|
|
7049
|
+
} catch {}
|
|
7050
|
+
}
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
7053
|
+
|
|
6949
7054
|
// src/config/paths.ts
|
|
6950
7055
|
import { homedir } from "node:os";
|
|
6951
7056
|
import { join } from "node:path";
|
|
6952
7057
|
function configDir() {
|
|
6953
7058
|
return process.env.SIM_CONFIG_DIR || join(homedir(), ".sim");
|
|
6954
7059
|
}
|
|
6955
|
-
function configPath() {
|
|
6956
|
-
return process.env.SIM_CONFIG_FILE || join(configDir(), "config");
|
|
7060
|
+
function configPath() {
|
|
7061
|
+
return process.env.SIM_CONFIG_FILE || join(configDir(), "config");
|
|
7062
|
+
}
|
|
7063
|
+
function credentialsPath() {
|
|
7064
|
+
return process.env.SIM_CREDENTIALS_FILE || join(configDir(), "credentials");
|
|
7065
|
+
}
|
|
7066
|
+
function updateCachePath() {
|
|
7067
|
+
return join(configDir(), "update-check.json");
|
|
7068
|
+
}
|
|
7069
|
+
function telemetryStatePath() {
|
|
7070
|
+
return join(configDir(), "telemetry.json");
|
|
7071
|
+
}
|
|
7072
|
+
|
|
7073
|
+
// src/environment.ts
|
|
7074
|
+
var CI_VARIABLES = [
|
|
7075
|
+
"CI",
|
|
7076
|
+
"GITHUB_ACTIONS",
|
|
7077
|
+
"JENKINS_URL",
|
|
7078
|
+
"TEAMCITY_VERSION",
|
|
7079
|
+
"BUILDKITE"
|
|
7080
|
+
];
|
|
7081
|
+
function isEnabled(value) {
|
|
7082
|
+
if (value === undefined)
|
|
7083
|
+
return false;
|
|
7084
|
+
const normalized = value.trim().toLowerCase();
|
|
7085
|
+
return normalized !== "" && normalized !== "0" && normalized !== "false";
|
|
7086
|
+
}
|
|
7087
|
+
function isCi(env = process.env) {
|
|
7088
|
+
return CI_VARIABLES.some((variable) => isEnabled(env[variable]));
|
|
7089
|
+
}
|
|
7090
|
+
function proxyExecArgv() {
|
|
7091
|
+
return process.execArgv.filter((argument) => argument === "--use-env-proxy" || argument === "--no-use-env-proxy");
|
|
7092
|
+
}
|
|
7093
|
+
function childProcessEnv(strip, extra = {}) {
|
|
7094
|
+
const env = { ...process.env };
|
|
7095
|
+
const stripped = new Set(strip.map((name) => name.toLowerCase()));
|
|
7096
|
+
for (const key of Object.keys(env)) {
|
|
7097
|
+
if (stripped.has(key.toLowerCase()))
|
|
7098
|
+
delete env[key];
|
|
7099
|
+
}
|
|
7100
|
+
return { ...env, ...extra };
|
|
7101
|
+
}
|
|
7102
|
+
|
|
7103
|
+
// src/version.ts
|
|
7104
|
+
import { readFileSync } from "node:fs";
|
|
7105
|
+
function readPackageVersion() {
|
|
7106
|
+
const metadata = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
7107
|
+
if (typeof metadata !== "object" || metadata === null || !("version" in metadata) || typeof metadata.version !== "string") {
|
|
7108
|
+
throw new Error("CLI package metadata is missing a valid version");
|
|
7109
|
+
}
|
|
7110
|
+
return metadata.version;
|
|
7111
|
+
}
|
|
7112
|
+
var CLI_VERSION = readPackageVersion();
|
|
7113
|
+
var USER_AGENT = `sim-cli/${CLI_VERSION} node/${process.versions.node} (${process.platform}; ${process.arch})`;
|
|
7114
|
+
|
|
7115
|
+
// src/update/check.ts
|
|
7116
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
7117
|
+
var REGISTRY_TIMEOUT_MS = 1000;
|
|
7118
|
+
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
7119
|
+
var PACKAGE_NAME = "sim";
|
|
7120
|
+
var DIST_TAGS_PATH = `-/package/${PACKAGE_NAME}/dist-tags`;
|
|
7121
|
+
var MAX_RESPONSE_BYTES = 64 * 1024;
|
|
7122
|
+
var MAX_CACHE_BYTES = 4 * 1024;
|
|
7123
|
+
var STABLE_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
7124
|
+
function parseStableVersion(version) {
|
|
7125
|
+
const match = STABLE_VERSION_PATTERN.exec(version);
|
|
7126
|
+
if (!match)
|
|
7127
|
+
return null;
|
|
7128
|
+
const parsed = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
7129
|
+
return parsed.every(Number.isSafeInteger) ? parsed : null;
|
|
7130
|
+
}
|
|
7131
|
+
function isNewerVersion(candidate, current) {
|
|
7132
|
+
if (candidate[0] !== current[0])
|
|
7133
|
+
return candidate[0] > current[0];
|
|
7134
|
+
if (candidate[1] !== current[1])
|
|
7135
|
+
return candidate[1] > current[1];
|
|
7136
|
+
return candidate[2] > current[2];
|
|
7137
|
+
}
|
|
7138
|
+
var CACHE_VERSION = 1;
|
|
7139
|
+
function isProjectLocalInstall(modulePath, cwd) {
|
|
7140
|
+
const normalizedModulePath = normalizeModulePath(modulePath);
|
|
7141
|
+
const nodeModulesIndex = normalizedModulePath.indexOf("/node_modules/");
|
|
7142
|
+
if (nodeModulesIndex < 0)
|
|
7143
|
+
return false;
|
|
7144
|
+
const installRoot = normalizedModulePath.slice(0, nodeModulesIndex);
|
|
7145
|
+
const workingDirectory = normalizeModulePath(cwd).replace(/\/+$/, "");
|
|
7146
|
+
return workingDirectory === installRoot || workingDirectory.startsWith(`${installRoot}/`);
|
|
7147
|
+
}
|
|
7148
|
+
function isUnadvisableInstall(modulePath, env, cwd) {
|
|
7149
|
+
const normalized = normalizeModulePath(modulePath);
|
|
7150
|
+
return env.npm_command === "exec" || normalized.includes("/_npx/") || normalized.includes("/packages/sim-cli/") || isProjectLocalInstall(modulePath, cwd);
|
|
7151
|
+
}
|
|
7152
|
+
function normalizeModulePath(modulePath) {
|
|
7153
|
+
return modulePath.replace(/\\/g, "/").toLowerCase();
|
|
7154
|
+
}
|
|
7155
|
+
function registryUrl(env) {
|
|
7156
|
+
const fallback = new URL(DIST_TAGS_PATH, DEFAULT_REGISTRY);
|
|
7157
|
+
const configured = env.npm_config_registry?.trim();
|
|
7158
|
+
if (!configured)
|
|
7159
|
+
return fallback;
|
|
7160
|
+
try {
|
|
7161
|
+
const base = new URL(configured);
|
|
7162
|
+
if (base.protocol !== "http:" && base.protocol !== "https:")
|
|
7163
|
+
return null;
|
|
7164
|
+
if (base.username || base.password)
|
|
7165
|
+
return null;
|
|
7166
|
+
base.pathname = `${base.pathname.replace(/\/$/, "")}/${DIST_TAGS_PATH}`;
|
|
7167
|
+
return base;
|
|
7168
|
+
} catch {
|
|
7169
|
+
return null;
|
|
7170
|
+
}
|
|
7171
|
+
}
|
|
7172
|
+
var REGISTRY_REQUEST_SCRIPT = `
|
|
7173
|
+
let input = ''
|
|
7174
|
+
process.stdin.setEncoding('utf8')
|
|
7175
|
+
for await (const chunk of process.stdin) input += chunk
|
|
7176
|
+
|
|
7177
|
+
try {
|
|
7178
|
+
const { url, headers, maxResponseBytes, timeoutMs } = JSON.parse(input)
|
|
7179
|
+
const deadline = setTimeout(() => process.exit(1), timeoutMs)
|
|
7180
|
+
const response = await fetch(url, { headers, redirect: 'error' })
|
|
7181
|
+
const declared = Number(response.headers.get('content-length'))
|
|
7182
|
+
|
|
7183
|
+
if (!response.ok || !response.body || (Number.isFinite(declared) && declared > maxResponseBytes)) {
|
|
7184
|
+
process.exit(1)
|
|
7185
|
+
}
|
|
7186
|
+
|
|
7187
|
+
const reader = response.body.getReader()
|
|
7188
|
+
const chunks = []
|
|
7189
|
+
let seen = 0
|
|
7190
|
+
|
|
7191
|
+
while (true) {
|
|
7192
|
+
const { done, value } = await reader.read()
|
|
7193
|
+
if (done) break
|
|
7194
|
+
seen += value.byteLength
|
|
7195
|
+
if (seen > maxResponseBytes) {
|
|
7196
|
+
process.exit(1)
|
|
7197
|
+
}
|
|
7198
|
+
chunks.push(Buffer.from(value))
|
|
7199
|
+
}
|
|
7200
|
+
|
|
7201
|
+
clearTimeout(deadline)
|
|
7202
|
+
process.stdout.write(Buffer.concat(chunks), () => process.exit(0))
|
|
7203
|
+
} catch {
|
|
7204
|
+
process.exit(1)
|
|
7205
|
+
}
|
|
7206
|
+
`;
|
|
7207
|
+
function requestRegistry(url, { headers, maxResponseBytes, timeoutMs }) {
|
|
7208
|
+
return new Promise((resolve, reject) => {
|
|
7209
|
+
const child = spawn(process.execPath, [...proxyExecArgv(), "--input-type=module", "--eval", REGISTRY_REQUEST_SCRIPT], {
|
|
7210
|
+
env: childProcessEnv(["npm_config_registry", "sim_api_key"]),
|
|
7211
|
+
killSignal: "SIGKILL",
|
|
7212
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
7213
|
+
timeout: timeoutMs,
|
|
7214
|
+
windowsHide: true
|
|
7215
|
+
});
|
|
7216
|
+
const chunks = [];
|
|
7217
|
+
let failed = false;
|
|
7218
|
+
let seen = 0;
|
|
7219
|
+
child.stdout.on("data", (chunk) => {
|
|
7220
|
+
seen += chunk.byteLength;
|
|
7221
|
+
if (seen > maxResponseBytes) {
|
|
7222
|
+
failed = true;
|
|
7223
|
+
child.kill("SIGKILL");
|
|
7224
|
+
return;
|
|
7225
|
+
}
|
|
7226
|
+
chunks.push(chunk);
|
|
7227
|
+
});
|
|
7228
|
+
child.stdout.on("error", () => {
|
|
7229
|
+
failed = true;
|
|
7230
|
+
child.kill("SIGKILL");
|
|
7231
|
+
});
|
|
7232
|
+
child.stdin.on("error", () => {});
|
|
7233
|
+
child.once("error", reject);
|
|
7234
|
+
child.once("close", (code) => {
|
|
7235
|
+
resolve(code === 0 && !failed ? Buffer.concat(chunks).toString("utf8") : null);
|
|
7236
|
+
});
|
|
7237
|
+
child.stdin.end(JSON.stringify({ headers, maxResponseBytes, timeoutMs, url: url.href }));
|
|
7238
|
+
});
|
|
7239
|
+
}
|
|
7240
|
+
async function fetchDistTags(env, request) {
|
|
7241
|
+
try {
|
|
7242
|
+
const url = registryUrl(env);
|
|
7243
|
+
if (!url)
|
|
7244
|
+
return null;
|
|
7245
|
+
const text = await request(url, {
|
|
7246
|
+
headers: { accept: "application/json", "user-agent": `${PACKAGE_NAME}-cli/${CLI_VERSION}` },
|
|
7247
|
+
maxResponseBytes: MAX_RESPONSE_BYTES,
|
|
7248
|
+
timeoutMs: REGISTRY_TIMEOUT_MS
|
|
7249
|
+
});
|
|
7250
|
+
if (text === null || Buffer.byteLength(text) > MAX_RESPONSE_BYTES)
|
|
7251
|
+
return null;
|
|
7252
|
+
const body = JSON.parse(text);
|
|
7253
|
+
if (typeof body !== "object" || body === null || Array.isArray(body))
|
|
7254
|
+
return null;
|
|
7255
|
+
const tags = {};
|
|
7256
|
+
for (const [tag, version] of Object.entries(body)) {
|
|
7257
|
+
if (typeof version === "string")
|
|
7258
|
+
tags[tag] = version;
|
|
7259
|
+
}
|
|
7260
|
+
return tags;
|
|
7261
|
+
} catch {
|
|
7262
|
+
return null;
|
|
7263
|
+
}
|
|
7264
|
+
}
|
|
7265
|
+
function readCache(path) {
|
|
7266
|
+
const parsed = readJsonFile(path, MAX_CACHE_BYTES);
|
|
7267
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
7268
|
+
return null;
|
|
7269
|
+
const entry = parsed;
|
|
7270
|
+
if (entry.version !== CACHE_VERSION)
|
|
7271
|
+
return null;
|
|
7272
|
+
if (typeof entry.checkedAt !== "string" || Number.isNaN(Date.parse(entry.checkedAt)))
|
|
7273
|
+
return null;
|
|
7274
|
+
return { version: CACHE_VERSION, checkedAt: entry.checkedAt };
|
|
7275
|
+
}
|
|
7276
|
+
function writeCache(path, entry) {
|
|
7277
|
+
writeJsonFile(path, entry);
|
|
7278
|
+
}
|
|
7279
|
+
function isFresh(entry, now) {
|
|
7280
|
+
const age = now.getTime() - Date.parse(entry.checkedAt);
|
|
7281
|
+
return age >= 0 && age < CHECK_INTERVAL_MS;
|
|
7282
|
+
}
|
|
7283
|
+
function upgradeCommand(modulePath = fileURLToPath(import.meta.url), env = process.env) {
|
|
7284
|
+
const target = `${PACKAGE_NAME}@latest`;
|
|
7285
|
+
const normalized = normalizeModulePath(modulePath);
|
|
7286
|
+
if (normalized.includes(".bun/install/global"))
|
|
7287
|
+
return `bun add -g ${target}`;
|
|
7288
|
+
if (normalized.includes("/pnpm/") || normalized.includes("/.pnpm/")) {
|
|
7289
|
+
return `pnpm add -g ${target}`;
|
|
7290
|
+
}
|
|
7291
|
+
if (normalized.includes("/.yarn/") || normalized.includes("/yarn/")) {
|
|
7292
|
+
return `yarn global add ${target}`;
|
|
7293
|
+
}
|
|
7294
|
+
const agent = env.npm_config_user_agent ?? "";
|
|
7295
|
+
if (agent.startsWith("pnpm/"))
|
|
7296
|
+
return `pnpm add -g ${target}`;
|
|
7297
|
+
if (agent.startsWith("yarn/"))
|
|
7298
|
+
return `yarn global add ${target}`;
|
|
7299
|
+
if (agent.startsWith("bun/"))
|
|
7300
|
+
return `bun add -g ${target}`;
|
|
7301
|
+
return `npm install -g ${target}`;
|
|
7302
|
+
}
|
|
7303
|
+
async function announceUpdateIfAvailable(options = {}) {
|
|
7304
|
+
try {
|
|
7305
|
+
const env = options.env ?? process.env;
|
|
7306
|
+
const isTty = options.isTty ?? process.stderr.isTTY === true;
|
|
7307
|
+
const modulePath = options.modulePath ?? fileURLToPath(import.meta.url);
|
|
7308
|
+
const cwd = options.cwd ?? process.cwd();
|
|
7309
|
+
const now = options.now ?? new Date;
|
|
7310
|
+
if (isEnabled(env.SIM_NO_UPDATE_CHECK))
|
|
7311
|
+
return;
|
|
7312
|
+
if (!isTty)
|
|
7313
|
+
return;
|
|
7314
|
+
if (isCi(env))
|
|
7315
|
+
return;
|
|
7316
|
+
if (isUnadvisableInstall(modulePath, env, cwd))
|
|
7317
|
+
return;
|
|
7318
|
+
const currentVersion = options.currentVersion ?? CLI_VERSION;
|
|
7319
|
+
const current = parseStableVersion(currentVersion);
|
|
7320
|
+
if (!current)
|
|
7321
|
+
return;
|
|
7322
|
+
const cachePath = updateCachePath();
|
|
7323
|
+
const cached = readCache(cachePath);
|
|
7324
|
+
if (cached && isFresh(cached, now))
|
|
7325
|
+
return;
|
|
7326
|
+
const tags = await fetchDistTags(env, options.registryRequest ?? requestRegistry);
|
|
7327
|
+
const latest = tags?.latest ?? null;
|
|
7328
|
+
const available = latest ? parseStableVersion(latest) : null;
|
|
7329
|
+
writeCache(cachePath, {
|
|
7330
|
+
version: CACHE_VERSION,
|
|
7331
|
+
checkedAt: now.toISOString()
|
|
7332
|
+
});
|
|
7333
|
+
if (!latest || !available)
|
|
7334
|
+
return;
|
|
7335
|
+
if (!isNewerVersion(available, current))
|
|
7336
|
+
return;
|
|
7337
|
+
const write = options.write ?? ((message) => void process.stderr.write(message));
|
|
7338
|
+
write(`Update available: sim ${currentVersion} → ${latest}. Run: sim update
|
|
7339
|
+
`);
|
|
7340
|
+
} catch {}
|
|
6957
7341
|
}
|
|
6958
|
-
|
|
6959
|
-
|
|
7342
|
+
|
|
7343
|
+
// src/update/install.ts
|
|
7344
|
+
class CliUpdateError extends Error {
|
|
7345
|
+
}
|
|
7346
|
+
var PACKAGE_MANAGERS = ["npm", "pnpm", "bun", "yarn"];
|
|
7347
|
+
var runPackageManager = (manager, args, { env, capture }) => new Promise((resolve, reject) => {
|
|
7348
|
+
const child = spawn2(manager, args, {
|
|
7349
|
+
cwd: homedir2(),
|
|
7350
|
+
env,
|
|
7351
|
+
shell: process.platform === "win32",
|
|
7352
|
+
stdio: ["ignore", capture ? "pipe" : process.stderr, process.stderr],
|
|
7353
|
+
timeout: capture ? 1e4 : 5 * 60000,
|
|
7354
|
+
killSignal: "SIGKILL",
|
|
7355
|
+
windowsHide: true
|
|
7356
|
+
});
|
|
7357
|
+
let output = "";
|
|
7358
|
+
child.stdout?.setEncoding("utf8").on("data", (chunk) => {
|
|
7359
|
+
output += chunk;
|
|
7360
|
+
if (Buffer.byteLength(output) > 64 * 1024) {
|
|
7361
|
+
child.kill("SIGKILL");
|
|
7362
|
+
reject(new CliUpdateError(`${manager} returned too much output while checking Sim.`));
|
|
7363
|
+
}
|
|
7364
|
+
});
|
|
7365
|
+
child.once("error", (error) => {
|
|
7366
|
+
reject(new CliUpdateError(`Could not run ${manager}: ${getErrorMessage(error)}`));
|
|
7367
|
+
});
|
|
7368
|
+
child.once("close", (code, signal) => {
|
|
7369
|
+
if (code !== 0) {
|
|
7370
|
+
reject(new CliUpdateError(`${manager} ${args.join(" ")} failed (${signal ?? `exit ${code}`}). Resolve the package-manager error and run sim update again.`));
|
|
7371
|
+
return;
|
|
7372
|
+
}
|
|
7373
|
+
resolve(output.trim());
|
|
7374
|
+
});
|
|
7375
|
+
});
|
|
7376
|
+
function parseReleaseVersion(version) {
|
|
7377
|
+
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(preview|dev)\.(0|[1-9]\d*)\.(0|[1-9]\d*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.exec(version);
|
|
7378
|
+
if (version.length > 256 || !match) {
|
|
7379
|
+
throw new CliUpdateError(`Cannot determine the release channel for Sim ${version}.`);
|
|
7380
|
+
}
|
|
7381
|
+
const precedence = [BigInt(match[1]), BigInt(match[2]), BigInt(match[3])];
|
|
7382
|
+
if (match[4])
|
|
7383
|
+
precedence.push(BigInt(match[5]), BigInt(match[6]));
|
|
7384
|
+
return {
|
|
7385
|
+
channel: match[4] === "preview" ? "staging" : match[4] === "dev" ? "dev" : "latest",
|
|
7386
|
+
precedence
|
|
7387
|
+
};
|
|
6960
7388
|
}
|
|
6961
|
-
function
|
|
6962
|
-
|
|
7389
|
+
function compareReleases(candidate, current) {
|
|
7390
|
+
for (const [index, component] of candidate.precedence.entries()) {
|
|
7391
|
+
if (component !== current.precedence[index])
|
|
7392
|
+
return component > current.precedence[index] ? 1 : -1;
|
|
7393
|
+
}
|
|
7394
|
+
return 0;
|
|
7395
|
+
}
|
|
7396
|
+
function resolveInstallationPath(path) {
|
|
7397
|
+
try {
|
|
7398
|
+
return realpathSync(path);
|
|
7399
|
+
} catch (cause) {
|
|
7400
|
+
throw new CliUpdateError(`Cannot access the Sim installation: ${getErrorMessage(cause)}`, {
|
|
7401
|
+
cause
|
|
7402
|
+
});
|
|
7403
|
+
}
|
|
7404
|
+
}
|
|
7405
|
+
function readInstalledVersion(entrypoint) {
|
|
7406
|
+
const manifestPath = join2(dirname2(dirname2(resolveInstallationPath(entrypoint))), "package.json");
|
|
7407
|
+
let manifest;
|
|
7408
|
+
try {
|
|
7409
|
+
manifest = JSON.parse(readFileSync2(manifestPath, "utf8"));
|
|
7410
|
+
} catch (cause) {
|
|
7411
|
+
throw new CliUpdateError(`Cannot read the installed Sim manifest: ${getErrorMessage(cause)}`, {
|
|
7412
|
+
cause
|
|
7413
|
+
});
|
|
7414
|
+
}
|
|
7415
|
+
if (typeof manifest !== "object" || manifest === null || !("name" in manifest) || manifest.name !== "sim" || !("version" in manifest) || typeof manifest.version !== "string") {
|
|
7416
|
+
throw new CliUpdateError("The installed Sim manifest must name the sim package and its version.");
|
|
7417
|
+
}
|
|
7418
|
+
return manifest.version;
|
|
7419
|
+
}
|
|
7420
|
+
function parseRegistryVersion(output, manager) {
|
|
7421
|
+
let version;
|
|
7422
|
+
try {
|
|
7423
|
+
if (manager === "yarn") {
|
|
7424
|
+
const events = output.split(/\r?\n/).filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
7425
|
+
const inspections = events.filter((event) => typeof event === "object" && event !== null && ("type" in event) && event.type === "inspect" && ("data" in event));
|
|
7426
|
+
if (inspections.length === 1)
|
|
7427
|
+
version = inspections[0].data;
|
|
7428
|
+
} else {
|
|
7429
|
+
version = JSON.parse(output);
|
|
7430
|
+
}
|
|
7431
|
+
} catch (cause) {
|
|
7432
|
+
throw new CliUpdateError(`${manager} returned invalid registry JSON.`, { cause });
|
|
7433
|
+
}
|
|
7434
|
+
if (typeof version !== "string") {
|
|
7435
|
+
throw new CliUpdateError(`${manager} did not resolve a single Sim release version.`);
|
|
7436
|
+
}
|
|
7437
|
+
return version;
|
|
7438
|
+
}
|
|
7439
|
+
async function installUpdate(options = {}) {
|
|
7440
|
+
const modulePath = resolveInstallationPath(options.modulePath ?? fileURLToPath2(import.meta.url));
|
|
7441
|
+
const env = omit(options.env ?? process.env, ["SIM_API_KEY"]);
|
|
7442
|
+
const normalized = modulePath.replaceAll("\\", "/").toLowerCase();
|
|
7443
|
+
if (env.npm_command === "exec" || normalized.includes("/_npx/") || normalized.includes("/bunx-") || !normalized.endsWith("/node_modules/sim/dist/index.js")) {
|
|
7444
|
+
throw new CliUpdateError("sim update requires a global installation. Update project dependencies with their package manager, or use sim@latest with your package runner.");
|
|
7445
|
+
}
|
|
7446
|
+
const manager = options.packageManager ?? upgradeCommand(modulePath, env).split(" ")[0];
|
|
7447
|
+
if (!PACKAGE_MANAGERS.includes(manager)) {
|
|
7448
|
+
throw new CliUpdateError("Cannot determine which package manager installed Sim.");
|
|
7449
|
+
}
|
|
7450
|
+
const packageManager = manager;
|
|
7451
|
+
const run = options.run ?? runPackageManager;
|
|
7452
|
+
const currentVersion = options.currentVersion ?? CLI_VERSION;
|
|
7453
|
+
const current = parseReleaseVersion(currentVersion);
|
|
7454
|
+
const target = current.channel;
|
|
7455
|
+
const write = options.write ?? ((message) => void process.stderr.write(message));
|
|
7456
|
+
env.SIM_NO_UPDATE_CHECK = "1";
|
|
7457
|
+
const locateArgs = packageManager === "bun" ? ["pm", "bin", "-g"] : packageManager === "yarn" ? ["global", "dir", "--silent"] : ["root", "-g"];
|
|
7458
|
+
const directory = await run(packageManager, locateArgs, { env, capture: true });
|
|
7459
|
+
if (!isAbsolute(directory) || /[\r\n]/.test(directory)) {
|
|
7460
|
+
throw new CliUpdateError(`${packageManager} did not return a valid global installation path.`);
|
|
7461
|
+
}
|
|
7462
|
+
const installedEntry = packageManager === "bun" ? join2(directory, "sim") : join2(directory, ...packageManager === "yarn" ? ["node_modules"] : [], "sim/dist/index.js");
|
|
7463
|
+
if (resolveInstallationPath(installedEntry) !== modulePath) {
|
|
7464
|
+
throw new CliUpdateError(`${packageManager} would update a different Sim installation. Use the package manager and global configuration that installed this copy, or select --package-manager.`);
|
|
7465
|
+
}
|
|
7466
|
+
const release = await import_proper_lockfile.lock(dirname2(dirname2(modulePath)), { retries: 0, realpath: false }).catch((cause) => {
|
|
7467
|
+
throw new CliUpdateError(`Cannot lock Sim for update: ${getErrorMessage(cause)}`, { cause });
|
|
7468
|
+
});
|
|
7469
|
+
let updateFailed = false;
|
|
7470
|
+
try {
|
|
7471
|
+
if (readInstalledVersion(installedEntry) !== currentVersion) {
|
|
7472
|
+
throw new CliUpdateError("The Sim installation changed while starting the update. Run sim update again.");
|
|
7473
|
+
}
|
|
7474
|
+
const version = parseRegistryVersion(await run(packageManager, [
|
|
7475
|
+
packageManager === "bun" || packageManager === "yarn" ? "info" : "view",
|
|
7476
|
+
`sim@${target}`,
|
|
7477
|
+
"version",
|
|
7478
|
+
"--json"
|
|
7479
|
+
], { env, capture: true }), packageManager);
|
|
7480
|
+
const candidate = parseReleaseVersion(version);
|
|
7481
|
+
if (candidate.channel !== target) {
|
|
7482
|
+
throw new CliUpdateError("The registry resolved Sim to a different release channel.");
|
|
7483
|
+
}
|
|
7484
|
+
const comparison = compareReleases(candidate, current);
|
|
7485
|
+
if (comparison < 0) {
|
|
7486
|
+
throw new CliUpdateError(`Refusing to downgrade Sim ${currentVersion} to ${version}. Check your package-manager registry settings.`);
|
|
7487
|
+
}
|
|
7488
|
+
if (comparison === 0) {
|
|
7489
|
+
write(`Sim ${currentVersion} is already up to date.
|
|
7490
|
+
`);
|
|
7491
|
+
return;
|
|
7492
|
+
}
|
|
7493
|
+
write(`Updating Sim ${currentVersion} with ${packageManager} (sim@${version})…
|
|
7494
|
+
`);
|
|
7495
|
+
const args = packageManager === "npm" ? ["install", "-g", `sim@${version}`] : packageManager === "yarn" ? ["global", "add", `sim@${version}`] : ["add", "-g", `sim@${version}`];
|
|
7496
|
+
await run(packageManager, args, { env, capture: false });
|
|
7497
|
+
if (readInstalledVersion(installedEntry) !== version) {
|
|
7498
|
+
throw new CliUpdateError("The package manager did not install the expected Sim version.");
|
|
7499
|
+
}
|
|
7500
|
+
write(`Updated Sim ${currentVersion} → ${version}. The next invocation will use the new version.
|
|
7501
|
+
`);
|
|
7502
|
+
} catch (error) {
|
|
7503
|
+
updateFailed = true;
|
|
7504
|
+
throw error;
|
|
7505
|
+
} finally {
|
|
7506
|
+
await release().catch((cause) => {
|
|
7507
|
+
const message = `Cannot release the Sim update lock: ${getErrorMessage(cause)}`;
|
|
7508
|
+
if (updateFailed) {
|
|
7509
|
+
write(`${message}
|
|
7510
|
+
`);
|
|
7511
|
+
} else {
|
|
7512
|
+
throw new CliUpdateError(message, { cause });
|
|
7513
|
+
}
|
|
7514
|
+
});
|
|
7515
|
+
}
|
|
6963
7516
|
}
|
|
6964
7517
|
// src/config/profile.ts
|
|
6965
|
-
var
|
|
7518
|
+
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
6966
7519
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6967
7520
|
import { createHash } from "node:crypto";
|
|
6968
7521
|
import {
|
|
6969
7522
|
chmodSync,
|
|
6970
7523
|
existsSync,
|
|
6971
|
-
mkdirSync,
|
|
6972
|
-
readFileSync,
|
|
6973
|
-
renameSync,
|
|
7524
|
+
mkdirSync as mkdirSync2,
|
|
7525
|
+
readFileSync as readFileSync3,
|
|
7526
|
+
renameSync as renameSync2,
|
|
6974
7527
|
rmSync,
|
|
6975
|
-
writeFileSync
|
|
7528
|
+
writeFileSync as writeFileSync2
|
|
6976
7529
|
} from "node:fs";
|
|
6977
|
-
import { dirname } from "node:path";
|
|
7530
|
+
import { dirname as dirname3 } from "node:path";
|
|
6978
7531
|
|
|
6979
7532
|
// src/config/ini.ts
|
|
6980
7533
|
class ProfileConfigError extends Error {
|
|
@@ -7130,16 +7683,16 @@ function configSectionName(profile) {
|
|
|
7130
7683
|
function readIni(path) {
|
|
7131
7684
|
if (!existsSync(path))
|
|
7132
7685
|
return { preamble: [], sections: [] };
|
|
7133
|
-
return parseIni(
|
|
7686
|
+
return parseIni(readFileSync3(path, "utf8"));
|
|
7134
7687
|
}
|
|
7135
7688
|
function writeIni(path, doc, secret) {
|
|
7136
|
-
|
|
7689
|
+
mkdirSync2(dirname3(path), { recursive: true, mode: 448 });
|
|
7137
7690
|
const temporary = `${path}.${process.pid}.${temporaryFileSequence++}.tmp`;
|
|
7138
7691
|
try {
|
|
7139
|
-
|
|
7692
|
+
writeFileSync2(temporary, serializeIni(doc), { mode: secret ? 384 : 420 });
|
|
7140
7693
|
if (secret)
|
|
7141
7694
|
chmodSync(temporary, 384);
|
|
7142
|
-
|
|
7695
|
+
renameSync2(temporary, path);
|
|
7143
7696
|
} catch (error) {
|
|
7144
7697
|
rmSync(temporary, { force: true });
|
|
7145
7698
|
throw error;
|
|
@@ -7301,10 +7854,10 @@ var heldLock = new AsyncLocalStorage;
|
|
|
7301
7854
|
async function withProfileLoginLease(profile, work) {
|
|
7302
7855
|
const digest = createHash("sha256").update(profile, "utf8").digest("hex");
|
|
7303
7856
|
const path = `${credentialsPath()}.login-${digest}`;
|
|
7304
|
-
|
|
7857
|
+
mkdirSync2(dirname3(path), { recursive: true, mode: 448 });
|
|
7305
7858
|
let release;
|
|
7306
7859
|
try {
|
|
7307
|
-
release = await
|
|
7860
|
+
release = await import_proper_lockfile2.lock(path, {
|
|
7308
7861
|
realpath: false,
|
|
7309
7862
|
stale: CREDENTIALS_LOCK_STALE_MS,
|
|
7310
7863
|
update: CREDENTIALS_LOCK_STALE_MS / 3,
|
|
@@ -7326,10 +7879,10 @@ async function withCredentialsLock(work) {
|
|
|
7326
7879
|
if (heldLock.getStore())
|
|
7327
7880
|
return work();
|
|
7328
7881
|
const path = credentialsPath();
|
|
7329
|
-
|
|
7882
|
+
mkdirSync2(dirname3(path), { recursive: true, mode: 448 });
|
|
7330
7883
|
let release;
|
|
7331
7884
|
try {
|
|
7332
|
-
release = await
|
|
7885
|
+
release = await import_proper_lockfile2.lock(path, {
|
|
7333
7886
|
realpath: false,
|
|
7334
7887
|
stale: CREDENTIALS_LOCK_STALE_MS,
|
|
7335
7888
|
update: CREDENTIALS_LOCK_STALE_MS / 3,
|
|
@@ -7468,17 +8021,190 @@ function resolveProfile(overrides = {}) {
|
|
|
7468
8021
|
}
|
|
7469
8022
|
};
|
|
7470
8023
|
}
|
|
7471
|
-
// src/
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
8024
|
+
// ../utils/src/client-info.ts
|
|
8025
|
+
var CLIENT_INFO_HEADER = "x-sim-client-info";
|
|
8026
|
+
var SIM_SURFACES = ["web", "desktop", "cli", "sdk-js", "sdk-python"];
|
|
8027
|
+
var TOKEN_PATTERN = /^[A-Za-z0-9._+-]+$/;
|
|
8028
|
+
var OS_KEY = "os";
|
|
8029
|
+
var ARCH_KEY = "arch";
|
|
8030
|
+
var AGENT_KEY = "agent";
|
|
8031
|
+
var SURFACE_SET = new Set(SIM_SURFACES);
|
|
8032
|
+
function isToken(value) {
|
|
8033
|
+
return TOKEN_PATTERN.test(value);
|
|
8034
|
+
}
|
|
8035
|
+
function product(name, version) {
|
|
8036
|
+
if (!isToken(name))
|
|
8037
|
+
throw new Error(`Client info token name is not a valid token: ${name}`);
|
|
8038
|
+
if (version === undefined)
|
|
8039
|
+
return name;
|
|
8040
|
+
if (!isToken(version))
|
|
8041
|
+
throw new Error(`Client info token version is not a valid token: ${version}`);
|
|
8042
|
+
return `${name}/${version}`;
|
|
8043
|
+
}
|
|
8044
|
+
function formatClientInfo(info) {
|
|
8045
|
+
const tokens = [product(info.surface, info.version)];
|
|
8046
|
+
if (info.runtime)
|
|
8047
|
+
tokens.push(product(info.runtime.name, info.runtime.version));
|
|
8048
|
+
if (info.os)
|
|
8049
|
+
tokens.push(product(OS_KEY, info.os));
|
|
8050
|
+
if (info.arch)
|
|
8051
|
+
tokens.push(product(ARCH_KEY, info.arch));
|
|
8052
|
+
if (info.agent)
|
|
8053
|
+
tokens.push(product(AGENT_KEY, info.agent));
|
|
8054
|
+
return tokens.join("; ");
|
|
8055
|
+
}
|
|
8056
|
+
|
|
8057
|
+
// src/telemetry/coding-agent.ts
|
|
8058
|
+
var AGENT_NAME_PATTERN = /^[a-z0-9_-]+$/i;
|
|
8059
|
+
var MAX_AGENT_NAME_LENGTH = 64;
|
|
8060
|
+
var anyOf = (...variables) => (env) => variables.some((variable) => Boolean(env[variable]));
|
|
8061
|
+
var AGENT_MARKERS = [
|
|
8062
|
+
{ name: "amp", matches: (env) => env.AGENT === "amp" || Boolean(env.AMP_CURRENT_THREAD_ID) },
|
|
8063
|
+
{
|
|
8064
|
+
name: "codex",
|
|
8065
|
+
matches: anyOf("CODEX_THREAD_ID", "CODEX_SANDBOX", "CODEX_CI", "CODEX_SANDBOX_NETWORK_DISABLED")
|
|
8066
|
+
},
|
|
8067
|
+
{ name: "gemini-cli", matches: anyOf("GEMINI_CLI") },
|
|
8068
|
+
{ name: "opencode", matches: anyOf("OPENCODE") },
|
|
8069
|
+
{ name: "antigravity", matches: anyOf("ANTIGRAVITY_AGENT") },
|
|
8070
|
+
{ name: "augment", matches: anyOf("AUGMENT_AGENT") },
|
|
8071
|
+
{ name: "cline", matches: anyOf("CLINE_ACTIVE") },
|
|
8072
|
+
{ name: "cowork", matches: anyOf("CLAUDE_CODE_IS_COWORK") },
|
|
8073
|
+
{ name: "claude-code", matches: anyOf("CLAUDECODE", "CLAUDE_CODE") },
|
|
8074
|
+
{
|
|
8075
|
+
name: "cursor",
|
|
8076
|
+
matches: (env) => anyOf("CURSOR_AGENT", "CURSOR_TRACE_ID")(env) || env.CURSOR_EXTENSION_HOST_ROLE === "agent-exec"
|
|
8077
|
+
},
|
|
8078
|
+
{ name: "warp", matches: anyOf("OZ_RUN_ID") },
|
|
8079
|
+
{ name: "pi", matches: anyOf("PI_CODING_AGENT") },
|
|
8080
|
+
{ name: "crush", matches: anyOf("CRUSH") }
|
|
8081
|
+
];
|
|
8082
|
+
function declaredAgentName(value) {
|
|
8083
|
+
const trimmed = value?.trim().toLowerCase();
|
|
8084
|
+
if (!trimmed || trimmed.length > MAX_AGENT_NAME_LENGTH)
|
|
8085
|
+
return;
|
|
8086
|
+
return AGENT_NAME_PATTERN.test(trimmed) ? trimmed : undefined;
|
|
8087
|
+
}
|
|
8088
|
+
function detectCodingAgent(env = process.env) {
|
|
8089
|
+
const declared = declaredAgentName(env.AI_AGENT);
|
|
8090
|
+
if (declared)
|
|
8091
|
+
return declared;
|
|
8092
|
+
const generic = declaredAgentName(env.AGENT);
|
|
8093
|
+
if (generic && generic !== "1")
|
|
8094
|
+
return generic;
|
|
8095
|
+
return AGENT_MARKERS.find((marker) => marker.matches(env))?.name;
|
|
8096
|
+
}
|
|
8097
|
+
|
|
8098
|
+
// src/telemetry/policy.ts
|
|
8099
|
+
var DO_NOT_TRACK_VARIABLE = "DO_NOT_TRACK";
|
|
8100
|
+
var TELEMETRY_DISABLED_VARIABLE = "SIM_TELEMETRY_DISABLED";
|
|
8101
|
+
function telemetryStatus({ env, state, configured }) {
|
|
8102
|
+
if (isEnabled(env[DO_NOT_TRACK_VARIABLE]))
|
|
8103
|
+
return { enabled: false, reason: "do_not_track" };
|
|
8104
|
+
if (isEnabled(env[TELEMETRY_DISABLED_VARIABLE]))
|
|
8105
|
+
return { enabled: false, reason: "environment" };
|
|
8106
|
+
if (state.enabled === false)
|
|
8107
|
+
return { enabled: false, reason: "setting" };
|
|
8108
|
+
if (!configured)
|
|
8109
|
+
return { enabled: false, reason: "unconfigured" };
|
|
8110
|
+
return { enabled: true };
|
|
8111
|
+
}
|
|
8112
|
+
|
|
8113
|
+
// ../utils/src/id.ts
|
|
8114
|
+
function generateId() {
|
|
8115
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
8116
|
+
return crypto.randomUUID();
|
|
8117
|
+
}
|
|
8118
|
+
const bytes = new Uint8Array(16);
|
|
8119
|
+
crypto.getRandomValues(bytes);
|
|
8120
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
8121
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
8122
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
8123
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
8124
|
+
}
|
|
8125
|
+
|
|
8126
|
+
// src/telemetry/state.ts
|
|
8127
|
+
var SESSION_IDLE_MS = 30 * 60 * 1000;
|
|
8128
|
+
var MAX_STATE_BYTES = 4 * 1024;
|
|
8129
|
+
var STATE_VERSION = 1;
|
|
8130
|
+
var STATE_FILE_MODE = 384;
|
|
8131
|
+
function isIsoTimestamp(value) {
|
|
8132
|
+
return typeof value === "string" && !Number.isNaN(Date.parse(value));
|
|
8133
|
+
}
|
|
8134
|
+
function parseSession(value) {
|
|
8135
|
+
if (typeof value !== "object" || value === null)
|
|
8136
|
+
return;
|
|
8137
|
+
const session = value;
|
|
8138
|
+
if (typeof session.id !== "string" || !session.id)
|
|
8139
|
+
return;
|
|
8140
|
+
if (!isIsoTimestamp(session.lastActiveAt))
|
|
8141
|
+
return;
|
|
8142
|
+
if (!Number.isSafeInteger(session.sequence) || session.sequence < 0)
|
|
8143
|
+
return;
|
|
8144
|
+
return {
|
|
8145
|
+
id: session.id,
|
|
8146
|
+
lastActiveAt: session.lastActiveAt,
|
|
8147
|
+
sequence: session.sequence
|
|
8148
|
+
};
|
|
8149
|
+
}
|
|
8150
|
+
function initialTelemetryState() {
|
|
8151
|
+
return { version: STATE_VERSION, deviceId: generateId() };
|
|
8152
|
+
}
|
|
8153
|
+
function readTelemetryState(path = telemetryStatePath()) {
|
|
8154
|
+
const parsed = readJsonFile(path, MAX_STATE_BYTES);
|
|
8155
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
8156
|
+
return null;
|
|
8157
|
+
const state = parsed;
|
|
8158
|
+
if (state.version !== STATE_VERSION)
|
|
8159
|
+
return null;
|
|
8160
|
+
if (typeof state.deviceId !== "string" || !state.deviceId)
|
|
8161
|
+
return null;
|
|
8162
|
+
const result = { version: STATE_VERSION, deviceId: state.deviceId };
|
|
8163
|
+
if (typeof state.enabled === "boolean")
|
|
8164
|
+
result.enabled = state.enabled;
|
|
8165
|
+
if (isIsoTimestamp(state.noticeShownAt))
|
|
8166
|
+
result.noticeShownAt = state.noticeShownAt;
|
|
8167
|
+
const session = parseSession(state.session);
|
|
8168
|
+
if (session)
|
|
8169
|
+
result.session = session;
|
|
8170
|
+
return result;
|
|
8171
|
+
}
|
|
8172
|
+
function loadTelemetryState(path = telemetryStatePath()) {
|
|
8173
|
+
return readTelemetryState(path) ?? initialTelemetryState();
|
|
8174
|
+
}
|
|
8175
|
+
function writeTelemetryState(state, path = telemetryStatePath()) {
|
|
8176
|
+
writeJsonFile(path, state, STATE_FILE_MODE);
|
|
8177
|
+
}
|
|
8178
|
+
function nextSession(state, now) {
|
|
8179
|
+
const current = state.session;
|
|
8180
|
+
const idleFor = current ? now.getTime() - Date.parse(current.lastActiveAt) : Number.NaN;
|
|
8181
|
+
if (current && idleFor >= 0 && idleFor < SESSION_IDLE_MS) {
|
|
8182
|
+
return { id: current.id, lastActiveAt: now.toISOString(), sequence: current.sequence + 1 };
|
|
8183
|
+
}
|
|
8184
|
+
return { id: generateId(), lastActiveAt: now.toISOString(), sequence: 1 };
|
|
8185
|
+
}
|
|
8186
|
+
|
|
8187
|
+
// src/telemetry/client-info.ts
|
|
8188
|
+
var cached;
|
|
8189
|
+
function clientInfoHeader(env = process.env) {
|
|
8190
|
+
if (env !== process.env)
|
|
8191
|
+
return buildClientInfoHeader(env);
|
|
8192
|
+
cached ??= buildClientInfoHeader(env);
|
|
8193
|
+
return cached;
|
|
8194
|
+
}
|
|
8195
|
+
function buildClientInfoHeader(env) {
|
|
8196
|
+
return formatClientInfo({
|
|
8197
|
+
surface: "cli",
|
|
8198
|
+
version: CLI_VERSION,
|
|
8199
|
+
runtime: { name: "node", version: process.versions.node },
|
|
8200
|
+
os: process.platform,
|
|
8201
|
+
arch: process.arch,
|
|
8202
|
+
...reportingAllowed(env) ? { agent: detectCodingAgent(env) } : {}
|
|
8203
|
+
});
|
|
8204
|
+
}
|
|
8205
|
+
function reportingAllowed(env) {
|
|
8206
|
+
return telemetryStatus({ env, state: loadTelemetryState(), configured: true }).enabled;
|
|
7479
8207
|
}
|
|
7480
|
-
var CLI_VERSION = readPackageVersion();
|
|
7481
|
-
var USER_AGENT = `sim-cli/${CLI_VERSION} node/${process.versions.node} (${process.platform}; ${process.arch})`;
|
|
7482
8208
|
|
|
7483
8209
|
// src/http/environment.ts
|
|
7484
8210
|
var reported = new Set;
|
|
@@ -7818,6 +8544,7 @@ class SimClient {
|
|
|
7818
8544
|
...credential?.kind === "oauth" ? { authorization: `Bearer ${credential.oauth.accessToken}` } : {},
|
|
7819
8545
|
accept: "application/json",
|
|
7820
8546
|
"user-agent": USER_AGENT,
|
|
8547
|
+
[CLIENT_INFO_HEADER]: clientInfoHeader(),
|
|
7821
8548
|
...hasBody ? { "content-type": "application/json" } : {},
|
|
7822
8549
|
...options.headers
|
|
7823
8550
|
},
|
|
@@ -8466,20 +9193,18 @@ var {
|
|
|
8466
9193
|
Help
|
|
8467
9194
|
} = import__.default;
|
|
8468
9195
|
|
|
9196
|
+
// src/commands/update.ts
|
|
9197
|
+
function updateCommand() {
|
|
9198
|
+
return new Command("update").description("Update this global CLI installation to the newest release on its channel").addOption(new Option("--package-manager <manager>", "Package manager that installed this copy").choices(["npm", "pnpm", "bun", "yarn"])).action(async (options) => {
|
|
9199
|
+
await installUpdate({ packageManager: options.packageManager });
|
|
9200
|
+
});
|
|
9201
|
+
}
|
|
9202
|
+
|
|
8469
9203
|
// src/commands/auth.ts
|
|
8470
|
-
import { spawn } from "node:child_process";
|
|
9204
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
8471
9205
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
8472
9206
|
import { createInterface } from "node:readline/promises";
|
|
8473
9207
|
|
|
8474
|
-
// ../utils/src/errors.ts
|
|
8475
|
-
function getErrorMessage(value, fallback) {
|
|
8476
|
-
if (value instanceof Error)
|
|
8477
|
-
return value.message;
|
|
8478
|
-
if (typeof value === "string" && value.length > 0)
|
|
8479
|
-
return value;
|
|
8480
|
-
return fallback ?? String(value);
|
|
8481
|
-
}
|
|
8482
|
-
|
|
8483
9208
|
// src/auth/device-flow.ts
|
|
8484
9209
|
import { createHash as createHash3, randomBytes as randomBytes2, randomInt } from "node:crypto";
|
|
8485
9210
|
|
|
@@ -14627,7 +15352,7 @@ var MAX_INTERACTIVE_WORKSPACES = 1000;
|
|
|
14627
15352
|
function openBrowser(url) {
|
|
14628
15353
|
const [command, args] = process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : [process.platform === "darwin" ? "open" : "xdg-open", [url]];
|
|
14629
15354
|
try {
|
|
14630
|
-
const child =
|
|
15355
|
+
const child = spawn3(command, args, { stdio: "ignore", detached: true });
|
|
14631
15356
|
child.on("error", () => {});
|
|
14632
15357
|
child.unref();
|
|
14633
15358
|
} catch {}
|
|
@@ -17094,7 +17819,7 @@ function attachWorkspaceOperationWait(operations) {
|
|
|
17094
17819
|
}
|
|
17095
17820
|
|
|
17096
17821
|
// src/runtime/request.ts
|
|
17097
|
-
import { closeSync, existsSync as existsSync2, fstatSync, openSync, readSync } from "node:fs";
|
|
17822
|
+
import { closeSync as closeSync2, existsSync as existsSync2, fstatSync as fstatSync2, openSync as openSync2, readSync as readSync2 } from "node:fs";
|
|
17098
17823
|
var PROFILE_INJECTED_FIELD = "workspaceId";
|
|
17099
17824
|
function isProfileWorkspacePath(commandSpec, param) {
|
|
17100
17825
|
return commandSpec.profileWorkspacePath === true && param === PROFILE_INJECTED_FIELD;
|
|
@@ -17158,7 +17883,7 @@ function readArgumentDescriptor(descriptor) {
|
|
|
17158
17883
|
for (;; ) {
|
|
17159
17884
|
let read;
|
|
17160
17885
|
try {
|
|
17161
|
-
read =
|
|
17886
|
+
read = readSync2(descriptor, buffer, 0, buffer.length, null);
|
|
17162
17887
|
} catch (error) {
|
|
17163
17888
|
const code = error.code;
|
|
17164
17889
|
if (code === "EAGAIN") {
|
|
@@ -17200,13 +17925,13 @@ function readArgumentSource(raw, flagName) {
|
|
|
17200
17925
|
}
|
|
17201
17926
|
}
|
|
17202
17927
|
try {
|
|
17203
|
-
const descriptor =
|
|
17928
|
+
const descriptor = openSync2(path, "r");
|
|
17204
17929
|
try {
|
|
17205
|
-
if (
|
|
17930
|
+
if (fstatSync2(descriptor).size > MAX_JSON_ARGUMENT_BYTES)
|
|
17206
17931
|
throw new SimApiError("JSON input exceeds 10 MiB", 0);
|
|
17207
17932
|
return { text: readArgumentDescriptor(descriptor), from: ` (read from ${path})` };
|
|
17208
17933
|
} finally {
|
|
17209
|
-
|
|
17934
|
+
closeSync2(descriptor);
|
|
17210
17935
|
}
|
|
17211
17936
|
} catch (error) {
|
|
17212
17937
|
throw new SimApiError(`--${flagName} cannot read ${path}: ${error.message}${literalAtHint(error, path)}`, 0);
|
|
@@ -18511,7 +19236,7 @@ Examples:
|
|
|
18511
19236
|
import { once as once2 } from "node:events";
|
|
18512
19237
|
import { createWriteStream, rmSync as rmSync2 } from "node:fs";
|
|
18513
19238
|
import { link, lstat, mkdtemp, readlink, rename, rm } from "node:fs/promises";
|
|
18514
|
-
import { dirname as
|
|
19239
|
+
import { dirname as dirname4, join as join3, resolve as resolve2 } from "node:path";
|
|
18515
19240
|
import { Readable } from "node:stream";
|
|
18516
19241
|
import { pipeline } from "node:stream/promises";
|
|
18517
19242
|
function writeFailure(path, error) {
|
|
@@ -18543,7 +19268,7 @@ async function forcedPublicationTarget(target) {
|
|
|
18543
19268
|
}
|
|
18544
19269
|
if (!metadata.isSymbolicLink())
|
|
18545
19270
|
return candidate;
|
|
18546
|
-
candidate = resolve2(
|
|
19271
|
+
candidate = resolve2(dirname4(candidate), await readlink(candidate));
|
|
18547
19272
|
}
|
|
18548
19273
|
}
|
|
18549
19274
|
function normalizedWriteFailure(target, error) {
|
|
@@ -18596,8 +19321,8 @@ async function saveStagedFile(body, target, force) {
|
|
|
18596
19321
|
try {
|
|
18597
19322
|
try {
|
|
18598
19323
|
const publicationTarget = force ? await forcedPublicationTarget(target) : target;
|
|
18599
|
-
temporaryDirectory = await mkdtemp(
|
|
18600
|
-
const temporaryPath =
|
|
19324
|
+
temporaryDirectory = await mkdtemp(join3(dirname4(publicationTarget), ".sim-download-"));
|
|
19325
|
+
const temporaryPath = join3(temporaryDirectory, "payload");
|
|
18601
19326
|
await streamToFile(body, createWriteStream(temporaryPath, { flags: "wx" }), target);
|
|
18602
19327
|
if (force) {
|
|
18603
19328
|
await rename(temporaryPath, publicationTarget);
|
|
@@ -18695,7 +19420,7 @@ function attachFileGet(files) {
|
|
|
18695
19420
|
}
|
|
18696
19421
|
|
|
18697
19422
|
// src/transfer/local-file.ts
|
|
18698
|
-
import { constants } from "node:fs";
|
|
19423
|
+
import { constants as constants2 } from "node:fs";
|
|
18699
19424
|
import { access, stat } from "node:fs/promises";
|
|
18700
19425
|
import { basename } from "node:path";
|
|
18701
19426
|
var CONTENT_TYPES = {
|
|
@@ -18736,7 +19461,7 @@ async function localFile(path, override) {
|
|
|
18736
19461
|
const stats = await stat(path);
|
|
18737
19462
|
if (!stats.isFile())
|
|
18738
19463
|
throw new SimApiError(`${path} is not a regular file`, 0);
|
|
18739
|
-
await access(path,
|
|
19464
|
+
await access(path, constants2.R_OK);
|
|
18740
19465
|
size = stats.size;
|
|
18741
19466
|
} catch (error) {
|
|
18742
19467
|
if (error instanceof SimApiError)
|
|
@@ -18907,7 +19632,7 @@ function attachKnowledgeDocumentUpload(documents) {
|
|
|
18907
19632
|
}
|
|
18908
19633
|
|
|
18909
19634
|
// src/commands/protocol/knowledge-export.ts
|
|
18910
|
-
import { basename as basename2, join as
|
|
19635
|
+
import { basename as basename2, join as join4 } from "node:path";
|
|
18911
19636
|
function attachmentFileName(contentDisposition) {
|
|
18912
19637
|
if (!contentDisposition)
|
|
18913
19638
|
return null;
|
|
@@ -18949,7 +19674,7 @@ function attachKnowledgeExport(knowledge) {
|
|
|
18949
19674
|
await streamToStdout(response.body);
|
|
18950
19675
|
return;
|
|
18951
19676
|
}
|
|
18952
|
-
const target = options.outputFile ??
|
|
19677
|
+
const target = options.outputFile ?? join4(process.cwd(), attachmentFileName(response.headers.get("content-disposition")) ?? `${knowledgeBaseId}.simkb.zip`);
|
|
18953
19678
|
await saveToFile(response.body, target, Boolean(options.force));
|
|
18954
19679
|
printProtocolResult(profile.output, {
|
|
18955
19680
|
id: knowledgeBaseId,
|
|
@@ -20087,341 +20812,252 @@ async function setSecret(name, options, command, redactionSpellings) {
|
|
|
20087
20812
|
body: {
|
|
20088
20813
|
workspaceId: client.requireWorkspace(),
|
|
20089
20814
|
scope: options.scope,
|
|
20090
|
-
...value === undefined ? {} : { value },
|
|
20091
|
-
description,
|
|
20092
|
-
...unredacted === undefined ? {} : { unredacted }
|
|
20093
|
-
}
|
|
20094
|
-
});
|
|
20095
|
-
renderResult("setSecret", profile.output, response.data, SECRET_RESULT);
|
|
20096
|
-
}
|
|
20097
|
-
function attachSecretCommands(program) {
|
|
20098
|
-
const secrets = program.commands.find((command) => command.name() === "secrets");
|
|
20099
|
-
if (!secrets)
|
|
20100
|
-
throw new Error("The generated secrets command group is missing");
|
|
20101
|
-
const redactionSpellings = new Set;
|
|
20102
|
-
secrets.command("set").argument("<name>", "Secret name, as referenced in workflows").description(describeOperation(V2_OPERATIONS.setSecret, "Create or replace a named secret")).addOption(new Option("--scope <scope>", "Secret ownership scope (required)").choices([...SECRET_SCOPES]).makeOptionMandatory()).option("--value <value|@file>", "Secret value. Passing it inline exposes it to shell history and process listings; @path reads it from a file and @- from stdin, verbatim — a trailing newline is part of the value, so write the file with printf rather than echo. Prefix a literal leading @ with a second one").option("--description <description>", "What the secret is for, shown to teammates; workspace scope only. Omit to leave an existing description unchanged").option("--unredacted", `${V2_OPERATIONS.setSecret.body.unredacted.describe} Pass --no-unredacted to restore redaction`).option("--no-unredacted", "Send --unredacted as false").on("option:unredacted", () => redactionSpellings.add("--unredacted")).on("option:no-unredacted", () => redactionSpellings.add("--no-unredacted")).action((name, options, command) => setSecret(name, options, command, redactionSpellings));
|
|
20103
|
-
}
|
|
20104
|
-
|
|
20105
|
-
// src/update/check.ts
|
|
20106
|
-
import { spawn as spawn2 } from "node:child_process";
|
|
20107
|
-
import {
|
|
20108
|
-
closeSync as closeSync2,
|
|
20109
|
-
constants as constants2,
|
|
20110
|
-
fstatSync as fstatSync2,
|
|
20111
|
-
lstatSync,
|
|
20112
|
-
mkdirSync as mkdirSync2,
|
|
20113
|
-
openSync as openSync2,
|
|
20114
|
-
readSync as readSync2,
|
|
20115
|
-
renameSync as renameSync2,
|
|
20116
|
-
unlinkSync,
|
|
20117
|
-
writeFileSync as writeFileSync2
|
|
20118
|
-
} from "node:fs";
|
|
20119
|
-
import { dirname as dirname3 } from "node:path";
|
|
20120
|
-
import { fileURLToPath } from "node:url";
|
|
20121
|
-
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
20122
|
-
var REGISTRY_TIMEOUT_MS = 1000;
|
|
20123
|
-
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
20124
|
-
var PACKAGE_NAME = "sim";
|
|
20125
|
-
var DIST_TAGS_PATH = `-/package/${PACKAGE_NAME}/dist-tags`;
|
|
20126
|
-
var MAX_RESPONSE_BYTES = 64 * 1024;
|
|
20127
|
-
var MAX_CACHE_BYTES = 4 * 1024;
|
|
20128
|
-
var STABLE_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
20129
|
-
function parseStableVersion(version) {
|
|
20130
|
-
const match = STABLE_VERSION_PATTERN.exec(version);
|
|
20131
|
-
if (!match)
|
|
20132
|
-
return null;
|
|
20133
|
-
const parsed = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
20134
|
-
return parsed.every(Number.isSafeInteger) ? parsed : null;
|
|
20135
|
-
}
|
|
20136
|
-
function isNewerVersion(candidate, current) {
|
|
20137
|
-
if (candidate[0] !== current[0])
|
|
20138
|
-
return candidate[0] > current[0];
|
|
20139
|
-
if (candidate[1] !== current[1])
|
|
20140
|
-
return candidate[1] > current[1];
|
|
20141
|
-
return candidate[2] > current[2];
|
|
20142
|
-
}
|
|
20143
|
-
var CI_VARIABLES = [
|
|
20144
|
-
"CI",
|
|
20145
|
-
"GITHUB_ACTIONS",
|
|
20146
|
-
"JENKINS_URL",
|
|
20147
|
-
"TEAMCITY_VERSION",
|
|
20148
|
-
"BUILDKITE"
|
|
20149
|
-
];
|
|
20150
|
-
var CACHE_VERSION = 1;
|
|
20151
|
-
var cacheWriteSequence = 0;
|
|
20152
|
-
function isEnabled(value) {
|
|
20153
|
-
if (value === undefined)
|
|
20154
|
-
return false;
|
|
20155
|
-
const normalized = value.trim().toLowerCase();
|
|
20156
|
-
return normalized !== "" && normalized !== "0" && normalized !== "false";
|
|
20157
|
-
}
|
|
20158
|
-
function isProjectLocalInstall(modulePath, cwd) {
|
|
20159
|
-
const normalizedModulePath = normalizeModulePath(modulePath);
|
|
20160
|
-
const nodeModulesIndex = normalizedModulePath.indexOf("/node_modules/");
|
|
20161
|
-
if (nodeModulesIndex < 0)
|
|
20162
|
-
return false;
|
|
20163
|
-
const installRoot = normalizedModulePath.slice(0, nodeModulesIndex);
|
|
20164
|
-
const workingDirectory = normalizeModulePath(cwd).replace(/\/+$/, "");
|
|
20165
|
-
return workingDirectory === installRoot || workingDirectory.startsWith(`${installRoot}/`);
|
|
20166
|
-
}
|
|
20167
|
-
function isUnadvisableInstall(modulePath, env, cwd) {
|
|
20168
|
-
const normalized = normalizeModulePath(modulePath);
|
|
20169
|
-
return env.npm_command === "exec" || normalized.includes("/_npx/") || normalized.includes("/packages/sim-cli/") || isProjectLocalInstall(modulePath, cwd);
|
|
20170
|
-
}
|
|
20171
|
-
function normalizeModulePath(modulePath) {
|
|
20172
|
-
return modulePath.replace(/\\/g, "/").toLowerCase();
|
|
20173
|
-
}
|
|
20174
|
-
function registryUrl(env) {
|
|
20175
|
-
const fallback = new URL(DIST_TAGS_PATH, DEFAULT_REGISTRY);
|
|
20176
|
-
const configured = env.npm_config_registry?.trim();
|
|
20177
|
-
if (!configured)
|
|
20178
|
-
return fallback;
|
|
20179
|
-
try {
|
|
20180
|
-
const base = new URL(configured);
|
|
20181
|
-
if (base.protocol !== "http:" && base.protocol !== "https:")
|
|
20182
|
-
return null;
|
|
20183
|
-
if (base.username || base.password)
|
|
20184
|
-
return null;
|
|
20185
|
-
base.pathname = `${base.pathname.replace(/\/$/, "")}/${DIST_TAGS_PATH}`;
|
|
20186
|
-
return base;
|
|
20187
|
-
} catch {
|
|
20188
|
-
return null;
|
|
20189
|
-
}
|
|
20815
|
+
...value === undefined ? {} : { value },
|
|
20816
|
+
description,
|
|
20817
|
+
...unredacted === undefined ? {} : { unredacted }
|
|
20818
|
+
}
|
|
20819
|
+
});
|
|
20820
|
+
renderResult("setSecret", profile.output, response.data, SECRET_RESULT);
|
|
20190
20821
|
}
|
|
20191
|
-
|
|
20192
|
-
|
|
20193
|
-
|
|
20194
|
-
|
|
20195
|
-
|
|
20822
|
+
function attachSecretCommands(program) {
|
|
20823
|
+
const secrets = program.commands.find((command) => command.name() === "secrets");
|
|
20824
|
+
if (!secrets)
|
|
20825
|
+
throw new Error("The generated secrets command group is missing");
|
|
20826
|
+
const redactionSpellings = new Set;
|
|
20827
|
+
secrets.command("set").argument("<name>", "Secret name, as referenced in workflows").description(describeOperation(V2_OPERATIONS.setSecret, "Create or replace a named secret")).addOption(new Option("--scope <scope>", "Secret ownership scope (required)").choices([...SECRET_SCOPES]).makeOptionMandatory()).option("--value <value|@file>", "Secret value. Passing it inline exposes it to shell history and process listings; @path reads it from a file and @- from stdin, verbatim — a trailing newline is part of the value, so write the file with printf rather than echo. Prefix a literal leading @ with a second one").option("--description <description>", "What the secret is for, shown to teammates; workspace scope only. Omit to leave an existing description unchanged").option("--unredacted", `${V2_OPERATIONS.setSecret.body.unredacted.describe} Pass --no-unredacted to restore redaction`).option("--no-unredacted", "Send --unredacted as false").on("option:unredacted", () => redactionSpellings.add("--unredacted")).on("option:no-unredacted", () => redactionSpellings.add("--no-unredacted")).action((name, options, command) => setSecret(name, options, command, redactionSpellings));
|
|
20828
|
+
}
|
|
20829
|
+
// src/telemetry/transport.ts
|
|
20830
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
20831
|
+
var BUILT_IN_KEY = process.env.SIM_CLI_TELEMETRY_KEY;
|
|
20832
|
+
var BUILT_IN_HOST = process.env.SIM_CLI_TELEMETRY_HOST;
|
|
20833
|
+
var DEFAULT_INGEST_HOST = "https://us.i.posthog.com";
|
|
20834
|
+
var CAPTURE_PATH = "/i/v0/e/";
|
|
20835
|
+
var SEND_TIMEOUT_MS = 5000;
|
|
20836
|
+
var PAYLOAD_VARIABLE = "SIM_TELEMETRY_CAPTURE";
|
|
20837
|
+
function builtInIngestTarget() {
|
|
20838
|
+
if (!BUILT_IN_KEY)
|
|
20839
|
+
return;
|
|
20840
|
+
return { key: BUILT_IN_KEY, host: BUILT_IN_HOST || DEFAULT_INGEST_HOST };
|
|
20841
|
+
}
|
|
20842
|
+
var SEND_SCRIPT = `
|
|
20196
20843
|
try {
|
|
20197
|
-
const { url,
|
|
20844
|
+
const { url, body, timeoutMs } = JSON.parse(process.env[${JSON.stringify(PAYLOAD_VARIABLE)}])
|
|
20198
20845
|
const deadline = setTimeout(() => process.exit(1), timeoutMs)
|
|
20199
|
-
|
|
20200
|
-
|
|
20201
|
-
|
|
20202
|
-
|
|
20203
|
-
|
|
20204
|
-
}
|
|
20205
|
-
|
|
20206
|
-
const reader = response.body.getReader()
|
|
20207
|
-
const chunks = []
|
|
20208
|
-
let seen = 0
|
|
20209
|
-
|
|
20210
|
-
while (true) {
|
|
20211
|
-
const { done, value } = await reader.read()
|
|
20212
|
-
if (done) break
|
|
20213
|
-
seen += value.byteLength
|
|
20214
|
-
if (seen > maxResponseBytes) {
|
|
20215
|
-
process.exit(1)
|
|
20216
|
-
}
|
|
20217
|
-
chunks.push(Buffer.from(value))
|
|
20218
|
-
}
|
|
20219
|
-
|
|
20846
|
+
await fetch(url, {
|
|
20847
|
+
method: 'POST',
|
|
20848
|
+
headers: { 'content-type': 'application/json' },
|
|
20849
|
+
body,
|
|
20850
|
+
redirect: 'error',
|
|
20851
|
+
})
|
|
20220
20852
|
clearTimeout(deadline)
|
|
20221
|
-
process.
|
|
20853
|
+
process.exit(0)
|
|
20222
20854
|
} catch {
|
|
20223
20855
|
process.exit(1)
|
|
20224
20856
|
}
|
|
20225
20857
|
`;
|
|
20226
|
-
function
|
|
20227
|
-
const
|
|
20228
|
-
|
|
20229
|
-
|
|
20230
|
-
|
|
20231
|
-
delete env[key];
|
|
20232
|
-
}
|
|
20233
|
-
return env;
|
|
20234
|
-
}
|
|
20235
|
-
function requestRegistry(url, { headers, maxResponseBytes, timeoutMs }) {
|
|
20236
|
-
return new Promise((resolve, reject) => {
|
|
20237
|
-
const proxyArguments = process.execArgv.filter((argument) => argument === "--use-env-proxy" || argument === "--no-use-env-proxy");
|
|
20238
|
-
const child = spawn2(process.execPath, [...proxyArguments, "--input-type=module", "--eval", REGISTRY_REQUEST_SCRIPT], {
|
|
20239
|
-
env: registryProcessEnv(),
|
|
20240
|
-
killSignal: "SIGKILL",
|
|
20241
|
-
stdio: ["pipe", "pipe", "ignore"],
|
|
20242
|
-
timeout: timeoutMs,
|
|
20243
|
-
windowsHide: true
|
|
20244
|
-
});
|
|
20245
|
-
const chunks = [];
|
|
20246
|
-
let failed = false;
|
|
20247
|
-
let seen = 0;
|
|
20248
|
-
child.stdout.on("data", (chunk) => {
|
|
20249
|
-
seen += chunk.byteLength;
|
|
20250
|
-
if (seen > maxResponseBytes) {
|
|
20251
|
-
failed = true;
|
|
20252
|
-
child.kill("SIGKILL");
|
|
20253
|
-
return;
|
|
20254
|
-
}
|
|
20255
|
-
chunks.push(chunk);
|
|
20256
|
-
});
|
|
20257
|
-
child.stdout.on("error", () => {
|
|
20258
|
-
failed = true;
|
|
20259
|
-
child.kill("SIGKILL");
|
|
20260
|
-
});
|
|
20261
|
-
child.stdin.on("error", () => {});
|
|
20262
|
-
child.once("error", reject);
|
|
20263
|
-
child.once("close", (code) => {
|
|
20264
|
-
resolve(code === 0 && !failed ? Buffer.concat(chunks).toString("utf8") : null);
|
|
20265
|
-
});
|
|
20266
|
-
child.stdin.end(JSON.stringify({ headers, maxResponseBytes, timeoutMs, url: url.href }));
|
|
20858
|
+
function sendCapture(target, request, spawnSender = spawn4) {
|
|
20859
|
+
const payload = JSON.stringify({
|
|
20860
|
+
url: new URL(CAPTURE_PATH, target.host).href,
|
|
20861
|
+
body: JSON.stringify(request),
|
|
20862
|
+
timeoutMs: SEND_TIMEOUT_MS
|
|
20267
20863
|
});
|
|
20268
|
-
}
|
|
20269
|
-
async function fetchDistTags(env, request) {
|
|
20270
20864
|
try {
|
|
20271
|
-
const
|
|
20272
|
-
|
|
20273
|
-
|
|
20274
|
-
|
|
20275
|
-
|
|
20276
|
-
maxResponseBytes: MAX_RESPONSE_BYTES,
|
|
20277
|
-
timeoutMs: REGISTRY_TIMEOUT_MS
|
|
20865
|
+
const child = spawnSender(process.execPath, [...proxyExecArgv(), "--input-type=module", "--eval", SEND_SCRIPT], {
|
|
20866
|
+
detached: true,
|
|
20867
|
+
env: childProcessEnv(["sim_api_key"], { [PAYLOAD_VARIABLE]: payload }),
|
|
20868
|
+
stdio: "ignore",
|
|
20869
|
+
windowsHide: true
|
|
20278
20870
|
});
|
|
20279
|
-
|
|
20280
|
-
|
|
20281
|
-
|
|
20282
|
-
|
|
20283
|
-
|
|
20284
|
-
|
|
20285
|
-
|
|
20286
|
-
|
|
20287
|
-
|
|
20288
|
-
|
|
20289
|
-
|
|
20290
|
-
|
|
20291
|
-
|
|
20871
|
+
child.once("error", () => {});
|
|
20872
|
+
child.unref();
|
|
20873
|
+
} catch {}
|
|
20874
|
+
}
|
|
20875
|
+
|
|
20876
|
+
// src/telemetry/invocation.ts
|
|
20877
|
+
var COMMAND_EVENT = "cli_command_executed";
|
|
20878
|
+
var LIBRARY_NAME = "sim-cli";
|
|
20879
|
+
var EXCLUDED_ROOT_COMMAND = "telemetry";
|
|
20880
|
+
var USAGE_DATA_DOCS_URL = "https://docs.sim.ai/cli/usage-data";
|
|
20881
|
+
var FIRST_RUN_NOTICE = [
|
|
20882
|
+
"Sim collects anonymous usage data to improve the CLI: which commands run, whether",
|
|
20883
|
+
"they succeed, and how long they take. Nothing you type is sent.",
|
|
20884
|
+
`Learn more: ${USAGE_DATA_DOCS_URL}`,
|
|
20885
|
+
"Turn it off: sim telemetry disable",
|
|
20886
|
+
""
|
|
20887
|
+
].join(`
|
|
20888
|
+
`);
|
|
20889
|
+
function commandPath2(command) {
|
|
20890
|
+
const names = [];
|
|
20891
|
+
for (let current = command;current?.parent; current = current.parent) {
|
|
20892
|
+
names.unshift(current.name());
|
|
20292
20893
|
}
|
|
20894
|
+
return names;
|
|
20293
20895
|
}
|
|
20294
|
-
function
|
|
20295
|
-
|
|
20296
|
-
|
|
20297
|
-
|
|
20298
|
-
|
|
20299
|
-
|
|
20300
|
-
|
|
20301
|
-
|
|
20302
|
-
|
|
20303
|
-
}
|
|
20304
|
-
const buffer = Buffer.allocUnsafe(MAX_CACHE_BYTES + 1);
|
|
20305
|
-
let bytesRead = 0;
|
|
20306
|
-
while (bytesRead < buffer.byteLength) {
|
|
20307
|
-
const count = readSync2(descriptor, buffer, bytesRead, buffer.byteLength - bytesRead, bytesRead);
|
|
20308
|
-
if (count === 0)
|
|
20309
|
-
break;
|
|
20310
|
-
bytesRead += count;
|
|
20311
|
-
}
|
|
20312
|
-
if (bytesRead > MAX_CACHE_BYTES)
|
|
20313
|
-
return null;
|
|
20314
|
-
const parsed = JSON.parse(buffer.subarray(0, bytesRead).toString("utf8"));
|
|
20315
|
-
if (typeof parsed !== "object" || parsed === null)
|
|
20316
|
-
return null;
|
|
20317
|
-
const entry = parsed;
|
|
20318
|
-
if (entry.version !== CACHE_VERSION)
|
|
20319
|
-
return null;
|
|
20320
|
-
if (typeof entry.checkedAt !== "string" || Number.isNaN(Date.parse(entry.checkedAt)))
|
|
20321
|
-
return null;
|
|
20322
|
-
return {
|
|
20323
|
-
version: CACHE_VERSION,
|
|
20324
|
-
checkedAt: entry.checkedAt
|
|
20325
|
-
};
|
|
20326
|
-
} catch {
|
|
20327
|
-
return null;
|
|
20328
|
-
} finally {
|
|
20329
|
-
if (descriptor !== null) {
|
|
20330
|
-
try {
|
|
20331
|
-
closeSync2(descriptor);
|
|
20332
|
-
} catch {}
|
|
20896
|
+
function typedFlags(command) {
|
|
20897
|
+
const flags = new Set;
|
|
20898
|
+
for (let current = command;current; current = current.parent) {
|
|
20899
|
+
for (const option of current.options) {
|
|
20900
|
+
if (current.getOptionValueSource(option.attributeName()) !== "cli")
|
|
20901
|
+
continue;
|
|
20902
|
+
const name = option.long ?? option.short;
|
|
20903
|
+
if (name)
|
|
20904
|
+
flags.add(name);
|
|
20333
20905
|
}
|
|
20334
20906
|
}
|
|
20907
|
+
return [...flags];
|
|
20335
20908
|
}
|
|
20336
|
-
function
|
|
20337
|
-
let descriptor = null;
|
|
20338
|
-
let temporaryCreated = false;
|
|
20339
|
-
const temporaryPath = `${path}.${process.pid}.${Date.now()}.${cacheWriteSequence++}.tmp`;
|
|
20909
|
+
function endpointKind(command) {
|
|
20340
20910
|
try {
|
|
20341
|
-
|
|
20342
|
-
|
|
20343
|
-
|
|
20344
|
-
|
|
20345
|
-
`);
|
|
20346
|
-
closeSync2(descriptor);
|
|
20347
|
-
descriptor = null;
|
|
20348
|
-
renameSync2(temporaryPath, path);
|
|
20349
|
-
temporaryCreated = false;
|
|
20350
|
-
} catch {} finally {
|
|
20351
|
-
if (descriptor !== null) {
|
|
20352
|
-
try {
|
|
20353
|
-
closeSync2(descriptor);
|
|
20354
|
-
} catch {}
|
|
20355
|
-
}
|
|
20356
|
-
if (temporaryCreated) {
|
|
20357
|
-
try {
|
|
20358
|
-
unlinkSync(temporaryPath);
|
|
20359
|
-
} catch {}
|
|
20360
|
-
}
|
|
20911
|
+
const hostname = new URL(profileFrom(command).endpoint).hostname;
|
|
20912
|
+
return hostname === "sim.ai" || hostname.endsWith(".sim.ai") ? "hosted" : "self_hosted";
|
|
20913
|
+
} catch {
|
|
20914
|
+
return;
|
|
20361
20915
|
}
|
|
20362
20916
|
}
|
|
20363
|
-
function
|
|
20364
|
-
|
|
20365
|
-
|
|
20366
|
-
|
|
20367
|
-
|
|
20368
|
-
const
|
|
20369
|
-
|
|
20370
|
-
|
|
20371
|
-
|
|
20372
|
-
|
|
20373
|
-
|
|
20374
|
-
}
|
|
20375
|
-
|
|
20376
|
-
|
|
20917
|
+
function failureProperties(error) {
|
|
20918
|
+
if (error === undefined)
|
|
20919
|
+
return {};
|
|
20920
|
+
if (!(error instanceof Error))
|
|
20921
|
+
return { error_name: "unknown" };
|
|
20922
|
+
const properties = { error_name: error.name };
|
|
20923
|
+
if (error instanceof SimApiError) {
|
|
20924
|
+
if (error.code)
|
|
20925
|
+
properties.error_code = error.code;
|
|
20926
|
+
if (error.status > 0)
|
|
20927
|
+
properties.http_status = error.status;
|
|
20928
|
+
}
|
|
20929
|
+
return properties;
|
|
20930
|
+
}
|
|
20931
|
+
var listenForProcessExit = (listener) => {
|
|
20932
|
+
process.once("exit", listener);
|
|
20933
|
+
};
|
|
20934
|
+
function createCommandTelemetry(options = {}) {
|
|
20935
|
+
const env = options.env ?? process.env;
|
|
20936
|
+
const ingestTarget = options.ingestTarget ?? builtInIngestTarget;
|
|
20937
|
+
const send = options.send ?? sendCapture;
|
|
20938
|
+
const now = options.now ?? (() => new Date);
|
|
20939
|
+
const elapsed = options.elapsed ?? (() => performance.now());
|
|
20940
|
+
const stdoutIsTty = options.stdoutIsTty ?? process.stdout.isTTY === true;
|
|
20941
|
+
const stderrIsTty = options.stderrIsTty ?? process.stderr.isTTY === true;
|
|
20942
|
+
const write = options.write ?? ((message) => void process.stderr.write(message));
|
|
20943
|
+
const onExit = options.onExit ?? listenForProcessExit;
|
|
20944
|
+
let recorded;
|
|
20945
|
+
function isReportable(state) {
|
|
20946
|
+
return telemetryStatus({ env, state, configured: ingestTarget() !== undefined }).enabled;
|
|
20947
|
+
}
|
|
20948
|
+
function showNoticeIfDue(state) {
|
|
20949
|
+
if (state.noticeShownAt || !stderrIsTty || isCi(env))
|
|
20950
|
+
return false;
|
|
20951
|
+
write(FIRST_RUN_NOTICE);
|
|
20952
|
+
writeTelemetryState({ ...state, noticeShownAt: now().toISOString() });
|
|
20953
|
+
return true;
|
|
20377
20954
|
}
|
|
20378
|
-
|
|
20379
|
-
|
|
20380
|
-
|
|
20381
|
-
|
|
20382
|
-
return `yarn global add ${target}`;
|
|
20383
|
-
if (agent.startsWith("bun/"))
|
|
20384
|
-
return `bun add -g ${target}`;
|
|
20385
|
-
return `npm install -g ${target}`;
|
|
20386
|
-
}
|
|
20387
|
-
async function announceUpdateIfAvailable(options = {}) {
|
|
20388
|
-
try {
|
|
20389
|
-
const env = options.env ?? process.env;
|
|
20390
|
-
const isTty = options.isTty ?? process.stderr.isTTY === true;
|
|
20391
|
-
const modulePath = options.modulePath ?? fileURLToPath(import.meta.url);
|
|
20392
|
-
const cwd = options.cwd ?? process.cwd();
|
|
20393
|
-
const now = options.now ?? new Date;
|
|
20394
|
-
if (isEnabled(env.SIM_NO_UPDATE_CHECK))
|
|
20395
|
-
return;
|
|
20396
|
-
if (!isTty)
|
|
20397
|
-
return;
|
|
20398
|
-
if (CI_VARIABLES.some((variable) => isEnabled(env[variable])))
|
|
20399
|
-
return;
|
|
20400
|
-
if (isUnadvisableInstall(modulePath, env, cwd))
|
|
20955
|
+
function complete(outcome) {
|
|
20956
|
+
const invocation = recorded;
|
|
20957
|
+
recorded = undefined;
|
|
20958
|
+
if (!invocation || invocation.noticeShown)
|
|
20401
20959
|
return;
|
|
20402
|
-
const
|
|
20403
|
-
|
|
20404
|
-
if (!current)
|
|
20960
|
+
const target = ingestTarget();
|
|
20961
|
+
if (!target)
|
|
20405
20962
|
return;
|
|
20406
|
-
const
|
|
20407
|
-
|
|
20408
|
-
if (cached && isFresh(cached, now))
|
|
20963
|
+
const state = loadTelemetryState();
|
|
20964
|
+
if (!isReportable(state))
|
|
20409
20965
|
return;
|
|
20410
|
-
const
|
|
20411
|
-
const
|
|
20412
|
-
|
|
20413
|
-
|
|
20414
|
-
|
|
20415
|
-
|
|
20966
|
+
const timestamp = now();
|
|
20967
|
+
const session = nextSession(state, timestamp);
|
|
20968
|
+
writeTelemetryState({ ...state, session });
|
|
20969
|
+
const properties = {
|
|
20970
|
+
$lib: LIBRARY_NAME,
|
|
20971
|
+
$lib_version: CLI_VERSION,
|
|
20972
|
+
$process_person_profile: false,
|
|
20973
|
+
$session_id: session.id,
|
|
20974
|
+
session_sequence: session.sequence,
|
|
20975
|
+
surface: "cli",
|
|
20976
|
+
command: invocation.command,
|
|
20977
|
+
flags: invocation.flags,
|
|
20978
|
+
arg_count: invocation.argCount,
|
|
20979
|
+
exit_code: outcome.exitCode,
|
|
20980
|
+
duration_ms: Math.round(elapsed()),
|
|
20981
|
+
...failureProperties(outcome.error),
|
|
20982
|
+
cli_version: CLI_VERSION,
|
|
20983
|
+
node_version: process.versions.node,
|
|
20984
|
+
os: process.platform,
|
|
20985
|
+
arch: process.arch,
|
|
20986
|
+
is_tty: stdoutIsTty,
|
|
20987
|
+
is_ci: isCi(env)
|
|
20988
|
+
};
|
|
20989
|
+
const kind = endpointKind(invocation.action);
|
|
20990
|
+
if (kind)
|
|
20991
|
+
properties.endpoint_kind = kind;
|
|
20992
|
+
const agent = detectCodingAgent(env);
|
|
20993
|
+
if (agent)
|
|
20994
|
+
properties.coding_agent = agent;
|
|
20995
|
+
send(target, {
|
|
20996
|
+
api_key: target.key,
|
|
20997
|
+
event: COMMAND_EVENT,
|
|
20998
|
+
distinct_id: state.deviceId,
|
|
20999
|
+
timestamp: timestamp.toISOString(),
|
|
21000
|
+
properties
|
|
20416
21001
|
});
|
|
20417
|
-
|
|
20418
|
-
|
|
20419
|
-
|
|
20420
|
-
|
|
20421
|
-
|
|
20422
|
-
|
|
20423
|
-
|
|
20424
|
-
|
|
21002
|
+
}
|
|
21003
|
+
return {
|
|
21004
|
+
observe(program) {
|
|
21005
|
+
program.hook("preAction", (_root, action) => {
|
|
21006
|
+
const path = commandPath2(action);
|
|
21007
|
+
if (path[0] === EXCLUDED_ROOT_COMMAND || !isReportable({}))
|
|
21008
|
+
return;
|
|
21009
|
+
const state = loadTelemetryState();
|
|
21010
|
+
if (!isReportable(state))
|
|
21011
|
+
return;
|
|
21012
|
+
recorded = {
|
|
21013
|
+
action,
|
|
21014
|
+
command: path.join(" "),
|
|
21015
|
+
flags: typedFlags(action),
|
|
21016
|
+
argCount: action.args.length,
|
|
21017
|
+
state,
|
|
21018
|
+
noticeShown: showNoticeIfDue(state)
|
|
21019
|
+
};
|
|
21020
|
+
});
|
|
21021
|
+
onExit((exitCode) => complete({ exitCode }));
|
|
21022
|
+
},
|
|
21023
|
+
complete
|
|
21024
|
+
};
|
|
21025
|
+
}
|
|
21026
|
+
// src/commands/telemetry.ts
|
|
21027
|
+
function describe(status) {
|
|
21028
|
+
if (status.enabled)
|
|
21029
|
+
return "Usage reporting is on.";
|
|
21030
|
+
switch (status.reason) {
|
|
21031
|
+
case "do_not_track":
|
|
21032
|
+
return `Usage reporting is off: ${DO_NOT_TRACK_VARIABLE} is set.`;
|
|
21033
|
+
case "environment":
|
|
21034
|
+
return `Usage reporting is off: ${TELEMETRY_DISABLED_VARIABLE} is set.`;
|
|
21035
|
+
case "setting":
|
|
21036
|
+
return "Usage reporting is off. Turn it on with: sim telemetry enable";
|
|
21037
|
+
case "unconfigured":
|
|
21038
|
+
return "Usage reporting is off: this build has no reporting destination.";
|
|
21039
|
+
}
|
|
21040
|
+
}
|
|
21041
|
+
function currentStatus() {
|
|
21042
|
+
return telemetryStatus({
|
|
21043
|
+
env: process.env,
|
|
21044
|
+
state: loadTelemetryState(),
|
|
21045
|
+
configured: builtInIngestTarget() !== undefined
|
|
21046
|
+
});
|
|
21047
|
+
}
|
|
21048
|
+
function setEnabled(enabled) {
|
|
21049
|
+
writeTelemetryState({ ...loadTelemetryState(), enabled });
|
|
21050
|
+
console.log(describe(currentStatus()));
|
|
21051
|
+
}
|
|
21052
|
+
function telemetryCommand() {
|
|
21053
|
+
const telemetry = new Command("telemetry").description("Control anonymous usage reporting");
|
|
21054
|
+
telemetry.command("status").description("Show whether usage reporting is on, and why not if it is off").action(() => {
|
|
21055
|
+
console.log(describe(currentStatus()));
|
|
21056
|
+
console.log(`Learn more: ${USAGE_DATA_DOCS_URL}`);
|
|
21057
|
+
});
|
|
21058
|
+
telemetry.command("enable").description("Turn usage reporting on for this machine").action(() => setEnabled(true));
|
|
21059
|
+
telemetry.command("disable").description("Turn usage reporting off for this machine").action(() => setEnabled(false));
|
|
21060
|
+
return telemetry;
|
|
20425
21061
|
}
|
|
20426
21062
|
|
|
20427
21063
|
// src/program.ts
|
|
@@ -20497,6 +21133,9 @@ function buildProgram(options = {}) {
|
|
|
20497
21133
|
program.addCommand(whoamiCommand());
|
|
20498
21134
|
program.addCommand(profilesCommand());
|
|
20499
21135
|
program.addCommand(configureCommand());
|
|
21136
|
+
const update = updateCommand();
|
|
21137
|
+
program.addCommand(update);
|
|
21138
|
+
program.addCommand(telemetryCommand());
|
|
20500
21139
|
for (const command of buildGeneratedCommands()) {
|
|
20501
21140
|
program.addCommand(command);
|
|
20502
21141
|
}
|
|
@@ -20504,54 +21143,67 @@ function buildProgram(options = {}) {
|
|
|
20504
21143
|
attachProtocolCommands(program);
|
|
20505
21144
|
attachSecretCommands(program);
|
|
20506
21145
|
program.addHelpText("after", HELP_EPILOGUE);
|
|
20507
|
-
program.hook("preAction", () =>
|
|
21146
|
+
program.hook("preAction", async (_program, command) => {
|
|
21147
|
+
if (command === update)
|
|
21148
|
+
return;
|
|
21149
|
+
await announceUpdateIfAvailable();
|
|
21150
|
+
});
|
|
20508
21151
|
refuseHelpAfterUnknownCommand(program);
|
|
20509
21152
|
assertNoReservedProgramFlags(program);
|
|
20510
21153
|
return program;
|
|
20511
21154
|
}
|
|
20512
21155
|
|
|
20513
21156
|
// src/index.ts
|
|
21157
|
+
function explainFailure(error, program) {
|
|
21158
|
+
if (error instanceof ProfileConfigError || error instanceof CliUpdateError) {
|
|
21159
|
+
console.error(source_default.red(`Error: ${sanitize(error.message)}`));
|
|
21160
|
+
return 1;
|
|
21161
|
+
}
|
|
21162
|
+
if (isRequestTimeout(error)) {
|
|
21163
|
+
console.error(source_default.red(`Error: the request timed out. ${RAISE_TIMEOUT_HINT}`));
|
|
21164
|
+
return 1;
|
|
21165
|
+
}
|
|
21166
|
+
if (error instanceof SimApiError) {
|
|
21167
|
+
let output = program.opts().output;
|
|
21168
|
+
try {
|
|
21169
|
+
output = clientFrom(program).profile.output;
|
|
21170
|
+
} catch {}
|
|
21171
|
+
if (output === "json" || output === "yaml") {
|
|
21172
|
+
const payload = {
|
|
21173
|
+
error: {
|
|
21174
|
+
code: error.code ?? "CLI_ERROR",
|
|
21175
|
+
message: error.message,
|
|
21176
|
+
...error.details === undefined ? {} : { details: error.details }
|
|
21177
|
+
}
|
|
21178
|
+
};
|
|
21179
|
+
process.stderr.write(output === "json" ? `${JSON.stringify(payload)}
|
|
21180
|
+
` : dump(payload));
|
|
21181
|
+
return error.exitCode;
|
|
21182
|
+
}
|
|
21183
|
+
console.error(source_default.red(`Error: ${sanitize(error.message)}`));
|
|
21184
|
+
if (error.code)
|
|
21185
|
+
console.error(source_default.dim(` code: ${sanitize(error.code)}`));
|
|
21186
|
+
if (error.details !== undefined) {
|
|
21187
|
+
for (const line of formatApiErrorDetails(error.details)) {
|
|
21188
|
+
console.error(source_default.dim(sanitize(line)));
|
|
21189
|
+
}
|
|
21190
|
+
}
|
|
21191
|
+
return error.exitCode;
|
|
21192
|
+
}
|
|
21193
|
+
return null;
|
|
21194
|
+
}
|
|
20514
21195
|
async function main() {
|
|
21196
|
+
const telemetry = createCommandTelemetry();
|
|
20515
21197
|
const program = buildProgram();
|
|
21198
|
+
telemetry.observe(program);
|
|
20516
21199
|
try {
|
|
20517
21200
|
await program.parseAsync(process.argv);
|
|
20518
21201
|
} catch (error) {
|
|
20519
|
-
|
|
20520
|
-
|
|
20521
|
-
|
|
20522
|
-
|
|
20523
|
-
|
|
20524
|
-
console.error(source_default.red(`Error: the request timed out. ${RAISE_TIMEOUT_HINT}`));
|
|
20525
|
-
process.exit(1);
|
|
20526
|
-
}
|
|
20527
|
-
if (error instanceof SimApiError) {
|
|
20528
|
-
let output = program.opts().output;
|
|
20529
|
-
try {
|
|
20530
|
-
output = clientFrom(program).profile.output;
|
|
20531
|
-
} catch {}
|
|
20532
|
-
if (output === "json" || output === "yaml") {
|
|
20533
|
-
const payload = {
|
|
20534
|
-
error: {
|
|
20535
|
-
code: error.code ?? "CLI_ERROR",
|
|
20536
|
-
message: error.message,
|
|
20537
|
-
...error.details === undefined ? {} : { details: error.details }
|
|
20538
|
-
}
|
|
20539
|
-
};
|
|
20540
|
-
process.stderr.write(output === "json" ? `${JSON.stringify(payload)}
|
|
20541
|
-
` : dump(payload));
|
|
20542
|
-
process.exit(error.exitCode);
|
|
20543
|
-
}
|
|
20544
|
-
console.error(source_default.red(`Error: ${sanitize(error.message)}`));
|
|
20545
|
-
if (error.code)
|
|
20546
|
-
console.error(source_default.dim(` code: ${sanitize(error.code)}`));
|
|
20547
|
-
if (error.details !== undefined) {
|
|
20548
|
-
for (const line of formatApiErrorDetails(error.details)) {
|
|
20549
|
-
console.error(source_default.dim(sanitize(line)));
|
|
20550
|
-
}
|
|
20551
|
-
}
|
|
20552
|
-
process.exit(error.exitCode);
|
|
20553
|
-
}
|
|
20554
|
-
throw error;
|
|
21202
|
+
const exitCode = explainFailure(error, program);
|
|
21203
|
+
telemetry.complete({ exitCode: exitCode ?? 1, error });
|
|
21204
|
+
if (exitCode === null)
|
|
21205
|
+
throw error;
|
|
21206
|
+
process.exit(exitCode);
|
|
20555
21207
|
}
|
|
20556
21208
|
}
|
|
20557
21209
|
main();
|