chofex-cli 0.1.186 → 0.1.187

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 -8
  2. package/dist/index.js +407 -224
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -19,11 +19,11 @@ chofex register
19
19
  chofex status
20
20
  chofex requirements
21
21
  chofex challenge list
22
- chofex challenge query
23
- chofex challenge notebook
24
- chofex challenge test --source ./shipping.js
25
- chofex challenge evaluate --source ./shipping.js
26
- chofex challenge ranking
22
+ chofex challenge query --challenge black-box
23
+ chofex challenge notebook --challenge black-box
24
+ chofex challenge test --challenge black-box --source ./shipping.js
25
+ chofex challenge evaluate --challenge black-box --source ./shipping.js
26
+ chofex challenge ranking --challenge black-box
27
27
  chofex challenge init --challenge broken-agent
28
28
  cd broken-agent && npm test
29
29
  chofex challenge test --challenge broken-agent --source ./scheduler.js
@@ -46,9 +46,9 @@ actual. Usa `CHOFEX_AUTO_UPDATE=0` para desactivar esta comprobación.
46
46
  optional phone number, bio, portfolio URL, shipped project, LinkedIn and GitHub
47
47
  URLs, and Terms and Conditions. Use `--input` to submit a completed JSON
48
48
  application.
49
- Acceptance creates a default badge from the profile visible to reviewers.
50
- `chofex confirm` updates its public name, one-line description, and picture
51
- while collecting the venue details required for attendance. After confirmation,
49
+ Acceptance creates a default badge from the Clerk profile visible to reviewers.
50
+ `chofex confirm` updates the public name, one-line description, and picture
51
+ while separately collecting the legal full name and venue details required for attendance. After confirmation,
52
52
  `chofex badge regenerate` can also update those public fields and the QR
53
53
  destination without changing the submitted application.
54
54
  The technical challenges do not block submission, but every challenge winner must submit
