linkshell-cli 0.9.0 → 0.10.1

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 (168) hide show
  1. package/README.md +11 -6
  2. package/dist/cli/src/commands/gateway.d.ts +2 -0
  3. package/dist/cli/src/commands/gateway.js +29 -0
  4. package/dist/cli/src/commands/gateway.js.map +1 -0
  5. package/dist/cli/src/commands/host.d.ts +2 -0
  6. package/dist/cli/src/commands/host.js +12 -2
  7. package/dist/cli/src/commands/host.js.map +1 -1
  8. package/dist/cli/src/commands/setup.js +4 -2
  9. package/dist/cli/src/commands/setup.js.map +1 -1
  10. package/dist/cli/src/index.js +12 -334
  11. package/dist/cli/src/index.js.map +1 -1
  12. package/dist/cli/src/utils/daemon.d.ts +0 -7
  13. package/dist/cli/src/utils/daemon.js +1 -18
  14. package/dist/cli/src/utils/daemon.js.map +1 -1
  15. package/dist/cli/tsconfig.tsbuildinfo +1 -1
  16. package/dist/gateway/src/accounts.d.ts +6 -0
  17. package/dist/gateway/src/accounts.js +32 -0
  18. package/dist/gateway/src/accounts.js.map +1 -0
  19. package/dist/gateway/src/index.d.ts +4 -0
  20. package/dist/gateway/src/index.js +5 -0
  21. package/dist/gateway/src/index.js.map +1 -0
  22. package/dist/gateway/src/main.d.ts +1 -0
  23. package/dist/gateway/src/main.js +57 -0
  24. package/dist/gateway/src/main.js.map +1 -0
  25. package/dist/gateway/src/rate-limit.d.ts +22 -0
  26. package/dist/gateway/src/rate-limit.js +66 -0
  27. package/dist/gateway/src/rate-limit.js.map +1 -0
  28. package/dist/gateway/src/relay.d.ts +84 -0
  29. package/dist/gateway/src/relay.js +434 -0
  30. package/dist/gateway/src/relay.js.map +1 -0
  31. package/dist/gateway/src/serve.d.ts +34 -0
  32. package/dist/gateway/src/serve.js +102 -0
  33. package/dist/gateway/src/serve.js.map +1 -0
  34. package/dist/gateway/src/store.d.ts +35 -0
  35. package/dist/gateway/src/store.js +109 -0
  36. package/dist/gateway/src/store.js.map +1 -0
  37. package/dist/gateway/src/subscription.d.ts +18 -0
  38. package/dist/gateway/src/subscription.js +46 -0
  39. package/dist/gateway/src/subscription.js.map +1 -0
  40. package/dist/host/src/drivers/claude/transcript.d.ts +23 -23
  41. package/dist/host/src/drivers/codex/app-server.d.ts +31 -6
  42. package/dist/host/src/drivers/codex/app-server.js +99 -24
  43. package/dist/host/src/drivers/codex/app-server.js.map +1 -1
  44. package/dist/host/src/drivers/codex/desktop-ipc.d.ts +8 -0
  45. package/dist/host/src/drivers/codex/desktop-ipc.js +124 -0
  46. package/dist/host/src/drivers/codex/desktop-ipc.js.map +1 -0
  47. package/dist/host/src/drivers/codex/driver.d.ts +111 -2
  48. package/dist/host/src/drivers/codex/driver.js +629 -63
  49. package/dist/host/src/drivers/codex/driver.js.map +1 -1
  50. package/dist/host/src/drivers/codex/mapper.d.ts +21 -0
  51. package/dist/host/src/drivers/codex/mapper.js +45 -6
  52. package/dist/host/src/drivers/codex/mapper.js.map +1 -1
  53. package/dist/host/src/drivers/types.d.ts +6 -0
  54. package/dist/host/src/fs.d.ts +3 -3
  55. package/dist/host/src/hub.js +8 -1
  56. package/dist/host/src/hub.js.map +1 -1
  57. package/dist/host/src/input.d.ts +4 -4
  58. package/dist/host/src/terminals.d.ts +1 -1
  59. package/dist/wire/src/model.d.ts +6 -6
  60. package/dist/wire/src/relay.d.ts +8 -8
  61. package/dist/wire/src/rpc.d.ts +818 -818
  62. package/dist/wire/src/updates.d.ts +18 -18
  63. package/package.json +5 -14
  64. package/src/commands/gateway.ts +31 -0
  65. package/src/commands/host.ts +13 -2
  66. package/src/commands/setup.ts +4 -2
  67. package/src/index.ts +14 -429
  68. package/src/utils/daemon.ts +2 -27
  69. package/dist/cli/src/config.d.ts +0 -14
  70. package/dist/cli/src/config.js +0 -23
  71. package/dist/cli/src/config.js.map +0 -1
  72. package/dist/cli/src/machine-id.d.ts +0 -6
  73. package/dist/cli/src/machine-id.js +0 -50
  74. package/dist/cli/src/machine-id.js.map +0 -1
  75. package/dist/cli/src/providers.d.ts +0 -13
  76. package/dist/cli/src/providers.js +0 -77
  77. package/dist/cli/src/providers.js.map +0 -1
  78. package/dist/cli/src/runtime/acp/acp-client.d.ts +0 -128
  79. package/dist/cli/src/runtime/acp/acp-client.js +0 -430
  80. package/dist/cli/src/runtime/acp/acp-client.js.map +0 -1
  81. package/dist/cli/src/runtime/acp/agent-process-discovery.d.ts +0 -48
  82. package/dist/cli/src/runtime/acp/agent-process-discovery.js +0 -278
  83. package/dist/cli/src/runtime/acp/agent-process-discovery.js.map +0 -1
  84. package/dist/cli/src/runtime/acp/agent-session.d.ts +0 -62
  85. package/dist/cli/src/runtime/acp/agent-session.js +0 -1081
  86. package/dist/cli/src/runtime/acp/agent-session.js.map +0 -1
  87. package/dist/cli/src/runtime/acp/agent-workspace.d.ts +0 -311
  88. package/dist/cli/src/runtime/acp/agent-workspace.js +0 -6083
  89. package/dist/cli/src/runtime/acp/agent-workspace.js.map +0 -1
  90. package/dist/cli/src/runtime/acp/claude-sdk-client.d.ts +0 -121
  91. package/dist/cli/src/runtime/acp/claude-sdk-client.js +0 -1147
  92. package/dist/cli/src/runtime/acp/claude-sdk-client.js.map +0 -1
  93. package/dist/cli/src/runtime/acp/claude-stream-json-client.d.ts +0 -53
  94. package/dist/cli/src/runtime/acp/claude-stream-json-client.js +0 -552
  95. package/dist/cli/src/runtime/acp/claude-stream-json-client.js.map +0 -1
  96. package/dist/cli/src/runtime/acp/json-rpc.d.ts +0 -22
  97. package/dist/cli/src/runtime/acp/json-rpc.js +0 -160
  98. package/dist/cli/src/runtime/acp/json-rpc.js.map +0 -1
  99. package/dist/cli/src/runtime/acp/provider-resolver.d.ts +0 -16
  100. package/dist/cli/src/runtime/acp/provider-resolver.js +0 -132
  101. package/dist/cli/src/runtime/acp/provider-resolver.js.map +0 -1
  102. package/dist/cli/src/runtime/bridge-session.d.ts +0 -97
  103. package/dist/cli/src/runtime/bridge-session.js +0 -1364
  104. package/dist/cli/src/runtime/bridge-session.js.map +0 -1
  105. package/dist/cli/src/runtime/hook-command.d.ts +0 -9
  106. package/dist/cli/src/runtime/hook-command.js +0 -80
  107. package/dist/cli/src/runtime/hook-command.js.map +0 -1
  108. package/dist/cli/src/runtime/screen-fallback.d.ts +0 -22
  109. package/dist/cli/src/runtime/screen-fallback.js +0 -202
  110. package/dist/cli/src/runtime/screen-fallback.js.map +0 -1
  111. package/dist/cli/src/runtime/screen-share.d.ts +0 -34
  112. package/dist/cli/src/runtime/screen-share.js +0 -376
  113. package/dist/cli/src/runtime/screen-share.js.map +0 -1
  114. package/dist/cli/src/runtime/scrollback.d.ts +0 -11
  115. package/dist/cli/src/runtime/scrollback.js +0 -33
  116. package/dist/cli/src/runtime/scrollback.js.map +0 -1
  117. package/dist/cli/src/runtime/usage-report.d.ts +0 -34
  118. package/dist/cli/src/runtime/usage-report.js +0 -332
  119. package/dist/cli/src/runtime/usage-report.js.map +0 -1
  120. package/dist/cli/src/utils/keep-awake.d.ts +0 -6
  121. package/dist/cli/src/utils/keep-awake.js +0 -48
  122. package/dist/cli/src/utils/keep-awake.js.map +0 -1
  123. package/dist/cli/src/utils/lan-ip.d.ts +0 -9
  124. package/dist/cli/src/utils/lan-ip.js +0 -61
  125. package/dist/cli/src/utils/lan-ip.js.map +0 -1
  126. package/dist/host/src/input-helper.d.ts +0 -1
  127. package/dist/host/src/input-helper.js +0 -564
  128. package/dist/host/src/input-helper.js.map +0 -1
  129. package/dist/shared-protocol/src/index.d.ts +0 -17029
  130. package/dist/shared-protocol/src/index.js +0 -1064
  131. package/dist/shared-protocol/src/index.js.map +0 -1
  132. package/scripts/copy-web.mjs +0 -34
  133. package/src/config.ts +0 -36
  134. package/src/machine-id.ts +0 -61
  135. package/src/providers.ts +0 -97
  136. package/src/runtime/acp/acp-client.ts +0 -521
  137. package/src/runtime/acp/agent-process-discovery.ts +0 -308
  138. package/src/runtime/acp/agent-session.ts +0 -1186
  139. package/src/runtime/acp/agent-workspace.ts +0 -6590
  140. package/src/runtime/acp/claude-sdk-client.ts +0 -1221
  141. package/src/runtime/acp/claude-stream-json-client.ts +0 -633
  142. package/src/runtime/acp/json-rpc.ts +0 -184
  143. package/src/runtime/acp/provider-resolver.ts +0 -154
  144. package/src/runtime/bridge-session.ts +0 -1549
  145. package/src/runtime/hook-command.ts +0 -73
  146. package/src/runtime/screen-fallback.ts +0 -235
  147. package/src/runtime/screen-share.ts +0 -426
  148. package/src/runtime/scrollback.ts +0 -43
  149. package/src/runtime/usage-report.ts +0 -342
  150. package/src/utils/keep-awake.ts +0 -61
  151. package/src/utils/lan-ip.ts +0 -61
  152. package/web/assets/FileBrowser-wOAfY-xj.js +0 -2
  153. package/web/assets/PortPreview-Cbvv7yzA.js +0 -2
  154. package/web/assets/TerminalPanel-CTSklkct.js +0 -1
  155. package/web/assets/UsageDashboard-CJ1AsNmd.js +0 -1
  156. package/web/assets/index-BsnDaeCt.css +0 -33
  157. package/web/assets/index-q85psYZ5.js +0 -36
  158. package/web/assets/vendor-highlight-NXWAAyIv.js +0 -5
  159. package/web/assets/vendor-react-M7xG3qiw.js +0 -49
  160. package/web/assets/vendor-xterm-D15THcI4.js +0 -9
  161. package/web/index.html +0 -37
  162. package/web/logos/claude.png +0 -0
  163. package/web/logos/codex.png +0 -0
  164. package/web/logos/copilot.png +0 -0
  165. package/web/logos/gemini.png +0 -0
  166. package/web/logos/linkshell-1024.png +0 -0
  167. package/web/logos/linkshell-splash.png +0 -0
  168. package/web/logos/linkshell.png +0 -0
