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/gateway/index.js
CHANGED
|
@@ -1204,7 +1204,7 @@ var init_sql = __esm({
|
|
|
1204
1204
|
return new SQL([new StringChunk(str)]);
|
|
1205
1205
|
}
|
|
1206
1206
|
sql2.raw = raw2;
|
|
1207
|
-
function
|
|
1207
|
+
function join7(chunks, separator) {
|
|
1208
1208
|
const result = [];
|
|
1209
1209
|
for (const [i, chunk] of chunks.entries()) {
|
|
1210
1210
|
if (i > 0 && separator !== void 0) {
|
|
@@ -1214,7 +1214,7 @@ var init_sql = __esm({
|
|
|
1214
1214
|
}
|
|
1215
1215
|
return new SQL(result);
|
|
1216
1216
|
}
|
|
1217
|
-
sql2.join =
|
|
1217
|
+
sql2.join = join7;
|
|
1218
1218
|
function identifier(value) {
|
|
1219
1219
|
return new Name(value);
|
|
1220
1220
|
}
|
|
@@ -3830,7 +3830,7 @@ var init_select2 = __esm({
|
|
|
3830
3830
|
return (table, on) => {
|
|
3831
3831
|
const baseTableName = this.tableName;
|
|
3832
3832
|
const tableName = getTableLikeName(table);
|
|
3833
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
3833
|
+
if (typeof tableName === "string" && this.config.joins?.some((join7) => join7.alias === tableName)) {
|
|
3834
3834
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
3835
3835
|
}
|
|
3836
3836
|
if (!this.isPartialSelect) {
|
|
@@ -4672,7 +4672,7 @@ var init_update = __esm({
|
|
|
4672
4672
|
createJoin(joinType) {
|
|
4673
4673
|
return (table, on) => {
|
|
4674
4674
|
const tableName = getTableLikeName(table);
|
|
4675
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
4675
|
+
if (typeof tableName === "string" && this.config.joins.some((join7) => join7.alias === tableName)) {
|
|
4676
4676
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
4677
4677
|
}
|
|
4678
4678
|
if (typeof on === "function") {
|
|
@@ -19628,6 +19628,116 @@ var init_duration = __esm({
|
|
|
19628
19628
|
}
|
|
19629
19629
|
});
|
|
19630
19630
|
|
|
19631
|
+
// src/core/opencode-catalog.ts
|
|
19632
|
+
import { spawn as spawn2 } from "child_process";
|
|
19633
|
+
function cleanOutput(value) {
|
|
19634
|
+
return value.replace(ANSI_PATTERN, "").replace(/\r/g, "");
|
|
19635
|
+
}
|
|
19636
|
+
function runOpenCode(executable, args, cwd, timeoutMs) {
|
|
19637
|
+
return new Promise((resolve4, reject) => {
|
|
19638
|
+
const child = spawn2(executable, args, {
|
|
19639
|
+
cwd,
|
|
19640
|
+
env: process.env,
|
|
19641
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
19642
|
+
});
|
|
19643
|
+
let stdout = "";
|
|
19644
|
+
let stderr = "";
|
|
19645
|
+
let failure = null;
|
|
19646
|
+
let finished = false;
|
|
19647
|
+
const append = (current, chunk) => {
|
|
19648
|
+
const next = current + chunk.toString();
|
|
19649
|
+
if (Buffer.byteLength(next) > MAX_OUTPUT_BYTES && failure === null) {
|
|
19650
|
+
failure = new Error(`OpenCode \u8F93\u51FA\u8D85\u8FC7 ${MAX_OUTPUT_BYTES} bytes`);
|
|
19651
|
+
child.kill("SIGTERM");
|
|
19652
|
+
}
|
|
19653
|
+
return next.slice(-MAX_OUTPUT_BYTES);
|
|
19654
|
+
};
|
|
19655
|
+
child.stdout?.on("data", (chunk) => {
|
|
19656
|
+
stdout = append(stdout, chunk);
|
|
19657
|
+
});
|
|
19658
|
+
child.stderr?.on("data", (chunk) => {
|
|
19659
|
+
stderr = append(stderr, chunk);
|
|
19660
|
+
});
|
|
19661
|
+
child.once("error", (error) => {
|
|
19662
|
+
failure ??= error;
|
|
19663
|
+
});
|
|
19664
|
+
const timer = setTimeout(() => {
|
|
19665
|
+
failure ??= new Error(`OpenCode \u547D\u4EE4\u8D85\u8FC7 ${timeoutMs}ms \u672A\u5B8C\u6210`);
|
|
19666
|
+
child.kill("SIGTERM");
|
|
19667
|
+
}, timeoutMs);
|
|
19668
|
+
child.once("close", (code) => {
|
|
19669
|
+
if (finished) return;
|
|
19670
|
+
finished = true;
|
|
19671
|
+
clearTimeout(timer);
|
|
19672
|
+
if (failure) {
|
|
19673
|
+
reject(failure);
|
|
19674
|
+
return;
|
|
19675
|
+
}
|
|
19676
|
+
if (code !== 0) {
|
|
19677
|
+
const detail = cleanOutput(stderr).trim() || `\u9000\u51FA\u7801 ${code ?? "null"}`;
|
|
19678
|
+
reject(new Error(`OpenCode ${args.join(" ")} \u5931\u8D25\uFF1A${detail}`));
|
|
19679
|
+
return;
|
|
19680
|
+
}
|
|
19681
|
+
resolve4(cleanOutput(stdout));
|
|
19682
|
+
});
|
|
19683
|
+
});
|
|
19684
|
+
}
|
|
19685
|
+
function parseOpenCodeModels(output) {
|
|
19686
|
+
return [...new Set(cleanOutput(output).split("\n").map((line) => line.trim()).filter((line) => /^[^\s/]+\/.+/.test(line)))].sort((left, right) => left.localeCompare(right));
|
|
19687
|
+
}
|
|
19688
|
+
function parseOpenCodeAgents(output) {
|
|
19689
|
+
const agents = /* @__PURE__ */ new Map();
|
|
19690
|
+
for (const line of cleanOutput(output).split("\n")) {
|
|
19691
|
+
const match2 = /^([^\s()]+) \((primary|subagent|all)\)$/.exec(line.trim());
|
|
19692
|
+
if (!match2) continue;
|
|
19693
|
+
const name = match2[1];
|
|
19694
|
+
const mode = match2[2];
|
|
19695
|
+
if (name === "supertask-runner") continue;
|
|
19696
|
+
agents.set(name, { name, mode });
|
|
19697
|
+
}
|
|
19698
|
+
const rank = { primary: 0, all: 1, subagent: 2 };
|
|
19699
|
+
return [...agents.values()].sort((left, right) => rank[left.mode] - rank[right.mode] || left.name.localeCompare(right.name));
|
|
19700
|
+
}
|
|
19701
|
+
async function loadOpenCodeCatalog(cwd, options = {}) {
|
|
19702
|
+
validateTaskWorkingDirectory(cwd);
|
|
19703
|
+
const executable = options.executable ?? process.env.SUPERTASK_OPENCODE_BIN ?? "opencode";
|
|
19704
|
+
const timeoutMs = options.timeoutMs ?? COMMAND_TIMEOUT_MS;
|
|
19705
|
+
const cacheKey = `${executable}\0${cwd}`;
|
|
19706
|
+
const cached = catalogCache.get(cacheKey);
|
|
19707
|
+
if (options.useCache !== false && cached && cached.expiresAt > Date.now()) {
|
|
19708
|
+
return cached.result;
|
|
19709
|
+
}
|
|
19710
|
+
const result = Promise.all([
|
|
19711
|
+
runOpenCode(executable, ["models"], cwd, timeoutMs),
|
|
19712
|
+
runOpenCode(executable, ["agent", "list"], cwd, timeoutMs)
|
|
19713
|
+
]).then(([modelsOutput, agentsOutput]) => {
|
|
19714
|
+
const models = parseOpenCodeModels(modelsOutput);
|
|
19715
|
+
const agents = parseOpenCodeAgents(agentsOutput).filter((agent) => agent.mode !== "subagent");
|
|
19716
|
+
if (models.length === 0) throw new Error("OpenCode \u6CA1\u6709\u8FD4\u56DE\u53EF\u7528\u6A21\u578B");
|
|
19717
|
+
if (agents.length === 0) throw new Error("OpenCode \u6CA1\u6709\u8FD4\u56DE\u53EF\u76F4\u63A5\u8FD0\u884C\u7684\u4E3B Agent");
|
|
19718
|
+
return { cwd, models, agents };
|
|
19719
|
+
});
|
|
19720
|
+
if (options.useCache !== false) {
|
|
19721
|
+
catalogCache.set(cacheKey, { expiresAt: Date.now() + CATALOG_CACHE_MS, result });
|
|
19722
|
+
result.catch(() => {
|
|
19723
|
+
if (catalogCache.get(cacheKey)?.result === result) catalogCache.delete(cacheKey);
|
|
19724
|
+
});
|
|
19725
|
+
}
|
|
19726
|
+
return result;
|
|
19727
|
+
}
|
|
19728
|
+
var CATALOG_CACHE_MS, COMMAND_TIMEOUT_MS, MAX_OUTPUT_BYTES, ANSI_PATTERN, catalogCache;
|
|
19729
|
+
var init_opencode_catalog = __esm({
|
|
19730
|
+
"src/core/opencode-catalog.ts"() {
|
|
19731
|
+
"use strict";
|
|
19732
|
+
init_task_working_directory();
|
|
19733
|
+
CATALOG_CACHE_MS = 3e4;
|
|
19734
|
+
COMMAND_TIMEOUT_MS = 2e4;
|
|
19735
|
+
MAX_OUTPUT_BYTES = 4 * 1024 * 1024;
|
|
19736
|
+
ANSI_PATTERN = /\x1B(?:[@-_][0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\))/g;
|
|
19737
|
+
catalogCache = /* @__PURE__ */ new Map();
|
|
19738
|
+
}
|
|
19739
|
+
});
|
|
19740
|
+
|
|
19631
19741
|
// src/core/services/database-maintenance.service.ts
|
|
19632
19742
|
import { Database as Database3 } from "bun:sqlite";
|
|
19633
19743
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -20159,7 +20269,27 @@ function scopesMatch(left, right) {
|
|
|
20159
20269
|
function currentScope() {
|
|
20160
20270
|
return runtimeScope({ cwd: process.cwd(), env: process.env });
|
|
20161
20271
|
}
|
|
20162
|
-
function
|
|
20272
|
+
function diagnoseOpenCodeRuntime(runtime = {
|
|
20273
|
+
cwd: process.cwd(),
|
|
20274
|
+
env: process.env
|
|
20275
|
+
}) {
|
|
20276
|
+
const executable = runtimeScope(runtime).opencodePath;
|
|
20277
|
+
const result = spawnSync2(executable, ["--version"], {
|
|
20278
|
+
cwd: runtime.cwd,
|
|
20279
|
+
env: runtime.env,
|
|
20280
|
+
encoding: "utf8",
|
|
20281
|
+
timeout: 1e4,
|
|
20282
|
+
killSignal: "SIGKILL"
|
|
20283
|
+
});
|
|
20284
|
+
const ok = result.status === 0 && result.error === void 0;
|
|
20285
|
+
return {
|
|
20286
|
+
ok,
|
|
20287
|
+
executable,
|
|
20288
|
+
version: ok ? result.stdout.trim() || result.stderr.trim() || null : null,
|
|
20289
|
+
error: ok ? null : result.error?.message || result.stderr.trim() || result.stdout.trim() || `exit code ${result.status}`
|
|
20290
|
+
};
|
|
20291
|
+
}
|
|
20292
|
+
function getGatewayDiagnostic(options = {}) {
|
|
20163
20293
|
const producerScope = currentScope();
|
|
20164
20294
|
if (!isPm2Installed()) {
|
|
20165
20295
|
return {
|
|
@@ -20175,7 +20305,8 @@ function getGatewayDiagnostic() {
|
|
|
20175
20305
|
startupConfigured: process.platform === "darwin" || process.platform === "linux" ? false : null,
|
|
20176
20306
|
currentScope: producerScope,
|
|
20177
20307
|
gatewayScope: null,
|
|
20178
|
-
scopeMatches: false
|
|
20308
|
+
scopeMatches: false,
|
|
20309
|
+
gatewayOpenCode: null
|
|
20179
20310
|
};
|
|
20180
20311
|
}
|
|
20181
20312
|
const processes = pm2JsonList();
|
|
@@ -20203,7 +20334,8 @@ function getGatewayDiagnostic() {
|
|
|
20203
20334
|
) : process.platform === "linux" ? isLinuxStartupConfigured(gatewayEnv, runtime?.cwd, runtime ?? void 0) : null,
|
|
20204
20335
|
currentScope: producerScope,
|
|
20205
20336
|
gatewayScope: managedScope,
|
|
20206
|
-
scopeMatches: managedScope != null && scopesMatch(producerScope, managedScope)
|
|
20337
|
+
scopeMatches: managedScope != null && scopesMatch(producerScope, managedScope),
|
|
20338
|
+
gatewayOpenCode: runtime === null || !options.probeOpenCode ? null : diagnoseOpenCodeRuntime(runtime)
|
|
20207
20339
|
};
|
|
20208
20340
|
}
|
|
20209
20341
|
function pm2Bin(env = process.env) {
|
|
@@ -20566,7 +20698,8 @@ function icon(name, className = "icon") {
|
|
|
20566
20698
|
check: '<path d="m5 12 4 4L19 6"/>',
|
|
20567
20699
|
alert: '<path d="M12 3 2.8 19h18.4L12 3Z"/><path d="M12 9v4M12 17h.01"/>',
|
|
20568
20700
|
clock: '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',
|
|
20569
|
-
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"/>'
|
|
20701
|
+
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"/>',
|
|
20702
|
+
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"/>'
|
|
20570
20703
|
};
|
|
20571
20704
|
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>`;
|
|
20572
20705
|
}
|
|
@@ -20579,7 +20712,70 @@ function clientMessages(locale) {
|
|
|
20579
20712
|
"action.refresh",
|
|
20580
20713
|
"action.logs",
|
|
20581
20714
|
"action.hideLogs",
|
|
20715
|
+
"details.title",
|
|
20716
|
+
"details.subtitle",
|
|
20717
|
+
"details.taskTitle",
|
|
20718
|
+
"details.runTitle",
|
|
20719
|
+
"details.templateTitle",
|
|
20720
|
+
"details.raw",
|
|
20582
20721
|
"details.copySuccess",
|
|
20722
|
+
"details.id",
|
|
20723
|
+
"details.project",
|
|
20724
|
+
"details.prompt",
|
|
20725
|
+
"details.result",
|
|
20726
|
+
"details.category",
|
|
20727
|
+
"details.batch",
|
|
20728
|
+
"details.dependency",
|
|
20729
|
+
"details.importance",
|
|
20730
|
+
"details.urgency",
|
|
20731
|
+
"details.retryCount",
|
|
20732
|
+
"details.retryBackoff",
|
|
20733
|
+
"details.timeout",
|
|
20734
|
+
"details.createdAt",
|
|
20735
|
+
"details.updatedAt",
|
|
20736
|
+
"details.startedAt",
|
|
20737
|
+
"details.finishedAt",
|
|
20738
|
+
"details.scheduledAt",
|
|
20739
|
+
"details.enabled",
|
|
20740
|
+
"details.scheduleRule",
|
|
20741
|
+
"details.maxInstances",
|
|
20742
|
+
"details.maxRetries",
|
|
20743
|
+
"details.lastRun",
|
|
20744
|
+
"details.nextRun",
|
|
20745
|
+
"details.taskId",
|
|
20746
|
+
"details.session",
|
|
20747
|
+
"details.heartbeat",
|
|
20748
|
+
"details.process",
|
|
20749
|
+
"details.history",
|
|
20750
|
+
"details.noHistory",
|
|
20751
|
+
"details.none",
|
|
20752
|
+
"details.default",
|
|
20753
|
+
"details.enabledYes",
|
|
20754
|
+
"details.enabledNo",
|
|
20755
|
+
"table.name",
|
|
20756
|
+
"table.agent",
|
|
20757
|
+
"table.model",
|
|
20758
|
+
"table.status",
|
|
20759
|
+
"table.duration",
|
|
20760
|
+
"template.scheduleType",
|
|
20761
|
+
"status.pending",
|
|
20762
|
+
"status.running",
|
|
20763
|
+
"status.done",
|
|
20764
|
+
"status.failed",
|
|
20765
|
+
"status.dead_letter",
|
|
20766
|
+
"status.cancelled",
|
|
20767
|
+
"status.unknown",
|
|
20768
|
+
"runStatus.running",
|
|
20769
|
+
"runStatus.done",
|
|
20770
|
+
"runStatus.failed",
|
|
20771
|
+
"schedule.cron",
|
|
20772
|
+
"schedule.recurring",
|
|
20773
|
+
"schedule.delayed",
|
|
20774
|
+
"schedule.unknown",
|
|
20775
|
+
"duration.seconds",
|
|
20776
|
+
"duration.minutes",
|
|
20777
|
+
"duration.hours",
|
|
20778
|
+
"duration.days",
|
|
20583
20779
|
"feedback.copyFailed",
|
|
20584
20780
|
"dialog.cancelTask",
|
|
20585
20781
|
"dialog.cancelTaskBody",
|
|
@@ -20621,7 +20817,20 @@ function clientMessages(locale) {
|
|
|
20621
20817
|
"feedback.restartTimeout",
|
|
20622
20818
|
"template.createTitle",
|
|
20623
20819
|
"template.editTitle",
|
|
20624
|
-
"filter.noResults"
|
|
20820
|
+
"filter.noResults",
|
|
20821
|
+
"catalog.chooseProject",
|
|
20822
|
+
"catalog.defaultModel",
|
|
20823
|
+
"catalog.defaultProvider",
|
|
20824
|
+
"catalog.loading",
|
|
20825
|
+
"catalog.loaded",
|
|
20826
|
+
"catalog.failed",
|
|
20827
|
+
"catalog.primary",
|
|
20828
|
+
"catalog.subagent",
|
|
20829
|
+
"catalog.all",
|
|
20830
|
+
"directory.empty",
|
|
20831
|
+
"feedback.commandCopied",
|
|
20832
|
+
"action.showHidden",
|
|
20833
|
+
"action.hideHidden"
|
|
20625
20834
|
];
|
|
20626
20835
|
return Object.fromEntries(keys.map((key) => [key, t(locale, key)]));
|
|
20627
20836
|
}
|
|
@@ -20689,9 +20898,14 @@ function renderLayout(options) {
|
|
|
20689
20898
|
<footer>${t(locale, "app.footer")}</footer>
|
|
20690
20899
|
</div>
|
|
20691
20900
|
<div id="toast-region" class="toast-region" role="status" aria-live="polite"></div>
|
|
20901
|
+
<dialog id="directory-dialog" class="directory-dialog">
|
|
20902
|
+
<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>
|
|
20903
|
+
<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>
|
|
20904
|
+
<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>
|
|
20905
|
+
</dialog>
|
|
20692
20906
|
<dialog id="detail-dialog">
|
|
20693
|
-
<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>
|
|
20694
|
-
<div class="dialog-body"><
|
|
20907
|
+
<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>
|
|
20908
|
+
<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>
|
|
20695
20909
|
<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>
|
|
20696
20910
|
</dialog>
|
|
20697
20911
|
<dialog id="confirm-dialog">
|
|
@@ -20723,30 +20937,77 @@ function renderLayout(options) {
|
|
|
20723
20937
|
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')}}
|
|
20724
20938
|
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')}}
|
|
20725
20939
|
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')}}
|
|
20726
|
-
|
|
20727
|
-
const
|
|
20728
|
-
|
|
20940
|
+
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)}
|
|
20941
|
+
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'}
|
|
20942
|
+
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')}
|
|
20943
|
+
function detailScheduleType(value){const key='schedule.'+String(value||'unknown');return Object.prototype.hasOwnProperty.call(UI,key)?text(key):text('schedule.unknown')}
|
|
20944
|
+
function detailModel(value){return !value||value==='default'?text('details.default'):String(value)}
|
|
20945
|
+
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)}
|
|
20946
|
+
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')}
|
|
20947
|
+
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}
|
|
20948
|
+
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}
|
|
20949
|
+
function detailFields(type,data){if(type==='task')return [
|
|
20950
|
+
[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}],
|
|
20951
|
+
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
20952
|
+
[text('details.category'),data.category],[text('details.batch'),data.batchId],[text('details.dependency'),data.dependsOn?'#'+data.dependsOn:text('details.none')],
|
|
20953
|
+
[text('details.importance'),data.importance],[text('details.urgency'),data.urgency],[text('details.retryCount'),String(data.retryCount??0)+' / '+String(data.maxRetries??0)],
|
|
20954
|
+
[text('details.retryBackoff'),detailDuration(data.retryBackoffMs)],[text('details.timeout'),detailDuration(data.timeoutMs)],[text('details.scheduledAt'),detailDate(data.scheduledAt)],
|
|
20955
|
+
[text('details.createdAt'),detailDate(data.createdAt)],[text('details.startedAt'),detailDate(data.startedAt)],[text('details.finishedAt'),detailDate(data.finishedAt)],
|
|
20956
|
+
[text('details.result'),detailTaskResult(data),{wide:true,long:true}]
|
|
20957
|
+
];if(type==='run'){const started=data.startedAt?new Date(data.startedAt).getTime():null;const finished=data.finishedAt?new Date(data.finishedAt).getTime():null;return [
|
|
20958
|
+
[text('details.id'),'Run #'+data.id],[text('details.taskId'),'#'+data.taskId],[text('table.status'),detailStatus('run',data.status)],[text('table.model'),detailModel(data.model)],
|
|
20959
|
+
[text('details.session'),detailSession(data.sessionId)],[text('details.startedAt'),detailDate(data.startedAt)],[text('details.finishedAt'),detailDate(data.finishedAt)],
|
|
20960
|
+
[text('table.duration'),started!==null?detailDuration((finished??Date.now())-started):text('details.none')],[text('details.heartbeat'),detailDate(data.heartbeatAt)],
|
|
20961
|
+
[text('details.process'),'Worker PID '+String(data.workerPid??'\u2014')+' \xB7 OpenCode PID '+String(data.childPid??'\u2014'),{wide:true,mono:true}]
|
|
20962
|
+
];}const scheduleRule=data.scheduleType==='cron'?data.cronExpr:data.scheduleType==='recurring'?detailDuration(data.intervalMs):detailDate(data.runAt);return [
|
|
20963
|
+
[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}],
|
|
20964
|
+
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
20965
|
+
[text('template.scheduleType'),detailScheduleType(data.scheduleType)],[text('details.scheduleRule'),scheduleRule],[text('details.category'),data.category],[text('details.batch'),data.batchId],
|
|
20966
|
+
[text('details.importance'),data.importance],[text('details.urgency'),data.urgency],[text('details.maxInstances'),data.maxInstances],[text('details.maxRetries'),data.maxRetries??0],
|
|
20967
|
+
[text('details.retryBackoff'),detailDuration(data.retryBackoffMs)],[text('details.timeout'),detailDuration(data.timeoutMs)],[text('details.lastRun'),detailDate(data.lastRunAt)],[text('details.nextRun'),detailDate(data.nextRunAt)],
|
|
20968
|
+
[text('details.createdAt'),detailDate(data.createdAt)],[text('details.updatedAt'),detailDate(data.updatedAt)]
|
|
20969
|
+
]}
|
|
20970
|
+
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')}}
|
|
20971
|
+
const showDetail=id=>showRecord('/api/tasks/'+id,'task');const showRunDetail=id=>showRecord('/api/runs/'+id,'run');const showTemplateDetail=id=>showRecord('/api/templates/'+id,'template');
|
|
20972
|
+
async function copyDetails(){try{await navigator.clipboard.writeText(document.getElementById('detail-raw').textContent);showToast(text('details.copySuccess'))}catch{showToast(text('feedback.copyFailed'),'error')}}
|
|
20729
20973
|
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')}}
|
|
20974
|
+
async function copyRunCommand(id){try{await navigator.clipboard.writeText(document.getElementById('command-'+id).textContent);showToast(text('feedback.commandCopied'))}catch{showToast(text('feedback.copyFailed'),'error')}}
|
|
20730
20975
|
function taskField(name){return document.getElementById('task-'+name)}
|
|
20976
|
+
function templateField(name){return document.getElementById('template-'+name)}
|
|
20731
20977
|
function taskProjects(){const node=document.getElementById('task-project-data');if(!node)return {};try{return JSON.parse(node.textContent||'{}')}catch{return {}}}
|
|
20732
20978
|
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')}
|
|
20733
|
-
|
|
20734
|
-
|
|
20735
|
-
|
|
20736
|
-
function
|
|
20737
|
-
function
|
|
20979
|
+
const catalogTimers={};const catalogRequests={};const catalogModels={};
|
|
20980
|
+
function catalogField(prefix,name){return document.getElementById(prefix+'-'+name)}
|
|
20981
|
+
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='';}
|
|
20982
|
+
function appendCurrentOption(select,value){if(!value||[...select.options].some(option=>option.value===value))return;select.appendChild(new Option(value,value));}
|
|
20983
|
+
function modelProvider(value){const slash=value.indexOf('/');return slash>0?value.slice(0,slash):''}
|
|
20984
|
+
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}
|
|
20985
|
+
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}}}
|
|
20986
|
+
function scheduleCatalogLoad(prefix){clearTimeout(catalogTimers[prefix]);catalogTimers[prefix]=setTimeout(()=>loadCatalog(prefix),450)}
|
|
20987
|
+
let directoryTargetId='';let directoryCurrent='';let directoryEntries=[];let directoryShowHidden=false;
|
|
20988
|
+
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)}}
|
|
20989
|
+
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}}
|
|
20990
|
+
document.getElementById('directory-hidden').onclick=()=>{directoryShowHidden=!directoryShowHidden;renderDirectoryEntries()};
|
|
20991
|
+
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('')}
|
|
20992
|
+
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)};
|
|
20993
|
+
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'}
|
|
20994
|
+
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}
|
|
20995
|
+
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)}
|
|
20996
|
+
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)}
|
|
20997
|
+
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')}}
|
|
20998
|
+
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}}
|
|
20738
20999
|
function localDateTime(milliseconds){const date=new Date(milliseconds);const local=new Date(milliseconds-date.getTimezoneOffset()*60000);return local.toISOString().slice(0,23)}
|
|
20739
|
-
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}}
|
|
21000
|
+
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')}}
|
|
20740
21001
|
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}
|
|
20741
21002
|
function selectedRunAt(){const input=templateField('run-at');return resolveEditedRunAt(input.dataset.originalEpoch?Number(input.dataset.originalEpoch):null,input.dataset.originalLocal||'',input.value)}
|
|
20742
|
-
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)}
|
|
20743
|
-
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('
|
|
20744
|
-
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:
|
|
21003
|
+
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)}
|
|
21004
|
+
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')}}
|
|
21005
|
+
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}}
|
|
20745
21006
|
async function enableTmpl(id){try{await readJson(await fetch('/api/templates/'+id+'/enable',{method:'POST'}));location.reload()}catch(error){showToast(error.message,'error')}}
|
|
20746
21007
|
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')}}
|
|
20747
21008
|
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')}}
|
|
20748
21009
|
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')}}
|
|
20749
|
-
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');}
|
|
21010
|
+
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'}));}
|
|
20750
21011
|
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;}
|
|
20751
21012
|
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')}}
|
|
20752
21013
|
async function confirmGatewayRestart(runningCount=0){const body=runningCount>0?text('dialog.restartGatewayRunningBody',{count:runningCount}):text('dialog.restartGatewayBody');return await ask(text('dialog.restartGateway'),body)}
|
|
@@ -20792,7 +21053,7 @@ var init_ui = __esm({
|
|
|
20792
21053
|
"action.hideLogs": "\u6536\u8D77\u65E5\u5FD7",
|
|
20793
21054
|
"action.save": "\u4FDD\u5B58\u8BBE\u7F6E",
|
|
20794
21055
|
"action.saveAndRestart": "\u4FDD\u5B58\u5E76\u91CD\u542F",
|
|
20795
|
-
"action.copy": "\u590D\u5236
|
|
21056
|
+
"action.copy": "\u590D\u5236\u539F\u59CB\u6570\u636E",
|
|
20796
21057
|
"action.close": "\u5173\u95ED",
|
|
20797
21058
|
"action.confirm": "\u786E\u8BA4",
|
|
20798
21059
|
"action.clearDatabase": "\u6E05\u7A7A\u6570\u636E\u5E93",
|
|
@@ -20801,6 +21062,13 @@ var init_ui = __esm({
|
|
|
20801
21062
|
"action.updateTask": "\u4FDD\u5B58\u4FEE\u6539",
|
|
20802
21063
|
"action.createTemplate": "\u65B0\u5EFA\u5B9A\u65F6\u4EFB\u52A1",
|
|
20803
21064
|
"action.saveTemplate": "\u4FDD\u5B58\u5B9A\u65F6\u4EFB\u52A1",
|
|
21065
|
+
"action.chooseFolder": "\u9009\u62E9\u6587\u4EF6\u5939",
|
|
21066
|
+
"action.chooseThisFolder": "\u9009\u62E9\u5F53\u524D\u6587\u4EF6\u5939",
|
|
21067
|
+
"action.home": "\u4E3B\u76EE\u5F55",
|
|
21068
|
+
"action.up": "\u4E0A\u4E00\u7EA7",
|
|
21069
|
+
"action.copyCommand": "\u590D\u5236\u547D\u4EE4",
|
|
21070
|
+
"action.showHidden": "\u663E\u793A\u9690\u85CF\u6587\u4EF6\u5939",
|
|
21071
|
+
"action.hideHidden": "\u9690\u85CF\u9690\u85CF\u6587\u4EF6\u5939",
|
|
20804
21072
|
"status.pending": "\u5F85\u6267\u884C",
|
|
20805
21073
|
"status.running": "\u8FD0\u884C\u4E2D",
|
|
20806
21074
|
"status.done": "\u5DF2\u5B8C\u6210",
|
|
@@ -20867,6 +21135,15 @@ var init_ui = __esm({
|
|
|
20867
21135
|
"schedule.hours": "{count} \u5C0F\u65F6",
|
|
20868
21136
|
"schedule.days": "{count} \u5929",
|
|
20869
21137
|
"schedule.overdue": "\u5DF2\u5230\u671F",
|
|
21138
|
+
"duration.unit": "\u65F6\u95F4\u5355\u4F4D",
|
|
21139
|
+
"duration.seconds": "\u79D2",
|
|
21140
|
+
"duration.minutes": "\u5206\u949F",
|
|
21141
|
+
"duration.hours": "\u5C0F\u65F6",
|
|
21142
|
+
"duration.days": "\u5929",
|
|
21143
|
+
"duration.systemDefault": "\u4F7F\u7528 Gateway \u9ED8\u8BA4\u8D85\u65F6",
|
|
21144
|
+
"duration.immediate": "\u7ACB\u5373\u91CD\u8BD5",
|
|
21145
|
+
"duration.custom": "\u81EA\u5B9A\u4E49\u2026",
|
|
21146
|
+
"duration.every": "\u6BCF {duration}",
|
|
20870
21147
|
"system.worker": "\u4EFB\u52A1\u6267\u884C",
|
|
20871
21148
|
"system.scheduler": "\u5B9A\u65F6\u4EFB\u52A1\u670D\u52A1",
|
|
20872
21149
|
"system.watchdog": "\u8FD0\u884C\u76D1\u63A7",
|
|
@@ -20914,6 +21191,9 @@ var init_ui = __esm({
|
|
|
20914
21191
|
"template.interval": "\u6267\u884C\u95F4\u9694",
|
|
20915
21192
|
"template.runAt": "\u6267\u884C\u65F6\u95F4",
|
|
20916
21193
|
"template.durationHint": "\u652F\u6301 30s\u30015min\u30011h\u30012d",
|
|
21194
|
+
"template.intervalHint": "\u76F4\u63A5\u9009\u62E9\u5E38\u7528\u9891\u7387\uFF1B\u53EA\u6709\u7279\u6B8A\u9700\u6C42\u624D\u9700\u8981\u81EA\u5B9A\u4E49\u3002",
|
|
21195
|
+
"template.retryBackoffHint": "\u4E00\u6B21\u5931\u8D25\u540E\uFF0C\u7B49\u5F85\u591A\u4E45\u518D\u91CD\u8BD5\u3002",
|
|
21196
|
+
"template.timeoutHint": "\u7559\u7A7A\u8868\u793A\u4F7F\u7528 Gateway \u7684\u9ED8\u8BA4\u4EFB\u52A1\u8D85\u65F6\u3002",
|
|
20917
21197
|
"template.advanced": "\u66F4\u591A\u6267\u884C\u8BBE\u7F6E",
|
|
20918
21198
|
"template.category": "\u5206\u7C7B",
|
|
20919
21199
|
"template.batchId": "\u6279\u6B21 ID",
|
|
@@ -20938,14 +21218,73 @@ var init_ui = __esm({
|
|
|
20938
21218
|
"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",
|
|
20939
21219
|
"task.projectExisting": "\u6B64\u9879\u76EE\u73B0\u6709 {total} \u4E2A\u4EFB\u52A1\uFF1A\u8FD0\u884C {running}\uFF0C\u6392\u961F {pending}\uFF0C\u5F02\u5E38 {failed}\u3002",
|
|
20940
21220
|
"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",
|
|
21221
|
+
"catalog.chooseProject": "\u8BF7\u5148\u9009\u62E9\u9879\u76EE\u76EE\u5F55",
|
|
21222
|
+
"catalog.defaultModel": "\u8DDF\u968F Agent / OpenCode \u9ED8\u8BA4\u6A21\u578B",
|
|
21223
|
+
"catalog.defaultProvider": "\u9ED8\u8BA4\u6A21\u578B",
|
|
21224
|
+
"catalog.provider": "\u6A21\u578B\u63D0\u4F9B\u5546",
|
|
21225
|
+
"catalog.model": "\u5177\u4F53\u6A21\u578B",
|
|
21226
|
+
"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",
|
|
21227
|
+
"catalog.agentHint": "\u6765\u81EA\u5F53\u524D\u9879\u76EE\u7684 opencode agent list\u3002",
|
|
21228
|
+
"catalog.loading": "\u6B63\u5728\u8BFB\u53D6\u6B64\u9879\u76EE\u53EF\u7528\u7684 Agent \u548C\u6A21\u578B\u2026",
|
|
21229
|
+
"catalog.loaded": "\u5DF2\u4ECE\u672C\u673A OpenCode \u8BFB\u53D6 {agents} \u4E2A Agent\u3001{models} \u4E2A\u6A21\u578B\u3002",
|
|
21230
|
+
"catalog.failed": "\u65E0\u6CD5\u8BFB\u53D6\u6B64\u9879\u76EE\u7684 OpenCode \u914D\u7F6E\uFF1A{error}",
|
|
21231
|
+
"catalog.primary": "\u4E3B Agent",
|
|
21232
|
+
"catalog.subagent": "\u5B50 Agent",
|
|
21233
|
+
"catalog.all": "\u901A\u7528 Agent",
|
|
21234
|
+
"directory.title": "\u9009\u62E9\u9879\u76EE\u76EE\u5F55",
|
|
21235
|
+
"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",
|
|
21236
|
+
"directory.empty": "\u8FD9\u4E2A\u6587\u4EF6\u5939\u4E2D\u6CA1\u6709\u5B50\u6587\u4EF6\u5939",
|
|
21237
|
+
"logs.command": "\u5B9E\u9645\u6267\u884C\u547D\u4EE4",
|
|
21238
|
+
"logs.output": "Agent \u8F93\u51FA",
|
|
21239
|
+
"logs.error": "\u5931\u8D25\u539F\u56E0",
|
|
21240
|
+
"logs.tools": "\u5DE5\u5177\u8C03\u7528",
|
|
21241
|
+
"logs.raw": "\u67E5\u770B\u539F\u59CB\u6267\u884C\u65E5\u5FD7",
|
|
21242
|
+
"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",
|
|
20941
21243
|
"theme.label": "\u4E3B\u9898",
|
|
20942
21244
|
"theme.system": "\u8DDF\u968F\u7CFB\u7EDF",
|
|
20943
21245
|
"theme.light": "\u6D45\u8272",
|
|
20944
21246
|
"theme.dark": "\u6DF1\u8272",
|
|
20945
21247
|
"language.label": "\u8BED\u8A00",
|
|
20946
|
-
"details.title": "\
|
|
20947
|
-
"details.subtitle": "\u539F\u59CB\
|
|
20948
|
-
"details.
|
|
21248
|
+
"details.title": "\u8BE6\u60C5",
|
|
21249
|
+
"details.subtitle": "\u91CD\u70B9\u4FE1\u606F\u5DF2\u6574\u7406\uFF1B\u539F\u59CB\u6570\u636E\u4EC5\u7528\u4E8E\u6392\u969C\u3002",
|
|
21250
|
+
"details.taskTitle": "\u4EFB\u52A1\u8BE6\u60C5",
|
|
21251
|
+
"details.runTitle": "\u6267\u884C\u8BE6\u60C5",
|
|
21252
|
+
"details.templateTitle": "\u5B9A\u65F6\u4EFB\u52A1\u8BE6\u60C5",
|
|
21253
|
+
"details.raw": "\u67E5\u770B\u539F\u59CB\u6570\u636E\uFF08JSON\uFF09",
|
|
21254
|
+
"details.copySuccess": "\u539F\u59CB\u6570\u636E\u5DF2\u590D\u5236",
|
|
21255
|
+
"details.id": "\u7F16\u53F7",
|
|
21256
|
+
"details.project": "\u9879\u76EE\u76EE\u5F55",
|
|
21257
|
+
"details.prompt": "\u63D0\u793A\u8BCD",
|
|
21258
|
+
"details.result": "\u6267\u884C\u7ED3\u679C / \u5931\u8D25\u539F\u56E0",
|
|
21259
|
+
"details.category": "\u5206\u7C7B",
|
|
21260
|
+
"details.batch": "\u6279\u6B21",
|
|
21261
|
+
"details.dependency": "\u4F9D\u8D56\u4EFB\u52A1",
|
|
21262
|
+
"details.importance": "\u91CD\u8981\u7A0B\u5EA6",
|
|
21263
|
+
"details.urgency": "\u7D27\u6025\u7A0B\u5EA6",
|
|
21264
|
+
"details.retryCount": "\u5DF2\u91CD\u8BD5 / \u6700\u591A\u91CD\u8BD5",
|
|
21265
|
+
"details.retryBackoff": "\u91CD\u8BD5\u7B49\u5F85",
|
|
21266
|
+
"details.timeout": "\u6267\u884C\u8D85\u65F6",
|
|
21267
|
+
"details.createdAt": "\u521B\u5EFA\u65F6\u95F4",
|
|
21268
|
+
"details.updatedAt": "\u66F4\u65B0\u65F6\u95F4",
|
|
21269
|
+
"details.startedAt": "\u5F00\u59CB\u65F6\u95F4",
|
|
21270
|
+
"details.finishedAt": "\u7ED3\u675F\u65F6\u95F4",
|
|
21271
|
+
"details.scheduledAt": "\u8BA1\u5212\u65F6\u95F4",
|
|
21272
|
+
"details.enabled": "\u81EA\u52A8\u8FD0\u884C",
|
|
21273
|
+
"details.scheduleRule": "\u8FD0\u884C\u89C4\u5219",
|
|
21274
|
+
"details.maxInstances": "\u81EA\u52A8\u8C03\u5EA6\u4E0A\u9650",
|
|
21275
|
+
"details.maxRetries": "\u5931\u8D25\u91CD\u8BD5\u6B21\u6570",
|
|
21276
|
+
"details.lastRun": "\u4E0A\u6B21\u8FD0\u884C",
|
|
21277
|
+
"details.nextRun": "\u4E0B\u6B21\u8FD0\u884C",
|
|
21278
|
+
"details.taskId": "\u6240\u5C5E\u4EFB\u52A1",
|
|
21279
|
+
"details.session": "OpenCode \u4F1A\u8BDD",
|
|
21280
|
+
"details.heartbeat": "\u6700\u8FD1\u5FC3\u8DF3",
|
|
21281
|
+
"details.process": "\u8FDB\u7A0B",
|
|
21282
|
+
"details.history": "\u6267\u884C\u5386\u53F2",
|
|
21283
|
+
"details.noHistory": "\u8FD8\u6CA1\u6709\u6267\u884C\u8BB0\u5F55",
|
|
21284
|
+
"details.none": "\u65E0",
|
|
21285
|
+
"details.default": "\u8DDF\u968F\u7CFB\u7EDF\u9ED8\u8BA4",
|
|
21286
|
+
"details.enabledYes": "\u5DF2\u542F\u7528",
|
|
21287
|
+
"details.enabledNo": "\u5DF2\u505C\u7528",
|
|
20949
21288
|
"dialog.cancelTask": "\u53D6\u6D88\u4EFB\u52A1 #{id}\uFF1F",
|
|
20950
21289
|
"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",
|
|
20951
21290
|
"dialog.retryTask": "\u91CD\u8BD5\u4EFB\u52A1 #{id}\uFF1F",
|
|
@@ -20975,6 +21314,7 @@ var init_ui = __esm({
|
|
|
20975
21314
|
"feedback.templateUpdated": "\u5B9A\u65F6\u4EFB\u52A1\u5DF2\u66F4\u65B0",
|
|
20976
21315
|
"feedback.configSaved": "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58",
|
|
20977
21316
|
"feedback.sessionCommandCopied": "\u4F1A\u8BDD\u547D\u4EE4\u5DF2\u590D\u5236\uFF0C\u53EF\u76F4\u63A5\u7C98\u8D34\u5230\u7EC8\u7AEF\u8FD0\u884C",
|
|
21317
|
+
"feedback.commandCopied": "\u6267\u884C\u547D\u4EE4\u5DF2\u590D\u5236",
|
|
20978
21318
|
"feedback.restarting": "Gateway \u6B63\u5728\u91CD\u542F\uFF0C\u8BF7\u7A0D\u5019\u2026",
|
|
20979
21319
|
"feedback.restartTimeout": "Gateway \u5C1A\u672A\u6062\u590D\uFF0C\u8BF7\u7A0D\u540E\u5237\u65B0\u6216\u68C0\u67E5 PM2 \u72B6\u6001",
|
|
20980
21320
|
"feedback.databaseCleared": "\u6570\u636E\u5E93\u5DF2\u6E05\u7A7A\uFF0C\u5907\u4EFD\u4F4D\u4E8E\uFF1A{path}",
|
|
@@ -21014,7 +21354,7 @@ var init_ui = __esm({
|
|
|
21014
21354
|
"action.hideLogs": "Hide log",
|
|
21015
21355
|
"action.save": "Save settings",
|
|
21016
21356
|
"action.saveAndRestart": "Save and restart",
|
|
21017
|
-
"action.copy": "Copy
|
|
21357
|
+
"action.copy": "Copy raw data",
|
|
21018
21358
|
"action.close": "Close",
|
|
21019
21359
|
"action.confirm": "Confirm",
|
|
21020
21360
|
"action.clearDatabase": "Clear database",
|
|
@@ -21023,6 +21363,13 @@ var init_ui = __esm({
|
|
|
21023
21363
|
"action.updateTask": "Save changes",
|
|
21024
21364
|
"action.createTemplate": "New scheduled task",
|
|
21025
21365
|
"action.saveTemplate": "Save scheduled task",
|
|
21366
|
+
"action.chooseFolder": "Choose folder",
|
|
21367
|
+
"action.chooseThisFolder": "Choose this folder",
|
|
21368
|
+
"action.home": "Home",
|
|
21369
|
+
"action.up": "Up",
|
|
21370
|
+
"action.copyCommand": "Copy command",
|
|
21371
|
+
"action.showHidden": "Show hidden folders",
|
|
21372
|
+
"action.hideHidden": "Hide hidden folders",
|
|
21026
21373
|
"status.pending": "Pending",
|
|
21027
21374
|
"status.running": "Running",
|
|
21028
21375
|
"status.done": "Done",
|
|
@@ -21089,6 +21436,15 @@ var init_ui = __esm({
|
|
|
21089
21436
|
"schedule.hours": "{count} hr",
|
|
21090
21437
|
"schedule.days": "{count} days",
|
|
21091
21438
|
"schedule.overdue": "Overdue",
|
|
21439
|
+
"duration.unit": "Time unit",
|
|
21440
|
+
"duration.seconds": "seconds",
|
|
21441
|
+
"duration.minutes": "minutes",
|
|
21442
|
+
"duration.hours": "hours",
|
|
21443
|
+
"duration.days": "days",
|
|
21444
|
+
"duration.systemDefault": "Use Gateway default timeout",
|
|
21445
|
+
"duration.immediate": "Retry immediately",
|
|
21446
|
+
"duration.custom": "Custom\u2026",
|
|
21447
|
+
"duration.every": "Every {duration}",
|
|
21092
21448
|
"system.worker": "Task execution",
|
|
21093
21449
|
"system.scheduler": "Scheduled task service",
|
|
21094
21450
|
"system.watchdog": "Runtime monitor",
|
|
@@ -21136,6 +21492,9 @@ var init_ui = __esm({
|
|
|
21136
21492
|
"template.interval": "Interval",
|
|
21137
21493
|
"template.runAt": "Run at",
|
|
21138
21494
|
"template.durationHint": "Supports 30s, 5min, 1h, 2d",
|
|
21495
|
+
"template.intervalHint": "Choose a common frequency directly; customize only when necessary.",
|
|
21496
|
+
"template.retryBackoffHint": "How long to wait after a failure before retrying.",
|
|
21497
|
+
"template.timeoutHint": "Leave blank to use the Gateway default task timeout.",
|
|
21139
21498
|
"template.advanced": "More execution settings",
|
|
21140
21499
|
"template.category": "Category",
|
|
21141
21500
|
"template.batchId": "Batch ID",
|
|
@@ -21160,14 +21519,73 @@ var init_ui = __esm({
|
|
|
21160
21519
|
"task.batchHint": "Tasks with the same non-empty batch ID run serially. Blank removes the batch constraint; global concurrency and dependencies still apply.",
|
|
21161
21520
|
"task.projectExisting": "This project has {total} tasks: {running} running, {pending} queued, and {failed} with issues.",
|
|
21162
21521
|
"task.projectNew": "This is a new project group. It appears in the project list after creation.",
|
|
21522
|
+
"catalog.chooseProject": "Choose a project directory first",
|
|
21523
|
+
"catalog.defaultModel": "Use the Agent / OpenCode default model",
|
|
21524
|
+
"catalog.defaultProvider": "Default model",
|
|
21525
|
+
"catalog.provider": "Model provider",
|
|
21526
|
+
"catalog.model": "Model",
|
|
21527
|
+
"catalog.modelHint": "Choose a provider, then a model returned by opencode models for this project. Default does not pass -m.",
|
|
21528
|
+
"catalog.agentHint": "Loaded from opencode agent list for this project.",
|
|
21529
|
+
"catalog.loading": "Loading Agents and models available to this project\u2026",
|
|
21530
|
+
"catalog.loaded": "Loaded {agents} Agents and {models} models from local OpenCode.",
|
|
21531
|
+
"catalog.failed": "Could not load this project\u2019s OpenCode configuration: {error}",
|
|
21532
|
+
"catalog.primary": "primary Agent",
|
|
21533
|
+
"catalog.subagent": "subagent",
|
|
21534
|
+
"catalog.all": "general Agent",
|
|
21535
|
+
"directory.title": "Choose project directory",
|
|
21536
|
+
"directory.subtitle": "OpenCode runs in this directory, and its project-specific Agents and models are loaded.",
|
|
21537
|
+
"directory.empty": "This folder has no subfolders",
|
|
21538
|
+
"logs.command": "Executed command",
|
|
21539
|
+
"logs.output": "Agent output",
|
|
21540
|
+
"logs.error": "Failure reason",
|
|
21541
|
+
"logs.tools": "Tool calls",
|
|
21542
|
+
"logs.raw": "View raw execution log",
|
|
21543
|
+
"logs.noText": "This run produced no displayable text. Inspect the raw log for details.",
|
|
21163
21544
|
"theme.label": "Theme",
|
|
21164
21545
|
"theme.system": "System",
|
|
21165
21546
|
"theme.light": "Light",
|
|
21166
21547
|
"theme.dark": "Dark",
|
|
21167
21548
|
"language.label": "Language",
|
|
21168
|
-
"details.title": "
|
|
21169
|
-
"details.subtitle": "
|
|
21170
|
-
"details.
|
|
21549
|
+
"details.title": "Details",
|
|
21550
|
+
"details.subtitle": "Key information is organized below; raw data is only for troubleshooting.",
|
|
21551
|
+
"details.taskTitle": "Task details",
|
|
21552
|
+
"details.runTitle": "Run details",
|
|
21553
|
+
"details.templateTitle": "Scheduled task details",
|
|
21554
|
+
"details.raw": "View raw data (JSON)",
|
|
21555
|
+
"details.copySuccess": "Raw data copied",
|
|
21556
|
+
"details.id": "ID",
|
|
21557
|
+
"details.project": "Project directory",
|
|
21558
|
+
"details.prompt": "Prompt",
|
|
21559
|
+
"details.result": "Result / failure reason",
|
|
21560
|
+
"details.category": "Category",
|
|
21561
|
+
"details.batch": "Batch",
|
|
21562
|
+
"details.dependency": "Dependency",
|
|
21563
|
+
"details.importance": "Importance",
|
|
21564
|
+
"details.urgency": "Urgency",
|
|
21565
|
+
"details.retryCount": "Retries used / allowed",
|
|
21566
|
+
"details.retryBackoff": "Retry delay",
|
|
21567
|
+
"details.timeout": "Run timeout",
|
|
21568
|
+
"details.createdAt": "Created",
|
|
21569
|
+
"details.updatedAt": "Updated",
|
|
21570
|
+
"details.startedAt": "Started",
|
|
21571
|
+
"details.finishedAt": "Finished",
|
|
21572
|
+
"details.scheduledAt": "Scheduled for",
|
|
21573
|
+
"details.enabled": "Automatic runs",
|
|
21574
|
+
"details.scheduleRule": "Schedule rule",
|
|
21575
|
+
"details.maxInstances": "Automatic scheduling limit",
|
|
21576
|
+
"details.maxRetries": "Failure retries",
|
|
21577
|
+
"details.lastRun": "Last run",
|
|
21578
|
+
"details.nextRun": "Next run",
|
|
21579
|
+
"details.taskId": "Task",
|
|
21580
|
+
"details.session": "OpenCode session",
|
|
21581
|
+
"details.heartbeat": "Latest heartbeat",
|
|
21582
|
+
"details.process": "Processes",
|
|
21583
|
+
"details.history": "Run history",
|
|
21584
|
+
"details.noHistory": "No runs yet",
|
|
21585
|
+
"details.none": "None",
|
|
21586
|
+
"details.default": "Use system default",
|
|
21587
|
+
"details.enabledYes": "Enabled",
|
|
21588
|
+
"details.enabledNo": "Disabled",
|
|
21171
21589
|
"dialog.cancelTask": "Cancel task #{id}?",
|
|
21172
21590
|
"dialog.cancelTaskBody": "A running task will terminate its process tree on the next worker poll.",
|
|
21173
21591
|
"dialog.retryTask": "Retry task #{id}?",
|
|
@@ -21197,6 +21615,7 @@ var init_ui = __esm({
|
|
|
21197
21615
|
"feedback.templateUpdated": "Scheduled task updated",
|
|
21198
21616
|
"feedback.configSaved": "Settings saved",
|
|
21199
21617
|
"feedback.sessionCommandCopied": "Session command copied. Paste it into a terminal to continue.",
|
|
21618
|
+
"feedback.commandCopied": "Execution command copied",
|
|
21200
21619
|
"feedback.restarting": "Gateway is restarting\u2026",
|
|
21201
21620
|
"feedback.restartTimeout": "Gateway has not recovered yet. Refresh later or check PM2 status.",
|
|
21202
21621
|
"feedback.databaseCleared": "Database cleared. Backup: {path}",
|
|
@@ -21407,6 +21826,20 @@ var init_ui = __esm({
|
|
|
21407
21826
|
.danger-card h2 .icon { width:17px; height:17px; }
|
|
21408
21827
|
.danger-card p { max-width:800px; margin:0 0 14px; color:var(--text-2); font-size:12px; }
|
|
21409
21828
|
.log-panel { margin:12px 0; animation:reveal .18s ease both; }
|
|
21829
|
+
.run-log-row td { padding:0 16px 16px; background:color-mix(in srgb,var(--surface-2) 64%,var(--surface)); }
|
|
21830
|
+
.run-log-row .log-panel { margin:0; box-shadow:none; }
|
|
21831
|
+
.log-content { display:grid; gap:14px; padding:16px; }
|
|
21832
|
+
.log-section-head { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:7px; }
|
|
21833
|
+
.run-command,.run-output,.run-error,.run-tools { min-width:0; }
|
|
21834
|
+
.run-command strong,.run-output>strong,.run-error>strong,.run-tools>strong { display:block; margin-bottom:7px; font-size:12px; }
|
|
21835
|
+
.command-cwd { margin-bottom:6px; color:var(--text-3); font-family:"SFMono-Regular",Consolas,monospace; font-size:10px; overflow-wrap:anywhere; }
|
|
21836
|
+
.run-command pre,.run-output pre,.run-error pre { margin:0; padding:12px; overflow:auto; border:1px solid var(--border); border-radius:9px;
|
|
21837
|
+
color:var(--text-2); background:var(--surface-2); font-family:"SFMono-Regular",Consolas,monospace; font-size:11px; white-space:pre-wrap; overflow-wrap:anywhere; }
|
|
21838
|
+
.run-output pre { color:var(--text); font-family:inherit; font-size:13px; line-height:1.65; }
|
|
21839
|
+
.run-error pre { color:var(--red); border-color:color-mix(in srgb,var(--red) 28%,var(--border)); background:var(--red-soft); }
|
|
21840
|
+
.raw-log { padding-top:12px; border-top:1px solid var(--border); }
|
|
21841
|
+
.raw-log summary { color:var(--text-2); cursor:pointer; font-size:12px; font-weight:650; }
|
|
21842
|
+
.raw-log .log-box { margin-top:10px; border-radius:9px; }
|
|
21410
21843
|
.log-box { max-height:360px; overflow:auto; padding:16px; color:var(--text-2); background:#0b1018; font-family:"SFMono-Regular",Consolas,monospace;
|
|
21411
21844
|
font-size:12px; white-space:pre-wrap; overflow-wrap:anywhere; }
|
|
21412
21845
|
:root[data-theme="light"] .log-box { color:#dbe5f3; }
|
|
@@ -21425,14 +21858,48 @@ var init_ui = __esm({
|
|
|
21425
21858
|
.form-field-wide { grid-column:1 / -1; }
|
|
21426
21859
|
.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;
|
|
21427
21860
|
outline:none; color:var(--text); background:var(--surface-2); font-weight:450; }
|
|
21861
|
+
.field-action { display:flex; align-items:stretch; gap:7px; }
|
|
21862
|
+
.field-action input { min-width:0; flex:1; }
|
|
21863
|
+
.field-action .btn { flex:0 0 auto; white-space:nowrap; }
|
|
21864
|
+
.model-selector { display:grid; grid-template-columns:minmax(120px,.75fr) minmax(0,1.25fr); gap:7px; }
|
|
21865
|
+
.duration-picker { display:grid; gap:7px; }
|
|
21866
|
+
.duration-control { display:grid; grid-template-columns:minmax(0,1fr) 112px; gap:7px; }
|
|
21867
|
+
.duration-control input,.duration-control select { min-width:0; }
|
|
21428
21868
|
.form-field textarea { resize:vertical; line-height:1.5; }
|
|
21429
21869
|
.form-field input:focus,.form-field select:focus,.form-field textarea:focus { border-color:var(--primary); box-shadow:var(--focus); background:var(--surface); }
|
|
21430
21870
|
.form-field small { color:var(--text-3); font-size:10px; font-weight:450; }
|
|
21431
21871
|
.advanced-fields { margin-top:18px; padding-top:14px; border-top:1px solid var(--border); }
|
|
21432
21872
|
.advanced-fields summary { margin-bottom:14px; color:var(--text-2); cursor:pointer; font-size:12px; font-weight:700; }
|
|
21433
21873
|
.form-note { margin:16px 0 0; color:var(--text-3); font-size:11px; }
|
|
21434
|
-
.
|
|
21435
|
-
|
|
21874
|
+
.catalog-status[data-state="loading"] { color:var(--blue); }
|
|
21875
|
+
.catalog-status[data-state="ready"] { color:var(--green); }
|
|
21876
|
+
.catalog-status[data-state="error"] { color:var(--red); }
|
|
21877
|
+
.directory-dialog { width:min(720px,calc(100% - 32px)); }
|
|
21878
|
+
.directory-toolbar { display:flex; align-items:center; gap:8px; margin-bottom:12px; }
|
|
21879
|
+
.directory-path { min-width:0; flex:1; padding:9px 11px; overflow:hidden; border:1px solid var(--border); border-radius:9px;
|
|
21880
|
+
color:var(--text-2); background:var(--surface-2); font-family:"SFMono-Regular",Consolas,monospace; font-size:11px; text-overflow:ellipsis; white-space:nowrap; }
|
|
21881
|
+
.directory-list { min-height:260px; max-height:48vh; display:grid; align-content:start; gap:6px; overflow:auto; }
|
|
21882
|
+
.directory-item { width:100%; min-height:40px; display:flex; align-items:center; gap:9px; padding:0 11px; border:1px solid transparent; border-radius:9px;
|
|
21883
|
+
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; }
|
|
21884
|
+
.directory-item:hover { color:var(--text); border-color:var(--border); background:var(--surface-2); }
|
|
21885
|
+
.directory-item:active { transform:scale(.99); }
|
|
21886
|
+
.directory-item .icon { width:17px; height:17px; color:var(--primary); flex:0 0 auto; }
|
|
21887
|
+
.directory-empty { min-height:220px; display:grid; place-items:center; color:var(--text-3); }
|
|
21888
|
+
.detail-view { display:grid; gap:16px; }
|
|
21889
|
+
.detail-grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; }
|
|
21890
|
+
.detail-item { min-width:0; padding:12px 13px; border:1px solid var(--border); border-radius:10px; background:var(--surface-2); }
|
|
21891
|
+
.detail-item.wide { grid-column:1 / -1; }
|
|
21892
|
+
.detail-label { margin-bottom:5px; color:var(--text-3); font-size:10px; font-weight:750; letter-spacing:.045em; text-transform:uppercase; }
|
|
21893
|
+
.detail-value { color:var(--text); font-size:13px; line-height:1.55; overflow-wrap:anywhere; }
|
|
21894
|
+
.detail-value.mono { font-family:"SFMono-Regular",Consolas,monospace; font-size:11px; }
|
|
21895
|
+
.detail-value.long { max-height:240px; margin:0; overflow:auto; white-space:pre-wrap; }
|
|
21896
|
+
.detail-history h3 { margin:0 0 8px; font-size:13px; }
|
|
21897
|
+
.detail-history-list { display:grid; gap:7px; }
|
|
21898
|
+
.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; }
|
|
21899
|
+
.detail-raw { padding-top:12px; border-top:1px solid var(--border); }
|
|
21900
|
+
.detail-raw summary { color:var(--text-2); cursor:pointer; font-size:12px; font-weight:650; }
|
|
21901
|
+
.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);
|
|
21902
|
+
background:var(--surface-2); font-family:"SFMono-Regular",Consolas,monospace; font-size:11px; white-space:pre-wrap; overflow-wrap:anywhere; }
|
|
21436
21903
|
.confirm-copy { color:var(--text-2); margin:0; }
|
|
21437
21904
|
.confirm-copy strong { display:block; margin-bottom:5px; color:var(--text); font-size:15px; }
|
|
21438
21905
|
.danger-input { width:100%; height:40px; margin-top:14px; padding:0 12px; border:1px solid var(--border); border-radius:9px; outline:none;
|
|
@@ -21496,9 +21963,17 @@ var init_ui = __esm({
|
|
|
21496
21963
|
.responsive-table td[data-primary]::before { display:none; }
|
|
21497
21964
|
.responsive-table .task-prompt { max-width:100%; }
|
|
21498
21965
|
.responsive-table .actions { justify-content:flex-start; }
|
|
21966
|
+
.responsive-table .run-log-row { padding:0; overflow:hidden; }
|
|
21967
|
+
.responsive-table .run-log-cell { display:block; padding:0; }
|
|
21968
|
+
.responsive-table .run-log-cell::before { display:none; }
|
|
21499
21969
|
.project-grid { grid-template-columns:1fr; }
|
|
21500
21970
|
.template-form-grid { grid-template-columns:1fr; }
|
|
21971
|
+
.detail-grid { grid-template-columns:1fr; }
|
|
21972
|
+
.detail-item.wide { grid-column:auto; }
|
|
21501
21973
|
.form-field-wide { grid-column:auto; }
|
|
21974
|
+
.field-action { align-items:stretch; flex-direction:column; }
|
|
21975
|
+
.field-action .btn { width:100%; }
|
|
21976
|
+
.model-selector { grid-template-columns:1fr; }
|
|
21502
21977
|
}
|
|
21503
21978
|
@media (max-width:520px) {
|
|
21504
21979
|
.stats-grid,.stats-grid.three { grid-template-columns:1fr 1fr; }
|
|
@@ -21528,11 +22003,21 @@ __export(web_exports, {
|
|
|
21528
22003
|
dashboardApp: () => dashboardApp,
|
|
21529
22004
|
default: () => web_default,
|
|
21530
22005
|
isSafeDashboardRestartTarget: () => isSafeDashboardRestartTarget,
|
|
22006
|
+
presentRunLog: () => presentRunLog,
|
|
21531
22007
|
resolveDashboardConfigState: () => resolveDashboardConfigState,
|
|
21532
22008
|
setDashboardRuntimeConfig: () => setDashboardRuntimeConfig
|
|
21533
22009
|
});
|
|
21534
|
-
import {
|
|
21535
|
-
|
|
22010
|
+
import {
|
|
22011
|
+
existsSync as existsSync7,
|
|
22012
|
+
mkdirSync as mkdirSync4,
|
|
22013
|
+
readFileSync as readFileSync4,
|
|
22014
|
+
readdirSync,
|
|
22015
|
+
renameSync as renameSync2,
|
|
22016
|
+
statSync as statSync4,
|
|
22017
|
+
writeFileSync as writeFileSync3
|
|
22018
|
+
} from "fs";
|
|
22019
|
+
import { homedir as homedir4 } from "os";
|
|
22020
|
+
import { basename as basename3, dirname as dirname7, join as join6 } from "path";
|
|
21536
22021
|
function setDashboardRuntimeConfig(config) {
|
|
21537
22022
|
runtimeConfig = config === null ? null : structuredClone(config);
|
|
21538
22023
|
}
|
|
@@ -21573,6 +22058,23 @@ function parsePositiveInteger(value) {
|
|
|
21573
22058
|
function parseTaskStatus(value) {
|
|
21574
22059
|
return TASK_STATUSES.has(value) ? value : null;
|
|
21575
22060
|
}
|
|
22061
|
+
function listChildDirectories(path) {
|
|
22062
|
+
return readdirSync(path, { withFileTypes: true }).flatMap((entry) => {
|
|
22063
|
+
const entryPath = join6(path, entry.name);
|
|
22064
|
+
if (entry.isDirectory()) return [{ name: entry.name, path: entryPath, hidden: entry.name.startsWith(".") }];
|
|
22065
|
+
if (!entry.isSymbolicLink()) return [];
|
|
22066
|
+
try {
|
|
22067
|
+
return statSync4(entryPath).isDirectory() ? [{ name: entry.name, path: entryPath, hidden: entry.name.startsWith(".") }] : [];
|
|
22068
|
+
} catch {
|
|
22069
|
+
return [];
|
|
22070
|
+
}
|
|
22071
|
+
}).sort((left, right) => {
|
|
22072
|
+
const leftHidden = left.name.startsWith(".");
|
|
22073
|
+
const rightHidden = right.name.startsWith(".");
|
|
22074
|
+
if (leftHidden !== rightHidden) return leftHidden ? 1 : -1;
|
|
22075
|
+
return left.name.localeCompare(right.name);
|
|
22076
|
+
});
|
|
22077
|
+
}
|
|
21576
22078
|
function parseTaskPayload(value) {
|
|
21577
22079
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
21578
22080
|
throw new Error("\u8BF7\u6C42\u5185\u5BB9\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
@@ -21729,6 +22231,66 @@ function formatDuration(startAt, endAt) {
|
|
|
21729
22231
|
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
|
|
21730
22232
|
return `${Math.floor(seconds / 3600)}h ${Math.floor(seconds % 3600 / 60)}m`;
|
|
21731
22233
|
}
|
|
22234
|
+
function recordValue(value) {
|
|
22235
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
22236
|
+
}
|
|
22237
|
+
function shellQuote(value) {
|
|
22238
|
+
if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value)) return value;
|
|
22239
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
22240
|
+
}
|
|
22241
|
+
function presentRunLog(log) {
|
|
22242
|
+
let command = null;
|
|
22243
|
+
const textParts = [];
|
|
22244
|
+
const errors = [];
|
|
22245
|
+
const tools = [];
|
|
22246
|
+
for (const line of log.split("\n")) {
|
|
22247
|
+
const trimmed = line.trim();
|
|
22248
|
+
if (!trimmed) continue;
|
|
22249
|
+
let parsed = null;
|
|
22250
|
+
try {
|
|
22251
|
+
parsed = recordValue(JSON.parse(trimmed));
|
|
22252
|
+
} catch {
|
|
22253
|
+
errors.push(line);
|
|
22254
|
+
continue;
|
|
22255
|
+
}
|
|
22256
|
+
if (!parsed) continue;
|
|
22257
|
+
if (parsed.type === "supertask_command") {
|
|
22258
|
+
const executable = typeof parsed.executable === "string" ? parsed.executable : null;
|
|
22259
|
+
const cwd = typeof parsed.cwd === "string" ? parsed.cwd : null;
|
|
22260
|
+
const args = Array.isArray(parsed.args) && parsed.args.every((item) => typeof item === "string") ? parsed.args : null;
|
|
22261
|
+
if (executable && cwd && args) {
|
|
22262
|
+
command = {
|
|
22263
|
+
cwd,
|
|
22264
|
+
command: `cd ${shellQuote(cwd)} && ${[executable, ...args].map(shellQuote).join(" ")}`
|
|
22265
|
+
};
|
|
22266
|
+
}
|
|
22267
|
+
continue;
|
|
22268
|
+
}
|
|
22269
|
+
const part = recordValue(parsed.part);
|
|
22270
|
+
const eventType = typeof parsed.type === "string" ? parsed.type : "";
|
|
22271
|
+
const partType = typeof part?.type === "string" ? part.type : "";
|
|
22272
|
+
const text2 = typeof part?.text === "string" ? part.text : typeof parsed.text === "string" ? parsed.text : null;
|
|
22273
|
+
if (text2 && (eventType === "text" || partType === "text")) textParts.push(text2);
|
|
22274
|
+
const tool = typeof part?.tool === "string" ? part.tool : typeof parsed.tool === "string" ? parsed.tool : null;
|
|
22275
|
+
if (tool && (eventType === "tool_use" || partType === "tool")) tools.push(tool);
|
|
22276
|
+
const error = typeof parsed.error === "string" ? parsed.error : typeof part?.error === "string" ? part.error : null;
|
|
22277
|
+
if (error) errors.push(error);
|
|
22278
|
+
}
|
|
22279
|
+
return {
|
|
22280
|
+
command,
|
|
22281
|
+
text: textParts.join("\n").trim(),
|
|
22282
|
+
errors: [...new Set(errors)],
|
|
22283
|
+
tools
|
|
22284
|
+
};
|
|
22285
|
+
}
|
|
22286
|
+
function renderRunLog(runId, taskName, log, locale) {
|
|
22287
|
+
const presentation = presentRunLog(log);
|
|
22288
|
+
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>` : "";
|
|
22289
|
+
const errors = presentation.errors.length > 0 ? `<div class="run-error"><strong>${t(locale, "logs.error")}</strong><pre>${esc(presentation.errors.join("\n"))}</pre></div>` : "";
|
|
22290
|
+
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>` : "";
|
|
22291
|
+
const output = `<div class="run-output"><strong>${t(locale, "logs.output")}</strong><pre>${esc(presentation.text || t(locale, "logs.noText"))}</pre></div>`;
|
|
22292
|
+
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>`;
|
|
22293
|
+
}
|
|
21732
22294
|
function esc(value) {
|
|
21733
22295
|
if (!value) return "";
|
|
21734
22296
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -21760,6 +22322,25 @@ function emptyState(title, hint, code = "") {
|
|
|
21760
22322
|
return `<div class="empty-state"><div><div class="empty-icon">${icon("inbox")}</div>
|
|
21761
22323
|
<h3>${title}</h3><p>${hint}</p>${code ? `<code>${code}</code>` : ""}</div></div>`;
|
|
21762
22324
|
}
|
|
22325
|
+
function durationControl(locale, id, value, kind) {
|
|
22326
|
+
const units = [
|
|
22327
|
+
{ value: "s", label: t(locale, "duration.seconds") },
|
|
22328
|
+
{ value: "min", label: t(locale, "duration.minutes") },
|
|
22329
|
+
{ value: "h", label: t(locale, "duration.hours") },
|
|
22330
|
+
{ value: "d", label: t(locale, "duration.days") }
|
|
22331
|
+
];
|
|
22332
|
+
const values = kind === "interval" ? [3e5, 9e5, 18e5, 36e5, 216e5, 432e5, 864e5] : kind === "retry" ? [0, 1e4, 3e4, 6e4, 3e5] : [3e5, 9e5, 18e5, 36e5, 72e5, 144e5];
|
|
22333
|
+
const presets = [
|
|
22334
|
+
...kind === "timeout" ? [{ value: "", label: t(locale, "duration.systemDefault") }] : [],
|
|
22335
|
+
...values.map((milliseconds) => ({
|
|
22336
|
+
value: String(milliseconds),
|
|
22337
|
+
label: milliseconds === 0 ? t(locale, "duration.immediate") : kind === "interval" ? t(locale, "duration.every", { duration: formatInterval(milliseconds, locale) }) : formatInterval(milliseconds, locale)
|
|
22338
|
+
})),
|
|
22339
|
+
{ value: "custom", label: t(locale, "duration.custom") }
|
|
22340
|
+
];
|
|
22341
|
+
const selected = value === null ? "" : String(value);
|
|
22342
|
+
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>`;
|
|
22343
|
+
}
|
|
21763
22344
|
function formatInterval(milliseconds, locale) {
|
|
21764
22345
|
const formatter = new Intl.NumberFormat(locale === "en" ? "en-US" : "zh-CN", {
|
|
21765
22346
|
maximumFractionDigits: 1
|
|
@@ -21788,6 +22369,8 @@ var init_web = __esm({
|
|
|
21788
22369
|
init_drizzle_orm();
|
|
21789
22370
|
init_db2();
|
|
21790
22371
|
init_duration();
|
|
22372
|
+
init_opencode_catalog();
|
|
22373
|
+
init_task_working_directory();
|
|
21791
22374
|
init_database_maintenance_service();
|
|
21792
22375
|
init_task_run_service();
|
|
21793
22376
|
init_task_service();
|
|
@@ -21841,6 +22424,33 @@ var init_web = __esm({
|
|
|
21841
22424
|
const health = getGatewayHealth();
|
|
21842
22425
|
return c.json(health, health.status === "ok" ? 200 : 503);
|
|
21843
22426
|
});
|
|
22427
|
+
app.get("/api/filesystem/directories", (c) => {
|
|
22428
|
+
const requestedPath = c.req.query("path")?.trim() || homedir4();
|
|
22429
|
+
try {
|
|
22430
|
+
validateTaskWorkingDirectory(requestedPath);
|
|
22431
|
+
return c.json({
|
|
22432
|
+
path: requestedPath,
|
|
22433
|
+
parent: dirname7(requestedPath),
|
|
22434
|
+
home: homedir4(),
|
|
22435
|
+
directories: listChildDirectories(requestedPath)
|
|
22436
|
+
});
|
|
22437
|
+
} catch (error) {
|
|
22438
|
+
return c.json({
|
|
22439
|
+
error: error instanceof Error ? error.message : String(error)
|
|
22440
|
+
}, 400);
|
|
22441
|
+
}
|
|
22442
|
+
});
|
|
22443
|
+
app.get("/api/opencode/catalog", async (c) => {
|
|
22444
|
+
const cwd = c.req.query("cwd")?.trim();
|
|
22445
|
+
if (!cwd) return c.json({ error: "cwd \u4E0D\u80FD\u4E3A\u7A7A" }, 400);
|
|
22446
|
+
try {
|
|
22447
|
+
return c.json(await loadOpenCodeCatalog(cwd));
|
|
22448
|
+
} catch (error) {
|
|
22449
|
+
return c.json({
|
|
22450
|
+
error: error instanceof Error ? error.message : String(error)
|
|
22451
|
+
}, 400);
|
|
22452
|
+
}
|
|
22453
|
+
});
|
|
21844
22454
|
app.get("/", async (c) => {
|
|
21845
22455
|
const locale = resolveLocale(c);
|
|
21846
22456
|
const page = parsePositiveInteger(c.req.query("page") || "1");
|
|
@@ -21985,13 +22595,14 @@ var init_web = __esm({
|
|
|
21985
22595
|
<div class="dialog-body">
|
|
21986
22596
|
<div class="template-form-grid">
|
|
21987
22597
|
<label class="form-field"><span>${t(locale, "template.name")}</span><input id="task-name" required maxlength="200" autocomplete="off"></label>
|
|
21988
|
-
<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>
|
|
22598
|
+
<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>
|
|
21989
22599
|
<datalist id="task-cwd-options">${projects.map((project) => `<option value="${esc(project.cwd)}"></option>`).join("")}</datalist>
|
|
21990
|
-
<label class="form-field"><span>${t(locale, "template.agent")}</span><
|
|
21991
|
-
<label class="form-field"><span>${t(locale, "template.model")}</span><
|
|
22600
|
+
<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>
|
|
22601
|
+
<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>
|
|
21992
22602
|
<label class="form-field form-field-wide"><span>${t(locale, "template.prompt")}</span><textarea id="task-prompt" rows="6" required></textarea></label>
|
|
21993
22603
|
</div>
|
|
21994
22604
|
<p id="task-project-status" class="form-note"></p>
|
|
22605
|
+
<p id="task-catalog-status" class="form-note catalog-status"></p>
|
|
21995
22606
|
<details class="advanced-fields">
|
|
21996
22607
|
<summary>${t(locale, "template.advanced")}</summary>
|
|
21997
22608
|
<div class="template-form-grid">
|
|
@@ -22000,8 +22611,8 @@ var init_web = __esm({
|
|
|
22000
22611
|
<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>
|
|
22001
22612
|
<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>
|
|
22002
22613
|
<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>
|
|
22003
|
-
<label class="form-field"><span>${t(locale, "template.retryBackoff")}</span
|
|
22004
|
-
<label class="form-field"><span>${t(locale, "template.timeout")}</span
|
|
22614
|
+
<label class="form-field"><span>${t(locale, "template.retryBackoff")}</span>${durationControl(locale, "task-retry-backoff", 3e4, "retry")}<small>${t(locale, "template.retryBackoffHint")}</small></label>
|
|
22615
|
+
<label class="form-field"><span>${t(locale, "template.timeout")}</span>${durationControl(locale, "task-timeout", null, "timeout")}<small>${t(locale, "template.timeoutHint")}</small></label>
|
|
22005
22616
|
</div>
|
|
22006
22617
|
</details>
|
|
22007
22618
|
</div>
|
|
@@ -22061,15 +22672,16 @@ var init_web = __esm({
|
|
|
22061
22672
|
<div class="dialog-body">
|
|
22062
22673
|
<div class="template-form-grid">
|
|
22063
22674
|
<label class="form-field"><span>${t(locale, "template.name")}</span><input id="template-name" required maxlength="200" autocomplete="off"></label>
|
|
22064
|
-
<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>
|
|
22065
|
-
<label class="form-field"><span>${t(locale, "template.agent")}</span><
|
|
22066
|
-
<label class="form-field"><span>${t(locale, "template.model")}</span><
|
|
22675
|
+
<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>
|
|
22676
|
+
<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>
|
|
22677
|
+
<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>
|
|
22067
22678
|
<label class="form-field form-field-wide"><span>${t(locale, "template.prompt")}</span><textarea id="template-prompt" rows="6" required></textarea></label>
|
|
22068
22679
|
<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>
|
|
22069
22680
|
<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>
|
|
22070
|
-
<label id="template-interval-field" class="form-field"><span>${t(locale, "template.interval")}</span
|
|
22681
|
+
<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>
|
|
22071
22682
|
<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>
|
|
22072
22683
|
</div>
|
|
22684
|
+
<p id="template-catalog-status" class="form-note catalog-status"></p>
|
|
22073
22685
|
<details class="advanced-fields">
|
|
22074
22686
|
<summary>${t(locale, "template.advanced")}</summary>
|
|
22075
22687
|
<div class="template-form-grid">
|
|
@@ -22079,8 +22691,8 @@ var init_web = __esm({
|
|
|
22079
22691
|
<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>
|
|
22080
22692
|
<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>
|
|
22081
22693
|
<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>
|
|
22082
|
-
<label class="form-field"><span>${t(locale, "template.retryBackoff")}</span
|
|
22083
|
-
<label class="form-field"><span>${t(locale, "template.timeout")}</span
|
|
22694
|
+
<label class="form-field"><span>${t(locale, "template.retryBackoff")}</span>${durationControl(locale, "template-retry-backoff", 3e4, "retry")}<small>${t(locale, "template.retryBackoffHint")}</small></label>
|
|
22695
|
+
<label class="form-field"><span>${t(locale, "template.timeout")}</span>${durationControl(locale, "template-timeout", null, "timeout")}<small>${t(locale, "template.timeoutHint")}</small></label>
|
|
22084
22696
|
</div>
|
|
22085
22697
|
</details>
|
|
22086
22698
|
<p class="form-note">${t(locale, "template.futureOnly")}</p>
|
|
@@ -22117,14 +22729,11 @@ var init_web = __esm({
|
|
|
22117
22729
|
const total = Number(totalResult[0]?.count ?? 0);
|
|
22118
22730
|
const totalPages = Math.max(1, Math.ceil(total / limit));
|
|
22119
22731
|
if (page > totalPages) return c.redirect(`/runs?page=${totalPages}`);
|
|
22120
|
-
const logs = [];
|
|
22121
22732
|
const rows = runs.map((run) => {
|
|
22122
22733
|
const status = safeStatus(run.status);
|
|
22123
22734
|
const resumable = isValidSessionId(run.sessionId);
|
|
22124
|
-
|
|
22125
|
-
|
|
22126
|
-
}
|
|
22127
|
-
return `<tr>
|
|
22735
|
+
const log = run.log ? renderRunLog(run.id, run.taskName, run.log, locale) : "";
|
|
22736
|
+
return `<tr class="run-summary-row">
|
|
22128
22737
|
<td class="faint" data-label="${t(locale, "table.run")}">#${run.id}</td>
|
|
22129
22738
|
<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>
|
|
22130
22739
|
<td data-label="${t(locale, "table.agent")}"><span class="tag">${esc(run.taskAgent)}</span></td>
|
|
@@ -22135,7 +22744,7 @@ var init_web = __esm({
|
|
|
22135
22744
|
<td data-label="${t(locale, "table.actions")}"><div class="actions"><button type="button" class="btn" onclick="showRunDetail(${run.id})">${t(locale, "action.details")}</button>
|
|
22136
22745
|
${resumable ? `<button type="button" class="btn" onclick="copySessionCommand(${run.id})">${icon("copy")}${t(locale, "action.continueSession")}</button>` : ""}
|
|
22137
22746
|
${run.log ? `<button type="button" class="btn" aria-expanded="false" onclick="toggleLog(${run.id},this)">${t(locale, "action.logs")}</button>` : ""}</div></td>
|
|
22138
|
-
</tr
|
|
22747
|
+
</tr>${log ? `<tr id="log-${run.id}" class="run-log-row" hidden><td class="run-log-cell" colspan="8">${log}</td></tr>` : ""}`;
|
|
22139
22748
|
}).join("");
|
|
22140
22749
|
const body = `
|
|
22141
22750
|
<div class="stats-grid">
|
|
@@ -22145,7 +22754,7 @@ var init_web = __esm({
|
|
|
22145
22754
|
${statCard(runs.filter((run) => run.status === "running").length, t(locale, "stats.pageRunning"), "tone-blue", icon("activity"), "reveal-delay-2")}
|
|
22146
22755
|
</div>
|
|
22147
22756
|
<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>
|
|
22148
|
-
${
|
|
22757
|
+
${pagination(locale, "/runs", page, totalPages, total)}`;
|
|
22149
22758
|
return c.html(renderLayout({ locale, activeTab: "runs", body }));
|
|
22150
22759
|
});
|
|
22151
22760
|
app.get("/system", async (c) => {
|
|
@@ -22252,7 +22861,11 @@ var init_web = __esm({
|
|
|
22252
22861
|
const task = await TaskService.getById(id);
|
|
22253
22862
|
if (!task) return c.json({ error: "not found" }, 404);
|
|
22254
22863
|
const runs = await TaskRunService.listByTaskId(id);
|
|
22255
|
-
return c.json({
|
|
22864
|
+
return c.json({
|
|
22865
|
+
...task,
|
|
22866
|
+
_resultPresentation: task.resultLog ? presentRunLog(task.resultLog) : null,
|
|
22867
|
+
_runs: runs
|
|
22868
|
+
});
|
|
22256
22869
|
});
|
|
22257
22870
|
app.get("/api/runs/:id", async (c) => {
|
|
22258
22871
|
const id = parsePositiveInteger(c.req.param("id"));
|
|
@@ -22467,6 +23080,14 @@ import { dirname as dirname3, join as join3 } from "path";
|
|
|
22467
23080
|
import { randomUUID } from "crypto";
|
|
22468
23081
|
var DEFAULT_MAX_OUTPUT_CHARS = 64 * 1024;
|
|
22469
23082
|
var FORBIDDEN_AGENT = "supertask-runner";
|
|
23083
|
+
function runCommandContext(executable, args, cwd) {
|
|
23084
|
+
return JSON.stringify({
|
|
23085
|
+
type: "supertask_command",
|
|
23086
|
+
executable,
|
|
23087
|
+
args,
|
|
23088
|
+
cwd
|
|
23089
|
+
});
|
|
23090
|
+
}
|
|
22470
23091
|
function assertWorkerProcessIsolationSupported(platform = process.platform) {
|
|
22471
23092
|
if (platform === "win32") {
|
|
22472
23093
|
throw new Error(
|
|
@@ -22675,6 +23296,7 @@ var WorkerEngine = class {
|
|
|
22675
23296
|
runId,
|
|
22676
23297
|
launchIdentity,
|
|
22677
23298
|
child,
|
|
23299
|
+
commandContext: runCommandContext(this.opencodeBin, args, task.cwd || process.cwd()),
|
|
22678
23300
|
output: "",
|
|
22679
23301
|
sessionId: null,
|
|
22680
23302
|
timeoutTimer: null,
|
|
@@ -22839,7 +23461,7 @@ var WorkerEngine = class {
|
|
|
22839
23461
|
const termination = entry.termination;
|
|
22840
23462
|
if (termination?.kind === "shutdown") return;
|
|
22841
23463
|
if (termination?.kind === "cancel") {
|
|
22842
|
-
const output2 =
|
|
23464
|
+
const output2 = this.outputWithCommand(entry);
|
|
22843
23465
|
const log2 = `${termination.message}${output2 ? `
|
|
22844
23466
|
${output2}` : ""}`;
|
|
22845
23467
|
await TaskRunService.fail(entry.runId, log2);
|
|
@@ -22853,7 +23475,7 @@ ${output2}` : ""}`;
|
|
|
22853
23475
|
}
|
|
22854
23476
|
const currentRun = await TaskRunService.getById(entry.runId);
|
|
22855
23477
|
if (!currentRun || currentRun.status !== "running") return;
|
|
22856
|
-
const output =
|
|
23478
|
+
const output = this.outputWithCommand(entry);
|
|
22857
23479
|
const log = failure ? `${failure}${output ? `
|
|
22858
23480
|
${output}` : ""}` : output;
|
|
22859
23481
|
if (code === 0 && !failure) {
|
|
@@ -22989,6 +23611,11 @@ ${output}` : ""}` : output;
|
|
|
22989
23611
|
const batchId = normalizeTaskBatchId(task.batchId);
|
|
22990
23612
|
if (batchId) this.activeBatchIds.delete(batchId);
|
|
22991
23613
|
}
|
|
23614
|
+
outputWithCommand(entry) {
|
|
23615
|
+
const output = entry.output.trim();
|
|
23616
|
+
return `${entry.commandContext}${output ? `
|
|
23617
|
+
${output}` : ""}`;
|
|
23618
|
+
}
|
|
22992
23619
|
resolveModel(taskModel) {
|
|
22993
23620
|
if (!taskModel || taskModel === "default") return null;
|
|
22994
23621
|
return taskModel;
|