@uxnan/shared 0.0.15-alpha.20260813 → 0.0.17-alpha.20260926

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.
Files changed (37) hide show
  1. package/README.md +6 -3
  2. package/agent-locations.json +82 -0
  3. package/dist/src/agents/agent-adapter.d.ts +14 -0
  4. package/dist/src/agents/agent-capabilities.d.ts +17 -3
  5. package/dist/src/agents/agent-locations.d.ts +61 -0
  6. package/dist/src/agents/agent-locations.js +124 -0
  7. package/dist/src/agents/agent-locations.js.map +1 -0
  8. package/dist/src/index.d.ts +4 -0
  9. package/dist/src/index.js +5 -0
  10. package/dist/src/index.js.map +1 -1
  11. package/dist/src/jsonrpc/method-registry.d.ts +1 -1
  12. package/dist/src/jsonrpc/method-registry.js +13 -0
  13. package/dist/src/jsonrpc/method-registry.js.map +1 -1
  14. package/dist/src/jsonrpc/methods.d.ts +81 -12
  15. package/dist/src/jsonrpc/notifications.d.ts +136 -14
  16. package/dist/src/jsonrpc/notifications.js +30 -2
  17. package/dist/src/jsonrpc/notifications.js.map +1 -1
  18. package/dist/src/local-control/local-control.d.ts +137 -0
  19. package/dist/src/local-control/local-control.js +68 -0
  20. package/dist/src/local-control/local-control.js.map +1 -0
  21. package/dist/src/models/project.d.ts +40 -1
  22. package/dist/src/models/project.js +5 -0
  23. package/dist/src/models/project.js.map +1 -1
  24. package/dist/src/models/session.d.ts +86 -0
  25. package/dist/src/models/session.js +0 -5
  26. package/dist/src/models/session.js.map +1 -1
  27. package/dist/src/models/sync.d.ts +88 -0
  28. package/dist/src/models/sync.js +2 -0
  29. package/dist/src/models/sync.js.map +1 -0
  30. package/dist/src/models/thread.d.ts +25 -0
  31. package/dist/src/models/tool.d.ts +68 -0
  32. package/dist/src/models/tool.js +11 -0
  33. package/dist/src/models/tool.js.map +1 -0
  34. package/dist/src/models/usage.d.ts +12 -3
  35. package/dist/src/models/usage.js +5 -2
  36. package/dist/src/models/usage.js.map +1 -1
  37. package/package.json +3 -2
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Replica sync: how a client converges on the bridge's shared state without
3
+ * trusting that it saw every notification (architecture/02a §5.8.17).
4
+ *
5
+ * The bridge numbers every change to shared state — a thread, a project, the
6
+ * shared settings — with one global, persisted, strictly increasing **revision**
7
+ * (`rev`), and keeps a bounded list of deletions. A client remembers the last
8
+ * `rev` it applied and asks `sync/changes { since }`:
9
+ *
10
+ * - on every (re)connect and app resume;
11
+ * - whenever a notification carries a `rev` that is not `last + 1` (it missed
12
+ * something in between).
13
+ *
14
+ * The answer is either the changes after `since` or, when the client cannot be
15
+ * served incrementally (`storeId` differs — a new state directory — or `since`
16
+ * predates the deletions the bridge still remembers), a full snapshot with
17
+ * `reset: true` that the client applies by replacing its replica.
18
+ */
19
+ import type { Project } from './project.js';
20
+ import type { Thread } from './thread.js';
21
+ import type { TrustedDevice } from './session.js';
22
+ /**
23
+ * Settings the bridge shares with every client, editable from any of them
24
+ * (`settings/set`) and from its own CLI (`uxnan-bridge config set`).
25
+ */
26
+ export interface BridgeSettings {
27
+ /**
28
+ * The folder the bridge starts from, whatever directory `start` ran in: where
29
+ * exploring for a new project begins, and the boundary a phone may register
30
+ * projects under. Defaults to the user's home directory.
31
+ */
32
+ home: string;
33
+ /**
34
+ * What every client calls this PC. Defaults to the machine's own name; any
35
+ * client, or `uxnan-bridge config set name`, can change it.
36
+ */
37
+ name: string;
38
+ }
39
+ export interface SettingsSetParams {
40
+ /** New start folder: an absolute path to an existing directory. */
41
+ home?: string;
42
+ /** New name for this PC; empty goes back to the machine's own name. */
43
+ name?: string;
44
+ /**
45
+ * See `ActionAgeMs`: a change made offline and sent now, applied to each
46
+ * setting only if nobody changed that setting later.
47
+ */
48
+ ageMs?: number;
49
+ }
50
+ export interface SyncChangesParams {
51
+ /** The last revision this client applied; absent on a first sync. */
52
+ since?: number;
53
+ /** The `storeId` that revision belongs to; a different one forces a reset. */
54
+ storeId?: string;
55
+ }
56
+ /** What kind of client is connected. */
57
+ export type ClientKind = 'phone' | 'desktop';
58
+ /** One client connected to the bridge right now. */
59
+ export interface ClientPresence {
60
+ /** Stable id: the phone's device id, or `local:<client>` for the desktop. */
61
+ id: string;
62
+ kind: ClientKind;
63
+ /** Human name (the phone's device name, the desktop's machine name). */
64
+ name: string;
65
+ /** When this connection opened (epoch ms). */
66
+ since: number;
67
+ }
68
+ export interface SyncChanges {
69
+ /** Identity of the bridge's state directory; changes only if it is recreated. */
70
+ storeId: string;
71
+ /** The revision this answer brings the client up to. */
72
+ rev: number;
73
+ /** True → a full snapshot: replace the replica instead of merging. */
74
+ reset: boolean;
75
+ settings: BridgeSettings;
76
+ /** Projects changed after `since` (all of them on a reset). */
77
+ projects: Project[];
78
+ /** Projects removed after `since` (empty on a reset). */
79
+ removedProjectIds: string[];
80
+ /** Threads changed after `since` (all of them on a reset). */
81
+ threads: Thread[];
82
+ /** Threads deleted after `since` (empty on a reset). */
83
+ removedThreadIds: string[];
84
+ /** Who is connected right now (live, not revisioned). */
85
+ clients: ClientPresence[];
86
+ /** Every paired phone, as it stands (small; always whole). */
87
+ devices: TrustedDevice[];
88
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../src/models/sync.ts"],"names":[],"mappings":""}
@@ -70,6 +70,13 @@ export interface Message {
70
70
  export interface Turn {
71
71
  id: string;
72
72
  threadId: string;
73
+ /**
74
+ * The turn's position in its thread (1-based, assigned by the bridge when the
75
+ * turn is stored, never reused). Clients order a conversation by it — never by
76
+ * the order notifications happened to arrive — so a turn a client missed and
77
+ * fetched later still lands in its place. Absent on an older bridge.
78
+ */
79
+ seq?: number;
73
80
  status: TurnStatus;
74
81
  messages: Message[];
75
82
  createdAt: number;
@@ -112,6 +119,14 @@ export interface Thread {
112
119
  agentSessionId?: string;
113
120
  /** Per-thread access (approval) mode; see {@link AccessMode}. */
114
121
  accessMode?: AccessMode;
122
+ /**
123
+ * Live, never persisted: the turn running on this thread right now, set by
124
+ * the bridge on `thread/list` and `thread/read` responses (the same value as
125
+ * `TurnList.activeTurnId`). Lets a client that just connected show which
126
+ * conversations are working without reading each one's turns. Absent when
127
+ * nothing runs.
128
+ */
129
+ activeTurnId?: string;
115
130
  /**
116
131
  * Where {@link title} came from, so a better title can replace a weaker one
117
132
  * without ever overwriting a name the **user** chose.
@@ -126,6 +141,16 @@ export interface Thread {
126
141
  * is what they are.
127
142
  */
128
143
  titleSource?: ThreadTitleSource;
144
+ /** Which client started the conversation, when known. */
145
+ origin?: ThreadOrigin;
146
+ /** Sync revision of the thread's last change (see `SyncChanges`). */
147
+ rev?: number;
148
+ }
149
+ /** Where a conversation was started. */
150
+ export interface ThreadOrigin {
151
+ kind: 'phone' | 'desktop';
152
+ /** The device's or machine's name. */
153
+ name: string;
129
154
  }
130
155
  /** Where a thread's title came from. See {@link Thread.titleSource}. */
131
156
  export type ThreadTitleSource = 'prompt' | 'agent' | 'user';
@@ -0,0 +1,68 @@
1
+ /**
2
+ * What a tool call did, in one vocabulary shared by every agent. Each agent
3
+ * names its tools its own way (`Read`, `read_file`, `view_file`, an ACP
4
+ * `kind`, a Codex item type…); the bridge classifies them once, so a client
5
+ * says "Read notes.txt" for all of them instead of learning every CLI.
6
+ *
7
+ * - `read`: read a file or an image
8
+ * - `search`: search file contents or names (grep, glob, find)
9
+ * - `list`: list a folder
10
+ * - `fetch`: fetch a URL
11
+ * - `web_search`: search the web
12
+ * - `mcp`: a tool of an MCP server
13
+ * - `other`: anything else — clients show the tool's name
14
+ */
15
+ export type ToolKind = 'read' | 'search' | 'list' | 'fetch' | 'web_search' | 'mcp' | 'other';
16
+ /** Every {@link ToolKind}, for validators and exhaustive checks. */
17
+ export declare const TOOL_KINDS: readonly ToolKind[];
18
+ /**
19
+ * A step shown while it runs. Any structured block may carry a `blockId`, the
20
+ * id of the step it stands for: a later block of the **same turn** with the
21
+ * same `blockId` replaces it in place — in the bridge's store and in every
22
+ * client's live view — so a step appears as it starts (`status: 'running'`,
23
+ * or `state.status: 'running'` for a subagent) and settles into its result
24
+ * where it stood. Once the turn ends a step is never running: the bridge
25
+ * settles any the agent left open, and a client treats a running step of a
26
+ * turn that is no longer live as settled.
27
+ */
28
+ export interface LiveBlock {
29
+ blockId?: string;
30
+ }
31
+ /**
32
+ * A tool call that is not a shell command, an edit, a plan or a subagent,
33
+ * as a `stream/content/block` (persisted with the assistant message).
34
+ */
35
+ export interface ToolContentBlock extends LiveBlock {
36
+ type: 'tool';
37
+ /** The agent's own name for the tool (`Read`, `grep`, `server/tool`…). */
38
+ toolName: string;
39
+ toolId: string;
40
+ input: Record<string, unknown>;
41
+ output?: string;
42
+ isError: boolean;
43
+ /** `running` while the call is in flight (see {@link LiveBlock}); absent once it finished. */
44
+ status?: 'running';
45
+ /** What the call did, classified by the bridge. */
46
+ kind: ToolKind;
47
+ /**
48
+ * What it acted on, ready to show: a path (relative to the project when it
49
+ * is inside it), a search pattern, a URL, a query. Absent when there is none.
50
+ */
51
+ target?: string;
52
+ }
53
+ /**
54
+ * A subagent the agent delegated to (Claude's `Agent`, OpenCode's `task`,
55
+ * Codex's collaboration tools, Antigravity's subagents): running, then
56
+ * finished with its report.
57
+ */
58
+ export interface SubagentContentBlock extends LiveBlock {
59
+ type: 'subagent';
60
+ state: {
61
+ id: string;
62
+ /** What the subagent was asked to do, in a few words. */
63
+ name: string;
64
+ status: 'running' | 'completed' | 'error';
65
+ /** Its final report, truncated for the wire. */
66
+ output?: string;
67
+ };
68
+ }
@@ -0,0 +1,11 @@
1
+ /** Every {@link ToolKind}, for validators and exhaustive checks. */
2
+ export const TOOL_KINDS = [
3
+ 'read',
4
+ 'search',
5
+ 'list',
6
+ 'fetch',
7
+ 'web_search',
8
+ 'mcp',
9
+ 'other',
10
+ ];
11
+ //# sourceMappingURL=tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../../../src/models/tool.ts"],"names":[],"mappings":"AAgBA,oEAAoE;AACpE,MAAM,CAAC,MAAM,UAAU,GAAwB;IAC7C,MAAM;IACN,QAAQ;IACR,MAAM;IACN,OAAO;IACP,YAAY;IACZ,KAAK;IACL,OAAO;CACR,CAAC"}
@@ -11,8 +11,11 @@
11
11
  * over `agent/usageStats`. The Dart equivalents live in uxnanmobile and are kept
12
12
  * in sync manually (see 02e-bridge-integration.md §4.2).
13
13
  *
14
- * Posture: only the CLI's own stored token is read — never browser cookies or
15
- * user-pasted API keys.
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.
16
19
  */
17
20
  /** A coding CLI whose usage we read from its own stored token. */
18
21
  export type UsageProvider = 'codex' | 'claude' | 'copilot' | 'grok';
@@ -22,6 +25,11 @@ export type UsageStatus =
22
25
  'ok'
23
26
  /** CLI is present but not signed in (no usable token). */
24
27
  | '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'
25
33
  /** CLI / its config directory is not present on this machine. */
26
34
  | 'notInstalled'
27
35
  /** Read/network/parse failure — see {@link ProviderUsage.message}. */
@@ -121,7 +129,8 @@ export interface ProviderUsage {
121
129
  resetCredits?: ResetCredits;
122
130
  /** When this snapshot was produced (epoch ms). */
123
131
  updatedAt: number;
124
- /** Error/hint message for `error` / `authRequired` / `notInstalled` states. */
132
+ /** Error/hint message for `error` / `authRequired` / `accessRequired` /
133
+ * `notInstalled` states. */
125
134
  message?: string;
126
135
  }
127
136
  /**
@@ -11,8 +11,11 @@
11
11
  * over `agent/usageStats`. The Dart equivalents live in uxnanmobile and are kept
12
12
  * in sync manually (see 02e-bridge-integration.md §4.2).
13
13
  *
14
- * Posture: only the CLI's own stored token is read — never browser cookies or
15
- * user-pasted API keys.
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.
16
19
  */
17
20
  export {};
18
21
  //# sourceMappingURL=usage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/models/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/models/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxnan/shared",
3
- "version": "0.0.15-alpha.20260813",
3
+ "version": "0.0.17-alpha.20260926",
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",
@@ -14,7 +14,8 @@
14
14
  }
15
15
  },
16
16
  "files": [
17
- "dist/src"
17
+ "dist/src",
18
+ "agent-locations.json"
18
19
  ],
19
20
  "engines": {
20
21
  "node": ">=18"