@kradle/cli 0.2.2 → 0.2.3

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
@@ -128,6 +128,7 @@ Run a challenge in production or studio environment:
128
128
  ```bash
129
129
  kradle challenge run <challenge-name>
130
130
  kradle challenge run <challenge-name> --studio # Run in local studio environment
131
+ kradle challenge run <team-name>:<challenge-name> # Run a public challenge from another team
131
132
  ```
132
133
 
133
134
  ## Experiment Commands
@@ -11,7 +11,6 @@ export default class Run extends Command {
11
11
  "web-url": import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
12
12
  "studio-api-url": import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
13
13
  "studio-url": import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
14
- "challenges-path": import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
15
14
  studio: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
15
  open: import("@oclif/core/interfaces").BooleanFlag<boolean>;
17
16
  };
@@ -2,7 +2,6 @@ import { Command, Flags } from "@oclif/core";
2
2
  import pc from "picocolors";
3
3
  import { ApiClient } from "../../lib/api-client.js";
4
4
  import { getChallengeSlugArgument } from "../../lib/arguments.js";
5
- import { Challenge } from "../../lib/challenge.js";
6
5
  import { getConfigFlags } from "../../lib/flags.js";
7
6
  import { loadTemplateRun, openInBrowser } from "../../lib/utils.js";
