sim 2.1.14-preview.116.1 → 2.1.14
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 +18 -0
- package/dist/index.js +571 -128
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -317,6 +317,7 @@ The main environment variables are:
|
|
|
317
317
|
| `SIM_TIMEOUT_SECONDS` | Per-request timeout; `0` waits indefinitely |
|
|
318
318
|
| `SIM_DEBUG` | Print request diagnostics to stderr |
|
|
319
319
|
| `SIM_NO_UPDATE_CHECK` | Turn off update notices |
|
|
320
|
+
| `SIM_TELEMETRY_DISABLED` | Turn off anonymous usage reporting (`DO_NOT_TRACK=1` also works) |
|
|
320
321
|
|
|
321
322
|
On eligible interactive invocations, `sim` uses a daily cache before asking
|
|
322
323
|
`registry.npmjs.org` what is published under the `latest` tag and prints an
|
|
@@ -334,6 +335,22 @@ use the public default; non-empty malformed or non-HTTP(S) values fail closed.
|
|
|
334
335
|
The full list of cases where it stays quiet is in the
|
|
335
336
|
[configuration guide](https://docs.sim.ai/cli/configuration).
|
|
336
337
|
|
|
338
|
+
## Usage data
|
|
339
|
+
|
|
340
|
+
The CLI reports anonymous usage data — which commands run, whether they
|
|
341
|
+
succeed, and how long they take — so the team can see how it is used. Nothing
|
|
342
|
+
you type is sent: no argument or flag values, paths, ids, error messages, or
|
|
343
|
+
credentials. The first interactive run prints a notice and is not reported.
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
sim telemetry status
|
|
347
|
+
sim telemetry disable
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
`DO_NOT_TRACK=1` or `SIM_TELEMETRY_DISABLED=1` in the environment also turns it
|
|
351
|
+
off. The full description of what is sent is in the
|
|
352
|
+
[usage data guide](https://docs.sim.ai/cli/usage-data).
|
|
353
|
+
|
|
337
354
|
## Documentation
|
|
338
355
|
|
|
339
356
|
- [CLI documentation](https://docs.sim.ai/cli)
|
|
@@ -342,6 +359,7 @@ The full list of cases where it stays quiet is in the
|
|
|
342
359
|
- [Profiles and configuration](https://docs.sim.ai/cli/configuration)
|
|
343
360
|
- [Scripting](https://docs.sim.ai/cli/scripting)
|
|
344
361
|
- [Troubleshooting](https://docs.sim.ai/cli/troubleshooting)
|
|
362
|
+
- [Usage data](https://docs.sim.ai/cli/usage-data)
|
|
345
363
|
|
|
346
364
|
## License
|
|
347
365
|
|
package/dist/index.js
CHANGED
|
@@ -6976,6 +6976,9 @@ var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
|
6976
6976
|
|
|
6977
6977
|
// src/update/check.ts
|
|
6978
6978
|
import { spawn } from "node:child_process";
|
|
6979
|
+
import { fileURLToPath } from "node:url";
|
|
6980
|
+
|
|
6981
|
+
// src/config/json-file.ts
|
|
6979
6982
|
import {
|
|
6980
6983
|
closeSync,
|
|
6981
6984
|
constants,
|
|
@@ -6989,7 +6992,64 @@ import {
|
|
|
6989
6992
|
writeFileSync
|
|
6990
6993
|
} from "node:fs";
|
|
6991
6994
|
import { dirname } from "node:path";
|
|
6992
|
-
|
|
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
|
+
}
|
|
6993
7053
|
|
|
6994
7054
|
// src/config/paths.ts
|
|
6995
7055
|
import { homedir } from "node:os";
|
|
@@ -7006,6 +7066,39 @@ function credentialsPath() {
|
|
|
7006
7066
|
function updateCachePath() {
|
|
7007
7067
|
return join(configDir(), "update-check.json");
|
|
7008
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
|
+
}
|
|
7009
7102
|
|
|
7010
7103
|
// src/version.ts
|
|
7011
7104
|
import { readFileSync } from "node:fs";
|
|
@@ -7042,21 +7135,7 @@ function isNewerVersion(candidate, current) {
|
|
|
7042
7135
|
return candidate[1] > current[1];
|
|
7043
7136
|
return candidate[2] > current[2];
|
|
7044
7137
|
}
|
|
7045
|
-
var CI_VARIABLES = [
|
|
7046
|
-
"CI",
|
|
7047
|
-
"GITHUB_ACTIONS",
|
|
7048
|
-
"JENKINS_URL",
|
|
7049
|
-
"TEAMCITY_VERSION",
|
|
7050
|
-
"BUILDKITE"
|
|
7051
|
-
];
|
|
7052
7138
|
var CACHE_VERSION = 1;
|
|
7053
|
-
var cacheWriteSequence = 0;
|
|
7054
|
-
function isEnabled(value) {
|
|
7055
|
-
if (value === undefined)
|
|
7056
|
-
return false;
|
|
7057
|
-
const normalized = value.trim().toLowerCase();
|
|
7058
|
-
return normalized !== "" && normalized !== "0" && normalized !== "false";
|
|
7059
|
-
}
|
|
7060
7139
|
function isProjectLocalInstall(modulePath, cwd) {
|
|
7061
7140
|
const normalizedModulePath = normalizeModulePath(modulePath);
|
|
7062
7141
|
const nodeModulesIndex = normalizedModulePath.indexOf("/node_modules/");
|
|
@@ -7125,20 +7204,10 @@ try {
|
|
|
7125
7204
|
process.exit(1)
|
|
7126
7205
|
}
|
|
7127
7206
|
`;
|
|
7128
|
-
function registryProcessEnv() {
|
|
7129
|
-
const env = { ...process.env };
|
|
7130
|
-
for (const key of Object.keys(env)) {
|
|
7131
|
-
const normalized = key.toLowerCase();
|
|
7132
|
-
if (normalized === "npm_config_registry" || normalized === "sim_api_key")
|
|
7133
|
-
delete env[key];
|
|
7134
|
-
}
|
|
7135
|
-
return env;
|
|
7136
|
-
}
|
|
7137
7207
|
function requestRegistry(url, { headers, maxResponseBytes, timeoutMs }) {
|
|
7138
7208
|
return new Promise((resolve, reject) => {
|
|
7139
|
-
const
|
|
7140
|
-
|
|
7141
|
-
env: registryProcessEnv(),
|
|
7209
|
+
const child = spawn(process.execPath, [...proxyExecArgv(), "--input-type=module", "--eval", REGISTRY_REQUEST_SCRIPT], {
|
|
7210
|
+
env: childProcessEnv(["npm_config_registry", "sim_api_key"]),
|
|
7142
7211
|
killSignal: "SIGKILL",
|
|
7143
7212
|
stdio: ["pipe", "pipe", "ignore"],
|
|
7144
7213
|
timeout: timeoutMs,
|
|
@@ -7194,73 +7263,18 @@ async function fetchDistTags(env, request) {
|
|
|
7194
7263
|
}
|
|
7195
7264
|
}
|
|
7196
7265
|
function readCache(path) {
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
if (!lstatSync(path).isFile())
|
|
7200
|
-
return null;
|
|
7201
|
-
descriptor = openSync(path, constants.O_RDONLY | constants.O_NONBLOCK | constants.O_NOFOLLOW);
|
|
7202
|
-
const descriptorStats = fstatSync(descriptor);
|
|
7203
|
-
if (!descriptorStats.isFile() || descriptorStats.size > MAX_CACHE_BYTES) {
|
|
7204
|
-
return null;
|
|
7205
|
-
}
|
|
7206
|
-
const buffer = Buffer.allocUnsafe(MAX_CACHE_BYTES + 1);
|
|
7207
|
-
let bytesRead = 0;
|
|
7208
|
-
while (bytesRead < buffer.byteLength) {
|
|
7209
|
-
const count = readSync(descriptor, buffer, bytesRead, buffer.byteLength - bytesRead, bytesRead);
|
|
7210
|
-
if (count === 0)
|
|
7211
|
-
break;
|
|
7212
|
-
bytesRead += count;
|
|
7213
|
-
}
|
|
7214
|
-
if (bytesRead > MAX_CACHE_BYTES)
|
|
7215
|
-
return null;
|
|
7216
|
-
const parsed = JSON.parse(buffer.subarray(0, bytesRead).toString("utf8"));
|
|
7217
|
-
if (typeof parsed !== "object" || parsed === null)
|
|
7218
|
-
return null;
|
|
7219
|
-
const entry = parsed;
|
|
7220
|
-
if (entry.version !== CACHE_VERSION)
|
|
7221
|
-
return null;
|
|
7222
|
-
if (typeof entry.checkedAt !== "string" || Number.isNaN(Date.parse(entry.checkedAt)))
|
|
7223
|
-
return null;
|
|
7224
|
-
return {
|
|
7225
|
-
version: CACHE_VERSION,
|
|
7226
|
-
checkedAt: entry.checkedAt
|
|
7227
|
-
};
|
|
7228
|
-
} catch {
|
|
7266
|
+
const parsed = readJsonFile(path, MAX_CACHE_BYTES);
|
|
7267
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
7229
7268
|
return null;
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
}
|
|
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 };
|
|
7237
7275
|
}
|
|
7238
7276
|
function writeCache(path, entry) {
|
|
7239
|
-
|
|
7240
|
-
let temporaryCreated = false;
|
|
7241
|
-
const temporaryPath = `${path}.${process.pid}.${Date.now()}.${cacheWriteSequence++}.tmp`;
|
|
7242
|
-
try {
|
|
7243
|
-
mkdirSync(dirname(path), { recursive: true, mode: 448 });
|
|
7244
|
-
descriptor = openSync(temporaryPath, "wx", 420);
|
|
7245
|
-
temporaryCreated = true;
|
|
7246
|
-
writeFileSync(descriptor, `${JSON.stringify(entry, null, 2)}
|
|
7247
|
-
`);
|
|
7248
|
-
closeSync(descriptor);
|
|
7249
|
-
descriptor = null;
|
|
7250
|
-
renameSync(temporaryPath, path);
|
|
7251
|
-
temporaryCreated = false;
|
|
7252
|
-
} catch {} finally {
|
|
7253
|
-
if (descriptor !== null) {
|
|
7254
|
-
try {
|
|
7255
|
-
closeSync(descriptor);
|
|
7256
|
-
} catch {}
|
|
7257
|
-
}
|
|
7258
|
-
if (temporaryCreated) {
|
|
7259
|
-
try {
|
|
7260
|
-
unlinkSync(temporaryPath);
|
|
7261
|
-
} catch {}
|
|
7262
|
-
}
|
|
7263
|
-
}
|
|
7277
|
+
writeJsonFile(path, entry);
|
|
7264
7278
|
}
|
|
7265
7279
|
function isFresh(entry, now) {
|
|
7266
7280
|
const age = now.getTime() - Date.parse(entry.checkedAt);
|
|
@@ -7297,7 +7311,7 @@ async function announceUpdateIfAvailable(options = {}) {
|
|
|
7297
7311
|
return;
|
|
7298
7312
|
if (!isTty)
|
|
7299
7313
|
return;
|
|
7300
|
-
if (
|
|
7314
|
+
if (isCi(env))
|
|
7301
7315
|
return;
|
|
7302
7316
|
if (isUnadvisableInstall(modulePath, env, cwd))
|
|
7303
7317
|
return;
|
|
@@ -8007,6 +8021,191 @@ function resolveProfile(overrides = {}) {
|
|
|
8007
8021
|
}
|
|
8008
8022
|
};
|
|
8009
8023
|
}
|
|
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;
|
|
8207
|
+
}
|
|
8208
|
+
|
|
8010
8209
|
// src/http/environment.ts
|
|
8011
8210
|
var reported = new Set;
|
|
8012
8211
|
function once(key, message) {
|
|
@@ -8345,6 +8544,7 @@ class SimClient {
|
|
|
8345
8544
|
...credential?.kind === "oauth" ? { authorization: `Bearer ${credential.oauth.accessToken}` } : {},
|
|
8346
8545
|
accept: "application/json",
|
|
8347
8546
|
"user-agent": USER_AGENT,
|
|
8547
|
+
[CLIENT_INFO_HEADER]: clientInfoHeader(),
|
|
8348
8548
|
...hasBody ? { "content-type": "application/json" } : {},
|
|
8349
8549
|
...options.headers
|
|
8350
8550
|
},
|
|
@@ -20626,6 +20826,239 @@ function attachSecretCommands(program) {
|
|
|
20626
20826
|
const redactionSpellings = new Set;
|
|
20627
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));
|
|
20628
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 = `
|
|
20843
|
+
try {
|
|
20844
|
+
const { url, body, timeoutMs } = JSON.parse(process.env[${JSON.stringify(PAYLOAD_VARIABLE)}])
|
|
20845
|
+
const deadline = setTimeout(() => process.exit(1), timeoutMs)
|
|
20846
|
+
await fetch(url, {
|
|
20847
|
+
method: 'POST',
|
|
20848
|
+
headers: { 'content-type': 'application/json' },
|
|
20849
|
+
body,
|
|
20850
|
+
redirect: 'error',
|
|
20851
|
+
})
|
|
20852
|
+
clearTimeout(deadline)
|
|
20853
|
+
process.exit(0)
|
|
20854
|
+
} catch {
|
|
20855
|
+
process.exit(1)
|
|
20856
|
+
}
|
|
20857
|
+
`;
|
|
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
|
|
20863
|
+
});
|
|
20864
|
+
try {
|
|
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
|
|
20870
|
+
});
|
|
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());
|
|
20893
|
+
}
|
|
20894
|
+
return names;
|
|
20895
|
+
}
|
|
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);
|
|
20905
|
+
}
|
|
20906
|
+
}
|
|
20907
|
+
return [...flags];
|
|
20908
|
+
}
|
|
20909
|
+
function endpointKind(command) {
|
|
20910
|
+
try {
|
|
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;
|
|
20915
|
+
}
|
|
20916
|
+
}
|
|
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;
|
|
20954
|
+
}
|
|
20955
|
+
function complete(outcome) {
|
|
20956
|
+
const invocation = recorded;
|
|
20957
|
+
recorded = undefined;
|
|
20958
|
+
if (!invocation || invocation.noticeShown)
|
|
20959
|
+
return;
|
|
20960
|
+
const target = ingestTarget();
|
|
20961
|
+
if (!target)
|
|
20962
|
+
return;
|
|
20963
|
+
const state = loadTelemetryState();
|
|
20964
|
+
if (!isReportable(state))
|
|
20965
|
+
return;
|
|
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
|
|
21001
|
+
});
|
|
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;
|
|
21061
|
+
}
|
|
20629
21062
|
|
|
20630
21063
|
// src/program.ts
|
|
20631
21064
|
var PROGRAM_DESCRIPTION = "Talk to the Sim API from your terminal";
|
|
@@ -20702,6 +21135,7 @@ function buildProgram(options = {}) {
|
|
|
20702
21135
|
program.addCommand(configureCommand());
|
|
20703
21136
|
const update = updateCommand();
|
|
20704
21137
|
program.addCommand(update);
|
|
21138
|
+
program.addCommand(telemetryCommand());
|
|
20705
21139
|
for (const command of buildGeneratedCommands()) {
|
|
20706
21140
|
program.addCommand(command);
|
|
20707
21141
|
}
|
|
@@ -20720,47 +21154,56 @@ function buildProgram(options = {}) {
|
|
|
20720
21154
|
}
|
|
20721
21155
|
|
|
20722
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
|
+
}
|
|
20723
21195
|
async function main() {
|
|
21196
|
+
const telemetry = createCommandTelemetry();
|
|
20724
21197
|
const program = buildProgram();
|
|
21198
|
+
telemetry.observe(program);
|
|
20725
21199
|
try {
|
|
20726
21200
|
await program.parseAsync(process.argv);
|
|
20727
21201
|
} catch (error) {
|
|
20728
|
-
|
|
20729
|
-
|
|
20730
|
-
|
|
20731
|
-
|
|
20732
|
-
|
|
20733
|
-
console.error(source_default.red(`Error: the request timed out. ${RAISE_TIMEOUT_HINT}`));
|
|
20734
|
-
process.exit(1);
|
|
20735
|
-
}
|
|
20736
|
-
if (error instanceof SimApiError) {
|
|
20737
|
-
let output = program.opts().output;
|
|
20738
|
-
try {
|
|
20739
|
-
output = clientFrom(program).profile.output;
|
|
20740
|
-
} catch {}
|
|
20741
|
-
if (output === "json" || output === "yaml") {
|
|
20742
|
-
const payload = {
|
|
20743
|
-
error: {
|
|
20744
|
-
code: error.code ?? "CLI_ERROR",
|
|
20745
|
-
message: error.message,
|
|
20746
|
-
...error.details === undefined ? {} : { details: error.details }
|
|
20747
|
-
}
|
|
20748
|
-
};
|
|
20749
|
-
process.stderr.write(output === "json" ? `${JSON.stringify(payload)}
|
|
20750
|
-
` : dump(payload));
|
|
20751
|
-
process.exit(error.exitCode);
|
|
20752
|
-
}
|
|
20753
|
-
console.error(source_default.red(`Error: ${sanitize(error.message)}`));
|
|
20754
|
-
if (error.code)
|
|
20755
|
-
console.error(source_default.dim(` code: ${sanitize(error.code)}`));
|
|
20756
|
-
if (error.details !== undefined) {
|
|
20757
|
-
for (const line of formatApiErrorDetails(error.details)) {
|
|
20758
|
-
console.error(source_default.dim(sanitize(line)));
|
|
20759
|
-
}
|
|
20760
|
-
}
|
|
20761
|
-
process.exit(error.exitCode);
|
|
20762
|
-
}
|
|
20763
|
-
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);
|
|
20764
21207
|
}
|
|
20765
21208
|
}
|
|
20766
21209
|
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sim",
|
|
3
|
-
"version": "2.1.14
|
|
3
|
+
"version": "2.1.14",
|
|
4
4
|
"description": "Sim CLI - talk to the Sim API from your terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"imports": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"prebuild": "bun run clean",
|
|
14
|
-
"build": "bun build src/index.ts --target=node --format=esm --packages=bundle --reject-unresolved --outfile=dist/index.js",
|
|
14
|
+
"build": "bun build src/index.ts --target=node --format=esm --packages=bundle --reject-unresolved --env='SIM_CLI_TELEMETRY_*' --outfile=dist/index.js",
|
|
15
15
|
"clean": "bun -e \"import { rmSync } from 'node:fs'; rmSync('dist', { recursive: true, force: true })\"",
|
|
16
16
|
"type-check": "tsc --noEmit",
|
|
17
17
|
"lint": "biome check --write --unsafe .",
|