@uxnan/shared 0.0.6-alpha.20260716 → 0.0.8-alpha.20260720

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  ![TypeScript](https://img.shields.io/badge/TypeScript-ESM-3178C6?style=for-the-badge&logo=typescript&logoColor=white)
4
4
  ![Node.js](https://img.shields.io/badge/Node.js-%E2%89%A518-339933?style=for-the-badge&logo=nodedotjs&logoColor=white)
5
5
  ![JSON Schema](https://img.shields.io/badge/validation-Ajv-000000?style=for-the-badge&logo=json&logoColor=white)
6
- ![Contracts](https://img.shields.io/badge/60_methods_%7C_8_notifications-blue?style=for-the-badge)
6
+ ![Contracts](https://img.shields.io/badge/66_methods_%7C_8_notifications-blue?style=for-the-badge)
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
@@ -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
- ## Publish (planned)
93
+ ## Published
94
94
 
95
- `@uxnan/shared` is published to npm **first**; `uxnan-bridge` and `uxnan-relay`
96
- then pin `"@uxnan/shared": "^0.x"` instead of the `"*"` workspace spec they
97
- use today. See `bridge/FOR-DEV.md` *Packaging*.
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,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' | 'pi-agent'
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`). */
@@ -6,8 +6,29 @@
6
6
  *
7
7
  * Source: architecture/02a-system-architecture.md §5.9.1.
8
8
  */
9
- /** Secure transport protocol version negotiated in the handshake. */
10
- export declare const SECURE_PROTOCOL_VERSION = 1;
9
+ /**
10
+ * Secure transport protocol version negotiated in the handshake. Both sides
11
+ * reject a mismatch during `clientHello`/`serverHello`, so an incompatible pair
12
+ * fails fast and legibly instead of completing the handshake and then dropping
13
+ * every encrypted frame.
14
+ *
15
+ * **Bump this whenever the encrypted-frame format changes** (envelope shape,
16
+ * AAD layout, key derivation) — not just when the handshake JSON changes. The
17
+ * handshake is the only place the two sides can still talk, so it is the only
18
+ * place a version gap can be reported.
19
+ *
20
+ * - `1` — initial: AES-256-GCM over the envelope's ciphertext only.
21
+ * - `2` — `sessionId`/`seq`/direction bound as GCM AAD (`buildEnvelopeAad`).
22
+ */
23
+ export declare const SECURE_PROTOCOL_VERSION = 2;
24
+ /**
25
+ * AAD direction bytes for {@link SECURE_PROTOCOL_VERSION} ≥ 2. The session key
26
+ * is shared by both directions, so the direction is bound into the AAD to stop
27
+ * a frame being reflected back at its own sender as apparently-inbound traffic.
28
+ * Mirrored in the mobile `ProtocolConstants`.
29
+ */
30
+ export declare const ENVELOPE_DIRECTION_PHONE_TO_BRIDGE = 1;
31
+ export declare const ENVELOPE_DIRECTION_BRIDGE_TO_PHONE = 2;
11
32
  /** Version stamped into the pairing QR payload. */
12
33
  export declare const PAIRING_QR_VERSION = 2;
13
34
  /** HKDF `info` tag used when deriving the session key. */
@@ -6,8 +6,29 @@
6
6
  *
7
7
  * Source: architecture/02a-system-architecture.md §5.9.1.
8
8
  */
9
- /** Secure transport protocol version negotiated in the handshake. */
10
- export const SECURE_PROTOCOL_VERSION = 1;
9
+ /**
10
+ * Secure transport protocol version negotiated in the handshake. Both sides
11
+ * reject a mismatch during `clientHello`/`serverHello`, so an incompatible pair
12
+ * fails fast and legibly instead of completing the handshake and then dropping
13
+ * every encrypted frame.
14
+ *
15
+ * **Bump this whenever the encrypted-frame format changes** (envelope shape,
16
+ * AAD layout, key derivation) — not just when the handshake JSON changes. The
17
+ * handshake is the only place the two sides can still talk, so it is the only
18
+ * place a version gap can be reported.
19
+ *
20
+ * - `1` — initial: AES-256-GCM over the envelope's ciphertext only.
21
+ * - `2` — `sessionId`/`seq`/direction bound as GCM AAD (`buildEnvelopeAad`).
22
+ */
23
+ export const SECURE_PROTOCOL_VERSION = 2;
24
+ /**
25
+ * AAD direction bytes for {@link SECURE_PROTOCOL_VERSION} ≥ 2. The session key
26
+ * is shared by both directions, so the direction is bound into the AAD to stop
27
+ * a frame being reflected back at its own sender as apparently-inbound traffic.
28
+ * Mirrored in the mobile `ProtocolConstants`.
29
+ */
30
+ export const ENVELOPE_DIRECTION_PHONE_TO_BRIDGE = 0x01;
31
+ export const ENVELOPE_DIRECTION_BRIDGE_TO_PHONE = 0x02;
11
32
  /** Version stamped into the pairing QR payload. */
12
33
  export const PAIRING_QR_VERSION = 2;
13
34
  /** HKDF `info` tag used when deriving the session key. */
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,qEAAqE;AACrE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAEzC,mDAAmD;AACnD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAEpC,0DAA0D;AAC1D,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAE7C,0EAA0E;AAC1E,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAE1C,mEAAmE;AACnE,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE9C,gEAAgE;AAChE,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEhD,uEAAuE;AACvE,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEhD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,yBAAyB,GAAG,UAAU,CAAC;AAEpD,8BAA8B;AAC9B,MAAM,CAAC,MAAM,iBAAiB,GAAG,sBAAsB,CAAC;AAExD,yDAAyD;AACzD,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAEtC,wCAAwC;AACxC,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kCAAkC,GAAG,IAAI,CAAC;AACvD,MAAM,CAAC,MAAM,kCAAkC,GAAG,IAAI,CAAC;AAEvD,mDAAmD;AACnD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAEpC,0DAA0D;AAC1D,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAE7C,0EAA0E;AAC1E,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAE1C,mEAAmE;AACnE,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE9C,gEAAgE;AAChE,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEhD,uEAAuE;AACvE,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEhD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,yBAAyB,GAAG,UAAU,CAAC;AAEpD,8BAA8B;AAC9B,MAAM,CAAC,MAAM,iBAAiB,GAAG,sBAAsB,CAAC;AAExD,yDAAyD;AACzD,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAEtC,wCAAwC;AACxC,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC"}
@@ -5,8 +5,24 @@
5
5
  */
6
6
  export interface SecureEnvelope {
7
7
  kind: 'encryptedEnvelope';
8
+ /**
9
+ * Session this envelope belongs to. Travels in the clear (the receiver needs
10
+ * it before it can look up a key) and is therefore bound as GCM AAD — see
11
+ * {@link seq}.
12
+ */
8
13
  sessionId: string;
9
- /** Monotonic sequence number (replay protection). */
14
+ /**
15
+ * Monotonic sequence number (replay protection). Like `sessionId` it is
16
+ * visible on the wire, so from `SECURE_PROTOCOL_VERSION` 2 both are bound —
17
+ * together with a direction byte — as the AES-GCM **AAD**:
18
+ *
19
+ * AAD = utf8(sessionId) || 0x00 || u64_be(seq) || 0x00 || direction
20
+ *
21
+ * so tampering with either field fails the tag instead of silently passing an
22
+ * unauthenticated `seq <= lastApplied` check. Both implementations must build
23
+ * this byte-for-byte identically (`buildEnvelopeAad` on each side); see
24
+ * architecture/02a §5.9.1.
25
+ */
10
26
  seq: number;
11
27
  /** Per-message random nonce (hex, 12 bytes). */
12
28
  nonce: string;
@@ -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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxnan/shared",
3
- "version": "0.0.6-alpha.20260716",
3
+ "version": "0.0.8-alpha.20260720",
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",