tokmon 0.28.1 → 0.28.2

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.
@@ -739,243 +739,6 @@ function coalesceTables(list) {
739
739
  return mergeTables(list);
740
740
  }
741
741
 
742
- // src/rpc/contract.ts
743
- import { Schema } from "effect";
744
- import * as Rpc from "effect/unstable/rpc/Rpc";
745
- import * as RpcGroup from "effect/unstable/rpc/RpcGroup";
746
- var TOKMON_WS_PATH = "/ws";
747
- var TOKMON_PROTOCOL_VERSION = 3;
748
- var TOKMON_CAPABILITIES = ["config-cas", "config-revision", "allowed-hosts"];
749
- var TOKMON_WS_METHODS = {
750
- getConfig: "tokmon.getConfig",
751
- setConfig: "tokmon.setConfig",
752
- refresh: "tokmon.refresh",
753
- browseFs: "tokmon.browseFs",
754
- snapshot: "tokmon.snapshot",
755
- config: "tokmon.config"
756
- };
757
- var RefreshScopeSchema = Schema.Literals([
758
- "all",
759
- "summary",
760
- "table",
761
- "billing",
762
- "peak"
763
- ]);
764
- var ProviderIdSchema = Schema.Literals(PROVIDER_IDS);
765
- var NonNegativeIntegerSchema = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
766
- var PositiveFiniteSchema = Schema.Finite.check(Schema.isGreaterThanOrEqualTo(1));
767
- var AccountSchema = Schema.Struct({
768
- id: Schema.String,
769
- providerId: ProviderIdSchema,
770
- name: Schema.String,
771
- homeDir: Schema.String,
772
- color: Schema.optionalKey(Schema.String)
773
- });
774
- var ConfigSchema = Schema.Struct({
775
- revision: NonNegativeIntegerSchema,
776
- interval: PositiveFiniteSchema,
777
- billingInterval: PositiveFiniteSchema,
778
- clearScreen: Schema.Boolean,
779
- privacyMode: Schema.Boolean,
780
- privacyToggleKey: Schema.String,
781
- timezone: Schema.NullOr(Schema.String),
782
- accounts: Schema.Array(AccountSchema),
783
- activeAccountId: Schema.NullOr(Schema.String),
784
- disabledProviders: Schema.Array(ProviderIdSchema),
785
- onboarded: Schema.Boolean,
786
- dashboardLayout: Schema.Literals(["grid", "single"]),
787
- defaultFocus: Schema.Literals(["all", "last"]),
788
- ascii: Schema.Literals(["auto", "on", "off"]),
789
- allowNetworkAccess: Schema.Boolean,
790
- allowedHosts: Schema.Array(Schema.String),
791
- resetDisplay: Schema.Literals(["relative", "absolute"]),
792
- knownProviders: Schema.Array(ProviderIdSchema)
793
- });
794
- var ProtocolInfoSchema = Schema.Struct({
795
- version: Schema.Literal(TOKMON_PROTOCOL_VERSION),
796
- // Capabilities are additive within a protocol version. Older clients must
797
- // preserve forward compatibility when a newer daemon advertises one they do
798
- // not understand yet.
799
- capabilities: Schema.Array(Schema.String)
800
- });
801
- var ConfigStateSchema = Schema.Struct({
802
- protocol: ProtocolInfoSchema,
803
- config: ConfigSchema
804
- });
805
- var ConfigUpdateRequestSchema = Schema.Struct({
806
- expectedRevision: NonNegativeIntegerSchema,
807
- config: ConfigSchema
808
- });
809
- var ConfigUpdateConflictSchema = Schema.Struct({
810
- kind: Schema.Literal("conflict"),
811
- state: ConfigStateSchema
812
- });
813
- var ConfigPersistenceFailureSchema = Schema.Struct({
814
- kind: Schema.Literal("persistence"),
815
- message: Schema.String
816
- });
817
- var FsEntrySchema = Schema.Struct({
818
- name: Schema.String,
819
- path: Schema.String,
820
- dir: Schema.Boolean
821
- });
822
- var FsListingSchema = Schema.Struct({
823
- path: Schema.String,
824
- parent: Schema.NullOr(Schema.String),
825
- entries: Schema.Array(FsEntrySchema)
826
- });
827
- var UsageSummarySchema = Schema.Struct({
828
- cost: Schema.Finite,
829
- tokens: Schema.Finite,
830
- input: Schema.Finite,
831
- cacheRead: Schema.Finite,
832
- cacheSavings: Schema.Finite
833
- });
834
- var ModelDetailSchema = Schema.Struct({
835
- name: Schema.String,
836
- input: Schema.Finite,
837
- output: Schema.Finite,
838
- cacheCreate: Schema.Finite,
839
- cacheRead: Schema.Finite,
840
- cacheSavings: Schema.Finite,
841
- cost: Schema.Finite,
842
- count: Schema.Finite
843
- });
844
- var TableRowSchema = Schema.Struct({
845
- label: Schema.String,
846
- models: Schema.Array(Schema.String),
847
- input: Schema.Finite,
848
- output: Schema.Finite,
849
- cacheCreate: Schema.Finite,
850
- cacheRead: Schema.Finite,
851
- cacheSavings: Schema.Finite,
852
- total: Schema.Finite,
853
- cost: Schema.Finite,
854
- count: Schema.Finite,
855
- breakdown: Schema.Array(ModelDetailSchema)
856
- });
857
- var DashboardDataSchema = Schema.Struct({
858
- today: UsageSummarySchema,
859
- week: UsageSummarySchema,
860
- month: UsageSummarySchema,
861
- burnRate: Schema.Finite,
862
- series: Schema.Array(Schema.Finite)
863
- });
864
- var TableDataSchema = Schema.Struct({
865
- daily: Schema.Array(TableRowSchema),
866
- weekly: Schema.Array(TableRowSchema),
867
- monthly: Schema.Array(TableRowSchema)
868
- });
869
- var MetricFormatSchema = Schema.Union([
870
- Schema.Struct({ kind: Schema.Literal("percent") }),
871
- Schema.Struct({ kind: Schema.Literal("dollars"), currency: Schema.optionalKey(Schema.String) }),
872
- Schema.Struct({ kind: Schema.Literal("count"), suffix: Schema.optionalKey(Schema.String) })
873
- ]);
874
- var MetricSchema = Schema.Struct({
875
- label: Schema.String,
876
- used: Schema.Finite,
877
- limit: Schema.NullOr(Schema.Finite),
878
- format: MetricFormatSchema,
879
- resetsAt: Schema.optionalKey(Schema.NullOr(Schema.String)),
880
- primary: Schema.optionalKey(Schema.Boolean)
881
- });
882
- var BillingResultSchema = Schema.Struct({
883
- plan: Schema.NullOr(Schema.String),
884
- metrics: Schema.Array(MetricSchema),
885
- error: Schema.NullOr(Schema.String),
886
- email: Schema.optionalKey(Schema.NullOr(Schema.String)),
887
- displayName: Schema.optionalKey(Schema.NullOr(Schema.String)),
888
- activity: Schema.optionalKey(Schema.NullOr(Schema.Struct({
889
- series: Schema.Array(Schema.Finite),
890
- summary: Schema.String
891
- }))),
892
- modelSpend: Schema.optionalKey(Schema.NullOr(Schema.Array(Schema.Struct({
893
- name: Schema.String,
894
- usd: Schema.Finite,
895
- requests: Schema.Finite
896
- })))),
897
- asOfMs: Schema.optionalKey(Schema.Finite)
898
- });
899
- var WebAccountSchema = Schema.Struct({
900
- id: Schema.String,
901
- providerId: ProviderIdSchema,
902
- name: Schema.String,
903
- color: Schema.String,
904
- homeDir: Schema.NullOr(Schema.String),
905
- hasUsage: Schema.Boolean,
906
- hasBilling: Schema.Boolean,
907
- email: Schema.optionalKey(Schema.NullOr(Schema.String)),
908
- displayName: Schema.optionalKey(Schema.NullOr(Schema.String)),
909
- plan: Schema.optionalKey(Schema.NullOr(Schema.String)),
910
- dashboard: Schema.NullOr(DashboardDataSchema),
911
- table: Schema.NullOr(TableDataSchema),
912
- billing: Schema.NullOr(BillingResultSchema),
913
- summaryState: Schema.Literals(["pending", "ready", "error"]),
914
- billingState: Schema.Literals(["pending", "ready", "error"]),
915
- tableState: Schema.Literals(["pending", "ready", "error"]),
916
- summaryUpdatedAt: Schema.optionalKey(Schema.NullOr(NonNegativeIntegerSchema)),
917
- billingUpdatedAt: Schema.optionalKey(Schema.NullOr(NonNegativeIntegerSchema)),
918
- tableUpdatedAt: Schema.optionalKey(Schema.NullOr(NonNegativeIntegerSchema))
919
- });
920
- var WebSnapshotSchema = Schema.Struct({
921
- version: Schema.String,
922
- generatedAt: NonNegativeIntegerSchema,
923
- tz: Schema.String,
924
- intervalMs: PositiveFiniteSchema,
925
- billingIntervalMs: Schema.optionalKey(PositiveFiniteSchema),
926
- providers: Schema.Array(Schema.Struct({
927
- id: ProviderIdSchema,
928
- name: Schema.String,
929
- color: Schema.String
930
- })),
931
- accounts: Schema.Array(WebAccountSchema),
932
- seeded: Schema.Boolean,
933
- peak: Schema.NullOr(Schema.Struct({
934
- state: Schema.Literals(["peak", "off-peak", "weekend"]),
935
- label: Schema.String,
936
- // The upstream clock is only normalized to a finite number; do not make
937
- // the wire contract narrower than the producer's declared type.
938
- minutesUntilChange: Schema.NullOr(Schema.Finite),
939
- changesAt: Schema.optionalKey(Schema.NullOr(Schema.String))
940
- }))
941
- });
942
- var EmptyPayloadSchema = Schema.Struct({});
943
- var GetConfigRpc = Rpc.make(TOKMON_WS_METHODS.getConfig, {
944
- payload: EmptyPayloadSchema,
945
- success: ConfigStateSchema
946
- });
947
- var SetConfigRpc = Rpc.make(TOKMON_WS_METHODS.setConfig, {
948
- payload: ConfigUpdateRequestSchema,
949
- success: ConfigStateSchema,
950
- error: Schema.Union([ConfigUpdateConflictSchema, ConfigPersistenceFailureSchema])
951
- });
952
- var RefreshRpc = Rpc.make(TOKMON_WS_METHODS.refresh, {
953
- payload: Schema.Struct({ scope: RefreshScopeSchema }),
954
- success: Schema.Void
955
- });
956
- var BrowseFsRpc = Rpc.make(TOKMON_WS_METHODS.browseFs, {
957
- payload: Schema.Struct({ path: Schema.String }),
958
- success: FsListingSchema
959
- });
960
- var SnapshotRpc = Rpc.make(TOKMON_WS_METHODS.snapshot, {
961
- payload: EmptyPayloadSchema,
962
- success: WebSnapshotSchema,
963
- stream: true
964
- });
965
- var ConfigRpc = Rpc.make(TOKMON_WS_METHODS.config, {
966
- payload: EmptyPayloadSchema,
967
- success: ConfigStateSchema,
968
- stream: true
969
- });
970
- var TokmonRpcGroup = RpcGroup.make(
971
- GetConfigRpc,
972
- SetConfigRpc,
973
- RefreshRpc,
974
- BrowseFsRpc,
975
- SnapshotRpc,
976
- ConfigRpc
977
- );
978
-
979
742
  // src/shared/format.ts
