opencode-supertask 0.1.31 → 0.1.32-rc.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.
- package/README.md +78 -31
- package/dist/cli/index.js +1560 -538
- package/dist/cli/index.js.map +1 -1
- package/dist/config-CCUuD6Az.d.ts +26 -0
- package/dist/gateway/index.js +1533 -221
- package/dist/gateway/index.js.map +1 -1
- package/dist/plugin/supertask.js +237 -48
- package/dist/plugin/supertask.js.map +1 -1
- package/dist/web/index.d.ts +30 -1
- package/dist/web/index.js +1426 -181
- package/dist/web/index.js.map +1 -1
- package/dist/worker/index.d.ts +1 -24
- package/dist/worker/index.js +173 -23
- package/dist/worker/index.js.map +1 -1
- package/dist/worker/launcher.js +39 -7
- package/dist/worker/launcher.js.map +1 -1
- package/package.json +2 -2
package/dist/worker/index.d.ts
CHANGED
|
@@ -1,27 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
configVersion: 2;
|
|
3
|
-
worker: {
|
|
4
|
-
maxConcurrency: number;
|
|
5
|
-
pollIntervalMs: number;
|
|
6
|
-
heartbeatIntervalMs: number;
|
|
7
|
-
taskTimeoutMs: number;
|
|
8
|
-
shutdownGracePeriodMs: number;
|
|
9
|
-
};
|
|
10
|
-
scheduler: {
|
|
11
|
-
enabled: boolean;
|
|
12
|
-
checkIntervalMs: number;
|
|
13
|
-
};
|
|
14
|
-
watchdog: {
|
|
15
|
-
heartbeatTimeoutMs: number;
|
|
16
|
-
checkIntervalMs: number;
|
|
17
|
-
cleanupIntervalMs: number;
|
|
18
|
-
retentionDays: number;
|
|
19
|
-
};
|
|
20
|
-
dashboard: {
|
|
21
|
-
enabled: boolean;
|
|
22
|
-
port: number;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
1
|
+
import { G as GatewayConfig } from '../config-CCUuD6Az.js';
|
|
25
2
|
|
|
26
3
|
interface WorkerEngineOptions {
|
|
27
4
|
opencodeBin?: string;
|
package/dist/worker/index.js
CHANGED
|
@@ -5359,6 +5359,42 @@ function computeBackoff(retryCount, baseMs = 3e4, maxMs = MAX_BACKOFF_MS) {
|
|
|
5359
5359
|
return Math.min(baseMs * Math.pow(2, retryCount - 1), maxMs);
|
|
5360
5360
|
}
|
|
5361
5361
|
|
|
5362
|
+
// src/core/task-working-directory.ts
|
|
5363
|
+
import { statSync } from "fs";
|
|
5364
|
+
import { isAbsolute } from "path";
|
|
5365
|
+
var InvalidTaskWorkingDirectoryError = class extends Error {
|
|
5366
|
+
constructor(message) {
|
|
5367
|
+
super(message);
|
|
5368
|
+
this.name = "InvalidTaskWorkingDirectoryError";
|
|
5369
|
+
}
|
|
5370
|
+
};
|
|
5371
|
+
function validateTaskWorkingDirectory(cwd) {
|
|
5372
|
+
if (cwd == null) return;
|
|
5373
|
+
if (!cwd.trim()) {
|
|
5374
|
+
throw new InvalidTaskWorkingDirectoryError("\u4EFB\u52A1\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u80FD\u4E3A\u7A7A");
|
|
5375
|
+
}
|
|
5376
|
+
if (!isAbsolute(cwd)) {
|
|
5377
|
+
throw new InvalidTaskWorkingDirectoryError(`\u4EFB\u52A1\u5DE5\u4F5C\u76EE\u5F55\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\uFF1A${cwd}`);
|
|
5378
|
+
}
|
|
5379
|
+
let stat;
|
|
5380
|
+
try {
|
|
5381
|
+
stat = statSync(cwd);
|
|
5382
|
+
} catch (error) {
|
|
5383
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
5384
|
+
throw new InvalidTaskWorkingDirectoryError(`\u4EFB\u52A1\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u65E0\u6CD5\u8BBF\u95EE\uFF1A${cwd}\uFF08${detail}\uFF09`);
|
|
5385
|
+
}
|
|
5386
|
+
if (!stat.isDirectory()) {
|
|
5387
|
+
throw new InvalidTaskWorkingDirectoryError(`\u4EFB\u52A1\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u662F\u76EE\u5F55\uFF1A${cwd}`);
|
|
5388
|
+
}
|
|
5389
|
+
}
|
|
5390
|
+
|
|
5391
|
+
// src/core/task-batch.ts
|
|
5392
|
+
var TASK_BATCH_TRIM_CHARACTERS = " \n\v\f\r\xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF";
|
|
5393
|
+
function normalizeTaskBatchId(batchId) {
|
|
5394
|
+
if (batchId == null) return batchId;
|
|
5395
|
+
return batchId.trim() || null;
|
|
5396
|
+
}
|
|
5397
|
+
|
|
5362
5398
|
// src/core/services/task.service.ts
|
|
5363
5399
|
var { tasks: tasks2, taskRuns: taskRuns2 } = schema_exports;
|
|
5364
5400
|
var cleanupInvocation = 0;
|
|
@@ -5422,34 +5458,75 @@ var TaskService = class {
|
|
|
5422
5458
|
return conditions;
|
|
5423
5459
|
}
|
|
5424
5460
|
static async add(data) {
|
|
5425
|
-
|
|
5461
|
+
const normalizedData = {
|
|
5462
|
+
...data,
|
|
5463
|
+
batchId: normalizeTaskBatchId(data.batchId)
|
|
5464
|
+
};
|
|
5465
|
+
this.validateNewTask(normalizedData);
|
|
5426
5466
|
return db.transaction((tx) => {
|
|
5427
|
-
if (
|
|
5467
|
+
if (normalizedData.dependsOn != null) {
|
|
5428
5468
|
const dependency = tx.select({
|
|
5429
5469
|
id: tasks2.id,
|
|
5430
5470
|
cwd: tasks2.cwd,
|
|
5431
5471
|
status: tasks2.status,
|
|
5432
5472
|
retryCount: tasks2.retryCount,
|
|
5433
5473
|
maxRetries: tasks2.maxRetries
|
|
5434
|
-
}).from(tasks2).where(eq(tasks2.id,
|
|
5474
|
+
}).from(tasks2).where(eq(tasks2.id, normalizedData.dependsOn)).get();
|
|
5435
5475
|
if (!dependency) {
|
|
5436
|
-
throw new Error(`dependsOn \u6307\u5411\u7684\u4EFB\u52A1 #${
|
|
5476
|
+
throw new Error(`dependsOn \u6307\u5411\u7684\u4EFB\u52A1 #${normalizedData.dependsOn} \u4E0D\u5B58\u5728`);
|
|
5437
5477
|
}
|
|
5438
|
-
if ((dependency.cwd ?? null) !== (
|
|
5478
|
+
if ((dependency.cwd ?? null) !== (normalizedData.cwd ?? null)) {
|
|
5439
5479
|
throw new Error("dependsOn \u5FC5\u987B\u6307\u5411\u540C\u4E00 cwd \u7684\u4EFB\u52A1");
|
|
5440
5480
|
}
|
|
5441
5481
|
const dependencyIsRecoverable = dependency.status === "pending" || dependency.status === "running" || dependency.status === "done" || dependency.status === "failed" && (dependency.retryCount ?? 0) <= (dependency.maxRetries ?? 3);
|
|
5442
5482
|
if (!dependencyIsRecoverable) {
|
|
5443
|
-
throw new Error(`dependsOn \u6307\u5411\u7684\u4EFB\u52A1 #${
|
|
5483
|
+
throw new Error(`dependsOn \u6307\u5411\u7684\u4EFB\u52A1 #${normalizedData.dependsOn} \u5DF2\u8FDB\u5165\u4E0D\u53EF\u6062\u590D\u7EC8\u6001`);
|
|
5444
5484
|
}
|
|
5445
5485
|
}
|
|
5446
|
-
return tx.insert(tasks2).values(
|
|
5486
|
+
return tx.insert(tasks2).values(normalizedData).returning().get();
|
|
5487
|
+
}, { behavior: "immediate" });
|
|
5488
|
+
}
|
|
5489
|
+
static async update(id, data, scope = {}) {
|
|
5490
|
+
if (Object.keys(data).length === 0) throw new Error("\u81F3\u5C11\u63D0\u4F9B\u4E00\u4E2A\u8981\u4FEE\u6539\u7684\u5B57\u6BB5");
|
|
5491
|
+
const normalizedData = data.batchId === void 0 ? data : { ...data, batchId: normalizeTaskBatchId(data.batchId) ?? null };
|
|
5492
|
+
return db.transaction((tx) => {
|
|
5493
|
+
const task = tx.select().from(tasks2).where(and(
|
|
5494
|
+
eq(tasks2.id, id),
|
|
5495
|
+
sql`${tasks2.status} IN ('pending', 'failed', 'dead_letter')`,
|
|
5496
|
+
...this.buildScopeWhere(scope)
|
|
5497
|
+
)).get();
|
|
5498
|
+
if (!task) return null;
|
|
5499
|
+
this.validateNewTask({
|
|
5500
|
+
name: normalizedData.name ?? task.name,
|
|
5501
|
+
agent: normalizedData.agent ?? task.agent,
|
|
5502
|
+
model: normalizedData.model ?? task.model,
|
|
5503
|
+
prompt: normalizedData.prompt ?? task.prompt,
|
|
5504
|
+
cwd: task.cwd,
|
|
5505
|
+
category: normalizedData.category ?? task.category,
|
|
5506
|
+
importance: normalizedData.importance ?? task.importance,
|
|
5507
|
+
urgency: normalizedData.urgency ?? task.urgency,
|
|
5508
|
+
batchId: normalizedData.batchId === void 0 ? task.batchId : normalizedData.batchId,
|
|
5509
|
+
maxRetries: normalizedData.maxRetries ?? task.maxRetries,
|
|
5510
|
+
retryBackoffMs: normalizedData.retryBackoffMs ?? task.retryBackoffMs,
|
|
5511
|
+
timeoutMs: normalizedData.timeoutMs === void 0 ? task.timeoutMs : normalizedData.timeoutMs,
|
|
5512
|
+
dependsOn: task.dependsOn
|
|
5513
|
+
});
|
|
5514
|
+
const maxRetries = normalizedData.maxRetries ?? task.maxRetries ?? 3;
|
|
5515
|
+
const exhausted = task.status === "failed" && (task.retryCount ?? 0) > maxRetries;
|
|
5516
|
+
return tx.update(tasks2).set({
|
|
5517
|
+
...normalizedData,
|
|
5518
|
+
...exhausted ? {
|
|
5519
|
+
status: "dead_letter",
|
|
5520
|
+
retryAfter: null
|
|
5521
|
+
} : {}
|
|
5522
|
+
}).where(eq(tasks2.id, id)).returning().get() ?? null;
|
|
5447
5523
|
}, { behavior: "immediate" });
|
|
5448
5524
|
}
|
|
5449
5525
|
static validateNewTask(data) {
|
|
5450
5526
|
if (!data.name.trim()) throw new Error("name \u4E0D\u80FD\u4E3A\u7A7A");
|
|
5451
5527
|
if (!data.agent.trim()) throw new Error("agent \u4E0D\u80FD\u4E3A\u7A7A");
|
|
5452
5528
|
if (!data.prompt.trim()) throw new Error("prompt \u4E0D\u80FD\u4E3A\u7A7A");
|
|
5529
|
+
validateTaskWorkingDirectory(data.cwd);
|
|
5453
5530
|
this.validateInteger("importance", data.importance, 1, 5);
|
|
5454
5531
|
this.validateInteger("urgency", data.urgency, 1, 5);
|
|
5455
5532
|
this.validateInteger("maxRetries", data.maxRetries, 0, 1e3);
|
|
@@ -5470,12 +5547,14 @@ var TaskService = class {
|
|
|
5470
5547
|
isNull(tasks2.retryAfter),
|
|
5471
5548
|
sql`${tasks2.retryAfter} <= ${nowMs}`
|
|
5472
5549
|
);
|
|
5473
|
-
const
|
|
5550
|
+
const excludedBatchIds = [...new Set((scope.excludedBatchIds ?? []).map((batchId) => normalizeTaskBatchId(batchId)).filter((batchId) => Boolean(batchId)))];
|
|
5551
|
+
const hasExcludedBatches = excludedBatchIds.length > 0;
|
|
5474
5552
|
let batchFilter;
|
|
5475
5553
|
if (hasExcludedBatches) {
|
|
5476
5554
|
batchFilter = or(
|
|
5477
5555
|
isNull(tasks2.batchId),
|
|
5478
|
-
sql
|
|
5556
|
+
sql`trim(${tasks2.batchId}, ${TASK_BATCH_TRIM_CHARACTERS}) = ''`,
|
|
5557
|
+
sql`trim(${tasks2.batchId}, ${TASK_BATCH_TRIM_CHARACTERS}) NOT IN ${excludedBatchIds}`
|
|
5479
5558
|
);
|
|
5480
5559
|
}
|
|
5481
5560
|
const statusConditions = or(
|
|
@@ -5509,9 +5588,11 @@ var TaskService = class {
|
|
|
5509
5588
|
),
|
|
5510
5589
|
or(
|
|
5511
5590
|
isNull(tasks2.batchId),
|
|
5591
|
+
sql`trim(${tasks2.batchId}, ${TASK_BATCH_TRIM_CHARACTERS}) = ''`,
|
|
5512
5592
|
sql`NOT EXISTS (
|
|
5513
5593
|
SELECT 1 FROM tasks AS running_batch_task
|
|
5514
|
-
WHERE running_batch_task.batch_id
|
|
5594
|
+
WHERE trim(running_batch_task.batch_id, ${TASK_BATCH_TRIM_CHARACTERS})
|
|
5595
|
+
= trim(${tasks2.batchId}, ${TASK_BATCH_TRIM_CHARACTERS})
|
|
5515
5596
|
AND (
|
|
5516
5597
|
running_batch_task.status = 'running'
|
|
5517
5598
|
OR EXISTS (
|
|
@@ -5535,12 +5616,18 @@ var TaskService = class {
|
|
|
5535
5616
|
).limit(1);
|
|
5536
5617
|
return result[0] ?? null;
|
|
5537
5618
|
}
|
|
5538
|
-
static async countRunning() {
|
|
5619
|
+
static async countRunning(scope = {}) {
|
|
5620
|
+
const scopeConditions = scope.legacyCwd ? [sql`${tasks2.cwd} IS NULL OR trim(${tasks2.cwd}) = ''`] : this.buildScopeWhere(scope);
|
|
5621
|
+
if (scope.batchId !== void 0) {
|
|
5622
|
+
const batchId = normalizeTaskBatchId(scope.batchId);
|
|
5623
|
+
scopeConditions.push(batchId ? sql`trim(${tasks2.batchId}, ${TASK_BATCH_TRIM_CHARACTERS}) = ${batchId}` : sql`0`);
|
|
5624
|
+
}
|
|
5539
5625
|
return db.transaction((tx) => {
|
|
5540
|
-
const runningTasks = tx.select({ count: sql`count(*)` }).from(tasks2).where(eq(tasks2.status, "running")).get();
|
|
5626
|
+
const runningTasks = tx.select({ count: sql`count(*)` }).from(tasks2).where(and(eq(tasks2.status, "running"), ...scopeConditions)).get();
|
|
5541
5627
|
const runsWithoutRunningTask = tx.select({ count: sql`count(DISTINCT ${taskRuns2.taskId})` }).from(taskRuns2).innerJoin(tasks2, eq(tasks2.id, taskRuns2.taskId)).where(and(
|
|
5542
5628
|
eq(taskRuns2.status, "running"),
|
|
5543
|
-
sql`${tasks2.status} <> 'running'
|
|
5629
|
+
sql`${tasks2.status} <> 'running'`,
|
|
5630
|
+
...scopeConditions
|
|
5544
5631
|
)).get();
|
|
5545
5632
|
return Number(runningTasks?.count ?? 0) + Number(runsWithoutRunningTask?.count ?? 0);
|
|
5546
5633
|
}, { behavior: "deferred" });
|
|
@@ -5873,15 +5960,17 @@ var TaskService = class {
|
|
|
5873
5960
|
}).where(and(...conditions, hasViableDependency())).returning().get() ?? null, { behavior: "immediate" });
|
|
5874
5961
|
}
|
|
5875
5962
|
static async retryBatch(batchId, scope = {}) {
|
|
5963
|
+
const normalizedBatchId = normalizeTaskBatchId(batchId);
|
|
5964
|
+
if (!normalizedBatchId) return 0;
|
|
5876
5965
|
const sqlite2 = getSqlite();
|
|
5877
5966
|
const scopeFilter = scope.cwd === void 0 ? "" : "AND candidate.cwd = ?";
|
|
5878
|
-
const parameters = scope.cwd === void 0 ? [
|
|
5967
|
+
const parameters = scope.cwd === void 0 ? [TASK_BATCH_TRIM_CHARACTERS, normalizedBatchId] : [TASK_BATCH_TRIM_CHARACTERS, normalizedBatchId, scope.cwd];
|
|
5879
5968
|
return db.transaction(() => sqlite2.query(`
|
|
5880
5969
|
WITH RECURSIVE
|
|
5881
5970
|
candidate(id, cwd, depends_on) AS MATERIALIZED (
|
|
5882
5971
|
SELECT candidate.id, candidate.cwd, candidate.depends_on
|
|
5883
5972
|
FROM tasks AS candidate
|
|
5884
|
-
WHERE candidate.batch_id = ?
|
|
5973
|
+
WHERE trim(candidate.batch_id, ?) = ?
|
|
5885
5974
|
AND candidate.status IN ('failed', 'dead_letter')
|
|
5886
5975
|
${scopeFilter}
|
|
5887
5976
|
),
|
|
@@ -5935,16 +6024,28 @@ var TaskService = class {
|
|
|
5935
6024
|
static async list(options = {}) {
|
|
5936
6025
|
let query = db.select().from(tasks2).$dynamic();
|
|
5937
6026
|
const conditions = [];
|
|
5938
|
-
if (options.
|
|
6027
|
+
if (options.activeExecution) {
|
|
6028
|
+
conditions.push(or(
|
|
6029
|
+
eq(tasks2.status, "running"),
|
|
6030
|
+
sql`EXISTS (
|
|
6031
|
+
SELECT 1 FROM task_runs AS active_list_run
|
|
6032
|
+
WHERE active_list_run.task_id = ${tasks2.id}
|
|
6033
|
+
AND active_list_run.status = 'running'
|
|
6034
|
+
)`
|
|
6035
|
+
));
|
|
6036
|
+
} else if (options.status) {
|
|
5939
6037
|
conditions.push(eq(tasks2.status, options.status));
|
|
5940
6038
|
}
|
|
5941
|
-
if (options.batchId) {
|
|
5942
|
-
|
|
6039
|
+
if (options.batchId !== void 0) {
|
|
6040
|
+
const batchId = normalizeTaskBatchId(options.batchId);
|
|
6041
|
+
conditions.push(batchId ? sql`trim(${tasks2.batchId}, ${TASK_BATCH_TRIM_CHARACTERS}) = ${batchId}` : sql`0`);
|
|
5943
6042
|
}
|
|
5944
6043
|
if (options.category) {
|
|
5945
6044
|
conditions.push(eq(tasks2.category, options.category));
|
|
5946
6045
|
}
|
|
5947
|
-
if (options.
|
|
6046
|
+
if (options.legacyCwd) {
|
|
6047
|
+
conditions.push(sql`${tasks2.cwd} IS NULL OR trim(${tasks2.cwd}) = ''`);
|
|
6048
|
+
} else if (options.cwd !== void 0) {
|
|
5948
6049
|
conditions.push(eq(tasks2.cwd, options.cwd));
|
|
5949
6050
|
}
|
|
5950
6051
|
if (conditions.length > 0) {
|
|
@@ -5962,9 +6063,12 @@ var TaskService = class {
|
|
|
5962
6063
|
static async stats(options = {}) {
|
|
5963
6064
|
const conditions = [];
|
|
5964
6065
|
if (options.batchId !== void 0) {
|
|
5965
|
-
|
|
6066
|
+
const batchId = normalizeTaskBatchId(options.batchId);
|
|
6067
|
+
conditions.push(batchId ? sql`trim(${tasks2.batchId}, ${TASK_BATCH_TRIM_CHARACTERS}) = ${batchId}` : sql`0`);
|
|
5966
6068
|
}
|
|
5967
|
-
if (options.
|
|
6069
|
+
if (options.legacyCwd) {
|
|
6070
|
+
conditions.push(sql`${tasks2.cwd} IS NULL OR trim(${tasks2.cwd}) = ''`);
|
|
6071
|
+
} else if (options.cwd !== void 0) {
|
|
5968
6072
|
conditions.push(eq(tasks2.cwd, options.cwd));
|
|
5969
6073
|
}
|
|
5970
6074
|
const whereCondition = conditions.length > 0 ? and(...conditions) : void 0;
|
|
@@ -5989,6 +6093,33 @@ var TaskService = class {
|
|
|
5989
6093
|
}
|
|
5990
6094
|
return stats;
|
|
5991
6095
|
}
|
|
6096
|
+
static async projectSummaries(limit = 100) {
|
|
6097
|
+
this.validateInteger("limit", limit, 1, 1e3);
|
|
6098
|
+
const lastCreatedAt = sql`max(${tasks2.createdAt})`;
|
|
6099
|
+
const lastTaskId = sql`max(${tasks2.id})`;
|
|
6100
|
+
const rows = await db.select({
|
|
6101
|
+
cwd: tasks2.cwd,
|
|
6102
|
+
total: sql`count(*)`,
|
|
6103
|
+
pending: sql`sum(CASE WHEN ${tasks2.status} = 'pending' THEN 1 ELSE 0 END)`,
|
|
6104
|
+
running: sql`sum(CASE WHEN ${tasks2.status} = 'running' OR EXISTS (
|
|
6105
|
+
SELECT 1 FROM task_runs AS active_project_run
|
|
6106
|
+
WHERE active_project_run.task_id = ${tasks2.id}
|
|
6107
|
+
AND active_project_run.status = 'running'
|
|
6108
|
+
) THEN 1 ELSE 0 END)`,
|
|
6109
|
+
failed: sql`sum(CASE WHEN ${tasks2.status} IN ('failed', 'dead_letter') THEN 1 ELSE 0 END)`,
|
|
6110
|
+
done: sql`sum(CASE WHEN ${tasks2.status} = 'done' THEN 1 ELSE 0 END)`,
|
|
6111
|
+
lastCreatedAt
|
|
6112
|
+
}).from(tasks2).where(sql`${tasks2.cwd} IS NOT NULL AND trim(${tasks2.cwd}) <> ''`).groupBy(tasks2.cwd).orderBy(desc(lastCreatedAt), desc(lastTaskId)).limit(limit);
|
|
6113
|
+
return rows.flatMap((row) => row.cwd === null ? [] : [{
|
|
6114
|
+
cwd: row.cwd,
|
|
6115
|
+
total: Number(row.total),
|
|
6116
|
+
pending: Number(row.pending),
|
|
6117
|
+
running: Number(row.running),
|
|
6118
|
+
failed: Number(row.failed),
|
|
6119
|
+
done: Number(row.done),
|
|
6120
|
+
lastCreatedAt: row.lastCreatedAt === null ? null : Number(row.lastCreatedAt) * 1e3
|
|
6121
|
+
}]);
|
|
6122
|
+
}
|
|
5992
6123
|
static async delete(id, scope = {}) {
|
|
5993
6124
|
const conditions = [
|
|
5994
6125
|
eq(tasks2.id, id),
|
|
@@ -6125,11 +6256,15 @@ import { basename, dirname as dirname2, resolve } from "path";
|
|
|
6125
6256
|
var TOKEN_GUARDIAN_LAUNCH_PROTOCOL = "gated-v3-token-guardian";
|
|
6126
6257
|
var LAUNCH_IDENTITY_ARGUMENT = "--supertask-launch-identity";
|
|
6127
6258
|
var DRAIN_PROOF_MESSAGE_TYPE = "supertask-drained";
|
|
6259
|
+
var DRAIN_PROOF_ACK_MESSAGE_TYPE = "supertask-drained-ack";
|
|
6128
6260
|
var MANAGED_RUN_ENV = "SUPERTASK_MANAGED_RUN";
|
|
6129
6261
|
var MANAGED_RUN_ENV_VALUE = "1";
|
|
6130
6262
|
function isLaunchIdentity(value) {
|
|
6131
6263
|
return value != null && /^gateway-[1-9]\d*:launch:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
6132
6264
|
}
|
|
6265
|
+
function drainProofAckForIdentity(launchIdentity) {
|
|
6266
|
+
return { type: DRAIN_PROOF_ACK_MESSAGE_TYPE, identity: launchIdentity };
|
|
6267
|
+
}
|
|
6133
6268
|
function isMatchingDrainProof(message, launchIdentity) {
|
|
6134
6269
|
if (typeof message !== "object" || message == null) return false;
|
|
6135
6270
|
const candidate = message;
|
|
@@ -6627,7 +6762,8 @@ var WorkerEngine = class {
|
|
|
6627
6762
|
if (!task) break;
|
|
6628
6763
|
if (this.stopped) break;
|
|
6629
6764
|
if (!await TaskService.start(task.id)) continue;
|
|
6630
|
-
|
|
6765
|
+
const batchId = normalizeTaskBatchId(task.batchId);
|
|
6766
|
+
if (batchId) this.activeBatchIds.add(batchId);
|
|
6631
6767
|
if (this.stopped) {
|
|
6632
6768
|
await TaskService.resetRunningToPending([task.id]);
|
|
6633
6769
|
this.releaseBatch(task);
|
|
@@ -6658,6 +6794,14 @@ var WorkerEngine = class {
|
|
|
6658
6794
|
this.releaseBatch(task);
|
|
6659
6795
|
continue;
|
|
6660
6796
|
}
|
|
6797
|
+
try {
|
|
6798
|
+
validateTaskWorkingDirectory(task.cwd);
|
|
6799
|
+
} catch (error) {
|
|
6800
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6801
|
+
await TaskService.failRun(task.id, run.id, message, { setDeadLetter: true });
|
|
6802
|
+
this.releaseBatch(task);
|
|
6803
|
+
continue;
|
|
6804
|
+
}
|
|
6661
6805
|
await this.spawnTask(task, run.id, launchIdentity);
|
|
6662
6806
|
} catch (err) {
|
|
6663
6807
|
this.releaseBatch(task);
|
|
@@ -6743,6 +6887,11 @@ var WorkerEngine = class {
|
|
|
6743
6887
|
child.on("message", (message) => {
|
|
6744
6888
|
if (isMatchingDrainProof(message, entry.launchIdentity)) {
|
|
6745
6889
|
entry.guardianDrained = true;
|
|
6890
|
+
try {
|
|
6891
|
+
child.send(drainProofAckForIdentity(entry.launchIdentity));
|
|
6892
|
+
} catch (error) {
|
|
6893
|
+
this.logError("drain proof acknowledgment failed", error, task.id);
|
|
6894
|
+
}
|
|
6746
6895
|
}
|
|
6747
6896
|
});
|
|
6748
6897
|
let spawnError = null;
|
|
@@ -7022,7 +7171,8 @@ ${output}` : ""}` : output;
|
|
|
7022
7171
|
);
|
|
7023
7172
|
}
|
|
7024
7173
|
releaseBatch(task) {
|
|
7025
|
-
|
|
7174
|
+
const batchId = normalizeTaskBatchId(task.batchId);
|
|
7175
|
+
if (batchId) this.activeBatchIds.delete(batchId);
|
|
7026
7176
|
}
|
|
7027
7177
|
resolveModel(taskModel) {
|
|
7028
7178
|
if (!taskModel || taskModel === "default") return null;
|