tracksiy 0.9.0 → 0.9.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.
Files changed (2) hide show
  1. package/dist/tracksiy.mjs +29 -9
  2. package/package.json +1 -1
package/dist/tracksiy.mjs CHANGED
@@ -4,7 +4,7 @@
4
4
  import { readFileSync as readFileSync2 } from "node:fs";
5
5
 
6
6
  // src/version.ts
7
- var VERSION = true ? "0.9.0" : "0.0.0-dev";
7
+ var VERSION = true ? "0.9.1" : "0.0.0-dev";
8
8
  var USER_AGENT = `tracksiy-cli/${VERSION} (node ${process.versions.node}; ${process.platform})`;
9
9
 
10
10
  // src/core/errors.ts
@@ -822,7 +822,7 @@ var monitorsList = {
822
822
  status: { type: "string", enum: ["all", "up", "down", "never"], description: "Filter by state. Default all." },
823
823
  type: { type: "string", enum: ["heartbeat", "get", "ping", "ssl", "ingest"], description: "Only this monitor type." }
824
824
  },
825
- output: "{summary{total, up, down, never, unalertable}, monitors:[{id, name, project, monitorType, url, upNow, lastCheck, overdue, alertable, checkInUrl, downReason, lastCheckDetail{status, expectedStatus, bytes, truncated, expectedTextFound, forbiddenTextFound, error, ms}}], notes[]}",
825
+ output: "{summary{total, up, down, never, unalertable}, monitors:[{id, name, slug, project, monitorType, url, upNow, lastCheck, overdue, alertable, checkInUrl, downReason, lastCheckDetail{status, expectedStatus, bytes, truncated, expectedTextFound, forbiddenTextFound, error, ms}}], notes[]}",
826
826
  text: (d) => `${kv(d.summary ?? {})}
827
827
 
828
828
  ${table(d.monitors ?? [], [
@@ -1141,6 +1141,22 @@ var BUDGET_KEYS = {
1141
1141
  minSamples: "minSamples"
1142
1142
  };
1143
1143
  var NUMERIC = /* @__PURE__ */ new Set(["max", "windowMinutes", "minSamples"]);
1144
+ BUDGET_KEYS["window_minutes"] = "windowMinutes";
1145
+ BUDGET_KEYS["min_samples"] = "minSamples";
1146
+ function normalizeBudget(raw) {
1147
+ const out = {};
1148
+ for (const [key, value] of Object.entries(raw ?? {})) {
1149
+ out[BUDGET_KEYS[key] ?? key] = value;
1150
+ }
1151
+ return out;
1152
+ }
1153
+ function budgetsBody(body) {
1154
+ const wrapped = Array.isArray(body) ? { budgets: body } : body;
1155
+ if (!wrapped || !Array.isArray(wrapped.budgets)) {
1156
+ throw usageError("bad_value", '--body must be {"budgets": [...]} or a list of budgets.', `e.g. --body '{"budgets": [{"name": "init", "transaction": "GET /api/v1/init", "metric": "p95", "max": 800, "windowMinutes": 60}]}'`);
1157
+ }
1158
+ return { ...wrapped, budgets: wrapped.budgets.map(normalizeBudget) };
1159
+ }
1144
1160
  function parseBudget(raw) {
1145
1161
  const out = {};
1146
1162
  for (const part of String(raw).split(/,(?=\s*[\w-]+=)/)) {
@@ -1192,7 +1208,7 @@ var budgetsGet = {
1192
1208
  var budgetsSet = {
1193
1209
  path: ["budgets", "set"],
1194
1210
  summary: "Declare performance budgets: told once when one is crossed and once when it is met again.",
1195
- description: `The list replaces the stored one, by name (--merge keeps the others). Metrics: ${METRICS}. max is an upper bound: ms, a 0..1 ratio for failure_rate, unitless for cls. Below min-samples the verdict is unknown, never pass. Alerts go through the project's rules with performance on (the default).`,
1211
+ description: `The list replaces the stored one, by name (--merge keeps the others). Metrics: ${METRICS}. max is an upper bound: ms, a 0..1 ratio for failure_rate, unitless for cls. Below min-samples the verdict is unknown, never pass. Alerts go through the project's rules with performance on (the default). --body takes the API's shape, {"budgets": [{"name", "metric", "max", "transaction"?, "op"?, "monitor"? (slug or id), "windowMinutes"?, "minSamples"?}]}, or a bare list; the flag spellings window and min-samples are accepted there too, and --dry-run and --merge apply to it.`,
1196
1212
  context: "project",
1197
1213
  effect: "write",