8
7
  export default class Run extends Command {
@@ -10,27 +9,31 @@ export default class Run extends Command {
10
9
  static examples = [
11
10
  "<%= config.bin %> <%= command.id %> my-challenge",
12
11
  "<%= config.bin %> <%= command.id %> my-challenge --studio",
12
+ "<%= config.bin %> <%= command.id %> team-name:my-challenge",
13
13
  ];
14
14
  static args = {
15
- challengeSlug: getChallengeSlugArgument({ description: "Challenge slug to run" }),
15
+ challengeSlug: getChallengeSlugArgument({
16
+ description: "Challenge slug to run (e.g., 'my-challenge' or 'team-name:my-challenge')",
17
+ allowTeam: true,
18
+ }),
16
19
  };
17
20
  static flags = {
18
21
  studio: Flags.boolean({ char: "s", description: "Run in studio environment", default: false }),
19
22
  open: Flags.boolean({ char: "o", description: "Open the run URL in the browser", default: false }),
20
- ...getConfigFlags("api-key", "api-url", "challenges-path", "web-url", "studio-url", "studio-api-url"),
23
+ ...getConfigFlags("api-key", "api-url", "web-url", "studio-url", "studio-api-url"),
21
24
  };
22
25
  async run() {
23
26
  const { args, flags } = await this.parse(Run);
24
27
  const apiUrl = flags.studio ? flags["studio-api-url"] : flags["api-url"];
25
28
  const studioApi = new ApiClient(apiUrl, flags["api-key"], flags.studio);
26
- const challenge = new Challenge(args.challengeSlug, flags["challenges-path"]);
29
+ const challengeSlug = args.challengeSlug;
27
30
  try {
28
31
  const { participants } = (await loadTemplateRun());
29
32
  const template = {
30
- challenge: challenge.shortSlug,
33
+ challenge: challengeSlug,
31
34
  participants,
32
35
  };
33
- this.log(pc.blue(`>> Running challenge: ${challenge.shortSlug}${flags.studio ? " (studio)" : ""}...`));
36
+ this.log(pc.blue(`>> Running challenge: ${challengeSlug}${flags.studio ? " (studio)" : ""}...`));
34
37
  const response = await studioApi.runChallenge(template);
35
38
  if (response.runIds && response.runIds.length > 0) {
36
39
  const baseUrl = flags.studio ? flags["studio-url"] : flags["web-url"];
@@ -1,8 +1,12 @@
1
1
  import type { Arg } from "@oclif/core/interfaces";
2
2
  /**
3
- * Returns a "challenge slug" argument, and validates it to be a valid challenge slug.
3
+ * Returns a "challenge slug" argument, validating it to be a valid challenge slug.
4
+ * @param description - Description for the argument
5
+ * @param required - Whether the argument is required (default: true)
6
+ * @param allowTeam - Whether to allow namespaced slugs like "team-name:my-challenge" (default: false)
4
7
  */
5
- export declare function getChallengeSlugArgument<R extends boolean = true>({ description, required, }: {
8
+ export declare function getChallengeSlugArgument<R extends boolean = true>({ description, required, allowTeam, }: {
6
9
  description: string;
7
10
  required?: R;
11
+ allowTeam?: boolean;
8
12
  }): Arg<R extends true ? string : string | undefined>;
@@ -1,15 +1,27 @@
1
1
  import { Args } from "@oclif/core";
2
- const CHALLENGE_SLUG_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
2
+ // Base pattern for a slug segment (lowercase alphanumeric with hyphens, no leading/trailing hyphens)
3
+ const SLUG_SEGMENT = "[a-z0-9]+(?:-[a-z0-9]+)*";
4
+ // Local challenge slug pattern: just the challenge name (no namespace)
5
+ const LOCAL_SLUG_REGEX = new RegExp(`^${SLUG_SEGMENT}$`);
6
+ // Full challenge slug pattern: optional namespace prefix (e.g., "team-name:") followed by the challenge slug
7
+ const NAMESPACED_SLUG_REGEX = new RegExp(`^(?:${SLUG_SEGMENT}:)?${SLUG_SEGMENT}$`);
3
8
  /**
4
- * Returns a "challenge slug" argument, and validates it to be a valid challenge slug.
9
+ * Returns a "challenge slug" argument, validating it to be a valid challenge slug.
10
+ * @param description - Description for the argument
11
+ * @param required - Whether the argument is required (default: true)
12
+ * @param allowTeam - Whether to allow namespaced slugs like "team-name:my-challenge" (default: false)
5
13
  */
6
- export function getChallengeSlugArgument({ description, required, }) {
14
+ export function getChallengeSlugArgument({ description, required, allowTeam = false, }) {
15
+ const regex = allowTeam ? NAMESPACED_SLUG_REGEX : LOCAL_SLUG_REGEX;
16
+ const errorMessage = allowTeam
17
+ ? "Challenge slugs must be lowercase alphanumeric characters and hyphens, and must not start or end with a hyphen. Optionally, a team prefix can be provided (e.g., 'team-name:my-challenge')."
18
+ : "Challenge slugs must be lowercase alphanumeric characters and hyphens, and must not start or end with a hyphen.";
7
19
  const arg = Args.string({
8
20
  description,
9
21
  required: required ?? true,
10
22
  parse: async (input) => {
11
- if (!CHALLENGE_SLUG_REGEX.test(input)) {
12
- throw new Error(`Invalid challenge slug: ${input}. Challenge slugs must be lowercase alphanumeric characters and hyphens, and must not start or end with a hyphen.`);
23
+ if (!regex.test(input)) {
24
+ throw new Error(`Invalid challenge slug: ${input}. ${errorMessage}`);
13
25
  }
14
26
  return input;
15
27
  },
@@ -86,54 +86,6 @@
86
86
  "list.js"
87
87
  ]
88
88
  },
89
- "ai-docs:api": {
90
- "aliases": [],
91
- "args": {},
92
- "description": "Output the Kradle API reference documentation for LLMs",
93
- "examples": [
94
- "<%= config.bin %> <%= command.id %>"
95
- ],
96
- "flags": {},
97
- "hasDynamicHelp": false,
98
- "hiddenAliases": [],
99
- "id": "ai-docs:api",
100
- "pluginAlias": "@kradle/cli",
101
- "pluginName": "@kradle/cli",
102
- "pluginType": "core",
103
- "strict": true,
104
- "enableJsonFlag": false,
105
- "isESM": true,
106
- "relativePath": [
107
- "dist",
108
- "commands",
109
- "ai-docs",
110
- "api.js"
111
- ]
112
- },
113
- "ai-docs:cli": {
114
- "aliases": [],
115
- "args": {},
116
- "description": "Output the Kradle CLI reference documentation for LLMs",
117
- "examples": [
118
- "<%= config.bin %> <%= command.id %>"
119
- ],
120
- "flags": {},
121
- "hasDynamicHelp": false,
122
- "hiddenAliases": [],
123
- "id": "ai-docs:cli",
124
- "pluginAlias": "@kradle/cli",
125
- "pluginName": "@kradle/cli",
126
- "pluginType": "core",
127
- "strict": true,
128
- "enableJsonFlag": false,
129
- "isESM": true,
130
- "relativePath": [
131
- "dist",
132
- "commands",
133
- "ai-docs",
134
- "cli.js"
135
- ]
136
- },
137
89
  "challenge:build": {
138
90
  "aliases": [],
139
91
  "args": {
@@ -409,7 +361,7 @@
409
361
  "aliases": [],
410
362
  "args": {
411
363
  "challengeSlug": {
412
- "description": "Challenge slug to run",
364
+ "description": "Challenge slug to run (e.g., 'my-challenge' or 'team-name:my-challenge')",
413
365
  "name": "challengeSlug",
414
366
  "required": true
415
367
  }
@@ -417,7 +369,8 @@
417
369
  "description": "Run a challenge",
418
370
  "examples": [
419
371
  "<%= config.bin %> <%= command.id %> my-challenge",
420
- "<%= config.bin %> <%= command.id %> my-challenge --studio"
372
+ "<%= config.bin %> <%= command.id %> my-challenge --studio",
373
+ "<%= config.bin %> <%= command.id %> team-name:my-challenge"
421
374
  ],
422
375
  "flags": {
423
376
  "studio": {
@@ -453,15 +406,6 @@
453
406
  "multiple": false,
454
407
  "type": "option"
455
408
  },
456
- "challenges-path": {
457
- "description": "Absolute path to the challenges directory",
458
- "env": "KRADLE_CHALLENGES_PATH",
459
- "name": "challenges-path",
460
- "default": "~/Documents/kradle-studio/challenges",
461
- "hasDynamicHelp": false,
462
- "multiple": false,
463
- "type": "option"
464
- },
465
409
  "web-url": {
466
410
  "description": "Kradle Web URL, used to display the run URL",
467
411
  "env": "KRADLE_WEB_URL",
@@ -574,6 +518,54 @@
574
518
  "watch.js"
575
519
  ]
576
520
  },
521
+ "ai-docs:api": {
522
+ "aliases": [],
523
+ "args": {},
524
+ "description": "Output the Kradle API reference documentation for LLMs",
525
+ "examples": [
526
+ "<%= config.bin %> <%= command.id %>"
527
+ ],
528
+ "flags": {},
529
+ "hasDynamicHelp": false,
530
+ "hiddenAliases": [],
531
+ "id": "ai-docs:api",
532
+ "pluginAlias": "@kradle/cli",
533
+ "pluginName": "@kradle/cli",
534
+ "pluginType": "core",
535
+ "strict": true,
536
+ "enableJsonFlag": false,
537
+ "isESM": true,
538
+ "relativePath": [
539
+ "dist",
540
+ "commands",
541
+ "ai-docs",
542
+ "api.js"
543
+ ]
544
+ },
545
+ "ai-docs:cli": {
546
+ "aliases": [],
547
+ "args": {},
548
+ "description": "Output the Kradle CLI reference documentation for LLMs",
549
+ "examples": [
550
+ "<%= config.bin %> <%= command.id %>"
551
+ ],
552
+ "flags": {},
553
+ "hasDynamicHelp": false,
554
+ "hiddenAliases": [],
555
+ "id": "ai-docs:cli",
556
+ "pluginAlias": "@kradle/cli",
557
+ "pluginName": "@kradle/cli",
558
+ "pluginType": "core",
559
+ "strict": true,
560
+ "enableJsonFlag": false,
561
+ "isESM": true,
562
+ "relativePath": [
563
+ "dist",
564
+ "commands",
565
+ "ai-docs",
566
+ "cli.js"
567
+ ]
568
+ },
577
569
  "experiment:create": {
578
570
  "aliases": [],
579
571
  "args": {
@@ -808,5 +800,5 @@
808
800
  ]
809
801
  }
810
802
  },
811
- "version": "0.2.2"
803
+ "version": "0.2.3"
812
804
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kradle/cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Kradle's CLI. Manage challenges, experiments, agents and more!",
5
5
  "keywords": [
6
6
  "cli"
@@ -260,17 +260,19 @@ Runs a challenge with configured participants.
260
260
  ```bash
261
261
  kradle challenge run <challenge-name>
262
262
  kradle challenge run <challenge-name> --studio
263
+ kradle challenge run <team-name>:<challenge-name>
263
264
  ```
264
265
 
265
266
  **Arguments:**
266
267
  | Argument | Description | Required |
267
268
  |----------|-------------|----------|
268
- | `challenge-name` | Challenge to run | Yes |
269
+ | `challenge-name` | Challenge to run. Can be a short slug (e.g., `my-challenge`) or include a team/user namespace (e.g., `team-name:my-challenge`). The namespace is useful for running public challenges owned by other teams. If no namespace is provided, it defaults to the user's own namespace. | Yes |
269
270
 
270
271
  **Flags:**
271
272
  | Flag | Description | Default |
272
273
  |------|-------------|---------|
273
274
  | `--studio` | Run in local studio environment instead of production | false |
275
+ | `--open` | Open the run URL in the browser | false |
274
276
 
275
277
  **Prerequisites:**
276
278
  - `template-run.json` must exist in project root with participant configuration
@@ -294,9 +296,12 @@ kradle challenge run <challenge-name> --studio
294
296
 
295
297
  **Examples:**
296
298
  ```bash
297
- # Run in production
299
+ # Run your own challenge in production
298
300
  kradle challenge run my-challenge
299
301
 
302
+ # Run a public challenge from another team
303
+ kradle challenge run team-kradle:battle-royale
304
+
300
305
  # Run in local studio
301
306
  kradle challenge run my-challenge --studio
302
307
  ```