runcycles 0.1.2 → 0.3.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/README.md CHANGED
@@ -1,3 +1,9 @@
1
+ [![npm](https://img.shields.io/npm/v/runcycles)](https://www.npmjs.com/package/runcycles)
2
+ [![npm Downloads](https://img.shields.io/npm/dm/runcycles)](https://www.npmjs.com/package/runcycles)
3
+ [![CI](https://github.com/runcycles/cycles-client-typescript/actions/workflows/ci.yml/badge.svg)](https://github.com/runcycles/cycles-client-typescript/actions)
4
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE)
5
+ [![Coverage](https://img.shields.io/badge/coverage-98%25-brightgreen)](https://github.com/runcycles/cycles-client-typescript/actions)
6
+
1
7
  # Cycles TypeScript Client
2
8
 
3
9
  TypeScript client for the [Cycles](https://runcycles.io) budget-management protocol — govern spend on AI calls, API usage, and any metered resource.
@@ -69,6 +75,24 @@ const result = await callLlm("Hello", 100);
69
75
 
70
76
  **What happens:** `withCycles` reserves budget before calling your function, runs it inside an async context (so `getCyclesContext()` works), commits the actual cost on success, or releases the reservation on failure. A background heartbeat keeps the reservation alive.
71
77
 
78
+ ### Budget lifecycle
79
+
80
+ | Scenario | Outcome | Detail |
81
+ |---|---|---|
82
+ | Reservation denied | **Neither** | `BudgetExceededError`, `OverdraftLimitExceededError`, or `DebtOutstandingError` thrown; function never executes |
83
+ | `dryRun: true`, any decision | **Neither** | Returns `DryRunResult` or throws; no real reservation created |
84
+ | Function returns successfully | **Commit** | Actual amount charged; unused remainder auto-released |
85
+ | Function throws any error | **Release** | Full reserved amount returned to budget; error re-thrown |
86
+ | Commit fails (5xx / network) | **Retry** | Exponential backoff with configurable attempts |
87
+ | Commit fails (non-retryable 4xx) | **Release** | Reservation released after non-retryable client error |
88
+ | Commit gets RESERVATION_EXPIRED | **Neither** | Server already reclaimed budget on TTL expiry |
89
+ | Commit gets RESERVATION_FINALIZED | **Neither** | Already committed or released (idempotent replay) |
90
+ | Commit gets IDEMPOTENCY_MISMATCH | **Neither** | Previous commit already processed; no release attempted |
91
+
92
+ **Streaming (`reserveForStream`):** Call `handle.commit(actual)` on success or `handle.release(reason)` on failure. If neither is called, the server reclaims the budget when the reservation TTL expires.
93
+
94
+ All thrown errors from the guarded function trigger release. See [How Reserve-Commit Works](https://runcycles.io/protocol/how-reserve-commit-works-in-cycles) for the full protocol-level explanation.
95
+
72
96
  ### 2. Streaming adapter
73
97
 
74
98
  For LLM streaming where usage is only known after the stream finishes:
@@ -292,9 +316,9 @@ interface WithCyclesConfig {
292
316
  actual?: number | ((result) => number); // Actual cost (static or computed from result)
293
317
  useEstimateIfActualNotProvided?: boolean; // Default: true — use estimate as actual
294
318
 
295
- // Action identification
296
- actionKind?: string; // e.g. "llm.completion" (default: "unknown")
297
- actionName?: string; // e.g. "gpt-4" (default: "unknown")
319
+ // Action identification (static or computed from args)
320
+ actionKind?: string | ((...args) => string | undefined); // e.g. "llm.completion" (default: "unknown")
321
+ actionName?: string | ((...args) => string | undefined); // e.g. "gpt-4" (default: "unknown")
298
322
  actionTags?: string[]; // Optional tags for categorization
299
323
 
300
324
  // Budget unit
@@ -303,16 +327,16 @@ interface WithCyclesConfig {
303
327
  // Reservation settings
304
328
  ttlMs?: number; // Time-to-live in ms (default: 60000, range: 1000–86400000)
305
329
  gracePeriodMs?: number; // Grace period in ms (range: 0–60000)
306
- overagePolicy?: string; // "REJECT" (default), "ALLOW_IF_AVAILABLE", "ALLOW_WITH_OVERDRAFT"
330
+ overagePolicy?: string; // "ALLOW_IF_AVAILABLE" (default), "REJECT", "ALLOW_WITH_OVERDRAFT"
307
331
  dryRun?: boolean; // Shadow mode — evaluates budget without executing
308
332
 
309
- // Subject fields (override config defaults)
310
- tenant?: string;
311
- workspace?: string;
312
- app?: string;
313
- workflow?: string;
314
- agent?: string;
315
- toolset?: string;
333
+ // Subject fields (override config defaults; static or computed from args)
334
+ tenant?: string | ((...args) => string | undefined);
335
+ workspace?: string | ((...args) => string | undefined);
336
+ app?: string | ((...args) => string | undefined);
337
+ workflow?: string | ((...args) => string | undefined);
338
+ agent?: string | ((...args) => string | undefined);
339
+ toolset?: string | ((...args) => string | undefined);
316
340
  dimensions?: Record<string, string>; // Custom key-value dimensions
317
341
 
318
342
  // Client
@@ -320,6 +344,28 @@ interface WithCyclesConfig {
320
344
  }
321
345
  ```
322
346
 
347
+ A callable returning `undefined` falls through to the client-config default for subject fields, or to `"unknown"` for `actionKind` / `actionName` — same fallback semantics as a missing static. Callables run before the reservation is created; if one throws, the reservation is never attempted and the error propagates to the caller.
348
+
349
+ ### Dynamic subject and action fields
350
+
351
+ Derive the subject scope or action identity from per-call arguments:
352
+
353
+ ```typescript
354
+ const runRequest = withCycles(
355
+ {
356
+ estimate: (req, workspaceId) => req.tokens * 10,
357
+ workspace: (_req, workspaceId) => workspaceId,
358
+ actionKind: "llm.completion",
359
+ actionName: (req) => req.model,
360
+ client,
361
+ },
362
+ async (req: { tokens: number; model: string }, workspaceId: string) => {
363
+ // ... the reservation routes to this workspaceId ...
364
+ return callLLM(req);
365
+ },
366
+ );
367
+ ```
368
+
323
369
  ## Context Access
324
370
 
325
371
  Inside a `withCycles`-guarded function, access the active reservation via `getCyclesContext()`:
@@ -795,6 +841,29 @@ ErrorCode.INTERNAL_ERROR
795
841
  ErrorCode.UNKNOWN
796
842
  ```
797
843
 
844
+ ## Nested `withCycles` Calls
845
+
846
+ Calling a `withCycles`-wrapped function from inside another `withCycles`-wrapped function is allowed — it will not throw an error. However, each wrapper creates an **independent reservation** that deducts budget separately:
847
+
848
+ ```typescript
849
+ const inner = withCycles({ estimate: 100, actionName: "inner" }, async () => "done");
850
+ const outer = withCycles({ estimate: 500, actionName: "outer" }, async () => {
851
+ return await inner(); // creates a SECOND reservation — 600 total deducted, not 500
852
+ });
853
+ ```
854
+
855
+ This means nested guards **double-count budget**. The outer reservation already covers the full estimated cost of the operation, so an inner reservation deducts additional budget from the same pool.
856
+
857
+ **Recommended pattern:** Place `withCycles` at the outermost entry point only. Inner functions should be plain async functions without their own guard:
858
+
859
+ ```typescript
860
+ const inner = async () => "done"; // no withCycles — called within a guarded operation
861
+
862
+ const outer = withCycles({ estimate: 500, actionName: "outer" }, async () => {
863
+ return await inner(); // single reservation — 500 total
864
+ });
865
+ ```
866
+
798
867
  ## Examples
799
868
 
800
869
  See the [`examples/`](./examples/) directory:
@@ -824,6 +893,13 @@ See the [`examples/`](./examples/) directory:
824
893
  - **Dual ESM/CJS**: Works with both module systems
825
894
  - **Input validation**: Client-side validation of TTL, amounts, subject fields, and more
826
895
 
896
+ ## Documentation
897
+
898
+ - [Cycles Documentation](https://runcycles.io) — full docs site
899
+ - [TypeScript Quickstart](https://runcycles.io/quickstart/getting-started-with-the-typescript-client) — getting started guide
900
+ - [TypeScript Client Configuration Reference](https://runcycles.io/configuration/typescript-client-configuration-reference) — all configuration options
901
+ - [Error Handling Patterns in TypeScript](https://runcycles.io/how-to/error-handling-patterns-in-typescript) — handling budget errors
902
+
827
903
  ## License
828
904
 
829
905
  Apache-2.0
package/dist/index.cjs CHANGED
@@ -835,12 +835,15 @@ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
835
835
  ErrorCode2["FORBIDDEN"] = "FORBIDDEN";
836
836
  ErrorCode2["NOT_FOUND"] = "NOT_FOUND";
837
837
  ErrorCode2["BUDGET_EXCEEDED"] = "BUDGET_EXCEEDED";
838
+ ErrorCode2["BUDGET_FROZEN"] = "BUDGET_FROZEN";
839
+ ErrorCode2["BUDGET_CLOSED"] = "BUDGET_CLOSED";
838
840
  ErrorCode2["RESERVATION_EXPIRED"] = "RESERVATION_EXPIRED";
839
841
  ErrorCode2["RESERVATION_FINALIZED"] = "RESERVATION_FINALIZED";
840
842
  ErrorCode2["IDEMPOTENCY_MISMATCH"] = "IDEMPOTENCY_MISMATCH";
841
843
  ErrorCode2["UNIT_MISMATCH"] = "UNIT_MISMATCH";
842
844
  ErrorCode2["OVERDRAFT_LIMIT_EXCEEDED"] = "OVERDRAFT_LIMIT_EXCEEDED";
843
845
  ErrorCode2["DEBT_OUTSTANDING"] = "DEBT_OUTSTANDING";
846
+ ErrorCode2["MAX_EXTENSIONS_EXCEEDED"] = "MAX_EXTENSIONS_EXCEEDED";
844
847
  ErrorCode2["INTERNAL_ERROR"] = "INTERNAL_ERROR";
845
848
  ErrorCode2["UNKNOWN"] = "UNKNOWN";
846
849
  return ErrorCode2;
@@ -926,7 +929,13 @@ function evaluateActual(expr, result, estimate, useEstimateFallback) {
926
929
  "actual expression is required when useEstimateIfActualNotProvided is false"
927
930
  );
928
931
  }
929
- function buildReservationBody(cfg, estimate, defaultSubject) {
932
+ function evaluateStringField(expr, args) {
933
+ if (typeof expr === "function") {
934
+ return expr(...args);
935
+ }
936
+ return expr;
937
+ }
938
+ function buildReservationBody(cfg, estimate, defaultSubject, args) {
930
939
  validateNonNegative(estimate, "estimate");
931
940
  const ttlMs = cfg.ttlMs ?? DEFAULT_TTL_MS;
932
941
  validateTtlMs(ttlMs);
@@ -939,7 +948,8 @@ function buildReservationBody(cfg, estimate, defaultSubject) {
939
948
  "agent",
940
949
  "toolset"
941
950
  ]) {
942
- const val = cfg[field] ?? defaultSubject[field];
951
+ const resolved = evaluateStringField(cfg[field], args);
952
+ const val = resolved ?? defaultSubject[field];
943
953
  if (val) {
944
954
  subject[field] = val;
945
955
  }
@@ -949,8 +959,8 @@ function buildReservationBody(cfg, estimate, defaultSubject) {
949
959
  }
950
960
  validateSubject(subject);
951
961
  const action = {
952
- kind: cfg.actionKind ?? "unknown",
953
- name: cfg.actionName ?? "unknown"
962
+ kind: evaluateStringField(cfg.actionKind, args) ?? "unknown",
963
+ name: evaluateStringField(cfg.actionName, args) ?? "unknown"
954
964
  };
955
965
  if (cfg.actionTags) {
956
966
  action.tags = cfg.actionTags;
@@ -962,7 +972,7 @@ function buildReservationBody(cfg, estimate, defaultSubject) {
962
972
  action,
963
973
  estimate: { unit, amount: estimate },
964
974
  ttl_ms: ttlMs,
965
- overage_policy: cfg.overagePolicy ?? "REJECT"
975
+ overage_policy: cfg.overagePolicy ?? "ALLOW_IF_AVAILABLE"
966
976
  };
967
977
  validateGracePeriodMs(cfg.gracePeriodMs);
968
978
  if (cfg.gracePeriodMs !== void 0) {
@@ -1005,7 +1015,12 @@ var AsyncCyclesLifecycle = class {
1005
1015
  }
1006
1016
  async execute(fn, args, cfg) {
1007
1017
  const estimate = evaluateAmount(cfg.estimate, args);
1008
- const createBody = buildReservationBody(cfg, estimate, this._defaultSubject);
1018
+ const createBody = buildReservationBody(
1019
+ cfg,
1020
+ estimate,
1021
+ this._defaultSubject,
1022
+ args
1023
+ );
1009
1024
  const resResponse = await this._client.createReservation(createBody);
1010
1025
  if (!resResponse.isSuccess) {
1011
1026
  throw buildProtocolException("Failed to create reservation", resResponse);
@@ -1284,7 +1299,7 @@ async function reserveForStream(options) {
1284
1299
  actionTags,
1285
1300
  ttlMs = DEFAULT_TTL_MS,
1286
1301
  gracePeriodMs,
1287
- overagePolicy = "REJECT",
1302
+ overagePolicy = "ALLOW_IF_AVAILABLE",
1288
1303
  dimensions
1289
1304
  } = options;
1290
1305
  validateNonNegative(estimate, "estimate");
package/dist/index.d.cts CHANGED
@@ -76,12 +76,15 @@ declare enum ErrorCode {
76
76
  FORBIDDEN = "FORBIDDEN",
77
77
  NOT_FOUND = "NOT_FOUND",
78
78
  BUDGET_EXCEEDED = "BUDGET_EXCEEDED",
79
+ BUDGET_FROZEN = "BUDGET_FROZEN",
80
+ BUDGET_CLOSED = "BUDGET_CLOSED",
79
81
  RESERVATION_EXPIRED = "RESERVATION_EXPIRED",
80
82
  RESERVATION_FINALIZED = "RESERVATION_FINALIZED",
81
83
  IDEMPOTENCY_MISMATCH = "IDEMPOTENCY_MISMATCH",
82
84
  UNIT_MISMATCH = "UNIT_MISMATCH",
83
85
  OVERDRAFT_LIMIT_EXCEEDED = "OVERDRAFT_LIMIT_EXCEEDED",
84
86
  DEBT_OUTSTANDING = "DEBT_OUTSTANDING",
87
+ MAX_EXTENSIONS_EXCEEDED = "MAX_EXTENSIONS_EXCEEDED",
85
88
  INTERNAL_ERROR = "INTERNAL_ERROR",
86
89
  UNKNOWN = "UNKNOWN"
87
90
  }
@@ -213,6 +216,7 @@ interface DecisionResponse {
213
216
  interface EventCreateResponse {
214
217
  status: EventStatus;
215
218
  eventId: string;
219
+ charged?: Amount;
216
220
  balances?: Balance[];
217
221
  }
218
222
  interface DryRunResult {
@@ -338,20 +342,20 @@ declare class CyclesClient {
338
342
  interface WithCyclesConfig<TArgs extends unknown[] = unknown[], TResult = unknown> {
339
343
  estimate: number | ((...args: TArgs) => number);
340
344
  actual?: number | ((result: TResult) => number);
341
- actionKind?: string;
342
- actionName?: string;
345
+ actionKind?: string | ((...args: TArgs) => string | undefined);
346
+ actionName?: string | ((...args: TArgs) => string | undefined);
343
347
  actionTags?: string[];
344
348
  unit?: string;
345
349
  ttlMs?: number;
346
350
  gracePeriodMs?: number;
347
351
  overagePolicy?: string;
348
352
  dryRun?: boolean;
349
- tenant?: string;
350
- workspace?: string;
351
- app?: string;
352
- workflow?: string;
353
- agent?: string;
354
- toolset?: string;
353
+ tenant?: string | ((...args: TArgs) => string | undefined);
354
+ workspace?: string | ((...args: TArgs) => string | undefined);
355
+ app?: string | ((...args: TArgs) => string | undefined);
356
+ workflow?: string | ((...args: TArgs) => string | undefined);
357
+ agent?: string | ((...args: TArgs) => string | undefined);
358
+ toolset?: string | ((...args: TArgs) => string | undefined);
355
359
  dimensions?: Record<string, string>;
356
360
  useEstimateIfActualNotProvided?: boolean;
357
361
  }
package/dist/index.d.ts CHANGED
@@ -76,12 +76,15 @@ declare enum ErrorCode {
76
76
  FORBIDDEN = "FORBIDDEN",
77
77
  NOT_FOUND = "NOT_FOUND",
78
78
  BUDGET_EXCEEDED = "BUDGET_EXCEEDED",
79
+ BUDGET_FROZEN = "BUDGET_FROZEN",
80
+ BUDGET_CLOSED = "BUDGET_CLOSED",
79
81
  RESERVATION_EXPIRED = "RESERVATION_EXPIRED",
80
82
  RESERVATION_FINALIZED = "RESERVATION_FINALIZED",
81
83
  IDEMPOTENCY_MISMATCH = "IDEMPOTENCY_MISMATCH",
82
84
  UNIT_MISMATCH = "UNIT_MISMATCH",
83
85
  OVERDRAFT_LIMIT_EXCEEDED = "OVERDRAFT_LIMIT_EXCEEDED",
84
86
  DEBT_OUTSTANDING = "DEBT_OUTSTANDING",
87
+ MAX_EXTENSIONS_EXCEEDED = "MAX_EXTENSIONS_EXCEEDED",
85
88
  INTERNAL_ERROR = "INTERNAL_ERROR",
86
89
  UNKNOWN = "UNKNOWN"
87
90
  }
@@ -213,6 +216,7 @@ interface DecisionResponse {
213
216
  interface EventCreateResponse {
214
217
  status: EventStatus;
215
218
  eventId: string;
219
+ charged?: Amount;
216
220
  balances?: Balance[];
217
221
  }
218
222
  interface DryRunResult {
@@ -338,20 +342,20 @@ declare class CyclesClient {
338
342
  interface WithCyclesConfig<TArgs extends unknown[] = unknown[], TResult = unknown> {
339
343
  estimate: number | ((...args: TArgs) => number);
340
344
  actual?: number | ((result: TResult) => number);
341
- actionKind?: string;
342
- actionName?: string;
345
+ actionKind?: string | ((...args: TArgs) => string | undefined);
346
+ actionName?: string | ((...args: TArgs) => string | undefined);
343
347
  actionTags?: string[];
344
348
  unit?: string;
345
349
  ttlMs?: number;
346
350
  gracePeriodMs?: number;
347
351
  overagePolicy?: string;
348
352
  dryRun?: boolean;
349
- tenant?: string;
350
- workspace?: string;
351
- app?: string;
352
- workflow?: string;
353
- agent?: string;
354
- toolset?: string;
353
+ tenant?: string | ((...args: TArgs) => string | undefined);
354
+ workspace?: string | ((...args: TArgs) => string | undefined);
355
+ app?: string | ((...args: TArgs) => string | undefined);
356
+ workflow?: string | ((...args: TArgs) => string | undefined);
357
+ agent?: string | ((...args: TArgs) => string | undefined);
358
+ toolset?: string | ((...args: TArgs) => string | undefined);
355
359
  dimensions?: Record<string, string>;
356
360
  useEstimateIfActualNotProvided?: boolean;
357
361
  }
package/dist/index.js CHANGED
@@ -760,12 +760,15 @@ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
760
760
  ErrorCode2["FORBIDDEN"] = "FORBIDDEN";
761
761
  ErrorCode2["NOT_FOUND"] = "NOT_FOUND";
762
762
  ErrorCode2["BUDGET_EXCEEDED"] = "BUDGET_EXCEEDED";
763
+ ErrorCode2["BUDGET_FROZEN"] = "BUDGET_FROZEN";
764
+ ErrorCode2["BUDGET_CLOSED"] = "BUDGET_CLOSED";
763
765
  ErrorCode2["RESERVATION_EXPIRED"] = "RESERVATION_EXPIRED";
764
766
  ErrorCode2["RESERVATION_FINALIZED"] = "RESERVATION_FINALIZED";
765
767
  ErrorCode2["IDEMPOTENCY_MISMATCH"] = "IDEMPOTENCY_MISMATCH";
766
768
  ErrorCode2["UNIT_MISMATCH"] = "UNIT_MISMATCH";
767
769
  ErrorCode2["OVERDRAFT_LIMIT_EXCEEDED"] = "OVERDRAFT_LIMIT_EXCEEDED";
768
770
  ErrorCode2["DEBT_OUTSTANDING"] = "DEBT_OUTSTANDING";
771
+ ErrorCode2["MAX_EXTENSIONS_EXCEEDED"] = "MAX_EXTENSIONS_EXCEEDED";
769
772
  ErrorCode2["INTERNAL_ERROR"] = "INTERNAL_ERROR";
770
773
  ErrorCode2["UNKNOWN"] = "UNKNOWN";
771
774
  return ErrorCode2;
@@ -851,7 +854,13 @@ function evaluateActual(expr, result, estimate, useEstimateFallback) {
851
854
  "actual expression is required when useEstimateIfActualNotProvided is false"
852
855
  );
853
856
  }
854
- function buildReservationBody(cfg, estimate, defaultSubject) {
857
+ function evaluateStringField(expr, args) {
858
+ if (typeof expr === "function") {
859
+ return expr(...args);
860
+ }
861
+ return expr;
862
+ }
863
+ function buildReservationBody(cfg, estimate, defaultSubject, args) {
855
864
  validateNonNegative(estimate, "estimate");
856
865
  const ttlMs = cfg.ttlMs ?? DEFAULT_TTL_MS;
857
866
  validateTtlMs(ttlMs);
@@ -864,7 +873,8 @@ function buildReservationBody(cfg, estimate, defaultSubject) {
864
873
  "agent",
865
874
  "toolset"
866
875
  ]) {
867
- const val = cfg[field] ?? defaultSubject[field];
876
+ const resolved = evaluateStringField(cfg[field], args);
877
+ const val = resolved ?? defaultSubject[field];
868
878
  if (val) {
869
879
  subject[field] = val;
870
880
  }
@@ -874,8 +884,8 @@ function buildReservationBody(cfg, estimate, defaultSubject) {
874
884
  }
875
885
  validateSubject(subject);
876
886
  const action = {
877
- kind: cfg.actionKind ?? "unknown",
878
- name: cfg.actionName ?? "unknown"
887
+ kind: evaluateStringField(cfg.actionKind, args) ?? "unknown",
888
+ name: evaluateStringField(cfg.actionName, args) ?? "unknown"
879
889
  };
880
890
  if (cfg.actionTags) {
881
891
  action.tags = cfg.actionTags;
@@ -887,7 +897,7 @@ function buildReservationBody(cfg, estimate, defaultSubject) {
887
897
  action,
888
898
  estimate: { unit, amount: estimate },
889
899
  ttl_ms: ttlMs,
890
- overage_policy: cfg.overagePolicy ?? "REJECT"
900
+ overage_policy: cfg.overagePolicy ?? "ALLOW_IF_AVAILABLE"
891
901
  };
892
902
  validateGracePeriodMs(cfg.gracePeriodMs);
893
903
  if (cfg.gracePeriodMs !== void 0) {
@@ -930,7 +940,12 @@ var AsyncCyclesLifecycle = class {
930
940
  }
931
941
  async execute(fn, args, cfg) {
932
942
  const estimate = evaluateAmount(cfg.estimate, args);
933
- const createBody = buildReservationBody(cfg, estimate, this._defaultSubject);
943
+ const createBody = buildReservationBody(
944
+ cfg,
945
+ estimate,
946
+ this._defaultSubject,
947
+ args
948
+ );
934
949
  const resResponse = await this._client.createReservation(createBody);
935
950
  if (!resResponse.isSuccess) {
936
951
  throw buildProtocolException("Failed to create reservation", resResponse);
@@ -1209,7 +1224,7 @@ async function reserveForStream(options) {
1209
1224
  actionTags,
1210
1225
  ttlMs = DEFAULT_TTL_MS,
1211
1226
  gracePeriodMs,
1212
- overagePolicy = "REJECT",
1227
+ overagePolicy = "ALLOW_IF_AVAILABLE",
1213
1228
  dimensions
1214
1229
  } = options;
1215
1230
  validateNonNegative(estimate, "estimate");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runcycles",
3
- "version": "0.1.2",
3
+ "version": "0.3.0",
4
4
  "description": "TypeScript client for the Cycles budget-management protocol",
5
5
  "license": "Apache-2.0",
6
6
  "author": "runcycles",
@@ -8,7 +8,7 @@
8
8
  "type": "git",
9
9
  "url": "https://github.com/runcycles/cycles-client-typescript.git"
10
10
  },
11
- "homepage": "https://github.com/runcycles/cycles-client-typescript#readme",
11
+ "homepage": "https://runcycles.io",
12
12
  "bugs": {
13
13
  "url": "https://github.com/runcycles/cycles-client-typescript/issues"
14
14
  },
@@ -20,7 +20,14 @@
20
20
  "api-client",
21
21
  "ai",
22
22
  "llm",
23
- "runcycles"
23
+ "runcycles",
24
+ "cost-control",
25
+ "governance",
26
+ "agents",
27
+ "anthropic",
28
+ "openai",
29
+ "token-budget",
30
+ "spend-limit"
24
31
  ],
25
32
  "type": "module",
26
33
  "main": "./dist/index.cjs",
@@ -56,14 +63,17 @@
56
63
  "prepublishOnly": "npm run lint && npm run build"
57
64
  },
58
65
  "devDependencies": {
59
- "@types/node": "^22.19.15",
60
- "@typescript-eslint/eslint-plugin": "^8.57.0",
61
- "@typescript-eslint/parser": "^8.57.0",
66
+ "@types/node": "^25.5.0",
67
+ "@typescript-eslint/eslint-plugin": "^8.58.0",
68
+ "@typescript-eslint/parser": "^8.58.0",
62
69
  "@vitest/coverage-v8": "^4.1.0",
70
+ "ajv": "^8.18.0",
71
+ "ajv-formats": "^3.0.1",
63
72
  "eslint": "^10.0.3",
64
73
  "tsup": "^8.0.0",
65
- "typescript": "^5.9.3",
66
- "vite": "^6.4.1",
67
- "vitest": "^4.1.0"
74
+ "typescript": "^6.0.2",
75
+ "vite": "^8.0.3",
76
+ "vitest": "^4.1.0",
77
+ "yaml": "^2.8.3"
68
78
  }
69
79
  }