@uxnan/shared 0.0.22-alpha.20260927 → 0.0.23-alpha.20260927

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
@@ -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 — **87 JSON-RPC methods** + **22 streaming
16
+ > **Status:** implemented and stable — **93 JSON-RPC methods** + **24 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
@@ -49,14 +49,15 @@ flowchart TB
49
49
 
50
50
  | Area | Exports |
51
51
  |---|---|
52
- | JSON-RPC | envelope types + constructors (`makeRequest`, `makeNotification`, `makeResponse`, `makeErrorResponse`), error codes (`JsonRpcErrorCode` + Uxnan-specific `-32000..-32009`), `RpcError`, typed method registry (`JsonRpcMethodRegistry` + `METHOD_NAMES`), `isKnownMethod` |
52
+ | JSON-RPC | envelope types + constructors (`makeRequest`, `makeNotification`, `makeResponse`, `makeErrorResponse`), error codes (`JsonRpcErrorCode` + Uxnan-specific `-32000..-32010`), `RpcError`, typed method registry (`JsonRpcMethodRegistry` + `METHOD_NAMES`), `isKnownMethod` |
53
53
  | Streaming | `StreamNotification` enum + param types (`TurnStartedParams`, `MessageDeltaParams`, `ThinkingDeltaParams`, `ContentBlockParams`, `TurnCompletedParams`, `TurnUsage`, `TurnErrorParams`, `TurnAbortedParams`, `ModelResolvedParams`, and the multi-client set: `ThreadUpdatedParams`, `ThreadDeletedParams`, `TurnCreatedParams`, `ApprovalResolvedParams`, `QuestionResolvedParams`) |
54
54
  | Local control | the loopback channel Uxnan Desktop uses on the bridge's machine: `LOCAL_CONTROL_FILE` / `LOCAL_CONTROL_PATH`, `LocalControlDiscovery`, the `LocalControlFrame` union (`hello` + `message`), `isValidLocalClientId`, `localReceiverId` (architecture/02a §5.8.15) |
55
55
  | Replica sync | `sync/changes` (`SyncChanges`: revisioned threads, projects, settings, deletions, presence), `BridgeSettings { home }`, `ClientPresence`, `Project` registry fields, `Turn.seq`, `Thread.origin` (`src/models/sync.ts`, architecture/02a §5.8.17) |
56
56
  | Agent locations | `agent-locations.json` (package root) + `locateAgent` / `agentLocation`: where every agent CLI installs — the one table the bridge and Uxnan Desktop resolve from |
57
57
  | E2EE | handshake messages (`clientHello` / `serverHello` / `clientAuth` / `ready`), `buildHandshakeTranscript`, `SecureEnvelope`, `PairingPayload` v2 (`relay` optional + `hosts: string[]`) with `Base64(utf8(JSON))` QR encoding |
58
58
  | Models | thread / turn / message (with `MessageContent` polymorphic blocks), durable `CompactionContentBlock` and `AssistantResponseBoundaryBlock`, git, workspace (incl. `browseDirs` + `exists`), project, auth, session/trust (`BridgeStatus` incl. `latestVersion?`/`updateAvailable?`), bridge-owned profile metrics (complete-ledger export/import), approval, question (interactive multiple-choice) |
