@withgauge/cli 0.1.0 → 0.2.0

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 (3) hide show
  1. package/README.md +8 -2
  2. package/dist/index.js +280 -24
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @withgauge/cli
2
2
 
3
- `gauge` — the [Gauge](https://withgauge.com) command-line interface. Manage
3
+ `gauge` — the [Gauge](https://agents.withgauge.com) command-line interface. Manage
4
4
  your prompts, repositories, and agent runs, and watch runs live from your
5
5
  terminal.
6
6
 
@@ -19,12 +19,18 @@ gauge prompts list # your prompts
19
19
  gauge runs list --status running # recent & active runs
20
20
  gauge runs watch <run-id> # follow a run as the agent works
21
21
  gauge repos list # your repository catalog
22
+ gauge stats rankings -o json # brand rankings (share of voice) as JSON
22
23
  ```
23
24
 
24
25
  Run `gauge --help` (or `gauge <command> --help`) for the full command set:
25
- prompts, schedules, repos, runs, brands, tags, topics, provider keys,
26
+ prompts, schedules, repos, runs, stats, brands, tags, topics, provider keys,
26
27
  billing, and more.
27
28
 
29
+ To launch runs declaratively, `gauge apply -f <spec>.json`. Discover the spec
30
+ format without leaving the terminal: `gauge apply --example` prints a starter
31
+ spec (`gauge apply --example > battery.json`), and `gauge apply --schema` prints
32
+ its JSON Schema.
33
+
28
34
  Every read supports `-o json` for scripting. `GAUGE_API_TOKEN` overrides
29
35
  stored credentials (useful in CI). Exit codes: `0` ok · `1` error ·
30
36
  `2` usage · `3` billing-blocked.
package/dist/index.js CHANGED
@@ -16,6 +16,30 @@ __export(apply_exports, {
16
16
  import { readFileSync as readFileSync3 } from "fs";
17
17
 
18
18
  // ../packages/api-schemas/src/batteries.ts
19
+ var batteries_exports = {};
20
+ __export(batteries_exports, {
21
+ BATTERY_AGENTS: () => BATTERY_AGENTS,
22
+ BATTERY_CADENCES: () => BATTERY_CADENCES,
23
+ BATTERY_MAX_LIMITS: () => BATTERY_MAX_LIMITS,
24
+ BATTERY_SCENARIOS: () => BATTERY_SCENARIOS,
25
+ MAX_SAMPLES_PER_CYCLE: () => MAX_SAMPLES_PER_CYCLE,
26
+ batchDetailSchema: () => batchDetailSchema,
27
+ batchListQuerySchema: () => batchListQuerySchema,
28
+ batchListResponseSchema: () => batchListResponseSchema,
29
+ batchRunStatusSchema: () => batchRunStatusSchema,
30
+ batchRunSummarySchema: () => batchRunSummarySchema,
31
+ batchSummarySchema: () => batchSummarySchema,
32
+ batteryAgentSchema: () => batteryAgentSchema,
33
+ batteryApplyResponseSchema: () => batteryApplyResponseSchema,
34
+ batteryDefaultsSchema: () => batteryDefaultsSchema,
35
+ batteryLimitsSchema: () => batteryLimitsSchema,
36
+ batteryPlanPromptSchema: () => batteryPlanPromptSchema,
37
+ batteryPlanScheduleSchema: () => batteryPlanScheduleSchema,
38
+ batteryPlanSchema: () => batteryPlanSchema,
39
+ batteryPromptSpecSchema: () => batteryPromptSpecSchema,
40
+ batteryScheduleSpecSchema: () => batteryScheduleSpecSchema,
41
+ batterySpecSchema: () => batterySpecSchema
42
+ });
19
43
  import { z as z2 } from "zod";
20
44
 
21
45
  // ../packages/api-schemas/src/common.ts
@@ -632,28 +656,92 @@ var runEventSchema = z12.looseObject({
632
656
  type: z12.string()
633
657
  });
634
658
 
635
- // ../packages/api-schemas/src/tokens.ts
659
+ // ../packages/api-schemas/src/stats.ts
636
660
  import { z as z13 } from "zod";
637
- var apiTokenSchema = z13.object({
638
- id: z13.string(),
661
+ var BRAND_KINDS2 = ["OWNED", "COMPETITOR", "OTHER"];
662
+ var brandKindSchema2 = z13.enum(BRAND_KINDS2);
663
+ var brandRankingSchema = z13.object({
664
+ rank: z13.number().int(),
665
+ brandId: z13.string(),
666
+ brandName: z13.string(),
667
+ kind: brandKindSchema2,
668
+ installs: z13.number().int(),
669
+ installRate: z13.number(),
670
+ mentionRate: z13.number(),
671
+ /** Movement between the two most recent batch windows; null if not ranked in both. */
672
+ deltaRank: z13.number().int().nullable()
673
+ });
674
+ var packageRateSchema = z13.object({
675
+ ecosystem: z13.string(),
639
676
  name: z13.string(),
677
+ brandName: z13.string().optional(),
678
+ kind: brandKindSchema2.optional(),
679
+ installs: z13.number().int(),
680
+ rate: z13.number()
681
+ });
682
+ var brandRateSchema = z13.object({
683
+ brandId: z13.string(),
684
+ brandName: z13.string(),
685
+ kind: brandKindSchema2,
686
+ installs: z13.number().int(),
687
+ rate: z13.number()
688
+ });
689
+ var brandFunnelRowSchema = z13.object({
690
+ brandId: z13.string(),
691
+ brandName: z13.string(),
692
+ kind: brandKindSchema2,
693
+ mentionRate: z13.number(),
694
+ installRate: z13.number()
695
+ });
696
+ var domainRateSchema = z13.object({
697
+ domain: z13.string(),
698
+ runs: z13.number().int(),
699
+ rate: z13.number(),
700
+ requests: z13.number().int(),
701
+ deniedRequests: z13.number().int(),
702
+ brandName: z13.string().optional(),
703
+ owned: z13.boolean().optional()
704
+ });
705
+ var statsFreshnessSchema = z13.object({
706
+ /** Newest run-ingest time across the org (ISO), or null if nothing ingested. */
707
+ watermark: z13.string().nullable(),
708
+ /** Runs that succeeded recently but haven't landed in the warehouse yet. */
709
+ pending: z13.number().int(),
710
+ /** False when the freshness read itself failed (distinguish from genuine zero). */
711
+ available: z13.boolean()
712
+ });
713
+ var statsResponseSchema = (item) => z13.object({ items: z13.array(item), freshness: statsFreshnessSchema });
714
+ var rankingsResponseSchema = statsResponseSchema(brandRankingSchema);
715
+ var installsResponseSchema = statsResponseSchema(packageRateSchema);
716
+ var brandsResponseSchema = statsResponseSchema(brandRateSchema);
717
+ var funnelResponseSchema = statsResponseSchema(brandFunnelRowSchema);
718
+ var domainsResponseSchema = statsResponseSchema(domainRateSchema);
719
+
720
+ // ../packages/api-schemas/src/tokens.ts
721
+ import { z as z14 } from "zod";
722
+ var apiTokenSchema = z14.object({
723
+ id: z14.string(),
724
+ name: z14.string(),
640
725
  /** Last 4 chars of the plaintext, for recognizability (non-secret). */
641
- last4: z13.string(),
642
- expiresAt: z13.iso.datetime().nullable(),
643
- lastUsedAt: z13.iso.datetime().nullable(),
644
- createdAt: z13.iso.datetime(),
645
- revokedAt: z13.iso.datetime().nullable()
646
- });
647
- var createTokenRequestSchema = z13.object({
648
- name: z13.string().min(1).max(100),
726
+ last4: z14.string(),
727
+ expiresAt: z14.iso.datetime().nullable(),
728
+ lastUsedAt: z14.iso.datetime().nullable(),
729
+ createdAt: z14.iso.datetime(),
730
+ revokedAt: z14.iso.datetime().nullable()
731
+ });
732
+ var createTokenRequestSchema = z14.object({
733
+ name: z14.string().min(1).max(100),
649
734
  /** ISO-8601 datetime; omit for no expiry. */
650
- expiresAt: z13.iso.datetime({ offset: true }).optional()
735
+ expiresAt: z14.iso.datetime({ offset: true }).optional()
651
736
  });
652
737
  var createTokenResponseSchema = apiTokenSchema.extend({
653
- token: z13.string()
738
+ token: z14.string()
654
739
  });
655
740
  var listTokensResponseSchema = listResponseSchema(apiTokenSchema);
656
741
 
742
+ // src/commands/apply.ts
743
+ import { z as z15 } from "zod";
744
+
657
745
  // src/version.ts
658
746
  import { createRequire } from "module";
659
747
  var CLI_VERSION = createRequire(import.meta.url)("../package.json").version;
@@ -979,6 +1067,25 @@ function cell(value) {
979
1067
  }
980
1068
 
981
1069
  // src/commands/apply.ts
1070
+ var EXAMPLE_SPEC = {
1071
+ version: 1,
1072
+ expand: true,
1073
+ experiment: "my-experiment",
1074
+ defaults: { agents: ["CLAUDE_CODE"], samplesPerCycle: 3 },
1075
+ prompts: [
1076
+ {
1077
+ key: "add-healthcheck",
1078
+ text: "Add a /health endpoint that returns 200 OK.",
1079
+ scenario: "GREENFIELD"
1080
+ },
1081
+ {
1082
+ key: "migrate-to-vitest",
1083
+ text: "Migrate the test suite from Jest to Vitest.",
1084
+ scenario: "MIGRATION",
1085
+ schedules: [{ repoUrl: "https://github.com/acme/api", repoRef: "main" }]
1086
+ }
1087
+ ]
1088
+ };
982
1089
  function readSpec(path) {
983
1090
  let raw;
984
1091
  try {
@@ -998,10 +1105,18 @@ function readSpec(path) {
998
1105
  `spec is not valid JSON: ${e instanceof Error ? e.message : String(e)}`
999
1106
  );
1000
1107
  }
1001
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
1002
- throw new CliError("invalid_request", "spec must be a JSON object");
1108
+ const result = batteries_exports.batterySpecSchema.safeParse(parsed);
1109
+ if (!result.success) {
1110
+ const details = result.error.issues.map((i) => ` ${i.path.join(".") || "(spec)"}: ${i.message}`).join("\n");
1111
+ throw new CliError(
1112
+ "invalid_request",
1113
+ `not a valid battery spec:
1114
+ ${details}
1115
+
1116
+ Run \`gauge apply --schema\` for the full schema, or \`gauge apply --example\` for a starter.`
1117
+ );
1003
1118
  }
