@uxnan/shared 0.0.5-alpha.20260711 → 0.0.7-alpha.20260719
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 +7 -6
- package/dist/src/agents/agent-adapter.d.ts +29 -1
- package/dist/src/agents/agent-capabilities.d.ts +59 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -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 +5 -0
- package/dist/src/jsonrpc/method-registry.js.map +1 -1
- package/dist/src/jsonrpc/methods.d.ts +39 -1
- package/dist/src/jsonrpc/notifications.d.ts +12 -0
- 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/usage.d.ts +46 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|

|
|
4
4
|

|
|
5
5
|

|
|
6
|
-

|
|
7
7
|
|
|
8
8
|
Shared JSON-RPC and E2EE contracts for the [Uxnan](../README.md) ecosystem — the
|
|
9
9
|
single source of truth every component agrees on. Consumed as a local workspace
|
|
@@ -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
|
|
@@ -90,8 +90,9 @@ and [`src/jsonrpc/notifications.ts`](src/jsonrpc/notifications.ts)
|
|
|
90
90
|
§1.2 / §1.4. Per `AGENTS.md` → *Spec drift control*, any change here MUST be
|
|
91
91
|
reflected in the spec in the same change set.
|
|
92
92
|
|
|
93
|
-
##
|
|
93
|
+
## Published
|
|
94
94
|
|
|
95
|
-
`@uxnan/shared` is published to npm
|
|
96
|
-
then pin `"@uxnan/shared": "^0.x"`
|
|
97
|
-
|
|
95
|
+
`@uxnan/shared` is published to npm; `uxnan-bridge` and `uxnan-relay`
|
|
96
|
+
then pin `"@uxnan/shared": "^0.x"` — the release workflow replaces the
|
|
97
|
+
`"*"` workspace spec with the exact published version at build time.
|
|
98
|
+
See `bridge/FOR-DEV.md` → *Packaging*.
|
|
@@ -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,9 @@
|
|
|
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'
|
|
6
|
+
export type AgentId = 'codex' | 'opencode' | 'claude-code' | 'gemini-cli'
|
|
7
|
+
/** Antigravity — Google's `agy` CLI, the successor to the deprecated Gemini CLI. */
|
|
8
|
+
| 'antigravity-cli' | 'pi-agent'
|
|
7
9
|
/** Zero — open-source Go coding agent, driven over the Agent Client Protocol. */
|
|
8
10
|
| 'zero'
|
|
9
11
|
/** Grok — xAI's coding CLI, driven over the Agent Client Protocol (`grok agent stdio`). */
|
|
@@ -36,6 +38,13 @@ export interface AgentCapabilities {
|
|
|
36
38
|
* false means the agent either gates tools or is pending approval wiring.
|
|
37
39
|
*/
|
|
38
40
|
autonomous?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Agent exposes special ("slash") commands the phone can discover via
|
|
43
|
+
* `agent/commands` and invoke through `turn/send` `command`. Optional for
|
|
44
|
+
* back-compat; absent/false means the agent advertises none (the phone shows
|
|
45
|
+
* only its client-side `/` palette). See {@link AgentCommand}.
|
|
46
|
+
*/
|
|
47
|
+
commands?: boolean;
|
|
39
48
|
}
|
|
40
49
|
/**
|
|
41
50
|
* A registered agent the phone can pick for a thread, returned by `agent/list`.
|
|
@@ -124,3 +133,52 @@ export interface AgentModel {
|
|
|
124
133
|
*/
|
|
125
134
|
isLatestAlias?: boolean;
|
|
126
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* A special ("slash") command an agent exposes, returned by `agent/commands`.
|
|
138
|
+
*
|
|
139
|
+
* Two kinds are unified under this one shape:
|
|
140
|
+
* - **control** commands the CLI understands in its headless/programmatic mode
|
|
141
|
+
* (Claude Code's `/compact` sent as the prompt with `--resume`; the commands
|
|
142
|
+
* ACP agents advertise via `available_commands_update`), and
|
|
143
|
+
* - **custom** user-defined prompt-template commands (`.claude/commands`,
|
|
144
|
+
* `~/.codex/prompts`, `.gemini/commands`, `.opencode/command`) that the bridge
|
|
145
|
+
* expands itself before running a normal turn.
|
|
146
|
+
*
|
|
147
|
+
* The phone is a generic renderer: it lists the advertised commands in its `/`
|
|
148
|
+
* palette and, when one is picked, echoes it back on `turn/send` under
|
|
149
|
+
* {@link AgentCommandInvocation} — the bridge resolves it to the final prompt
|
|
150
|
+
* text (expanded template) or the CLI's native `/name args` form. Consumers MUST
|
|
151
|
+
* tolerate absent optional fields so a newer bridge advertising a richer command
|
|
152
|
+
* never breaks an older app.
|
|
153
|
+
*/
|
|
154
|
+
export interface AgentCommand {
|
|
155
|
+
/** Command name WITHOUT the leading slash (e.g. `compact`, `refactor`). */
|
|
156
|
+
name: string;
|
|
157
|
+
/** One-line description for the palette, when the source provides one. */
|
|
158
|
+
description?: string;
|
|
159
|
+
/** Hint for the arguments the command accepts (e.g. `<file> <priority>`). */
|
|
160
|
+
argumentHint?: string;
|
|
161
|
+
/**
|
|
162
|
+
* Where the command comes from: `acp` (advertised by an ACP agent),
|
|
163
|
+
* `builtin` (a CLI control command reachable headless), or `custom` (a
|
|
164
|
+
* user-defined prompt-template file the bridge expands).
|
|
165
|
+
*/
|
|
166
|
+
source: 'acp' | 'builtin' | 'custom';
|
|
167
|
+
/**
|
|
168
|
+
* Whether the command actually runs in the agent's headless/programmatic mode.
|
|
169
|
+
* Absent/true means yes; `false` marks a command that only works in the CLI's
|
|
170
|
+
* interactive TUI, which the phone should hide. The bridge only advertises
|
|
171
|
+
* commands it can run, so this is a belt-and-suspenders gate.
|
|
172
|
+
*/
|
|
173
|
+
headlessSupported?: boolean;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* A picked {@link AgentCommand} carried on `turn/send` under `command`, instead
|
|
177
|
+
* of free-form `text`. The bridge resolves `{ name, args }` to the final prompt.
|
|
178
|
+
*/
|
|
179
|
+
export interface AgentCommandInvocation {
|
|
180
|
+
/** The command's {@link AgentCommand.name} (no leading slash). */
|
|
181
|
+
name: string;
|
|
182
|
+
/** Raw argument string the user appended after the command, if any. */
|
|
183
|
+
args?: string;
|
|
184
|
+
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -24,5 +24,6 @@ export * from './models/session.js';
|
|
|
24
24
|
export * from './models/approval.js';
|
|
25
25
|
export * from './models/question.js';
|
|
26
26
|
export * from './models/usage.js';
|
|
27
|
+
export * from './models/metrics.js';
|
|
27
28
|
export * from './validators/validate.js';
|
|
28
29
|
export * from './validators/json-schema/schemas.js';
|
package/dist/src/index.js
CHANGED
|
@@ -30,6 +30,7 @@ export * from './models/session.js';
|
|
|
30
30
|
export * from './models/approval.js';
|
|
31
31
|
export * from './models/question.js';
|
|
32
32
|
export * from './models/usage.js';
|
|
33
|
+
export * from './models/metrics.js';
|
|
33
34
|
// Validators
|
|
34
35
|
export * from './validators/validate.js';
|
|
35
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;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,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", "agent/usageStats", "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,7 +53,12 @@ export const METHOD_NAMES = [
|
|
|
53
53
|
// Agents
|
|
54
54
|
'agent/list',
|
|
55
55
|
'agent/models',
|
|
56
|
+
'agent/commands',
|
|
56
57
|
'agent/usageStats',
|
|
58
|
+
// Metrics (bridge-owned, survivable profile stats + tamper-proof backup)
|
|
59
|
+
'metrics/get',
|
|
60
|
+
'metrics/export',
|
|
61
|
+
'metrics/import',
|
|
57
62
|
// Auth
|
|
58
63
|
'auth/status',
|
|
59
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,kBAAkB;IAClB,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"}
|
|
@@ -13,8 +13,9 @@ import type { ApprovalResponse } from '../models/approval.js';
|
|
|
13
13
|
import type { QuestionResponse } from '../models/question.js';
|
|
14
14
|
import type { BridgeStatus, ConnectedPhone, TrustedDevice } from '../models/session.js';
|
|
15
15
|
import type { PairingPayload } from '../e2ee/pairing-payload.js';
|
|
16
|
-
import type { AgentDescriptor, AgentId, AgentModel } from '../agents/agent-capabilities.js';
|
|
16
|
+
import type { AgentCommand, AgentCommandInvocation, AgentDescriptor, AgentId, AgentModel } from '../agents/agent-capabilities.js';
|
|
17
17
|
import type { UsageStatsParams, UsageStatsResult } from '../models/usage.js';
|
|
18
|
+
import type { MetricsExportParams, MetricsExportResult, MetricsImportParams, MetricsImportResult, MetricsSnapshot } from '../models/metrics.js';
|
|
18
19
|
import type { PushPlatform } from '../notifications/push-payload.js';
|
|
19
20
|
export interface ListThreadsParams {
|
|
20
21
|
projectId?: string;
|
|
@@ -82,6 +83,14 @@ export interface TurnSendParams {
|
|
|
82
83
|
* is not required.
|
|
83
84
|
*/
|
|
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;
|
|
85
94
|
}
|
|
86
95
|
export interface ThreadSetModelParams {
|
|
87
96
|
threadId: string;
|
|
@@ -220,6 +229,19 @@ export interface AgentModelsResult {
|
|
|
220
229
|
/** Models the agent can use, with presentation metadata, as reported by its CLI. */
|
|
221
230
|
models: AgentModel[];
|
|
222
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
|
+
}
|
|
223
245
|
/** What the phone wants to be notified about (background push). */
|
|
224
246
|
export interface NotificationPreferences {
|
|
225
247
|
/** Push when an agent turn completes. */
|
|
@@ -476,10 +498,26 @@ export interface JsonRpcMethodRegistry {
|
|
|
476
498
|
params: AgentModelsParams;
|
|
477
499
|
result: AgentModelsResult;
|
|
478
500
|
};
|
|
501
|
+
'agent/commands': {
|
|
502
|
+
params: AgentCommandsParams;
|
|
503
|
+
result: AgentCommandsResult;
|
|
504
|
+
};
|
|
479
505
|
'agent/usageStats': {
|
|
480
506
|
params: UsageStatsParams;
|
|
481
507
|
result: UsageStatsResult;
|
|
482
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
|
+
};
|
|
483
521
|
'auth/status': {
|
|
484
522
|
params: {
|
|
485
523
|
agentId: AgentId;
|
|
@@ -45,6 +45,18 @@ export interface ContentBlockParams {
|
|
|
45
45
|
turnId: string;
|
|
46
46
|
messageId: string;
|
|
47
47
|
content: unknown;
|
|
48
|
+
/**
|
|
49
|
+
* `true` when the block arrived from a **parallel/background** activity (e.g.
|
|
50
|
+
* a Claude Code subagent's tool run) while the assistant's main text was
|
|
51
|
+
* still streaming. The client must then insert the block BEFORE the
|
|
52
|
+
* currently-open text run instead of appending it after — appending would
|
|
53
|
+
* sever the run and render the sentence split mid-word by an activity card.
|
|
54
|
+
* Absent/false for the sequential case (the block lands at a real text-run
|
|
55
|
+
* boundary and is appended in arrival order). Mirrors how the bridge itself
|
|
56
|
+
* orders the block inside the persisted `Message.segments`, so the live view
|
|
57
|
+
* and a later `turn/list` re-sync render the identical interleave.
|
|
58
|
+
*/
|
|
59
|
+
beforeText?: boolean;
|
|
48
60
|
}
|
|
49
61
|
/**
|
|
50
62
|
* Token usage for a completed turn, as reported by the agent's CLI.
|
|
@@ -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"}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* user-pasted API keys.
|
|
16
16
|
*/
|
|
17
17
|
/** A coding CLI whose usage we read from its own stored token. */
|
|
18
|
-
export type UsageProvider = 'codex' | 'claude' | 'copilot' | 'gemini';
|
|
18
|
+
export type UsageProvider = 'codex' | 'claude' | 'copilot' | 'gemini' | 'grok';
|
|
19
19
|
/** Outcome of reading one provider's usage. */
|
|
20
20
|
export type UsageStatus =
|
|
21
21
|
/** Fresh quota/credit data was read. */
|
|
@@ -29,6 +29,22 @@ export type UsageStatus =
|
|
|
29
29
|
/** How the data was obtained, for the UI's provenance label. Every wired
|
|
30
30
|
* provider reads its quota from the CLI's own signed-in token. */
|
|
31
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';
|
|
32
48
|
/**
|
|
33
49
|
* A single quota/rate window, expressed as a used-percentage with an optional
|
|
34
50
|
* reset time — the atomic unit a provider reports (e.g. a 5-hour session, a
|
|
@@ -59,6 +75,32 @@ export interface CreditBalance {
|
|
|
59
75
|
period: string;
|
|
60
76
|
/** When the balance resets (epoch ms), when known. */
|
|
61
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[];
|
|
62
104
|
}
|
|
63
105
|
/** One provider's usage snapshot. */
|
|
64
106
|
export interface ProviderUsage {
|
|
@@ -70,10 +112,13 @@ export interface ProviderUsage {
|
|
|
70
112
|
email?: string;
|
|
71
113
|
organization?: string;
|
|
72
114
|
plan?: string;
|
|
115
|
+
accountType?: AccountType;
|
|
73
116
|
};
|
|
74
117
|
/** Quota/rate windows (percentage-based). Empty when none apply. */
|
|
75
118
|
windows: UsageWindow[];
|
|
76
119
|
credit?: CreditBalance;
|
|
120
|
+
/** Redeemable rate-limit resets (Codex), when the provider grants them. */
|
|
121
|
+
resetCredits?: ResetCredits;
|
|
77
122
|
/** When this snapshot was produced (epoch ms). */
|
|
78
123
|
updatedAt: number;
|
|
79
124
|
/** Error/hint message for `error` / `authRequired` / `notInstalled` states. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uxnan/shared",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7-alpha.20260719",
|
|
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",
|