59
- | Agents | `IAgentAdapter` (with `respondApproval`, `listModels`, `nativeSessionId`, `SendTurnOptions { threadId, turnId, text, service?, effort?, options?, attachments?, cwd?, accessMode? }`), `AgentModel` (incl. `version?`, `isDefault?`, `options?`, `contextWindow?`, `isLatestAlias?`), `AgentCapabilities` (incl. `images`, `approvals`, `reportsContextUsage`, `reportsCompaction`), `AgentDescriptor.deprecated`, `AgentConfig` (cwd, agentId, model, plus optional `binaryPath`/`extraArgs`) |
59
+ | Agent sessions | `agent/sessions` · `holds` · `hold` · `release` · `requestHandoff` · `handoffAnswer` (`AgentSessionSummary`, `AgentSessionHold`, hand-off outcomes), `stream/agent/held` / `handoffRequested`, `SessionHeld` (`-32010`), `ONE_SHOT_PROMPT_OPENERS` / `isOneShotPrompt` (`src/models/agent-session.ts`, `src/agents/one-shot.ts`, architecture/02a §5.8.19) |
60
+ | Agents | `IAgentAdapter` (with `respondApproval`, `listModels`, `nativeSessionId`, `adoptNativeSession`, `listNativeSessions` → `NativeSessionInfo`, `SendTurnOptions { threadId, turnId, text, service?, effort?, options?, attachments?, cwd?, accessMode? }`), `AgentModel` (incl. `version?`, `isDefault?`, `options?`, `contextWindow?`, `isLatestAlias?`), `AgentCapabilities` (incl. `images`, `approvals`, `reportsContextUsage`, `reportsCompaction`), `AgentDescriptor.deprecated`, `AgentConfig` (cwd, agentId, model, plus optional `binaryPath`/`extraArgs`) |
60
61
  | Version | `compareVersions` / `isNewerVersion` — dependency-free SemVer precedence (used by the bridge's npm update check) |
61
62
  | Validation | Ajv validators for requests, responses, envelopes, pairing payload, push payloads |
62
63
 
@@ -85,6 +85,26 @@ export interface GenerateTitleOptions {
85
85
  /** Working directory to run the one-shot in (the thread's own). */
86
86
  cwd?: string;
87
87
  }
88
+ /**
89
+ * One of the agent's own sessions in a folder, as its CLI keeps it — the raw
90
+ * material of `agent/sessions` (the bridge turns the time into an age and
91
+ * links the conversation that continues it).
92
+ */
93
+ export interface NativeSessionInfo {
94
+ sessionId: string;
95
+ cwd: string;
96
+ /** The CLI's own title for it, else the first thing the person asked. */
97
+ title?: string;
98
+ /** When it last changed, on this PC's clock (epoch ms). */
99
+ updatedAt: number;
100
+ /**
101
+ * Started by a person in the agent's own interface (its terminal UI or
102
+ * app), rather than run headless by a program — the bridge's own runs, or
103
+ * one-shots like naming a conversation. A headless session is listed only
104
+ * when a conversation continues it.
105
+ */
106
+ interactive: boolean;
107
+ }
88
108
  export interface IAgentAdapter {
89
109
  readonly agentId: AgentId;
90
110
  readonly capabilities: AgentCapabilities;
@@ -96,6 +116,33 @@ export interface IAgentAdapter {
96
116
  sendTurn(options: SendTurnOptions): Promise<void>;
97
117
  /** Cancel an in-flight turn. */
98
118
  cancelTurn(threadId: string, turnId: string): Promise<void>;
119
+ /**
120
+ * The agent's own session id for a conversation — the id its CLI resumes
121
+ * (`claude --resume`, Codex `thread/resume`, ACP `session/load`, …) and the
122
+ * one its transcript on disk is named after. `undefined` until the agent
123
+ * has one for the thread.
124
+ */
125
+ nativeSessionId(threadId: string): string | undefined;
126
+ /**
127
+ * Continue a conversation in a native session this process did not open:
128
+ * the id the bridge stored before it restarted, or a session started
129
+ * elsewhere (a terminal) that the conversation now takes over. The next
130
+ * turn resumes it instead of opening a new one, so the agent keeps the
131
+ * context the user can see.
132
+ *
133
+ * Never replaces a session the adapter already holds for the thread, and
134
+ * never takes back an id the CLI already refused to resume for it: that
135
+ * conversation continues in the fresh session that replaced it.
136
+ */
137
+ adoptNativeSession(threadId: string, sessionId: string): void;
138
+ /**
139
+ * The agent's sessions in a folder, most recent first, read the way this
140
+ * CLI exposes them (its app-server, its server, ACP `session/list`, or its
141
+ * own session store — head and tail only, never whole transcripts).
142
+ * Optional: an agent whose CLI cannot list its sessions (Antigravity) omits
143
+ * it, and its sessions are continued only from the terminal they run in.
144
+ */
145
+ listNativeSessions?(cwd: string): Promise<NativeSessionInfo[]>;
99
146
  /**
100
147
  * Name a conversation from its opening exchange — a handful of words, no
101
148
  * punctuation, in the language the user wrote in.
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Uxnan's own one-shot prompts: the short headless runs it makes through an
3
+ * agent's CLI to name a conversation or write a commit message or a pull
4
+ * request body. They are errands, not conversations — but a CLI that cannot
5
+ * run without keeping a session (OpenCode, Grok, Zero, Antigravity; Claude
6
+ * Code, Codex and pi run them without one) keeps them in its history like any
7
+ * other session. The session catalog (`agent/sessions`) leaves them out by
8
+ * how they open.
9
+ *
10
+ * Every producer's test checks its prompt opens with one of these, so a
11
+ * reworded prompt cannot leak back into the list: the bridge's
12
+ * (`agents/thread-title.ts`) and the desktop's (`convtitle.rs`, `aicommit.rs`).
13
+ */
14
+ export declare const ONE_SHOT_PROMPT_OPENERS: readonly ["Name this conversation in 3 to 6 words", "Below is an excerpt of a terminal session with a coding agent.", "Write a git commit message for the following staged changes.", "Write a GitHub pull request description in Markdown"];
15
+ /** Whether a session's first prompt is one of Uxnan's own one-shots. */
16
+ export declare function isOneShotPrompt(prompt: string): boolean;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Uxnan's own one-shot prompts: the short headless runs it makes through an
3
+ * agent's CLI to name a conversation or write a commit message or a pull
4
+ * request body. They are errands, not conversations — but a CLI that cannot
5
+ * run without keeping a session (OpenCode, Grok, Zero, Antigravity; Claude
6
+ * Code, Codex and pi run them without one) keeps them in its history like any
7
+ * other session. The session catalog (`agent/sessions`) leaves them out by
8
+ * how they open.
9
+ *
10
+ * Every producer's test checks its prompt opens with one of these, so a
11
+ * reworded prompt cannot leak back into the list: the bridge's
12
+ * (`agents/thread-title.ts`) and the desktop's (`convtitle.rs`, `aicommit.rs`).
13
+ */
14
+ export const ONE_SHOT_PROMPT_OPENERS = [
15
+ // Naming a chat (the bridge).
16
+ 'Name this conversation in 3 to 6 words',
17
+ // Naming a terminal session (the desktop).
18
+ 'Below is an excerpt of a terminal session with a coding agent.',
19
+ // A commit message (the desktop).
20
+ 'Write a git commit message for the following staged changes.',
21
+ // A pull request body (the desktop).
22
+ 'Write a GitHub pull request description in Markdown',
23
+ ];
24
+ /** Whether a session's first prompt is one of Uxnan's own one-shots. */
25
+ export function isOneShotPrompt(prompt) {
26
+ const text = prompt.trimStart();
27
+ return ONE_SHOT_PROMPT_OPENERS.some((opener) => text.startsWith(opener));
28
+ }
29
+ //# sourceMappingURL=one-shot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"one-shot.js","sourceRoot":"","sources":["../../../src/agents/one-shot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,8BAA8B;IAC9B,wCAAwC;IACxC,2CAA2C;IAC3C,gEAAgE;IAChE,kCAAkC;IAClC,8DAA8D;IAC9D,qCAAqC;IACrC,qDAAqD;CAC7C,CAAC;AAEX,wEAAwE;AACxE,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;IAChC,OAAO,uBAAuB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AAC3E,CAAC"}
@@ -15,6 +15,7 @@ export * from './agents/agent-capabilities.js';
15
15
  export * from './agents/agent-config.js';
16
16
  export * from './agents/agent-adapter.js';
17
17
  export * from './agents/agent-locations.js';
18
+ export * from './agents/one-shot.js';
18
19
  export * from './local-control/local-control.js';
19
20
  export * from './version/compare.js';
20
21
  export * from './notifications/push-payload.js';
@@ -31,5 +32,6 @@ export * from './models/assistant-response.js';
31
32
  export * from './models/tool.js';
32
33
  export * from './models/usage.js';
33
34
  export * from './models/metrics.js';
35
+ export * from './models/agent-session.js';
34
36
  export * from './validators/validate.js';
35
37
  export * from './validators/json-schema/schemas.js';
package/dist/src/index.js CHANGED
@@ -18,6 +18,7 @@ export * from './agents/agent-capabilities.js';
18
18
  export * from './agents/agent-config.js';
19
19
  export * from './agents/agent-adapter.js';
20
20
  export * from './agents/agent-locations.js';
21
+ export * from './agents/one-shot.js';
21
22
  // Local control channel (desktop ↔ bridge on the same machine)
22
23
  export * from './local-control/local-control.js';
23
24
  // Version
@@ -38,6 +39,7 @@ export * from './models/assistant-response.js';
38
39
  export * from './models/tool.js';
39
40
  export * from './models/usage.js';
40
41
  export * from './models/metrics.js';
42
+ export * from './models/agent-session.js';
41
43
  // Validators
42
44
  export * from './validators/validate.js';
43
45
  export * from './validators/json-schema/schemas.js';
@@ -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;AAC1C,cAAc,6BAA6B,CAAC;AAE5C,+DAA+D;AAC/D,cAAc,kCAAkC,CAAC;AAEjD,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,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AAEpC,aAAa;AACb,cAAc,0BAA0B,CAAC;AACzC,cAAc,qCAAqC,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;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AAErC,+DAA+D;AAC/D,cAAc,kCAAkC,CAAC;AAEjD,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,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAE1C,aAAa;AACb,cAAc,0BAA0B,CAAC;AACzC,cAAc,qCAAqC,CAAC"}
@@ -25,6 +25,12 @@ export declare const JsonRpcErrorCode: {
25
25
  * explicit opt-out — the default is to queue.
26
26
  */
27
27
  readonly AgentBusy: -32009;
28
+ /**
29
+ * The conversation's agent session is open in a desktop terminal
30
+ * (`agent/hold`): the bridge runs no turn in it until the terminal
31
+ * lets it go. `data` carries the {@link AgentSessionHold}.
32
+ */
33
+ readonly SessionHeld: -32010;
28
34
  };
29
35
  export type JsonRpcErrorCode = (typeof JsonRpcErrorCode)[keyof typeof JsonRpcErrorCode];
30
36
  /** Human-readable default messages for each error code. */
@@ -27,6 +27,12 @@ export const JsonRpcErrorCode = {
27
27
  * explicit opt-out — the default is to queue.
28
28
  */
29
29
  AgentBusy: -32009,
30
+ /**
31
+ * The conversation's agent session is open in a desktop terminal
32
+ * (`agent/hold`): the bridge runs no turn in it until the terminal
33
+ * lets it go. `data` carries the {@link AgentSessionHold}.
34
+ */
35
+ SessionHeld: -32010,
30
36
  };
31
37
  /** Human-readable default messages for each error code. */
32
38
  export const JSON_RPC_ERROR_MESSAGES = {
@@ -45,6 +51,7 @@ export const JSON_RPC_ERROR_MESSAGES = {
45
51
  [JsonRpcErrorCode.ConfirmationRequired]: 'Confirmation required',
46
52
  [JsonRpcErrorCode.ResourceNotFound]: 'Resource not found',
47
53
  [JsonRpcErrorCode.AgentBusy]: 'Agent busy',
54
+ [JsonRpcErrorCode.SessionHeld]: 'Session open in a terminal',
48
55
  };
49
56
  /**
50
57
  * Error carrying a JSON-RPC error code, so handlers can throw a typed error
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/jsonrpc/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/jsonrpc/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,wBAAwB;IACxB,UAAU,EAAE,CAAC,KAAK;IAClB,cAAc,EAAE,CAAC,KAAK;IACtB,cAAc,EAAE,CAAC,KAAK;IACtB,aAAa,EAAE,CAAC,KAAK;IACrB,aAAa,EAAE,CAAC,KAAK;IACrB,iBAAiB;IACjB,WAAW,EAAE,CAAC,KAAK;IACnB,sBAAsB,EAAE,CAAC,KAAK;IAC9B,eAAe,EAAE,CAAC,KAAK;IACvB,kBAAkB,EAAE,CAAC,KAAK;IAC1B,qBAAqB,EAAE,CAAC,KAAK;IAC7B,yBAAyB,EAAE,CAAC,KAAK;IACjC,cAAc,EAAE,CAAC,KAAK;IACtB,oBAAoB,EAAE,CAAC,KAAK;IAC5B,gBAAgB,EAAE,CAAC,KAAK;IACxB;;;;OAIG;IACH,SAAS,EAAE,CAAC,KAAK;IACjB;;;;OAIG;IACH,WAAW,EAAE,CAAC,KAAK;CACX,CAAC;AAIX,2DAA2D;AAC3D,MAAM,CAAC,MAAM,uBAAuB,GAAqC;IACvE,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE,aAAa;IAC5C,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,iBAAiB;IACpD,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,kBAAkB;IACrD,CAAC,gBAAgB,CAAC,aAAa,CAAC,EAAE,gBAAgB;IAClD,CAAC,gBAAgB,CAAC,aAAa,CAAC,EAAE,gBAAgB;IAClD,CAAC,gBAAgB,CAAC,WAAW,CAAC,EAAE,cAAc;IAC9C,CAAC,gBAAgB,CAAC,sBAAsB,CAAC,EAAE,yBAAyB;IACpE,CAAC,gBAAgB,CAAC,eAAe,CAAC,EAAE,mBAAmB;IACvD,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,EAAE,sBAAsB;IAC7D,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,EAAE,yBAAyB;IACnE,CAAC,gBAAgB,CAAC,yBAAyB,CAAC,EAAE,6BAA6B;IAC3E,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,iBAAiB;IACpD,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,uBAAuB;IAChE,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,EAAE,oBAAoB;IACzD,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE,YAAY;IAC1C,CAAC,gBAAgB,CAAC,WAAW,CAAC,EAAE,4BAA4B;CAC7D,CAAC;AASF;;;GAGG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,CAAS;IACb,IAAI,CAAW;IAExB,YAAY,IAAY,EAAE,OAAgB,EAAE,IAAc;QACxD,MAAM,QAAQ,GAAG,OAAO,IAAI,uBAAuB,CAAC,IAAwB,CAAC,IAAI,cAAc,CAAC;QAChG,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,CAAC;IACH,CAAC;IAED,aAAa;QACX,MAAM,GAAG,GAAuB,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QAC3E,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,MAAc;QAClC,OAAO,IAAI,QAAQ,CAAC,gBAAgB,CAAC,cAAc,EAAE,qBAAqB,MAAM,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,CAAC,aAAa,CAAC,MAAe,EAAE,IAAc;QAClD,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,mBAAmB,MAAM,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;QACxE,OAAO,IAAI,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACrE,CAAC;CACF"}
@@ -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", "turn/attachment", "queue/resume", "queue/clear", "queue/sendNow", "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", "project/add", "project/remove", "project/rename", "sync/changes", "settings/get", "settings/set", "device/describe", "device/rename", "agent/list", "agent/models", "agent/commands", "agent/usageStats", "usage/redeemReset", "usage/summary", "agent/doctor", "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", "bridge/update", "bridge/checkForUpdate", "desktop/attach", "desktop/detach"];
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", "turn/attachment", "queue/resume", "queue/clear", "queue/sendNow", "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", "project/add", "project/remove", "project/rename", "sync/changes", "settings/get", "settings/set", "device/describe", "device/rename", "agent/list", "agent/models", "agent/commands", "agent/usageStats", "usage/redeemReset", "usage/summary", "agent/sessions", "agent/holds", "agent/hold", "agent/release", "agent/requestHandoff", "agent/handoffAnswer", "agent/doctor", "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", "bridge/update", "bridge/checkForUpdate", "desktop/attach", "desktop/detach"];
7
7
  export declare function isKnownMethod(method: string): method is JsonRpcMethodName;
@@ -73,6 +73,13 @@ export const METHOD_NAMES = [
73
73
  'agent/usageStats',
74
74
  'usage/redeemReset',
75
75
  'usage/summary',
76
+ // Agent sessions
77
+ 'agent/sessions',
78
+ 'agent/holds',
79
+ 'agent/hold',
80
+ 'agent/release',
81
+ 'agent/requestHandoff',
82
+ 'agent/handoffAnswer',
76
83
  'agent/doctor',
77
84
  // Metrics (bridge-owned, survivable profile stats + tamper-proof backup)
78
85
  'metrics/get',
@@ -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,iBAAiB;IACjB,gBAAgB;IAChB,cAAc;IACd,aAAa;IACb,eAAe;IACf,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,aAAa;IACb,gBAAgB;IAChB,gBAAgB;IAChB,mCAAmC;IACnC,cAAc;IACd,cAAc;IACd,cAAc;IACd,iBAAiB;IACjB,eAAe;IACf,SAAS;IACT,YAAY;IACZ,cAAc;IACd,gBAAgB;IAChB,kBAAkB;IAClB,mBAAmB;IACnB,eAAe;IACf,cAAc;IACd,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;IAC5B,eAAe;IACf,uBAAuB;IACvB,mEAAmE;IACnE,gBAAgB;IAChB,gBAAgB;CACR,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,iBAAiB;IACjB,gBAAgB;IAChB,cAAc;IACd,aAAa;IACb,eAAe;IACf,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,aAAa;IACb,gBAAgB;IAChB,gBAAgB;IAChB,mCAAmC;IACnC,cAAc;IACd,cAAc;IACd,cAAc;IACd,iBAAiB;IACjB,eAAe;IACf,SAAS;IACT,YAAY;IACZ,cAAc;IACd,gBAAgB;IAChB,kBAAkB;IAClB,mBAAmB;IACnB,eAAe;IACf,iBAAiB;IACjB,gBAAgB;IAChB,aAAa;IACb,YAAY;IACZ,eAAe;IACf,sBAAsB;IACtB,qBAAqB;IACrB,cAAc;IACd,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;IAC5B,eAAe;IACf,uBAAuB;IACvB,mEAAmE;IACnE,gBAAgB;IAChB,gBAAgB;CACR,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"}
@@ -5,6 +5,7 @@
5
5
  * Source: architecture/02b-contracts-and-requirements.md and
6
6
  * uxnandesktop/architecture/02e-bridge-integration.md §4.4.
7
7
  */
8
+ import type { AgentSessionHandoffAnswerParams, AgentSessionHandoffResult, AgentSessionHold, AgentSessionHoldParams, AgentSessionHoldsResult, AgentSessionKey, AgentSessionListParams, AgentSessionListResult } from '../models/agent-session.js';
8
9
  import type { AccessMode, QueuePausedReason, Thread, ThreadList, Turn, TurnList } from '../models/thread.js';
9
10
  import type { GitBranchList, GitBranchResult, GitCommitDetails, GitCommitResult, GitCommitShowParams, GitDiff, GitLogParams, GitLogResult, GitPrResult, GitPullResult, GitPushResult, GitRepoStatus, GitWorktreeList, GitWorktreeResult } from '../models/git.js';
10
11
  import type { ApplyResult, BrowseResult, Checkpoint, CheckpointDiff, FileContent, ImageContent, PatchChange, TurnAttachment, WorkspaceFileTarget, WorkspaceExistsResult, WorkspaceListing, SearchFilesParams, WorkspaceSearchResult } from '../models/workspace.js';
@@ -31,6 +32,13 @@ export interface StartThreadParams {
31
32
  model?: string;
32
33
  /** Working directory override; defaults to the project's cwd. */
33
34
  cwd?: string;
35
+ /**
36
+ * Continue this existing session of the agent (`agent/sessions`) instead
37
+ * of opening a new one: its turns become the conversation's history and the
38
+ * first turn resumes it. Requires `agentId`. When a conversation already
39
+ * continues the session, that conversation is returned instead of a second one.
40
+ */
41
+ agentSessionId?: string;
34
42
  }
35
43
  export interface ForkParams {
36
44
  threadId: string;
@@ -684,6 +692,30 @@ export interface JsonRpcMethodRegistry {
684
692
  params: UsageSummaryParams;
685
693
  result: UsageSummary;
686
694
  };
695
+ 'agent/sessions': {
696
+ params: AgentSessionListParams;
697
+ result: AgentSessionListResult;
698
+ };
699
+ 'agent/holds': {
700
+ params: void;
701
+ result: AgentSessionHoldsResult;
702
+ };
703
+ 'agent/hold': {
704
+ params: AgentSessionHoldParams;
705
+ result: AgentSessionHold;
706
+ };
707
+ 'agent/release': {
708
+ params: AgentSessionKey;
709
+ result: void;
710
+ };
711
+ 'agent/requestHandoff': {
712
+ params: AgentSessionKey;
713
+ result: AgentSessionHandoffResult;
714
+ };
715
+ 'agent/handoffAnswer': {
716
+ params: AgentSessionHandoffAnswerParams;
717
+ result: void;
718
+ };
687
719
  'agent/doctor': {
688
720
  params: void;
689
721
  result: {
@@ -67,6 +67,16 @@ export declare const StreamNotification: {
67
67
  * would answer now (idempotent).
68
68
  */
69
69
  readonly BridgeUpdated: "stream/bridge/updated";
70
+ /**
71
+ * A session's hold changed: a desktop terminal took it, its agent started or
72
+ * stopped working, or the terminal let it go (`hold` absent).
73
+ */
74
+ readonly AgentSessionHeld: "stream/agent/held";
75
+ /**
76
+ * Someone asked the holding desktop to let a session go (sent to that
77
+ * desktop only); it answers with `agent/handoffAnswer`.
78
+ */
79
+ readonly AgentSessionHandoffRequested: "stream/agent/handoffRequested";
70
80
  };
71
81
  export type StreamNotification = (typeof StreamNotification)[keyof typeof StreamNotification];
72
82
  export interface TurnStartedParams {
@@ -50,5 +50,15 @@ export const StreamNotification = {
50
50
  * would answer now (idempotent).
51
51
  */
52
52
  BridgeUpdated: 'stream/bridge/updated',
53
+ /**
54
+ * A session's hold changed: a desktop terminal took it, its agent started or
55
+ * stopped working, or the terminal let it go (`hold` absent).
56
+ */
57
+ AgentSessionHeld: 'stream/agent/held',
58
+ /**
59
+ * Someone asked the holding desktop to let a session go (sent to that
60
+ * desktop only); it answers with `agent/handoffAnswer`.
61
+ */
62
+ AgentSessionHandoffRequested: 'stream/agent/handoffRequested',
53
63
  };
54
64
  //# sourceMappingURL=notifications.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../../src/jsonrpc/notifications.ts"],"names":[],"mappings":"AAkBA,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;IACtC;;;;OAIG;IACH,aAAa,EAAE,uBAAuB;IACtC,4BAA4B;IAC5B,aAAa,EAAE,uBAAuB;IACtC;;;;OAIG;IACH,WAAW,EAAE,qBAAqB;IAClC,oEAAoE;IACpE,gBAAgB,EAAE,0BAA0B;IAC5C,6EAA6E;IAC7E,gBAAgB,EAAE,0BAA0B;IAC5C,qDAAqD;IACrD,cAAc,EAAE,wBAAwB;IACxC,wEAAwE;IACxE,cAAc,EAAE,wBAAwB;IACxC,yEAAyE;IACzE,eAAe,EAAE,yBAAyB;IAC1C,0CAA0C;IAC1C,eAAe,EAAE,yBAAyB;IAC1C,uDAAuD;IACvD,cAAc,EAAE,wBAAwB;IACxC,qEAAqE;IACrE,aAAa,EAAE,uBAAuB;IACtC;;;;OAIG;IACH,aAAa,EAAE,uBAAuB;CAC9B,CAAC"}
1
+ {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../../src/jsonrpc/notifications.ts"],"names":[],"mappings":"AAkBA,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;IACtC;;;;OAIG;IACH,aAAa,EAAE,uBAAuB;IACtC,4BAA4B;IAC5B,aAAa,EAAE,uBAAuB;IACtC;;;;OAIG;IACH,WAAW,EAAE,qBAAqB;IAClC,oEAAoE;IACpE,gBAAgB,EAAE,0BAA0B;IAC5C,6EAA6E;IAC7E,gBAAgB,EAAE,0BAA0B;IAC5C,qDAAqD;IACrD,cAAc,EAAE,wBAAwB;IACxC,wEAAwE;IACxE,cAAc,EAAE,wBAAwB;IACxC,yEAAyE;IACzE,eAAe,EAAE,yBAAyB;IAC1C,0CAA0C;IAC1C,eAAe,EAAE,yBAAyB;IAC1C,uDAAuD;IACvD,cAAc,EAAE,wBAAwB;IACxC,qEAAqE;IACrE,aAAa,EAAE,uBAAuB;IACtC;;;;OAIG;IACH,aAAa,EAAE,uBAAuB;IACtC;;;OAGG;IACH,gBAAgB,EAAE,mBAAmB;IACrC;;;OAGG;IACH,4BAA4B,EAAE,+BAA+B;CACrD,CAAC"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Agent sessions: the conversations an agent CLI keeps on the PC, whoever
3
+ * started them — a terminal, the bridge, the agent's own app — and whether one
4
+ * is open in a terminal right now (architecture/02a §5.8.19).
5
+ *
6
+ * The bridge owns both: it lists each agent's sessions through that agent's
7
+ * own surface (`agent/sessions`), and it knows which ones a desktop
8
+ * terminal holds (`agent/hold`), so every client — phone, desktop — can
9
+ * pick a session up, and none of them ever writes into a session a terminal is
10
+ * running.
11
+ *
12
+ * Across devices every time is an age (`…AgoMs`), never a timestamp.
13
+ */
14
+ import type { AgentId } from '../agents/agent-capabilities.js';
15
+ /** One of an agent's sessions in a folder, as `agent/sessions` returns it. */
16
+ export interface AgentSessionSummary {
17
+ agentId: AgentId;
18
+ /** The agent's own session id — the one its CLI resumes. */
19
+ sessionId: string;
20
+ /** The folder the session runs in. */
21
+ cwd: string;
22
+ /**
23
+ * The session's name: the CLI's own title when it keeps one, else the
24
+ * first thing the person asked, trimmed. Absent when neither is known.
25
+ */
26
+ title?: string;
27
+ /** How long ago the session last changed. */
28
+ updatedAgoMs: number;
29
+ /** The conversation that continues this session, when one does. */
30
+ threadId?: string;
31
+ /** Where the session is open right now, when a terminal holds it. */
32
+ hold?: AgentSessionHold;
33
+ }
34
+ /** Who holds a session: a terminal of Uxnan Desktop, on the named PC. */
35
+ export interface AgentSessionHolder {
36
+ kind: 'terminal';
37
+ /** The PC's name, as the bridge's shared settings call it. */
38
+ name: string;
39
+ }
40
+ /**
41
+ * A session open in a desktop terminal. While it is held, the bridge runs no
42
+ * turn in it: a CLI's session has one writer, and the terminal is it.
43
+ */
44
+ export interface AgentSessionHold {
45
+ agentId: AgentId;
46
+ sessionId: string;
47
+ cwd?: string;
48
+ holder: AgentSessionHolder;
49
+ /** How long ago the terminal took it. */
50
+ heldAgoMs: number;
51
+ /** Whether the agent is working right now; a hand-off waits until it is not. */
52
+ busy: boolean;
53
+ /** The conversation that continues this session, when one does. */
54
+ threadId?: string;
55
+ }
56
+ /** Which session: an agent and its session id. */
57
+ export interface AgentSessionKey {
58
+ agentId: AgentId;
59
+ sessionId: string;
60
+ }
61
+ export interface AgentSessionListParams {
62
+ /** The folder whose sessions to list. */
63
+ cwd: string;
64
+ /** Only this agent's sessions; every agent's when absent. */
65
+ agentId?: AgentId;
66
+ }
67
+ export interface AgentSessionListResult {
68
+ /** Most recently changed first. */
69
+ sessions: AgentSessionSummary[];
70
+ /**
71
+ * Agents installed here whose CLI cannot list its sessions (Antigravity):
72
+ * one of their sessions can still be continued from the terminal it runs in.
73
+ */
74
+ unlisted: AgentId[];
75
+ }
76
+ /**
77
+ * `agent/hold` — Uxnan Desktop says one of its terminals has this
78
+ * session open (or that its agent started or stopped working). Idempotent:
79
+ * the latest call wins. Accepted only over the local control channel, and
80
+ * dropped when that connection closes (the terminals close with the app).
81
+ */
82
+ export interface AgentSessionHoldParams extends AgentSessionKey {
83
+ cwd?: string;
84
+ busy?: boolean;
85
+ }
86
+ export interface AgentSessionHoldsResult {
87
+ holds: AgentSessionHold[];
88
+ }
89
+ /**
90
+ * How asking a terminal to let go of a session ended:
91
+ * - `released`: the agent was closed in its terminal; the session is free.
92
+ * - `busy`: the agent is working; ask again when it is done.
93
+ * - `declined`: the person at the PC kept it.
94
+ * - `unreachable`: the desktop did not answer in time.
95
+ * - `notHeld`: no terminal holds it; it is free already.
96
+ */
97
+ export type AgentSessionHandoffOutcome = 'released' | 'busy' | 'declined' | 'unreachable' | 'notHeld';
98
+ export interface AgentSessionHandoffResult {
99
+ outcome: AgentSessionHandoffOutcome;
100
+ }
101
+ /** `stream/agent/handoffRequested` — sent only to the holding desktop. */
102
+ export interface AgentSessionHandoffRequestedParams extends AgentSessionKey {
103
+ /** Answer with `agent/handoffAnswer` quoting this id. */
104
+ requestId: string;
105
+ /** Who asks: the client's name (a phone's, or the PC's). */
106
+ from: string;
107
+ }
108
+ /** `agent/handoffAnswer` — the holding desktop's answer. */
109
+ export interface AgentSessionHandoffAnswerParams {
110
+ requestId: string;
111
+ outcome: Extract<AgentSessionHandoffOutcome, 'released' | 'busy' | 'declined'>;
112
+ }
113
+ /**
114
+ * `stream/agent/held` — a session's hold changed: taken, busy or idle,
115
+ * or let go (`hold` absent). Every client follows it; one that missed some
116
+ * asks `agent/holds`.
117
+ */
118
+ export interface AgentSessionHeldParams extends AgentSessionKey {
119
+ hold?: AgentSessionHold;
120
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=agent-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-session.js","sourceRoot":"","sources":["../../../src/models/agent-session.ts"],"names":[],"mappings":""}
@@ -225,4 +225,12 @@ export interface BridgeFeatures {
225
225
  * `Turn.seq`. Absent/false → a client keeps its older `thread/list` flow.
226
226
  */
227
227
  sync?: boolean;
228
+ /**
229
+ * The bridge lists every agent's sessions in a folder (`agent/sessions`),
230
+ * starts a conversation that continues one (`thread/start` with
231
+ * `agentSessionId`) and knows which ones a desktop terminal holds
232
+ * (`agent/holds`, `agent/hold`, …, `stream/agent/held`). Absent/false → a client
233
+ * offers none of it.
234
+ */
235
+ agentSessions?: boolean;
228
236
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxnan/shared",
3
- "version": "0.0.22-alpha.20260927",
3
+ "version": "0.0.23-alpha.20260927",
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",