SLOPSHOPPER

cc-idle

An idle game that runs beside Claude Code, fed only by the work Claude does for you

newpaneguardcommandtoaststatus
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · cc-idle
│ ┃ cc-idle ✕ › fix the failing auth test and add an audit log call │ ┃ ▶ Claude finished — your turn │ ┃ GEN-1 10 FLOPS · 12 eng · 2 data · 1 rep · 0 ⏺ Read(src/auth.ts) │ ┃ ★ ⎿ Read 6 lines │ ┃ ⏺ Update(src/auth.ts) │ ┃ WELCOME TO CC-IDLE ⎿ Added 2 lines, removed 1 line │ ┃ You run an AI lab. Claude does the work; you ⏺ Bash(bun test) │ ┃ spend what it earns. ⎿ 3 pass, 1 fail │ ┃ Output tokens → FLOPS · Edit/Write/Bash → │ ┃ eng · Read/Search → data ● Done. refresh now rejects expired claims and logs an audit event. │ ┃ A finished turn pays a bonus. A subagent is │ ┃ a training run. A failed tool is an ✻ Worked for 42s · done 4:20 PM │ ┃ incident. │ ┃ g r d buy GPUs, racks and datacenters: more › /idle │ ┃ FLOPS per token. │ ┃ e runs an experiment and a subagent runs │ ┃ training: both fill the model bar. h hires │ ┃ researchers to multiply it. │ ┃ s ships the generation for ★ Breakthroughs │ ┃ (v), which outlast the reset. │ ┃ Esc hands the keyboard back. /idle takes it │ ┃ again. /idle close hides the pane. │ ┃ i: got it, start playing │ ┃ Type /idle to give the pane the keyboard. │ ┃ │ ┃ ⛏ region "app" founded ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts ⚠ cc-idle: cc-idle 10 FLOPS · Gen-1 · ↯1

Draws

Pane · cc-idle
▶ Claude finished — your turn GEN-1 10 FLOPS · 12 eng · 2 data · 1 rep · 0 ★ WELCOME TO CC-IDLE You run an AI lab. Claude does the work; you spend what it earns. Output tokens → FLOPS · Edit/Write/Bash → eng · Read/Search → data A finished turn pays a bonus. A subagent is a training run. A failed tool is an incident. g r d buy GPUs, racks and datacenters: more FLOPS per token. e runs an experiment and a subagent runs training: both fill the model bar. h hires researchers to multiply it. s ships the generation for ★ Breakthroughs (v), which outlast the reset. Esc hands the keyboard back. /idle takes it again. /idle close hides the pane. i: got it, start playing Type /idle to give the pane the keyboard. ⛏ region "app" founded ↯ incident in "app": GPU thermal event in hall B — [a] to acknowledge
README

cc-idle (Claude Code mod)

CC Idle as a Claude Code mod: the game runs in a pane beside the transcript, fed by Claude Code's own events. No tmux, no daemon, no hook shims.

Requires Claude Code v2.1.287 or later.

Install

/plugin marketplace add RichardAtCT/cc-idle
/plugin install cc-idle@cc-idle

Or try it from a clone for one session: claude --plugin-dir ./plugins/cc-idle.

To pick up new commits from main inside Claude Code, refresh the marketplace, then load the new version into the running session. No restart is needed.

/plugin marketplace update cc-idle
/reload-plugins

If the new version does not appear, type /plugin, open cc-idle under the installed plugins, choose update, then run /reload-plugins again. From a shell, the same update is:

claude plugin marketplace update cc-idle && claude plugin update cc-idle@cc-idle

plugin.json sets no version on purpose. Claude Code then uses the commit SHA as the version, so every merge to main is an update. claude plugin validate warns about the missing version; ignore that warning.

Play

  • In a terminal at least 144 columns wide, the pane opens beside the transcript by itself. Anywhere else, type /idle. It works mid-turn, so you can play while Claude works. Until you have played once, a toast tells you so.
  • The first time, the pane shows a welcome that explains the game. After that, a yellow → line under the header names the next useful move when there is one.
  • /idle also gives the pane the keyboard. Esc hands it back to the prompt. /idle close closes the pane.
  • When Claude finishes a turn, asks a question or needs permission, a banner at the top of the pane says so.
  • Your Compute and generation also show on the status line, even with the pane closed.
KeyAction
g / r / dBuy a GPU / rack / datacenter in the focused region
aAcknowledge the region's incident (the post-mortem pays engineering)
nNext region
hHire a researcher
eRun an experiment
sShip the generation (asks y / n first)
vBreakthrough tree (1–6 buy, v back)
cTalk to the board (Enter on an empty line goes back)
iHow to play (i back)

The original TUI's tab and P became n and s, because a mod's hotkeys must be a single lowercase letter or digit, and Tab and the arrow keys stay Claude Code's.

The board

A board member of your lab lives in the pane. It is Haiku, run through your own Claude Code session, so each line it says is one small Haiku call on your account.

The board explains an incident unasked, then answers a rules question and a cheeky one

  • Press c to open the board, type a short line (80 characters at most) and press Enter. It answers in one line. The text field takes every key, so Enter on an empty line goes back to the game. Esc hands the keyboard to the prompt, as on every screen.
  • It knows the rules, so it doubles as help: ask "what does diminishing returns mean?" and it answers from the game's real balance numbers.
  • The first time you meet a mechanic (an incident, diminishing returns, a second region, a shippable model, Breakthroughs to spend), it explains it once, unasked. It never repeats one.
  • It also reacts by itself to big moments: a region founded, a generation shipped, a breakthrough, an incident. It does so at most once a minute, and only while the pane is in view. Unasked lines share that limit. Its last word shows under the hint on the main screen.
  • The chat stays in this session. It is not part of the shared save.

How it works

Claude Code eventBecomesEconomy
turn.start (main loop)UserPromptSubmitthe region is hot; the turn's accrual starts
turn.step (every model request, subagents too)TokenUsageoutput tokens → Compute, live
tool.call succeededPostToolUseEdit/Write/Bash → engineering, Read/Search/Fetch → research data
tool.call erroredPostToolUse (failed)an incident
turn.complete (subagent)SubagentStopa training run
turn.complete (main, answered)Stopmilestone shipped: completion bonus and reputation
session.endSessionEndthe session leaves its region

