u-foo 2.4.5 → 2.4.7

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 (64) hide show
  1. package/README.md +6 -8
  2. package/README.zh-CN.md +5 -5
  3. package/SKILLS/ufoo/SKILL.md +2 -2
  4. package/SKILLS/uinit/SKILL.md +8 -11
  5. package/package.json +3 -8
  6. package/scripts/postinstall.js +1 -21
  7. package/src/agents/launch/launcher.js +1 -13
  8. package/src/app/chat/commandExecutor.js +14 -9
  9. package/src/app/chat/commands.js +2 -2
  10. package/src/app/chat/daemonCoordinator.js +4 -0
  11. package/src/app/chat/daemonReconnect.js +17 -7
  12. package/src/app/cli/features/doctor.js +11 -18
  13. package/src/app/cli/features/init.js +12 -191
  14. package/src/app/cli/features/skills.js +0 -15
  15. package/src/app/cli/run.js +12 -7
  16. package/src/code/README.md +4 -4
  17. package/src/code/cli.js +1 -1
  18. package/src/code/launcher/ucode.js +18 -45
  19. package/src/code/skills/loader.js +0 -13
  20. package/src/coordination/context/doctor.js +6 -26
  21. package/src/online/server.js +1 -1
  22. package/src/runtime/daemon/index.js +1 -1
  23. package/src/runtime/daemon/mcpServer.js +1 -1
  24. package/src/runtime/daemon/restart.js +293 -0
  25. package/src/runtime/daemon/run.js +31 -37
  26. package/src/runtime/terminal/index.js +1 -1
  27. package/src/ui/MIGRATION.md +8 -10
  28. package/src/ui/ink/ChatApp.js +12 -6
  29. package/bin/ucode-core.js +0 -15
  30. package/bin/ufoo +0 -71
  31. package/modules/AGENTS.template.md +0 -8
  32. package/modules/bus/README.md +0 -140
  33. package/modules/context/README.md +0 -60
  34. package/modules/online/README.md +0 -92
  35. package/modules/resources/ICONS/README.md +0 -12
  36. package/modules/resources/ICONS/libraries/README.md +0 -17
  37. package/modules/resources/ICONS/libraries/heroicons/LICENSE +0 -22
  38. package/modules/resources/ICONS/libraries/heroicons/README.md +0 -15
  39. package/modules/resources/ICONS/libraries/heroicons/arrow-right.svg +0 -4
  40. package/modules/resources/ICONS/libraries/heroicons/check.svg +0 -4
  41. package/modules/resources/ICONS/libraries/heroicons/chevron-down.svg +0 -4
  42. package/modules/resources/ICONS/libraries/heroicons/cog-6-tooth.svg +0 -5
  43. package/modules/resources/ICONS/libraries/heroicons/magnifying-glass.svg +0 -4
  44. package/modules/resources/ICONS/libraries/heroicons/x-mark.svg +0 -4
  45. package/modules/resources/ICONS/libraries/lucide/LICENSE +0 -40
  46. package/modules/resources/ICONS/libraries/lucide/README.md +0 -15
  47. package/modules/resources/ICONS/libraries/lucide/arrow-right.svg +0 -15
  48. package/modules/resources/ICONS/libraries/lucide/check.svg +0 -14
  49. package/modules/resources/ICONS/libraries/lucide/chevron-down.svg +0 -14
  50. package/modules/resources/ICONS/libraries/lucide/search.svg +0 -15
  51. package/modules/resources/ICONS/libraries/lucide/settings.svg +0 -15
  52. package/modules/resources/ICONS/libraries/lucide/x.svg +0 -15
  53. package/modules/resources/ICONS/rules.md +0 -7
  54. package/modules/resources/README.md +0 -9
  55. package/modules/resources/UI/ANTI-PATTERNS.md +0 -6
  56. package/modules/resources/UI/TONE.md +0 -6
  57. package/scripts/chat-app-smoke.js +0 -30
  58. package/scripts/global-chat-switch-benchmark.js +0 -406
  59. package/scripts/ink-demo.js +0 -23
  60. package/scripts/ink-smoke.js +0 -30
  61. package/scripts/ucode-app-smoke.js +0 -36
  62. /package/{modules/bus/SKILLS → SKILLS}/ubus/SKILL.md +0 -0
  63. /package/{modules/context/SKILLS → SKILLS}/uctx/SKILL.md +0 -0
  64. /package/{modules/online/SKILLS → SKILLS}/ufoo-online/SKILL.md +0 -0
