@uxnan/shared 0.0.20-alpha.20260926 → 0.0.22-alpha.20260927

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
@@ -13,7 +13,7 @@ equivalents (see
13
13
  [`architecture/02b-contracts-and-requirements.md`](../architecture/02b-contracts-and-requirements.md)
14
14
  §1 for the canonical contract list).
15
15
 
16
- > **Status:** implemented and stable — **83 JSON-RPC methods** + **22 streaming
16
+ > **Status:** implemented and stable — **87 JSON-RPC methods** + **22 streaming
17
17
  > notifications**, kept lock-step at build time with the `METHOD_NAMES` array and
18
18
  > the `StreamNotification` enum (a compile-time assertion in
19
19
  > `src/jsonrpc/method-registry.ts` fails the build on any drift). Changes are
@@ -3,5 +3,5 @@
3
3
  * compile-time {@link JsonRpcMethodRegistry} via the assertion below.
4
4
  */
5
5
  import type { JsonRpcMethodName } from './methods.js';
6
- export declare const METHOD_NAMES: readonly ["thread/list", "thread/read", "thread/start", "thread/resume", "thread/fork", "thread/setModel", "thread/rename", "thread/setAccessMode", "thread/archive", "thread/unarchive", "thread/delete", "turn/list", "turn/read", "turn/send", "turn/cancel", "queue/resume", "queue/clear", "git/status", "git/diff", "git/commit", "git/push", "git/pull", "git/checkout", "git/createBranch", "git/createWorktree", "git/stage", "git/unstage", "git/discard", "git/createPr", "git/undoCommit", "git/branches", "git/switchBranch", "git/revert", "git/deleteBranch", "git/removeWorktree", "git/worktrees", "git/log", "git/commitShow", "workspace/readFile", "workspace/readImage", "workspace/list", "workspace/searchFiles", "workspace/resolveFileLink", "workspace/browseDirs", "workspace/checkpoint", "workspace/diffCheckpoint", "workspace/applyCheckpoint", "workspace/applyPatch", "workspace/exists", "project/list", "project/resolve", "project/add", "project/remove", "project/rename", "sync/changes", "settings/get", "settings/set", "device/describe", "device/rename", "agent/list", "agent/models", "agent/commands", "agent/usageStats", "agent/doctor", "metrics/get", "metrics/export", "metrics/import", "auth/status", "auth/login", "auth/logout", "notifications/register", "notifications/update", "notifications/unregister", "bridge/status", "bridge/generatePairingQr", "bridge/connectedPhones", "bridge/disconnectPhone", "bridge/trustedDevices", "bridge/removeTrustedDevice", "bridge/update", "bridge/checkForUpdate", "desktop/attach", "desktop/detach"];
6
+ export declare const METHOD_NAMES: readonly ["thread/list", "thread/read", "thread/start", "thread/resume", "thread/fork", "thread/setModel", "thread/rename", "thread/setAccessMode", "thread/archive", "thread/unarchive", "thread/delete", "turn/list", "turn/read", "turn/send", "turn/cancel", "turn/attachment", "queue/resume", "queue/clear", "queue/sendNow", "git/status", "git/diff", "git/commit", "git/push", "git/pull", "git/checkout", "git/createBranch", "git/createWorktree", "git/stage", "git/unstage", "git/discard", "git/createPr", "git/undoCommit", "git/branches", "git/switchBranch", "git/revert", "git/deleteBranch", "git/removeWorktree", "git/worktrees", "git/log", "git/commitShow", "workspace/readFile", "workspace/readImage", "workspace/list", "workspace/searchFiles", "workspace/resolveFileLink", "workspace/browseDirs", "workspace/checkpoint", "workspace/diffCheckpoint", "workspace/applyCheckpoint", "workspace/applyPatch", "workspace/exists", "project/list", "project/resolve", "project/add", "project/remove", "project/rename", "sync/changes", "settings/get", "settings/set", "device/describe", "device/rename", "agent/list", "agent/models", "agent/commands", "agent/usageStats", "usage/redeemReset", "usage/summary", "agent/doctor", "metrics/get", "metrics/export", "metrics/import", "auth/status", "auth/login", "auth/logout", "notifications/register", "notifications/update", "notifications/unregister", "bridge/status", "bridge/generatePairingQr", "bridge/connectedPhones", "bridge/disconnectPhone", "bridge/trustedDevices", "bridge/removeTrustedDevice", "bridge/update", "bridge/checkForUpdate", "desktop/attach", "desktop/detach"];
7
7
  export declare function isKnownMethod(method: string): method is JsonRpcMethodName;