@@ -0,0 +1,124 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { existsSync } from "node:fs";
3
+ import { connect } from "node:net";
4
+ import { homedir } from "node:os";
5
+ import { join } from "node:path";
6
+ // The Codex desktop app and its IDE extension keep the threads they run in
7
+ // app-servers of their own, which take no other clients. What they do share
8
+ // is a message bus between their windows, on a socket in Codex's home: a
9
+ // window that doesn't run a thread asks the one that does to act on it
10
+ // ("thread-follower-…" requests). That is the only way to stop a turn the
11
+ // desktop app is running without stopping the app.
12
+ //
13
+ // The bus is the app's own, not a published interface: each method carries a
14
+ // version the receiver checks, and a request it doesn't recognise is refused.
15
+ // So everything here is one question with a yes or a no; a no is reported as
16
+ // "can't be stopped from here", never retried in another shape.
17
+ /** Where the desktop app's bus listens (the first Codex window to start serves it). */
18
+ export function desktopBusSocket(env = process.env) {
19
+ return join(env.CODEX_HOME || join(homedir(), ".codex"), "ipc", "ipc.sock");
20
+ }
21
+ /** The version of the interrupt request the installed apps accept: with the turn it is meant for, or (older) without. */
22
+ const INTERRUPT_VERSION = { withTurn: 4, anyTurn: 3 };
23
+ function frame(message) {
24
+ const body = Buffer.from(JSON.stringify(message), "utf8");
25
+ const head = Buffer.alloc(4);
26
+ head.writeUInt32LE(body.length, 0);
27
+ return Buffer.concat([head, body]);
28
+ }
29
+ /**
30
+ * Asks whichever Codex window runs `threadId` to stop its turn, as its own
31
+ * Stop button does. Resolves when that window says it has; rejects when no
32
+ * window runs the thread, none answers in time, or the app isn't there.
33
+ */
34
+ export async function interruptThroughDesktop(socketPath, threadId, turnId, timeoutMs = 12_000) {
35
+ if (!existsSync(socketPath))
36
+ throw new Error("the Codex desktop app isn't running");
37
+ const socket = connect(socketPath);
38
+ try {
39
+ await new Promise((resolve, reject) => {
40
+ socket.once("connect", resolve);
41
+ socket.once("error", reject);
42
+ });
43
+ const bus = busClient(socket, timeoutMs);
44
+ const registered = await bus.request("initialize", { clientType: "linkshell" }, 0);
45
+ bus.clientId = String(registered.clientId ?? "");
46
+ await bus.request("thread-follower-interrupt-turn", { conversationId: threadId, mode: "user-stop", ...(turnId ? { expectedTurnId: turnId } : {}) }, turnId ? INTERRUPT_VERSION.withTurn : INTERRUPT_VERSION.anyTurn);
47
+ }
48
+ finally {
49
+ socket.destroy();
50
+ }
51
+ }
52
+ /** One connection to the bus: length-prefixed JSON, requests answered by `requestId`. */
53
+ function busClient(socket, timeoutMs) {
54
+ const pending = new Map();
55
+ let buffered = Buffer.alloc(0);
56
+ const failAll = (error) => {
57
+ for (const waiting of pending.values())
58
+ waiting.reject(error);
59
+ pending.clear();
60
+ };
61
+ socket.on("data", (chunk) => {
62
+ buffered = Buffer.concat([buffered, chunk]);
63
+ while (buffered.length >= 4) {
64
+ const length = buffered.readUInt32LE(0);
65
+ if (buffered.length < 4 + length)
66
+ return;
67
+ let message;
68
+ try {
69
+ message = JSON.parse(buffered.subarray(4, 4 + length).toString("utf8"));
70
+ }
71
+ catch {
72
+ failAll(new Error("the Codex desktop app sent something unreadable"));
73
+ socket.destroy();
74
+ return;
75
+ }
76
+ buffered = buffered.subarray(4 + length);
77
+ if (message.type === "response") {
78
+ const waiting = pending.get(String(message.requestId));
79
+ if (!waiting)
80
+ continue;
81
+ pending.delete(String(message.requestId));
82
+ if (message.resultType === "success")
83
+ waiting.resolve(message.result);
84
+ else
85
+ waiting.reject(new Error(String(message.error ?? "refused")));
86
+ }
87
+ else if (message.type === "client-discovery-request") {
88
+ // The bus asks every client whether it runs the thread a request is about. Left
89
+ // unanswered, the asker waits ten seconds for this client; it never does.
90
+ socket.write(frame({ type: "client-discovery-response", requestId: message.requestId, response: { canHandle: false } }));
91
+ }
92
+ else if (message.type === "request") {
93
+ socket.write(frame({ type: "response", requestId: message.requestId, resultType: "error", error: "no-handler-for-request" }));
94
+ }
95
+ }
96
+ });
97
+ socket.on("close", () => failAll(new Error("the Codex desktop app closed the connection")));
98
+ socket.on("error", () => { });
99
+ const client = {
100
+ clientId: "initializing-client",
101
+ request(method, params, version) {
102
+ const requestId = randomUUID();
103
+ return new Promise((resolve, reject) => {
104
+ const timer = setTimeout(() => {
105
+ pending.delete(requestId);
106
+ reject(new Error("timeout"));
107
+ }, timeoutMs);
108
+ pending.set(requestId, {
109
+ resolve: (result) => {
110
+ clearTimeout(timer);
111
+ resolve(result);
112
+ },
113
+ reject: (error) => {
114
+ clearTimeout(timer);
115
+ reject(error);
116
+ },
117
+ });
118
+ socket.write(frame({ type: "request", requestId, sourceClientId: client.clientId, version, method, params, timeoutMs }));
119
+ });
120
+ },
121
+ };
122
+ return client;
123
+ }
124
+ //# sourceMappingURL=desktop-ipc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desktop-ipc.js","sourceRoot":"","sources":["../../../../../../host/src/drivers/codex/desktop-ipc.ts"],"names":[],"mappings":"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"}
@@ -8,10 +8,31 @@ export interface CodexDriverOptions {
8
8
  hostVersion: string;
9
9
  /** Delay before restarting a crashed app-server; doubles up to 30s. */
10
10
  restartDelayMs?: number;
11
+ /**
12
+ * Codex's own background server, joined for the threads that live in it
13
+ * (default: where the installed Codex keeps it). `false`: never.
14
+ */
15
+ sharedSocketPath?: string | false;
16
+ /**
17
+ * The bus the Codex desktop app's windows share, through which it is asked
18
+ * to stop a turn it runs (default: where the installed Codex keeps it). `false`: never.
19
+ */
20
+ desktopBusPath?: string | false;
21
+ /** How often a thread that can only be read is looked at again. */
22
+ observeIntervalMs?: number;
23
+ /** How long a thread no device has open, and that isn't working, stays joined. */
24
+ releaseDelayMs?: number;
11
25
  }