The mod builds the same v1 envelopes the shell hooks wrote, so the engine in packages/game, its balance constants and the replay/backtest tooling are unchanged.

One economy for all your sessions. Every Claude Code session running the mod shares one save in $.store. Each session applies events locally at once, then about a second later re-reads the save, replays its queued events on top and writes it back. Every 5 seconds it picks up the other sessions' writes. Only a write that lands between another session's read and its write is lost.

What it touches. claude plugin validate plugins/cc-idle lists every call the mod makes: $.store, $.state, $.ui, $.clock, $.model.complete, $.command.register, $.session.id and $.session.cwd. Its only model calls are the board's Haiku calls. It makes no filesystem, network or process calls. It never denies or rewrites a tool call, prompt or turn: every hook passes its event on unchanged.

Developing

hooks/register.js is generated. Its sources are in packages/mod/src, bundled with the pure game engine and zod by pnpm --filter @ccidle/mod build. A mod loads no packages and has no Node, so everything it needs travels in that one file.

pnpm --filter @ccidle/mod build      # regenerate hooks/register.js
pnpm --filter @ccidle/mod test       # sync, telemetry and view unit tests (vitest)
pnpm --filter @ccidle/mod typecheck  # against the mods API types in packages/mod/types
claude plugin validate plugins/cc-idle
claude plugin test plugins/cc-idle   # hooks and pane tests in Claude Code's own test engine

packages/mod/types/claude-code.d.ts is the mods API declaration file that Claude Code 2.1.287 writes. When Claude Code updates, copy in the new one; don't edit it by hand.

