lark-remote 0.1.5 → 0.1.6
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/CHANGELOG.md +17 -0
- package/README.en.md +0 -4
- package/README.md +0 -4
- package/dist/bridge/approval-coordinator.d.ts +108 -0
- package/dist/bridge/approval-coordinator.js +258 -0
- package/dist/bridge/index.d.ts +62 -0
- package/dist/bridge/index.js +402 -21
- package/dist/bridge/queue-manager.d.ts +9 -0
- package/dist/bridge/queue-manager.js +19 -11
- package/dist/card/approval-render.d.ts +16 -0
- package/dist/card/approval-render.js +247 -0
- package/dist/card/card-shared.d.ts +14 -0
- package/dist/card/card-shared.js +28 -0
- package/dist/card/run-renderer.js +77 -6
- package/dist/card/run-state.d.ts +25 -3
- package/dist/card/run-state.js +203 -2
- package/dist/config/dir.js +1 -1
- package/dist/config/index.d.ts +42 -0
- package/dist/config/index.js +23 -1
- package/dist/connector/index.d.ts +5 -0
- package/dist/connector/index.js +12 -0
- package/dist/index.js +44 -22
- package/dist/router/config/codex.d.ts +1 -1
- package/dist/router/config/codex.js +49 -0
- package/dist/router/config/common/render.js +4 -0
- package/dist/router/config/types.d.ts +1 -1
- package/dist/router/index.d.ts +27 -2
- package/dist/router/index.js +109 -28
- package/dist/router/utils.d.ts +2 -0
- package/dist/router/utils.js +5 -2
- package/dist/runner/codex/app-server/client.d.ts +82 -0
- package/dist/runner/codex/app-server/client.js +234 -0
- package/dist/runner/codex/app-server/connection-manager.d.ts +56 -0
- package/dist/runner/codex/app-server/connection-manager.js +170 -0
- package/dist/runner/codex/app-server/protocol-types.d.ts +527 -0
- package/dist/runner/codex/app-server/protocol-types.js +67 -0
- package/dist/runner/codex/app-server/runner.d.ts +121 -0
- package/dist/runner/codex/app-server/runner.js +554 -0
- package/dist/runner/codex/app-server/translator.d.ts +109 -0
- package/dist/runner/codex/app-server/translator.js +734 -0
- package/dist/runner/codex/app-server/transport.d.ts +49 -0
- package/dist/runner/codex/app-server/transport.js +231 -0
- package/dist/runner/codex/factory.d.ts +29 -0
- package/dist/runner/codex/factory.js +39 -0
- package/dist/runner/codex/index.d.ts +2 -0
- package/dist/runner/codex/index.js +2 -0
- package/dist/runner/codex/runner.d.ts +3 -0
- package/dist/runner/codex/runner.js +5 -0
- package/dist/runner/common/usage.d.ts +2 -0
- package/dist/runner/common/usage.js +2 -0
- package/dist/runner/index.d.ts +2 -2
- package/dist/runner/index.js +1 -1
- package/dist/runner/types.d.ts +123 -2
- package/dist/session/codex/rollout-reader.js +43 -0
- package/package.json +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConnectionManager: manages Codex App Server connections per workspace.
|
|
3
|
+
*
|
|
4
|
+
* Each workspace gets its own connection (transport + client). Connections are
|
|
5
|
+
* created on demand via `acquire()`, cached for reuse, and released after an
|
|
6
|
+
* idle timeout (30 minutes default).
|
|
7
|
+
*/
|
|
8
|
+
import { CodexAppServerClient } from './client.js';
|
|
9
|
+
export interface ConnectionManagerOptions {
|
|
10
|
+
/** Path to the codex binary. */
|
|
11
|
+
binary: string;
|
|
12
|
+
/** Args to spawn the app server with. Defaults to `['app-server', '--stdio']`. */
|
|
13
|
+
args?: string[];
|
|
14
|
+
/** Environment variables to pass to the binary. */
|
|
15
|
+
env?: Record<string, string | undefined>;
|
|
16
|
+
/** Request timeout in milliseconds. */
|
|
17
|
+
requestTimeoutMs?: number;
|
|
18
|
+
/** Idle TTL in milliseconds. */
|
|
19
|
+
idleTtlMs?: number;
|
|
20
|
+
}
|
|
21
|
+
export declare class ConnectionManager {
|
|
22
|
+
private slots;
|
|
23
|
+
private readonly binary;
|
|
24
|
+
private readonly args;
|
|
25
|
+
private readonly env;
|
|
26
|
+
private readonly requestTimeoutMs;
|
|
27
|
+
private readonly idleTtlMs;
|
|
28
|
+
/** Callback when a connection is lost — cleared from slot map. */
|
|
29
|
+
onConnectionLost?: (workspace: string) => void;
|
|
30
|
+
constructor(opts: ConnectionManagerOptions);
|
|
31
|
+
/**
|
|
32
|
+
* Acquire a connection for the given workspace.
|
|
33
|
+
* Creates a new connection if one does not exist or the previous one was lost.
|
|
34
|
+
* Serializes creation so concurrent calls share the same connection.
|
|
35
|
+
*/
|
|
36
|
+
acquire(workspace: string): Promise<CodexAppServerClient>;
|
|
37
|
+
/**
|
|
38
|
+
* Release (dispose) a connection for the given workspace.
|
|
39
|
+
*/
|
|
40
|
+
release(workspace: string): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Dispose all connections.
|
|
43
|
+
*/
|
|
44
|
+
disposeAll(): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Notify that the workspace is active — disarm the idle timer.
|
|
47
|
+
*/
|
|
48
|
+
notifyActivity(workspace: string): void;
|
|
49
|
+
/**
|
|
50
|
+
* Notify that the workspace is idle — arm the idle timer.
|
|
51
|
+
*/
|
|
52
|
+
notifyIdle(workspace: string): void;
|
|
53
|
+
private createClient;
|
|
54
|
+
private clearIdleTimer;
|
|
55
|
+
private disposeSlot;
|
|
56
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConnectionManager: manages Codex App Server connections per workspace.
|
|
3
|
+
*
|
|
4
|
+
* Each workspace gets its own connection (transport + client). Connections are
|
|
5
|
+
* created on demand via `acquire()`, cached for reuse, and released after an
|
|
6
|
+
* idle timeout (30 minutes default).
|
|
7
|
+
*/
|
|
8
|
+
import { JsonlRpcTransport } from './transport.js';
|
|
9
|
+
import { CodexAppServerClient } from './client.js';
|
|
10
|
+
import { getLogger } from '../../../logger/index.js';
|
|
11
|
+
const DEFAULT_IDLE_TTL_MS = 30 * 60 * 1000; // 30 minutes
|
|
12
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 60_000; // 60 seconds
|
|
13
|
+
export class ConnectionManager {
|
|
14
|
+
slots = new Map();
|
|
15
|
+
binary;
|
|
16
|
+
args;
|
|
17
|
+
env;
|
|
18
|
+
requestTimeoutMs;
|
|
19
|
+
idleTtlMs;
|
|
20
|
+
/** Callback when a connection is lost — cleared from slot map. */
|
|
21
|
+
onConnectionLost;
|
|
22
|
+
constructor(opts) {
|
|
23
|
+
this.binary = opts.binary;
|
|
24
|
+
this.args = opts.args ?? ['app-server', '--stdio'];
|
|
25
|
+
this.env = opts.env ?? {};
|
|
26
|
+
this.requestTimeoutMs = opts.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
27
|
+
this.idleTtlMs = opts.idleTtlMs ?? DEFAULT_IDLE_TTL_MS;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Acquire a connection for the given workspace.
|
|
31
|
+
* Creates a new connection if one does not exist or the previous one was lost.
|
|
32
|
+
* Serializes creation so concurrent calls share the same connection.
|
|
33
|
+
*/
|
|
34
|
+
async acquire(workspace) {
|
|
35
|
+
const existing = this.slots.get(workspace);
|
|
36
|
+
if (existing) {
|
|
37
|
+
// If a create is in flight, wait for it
|
|
38
|
+
if (existing.createPromise) {
|
|
39
|
+
return existing.createPromise;
|
|
40
|
+
}
|
|
41
|
+
// If the client is ready and its transport is alive, return it
|
|
42
|
+
if (existing.client.ready && existing.client.healthy) {
|
|
43
|
+
return existing.client;
|
|
44
|
+
}
|
|
45
|
+
// Client is disposed, dead (e.g. app-server process killed externally),
|
|
46
|
+
// or not ready — replace it so the next run respawns the process.
|
|
47
|
+
this.disposeSlot(workspace);
|
|
48
|
+
}
|
|
49
|
+
const createPromise = this.createClient(workspace);
|
|
50
|
+
this.slots.set(workspace, {
|
|
51
|
+
client: null, // placeholder
|
|
52
|
+
idleTimer: null,
|
|
53
|
+
createPromise: createPromise,
|
|
54
|
+
});
|
|
55
|
+
try {
|
|
56
|
+
const client = await createPromise;
|
|
57
|
+
// P2-2 竞态:创建期间 release()/disposeAll() 已把 slot 删掉(并可能已
|
|
58
|
+
// dispose 连接)。此时不能再把新连接塞回 slot——否则会复活一个无人管理、
|
|
59
|
+
// 无 idle timer 的连接泄漏。归还给调用者继续使用,但不再缓存。
|
|
60
|
+
const slotAfterCreate = this.slots.get(workspace);
|
|
61
|
+
if (!slotAfterCreate || slotAfterCreate.createPromise !== createPromise) {
|
|
62
|
+
return client;
|
|
63
|
+
}
|
|
64
|
+
this.slots.set(workspace, {
|
|
65
|
+
client,
|
|
66
|
+
idleTimer: null,
|
|
67
|
+
createPromise: null,
|
|
68
|
+
});
|
|
69
|
+
return client;
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
// 只删除自己的槽位:并发 release + 重新 acquire 后 slot 可能已被新的
|
|
73
|
+
// createPromise 占据,误删会破坏新连接。
|
|
74
|
+
const current = this.slots.get(workspace);
|
|
75
|
+
if (current && current.createPromise === createPromise) {
|
|
76
|
+
this.slots.delete(workspace);
|
|
77
|
+
}
|
|
78
|
+
throw err;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Release (dispose) a connection for the given workspace.
|
|
83
|
+
*/
|
|
84
|
+
async release(workspace) {
|
|
85
|
+
this.disposeSlot(workspace);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Dispose all connections.
|
|
89
|
+
*/
|
|
90
|
+
async disposeAll() {
|
|
91
|
+
const workspaces = [...this.slots.keys()];
|
|
92
|
+
await Promise.all(workspaces.map((w) => this.disposeSlot(w)));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Notify that the workspace is active — disarm the idle timer.
|
|
96
|
+
*/
|
|
97
|
+
notifyActivity(workspace) {
|
|
98
|
+
const slot = this.slots.get(workspace);
|
|
99
|
+
if (slot) {
|
|
100
|
+
this.clearIdleTimer(slot);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Notify that the workspace is idle — arm the idle timer.
|
|
105
|
+
*/
|
|
106
|
+
notifyIdle(workspace) {
|
|
107
|
+
const slot = this.slots.get(workspace);
|
|
108
|
+
if (slot) {
|
|
109
|
+
this.clearIdleTimer(slot);
|
|
110
|
+
slot.idleTimer = setTimeout(() => {
|
|
111
|
+
getLogger().info(`[codex-connection-manager] idle timeout for workspace=${workspace}, releasing connection`);
|
|
112
|
+
this.disposeSlot(workspace);
|
|
113
|
+
}, this.idleTtlMs);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// =========================================================================
|
|
117
|
+
// Internal
|
|
118
|
+
// =========================================================================
|
|
119
|
+
async createClient(workspace) {
|
|
120
|
+
const transport = new JsonlRpcTransport({
|
|
121
|
+
binary: this.binary,
|
|
122
|
+
args: this.args,
|
|
123
|
+
cwd: workspace,
|
|
124
|
+
env: this.env,
|
|
125
|
+
});
|
|
126
|
+
let client = null;
|
|
127
|
+
const hooks = {
|
|
128
|
+
onNotification: (_method, _params) => {
|
|
129
|
+
// Notifications are handled by the runner via translator
|
|
130
|
+
},
|
|
131
|
+
onServerRequest: (_id, _method, _params) => {
|
|
132
|
+
// Server requests are handled by the runner via translator
|
|
133
|
+
},
|
|
134
|
+
onClose: () => {
|
|
135
|
+
getLogger().info(`[codex-connection-manager] connection closed workspace=${workspace}`);
|
|
136
|
+
// 只清理自己创建的 slot:并发 release + 重新 acquire 后 slot 可能已被
|
|
137
|
+
// 新连接占据,误删会破坏新连接。
|
|
138
|
+
if (this.slots.get(workspace)?.client === client) {
|
|
139
|
+
this.slots.delete(workspace);
|
|
140
|
+
this.onConnectionLost?.(workspace);
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
client = new CodexAppServerClient(transport, hooks, this.requestTimeoutMs);
|
|
145
|
+
await client.connect();
|
|
146
|
+
return client;
|
|
147
|
+
}
|
|
148
|
+
clearIdleTimer(slot) {
|
|
149
|
+
if (slot.idleTimer !== null) {
|
|
150
|
+
clearTimeout(slot.idleTimer);
|
|
151
|
+
slot.idleTimer = null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async disposeSlot(workspace) {
|
|
155
|
+
const slot = this.slots.get(workspace);
|
|
156
|
+
if (!slot)
|
|
157
|
+
return;
|
|
158
|
+
this.slots.delete(workspace);
|
|
159
|
+
this.clearIdleTimer(slot);
|
|
160
|
+
if (slot.client) {
|
|
161
|
+
try {
|
|
162
|
+
await slot.client.dispose();
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
getLogger().warn(`[codex-connection-manager] dispose error workspace=${workspace}: ${err}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=connection-manager.js.map
|