12
26
  /**
13
27
  * Codex, tier multi_client: LinkShell and the desktop TUI (`codex --remote`)
14
28
  * are both clients of one app-server, so every thread is live on both sides.
29
+ *
30
+ * Codex lets one process have a thread loaded at a time. A thread loaded in
31
+ * Codex's own background server (a plain `codex` in a terminal) is joined
32
+ * there, as one more client. A thread in a process that takes no other
33
+ * clients (the desktop app, an IDE extension) is read from disk as that
34
+ * process writes it; a message for it goes into Codex's own queue, which that
35
+ * process starts when it is idle; and its turn is stopped by asking the app.
15
36
  */
16
37
  export declare class CodexDriver implements AgentDriver {
17
38
  private readonly options;
@@ -52,12 +73,35 @@ export declare class CodexDriver implements AgentDriver {
52
73
  private restartTimer?;
53
74
  private restartDelay;
54
75
  private stopped;
76
+ private shared?;
77
+ /** Threads loaded in Codex's background server: announced by it, or joined there. */
78
+ private readonly inShared;
79
+ private readonly observed;
80
+ private readonly takingUp;
81
+ /** Messages in Codex's own queue for threads another process holds: it starts them when it is idle or its turn ends. */
82
+ private readonly waiting;
83
+ /** Notifications for a thread being joined, held until its history has been read. */
84
+ private readonly joining;
85
+ /** Threads a device has open. */
86
+ private readonly watching;
87
+ /** Threads another client of this host's app-server opened (`linkshell codex`): followed for as long as the host runs. */
88
+ private readonly kept;
89
+ /** Threads started here that have had no turn: nothing on disk yet to come back to. */
90
+ private readonly fresh;
91
+ private readonly releases;
92
+ /** What was last announced per thread (settings, commands): a thread joined again says it only if it changed. */
93
+ private readonly announced;
94
+ private readonly observeIntervalMs;
95
+ private readonly releaseDelayMs;
96
+ private readonly sharedSocketPath?;
97
+ private readonly desktopBusPath?;
55
98
  constructor(options: CodexDriverOptions);
56
99
  status(): DriverStatus;
57
100
  start(host: DriverHost): Promise<DriverStatus>;
58
101
  authStatus(): Promise<AgentAuth>;
59
102
  stop(): Promise<void>;
60
103
  listSessions(limit: number): Promise<DiscoveredSession[]>;
104
+ private stateElsewhere;
61
105
  /** Codex's own fork: a new thread with this one's turns, all or through `lastTurnId`, in `cwd`. */
62
106
  fork(nativeId: string, options: ForkOptions): Promise<DiscoveredSession>;
63
107
  createSession(options: {
@@ -65,10 +109,67 @@ export declare class CodexDriver implements AgentDriver {
65
109
  model?: string;
66
110
  }): Promise<DiscoveredSession>;
67
111
  attach(nativeId: string): Promise<HistoryItem[]>;
112
+ /**
113
+ * Subscribes to a thread where it can be driven: this host's app-server, or
114
+ * Codex's background server when the thread is loaded there. What the
115
+ * server sends from then on is held until `goLive`.
116
+ */
117
+ private subscribe;
118
+ /** thread/resume where the thread can be loaded: here, or in Codex's background server if it is loaded there. */
119
+ private resume;
120
+ /** Says where the joined thread stands, then lets through what arrived while it was being read. */
121
+ private goLive;
122
+ /** Reads the thread from disk, and keeps reading while a device has it open. */
123
+ private observe;
124
+ /** Reports what the other process has finished since the last look. An item still being written isn't on disk. */
125
+ private refresh;
126
+ private report;
127
+ private stopObserving;
128
+ /**
129
+ * Before writing to a thread that could only be read: joins it if whoever
130
+ * had it has let go, with what they wrote since the last look. Still held,
131
+ * it stays as it is.
132
+ */
133
+ private takeUp;
134
+ /**
135
+ * Leaves a message in Codex's own queue for a thread another process holds.
136
+ * That process starts it when it is idle, or right after the turn it is running.
137
+ */
138
+ private enqueue;
139
+ /** What waits in Codex's queue for the thread, as the session's queue on the devices. */
140
+ private syncWaiting;
141
+ private setWaiting;
142
+ unqueue(nativeId: string, clientMessageId: string): boolean;
143
+ /** A queued message can't be put into the turn another Codex is running: that turn is stopped, and the queue goes on. */
144
+ sendQueuedNow(nativeId: string): Promise<void>;
145
+ /**
146
+ * Stops the turn a Codex that can't be joined is running. Only its own app
147
+ * can: it is asked over the bus its windows share.
148
+ */
149
+ private stopElsewhere;
150
+ /**
151
+ * What a message for a thread held elsewhere is refused with. The apps show
152
+ * a failed message without its reason, so the reason goes into the session too.
153
+ */
154
+ private refused;
155
+ /** Says, when it becomes so and when it is over, that the session is in a Codex this host can't join. */
156
+ private reportHeld;
157
+ /** Whether a device has the session open. */
158
+ watched(nativeId: string, open: boolean): void;
159
+ private cancelRelease;
160
+ /**
161
+ * A thread stays loaded, and closed to every other Codex program, for as
162
+ * long as this host is subscribed to it. One that no device has open and
163
+ * that isn't working is let go after a while, so the desktop app or a
164
+ * `codex` in a terminal can open it; opening it on a device joins it again.
165
+ */
166
+ private considerRelease;
167
+ private release;
168
+ private hasApprovals;
68
169
  /** Nests each sub-agent's own history right after the call that spawned it. */
69
170
  private withSubAgents;
70
171
  detach(nativeId: string): Promise<void>;
71
- prompt(nativeId: string, content: ContentBlock[], clientMessageId: string): Promise<"started" | "steered">;
172
+ prompt(nativeId: string, content: ContentBlock[], clientMessageId: string): Promise<"started" | "steered" | "queued">;
72
173
  /**
73
174
  * `/compact`, `/review`, `/init` and `/<skill>`: what the TUI does for them,
74
175
  * through the app-server. Anything else is an ordinary message.
@@ -79,6 +180,7 @@ export declare class CodexDriver implements AgentDriver {
79
180
  setConfig(nativeId: string, optionId: string, value: string): Promise<void>;
80
181
  private loadModels;
81
182
  private announceConfig;
183
+ private isNews;
82
184
  private loadSkills;
83
185
  /** What `/` offers on a device: the commands above, then the skills this project can use. */
84
186
  private announceCommands;
@@ -88,7 +190,7 @@ export declare class CodexDriver implements AgentDriver {
88
190
  cancel(nativeId: string): Promise<void>;
89
191
  respondPermission(nativeId: string, requestId: string, optionId: string): Promise<void>;
90
192
  answerQuestion(nativeId: string, requestId: string, answers: QuestionAnswer[]): Promise<void>;
91
- desktopLaunch(args: string[], nativeId?: string): LaunchSpec;
193
+ desktopLaunch(args: string[], nativeId?: string): Promise<LaunchSpec>;
92
194
  private boot;
93
195
  /** Follows every thread already live in the app-server (e.g. opened in the TUI). */
94
196
  private reattachLoaded;
@@ -107,4 +209,11 @@ export declare class CodexDriver implements AgentDriver {
107
209
  private onServerRequest;
108
210
  private rememberTitle;
109
211
  private rpc;
212
+ /** A request about a thread, to the server it is loaded in. */
213
+ private rpcFor;
214
+ /** Connects to Codex's background server, if it is running. */
215
+ private connectShared;
216
+ /** Codex's background server went away (stopped, or restarted by its updater): the threads joined there are joined again wherever they are now. */
217
+ private onSharedDown;
218
+ private abandonApprovals;
110
219
  }