980
743
  var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
981
744
  function formatCurrency(value, opts = {}) {
@@ -1727,13 +1490,14 @@ function timestampSecond(value) {
1727
1490
  const ts = timestampMs(value);
1728
1491
  return ts === null ? null : new Date(ts).toISOString().slice(0, 19);
1729
1492
  }
1730
- async function hasThreadSpawn(path) {
1493
+ async function hasForkedHistory(path) {
1731
1494
  let handle = null;
1732
1495
  try {
1733
1496
  handle = await openFile(path, "r");
1734
1497
  const buffer = Buffer.alloc(16 * 1024);
1735
1498
  const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
1736
- return buffer.subarray(0, bytesRead).includes("thread_spawn");
1499
+ const prefix = buffer.subarray(0, bytesRead).toString("utf8");
1500
+ return prefix.includes("thread_spawn") && /"forked_from_id"\s*:\s*"[^"]+"/.test(prefix);
1737
1501
  } catch {
1738
1502
  return false;
1739
1503
  } finally {
@@ -1741,32 +1505,11 @@ async function hasThreadSpawn(path) {
1741
1505
  });
1742
1506
  }
1743
1507
  }
1744
- async function detectReplaySecond(path) {
1745
- if (!await hasThreadSpawn(path)) return null;
1746
- let first = null;
1747
- const input = createReadStream2(path);
1748
- input.on("error", () => {
1749
- });
1750
- const rl = createInterface2({ input, crlfDelay: Infinity });
1751
- try {
1752
- for await (const rawLine of rl) {
1753
- if (!rawLine.includes("token_count")) continue;
1754
- try {
1755
- const line = rawLine.charCodeAt(0) === 65279 ? rawLine.slice(1) : rawLine;
1756
- const obj = JSON.parse(line);
1757
- if ((obj?.payload?.type ?? obj?.type) !== "token_count") continue;
1758
- const info = obj?.payload?.info;
1759
- if (!normalizeUsage(info?.last_token_usage) && !normalizeUsage(info?.total_token_usage)) continue;
1760
- const second = timestampSecond(obj.timestamp ?? obj?.payload?.timestamp);
1761
- if (!second) continue;
1762
- if (!first) first = second;
1763
- else return first === second ? second : null;
1764
- } catch {
1765
- }
1766
- }
1767
- } catch {
1768
- }
1769
- return null;
1508
+ function isLiveTaskStart(obj) {
1509
+ if ((obj?.payload?.type ?? obj?.type) !== "task_started") return false;
1510
+ const eventSecond = timestampSecond(obj?.timestamp ?? obj?.payload?.timestamp);
1511
+ const startedSecond = timestampSecond(obj?.payload?.started_at);
1512
+ return eventSecond !== null && eventSecond === startedSecond;
1770
1513
  }
1771
1514
  function findUsage(obj) {
1772
1515
  return normalizeUsage(obj?.usage) ?? normalizeUsage(obj?.payload?.usage) ?? normalizeUsage(obj?.payload?.info?.usage) ?? normalizeUsage(obj?.result?.usage) ?? normalizeUsage(obj?.response?.usage) ?? normalizeUsage(obj?.token_usage) ?? normalizeUsage(obj);
@@ -1779,19 +1522,22 @@ async function parseFile2(path) {
1779
1522
  let model = "gpt-5";
1780
1523
  let prevTotal = null;
1781
1524
  let prevSig = null;
1782
- const replaySecond = await detectReplaySecond(path);
1783
- let skipReplay = replaySecond !== null;
1525
+ let skipReplay = await hasForkedHistory(path);
1784
1526
  const input = createReadStream2(path);
1785
1527
  input.on("error", () => {
1786
1528
  });
1787
1529
  const rl = createInterface2({ input, crlfDelay: Infinity });
1788
1530
  try {
1789
1531
  for await (const rawLine of rl) {
1790
- if (!rawLine.includes("token_count") && !rawLine.includes("turn_context") && !rawLine.includes('"usage"') && !rawLine.includes("input_tokens") && !rawLine.includes("prompt_tokens")) continue;
1532
+ if (!rawLine.includes("token_count") && !rawLine.includes("task_started") && !rawLine.includes("turn_context") && !rawLine.includes('"usage"') && !rawLine.includes("input_tokens") && !rawLine.includes("prompt_tokens")) continue;
1791
1533
  try {
1792
1534
  const line = rawLine.charCodeAt(0) === 65279 ? rawLine.slice(1) : rawLine;
1793
1535
  const obj = JSON.parse(line);
1794
1536
  const payloadType = obj?.payload?.type ?? obj?.type;
1537
+ if (skipReplay) {
1538
+ if (isLiveTaskStart(obj)) skipReplay = false;
1539
+ continue;
1540
+ }
1795
1541
  if (payloadType === "turn_context") {
1796
1542
  const m2 = extractModel(obj);
1797
1543
  if (typeof m2 === "string" && m2.trim()) model = m2;
@@ -1827,14 +1573,6 @@ async function parseFile2(path) {
1827
1573
  const total = normalizeUsage(info?.total_token_usage);
1828
1574
  const last = normalizeUsage(info?.last_token_usage);
1829
1575
  const tsValue = obj.timestamp ?? obj?.payload?.timestamp;
1830
- if (skipReplay && replaySecond) {
1831
- const second = timestampSecond(tsValue);
1832
- if (second === replaySecond) {
1833
- if (total) prevTotal = total;
1834
- continue;
1835
- }
1836
- if (second) skipReplay = false;
1837
- }
1838
1576
  const sig = eventSig(last, total);
1839
1577
  if (sig === prevSig) continue;
1840
1578
  prevSig = sig;
@@ -4622,11 +4360,6 @@ async function detectProviders() {
4622
4360
  }
4623
4361
 
4624
4362
  export {
4625
- TOKMON_WS_PATH,
4626
- TOKMON_PROTOCOL_VERSION,
4627
- TOKMON_CAPABILITIES,
4628
- TOKMON_WS_METHODS,
4629
- TokmonRpcGroup,
4630
4363
  withTimeout,
4631
4364
  systemTimezone,
4632
4365
  resolveTimezone,
@@ -5,10 +5,10 @@ import {
5
5
  readLock,
6
6
  reclaimDeadLock,
7
7
  verifyLock
8
- } from "./chunk-XDA5RJST.js";
8
+ } from "./chunk-J3JW3RFP.js";
9
9
  import {
10
- appVersion
11
- } from "./chunk-SMPY52EV.js";
10
+ TOKMON_PROTOCOL_VERSION
11
+ } from "./chunk-WUK3MQUB.js";
12
12
 
13
13
  // src/client/daemon-handle.ts
14
14
  import { spawn } from "child_process";
@@ -37,7 +37,7 @@ function runtimeExecArgv(entry, override) {
37
37
  function parseHandshake(line) {
38
38
  try {
39
39
  const value = JSON.parse(line);
40
- return value?.ready === 1 && typeof value.url === "string" && typeof value.wsToken === "string" && typeof value.version === "string" ? value : null;
40
+ return value?.ready === 1 && typeof value.url === "string" && typeof value.wsToken === "string" && typeof value.version === "string" && typeof value.protocolVersion === "number" && Array.isArray(value.capabilities) && value.capabilities.every((capability) => typeof capability === "string") && (value.ownerKind === "cli" || value.ownerKind === "desktop") ? value : null;
41
41
  } catch {
42
42
  return null;
43
43
  }
@@ -46,18 +46,18 @@ function connected(url) {
46
46
  return { kind: "spawned", baseUrl: url, stop: () => {
47
47
  } };
48
48
  }
49
- async function attach(opts, version) {
50
- const lock = await verifyLock(readLock(opts), version);
49
+ async function attach(opts, protocolVersion) {
50
+ const lock = await verifyLock(readLock(opts), protocolVersion);
51
51
  return lock ? connected(lock.url) : null;
52
52
  }
53
53
  var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
54
- async function retireIncompatibleDaemon(opts, version, timeoutMs) {
54
+ async function retireIncompatibleDaemon(opts, protocolVersion, timeoutMs) {
55
55
  const lock = readLock(opts);
56
- if (!lock || lock.state !== "ready" || lock.version === version || lock.pid === process.pid || !isAlive(lock.pid)) return;
56
+ if (!lock || lock.state !== "ready" || lock.protocolVersion === protocolVersion || lock.ownerKind === "desktop" || lock.pid === process.pid || !isAlive(lock.pid)) return;
57
57
  const authenticated = await probeHealth(
58
58
  lock.url,
59
59
  lock.wsToken,
60
- lock.version,
60
+ lock,
61
61
  Math.min(1e3, timeoutMs)
62
62
  );
63
63
  if (!authenticated) return;
@@ -79,12 +79,12 @@ async function retireIncompatibleDaemon(opts, version, timeoutMs) {
79
79
  }
80
80
  }
81
81
  async function attachOrSpawn(opts = {}) {
82
- const version = appVersion();
82
+ const protocolVersion = TOKMON_PROTOCOL_VERSION;
83
83
  const timeoutMs = opts.timeoutMs ?? HANDSHAKE_TIMEOUT_MS;
84
- const existing = await attach(opts, version);
84
+ const existing = await attach(opts, protocolVersion);
85
85
  if (existing) return existing;
86
- await retireIncompatibleDaemon(opts, version, timeoutMs);
87
- const upgraded = await attach(opts, version);
86
+ await retireIncompatibleDaemon(opts, protocolVersion, timeoutMs);
87
+ const upgraded = await attach(opts, protocolVersion);
88
88
  if (upgraded) return upgraded;
89
89
  const entry = opts.entry ?? process.argv[1];
90
90
  if (!entry) return degraded();
@@ -117,7 +117,7 @@ async function attachOrSpawn(opts = {}) {
117
117
  resolve(handle);
118
118
  };
119
119
  const tryAttach = (final = false) => {
120
- void attach(opts, version).then((found) => {
120
+ void attach(opts, protocolVersion).then((found) => {
121
121
  if (found) {
122
122
  finish(found);
123
123
  return;
@@ -143,7 +143,7 @@ async function attachOrSpawn(opts = {}) {
143
143
  const line = stdout.slice(0, newline).trim();
144
144
  stdout = stdout.slice(newline + 1);
145
145
  const handshake = parseHandshake(line);
146
- if (!handshake || handshake.version !== version) continue;
146
+ if (!handshake || handshake.protocolVersion !== protocolVersion) continue;
147
147
  tryAttach();
148
148
  return;
149
149
  }
@@ -3,7 +3,7 @@ import {
3
3
  TOKMON_WS_METHODS,
4
4
  TOKMON_WS_PATH,
5
5
  TokmonRpcGroup
6
- } from "./chunk-CVKCVHS7.js";
6
+ } from "./chunk-WUK3MQUB.js";
7
7
 
8
8
  // src/client/daemon-rpc-client.ts
9
9
  import { Cause, Context, Duration, Effect, Exit, Fiber, Layer, ManagedRuntime, Schedule, Stream } from "effect";
@@ -0,0 +1,249 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ PROVIDER_IDS
4
+ } from "./chunk-HP5UZCXP.js";
5
+
6
+ // src/rpc/contract.ts
7
+ import { Schema } from "effect";
8
+ import * as Rpc from "effect/unstable/rpc/Rpc";
9
+ import * as RpcGroup from "effect/unstable/rpc/RpcGroup";
10
+ var TOKMON_WS_PATH = "/ws";
11
+ var TOKMON_PROTOCOL_VERSION = 3;
12
+ var TOKMON_CAPABILITIES = ["config-cas", "config-revision", "allowed-hosts"];
13
+ var TOKMON_WS_METHODS = {
14
+ getConfig: "tokmon.getConfig",
15
+ setConfig: "tokmon.setConfig",
16
+ refresh: "tokmon.refresh",
17
+ browseFs: "tokmon.browseFs",
18
+ snapshot: "tokmon.snapshot",
19
+ config: "tokmon.config"
20
+ };
21
+ var RefreshScopeSchema = Schema.Literals([
22
+ "all",
23
+ "summary",
24
+ "table",
25
+ "billing",
26
+ "peak"
27
+ ]);
28
+ var ProviderIdSchema = Schema.Literals(PROVIDER_IDS);
29
+ var NonNegativeIntegerSchema = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
30
+ var PositiveFiniteSchema = Schema.Finite.check(Schema.isGreaterThanOrEqualTo(1));
31
+ var AccountSchema = Schema.Struct({
32
+ id: Schema.String,
33
+ providerId: ProviderIdSchema,
34
+ name: Schema.String,
35
+ homeDir: Schema.String,
36
+ color: Schema.optionalKey(Schema.String)
37
+ });
38
+ var ConfigSchema = Schema.Struct({
39
+ revision: NonNegativeIntegerSchema,
40
+ interval: PositiveFiniteSchema,
41
+ billingInterval: PositiveFiniteSchema,
42
+ clearScreen: Schema.Boolean,
43
+ privacyMode: Schema.Boolean,
44
+ privacyToggleKey: Schema.String,
45
+ timezone: Schema.NullOr(Schema.String),
46
+ accounts: Schema.Array(AccountSchema),
47
+ activeAccountId: Schema.NullOr(Schema.String),
48
+ disabledProviders: Schema.Array(ProviderIdSchema),
49
+ onboarded: Schema.Boolean,
50
+ dashboardLayout: Schema.Literals(["grid", "single"]),
51
+ defaultFocus: Schema.Literals(["all", "last"]),
52
+ ascii: Schema.Literals(["auto", "on", "off"]),
53
+ allowNetworkAccess: Schema.Boolean,
54
+ allowedHosts: Schema.Array(Schema.String),
55
+ resetDisplay: Schema.Literals(["relative", "absolute"]),
56
+ knownProviders: Schema.Array(ProviderIdSchema)
57
+ });
58
+ var ProtocolInfoSchema = Schema.Struct({
59
+ version: Schema.Literal(TOKMON_PROTOCOL_VERSION),
60
+ // Capabilities are additive within a protocol version. Older clients must
61
+ // preserve forward compatibility when a newer daemon advertises one they do
62
+ // not understand yet.
63
+ capabilities: Schema.Array(Schema.String)
64
+ });
65
+ var ConfigStateSchema = Schema.Struct({
66
+ protocol: ProtocolInfoSchema,
67
+ config: ConfigSchema
68
+ });
69
+ var ConfigUpdateRequestSchema = Schema.Struct({
70
+ expectedRevision: NonNegativeIntegerSchema,
71
+ config: ConfigSchema
72
+ });
73
+ var ConfigUpdateConflictSchema = Schema.Struct({
74
+ kind: Schema.Literal("conflict"),
75
+ state: ConfigStateSchema
76
+ });
77
+ var ConfigPersistenceFailureSchema = Schema.Struct({
78
+ kind: Schema.Literal("persistence"),
79
+ message: Schema.String
80
+ });
81
+ var FsEntrySchema = Schema.Struct({
82
+ name: Schema.String,
83
+ path: Schema.String,
84
+ dir: Schema.Boolean
85
+ });
86
+ var FsListingSchema = Schema.Struct({
87
+ path: Schema.String,
88
+ parent: Schema.NullOr(Schema.String),
89
+ entries: Schema.Array(FsEntrySchema)
90
+ });
91
+ var UsageSummarySchema = Schema.Struct({
92
+ cost: Schema.Finite,
93
+ tokens: Schema.Finite,
94
+ input: Schema.Finite,
95
+ cacheRead: Schema.Finite,
96
+ cacheSavings: Schema.Finite
97
+ });
98
+ var ModelDetailSchema = Schema.Struct({
99
+ name: Schema.String,
100
+ input: Schema.Finite,
101
+ output: Schema.Finite,
102
+ cacheCreate: Schema.Finite,
103
+ cacheRead: Schema.Finite,
104
+ cacheSavings: Schema.Finite,
105
+ cost: Schema.Finite,
106
+ count: Schema.Finite
107
+ });
108
+ var TableRowSchema = Schema.Struct({
109
+ label: Schema.String,
110
+ models: Schema.Array(Schema.String),
111
+ input: Schema.Finite,
112
+ output: Schema.Finite,
113
+ cacheCreate: Schema.Finite,
114
+ cacheRead: Schema.Finite,
115
+ cacheSavings: Schema.Finite,
116
+ total: Schema.Finite,
117
+ cost: Schema.Finite,
118
+ count: Schema.Finite,
119
+ breakdown: Schema.Array(ModelDetailSchema)
120
+ });
121
+ var DashboardDataSchema = Schema.Struct({
122
+ today: UsageSummarySchema,
123
+ week: UsageSummarySchema,
124
+ month: UsageSummarySchema,
125
+ burnRate: Schema.Finite,
126
+ series: Schema.Array(Schema.Finite)
127
+ });
128
+ var TableDataSchema = Schema.Struct({
129
+ daily: Schema.Array(TableRowSchema),
130
+ weekly: Schema.Array(TableRowSchema),
131
+ monthly: Schema.Array(TableRowSchema)
132
+ });
133
+ var MetricFormatSchema = Schema.Union([
134
+ Schema.Struct({ kind: Schema.Literal("percent") }),
135
+ Schema.Struct({ kind: Schema.Literal("dollars"), currency: Schema.optionalKey(Schema.String) }),
136
+ Schema.Struct({ kind: Schema.Literal("count"), suffix: Schema.optionalKey(Schema.String) })
137
+ ]);
138
+ var MetricSchema = Schema.Struct({
139
+ label: Schema.String,
140
+ used: Schema.Finite,
141
+ limit: Schema.NullOr(Schema.Finite),
142
+ format: MetricFormatSchema,
143
+ resetsAt: Schema.optionalKey(Schema.NullOr(Schema.String)),
144
+ primary: Schema.optionalKey(Schema.Boolean)
145
+ });
146
+ var BillingResultSchema = Schema.Struct({
147
+ plan: Schema.NullOr(Schema.String),
148
+ metrics: Schema.Array(MetricSchema),
149
+ error: Schema.NullOr(Schema.String),
150
+ email: Schema.optionalKey(Schema.NullOr(Schema.String)),
151
+ displayName: Schema.optionalKey(Schema.NullOr(Schema.String)),
152
+ activity: Schema.optionalKey(Schema.NullOr(Schema.Struct({
153
+ series: Schema.Array(Schema.Finite),
154
+ summary: Schema.String
155
+ }))),
156
+ modelSpend: Schema.optionalKey(Schema.NullOr(Schema.Array(Schema.Struct({
157
+ name: Schema.String,
158
+ usd: Schema.Finite,
159
+ requests: Schema.Finite
160
+ })))),
161
+ asOfMs: Schema.optionalKey(Schema.Finite)
162
+ });
163
+ var WebAccountSchema = Schema.Struct({
164
+ id: Schema.String,
165
+ providerId: ProviderIdSchema,
166
+ name: Schema.String,
167
+ color: Schema.String,
168
+ homeDir: Schema.NullOr(Schema.String),
169
+ hasUsage: Schema.Boolean,
170
+ hasBilling: Schema.Boolean,
171
+ email: Schema.optionalKey(Schema.NullOr(Schema.String)),
172
+ displayName: Schema.optionalKey(Schema.NullOr(Schema.String)),
173
+ plan: Schema.optionalKey(Schema.NullOr(Schema.String)),
174
+ dashboard: Schema.NullOr(DashboardDataSchema),
175
+ table: Schema.NullOr(TableDataSchema),
176
+ billing: Schema.NullOr(BillingResultSchema),
177
+ summaryState: Schema.Literals(["pending", "ready", "error"]),
178
+ billingState: Schema.Literals(["pending", "ready", "error"]),
179
+ tableState: Schema.Literals(["pending", "ready", "error"]),
180
+ summaryUpdatedAt: Schema.optionalKey(Schema.NullOr(NonNegativeIntegerSchema)),
181
+ billingUpdatedAt: Schema.optionalKey(Schema.NullOr(NonNegativeIntegerSchema)),
182
+ tableUpdatedAt: Schema.optionalKey(Schema.NullOr(NonNegativeIntegerSchema))
183
+ });
184
+ var WebSnapshotSchema = Schema.Struct({
185
+ version: Schema.String,
186
+ generatedAt: NonNegativeIntegerSchema,
187
+ tz: Schema.String,
188
+ intervalMs: PositiveFiniteSchema,
189
+ billingIntervalMs: Schema.optionalKey(PositiveFiniteSchema),
190
+ providers: Schema.Array(Schema.Struct({
191
+ id: ProviderIdSchema,
192
+ name: Schema.String,
193
+ color: Schema.String
194
+ })),
195
+ accounts: Schema.Array(WebAccountSchema),
196
+ seeded: Schema.Boolean,
197
+ peak: Schema.NullOr(Schema.Struct({
198
+ state: Schema.Literals(["peak", "off-peak", "weekend"]),
199
+ label: Schema.String,
200
+ // The upstream clock is only normalized to a finite number; do not make
201
+ // the wire contract narrower than the producer's declared type.
202
+ minutesUntilChange: Schema.NullOr(Schema.Finite),
203
+ changesAt: Schema.optionalKey(Schema.NullOr(Schema.String))
204
+ }))
205
+ });
206
+ var EmptyPayloadSchema = Schema.Struct({});
207
+ var GetConfigRpc = Rpc.make(TOKMON_WS_METHODS.getConfig, {
208
+ payload: EmptyPayloadSchema,
209
+ success: ConfigStateSchema
210
+ });
211
+ var SetConfigRpc = Rpc.make(TOKMON_WS_METHODS.setConfig, {
212
+ payload: ConfigUpdateRequestSchema,
213
+ success: ConfigStateSchema,
214
+ error: Schema.Union([ConfigUpdateConflictSchema, ConfigPersistenceFailureSchema])
215
+ });
216
+ var RefreshRpc = Rpc.make(TOKMON_WS_METHODS.refresh, {
217
+ payload: Schema.Struct({ scope: RefreshScopeSchema }),
218
+ success: Schema.Void
219
+ });
220
+ var BrowseFsRpc = Rpc.make(TOKMON_WS_METHODS.browseFs, {
221
+ payload: Schema.Struct({ path: Schema.String }),
222
+ success: FsListingSchema
223
+ });
224
+ var SnapshotRpc = Rpc.make(TOKMON_WS_METHODS.snapshot, {
225
+ payload: EmptyPayloadSchema,
226
+ success: WebSnapshotSchema,
227
+ stream: true
228
+ });
229
+ var ConfigRpc = Rpc.make(TOKMON_WS_METHODS.config, {
230
+ payload: EmptyPayloadSchema,
231
+ success: ConfigStateSchema,
232
+ stream: true
233
+ });
234
+ var TokmonRpcGroup = RpcGroup.make(
235
+ GetConfigRpc,
236
+ SetConfigRpc,
237
+ RefreshRpc,
238
+ BrowseFsRpc,
239
+ SnapshotRpc,
240
+ ConfigRpc
241
+ );
242
+
243
+ export {
244
+ TOKMON_WS_PATH,
245
+ TOKMON_PROTOCOL_VERSION,
246
+ TOKMON_CAPABILITIES,
247
+ TOKMON_WS_METHODS,
248
+ TokmonRpcGroup
249
+ };