opencode-supertask 0.1.39 → 0.1.41
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 +27 -1
- package/LICENSE +21 -0
- package/README.md +159 -352
- package/README.zh-CN.md +250 -0
- package/dist/cli/index.js +580 -171
- package/dist/cli/index.js.map +1 -1
- package/dist/daemon/gateway-diagnostic-runner.d.ts +2 -0
- package/dist/daemon/gateway-diagnostic-runner.js +461 -0
- package/dist/daemon/gateway-diagnostic-runner.js.map +1 -0
- package/dist/gateway/index.js +543 -615
- package/dist/gateway/index.js.map +1 -1
- package/dist/plugin/supertask.js +90 -28
- package/dist/plugin/supertask.js.map +1 -1
- package/dist/web/index.js +410 -528
- package/dist/web/index.js.map +1 -1
- package/dist/worker/index.d.ts +9 -0
- package/dist/worker/index.js +225 -69
- package/dist/worker/index.js.map +1 -1
- package/dist/worker/launcher.js.map +1 -1
- package/drizzle/0008_good_smasher.sql +3 -0
- package/drizzle/meta/0008_snapshot.json +606 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +12 -3
package/dist/cli/index.js
CHANGED
|
@@ -4506,7 +4506,7 @@ var init_sql = __esm({
|
|
|
4506
4506
|
return new SQL([new StringChunk(str)]);
|
|
4507
4507
|
}
|
|
4508
4508
|
sql2.raw = raw2;
|
|
4509
|
-
function
|
|
4509
|
+
function join9(chunks, separator) {
|
|
4510
4510
|
const result = [];
|
|
4511
4511
|
for (const [i, chunk] of chunks.entries()) {
|
|
4512
4512
|
if (i > 0 && separator !== void 0) {
|
|
@@ -4516,7 +4516,7 @@ var init_sql = __esm({
|
|
|
4516
4516
|
}
|
|
4517
4517
|
return new SQL(result);
|
|
4518
4518
|
}
|
|
4519
|
-
sql2.join =
|
|
4519
|
+
sql2.join = join9;
|
|
4520
4520
|
function identifier(value) {
|
|
4521
4521
|
return new Name(value);
|
|
4522
4522
|
}
|
|
@@ -7132,7 +7132,7 @@ var init_select2 = __esm({
|
|
|
7132
7132
|
return (table, on) => {
|
|
7133
7133
|
const baseTableName = this.tableName;
|
|
7134
7134
|
const tableName = getTableLikeName(table);
|
|
7135
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
7135
|
+
if (typeof tableName === "string" && this.config.joins?.some((join9) => join9.alias === tableName)) {
|
|
7136
7136
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
7137
7137
|
}
|
|
7138
7138
|
if (!this.isPartialSelect) {
|
|
@@ -7974,7 +7974,7 @@ var init_update = __esm({
|
|
|
7974
7974
|
createJoin(joinType) {
|
|
7975
7975
|
return (table, on) => {
|
|
7976
7976
|
const tableName = getTableLikeName(table);
|
|
7977
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
7977
|
+
if (typeof tableName === "string" && this.config.joins.some((join9) => join9.alias === tableName)) {
|
|
7978
7978
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
7979
7979
|
}
|
|
7980
7980
|
if (typeof on === "function") {
|
|
@@ -9307,6 +9307,7 @@ var init_schema = __esm({
|
|
|
9307
9307
|
name: text("name").notNull(),
|
|
9308
9308
|
agent: text("agent").notNull(),
|
|
9309
9309
|
model: text("model").default("default"),
|
|
9310
|
+
variant: text("variant"),
|
|
9310
9311
|
prompt: text("prompt").notNull(),
|
|
9311
9312
|
cwd: text("cwd"),
|
|
9312
9313
|
// 分类与优先级
|
|
@@ -9351,6 +9352,7 @@ var init_schema = __esm({
|
|
|
9351
9352
|
taskId: integer("task_id").notNull().references(() => tasks.id, { onDelete: "cascade" }),
|
|
9352
9353
|
sessionId: text("session_id"),
|
|
9353
9354
|
model: text("model"),
|
|
9355
|
+
variant: text("variant"),
|
|
9354
9356
|
status: text("status").default("running"),
|
|
9355
9357
|
startedAt: integer("started_at", { mode: "timestamp" }).$defaultFn(() => /* @__PURE__ */ new Date()),
|
|
9356
9358
|
finishedAt: integer("finished_at", { mode: "timestamp" }),
|
|
@@ -9371,6 +9373,7 @@ var init_schema = __esm({
|
|
|
9371
9373
|
name: text("name").notNull(),
|
|
9372
9374
|
agent: text("agent").notNull(),
|
|
9373
9375
|
model: text("model").default("default"),
|
|
9376
|
+
variant: text("variant"),
|
|
9374
9377
|
prompt: text("prompt").notNull(),
|
|
9375
9378
|
cwd: text("cwd"),
|
|
9376
9379
|
category: text("category").default("general"),
|
|
@@ -9631,6 +9634,28 @@ var init_task_batch = __esm({
|
|
|
9631
9634
|
}
|
|
9632
9635
|
});
|
|
9633
9636
|
|
|
9637
|
+
// src/core/model-variant.ts
|
|
9638
|
+
function normalizeModelVariant(value) {
|
|
9639
|
+
if (value === void 0 || value === null) return value;
|
|
9640
|
+
const normalized = value.trim();
|
|
9641
|
+
if (!normalized) return null;
|
|
9642
|
+
if (normalized.length > MAX_MODEL_VARIANT_LENGTH) {
|
|
9643
|
+
throw new Error(`variant \u957F\u5EA6\u4E0D\u80FD\u8D85\u8FC7 ${MAX_MODEL_VARIANT_LENGTH} \u4E2A\u5B57\u7B26`);
|
|
9644
|
+
}
|
|
9645
|
+
if (CONTROL_CHARACTER_PATTERN.test(normalized)) {
|
|
9646
|
+
throw new Error("variant \u4E0D\u80FD\u5305\u542B\u63A7\u5236\u5B57\u7B26");
|
|
9647
|
+
}
|
|
9648
|
+
return normalized;
|
|
9649
|
+
}
|
|
9650
|
+
var MAX_MODEL_VARIANT_LENGTH, CONTROL_CHARACTER_PATTERN;
|
|
9651
|
+
var init_model_variant = __esm({
|
|
9652
|
+
"src/core/model-variant.ts"() {
|
|
9653
|
+
"use strict";
|
|
9654
|
+
MAX_MODEL_VARIANT_LENGTH = 128;
|
|
9655
|
+
CONTROL_CHARACTER_PATTERN = /[\u0000-\u001F\u007F]/;
|
|
9656
|
+
}
|
|
9657
|
+
});
|
|
9658
|
+
|
|
9634
9659
|
// src/core/services/task.service.ts
|
|
9635
9660
|
function hasNoExecutableDependents() {
|
|
9636
9661
|
return sql`NOT EXISTS (
|
|
@@ -9686,6 +9711,7 @@ var init_task_service = __esm({
|
|
|
9686
9711
|
init_backoff();
|
|
9687
9712
|
init_task_working_directory();
|
|
9688
9713
|
init_task_batch();
|
|
9714
|
+
init_model_variant();
|
|
9689
9715
|
({ tasks: tasks2, taskRuns: taskRuns2 } = schema_exports);
|
|
9690
9716
|
cleanupInvocation = 0;
|
|
9691
9717
|
TaskDeletionConflictError = class extends Error {
|
|
@@ -9705,7 +9731,8 @@ var init_task_service = __esm({
|
|
|
9705
9731
|
static async add(data) {
|
|
9706
9732
|
const normalizedData = {
|
|
9707
9733
|
...data,
|
|
9708
|
-
batchId: normalizeTaskBatchId(data.batchId)
|
|
9734
|
+
batchId: normalizeTaskBatchId(data.batchId),
|
|
9735
|
+
variant: normalizeModelVariant(data.variant)
|
|
9709
9736
|
};
|
|
9710
9737
|
this.validateNewTask(normalizedData);
|
|
9711
9738
|
return db.transaction((tx) => {
|
|
@@ -9733,7 +9760,11 @@ var init_task_service = __esm({
|
|
|
9733
9760
|
}
|
|
9734
9761
|
static async update(id, data, scope = {}) {
|
|
9735
9762
|
if (Object.keys(data).length === 0) throw new Error("\u81F3\u5C11\u63D0\u4F9B\u4E00\u4E2A\u8981\u4FEE\u6539\u7684\u5B57\u6BB5");
|
|
9736
|
-
const normalizedData =
|
|
9763
|
+
const normalizedData = {
|
|
9764
|
+
...data,
|
|
9765
|
+
...data.batchId === void 0 ? {} : { batchId: normalizeTaskBatchId(data.batchId) ?? null },
|
|
9766
|
+
...data.variant === void 0 ? {} : { variant: normalizeModelVariant(data.variant) ?? null }
|
|
9767
|
+
};
|
|
9737
9768
|
return db.transaction((tx) => {
|
|
9738
9769
|
const task = tx.select().from(tasks2).where(and(
|
|
9739
9770
|
eq(tasks2.id, id),
|
|
@@ -9745,6 +9776,7 @@ var init_task_service = __esm({
|
|
|
9745
9776
|
name: normalizedData.name ?? task.name,
|
|
9746
9777
|
agent: normalizedData.agent ?? task.agent,
|
|
9747
9778
|
model: normalizedData.model ?? task.model,
|
|
9779
|
+
variant: normalizedData.variant === void 0 ? task.variant : normalizedData.variant,
|
|
9748
9780
|
prompt: normalizedData.prompt ?? task.prompt,
|
|
9749
9781
|
cwd: task.cwd,
|
|
9750
9782
|
category: normalizedData.category ?? task.category,
|
|
@@ -9758,13 +9790,23 @@ var init_task_service = __esm({
|
|
|
9758
9790
|
});
|
|
9759
9791
|
const maxRetries = normalizedData.maxRetries ?? task.maxRetries ?? 3;
|
|
9760
9792
|
const exhausted = task.status === "failed" && (task.retryCount ?? 0) > maxRetries;
|
|
9761
|
-
|
|
9793
|
+
const updated = tx.update(tasks2).set({
|
|
9762
9794
|
...normalizedData,
|
|
9763
9795
|
...exhausted ? {
|
|
9764
9796
|
status: "dead_letter",
|
|
9765
9797
|
retryAfter: null
|
|
9766
9798
|
} : {}
|
|
9767
9799
|
}).where(eq(tasks2.id, id)).returning().get() ?? null;
|
|
9800
|
+
if (exhausted && updated) {
|
|
9801
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
9802
|
+
tx.update(tasks2).set({
|
|
9803
|
+
status: "dead_letter",
|
|
9804
|
+
finishedAt,
|
|
9805
|
+
retryAfter: null,
|
|
9806
|
+
resultLog: `\u4F9D\u8D56\u4EFB\u52A1 #${id} \u5DF2\u8FDB\u5165\u4E0D\u53EF\u6062\u590D\u7EC8\u6001`
|
|
9807
|
+
}).where(blockedDependentsOf(id)).run();
|
|
9808
|
+
}
|
|
9809
|
+
return updated;
|
|
9768
9810
|
}, { behavior: "immediate" });
|
|
9769
9811
|
}
|
|
9770
9812
|
static validateNewTask(data) {
|
|
@@ -9785,7 +9827,7 @@ var init_task_service = __esm({
|
|
|
9785
9827
|
throw new Error(`${name} \u5FC5\u987B\u662F ${min} \u5230 ${max} \u4E4B\u95F4\u7684\u6574\u6570`);
|
|
9786
9828
|
}
|
|
9787
9829
|
}
|
|
9788
|
-
static
|
|
9830
|
+
static buildRunnableTaskWhere(scope) {
|
|
9789
9831
|
const baseConditions = [...this.buildScopeWhere(scope)];
|
|
9790
9832
|
const nowMs = Date.now();
|
|
9791
9833
|
const retryAfterFilter = or(
|
|
@@ -9820,40 +9862,43 @@ var init_task_service = __esm({
|
|
|
9820
9862
|
if (batchFilter) {
|
|
9821
9863
|
conditions.push(batchFilter);
|
|
9822
9864
|
}
|
|
9823
|
-
|
|
9865
|
+
return and(
|
|
9824
9866
|
...conditions,
|
|
9825
9867
|
or(
|
|
9826
9868
|
isNull(tasks2.dependsOn),
|
|
9827
9869
|
sql`EXISTS (
|
|
9828
|
-
|
|
9829
|
-
|
|
9830
|
-
|
|
9831
|
-
|
|
9832
|
-
|
|
9870
|
+
SELECT 1 FROM tasks AS dependency_task
|
|
9871
|
+
WHERE dependency_task.id = ${tasks2.dependsOn}
|
|
9872
|
+
AND dependency_task.status = 'done'
|
|
9873
|
+
AND dependency_task.cwd IS ${tasks2.cwd}
|
|
9874
|
+
)`
|
|
9833
9875
|
),
|
|
9834
9876
|
or(
|
|
9835
9877
|
isNull(tasks2.batchId),
|
|
9836
9878
|
sql`trim(${tasks2.batchId}, ${TASK_BATCH_TRIM_CHARACTERS}) = ''`,
|
|
9837
9879
|
sql`NOT EXISTS (
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
|
|
9846
|
-
|
|
9847
|
-
)
|
|
9880
|
+
SELECT 1 FROM tasks AS running_batch_task
|
|
9881
|
+
WHERE trim(running_batch_task.batch_id, ${TASK_BATCH_TRIM_CHARACTERS})
|
|
9882
|
+
= trim(${tasks2.batchId}, ${TASK_BATCH_TRIM_CHARACTERS})
|
|
9883
|
+
AND (
|
|
9884
|
+
running_batch_task.status = 'running'
|
|
9885
|
+
OR EXISTS (
|
|
9886
|
+
SELECT 1 FROM task_runs AS running_batch_run
|
|
9887
|
+
WHERE running_batch_run.task_id = running_batch_task.id
|
|
9888
|
+
AND running_batch_run.status = 'running'
|
|
9848
9889
|
)
|
|
9849
|
-
|
|
9890
|
+
)
|
|
9891
|
+
)`
|
|
9850
9892
|
),
|
|
9851
9893
|
sql`NOT EXISTS (
|
|
9852
|
-
|
|
9853
|
-
|
|
9854
|
-
|
|
9855
|
-
|
|
9856
|
-
)
|
|
9894
|
+
SELECT 1 FROM task_runs AS candidate_active_run
|
|
9895
|
+
WHERE candidate_active_run.task_id = ${tasks2.id}
|
|
9896
|
+
AND candidate_active_run.status = 'running'
|
|
9897
|
+
)`
|
|
9898
|
+
);
|
|
9899
|
+
}
|
|
9900
|
+
static async next(scope = {}) {
|
|
9901
|
+
const result = await db.select().from(tasks2).where(this.buildRunnableTaskWhere(scope)).orderBy(
|
|
9857
9902
|
desc(tasks2.urgency),
|
|
9858
9903
|
desc(tasks2.importance),
|
|
9859
9904
|
asc(tasks2.createdAt),
|
|
@@ -9861,6 +9906,22 @@ var init_task_service = __esm({
|
|
|
9861
9906
|
).limit(1);
|
|
9862
9907
|
return result[0] ?? null;
|
|
9863
9908
|
}
|
|
9909
|
+
static async claimNext(scope = {}) {
|
|
9910
|
+
return db.transaction((tx) => {
|
|
9911
|
+
const candidate = tx.select().from(tasks2).where(this.buildRunnableTaskWhere(scope)).orderBy(
|
|
9912
|
+
desc(tasks2.urgency),
|
|
9913
|
+
desc(tasks2.importance),
|
|
9914
|
+
asc(tasks2.createdAt),
|
|
9915
|
+
asc(tasks2.id)
|
|
9916
|
+
).limit(1).get();
|
|
9917
|
+
if (!candidate) return null;
|
|
9918
|
+
return tx.update(tasks2).set({
|
|
9919
|
+
status: "running",
|
|
9920
|
+
startedAt: /* @__PURE__ */ new Date(),
|
|
9921
|
+
finishedAt: null
|
|
9922
|
+
}).where(eq(tasks2.id, candidate.id)).returning().get() ?? null;
|
|
9923
|
+
}, { behavior: "immediate" });
|
|
9924
|
+
}
|
|
9864
9925
|
static async countRunning(scope = {}) {
|
|
9865
9926
|
const scopeConditions = scope.legacyCwd ? [sql`${tasks2.cwd} IS NULL OR trim(${tasks2.cwd}) = ''`] : this.buildScopeWhere(scope);
|
|
9866
9927
|
if (scope.batchId !== void 0) {
|
|
@@ -10521,9 +10582,34 @@ var init_launch_protocol = __esm({
|
|
|
10521
10582
|
});
|
|
10522
10583
|
|
|
10523
10584
|
// src/core/process-control.ts
|
|
10524
|
-
import { spawnSync } from "child_process";
|
|
10525
10585
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
10526
10586
|
import { basename, dirname as dirname2, resolve } from "path";
|
|
10587
|
+
function runBoundedOsCommand(command, args, captureOutput = true) {
|
|
10588
|
+
const result = Bun.spawnSync({
|
|
10589
|
+
cmd: [
|
|
10590
|
+
process.execPath,
|
|
10591
|
+
"-e",
|
|
10592
|
+
BOUNDED_OS_COMMAND_RUNNER,
|
|
10593
|
+
"supertask-os-command",
|
|
10594
|
+
command,
|
|
10595
|
+
...args
|
|
10596
|
+
],
|
|
10597
|
+
detached: process.platform !== "win32",
|
|
10598
|
+
maxBuffer: OS_COMMAND_MAX_OUTPUT_BYTES + 1024,
|
|
10599
|
+
stdin: "ignore",
|
|
10600
|
+
stdout: "pipe",
|
|
10601
|
+
stderr: "ignore"
|
|
10602
|
+
});
|
|
10603
|
+
const output = new TextDecoder().decode(result.stdout);
|
|
10604
|
+
const markerIndex = output.lastIndexOf(OS_COMMAND_RESULT_MARKER);
|
|
10605
|
+
if (markerIndex < 0) return { status: null, stdout: "" };
|
|
10606
|
+
const statusText2 = output.slice(markerIndex + OS_COMMAND_RESULT_MARKER.length);
|
|
10607
|
+
if (!/^\d+$/.test(statusText2)) return { status: null, stdout: "" };
|
|
10608
|
+
return {
|
|
10609
|
+
status: Number(statusText2),
|
|
10610
|
+
stdout: captureOutput ? output.slice(0, markerIndex) : ""
|
|
10611
|
+
};
|
|
10612
|
+
}
|
|
10527
10613
|
function isSafePid(pid) {
|
|
10528
10614
|
return Number.isInteger(pid) && pid > 1 && pid !== process.pid;
|
|
10529
10615
|
}
|
|
@@ -10560,12 +10646,10 @@ function inspectSpawnedProcessTreePresence(pid) {
|
|
|
10560
10646
|
}
|
|
10561
10647
|
}
|
|
10562
10648
|
function inspectUnixProcess(pid) {
|
|
10563
|
-
const result =
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10567
|
-
killSignal: "SIGKILL"
|
|
10568
|
-
});
|
|
10649
|
+
const result = runBoundedOsCommand(
|
|
10650
|
+
"ps",
|
|
10651
|
+
["-o", "pgid=", "-o", "command=", "-p", String(pid)]
|
|
10652
|
+
);
|
|
10569
10653
|
if (result.status !== 0) return null;
|
|
10570
10654
|
const match2 = result.stdout.trim().match(/^(\d+)\s+(.+)$/s);
|
|
10571
10655
|
if (!match2) return null;
|
|
@@ -10573,30 +10657,18 @@ function inspectUnixProcess(pid) {
|
|
|
10573
10657
|
}
|
|
10574
10658
|
function inspectWindowsCommand(pid) {
|
|
10575
10659
|
const script = `(Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}").CommandLine`;
|
|
10576
|
-
const result =
|
|
10660
|
+
const result = runBoundedOsCommand(
|
|
10577
10661
|
"powershell.exe",
|
|
10578
|
-
["-NoProfile", "-NonInteractive", "-Command", script]
|
|
10579
|
-
{
|
|
10580
|
-
encoding: "utf8",
|
|
10581
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
10582
|
-
timeout: OS_COMMAND_TIMEOUT_MS,
|
|
10583
|
-
killSignal: "SIGKILL"
|
|
10584
|
-
}
|
|
10662
|
+
["-NoProfile", "-NonInteractive", "-Command", script]
|
|
10585
10663
|
);
|
|
10586
10664
|
if (result.status !== 0) return null;
|
|
10587
10665
|
return result.stdout.trim() || null;
|
|
10588
10666
|
}
|
|
10589
10667
|
function inspectWindowsProcessTree(rootPid) {
|
|
10590
10668
|
const script = `$root=${rootPid}; $all=@(Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId); $ids=New-Object 'System.Collections.Generic.HashSet[int]'; [void]$ids.Add($root); do { $added=$false; foreach($p in $all) { if($ids.Contains([int]$p.ParentProcessId) -and $ids.Add([int]$p.ProcessId)) { $added=$true } } } while($added); $all | Where-Object { $ids.Contains([int]$_.ProcessId) } | Select-Object -ExpandProperty ProcessId`;
|
|
10591
|
-
const result =
|
|
10669
|
+
const result = runBoundedOsCommand(
|
|
10592
10670
|
"powershell.exe",
|
|
10593
|
-
["-NoProfile", "-NonInteractive", "-Command", script]
|
|
10594
|
-
{
|
|
10595
|
-
encoding: "utf8",
|
|
10596
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
10597
|
-
timeout: OS_COMMAND_TIMEOUT_MS,
|
|
10598
|
-
killSignal: "SIGKILL"
|
|
10599
|
-
}
|
|
10671
|
+
["-NoProfile", "-NonInteractive", "-Command", script]
|
|
10600
10672
|
);
|
|
10601
10673
|
if (result.status !== 0) return null;
|
|
10602
10674
|
return result.stdout.split(/\s+/).filter(Boolean).map(Number).filter((pid) => Number.isInteger(pid) && pid > 0);
|
|
@@ -10667,11 +10739,7 @@ function signalRecordedProcessTreeWithResult(pid, signal, expectedExecutable, la
|
|
|
10667
10739
|
}
|
|
10668
10740
|
const args = ["/PID", String(pid), "/T"];
|
|
10669
10741
|
if (signal === "SIGKILL") args.push("/F");
|
|
10670
|
-
const status =
|
|
10671
|
-
stdio: "ignore",
|
|
10672
|
-
timeout: OS_COMMAND_TIMEOUT_MS,
|
|
10673
|
-
killSignal: "SIGKILL"
|
|
10674
|
-
}).status;
|
|
10742
|
+
const status = runBoundedOsCommand("taskkill", args, false).status;
|
|
10675
10743
|
if (status === 0) return "signalled";
|
|
10676
10744
|
return isProcessAlive(pid) ? "signal-failed" : absentLeaderResult(pid);
|
|
10677
10745
|
}
|
|
@@ -10700,12 +10768,64 @@ async function waitForSpawnedProcessTreeExit(pid, timeoutMs = 5e3) {
|
|
|
10700
10768
|
}
|
|
10701
10769
|
return inspectSpawnedProcessTreePresence(pid) === "not-running";
|
|
10702
10770
|
}
|
|
10703
|
-
var OS_COMMAND_TIMEOUT_MS;
|
|
10771
|
+
var OS_COMMAND_TIMEOUT_MS, OS_COMMAND_MAX_OUTPUT_BYTES, OS_COMMAND_RESULT_MARKER, BOUNDED_OS_COMMAND_RUNNER;
|
|
10704
10772
|
var init_process_control = __esm({
|
|
10705
10773
|
"src/core/process-control.ts"() {
|
|
10706
10774
|
"use strict";
|
|
10707
10775
|
init_launch_protocol();
|
|
10708
10776
|
OS_COMMAND_TIMEOUT_MS = 2e3;
|
|
10777
|
+
OS_COMMAND_MAX_OUTPUT_BYTES = 4 * 1024 * 1024;
|
|
10778
|
+
OS_COMMAND_RESULT_MARKER = "\n\0supertask-os-command-result:";
|
|
10779
|
+
BOUNDED_OS_COMMAND_RUNNER = `
|
|
10780
|
+
const { writeSync } = await import('fs');
|
|
10781
|
+
let child;
|
|
10782
|
+
try {
|
|
10783
|
+
child = Bun.spawn(process.argv.slice(2), {
|
|
10784
|
+
stdin: 'ignore',
|
|
10785
|
+
stdout: 'pipe',
|
|
10786
|
+
stderr: 'ignore',
|
|
10787
|
+
});
|
|
10788
|
+
} catch {
|
|
10789
|
+
process.exit(127);
|
|
10790
|
+
}
|
|
10791
|
+
const terminateGroup = () => {
|
|
10792
|
+
if (process.platform !== 'win32') {
|
|
10793
|
+
try {
|
|
10794
|
+
process.kill(-process.pid, 'SIGKILL');
|
|
10795
|
+
} catch {
|
|
10796
|
+
}
|
|
10797
|
+
}
|
|
10798
|
+
try {
|
|
10799
|
+
child.kill('SIGKILL');
|
|
10800
|
+
} catch {
|
|
10801
|
+
}
|
|
10802
|
+
process.exit(1);
|
|
10803
|
+
};
|
|
10804
|
+
const timer = setTimeout(terminateGroup, ${OS_COMMAND_TIMEOUT_MS});
|
|
10805
|
+
try {
|
|
10806
|
+
const chunks = [];
|
|
10807
|
+
let outputBytes = 0;
|
|
10808
|
+
const readOutput = async () => {
|
|
10809
|
+
const reader = child.stdout.getReader();
|
|
10810
|
+
while (true) {
|
|
10811
|
+
const { done, value } = await reader.read();
|
|
10812
|
+
if (done) return;
|
|
10813
|
+
outputBytes += value.byteLength;
|
|
10814
|
+
if (outputBytes > ${OS_COMMAND_MAX_OUTPUT_BYTES}) terminateGroup();
|
|
10815
|
+
chunks.push(value);
|
|
10816
|
+
}
|
|
10817
|
+
};
|
|
10818
|
+
const [exitCode] = await Promise.all([child.exited, readOutput()]);
|
|
10819
|
+
clearTimeout(timer);
|
|
10820
|
+
for (const chunk of chunks) writeSync(1, chunk);
|
|
10821
|
+
writeSync(1, ${JSON.stringify(OS_COMMAND_RESULT_MARKER)} + String(exitCode));
|
|
10822
|
+
if (process.platform !== 'win32') terminateGroup();
|
|
10823
|
+
process.exit(0);
|
|
10824
|
+
} catch {
|
|
10825
|
+
clearTimeout(timer);
|
|
10826
|
+
terminateGroup();
|
|
10827
|
+
}
|
|
10828
|
+
`;
|
|
10709
10829
|
}
|
|
10710
10830
|
});
|
|
10711
10831
|
|
|
@@ -10857,7 +10977,7 @@ var init_task_run_service = __esm({
|
|
|
10857
10977
|
}
|
|
10858
10978
|
if (current.childPid != null) {
|
|
10859
10979
|
throw new LegacyRunAbandonConflictError(
|
|
10860
|
-
`run #${runId} \u5DF2\u8BB0\u5F55 child PID ${current.childPid}\uFF0C\u5FC5\u987B\u7531 Worker/Watchdog \u786E\u8BA4\u8FDB\u7A0B\
|
|
10980
|
+
`run #${runId} \u5DF2\u8BB0\u5F55 child PID ${current.childPid}\uFF0C\u5FC5\u987B\u7531 Worker/Watchdog \u786E\u8BA4\u53D7\u7BA1\u8FDB\u7A0B\u7EC4\u6392\u7A7A`
|
|
10861
10981
|
);
|
|
10862
10982
|
}
|
|
10863
10983
|
if (current.workerPid != null && isProcessAlive(current.workerPid)) {
|
|
@@ -20106,12 +20226,14 @@ var init_task_template_service = __esm({
|
|
|
20106
20226
|
init_cron_parser();
|
|
20107
20227
|
init_task_working_directory();
|
|
20108
20228
|
init_task_batch();
|
|
20229
|
+
init_model_variant();
|
|
20109
20230
|
({ taskTemplates: taskTemplates2 } = schema_exports);
|
|
20110
20231
|
TaskTemplateService = class {
|
|
20111
20232
|
static async create(data) {
|
|
20112
20233
|
const normalizedData = {
|
|
20113
20234
|
...data,
|
|
20114
|
-
batchId: normalizeTaskBatchId(data.batchId)
|
|
20235
|
+
batchId: normalizeTaskBatchId(data.batchId),
|
|
20236
|
+
variant: normalizeModelVariant(data.variant)
|
|
20115
20237
|
};
|
|
20116
20238
|
this.validate(normalizedData);
|
|
20117
20239
|
const now = Date.now();
|
|
@@ -20177,7 +20299,8 @@ var init_task_template_service = __esm({
|
|
|
20177
20299
|
static async update(id, data) {
|
|
20178
20300
|
const normalizedData = {
|
|
20179
20301
|
...data,
|
|
20180
|
-
batchId: normalizeTaskBatchId(data.batchId) ?? null
|
|
20302
|
+
batchId: normalizeTaskBatchId(data.batchId) ?? null,
|
|
20303
|
+
...data.variant === void 0 ? {} : { variant: normalizeModelVariant(data.variant) ?? null }
|
|
20181
20304
|
};
|
|
20182
20305
|
this.validate(normalizedData);
|
|
20183
20306
|
const now = Date.now();
|
|
@@ -20975,7 +21098,7 @@ __export(pm2_exports, {
|
|
|
20975
21098
|
upgrade: () => upgrade,
|
|
20976
21099
|
withGatewayMaintenance: () => withGatewayMaintenance
|
|
20977
21100
|
});
|
|
20978
|
-
import { execSync, spawnSync
|
|
21101
|
+
import { execSync, spawnSync } from "child_process";
|
|
20979
21102
|
import {
|
|
20980
21103
|
accessSync,
|
|
20981
21104
|
chmodSync as chmodSync2,
|
|
@@ -21080,7 +21203,7 @@ function diagnoseOpenCodeRuntime(runtime = {
|
|
|
21080
21203
|
env: process.env
|
|
21081
21204
|
}) {
|
|
21082
21205
|
const executable = runtimeScope(runtime).opencodePath;
|
|
21083
|
-
const result =
|
|
21206
|
+
const result = spawnSync(executable, ["--version"], {
|
|
21084
21207
|
cwd: runtime.cwd,
|
|
21085
21208
|
env: runtime.env,
|
|
21086
21209
|
encoding: "utf8",
|
|
@@ -21170,7 +21293,7 @@ function xmlEscape(value) {
|
|
|
21170
21293
|
function resolvePm2Bin() {
|
|
21171
21294
|
const configured = pm2Bin();
|
|
21172
21295
|
if (isAbsolute2(configured)) return configured;
|
|
21173
|
-
const result =
|
|
21296
|
+
const result = spawnSync("which", [configured], { encoding: "utf8" });
|
|
21174
21297
|
const resolved = result.status === 0 ? result.stdout.trim().split("\n")[0] : "";
|
|
21175
21298
|
if (!resolved) throw new Error(`[supertask] \u65E0\u6CD5\u89E3\u6790 pm2 \u53EF\u6267\u884C\u6587\u4EF6: ${configured}`);
|
|
21176
21299
|
return resolved;
|
|
@@ -21227,18 +21350,18 @@ function isMacLaunchAgentConfigured(expectedPm2Home, expectedRuntime) {
|
|
|
21227
21350
|
accessSync(bunPath, constants.X_OK);
|
|
21228
21351
|
accessSync(supervisorEntry, constants.R_OK);
|
|
21229
21352
|
accessSync(pm2Path, constants.X_OK);
|
|
21230
|
-
if (
|
|
21353
|
+
if (spawnSync(bunPath, ["--version"], {
|
|
21231
21354
|
stdio: "ignore",
|
|
21232
21355
|
timeout: pm2CommandTimeoutMs(),
|
|
21233
21356
|
killSignal: "SIGKILL"
|
|
21234
21357
|
}).status !== 0) return false;
|
|
21235
|
-
if (
|
|
21358
|
+
if (spawnSync(pm2Path, ["--version"], {
|
|
21236
21359
|
stdio: "ignore",
|
|
21237
21360
|
env: { ...process.env, PM2_HOME: pm2Home },
|
|
21238
21361
|
timeout: pm2CommandTimeoutMs(),
|
|
21239
21362
|
killSignal: "SIGKILL"
|
|
21240
21363
|
}).status !== 0) return false;
|
|
21241
|
-
const loaded =
|
|
21364
|
+
const loaded = spawnSync(
|
|
21242
21365
|
launchctlBin(),
|
|
21243
21366
|
["print", `gui/${process.getuid()}/${MAC_LAUNCH_AGENT_LABEL}`],
|
|
21244
21367
|
{
|
|
@@ -21266,7 +21389,7 @@ function isMacLaunchAgentConfigured(expectedPm2Home, expectedRuntime) {
|
|
|
21266
21389
|
function bootstrapMacLaunchAgent(domain, path) {
|
|
21267
21390
|
const retryDeadline = Date.now() + 2e3;
|
|
21268
21391
|
const sleeper = new Int32Array(new SharedArrayBuffer(4));
|
|
21269
|
-
let result =
|
|
21392
|
+
let result = spawnSync(launchctlBin(), ["bootstrap", domain, path], {
|
|
21270
21393
|
encoding: "utf8",
|
|
21271
21394
|
timeout: pm2CommandTimeoutMs(),
|
|
21272
21395
|
killSignal: "SIGKILL"
|
|
@@ -21275,7 +21398,7 @@ function bootstrapMacLaunchAgent(domain, path) {
|
|
|
21275
21398
|
const output = `${result.stdout ?? ""}${result.stderr ?? ""}`;
|
|
21276
21399
|
if (result.status !== 5 && !output.includes("Bootstrap failed: 5:")) break;
|
|
21277
21400
|
Atomics.wait(sleeper, 0, 0, 100);
|
|
21278
|
-
result =
|
|
21401
|
+
result = spawnSync(launchctlBin(), ["bootstrap", domain, path], {
|
|
21279
21402
|
encoding: "utf8",
|
|
21280
21403
|
timeout: pm2CommandTimeoutMs(),
|
|
21281
21404
|
killSignal: "SIGKILL"
|
|
@@ -21333,7 +21456,7 @@ function installMacLaunchAgent(expectedRuntime = currentGatewayRuntime()) {
|
|
|
21333
21456
|
`;
|
|
21334
21457
|
const domain = `gui/${process.getuid()}`;
|
|
21335
21458
|
const previousPlist = existsSync5(path) ? readFileSync3(path) : null;
|
|
21336
|
-
const wasLoaded = previousPlist != null &&
|
|
21459
|
+
const wasLoaded = previousPlist != null && spawnSync(
|
|
21337
21460
|
launchctlBin(),
|
|
21338
21461
|
["print", `${domain}/${MAC_LAUNCH_AGENT_LABEL}`],
|
|
21339
21462
|
{
|
|
@@ -21345,7 +21468,7 @@ function installMacLaunchAgent(expectedRuntime = currentGatewayRuntime()) {
|
|
|
21345
21468
|
mkdirSync4(dirname6(path), { recursive: true });
|
|
21346
21469
|
writeFileSync2(path, plist, { mode: 384 });
|
|
21347
21470
|
chmodSync2(path, 384);
|
|
21348
|
-
|
|
21471
|
+
spawnSync(launchctlBin(), ["bootout", `${domain}/${MAC_LAUNCH_AGENT_LABEL}`], {
|
|
21349
21472
|
stdio: "ignore",
|
|
21350
21473
|
timeout: pm2CommandTimeoutMs(),
|
|
21351
21474
|
killSignal: "SIGKILL"
|
|
@@ -21363,7 +21486,7 @@ function installMacLaunchAgent(expectedRuntime = currentGatewayRuntime()) {
|
|
|
21363
21486
|
if (loaded.status !== 0 || !verified) {
|
|
21364
21487
|
const output = loaded.status === 0 ? "supervisor \u672A\u4FDD\u6301 running \u6216 PM2 dump \u4E0D\u53EF\u6062\u590D" : `${loaded.stdout ?? ""}${loaded.stderr ?? ""}`.trim();
|
|
21365
21488
|
if (loaded.status === 0) {
|
|
21366
|
-
|
|
21489
|
+
spawnSync(launchctlBin(), ["bootout", `${domain}/${MAC_LAUNCH_AGENT_LABEL}`], {
|
|
21367
21490
|
stdio: "ignore",
|
|
21368
21491
|
timeout: pm2CommandTimeoutMs(),
|
|
21369
21492
|
killSignal: "SIGKILL"
|
|
@@ -21390,7 +21513,7 @@ function systemctlBin(env = process.env) {
|
|
|
21390
21513
|
}
|
|
21391
21514
|
function isLinuxStartupConfigured(env = process.env, cwd = process.cwd(), expectedRuntime) {
|
|
21392
21515
|
const unit = env.SUPERTASK_PM2_SYSTEMD_UNIT ?? `pm2-${userInfo().username}.service`;
|
|
21393
|
-
const enabled =
|
|
21516
|
+
const enabled = spawnSync(systemctlBin(env), ["is-enabled", unit], {
|
|
21394
21517
|
encoding: "utf8",
|
|
21395
21518
|
env,
|
|
21396
21519
|
stdio: ["ignore", "pipe", "ignore"],
|
|
@@ -21398,7 +21521,7 @@ function isLinuxStartupConfigured(env = process.env, cwd = process.cwd(), expect
|
|
|
21398
21521
|
killSignal: "SIGKILL"
|
|
21399
21522
|
});
|
|
21400
21523
|
if (enabled.status !== 0 || enabled.stdout.trim() !== "enabled") return false;
|
|
21401
|
-
const contents =
|
|
21524
|
+
const contents = spawnSync(systemctlBin(env), ["cat", unit], {
|
|
21402
21525
|
encoding: "utf8",
|
|
21403
21526
|
env,
|
|
21404
21527
|
stdio: ["ignore", "pipe", "ignore"],
|
|
@@ -21422,7 +21545,7 @@ function isLinuxStartupConfigured(env = process.env, cwd = process.cwd(), expect
|
|
|
21422
21545
|
}
|
|
21423
21546
|
}
|
|
21424
21547
|
function isPm2Installed(env = process.env) {
|
|
21425
|
-
const result =
|
|
21548
|
+
const result = spawnSync(pm2Bin(env), ["--version"], {
|
|
21426
21549
|
stdio: "ignore",
|
|
21427
21550
|
env,
|
|
21428
21551
|
shell: process.platform === "win32",
|
|
@@ -21447,7 +21570,7 @@ function installPm2() {
|
|
|
21447
21570
|
}
|
|
21448
21571
|
function resolveCommand(command) {
|
|
21449
21572
|
const lookup = process.platform === "win32" ? "where" : "which";
|
|
21450
|
-
const result =
|
|
21573
|
+
const result = spawnSync(lookup, [command], { encoding: "utf8" });
|
|
21451
21574
|
return result.status === 0 ? result.stdout.trim().split("\n")[0] || null : null;
|
|
21452
21575
|
}
|
|
21453
21576
|
function npmPreferredEnvironment() {
|
|
@@ -21469,7 +21592,7 @@ function npmPreferredEnvironment() {
|
|
|
21469
21592
|
function pm2Exec(args, options = {}) {
|
|
21470
21593
|
const npmEnvironment = options.preferNpm ? npmPreferredEnvironment() : null;
|
|
21471
21594
|
const effectiveEnv = options.env ?? npmEnvironment?.env ?? process.env;
|
|
21472
|
-
const result =
|
|
21595
|
+
const result = spawnSync(npmEnvironment?.command ?? pm2Bin(effectiveEnv), args, {
|
|
21473
21596
|
stdio: ["pipe", "pipe", "pipe"],
|
|
21474
21597
|
encoding: "utf-8",
|
|
21475
21598
|
env: effectiveEnv,
|
|
@@ -21544,7 +21667,7 @@ function gatewayRuntimeFromProcess(processInfo) {
|
|
|
21544
21667
|
try {
|
|
21545
21668
|
accessSync(savedBunPath, constants.X_OK);
|
|
21546
21669
|
if (!statSync3(savedCwd).isDirectory()) return null;
|
|
21547
|
-
if (
|
|
21670
|
+
if (spawnSync(savedBunPath, ["--version"], {
|
|
21548
21671
|
stdio: "ignore",
|
|
21549
21672
|
env: savedEnv,
|
|
21550
21673
|
timeout: pm2CommandTimeoutMs(savedEnv),
|
|
@@ -22006,7 +22129,7 @@ function removeMacLaunchAgent() {
|
|
|
22006
22129
|
if (typeof process.getuid !== "function") return;
|
|
22007
22130
|
const path = launchAgentPath();
|
|
22008
22131
|
const domain = `gui/${process.getuid()}`;
|
|
22009
|
-
const loaded =
|
|
22132
|
+
const loaded = spawnSync(
|
|
22010
22133
|
launchctlBin(),
|
|
22011
22134
|
["print", `${domain}/${MAC_LAUNCH_AGENT_LABEL}`],
|
|
22012
22135
|
{
|
|
@@ -22019,7 +22142,7 @@ function removeMacLaunchAgent() {
|
|
|
22019
22142
|
throw new Error(`[supertask] \u65E0\u6CD5\u786E\u8BA4 macOS LaunchAgent \u72B6\u6001: ${loaded.error.message}`);
|
|
22020
22143
|
}
|
|
22021
22144
|
if (loaded.status === 0) {
|
|
22022
|
-
const removed =
|
|
22145
|
+
const removed = spawnSync(
|
|
22023
22146
|
launchctlBin(),
|
|
22024
22147
|
["bootout", `${domain}/${MAC_LAUNCH_AGENT_LABEL}`],
|
|
22025
22148
|
{
|
|
@@ -22230,7 +22353,7 @@ __export(update_exports, {
|
|
|
22230
22353
|
resolveInstalledPluginVersion: () => resolveInstalledPluginVersion,
|
|
22231
22354
|
updateGlobalCli: () => updateGlobalCli
|
|
22232
22355
|
});
|
|
22233
|
-
import { spawnSync as
|
|
22356
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
22234
22357
|
import {
|
|
22235
22358
|
chmodSync as chmodSync3,
|
|
22236
22359
|
closeSync,
|
|
@@ -22295,7 +22418,7 @@ function bunBin() {
|
|
|
22295
22418
|
function resolveGlobalCliExecutable() {
|
|
22296
22419
|
const override = process.env.SUPERTASK_CLI_BIN;
|
|
22297
22420
|
if (override) return existsSync6(override) ? resolve4(override) : null;
|
|
22298
|
-
const result =
|
|
22421
|
+
const result = spawnSync2(process.platform === "win32" ? "where" : "which", ["supertask"], {
|
|
22299
22422
|
encoding: "utf8",
|
|
22300
22423
|
env: process.env,
|
|
22301
22424
|
timeout: 1e4
|
|
@@ -22330,7 +22453,7 @@ function packageVersion(packageDir) {
|
|
|
22330
22453
|
}
|
|
22331
22454
|
}
|
|
22332
22455
|
function npmGlobalRoot() {
|
|
22333
|
-
const result =
|
|
22456
|
+
const result = spawnSync2(npmBin(), ["root", "-g"], {
|
|
22334
22457
|
encoding: "utf8",
|
|
22335
22458
|
env: process.env,
|
|
22336
22459
|
timeout: 3e4
|
|
@@ -22394,7 +22517,7 @@ function updateGlobalCli(version2) {
|
|
|
22394
22517
|
}
|
|
22395
22518
|
const command = before.packageManager === "npm" ? npmBin() : bunBin();
|
|
22396
22519
|
const args = before.packageManager === "npm" ? ["install", "-g", `${PACKAGE_NAME}@${version2}`] : ["add", "-g", `${PACKAGE_NAME}@${version2}`];
|
|
22397
|
-
const result =
|
|
22520
|
+
const result = spawnSync2(command, args, {
|
|
22398
22521
|
encoding: "utf8",
|
|
22399
22522
|
env: process.env,
|
|
22400
22523
|
timeout: 12e4
|
|
@@ -22415,7 +22538,7 @@ function updateGlobalCli(version2) {
|
|
|
22415
22538
|
return { ...after, action: "updated" };
|
|
22416
22539
|
}
|
|
22417
22540
|
function getLatestVersion() {
|
|
22418
|
-
const result =
|
|
22541
|
+
const result = spawnSync2(npmBin(), [
|
|
22419
22542
|
"view",
|
|
22420
22543
|
PACKAGE_NAME,
|
|
22421
22544
|
"dist-tags.latest",
|
|
@@ -22498,7 +22621,7 @@ function getOpenCodePluginDiagnostic() {
|
|
|
22498
22621
|
chmodSync3(outputDirectory, 448);
|
|
22499
22622
|
const outputPath = join5(outputDirectory, "resolved-config.json");
|
|
22500
22623
|
outputFd = openSync(outputPath, "w", 384);
|
|
22501
|
-
const result =
|
|
22624
|
+
const result = spawnSync2(opencodeBin(), ["debug", "config", "--pure"], {
|
|
22502
22625
|
encoding: "utf8",
|
|
22503
22626
|
env: process.env,
|
|
22504
22627
|
timeout: 3e4,
|
|
@@ -22568,7 +22691,7 @@ function installPluginVersion(version2) {
|
|
|
22568
22691
|
if (!isSemanticVersion(version2)) {
|
|
22569
22692
|
throw new Error(`[supertask] OpenCode \u63D2\u4EF6\u7248\u672C\u65E0\u6548: ${version2}`);
|
|
22570
22693
|
}
|
|
22571
|
-
const result =
|
|
22694
|
+
const result = spawnSync2(opencodeBin(), [
|
|
22572
22695
|
"plugin",
|
|
22573
22696
|
`${PACKAGE_NAME}@${version2}`,
|
|
22574
22697
|
"--global",
|
|
@@ -22747,7 +22870,7 @@ function runCommandContext(executable, args, cwd) {
|
|
|
22747
22870
|
function assertWorkerProcessIsolationSupported(platform = process.platform) {
|
|
22748
22871
|
if (platform === "win32") {
|
|
22749
22872
|
throw new Error(
|
|
22750
|
-
"Windows Worker \u5DF2\u5B89\u5168\u7981\u7528\uFF1A\u5F53\u524D\u8FD0\u884C\u65F6\u65E0\u6CD5\u7528 Job Object \
|
|
22873
|
+
"Windows Worker \u5DF2\u5B89\u5168\u7981\u7528\uFF1A\u5F53\u524D\u8FD0\u884C\u65F6\u65E0\u6CD5\u7528 Job Object \u63D0\u4F9B\u7B49\u4EF7\u7684\u53D7\u7BA1\u8FDB\u7A0B\u9694\u79BB\u4E0E\u6392\u7A7A\u8BC1\u660E"
|
|
22751
22874
|
);
|
|
22752
22875
|
}
|
|
22753
22876
|
}
|
|
@@ -22771,17 +22894,24 @@ var init_worker = __esm({
|
|
|
22771
22894
|
pollTimer = null;
|
|
22772
22895
|
heartbeatTimer = null;
|
|
22773
22896
|
pollCyclePromise = null;
|
|
22897
|
+
shutdownDeadlineMs = null;
|
|
22898
|
+
settlementRetryWakeups = /* @__PURE__ */ new Set();
|
|
22774
22899
|
cfg;
|
|
22775
22900
|
opencodeBin;
|
|
22776
22901
|
maxOutputChars;
|
|
22902
|
+
settlementRetryDelaysMs;
|
|
22903
|
+
settlementRetryIntervalMs;
|
|
22777
22904
|
constructor(cfg, options = {}) {
|
|
22778
22905
|
this.cfg = cfg.worker;
|
|
22779
22906
|
this.opencodeBin = options.opencodeBin ?? process.env.SUPERTASK_OPENCODE_BIN ?? "opencode";
|
|
22780
22907
|
this.maxOutputChars = options.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;
|
|
22908
|
+
this.settlementRetryDelaysMs = options.settlementRetryDelaysMs ?? [250, 1e3, 4e3];
|
|
22909
|
+
this.settlementRetryIntervalMs = options.settlementRetryIntervalMs ?? 5e3;
|
|
22781
22910
|
}
|
|
22782
22911
|
start() {
|
|
22783
22912
|
assertWorkerProcessIsolationSupported();
|
|
22784
22913
|
this.stopped = false;
|
|
22914
|
+
this.shutdownDeadlineMs = null;
|
|
22785
22915
|
markGatewayActivity("worker");
|
|
22786
22916
|
this.poll();
|
|
22787
22917
|
this.heartbeatTimer = setInterval(() => {
|
|
@@ -22790,6 +22920,8 @@ var init_worker = __esm({
|
|
|
22790
22920
|
}
|
|
22791
22921
|
async stop(gracePeriodMs = 0) {
|
|
22792
22922
|
this.stopped = true;
|
|
22923
|
+
this.shutdownDeadlineMs = Date.now() + Math.max(0, gracePeriodMs);
|
|
22924
|
+
for (const wake of [...this.settlementRetryWakeups]) wake();
|
|
22793
22925
|
if (this.pollTimer) {
|
|
22794
22926
|
clearTimeout(this.pollTimer);
|
|
22795
22927
|
this.pollTimer = null;
|
|
@@ -22859,27 +22991,25 @@ var init_worker = __esm({
|
|
|
22859
22991
|
if (databaseRunningCount >= this.cfg.maxConcurrency) break;
|
|
22860
22992
|
let task;
|
|
22861
22993
|
try {
|
|
22862
|
-
task = await TaskService.
|
|
22994
|
+
task = await TaskService.claimNext({ excludedBatchIds: [...this.activeBatchIds] });
|
|
22863
22995
|
} catch (err) {
|
|
22864
22996
|
this.logError("task claim failed", err);
|
|
22865
22997
|
throw err;
|
|
22866
22998
|
}
|
|
22867
22999
|
if (!task) break;
|
|
22868
|
-
if (this.stopped) break;
|
|
22869
|
-
if (!await TaskService.start(task.id)) continue;
|
|
22870
|
-
const batchId = normalizeTaskBatchId(task.batchId);
|
|
22871
|
-
if (batchId) this.activeBatchIds.add(batchId);
|
|
22872
23000
|
if (this.stopped) {
|
|
22873
23001
|
await TaskService.resetRunningToPending([task.id]);
|
|
22874
|
-
this.releaseBatch(task);
|
|
22875
23002
|
break;
|
|
22876
23003
|
}
|
|
23004
|
+
const batchId = normalizeTaskBatchId(task.batchId);
|
|
23005
|
+
if (batchId) this.activeBatchIds.add(batchId);
|
|
22877
23006
|
let runId = null;
|
|
22878
23007
|
try {
|
|
22879
23008
|
const launchIdentity = `gateway-${process.pid}:launch:${randomUUID3()}`;
|
|
22880
23009
|
const run = await TaskRunService.create({
|
|
22881
23010
|
taskId: task.id,
|
|
22882
23011
|
model: this.resolveModel(task.model),
|
|
23012
|
+
variant: this.resolveVariant(task.variant),
|
|
22883
23013
|
status: "running",
|
|
22884
23014
|
workerPid: process.pid,
|
|
22885
23015
|
lockedAt: Date.now(),
|
|
@@ -22942,8 +23072,10 @@ var init_worker = __esm({
|
|
|
22942
23072
|
}
|
|
22943
23073
|
async spawnTask(task, runId, launchIdentity) {
|
|
22944
23074
|
const model = this.resolveModel(task.model);
|
|
23075
|
+
const variant = this.resolveVariant(task.variant);
|
|
22945
23076
|
const args = ["run", "--agent", task.agent, "--format", "json"];
|
|
22946
23077
|
if (model) args.push("-m", model);
|
|
23078
|
+
if (variant) args.push("--variant", variant);
|
|
22947
23079
|
args.push(task.prompt);
|
|
22948
23080
|
const cwd = task.cwd || process.cwd();
|
|
22949
23081
|
const child = spawn(process.execPath, [
|
|
@@ -23081,7 +23213,7 @@ var init_worker = __esm({
|
|
|
23081
23213
|
if (!entry.guardianDrained) {
|
|
23082
23214
|
const pid = entry.child.pid;
|
|
23083
23215
|
const presence = pid == null ? spawnError == null ? "unknown" : "not-running" : inspectSpawnedProcessTreePresence(pid);
|
|
23084
|
-
const message = "guardian \u672A\u63D0\u4F9B\u8FDB\u7A0B\
|
|
23216
|
+
const message = "guardian \u672A\u63D0\u4F9B\u53D7\u7BA1\u8FDB\u7A0B\u7EC4\u6392\u7A7A\u8BC1\u660E";
|
|
23085
23217
|
if (presence !== "not-running") {
|
|
23086
23218
|
if (entry.timeoutTimer) {
|
|
23087
23219
|
clearTimeout(entry.timeoutTimer);
|
|
@@ -23102,7 +23234,7 @@ var init_worker = __esm({
|
|
|
23102
23234
|
);
|
|
23103
23235
|
return;
|
|
23104
23236
|
}
|
|
23105
|
-
const failure = code === 0 ? void 0 : `${spawnError ? "\u65E0\u6CD5\u542F\u52A8 opencode" : "opencode \u9000\u51FA\u7801"} ${spawnError?.message ?? code ?? "null"}${signal ? `\uFF0C\u4FE1\u53F7 ${signal}` : ""}\uFF08agent=${entry.task.agent}\uFF0Cmodel=${this.resolveModel(entry.task.model) ?? "Agent/\u9ED8\u8BA4\u914D\u7F6E"}\uFF0Ccwd=${entry.task.cwd ?? process.cwd()}\uFF09`;
|
|
23237
|
+
const failure = code === 0 ? void 0 : `${spawnError ? "\u65E0\u6CD5\u542F\u52A8 opencode" : "opencode \u9000\u51FA\u7801"} ${spawnError?.message ?? code ?? "null"}${signal ? `\uFF0C\u4FE1\u53F7 ${signal}` : ""}\uFF08agent=${entry.task.agent}\uFF0Cmodel=${this.resolveModel(entry.task.model) ?? "Agent/\u9ED8\u8BA4\u914D\u7F6E"}\uFF0Cvariant=${this.resolveVariant(entry.task.variant) ?? "Agent/\u6A21\u578B\u9ED8\u8BA4\u914D\u7F6E"}\uFF0Ccwd=${entry.task.cwd ?? process.cwd()}\uFF09`;
|
|
23106
23238
|
this.runDetached(
|
|
23107
23239
|
this.settleEntry(entry, code, failure),
|
|
23108
23240
|
"task settlement failed",
|
|
@@ -23117,17 +23249,48 @@ var init_worker = __esm({
|
|
|
23117
23249
|
clearTimeout(entry.timeoutTimer);
|
|
23118
23250
|
entry.timeoutTimer = null;
|
|
23119
23251
|
}
|
|
23120
|
-
const settlement = this.
|
|
23121
|
-
markGatewayFailure("worker", error);
|
|
23122
|
-
this.logError("task settlement failed", error, entry.task.id);
|
|
23123
|
-
return false;
|
|
23124
|
-
}).finally(() => {
|
|
23252
|
+
const settlement = this.commitEntryWithRetry(entry, code, failure).finally(() => {
|
|
23125
23253
|
this.runningTasks.delete(entry.task.id);
|
|
23126
23254
|
this.releaseBatch(entry.task);
|
|
23127
23255
|
});
|
|
23128
23256
|
entry.settlementPromise = settlement;
|
|
23129
23257
|
return settlement;
|
|
23130
23258
|
}
|
|
23259
|
+
async commitEntryWithRetry(entry, code, failure) {
|
|
23260
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
23261
|
+
try {
|
|
23262
|
+
await this.commitEntry(entry, code, failure);
|
|
23263
|
+
return true;
|
|
23264
|
+
} catch (error) {
|
|
23265
|
+
markGatewayFailure("worker", error);
|
|
23266
|
+
const shortRetryDelayMs = this.settlementRetryDelaysMs[attempt];
|
|
23267
|
+
let retryDelayMs = shortRetryDelayMs ?? this.settlementRetryIntervalMs;
|
|
23268
|
+
if (this.stopped) {
|
|
23269
|
+
const remainingMs = Math.max(0, (this.shutdownDeadlineMs ?? 0) - Date.now());
|
|
23270
|
+
if (remainingMs === 0) return false;
|
|
23271
|
+
retryDelayMs = Math.min(retryDelayMs, remainingMs);
|
|
23272
|
+
}
|
|
23273
|
+
this.logError(
|
|
23274
|
+
`task settlement failed; retrying in ${retryDelayMs}ms`,
|
|
23275
|
+
error,
|
|
23276
|
+
entry.task.id
|
|
23277
|
+
);
|
|
23278
|
+
await this.waitForSettlementRetry(retryDelayMs);
|
|
23279
|
+
}
|
|
23280
|
+
}
|
|
23281
|
+
}
|
|
23282
|
+
waitForSettlementRetry(delayMs) {
|
|
23283
|
+
return new Promise((resolve6) => {
|
|
23284
|
+
let timer;
|
|
23285
|
+
const finish = () => {
|
|
23286
|
+
clearTimeout(timer);
|
|
23287
|
+
this.settlementRetryWakeups.delete(finish);
|
|
23288
|
+
resolve6();
|
|
23289
|
+
};
|
|
23290
|
+
timer = setTimeout(finish, delayMs);
|
|
23291
|
+
this.settlementRetryWakeups.add(finish);
|
|
23292
|
+
});
|
|
23293
|
+
}
|
|
23131
23294
|
async commitEntry(entry, code, failure) {
|
|
23132
23295
|
const termination = entry.termination;
|
|
23133
23296
|
if (termination?.kind === "shutdown") return;
|
|
@@ -23291,6 +23454,9 @@ ${output}` : ""}`;
|
|
|
23291
23454
|
if (!taskModel || taskModel === "default") return null;
|
|
23292
23455
|
return taskModel;
|
|
23293
23456
|
}
|
|
23457
|
+
resolveVariant(taskVariant) {
|
|
23458
|
+
return taskVariant?.trim() || null;
|
|
23459
|
+
}
|
|
23294
23460
|
runDetached(operation, message, taskId) {
|
|
23295
23461
|
operation.catch((error) => {
|
|
23296
23462
|
markGatewayFailure("worker", error);
|
|
@@ -23668,6 +23834,7 @@ function createTaskFromTemplate(templateId, options) {
|
|
|
23668
23834
|
name: `${options.namePrefix ?? ""}${tmpl.name}`,
|
|
23669
23835
|
agent: tmpl.agent,
|
|
23670
23836
|
model: tmpl.model ?? "default",
|
|
23837
|
+
variant: tmpl.variant,
|
|
23671
23838
|
prompt: tmpl.prompt,
|
|
23672
23839
|
cwd: tmpl.cwd ?? null,
|
|
23673
23840
|
category: tmpl.category ?? "general",
|
|
@@ -26073,17 +26240,49 @@ function runOpenCode(executable, args, cwd, timeoutMs) {
|
|
|
26073
26240
|
const child = spawn2(executable, args, {
|
|
26074
26241
|
cwd,
|
|
26075
26242
|
env: process.env,
|
|
26076
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
26243
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
26244
|
+
detached: process.platform !== "win32"
|
|
26077
26245
|
});
|
|
26078
26246
|
let stdout = "";
|
|
26079
26247
|
let stderr = "";
|
|
26080
26248
|
let failure = null;
|
|
26081
|
-
let
|
|
26249
|
+
let settled = false;
|
|
26250
|
+
let forceKillTimer = null;
|
|
26251
|
+
let finalRejectTimer = null;
|
|
26252
|
+
let timer;
|
|
26253
|
+
const signalProcessTree = (signal) => {
|
|
26254
|
+
if (process.platform !== "win32" && child.pid) {
|
|
26255
|
+
try {
|
|
26256
|
+
process.kill(-child.pid, signal);
|
|
26257
|
+
return;
|
|
26258
|
+
} catch {
|
|
26259
|
+
}
|
|
26260
|
+
}
|
|
26261
|
+
child.kill(signal);
|
|
26262
|
+
};
|
|
26263
|
+
const rejectOnce = (error) => {
|
|
26264
|
+
failure ??= error;
|
|
26265
|
+
if (settled) return;
|
|
26266
|
+
settled = true;
|
|
26267
|
+
clearTimeout(timer);
|
|
26268
|
+
if (forceKillTimer) clearTimeout(forceKillTimer);
|
|
26269
|
+
if (finalRejectTimer) clearTimeout(finalRejectTimer);
|
|
26270
|
+
reject(failure);
|
|
26271
|
+
};
|
|
26272
|
+
const terminate = (error) => {
|
|
26273
|
+
if (failure) return;
|
|
26274
|
+
failure = error;
|
|
26275
|
+
signalProcessTree("SIGTERM");
|
|
26276
|
+
forceKillTimer = setTimeout(() => {
|
|
26277
|
+
signalProcessTree("SIGKILL");
|
|
26278
|
+
rejectOnce(error);
|
|
26279
|
+
}, 1e3);
|
|
26280
|
+
finalRejectTimer = setTimeout(() => rejectOnce(error), 2e3);
|
|
26281
|
+
};
|
|
26082
26282
|
const append = (current, chunk) => {
|
|
26083
26283
|
const next = current + chunk.toString();
|
|
26084
26284
|
if (Buffer.byteLength(next) > MAX_OUTPUT_BYTES && failure === null) {
|
|
26085
|
-
|
|
26086
|
-
child.kill("SIGTERM");
|
|
26285
|
+
terminate(new Error(`OpenCode \u8F93\u51FA\u8D85\u8FC7 ${MAX_OUTPUT_BYTES} bytes`));
|
|
26087
26286
|
}
|
|
26088
26287
|
return next.slice(-MAX_OUTPUT_BYTES);
|
|
26089
26288
|
};
|
|
@@ -26094,23 +26293,25 @@ function runOpenCode(executable, args, cwd, timeoutMs) {
|
|
|
26094
26293
|
stderr = append(stderr, chunk);
|
|
26095
26294
|
});
|
|
26096
26295
|
child.once("error", (error) => {
|
|
26097
|
-
|
|
26296
|
+
if (forceKillTimer) return;
|
|
26297
|
+
rejectOnce(error);
|
|
26098
26298
|
});
|
|
26099
|
-
|
|
26100
|
-
|
|
26101
|
-
child.kill("SIGTERM");
|
|
26299
|
+
timer = setTimeout(() => {
|
|
26300
|
+
terminate(new Error(`OpenCode \u547D\u4EE4\u8D85\u8FC7 ${timeoutMs}ms \u672A\u5B8C\u6210`));
|
|
26102
26301
|
}, timeoutMs);
|
|
26103
26302
|
child.once("close", (code) => {
|
|
26104
|
-
if (finished) return;
|
|
26105
|
-
finished = true;
|
|
26106
26303
|
clearTimeout(timer);
|
|
26304
|
+
if (forceKillTimer) return;
|
|
26305
|
+
if (finalRejectTimer) clearTimeout(finalRejectTimer);
|
|
26306
|
+
if (settled) return;
|
|
26307
|
+
settled = true;
|
|
26107
26308
|
if (failure) {
|
|
26108
26309
|
reject(failure);
|
|
26109
26310
|
return;
|
|
26110
26311
|
}
|
|
26111
26312
|
if (code !== 0) {
|
|
26112
26313
|
const detail = cleanOutput(stderr).trim() || `\u9000\u51FA\u7801 ${code ?? "null"}`;
|
|
26113
|
-
reject(new
|
|
26314
|
+
reject(new OpenCodeCommandExitError(`OpenCode ${args.join(" ")} \u5931\u8D25\uFF1A${detail}`));
|
|
26114
26315
|
return;
|
|
26115
26316
|
}
|
|
26116
26317
|
resolve6(cleanOutput(stdout));
|
|
@@ -26120,6 +26321,52 @@ function runOpenCode(executable, args, cwd, timeoutMs) {
|
|
|
26120
26321
|
function parseOpenCodeModels(output) {
|
|
26121
26322
|
return [...new Set(cleanOutput(output).split("\n").map((line) => line.trim()).filter((line) => /^[^\s/]+\/.+/.test(line)))].sort((left, right) => left.localeCompare(right));
|
|
26122
26323
|
}
|
|
26324
|
+
function isRecord(value) {
|
|
26325
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26326
|
+
}
|
|
26327
|
+
function findJsonObjectEnd(value, start) {
|
|
26328
|
+
let depth = 0;
|
|
26329
|
+
let inString = false;
|
|
26330
|
+
let escaped = false;
|
|
26331
|
+
for (let index2 = start; index2 < value.length; index2 += 1) {
|
|
26332
|
+
const character = value[index2];
|
|
26333
|
+
if (inString) {
|
|
26334
|
+
if (escaped) escaped = false;
|
|
26335
|
+
else if (character === "\\") escaped = true;
|
|
26336
|
+
else if (character === '"') inString = false;
|
|
26337
|
+
continue;
|
|
26338
|
+
}
|
|
26339
|
+
if (character === '"') inString = true;
|
|
26340
|
+
else if (character === "{") depth += 1;
|
|
26341
|
+
else if (character === "}" && --depth === 0) return index2 + 1;
|
|
26342
|
+
}
|
|
26343
|
+
return null;
|
|
26344
|
+
}
|
|
26345
|
+
function parseOpenCodeModelMetadata(output) {
|
|
26346
|
+
const cleaned = cleanOutput(output);
|
|
26347
|
+
const models = /* @__PURE__ */ new Set();
|
|
26348
|
+
const variantsByModel = {};
|
|
26349
|
+
const headingPattern = /^([^\s/]+\/[^\r\n]+)\r?\n\s*(?=\{)/gm;
|
|
26350
|
+
for (const match2 of cleaned.matchAll(headingPattern)) {
|
|
26351
|
+
const model = match2[1].trim();
|
|
26352
|
+
models.add(model);
|
|
26353
|
+
let objectStart = (match2.index ?? 0) + match2[0].length;
|
|
26354
|
+
while (/\s/.test(cleaned[objectStart] ?? "")) objectStart += 1;
|
|
26355
|
+
if (cleaned[objectStart] !== "{") continue;
|
|
26356
|
+
const objectEnd = findJsonObjectEnd(cleaned, objectStart);
|
|
26357
|
+
if (objectEnd === null) continue;
|
|
26358
|
+
try {
|
|
26359
|
+
const metadata = JSON.parse(cleaned.slice(objectStart, objectEnd));
|
|
26360
|
+
if (!isRecord(metadata) || !isRecord(metadata.variants)) continue;
|
|
26361
|
+
variantsByModel[model] = Object.keys(metadata.variants).filter((variant) => variant.trim().length > 0).sort((left, right) => left.localeCompare(right));
|
|
26362
|
+
} catch {
|
|
26363
|
+
}
|
|
26364
|
+
}
|
|
26365
|
+
return {
|
|
26366
|
+
models: [...models].sort((left, right) => left.localeCompare(right)),
|
|
26367
|
+
variantsByModel
|
|
26368
|
+
};
|
|
26369
|
+
}
|
|
26123
26370
|
function parseOpenCodeAgents(output) {
|
|
26124
26371
|
const agents = /* @__PURE__ */ new Map();
|
|
26125
26372
|
for (const line of cleanOutput(output).split("\n")) {
|
|
@@ -26138,19 +26385,23 @@ async function loadOpenCodeCatalog(cwd, options = {}) {
|
|
|
26138
26385
|
const executable = options.executable ?? process.env.SUPERTASK_OPENCODE_BIN ?? "opencode";
|
|
26139
26386
|
const timeoutMs = options.timeoutMs ?? COMMAND_TIMEOUT_MS;
|
|
26140
26387
|
const cacheKey = `${executable}\0${cwd}`;
|
|
26141
|
-
const
|
|
26142
|
-
if (options.useCache !== false &&
|
|
26143
|
-
return
|
|
26388
|
+
const cached2 = catalogCache.get(cacheKey);
|
|
26389
|
+
if (options.useCache !== false && cached2 && cached2.expiresAt > Date.now()) {
|
|
26390
|
+
return cached2.result;
|
|
26144
26391
|
}
|
|
26145
26392
|
const result = Promise.all([
|
|
26146
|
-
runOpenCode(executable, ["models"], cwd, timeoutMs)
|
|
26393
|
+
runOpenCode(executable, ["models", "--verbose"], cwd, timeoutMs).catch((error) => {
|
|
26394
|
+
if (!(error instanceof OpenCodeCommandExitError)) throw error;
|
|
26395
|
+
return runOpenCode(executable, ["models"], cwd, timeoutMs);
|
|
26396
|
+
}),
|
|
26147
26397
|
runOpenCode(executable, ["agent", "list"], cwd, timeoutMs)
|
|
26148
26398
|
]).then(([modelsOutput, agentsOutput]) => {
|
|
26149
|
-
const
|
|
26399
|
+
const metadata = parseOpenCodeModelMetadata(modelsOutput);
|
|
26400
|
+
const models = metadata.models.length > 0 ? metadata.models : parseOpenCodeModels(modelsOutput);
|
|
26150
26401
|
const agents = parseOpenCodeAgents(agentsOutput).filter((agent) => agent.mode !== "subagent");
|
|
26151
26402
|
if (models.length === 0) throw new Error("OpenCode \u6CA1\u6709\u8FD4\u56DE\u53EF\u7528\u6A21\u578B");
|
|
26152
26403
|
if (agents.length === 0) throw new Error("OpenCode \u6CA1\u6709\u8FD4\u56DE\u53EF\u76F4\u63A5\u8FD0\u884C\u7684\u4E3B Agent");
|
|
26153
|
-
return { cwd, models, agents };
|
|
26404
|
+
return { cwd, models, variantsByModel: metadata.variantsByModel, agents };
|
|
26154
26405
|
});
|
|
26155
26406
|
if (options.useCache !== false) {
|
|
26156
26407
|
catalogCache.set(cacheKey, { expiresAt: Date.now() + CATALOG_CACHE_MS, result });
|
|
@@ -26160,7 +26411,7 @@ async function loadOpenCodeCatalog(cwd, options = {}) {
|
|
|
26160
26411
|
}
|
|
26161
26412
|
return result;
|
|
26162
26413
|
}
|
|
26163
|
-
var CATALOG_CACHE_MS, COMMAND_TIMEOUT_MS, MAX_OUTPUT_BYTES, ANSI_PATTERN, catalogCache;
|
|
26414
|
+
var CATALOG_CACHE_MS, COMMAND_TIMEOUT_MS, MAX_OUTPUT_BYTES, ANSI_PATTERN, OpenCodeCommandExitError, catalogCache;
|
|
26164
26415
|
var init_opencode_catalog = __esm({
|
|
26165
26416
|
"src/core/opencode-catalog.ts"() {
|
|
26166
26417
|
"use strict";
|
|
@@ -26169,10 +26420,115 @@ var init_opencode_catalog = __esm({
|
|
|
26169
26420
|
COMMAND_TIMEOUT_MS = 2e4;
|
|
26170
26421
|
MAX_OUTPUT_BYTES = 4 * 1024 * 1024;
|
|
26171
26422
|
ANSI_PATTERN = /\x1B(?:[@-_][0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\))/g;
|
|
26423
|
+
OpenCodeCommandExitError = class extends Error {
|
|
26424
|
+
};
|
|
26172
26425
|
catalogCache = /* @__PURE__ */ new Map();
|
|
26173
26426
|
}
|
|
26174
26427
|
});
|
|
26175
26428
|
|
|
26429
|
+
// src/web/gateway-diagnostic.ts
|
|
26430
|
+
import { spawn as spawn3 } from "child_process";
|
|
26431
|
+
import { existsSync as existsSync8 } from "fs";
|
|
26432
|
+
import { dirname as dirname9, join as join7 } from "path";
|
|
26433
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
26434
|
+
function killDiagnosticGroup(pid) {
|
|
26435
|
+
if (process.platform !== "win32") {
|
|
26436
|
+
try {
|
|
26437
|
+
process.kill(-pid, "SIGKILL");
|
|
26438
|
+
return;
|
|
26439
|
+
} catch {
|
|
26440
|
+
}
|
|
26441
|
+
}
|
|
26442
|
+
try {
|
|
26443
|
+
process.kill(pid, "SIGKILL");
|
|
26444
|
+
} catch {
|
|
26445
|
+
}
|
|
26446
|
+
}
|
|
26447
|
+
function diagnosticEntry() {
|
|
26448
|
+
const extension = import.meta.url.endsWith(".ts") ? "ts" : "js";
|
|
26449
|
+
const moduleDir = dirname9(fileURLToPath6(import.meta.url));
|
|
26450
|
+
const candidates = [
|
|
26451
|
+
join7(moduleDir, `../daemon/gateway-diagnostic-runner.${extension}`),
|
|
26452
|
+
join7(moduleDir, `../../src/daemon/gateway-diagnostic-runner.${extension}`)
|
|
26453
|
+
];
|
|
26454
|
+
const entry = candidates.find((candidate) => existsSync8(candidate));
|
|
26455
|
+
if (!entry) throw new Error(`Gateway diagnostic runner \u4E0D\u5B58\u5728\uFF1A${candidates.join(", ")}`);
|
|
26456
|
+
return entry;
|
|
26457
|
+
}
|
|
26458
|
+
async function runGatewayDiagnostic() {
|
|
26459
|
+
return new Promise((resolve6, reject) => {
|
|
26460
|
+
const child = spawn3(process.execPath, [diagnosticEntry()], {
|
|
26461
|
+
cwd: process.cwd(),
|
|
26462
|
+
env: process.env,
|
|
26463
|
+
detached: process.platform !== "win32",
|
|
26464
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
26465
|
+
});
|
|
26466
|
+
let stdout = "";
|
|
26467
|
+
let stderr = "";
|
|
26468
|
+
let timedOut = false;
|
|
26469
|
+
if (child.pid) activeProcessGroups.add(child.pid);
|
|
26470
|
+
child.stdout?.on("data", (chunk) => {
|
|
26471
|
+
stdout += chunk.toString();
|
|
26472
|
+
});
|
|
26473
|
+
child.stderr?.on("data", (chunk) => {
|
|
26474
|
+
stderr += chunk.toString();
|
|
26475
|
+
});
|
|
26476
|
+
child.once("error", reject);
|
|
26477
|
+
child.once("close", (exitCode) => {
|
|
26478
|
+
clearTimeout(timer);
|
|
26479
|
+
if (child.pid) {
|
|
26480
|
+
killDiagnosticGroup(child.pid);
|
|
26481
|
+
activeProcessGroups.delete(child.pid);
|
|
26482
|
+
}
|
|
26483
|
+
if (timedOut) {
|
|
26484
|
+
reject(new Error(`Gateway diagnostic runner \u8D85\u8FC7 ${DIAGNOSTIC_TIMEOUT_MS}ms \u672A\u5B8C\u6210`));
|
|
26485
|
+
return;
|
|
26486
|
+
}
|
|
26487
|
+
if (exitCode !== 0) {
|
|
26488
|
+
reject(new Error(stderr.trim() || `Gateway diagnostic runner \u9000\u51FA\u7801 ${exitCode}`));
|
|
26489
|
+
return;
|
|
26490
|
+
}
|
|
26491
|
+
try {
|
|
26492
|
+
resolve6(JSON.parse(stdout));
|
|
26493
|
+
} catch (error) {
|
|
26494
|
+
reject(error);
|
|
26495
|
+
}
|
|
26496
|
+
});
|
|
26497
|
+
const timer = setTimeout(() => {
|
|
26498
|
+
timedOut = true;
|
|
26499
|
+
if (child.pid) killDiagnosticGroup(child.pid);
|
|
26500
|
+
else child.kill("SIGKILL");
|
|
26501
|
+
}, DIAGNOSTIC_TIMEOUT_MS);
|
|
26502
|
+
});
|
|
26503
|
+
}
|
|
26504
|
+
async function getDashboardGatewayDiagnostic(options = {}) {
|
|
26505
|
+
if (!options.fresh && cached && cached.expiresAt > Date.now()) return cached.diagnostic;
|
|
26506
|
+
if (!options.fresh && pending) return pending;
|
|
26507
|
+
const operation = runGatewayDiagnostic().then((diagnostic) => {
|
|
26508
|
+
cached = { expiresAt: Date.now() + CACHE_TTL_MS, diagnostic };
|
|
26509
|
+
return diagnostic;
|
|
26510
|
+
});
|
|
26511
|
+
if (options.fresh) return operation;
|
|
26512
|
+
pending = operation.finally(() => {
|
|
26513
|
+
pending = null;
|
|
26514
|
+
});
|
|
26515
|
+
return pending;
|
|
26516
|
+
}
|
|
26517
|
+
var CACHE_TTL_MS, DIAGNOSTIC_TIMEOUT_MS, cached, pending, activeProcessGroups;
|
|
26518
|
+
var init_gateway_diagnostic = __esm({
|
|
26519
|
+
"src/web/gateway-diagnostic.ts"() {
|
|
26520
|
+
"use strict";
|
|
26521
|
+
CACHE_TTL_MS = 5e3;
|
|
26522
|
+
DIAGNOSTIC_TIMEOUT_MS = 2e4;
|
|
26523
|
+
cached = null;
|
|
26524
|
+
pending = null;
|
|
26525
|
+
activeProcessGroups = /* @__PURE__ */ new Set();
|
|
26526
|
+
process.once("exit", () => {
|
|
26527
|
+
for (const pid of activeProcessGroups) killDiagnosticGroup(pid);
|
|
26528
|
+
});
|
|
26529
|
+
}
|
|
26530
|
+
});
|
|
26531
|
+
|
|
26176
26532
|
// src/web/ui.ts
|
|
26177
26533
|
function t(locale, key, values = {}) {
|
|
26178
26534
|
const template = (locale === "en" ? EN : ZH)[key];
|
|
@@ -26259,6 +26615,7 @@ function clientMessages(locale) {
|
|
|
26259
26615
|
"details.copySuccess",
|
|
26260
26616
|
"details.id",
|
|
26261
26617
|
"details.project",
|
|
26618
|
+
"details.variant",
|
|
26262
26619
|
"details.prompt",
|
|
26263
26620
|
"details.result",
|
|
26264
26621
|
"details.category",
|
|
@@ -26359,6 +26716,7 @@ function clientMessages(locale) {
|
|
|
26359
26716
|
"catalog.chooseProject",
|
|
26360
26717
|
"catalog.defaultModel",
|
|
26361
26718
|
"catalog.defaultProvider",
|
|
26719
|
+
"catalog.defaultVariant",
|
|
26362
26720
|
"catalog.loading",
|
|
26363
26721
|
"catalog.loaded",
|
|
26364
26722
|
"catalog.failed",
|
|
@@ -26483,23 +26841,23 @@ function renderLayout(options) {
|
|
|
26483
26841
|
function detailSession(value){if(!value)return text('details.none');const session=String(value);return session.length<=10?session:session.slice(0,6)+'***'+session.slice(-4)}
|
|
26484
26842
|
function detailTaskResult(data){const presentation=data._resultPresentation;if(!presentation)return text('details.none');const parts=[];if(Array.isArray(presentation.errors)&&presentation.errors.length)parts.push(presentation.errors.join('\\n'));if(presentation.text)parts.push(presentation.text);return parts.join('\\n\\n')||text('details.none')}
|
|
26485
26843
|
function detailField(label,value,options={}){const item=document.createElement('div');item.className='detail-item'+(options.wide?' wide':'');const name=document.createElement('div');name.className='detail-label';name.textContent=label;const content=options.long?document.createElement('pre'):document.createElement('div');content.className='detail-value'+(options.mono?' mono':'')+(options.long?' long':'');content.textContent=value===null||value===undefined||value===''?text('details.none'):String(value);item.append(name,content);return item}
|
|
26486
|
-
function renderDetailHistory(runs){const section=document.createElement('section');section.className='detail-history';const title=document.createElement('h3');title.textContent=text('details.history');section.appendChild(title);if(!Array.isArray(runs)||runs.length===0){const empty=document.createElement('div');empty.className='muted small';empty.textContent=text('details.noHistory');section.appendChild(empty);return section}const list=document.createElement('div');list.className='detail-history-list';for(const run of runs){const item=document.createElement('div');item.className='detail-history-item';const primary=document.createElement('strong');primary.textContent='Run #'+run.id+' \xB7 '+detailStatus('run',run.status);const secondary=document.createElement('span');secondary.className='muted';secondary.textContent=detailDate(run.startedAt)+(run.model?' \xB7 '+detailModel(run.model):'');item.append(primary,secondary);list.appendChild(item)}section.appendChild(list);return section}
|
|
26844
|
+
function renderDetailHistory(runs){const section=document.createElement('section');section.className='detail-history';const title=document.createElement('h3');title.textContent=text('details.history');section.appendChild(title);if(!Array.isArray(runs)||runs.length===0){const empty=document.createElement('div');empty.className='muted small';empty.textContent=text('details.noHistory');section.appendChild(empty);return section}const list=document.createElement('div');list.className='detail-history-list';for(const run of runs){const item=document.createElement('div');item.className='detail-history-item';const primary=document.createElement('strong');primary.textContent='Run #'+run.id+' \xB7 '+detailStatus('run',run.status);const secondary=document.createElement('span');secondary.className='muted';secondary.textContent=detailDate(run.startedAt)+(run.model?' \xB7 '+detailModel(run.model):'')+(run.variant?' \xB7 '+run.variant:'');item.append(primary,secondary);list.appendChild(item)}section.appendChild(list);return section}
|
|
26487
26845
|
function detailFields(type,data){if(type==='task')return [
|
|
26488
26846
|
[text('details.id'),'#'+data.id],[text('table.name'),data.name],[text('table.status'),detailStatus('task',data.status)],[text('details.project'),data.cwd,{wide:true,mono:true}],
|
|
26489
|
-
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
26847
|
+
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.variant'),data.variant||text('details.default')],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
26490
26848
|
[text('details.category'),data.category],[text('details.batch'),data.batchId],[text('details.dependency'),data.dependsOn?'#'+data.dependsOn:text('details.none')],
|
|
26491
26849
|
[text('details.importance'),data.importance],[text('details.urgency'),data.urgency],[text('details.retryCount'),String(data.retryCount??0)+' / '+String(data.maxRetries??0)],
|
|
26492
26850
|
[text('details.retryBackoff'),detailDuration(data.retryBackoffMs)],[text('details.timeout'),detailDuration(data.timeoutMs)],[text('details.scheduledAt'),detailDate(data.scheduledAt)],
|
|
26493
26851
|
[text('details.createdAt'),detailDate(data.createdAt)],[text('details.startedAt'),detailDate(data.startedAt)],[text('details.finishedAt'),detailDate(data.finishedAt)],
|
|
26494
26852
|
[text('details.result'),detailTaskResult(data),{wide:true,long:true}]
|
|
26495
26853
|
];if(type==='run'){const started=data.startedAt?new Date(data.startedAt).getTime():null;const finished=data.finishedAt?new Date(data.finishedAt).getTime():null;return [
|
|
26496
|
-
[text('details.id'),'Run #'+data.id],[text('details.taskId'),'#'+data.taskId],[text('table.status'),detailStatus('run',data.status)],[text('table.model'),detailModel(data.model)],
|
|
26854
|
+
[text('details.id'),'Run #'+data.id],[text('details.taskId'),'#'+data.taskId],[text('table.status'),detailStatus('run',data.status)],[text('table.model'),detailModel(data.model)],[text('details.variant'),data.variant||text('details.default')],
|
|
26497
26855
|
[text('details.session'),detailSession(data.sessionId)],[text('details.startedAt'),detailDate(data.startedAt)],[text('details.finishedAt'),detailDate(data.finishedAt)],
|
|
26498
26856
|
[text('table.duration'),started!==null?detailDuration((finished??Date.now())-started):text('details.none')],[text('details.heartbeat'),detailDate(data.heartbeatAt)],
|
|
26499
26857
|
[text('details.process'),'Worker PID '+String(data.workerPid??'\u2014')+' \xB7 OpenCode PID '+String(data.childPid??'\u2014'),{wide:true,mono:true}]
|
|
26500
26858
|
];}const scheduleRule=data.scheduleType==='cron'?data.cronExpr:data.scheduleType==='recurring'?detailDuration(data.intervalMs):detailDate(data.runAt);return [
|
|
26501
26859
|
[text('details.id'),'#'+data.id],[text('table.name'),data.name],[text('details.enabled'),data.enabled?text('details.enabledYes'):text('details.enabledNo')],[text('details.project'),data.cwd,{wide:true,mono:true}],
|
|
26502
|
-
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
26860
|
+
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.variant'),data.variant||text('details.default')],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
26503
26861
|
[text('template.scheduleType'),detailScheduleType(data.scheduleType)],[text('details.scheduleRule'),scheduleRule],[text('details.category'),data.category],[text('details.batch'),data.batchId],
|
|
26504
26862
|
[text('details.importance'),data.importance],[text('details.urgency'),data.urgency],[text('details.maxInstances'),data.maxInstances],[text('details.maxRetries'),data.maxRetries??0],
|
|
26505
26863
|
[text('details.retryBackoff'),detailDuration(data.retryBackoffMs)],[text('details.timeout'),detailDuration(data.timeoutMs)],[text('details.lastRun'),detailDate(data.lastRunAt)],[text('details.nextRun'),detailDate(data.nextRunAt)],
|
|
@@ -26516,12 +26874,20 @@ function renderLayout(options) {
|
|
|
26516
26874
|
function updateTaskProjectStatus(){const node=taskField('project-status');if(!node)return;const cwd=taskField('cwd').value.trim();if(!cwd){node.textContent='';return}const project=taskProjects()[cwd];node.textContent=project?text('task.projectExisting',project):text('task.projectNew')}
|
|
26517
26875
|
const catalogTimers={};const catalogRequests={};const catalogModels={};
|
|
26518
26876
|
function catalogField(prefix,name){return document.getElementById(prefix+'-'+name)}
|
|
26519
|
-
function resetCatalog(prefix){const agent=catalogField(prefix,'agent');const provider=catalogField(prefix,'model-provider');const model=catalogField(prefix,'model');if(!agent||!provider||!model)return;catalogModels[prefix]=[];agent.replaceChildren(new Option(text('catalog.chooseProject'),''));provider.replaceChildren(new Option(text('catalog.defaultProvider'),''));model.replaceChildren(new Option(text('catalog.defaultModel'),'default'));agent.disabled=false;provider.disabled=true;model.disabled=true;catalogField(prefix,'catalog-status').textContent='';}
|
|
26877
|
+
function resetCatalog(prefix){const agent=catalogField(prefix,'agent');const provider=catalogField(prefix,'model-provider');const model=catalogField(prefix,'model');const variant=catalogField(prefix,'variant');if(!agent||!provider||!model||!variant)return;const preferredVariant=variant.dataset.preferred||'';catalogModels[prefix]=[];agent.replaceChildren(new Option(text('catalog.chooseProject'),''));provider.replaceChildren(new Option(text('catalog.defaultProvider'),''));model.replaceChildren(new Option(text('catalog.defaultModel'),'default'));variant.replaceChildren(new Option(text('catalog.defaultVariant'),''));if(preferredVariant)appendCurrentOption(variant,preferredVariant);variant.value=preferredVariant;agent.disabled=false;provider.disabled=true;model.disabled=true;variant.disabled=!preferredVariant;catalogField(prefix,'catalog-status').textContent='';}
|
|
26520
26878
|
function appendCurrentOption(select,value){if(!value||[...select.options].some(option=>option.value===value))return;select.appendChild(new Option(value,value));}
|
|
26879
|
+
function setPreferredVariant(prefix,modelValue,variantValue){const variant=catalogField(prefix,'variant');if(!variant)return;const preferred=variantValue||'';variant.dataset.preferred=preferred;variant.dataset.preferredModel=modelValue||'default';variant.replaceChildren(new Option(text('catalog.defaultVariant'),''));if(preferred)appendCurrentOption(variant,preferred);variant.value=preferred;variant.disabled=!preferred}
|
|
26880
|
+
function invalidateVariantRequest(prefix){const key=prefix+'-variant';catalogRequests[key]=(catalogRequests[key]||0)+1}
|
|
26881
|
+
function invalidateCatalogRequests(prefix){clearTimeout(catalogTimers[prefix]);catalogRequests[prefix]=(catalogRequests[prefix]||0)+1;invalidateVariantRequest(prefix)}
|
|
26882
|
+
function clearVariantPreference(prefix){const variant=catalogField(prefix,'variant');if(!variant)return;invalidateVariantRequest(prefix);variant.dataset.preferred='';variant.dataset.preferredModel='';variant.replaceChildren(new Option(text('catalog.defaultVariant'),''));variant.value='';variant.disabled=true}
|
|
26883
|
+
function handleProviderChange(prefix){clearVariantPreference(prefix);populateModelOptions(prefix)}
|
|
26884
|
+
function handleModelChange(prefix){clearVariantPreference(prefix);populateVariantOptions(prefix)}
|
|
26885
|
+
function handleVariantChange(prefix){const variant=catalogField(prefix,'variant');if(!variant)return;invalidateVariantRequest(prefix);variant.dataset.preferred='';variant.dataset.preferredModel=''}
|
|
26521
26886
|
function modelProvider(value){const slash=value.indexOf('/');return slash>0?value.slice(0,slash):''}
|
|
26522
|
-
function populateModelOptions(prefix,preferredModel=''){const provider=catalogField(prefix,'model-provider');const model=catalogField(prefix,'model');if(!provider||!model)return;const selectedProvider=provider.value;model.replaceChildren();if(!selectedProvider){model.appendChild(new Option(text('catalog.defaultModel'),'default'));model.disabled=true;return}const available=(catalogModels[prefix]||[]).filter(value=>modelProvider(value)===selectedProvider);for(const value of available)model.appendChild(new Option(value,value));if(preferredModel&&available.includes(preferredModel))model.value=preferredModel;model.disabled=available.length===0}
|
|
26887
|
+
function populateModelOptions(prefix,preferredModel=''){const provider=catalogField(prefix,'model-provider');const model=catalogField(prefix,'model');if(!provider||!model)return;const selectedProvider=provider.value;model.replaceChildren();if(!selectedProvider){model.appendChild(new Option(text('catalog.defaultModel'),'default'));model.disabled=true;populateVariantOptions(prefix);return}const available=(catalogModels[prefix]||[]).filter(value=>modelProvider(value)===selectedProvider);for(const value of available)model.appendChild(new Option(value,value));if(preferredModel&&available.includes(preferredModel))model.value=preferredModel;model.disabled=available.length===0;populateVariantOptions(prefix)}
|
|
26888
|
+
async function populateVariantOptions(prefix,preferredVariant=''){const cwd=catalogField(prefix,'cwd')?.value.trim()||'';const model=catalogField(prefix,'model');const variant=catalogField(prefix,'variant');if(!model||!variant)return;const selectedModel=model.value;const preferred=preferredVariant||(variant.dataset.preferredModel===selectedModel?variant.dataset.preferred||'':'');if(!cwd||!selectedModel||selectedModel==='default'){variant.replaceChildren(new Option(text('catalog.defaultVariant'),''));if(preferred)appendCurrentOption(variant,preferred);variant.value=preferred;variant.dataset.preferred='';variant.dataset.preferredModel='';variant.disabled=!preferred;return}if(!preferred){variant.replaceChildren(new Option(text('catalog.defaultVariant'),''));variant.value=''}const requestKey=prefix+'-variant';const request=(catalogRequests[requestKey]||0)+1;catalogRequests[requestKey]=request;variant.disabled=true;try{const data=await readJson(await fetch('/api/opencode/catalog?cwd='+encodeURIComponent(cwd)));if(catalogRequests[requestKey]!==request||catalogField(prefix,'cwd')?.value.trim()!==cwd||model.value!==selectedModel)return;const available=Array.isArray(data.variantsByModel?.[selectedModel])?data.variantsByModel[selectedModel]:[];variant.replaceChildren(new Option(text('catalog.defaultVariant'),''));for(const value of available)variant.appendChild(new Option(value,value));if(preferred)appendCurrentOption(variant,preferred);variant.value=[...variant.options].some(option=>option.value===preferred)?preferred:'';variant.dataset.preferred='';variant.dataset.preferredModel='';variant.disabled=available.length===0&&!preferred}catch(error){if(catalogRequests[requestKey]!==request||catalogField(prefix,'cwd')?.value.trim()!==cwd||model.value!==selectedModel)return;if(preferred)appendCurrentOption(variant,preferred);variant.value=preferred;variant.dataset.preferred=preferred;variant.dataset.preferredModel=selectedModel;variant.disabled=!preferred}}
|
|
26523
26889
|
async function loadCatalog(prefix,preferredAgent='',preferredModel='default',preserveUnavailable=false){const cwd=catalogField(prefix,'cwd')?.value.trim()||'';const status=catalogField(prefix,'catalog-status');const agent=catalogField(prefix,'agent');const provider=catalogField(prefix,'model-provider');const model=catalogField(prefix,'model');if(!cwd||!status||!agent||!provider||!model){if(!cwd)resetCatalog(prefix);return}const request=(catalogRequests[prefix]||0)+1;catalogRequests[prefix]=request;status.dataset.state='loading';status.textContent=text('catalog.loading');agent.disabled=true;provider.disabled=true;model.disabled=true;try{const data=await readJson(await fetch('/api/opencode/catalog?cwd='+encodeURIComponent(cwd)));if(catalogRequests[prefix]!==request||catalogField(prefix,'cwd').value.trim()!==cwd)return;agent.replaceChildren();for(const item of data.agents){const label=item.name+' \u2014 '+text('catalog.'+item.mode);agent.appendChild(new Option(label,item.name))}if(preserveUnavailable)appendCurrentOption(agent,preferredAgent);const defaultAgent=preferredAgent||data.agents.find(item=>item.name==='build')?.name||data.agents.find(item=>item.mode==='primary')?.name||data.agents[0]?.name||'';agent.value=[...agent.options].some(option=>option.value===defaultAgent)?defaultAgent:(agent.options[0]?.value||'');catalogModels[prefix]=[...data.models];if(preserveUnavailable&&preferredModel&&preferredModel!=='default'&&!catalogModels[prefix].includes(preferredModel))catalogModels[prefix].push(preferredModel);provider.replaceChildren(new Option(text('catalog.defaultProvider'),''));for(const name of [...new Set(catalogModels[prefix].map(modelProvider).filter(Boolean))].sort())provider.appendChild(new Option(name,name));const preferredProvider=preferredModel==='default'?'':modelProvider(preferredModel);provider.value=[...provider.options].some(option=>option.value===preferredProvider)?preferredProvider:'';populateModelOptions(prefix,preferredModel);status.dataset.state='ready';status.textContent=text('catalog.loaded',{agents:data.agents.length,models:data.models.length})}catch(error){if(catalogRequests[prefix]!==request)return;resetCatalog(prefix);if(preserveUnavailable){appendCurrentOption(agent,preferredAgent);if(preferredModel&&preferredModel!=='default'){catalogModels[prefix]=[preferredModel];appendCurrentOption(provider,modelProvider(preferredModel));provider.value=modelProvider(preferredModel);populateModelOptions(prefix,preferredModel)}}status.dataset.state='error';status.textContent=text('catalog.failed',{error:error.message})}finally{if(catalogRequests[prefix]===request){agent.disabled=false;provider.disabled=false;if(provider.value)model.disabled=false}}}
|
|
26524
|
-
function scheduleCatalogLoad(prefix){
|
|
26890
|
+
function scheduleCatalogLoad(prefix){invalidateCatalogRequests(prefix);resetCatalog(prefix);catalogTimers[prefix]=setTimeout(()=>loadCatalog(prefix),450)}
|
|
26525
26891
|
let directoryTargetId='';let directoryCurrent='';let directoryEntries=[];let directoryShowHidden=false;
|
|
26526
26892
|
function renderDirectoryEntries(){const list=document.getElementById('directory-list');list.replaceChildren();const entries=directoryEntries.filter(entry=>directoryShowHidden||!entry.hidden);const hidden=document.getElementById('directory-hidden');hidden.textContent=text(directoryShowHidden?'action.hideHidden':'action.showHidden');if(entries.length===0){const empty=document.createElement('div');empty.className='directory-empty';empty.textContent=text('directory.empty');list.appendChild(empty);return}for(const entry of entries){const button=document.createElement('button');button.type='button';button.className='directory-item';button.innerHTML='${icon("folder")}<span></span>';button.querySelector('span').textContent=entry.name;button.onclick=()=>browseDirectory(entry.path);list.appendChild(button)}}
|
|
26527
26893
|
async function browseDirectory(path=''){const choose=document.getElementById('directory-choose');choose.disabled=true;try{const suffix=path?'?path='+encodeURIComponent(path):'';const data=await readJson(await fetch('/api/filesystem/directories'+suffix));directoryCurrent=data.path;directoryEntries=data.directories;document.getElementById('directory-path').textContent=data.path;document.getElementById('directory-up').disabled=data.parent===data.path;document.getElementById('directory-up').onclick=()=>browseDirectory(data.parent);document.getElementById('directory-home').onclick=()=>browseDirectory(data.home);renderDirectoryEntries();choose.disabled=false;return true}catch(error){directoryCurrent='';directoryEntries=[];document.getElementById('directory-path').textContent='';renderDirectoryEntries();showToast(error.message,'error');return false}}
|
|
@@ -26531,16 +26897,16 @@ function renderLayout(options) {
|
|
|
26531
26897
|
function updateDurationControl(id){const preset=document.getElementById(id+'-preset');const custom=document.getElementById(id+'-custom');const input=document.getElementById(id+'-value');const visible=preset.value==='custom';custom.hidden=!visible;input.required=visible;if(visible&&!input.value)input.value='1'}
|
|
26532
26898
|
function readDuration(id){const preset=document.getElementById(id+'-preset').value;if(preset==='')return '';if(preset!=='custom')return preset==='0'?'0':preset+'ms';const value=document.getElementById(id+'-value').value.trim();return value===''?'':value+document.getElementById(id+'-unit').value}
|
|
26533
26899
|
function setDuration(id,milliseconds){const preset=document.getElementById(id+'-preset');const exact=milliseconds==null?'':String(milliseconds);if([...preset.options].some(option=>option.value===exact)){preset.value=exact;updateDurationControl(id);return}preset.value='custom';const input=document.getElementById(id+'-value');const unit=document.getElementById(id+'-unit');const units=[['d',86400000],['h',3600000],['min',60000],['s',1000]];let matched=false;for(const [name,factor] of units){if(milliseconds!=null&&(milliseconds===0||milliseconds%factor===0)){input.value=String(milliseconds/factor);unit.value=name;matched=true;break}}if(!matched){input.value=String((milliseconds??60000)/1000);unit.value='s'}updateDurationControl(id)}
|
|
26534
|
-
function openTaskCreator(){const form=document.getElementById('task-form');form.reset();taskField('id').value='';taskField('cwd').readOnly=false;taskField('cwd-picker').hidden=false;taskField('cwd').value=form.dataset.defaultCwd||'';setDuration('task-retry-backoff',30000);setDuration('task-timeout',null);taskField('dialog-title').textContent=text('task.createTitle');taskField('save').textContent=text('action.saveTask');updateTaskProjectStatus();resetCatalog('task');document.getElementById('task-dialog').showModal();if(taskField('cwd').value)loadCatalog('task');setTimeout(()=>taskField('name').focus(),50)}
|
|
26535
|
-
async function openTaskEditor(id){try{const data=await readJson(await fetch('/api/tasks/'+id));taskField('id').value=String(id);taskField('cwd').value=data.cwd||'';taskField('cwd').readOnly=true;taskField('cwd-picker').hidden=true;taskField('name').value=data.name||'';taskField('prompt').value=data.prompt||'';taskField('category').value=data.category||'general';taskField('batch').value=data.batchId||'';taskField('importance').value=String(data.importance??3);taskField('urgency').value=String(data.urgency??3);taskField('max-retries').value=String(data.maxRetries??3);setDuration('task-retry-backoff',data.retryBackoffMs??30000);setDuration('task-timeout',data.timeoutMs);taskField('dialog-title').textContent=text('task.editTitle');taskField('save').textContent=text('action.updateTask');updateTaskProjectStatus();resetCatalog('task');document.getElementById('task-dialog').showModal();loadCatalog('task',data.agent||'',data.model||'default',true);setTimeout(()=>taskField('name').focus(),50)}catch(error){showToast(error.message,'error')}}
|
|
26536
|
-
async function saveTask(event){event.preventDefault();const form=document.getElementById('task-form');if(!form.reportValidity())return;const id=taskField('id').value;const body={name:taskField('name').value,cwd:taskField('cwd').value,agent:taskField('agent').value,model:taskField('model').value,prompt:taskField('prompt').value,category:taskField('category').value,batchId:taskField('batch').value,importance:Number(taskField('importance').value),urgency:Number(taskField('urgency').value),maxRetries:Number(taskField('max-retries').value),retryBackoff:readDuration('task-retry-backoff'),timeout:readDuration('task-timeout')};const button=taskField('save');button.disabled=true;try{const data=await readJson(await fetch(id?'/api/tasks/'+id:'/api/tasks',{method:id?'PUT':'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}));showToast(text(id?'feedback.taskUpdated':'feedback.taskCreated',{id:data.task.id}));document.getElementById('task-dialog').close();setTimeout(()=>location.assign(id?location.href:'/?cwd='+encodeURIComponent(data.task.cwd||'')),450)}catch(error){showToast(error.message,'error')}finally{button.disabled=false}}
|
|
26900
|
+
function openTaskCreator(){invalidateCatalogRequests('task');const form=document.getElementById('task-form');form.reset();taskField('id').value='';setPreferredVariant('task','default','');taskField('cwd').readOnly=false;taskField('cwd-picker').hidden=false;taskField('cwd').value=form.dataset.defaultCwd||'';setDuration('task-retry-backoff',30000);setDuration('task-timeout',null);taskField('dialog-title').textContent=text('task.createTitle');taskField('save').textContent=text('action.saveTask');updateTaskProjectStatus();resetCatalog('task');document.getElementById('task-dialog').showModal();if(taskField('cwd').value)loadCatalog('task');setTimeout(()=>taskField('name').focus(),50)}
|
|
26901
|
+
async function openTaskEditor(id){invalidateCatalogRequests('task');try{const data=await readJson(await fetch('/api/tasks/'+id));document.getElementById('task-form').reset();taskField('id').value=String(id);taskField('cwd').value=data.cwd||'';taskField('cwd').readOnly=true;taskField('cwd-picker').hidden=true;taskField('name').value=data.name||'';taskField('prompt').value=data.prompt||'';taskField('category').value=data.category||'general';taskField('batch').value=data.batchId||'';taskField('importance').value=String(data.importance??3);taskField('urgency').value=String(data.urgency??3);taskField('max-retries').value=String(data.maxRetries??3);setDuration('task-retry-backoff',data.retryBackoffMs??30000);setDuration('task-timeout',data.timeoutMs);taskField('dialog-title').textContent=text('task.editTitle');taskField('save').textContent=text('action.updateTask');updateTaskProjectStatus();setPreferredVariant('task',data.model||'default',data.variant||'');resetCatalog('task');document.getElementById('task-dialog').showModal();loadCatalog('task',data.agent||'',data.model||'default',true);setTimeout(()=>taskField('name').focus(),50)}catch(error){showToast(error.message,'error')}}
|
|
26902
|
+
async function saveTask(event){event.preventDefault();const form=document.getElementById('task-form');if(!form.reportValidity())return;const id=taskField('id').value;const body={name:taskField('name').value,cwd:taskField('cwd').value,agent:taskField('agent').value,model:taskField('model').value,variant:taskField('variant').value,prompt:taskField('prompt').value,category:taskField('category').value,batchId:taskField('batch').value,importance:Number(taskField('importance').value),urgency:Number(taskField('urgency').value),maxRetries:Number(taskField('max-retries').value),retryBackoff:readDuration('task-retry-backoff'),timeout:readDuration('task-timeout')};const button=taskField('save');button.disabled=true;try{const data=await readJson(await fetch(id?'/api/tasks/'+id:'/api/tasks',{method:id?'PUT':'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}));showToast(text(id?'feedback.taskUpdated':'feedback.taskCreated',{id:data.task.id}));document.getElementById('task-dialog').close();setTimeout(()=>location.assign(id?location.href:'/?cwd='+encodeURIComponent(data.task.cwd||'')),450)}catch(error){showToast(error.message,'error')}finally{button.disabled=false}}
|
|
26537
26903
|
function localDateTime(milliseconds){const date=new Date(milliseconds);const local=new Date(milliseconds-date.getTimezoneOffset()*60000);return local.toISOString().slice(0,23)}
|
|
26538
26904
|
function updateTemplateScheduleFields(){const type=templateField('schedule-type').value;const fields={cron:templateField('cron-field'),recurring:templateField('interval-field'),delayed:templateField('run-at-field')};for(const [name,node] of Object.entries(fields)){node.hidden=name!==type;for(const control of node.querySelectorAll('input,select'))control.required=false;const required=name==='recurring'?node.querySelector('[id$="-preset"]'):node.querySelector('input');if(required)required.required=name===type;if(name==='recurring'&&name===type)updateDurationControl('template-interval')}}
|
|
26539
26905
|
function setOriginalRunAt(epoch){const input=templateField('run-at');const local=epoch?localDateTime(epoch):'';input.value=local;input.dataset.originalEpoch=epoch?String(epoch):'';input.dataset.originalLocal=local}
|
|
26540
26906
|
function selectedRunAt(){const input=templateField('run-at');return resolveEditedRunAt(input.dataset.originalEpoch?Number(input.dataset.originalEpoch):null,input.dataset.originalLocal||'',input.value)}
|
|
26541
|
-
function openTemplateCreator(){const form=document.getElementById('template-form');form.reset();templateField('id').value='';templateField('dialog-title').textContent=text('template.createTitle');setDuration('template-interval',3600000);setDuration('template-retry-backoff',30000);setDuration('template-timeout',null);setOriginalRunAt(null);templateField('run-at').value=localDateTime(Date.now()+3600000);updateTemplateScheduleFields();resetCatalog('template');document.getElementById('template-dialog').showModal();if(templateField('cwd').value)loadCatalog('template');setTimeout(()=>templateField('name').focus(),50)}
|
|
26542
|
-
async function openTemplateEditor(id){try{const data=await readJson(await fetch('/api/templates/'+id));templateField('id').value=String(id);templateField('dialog-title').textContent=text('template.editTitle');templateField('name').value=data.name||'';templateField('cwd').value=data.cwd||'';templateField('prompt').value=data.prompt||'';templateField('schedule-type').value=data.scheduleType;templateField('cron').value=data.cronExpr||'';setDuration('template-interval',data.intervalMs);setOriginalRunAt(data.runAt||null);if(!data.runAt)templateField('run-at').value=localDateTime(Date.now()+3600000);templateField('category').value=data.category||'general';templateField('batch').value=data.batchId||'';templateField('importance').value=String(data.importance??3);templateField('urgency').value=String(data.urgency??3);templateField('max-instances').value=String(data.maxInstances??1);templateField('max-retries').value=String(data.maxRetries??3);setDuration('template-retry-backoff',data.retryBackoffMs??30000);setDuration('template-timeout',data.timeoutMs);updateTemplateScheduleFields();resetCatalog('template');document.getElementById('template-dialog').showModal();loadCatalog('template',data.agent||'',data.model||'default',true);setTimeout(()=>templateField('name').focus(),50)}catch(error){showToast(error.message,'error')}}
|
|
26543
|
-
async function saveTemplate(event){event.preventDefault();const form=document.getElementById('template-form');if(!form.reportValidity())return;const id=templateField('id').value;const type=templateField('schedule-type').value;const body={name:templateField('name').value,cwd:templateField('cwd').value,agent:templateField('agent').value,model:templateField('model').value,prompt:templateField('prompt').value,scheduleType:type,cronExpr:templateField('cron').value,interval:readDuration('template-interval'),runAt:type==='delayed'?selectedRunAt():null,category:templateField('category').value,batchId:templateField('batch').value,importance:Number(templateField('importance').value),urgency:Number(templateField('urgency').value),maxInstances:Number(templateField('max-instances').value),maxRetries:Number(templateField('max-retries').value),retryBackoff:readDuration('template-retry-backoff'),timeout:readDuration('template-timeout')};const button=templateField('save');button.disabled=true;try{await readJson(await fetch(id?'/api/templates/'+id:'/api/templates',{method:id?'PUT':'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}));showToast(text(id?'feedback.templateUpdated':'feedback.templateCreated'));document.getElementById('template-dialog').close();setTimeout(()=>location.assign(id?location.href:'/templates'),450)}catch(error){showToast(error.message,'error')}finally{button.disabled=false}}
|
|
26907
|
+
function openTemplateCreator(){invalidateCatalogRequests('template');const form=document.getElementById('template-form');form.reset();templateField('id').value='';setPreferredVariant('template','default','');templateField('dialog-title').textContent=text('template.createTitle');setDuration('template-interval',3600000);setDuration('template-retry-backoff',30000);setDuration('template-timeout',null);setOriginalRunAt(null);templateField('run-at').value=localDateTime(Date.now()+3600000);updateTemplateScheduleFields();resetCatalog('template');document.getElementById('template-dialog').showModal();if(templateField('cwd').value)loadCatalog('template');setTimeout(()=>templateField('name').focus(),50)}
|
|
26908
|
+
async function openTemplateEditor(id){invalidateCatalogRequests('template');try{const data=await readJson(await fetch('/api/templates/'+id));document.getElementById('template-form').reset();templateField('id').value=String(id);templateField('dialog-title').textContent=text('template.editTitle');templateField('name').value=data.name||'';templateField('cwd').value=data.cwd||'';templateField('prompt').value=data.prompt||'';templateField('schedule-type').value=data.scheduleType;templateField('cron').value=data.cronExpr||'';setDuration('template-interval',data.intervalMs);setOriginalRunAt(data.runAt||null);if(!data.runAt)templateField('run-at').value=localDateTime(Date.now()+3600000);templateField('category').value=data.category||'general';templateField('batch').value=data.batchId||'';templateField('importance').value=String(data.importance??3);templateField('urgency').value=String(data.urgency??3);templateField('max-instances').value=String(data.maxInstances??1);templateField('max-retries').value=String(data.maxRetries??3);setDuration('template-retry-backoff',data.retryBackoffMs??30000);setDuration('template-timeout',data.timeoutMs);updateTemplateScheduleFields();setPreferredVariant('template',data.model||'default',data.variant||'');resetCatalog('template');document.getElementById('template-dialog').showModal();loadCatalog('template',data.agent||'',data.model||'default',true);setTimeout(()=>templateField('name').focus(),50)}catch(error){showToast(error.message,'error')}}
|
|
26909
|
+
async function saveTemplate(event){event.preventDefault();const form=document.getElementById('template-form');if(!form.reportValidity())return;const id=templateField('id').value;const type=templateField('schedule-type').value;const body={name:templateField('name').value,cwd:templateField('cwd').value,agent:templateField('agent').value,model:templateField('model').value,variant:templateField('variant').value,prompt:templateField('prompt').value,scheduleType:type,cronExpr:templateField('cron').value,interval:readDuration('template-interval'),runAt:type==='delayed'?selectedRunAt():null,category:templateField('category').value,batchId:templateField('batch').value,importance:Number(templateField('importance').value),urgency:Number(templateField('urgency').value),maxInstances:Number(templateField('max-instances').value),maxRetries:Number(templateField('max-retries').value),retryBackoff:readDuration('template-retry-backoff'),timeout:readDuration('template-timeout')};const button=templateField('save');button.disabled=true;try{await readJson(await fetch(id?'/api/templates/'+id:'/api/templates',{method:id?'PUT':'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}));showToast(text(id?'feedback.templateUpdated':'feedback.templateCreated'));document.getElementById('template-dialog').close();setTimeout(()=>location.assign(id?location.href:'/templates'),450)}catch(error){showToast(error.message,'error')}finally{button.disabled=false}}
|
|
26544
26910
|
async function enableTmpl(id){try{await readJson(await fetch('/api/templates/'+id+'/enable',{method:'POST'}));location.reload()}catch(error){showToast(error.message,'error')}}
|
|
26545
26911
|
async function disableTmpl(id){if(!await ask(text('dialog.disableTemplate'),text('dialog.disableTemplateBody')))return;try{await readJson(await fetch('/api/templates/'+id+'/disable',{method:'POST'}));location.reload()}catch(error){showToast(error.message,'error')}}
|
|
26546
26912
|
async function deleteTmpl(id){if(!await ask(text('dialog.deleteTemplate'),text('dialog.deleteTemplateBody'),true))return;try{await readJson(await fetch('/api/templates/'+id,{method:'DELETE'}));location.reload()}catch(error){showToast(error.message,'error')}}
|
|
@@ -26722,6 +27088,7 @@ var init_ui = __esm({
|
|
|
26722
27088
|
"template.cwdHint": "OpenCode \u4F1A\u5728\u8FD9\u4E2A\u76EE\u5F55\u4E2D\u6267\u884C\u4EFB\u52A1\u3002",
|
|
26723
27089
|
"template.agent": "Agent",
|
|
26724
27090
|
"template.model": "\u6A21\u578B",
|
|
27091
|
+
"template.variant": "\u6A21\u578B Variant",
|
|
26725
27092
|
"template.prompt": "\u63D0\u793A\u8BCD",
|
|
26726
27093
|
"template.scheduleType": "\u6267\u884C\u65B9\u5F0F",
|
|
26727
27094
|
"template.cronExpr": "Cron \u8868\u8FBE\u5F0F",
|
|
@@ -26759,9 +27126,11 @@ var init_ui = __esm({
|
|
|
26759
27126
|
"catalog.chooseProject": "\u8BF7\u5148\u9009\u62E9\u9879\u76EE\u76EE\u5F55",
|
|
26760
27127
|
"catalog.defaultModel": "\u8DDF\u968F Agent / OpenCode \u9ED8\u8BA4\u6A21\u578B",
|
|
26761
27128
|
"catalog.defaultProvider": "\u9ED8\u8BA4\u6A21\u578B",
|
|
27129
|
+
"catalog.defaultVariant": "\u8DDF\u968F Agent / \u6A21\u578B\u9ED8\u8BA4\u8BBE\u7F6E",
|
|
26762
27130
|
"catalog.provider": "\u6A21\u578B\u63D0\u4F9B\u5546",
|
|
26763
27131
|
"catalog.model": "\u5177\u4F53\u6A21\u578B",
|
|
26764
|
-
"catalog.modelHint": "\u5148\u9009\u63D0\u4F9B\u5546\uFF0C\u518D\u9009\u672C\u9879\u76EE opencode models \u8FD4\u56DE\u7684\u6A21\u578B\uFF1B\u9ED8\u8BA4\u9009\u9879\u4E0D\u4F1A\u4F20\u5165 -m\u3002",
|
|
27132
|
+
"catalog.modelHint": "\u5148\u9009\u63D0\u4F9B\u5546\uFF0C\u518D\u9009\u672C\u9879\u76EE opencode models --verbose \u8FD4\u56DE\u7684\u6A21\u578B\uFF1B\u9ED8\u8BA4\u9009\u9879\u4E0D\u4F1A\u4F20\u5165 -m\u3002",
|
|
27133
|
+
"catalog.variantHint": "\u4EC5\u663E\u793A\u6240\u9009\u6A21\u578B\u58F0\u660E\u652F\u6301\u7684 variants\uFF1B\u9ED8\u8BA4\u9009\u9879\u4E0D\u4F1A\u4F20\u5165 --variant\u3002",
|
|
26765
27134
|
"catalog.agentHint": "\u6765\u81EA\u5F53\u524D\u9879\u76EE\u7684 opencode agent list\u3002",
|
|
26766
27135
|
"catalog.loading": "\u6B63\u5728\u8BFB\u53D6\u6B64\u9879\u76EE\u53EF\u7528\u7684 Agent \u548C\u6A21\u578B\u2026",
|
|
26767
27136
|
"catalog.loaded": "\u5DF2\u4ECE\u672C\u673A OpenCode \u8BFB\u53D6 {agents} \u4E2A Agent\u3001{models} \u4E2A\u6A21\u578B\u3002",
|
|
@@ -26792,6 +27161,7 @@ var init_ui = __esm({
|
|
|
26792
27161
|
"details.copySuccess": "\u539F\u59CB\u6570\u636E\u5DF2\u590D\u5236",
|
|
26793
27162
|
"details.id": "\u7F16\u53F7",
|
|
26794
27163
|
"details.project": "\u9879\u76EE\u76EE\u5F55",
|
|
27164
|
+
"details.variant": "\u6A21\u578B Variant",
|
|
26795
27165
|
"details.prompt": "\u63D0\u793A\u8BCD",
|
|
26796
27166
|
"details.result": "\u6267\u884C\u7ED3\u679C / \u5931\u8D25\u539F\u56E0",
|
|
26797
27167
|
"details.category": "\u5206\u7C7B",
|
|
@@ -26824,7 +27194,7 @@ var init_ui = __esm({
|
|
|
26824
27194
|
"details.enabledYes": "\u5DF2\u542F\u7528",
|
|
26825
27195
|
"details.enabledNo": "\u5DF2\u505C\u7528",
|
|
26826
27196
|
"dialog.cancelTask": "\u53D6\u6D88\u4EFB\u52A1 #{id}\uFF1F",
|
|
26827
|
-
"dialog.cancelTaskBody": "\u8FD0\u884C\u4E2D\u7684\u4EFB\u52A1\u4F1A\u5728\u4E0B\u4E00\u4E2A\u8F6E\u8BE2\u5468\u671F\u7EC8\u6B62\u5BF9\u5E94\u8FDB\u7A0B\
|
|
27197
|
+
"dialog.cancelTaskBody": "\u8FD0\u884C\u4E2D\u7684\u4EFB\u52A1\u4F1A\u5728\u4E0B\u4E00\u4E2A\u8F6E\u8BE2\u5468\u671F\u7EC8\u6B62\u5BF9\u5E94\u7684\u53D7\u7BA1\u8FDB\u7A0B\u7EC4\u3002",
|
|
26828
27198
|
"dialog.retryTask": "\u91CD\u8BD5\u4EFB\u52A1 #{id}\uFF1F",
|
|
26829
27199
|
"dialog.retryTaskBody": "\u4EFB\u52A1\u5C06\u56DE\u5230\u5F85\u6267\u884C\u72B6\u6001\uFF0C\u5E76\u91CD\u7F6E\u81EA\u52A8\u91CD\u8BD5\u9884\u7B97\u3002",
|
|
26830
27200
|
"dialog.deleteTask": "\u5220\u9664\u4EFB\u52A1 #{id}\uFF1F",
|
|
@@ -27023,6 +27393,7 @@ var init_ui = __esm({
|
|
|
27023
27393
|
"template.cwdHint": "OpenCode runs the task in this directory.",
|
|
27024
27394
|
"template.agent": "Agent",
|
|
27025
27395
|
"template.model": "Model",
|
|
27396
|
+
"template.variant": "Model variant",
|
|
27026
27397
|
"template.prompt": "Prompt",
|
|
27027
27398
|
"template.scheduleType": "Schedule",
|
|
27028
27399
|
"template.cronExpr": "Cron expression",
|
|
@@ -27060,9 +27431,11 @@ var init_ui = __esm({
|
|
|
27060
27431
|
"catalog.chooseProject": "Choose a project directory first",
|
|
27061
27432
|
"catalog.defaultModel": "Use the Agent / OpenCode default model",
|
|
27062
27433
|
"catalog.defaultProvider": "Default model",
|
|
27434
|
+
"catalog.defaultVariant": "Use the Agent / model default",
|
|
27063
27435
|
"catalog.provider": "Model provider",
|
|
27064
27436
|
"catalog.model": "Model",
|
|
27065
|
-
"catalog.modelHint": "Choose a provider, then a model returned by opencode models for this project. Default does not pass -m.",
|
|
27437
|
+
"catalog.modelHint": "Choose a provider, then a model returned by opencode models --verbose for this project. Default does not pass -m.",
|
|
27438
|
+
"catalog.variantHint": "Only variants declared by the selected model are shown. Default does not pass --variant.",
|
|
27066
27439
|
"catalog.agentHint": "Loaded from opencode agent list for this project.",
|
|
27067
27440
|
"catalog.loading": "Loading Agents and models available to this project\u2026",
|
|
27068
27441
|
"catalog.loaded": "Loaded {agents} Agents and {models} models from local OpenCode.",
|
|
@@ -27093,6 +27466,7 @@ var init_ui = __esm({
|
|
|
27093
27466
|
"details.copySuccess": "Raw data copied",
|
|
27094
27467
|
"details.id": "ID",
|
|
27095
27468
|
"details.project": "Project directory",
|
|
27469
|
+
"details.variant": "Model variant",
|
|
27096
27470
|
"details.prompt": "Prompt",
|
|
27097
27471
|
"details.result": "Result / failure reason",
|
|
27098
27472
|
"details.category": "Category",
|
|
@@ -27125,7 +27499,7 @@ var init_ui = __esm({
|
|
|
27125
27499
|
"details.enabledYes": "Enabled",
|
|
27126
27500
|
"details.enabledNo": "Disabled",
|
|
27127
27501
|
"dialog.cancelTask": "Cancel task #{id}?",
|
|
27128
|
-
"dialog.cancelTaskBody": "A running task will terminate its process
|
|
27502
|
+
"dialog.cancelTaskBody": "A running task will terminate its managed process group on the next worker poll.",
|
|
27129
27503
|
"dialog.retryTask": "Retry task #{id}?",
|
|
27130
27504
|
"dialog.retryTaskBody": "The task returns to pending and its automatic retry budget is reset.",
|
|
27131
27505
|
"dialog.deleteTask": "Delete task #{id}?",
|
|
@@ -27546,7 +27920,7 @@ __export(web_exports, {
|
|
|
27546
27920
|
setDashboardRuntimeConfig: () => setDashboardRuntimeConfig
|
|
27547
27921
|
});
|
|
27548
27922
|
import {
|
|
27549
|
-
existsSync as
|
|
27923
|
+
existsSync as existsSync9,
|
|
27550
27924
|
mkdirSync as mkdirSync5,
|
|
27551
27925
|
readFileSync as readFileSync5,
|
|
27552
27926
|
readdirSync as readdirSync2,
|
|
@@ -27555,7 +27929,7 @@ import {
|
|
|
27555
27929
|
writeFileSync as writeFileSync3
|
|
27556
27930
|
} from "fs";
|
|
27557
27931
|
import { homedir as homedir5 } from "os";
|
|
27558
|
-
import { basename as basename3, dirname as
|
|
27932
|
+
import { basename as basename3, dirname as dirname10, join as join8 } from "path";
|
|
27559
27933
|
function setDashboardRuntimeConfig(config) {
|
|
27560
27934
|
runtimeConfig = config === null ? null : structuredClone(config);
|
|
27561
27935
|
}
|
|
@@ -27580,10 +27954,13 @@ function resolveDashboardConfigState(runtimeAvailable, restartRequired, managedR
|
|
|
27580
27954
|
function isSafeDashboardRestartTarget(diagnostic, currentPid) {
|
|
27581
27955
|
return diagnostic.pm2Installed && diagnostic.processFound && diagnostic.status === "online" && diagnostic.pid === currentPid && diagnostic.ready && diagnostic.scopeMatches;
|
|
27582
27956
|
}
|
|
27583
|
-
function canRestartCurrentGateway() {
|
|
27957
|
+
async function canRestartCurrentGateway(fresh = false) {
|
|
27584
27958
|
if (runtimeConfig === null) return false;
|
|
27585
27959
|
try {
|
|
27586
|
-
return isSafeDashboardRestartTarget(
|
|
27960
|
+
return isSafeDashboardRestartTarget(
|
|
27961
|
+
await getDashboardGatewayDiagnostic({ fresh }),
|
|
27962
|
+
process.pid
|
|
27963
|
+
);
|
|
27587
27964
|
} catch {
|
|
27588
27965
|
return false;
|
|
27589
27966
|
}
|
|
@@ -27598,7 +27975,7 @@ function parseTaskStatus2(value) {
|
|
|
27598
27975
|
}
|
|
27599
27976
|
function listChildDirectories(path) {
|
|
27600
27977
|
return readdirSync2(path, { withFileTypes: true }).flatMap((entry) => {
|
|
27601
|
-
const entryPath =
|
|
27978
|
+
const entryPath = join8(path, entry.name);
|
|
27602
27979
|
if (entry.isDirectory()) return [{ name: entry.name, path: entryPath, hidden: entry.name.startsWith(".") }];
|
|
27603
27980
|
if (!entry.isSymbolicLink()) return [];
|
|
27604
27981
|
try {
|
|
@@ -27655,6 +28032,7 @@ function parseTaskPayload(value) {
|
|
|
27655
28032
|
cwd: requiredString("cwd"),
|
|
27656
28033
|
agent: requiredString("agent"),
|
|
27657
28034
|
model: optionalString("model", "default"),
|
|
28035
|
+
variant: Object.hasOwn(input, "variant") ? optionalString("variant") : void 0,
|
|
27658
28036
|
prompt: requiredString("prompt"),
|
|
27659
28037
|
category: optionalString("category", "general"),
|
|
27660
28038
|
batchId: optionalString("batchId"),
|
|
@@ -27670,6 +28048,7 @@ function editableTaskPayload(input) {
|
|
|
27670
28048
|
name: input.name,
|
|
27671
28049
|
agent: input.agent,
|
|
27672
28050
|
model: input.model ?? "default",
|
|
28051
|
+
...input.variant === void 0 ? {} : { variant: input.variant },
|
|
27673
28052
|
prompt: input.prompt,
|
|
27674
28053
|
category: input.category ?? "general",
|
|
27675
28054
|
batchId: input.batchId ?? null,
|
|
@@ -27725,6 +28104,7 @@ function parseTemplatePayload(value) {
|
|
|
27725
28104
|
name: requiredString("name"),
|
|
27726
28105
|
agent: requiredString("agent"),
|
|
27727
28106
|
model: optionalString("model", "default"),
|
|
28107
|
+
variant: Object.hasOwn(input, "variant") ? optionalString("variant") : void 0,
|
|
27728
28108
|
prompt: requiredString("prompt"),
|
|
27729
28109
|
cwd: requiredString("cwd"),
|
|
27730
28110
|
category: optionalString("category", "general"),
|
|
@@ -27835,7 +28215,7 @@ function esc(value) {
|
|
|
27835
28215
|
}
|
|
27836
28216
|
function readCurrentConfig() {
|
|
27837
28217
|
const configPath = getConfigPath();
|
|
27838
|
-
if (!
|
|
28218
|
+
if (!existsSync9(configPath)) return {};
|
|
27839
28219
|
try {
|
|
27840
28220
|
return JSON.parse(readFileSync5(configPath, "utf-8"));
|
|
27841
28221
|
} catch {
|
|
@@ -27844,8 +28224,8 @@ function readCurrentConfig() {
|
|
|
27844
28224
|
}
|
|
27845
28225
|
function writeConfig(cfg) {
|
|
27846
28226
|
const configPath = getConfigPath();
|
|
27847
|
-
const dir =
|
|
27848
|
-
if (!
|
|
28227
|
+
const dir = dirname10(configPath);
|
|
28228
|
+
if (!existsSync9(dir)) mkdirSync5(dir, { recursive: true });
|
|
27849
28229
|
const tempPath = `${configPath}.${process.pid}.tmp`;
|
|
27850
28230
|
writeFileSync3(tempPath, JSON.stringify(cfg, null, 2) + "\n", { mode: 384 });
|
|
27851
28231
|
renameSync2(tempPath, configPath);
|
|
@@ -27899,7 +28279,7 @@ function pagination(locale, basePath, page, pages, total, suffix = "") {
|
|
|
27899
28279
|
const next = page < pages ? `<a class="btn" href="${basePath}?page=${page + 1}${suffix}">${t(locale, "pagination.next")}${icon("chevronRight")}</a>` : "";
|
|
27900
28280
|
return `<div class="pagination">${previous}<span class="summary">${t(locale, "pagination.summary", { page, pages, total })}</span>${next}</div>`;
|
|
27901
28281
|
}
|
|
27902
|
-
var app, LEGACY_PROJECT_FILTER, TASK_STATUSES2, SESSION_ID_PATTERN, runtimeConfig, restartScheduled, dashboardApp, web_default;
|
|
28282
|
+
var app, LEGACY_PROJECT_FILTER, TASK_STATUSES2, SESSION_ID_PATTERN, LOOPBACK_HOST_PATTERN, runtimeConfig, restartScheduled, dashboardApp, web_default;
|
|
27903
28283
|
var init_web = __esm({
|
|
27904
28284
|
"src/web/index.tsx"() {
|
|
27905
28285
|
"use strict";
|
|
@@ -27916,7 +28296,7 @@ var init_web = __esm({
|
|
|
27916
28296
|
init_config();
|
|
27917
28297
|
init_health();
|
|
27918
28298
|
init_job_templates();
|
|
27919
|
-
|
|
28299
|
+
init_gateway_diagnostic();
|
|
27920
28300
|
init_ui();
|
|
27921
28301
|
app = new Hono2();
|
|
27922
28302
|
LEGACY_PROJECT_FILTER = "__supertask_legacy__";
|
|
@@ -27929,9 +28309,18 @@ var init_web = __esm({
|
|
|
27929
28309
|
"cancelled"
|
|
27930
28310
|
]);
|
|
27931
28311
|
SESSION_ID_PATTERN = /^ses_[A-Za-z0-9_]+$/;
|
|
28312
|
+
LOOPBACK_HOST_PATTERN = /^(?:localhost|127\.0\.0\.1|\[::1\])(?::([1-9]\d{0,4}))?$/i;
|
|
27932
28313
|
runtimeConfig = null;
|
|
27933
28314
|
restartScheduled = false;
|
|
27934
28315
|
app.use("*", async (c, next) => {
|
|
28316
|
+
const requestHostname = new URL(c.req.url).hostname;
|
|
28317
|
+
const hostHeader = c.req.header("Host");
|
|
28318
|
+
const loopbackHosts = ["localhost", "127.0.0.1", "[::1]"];
|
|
28319
|
+
const hostMatch = hostHeader?.match(LOOPBACK_HOST_PATTERN) ?? null;
|
|
28320
|
+
const hostPort = hostMatch?.[1] === void 0 ? null : Number(hostMatch[1]);
|
|
28321
|
+
if (!loopbackHosts.includes(requestHostname) || hostHeader !== void 0 && (!hostMatch || hostPort !== null && hostPort > 65535)) {
|
|
28322
|
+
return c.json({ error: "invalid dashboard host" }, 421);
|
|
28323
|
+
}
|
|
27935
28324
|
await next();
|
|
27936
28325
|
c.header("X-Content-Type-Options", "nosniff");
|
|
27937
28326
|
c.header("X-Frame-Options", "DENY");
|
|
@@ -27968,7 +28357,7 @@ var init_web = __esm({
|
|
|
27968
28357
|
validateTaskWorkingDirectory(requestedPath);
|
|
27969
28358
|
return c.json({
|
|
27970
28359
|
path: requestedPath,
|
|
27971
|
-
parent:
|
|
28360
|
+
parent: dirname10(requestedPath),
|
|
27972
28361
|
home: homedir5(),
|
|
27973
28362
|
directories: listChildDirectories(requestedPath)
|
|
27974
28363
|
});
|
|
@@ -28058,7 +28447,7 @@ var init_web = __esm({
|
|
|
28058
28447
|
const latestRun = latestRuns.get(task.id);
|
|
28059
28448
|
const executionActive = latestRun?.status === "running";
|
|
28060
28449
|
const batchId = task.batchId?.trim() || null;
|
|
28061
|
-
const searchable = esc(`${task.name} ${task.agent} ${task.prompt} ${task.cwd ?? ""} ${task.batchId ?? ""} ${task.category ?? ""}`);
|
|
28450
|
+
const searchable = esc(`${task.name} ${task.agent} ${task.model ?? ""} ${task.variant ?? ""} ${task.prompt} ${task.cwd ?? ""} ${task.batchId ?? ""} ${task.category ?? ""}`);
|
|
28062
28451
|
return `<tr data-task-row data-search="${searchable}">
|
|
28063
28452
|
<td class="faint" data-label="${t(locale, "table.id")}">#${task.id}</td>
|
|
28064
28453
|
<td data-primary data-label="${t(locale, "table.task")}"><div class="task-name">${esc(task.name)}</div><div class="task-prompt" title="${esc(task.prompt)}">${esc(task.prompt.substring(0, 160))}</div>
|
|
@@ -28136,11 +28525,12 @@ var init_web = __esm({
|
|
|
28136
28525
|
<label class="form-field"><span>${t(locale, "template.cwd")}</span><div class="field-action"><input id="task-cwd" required autocomplete="off" list="task-cwd-options" placeholder="/path/to/project" oninput="updateTaskProjectStatus();scheduleCatalogLoad('task')"><button id="task-cwd-picker" type="button" class="btn" onclick="openDirectoryPicker('task-cwd')">${icon("folder")}${t(locale, "action.chooseFolder")}</button></div><small>${t(locale, "template.cwdHint")}</small></label>
|
|
28137
28526
|
<datalist id="task-cwd-options">${projects.map((project) => `<option value="${esc(project.cwd)}"></option>`).join("")}</datalist>
|
|
28138
28527
|
<label class="form-field"><span>${t(locale, "template.agent")}</span><select id="task-agent" required><option value="">${t(locale, "catalog.chooseProject")}</option></select><small>${t(locale, "catalog.agentHint")}</small></label>
|
|
28139
|
-
<label class="form-field"><span>${t(locale, "template.model")}</span><div class="model-selector"><select id="task-model-provider" aria-label="${t(locale, "catalog.provider")}" onchange="
|
|
28528
|
+
<label class="form-field"><span>${t(locale, "template.model")}</span><div class="model-selector"><select id="task-model-provider" aria-label="${t(locale, "catalog.provider")}" onchange="handleProviderChange('task')"><option value="">${t(locale, "catalog.defaultProvider")}</option></select><select id="task-model" required aria-label="${t(locale, "catalog.model")}" onchange="handleModelChange('task')" disabled><option value="default">${t(locale, "catalog.defaultModel")}</option></select></div><small>${t(locale, "catalog.modelHint")}</small></label>
|
|
28529
|
+
<label class="form-field"><span>${t(locale, "template.variant")}</span><select id="task-variant" onchange="handleVariantChange('task')" disabled><option value="">${t(locale, "catalog.defaultVariant")}</option></select><small>${t(locale, "catalog.variantHint")}</small></label>
|
|
28140
28530
|
<label class="form-field form-field-wide"><span>${t(locale, "template.prompt")}</span><textarea id="task-prompt" rows="6" required></textarea></label>
|
|
28141
28531
|
</div>
|
|
28142
28532
|
<p id="task-project-status" class="form-note"></p>
|
|
28143
|
-
<p id="task-catalog-status" class="form-note catalog-status"></p>
|
|
28533
|
+
<p id="task-catalog-status" class="form-note catalog-status" role="status" aria-live="polite"></p>
|
|
28144
28534
|
<details class="advanced-fields">
|
|
28145
28535
|
<summary>${t(locale, "template.advanced")}</summary>
|
|
28146
28536
|
<div class="template-form-grid">
|
|
@@ -28182,7 +28572,7 @@ var init_web = __esm({
|
|
|
28182
28572
|
return `<tr>
|
|
28183
28573
|
<td class="faint" data-label="${t(locale, "table.id")}">#${template.id}</td>
|
|
28184
28574
|
<td data-primary data-label="${t(locale, "table.name")}"><div class="task-name">${esc(template.name)}</div><div class="task-prompt" title="${esc(template.prompt)}">${esc(template.prompt.substring(0, 140))}</div>
|
|
28185
|
-
<div class="actions" style="margin-top:5px"><span class="tag">${esc(template.agent)}</span>${template.model && template.model !== "default" ? `<span class="tag">${esc(template.model)}</span>` : ""}</div></td>
|
|
28575
|
+
<div class="actions" style="margin-top:5px"><span class="tag">${esc(template.agent)}</span>${template.model && template.model !== "default" ? `<span class="tag">${esc(template.model)}</span>` : ""}${template.variant ? `<span class="tag">${esc(template.variant)}</span>` : ""}</div></td>
|
|
28186
28576
|
<td data-label="${t(locale, "table.type")}"><span class="tag t-${scheduleType}">${typeLabel}</span></td>
|
|
28187
28577
|
<td data-label="${t(locale, "table.rule")}" class="m small">${esc(rule)}</td>
|
|
28188
28578
|
<td data-label="${t(locale, "table.status")}"><span class="badge ${template.enabled ? "b-done" : "b-cancelled"}">${t(locale, template.enabled ? "schedule.enabled" : "schedule.disabled")}</span></td>
|
|
@@ -28212,14 +28602,15 @@ var init_web = __esm({
|
|
|
28212
28602
|
<label class="form-field"><span>${t(locale, "template.name")}</span><input id="template-name" required maxlength="200" autocomplete="off"></label>
|
|
28213
28603
|
<label class="form-field"><span>${t(locale, "template.cwd")}</span><div class="field-action"><input id="template-cwd" required autocomplete="off" placeholder="/path/to/project" oninput="scheduleCatalogLoad('template')"><button type="button" class="btn" onclick="openDirectoryPicker('template-cwd')">${icon("folder")}${t(locale, "action.chooseFolder")}</button></div><small>${t(locale, "template.cwdHint")}</small></label>
|
|
28214
28604
|
<label class="form-field"><span>${t(locale, "template.agent")}</span><select id="template-agent" required><option value="">${t(locale, "catalog.chooseProject")}</option></select><small>${t(locale, "catalog.agentHint")}</small></label>
|
|
28215
|
-
<label class="form-field"><span>${t(locale, "template.model")}</span><div class="model-selector"><select id="template-model-provider" aria-label="${t(locale, "catalog.provider")}" onchange="
|
|
28605
|
+
<label class="form-field"><span>${t(locale, "template.model")}</span><div class="model-selector"><select id="template-model-provider" aria-label="${t(locale, "catalog.provider")}" onchange="handleProviderChange('template')"><option value="">${t(locale, "catalog.defaultProvider")}</option></select><select id="template-model" required aria-label="${t(locale, "catalog.model")}" onchange="handleModelChange('template')" disabled><option value="default">${t(locale, "catalog.defaultModel")}</option></select></div><small>${t(locale, "catalog.modelHint")}</small></label>
|
|
28606
|
+
<label class="form-field"><span>${t(locale, "template.variant")}</span><select id="template-variant" onchange="handleVariantChange('template')" disabled><option value="">${t(locale, "catalog.defaultVariant")}</option></select><small>${t(locale, "catalog.variantHint")}</small></label>
|
|
28216
28607
|
<label class="form-field form-field-wide"><span>${t(locale, "template.prompt")}</span><textarea id="template-prompt" rows="6" required></textarea></label>
|
|
28217
28608
|
<label class="form-field"><span>${t(locale, "template.scheduleType")}</span><select id="template-schedule-type" onchange="updateTemplateScheduleFields()"><option value="recurring">${t(locale, "schedule.recurring")}</option><option value="delayed">${t(locale, "schedule.delayed")}</option><option value="cron">${t(locale, "schedule.cron")}</option></select></label>
|
|
28218
28609
|
<label id="template-cron-field" class="form-field" hidden><span>${t(locale, "template.cronExpr")}</span><input id="template-cron" autocomplete="off" placeholder="0 9 * * *"><small>${t(locale, "template.cronHint")}</small></label>
|
|
28219
28610
|
<label id="template-interval-field" class="form-field"><span>${t(locale, "template.interval")}</span>${durationControl(locale, "template-interval", 36e5, "interval")}<small>${t(locale, "template.intervalHint")}</small></label>
|
|
28220
28611
|
<label id="template-run-at-field" class="form-field" hidden><span>${t(locale, "template.runAt")}</span><input id="template-run-at" type="datetime-local" step="0.001"></label>
|
|
28221
28612
|
</div>
|
|
28222
|
-
<p id="template-catalog-status" class="form-note catalog-status"></p>
|
|
28613
|
+
<p id="template-catalog-status" class="form-note catalog-status" role="status" aria-live="polite"></p>
|
|
28223
28614
|
<details class="advanced-fields">
|
|
28224
28615
|
<summary>${t(locale, "template.advanced")}</summary>
|
|
28225
28616
|
<div class="template-form-grid">
|
|
@@ -28253,6 +28644,7 @@ var init_web = __esm({
|
|
|
28253
28644
|
taskId: taskRuns4.taskId,
|
|
28254
28645
|
sessionId: taskRuns4.sessionId,
|
|
28255
28646
|
model: taskRuns4.model,
|
|
28647
|
+
variant: taskRuns4.variant,
|
|
28256
28648
|
status: taskRuns4.status,
|
|
28257
28649
|
startedAt: taskRuns4.startedAt,
|
|
28258
28650
|
finishedAt: taskRuns4.finishedAt,
|
|
@@ -28273,7 +28665,7 @@ var init_web = __esm({
|
|
|
28273
28665
|
const log = run.log ? renderRunLog(run.id, run.taskName, run.log, locale, run.status !== "done") : "";
|
|
28274
28666
|
return `<tr class="run-summary-row">
|
|
28275
28667
|
<td class="faint" data-label="${t(locale, "table.run")}">#${run.id}</td>
|
|
28276
|
-
<td data-primary data-label="${t(locale, "table.task")}"><div class="task-name">${esc(run.taskName)} <span class="faint">#${run.taskId}</span></div>${run.model ? `<div style="margin-top:4px"
|
|
28668
|
+
<td data-primary data-label="${t(locale, "table.task")}"><div class="task-name">${esc(run.taskName)} <span class="faint">#${run.taskId}</span></div>${run.model || run.variant ? `<div class="actions" style="margin-top:4px">${run.model ? `<span class="tag">${esc(run.model)}</span>` : ""}${run.variant ? `<span class="tag">${esc(run.variant)}</span>` : ""}</div>` : ""}</td>
|
|
28277
28669
|
<td data-label="${t(locale, "table.agent")}"><span class="tag">${esc(run.taskAgent)}</span></td>
|
|
28278
28670
|
<td data-label="${t(locale, "table.session")}" class="m small">${esc(maskSessionId(run.sessionId))}</td>
|
|
28279
28671
|
<td data-label="${t(locale, "table.status")}"><span class="badge b-${status}">${runStatusText(locale, run.status ?? "unknown")}</span></td>
|
|
@@ -28300,7 +28692,7 @@ var init_web = __esm({
|
|
|
28300
28692
|
const config = loadConfig();
|
|
28301
28693
|
const activeConfig = runtimeConfig ?? config;
|
|
28302
28694
|
const restartRequired = runtimeConfig !== null && !configsEqual(config, runtimeConfig);
|
|
28303
|
-
const managedRestart = canRestartCurrentGateway();
|
|
28695
|
+
const managedRestart = await canRestartCurrentGateway();
|
|
28304
28696
|
const configState = resolveDashboardConfigState(
|
|
28305
28697
|
runtimeConfig !== null,
|
|
28306
28698
|
restartRequired,
|
|
@@ -28319,11 +28711,11 @@ var init_web = __esm({
|
|
|
28319
28711
|
TaskRunService.getAllRunningRuns(),
|
|
28320
28712
|
TaskTemplateService.stats()
|
|
28321
28713
|
]);
|
|
28322
|
-
const configExists =
|
|
28714
|
+
const configExists = existsSync9(configPath);
|
|
28323
28715
|
const runRows = runningRuns.map((run) => {
|
|
28324
28716
|
const session = maskSessionId(run.sessionId);
|
|
28325
28717
|
return `<tr><td class="faint" data-label="${t(locale, "table.run")}">#${run.id}</td><td data-primary data-label="${t(locale, "table.task")}">#${run.taskId}</td><td data-label="${t(locale, "table.session")}" class="m small">${esc(session)}</td>
|
|
28326
|
-
<td data-label="${t(locale, "table.model")}" class="small">${esc(run.model) || "\u2014"}</td><td data-label="${t(locale, "table.startedAt")}" class="small">${formatDateTime(run.startedAt, locale)}</td>
|
|
28718
|
+
<td data-label="${t(locale, "table.model")}" class="small">${esc(run.model) || "\u2014"}${run.variant ? ` \xB7 ${esc(run.variant)}` : ""}</td><td data-label="${t(locale, "table.startedAt")}" class="small">${formatDateTime(run.startedAt, locale)}</td>
|
|
28327
28719
|
<td data-label="${t(locale, "table.heartbeat")}" class="small muted">${formatRelative(run.heartbeatAt, locale)}</td><td data-label="${t(locale, "table.pid")}" class="m small">W:${run.workerPid ?? "\u2014"} C:${run.childPid ?? "\u2014"}</td>
|
|
28328
28720
|
<td data-label="${t(locale, "table.duration")}" class="small">${formatDuration(run.startedAt, null)}</td></tr>`;
|
|
28329
28721
|
}).join("");
|
|
@@ -28420,9 +28812,9 @@ var init_web = __esm({
|
|
|
28420
28812
|
if (!isValidSessionId(run.sessionId)) return c.json({ error: "session unavailable" }, 409);
|
|
28421
28813
|
return c.json({ command: sessionCommand(run.sessionId) });
|
|
28422
28814
|
});
|
|
28423
|
-
app.get("/api/gateway/status", (c) => {
|
|
28815
|
+
app.get("/api/gateway/status", async (c) => {
|
|
28424
28816
|
const savedConfig = loadConfig();
|
|
28425
|
-
const managed = canRestartCurrentGateway();
|
|
28817
|
+
const managed = await canRestartCurrentGateway();
|
|
28426
28818
|
return c.json({
|
|
28427
28819
|
pid: process.pid,
|
|
28428
28820
|
managed,
|
|
@@ -28547,7 +28939,7 @@ var init_web = __esm({
|
|
|
28547
28939
|
return c.json({
|
|
28548
28940
|
success: true,
|
|
28549
28941
|
restartRequired: runtimeConfig === null || !configsEqual(savedConfig, runtimeConfig),
|
|
28550
|
-
managed: canRestartCurrentGateway()
|
|
28942
|
+
managed: await canRestartCurrentGateway()
|
|
28551
28943
|
});
|
|
28552
28944
|
} catch (error) {
|
|
28553
28945
|
return c.json({
|
|
@@ -28563,9 +28955,10 @@ var init_web = __esm({
|
|
|
28563
28955
|
return c.json({ error: "confirmation must be RESTART" }, 400);
|
|
28564
28956
|
}
|
|
28565
28957
|
if (restartScheduled) return c.json({ error: "restart already scheduled" }, 409);
|
|
28566
|
-
if (!canRestartCurrentGateway()) {
|
|
28958
|
+
if (!await canRestartCurrentGateway(true)) {
|
|
28567
28959
|
return c.json({ error: "\u5F53\u524D Gateway \u4E0D\u662F\u7531\u5339\u914D\u8FD0\u884C\u4F5C\u7528\u57DF\u7684 PM2 \u8FDB\u7A0B\u6258\u7BA1\uFF0C\u65E0\u6CD5\u4ECE\u7F51\u9875\u5B89\u5168\u91CD\u542F" }, 409);
|
|
28568
28960
|
}
|
|
28961
|
+
if (restartScheduled) return c.json({ error: "restart already scheduled" }, 409);
|
|
28569
28962
|
restartScheduled = true;
|
|
28570
28963
|
const previousPid = process.pid;
|
|
28571
28964
|
setTimeout(() => {
|
|
@@ -29152,11 +29545,13 @@ async function runDoctorSmoke(options) {
|
|
|
29152
29545
|
const cwd = resolve5(options.cwd);
|
|
29153
29546
|
const marker = options.marker ?? `SUPERTASK_SMOKE_${randomUUID2().replaceAll("-", "").toUpperCase()}`;
|
|
29154
29547
|
const model = options.model && options.model !== "default" ? options.model : void 0;
|
|
29548
|
+
const variant = options.variant?.trim() || void 0;
|
|
29155
29549
|
const startedAt = Date.now();
|
|
29156
29550
|
const task = await TaskService.add({
|
|
29157
29551
|
name: "[doctor] Gateway real smoke test",
|
|
29158
29552
|
agent: options.agent,
|
|
29159
29553
|
model,
|
|
29554
|
+
variant,
|
|
29160
29555
|
prompt: `\u4E0D\u8981\u8C03\u7528\u4EFB\u4F55\u5DE5\u5177\u3002\u53EA\u56DE\u590D\u8FD9\u4E00\u884C\uFF1A${marker}`,
|
|
29161
29556
|
cwd,
|
|
29162
29557
|
category: "diagnostic",
|
|
@@ -29180,6 +29575,7 @@ async function runDoctorSmoke(options) {
|
|
|
29180
29575
|
status: "missing",
|
|
29181
29576
|
agent: options.agent,
|
|
29182
29577
|
model: model ?? null,
|
|
29578
|
+
variant: variant ?? null,
|
|
29183
29579
|
cwd,
|
|
29184
29580
|
durationMs: Date.now() - startedAt,
|
|
29185
29581
|
error: "\u5192\u70DF\u4EFB\u52A1\u5728\u5B8C\u6210\u524D\u88AB\u5220\u9664"
|
|
@@ -29195,6 +29591,7 @@ async function runDoctorSmoke(options) {
|
|
|
29195
29591
|
status: current2.status,
|
|
29196
29592
|
agent: options.agent,
|
|
29197
29593
|
model: model ?? null,
|
|
29594
|
+
variant: variant ?? null,
|
|
29198
29595
|
cwd,
|
|
29199
29596
|
durationMs: Date.now() - startedAt,
|
|
29200
29597
|
error: markerObserved ? null : "OpenCode \u5DF2\u9000\u51FA\u6210\u529F\uFF0C\u4F46\u6A21\u578B\u6587\u672C\u4E0D\u662F\u9884\u671F\u7684\u7CBE\u786E\u6807\u8BB0"
|
|
@@ -29208,6 +29605,7 @@ async function runDoctorSmoke(options) {
|
|
|
29208
29605
|
status: current2.status,
|
|
29209
29606
|
agent: options.agent,
|
|
29210
29607
|
model: model ?? null,
|
|
29608
|
+
variant: variant ?? null,
|
|
29211
29609
|
cwd,
|
|
29212
29610
|
durationMs: Date.now() - startedAt,
|
|
29213
29611
|
error: tail(run2?.log ?? current2.resultLog) ?? `\u4EFB\u52A1\u8FDB\u5165 ${current2.status}`
|
|
@@ -29225,6 +29623,7 @@ async function runDoctorSmoke(options) {
|
|
|
29225
29623
|
status: current?.status ?? "missing",
|
|
29226
29624
|
agent: options.agent,
|
|
29227
29625
|
model: model ?? null,
|
|
29626
|
+
variant: variant ?? null,
|
|
29228
29627
|
cwd,
|
|
29229
29628
|
durationMs: Date.now() - startedAt,
|
|
29230
29629
|
error: `\u7B49\u5F85 Gateway \u6267\u884C\u8D85\u8FC7 ${options.timeoutMs}ms\uFF0C\u5192\u70DF\u4EFB\u52A1\u5DF2\u8BF7\u6C42\u53D6\u6D88`
|
|
@@ -29265,7 +29664,7 @@ if (cliLocale === "zh-CN") {
|
|
|
29265
29664
|
writeOut: (value) => process.stdout.write(value.replace(/^Usage:/gm, "\u7528\u6CD5\uFF1A").replace(/^Options:/gm, "\u9009\u9879\uFF1A").replace(/^Commands:/gm, "\u547D\u4EE4\uFF1A").replace(/^Arguments:/gm, "\u53C2\u6570\uFF1A"))
|
|
29266
29665
|
});
|
|
29267
29666
|
}
|
|
29268
|
-
program2.command("add").description(t2("\u521B\u5EFA\u65B0\u4EFB\u52A1", "create a queued task")).requiredOption("-n, --name <name>", t2("\u4EFB\u52A1\u540D\u79F0", "task name")).requiredOption("-a, --agent <agent>", t2("\u4E3B Agent \u540D\u79F0", "primary agent name")).requiredOption("-p, --prompt <prompt>", t2("\u63D0\u793A\u8BCD", "prompt")).option("-m, --model <model>", t2("\u6A21\u578B", "model")).option("-c, --category <category>", t2("\u5206\u7C7B", "category"), "general").option("-i, --importance <number>", t2("\u91CD\u8981\u7A0B\u5EA6 (1-5)", "importance (1-5)"), "3").option("-u, --urgency <number>", t2("\u7D27\u6025\u7A0B\u5EA6 (1-5)", "urgency (1-5)"), "3").option("-b, --batch <batchId>", t2("\u6279\u6B21 ID", "batch ID")).option("-d, --depends <taskId>", t2("\u4F9D\u8D56\u7684\u4EFB\u52A1 ID", "dependency task ID")).option("--max-retries <number>", t2("\u9996\u6B21\u6267\u884C\u4E4B\u5916\u5141\u8BB8\u7684\u91CD\u8BD5\u6B21\u6570", "retries allowed after the first attempt"), "3").option("--retry-backoff <duration>", t2("\u91CD\u8BD5\u9000\u907F\u57FA\u7840\u95F4\u9694\uFF0C\u5982 30s / 5min", "retry backoff base, e.g. 30s / 5min"), "30s").option("--timeout <duration>", t2("\u4EFB\u52A1\u786C\u8D85\u65F6\uFF0C\u5982 30min / 2h", "hard timeout, e.g. 30min / 2h")).option("-w, --cwd <path>", t2("(\u5DF2\u5E9F\u5F03) \u7CFB\u7EDF\u4F1A\u81EA\u52A8\u8BB0\u5F55\u63D0\u4EA4\u65F6\u7684\u5F53\u524D\u76EE\u5F55", "(deprecated) the submission directory is recorded automatically")).action(async (options) => withDb(async () => {
|
|
29667
|
+
program2.command("add").description(t2("\u521B\u5EFA\u65B0\u4EFB\u52A1", "create a queued task")).requiredOption("-n, --name <name>", t2("\u4EFB\u52A1\u540D\u79F0", "task name")).requiredOption("-a, --agent <agent>", t2("\u4E3B Agent \u540D\u79F0", "primary agent name")).requiredOption("-p, --prompt <prompt>", t2("\u63D0\u793A\u8BCD", "prompt")).option("-m, --model <model>", t2("\u6A21\u578B", "model")).option("--variant <variant>", t2("\u6A21\u578B variant\uFF0C\u5982 high / xhigh", "model variant, e.g. high / xhigh")).option("-c, --category <category>", t2("\u5206\u7C7B", "category"), "general").option("-i, --importance <number>", t2("\u91CD\u8981\u7A0B\u5EA6 (1-5)", "importance (1-5)"), "3").option("-u, --urgency <number>", t2("\u7D27\u6025\u7A0B\u5EA6 (1-5)", "urgency (1-5)"), "3").option("-b, --batch <batchId>", t2("\u6279\u6B21 ID", "batch ID")).option("-d, --depends <taskId>", t2("\u4F9D\u8D56\u7684\u4EFB\u52A1 ID", "dependency task ID")).option("--max-retries <number>", t2("\u9996\u6B21\u6267\u884C\u4E4B\u5916\u5141\u8BB8\u7684\u91CD\u8BD5\u6B21\u6570", "retries allowed after the first attempt"), "3").option("--retry-backoff <duration>", t2("\u91CD\u8BD5\u9000\u907F\u57FA\u7840\u95F4\u9694\uFF0C\u5982 30s / 5min", "retry backoff base, e.g. 30s / 5min"), "30s").option("--timeout <duration>", t2("\u4EFB\u52A1\u786C\u8D85\u65F6\uFF0C\u5982 30min / 2h", "hard timeout, e.g. 30min / 2h")).option("-w, --cwd <path>", t2("(\u5DF2\u5E9F\u5F03) \u7CFB\u7EDF\u4F1A\u81EA\u52A8\u8BB0\u5F55\u63D0\u4EA4\u65F6\u7684\u5F53\u524D\u76EE\u5F55", "(deprecated) the submission directory is recorded automatically")).action(async (options) => withDb(async () => {
|
|
29269
29668
|
const submitCwd = process.cwd();
|
|
29270
29669
|
const retryBackoffMs = parseDuration(options.retryBackoff);
|
|
29271
29670
|
const timeoutMs = options.timeout ? parseDuration(options.timeout) : null;
|
|
@@ -29277,6 +29676,7 @@ program2.command("add").description(t2("\u521B\u5EFA\u65B0\u4EFB\u52A1", "create
|
|
|
29277
29676
|
agent: options.agent,
|
|
29278
29677
|
prompt: options.prompt,
|
|
29279
29678
|
model: options.model,
|
|
29679
|
+
variant: options.variant,
|
|
29280
29680
|
category: options.category,
|
|
29281
29681
|
importance: parseBoundedInteger(options.importance, "importance", 1, 5),
|
|
29282
29682
|
urgency: parseBoundedInteger(options.urgency, "urgency", 1, 5),
|
|
@@ -29289,17 +29689,23 @@ program2.command("add").description(t2("\u521B\u5EFA\u65B0\u4EFB\u52A1", "create
|
|
|
29289
29689
|
});
|
|
29290
29690
|
console.log(JSON.stringify({ id: task.id, status: "created" }, null, 2));
|
|
29291
29691
|
}));
|
|
29292
|
-
program2.command("edit").description(t2("\u4FEE\u6539\u5F53\u524D\u9879\u76EE\u4E2D\u5C1A\u672A\u5B8C\u6210\u7684\u4EFB\u52A1", "edit an unfinished task in the current project")).requiredOption("--id <id>", t2("\u4EFB\u52A1 ID", "task ID")).option("-n, --name <name>", t2("\u4EFB\u52A1\u540D\u79F0", "task name")).option("-a, --agent <agent>", t2("Agent \u540D\u79F0", "agent name")).option("-m, --model <model>", t2("\u6A21\u578B", "model")).option("-p, --prompt <prompt>", t2("\u63D0\u793A\u8BCD", "prompt")).option("-c, --category <category>", t2("\u5206\u7C7B", "category")).option("-i, --importance <number>", t2("\u91CD\u8981\u7A0B\u5EA6 (1-5)", "importance (1-5)")).option("-u, --urgency <number>", t2("\u7D27\u6025\u7A0B\u5EA6 (1-5)", "urgency (1-5)")).option("-b, --batch <batchId>", t2("\u6279\u6B21 ID", "batch ID")).option("--clear-batch", t2("\u6E05\u7A7A\u6279\u6B21 ID", "clear the batch ID")).option("--max-retries <number>", t2("\u9996\u6B21\u6267\u884C\u4E4B\u5916\u5141\u8BB8\u7684\u91CD\u8BD5\u6B21\u6570", "retries allowed after the first attempt")).option("--retry-backoff <duration>", t2("\u91CD\u8BD5\u9000\u907F\u57FA\u7840\u95F4\u9694\uFF0C\u5982 30s / 5min", "retry backoff base, e.g. 30s / 5min")).option("--timeout <duration>", t2("\u4EFB\u52A1\u786C\u8D85\u65F6\uFF0C\u5982 30min / 2h", "hard timeout, e.g. 30min / 2h")).option("--clear-timeout", t2("\u6E05\u7A7A\u4EFB\u52A1\u7EA7\u8D85\u65F6\uFF0C\u6539\u7528 Gateway \u9ED8\u8BA4\u503C", "clear the task timeout and use the Gateway default")).action(async (options) => withDb(async () => {
|
|
29692
|
+
program2.command("edit").description(t2("\u4FEE\u6539\u5F53\u524D\u9879\u76EE\u4E2D\u5C1A\u672A\u5B8C\u6210\u7684\u4EFB\u52A1", "edit an unfinished task in the current project")).requiredOption("--id <id>", t2("\u4EFB\u52A1 ID", "task ID")).option("-n, --name <name>", t2("\u4EFB\u52A1\u540D\u79F0", "task name")).option("-a, --agent <agent>", t2("Agent \u540D\u79F0", "agent name")).option("-m, --model <model>", t2("\u6A21\u578B", "model")).option("--variant <variant>", t2("\u6A21\u578B variant\uFF0C\u5982 high / xhigh", "model variant, e.g. high / xhigh")).option("--clear-variant", t2("\u6E05\u7A7A\u4EFB\u52A1\u7EA7 variant\uFF0C\u8DDF\u968F Agent / \u6A21\u578B\u9ED8\u8BA4\u503C", "clear the task variant and use the Agent / model default")).option("-p, --prompt <prompt>", t2("\u63D0\u793A\u8BCD", "prompt")).option("-c, --category <category>", t2("\u5206\u7C7B", "category")).option("-i, --importance <number>", t2("\u91CD\u8981\u7A0B\u5EA6 (1-5)", "importance (1-5)")).option("-u, --urgency <number>", t2("\u7D27\u6025\u7A0B\u5EA6 (1-5)", "urgency (1-5)")).option("-b, --batch <batchId>", t2("\u6279\u6B21 ID", "batch ID")).option("--clear-batch", t2("\u6E05\u7A7A\u6279\u6B21 ID", "clear the batch ID")).option("--max-retries <number>", t2("\u9996\u6B21\u6267\u884C\u4E4B\u5916\u5141\u8BB8\u7684\u91CD\u8BD5\u6B21\u6570", "retries allowed after the first attempt")).option("--retry-backoff <duration>", t2("\u91CD\u8BD5\u9000\u907F\u57FA\u7840\u95F4\u9694\uFF0C\u5982 30s / 5min", "retry backoff base, e.g. 30s / 5min")).option("--timeout <duration>", t2("\u4EFB\u52A1\u786C\u8D85\u65F6\uFF0C\u5982 30min / 2h", "hard timeout, e.g. 30min / 2h")).option("--clear-timeout", t2("\u6E05\u7A7A\u4EFB\u52A1\u7EA7\u8D85\u65F6\uFF0C\u6539\u7528 Gateway \u9ED8\u8BA4\u503C", "clear the task timeout and use the Gateway default")).action(async (options) => withDb(async () => {
|
|
29293
29693
|
if (options.batch !== void 0 && options.clearBatch) {
|
|
29294
29694
|
throw new Error("batch \u548C clear-batch \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
|
|
29295
29695
|
}
|
|
29296
29696
|
if (options.timeout !== void 0 && options.clearTimeout) {
|
|
29297
29697
|
throw new Error("timeout \u548C clear-timeout \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
|
|
29298
29698
|
}
|
|
29699
|
+
if (options.variant !== void 0 && options.clearVariant) {
|
|
29700
|
+
throw new Error("variant \u548C clear-variant \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
|
|
29701
|
+
}
|
|
29299
29702
|
const update = {};
|
|
29300
29703
|
for (const field of ["name", "agent", "model", "prompt", "category"]) {
|
|
29301
29704
|
if (options[field] !== void 0) update[field] = options[field];
|
|
29302
29705
|
}
|
|
29706
|
+
if (options.variant !== void 0 || options.clearVariant) {
|
|
29707
|
+
update.variant = options.clearVariant ? null : options.variant;
|
|
29708
|
+
}
|
|
29303
29709
|
if (options.importance !== void 0) {
|
|
29304
29710
|
update.importance = parseBoundedInteger(options.importance, "importance", 1, 5);
|
|
29305
29711
|
}
|
|
@@ -29335,6 +29741,7 @@ program2.command("next").description(t2("\u83B7\u53D6\u4E0B\u4E00\u4E2A\u5F85\u6
|
|
|
29335
29741
|
name: task.name,
|
|
29336
29742
|
agent: task.agent,
|
|
29337
29743
|
model: task.model,
|
|
29744
|
+
variant: task.variant,
|
|
29338
29745
|
prompt: task.prompt,
|
|
29339
29746
|
cwd: task.cwd,
|
|
29340
29747
|
category: task.category,
|
|
@@ -29411,7 +29818,7 @@ program2.command("delete").description(t2("\u5220\u9664\u4EFB\u52A1", "delete a
|
|
|
29411
29818
|
console.log(JSON.stringify({ deleted, id }));
|
|
29412
29819
|
}));
|
|
29413
29820
|
program2.command("template").description(t2("\u7BA1\u7406\u5B9A\u65F6\u4EFB\u52A1\u6A21\u677F", "manage scheduled task templates")).addCommand(
|
|
29414
|
-
new Command("add").description(t2("\u521B\u5EFA\u5B9A\u65F6\u4EFB\u52A1\u6A21\u677F", "create a scheduled task template")).requiredOption("-n, --name <name>", t2("\u6A21\u677F\u540D\u79F0", "template name")).requiredOption("-a, --agent <agent>", t2("Agent \u540D\u79F0", "agent name")).requiredOption("-p, --prompt <prompt>", t2("\u63D0\u793A\u8BCD", "prompt")).requiredOption("-t, --type <type>", t2("\u5B9A\u65F6\u7C7B\u578B\uFF1Acron/delayed/recurring", "schedule type: cron/delayed/recurring")).option("--cron <expr>", t2("cron \u8868\u8FBE\u5F0F\uFF08cron \u7C7B\u578B\u5FC5\u586B\uFF09", "cron expression (required for cron)")).option("--delay <duration>", t2("\u5EF6\u8FDF\u65F6\u95F4\uFF08delayed \u5FC5\u586B\uFF09\uFF0C\u5982 30s / 5min / 1h / 2d", "delay (required for delayed), e.g. 30s / 5min / 1h / 2d")).option("--interval <duration>", t2("\u5FAA\u73AF\u95F4\u9694\uFF08recurring \u5FC5\u586B\uFF09\uFF0C\u5982 1h / 30min / 5s", "interval (required for recurring), e.g. 1h / 30min / 5s")).option("-m, --model <model>", t2("\u6A21\u578B", "model")).option("-c, --category <category>", t2("\u5206\u7C7B", "category"), "general").option("-i, --importance <number>", t2("\u91CD\u8981\u7A0B\u5EA6 1-5", "importance 1-5"), "3").option("-u, --urgency <number>", t2("\u7D27\u6025\u7A0B\u5EA6 1-5", "urgency 1-5"), "3").option("-b, --batch <batchId>", t2("\u6A21\u677F\u751F\u6210\u4EFB\u52A1\u7684\u6279\u6B21 ID", "batch ID for generated tasks")).option("--max-instances <number>", t2("\u81EA\u52A8\u5B9A\u65F6\u4EFB\u52A1\u7684\u6D3B\u8DC3\u5B9E\u4F8B\u4E0A\u9650\uFF08\u7ACB\u5373\u89E6\u53D1\u4E0D\u53D7\u9650\uFF09", "active instance limit for automatic scheduling (Run now is unrestricted)"), "1").option("--max-retries <number>", t2("\u6700\u5927\u91CD\u8BD5\u6B21\u6570", "maximum retries"), "3").option("--retry-backoff <duration>", t2("\u9000\u907F\u57FA\u7840\u95F4\u9694\uFF0C\u5982 30s / 5min", "retry backoff base, e.g. 30s / 5min"), "30s").option("--timeout <duration>", t2("\u6BCF\u6B21\u4EFB\u52A1\u786C\u8D85\u65F6\uFF0C\u5982 30min / 2h", "hard timeout per task, e.g. 30min / 2h")).action(async (options) => withDb(async () => {
|
|
29821
|
+
new Command("add").description(t2("\u521B\u5EFA\u5B9A\u65F6\u4EFB\u52A1\u6A21\u677F", "create a scheduled task template")).requiredOption("-n, --name <name>", t2("\u6A21\u677F\u540D\u79F0", "template name")).requiredOption("-a, --agent <agent>", t2("Agent \u540D\u79F0", "agent name")).requiredOption("-p, --prompt <prompt>", t2("\u63D0\u793A\u8BCD", "prompt")).requiredOption("-t, --type <type>", t2("\u5B9A\u65F6\u7C7B\u578B\uFF1Acron/delayed/recurring", "schedule type: cron/delayed/recurring")).option("--cron <expr>", t2("cron \u8868\u8FBE\u5F0F\uFF08cron \u7C7B\u578B\u5FC5\u586B\uFF09", "cron expression (required for cron)")).option("--delay <duration>", t2("\u5EF6\u8FDF\u65F6\u95F4\uFF08delayed \u5FC5\u586B\uFF09\uFF0C\u5982 30s / 5min / 1h / 2d", "delay (required for delayed), e.g. 30s / 5min / 1h / 2d")).option("--interval <duration>", t2("\u5FAA\u73AF\u95F4\u9694\uFF08recurring \u5FC5\u586B\uFF09\uFF0C\u5982 1h / 30min / 5s", "interval (required for recurring), e.g. 1h / 30min / 5s")).option("-m, --model <model>", t2("\u6A21\u578B", "model")).option("--variant <variant>", t2("\u6A21\u578B variant\uFF0C\u5982 high / xhigh", "model variant, e.g. high / xhigh")).option("-c, --category <category>", t2("\u5206\u7C7B", "category"), "general").option("-i, --importance <number>", t2("\u91CD\u8981\u7A0B\u5EA6 1-5", "importance 1-5"), "3").option("-u, --urgency <number>", t2("\u7D27\u6025\u7A0B\u5EA6 1-5", "urgency 1-5"), "3").option("-b, --batch <batchId>", t2("\u6A21\u677F\u751F\u6210\u4EFB\u52A1\u7684\u6279\u6B21 ID", "batch ID for generated tasks")).option("--max-instances <number>", t2("\u81EA\u52A8\u5B9A\u65F6\u4EFB\u52A1\u7684\u6D3B\u8DC3\u5B9E\u4F8B\u4E0A\u9650\uFF08\u7ACB\u5373\u89E6\u53D1\u4E0D\u53D7\u9650\uFF09", "active instance limit for automatic scheduling (Run now is unrestricted)"), "1").option("--max-retries <number>", t2("\u6700\u5927\u91CD\u8BD5\u6B21\u6570", "maximum retries"), "3").option("--retry-backoff <duration>", t2("\u9000\u907F\u57FA\u7840\u95F4\u9694\uFF0C\u5982 30s / 5min", "retry backoff base, e.g. 30s / 5min"), "30s").option("--timeout <duration>", t2("\u6BCF\u6B21\u4EFB\u52A1\u786C\u8D85\u65F6\uFF0C\u5982 30min / 2h", "hard timeout per task, e.g. 30min / 2h")).action(async (options) => withDb(async () => {
|
|
29415
29822
|
let intervalMs = null;
|
|
29416
29823
|
let runAt = null;
|
|
29417
29824
|
const retryBackoffMs = parseDuration(options.retryBackoff);
|
|
@@ -29439,6 +29846,7 @@ program2.command("template").description(t2("\u7BA1\u7406\u5B9A\u65F6\u4EFB\u52A
|
|
|
29439
29846
|
agent: options.agent,
|
|
29440
29847
|
prompt: options.prompt,
|
|
29441
29848
|
model: options.model,
|
|
29849
|
+
variant: options.variant,
|
|
29442
29850
|
category: options.category,
|
|
29443
29851
|
importance: parseBoundedInteger(options.importance, "importance", 1, 5),
|
|
29444
29852
|
urgency: parseBoundedInteger(options.urgency, "urgency", 1, 5),
|
|
@@ -29519,13 +29927,13 @@ databaseCommand.command("restore").description(t2("\u81EA\u52A8\u5907\u4EFD\u5F5
|
|
|
29519
29927
|
}, (error) => renderDatabaseError(error, { forceJson: options.json })));
|
|
29520
29928
|
program2.addCommand(databaseCommand);
|
|
29521
29929
|
program2.command("init").description(t2("\u521D\u59CB\u5316 SuperTask\uFF08\u521B\u5EFA\u914D\u7F6E\u5E76\u6267\u884C\u8FC1\u79FB\uFF09", "initialize SuperTask (create config and run migrations)")).action(async () => withDb(async () => {
|
|
29522
|
-
const { existsSync:
|
|
29523
|
-
const { dirname:
|
|
29930
|
+
const { existsSync: existsSync10, mkdirSync: mkdirSync6, writeFileSync: writeFileSync4 } = await import("fs");
|
|
29931
|
+
const { dirname: dirname11 } = await import("path");
|
|
29524
29932
|
const { getConfigPath: getConfigPath2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
29525
29933
|
const configPath = getConfigPath2();
|
|
29526
|
-
if (!
|
|
29527
|
-
const dir =
|
|
29528
|
-
if (!
|
|
29934
|
+
if (!existsSync10(configPath)) {
|
|
29935
|
+
const dir = dirname11(configPath);
|
|
29936
|
+
if (!existsSync10(dir)) mkdirSync6(dir, { recursive: true });
|
|
29529
29937
|
writeFileSync4(configPath, JSON.stringify({
|
|
29530
29938
|
configVersion: 2,
|
|
29531
29939
|
worker: { maxConcurrency: 2 },
|
|
@@ -29565,7 +29973,7 @@ program2.command("config").description(t2("\u663E\u793A\u5F53\u524D\u914D\u7F6E"
|
|
|
29565
29973
|
const cfg = loadConfig2();
|
|
29566
29974
|
console.log(JSON.stringify(cfg, null, 2));
|
|
29567
29975
|
});
|
|
29568
|
-
program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u636E\u5E93\u3001Gateway\u3001Web \u754C\u9762\u548C\u65E5\u5FD7\u8F6E\u8F6C", "diagnose OpenCode, database, Gateway, Dashboard, and log rotation")).option("--json", t2("\u5F3A\u5236\u8F93\u51FA JSON", "force JSON output")).option("--smoke", t2("\u901A\u8FC7 Gateway \u63D0\u4EA4\u4E00\u4E2A\u771F\u5B9E OpenCode \u4EFB\u52A1\u5E76\u9A8C\u8BC1\u8F93\u51FA", "queue a real OpenCode task through Gateway and verify its output")).option("--smoke-agent <agent>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u4F7F\u7528\u7684 Agent", "Agent used by the real smoke task"), "build").option("--smoke-model <model>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u4F7F\u7528\u7684\u6A21\u578B\uFF1B\u9ED8\u8BA4\u8DDF\u968F Agent \u914D\u7F6E", "model used by the real smoke task; defaults to the Agent configuration")).option("--smoke-cwd <path>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u7684\u9879\u76EE\u76EE\u5F55\uFF1B\u9ED8\u8BA4\u4E3A\u5F53\u524D\u76EE\u5F55", "project directory for the real smoke task; defaults to the current directory")).option("--smoke-timeout <duration>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u7B49\u5F85\u4E0A\u9650\uFF0C\u5982 2min / 5min", "real smoke task timeout, e.g. 2min / 5min"), "3min").action(async (options) => withDb(async () => {
|
|
29976
|
+
program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u636E\u5E93\u3001Gateway\u3001Web \u754C\u9762\u548C\u65E5\u5FD7\u8F6E\u8F6C", "diagnose OpenCode, database, Gateway, Dashboard, and log rotation")).option("--json", t2("\u5F3A\u5236\u8F93\u51FA JSON", "force JSON output")).option("--smoke", t2("\u901A\u8FC7 Gateway \u63D0\u4EA4\u4E00\u4E2A\u771F\u5B9E OpenCode \u4EFB\u52A1\u5E76\u9A8C\u8BC1\u8F93\u51FA", "queue a real OpenCode task through Gateway and verify its output")).option("--smoke-agent <agent>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u4F7F\u7528\u7684 Agent", "Agent used by the real smoke task"), "build").option("--smoke-model <model>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u4F7F\u7528\u7684\u6A21\u578B\uFF1B\u9ED8\u8BA4\u8DDF\u968F Agent \u914D\u7F6E", "model used by the real smoke task; defaults to the Agent configuration")).option("--smoke-variant <variant>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u4F7F\u7528\u7684\u6A21\u578B variant", "model variant used by the real smoke task")).option("--smoke-cwd <path>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u7684\u9879\u76EE\u76EE\u5F55\uFF1B\u9ED8\u8BA4\u4E3A\u5F53\u524D\u76EE\u5F55", "project directory for the real smoke task; defaults to the current directory")).option("--smoke-timeout <duration>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u7B49\u5F85\u4E0A\u9650\uFF0C\u5982 2min / 5min", "real smoke task timeout, e.g. 2min / 5min"), "3min").action(async (options) => withDb(async () => {
|
|
29569
29977
|
const config = loadConfig();
|
|
29570
29978
|
const database = DatabaseMaintenanceService.check();
|
|
29571
29979
|
const legacyQuarantinedRuns = await TaskRunService.listLegacyQuarantinedRuns(
|
|
@@ -29678,6 +30086,7 @@ program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u63
|
|
|
29678
30086
|
smoke = await runDoctorSmoke({
|
|
29679
30087
|
agent: options.smokeAgent,
|
|
29680
30088
|
model: options.smokeModel,
|
|
30089
|
+
variant: options.smokeVariant,
|
|
29681
30090
|
cwd: options.smokeCwd ?? process.cwd(),
|
|
29682
30091
|
timeoutMs: smokeTimeoutMs
|
|
29683
30092
|
});
|