Source 2 files
hooks/register.js 5714 lines
1// GENERATED by packages/mod/build.mjs from packages/mod/src and packages/game. Do not edit by hand.
2var __defProp = Object.defineProperty;
3var __export = (target, all) => {
4  for (var name in all)
5    __defProp(target, name, { get: all[name], enumerable: true });
6};
7
8// src/register.tsx
9import { atom, read, update } from "claude-code";
10
11// ../game/src/balance.ts
12var INFRA_TIERS = [
13  { id: "gpu", name: "GPU", baseCost: 500, costGrowth: 1.15, multiplier: 0.02, requiresPrevious: 0, glyph: "\u25AA" },
14  { id: "rack", name: "Rack", baseCost: 12e3, costGrowth: 1.18, multiplier: 0.3, requiresPrevious: 8, glyph: "\u25AE" },
15  { id: "datacenter", name: "Datacenter", baseCost: 25e4, costGrowth: 1.22, multiplier: 2, requiresPrevious: 4, glyph: "\u2B22" }
16];
17var BALANCE = {
18  compute: {
19    /** Compute (FLOPS) granted per weighted output token. */
20    perOutputToken: 1,
21    /**
22     * Diminishing returns (PRD §5): per region, the first
23     * `fullRateTokensPerWindow` output tokens in a rolling `windowMs` window
24     * convert at full rate; beyond that the marginal rate is
25     * 1 / (1 + log2(windowTokens / fullRateTokensPerWindow)).
26     */
27    fullRateTokensPerWindow: 4e4,
28    windowMs: 36e5,
29    /** Retroactive completion multiplier on a turn's accrual when it ends in Stop. */
30    turnCompletionBonus: 0.25,
31    /** Small flat Compute granted to every live region on any Stop (PRD §4). */
32    stopAllRegionBonus: 10
33  },
34  engineering: {
35    /** Engineering per successful engineering-class tool call. */
36    perToolCall: 2,
37    /** Engineering granted for acknowledging an incident ("post-mortem"). */
38    postMortem: 3
39  },
40  research: {
41    /** Research Data per successful research-class tool call. */
42    perToolCall: 1
43  },
44  reputation: {
45    /** Reputation per clean Stop (completed turn). */
46    perStop: 1,
47    /** Open question #1 resolved per the PRD lean: a mirror, not a treadmill. */
48    decayPerDay: 0
49  },
50  /** Tool classification for resource accrual (PRD §3). */
51  tools: {
52    engineering: ["Edit", "Write", "MultiEdit", "NotebookEdit", "Bash"],
53    research: ["Read", "WebSearch", "WebFetch", "Grep", "Glob"]
54  },
55  lab: {
56    /** First researcher's cost in Engineering; geometric growth per hire. */
57    hireBaseCost: 60,
58    hireCostGrowth: 1.35,
59    /** Hire cap = 1 + floor(reputation / reputationPerHireSlot) — the §3 soft gate. */
60    reputationPerHireSlot: 5,
61    /** Each researcher adds this to the lab progress multiplier. */
62    progressPerResearcher: 0.25,
63    /** Manual experiment: costs and Model Progress payout. */
64    experimentDataCost: 25,
65    experimentEngineeringCost: 10,
66    experimentProgress: 10,
67    /** Training run (fires on SubagentStop): Research Data consumed per run. */
68    trainingDataCost: 15,
69    /** Progress payout = base + perMinute × clamped subagent minutes. */
70    trainingBaseProgress: 5,
71    trainingProgressPerMinute: 4,
72    trainingMaxMinutes: 30,
73    /** Assumed duration when the SubagentStop payload carries none. */
74    trainingDefaultMinutes: 2,
75    /** Compute payout per training-run minute (scaled by the region multiplier). */
76    trainingComputePerMinute: 100,
77    /**
78     * With no Research Data banked a run still pays this fraction — training
79     * never blocks (PRD §1.4), data just makes it much better.
80     */
81    trainingMinEfficiency: 0.25
82  },
83  generations: {
84    /** Model Progress required to ship Gen-1; geometric growth per generation. */
85    baseProgress: 100,
86    progressGrowth: 2.5,
87    /** Breakthroughs banked per shipped generation, plus overshoot bonus below. */
88    breakthroughsPerShip: 3,
89    /** +1 Breakthrough per whole extra multiple of the threshold, capped here. */
90    overshootBonusCap: 3
91  },
92  incidents: {
93    /** Frequency caps (PRD §6): alert fatigue guard. */
94    maxActivePerRegion: 3,
95    minIntervalMs: 6e4,
96    /** Multiplicative regional debuff per active incident (mild by design). */
97    debuffPerIncident: 0.08,
98    /** Floor so a noisy region never drops below half rate. */
99    debuffFloor: 0.5
100  },
101  /** Bounded narration log kept in game state for the TUI feed. */
102  logLimit: 100
103};
104function tierCost(tier, owned) {
105  return Math.ceil(tier.baseCost * Math.pow(tier.costGrowth, owned));
106}
107function hireCost(researchers) {
108  return Math.ceil(BALANCE.lab.hireBaseCost * Math.pow(BALANCE.lab.hireCostGrowth, researchers));
109}
110function generationThreshold(generation) {
111  return Math.ceil(
112    BALANCE.generations.baseProgress * Math.pow(BALANCE.generations.progressGrowth, generation - 1)
113  );
114}
115function hireCap(reputation) {
116  return 1 + Math.floor(reputation / BALANCE.lab.reputationPerHireSlot);
117}
118
119// ../game/src/content.ts
120var INCIDENT_FLAVOURS = [
121  "GPU thermal event in hall B",
122  "eval regression on the nightly suite",
123  "on-call page: gradient overflow",
124  "checkpoint corruption detected",
125  "dataloader stall in shard 7",
126  "spot capacity reclaimed mid-epoch",
127  "network fabric flapping",
128  "cooling loop pressure warning"
129];
130var BREAKTHROUGH_NODES = [
131  {
132    id: "quantization",
133    name: "Quantization",
134    description: "+20% Compute conversion per level",
135    maxLevel: 5,
136    cost: (level) => 1 + level
137  },
138  {
139    id: "synthetic-data",
140    name: "Synthetic Data",
141    description: "+25% Research Data per level",
142    maxLevel: 5,
143    cost: (level) => 1 + level
144  },
145  {
146    id: "scaling-laws",
147    name: "Scaling Laws",
148    description: "+25% Model Progress from training & experiments per level",
149    maxLevel: 5,
150    cost: (level) => 1 + level
151  },
152  {
153    id: "self-healing",
154    name: "Self-Healing Infra",
155    description: "incidents auto-acknowledge (post-mortem included)",
156    maxLevel: 1,
157    cost: () => 2
158  },
159  {
160    id: "procurement",
161    name: "Procurement Bots",
162    description: "auto-buy GPUs whenever a region can afford them",
163    maxLevel: 1,
164    cost: () => 2
165  },
166  {
167    id: "blueprints",
168    name: "Reference Designs",
169    description: "each new generation starts with 4 GPUs per region per level",
170    maxLevel: 3,
171    cost: (level) => 2 + level
172  }
173];
174function breakthroughNode(id) {
175  return BREAKTHROUGH_NODES.find((node) => node.id === id);
176}
177
178// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
179var external_exports = {};
180__export(external_exports, {
181  BRAND: () => BRAND,
182  DIRTY: () => DIRTY,
183  EMPTY_PATH: () => EMPTY_PATH,
184  INVALID: () => INVALID,
185  NEVER: () => NEVER,
186  OK: () => OK,
187  ParseStatus: () => ParseStatus,
188  Schema: () => ZodType,
189  ZodAny: () => ZodAny,
190  ZodArray: () => ZodArray,
191  ZodBigInt: () => ZodBigInt,
192  ZodBoolean: () => ZodBoolean,
193  ZodBranded: () => ZodBranded,
194  ZodCatch: () => ZodCatch,
195  ZodDate: () => ZodDate,
196  ZodDefault: () => ZodDefault,
197  ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
198  ZodEffects: () => ZodEffects,
199  ZodEnum: () => ZodEnum,
200  ZodError: () => ZodError,
201  ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
202  ZodFunction: () => ZodFunction,
203  ZodIntersection: () => ZodIntersection,
204  ZodIssueCode: () => ZodIssueCode,
205  ZodLazy: () => ZodLazy,
206  ZodLiteral: () => ZodLiteral,
207  ZodMap: () => ZodMap,
208  ZodNaN: () => ZodNaN,
209  ZodNativeEnum: () => ZodNativeEnum,
210  ZodNever: () => ZodNever,
211  ZodNull: () => ZodNull,
212  ZodNullable: () => ZodNullable,
213  ZodNumber: () => ZodNumber,
214  ZodObject: () => ZodObject,
215  ZodOptional: () => ZodOptional,
216  ZodParsedType: () => ZodParsedType,
217  ZodPipeline: () => ZodPipeline,
218  ZodPromise: () => ZodPromise,
219  ZodReadonly: () => ZodReadonly,
220  ZodRecord: () => ZodRecord,
221  ZodSchema: () => ZodType,
222  ZodSet: () => ZodSet,
223  ZodString: () => ZodString,
224  ZodSymbol: () => ZodSymbol,
225  ZodTransformer: () => ZodEffects,
226  ZodTuple: () => ZodTuple,
227  ZodType: () => ZodType,
228  ZodUndefined: () => ZodUndefined,
229  ZodUnion: () => ZodUnion,
230  ZodUnknown: () => ZodUnknown,
231  ZodVoid: () => ZodVoid,
232  addIssueToContext: () => addIssueToContext,
233  any: () => anyType,
234  array: () => arrayType,
235  bigint: () => bigIntType,
236  boolean: () => booleanType,
237  coerce: () => coerce,
238  custom: () => custom,
239  date: () => dateType,
240  datetimeRegex: () => datetimeRegex,
241  defaultErrorMap: () => en_default,
242  discriminatedUnion: () => discriminatedUnionType,
243  effect: () => effectsType,
244  enum: () => enumType,
245  function: () => functionType,
246  getErrorMap: () => getErrorMap,
247  getParsedType: () => getParsedType,
248  instanceof: () => instanceOfType,
249  intersection: () => intersectionType,
250  isAborted: () => isAborted,
251  isAsync: () => isAsync,
252  isDirty: () => isDirty,
253  isValid: () => isValid,
254  late: () => late,
255  lazy: () => lazyType,
256  literal: () => literalType,
257  makeIssue: () => makeIssue,
258  map: () => mapType,
259  nan: () => nanType,
260  nativeEnum: () => nativeEnumType,
261  never: () => neverType,
262  null: () => nullType,
263  nullable: () => nullableType,
264  number: () => numberType,
265  object: () => objectType,
266  objectUtil: () => objectUtil,
267  oboolean: () => oboolean,
268  onumber: () => onumber,
269  optional: () => optionalType,
270  ostring: () => ostring,
271  pipeline: () => pipelineType,
272  preprocess: () => preprocessType,
273  promise: () => promiseType,
274  quotelessJson: () => quotelessJson,
275  record: () => recordType,
276  set: () => setType,
277  setErrorMap: () => setErrorMap,
278  strictObject: () => strictObjectType,
279  string: () => stringType,
280  symbol: () => symbolType,
281  transformer: () => effectsType,
282  tuple: () => tupleType,
283  undefined: () => undefinedType,
284  union: () => unionType,
285  unknown: () => unknownType,
286  util: () => util,
287  void: () => voidType
288});
289
290// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js
291var util;
292(function(util2) {
293  util2.assertEqual = (_) => {
294  };
295  function assertIs(_arg) {
296  }
297  util2.assertIs = assertIs;
298  function assertNever(_x) {
299    throw new Error();
300  }
301  util2.assertNever = assertNever;
302  util2.arrayToEnum = (items) => {
303    const obj = {};
304    for (const item of items) {
305      obj[item] = item;
306    }
307    return obj;
308  };
309  util2.getValidEnumValues = (obj) => {
310    const validKeys = util2.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== "number");
311    const filtered = {};
312    for (const k of validKeys) {
313      filtered[k] = obj[k];
314    }
315    return util2.objectValues(filtered);
316  };
317  util2.objectValues = (obj) => {
318    return util2.objectKeys(obj).map(function(e) {
319      return obj[e];
320    });
321  };
322  util2.objectKeys = typeof Object.keys === "function" ? (obj) => Object.keys(obj) : (object) => {
323    const keys = [];
324    for (const key in object) {
325      if (Object.prototype.hasOwnProperty.call(object, key)) {
326        keys.push(key);
327      }
328    }
329    return keys;
330  };
331  util2.find = (arr, checker) => {
332    for (const item of arr) {
333      if (checker(item))
334        return item;
335    }
336    return void 0;
337  };
338  util2.isInteger = typeof Number.isInteger === "function" ? (val) => Number.isInteger(val) : (val) => typeof val === "number" && Number.isFinite(val) && Math.floor(val) === val;
339  function joinValues(array, separator = " | ") {
340    return array.map((val) => typeof val === "string" ? `'${val}'` : val).join(separator);
341  }
342  util2.joinValues = joinValues;
343  util2.jsonStringifyReplacer = (_, value) => {
344    if (typeof value === "bigint") {
345      return value.toString();
346    }
347    return value;
348  };
349})(util || (util = {}));
350var objectUtil;
351(function(objectUtil2) {
352  objectUtil2.mergeShapes = (first, second) => {
353    return {
354      ...first,
355      ...second
356      // second overwrites first
357    };
358  };
359})(objectUtil || (objectUtil = {}));
360var ZodParsedType = util.arrayToEnum([
361  "string",
362  "nan",
363  "number",
364  "integer",
365  "float",
366  "boolean",
367  "date",
368  "bigint",
369  "symbol",
370  "function",
371  "undefined",
372  "null",
373  "array",
374  "object",
375  "unknown",
376  "promise",
377  "void",
378  "never",
379  "map",
380  "set"
381]);
382var getParsedType = (data) => {
383  const t = typeof data;
384  switch (t) {
385    case "undefined":
386      return ZodParsedType.undefined;
387    case "string":
388      return ZodParsedType.string;
389    case "number":
390      return Number.isNaN(data) ? ZodParsedType.nan : ZodParsedType.number;
391    case "boolean":
392      return ZodParsedType.boolean;
393    case "function":
394      return ZodParsedType.function;
395    case "bigint":
396      return ZodParsedType.bigint;
397    case "symbol":
398      return ZodParsedType.symbol;
399    case "object":
400      if (Array.isArray(data)) {
401        return ZodParsedType.array;
402      }
403      if (data === null) {
404        return ZodParsedType.null;
405      }
406      if (data.then && typeof data.then === "function" && data.catch && typeof data.catch === "function") {
407        return ZodParsedType.promise;
408      }
409      if (typeof Map !== "undefined" && data instanceof Map) {
410        return ZodParsedType.map;
411      }
412      if (typeof Set !== "undefined" && data instanceof Set) {
413        return ZodParsedType.set;
414      }
415      if (typeof Date !== "undefined" && data instanceof Date) {
416        return ZodParsedType.date;
417      }
418      return ZodParsedType.object;
419    default:
420      return ZodParsedType.unknown;
421  }
422};
423
424// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js
425var ZodIssueCode = util.arrayToEnum([
426  "invalid_type",
427  "invalid_literal",
428  "custom",
429  "invalid_union",
430  "invalid_union_discriminator",
431  "invalid_enum_value",
432  "unrecognized_keys",
433  "invalid_arguments",
434  "invalid_return_type",
435  "invalid_date",
436  "invalid_string",
437  "too_small",
438  "too_big",
439  "invalid_intersection_types",
440  "not_multiple_of",
441  "not_finite"
442]);
443var quotelessJson = (obj) => {
444  const json = JSON.stringify(obj, null, 2);
445  return json.replace(/"([^"]+)":/g, "$1:");
446};
447var ZodError = class _ZodError extends Error {
448  get errors() {
449    return this.issues;
450  }
451  constructor(issues) {
452    super();
453    this.issues = [];
454    this.addIssue = (sub) => {
455      this.issues = [...this.issues, sub];
456    };
457    this.addIssues = (subs = []) => {
458      this.issues = [...this.issues, ...subs];
459    };
460    const actualProto = new.target.prototype;
461    if (Object.setPrototypeOf) {
462      Object.setPrototypeOf(this, actualProto);
463    } else {
464      this.__proto__ = actualProto;
465    }
466    this.name = "ZodError";
467    this.issues = issues;
468  }
469  format(_mapper) {
470    const mapper = _mapper || function(issue) {
471      return issue.message;
472    };
473    const fieldErrors = { _errors: [] };
474    const processError = (error) => {
475      for (const issue of error.issues) {
476        if (issue.code === "invalid_union") {
477          issue.unionErrors.map(processError);
478        } else if (issue.code === "invalid_return_type") {
479          processError(issue.returnTypeError);
480        } else if (issue.code === "invalid_arguments") {
481          processError(issue.argumentsError);
482        } else if (issue.path.length === 0) {
483          fieldErrors._errors.push(mapper(issue));
484        } else {
485          let curr = fieldErrors;
486          let i = 0;
487          while (i < issue.path.length) {
488            const el = issue.path[i];
489            const terminal = i === issue.path.length - 1;
490            if (!terminal) {
491              curr[el] = curr[el] || { _errors: [] };
492            } else {
493              curr[el] = curr[el] || { _errors: [] };
494              curr[el]._errors.push(mapper(issue));
495            }
496            curr = curr[el];
497            i++;
498          }
499        }
500      }
501    };
502    processError(this);
503    return fieldErrors;
504  }
505  static assert(value) {
506    if (!(value instanceof _ZodError)) {
507      throw new Error(`Not a ZodError: ${value}`);
508    }
509  }
510  toString() {
511    return this.message;
512  }
513  get message() {
514    return JSON.stringify(this.issues, util.jsonStringifyReplacer, 2);
515  }
516  get isEmpty() {
517    return this.issues.length === 0;
518  }
519  flatten(mapper = (issue) => issue.message) {
520    const fieldErrors = {};
521    const formErrors = [];
522    for (const sub of this.issues) {
523      if (sub.path.length > 0) {
524        const firstEl = sub.path[0];
525        fieldErrors[firstEl] = fieldErrors[firstEl] || [];
526        fieldErrors[firstEl].push(mapper(sub));
527      } else {
528        formErrors.push(mapper(sub));
529      }
530    }
531    return { formErrors, fieldErrors };
532  }
533  get formErrors() {
534    return this.flatten();
535  }
536};
537ZodError.create = (issues) => {
538  const error = new ZodError(issues);
539  return error;
540};
541
542// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js
543var errorMap = (issue, _ctx) => {
544  let message;
545  switch (issue.code) {
546    case ZodIssueCode.invalid_type:
547      if (issue.received === ZodParsedType.undefined) {
548        message = "Required";
549      } else {
550        message = `Expected ${issue.expected}, received ${issue.received}`;
551      }
552      break;
553    case ZodIssueCode.invalid_literal:
554      message = `Invalid literal value, expected ${JSON.stringify(issue.expected, util.jsonStringifyReplacer)}`;
555      break;
556    case ZodIssueCode.unrecognized_keys:
557      message = `Unrecognized key(s) in object: ${util.joinValues(issue.keys, ", ")}`;
558      break;
559    case ZodIssueCode.invalid_union:
560      message = `Invalid input`;
561      break;
562    case ZodIssueCode.invalid_union_discriminator:
563      message = `Invalid discriminator value. Expected ${util.joinValues(issue.options)}`;
564      break;
565    case ZodIssueCode.invalid_enum_value:
566      message = `Invalid enum value. Expected ${util.joinValues(issue.options)}, received '${issue.received}'`;
567      break;
568    case ZodIssueCode.invalid_arguments:
569      message = `Invalid function arguments`;
570      break;
571    case ZodIssueCode.invalid_return_type:
572      message = `Invalid function return type`;
573      break;
574    case ZodIssueCode.invalid_date:
575      message = `Invalid date`;
576      break;
577    case ZodIssueCode.invalid_string:
578      if (typeof issue.validation === "object") {
579        if ("includes" in issue.validation) {
580          message = `Invalid input: must include "${issue.validation.includes}"`;
581          if (typeof issue.validation.position === "number") {
582            message = `${message} at one or more positions greater than or equal to ${issue.validation.position}`;
583          }
584        } else if ("startsWith" in issue.validation) {
585          message = `Invalid input: must start with "${issue.validation.startsWith}"`;
586        } else if ("endsWith" in issue.validation) {
587          message = `Invalid input: must end with "${issue.validation.endsWith}"`;
588        } else {
589          util.assertNever(issue.validation);
590        }
591      } else if (issue.validation !== "regex") {
592        message = `Invalid ${issue.validation}`;
593      } else {
594        message = "Invalid";
595      }
596      break;
597    case ZodIssueCode.too_small:
598      if (issue.type === "array")
599        message = `Array must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `more than`} ${issue.minimum} element(s)`;
600      else if (issue.type === "string")
601        message = `String must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `over`} ${issue.minimum} character(s)`;
602      else if (issue.type === "number")
603        message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
604      else if (issue.type === "bigint")
605        message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
606      else if (issue.type === "date")
607        message = `Date must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${new Date(Number(issue.minimum))}`;
608      else
609        message = "Invalid input";
610      break;
611    case ZodIssueCode.too_big:
612      if (issue.type === "array")
613        message = `Array must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than`} ${issue.maximum} element(s)`;
614      else if (issue.type === "string")
615        message = `String must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `under`} ${issue.maximum} character(s)`;
616      else if (issue.type === "number")
617        message = `Number must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`;
618      else if (issue.type === "bigint")
619        message = `BigInt must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`;
620      else if (issue.type === "date")
621        message = `Date must be ${issue.exact ? `exactly` : issue.inclusive ? `smaller than or equal to` : `smaller than`} ${new Date(Number(issue.maximum))}`;
622      else
623        message = "Invalid input";
624      break;
625    case ZodIssueCode.custom:
626      message = `Invalid input`;
627      break;
628    case ZodIssueCode.invalid_intersection_types:
629      message = `Intersection results could not be merged`;
630      break;
631    case ZodIssueCode.not_multiple_of:
632      message = `Number must be a multiple of ${issue.multipleOf}`;
633      break;
634    case ZodIssueCode.not_finite:
635      message = "Number must be finite";
636      break;
637    default:
638      message = _ctx.defaultError;
639      util.assertNever(issue);
640  }
641  return { message };
642};
643var en_default = errorMap;
644
645// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js
646var overrideErrorMap = en_default;
647function setErrorMap(map) {
648  overrideErrorMap = map;
649}
650function getErrorMap() {
651  return overrideErrorMap;
652}
653
654// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
655var makeIssue = (params) => {
656  const { data, path, errorMaps, issueData } = params;
657  const fullPath = [...path, ...issueData.path || []];
658  const fullIssue = {
659    ...issueData,
660    path: fullPath
661  };
662  if (issueData.message !== void 0) {
663    return {
664      ...issueData,
665      path: fullPath,
666      message: issueData.message
667    };
668  }
669  let errorMessage = "";
670  const maps = errorMaps.filter((m) => !!m).slice().reverse();
671  for (const map of maps) {
672    errorMessage = map(fullIssue, { data, defaultError: errorMessage }).message;
673  }
674  return {
675    ...issueData,
676    path: fullPath,
677    message: errorMessage
678  };
679};
680var EMPTY_PATH = [];
681function addIssueToContext(ctx, issueData) {
682  const overrideMap = getErrorMap();
683  const issue = makeIssue({
684    issueData,
685    data: ctx.data,
686    path: ctx.path,
687    errorMaps: [
688      ctx.common.contextualErrorMap,
689      // contextual error map is first priority
690      ctx.schemaErrorMap,
691      // then schema-bound map if available
692      overrideMap,
693      // then global override map
694      overrideMap === en_default ? void 0 : en_default
695      // then global default map
696    ].filter((x) => !!x)
697  });
698  ctx.common.issues.push(issue);
699}
700var ParseStatus = class _ParseStatus {
701  constructor() {
702    this.value = "valid";
703  }
704  dirty() {
705    if (this.value === "valid")
706      this.value = "dirty";
707  }
708  abort() {
709    if (this.value !== "aborted")
710      this.value = "aborted";
711  }
712  static mergeArray(status, results) {
713    const arrayValue = [];
714    for (const s of results) {
715      if (s.status === "aborted")
716        return INVALID;
717      if (s.status === "dirty")
718        status.dirty();
719      arrayValue.push(s.value);
720    }
721    return { status: status.value, value: arrayValue };
722  }
723  static async mergeObjectAsync(status, pairs) {
724    const syncPairs = [];
725    for (const pair of pairs) {
726      const key = await pair.key;
727      const value = await pair.value;
728      syncPairs.push({
729        key,
730        value
731      });
732    }
733    return _ParseStatus.mergeObjectSync(status, syncPairs);
734  }
735  static mergeObjectSync(status, pairs) {
736    const finalObject = {};
737    for (const pair of pairs) {
738      const { key, value } = pair;
739      if (key.status === "aborted")
740        return INVALID;
741      if (value.status === "aborted")
742        return INVALID;
743      if (key.status === "dirty")
744        status.dirty();
745      if (value.status === "dirty")
746        status.dirty();
747      if (key.value !== "__proto__" && (typeof value.value !== "undefined" || pair.alwaysSet)) {
748        finalObject[key.value] = value.value;
749      }
750    }
751    return { status: status.value, value: finalObject };
752  }
753};
754var INVALID = Object.freeze({
755  status: "aborted"
756});
757var DIRTY = (value) => ({ status: "dirty", value });
758var OK = (value) => ({ status: "valid", value });
759var isAborted = (x) => x.status === "aborted";
760var isDirty = (x) => x.status === "dirty";
761var isValid = (x) => x.status === "valid";
762var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
763
764// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
765var errorUtil;
766(function(errorUtil2) {
767  errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
768  errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
769})(errorUtil || (errorUtil = {}));
770
771// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
772var ParseInputLazyPath = class {
773  constructor(parent, value, path, key) {
774    this._cachedPath = [];
775    this.parent = parent;
776    this.data = value;
777    this._path = path;
778    this._key = key;
779  }
780  get path() {
781    if (!this._cachedPath.length) {
782      if (Array.isArray(this._key)) {
783        this._cachedPath.push(...this._path, ...this._key);
784      } else {
785        this._cachedPath.push(...this._path, this._key);
786      }
787    }
788    return this._cachedPath;
789  }
790};
791var handleResult = (ctx, result) => {
792  if (isValid(result)) {
793    return { success: true, data: result.value };
794  } else {
795    if (!ctx.common.issues.length) {
796      throw new Error("Validation failed but no issues detected.");
797    }
798    return {
799      success: false,
800      get error() {
801        if (this._error)
802          return this._error;
803        const error = new ZodError(ctx.common.issues);
804        this._error = error;
805        return this._error;
806      }
807    };
808  }
809};
810function processCreateParams(params) {
811  if (!params)
812    return {};
813  const { errorMap: errorMap2, invalid_type_error, required_error, description } = params;
814  if (errorMap2 && (invalid_type_error || required_error)) {
815    throw new Error(`Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`);
816  }
817  if (errorMap2)
818    return { errorMap: errorMap2, description };
819  const customMap = (iss, ctx) => {
820    const { message } = params;
821    if (iss.code === "invalid_enum_value") {
822      return { message: message ?? ctx.defaultError };
823    }
824    if (typeof ctx.data === "undefined") {
825      return { message: message ?? required_error ?? ctx.defaultError };
826    }
827    if (iss.code !== "invalid_type")
828      return { message: ctx.defaultError };
829    return { message: message ?? invalid_type_error ?? ctx.defaultError };
830  };
831  return { errorMap: customMap, description };
832}
833var ZodType = class {
834  get description() {
835    return this._def.description;
836  }
837  _getType(input) {
838    return getParsedType(input.data);
839  }
840  _getOrReturnCtx(input, ctx) {
841    return ctx || {
842      common: input.parent.common,
843      data: input.data,
844      parsedType: getParsedType(input.data),
845      schemaErrorMap: this._def.errorMap,
846      path: input.path,
847      parent: input.parent
848    };
849  }
850  _processInputParams(input) {
851    return {
852      status: new ParseStatus(),
853      ctx: {
854        common: input.parent.common,
855        data: input.data,
856        parsedType: getParsedType(input.data),
857        schemaErrorMap: this._def.errorMap,
858        path: input.path,
859        parent: input.parent
860      }
861    };
862  }
863  _parseSync(input) {
864    const result = this._parse(input);
865    if (isAsync(result)) {
866      throw new Error("Synchronous parse encountered promise.");
867    }
868    return result;
869  }
870  _parseAsync(input) {
871    const result = this._parse(input);
872    return Promise.resolve(result);
873  }
874  parse(data, params) {
875    const result = this.safeParse(data, params);
876    if (result.success)
877      return result.data;
878    throw result.error;
879  }
880  safeParse(data, params) {
881    const ctx = {
882      common: {
883        issues: [],
884        async: params?.async ?? false,
885        contextualErrorMap: params?.errorMap
886      },
887      path: params?.path || [],
888      schemaErrorMap: this._def.errorMap,
889      parent: null,
890      data,
891      parsedType: getParsedType(data)
892    };
893    const result = this._parseSync({ data, path: ctx.path, parent: ctx });
894    return handleResult(ctx, result);
895  }
896  "~validate"(data) {
897    const ctx = {
898      common: {
899        issues: [],
900        async: !!this["~standard"].async
901      },
902      path: [],
903      schemaErrorMap: this._def.errorMap,
904      parent: null,
905      data,
906      parsedType: getParsedType(data)
907    };
908    if (!this["~standard"].async) {
909      try {
910        const result = this._parseSync({ data, path: [], parent: ctx });
911        return isValid(result) ? {
912          value: result.value
913        } : {
914          issues: ctx.common.issues
915        };
916      } catch (err) {
917        if (err?.message?.toLowerCase()?.includes("encountered")) {
918          this["~standard"].async = true;
919        }
920        ctx.common = {
921          issues: [],
922          async: true
923        };
924      }
925    }
926    return this._parseAsync({ data, path: [], parent: ctx }).then((result) => isValid(result) ? {
927      value: result.value
928    } : {
929      issues: ctx.common.issues
930    });
931  }
932  async parseAsync(data, params) {
933    const result = await this.safeParseAsync(data, params);
934    if (result.success)
935      return result.data;
936    throw result.error;
937  }
938  async safeParseAsync(data, params) {
939    const ctx = {
940      common: {
941        issues: [],
942        contextualErrorMap: params?.errorMap,
943        async: true
944      },
945      path: params?.path || [],
946      schemaErrorMap: this._def.errorMap,
947      parent: null,
948      data,
949      parsedType: getParsedType(data)
950    };
951    const maybeAsyncResult = this._parse({ data, path: ctx.path, parent: ctx });
952    const result = await (isAsync(maybeAsyncResult) ? maybeAsyncResult : Promise.resolve(maybeAsyncResult));
953    return handleResult(ctx, result);
954  }
955  refine(check, message) {
956    const getIssueProperties = (val) => {
957      if (typeof message === "string" || typeof message === "undefined") {
958        return { message };
959      } else if (typeof message === "function") {
960        return message(val);
961      } else {
962        return message;
963      }
964    };
965    return this._refinement((val, ctx) => {
966      const result = check(val);
967      const setError = () => ctx.addIssue({
968        code: ZodIssueCode.custom,
969        ...getIssueProperties(val)
970      });
971      if (typeof Promise !== "undefined" && result instanceof Promise) {
972        return result.then((data) => {
973          if (!data) {
974            setError();
975            return false;
976          } else {
977            return true;
978          }
979        });
980      }
981      if (!result) {
982        setError();
983        return false;
984      } else {
985        return true;
986      }
987    });
988  }
989  refinement(check, refinementData) {
990    return this._refinement((val, ctx) => {
991      if (!check(val)) {
992        ctx.addIssue(typeof refinementData === "function" ? refinementData(val, ctx) : refinementData);
993        return false;
994      } else {
995        return true;
996      }
997    });
998  }
999  _refinement(refinement) {
1000    return new ZodEffects({
1001      schema: this,
1002      typeName: ZodFirstPartyTypeKind.ZodEffects,
1003      effect: { type: "refinement", refinement }
1004    });
1005  }
1006  superRefine(refinement) {
1007    return this._refinement(refinement);
1008  }
1009  constructor(def) {
1010    this.spa = this.safeParseAsync;
1011    this._def = def;
1012    this.parse = this.parse.bind(this);
1013    this.safeParse = this.safeParse.bind(this);
1014    this.parseAsync = this.parseAsync.bind(this);
1015    this.safeParseAsync = this.safeParseAsync.bind(this);
1016    this.spa = this.spa.bind(this);
1017    this.refine = this.refine.bind(this);
1018    this.refinement = this.refinement.bind(this);
1019    this.superRefine = this.superRefine.bind(this);
1020    this.optional = this.optional.bind(this);
1021    this.nullable = this.nullable.bind(this);
1022    this.nullish = this.nullish.bind(this);
1023    this.array = this.array.bind(this);
1024    this.promise = this.promise.bind(this);
1025    this.or = this.or.bind(this);
1026    this.and = this.and.bind(this);
1027    this.transform = this.transform.bind(this);
1028    this.brand = this.brand.bind(this);
1029    this.default = this.default.bind(this);
1030    this.catch = this.catch.bind(this);
1031    this.describe = this.describe.bind(this);
1032    this.pipe = this.pipe.bind(this);
1033    this.readonly = this.readonly.bind(this);
1034    this.isNullable = this.isNullable.bind(this);
1035    this.isOptional = this.isOptional.bind(this);
1036    this["~standard"] = {
1037      version: 1,
1038      vendor: "zod",
1039      validate: (data) => this["~validate"](data)
1040    };
1041  }
1042  optional() {
1043    return ZodOptional.create(this, this._def);
1044  }
1045  nullable() {
1046    return ZodNullable.create(this, this._def);
1047  }
1048  nullish() {
1049    return this.nullable().optional();
1050  }
1051  array() {
1052    return ZodArray.create(this);
1053  }
1054  promise() {
1055    return ZodPromise.create(this, this._def);
1056  }
1057  or(option) {
1058    return ZodUnion.create([this, option], this._def);
1059  }
1060  and(incoming) {
1061    return ZodIntersection.create(this, incoming, this._def);
1062  }
1063  transform(transform) {
1064    return new ZodEffects({
1065      ...processCreateParams(this._def),
1066      schema: this,
1067      typeName: ZodFirstPartyTypeKind.ZodEffects,
1068      effect: { type: "transform", transform }
1069    });
1070  }
1071  default(def) {
1072    const defaultValueFunc = typeof def === "function" ? def : () => def;
1073    return new ZodDefault({
1074      ...processCreateParams(this._def),
1075      innerType: this,
1076      defaultValue: defaultValueFunc,
1077      typeName: ZodFirstPartyTypeKind.ZodDefault
1078    });
1079  }
1080  brand() {
1081    return new ZodBranded({
1082      typeName: ZodFirstPartyTypeKind.ZodBranded,
1083      type: this,
1084      ...processCreateParams(this._def)
1085    });
1086  }
1087  catch(def) {
1088    const catchValueFunc = typeof def === "function" ? def : () => def;
1089    return new ZodCatch({
1090      ...processCreateParams(this._def),
1091      innerType: this,
1092      catchValue: catchValueFunc,
1093      typeName: ZodFirstPartyTypeKind.ZodCatch
1094    });
1095  }
1096  describe(description) {
1097    const This = this.constructor;
1098    return new This({
1099      ...this._def,
1100      description
1101    });
1102  }
1103  pipe(target) {
1104    return ZodPipeline.create(this, target);
1105  }
1106  readonly() {
1107    return ZodReadonly.create(this);
1108  }
1109  isOptional() {
1110    return this.safeParse(void 0).success;
1111  }
1112  isNullable() {
1113    return this.safeParse(null).success;
1114  }
1115};
1116var cuidRegex = /^c[^\s-]{8,}$/i;
1117var cuid2Regex = /^[0-9a-z]+$/;
1118var ulidRegex = /^[0-9A-HJKMNP-TV-Z]{26}$/i;
1119var uuidRegex = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i;
1120var nanoidRegex = /^[a-z0-9_-]{21}$/i;
1121var jwtRegex = /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/;
1122var durationRegex = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/;
1123var emailRegex = /^(?!\.)(?!.*\.\.)([A-Z0-9_'+\-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i;
1124var _emojiRegex = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`;
1125var emojiRegex;
1126var ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
1127var ipv4CidrRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/;
1128var ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/;
1129var ipv6CidrRegex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/;
1130var base64Regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
1131var base64urlRegex = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/;
1132var dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
1133var dateRegex = new RegExp(`^${dateRegexSource}$`);
1134function timeRegexSource(args) {
1135  let secondsRegexSource = `[0-5]\\d`;
1136  if (args.precision) {
1137    secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`;
1138  } else if (args.precision == null) {
1139    secondsRegexSource = `${secondsRegexSource}(\\.\\d+)?`;
1140  }
1141  const secondsQuantifier = args.precision ? "+" : "?";
1142  return `([01]\\d|2[0-3]):[0-5]\\d(:${secondsRegexSource})${secondsQuantifier}`;
1143}
1144function timeRegex(args) {
1145  return new RegExp(`^${timeRegexSource(args)}$`);
1146}
1147function datetimeRegex(args) {
1148  let regex = `${dateRegexSource}T${timeRegexSource(args)}`;
1149  const opts = [];
1150  opts.push(args.local ? `Z?` : `Z`);
1151  if (args.offset)
1152    opts.push(`([+-]\\d{2}:?\\d{2})`);
1153  regex = `${regex}(${opts.join("|")})`;
1154  return new RegExp(`^${regex}$`);
1155}
1156function isValidIP(ip, version) {
1157  if ((version === "v4" || !version) && ipv4Regex.test(ip)) {
1158    return true;
1159  }
1160  if ((version === "v6" || !version) && ipv6Regex.test(ip)) {
1161    return true;
1162  }
1163  return false;
1164}
1165function isValidJWT(jwt, alg) {
1166  if (!jwtRegex.test(jwt))
1167    return false;
1168  try {
1169    const [header] = jwt.split(".");
1170    if (!header)
1171      return false;
1172    const base64 = header.replace(/-/g, "+").replace(/_/g, "/").padEnd(header.length + (4 - header.length % 4) % 4, "=");
1173    const decoded = JSON.parse(atob(base64));
1174    if (typeof decoded !== "object" || decoded === null)
1175      return false;
1176    if ("typ" in decoded && decoded?.typ !== "JWT")
1177      return false;
1178    if (!decoded.alg)
1179      return false;
1180    if (alg && decoded.alg !== alg)
1181      return false;
1182    return true;
1183  } catch {
1184    return false;
1185  }
1186}
1187function isValidCidr(ip, version) {
1188  if ((version === "v4" || !version) && ipv4CidrRegex.test(ip)) {
1189    return true;
1190  }
1191  if ((version === "v6" || !version) && ipv6CidrRegex.test(ip)) {
1192    return true;
1193  }
1194  return false;
1195}
1196var ZodString = class _ZodString extends ZodType {
1197  _parse(input) {
1198    if (this._def.coerce) {
1199      input.data = String(input.data);
1200    }
types/index.d.ts 24 lines
1// The cc-idle mod's $.state contract: session-scoped UI state the pane draws from.
2// The economy itself lives in $.store (shared by every session), not here.
3
4/** Which screen the pane shows. 'help' is also the welcome a new player sees first; 'chat' talks to the board. */
5export type IdleView = 'main' | 'tree' | 'confirm-ship' | 'help' | 'chat';
6
7/** Why Claude Code is waiting on the person, or '' while it isn't. */
8export type IdleNeedsYou = '' | 'done' | 'permission' | 'question';
9
10declare module 'claude-code' {
11  interface PluginState {
12    'cc-idle': {
13      /** Bumped whenever the economy changes, so the pane redraws. */
14      rev: number;
15      view: IdleView;
16      /** Index of the focused region, in founding order. */
17      region: number;
18      needsYou: IdleNeedsYou;
19      /** Bumped whenever the board chat changes, so the pane redraws. */
20      board: number;
21    };
22  }
23}
24