@uxnan/shared 0.0.4-alpha.20260703 → 0.0.6-alpha.20260716
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 +2 -2
- package/dist/src/agents/agent-adapter.d.ts +29 -1
- package/dist/src/agents/agent-capabilities.d.ts +69 -1
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/jsonrpc/method-registry.d.ts +1 -1
- package/dist/src/jsonrpc/method-registry.js +6 -0
- package/dist/src/jsonrpc/method-registry.js.map +1 -1
- package/dist/src/jsonrpc/methods.d.ts +51 -1
- package/dist/src/models/metrics.d.ts +162 -0
- package/dist/src/models/metrics.js +26 -0
- package/dist/src/models/metrics.js.map +1 -0
- package/dist/src/models/question.d.ts +54 -0
- package/dist/src/models/question.js +14 -0
- package/dist/src/models/question.js.map +1 -0
- package/dist/src/models/usage.d.ts +137 -0
- package/dist/src/models/usage.js +18 -0
- package/dist/src/models/usage.js.map +1 -0
- package/package.json +1 -1
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 — **
|
|
16
|
+
> **Status:** implemented and stable — **66 JSON-RPC methods** + **8 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
|
|
@@ -52,7 +52,7 @@ flowchart TB
|
|
|
52
52
|
| JSON-RPC | envelope types + constructors (`makeRequest`, `makeNotification`, `makeResponse`, `makeErrorResponse`), error codes (`JsonRpcErrorCode` + Uxnan-specific `-32000..-32008`), `RpcError`, typed method registry (`JsonRpcMethodRegistry` + `METHOD_NAMES`), `isKnownMethod` |
|
|
53
53
|
| Streaming | `StreamNotification` enum + param types (`TurnStartedParams`, `MessageDeltaParams`, `ThinkingDeltaParams`, `ContentBlockParams`, `TurnCompletedParams`, `TurnUsage`, `TurnErrorParams`, `TurnAbortedParams`, `ModelResolvedParams`) |
|
|
54
54
|
| E2EE | handshake messages (`clientHello` / `serverHello` / `clientAuth` / `ready`), `buildHandshakeTranscript`, `SecureEnvelope`, `PairingPayload` v2 (`relay` optional + `hosts: string[]`) with `Base64(utf8(JSON))` QR encoding |
|
|
55
|
-
| Models | thread / turn / message (with `MessageContent` polymorphic blocks), git, workspace (incl. `browseDirs` + `exists`), project, auth, session/trust (`BridgeStatus` incl. `latestVersion?`/`updateAvailable?`), approval |
|
|
55
|
+
| Models | thread / turn / message (with `MessageContent` polymorphic blocks), git, workspace (incl. `browseDirs` + `exists`), project, auth, session/trust (`BridgeStatus` incl. `latestVersion?`/`updateAvailable?`), approval, question (interactive multiple-choice) |
|
|
56
56
|
| Agents | `IAgentAdapter` (with `respondApproval`, `listModels`, `nativeSessionId`, `SendTurnOptions { threadId, turnId, text, service?, effort?, options?, attachments?, cwd?, accessMode? }`), `AgentModel` (incl. `version?`, `isDefault?`, `options?`, `contextWindow?`, `isLatestAlias?`), `AgentCapabilities` (incl. `images`, `approvals`, `reportsContextUsage`), `AgentConfig` (cwd, agentId, model, plus optional `binaryPath`/`extraArgs`) |
|
|
57
57
|
| Version | `compareVersions` / `isNewerVersion` — dependency-free SemVer precedence (used by the bridge's npm update check) |
|
|
58
58
|
| Validation | Ajv validators for requests, responses, envelopes, pairing payload, push payloads |
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Source: architecture/02a-system-architecture.md §5.8.2 (adapters/base-adapter).
|
|
5
5
|
*/
|
|
6
|
-
import type { AgentCapabilities, AgentId, AgentModel } from './agent-capabilities.js';
|
|
6
|
+
import type { AgentCapabilities, AgentCommand, AgentCommandInvocation, AgentId, AgentModel } from './agent-capabilities.js';
|
|
7
7
|
import type { AgentConfig } from './agent-config.js';
|
|
8
8
|
import type { TurnAttachment } from '../models/workspace.js';
|
|
9
9
|
import type { ApprovalDecision } from '../models/approval.js';
|
|
@@ -52,6 +52,15 @@ export interface SendTurnOptions {
|
|
|
52
52
|
* configured default posture (no behaviour change).
|
|
53
53
|
*/
|
|
54
54
|
accessMode?: AccessMode;
|
|
55
|
+
/**
|
|
56
|
+
* Invoke an advertised agent command (from `agent/commands`) instead of
|
|
57
|
+
* free-form {@link text}. The {@link AgentManager} resolves it before the
|
|
58
|
+
* adapter runs — expanding a custom prompt-template via {@link
|
|
59
|
+
* IAgentAdapter.expandCommand}, or composing the CLI's native `/name args`
|
|
60
|
+
* form — and sets {@link text} to the result, so most adapters need no
|
|
61
|
+
* per-command handling. Absent for an ordinary text turn.
|
|
62
|
+
*/
|
|
63
|
+
command?: AgentCommandInvocation;
|
|
55
64
|
}
|
|
56
65
|
export interface IAgentAdapter {
|
|
57
66
|
readonly agentId: AgentId;
|
|
@@ -75,4 +84,23 @@ export interface IAgentAdapter {
|
|
|
75
84
|
onEvent(listener: (event: AgentStreamEvent) => void): () => void;
|
|
76
85
|
/** List the models this agent's CLI reports as available (optional). */
|
|
77
86
|
listModels?(): Promise<AgentModel[]>;
|
|
87
|
+
/**
|
|
88
|
+
* List the special ("slash") commands this agent exposes — control commands
|
|
89
|
+
* reachable headless plus user-defined prompt-template commands scanned from
|
|
90
|
+
* disk (optional; adapters with none simply don't implement it). `cwd` is the
|
|
91
|
+
* thread/project directory so project-scoped custom commands (`<cwd>/.claude/
|
|
92
|
+
* commands`, `<cwd>/.gemini/commands`, …) are discovered alongside user-level
|
|
93
|
+
* ones. Discovery only; invocation flows through {@link sendTurn} with {@link
|
|
94
|
+
* SendTurnOptions.command}.
|
|
95
|
+
*/
|
|
96
|
+
listCommands?(cwd?: string): Promise<AgentCommand[]>;
|
|
97
|
+
/**
|
|
98
|
+
* Resolve a custom prompt-template command to the final prompt text (reads the
|
|
99
|
+
* template file from `cwd`/user config, substitutes arguments). Implemented
|
|
100
|
+
* only by adapters whose commands are prompt templates the bridge expands
|
|
101
|
+
* itself (Codex/Gemini/OpenCode); adapters whose commands run natively (Claude
|
|
102
|
+
* Code, ACP agents) leave it unset and receive the composed `/name args` form
|
|
103
|
+
* as {@link SendTurnOptions.text}. Throw if `name` is not a known custom command.
|
|
104
|
+
*/
|
|
105
|
+
expandCommand?(name: string, args?: string, cwd?: string): Promise<string>;
|
|
78
106
|
}
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Source: architecture/02a-system-architecture.md §5.8.2 (adapters).
|
|
5
5
|
*/
|
|
6
|
-
export type AgentId = 'codex' | 'opencode' | 'claude-code' | 'gemini-cli' | 'pi-agent'
|
|
6
|
+
export type AgentId = 'codex' | 'opencode' | 'claude-code' | 'gemini-cli' | 'pi-agent'
|
|
7
|
+
/** Zero — open-source Go coding agent, driven over the Agent Client Protocol. */
|
|
8
|
+
| 'zero'
|
|
9
|
+
/** Grok — xAI's coding CLI, driven over the Agent Client Protocol (`grok agent stdio`). */
|
|
10
|
+
| 'grok'
|
|
7
11
|
/** Built-in reference/dev agent that echoes the prompt (no external CLI). */
|
|
8
12
|
| 'echo';
|
|
9
13
|
export interface AgentCapabilities {
|
|
@@ -24,6 +28,21 @@ export interface AgentCapabilities {
|
|
|
24
28
|
* OpenCode) and the meter stays hidden.
|
|
25
29
|
*/
|
|
26
30
|
reportsContextUsage?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Agent runs in autonomous ("YOLO") mode by default — it acts and edits
|
|
33
|
+
* without per-action approval prompts because its headless CLI exposes no
|
|
34
|
+
* pre-tool approval channel. The phone surfaces this so the user knows Pi
|
|
35
|
+
* (and any such agent) will not ask before running tools. Optional; absent/
|
|
36
|
+
* false means the agent either gates tools or is pending approval wiring.
|
|
37
|
+
*/
|
|
38
|
+
autonomous?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Agent exposes special ("slash") commands the phone can discover via
|
|
41
|
+
* `agent/commands` and invoke through `turn/send` `command`. Optional for
|
|
42
|
+
* back-compat; absent/false means the agent advertises none (the phone shows
|
|
43
|
+
* only its client-side `/` palette). See {@link AgentCommand}.
|
|
44
|
+
*/
|
|
45
|
+
commands?: boolean;
|
|
27
46
|
}
|
|
28
47
|
/**
|
|
29
48
|
* A registered agent the phone can pick for a thread, returned by `agent/list`.
|
|
@@ -112,3 +131,52 @@ export interface AgentModel {
|
|
|
112
131
|
*/
|
|
113
132
|
isLatestAlias?: boolean;
|
|
114
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* A special ("slash") command an agent exposes, returned by `agent/commands`.
|
|
136
|
+
*
|
|
137
|
+
* Two kinds are unified under this one shape:
|
|
138
|
+
* - **control** commands the CLI understands in its headless/programmatic mode
|
|
139
|
+
* (Claude Code's `/compact` sent as the prompt with `--resume`; the commands
|
|
140
|
+
* ACP agents advertise via `available_commands_update`), and
|
|
141
|
+
* - **custom** user-defined prompt-template commands (`.claude/commands`,
|
|
142
|
+
* `~/.codex/prompts`, `.gemini/commands`, `.opencode/command`) that the bridge
|
|
143
|
+
* expands itself before running a normal turn.
|
|
144
|
+
*
|
|
145
|
+
* The phone is a generic renderer: it lists the advertised commands in its `/`
|
|
146
|
+
* palette and, when one is picked, echoes it back on `turn/send` under
|
|
147
|
+
* {@link AgentCommandInvocation} — the bridge resolves it to the final prompt
|
|
148
|
+
* text (expanded template) or the CLI's native `/name args` form. Consumers MUST
|
|
149
|
+
* tolerate absent optional fields so a newer bridge advertising a richer command
|
|
150
|
+
* never breaks an older app.
|
|
151
|
+
*/
|
|
152
|
+
export interface AgentCommand {
|
|
153
|
+
/** Command name WITHOUT the leading slash (e.g. `compact`, `refactor`). */
|
|
154
|
+
name: string;
|
|
155
|
+
/** One-line description for the palette, when the source provides one. */
|
|
156
|
+
description?: string;
|
|
157
|
+
/** Hint for the arguments the command accepts (e.g. `<file> <priority>`). */
|
|
158
|
+
argumentHint?: string;
|
|
159
|
+
/**
|
|
160
|
+
* Where the command comes from: `acp` (advertised by an ACP agent),
|
|
161
|
+
* `builtin` (a CLI control command reachable headless), or `custom` (a
|
|
162
|
+
* user-defined prompt-template file the bridge expands).
|
|
163
|
+
*/
|
|
164
|
+
source: 'acp' | 'builtin' | 'custom';
|
|
165
|
+
/**
|
|
166
|
+
* Whether the command actually runs in the agent's headless/programmatic mode.
|
|
167
|
+
* Absent/true means yes; `false` marks a command that only works in the CLI's
|
|
168
|
+
* interactive TUI, which the phone should hide. The bridge only advertises
|
|
169
|
+
* commands it can run, so this is a belt-and-suspenders gate.
|
|
170
|
+
*/
|
|
171
|
+
headlessSupported?: boolean;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* A picked {@link AgentCommand} carried on `turn/send` under `command`, instead
|
|
175
|
+
* of free-form `text`. The bridge resolves `{ name, args }` to the final prompt.
|
|
176
|
+
*/
|
|
177
|
+
export interface AgentCommandInvocation {
|
|
178
|
+
/** The command's {@link AgentCommand.name} (no leading slash). */
|
|
179
|
+
name: string;
|
|
180
|
+
/** Raw argument string the user appended after the command, if any. */
|
|
181
|
+
args?: string;
|
|
182
|
+
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -22,5 +22,8 @@ export * from './models/workspace.js';
|
|
|
22
22
|
export * from './models/project.js';
|
|
23
23
|
export * from './models/session.js';
|
|
24
24
|
export * from './models/approval.js';
|
|
25
|
+
export * from './models/question.js';
|
|
26
|
+
export * from './models/usage.js';
|
|
27
|
+
export * from './models/metrics.js';
|
|
25
28
|
export * from './validators/validate.js';
|
|
26
29
|
export * from './validators/json-schema/schemas.js';
|
package/dist/src/index.js
CHANGED
|
@@ -28,6 +28,9 @@ export * from './models/workspace.js';
|
|
|
28
28
|
export * from './models/project.js';
|
|
29
29
|
export * from './models/session.js';
|
|
30
30
|
export * from './models/approval.js';
|
|
31
|
+
export * from './models/question.js';
|
|
32
|
+
export * from './models/usage.js';
|
|
33
|
+
export * from './models/metrics.js';
|
|
31
34
|
// Validators
|
|
32
35
|
export * from './validators/validate.js';
|
|
33
36
|
export * from './validators/json-schema/schemas.js';
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,gBAAgB,CAAC;AAE/B,WAAW;AACX,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAE3C,OAAO;AACP,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAE1C,SAAS;AACT,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAE1C,UAAU;AACV,cAAc,sBAAsB,CAAC;AAErC,gBAAgB;AAChB,cAAc,iCAAiC,CAAC;AAEhD,SAAS;AACT,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,gBAAgB,CAAC;AAE/B,WAAW;AACX,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAE3C,OAAO;AACP,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAE1C,SAAS;AACT,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAE1C,UAAU;AACV,cAAc,sBAAsB,CAAC;AAErC,gBAAgB;AAChB,cAAc,iCAAiC,CAAC;AAEhD,SAAS;AACT,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AAEpC,aAAa;AACb,cAAc,0BAA0B,CAAC;AACzC,cAAc,qCAAqC,CAAC"}
|
|
@@ -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", "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/log", "git/commitShow", "workspace/readFile", "workspace/readImage", "workspace/list", "workspace/searchFiles", "workspace/browseDirs", "workspace/checkpoint", "workspace/diffCheckpoint", "workspace/applyCheckpoint", "workspace/applyPatch", "workspace/exists", "project/list", "project/resolve", "agent/list", "agent/models", "auth/status", "auth/login", "auth/logout", "notifications/register", "notifications/update", "notifications/unregister", "bridge/status", "bridge/generatePairingQr", "bridge/connectedPhones", "bridge/disconnectPhone", "bridge/trustedDevices", "bridge/removeTrustedDevice"];
|
|
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", "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/log", "git/commitShow", "workspace/readFile", "workspace/readImage", "workspace/list", "workspace/searchFiles", "workspace/browseDirs", "workspace/checkpoint", "workspace/diffCheckpoint", "workspace/applyCheckpoint", "workspace/applyPatch", "workspace/exists", "project/list", "project/resolve", "agent/list", "agent/models", "agent/commands", "agent/usageStats", "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"];
|
|
7
7
|
export declare function isKnownMethod(method: string): method is JsonRpcMethodName;
|
|
@@ -53,6 +53,12 @@ export const METHOD_NAMES = [
|
|
|
53
53
|
// Agents
|
|
54
54
|
'agent/list',
|
|
55
55
|
'agent/models',
|
|
56
|
+
'agent/commands',
|
|
57
|
+
'agent/usageStats',
|
|
58
|
+
// Metrics (bridge-owned, survivable profile stats + tamper-proof backup)
|
|
59
|
+
'metrics/get',
|
|
60
|
+
'metrics/export',
|
|
61
|
+
'metrics/import',
|
|
56
62
|
// Auth
|
|
57
63
|
'auth/status',
|
|
58
64
|
'auth/login',
|
|
@@ -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,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,SAAS;IACT,gBAAgB;IAChB,YAAY;IACZ,oBAAoB;IACpB,qBAAqB;IACrB,gBAAgB;IAChB,uBAAuB;IACvB,sBAAsB;IACtB,sBAAsB;IACtB,0BAA0B;IAC1B,2BAA2B;IAC3B,sBAAsB;IACtB,kBAAkB;IAClB,WAAW;IACX,cAAc;IACd,iBAAiB;IACjB,SAAS;IACT,YAAY;IACZ,cAAc;IACd,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;CACpB,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,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,SAAS;IACT,gBAAgB;IAChB,YAAY;IACZ,oBAAoB;IACpB,qBAAqB;IACrB,gBAAgB;IAChB,uBAAuB;IACvB,sBAAsB;IACtB,sBAAsB;IACtB,0BAA0B;IAC1B,2BAA2B;IAC3B,sBAAsB;IACtB,kBAAkB;IAClB,WAAW;IACX,cAAc;IACd,iBAAiB;IACjB,SAAS;IACT,YAAY;IACZ,cAAc;IACd,gBAAgB;IAChB,kBAAkB;IAClB,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;CACpB,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"}
|
|
@@ -10,9 +10,12 @@ import type { GitBranchList, GitBranchResult, GitCommitDetails, GitCommitResult,
|
|
|
10
10
|
import type { ApplyResult, BrowseResult, Checkpoint, CheckpointDiff, FileContent, ImageContent, PatchChange, TurnAttachment, WorkspaceExistsResult, WorkspaceListing, SearchFilesParams, WorkspaceSearchResult } from '../models/workspace.js';
|
|
11
11
|
import type { AuthStatus, Project } from '../models/project.js';
|
|
12
12
|
import type { ApprovalResponse } from '../models/approval.js';
|
|
13
|
+
import type { QuestionResponse } from '../models/question.js';
|
|
13
14
|
import type { BridgeStatus, ConnectedPhone, TrustedDevice } from '../models/session.js';
|
|
14
15
|
import type { PairingPayload } from '../e2ee/pairing-payload.js';
|
|
15
|
-
import type { AgentDescriptor, AgentId, AgentModel } from '../agents/agent-capabilities.js';
|
|
16
|
+
import type { AgentCommand, AgentCommandInvocation, AgentDescriptor, AgentId, AgentModel } from '../agents/agent-capabilities.js';
|
|
17
|
+
import type { UsageStatsParams, UsageStatsResult } from '../models/usage.js';
|
|
18
|
+
import type { MetricsExportParams, MetricsExportResult, MetricsImportParams, MetricsImportResult, MetricsSnapshot } from '../models/metrics.js';
|
|
16
19
|
import type { PushPlatform } from '../notifications/push-payload.js';
|
|
17
20
|
export interface ListThreadsParams {
|
|
18
21
|
projectId?: string;
|
|
@@ -74,6 +77,20 @@ export interface TurnSendParams {
|
|
|
74
77
|
* is not required.
|
|
75
78
|
*/
|
|
76
79
|
approvalResponse?: ApprovalResponse;
|
|
80
|
+
/**
|
|
81
|
+
* Reply to a pending question the agent asked (no new turn is created). The
|
|
82
|
+
* bridge routes the chosen answers to the agent adapter. When present, `text`
|
|
83
|
+
* is not required.
|
|
84
|
+
*/
|
|
85
|
+
questionResponse?: QuestionResponse;
|
|
86
|
+
/**
|
|
87
|
+
* Invoke an advertised agent command (from `agent/commands`) instead of
|
|
88
|
+
* free-form `text`. The bridge resolves `{ name, args }` to the final prompt —
|
|
89
|
+
* expanding a custom prompt-template file, or composing the CLI's native
|
|
90
|
+
* `/name args` form — then runs a normal turn. When present, `text` is not
|
|
91
|
+
* required.
|
|
92
|
+
*/
|
|
93
|
+
command?: AgentCommandInvocation;
|
|
77
94
|
}
|
|
78
95
|
export interface ThreadSetModelParams {
|
|
79
96
|
threadId: string;
|
|
@@ -212,6 +229,19 @@ export interface AgentModelsResult {
|
|
|
212
229
|
/** Models the agent can use, with presentation metadata, as reported by its CLI. */
|
|
213
230
|
models: AgentModel[];
|
|
214
231
|
}
|
|
232
|
+
export interface AgentCommandsParams {
|
|
233
|
+
agentId: AgentId;
|
|
234
|
+
/**
|
|
235
|
+
* Thread/project directory, so project-scoped custom commands (e.g.
|
|
236
|
+
* `<cwd>/.claude/commands`, `<cwd>/.gemini/commands`) are discovered alongside
|
|
237
|
+
* the user-level ones. Omitted → only user-level commands are returned.
|
|
238
|
+
*/
|
|
239
|
+
cwd?: string;
|
|
240
|
+
}
|
|
241
|
+
export interface AgentCommandsResult {
|
|
242
|
+
/** Special ("slash") commands the agent exposes, discovered from its CLI/disk. */
|
|
243
|
+
commands: AgentCommand[];
|
|
244
|
+
}
|
|
215
245
|
/** What the phone wants to be notified about (background push). */
|
|
216
246
|
export interface NotificationPreferences {
|
|
217
247
|
/** Push when an agent turn completes. */
|
|
@@ -468,6 +498,26 @@ export interface JsonRpcMethodRegistry {
|
|
|
468
498
|
params: AgentModelsParams;
|
|
469
499
|
result: AgentModelsResult;
|
|
470
500
|
};
|
|
501
|
+
'agent/commands': {
|
|
502
|
+
params: AgentCommandsParams;
|
|
503
|
+
result: AgentCommandsResult;
|
|
504
|
+
};
|
|
505
|
+
'agent/usageStats': {
|
|
506
|
+
params: UsageStatsParams;
|
|
507
|
+
result: UsageStatsResult;
|
|
508
|
+
};
|
|
509
|
+
'metrics/get': {
|
|
510
|
+
params: void;
|
|
511
|
+
result: MetricsSnapshot;
|
|
512
|
+
};
|
|
513
|
+
'metrics/export': {
|
|
514
|
+
params: MetricsExportParams;
|
|
515
|
+
result: MetricsExportResult;
|
|
516
|
+
};
|
|
517
|
+
'metrics/import': {
|
|
518
|
+
params: MetricsImportParams;
|
|
519
|
+
result: MetricsImportResult;
|
|
520
|
+
};
|
|
471
521
|
'auth/status': {
|
|
472
522
|
params: {
|
|
473
523
|
agentId: AgentId;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile metrics — a bridge-owned, survivable tally of a PC's activity, plus a
|
|
3
|
+
* tamper-proof export/import backup.
|
|
4
|
+
*
|
|
5
|
+
* The mobile profile screen shows aggregated metrics (conversations, messages,
|
|
6
|
+
* agents/models used, connection time, git actions, an activity heatmap). Those
|
|
7
|
+
* were derived on the phone from local storage and so were lost on an app
|
|
8
|
+
* uninstall (the app has no cloud login). To make them durable, the **bridge**
|
|
9
|
+
* becomes the source of truth: it computes them from its own authoritative data
|
|
10
|
+
* (the conversation store) plus persisted session + git-action event logs it
|
|
11
|
+
* observes itself, and serves them over `metrics/get`. The phone renders one
|
|
12
|
+
* snapshot per PC and sums across PCs.
|
|
13
|
+
*
|
|
14
|
+
* A `metrics/export` produces an opaque, tamper-proof file only the SAME bridge
|
|
15
|
+
* can later verify + decrypt (AES-256-GCM under a secret held in the PC's OS
|
|
16
|
+
* keychain), so users cannot fabricate or edit their stats; `metrics/import`
|
|
17
|
+
* feeds one back and merges its events by id (idempotent).
|
|
18
|
+
*
|
|
19
|
+
* Provider usage/credits are deliberately NOT part of this — those are read live
|
|
20
|
+
* via `agent/usageStats` and never persisted.
|
|
21
|
+
*
|
|
22
|
+
* Source: architecture/02a-system-architecture.md §5.8.11 and
|
|
23
|
+
* 02b-contracts-and-requirements.md.
|
|
24
|
+
*/
|
|
25
|
+
/** Transport a phone→PC connection session used. */
|
|
26
|
+
export type MetricsTransport = 'relay' | 'direct';
|
|
27
|
+
/** Per-agent conversation tally (most-used first). */
|
|
28
|
+
export interface MetricsAgentUsage {
|
|
29
|
+
/** Agent wire id (e.g. `claude-code`, `codex`). */
|
|
30
|
+
agentId: string;
|
|
31
|
+
/** Conversations started with this agent on this PC. */
|
|
32
|
+
conversations: number;
|
|
33
|
+
}
|
|
34
|
+
/** One agent's activity on a given day (drives the per-agent bars). */
|
|
35
|
+
export interface MetricsAgentDay {
|
|
36
|
+
/** Agent wire id (e.g. `claude-code`, `codex`). */
|
|
37
|
+
agentId: string;
|
|
38
|
+
/** Conversations (threads) this agent started that day. */
|
|
39
|
+
conversations: number;
|
|
40
|
+
/** Messages exchanged that day in this agent's threads. */
|
|
41
|
+
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
|
+
}
|
|
50
|
+
/** One calendar day's activity split per agent. */
|
|
51
|
+
export interface MetricsDayBreakdown {
|
|
52
|
+
/** UTC-midnight epoch ms of the calendar date (same encoding as `activity`). */
|
|
53
|
+
day: number;
|
|
54
|
+
/** Per-agent activity that day (agents with any conversation/message/token). */
|
|
55
|
+
byAgent: MetricsAgentDay[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* One local calendar-day activity bucket. Counts are split by category so a
|
|
59
|
+
* client can render any metric filter (combined / conversations / messages /
|
|
60
|
+
* work) with no extra round-trip. Days with no activity are omitted.
|
|
61
|
+
*/
|
|
62
|
+
export interface MetricsActivityDay {
|
|
63
|
+
/**
|
|
64
|
+
* The calendar date this bucket covers, as **UTC-midnight epoch ms** of the
|
|
65
|
+
* bridge host's local date. Encoding the local date at UTC midnight (not the
|
|
66
|
+
* local-midnight instant) makes the key timezone-stable, so a phone in any
|
|
67
|
+
* timezone maps it to the correct heatmap cell.
|
|
68
|
+
*/
|
|
69
|
+
day: number;
|
|
70
|
+
/** Conversations started that day. */
|
|
71
|
+
conversations: number;
|
|
72
|
+
/** Messages exchanged that day. */
|
|
73
|
+
messages: number;
|
|
74
|
+
/** Git/work actions performed that day. */
|
|
75
|
+
work: number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Aggregated metrics for ONE PC (the bridge that returns it), built from the
|
|
79
|
+
* bridge's own authoritative data: the conversation store (threads/turns) plus
|
|
80
|
+
* its persisted session + git-action event logs. The phone renders this per PC
|
|
81
|
+
* and sums across PCs for the all-PCs profile. Every field is a count the phone
|
|
82
|
+
* cannot inflate — the bridge observes it. Source of `metrics/get`.
|
|
83
|
+
*/
|
|
84
|
+
export interface MetricsSnapshot {
|
|
85
|
+
/** Schema version, for forward-compatible parsing. */
|
|
86
|
+
version: number;
|
|
87
|
+
/** The bridge PC's `macDeviceId` this snapshot belongs to. */
|
|
88
|
+
deviceId: string;
|
|
89
|
+
/** Total conversations (threads) started on this PC. */
|
|
90
|
+
conversations: number;
|
|
91
|
+
/** Distinct agents used. */
|
|
92
|
+
agentsUsed: number;
|
|
93
|
+
/** Distinct models used. */
|
|
94
|
+
modelsUsed: number;
|
|
95
|
+
/** Total messages exchanged (both roles). */
|
|
96
|
+
messages: number;
|
|
97
|
+
/** Total git actions performed (mutating operations). */
|
|
98
|
+
gitActions: number;
|
|
99
|
+
/** Connection sessions recorded. */
|
|
100
|
+
sessions: number;
|
|
101
|
+
/** Cumulative connected time across all sessions, ms. */
|
|
102
|
+
totalConnectedMs: number;
|
|
103
|
+
/** The single longest connection session, ms. */
|
|
104
|
+
longestSessionMs: number;
|
|
105
|
+
/** Sessions that ran over the relay. */
|
|
106
|
+
relaySessions: number;
|
|
107
|
+
/** Sessions that ran over a direct LAN/Tailscale host. */
|
|
108
|
+
directSessions: number;
|
|
109
|
+
/** Per-agent conversation tallies, most-used first. */
|
|
110
|
+
byAgent: MetricsAgentUsage[];
|
|
111
|
+
/** Earliest conversation creation (epoch ms); absent when there are none. */
|
|
112
|
+
memberSince?: number;
|
|
113
|
+
/** Per-day activity buckets for the contribution heatmap. */
|
|
114
|
+
activity: MetricsActivityDay[];
|
|
115
|
+
/**
|
|
116
|
+
* Per-day activity split per agent (conversations, messages, tokens), for the
|
|
117
|
+
* unified agent-activity view: the per-agent bars show all-time totals, or a
|
|
118
|
+
* single day's totals when a heatmap cell is selected. See
|
|
119
|
+
* {@link MetricsAgentDay}.
|
|
120
|
+
*/
|
|
121
|
+
byAgentDay: MetricsDayBreakdown[];
|
|
122
|
+
/** When the bridge produced this snapshot (epoch ms). */
|
|
123
|
+
updatedAt: number;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* `metrics/export` request. The bridge seals its metrics event log into an
|
|
127
|
+
* opaque, tamper-proof blob that only THIS same bridge can later verify +
|
|
128
|
+
* decrypt (AES-256-GCM under a secret held in the OS keychain). An optional user
|
|
129
|
+
* [passphrase] adds a second confidentiality layer (scrypt-derived), so a leaked
|
|
130
|
+
* file also needs the phrase; it must be supplied again at import.
|
|
131
|
+
*/
|
|
132
|
+
export interface MetricsExportParams {
|
|
133
|
+
/** Optional extra passphrase lock; required again at import when set. */
|
|
134
|
+
passphrase?: string;
|
|
135
|
+
}
|
|
136
|
+
export interface MetricsExportResult {
|
|
137
|
+
/** The sealed blob to write to a file (a JSON string, opaque to the phone). */
|
|
138
|
+
blob: string;
|
|
139
|
+
/** Suggested filename (e.g. `uxnan-metrics-<host>-<date>.uxmetrics`). */
|
|
140
|
+
filename: string;
|
|
141
|
+
/** Whether the blob carries an extra passphrase lock (import will need it). */
|
|
142
|
+
passphraseProtected: boolean;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* `metrics/import` request. The phone sends back a previously exported [blob].
|
|
146
|
+
* The bridge verifies it was sealed by THIS PC — a foreign or edited file is
|
|
147
|
+
* rejected — decrypts it (using [passphrase] when the file was passphrase-locked)
|
|
148
|
+
* and merges its events by id (idempotent: re-importing the same file changes
|
|
149
|
+
* nothing). Returns the refreshed snapshot.
|
|
150
|
+
*/
|
|
151
|
+
export interface MetricsImportParams {
|
|
152
|
+
/** The sealed blob produced by a prior `metrics/export` on this PC. */
|
|
153
|
+
blob: string;
|
|
154
|
+
/** The passphrase, when the file was exported with one. */
|
|
155
|
+
passphrase?: string;
|
|
156
|
+
}
|
|
157
|
+
export interface MetricsImportResult {
|
|
158
|
+
/** How many new session + git-action events were merged in. */
|
|
159
|
+
imported: number;
|
|
160
|
+
/** The refreshed snapshot after the merge. */
|
|
161
|
+
snapshot: MetricsSnapshot;
|
|
162
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile metrics — a bridge-owned, survivable tally of a PC's activity, plus a
|
|
3
|
+
* tamper-proof export/import backup.
|
|
4
|
+
*
|
|
5
|
+
* The mobile profile screen shows aggregated metrics (conversations, messages,
|
|
6
|
+
* agents/models used, connection time, git actions, an activity heatmap). Those
|
|
7
|
+
* were derived on the phone from local storage and so were lost on an app
|
|
8
|
+
* uninstall (the app has no cloud login). To make them durable, the **bridge**
|
|
9
|
+
* becomes the source of truth: it computes them from its own authoritative data
|
|
10
|
+
* (the conversation store) plus persisted session + git-action event logs it
|
|
11
|
+
* observes itself, and serves them over `metrics/get`. The phone renders one
|
|
12
|
+
* snapshot per PC and sums across PCs.
|
|
13
|
+
*
|
|
14
|
+
* A `metrics/export` produces an opaque, tamper-proof file only the SAME bridge
|
|
15
|
+
* can later verify + decrypt (AES-256-GCM under a secret held in the PC's OS
|
|
16
|
+
* keychain), so users cannot fabricate or edit their stats; `metrics/import`
|
|
17
|
+
* feeds one back and merges its events by id (idempotent).
|
|
18
|
+
*
|
|
19
|
+
* Provider usage/credits are deliberately NOT part of this — those are read live
|
|
20
|
+
* via `agent/usageStats` and never persisted.
|
|
21
|
+
*
|
|
22
|
+
* Source: architecture/02a-system-architecture.md §5.8.11 and
|
|
23
|
+
* 02b-contracts-and-requirements.md.
|
|
24
|
+
*/
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../src/models/metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive question contracts.
|
|
3
|
+
*
|
|
4
|
+
* An agent that needs the user to CHOOSE among options (not just approve/reject
|
|
5
|
+
* an action) emits a `question` content block (on `stream/content/block`); the
|
|
6
|
+
* phone renders an interactive picker and replies via `turn/send { questionResponse }`.
|
|
7
|
+
* The bridge routes the chosen answers back to the agent adapter. This mirrors
|
|
8
|
+
* the {@link ApprovalResponse} flow but carries multiple-choice answers instead
|
|
9
|
+
* of a binary decision.
|
|
10
|
+
*
|
|
11
|
+
* Source: architecture/02a-system-architecture.md §6.2.
|
|
12
|
+
*/
|
|
13
|
+
/** One selectable option of a {@link QuestionItem}. */
|
|
14
|
+
export interface QuestionOption {
|
|
15
|
+
/** Display text the user picks (also the value echoed back as the answer). */
|
|
16
|
+
label: string;
|
|
17
|
+
/** Optional one-line explanation of what choosing this option means. */
|
|
18
|
+
description?: string;
|
|
19
|
+
}
|
|
20
|
+
/** A single question with its options. */
|
|
21
|
+
export interface QuestionItem {
|
|
22
|
+
/** The full question text. */
|
|
23
|
+
question: string;
|
|
24
|
+
/** Optional short label/category for the question. */
|
|
25
|
+
header?: string;
|
|
26
|
+
/** The choices the user may pick from. */
|
|
27
|
+
options: QuestionOption[];
|
|
28
|
+
/** Whether more than one option may be selected (defaults to single-select). */
|
|
29
|
+
multiple?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Payload of a `question` content block. The phone decodes this into its
|
|
33
|
+
* interactive question card. `questionId` is the bridge handle the user echoes
|
|
34
|
+
* back in {@link QuestionResponse.questionId}.
|
|
35
|
+
*/
|
|
36
|
+
export interface QuestionRequestBlock {
|
|
37
|
+
type: 'question';
|
|
38
|
+
/** Bridge id the phone echoes back in `questionResponse.questionId`. */
|
|
39
|
+
questionId: string;
|
|
40
|
+
/** The questions to ask (usually one; an agent may batch a few). */
|
|
41
|
+
questions: QuestionItem[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The user's reply to a pending question, carried on `turn/send`. `answers` is
|
|
45
|
+
* one entry per question (in order), each an array of the chosen option
|
|
46
|
+
* `label`s (one for single-select, several for a `multiple` question, empty when
|
|
47
|
+
* the user skipped that question).
|
|
48
|
+
*/
|
|
49
|
+
export interface QuestionResponse {
|
|
50
|
+
/** The id from the question request the user is answering. */
|
|
51
|
+
questionId: string;
|
|
52
|
+
/** Chosen option labels, per question, in question order. */
|
|
53
|
+
answers: string[][];
|
|
54
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive question contracts.
|
|
3
|
+
*
|
|
4
|
+
* An agent that needs the user to CHOOSE among options (not just approve/reject
|
|
5
|
+
* an action) emits a `question` content block (on `stream/content/block`); the
|
|
6
|
+
* phone renders an interactive picker and replies via `turn/send { questionResponse }`.
|
|
7
|
+
* The bridge routes the chosen answers back to the agent adapter. This mirrors
|
|
8
|
+
* the {@link ApprovalResponse} flow but carries multiple-choice answers instead
|
|
9
|
+
* of a binary decision.
|
|
10
|
+
*
|
|
11
|
+
* Source: architecture/02a-system-architecture.md §6.2.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=question.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"question.js","sourceRoot":"","sources":["../../../src/models/question.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,137 @@
|
|
|
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.
|
|
6
|
+
*
|
|
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 CLI's own stored token is read — never browser cookies or
|
|
15
|
+
* user-pasted API keys.
|
|
16
|
+
*/
|
|
17
|
+
/** A coding CLI whose usage we read from its own stored token. */
|
|
18
|
+
export type UsageProvider = 'codex' | 'claude' | 'copilot' | 'gemini' | 'grok';
|
|
19
|
+
/** Outcome of reading one provider's usage. */
|
|
20
|
+
export type UsageStatus =
|
|
21
|
+
/** Fresh quota/credit data was read. */
|
|
22
|
+
'ok'
|
|
23
|
+
/** CLI is present but not signed in (no usable token). */
|
|
24
|
+
| 'authRequired'
|
|
25
|
+
/** CLI / its config directory is not present on this machine. */
|
|
26
|
+
| 'notInstalled'
|
|
27
|
+
/** Read/network/parse failure — see {@link ProviderUsage.message}. */
|
|
28
|
+
| 'error';
|
|
29
|
+
/** How the data was obtained, for the UI's provenance label. Every wired
|
|
30
|
+
* provider reads its quota from the CLI's own signed-in token. */
|
|
31
|
+
export type UsageSource = 'token';
|
|
32
|
+
/**
|
|
33
|
+
* The kind of billing relationship, so the UI can label an account beyond its
|
|
34
|
+
* plan name (e.g. distinguish a flat subscription from usage/credit billing).
|
|
35
|
+
* Derived per provider from its plan / billing signals.
|
|
36
|
+
*/
|
|
37
|
+
export type AccountType =
|
|
38
|
+
/** A flat paid subscription (Pro / Max / Plus / Pro+ …). */
|
|
39
|
+
'subscription'
|
|
40
|
+
/** Usage-billed: credits, on-demand, or pay-as-you-go on top of / instead of a plan. */
|
|
41
|
+
| 'payAsYouGo'
|
|
42
|
+
/** Free tier. */
|
|
43
|
+
| 'free'
|
|
44
|
+
/** A team / organization seat. */
|
|
45
|
+
| 'team'
|
|
46
|
+
/** An enterprise plan. */
|
|
47
|
+
| 'enterprise';
|
|
48
|
+
/**
|
|
49
|
+
* A single quota/rate window, expressed as a used-percentage with an optional
|
|
50
|
+
* reset time — the atomic unit a provider reports (e.g. a 5-hour session, a
|
|
51
|
+
* weekly cap, or a model-specific window).
|
|
52
|
+
*/
|
|
53
|
+
export interface UsageWindow {
|
|
54
|
+
/** Stable id (e.g. `session5h`, `weekly`, `opusWeekly`) — used by the
|
|
55
|
+
* status-bar picker to remember which windows to surface. */
|
|
56
|
+
id: string;
|
|
57
|
+
/** Human label (English; the UI localizes known ids, else shows this). */
|
|
58
|
+
label: string;
|
|
59
|
+
/** Consumed fraction of this window, clamped to 0–100. */
|
|
60
|
+
usedPercent: number;
|
|
61
|
+
/** Window length in minutes (300 = 5h, 10080 = 7d, 1440 = 24h), when known. */
|
|
62
|
+
windowMinutes?: number;
|
|
63
|
+
/** When the window resets (epoch ms), when the provider reports it. */
|
|
64
|
+
resetsAt?: number;
|
|
65
|
+
}
|
|
66
|
+
/** A monetary / credit balance, kept separate from the percentage windows. */
|
|
67
|
+
export interface CreditBalance {
|
|
68
|
+
/** Amount consumed this period, in `currency`. */
|
|
69
|
+
used: number;
|
|
70
|
+
/** Spend/credit cap, when the provider exposes one. */
|
|
71
|
+
limit?: number;
|
|
72
|
+
/** ISO-4217 code (`USD`, `EUR`, …) or `credits` for non-currency units. */
|
|
73
|
+
currency: string;
|
|
74
|
+
/** Period label (English; e.g. `Monthly`, `Credits`). */
|
|
75
|
+
period: string;
|
|
76
|
+
/** When the balance resets (epoch ms), when known. */
|
|
77
|
+
resetsAt?: number;
|
|
78
|
+
/** Amount still available this period, in `currency`, when the provider
|
|
79
|
+
* reports a remaining balance directly (e.g. Grok on-demand / prepaid). */
|
|
80
|
+
available?: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* "Reset credits" a provider grants to roll a hit rate-limit back early — Codex's
|
|
84
|
+
* rate-limit reset-credit system. Distinct from `credit` (money): these are
|
|
85
|
+
* redeemable reset tokens, not a balance.
|
|
86
|
+
*/
|
|
87
|
+
/** One redeemable reset — for the per-credit detail (which one, when it expires). */
|
|
88
|
+
export interface ResetCreditEntry {
|
|
89
|
+
/** Short label the provider gives the reset (e.g. "Full reset"). */
|
|
90
|
+
title?: string;
|
|
91
|
+
/** When this reset lapses (epoch ms). */
|
|
92
|
+
expiresAt?: number;
|
|
93
|
+
}
|
|
94
|
+
export interface ResetCredits {
|
|
95
|
+
/** How many resets can be redeemed right now. */
|
|
96
|
+
available: number;
|
|
97
|
+
/** Total resets ever granted to this account, when reported. */
|
|
98
|
+
totalEarned?: number;
|
|
99
|
+
/** When the soonest still-available reset lapses (epoch ms), when known. */
|
|
100
|
+
nextExpiresAt?: number;
|
|
101
|
+
/** The individual available resets, soonest-expiring first, when the provider
|
|
102
|
+
* details them. */
|
|
103
|
+
entries?: ResetCreditEntry[];
|
|
104
|
+
}
|
|
105
|
+
/** One provider's usage snapshot. */
|
|
106
|
+
export interface ProviderUsage {
|
|
107
|
+
provider: UsageProvider;
|
|
108
|
+
status: UsageStatus;
|
|
109
|
+
/** How `windows`/`credit` were obtained (absent for states with no data). */
|
|
110
|
+
source?: UsageSource;
|
|
111
|
+
account?: {
|
|
112
|
+
email?: string;
|
|
113
|
+
organization?: string;
|
|
114
|
+
plan?: string;
|
|
115
|
+
accountType?: AccountType;
|
|
116
|
+
};
|
|
117
|
+
/** Quota/rate windows (percentage-based). Empty when none apply. */
|
|
118
|
+
windows: UsageWindow[];
|
|
119
|
+
credit?: CreditBalance;
|
|
120
|
+
/** Redeemable rate-limit resets (Codex), when the provider grants them. */
|
|
121
|
+
resetCredits?: ResetCredits;
|
|
122
|
+
/** When this snapshot was produced (epoch ms). */
|
|
123
|
+
updatedAt: number;
|
|
124
|
+
/** Error/hint message for `error` / `authRequired` / `notInstalled` states. */
|
|
125
|
+
message?: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* `agent/usageStats` request: read usage for exactly these providers — only the
|
|
129
|
+
* ones the user activated. The reader never polls providers not listed here, so
|
|
130
|
+
* inactive providers cost nothing.
|
|
131
|
+
*/
|
|
132
|
+
export interface UsageStatsParams {
|
|
133
|
+
providers: UsageProvider[];
|
|
134
|
+
}
|
|
135
|
+
export interface UsageStatsResult {
|
|
136
|
+
usage: ProviderUsage[];
|
|
137
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
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.
|
|
6
|
+
*
|
|
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 CLI's own stored token is read — never browser cookies or
|
|
15
|
+
* user-pasted API keys.
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/models/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uxnan/shared",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6-alpha.20260716",
|
|
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",
|