opencode-supertask 0.1.39 → 0.1.40
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 +9 -0
- package/README.md +152 -352
- package/README.zh-CN.md +243 -0
- package/dist/cli/index.js +215 -47
- package/dist/cli/index.js.map +1 -1
- package/dist/gateway/index.js +195 -43
- package/dist/gateway/index.js.map +1 -1
- package/dist/plugin/supertask.js +37 -4
- package/dist/plugin/supertask.js.map +1 -1
- package/dist/web/index.js +179 -41
- package/dist/web/index.js.map +1 -1
- package/dist/worker/index.d.ts +1 -0
- package/dist/worker/index.js +34 -3
- package/dist/worker/index.js.map +1 -1
- package/drizzle/0008_good_smasher.sql +3 -0
- package/drizzle/meta/0008_snapshot.json +606 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +1 -1
package/dist/gateway/index.js
CHANGED
|
@@ -6005,6 +6005,7 @@ var init_schema = __esm({
|
|
|
6005
6005
|
name: text("name").notNull(),
|
|
6006
6006
|
agent: text("agent").notNull(),
|
|
6007
6007
|
model: text("model").default("default"),
|
|
6008
|
+
variant: text("variant"),
|
|
6008
6009
|
prompt: text("prompt").notNull(),
|
|
6009
6010
|
cwd: text("cwd"),
|
|
6010
6011
|
// 分类与优先级
|
|
@@ -6049,6 +6050,7 @@ var init_schema = __esm({
|
|
|
6049
6050
|
taskId: integer("task_id").notNull().references(() => tasks.id, { onDelete: "cascade" }),
|
|
6050
6051
|
sessionId: text("session_id"),
|
|
6051
6052
|
model: text("model"),
|
|
6053
|
+
variant: text("variant"),
|
|
6052
6054
|
status: text("status").default("running"),
|
|
6053
6055
|
startedAt: integer("started_at", { mode: "timestamp" }).$defaultFn(() => /* @__PURE__ */ new Date()),
|
|
6054
6056
|
finishedAt: integer("finished_at", { mode: "timestamp" }),
|
|
@@ -6069,6 +6071,7 @@ var init_schema = __esm({
|
|
|
6069
6071
|
name: text("name").notNull(),
|
|
6070
6072
|
agent: text("agent").notNull(),
|
|
6071
6073
|
model: text("model").default("default"),
|
|
6074
|
+
variant: text("variant"),
|
|
6072
6075
|
prompt: text("prompt").notNull(),
|
|
6073
6076
|
cwd: text("cwd"),
|
|
6074
6077
|
category: text("category").default("general"),
|
|
@@ -6439,6 +6442,28 @@ var init_task_batch = __esm({
|
|
|
6439
6442
|
}
|
|
6440
6443
|
});
|
|
6441
6444
|
|
|
6445
|
+
// src/core/model-variant.ts
|
|
6446
|
+
function normalizeModelVariant(value) {
|
|
6447
|
+
if (value === void 0 || value === null) return value;
|
|
6448
|
+
const normalized = value.trim();
|
|
6449
|
+
if (!normalized) return null;
|
|
6450
|
+
if (normalized.length > MAX_MODEL_VARIANT_LENGTH) {
|
|
6451
|
+
throw new Error(`variant \u957F\u5EA6\u4E0D\u80FD\u8D85\u8FC7 ${MAX_MODEL_VARIANT_LENGTH} \u4E2A\u5B57\u7B26`);
|
|
6452
|
+
}
|
|
6453
|
+
if (CONTROL_CHARACTER_PATTERN.test(normalized)) {
|
|
6454
|
+
throw new Error("variant \u4E0D\u80FD\u5305\u542B\u63A7\u5236\u5B57\u7B26");
|
|
6455
|
+
}
|
|
6456
|
+
return normalized;
|
|
6457
|
+
}
|
|
6458
|
+
var MAX_MODEL_VARIANT_LENGTH, CONTROL_CHARACTER_PATTERN;
|
|
6459
|
+
var init_model_variant = __esm({
|
|
6460
|
+
"src/core/model-variant.ts"() {
|
|
6461
|
+
"use strict";
|
|
6462
|
+
MAX_MODEL_VARIANT_LENGTH = 128;
|
|
6463
|
+
CONTROL_CHARACTER_PATTERN = /[\u0000-\u001F\u007F]/;
|
|
6464
|
+
}
|
|
6465
|
+
});
|
|
6466
|
+
|
|
6442
6467
|
// src/core/services/task.service.ts
|
|
6443
6468
|
function hasNoExecutableDependents() {
|
|
6444
6469
|
return sql`NOT EXISTS (
|
|
@@ -6494,6 +6519,7 @@ var init_task_service = __esm({
|
|
|
6494
6519
|
init_backoff();
|
|
6495
6520
|
init_task_working_directory();
|
|
6496
6521
|
init_task_batch();
|
|
6522
|
+
init_model_variant();
|
|
6497
6523
|
({ tasks: tasks2, taskRuns: taskRuns2 } = schema_exports);
|
|
6498
6524
|
cleanupInvocation = 0;
|
|
6499
6525
|
TaskDeletionConflictError = class extends Error {
|
|
@@ -6513,7 +6539,8 @@ var init_task_service = __esm({
|
|
|
6513
6539
|
static async add(data) {
|
|
6514
6540
|
const normalizedData = {
|
|
6515
6541
|
...data,
|
|
6516
|
-
batchId: normalizeTaskBatchId(data.batchId)
|
|
6542
|
+
batchId: normalizeTaskBatchId(data.batchId),
|
|
6543
|
+
variant: normalizeModelVariant(data.variant)
|
|
6517
6544
|
};
|
|
6518
6545
|
this.validateNewTask(normalizedData);
|
|
6519
6546
|
return db.transaction((tx) => {
|
|
@@ -6541,7 +6568,11 @@ var init_task_service = __esm({
|
|
|
6541
6568
|
}
|
|
6542
6569
|
static async update(id, data, scope = {}) {
|
|
6543
6570
|
if (Object.keys(data).length === 0) throw new Error("\u81F3\u5C11\u63D0\u4F9B\u4E00\u4E2A\u8981\u4FEE\u6539\u7684\u5B57\u6BB5");
|
|
6544
|
-
const normalizedData =
|
|
6571
|
+
const normalizedData = {
|
|
6572
|
+
...data,
|
|
6573
|
+
...data.batchId === void 0 ? {} : { batchId: normalizeTaskBatchId(data.batchId) ?? null },
|
|
6574
|
+
...data.variant === void 0 ? {} : { variant: normalizeModelVariant(data.variant) ?? null }
|
|
6575
|
+
};
|
|
6545
6576
|
return db.transaction((tx) => {
|
|
6546
6577
|
const task = tx.select().from(tasks2).where(and(
|
|
6547
6578
|
eq(tasks2.id, id),
|
|
@@ -6553,6 +6584,7 @@ var init_task_service = __esm({
|
|
|
6553
6584
|
name: normalizedData.name ?? task.name,
|
|
6554
6585
|
agent: normalizedData.agent ?? task.agent,
|
|
6555
6586
|
model: normalizedData.model ?? task.model,
|
|
6587
|
+
variant: normalizedData.variant === void 0 ? task.variant : normalizedData.variant,
|
|
6556
6588
|
prompt: normalizedData.prompt ?? task.prompt,
|
|
6557
6589
|
cwd: task.cwd,
|
|
6558
6590
|
category: normalizedData.category ?? task.category,
|
|
@@ -17045,12 +17077,14 @@ var init_task_template_service = __esm({
|
|
|
17045
17077
|
init_cron_parser();
|
|
17046
17078
|
init_task_working_directory();
|
|
17047
17079
|
init_task_batch();
|
|
17080
|
+
init_model_variant();
|
|
17048
17081
|
({ taskTemplates: taskTemplates2 } = schema_exports);
|
|
17049
17082
|
TaskTemplateService = class {
|
|
17050
17083
|
static async create(data) {
|
|
17051
17084
|
const normalizedData = {
|
|
17052
17085
|
...data,
|
|
17053
|
-
batchId: normalizeTaskBatchId(data.batchId)
|
|
17086
|
+
batchId: normalizeTaskBatchId(data.batchId),
|
|
17087
|
+
variant: normalizeModelVariant(data.variant)
|
|
17054
17088
|
};
|
|
17055
17089
|
this.validate(normalizedData);
|
|
17056
17090
|
const now = Date.now();
|
|
@@ -17116,7 +17150,8 @@ var init_task_template_service = __esm({
|
|
|
17116
17150
|
static async update(id, data) {
|
|
17117
17151
|
const normalizedData = {
|
|
17118
17152
|
...data,
|
|
17119
|
-
batchId: normalizeTaskBatchId(data.batchId) ?? null
|
|
17153
|
+
batchId: normalizeTaskBatchId(data.batchId) ?? null,
|
|
17154
|
+
...data.variant === void 0 ? {} : { variant: normalizeModelVariant(data.variant) ?? null }
|
|
17120
17155
|
};
|
|
17121
17156
|
this.validate(normalizedData);
|
|
17122
17157
|
const now = Date.now();
|
|
@@ -17279,6 +17314,7 @@ function createTaskFromTemplate(templateId, options) {
|
|
|
17279
17314
|
name: `${options.namePrefix ?? ""}${tmpl.name}`,
|
|
17280
17315
|
agent: tmpl.agent,
|
|
17281
17316
|
model: tmpl.model ?? "default",
|
|
17317
|
+
variant: tmpl.variant,
|
|
17282
17318
|
prompt: tmpl.prompt,
|
|
17283
17319
|
cwd: tmpl.cwd ?? null,
|
|
17284
17320
|
category: tmpl.category ?? "general",
|
|
@@ -19638,17 +19674,49 @@ function runOpenCode(executable, args, cwd, timeoutMs) {
|
|
|
19638
19674
|
const child = spawn2(executable, args, {
|
|
19639
19675
|
cwd,
|
|
19640
19676
|
env: process.env,
|
|
19641
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
19677
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
19678
|
+
detached: process.platform !== "win32"
|
|
19642
19679
|
});
|
|
19643
19680
|
let stdout = "";
|
|
19644
19681
|
let stderr = "";
|
|
19645
19682
|
let failure = null;
|
|
19646
|
-
let
|
|
19683
|
+
let settled = false;
|
|
19684
|
+
let forceKillTimer = null;
|
|
19685
|
+
let finalRejectTimer = null;
|
|
19686
|
+
let timer;
|
|
19687
|
+
const signalProcessTree = (signal) => {
|
|
19688
|
+
if (process.platform !== "win32" && child.pid) {
|
|
19689
|
+
try {
|
|
19690
|
+
process.kill(-child.pid, signal);
|
|
19691
|
+
return;
|
|
19692
|
+
} catch {
|
|
19693
|
+
}
|
|
19694
|
+
}
|
|
19695
|
+
child.kill(signal);
|
|
19696
|
+
};
|
|
19697
|
+
const rejectOnce = (error) => {
|
|
19698
|
+
failure ??= error;
|
|
19699
|
+
if (settled) return;
|
|
19700
|
+
settled = true;
|
|
19701
|
+
clearTimeout(timer);
|
|
19702
|
+
if (forceKillTimer) clearTimeout(forceKillTimer);
|
|
19703
|
+
if (finalRejectTimer) clearTimeout(finalRejectTimer);
|
|
19704
|
+
reject(failure);
|
|
19705
|
+
};
|
|
19706
|
+
const terminate = (error) => {
|
|
19707
|
+
if (failure) return;
|
|
19708
|
+
failure = error;
|
|
19709
|
+
signalProcessTree("SIGTERM");
|
|
19710
|
+
forceKillTimer = setTimeout(() => {
|
|
19711
|
+
signalProcessTree("SIGKILL");
|
|
19712
|
+
rejectOnce(error);
|
|
19713
|
+
}, 1e3);
|
|
19714
|
+
finalRejectTimer = setTimeout(() => rejectOnce(error), 2e3);
|
|
19715
|
+
};
|
|
19647
19716
|
const append = (current, chunk) => {
|
|
19648
19717
|
const next = current + chunk.toString();
|
|
19649
19718
|
if (Buffer.byteLength(next) > MAX_OUTPUT_BYTES && failure === null) {
|
|
19650
|
-
|
|
19651
|
-
child.kill("SIGTERM");
|
|
19719
|
+
terminate(new Error(`OpenCode \u8F93\u51FA\u8D85\u8FC7 ${MAX_OUTPUT_BYTES} bytes`));
|
|
19652
19720
|
}
|
|
19653
19721
|
return next.slice(-MAX_OUTPUT_BYTES);
|
|
19654
19722
|
};
|
|
@@ -19659,23 +19727,25 @@ function runOpenCode(executable, args, cwd, timeoutMs) {
|
|
|
19659
19727
|
stderr = append(stderr, chunk);
|
|
19660
19728
|
});
|
|
19661
19729
|
child.once("error", (error) => {
|
|
19662
|
-
|
|
19730
|
+
if (forceKillTimer) return;
|
|
19731
|
+
rejectOnce(error);
|
|
19663
19732
|
});
|
|
19664
|
-
|
|
19665
|
-
|
|
19666
|
-
child.kill("SIGTERM");
|
|
19733
|
+
timer = setTimeout(() => {
|
|
19734
|
+
terminate(new Error(`OpenCode \u547D\u4EE4\u8D85\u8FC7 ${timeoutMs}ms \u672A\u5B8C\u6210`));
|
|
19667
19735
|
}, timeoutMs);
|
|
19668
19736
|
child.once("close", (code) => {
|
|
19669
|
-
if (finished) return;
|
|
19670
|
-
finished = true;
|
|
19671
19737
|
clearTimeout(timer);
|
|
19738
|
+
if (forceKillTimer) return;
|
|
19739
|
+
if (finalRejectTimer) clearTimeout(finalRejectTimer);
|
|
19740
|
+
if (settled) return;
|
|
19741
|
+
settled = true;
|
|
19672
19742
|
if (failure) {
|
|
19673
19743
|
reject(failure);
|
|
19674
19744
|
return;
|
|
19675
19745
|
}
|
|
19676
19746
|
if (code !== 0) {
|
|
19677
19747
|
const detail = cleanOutput(stderr).trim() || `\u9000\u51FA\u7801 ${code ?? "null"}`;
|
|
19678
|
-
reject(new
|
|
19748
|
+
reject(new OpenCodeCommandExitError(`OpenCode ${args.join(" ")} \u5931\u8D25\uFF1A${detail}`));
|
|
19679
19749
|
return;
|
|
19680
19750
|
}
|
|
19681
19751
|
resolve4(cleanOutput(stdout));
|
|
@@ -19685,6 +19755,52 @@ function runOpenCode(executable, args, cwd, timeoutMs) {
|
|
|
19685
19755
|
function parseOpenCodeModels(output) {
|
|
19686
19756
|
return [...new Set(cleanOutput(output).split("\n").map((line) => line.trim()).filter((line) => /^[^\s/]+\/.+/.test(line)))].sort((left, right) => left.localeCompare(right));
|
|
19687
19757
|
}
|
|
19758
|
+
function isRecord(value) {
|
|
19759
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19760
|
+
}
|
|
19761
|
+
function findJsonObjectEnd(value, start) {
|
|
19762
|
+
let depth = 0;
|
|
19763
|
+
let inString = false;
|
|
19764
|
+
let escaped = false;
|
|
19765
|
+
for (let index2 = start; index2 < value.length; index2 += 1) {
|
|
19766
|
+
const character = value[index2];
|
|
19767
|
+
if (inString) {
|
|
19768
|
+
if (escaped) escaped = false;
|
|
19769
|
+
else if (character === "\\") escaped = true;
|
|
19770
|
+
else if (character === '"') inString = false;
|
|
19771
|
+
continue;
|
|
19772
|
+
}
|
|
19773
|
+
if (character === '"') inString = true;
|
|
19774
|
+
else if (character === "{") depth += 1;
|
|
19775
|
+
else if (character === "}" && --depth === 0) return index2 + 1;
|
|
19776
|
+
}
|
|
19777
|
+
return null;
|
|
19778
|
+
}
|
|
19779
|
+
function parseOpenCodeModelMetadata(output) {
|
|
19780
|
+
const cleaned = cleanOutput(output);
|
|
19781
|
+
const models = /* @__PURE__ */ new Set();
|
|
19782
|
+
const variantsByModel = {};
|
|
19783
|
+
const headingPattern = /^([^\s/]+\/[^\r\n]+)\r?\n\s*(?=\{)/gm;
|
|
19784
|
+
for (const match2 of cleaned.matchAll(headingPattern)) {
|
|
19785
|
+
const model = match2[1].trim();
|
|
19786
|
+
models.add(model);
|
|
19787
|
+
let objectStart = (match2.index ?? 0) + match2[0].length;
|
|
19788
|
+
while (/\s/.test(cleaned[objectStart] ?? "")) objectStart += 1;
|
|
19789
|
+
if (cleaned[objectStart] !== "{") continue;
|
|
19790
|
+
const objectEnd = findJsonObjectEnd(cleaned, objectStart);
|
|
19791
|
+
if (objectEnd === null) continue;
|
|
19792
|
+
try {
|
|
19793
|
+
const metadata = JSON.parse(cleaned.slice(objectStart, objectEnd));
|
|
19794
|
+
if (!isRecord(metadata) || !isRecord(metadata.variants)) continue;
|
|
19795
|
+
variantsByModel[model] = Object.keys(metadata.variants).filter((variant) => variant.trim().length > 0).sort((left, right) => left.localeCompare(right));
|
|
19796
|
+
} catch {
|
|
19797
|
+
}
|
|
19798
|
+
}
|
|
19799
|
+
return {
|
|
19800
|
+
models: [...models].sort((left, right) => left.localeCompare(right)),
|
|
19801
|
+
variantsByModel
|
|
19802
|
+
};
|
|
19803
|
+
}
|
|
19688
19804
|
function parseOpenCodeAgents(output) {
|
|
19689
19805
|
const agents = /* @__PURE__ */ new Map();
|
|
19690
19806
|
for (const line of cleanOutput(output).split("\n")) {
|
|
@@ -19708,14 +19824,18 @@ async function loadOpenCodeCatalog(cwd, options = {}) {
|
|
|
19708
19824
|
return cached.result;
|
|
19709
19825
|
}
|
|
19710
19826
|
const result = Promise.all([
|
|
19711
|
-
runOpenCode(executable, ["models"], cwd, timeoutMs)
|
|
19827
|
+
runOpenCode(executable, ["models", "--verbose"], cwd, timeoutMs).catch((error) => {
|
|
19828
|
+
if (!(error instanceof OpenCodeCommandExitError)) throw error;
|
|
19829
|
+
return runOpenCode(executable, ["models"], cwd, timeoutMs);
|
|
19830
|
+
}),
|
|
19712
19831
|
runOpenCode(executable, ["agent", "list"], cwd, timeoutMs)
|
|
19713
19832
|
]).then(([modelsOutput, agentsOutput]) => {
|
|
19714
|
-
const
|
|
19833
|
+
const metadata = parseOpenCodeModelMetadata(modelsOutput);
|
|
19834
|
+
const models = metadata.models.length > 0 ? metadata.models : parseOpenCodeModels(modelsOutput);
|
|
19715
19835
|
const agents = parseOpenCodeAgents(agentsOutput).filter((agent) => agent.mode !== "subagent");
|
|
19716
19836
|
if (models.length === 0) throw new Error("OpenCode \u6CA1\u6709\u8FD4\u56DE\u53EF\u7528\u6A21\u578B");
|
|
19717
19837
|
if (agents.length === 0) throw new Error("OpenCode \u6CA1\u6709\u8FD4\u56DE\u53EF\u76F4\u63A5\u8FD0\u884C\u7684\u4E3B Agent");
|
|
19718
|
-
return { cwd, models, agents };
|
|
19838
|
+
return { cwd, models, variantsByModel: metadata.variantsByModel, agents };
|
|
19719
19839
|
});
|
|
19720
19840
|
if (options.useCache !== false) {
|
|
19721
19841
|
catalogCache.set(cacheKey, { expiresAt: Date.now() + CATALOG_CACHE_MS, result });
|
|
@@ -19725,7 +19845,7 @@ async function loadOpenCodeCatalog(cwd, options = {}) {
|
|
|
19725
19845
|
}
|
|
19726
19846
|
return result;
|
|
19727
19847
|
}
|
|
19728
|
-
var CATALOG_CACHE_MS, COMMAND_TIMEOUT_MS, MAX_OUTPUT_BYTES, ANSI_PATTERN, catalogCache;
|
|
19848
|
+
var CATALOG_CACHE_MS, COMMAND_TIMEOUT_MS, MAX_OUTPUT_BYTES, ANSI_PATTERN, OpenCodeCommandExitError, catalogCache;
|
|
19729
19849
|
var init_opencode_catalog = __esm({
|
|
19730
19850
|
"src/core/opencode-catalog.ts"() {
|
|
19731
19851
|
"use strict";
|
|
@@ -19734,6 +19854,8 @@ var init_opencode_catalog = __esm({
|
|
|
19734
19854
|
COMMAND_TIMEOUT_MS = 2e4;
|
|
19735
19855
|
MAX_OUTPUT_BYTES = 4 * 1024 * 1024;
|
|
19736
19856
|
ANSI_PATTERN = /\x1B(?:[@-_][0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1B\\))/g;
|
|
19857
|
+
OpenCodeCommandExitError = class extends Error {
|
|
19858
|
+
};
|
|
19737
19859
|
catalogCache = /* @__PURE__ */ new Map();
|
|
19738
19860
|
}
|
|
19739
19861
|
});
|
|
@@ -20721,6 +20843,7 @@ function clientMessages(locale) {
|
|
|
20721
20843
|
"details.copySuccess",
|
|
20722
20844
|
"details.id",
|
|
20723
20845
|
"details.project",
|
|
20846
|
+
"details.variant",
|
|
20724
20847
|
"details.prompt",
|
|
20725
20848
|
"details.result",
|
|
20726
20849
|
"details.category",
|
|
@@ -20821,6 +20944,7 @@ function clientMessages(locale) {
|
|
|
20821
20944
|
"catalog.chooseProject",
|
|
20822
20945
|
"catalog.defaultModel",
|
|
20823
20946
|
"catalog.defaultProvider",
|
|
20947
|
+
"catalog.defaultVariant",
|
|
20824
20948
|
"catalog.loading",
|
|
20825
20949
|
"catalog.loaded",
|
|
20826
20950
|
"catalog.failed",
|
|
@@ -20945,23 +21069,23 @@ function renderLayout(options) {
|
|
|
20945
21069
|
function detailSession(value){if(!value)return text('details.none');const session=String(value);return session.length<=10?session:session.slice(0,6)+'***'+session.slice(-4)}
|
|
20946
21070
|
function detailTaskResult(data){const presentation=data._resultPresentation;if(!presentation)return text('details.none');const parts=[];if(Array.isArray(presentation.errors)&&presentation.errors.length)parts.push(presentation.errors.join('\\n'));if(presentation.text)parts.push(presentation.text);return parts.join('\\n\\n')||text('details.none')}
|
|
20947
21071
|
function detailField(label,value,options={}){const item=document.createElement('div');item.className='detail-item'+(options.wide?' wide':'');const name=document.createElement('div');name.className='detail-label';name.textContent=label;const content=options.long?document.createElement('pre'):document.createElement('div');content.className='detail-value'+(options.mono?' mono':'')+(options.long?' long':'');content.textContent=value===null||value===undefined||value===''?text('details.none'):String(value);item.append(name,content);return item}
|
|
20948
|
-
function renderDetailHistory(runs){const section=document.createElement('section');section.className='detail-history';const title=document.createElement('h3');title.textContent=text('details.history');section.appendChild(title);if(!Array.isArray(runs)||runs.length===0){const empty=document.createElement('div');empty.className='muted small';empty.textContent=text('details.noHistory');section.appendChild(empty);return section}const list=document.createElement('div');list.className='detail-history-list';for(const run of runs){const item=document.createElement('div');item.className='detail-history-item';const primary=document.createElement('strong');primary.textContent='Run #'+run.id+' \xB7 '+detailStatus('run',run.status);const secondary=document.createElement('span');secondary.className='muted';secondary.textContent=detailDate(run.startedAt)+(run.model?' \xB7 '+detailModel(run.model):'');item.append(primary,secondary);list.appendChild(item)}section.appendChild(list);return section}
|
|
21072
|
+
function renderDetailHistory(runs){const section=document.createElement('section');section.className='detail-history';const title=document.createElement('h3');title.textContent=text('details.history');section.appendChild(title);if(!Array.isArray(runs)||runs.length===0){const empty=document.createElement('div');empty.className='muted small';empty.textContent=text('details.noHistory');section.appendChild(empty);return section}const list=document.createElement('div');list.className='detail-history-list';for(const run of runs){const item=document.createElement('div');item.className='detail-history-item';const primary=document.createElement('strong');primary.textContent='Run #'+run.id+' \xB7 '+detailStatus('run',run.status);const secondary=document.createElement('span');secondary.className='muted';secondary.textContent=detailDate(run.startedAt)+(run.model?' \xB7 '+detailModel(run.model):'')+(run.variant?' \xB7 '+run.variant:'');item.append(primary,secondary);list.appendChild(item)}section.appendChild(list);return section}
|
|
20949
21073
|
function detailFields(type,data){if(type==='task')return [
|
|
20950
21074
|
[text('details.id'),'#'+data.id],[text('table.name'),data.name],[text('table.status'),detailStatus('task',data.status)],[text('details.project'),data.cwd,{wide:true,mono:true}],
|
|
20951
|
-
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
21075
|
+
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.variant'),data.variant||text('details.default')],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
20952
21076
|
[text('details.category'),data.category],[text('details.batch'),data.batchId],[text('details.dependency'),data.dependsOn?'#'+data.dependsOn:text('details.none')],
|
|
20953
21077
|
[text('details.importance'),data.importance],[text('details.urgency'),data.urgency],[text('details.retryCount'),String(data.retryCount??0)+' / '+String(data.maxRetries??0)],
|
|
20954
21078
|
[text('details.retryBackoff'),detailDuration(data.retryBackoffMs)],[text('details.timeout'),detailDuration(data.timeoutMs)],[text('details.scheduledAt'),detailDate(data.scheduledAt)],
|
|
20955
21079
|
[text('details.createdAt'),detailDate(data.createdAt)],[text('details.startedAt'),detailDate(data.startedAt)],[text('details.finishedAt'),detailDate(data.finishedAt)],
|
|
20956
21080
|
[text('details.result'),detailTaskResult(data),{wide:true,long:true}]
|
|
20957
21081
|
];if(type==='run'){const started=data.startedAt?new Date(data.startedAt).getTime():null;const finished=data.finishedAt?new Date(data.finishedAt).getTime():null;return [
|
|
20958
|
-
[text('details.id'),'Run #'+data.id],[text('details.taskId'),'#'+data.taskId],[text('table.status'),detailStatus('run',data.status)],[text('table.model'),detailModel(data.model)],
|
|
21082
|
+
[text('details.id'),'Run #'+data.id],[text('details.taskId'),'#'+data.taskId],[text('table.status'),detailStatus('run',data.status)],[text('table.model'),detailModel(data.model)],[text('details.variant'),data.variant||text('details.default')],
|
|
20959
21083
|
[text('details.session'),detailSession(data.sessionId)],[text('details.startedAt'),detailDate(data.startedAt)],[text('details.finishedAt'),detailDate(data.finishedAt)],
|
|
20960
21084
|
[text('table.duration'),started!==null?detailDuration((finished??Date.now())-started):text('details.none')],[text('details.heartbeat'),detailDate(data.heartbeatAt)],
|
|
20961
21085
|
[text('details.process'),'Worker PID '+String(data.workerPid??'\u2014')+' \xB7 OpenCode PID '+String(data.childPid??'\u2014'),{wide:true,mono:true}]
|
|
20962
21086
|
];}const scheduleRule=data.scheduleType==='cron'?data.cronExpr:data.scheduleType==='recurring'?detailDuration(data.intervalMs):detailDate(data.runAt);return [
|
|
20963
21087
|
[text('details.id'),'#'+data.id],[text('table.name'),data.name],[text('details.enabled'),data.enabled?text('details.enabledYes'):text('details.enabledNo')],[text('details.project'),data.cwd,{wide:true,mono:true}],
|
|
20964
|
-
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
21088
|
+
[text('table.agent'),data.agent],[text('table.model'),detailModel(data.model)],[text('details.variant'),data.variant||text('details.default')],[text('details.prompt'),data.prompt,{wide:true,long:true}],
|
|
20965
21089
|
[text('template.scheduleType'),detailScheduleType(data.scheduleType)],[text('details.scheduleRule'),scheduleRule],[text('details.category'),data.category],[text('details.batch'),data.batchId],
|
|
20966
21090
|
[text('details.importance'),data.importance],[text('details.urgency'),data.urgency],[text('details.maxInstances'),data.maxInstances],[text('details.maxRetries'),data.maxRetries??0],
|
|
20967
21091
|
[text('details.retryBackoff'),detailDuration(data.retryBackoffMs)],[text('details.timeout'),detailDuration(data.timeoutMs)],[text('details.lastRun'),detailDate(data.lastRunAt)],[text('details.nextRun'),detailDate(data.nextRunAt)],
|
|
@@ -20978,12 +21102,20 @@ function renderLayout(options) {
|
|
|
20978
21102
|
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')}
|
|
20979
21103
|
const catalogTimers={};const catalogRequests={};const catalogModels={};
|
|
20980
21104
|
function catalogField(prefix,name){return document.getElementById(prefix+'-'+name)}
|
|
20981
|
-
function resetCatalog(prefix){const agent=catalogField(prefix,'agent');const provider=catalogField(prefix,'model-provider');const model=catalogField(prefix,'model');if(!agent||!provider||!model)return;catalogModels[prefix]=[];agent.replaceChildren(new Option(text('catalog.chooseProject'),''));provider.replaceChildren(new Option(text('catalog.defaultProvider'),''));model.replaceChildren(new Option(text('catalog.defaultModel'),'default'));agent.disabled=false;provider.disabled=true;model.disabled=true;catalogField(prefix,'catalog-status').textContent='';}
|
|
21105
|
+
function resetCatalog(prefix){const agent=catalogField(prefix,'agent');const provider=catalogField(prefix,'model-provider');const model=catalogField(prefix,'model');const variant=catalogField(prefix,'variant');if(!agent||!provider||!model||!variant)return;const preferredVariant=variant.dataset.preferred||'';catalogModels[prefix]=[];agent.replaceChildren(new Option(text('catalog.chooseProject'),''));provider.replaceChildren(new Option(text('catalog.defaultProvider'),''));model.replaceChildren(new Option(text('catalog.defaultModel'),'default'));variant.replaceChildren(new Option(text('catalog.defaultVariant'),''));if(preferredVariant)appendCurrentOption(variant,preferredVariant);variant.value=preferredVariant;agent.disabled=false;provider.disabled=true;model.disabled=true;variant.disabled=!preferredVariant;catalogField(prefix,'catalog-status').textContent='';}
|
|
20982
21106
|
function appendCurrentOption(select,value){if(!value||[...select.options].some(option=>option.value===value))return;select.appendChild(new Option(value,value));}
|
|
21107
|
+
function setPreferredVariant(prefix,modelValue,variantValue){const variant=catalogField(prefix,'variant');if(!variant)return;const preferred=variantValue||'';variant.dataset.preferred=preferred;variant.dataset.preferredModel=modelValue||'default';variant.replaceChildren(new Option(text('catalog.defaultVariant'),''));if(preferred)appendCurrentOption(variant,preferred);variant.value=preferred;variant.disabled=!preferred}
|
|
21108
|
+
function invalidateVariantRequest(prefix){const key=prefix+'-variant';catalogRequests[key]=(catalogRequests[key]||0)+1}
|
|
21109
|
+
function invalidateCatalogRequests(prefix){clearTimeout(catalogTimers[prefix]);catalogRequests[prefix]=(catalogRequests[prefix]||0)+1;invalidateVariantRequest(prefix)}
|
|
21110
|
+
function clearVariantPreference(prefix){const variant=catalogField(prefix,'variant');if(!variant)return;invalidateVariantRequest(prefix);variant.dataset.preferred='';variant.dataset.preferredModel='';variant.replaceChildren(new Option(text('catalog.defaultVariant'),''));variant.value='';variant.disabled=true}
|
|
21111
|
+
function handleProviderChange(prefix){clearVariantPreference(prefix);populateModelOptions(prefix)}
|
|
21112
|
+
function handleModelChange(prefix){clearVariantPreference(prefix);populateVariantOptions(prefix)}
|
|
21113
|
+
function handleVariantChange(prefix){const variant=catalogField(prefix,'variant');if(!variant)return;invalidateVariantRequest(prefix);variant.dataset.preferred='';variant.dataset.preferredModel=''}
|
|
20983
21114
|
function modelProvider(value){const slash=value.indexOf('/');return slash>0?value.slice(0,slash):''}
|
|
20984
|
-
function populateModelOptions(prefix,preferredModel=''){const provider=catalogField(prefix,'model-provider');const model=catalogField(prefix,'model');if(!provider||!model)return;const selectedProvider=provider.value;model.replaceChildren();if(!selectedProvider){model.appendChild(new Option(text('catalog.defaultModel'),'default'));model.disabled=true;return}const available=(catalogModels[prefix]||[]).filter(value=>modelProvider(value)===selectedProvider);for(const value of available)model.appendChild(new Option(value,value));if(preferredModel&&available.includes(preferredModel))model.value=preferredModel;model.disabled=available.length===0}
|
|
21115
|
+
function populateModelOptions(prefix,preferredModel=''){const provider=catalogField(prefix,'model-provider');const model=catalogField(prefix,'model');if(!provider||!model)return;const selectedProvider=provider.value;model.replaceChildren();if(!selectedProvider){model.appendChild(new Option(text('catalog.defaultModel'),'default'));model.disabled=true;populateVariantOptions(prefix);return}const available=(catalogModels[prefix]||[]).filter(value=>modelProvider(value)===selectedProvider);for(const value of available)model.appendChild(new Option(value,value));if(preferredModel&&available.includes(preferredModel))model.value=preferredModel;model.disabled=available.length===0;populateVariantOptions(prefix)}
|
|
21116
|
+
async function populateVariantOptions(prefix,preferredVariant=''){const cwd=catalogField(prefix,'cwd')?.value.trim()||'';const model=catalogField(prefix,'model');const variant=catalogField(prefix,'variant');if(!model||!variant)return;const selectedModel=model.value;const preferred=preferredVariant||(variant.dataset.preferredModel===selectedModel?variant.dataset.preferred||'':'');if(!cwd||!selectedModel||selectedModel==='default'){variant.replaceChildren(new Option(text('catalog.defaultVariant'),''));if(preferred)appendCurrentOption(variant,preferred);variant.value=preferred;variant.dataset.preferred='';variant.dataset.preferredModel='';variant.disabled=!preferred;return}if(!preferred){variant.replaceChildren(new Option(text('catalog.defaultVariant'),''));variant.value=''}const requestKey=prefix+'-variant';const request=(catalogRequests[requestKey]||0)+1;catalogRequests[requestKey]=request;variant.disabled=true;try{const data=await readJson(await fetch('/api/opencode/catalog?cwd='+encodeURIComponent(cwd)));if(catalogRequests[requestKey]!==request||catalogField(prefix,'cwd')?.value.trim()!==cwd||model.value!==selectedModel)return;const available=Array.isArray(data.variantsByModel?.[selectedModel])?data.variantsByModel[selectedModel]:[];variant.replaceChildren(new Option(text('catalog.defaultVariant'),''));for(const value of available)variant.appendChild(new Option(value,value));if(preferred)appendCurrentOption(variant,preferred);variant.value=[...variant.options].some(option=>option.value===preferred)?preferred:'';variant.dataset.preferred='';variant.dataset.preferredModel='';variant.disabled=available.length===0&&!preferred}catch(error){if(catalogRequests[requestKey]!==request||catalogField(prefix,'cwd')?.value.trim()!==cwd||model.value!==selectedModel)return;if(preferred)appendCurrentOption(variant,preferred);variant.value=preferred;variant.dataset.preferred=preferred;variant.dataset.preferredModel=selectedModel;variant.disabled=!preferred}}
|
|
20985
21117
|
async function loadCatalog(prefix,preferredAgent='',preferredModel='default',preserveUnavailable=false){const cwd=catalogField(prefix,'cwd')?.value.trim()||'';const status=catalogField(prefix,'catalog-status');const agent=catalogField(prefix,'agent');const provider=catalogField(prefix,'model-provider');const model=catalogField(prefix,'model');if(!cwd||!status||!agent||!provider||!model){if(!cwd)resetCatalog(prefix);return}const request=(catalogRequests[prefix]||0)+1;catalogRequests[prefix]=request;status.dataset.state='loading';status.textContent=text('catalog.loading');agent.disabled=true;provider.disabled=true;model.disabled=true;try{const data=await readJson(await fetch('/api/opencode/catalog?cwd='+encodeURIComponent(cwd)));if(catalogRequests[prefix]!==request||catalogField(prefix,'cwd').value.trim()!==cwd)return;agent.replaceChildren();for(const item of data.agents){const label=item.name+' \u2014 '+text('catalog.'+item.mode);agent.appendChild(new Option(label,item.name))}if(preserveUnavailable)appendCurrentOption(agent,preferredAgent);const defaultAgent=preferredAgent||data.agents.find(item=>item.name==='build')?.name||data.agents.find(item=>item.mode==='primary')?.name||data.agents[0]?.name||'';agent.value=[...agent.options].some(option=>option.value===defaultAgent)?defaultAgent:(agent.options[0]?.value||'');catalogModels[prefix]=[...data.models];if(preserveUnavailable&&preferredModel&&preferredModel!=='default'&&!catalogModels[prefix].includes(preferredModel))catalogModels[prefix].push(preferredModel);provider.replaceChildren(new Option(text('catalog.defaultProvider'),''));for(const name of [...new Set(catalogModels[prefix].map(modelProvider).filter(Boolean))].sort())provider.appendChild(new Option(name,name));const preferredProvider=preferredModel==='default'?'':modelProvider(preferredModel);provider.value=[...provider.options].some(option=>option.value===preferredProvider)?preferredProvider:'';populateModelOptions(prefix,preferredModel);status.dataset.state='ready';status.textContent=text('catalog.loaded',{agents:data.agents.length,models:data.models.length})}catch(error){if(catalogRequests[prefix]!==request)return;resetCatalog(prefix);if(preserveUnavailable){appendCurrentOption(agent,preferredAgent);if(preferredModel&&preferredModel!=='default'){catalogModels[prefix]=[preferredModel];appendCurrentOption(provider,modelProvider(preferredModel));provider.value=modelProvider(preferredModel);populateModelOptions(prefix,preferredModel)}}status.dataset.state='error';status.textContent=text('catalog.failed',{error:error.message})}finally{if(catalogRequests[prefix]===request){agent.disabled=false;provider.disabled=false;if(provider.value)model.disabled=false}}}
|
|
20986
|
-
function scheduleCatalogLoad(prefix){
|
|
21118
|
+
function scheduleCatalogLoad(prefix){invalidateCatalogRequests(prefix);resetCatalog(prefix);catalogTimers[prefix]=setTimeout(()=>loadCatalog(prefix),450)}
|
|
20987
21119
|
let directoryTargetId='';let directoryCurrent='';let directoryEntries=[];let directoryShowHidden=false;
|
|
20988
21120
|
function renderDirectoryEntries(){const list=document.getElementById('directory-list');list.replaceChildren();const entries=directoryEntries.filter(entry=>directoryShowHidden||!entry.hidden);const hidden=document.getElementById('directory-hidden');hidden.textContent=text(directoryShowHidden?'action.hideHidden':'action.showHidden');if(entries.length===0){const empty=document.createElement('div');empty.className='directory-empty';empty.textContent=text('directory.empty');list.appendChild(empty);return}for(const entry of entries){const button=document.createElement('button');button.type='button';button.className='directory-item';button.innerHTML='${icon("folder")}<span></span>';button.querySelector('span').textContent=entry.name;button.onclick=()=>browseDirectory(entry.path);list.appendChild(button)}}
|
|
20989
21121
|
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}}
|
|
@@ -20993,16 +21125,16 @@ function renderLayout(options) {
|
|
|
20993
21125
|
function updateDurationControl(id){const preset=document.getElementById(id+'-preset');const custom=document.getElementById(id+'-custom');const input=document.getElementById(id+'-value');const visible=preset.value==='custom';custom.hidden=!visible;input.required=visible;if(visible&&!input.value)input.value='1'}
|
|
20994
21126
|
function readDuration(id){const preset=document.getElementById(id+'-preset').value;if(preset==='')return '';if(preset!=='custom')return preset==='0'?'0':preset+'ms';const value=document.getElementById(id+'-value').value.trim();return value===''?'':value+document.getElementById(id+'-unit').value}
|
|
20995
21127
|
function setDuration(id,milliseconds){const preset=document.getElementById(id+'-preset');const exact=milliseconds==null?'':String(milliseconds);if([...preset.options].some(option=>option.value===exact)){preset.value=exact;updateDurationControl(id);return}preset.value='custom';const input=document.getElementById(id+'-value');const unit=document.getElementById(id+'-unit');const units=[['d',86400000],['h',3600000],['min',60000],['s',1000]];let matched=false;for(const [name,factor] of units){if(milliseconds!=null&&(milliseconds===0||milliseconds%factor===0)){input.value=String(milliseconds/factor);unit.value=name;matched=true;break}}if(!matched){input.value=String((milliseconds??60000)/1000);unit.value='s'}updateDurationControl(id)}
|
|
20996
|
-
function openTaskCreator(){const form=document.getElementById('task-form');form.reset();taskField('id').value='';taskField('cwd').readOnly=false;taskField('cwd-picker').hidden=false;taskField('cwd').value=form.dataset.defaultCwd||'';setDuration('task-retry-backoff',30000);setDuration('task-timeout',null);taskField('dialog-title').textContent=text('task.createTitle');taskField('save').textContent=text('action.saveTask');updateTaskProjectStatus();resetCatalog('task');document.getElementById('task-dialog').showModal();if(taskField('cwd').value)loadCatalog('task');setTimeout(()=>taskField('name').focus(),50)}
|
|
20997
|
-
async function openTaskEditor(id){try{const data=await readJson(await fetch('/api/tasks/'+id));taskField('id').value=String(id);taskField('cwd').value=data.cwd||'';taskField('cwd').readOnly=true;taskField('cwd-picker').hidden=true;taskField('name').value=data.name||'';taskField('prompt').value=data.prompt||'';taskField('category').value=data.category||'general';taskField('batch').value=data.batchId||'';taskField('importance').value=String(data.importance??3);taskField('urgency').value=String(data.urgency??3);taskField('max-retries').value=String(data.maxRetries??3);setDuration('task-retry-backoff',data.retryBackoffMs??30000);setDuration('task-timeout',data.timeoutMs);taskField('dialog-title').textContent=text('task.editTitle');taskField('save').textContent=text('action.updateTask');updateTaskProjectStatus();resetCatalog('task');document.getElementById('task-dialog').showModal();loadCatalog('task',data.agent||'',data.model||'default',true);setTimeout(()=>taskField('name').focus(),50)}catch(error){showToast(error.message,'error')}}
|
|
20998
|
-
async function saveTask(event){event.preventDefault();const form=document.getElementById('task-form');if(!form.reportValidity())return;const id=taskField('id').value;const body={name:taskField('name').value,cwd:taskField('cwd').value,agent:taskField('agent').value,model:taskField('model').value,prompt:taskField('prompt').value,category:taskField('category').value,batchId:taskField('batch').value,importance:Number(taskField('importance').value),urgency:Number(taskField('urgency').value),maxRetries:Number(taskField('max-retries').value),retryBackoff:readDuration('task-retry-backoff'),timeout:readDuration('task-timeout')};const button=taskField('save');button.disabled=true;try{const data=await readJson(await fetch(id?'/api/tasks/'+id:'/api/tasks',{method:id?'PUT':'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}));showToast(text(id?'feedback.taskUpdated':'feedback.taskCreated',{id:data.task.id}));document.getElementById('task-dialog').close();setTimeout(()=>location.assign(id?location.href:'/?cwd='+encodeURIComponent(data.task.cwd||'')),450)}catch(error){showToast(error.message,'error')}finally{button.disabled=false}}
|
|
21128
|
+
function openTaskCreator(){invalidateCatalogRequests('task');const form=document.getElementById('task-form');form.reset();taskField('id').value='';setPreferredVariant('task','default','');taskField('cwd').readOnly=false;taskField('cwd-picker').hidden=false;taskField('cwd').value=form.dataset.defaultCwd||'';setDuration('task-retry-backoff',30000);setDuration('task-timeout',null);taskField('dialog-title').textContent=text('task.createTitle');taskField('save').textContent=text('action.saveTask');updateTaskProjectStatus();resetCatalog('task');document.getElementById('task-dialog').showModal();if(taskField('cwd').value)loadCatalog('task');setTimeout(()=>taskField('name').focus(),50)}
|
|
21129
|
+
async function openTaskEditor(id){invalidateCatalogRequests('task');try{const data=await readJson(await fetch('/api/tasks/'+id));document.getElementById('task-form').reset();taskField('id').value=String(id);taskField('cwd').value=data.cwd||'';taskField('cwd').readOnly=true;taskField('cwd-picker').hidden=true;taskField('name').value=data.name||'';taskField('prompt').value=data.prompt||'';taskField('category').value=data.category||'general';taskField('batch').value=data.batchId||'';taskField('importance').value=String(data.importance??3);taskField('urgency').value=String(data.urgency??3);taskField('max-retries').value=String(data.maxRetries??3);setDuration('task-retry-backoff',data.retryBackoffMs??30000);setDuration('task-timeout',data.timeoutMs);taskField('dialog-title').textContent=text('task.editTitle');taskField('save').textContent=text('action.updateTask');updateTaskProjectStatus();setPreferredVariant('task',data.model||'default',data.variant||'');resetCatalog('task');document.getElementById('task-dialog').showModal();loadCatalog('task',data.agent||'',data.model||'default',true);setTimeout(()=>taskField('name').focus(),50)}catch(error){showToast(error.message,'error')}}
|
|
21130
|
+
async function saveTask(event){event.preventDefault();const form=document.getElementById('task-form');if(!form.reportValidity())return;const id=taskField('id').value;const body={name:taskField('name').value,cwd:taskField('cwd').value,agent:taskField('agent').value,model:taskField('model').value,variant:taskField('variant').value,prompt:taskField('prompt').value,category:taskField('category').value,batchId:taskField('batch').value,importance:Number(taskField('importance').value),urgency:Number(taskField('urgency').value),maxRetries:Number(taskField('max-retries').value),retryBackoff:readDuration('task-retry-backoff'),timeout:readDuration('task-timeout')};const button=taskField('save');button.disabled=true;try{const data=await readJson(await fetch(id?'/api/tasks/'+id:'/api/tasks',{method:id?'PUT':'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}));showToast(text(id?'feedback.taskUpdated':'feedback.taskCreated',{id:data.task.id}));document.getElementById('task-dialog').close();setTimeout(()=>location.assign(id?location.href:'/?cwd='+encodeURIComponent(data.task.cwd||'')),450)}catch(error){showToast(error.message,'error')}finally{button.disabled=false}}
|
|
20999
21131
|
function localDateTime(milliseconds){const date=new Date(milliseconds);const local=new Date(milliseconds-date.getTimezoneOffset()*60000);return local.toISOString().slice(0,23)}
|
|
21000
21132
|
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')}}
|
|
21001
21133
|
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}
|
|
21002
21134
|
function selectedRunAt(){const input=templateField('run-at');return resolveEditedRunAt(input.dataset.originalEpoch?Number(input.dataset.originalEpoch):null,input.dataset.originalLocal||'',input.value)}
|
|
21003
|
-
function openTemplateCreator(){const form=document.getElementById('template-form');form.reset();templateField('id').value='';templateField('dialog-title').textContent=text('template.createTitle');setDuration('template-interval',3600000);setDuration('template-retry-backoff',30000);setDuration('template-timeout',null);setOriginalRunAt(null);templateField('run-at').value=localDateTime(Date.now()+3600000);updateTemplateScheduleFields();resetCatalog('template');document.getElementById('template-dialog').showModal();if(templateField('cwd').value)loadCatalog('template');setTimeout(()=>templateField('name').focus(),50)}
|
|
21004
|
-
async function openTemplateEditor(id){try{const data=await readJson(await fetch('/api/templates/'+id));templateField('id').value=String(id);templateField('dialog-title').textContent=text('template.editTitle');templateField('name').value=data.name||'';templateField('cwd').value=data.cwd||'';templateField('prompt').value=data.prompt||'';templateField('schedule-type').value=data.scheduleType;templateField('cron').value=data.cronExpr||'';setDuration('template-interval',data.intervalMs);setOriginalRunAt(data.runAt||null);if(!data.runAt)templateField('run-at').value=localDateTime(Date.now()+3600000);templateField('category').value=data.category||'general';templateField('batch').value=data.batchId||'';templateField('importance').value=String(data.importance??3);templateField('urgency').value=String(data.urgency??3);templateField('max-instances').value=String(data.maxInstances??1);templateField('max-retries').value=String(data.maxRetries??3);setDuration('template-retry-backoff',data.retryBackoffMs??30000);setDuration('template-timeout',data.timeoutMs);updateTemplateScheduleFields();resetCatalog('template');document.getElementById('template-dialog').showModal();loadCatalog('template',data.agent||'',data.model||'default',true);setTimeout(()=>templateField('name').focus(),50)}catch(error){showToast(error.message,'error')}}
|
|
21005
|
-
async function saveTemplate(event){event.preventDefault();const form=document.getElementById('template-form');if(!form.reportValidity())return;const id=templateField('id').value;const type=templateField('schedule-type').value;const body={name:templateField('name').value,cwd:templateField('cwd').value,agent:templateField('agent').value,model:templateField('model').value,prompt:templateField('prompt').value,scheduleType:type,cronExpr:templateField('cron').value,interval:readDuration('template-interval'),runAt:type==='delayed'?selectedRunAt():null,category:templateField('category').value,batchId:templateField('batch').value,importance:Number(templateField('importance').value),urgency:Number(templateField('urgency').value),maxInstances:Number(templateField('max-instances').value),maxRetries:Number(templateField('max-retries').value),retryBackoff:readDuration('template-retry-backoff'),timeout:readDuration('template-timeout')};const button=templateField('save');button.disabled=true;try{await readJson(await fetch(id?'/api/templates/'+id:'/api/templates',{method:id?'PUT':'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}));showToast(text(id?'feedback.templateUpdated':'feedback.templateCreated'));document.getElementById('template-dialog').close();setTimeout(()=>location.assign(id?location.href:'/templates'),450)}catch(error){showToast(error.message,'error')}finally{button.disabled=false}}
|
|
21135
|
+
function openTemplateCreator(){invalidateCatalogRequests('template');const form=document.getElementById('template-form');form.reset();templateField('id').value='';setPreferredVariant('template','default','');templateField('dialog-title').textContent=text('template.createTitle');setDuration('template-interval',3600000);setDuration('template-retry-backoff',30000);setDuration('template-timeout',null);setOriginalRunAt(null);templateField('run-at').value=localDateTime(Date.now()+3600000);updateTemplateScheduleFields();resetCatalog('template');document.getElementById('template-dialog').showModal();if(templateField('cwd').value)loadCatalog('template');setTimeout(()=>templateField('name').focus(),50)}
|
|
21136
|
+
async function openTemplateEditor(id){invalidateCatalogRequests('template');try{const data=await readJson(await fetch('/api/templates/'+id));document.getElementById('template-form').reset();templateField('id').value=String(id);templateField('dialog-title').textContent=text('template.editTitle');templateField('name').value=data.name||'';templateField('cwd').value=data.cwd||'';templateField('prompt').value=data.prompt||'';templateField('schedule-type').value=data.scheduleType;templateField('cron').value=data.cronExpr||'';setDuration('template-interval',data.intervalMs);setOriginalRunAt(data.runAt||null);if(!data.runAt)templateField('run-at').value=localDateTime(Date.now()+3600000);templateField('category').value=data.category||'general';templateField('batch').value=data.batchId||'';templateField('importance').value=String(data.importance??3);templateField('urgency').value=String(data.urgency??3);templateField('max-instances').value=String(data.maxInstances??1);templateField('max-retries').value=String(data.maxRetries??3);setDuration('template-retry-backoff',data.retryBackoffMs??30000);setDuration('template-timeout',data.timeoutMs);updateTemplateScheduleFields();setPreferredVariant('template',data.model||'default',data.variant||'');resetCatalog('template');document.getElementById('template-dialog').showModal();loadCatalog('template',data.agent||'',data.model||'default',true);setTimeout(()=>templateField('name').focus(),50)}catch(error){showToast(error.message,'error')}}
|
|
21137
|
+
async function saveTemplate(event){event.preventDefault();const form=document.getElementById('template-form');if(!form.reportValidity())return;const id=templateField('id').value;const type=templateField('schedule-type').value;const body={name:templateField('name').value,cwd:templateField('cwd').value,agent:templateField('agent').value,model:templateField('model').value,variant:templateField('variant').value,prompt:templateField('prompt').value,scheduleType:type,cronExpr:templateField('cron').value,interval:readDuration('template-interval'),runAt:type==='delayed'?selectedRunAt():null,category:templateField('category').value,batchId:templateField('batch').value,importance:Number(templateField('importance').value),urgency:Number(templateField('urgency').value),maxInstances:Number(templateField('max-instances').value),maxRetries:Number(templateField('max-retries').value),retryBackoff:readDuration('template-retry-backoff'),timeout:readDuration('template-timeout')};const button=templateField('save');button.disabled=true;try{await readJson(await fetch(id?'/api/templates/'+id:'/api/templates',{method:id?'PUT':'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}));showToast(text(id?'feedback.templateUpdated':'feedback.templateCreated'));document.getElementById('template-dialog').close();setTimeout(()=>location.assign(id?location.href:'/templates'),450)}catch(error){showToast(error.message,'error')}finally{button.disabled=false}}
|
|
21006
21138
|
async function enableTmpl(id){try{await readJson(await fetch('/api/templates/'+id+'/enable',{method:'POST'}));location.reload()}catch(error){showToast(error.message,'error')}}
|
|
21007
21139
|
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')}}
|
|
21008
21140
|
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')}}
|
|
@@ -21184,6 +21316,7 @@ var init_ui = __esm({
|
|
|
21184
21316
|
"template.cwdHint": "OpenCode \u4F1A\u5728\u8FD9\u4E2A\u76EE\u5F55\u4E2D\u6267\u884C\u4EFB\u52A1\u3002",
|
|
21185
21317
|
"template.agent": "Agent",
|
|
21186
21318
|
"template.model": "\u6A21\u578B",
|
|
21319
|
+
"template.variant": "\u6A21\u578B Variant",
|
|
21187
21320
|
"template.prompt": "\u63D0\u793A\u8BCD",
|
|
21188
21321
|
"template.scheduleType": "\u6267\u884C\u65B9\u5F0F",
|
|
21189
21322
|
"template.cronExpr": "Cron \u8868\u8FBE\u5F0F",
|
|
@@ -21221,9 +21354,11 @@ var init_ui = __esm({
|
|
|
21221
21354
|
"catalog.chooseProject": "\u8BF7\u5148\u9009\u62E9\u9879\u76EE\u76EE\u5F55",
|
|
21222
21355
|
"catalog.defaultModel": "\u8DDF\u968F Agent / OpenCode \u9ED8\u8BA4\u6A21\u578B",
|
|
21223
21356
|
"catalog.defaultProvider": "\u9ED8\u8BA4\u6A21\u578B",
|
|
21357
|
+
"catalog.defaultVariant": "\u8DDF\u968F Agent / \u6A21\u578B\u9ED8\u8BA4\u8BBE\u7F6E",
|
|
21224
21358
|
"catalog.provider": "\u6A21\u578B\u63D0\u4F9B\u5546",
|
|
21225
21359
|
"catalog.model": "\u5177\u4F53\u6A21\u578B",
|
|
21226
|
-
"catalog.modelHint": "\u5148\u9009\u63D0\u4F9B\u5546\uFF0C\u518D\u9009\u672C\u9879\u76EE opencode models \u8FD4\u56DE\u7684\u6A21\u578B\uFF1B\u9ED8\u8BA4\u9009\u9879\u4E0D\u4F1A\u4F20\u5165 -m\u3002",
|
|
21360
|
+
"catalog.modelHint": "\u5148\u9009\u63D0\u4F9B\u5546\uFF0C\u518D\u9009\u672C\u9879\u76EE opencode models --verbose \u8FD4\u56DE\u7684\u6A21\u578B\uFF1B\u9ED8\u8BA4\u9009\u9879\u4E0D\u4F1A\u4F20\u5165 -m\u3002",
|
|
21361
|
+
"catalog.variantHint": "\u4EC5\u663E\u793A\u6240\u9009\u6A21\u578B\u58F0\u660E\u652F\u6301\u7684 variants\uFF1B\u9ED8\u8BA4\u9009\u9879\u4E0D\u4F1A\u4F20\u5165 --variant\u3002",
|
|
21227
21362
|
"catalog.agentHint": "\u6765\u81EA\u5F53\u524D\u9879\u76EE\u7684 opencode agent list\u3002",
|
|
21228
21363
|
"catalog.loading": "\u6B63\u5728\u8BFB\u53D6\u6B64\u9879\u76EE\u53EF\u7528\u7684 Agent \u548C\u6A21\u578B\u2026",
|
|
21229
21364
|
"catalog.loaded": "\u5DF2\u4ECE\u672C\u673A OpenCode \u8BFB\u53D6 {agents} \u4E2A Agent\u3001{models} \u4E2A\u6A21\u578B\u3002",
|
|
@@ -21254,6 +21389,7 @@ var init_ui = __esm({
|
|
|
21254
21389
|
"details.copySuccess": "\u539F\u59CB\u6570\u636E\u5DF2\u590D\u5236",
|
|
21255
21390
|
"details.id": "\u7F16\u53F7",
|
|
21256
21391
|
"details.project": "\u9879\u76EE\u76EE\u5F55",
|
|
21392
|
+
"details.variant": "\u6A21\u578B Variant",
|
|
21257
21393
|
"details.prompt": "\u63D0\u793A\u8BCD",
|
|
21258
21394
|
"details.result": "\u6267\u884C\u7ED3\u679C / \u5931\u8D25\u539F\u56E0",
|
|
21259
21395
|
"details.category": "\u5206\u7C7B",
|
|
@@ -21485,6 +21621,7 @@ var init_ui = __esm({
|
|
|
21485
21621
|
"template.cwdHint": "OpenCode runs the task in this directory.",
|
|
21486
21622
|
"template.agent": "Agent",
|
|
21487
21623
|
"template.model": "Model",
|
|
21624
|
+
"template.variant": "Model variant",
|
|
21488
21625
|
"template.prompt": "Prompt",
|
|
21489
21626
|
"template.scheduleType": "Schedule",
|
|
21490
21627
|
"template.cronExpr": "Cron expression",
|
|
@@ -21522,9 +21659,11 @@ var init_ui = __esm({
|
|
|
21522
21659
|
"catalog.chooseProject": "Choose a project directory first",
|
|
21523
21660
|
"catalog.defaultModel": "Use the Agent / OpenCode default model",
|
|
21524
21661
|
"catalog.defaultProvider": "Default model",
|
|
21662
|
+
"catalog.defaultVariant": "Use the Agent / model default",
|
|
21525
21663
|
"catalog.provider": "Model provider",
|
|
21526
21664
|
"catalog.model": "Model",
|
|
21527
|
-
"catalog.modelHint": "Choose a provider, then a model returned by opencode models for this project. Default does not pass -m.",
|
|
21665
|
+
"catalog.modelHint": "Choose a provider, then a model returned by opencode models --verbose for this project. Default does not pass -m.",
|
|
21666
|
+
"catalog.variantHint": "Only variants declared by the selected model are shown. Default does not pass --variant.",
|
|
21528
21667
|
"catalog.agentHint": "Loaded from opencode agent list for this project.",
|
|
21529
21668
|
"catalog.loading": "Loading Agents and models available to this project\u2026",
|
|
21530
21669
|
"catalog.loaded": "Loaded {agents} Agents and {models} models from local OpenCode.",
|
|
@@ -21555,6 +21694,7 @@ var init_ui = __esm({
|
|
|
21555
21694
|
"details.copySuccess": "Raw data copied",
|
|
21556
21695
|
"details.id": "ID",
|
|
21557
21696
|
"details.project": "Project directory",
|
|
21697
|
+
"details.variant": "Model variant",
|
|
21558
21698
|
"details.prompt": "Prompt",
|
|
21559
21699
|
"details.result": "Result / failure reason",
|
|
21560
21700
|
"details.category": "Category",
|
|
@@ -22117,6 +22257,7 @@ function parseTaskPayload(value) {
|
|
|
22117
22257
|
cwd: requiredString("cwd"),
|
|
22118
22258
|
agent: requiredString("agent"),
|
|
22119
22259
|
model: optionalString("model", "default"),
|
|
22260
|
+
variant: Object.hasOwn(input, "variant") ? optionalString("variant") : void 0,
|
|
22120
22261
|
prompt: requiredString("prompt"),
|
|
22121
22262
|
category: optionalString("category", "general"),
|
|
22122
22263
|
batchId: optionalString("batchId"),
|
|
@@ -22132,6 +22273,7 @@ function editableTaskPayload(input) {
|
|
|
22132
22273
|
name: input.name,
|
|
22133
22274
|
agent: input.agent,
|
|
22134
22275
|
model: input.model ?? "default",
|
|
22276
|
+
...input.variant === void 0 ? {} : { variant: input.variant },
|
|
22135
22277
|
prompt: input.prompt,
|
|
22136
22278
|
category: input.category ?? "general",
|
|
22137
22279
|
batchId: input.batchId ?? null,
|
|
@@ -22187,6 +22329,7 @@ function parseTemplatePayload(value) {
|
|
|
22187
22329
|
name: requiredString("name"),
|
|
22188
22330
|
agent: requiredString("agent"),
|
|
22189
22331
|
model: optionalString("model", "default"),
|
|
22332
|
+
variant: Object.hasOwn(input, "variant") ? optionalString("variant") : void 0,
|
|
22190
22333
|
prompt: requiredString("prompt"),
|
|
22191
22334
|
cwd: requiredString("cwd"),
|
|
22192
22335
|
category: optionalString("category", "general"),
|
|
@@ -22520,7 +22663,7 @@ var init_web = __esm({
|
|
|
22520
22663
|
const latestRun = latestRuns.get(task.id);
|
|
22521
22664
|
const executionActive = latestRun?.status === "running";
|
|
22522
22665
|
const batchId = task.batchId?.trim() || null;
|
|
22523
|
-
const searchable = esc(`${task.name} ${task.agent} ${task.prompt} ${task.cwd ?? ""} ${task.batchId ?? ""} ${task.category ?? ""}`);
|
|
22666
|
+
const searchable = esc(`${task.name} ${task.agent} ${task.model ?? ""} ${task.variant ?? ""} ${task.prompt} ${task.cwd ?? ""} ${task.batchId ?? ""} ${task.category ?? ""}`);
|
|
22524
22667
|
return `<tr data-task-row data-search="${searchable}">
|
|
22525
22668
|
<td class="faint" data-label="${t(locale, "table.id")}">#${task.id}</td>
|
|
22526
22669
|
<td data-primary data-label="${t(locale, "table.task")}"><div class="task-name">${esc(task.name)}</div><div class="task-prompt" title="${esc(task.prompt)}">${esc(task.prompt.substring(0, 160))}</div>
|
|
@@ -22598,11 +22741,12 @@ var init_web = __esm({
|
|
|
22598
22741
|
<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>
|
|
22599
22742
|
<datalist id="task-cwd-options">${projects.map((project) => `<option value="${esc(project.cwd)}"></option>`).join("")}</datalist>
|
|
22600
22743
|
<label class="form-field"><span>${t(locale, "template.agent")}</span><select id="task-agent" required><option value="">${t(locale, "catalog.chooseProject")}</option></select><small>${t(locale, "catalog.agentHint")}</small></label>
|
|
22601
|
-
<label class="form-field"><span>${t(locale, "template.model")}</span><div class="model-selector"><select id="task-model-provider" aria-label="${t(locale, "catalog.provider")}" onchange="
|
|
22744
|
+
<label class="form-field"><span>${t(locale, "template.model")}</span><div class="model-selector"><select id="task-model-provider" aria-label="${t(locale, "catalog.provider")}" onchange="handleProviderChange('task')"><option value="">${t(locale, "catalog.defaultProvider")}</option></select><select id="task-model" required aria-label="${t(locale, "catalog.model")}" onchange="handleModelChange('task')" disabled><option value="default">${t(locale, "catalog.defaultModel")}</option></select></div><small>${t(locale, "catalog.modelHint")}</small></label>
|
|
22745
|
+
<label class="form-field"><span>${t(locale, "template.variant")}</span><select id="task-variant" onchange="handleVariantChange('task')" disabled><option value="">${t(locale, "catalog.defaultVariant")}</option></select><small>${t(locale, "catalog.variantHint")}</small></label>
|
|
22602
22746
|
<label class="form-field form-field-wide"><span>${t(locale, "template.prompt")}</span><textarea id="task-prompt" rows="6" required></textarea></label>
|
|
22603
22747
|
</div>
|
|
22604
22748
|
<p id="task-project-status" class="form-note"></p>
|
|
22605
|
-
<p id="task-catalog-status" class="form-note catalog-status"></p>
|
|
22749
|
+
<p id="task-catalog-status" class="form-note catalog-status" role="status" aria-live="polite"></p>
|
|
22606
22750
|
<details class="advanced-fields">
|
|
22607
22751
|
<summary>${t(locale, "template.advanced")}</summary>
|
|
22608
22752
|
<div class="template-form-grid">
|
|
@@ -22644,7 +22788,7 @@ var init_web = __esm({
|
|
|
22644
22788
|
return `<tr>
|
|
22645
22789
|
<td class="faint" data-label="${t(locale, "table.id")}">#${template.id}</td>
|
|
22646
22790
|
<td data-primary data-label="${t(locale, "table.name")}"><div class="task-name">${esc(template.name)}</div><div class="task-prompt" title="${esc(template.prompt)}">${esc(template.prompt.substring(0, 140))}</div>
|
|
22647
|
-
<div class="actions" style="margin-top:5px"><span class="tag">${esc(template.agent)}</span>${template.model && template.model !== "default" ? `<span class="tag">${esc(template.model)}</span>` : ""}</div></td>
|
|
22791
|
+
<div class="actions" style="margin-top:5px"><span class="tag">${esc(template.agent)}</span>${template.model && template.model !== "default" ? `<span class="tag">${esc(template.model)}</span>` : ""}${template.variant ? `<span class="tag">${esc(template.variant)}</span>` : ""}</div></td>
|
|
22648
22792
|
<td data-label="${t(locale, "table.type")}"><span class="tag t-${scheduleType}">${typeLabel}</span></td>
|
|
22649
22793
|
<td data-label="${t(locale, "table.rule")}" class="m small">${esc(rule)}</td>
|
|
22650
22794
|
<td data-label="${t(locale, "table.status")}"><span class="badge ${template.enabled ? "b-done" : "b-cancelled"}">${t(locale, template.enabled ? "schedule.enabled" : "schedule.disabled")}</span></td>
|
|
@@ -22674,14 +22818,15 @@ var init_web = __esm({
|
|
|
22674
22818
|
<label class="form-field"><span>${t(locale, "template.name")}</span><input id="template-name" required maxlength="200" autocomplete="off"></label>
|
|
22675
22819
|
<label class="form-field"><span>${t(locale, "template.cwd")}</span><div class="field-action"><input id="template-cwd" required autocomplete="off" placeholder="/path/to/project" oninput="scheduleCatalogLoad('template')"><button type="button" class="btn" onclick="openDirectoryPicker('template-cwd')">${icon("folder")}${t(locale, "action.chooseFolder")}</button></div><small>${t(locale, "template.cwdHint")}</small></label>
|
|
22676
22820
|
<label class="form-field"><span>${t(locale, "template.agent")}</span><select id="template-agent" required><option value="">${t(locale, "catalog.chooseProject")}</option></select><small>${t(locale, "catalog.agentHint")}</small></label>
|
|
22677
|
-
<label class="form-field"><span>${t(locale, "template.model")}</span><div class="model-selector"><select id="template-model-provider" aria-label="${t(locale, "catalog.provider")}" onchange="
|
|
22821
|
+
<label class="form-field"><span>${t(locale, "template.model")}</span><div class="model-selector"><select id="template-model-provider" aria-label="${t(locale, "catalog.provider")}" onchange="handleProviderChange('template')"><option value="">${t(locale, "catalog.defaultProvider")}</option></select><select id="template-model" required aria-label="${t(locale, "catalog.model")}" onchange="handleModelChange('template')" disabled><option value="default">${t(locale, "catalog.defaultModel")}</option></select></div><small>${t(locale, "catalog.modelHint")}</small></label>
|
|
22822
|
+
<label class="form-field"><span>${t(locale, "template.variant")}</span><select id="template-variant" onchange="handleVariantChange('template')" disabled><option value="">${t(locale, "catalog.defaultVariant")}</option></select><small>${t(locale, "catalog.variantHint")}</small></label>
|
|
22678
22823
|
<label class="form-field form-field-wide"><span>${t(locale, "template.prompt")}</span><textarea id="template-prompt" rows="6" required></textarea></label>
|
|
22679
22824
|
<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>
|
|
22680
22825
|
<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>
|
|
22681
22826
|
<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>
|
|
22682
22827
|
<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>
|
|
22683
22828
|
</div>
|
|
22684
|
-
<p id="template-catalog-status" class="form-note catalog-status"></p>
|
|
22829
|
+
<p id="template-catalog-status" class="form-note catalog-status" role="status" aria-live="polite"></p>
|
|
22685
22830
|
<details class="advanced-fields">
|
|
22686
22831
|
<summary>${t(locale, "template.advanced")}</summary>
|
|
22687
22832
|
<div class="template-form-grid">
|
|
@@ -22715,6 +22860,7 @@ var init_web = __esm({
|
|
|
22715
22860
|
taskId: taskRuns4.taskId,
|
|
22716
22861
|
sessionId: taskRuns4.sessionId,
|
|
22717
22862
|
model: taskRuns4.model,
|
|
22863
|
+
variant: taskRuns4.variant,
|
|
22718
22864
|
status: taskRuns4.status,
|
|
22719
22865
|
startedAt: taskRuns4.startedAt,
|
|
22720
22866
|
finishedAt: taskRuns4.finishedAt,
|
|
@@ -22735,7 +22881,7 @@ var init_web = __esm({
|
|
|
22735
22881
|
const log = run.log ? renderRunLog(run.id, run.taskName, run.log, locale, run.status !== "done") : "";
|
|
22736
22882
|
return `<tr class="run-summary-row">
|
|
22737
22883
|
<td class="faint" data-label="${t(locale, "table.run")}">#${run.id}</td>
|
|
22738
|
-
<td data-primary data-label="${t(locale, "table.task")}"><div class="task-name">${esc(run.taskName)} <span class="faint">#${run.taskId}</span></div>${run.model ? `<div style="margin-top:4px"
|
|
22884
|
+
<td data-primary data-label="${t(locale, "table.task")}"><div class="task-name">${esc(run.taskName)} <span class="faint">#${run.taskId}</span></div>${run.model || run.variant ? `<div class="actions" style="margin-top:4px">${run.model ? `<span class="tag">${esc(run.model)}</span>` : ""}${run.variant ? `<span class="tag">${esc(run.variant)}</span>` : ""}</div>` : ""}</td>
|
|
22739
22885
|
<td data-label="${t(locale, "table.agent")}"><span class="tag">${esc(run.taskAgent)}</span></td>
|
|
22740
22886
|
<td data-label="${t(locale, "table.session")}" class="m small">${esc(maskSessionId(run.sessionId))}</td>
|
|
22741
22887
|
<td data-label="${t(locale, "table.status")}"><span class="badge b-${status}">${runStatusText(locale, run.status ?? "unknown")}</span></td>
|
|
@@ -22785,7 +22931,7 @@ var init_web = __esm({
|
|
|
22785
22931
|
const runRows = runningRuns.map((run) => {
|
|
22786
22932
|
const session = maskSessionId(run.sessionId);
|
|
22787
22933
|
return `<tr><td class="faint" data-label="${t(locale, "table.run")}">#${run.id}</td><td data-primary data-label="${t(locale, "table.task")}">#${run.taskId}</td><td data-label="${t(locale, "table.session")}" class="m small">${esc(session)}</td>
|
|
22788
|
-
<td data-label="${t(locale, "table.model")}" class="small">${esc(run.model) || "\u2014"}</td><td data-label="${t(locale, "table.startedAt")}" class="small">${formatDateTime(run.startedAt, locale)}</td>
|
|
22934
|
+
<td data-label="${t(locale, "table.model")}" class="small">${esc(run.model) || "\u2014"}${run.variant ? ` \xB7 ${esc(run.variant)}` : ""}</td><td data-label="${t(locale, "table.startedAt")}" class="small">${formatDateTime(run.startedAt, locale)}</td>
|
|
22789
22935
|
<td data-label="${t(locale, "table.heartbeat")}" class="small muted">${formatRelative(run.heartbeatAt, locale)}</td><td data-label="${t(locale, "table.pid")}" class="m small">W:${run.workerPid ?? "\u2014"} C:${run.childPid ?? "\u2014"}</td>
|
|
22790
22936
|
<td data-label="${t(locale, "table.duration")}" class="small">${formatDuration(run.startedAt, null)}</td></tr>`;
|
|
22791
22937
|
}).join("");
|
|
@@ -23211,6 +23357,7 @@ var WorkerEngine = class {
|
|
|
23211
23357
|
const run = await TaskRunService.create({
|
|
23212
23358
|
taskId: task.id,
|
|
23213
23359
|
model: this.resolveModel(task.model),
|
|
23360
|
+
variant: this.resolveVariant(task.variant),
|
|
23214
23361
|
status: "running",
|
|
23215
23362
|
workerPid: process.pid,
|
|
23216
23363
|
lockedAt: Date.now(),
|
|
@@ -23273,8 +23420,10 @@ var WorkerEngine = class {
|
|
|
23273
23420
|
}
|
|
23274
23421
|
async spawnTask(task, runId, launchIdentity) {
|
|
23275
23422
|
const model = this.resolveModel(task.model);
|
|
23423
|
+
const variant = this.resolveVariant(task.variant);
|
|
23276
23424
|
const args = ["run", "--agent", task.agent, "--format", "json"];
|
|
23277
23425
|
if (model) args.push("-m", model);
|
|
23426
|
+
if (variant) args.push("--variant", variant);
|
|
23278
23427
|
args.push(task.prompt);
|
|
23279
23428
|
const cwd = task.cwd || process.cwd();
|
|
23280
23429
|
const child = spawn(process.execPath, [
|
|
@@ -23433,7 +23582,7 @@ var WorkerEngine = class {
|
|
|
23433
23582
|
);
|
|
23434
23583
|
return;
|
|
23435
23584
|
}
|
|
23436
|
-
const failure = code === 0 ? void 0 : `${spawnError ? "\u65E0\u6CD5\u542F\u52A8 opencode" : "opencode \u9000\u51FA\u7801"} ${spawnError?.message ?? code ?? "null"}${signal ? `\uFF0C\u4FE1\u53F7 ${signal}` : ""}\uFF08agent=${entry.task.agent}\uFF0Cmodel=${this.resolveModel(entry.task.model) ?? "Agent/\u9ED8\u8BA4\u914D\u7F6E"}\uFF0Ccwd=${entry.task.cwd ?? process.cwd()}\uFF09`;
|
|
23585
|
+
const failure = code === 0 ? void 0 : `${spawnError ? "\u65E0\u6CD5\u542F\u52A8 opencode" : "opencode \u9000\u51FA\u7801"} ${spawnError?.message ?? code ?? "null"}${signal ? `\uFF0C\u4FE1\u53F7 ${signal}` : ""}\uFF08agent=${entry.task.agent}\uFF0Cmodel=${this.resolveModel(entry.task.model) ?? "Agent/\u9ED8\u8BA4\u914D\u7F6E"}\uFF0Cvariant=${this.resolveVariant(entry.task.variant) ?? "Agent/\u6A21\u578B\u9ED8\u8BA4\u914D\u7F6E"}\uFF0Ccwd=${entry.task.cwd ?? process.cwd()}\uFF09`;
|
|
23437
23586
|
this.runDetached(
|
|
23438
23587
|
this.settleEntry(entry, code, failure),
|
|
23439
23588
|
"task settlement failed",
|
|
@@ -23622,6 +23771,9 @@ ${output}` : ""}`;
|
|
|
23622
23771
|
if (!taskModel || taskModel === "default") return null;
|
|
23623
23772
|
return taskModel;
|
|
23624
23773
|
}
|
|
23774
|
+
resolveVariant(taskVariant) {
|
|
23775
|
+
return taskVariant?.trim() || null;
|
|
23776
|
+
}
|
|
23625
23777
|
runDetached(operation, message, taskId) {
|
|
23626
23778
|
operation.catch((error) => {
|
|
23627
23779
|
markGatewayFailure("worker", error);
|