@@ -7,23 +7,22 @@ const path = require("path");
7
7
  class UfooInit {
8
8
  constructor(repoRoot) {
9
9
  this.repoRoot = repoRoot;
10
- this.contextMod = path.join(repoRoot, "modules", "context");
11
- this.busMod = path.join(repoRoot, "modules", "bus");
12
- this.resourcesMod = path.join(repoRoot, "modules", "resources");
13
- this.agentsTemplate = path.join(repoRoot, "modules", "AGENTS.template.md");
14
10
  }
15
11
 
16
12
  /**
17
13
  * 初始化项目
18
14
  */
19
15
  async init(options = {}) {
20
- const modules = (options.modules || "context").split(",");
16
+ const targets = (options.targets || options.modules || "context")
17
+ .split(",")
18
+ .map((item) => item.trim())
19
+ .filter(Boolean);
21
20
  const project = options.project || process.cwd();
22
21
  const controllerMode = options.controllerMode === true;
23
22
 
24
23
  console.log("=== ufoo init ===");
25
24
  console.log(`Project directory: ${project}`);
26
- console.log(`Modules: ${modules.join(", ")}`);
25
+ console.log(`Targets: ${targets.join(", ")}`);
27
26
  console.log();
28
27
 
29
28
  if (!controllerMode) {
@@ -33,24 +32,17 @@ class UfooInit {
33
32
  // 初始化核心
34
33
  this.initCore(project, { controllerMode });
35
34
 
36
- if (!controllerMode) {
37
- this.injectAgentsTemplate(project);
38
- }
39
-
40
- // 初始化各模块
41
- for (const module of modules) {
42
- switch (module.trim()) {
35
+ // Initialize selected workspace features.
36
+ for (const target of targets) {
37
+ switch (target) {
43
38
  case "context":
44
39
  this.initContext(project);
45
40
  break;
46
41
  case "bus":
47
42
  await this.initBus(project);
48
43
  break;
49
- case "resources":
50
- this.initResources(project);
51
- break;
52
44
  default:
53
- console.error(`Unknown module: ${module}`);
45
+ console.error(`Unknown init target: ${target}`);
54
46
  }
55
47
  }
56
48
 
@@ -121,106 +113,7 @@ class UfooInit {
121
113
  }
122
114
 
123
115
  /**
124
- * 注入 ufoo 模板到 AGENTS.md / CLAUDE.md
125
- */
126
- injectAgentsTemplate(project) {
127
- if (!fs.existsSync(this.agentsTemplate)) {
128
- console.log("[template] AGENTS.template.md not found, skipping");
129
- return;
130
- }
131
-
132
- const template = fs.readFileSync(this.agentsTemplate, "utf8");
133
- const targets = this.resolveTemplateTargets(project);
134
- if (targets.length === 0) {
135
- console.log("[template] No target markdown files found, skipping");
136
- return;
137
- }
138
-
139
- const labels = targets.map((file) => path.relative(project, file) || path.basename(file));
140
- console.log(`[template] Injecting ufoo template into: ${labels.join(", ")}`);
141
-
142
- for (const file of targets) {
143
- this.injectTemplateIntoFile(file, template);
144
- }
145
-
146
- console.log("[template] Done");
147
- }
148
-
149
- resolveTemplateTargets(project) {
150
- const agentsFile = path.resolve(path.join(project, "AGENTS.md"));
151
- const claudeFile = path.resolve(path.join(project, "CLAUDE.md"));
152
- const targets = new Set();
153
-
154
- if (fs.existsSync(agentsFile)) {
155
- targets.add(agentsFile);
156
- }
157
-
158
- const claudeStat = this.safeLstat(claudeFile);
159
- if (!claudeStat) return Array.from(targets);
160
-
161
- if (claudeStat.isSymbolicLink()) {
162
- try {
163
- const rawTarget = fs.readlinkSync(claudeFile);
164
- const sourceFile = path.resolve(path.dirname(claudeFile), rawTarget);
165
- const projectRoot = path.resolve(project);
166
- const inProject = sourceFile === projectRoot || sourceFile.startsWith(`${projectRoot}${path.sep}`);
167
- if (inProject) {
168
- targets.add(sourceFile);
169
- } else {
170
- console.warn(`[template] CLAUDE.md symlink target outside project, skipped: ${sourceFile}`);
171
- }
172
- } catch {
173
- // ignore broken symlink
174
- }
175
- return Array.from(targets);
176
- }
177
-
178
- targets.add(claudeFile);
179
- return Array.from(targets);
180
- }
181
-
182
- injectTemplateIntoFile(filePath, template) {
183
- if (!fs.existsSync(filePath)) return;
184
-
185
- let content = fs.readFileSync(filePath, "utf8");
186
- const marker = "<!-- ufoo-template -->";
187
- const block = `${marker}\n${template}\n${marker}`;
188
-
189
- if (content.includes(marker)) {
190
- const startIdx = content.indexOf(marker);
191
- const endIdx = content.indexOf(marker, startIdx + marker.length);
192
- if (endIdx !== -1) {
193
- content = content.slice(0, startIdx) + block + content.slice(endIdx + marker.length);
194
- } else {
195
- content = content.slice(0, startIdx) + block + content.slice(startIdx + marker.length);
196
- }
197
- } else {
198
- const headingEnd = this.findFirstHeadingEnd(content);
199
- if (headingEnd !== -1) {
200
- content = content.slice(0, headingEnd) + `\n${block}\n\n` + content.slice(headingEnd);
201
- } else {
202
- content = `${block}\n\n${content}`;
203
- }
204
- }
205
- fs.writeFileSync(filePath, content, "utf8");
206
- }
207
-
208
- findFirstHeadingEnd(content) {
209
- const atxHeading = content.match(/^(?:[ \t]{0,3})#{1,6}[ \t]*[^\n]*(?:\n|$)/m);
210
- const setextHeading = content.match(/^[^\n]+\n(?:=+|-+)[ \t]*(?:\n|$)/m);
211
-
212
- let bestMatch = null;
213
- if (atxHeading && setextHeading) {
214
- bestMatch = atxHeading.index <= setextHeading.index ? atxHeading : setextHeading;
215
- } else {
216
- bestMatch = atxHeading || setextHeading;
217
- }
218
- if (!bestMatch) return -1;
219
- return bestMatch.index + bestMatch[0].length;
220
- }
221
-
222
- /**
223
- * 初始化 context 模块
116
+ * 初始化 context
224
117
  */
225
118
  initContext(project) {
226
119
  console.log("[context] Initializing decision-only context...");
@@ -247,10 +140,10 @@ class UfooInit {
247
140
  }
248
141
 
249
142
  /**
250
- * 初始化 bus 模块
143
+ * 初始化 bus
251
144
  */
252
145
  async initBus(project) {
253
- console.log("[bus] Initializing bus module...");
146
+ console.log("[bus] Initializing bus...");
254
147
 
255
148
  const EventBus = require("../../../coordination/bus");
256
149
  const bus = new EventBus(project);
@@ -263,78 +156,6 @@ class UfooInit {
263
156
  }
264
157
  }
265
158
 
266
- /**
267
- * 初始化 resources 模块
268
- */
269
- initResources(project) {
270
- if (!fs.existsSync(this.resourcesMod)) {
271
- console.log("[resources] Module not found, skipping");
272
- return;
273
- }
274
-
275
- console.log("[resources] Initializing resources module...");
276
-
277
- const targetDir = path.join(project, ".ufoo", "resources");
278
-
279
- // 复制模块内容
280
- this.copyModuleContent(this.resourcesMod, targetDir);
281
-
282
- console.log("[resources] Done");
283
- }
284
-
285
- /**
286
- * 复制模块内容
287
- */
288
- copyModuleContent(src, dest) {
289
- if (!fs.existsSync(dest)) {
290
- fs.mkdirSync(dest, { recursive: true });
291
- }
292
-
293
- // 复制所有文件和目录(排除 .git、node_modules 等)
294
- const entries = fs.readdirSync(src, { withFileTypes: true });
295
-
296
- for (const entry of entries) {
297
- // 跳过特殊目录
298
- if (entry.name.startsWith(".") || entry.name === "node_modules") {
299
- continue;
300
- }
301
-
302
- const srcPath = path.join(src, entry.name);
303
- const destPath = path.join(dest, entry.name);
304
-
305
- if (entry.isDirectory()) {
306
- this.copyRecursive(srcPath, destPath);
307
- } else {
308
- fs.copyFileSync(srcPath, destPath);
309
- }
310
- }
311
- }
312
-
313
- /**
314
- * 递归复制目录
315
- */
316
- copyRecursive(src, dest) {
317
- if (!fs.existsSync(dest)) {
318
- fs.mkdirSync(dest, { recursive: true });
319
- }
320
-
321
- const entries = fs.readdirSync(src, { withFileTypes: true });
322
-
323
- for (const entry of entries) {
324
- if (entry.name.startsWith(".") || entry.name === "node_modules") {
325
- continue;
326
- }
327
-
328
- const srcPath = path.join(src, entry.name);
329
- const destPath = path.join(dest, entry.name);
330
-
331
- if (entry.isDirectory()) {
332
- this.copyRecursive(srcPath, destPath);
333
- } else {
334
- fs.copyFileSync(srcPath, destPath);
335
- }
336
- }
337
- }
338
159
  }
339
160
 
340
161
  module.exports = UfooInit;
@@ -15,25 +15,10 @@ class SkillsManager {
15
15
  */
16
16
  findSkillRoots() {
17
17
  const roots = [];
18
-
19
- // 检查 SKILLS 目录
20
18
  const mainSkills = path.join(this.repoRoot, "SKILLS");
21
19
  if (fs.existsSync(mainSkills)) {
22
20
  roots.push(mainSkills);
23
21
  }
24
-
25
- // 检查 modules 中的 SKILLS
26
- const modulesDir = path.join(this.repoRoot, "modules");
27
- if (fs.existsSync(modulesDir)) {
28
- const modules = fs.readdirSync(modulesDir);
29
- for (const module of modules) {
30
- const moduleSkills = path.join(modulesDir, module, "SKILLS");
31
- if (fs.existsSync(moduleSkills)) {
32
- roots.push(moduleSkills);
33
- }
34
- }
35
- }
36
-
37
22
  return roots;
38
23
  }
39
24
 
@@ -535,7 +535,7 @@ async function runCli(argv) {
535
535
  const chalk = requireOptional("chalk") || { cyan: (s) => s, red: (s) => s };
536
536
 
537
537
  if (commander && commander.Command) {
538
- const { Command } = commander;
538
+ const { Command, Option } = commander;
539
539
  const program = new Command();
540
540
 
541
541
  program
@@ -1074,10 +1074,10 @@ async function runCli(argv) {
1074
1074
  }
1075
1075
  });
1076
1076
 
1077
- program
1077
+ const initCommand = program
1078
1078
  .command("init")
1079
- .description("Initialize modules in a project")
1080
- .option("--modules <list>", "Comma-separated modules (context,bus,resources)", "context")
1079
+ .description("Initialize ufoo workspace state in a project")
1080
+ .option("--targets <list>", "Comma-separated init targets (context,bus)")
1081
1081
  .option("--project <dir>", "Target project directory", process.cwd())
1082
1082
  .action(async (opts) => {
1083
1083
  const UfooInit = require("./features/init");
@@ -1090,6 +1090,11 @@ async function runCli(argv) {
1090
1090
  process.exitCode = 1;
1091
1091
  }
1092
1092
  });
1093
+ if (Option && typeof Option === "function") {
1094
+ initCommand.addOption(new Option("--modules <list>", "Deprecated alias for --targets").hideHelp());
1095
+ } else {
1096
+ initCommand.option("--modules <list>", "Deprecated alias for --targets");
1097
+ }
1093
1098
 
1094
1099
  const skills = program.command("skills").description("Manage skills templates");
1095
1100
  skills
@@ -1675,7 +1680,7 @@ async function runCli(argv) {
1675
1680
  program.addHelpText(
1676
1681
  "after",
1677
1682
  `\nNotes:\n - If 'ufoo' isn't in PATH, run it via ${chalk.cyan(
1678
- "./bin/ufoo"
1683
+ "./bin/ufoo.js"
1679
1684
  )} (repo) or install globally via npm.\n - For bus notifications inside Codex, prefer ${chalk.cyan(
1680
1685
  "ufoo bus alert"
1681
1686
  )} / ${chalk.cyan("ufoo bus listen")} (no IME issues).\n`
@@ -1713,7 +1718,7 @@ async function runCli(argv) {
1713
1718
  console.log(" ufoo recover [list [target] | run <target>] [--json]");
1714
1719
  console.log(" ufoo report <start|progress|done|error|list> [message] [--task <id>] [--agent <id>]");
1715
1720
  console.log(" ufoo ucode [doctor|prepare|build] [--skip-install]");
1716
- console.log(" ufoo init [--modules <list>] [--project <dir>]");
1721
+ console.log(" ufoo init [--targets <list>] [--project <dir>]");
1717
1722
  console.log(" ufoo skills list");
1718
1723
  console.log(" ufoo skills install <name|all> [--target <dir> | --codex | --agents]");
1719
1724
  console.log(" ufoo group templates [list|ls] [--json]");
@@ -2058,7 +2063,7 @@ async function runCli(argv) {
2058
2063
  };
2059
2064
 
2060
2065
  const opts = {
2061
- modules: getOpt("--modules", "context"),
2066
+ targets: getOpt("--targets", getOpt("--modules", "context")),
2062
2067
  project: getOpt("--project", process.cwd()),
2063
2068
  };
2064
2069
 
@@ -15,7 +15,7 @@
15
15
  - `ucode> ...` free-form task input routes to model-backed planner path
16
16
  - `tool/run` commands stay available as deterministic fallback
17
17
  - Dispatcher: `runToolCall({ tool, args }, { workspaceRoot })`
18
- - Queue runtime:
19
- - `ucode-core submit`
20
- - `ucode-core run-once`
21
- - `ucode-core list`
18
+ - Queue runtime internals:
19
+ - `submitTask`
20
+ - `runOnce`
21
+ - `listResults`
package/src/code/cli.js CHANGED
@@ -78,7 +78,7 @@ function parseArgs(argv = []) {
78
78
 
79
79
  function usage() {
80
80
  return [
81
- "ucode-core native runtime CLI",
81
+ "ucode native runtime internals",
82
82
  "",
83
83
  "Commands:",
84
84
  " submit --tool <read|write|edit|bash> --args-json <json> [--workspace <path>] [--task-id <id>]",
@@ -206,13 +206,11 @@ function isLikelyPiCoreCommand(command = "", args = []) {
206
206
  const cmdText = String(command || "").trim();
207
207
  const cmdBase = path.basename(cmdText).toLowerCase();
208
208
  if (cmdBase === "ucode" || cmdBase === "ucode.exe") return true;
209
- if (cmdBase === "ucode-core" || cmdBase === "ucode-core.exe") return true;
210
209
 
211
210
  const joined = [cmdText, ...(Array.isArray(args) ? args : [])]
212
211
  .map((part) => String(part || "").toLowerCase())
213
212
  .join(" ");
214
213
  if (!joined) return false;
215
- if (joined.includes("ucode-core")) return true;
216
214
  if (joined.includes("/src/code/agent.js")) return true;
217
215
  if (joined.includes("\\src\\code\\agent.js")) return true;
218
216
  return false;
@@ -287,55 +285,30 @@ function resolveCandidateCoreRoot({
287
285
  }
288
286
 
289
287
  function resolveNativeFallbackCommand({ env = process.env } = {}) {
290
- const candidates = [
291
- path.resolve(__dirname, "..", "agent.js"),
292
- path.resolve(__dirname, "..", "..", "..", "bin", "ucode-core.js"),
293
- ];
294
- for (const entry of candidates) {
295
- try {
296
- if (isReadableFile(entry)) {
297
- if (entry.endsWith("agent.js")) {
298
- return {
299
- command: process.execPath,
300
- args: [entry],
301
- root: path.resolve(__dirname, ".."),
302
- kind: "native",
303
- available: true,
304
- resolvedPath: entry,
305
- };
306
- }
307
- return {
308
- command: process.execPath,
309
- args: [entry, "agent"],
310
- root: path.resolve(__dirname, ".."),
311
- kind: "native",
312
- available: true,
313
- resolvedPath: entry,
314
- };
315
- }
316
- } catch {
317
- // ignore
288
+ void env;
289
+ const entry = path.resolve(__dirname, "..", "agent.js");
290
+ try {
291
+ if (isReadableFile(entry)) {
292
+ return {
293
+ command: process.execPath,
294
+ args: [entry],
295
+ root: path.resolve(__dirname, ".."),
296
+ kind: "native",
297
+ available: true,
298
+ resolvedPath: entry,
299
+ };
318
300
  }
319
- }
320
- const resolvedCommand = resolveExecutableFromPath("ucode-core", env);
321
- if (resolvedCommand) {
322
- return {
323
- command: "ucode-core",
324
- args: ["agent"],
325
- root: "",
326
- kind: "native",
327
- available: true,
328
- resolvedPath: resolvedCommand,
329
- };
301
+ } catch {
302
+ // ignore
330
303
  }
331
304
  return {
332
- command: "ucode-core",
333
- args: ["agent"],
334
- root: "",
305
+ command: process.execPath,
306
+ args: [entry],
307
+ root: path.resolve(__dirname, ".."),
335
308
  kind: "native",
336
309
  available: false,
337
310
  resolvedPath: "",
338
- missingReason: "src/code/agent.js not found and ucode-core is not available on PATH",
311
+ missingReason: "src/code/agent.js not found",
339
312
  };
340
313
  }
341
314
 
@@ -63,19 +63,6 @@ function defaultSkillRoots({
63
63
 
64
64
  const root = path.resolve(String(repoRoot || repoRootFromHere()));
65
65
  roots.push({ path: path.join(root, "SKILLS"), scope: "builtin", source: "ufoo" });
66
- const modulesDir = path.join(root, "modules");
67
- try {
68
- for (const entry of fs.readdirSync(modulesDir, { withFileTypes: true })) {
69
- if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
70
- roots.push({
71
- path: path.join(modulesDir, entry.name, "SKILLS"),
72
- scope: "builtin",
73
- source: `ufoo-module:${entry.name}`,
74
- });
75
- }
76
- } catch {
77
- // Modules are optional in tests and local installs.
78
- }
79
66
 
80
67
  const seen = new Set();
81
68
  return roots
@@ -83,24 +83,18 @@ class ContextDoctor {
83
83
  }
84
84
 
85
85
  /**
86
- * Lint 协议 repo(modules/context
86
+ * Lint bundled context skill.
87
87
  */
88
88
  lintProtocol() {
89
- const moduleRoot = path.join(this.projectRoot, "modules", "context");
89
+ const repoSkill = path.join(this.projectRoot, "SKILLS", "uctx", "SKILL.md");
90
90
 
91
- if (!fs.existsSync(moduleRoot)) {
92
- console.log("No protocol module found (skipping protocol lint)");
91
+ if (!fs.existsSync(repoSkill)) {
92
+ console.log("No bundled context skill found (skipping protocol lint)");
93
93
  return true;
94
94
  }
95
95
 
96
- console.log(`Linting protocol repo: ${moduleRoot}`);
97
-
98
- // Check minimal module files
99
- this.checkFile(path.join(moduleRoot, "README.md"), "README.md");
100
- this.checkFile(
101
- path.join(moduleRoot, "SKILLS", "uctx", "SKILL.md"),
102
- "SKILLS/uctx/SKILL.md"
103
- );
96
+ console.log(`Linting bundled context skill: ${repoSkill}`);
97
+ this.checkFile(repoSkill, "SKILLS/uctx/SKILL.md");
104
98
 
105
99
  return !this.failed;
106
100
  }
@@ -155,20 +149,6 @@ class ContextDoctor {
155
149
  }
156
150
  }
157
151
 
158
- // Check global modules
159
- const globalContext = path.join(
160
- process.env.HOME,
161
- ".ufoo",
162
- "modules",
163
- "context"
164
- );
165
- if (!fs.existsSync(globalContext)) {
166
- console.log("");
167
- console.log(
168
- `WARN: ${globalContext} not found (install via ufoo for best UX)`
169
- );
170
- }
171
-
172
152
  console.log("");
173
153
  if (this.failed) {
174
154
  console.log("Status: FAILED");
@@ -10,7 +10,7 @@ const WebSocket = require("ws");
10
10
  * ufoo-online (Phase 1)
11
11
  *
12
12
  * Minimal WebSocket relay implementing hello/auth + join/leave + event routing.
13
- * Intended WebSocket path: /ufoo/online (see docs/ufoo-online/PROTOCOL.md)
13
+ * Intended WebSocket path: /ufoo/online.
14
14
  */
15
15
  class OnlineServer extends EventEmitter {
16
16
  constructor(options = {}) {
@@ -1438,7 +1438,7 @@ function startDaemon({ projectRoot, provider, model, resumeMode = "auto" }) {
1438
1438
  if (!fs.existsSync(targetPaths.ufooDir)) {
1439
1439
  const repoRoot = path.join(__dirname, "..", "..", "..");
1440
1440
  const init = new (require("../../app/cli/features/init"))(repoRoot);
1441
- await init.init({ modules: "context,bus", project: root });
1441
+ await init.init({ targets: "context,bus", project: root });
1442
1442
  }
1443
1443
  if (!isRunning(root)) {
1444
1444
  cleanupStaleState(root);
@@ -400,7 +400,7 @@ async function ensureGlobalControllerDaemon(options = {}) {
400
400
  const UfooInit = require("../../app/cli/features/init");
401
401
  const init = new UfooInit(PACKAGE_ROOT);
402
402
  await suppressConsoleToStderr(() => init.init({
403
- modules: "context,bus",
403
+ targets: "context,bus",
404
404
  project: root,
405
405
  controllerMode: true,
406
406
  }));