@kradle/cli 0.0.5 → 0.0.6

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Kradle's CLI for managing Minecraft challenges, evaluations, agents, and more!
4
4
 
5
- ## Kradle - private installation
5
+ ## Installation
6
6
 
7
7
  1. Install Kradle's CLI globally
8
8
  ```
@@ -48,7 +48,7 @@ KRADLE_API_KEY=your-api-key
48
48
  KRADLE_CHALLENGES_PATH=~/Documents/kradle-studio/challenges
49
49
  ```
50
50
 
51
- ## Commands
51
+ ## Challenge Commands
52
52
 
53
53
  ### Create Challenge
54
54
 
@@ -125,7 +125,7 @@ kradle challenge multi-upload
125
125
 
126
126
  Provides an interactive UI to select multiple challenges and uploads them in parallel.
127
127
 
128
- ### Evaluations (beta)
128
+ ## Evaluations commands
129
129
 
130
130
  Plan and execute batches of runs across challenges/agents, with resumable iterations and a TUI.
131
131
 
@@ -148,6 +148,23 @@ Features:
148
148
  - Ink TUI: live status counts, elapsed times, scrollable run list; keys `q/Ctrl+C` quit, `↑/↓/j/k` move, `o` open run URL.
149
149
  - Per-iteration manifest: generated from the evaluation `config.ts` into `manifest.json` before runs start.
150
150
 
151
+ ## Publishing a New Version
152
+
153
+ The CLI uses GitHub Actions for automated releases. To publish a new version:
154
+
155
+ 1. **Go to Actions** in the GitHub repository
156
+ 2. **Select "Create Release PR"** workflow from the sidebar
157
+ 3. **Click "Run workflow"** and choose the release type:
158
+ - `patch` - Bug fixes (0.0.5 → 0.0.6)
159
+ - `minor` - New features (0.0.5 → 0.1.0)
160
+ - `major` - Breaking changes (0.0.5 → 1.0.0)
161
+ 4. **Review and merge** the automatically created PR
162
+ 5. **Done!** The package is automatically published to npm when the PR is merged
163
+
164
+ ### Setup (one-time)
165
+
166
+ For the publish workflow to work, we're using [NPM Trusted Publishers](https://docs.npmjs.com/trusted-publishers).
167
+
151
168
  ## Development
152
169
 
153
170
  ### Setup
@@ -12,7 +12,13 @@ const DEFAULT_CHALLENGE_SCHEMA = {
12
12
  objective: {
13
13
  fieldName: "success_rate",
14
14
  direction: "maximize",
15
- },
15
+ } /*
16
+ endStates: {
17
+ "red": "Red team only wins",
18
+ "blue": "Blue team only wins",
19
+ "both": "Both teams win",
20
+ "none": "No team wins",
21
+ },*/,
16
22
  };
