opencode-supertask 0.1.35 → 0.1.37
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 +23 -0
- package/README.md +7 -4
- package/dist/cli/index.js +414 -53
- package/dist/cli/index.js.map +1 -1
- package/dist/gateway/index.js +242 -30
- 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 +7 -0
- package/dist/web/index.js +238 -28
- package/dist/web/index.js.map +1 -1
- package/dist/worker/index.js +4 -2
- package/dist/worker/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -20955,6 +20955,7 @@ var init_management_lock = __esm({
|
|
|
20955
20955
|
// src/daemon/pm2.ts
|
|
20956
20956
|
var pm2_exports = {};
|
|
20957
20957
|
__export(pm2_exports, {
|
|
20958
|
+
diagnoseOpenCodeRuntime: () => diagnoseOpenCodeRuntime,
|
|
20958
20959
|
ensureGateway: () => ensureGateway,
|
|
20959
20960
|
ensurePm2LogRotation: () => ensurePm2LogRotation,
|
|
20960
20961
|
getGatewayDiagnostic: () => getGatewayDiagnostic,
|
|
@@ -21074,7 +21075,35 @@ function scopesMatch(left, right) {
|
|
|
21074
21075
|
function currentScope() {
|
|
21075
21076
|
return runtimeScope({ cwd: process.cwd(), env: process.env });
|
|
21076
21077
|
}
|
|
21077
|
-
function
|
|
21078
|
+
function diagnoseOpenCodeRuntime(runtime = {
|
|
21079
|
+
cwd: process.cwd(),
|
|
21080
|
+
env: process.env
|
|
21081
|
+
}) {
|
|
21082
|
+
const executable = runtimeScope(runtime).opencodePath;
|
|
21083
|
+
const result = spawnSync2(executable, ["--version"], {
|
|
21084
|
+
cwd: runtime.cwd,
|
|
21085
|
+
env: runtime.env,
|
|
21086
|
+
encoding: "utf8",
|
|
21087
|
+
timeout: 1e4,
|
|
21088
|
+
killSignal: "SIGKILL"
|
|
21089
|
+
});
|
|
21090
|
+
const ok = result.status === 0 && result.error === void 0;
|
|
21091
|
+
return {
|
|
21092
|
+
ok,
|
|
21093
|
+
executable,
|
|
21094
|
+
version: ok ? result.stdout.trim() || result.stderr.trim() || null : null,
|
|
21095
|
+
error: ok ? null : result.error?.message || result.stderr.trim() || result.stdout.trim() || `exit code ${result.status}`
|
|
21096
|
+
};
|
|
21097
|
+
}
|
|
21098
|
+
function assertOpenCodeRuntime(runtime) {
|
|
21099
|
+
const diagnostic = diagnoseOpenCodeRuntime(runtime);
|
|
21100
|
+
if (!diagnostic.ok) {
|
|
21101
|
+
throw new Error(
|
|
21102
|
+
`[supertask] \u76EE\u6807 Gateway \u73AF\u5883\u65E0\u6CD5\u6267\u884C OpenCode (${diagnostic.executable}): ${diagnostic.error}`
|
|
21103
|
+
);
|
|
21104
|
+
}
|
|
21105
|
+
}
|
|
21106
|
+
function getGatewayDiagnostic(options = {}) {
|
|
21078
21107
|
const producerScope = currentScope();
|
|
21079
21108
|
if (!isPm2Installed()) {
|
|
21080
21109
|
return {
|
|
@@ -21090,7 +21119,8 @@ function getGatewayDiagnostic() {
|
|
|
21090
21119
|
startupConfigured: process.platform === "darwin" || process.platform === "linux" ? false : null,
|
|
21091
21120
|
currentScope: producerScope,
|
|
21092
21121
|
gatewayScope: null,
|
|
21093
|
-
scopeMatches: false
|
|
21122
|
+
scopeMatches: false,
|
|
21123
|
+
gatewayOpenCode: null
|
|
21094
21124
|
};
|
|
21095
21125
|
}
|
|
21096
21126
|
const processes = pm2JsonList();
|
|
@@ -21118,7 +21148,8 @@ function getGatewayDiagnostic() {
|
|
|
21118
21148
|
) : process.platform === "linux" ? isLinuxStartupConfigured(gatewayEnv, runtime?.cwd, runtime ?? void 0) : null,
|
|
21119
21149
|
currentScope: producerScope,
|
|
21120
21150
|
gatewayScope: managedScope,
|
|
21121
|
-
scopeMatches: managedScope != null && scopesMatch(producerScope, managedScope)
|
|
21151
|
+
scopeMatches: managedScope != null && scopesMatch(producerScope, managedScope),
|
|
21152
|
+
gatewayOpenCode: runtime === null || !options.probeOpenCode ? null : diagnoseOpenCodeRuntime(runtime)
|
|
21122
21153
|
};
|
|
21123
21154
|
}
|
|
21124
21155
|
function writeRunningVersion(version2, env = process.env, cwd = process.cwd()) {
|
|
@@ -21921,6 +21952,7 @@ function installUnlocked() {
|
|
|
21921
21952
|
assertRuntimeCanControlPm2(oldRuntime, existing);
|
|
21922
21953
|
gatewayKillTimeoutMs(targetRuntime);
|
|
21923
21954
|
gatewayTerminationCommandTimeoutMs(targetRuntime);
|
|
21955
|
+
assertOpenCodeRuntime(targetRuntime);
|
|
21924
21956
|
if (existing) requirePm2Termination("delete", "pm2 delete existing Gateway", oldRuntime);
|
|
21925
21957
|
const version2 = getPackageVersion();
|
|
21926
21958
|
try {
|
|
@@ -22033,6 +22065,7 @@ function upgradeUnlocked(target) {
|
|
|
22033
22065
|
assertRuntimeCanControlPm2(oldRuntime, existing);
|
|
22034
22066
|
gatewayKillTimeoutMs(targetRuntime);
|
|
22035
22067
|
gatewayTerminationCommandTimeoutMs(targetRuntime);
|
|
22068
|
+
assertOpenCodeRuntime(targetRuntime);
|
|
22036
22069
|
if (existing) requirePm2Termination("delete", "pm2 delete old Gateway", oldRuntime);
|
|
22037
22070
|
try {
|
|
22038
22071
|
pm2StartGateway(targetRuntime);
|
|
@@ -22085,6 +22118,7 @@ function ensureGatewayUnlocked() {
|
|
|
22085
22118
|
const before = getRunningVersion(oldRuntime?.env ?? process.env, oldRuntime?.cwd);
|
|
22086
22119
|
gatewayKillTimeoutMs(targetRuntime);
|
|
22087
22120
|
gatewayTerminationCommandTimeoutMs(targetRuntime);
|
|
22121
|
+
assertOpenCodeRuntime(targetRuntime);
|
|
22088
22122
|
if (existing) requirePm2Termination("delete", "pm2 delete stale Gateway", oldRuntime);
|
|
22089
22123
|
try {
|
|
22090
22124
|
pm2StartGateway(targetRuntime);
|
|
@@ -22665,7 +22699,7 @@ import { spawn } from "child_process";
|
|
|
22665
22699
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
22666
22700
|
import { existsSync as existsSync7 } from "fs";
|
|
22667
22701
|
import { dirname as dirname8, join as join6 } from "path";
|
|
22668
|
-
import { randomUUID as
|
|
22702
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
22669
22703
|
function runCommandContext(executable, args, cwd) {
|
|
22670
22704
|
return JSON.stringify({
|
|
22671
22705
|
type: "supertask_command",
|
|
@@ -22806,7 +22840,7 @@ var init_worker = __esm({
|
|
|
22806
22840
|
}
|
|
22807
22841
|
let runId = null;
|
|
22808
22842
|
try {
|
|
22809
|
-
const launchIdentity = `gateway-${process.pid}:launch:${
|
|
22843
|
+
const launchIdentity = `gateway-${process.pid}:launch:${randomUUID3()}`;
|
|
22810
22844
|
const run = await TaskRunService.create({
|
|
22811
22845
|
taskId: task.id,
|
|
22812
22846
|
model: this.resolveModel(task.model),
|
|
@@ -22875,6 +22909,7 @@ var init_worker = __esm({
|
|
|
22875
22909
|
const args = ["run", "--agent", task.agent, "--format", "json"];
|
|
22876
22910
|
if (model) args.push("-m", model);
|
|
22877
22911
|
args.push(task.prompt);
|
|
22912
|
+
const cwd = task.cwd || process.cwd();
|
|
22878
22913
|
const child = spawn(process.execPath, [
|
|
22879
22914
|
this.launcherEntry(),
|
|
22880
22915
|
LAUNCH_IDENTITY_ARGUMENT,
|
|
@@ -22882,9 +22917,10 @@ var init_worker = __esm({
|
|
|
22882
22917
|
this.opencodeBin,
|
|
22883
22918
|
...args
|
|
22884
22919
|
], {
|
|
22885
|
-
cwd
|
|
22920
|
+
cwd,
|
|
22886
22921
|
env: {
|
|
22887
22922
|
...process.env,
|
|
22923
|
+
PWD: cwd,
|
|
22888
22924
|
[MANAGED_RUN_ENV]: MANAGED_RUN_ENV_VALUE
|
|
22889
22925
|
},
|
|
22890
22926
|
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
|
@@ -22895,7 +22931,7 @@ var init_worker = __esm({
|
|
|
22895
22931
|
runId,
|
|
22896
22932
|
launchIdentity,
|
|
22897
22933
|
child,
|
|
22898
|
-
commandContext: runCommandContext(this.opencodeBin, args,
|
|
22934
|
+
commandContext: runCommandContext(this.opencodeBin, args, cwd),
|
|
22899
22935
|
output: "",
|
|
22900
22936
|
sessionId: null,
|
|
22901
22937
|
timeoutTimer: null,
|
|
@@ -22931,8 +22967,8 @@ var init_worker = __esm({
|
|
|
22931
22967
|
}
|
|
22932
22968
|
});
|
|
22933
22969
|
let spawnError = null;
|
|
22934
|
-
const spawned = new Promise((
|
|
22935
|
-
child.once("spawn",
|
|
22970
|
+
const spawned = new Promise((resolve6, reject) => {
|
|
22971
|
+
child.once("spawn", resolve6);
|
|
22936
22972
|
child.once("error", (error) => {
|
|
22937
22973
|
spawnError = error;
|
|
22938
22974
|
reject(error);
|
|
@@ -22980,10 +23016,10 @@ var init_worker = __esm({
|
|
|
22980
23016
|
return;
|
|
22981
23017
|
}
|
|
22982
23018
|
try {
|
|
22983
|
-
await new Promise((
|
|
23019
|
+
await new Promise((resolve6, reject) => {
|
|
22984
23020
|
child.stdin.end("START\n", (error) => {
|
|
22985
23021
|
if (error) reject(error);
|
|
22986
|
-
else
|
|
23022
|
+
else resolve6();
|
|
22987
23023
|
});
|
|
22988
23024
|
});
|
|
22989
23025
|
} catch (error) {
|
|
@@ -25997,7 +26033,7 @@ function cleanOutput(value) {
|
|
|
25997
26033
|
return value.replace(ANSI_PATTERN, "").replace(/\r/g, "");
|
|
25998
26034
|
}
|
|
25999
26035
|
function runOpenCode(executable, args, cwd, timeoutMs) {
|
|
26000
|
-
return new Promise((
|
|
26036
|
+
return new Promise((resolve6, reject) => {
|
|
26001
26037
|
const child = spawn2(executable, args, {
|
|
26002
26038
|
cwd,
|
|
26003
26039
|
env: process.env,
|
|
@@ -26041,7 +26077,7 @@ function runOpenCode(executable, args, cwd, timeoutMs) {
|
|
|
26041
26077
|
reject(new Error(`OpenCode ${args.join(" ")} \u5931\u8D25\uFF1A${detail}`));
|
|
26042
26078
|
return;
|
|
26043
26079
|
}
|
|
26044
|
-
|
|
26080
|
+
resolve6(cleanOutput(stdout));
|
|
26045
26081
|
});
|
|
26046
26082
|
});
|
|
26047
26083
|
}
|
|
@@ -26178,7 +26214,70 @@ function clientMessages(locale) {
|
|
|
26178
26214
|
"action.refresh",
|
|
26179
26215
|
"action.logs",
|
|
26180
26216
|
"action.hideLogs",
|
|
26217
|
+
"details.title",
|
|
26218
|
+
"details.subtitle",
|
|
26219
|
+
"details.taskTitle",
|
|
26220
|
+
"details.runTitle",
|
|
26221
|
+
"details.templateTitle",
|
|
26222
|
+
"details.raw",
|
|
26181
26223
|
"details.copySuccess",
|
|
26224
|
+
"details.id",
|
|
26225
|
+
"details.project",
|
|
26226
|
+
"details.prompt",
|
|
26227
|
+
"details.result",
|
|
26228
|
+
"details.category",
|
|
26229
|
+
"details.batch",
|
|
26230
|
+
"details.dependency",
|
|
26231
|
+
"details.importance",
|
|
26232
|
+
"details.urgency",
|
|
26233
|
+
"details.retryCount",
|
|
26234
|
+
"details.retryBackoff",
|
|
26235
|
+
"details.timeout",
|
|
26236
|
+
"details.createdAt",
|
|
26237
|
+
"details.updatedAt",
|
|
26238
|
+
"details.startedAt",
|
|
26239
|
+
"details.finishedAt",
|
|
26240
|
+
"details.scheduledAt",
|
|
26241
|
+
"details.enabled",
|
|
26242
|
+
"details.scheduleRule",
|
|
26243
|
+
"details.maxInstances",
|
|
26244
|
+
"details.maxRetries",
|
|
26245
|
+
"details.lastRun",
|
|
26246
|
+
"details.nextRun",
|
|
26247
|
+
"details.taskId",
|
|
26248
|
+
"details.session",
|
|
26249
|
+
"details.heartbeat",
|
|
26250
|
+
"details.process",
|
|
26251
|
+
"details.history",
|
|
26252
|
+
"details.noHistory",
|
|
26253
|
+
"details.none",
|
|
26254
|
+
"details.default",
|
|
26255
|
+
"details.enabledYes",
|
|
26256
|
+
"details.enabledNo",
|
|
26257
|
+
"table.name",
|
|
26258
|
+
"table.agent",
|
|
26259
|
+
"table.model",
|
|
26260
|
+
"table.status",
|
|
26261
|
+
"table.duration",
|
|
26262
|
+
"template.scheduleType",
|
|
26263
|
+
"status.pending",
|
|
26264
|
+
"status.running",
|
|
26265
|
+
"status.done",
|
|
26266
|
+
"status.failed",
|
|
26267
|
+
"status.dead_letter",
|
|
26268
|
+
"status.cancelled",
|
|
26269
|
+
"status.unknown",
|
|
26270
|
+
"runStatus.running",
|
|
26271
|
+
"runStatus.done",
|
|
26272
|
+
"runStatus.failed",
|
|
26273
|
+
"schedule.cron",
|
|
26274
|
+
"schedule.recurring",
|
|
26275
|
+
"schedule.delayed",
|
|
26276
|
+
"schedule.unknown",
|
|
26277
|
+
"duration.seconds",
|
|
26278
|
+
"duration.minutes",
|
|
26279
|
+
"duration.hours",
|
|
26280
|
+
"duration.days",
|
|
26182
26281
|
"feedback.copyFailed",
|
|
26183
26282
|
"dialog.cancelTask",
|
|
26184
26283
|
"dialog.cancelTaskBody",
|
|
@@ -26307,8 +26406,8 @@ function renderLayout(options) {
|
|
|
26307
26406
|
<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
26407
|
</dialog>
|
|
26309
26408
|
<dialog id="detail-dialog">
|
|
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>
|
|
26311
|
-
<div class="dialog-body"><
|
|
26409
|
+
<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>
|
|
26410
|
+
<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>
|
|
26312
26411
|
<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>
|
|
26313
26412
|
</dialog>
|
|
26314
26413
|
<dialog id="confirm-dialog">
|
|
@@ -26340,9 +26439,39 @@ function renderLayout(options) {
|
|
|
26340
26439
|
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')}}
|
|
26341
26440
|
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')}}
|
|
26342
26441
|
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')}}
|
|
26343
|
-
|
|
26344
|
-
const
|
|
26345
|
-
|
|
26442
|
+
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)}
|
|
26443
|
+
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'}
|
|
26444
|
+
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')}
|
|
26445
|
+
function detailScheduleType(value){const key='schedule.'+String(value||'unknown');return Object.prototype.hasOwnProperty.call(UI,key)?text(key):text('schedule.unknown')}
|
|
26446
|
+
function detailModel(value){return !value||value==='default'?text('details.default'):String(value)}
|
|
26447
|
+
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)}
|
|
26448
|
+
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')}
|
|
26449
|
+
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}
|
|
26450
|
+
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}
|
|
26451
|
+
function detailFields(type,data){if(type==='task')return [
|
|
26452
|
+
[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}],
|
|
26453
|
+
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
26454
|
+
[text('details.category'),data.category],[text('details.batch'),data.batchId],[text('details.dependency'),data.dependsOn?'#'+data.dependsOn:text('details.none')],
|
|
26455
|
+
[text('details.importance'),data.importance],[text('details.urgency'),data.urgency],[text('details.retryCount'),String(data.retryCount??0)+' / '+String(data.maxRetries??0)],
|
|
26456
|
+
[text('details.retryBackoff'),detailDuration(data.retryBackoffMs)],[text('details.timeout'),detailDuration(data.timeoutMs)],[text('details.scheduledAt'),detailDate(data.scheduledAt)],
|
|
26457
|
+
[text('details.createdAt'),detailDate(data.createdAt)],[text('details.startedAt'),detailDate(data.startedAt)],[text('details.finishedAt'),detailDate(data.finishedAt)],
|
|
26458
|
+
[text('details.result'),detailTaskResult(data),{wide:true,long:true}]
|
|
26459
|
+
];if(type==='run'){const started=data.startedAt?new Date(data.startedAt).getTime():null;const finished=data.finishedAt?new Date(data.finishedAt).getTime():null;return [
|
|
26460
|
+
[text('details.id'),'Run #'+data.id],[text('details.taskId'),'#'+data.taskId],[text('table.status'),detailStatus('run',data.status)],[text('table.model'),detailModel(data.model)],
|
|
26461
|
+
[text('details.session'),detailSession(data.sessionId)],[text('details.startedAt'),detailDate(data.startedAt)],[text('details.finishedAt'),detailDate(data.finishedAt)],
|
|
26462
|
+
[text('table.duration'),started!==null?detailDuration((finished??Date.now())-started):text('details.none')],[text('details.heartbeat'),detailDate(data.heartbeatAt)],
|
|
26463
|
+
[text('details.process'),'Worker PID '+String(data.workerPid??'\u2014')+' \xB7 OpenCode PID '+String(data.childPid??'\u2014'),{wide:true,mono:true}]
|
|
26464
|
+
];}const scheduleRule=data.scheduleType==='cron'?data.cronExpr:data.scheduleType==='recurring'?detailDuration(data.intervalMs):detailDate(data.runAt);return [
|
|
26465
|
+
[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}],
|
|
26466
|
+
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
26467
|
+
[text('template.scheduleType'),detailScheduleType(data.scheduleType)],[text('details.scheduleRule'),scheduleRule],[text('details.category'),data.category],[text('details.batch'),data.batchId],
|
|
26468
|
+
[text('details.importance'),data.importance],[text('details.urgency'),data.urgency],[text('details.maxInstances'),data.maxInstances],[text('details.maxRetries'),data.maxRetries??0],
|
|
26469
|
+
[text('details.retryBackoff'),detailDuration(data.retryBackoffMs)],[text('details.timeout'),detailDuration(data.timeoutMs)],[text('details.lastRun'),detailDate(data.lastRunAt)],[text('details.nextRun'),detailDate(data.nextRunAt)],
|
|
26470
|
+
[text('details.createdAt'),detailDate(data.createdAt)],[text('details.updatedAt'),detailDate(data.updatedAt)]
|
|
26471
|
+
]}
|
|
26472
|
+
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')}}
|
|
26473
|
+
const showDetail=id=>showRecord('/api/tasks/'+id,'task');const showRunDetail=id=>showRecord('/api/runs/'+id,'run');const showTemplateDetail=id=>showRecord('/api/templates/'+id,'template');
|
|
26474
|
+
async function copyDetails(){try{await navigator.clipboard.writeText(document.getElementById('detail-raw').textContent);showToast(text('details.copySuccess'))}catch{showToast(text('feedback.copyFailed'),'error')}}
|
|
26346
26475
|
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
26476
|
async function copyRunCommand(id){try{await navigator.clipboard.writeText(document.getElementById('command-'+id).textContent);showToast(text('feedback.commandCopied'))}catch{showToast(text('feedback.copyFailed'),'error')}}
|
|
26348
26477
|
function taskField(name){return document.getElementById('task-'+name)}
|
|
@@ -26380,7 +26509,7 @@ function renderLayout(options) {
|
|
|
26380
26509
|
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')}}
|
|
26381
26510
|
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')}}
|
|
26382
26511
|
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')}}
|
|
26383
|
-
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');}
|
|
26512
|
+
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'}));}
|
|
26384
26513
|
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;}
|
|
26385
26514
|
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')}}
|
|
26386
26515
|
async function confirmGatewayRestart(runningCount=0){const body=runningCount>0?text('dialog.restartGatewayRunningBody',{count:runningCount}):text('dialog.restartGatewayBody');return await ask(text('dialog.restartGateway'),body)}
|
|
@@ -26426,7 +26555,7 @@ var init_ui = __esm({
|
|
|
26426
26555
|
"action.hideLogs": "\u6536\u8D77\u65E5\u5FD7",
|
|
26427
26556
|
"action.save": "\u4FDD\u5B58\u8BBE\u7F6E",
|
|
26428
26557
|
"action.saveAndRestart": "\u4FDD\u5B58\u5E76\u91CD\u542F",
|
|
26429
|
-
"action.copy": "\u590D\u5236
|
|
26558
|
+
"action.copy": "\u590D\u5236\u539F\u59CB\u6570\u636E",
|
|
26430
26559
|
"action.close": "\u5173\u95ED",
|
|
26431
26560
|
"action.confirm": "\u786E\u8BA4",
|
|
26432
26561
|
"action.clearDatabase": "\u6E05\u7A7A\u6570\u636E\u5E93",
|
|
@@ -26618,9 +26747,46 @@ var init_ui = __esm({
|
|
|
26618
26747
|
"theme.light": "\u6D45\u8272",
|
|
26619
26748
|
"theme.dark": "\u6DF1\u8272",
|
|
26620
26749
|
"language.label": "\u8BED\u8A00",
|
|
26621
|
-
"details.title": "\
|
|
26622
|
-
"details.subtitle": "\u539F\u59CB\
|
|
26623
|
-
"details.
|
|
26750
|
+
"details.title": "\u8BE6\u60C5",
|
|
26751
|
+
"details.subtitle": "\u91CD\u70B9\u4FE1\u606F\u5DF2\u6574\u7406\uFF1B\u539F\u59CB\u6570\u636E\u4EC5\u7528\u4E8E\u6392\u969C\u3002",
|
|
26752
|
+
"details.taskTitle": "\u4EFB\u52A1\u8BE6\u60C5",
|
|
26753
|
+
"details.runTitle": "\u6267\u884C\u8BE6\u60C5",
|
|
26754
|
+
"details.templateTitle": "\u5B9A\u65F6\u4EFB\u52A1\u8BE6\u60C5",
|
|
26755
|
+
"details.raw": "\u67E5\u770B\u539F\u59CB\u6570\u636E\uFF08JSON\uFF09",
|
|
26756
|
+
"details.copySuccess": "\u539F\u59CB\u6570\u636E\u5DF2\u590D\u5236",
|
|
26757
|
+
"details.id": "\u7F16\u53F7",
|
|
26758
|
+
"details.project": "\u9879\u76EE\u76EE\u5F55",
|
|
26759
|
+
"details.prompt": "\u63D0\u793A\u8BCD",
|
|
26760
|
+
"details.result": "\u6267\u884C\u7ED3\u679C / \u5931\u8D25\u539F\u56E0",
|
|
26761
|
+
"details.category": "\u5206\u7C7B",
|
|
26762
|
+
"details.batch": "\u6279\u6B21",
|
|
26763
|
+
"details.dependency": "\u4F9D\u8D56\u4EFB\u52A1",
|
|
26764
|
+
"details.importance": "\u91CD\u8981\u7A0B\u5EA6",
|
|
26765
|
+
"details.urgency": "\u7D27\u6025\u7A0B\u5EA6",
|
|
26766
|
+
"details.retryCount": "\u5DF2\u91CD\u8BD5 / \u6700\u591A\u91CD\u8BD5",
|
|
26767
|
+
"details.retryBackoff": "\u91CD\u8BD5\u7B49\u5F85",
|
|
26768
|
+
"details.timeout": "\u6267\u884C\u8D85\u65F6",
|
|
26769
|
+
"details.createdAt": "\u521B\u5EFA\u65F6\u95F4",
|
|
26770
|
+
"details.updatedAt": "\u66F4\u65B0\u65F6\u95F4",
|
|
26771
|
+
"details.startedAt": "\u5F00\u59CB\u65F6\u95F4",
|
|
26772
|
+
"details.finishedAt": "\u7ED3\u675F\u65F6\u95F4",
|
|
26773
|
+
"details.scheduledAt": "\u8BA1\u5212\u65F6\u95F4",
|
|
26774
|
+
"details.enabled": "\u81EA\u52A8\u8FD0\u884C",
|
|
26775
|
+
"details.scheduleRule": "\u8FD0\u884C\u89C4\u5219",
|
|
26776
|
+
"details.maxInstances": "\u81EA\u52A8\u8C03\u5EA6\u4E0A\u9650",
|
|
26777
|
+
"details.maxRetries": "\u5931\u8D25\u91CD\u8BD5\u6B21\u6570",
|
|
26778
|
+
"details.lastRun": "\u4E0A\u6B21\u8FD0\u884C",
|
|
26779
|
+
"details.nextRun": "\u4E0B\u6B21\u8FD0\u884C",
|
|
26780
|
+
"details.taskId": "\u6240\u5C5E\u4EFB\u52A1",
|
|
26781
|
+
"details.session": "OpenCode \u4F1A\u8BDD",
|
|
26782
|
+
"details.heartbeat": "\u6700\u8FD1\u5FC3\u8DF3",
|
|
26783
|
+
"details.process": "\u8FDB\u7A0B",
|
|
26784
|
+
"details.history": "\u6267\u884C\u5386\u53F2",
|
|
26785
|
+
"details.noHistory": "\u8FD8\u6CA1\u6709\u6267\u884C\u8BB0\u5F55",
|
|
26786
|
+
"details.none": "\u65E0",
|
|
26787
|
+
"details.default": "\u8DDF\u968F\u7CFB\u7EDF\u9ED8\u8BA4",
|
|
26788
|
+
"details.enabledYes": "\u5DF2\u542F\u7528",
|
|
26789
|
+
"details.enabledNo": "\u5DF2\u505C\u7528",
|
|
26624
26790
|
"dialog.cancelTask": "\u53D6\u6D88\u4EFB\u52A1 #{id}\uFF1F",
|
|
26625
26791
|
"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",
|
|
26626
26792
|
"dialog.retryTask": "\u91CD\u8BD5\u4EFB\u52A1 #{id}\uFF1F",
|
|
@@ -26690,7 +26856,7 @@ var init_ui = __esm({
|
|
|
26690
26856
|
"action.hideLogs": "Hide log",
|
|
26691
26857
|
"action.save": "Save settings",
|
|
26692
26858
|
"action.saveAndRestart": "Save and restart",
|
|
26693
|
-
"action.copy": "Copy
|
|
26859
|
+
"action.copy": "Copy raw data",
|
|
26694
26860
|
"action.close": "Close",
|
|
26695
26861
|
"action.confirm": "Confirm",
|
|
26696
26862
|
"action.clearDatabase": "Clear database",
|
|
@@ -26882,9 +27048,46 @@ var init_ui = __esm({
|
|
|
26882
27048
|
"theme.light": "Light",
|
|
26883
27049
|
"theme.dark": "Dark",
|
|
26884
27050
|
"language.label": "Language",
|
|
26885
|
-
"details.title": "
|
|
26886
|
-
"details.subtitle": "
|
|
26887
|
-
"details.
|
|
27051
|
+
"details.title": "Details",
|
|
27052
|
+
"details.subtitle": "Key information is organized below; raw data is only for troubleshooting.",
|
|
27053
|
+
"details.taskTitle": "Task details",
|
|
27054
|
+
"details.runTitle": "Run details",
|
|
27055
|
+
"details.templateTitle": "Scheduled task details",
|
|
27056
|
+
"details.raw": "View raw data (JSON)",
|
|
27057
|
+
"details.copySuccess": "Raw data copied",
|
|
27058
|
+
"details.id": "ID",
|
|
27059
|
+
"details.project": "Project directory",
|
|
27060
|
+
"details.prompt": "Prompt",
|
|
27061
|
+
"details.result": "Result / failure reason",
|
|
27062
|
+
"details.category": "Category",
|
|
27063
|
+
"details.batch": "Batch",
|
|
27064
|
+
"details.dependency": "Dependency",
|
|
27065
|
+
"details.importance": "Importance",
|
|
27066
|
+
"details.urgency": "Urgency",
|
|
27067
|
+
"details.retryCount": "Retries used / allowed",
|
|
27068
|
+
"details.retryBackoff": "Retry delay",
|
|
27069
|
+
"details.timeout": "Run timeout",
|
|
27070
|
+
"details.createdAt": "Created",
|
|
27071
|
+
"details.updatedAt": "Updated",
|
|
27072
|
+
"details.startedAt": "Started",
|
|
27073
|
+
"details.finishedAt": "Finished",
|
|
27074
|
+
"details.scheduledAt": "Scheduled for",
|
|
27075
|
+
"details.enabled": "Automatic runs",
|
|
27076
|
+
"details.scheduleRule": "Schedule rule",
|
|
27077
|
+
"details.maxInstances": "Automatic scheduling limit",
|
|
27078
|
+
"details.maxRetries": "Failure retries",
|
|
27079
|
+
"details.lastRun": "Last run",
|
|
27080
|
+
"details.nextRun": "Next run",
|
|
27081
|
+
"details.taskId": "Task",
|
|
27082
|
+
"details.session": "OpenCode session",
|
|
27083
|
+
"details.heartbeat": "Latest heartbeat",
|
|
27084
|
+
"details.process": "Processes",
|
|
27085
|
+
"details.history": "Run history",
|
|
27086
|
+
"details.noHistory": "No runs yet",
|
|
27087
|
+
"details.none": "None",
|
|
27088
|
+
"details.default": "Use system default",
|
|
27089
|
+
"details.enabledYes": "Enabled",
|
|
27090
|
+
"details.enabledNo": "Disabled",
|
|
26888
27091
|
"dialog.cancelTask": "Cancel task #{id}?",
|
|
26889
27092
|
"dialog.cancelTaskBody": "A running task will terminate its process tree on the next worker poll.",
|
|
26890
27093
|
"dialog.retryTask": "Retry task #{id}?",
|
|
@@ -27125,6 +27328,8 @@ var init_ui = __esm({
|
|
|
27125
27328
|
.danger-card h2 .icon { width:17px; height:17px; }
|
|
27126
27329
|
.danger-card p { max-width:800px; margin:0 0 14px; color:var(--text-2); font-size:12px; }
|
|
27127
27330
|
.log-panel { margin:12px 0; animation:reveal .18s ease both; }
|
|
27331
|
+
.run-log-row td { padding:0 16px 16px; background:color-mix(in srgb,var(--surface-2) 64%,var(--surface)); }
|
|
27332
|
+
.run-log-row .log-panel { margin:0; box-shadow:none; }
|
|
27128
27333
|
.log-content { display:grid; gap:14px; padding:16px; }
|
|
27129
27334
|
.log-section-head { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:7px; }
|
|
27130
27335
|
.run-command,.run-output,.run-error,.run-tools { min-width:0; }
|
|
@@ -27182,8 +27387,21 @@ var init_ui = __esm({
|
|
|
27182
27387
|
.directory-item:active { transform:scale(.99); }
|
|
27183
27388
|
.directory-item .icon { width:17px; height:17px; color:var(--primary); flex:0 0 auto; }
|
|
27184
27389
|
.directory-empty { min-height:220px; display:grid; place-items:center; color:var(--text-3); }
|
|
27185
|
-
.
|
|
27186
|
-
|
|
27390
|
+
.detail-view { display:grid; gap:16px; }
|
|
27391
|
+
.detail-grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; }
|
|
27392
|
+
.detail-item { min-width:0; padding:12px 13px; border:1px solid var(--border); border-radius:10px; background:var(--surface-2); }
|
|
27393
|
+
.detail-item.wide { grid-column:1 / -1; }
|
|
27394
|
+
.detail-label { margin-bottom:5px; color:var(--text-3); font-size:10px; font-weight:750; letter-spacing:.045em; text-transform:uppercase; }
|
|
27395
|
+
.detail-value { color:var(--text); font-size:13px; line-height:1.55; overflow-wrap:anywhere; }
|
|
27396
|
+
.detail-value.mono { font-family:"SFMono-Regular",Consolas,monospace; font-size:11px; }
|
|
27397
|
+
.detail-value.long { max-height:240px; margin:0; overflow:auto; white-space:pre-wrap; }
|
|
27398
|
+
.detail-history h3 { margin:0 0 8px; font-size:13px; }
|
|
27399
|
+
.detail-history-list { display:grid; gap:7px; }
|
|
27400
|
+
.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; }
|
|
27401
|
+
.detail-raw { padding-top:12px; border-top:1px solid var(--border); }
|
|
27402
|
+
.detail-raw summary { color:var(--text-2); cursor:pointer; font-size:12px; font-weight:650; }
|
|
27403
|
+
.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);
|
|
27404
|
+
background:var(--surface-2); font-family:"SFMono-Regular",Consolas,monospace; font-size:11px; white-space:pre-wrap; overflow-wrap:anywhere; }
|
|
27187
27405
|
.confirm-copy { color:var(--text-2); margin:0; }
|
|
27188
27406
|
.confirm-copy strong { display:block; margin-bottom:5px; color:var(--text); font-size:15px; }
|
|
27189
27407
|
.danger-input { width:100%; height:40px; margin-top:14px; padding:0 12px; border:1px solid var(--border); border-radius:9px; outline:none;
|
|
@@ -27247,8 +27465,13 @@ var init_ui = __esm({
|
|
|
27247
27465
|
.responsive-table td[data-primary]::before { display:none; }
|
|
27248
27466
|
.responsive-table .task-prompt { max-width:100%; }
|
|
27249
27467
|
.responsive-table .actions { justify-content:flex-start; }
|
|
27468
|
+
.responsive-table .run-log-row { padding:0; overflow:hidden; }
|
|
27469
|
+
.responsive-table .run-log-cell { display:block; padding:0; }
|
|
27470
|
+
.responsive-table .run-log-cell::before { display:none; }
|
|
27250
27471
|
.project-grid { grid-template-columns:1fr; }
|
|
27251
27472
|
.template-form-grid { grid-template-columns:1fr; }
|
|
27473
|
+
.detail-grid { grid-template-columns:1fr; }
|
|
27474
|
+
.detail-item.wide { grid-column:auto; }
|
|
27252
27475
|
.form-field-wide { grid-column:auto; }
|
|
27253
27476
|
.field-action { align-items:stretch; flex-direction:column; }
|
|
27254
27477
|
.field-action .btn { width:100%; }
|
|
@@ -27568,7 +27791,7 @@ function renderRunLog(runId, taskName, log, locale) {
|
|
|
27568
27791
|
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
27792
|
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
27793
|
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
|
|
27794
|
+
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>`;
|
|
27572
27795
|
}
|
|
27573
27796
|
function esc(value) {
|
|
27574
27797
|
if (!value) return "";
|
|
@@ -28008,14 +28231,11 @@ var init_web = __esm({
|
|
|
28008
28231
|
const total = Number(totalResult[0]?.count ?? 0);
|
|
28009
28232
|
const totalPages = Math.max(1, Math.ceil(total / limit));
|
|
28010
28233
|
if (page > totalPages) return c.redirect(`/runs?page=${totalPages}`);
|
|
28011
|
-
const logs = [];
|
|
28012
28234
|
const rows = runs.map((run) => {
|
|
28013
28235
|
const status = safeStatus(run.status);
|
|
28014
28236
|
const resumable = isValidSessionId(run.sessionId);
|
|
28015
|
-
|
|
28016
|
-
|
|
28017
|
-
}
|
|
28018
|
-
return `<tr>
|
|
28237
|
+
const log = run.log ? renderRunLog(run.id, run.taskName, run.log, locale) : "";
|
|
28238
|
+
return `<tr class="run-summary-row">
|
|
28019
28239
|
<td class="faint" data-label="${t(locale, "table.run")}">#${run.id}</td>
|
|
28020
28240
|
<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>
|
|
28021
28241
|
<td data-label="${t(locale, "table.agent")}"><span class="tag">${esc(run.taskAgent)}</span></td>
|
|
@@ -28026,7 +28246,7 @@ var init_web = __esm({
|
|
|
28026
28246
|
<td data-label="${t(locale, "table.actions")}"><div class="actions"><button type="button" class="btn" onclick="showRunDetail(${run.id})">${t(locale, "action.details")}</button>
|
|
28027
28247
|
${resumable ? `<button type="button" class="btn" onclick="copySessionCommand(${run.id})">${icon("copy")}${t(locale, "action.continueSession")}</button>` : ""}
|
|
28028
28248
|
${run.log ? `<button type="button" class="btn" aria-expanded="false" onclick="toggleLog(${run.id},this)">${t(locale, "action.logs")}</button>` : ""}</div></td>
|
|
28029
|
-
</tr
|
|
28249
|
+
</tr>${log ? `<tr id="log-${run.id}" class="run-log-row" hidden><td class="run-log-cell" colspan="8">${log}</td></tr>` : ""}`;
|
|
28030
28250
|
}).join("");
|
|
28031
28251
|
const body = `
|
|
28032
28252
|
<div class="stats-grid">
|
|
@@ -28036,7 +28256,7 @@ var init_web = __esm({
|
|
|
28036
28256
|
${statCard(runs.filter((run) => run.status === "running").length, t(locale, "stats.pageRunning"), "tone-blue", icon("activity"), "reveal-delay-2")}
|
|
28037
28257
|
</div>
|
|
28038
28258
|
<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>
|
|
28039
|
-
${
|
|
28259
|
+
${pagination(locale, "/runs", page, totalPages, total)}`;
|
|
28040
28260
|
return c.html(renderLayout({ locale, activeTab: "runs", body }));
|
|
28041
28261
|
});
|
|
28042
28262
|
app.get("/system", async (c) => {
|
|
@@ -28143,7 +28363,11 @@ var init_web = __esm({
|
|
|
28143
28363
|
const task = await TaskService.getById(id);
|
|
28144
28364
|
if (!task) return c.json({ error: "not found" }, 404);
|
|
28145
28365
|
const runs = await TaskRunService.listByTaskId(id);
|
|
28146
|
-
return c.json({
|
|
28366
|
+
return c.json({
|
|
28367
|
+
...task,
|
|
28368
|
+
_resultPresentation: task.resultLog ? presentRunLog(task.resultLog) : null,
|
|
28369
|
+
_runs: runs
|
|
28370
|
+
});
|
|
28147
28371
|
});
|
|
28148
28372
|
app.get("/api/runs/:id", async (c) => {
|
|
28149
28373
|
const id = parsePositiveInteger2(c.req.param("id"));
|
|
@@ -28648,7 +28872,6 @@ init_db2();
|
|
|
28648
28872
|
init_duration();
|
|
28649
28873
|
init_pm2();
|
|
28650
28874
|
init_config();
|
|
28651
|
-
import { spawnSync as spawnSync4 } from "child_process";
|
|
28652
28875
|
|
|
28653
28876
|
// src/cli/i18n.ts
|
|
28654
28877
|
function requestedLanguage(argv) {
|
|
@@ -28861,6 +29084,118 @@ function parseTaskStatus(value) {
|
|
|
28861
29084
|
|
|
28862
29085
|
// src/cli/index.ts
|
|
28863
29086
|
init_update2();
|
|
29087
|
+
|
|
29088
|
+
// src/cli/doctor-smoke.ts
|
|
29089
|
+
init_task_service();
|
|
29090
|
+
init_task_run_service();
|
|
29091
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
29092
|
+
import { resolve as resolve5 } from "path";
|
|
29093
|
+
function tail(value, maxLength = 2e3) {
|
|
29094
|
+
if (!value) return null;
|
|
29095
|
+
return value.length <= maxLength ? value : value.slice(-maxLength);
|
|
29096
|
+
}
|
|
29097
|
+
function extractOpenCodeText(log) {
|
|
29098
|
+
if (!log) return "";
|
|
29099
|
+
const parts = [];
|
|
29100
|
+
for (const line of log.split("\n")) {
|
|
29101
|
+
try {
|
|
29102
|
+
const parsed = JSON.parse(line);
|
|
29103
|
+
if (parsed.type === "text" && parsed.part?.type === "text" && typeof parsed.part.text === "string") {
|
|
29104
|
+
parts.push(parsed.part.text);
|
|
29105
|
+
}
|
|
29106
|
+
} catch {
|
|
29107
|
+
}
|
|
29108
|
+
}
|
|
29109
|
+
return parts.join("\n").trim();
|
|
29110
|
+
}
|
|
29111
|
+
async function runDoctorSmoke(options) {
|
|
29112
|
+
if (!options.agent.trim()) throw new Error("smoke agent \u4E0D\u80FD\u4E3A\u7A7A");
|
|
29113
|
+
if (!Number.isInteger(options.timeoutMs) || options.timeoutMs < 1e3 || options.timeoutMs > 6048e5) {
|
|
29114
|
+
throw new Error("smoke timeout \u5FC5\u987B\u662F 1 \u79D2\u5230 7 \u5929\u4E4B\u95F4\u7684\u6574\u6570\u6BEB\u79D2\u503C");
|
|
29115
|
+
}
|
|
29116
|
+
const cwd = resolve5(options.cwd);
|
|
29117
|
+
const marker = options.marker ?? `SUPERTASK_SMOKE_${randomUUID2().replaceAll("-", "").toUpperCase()}`;
|
|
29118
|
+
const model = options.model && options.model !== "default" ? options.model : void 0;
|
|
29119
|
+
const startedAt = Date.now();
|
|
29120
|
+
const task = await TaskService.add({
|
|
29121
|
+
name: "[doctor] Gateway real smoke test",
|
|
29122
|
+
agent: options.agent,
|
|
29123
|
+
model,
|
|
29124
|
+
prompt: `\u4E0D\u8981\u8C03\u7528\u4EFB\u4F55\u5DE5\u5177\u3002\u53EA\u56DE\u590D\u8FD9\u4E00\u884C\uFF1A${marker}`,
|
|
29125
|
+
cwd,
|
|
29126
|
+
category: "diagnostic",
|
|
29127
|
+
importance: 5,
|
|
29128
|
+
urgency: 5,
|
|
29129
|
+
batchId: `doctor-smoke-${randomUUID2()}`,
|
|
29130
|
+
maxRetries: 0,
|
|
29131
|
+
retryBackoffMs: 0,
|
|
29132
|
+
timeoutMs: options.timeoutMs
|
|
29133
|
+
});
|
|
29134
|
+
const deadline = startedAt + options.timeoutMs;
|
|
29135
|
+
const pollIntervalMs = Math.max(10, options.pollIntervalMs ?? 250);
|
|
29136
|
+
while (Date.now() < deadline) {
|
|
29137
|
+
const current2 = await TaskService.getById(task.id);
|
|
29138
|
+
const run2 = await TaskRunService.getLatestByTaskId(task.id);
|
|
29139
|
+
if (!current2) {
|
|
29140
|
+
return {
|
|
29141
|
+
ok: false,
|
|
29142
|
+
taskId: task.id,
|
|
29143
|
+
runId: run2?.id ?? null,
|
|
29144
|
+
status: "missing",
|
|
29145
|
+
agent: options.agent,
|
|
29146
|
+
model: model ?? null,
|
|
29147
|
+
cwd,
|
|
29148
|
+
durationMs: Date.now() - startedAt,
|
|
29149
|
+
error: "\u5192\u70DF\u4EFB\u52A1\u5728\u5B8C\u6210\u524D\u88AB\u5220\u9664"
|
|
29150
|
+
};
|
|
29151
|
+
}
|
|
29152
|
+
if (current2.status === "done") {
|
|
29153
|
+
const log = run2?.log ?? current2.resultLog;
|
|
29154
|
+
const markerObserved = extractOpenCodeText(log) === marker;
|
|
29155
|
+
return {
|
|
29156
|
+
ok: markerObserved,
|
|
29157
|
+
taskId: task.id,
|
|
29158
|
+
runId: run2?.id ?? null,
|
|
29159
|
+
status: current2.status,
|
|
29160
|
+
agent: options.agent,
|
|
29161
|
+
model: model ?? null,
|
|
29162
|
+
cwd,
|
|
29163
|
+
durationMs: Date.now() - startedAt,
|
|
29164
|
+
error: markerObserved ? null : "OpenCode \u5DF2\u9000\u51FA\u6210\u529F\uFF0C\u4F46\u6A21\u578B\u6587\u672C\u4E0D\u662F\u9884\u671F\u7684\u7CBE\u786E\u6807\u8BB0"
|
|
29165
|
+
};
|
|
29166
|
+
}
|
|
29167
|
+
if (current2.status === "dead_letter" || current2.status === "cancelled") {
|
|
29168
|
+
return {
|
|
29169
|
+
ok: false,
|
|
29170
|
+
taskId: task.id,
|
|
29171
|
+
runId: run2?.id ?? null,
|
|
29172
|
+
status: current2.status,
|
|
29173
|
+
agent: options.agent,
|
|
29174
|
+
model: model ?? null,
|
|
29175
|
+
cwd,
|
|
29176
|
+
durationMs: Date.now() - startedAt,
|
|
29177
|
+
error: tail(run2?.log ?? current2.resultLog) ?? `\u4EFB\u52A1\u8FDB\u5165 ${current2.status}`
|
|
29178
|
+
};
|
|
29179
|
+
}
|
|
29180
|
+
await Bun.sleep(Math.min(pollIntervalMs, Math.max(1, deadline - Date.now())));
|
|
29181
|
+
}
|
|
29182
|
+
const current = await TaskService.getById(task.id);
|
|
29183
|
+
const run = await TaskRunService.getLatestByTaskId(task.id);
|
|
29184
|
+
await TaskService.cancel(task.id);
|
|
29185
|
+
return {
|
|
29186
|
+
ok: false,
|
|
29187
|
+
taskId: task.id,
|
|
29188
|
+
runId: run?.id ?? null,
|
|
29189
|
+
status: current?.status ?? "missing",
|
|
29190
|
+
agent: options.agent,
|
|
29191
|
+
model: model ?? null,
|
|
29192
|
+
cwd,
|
|
29193
|
+
durationMs: Date.now() - startedAt,
|
|
29194
|
+
error: `\u7B49\u5F85 Gateway \u6267\u884C\u8D85\u8FC7 ${options.timeoutMs}ms\uFF0C\u5192\u70DF\u4EFB\u52A1\u5DF2\u8BF7\u6C42\u53D6\u6D88`
|
|
29195
|
+
};
|
|
29196
|
+
}
|
|
29197
|
+
|
|
29198
|
+
// src/cli/index.ts
|
|
28864
29199
|
var cliLocale = resolveCliLocale();
|
|
28865
29200
|
var t2 = (zh, en) => cliText(cliLocale, zh, en);
|
|
28866
29201
|
async function withDb(fn, formatError = (error) => JSON.stringify({
|
|
@@ -29194,25 +29529,15 @@ program2.command("config").description(t2("\u663E\u793A\u5F53\u524D\u914D\u7F6E"
|
|
|
29194
29529
|
const cfg = loadConfig2();
|
|
29195
29530
|
console.log(JSON.stringify(cfg, null, 2));
|
|
29196
29531
|
});
|
|
29197
|
-
program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u636E\u5E93\u3001Gateway\u3001Web \u754C\u9762\u548C\u65E5\u5FD7\u8F6E\u8F6C", "diagnose OpenCode, database, Gateway, Dashboard, and log rotation")).option("--json", t2("\u5F3A\u5236\u8F93\u51FA JSON", "force JSON output")).action(async (options) => withDb(async () => {
|
|
29532
|
+
program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u636E\u5E93\u3001Gateway\u3001Web \u754C\u9762\u548C\u65E5\u5FD7\u8F6E\u8F6C", "diagnose OpenCode, database, Gateway, Dashboard, and log rotation")).option("--json", t2("\u5F3A\u5236\u8F93\u51FA JSON", "force JSON output")).option("--smoke", t2("\u901A\u8FC7 Gateway \u63D0\u4EA4\u4E00\u4E2A\u771F\u5B9E OpenCode \u4EFB\u52A1\u5E76\u9A8C\u8BC1\u8F93\u51FA", "queue a real OpenCode task through Gateway and verify its output")).option("--smoke-agent <agent>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u4F7F\u7528\u7684 Agent", "Agent used by the real smoke task"), "build").option("--smoke-model <model>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u4F7F\u7528\u7684\u6A21\u578B\uFF1B\u9ED8\u8BA4\u8DDF\u968F Agent \u914D\u7F6E", "model used by the real smoke task; defaults to the Agent configuration")).option("--smoke-cwd <path>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u7684\u9879\u76EE\u76EE\u5F55\uFF1B\u9ED8\u8BA4\u4E3A\u5F53\u524D\u76EE\u5F55", "project directory for the real smoke task; defaults to the current directory")).option("--smoke-timeout <duration>", t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u7B49\u5F85\u4E0A\u9650\uFF0C\u5982 2min / 5min", "real smoke task timeout, e.g. 2min / 5min"), "3min").action(async (options) => withDb(async () => {
|
|
29198
29533
|
const config = loadConfig();
|
|
29199
29534
|
const database = DatabaseMaintenanceService.check();
|
|
29200
29535
|
const legacyQuarantinedRuns = await TaskRunService.listLegacyQuarantinedRuns(
|
|
29201
29536
|
config.watchdog.heartbeatTimeoutMs
|
|
29202
29537
|
);
|
|
29203
|
-
const gateway = getGatewayDiagnostic();
|
|
29538
|
+
const gateway = getGatewayDiagnostic({ probeOpenCode: true });
|
|
29204
29539
|
const packageVersion2 = getPackageVersion();
|
|
29205
|
-
const
|
|
29206
|
-
const opencodeResult = spawnSync4(opencodeBin2, ["--version"], {
|
|
29207
|
-
encoding: "utf8",
|
|
29208
|
-
env: process.env
|
|
29209
|
-
});
|
|
29210
|
-
const opencode = {
|
|
29211
|
-
ok: opencodeResult.status === 0,
|
|
29212
|
-
executable: opencodeBin2,
|
|
29213
|
-
version: opencodeResult.status === 0 ? opencodeResult.stdout.trim() : null,
|
|
29214
|
-
error: opencodeResult.status === 0 ? null : opencodeResult.error?.message || opencodeResult.stderr.trim() || t2(`\u9000\u51FA\u7801 ${opencodeResult.status}`, `exit code ${opencodeResult.status}`)
|
|
29215
|
-
};
|
|
29540
|
+
const opencode = diagnoseOpenCodeRuntime();
|
|
29216
29541
|
const plugin = getOpenCodePluginDiagnostic();
|
|
29217
29542
|
let dashboard = {
|
|
29218
29543
|
enabled: config.dashboard.enabled,
|
|
@@ -29284,6 +29609,12 @@ program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u63
|
|
|
29284
29609
|
"The current CLI/OpenCode database, config, or OpenCode executable scope does not match the PM2 Gateway"
|
|
29285
29610
|
));
|
|
29286
29611
|
}
|
|
29612
|
+
if (gateway.processFound && gateway.gatewayOpenCode?.ok !== true) {
|
|
29613
|
+
warnings.push(t2(
|
|
29614
|
+
`PM2 \u4FDD\u5B58\u7684 Gateway \u73AF\u5883\u65E0\u6CD5\u6267\u884C OpenCode\uFF1A${gateway.gatewayOpenCode?.error ?? "\u65E0\u6CD5\u8BFB\u53D6\u8FD0\u884C\u73AF\u5883"}`,
|
|
29615
|
+
`The Gateway environment saved by PM2 cannot execute OpenCode: ${gateway.gatewayOpenCode?.error ?? "runtime unavailable"}`
|
|
29616
|
+
));
|
|
29617
|
+
}
|
|
29287
29618
|
for (const run of legacyQuarantinedRuns) {
|
|
29288
29619
|
const cwdHint = run.taskCwd == null ? t2("\uFF08\u65E7\u4EFB\u52A1\u6CA1\u6709 cwd\uFF0C\u8BF7\u5148\u5728 Dashboard \u53D6\u6D88\uFF09", " (the legacy task has no cwd; cancel it in the Dashboard first)") : t2(`\uFF08\u5728 ${run.taskCwd} \u6267\u884C\uFF09`, ` (run in ${run.taskCwd})`);
|
|
29289
29620
|
const cancel = run.taskStatus === "cancelled" ? "" : t2(`\u5148${cwdHint} supertask cancel --id ${run.taskId}\uFF1B`, `first${cwdHint}: supertask cancel --id ${run.taskId}; `);
|
|
@@ -29293,7 +29624,31 @@ program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u63
|
|
|
29293
29624
|
`Legacy quarantined run #${run.runId}: ${owner}${cancel}after confirming no OpenCode process remains, run supertask run abandon --id ${run.runId} --confirm ABANDON`
|
|
29294
29625
|
));
|
|
29295
29626
|
}
|
|
29296
|
-
|
|
29627
|
+
let smoke = null;
|
|
29628
|
+
if (options.smoke) {
|
|
29629
|
+
const gatewayCanExecute = gateway.status === "online" && gateway.ready && gateway.scopeMatches && gateway.gatewayOpenCode?.ok === true;
|
|
29630
|
+
if (!gatewayCanExecute) {
|
|
29631
|
+
smoke = {
|
|
29632
|
+
ok: false,
|
|
29633
|
+
skipped: true,
|
|
29634
|
+
error: t2(
|
|
29635
|
+
"Gateway \u5C1A\u672A\u5C31\u7EEA\uFF0C\u6216\u5176 PM2 \u73AF\u5883\u65E0\u6CD5\u6267\u884C OpenCode\uFF1B\u5DF2\u8DF3\u8FC7\u771F\u5B9E\u4EFB\u52A1",
|
|
29636
|
+
"Gateway is not ready or its PM2 environment cannot execute OpenCode; the real task was skipped"
|
|
29637
|
+
)
|
|
29638
|
+
};
|
|
29639
|
+
} else {
|
|
29640
|
+
const smokeTimeoutMs = parseDuration(options.smokeTimeout);
|
|
29641
|
+
if (smokeTimeoutMs === null) throw new Error("smoke-timeout \u683C\u5F0F\u65E0\u6548");
|
|
29642
|
+
smoke = await runDoctorSmoke({
|
|
29643
|
+
agent: options.smokeAgent,
|
|
29644
|
+
model: options.smokeModel,
|
|
29645
|
+
cwd: options.smokeCwd ?? process.cwd(),
|
|
29646
|
+
timeoutMs: smokeTimeoutMs
|
|
29647
|
+
});
|
|
29648
|
+
}
|
|
29649
|
+
if (!smoke.ok) warnings.push(smoke.error ?? t2("\u771F\u5B9E\u5192\u70DF\u4EFB\u52A1\u5931\u8D25", "Real smoke task failed"));
|
|
29650
|
+
}
|
|
29651
|
+
const ok = opencode.ok && plugin.ok && database.ok && legacyQuarantinedRuns.length === 0 && gateway.pm2Installed && gateway.status === "online" && gateway.ready && gatewayEntryPinned && gatewayVersionMatchesPackage && configuredVersionsMatch && cliVersionMatchesPlugin && gateway.scopeMatches && gateway.gatewayOpenCode?.ok === true && gateway.logRotationInstalled && gateway.startupConfigured !== false && dashboard.ok && (!options.smoke || smoke?.ok === true);
|
|
29297
29652
|
const report = {
|
|
29298
29653
|
ok,
|
|
29299
29654
|
packageVersion: packageVersion2,
|
|
@@ -29305,6 +29660,7 @@ program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u63
|
|
|
29305
29660
|
legacyQuarantinedRuns,
|
|
29306
29661
|
gateway,
|
|
29307
29662
|
dashboard,
|
|
29663
|
+
smoke,
|
|
29308
29664
|
warnings
|
|
29309
29665
|
};
|
|
29310
29666
|
const json = options.json || !process.stdout.isTTY;
|
|
@@ -29314,10 +29670,15 @@ program2.command("doctor").description(t2("\u68C0\u67E5 OpenCode\u3001\u6570\u63
|
|
|
29314
29670
|
const mark = (value) => value ? "\u2713" : "\u2717";
|
|
29315
29671
|
console.log(`SuperTask doctor: ${ok ? t2("\u6B63\u5E38", "healthy") : t2("\u5F02\u5E38", "unhealthy")}`);
|
|
29316
29672
|
console.log(`${mark(opencode.ok)} OpenCode ${opencode.version ?? opencode.error ?? t2("\u4E0D\u53EF\u7528", "unavailable")}`);
|
|
29673
|
+
console.log(`${mark(gateway.gatewayOpenCode?.ok === true)} ${t2("Gateway \u73AF\u5883\u4E2D\u7684 OpenCode", "OpenCode in Gateway environment")} ${gateway.gatewayOpenCode?.version ?? gateway.gatewayOpenCode?.error ?? t2("\u4E0D\u53EF\u7528", "unavailable")}${gateway.gatewayOpenCode?.executable ? `\uFF0C${gateway.gatewayOpenCode.executable}` : ""}`);
|
|
29317
29674
|
console.log(`${mark(plugin.ok)} ${t2("OpenCode \u63D2\u4EF6", "OpenCode plugin")} ${plugin.spec || plugin.error || t2("\u672A\u914D\u7F6E", "not configured")}${plugin.cachedVersion ? t2(`\uFF08\u7F13\u5B58 v${plugin.cachedVersion}\uFF09`, ` (cached v${plugin.cachedVersion})`) : ""}`);
|
|
29318
29675
|
console.log(`${mark(database.ok)} ${t2("\u6570\u636E\u5E93", "Database")} ${database.path}${t2(`\uFF08\u4EFB\u52A1 ${database.counts.tasks}\uFF0C\u8FD0\u884C\u4E2D ${database.runningTasks}\uFF09`, ` (tasks ${database.counts.tasks}, running ${database.runningTasks})`)}`);
|
|
29319
29676
|
console.log(`${mark(gateway.status === "online" && gateway.ready && gatewayEntryPinned && gatewayVersionMatchesPackage)} Gateway ${gateway.status ?? "missing"}${gateway.pid ? `\uFF0CPID ${gateway.pid}` : ""}${gateway.runningVersion ? `\uFF0Cv${gateway.runningVersion}` : ""}${gateway.gatewayEntry ? `\uFF0C${gateway.gatewayEntry}` : ""}`);
|
|
29320
29677
|
console.log(`${mark(dashboard.ok)} Dashboard ${dashboard.enabled ? dashboard.url : t2("\u5DF2\u7981\u7528", "disabled")}`);
|
|
29678
|
+
if (options.smoke) {
|
|
29679
|
+
const smokeSummary = smoke && "taskId" in smoke ? `task #${smoke.taskId}${smoke.runId ? ` / run #${smoke.runId}` : ""}\uFF0C${smoke.durationMs}ms` : smoke?.error ?? t2("\u672A\u6267\u884C", "not run");
|
|
29680
|
+
console.log(`${mark(smoke?.ok === true)} ${t2("\u771F\u5B9E Gateway \u5192\u70DF\u4EFB\u52A1", "Real Gateway smoke task")} ${smokeSummary}`);
|
|
29681
|
+
}
|
|
29321
29682
|
for (const warning of warnings) console.log(`! ${warning}`);
|
|
29322
29683
|
}
|
|
29323
29684
|
if (!ok) process.exitCode = 1;
|