opencode-supertask 0.1.34 → 0.1.36
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 +30 -0
- package/README.md +16 -9
- package/dist/cli/index.js +854 -78
- package/dist/cli/index.js.map +1 -1
- package/dist/gateway/index.js +684 -57
- package/dist/gateway/index.js.map +1 -1
- package/dist/plugin/supertask.js +30 -0
- package/dist/plugin/supertask.js.map +1 -1
- package/dist/web/index.d.ts +19 -1
- package/dist/web/index.js +695 -89
- package/dist/web/index.js.map +1 -1
- package/dist/worker/index.d.ts +3 -1
- package/dist/worker/index.js +18 -3
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
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 join8(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 = join8;
|
|
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((join8) => join8.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((join8) => join8.alias === tableName)) {
|
|
7978
7978
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
7979
7979
|
}
|
|
7980
7980
|
if (typeof on === "function") {
|
|
@@ -20955,6 +20955,7 @@ var init_management_lock = __esm({
|
|
|
20955
20955
|
// src/daemon/pm2.ts
|
|
20956
20956
|
var pm2_exports = {};
|
|
20957
20957
|
__export(pm2_exports, {
|
|
20958
|
+
diagnoseOpenCodeRuntime: () => diagnoseOpenCodeRuntime,
|
|
20958
20959
|
ensureGateway: () => ensureGateway,
|
|
20959
20960
|
ensurePm2LogRotation: () => ensurePm2LogRotation,
|
|
20960
20961
|
getGatewayDiagnostic: () => getGatewayDiagnostic,
|
|
@@ -21074,7 +21075,35 @@ function scopesMatch(left, right) {
|
|
|
21074
21075
|
function currentScope() {
|
|
21075
21076
|
return runtimeScope({ cwd: process.cwd(), env: process.env });
|
|
21076
21077
|
}
|
|
21077
|
-
function
|
|
21078
|
+
function diagnoseOpenCodeRuntime(runtime = {
|
|
21079
|
+
cwd: process.cwd(),
|
|
21080
|
+
env: process.env
|
|
21081
|
+
}) {
|
|
21082
|
+
const executable = runtimeScope(runtime).opencodePath;
|
|
21083
|
+
const result = spawnSync2(executable, ["--version"], {
|
|
21084
|
+
cwd: runtime.cwd,
|
|
21085
|
+
env: runtime.env,
|
|
21086
|
+
encoding: "utf8",
|
|
21087
|
+
timeout: 1e4,
|
|
21088
|
+
killSignal: "SIGKILL"
|
|
21089
|
+
});
|
|
21090
|
+
const ok = result.status === 0 && result.error === void 0;
|
|
21091
|
+
return {
|
|
21092
|
+
ok,
|
|
21093
|
+
executable,
|
|
21094
|
+
version: ok ? result.stdout.trim() || result.stderr.trim() || null : null,
|
|
21095
|
+
error: ok ? null : result.error?.message || result.stderr.trim() || result.stdout.trim() || `exit code ${result.status}`
|
|
21096
|
+
};
|
|
21097
|
+
}
|
|
21098
|
+
function assertOpenCodeRuntime(runtime) {
|
|
21099
|
+
const diagnostic = diagnoseOpenCodeRuntime(runtime);
|
|
21100
|
+
if (!diagnostic.ok) {
|
|
21101
|
+
throw new Error(
|
|
21102
|
+
`[supertask] \u76EE\u6807 Gateway \u73AF\u5883\u65E0\u6CD5\u6267\u884C OpenCode (${diagnostic.executable}): ${diagnostic.error}`
|
|
21103
|
+
);
|
|
21104
|
+
}
|
|
21105
|
+
}
|
|
21106
|
+
function getGatewayDiagnostic(options = {}) {
|
|
21078
21107
|
const producerScope = currentScope();
|
|
21079
21108
|
if (!isPm2Installed()) {
|
|
21080
21109
|
return {
|
|
@@ -21090,7 +21119,8 @@ function getGatewayDiagnostic() {
|
|
|
21090
21119
|
startupConfigured: process.platform === "darwin" || process.platform === "linux" ? false : null,
|
|
21091
21120
|
currentScope: producerScope,
|
|
21092
21121
|
gatewayScope: null,
|
|
21093
|
-
scopeMatches: false
|
|
21122
|
+
scopeMatches: false,
|
|
21123
|
+
gatewayOpenCode: null
|
|
21094
21124
|
};
|
|
21095
21125
|
}
|
|
21096
21126
|
const processes = pm2JsonList();
|
|
@@ -21118,7 +21148,8 @@ function getGatewayDiagnostic() {
|
|
|
21118
21148
|
) : process.platform === "linux" ? isLinuxStartupConfigured(gatewayEnv, runtime?.cwd, runtime ?? void 0) : null,
|
|
21119
21149
|
currentScope: producerScope,
|
|
21120
21150
|
gatewayScope: managedScope,
|
|
21121
|
-
scopeMatches: managedScope != null && scopesMatch(producerScope, managedScope)
|
|
21151
|
+
scopeMatches: managedScope != null && scopesMatch(producerScope, managedScope),
|
|
21152
|
+
gatewayOpenCode: runtime === null || !options.probeOpenCode ? null : diagnoseOpenCodeRuntime(runtime)
|
|
21122
21153
|
};
|
|
21123
21154
|
}
|
|
21124
21155
|
function writeRunningVersion(version2, env = process.env, cwd = process.cwd()) {
|
|
@@ -21921,6 +21952,7 @@ function installUnlocked() {
|
|
|
21921
21952
|
assertRuntimeCanControlPm2(oldRuntime, existing);
|
|
21922
21953
|
gatewayKillTimeoutMs(targetRuntime);
|
|
21923
21954
|
gatewayTerminationCommandTimeoutMs(targetRuntime);
|
|
21955
|
+
assertOpenCodeRuntime(targetRuntime);
|
|
21924
21956
|
if (existing) requirePm2Termination("delete", "pm2 delete existing Gateway", oldRuntime);
|
|
21925
21957
|
const version2 = getPackageVersion();
|
|
21926
21958
|
try {
|
|
@@ -22033,6 +22065,7 @@ function upgradeUnlocked(target) {
|
|
|
22033
22065
|
assertRuntimeCanControlPm2(oldRuntime, existing);
|
|
22034
22066
|
gatewayKillTimeoutMs(targetRuntime);
|
|
22035
22067
|
gatewayTerminationCommandTimeoutMs(targetRuntime);
|
|
22068
|
+
assertOpenCodeRuntime(targetRuntime);
|
|
22036
22069
|
if (existing) requirePm2Termination("delete", "pm2 delete old Gateway", oldRuntime);
|
|
22037
22070
|
try {
|
|
22038
22071
|
pm2StartGateway(targetRuntime);
|
|
@@ -22085,6 +22118,7 @@ function ensureGatewayUnlocked() {
|
|
|
22085
22118
|
const before = getRunningVersion(oldRuntime?.env ?? process.env, oldRuntime?.cwd);
|
|
22086
22119
|
gatewayKillTimeoutMs(targetRuntime);
|
|
22087
22120
|
gatewayTerminationCommandTimeoutMs(targetRuntime);
|
|
22121
|
+
assertOpenCodeRuntime(targetRuntime);
|
|
22088
22122
|
if (existing) requirePm2Termination("delete", "pm2 delete stale Gateway", oldRuntime);
|
|
22089
22123
|
try {
|
|
22090
22124
|
pm2StartGateway(targetRuntime);
|
|
@@ -22665,7 +22699,15 @@ import { spawn } from "child_process";
|
|
|
22665
22699
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
22666
22700
|
import { existsSync as existsSync7 } from "fs";
|
|
22667
22701
|
import { dirname as dirname8, join as join6 } from "path";
|
|
22668
|
-
import { randomUUID as
|
|
22702
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
22703
|
+
function runCommandContext(executable, args, cwd) {
|
|
22704
|
+
return JSON.stringify({
|
|
22705
|
+
type: "supertask_command",
|
|
22706
|
+
executable,
|
|
22707
|
+
args,
|
|
22708
|
+
cwd
|
|
22709
|
+
});
|
|
22710
|
+
}
|
|
22669
22711
|
function assertWorkerProcessIsolationSupported(platform = process.platform) {
|
|
22670
22712
|
if (platform === "win32") {
|
|
22671
22713
|
throw new Error(
|
|
@@ -22798,7 +22840,7 @@ var init_worker = __esm({
|
|
|
22798
22840
|
}
|
|
22799
22841
|
let runId = null;
|
|
22800
22842
|
try {
|
|
22801
|
-
const launchIdentity = `gateway-${process.pid}:launch:${
|
|
22843
|
+
const launchIdentity = `gateway-${process.pid}:launch:${randomUUID3()}`;
|
|
22802
22844
|
const run = await TaskRunService.create({
|
|
22803
22845
|
taskId: task.id,
|
|
22804
22846
|
model: this.resolveModel(task.model),
|
|
@@ -22887,6 +22929,7 @@ var init_worker = __esm({
|
|
|
22887
22929
|
runId,
|
|
22888
22930
|
launchIdentity,
|
|
22889
22931
|
child,
|
|
22932
|
+
commandContext: runCommandContext(this.opencodeBin, args, task.cwd || process.cwd()),
|
|
22890
22933
|
output: "",
|
|
22891
22934
|
sessionId: null,
|
|
22892
22935
|
timeoutTimer: null,
|
|
@@ -22922,8 +22965,8 @@ var init_worker = __esm({
|
|
|
22922
22965
|
}
|
|
22923
22966
|
});
|
|
22924
22967
|
let spawnError = null;
|
|
22925
|
-
const spawned = new Promise((
|
|
22926
|
-
child.once("spawn",
|
|
22968
|
+
const spawned = new Promise((resolve6, reject) => {
|
|
22969
|
+
child.once("spawn", resolve6);
|
|
22927
22970
|
child.once("error", (error) => {
|
|
22928
22971
|
spawnError = error;
|
|
22929
22972
|
reject(error);
|
|
@@ -22971,10 +23014,10 @@ var init_worker = __esm({
|
|
|
22971
23014
|
return;
|
|
22972
23015
|
}
|
|
22973
23016
|
try {
|
|
22974
|
-
await new Promise((
|
|
23017
|
+
await new Promise((resolve6, reject) => {
|
|
22975
23018
|
child.stdin.end("START\n", (error) => {
|
|
22976
23019
|
if (error) reject(error);
|
|
22977
|
-
else
|
|
23020
|
+
else resolve6();
|
|
22978
23021
|
});
|
|
22979
23022
|
});
|
|
22980
23023
|
} catch (error) {
|
|
@@ -23051,7 +23094,7 @@ var init_worker = __esm({
|
|
|
23051
23094
|
const termination = entry.termination;
|
|
23052
23095
|
if (termination?.kind === "shutdown") return;
|
|
23053
23096
|
if (termination?.kind === "cancel") {
|
|
23054
|
-
const output2 =
|
|
23097
|
+
const output2 = this.outputWithCommand(entry);
|
|
23055
23098
|
const log2 = `${termination.message}${output2 ? `
|
|
23056
23099
|
${output2}` : ""}`;
|
|
23057
23100
|
await TaskRunService.fail(entry.runId, log2);
|
|
@@ -23065,7 +23108,7 @@ ${output2}` : ""}`;
|
|
|
23065
23108
|
}
|
|
23066
23109
|
const currentRun = await TaskRunService.getById(entry.runId);
|
|
23067
23110
|
if (!currentRun || currentRun.status !== "running") return;
|
|
23068
|
-
const output =
|
|
23111
|
+
const output = this.outputWithCommand(entry);
|
|
23069
23112
|
const log = failure ? `${failure}${output ? `
|
|
23070
23113
|
${output}` : ""}` : output;
|
|
23071
23114
|
if (code === 0 && !failure) {
|
|
@@ -23201,6 +23244,11 @@ ${output}` : ""}` : output;
|
|
|
23201
23244
|
const batchId = normalizeTaskBatchId(task.batchId);
|
|
23202
23245
|
if (batchId) this.activeBatchIds.delete(batchId);
|
|
23203
23246
|
}
|
|
23247
|
+
outputWithCommand(entry) {
|
|
23248
|
+
const output = entry.output.trim();
|
|
23249
|
+
return `${entry.commandContext}${output ? `
|
|
23250
|
+
${output}` : ""}`;
|
|
23251
|
+
}
|
|
23204
23252
|
resolveModel(taskModel) {
|
|
23205
23253
|
if (!taskModel || taskModel === "default") return null;
|
|
23206
23254
|
return taskModel;
|
|
@@ -25977,6 +26025,116 @@ var init_dist = __esm({
|
|
|
25977
26025
|
}
|
|
25978
26026
|
});
|
|
25979
26027
|
|
|
26028
|
+
// src/core/opencode-catalog.ts
|
|
26029
|
+
import { spawn as spawn2 } from "child_process";
|
|
26030
|
+
function cleanOutput(value) {
|
|
26031
|
+
return value.replace(ANSI_PATTERN, "").replace(/\r/g, "");
|
|
26032
|
+
}
|
|
26033
|
+
function runOpenCode(executable, args, cwd, timeoutMs) {
|
|
26034
|
+
return new Promise((resolve6, reject) => {
|
|
26035
|
+
const child = spawn2(executable, args, {
|
|
26036
|
+
cwd,
|
|
26037
|
+
env: process.env,
|
|
26038
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
26039
|
+
});
|
|
26040
|
+
let stdout = "";
|
|
26041
|
+
let stderr = "";
|
|
26042
|
+
let failure = null;
|
|
26043
|
+
let finished = false;
|
|
26044
|
+
const append = (current, chunk) => {
|
|
26045
|
+
const next = current + chunk.toString();
|
|
26046
|
+
if (Buffer.byteLength(next) > MAX_OUTPUT_BYTES && failure === null) {
|
|
26047
|
+
failure = new Error(`OpenCode \u8F93\u51FA\u8D85\u8FC7 ${MAX_OUTPUT_BYTES} bytes`);
|
|
26048
|
+
child.kill("SIGTERM");
|
|
26049
|
+
}
|
|
26050
|
+
return next.slice(-MAX_OUTPUT_BYTES);
|
|
26051
|
+
};
|
|
26052
|
+
child.stdout?.on("data", (chunk) => {
|
|
26053
|
+
stdout = append(stdout, chunk);
|
|
26054
|
+
});
|
|
26055
|
+
child.stderr?.on("data", (chunk) => {
|
|
26056
|
+
stderr = append(stderr, chunk);
|
|
26057
|
+
});
|
|
26058
|
+
child.once("error", (error) => {
|
|
26059
|
+
failure ??= error;
|
|
26060
|
+
});
|
|
26061
|
+
const timer = setTimeout(() => {
|
|
26062
|
+
failure ??= new Error(`OpenCode \u547D\u4EE4\u8D85\u8FC7 ${timeoutMs}ms \u672A\u5B8C\u6210`);
|
|
26063
|
+
child.kill("SIGTERM");
|
|
26064
|
+
}, timeoutMs);
|
|
26065
|
+
child.once("close", (code) => {
|
|
26066
|
+
if (finished) return;
|
|
26067
|
+
finished = true;
|
|
26068
|
+
clearTimeout(timer);
|
|
26069
|
+
if (failure) {
|
|
26070
|
+
reject(failure);
|
|
26071
|
+
return;
|
|
26072
|
+
}
|
|
26073
|
+
if (code !== 0) {
|
|
26074
|
+
const detail = cleanOutput(stderr).trim() || `\u9000\u51FA\u7801 ${code ?? "null"}`;
|
|
26075
|
+
reject(new Error(`OpenCode ${args.join(" ")} \u5931\u8D25\uFF1A${detail}`));
|
|
26076
|
+
return;
|
|
26077
|
+
}
|
|
26078
|
+
resolve6(cleanOutput(stdout));
|
|
26079
|
+
});
|
|
26080
|
+
});
|
|
26081
|
+
}
|
|
26082
|
+
function parseOpenCodeModels(output) {
|
|
26083
|
+
return [...new Set(cleanOutput(output).split("\n").map((line) => line.trim()).filter((line) => /^[^\s/]+\/.+/.test(line)))].sort((left, right) => left.localeCompare(right));
|
|
26084
|
+
}
|
|
26085
|
+
function parseOpenCodeAgents(output) {
|
|
26086
|
+
const agents = /* @__PURE__ */ new Map();
|
|
26087
|
+
for (const line of cleanOutput(output).split("\n")) {
|
|
26088
|
+
const match2 = /^([^\s()]+) \((primary|subagent|all)\)$/.exec(line.trim());
|
|
26089
|
+
if (!match2) continue;
|
|
26090
|
+
const name = match2[1];
|
|
26091
|
+
const mode = match2[2];
|
|
26092
|
+
if (name === "supertask-runner") continue;
|
|
26093
|
+
agents.set(name, { name, mode });
|
|
26094
|
+
}
|
|
26095
|
+
const rank = { primary: 0, all: 1, subagent: 2 };
|
|
26096
|
+
return [...agents.values()].sort((left, right) => rank[left.mode] - rank[right.mode] || left.name.localeCompare(right.name));
|
|
26097
|
+
}
|
|
26098
|
+
async function loadOpenCodeCatalog(cwd, options = {}) {
|
|
26099
|
+
validateTaskWorkingDirectory(cwd);
|
|
26100
|
+
const executable = options.executable ?? process.env.SUPERTASK_OPENCODE_BIN ?? "opencode";
|
|
26101
|
+
const timeoutMs = options.timeoutMs ?? COMMAND_TIMEOUT_MS;
|
|
26102
|
+
const cacheKey = `${executable}\0${cwd}`;
|
|
26103
|
+
const cached = catalogCache.get(cacheKey);
|
|
26104
|
+
if (options.useCache !== false && cached && cached.expiresAt > Date.now()) {
|
|
26105
|
+
return cached.result;
|
|
26106
|
+
}
|
|
26107
|
+
const result = Promise.all([
|
|
26108
|
+
runOpenCode(executable, ["models"], cwd, timeoutMs),
|
|
26109
|
+
runOpenCode(executable, ["agent", "list"], cwd, timeoutMs)
|
|
26110
|
+
]).then(([modelsOutput, agentsOutput]) => {
|
|
26111
|
+
const models = parseOpenCodeModels(modelsOutput);
|
|
26112
|
+
const agents = parseOpenCodeAgents(agentsOutput).filter((agent) => agent.mode !== "subagent");
|
|
26113
|
+
if (models.length === 0) throw new Error("OpenCode \u6CA1\u6709\u8FD4\u56DE\u53EF\u7528\u6A21\u578B");
|
|
26114
|
+
if (agents.length === 0) throw new Error("OpenCode \u6CA1\u6709\u8FD4\u56DE\u53EF\u76F4\u63A5\u8FD0\u884C\u7684\u4E3B Agent");
|
|
26115
|
+
return { cwd, models, agents };
|
|
26116
|
+
});
|
|
26117
|
+
if (options.useCache !== false) {
|
|
26118
|
+
catalogCache.set(cacheKey, { expiresAt: Date.now() + CATALOG_CACHE_MS, result });
|
|
26119
|
+
result.catch(() => {
|
|
26120
|
+
if (catalogCache.get(cacheKey)?.result === result) catalogCache.delete(cacheKey);
|
|
26121
|
+
});
|
|
26122
|
+
}
|
|
26123
|
+
return result;
|
|
26124
|
+
}
|
|
26125
|
+
var CATALOG_CACHE_MS, COMMAND_TIMEOUT_MS, MAX_OUTPUT_BYTES, ANSI_PATTERN, catalogCache;
|
|
26126
|
+
var init_opencode_catalog = __esm({
|
|
26127
|
+
"src/core/opencode-catalog.ts"() {
|
|
26128
|
+
"use strict";
|
|
26129
|
+
init_task_working_directory();
|
|
26130
|
+
CATALOG_CACHE_MS = 3e4;
|
|
26131
|
+
COMMAND_TIMEOUT_MS = 2e4;
|
|
26132
|
+
MAX_OUTPUT_BYTES = 4 * 1024 * 1024;
|
|
26133
|
+
ANSI_PATTERN = /\x1B(?:[@-_][0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\))/g;
|
|
26134
|
+
catalogCache = /* @__PURE__ */ new Map();
|
|
26135
|
+
}
|
|
26136
|
+
});
|
|
26137
|
+
|
|
25980
26138
|
// src/web/ui.ts
|
|
25981
26139
|
function t(locale, key, values = {}) {
|
|
25982
26140
|
const template = (locale === "en" ? EN : ZH)[key];
|
|
@@ -26040,7 +26198,8 @@ function icon(name, className = "icon") {
|
|
|
26040
26198
|
check: '<path d="m5 12 4 4L19 6"/>',
|
|
26041
26199
|
alert: '<path d="M12 3 2.8 19h18.4L12 3Z"/><path d="M12 9v4M12 17h.01"/>',
|
|
26042
26200
|
clock: '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',
|
|
26043
|
-
database: '<ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v6c0 1.66 3.58 3 8 3s8-1.34 8-3V5M4 11v6c0 1.66 3.58 3 8 3s8-1.34 8-3v-6"/>'
|
|
26201
|
+
database: '<ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v6c0 1.66 3.58 3 8 3s8-1.34 8-3V5M4 11v6c0 1.66 3.58 3 8 3s8-1.34 8-3v-6"/>',
|
|
26202
|
+
folder: '<path d="M3 7.5A2.5 2.5 0 0 1 5.5 5H10l2 2h6.5A2.5 2.5 0 0 1 21 9.5v7A2.5 2.5 0 0 1 18.5 19h-13A2.5 2.5 0 0 1 3 16.5v-9Z"/>'
|
|
26044
26203
|
};
|
|
26045
26204
|
return `<svg class="${className}" viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">${paths[name]}</svg>`;
|
|
26046
26205
|
}
|
|
@@ -26053,7 +26212,70 @@ function clientMessages(locale) {
|
|
|
26053
26212
|
"action.refresh",
|
|
26054
26213
|
"action.logs",
|
|
26055
26214
|
"action.hideLogs",
|
|
26215
|
+
"details.title",
|
|
26216
|
+
"details.subtitle",
|
|
26217
|
+
"details.taskTitle",
|
|
26218
|
+
"details.runTitle",
|
|
26219
|
+
"details.templateTitle",
|
|
26220
|
+
"details.raw",
|
|
26056
26221
|
"details.copySuccess",
|
|
26222
|
+
"details.id",
|
|
26223
|
+
"details.project",
|
|
26224
|
+
"details.prompt",
|
|
26225
|
+
"details.result",
|
|
26226
|
+
"details.category",
|
|
26227
|
+
"details.batch",
|
|
26228
|
+
"details.dependency",
|
|
26229
|
+
"details.importance",
|
|
26230
|
+
"details.urgency",
|
|
26231
|
+
"details.retryCount",
|
|
26232
|
+
"details.retryBackoff",
|
|
26233
|
+
"details.timeout",
|
|
26234
|
+
"details.createdAt",
|
|
26235
|
+
"details.updatedAt",
|
|
26236
|
+
"details.startedAt",
|
|
26237
|
+
"details.finishedAt",
|
|
26238
|
+
"details.scheduledAt",
|
|
26239
|
+
"details.enabled",
|
|
26240
|
+
"details.scheduleRule",
|
|
26241
|
+
"details.maxInstances",
|
|
26242
|
+
"details.maxRetries",
|
|
26243
|
+
"details.lastRun",
|
|
26244
|
+
"details.nextRun",
|
|
26245
|
+
"details.taskId",
|
|
26246
|
+
"details.session",
|
|
26247
|
+
"details.heartbeat",
|
|
26248
|
+
"details.process",
|
|
26249
|
+
"details.history",
|
|
26250
|
+
"details.noHistory",
|
|
26251
|
+
"details.none",
|
|
26252
|
+
"details.default",
|
|
26253
|
+
"details.enabledYes",
|
|
26254
|
+
"details.enabledNo",
|
|
26255
|
+
"table.name",
|
|
26256
|
+
"table.agent",
|
|
26257
|
+
"table.model",
|
|
26258
|
+
"table.status",
|
|
26259
|
+
"table.duration",
|
|
26260
|
+
"template.scheduleType",
|
|
26261
|
+
"status.pending",
|
|
26262
|
+
"status.running",
|
|
26263
|
+
"status.done",
|
|
26264
|
+
"status.failed",
|
|
26265
|
+
"status.dead_letter",
|
|
26266
|
+
"status.cancelled",
|
|
26267
|
+
"status.unknown",
|
|
26268
|
+
"runStatus.running",
|
|
26269
|
+
"runStatus.done",
|
|
26270
|
+
"runStatus.failed",
|
|
26271
|
+
"schedule.cron",
|
|
26272
|
+
"schedule.recurring",
|
|
26273
|
+
"schedule.delayed",
|
|
26274
|
+
"schedule.unknown",
|
|
26275
|
+
"duration.seconds",
|
|
26276
|
+
"duration.minutes",
|
|
26277
|
+
"duration.hours",
|
|
26278
|
+
"duration.days",
|
|
26057
26279
|
"feedback.copyFailed",
|
|
26058
26280
|
"dialog.cancelTask",
|
|
26059
26281
|
"dialog.cancelTaskBody",
|
|
@@ -26095,7 +26317,20 @@ function clientMessages(locale) {
|
|
|
26095
26317
|
"feedback.restartTimeout",
|
|
26096
26318
|
"template.createTitle",
|
|
26097
26319
|
"template.editTitle",
|
|
26098
|
-
"filter.noResults"
|
|
26320
|
+
"filter.noResults",
|
|
26321
|
+
"catalog.chooseProject",
|
|
26322
|
+
"catalog.defaultModel",
|
|
26323
|
+
"catalog.defaultProvider",
|
|
26324
|
+
"catalog.loading",
|
|
26325
|
+
"catalog.loaded",
|
|
26326
|
+
"catalog.failed",
|
|
26327
|
+
"catalog.primary",
|
|
26328
|
+
"catalog.subagent",
|
|
26329
|
+
"catalog.all",
|
|
26330
|
+
"directory.empty",
|
|
26331
|
+
"feedback.commandCopied",
|
|
26332
|
+
"action.showHidden",
|
|
26333
|
+
"action.hideHidden"
|
|
26099
26334
|
];
|
|
26100
26335
|
return Object.fromEntries(keys.map((key) => [key, t(locale, key)]));
|
|
26101
26336
|
}
|
|
@@ -26163,9 +26398,14 @@ function renderLayout(options) {
|
|
|
26163
26398
|
<footer>${t(locale, "app.footer")}</footer>
|
|
26164
26399
|
</div>
|
|
26165
26400
|
<div id="toast-region" class="toast-region" role="status" aria-live="polite"></div>
|
|
26401
|
+
<dialog id="directory-dialog" class="directory-dialog">
|
|
26402
|
+
<div class="dialog-head"><div><h2>${t(locale, "directory.title")}</h2><p>${t(locale, "directory.subtitle")}</p></div><button type="button" class="icon-button" onclick="document.getElementById('directory-dialog').close()" aria-label="${t(locale, "action.close")}">${icon("close")}</button></div>
|
|
26403
|
+
<div class="dialog-body"><div class="directory-toolbar"><button id="directory-home" type="button" class="btn">${t(locale, "action.home")}</button><button id="directory-up" type="button" class="btn">${t(locale, "action.up")}</button><button id="directory-hidden" type="button" class="btn">${t(locale, "action.showHidden")}</button><div id="directory-path" class="directory-path"></div></div><div id="directory-list" class="directory-list"></div></div>
|
|
26404
|
+
<div class="dialog-actions"><button type="button" class="btn" onclick="document.getElementById('directory-dialog').close()">${t(locale, "action.cancel")}</button><button id="directory-choose" type="button" class="btn btn-primary">${icon("folder")}${t(locale, "action.chooseThisFolder")}</button></div>
|
|
26405
|
+
</dialog>
|
|
26166
26406
|
<dialog id="detail-dialog">
|
|
26167
|
-
<div class="dialog-head"><div><h2>${t(locale, "details.title")}</h2><p>${t(locale, "details.subtitle")}</p></div><button class="icon-button" onclick="document.getElementById('detail-dialog').close()" aria-label="${t(locale, "action.close")}">${icon("close")}</button></div>
|
|
26168
|
-
<div class="dialog-body"><
|
|
26407
|
+
<div class="dialog-head"><div><h2 id="detail-title">${t(locale, "details.title")}</h2><p>${t(locale, "details.subtitle")}</p></div><button class="icon-button" onclick="document.getElementById('detail-dialog').close()" aria-label="${t(locale, "action.close")}">${icon("close")}</button></div>
|
|
26408
|
+
<div class="dialog-body"><div id="detail-content" class="detail-view"></div><details class="detail-raw"><summary>${t(locale, "details.raw")}</summary><pre id="detail-raw" class="json-view"></pre></details></div>
|
|
26169
26409
|
<div class="dialog-actions"><button class="btn" onclick="copyDetails()">${icon("copy")}${t(locale, "action.copy")}</button><button class="btn btn-primary" onclick="document.getElementById('detail-dialog').close()">${t(locale, "action.close")}</button></div>
|
|
26170
26410
|
</dialog>
|
|
26171
26411
|
<dialog id="confirm-dialog">
|
|
@@ -26197,30 +26437,77 @@ function renderLayout(options) {
|
|
|
26197
26437
|
async function retryTask(id){if(!await ask(text('dialog.retryTask',{id}),text('dialog.retryTaskBody')))return;try{await readJson(await fetch('/api/tasks/'+id+'/retry',{method:'POST'}));location.reload()}catch(error){showToast(text('feedback.retryFailed')+': '+error.message,'error')}}
|
|
26198
26438
|
async function cancelTask(id){if(!await ask(text('dialog.cancelTask',{id}),text('dialog.cancelTaskBody'),true))return;try{await readJson(await fetch('/api/tasks/'+id+'/cancel',{method:'POST'}));location.reload()}catch(error){showToast(text('feedback.cancelFailed')+': '+error.message,'error')}}
|
|
26199
26439
|
async function deleteTask(id){if(!await ask(text('dialog.deleteTask',{id}),text('dialog.deleteTaskBody'),true))return;try{await readJson(await fetch('/api/tasks/'+id,{method:'DELETE'}));location.reload()}catch(error){showToast(text('feedback.deleteFailed')+': '+error.message,'error')}}
|
|
26200
|
-
|
|
26201
|
-
const
|
|
26202
|
-
|
|
26440
|
+
function detailDate(value){if(value===null||value===undefined||value==='')return text('details.none');const epoch=typeof value==='number'&&value<100000000000?value*1000:value;const date=new Date(epoch);return Number.isNaN(date.getTime())?String(value):date.toLocaleString(document.documentElement.lang)}
|
|
26441
|
+
function detailDuration(value){if(value===null||value===undefined)return text('details.default');const milliseconds=Number(value);if(!Number.isFinite(milliseconds))return String(value);if(milliseconds===0)return '0 ms';const units=[[86400000,text('duration.days')],[3600000,text('duration.hours')],[60000,text('duration.minutes')],[1000,text('duration.seconds')]];for(const [size,label] of units){if(milliseconds>=size&&milliseconds%size===0)return String(milliseconds/size)+' '+label}return String(milliseconds)+' ms'}
|
|
26442
|
+
function detailStatus(type,value){const prefix=type==='run'?'runStatus.':'status.';const key=prefix+String(value||'unknown');return Object.prototype.hasOwnProperty.call(UI,key)?text(key):text('status.unknown')}
|
|
26443
|
+
function detailScheduleType(value){const key='schedule.'+String(value||'unknown');return Object.prototype.hasOwnProperty.call(UI,key)?text(key):text('schedule.unknown')}
|
|
26444
|
+
function detailModel(value){return !value||value==='default'?text('details.default'):String(value)}
|
|
26445
|
+
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)}
|
|
26446
|
+
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')}
|
|
26447
|
+
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}
|
|
26448
|
+
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}
|
|
26449
|
+
function detailFields(type,data){if(type==='task')return [
|
|
26450
|
+
[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}],
|
|
26451
|
+
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
26452
|
+
[text('details.category'),data.category],[text('details.batch'),data.batchId],[text('details.dependency'),data.dependsOn?'#'+data.dependsOn:text('details.none')],
|
|
26453
|
+
[text('details.importance'),data.importance],[text('details.urgency'),data.urgency],[text('details.retryCount'),String(data.retryCount??0)+' / '+String(data.maxRetries??0)],
|
|
26454
|
+
[text('details.retryBackoff'),detailDuration(data.retryBackoffMs)],[text('details.timeout'),detailDuration(data.timeoutMs)],[text('details.scheduledAt'),detailDate(data.scheduledAt)],
|
|
26455
|
+
[text('details.createdAt'),detailDate(data.createdAt)],[text('details.startedAt'),detailDate(data.startedAt)],[text('details.finishedAt'),detailDate(data.finishedAt)],
|
|
26456
|
+
[text('details.result'),detailTaskResult(data),{wide:true,long:true}]
|
|
26457
|
+
];if(type==='run'){const started=data.startedAt?new Date(data.startedAt).getTime():null;const finished=data.finishedAt?new Date(data.finishedAt).getTime():null;return [
|
|
26458
|
+
[text('details.id'),'Run #'+data.id],[text('details.taskId'),'#'+data.taskId],[text('table.status'),detailStatus('run',data.status)],[text('table.model'),detailModel(data.model)],
|
|
26459
|
+
[text('details.session'),detailSession(data.sessionId)],[text('details.startedAt'),detailDate(data.startedAt)],[text('details.finishedAt'),detailDate(data.finishedAt)],
|
|
26460
|
+
[text('table.duration'),started!==null?detailDuration((finished??Date.now())-started):text('details.none')],[text('details.heartbeat'),detailDate(data.heartbeatAt)],
|
|
26461
|
+
[text('details.process'),'Worker PID '+String(data.workerPid??'\u2014')+' \xB7 OpenCode PID '+String(data.childPid??'\u2014'),{wide:true,mono:true}]
|
|
26462
|
+
];}const scheduleRule=data.scheduleType==='cron'?data.cronExpr:data.scheduleType==='recurring'?detailDuration(data.intervalMs):detailDate(data.runAt);return [
|
|
26463
|
+
[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}],
|
|
26464
|
+
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
26465
|
+
[text('template.scheduleType'),detailScheduleType(data.scheduleType)],[text('details.scheduleRule'),scheduleRule],[text('details.category'),data.category],[text('details.batch'),data.batchId],
|
|
26466
|
+
[text('details.importance'),data.importance],[text('details.urgency'),data.urgency],[text('details.maxInstances'),data.maxInstances],[text('details.maxRetries'),data.maxRetries??0],
|
|
26467
|
+
[text('details.retryBackoff'),detailDuration(data.retryBackoffMs)],[text('details.timeout'),detailDuration(data.timeoutMs)],[text('details.lastRun'),detailDate(data.lastRunAt)],[text('details.nextRun'),detailDate(data.nextRunAt)],
|
|
26468
|
+
[text('details.createdAt'),detailDate(data.createdAt)],[text('details.updatedAt'),detailDate(data.updatedAt)]
|
|
26469
|
+
]}
|
|
26470
|
+
async function showRecord(url,type){try{const data=await readJson(await fetch(url));const content=document.getElementById('detail-content');content.replaceChildren();const grid=document.createElement('div');grid.className='detail-grid';for(const [label,value,options] of detailFields(type,data))grid.appendChild(detailField(label,value,options));content.appendChild(grid);if(type==='task')content.appendChild(renderDetailHistory(data._runs));document.getElementById('detail-title').textContent=text(type==='task'?'details.taskTitle':type==='run'?'details.runTitle':'details.templateTitle');document.getElementById('detail-raw').textContent=JSON.stringify(data,null,2);document.querySelector('#detail-dialog .detail-raw').open=false;document.getElementById('detail-dialog').showModal()}catch(error){showToast(error.message,'error')}}
|
|
26471
|
+
const showDetail=id=>showRecord('/api/tasks/'+id,'task');const showRunDetail=id=>showRecord('/api/runs/'+id,'run');const showTemplateDetail=id=>showRecord('/api/templates/'+id,'template');
|
|
26472
|
+
async function copyDetails(){try{await navigator.clipboard.writeText(document.getElementById('detail-raw').textContent);showToast(text('details.copySuccess'))}catch{showToast(text('feedback.copyFailed'),'error')}}
|
|
26203
26473
|
async function copySessionCommand(id){try{const data=await readJson(await fetch('/api/runs/'+id+'/session-command'));await navigator.clipboard.writeText(data.command);showToast(text('feedback.sessionCommandCopied'))}catch(error){showToast(error.message||text('feedback.copyFailed'),'error')}}
|
|
26474
|
+
async function copyRunCommand(id){try{await navigator.clipboard.writeText(document.getElementById('command-'+id).textContent);showToast(text('feedback.commandCopied'))}catch{showToast(text('feedback.copyFailed'),'error')}}
|
|
26204
26475
|
function taskField(name){return document.getElementById('task-'+name)}
|
|
26476
|
+
function templateField(name){return document.getElementById('template-'+name)}
|
|
26205
26477
|
function taskProjects(){const node=document.getElementById('task-project-data');if(!node)return {};try{return JSON.parse(node.textContent||'{}')}catch{return {}}}
|
|
26206
26478
|
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')}
|
|
26207
|
-
|
|
26208
|
-
|
|
26209
|
-
|
|
26210
|
-
function
|
|
26211
|
-
function
|
|
26479
|
+
const catalogTimers={};const catalogRequests={};const catalogModels={};
|
|
26480
|
+
function catalogField(prefix,name){return document.getElementById(prefix+'-'+name)}
|
|
26481
|
+
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='';}
|
|
26482
|
+
function appendCurrentOption(select,value){if(!value||[...select.options].some(option=>option.value===value))return;select.appendChild(new Option(value,value));}
|
|
26483
|
+
function modelProvider(value){const slash=value.indexOf('/');return slash>0?value.slice(0,slash):''}
|
|
26484
|
+
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}
|
|
26485
|
+
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}}}
|
|
26486
|
+
function scheduleCatalogLoad(prefix){clearTimeout(catalogTimers[prefix]);catalogTimers[prefix]=setTimeout(()=>loadCatalog(prefix),450)}
|
|
26487
|
+
let directoryTargetId='';let directoryCurrent='';let directoryEntries=[];let directoryShowHidden=false;
|
|
26488
|
+
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)}}
|
|
26489
|
+
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}}
|
|
26490
|
+
document.getElementById('directory-hidden').onclick=()=>{directoryShowHidden=!directoryShowHidden;renderDirectoryEntries()};
|
|
26491
|
+
async function openDirectoryPicker(targetId){const input=document.getElementById(targetId);if(!input||input.readOnly)return;directoryTargetId=targetId;directoryShowHidden=false;document.getElementById('directory-dialog').showModal();if(!await browseDirectory(input.value.trim()||''))await browseDirectory('')}
|
|
26492
|
+
document.getElementById('directory-choose').onclick=()=>{const input=document.getElementById(directoryTargetId);if(!input||!directoryCurrent)return;input.value=directoryCurrent;input.dispatchEvent(new Event('input',{bubbles:true}));document.getElementById('directory-dialog').close();const prefix=directoryTargetId.startsWith('task-')?'task':'template';loadCatalog(prefix)};
|
|
26493
|
+
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'}
|
|
26494
|
+
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}
|
|
26495
|
+
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)}
|
|
26496
|
+
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)}
|
|
26497
|
+
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')}}
|
|
26498
|
+
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}}
|
|
26212
26499
|
function localDateTime(milliseconds){const date=new Date(milliseconds);const local=new Date(milliseconds-date.getTimezoneOffset()*60000);return local.toISOString().slice(0,23)}
|
|
26213
|
-
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;node.querySelector('input').required=name===type}}
|
|
26500
|
+
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')}}
|
|
26214
26501
|
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}
|
|
26215
26502
|
function selectedRunAt(){const input=templateField('run-at');return resolveEditedRunAt(input.dataset.originalEpoch?Number(input.dataset.originalEpoch):null,input.dataset.originalLocal||'',input.value)}
|
|
26216
|
-
function openTemplateCreator(){const form=document.getElementById('template-form');form.reset();templateField('id').value='';templateField('dialog-title').textContent=text('template.createTitle');setOriginalRunAt(null);templateField('run-at').value=localDateTime(Date.now()+3600000);updateTemplateScheduleFields();document.getElementById('template-dialog').showModal();setTimeout(()=>templateField('name').focus(),50)}
|
|
26217
|
-
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('
|
|
26218
|
-
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:
|
|
26503
|
+
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)}
|
|
26504
|
+
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')}}
|
|
26505
|
+
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}}
|
|
26219
26506
|
async function enableTmpl(id){try{await readJson(await fetch('/api/templates/'+id+'/enable',{method:'POST'}));location.reload()}catch(error){showToast(error.message,'error')}}
|
|
26220
26507
|
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')}}
|
|
26221
26508
|
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')}}
|
|
26222
26509
|
async function triggerTmpl(id){if(!await ask(text('dialog.triggerTemplate'),text('dialog.triggerTemplateBody')))return;try{const data=await readJson(await fetch('/api/templates/'+id+'/trigger',{method:'POST'}));showToast(text('feedback.triggered',{id:data.taskId}));setTimeout(()=>location.reload(),550)}catch(error){showToast(error.message,'error')}}
|
|
26223
|
-
function toggleLog(id,button){const panel=document.getElementById('log-'+id);const hidden=!panel.hidden;panel.hidden=hidden;button.setAttribute('aria-expanded',String(!hidden));button.textContent=text(hidden?'action.logs':'action.hideLogs');}
|
|
26510
|
+
function toggleLog(id,button){const panel=document.getElementById('log-'+id);const hidden=!panel.hidden;panel.hidden=hidden;button.setAttribute('aria-expanded',String(!hidden));button.textContent=text(hidden?'action.logs':'action.hideLogs');if(!hidden)requestAnimationFrame(()=>panel.scrollIntoView({block:'nearest',behavior:'smooth'}));}
|
|
26224
26511
|
function filterTasks(value){const query=value.trim().toLocaleLowerCase();let visible=0;document.querySelectorAll('[data-task-row]').forEach(row=>{const match=!query||row.dataset.search.toLocaleLowerCase().includes(query);row.hidden=!match;if(match)visible++});const empty=document.getElementById('search-empty');if(empty)empty.hidden=visible!==0;}
|
|
26225
26512
|
async function clearDatabase(){if(!await askDanger())return;try{const data=await readJson(await fetch('/api/database/clear',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({confirmation:'CLEAR'})}));showToast(text('feedback.databaseCleared',{path:data.backupPath}));setTimeout(()=>location.reload(),1000)}catch(error){showToast(error.message,'error')}}
|
|
26226
26513
|
async function confirmGatewayRestart(runningCount=0){const body=runningCount>0?text('dialog.restartGatewayRunningBody',{count:runningCount}):text('dialog.restartGatewayBody');return await ask(text('dialog.restartGateway'),body)}
|
|
@@ -26266,7 +26553,7 @@ var init_ui = __esm({
|
|
|
26266
26553
|
"action.hideLogs": "\u6536\u8D77\u65E5\u5FD7",
|
|
26267
26554
|
"action.save": "\u4FDD\u5B58\u8BBE\u7F6E",
|
|
26268
26555
|
"action.saveAndRestart": "\u4FDD\u5B58\u5E76\u91CD\u542F",
|
|
26269
|
-
"action.copy": "\u590D\u5236
|
|
26556
|
+
"action.copy": "\u590D\u5236\u539F\u59CB\u6570\u636E",
|
|
26270
26557
|
"action.close": "\u5173\u95ED",
|
|
26271
26558
|
"action.confirm": "\u786E\u8BA4",
|
|
26272
26559
|
"action.clearDatabase": "\u6E05\u7A7A\u6570\u636E\u5E93",
|
|
@@ -26275,6 +26562,13 @@ var init_ui = __esm({
|
|
|
26275
26562
|
"action.updateTask": "\u4FDD\u5B58\u4FEE\u6539",
|
|
26276
26563
|
"action.createTemplate": "\u65B0\u5EFA\u5B9A\u65F6\u4EFB\u52A1",
|
|
26277
26564
|
"action.saveTemplate": "\u4FDD\u5B58\u5B9A\u65F6\u4EFB\u52A1",
|
|
26565
|
+
"action.chooseFolder": "\u9009\u62E9\u6587\u4EF6\u5939",
|
|
26566
|
+
"action.chooseThisFolder": "\u9009\u62E9\u5F53\u524D\u6587\u4EF6\u5939",
|
|
26567
|
+
"action.home": "\u4E3B\u76EE\u5F55",
|
|
26568
|
+
"action.up": "\u4E0A\u4E00\u7EA7",
|
|
26569
|
+
"action.copyCommand": "\u590D\u5236\u547D\u4EE4",
|
|
26570
|
+
"action.showHidden": "\u663E\u793A\u9690\u85CF\u6587\u4EF6\u5939",
|
|
26571
|
+
"action.hideHidden": "\u9690\u85CF\u9690\u85CF\u6587\u4EF6\u5939",
|
|
26278
26572
|
"status.pending": "\u5F85\u6267\u884C",
|
|
26279
26573
|
"status.running": "\u8FD0\u884C\u4E2D",
|
|
26280
26574
|
"status.done": "\u5DF2\u5B8C\u6210",
|
|
@@ -26341,6 +26635,15 @@ var init_ui = __esm({
|
|
|
26341
26635
|
"schedule.hours": "{count} \u5C0F\u65F6",
|
|
26342
26636
|
"schedule.days": "{count} \u5929",
|
|
26343
26637
|
"schedule.overdue": "\u5DF2\u5230\u671F",
|
|
26638
|
+
"duration.unit": "\u65F6\u95F4\u5355\u4F4D",
|
|
26639
|
+
"duration.seconds": "\u79D2",
|
|
26640
|
+
"duration.minutes": "\u5206\u949F",
|
|
26641
|
+
"duration.hours": "\u5C0F\u65F6",
|
|
26642
|
+
"duration.days": "\u5929",
|
|
26643
|
+
"duration.systemDefault": "\u4F7F\u7528 Gateway \u9ED8\u8BA4\u8D85\u65F6",
|
|
26644
|
+
"duration.immediate": "\u7ACB\u5373\u91CD\u8BD5",
|
|
26645
|
+
"duration.custom": "\u81EA\u5B9A\u4E49\u2026",
|
|
26646
|
+
"duration.every": "\u6BCF {duration}",
|
|
26344
26647
|
"system.worker": "\u4EFB\u52A1\u6267\u884C",
|
|
26345
26648
|
"system.scheduler": "\u5B9A\u65F6\u4EFB\u52A1\u670D\u52A1",
|
|
26346
26649
|
"system.watchdog": "\u8FD0\u884C\u76D1\u63A7",
|
|
@@ -26388,6 +26691,9 @@ var init_ui = __esm({
|
|
|
26388
26691
|
"template.interval": "\u6267\u884C\u95F4\u9694",
|
|
26389
26692
|
"template.runAt": "\u6267\u884C\u65F6\u95F4",
|
|
26390
26693
|
"template.durationHint": "\u652F\u6301 30s\u30015min\u30011h\u30012d",
|
|
26694
|
+
"template.intervalHint": "\u76F4\u63A5\u9009\u62E9\u5E38\u7528\u9891\u7387\uFF1B\u53EA\u6709\u7279\u6B8A\u9700\u6C42\u624D\u9700\u8981\u81EA\u5B9A\u4E49\u3002",
|
|
26695
|
+
"template.retryBackoffHint": "\u4E00\u6B21\u5931\u8D25\u540E\uFF0C\u7B49\u5F85\u591A\u4E45\u518D\u91CD\u8BD5\u3002",
|
|
26696
|
+
"template.timeoutHint": "\u7559\u7A7A\u8868\u793A\u4F7F\u7528 Gateway \u7684\u9ED8\u8BA4\u4EFB\u52A1\u8D85\u65F6\u3002",
|
|
26391
26697
|
"template.advanced": "\u66F4\u591A\u6267\u884C\u8BBE\u7F6E",
|
|
26392
26698
|
"template.category": "\u5206\u7C7B",
|
|
26393
26699
|
"template.batchId": "\u6279\u6B21 ID",
|
|
@@ -26412,14 +26718,73 @@ var init_ui = __esm({
|
|
|
26412
26718
|
"task.batchHint": "\u76F8\u540C\u975E\u7A7A\u6279\u6B21 ID \u7684\u4EFB\u52A1\u4E25\u683C\u4E32\u884C\uFF1B\u7559\u7A7A\u5219\u4E0D\u53D7\u6279\u6B21\u4E32\u884C\u9650\u5236\uFF0C\u4F46\u4ECD\u53D7\u5168\u5C40\u5E76\u53D1\u548C\u4F9D\u8D56\u7EA6\u675F\u3002",
|
|
26413
26719
|
"task.projectExisting": "\u6B64\u9879\u76EE\u73B0\u6709 {total} \u4E2A\u4EFB\u52A1\uFF1A\u8FD0\u884C {running}\uFF0C\u6392\u961F {pending}\uFF0C\u5F02\u5E38 {failed}\u3002",
|
|
26414
26720
|
"task.projectNew": "\u8FD9\u662F\u4E00\u4E2A\u65B0\u9879\u76EE\u5206\u7EC4\uFF1B\u521B\u5EFA\u540E\u4F1A\u51FA\u73B0\u5728\u9879\u76EE\u5217\u8868\u4E2D\u3002",
|
|
26721
|
+
"catalog.chooseProject": "\u8BF7\u5148\u9009\u62E9\u9879\u76EE\u76EE\u5F55",
|
|
26722
|
+
"catalog.defaultModel": "\u8DDF\u968F Agent / OpenCode \u9ED8\u8BA4\u6A21\u578B",
|
|
26723
|
+
"catalog.defaultProvider": "\u9ED8\u8BA4\u6A21\u578B",
|
|
26724
|
+
"catalog.provider": "\u6A21\u578B\u63D0\u4F9B\u5546",
|
|
26725
|
+
"catalog.model": "\u5177\u4F53\u6A21\u578B",
|
|
26726
|
+
"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",
|
|
26727
|
+
"catalog.agentHint": "\u6765\u81EA\u5F53\u524D\u9879\u76EE\u7684 opencode agent list\u3002",
|
|
26728
|
+
"catalog.loading": "\u6B63\u5728\u8BFB\u53D6\u6B64\u9879\u76EE\u53EF\u7528\u7684 Agent \u548C\u6A21\u578B\u2026",
|
|
26729
|
+
"catalog.loaded": "\u5DF2\u4ECE\u672C\u673A OpenCode \u8BFB\u53D6 {agents} \u4E2A Agent\u3001{models} \u4E2A\u6A21\u578B\u3002",
|
|
26730
|
+
"catalog.failed": "\u65E0\u6CD5\u8BFB\u53D6\u6B64\u9879\u76EE\u7684 OpenCode \u914D\u7F6E\uFF1A{error}",
|
|
26731
|
+
"catalog.primary": "\u4E3B Agent",
|
|
26732
|
+
"catalog.subagent": "\u5B50 Agent",
|
|
26733
|
+
"catalog.all": "\u901A\u7528 Agent",
|
|
26734
|
+
"directory.title": "\u9009\u62E9\u9879\u76EE\u76EE\u5F55",
|
|
26735
|
+
"directory.subtitle": "\u9009\u62E9\u540E\uFF0C\u7CFB\u7EDF\u4F1A\u5728\u8BE5\u76EE\u5F55\u8FD0\u884C OpenCode\uFF0C\u5E76\u8BFB\u53D6\u8BE5\u9879\u76EE\u53EF\u7528\u7684 Agent \u548C\u6A21\u578B\u3002",
|
|
26736
|
+
"directory.empty": "\u8FD9\u4E2A\u6587\u4EF6\u5939\u4E2D\u6CA1\u6709\u5B50\u6587\u4EF6\u5939",
|
|
26737
|
+
"logs.command": "\u5B9E\u9645\u6267\u884C\u547D\u4EE4",
|
|
26738
|
+
"logs.output": "Agent \u8F93\u51FA",
|
|
26739
|
+
"logs.error": "\u5931\u8D25\u539F\u56E0",
|
|
26740
|
+
"logs.tools": "\u5DE5\u5177\u8C03\u7528",
|
|
26741
|
+
"logs.raw": "\u67E5\u770B\u539F\u59CB\u6267\u884C\u65E5\u5FD7",
|
|
26742
|
+
"logs.noText": "\u8FD9\u6B21\u6267\u884C\u6CA1\u6709\u4EA7\u751F\u53EF\u5C55\u793A\u7684\u6587\u672C\u8F93\u51FA\uFF0C\u8BF7\u67E5\u770B\u539F\u59CB\u65E5\u5FD7\u3002",
|
|
26415
26743
|
"theme.label": "\u4E3B\u9898",
|
|
26416
26744
|
"theme.system": "\u8DDF\u968F\u7CFB\u7EDF",
|
|
26417
26745
|
"theme.light": "\u6D45\u8272",
|
|
26418
26746
|
"theme.dark": "\u6DF1\u8272",
|
|
26419
26747
|
"language.label": "\u8BED\u8A00",
|
|
26420
|
-
"details.title": "\
|
|
26421
|
-
"details.subtitle": "\u539F\u59CB\
|
|
26422
|
-
"details.
|
|
26748
|
+
"details.title": "\u8BE6\u60C5",
|
|
26749
|
+
"details.subtitle": "\u91CD\u70B9\u4FE1\u606F\u5DF2\u6574\u7406\uFF1B\u539F\u59CB\u6570\u636E\u4EC5\u7528\u4E8E\u6392\u969C\u3002",
|
|
26750
|
+
"details.taskTitle": "\u4EFB\u52A1\u8BE6\u60C5",
|
|
26751
|
+
"details.runTitle": "\u6267\u884C\u8BE6\u60C5",
|
|
26752
|
+
"details.templateTitle": "\u5B9A\u65F6\u4EFB\u52A1\u8BE6\u60C5",
|
|
26753
|
+
"details.raw": "\u67E5\u770B\u539F\u59CB\u6570\u636E\uFF08JSON\uFF09",
|
|
26754
|
+
"details.copySuccess": "\u539F\u59CB\u6570\u636E\u5DF2\u590D\u5236",
|
|
26755
|
+
"details.id": "\u7F16\u53F7",
|
|
26756
|
+
"details.project": "\u9879\u76EE\u76EE\u5F55",
|
|
26757
|
+
"details.prompt": "\u63D0\u793A\u8BCD",
|
|
26758
|
+
"details.result": "\u6267\u884C\u7ED3\u679C / \u5931\u8D25\u539F\u56E0",
|
|
26759
|
+
"details.category": "\u5206\u7C7B",
|
|
26760
|
+
"details.batch": "\u6279\u6B21",
|
|
26761
|
+
"details.dependency": "\u4F9D\u8D56\u4EFB\u52A1",
|
|
26762
|
+
"details.importance": "\u91CD\u8981\u7A0B\u5EA6",
|
|
26763
|
+
"details.urgency": "\u7D27\u6025\u7A0B\u5EA6",
|
|
26764
|
+
"details.retryCount": "\u5DF2\u91CD\u8BD5 / \u6700\u591A\u91CD\u8BD5",
|
|
26765
|
+
"details.retryBackoff": "\u91CD\u8BD5\u7B49\u5F85",
|
|
26766
|
+
"details.timeout": "\u6267\u884C\u8D85\u65F6",
|
|
26767
|
+
"details.createdAt": "\u521B\u5EFA\u65F6\u95F4",
|
|
26768
|
+
"details.updatedAt": "\u66F4\u65B0\u65F6\u95F4",
|
|
26769
|
+
"details.startedAt": "\u5F00\u59CB\u65F6\u95F4",
|
|
26770
|
+
"details.finishedAt": "\u7ED3\u675F\u65F6\u95F4",
|
|
26771
|
+
"details.scheduledAt": "\u8BA1\u5212\u65F6\u95F4",
|
|
26772
|
+
"details.enabled": "\u81EA\u52A8\u8FD0\u884C",
|
|
26773
|
+
"details.scheduleRule": "\u8FD0\u884C\u89C4\u5219",
|
|
26774
|
+
"details.maxInstances": "\u81EA\u52A8\u8C03\u5EA6\u4E0A\u9650",
|
|
26775
|
+
"details.maxRetries": "\u5931\u8D25\u91CD\u8BD5\u6B21\u6570",
|
|
26776
|
+
"details.lastRun": "\u4E0A\u6B21\u8FD0\u884C",
|
|
26777
|
+
"details.nextRun": "\u4E0B\u6B21\u8FD0\u884C",
|
|
26778
|
+
"details.taskId": "\u6240\u5C5E\u4EFB\u52A1",
|
|
26779
|
+
"details.session": "OpenCode \u4F1A\u8BDD",
|
|
26780
|
+
"details.heartbeat": "\u6700\u8FD1\u5FC3\u8DF3",
|
|
26781
|
+
"details.process": "\u8FDB\u7A0B",
|
|
26782
|
+
"details.history": "\u6267\u884C\u5386\u53F2",
|
|
26783
|
+
"details.noHistory": "\u8FD8\u6CA1\u6709\u6267\u884C\u8BB0\u5F55",
|
|
26784
|
+
"details.none": "\u65E0",
|
|
26785
|
+
"details.default": "\u8DDF\u968F\u7CFB\u7EDF\u9ED8\u8BA4",
|
|
26786
|
+
"details.enabledYes": "\u5DF2\u542F\u7528",
|
|
26787
|
+
"details.enabledNo": "\u5DF2\u505C\u7528",
|
|
26423
26788
|
"dialog.cancelTask": "\u53D6\u6D88\u4EFB\u52A1 #{id}\uFF1F",
|
|
26424
26789
|
"dialog.cancelTaskBody": "\u8FD0\u884C\u4E2D\u7684\u4EFB\u52A1\u4F1A\u5728\u4E0B\u4E00\u4E2A\u8F6E\u8BE2\u5468\u671F\u7EC8\u6B62\u5BF9\u5E94\u8FDB\u7A0B\u6811\u3002",
|
|
26425
26790
|
"dialog.retryTask": "\u91CD\u8BD5\u4EFB\u52A1 #{id}\uFF1F",
|
|
@@ -26449,6 +26814,7 @@ var init_ui = __esm({
|
|
|
26449
26814
|
"feedback.templateUpdated": "\u5B9A\u65F6\u4EFB\u52A1\u5DF2\u66F4\u65B0",
|
|
26450
26815
|
"feedback.configSaved": "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58",
|
|
26451
26816
|
"feedback.sessionCommandCopied": "\u4F1A\u8BDD\u547D\u4EE4\u5DF2\u590D\u5236\uFF0C\u53EF\u76F4\u63A5\u7C98\u8D34\u5230\u7EC8\u7AEF\u8FD0\u884C",
|
|
26817
|
+
"feedback.commandCopied": "\u6267\u884C\u547D\u4EE4\u5DF2\u590D\u5236",
|
|
26452
26818
|
"feedback.restarting": "Gateway \u6B63\u5728\u91CD\u542F\uFF0C\u8BF7\u7A0D\u5019\u2026",
|
|
26453
26819
|
"feedback.restartTimeout": "Gateway \u5C1A\u672A\u6062\u590D\uFF0C\u8BF7\u7A0D\u540E\u5237\u65B0\u6216\u68C0\u67E5 PM2 \u72B6\u6001",
|
|
26454
26820
|
"feedback.databaseCleared": "\u6570\u636E\u5E93\u5DF2\u6E05\u7A7A\uFF0C\u5907\u4EFD\u4F4D\u4E8E\uFF1A{path}",
|
|
@@ -26488,7 +26854,7 @@ var init_ui = __esm({
|
|
|
26488
26854
|
"action.hideLogs": "Hide log",
|
|
26489
26855
|
"action.save": "Save settings",
|
|
26490
26856
|
"action.saveAndRestart": "Save and restart",
|
|
26491
|
-
"action.copy": "Copy
|
|
26857
|
+
"action.copy": "Copy raw data",
|
|
26492
26858
|
"action.close": "Close",
|
|
26493
26859
|
"action.confirm": "Confirm",
|
|
26494
26860
|
"action.clearDatabase": "Clear database",
|
|
@@ -26497,6 +26863,13 @@ var init_ui = __esm({
|
|
|
26497
26863
|
"action.updateTask": "Save changes",
|
|
26498
26864
|
"action.createTemplate": "New scheduled task",
|
|
26499
26865
|
"action.saveTemplate": "Save scheduled task",
|
|
26866
|
+
"action.chooseFolder": "Choose folder",
|
|
26867
|
+
"action.chooseThisFolder": "Choose this folder",
|
|
26868
|
+
"action.home": "Home",
|
|
26869
|
+
"action.up": "Up",
|
|
26870
|
+
"action.copyCommand": "Copy command",
|
|
26871
|
+
"action.showHidden": "Show hidden folders",
|
|
26872
|
+
"action.hideHidden": "Hide hidden folders",
|
|
26500
26873
|
"status.pending": "Pending",
|
|
26501
26874
|
"status.running": "Running",
|
|
26502
26875
|
"status.done": "Done",
|
|
@@ -26563,6 +26936,15 @@ var init_ui = __esm({
|
|
|
26563
26936
|
"schedule.hours": "{count} hr",
|
|
26564
26937
|
"schedule.days": "{count} days",
|
|
26565
26938
|
"schedule.overdue": "Overdue",
|
|
26939
|
+
"duration.unit": "Time unit",
|
|
26940
|
+
"duration.seconds": "seconds",
|
|
26941
|
+
"duration.minutes": "minutes",
|
|
26942
|
+
"duration.hours": "hours",
|
|
26943
|
+
"duration.days": "days",
|
|
26944
|
+
"duration.systemDefault": "Use Gateway default timeout",
|
|
26945
|
+
"duration.immediate": "Retry immediately",
|
|
26946
|
+
"duration.custom": "Custom\u2026",
|
|
26947
|
+
"duration.every": "Every {duration}",
|
|
26566
26948
|
"system.worker": "Task execution",
|
|
26567
26949
|
"system.scheduler": "Scheduled task service",
|
|
26568
26950
|
"system.watchdog": "Runtime monitor",
|
|
@@ -26610,6 +26992,9 @@ var init_ui = __esm({
|
|
|
26610
26992
|
"template.interval": "Interval",
|
|
26611
26993
|
"template.runAt": "Run at",
|
|
26612
26994
|
"template.durationHint": "Supports 30s, 5min, 1h, 2d",
|
|
26995
|
+
"template.intervalHint": "Choose a common frequency directly; customize only when necessary.",
|
|
26996
|
+
"template.retryBackoffHint": "How long to wait after a failure before retrying.",
|
|
26997
|
+
"template.timeoutHint": "Leave blank to use the Gateway default task timeout.",
|
|
26613
26998
|
"template.advanced": "More execution settings",
|
|
26614
26999
|
"template.category": "Category",
|
|
26615
27000
|
"template.batchId": "Batch ID",
|
|
@@ -26634,14 +27019,73 @@ var init_ui = __esm({
|
|
|
26634
27019
|
"task.batchHint": "Tasks with the same non-empty batch ID run serially. Blank removes the batch constraint; global concurrency and dependencies still apply.",
|
|
26635
27020
|
"task.projectExisting": "This project has {total} tasks: {running} running, {pending} queued, and {failed} with issues.",
|
|
26636
27021
|
"task.projectNew": "This is a new project group. It appears in the project list after creation.",
|
|
27022
|
+
"catalog.chooseProject": "Choose a project directory first",
|
|
27023
|
+
"catalog.defaultModel": "Use the Agent / OpenCode default model",
|
|
27024
|
+
"catalog.defaultProvider": "Default model",
|
|
27025
|
+
"catalog.provider": "Model provider",
|
|
27026
|
+
"catalog.model": "Model",
|
|
27027
|
+
"catalog.modelHint": "Choose a provider, then a model returned by opencode models for this project. Default does not pass -m.",
|
|
27028
|
+
"catalog.agentHint": "Loaded from opencode agent list for this project.",
|
|
27029
|
+
"catalog.loading": "Loading Agents and models available to this project\u2026",
|
|
27030
|
+
"catalog.loaded": "Loaded {agents} Agents and {models} models from local OpenCode.",
|
|
27031
|
+
"catalog.failed": "Could not load this project\u2019s OpenCode configuration: {error}",
|
|
27032
|
+
"catalog.primary": "primary Agent",
|
|
27033
|
+
"catalog.subagent": "subagent",
|
|
27034
|
+
"catalog.all": "general Agent",
|
|
27035
|
+
"directory.title": "Choose project directory",
|
|
27036
|
+
"directory.subtitle": "OpenCode runs in this directory, and its project-specific Agents and models are loaded.",
|
|
27037
|
+
"directory.empty": "This folder has no subfolders",
|
|
27038
|
+
"logs.command": "Executed command",
|
|
27039
|
+
"logs.output": "Agent output",
|
|
27040
|
+
"logs.error": "Failure reason",
|
|
27041
|
+
"logs.tools": "Tool calls",
|
|
27042
|
+
"logs.raw": "View raw execution log",
|
|
27043
|
+
"logs.noText": "This run produced no displayable text. Inspect the raw log for details.",
|
|
26637
27044
|
"theme.label": "Theme",
|
|
26638
27045
|
"theme.system": "System",
|
|
26639
27046
|
"theme.light": "Light",
|
|
26640
27047
|
"theme.dark": "Dark",
|
|
26641
27048
|
"language.label": "Language",
|
|
26642
|
-
"details.title": "
|
|
26643
|
-
"details.subtitle": "
|
|
26644
|
-
"details.
|
|
27049
|
+
"details.title": "Details",
|
|
27050
|
+
"details.subtitle": "Key information is organized below; raw data is only for troubleshooting.",
|
|
27051
|
+
"details.taskTitle": "Task details",
|
|
27052
|
+
"details.runTitle": "Run details",
|
|
27053
|
+
"details.templateTitle": "Scheduled task details",
|
|
27054
|
+
"details.raw": "View raw data (JSON)",
|
|
27055
|
+
"details.copySuccess": "Raw data copied",
|
|
27056
|
+
"details.id": "ID",
|
|
27057
|
+
"details.project": "Project directory",
|
|
27058
|
+
"details.prompt": "Prompt",
|
|
27059
|
+
"details.result": "Result / failure reason",
|
|
27060
|
+
"details.category": "Category",
|
|
27061
|
+
"details.batch": "Batch",
|
|
27062
|
+
"details.dependency": "Dependency",
|
|
27063
|
+
"details.importance": "Importance",
|
|
27064
|
+
"details.urgency": "Urgency",
|
|
27065
|
+
"details.retryCount": "Retries used / allowed",
|
|
27066
|
+
"details.retryBackoff": "Retry delay",
|
|
27067
|
+
"details.timeout": "Run timeout",
|
|
27068
|
+
"details.createdAt": "Created",
|
|
27069
|
+
"details.updatedAt": "Updated",
|
|
27070
|
+
"details.startedAt": "Started",
|
|
27071
|
+
"details.finishedAt": "Finished",
|
|
27072
|
+
"details.scheduledAt": "Scheduled for",
|
|
27073
|
+
"details.enabled": "Automatic runs",
|
|
27074
|
+
"details.scheduleRule": "Schedule rule",
|
|
27075
|
+
"details.maxInstances": "Automatic scheduling limit",
|
|
27076
|
+
"details.maxRetries": "Failure retries",
|
|
27077
|
+
"details.lastRun": "Last run",
|
|
27078
|
+
"details.nextRun": "Next run",
|
|
27079
|
+
"details.taskId": "Task",
|
|
27080
|
+
"details.session": "OpenCode session",
|
|
27081
|
+
"details.heartbeat": "Latest heartbeat",
|
|
27082
|
+
"details.process": "Processes",
|
|
27083
|
+
"details.history": "Run history",
|
|
27084
|
+
"details.noHistory": "No runs yet",
|
|
27085
|
+
"details.none": "None",
|
|
27086
|
+
"details.default": "Use system default",
|
|
27087
|
+
"details.enabledYes": "Enabled",
|
|
27088
|
+
"details.enabledNo": "Disabled",
|
|
26645
27089
|
"dialog.cancelTask": "Cancel task #{id}?",
|
|
26646
27090
|
"dialog.cancelTaskBody": "A running task will terminate its process tree on the next worker poll.",
|
|
26647
27091
|
"dialog.retryTask": "Retry task #{id}?",
|
|
@@ -26671,6 +27115,7 @@ var init_ui = __esm({
|
|
|
26671
27115
|
"feedback.templateUpdated": "Scheduled task updated",
|
|
26672
27116
|
"feedback.configSaved": "Settings saved",
|
|
26673
27117
|
"feedback.sessionCommandCopied": "Session command copied. Paste it into a terminal to continue.",
|
|
27118
|
+
"feedback.commandCopied": "Execution command copied",
|
|
26674
27119
|
"feedback.restarting": "Gateway is restarting\u2026",
|
|
26675
27120
|
"feedback.restartTimeout": "Gateway has not recovered yet. Refresh later or check PM2 status.",
|
|
26676
27121
|
"feedback.databaseCleared": "Database cleared. Backup: {path}",
|
|
@@ -26881,6 +27326,20 @@ var init_ui = __esm({
|
|
|
26881
27326
|
.danger-card h2 .icon { width:17px; height:17px; }
|
|
26882
27327
|
.danger-card p { max-width:800px; margin:0 0 14px; color:var(--text-2); font-size:12px; }
|
|
26883
27328
|
.log-panel { margin:12px 0; animation:reveal .18s ease both; }
|
|
27329
|
+
.run-log-row td { padding:0 16px 16px; background:color-mix(in srgb,var(--surface-2) 64%,var(--surface)); }
|
|
27330
|
+
.run-log-row .log-panel { margin:0; box-shadow:none; }
|
|
27331
|
+
.log-content { display:grid; gap:14px; padding:16px; }
|
|
27332
|
+
.log-section-head { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:7px; }
|
|
27333
|
+
.run-command,.run-output,.run-error,.run-tools { min-width:0; }
|
|
27334
|
+
.run-command strong,.run-output>strong,.run-error>strong,.run-tools>strong { display:block; margin-bottom:7px; font-size:12px; }
|
|
27335
|
+
.command-cwd { margin-bottom:6px; color:var(--text-3); font-family:"SFMono-Regular",Consolas,monospace; font-size:10px; overflow-wrap:anywhere; }
|
|
27336
|
+
.run-command pre,.run-output pre,.run-error pre { margin:0; padding:12px; overflow:auto; border:1px solid var(--border); border-radius:9px;
|
|
27337
|
+
color:var(--text-2); background:var(--surface-2); font-family:"SFMono-Regular",Consolas,monospace; font-size:11px; white-space:pre-wrap; overflow-wrap:anywhere; }
|
|
27338
|
+
.run-output pre { color:var(--text); font-family:inherit; font-size:13px; line-height:1.65; }
|
|
27339
|
+
.run-error pre { color:var(--red); border-color:color-mix(in srgb,var(--red) 28%,var(--border)); background:var(--red-soft); }
|
|
27340
|
+
.raw-log { padding-top:12px; border-top:1px solid var(--border); }
|
|
27341
|
+
.raw-log summary { color:var(--text-2); cursor:pointer; font-size:12px; font-weight:650; }
|
|
27342
|
+
.raw-log .log-box { margin-top:10px; border-radius:9px; }
|
|
26884
27343
|
.log-box { max-height:360px; overflow:auto; padding:16px; color:var(--text-2); background:#0b1018; font-family:"SFMono-Regular",Consolas,monospace;
|
|
26885
27344
|
font-size:12px; white-space:pre-wrap; overflow-wrap:anywhere; }
|
|
26886
27345
|
:root[data-theme="light"] .log-box { color:#dbe5f3; }
|
|
@@ -26899,14 +27358,48 @@ var init_ui = __esm({
|
|
|
26899
27358
|
.form-field-wide { grid-column:1 / -1; }
|
|
26900
27359
|
.form-field input,.form-field select,.form-field textarea { width:100%; min-height:39px; padding:8px 10px; border:1px solid var(--border); border-radius:9px;
|
|
26901
27360
|
outline:none; color:var(--text); background:var(--surface-2); font-weight:450; }
|
|
27361
|
+
.field-action { display:flex; align-items:stretch; gap:7px; }
|
|
27362
|
+
.field-action input { min-width:0; flex:1; }
|
|
27363
|
+
.field-action .btn { flex:0 0 auto; white-space:nowrap; }
|
|
27364
|
+
.model-selector { display:grid; grid-template-columns:minmax(120px,.75fr) minmax(0,1.25fr); gap:7px; }
|
|
27365
|
+
.duration-picker { display:grid; gap:7px; }
|
|
27366
|
+
.duration-control { display:grid; grid-template-columns:minmax(0,1fr) 112px; gap:7px; }
|
|
27367
|
+
.duration-control input,.duration-control select { min-width:0; }
|
|
26902
27368
|
.form-field textarea { resize:vertical; line-height:1.5; }
|
|
26903
27369
|
.form-field input:focus,.form-field select:focus,.form-field textarea:focus { border-color:var(--primary); box-shadow:var(--focus); background:var(--surface); }
|
|
26904
27370
|
.form-field small { color:var(--text-3); font-size:10px; font-weight:450; }
|
|
26905
27371
|
.advanced-fields { margin-top:18px; padding-top:14px; border-top:1px solid var(--border); }
|
|
26906
27372
|
.advanced-fields summary { margin-bottom:14px; color:var(--text-2); cursor:pointer; font-size:12px; font-weight:700; }
|
|
26907
27373
|
.form-note { margin:16px 0 0; color:var(--text-3); font-size:11px; }
|
|
26908
|
-
.
|
|
26909
|
-
|
|
27374
|
+
.catalog-status[data-state="loading"] { color:var(--blue); }
|
|
27375
|
+
.catalog-status[data-state="ready"] { color:var(--green); }
|
|
27376
|
+
.catalog-status[data-state="error"] { color:var(--red); }
|
|
27377
|
+
.directory-dialog { width:min(720px,calc(100% - 32px)); }
|
|
27378
|
+
.directory-toolbar { display:flex; align-items:center; gap:8px; margin-bottom:12px; }
|
|
27379
|
+
.directory-path { min-width:0; flex:1; padding:9px 11px; overflow:hidden; border:1px solid var(--border); border-radius:9px;
|
|
27380
|
+
color:var(--text-2); background:var(--surface-2); font-family:"SFMono-Regular",Consolas,monospace; font-size:11px; text-overflow:ellipsis; white-space:nowrap; }
|
|
27381
|
+
.directory-list { min-height:260px; max-height:48vh; display:grid; align-content:start; gap:6px; overflow:auto; }
|
|
27382
|
+
.directory-item { width:100%; min-height:40px; display:flex; align-items:center; gap:9px; padding:0 11px; border:1px solid transparent; border-radius:9px;
|
|
27383
|
+
color:var(--text-2); background:transparent; cursor:pointer; text-align:left; transition:background-color .15s ease,border-color .15s ease,color .15s ease,transform .12s ease; }
|
|
27384
|
+
.directory-item:hover { color:var(--text); border-color:var(--border); background:var(--surface-2); }
|
|
27385
|
+
.directory-item:active { transform:scale(.99); }
|
|
27386
|
+
.directory-item .icon { width:17px; height:17px; color:var(--primary); flex:0 0 auto; }
|
|
27387
|
+
.directory-empty { min-height:220px; display:grid; place-items:center; color:var(--text-3); }
|
|
27388
|
+
.detail-view { display:grid; gap:16px; }
|
|
27389
|
+
.detail-grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; }
|
|
27390
|
+
.detail-item { min-width:0; padding:12px 13px; border:1px solid var(--border); border-radius:10px; background:var(--surface-2); }
|
|
27391
|
+
.detail-item.wide { grid-column:1 / -1; }
|
|
27392
|
+
.detail-label { margin-bottom:5px; color:var(--text-3); font-size:10px; font-weight:750; letter-spacing:.045em; text-transform:uppercase; }
|
|
27393
|
+
.detail-value { color:var(--text); font-size:13px; line-height:1.55; overflow-wrap:anywhere; }
|
|
27394
|
+
.detail-value.mono { font-family:"SFMono-Regular",Consolas,monospace; font-size:11px; }
|
|
27395
|
+
.detail-value.long { max-height:240px; margin:0; overflow:auto; white-space:pre-wrap; }
|
|
27396
|
+
.detail-history h3 { margin:0 0 8px; font-size:13px; }
|
|
27397
|
+
.detail-history-list { display:grid; gap:7px; }
|
|
27398
|
+
.detail-history-item { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:9px 11px; border:1px solid var(--border); border-radius:9px; background:var(--surface-2); font-size:11px; }
|
|
27399
|
+
.detail-raw { padding-top:12px; border-top:1px solid var(--border); }
|
|
27400
|
+
.detail-raw summary { color:var(--text-2); cursor:pointer; font-size:12px; font-weight:650; }
|
|
27401
|
+
.json-view { max-height:320px; margin:10px 0 0; padding:15px; overflow:auto; border:1px solid var(--border); border-radius:10px; color:var(--text-2);
|
|
27402
|
+
background:var(--surface-2); font-family:"SFMono-Regular",Consolas,monospace; font-size:11px; white-space:pre-wrap; overflow-wrap:anywhere; }
|
|
26910
27403
|
.confirm-copy { color:var(--text-2); margin:0; }
|
|
26911
27404
|
.confirm-copy strong { display:block; margin-bottom:5px; color:var(--text); font-size:15px; }
|
|
26912
27405
|
.danger-input { width:100%; height:40px; margin-top:14px; padding:0 12px; border:1px solid var(--border); border-radius:9px; outline:none;
|
|
@@ -26970,9 +27463,17 @@ var init_ui = __esm({
|
|
|
26970
27463
|
.responsive-table td[data-primary]::before { display:none; }
|
|
26971
27464
|
.responsive-table .task-prompt { max-width:100%; }
|
|
26972
27465
|
.responsive-table .actions { justify-content:flex-start; }
|
|
27466
|
+
.responsive-table .run-log-row { padding:0; overflow:hidden; }
|
|
27467
|
+
.responsive-table .run-log-cell { display:block; padding:0; }
|
|
27468
|
+
.responsive-table .run-log-cell::before { display:none; }
|
|
26973
27469
|
.project-grid { grid-template-columns:1fr; }
|
|
26974
27470
|
.template-form-grid { grid-template-columns:1fr; }
|
|
27471
|
+
.detail-grid { grid-template-columns:1fr; }
|
|
27472
|
+
.detail-item.wide { grid-column:auto; }
|
|
26975
27473
|
.form-field-wide { grid-column:auto; }
|
|
27474
|
+
.field-action { align-items:stretch; flex-direction:column; }
|
|
27475
|
+
.field-action .btn { width:100%; }
|
|
27476
|
+
.model-selector { grid-template-columns:1fr; }
|
|
26976
27477
|
}
|
|
26977
27478
|
@media (max-width:520px) {
|
|
26978
27479
|
.stats-grid,.stats-grid.three { grid-template-columns:1fr 1fr; }
|
|
@@ -27002,11 +27503,21 @@ __export(web_exports, {
|
|
|
27002
27503
|
dashboardApp: () => dashboardApp,
|
|
27003
27504
|
default: () => web_default,
|
|
27004
27505
|
isSafeDashboardRestartTarget: () => isSafeDashboardRestartTarget,
|
|
27506
|
+
presentRunLog: () => presentRunLog,
|
|
27005
27507
|
resolveDashboardConfigState: () => resolveDashboardConfigState,
|
|
27006
27508
|
setDashboardRuntimeConfig: () => setDashboardRuntimeConfig
|
|
27007
27509
|
});
|
|
27008
|
-
import {
|
|
27009
|
-
|
|
27510
|
+
import {
|
|
27511
|
+
existsSync as existsSync8,
|
|
27512
|
+
mkdirSync as mkdirSync5,
|
|
27513
|
+
readFileSync as readFileSync5,
|
|
27514
|
+
readdirSync as readdirSync2,
|
|
27515
|
+
renameSync as renameSync2,
|
|
27516
|
+
statSync as statSync4,
|
|
27517
|
+
writeFileSync as writeFileSync3
|
|
27518
|
+
} from "fs";
|
|
27519
|
+
import { homedir as homedir5 } from "os";
|
|
27520
|
+
import { basename as basename3, dirname as dirname9, join as join7 } from "path";
|
|
27010
27521
|
function setDashboardRuntimeConfig(config) {
|
|
27011
27522
|
runtimeConfig = config === null ? null : structuredClone(config);
|
|
27012
27523
|
}
|
|
@@ -27047,6 +27558,23 @@ function parsePositiveInteger2(value) {
|
|
|
27047
27558
|
function parseTaskStatus2(value) {
|
|
27048
27559
|
return TASK_STATUSES2.has(value) ? value : null;
|
|
27049
27560
|
}
|
|
27561
|
+
function listChildDirectories(path) {
|
|
27562
|
+
return readdirSync2(path, { withFileTypes: true }).flatMap((entry) => {
|
|
27563
|
+
const entryPath = join7(path, entry.name);
|
|
27564
|
+
if (entry.isDirectory()) return [{ name: entry.name, path: entryPath, hidden: entry.name.startsWith(".") }];
|
|
27565
|
+
if (!entry.isSymbolicLink()) return [];
|
|
27566
|
+
try {
|
|
27567
|
+
return statSync4(entryPath).isDirectory() ? [{ name: entry.name, path: entryPath, hidden: entry.name.startsWith(".") }] : [];
|
|
27568
|
+
} catch {
|
|
27569
|
+
return [];
|
|
27570
|
+
}
|
|
27571
|
+
}).sort((left, right) => {
|
|
27572
|
+
const leftHidden = left.name.startsWith(".");
|
|
27573
|
+
const rightHidden = right.name.startsWith(".");
|
|
27574
|
+
if (leftHidden !== rightHidden) return leftHidden ? 1 : -1;
|
|
27575
|
+
return left.name.localeCompare(right.name);
|
|
27576
|
+
});
|
|
27577
|
+
}
|
|
27050
27578
|
function parseTaskPayload(value) {
|
|
27051
27579
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
27052
27580
|
throw new Error("\u8BF7\u6C42\u5185\u5BB9\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
@@ -27203,6 +27731,66 @@ function formatDuration(startAt, endAt) {
|
|
|
27203
27731
|
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
|
|
27204
27732
|
return `${Math.floor(seconds / 3600)}h ${Math.floor(seconds % 3600 / 60)}m`;
|
|
27205
27733
|
}
|
|
27734
|
+
function recordValue(value) {
|
|
27735
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
27736
|
+
}
|
|
27737
|
+
function shellQuote(value) {
|
|
27738
|
+
if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value)) return value;
|
|
27739
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
27740
|
+
}
|
|
27741
|
+
function presentRunLog(log) {
|
|
27742
|
+
let command = null;
|
|
27743
|
+
const textParts = [];
|
|
27744
|
+
const errors = [];
|
|
27745
|
+
const tools = [];
|
|
27746
|
+
for (const line of log.split("\n")) {
|
|
27747
|
+
const trimmed = line.trim();
|
|
27748
|
+
if (!trimmed) continue;
|
|
27749
|
+
let parsed = null;
|
|
27750
|
+
try {
|
|
27751
|
+
parsed = recordValue(JSON.parse(trimmed));
|
|
27752
|
+
} catch {
|
|
27753
|
+
errors.push(line);
|
|
27754
|
+
continue;
|
|
27755
|
+
}
|
|
27756
|
+
if (!parsed) continue;
|
|
27757
|
+
if (parsed.type === "supertask_command") {
|
|
27758
|
+
const executable = typeof parsed.executable === "string" ? parsed.executable : null;
|
|
27759
|
+
const cwd = typeof parsed.cwd === "string" ? parsed.cwd : null;
|
|
27760
|
+
const args = Array.isArray(parsed.args) && parsed.args.every((item) => typeof item === "string") ? parsed.args : null;
|
|
27761
|
+
if (executable && cwd && args) {
|
|
27762
|
+
command = {
|
|
27763
|
+
cwd,
|
|
27764
|
+
command: `cd ${shellQuote(cwd)} && ${[executable, ...args].map(shellQuote).join(" ")}`
|
|
27765
|
+
};
|
|
27766
|
+
}
|
|
27767
|
+
continue;
|
|
27768
|
+
}
|
|
27769
|
+
const part = recordValue(parsed.part);
|
|
27770
|
+
const eventType = typeof parsed.type === "string" ? parsed.type : "";
|
|
27771
|
+
const partType = typeof part?.type === "string" ? part.type : "";
|
|
27772
|
+
const text2 = typeof part?.text === "string" ? part.text : typeof parsed.text === "string" ? parsed.text : null;
|
|
27773
|
+
if (text2 && (eventType === "text" || partType === "text")) textParts.push(text2);
|
|
27774
|
+
const tool = typeof part?.tool === "string" ? part.tool : typeof parsed.tool === "string" ? parsed.tool : null;
|
|
27775
|
+
if (tool && (eventType === "tool_use" || partType === "tool")) tools.push(tool);
|
|
27776
|
+
const error = typeof parsed.error === "string" ? parsed.error : typeof part?.error === "string" ? part.error : null;
|
|
27777
|
+
if (error) errors.push(error);
|
|
27778
|
+
}
|
|
27779
|
+
return {
|
|
27780
|
+
command,
|
|
27781
|
+
text: textParts.join("\n").trim(),
|
|
27782
|
+
errors: [...new Set(errors)],
|
|
27783
|
+
tools
|
|
27784
|
+
};
|
|
27785
|
+
}
|
|
27786
|
+
function renderRunLog(runId, taskName, log, locale) {
|
|
27787
|
+
const presentation = presentRunLog(log);
|
|
27788
|
+
const command = presentation.command ? `<div class="run-command"><div class="log-section-head"><strong>${t(locale, "logs.command")}</strong><button type="button" class="btn" onclick="copyRunCommand(${runId})">${icon("copy")}${t(locale, "action.copyCommand")}</button></div><div class="command-cwd">${esc(presentation.command.cwd)}</div><pre id="command-${runId}">${esc(presentation.command.command)}</pre></div>` : "";
|
|
27789
|
+
const errors = presentation.errors.length > 0 ? `<div class="run-error"><strong>${t(locale, "logs.error")}</strong><pre>${esc(presentation.errors.join("\n"))}</pre></div>` : "";
|
|
27790
|
+
const tools = presentation.tools.length > 0 ? `<div class="run-tools"><strong>${t(locale, "logs.tools")}</strong><div class="actions">${presentation.tools.map((tool) => `<span class="tag">${esc(tool)}</span>`).join("")}</div></div>` : "";
|
|
27791
|
+
const output = `<div class="run-output"><strong>${t(locale, "logs.output")}</strong><pre>${esc(presentation.text || t(locale, "logs.noText"))}</pre></div>`;
|
|
27792
|
+
return `<section class="panel log-panel"><div class="panel-head"><h3>Run #${runId} \xB7 ${esc(taskName)}</h3></div><div class="log-content">${command}${errors}${output}${tools}<details class="raw-log"><summary>${t(locale, "logs.raw")}</summary><div class="log-box">${esc(log)}</div></details></div></section>`;
|
|
27793
|
+
}
|
|
27206
27794
|
function esc(value) {
|
|
27207
27795
|
if (!value) return "";
|
|
27208
27796
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -27234,6 +27822,25 @@ function emptyState(title, hint, code = "") {
|
|
|
27234
27822
|
return `<div class="empty-state"><div><div class="empty-icon">${icon("inbox")}</div>
|
|
27235
27823
|
<h3>${title}</h3><p>${hint}</p>${code ? `<code>${code}</code>` : ""}</div></div>`;
|
|
27236
27824
|
}
|
|
27825
|
+
function durationControl(locale, id, value, kind) {
|
|
27826
|
+
const units = [
|
|
27827
|
+
{ value: "s", label: t(locale, "duration.seconds") },
|
|
27828
|
+
{ value: "min", label: t(locale, "duration.minutes") },
|
|
27829
|
+
{ value: "h", label: t(locale, "duration.hours") },
|
|
27830
|
+
{ value: "d", label: t(locale, "duration.days") }
|
|
27831
|
+
];
|
|
27832
|
+
const values = kind === "interval" ? [3e5, 9e5, 18e5, 36e5, 216e5, 432e5, 864e5] : kind === "retry" ? [0, 1e4, 3e4, 6e4, 3e5] : [3e5, 9e5, 18e5, 36e5, 72e5, 144e5];
|
|
27833
|
+
const presets = [
|
|
27834
|
+
...kind === "timeout" ? [{ value: "", label: t(locale, "duration.systemDefault") }] : [],
|
|
27835
|
+
...values.map((milliseconds) => ({
|
|
27836
|
+
value: String(milliseconds),
|
|
27837
|
+
label: milliseconds === 0 ? t(locale, "duration.immediate") : kind === "interval" ? t(locale, "duration.every", { duration: formatInterval(milliseconds, locale) }) : formatInterval(milliseconds, locale)
|
|
27838
|
+
})),
|
|
27839
|
+
{ value: "custom", label: t(locale, "duration.custom") }
|
|
27840
|
+
];
|
|
27841
|
+
const selected = value === null ? "" : String(value);
|
|
27842
|
+
return `<div class="duration-picker"><select id="${id}-preset" onchange="updateDurationControl('${id}')">${presets.map((item) => `<option value="${item.value}" ${item.value === selected ? "selected" : ""}>${item.label}</option>`).join("")}</select><div id="${id}-custom" class="duration-control" hidden><input id="${id}-value" type="number" min="${kind === "retry" ? 0 : 0.1}" step="0.1" inputmode="decimal"><select id="${id}-unit" aria-label="${t(locale, "duration.unit")}">${units.map((item) => `<option value="${item.value}">${item.label}</option>`).join("")}</select></div></div>`;
|
|
27843
|
+
}
|
|
27237
27844
|
function formatInterval(milliseconds, locale) {
|
|
27238
27845
|
const formatter = new Intl.NumberFormat(locale === "en" ? "en-US" : "zh-CN", {
|
|
27239
27846
|
maximumFractionDigits: 1
|
|
@@ -27262,6 +27869,8 @@ var init_web = __esm({
|
|
|
27262
27869
|
init_drizzle_orm();
|
|
27263
27870
|
init_db2();
|
|
27264
27871
|
init_duration();
|
|
27872
|
+
init_opencode_catalog();
|
|
27873
|
+
init_task_working_directory();
|
|
27265
27874
|
init_database_maintenance_service();
|
|
27266
27875
|
init_task_run_service();
|
|
27267
27876
|
init_task_service();
|
|
@@ -27315,6 +27924,33 @@ var init_web = __esm({
|
|
|
27315
27924
|
const health = getGatewayHealth();
|
|
27316
27925
|
return c.json(health, health.status === "ok" ? 200 : 503);
|
|
27317
27926
|
});
|
|
27927
|
+
app.get("/api/filesystem/directories", (c) => {
|
|
27928
|
+
const requestedPath = c.req.query("path")?.trim() || homedir5();
|
|
27929
|
+
try {
|
|
27930
|
+
validateTaskWorkingDirectory(requestedPath);
|
|
27931
|
+
return c.json({
|
|
27932
|
+
path: requestedPath,
|
|
27933
|
+
parent: dirname9(requestedPath),
|
|
27934
|
+
home: homedir5(),
|
|
27935
|
+
directories: listChildDirectories(requestedPath)
|
|
27936
|
+
});
|
|
27937
|
+
} catch (error) {
|
|
27938
|
+
return c.json({
|
|
27939
|
+
error: error instanceof Error ? error.message : String(error)
|
|
27940
|
+
}, 400);
|
|
27941
|
+
}
|
|
27942
|
+
});
|
|
27943
|
+
app.get("/api/opencode/catalog", async (c) => {
|
|
27944
|
+
const cwd = c.req.query("cwd")?.trim();
|
|
27945
|
+
if (!cwd) return c.json({ error: "cwd \u4E0D\u80FD\u4E3A\u7A7A" }, 400);
|
|
27946
|
+
try {
|
|
27947
|
+
return c.json(await loadOpenCodeCatalog(cwd));
|
|
27948
|
+
} catch (error) {
|
|
27949
|
+
return c.json({
|
|
27950
|
+
error: error instanceof Error ? error.message : String(error)
|
|
27951
|
+
}, 400);
|
|
27952
|
+
}
|
|
27953
|
+
});
|
|
27318
27954
|
app.get("/", async (c) => {
|
|
27319
27955
|
const locale = resolveLocale(c);
|
|
27320
27956
|
const page = parsePositiveInteger2(c.req.query("page") || "1");
|
|
@@ -27459,13 +28095,14 @@ var init_web = __esm({
|
|
|
27459
28095
|
<div class="dialog-body">
|
|
27460
28096
|
<div class="template-form-grid">
|
|
27461
28097
|
<label class="form-field"><span>${t(locale, "template.name")}</span><input id="task-name" required maxlength="200" autocomplete="off"></label>
|
|
27462
|
-
<label class="form-field"><span>${t(locale, "template.cwd")}</span><input id="task-cwd" required autocomplete="off" list="task-cwd-options" placeholder="/path/to/project" oninput="updateTaskProjectStatus()"><small>${t(locale, "template.cwdHint")}</small></label>
|
|
28098
|
+
<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>
|
|
27463
28099
|
<datalist id="task-cwd-options">${projects.map((project) => `<option value="${esc(project.cwd)}"></option>`).join("")}</datalist>
|
|
27464
|
-
<label class="form-field"><span>${t(locale, "template.agent")}</span><
|
|
27465
|
-
<label class="form-field"><span>${t(locale, "template.model")}</span><
|
|
28100
|
+
<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>
|
|
28101
|
+
<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="populateModelOptions('task')"><option value="">${t(locale, "catalog.defaultProvider")}</option></select><select id="task-model" required aria-label="${t(locale, "catalog.model")}" disabled><option value="default">${t(locale, "catalog.defaultModel")}</option></select></div><small>${t(locale, "catalog.modelHint")}</small></label>
|
|
27466
28102
|
<label class="form-field form-field-wide"><span>${t(locale, "template.prompt")}</span><textarea id="task-prompt" rows="6" required></textarea></label>
|
|
27467
28103
|
</div>
|
|
27468
28104
|
<p id="task-project-status" class="form-note"></p>
|
|
28105
|
+
<p id="task-catalog-status" class="form-note catalog-status"></p>
|
|
27469
28106
|
<details class="advanced-fields">
|
|
27470
28107
|
<summary>${t(locale, "template.advanced")}</summary>
|
|
27471
28108
|
<div class="template-form-grid">
|
|
@@ -27474,8 +28111,8 @@ var init_web = __esm({
|
|
|
27474
28111
|
<label class="form-field"><span>${t(locale, "template.importance")}</span><input id="task-importance" type="number" min="1" max="5" step="1" value="3" required></label>
|
|
27475
28112
|
<label class="form-field"><span>${t(locale, "template.urgency")}</span><input id="task-urgency" type="number" min="1" max="5" step="1" value="3" required></label>
|
|
27476
28113
|
<label class="form-field"><span>${t(locale, "template.maxRetries")}</span><input id="task-max-retries" type="number" min="0" max="1000" step="1" value="3" required></label>
|
|
27477
|
-
<label class="form-field"><span>${t(locale, "template.retryBackoff")}</span
|
|
27478
|
-
<label class="form-field"><span>${t(locale, "template.timeout")}</span
|
|
28114
|
+
<label class="form-field"><span>${t(locale, "template.retryBackoff")}</span>${durationControl(locale, "task-retry-backoff", 3e4, "retry")}<small>${t(locale, "template.retryBackoffHint")}</small></label>
|
|
28115
|
+
<label class="form-field"><span>${t(locale, "template.timeout")}</span>${durationControl(locale, "task-timeout", null, "timeout")}<small>${t(locale, "template.timeoutHint")}</small></label>
|
|
27479
28116
|
</div>
|
|
27480
28117
|
</details>
|
|
27481
28118
|
</div>
|
|
@@ -27535,15 +28172,16 @@ var init_web = __esm({
|
|
|
27535
28172
|
<div class="dialog-body">
|
|
27536
28173
|
<div class="template-form-grid">
|
|
27537
28174
|
<label class="form-field"><span>${t(locale, "template.name")}</span><input id="template-name" required maxlength="200" autocomplete="off"></label>
|
|
27538
|
-
<label class="form-field"><span>${t(locale, "template.cwd")}</span><input id="template-cwd" required autocomplete="off" placeholder="/path/to/project"><small>${t(locale, "template.cwdHint")}</small></label>
|
|
27539
|
-
<label class="form-field"><span>${t(locale, "template.agent")}</span><
|
|
27540
|
-
<label class="form-field"><span>${t(locale, "template.model")}</span><
|
|
28175
|
+
<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>
|
|
28176
|
+
<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>
|
|
28177
|
+
<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="populateModelOptions('template')"><option value="">${t(locale, "catalog.defaultProvider")}</option></select><select id="template-model" required aria-label="${t(locale, "catalog.model")}" disabled><option value="default">${t(locale, "catalog.defaultModel")}</option></select></div><small>${t(locale, "catalog.modelHint")}</small></label>
|
|
27541
28178
|
<label class="form-field form-field-wide"><span>${t(locale, "template.prompt")}</span><textarea id="template-prompt" rows="6" required></textarea></label>
|
|
27542
28179
|
<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>
|
|
27543
28180
|
<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>
|
|
27544
|
-
<label id="template-interval-field" class="form-field"><span>${t(locale, "template.interval")}</span
|
|
28181
|
+
<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>
|
|
27545
28182
|
<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>
|
|
27546
28183
|
</div>
|
|
28184
|
+
<p id="template-catalog-status" class="form-note catalog-status"></p>
|
|
27547
28185
|
<details class="advanced-fields">
|
|
27548
28186
|
<summary>${t(locale, "template.advanced")}</summary>
|
|
27549
28187
|
<div class="template-form-grid">
|
|
@@ -27553,8 +28191,8 @@ var init_web = __esm({
|
|
|
27553
28191
|
<label class="form-field"><span>${t(locale, "template.urgency")}</span><input id="template-urgency" type="number" min="1" max="5" step="1" value="3" required></label>
|
|
27554
28192
|
<label class="form-field"><span>${t(locale, "template.maxInstances")}</span><input id="template-max-instances" type="number" min="1" max="1000" step="1" value="1" required><small>${t(locale, "template.maxInstancesHint")}</small></label>
|
|
27555
28193
|
<label class="form-field"><span>${t(locale, "template.maxRetries")}</span><input id="template-max-retries" type="number" min="0" max="1000" step="1" value="3" required></label>
|
|
27556
|
-
<label class="form-field"><span>${t(locale, "template.retryBackoff")}</span
|
|
27557
|
-
<label class="form-field"><span>${t(locale, "template.timeout")}</span
|
|
28194
|
+
<label class="form-field"><span>${t(locale, "template.retryBackoff")}</span>${durationControl(locale, "template-retry-backoff", 3e4, "retry")}<small>${t(locale, "template.retryBackoffHint")}</small></label>
|
|
28195
|
+
<label class="form-field"><span>${t(locale, "template.timeout")}</span>${durationControl(locale, "template-timeout", null, "timeout")}<small>${t(locale, "template.timeoutHint")}</small></label>
|
|
27558
28196
|
</div>
|
|
27559
28197
|
</details>
|
|
27560
28198
|
<p class="form-note">${t(locale, "template.futureOnly")}</p>
|
|
@@ -27591,14 +28229,11 @@ var init_web = __esm({
|
|
|
27591
28229
|
const total = Number(totalResult[0]?.count ?? 0);
|
|
27592
28230
|
const totalPages = Math.max(1, Math.ceil(total / limit));
|
|
27593
28231
|
if (page > totalPages) return c.redirect(`/runs?page=${totalPages}`);
|
|
27594
|
-
const logs = [];
|
|
27595
28232
|
const rows = runs.map((run) => {
|
|
27596
28233
|
const status = safeStatus(run.status);
|
|
27597
28234
|
const resumable = isValidSessionId(run.sessionId);
|
|
27598
|
-
|
|
27599
|
-
|
|
27600
|
-
}
|
|
27601
|
-
return `<tr>
|
|
28235
|
+
const log = run.log ? renderRunLog(run.id, run.taskName, run.log, locale) : "";
|
|
28236
|
+
return `<tr class="run-summary-row">
|
|
27602
28237
|
<td class="faint" data-label="${t(locale, "table.run")}">#${run.id}</td>
|
|
27603
28238
|
<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"><span class="tag">${esc(run.model)}</span></div>` : ""}</td>
|
|
27604
28239
|
<td data-label="${t(locale, "table.agent")}"><span class="tag">${esc(run.taskAgent)}</span></td>
|
|
@@ -27609,7 +28244,7 @@ var init_web = __esm({
|
|
|
27609
28244
|
<td data-label="${t(locale, "table.actions")}"><div class="actions"><button type="button" class="btn" onclick="showRunDetail(${run.id})">${t(locale, "action.details")}</button>
|
|
27610
28245
|
${resumable ? `<button type="button" class="btn" onclick="copySessionCommand(${run.id})">${icon("copy")}${t(locale, "action.continueSession")}</button>` : ""}
|
|
27611
28246
|
${run.log ? `<button type="button" class="btn" aria-expanded="false" onclick="toggleLog(${run.id},this)">${t(locale, "action.logs")}</button>` : ""}</div></td>
|
|
27612
|
-
</tr
|
|
28247
|
+
</tr>${log ? `<tr id="log-${run.id}" class="run-log-row" hidden><td class="run-log-cell" colspan="8">${log}</td></tr>` : ""}`;
|
|
27613
28248
|
}).join("");
|
|
27614
28249
|
const body = `
|
|
27615
28250
|
<div class="stats-grid">
|
|
@@ -27619,7 +28254,7 @@ var init_web = __esm({
|
|
|
27619
28254
|
${statCard(runs.filter((run) => run.status === "running").length, t(locale, "stats.pageRunning"), "tone-blue", icon("activity"), "reveal-delay-2")}
|
|
27620
28255
|
</div>
|
|
27621
28256
|
<section class="panel reveal reveal-delay-2">${runs.length === 0 ? emptyState(t(locale, "empty.runs"), "") : `<div class="table-wrap"><table class="responsive-table"><thead><tr><th>${t(locale, "table.run")}</th><th>${t(locale, "table.task")}</th><th>${t(locale, "table.agent")}</th><th>${t(locale, "table.session")}</th><th>${t(locale, "table.status")}</th><th>${t(locale, "table.duration")}</th><th>${t(locale, "table.heartbeat")}</th><th>${t(locale, "table.actions")}</th></tr></thead><tbody>${rows}</tbody></table></div>`}</section>
|
|
27622
|
-
${
|
|
28257
|
+
${pagination(locale, "/runs", page, totalPages, total)}`;
|
|
27623
28258
|
return c.html(renderLayout({ locale, activeTab: "runs", body }));
|
|
27624
28259
|
});
|
|
27625
28260
|
app.get("/system", async (c) => {
|
|
@@ -27726,7 +28361,11 @@ var init_web = __esm({
|
|
|
27726
28361
|
const task = await TaskService.getById(id);
|
|
27727
28362
|
if (!task) return c.json({ error: "not found" }, 404);
|
|
27728
28363
|
const runs = await TaskRunService.listByTaskId(id);
|
|
27729
|
-
return c.json({
|
|
28364
|
+
return c.json({
|
|
28365
|
+
...task,
|
|
28366
|
+
_resultPresentation: task.resultLog ? presentRunLog(task.resultLog) : null,
|
|
28367
|
+
_runs: runs
|
|
28368
|
+
});
|
|
27730
28369
|
});
|
|
27731
28370
|
app.get("/api/runs/:id", async (c) => {
|
|
27732
28371
|
const id = parsePositiveInteger2(c.req.param("id"));
|
|
@@ -28231,7 +28870,6 @@ init_db2();
|
|
|
28231
28870
|
init_duration();
|
|
28232
28871
|
init_pm2();
|
|
28233
28872
|
init_config();
|
|
28234
|
-
import { spawnSync as spawnSync4 } from "child_process";
|
|
28235
28873
|
|
|
28236
28874
|
// src/cli/i18n.ts
|
|
28237
28875
|
function requestedLanguage(argv) {
|
|
@@ -28444,6 +29082,118 @@ function parseTaskStatus(value) {
|
|
|
28444
29082
|
|
|
28445
29083
|
// src/cli/index.ts
|
|
28446
29084
|
init_update2();
|
|
29085
|
+
|
|
29086
|
+
// src/cli/doctor-smoke.ts
|
|
29087
|
+
init_task_service();
|
|
29088
|
+
init_task_run_service();
|
|
29089
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
29090
|
+
import { resolve as resolve5 } from "path";
|
|
29091
|
+
function tail(value, maxLength = 2e3) {
|
|
29092
|
+
if (!value) return null;
|
|
29093
|
+
return value.length <= maxLength ? value : value.slice(-maxLength);
|
|
29094
|
+
}
|
|
29095
|
+
function extractOpenCodeText(log) {
|
|
29096
|
+
if (!log) return "";
|
|
29097
|
+
const parts = [];
|
|
29098
|
+
for (const line of log.split("\n")) {
|
|
29099
|
+
try {
|
|
29100
|
+
const parsed = JSON.parse(line);
|
|
29101
|
+
if (parsed.type === "text" && parsed.part?.type === "text" && typeof parsed.part.text === "string") {
|
|
29102
|
+
parts.push(parsed.part.text);
|
|
29103
|
+
}
|
|
29104
|
+
} catch {
|
|
29105
|
+
}
|
|
29106
|
+
}
|
|
29107
|
+
return parts.join("\n").trim();
|
|
29108
|
+
}
|
|
29109
|
+
async function runDoctorSmoke(options) {
|
|
29110
|
+
if (!options.agent.trim()) throw new Error("smoke agent \u4E0D\u80FD\u4E3A\u7A7A");
|
|
29111
|
+
if (!Number.isInteger(options.timeoutMs) || options.timeoutMs < 1e3 || options.timeoutMs > 6048e5) {
|
|
29112
|
+
throw new Error("smoke timeout \u5FC5\u987B\u662F 1 \u79D2\u5230 7 \u5929\u4E4B\u95F4\u7684\u6574\u6570\u6BEB\u79D2\u503C");
|
|
29113
|
+
}
|
|
29114
|
+
const cwd = resolve5(options.cwd);
|
|
29115
|
+
const marker = options.marker ?? `SUPERTASK_SMOKE_${randomUUID2().replaceAll("-", "").toUpperCase()}`;
|
|
29116
|
+
const model = options.model && options.model !== "default" ? options.model : void 0;
|
|
29117
|
+
const startedAt = Date.now();
|
|
29118
|
+
const task = await TaskService.add({
|
|
29119
|
+
name: "[doctor] Gateway real smoke test",
|
|
29120
|
+
agent: options.agent,
|
|
29121
|
+
model,
|
|
29122
|
+
prompt: `\u4E0D\u8981\u8C03\u7528\u4EFB\u4F55\u5DE5\u5177\u3002\u53EA\u56DE\u590D\u8FD9\u4E00\u884C\uFF1A${marker}`,
|
|
29123
|
+
cwd,
|
|
29124
|
+
category: "diagnostic",
|
|
29125
|
+
importance: 5,
|
|
29126
|
+
urgency: 5,
|
|
29127
|
+
batchId: `doctor-smoke-${randomUUID2()}`,
|
|
29128
|
+
maxRetries: 0,
|
|
29129
|
+
retryBackoffMs: 0,
|
|
29130
|
+
timeoutMs: options.timeoutMs
|
|
29131
|
+
});
|
|
29132
|
+
const deadline = startedAt + options.timeoutMs;
|
|
29133
|
+
const pollIntervalMs = Math.max(10, options.pollIntervalMs ?? 250);
|
|
29134
|
+
while (Date.now() < deadline) {
|
|
29135
|
+
const current2 = await TaskService.getById(task.id);
|
|
29136
|
+
const run2 = await TaskRunService.getLatestByTaskId(task.id);
|
|
29137
|
+
if (!current2) {
|
|
29138
|
+
return {
|
|
29139
|
+
ok: false,
|
|
29140
|
+
taskId: task.id,
|
|
29141
|
+
runId: run2?.id ?? null,
|
|
29142
|
+
status: "missing",
|
|
29143
|
+
agent: options.agent,
|
|
29144
|
+
model: model ?? null,
|
|
29145
|
+
cwd,
|
|
29146
|
+
durationMs: Date.now() - startedAt,
|
|
29147
|
+
error: "\u5192\u70DF\u4EFB\u52A1\u5728\u5B8C\u6210\u524D\u88AB\u5220\u9664"
|
|
29148
|
+
};
|
|
29149
|
+
}
|
|
29150
|
+
if (current2.status === "done") {
|
|
29151
|
+
const log = run2?.log ?? current2.resultLog;
|
|
29152
|
+
const markerObserved = extractOpenCodeText(log) === marker;
|
|
29153
|
+
return {
|
|
29154
|
+
ok: markerObserved,
|
|
29155
|
+
taskId: task.id,
|
|
29156
|
+
runId: run2?.id ?? null,
|
|
29157
|
+
status: current2.status,
|
|
29158
|
+
agent: options.agent,
|
|
29159
|
+
model: model ?? null,
|
|
29160
|
+
cwd,
|
|
29161
|
+
durationMs: Date.now() - startedAt,
|
|
29162
|
+
error: markerObserved ? null : "OpenCode \u5DF2\u9000\u51FA\u6210\u529F\uFF0C\u4F46\u6A21\u578B\u6587\u672C\u4E0D\u662F\u9884\u671F\u7684\u7CBE\u786E\u6807\u8BB0"
|
|
29163
|
+
};
|
|
29164
|
+
}
|
|
29165
|
+
if (current2.status === "dead_letter" || current2.status === "cancelled") {
|
|
29166
|
+
return {
|
|
29167
|
+
ok: false,
|
|
29168
|
+
taskId: task.id,
|
|
29169
|
+
runId: run2?.id ?? null,
|
|
29170
|
+
status: current2.status,
|
|
29171
|
+
agent: options.agent,
|
|
29172
|
+
model: model ?? null,
|
|
29173
|
+
cwd,
|
|
29174
|
+
durationMs: Date.now() - startedAt,
|
|
29175
|
+
error: tail(run2?.log ?? current2.resultLog) ?? `\u4EFB\u52A1\u8FDB\u5165 ${current2.status}`
|
|
29176
|
+
};
|
|
29177
|
+
}
|
|
29178
|
+
await Bun.sleep(Math.min(pollIntervalMs, Math.max(1, deadline - Date.now())));
|
|
29179
|
+
}
|
|
29180
|
+
const current = await TaskService.getById(task.id);
|
|
29181
|
+
const run = await TaskRunService.getLatestByTaskId(task.id);
|
|
29182
|
+
await TaskService.cancel(task.id);
|
|
29183
|
+
return {
|
|
29184
|
+
ok: false,
|
|
29185
|
+
taskId: task.id,
|
|
29186
|
+
runId: run?.id ?? null,
|
|
29187
|
+
status: current?.status ?? "missing",
|
|
29188
|
+
agent: options.agent,
|
|
29189
|
+
model: model ?? null,
|
|
29190
|
+
cwd,
|
|
29191
|
+
durationMs: Date.now() - startedAt,
|
|
29192
|
+
error: `\u7B49\u5F85 Gateway \u6267\u884C\u8D85\u8FC7 ${options.timeoutMs}ms\uFF0C\u5192\u70DF\u4EFB\u52A1\u5DF2\u8BF7\u6C42\u53D6\u6D88`
|
|
29193
|
+
};
|
|
29194
|
+
}
|
|
29195
|
+
|
|
29196
|
+
// src/cli/index.ts
|
|
28447
29197
|
var cliLocale = resolveCliLocale();
|
|
28448
29198
|
var t2 = (zh, en) => cliText(cliLocale, zh, en);
|
|
28449
29199
|
async function withDb(fn, formatError = (error) => JSON.stringify({
|
|
@@ -28777,25 +29527,15 @@ program2.command("config").description(t2("\u663E\u793A\u5F53\u524D\u914D\u7F6E"
|
|
|
28777
29527
|
const cfg = loadConfig2();
|
|
28778
29528
|
console.log(JSON.stringify(cfg, null, 2));
|
|
28779
29529
|
});
|
|
28780
|
-
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")).action(async (options) => withDb(async () => {
|
|
29530
|
+
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 () => {
|
|
28781
29531
|
const config = loadConfig();
|
|
28782
29532
|
const database = DatabaseMaintenanceService.check();
|
|
28783
29533
|
const legacyQuarantinedRuns = await TaskRunService.listLegacyQuarantinedRuns(
|
|
28784
29534
|
config.watchdog.heartbeatTimeoutMs
|
|
28785
29535
|
);
|
|
28786
|
-
const gateway = getGatewayDiagnostic();
|
|
29536
|
+
const gateway = getGatewayDiagnostic({ probeOpenCode: true });
|
|
28787
29537
|
const packageVersion2 = getPackageVersion();
|
|
28788
|
-
const
|
|
28789
|
-
const opencodeResult = spawnSync4(opencodeBin2, ["--version"], {
|
|
28790
|
-
encoding: "utf8",
|
|
28791
|
-
env: process.env
|
|
28792
|
-
});
|
|
28793
|
-
const opencode = {
|
|
28794
|
-
ok: opencodeResult.status === 0,
|
|
28795
|
-
executable: opencodeBin2,
|
|
28796
|
-
version: opencodeResult.status === 0 ? opencodeResult.stdout.trim() : null,
|
|
28797
|
-
error: opencodeResult.status === 0 ? null : opencodeResult.error?.message || opencodeResult.stderr.trim() || t2(`\u9000\u51FA\u7801 ${opencodeResult.status}`, `exit code ${opencodeResult.status}`)
|
|
28798
|
-
};
|
|
29538
|
+
const opencode = diagnoseOpenCodeRuntime();
|
|
28799
29539
|
const plugin = getOpenCodePluginDiagnostic();
|
|
28800
29540
|
let dashboard = {
|
|
28801
29541
|
enabled: config.dashboard.enabled,
|
|
@@ -28867,6 +29607,12 @@ program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u63
|
|
|
28867
29607
|
"The current CLI/OpenCode database, config, or OpenCode executable scope does not match the PM2 Gateway"
|
|
28868
29608
|
));
|
|
28869
29609
|
}
|
|
29610
|
+
if (gateway.processFound && gateway.gatewayOpenCode?.ok !== true) {
|
|
29611
|
+
warnings.push(t2(
|
|
29612
|
+
`PM2 \u4FDD\u5B58\u7684 Gateway \u73AF\u5883\u65E0\u6CD5\u6267\u884C OpenCode\uFF1A${gateway.gatewayOpenCode?.error ?? "\u65E0\u6CD5\u8BFB\u53D6\u8FD0\u884C\u73AF\u5883"}`,
|
|
29613
|
+
`The Gateway environment saved by PM2 cannot execute OpenCode: ${gateway.gatewayOpenCode?.error ?? "runtime unavailable"}`
|
|
29614
|
+
));
|
|
29615
|
+
}
|
|
28870
29616
|
for (const run of legacyQuarantinedRuns) {
|
|
28871
29617
|
const cwdHint = run.taskCwd == null ? t2("\uFF08\u65E7\u4EFB\u52A1\u6CA1\u6709 cwd\uFF0C\u8BF7\u5148\u5728 Dashboard \u53D6\u6D88\uFF09", " (the legacy task has no cwd; cancel it in the Dashboard first)") : t2(`\uFF08\u5728 ${run.taskCwd} \u6267\u884C\uFF09`, ` (run in ${run.taskCwd})`);
|
|
28872
29618
|
const cancel = run.taskStatus === "cancelled" ? "" : t2(`\u5148${cwdHint} supertask cancel --id ${run.taskId}\uFF1B`, `first${cwdHint}: supertask cancel --id ${run.taskId}; `);
|
|
@@ -28876,7 +29622,31 @@ program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u63
|
|
|
28876
29622
|
`Legacy quarantined run #${run.runId}: ${owner}${cancel}after confirming no OpenCode process remains, run supertask run abandon --id ${run.runId} --confirm ABANDON`
|
|
28877
29623
|
));
|
|
28878
29624
|
}
|
|
28879
|
-
|
|
29625
|
+
let smoke = null;
|
|
29626
|
+
if (options.smoke) {
|
|
29627
|
+
const gatewayCanExecute = gateway.status === "online" && gateway.ready && gateway.scopeMatches && gateway.gatewayOpenCode?.ok === true;
|
|
29628
|
+
if (!gatewayCanExecute) {
|
|
29629
|
+
smoke = {
|
|
29630
|
+
ok: false,
|
|
29631
|
+
skipped: true,
|
|
29632
|
+
error: t2(
|
|
29633
|
+
"Gateway \u5C1A\u672A\u5C31\u7EEA\uFF0C\u6216\u5176 PM2 \u73AF\u5883\u65E0\u6CD5\u6267\u884C OpenCode\uFF1B\u5DF2\u8DF3\u8FC7\u771F\u5B9E\u4EFB\u52A1",
|
|
29634
|
+
"Gateway is not ready or its PM2 environment cannot execute OpenCode; the real task was skipped"
|
|
29635
|
+
)
|
|
29636
|
+
};
|
|
29637
|
+
} else {
|
|
29638
|
+
const smokeTimeoutMs = parseDuration(options.smokeTimeout);
|
|
29639
|
+
if (smokeTimeoutMs === null) throw new Error("smoke-timeout \u683C\u5F0F\u65E0\u6548");
|
|
29640
|
+
smoke = await runDoctorSmoke({
|
|
29641
|
+
agent: options.smokeAgent,
|
|
29642
|
+
model: options.smokeModel,
|
|
29643
|
+
cwd: options.smokeCwd ?? process.cwd(),
|
|
29644
|
+
timeoutMs: smokeTimeoutMs
|
|
29645
|
+
});
|
|
29646
|
+
}
|
|
29647
|
+
if (!smoke.ok) warnings.push(smoke.error ?? t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u5931\u8D25", "Real smoke task failed"));
|
|
29648
|
+
}
|
|
29649
|
+
const ok = opencode.ok && plugin.ok && database.ok && legacyQuarantinedRuns.length === 0 && gateway.pm2Installed && gateway.status === "online" && gateway.ready && gatewayEntryPinned && gatewayVersionMatchesPackage && configuredVersionsMatch && cliVersionMatchesPlugin && gateway.scopeMatches && gateway.gatewayOpenCode?.ok === true && gateway.logRotationInstalled && gateway.startupConfigured !== false && dashboard.ok && (!options.smoke || smoke?.ok === true);
|
|
28880
29650
|
const report = {
|
|
28881
29651
|
ok,
|
|
28882
29652
|
packageVersion: packageVersion2,
|
|
@@ -28888,6 +29658,7 @@ program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u63
|
|
|
28888
29658
|
legacyQuarantinedRuns,
|
|
28889
29659
|
gateway,
|
|
28890
29660
|
dashboard,
|
|
29661
|
+
smoke,
|
|
28891
29662
|
warnings
|
|
28892
29663
|
};
|
|
28893
29664
|
const json = options.json || !process.stdout.isTTY;
|
|
@@ -28897,10 +29668,15 @@ program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u63
|
|
|
28897
29668
|
const mark = (value) => value ? "\u2713" : "\u2717";
|
|
28898
29669
|
console.log(`SuperTask doctor: ${ok ? t2("\u6B63\u5E38", "healthy") : t2("\u5F02\u5E38", "unhealthy")}`);
|
|
28899
29670
|
console.log(`${mark(opencode.ok)} OpenCode ${opencode.version ?? opencode.error ?? t2("\u4E0D\u53EF\u7528", "unavailable")}`);
|
|
29671
|
+
console.log(`${mark(gateway.gatewayOpenCode?.ok === true)} ${t2("Gateway \u73AF\u5883\u4E2D\u7684 OpenCode", "OpenCode in Gateway environment")} ${gateway.gatewayOpenCode?.version ?? gateway.gatewayOpenCode?.error ?? t2("\u4E0D\u53EF\u7528", "unavailable")}${gateway.gatewayOpenCode?.executable ? `\uFF0C${gateway.gatewayOpenCode.executable}` : ""}`);
|
|
28900
29672
|
console.log(`${mark(plugin.ok)} ${t2("OpenCode \u63D2\u4EF6", "OpenCode plugin")} ${plugin.spec || plugin.error || t2("\u672A\u914D\u7F6E", "not configured")}${plugin.cachedVersion ? t2(`\uFF08\u7F13\u5B58 v${plugin.cachedVersion}\uFF09`, ` (cached v${plugin.cachedVersion})`) : ""}`);
|
|
28901
29673
|
console.log(`${mark(database.ok)} ${t2("\u6570\u636E\u5E93", "Database")} ${database.path}${t2(`\uFF08\u4EFB\u52A1 ${database.counts.tasks}\uFF0C\u8FD0\u884C\u4E2D ${database.runningTasks}\uFF09`, ` (tasks ${database.counts.tasks}, running ${database.runningTasks})`)}`);
|
|
28902
29674
|
console.log(`${mark(gateway.status === "online" && gateway.ready && gatewayEntryPinned && gatewayVersionMatchesPackage)} Gateway ${gateway.status ?? "missing"}${gateway.pid ? `\uFF0CPID ${gateway.pid}` : ""}${gateway.runningVersion ? `\uFF0Cv${gateway.runningVersion}` : ""}${gateway.gatewayEntry ? `\uFF0C${gateway.gatewayEntry}` : ""}`);
|
|
28903
29675
|
console.log(`${mark(dashboard.ok)} Dashboard ${dashboard.enabled ? dashboard.url : t2("\u5DF2\u7981\u7528", "disabled")}`);
|
|
29676
|
+
if (options.smoke) {
|
|
29677
|
+
const smokeSummary = smoke && "taskId" in smoke ? `task #${smoke.taskId}${smoke.runId ? ` / run #${smoke.runId}` : ""}\uFF0C${smoke.durationMs}ms` : smoke?.error ?? t2("\u672A\u6267\u884C", "not run");
|
|
29678
|
+
console.log(`${mark(smoke?.ok === true)} ${t2("\u771F\u5B9E Gateway \u5192\u70DF\u4EFB\u52A1", "Real Gateway smoke task")} ${smokeSummary}`);
|
|
29679
|
+
}
|
|
28904
29680
|
for (const warning of warnings) console.log(`! ${warning}`);
|
|
28905
29681
|
}
|
|
28906
29682
|
if (!ok) process.exitCode = 1;
|