17
23
  export class ApiClient {
18
24
  config;
@@ -1,7 +1,6 @@
1
- import { exec } from "node:child_process";
2
1
  import fs from "node:fs/promises";
3
2
  import path from "node:path";
4
- import { executeNodeCommand } from "../utils.js";
3
+ import { executeNodeCommand, openInBrowser } from "../utils.js";
5
4
  import { Runner } from "./runner.js";
6
5
  import { TUI } from "./tui.js";
7
6
  import { EvaluationMetadataSchema, ManifestSchema, ProgressSchema } from "./types.js";
@@ -195,7 +194,9 @@ export class Evaluator {
195
194
  // Load manifest
196
195
  const manifest = await this.loadManifest(iteration);
197
196
  // We have 2 mandatory tags: "eval-<evaluation-name>" and "eval-<evaluation-name>-iteration-<iteration>"
198
- const tags = [`eval-${this.name}`, `eval-${this.name}-iteration-${iteration}`, ...(manifest.tags ?? [])];
197
+ const evaluationTag = `eval-${this.name}`;
198
+ const iterationTag = `${evaluationTag}-iteration-${iteration}`;
199
+ const tags = [evaluationTag, iterationTag, ...(manifest.tags ?? [])];
199
200
  // Create runner
200
201
  this.runner = new Runner(manifest.runs, this.api, this.config.WEB_URL, {
201
202
  maxConcurrent: options.maxConcurrent,
@@ -232,6 +233,9 @@ export class Evaluator {
232
233
  if (errors?.length > 0) {
233
234
  throw new Error(`${errors.map((error) => error.error).join("\n\n")}`);
234
235
  }
236
+ if (options.openMetabase ?? true) {
237
+ openInBrowser(`https://daunt-fair.metabaseapp.com/dashboard/10-runs-analysis&tags=${iterationTag}`);
238
+ }
235
239
  }
236
240
  /**
237
241
  * Handle state change from runner
@@ -258,18 +262,7 @@ export class Evaluator {
258
262
  openRun(index) {
259
263
  const url = this.runner?.getRunUrl(index);
260
264
  if (url) {
261
- const platform = process.platform;
262
- let command;
263
- if (platform === "darwin") {
264
- command = `open "${url}"`;
265
- }
266
- else if (platform === "win32") {
267
- command = `start "${url}"`;
268
- }
269
- else {
270
- command = `xdg-open "${url}"`;
271
- }
272
- exec(command);
265
+ openInBrowser(url);
273
266
  }
274
267
  }
275
268
  }
@@ -1,4 +1,4 @@
1
- export * from "./types.js";
2
1
  export { Evaluator } from "./evaluator.js";
3
2
  export { Runner } from "./runner.js";
4
3
  export { TUI } from "./tui.js";
4
+ export * from "./types.js";
@@ -1,4 +1,4 @@
1
- export * from "./types.js";
2
1
  export { Evaluator } from "./evaluator.js";
3
2
  export { Runner } from "./runner.js";
4
3
  export { TUI } from "./tui.js";
4
+ export * from "./types.js";
@@ -35,6 +35,7 @@ const RenderRunLine = ({ state, total, isSelected, padding, }) => {
35
35
  const agents = state.config.participants.map((p) => p.agent.split(":").pop() ?? p.agent).join(", ");
36
36
  const summary = `${state.config.challenge_slug} (${agents})`;
37
37
  const maxSummaryLength = getVisibleColumns() - indexLabel.length - statusLabel.length - (elapsedLabel ? elapsedLabel.length : 0) - 4; // 4 for the spaces and emoji
38
+ // biome-ignore lint/style/useTemplate: template literal would be less readable
38
39
  const summaryText = summary.length > maxSummaryLength ? summary.slice(0, maxSummaryLength - 1) + "…" : summary;
39
40
  return (_jsxs(Text, { inverse: isSelected, children: [_jsx(Text, { color: color, children: icon }), " ", indexLabel, " ", _jsx(Text, { color: color, children: statusLabel }), elapsedLabel ? (_jsxs(_Fragment, { children: [" ", _jsx(Text, { dimColor: true, children: elapsedLabel })] })) : null, " ", _jsx(Text, { dimColor: true, children: summaryText })] }));
40
41
  };
@@ -120,6 +120,7 @@ export type EvaluationMetadata = z.infer<typeof EvaluationMetadataSchema>;
120
120
  export interface EvaluationOptions {
121
121
  new: boolean;
122
122
  maxConcurrent: number;
123
+ openMetabase?: boolean;
123
124
  }
124
125
  export declare const STATUS_ICONS: Record<RunStatus, {
125
126
  icon: string;
@@ -35,6 +35,7 @@ export declare const ChallengeSchema: z.ZodObject<{
35
35
  minimize: "minimize";
36
36
  }>;
37
37
  }, z.core.$strip>;
38
+ endStates: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
38
39
  creationTime: z.ZodOptional<z.ZodString>;
39
40
  updateTime: z.ZodOptional<z.ZodString>;
40
41
  creator: z.ZodOptional<z.ZodString>;
@@ -76,6 +77,7 @@ export declare const ChallengesResponseSchema: z.ZodObject<{
76
77
  minimize: "minimize";
77
78
  }>;
78
79
  }, z.core.$strip>;
80
+ endStates: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
79
81
  creationTime: z.ZodOptional<z.ZodString>;
80
82
  updateTime: z.ZodOptional<z.ZodString>;
81
83
  creator: z.ZodOptional<z.ZodString>;
@@ -23,6 +23,7 @@ export const ChallengeSchema = z.object({
23
23
  fieldName: z.string(),
24
24
  direction: z.enum(["maximize", "minimize"]),
25
25
  }),
26
+ endStates: z.record(z.string(), z.string()).optional(),
26
27
  creationTime: z.string().optional(),
27
28
  updateTime: z.string().optional(),
28
29
  creator: z.string().optional(),
@@ -87,3 +87,10 @@ export declare function executeCommand(command: string, args: string[], options?
87
87
  * @returns A promise that resolves with the stdout of the command.
88
88
  */
89
89
  export declare function executeNodeCommand(args: string[], config: Config): Promise<string>;
90
+ /**
91
+ * Open a URL in the default browser.
92
+ * This is fire-and-forget, so we don't wait for it to complete.
93
+ *
94
+ * @param url The URL to open.
95
+ */
96
+ export declare function openInBrowser(url: string): void;
package/dist/lib/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- import { fork, spawn } from "node:child_process";
1
+ import { exec, fork, spawn } from "node:child_process";
2
2
  import fs from "node:fs/promises";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
@@ -168,3 +168,23 @@ export async function executeCommand(command, args, options) {
168
168
  export async function executeNodeCommand(args, config) {
169
169
  return executeCommand(process.execPath, args, { env: config });
170
170
  }
171
+ /**
172
+ * Open a URL in the default browser.
173
+ * This is fire-and-forget, so we don't wait for it to complete.
174
+ *
175
+ * @param url The URL to open.
176
+ */
177
+ export function openInBrowser(url) {
178
+ const platform = process.platform;
179
+ let command;
180
+ if (platform === "darwin") {
181
+ command = `open "${url}"`;
182
+ }
183
+ else if (platform === "win32") {
184
+ command = `start "${url}"`;
185
+ }
186
+ else {
187
+ command = `xdg-open "${url}"`;
188
+ }
189
+ exec(command);
190
+ }
@@ -409,5 +409,5 @@
409
409
  ]
410
410
  }
411
411
  },
412
- "version": "0.0.5"
412
+ "version": "0.0.6"
413
413
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kradle/cli",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Kradle's CLI. Manage challenges, evaluations, agents and more!",
5
5
  "keywords": [
6
6
  "cli"
@@ -24,11 +24,10 @@
24
24
  "build": "rm -rf dist && tsc",
25
25
  "watch": "rm -rf dist && tsc --watch",
26
26
  "lint": "biome check .",
27
- "lint:fix": "biome check --write .",
28
- "format": "biome format --write .",
27
+ "format": "biome format --write . && biome check --write .",
29
28
  "prepack": "sh scripts/prepack.sh",
30
29
  "postpack": "sh scripts/postpack.sh",
31
- "version": "oclif readme && git add README.md"
30
+ "version": "oclif manifest && oclif readme && git add README.md"
32
31
  },
33
32
  "dependencies": {
34
33
  "@google-cloud/storage": "^7.17.3",