u-foo 1.7.4 → 1.7.5
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/package.json +1 -1
- package/src/agent/ufooAgent.js +2 -2
- package/src/assistant/engine.js +1 -6
- package/src/chat/commandExecutor.js +18 -16
- package/src/chat/commands.js +1 -1
- package/src/chat/cronScheduler.js +37 -6
- package/src/chat/daemonMessageRouter.js +2 -2
- package/src/chat/dashboardKeyController.js +2 -65
- package/src/chat/dashboardView.js +2 -36
- package/src/chat/index.js +2 -41
- package/src/chat/settingsController.js +0 -28
- package/src/daemon/cronOps.js +48 -11
- package/src/daemon/index.js +2 -2
- package/src/daemon/status.js +2 -0
package/package.json
CHANGED
package/src/agent/ufooAgent.js
CHANGED
|
@@ -275,7 +275,7 @@ function buildSystemPrompt(context) {
|
|
|
275
275
|
' "reply": "string",',
|
|
276
276
|
` "assistant_call": {"kind":"explore|bash|mixed","task":"string","context":"optional","expect":"optional","provider":"codex|claude|ufoo (optional)","model":"optional","timeout_ms":${DEFAULT_ASSISTANT_TIMEOUT_MS}},`,
|
|
277
277
|
' "dispatch": [{"target":"broadcast|<agent-id>|<nickname>","message":"string","injection_mode":"immediate|queued (optional)","source":"optional"}],',
|
|
278
|
-
' "ops": [{"action":"launch|close|rename|cron","agent":"codex|claude|ucode","count":1,"agent_id":"id","nickname":"optional","operation":"start|list|stop","every":"30m","interval_ms":1800000,"target":"agent-id|nickname|csv","targets":["agent-id"],"prompt":"message","id":"task-id|all"}],',
|
|
278
|
+
' "ops": [{"action":"launch|close|rename|cron","agent":"codex|claude|ucode","count":1,"agent_id":"id","nickname":"optional","operation":"start|list|stop","every":"30m","interval_ms":1800000,"at":"YYYY-MM-DD HH:mm","once_at_ms":1700000000000,"target":"agent-id|nickname|csv","targets":["agent-id"],"title":"optional short title","prompt":"message","id":"task-id|all"}],',
|
|
279
279
|
' "disambiguate": {"prompt":"string","candidates":[{"agent_id":"id","reason":"string"}]}',
|
|
280
280
|
"}",
|
|
281
281
|
"Rules:",
|
|
@@ -283,7 +283,7 @@ function buildSystemPrompt(context) {
|
|
|
283
283
|
"- If multiple possible agents, use disambiguate with candidates and no dispatch.",
|
|
284
284
|
"- If user specifies a nickname for a new agent, include ops.launch with nickname so daemon can rename.",
|
|
285
285
|
"- If user requests rename, use ops.rename with agent_id and nickname (do NOT launch).",
|
|
286
|
-
"- For scheduled follow-up (cron), use ops.cron with operation=start and include
|
|
286
|
+
"- For scheduled follow-up (cron), use ops.cron with operation=start and include target(s)+prompt, plus optional title; use every/interval_ms for recurring or at/once_at_ms for one-time.",
|
|
287
287
|
"- To check scheduled tasks, use ops.cron with operation=list.",
|
|
288
288
|
"- To stop scheduled tasks, use ops.cron with operation=stop and id (or id=all).",
|
|
289
289
|
"- Use top-level assistant_call for project exploration, temporary shell tasks, and quick execution support.",
|
package/src/assistant/engine.js
CHANGED
|
@@ -18,16 +18,11 @@ function resolveAssistantEngine({
|
|
|
18
18
|
} = {}) {
|
|
19
19
|
const config = loadConfig(projectRoot);
|
|
20
20
|
|
|
21
|
-
const hasRequestedProvider = String(requestedProvider || "").trim().length > 0;
|
|
22
21
|
const requested = normalizeAssistantEngine(requestedProvider);
|
|
23
|
-
const configEngine = normalizeAssistantEngine(config.assistantEngine);
|
|
24
22
|
const fallback = normalizeAssistantEngine(fallbackProvider) || "codex";
|
|
25
23
|
|
|
26
24
|
let selected = requested;
|
|
27
|
-
|
|
28
|
-
// Explicit assistant_call provider=auto should inherit current main agent provider.
|
|
29
|
-
selected = hasRequestedProvider ? fallback : configEngine;
|
|
30
|
-
}
|
|
25
|
+
// Omitted/auto assistant providers inherit the active ufoo-agent provider.
|
|
31
26
|
if (selected === "auto") selected = fallback;
|
|
32
27
|
if (selected === "auto") selected = "codex";
|
|
33
28
|
|
|
@@ -688,6 +688,9 @@ function createCommandExecutor(options = {}) {
|
|
|
688
688
|
const targetsRaw = String(
|
|
689
689
|
kv.target || kv.targets || kv.agent || kv.agents || ""
|
|
690
690
|
).trim();
|
|
691
|
+
const title = String(
|
|
692
|
+
kv.title || kv.name || kv.label || ""
|
|
693
|
+
).trim();
|
|
691
694
|
const prompt = String(
|
|
692
695
|
kv.prompt || kv.message || kv.msg || nonKvParts.join(" ") || ""
|
|
693
696
|
).trim();
|
|
@@ -695,7 +698,7 @@ function createCommandExecutor(options = {}) {
|
|
|
695
698
|
if ((!intervalRaw && !atRaw) || !targetsRaw || !prompt) {
|
|
696
699
|
logMessage(
|
|
697
700
|
"error",
|
|
698
|
-
"{white-fg}✗{/white-fg} Usage: /cron start every=<10s|5m> or at=\"YYYY-MM-DD HH:mm\" target=<agent1,agent2> prompt=\"...\""
|
|
701
|
+
"{white-fg}✗{/white-fg} Usage: /cron start every=<10s|5m> or at=\"YYYY-MM-DD HH:mm\" target=<agent1,agent2> [title=\"...\"] prompt=\"...\""
|
|
699
702
|
);
|
|
700
703
|
return;
|
|
701
704
|
}
|
|
@@ -728,21 +731,18 @@ function createCommandExecutor(options = {}) {
|
|
|
728
731
|
}
|
|
729
732
|
|
|
730
733
|
if (typeof requestCron === "function") {
|
|
734
|
+
const request = {
|
|
735
|
+
operation: "start",
|
|
736
|
+
targets,
|
|
737
|
+
prompt,
|
|
738
|
+
};
|
|
739
|
+
if (title) request.title = title;
|
|
731
740
|
if (atMs > 0) {
|
|
732
|
-
|
|
733
|
-
operation: "start",
|
|
734
|
-
once_at_ms: atMs,
|
|
735
|
-
targets,
|
|
736
|
-
prompt,
|
|
737
|
-
});
|
|
741
|
+
request.once_at_ms = atMs;
|
|
738
742
|
} else {
|
|
739
|
-
|
|
740
|
-
operation: "start",
|
|
741
|
-
interval_ms: intervalMs,
|
|
742
|
-
targets,
|
|
743
|
-
prompt,
|
|
744
|
-
});
|
|
743
|
+
request.interval_ms = intervalMs;
|
|
745
744
|
}
|
|
745
|
+
requestCron(request);
|
|
746
746
|
schedule(requestStatus, 200);
|
|
747
747
|
return;
|
|
748
748
|
}
|
|
@@ -752,11 +752,13 @@ function createCommandExecutor(options = {}) {
|
|
|
752
752
|
return;
|
|
753
753
|
}
|
|
754
754
|
|
|
755
|
-
const
|
|
755
|
+
const taskPayload = {
|
|
756
756
|
intervalMs,
|
|
757
757
|
targets,
|
|
758
758
|
prompt,
|
|
759
|
-
}
|
|
759
|
+
};
|
|
760
|
+
if (title) taskPayload.title = title;
|
|
761
|
+
const task = createCronTask(taskPayload);
|
|
760
762
|
if (!task) {
|
|
761
763
|
logMessage("error", "{white-fg}✗{/white-fg} Failed to create cron task");
|
|
762
764
|
return;
|
|
@@ -764,7 +766,7 @@ function createCommandExecutor(options = {}) {
|
|
|
764
766
|
|
|
765
767
|
logMessage(
|
|
766
768
|
"system",
|
|
767
|
-
`{white-fg}✓{/white-fg} Cron started ${task.id}: ${atMs > 0 ? `at ${formatCronAt(atMs)}` : `every ${formatIntervalMs(intervalMs)}`} -> ${targets.join(", ")}`
|
|
769
|
+
`{white-fg}✓{/white-fg} Cron started ${task.id}: ${task.label || `${atMs > 0 ? `at ${formatCronAt(atMs)}` : `every ${formatIntervalMs(intervalMs)}`} -> ${targets.join(", ")}`}`
|
|
768
770
|
);
|
|
769
771
|
}
|
|
770
772
|
|
package/src/chat/commands.js
CHANGED
|
@@ -30,7 +30,7 @@ const COMMAND_TREE = {
|
|
|
30
30
|
"/cron": {
|
|
31
31
|
desc: "Cron scheduler operations",
|
|
32
32
|
children: {
|
|
33
|
-
start: { desc: "Create cron task" },
|
|
33
|
+
start: { desc: "Create cron task (optional title)" },
|
|
34
34
|
list: { desc: "List cron tasks" },
|
|
35
35
|
stop: { desc: "Stop cron task by id or all" },
|
|
36
36
|
},
|
|
@@ -29,13 +29,39 @@ function sanitizeSummaryText(value = "") {
|
|
|
29
29
|
.trim();
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
function truncateCronText(value = "", maxLength = 24) {
|
|
33
|
+
const text = String(value || "").trim();
|
|
34
|
+
if (!text) return "";
|
|
35
|
+
if (text.length <= maxLength) return text;
|
|
36
|
+
return `${text.slice(0, Math.max(1, maxLength - 3))}...`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function resolveTaskTitle(task = {}) {
|
|
40
|
+
const explicitTitle = truncateCronText(
|
|
41
|
+
sanitizeSummaryText(task.title || "").replace(/:/g, "-"),
|
|
42
|
+
24
|
|
43
|
+
);
|
|
44
|
+
if (explicitTitle) return explicitTitle;
|
|
45
|
+
const fallbackTitle = truncateCronText(
|
|
46
|
+
sanitizeSummaryText(task.prompt || "").replace(/:/g, "-"),
|
|
47
|
+
24
|
|
48
|
+
);
|
|
49
|
+
return fallbackTitle || "(empty)";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function buildTaskLabel(task = {}) {
|
|
53
|
+
const targets = Array.isArray(task.targets) && task.targets.length > 0
|
|
54
|
+
? task.targets.join("+")
|
|
55
|
+
: "unknown";
|
|
56
|
+
const title = resolveTaskTitle(task);
|
|
57
|
+
const interval = formatIntervalMs(task.intervalMs || 0);
|
|
58
|
+
return `${targets}:${title}:${interval}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
32
61
|
function summarizeTask(task = {}) {
|
|
33
62
|
const id = String(task.id || "");
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
const promptRaw = sanitizeSummaryText(task.prompt || "");
|
|
37
|
-
const prompt = promptRaw.length > 24 ? `${promptRaw.slice(0, 24)}...` : promptRaw;
|
|
38
|
-
return `${id}@${interval}->${targets}: ${prompt || "(empty)"}`;
|
|
63
|
+
const label = buildTaskLabel(task);
|
|
64
|
+
return id ? `${id} ${label}` : label;
|
|
39
65
|
}
|
|
40
66
|
|
|
41
67
|
function createCronScheduler(options = {}) {
|
|
@@ -58,7 +84,7 @@ function createCronScheduler(options = {}) {
|
|
|
58
84
|
}
|
|
59
85
|
}
|
|
60
86
|
|
|
61
|
-
function addTask({ intervalMs = 0, targets = [], prompt = "" } = {}) {
|
|
87
|
+
function addTask({ intervalMs = 0, targets = [], prompt = "", title = "" } = {}) {
|
|
62
88
|
const safeInterval = Number.parseInt(intervalMs, 10);
|
|
63
89
|
const safeTargets = Array.isArray(targets)
|
|
64
90
|
? targets.map((item) => String(item || "").trim()).filter(Boolean)
|
|
@@ -74,6 +100,7 @@ function createCronScheduler(options = {}) {
|
|
|
74
100
|
intervalMs: safeInterval,
|
|
75
101
|
targets: Array.from(new Set(safeTargets)),
|
|
76
102
|
prompt: safePrompt,
|
|
103
|
+
title: resolveTaskTitle({ title, prompt: safePrompt }),
|
|
77
104
|
createdAt: nowFn(),
|
|
78
105
|
lastRunAt: 0,
|
|
79
106
|
tickCount: 0,
|
|
@@ -100,6 +127,7 @@ function createCronScheduler(options = {}) {
|
|
|
100
127
|
notifyChange();
|
|
101
128
|
return {
|
|
102
129
|
...task,
|
|
130
|
+
label: buildTaskLabel(task),
|
|
103
131
|
summary: summarizeTask(task),
|
|
104
132
|
};
|
|
105
133
|
}
|
|
@@ -110,9 +138,11 @@ function createCronScheduler(options = {}) {
|
|
|
110
138
|
intervalMs: task.intervalMs,
|
|
111
139
|
targets: task.targets.slice(),
|
|
112
140
|
prompt: task.prompt,
|
|
141
|
+
title: task.title,
|
|
113
142
|
createdAt: task.createdAt,
|
|
114
143
|
lastRunAt: task.lastRunAt,
|
|
115
144
|
tickCount: task.tickCount,
|
|
145
|
+
label: buildTaskLabel(task),
|
|
116
146
|
summary: summarizeTask(task),
|
|
117
147
|
}));
|
|
118
148
|
}
|
|
@@ -155,6 +185,7 @@ function createCronScheduler(options = {}) {
|
|
|
155
185
|
module.exports = {
|
|
156
186
|
parseIntervalMs,
|
|
157
187
|
formatIntervalMs,
|
|
188
|
+
buildTaskLabel,
|
|
158
189
|
summarizeTask,
|
|
159
190
|
createCronScheduler,
|
|
160
191
|
};
|
|
@@ -254,12 +254,12 @@ function createDaemonMessageRouter(options = {}) {
|
|
|
254
254
|
if (task.mode === "once") {
|
|
255
255
|
logMessage(
|
|
256
256
|
"system",
|
|
257
|
-
`{white-fg}✓{/white-fg} Cron scheduled ${escapeBlessed(task.id)}
|
|
257
|
+
`{white-fg}✓{/white-fg} Cron scheduled ${escapeBlessed(task.id)}: ${escapeBlessed(task.label || task.onceAt || String(task.onceAtMs || ""))}`
|
|
258
258
|
);
|
|
259
259
|
} else {
|
|
260
260
|
logMessage(
|
|
261
261
|
"system",
|
|
262
|
-
`{white-fg}✓{/white-fg} Cron started ${escapeBlessed(task.id)}:
|
|
262
|
+
`{white-fg}✓{/white-fg} Cron started ${escapeBlessed(task.id)}: ${escapeBlessed(task.label || task.interval || String(task.intervalMs || ""))}`
|
|
263
263
|
);
|
|
264
264
|
}
|
|
265
265
|
} else if (operation === "stop") {
|
|
@@ -18,7 +18,6 @@ function createDashboardKeyController(options = {}) {
|
|
|
18
18
|
exitDashboardMode = () => {},
|
|
19
19
|
setLaunchMode = () => {},
|
|
20
20
|
setAgentProvider = () => {},
|
|
21
|
-
setAssistantEngine = () => {},
|
|
22
21
|
setAutoResume = () => {},
|
|
23
22
|
clampAgentWindow = () => {},
|
|
24
23
|
clampAgentWindowWithSelection = () => {},
|
|
@@ -232,10 +231,7 @@ function createDashboardKeyController(options = {}) {
|
|
|
232
231
|
}
|
|
233
232
|
|
|
234
233
|
if (key.name === "down") {
|
|
235
|
-
state.dashboardView = "
|
|
236
|
-
const list = Array.isArray(state.assistantOptions) ? state.assistantOptions : [];
|
|
237
|
-
const nextIndex = list.findIndex((opt) => opt.value === state.assistantEngine);
|
|
238
|
-
state.selectedAssistantIndex = nextIndex >= 0 ? nextIndex : 0;
|
|
234
|
+
state.dashboardView = "cron";
|
|
239
235
|
renderDashboardAndScreen();
|
|
240
236
|
return true;
|
|
241
237
|
}
|
|
@@ -261,67 +257,9 @@ function createDashboardKeyController(options = {}) {
|
|
|
261
257
|
return true;
|
|
262
258
|
}
|
|
263
259
|
|
|
264
|
-
function handleAssistantKey(key) {
|
|
265
|
-
const options = Array.isArray(state.assistantOptions) ? state.assistantOptions : [];
|
|
266
|
-
if (options.length === 0) {
|
|
267
|
-
if (key.name === "up") {
|
|
268
|
-
state.dashboardView = "provider";
|
|
269
|
-
renderDashboardAndScreen();
|
|
270
|
-
return true;
|
|
271
|
-
}
|
|
272
|
-
if (key.name === "escape" || key.name === "enter" || key.name === "return") {
|
|
273
|
-
exitDashboardMode(false);
|
|
274
|
-
return true;
|
|
275
|
-
}
|
|
276
|
-
return true;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (key.name === "left") {
|
|
280
|
-
state.selectedAssistantIndex = state.selectedAssistantIndex <= 0
|
|
281
|
-
? options.length - 1
|
|
282
|
-
: state.selectedAssistantIndex - 1;
|
|
283
|
-
renderDashboardAndScreen();
|
|
284
|
-
return true;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (key.name === "right") {
|
|
288
|
-
state.selectedAssistantIndex = state.selectedAssistantIndex >= options.length - 1
|
|
289
|
-
? 0
|
|
290
|
-
: state.selectedAssistantIndex + 1;
|
|
291
|
-
renderDashboardAndScreen();
|
|
292
|
-
return true;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (key.name === "up") {
|
|
296
|
-
state.dashboardView = "provider";
|
|
297
|
-
renderDashboardAndScreen();
|
|
298
|
-
return true;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (key.name === "down") {
|
|
302
|
-
state.dashboardView = "cron";
|
|
303
|
-
renderDashboardAndScreen();
|
|
304
|
-
return true;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (key.name === "enter" || key.name === "return") {
|
|
308
|
-
const selected = options[state.selectedAssistantIndex];
|
|
309
|
-
if (selected) setAssistantEngine(selected.value);
|
|
310
|
-
exitDashboardMode(false);
|
|
311
|
-
return true;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
if (key.name === "escape") {
|
|
315
|
-
exitDashboardMode(false);
|
|
316
|
-
return true;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
return true;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
260
|
function handleCronKey(key) {
|
|
323
261
|
if (key.name === "up") {
|
|
324
|
-
state.dashboardView = "
|
|
262
|
+
state.dashboardView = "provider";
|
|
325
263
|
renderDashboardAndScreen();
|
|
326
264
|
return true;
|
|
327
265
|
}
|
|
@@ -552,7 +490,6 @@ function createDashboardKeyController(options = {}) {
|
|
|
552
490
|
|
|
553
491
|
if (state.dashboardView === "mode") return handleModeKey(key);
|
|
554
492
|
if (state.dashboardView === "provider") return handleProviderKey(key);
|
|
555
|
-
if (state.dashboardView === "assistant") return handleAssistantKey(key);
|
|
556
493
|
if (state.dashboardView === "resume") return handleResumeKey(key);
|
|
557
494
|
if (state.dashboardView === "cron") return handleCronKey(key);
|
|
558
495
|
|
|
@@ -8,14 +8,6 @@ function providerLabel(value) {
|
|
|
8
8
|
return "codex";
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
function assistantLabel(value) {
|
|
12
|
-
if (value === "codex") return "codex";
|
|
13
|
-
if (value === "claude") return "claude";
|
|
14
|
-
if (value === "ufoo") return "ucode";
|
|
15
|
-
if (value === "ucode") return "ucode";
|
|
16
|
-
return "auto";
|
|
17
|
-
}
|
|
18
|
-
|
|
19
11
|
function ensureAtPrefix(value) {
|
|
20
12
|
const text = String(value || "").trim();
|
|
21
13
|
if (!text) return text;
|
|
@@ -43,7 +35,6 @@ function buildSummaryLine(options = {}) {
|
|
|
43
35
|
getAgentState = () => "",
|
|
44
36
|
launchMode = "terminal",
|
|
45
37
|
agentProvider = "codex-cli",
|
|
46
|
-
assistantEngine = "auto",
|
|
47
38
|
cronTasks = [],
|
|
48
39
|
} = options;
|
|
49
40
|
const agents = activeAgents.length > 0
|
|
@@ -55,7 +46,6 @@ function buildSummaryLine(options = {}) {
|
|
|
55
46
|
return `{gray-fg}Agents:{/gray-fg} {cyan-fg}${agents}{/cyan-fg}`
|
|
56
47
|
+ ` {gray-fg}Mode:{/gray-fg} {cyan-fg}${launchMode}{/cyan-fg}`
|
|
57
48
|
+ ` {gray-fg}Agent:{/gray-fg} {cyan-fg}${providerLabel(agentProvider)}{/cyan-fg}`
|
|
58
|
-
+ ` {gray-fg}Assistant:{/gray-fg} {cyan-fg}${assistantLabel(assistantEngine)}{/cyan-fg}`
|
|
59
49
|
+ ` {gray-fg}Cron:{/gray-fg} {cyan-fg}${Array.isArray(cronTasks) ? cronTasks.length : 0}{/cyan-fg}`;
|
|
60
50
|
}
|
|
61
51
|
|
|
@@ -134,11 +124,9 @@ function buildDashboardDetailLine(options = {}) {
|
|
|
134
124
|
getAgentState = () => "",
|
|
135
125
|
selectedModeIndex = 0,
|
|
136
126
|
selectedProviderIndex = 0,
|
|
137
|
-
selectedAssistantIndex = 0,
|
|
138
127
|
selectedResumeIndex = 0,
|
|
139
128
|
cronTasks = [],
|
|
140
129
|
providerOptions = [],
|
|
141
|
-
assistantOptions = [],
|
|
142
130
|
resumeOptions = [],
|
|
143
131
|
dashHints = {},
|
|
144
132
|
modeOptions = DEFAULT_MODE_OPTIONS,
|
|
@@ -171,18 +159,6 @@ function buildDashboardDetailLine(options = {}) {
|
|
|
171
159
|
return { content, windowStart };
|
|
172
160
|
}
|
|
173
161
|
|
|
174
|
-
if (dashboardView === "assistant") {
|
|
175
|
-
const assistantParts = assistantOptions.map((opt, i) => {
|
|
176
|
-
if (i === selectedAssistantIndex) {
|
|
177
|
-
return `{inverse}${opt.label}{/inverse}`;
|
|
178
|
-
}
|
|
179
|
-
return `{cyan-fg}${opt.label}{/cyan-fg}`;
|
|
180
|
-
});
|
|
181
|
-
content += `{gray-fg}Assistant:{/gray-fg} ${assistantParts.join(" ")}`;
|
|
182
|
-
content += ` {gray-fg}│ ${dashHints.assistant || ""}{/gray-fg}`;
|
|
183
|
-
return { content, windowStart };
|
|
184
|
-
}
|
|
185
|
-
|
|
186
162
|
if (dashboardView === "resume") {
|
|
187
163
|
const resumeParts = resumeOptions.map((opt, i) => {
|
|
188
164
|
if (i === selectedResumeIndex) {
|
|
@@ -198,9 +174,9 @@ function buildDashboardDetailLine(options = {}) {
|
|
|
198
174
|
if (dashboardView === "cron") {
|
|
199
175
|
const items = Array.isArray(cronTasks) ? cronTasks : [];
|
|
200
176
|
const summary = items.length > 0
|
|
201
|
-
? items.map((item) => item.summary || item.id || "").filter(Boolean).join(", ")
|
|
177
|
+
? items.map((item) => item.label || item.summary || item.id || "").filter(Boolean).join(", ")
|
|
202
178
|
: "none";
|
|
203
|
-
content += `{gray-fg}Cron:{/gray-fg} {
|
|
179
|
+
content += `{gray-fg}Cron:{/gray-fg} {inverse}${summary}{/inverse}`;
|
|
204
180
|
content += ` {gray-fg}│ ${dashHints.cron || ""}{/gray-fg}`;
|
|
205
181
|
return { content, windowStart };
|
|
206
182
|
}
|
|
@@ -259,14 +235,11 @@ function computeDashboardContent(options = {}) {
|
|
|
259
235
|
getAgentState = () => "",
|
|
260
236
|
launchMode = "terminal",
|
|
261
237
|
agentProvider = "codex-cli",
|
|
262
|
-
assistantEngine = "auto",
|
|
263
238
|
selectedModeIndex = 0,
|
|
264
239
|
selectedProviderIndex = 0,
|
|
265
|
-
selectedAssistantIndex = 0,
|
|
266
240
|
selectedResumeIndex = 0,
|
|
267
241
|
cronTasks = [],
|
|
268
242
|
providerOptions = [],
|
|
269
|
-
assistantOptions = [],
|
|
270
243
|
resumeOptions = [],
|
|
271
244
|
dashHints = {},
|
|
272
245
|
modeOptions = DEFAULT_MODE_OPTIONS,
|
|
@@ -297,7 +270,6 @@ function computeDashboardContent(options = {}) {
|
|
|
297
270
|
getAgentState,
|
|
298
271
|
launchMode,
|
|
299
272
|
agentProvider,
|
|
300
|
-
assistantEngine,
|
|
301
273
|
cronTasks,
|
|
302
274
|
});
|
|
303
275
|
return {
|
|
@@ -317,11 +289,9 @@ function computeDashboardContent(options = {}) {
|
|
|
317
289
|
getAgentState,
|
|
318
290
|
selectedModeIndex,
|
|
319
291
|
selectedProviderIndex,
|
|
320
|
-
selectedAssistantIndex,
|
|
321
292
|
selectedResumeIndex,
|
|
322
293
|
cronTasks,
|
|
323
294
|
providerOptions,
|
|
324
|
-
assistantOptions,
|
|
325
295
|
resumeOptions,
|
|
326
296
|
dashHints,
|
|
327
297
|
modeOptions,
|
|
@@ -344,11 +314,9 @@ function computeDashboardContent(options = {}) {
|
|
|
344
314
|
getAgentState,
|
|
345
315
|
selectedModeIndex,
|
|
346
316
|
selectedProviderIndex,
|
|
347
|
-
selectedAssistantIndex,
|
|
348
317
|
selectedResumeIndex,
|
|
349
318
|
cronTasks,
|
|
350
319
|
providerOptions,
|
|
351
|
-
assistantOptions,
|
|
352
320
|
resumeOptions,
|
|
353
321
|
dashHints,
|
|
354
322
|
modeOptions,
|
|
@@ -362,7 +330,6 @@ function computeDashboardContent(options = {}) {
|
|
|
362
330
|
getAgentState,
|
|
363
331
|
launchMode,
|
|
364
332
|
agentProvider,
|
|
365
|
-
assistantEngine,
|
|
366
333
|
cronTasks,
|
|
367
334
|
});
|
|
368
335
|
|
|
@@ -372,5 +339,4 @@ function computeDashboardContent(options = {}) {
|
|
|
372
339
|
module.exports = {
|
|
373
340
|
computeDashboardContent,
|
|
374
341
|
providerLabel,
|
|
375
|
-
assistantLabel,
|
|
376
342
|
};
|
package/src/chat/index.js
CHANGED
|
@@ -9,7 +9,6 @@ const {
|
|
|
9
9
|
saveConfig,
|
|
10
10
|
normalizeLaunchMode,
|
|
11
11
|
normalizeAgentProvider,
|
|
12
|
-
normalizeAssistantEngine,
|
|
13
12
|
} = require("../config");
|
|
14
13
|
const { socketPath, isRunning } = require("../daemon");
|
|
15
14
|
const UfooInit = require("../init");
|
|
@@ -104,7 +103,6 @@ async function runChat(projectRoot, options = {}) {
|
|
|
104
103
|
const config = loadConfig(projectRoot);
|
|
105
104
|
let launchMode = config.launchMode;
|
|
106
105
|
let agentProvider = config.agentProvider;
|
|
107
|
-
let assistantEngine = normalizeAssistantEngine(config.assistantEngine);
|
|
108
106
|
let autoResume = config.autoResume !== false;
|
|
109
107
|
let cronTasks = [];
|
|
110
108
|
|
|
@@ -675,7 +673,7 @@ async function runChat(projectRoot, options = {}) {
|
|
|
675
673
|
let selectedAgentIndex = -1; // -1 = not in dashboard selection mode
|
|
676
674
|
let targetAgent = null; // Selected agent for direct messaging
|
|
677
675
|
let focusMode = "input"; // "input" or "dashboard"
|
|
678
|
-
let dashboardView = "agents"; // "projects" | "agents" | "mode" | "provider" | "
|
|
676
|
+
let dashboardView = "agents"; // "projects" | "agents" | "mode" | "provider" | "cron"
|
|
679
677
|
let reportPendingTotal = 0;
|
|
680
678
|
let selectedModeIndex = Math.max(0, MODE_OPTIONS.indexOf(launchMode));
|
|
681
679
|
const providerOptions = [
|
|
@@ -684,16 +682,6 @@ async function runChat(projectRoot, options = {}) {
|
|
|
684
682
|
{ label: "ucode", value: "ucode" },
|
|
685
683
|
];
|
|
686
684
|
let selectedProviderIndex = Math.max(0, providerOptions.findIndex((opt) => opt.value === agentProvider));
|
|
687
|
-
const assistantOptions = [
|
|
688
|
-
{ label: "auto", value: "auto" },
|
|
689
|
-
{ label: "codex", value: "codex" },
|
|
690
|
-
{ label: "claude", value: "claude" },
|
|
691
|
-
{ label: "ucode", value: "ufoo" },
|
|
692
|
-
];
|
|
693
|
-
let selectedAssistantIndex = Math.max(
|
|
694
|
-
0,
|
|
695
|
-
assistantOptions.findIndex((opt) => opt.value === assistantEngine)
|
|
696
|
-
);
|
|
697
685
|
const resumeOptions = [
|
|
698
686
|
{ label: "Resume previous session", value: true },
|
|
699
687
|
{ label: "Start new session", value: false },
|
|
@@ -704,8 +692,7 @@ async function runChat(projectRoot, options = {}) {
|
|
|
704
692
|
agentsGlobal: "←/→ select · Enter · ↓ mode · ↑ projects",
|
|
705
693
|
agentsEmpty: "↓ mode · ↑ back",
|
|
706
694
|
mode: "←/→ select · Enter · ↓ provider · ↑ back",
|
|
707
|
-
provider: "←/→ select · Enter · ↓
|
|
708
|
-
assistant: "←/→ select · Enter · ↓ cron · ↑ back",
|
|
695
|
+
provider: "←/→ select · Enter · ↓ cron · ↑ back",
|
|
709
696
|
cron: "Ctrl+X close · ↑ back",
|
|
710
697
|
resume: "",
|
|
711
698
|
projects: "Use /project switch <index|path>",
|
|
@@ -1081,12 +1068,6 @@ async function runChat(projectRoot, options = {}) {
|
|
|
1081
1068
|
}
|
|
1082
1069
|
}
|
|
1083
1070
|
|
|
1084
|
-
function setAssistantEngine(value) {
|
|
1085
|
-
if (settingsController) {
|
|
1086
|
-
settingsController.setAssistantEngine(value);
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
1071
|
function setAutoResume(value) {
|
|
1091
1072
|
if (settingsController) {
|
|
1092
1073
|
settingsController.setAutoResume(value);
|
|
@@ -1103,7 +1084,6 @@ async function runChat(projectRoot, options = {}) {
|
|
|
1103
1084
|
saveConfig,
|
|
1104
1085
|
normalizeLaunchMode,
|
|
1105
1086
|
normalizeAgentProvider,
|
|
1106
|
-
normalizeAssistantEngine,
|
|
1107
1087
|
fsModule: fs,
|
|
1108
1088
|
getUfooPaths,
|
|
1109
1089
|
logMessage,
|
|
@@ -1124,14 +1104,6 @@ async function runChat(projectRoot, options = {}) {
|
|
|
1124
1104
|
setSelectedProviderIndex: (value) => {
|
|
1125
1105
|
selectedProviderIndex = value;
|
|
1126
1106
|
},
|
|
1127
|
-
getAssistantEngine: () => assistantEngine,
|
|
1128
|
-
setAssistantEngineState: (value) => {
|
|
1129
|
-
assistantEngine = value;
|
|
1130
|
-
},
|
|
1131
|
-
setSelectedAssistantIndex: (value) => {
|
|
1132
|
-
selectedAssistantIndex = value;
|
|
1133
|
-
},
|
|
1134
|
-
assistantOptions,
|
|
1135
1107
|
providerOptions,
|
|
1136
1108
|
modeOptions: MODE_OPTIONS,
|
|
1137
1109
|
getAutoResume: () => autoResume,
|
|
@@ -1180,15 +1152,12 @@ async function runChat(projectRoot, options = {}) {
|
|
|
1180
1152
|
},
|
|
1181
1153
|
launchMode,
|
|
1182
1154
|
agentProvider,
|
|
1183
|
-
assistantEngine,
|
|
1184
1155
|
autoResume,
|
|
1185
1156
|
selectedModeIndex,
|
|
1186
1157
|
selectedProviderIndex,
|
|
1187
|
-
selectedAssistantIndex,
|
|
1188
1158
|
selectedResumeIndex,
|
|
1189
1159
|
cronTasks,
|
|
1190
1160
|
providerOptions,
|
|
1191
|
-
assistantOptions,
|
|
1192
1161
|
resumeOptions,
|
|
1193
1162
|
pendingReports: reportPendingTotal,
|
|
1194
1163
|
dashHints: DASH_HINTS,
|
|
@@ -1337,10 +1306,6 @@ async function runChat(projectRoot, options = {}) {
|
|
|
1337
1306
|
}
|
|
1338
1307
|
selectedModeIndex = Math.max(0, MODE_OPTIONS.indexOf(launchMode));
|
|
1339
1308
|
selectedProviderIndex = Math.max(0, providerOptions.findIndex((opt) => opt.value === agentProvider));
|
|
1340
|
-
selectedAssistantIndex = Math.max(
|
|
1341
|
-
0,
|
|
1342
|
-
assistantOptions.findIndex((opt) => opt.value === assistantEngine)
|
|
1343
|
-
);
|
|
1344
1309
|
selectedResumeIndex = autoResume ? 0 : 1;
|
|
1345
1310
|
// Immediately set @target when first agent is selected.
|
|
1346
1311
|
if (!globalMode && selectedAgentIndex >= 0 && selectedAgentIndex < activeAgents.length) {
|
|
@@ -1368,15 +1333,12 @@ async function runChat(projectRoot, options = {}) {
|
|
|
1368
1333
|
activeAgentMetaMap: { get: () => activeAgentMetaMap },
|
|
1369
1334
|
selectedModeIndex: { get: () => selectedModeIndex, set: (value) => { selectedModeIndex = value; } },
|
|
1370
1335
|
selectedProviderIndex: { get: () => selectedProviderIndex, set: (value) => { selectedProviderIndex = value; } },
|
|
1371
|
-
selectedAssistantIndex: { get: () => selectedAssistantIndex, set: (value) => { selectedAssistantIndex = value; } },
|
|
1372
1336
|
selectedResumeIndex: { get: () => selectedResumeIndex, set: (value) => { selectedResumeIndex = value; } },
|
|
1373
1337
|
launchMode: { get: () => launchMode },
|
|
1374
1338
|
agentProvider: { get: () => agentProvider },
|
|
1375
|
-
assistantEngine: { get: () => assistantEngine },
|
|
1376
1339
|
autoResume: { get: () => autoResume },
|
|
1377
1340
|
cronTasks: { get: () => cronTasks },
|
|
1378
1341
|
providerOptions: { get: () => providerOptions },
|
|
1379
|
-
assistantOptions: { get: () => assistantOptions },
|
|
1380
1342
|
resumeOptions: { get: () => resumeOptions },
|
|
1381
1343
|
agentOutputSuppressed: {
|
|
1382
1344
|
get: () => getAgentOutputSuppressed(),
|
|
@@ -1415,7 +1377,6 @@ async function runChat(projectRoot, options = {}) {
|
|
|
1415
1377
|
exitDashboardMode,
|
|
1416
1378
|
setLaunchMode,
|
|
1417
1379
|
setAgentProvider,
|
|
1418
|
-
setAssistantEngine,
|
|
1419
1380
|
setAutoResume,
|
|
1420
1381
|
clampAgentWindow,
|
|
1421
1382
|
clampAgentWindowWithSelection,
|
|
@@ -6,7 +6,6 @@ function createSettingsController(options = {}) {
|
|
|
6
6
|
saveConfig = () => {},
|
|
7
7
|
normalizeLaunchMode = (value) => value,
|
|
8
8
|
normalizeAgentProvider = (value) => value,
|
|
9
|
-
normalizeAssistantEngine = (value) => value,
|
|
10
9
|
fsModule,
|
|
11
10
|
getUfooPaths = () => ({ agentDir: "" }),
|
|
12
11
|
logMessage = () => {},
|
|
@@ -19,10 +18,6 @@ function createSettingsController(options = {}) {
|
|
|
19
18
|
getAgentProvider = () => "codex-cli",
|
|
20
19
|
setAgentProviderState = () => {},
|
|
21
20
|
setSelectedProviderIndex = () => {},
|
|
22
|
-
getAssistantEngine = () => "auto",
|
|
23
|
-
setAssistantEngineState = () => {},
|
|
24
|
-
setSelectedAssistantIndex = () => {},
|
|
25
|
-
assistantOptions = [],
|
|
26
21
|
providerOptions = [],
|
|
27
22
|
modeOptions = [],
|
|
28
23
|
getAutoResume = () => true,
|
|
@@ -41,14 +36,6 @@ function createSettingsController(options = {}) {
|
|
|
41
36
|
return value === "claude-cli" ? "claude" : "codex";
|
|
42
37
|
}
|
|
43
38
|
|
|
44
|
-
function assistantLabel(value) {
|
|
45
|
-
const normalized = normalizeAssistantEngine(value);
|
|
46
|
-
if (normalized === "codex") return "codex";
|
|
47
|
-
if (normalized === "claude") return "claude";
|
|
48
|
-
if (normalized === "ufoo") return "ufoo";
|
|
49
|
-
return "auto";
|
|
50
|
-
}
|
|
51
|
-
|
|
52
39
|
function clearUfooAgentIdentity() {
|
|
53
40
|
const agentDir = getUfooPaths(projectRoot).agentDir;
|
|
54
41
|
const stateFile = path.join(agentDir, "ufoo-agent.json");
|
|
@@ -106,26 +93,11 @@ function createSettingsController(options = {}) {
|
|
|
106
93
|
return true;
|
|
107
94
|
}
|
|
108
95
|
|
|
109
|
-
function setAssistantEngine(engine) {
|
|
110
|
-
const next = normalizeAssistantEngine(engine);
|
|
111
|
-
if (next === getAssistantEngine()) return false;
|
|
112
|
-
setAssistantEngineState(next);
|
|
113
|
-
const idx = assistantOptions.findIndex((opt) => opt && opt.value === next);
|
|
114
|
-
setSelectedAssistantIndex(idx >= 0 ? idx : 0);
|
|
115
|
-
saveConfig(projectRoot, { assistantEngine: next });
|
|
116
|
-
logMessage("status", `{white-fg}⚙{/white-fg} assistant-engine: ${assistantLabel(next)}`);
|
|
117
|
-
renderDashboard();
|
|
118
|
-
renderScreen();
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
96
|
return {
|
|
123
97
|
providerLabel,
|
|
124
|
-
assistantLabel,
|
|
125
98
|
clearUfooAgentIdentity,
|
|
126
99
|
setLaunchMode,
|
|
127
100
|
setAgentProvider,
|
|
128
|
-
setAssistantEngine,
|
|
129
101
|
setAutoResume,
|
|
130
102
|
};
|
|
131
103
|
}
|
package/src/daemon/cronOps.js
CHANGED
|
@@ -128,18 +128,41 @@ function sanitizeSummaryText(value = "") {
|
|
|
128
128
|
.trim();
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
function
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
131
|
+
function truncateCronText(value = "", maxLength = 24) {
|
|
132
|
+
const text = String(value || "").trim();
|
|
133
|
+
if (!text) return "";
|
|
134
|
+
if (text.length <= maxLength) return text;
|
|
135
|
+
return `${text.slice(0, Math.max(1, maxLength - 3))}...`;
|
|
136
|
+
}
|
|
136
137
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
function normalizeCronTitle(value = "", prompt = "") {
|
|
139
|
+
const explicitTitle = truncateCronText(
|
|
140
|
+
sanitizeSummaryText(value || "").replace(/:/g, "-"),
|
|
141
|
+
24
|
|
142
|
+
);
|
|
143
|
+
if (explicitTitle) return explicitTitle;
|
|
144
|
+
const fallbackTitle = truncateCronText(
|
|
145
|
+
sanitizeSummaryText(prompt || "").replace(/:/g, "-"),
|
|
146
|
+
24
|
|
147
|
+
);
|
|
148
|
+
return fallbackTitle || "(empty)";
|
|
149
|
+
}
|
|
140
150
|
|
|
141
|
-
|
|
142
|
-
|
|
151
|
+
function buildCronLabel(task = {}) {
|
|
152
|
+
const targets = Array.isArray(task.targets) && task.targets.length > 0
|
|
153
|
+
? task.targets.join("+")
|
|
154
|
+
: "unknown";
|
|
155
|
+
const title = normalizeCronTitle(task.title || "", task.prompt || "");
|
|
156
|
+
const schedule = Number(task.onceAtMs) > 0
|
|
157
|
+
? formatCronAtMs(task.onceAtMs)
|
|
158
|
+
: formatIntervalMs(task.intervalMs || 0);
|
|
159
|
+
return `${targets}:${title}:${schedule || "0s"}`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function summarizeCronTask(task = {}) {
|
|
163
|
+
const id = String(task.id || "");
|
|
164
|
+
const label = buildCronLabel(task);
|
|
165
|
+
return id ? `${id} ${label}` : label;
|
|
143
166
|
}
|
|
144
167
|
|
|
145
168
|
function formatCronTask(task = {}) {
|
|
@@ -153,6 +176,8 @@ function formatCronTask(task = {}) {
|
|
|
153
176
|
onceAt: onceAtMs > 0 ? formatCronAtMs(onceAtMs) : "",
|
|
154
177
|
targets: Array.isArray(task.targets) ? task.targets.slice() : [],
|
|
155
178
|
prompt: String(task.prompt || ""),
|
|
179
|
+
title: normalizeCronTitle(task.title || "", task.prompt || ""),
|
|
180
|
+
label: buildCronLabel(task),
|
|
156
181
|
createdAt: Number(task.createdAt) || 0,
|
|
157
182
|
lastRunAt: Number(task.lastRunAt) || 0,
|
|
158
183
|
tickCount: Number(task.tickCount) || 0,
|
|
@@ -160,6 +185,10 @@ function formatCronTask(task = {}) {
|
|
|
160
185
|
};
|
|
161
186
|
}
|
|
162
187
|
|
|
188
|
+
function resolveCronTitle(op = {}) {
|
|
189
|
+
return String(op.title || op.name || op.label || "").trim();
|
|
190
|
+
}
|
|
191
|
+
|
|
163
192
|
function createDaemonCronController(options = {}) {
|
|
164
193
|
const {
|
|
165
194
|
projectRoot = "",
|
|
@@ -198,6 +227,7 @@ function createDaemonCronController(options = {}) {
|
|
|
198
227
|
onceAtMs: task.onceAtMs,
|
|
199
228
|
targets: task.targets.slice(),
|
|
200
229
|
prompt: task.prompt,
|
|
230
|
+
title: task.title,
|
|
201
231
|
createdAt: task.createdAt,
|
|
202
232
|
lastRunAt: task.lastRunAt,
|
|
203
233
|
tickCount: task.tickCount,
|
|
@@ -275,13 +305,14 @@ function createDaemonCronController(options = {}) {
|
|
|
275
305
|
}, task.intervalMs);
|
|
276
306
|
}
|
|
277
307
|
|
|
278
|
-
function addTask({ intervalMs = 0, onceAtMs = 0, targets = [], prompt = "" } = {}) {
|
|
308
|
+
function addTask({ intervalMs = 0, onceAtMs = 0, targets = [], prompt = "", title = "" } = {}) {
|
|
279
309
|
const safeInterval = Number.parseInt(intervalMs, 10);
|
|
280
310
|
const safeOnceAt = Number.parseInt(onceAtMs, 10);
|
|
281
311
|
const safeTargets = Array.isArray(targets)
|
|
282
312
|
? targets.map((item) => String(item || "").trim()).filter(Boolean)
|
|
283
313
|
: [];
|
|
284
314
|
const safePrompt = String(prompt || "").trim();
|
|
315
|
+
const safeTitle = normalizeCronTitle(title, safePrompt);
|
|
285
316
|
|
|
286
317
|
if (!safePrompt || safeTargets.length === 0) return null;
|
|
287
318
|
|
|
@@ -296,6 +327,7 @@ function createDaemonCronController(options = {}) {
|
|
|
296
327
|
onceAtMs: useOnce ? safeOnceAt : 0,
|
|
297
328
|
targets: Array.from(new Set(safeTargets)),
|
|
298
329
|
prompt: safePrompt,
|
|
330
|
+
title: safeTitle,
|
|
299
331
|
createdAt: nowFn(),
|
|
300
332
|
lastRunAt: 0,
|
|
301
333
|
tickCount: 0,
|
|
@@ -367,6 +399,7 @@ function createDaemonCronController(options = {}) {
|
|
|
367
399
|
? item.targets.map((v) => String(v || "").trim()).filter(Boolean)
|
|
368
400
|
: [];
|
|
369
401
|
const prompt = String(item && item.prompt ? item.prompt : "").trim();
|
|
402
|
+
const title = normalizeCronTitle(item && item.title ? item.title : "", prompt);
|
|
370
403
|
|
|
371
404
|
if (!prompt || targets.length === 0) {
|
|
372
405
|
changed = true;
|
|
@@ -389,6 +422,7 @@ function createDaemonCronController(options = {}) {
|
|
|
389
422
|
onceAtMs: Number.isFinite(onceAtMs) ? Math.floor(onceAtMs) : 0,
|
|
390
423
|
targets: Array.from(new Set(targets)),
|
|
391
424
|
prompt,
|
|
425
|
+
title,
|
|
392
426
|
createdAt: Number(item && item.createdAt) || now,
|
|
393
427
|
lastRunAt: Number(item && item.lastRunAt) || 0,
|
|
394
428
|
tickCount: Number(item && item.tickCount) || 0,
|
|
@@ -535,6 +569,7 @@ function createDaemonCronController(options = {}) {
|
|
|
535
569
|
onceAtMs,
|
|
536
570
|
targets,
|
|
537
571
|
prompt,
|
|
572
|
+
title: resolveCronTitle(op),
|
|
538
573
|
});
|
|
539
574
|
|
|
540
575
|
if (!task) {
|
|
@@ -567,8 +602,10 @@ module.exports = {
|
|
|
567
602
|
resolveCronOperation,
|
|
568
603
|
resolveCronIntervalMs,
|
|
569
604
|
resolveCronOnceAtMs,
|
|
605
|
+
resolveCronTitle,
|
|
570
606
|
resolveCronPrompt,
|
|
571
607
|
resolveCronTaskId,
|
|
572
608
|
parseCronAtMs,
|
|
609
|
+
buildCronLabel,
|
|
573
610
|
formatCronTask,
|
|
574
611
|
};
|
package/src/daemon/index.js
CHANGED
|
@@ -915,9 +915,9 @@ function startDaemon({ projectRoot, provider, model, resumeMode = "auto" }) {
|
|
|
915
915
|
}
|
|
916
916
|
} else if (result.operation === "start" && result.task) {
|
|
917
917
|
if (result.task.mode === "once") {
|
|
918
|
-
reply = `Cron scheduled ${result.task.id}
|
|
918
|
+
reply = `Cron scheduled ${result.task.id}: ${result.task.label || result.task.onceAt || result.task.onceAtMs}`;
|
|
919
919
|
} else {
|
|
920
|
-
reply = `Cron started ${result.task.id}:
|
|
920
|
+
reply = `Cron started ${result.task.id}: ${result.task.label || result.task.interval || result.task.intervalMs}`;
|
|
921
921
|
}
|
|
922
922
|
} else {
|
|
923
923
|
reply = "Cron updated";
|
package/src/daemon/status.js
CHANGED
|
@@ -72,6 +72,8 @@ function normalizeCronTasks(raw = []) {
|
|
|
72
72
|
onceAt: String(task && task.onceAt ? task.onceAt : ""),
|
|
73
73
|
targets: Array.isArray(task && task.targets) ? task.targets.slice() : [],
|
|
74
74
|
prompt: String(task && task.prompt ? task.prompt : ""),
|
|
75
|
+
title: String(task && task.title ? task.title : ""),
|
|
76
|
+
label: String(task && task.label ? task.label : ""),
|
|
75
77
|
summary: String(task && task.summary ? task.summary : ""),
|
|
76
78
|
createdAt: Number(task && task.createdAt ? task.createdAt : 0) || 0,
|
|
77
79
|
lastRunAt: Number(task && task.lastRunAt ? task.lastRunAt : 0) || 0,
|