@uxnan/shared 0.0.12-alpha.20260803 → 0.0.14-alpha.20260810

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/69_methods_%7C_10_notifications-blue?style=for-the-badge)
6
+ ![Contracts](https://img.shields.io/badge/69_methods_%7C_12_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
@@ -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 — **69 JSON-RPC methods** + **10 streaming
16
+ > **Status:** implemented and stable — **70 JSON-RPC methods** + **12 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
@@ -62,6 +62,15 @@ export interface SendTurnOptions {
62
62
  */
63
63
  command?: AgentCommandInvocation;
64
64
  }
65
+ /** Input for {@link IAgentAdapter.generateTitle}. */
66
+ export interface GenerateTitleOptions {
67
+ /** The user's opening message. */
68
+ userText: string;
69
+ /** The agent's reply to it, when there is one (trimmed by the caller). */
70
+ assistantText?: string;
71
+ /** Working directory to run the one-shot in (the thread's own). */
72
+ cwd?: string;
73
+ }
65
74
  export interface IAgentAdapter {
66
75
  readonly agentId: AgentId;
67
76
  readonly capabilities: AgentCapabilities;
@@ -73,6 +82,46 @@ export interface IAgentAdapter {
73
82
  sendTurn(options: SendTurnOptions): Promise<void>;
74
83
  /** Cancel an in-flight turn. */
75
84
  cancelTurn(threadId: string, turnId: string): Promise<void>;
85
+ /**
86
+ * Name a conversation from its opening exchange — a handful of words, no
87
+ * punctuation, in the language the user wrote in.
88
+ *
89
+ * **This is a side errand, not a turn.** Implementations run a fresh one-shot
90
+ * with **no session id**, so nothing lands in the thread's history, no
91
+ * streaming event is emitted, and the agent's own context is untouched. It is
92
+ * also expected to use the agent's *cheapest* model rather than the one the
93
+ * conversation runs on: naming is a trivial task and should never spend the
94
+ * expensive model's quota.
95
+ *
96
+ * Optional — an adapter that cannot do it cheaply simply omits it, and the
97
+ * thread keeps the provisional title derived from the opening message.
98
+ *
99
+ * Returns the bare title, or `undefined` when the agent produced nothing
100
+ * usable. **Never throws for an ordinary failure** (no credit, CLI missing,
101
+ * a timeout): titling is cosmetic and must not disturb a working thread.
102
+ */
103
+ generateTitle?(options: GenerateTitleOptions): Promise<string | undefined>;
104
+ /**
105
+ * Hand a follow-up to the agent **inside the turn already running** — what a
106
+ * CLI does when you type while it works and it picks the message up at the
107
+ * next tool boundary. Implemented only by adapters whose CLI has an input
108
+ * channel mid-turn; those advertise `AgentCapabilities.steering`.
109
+ *
110
+ * `activeTurnId` is the bridge turn currently in flight on the thread, so the
111
+ * adapter can address the right run (and refuse if it has already moved on).
112
+ * `turnId` is the queued turn the text came from — it does NOT start a run of
113
+ * its own; it exists so the bridge can mark it `delivered`.
114
+ *
115
+ * Returns **true only when the agent actually took the message**. Return
116
+ * `false` (don't throw) for an ordinary "too late / not applicable" — the
117
+ * turn ended between the check and the call, the protocol rejected the
118
+ * hand-off. The bridge then leaves the turn queued and it runs normally next,
119
+ * so a refusal costs the user nothing but a wait. Throwing is for a broken
120
+ * transport, and is handled the same way.
121
+ */
122
+ steerTurn?(options: SendTurnOptions & {
123
+ activeTurnId: string;
124
+ }): Promise<boolean>;
76
125
  /**
77
126
  * Reply to a pending approval the agent emitted (as an `approval` content
78
127
  * block) for {@link threadId}. Optional: adapters that never request approval
@@ -114,7 +163,7 @@ export interface IAgentAdapter {
114
163
  * reachable headless plus user-defined prompt-template commands scanned from
115
164
  * disk (optional; adapters with none simply don't implement it). `cwd` is the
116
165
  * thread/project directory so project-scoped custom commands (`<cwd>/.claude/
117
- * commands`, `<cwd>/.gemini/commands`, …) are discovered alongside user-level
166
+ * commands`, `<cwd>/.opencode/command`, …) are discovered alongside user-level
118
167
  * ones. Discovery only; invocation flows through {@link sendTurn} with {@link
119
168
  * SendTurnOptions.command}.
120
169
  */
@@ -123,7 +172,7 @@ export interface IAgentAdapter {
123
172
  * Resolve a custom prompt-template command to the final prompt text (reads the
124
173
  * template file from `cwd`/user config, substitutes arguments). Implemented
125
174
  * only by adapters whose commands are prompt templates the bridge expands
126
- * itself (Codex/Gemini/OpenCode); adapters whose commands run natively (Claude
175
+ * itself (Codex/OpenCode); adapters whose commands run natively (Claude
127
176
  * Code, ACP agents) leave it unset and receive the composed `/name args` form
128
177
  * as {@link SendTurnOptions.text}. Throw if `name` is not a known custom command.
129
178
  */
@@ -4,9 +4,7 @@
4
4
  * Source: architecture/02a-system-architecture.md §5.8.2 (adapters).
5
5
  */
6
6
  export type AgentId = 'codex' | 'opencode' | 'claude-code'
7
- /** @deprecated The standalone Gemini CLI is retired; use `antigravity-cli`. */
8
- | 'gemini-cli'
9
- /** Antigravity — Google's `agy` CLI, the successor to the deprecated Gemini CLI. */
7
+ /** Antigravity — Google's supported `agy` CLI. */
10
8
  | 'antigravity-cli' | 'pi-agent'
11
9
  /** Zero — open-source Go coding agent, driven over the Agent Client Protocol. */
12
10
  | 'zero'
@@ -53,6 +51,19 @@ export interface AgentCapabilities {
53
51
  * only its client-side `/` palette). See {@link AgentCommand}.
54
52
  */
55
53
  commands?: boolean;
54
+ /**
55
+ * Agent can take a follow-up **into the turn already running** instead of
56
+ * making it wait for the next one — what a CLI does when you type while it
57
+ * works and it picks the message up at the next tool boundary. The bridge
58
+ * hands such a turn straight to the adapter (`IAgentAdapter.steerTurn`)
59
+ * rather than holding it, and marks it `delivered` (see `TurnStatus`).
60
+ *
61
+ * Optional; absent/false means the agent has no input channel mid-turn (a
62
+ * one-shot CLI, or a protocol that serializes prompts per session), and its
63
+ * follow-ups keep waiting for the current turn to end. The phone reads this
64
+ * to tell the user which of the two is about to happen.
65
+ */
66
+ steering?: boolean;
56
67
  }
57
68
  /**
58
69
  * A registered agent the phone can pick for a thread, returned by `agent/list`.
@@ -155,7 +166,7 @@ export interface AgentModel {
155
166
  * (Claude Code's `/compact` sent as the prompt with `--resume`; the commands
156
167
  * ACP agents advertise via `available_commands_update`), and
157
168
  * - **custom** user-defined prompt-template commands (`.claude/commands`,
158
- * `~/.codex/prompts`, `.gemini/commands`, `.opencode/command`) that the bridge
169
+ * `~/.codex/prompts`, `.opencode/command`) that the bridge
159
170
  * expands itself before running a normal turn.
160
171
  *
161
172
  * The phone is a generic renderer: it lists the advertised commands in its `/`
@@ -3,5 +3,5 @@
3
3
  * compile-time {@link JsonRpcMethodRegistry} via the assertion below.
4
4
  */
5
5
  import type { JsonRpcMethodName } from './methods.js';
6
- export declare const METHOD_NAMES: readonly ["thread/list", "thread/read", "thread/start", "thread/resume", "thread/fork", "thread/setModel", "thread/rename", "thread/setAccessMode", "thread/archive", "thread/unarchive", "thread/delete", "turn/list", "turn/read", "turn/send", "turn/cancel", "queue/resume", "queue/clear", "git/status", "git/diff", "git/commit", "git/push", "git/pull", "git/checkout", "git/createBranch", "git/createWorktree", "git/stage", "git/unstage", "git/discard", "git/createPr", "git/undoCommit", "git/branches", "git/switchBranch", "git/revert", "git/deleteBranch", "git/removeWorktree", "git/log", "git/commitShow", "workspace/readFile", "workspace/readImage", "workspace/list", "workspace/searchFiles", "workspace/resolveFileLink", "workspace/browseDirs", "workspace/checkpoint", "workspace/diffCheckpoint", "workspace/applyCheckpoint", "workspace/applyPatch", "workspace/exists", "project/list", "project/resolve", "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"];
6
+ export declare const METHOD_NAMES: readonly ["thread/list", "thread/read", "thread/start", "thread/resume", "thread/fork", "thread/setModel", "thread/rename", "thread/setAccessMode", "thread/archive", "thread/unarchive", "thread/delete", "turn/list", "turn/read", "turn/send", "turn/cancel", "queue/resume", "queue/clear", "git/status", "git/diff", "git/commit", "git/push", "git/pull", "git/checkout", "git/createBranch", "git/createWorktree", "git/stage", "git/unstage", "git/discard", "git/createPr", "git/undoCommit", "git/branches", "git/switchBranch", "git/revert", "git/deleteBranch", "git/removeWorktree", "git/worktrees", "git/log", "git/commitShow", "workspace/readFile", "workspace/readImage", "workspace/list", "workspace/searchFiles", "workspace/resolveFileLink", "workspace/browseDirs", "workspace/checkpoint", "workspace/diffCheckpoint", "workspace/applyCheckpoint", "workspace/applyPatch", "workspace/exists", "project/list", "project/resolve", "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;
@@ -37,6 +37,7 @@ export const METHOD_NAMES = [
37
37
  'git/revert',
38
38
  'git/deleteBranch',
39
39
  'git/removeWorktree',
40
+ 'git/worktrees',
40
41
  'git/log',
41
42
  'git/commitShow',
42
43
  // Workspace
@@ -1 +1 @@
1
- {"version":3,"file":"method-registry.js","sourceRoot":"","sources":["../../../src/jsonrpc/method-registry.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,kBAAkB;IAClB,aAAa;IACb,aAAa;IACb,cAAc;IACd,eAAe;IACf,aAAa;IACb,iBAAiB;IACjB,eAAe;IACf,sBAAsB;IACtB,gBAAgB;IAChB,kBAAkB;IAClB,eAAe;IACf,WAAW;IACX,WAAW;IACX,WAAW;IACX,aAAa;IACb,gBAAgB;IAChB,cAAc;IACd,aAAa;IACb,MAAM;IACN,YAAY;IACZ,UAAU;IACV,YAAY;IACZ,UAAU;IACV,UAAU;IACV,cAAc;IACd,kBAAkB;IAClB,oBAAoB;IACpB,WAAW;IACX,aAAa;IACb,aAAa;IACb,cAAc;IACd,gBAAgB;IAChB,cAAc;IACd,kBAAkB;IAClB,YAAY;IACZ,kBAAkB;IAClB,oBAAoB;IACpB,SAAS;IACT,gBAAgB;IAChB,YAAY;IACZ,oBAAoB;IACpB,qBAAqB;IACrB,gBAAgB;IAChB,uBAAuB;IACvB,2BAA2B;IAC3B,sBAAsB;IACtB,sBAAsB;IACtB,0BAA0B;IAC1B,2BAA2B;IAC3B,sBAAsB;IACtB,kBAAkB;IAClB,WAAW;IACX,cAAc;IACd,iBAAiB;IACjB,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"}
1
+ {"version":3,"file":"method-registry.js","sourceRoot":"","sources":["../../../src/jsonrpc/method-registry.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,kBAAkB;IAClB,aAAa;IACb,aAAa;IACb,cAAc;IACd,eAAe;IACf,aAAa;IACb,iBAAiB;IACjB,eAAe;IACf,sBAAsB;IACtB,gBAAgB;IAChB,kBAAkB;IAClB,eAAe;IACf,WAAW;IACX,WAAW;IACX,WAAW;IACX,aAAa;IACb,gBAAgB;IAChB,cAAc;IACd,aAAa;IACb,MAAM;IACN,YAAY;IACZ,UAAU;IACV,YAAY;IACZ,UAAU;IACV,UAAU;IACV,cAAc;IACd,kBAAkB;IAClB,oBAAoB;IACpB,WAAW;IACX,aAAa;IACb,aAAa;IACb,cAAc;IACd,gBAAgB;IAChB,cAAc;IACd,kBAAkB;IAClB,YAAY;IACZ,kBAAkB;IAClB,oBAAoB;IACpB,eAAe;IACf,SAAS;IACT,gBAAgB;IAChB,YAAY;IACZ,oBAAoB;IACpB,qBAAqB;IACrB,gBAAgB;IAChB,uBAAuB;IACvB,2BAA2B;IAC3B,sBAAsB;IACtB,sBAAsB;IACtB,0BAA0B;IAC1B,2BAA2B;IAC3B,sBAAsB;IACtB,kBAAkB;IAClB,WAAW;IACX,cAAc;IACd,iBAAiB;IACjB,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"}
@@ -6,7 +6,7 @@
6
6
  * uxnandesktop/architecture/02e-bridge-integration.md §4.4.
7
7
  */
8
8
  import type { AccessMode, QueuePausedReason, Thread, ThreadList, Turn, TurnList } from '../models/thread.js';
9
- import type { GitBranchList, GitBranchResult, GitCommitDetails, GitCommitResult, GitCommitShowParams, GitDiff, GitLogParams, GitLogResult, GitPrResult, GitPullResult, GitPushResult, GitRepoStatus, GitWorktreeResult } from '../models/git.js';
9
+ import type { GitBranchList, GitBranchResult, GitCommitDetails, GitCommitResult, GitCommitShowParams, GitDiff, GitLogParams, GitLogResult, GitPrResult, GitPullResult, GitPushResult, GitRepoStatus, GitWorktreeList, GitWorktreeResult } from '../models/git.js';
10
10
  import type { ApplyResult, BrowseResult, Checkpoint, CheckpointDiff, FileContent, ImageContent, PatchChange, TurnAttachment, WorkspaceFileTarget, 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';
@@ -99,7 +99,7 @@ export interface TurnSendParams {
99
99
  * wants to handle the busy case itself).
100
100
  * - absent — **queue it anyway**. Queueing is the safe default because the
101
101
  * bridge can only drive ONE turn per thread: half the agents run one-shot
102
- * per turn (`claude -p --resume`, gemini, pi, antigravity) and a second
102
+ * per turn (`claude -p --resume`, pi, antigravity) and a second
103
103
  * concurrent turn would put two CLI processes on the same session.
104
104
  *
105
105
  * Ignored when no turn is in flight — the turn simply starts.
@@ -114,6 +114,16 @@ export interface ThreadRenameParams {
114
114
  threadId: string;
115
115
  /** New, non-empty title for the thread. */
116
116
  title: string;
117
+ /**
118
+ * Who is naming it. **Absent means the user did** — the safe default, since
119
+ * `thread/rename` is the hand-rename call and a name the user chose is final.
120
+ *
121
+ * A client that auto-names a new thread from its opening message MUST send
122
+ * `'prompt'`; otherwise its throwaway title is recorded as the user's choice
123
+ * and the real generated title is refused later. `'agent'` is not accepted
124
+ * here — the bridge writes those itself when it generates one.
125
+ */
126
+ source?: 'prompt' | 'user';
117
127
  }
118
128
  export interface ThreadSetAccessModeParams {
119
129
  threadId: string;
@@ -130,6 +140,17 @@ export interface TurnSendResult {
130
140
  queued?: boolean;
131
141
  /** 1-based place in the queue when `queued` is true (1 = runs next). */
132
142
  queuePosition?: number;
143
+ /**
144
+ * True when the agent took the message **into the turn already running**
145
+ * rather than making it wait (status `delivered`, see `TurnStatus`). It will
146
+ * never run as a turn of its own — the reply belongs to the turn it joined —
147
+ * so the client renders the user's message in place and stops offering to
148
+ * edit or cancel it. Mutually exclusive with {@link queued}.
149
+ *
150
+ * Only ever true when the agent advertises `AgentCapabilities.steering`; on
151
+ * every other agent a follow-up still comes back `queued`.
152
+ */
153
+ delivered?: boolean;
133
154
  }
134
155
  export interface QueueStateResult {
135
156
  /** Queued turn ids in drain order. */
@@ -263,7 +284,7 @@ export interface AgentCommandsParams {
263
284
  agentId: AgentId;
264
285
  /**
265
286
  * Thread/project directory, so project-scoped custom commands (e.g.
266
- * `<cwd>/.claude/commands`, `<cwd>/.gemini/commands`) are discovered alongside
287
+ * `<cwd>/.claude/commands`, `<cwd>/.opencode/command`) are discovered alongside
267
288
  * the user-level ones. Omitted → only user-level commands are returned.
268
289
  */
269
290
  cwd?: string;
@@ -464,6 +485,13 @@ export interface JsonRpcMethodRegistry {
464
485
  params: GitRemoveWorktreeParams;
465
486
  result: void;
466
487
  };
488
+ /** Which directories are worktrees of the repository at `cwd`. */
489
+ 'git/worktrees': {
490
+ params: {
491
+ cwd: string;
492
+ };
493
+ result: GitWorktreeList;
494
+ };
467
495
  'git/log': {
468
496
  params: GitLogParams;
469
497
  result: GitLogResult;
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Source: architecture/02b-contracts-and-requirements.md (streaming events).
5
5
  */
6
- import type { QueuePausedReason } from '../models/thread.js';
6
+ import type { QueuePausedReason, ThreadTitleSource } from '../models/thread.js';
7
7
  export declare const StreamNotification: {
8
8
  readonly TurnStarted: "stream/turn/started";
9
9
  readonly MessageDelta: "stream/message/delta";
@@ -16,10 +16,17 @@ export declare const StreamNotification: {
16
16
  readonly TurnAborted: "stream/turn/aborted";
17
17
  /** A queued turn was removed before it ever ran (status → `cancelled`). */
18
18
  readonly TurnCancelled: "stream/turn/cancelled";
19
+ /**
20
+ * A queued turn was handed to the agent **inside the turn already running**
21
+ * instead of waiting for it (status → `delivered`).
22
+ */
23
+ readonly TurnDelivered: "stream/turn/delivered";
19
24
  /** The thread's message queue changed (queued, drained, cancelled, paused). */
20
25
  readonly QueueUpdated: "stream/queue/updated";
21
26
  /** The agent resolved an alias (e.g. `opus`) to a concrete model id for this turn. */
22
27
  readonly ModelResolved: "stream/model/resolved";
28
+ /** A thread's title changed on the bridge (a generated title, or another device's rename). */
29
+ readonly ThreadRenamed: "stream/thread/renamed";
23
30
  };
24
31
  export type StreamNotification = (typeof StreamNotification)[keyof typeof StreamNotification];
25
32
  export interface TurnStartedParams {
@@ -103,6 +110,22 @@ export interface TurnCancelledParams {
103
110
  threadId: string;
104
111
  turnId: string;
105
112
  }
113
+ /**
114
+ * A queued turn reached the agent **without waiting**: it was folded into the
115
+ * turn that was already running (its status is now `delivered`), the way a CLI
116
+ * picks up what you typed while it worked. It will never run as a turn of its
117
+ * own — the answer is part of `intoTurnId`.
118
+ *
119
+ * The client keeps the user's message where it is and stops offering to edit or
120
+ * cancel it: the agent already has it.
121
+ */
122
+ export interface TurnDeliveredParams {
123
+ threadId: string;
124
+ /** The queued turn that was handed over. */
125
+ turnId: string;
126
+ /** The running turn it was folded into; its reply covers both messages. */
127
+ intoTurnId: string;
128
+ }
106
129
  /**
107
130
  * The thread's message queue changed. Carries the WHOLE state rather than a
108
131
  * delta, so it is idempotent: a client that missed one (backgrounded, mid-
@@ -126,3 +149,18 @@ export interface ModelResolvedParams {
126
149
  /** Concrete model id the agent resolved for this turn (e.g. `claude-opus-4-8`). */
127
150
  model: string;
128
151
  }
152
+ /**
153
+ * A thread's title changed **on the bridge**, so every client converges without
154
+ * refetching the list. Emitted when a generated title replaces the provisional
155
+ * one taken from the opening message, and when another device renames a thread.
156
+ *
157
+ * `titleSource` says how much to trust it: `user` is final, `agent` is the
158
+ * generated name, `prompt` the weak fallback. A client MUST NOT let an `agent`
159
+ * title overwrite a `user` one — the bridge already enforces that, and this
160
+ * field is what lets a client reason about it too.
161
+ */
162
+ export interface ThreadRenamedParams {
163
+ threadId: string;
164
+ title: string;
165
+ titleSource: ThreadTitleSource;
166
+ }
@@ -10,9 +10,16 @@ export const StreamNotification = {
10
10
  TurnAborted: 'stream/turn/aborted',
11
11
  /** A queued turn was removed before it ever ran (status → `cancelled`). */
12
12
  TurnCancelled: 'stream/turn/cancelled',
13
+ /**
14
+ * A queued turn was handed to the agent **inside the turn already running**
15
+ * instead of waiting for it (status → `delivered`).
16
+ */
17
+ TurnDelivered: 'stream/turn/delivered',
13
18
  /** The thread's message queue changed (queued, drained, cancelled, paused). */
14
19
  QueueUpdated: 'stream/queue/updated',
15
20
  /** The agent resolved an alias (e.g. `opus`) to a concrete model id for this turn. */
16
21
  ModelResolved: 'stream/model/resolved',
22
+ /** A thread's title changed on the bridge (a generated title, or another device's rename). */
23
+ ThreadRenamed: 'stream/thread/renamed',
17
24
  };
18
25
  //# sourceMappingURL=notifications.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../../src/jsonrpc/notifications.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,WAAW,EAAE,qBAAqB;IAClC,YAAY,EAAE,sBAAsB;IACpC,kFAAkF;IAClF,aAAa,EAAE,uBAAuB;IACtC,mFAAmF;IACnF,YAAY,EAAE,sBAAsB;IACpC,aAAa,EAAE,uBAAuB;IACtC,SAAS,EAAE,mBAAmB;IAC9B,WAAW,EAAE,qBAAqB;IAClC,2EAA2E;IAC3E,aAAa,EAAE,uBAAuB;IACtC,+EAA+E;IAC/E,YAAY,EAAE,sBAAsB;IACpC,sFAAsF;IACtF,aAAa,EAAE,uBAAuB;CAC9B,CAAC"}
1
+ {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../../src/jsonrpc/notifications.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,WAAW,EAAE,qBAAqB;IAClC,YAAY,EAAE,sBAAsB;IACpC,kFAAkF;IAClF,aAAa,EAAE,uBAAuB;IACtC,mFAAmF;IACnF,YAAY,EAAE,sBAAsB;IACpC,aAAa,EAAE,uBAAuB;IACtC,SAAS,EAAE,mBAAmB;IAC9B,WAAW,EAAE,qBAAqB;IAClC,2EAA2E;IAC3E,aAAa,EAAE,uBAAuB;IACtC;;;OAGG;IACH,aAAa,EAAE,uBAAuB;IACtC,+EAA+E;IAC/E,YAAY,EAAE,sBAAsB;IACpC,sFAAsF;IACtF,aAAa,EAAE,uBAAuB;IACtC,8FAA8F;IAC9F,aAAa,EAAE,uBAAuB;CAC9B,CAAC"}
@@ -53,6 +53,28 @@ export interface GitWorktreeResult {
53
53
  path: string;
54
54
  branch: string;
55
55
  }
56
+ /**
57
+ * One entry of `git worktree list --porcelain`.
58
+ *
59
+ * A repository's worktrees are siblings on disk, not children — a checkout of
60
+ * `repo` at `../repo-feature` is a peer directory with no path relationship to
61
+ * its main worktree. That is precisely why a client cannot infer the hierarchy
62
+ * from paths alone and has to be told.
63
+ */
64
+ export interface GitWorktreeEntry {
65
+ /** Absolute path of the worktree. */
66
+ path: string;
67
+ /** Checked-out branch; absent when the worktree is in a detached HEAD. */
68
+ branch?: string;
69
+ /** Whether this is the repository's main worktree. */
70
+ isMain: boolean;
71
+ /** Whether `git worktree lock` has been applied to it. */
72
+ isLocked?: boolean;
73
+ }
74
+ export interface GitWorktreeList {
75
+ /** The main worktree first, then the linked ones in git's own order. */
76
+ worktrees: GitWorktreeEntry[];
77
+ }
56
78
  export interface GitBranchList {
57
79
  /** The currently checked-out branch (`HEAD` when detached). */
58
80
  current: string;
@@ -60,4 +60,16 @@ export interface BridgeFeatures {
60
60
  * that bridge.
61
61
  */
62
62
  messageQueue?: boolean;
63
+ /**
64
+ * The bridge can hand a queued turn to the agent **inside the turn already
65
+ * running**, for agents whose CLI has an input channel mid-turn — it marks
66
+ * that turn `delivered` and emits `stream/turn/delivered`. Absent/false → the
67
+ * client must expect every follow-up to wait for the current turn to end, and
68
+ * must not promise otherwise in its UI.
69
+ *
70
+ * Distinct from {@link messageQueue}, which this builds on: the queue is where
71
+ * a follow-up lands, and per-agent `AgentCapabilities.steering` decides
72
+ * whether it waits there or goes straight through.
73
+ */
74
+ midTurnDelivery?: boolean;
63
75
  }
@@ -17,8 +17,14 @@ export type MessageRole = 'user' | 'assistant' | 'system' | 'tool';
17
17
  * thread (never deleted) so the user's message stays visible with a "cancelled"
18
18
  * mark instead of silently vanishing; distinct from `aborted` precisely so a
19
19
  * client can tell "never ran" from "interrupted".
20
+ * - `delivered` — it was QUEUED and the agent took it **into the turn already
21
+ * running** (see `AgentCapabilities.steering`), so it will never run as a turn
22
+ * of its own: the answer is part of the turn it was folded into
23
+ * (`deliveredIntoTurnId`). Terminal and successful — distinct from `cancelled`
24
+ * precisely because the message DID reach the agent; the user's bubble stays,
25
+ * with no assistant reply hanging off it.
20
26
  */
21
- export type TurnStatus = 'queued' | 'pending' | 'streaming' | 'completed' | 'error' | 'aborted' | 'cancelled';
27
+ export type TurnStatus = 'queued' | 'pending' | 'streaming' | 'completed' | 'error' | 'aborted' | 'cancelled' | 'delivered';
22
28
  export type ThreadStatus = 'active' | 'idle' | 'archived';
23
29
  /**
24
30
  * Why a thread's message queue is held instead of draining:
@@ -68,6 +74,12 @@ export interface Turn {
68
74
  messages: Message[];
69
75
  createdAt: number;
70
76
  completedAt?: number;
77
+ /**
78
+ * For a `delivered` turn: the id of the turn its message was folded into.
79
+ * The reply lives there, so a client renders this turn's user message in
80
+ * place and expects no assistant message of its own. Absent otherwise.
81
+ */
82
+ deliveredIntoTurnId?: string;
71
83
  }
72
84
  /**
73
85
  * Per-thread access (approval) mode: how much the agent may do before it must
@@ -100,7 +112,23 @@ export interface Thread {
100
112
  agentSessionId?: string;
101
113
  /** Per-thread access (approval) mode; see {@link AccessMode}. */
102
114
  accessMode?: AccessMode;
115
+ /**
116
+ * Where {@link title} came from, so a better title can replace a weaker one
117
+ * without ever overwriting a name the **user** chose.
118
+ *
119
+ * - `prompt` — provisional, derived from the opening message. Instant, and
120
+ * the weakest: two conversations that start with the same phrase collide.
121
+ * - `agent` — written by a model that read the first exchange. Replaces
122
+ * `prompt`, never `user`.
123
+ * - `user` — renamed by hand (`thread/rename`). Final; nothing overwrites it.
124
+ *
125
+ * Absent on threads stored before this existed; treat that as `prompt`, which
126
+ * is what they are.
127
+ */
128
+ titleSource?: ThreadTitleSource;
103
129
  }
130
+ /** Where a thread's title came from. See {@link Thread.titleSource}. */
131
+ export type ThreadTitleSource = 'prompt' | 'agent' | 'user';
104
132
  export interface ThreadList {
105
133
  threads: Thread[];
106
134
  }
@@ -15,9 +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'
19
- /** @deprecated Legacy read-only usage source for retired Gemini CLI installs. */
20
- | 'gemini' | 'grok';
18
+ export type UsageProvider = 'codex' | 'claude' | 'copilot' | 'grok';
21
19
  /** Outcome of reading one provider's usage. */
22
20
  export type UsageStatus =
23
21
  /** Fresh quota/credit data was read. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxnan/shared",
3
- "version": "0.0.12-alpha.20260803",
3
+ "version": "0.0.14-alpha.20260810",
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",