@@ -15,9 +15,11 @@ export const METHOD_NAMES = [
15
15
  'turn/read',
16
16
  'turn/send',
17
17
  'turn/cancel',
18
+ 'turn/attachment',
18
19
  // Message queue
19
20
  'queue/resume',
20
21
  'queue/clear',
22
+ 'queue/sendNow',
21
23
  // Git
22
24
  'git/status',
23
25
  'git/diff',
@@ -69,6 +71,8 @@ export const METHOD_NAMES = [
69
71
  'agent/models',
70
72
  'agent/commands',
71
73
  'agent/usageStats',
74
+ 'usage/redeemReset',
75
+ 'usage/summary',
72
76
  'agent/doctor',
73
77
  // Metrics (bridge-owned, survivable profile stats + tamper-proof backup)
74
78
  'metrics/get',
@@ -1 +1 @@
1
- {"version":3,"file":"method-registry.js","sourceRoot":"","sources":["../../../src/jsonrpc/method-registry.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,kBAAkB;IAClB,aAAa;IACb,aAAa;IACb,cAAc;IACd,eAAe;IACf,aAAa;IACb,iBAAiB;IACjB,eAAe;IACf,sBAAsB;IACtB,gBAAgB;IAChB,kBAAkB;IAClB,eAAe;IACf,WAAW;IACX,WAAW;IACX,WAAW;IACX,aAAa;IACb,gBAAgB;IAChB,cAAc;IACd,aAAa;IACb,MAAM;IACN,YAAY;IACZ,UAAU;IACV,YAAY;IACZ,UAAU;IACV,UAAU;IACV,cAAc;IACd,kBAAkB;IAClB,oBAAoB;IACpB,WAAW;IACX,aAAa;IACb,aAAa;IACb,cAAc;IACd,gBAAgB;IAChB,cAAc;IACd,kBAAkB;IAClB,YAAY;IACZ,kBAAkB;IAClB,oBAAoB;IACpB,eAAe;IACf,SAAS;IACT,gBAAgB;IAChB,YAAY;IACZ,oBAAoB;IACpB,qBAAqB;IACrB,gBAAgB;IAChB,uBAAuB;IACvB,2BAA2B;IAC3B,sBAAsB;IACtB,sBAAsB;IACtB,0BAA0B;IAC1B,2BAA2B;IAC3B,sBAAsB;IACtB,kBAAkB;IAClB,WAAW;IACX,cAAc;IACd,iBAAiB;IACjB,aAAa;IACb,gBAAgB;IAChB,gBAAgB;IAChB,mCAAmC;IACnC,cAAc;IACd,cAAc;IACd,cAAc;IACd,iBAAiB;IACjB,eAAe;IACf,SAAS;IACT,YAAY;IACZ,cAAc;IACd,gBAAgB;IAChB,kBAAkB;IAClB,cAAc;IACd,yEAAyE;IACzE,aAAa;IACb,gBAAgB;IAChB,gBAAgB;IAChB,OAAO;IACP,aAAa;IACb,YAAY;IACZ,aAAa;IACb,uBAAuB;IACvB,wBAAwB;IACxB,sBAAsB;IACtB,0BAA0B;IAC1B,iBAAiB;IACjB,eAAe;IACf,0BAA0B;IAC1B,wBAAwB;IACxB,wBAAwB;IACxB,uBAAuB;IACvB,4BAA4B;IAC5B,eAAe;IACf,uBAAuB;IACvB,mEAAmE;IACnE,gBAAgB;IAChB,gBAAgB;CACR,CAAC;AAQX,MAAM,sBAAsB,GAAqB,IAAI,CAAC;AACtD,MAAM,sBAAsB,GAAqB,IAAI,CAAC;AACtD,KAAK,sBAAsB,CAAC;AAC5B,KAAK,sBAAsB,CAAC;AAE5B,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;AAEnE,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,OAAO,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC"}
1
+ {"version":3,"file":"method-registry.js","sourceRoot":"","sources":["../../../src/jsonrpc/method-registry.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,kBAAkB;IAClB,aAAa;IACb,aAAa;IACb,cAAc;IACd,eAAe;IACf,aAAa;IACb,iBAAiB;IACjB,eAAe;IACf,sBAAsB;IACtB,gBAAgB;IAChB,kBAAkB;IAClB,eAAe;IACf,WAAW;IACX,WAAW;IACX,WAAW;IACX,aAAa;IACb,iBAAiB;IACjB,gBAAgB;IAChB,cAAc;IACd,aAAa;IACb,eAAe;IACf,MAAM;IACN,YAAY;IACZ,UAAU;IACV,YAAY;IACZ,UAAU;IACV,UAAU;IACV,cAAc;IACd,kBAAkB;IAClB,oBAAoB;IACpB,WAAW;IACX,aAAa;IACb,aAAa;IACb,cAAc;IACd,gBAAgB;IAChB,cAAc;IACd,kBAAkB;IAClB,YAAY;IACZ,kBAAkB;IAClB,oBAAoB;IACpB,eAAe;IACf,SAAS;IACT,gBAAgB;IAChB,YAAY;IACZ,oBAAoB;IACpB,qBAAqB;IACrB,gBAAgB;IAChB,uBAAuB;IACvB,2BAA2B;IAC3B,sBAAsB;IACtB,sBAAsB;IACtB,0BAA0B;IAC1B,2BAA2B;IAC3B,sBAAsB;IACtB,kBAAkB;IAClB,WAAW;IACX,cAAc;IACd,iBAAiB;IACjB,aAAa;IACb,gBAAgB;IAChB,gBAAgB;IAChB,mCAAmC;IACnC,cAAc;IACd,cAAc;IACd,cAAc;IACd,iBAAiB;IACjB,eAAe;IACf,SAAS;IACT,YAAY;IACZ,cAAc;IACd,gBAAgB;IAChB,kBAAkB;IAClB,mBAAmB;IACnB,eAAe;IACf,cAAc;IACd,yEAAyE;IACzE,aAAa;IACb,gBAAgB;IAChB,gBAAgB;IAChB,OAAO;IACP,aAAa;IACb,YAAY;IACZ,aAAa;IACb,uBAAuB;IACvB,wBAAwB;IACxB,sBAAsB;IACtB,0BAA0B;IAC1B,iBAAiB;IACjB,eAAe;IACf,0BAA0B;IAC1B,wBAAwB;IACxB,wBAAwB;IACxB,uBAAuB;IACvB,4BAA4B;IAC5B,eAAe;IACf,uBAAuB;IACvB,mEAAmE;IACnE,gBAAgB;IAChB,gBAAgB;CACR,CAAC;AAQX,MAAM,sBAAsB,GAAqB,IAAI,CAAC;AACtD,MAAM,sBAAsB,GAAqB,IAAI,CAAC;AACtD,KAAK,sBAAsB,CAAC;AAC5B,KAAK,sBAAsB,CAAC;AAE5B,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;AAEnE,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,OAAO,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC"}
@@ -15,7 +15,7 @@ import type { QuestionResponse } from '../models/question.js';
15
15
  import type { BridgeStatus, BridgeUpdate, ConnectedPhone, DeviceDescribeParams, DeviceDescription, DeviceRenameParams, TrustedDevice } from '../models/session.js';
16
16
  import type { PairingPayload } from '../e2ee/pairing-payload.js';
17
17
  import type { AgentCommand, AgentCommandInvocation, AgentDescriptor, AgentDiagnosis, AgentId, AgentModel } from '../agents/agent-capabilities.js';
18
- import type { UsageStatsParams, UsageStatsResult } from '../models/usage.js';
18
+ import type { ProviderUsage, UsageRedeemResetParams, UsageStatsParams, UsageStatsResult, UsageSummary, UsageSummaryParams } from '../models/usage.js';
19
19
  import type { MetricsExportParams, MetricsExportResult, MetricsImportParams, MetricsImportResult, MetricsSnapshot } from '../models/metrics.js';
20
20
  import type { PushPlatform } from '../notifications/push-payload.js';
21
21
  import type { DesktopAttachParams, DesktopAttachResult } from '../local-control/local-control.js';
@@ -47,6 +47,17 @@ export interface TurnListParams {
47
47
  */
48
48
  fromEnd?: boolean;
49
49
  }
50
+ /** `turn/attachment`: one image a user message carries (`Message.attachments`). */
51
+ export interface TurnAttachmentParams {
52
+ threadId: string;
53
+ attachmentId: string;
54
+ }
55
+ /** The image's bytes, as they were sent. */
56
+ export interface TurnAttachmentData {
57
+ mimeType: string;
58
+ /** Base64 payload (no `data:` URI prefix). */
59
+ base64Data: string;
60
+ }
50
61
  export interface TurnSendParams {
51
62
  threadId: string;
52
63
  /**
@@ -421,6 +432,11 @@ export interface JsonRpcMethodRegistry {
421
432
  };
422
433
  result: void;
423
434
  };
435
+ /** The bytes of an image a user message carries (`Message.attachments`). */
436
+ 'turn/attachment': {
437
+ params: TurnAttachmentParams;
438
+ result: TurnAttachmentData;
439
+ };
424
440
  /** Resumes draining after a stop/failure held the queue. */
425
441
  'queue/resume': {
426
442
  params: {
@@ -435,6 +451,19 @@ export interface JsonRpcMethodRegistry {
435
451
  };
436
452
  result: QueueStateResult;
437
453
  };
454
+ /**
455
+ * Sends one queued message now: into the running turn when its agent takes
456
+ * input mid-turn (`capabilities.steering`), else — nothing running — as the
457
+ * next turn at once, through a pause. Refused while a turn runs whose agent
458
+ * cannot take it, or the agent waits on the person's answer.
459
+ */
460
+ 'queue/sendNow': {
461
+ params: {
462
+ threadId: string;
463
+ turnId: string;
464
+ };
465
+ result: QueueStateResult;
466
+ };
438
467
  'git/status': {
439
468
  params: {
440
469
  cwd: string;
@@ -645,6 +674,16 @@ export interface JsonRpcMethodRegistry {
645
674
  params: UsageStatsParams;
646
675
  result: UsageStatsResult;
647
676
  };
677
+ /** Redeem a rate-limit reset (Codex); answers the provider's fresh usage. */
678
+ 'usage/redeemReset': {
679
+ params: UsageRedeemResetParams;
680
+ result: ProviderUsage;
681
+ };
682
+ /** Tokens and cost the agent CLIs on this PC spent, by day, agent and model. */
683
+ 'usage/summary': {
684
+ params: UsageSummaryParams;
685
+ result: UsageSummary;
686
+ };
648
687
  'agent/doctor': {
649
688
  params: void;
650
689
  result: {
@@ -7,7 +7,7 @@
7
7
  * were derived on the phone from local storage and so were lost on an app
8
8
  * uninstall (the app has no cloud login). To make them durable, the **bridge**
9
9
  * becomes the source of truth: it persists a complete activity ledger
10
- * (conversations, turns/messages, reported tokens, sessions and Git actions)
10
+ * (conversations, turns/messages, sessions and Git actions)
11
11
  * and serves it over `metrics/get`. Deleting mutable conversation history does
12
12
  * not subtract activity. The phone renders one snapshot per PC and sums PCs.
13
13
  *
@@ -16,8 +16,10 @@
16
16
  * keychain), so users cannot fabricate or edit their stats; `metrics/import`
17
17
  * feeds one back and merges its events by id (idempotent).
18
18
  *
19
- * Provider usage/credits are deliberately NOT part of this — those are read live
20
- * via `agent/usageStats` and never persisted.
19
+ * What the agents spent (tokens, cost) and provider limits are deliberately NOT
20
+ * part of this: `usage/summary` reads spend from each CLI's own history (every
21
+ * session, not only the bridge's) and `agent/usageStats` asks for limits live.
22
+ * The development `echo` agent is never counted.
21
23
  *
22
24
  * Source: architecture/02a-system-architecture.md §5.8.11 and
23
25
  * 02b-contracts-and-requirements.md.
@@ -39,19 +41,12 @@ export interface MetricsAgentDay {
39
41
  conversations: number;
40
42
  /** Messages exchanged that day in this agent's threads. */
41
43
  messages: number;
42
- /**
43
- * Tokens processed that day — the sum of each turn's reported usage (input
44
- * incl. the re-sent context + output). **Throughput, not billed cost**: caching
45
- * and input/output pricing differ (use `agent/usageStats` for money). 0 for
46
- * agents that don't report usage (e.g. Zero).
47
- */
48
- tokens: number;
49
44
  }
50
45
  /** One calendar day's activity split per agent. */
51
46
  export interface MetricsDayBreakdown {
52
47
  /** UTC-midnight epoch ms of the calendar date (same encoding as `activity`). */
53
48
  day: number;
54
- /** Per-agent activity that day (agents with any conversation/message/token). */
49
+ /** Per-agent activity that day (agents with any conversation or message). */
55
50
  byAgent: MetricsAgentDay[];
56
51
  }
57
52
  /**
@@ -112,7 +107,7 @@ export interface MetricsSnapshot {
112
107
  /** Per-day activity buckets for the contribution heatmap. */
113
108
  activity: MetricsActivityDay[];
114
109
  /**
115
- * Per-day activity split per agent (conversations, messages, tokens), for the
110
+ * Per-day activity split per agent (conversations, messages), for the
116
111
  * unified agent-activity view: the per-agent bars show all-time totals, or a
117
112
  * single day's totals when a heatmap cell is selected. See
118
113
  * {@link MetricsAgentDay}.
@@ -7,7 +7,7 @@
7
7
  * were derived on the phone from local storage and so were lost on an app
8
8
  * uninstall (the app has no cloud login). To make them durable, the **bridge**
9
9
  * becomes the source of truth: it persists a complete activity ledger
10
- * (conversations, turns/messages, reported tokens, sessions and Git actions)
10
+ * (conversations, turns/messages, sessions and Git actions)
11
11
  * and serves it over `metrics/get`. Deleting mutable conversation history does
12
12
  * not subtract activity. The phone renders one snapshot per PC and sums PCs.
13
13
  *
@@ -16,8 +16,10 @@
16
16
  * keychain), so users cannot fabricate or edit their stats; `metrics/import`
17
17
  * feeds one back and merges its events by id (idempotent).
18
18
  *
19
- * Provider usage/credits are deliberately NOT part of this — those are read live
20
- * via `agent/usageStats` and never persisted.
19
+ * What the agents spent (tokens, cost) and provider limits are deliberately NOT
20
+ * part of this: `usage/summary` reads spend from each CLI's own history (every
21
+ * session, not only the bridge's) and `agent/usageStats` asks for limits live.
22
+ * The development `echo` agent is never counted.
21
23
  *
22
24
  * Source: architecture/02a-system-architecture.md §5.8.11 and
23
25
  * 02b-contracts-and-requirements.md.
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../src/models/metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../src/models/metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG"}
@@ -64,8 +64,30 @@ export interface Message {
64
64
  tokens: number;
65
65
  contextWindow?: number;
66
66
  };
67
+ /**
68
+ * The images and files the user attached to this message, kept by the bridge
69
+ * with the turn (user messages only). They are named here, not inlined — a page of
70
+ * history stays small — and each client fetches the bytes it shows with
71
+ * `turn/attachment`.
72
+ */
73
+ attachments?: MessageAttachment[];
67
74
  createdAt: number;
68
75
  }
76
+ /** An image or a file attached to a user message, as `turn/list` names it. */
77
+ export interface MessageAttachment {
78
+ /** Opaque id, unique in its thread; the key for `turn/attachment`. */
79
+ id: string;
80
+ /** MIME type, e.g. `image/png`. */
81
+ mimeType: string;
82
+ /** Size of the stored image or file in bytes. */
83
+ bytes: number;
84
+ /** A file's name, as it was sent (absent for an image). */
85
+ name?: string;
86
+ /** Pixel width, when the sender knew it. */
87
+ width?: number;
88
+ /** Pixel height, when the sender knew it. */
89
+ height?: number;
90
+ }
69
91
  /**
70
92
  * One exchange: at most one user message (absent when the agent spoke on its
71
93
  * own) and ONE assistant message, whose `segments` carry its prose and steps
@@ -1,21 +1,17 @@
1
1
  /**
2
- * AI-provider usage statistics: quota/rate windows, plan/account, credit
3
- * balance and local token tallies read from a coding CLI's on-disk state — its
4
- * stored OAuth token (→ the provider's official usage API) and/or its local
5
- * session logs.
2
+ * AI-provider usage: plan limits (quota windows, plan, account, credit) and
3
+ * spend (tokens and cost by day, agent and model).
6
4
  *
7
- * Surfaced in the desktop's Settings → Providers section and, over the bridge,
8
- * on the phone. The access path is per-runtime by design (02a §5.8.10): the
9
- * desktop reads these files natively in Rust; the bridge reads them in TS so a
10
- * paired phone — which cannot see the PC's disk directly — gets the same data
11
- * over `agent/usageStats`. The Dart equivalents live in uxnanmobile and are kept
12
- * in sync manually (see 02e-bridge-integration.md §4.2).
13
- *
14
- * Posture: only the token the CLI itself stored is read — from its file, or
15
- * from the OS credential store where that is where the CLI keeps it (Claude
16
- * Code on macOS), and then only after the user has granted the OS-level
17
- * permission once (see `accessRequired`). Never browser cookies, never
18
- * user-pasted API keys, never a refresh token.
5
+ * The bridge is the one reader; every client — the phone, Uxnan Desktop's
6
+ * Providers panel — asks it (`agent/usageStats`, `usage/summary`,
7
+ * `usage/redeemReset`). Claude Code and Codex are asked themselves: each CLI
8
+ * answers for the account it is signed in to, so no credential is read and no
9
+ * OS permission is needed. Copilot and Grok have no such surface: only the
10
+ * token each CLI stored is read (`gh auth token`, `~/.grok/auth.json`) and sent
11
+ * to the provider's own usage API. Spend comes from the transcripts every
12
+ * agent CLI keeps on disk. Never browser cookies, never a pasted key, never a
13
+ * refresh token. The Dart equivalents live in uxnanmobile and are kept in sync
14
+ * manually.
19
15
  */
20
16
  /** A coding CLI whose usage we read from its own stored token. */
21
17
  export type UsageProvider = 'codex' | 'claude' | 'copilot' | 'grok';
@@ -25,18 +21,13 @@ export type UsageStatus =
25
21
  'ok'
26
22
  /** CLI is present but not signed in (no usable token). */
27
23
  | 'authRequired'
28
- /** The CLI's token exists in the OS credential store, but the OS has not yet
29
- * authorized the reader to open it. The user grants that once from the
30
- * desktop's Providers panel (the OS shows its own dialog); the reader never
31
- * prompts on its own. A phone shows "grant access on the PC". */
32
- | 'accessRequired'
33
24
  /** CLI / its config directory is not present on this machine. */
34
25
  | 'notInstalled'
35
26
  /** Read/network/parse failure — see {@link ProviderUsage.message}. */
36
27
  | 'error';
37
- /** How the data was obtained, for the UI's provenance label. Every wired
38
- * provider reads its quota from the CLI's own signed-in token. */
39
- export type UsageSource = 'token';
28
+ /** How the data was obtained: asked of the CLI itself (`cli`, Claude Code and
29
+ * Codex), or its stored token sent to the provider's usage API (`token`). */
30
+ export type UsageSource = 'cli' | 'token';
40
31
  /**
41
32
  * The kind of billing relationship, so the UI can label an account beyond its
42
33
  * plan name (e.g. distinguish a flat subscription from usage/credit billing).
@@ -94,6 +85,8 @@ export interface CreditBalance {
94
85
  */
95
86
  /** One redeemable reset — for the per-credit detail (which one, when it expires). */
96
87
  export interface ResetCreditEntry {
88
+ /** The provider's id for this reset, to redeem exactly it (`usage/redeemReset`). */
89
+ id?: string;
97
90
  /** Short label the provider gives the reset (e.g. "Full reset"). */
98
91
  title?: string;
99
92
  /** When this reset lapses (epoch ms). */
@@ -129,8 +122,7 @@ export interface ProviderUsage {
129
122
  resetCredits?: ResetCredits;
130
123
  /** When this snapshot was produced (epoch ms). */
131
124
  updatedAt: number;
132
- /** Error/hint message for `error` / `authRequired` / `accessRequired` /
133
- * `notInstalled` states. */
125
+ /** Error/hint message for `error` / `authRequired` / `notInstalled` states. */
134
126
  message?: string;
135
127
  }
136
128
  /**
@@ -144,3 +136,77 @@ export interface UsageStatsParams {
144
136
  export interface UsageStatsResult {
145
137
  usage: ProviderUsage[];
146
138
  }
139
+ /**
140
+ * `usage/redeemReset` request: redeem one of a provider's rate-limit resets
141
+ * (Codex today) — [creditId] from `ResetCredits.entries`, or the
142
+ * soonest-expiring one when absent. [idempotencyKey] names the attempt, so a
143
+ * retry after a lost answer never redeems twice.
144
+ */
145
+ export interface UsageRedeemResetParams {
146
+ provider: UsageProvider;
147
+ idempotencyKey: string;
148
+ creditId?: string;
149
+ }
150
+ /**
151
+ * `usage/summary` request: the last [days] calendar days of this PC (today
152
+ * included), 1–366.
153
+ */
154
+ export interface UsageSummaryParams {
155
+ days: number;
156
+ }
157
+ /** Tokens and cost of a set of model responses. */
158
+ export interface UsageSpend {
159
+ /** Input not read from the cache. */
160
+ inputTokens: number;
161
+ /** Input read from the cache. */
162
+ cachedInputTokens: number;
163
+ /** Input written to the cache. */
164
+ cacheWriteTokens: number;
165
+ /** Output, reasoning included. */
166
+ outputTokens: number;
167
+ /** The reasoning part of `outputTokens`, where the CLI records it. */
168
+ reasoningTokens: number;
169
+ /** US dollars: what the provider billed where the CLI records it, else the
170
+ * estimate at API prices (`estimatedCostUsd` of it). */
171
+ costUsd: number;
172
+ /** The part of `costUsd` estimated at API prices (on a subscription, what
173
+ * the same work would cost pay-as-you-go). */
174
+ estimatedCostUsd: number;
175
+ /** Tokens of responses whose model has no known price — not in `costUsd`. */
176
+ unpricedTokens: number;
177
+ /** Model responses counted. */
178
+ responses: number;
179
+ }
180
+ /** One agent + model's spend on one day. */
181
+ export interface UsageBucket extends UsageSpend {
182
+ /** Wire agent id (`claude-code`, `codex`, `pi-agent`, `grok`, `opencode`). */
183
+ agentId: string;
184
+ /** The model id as the CLI recorded it (`provider/model` where it routes). */
185
+ model: string;
186
+ }
187
+ /** One calendar day of this PC. */
188
+ export interface UsageDay {
189
+ /** `YYYY-MM-DD`, the PC's local date. */
190
+ day: string;
191
+ buckets: UsageBucket[];
192
+ }
193
+ /** What was found for one agent. */
194
+ export interface UsageAgentSource {
195
+ agentId: string;
196
+ /** Sessions with spend in the period. */
197
+ sessions: number;
198
+ /** `ok`: read (possibly nothing in the period); `unreadable`: its store
199
+ * exists but could not be read (see `message`). Agents with no store on
200
+ * this PC are not listed. */
201
+ status: 'ok' | 'unreadable';
202
+ message?: string;
203
+ }
204
+ /**
205
+ * `usage/summary` result: every model response the agent CLIs on this PC
206
+ * recorded in the period — the bridge's turns and a person's own terminal
207
+ * sessions alike — by day, agent and model. Only days with spend are listed.
208
+ */
209
+ export interface UsageSummary {
210
+ days: UsageDay[];
211
+ agents: UsageAgentSource[];
212
+ }
@@ -1,21 +1,17 @@
1
1
  /**
2
- * AI-provider usage statistics: quota/rate windows, plan/account, credit
3
- * balance and local token tallies read from a coding CLI's on-disk state — its
4
- * stored OAuth token (→ the provider's official usage API) and/or its local
5
- * session logs.
2
+ * AI-provider usage: plan limits (quota windows, plan, account, credit) and
3
+ * spend (tokens and cost by day, agent and model).
6
4
  *
7
- * Surfaced in the desktop's Settings → Providers section and, over the bridge,
8
- * on the phone. The access path is per-runtime by design (02a §5.8.10): the
9
- * desktop reads these files natively in Rust; the bridge reads them in TS so a
10
- * paired phone — which cannot see the PC's disk directly — gets the same data
11
- * over `agent/usageStats`. The Dart equivalents live in uxnanmobile and are kept
12
- * in sync manually (see 02e-bridge-integration.md §4.2).
13
- *
14
- * Posture: only the token the CLI itself stored is read — from its file, or
15
- * from the OS credential store where that is where the CLI keeps it (Claude
16
- * Code on macOS), and then only after the user has granted the OS-level
17
- * permission once (see `accessRequired`). Never browser cookies, never
18
- * user-pasted API keys, never a refresh token.
5
+ * The bridge is the one reader; every client — the phone, Uxnan Desktop's
6
+ * Providers panel — asks it (`agent/usageStats`, `usage/summary`,
7
+ * `usage/redeemReset`). Claude Code and Codex are asked themselves: each CLI
8
+ * answers for the account it is signed in to, so no credential is read and no
9
+ * OS permission is needed. Copilot and Grok have no such surface: only the
10
+ * token each CLI stored is read (`gh auth token`, `~/.grok/auth.json`) and sent
11
+ * to the provider's own usage API. Spend comes from the transcripts every
12
+ * agent CLI keeps on disk. Never browser cookies, never a pasted key, never a
13
+ * refresh token. The Dart equivalents live in uxnanmobile and are kept in sync
14
+ * manually.
19
15
  */
20
16
  export {};
21
17
  //# sourceMappingURL=usage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/models/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/models/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
@@ -26,14 +26,21 @@ export interface WorkspaceFileTarget {
26
26
  path: string;
27
27
  }
28
28
  /**
29
- * An image (or other media) attached to a user turn (`turn/send { attachments }`).
30
- * Tolerant by design — the phone sends inline base64 with the original
29
+ * An image or a file attached to a user turn (`turn/send { attachments }`).
30
+ * Tolerant by design — clients send inline base64 with the original
31
31
  * `mimeType`; `path`/`width`/`height` are best-effort metadata. At least one of
32
32
  * `base64Data`/`path` must be present for the bridge to deliver it to the agent.
33
+ * The bridge writes each one into the agent's folder for the turn and names
34
+ * it in the prompt, so every agent opens it with its own tools; a file keeps
35
+ * its `name` there. At most {@link MAX_ATTACHMENT_BYTES} each.
33
36
  */
37
+ /** The largest attachment `turn/send` takes, decoded: 20 MB. */
38
+ export declare const MAX_ATTACHMENT_BYTES: number;
34
39
  export interface TurnAttachment {
35
- /** Wire discriminator (always `image` today). */
36
- type?: 'image';
40
+ /** An image (the default), or any other file. */
41
+ type?: 'image' | 'file';
42
+ /** A file's name (no directories), kept when the agent receives it. */
43
+ name?: string;
37
44
  /** MIME type, e.g. `image/png`. */
38
45
  mimeType: string;
39
46
  /** Inline base64 payload (no `data:` URI prefix). */
@@ -3,5 +3,15 @@
3
3
  *
4
4
  * Source: architecture/02a-system-architecture.md §5.8.7.
5
5
  */
6
- export {};
6
+ /**
7
+ * An image or a file attached to a user turn (`turn/send { attachments }`).
8
+ * Tolerant by design — clients send inline base64 with the original
9
+ * `mimeType`; `path`/`width`/`height` are best-effort metadata. At least one of
10
+ * `base64Data`/`path` must be present for the bridge to deliver it to the agent.
11
+ * The bridge writes each one into the agent's folder for the turn and names
12
+ * it in the prompt, so every agent opens it with its own tools; a file keeps
13
+ * its `name` there. At most {@link MAX_ATTACHMENT_BYTES} each.
14
+ */
15
+ /** The largest attachment `turn/send` takes, decoded: 20 MB. */
16
+ export const MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
7
17
  //# sourceMappingURL=workspace.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/models/workspace.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/models/workspace.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA2BH;;;;;;;;GAQG;AACH,gEAAgE;AAChE,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxnan/shared",
3
- "version": "0.0.20-alpha.20260926",
3
+ "version": "0.0.22-alpha.20260927",
4
4
  "description": "Shared JSON-RPC and E2EE contracts for the Uxnan ecosystem (bridge, relay, mobile).",
5
5
  "license": "MPL-2.0",
6
6
  "author": "Luis Donaldo Gamas Vazquez",