@cjhyy/code-shell-server 0.9.20 → 0.9.21
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/panels/runtime.js +39 -14
- package/dist/panels/tool-jobs.d.ts +1 -1
- package/dist/panels/tool-jobs.js +23 -1
- package/package.json +5 -5
package/dist/panels/runtime.js
CHANGED
|
@@ -447,6 +447,7 @@ export function createPanelRuntime(options) {
|
|
|
447
447
|
}, 60_000);
|
|
448
448
|
reaper.unref();
|
|
449
449
|
const preparing = new Set();
|
|
450
|
+
const preparingTools = new Set();
|
|
450
451
|
async function dispatchToolJobs(grant, method, params) {
|
|
451
452
|
if (!grant.app.permissions.includes("process") || !grant.app.permissions.includes("resources"))
|
|
452
453
|
error(403, "原生后台任务需要 process 和 resources 权限。");
|
|
@@ -466,21 +467,37 @@ export function createPanelRuntime(options) {
|
|
|
466
467
|
error(403, "你取消了后台工具执行。");
|
|
467
468
|
if (!(await authorized(grant)))
|
|
468
469
|
error(410, "面板授权已失效。");
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
470
|
+
const preparation = {
|
|
471
|
+
owner: grant.owner,
|
|
472
|
+
appId: scope.appId,
|
|
473
|
+
controller: new AbortController(),
|
|
474
|
+
};
|
|
475
|
+
preparingTools.add(preparation);
|
|
476
|
+
try {
|
|
477
|
+
const job = await service.start(scope, {
|
|
478
|
+
entry: { name: input.entry, sha256: entry.sha256 },
|
|
479
|
+
input: input.input,
|
|
480
|
+
recovery: input.recovery ?? "manual",
|
|
481
|
+
requestKey: input.requestKey,
|
|
482
|
+
}, preparation.controller.signal);
|
|
483
|
+
if (!jobOwners.has(job.id))
|
|
484
|
+
jobOwners.set(job.id, { owner: grant.owner, scope });
|
|
485
|
+
if (!(await authorized(grant))) {
|
|
486
|
+
if (jobOwners.get(job.id)?.owner === grant.owner)
|
|
487
|
+
await service.cancel(scope, job.id);
|
|
488
|
+
error(410, "登录授权已撤销。");
|
|
489
|
+
}
|
|
490
|
+
emitTaskEvent(await service.get(scope, job.id));
|
|
491
|
+
return job;
|
|
492
|
+
}
|
|
493
|
+
catch (cause) {
|
|
494
|
+
if (preparation.controller.signal.aborted)
|
|
495
|
+
error(410, "登录授权已撤销,输入准备已取消。");
|
|
496
|
+
throw cause;
|
|
497
|
+
}
|
|
498
|
+
finally {
|
|
499
|
+
preparingTools.delete(preparation);
|
|
481
500
|
}
|
|
482
|
-
emitTaskEvent(await service.get(scope, job.id));
|
|
483
|
-
return job;
|
|
484
501
|
}
|
|
485
502
|
if (method === "tasks.list") {
|
|
486
503
|
const offset = input.offset ?? 0, limit = input.limit ?? 50;
|
|
@@ -743,6 +760,9 @@ export function createPanelRuntime(options) {
|
|
|
743
760
|
};
|
|
744
761
|
}
|
|
745
762
|
function cancelOwner(owner) {
|
|
763
|
+
for (const preparation of preparingTools)
|
|
764
|
+
if (preparation.owner === owner)
|
|
765
|
+
preparation.controller.abort();
|
|
746
766
|
for (const preparation of preparing)
|
|
747
767
|
if (preparation.owner === owner)
|
|
748
768
|
preparation.cancelled = true;
|
|
@@ -1187,6 +1207,9 @@ export function createPanelRuntime(options) {
|
|
|
1187
1207
|
cancelOwner,
|
|
1188
1208
|
invalidate(appId) {
|
|
1189
1209
|
generation++;
|
|
1210
|
+
for (const preparation of preparingTools)
|
|
1211
|
+
if (!appId || preparation.appId === appId)
|
|
1212
|
+
preparation.controller.abort();
|
|
1190
1213
|
for (const grant of grants.values())
|
|
1191
1214
|
if (!appId || grant.app.id === appId)
|
|
1192
1215
|
remove(grant);
|
|
@@ -1199,6 +1222,8 @@ export function createPanelRuntime(options) {
|
|
|
1199
1222
|
},
|
|
1200
1223
|
async close() {
|
|
1201
1224
|
closed = true;
|
|
1225
|
+
for (const preparation of preparingTools)
|
|
1226
|
+
preparation.controller.abort();
|
|
1202
1227
|
clearInterval(reaper);
|
|
1203
1228
|
for (const grant of grants.values())
|
|
1204
1229
|
remove(grant);
|
|
@@ -92,7 +92,7 @@ export declare class PanelToolJobService {
|
|
|
92
92
|
get(rawScope: ToolJobScope, id: string): Promise<ToolJob & {
|
|
93
93
|
readOnly: boolean;
|
|
94
94
|
}>;
|
|
95
|
-
start(rawScope: ToolJobScope, request: ToolJobRequest): Promise<ToolJob>;
|
|
95
|
+
start(rawScope: ToolJobScope, request: ToolJobRequest, signal?: AbortSignal): Promise<ToolJob>;
|
|
96
96
|
private schedule;
|
|
97
97
|
private pump;
|
|
98
98
|
private run;
|
package/dist/panels/tool-jobs.js
CHANGED
|
@@ -208,7 +208,8 @@ export class PanelToolJobService {
|
|
|
208
208
|
const job = this.lookup(scope, id);
|
|
209
209
|
return { ...publicJob(job), readOnly: job.scope.revision !== scope.revision };
|
|
210
210
|
}
|
|
211
|
-
async start(rawScope, request) {
|
|
211
|
+
async start(rawScope, request, signal) {
|
|
212
|
+
signal?.throwIfAborted();
|
|
212
213
|
const scope = scopeValue(rawScope);
|
|
213
214
|
const entry = entryValue(request?.entry);
|
|
214
215
|
if (!["manual", "retry"].includes(request.recovery))
|
|
@@ -232,6 +233,7 @@ export class PanelToolJobService {
|
|
|
232
233
|
await this.authorize(scope);
|
|
233
234
|
let done;
|
|
234
235
|
const reservation = await this.exclusive(async () => {
|
|
236
|
+
signal?.throwIfAborted();
|
|
235
237
|
if (this.stopping)
|
|
236
238
|
throw new Error("tool job service is shutting down");
|
|
237
239
|
if (request.requestKey) {
|
|
@@ -268,8 +270,14 @@ export class PanelToolJobService {
|
|
|
268
270
|
if (reservation.existing)
|
|
269
271
|
return publicJob(reservation.existing);
|
|
270
272
|
const { id, controller } = reservation;
|
|
273
|
+
const abort = () => controller.abort(signal?.reason);
|
|
274
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
275
|
+
if (signal?.aborted)
|
|
276
|
+
abort();
|
|
271
277
|
try {
|
|
278
|
+
controller.signal.throwIfAborted();
|
|
272
279
|
const workDir = await this.storage.directory(id, true, true);
|
|
280
|
+
controller.signal.throwIfAborted();
|
|
273
281
|
const prepared = this.options.prepareInput
|
|
274
282
|
? await this.options.prepareInput(scope, input, workDir, controller.signal)
|
|
275
283
|
: input;
|
|
@@ -296,6 +304,19 @@ export class PanelToolJobService {
|
|
|
296
304
|
[...this.jobs.values()].some((other) => sameScope(other.scope, scope) && other.requestKey === request.requestKey))
|
|
297
305
|
throw new Error("tool job request key is already being prepared");
|
|
298
306
|
await this.commit(job);
|
|
307
|
+
// Cancellation can arrive during the durable write. The serial fence
|
|
308
|
+
// prevents the scheduler from selecting this job before cancellation.
|
|
309
|
+
if (controller.signal.aborted) {
|
|
310
|
+
job.status = "cancelled";
|
|
311
|
+
job.completedAt = this.now();
|
|
312
|
+
job.error = {
|
|
313
|
+
code: "CANCELLED",
|
|
314
|
+
message: "Task was cancelled before execution.",
|
|
315
|
+
retryable: job.recovery === "retry",
|
|
316
|
+
};
|
|
317
|
+
await this.commit(job);
|
|
318
|
+
controller.signal.throwIfAborted();
|
|
319
|
+
}
|
|
299
320
|
});
|
|
300
321
|
this.schedule();
|
|
301
322
|
return publicJob(job);
|
|
@@ -307,6 +328,7 @@ export class PanelToolJobService {
|
|
|
307
328
|
throw error;
|
|
308
329
|
}
|
|
309
330
|
finally {
|
|
331
|
+
signal?.removeEventListener("abort", abort);
|
|
310
332
|
this.preparing.delete(id);
|
|
311
333
|
done();
|
|
312
334
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cjhyy/code-shell-server",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.21",
|
|
4
4
|
"description": "CodeShell server transport layer — mobile remote HTTP/WS host, pairing, passcode gate, tunnel, rooms, uploads, and session/attachment services. Electron-free; precursor of the auth gateway.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -51,13 +51,13 @@
|
|
|
51
51
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@cjhyy/code-shell-capability-coding": "0.9.
|
|
55
|
-
"@cjhyy/code-shell-core": "0.9.
|
|
56
|
-
"@cjhyy/code-shell-web": "0.9.
|
|
54
|
+
"@cjhyy/code-shell-capability-coding": "0.9.21",
|
|
55
|
+
"@cjhyy/code-shell-core": "0.9.21",
|
|
56
|
+
"@cjhyy/code-shell-web": "0.9.21",
|
|
57
57
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
58
58
|
"@types/ws": "^8.18.1",
|
|
59
59
|
"ws": "^8.21.0",
|
|
60
|
-
"@cjhyy/code-shell-link": "0.9.
|
|
60
|
+
"@cjhyy/code-shell-link": "0.9.21"
|
|
61
61
|
},
|
|
62
62
|
"engines": {
|
|
63
63
|
"node": ">=20.10"
|