1004
- return parsed;
1119
+ return result.data;
1005
1120
  }
1006
1121
  function resolveApplyOrg(command, spec) {
1007
1122
  const { org } = command.optsWithGlobals();
@@ -1061,8 +1176,27 @@ function printApplied(res) {
1061
1176
  }
1062
1177
  }
1063
1178
  function register(program2) {
1064
- program2.command("apply").description("Apply a declarative battery spec (see specs/battery.md)").requiredOption("-f, --file <path>", "battery spec JSON file").option("--dry-run", "print the plan without applying").action(
1179
+ program2.command("apply").description(
1180
+ "Apply a declarative battery spec. Use --example to scaffold one, or --schema to print its JSON Schema."
1181
+ ).option("-f, --file <path>", "battery spec JSON file").option("--dry-run", "print the plan without applying").option("--schema", "print the battery spec JSON Schema and exit").option("--example", "print a minimal example battery spec and exit").action(
1065
1182
  async (opts, command) => {
1183
+ if (opts.schema) {
1184
+ printJson(z15.toJSONSchema(batteries_exports.batterySpecSchema));
1185
+ return;
1186
+ }
1187
+ if (opts.example) {
1188
+ printJson(EXAMPLE_SPEC);
1189
+ console.error(
1190
+ "\n# Save to battery.json, edit, then: gauge apply -f battery.json"
1191
+ );
1192
+ return;
1193
+ }
1194
+ if (!opts.file) {
1195
+ throw new CliError(
1196
+ "usage",
1197
+ "Pass -f <path> with a battery spec (or --example to scaffold one, --schema to see the schema)."
1198
+ );
1199
+ }
1066
1200
  const spec = readSpec(opts.file);
1067
1201
  const org = resolveApplyOrg(command, spec);
1068
1202
  const output = resolveOutput(command);
@@ -2562,15 +2696,132 @@ function register12(program2) {
2562
2696
  });
2563
2697
  }
2564
2698
 
2699
+ // src/commands/stats.ts
2700
+ var stats_exports2 = {};
2701
+ __export(stats_exports2, {
2702
+ register: () => register13
2703
+ });
2704
+ function addFilterOptions(cmd) {
2705
+ return cmd.option("--prompt <id>", "filter to a single prompt").option("--topic <ids>", "comma-separated topic ids").option("--tag <ids>", "comma-separated tag ids").option("--repo <urls>", "comma-separated base repo urls").option("--language <langs>", "comma-separated repo languages").option("--framework <names>", "comma-separated repo frameworks").option("--size <buckets>", "comma-separated codebase-size buckets").option("--branded", "only branded prompts").option("--unbranded", "only non-branded prompts").option("--limit <n>", "max rows (default 50)").option("--full", "return all rows (up to 1000)");
2706
+ }
2707
+ function filterQuery(opts) {
2708
+ if (opts.branded && opts.unbranded) {
2709
+ throw new CliError("usage", "Pass at most one of --branded / --unbranded.");
2710
+ }
2711
+ return {
2712
+ prompt: opts.prompt,
2713
+ topic: opts.topic,
2714
+ tag: opts.tag,
2715
+ repo: opts.repo,
2716
+ language: opts.language,
2717
+ framework: opts.framework,
2718
+ size: opts.size,
2719
+ branded: opts.branded ? "true" : opts.unbranded ? "false" : void 0,
2720
+ limit: opts.full ? "1000" : opts.limit
2721
+ };
2722
+ }
2723
+ var pct = (rate) => `${(rate * 100).toFixed(1)}%`;
2724
+ var delta = (d) => d === null || d === 0 ? "\u2014" : d > 0 ? `+${d}` : String(d);
2725
+ function noteFreshness(f) {
2726
+ if (!f.available) {
2727
+ console.error(
2728
+ "warning: analytics store is temporarily unavailable; results may be incomplete."
2729
+ );
2730
+ } else if (f.pending > 0) {
2731
+ console.error(
2732
+ `note: ${f.pending} recent run(s) still ingesting; results may not reflect them yet.`
2733
+ );
2734
+ }
2735
+ }
2736
+ async function runStats(command, resource, opts, toRow6) {
2737
+ const org = resolveOrg(command);
2738
+ const output = resolveOutput(command);
2739
+ const res = await createClient().get(
2740
+ `/api/v1/orgs/${encodeURIComponent(org)}/stats/${resource}`,
2741
+ filterQuery(opts)
2742
+ );
2743
+ if (output === "json") {
2744
+ printJson(res);
2745
+ return;
2746
+ }
2747
+ printItems(res.items.map(toRow6), "table");
2748
+ noteFreshness(res.freshness);
2749
+ }
2750
+ var rankingRow = (r) => ({
2751
+ rank: r.rank,
2752
+ brand: r.brandName,
2753
+ kind: r.kind,
2754
+ installs: r.installs,
2755
+ "install%": pct(r.installRate),
2756
+ "mention%": pct(r.mentionRate),
2757
+ delta: delta(r.deltaRank)
2758
+ });
2759
+ var packageRow = (r) => ({
2760
+ package: r.name,
2761
+ ecosystem: r.ecosystem,
2762
+ brand: r.brandName,
2763
+ kind: r.kind,
2764
+ installs: r.installs,
2765
+ rate: pct(r.rate)
2766
+ });
2767
+ var brandRow = (r) => ({
2768
+ brand: r.brandName,
2769
+ kind: r.kind,
2770
+ installs: r.installs,
2771
+ rate: pct(r.rate)
2772
+ });
2773
+ var funnelRow = (r) => ({
2774
+ brand: r.brandName,
2775
+ kind: r.kind,
2776
+ "mention%": pct(r.mentionRate),
2777
+ "install%": pct(r.installRate)
2778
+ });
2779
+ var domainRow = (r) => ({
2780
+ domain: r.domain,
2781
+ brand: r.brandName,
2782
+ runs: r.runs,
2783
+ rate: pct(r.rate),
2784
+ requests: r.requests,
2785
+ denied: r.deniedRequests
2786
+ });
2787
+ function register13(program2) {
2788
+ const group = program2.command("stats").description("Read-only analytics over your runs");
2789
+ addFilterOptions(
2790
+ group.command("rankings").description("Brands ranked by install rate")
2791
+ ).action(
2792
+ (opts, command) => runStats(command, "rankings", opts, rankingRow)
2793
+ );
2794
+ addFilterOptions(
2795
+ group.command("installs").description("Package install rates (share of voice)")
2796
+ ).action(
2797
+ (opts, command) => runStats(command, "installs", opts, packageRow)
2798
+ );
2799
+ addFilterOptions(
2800
+ group.command("brands").description("Per-brand (company-level) install rates")
2801
+ ).action(
2802
+ (opts, command) => runStats(command, "brands", opts, brandRow)
2803
+ );
2804
+ addFilterOptions(
2805
+ group.command("funnel").description("Per-brand mention rate beside install rate")
2806
+ ).action(
2807
+ (opts, command) => runStats(command, "funnel", opts, funnelRow)
2808
+ );
2809
+ addFilterOptions(
2810
+ group.command("domains").description("Outbound fetch rates by registrable domain")
2811
+ ).action(
2812
+ (opts, command) => runStats(command, "domains", opts, domainRow)
2813
+ );
2814
+ }
2815
+
2565
2816
  // src/commands/tags.ts
2566
2817
  var tags_exports2 = {};
2567
2818
  __export(tags_exports2, {
2568
- register: () => register13
2819
+ register: () => register14
2569
2820
  });
2570
2821
  function tagsPath(org) {
2571
2822
  return `/api/v1/orgs/${encodeURIComponent(org)}/tags`;
2572
2823
  }
2573
- function register13(program2) {
2824
+ function register14(program2) {
2574
2825
  const group = program2.command("tags").description("Manage org tags");
2575
2826
  group.command("list").description("List tags").action(async (_opts, cmd) => {
2576
2827
  const org = resolveOrg(cmd);
@@ -2613,12 +2864,12 @@ function register13(program2) {
2613
2864
  // src/commands/topics.ts
2614
2865
  var topics_exports2 = {};
2615
2866
  __export(topics_exports2, {
2616
- register: () => register14
2867
+ register: () => register15
2617
2868
  });
2618
2869
  function topicsPath(org) {
2619
2870
  return `/api/v1/orgs/${encodeURIComponent(org)}/topics`;
2620
2871
  }
2621
- function register14(program2) {
2872
+ function register15(program2) {
2622
2873
  const group = program2.command("topics").description("Manage org topics");
2623
2874
  group.command("list").description("List topics").action(async (_opts, cmd) => {
2624
2875
  const org = resolveOrg(cmd);
@@ -2639,9 +2890,9 @@ function register14(program2) {
2639
2890
  // src/commands/usage.ts
2640
2891
  var usage_exports = {};
2641
2892
  __export(usage_exports, {
2642
- register: () => register15
2893
+ register: () => register16
2643
2894
  });
2644
- function register15(program2) {
2895
+ function register16(program2) {
2645
2896
  program2.command("usage").description("List credit ledger entries").option("--since <window>", 'e.g. "30d", "24h", or an ISO date').option("--limit <n>", "page size (1-200)", parseLimit, 50).option("--cursor <cursor>", "resume from a previous page's nextCursor").action(
2646
2897
  async (opts, cmd) => {
2647
2898
  const org = resolveOrg(cmd);
@@ -2710,6 +2961,7 @@ for (const group of [
2710
2961
  keys_exports2,
2711
2962
  billing_exports2,
2712
2963
  usage_exports,
2964
+ stats_exports2,
2713
2965
  config_exports
2714
2966
  ]) {
2715
2967
  group.register(program);
@@ -2722,7 +2974,11 @@ try {
2722
2974
  process.exit(error.exitCode === 0 ? 0 : 2);
2723
2975
  }
2724
2976
  if (error instanceof CliError) {
2725
- process.stderr.write(`error: ${error.message}
2977
+ let message2 = error.message;
2978
+ if (error.code === "not_found" && /organization/i.test(message2) && !program.opts().org) {
2979
+ message2 += "\nThat is your configured default organization. Run `gauge orgs list` to see yours, then `gauge orgs use <org>` to update it.";
2980
+ }
2981
+ process.stderr.write(`error: ${message2}
2726
2982
  `);
2727
2983
  process.exit(error.exitCode);
2728
2984
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withgauge/cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Gauge customer CLI — prompts, repos, runs & org settings over the Gauge API",
5
5
  "private": false,
6
6
  "author": "Gauge <support@withgauge.com> (https://withgauge.com)",
@@ -11,7 +11,7 @@
11
11
  "access": "public"
12
12
  },
13
13
  "bin": {
14
- "gauge": "./dist/index.js"
14
+ "gauge": "dist/index.js"
15
15
  },
16
16
  "files": [
17
17
  "dist"