@linxin666/dsh-client-ui-task-board 0.4.5 → 0.4.6
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/README.i18n.yaml +2 -2
- package/README.md +20 -12
- package/README.zh.md +20 -12
- package/lib/client.js +1327 -229
- package/lib/client.js.map +1 -1
- package/lib/index.js +1909 -348
- package/lib/types/client/TaskBoardSettingsCard.d.ts +12 -0
- package/lib/types/client/index.d.ts +4 -5
- package/lib/types/client/locales.d.ts +65 -0
- package/lib/types/client/plugin-card-seat.d.ts +5 -0
- package/lib/types/client/schedule-zone.d.ts +50 -0
- package/lib/types/core/controller.d.ts +10 -11
- package/lib/types/core/poll-cadence.d.ts +31 -0
- package/lib/types/core/tasks.d.ts +144 -14
- package/lib/types/core/use-cases/task-schedule.d.ts +68 -10
- package/lib/types/core/verification-budget.d.ts +52 -0
- package/lib/types/core/verification.d.ts +376 -9
- package/lib/types/host/verification-gate.d.ts +24 -0
- package/lib/types/host/verification-runner.d.ts +38 -7
- package/lib/types/host-ledger.d.ts +82 -7
- package/lib/types/host-runner.d.ts +32 -9
- package/lib/types/host-service.d.ts +117 -9
- package/lib/types/index.d.ts +54 -0
- package/lib/types/protocol.d.ts +50 -12
- package/package.json +2 -6
- package/src/client/TaskBoardSettingsCard.tsx +74 -1
- package/src/client/board/NewTaskModal.tsx +151 -20
- package/src/client/board/TaskCard.tsx +3 -3
- package/src/client/board/TaskDetail.tsx +219 -18
- package/src/client/board/VerificationReport.tsx +132 -13
- package/src/client/board/status-key.ts +3 -0
- package/src/client/index.ts +43 -50
- package/src/client/locales.ts +137 -4
- package/src/client/plugin-card-seat.ts +7 -0
- package/src/client/schedule-zone.ts +100 -2
- package/src/core/controller.ts +12 -8
- package/src/core/poll-cadence.ts +41 -0
- package/src/core/store.ts +64 -15
- package/src/core/tasks.ts +193 -39
- package/src/core/use-cases/task-create.ts +30 -9
- package/src/core/use-cases/task-schedule.ts +190 -25
- package/src/core/use-cases/task-update.ts +3 -3
- package/src/core/verification-budget.ts +115 -0
- package/src/core/verification.ts +785 -17
- package/src/host/agent-tools.ts +106 -21
- package/src/host/verification-gate.ts +172 -16
- package/src/host/verification-runner.ts +207 -40
- package/src/host-ledger.ts +328 -42
- package/src/host-runner.ts +52 -19
- package/src/host-service.ts +299 -36
- package/src/index.ts +101 -5
- package/src/protocol.ts +132 -28
- package/lib/invariant.js +0 -6
- package/lib/types/client/board-card-seat.d.ts +0 -34
- package/lib/types/invariant.d.ts +0 -3
- package/src/client/board-card-seat.ts +0 -102
- package/src/invariant.ts +0 -4
package/lib/client.js
CHANGED
|
@@ -78,6 +78,28 @@ window.__ModuleLoader__.load({
|
|
|
78
78
|
}
|
|
79
79
|
return Object.keys(result).length === 0 ? void 0 : result;
|
|
80
80
|
}
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/core/tasks.ts
|
|
83
|
+
/** Every stop reason this build understands; the repair and wire gates share it. */
|
|
84
|
+
const SCHEDULE_STOP_REASONS = [
|
|
85
|
+
"fired",
|
|
86
|
+
"limit",
|
|
87
|
+
"no-target",
|
|
88
|
+
"missed",
|
|
89
|
+
"busy",
|
|
90
|
+
"permission",
|
|
91
|
+
"launch-failed"
|
|
92
|
+
];
|
|
93
|
+
/**
|
|
94
|
+
* The rule's total run budget: one for a one-shot, the stored cap for a
|
|
95
|
+
* recurring rule, and undefined when the rule is unlimited.
|
|
96
|
+
* @param rule - the schedule rule.
|
|
97
|
+
* @returns the budget, or undefined for an uncapped rule.
|
|
98
|
+
*/
|
|
99
|
+
function scheduleRunBudget(rule) {
|
|
100
|
+
if (rule.mode === "once") return 1;
|
|
101
|
+
return rule.maxRuns;
|
|
102
|
+
}
|
|
81
103
|
/**
|
|
82
104
|
* Repair a persisted tag list: keep the well-formed entries, trim, drop
|
|
83
105
|
* blanks and repeats, cap the count, and collapse a blank prompt line to
|
|
@@ -274,7 +296,7 @@ window.__ModuleLoader__.load({
|
|
|
274
296
|
model: normalizeTargetId(input.model),
|
|
275
297
|
reuseSession: input.reuseSession === true ? true : void 0,
|
|
276
298
|
teamRun: input.teamRun === true ? true : void 0,
|
|
277
|
-
goalRun: input.goalRun ===
|
|
299
|
+
goalRun: input.goalRun === true ? true : void 0,
|
|
278
300
|
skipVerification: input.skipVerification === true ? true : void 0,
|
|
279
301
|
...input.freeze === void 0 ? {} : { freeze: freezeOf(input.freeze, now) },
|
|
280
302
|
...input.handover === void 0 ? {} : { handover: {
|
|
@@ -294,27 +316,47 @@ window.__ModuleLoader__.load({
|
|
|
294
316
|
updatedAt: now
|
|
295
317
|
};
|
|
296
318
|
}
|
|
319
|
+
/** Every field a schedule patch may carry; the rest of the rule is carried over. */
|
|
320
|
+
const SCHEDULE_PATCH_KEYS = [
|
|
321
|
+
"enabled",
|
|
322
|
+
"mode",
|
|
323
|
+
"cron",
|
|
324
|
+
"at",
|
|
325
|
+
"timeZone",
|
|
326
|
+
"nextRunAt",
|
|
327
|
+
"lastTriggeredAt",
|
|
328
|
+
"runCount",
|
|
329
|
+
"maxRuns",
|
|
330
|
+
"endedAt",
|
|
331
|
+
"endedReason",
|
|
332
|
+
"skippedAt",
|
|
333
|
+
"skippedReason"
|
|
334
|
+
];
|
|
297
335
|
/**
|
|
298
336
|
* Merge a schedule patch into a task's schedule rule (creating it when
|
|
299
337
|
* absent), with a fresh updatedAt. Keys present in the patch overwrite the
|
|
300
338
|
* current value — including explicit `undefined`, which clears a field (used
|
|
301
|
-
* to disarm `nextRunAt`); absent keys keep
|
|
339
|
+
* to disarm `nextRunAt` or to drop an ended/skip record); absent keys keep
|
|
340
|
+
* their current value.
|
|
302
341
|
*/
|
|
303
342
|
function withSchedule(task, patch, now) {
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
343
|
+
const schedule = task.schedule === void 0 ? {
|
|
344
|
+
enabled: false,
|
|
345
|
+
mode: "cron",
|
|
346
|
+
nextRunAt: void 0,
|
|
347
|
+
lastTriggeredAt: void 0,
|
|
348
|
+
runCount: 0
|
|
349
|
+
} : { ...task.schedule };
|
|
350
|
+
const fields = schedule;
|
|
351
|
+
const next = patch;
|
|
352
|
+
for (const key of SCHEDULE_PATCH_KEYS) {
|
|
353
|
+
if (!(key in patch)) continue;
|
|
354
|
+
if (next[key] === void 0) delete fields[key];
|
|
355
|
+
else fields[key] = next[key];
|
|
356
|
+
}
|
|
357
|
+
if (schedule.enabled !== true) schedule.enabled = false;
|
|
358
|
+
if (schedule.mode !== "once") schedule.mode = "cron";
|
|
359
|
+
if (!Number.isFinite(schedule.runCount) || schedule.runCount < 0) schedule.runCount = 0;
|
|
318
360
|
return {
|
|
319
361
|
...task,
|
|
320
362
|
updatedAt: now,
|
|
@@ -889,21 +931,49 @@ window.__ModuleLoader__.load({
|
|
|
889
931
|
model: input.model ?? parent.model
|
|
890
932
|
}, now, id);
|
|
891
933
|
const requested = input.schedule;
|
|
892
|
-
if (requested?.enabled === true
|
|
893
|
-
const cron = requested.cron.trim();
|
|
934
|
+
if (requested?.enabled === true) {
|
|
894
935
|
const requestedZone = requested.timeZone;
|
|
895
936
|
if (requestedZone !== void 0 && !isValidTimeZone(requestedZone)) return {
|
|
896
937
|
task: void 0,
|
|
897
938
|
tasks,
|
|
898
939
|
error: "invalid schedule time zone"
|
|
899
940
|
};
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
941
|
+
if (requested.mode === "once") {
|
|
942
|
+
const at = requested.at;
|
|
943
|
+
if (at === void 0 || !Number.isInteger(at) || at <= now) return {
|
|
944
|
+
task: void 0,
|
|
945
|
+
tasks,
|
|
946
|
+
error: "invalid schedule instant"
|
|
947
|
+
};
|
|
948
|
+
task = withSchedule(task, {
|
|
949
|
+
enabled: true,
|
|
950
|
+
mode: "once",
|
|
951
|
+
at,
|
|
952
|
+
timeZone: requestedZone,
|
|
953
|
+
nextRunAt: at,
|
|
954
|
+
runCount: 0
|
|
955
|
+
}, now);
|
|
956
|
+
} else {
|
|
957
|
+
const cron = (requested.cron ?? "").trim();
|
|
958
|
+
if (cron !== "" && isValidCron(cron)) {
|
|
959
|
+
const maxRuns = requested.maxRuns;
|
|
960
|
+
if (maxRuns !== void 0 && (!Number.isInteger(maxRuns) || maxRuns < 1)) return {
|
|
961
|
+
task: void 0,
|
|
962
|
+
tasks,
|
|
963
|
+
error: "invalid schedule run cap"
|
|
964
|
+
};
|
|
965
|
+
const nextRunAt = nextRunAtMs(cron, now, requestedZone ?? hostTimeZone);
|
|
966
|
+
if (nextRunAt !== void 0) task = withSchedule(task, {
|
|
967
|
+
enabled: true,
|
|
968
|
+
mode: "cron",
|
|
969
|
+
cron,
|
|
970
|
+
maxRuns,
|
|
971
|
+
timeZone: requestedZone,
|
|
972
|
+
nextRunAt,
|
|
973
|
+
runCount: 0
|
|
974
|
+
}, now);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
907
977
|
}
|
|
908
978
|
return {
|
|
909
979
|
task,
|
|
@@ -934,16 +1004,30 @@ window.__ModuleLoader__.load({
|
|
|
934
1004
|
//#endregion
|
|
935
1005
|
//#region src/core/use-cases/task-schedule.ts
|
|
936
1006
|
/**
|
|
937
|
-
* Schedule use
|
|
938
|
-
* Pure ledger transitions (no persistence or notify
|
|
939
|
-
* orchestrates those). Validation and next-run computation
|
|
940
|
-
* the core cron parser (schedule.ts) and the withSchedule
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
*
|
|
944
|
-
*
|
|
945
|
-
*
|
|
946
|
-
*
|
|
1007
|
+
* Schedule use cases: arm/disarm a task's scheduling rule, and record what a
|
|
1008
|
+
* due occurrence did to it. Pure ledger transitions (no persistence or notify
|
|
1009
|
+
* — the controller orchestrates those). Validation and next-run computation
|
|
1010
|
+
* live here, sharing the core cron parser (schedule.ts) and the withSchedule
|
|
1011
|
+
* transition.
|
|
1012
|
+
*
|
|
1013
|
+
* A rule is either a recurring cron rule or a single planned instant, and
|
|
1014
|
+
* either kind may be capped by a run budget. The counter (`runCount`) moves
|
|
1015
|
+
* only when the Host actually opened an execution; a skipped occurrence
|
|
1016
|
+
* (busy, unconfirmed permission, missed instant, unreachable plan) moves the
|
|
1017
|
+
* rule without consuming its budget.
|
|
1018
|
+
*/
|
|
1019
|
+
/**
|
|
1020
|
+
* Set an on-board task's scheduling rule. An unknown or archived task, an
|
|
1021
|
+
* unusable zone, a blank or invalid cron, a one-shot with no usable instant,
|
|
1022
|
+
* a one-shot armed in the past, and a run cap that is not a positive integer
|
|
1023
|
+
* are all rejected (state untouched). An enabled rule computes its next run
|
|
1024
|
+
* instant immediately — a one-shot's next instant IS its planned instant — and
|
|
1025
|
+
* a disabled rule carries none.
|
|
1026
|
+
*
|
|
1027
|
+
* Arming a rule that was not enabled, or switching its kind, starts a fresh
|
|
1028
|
+
* budget: the run counter and any previous stop/skip record are cleared. Edits
|
|
1029
|
+
* to a live rule (expression, zone, cap) keep the consumed count, so an
|
|
1030
|
+
* already-spent budget can never silently reset and overrun.
|
|
947
1031
|
* @param tasks - current ledger.
|
|
948
1032
|
* @param id - the task to schedule.
|
|
949
1033
|
* @param patch - rule fields to change (absent fields keep their current value).
|
|
@@ -957,36 +1041,91 @@ window.__ModuleLoader__.load({
|
|
|
957
1041
|
applied: false
|
|
958
1042
|
};
|
|
959
1043
|
const current = task.schedule;
|
|
1044
|
+
const mode = patch.mode ?? current?.mode ?? "cron";
|
|
1045
|
+
const timeZone = patch.timeZone === void 0 ? current?.timeZone : patch.timeZone ?? void 0;
|
|
1046
|
+
if (timeZone !== void 0 && !isValidTimeZone(timeZone)) return {
|
|
1047
|
+
tasks,
|
|
1048
|
+
applied: false
|
|
1049
|
+
};
|
|
1050
|
+
const enabled = patch.enabled ?? current?.enabled ?? false;
|
|
1051
|
+
const restart = enabled && current?.enabled !== true || (current?.mode ?? "cron") !== mode;
|
|
1052
|
+
const runCount = restart ? 0 : current?.runCount ?? 0;
|
|
1053
|
+
const effectiveZone = timeZone ?? hostTimeZone;
|
|
1054
|
+
const cleared = restart ? {
|
|
1055
|
+
endedAt: void 0,
|
|
1056
|
+
endedReason: void 0,
|
|
1057
|
+
skippedAt: void 0,
|
|
1058
|
+
skippedReason: void 0
|
|
1059
|
+
} : {
|
|
1060
|
+
endedAt: current?.endedAt,
|
|
1061
|
+
endedReason: current?.endedReason,
|
|
1062
|
+
skippedAt: current?.skippedAt,
|
|
1063
|
+
skippedReason: current?.skippedReason
|
|
1064
|
+
};
|
|
1065
|
+
if (mode === "once") {
|
|
1066
|
+
const at = patch.at ?? current?.at;
|
|
1067
|
+
if (at === void 0 || !Number.isInteger(at)) return {
|
|
1068
|
+
tasks,
|
|
1069
|
+
applied: false
|
|
1070
|
+
};
|
|
1071
|
+
if (enabled && at <= now) return {
|
|
1072
|
+
tasks,
|
|
1073
|
+
applied: false
|
|
1074
|
+
};
|
|
1075
|
+
return {
|
|
1076
|
+
tasks: tasks.map((candidate) => candidate.id !== id ? candidate : withSchedule(candidate, {
|
|
1077
|
+
enabled,
|
|
1078
|
+
mode: "once",
|
|
1079
|
+
at,
|
|
1080
|
+
cron: void 0,
|
|
1081
|
+
maxRuns: void 0,
|
|
1082
|
+
timeZone: timeZone ?? void 0,
|
|
1083
|
+
nextRunAt: enabled ? at : void 0,
|
|
1084
|
+
runCount,
|
|
1085
|
+
...cleared
|
|
1086
|
+
}, now)),
|
|
1087
|
+
applied: true
|
|
1088
|
+
};
|
|
1089
|
+
}
|
|
960
1090
|
const cron = (patch.cron ?? current?.cron ?? "").trim();
|
|
961
1091
|
if (cron === "" || !isValidCron(cron)) return {
|
|
962
1092
|
tasks,
|
|
963
1093
|
applied: false
|
|
964
1094
|
};
|
|
965
|
-
const
|
|
966
|
-
if (
|
|
1095
|
+
const maxRuns = ("maxRuns" in patch ? patch.maxRuns : current?.maxRuns) ?? void 0;
|
|
1096
|
+
if (maxRuns !== void 0 && (!Number.isInteger(maxRuns) || maxRuns < 1)) return {
|
|
967
1097
|
tasks,
|
|
968
1098
|
applied: false
|
|
969
1099
|
};
|
|
970
|
-
const
|
|
971
|
-
const
|
|
972
|
-
|
|
1100
|
+
const spent = maxRuns !== void 0 && runCount >= maxRuns;
|
|
1101
|
+
const armed = enabled && !spent;
|
|
1102
|
+
const nextRunAt = armed ? nextRunAtMs(cron, now, effectiveZone) : void 0;
|
|
1103
|
+
if (armed && nextRunAt === void 0) return {
|
|
973
1104
|
tasks,
|
|
974
1105
|
applied: false
|
|
975
1106
|
};
|
|
1107
|
+
const exhausted = enabled && spent;
|
|
976
1108
|
return {
|
|
977
|
-
tasks: tasks.map((candidate) => candidate.id
|
|
978
|
-
enabled,
|
|
1109
|
+
tasks: tasks.map((candidate) => candidate.id !== id ? candidate : withSchedule(candidate, {
|
|
1110
|
+
enabled: armed,
|
|
1111
|
+
mode: "cron",
|
|
979
1112
|
cron,
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1113
|
+
at: void 0,
|
|
1114
|
+
maxRuns,
|
|
1115
|
+
timeZone: timeZone ?? void 0,
|
|
1116
|
+
nextRunAt,
|
|
1117
|
+
runCount,
|
|
1118
|
+
...exhausted ? {
|
|
1119
|
+
endedAt: now,
|
|
1120
|
+
endedReason: "limit"
|
|
1121
|
+
} : cleared
|
|
1122
|
+
}, now)),
|
|
983
1123
|
applied: true
|
|
984
1124
|
};
|
|
985
1125
|
}
|
|
986
1126
|
/**
|
|
987
|
-
* Roll a task's schedule rule forward (
|
|
988
|
-
* due instant and the trigger instant. No-op for tasks without a rule
|
|
989
|
-
* mid-tick, for example).
|
|
1127
|
+
* Roll a task's schedule rule forward (legacy pure-controller seam): persist
|
|
1128
|
+
* the next due instant and the trigger instant. No-op for tasks without a rule.
|
|
990
1129
|
* @param tasks - current ledger.
|
|
991
1130
|
* @param id - the task to roll forward.
|
|
992
1131
|
* @param nextRunAt - next due instant (may be undefined to clear).
|
|
@@ -1258,7 +1397,7 @@ window.__ModuleLoader__.load({
|
|
|
1258
1397
|
if ("permission" in patch && patch.permission !== void 0 && patch.permission !== task.permission || "handover" in patch) next.permissionConfirmedAt = void 0;
|
|
1259
1398
|
if ("reuseSession" in patch) next.reuseSession = patch.reuseSession === true ? true : void 0;
|
|
1260
1399
|
if ("teamRun" in patch) next.teamRun = patch.teamRun === true ? true : void 0;
|
|
1261
|
-
if ("goalRun" in patch) next.goalRun = patch.goalRun ===
|
|
1400
|
+
if ("goalRun" in patch) next.goalRun = patch.goalRun === true ? true : void 0;
|
|
1262
1401
|
if ("skipVerification" in patch) next.skipVerification = patch.skipVerification === true ? true : void 0;
|
|
1263
1402
|
if (workspaceId !== void 0 || "workspaceId" in patch) next.workspaceId = workspaceId;
|
|
1264
1403
|
if (mode !== void 0 || "mode" in patch) next.mode = mode;
|
|
@@ -1673,13 +1812,15 @@ window.__ModuleLoader__.load({
|
|
|
1673
1812
|
return true;
|
|
1674
1813
|
}
|
|
1675
1814
|
/**
|
|
1676
|
-
* Update a task's schedule rule.
|
|
1677
|
-
*
|
|
1678
|
-
*
|
|
1679
|
-
*
|
|
1815
|
+
* Update a task's schedule rule. An unusable plan (blank or invalid cron, a
|
|
1816
|
+
* one-shot with no future instant, a non-positive run cap) is rejected
|
|
1817
|
+
* (returns false, state untouched). When the rule ends up enabled the next
|
|
1818
|
+
* run instant is computed immediately — a one-shot's next instant IS its
|
|
1819
|
+
* planned instant — and a disabled rule carries none. Delegates the domain
|
|
1820
|
+
* transition to the schedule use case.
|
|
1680
1821
|
* @param id - the task to schedule.
|
|
1681
1822
|
* @param patch - fields to change (absent fields keep their current value).
|
|
1682
|
-
* @returns true when applied, false when rejected (
|
|
1823
|
+
* @returns true when applied, false when rejected (unknown task / unusable plan).
|
|
1683
1824
|
*/
|
|
1684
1825
|
setSchedule(id, patch) {
|
|
1685
1826
|
const hostTimeZone = this.hostState?.scheduler.timeZone ?? resolveHostTimeZone();
|
|
@@ -1879,6 +2020,7 @@ window.__ModuleLoader__.load({
|
|
|
1879
2020
|
const sessionDefaultPermission = snapshot.sessionDefaultPermission ?? this.hostState?.sessionDefaultPermission;
|
|
1880
2021
|
const maxSubtaskDepth = snapshot.maxSubtaskDepth ?? this.hostState?.maxSubtaskDepth;
|
|
1881
2022
|
const teamRunAvailable = snapshot.teamRunAvailable ?? this.hostState?.teamRunAvailable;
|
|
2023
|
+
const goalRunEnabled = snapshot.goalRunEnabled ?? this.hostState?.goalRunEnabled;
|
|
1882
2024
|
const extensions = snapshot.extensions ?? this.hostState?.extensions;
|
|
1883
2025
|
return {
|
|
1884
2026
|
revision: snapshot.revision,
|
|
@@ -1887,6 +2029,7 @@ window.__ModuleLoader__.load({
|
|
|
1887
2029
|
...sessionDefaultPermission === void 0 ? {} : { sessionDefaultPermission },
|
|
1888
2030
|
...maxSubtaskDepth === void 0 ? {} : { maxSubtaskDepth },
|
|
1889
2031
|
...teamRunAvailable === void 0 ? {} : { teamRunAvailable },
|
|
2032
|
+
...goalRunEnabled === void 0 ? {} : { goalRunEnabled },
|
|
1890
2033
|
...extensions === void 0 ? {} : { extensions }
|
|
1891
2034
|
};
|
|
1892
2035
|
}
|
|
@@ -2210,6 +2353,19 @@ window.__ModuleLoader__.load({
|
|
|
2210
2353
|
function exceptionAttempts(verification) {
|
|
2211
2354
|
return verification === void 0 ? [] : verification.attempts.filter((attempt) => attempt.stage === "exception");
|
|
2212
2355
|
}
|
|
2356
|
+
/**
|
|
2357
|
+
* Invalid acceptances spent by this cycle: a veto whose required evidence was
|
|
2358
|
+
* missing, unlocatable, or aimed at the empty-work baseline. They are NOT
|
|
2359
|
+
* quality verdicts, so they never close the cycle and never fail the card; the
|
|
2360
|
+
* bound is what keeps an evidence-free judge from re-running forever.
|
|
2361
|
+
*/
|
|
2362
|
+
function invalidAttempts(verification) {
|
|
2363
|
+
return verification === void 0 ? [] : verification.attempts.filter((attempt) => attempt.stage === "invalid");
|
|
2364
|
+
}
|
|
2365
|
+
/** Whether this cycle still has invalid-acceptance budget left. */
|
|
2366
|
+
function hasInvalidBudget(verification) {
|
|
2367
|
+
return invalidAttempts(verification).length < 2;
|
|
2368
|
+
}
|
|
2213
2369
|
/** The quality attempt that passed, when one did. */
|
|
2214
2370
|
function passedAttempt(verification) {
|
|
2215
2371
|
return qualityAttempts(verification).find((attempt) => attempt.passed);
|
|
@@ -2225,7 +2381,7 @@ window.__ModuleLoader__.load({
|
|
|
2225
2381
|
if (verification.failedReason !== void 0) return "failed";
|
|
2226
2382
|
if (passedAttempt(verification) !== void 0) return "passed";
|
|
2227
2383
|
if (verification.inFlight === true) return "verifying";
|
|
2228
|
-
if (qualityAttempts(verification).length === 0) return "executing";
|
|
2384
|
+
if (qualityAttempts(verification).length === 0) return hasInvalidBudget(verification) ? "executing" : "invalid";
|
|
2229
2385
|
return hasQualityBudget(verification) ? "repairing" : "failed";
|
|
2230
2386
|
}
|
|
2231
2387
|
/** Whether an unknown value carries every field a persisted attempt needs. */
|
|
@@ -2233,7 +2389,7 @@ window.__ModuleLoader__.load({
|
|
|
2233
2389
|
if (typeof value !== "object" || value === null) return void 0;
|
|
2234
2390
|
const row = value;
|
|
2235
2391
|
if (typeof row.index !== "number" || typeof row.at !== "number") return void 0;
|
|
2236
|
-
if (row.stage !== "quality" && row.stage !== "exception") return void 0;
|
|
2392
|
+
if (row.stage !== "quality" && row.stage !== "exception" && row.stage !== "budget" && row.stage !== "invalid") return void 0;
|
|
2237
2393
|
if (typeof row.passed !== "boolean") return void 0;
|
|
2238
2394
|
if (typeof row.score !== "number" || !Number.isFinite(row.score)) return void 0;
|
|
2239
2395
|
if (typeof row.baseline !== "number" || !Number.isFinite(row.baseline)) return void 0;
|
|
@@ -2268,7 +2424,18 @@ window.__ModuleLoader__.load({
|
|
|
2268
2424
|
const routeRow = route;
|
|
2269
2425
|
if (typeof routeRow.provider !== "string" || typeof routeRow.model !== "string") return void 0;
|
|
2270
2426
|
if (routeRow.reasoningEffort !== void 0 && typeof routeRow.reasoningEffort !== "string") return void 0;
|
|
2271
|
-
const findings = Array.isArray(row.findings) ? row.findings.filter((item) => typeof item === "string")
|
|
2427
|
+
const findings = (Array.isArray(row.findings) ? row.findings : []).filter((item) => typeof item === "string").slice(0, 12).map((item) => clipRead(item, 400));
|
|
2428
|
+
const criterionFindings = [];
|
|
2429
|
+
if (Array.isArray(row.criterionFindings)) {
|
|
2430
|
+
if (row.criterionFindings.length > 12) return void 0;
|
|
2431
|
+
for (const entry of row.criterionFindings) {
|
|
2432
|
+
const finding = readCriterionFinding(entry);
|
|
2433
|
+
if (finding === void 0) return void 0;
|
|
2434
|
+
criterionFindings.push(finding);
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
const invalidReason = row.invalidReason;
|
|
2438
|
+
if (invalidReason !== void 0 && invalidReason !== "missing-finding" && invalidReason !== "unlocatable-quote" && invalidReason !== "baseline-finding" && invalidReason !== "vacuous-finding" && invalidReason !== "insufficient-evidence") return void 0;
|
|
2272
2439
|
return {
|
|
2273
2440
|
index: row.index,
|
|
2274
2441
|
at: row.at,
|
|
@@ -2301,7 +2468,51 @@ window.__ModuleLoader__.load({
|
|
|
2301
2468
|
},
|
|
2302
2469
|
channel: "explicit-tag",
|
|
2303
2470
|
rounds: typeof row.rounds === "number" ? row.rounds : 2,
|
|
2304
|
-
...typeof row.error === "string" ? { error: row.error } : {}
|
|
2471
|
+
...typeof row.error === "string" ? { error: row.error } : {},
|
|
2472
|
+
...criterionFindings.length === 0 ? {} : { criterionFindings },
|
|
2473
|
+
...typeof invalidReason === "string" ? { invalidReason } : {}
|
|
2474
|
+
};
|
|
2475
|
+
}
|
|
2476
|
+
/**
|
|
2477
|
+
* Bound one persisted finding's text to what the acceptance itself would have
|
|
2478
|
+
* written.
|
|
2479
|
+
*
|
|
2480
|
+
* The reader is the only other door into the ledger: a hand-edited or
|
|
2481
|
+
* corrupted document could otherwise carry a megabyte of prose in a field the
|
|
2482
|
+
* writer caps at a few hundred characters, and every later render, audit
|
|
2483
|
+
* summary and cleanup pass would pay for it. Clipping on READ (never rejecting)
|
|
2484
|
+
* keeps the block usable and its capacity bounded: the acceptance-only material
|
|
2485
|
+
* the cleanup removes is bounded by construction on both sides.
|
|
2486
|
+
* @param value - the raw persisted text.
|
|
2487
|
+
* @param max - the cap the writer applies to that field.
|
|
2488
|
+
* @returns the bounded text.
|
|
2489
|
+
*/
|
|
2490
|
+
function clipRead(value, max) {
|
|
2491
|
+
return value.length <= max ? value : value.slice(0, max);
|
|
2492
|
+
}
|
|
2493
|
+
/**
|
|
2494
|
+
* Repair one persisted structured finding, or undefined when it is unusable.
|
|
2495
|
+
* A malformed finding drops the WHOLE acceptance block (fail closed): a
|
|
2496
|
+
* persisted veto that cannot be read back could otherwise be counted as
|
|
2497
|
+
* evidence it no longer holds.
|
|
2498
|
+
*/
|
|
2499
|
+
function readCriterionFinding(value) {
|
|
2500
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
2501
|
+
const row = value;
|
|
2502
|
+
if (typeof row.criterionId !== "string" || row.criterionId === "") return void 0;
|
|
2503
|
+
if (typeof row.requirement !== "string" || typeof row.observation !== "string" || typeof row.gap !== "string") return void 0;
|
|
2504
|
+
if (typeof row.quote !== "string") return void 0;
|
|
2505
|
+
if (row.criterionId.length > 64) return void 0;
|
|
2506
|
+
const location = row.location;
|
|
2507
|
+
if (location !== "task" && location !== "trajectory" && location !== "workspace" && location !== "baseline" && location !== "unknown") return void 0;
|
|
2508
|
+
return {
|
|
2509
|
+
criterionId: row.criterionId,
|
|
2510
|
+
requirement: clipRead(row.requirement, 400),
|
|
2511
|
+
observation: clipRead(row.observation, 400),
|
|
2512
|
+
gap: clipRead(row.gap, 400),
|
|
2513
|
+
quote: clipRead(row.quote, 600),
|
|
2514
|
+
location,
|
|
2515
|
+
...typeof row.action === "string" ? { action: clipRead(row.action, 400) } : {}
|
|
2305
2516
|
};
|
|
2306
2517
|
}
|
|
2307
2518
|
/**
|
|
@@ -2349,7 +2560,7 @@ window.__ModuleLoader__.load({
|
|
|
2349
2560
|
};
|
|
2350
2561
|
}
|
|
2351
2562
|
const applicability = row.applicability;
|
|
2352
|
-
if (applicability !== "enforced" && applicability !== "disabled" && applicability !== "skipped" && applicability !== "goal-unavailable" && applicability !== "team-member") return void 0;
|
|
2563
|
+
if (applicability !== "enforced" && applicability !== "disabled" && applicability !== "skipped" && applicability !== "goal-unavailable" && applicability !== "team-member" && applicability !== "goal-disabled") return void 0;
|
|
2353
2564
|
const attempts = [];
|
|
2354
2565
|
if (!Array.isArray(row.attempts)) return void 0;
|
|
2355
2566
|
for (const entry of row.attempts) {
|
|
@@ -2358,6 +2569,8 @@ window.__ModuleLoader__.load({
|
|
|
2358
2569
|
attempts.push(attempt);
|
|
2359
2570
|
}
|
|
2360
2571
|
if (typeof row.failedReason === "string" && row.failedReason === "") return void 0;
|
|
2572
|
+
const cleanup = readCleanupRecord(row.cleanup);
|
|
2573
|
+
if (row.cleanup !== void 0 && cleanup === void 0) return void 0;
|
|
2361
2574
|
return {
|
|
2362
2575
|
contract: {
|
|
2363
2576
|
enabled: contractRow.enabled,
|
|
@@ -2372,7 +2585,98 @@ window.__ModuleLoader__.load({
|
|
|
2372
2585
|
...row.inFlight === true ? { inFlight: true } : {},
|
|
2373
2586
|
applicability,
|
|
2374
2587
|
...typeof row.failedReason === "string" ? { failedReason: row.failedReason } : {},
|
|
2375
|
-
...typeof row.failedAt === "number" && Number.isFinite(row.failedAt) ? { failedAt: row.failedAt } : {}
|
|
2588
|
+
...typeof row.failedAt === "number" && Number.isFinite(row.failedAt) ? { failedAt: row.failedAt } : {},
|
|
2589
|
+
...cleanup === void 0 ? {} : { cleanup }
|
|
2590
|
+
};
|
|
2591
|
+
}
|
|
2592
|
+
/**
|
|
2593
|
+
* Repair the persisted cleanup record, or undefined when it is unusable. The
|
|
2594
|
+
* record is the audit trail the UI reads to tell "the judge gave its evidence
|
|
2595
|
+
* and it was cleaned up" apart from "the judge produced no evidence at all",
|
|
2596
|
+
* so a malformed one drops the whole block (fail closed).
|
|
2597
|
+
*/
|
|
2598
|
+
function readCleanupRecord(value) {
|
|
2599
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
2600
|
+
const row = value;
|
|
2601
|
+
if (row.state !== "pending" && row.state !== "cleaned" && row.state !== "failed") return void 0;
|
|
2602
|
+
if (typeof row.attempts !== "number" || !Number.isInteger(row.attempts) || row.attempts < 0) return void 0;
|
|
2603
|
+
if (typeof row.startedAt !== "number" || !Number.isFinite(row.startedAt)) return void 0;
|
|
2604
|
+
if (row.cleanedAt !== void 0 && (typeof row.cleanedAt !== "number" || !Number.isFinite(row.cleanedAt))) return void 0;
|
|
2605
|
+
if (row.lastError !== void 0 && typeof row.lastError !== "string") return void 0;
|
|
2606
|
+
if (!Array.isArray(row.audit)) return void 0;
|
|
2607
|
+
const audit = [];
|
|
2608
|
+
for (const entry of row.audit) {
|
|
2609
|
+
const parsed = readAuditRecord(entry);
|
|
2610
|
+
if (parsed === void 0) return void 0;
|
|
2611
|
+
audit.push(parsed);
|
|
2612
|
+
}
|
|
2613
|
+
return {
|
|
2614
|
+
state: row.state,
|
|
2615
|
+
attempts: row.attempts,
|
|
2616
|
+
startedAt: row.startedAt,
|
|
2617
|
+
...typeof row.cleanedAt === "number" ? { cleanedAt: row.cleanedAt } : {},
|
|
2618
|
+
...typeof row.lastError === "string" ? { lastError: row.lastError } : {},
|
|
2619
|
+
audit
|
|
2620
|
+
};
|
|
2621
|
+
}
|
|
2622
|
+
/** Repair one persisted audit credential, or undefined when it is unusable. */
|
|
2623
|
+
function readAuditRecord(value) {
|
|
2624
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
2625
|
+
const row = value;
|
|
2626
|
+
if (row.stage !== "quality" && row.stage !== "exception" && row.stage !== "budget" && row.stage !== "invalid") return void 0;
|
|
2627
|
+
if (typeof row.passed !== "boolean") return void 0;
|
|
2628
|
+
if (typeof row.at !== "number" || !Number.isFinite(row.at)) return void 0;
|
|
2629
|
+
if (typeof row.score !== "number" || !Number.isFinite(row.score)) return void 0;
|
|
2630
|
+
if (typeof row.baseline !== "number" || !Number.isFinite(row.baseline)) return void 0;
|
|
2631
|
+
if (!Array.isArray(row.criteria)) return void 0;
|
|
2632
|
+
const criteria = [];
|
|
2633
|
+
for (const entry of row.criteria) {
|
|
2634
|
+
if (typeof entry !== "object" || entry === null) return void 0;
|
|
2635
|
+
const criterion = entry;
|
|
2636
|
+
if (typeof criterion.id !== "string" || typeof criterion.name !== "string") return void 0;
|
|
2637
|
+
if (typeof criterion.score !== "number" || !Number.isFinite(criterion.score)) return void 0;
|
|
2638
|
+
if (typeof criterion.baseline !== "number" || !Number.isFinite(criterion.baseline)) return void 0;
|
|
2639
|
+
if (typeof criterion.threshold !== "number" || !Number.isFinite(criterion.threshold)) return void 0;
|
|
2640
|
+
criteria.push({
|
|
2641
|
+
id: criterion.id,
|
|
2642
|
+
name: criterion.name,
|
|
2643
|
+
score: criterion.score,
|
|
2644
|
+
baseline: criterion.baseline,
|
|
2645
|
+
threshold: criterion.threshold,
|
|
2646
|
+
passed: criterion.passed === true
|
|
2647
|
+
});
|
|
2648
|
+
}
|
|
2649
|
+
if (typeof row.evidenceHash !== "string") return void 0;
|
|
2650
|
+
const route = row.route;
|
|
2651
|
+
if (typeof route !== "object" || route === null) return void 0;
|
|
2652
|
+
const routeRow = route;
|
|
2653
|
+
if (typeof routeRow.provider !== "string" || typeof routeRow.model !== "string") return void 0;
|
|
2654
|
+
const usage = row.usage;
|
|
2655
|
+
if (typeof usage !== "object" || usage === null) return void 0;
|
|
2656
|
+
const usageRow = usage;
|
|
2657
|
+
if (typeof usageRow.calls !== "number" || typeof usageRow.inputTokens !== "number" || typeof usageRow.outputTokens !== "number" || typeof usageRow.reasoningTokens !== "number") return void 0;
|
|
2658
|
+
return {
|
|
2659
|
+
stage: row.stage,
|
|
2660
|
+
passed: row.passed,
|
|
2661
|
+
at: row.at,
|
|
2662
|
+
score: row.score,
|
|
2663
|
+
baseline: row.baseline,
|
|
2664
|
+
criteria,
|
|
2665
|
+
evidenceHash: row.evidenceHash,
|
|
2666
|
+
route: {
|
|
2667
|
+
provider: routeRow.provider,
|
|
2668
|
+
model: routeRow.model,
|
|
2669
|
+
...typeof routeRow.reasoningEffort === "string" ? { reasoningEffort: routeRow.reasoningEffort } : {}
|
|
2670
|
+
},
|
|
2671
|
+
...typeof row.error === "string" ? { error: row.error } : {},
|
|
2672
|
+
...typeof row.findingSummary === "string" ? { findingSummary: row.findingSummary } : {},
|
|
2673
|
+
usage: {
|
|
2674
|
+
calls: usageRow.calls,
|
|
2675
|
+
inputTokens: usageRow.inputTokens,
|
|
2676
|
+
outputTokens: usageRow.outputTokens,
|
|
2677
|
+
reasoningTokens: usageRow.reasoningTokens,
|
|
2678
|
+
...usageRow.usageIncomplete === true ? { usageIncomplete: true } : {}
|
|
2679
|
+
}
|
|
2376
2680
|
};
|
|
2377
2681
|
}
|
|
2378
2682
|
/** Sum the attempts of one execution. */
|
|
@@ -2380,6 +2684,7 @@ window.__ModuleLoader__.load({
|
|
|
2380
2684
|
const totals = {
|
|
2381
2685
|
quality: 0,
|
|
2382
2686
|
exceptions: 0,
|
|
2687
|
+
invalid: 0,
|
|
2383
2688
|
calls: 0,
|
|
2384
2689
|
inputTokens: 0,
|
|
2385
2690
|
outputTokens: 0,
|
|
@@ -2389,6 +2694,7 @@ window.__ModuleLoader__.load({
|
|
|
2389
2694
|
if (verification === void 0) return totals;
|
|
2390
2695
|
for (const attempt of verification.attempts) {
|
|
2391
2696
|
if (attempt.stage === "quality") totals.quality += 1;
|
|
2697
|
+
else if (attempt.stage === "invalid") totals.invalid += 1;
|
|
2392
2698
|
else totals.exceptions += 1;
|
|
2393
2699
|
totals.calls += attempt.usage.calls;
|
|
2394
2700
|
totals.inputTokens += attempt.usage.inputTokens;
|
|
@@ -2526,6 +2832,7 @@ window.__ModuleLoader__.load({
|
|
|
2526
2832
|
if (entry.initiatedBy !== void 0 && typeof entry.initiatedBy !== "string") return false;
|
|
2527
2833
|
if (entry.frozenBy !== void 0 && typeof entry.frozenBy !== "string") return false;
|
|
2528
2834
|
if (entry.frozenAt !== void 0 && typeof entry.frozenAt !== "number") return false;
|
|
2835
|
+
if (entry.external !== void 0 && typeof entry.external !== "boolean") return false;
|
|
2529
2836
|
if (entry.verification !== void 0 && normalizeVerification(entry.verification) === void 0) return false;
|
|
2530
2837
|
}
|
|
2531
2838
|
return true;
|
|
@@ -2534,23 +2841,62 @@ window.__ModuleLoader__.load({
|
|
|
2534
2841
|
function normalizeStatus(status) {
|
|
2535
2842
|
return isTaskStatus(status) ? status : "todo";
|
|
2536
2843
|
}
|
|
2844
|
+
/** A persisted ms timestamp, kept only when it is a usable finite number. */
|
|
2845
|
+
function optionalInstant(value) {
|
|
2846
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
2847
|
+
}
|
|
2848
|
+
/** A persisted positive-integer run cap, or undefined for unlimited/repair. */
|
|
2849
|
+
function optionalRunCap(value) {
|
|
2850
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 1 ? value : void 0;
|
|
2851
|
+
}
|
|
2852
|
+
/** A persisted stop reason, kept only when it names a reason this build knows. */
|
|
2853
|
+
function optionalStopReason(value) {
|
|
2854
|
+
return typeof value === "string" && SCHEDULE_STOP_REASONS.includes(value) ? value : void 0;
|
|
2855
|
+
}
|
|
2537
2856
|
/**
|
|
2538
|
-
* Repair a persisted schedule rule
|
|
2539
|
-
*
|
|
2540
|
-
*
|
|
2857
|
+
* Repair a persisted schedule rule. Both modes are repaired field by field and
|
|
2858
|
+
* a rule that carries no usable plan is dropped (the task row survives):
|
|
2859
|
+
* a recurring rule without a well-formed 5-field cron, or a one-shot without a
|
|
2860
|
+
* finite planned instant. A rule written before `mode` existed is a cron rule.
|
|
2541
2861
|
*/
|
|
2542
2862
|
function normalizeSchedule(schedule) {
|
|
2543
2863
|
if (typeof schedule !== "object" || schedule === null) return void 0;
|
|
2544
2864
|
const rule = schedule;
|
|
2865
|
+
const timeZone = typeof rule.timeZone === "string" && isValidTimeZone(rule.timeZone) ? rule.timeZone : void 0;
|
|
2866
|
+
const runCountValue = rule.runCount;
|
|
2867
|
+
const runCount = typeof runCountValue === "number" && Number.isInteger(runCountValue) && runCountValue >= 0 ? runCountValue : 0;
|
|
2868
|
+
const endedAt = optionalInstant(rule.endedAt);
|
|
2869
|
+
const endedReason = optionalStopReason(rule.endedReason);
|
|
2870
|
+
const skippedAt = optionalInstant(rule.skippedAt);
|
|
2871
|
+
const skippedReason = optionalStopReason(rule.skippedReason);
|
|
2872
|
+
const common = {
|
|
2873
|
+
enabled: rule.enabled === true,
|
|
2874
|
+
...timeZone === void 0 ? {} : { timeZone },
|
|
2875
|
+
nextRunAt: optionalInstant(rule.nextRunAt),
|
|
2876
|
+
lastTriggeredAt: optionalInstant(rule.lastTriggeredAt),
|
|
2877
|
+
runCount,
|
|
2878
|
+
...endedAt === void 0 ? {} : { endedAt },
|
|
2879
|
+
...endedReason === void 0 ? {} : { endedReason },
|
|
2880
|
+
...skippedAt === void 0 ? {} : { skippedAt },
|
|
2881
|
+
...skippedReason === void 0 ? {} : { skippedReason }
|
|
2882
|
+
};
|
|
2883
|
+
if (rule.mode === "once") {
|
|
2884
|
+
const at = optionalInstant(rule.at);
|
|
2885
|
+
if (at === void 0) return void 0;
|
|
2886
|
+
return {
|
|
2887
|
+
...common,
|
|
2888
|
+
mode: "once",
|
|
2889
|
+
at
|
|
2890
|
+
};
|
|
2891
|
+
}
|
|
2545
2892
|
if (typeof rule.cron !== "string") return void 0;
|
|
2546
2893
|
if (rule.cron.trim() === "" || !isValidCron(rule.cron)) return void 0;
|
|
2547
|
-
const
|
|
2894
|
+
const maxRuns = optionalRunCap(rule.maxRuns);
|
|
2548
2895
|
return {
|
|
2549
|
-
|
|
2896
|
+
...common,
|
|
2897
|
+
mode: "cron",
|
|
2550
2898
|
cron: rule.cron,
|
|
2551
|
-
...
|
|
2552
|
-
nextRunAt: typeof rule.nextRunAt === "number" ? rule.nextRunAt : void 0,
|
|
2553
|
-
lastTriggeredAt: typeof rule.lastTriggeredAt === "number" ? rule.lastTriggeredAt : void 0
|
|
2899
|
+
...maxRuns === void 0 ? {} : { maxRuns }
|
|
2554
2900
|
};
|
|
2555
2901
|
}
|
|
2556
2902
|
/**
|
|
@@ -2627,14 +2973,15 @@ window.__ModuleLoader__.load({
|
|
|
2627
2973
|
runGroupId: normalizeTargetId(execution.runGroupId),
|
|
2628
2974
|
ownResult: isExecutionOutcome(execution.ownResult) ? execution.ownResult : void 0,
|
|
2629
2975
|
ownError: typeof execution.ownError === "string" ? execution.ownError : void 0,
|
|
2630
|
-
verification: normalizeVerification(execution.verification)
|
|
2976
|
+
verification: normalizeVerification(execution.verification),
|
|
2977
|
+
external: execution.external === true ? true : void 0
|
|
2631
2978
|
}));
|
|
2632
2979
|
task.workspaceId = normalizeTargetId(row.workspaceId);
|
|
2633
2980
|
task.mode = normalizeTargetId(row.mode);
|
|
2634
2981
|
task.archivedAt = typeof row.archivedAt === "number" && Number.isFinite(row.archivedAt) ? row.archivedAt : void 0;
|
|
2635
2982
|
task.permission = isTaskPermission(row.permission) ? row.permission : void 0;
|
|
2636
2983
|
task.reuseSession = row.reuseSession === true ? true : void 0;
|
|
2637
|
-
task.goalRun = row.goalRun ===
|
|
2984
|
+
task.goalRun = row.goalRun === true ? true : void 0;
|
|
2638
2985
|
task.skipVerification = row.skipVerification === true ? true : void 0;
|
|
2639
2986
|
task.freeze = normalizeFreeze(row.freeze);
|
|
2640
2987
|
task.handover = normalizeHandover(row.handover);
|
|
@@ -2877,6 +3224,7 @@ window.__ModuleLoader__.load({
|
|
|
2877
3224
|
"detail.noSession": "暂无会话",
|
|
2878
3225
|
"detail.executionStarted": "已启动",
|
|
2879
3226
|
"detail.execution.initiator": "发起会话 {session}",
|
|
3227
|
+
"detail.execution.external": "Host 之外完成:{agent}",
|
|
2880
3228
|
"detail.executionEnded": "已结束",
|
|
2881
3229
|
"detail.result.succeeded": "成功",
|
|
2882
3230
|
"detail.result.failed": "失败",
|
|
@@ -2919,7 +3267,34 @@ window.__ModuleLoader__.load({
|
|
|
2919
3267
|
"detail.schedule.duration.hours": "{count} 小时",
|
|
2920
3268
|
"detail.schedule.duration.minutes": "{count} 分钟",
|
|
2921
3269
|
"detail.schedule.duration.seconds": "{count} 秒",
|
|
3270
|
+
"detail.schedule.mode": "调度方式",
|
|
3271
|
+
"detail.schedule.mode.cron": "循环",
|
|
3272
|
+
"detail.schedule.mode.once": "单次",
|
|
3273
|
+
"detail.schedule.at": "执行时间",
|
|
3274
|
+
"detail.schedule.atHint": "按所选时区解读的计划时刻;必须是未来时间。",
|
|
3275
|
+
"detail.schedule.atInvalid": "请选择未来的有效时间",
|
|
3276
|
+
"detail.schedule.plannedAt": "计划时间",
|
|
3277
|
+
"detail.schedule.zoneOnceHint": "所选时刻按此时区解读。",
|
|
3278
|
+
"detail.schedule.maxRuns": "次数上限",
|
|
3279
|
+
"detail.schedule.maxRunsUnlimited": "不限次数",
|
|
3280
|
+
"detail.schedule.maxRunsValue": "最多 {count} 次",
|
|
3281
|
+
"detail.schedule.maxRunsCustom": "自定义",
|
|
3282
|
+
"detail.schedule.maxRunsInvalid": "次数上限必须是正整数",
|
|
3283
|
+
"detail.schedule.runs": "已执行 {done}/{total} 次",
|
|
3284
|
+
"detail.schedule.runsUnlimited": "已执行 {done} 次",
|
|
3285
|
+
"detail.schedule.remaining": "剩余 {count} 次",
|
|
3286
|
+
"detail.schedule.cancel": "关闭调度",
|
|
3287
|
+
"detail.schedule.ended": "调度已结束:{reason}",
|
|
3288
|
+
"detail.schedule.skipped": "上次跳过:{reason}",
|
|
3289
|
+
"detail.schedule.stop.fired": "单次计划已执行",
|
|
3290
|
+
"detail.schedule.stop.limit": "已达次数上限",
|
|
3291
|
+
"detail.schedule.stop.no-target": "计划已无可执行时刻",
|
|
3292
|
+
"detail.schedule.stop.missed": "错过执行时刻,已跳过",
|
|
3293
|
+
"detail.schedule.stop.busy": "触发时任务正在运行,已跳过",
|
|
3294
|
+
"detail.schedule.stop.permission": "权限待人工确认,已跳过",
|
|
3295
|
+
"detail.schedule.stop.launch-failed": "启动失败未创建执行,次数已退回",
|
|
2922
3296
|
"card.scheduled": "定时",
|
|
3297
|
+
"card.scheduledOnce": "单次",
|
|
2923
3298
|
"new.workspace": "工作区",
|
|
2924
3299
|
"new.agentPreset": "Agent 预设",
|
|
2925
3300
|
"new.permission": "权限",
|
|
@@ -2949,7 +3324,7 @@ window.__ModuleLoader__.load({
|
|
|
2949
3324
|
"exec.teamRunUnavailable": "当前部署未提供 Agent Teams 服务,无法启用。",
|
|
2950
3325
|
"exec.reuseSessionHint": "开启后,本任务的后续执行在上一次会话里继续(该会话空闲且仍存在时),不再每次新建对话;每次复用时都会重新应用上面钉住的权限与模型。",
|
|
2951
3326
|
"exec.goalRun": "以 dsh 内置的 /goal 开始执行任务",
|
|
2952
|
-
"exec.goalRunHint": "
|
|
3327
|
+
"exec.goalRunHint": "默认关闭:勾选后执行时把任务目标作为持久目标交给 dsh 内置的 /goal,会话会自动续跑多轮,直到 agent 标记目标完成;看板在该目标真正结束后才结算本次执行。不勾选则只执行一轮普通对话。",
|
|
2953
3328
|
"exec.skipVerification": "跳过本任务的验收",
|
|
2954
3329
|
"exec.skipVerificationHint": "默认关闭:勾选后本任务以 goal 形式执行时不再拦截 update_goal 标记完成,也不要求通过验收;执行记录会标注「该卡片跳过验收」。仅对之后新开的执行生效,验收总开关关闭时本项无意义。",
|
|
2955
3330
|
"detail.executionSettings": "执行设置",
|
|
@@ -2982,9 +3357,16 @@ window.__ModuleLoader__.load({
|
|
|
2982
3357
|
"settings.unsaved": "未保存",
|
|
2983
3358
|
"settings.saveFailed": "部署未接受这些值,已保留供你修改。",
|
|
2984
3359
|
"settings.invalidNumber": "请输入数字,留空则使用默认值。",
|
|
3360
|
+
"settings.sessionPollSeconds": "会话轮询间隔(秒)",
|
|
3361
|
+
"settings.sessionPollSecondsHint": "默认 5 秒。仅在看板有需要核对的事情——运行中的卡片或未结算的执行——时才读取会话名册;两者都没有时不再轮询,Host 不会持续扫描持久化会话目录。取值 1–300 秒:间隔越短结算越快、Host 负载越高。",
|
|
2985
3362
|
"settings.maxSubtaskDepth": "子任务深度上限",
|
|
2986
3363
|
"settings.maxSubtaskDepthHint": "默认 1:一个任务只允许一层子任务,子任务不能再创建或关联子任务。最大 3。执行父任务会并发执行它的整棵子任务树,层级越深,一次执行开启的会话越多。",
|
|
2987
3364
|
"settings.maxSubtaskDepthOption": "{depth} 层",
|
|
3365
|
+
"settings.runBehaviorTitle": "运行行为",
|
|
3366
|
+
"settings.runBehaviorCardHint": "全局原生 /goal 执行开关(总开关,默认关闭)。",
|
|
3367
|
+
"settings.goalRunGlobal": "全局启用 DSH 原生 /goal 执行",
|
|
3368
|
+
"settings.goalRunGlobalHint": "默认关闭。关闭时所有任务都按普通单回合执行,不调用 dsh 内置的 /goal;只有这里开启、且任务级「以 /goal 开始执行」被勾选时,才执行原生 /goal。任务级勾选始终可操作、也不会被这里的开关改写,总开关只决定它是否生效。开关按执行启动时冻结,只影响之后新开的执行。",
|
|
3369
|
+
"settings.goalRunGlobalDisabledTaskOption": "全局「原生 /goal 执行」总开关已关闭:任务级选项仍可随时勾选或取消,但暂不生效,你保存的偏好也不会被改写;开启总开关后即按该偏好执行。本次执行按普通单回合进行,未执行 goal 验收。",
|
|
2988
3370
|
"settings.goalVerificationTitle": "任务验收",
|
|
2989
3371
|
"settings.goalVerification": "启用任务验收",
|
|
2990
3372
|
"settings.goalVerificationCardHint": "验收开关、裁判模型与判据阈值。",
|
|
@@ -3014,6 +3396,7 @@ window.__ModuleLoader__.load({
|
|
|
3014
3396
|
"running.repairing": "验收未通过修复中",
|
|
3015
3397
|
"running.verificationPassed": "验收通过",
|
|
3016
3398
|
"running.verificationFailed": "验收未通过",
|
|
3399
|
+
"running.verificationInvalid": "验收无效,等待处理",
|
|
3017
3400
|
"verify.title": "验收报告",
|
|
3018
3401
|
"verify.status.passed": "通过",
|
|
3019
3402
|
"verify.status.failed": "未通过",
|
|
@@ -3021,6 +3404,34 @@ window.__ModuleLoader__.load({
|
|
|
3021
3404
|
"verify.status.verifying": "验收中",
|
|
3022
3405
|
"verify.status.pending": "待验收",
|
|
3023
3406
|
"verify.status.off": "本次执行未启用验收",
|
|
3407
|
+
"verify.status.invalid": "验收无效",
|
|
3408
|
+
"verify.status.invalidHeld": "验收无效,等待人工处理",
|
|
3409
|
+
"verify.attemptInvalid": "第 {index} 次验收无效",
|
|
3410
|
+
"verify.invalidReason.missing-finding": "未达标的判据没有对应的结构化问题反馈",
|
|
3411
|
+
"verify.invalidReason.unlocatable-quote": "问题反馈引用的位置不存在于本次裁判所见的证据中",
|
|
3412
|
+
"verify.invalidReason.baseline-finding": "问题反馈指向空工作基线,而不是本次执行的工作",
|
|
3413
|
+
"verify.invalidReason.vacuous-finding": "问题反馈为空或空泛评价,没有说明实际观测与差异",
|
|
3414
|
+
"verify.invalidReason.insufficient-evidence": "裁判看到的证据不足(例如轨迹被截断),无法支撑否决",
|
|
3415
|
+
"verify.invalidReason.unknown": "未产生可用的质量判定",
|
|
3416
|
+
"verify.invalidCounts": "有效质量判定 {quality}/{max} · 无效验收 {invalid}/{maxInvalid} · 验收异常 {exceptions}/{max}",
|
|
3417
|
+
"verify.invalidDetail": "无效原因:{reason}",
|
|
3418
|
+
"verify.criterionFindings": "结构化问题反馈(判据 · 引用位置 · 实际引用)",
|
|
3419
|
+
"verify.criterionFinding": "{criterion} · {location}:“{quote}”",
|
|
3420
|
+
"verify.criterionFindingFull": "{criterion} · {location}:“{quote}” 要求:{requirement} 观测:{observation} 差异:{gap}",
|
|
3421
|
+
"verify.location.task": "任务要求",
|
|
3422
|
+
"verify.location.trajectory": "执行轨迹",
|
|
3423
|
+
"verify.location.workspace": "宿主记录的变更",
|
|
3424
|
+
"verify.location.baseline": "空工作基线(不构成否决证据)",
|
|
3425
|
+
"verify.location.unknown": "未标明位置",
|
|
3426
|
+
"verify.detailRemoved": "本条验收的详细材料已在通过并成功结算后自动清理(不是裁判未举证)。",
|
|
3427
|
+
"verify.cleanup.cleaned": "本次执行的验收专用详细材料已在通过并成功结算后自动清理;以下为保留的轻量审计凭据。",
|
|
3428
|
+
"verify.cleanup.pending": "验收专用详细材料待清理(将通过并结算后启动)。",
|
|
3429
|
+
"verify.cleanup.failed": "验收详细材料清理失败(已重试 {attempts} 次):{error};通过记录仍然有效,宿主重启后会补清。",
|
|
3430
|
+
"verify.cleanup.audit": "保留凭据:第 {index} 次 · {stage} · 分数 {score} · 证据哈希 {hash}",
|
|
3431
|
+
"verify.cleanup.stage.quality": "质量判定",
|
|
3432
|
+
"verify.cleanup.stage.invalid": "无效验收",
|
|
3433
|
+
"verify.cleanup.stage.exception": "验收异常",
|
|
3434
|
+
"verify.cleanup.stage.budget": "时间预算耗尽",
|
|
3024
3435
|
"verify.summary": "总分 {score}(阈值 {threshold})· 空工作基线 {baseline}",
|
|
3025
3436
|
"verify.criteria": "逐项判据",
|
|
3026
3437
|
"verify.criterion": "{name}:{score}(阈值 {threshold})",
|
|
@@ -3039,9 +3450,10 @@ window.__ModuleLoader__.load({
|
|
|
3039
3450
|
"verify.usageIncomplete": "(至少一次请求的用量未知,以上为下限)",
|
|
3040
3451
|
"verify.finalFailure": "判定依据:{reason}",
|
|
3041
3452
|
"verify.applicability.disabled": "本次执行启动时验收开关关闭,按原有回合判定结算。",
|
|
3042
|
-
"verify.applicability.goalUnavailable": "本次执行未成为 goal
|
|
3453
|
+
"verify.applicability.goalUnavailable": "本次执行未成为 goal 执行(卡片未勾选「以 /goal 开始执行任务」,或 /goal 被拒绝/不可用),验收未强制执行。",
|
|
3043
3454
|
"verify.applicability.skipped": "该任务卡勾选了「跳过验收」,本次执行未经验收判定。",
|
|
3044
3455
|
"verify.applicability.teamMember": "团队执行成员:由 Lead 的团队汇总证据统一验收。",
|
|
3456
|
+
"verify.applicability.goalDisabled": "本次执行启动时全局「原生 /goal 执行」总开关关闭,按普通单回合执行:本次未执行 goal 验收,既不算已验收通过,也不因此判失败。",
|
|
3045
3457
|
"verify.effortFallback": "推理强度回退:{requested} → {resolved}",
|
|
3046
3458
|
"verify.thresholdValue": "{value}%",
|
|
3047
3459
|
"detail.parent": "父任务",
|
|
@@ -3236,6 +3648,7 @@ window.__ModuleLoader__.load({
|
|
|
3236
3648
|
"detail.noSession": "No session",
|
|
3237
3649
|
"detail.executionStarted": "Started",
|
|
3238
3650
|
"detail.execution.initiator": "Initiated by session {session}",
|
|
3651
|
+
"detail.execution.external": "Completed outside this Host by {agent}",
|
|
3239
3652
|
"detail.executionEnded": "Ended",
|
|
3240
3653
|
"detail.result.succeeded": "Succeeded",
|
|
3241
3654
|
"detail.result.failed": "Failed",
|
|
@@ -3278,7 +3691,34 @@ window.__ModuleLoader__.load({
|
|
|
3278
3691
|
"detail.schedule.duration.hours": "{count}h",
|
|
3279
3692
|
"detail.schedule.duration.minutes": "{count}m",
|
|
3280
3693
|
"detail.schedule.duration.seconds": "{count}s",
|
|
3694
|
+
"detail.schedule.mode": "Mode",
|
|
3695
|
+
"detail.schedule.mode.cron": "Recurring",
|
|
3696
|
+
"detail.schedule.mode.once": "Once",
|
|
3697
|
+
"detail.schedule.at": "Run at",
|
|
3698
|
+
"detail.schedule.atHint": "Planned instant, read in the selected zone; it must be in the future.",
|
|
3699
|
+
"detail.schedule.atInvalid": "Choose a valid future time",
|
|
3700
|
+
"detail.schedule.plannedAt": "Planned time",
|
|
3701
|
+
"detail.schedule.zoneOnceHint": "The chosen instant is read in this zone.",
|
|
3702
|
+
"detail.schedule.maxRuns": "Run limit",
|
|
3703
|
+
"detail.schedule.maxRunsUnlimited": "Unlimited",
|
|
3704
|
+
"detail.schedule.maxRunsValue": "At most {count} runs",
|
|
3705
|
+
"detail.schedule.maxRunsCustom": "Custom",
|
|
3706
|
+
"detail.schedule.maxRunsInvalid": "The run limit must be a positive whole number",
|
|
3707
|
+
"detail.schedule.runs": "Ran {done}/{total}",
|
|
3708
|
+
"detail.schedule.runsUnlimited": "Ran {done}",
|
|
3709
|
+
"detail.schedule.remaining": "{count} left",
|
|
3710
|
+
"detail.schedule.cancel": "Cancel schedule",
|
|
3711
|
+
"detail.schedule.ended": "Schedule ended: {reason}",
|
|
3712
|
+
"detail.schedule.skipped": "Last skip: {reason}",
|
|
3713
|
+
"detail.schedule.stop.fired": "the one-shot ran",
|
|
3714
|
+
"detail.schedule.stop.limit": "the run limit was reached",
|
|
3715
|
+
"detail.schedule.stop.no-target": "the plan has no reachable occurrence",
|
|
3716
|
+
"detail.schedule.stop.missed": "the instant was missed and skipped",
|
|
3717
|
+
"detail.schedule.stop.busy": "the task was already running, so the occurrence was skipped",
|
|
3718
|
+
"detail.schedule.stop.permission": "a permission awaited human confirmation, so the occurrence was skipped",
|
|
3719
|
+
"detail.schedule.stop.launch-failed": "the launch failed before any execution existed, so the run was refunded",
|
|
3281
3720
|
"card.scheduled": "scheduled",
|
|
3721
|
+
"card.scheduledOnce": "once",
|
|
3282
3722
|
"new.workspace": "Workspace",
|
|
3283
3723
|
"new.agentPreset": "Agent preset",
|
|
3284
3724
|
"new.permission": "Permission",
|
|
@@ -3308,7 +3748,7 @@ window.__ModuleLoader__.load({
|
|
|
3308
3748
|
"exec.teamRunUnavailable": "This deployment serves no Agent Teams service, so team runs cannot be enabled.",
|
|
3309
3749
|
"exec.reuseSessionHint": "When on, later runs continue in the previous session (when that session is idle and still exists) instead of starting a new conversation each time; the pinned permission and model above are re-applied on every reuse.",
|
|
3310
3750
|
"exec.goalRun": "Start the run with dsh's built-in /goal",
|
|
3311
|
-
"exec.goalRunHint": "
|
|
3751
|
+
"exec.goalRunHint": "Off by default: when checked, the run arms dsh built-in /goal with the task objective, so the session keeps working automatic continuation rounds until the agent marks the goal complete, and the board settles the execution only when that goal really ends. Unchecked: one plain turn.",
|
|
3312
3752
|
"exec.skipVerification": "Skip acceptance for this task",
|
|
3313
3753
|
"exec.skipVerificationHint": "Off by default: when checked, a goal-form run of this task no longer gates update_goal on a passing acceptance, and the execution record is marked as skipped. It applies only to executions started afterwards, and means nothing while the board-wide acceptance switch is off.",
|
|
3314
3754
|
"detail.executionSettings": "Execution Settings",
|
|
@@ -3341,9 +3781,16 @@ window.__ModuleLoader__.load({
|
|
|
3341
3781
|
"settings.unsaved": "Unsaved",
|
|
3342
3782
|
"settings.saveFailed": "The deployment did not accept these values; they were left for you to correct.",
|
|
3343
3783
|
"settings.invalidNumber": "Enter a number, or leave blank to use the default.",
|
|
3784
|
+
"settings.sessionPollSeconds": "Session poll interval (seconds)",
|
|
3785
|
+
"settings.sessionPollSecondsHint": "Default 5. The Host reads the DSH session roster only while the board has something to reconcile: a running card or an open execution. With neither it stops polling and never re-scans the persisted session directory. Range 1 to 300 seconds: a shorter interval settles runs sooner and costs the Host more.",
|
|
3344
3786
|
"settings.maxSubtaskDepth": "Subtask depth limit",
|
|
3345
3787
|
"settings.maxSubtaskDepthHint": "Default 1: a task may carry one level of subtasks, and a subtask cannot create or link further subtasks. Maximum 3. Running a task also runs its whole subtask tree concurrently, and every extra level opens more sessions per run.",
|
|
3346
3788
|
"settings.maxSubtaskDepthOption": "{depth} levels",
|
|
3789
|
+
"settings.runBehaviorTitle": "Run behavior",
|
|
3790
|
+
"settings.runBehaviorCardHint": "The global native /goal switch (master control, off by default).",
|
|
3791
|
+
"settings.goalRunGlobal": "Global: run tasks with dsh native /goal",
|
|
3792
|
+
"settings.goalRunGlobalHint": "Off by default. While off, every task runs one plain turn and never calls dsh built-in /goal; a run uses native /goal only when this is on AND the task-level option is checked (see the task option below). The task-level checkbox always stays operable and this switch never rewrites it: the master switch only decides whether that choice takes effect. The switch is frozen when an execution starts, so it only affects runs opened afterwards.",
|
|
3793
|
+
"settings.goalRunGlobalDisabledTaskOption": "The global native /goal switch is off: the task-level option can still be checked or cleared, but it has no effect right now and the preference you save is never rewritten; turning the global switch back on applies it. This execution runs one plain turn and performs no goal acceptance.",
|
|
3347
3794
|
"settings.goalVerificationTitle": "Task acceptance",
|
|
3348
3795
|
"settings.goalVerification": "Enable task acceptance",
|
|
3349
3796
|
"settings.goalVerificationCardHint": "The switch, the judge model and the criteria threshold.",
|
|
@@ -3373,6 +3820,7 @@ window.__ModuleLoader__.load({
|
|
|
3373
3820
|
"running.repairing": "Fixing a failed acceptance",
|
|
3374
3821
|
"running.verificationPassed": "Acceptance passed",
|
|
3375
3822
|
"running.verificationFailed": "Acceptance failed",
|
|
3823
|
+
"running.verificationInvalid": "Invalid acceptance, waiting for a human",
|
|
3376
3824
|
"verify.title": "Acceptance report",
|
|
3377
3825
|
"verify.status.passed": "Passed",
|
|
3378
3826
|
"verify.status.failed": "Failed",
|
|
@@ -3380,6 +3828,34 @@ window.__ModuleLoader__.load({
|
|
|
3380
3828
|
"verify.status.verifying": "Verifying",
|
|
3381
3829
|
"verify.status.pending": "Not yet verified",
|
|
3382
3830
|
"verify.status.off": "Acceptance was off for this execution",
|
|
3831
|
+
"verify.status.invalid": "Invalid acceptance",
|
|
3832
|
+
"verify.status.invalidHeld": "Invalid acceptance, waiting for a human",
|
|
3833
|
+
"verify.attemptInvalid": "Invalid acceptance {index}",
|
|
3834
|
+
"verify.invalidReason.missing-finding": "A failing criterion carries no structured finding of its own",
|
|
3835
|
+
"verify.invalidReason.unlocatable-quote": "A finding cites a passage that is not in the evidence the judge saw",
|
|
3836
|
+
"verify.invalidReason.baseline-finding": "A finding points at the empty-work baseline instead of this execution's work",
|
|
3837
|
+
"verify.invalidReason.vacuous-finding": "A finding is empty or a generic evaluation with no observation or difference",
|
|
3838
|
+
"verify.invalidReason.insufficient-evidence": "The judge saw too little evidence (for example a truncated trace) to support a veto",
|
|
3839
|
+
"verify.invalidReason.unknown": "No usable quality verdict was produced",
|
|
3840
|
+
"verify.invalidCounts": "Valid quality verdicts {quality}/{max} · invalid acceptances {invalid}/{maxInvalid} · anomalies {exceptions}/{max}",
|
|
3841
|
+
"verify.invalidDetail": "Invalid because: {reason}",
|
|
3842
|
+
"verify.criterionFindings": "Structured findings (criterion · cited location · verbatim citation)",
|
|
3843
|
+
"verify.criterionFinding": "{criterion} · {location}: \"{quote}\"",
|
|
3844
|
+
"verify.criterionFindingFull": "{criterion} · {location}: \"{quote}\" requirement: {requirement} observed: {observation} gap: {gap}",
|
|
3845
|
+
"verify.location.task": "task statement",
|
|
3846
|
+
"verify.location.trajectory": "execution trajectory",
|
|
3847
|
+
"verify.location.workspace": "host-recorded changes",
|
|
3848
|
+
"verify.location.baseline": "empty-work baseline (not evidence against the work)",
|
|
3849
|
+
"verify.location.unknown": "location not named",
|
|
3850
|
+
"verify.detailRemoved": "This attempt detail was cleaned up automatically after the execution passed and settled (the judge did report evidence).",
|
|
3851
|
+
"verify.cleanup.cleaned": "The acceptance-only detail of this execution was cleaned up automatically after it passed and settled; what remains is the lightweight audit credential.",
|
|
3852
|
+
"verify.cleanup.pending": "The acceptance-only detail is pending cleanup (started once the execution passes and settles).",
|
|
3853
|
+
"verify.cleanup.failed": "Cleaning the acceptance detail failed after {attempts} attempts: {error}. The pass record is still valid and the host retries on its next start.",
|
|
3854
|
+
"verify.cleanup.audit": "Kept credential: attempt {index} · {stage} · score {score} · evidence hash {hash}",
|
|
3855
|
+
"verify.cleanup.stage.quality": "quality verdict",
|
|
3856
|
+
"verify.cleanup.stage.invalid": "invalid acceptance",
|
|
3857
|
+
"verify.cleanup.stage.exception": "acceptance anomaly",
|
|
3858
|
+
"verify.cleanup.stage.budget": "time budget exhausted",
|
|
3383
3859
|
"verify.summary": "Total {score} (threshold {threshold}) · empty-work baseline {baseline}",
|
|
3384
3860
|
"verify.criteria": "Per-criterion scores",
|
|
3385
3861
|
"verify.criterion": "{name}: {score} (threshold {threshold})",
|
|
@@ -3398,9 +3874,10 @@ window.__ModuleLoader__.load({
|
|
|
3398
3874
|
"verify.usageIncomplete": " (at least one request usage is unknown; these counts are a floor)",
|
|
3399
3875
|
"verify.finalFailure": "Verdict basis: {reason}",
|
|
3400
3876
|
"verify.applicability.disabled": "Acceptance was off when this execution started; it settles on the historical verdict.",
|
|
3401
|
-
"verify.applicability.goalUnavailable": "This execution never became a goal run (/goal was refused or unavailable), so acceptance was not enforced.",
|
|
3877
|
+
"verify.applicability.goalUnavailable": "This execution never became a goal run (the card did not check Start with /goal, or /goal was refused or unavailable), so acceptance was not enforced.",
|
|
3402
3878
|
"verify.applicability.skipped": "This card checked Skip acceptance, so the execution was never judged.",
|
|
3403
3879
|
"verify.applicability.teamMember": "Team member: the Lead team-summary evidence is accepted as one execution.",
|
|
3880
|
+
"verify.applicability.goalDisabled": "The global native /goal switch was off when this execution started, so it ran one plain turn: no goal acceptance was performed, which neither counts as a pass nor fails the run.",
|
|
3404
3881
|
"verify.effortFallback": "Reasoning effort fallback: {requested} → {resolved}",
|
|
3405
3882
|
"verify.thresholdValue": "{value}%",
|
|
3406
3883
|
"detail.parent": "Parent task",
|
|
@@ -3812,6 +4289,95 @@ window.__ModuleLoader__.load({
|
|
|
3812
4289
|
if (delta < 0) return t("detail.schedule.nextRunOverdue", { duration: durationParts(-delta) });
|
|
3813
4290
|
return `${durationParts(delta)}`;
|
|
3814
4291
|
}
|
|
4292
|
+
/** Zero-pad a calendar/clock field for a `datetime-local` value. */
|
|
4293
|
+
function pad(value) {
|
|
4294
|
+
return String(value).padStart(2, "0");
|
|
4295
|
+
}
|
|
4296
|
+
/**
|
|
4297
|
+
* The `datetime-local` input value for an instant, read in an explicit zone:
|
|
4298
|
+
* `YYYY-MM-DDTHH:mm`. Uses the shared engine's zone reader, so the editor
|
|
4299
|
+
* shows the same wall clock the Host schedules by.
|
|
4300
|
+
* @param epochMs - the instant to render.
|
|
4301
|
+
* @param timeZone - zone to read it in; absent uses the Host zone.
|
|
4302
|
+
* @returns the input value.
|
|
4303
|
+
*/
|
|
4304
|
+
function zonedInputValue(epochMs, timeZone) {
|
|
4305
|
+
const parts = partsInZone(usableZone(timeZone), epochMs);
|
|
4306
|
+
return `${parts.year}-${pad(parts.month)}-${pad(parts.day)}T${pad(parts.hour)}:${pad(parts.minute)}`;
|
|
4307
|
+
}
|
|
4308
|
+
/**
|
|
4309
|
+
* Parse a `datetime-local` input value back to an instant, read in an explicit
|
|
4310
|
+
* zone. Returns undefined when the text is not a whole calendar wall clock or
|
|
4311
|
+
* names one the zone skips (a spring-forward gap), so the editor can refuse an
|
|
4312
|
+
* unusable instant instead of silently moving it.
|
|
4313
|
+
* @param value - the input text.
|
|
4314
|
+
* @param timeZone - zone to interpret it in; absent uses the Host zone.
|
|
4315
|
+
* @returns the instant, or undefined when it is not a usable wall clock.
|
|
4316
|
+
*/
|
|
4317
|
+
function parseZonedInput(value, timeZone) {
|
|
4318
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})/.exec(value.trim());
|
|
4319
|
+
if (match === null) return void 0;
|
|
4320
|
+
const [year, month, day, hour, minute] = match.slice(1).map(Number);
|
|
4321
|
+
if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59) return void 0;
|
|
4322
|
+
return zonedEpoch(usableZone(timeZone), year, month, day, hour, minute);
|
|
4323
|
+
}
|
|
4324
|
+
/**
|
|
4325
|
+
* The default instant a new one-shot editor opens on: the next whole hour,
|
|
4326
|
+
* rendered in the zone the rule will be read in.
|
|
4327
|
+
* @param now - reference instant.
|
|
4328
|
+
* @param timeZone - zone the rule is read in.
|
|
4329
|
+
* @returns the input value for a near-future default.
|
|
4330
|
+
*/
|
|
4331
|
+
function defaultZonedInputValue(now, timeZone) {
|
|
4332
|
+
return zonedInputValue(Math.ceil(now / 36e5) * 36e5, timeZone);
|
|
4333
|
+
}
|
|
4334
|
+
/** The zone the input helpers resolve against: an explicit resolved zone, or the Host zone. */
|
|
4335
|
+
function usableZone(timeZone) {
|
|
4336
|
+
return timeZone !== void 0 && isValidTimeZone(timeZone) ? timeZone : resolveHostTimeZone();
|
|
4337
|
+
}
|
|
4338
|
+
/**
|
|
4339
|
+
* The editor's run-cap option for a stored cap: the two named presets, the
|
|
4340
|
+
* unlimited entry, or a custom value the editor shows in its own field.
|
|
4341
|
+
* @param maxRuns - the stored cap, when any.
|
|
4342
|
+
* @returns the select option value.
|
|
4343
|
+
*/
|
|
4344
|
+
function runCapOption(maxRuns) {
|
|
4345
|
+
if (maxRuns === void 0) return "unlimited";
|
|
4346
|
+
if (maxRuns === 1) return "1";
|
|
4347
|
+
if (maxRuns === 2) return "2";
|
|
4348
|
+
return "custom";
|
|
4349
|
+
}
|
|
4350
|
+
/** The locale key describing why a rule stopped or skipped an occurrence. */
|
|
4351
|
+
function stopReasonKey(reason) {
|
|
4352
|
+
return `detail.schedule.stop.${reason}`;
|
|
4353
|
+
}
|
|
4354
|
+
/**
|
|
4355
|
+
* The run-budget line: how many scheduled executions the Host opened and how
|
|
4356
|
+
* many remain. Derived from the counter and the cap rather than stored, so the
|
|
4357
|
+
* display cannot drift from the ledger.
|
|
4358
|
+
* @param rule - the schedule rule.
|
|
4359
|
+
* @returns localized wording.
|
|
4360
|
+
*/
|
|
4361
|
+
function budgetLabel(rule) {
|
|
4362
|
+
const budget = scheduleRunBudget(rule);
|
|
4363
|
+
const done = String(rule.runCount);
|
|
4364
|
+
if (budget === void 0) return t("detail.schedule.runsUnlimited", { done });
|
|
4365
|
+
const remaining = Math.max(budget - rule.runCount, 0);
|
|
4366
|
+
return `${t("detail.schedule.runs", {
|
|
4367
|
+
done,
|
|
4368
|
+
total: String(budget)
|
|
4369
|
+
})} · ${t("detail.schedule.remaining", { count: String(remaining) })}`;
|
|
4370
|
+
}
|
|
4371
|
+
/** The line describing a rule that stopped itself, or undefined while it may still fire. */
|
|
4372
|
+
function endedLabel(rule) {
|
|
4373
|
+
if (rule.endedReason === void 0) return void 0;
|
|
4374
|
+
return t("detail.schedule.ended", { reason: t(stopReasonKey(rule.endedReason)) });
|
|
4375
|
+
}
|
|
4376
|
+
/** The line describing the last skipped occurrence, or undefined when none. */
|
|
4377
|
+
function skippedLabel(rule) {
|
|
4378
|
+
if (rule.skippedReason === void 0) return void 0;
|
|
4379
|
+
return t("detail.schedule.skipped", { reason: t(stopReasonKey(rule.skippedReason)) });
|
|
4380
|
+
}
|
|
3815
4381
|
/**
|
|
3816
4382
|
* The full next-run label: the absolute wall clock in the schedule's own zone,
|
|
3817
4383
|
* plus the relative distance in parentheses. Showing both matters because a
|
|
@@ -4474,7 +5040,8 @@ window.__ModuleLoader__.load({
|
|
|
4474
5040
|
verifying: "running.verifying",
|
|
4475
5041
|
repairing: "running.repairing",
|
|
4476
5042
|
passed: "running.verificationPassed",
|
|
4477
|
-
failed: "running.verificationFailed"
|
|
5043
|
+
failed: "running.verificationFailed",
|
|
5044
|
+
invalid: "running.verificationInvalid"
|
|
4478
5045
|
};
|
|
4479
5046
|
/**
|
|
4480
5047
|
* The acceptance label for one open execution, or undefined when acceptance
|
|
@@ -6649,8 +7216,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6649
7216
|
}),
|
|
6650
7217
|
!archived && task.schedule?.enabled === true && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6651
7218
|
className: board_module_css_default.cardSchedule,
|
|
6652
|
-
title: task.schedule.nextRunAt !== void 0 ? `${t("card.scheduled")} · ${formatHostTimestamp(task.schedule.nextRunAt, timeZone)}` : t("card.scheduled"),
|
|
6653
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconClock, { size: 12 }), t("card.scheduled")]
|
|
7219
|
+
title: task.schedule.nextRunAt !== void 0 ? `${t(task.schedule.mode === "once" ? "card.scheduledOnce" : "card.scheduled")} · ${formatHostTimestamp(task.schedule.nextRunAt, timeZone)}` : t(task.schedule.mode === "once" ? "card.scheduledOnce" : "card.scheduled"),
|
|
7220
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconClock, { size: 12 }), t(task.schedule.mode === "once" ? "card.scheduledOnce" : "card.scheduled")]
|
|
6654
7221
|
}),
|
|
6655
7222
|
latest !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6656
7223
|
className: board_module_css_default.cardRun,
|
|
@@ -6765,10 +7332,14 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6765
7332
|
const [model, setModel] = (0, react.useState)(initialTask?.model ?? parentTask?.model ?? "");
|
|
6766
7333
|
const inheritedPermission = parentTask === void 0 ? void 0 : effectiveTaskPermission(parentTask);
|
|
6767
7334
|
const [reuseSession, setReuseSession] = (0, react.useState)(initialTask?.reuseSession ?? false);
|
|
6768
|
-
const [goalRun, setGoalRun] = (0, react.useState)(initialTask?.goalRun ??
|
|
7335
|
+
const [goalRun, setGoalRun] = (0, react.useState)(initialTask?.goalRun ?? false);
|
|
6769
7336
|
const [skipVerification, setSkipVerification] = (0, react.useState)(initialTask?.skipVerification ?? false);
|
|
6770
7337
|
const [scheduleEnabled, setScheduleEnabled] = (0, react.useState)(initialTask?.schedule?.enabled ?? false);
|
|
7338
|
+
const [scheduleMode, setScheduleMode] = (0, react.useState)(initialTask?.schedule?.mode ?? "cron");
|
|
6771
7339
|
const [scheduleCron, setScheduleCron] = (0, react.useState)(initialTask?.schedule?.cron ?? "");
|
|
7340
|
+
const [scheduleAt, setScheduleAt] = (0, react.useState)(() => initialTask?.schedule?.mode === "once" && initialTask.schedule.at !== void 0 ? zonedInputValue(initialTask.schedule.at, initialTask.schedule.timeZone) : defaultZonedInputValue(Date.now(), initialTask?.schedule?.timeZone));
|
|
7341
|
+
const [scheduleMaxRunsChoice, setScheduleMaxRunsChoice] = (0, react.useState)(() => runCapOption(initialTask?.schedule?.maxRuns));
|
|
7342
|
+
const [scheduleMaxRunsText, setScheduleMaxRunsText] = (0, react.useState)(initialTask?.schedule?.maxRuns === void 0 ? "" : String(initialTask.schedule.maxRuns));
|
|
6772
7343
|
const [scheduleZone, setScheduleZone] = (0, react.useState)(initialTask?.schedule?.timeZone ?? "");
|
|
6773
7344
|
const [scheduleError, setScheduleError] = (0, react.useState)(void 0);
|
|
6774
7345
|
const [freezeText, setFreezeText] = (0, react.useState)("");
|
|
@@ -6779,6 +7350,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6779
7350
|
const [error, setError] = (0, react.useState)(void 0);
|
|
6780
7351
|
const [pending, setPending] = (0, react.useState)(false);
|
|
6781
7352
|
const [options, setOptions] = (0, react.useState)(controller.getSnapshot().executionOptions);
|
|
7353
|
+
const [goalRunEnabled, setGoalRunEnabled] = (0, react.useState)(controller.getSnapshot().host?.goalRunEnabled === true);
|
|
6782
7354
|
const [canParse] = (0, react.useState)(controller.getSnapshot().canParseTask === true);
|
|
6783
7355
|
const [parseText, setParseText] = (0, react.useState)("");
|
|
6784
7356
|
const [parseModel, setParseModel] = (0, react.useState)(() => readParseModelPreference());
|
|
@@ -6789,7 +7361,11 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6789
7361
|
const workspaceKnown = workspaceId === "" || options.workspaces.some((item) => item.workspaceId === workspaceId);
|
|
6790
7362
|
const modeKnown = mode === "" || options.presets.some((item) => item.id === mode);
|
|
6791
7363
|
const modelKnown = model === "" || parseModels.some((item) => item.id === model);
|
|
6792
|
-
(0, react.useEffect)(() => controller.subscribe(() =>
|
|
7364
|
+
(0, react.useEffect)(() => controller.subscribe(() => {
|
|
7365
|
+
const snapshot = controller.getSnapshot();
|
|
7366
|
+
setOptions(snapshot.executionOptions);
|
|
7367
|
+
setGoalRunEnabled(snapshot.host?.goalRunEnabled === true);
|
|
7368
|
+
}), [controller]);
|
|
6793
7369
|
(0, react.useEffect)(() => {
|
|
6794
7370
|
if (parseModel === "" || parseModels.length === 0) return;
|
|
6795
7371
|
if (parseModels.some((option) => option.id === parseModel)) return;
|
|
@@ -6828,12 +7404,25 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6828
7404
|
* reporting the creation as failed.
|
|
6829
7405
|
*/
|
|
6830
7406
|
const submit = async (runAfterCreate) => {
|
|
6831
|
-
if (scheduleEnabled) {
|
|
7407
|
+
if (scheduleEnabled) if (scheduleMode === "once") {
|
|
7408
|
+
const at = parseZonedInput(scheduleAt, scheduleZone === "" ? hostTimeZone : scheduleZone);
|
|
7409
|
+
if (at === void 0 || at <= Date.now()) {
|
|
7410
|
+
setScheduleError(t("detail.schedule.atInvalid"));
|
|
7411
|
+
return;
|
|
7412
|
+
}
|
|
7413
|
+
} else {
|
|
6832
7414
|
const cron = scheduleCron.trim();
|
|
6833
7415
|
if (cron === "" || !isValidCron(cron)) {
|
|
6834
7416
|
setScheduleError(t("detail.schedule.invalid"));
|
|
6835
7417
|
return;
|
|
6836
7418
|
}
|
|
7419
|
+
if (scheduleMaxRunsChoice === "custom") {
|
|
7420
|
+
const cap = Number(scheduleMaxRunsText.trim());
|
|
7421
|
+
if (scheduleMaxRunsText.trim() === "" || !Number.isInteger(cap) || cap < 1) {
|
|
7422
|
+
setScheduleError(t("detail.schedule.maxRunsInvalid"));
|
|
7423
|
+
return;
|
|
7424
|
+
}
|
|
7425
|
+
}
|
|
6837
7426
|
}
|
|
6838
7427
|
let freeze = void 0;
|
|
6839
7428
|
if (freezeText.trim() !== "") {
|
|
@@ -6868,12 +7457,19 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6868
7457
|
permission: permission === "" ? void 0 : permission,
|
|
6869
7458
|
model: model === "" ? void 0 : model,
|
|
6870
7459
|
...reuseSession ? { reuseSession: true } : {},
|
|
6871
|
-
...goalRun ? {
|
|
7460
|
+
...goalRun ? { goalRun: true } : {},
|
|
6872
7461
|
...skipVerification ? { skipVerification: true } : {},
|
|
6873
7462
|
...tagList.length > 0 ? { tags: tagList } : {},
|
|
6874
|
-
schedule: scheduleEnabled ? {
|
|
7463
|
+
schedule: scheduleEnabled ? scheduleMode === "once" ? {
|
|
7464
|
+
enabled: true,
|
|
7465
|
+
mode: "once",
|
|
7466
|
+
at: parseZonedInput(scheduleAt, scheduleZone === "" ? hostTimeZone : scheduleZone),
|
|
7467
|
+
...scheduleZone === "" ? {} : { timeZone: scheduleZone }
|
|
7468
|
+
} : {
|
|
6875
7469
|
enabled: true,
|
|
7470
|
+
mode: "cron",
|
|
6876
7471
|
cron: scheduleCron.trim(),
|
|
7472
|
+
...scheduleMaxRunsChoice === "unlimited" ? {} : { maxRuns: scheduleMaxRunsChoice === "custom" ? Number(scheduleMaxRunsText.trim()) : Number(scheduleMaxRunsChoice) },
|
|
6877
7473
|
...scheduleZone === "" ? {} : { timeZone: scheduleZone }
|
|
6878
7474
|
} : void 0
|
|
6879
7475
|
});
|
|
@@ -6891,7 +7487,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6891
7487
|
};
|
|
6892
7488
|
const hostTimeZone = controller.getSnapshot().host?.scheduler.timeZone;
|
|
6893
7489
|
const scheduleTimeZone = scheduleZone === "" ? hostTimeZone : scheduleZone;
|
|
6894
|
-
const scheduleNextRun = scheduleEnabled
|
|
7490
|
+
const scheduleNextRun = !scheduleEnabled ? void 0 : scheduleMode === "once" ? parseZonedInput(scheduleAt, scheduleTimeZone) : scheduleCron.trim() !== "" && isValidCron(scheduleCron) ? nextRunAtMs(scheduleCron, Date.now(), scheduleTimeZone) : void 0;
|
|
6895
7491
|
const modalTitle = parentTask !== void 0 ? t("new.subtaskTitle") : isDuplicate ? t("new.duplicateTitle") : t("board.new");
|
|
6896
7492
|
const builtinPresets = options.presets.filter((preset) => isBuiltinPreset(preset.id));
|
|
6897
7493
|
const customPresets = options.presets.filter((preset) => !isBuiltinPreset(preset.id));
|
|
@@ -6909,9 +7505,9 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6909
7505
|
].join(" · ");
|
|
6910
7506
|
const tagCount = cleanTags(tags).length;
|
|
6911
7507
|
const labelsSummary = tagCount === 0 ? t("new.summary.none") : t("new.summary.labelCount", { count: String(tagCount) });
|
|
6912
|
-
const runSummary = [goalRun ? t("new.summary.multiRound") : t("new.summary.singleRound"), ...reuseSession ? [t("exec.reuseSession")] : []].join(" · ");
|
|
7508
|
+
const runSummary = [goalRun && goalRunEnabled ? t("new.summary.multiRound") : t("new.summary.singleRound"), ...reuseSession ? [t("exec.reuseSession")] : []].join(" · ");
|
|
6913
7509
|
const handoverSummary = freezeText.trim() !== "" || handoverText.trim() !== "" ? t("new.summary.filled") : t("new.summary.none");
|
|
6914
|
-
const scheduleSummary = !scheduleEnabled ? t("new.summary.scheduleOff") : scheduleCron.trim() === "" ? t("new.summary.none") : scheduleCron.trim();
|
|
7510
|
+
const scheduleSummary = !scheduleEnabled ? t("new.summary.scheduleOff") : scheduleMode === "once" ? `${t("detail.schedule.mode.once")} · ${scheduleAt.replace("T", " ")}` : scheduleCron.trim() === "" ? t("new.summary.none") : [scheduleCron.trim(), ...scheduleMaxRunsChoice === "unlimited" ? [] : [t("detail.schedule.maxRunsValue", { count: scheduleMaxRunsChoice === "custom" ? scheduleMaxRunsText : scheduleMaxRunsChoice })]].join(" · ");
|
|
6915
7511
|
const parseSummary = parseText.trim() === "" ? t("new.summary.none") : t("new.summary.filled");
|
|
6916
7512
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ModalShell, {
|
|
6917
7513
|
ariaLabel: modalTitle,
|
|
@@ -7202,6 +7798,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
7202
7798
|
className: board_module_css_default.detailText,
|
|
7203
7799
|
children: t("exec.goalRunHint")
|
|
7204
7800
|
}),
|
|
7801
|
+
!goalRunEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7802
|
+
className: board_module_css_default.detailText,
|
|
7803
|
+
children: t("settings.goalRunGlobalDisabledTaskOption")
|
|
7804
|
+
}),
|
|
7205
7805
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
7206
7806
|
className: board_module_css_default.scheduleToggle,
|
|
7207
7807
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
@@ -7277,36 +7877,116 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
7277
7877
|
}
|
|
7278
7878
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("detail.schedule.enable") })]
|
|
7279
7879
|
}), scheduleEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
7280
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
7281
|
-
className: board_module_css_default.
|
|
7282
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
7283
|
-
className: `${board_module_css_default.input} ${board_module_css_default.scheduleInput}${scheduleError !== void 0 ? ` ${board_module_css_default.scheduleInputInvalid}` : ""}`,
|
|
7284
|
-
value: scheduleCron,
|
|
7285
|
-
placeholder: "0 9 * * *",
|
|
7286
|
-
spellCheck: false,
|
|
7287
|
-
"aria-label": t("detail.schedule.cron"),
|
|
7288
|
-
onChange: (event) => {
|
|
7289
|
-
setScheduleCron(event.target.value);
|
|
7290
|
-
setScheduleError(void 0);
|
|
7291
|
-
}
|
|
7292
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
7880
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
7881
|
+
className: board_module_css_default.scheduleZone,
|
|
7882
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("detail.schedule.mode") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
7293
7883
|
className: board_module_css_default.schedulePreset,
|
|
7294
|
-
value:
|
|
7295
|
-
"aria-label": t("detail.schedule.
|
|
7884
|
+
value: scheduleMode,
|
|
7885
|
+
"aria-label": t("detail.schedule.mode"),
|
|
7296
7886
|
onChange: (event) => {
|
|
7297
|
-
|
|
7298
|
-
setScheduleCron(event.target.value);
|
|
7887
|
+
setScheduleMode(event.target.value);
|
|
7299
7888
|
setScheduleError(void 0);
|
|
7300
7889
|
},
|
|
7301
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
7302
|
-
value: "",
|
|
7303
|
-
children:
|
|
7304
|
-
}),
|
|
7305
|
-
value:
|
|
7306
|
-
children: t(
|
|
7307
|
-
}
|
|
7890
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
7891
|
+
value: "cron",
|
|
7892
|
+
children: t("detail.schedule.mode.cron")
|
|
7893
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
7894
|
+
value: "once",
|
|
7895
|
+
children: t("detail.schedule.mode.once")
|
|
7896
|
+
})]
|
|
7308
7897
|
})]
|
|
7309
7898
|
}),
|
|
7899
|
+
scheduleMode === "once" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
7900
|
+
className: board_module_css_default.scheduleZone,
|
|
7901
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("detail.schedule.at") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
7902
|
+
className: board_module_css_default.input,
|
|
7903
|
+
type: "datetime-local",
|
|
7904
|
+
value: scheduleAt,
|
|
7905
|
+
"aria-label": t("detail.schedule.at"),
|
|
7906
|
+
title: t("detail.schedule.atHint"),
|
|
7907
|
+
onChange: (event) => {
|
|
7908
|
+
setScheduleAt(event.target.value);
|
|
7909
|
+
setScheduleError(void 0);
|
|
7910
|
+
}
|
|
7911
|
+
})]
|
|
7912
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
7913
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7914
|
+
className: board_module_css_default.scheduleRow,
|
|
7915
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
7916
|
+
className: `${board_module_css_default.input} ${board_module_css_default.scheduleInput}${scheduleError !== void 0 ? ` ${board_module_css_default.scheduleInputInvalid}` : ""}`,
|
|
7917
|
+
value: scheduleCron,
|
|
7918
|
+
placeholder: "0 9 * * *",
|
|
7919
|
+
spellCheck: false,
|
|
7920
|
+
"aria-label": t("detail.schedule.cron"),
|
|
7921
|
+
onChange: (event) => {
|
|
7922
|
+
setScheduleCron(event.target.value);
|
|
7923
|
+
setScheduleError(void 0);
|
|
7924
|
+
}
|
|
7925
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
7926
|
+
className: board_module_css_default.schedulePreset,
|
|
7927
|
+
value: "",
|
|
7928
|
+
"aria-label": t("detail.schedule.presets"),
|
|
7929
|
+
onChange: (event) => {
|
|
7930
|
+
if (event.target.value === "") return;
|
|
7931
|
+
setScheduleCron(event.target.value);
|
|
7932
|
+
setScheduleError(void 0);
|
|
7933
|
+
},
|
|
7934
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
|
|
7935
|
+
value: "",
|
|
7936
|
+
children: [t("detail.schedule.presets"), "…"]
|
|
7937
|
+
}), SCHEDULE_PRESETS.map((preset) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
7938
|
+
value: preset.cron,
|
|
7939
|
+
children: t(preset.label)
|
|
7940
|
+
}, preset.cron))]
|
|
7941
|
+
})]
|
|
7942
|
+
}),
|
|
7943
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
7944
|
+
className: board_module_css_default.scheduleZone,
|
|
7945
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("detail.schedule.maxRuns") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
7946
|
+
className: board_module_css_default.schedulePreset,
|
|
7947
|
+
value: scheduleMaxRunsChoice,
|
|
7948
|
+
"aria-label": t("detail.schedule.maxRuns"),
|
|
7949
|
+
onChange: (event) => {
|
|
7950
|
+
setScheduleMaxRunsChoice(event.target.value);
|
|
7951
|
+
setScheduleError(void 0);
|
|
7952
|
+
if (event.target.value === "custom") setScheduleMaxRunsText(initialTask?.schedule?.maxRuns === void 0 ? "" : String(initialTask.schedule.maxRuns));
|
|
7953
|
+
},
|
|
7954
|
+
children: [
|
|
7955
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
7956
|
+
value: "unlimited",
|
|
7957
|
+
children: t("detail.schedule.maxRunsUnlimited")
|
|
7958
|
+
}),
|
|
7959
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
7960
|
+
value: "1",
|
|
7961
|
+
children: t("detail.schedule.maxRunsValue", { count: "1" })
|
|
7962
|
+
}),
|
|
7963
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
7964
|
+
value: "2",
|
|
7965
|
+
children: t("detail.schedule.maxRunsValue", { count: "2" })
|
|
7966
|
+
}),
|
|
7967
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
7968
|
+
value: "custom",
|
|
7969
|
+
children: t("detail.schedule.maxRunsCustom")
|
|
7970
|
+
})
|
|
7971
|
+
]
|
|
7972
|
+
})]
|
|
7973
|
+
}),
|
|
7974
|
+
scheduleMaxRunsChoice === "custom" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
7975
|
+
className: board_module_css_default.scheduleZone,
|
|
7976
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("detail.schedule.maxRuns") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
7977
|
+
className: board_module_css_default.input,
|
|
7978
|
+
type: "number",
|
|
7979
|
+
min: 1,
|
|
7980
|
+
step: 1,
|
|
7981
|
+
value: scheduleMaxRunsText,
|
|
7982
|
+
"aria-label": t("detail.schedule.maxRuns"),
|
|
7983
|
+
onChange: (event) => {
|
|
7984
|
+
setScheduleMaxRunsText(event.target.value);
|
|
7985
|
+
setScheduleError(void 0);
|
|
7986
|
+
}
|
|
7987
|
+
})]
|
|
7988
|
+
})
|
|
7989
|
+
] }),
|
|
7310
7990
|
scheduleError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7311
7991
|
className: board_module_css_default.formError,
|
|
7312
7992
|
children: scheduleError
|
|
@@ -7317,7 +7997,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
7317
7997
|
className: board_module_css_default.schedulePreset,
|
|
7318
7998
|
value: scheduleZone,
|
|
7319
7999
|
"aria-label": t("detail.schedule.timeZone"),
|
|
7320
|
-
title: t("detail.schedule.timeZoneHint"),
|
|
8000
|
+
title: scheduleMode === "once" ? t("detail.schedule.zoneOnceHint") : t("detail.schedule.timeZoneHint"),
|
|
7321
8001
|
onChange: (event) => {
|
|
7322
8002
|
setScheduleZone(event.target.value);
|
|
7323
8003
|
setScheduleError(void 0);
|
|
@@ -7847,11 +8527,39 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
7847
8527
|
verifying: "verify.status.verifying",
|
|
7848
8528
|
repairing: "verify.status.failed",
|
|
7849
8529
|
passed: "verify.status.passed",
|
|
7850
|
-
failed: "verify.status.failed"
|
|
8530
|
+
failed: "verify.status.failed",
|
|
8531
|
+
invalid: "verify.status.invalidHeld"
|
|
7851
8532
|
};
|
|
7852
|
-
/**
|
|
7853
|
-
|
|
7854
|
-
|
|
8533
|
+
/** Evidence location → locale key, for one structured finding's citation. */
|
|
8534
|
+
const LOCATION_KEY = {
|
|
8535
|
+
task: "verify.location.task",
|
|
8536
|
+
trajectory: "verify.location.trajectory",
|
|
8537
|
+
workspace: "verify.location.workspace",
|
|
8538
|
+
baseline: "verify.location.baseline",
|
|
8539
|
+
unknown: "verify.location.unknown"
|
|
8540
|
+
};
|
|
8541
|
+
/** Invalid reason → locale key. */
|
|
8542
|
+
function invalidReasonKey(attempt) {
|
|
8543
|
+
switch (attempt.invalidReason) {
|
|
8544
|
+
case "missing-finding": return "verify.invalidReason.missing-finding";
|
|
8545
|
+
case "unlocatable-quote": return "verify.invalidReason.unlocatable-quote";
|
|
8546
|
+
case "baseline-finding": return "verify.invalidReason.baseline-finding";
|
|
8547
|
+
case "vacuous-finding": return "verify.invalidReason.vacuous-finding";
|
|
8548
|
+
case "insufficient-evidence": return "verify.invalidReason.insufficient-evidence";
|
|
8549
|
+
default: return "verify.invalidReason.unknown";
|
|
8550
|
+
}
|
|
8551
|
+
}
|
|
8552
|
+
/** Audit stage → locale key (the lightweight credential after cleanup). */
|
|
8553
|
+
const AUDIT_STAGE_KEY = {
|
|
8554
|
+
quality: "verify.cleanup.stage.quality",
|
|
8555
|
+
invalid: "verify.cleanup.stage.invalid",
|
|
8556
|
+
exception: "verify.cleanup.stage.exception",
|
|
8557
|
+
budget: "verify.cleanup.stage.budget"
|
|
8558
|
+
};
|
|
8559
|
+
/** One recorded attempt: a quality verdict, an invalid veto, an anomaly, or a budget stop. */
|
|
8560
|
+
function AttemptRow({ attempt, detailRemoved }) {
|
|
8561
|
+
const invalid = attempt.stage === "invalid";
|
|
8562
|
+
const exception = attempt.stage !== "quality" && !invalid;
|
|
7855
8563
|
const result = exception ? "failed" : attempt.passed ? "succeeded" : "failed";
|
|
7856
8564
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
7857
8565
|
className: board_module_css_default.executionRow,
|
|
@@ -7860,17 +8568,21 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
7860
8568
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7861
8569
|
className: board_module_css_default.executionBadge,
|
|
7862
8570
|
"data-result": result,
|
|
7863
|
-
children: exception ? t("verify.status.exception") : attempt.passed ? t("verify.status.passed") : t("verify.status.failed")
|
|
8571
|
+
children: invalid ? t("verify.status.invalid") : exception ? t("verify.status.exception") : attempt.passed ? t("verify.status.passed") : t("verify.status.failed")
|
|
7864
8572
|
}),
|
|
7865
8573
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7866
8574
|
className: board_module_css_default.executionTimes,
|
|
7867
8575
|
children: [
|
|
7868
|
-
exception ? t("verify.attemptException", { index: String(attempt.index) }) : t("verify.attempt", { index: String(attempt.index) }),
|
|
8576
|
+
invalid ? t("verify.attemptInvalid", { index: String(attempt.index) }) : exception ? t("verify.attemptException", { index: String(attempt.index) }) : t("verify.attempt", { index: String(attempt.index) }),
|
|
7869
8577
|
" · ",
|
|
7870
8578
|
routeLabel(attempt),
|
|
7871
|
-
!exception && " · " + t("verify.rounds", { rounds: String(attempt.rounds) })
|
|
8579
|
+
!exception && !invalid && " · " + t("verify.rounds", { rounds: String(attempt.rounds) })
|
|
7872
8580
|
]
|
|
7873
8581
|
}),
|
|
8582
|
+
invalid && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8583
|
+
className: board_module_css_default.executionTimes,
|
|
8584
|
+
children: t("verify.invalidDetail", { reason: t(invalidReasonKey(attempt)) })
|
|
8585
|
+
}),
|
|
7874
8586
|
attempt.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7875
8587
|
className: board_module_css_default.executionTimes,
|
|
7876
8588
|
children: attempt.error
|
|
@@ -7900,6 +8612,23 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
7900
8612
|
}, criterion.id))
|
|
7901
8613
|
})
|
|
7902
8614
|
] }),
|
|
8615
|
+
(attempt.criterionFindings ?? []).length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8616
|
+
className: board_module_css_default.executionTimes,
|
|
8617
|
+
children: t("verify.criterionFindings")
|
|
8618
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
8619
|
+
className: board_module_css_default.executionList,
|
|
8620
|
+
children: (attempt.criterionFindings ?? []).map((finding, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
8621
|
+
className: board_module_css_default.executionTimes,
|
|
8622
|
+
children: t("verify.criterionFindingFull", {
|
|
8623
|
+
criterion: finding.criterionId,
|
|
8624
|
+
location: t(LOCATION_KEY[finding.location]),
|
|
8625
|
+
quote: finding.quote,
|
|
8626
|
+
requirement: finding.requirement,
|
|
8627
|
+
observation: finding.observation,
|
|
8628
|
+
gap: finding.gap
|
|
8629
|
+
})
|
|
8630
|
+
}, findingKey(attempt, index)))
|
|
8631
|
+
})] }),
|
|
7903
8632
|
attempt.findings.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7904
8633
|
className: board_module_css_default.executionTimes,
|
|
7905
8634
|
children: t("verify.findings")
|
|
@@ -7910,9 +8639,9 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
7910
8639
|
children: finding
|
|
7911
8640
|
}, findingKey(attempt, index)))
|
|
7912
8641
|
})] }),
|
|
7913
|
-
!exception && attempt.findings.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8642
|
+
!exception && !invalid && attempt.findings.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7914
8643
|
className: board_module_css_default.executionTimes,
|
|
7915
|
-
children: t("verify.noFindings")
|
|
8644
|
+
children: t(detailRemoved ? "verify.detailRemoved" : "verify.noFindings")
|
|
7916
8645
|
}),
|
|
7917
8646
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7918
8647
|
className: board_module_css_default.executionTimes,
|
|
@@ -7948,7 +8677,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
7948
8677
|
if (phase === "off" && verification.contract.enabled === false && verification.applicability !== "skipped") return null;
|
|
7949
8678
|
const totals = verificationTotals(verification);
|
|
7950
8679
|
const route = verification.contract.route;
|
|
7951
|
-
const applicabilityKey = verification.applicability === "disabled" ? "verify.applicability.disabled" : verification.applicability === "skipped" ? "verify.applicability.skipped" : verification.applicability === "goal-unavailable" ? "verify.applicability.goalUnavailable" : verification.applicability === "team-member" ? "verify.applicability.teamMember" : void 0;
|
|
8680
|
+
const applicabilityKey = verification.applicability === "disabled" ? "verify.applicability.disabled" : verification.applicability === "skipped" ? "verify.applicability.skipped" : verification.applicability === "goal-unavailable" ? "verify.applicability.goalUnavailable" : verification.applicability === "goal-disabled" ? "verify.applicability.goalDisabled" : verification.applicability === "team-member" ? "verify.applicability.teamMember" : void 0;
|
|
7952
8681
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7953
8682
|
className: board_module_css_default.executionTimes,
|
|
7954
8683
|
children: [
|
|
@@ -7963,9 +8692,11 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
7963
8692
|
}),
|
|
7964
8693
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7965
8694
|
className: board_module_css_default.executionTimes,
|
|
7966
|
-
children: t("verify.
|
|
8695
|
+
children: t("verify.invalidCounts", {
|
|
7967
8696
|
quality: String(qualityAttempts(verification).length),
|
|
7968
8697
|
max: String(2),
|
|
8698
|
+
invalid: String(invalidAttempts(verification).length),
|
|
8699
|
+
maxInvalid: String(2),
|
|
7969
8700
|
exceptions: String(exceptionAttempts(verification).length)
|
|
7970
8701
|
})
|
|
7971
8702
|
}),
|
|
@@ -8002,11 +8733,45 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8002
8733
|
}),
|
|
8003
8734
|
verification.attempts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
8004
8735
|
className: board_module_css_default.executionList,
|
|
8005
|
-
children: [...verification.attempts].reverse().map((attempt) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttemptRow, {
|
|
8006
|
-
|
|
8736
|
+
children: [...verification.attempts].reverse().map((attempt) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AttemptRow, {
|
|
8737
|
+
attempt,
|
|
8738
|
+
detailRemoved: verification.cleanup?.state === "cleaned"
|
|
8739
|
+
}, attempt.at.toString(36) + "-" + attempt.stage + "-" + String(attempt.index)))
|
|
8740
|
+
}),
|
|
8741
|
+
verification.cleanup !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CleanupNotice, { cleanup: verification.cleanup })
|
|
8007
8742
|
]
|
|
8008
8743
|
});
|
|
8009
8744
|
}
|
|
8745
|
+
/**
|
|
8746
|
+
* Retention notice of one execution's acceptance detail.
|
|
8747
|
+
*
|
|
8748
|
+
* It exists so a reader never mistakes a cleaned-up report for a judge that
|
|
8749
|
+
* produced no evidence: the notice says the detail WAS produced and was removed
|
|
8750
|
+
* by the automatic cleanup, and lists the lightweight credential that survives.
|
|
8751
|
+
* A pending or failed cleanup is reported the same way — never as a missing
|
|
8752
|
+
* verdict and never as a revoked pass.
|
|
8753
|
+
*/
|
|
8754
|
+
function CleanupNotice({ cleanup }) {
|
|
8755
|
+
const key = cleanup.state === "cleaned" ? "verify.cleanup.cleaned" : cleanup.state === "failed" ? "verify.cleanup.failed" : "verify.cleanup.pending";
|
|
8756
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8757
|
+
className: board_module_css_default.executionTimes,
|
|
8758
|
+
children: cleanup.state === "failed" ? t(key, {
|
|
8759
|
+
attempts: String(cleanup.attempts),
|
|
8760
|
+
error: cleanup.lastError ?? ""
|
|
8761
|
+
}) : t(key)
|
|
8762
|
+
}), cleanup.audit.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
8763
|
+
className: board_module_css_default.executionList,
|
|
8764
|
+
children: cleanup.audit.map((record, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
8765
|
+
className: board_module_css_default.executionTimes,
|
|
8766
|
+
children: [t("verify.cleanup.audit", {
|
|
8767
|
+
index: String(index + 1),
|
|
8768
|
+
stage: t(AUDIT_STAGE_KEY[record.stage]),
|
|
8769
|
+
score: percent(record.score),
|
|
8770
|
+
hash: record.evidenceHash.slice(0, 12)
|
|
8771
|
+
}), record.findingSummary === void 0 ? "" : " · " + record.findingSummary]
|
|
8772
|
+
}, record.at.toString(36) + "-" + record.stage + "-" + String(index)))
|
|
8773
|
+
})] });
|
|
8774
|
+
}
|
|
8010
8775
|
//#endregion
|
|
8011
8776
|
//#region src/client/board/ClampedMarkdown.tsx
|
|
8012
8777
|
/**
|
|
@@ -8079,9 +8844,11 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8079
8844
|
/** One execution-history row. */
|
|
8080
8845
|
function ExecutionRow({ execution, timeZone, onOpen }) {
|
|
8081
8846
|
const result = execution.result;
|
|
8847
|
+
const external = execution.external === true;
|
|
8082
8848
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
8083
8849
|
className: board_module_css_default.executionRow,
|
|
8084
8850
|
"data-result": result,
|
|
8851
|
+
"data-external": external ? "true" : void 0,
|
|
8085
8852
|
children: [
|
|
8086
8853
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8087
8854
|
className: board_module_css_default.executionBadge,
|
|
@@ -8097,7 +8864,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8097
8864
|
execution.endedAt !== void 0 && ` · ${t("detail.executionEnded")} ${formatTime(execution.endedAt, timeZone)}`
|
|
8098
8865
|
]
|
|
8099
8866
|
}),
|
|
8100
|
-
execution.initiatedBy !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8867
|
+
external && execution.initiatedBy !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8868
|
+
className: board_module_css_default.executionTimes,
|
|
8869
|
+
title: execution.initiatedBy,
|
|
8870
|
+
children: t("detail.execution.external", { agent: execution.initiatedBy })
|
|
8871
|
+
}),
|
|
8872
|
+
!external && execution.initiatedBy !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8101
8873
|
className: board_module_css_default.executionTimes,
|
|
8102
8874
|
title: execution.initiatedBy,
|
|
8103
8875
|
children: t("detail.execution.initiator", { session: execution.initiatedBy })
|
|
@@ -8120,7 +8892,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8120
8892
|
});
|
|
8121
8893
|
}
|
|
8122
8894
|
/** The execution-target editor: workspace / mode / permission pickers. */
|
|
8123
|
-
function ExecutionSettingsSection({ controller, task, pending, executionOptions, teamRunAvailable }) {
|
|
8895
|
+
function ExecutionSettingsSection({ controller, task, pending, executionOptions, teamRunAvailable, goalRunEnabled }) {
|
|
8124
8896
|
const options = executionOptions;
|
|
8125
8897
|
const workspaceId = task.workspaceId ?? "";
|
|
8126
8898
|
const mode = task.mode ?? "";
|
|
@@ -8266,7 +9038,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8266
9038
|
className: board_module_css_default.scheduleToggle,
|
|
8267
9039
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
8268
9040
|
type: "checkbox",
|
|
8269
|
-
checked: task.goalRun
|
|
9041
|
+
checked: task.goalRun === true,
|
|
8270
9042
|
disabled: pending,
|
|
8271
9043
|
onChange: (event) => {
|
|
8272
9044
|
controller.updateTask(task.id, { goalRun: event.target.checked });
|
|
@@ -8277,6 +9049,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8277
9049
|
className: board_module_css_default.detailText,
|
|
8278
9050
|
children: t("exec.goalRunHint")
|
|
8279
9051
|
}),
|
|
9052
|
+
!goalRunEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9053
|
+
className: board_module_css_default.detailText,
|
|
9054
|
+
children: t("settings.goalRunGlobalDisabledTaskOption")
|
|
9055
|
+
}),
|
|
8280
9056
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
8281
9057
|
className: board_module_css_default.scheduleToggle,
|
|
8282
9058
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
@@ -8310,31 +9086,48 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8310
9086
|
]
|
|
8311
9087
|
});
|
|
8312
9088
|
}
|
|
8313
|
-
/**
|
|
9089
|
+
/**
|
|
9090
|
+
* The scheduled-runs editor. A one-shot has one planned instant; a recurring
|
|
9091
|
+
* rule has a cron expression, an optional run cap, and a zone. The editor
|
|
9092
|
+
* shows the rule's own state (next target, run counter, stop/skip record) and
|
|
9093
|
+
* can cancel a future plan.
|
|
9094
|
+
*/
|
|
8314
9095
|
function ScheduleSection({ controller, task, pending }) {
|
|
8315
9096
|
const schedule = task.schedule;
|
|
9097
|
+
const hostTimeZone = controller.getSnapshot().host?.scheduler.timeZone;
|
|
9098
|
+
const [zone, setZone] = (0, react.useState)(schedule?.timeZone ?? "");
|
|
9099
|
+
const [mode, setMode] = (0, react.useState)(schedule?.mode ?? "cron");
|
|
8316
9100
|
const [cron, setCron] = (0, react.useState)(schedule?.cron ?? "0 9 * * *");
|
|
9101
|
+
const [atText, setAtText] = (0, react.useState)(() => schedule?.at === void 0 ? defaultZonedInputValue(Date.now(), schedule?.timeZone ?? hostTimeZone) : zonedInputValue(schedule.at, schedule?.timeZone ?? hostTimeZone));
|
|
9102
|
+
const [maxRunsChoice, setMaxRunsChoice] = (0, react.useState)(() => runCapOption(schedule?.maxRuns));
|
|
9103
|
+
const [maxRunsText, setMaxRunsText] = (0, react.useState)(schedule?.maxRuns === void 0 ? "" : String(schedule.maxRuns));
|
|
8317
9104
|
const [enabled, setEnabled] = (0, react.useState)(schedule?.enabled ?? false);
|
|
8318
9105
|
const [nextRunAt, setNextRunAt] = (0, react.useState)(schedule?.nextRunAt);
|
|
8319
9106
|
const [lastTriggeredAt, setLastTriggeredAt] = (0, react.useState)(schedule?.lastTriggeredAt);
|
|
8320
9107
|
const [error, setError] = (0, react.useState)(void 0);
|
|
8321
|
-
const hostTimeZone = controller.getSnapshot().host?.scheduler.timeZone;
|
|
8322
|
-
const [zone, setZone] = (0, react.useState)(schedule?.timeZone ?? "");
|
|
8323
9108
|
const now = Date.now();
|
|
8324
9109
|
(0, react.useEffect)(() => {
|
|
9110
|
+
setMode(schedule?.mode ?? "cron");
|
|
8325
9111
|
setCron(schedule?.cron ?? "0 9 * * *");
|
|
9112
|
+
setZone(schedule?.timeZone ?? "");
|
|
9113
|
+
setAtText(schedule?.at === void 0 ? defaultZonedInputValue(Date.now(), schedule?.timeZone ?? hostTimeZone) : zonedInputValue(schedule.at, schedule?.timeZone ?? hostTimeZone));
|
|
9114
|
+
setMaxRunsChoice(runCapOption(schedule?.maxRuns));
|
|
9115
|
+
setMaxRunsText(schedule?.maxRuns === void 0 ? "" : String(schedule.maxRuns));
|
|
8326
9116
|
setEnabled(schedule?.enabled ?? false);
|
|
8327
9117
|
setNextRunAt(schedule?.nextRunAt);
|
|
8328
9118
|
setLastTriggeredAt(schedule?.lastTriggeredAt);
|
|
8329
|
-
setZone(schedule?.timeZone ?? "");
|
|
8330
9119
|
setError(void 0);
|
|
8331
9120
|
}, [
|
|
8332
9121
|
task.id,
|
|
9122
|
+
hostTimeZone,
|
|
9123
|
+
schedule?.mode,
|
|
8333
9124
|
schedule?.enabled,
|
|
8334
9125
|
schedule?.cron,
|
|
9126
|
+
schedule?.at,
|
|
8335
9127
|
schedule?.timeZone,
|
|
8336
9128
|
schedule?.nextRunAt,
|
|
8337
|
-
schedule?.lastTriggeredAt
|
|
9129
|
+
schedule?.lastTriggeredAt,
|
|
9130
|
+
schedule?.maxRuns
|
|
8338
9131
|
]);
|
|
8339
9132
|
/** Validate + persist the current cron text (Enter or blur). */
|
|
8340
9133
|
const saveCron = (value) => {
|
|
@@ -8345,19 +9138,113 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8345
9138
|
return;
|
|
8346
9139
|
}
|
|
8347
9140
|
setError(void 0);
|
|
8348
|
-
controller.setSchedule(task.id, {
|
|
9141
|
+
controller.setSchedule(task.id, {
|
|
9142
|
+
mode: "cron",
|
|
9143
|
+
cron: trimmed
|
|
9144
|
+
});
|
|
9145
|
+
};
|
|
9146
|
+
/** Validate + persist the one-shot's planned instant. */
|
|
9147
|
+
const saveAt = (value) => {
|
|
9148
|
+
setAtText(value);
|
|
9149
|
+
const at = parseZonedInput(value, effectiveZone);
|
|
9150
|
+
if (at === void 0 || at <= now) {
|
|
9151
|
+
setError(t("detail.schedule.atInvalid"));
|
|
9152
|
+
return;
|
|
9153
|
+
}
|
|
9154
|
+
setError(void 0);
|
|
9155
|
+
controller.setSchedule(task.id, {
|
|
9156
|
+
mode: "once",
|
|
9157
|
+
at
|
|
9158
|
+
});
|
|
9159
|
+
};
|
|
9160
|
+
/** Switch the kind of plan, persisting a usable target for the new kind. */
|
|
9161
|
+
const changeMode = (next) => {
|
|
9162
|
+
if (next === "once") {
|
|
9163
|
+
const at = parseZonedInput(atText, effectiveZone);
|
|
9164
|
+
if (at === void 0 || at <= now) {
|
|
9165
|
+
setError(t("detail.schedule.atInvalid"));
|
|
9166
|
+
return;
|
|
9167
|
+
}
|
|
9168
|
+
setMode("once");
|
|
9169
|
+
setError(void 0);
|
|
9170
|
+
controller.setSchedule(task.id, {
|
|
9171
|
+
mode: "once",
|
|
9172
|
+
at
|
|
9173
|
+
});
|
|
9174
|
+
return;
|
|
9175
|
+
}
|
|
9176
|
+
const trimmed = cron.trim();
|
|
9177
|
+
if (trimmed === "" || !isValidCron(trimmed)) {
|
|
9178
|
+
setError(t("detail.schedule.invalid"));
|
|
9179
|
+
return;
|
|
9180
|
+
}
|
|
9181
|
+
setMode("cron");
|
|
9182
|
+
setError(void 0);
|
|
9183
|
+
controller.setSchedule(task.id, {
|
|
9184
|
+
mode: "cron",
|
|
9185
|
+
cron: trimmed
|
|
9186
|
+
});
|
|
8349
9187
|
};
|
|
8350
9188
|
/**
|
|
8351
9189
|
* Change the rule's zone. `''` clears the stored zone, which is how a user
|
|
8352
|
-
* returns a rule to following the Host zone.
|
|
9190
|
+
* returns a rule to following the Host zone. A one-shot's instant is
|
|
9191
|
+
* absolute, so only its rendered wall clock follows the new zone; a cron
|
|
9192
|
+
* rule's wall clock itself moves with the zone.
|
|
8353
9193
|
*/
|
|
8354
9194
|
const changeZone = (value) => {
|
|
8355
9195
|
setZone(value);
|
|
8356
9196
|
setError(void 0);
|
|
9197
|
+
if (mode === "once" && schedule?.at !== void 0) {
|
|
9198
|
+
setAtText(zonedInputValue(schedule.at, value === "" ? hostTimeZone : value));
|
|
9199
|
+
controller.setSchedule(task.id, {
|
|
9200
|
+
mode: "once",
|
|
9201
|
+
timeZone: value === "" ? null : value
|
|
9202
|
+
});
|
|
9203
|
+
return;
|
|
9204
|
+
}
|
|
8357
9205
|
controller.setSchedule(task.id, { timeZone: value === "" ? null : value });
|
|
8358
9206
|
};
|
|
8359
|
-
/**
|
|
9207
|
+
/** Change the recurring rule's run cap (unlimited, a preset, or a custom value). */
|
|
9208
|
+
const applyMaxRuns = (choice) => {
|
|
9209
|
+
setMaxRunsChoice(choice);
|
|
9210
|
+
setError(void 0);
|
|
9211
|
+
if (choice === "unlimited") {
|
|
9212
|
+
controller.setSchedule(task.id, { maxRuns: null });
|
|
9213
|
+
return;
|
|
9214
|
+
}
|
|
9215
|
+
if (choice === "custom") {
|
|
9216
|
+
setMaxRunsText(schedule?.maxRuns === void 0 ? "" : String(schedule.maxRuns));
|
|
9217
|
+
return;
|
|
9218
|
+
}
|
|
9219
|
+
controller.setSchedule(task.id, { maxRuns: Number(choice) });
|
|
9220
|
+
};
|
|
9221
|
+
/** Persist a custom run cap; a non-positive or fractional value is refused. */
|
|
9222
|
+
const saveCustomMaxRuns = (value) => {
|
|
9223
|
+
setMaxRunsText(value);
|
|
9224
|
+
const parsed = Number(value.trim());
|
|
9225
|
+
if (value.trim() === "" || !Number.isInteger(parsed) || parsed < 1) {
|
|
9226
|
+
setError(t("detail.schedule.maxRunsInvalid"));
|
|
9227
|
+
return;
|
|
9228
|
+
}
|
|
9229
|
+
setError(void 0);
|
|
9230
|
+
controller.setSchedule(task.id, { maxRuns: parsed });
|
|
9231
|
+
};
|
|
9232
|
+
/** Arm/disarm the schedule (arming first persists the edited plan). */
|
|
8360
9233
|
const toggleEnabled = (next) => {
|
|
9234
|
+
if (next && mode === "once") {
|
|
9235
|
+
const at = parseZonedInput(atText, effectiveZone);
|
|
9236
|
+
if (at === void 0 || at <= now) {
|
|
9237
|
+
setError(t("detail.schedule.atInvalid"));
|
|
9238
|
+
return;
|
|
9239
|
+
}
|
|
9240
|
+
setError(void 0);
|
|
9241
|
+
if (controller.setSchedule(task.id, {
|
|
9242
|
+
mode: "once",
|
|
9243
|
+
at,
|
|
9244
|
+
enabled: true
|
|
9245
|
+
}) && !controller.isHostBacked()) setEnabled(true);
|
|
9246
|
+
return;
|
|
9247
|
+
}
|
|
8361
9248
|
const trimmed = cron.trim();
|
|
8362
9249
|
if (next && (trimmed === "" || !isValidCron(trimmed))) {
|
|
8363
9250
|
setError(t("detail.schedule.invalid"));
|
|
@@ -8369,16 +9256,28 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8369
9256
|
...next && trimmed !== schedule?.cron ? { cron: trimmed } : {}
|
|
8370
9257
|
}) && !controller.isHostBacked()) setEnabled(next);
|
|
8371
9258
|
};
|
|
9259
|
+
/** Drop every future trigger without touching the card's execution history. */
|
|
9260
|
+
const cancelSchedule = () => {
|
|
9261
|
+
setError(void 0);
|
|
9262
|
+
if (controller.setSchedule(task.id, { enabled: false }) && !controller.isHostBacked()) setEnabled(false);
|
|
9263
|
+
};
|
|
8372
9264
|
const applyPreset = (preset) => {
|
|
8373
9265
|
if (preset === "") return;
|
|
8374
9266
|
setCron(preset);
|
|
9267
|
+
setMode("cron");
|
|
8375
9268
|
setError(void 0);
|
|
8376
|
-
controller.setSchedule(task.id, {
|
|
9269
|
+
controller.setSchedule(task.id, {
|
|
9270
|
+
mode: "cron",
|
|
9271
|
+
cron: preset
|
|
9272
|
+
});
|
|
8377
9273
|
};
|
|
8378
9274
|
const effectiveZone = zone === "" ? hostTimeZone : zone;
|
|
8379
9275
|
const nextLabel = !enabled || nextRunAt === void 0 ? t("detail.schedule.notScheduled") : nextRunAt <= now ? t("detail.schedule.dueSoon") : nextRunLabel(nextRunAt, effectiveZone, formatHostTimestamp, now);
|
|
8380
9276
|
const lastLabel = lastTriggeredAt === void 0 ? "—" : formatHostTimestamp(lastTriggeredAt, effectiveZone);
|
|
8381
9277
|
const zones = zoneChoices(hostTimeZone, schedule?.timeZone);
|
|
9278
|
+
const budget = schedule === void 0 ? void 0 : budgetLabel(schedule);
|
|
9279
|
+
const ended = schedule === void 0 ? void 0 : endedLabel(schedule);
|
|
9280
|
+
const skipped = schedule === void 0 ? void 0 : skippedLabel(schedule);
|
|
8382
9281
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
8383
9282
|
className: board_module_css_default.detailSection,
|
|
8384
9283
|
children: [
|
|
@@ -8394,42 +9293,128 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8394
9293
|
}
|
|
8395
9294
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("detail.schedule.enable") })]
|
|
8396
9295
|
}),
|
|
8397
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
8398
|
-
className: board_module_css_default.
|
|
8399
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
8400
|
-
className:
|
|
8401
|
-
value:
|
|
9296
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
9297
|
+
className: board_module_css_default.scheduleZone,
|
|
9298
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("detail.schedule.mode") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
9299
|
+
className: board_module_css_default.schedulePreset,
|
|
9300
|
+
value: mode,
|
|
8402
9301
|
disabled: pending,
|
|
8403
|
-
|
|
8404
|
-
spellCheck: false,
|
|
8405
|
-
"aria-label": t("detail.schedule.cron"),
|
|
9302
|
+
"aria-label": t("detail.schedule.mode"),
|
|
8406
9303
|
onChange: (event) => {
|
|
8407
|
-
|
|
8408
|
-
setError(void 0);
|
|
9304
|
+
changeMode(event.target.value);
|
|
8409
9305
|
},
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
9306
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
9307
|
+
value: "cron",
|
|
9308
|
+
children: t("detail.schedule.mode.cron")
|
|
9309
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
9310
|
+
value: "once",
|
|
9311
|
+
children: t("detail.schedule.mode.once")
|
|
9312
|
+
})]
|
|
9313
|
+
})]
|
|
9314
|
+
}),
|
|
9315
|
+
mode === "once" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
9316
|
+
className: board_module_css_default.scheduleZone,
|
|
9317
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("detail.schedule.at") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
9318
|
+
className: board_module_css_default.input,
|
|
9319
|
+
type: "datetime-local",
|
|
9320
|
+
value: atText,
|
|
8419
9321
|
disabled: pending,
|
|
8420
|
-
"aria-label": t("detail.schedule.
|
|
9322
|
+
"aria-label": t("detail.schedule.at"),
|
|
9323
|
+
title: t("detail.schedule.atHint"),
|
|
8421
9324
|
onChange: (event) => {
|
|
8422
|
-
|
|
9325
|
+
setAtText(event.target.value);
|
|
9326
|
+
setError(void 0);
|
|
8423
9327
|
},
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
}), SCHEDULE_PRESETS.map((preset) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
8428
|
-
value: preset.cron,
|
|
8429
|
-
children: t(preset.label)
|
|
8430
|
-
}, preset.cron))]
|
|
9328
|
+
onBlur: () => {
|
|
9329
|
+
saveAt(atText);
|
|
9330
|
+
}
|
|
8431
9331
|
})]
|
|
8432
|
-
}),
|
|
9332
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
9333
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9334
|
+
className: board_module_css_default.scheduleRow,
|
|
9335
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
9336
|
+
className: `${board_module_css_default.input} ${board_module_css_default.scheduleInput}${error !== void 0 ? ` ${board_module_css_default.scheduleInputInvalid}` : ""}`,
|
|
9337
|
+
value: cron,
|
|
9338
|
+
disabled: pending,
|
|
9339
|
+
placeholder: "0 9 * * *",
|
|
9340
|
+
spellCheck: false,
|
|
9341
|
+
"aria-label": t("detail.schedule.cron"),
|
|
9342
|
+
onChange: (event) => {
|
|
9343
|
+
setCron(event.target.value);
|
|
9344
|
+
setError(void 0);
|
|
9345
|
+
},
|
|
9346
|
+
onBlur: () => {
|
|
9347
|
+
saveCron(cron);
|
|
9348
|
+
},
|
|
9349
|
+
onKeyDown: (event) => {
|
|
9350
|
+
if (event.key === "Enter") saveCron(cron);
|
|
9351
|
+
}
|
|
9352
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
9353
|
+
className: board_module_css_default.schedulePreset,
|
|
9354
|
+
value: "",
|
|
9355
|
+
disabled: pending,
|
|
9356
|
+
"aria-label": t("detail.schedule.presets"),
|
|
9357
|
+
onChange: (event) => {
|
|
9358
|
+
applyPreset(event.target.value);
|
|
9359
|
+
},
|
|
9360
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
|
|
9361
|
+
value: "",
|
|
9362
|
+
children: [t("detail.schedule.presets"), "…"]
|
|
9363
|
+
}), SCHEDULE_PRESETS.map((preset) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
9364
|
+
value: preset.cron,
|
|
9365
|
+
children: t(preset.label)
|
|
9366
|
+
}, preset.cron))]
|
|
9367
|
+
})]
|
|
9368
|
+
}),
|
|
9369
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
9370
|
+
className: board_module_css_default.scheduleZone,
|
|
9371
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("detail.schedule.maxRuns") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
9372
|
+
className: board_module_css_default.schedulePreset,
|
|
9373
|
+
value: maxRunsChoice,
|
|
9374
|
+
disabled: pending,
|
|
9375
|
+
"aria-label": t("detail.schedule.maxRuns"),
|
|
9376
|
+
onChange: (event) => {
|
|
9377
|
+
applyMaxRuns(event.target.value);
|
|
9378
|
+
},
|
|
9379
|
+
children: [
|
|
9380
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
9381
|
+
value: "unlimited",
|
|
9382
|
+
children: t("detail.schedule.maxRunsUnlimited")
|
|
9383
|
+
}),
|
|
9384
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
9385
|
+
value: "1",
|
|
9386
|
+
children: t("detail.schedule.maxRunsValue", { count: "1" })
|
|
9387
|
+
}),
|
|
9388
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
9389
|
+
value: "2",
|
|
9390
|
+
children: t("detail.schedule.maxRunsValue", { count: "2" })
|
|
9391
|
+
}),
|
|
9392
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
9393
|
+
value: "custom",
|
|
9394
|
+
children: t("detail.schedule.maxRunsCustom")
|
|
9395
|
+
})
|
|
9396
|
+
]
|
|
9397
|
+
})]
|
|
9398
|
+
}),
|
|
9399
|
+
maxRunsChoice === "custom" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
9400
|
+
className: board_module_css_default.scheduleZone,
|
|
9401
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("detail.schedule.maxRuns") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
9402
|
+
className: board_module_css_default.input,
|
|
9403
|
+
type: "number",
|
|
9404
|
+
min: 1,
|
|
9405
|
+
step: 1,
|
|
9406
|
+
value: maxRunsText,
|
|
9407
|
+
disabled: pending,
|
|
9408
|
+
"aria-label": t("detail.schedule.maxRuns"),
|
|
9409
|
+
onChange: (event) => {
|
|
9410
|
+
setMaxRunsText(event.target.value);
|
|
9411
|
+
},
|
|
9412
|
+
onBlur: () => {
|
|
9413
|
+
saveCustomMaxRuns(maxRunsText);
|
|
9414
|
+
}
|
|
9415
|
+
})]
|
|
9416
|
+
})
|
|
9417
|
+
] }),
|
|
8433
9418
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
8434
9419
|
className: board_module_css_default.scheduleZone,
|
|
8435
9420
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("detail.schedule.timeZone") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
@@ -8437,7 +9422,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8437
9422
|
value: zone,
|
|
8438
9423
|
disabled: pending,
|
|
8439
9424
|
"aria-label": t("detail.schedule.timeZone"),
|
|
8440
|
-
title: t("detail.schedule.timeZoneHint"),
|
|
9425
|
+
title: mode === "once" ? t("detail.schedule.zoneOnceHint") : t("detail.schedule.timeZoneHint"),
|
|
8441
9426
|
onChange: (event) => {
|
|
8442
9427
|
changeZone(event.target.value);
|
|
8443
9428
|
},
|
|
@@ -8462,6 +9447,25 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8462
9447
|
" ",
|
|
8463
9448
|
lastLabel
|
|
8464
9449
|
]
|
|
9450
|
+
}),
|
|
9451
|
+
budget !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9452
|
+
className: board_module_css_default.scheduleMeta,
|
|
9453
|
+
children: budget
|
|
9454
|
+
}),
|
|
9455
|
+
ended !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9456
|
+
className: board_module_css_default.scheduleMeta,
|
|
9457
|
+
children: ended
|
|
9458
|
+
}),
|
|
9459
|
+
ended === void 0 && skipped !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9460
|
+
className: board_module_css_default.scheduleMeta,
|
|
9461
|
+
children: skipped
|
|
9462
|
+
}),
|
|
9463
|
+
enabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9464
|
+
type: "button",
|
|
9465
|
+
className: board_module_css_default.ghostButton,
|
|
9466
|
+
disabled: pending,
|
|
9467
|
+
onClick: cancelSchedule,
|
|
9468
|
+
children: t("detail.schedule.cancel")
|
|
8465
9469
|
})
|
|
8466
9470
|
]
|
|
8467
9471
|
});
|
|
@@ -8818,7 +9822,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
8818
9822
|
task: current,
|
|
8819
9823
|
pending,
|
|
8820
9824
|
executionOptions: snapshot.executionOptions,
|
|
8821
|
-
teamRunAvailable: snapshot.host?.teamRunAvailable === true
|
|
9825
|
+
teamRunAvailable: snapshot.host?.teamRunAvailable === true,
|
|
9826
|
+
goalRunEnabled: snapshot.host?.goalRunEnabled === true
|
|
8822
9827
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScheduleSection, {
|
|
8823
9828
|
controller,
|
|
8824
9829
|
task: current,
|
|
@@ -9846,6 +10851,51 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
9846
10851
|
}) : null]
|
|
9847
10852
|
});
|
|
9848
10853
|
}
|
|
10854
|
+
/** A staged value field. `numeric` only hints the keypad: which drafts a field accepts is decided by its spec. */
|
|
10855
|
+
function ValueField(props) {
|
|
10856
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10857
|
+
className: settings_card_module_css_default.field,
|
|
10858
|
+
children: [
|
|
10859
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10860
|
+
className: settings_card_module_css_default.head,
|
|
10861
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
10862
|
+
className: settings_card_module_css_default.label,
|
|
10863
|
+
htmlFor: props.id,
|
|
10864
|
+
children: props.label
|
|
10865
|
+
}), props.overridden ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10866
|
+
className: settings_card_module_css_default.badges,
|
|
10867
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10868
|
+
className: settings_card_module_css_default.badge,
|
|
10869
|
+
children: props.overriddenLabel
|
|
10870
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10871
|
+
type: "button",
|
|
10872
|
+
className: settings_card_module_css_default.reset,
|
|
10873
|
+
disabled: props.disabled,
|
|
10874
|
+
onClick: props.onReset,
|
|
10875
|
+
children: props.resetLabel
|
|
10876
|
+
})]
|
|
10877
|
+
}) : null]
|
|
10878
|
+
}),
|
|
10879
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
10880
|
+
id: props.id,
|
|
10881
|
+
className: props.invalid ? settings_card_module_css_default.inputInvalid : settings_card_module_css_default.input,
|
|
10882
|
+
type: "text",
|
|
10883
|
+
...props.numeric === true ? { inputMode: "numeric" } : {},
|
|
10884
|
+
...props.invalid ? { "aria-invalid": true } : {},
|
|
10885
|
+
value: props.text,
|
|
10886
|
+
placeholder: props.placeholder ?? "",
|
|
10887
|
+
disabled: props.disabled,
|
|
10888
|
+
onChange: (event) => {
|
|
10889
|
+
props.onEdit(event.target.value);
|
|
10890
|
+
}
|
|
10891
|
+
}),
|
|
10892
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10893
|
+
className: props.invalid ? settings_card_module_css_default.invalid : settings_card_module_css_default.hint,
|
|
10894
|
+
children: props.invalid ? props.invalidLabel : props.hint
|
|
10895
|
+
})
|
|
10896
|
+
]
|
|
10897
|
+
});
|
|
10898
|
+
}
|
|
9849
10899
|
const NON_SKIN_BODY_MARKERS = /* @__PURE__ */ new Set(["dshSkinCenter", "dshSidebarCollapsed"]);
|
|
9850
10900
|
function isSkinActive() {
|
|
9851
10901
|
return Object.keys(document.body.dataset).some((key) => key.startsWith("dsh") && !NON_SKIN_BODY_MARKERS.has(key));
|
|
@@ -10444,6 +11494,28 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
10444
11494
|
/** The depth choices the card offers, derived from the supported range. */
|
|
10445
11495
|
const SUBTASK_DEPTH_CHOICES = Array.from({ length: 3 }, (_, index) => String(1 + index));
|
|
10446
11496
|
/**
|
|
11497
|
+
* The roster-poll cadence field: a whole number of seconds inside the
|
|
11498
|
+
* supported range, because the Host schema (`sessionPollSeconds`) is numeric.
|
|
11499
|
+
* A draft outside the range blocks the save instead of staging a value the
|
|
11500
|
+
* Host would clamp behind the user's back.
|
|
11501
|
+
*/
|
|
11502
|
+
function sessionPollField() {
|
|
11503
|
+
return {
|
|
11504
|
+
field: "sessionPollSeconds",
|
|
11505
|
+
format: (value) => typeof value === "number" && Number.isInteger(value) ? String(value) : "",
|
|
11506
|
+
parse: (text) => {
|
|
11507
|
+
const trimmed = text.trim();
|
|
11508
|
+
if (trimmed === "") return { kind: "clear" };
|
|
11509
|
+
if (!/^\d+$/.test(trimmed)) return void 0;
|
|
11510
|
+
const seconds = Number(trimmed);
|
|
11511
|
+
return seconds >= 1 && seconds <= 300 ? {
|
|
11512
|
+
kind: "set",
|
|
11513
|
+
value: seconds
|
|
11514
|
+
} : void 0;
|
|
11515
|
+
}
|
|
11516
|
+
};
|
|
11517
|
+
}
|
|
11518
|
+
/**
|
|
10447
11519
|
* The depth field: a choice among the supported levels whose draft text is a
|
|
10448
11520
|
* number, because the Host schema (`maxSubtaskDepth`) is numeric. A draft
|
|
10449
11521
|
* outside the range blocks the save instead of staging a value the Host
|
|
@@ -10513,6 +11585,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
10513
11585
|
booleanField("announceToAgent"),
|
|
10514
11586
|
booleanField("preventIdleSleep"),
|
|
10515
11587
|
subtaskDepthField(),
|
|
11588
|
+
sessionPollField(),
|
|
11589
|
+
booleanField("goalRunEnabled"),
|
|
10516
11590
|
booleanField("goalVerification"),
|
|
10517
11591
|
judgeModelField(),
|
|
10518
11592
|
judgeEffortField()
|
|
@@ -10526,6 +11600,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
10526
11600
|
announceToAgent: this.form.field("announceToAgent"),
|
|
10527
11601
|
preventIdleSleep: this.form.field("preventIdleSleep"),
|
|
10528
11602
|
maxSubtaskDepth: this.form.field("maxSubtaskDepth"),
|
|
11603
|
+
sessionPollSeconds: this.form.field("sessionPollSeconds"),
|
|
11604
|
+
goalRunEnabled: this.form.field("goalRunEnabled"),
|
|
10529
11605
|
goalVerification: this.form.field("goalVerification"),
|
|
10530
11606
|
goalVerificationModel: this.form.field("goalVerificationModel"),
|
|
10531
11607
|
goalVerificationReasoningEffort: this.form.field("goalVerificationReasoningEffort")
|
|
@@ -10728,6 +11804,20 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
10728
11804
|
props.resetField("preventIdleSleep");
|
|
10729
11805
|
}
|
|
10730
11806
|
}),
|
|
11807
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
|
|
11808
|
+
id: "settings-task-board-session-poll",
|
|
11809
|
+
label: t("settings.sessionPollSeconds"),
|
|
11810
|
+
hint: t("settings.sessionPollSecondsHint"),
|
|
11811
|
+
numeric: true,
|
|
11812
|
+
...fieldProps,
|
|
11813
|
+
...state.sessionPollSeconds,
|
|
11814
|
+
onEdit: (text) => {
|
|
11815
|
+
props.edit("sessionPollSeconds", text);
|
|
11816
|
+
},
|
|
11817
|
+
onReset: () => {
|
|
11818
|
+
props.resetField("sessionPollSeconds");
|
|
11819
|
+
}
|
|
11820
|
+
}),
|
|
10731
11821
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChoiceField, {
|
|
10732
11822
|
id: "settings-task-board-subtask-depth",
|
|
10733
11823
|
label: t("settings.maxSubtaskDepth"),
|
|
@@ -10748,6 +11838,32 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
10748
11838
|
})
|
|
10749
11839
|
]
|
|
10750
11840
|
}),
|
|
11841
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PluginSettingsCard, {
|
|
11842
|
+
t,
|
|
11843
|
+
titleKey: "settings.runBehaviorTitle",
|
|
11844
|
+
descriptionKey: "settings.runBehaviorCardHint",
|
|
11845
|
+
defaultOpen: false,
|
|
11846
|
+
hideFooter: true,
|
|
11847
|
+
state: nestedShell,
|
|
11848
|
+
onSave: props.save,
|
|
11849
|
+
onDiscard: props.discard,
|
|
11850
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BooleanField, {
|
|
11851
|
+
id: "settings-task-board-goal-run",
|
|
11852
|
+
label: t("settings.goalRunGlobal"),
|
|
11853
|
+
hint: t("settings.goalRunGlobalHint"),
|
|
11854
|
+
inheritLabel: t("settings.inherit"),
|
|
11855
|
+
onLabel: t("settings.on"),
|
|
11856
|
+
offLabel: t("settings.off"),
|
|
11857
|
+
...fieldProps,
|
|
11858
|
+
...state.goalRunEnabled,
|
|
11859
|
+
onEdit: (text) => {
|
|
11860
|
+
props.edit("goalRunEnabled", text);
|
|
11861
|
+
},
|
|
11862
|
+
onReset: () => {
|
|
11863
|
+
props.resetField("goalRunEnabled");
|
|
11864
|
+
}
|
|
11865
|
+
})
|
|
11866
|
+
}),
|
|
10751
11867
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(PluginSettingsCard, {
|
|
10752
11868
|
t,
|
|
10753
11869
|
titleKey: "settings.goalVerificationTitle",
|
|
@@ -11220,7 +12336,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
11220
12336
|
/** The building package's version, when the bundle carries it. */
|
|
11221
12337
|
function bakedVersion() {
|
|
11222
12338
|
try {
|
|
11223
|
-
return "0.4.
|
|
12339
|
+
return "0.4.6";
|
|
11224
12340
|
} catch {
|
|
11225
12341
|
return;
|
|
11226
12342
|
}
|
|
@@ -11343,40 +12459,33 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
11343
12459
|
return false;
|
|
11344
12460
|
}
|
|
11345
12461
|
}
|
|
11346
|
-
|
|
11347
|
-
//#region src/client/board-card-seat.ts
|
|
11348
|
-
/**
|
|
11349
|
-
* Board-owned variant of the family plugin-card seat that can declare child
|
|
11350
|
-
* slots on the registration.
|
|
11351
|
-
*
|
|
11352
|
-
* The shared `installPluginCard` helper owns seat selection but cannot forward
|
|
11353
|
-
* a `children` declaration, and the task board's settings card declares the
|
|
11354
|
-
* `task-board.settings.section` seat a provider renders into. This wrapper
|
|
11355
|
-
* reuses the shared seat decision (`familyGroupLoaded` and the two seat keys)
|
|
11356
|
-
* and adds the declaration; it should collapse back into the shared helper once
|
|
11357
|
-
* that helper accepts children.
|
|
11358
|
-
*
|
|
11359
|
-
* @module dsh-task-board/client/board-card-seat
|
|
11360
|
-
*/
|
|
12462
|
+
/** Report a refused registration instead of leaving the user with no card. */
|
|
11361
12463
|
function warnRefusedSeat(seat, error) {
|
|
11362
12464
|
try {
|
|
11363
12465
|
console.warn(`[dsh-web] plugin card registration into "${seat}" was refused; the card will not render`, error);
|
|
11364
12466
|
} catch {}
|
|
11365
12467
|
}
|
|
11366
12468
|
/**
|
|
11367
|
-
* Contribute
|
|
11368
|
-
* the
|
|
11369
|
-
*
|
|
12469
|
+
* Contribute one family plugin card to the seat this host renders, following
|
|
12470
|
+
* the group if it loads later. The entry is disposed and re-registered on a
|
|
12471
|
+
* seat change, never duplicated.
|
|
11370
12472
|
* @param ctx - client context (its slot registry decides the seat).
|
|
11371
|
-
* @param seat - the card contribution
|
|
12473
|
+
* @param seat - the card contribution.
|
|
11372
12474
|
*/
|
|
11373
|
-
function
|
|
12475
|
+
function installPluginCard(ctx, seat) {
|
|
11374
12476
|
const slots = ctx.slots;
|
|
11375
12477
|
const component = seat.component;
|
|
11376
12478
|
const inject = seat.inject;
|
|
11377
12479
|
let dispose;
|
|
11378
12480
|
let current;
|
|
12481
|
+
/**
|
|
12482
|
+
* Re-entrancy latch. The registry emits a change event synchronously from
|
|
12483
|
+
* inside both `register` and the previous entry's disposer, so an unguarded
|
|
12484
|
+
* reconcile would re-enter itself mid-move and register the card twice into
|
|
12485
|
+
* the seat it is leaving ("already has an entry for key ...").
|
|
12486
|
+
*/
|
|
11379
12487
|
let reconciling = false;
|
|
12488
|
+
/** Reconcile the contribution with the currently live seat (no-op when unchanged). */
|
|
11380
12489
|
const reconcile = () => {
|
|
11381
12490
|
if (reconciling) return;
|
|
11382
12491
|
const target = familyGroupLoaded(ctx) ? FAMILY_PLUGIN_CARD_SEAT : OFFICIAL_PLUGIN_CARD_SEAT;
|
|
@@ -11393,13 +12502,13 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
11393
12502
|
...seat.order === void 0 ? {} : { order: seat.order },
|
|
11394
12503
|
...seat.label === void 0 ? {} : { label: seat.label },
|
|
11395
12504
|
locale: seat.locale,
|
|
11396
|
-
children: seat.children,
|
|
12505
|
+
...seat.children === void 0 ? {} : { children: seat.children },
|
|
11397
12506
|
...seat.inject === void 0 ? {} : { inject }
|
|
11398
12507
|
} : {
|
|
11399
12508
|
name: OFFICIAL_PLUGIN_CARD_SEAT,
|
|
11400
12509
|
key: seat.bundle,
|
|
11401
12510
|
locale: seat.locale,
|
|
11402
|
-
children: seat.children,
|
|
12511
|
+
...seat.children === void 0 ? {} : { children: seat.children },
|
|
11403
12512
|
...seat.inject === void 0 ? {} : { inject }
|
|
11404
12513
|
}, component);
|
|
11405
12514
|
current = target;
|
|
@@ -11601,11 +12710,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
11601
12710
|
];
|
|
11602
12711
|
/**
|
|
11603
12712
|
* Required services (fiber inject waiting — the runtime must be up first).
|
|
11604
|
-
* The generated remote
|
|
11605
|
-
* `remote.agentPresets`
|
|
11606
|
-
*
|
|
11607
|
-
*
|
|
11608
|
-
* connection RPC face.
|
|
12713
|
+
* The generated remote namespaces are not all hard injects: `remote.session`
|
|
12714
|
+
* is one, while `remote.agentPresets` is reached through a scoped inject at
|
|
12715
|
+
* use time (see mountUi), because the namespace mounts with the official
|
|
12716
|
+
* api-remotes assembly applied beside this entry rather than before it.
|
|
11609
12717
|
*/
|
|
11610
12718
|
const inject = [
|
|
11611
12719
|
"slots",
|
|
@@ -11620,41 +12728,22 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
11620
12728
|
"layout"
|
|
11621
12729
|
];
|
|
11622
12730
|
/**
|
|
11623
|
-
* Read the agent-preset roster through
|
|
11624
|
-
*
|
|
11625
|
-
*
|
|
11626
|
-
*
|
|
11627
|
-
*
|
|
11628
|
-
*
|
|
12731
|
+
* Read the agent-preset roster through the generated api-remotes face. The
|
|
12732
|
+
* caller passes the namespace resolved inside its scoped inject, so a host
|
|
12733
|
+
* that serves no such namespace never reaches here; a host that serves it
|
|
12734
|
+
* answers `ok: false` instead, which leaves the picker options untouched.
|
|
12735
|
+
* @param remote - the `remote.agentPresets` namespace.
|
|
12736
|
+
* @returns the roster, or a failed read the caller ignores.
|
|
11629
12737
|
*/
|
|
11630
|
-
async function readPresetRoster(
|
|
11631
|
-
|
|
11632
|
-
|
|
11633
|
-
remotes = remote.agentPresets;
|
|
11634
|
-
} catch {
|
|
11635
|
-
remotes = void 0;
|
|
11636
|
-
}
|
|
11637
|
-
if (remotes !== void 0) {
|
|
11638
|
-
const response = await remotes.list();
|
|
11639
|
-
if (!response.ok) return {
|
|
11640
|
-
ok: false,
|
|
11641
|
-
presets: []
|
|
11642
|
-
};
|
|
11643
|
-
return {
|
|
11644
|
-
ok: true,
|
|
11645
|
-
presets: response.value.presets
|
|
11646
|
-
};
|
|
11647
|
-
}
|
|
11648
|
-
const legacy = ctx.get("connection").api?.agentPresets;
|
|
11649
|
-
if (legacy === void 0) return void 0;
|
|
11650
|
-
const response = await legacy.list({});
|
|
11651
|
-
if (!response.result.ok || response.result.value === void 0) return {
|
|
12738
|
+
async function readPresetRoster(remote) {
|
|
12739
|
+
const response = await remote.list();
|
|
12740
|
+
if (!response.ok) return {
|
|
11652
12741
|
ok: false,
|
|
11653
12742
|
presets: []
|
|
11654
12743
|
};
|
|
11655
12744
|
return {
|
|
11656
12745
|
ok: true,
|
|
11657
|
-
presets: response.
|
|
12746
|
+
presets: response.value.presets
|
|
11658
12747
|
};
|
|
11659
12748
|
}
|
|
11660
12749
|
/**
|
|
@@ -11685,7 +12774,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
11685
12774
|
clientService.detach();
|
|
11686
12775
|
}, "task-board: extension service");
|
|
11687
12776
|
const settingsCard = new TaskBoardSettingsCardController(settingsForm, (request) => clientService.dispatch(request));
|
|
11688
|
-
|
|
12777
|
+
installPluginCard(ctx, {
|
|
11689
12778
|
bundle: "@linxin666/dsh-client-ui-task-board",
|
|
11690
12779
|
id: "task-board",
|
|
11691
12780
|
order: 110,
|
|
@@ -11733,10 +12822,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
11733
12822
|
controller.setWorkspaceCreator(async (path) => {
|
|
11734
12823
|
return { workspaceId: (await workspaces.create({ path })).workspaceId };
|
|
11735
12824
|
});
|
|
11736
|
-
const pushPresetOptions = async () => {
|
|
12825
|
+
const pushPresetOptions = async (presetRemote) => {
|
|
11737
12826
|
try {
|
|
11738
|
-
const roster = await readPresetRoster(
|
|
11739
|
-
if (
|
|
12827
|
+
const roster = await readPresetRoster(presetRemote);
|
|
12828
|
+
if (!roster.ok) return;
|
|
11740
12829
|
controller.setExecutionOptions({ presets: roster.presets.map((preset) => ({
|
|
11741
12830
|
id: preset.id,
|
|
11742
12831
|
name: preset.name,
|
|
@@ -11748,6 +12837,17 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
11748
12837
|
console.error("[dsh-task-board] agent preset roster read failed", error);
|
|
11749
12838
|
}
|
|
11750
12839
|
};
|
|
12840
|
+
const presetRosterFeed = ctx.inject(["remote.agentPresets"], (inner) => {
|
|
12841
|
+
const presetRemote = inner.get("remote.agentPresets");
|
|
12842
|
+
if (presetRemote === void 0) return;
|
|
12843
|
+
pushPresetOptions(presetRemote);
|
|
12844
|
+
return inner.on("connection/reset", () => {
|
|
12845
|
+
pushPresetOptions(presetRemote);
|
|
12846
|
+
});
|
|
12847
|
+
});
|
|
12848
|
+
disposers.push(() => {
|
|
12849
|
+
presetRosterFeed.dispose();
|
|
12850
|
+
});
|
|
11751
12851
|
const pushModelOptions = async () => {
|
|
11752
12852
|
try {
|
|
11753
12853
|
let models = [];
|
|
@@ -11803,10 +12903,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
11803
12903
|
console.error("[dsh-task-board] model options read failed", error);
|
|
11804
12904
|
}
|
|
11805
12905
|
};
|
|
11806
|
-
pushPresetOptions();
|
|
11807
12906
|
pushModelOptions();
|
|
11808
12907
|
disposers.push(ctx.on("connection/reset", () => {
|
|
11809
|
-
pushPresetOptions();
|
|
11810
12908
|
pushModelOptions();
|
|
11811
12909
|
}));
|
|
11812
12910
|
try {
|