1198
1214
  idempotent: true,
@@ -1211,23 +1227,27 @@ var budgetsSet = {
1211
1227
  examples: [
1212
1228
  { command: "tracksiy budgets set --budget 'name=init,transaction=GET /api/v1/init,metric=p95,max=800'", description: "Told when the init call's p95 passes 800 ms over an hour." },
1213
1229
  { command: "tracksiy budgets set --merge --budget 'name=inp,op=ui.interaction,metric=inp,max=200,window=1440'", description: "INP p75 over a day, across every route; keeps the other budgets." },
1214
- { command: "tracksiy budgets set --merge --budget 'name=backup,monitor=db-backup-s3,metric=duration_p95,max=1200000,window=10080,min-samples=3'", description: "Told before the nightly backup gets near its max runtime." }
1230
+ { command: "tracksiy budgets set --merge --budget 'name=backup,monitor=db-backup-s3,metric=duration_p95,max=1200000,window=10080,min-samples=3'", description: "Told before the nightly backup gets near its max runtime." },
1231
+ { command: "tracksiy budgets set --body @tools/tracksiy/budgets.json --dry-run", description: "The whole declaration from a file; shows the changes, writes nothing." },
1232
+ { command: "tracksiy budgets set --merge --budget 'name=site-ttfb,monitor=41,metric=ttfb_p95,max=800'", description: "A monitor by its id (from `monitors list`), for one whose name has spaces." }
1215
1233
  ],
1216
1234
  output: "The stored budgets and `changes` [{name, action}], same shape as `budgets get`.",
1217
1235
  text: budgetsText,
1218
1236
  async run(ctx) {
1219
1237
  const path = await projectPath(ctx, "budgets");
1220
1238
  const i = ctx.input;
1221
- if (i.body) return ctx.api.send("PUT", path, i.body);
1222
- if (!i.budget?.length && !i.merge) throw usageError("missing_flag", "No --budget given.", `Pass --budget ... (repeatable), or --body. To delete every budget: --body '{"budgets": []}'.`);
1223
- let budgets = (i.budget ?? []).map(parseBudget);
1239
+ if (!i.body && !i.budget?.length && !i.merge) throw usageError("missing_flag", "No --budget given.", `Pass --budget ... (repeatable), or --body. To delete every budget: --body '{"budgets": []}'.`);
1240
+ const fromBody = i.body ? budgetsBody(i.body) : void 0;
1241
+ let budgets = fromBody ? fromBody.budgets : (i.budget ?? []).map(parseBudget);
1242
+ if (fromBody && i.budget?.length) budgets = [...budgets, ...i.budget.map(parseBudget)];
1224
1243
  if (i.merge) {
1225
1244
  const current = await ctx.api.get(path);
1226
1245
  const named = new Set(budgets.map((b) => b.name));
1227
1246
  const kept = (current.budgets ?? []).filter((b) => !named.has(b.name)).map((b) => compact({ name: b.name, transaction: b.transaction ?? void 0, op: b.op ?? void 0, monitor: b.monitor ?? void 0, metric: b.metric, max: b.max, windowMinutes: b.windowMinutes, minSamples: b.minSamples }));
1228
1247
  budgets = [...kept, ...budgets];
1229
1248
  }
1230
- return ctx.api.send("PUT", path, compact({ budgets, dryRun: i.dryRun }));
1249
+ const dryRun = i.dryRun || fromBody?.dryRun || void 0;
1250
+ return ctx.api.send("PUT", path, compact({ budgets, dryRun }));
1231
1251
  }
1232
1252
  };
1233
1253
  var budgetsCheck = {
@@ -1294,7 +1314,7 @@ var monitorsTiming = {
1294
1314
  context: "project",
1295
1315
  effect: "read",
1296
1316
  endpoint: { method: "GET", path: "/api/agent/v1/projects/{org}/{project}/monitors/{slug}/timing" },
1297
- args: [{ name: "slug", required: true, description: "The monitor's slug (its name)." }],
1317
+ args: [{ name: "slug", required: true, description: "The monitor's slug (its name; quote it when it has spaces), or its id from `monitors list`." }],
1298
1318
  flags: { since: { type: "string", value: TIME, description: "Default 24h for HTTP, 7d for jobs; compared with the window before." } },
1299
1319
  examples: [
1300
1320
  { command: "tracksiy monitors timing home", description: "Is the home page slow at the server, or on the wire?" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tracksiy",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Agent-first CLI and MCP server for Tracksiy: errors, uptime, alerts, releases and source maps, from one token.",
5
5
  "type": "module",
6
6
  "bin": {