@wirecat/cli-core 0.583.0 → 0.584.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,19 @@ shape of this file.
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## 0.584.0 — 06.11.2026
11
+
12
+ ### Added
13
+
14
+ - **`schedule list` gives an agent schedule's cost caps.** `max_cost_usd` is the cap on one run (`--max-cost`, null
15
+ when none) and `max_cost_per_day_usd` the daily cap in force, the schedule's `--max-cost-per-day` or the config's
16
+ (0 for none), so a screen can show `$0.84 of $5.00`; the text line says `today $0.84 of $5.00`.
17
+
18
+ ### Fixed
19
+
20
+ - **`schedule list`'s output schema describes what it prints.** `spent_today_usd`, and the last run's `cost_usd`
21
+ and `skipped`, were printed but missing from the strict `scheduled_job` schema.
22
+
10
23
  ## 0.583.0 — 05.11.2026
11
24
 
12
25
  ### Changed — may break callers
@@ -138,6 +138,12 @@ export const scheduleLimitsOf = (config) => {
138
138
  const given = (limits) => Object.fromEntries(Object.entries(limits).filter(([, value]) => value !== undefined));
139
139
  const shown = (argv) => argv.map((arg) => (arg === "" ? '""' : arg)).join(" ");
140
140
  const usd = (value) => `$${value.toFixed(2)}`;
141
+ /** The per-run cap an agent schedule was made with (`--max-cost`, passed to claude as --max-budget-usd), or null. */
142
+ const runCapOf = (argv) => {
143
+ const at = argv.indexOf("--max-budget-usd");
144
+ const cap = at < 0 ? Number.NaN : Number(argv[at + 1]);
145
+ return Number.isFinite(cap) ? cap : null;
146
+ };
141
147
  /**
142
148
  * Runs the CLI's own commands, or an agent, later or on a timer — through systemd (Linux), launchd
143
149
  * (macOS) or Task Scheduler (Windows). Every timer runs `schedule exec <file>`; the schedule file holds
@@ -184,19 +190,21 @@ export const scheduleCommandFor = ({ app, context: contextOf, newMail, limits: c
184
190
  * Why a run does not start now, or nothing: an agent whose runs reached the day's cost cap waits for tomorrow, and
185
191
  * one gated on mail waits for mail past its holder's mark — on its timer, until enough of it waits.
186
192
  */
193
+ /** A schedule's own limits, else the config file's, else the defaults. */
194
+ const limitsOf = (self, schedule) => ({
195
+ ...SCHEDULE_DEFAULTS,
196
+ ...given(configured?.(self) ?? {}),
197
+ ...given({
198
+ mailWaitMinutes: schedule.mailWaitMinutes,
199
+ mailBatch: schedule.mailBatch,
200
+ maxCostPerDay: schedule.maxCostPerDay,
201
+ }),
202
+ });
187
203
  const waits = async (self, file, { timed }) => {
188
204
  if (!existsSync(file))
189
205
  return undefined;
190
206
  const schedule = readSchedule(file);
191
- const { mailWaitMinutes, mailBatch, maxCostPerDay } = {
192
- ...SCHEDULE_DEFAULTS,
193
- ...given(configured?.(self) ?? {}),
194
- ...given({
195
- mailWaitMinutes: schedule.mailWaitMinutes,
196
- mailBatch: schedule.mailBatch,
197
- maxCostPerDay: schedule.maxCostPerDay,
198
- }),
199
- };
207
+ const { mailWaitMinutes, mailBatch, maxCostPerDay } = limitsOf(self, schedule);
200
208
  if (schedule.kind === "agent" && maxCostPerDay > 0) {
201
209
  const spent = spentToday(file);
202
210
  if (spent >= maxCostPerDay) {
@@ -342,7 +350,13 @@ export const scheduleCommandFor = ({ app, context: contextOf, newMail, limits: c
342
350
  kind: schedule.kind,
343
351
  when: describeWhen(schedule.when),
344
352
  last: lastRun(scheduleFile(state, schedule.name)) ?? null,
345
- ...(schedule.kind === "agent" ? { spentTodayUsd: spentToday(scheduleFile(state, schedule.name)) } : {}),
353
+ ...(schedule.kind === "agent"
354
+ ? {
355
+ spentTodayUsd: spentToday(scheduleFile(state, schedule.name)),
356
+ maxCostUsd: runCapOf(schedule.argv),
357
+ maxCostPerDayUsd: limitsOf(this, schedule).maxCostPerDay,
358
+ }
359
+ : {}),
346
360
  }));
347
361
  const answer = listOf("schedule list", {
348
362
  items: rows.map((row) => snakeKeys(row)),
@@ -355,7 +369,7 @@ export const scheduleCommandFor = ({ app, context: contextOf, newMail, limits: c
355
369
  return "";
356
370
  }
357
371
  return rows
358
- .map(({ name, kind, when, last, spentTodayUsd }) => [
372
+ .map(({ name, kind, when, last, spentTodayUsd, maxCostPerDayUsd }) => [
359
373
  name,
360
374
  kind,
361
375
  when,
@@ -366,7 +380,9 @@ export const scheduleCommandFor = ({ app, context: contextOf, newMail, limits: c
366
380
  `${last.failures} in a row${last.reason ? `: ${last.reason}` : ""} — ${last.output}`
367
381
  : "")
368
382
  : "not run yet",
369
- ...(spentTodayUsd ? [`today ${usd(spentTodayUsd)}`] : []),
383
+ ...(spentTodayUsd
384
+ ? [`today ${usd(spentTodayUsd)}${maxCostPerDayUsd ? ` of ${usd(maxCostPerDayUsd)}` : ""}`]
385
+ : []),
370
386
  ...(last?.skipped
371
387
  ? [`skipped ${last.skipped.at.slice(0, 16).replace("T", " ")}: ${last.skipped.why}`]
372
388
  : []),
@@ -3979,7 +3979,15 @@ export declare const ENTITIES: {
3979
3979
  readonly error_code: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
3980
3980
  readonly failing_since: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
3981
3981
  readonly failures: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
3982
+ readonly cost_usd: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
3983
+ readonly skipped: v.OptionalSchema<v.StrictObjectSchema<{
3984
+ readonly at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
3985
+ readonly why: v.StringSchema<undefined>;
3986
+ }, undefined>, undefined>;
3982
3987
  }, undefined>, undefined>;
3988
+ readonly spent_today_usd: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
3989
+ readonly max_cost_usd: v.OptionalSchema<v.NullableSchema<v.NumberSchema<undefined>, undefined>, undefined>;
3990
+ readonly max_cost_per_day_usd: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
3983
3991
  }, undefined>;
3984
3992
  readonly call_record: v.StrictObjectSchema<{
3985
3993
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
@@ -57,7 +57,19 @@ export declare const scheduledJob: v.StrictObjectSchema<{
57
57
  readonly error_code: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
58
58
  readonly failing_since: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
59
59
  readonly failures: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
60
+ readonly cost_usd: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
61
+ /** The last time a run did not start, and why: the day's cost cap, or too little new mail. */
62
+ readonly skipped: v.OptionalSchema<v.StrictObjectSchema<{
63
+ readonly at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
64
+ readonly why: v.StringSchema<undefined>;
65
+ }, undefined>, undefined>;
60
66
  }, undefined>, undefined>;
67
+ /** Agent schedules: what today's runs cost, in US dollars. */
68
+ readonly spent_today_usd: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
69
+ /** Agent schedules: the cap on one run (`--max-cost`), null when none. */
70
+ readonly max_cost_usd: v.OptionalSchema<v.NullableSchema<v.NumberSchema<undefined>, undefined>, undefined>;
71
+ /** Agent schedules: the daily cap in force, the schedule's `--max-cost-per-day` or the config's; 0 for none. */
72
+ readonly max_cost_per_day_usd: v.OptionalSchema<v.NumberSchema<undefined>, undefined>;
61
73
  }, undefined>;
62
74
  export declare const botTemplate: v.StrictObjectSchema<{
63
75
  readonly name: v.NullableSchema<v.StringSchema<undefined>, undefined>;
@@ -41,7 +41,16 @@ export const scheduledJob = v.strictObject({
41
41
  error_code: v.optional(text),
42
42
  failing_since: v.optional(time),
43
43
  failures: v.optional(v.number()),
44
+ cost_usd: v.optional(v.number()),
45
+ /** The last time a run did not start, and why: the day's cost cap, or too little new mail. */
46
+ skipped: v.optional(v.strictObject({ at: time, why: text })),
44
47
  })),
48
+ /** Agent schedules: what today's runs cost, in US dollars. */
49
+ spent_today_usd: v.optional(v.number()),
50
+ /** Agent schedules: the cap on one run (`--max-cost`), null when none. */
51
+ max_cost_usd: v.optional(v.nullable(v.number())),
52
+ /** Agent schedules: the daily cap in force, the schedule's `--max-cost-per-day` or the config's; 0 for none. */
53
+ max_cost_per_day_usd: v.optional(v.number()),
45
54
  });
46
55
  export const botTemplate = v.strictObject({
47
56
  name: v.nullable(text),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-core",
3
- "version": "0.583.0",
3
+ "version": "0.584.0",
4
4
  "description": "The messenger-neutral half of a messaging CLI: domain model, message locators, rendering, name resolution, the SQLite seam, the command skeleton and shared read commands, the send guard, run records and the message store",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Viacheslav Ptsarev",