package/dist/index.js CHANGED
@@ -58580,11 +58580,13 @@ var challengeCatalog = [
58580
58580
  code: "02",
58581
58581
  theme: "Broken Agent",
58582
58582
  title: "The Scheduler",
58583
- summary: "Take a plausible AI-generated job scheduler whose public tests already pass and harden it against production reality.",
58584
- coreSkill: "Production correctness & reliability",
58583
+ summary: "Audita un job scheduler generado por AI cuyos tests públicos ya pasan y hazlo confiable bajo condiciones reales de producción.",
58584
+ coreSkill: "Correctitud y confiabilidad en producción",
58585
58585
  format: "accuracy",
58586
- formatLabel: "Production readiness score",
58586
+ formatLabel: "Puntaje de preparación para producción",
58587
58587
  opensAt: "2026-09-24T19:25:00.000Z",
58588
+ closesAt: "2026-10-02T05:00:00.000Z",
58589
+ rankingVisibleAt: "2026-10-01T20:00:00.000Z",
58588
58590
  queryLimit: 0,
58589
58591
  evaluationLimit: 5,
58590
58592
  hiddenSampleSize: 100,
@@ -58664,18 +58666,18 @@ var isChallengeRankingVisibleAt = (challenge, now3) => {
58664
58666
  };
58665
58667
  var challengeTimeZoneOffsetMs = 5 * 60 * 60 * 1000;
58666
58668
  var monthNames = [
58667
- "January",
58668
- "February",
58669
- "March",
58670
- "April",
58671
- "May",
58672
- "June",
58673
- "July",
58674
- "August",
58675
- "September",
58676
- "October",
58677
- "November",
58678
- "December"
58669
+ "enero",
58670
+ "febrero",
58671
+ "marzo",
58672
+ "abril",
58673
+ "mayo",
58674
+ "junio",
58675
+ "julio",
58676
+ "agosto",
58677
+ "septiembre",
58678
+ "octubre",
58679
+ "noviembre",
58680
+ "diciembre"
58679
58681
  ];
58680
58682
  var formatChallengeOpeningInPeru = (opensAt) => {
58681
58683
  const localTime = new Date(Date.parse(opensAt) - challengeTimeZoneOffsetMs);
@@ -58687,9 +58689,9 @@ var formatChallengeOpeningInPeru = (opensAt) => {
58687
58689
  const year = localTime.getUTCFullYear();
58688
58690
  const hour = String(localTime.getUTCHours()).padStart(2, "0");
58689
58691
  const minute = String(localTime.getUTCMinutes()).padStart(2, "0");
58690
- return `${month} ${day}, ${year} at ${hour}:${minute} (UTC-5)`;
58692
+ return `${day} de ${month} de ${year} a las ${hour}:${minute} (UTC-5)`;
58691
58693
  };
58692
- var challengeOpeningNotice = (title, opensAt) => `${title} opens ${formatChallengeOpeningInPeru(opensAt)}. Queries and evaluations are disabled until then; no attempts will be consumed.`;
58694
+ var challengeOpeningNotice = (title, opensAt) => `${title} abre el ${formatChallengeOpeningInPeru(opensAt)}. Las consultas y evaluaciones están deshabilitadas hasta entonces; no se consumirá ningún intento.`;
58693
58695
  var ChallengeSlugSchema = exports_Schema.Literals([
58694
58696
  "black-box",
58695
58697
  "broken-agent",
@@ -58721,6 +58723,7 @@ var ChallengeScoreSchema = exports_Schema.Struct({
58721
58723
  meanError: exports_Schema.Number,
58722
58724
  queriesUsed: exports_Schema.Number,
58723
58725
  runtimeMs: exports_Schema.Number,
58726
+ executionCost: exports_Schema.optional(exports_Schema.Number),
58724
58727
  evaluationsUsed: exports_Schema.optional(exports_Schema.Number),
58725
58728
  breakdown: exports_Schema.optional(exports_Schema.Struct({
58726
58729
  coreBehavior: exports_Schema.Struct({
@@ -58815,6 +58818,7 @@ var ChallengeEvaluationSummarySchema = exports_Schema.Struct({
58815
58818
  meanError: exports_Schema.Number,
58816
58819
  queriesUsed: exports_Schema.Number,
58817
58820
  runtimeMs: exports_Schema.Number,
58821
+ executionCost: exports_Schema.optional(exports_Schema.Number),
58818
58822
  shareCode: exports_Schema.String,
58819
58823
  rank: exports_Schema.optional(exports_Schema.Number),
58820
58824
  percentile: exports_Schema.optional(exports_Schema.Number),
@@ -58854,6 +58858,7 @@ var ChallengeEvaluationResultSchema = exports_Schema.Struct({
58854
58858
  meanError: exports_Schema.Number,
58855
58859
  queriesUsed: exports_Schema.Number,
58856
58860
  runtimeMs: exports_Schema.Number,
58861
+ executionCost: exports_Schema.optional(exports_Schema.Number),
58857
58862
  shareCode: exports_Schema.String,
58858
58863
  rank: exports_Schema.optional(exports_Schema.Number),
58859
58864
  competitorCount: exports_Schema.optional(exports_Schema.Number),
@@ -58877,6 +58882,7 @@ var ChallengeRankingEntrySchema = exports_Schema.Struct({
58877
58882
  meanError: exports_Schema.Number,
58878
58883
  queriesUsed: exports_Schema.Number,
58879
58884
  runtimeMs: exports_Schema.Number,
58885
+ executionCost: exports_Schema.optional(exports_Schema.Number),
58880
58886
  evaluatedAt: exports_Schema.String
58881
58887
  });
58882
58888
  var ChallengeRankingSchema = exports_Schema.Struct({
@@ -59045,7 +59051,7 @@ var ApplicationPartId = exports_Schema.Literals([
59045
59051
  ]);
59046
59052
  var acceptedDetailsInputFields = {
59047
59053
  fullName: nonBlank(200),
59048
- displayName: exports_Schema.optional(nonBlank(200)),
59054
+ name: exports_Schema.optional(nonBlank(200)),
59049
59055
  oneLiner: exports_Schema.optional(nonBlank(30)),
59050
59056
  phone: exports_Schema.optional(phone),
59051
59057
  dateOfBirth: exports_Schema.String.pipe(exports_Schema.check(exports_Schema.isPattern(/^\d{4}-\d{2}-\d{2}$/, {
@@ -59765,7 +59771,7 @@ var getChallengeRanking = (options, slug) => publicRequest(options, `/api/v1/cha
59765
59771
 
59766
59772
  // src/challenge-input.ts
59767
59773
  import { readFile as readFile3 } from "node:fs/promises";
59768
- var defaultChallengeSlug = "black-box";
59774
+ var defaultChallengeSlug = "broken-agent";
59769
59775
  var readStdin = async () => {
59770
59776
  const chunks = [];
59771
59777
  for await (const chunk of process.stdin) {
@@ -59894,28 +59900,28 @@ var challengeShowText = (attempt) => {
59894
59900
  const queriesRemaining = progress.queriesLimit - progress.queriesUsed;
59895
59901
  const evaluationsRemaining = progress.evaluationsLimit - progress.evaluationsUsed;
59896
59902
  if (challenge.slug === "broken-agent") {
59897
- let caseStatus2 = "READY TO AUDIT";
59903
+ let caseStatus2 = "LISTO PARA AUDITAR";
59898
59904
  if (attempt.latestEvaluation)
59899
- caseStatus2 = "EVALUATED";
59905
+ caseStatus2 = "EVALUADO";
59900
59906
  const lines3 = [
59901
- `${challenge.title.toUpperCase()} — CASE #${challenge.code}`,
59907
+ `${challenge.title.toUpperCase()} — CASO #${challenge.code}`,
59902
59908
  challenge.summary,
59903
59909
  "",
59904
- `CASE STATUS: ${caseStatus2}`,
59910
+ `ESTADO DEL CASO: ${caseStatus2}`,
59905
59911
  "",
59906
- "The public tests are green. Your job is to make the scheduler trustworthy under production conditions.",
59907
- "AI tools are allowed.",
59912
+ "Los tests públicos están verdes. Tu trabajo es hacer que el scheduler sea confiable bajo condiciones de producción.",
59913
+ "Las herramientas de AI están permitidas.",
59908
59914
  "",
59909
- `Evaluations ${evaluationsRemaining} / ${progress.evaluationsLimit} remaining`
59915
+ `Evaluaciones ${evaluationsRemaining} / ${progress.evaluationsLimit} restantes`
59910
59916
  ];
59911
59917
  if (progress.bestAccuracy !== undefined) {
59912
- lines3.push("", `Best score ${percent(progress.bestAccuracy)}`);
59918
+ lines3.push("", `Mejor puntaje ${percent(progress.bestAccuracy)}`);
59913
59919
  if (progress.rank !== undefined)
59914
- lines3.push(`Rank #${progress.rank}`);
59920
+ lines3.push(`Puesto #${progress.rank}`);
59915
59921
  if (progress.shareCode)
59916
- lines3.push(`Share code #${progress.shareCode}`);
59922
+ lines3.push(`Código #${progress.shareCode}`);
59917
59923
  }
59918
- lines3.push("", "YOUR NEXT MOVE", "Read the contract, audit scheduler.js, and keep the visible suite green.", " cd broken-agent && npm test", " chofex challenge test --challenge broken-agent --source ./broken-agent/scheduler.js");
59924
+ lines3.push("", "SIGUIENTE PASO", "Lee el contrato, audita scheduler.js y conserva verdes los tests visibles.", " cd broken-agent && npm test", " chofex challenge test --challenge broken-agent --source ./scheduler.js");
59919
59925
  return lines3.join(`
59920
59926
  `);
59921
59927
  }
@@ -60083,21 +60089,21 @@ var notebookCsvText = (observations) => {
60083
60089
  var challengeTestText = (result3) => {
60084
60090
  if (result3.kind === "broken_agent") {
60085
60091
  const lines3 = [
60086
- "PUBLIC SUITE — BROKEN AGENT",
60087
- `${result3.matchedObservations} / ${result3.observationCount} visible behaviors passing`
60092
+ "TESTS PÚBLICOS — BROKEN AGENT",
60093
+ `${result3.matchedObservations} / ${result3.observationCount} comportamientos visibles pasan`
60088
60094
  ];
60089
60095
  if (result3.accuracy === 1) {
60090
- lines3.push("", "Everything passes.", "Unfortunately, that does not mean the scheduler is production-correct.", "Reason about concurrency, restarts, failures, and idempotency before evaluating.", "", "Next: spend one official evaluation when you would ship it", " chofex challenge evaluate --challenge broken-agent --source ./broken-agent/scheduler.js");
60096
+ lines3.push("", "Todo pasa.", "Eso todavía no significa que el scheduler sea correcto en producción.", "Razona sobre concurrencia, reinicios, fallas e idempotencia antes de evaluar.", "", "Siguiente: usa una evaluación oficial cuando lo enviarías a producción", " chofex challenge evaluate --challenge broken-agent --source ./scheduler.js");
60091
60097
  return lines3.join(`
60092
60098
  `);
60093
60099
  }
60094
60100
  if (result3.mismatches.length > 0) {
60095
- lines3.push("", "Visible failures:");
60101
+ lines3.push("", "Fallas visibles:");
60096
60102
  for (const mismatch of result3.mismatches) {
60097
60103
  lines3.push(` ${String(mismatch.actual)}`);
60098
60104
  }
60099
60105
  }
60100
- lines3.push("", "Fix the public regressions before using an official evaluation.");
60106
+ lines3.push("", "Corrige las regresiones públicas antes de usar una evaluación oficial.");
60101
60107
  return lines3.join(`
60102
60108
  `);
60103
60109
  }
@@ -60128,29 +60134,30 @@ var challengeTestText = (result3) => {
60128
60134
  };
60129
60135
  var challengeEvaluateText = (result3) => {
60130
60136
  if (result3.breakdown) {
60137
+ const executionCost = result3.executionCost ?? result3.runtimeMs;
60131
60138
  const capabilityLines = [
60132
- ["Core behavior", result3.breakdown.coreBehavior],
60133
- ["Persistence", result3.breakdown.persistence],
60134
- ["Concurrency", result3.breakdown.concurrency],
60135
- ["Failure recovery", result3.breakdown.failureRecovery],
60136
- ["Idempotency", result3.breakdown.idempotency],
60137
- ["Regression safety", result3.breakdown.regressionSafety],
60138
- ["Performance", result3.breakdown.performance]
60139
+ ["Comportamiento base", result3.breakdown.coreBehavior],
60140
+ ["Persistencia", result3.breakdown.persistence],
60141
+ ["Concurrencia", result3.breakdown.concurrency],
60142
+ ["Recuperación", result3.breakdown.failureRecovery],
60143
+ ["Idempotencia", result3.breakdown.idempotency],
60144
+ ["Sin regresiones", result3.breakdown.regressionSafety],
60145
+ ["Rendimiento", result3.breakdown.performance]
60139
60146
  ];
60140
60147
  const lines3 = [
60141
- "OFFICIAL VERDICT — BROKEN AGENT — PRODUCTION READINESS",
60142
- `Score ${(result3.accuracy * 100).toFixed(2)} / ${result3.sampleSize}`,
60143
- `Runtime ${result3.runtimeMs} ms`,
60148
+ "VEREDICTO OFICIAL — BROKEN AGENT — PREPARACIÓN PARA PRODUCCIÓN",
60149
+ `Puntaje ${(result3.accuracy * 100).toFixed(2)} / ${result3.sampleSize}`,
60150
+ `Costo determinístico ${executionCost} ops`,
60144
60151
  "",
60145
- "Capability scores",
60152
+ "Puntajes por capacidad",
60146
60153
  ...capabilityLines.map(([label, score]) => `${label.padEnd(20)}${score.earned.toFixed(2)} / ${score.available}`)
60147
60154
  ];
60148
60155
  if (result3.rank !== undefined) {
60149
- lines3.push(`Rank #${result3.rank}`);
60156
+ lines3.push(`Puesto #${result3.rank}`);
60150
60157
  }
60151
- lines3.push(`Official evaluations remaining ${result3.evaluationsRemaining} / ${result3.evaluationsLimit}`, "", result3.shareText, "", "Next: inspect the leaderboard", " chofex challenge ranking --challenge broken-agent");
60158
+ lines3.push(`Evaluaciones oficiales restantes ${result3.evaluationsRemaining} / ${result3.evaluationsLimit}`, "", result3.shareText, "", "Siguiente: consulta el ranking", " chofex challenge ranking --challenge broken-agent");
60152
60159
  if (result3.evaluationsRemaining > 0) {
60153
- lines3.push("", "The evaluator reports capabilities, not individual hidden cases. Reason before submitting again.", " chofex challenge test --challenge broken-agent --source ./broken-agent/scheduler.js");
60160
+ lines3.push("", "El evaluador reporta capacidades, no casos ocultos individuales. Razona antes de volver a enviar.", " chofex challenge test --challenge broken-agent --source ./scheduler.js");
60154
60161
  }
60155
60162
  return lines3.join(`
60156
60163
  `);
@@ -60175,23 +60182,24 @@ var challengeRankingText = (ranking, now3 = new Date) => {
60175
60182
  const lines2 = [`${ranking.challenge.theme} — ${ranking.challenge.title}`];
60176
60183
  const { rankingVisibleAt } = ranking.challenge;
60177
60184
  if (rankingVisibleAt && !isChallengeRankingVisibleAt(ranking.challenge, now3)) {
60178
- lines2.push("", `Ranking available ${formatChallengeOpeningInPeru(rankingVisibleAt)}.`);
60185
+ lines2.push("", `Ranking disponible ${formatChallengeOpeningInPeru(rankingVisibleAt)}.`);
60179
60186
  return lines2.join(`
60180
60187
  `);
60181
60188
  }
60182
60189
  lines2.push("");
60183
60190
  if (ranking.entries.length === 0) {
60184
- lines2.push("No official evaluations yet.");
60191
+ lines2.push("Todavía no hay evaluaciones oficiales.");
60185
60192
  return lines2.join(`
60186
60193
  `);
60187
60194
  }
60188
60195
  if (ranking.challenge.slug === "broken-agent") {
60189
- lines2.push("Rank Score Points Runtime Name");
60196
+ lines2.push("Psto Puntaje Puntos Costo Nombre");
60190
60197
  for (const entry of ranking.entries.slice(0, 20)) {
60191
60198
  const rank = String(entry.rank).padStart(4, " ");
60192
60199
  const accuracy = percent(entry.accuracy).padStart(8, " ");
60193
60200
  const points = `${entry.exactCount}/${entry.sampleSize}`.padStart(11, " ");
60194
- const runtime = `${entry.runtimeMs}ms`.padStart(8, " ");
60201
+ const executionCost = entry.executionCost ?? entry.runtimeMs;
60202
+ const runtime = `${executionCost}ops`.padStart(8, " ");
60195
60203
  const profileLinks = [entry.githubUrl, entry.linkedInUrl].filter(Boolean);
60196
60204
  const participant = [entry.displayName, ...profileLinks].join(" ");
60197
60205
  lines2.push(`${rank} ${accuracy} ${points} ${runtime} ${participant}`);
@@ -60250,16 +60258,83 @@ var brokenAgentPackageJson = `${JSON.stringify({
60250
60258
  var brokenAgentStarterSource = `/**
60251
60259
  * Broken Agent — The Scheduler
60252
60260
  *
60253
- * A coding agent implemented this scheduler and declared the feature complete.
60254
- * Every public test passes. The implementation is not production-correct.
60255
- * Keep the createScheduler interface intact and harden the implementation.
60261
+ * Un agente de código implementó este scheduler y declaró la tarea terminada.
60262
+ * Todos los tests públicos pasan, pero todavía hay fallas sutiles de producción.
60263
+ * Mantén intacta la interfaz createScheduler y endurece la implementación.
60256
60264
  */
60257
- function createScheduler({ store, clock, execute }) {
60265
+ function createScheduler({ store, clock, execute, workerId }) {
60266
+ const clone = (value) => JSON.parse(JSON.stringify(value));
60267
+ const canonical = (value) => {
60268
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
60269
+ if (Array.isArray(value)) return "[" + value.map(canonical).join(",") + "]";
60270
+ const entries = Object.keys(value).sort().map((key) =>
60271
+ JSON.stringify(key) + ":" + canonical(value[key]),
60272
+ );
60273
+ return "{" + entries.join(",") + "}";
60274
+ };
60275
+ const isJsonValue = (value) => {
60276
+ if (value === null) return true;
60277
+ if (["string", "boolean"].includes(typeof value)) return true;
60278
+ if (typeof value === "number") return Number.isFinite(value);
60279
+ if (Array.isArray(value)) return value.every(isJsonValue);
60280
+ if (!value || typeof value !== "object") return false;
60281
+ const prototype = Object.getPrototypeOf(value);
60282
+ if (prototype !== Object.prototype && prototype !== null) return false;
60283
+ return Object.values(value).every(isJsonValue);
60284
+ };
60285
+ const isIsoTimestamp = (value) => {
60286
+ if (typeof value !== "string") return false;
60287
+ const match = value.match(
60288
+ /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(?:\\.\\d{1,3})?(?:Z|([+-])(\\d{2}):(\\d{2}))$/,
60289
+ );
60290
+ if (!match) return false;
60291
+ const [, year, month, day, hour, minute, second, , offsetHour, offsetMinute] = match;
60292
+ const values = [year, month, day, hour, minute, second, offsetHour || "0", offsetMinute || "0"].map(Number);
60293
+ const [yearValue, monthValue, dayValue, hourValue, minuteValue, secondValue, offsetHourValue, offsetMinuteValue] = values;
60294
+ const maximumDay = new Date(Date.UTC(yearValue, monthValue, 0)).getUTCDate();
60295
+ return monthValue >= 1 && monthValue <= 12 &&
60296
+ dayValue >= 1 && dayValue <= maximumDay &&
60297
+ hourValue <= 23 && minuteValue <= 59 && secondValue <= 59 &&
60298
+ offsetHourValue <= 23 && offsetMinuteValue <= 59 &&
60299
+ Number.isFinite(Date.parse(value));
60300
+ };
60301
+ const ordered = (jobs) => jobs.sort((left, right) =>
60302
+ Date.parse(left.runAt) - Date.parse(right.runAt) ||
60303
+ left.id.localeCompare(right.id),
60304
+ );
60305
+ const normalize = (input) => {
60306
+ if (!input || typeof input !== "object") throw new Error("Job is required");
60307
+ if (typeof input.id !== "string" || !/^[A-Za-z0-9_-]{1,64}$/.test(input.id)) {
60308
+ throw new Error("Job id is invalid");
60309
+ }
60310
+ if (
60311
+ !isIsoTimestamp(input.runAt)
60312
+ ) throw new Error("runAt must include an explicit timezone");
60313
+ if (!isJsonValue(input.payload)) throw new Error("payload must be JSON");
60314
+ return {
60315
+ id: input.id,
60316
+ runAt: input.runAt,
60317
+ payload: clone(input.payload),
60318
+ status: "pending",
60319
+ attempts: 0,
60320
+ };
60321
+ };
60322
+
60258
60323
  return {
60259
60324
  async schedule(input) {
60260
- const job = { ...input, status: "pending" };
60261
- await store.transaction((tx) => tx.put(job));
60262
- return job;
60325
+ const requested = normalize(input);
60326
+ return store.transaction((tx) => {
60327
+ const existing = tx.get(requested.id);
60328
+ if (!existing) {
60329
+ tx.put(requested);
60330
+ return clone(requested);
60331
+ }
60332
+ const identical =
60333
+ existing.runAt === requested.runAt &&
60334
+ canonical(existing.payload) === canonical(requested.payload);
60335
+ if (!identical) throw new Error("A different job already uses this id");
60336
+ return clone(existing);
60337
+ });
60263
60338
  },
60264
60339
 
60265
60340
  async cancel(id) {
@@ -60272,18 +60347,59 @@ function createScheduler({ store, clock, execute }) {
60272
60347
  },
60273
60348
 
60274
60349
  async list() {
60275
- return store.transaction((tx) => tx.list());
60350
+ const jobs = await store.transaction((tx) => tx.list());
60351
+ return ordered(jobs).map(clone);
60276
60352
  },
60277
60353
 
60278
60354
  async runDue() {
60279
- const now = clock.now().getTime();
60280
- const jobs = await store.transaction((tx) => tx.list());
60281
- for (const job of jobs) {
60282
- if (job.status !== "pending" || Date.parse(job.runAt) > now) continue;
60283
- await execute(job);
60284
- await store.transaction((tx) =>
60285
- tx.put({ ...job, status: "completed" }),
60286
- );
60355
+ const visited = new Set();
60356
+ while (true) {
60357
+ const now = clock.now().getTime();
60358
+ const claimed = await store.transaction((tx) => {
60359
+ for (const job of tx.list()) {
60360
+ if (
60361
+ job.status === "running" &&
60362
+ typeof job.leaseUntil === "number" &&
60363
+ job.leaseUntil < now
60364
+ ) {
60365
+ tx.put({ ...job, status: "pending" });
60366
+ }
60367
+ }
60368
+ const due = ordered(tx.list()).find((job) =>
60369
+ job.status === "pending" &&
60370
+ !visited.has(job.id) &&
60371
+ Date.parse(job.runAt) <= now,
60372
+ );
60373
+ if (!due) return undefined;
60374
+ const running = {
60375
+ ...due,
60376
+ status: "running",
60377
+ attempts: due.attempts + 1,
60378
+ owner: workerId,
60379
+ leaseUntil: now + 30_000,
60380
+ };
60381
+ tx.put(running);
60382
+ return running;
60383
+ });
60384
+ if (!claimed) return;
60385
+ visited.add(claimed.id);
60386
+
60387
+ try {
60388
+ await execute(clone(claimed));
60389
+ await store.transaction((tx) => {
60390
+ const current = tx.get(claimed.id);
60391
+ if (current?.status === "running" && current.owner === workerId) {
60392
+ tx.put({ ...current, status: "completed" });
60393
+ }
60394
+ });
60395
+ } catch {
60396
+ await store.transaction((tx) => {
60397
+ const current = tx.get(claimed.id);
60398
+ if (current?.status !== "running" || current.owner !== workerId) return;
60399
+ const status = current.attempts > 3 ? "failed" : "pending";
60400
+ tx.put({ ...current, status });
60401
+ });
60402
+ }
60287
60403
  }
60288
60404
  },
60289
60405
  };
@@ -60293,78 +60409,98 @@ module.exports = { createScheduler };
60293
60409
  `;
60294
60410
  var brokenAgentReadme = `# Broken Agent — The Scheduler
60295
60411
 
60296
- > A coding agent was asked to implement a feature. It says it is done. It is
60297
- > not. Your job is to ship it.
60412
+ > Un agente de código dice que terminó. Todos los tests públicos pasan. Tu
60413
+ > trabajo es decidir si realmente lo enviarías a producción y repararlo.
60298
60414
 
60299
- The repository starts with all public tests passing. Repair \`scheduler.js\`
60300
- without changing its exported \`createScheduler(dependencies)\` interface.
60415
+ Repara \`scheduler.js\` sin cambiar la interfaz exportada
60416
+ \`createScheduler(dependencies)\`.
60301
60417
 
60302
- ## Commands
60418
+ ## Comandos
60303
60419
 
60304
60420
  \`\`\`sh
60305
60421
  npm test
60306
- chofex challenge test --challenge broken-agent --source ./broken-agent/scheduler.js
60307
- chofex challenge evaluate --challenge broken-agent --source ./broken-agent/scheduler.js
60422
+ chofex challenge test --challenge broken-agent --source ./scheduler.js
60423
+ chofex challenge evaluate --challenge broken-agent --source ./scheduler.js
60308
60424
  \`\`\`
60309
60425
 
60310
- Local and public tests are unlimited. You have **5 official evaluations**
60311
- against hidden production scenarios. AI tools are explicitly allowed.
60426
+ Los tests locales y públicos son ilimitados. Tienes **5 evaluaciones oficiales**
60427
+ contra escenarios ocultos. Las herramientas de AI están permitidas.
60312
60428
 
60313
- ## Public contract
60429
+ ## Contrato normativo
60314
60430
 
60315
- \`createScheduler({ store, clock, execute, workerId })\` returns:
60431
+ \`createScheduler({ store, clock, execute, workerId })\` devuelve:
60316
60432
 
60317
60433
  - \`schedule({ id, runAt, payload })\`
60318
60434
  - \`cancel(id)\`
60319
60435
  - \`list()\`
60320
60436
  - \`runDue()\`
60321
60437
 
60322
- ### Jobs
60323
-
60324
- - \`id\` matches \`^[A-Za-z0-9_-]{1,64}$\`.
60325
- - \`runAt\` is an ISO-8601 timestamp with an explicit timezone.
60326
- - \`payload\` is JSON-serializable.
60327
- - Scheduling an identical job ID is idempotent. Reusing an ID for different
60328
- work must reject without changing the original job.
60329
- - Past timestamps are valid and become due immediately.
60330
- - \`list()\` returns jobs ordered by \`runAt\`, then \`id\`.
60331
-
60332
- ### Durability and concurrency
60333
-
60334
- - The supplied store survives scheduler instances and process restarts.
60335
- - Several workers may call \`runDue()\` concurrently against the same store.
60336
- - A worker claim lasts 30 seconds. Another worker may reclaim the job when
60337
- \`clock.now()\` reaches that lease deadline.
60338
- - A pending job may be cancelled. A running or terminal job may not.
60339
- - Failed executions retry, without preventing other due jobs from running.
60340
- - A job becomes \`failed\` after 3 unsuccessful attempts.
60341
- - The execution adapter applies effects idempotently by job ID. A worker may
60342
- stop after the effect is applied but before completion is recorded; retrying
60343
- must eventually complete the job without duplicating the effect.
60344
-
60345
- The store exposes only \`transaction(action)\`. Inside an action, \`tx\`
60346
- provides synchronous \`get(id)\`, \`put(job)\`, \`delete(id)\`, and \`list()\`
60347
- operations. Transactions are serialized. Do not keep a transaction open while
60348
- executing a job.
60349
-
60350
- \`clock.now()\` returns a \`Date\`. \`execute(job)\` returns a promise.
60351
-
60352
- ## Evaluation
60353
-
60354
- The hidden evaluator checks the published contract under deterministic
60355
- concurrency, restart, failure, idempotency, compatibility, and load scenarios.
60356
- It reports capability-level scores, not individual hidden-test failures.
60357
-
60358
- - Core behavior: 10 points
60359
- - Persistence: 15 points
60360
- - Concurrency: 20 points
60361
- - Failure recovery: 20 points
60362
- - Idempotency: 15 points
60363
- - Regression safety: 15 points
60364
- - Performance: 5 points, available only when the load jobs complete correctly
60365
-
60366
- Ranking order is total score, fewer official evaluations used, runtime, then
60367
- official submission time. Submission time is only the final tie-breaker.
60438
+ ### Jobs y valores de retorno
60439
+
60440
+ - \`id\` cumple \`^[A-Za-z0-9_-]{1,64}$\`.
60441
+ - \`runAt\` usa el perfil ISO-8601
60442
+ \`YYYY-MM-DDTHH:mm:ss[.SSS](Z|±HH:mm)\`: los segundos y la zona son
60443
+ obligatorios, y la fracción opcional admite entre uno y tres dígitos.
60444
+ - \`payload\` es un valor JSON estricto: null, boolean, string, número finito,
60445
+ arreglo u objeto compuesto únicamente por otros valores JSON.
60446
+ - Los timestamps pasados son válidos y quedan vencidos inmediatamente.
60447
+ - \`schedule()\` persiste y devuelve el job. Programar el mismo ID, timestamp y
60448
+ payload JSON estructuralmente equivalente es idempotente. Reutilizar un ID
60449
+ para otro trabajo debe rechazar sin cambiar el job original.
60450
+ - \`cancel()\` devuelve true solo cuando cambia un job pendiente a cancelado.
60451
+ Un job running, completed, failed o inexistente no puede cancelarse.
60452
+ - \`list()\` devuelve todos los jobs ordenados cronológicamente por \`runAt\` y,
60453
+ ante empate, por \`id\`. Como mínimo expone \`id\`, \`runAt\`, \`payload\`,
60454
+ \`status\` y \`attempts\`.
60455
+
60456
+ ### Estado, concurrencia y recuperación
60457
+
60458
+ - Los estados son \`pending\`, \`running\`, \`completed\`, \`failed\` y
60459
+ \`cancelled\`. Los jobs nuevos empiezan pending con cero intentos.
60460
+ - El store sobrevive nuevas instancias del scheduler y reinicios del proceso.
60461
+ - Varios workers, incluso instancias que reutilizan un \`workerId\` después de
60462
+ reiniciar, pueden llamar \`runDue()\` contra el mismo store.
60463
+ - \`runDue()\` intenta una vez cada job vencido al inicio de esa llamada. Un job
60464
+ que falla queda pendiente para una llamada posterior y no bloquea otros jobs.
60465
+ - Cada ejecución debe reclamarse atómicamente antes de llamar al executor. El
60466
+ claim dura 30 segundos y necesita una identidad única distinta de
60467
+ \`workerId\`. Cuando \`clock.now()\` alcanza el deadline, otro worker puede
60468
+ reclamarlo. Un worker obsoleto nunca puede completar ni reabrir un claim más
60469
+ nuevo.
60470
+ - Un intento se cuenta al reclamar el job. Después de 3 ejecuciones fallidas el
60471
+ job queda failed.
60472
+ - \`execute(job)\` puede fallar antes o después de aplicar el efecto. El adapter
60473
+ aplica efectos idempotentemente por job ID, por lo que reintentar debe llevar
60474
+ el job a completed sin duplicar el efecto. No se promete exactly-once para
60475
+ efectos arbitrarios.
60476
+ - \`runDue()\` resuelve cuando ya procesó todos los jobs que podía reclamar en
60477
+ esa llamada. No mantiene una transacción abierta mientras ejecuta un job.
60478
+
60479
+ El store expone solo \`transaction(action)\`. Dentro de una acción, \`tx\`
60480
+ ofrece operaciones síncronas \`get(id)\`, \`put(job)\`, \`delete(id)\` y
60481
+ \`list()\`. Las transacciones están serializadas. \`clock.now()\` devuelve un
60482
+ \`Date\`; \`execute(job)\` devuelve una promesa.
60483
+
60484
+ ## Evaluación
60485
+
60486
+ El evaluador usa variantes determinísticas por participante para probar el
60487
+ contrato bajo concurrencia, reinicios, fallas, idempotencia, compatibilidad y
60488
+ carga. Reporta puntajes por capacidad, no casos ocultos individuales.
60489
+
60490
+ - Comportamiento base: 10 puntos
60491
+ - Persistencia: 15 puntos
60492
+ - Concurrencia: 20 puntos
60493
+ - Recuperación ante fallas: 20 puntos
60494
+ - Idempotencia: 15 puntos
60495
+ - Seguridad contra regresiones: 15 puntos
60496
+ - Rendimiento: 5 puntos, solo si la carga termina correctamente y sin perder
60497
+ seguridad de concurrencia
60498
+
60499
+ El ranking exige una postulación enviada o revisada. Ordena por puntaje total,
60500
+ menos evaluaciones oficiales, costo determinístico de ejecución y hora del mejor
60501
+ envío. El costo es \`transacciones + ceil(jobs recorridos por tx.list / 10)\` en
60502
+ una carga equivalente para todos; no usa tiempo de servidor. Todos los puntajes
60503
+ válidos aparecen en el ranking.
60368
60504
  `;
60369
60505
  var brokenAgentPublicTestSource = `const test = require("node:test");
60370
60506
  const assert = require("node:assert/strict");
@@ -60396,52 +60532,99 @@ class MemoryStore {
60396
60532
  }
60397
60533
  }
60398
60534
 
60399
- const setup = () => {
60400
- const store = new MemoryStore();
60401
- const now = new Date("2026-10-17T15:00:00.000Z");
60535
+ const setup = (options = {}) => {
60536
+ const store = options.store || new MemoryStore();
60537
+ const now = options.now || new Date("2026-10-17T15:00:00.000Z");
60402
60538
  const executed = [];
60539
+ const execute = options.execute || (async (job) => executed.push(job.id));
60403
60540
  const scheduler = createScheduler({
60404
60541
  store,
60405
60542
  clock: { now: () => new Date(now) },
60406
- execute: async (job) => executed.push(job.id),
60407
- workerId: "public-worker",
60543
+ execute,
60544
+ workerId: options.workerId || "public-worker",
60408
60545
  });
60409
60546
  return { store, scheduler, executed };
60410
60547
  };
60411
60548
 
60412
- const job = (id, runAt = "2026-10-17T15:00:00.000Z") => ({
60549
+ const job = (id, runAt = "2026-10-17T15:00:00.000Z", payload = { message: id }) => ({
60413
60550
  id,
60414
60551
  runAt,
60415
- payload: { message: id },
60552
+ payload,
60416
60553
  });
60417
60554
 
60418
- test("schedules and lists a job", async () => {
60555
+ test("programa un job y conserva el estado público", async () => {
60419
60556
  const { scheduler } = setup();
60420
- await scheduler.schedule(job("job-1"));
60557
+ const scheduled = await scheduler.schedule(job("job-1"));
60558
+ assert.equal(scheduled.status, "pending");
60559
+ assert.equal(scheduled.attempts, 0);
60421
60560
  assert.equal((await scheduler.list()).length, 1);
60422
60561
  });
60423
60562
 
60424
- test("executes a due job", async () => {
60425
- const { scheduler, executed } = setup();
60426
- await scheduler.schedule(job("job-1"));
60427
- await scheduler.runDue();
60428
- assert.deepEqual(executed, ["job-1"]);
60429
- });
60430
-
60431
- test("does not execute a future job", async () => {
60563
+ test("ejecuta vencidos y deja futuros pendientes", async () => {
60432
60564
  const { scheduler, executed } = setup();
60565
+ await scheduler.schedule(job("due"));
60433
60566
  await scheduler.schedule(job("future", "2026-10-17T16:00:00.000Z"));
60434
60567
  await scheduler.runDue();
60435
- assert.deepEqual(executed, []);
60568
+ assert.deepEqual(executed, ["due"]);
60569
+ const jobs = await scheduler.list();
60570
+ assert.equal(jobs.find((entry) => entry.id === "due").status, "completed");
60571
+ assert.equal(jobs.find((entry) => entry.id === "future").status, "pending");
60436
60572
  });
60437
60573
 
60438
- test("cancels a pending job", async () => {
60574
+ test("cancela únicamente jobs pendientes", async () => {
60439
60575
  const { scheduler, executed } = setup();
60440
60576
  await scheduler.schedule(job("cancel-me"));
60441
60577
  assert.equal(await scheduler.cancel("cancel-me"), true);
60578
+ assert.equal(await scheduler.cancel("cancel-me"), false);
60442
60579
  await scheduler.runDue();
60443
60580
  assert.deepEqual(executed, []);
60444
60581
  });
60582
+
60583
+ test("programar el mismo trabajo es idempotente y los conflictos rechazan", async () => {
60584
+ const { scheduler } = setup();
60585
+ await scheduler.schedule(job("same", undefined, { a: 1, b: 2 }));
60586
+ await scheduler.schedule(job("same", undefined, { b: 2, a: 1 }));
60587
+ await assert.rejects(() => scheduler.schedule(job("same", undefined, { a: 2 })));
60588
+ assert.equal((await scheduler.list()).length, 1);
60589
+ });
60590
+
60591
+ test("valida IDs, timestamps con zona y payloads JSON", async () => {
60592
+ const { scheduler } = setup();
60593
+ await assert.rejects(() => scheduler.schedule(job("contains spaces")));
60594
+ await assert.rejects(() => scheduler.schedule(job("bad-time", "tomorrow-ish")));
60595
+ await assert.rejects(() => scheduler.schedule(job("missing-zone", "2026-10-17T15:00:00")));
60596
+ await assert.rejects(() => scheduler.schedule(job("missing-seconds", "2026-10-17T15:00Z")));
60597
+ await assert.rejects(() => scheduler.schedule(job("long-fraction", "2026-10-17T15:00:00.1234Z")));
60598
+ await assert.rejects(() => scheduler.schedule(job("bad-payload", undefined, { value: undefined })));
60599
+ });
60600
+
60601
+ test("ordena cronológicamente y usa el ID para desempatar", async () => {
60602
+ const { scheduler } = setup();
60603
+ await scheduler.schedule(job("later", "2026-10-17T16:30:00.000Z"));
60604
+ await scheduler.schedule(job("first", "2026-10-17T10:00:00-05:00"));
60605
+ await scheduler.schedule(job("also-first", "2026-10-17T15:00:00.000Z"));
60606
+ assert.deepEqual((await scheduler.list()).map((entry) => entry.id), ["also-first", "first", "later"]);
60607
+ });
60608
+
60609
+ test("una falla no bloquea otros jobs y reintenta en la llamada siguiente", async () => {
60610
+ let failures = 1;
60611
+ const executed = [];
60612
+ const { scheduler } = setup({
60613
+ execute: async (entry) => {
60614
+ if (entry.id === "flaky" && failures > 0) {
60615
+ failures -= 1;
60616
+ throw new Error("transient");
60617
+ }
60618
+ executed.push(entry.id);
60619
+ },
60620
+ });
60621
+ await scheduler.schedule(job("flaky"));
60622
+ await scheduler.schedule(job("healthy"));
60623
+ await scheduler.runDue();
60624
+ assert.deepEqual(executed, ["healthy"]);
60625
+ await scheduler.runDue();
60626
+ assert.deepEqual(executed, ["healthy", "flaky"]);
60627
+ });
60445
60628
  `;
60446
60629
 
60447
60630
  // src/challenge-scaffold.ts
@@ -60655,69 +60838,69 @@ var badgeText = (result3) => {
60655
60838
 
60656
60839
  // src/challenge-commands.ts
60657
60840
  var challengeQuickstart = {
60658
- title: "THE SHIPPING MACHINE",
60841
+ title: "BROKEN AGENT — THE SCHEDULER",
60659
60842
  story: [
60660
- "A delivery company is about to retire the service that prices every shipment.",
60661
- "There is no documentation and no source code—only five controls and the price the machine returns."
60843
+ "Un agente de código implementó un job scheduler y declaró la tarea terminada.",
60844
+ "Los siete tests públicos pasan, pero eso no demuestra que sea seguro bajo concurrencia, reinicios y fallas."
60662
60845
  ],
60663
- mission: "Learn the hidden pricing rules, then replace the machine with your own calculateShipping(input) function.",
60846
+ mission: "Audita scheduler.js, conserva createScheduler(dependencies) y haz que el sistema cumpla el contrato de producción.",
60664
60847
  rules: [
60665
- "You have 25 oracle queries to gather evidence.",
60666
- "You have 3 official evaluations against hidden shipments.",
60667
- "Local notebook tests are free. Accuracy wins, then exact matches, then fewer oracle queries.",
60668
- "AI tools are welcome, but the hidden rules are personalized to you."
60848
+ "Tienes 5 evaluaciones oficiales contra variantes ocultas y determinísticas por participante.",
60849
+ "Los tests locales y públicos son ilimitados.",
60850
+ "Gana el puntaje total; los empates usan menos evaluaciones, costo determinístico y hora del mejor envío.",
60851
+ "Las herramientas de AI están permitidas."
60669
60852
  ],
60670
60853
  workflow: [
60671
60854
  {
60672
60855
  step: 1,
60673
- action: "Sign in",
60856
+ action: "Inicia sesión",
60674
60857
  command: "chofex login",
60675
- note: "Opens Clerk authentication in your browser."
60858
+ note: "Abre la autenticación de Clerk en tu navegador."
60676
60859
  },
60677
60860
  {
60678
60861
  step: 2,
60679
- action: "Prepare your field kit",
60680
- command: "chofex challenge init",
60681
- note: "Creates a documented shipping.js starter without overwriting existing work."
60862
+ action: "Crea el repositorio del challenge",
60863
+ command: "chofex challenge init --challenge broken-agent",
60864
+ note: "Crea broken-agent/ con el contrato, el scheduler y siete tests públicos sin sobrescribir trabajo existente."
60682
60865
  },
60683
60866
  {
60684
60867
  step: 3,
60685
- action: "Check your budget",
60686
- command: "chofex challenge show",
60687
- note: "Shows remaining oracle queries and official evaluations."
60868
+ action: "Confirma el punto de partida",
60869
+ command: "cd broken-agent && npm test",
60870
+ note: "Todo pasa. Ahora debes encontrar los riesgos que los happy paths no cubren."
60688
60871
  },
60689
60872
  {
60690
60873
  step: 4,
60691
- action: "Probe the Black Box",
60692
- command: "chofex challenge query --distance 10 --weight 3 --hour 14 --fragile false --express false",
60693
- note: "A successful query reveals one shipping price and consumes one query."
60874
+ action: "Revisa tu presupuesto",
60875
+ command: "chofex challenge show --challenge broken-agent",
60876
+ note: "Muestra las evaluaciones oficiales restantes y tu mejor puntaje."
60694
60877
  },
60695
60878
  {
60696
60879
  step: 5,
60697
- action: "Study your observations",
60698
- command: "chofex challenge notebook",
60699
- note: "Compare inputs and outputs to infer the pricing rules."
60880
+ action: "Audita y repara",
60881
+ command: "$EDITOR scheduler.js",
60882
+ note: "Razona sobre claims únicos, leases, reinicios, carreras, cancelación, reintentos e idempotencia."
60700
60883
  },
60701
60884
  {
60702
60885
  step: 6,
60703
- action: "Edit and test your replacement",
60704
- command: "chofex challenge test --source ./shipping.js",
60705
- note: "Checks your solution against your notebook without consuming an official evaluation."
60886
+ action: "Ejecuta los tests públicos",
60887
+ command: "chofex challenge test --challenge broken-agent --source ./scheduler.js",
60888
+ note: "Es seguro repetirlos y no consumen evaluaciones oficiales."
60706
60889
  },
60707
60890
  {
60708
60891
  step: 7,
60709
- action: "Submit to the hidden test set",
60710
- command: "chofex challenge evaluate --source ./shipping.js",
60711
- note: "Official evaluations are limited. Use test as often as needed, then evaluate when your solution is ready."
60892
+ action: "Solicita un veredicto oculto",
60893
+ command: "chofex challenge evaluate --challenge broken-agent --source ./scheduler.js",
60894
+ note: "Úsalo solo cuando enviarías la implementación a producción."
60712
60895
  },
60713
60896
  {
60714
60897
  step: 8,
60715
- action: "Check the leaderboard",
60716
- command: "chofex challenge ranking",
60717
- note: "Shows the public ranking without consuming budget."
60898
+ action: "Consulta el ranking",
60899
+ command: "chofex challenge ranking --challenge broken-agent",
60900
+ note: "Se revela el 1 de octubre a las 15:00, hora de Perú."
60718
60901
  }
60719
60902
  ],
60720
- helpCommand: "chofex challenge query --help"
60903
+ helpCommand: "chofex challenge test --help"
60721
60904
  };
60722
60905
  var launchNoticeFor = (slug) => {
60723
60906
  const challenge = challengeBySlug(slug);
@@ -60761,7 +60944,7 @@ var challengeQuickstartText = (participationState, launchNotice) => {
60761
60944
  `);
60762
60945
  };
60763
60946
  var optionalString = (name, description) => exports_Flag.string(name).pipe(exports_Flag.optional, exports_Flag.withDescription(description));
60764
- var challengeFlag = exports_Flag.string("challenge").pipe(exports_Flag.withDefault(defaultChallengeSlug), exports_Flag.withDescription("Challenge slug (default: black-box)"));
60947
+ var challengeFlag = exports_Flag.string("challenge").pipe(exports_Flag.withDefault(defaultChallengeSlug), exports_Flag.withDescription("Challenge slug (default: broken-agent)"));
60765
60948
  var sourceFlag = optionalString("source", "JavaScript challenge solution file");
60766
60949
  var inputFlag = optionalString("input", "JSON file, or - for stdin");
60767
60950
  var formatFlag = exports_Flag.choice("format", ["table", "json", "csv"]).pipe(exports_Flag.withDefault("table"), exports_Flag.withDescription("Notebook format"));
@@ -60782,24 +60965,24 @@ var challengeInitText = (result3) => {
60782
60965
  if (result3.challenge === "broken-agent") {
60783
60966
  if (result3.status === "exists") {
60784
60967
  return [
60785
- `${result3.path} already exists. Left it unchanged.`,
60968
+ `${result3.path} ya existe. No se modificó.`,
60786
60969
  "",
60787
- "Next: keep hardening your scheduler, then run the public tests",
60970
+ "Siguiente: continúa endureciendo el scheduler y ejecuta los tests públicos",
60788
60971
  ` cd ${result3.path} && npm test`,
60789
- ` chofex challenge test --challenge broken-agent --source ./${result3.path}/scheduler.js`
60972
+ " chofex challenge test --challenge broken-agent --source ./scheduler.js"
60790
60973
  ].join(`
60791
60974
  `);
60792
60975
  }
60793
60976
  return [
60794
- `Created ${result3.path}`,
60795
- "The previous agent says the scheduler is done. Everything passes.",
60796
- "Unfortunately, the agent was wrong.",
60977
+ `Se creó ${result3.path}`,
60978
+ "El agente anterior dice que el scheduler está terminado. Todo pasa.",
60979
+ "Pero todavía no es seguro para producción.",
60797
60980
  "",
60798
- "Start with the public contract and tests:",
60981
+ "Empieza con el contrato normativo y los tests públicos:",
60799
60982
  ` cd ${result3.path} && npm test`,
60800
60983
  "",
60801
- "Then repair scheduler.js and test it safely:",
60802
- ` chofex challenge test --challenge broken-agent --source ./${result3.path}/scheduler.js`
60984
+ "Luego repara scheduler.js y pruébalo sin consumir evaluaciones:",
60985
+ " chofex challenge test --challenge broken-agent --source ./scheduler.js"
60803
60986
  ].join(`
60804
60987
  `);
60805
60988
  }
@@ -60852,24 +61035,24 @@ var initCommand = exports_Command.make("init", { challenge: challengeFlag }, exp
60852
61035
  data
60853
61036
  })));
60854
61037
  yield* execute(options.output, operation, challengeInitText);
60855
- })).pipe(exports_Command.withDescription("Create a challenge starter without overwriting existing work."), exports_Command.withExamples([
61038
+ })).pipe(exports_Command.withDescription("Crea el starter de un challenge sin sobrescribir trabajo existente."), exports_Command.withExamples([
60856
61039
  {
60857
- command: "chofex challenge init",
60858
- description: "Prepare a safe JavaScript solution file"
61040
+ command: "chofex challenge init --challenge broken-agent",
61041
+ description: "Prepara el repositorio de Broken Agent"
60859
61042
  },
60860
61043
  {
60861
61044
  command: "chofex challenge init --challenge broken-agent",
60862
- description: "Prepare the Broken Agent starter repository"
61045
+ description: "Usa explícitamente el slug del challenge"
60863
61046
  }
60864
61047
  ]));
60865
61048
  var showCommand = exports_Command.make("show", { challenge: challengeFlag }, exports_Effect.fn("challengeShowCommand")(function* ({ challenge }) {
60866
61049
  const options = yield* root;
60867
61050
  const token = exports_Option.getOrUndefined(options.token);
60868
61051
  yield* execute(options.output, getChallengeAttempt({ apiUrl: options.apiUrl, token }, challenge), challengeShowText);
60869
- })).pipe(exports_Command.withDescription("Check your Black Box query budget, evaluation budget, score, and saved observations. Requires sign-in."), exports_Command.withExamples([
61052
+ })).pipe(exports_Command.withDescription("Consulta presupuesto, puntaje y progreso del challenge. Requiere iniciar sesión."), exports_Command.withExamples([
60870
61053
  {
60871
61054
  command: "chofex challenge show",
60872
- description: "Check your progress before spending limited attempts"
61055
+ description: "Revisa tu progreso antes de consumir intentos limitados"
60873
61056
  }
60874
61057
  ]));
60875
61058
  var queryCommand = exports_Command.make("query", {
@@ -60904,11 +61087,11 @@ var queryCommand = exports_Command.make("query", {
60904
61087
  yield* execute(options.output, operation, challengeQueryText);
60905
61088
  })).pipe(exports_Command.withDescription("Send one shipment to the undocumented oracle. A successful query consumes one limited request. Requires sign-in."), exports_Command.withExamples([
60906
61089
  {
60907
- command: "chofex challenge query --distance 10 --weight 3 --hour 14 --fragile false --express false",
61090
+ command: "chofex challenge query --challenge black-box --distance 10 --weight 3 --hour 14 --fragile false --express false",
60908
61091
  description: "Spend one oracle query"
60909
61092
  },
60910
61093
  {
60911
- command: "chofex challenge query --input shipment.json",
61094
+ command: "chofex challenge query --challenge black-box --input shipment.json",
60912
61095
  description: "Read the shipment fields from a JSON file"
60913
61096
  }
60914
61097
  ]));
@@ -60926,11 +61109,11 @@ var notebookCommand = exports_Command.make("notebook", { challenge: challengeFla
60926
61109
  });
60927
61110
  })).pipe(exports_Command.withDescription("Review every input and price you observed. Export table, JSON, or CSV for analysis. Requires sign-in."), exports_Command.withExamples([
60928
61111
  {
60929
- command: "chofex challenge notebook",
61112
+ command: "chofex challenge notebook --challenge black-box",
60930
61113
  description: "Read observations in a terminal table"
60931
61114
  },
60932
61115
  {
60933
- command: "chofex challenge notebook --format csv > observations.csv",
61116
+ command: "chofex challenge notebook --challenge black-box --format csv > observations.csv",
60934
61117
  description: "Save observations for a spreadsheet"
60935
61118
  }
60936
61119
  ]));
@@ -60944,8 +61127,8 @@ var testCommand = exports_Command.make("test", { challenge: challengeFlag, sourc
60944
61127
  yield* execute(options.output, operation, challengeTestText);
60945
61128
  })).pipe(exports_Command.withDescription("Run the challenge's public tests. Safe to repeat; official evaluations are not consumed. Requires sign-in."), exports_Command.withExamples([
60946
61129
  {
60947
- command: "chofex challenge test --source ./shipping.js",
60948
- description: "Test a JavaScript replacement against your notebook"
61130
+ command: "chofex challenge test --challenge broken-agent --source ./scheduler.js",
61131
+ description: "Ejecuta los tests públicos de Broken Agent"
60949
61132
  }
60950
61133
  ]));
60951
61134
  var evaluateCommand = exports_Command.make("evaluate", { challenge: challengeFlag, source: sourceFlag }, exports_Effect.fn("challengeEvaluateCommand")(function* ({ challenge, source }) {
@@ -60958,8 +61141,8 @@ var evaluateCommand = exports_Command.make("evaluate", { challenge: challengeFla
60958
61141
  yield* execute(options.output, operation, challengeEvaluateText);
60959
61142
  })).pipe(exports_Command.withDescription("Score a solution on hidden cases. This consumes one limited official evaluation. Requires sign-in."), exports_Command.withExamples([
60960
61143
  {
60961
- command: "chofex challenge evaluate --source ./shipping.js",
60962
- description: "Spend one official evaluation when your solution is ready"
61144
+ command: "chofex challenge evaluate --challenge broken-agent --source ./scheduler.js",
61145
+ description: "Consume una evaluación oficial cuando tu solución esté lista"
60963
61146
  }
60964
61147
  ]));
60965
61148
  var rankingCommand = exports_Command.make("ranking", { challenge: challengeFlag }, exports_Effect.fn("challengeRankingCommand")(function* ({ challenge }) {
@@ -60967,8 +61150,8 @@ var rankingCommand = exports_Command.make("ranking", { challenge: challengeFlag
60967
61150
  yield* execute(options.output, getChallengeRanking({ apiUrl: options.apiUrl }, challenge), challengeRankingText);
60968
61151
  })).pipe(exports_Command.withDescription("View the public leaderboard. No login required and no challenge budget consumed."), exports_Command.withExamples([
60969
61152
  {
60970
- command: "chofex challenge ranking",
60971
- description: "Compare official hidden-set scores"
61153
+ command: "chofex challenge ranking --challenge broken-agent",
61154
+ description: "Compara puntajes oficiales"
60972
61155
  }
60973
61156
  ]));
60974
61157
  var challengeCommand = exports_Command.make("challenge", {}, exports_Effect.fn("challengeQuickstartCommand")(function* () {
@@ -60987,7 +61170,7 @@ var challengeCommand = exports_Command.make("challenge", {}, exports_Effect.fn("
60987
61170
  workflow = rankingStep ? [rankingStep] : [];
60988
61171
  helpCommand = "chofex challenge ranking --help";
60989
61172
  story = [];
60990
- mission = "El Challenge 1 terminó. El ranking final sigue disponible.";
61173
+ mission = "El Challenge 2 terminó. El ranking final sigue disponible.";
60991
61174
  rules = [];
60992
61175
  } else if (participationState === "scheduled") {
60993
61176
  workflow = [];
@@ -61017,18 +61200,18 @@ var challengeCommand = exports_Command.make("challenge", {}, exports_Effect.fn("
61017
61200
  return;
61018
61201
  }
61019
61202
  yield* exports_Console.log(challengeQuickstartText(participationState, launchNotice));
61020
- })).pipe(exports_Command.withDescription("Play mini technical challenges. Start here: learn the Black Box workflow from first query to leaderboard. Run without a subcommand for the guided quickstart."), exports_Command.withExamples([
61203
+ })).pipe(exports_Command.withDescription("Compite en challenges técnicos. Ejecuta el comando sin subcomandos para abrir la guía del challenge actual."), exports_Command.withExamples([
61021
61204
  {
61022
61205
  command: "chofex challenge",
61023
- description: "Open the guided Black Box quickstart"
61206
+ description: "Abre la guía de Broken Agent"
61024
61207
  },
61025
61208
  {
61026
- command: "chofex challenge query --distance 10 --weight 3 --hour 14 --fragile false --express false",
61027
- description: "Make your first oracle query"
61209
+ command: "chofex challenge init --challenge broken-agent",
61210
+ description: "Crea el repositorio de Broken Agent"
61028
61211
  },
61029
61212
  {
61030
- command: "chofex challenge query --help",
61031
- description: "See flags and examples for the query step"
61213
+ command: "chofex challenge test --help",
61214
+ description: "Revisa cómo ejecutar los tests públicos"
61032
61215
  }
61033
61216
  ]), exports_Command.withSubcommands([
61034
61217
  listCommand,
@@ -61327,8 +61510,8 @@ var shirtSizePrompt = (participationMode) => {
61327
61510
  choices: ["xs", "s", "m", "l", "xl", "2xl", "3xl", "prefer_not_to_say"].map((value3) => ({ title: value3.toUpperCase(), value: value3 }))
61328
61511
  });
61329
61512
  };
61330
- var interactiveAcceptedDetails = (participationMode, pictures) => exports_Effect.gen(function* () {
61331
- let fullName = pictures.currentFullName;
61513
+ var interactiveAcceptedDetails = (participationMode, defaults2) => exports_Effect.gen(function* () {
61514
+ let fullName = defaults2.currentFullName;
61332
61515
  if (fullName) {
61333
61516
  const nameChoice = yield* exports_Prompt.run(exports_Prompt.select({
61334
61517
  message: `Is "${fullName}" your full name exactly as it appears on your ID document?`,
@@ -61343,10 +61526,10 @@ var interactiveAcceptedDetails = (participationMode, pictures) => exports_Effect
61343
61526
  if (!fullName) {
61344
61527
  fullName = yield* exports_Prompt.run(requiredText("Full name exactly as it appears on your ID document", acceptedDetailsInputFields.fullName));
61345
61528
  }
61346
- const displayName = yield* exports_Prompt.run(requiredText("Nombre impreso en tu carnet", acceptedDetailsInputFields.fullName, pictures.currentDisplayName ?? fullName));
61347
- const oneLiner = yield* exports_Prompt.run(requiredText("Presentación de una línea para tu carnet", badgeRegenerationInputFields.oneLiner, pictures.currentOneLiner));
61529
+ const name = yield* exports_Prompt.run(requiredText("Nombre impreso en tu carnet", acceptedDetailsInputFields.fullName, defaults2.currentName ?? fullName));
61530
+ const oneLiner = yield* exports_Prompt.run(requiredText("Presentación de una línea para tu carnet", badgeRegenerationInputFields.oneLiner, defaults2.currentOneLiner));
61348
61531
  const details = yield* exports_Prompt.run(exports_Prompt.all({
61349
- phone: optionalText2("Teléfono para WhatsApp (opcional)", acceptedDetailsInputFields.phone, pictures.currentPhone),
61532
+ phone: optionalText2("Teléfono para WhatsApp (opcional)", acceptedDetailsInputFields.phone, defaults2.currentPhone),
61350
61533
  dateOfBirth: dateOfBirthPrompt(),
61351
61534
  nationalIdNumber: requiredText("National ID or passport number", acceptedDetailsInputFields.nationalIdNumber),
61352
61535
  shirtSize: shirtSizePrompt(participationMode),
@@ -61359,20 +61542,20 @@ var interactiveAcceptedDetails = (participationMode, pictures) => exports_Effect
61359
61542
  })
61360
61543
  }));
61361
61544
  const pictureChoices = [];
61362
- if (pictures.clerkPictureUrl) {
61545
+ if (defaults2.clerkPictureUrl) {
61363
61546
  pictureChoices.push({
61364
- title: `Use my Clerk picture (${pictures.clerkPictureUrl})`,
61547
+ title: `Usar mi foto de Clerk (${defaults2.clerkPictureUrl})`,
61365
61548
  value: "clerk"
61366
61549
  });
61367
61550
  }
61368
- if (pictures.githubUrl) {
61551
+ if (defaults2.githubUrl) {
61369
61552
  pictureChoices.push({
61370
- title: `Use my GitHub picture (${pictures.githubUrl})`,
61553
+ title: `Usar mi foto de GitHub (${defaults2.githubUrl})`,
61371
61554
  value: "github"
61372
61555
  });
61373
61556
  }
61374
61557
  pictureChoices.push({
61375
- title: "Upload a different picture",
61558
+ title: "Subir una foto diferente",
61376
61559
  value: "upload"
61377
61560
  });
61378
61561
  const pictureSource = yield* exports_Prompt.run(exports_Prompt.select({
@@ -61381,7 +61564,7 @@ var interactiveAcceptedDetails = (participationMode, pictures) => exports_Effect
61381
61564
  }));
61382
61565
  return withoutEmptyStrings({
61383
61566
  fullName,
61384
- displayName,
61567
+ name,
61385
61568
  oneLiner,
61386
61569
  ...details,
61387
61570
  pictureSource
@@ -61400,7 +61583,7 @@ var inputOrInteractive = (path4, interactive) => {
61400
61583
  }));
61401
61584
  };
61402
61585
  var applicationInput = (path4, publicBaseUrl, defaults2 = {}) => inputOrInteractive(path4, collectApplicationFields(publicBaseUrl, defaults2).pipe(exports_Effect.map((input) => withoutEmptyStrings(input)))).pipe(exports_Effect.flatMap((input) => decode2(ApplicationInput, input, applicationInputFieldNames)), exports_Effect.flatMap((input) => validateSemantics(input, applicationSemanticRequirements(input))));
61403
- var acceptedDetailsInput = (path4, participationMode, pictures = {}) => inputOrInteractive(path4, interactiveAcceptedDetails(participationMode, pictures)).pipe(exports_Effect.flatMap((input) => decode2(AcceptedDetailsInput, input, acceptedDetailsInputFieldNames)), exports_Effect.flatMap((input) => validateSemantics(input, acceptedDetailsSemanticRequirements(input, participationMode))));
61586
+ var acceptedDetailsInput = (path4, participationMode, defaults2 = {}) => inputOrInteractive(path4, interactiveAcceptedDetails(participationMode, defaults2)).pipe(exports_Effect.flatMap((input) => decode2(AcceptedDetailsInput, input, acceptedDetailsInputFieldNames)), exports_Effect.flatMap((input) => validateSemantics(input, acceptedDetailsSemanticRequirements(input, participationMode))));
61404
61587
  var picturePathInput = (suppliedPath) => {
61405
61588
  if (suppliedPath)
61406
61589
  return exports_Effect.succeed(suppliedPath);
@@ -63494,7 +63677,7 @@ var confirmCommand = exports_Command.make("confirm", {
63494
63677
  clerkPictureUrl: currentUser.data.clerkPictureUrl,
63495
63678
  githubUrl: current.data.registration.githubUrl,
63496
63679
  currentPhone: current.data.registration.phone,
63497
- currentDisplayName: currentBadge.data.profile?.fullName,
63680
+ currentName: currentBadge.data.profile?.fullName,
63498
63681
  currentOneLiner: currentBadge.data.profile?.oneLiner ?? current.data.registration.role,
63499
63682
  currentFullName: current.data.registration.fullName || joinFullName(current.data.registration.firstName, current.data.registration.lastName)
63500
63683
  });
@@ -63633,7 +63816,7 @@ var applicationTemplate = {
63633
63816
  };
63634
63817
  var acceptanceTemplate = {
63635
63818
  fullName: "Ada Lovelace",
63636
- displayName: "Ada L.",
63819
+ name: "Ada L.",
63637
63820
  oneLiner: "Computing pioneer",
63638
63821
  phone: "+44 20 0000 0000",
63639
63822
  dateOfBirth: "1990-01-01",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chofex-cli",
3
- "version": "0.1.186",
3
+ "version": "0.1.187",
4
4
  "description": "Command-line client for Hack the Andes",
5
5
  "type": "module",
6
6
  "bin": {