kradle 0.6.9 → 0.6.11
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 +15 -4
- package/dist/commands/agent/list.js +68 -3
- package/dist/commands/{update.d.ts → ai-docs/sync.d.ts} +1 -1
- package/dist/commands/{update.js → ai-docs/sync.js} +4 -4
- package/dist/commands/challenge/run.d.ts +0 -1
- package/dist/commands/challenge/run.js +2 -24
- package/dist/commands/challenge/runs/get.d.ts +0 -1
- package/dist/commands/challenge/runs/get.js +0 -11
- package/dist/commands/init.js +1 -0
- package/dist/config/releases/arena-minecraft.d.ts +1 -1
- package/dist/config/releases/arena-minecraft.js +1 -1
- package/dist/lib/challenge.js +4 -5
- package/dist/lib/experiment/experimenter.js +6 -3
- package/dist/lib/local-runner.js +51 -2
- package/dist/lib/schemas.d.ts +49 -1
- package/dist/lib/schemas.js +13 -1
- package/oclif.manifest.json +48 -60
- package/package.json +1 -1
- package/static/ai_docs/LLM_CLI_REFERENCE.md +53 -15
package/README.md
CHANGED
|
@@ -226,13 +226,11 @@ Get details and logs for a specific run:
|
|
|
226
226
|
```bash
|
|
227
227
|
kradle challenge runs get <run-id>
|
|
228
228
|
kradle challenge runs get <run-id> --no-logs # Skip fetching logs
|
|
229
|
-
kradle challenge runs get <run-id> --no-summary # Skip AI summary
|
|
230
229
|
```
|
|
231
230
|
|
|
232
231
|
This displays:
|
|
233
232
|
- Run metadata (status, duration, end state)
|
|
234
233
|
- Participant results (agent, winner status, score)
|
|
235
|
-
- AI-generated summary (unless `--no-summary` is used)
|
|
236
234
|
- Log entries with timestamps and levels (unless `--no-logs` is used)
|
|
237
235
|
|
|
238
236
|
## Experiment Commands
|
|
@@ -407,7 +405,7 @@ Locations are synced to the cloud when you push the world.
|
|
|
407
405
|
|
|
408
406
|
### List Agents
|
|
409
407
|
|
|
410
|
-
List all agents registered in the system:
|
|
408
|
+
List all agents registered in the system with their model and pricing information (input/output cost per million tokens):
|
|
411
409
|
|
|
412
410
|
```bash
|
|
413
411
|
kradle agent list
|
|
@@ -415,7 +413,7 @@ kradle agent list
|
|
|
415
413
|
|
|
416
414
|
## AI Docs Commands
|
|
417
415
|
|
|
418
|
-
Output LLM-focused documentation to stdout
|
|
416
|
+
Output LLM-focused documentation to stdout, or sync local AI docs with the latest version from the CLI.
|
|
419
417
|
|
|
420
418
|
### CLI Reference
|
|
421
419
|
|
|
@@ -436,6 +434,19 @@ kradle ai-docs challenges-sdk 0.2.1 # Uses specific version
|
|
|
436
434
|
|
|
437
435
|
This fetches the documentation from unpkg.com, matching the SDK version in your project.
|
|
438
436
|
|
|
437
|
+
### Sync AI Docs
|
|
438
|
+
|
|
439
|
+
Sync project AI docs (`AGENTS.md`, `CLAUDE.md`) to the latest version bundled with the CLI:
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
kradle ai-docs sync # Interactive confirmation
|
|
443
|
+
kradle ai-docs sync --dry-run # Preview changes without applying
|
|
444
|
+
kradle ai-docs sync --yes # Skip confirmation prompts
|
|
445
|
+
kradle ai-docs sync --add-missing # Also create files missing locally
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
This compares your local `AGENTS.md` and `CLAUDE.md` against the templates bundled with the installed CLI version. Useful after upgrading `kradle` to pick up new AI doc templates.
|
|
449
|
+
|
|
439
450
|
## Publishing a New Version
|
|
440
451
|
|
|
441
452
|
The CLI uses GitHub Actions for automated releases. To publish a new version:
|
|
@@ -2,6 +2,49 @@ import { Command } from "@oclif/core";
|
|
|
2
2
|
import pc from "picocolors";
|
|
3
3
|
import { ApiClient } from "../../lib/api-client.js";
|
|
4
4
|
import { getConfigFlags } from "../../lib/flags.js";
|
|
5
|
+
async function fetchOpenRouterPricing() {
|
|
6
|
+
const pricing = new Map();
|
|
7
|
+
try {
|
|
8
|
+
const response = await fetch("https://openrouter.ai/api/v1/models", {
|
|
9
|
+
signal: AbortSignal.timeout(5000),
|
|
10
|
+
});
|
|
11
|
+
if (!response.ok)
|
|
12
|
+
return pricing;
|
|
13
|
+
const data = (await response.json());
|
|
14
|
+
for (const model of data.data) {
|
|
15
|
+
const promptCost = Number.parseFloat(model.pricing.prompt);
|
|
16
|
+
const completionCost = Number.parseFloat(model.pricing.completion);
|
|
17
|
+
if (!Number.isNaN(promptCost) && !Number.isNaN(completionCost) && promptCost >= 0 && completionCost >= 0) {
|
|
18
|
+
pricing.set(model.id, {
|
|
19
|
+
input: promptCost * 1_000_000,
|
|
20
|
+
output: completionCost * 1_000_000,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Silently fail - pricing is best-effort
|
|
27
|
+
}
|
|
28
|
+
return pricing;
|
|
29
|
+
}
|
|
30
|
+
function formatCost(cost) {
|
|
31
|
+
if (cost === 0)
|
|
32
|
+
return "$0";
|
|
33
|
+
if (cost < 0.01)
|
|
34
|
+
return `$${cost.toFixed(4)}`;
|
|
35
|
+
return `$${cost.toFixed(2)}`;
|
|
36
|
+
}
|
|
37
|
+
function colorizeCost(formatted, cost) {
|
|
38
|
+
if (cost === undefined)
|
|
39
|
+
return pc.dim("-");
|
|
40
|
+
if (cost < 1)
|
|
41
|
+
return pc.green(formatted);
|
|
42
|
+
if (cost < 5)
|
|
43
|
+
return pc.cyan(formatted);
|
|
44
|
+
if (cost < 15)
|
|
45
|
+
return pc.yellow(formatted);
|
|
46
|
+
return pc.red(formatted);
|
|
47
|
+
}
|
|
5
48
|
export default class List extends Command {
|
|
6
49
|
static description = "List all agents";
|
|
7
50
|
static examples = ["<%= config.bin %> <%= command.id %>"];
|
|
@@ -12,11 +55,33 @@ export default class List extends Command {
|
|
|
12
55
|
const { flags } = await this.parse(List);
|
|
13
56
|
const api = new ApiClient(flags["api-url"], flags["api-key"]);
|
|
14
57
|
this.log(pc.blue(">> Loading agents..."));
|
|
15
|
-
const agents = await api.listKradleAgents();
|
|
58
|
+
const [agents, pricing] = await Promise.all([api.listKradleAgents(), fetchOpenRouterPricing()]);
|
|
16
59
|
agents.sort((a, b) => a.username?.localeCompare(b.username || "") || 0);
|
|
60
|
+
// Calculate column widths
|
|
61
|
+
const rows = agents.map((agent) => {
|
|
62
|
+
const username = agent.username || "";
|
|
63
|
+
const model = agent.agentConfig && "model" in agent.agentConfig ? agent.agentConfig.model : "";
|
|
64
|
+
const costs = model ? pricing.get(model) : undefined;
|
|
65
|
+
const inputRaw = costs ? formatCost(costs.input) : "-";
|
|
66
|
+
const outputRaw = costs ? formatCost(costs.output) : "-";
|
|
67
|
+
const inputColored = colorizeCost(inputRaw, costs?.input);
|
|
68
|
+
const outputColored = colorizeCost(outputRaw, costs?.output);
|
|
69
|
+
return { username, model, inputRaw, outputRaw, inputColored, outputColored };
|
|
70
|
+
});
|
|
71
|
+
const nameWidth = Math.max("Agent".length, ...rows.map((r) => r.username.length));
|
|
72
|
+
const modelWidth = Math.max("Model".length, ...rows.map((r) => r.model.length));
|
|
73
|
+
const inputWidth = Math.max("Input/MTok".length, ...rows.map((r) => r.inputRaw.length));
|
|
74
|
+
const outputWidth = Math.max("Output/MTok".length, ...rows.map((r) => r.outputRaw.length));
|
|
17
75
|
this.log(pc.bold(`\nFound ${agents.length} agents:\n`));
|
|
18
|
-
|
|
19
|
-
|
|
76
|
+
// Header
|
|
77
|
+
const header = ` ${pc.bold("Agent".padEnd(nameWidth))} ${pc.bold("Model".padEnd(modelWidth))} ${pc.bold("Input/MTok".padEnd(inputWidth))} ${pc.bold("Output/MTok".padEnd(outputWidth))}`;
|
|
78
|
+
this.log(header);
|
|
79
|
+
this.log(` ${"─".repeat(nameWidth)} ${"─".repeat(modelWidth)} ${"─".repeat(inputWidth)} ${"─".repeat(outputWidth)}`);
|
|
80
|
+
for (const row of rows) {
|
|
81
|
+
// Pad using raw (uncolored) width, then replace with colored version
|
|
82
|
+
const inputPad = " ".repeat(Math.max(0, inputWidth - row.inputRaw.length));
|
|
83
|
+
const outputPad = " ".repeat(Math.max(0, outputWidth - row.outputRaw.length));
|
|
84
|
+
this.log(` ${pc.bold(row.username.padEnd(nameWidth))} ${row.model.padEnd(modelWidth)} ${row.inputColored}${inputPad} ${row.outputColored}${outputPad}`);
|
|
20
85
|
}
|
|
21
86
|
}
|
|
22
87
|
}
|
|
@@ -3,11 +3,11 @@ import path from "node:path";
|
|
|
3
3
|
import { Command, Flags } from "@oclif/core";
|
|
4
4
|
import enquirer from "enquirer";
|
|
5
5
|
import pc from "picocolors";
|
|
6
|
-
import { getStaticResourcePath } from "
|
|
6
|
+
import { getStaticResourcePath } from "../../lib/utils.js";
|
|
7
7
|
// Files that should be synced on update (documentation files only)
|
|
8
8
|
const SYNC_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
9
|
-
export default class
|
|
10
|
-
static description = "
|
|
9
|
+
export default class Sync extends Command {
|
|
10
|
+
static description = "Sync project AI docs (AGENTS.md, CLAUDE.md) to the latest version from the CLI";
|
|
11
11
|
static examples = [
|
|
12
12
|
"<%= config.bin %> <%= command.id %>",
|
|
13
13
|
"<%= config.bin %> <%= command.id %> --dry-run",
|
|
@@ -96,7 +96,7 @@ export default class Update extends Command {
|
|
|
96
96
|
this.log(pc.dim(" (file contents differ - will be replaced with template version)"));
|
|
97
97
|
}
|
|
98
98
|
async run() {
|
|
99
|
-
const { flags } = await this.parse(
|
|
99
|
+
const { flags } = await this.parse(Sync);
|
|
100
100
|
const isDryRun = flags["dry-run"];
|
|
101
101
|
const skipPrompts = flags.yes;
|
|
102
102
|
const addMissing = flags["add-missing"];
|
|
@@ -19,7 +19,6 @@ export default class Run extends Command {
|
|
|
19
19
|
"arena-image": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
20
|
"no-open": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
21
21
|
"no-wait": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
22
|
-
"no-summary": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
23
22
|
screenshots: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
24
23
|
};
|
|
25
24
|
private pollForCompletion;
|
|
@@ -51,20 +51,14 @@ export default class Run extends Command {
|
|
|
51
51
|
description: "Don't wait for the run to complete (fire and forget)",
|
|
52
52
|
default: false,
|
|
53
53
|
}),
|
|
54
|
-
"no-summary": Flags.boolean({
|
|
55
|
-
description: "Don't wait for the AI-generated summary",
|
|
56
|
-
default: false,
|
|
57
|
-
}),
|
|
58
54
|
screenshots: Flags.boolean({
|
|
59
55
|
description: "Open the run URL with screenshots mode enabled",
|
|
60
56
|
default: false,
|
|
61
57
|
}),
|
|
62
58
|
...getConfigFlags("api-key", "api-url", "web-url", "studio-url", "studio-api-url", "challenges-path"),
|
|
63
59
|
};
|
|
64
|
-
async pollForCompletion(api, runId
|
|
60
|
+
async pollForCompletion(api, runId) {
|
|
65
61
|
let lastStatus = "";
|
|
66
|
-
let reachedTerminal = false;
|
|
67
|
-
let waitingForSummary = false;
|
|
68
62
|
const startTime = Date.now();
|
|
69
63
|
while (true) {
|
|
70
64
|
// Check for timeout
|
|
@@ -83,18 +77,6 @@ export default class Run extends Command {
|
|
|
83
77
|
}
|
|
84
78
|
// Check for terminal state
|
|
85
79
|
if (TERMINAL_STATUSES.includes(currentStatus)) {
|
|
86
|
-
if (!reachedTerminal) {
|
|
87
|
-
reachedTerminal = true;
|
|
88
|
-
}
|
|
89
|
-
// If we need to wait for summary and it's not available yet, keep polling
|
|
90
|
-
if (waitForSummary && !result.summary) {
|
|
91
|
-
if (!waitingForSummary) {
|
|
92
|
-
waitingForSummary = true;
|
|
93
|
-
this.log(pc.dim(`Waiting for summary...`));
|
|
94
|
-
}
|
|
95
|
-
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
80
|
this.log("");
|
|
99
81
|
this.displayRunResult(result);
|
|
100
82
|
return;
|
|
@@ -119,10 +101,6 @@ export default class Run extends Command {
|
|
|
119
101
|
this.log(` ${winnerIcon} ${participantId}: ${pr.agent}${score}`);
|
|
120
102
|
}
|
|
121
103
|
}
|
|
122
|
-
if (result.summary) {
|
|
123
|
-
this.log(pc.bold("\n=== Summary ===\n"));
|
|
124
|
-
this.log(result.summary);
|
|
125
|
-
}
|
|
126
104
|
}
|
|
127
105
|
/**
|
|
128
106
|
* Parse inline agent arguments into participants.
|
|
@@ -409,7 +387,7 @@ export default class Run extends Command {
|
|
|
409
387
|
}
|
|
410
388
|
if (!flags["no-wait"]) {
|
|
411
389
|
this.log(pc.blue("\n>> Waiting for run to complete...\n"));
|
|
412
|
-
await this.pollForCompletion(api, runId
|
|
390
|
+
await this.pollForCompletion(api, runId);
|
|
413
391
|
}
|
|
414
392
|
}
|
|
415
393
|
else {
|
|
@@ -9,7 +9,6 @@ export default class GetRun extends Command {
|
|
|
9
9
|
"api-key": import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
"api-url": import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
11
|
"no-logs": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
-
"no-summary": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
12
|
};
|
|
14
13
|
run(): Promise<void>;
|
|
15
14
|
}
|
|
@@ -35,7 +35,6 @@ export default class GetRun extends Command {
|
|
|
35
35
|
static examples = [
|
|
36
36
|
"<%= config.bin %> <%= command.id %> abc123",
|
|
37
37
|
"<%= config.bin %> <%= command.id %> abc123 --no-logs",
|
|
38
|
-
"<%= config.bin %> <%= command.id %> abc123 --no-summary",
|
|
39
38
|
];
|
|
40
39
|
static args = {
|
|
41
40
|
runId: Args.string({
|
|
@@ -48,17 +47,12 @@ export default class GetRun extends Command {
|
|
|
48
47
|
description: "Skip fetching and displaying logs",
|
|
49
48
|
default: false,
|
|
50
49
|
}),
|
|
51
|
-
"no-summary": Flags.boolean({
|
|
52
|
-
description: "Skip displaying the AI-generated summary",
|
|
53
|
-
default: false,
|
|
54
|
-
}),
|
|
55
50
|
...getConfigFlags("api-key", "api-url"),
|
|
56
51
|
};
|
|
57
52
|
async run() {
|
|
58
53
|
const { args, flags } = await this.parse(GetRun);
|
|
59
54
|
const api = new ApiClient(flags["api-url"], flags["api-key"]);
|
|
60
55
|
const showLogs = !flags["no-logs"];
|
|
61
|
-
const showSummary = !flags["no-summary"];
|
|
62
56
|
this.log(pc.blue(`>> Loading run ${args.runId}...`));
|
|
63
57
|
try {
|
|
64
58
|
const [runResult, logs] = await Promise.all([
|
|
@@ -100,11 +94,6 @@ export default class GetRun extends Command {
|
|
|
100
94
|
this.log(`${participantId.padEnd(widths[0])} ${agentPadded} ${winner} ${score.padEnd(widths[3])} ${timeToSuccess}`);
|
|
101
95
|
}
|
|
102
96
|
}
|
|
103
|
-
// AI Summary
|
|
104
|
-
if (showSummary && runResult.summary) {
|
|
105
|
-
this.log(pc.bold("\n=== Summary ===\n"));
|
|
106
|
-
this.log(runResult.summary);
|
|
107
|
-
}
|
|
108
97
|
// Logs
|
|
109
98
|
if (showLogs) {
|
|
110
99
|
// Filter out logs with 'prompt' key (verbose LLM prompts)
|
package/dist/commands/init.js
CHANGED
|
@@ -148,6 +148,7 @@ export default class Init extends Command {
|
|
|
148
148
|
// Display success message and next steps
|
|
149
149
|
this.log(pc.green(`\n✓ Project initialized successfully!`));
|
|
150
150
|
this.log(pc.dim(`\nProject location: ${targetDir}`));
|
|
151
|
+
this.log(pc.dim("AGENTS.md and CLAUDE.md were added to the project — LLM-based coding agents will read them to learn how to work with Kradle."));
|
|
151
152
|
this.log(pc.bold("\n📝 Next steps:"));
|
|
152
153
|
if (targetDir !== cwd) {
|
|
153
154
|
this.log(pc.cyan(` cd ${projectName}`));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MINECRAFT_ARENA_MANAGER_TAG = "
|
|
1
|
+
export declare const MINECRAFT_ARENA_MANAGER_TAG = "14f7331";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Managed by https://github.com/Kradle-ai/arena-minecraft/actions/workflows/release.yaml
|
|
2
|
-
export const MINECRAFT_ARENA_MANAGER_TAG = "
|
|
2
|
+
export const MINECRAFT_ARENA_MANAGER_TAG = "14f7331";
|
package/dist/lib/challenge.js
CHANGED
|
@@ -169,17 +169,16 @@ export class Challenge {
|
|
|
169
169
|
*/
|
|
170
170
|
async buildLocal(options = { validate: true }) {
|
|
171
171
|
const { validate = true } = options;
|
|
172
|
+
// Ensure challenge exists locally
|
|
173
|
+
if (!this.exists()) {
|
|
174
|
+
throw new Error(`Challenge "${this.shortSlug}" does not exist locally. Make sure both the challenge.ts file and the config.ts file exist.`);
|
|
175
|
+
}
|
|
172
176
|
// Start validation service initialization in parallel with build (if validation enabled)
|
|
173
177
|
// This overlaps the init time with the build process.
|
|
174
178
|
let validationService = null;
|
|
175
179
|
if (validate) {
|
|
176
180
|
validationService = ValidationService.create(this.builtDatapackPath);
|
|
177
181
|
}
|
|
178
|
-
// Ensure challenge exists locally
|
|
179
|
-
if (!this.exists()) {
|
|
180
|
-
await validationService?.close();
|
|
181
|
-
throw new Error(`Challenge "${this.shortSlug}" does not exist locally. Make sure both the challenge.ts file and the config.ts file exist.`);
|
|
182
|
-
}
|
|
183
182
|
const config = await this.loadConfig();
|
|
184
183
|
// Build datapack (validation service initializes in parallel)
|
|
185
184
|
console.log(pc.blue(`>> Building datapack: ${this.shortSlug}`));
|
|
@@ -257,9 +257,12 @@ export class Experimenter {
|
|
|
257
257
|
this.currentVersion = version;
|
|
258
258
|
// Load manifest
|
|
259
259
|
const manifest = await this.loadManifest(version);
|
|
260
|
-
//
|
|
261
|
-
const
|
|
262
|
-
const
|
|
260
|
+
// Fetch the user's slug to prefix tags for uniqueness
|
|
261
|
+
const human = await this.api.getHuman();
|
|
262
|
+
const prefix = human.username;
|
|
263
|
+
// We have 2 mandatory tags: "<user>(<exp-name>)" and "<user>(<exp-name>-v<version>)"
|
|
264
|
+
const experimentTag = `${prefix}(exp-${this.name})`;
|
|
265
|
+
const versionTag = `${prefix}(exp-${this.name}-v${version})`;
|
|
263
266
|
const tags = [experimentTag, versionTag, ...(manifest.tags ?? [])];
|
|
264
267
|
// Create runner
|
|
265
268
|
this.runner = new Runner(manifest.runs, this.api, this.webUrl, {
|
package/dist/lib/local-runner.js
CHANGED
|
@@ -14,6 +14,23 @@ const SERVER_READY_TIMEOUT_MS = 120_000;
|
|
|
14
14
|
const SERVER_READY_POLL_MS = 3_000;
|
|
15
15
|
const CONTAINER_NAME_PREFIX_MC = "kradle-mc-server";
|
|
16
16
|
const CONTAINER_NAME_PREFIX_ARENA = "kradle-arena";
|
|
17
|
+
// Debug environment variables — mirrors the flags in Studio's MinecraftDomainAdapter.
|
|
18
|
+
//
|
|
19
|
+
// DEBUG_LOCAL_ARENA_MINECRAFT=true
|
|
20
|
+
// Uses a local dev image ("local-arena-minecraft-dev") and volume-mounts
|
|
21
|
+
// the arena-minecraft source tree so changes are picked up without rebuilding.
|
|
22
|
+
// Build the image with "docker compose build" inside the arena-minecraft repo.
|
|
23
|
+
//
|
|
24
|
+
// DEBUG_LOCAL_ARENA_MINECRAFT_WAIT=true
|
|
25
|
+
// Additionally starts Node with --inspect-wait so it pauses until a debugger
|
|
26
|
+
// attaches (requires Node 22+). Without this flag, --inspect is used instead.
|
|
27
|
+
//
|
|
28
|
+
// ARENA_MINECRAFT_SOURCE_PATH
|
|
29
|
+
// Path to the arena-minecraft source tree. Defaults to "../arena-minecraft"
|
|
30
|
+
// relative to cwd.
|
|
31
|
+
const DEBUG_LOCAL_ARENA = process.env.DEBUG_LOCAL_ARENA_MINECRAFT === "true";
|
|
32
|
+
const DEBUG_LOCAL_ARENA_WAIT = process.env.DEBUG_LOCAL_ARENA_MINECRAFT_WAIT === "true";
|
|
33
|
+
const ARENA_DEBUG_PORT = 9229;
|
|
17
34
|
export class LocalRunner {
|
|
18
35
|
config;
|
|
19
36
|
mcContainerId = null;
|
|
@@ -232,6 +249,9 @@ export class LocalRunner {
|
|
|
232
249
|
containerName,
|
|
233
250
|
"-p",
|
|
234
251
|
`${MC_PORT}:${MC_PORT}`,
|
|
252
|
+
// The arena container shares this container's network, so we must
|
|
253
|
+
// publish the debug port here.
|
|
254
|
+
...(DEBUG_LOCAL_ARENA ? ["-p", `${ARENA_DEBUG_PORT}:${ARENA_DEBUG_PORT}`] : []),
|
|
235
255
|
"-v",
|
|
236
256
|
`${serverDir}:/data`,
|
|
237
257
|
"-e",
|
|
@@ -280,9 +300,38 @@ export class LocalRunner {
|
|
|
280
300
|
`PROMPT_AGENT_BASE_URL=${agentBaseUrl}`,
|
|
281
301
|
"-e",
|
|
282
302
|
"MAX_IDLE_TIME=-1",
|
|
283
|
-
arenaImage,
|
|
284
|
-
`--job=${jobPayload}`,
|
|
285
303
|
];
|
|
304
|
+
if (DEBUG_LOCAL_ARENA) {
|
|
305
|
+
// Volume-mount the local source tree so edits are reflected without
|
|
306
|
+
// rebuilding the image.
|
|
307
|
+
const sourcePath = process.env.ARENA_MINECRAFT_SOURCE_PATH
|
|
308
|
+
? path.resolve(process.env.ARENA_MINECRAFT_SOURCE_PATH)
|
|
309
|
+
: path.resolve("../arena-minecraft/src");
|
|
310
|
+
args.push("-v", `${sourcePath}:/usr/src/app/src`);
|
|
311
|
+
// Override the entrypoint to run via ts-node so we execute from source.
|
|
312
|
+
args.push("--entrypoint", "node");
|
|
313
|
+
// Extra logging in debug mode.
|
|
314
|
+
args.push("-e", "LOGGING=true");
|
|
315
|
+
// Use the local dev image (built via "docker compose build" in arena-minecraft).
|
|
316
|
+
args.push("local-arena-minecraft-dev:latest");
|
|
317
|
+
// Node inspector flags — must come after the image name (they are the
|
|
318
|
+
// container CMD, not docker args).
|
|
319
|
+
if (DEBUG_LOCAL_ARENA_WAIT) {
|
|
320
|
+
args.push(`--inspect-wait=0.0.0.0:${ARENA_DEBUG_PORT}`);
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
args.push(`--inspect=0.0.0.0:${ARENA_DEBUG_PORT}`);
|
|
324
|
+
}
|
|
325
|
+
// Run from TypeScript source via ts-node.
|
|
326
|
+
args.push("--loader", "ts-node/esm", "--no-warnings", "/usr/src/app/src/index.ts");
|
|
327
|
+
// Job payload comes last.
|
|
328
|
+
args.push(`--job=${jobPayload}`);
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
// Production path: use the pre-built image.
|
|
332
|
+
args.push(arenaImage);
|
|
333
|
+
args.push(`--job=${jobPayload}`);
|
|
334
|
+
}
|
|
286
335
|
// Use execFileSync to bypass shell — the JSON payload contains quotes,
|
|
287
336
|
// parentheses, and other characters that break shell parsing.
|
|
288
337
|
const result = execFileSync("docker", args, {
|
package/dist/lib/schemas.d.ts
CHANGED
|
@@ -221,6 +221,25 @@ export declare const DownloadUrlResponseSchema: z.ZodObject<{
|
|
|
221
221
|
downloadUrl: z.ZodString;
|
|
222
222
|
expiresAt: z.ZodString;
|
|
223
223
|
}, z.core.$strip>;
|
|
224
|
+
export declare const PromptConfigSchema: z.ZodObject<{
|
|
225
|
+
model: z.ZodString;
|
|
226
|
+
persona: z.ZodOptional<z.ZodString>;
|
|
227
|
+
respondWithCode: z.ZodOptional<z.ZodBoolean>;
|
|
228
|
+
skinUrl: z.ZodOptional<z.ZodString>;
|
|
229
|
+
}, z.core.$strip>;
|
|
230
|
+
export declare const SdkV0ConfigSchema: z.ZodObject<{
|
|
231
|
+
url: z.ZodString;
|
|
232
|
+
skinUrl: z.ZodOptional<z.ZodString>;
|
|
233
|
+
}, z.core.$strip>;
|
|
234
|
+
export declare const AgentConfigSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
235
|
+
model: z.ZodString;
|
|
236
|
+
persona: z.ZodOptional<z.ZodString>;
|
|
237
|
+
respondWithCode: z.ZodOptional<z.ZodBoolean>;
|
|
238
|
+
skinUrl: z.ZodOptional<z.ZodString>;
|
|
239
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
240
|
+
url: z.ZodString;
|
|
241
|
+
skinUrl: z.ZodOptional<z.ZodString>;
|
|
242
|
+
}, z.core.$strip>, z.ZodObject<{}, z.core.$strip>]>;
|
|
224
243
|
export declare const AgentSchema: z.ZodObject<{
|
|
225
244
|
username: z.ZodOptional<z.ZodString>;
|
|
226
245
|
name: z.ZodOptional<z.ZodString>;
|
|
@@ -235,6 +254,21 @@ export declare const AgentSchema: z.ZodObject<{
|
|
|
235
254
|
deletionTime: z.ZodOptional<z.ZodString>;
|
|
236
255
|
creatorId: z.ZodOptional<z.ZodString>;
|
|
237
256
|
originalCreatorId: z.ZodOptional<z.ZodString>;
|
|
257
|
+
agentType: z.ZodOptional<z.ZodEnum<{
|
|
258
|
+
prompt: "prompt";
|
|
259
|
+
experimental: "experimental";
|
|
260
|
+
sdk_v0: "sdk_v0";
|
|
261
|
+
kradleverse_human: "kradleverse_human";
|
|
262
|
+
}>>;
|
|
263
|
+
agentConfig: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
264
|
+
model: z.ZodString;
|
|
265
|
+
persona: z.ZodOptional<z.ZodString>;
|
|
266
|
+
respondWithCode: z.ZodOptional<z.ZodBoolean>;
|
|
267
|
+
skinUrl: z.ZodOptional<z.ZodString>;
|
|
268
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
269
|
+
url: z.ZodString;
|
|
270
|
+
skinUrl: z.ZodOptional<z.ZodString>;
|
|
271
|
+
}, z.core.$strip>, z.ZodObject<{}, z.core.$strip>]>>;
|
|
238
272
|
}, z.core.$strip>;
|
|
239
273
|
export declare const AgentsResponseSchema: z.ZodObject<{
|
|
240
274
|
agents: z.ZodArray<z.ZodObject<{
|
|
@@ -251,6 +285,21 @@ export declare const AgentsResponseSchema: z.ZodObject<{
|
|
|
251
285
|
deletionTime: z.ZodOptional<z.ZodString>;
|
|
252
286
|
creatorId: z.ZodOptional<z.ZodString>;
|
|
253
287
|
originalCreatorId: z.ZodOptional<z.ZodString>;
|
|
288
|
+
agentType: z.ZodOptional<z.ZodEnum<{
|
|
289
|
+
prompt: "prompt";
|
|
290
|
+
experimental: "experimental";
|
|
291
|
+
sdk_v0: "sdk_v0";
|
|
292
|
+
kradleverse_human: "kradleverse_human";
|
|
293
|
+
}>>;
|
|
294
|
+
agentConfig: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
295
|
+
model: z.ZodString;
|
|
296
|
+
persona: z.ZodOptional<z.ZodString>;
|
|
297
|
+
respondWithCode: z.ZodOptional<z.ZodBoolean>;
|
|
298
|
+
skinUrl: z.ZodOptional<z.ZodString>;
|
|
299
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
300
|
+
url: z.ZodString;
|
|
301
|
+
skinUrl: z.ZodOptional<z.ZodString>;
|
|
302
|
+
}, z.core.$strip>, z.ZodObject<{}, z.core.$strip>]>>;
|
|
254
303
|
}, z.core.$strip>>;
|
|
255
304
|
nextPageToken: z.ZodOptional<z.ZodString>;
|
|
256
305
|
}, z.core.$strip>;
|
|
@@ -315,7 +364,6 @@ export declare const RunResultResponseSchema: z.ZodObject<{
|
|
|
315
364
|
score: z.ZodOptional<z.ZodNumber>;
|
|
316
365
|
timeToSuccess: z.ZodOptional<z.ZodNumber>;
|
|
317
366
|
}, z.core.$strip>>>;
|
|
318
|
-
summary: z.ZodOptional<z.ZodString>;
|
|
319
367
|
}, z.core.$strip>;
|
|
320
368
|
export declare const WorldSchema: z.ZodObject<{
|
|
321
369
|
id: z.ZodString;
|
package/dist/lib/schemas.js
CHANGED
|
@@ -94,6 +94,17 @@ export const DownloadUrlResponseSchema = z.object({
|
|
|
94
94
|
downloadUrl: z.string(),
|
|
95
95
|
expiresAt: z.string(),
|
|
96
96
|
});
|
|
97
|
+
export const PromptConfigSchema = z.object({
|
|
98
|
+
model: z.string(),
|
|
99
|
+
persona: z.string().optional(),
|
|
100
|
+
respondWithCode: z.boolean().optional(),
|
|
101
|
+
skinUrl: z.string().optional(),
|
|
102
|
+
});
|
|
103
|
+
export const SdkV0ConfigSchema = z.object({
|
|
104
|
+
url: z.string(),
|
|
105
|
+
skinUrl: z.string().optional(),
|
|
106
|
+
});
|
|
107
|
+
export const AgentConfigSchema = z.union([PromptConfigSchema, SdkV0ConfigSchema, z.object({})]);
|
|
97
108
|
export const AgentSchema = z.object({
|
|
98
109
|
username: z.string().optional(),
|
|
99
110
|
name: z.string().optional(),
|
|
@@ -104,6 +115,8 @@ export const AgentSchema = z.object({
|
|
|
104
115
|
deletionTime: z.string().optional(),
|
|
105
116
|
creatorId: z.string().optional(),
|
|
106
117
|
originalCreatorId: z.string().optional(),
|
|
118
|
+
agentType: z.enum(["prompt", "experimental", "sdk_v0", "kradleverse_human"]).optional(),
|
|
119
|
+
agentConfig: AgentConfigSchema.optional(),
|
|
107
120
|
});
|
|
108
121
|
export const AgentsResponseSchema = z.object({
|
|
109
122
|
agents: z.array(AgentSchema),
|
|
@@ -150,7 +163,6 @@ export const RunResultResponseSchema = z.object({
|
|
|
150
163
|
endTime: z.string().optional(),
|
|
151
164
|
aggregatedResults: RunAggregatedResultsSchema.optional(),
|
|
152
165
|
participantResults: z.record(z.string(), RunParticipantResultSchema).optional(),
|
|
153
|
-
summary: z.string().optional(),
|
|
154
166
|
});
|
|
155
167
|
export const WorldSchema = z.object({
|
|
156
168
|
id: z.string(),
|
package/oclif.manifest.json
CHANGED
|
@@ -42,51 +42,6 @@
|
|
|
42
42
|
"init.js"
|
|
43
43
|
]
|
|
44
44
|
},
|
|
45
|
-
"update": {
|
|
46
|
-
"aliases": [],
|
|
47
|
-
"args": {},
|
|
48
|
-
"description": "Update project template files (AGENTS.md, CLAUDE.md) to the latest version from the CLI",
|
|
49
|
-
"examples": [
|
|
50
|
-
"<%= config.bin %> <%= command.id %>",
|
|
51
|
-
"<%= config.bin %> <%= command.id %> --dry-run",
|
|
52
|
-
"<%= config.bin %> <%= command.id %> --yes"
|
|
53
|
-
],
|
|
54
|
-
"flags": {
|
|
55
|
-
"dry-run": {
|
|
56
|
-
"description": "Preview changes without applying them",
|
|
57
|
-
"name": "dry-run",
|
|
58
|
-
"allowNo": false,
|
|
59
|
-
"type": "boolean"
|
|
60
|
-
},
|
|
61
|
-
"yes": {
|
|
62
|
-
"char": "y",
|
|
63
|
-
"description": "Skip confirmation prompts",
|
|
64
|
-
"name": "yes",
|
|
65
|
-
"allowNo": false,
|
|
66
|
-
"type": "boolean"
|
|
67
|
-
},
|
|
68
|
-
"add-missing": {
|
|
69
|
-
"description": "Add files that exist in template but not locally",
|
|
70
|
-
"name": "add-missing",
|
|
71
|
-
"allowNo": false,
|
|
72
|
-
"type": "boolean"
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
"hasDynamicHelp": false,
|
|
76
|
-
"hiddenAliases": [],
|
|
77
|
-
"id": "update",
|
|
78
|
-
"pluginAlias": "kradle",
|
|
79
|
-
"pluginName": "kradle",
|
|
80
|
-
"pluginType": "core",
|
|
81
|
-
"strict": true,
|
|
82
|
-
"enableJsonFlag": false,
|
|
83
|
-
"isESM": true,
|
|
84
|
-
"relativePath": [
|
|
85
|
-
"dist",
|
|
86
|
-
"commands",
|
|
87
|
-
"update.js"
|
|
88
|
-
]
|
|
89
|
-
},
|
|
90
45
|
"agent:list": {
|
|
91
46
|
"aliases": [],
|
|
92
47
|
"args": {},
|
|
@@ -187,6 +142,52 @@
|
|
|
187
142
|
"cli.js"
|
|
188
143
|
]
|
|
189
144
|
},
|
|
145
|
+
"ai-docs:sync": {
|
|
146
|
+
"aliases": [],
|
|
147
|
+
"args": {},
|
|
148
|
+
"description": "Sync project AI docs (AGENTS.md, CLAUDE.md) to the latest version from the CLI",
|
|
149
|
+
"examples": [
|
|
150
|
+
"<%= config.bin %> <%= command.id %>",
|
|
151
|
+
"<%= config.bin %> <%= command.id %> --dry-run",
|
|
152
|
+
"<%= config.bin %> <%= command.id %> --yes"
|
|
153
|
+
],
|
|
154
|
+
"flags": {
|
|
155
|
+
"dry-run": {
|
|
156
|
+
"description": "Preview changes without applying them",
|
|
157
|
+
"name": "dry-run",
|
|
158
|
+
"allowNo": false,
|
|
159
|
+
"type": "boolean"
|
|
160
|
+
},
|
|
161
|
+
"yes": {
|
|
162
|
+
"char": "y",
|
|
163
|
+
"description": "Skip confirmation prompts",
|
|
164
|
+
"name": "yes",
|
|
165
|
+
"allowNo": false,
|
|
166
|
+
"type": "boolean"
|
|
167
|
+
},
|
|
168
|
+
"add-missing": {
|
|
169
|
+
"description": "Add files that exist in template but not locally",
|
|
170
|
+
"name": "add-missing",
|
|
171
|
+
"allowNo": false,
|
|
172
|
+
"type": "boolean"
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
"hasDynamicHelp": false,
|
|
176
|
+
"hiddenAliases": [],
|
|
177
|
+
"id": "ai-docs:sync",
|
|
178
|
+
"pluginAlias": "kradle",
|
|
179
|
+
"pluginName": "kradle",
|
|
180
|
+
"pluginType": "core",
|
|
181
|
+
"strict": true,
|
|
182
|
+
"enableJsonFlag": false,
|
|
183
|
+
"isESM": true,
|
|
184
|
+
"relativePath": [
|
|
185
|
+
"dist",
|
|
186
|
+
"commands",
|
|
187
|
+
"ai-docs",
|
|
188
|
+
"sync.js"
|
|
189
|
+
]
|
|
190
|
+
},
|
|
190
191
|
"ai-docs:workflow": {
|
|
191
192
|
"aliases": [],
|
|
192
193
|
"args": {},
|
|
@@ -626,12 +627,6 @@
|
|
|
626
627
|
"allowNo": false,
|
|
627
628
|
"type": "boolean"
|
|
628
629
|
},
|
|
629
|
-
"no-summary": {
|
|
630
|
-
"description": "Don't wait for the AI-generated summary",
|
|
631
|
-
"name": "no-summary",
|
|
632
|
-
"allowNo": false,
|
|
633
|
-
"type": "boolean"
|
|
634
|
-
},
|
|
635
630
|
"screenshots": {
|
|
636
631
|
"description": "Open the run URL with screenshots mode enabled",
|
|
637
632
|
"name": "screenshots",
|
|
@@ -1446,8 +1441,7 @@
|
|
|
1446
1441
|
"description": "Get details and logs for a specific run",
|
|
1447
1442
|
"examples": [
|
|
1448
1443
|
"<%= config.bin %> <%= command.id %> abc123",
|
|
1449
|
-
"<%= config.bin %> <%= command.id %> abc123 --no-logs"
|
|
1450
|
-
"<%= config.bin %> <%= command.id %> abc123 --no-summary"
|
|
1444
|
+
"<%= config.bin %> <%= command.id %> abc123 --no-logs"
|
|
1451
1445
|
],
|
|
1452
1446
|
"flags": {
|
|
1453
1447
|
"no-logs": {
|
|
@@ -1456,12 +1450,6 @@
|
|
|
1456
1450
|
"allowNo": false,
|
|
1457
1451
|
"type": "boolean"
|
|
1458
1452
|
},
|
|
1459
|
-
"no-summary": {
|
|
1460
|
-
"description": "Skip displaying the AI-generated summary",
|
|
1461
|
-
"name": "no-summary",
|
|
1462
|
-
"allowNo": false,
|
|
1463
|
-
"type": "boolean"
|
|
1464
|
-
},
|
|
1465
1453
|
"api-key": {
|
|
1466
1454
|
"description": "Kradle API key",
|
|
1467
1455
|
"env": "KRADLE_API_KEY",
|
|
@@ -1555,5 +1543,5 @@
|
|
|
1555
1543
|
]
|
|
1556
1544
|
}
|
|
1557
1545
|
},
|
|
1558
|
-
"version": "0.6.
|
|
1546
|
+
"version": "0.6.11"
|
|
1559
1547
|
}
|
package/package.json
CHANGED
|
@@ -421,7 +421,6 @@ When no agents are specified, the command enters interactive mode:
|
|
|
421
421
|
| `--arena-image` | | Override arena-minecraft Docker image URL (env: `KRADLE_ARENA_IMAGE`) |
|
|
422
422
|
| `--no-open` | | Don't open the run URL in the browser |
|
|
423
423
|
| `--no-wait` | | Don't wait for completion (fire and forget) |
|
|
424
|
-
| `--no-summary` | | Don't wait for the AI-generated summary |
|
|
425
424
|
|
|
426
425
|
**Behavior (remote, default):**
|
|
427
426
|
1. Parses inline agents or enters interactive mode for agent selection
|
|
@@ -545,7 +544,6 @@ Gets details and optionally logs for a specific run.
|
|
|
545
544
|
```bash
|
|
546
545
|
kradle challenge runs get <run-id>
|
|
547
546
|
kradle challenge runs get <run-id> --no-logs
|
|
548
|
-
kradle challenge runs get <run-id> --no-summary
|
|
549
547
|
```
|
|
550
548
|
|
|
551
549
|
**Arguments:**
|
|
@@ -557,7 +555,6 @@ kradle challenge runs get <run-id> --no-summary
|
|
|
557
555
|
| Flag | Description | Default |
|
|
558
556
|
|------|-------------|---------|
|
|
559
557
|
| `--no-logs` | Skip fetching and displaying logs | false |
|
|
560
|
-
| `--no-summary` | Skip displaying the AI-generated summary | false |
|
|
561
558
|
|
|
562
559
|
**Output sections:**
|
|
563
560
|
|
|
@@ -570,9 +567,7 @@ kradle challenge runs get <run-id> --no-summary
|
|
|
570
567
|
3. **Participant Results** - Per-participant breakdown (table format):
|
|
571
568
|
- Participant ID, Agent name, Winner status, Score, Time to Success
|
|
572
569
|
|
|
573
|
-
4. **
|
|
574
|
-
|
|
575
|
-
5. **Logs** - Log entries from the run (unless `--no-logs` is used):
|
|
570
|
+
4. **Logs** - Log entries from the run (unless `--no-logs` is used):
|
|
576
571
|
- Timestamp, Level (colored), Participant ID, Message
|
|
577
572
|
- JSON messages are automatically parsed and formatted
|
|
578
573
|
|
|
@@ -590,9 +585,6 @@ kradle challenge runs get abc123def456
|
|
|
590
585
|
# Get details without logs (faster)
|
|
591
586
|
kradle challenge runs get abc123def456 --no-logs
|
|
592
587
|
|
|
593
|
-
# Get details without AI summary
|
|
594
|
-
kradle challenge runs get abc123def456 --no-summary
|
|
595
|
-
|
|
596
588
|
# Get details for a run (full ID)
|
|
597
589
|
kradle challenge runs get 12345678-1234-1234-1234-123456789012
|
|
598
590
|
```
|
|
@@ -1145,7 +1137,9 @@ export const config = {
|
|
|
1145
1137
|
|
|
1146
1138
|
### `kradle agent list`
|
|
1147
1139
|
|
|
1148
|
-
Lists all agents registered in the Kradle system.
|
|
1140
|
+
Lists all agents registered in the Kradle system with their model and pricing information.
|
|
1141
|
+
|
|
1142
|
+
Pricing (input/output cost per million tokens) is fetched from the OpenRouter API. Models without pricing data show `-`.
|
|
1149
1143
|
|
|
1150
1144
|
**Usage:**
|
|
1151
1145
|
```bash
|
|
@@ -1154,10 +1148,13 @@ kradle agent list
|
|
|
1154
1148
|
|
|
1155
1149
|
**Output format:**
|
|
1156
1150
|
```
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1151
|
+
Found 451 agents:
|
|
1152
|
+
|
|
1153
|
+
Agent Model Input/MTok Output/MTok
|
|
1154
|
+
───────────────────────────── ─────────────────────────── ────────── ───────────
|
|
1155
|
+
team-kradle:claude-sonnet-4-6 anthropic/claude-sonnet-4.6 $3.00 $15.00
|
|
1156
|
+
team-kradle:gemini-2-5-flash google/gemini-2.5-flash $0.30 $2.50
|
|
1157
|
+
team-kradle:gpt-4o openai/gpt-4o $2.50 $10.00
|
|
1161
1158
|
```
|
|
1162
1159
|
|
|
1163
1160
|
**Example:**
|
|
@@ -1234,6 +1231,46 @@ kradle ai-docs challenges-sdk > api-reference.md
|
|
|
1234
1231
|
|
|
1235
1232
|
---
|
|
1236
1233
|
|
|
1234
|
+
### `kradle ai-docs sync`
|
|
1235
|
+
|
|
1236
|
+
Syncs project AI docs (`AGENTS.md`, `CLAUDE.md`) to the latest version bundled with the CLI.
|
|
1237
|
+
|
|
1238
|
+
**Usage:**
|
|
1239
|
+
```bash
|
|
1240
|
+
kradle ai-docs sync
|
|
1241
|
+
kradle ai-docs sync --dry-run
|
|
1242
|
+
kradle ai-docs sync --yes
|
|
1243
|
+
kradle ai-docs sync --add-missing
|
|
1244
|
+
```
|
|
1245
|
+
|
|
1246
|
+
**Flags:**
|
|
1247
|
+
| Flag | Description | Default |
|
|
1248
|
+
|------|-------------|---------|
|
|
1249
|
+
| `--dry-run` | Preview changes without applying them | `false` |
|
|
1250
|
+
| `--yes` / `-y` | Skip confirmation prompts | `false` |
|
|
1251
|
+
| `--add-missing` | Add files that exist in template but not locally | `false` |
|
|
1252
|
+
|
|
1253
|
+
**Behavior:**
|
|
1254
|
+
- Compares local `AGENTS.md` and `CLAUDE.md` against the templates in the CLI's `static/project_template/` directory
|
|
1255
|
+
- Shows status for each file: identical, different, or missing locally
|
|
1256
|
+
- Displays line count diff for changed files
|
|
1257
|
+
- Prompts for confirmation before overwriting (unless `--yes`)
|
|
1258
|
+
- Missing files are only created when `--add-missing` is specified
|
|
1259
|
+
|
|
1260
|
+
**Examples:**
|
|
1261
|
+
```bash
|
|
1262
|
+
# Check what would change
|
|
1263
|
+
kradle ai-docs sync --dry-run
|
|
1264
|
+
|
|
1265
|
+
# Update all changed files without prompting
|
|
1266
|
+
kradle ai-docs sync --yes
|
|
1267
|
+
|
|
1268
|
+
# Update changed files and create any missing ones
|
|
1269
|
+
kradle ai-docs sync --yes --add-missing
|
|
1270
|
+
```
|
|
1271
|
+
|
|
1272
|
+
---
|
|
1273
|
+
|
|
1237
1274
|
## Common Workflows
|
|
1238
1275
|
|
|
1239
1276
|
### Creating and Testing a New Challenge
|
|
@@ -1336,6 +1373,7 @@ kradle challenge build --all --public
|
|
|
1336
1373
|
| `kradle world pull [slug]` | Pull world from cloud |
|
|
1337
1374
|
| `kradle world list` | List all worlds |
|
|
1338
1375
|
| `kradle world delete <slug>` | Delete world |
|
|
1339
|
-
| `kradle agent list` | List
|
|
1376
|
+
| `kradle agent list` | List agents with model pricing |
|
|
1340
1377
|
| `kradle ai-docs cli` | Output CLI reference for LLMs |
|
|
1341
1378
|
| `kradle ai-docs challenges-sdk [version]` | Output SDK reference for LLMs |
|
|
1379
|
+
| `kradle ai-docs sync` | Sync project AI docs to latest CLI version |
|