@walkhi/code-relax 0.1.0-beta.34 → 0.1.0-beta.35
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/dist/build-platform.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"layout":"npm-platform-packages","version":"0.1.0-beta.
|
|
1
|
+
{"layout":"npm-platform-packages","version":"0.1.0-beta.35"}
|
|
@@ -35,6 +35,7 @@ export class ManagedAppServer extends EventEmitter {
|
|
|
35
35
|
this.recordPath = path.join(stateRoot, 'managed-app-server.json');
|
|
36
36
|
this.client = client;
|
|
37
37
|
this.state = { state: 'absent', ready: false, error: null };
|
|
38
|
+
this.client.diagnosticIdentity = () => ({ kernelPid: this.state.pid ?? null, kernelCreated: this.state.created ?? null });
|
|
38
39
|
this.restartStatus = null;
|
|
39
40
|
this.stopped = true;
|
|
40
41
|
this.restarting = false;
|
|
@@ -13,7 +13,7 @@ const writerConflictMessages = ['already has an active writer', 'already has a l
|
|
|
13
13
|
|
|
14
14
|
export class ThreadWriterConflictError extends Error {
|
|
15
15
|
constructor(threadId, message) {
|
|
16
|
-
super('
|
|
16
|
+
super('该对话存在写入冲突,请稍后重试。');
|
|
17
17
|
this.name = 'ThreadWriterConflictError';
|
|
18
18
|
this.code = 'thread_writer_owned_elsewhere';
|
|
19
19
|
this.threadId = threadId;
|
|
@@ -37,6 +37,7 @@ export class SharedAppServer extends EventEmitter {
|
|
|
37
37
|
this.serverVersion = '';
|
|
38
38
|
this.epoch = randomUUID();
|
|
39
39
|
this.sequence = 0;
|
|
40
|
+
this.connectionId = null;
|
|
40
41
|
this.pending = new Map();
|
|
41
42
|
this.serverRequests = new serverRequests.Store(randomUUID(), id => {
|
|
42
43
|
this.emit('requests-changed', id);
|
|
@@ -64,6 +65,7 @@ export class SharedAppServer extends EventEmitter {
|
|
|
64
65
|
async open() {
|
|
65
66
|
const socket = await this.openSocket();
|
|
66
67
|
this.socket = socket;
|
|
68
|
+
this.connectionId = randomUUID();
|
|
67
69
|
this.ready = false;
|
|
68
70
|
this.serverVersion = '';
|
|
69
71
|
this.serverRequests.reset(randomUUID());
|
|
@@ -78,12 +80,16 @@ export class SharedAppServer extends EventEmitter {
|
|
|
78
80
|
clearTimeout(pending.timer);
|
|
79
81
|
if (message.error) {
|
|
80
82
|
const text = String(message.error.message || 'app-server 请求失败');
|
|
83
|
+
this.traceLifecycle('error', pending, { rpcCode: message.error.code,
|
|
84
|
+
writerError: writerConflictMessages.find(value => text.toLowerCase().includes(value)) || null });
|
|
81
85
|
pending.reject(writerConflictMessages.some(value => text.toLowerCase().includes(value))
|
|
82
86
|
? new ThreadWriterConflictError(pending.threadId, text)
|
|
83
87
|
: Object.assign(new Error(text), { rpcCode: message.error.code, details: message.error.data,
|
|
84
88
|
...(/^invalid cursor:/i.test(text) ? { code: 'history_cursor_expired' } : {}) }));
|
|
85
89
|
}
|
|
86
90
|
else {
|
|
91
|
+
this.traceLifecycle('complete', pending, { status: message.result?.status,
|
|
92
|
+
resultThreadId: message.result?.thread?.id });
|
|
87
93
|
try { pending.resolve(pending.transform(message.result)); }
|
|
88
94
|
catch (error) { pending.reject(error); }
|
|
89
95
|
}
|
|
@@ -93,6 +99,7 @@ export class SharedAppServer extends EventEmitter {
|
|
|
93
99
|
this.serverVersion = '';
|
|
94
100
|
for (const pending of this.pending.values()) {
|
|
95
101
|
clearTimeout(pending.timer);
|
|
102
|
+
this.traceLifecycle('disconnected', pending);
|
|
96
103
|
pending.reject(new Error('Codex 内核连接断开;发送结果可能未确认,请检查对话后再操作。'));
|
|
97
104
|
}
|
|
98
105
|
this.pending.clear();
|
|
@@ -121,24 +128,44 @@ export class SharedAppServer extends EventEmitter {
|
|
|
121
128
|
|
|
122
129
|
request(method, params, transform = value => value) {
|
|
123
130
|
const id = ++this.sequence;
|
|
131
|
+
const diagnostic = { method, requestId: id, threadId: params?.threadId, connectionId: this.connectionId,
|
|
132
|
+
...(method === 'thread/settings/update' && params?.serviceTier !== undefined ? { serviceTier: params.serviceTier } : {}) };
|
|
133
|
+
this.traceLifecycle('begin', diagnostic);
|
|
124
134
|
return new Promise((resolve, reject) => {
|
|
125
135
|
const timer = setTimeout(() => {
|
|
126
136
|
const error = Object.assign(new Error(`${method} 超时;不会自动重发,请先检查对话。`),
|
|
127
137
|
{ code: 'app_server_request_timeout' });
|
|
138
|
+
this.traceLifecycle('timeout', diagnostic);
|
|
128
139
|
if ((method === 'turn/start' || method === 'turn/steer') && this.pending.has(id)) {
|
|
129
140
|
messageDelivery.retainLateResult(this.pending.get(id), error);
|
|
130
141
|
} else { this.pending.delete(id); reject(error); }
|
|
131
142
|
}, 30000);
|
|
132
|
-
this.pending.set(id, { resolve, reject, timer, transform,
|
|
143
|
+
this.pending.set(id, { resolve, reject, timer, transform, ...diagnostic });
|
|
133
144
|
this.socket.send(JSON.stringify({ id, method, params }), error => {
|
|
134
145
|
const pending = this.pending.get(id);
|
|
135
146
|
if (!error || !pending) return;
|
|
147
|
+
this.traceLifecycle('send-error', diagnostic);
|
|
136
148
|
this.pending.delete(id);
|
|
137
149
|
clearTimeout(timer); pending.reject(error);
|
|
138
150
|
});
|
|
139
151
|
});
|
|
140
152
|
}
|
|
141
153
|
|
|
154
|
+
traceLifecycle(phase, request, extra = {}) {
|
|
155
|
+
if (!['thread/start', 'thread/resume', 'thread/unsubscribe', 'thread/settings/update', 'thread/settings/updated'].includes(request.method)) return;
|
|
156
|
+
const threadId = value => typeof value === 'string' && /^[\w-]{1,80}$/.test(value) ? value : null;
|
|
157
|
+
const identity = this.diagnosticIdentity?.() || {};
|
|
158
|
+
console.info('[thread-lifecycle]', JSON.stringify({ time: new Date().toISOString(), bridgePid: process.pid,
|
|
159
|
+
kernelPid: identity.kernelPid ?? null, kernelCreated: identity.kernelCreated ?? null,
|
|
160
|
+
connectionId: request.connectionId, serverVersion: this.serverVersion, phase,
|
|
161
|
+
method: request.method, requestId: request.requestId, threadId: threadId(request.threadId),
|
|
162
|
+
...([null, 'default', 'priority', 'fast'].includes(request.serviceTier) ? { serviceTier: request.serviceTier } : {}),
|
|
163
|
+
...(extra.resultThreadId ? { resultThreadId: threadId(extra.resultThreadId) } : {}),
|
|
164
|
+
...(typeof extra.status === 'string' && /^[\w-]{1,40}$/.test(extra.status) ? { status: extra.status } : {}),
|
|
165
|
+
...(typeof extra.rpcCode === 'number' ? { rpcCode: extra.rpcCode } : {}),
|
|
166
|
+
...(extra.writerError ? { writerError: extra.writerError } : {}) }));
|
|
167
|
+
}
|
|
168
|
+
|
|
142
169
|
async projects() {
|
|
143
170
|
await this.connect();
|
|
144
171
|
return events.readProjects((method, params) => this.request(method, params));
|
|
@@ -190,6 +217,7 @@ export class SharedAppServer extends EventEmitter {
|
|
|
190
217
|
const id = params.threadId;
|
|
191
218
|
if (method === 'thread/settings/updated') {
|
|
192
219
|
const settings = params.threadSettings;
|
|
220
|
+
this.traceLifecycle('notification', { method, threadId: id, connectionId: this.connectionId, serviceTier: settings.serviceTier ?? null });
|
|
193
221
|
this.contexts.set(id, { ...this.contexts.get(id), model: settings.model, thinking: settings.effort, serviceTier: settings.serviceTier ?? null,
|
|
194
222
|
cwd: settings.cwd, ...events.permissionState(settings) });
|
|
195
223
|
this.settingsNotifications.set(id, settings);
|
|
@@ -315,7 +343,7 @@ export class SharedAppServer extends EventEmitter {
|
|
|
315
343
|
} catch (error) {
|
|
316
344
|
snapshot?.close();
|
|
317
345
|
if (!isThreadWriterConflict(error)) throw error;
|
|
318
|
-
record = await this.readOnlyRecord(threadId, pageOptions, '
|
|
346
|
+
record = await this.readOnlyRecord(threadId, pageOptions, '该对话存在写入冲突,请稍后重试。');
|
|
319
347
|
result = null;
|
|
320
348
|
}
|
|
321
349
|
if (result) try {
|
|
@@ -390,11 +418,18 @@ export class SharedAppServer extends EventEmitter {
|
|
|
390
418
|
slot.tail = slot.tail.then(async () => {
|
|
391
419
|
if (this.subscriptions.get(threadId) !== slot) return;
|
|
392
420
|
if (slot.users || slot.readers || this.threads.get(threadId)?.tokens.size || this.keepThreadLoaded(threadId, this.threads.get(threadId))) return;
|
|
393
|
-
this.threads.delete(threadId); this.contexts.delete(threadId); this.permissionOptions.delete(threadId);
|
|
394
|
-
this.subscriptions.delete(threadId); clearTimeout(slot.expiry);
|
|
395
421
|
if (this.ready && !record?.readOnly) await this.unsubscribeThread(threadId);
|
|
422
|
+
// Keep this queue registered until unsubscribe completes. A returning reader
|
|
423
|
+
// must enqueue its resume behind it, rather than creating a second queue.
|
|
424
|
+
if (this.subscriptions.get(threadId) !== slot) return;
|
|
425
|
+
this.threads.delete(threadId); this.contexts.delete(threadId); this.permissionOptions.delete(threadId);
|
|
426
|
+
if (!slot.users && !slot.readers) this.subscriptions.delete(threadId);
|
|
427
|
+
clearTimeout(slot.expiry);
|
|
396
428
|
this.serverRequests.forget(threadId);
|
|
397
|
-
}).catch(error =>
|
|
429
|
+
}).catch(error => {
|
|
430
|
+
if (this.subscriptions.get(threadId) === slot && this.threads.get(threadId) === record && record) record.needsReload = true;
|
|
431
|
+
this.emit('subscription-error', error);
|
|
432
|
+
});
|
|
398
433
|
}
|
|
399
434
|
|
|
400
435
|
keepThreadLoaded(threadId, record) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walkhi/code-relax",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.35",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"tag": "beta"
|
|
42
42
|
},
|
|
43
43
|
"optionalDependencies": {
|
|
44
|
-
"@walkhi/code-relax-native-win32-x64": "0.1.0-beta.
|
|
45
|
-
"@walkhi/code-relax-native-darwin-arm64": "0.1.0-beta.
|
|
46
|
-
"@walkhi/code-relax-native-darwin-x64": "0.1.0-beta.
|
|
44
|
+
"@walkhi/code-relax-native-win32-x64": "0.1.0-beta.35",
|
|
45
|
+
"@walkhi/code-relax-native-darwin-arm64": "0.1.0-beta.35",
|
|
46
|
+
"@walkhi/code-relax-native-darwin-x64": "0.1.0-beta.35"
|
|
47
47
|
}
|
|
48
48
|
}
|