opencode-supertask 0.1.34 → 0.1.35
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 +15 -0
- package/README.md +11 -7
- package/dist/cli/index.js +448 -31
- package/dist/cli/index.js.map +1 -1
- package/dist/gateway/index.js +448 -31
- package/dist/gateway/index.js.map +1 -1
- package/dist/web/index.d.ts +12 -1
- package/dist/web/index.js +459 -63
- package/dist/web/index.js.map +1 -1
- package/dist/worker/index.d.ts +3 -1
- package/dist/worker/index.js +18 -3
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -4506,7 +4506,7 @@ var init_sql = __esm({
|
|
|
4506
4506
|
return new SQL([new StringChunk(str)]);
|
|
4507
4507
|
}
|
|
4508
4508
|
sql2.raw = raw2;
|
|
4509
|
-
function
|
|
4509
|
+
function join8(chunks, separator) {
|
|
4510
4510
|
const result = [];
|
|
4511
4511
|
for (const [i, chunk] of chunks.entries()) {
|
|
4512
4512
|
if (i > 0 && separator !== void 0) {
|
|
@@ -4516,7 +4516,7 @@ var init_sql = __esm({
|
|
|
4516
4516
|
}
|
|
4517
4517
|
return new SQL(result);
|
|
4518
4518
|
}
|
|
4519
|
-
sql2.join =
|
|
4519
|
+
sql2.join = join8;
|
|
4520
4520
|
function identifier(value) {
|
|
4521
4521
|
return new Name(value);
|
|
4522
4522
|
}
|
|
@@ -7132,7 +7132,7 @@ var init_select2 = __esm({
|
|
|
7132
7132
|
return (table, on) => {
|
|
7133
7133
|
const baseTableName = this.tableName;
|
|
7134
7134
|
const tableName = getTableLikeName(table);
|
|
7135
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
7135
|
+
if (typeof tableName === "string" && this.config.joins?.some((join8) => join8.alias === tableName)) {
|
|
7136
7136
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
7137
7137
|
}
|
|
7138
7138
|
if (!this.isPartialSelect) {
|
|
@@ -7974,7 +7974,7 @@ var init_update = __esm({
|
|
|
7974
7974
|
createJoin(joinType) {
|
|
7975
7975
|
return (table, on) => {
|
|
7976
7976
|
const tableName = getTableLikeName(table);
|
|
7977
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
7977
|
+
if (typeof tableName === "string" && this.config.joins.some((join8) => join8.alias === tableName)) {
|
|
7978
7978
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
7979
7979
|
}
|
|
7980
7980
|
if (typeof on === "function") {
|
|
@@ -22666,6 +22666,14 @@ import { fileURLToPath as fileURLToPath5 } from "url";
|
|
|
22666
22666
|
import { existsSync as existsSync7 } from "fs";
|
|
22667
22667
|
import { dirname as dirname8, join as join6 } from "path";
|
|
22668
22668
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
22669
|
+
function runCommandContext(executable, args, cwd) {
|
|
22670
|
+
return JSON.stringify({
|
|
22671
|
+
type: "supertask_command",
|
|
22672
|
+
executable,
|
|
22673
|
+
args,
|
|
22674
|
+
cwd
|
|
22675
|
+
});
|
|
22676
|
+
}
|
|
22669
22677
|
function assertWorkerProcessIsolationSupported(platform = process.platform) {
|
|
22670
22678
|
if (platform === "win32") {
|
|
22671
22679
|
throw new Error(
|
|
@@ -22887,6 +22895,7 @@ var init_worker = __esm({
|
|
|
22887
22895
|
runId,
|
|
22888
22896
|
launchIdentity,
|
|
22889
22897
|
child,
|
|
22898
|
+
commandContext: runCommandContext(this.opencodeBin, args, task.cwd || process.cwd()),
|
|
22890
22899
|
output: "",
|
|
22891
22900
|
sessionId: null,
|
|
22892
22901
|
timeoutTimer: null,
|
|
@@ -23051,7 +23060,7 @@ var init_worker = __esm({
|
|
|
23051
23060
|
const termination = entry.termination;
|
|
23052
23061
|
if (termination?.kind === "shutdown") return;
|
|
23053
23062
|
if (termination?.kind === "cancel") {
|
|
23054
|
-
const output2 =
|
|
23063
|
+
const output2 = this.outputWithCommand(entry);
|
|
23055
23064
|
const log2 = `${termination.message}${output2 ? `
|
|
23056
23065
|
${output2}` : ""}`;
|
|
23057
23066
|
await TaskRunService.fail(entry.runId, log2);
|
|
@@ -23065,7 +23074,7 @@ ${output2}` : ""}`;
|
|
|
23065
23074
|
}
|
|
23066
23075
|
const currentRun = await TaskRunService.getById(entry.runId);
|
|
23067
23076
|
if (!currentRun || currentRun.status !== "running") return;
|
|
23068
|
-
const output =
|
|
23077
|
+
const output = this.outputWithCommand(entry);
|
|
23069
23078
|
const log = failure ? `${failure}${output ? `
|
|
23070
23079
|
${output}` : ""}` : output;
|
|
23071
23080
|
if (code === 0 && !failure) {
|
|
@@ -23201,6 +23210,11 @@ ${output}` : ""}` : output;
|
|
|
23201
23210
|
const batchId = normalizeTaskBatchId(task.batchId);
|
|
23202
23211
|
if (batchId) this.activeBatchIds.delete(batchId);
|
|
23203
23212
|
}
|
|
23213
|
+
outputWithCommand(entry) {
|
|
23214
|
+
const output = entry.output.trim();
|
|
23215
|
+
return `${entry.commandContext}${output ? `
|
|
23216
|
+
${output}` : ""}`;
|
|
23217
|
+
}
|
|
23204
23218
|
resolveModel(taskModel) {
|
|
23205
23219
|
if (!taskModel || taskModel === "default") return null;
|
|
23206
23220
|
return taskModel;
|
|
@@ -25977,6 +25991,116 @@ var init_dist = __esm({
|
|
|
25977
25991
|
}
|
|
25978
25992
|
});
|
|
25979
25993
|
|
|
25994
|
+
// src/core/opencode-catalog.ts
|
|
25995
|
+
import { spawn as spawn2 } from "child_process";
|
|
25996
|
+
function cleanOutput(value) {
|
|
25997
|
+
return value.replace(ANSI_PATTERN, "").replace(/\r/g, "");
|
|
25998
|
+
}
|
|
25999
|
+
function runOpenCode(executable, args, cwd, timeoutMs) {
|
|
26000
|
+
return new Promise((resolve5, reject) => {
|
|
26001
|
+
const child = spawn2(executable, args, {
|
|
26002
|
+
cwd,
|
|
26003
|
+
env: process.env,
|
|
26004
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
26005
|
+
});
|
|
26006
|
+
let stdout = "";
|
|
26007
|
+
let stderr = "";
|
|
26008
|
+
let failure = null;
|
|
26009
|
+
let finished = false;
|
|
26010
|
+
const append = (current, chunk) => {
|
|
26011
|
+
const next = current + chunk.toString();
|
|
26012
|
+
if (Buffer.byteLength(next) > MAX_OUTPUT_BYTES && failure === null) {
|
|
26013
|
+
failure = new Error(`OpenCode \u8F93\u51FA\u8D85\u8FC7 ${MAX_OUTPUT_BYTES} bytes`);
|
|
26014
|
+
child.kill("SIGTERM");
|
|
26015
|
+
}
|
|
26016
|
+
return next.slice(-MAX_OUTPUT_BYTES);
|
|
26017
|
+
};
|
|
26018
|
+
child.stdout?.on("data", (chunk) => {
|
|
26019
|
+
stdout = append(stdout, chunk);
|
|
26020
|
+
});
|
|
26021
|
+
child.stderr?.on("data", (chunk) => {
|
|
26022
|
+
stderr = append(stderr, chunk);
|
|
26023
|
+
});
|
|
26024
|
+
child.once("error", (error) => {
|
|
26025
|
+
failure ??= error;
|
|
26026
|
+
});
|
|
26027
|
+
const timer = setTimeout(() => {
|
|
26028
|
+
failure ??= new Error(`OpenCode \u547D\u4EE4\u8D85\u8FC7 ${timeoutMs}ms \u672A\u5B8C\u6210`);
|
|
26029
|
+
child.kill("SIGTERM");
|
|
26030
|
+
}, timeoutMs);
|
|
26031
|
+
child.once("close", (code) => {
|
|
26032
|
+
if (finished) return;
|
|
26033
|
+
finished = true;
|
|
26034
|
+
clearTimeout(timer);
|
|
26035
|
+
if (failure) {
|
|
26036
|
+
reject(failure);
|
|
26037
|
+
return;
|
|
26038
|
+
}
|
|
26039
|
+
if (code !== 0) {
|
|
26040
|
+
const detail = cleanOutput(stderr).trim() || `\u9000\u51FA\u7801 ${code ?? "null"}`;
|
|
26041
|
+
reject(new Error(`OpenCode ${args.join(" ")} \u5931\u8D25\uFF1A${detail}`));
|
|
26042
|
+
return;
|
|
26043
|
+
}
|
|
26044
|
+
resolve5(cleanOutput(stdout));
|
|
26045
|
+
});
|
|
26046
|
+
});
|
|
26047
|
+
}
|
|
26048
|
+
function parseOpenCodeModels(output) {
|
|
26049
|
+
return [...new Set(cleanOutput(output).split("\n").map((line) => line.trim()).filter((line) => /^[^\s/]+\/.+/.test(line)))].sort((left, right) => left.localeCompare(right));
|
|
26050
|
+
}
|
|
26051
|
+
function parseOpenCodeAgents(output) {
|
|
26052
|
+
const agents = /* @__PURE__ */ new Map();
|
|
26053
|
+
for (const line of cleanOutput(output).split("\n")) {
|
|
26054
|
+
const match2 = /^([^\s()]+) \((primary|subagent|all)\)$/.exec(line.trim());
|
|
26055
|
+
if (!match2) continue;
|
|
26056
|
+
const name = match2[1];
|
|
26057
|
+
const mode = match2[2];
|
|
26058
|
+
if (name === "supertask-runner") continue;
|
|
26059
|
+
agents.set(name, { name, mode });
|
|
26060
|
+
}
|
|
26061
|
+
const rank = { primary: 0, all: 1, subagent: 2 };
|
|
26062
|
+
return [...agents.values()].sort((left, right) => rank[left.mode] - rank[right.mode] || left.name.localeCompare(right.name));
|
|
26063
|
+
}
|
|
26064
|
+
async function loadOpenCodeCatalog(cwd, options = {}) {
|
|
26065
|
+
validateTaskWorkingDirectory(cwd);
|
|
26066
|
+
const executable = options.executable ?? process.env.SUPERTASK_OPENCODE_BIN ?? "opencode";
|
|
26067
|
+
const timeoutMs = options.timeoutMs ?? COMMAND_TIMEOUT_MS;
|
|
26068
|
+
const cacheKey = `${executable}\0${cwd}`;
|
|
26069
|
+
const cached = catalogCache.get(cacheKey);
|
|
26070
|
+
if (options.useCache !== false && cached && cached.expiresAt > Date.now()) {
|
|
26071
|
+
return cached.result;
|
|
26072
|
+
}
|
|
26073
|
+
const result = Promise.all([
|
|
26074
|
+
runOpenCode(executable, ["models"], cwd, timeoutMs),
|
|
26075
|
+
runOpenCode(executable, ["agent", "list"], cwd, timeoutMs)
|
|
26076
|
+
]).then(([modelsOutput, agentsOutput]) => {
|
|
26077
|
+
const models = parseOpenCodeModels(modelsOutput);
|
|
26078
|
+
const agents = parseOpenCodeAgents(agentsOutput).filter((agent) => agent.mode !== "subagent");
|
|
26079
|
+
if (models.length === 0) throw new Error("OpenCode \u6CA1\u6709\u8FD4\u56DE\u53EF\u7528\u6A21\u578B");
|
|
26080
|
+
if (agents.length === 0) throw new Error("OpenCode \u6CA1\u6709\u8FD4\u56DE\u53EF\u76F4\u63A5\u8FD0\u884C\u7684\u4E3B Agent");
|
|
26081
|
+
return { cwd, models, agents };
|
|
26082
|
+
});
|
|
26083
|
+
if (options.useCache !== false) {
|
|
26084
|
+
catalogCache.set(cacheKey, { expiresAt: Date.now() + CATALOG_CACHE_MS, result });
|
|
26085
|
+
result.catch(() => {
|
|
26086
|
+
if (catalogCache.get(cacheKey)?.result === result) catalogCache.delete(cacheKey);
|
|
26087
|
+
});
|
|
26088
|
+
}
|
|
26089
|
+
return result;
|
|
26090
|
+
}
|
|
26091
|
+
var CATALOG_CACHE_MS, COMMAND_TIMEOUT_MS, MAX_OUTPUT_BYTES, ANSI_PATTERN, catalogCache;
|
|
26092
|
+
var init_opencode_catalog = __esm({
|
|
26093
|
+
"src/core/opencode-catalog.ts"() {
|
|
26094
|
+
"use strict";
|
|
26095
|
+
init_task_working_directory();
|
|
26096
|
+
CATALOG_CACHE_MS = 3e4;
|
|
26097
|
+
COMMAND_TIMEOUT_MS = 2e4;
|
|
26098
|
+
MAX_OUTPUT_BYTES = 4 * 1024 * 1024;
|
|
26099
|
+
ANSI_PATTERN = /\x1B(?:[@-_][0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\))/g;
|
|
26100
|
+
catalogCache = /* @__PURE__ */ new Map();
|
|
26101
|
+
}
|
|
26102
|
+
});
|
|
26103
|
+
|
|
25980
26104
|
// src/web/ui.ts
|
|
25981
26105
|
function t(locale, key, values = {}) {
|
|
25982
26106
|
const template = (locale === "en" ? EN : ZH)[key];
|
|
@@ -26040,7 +26164,8 @@ function icon(name, className = "icon") {
|
|
|
26040
26164
|
check: '<path d="m5 12 4 4L19 6"/>',
|
|
26041
26165
|
alert: '<path d="M12 3 2.8 19h18.4L12 3Z"/><path d="M12 9v4M12 17h.01"/>',
|
|
26042
26166
|
clock: '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',
|
|
26043
|
-
database: '<ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v6c0 1.66 3.58 3 8 3s8-1.34 8-3V5M4 11v6c0 1.66 3.58 3 8 3s8-1.34 8-3v-6"/>'
|
|
26167
|
+
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"/>',
|
|
26168
|
+
folder: '<path d="M3 7.5A2.5 2.5 0 0 1 5.5 5H10l2 2h6.5A2.5 2.5 0 0 1 21 9.5v7A2.5 2.5 0 0 1 18.5 19h-13A2.5 2.5 0 0 1 3 16.5v-9Z"/>'
|
|
26044
26169
|
};
|
|
26045
26170
|
return `<svg class="${className}" viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">${paths[name]}</svg>`;
|
|
26046
26171
|
}
|
|
@@ -26095,7 +26220,20 @@ function clientMessages(locale) {
|
|
|
26095
26220
|
"feedback.restartTimeout",
|
|
26096
26221
|
"template.createTitle",
|
|
26097
26222
|
"template.editTitle",
|
|
26098
|
-
"filter.noResults"
|
|
26223
|
+
"filter.noResults",
|
|
26224
|
+
"catalog.chooseProject",
|
|
26225
|
+
"catalog.defaultModel",
|
|
26226
|
+
"catalog.defaultProvider",
|
|
26227
|
+
"catalog.loading",
|
|
26228
|
+
"catalog.loaded",
|
|
26229
|
+
"catalog.failed",
|
|
26230
|
+
"catalog.primary",
|
|
26231
|
+
"catalog.subagent",
|
|
26232
|
+
"catalog.all",
|
|
26233
|
+
"directory.empty",
|
|
26234
|
+
"feedback.commandCopied",
|
|
26235
|
+
"action.showHidden",
|
|
26236
|
+
"action.hideHidden"
|
|
26099
26237
|
];
|
|
26100
26238
|
return Object.fromEntries(keys.map((key) => [key, t(locale, key)]));
|
|
26101
26239
|
}
|
|
@@ -26163,6 +26301,11 @@ function renderLayout(options) {
|
|
|
26163
26301
|
<footer>${t(locale, "app.footer")}</footer>
|
|
26164
26302
|
</div>
|
|
26165
26303
|
<div id="toast-region" class="toast-region" role="status" aria-live="polite"></div>
|
|
26304
|
+
<dialog id="directory-dialog" class="directory-dialog">
|
|
26305
|
+
<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>
|
|
26306
|
+
<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>
|
|
26307
|
+
<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>
|
|
26308
|
+
</dialog>
|
|
26166
26309
|
<dialog id="detail-dialog">
|
|
26167
26310
|
<div class="dialog-head"><div><h2>${t(locale, "details.title")}</h2><p>${t(locale, "details.subtitle")}</p></div><button class="icon-button" onclick="document.getElementById('detail-dialog').close()" aria-label="${t(locale, "action.close")}">${icon("close")}</button></div>
|
|
26168
26311
|
<div class="dialog-body"><pre id="detail-content" class="json-view"></pre></div>
|
|
@@ -26201,21 +26344,38 @@ function renderLayout(options) {
|
|
|
26201
26344
|
const showDetail=id=>showRecord('/api/tasks/'+id);const showRunDetail=id=>showRecord('/api/runs/'+id);const showTemplateDetail=id=>showRecord('/api/templates/'+id);
|
|
26202
26345
|
async function copyDetails(){try{await navigator.clipboard.writeText(document.getElementById('detail-content').textContent);showToast(text('details.copySuccess'))}catch{showToast(text('feedback.copyFailed'),'error')}}
|
|
26203
26346
|
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')}}
|
|
26347
|
+
async function copyRunCommand(id){try{await navigator.clipboard.writeText(document.getElementById('command-'+id).textContent);showToast(text('feedback.commandCopied'))}catch{showToast(text('feedback.copyFailed'),'error')}}
|
|
26204
26348
|
function taskField(name){return document.getElementById('task-'+name)}
|
|
26349
|
+
function templateField(name){return document.getElementById('template-'+name)}
|
|
26205
26350
|
function taskProjects(){const node=document.getElementById('task-project-data');if(!node)return {};try{return JSON.parse(node.textContent||'{}')}catch{return {}}}
|
|
26206
26351
|
function updateTaskProjectStatus(){const node=taskField('project-status');if(!node)return;const cwd=taskField('cwd').value.trim();if(!cwd){node.textContent='';return}const project=taskProjects()[cwd];node.textContent=project?text('task.projectExisting',project):text('task.projectNew')}
|
|
26207
|
-
|
|
26208
|
-
|
|
26209
|
-
|
|
26210
|
-
function
|
|
26211
|
-
function
|
|
26352
|
+
const catalogTimers={};const catalogRequests={};const catalogModels={};
|
|
26353
|
+
function catalogField(prefix,name){return document.getElementById(prefix+'-'+name)}
|
|
26354
|
+
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='';}
|
|
26355
|
+
function appendCurrentOption(select,value){if(!value||[...select.options].some(option=>option.value===value))return;select.appendChild(new Option(value,value));}
|
|
26356
|
+
function modelProvider(value){const slash=value.indexOf('/');return slash>0?value.slice(0,slash):''}
|
|
26357
|
+
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}
|
|
26358
|
+
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}}}
|
|
26359
|
+
function scheduleCatalogLoad(prefix){clearTimeout(catalogTimers[prefix]);catalogTimers[prefix]=setTimeout(()=>loadCatalog(prefix),450)}
|
|
26360
|
+
let directoryTargetId='';let directoryCurrent='';let directoryEntries=[];let directoryShowHidden=false;
|
|
26361
|
+
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)}}
|
|
26362
|
+
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}}
|
|
26363
|
+
document.getElementById('directory-hidden').onclick=()=>{directoryShowHidden=!directoryShowHidden;renderDirectoryEntries()};
|
|
26364
|
+
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('')}
|
|
26365
|
+
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)};
|
|
26366
|
+
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'}
|
|
26367
|
+
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}
|
|
26368
|
+
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)}
|
|
26369
|
+
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)}
|
|
26370
|
+
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')}}
|
|
26371
|
+
async function saveTask(event){event.preventDefault();const form=document.getElementById('task-form');if(!form.reportValidity())return;const id=taskField('id').value;const body={name:taskField('name').value,cwd:taskField('cwd').value,agent:taskField('agent').value,model:taskField('model').value,prompt:taskField('prompt').value,category:taskField('category').value,batchId:taskField('batch').value,importance:Number(taskField('importance').value),urgency:Number(taskField('urgency').value),maxRetries:Number(taskField('max-retries').value),retryBackoff:readDuration('task-retry-backoff'),timeout:readDuration('task-timeout')};const button=taskField('save');button.disabled=true;try{const data=await readJson(await fetch(id?'/api/tasks/'+id:'/api/tasks',{method:id?'PUT':'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}));showToast(text(id?'feedback.taskUpdated':'feedback.taskCreated',{id:data.task.id}));document.getElementById('task-dialog').close();setTimeout(()=>location.assign(id?location.href:'/?cwd='+encodeURIComponent(data.task.cwd||'')),450)}catch(error){showToast(error.message,'error')}finally{button.disabled=false}}
|
|
26212
26372
|
function localDateTime(milliseconds){const date=new Date(milliseconds);const local=new Date(milliseconds-date.getTimezoneOffset()*60000);return local.toISOString().slice(0,23)}
|
|
26213
|
-
function updateTemplateScheduleFields(){const type=templateField('schedule-type').value;const fields={cron:templateField('cron-field'),recurring:templateField('interval-field'),delayed:templateField('run-at-field')};for(const [name,node] of Object.entries(fields)){node.hidden=name!==type;node.querySelector('input').required=name===type}}
|
|
26373
|
+
function updateTemplateScheduleFields(){const type=templateField('schedule-type').value;const fields={cron:templateField('cron-field'),recurring:templateField('interval-field'),delayed:templateField('run-at-field')};for(const [name,node] of Object.entries(fields)){node.hidden=name!==type;for(const control of node.querySelectorAll('input,select'))control.required=false;const required=name==='recurring'?node.querySelector('[id$="-preset"]'):node.querySelector('input');if(required)required.required=name===type;if(name==='recurring'&&name===type)updateDurationControl('template-interval')}}
|
|
26214
26374
|
function setOriginalRunAt(epoch){const input=templateField('run-at');const local=epoch?localDateTime(epoch):'';input.value=local;input.dataset.originalEpoch=epoch?String(epoch):'';input.dataset.originalLocal=local}
|
|
26215
26375
|
function selectedRunAt(){const input=templateField('run-at');return resolveEditedRunAt(input.dataset.originalEpoch?Number(input.dataset.originalEpoch):null,input.dataset.originalLocal||'',input.value)}
|
|
26216
|
-
function openTemplateCreator(){const form=document.getElementById('template-form');form.reset();templateField('id').value='';templateField('dialog-title').textContent=text('template.createTitle');setOriginalRunAt(null);templateField('run-at').value=localDateTime(Date.now()+3600000);updateTemplateScheduleFields();document.getElementById('template-dialog').showModal();setTimeout(()=>templateField('name').focus(),50)}
|
|
26217
|
-
async function openTemplateEditor(id){try{const data=await readJson(await fetch('/api/templates/'+id));templateField('id').value=String(id);templateField('dialog-title').textContent=text('template.editTitle');templateField('name').value=data.name||'';templateField('cwd').value=data.cwd||'';templateField('
|
|
26218
|
-
async function saveTemplate(event){event.preventDefault();const form=document.getElementById('template-form');if(!form.reportValidity())return;const id=templateField('id').value;const type=templateField('schedule-type').value;const body={name:templateField('name').value,cwd:templateField('cwd').value,agent:templateField('agent').value,model:templateField('model').value,prompt:templateField('prompt').value,scheduleType:type,cronExpr:templateField('cron').value,interval:
|
|
26376
|
+
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)}
|
|
26377
|
+
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')}}
|
|
26378
|
+
async function saveTemplate(event){event.preventDefault();const form=document.getElementById('template-form');if(!form.reportValidity())return;const id=templateField('id').value;const type=templateField('schedule-type').value;const body={name:templateField('name').value,cwd:templateField('cwd').value,agent:templateField('agent').value,model:templateField('model').value,prompt:templateField('prompt').value,scheduleType:type,cronExpr:templateField('cron').value,interval:readDuration('template-interval'),runAt:type==='delayed'?selectedRunAt():null,category:templateField('category').value,batchId:templateField('batch').value,importance:Number(templateField('importance').value),urgency:Number(templateField('urgency').value),maxInstances:Number(templateField('max-instances').value),maxRetries:Number(templateField('max-retries').value),retryBackoff:readDuration('template-retry-backoff'),timeout:readDuration('template-timeout')};const button=templateField('save');button.disabled=true;try{await readJson(await fetch(id?'/api/templates/'+id:'/api/templates',{method:id?'PUT':'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}));showToast(text(id?'feedback.templateUpdated':'feedback.templateCreated'));document.getElementById('template-dialog').close();setTimeout(()=>location.assign(id?location.href:'/templates'),450)}catch(error){showToast(error.message,'error')}finally{button.disabled=false}}
|
|
26219
26379
|
async function enableTmpl(id){try{await readJson(await fetch('/api/templates/'+id+'/enable',{method:'POST'}));location.reload()}catch(error){showToast(error.message,'error')}}
|
|
26220
26380
|
async function disableTmpl(id){if(!await ask(text('dialog.disableTemplate'),text('dialog.disableTemplateBody')))return;try{await readJson(await fetch('/api/templates/'+id+'/disable',{method:'POST'}));location.reload()}catch(error){showToast(error.message,'error')}}
|
|
26221
26381
|
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')}}
|
|
@@ -26275,6 +26435,13 @@ var init_ui = __esm({
|
|
|
26275
26435
|
"action.updateTask": "\u4FDD\u5B58\u4FEE\u6539",
|
|
26276
26436
|
"action.createTemplate": "\u65B0\u5EFA\u5B9A\u65F6\u4EFB\u52A1",
|
|
26277
26437
|
"action.saveTemplate": "\u4FDD\u5B58\u5B9A\u65F6\u4EFB\u52A1",
|
|
26438
|
+
"action.chooseFolder": "\u9009\u62E9\u6587\u4EF6\u5939",
|
|
26439
|
+
"action.chooseThisFolder": "\u9009\u62E9\u5F53\u524D\u6587\u4EF6\u5939",
|
|
26440
|
+
"action.home": "\u4E3B\u76EE\u5F55",
|
|
26441
|
+
"action.up": "\u4E0A\u4E00\u7EA7",
|
|
26442
|
+
"action.copyCommand": "\u590D\u5236\u547D\u4EE4",
|
|
26443
|
+
"action.showHidden": "\u663E\u793A\u9690\u85CF\u6587\u4EF6\u5939",
|
|
26444
|
+
"action.hideHidden": "\u9690\u85CF\u9690\u85CF\u6587\u4EF6\u5939",
|
|
26278
26445
|
"status.pending": "\u5F85\u6267\u884C",
|
|
26279
26446
|
"status.running": "\u8FD0\u884C\u4E2D",
|
|
26280
26447
|
"status.done": "\u5DF2\u5B8C\u6210",
|
|
@@ -26341,6 +26508,15 @@ var init_ui = __esm({
|
|
|
26341
26508
|
"schedule.hours": "{count} \u5C0F\u65F6",
|
|
26342
26509
|
"schedule.days": "{count} \u5929",
|
|
26343
26510
|
"schedule.overdue": "\u5DF2\u5230\u671F",
|
|
26511
|
+
"duration.unit": "\u65F6\u95F4\u5355\u4F4D",
|
|
26512
|
+
"duration.seconds": "\u79D2",
|
|
26513
|
+
"duration.minutes": "\u5206\u949F",
|
|
26514
|
+
"duration.hours": "\u5C0F\u65F6",
|
|
26515
|
+
"duration.days": "\u5929",
|
|
26516
|
+
"duration.systemDefault": "\u4F7F\u7528 Gateway \u9ED8\u8BA4\u8D85\u65F6",
|
|
26517
|
+
"duration.immediate": "\u7ACB\u5373\u91CD\u8BD5",
|
|
26518
|
+
"duration.custom": "\u81EA\u5B9A\u4E49\u2026",
|
|
26519
|
+
"duration.every": "\u6BCF {duration}",
|
|
26344
26520
|
"system.worker": "\u4EFB\u52A1\u6267\u884C",
|
|
26345
26521
|
"system.scheduler": "\u5B9A\u65F6\u4EFB\u52A1\u670D\u52A1",
|
|
26346
26522
|
"system.watchdog": "\u8FD0\u884C\u76D1\u63A7",
|
|
@@ -26388,6 +26564,9 @@ var init_ui = __esm({
|
|
|
26388
26564
|
"template.interval": "\u6267\u884C\u95F4\u9694",
|
|
26389
26565
|
"template.runAt": "\u6267\u884C\u65F6\u95F4",
|
|
26390
26566
|
"template.durationHint": "\u652F\u6301 30s\u30015min\u30011h\u30012d",
|
|
26567
|
+
"template.intervalHint": "\u76F4\u63A5\u9009\u62E9\u5E38\u7528\u9891\u7387\uFF1B\u53EA\u6709\u7279\u6B8A\u9700\u6C42\u624D\u9700\u8981\u81EA\u5B9A\u4E49\u3002",
|
|
26568
|
+
"template.retryBackoffHint": "\u4E00\u6B21\u5931\u8D25\u540E\uFF0C\u7B49\u5F85\u591A\u4E45\u518D\u91CD\u8BD5\u3002",
|
|
26569
|
+
"template.timeoutHint": "\u7559\u7A7A\u8868\u793A\u4F7F\u7528 Gateway \u7684\u9ED8\u8BA4\u4EFB\u52A1\u8D85\u65F6\u3002",
|
|
26391
26570
|
"template.advanced": "\u66F4\u591A\u6267\u884C\u8BBE\u7F6E",
|
|
26392
26571
|
"template.category": "\u5206\u7C7B",
|
|
26393
26572
|
"template.batchId": "\u6279\u6B21 ID",
|
|
@@ -26412,6 +26591,28 @@ var init_ui = __esm({
|
|
|
26412
26591
|
"task.batchHint": "\u76F8\u540C\u975E\u7A7A\u6279\u6B21 ID \u7684\u4EFB\u52A1\u4E25\u683C\u4E32\u884C\uFF1B\u7559\u7A7A\u5219\u4E0D\u53D7\u6279\u6B21\u4E32\u884C\u9650\u5236\uFF0C\u4F46\u4ECD\u53D7\u5168\u5C40\u5E76\u53D1\u548C\u4F9D\u8D56\u7EA6\u675F\u3002",
|
|
26413
26592
|
"task.projectExisting": "\u6B64\u9879\u76EE\u73B0\u6709 {total} \u4E2A\u4EFB\u52A1\uFF1A\u8FD0\u884C {running}\uFF0C\u6392\u961F {pending}\uFF0C\u5F02\u5E38 {failed}\u3002",
|
|
26414
26593
|
"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",
|
|
26594
|
+
"catalog.chooseProject": "\u8BF7\u5148\u9009\u62E9\u9879\u76EE\u76EE\u5F55",
|
|
26595
|
+
"catalog.defaultModel": "\u8DDF\u968F Agent / OpenCode \u9ED8\u8BA4\u6A21\u578B",
|
|
26596
|
+
"catalog.defaultProvider": "\u9ED8\u8BA4\u6A21\u578B",
|
|
26597
|
+
"catalog.provider": "\u6A21\u578B\u63D0\u4F9B\u5546",
|
|
26598
|
+
"catalog.model": "\u5177\u4F53\u6A21\u578B",
|
|
26599
|
+
"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",
|
|
26600
|
+
"catalog.agentHint": "\u6765\u81EA\u5F53\u524D\u9879\u76EE\u7684 opencode agent list\u3002",
|
|
26601
|
+
"catalog.loading": "\u6B63\u5728\u8BFB\u53D6\u6B64\u9879\u76EE\u53EF\u7528\u7684 Agent \u548C\u6A21\u578B\u2026",
|
|
26602
|
+
"catalog.loaded": "\u5DF2\u4ECE\u672C\u673A OpenCode \u8BFB\u53D6 {agents} \u4E2A Agent\u3001{models} \u4E2A\u6A21\u578B\u3002",
|
|
26603
|
+
"catalog.failed": "\u65E0\u6CD5\u8BFB\u53D6\u6B64\u9879\u76EE\u7684 OpenCode \u914D\u7F6E\uFF1A{error}",
|
|
26604
|
+
"catalog.primary": "\u4E3B Agent",
|
|
26605
|
+
"catalog.subagent": "\u5B50 Agent",
|
|
26606
|
+
"catalog.all": "\u901A\u7528 Agent",
|
|
26607
|
+
"directory.title": "\u9009\u62E9\u9879\u76EE\u76EE\u5F55",
|
|
26608
|
+
"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",
|
|
26609
|
+
"directory.empty": "\u8FD9\u4E2A\u6587\u4EF6\u5939\u4E2D\u6CA1\u6709\u5B50\u6587\u4EF6\u5939",
|
|
26610
|
+
"logs.command": "\u5B9E\u9645\u6267\u884C\u547D\u4EE4",
|
|
26611
|
+
"logs.output": "Agent \u8F93\u51FA",
|
|
26612
|
+
"logs.error": "\u5931\u8D25\u539F\u56E0",
|
|
26613
|
+
"logs.tools": "\u5DE5\u5177\u8C03\u7528",
|
|
26614
|
+
"logs.raw": "\u67E5\u770B\u539F\u59CB\u6267\u884C\u65E5\u5FD7",
|
|
26615
|
+
"logs.noText": "\u8FD9\u6B21\u6267\u884C\u6CA1\u6709\u4EA7\u751F\u53EF\u5C55\u793A\u7684\u6587\u672C\u8F93\u51FA\uFF0C\u8BF7\u67E5\u770B\u539F\u59CB\u65E5\u5FD7\u3002",
|
|
26415
26616
|
"theme.label": "\u4E3B\u9898",
|
|
26416
26617
|
"theme.system": "\u8DDF\u968F\u7CFB\u7EDF",
|
|
26417
26618
|
"theme.light": "\u6D45\u8272",
|
|
@@ -26449,6 +26650,7 @@ var init_ui = __esm({
|
|
|
26449
26650
|
"feedback.templateUpdated": "\u5B9A\u65F6\u4EFB\u52A1\u5DF2\u66F4\u65B0",
|
|
26450
26651
|
"feedback.configSaved": "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58",
|
|
26451
26652
|
"feedback.sessionCommandCopied": "\u4F1A\u8BDD\u547D\u4EE4\u5DF2\u590D\u5236\uFF0C\u53EF\u76F4\u63A5\u7C98\u8D34\u5230\u7EC8\u7AEF\u8FD0\u884C",
|
|
26653
|
+
"feedback.commandCopied": "\u6267\u884C\u547D\u4EE4\u5DF2\u590D\u5236",
|
|
26452
26654
|
"feedback.restarting": "Gateway \u6B63\u5728\u91CD\u542F\uFF0C\u8BF7\u7A0D\u5019\u2026",
|
|
26453
26655
|
"feedback.restartTimeout": "Gateway \u5C1A\u672A\u6062\u590D\uFF0C\u8BF7\u7A0D\u540E\u5237\u65B0\u6216\u68C0\u67E5 PM2 \u72B6\u6001",
|
|
26454
26656
|
"feedback.databaseCleared": "\u6570\u636E\u5E93\u5DF2\u6E05\u7A7A\uFF0C\u5907\u4EFD\u4F4D\u4E8E\uFF1A{path}",
|
|
@@ -26497,6 +26699,13 @@ var init_ui = __esm({
|
|
|
26497
26699
|
"action.updateTask": "Save changes",
|
|
26498
26700
|
"action.createTemplate": "New scheduled task",
|
|
26499
26701
|
"action.saveTemplate": "Save scheduled task",
|
|
26702
|
+
"action.chooseFolder": "Choose folder",
|
|
26703
|
+
"action.chooseThisFolder": "Choose this folder",
|
|
26704
|
+
"action.home": "Home",
|
|
26705
|
+
"action.up": "Up",
|
|
26706
|
+
"action.copyCommand": "Copy command",
|
|
26707
|
+
"action.showHidden": "Show hidden folders",
|
|
26708
|
+
"action.hideHidden": "Hide hidden folders",
|
|
26500
26709
|
"status.pending": "Pending",
|
|
26501
26710
|
"status.running": "Running",
|
|
26502
26711
|
"status.done": "Done",
|
|
@@ -26563,6 +26772,15 @@ var init_ui = __esm({
|
|
|
26563
26772
|
"schedule.hours": "{count} hr",
|
|
26564
26773
|
"schedule.days": "{count} days",
|
|
26565
26774
|
"schedule.overdue": "Overdue",
|
|
26775
|
+
"duration.unit": "Time unit",
|
|
26776
|
+
"duration.seconds": "seconds",
|
|
26777
|
+
"duration.minutes": "minutes",
|
|
26778
|
+
"duration.hours": "hours",
|
|
26779
|
+
"duration.days": "days",
|
|
26780
|
+
"duration.systemDefault": "Use Gateway default timeout",
|
|
26781
|
+
"duration.immediate": "Retry immediately",
|
|
26782
|
+
"duration.custom": "Custom\u2026",
|
|
26783
|
+
"duration.every": "Every {duration}",
|
|
26566
26784
|
"system.worker": "Task execution",
|
|
26567
26785
|
"system.scheduler": "Scheduled task service",
|
|
26568
26786
|
"system.watchdog": "Runtime monitor",
|
|
@@ -26610,6 +26828,9 @@ var init_ui = __esm({
|
|
|
26610
26828
|
"template.interval": "Interval",
|
|
26611
26829
|
"template.runAt": "Run at",
|
|
26612
26830
|
"template.durationHint": "Supports 30s, 5min, 1h, 2d",
|
|
26831
|
+
"template.intervalHint": "Choose a common frequency directly; customize only when necessary.",
|
|
26832
|
+
"template.retryBackoffHint": "How long to wait after a failure before retrying.",
|
|
26833
|
+
"template.timeoutHint": "Leave blank to use the Gateway default task timeout.",
|
|
26613
26834
|
"template.advanced": "More execution settings",
|
|
26614
26835
|
"template.category": "Category",
|
|
26615
26836
|
"template.batchId": "Batch ID",
|
|
@@ -26634,6 +26855,28 @@ var init_ui = __esm({
|
|
|
26634
26855
|
"task.batchHint": "Tasks with the same non-empty batch ID run serially. Blank removes the batch constraint; global concurrency and dependencies still apply.",
|
|
26635
26856
|
"task.projectExisting": "This project has {total} tasks: {running} running, {pending} queued, and {failed} with issues.",
|
|
26636
26857
|
"task.projectNew": "This is a new project group. It appears in the project list after creation.",
|
|
26858
|
+
"catalog.chooseProject": "Choose a project directory first",
|
|
26859
|
+
"catalog.defaultModel": "Use the Agent / OpenCode default model",
|
|
26860
|
+
"catalog.defaultProvider": "Default model",
|
|
26861
|
+
"catalog.provider": "Model provider",
|
|
26862
|
+
"catalog.model": "Model",
|
|
26863
|
+
"catalog.modelHint": "Choose a provider, then a model returned by opencode models for this project. Default does not pass -m.",
|
|
26864
|
+
"catalog.agentHint": "Loaded from opencode agent list for this project.",
|
|
26865
|
+
"catalog.loading": "Loading Agents and models available to this project\u2026",
|
|
26866
|
+
"catalog.loaded": "Loaded {agents} Agents and {models} models from local OpenCode.",
|
|
26867
|
+
"catalog.failed": "Could not load this project\u2019s OpenCode configuration: {error}",
|
|
26868
|
+
"catalog.primary": "primary Agent",
|
|
26869
|
+
"catalog.subagent": "subagent",
|
|
26870
|
+
"catalog.all": "general Agent",
|
|
26871
|
+
"directory.title": "Choose project directory",
|
|
26872
|
+
"directory.subtitle": "OpenCode runs in this directory, and its project-specific Agents and models are loaded.",
|
|
26873
|
+
"directory.empty": "This folder has no subfolders",
|
|
26874
|
+
"logs.command": "Executed command",
|
|
26875
|
+
"logs.output": "Agent output",
|
|
26876
|
+
"logs.error": "Failure reason",
|
|
26877
|
+
"logs.tools": "Tool calls",
|
|
26878
|
+
"logs.raw": "View raw execution log",
|
|
26879
|
+
"logs.noText": "This run produced no displayable text. Inspect the raw log for details.",
|
|
26637
26880
|
"theme.label": "Theme",
|
|
26638
26881
|
"theme.system": "System",
|
|
26639
26882
|
"theme.light": "Light",
|
|
@@ -26671,6 +26914,7 @@ var init_ui = __esm({
|
|
|
26671
26914
|
"feedback.templateUpdated": "Scheduled task updated",
|
|
26672
26915
|
"feedback.configSaved": "Settings saved",
|
|
26673
26916
|
"feedback.sessionCommandCopied": "Session command copied. Paste it into a terminal to continue.",
|
|
26917
|
+
"feedback.commandCopied": "Execution command copied",
|
|
26674
26918
|
"feedback.restarting": "Gateway is restarting\u2026",
|
|
26675
26919
|
"feedback.restartTimeout": "Gateway has not recovered yet. Refresh later or check PM2 status.",
|
|
26676
26920
|
"feedback.databaseCleared": "Database cleared. Backup: {path}",
|
|
@@ -26881,6 +27125,18 @@ var init_ui = __esm({
|
|
|
26881
27125
|
.danger-card h2 .icon { width:17px; height:17px; }
|
|
26882
27126
|
.danger-card p { max-width:800px; margin:0 0 14px; color:var(--text-2); font-size:12px; }
|
|
26883
27127
|
.log-panel { margin:12px 0; animation:reveal .18s ease both; }
|
|
27128
|
+
.log-content { display:grid; gap:14px; padding:16px; }
|
|
27129
|
+
.log-section-head { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:7px; }
|
|
27130
|
+
.run-command,.run-output,.run-error,.run-tools { min-width:0; }
|
|
27131
|
+
.run-command strong,.run-output>strong,.run-error>strong,.run-tools>strong { display:block; margin-bottom:7px; font-size:12px; }
|
|
27132
|
+
.command-cwd { margin-bottom:6px; color:var(--text-3); font-family:"SFMono-Regular",Consolas,monospace; font-size:10px; overflow-wrap:anywhere; }
|
|
27133
|
+
.run-command pre,.run-output pre,.run-error pre { margin:0; padding:12px; overflow:auto; border:1px solid var(--border); border-radius:9px;
|
|
27134
|
+
color:var(--text-2); background:var(--surface-2); font-family:"SFMono-Regular",Consolas,monospace; font-size:11px; white-space:pre-wrap; overflow-wrap:anywhere; }
|
|
27135
|
+
.run-output pre { color:var(--text); font-family:inherit; font-size:13px; line-height:1.65; }
|
|
27136
|
+
.run-error pre { color:var(--red); border-color:color-mix(in srgb,var(--red) 28%,var(--border)); background:var(--red-soft); }
|
|
27137
|
+
.raw-log { padding-top:12px; border-top:1px solid var(--border); }
|
|
27138
|
+
.raw-log summary { color:var(--text-2); cursor:pointer; font-size:12px; font-weight:650; }
|
|
27139
|
+
.raw-log .log-box { margin-top:10px; border-radius:9px; }
|
|
26884
27140
|
.log-box { max-height:360px; overflow:auto; padding:16px; color:var(--text-2); background:#0b1018; font-family:"SFMono-Regular",Consolas,monospace;
|
|
26885
27141
|
font-size:12px; white-space:pre-wrap; overflow-wrap:anywhere; }
|
|
26886
27142
|
:root[data-theme="light"] .log-box { color:#dbe5f3; }
|
|
@@ -26899,12 +27155,33 @@ var init_ui = __esm({
|
|
|
26899
27155
|
.form-field-wide { grid-column:1 / -1; }
|
|
26900
27156
|
.form-field input,.form-field select,.form-field textarea { width:100%; min-height:39px; padding:8px 10px; border:1px solid var(--border); border-radius:9px;
|
|
26901
27157
|
outline:none; color:var(--text); background:var(--surface-2); font-weight:450; }
|
|
27158
|
+
.field-action { display:flex; align-items:stretch; gap:7px; }
|
|
27159
|
+
.field-action input { min-width:0; flex:1; }
|
|
27160
|
+
.field-action .btn { flex:0 0 auto; white-space:nowrap; }
|
|
27161
|
+
.model-selector { display:grid; grid-template-columns:minmax(120px,.75fr) minmax(0,1.25fr); gap:7px; }
|
|
27162
|
+
.duration-picker { display:grid; gap:7px; }
|
|
27163
|
+
.duration-control { display:grid; grid-template-columns:minmax(0,1fr) 112px; gap:7px; }
|
|
27164
|
+
.duration-control input,.duration-control select { min-width:0; }
|
|
26902
27165
|
.form-field textarea { resize:vertical; line-height:1.5; }
|
|
26903
27166
|
.form-field input:focus,.form-field select:focus,.form-field textarea:focus { border-color:var(--primary); box-shadow:var(--focus); background:var(--surface); }
|
|
26904
27167
|
.form-field small { color:var(--text-3); font-size:10px; font-weight:450; }
|
|
26905
27168
|
.advanced-fields { margin-top:18px; padding-top:14px; border-top:1px solid var(--border); }
|
|
26906
27169
|
.advanced-fields summary { margin-bottom:14px; color:var(--text-2); cursor:pointer; font-size:12px; font-weight:700; }
|
|
26907
27170
|
.form-note { margin:16px 0 0; color:var(--text-3); font-size:11px; }
|
|
27171
|
+
.catalog-status[data-state="loading"] { color:var(--blue); }
|
|
27172
|
+
.catalog-status[data-state="ready"] { color:var(--green); }
|
|
27173
|
+
.catalog-status[data-state="error"] { color:var(--red); }
|
|
27174
|
+
.directory-dialog { width:min(720px,calc(100% - 32px)); }
|
|
27175
|
+
.directory-toolbar { display:flex; align-items:center; gap:8px; margin-bottom:12px; }
|
|
27176
|
+
.directory-path { min-width:0; flex:1; padding:9px 11px; overflow:hidden; border:1px solid var(--border); border-radius:9px;
|
|
27177
|
+
color:var(--text-2); background:var(--surface-2); font-family:"SFMono-Regular",Consolas,monospace; font-size:11px; text-overflow:ellipsis; white-space:nowrap; }
|
|
27178
|
+
.directory-list { min-height:260px; max-height:48vh; display:grid; align-content:start; gap:6px; overflow:auto; }
|
|
27179
|
+
.directory-item { width:100%; min-height:40px; display:flex; align-items:center; gap:9px; padding:0 11px; border:1px solid transparent; border-radius:9px;
|
|
27180
|
+
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; }
|
|
27181
|
+
.directory-item:hover { color:var(--text); border-color:var(--border); background:var(--surface-2); }
|
|
27182
|
+
.directory-item:active { transform:scale(.99); }
|
|
27183
|
+
.directory-item .icon { width:17px; height:17px; color:var(--primary); flex:0 0 auto; }
|
|
27184
|
+
.directory-empty { min-height:220px; display:grid; place-items:center; color:var(--text-3); }
|
|
26908
27185
|
.json-view { min-height:160px; margin:0; padding:15px; overflow:auto; border:1px solid var(--border); border-radius:10px; color:var(--text-2);
|
|
26909
27186
|
background:var(--surface-2); font-size:12px; white-space:pre-wrap; overflow-wrap:anywhere; }
|
|
26910
27187
|
.confirm-copy { color:var(--text-2); margin:0; }
|
|
@@ -26973,6 +27250,9 @@ var init_ui = __esm({
|
|
|
26973
27250
|
.project-grid { grid-template-columns:1fr; }
|
|
26974
27251
|
.template-form-grid { grid-template-columns:1fr; }
|
|
26975
27252
|
.form-field-wide { grid-column:auto; }
|
|
27253
|
+
.field-action { align-items:stretch; flex-direction:column; }
|
|
27254
|
+
.field-action .btn { width:100%; }
|
|
27255
|
+
.model-selector { grid-template-columns:1fr; }
|
|
26976
27256
|
}
|
|
26977
27257
|
@media (max-width:520px) {
|
|
26978
27258
|
.stats-grid,.stats-grid.three { grid-template-columns:1fr 1fr; }
|
|
@@ -27002,11 +27282,21 @@ __export(web_exports, {
|
|
|
27002
27282
|
dashboardApp: () => dashboardApp,
|
|
27003
27283
|
default: () => web_default,
|
|
27004
27284
|
isSafeDashboardRestartTarget: () => isSafeDashboardRestartTarget,
|
|
27285
|
+
presentRunLog: () => presentRunLog,
|
|
27005
27286
|
resolveDashboardConfigState: () => resolveDashboardConfigState,
|
|
27006
27287
|
setDashboardRuntimeConfig: () => setDashboardRuntimeConfig
|
|
27007
27288
|
});
|
|
27008
|
-
import {
|
|
27009
|
-
|
|
27289
|
+
import {
|
|
27290
|
+
existsSync as existsSync8,
|
|
27291
|
+
mkdirSync as mkdirSync5,
|
|
27292
|
+
readFileSync as readFileSync5,
|
|
27293
|
+
readdirSync as readdirSync2,
|
|
27294
|
+
renameSync as renameSync2,
|
|
27295
|
+
statSync as statSync4,
|
|
27296
|
+
writeFileSync as writeFileSync3
|
|
27297
|
+
} from "fs";
|
|
27298
|
+
import { homedir as homedir5 } from "os";
|
|
27299
|
+
import { basename as basename3, dirname as dirname9, join as join7 } from "path";
|
|
27010
27300
|
function setDashboardRuntimeConfig(config) {
|
|
27011
27301
|
runtimeConfig = config === null ? null : structuredClone(config);
|
|
27012
27302
|
}
|
|
@@ -27047,6 +27337,23 @@ function parsePositiveInteger2(value) {
|
|
|
27047
27337
|
function parseTaskStatus2(value) {
|
|
27048
27338
|
return TASK_STATUSES2.has(value) ? value : null;
|
|
27049
27339
|
}
|
|
27340
|
+
function listChildDirectories(path) {
|
|
27341
|
+
return readdirSync2(path, { withFileTypes: true }).flatMap((entry) => {
|
|
27342
|
+
const entryPath = join7(path, entry.name);
|
|
27343
|
+
if (entry.isDirectory()) return [{ name: entry.name, path: entryPath, hidden: entry.name.startsWith(".") }];
|
|
27344
|
+
if (!entry.isSymbolicLink()) return [];
|
|
27345
|
+
try {
|
|
27346
|
+
return statSync4(entryPath).isDirectory() ? [{ name: entry.name, path: entryPath, hidden: entry.name.startsWith(".") }] : [];
|
|
27347
|
+
} catch {
|
|
27348
|
+
return [];
|
|
27349
|
+
}
|
|
27350
|
+
}).sort((left, right) => {
|
|
27351
|
+
const leftHidden = left.name.startsWith(".");
|
|
27352
|
+
const rightHidden = right.name.startsWith(".");
|
|
27353
|
+
if (leftHidden !== rightHidden) return leftHidden ? 1 : -1;
|
|
27354
|
+
return left.name.localeCompare(right.name);
|
|
27355
|
+
});
|
|
27356
|
+
}
|
|
27050
27357
|
function parseTaskPayload(value) {
|
|
27051
27358
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
27052
27359
|
throw new Error("\u8BF7\u6C42\u5185\u5BB9\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
@@ -27203,6 +27510,66 @@ function formatDuration(startAt, endAt) {
|
|
|
27203
27510
|
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
|
|
27204
27511
|
return `${Math.floor(seconds / 3600)}h ${Math.floor(seconds % 3600 / 60)}m`;
|
|
27205
27512
|
}
|
|
27513
|
+
function recordValue(value) {
|
|
27514
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
27515
|
+
}
|
|
27516
|
+
function shellQuote(value) {
|
|
27517
|
+
if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value)) return value;
|
|
27518
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
27519
|
+
}
|
|
27520
|
+
function presentRunLog(log) {
|
|
27521
|
+
let command = null;
|
|
27522
|
+
const textParts = [];
|
|
27523
|
+
const errors = [];
|
|
27524
|
+
const tools = [];
|
|
27525
|
+
for (const line of log.split("\n")) {
|
|
27526
|
+
const trimmed = line.trim();
|
|
27527
|
+
if (!trimmed) continue;
|
|
27528
|
+
let parsed = null;
|
|
27529
|
+
try {
|
|
27530
|
+
parsed = recordValue(JSON.parse(trimmed));
|
|
27531
|
+
} catch {
|
|
27532
|
+
errors.push(line);
|
|
27533
|
+
continue;
|
|
27534
|
+
}
|
|
27535
|
+
if (!parsed) continue;
|
|
27536
|
+
if (parsed.type === "supertask_command") {
|
|
27537
|
+
const executable = typeof parsed.executable === "string" ? parsed.executable : null;
|
|
27538
|
+
const cwd = typeof parsed.cwd === "string" ? parsed.cwd : null;
|
|
27539
|
+
const args = Array.isArray(parsed.args) && parsed.args.every((item) => typeof item === "string") ? parsed.args : null;
|
|
27540
|
+
if (executable && cwd && args) {
|
|
27541
|
+
command = {
|
|
27542
|
+
cwd,
|
|
27543
|
+
command: `cd ${shellQuote(cwd)} && ${[executable, ...args].map(shellQuote).join(" ")}`
|
|
27544
|
+
};
|
|
27545
|
+
}
|
|
27546
|
+
continue;
|
|
27547
|
+
}
|
|
27548
|
+
const part = recordValue(parsed.part);
|
|
27549
|
+
const eventType = typeof parsed.type === "string" ? parsed.type : "";
|
|
27550
|
+
const partType = typeof part?.type === "string" ? part.type : "";
|
|
27551
|
+
const text2 = typeof part?.text === "string" ? part.text : typeof parsed.text === "string" ? parsed.text : null;
|
|
27552
|
+
if (text2 && (eventType === "text" || partType === "text")) textParts.push(text2);
|
|
27553
|
+
const tool = typeof part?.tool === "string" ? part.tool : typeof parsed.tool === "string" ? parsed.tool : null;
|
|
27554
|
+
if (tool && (eventType === "tool_use" || partType === "tool")) tools.push(tool);
|
|
27555
|
+
const error = typeof parsed.error === "string" ? parsed.error : typeof part?.error === "string" ? part.error : null;
|
|
27556
|
+
if (error) errors.push(error);
|
|
27557
|
+
}
|
|
27558
|
+
return {
|
|
27559
|
+
command,
|
|
27560
|
+
text: textParts.join("\n").trim(),
|
|
27561
|
+
errors: [...new Set(errors)],
|
|
27562
|
+
tools
|
|
27563
|
+
};
|
|
27564
|
+
}
|
|
27565
|
+
function renderRunLog(runId, taskName, log, locale) {
|
|
27566
|
+
const presentation = presentRunLog(log);
|
|
27567
|
+
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>` : "";
|
|
27568
|
+
const errors = presentation.errors.length > 0 ? `<div class="run-error"><strong>${t(locale, "logs.error")}</strong><pre>${esc(presentation.errors.join("\n"))}</pre></div>` : "";
|
|
27569
|
+
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>` : "";
|
|
27570
|
+
const output = `<div class="run-output"><strong>${t(locale, "logs.output")}</strong><pre>${esc(presentation.text || t(locale, "logs.noText"))}</pre></div>`;
|
|
27571
|
+
return `<section id="log-${runId}" class="panel log-panel" hidden><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>`;
|
|
27572
|
+
}
|
|
27206
27573
|
function esc(value) {
|
|
27207
27574
|
if (!value) return "";
|
|
27208
27575
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -27234,6 +27601,25 @@ function emptyState(title, hint, code = "") {
|
|
|
27234
27601
|
return `<div class="empty-state"><div><div class="empty-icon">${icon("inbox")}</div>
|
|
27235
27602
|
<h3>${title}</h3><p>${hint}</p>${code ? `<code>${code}</code>` : ""}</div></div>`;
|
|
27236
27603
|
}
|
|
27604
|
+
function durationControl(locale, id, value, kind) {
|
|
27605
|
+
const units = [
|
|
27606
|
+
{ value: "s", label: t(locale, "duration.seconds") },
|
|
27607
|
+
{ value: "min", label: t(locale, "duration.minutes") },
|
|
27608
|
+
{ value: "h", label: t(locale, "duration.hours") },
|
|
27609
|
+
{ value: "d", label: t(locale, "duration.days") }
|
|
27610
|
+
];
|
|
27611
|
+
const values = kind === "interval" ? [3e5, 9e5, 18e5, 36e5, 216e5, 432e5, 864e5] : kind === "retry" ? [0, 1e4, 3e4, 6e4, 3e5] : [3e5, 9e5, 18e5, 36e5, 72e5, 144e5];
|
|
27612
|
+
const presets = [
|
|
27613
|
+
...kind === "timeout" ? [{ value: "", label: t(locale, "duration.systemDefault") }] : [],
|
|
27614
|
+
...values.map((milliseconds) => ({
|
|
27615
|
+
value: String(milliseconds),
|
|
27616
|
+
label: milliseconds === 0 ? t(locale, "duration.immediate") : kind === "interval" ? t(locale, "duration.every", { duration: formatInterval(milliseconds, locale) }) : formatInterval(milliseconds, locale)
|
|
27617
|
+
})),
|
|
27618
|
+
{ value: "custom", label: t(locale, "duration.custom") }
|
|
27619
|
+
];
|
|
27620
|
+
const selected = value === null ? "" : String(value);
|
|
27621
|
+
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>`;
|
|
27622
|
+
}
|
|
27237
27623
|
function formatInterval(milliseconds, locale) {
|
|
27238
27624
|
const formatter = new Intl.NumberFormat(locale === "en" ? "en-US" : "zh-CN", {
|
|
27239
27625
|
maximumFractionDigits: 1
|
|
@@ -27262,6 +27648,8 @@ var init_web = __esm({
|
|
|
27262
27648
|
init_drizzle_orm();
|
|
27263
27649
|
init_db2();
|
|
27264
27650
|
init_duration();
|
|
27651
|
+
init_opencode_catalog();
|
|
27652
|
+
init_task_working_directory();
|
|
27265
27653
|
init_database_maintenance_service();
|
|
27266
27654
|
init_task_run_service();
|
|
27267
27655
|
init_task_service();
|
|
@@ -27315,6 +27703,33 @@ var init_web = __esm({
|
|
|
27315
27703
|
const health = getGatewayHealth();
|
|
27316
27704
|
return c.json(health, health.status === "ok" ? 200 : 503);
|
|
27317
27705
|
});
|
|
27706
|
+
app.get("/api/filesystem/directories", (c) => {
|
|
27707
|
+
const requestedPath = c.req.query("path")?.trim() || homedir5();
|
|
27708
|
+
try {
|
|
27709
|
+
validateTaskWorkingDirectory(requestedPath);
|
|
27710
|
+
return c.json({
|
|
27711
|
+
path: requestedPath,
|
|
27712
|
+
parent: dirname9(requestedPath),
|
|
27713
|
+
home: homedir5(),
|
|
27714
|
+
directories: listChildDirectories(requestedPath)
|
|
27715
|
+
});
|
|
27716
|
+
} catch (error) {
|
|
27717
|
+
return c.json({
|
|
27718
|
+
error: error instanceof Error ? error.message : String(error)
|
|
27719
|
+
}, 400);
|
|
27720
|
+
}
|
|
27721
|
+
});
|
|
27722
|
+
app.get("/api/opencode/catalog", async (c) => {
|
|
27723
|
+
const cwd = c.req.query("cwd")?.trim();
|
|
27724
|
+
if (!cwd) return c.json({ error: "cwd \u4E0D\u80FD\u4E3A\u7A7A" }, 400);
|
|
27725
|
+
try {
|
|
27726
|
+
return c.json(await loadOpenCodeCatalog(cwd));
|
|
27727
|
+
} catch (error) {
|
|
27728
|
+
return c.json({
|
|
27729
|
+
error: error instanceof Error ? error.message : String(error)
|
|
27730
|
+
}, 400);
|
|
27731
|
+
}
|
|
27732
|
+
});
|
|
27318
27733
|
app.get("/", async (c) => {
|
|
27319
27734
|
const locale = resolveLocale(c);
|
|
27320
27735
|
const page = parsePositiveInteger2(c.req.query("page") || "1");
|
|
@@ -27459,13 +27874,14 @@ var init_web = __esm({
|
|
|
27459
27874
|
<div class="dialog-body">
|
|
27460
27875
|
<div class="template-form-grid">
|
|
27461
27876
|
<label class="form-field"><span>${t(locale, "template.name")}</span><input id="task-name" required maxlength="200" autocomplete="off"></label>
|
|
27462
|
-
<label class="form-field"><span>${t(locale, "template.cwd")}</span><input id="task-cwd" required autocomplete="off" list="task-cwd-options" placeholder="/path/to/project" oninput="updateTaskProjectStatus()"><small>${t(locale, "template.cwdHint")}</small></label>
|
|
27877
|
+
<label class="form-field"><span>${t(locale, "template.cwd")}</span><div class="field-action"><input id="task-cwd" required autocomplete="off" list="task-cwd-options" placeholder="/path/to/project" oninput="updateTaskProjectStatus();scheduleCatalogLoad('task')"><button id="task-cwd-picker" type="button" class="btn" onclick="openDirectoryPicker('task-cwd')">${icon("folder")}${t(locale, "action.chooseFolder")}</button></div><small>${t(locale, "template.cwdHint")}</small></label>
|
|
27463
27878
|
<datalist id="task-cwd-options">${projects.map((project) => `<option value="${esc(project.cwd)}"></option>`).join("")}</datalist>
|
|
27464
|
-
<label class="form-field"><span>${t(locale, "template.agent")}</span><
|
|
27465
|
-
<label class="form-field"><span>${t(locale, "template.model")}</span><
|
|
27879
|
+
<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>
|
|
27880
|
+
<label class="form-field"><span>${t(locale, "template.model")}</span><div class="model-selector"><select id="task-model-provider" aria-label="${t(locale, "catalog.provider")}" onchange="populateModelOptions('task')"><option value="">${t(locale, "catalog.defaultProvider")}</option></select><select id="task-model" required aria-label="${t(locale, "catalog.model")}" disabled><option value="default">${t(locale, "catalog.defaultModel")}</option></select></div><small>${t(locale, "catalog.modelHint")}</small></label>
|
|
27466
27881
|
<label class="form-field form-field-wide"><span>${t(locale, "template.prompt")}</span><textarea id="task-prompt" rows="6" required></textarea></label>
|
|
27467
27882
|
</div>
|
|
27468
27883
|
<p id="task-project-status" class="form-note"></p>
|
|
27884
|
+
<p id="task-catalog-status" class="form-note catalog-status"></p>
|
|
27469
27885
|
<details class="advanced-fields">
|
|
27470
27886
|
<summary>${t(locale, "template.advanced")}</summary>
|
|
27471
27887
|
<div class="template-form-grid">
|
|
@@ -27474,8 +27890,8 @@ var init_web = __esm({
|
|
|
27474
27890
|
<label class="form-field"><span>${t(locale, "template.importance")}</span><input id="task-importance" type="number" min="1" max="5" step="1" value="3" required></label>
|
|
27475
27891
|
<label class="form-field"><span>${t(locale, "template.urgency")}</span><input id="task-urgency" type="number" min="1" max="5" step="1" value="3" required></label>
|
|
27476
27892
|
<label class="form-field"><span>${t(locale, "template.maxRetries")}</span><input id="task-max-retries" type="number" min="0" max="1000" step="1" value="3" required></label>
|
|
27477
|
-
<label class="form-field"><span>${t(locale, "template.retryBackoff")}</span
|
|
27478
|
-
<label class="form-field"><span>${t(locale, "template.timeout")}</span
|
|
27893
|
+
<label class="form-field"><span>${t(locale, "template.retryBackoff")}</span>${durationControl(locale, "task-retry-backoff", 3e4, "retry")}<small>${t(locale, "template.retryBackoffHint")}</small></label>
|
|
27894
|
+
<label class="form-field"><span>${t(locale, "template.timeout")}</span>${durationControl(locale, "task-timeout", null, "timeout")}<small>${t(locale, "template.timeoutHint")}</small></label>
|
|
27479
27895
|
</div>
|
|
27480
27896
|
</details>
|
|
27481
27897
|
</div>
|
|
@@ -27535,15 +27951,16 @@ var init_web = __esm({
|
|
|
27535
27951
|
<div class="dialog-body">
|
|
27536
27952
|
<div class="template-form-grid">
|
|
27537
27953
|
<label class="form-field"><span>${t(locale, "template.name")}</span><input id="template-name" required maxlength="200" autocomplete="off"></label>
|
|
27538
|
-
<label class="form-field"><span>${t(locale, "template.cwd")}</span><input id="template-cwd" required autocomplete="off" placeholder="/path/to/project"><small>${t(locale, "template.cwdHint")}</small></label>
|
|
27539
|
-
<label class="form-field"><span>${t(locale, "template.agent")}</span><
|
|
27540
|
-
<label class="form-field"><span>${t(locale, "template.model")}</span><
|
|
27954
|
+
<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>
|
|
27955
|
+
<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>
|
|
27956
|
+
<label class="form-field"><span>${t(locale, "template.model")}</span><div class="model-selector"><select id="template-model-provider" aria-label="${t(locale, "catalog.provider")}" onchange="populateModelOptions('template')"><option value="">${t(locale, "catalog.defaultProvider")}</option></select><select id="template-model" required aria-label="${t(locale, "catalog.model")}" disabled><option value="default">${t(locale, "catalog.defaultModel")}</option></select></div><small>${t(locale, "catalog.modelHint")}</small></label>
|
|
27541
27957
|
<label class="form-field form-field-wide"><span>${t(locale, "template.prompt")}</span><textarea id="template-prompt" rows="6" required></textarea></label>
|
|
27542
27958
|
<label class="form-field"><span>${t(locale, "template.scheduleType")}</span><select id="template-schedule-type" onchange="updateTemplateScheduleFields()"><option value="recurring">${t(locale, "schedule.recurring")}</option><option value="delayed">${t(locale, "schedule.delayed")}</option><option value="cron">${t(locale, "schedule.cron")}</option></select></label>
|
|
27543
27959
|
<label id="template-cron-field" class="form-field" hidden><span>${t(locale, "template.cronExpr")}</span><input id="template-cron" autocomplete="off" placeholder="0 9 * * *"><small>${t(locale, "template.cronHint")}</small></label>
|
|
27544
|
-
<label id="template-interval-field" class="form-field"><span>${t(locale, "template.interval")}</span
|
|
27960
|
+
<label id="template-interval-field" class="form-field"><span>${t(locale, "template.interval")}</span>${durationControl(locale, "template-interval", 36e5, "interval")}<small>${t(locale, "template.intervalHint")}</small></label>
|
|
27545
27961
|
<label id="template-run-at-field" class="form-field" hidden><span>${t(locale, "template.runAt")}</span><input id="template-run-at" type="datetime-local" step="0.001"></label>
|
|
27546
27962
|
</div>
|
|
27963
|
+
<p id="template-catalog-status" class="form-note catalog-status"></p>
|
|
27547
27964
|
<details class="advanced-fields">
|
|
27548
27965
|
<summary>${t(locale, "template.advanced")}</summary>
|
|
27549
27966
|
<div class="template-form-grid">
|
|
@@ -27553,8 +27970,8 @@ var init_web = __esm({
|
|
|
27553
27970
|
<label class="form-field"><span>${t(locale, "template.urgency")}</span><input id="template-urgency" type="number" min="1" max="5" step="1" value="3" required></label>
|
|
27554
27971
|
<label class="form-field"><span>${t(locale, "template.maxInstances")}</span><input id="template-max-instances" type="number" min="1" max="1000" step="1" value="1" required><small>${t(locale, "template.maxInstancesHint")}</small></label>
|
|
27555
27972
|
<label class="form-field"><span>${t(locale, "template.maxRetries")}</span><input id="template-max-retries" type="number" min="0" max="1000" step="1" value="3" required></label>
|
|
27556
|
-
<label class="form-field"><span>${t(locale, "template.retryBackoff")}</span
|
|
27557
|
-
<label class="form-field"><span>${t(locale, "template.timeout")}</span
|
|
27973
|
+
<label class="form-field"><span>${t(locale, "template.retryBackoff")}</span>${durationControl(locale, "template-retry-backoff", 3e4, "retry")}<small>${t(locale, "template.retryBackoffHint")}</small></label>
|
|
27974
|
+
<label class="form-field"><span>${t(locale, "template.timeout")}</span>${durationControl(locale, "template-timeout", null, "timeout")}<small>${t(locale, "template.timeoutHint")}</small></label>
|
|
27558
27975
|
</div>
|
|
27559
27976
|
</details>
|
|
27560
27977
|
<p class="form-note">${t(locale, "template.futureOnly")}</p>
|
|
@@ -27596,7 +28013,7 @@ var init_web = __esm({
|
|
|
27596
28013
|
const status = safeStatus(run.status);
|
|
27597
28014
|
const resumable = isValidSessionId(run.sessionId);
|
|
27598
28015
|
if (run.log) {
|
|
27599
|
-
logs.push(
|
|
28016
|
+
logs.push(renderRunLog(run.id, run.taskName, run.log, locale));
|
|
27600
28017
|
}
|
|
27601
28018
|
return `<tr>
|
|
27602
28019
|
<td class="faint" data-label="${t(locale, "table.run")}">#${run.id}</td>
|