u-foo 1.0.3 → 1.1.9

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.
Files changed (179) hide show
  1. package/README.md +110 -11
  2. package/README.zh-CN.md +9 -7
  3. package/SKILLS/ufoo/SKILL.md +132 -0
  4. package/SKILLS/uinit/SKILL.md +78 -0
  5. package/SKILLS/ustatus/SKILL.md +36 -0
  6. package/bin/uclaude.js +13 -0
  7. package/bin/ucode-core.js +15 -0
  8. package/bin/ucode.js +125 -0
  9. package/bin/ucodex.js +13 -0
  10. package/bin/ufoo +9 -31
  11. package/bin/ufoo-assistant-agent.js +5 -0
  12. package/bin/ufoo-engine.js +25 -0
  13. package/bin/ufoo.js +17 -0
  14. package/modules/AGENTS.template.md +29 -11
  15. package/modules/bus/README.md +33 -25
  16. package/modules/bus/SKILLS/ubus/SKILL.md +19 -8
  17. package/modules/context/README.md +18 -40
  18. package/modules/context/SKILLS/uctx/SKILL.md +63 -1
  19. package/modules/online/SKILLS/ufoo-online/SKILL.md +144 -0
  20. package/package.json +25 -4
  21. package/scripts/import-pi-mono.js +124 -0
  22. package/scripts/postinstall.js +30 -0
  23. package/scripts/sync-claude-skills.sh +21 -0
  24. package/src/agent/cliRunner.js +554 -33
  25. package/src/agent/internalRunner.js +150 -56
  26. package/src/agent/launcher.js +754 -0
  27. package/src/agent/normalizeOutput.js +1 -1
  28. package/src/agent/notifier.js +340 -0
  29. package/src/agent/ptyRunner.js +847 -0
  30. package/src/agent/ptyWrapper.js +379 -0
  31. package/src/agent/readyDetector.js +175 -0
  32. package/src/agent/ucode.js +443 -0
  33. package/src/agent/ucodeBootstrap.js +113 -0
  34. package/src/agent/ucodeBuild.js +67 -0
  35. package/src/agent/ucodeDoctor.js +184 -0
  36. package/src/agent/ucodeRuntimeConfig.js +129 -0
  37. package/src/agent/ufooAgent.js +46 -42
  38. package/src/assistant/agent.js +260 -0
  39. package/src/assistant/bridge.js +172 -0
  40. package/src/assistant/engine.js +252 -0
  41. package/src/assistant/stdio.js +58 -0
  42. package/src/assistant/ufooEngineCli.js +306 -0
  43. package/src/bus/activate.js +172 -0
  44. package/src/bus/daemon.js +436 -0
  45. package/src/bus/index.js +842 -0
  46. package/src/bus/inject.js +315 -0
  47. package/src/bus/message.js +430 -0
  48. package/src/bus/nickname.js +88 -0
  49. package/src/bus/queue.js +136 -0
  50. package/src/bus/shake.js +26 -0
  51. package/src/bus/store.js +189 -0
  52. package/src/bus/subscriber.js +312 -0
  53. package/src/bus/utils.js +363 -0
  54. package/src/chat/agentBar.js +117 -0
  55. package/src/chat/agentDirectory.js +88 -0
  56. package/src/chat/agentSockets.js +225 -0
  57. package/src/chat/agentViewController.js +298 -0
  58. package/src/chat/chatLogController.js +115 -0
  59. package/src/chat/commandExecutor.js +700 -0
  60. package/src/chat/commands.js +132 -0
  61. package/src/chat/completionController.js +414 -0
  62. package/src/chat/cronScheduler.js +160 -0
  63. package/src/chat/daemonConnection.js +166 -0
  64. package/src/chat/daemonCoordinator.js +64 -0
  65. package/src/chat/daemonMessageRouter.js +257 -0
  66. package/src/chat/daemonReconnect.js +41 -0
  67. package/src/chat/daemonTransport.js +36 -0
  68. package/src/chat/daemonTransportDefaults.js +10 -0
  69. package/src/chat/dashboardKeyController.js +480 -0
  70. package/src/chat/dashboardView.js +154 -0
  71. package/src/chat/index.js +1011 -1392
  72. package/src/chat/inputHistoryController.js +105 -0
  73. package/src/chat/inputListenerController.js +304 -0
  74. package/src/chat/inputMath.js +104 -0
  75. package/src/chat/inputSubmitHandler.js +171 -0
  76. package/src/chat/layout.js +165 -0
  77. package/src/chat/pasteController.js +81 -0
  78. package/src/chat/rawKeyMap.js +42 -0
  79. package/src/chat/settingsController.js +132 -0
  80. package/src/chat/statusLineController.js +177 -0
  81. package/src/chat/streamTracker.js +138 -0
  82. package/src/chat/text.js +70 -0
  83. package/src/chat/transport.js +61 -0
  84. package/src/cli/busCoreCommands.js +59 -0
  85. package/src/cli/ctxCoreCommands.js +199 -0
  86. package/src/cli/onlineCoreCommands.js +379 -0
  87. package/src/cli.js +1162 -96
  88. package/src/code/README.md +29 -0
  89. package/src/code/UCODE_PROMPT.md +32 -0
  90. package/src/code/agent.js +1651 -0
  91. package/src/code/cli.js +158 -0
  92. package/src/code/config +0 -0
  93. package/src/code/dispatch.js +42 -0
  94. package/src/code/index.js +70 -0
  95. package/src/code/nativeRunner.js +1213 -0
  96. package/src/code/runtime.js +154 -0
  97. package/src/code/sessionStore.js +162 -0
  98. package/src/code/taskDecomposer.js +269 -0
  99. package/src/code/tools/bash.js +53 -0
  100. package/src/code/tools/common.js +42 -0
  101. package/src/code/tools/edit.js +70 -0
  102. package/src/code/tools/read.js +44 -0
  103. package/src/code/tools/write.js +35 -0
  104. package/src/code/tui.js +1580 -0
  105. package/src/config.js +56 -3
  106. package/src/context/decisions.js +324 -0
  107. package/src/context/doctor.js +183 -0
  108. package/src/context/index.js +55 -0
  109. package/src/context/sync.js +127 -0
  110. package/src/daemon/agentProcessManager.js +74 -0
  111. package/src/daemon/cronOps.js +241 -0
  112. package/src/daemon/index.js +998 -170
  113. package/src/daemon/ipcServer.js +99 -0
  114. package/src/daemon/ops.js +630 -48
  115. package/src/daemon/promptLoop.js +319 -0
  116. package/src/daemon/promptRequest.js +101 -0
  117. package/src/daemon/providerSessions.js +306 -0
  118. package/src/daemon/reporting.js +90 -0
  119. package/src/daemon/run.js +31 -1
  120. package/src/daemon/status.js +48 -8
  121. package/src/doctor/index.js +50 -0
  122. package/src/init/index.js +318 -0
  123. package/src/online/bridge.js +663 -0
  124. package/src/online/client.js +245 -0
  125. package/src/online/runner.js +253 -0
  126. package/src/online/server.js +992 -0
  127. package/src/online/tokens.js +103 -0
  128. package/src/report/store.js +331 -0
  129. package/src/shared/eventContract.js +35 -0
  130. package/src/shared/ptySocketContract.js +21 -0
  131. package/src/skills/index.js +159 -0
  132. package/src/status/index.js +285 -0
  133. package/src/terminal/adapterContract.js +87 -0
  134. package/src/terminal/adapterRouter.js +84 -0
  135. package/src/terminal/adapters/externalAdapter.js +14 -0
  136. package/src/terminal/adapters/internalAdapter.js +13 -0
  137. package/src/terminal/adapters/internalPtyAdapter.js +42 -0
  138. package/src/terminal/adapters/internalQueueAdapter.js +37 -0
  139. package/src/terminal/adapters/terminalAdapter.js +31 -0
  140. package/src/terminal/adapters/tmuxAdapter.js +30 -0
  141. package/src/terminal/detect.js +64 -0
  142. package/src/terminal/index.js +8 -0
  143. package/src/terminal/iterm2.js +126 -0
  144. package/src/ufoo/agentsStore.js +107 -0
  145. package/src/ufoo/paths.js +46 -0
  146. package/src/utils/banner.js +76 -0
  147. package/bin/uclaude +0 -65
  148. package/bin/ucodex +0 -65
  149. package/modules/bus/scripts/bus-alert.sh +0 -185
  150. package/modules/bus/scripts/bus-listen.sh +0 -117
  151. package/modules/context/ASSUMPTIONS.md +0 -7
  152. package/modules/context/CONSTRAINTS.md +0 -7
  153. package/modules/context/CONTEXT-STRUCTURE.md +0 -49
  154. package/modules/context/DECISION-PROTOCOL.md +0 -62
  155. package/modules/context/HANDOFF.md +0 -33
  156. package/modules/context/RULES.md +0 -15
  157. package/modules/context/SKILLS/README.md +0 -14
  158. package/modules/context/SYSTEM.md +0 -18
  159. package/modules/context/TEMPLATES/assumptions.md +0 -4
  160. package/modules/context/TEMPLATES/constraints.md +0 -4
  161. package/modules/context/TEMPLATES/decision.md +0 -16
  162. package/modules/context/TEMPLATES/project-context-readme.md +0 -6
  163. package/modules/context/TEMPLATES/system.md +0 -3
  164. package/modules/context/TEMPLATES/terminology.md +0 -4
  165. package/modules/context/TERMINOLOGY.md +0 -10
  166. package/scripts/banner.sh +0 -89
  167. package/scripts/bus-alert.sh +0 -6
  168. package/scripts/bus-autotrigger.sh +0 -6
  169. package/scripts/bus-daemon.sh +0 -231
  170. package/scripts/bus-inject.sh +0 -144
  171. package/scripts/bus-listen.sh +0 -6
  172. package/scripts/bus.sh +0 -984
  173. package/scripts/context-decisions.sh +0 -167
  174. package/scripts/context-doctor.sh +0 -72
  175. package/scripts/context-lint.sh +0 -110
  176. package/scripts/doctor.sh +0 -22
  177. package/scripts/init.sh +0 -247
  178. package/scripts/skills.sh +0 -113
  179. package/scripts/status.sh +0 -125
@@ -0,0 +1,127 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ /**
5
+ * Sync log manager
6
+ * Stores lightweight agent progress notes as JSONL.
7
+ */
8
+ class SyncManager {
9
+ constructor(projectRoot) {
10
+ this.projectRoot = projectRoot;
11
+ this.contextDir = path.join(projectRoot, ".ufoo", "context");
12
+ this.syncFile = path.join(this.contextDir, "sync.jsonl");
13
+ }
14
+
15
+ ensureContextDir() {
16
+ fs.mkdirSync(this.contextDir, { recursive: true });
17
+ }
18
+
19
+ parseLines() {
20
+ if (!fs.existsSync(this.syncFile)) return [];
21
+ const raw = fs.readFileSync(this.syncFile, "utf8");
22
+ if (!raw.trim()) return [];
23
+ const lines = raw
24
+ .split(/\r?\n/)
25
+ .map((line) => line.trim())
26
+ .filter(Boolean);
27
+
28
+ const entries = [];
29
+ for (const line of lines) {
30
+ try {
31
+ entries.push(JSON.parse(line));
32
+ } catch {
33
+ // Skip malformed legacy lines.
34
+ }
35
+ }
36
+ return entries;
37
+ }
38
+
39
+ normalizeActor(value, fallback = "unknown") {
40
+ const text = String(value || "").trim();
41
+ if (text) return text;
42
+ return fallback;
43
+ }
44
+
45
+ buildEntry(options = {}) {
46
+ const message = String(options.message || "").trim();
47
+ if (!message) {
48
+ throw new Error(
49
+ "Missing sync message. Usage: ufoo ctx sync write [--for <agent>] \"message\""
50
+ );
51
+ }
52
+
53
+ return {
54
+ ts: new Date().toISOString(),
55
+ type: "sync",
56
+ from: this.normalizeActor(
57
+ options.from,
58
+ process.env.UFOO_SUBSCRIBER_ID ||
59
+ process.env.UFOO_NICKNAME ||
60
+ process.env.USER ||
61
+ process.env.USERNAME ||
62
+ "unknown"
63
+ ),
64
+ for: this.normalizeActor(options.for, ""),
65
+ message,
66
+ decision: String(options.decision || "").trim(),
67
+ file: String(options.file || "").trim(),
68
+ tests: String(options.tests || "").trim(),
69
+ verification: String(options.verification || "").trim(),
70
+ risk: String(options.risk || "").trim(),
71
+ next: String(options.next || "").trim(),
72
+ };
73
+ }
74
+
75
+ write(options = {}) {
76
+ const entry = this.buildEntry(options);
77
+ this.ensureContextDir();
78
+ fs.appendFileSync(this.syncFile, `${JSON.stringify(entry)}\n`, "utf8");
79
+ console.log(this.formatEntry(entry));
80
+ return entry;
81
+ }
82
+
83
+ formatEntry(entry) {
84
+ const parts = [];
85
+ parts.push("[sync]");
86
+ if (entry.for) parts.push(`[for ${entry.for}]`);
87
+ if (entry.from) parts.push(`[from ${entry.from}]`);
88
+ parts.push(entry.message);
89
+
90
+ if (entry.decision) parts.push(`decision: ${entry.decision}.`);
91
+ if (entry.file) parts.push(`file: ${entry.file}.`);
92
+ if (entry.tests) parts.push(`tests: ${entry.tests}.`);
93
+ if (entry.verification) parts.push(`verification: ${entry.verification}.`);
94
+ if (entry.risk) parts.push(`risk: ${entry.risk}.`);
95
+ if (entry.next) parts.push(`next-cut: ${entry.next}.`);
96
+
97
+ return parts.join(" ");
98
+ }
99
+
100
+ list(options = {}) {
101
+ const num = Number.isFinite(options.num) && options.num > 0 ? options.num : 20;
102
+ const filterFor = String(options.for || "").trim();
103
+ const filterFrom = String(options.from || "").trim();
104
+
105
+ let entries = this.parseLines();
106
+ if (filterFor) entries = entries.filter((entry) => String(entry.for || "") === filterFor);
107
+ if (filterFrom) entries = entries.filter((entry) => String(entry.from || "") === filterFrom);
108
+
109
+ entries.sort((a, b) => {
110
+ const left = new Date(a.ts || 0).getTime();
111
+ const right = new Date(b.ts || 0).getTime();
112
+ return right - left;
113
+ });
114
+
115
+ const shown = entries.slice(0, num);
116
+ console.log(`=== Sync (${shown.length} shown, ${entries.length} matched) ===`);
117
+ for (const entry of shown) {
118
+ console.log(`${entry.ts || "-"} ${this.formatEntry(entry)}`);
119
+ }
120
+ if (shown.length === 0) {
121
+ console.log("No sync entries found.");
122
+ }
123
+ return shown;
124
+ }
125
+ }
126
+
127
+ module.exports = SyncManager;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+
3
+ const EventBus = require("../bus");
4
+
5
+ class AgentProcessManager {
6
+ constructor(projectRoot) {
7
+ this.projectRoot = projectRoot;
8
+ this.processes = new Map(); // subscriber_id -> child_process
9
+ }
10
+
11
+ /**
12
+ * 注册子进程并监听退出事件
13
+ */
14
+ register(subscriberId, childProcess) {
15
+ if (!subscriberId || !childProcess) return;
16
+
17
+ this.processes.set(subscriberId, childProcess);
18
+
19
+ childProcess.on("exit", (code, signal) => {
20
+ this.processes.delete(subscriberId);
21
+
22
+ // 自动清理 bus 状态
23
+ try {
24
+ const eventBus = new EventBus(this.projectRoot);
25
+ eventBus.loadBusData();
26
+ if (eventBus.busData.agents?.[subscriberId]) {
27
+ eventBus.busData.agents[subscriberId].status = "inactive";
28
+ eventBus.busData.agents[subscriberId].last_seen = new Date().toISOString();
29
+ eventBus.saveBusData();
30
+ console.log(`[daemon] Agent ${subscriberId} exited (code=${code}, signal=${signal}), marked inactive`);
31
+ }
32
+ } catch (err) {
33
+ console.error(`[daemon] Failed to cleanup ${subscriberId}:`, err.message);
34
+ }
35
+ });
36
+
37
+ childProcess.on("error", (err) => {
38
+ console.error(`[daemon] Agent ${subscriberId} error:`, err.message);
39
+ this.processes.delete(subscriberId);
40
+ });
41
+ }
42
+
43
+ /**
44
+ * 获取运行中的进程
45
+ */
46
+ get(subscriberId) {
47
+ return this.processes.get(subscriberId);
48
+ }
49
+
50
+ /**
51
+ * 获取所有进程数量
52
+ */
53
+ count() {
54
+ return this.processes.size;
55
+ }
56
+
57
+ /**
58
+ * 清理所有子进程
59
+ */
60
+ cleanup() {
61
+ for (const [subscriberId, child] of this.processes.entries()) {
62
+ try {
63
+ child.kill("SIGTERM");
64
+ console.log(`[daemon] Killed agent ${subscriberId}`);
65
+ } catch {
66
+ // ignore
67
+ }
68
+ }
69
+ this.processes.clear();
70
+ }
71
+ }
72
+
73
+
74
+ module.exports = { AgentProcessManager };
@@ -0,0 +1,241 @@
1
+ const {
2
+ createCronScheduler,
3
+ parseIntervalMs,
4
+ formatIntervalMs,
5
+ } = require("../chat/cronScheduler");
6
+
7
+ function splitTargets(value = "") {
8
+ return String(value || "")
9
+ .split(",")
10
+ .map((item) => item.trim())
11
+ .filter(Boolean);
12
+ }
13
+
14
+ function normalizeCronTargets(op = {}) {
15
+ const fromArray = Array.isArray(op.targets)
16
+ ? op.targets.map((item) => String(item || "").trim()).filter(Boolean)
17
+ : [];
18
+ if (fromArray.length > 0) return Array.from(new Set(fromArray));
19
+
20
+ const merged = [
21
+ op.target,
22
+ op.agent,
23
+ op.to,
24
+ ]
25
+ .map((item) => String(item || "").trim())
26
+ .filter(Boolean)
27
+ .join(",");
28
+
29
+ return Array.from(new Set(splitTargets(merged)));
30
+ }
31
+
32
+ function resolveCronOperation(op = {}) {
33
+ const raw = String(op.operation || op.op || op.command || "").trim().toLowerCase();
34
+ if (raw) return raw;
35
+ if (op.list === true) return "list";
36
+ if (op.stop === true) return "stop";
37
+ if (op.id || op.task_id || op.taskId) return "stop";
38
+ return "start";
39
+ }
40
+
41
+ function resolveCronIntervalMs(op = {}) {
42
+ const numeric = Number(op.interval_ms ?? op.intervalMs);
43
+ if (Number.isFinite(numeric) && numeric > 0) {
44
+ return Math.floor(numeric);
45
+ }
46
+
47
+ const everyRaw = String(op.every || op.interval || op.ms || "").trim();
48
+ if (!everyRaw) return 0;
49
+ return parseIntervalMs(everyRaw);
50
+ }
51
+
52
+ function resolveCronPrompt(op = {}) {
53
+ return String(op.prompt || op.message || op.msg || "").trim();
54
+ }
55
+
56
+ function resolveCronTaskId(op = {}) {
57
+ return String(op.id || op.task_id || op.taskId || "").trim();
58
+ }
59
+
60
+ function formatCronTask(task = {}) {
61
+ return {
62
+ id: String(task.id || ""),
63
+ intervalMs: Number(task.intervalMs) || 0,
64
+ interval: formatIntervalMs(task.intervalMs || 0),
65
+ targets: Array.isArray(task.targets) ? task.targets.slice() : [],
66
+ prompt: String(task.prompt || ""),
67
+ createdAt: Number(task.createdAt) || 0,
68
+ lastRunAt: Number(task.lastRunAt) || 0,
69
+ tickCount: Number(task.tickCount) || 0,
70
+ summary: String(task.summary || ""),
71
+ };
72
+ }
73
+
74
+ function createDaemonCronController(options = {}) {
75
+ const {
76
+ dispatch = async () => {},
77
+ log = () => {},
78
+ setIntervalFn,
79
+ clearIntervalFn,
80
+ nowFn,
81
+ } = options;
82
+
83
+ const scheduler = createCronScheduler({
84
+ dispatch: ({ taskId, target, message }) => {
85
+ try {
86
+ Promise.resolve(dispatch({ taskId, target, message })).catch((err) => {
87
+ const detail = err && err.message ? err.message : String(err || "dispatch failed");
88
+ log(`cron dispatch failed task=${taskId} target=${target}: ${detail}`);
89
+ });
90
+ } catch (err) {
91
+ const detail = err && err.message ? err.message : String(err || "dispatch failed");
92
+ log(`cron dispatch failed task=${taskId} target=${target}: ${detail}`);
93
+ }
94
+ },
95
+ setIntervalFn,
96
+ clearIntervalFn,
97
+ nowFn,
98
+ });
99
+
100
+ function listTasks() {
101
+ return scheduler.listTasks().map(formatCronTask);
102
+ }
103
+
104
+ function handleCronOp(op = {}) {
105
+ const operation = resolveCronOperation(op);
106
+
107
+ if (operation === "list" || operation === "ls") {
108
+ const tasks = listTasks();
109
+ return {
110
+ action: "cron",
111
+ operation: "list",
112
+ ok: true,
113
+ count: tasks.length,
114
+ tasks,
115
+ };
116
+ }
117
+
118
+ if (operation === "stop" || operation === "rm" || operation === "remove") {
119
+ const id = resolveCronTaskId(op);
120
+ if (!id) {
121
+ return {
122
+ action: "cron",
123
+ operation: "stop",
124
+ ok: false,
125
+ error: "cron stop requires id or all",
126
+ };
127
+ }
128
+
129
+ if (id === "all") {
130
+ const stopped = scheduler.stopAll();
131
+ return {
132
+ action: "cron",
133
+ operation: "stop",
134
+ ok: true,
135
+ id: "all",
136
+ stopped,
137
+ };
138
+ }
139
+
140
+ const ok = scheduler.stopTask(id);
141
+ if (!ok) {
142
+ return {
143
+ action: "cron",
144
+ operation: "stop",
145
+ ok: false,
146
+ id,
147
+ error: `cron task not found: ${id}`,
148
+ };
149
+ }
150
+
151
+ return {
152
+ action: "cron",
153
+ operation: "stop",
154
+ ok: true,
155
+ id,
156
+ stopped: 1,
157
+ };
158
+ }
159
+
160
+ if (operation !== "start" && operation !== "add" && operation !== "create") {
161
+ return {
162
+ action: "cron",
163
+ operation,
164
+ ok: false,
165
+ error: `unsupported cron operation: ${operation}`,
166
+ };
167
+ }
168
+
169
+ const intervalMs = resolveCronIntervalMs(op);
170
+ if (!Number.isFinite(intervalMs) || intervalMs < 1000) {
171
+ return {
172
+ action: "cron",
173
+ operation: "start",
174
+ ok: false,
175
+ error: "invalid cron interval (min 1s)",
176
+ };
177
+ }
178
+
179
+ const targets = normalizeCronTargets(op);
180
+ if (targets.length === 0) {
181
+ return {
182
+ action: "cron",
183
+ operation: "start",
184
+ ok: false,
185
+ error: "cron start requires at least one target",
186
+ };
187
+ }
188
+
189
+ const prompt = resolveCronPrompt(op);
190
+ if (!prompt) {
191
+ return {
192
+ action: "cron",
193
+ operation: "start",
194
+ ok: false,
195
+ error: "cron start requires prompt",
196
+ };
197
+ }
198
+
199
+ const task = scheduler.addTask({
200
+ intervalMs,
201
+ targets,
202
+ prompt,
203
+ });
204
+
205
+ if (!task) {
206
+ return {
207
+ action: "cron",
208
+ operation: "start",
209
+ ok: false,
210
+ error: "failed to create cron task",
211
+ };
212
+ }
213
+
214
+ return {
215
+ action: "cron",
216
+ operation: "start",
217
+ ok: true,
218
+ task: formatCronTask(task),
219
+ };
220
+ }
221
+
222
+ function stopAll() {
223
+ return scheduler.stopAll();
224
+ }
225
+
226
+ return {
227
+ handleCronOp,
228
+ listTasks,
229
+ stopAll,
230
+ };
231
+ }
232
+
233
+ module.exports = {
234
+ createDaemonCronController,
235
+ normalizeCronTargets,
236
+ resolveCronOperation,
237
+ resolveCronIntervalMs,
238
+ resolveCronPrompt,
239
+ resolveCronTaskId,
240
+ formatCronTask,
241
+ };