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.
- package/README.md +6 -8
- package/README.zh-CN.md +5 -5
- package/SKILLS/ufoo/SKILL.md +2 -2
- package/SKILLS/uinit/SKILL.md +8 -11
- package/package.json +3 -8
- package/scripts/postinstall.js +1 -21
- package/src/agents/launch/launcher.js +1 -13
- package/src/app/chat/commandExecutor.js +14 -9
- package/src/app/chat/commands.js +2 -2
- package/src/app/chat/daemonCoordinator.js +4 -0
- package/src/app/chat/daemonReconnect.js +17 -7
- package/src/app/cli/features/doctor.js +11 -18
- package/src/app/cli/features/init.js +12 -191
- package/src/app/cli/features/skills.js +0 -15
- package/src/app/cli/run.js +12 -7
- package/src/code/README.md +4 -4
- package/src/code/cli.js +1 -1
- package/src/code/launcher/ucode.js +18 -45
- package/src/code/skills/loader.js +0 -13
- package/src/coordination/context/doctor.js +6 -26
- package/src/online/server.js +1 -1
- package/src/runtime/daemon/index.js +1 -1
- package/src/runtime/daemon/mcpServer.js +1 -1
- package/src/runtime/daemon/restart.js +293 -0
- package/src/runtime/daemon/run.js +31 -37
- package/src/runtime/terminal/index.js +1 -1
- package/src/ui/MIGRATION.md +8 -10
- package/src/ui/ink/ChatApp.js +12 -6
- package/bin/ucode-core.js +0 -15
- package/bin/ufoo +0 -71
- package/modules/AGENTS.template.md +0 -8
- package/modules/bus/README.md +0 -140
- package/modules/context/README.md +0 -60
- package/modules/online/README.md +0 -92
- package/modules/resources/ICONS/README.md +0 -12
- package/modules/resources/ICONS/libraries/README.md +0 -17
- package/modules/resources/ICONS/libraries/heroicons/LICENSE +0 -22
- package/modules/resources/ICONS/libraries/heroicons/README.md +0 -15
- package/modules/resources/ICONS/libraries/heroicons/arrow-right.svg +0 -4
- package/modules/resources/ICONS/libraries/heroicons/check.svg +0 -4
- package/modules/resources/ICONS/libraries/heroicons/chevron-down.svg +0 -4
- package/modules/resources/ICONS/libraries/heroicons/cog-6-tooth.svg +0 -5
- package/modules/resources/ICONS/libraries/heroicons/magnifying-glass.svg +0 -4
- package/modules/resources/ICONS/libraries/heroicons/x-mark.svg +0 -4
- package/modules/resources/ICONS/libraries/lucide/LICENSE +0 -40
- package/modules/resources/ICONS/libraries/lucide/README.md +0 -15
- package/modules/resources/ICONS/libraries/lucide/arrow-right.svg +0 -15
- package/modules/resources/ICONS/libraries/lucide/check.svg +0 -14
- package/modules/resources/ICONS/libraries/lucide/chevron-down.svg +0 -14
- package/modules/resources/ICONS/libraries/lucide/search.svg +0 -15
- package/modules/resources/ICONS/libraries/lucide/settings.svg +0 -15
- package/modules/resources/ICONS/libraries/lucide/x.svg +0 -15
- package/modules/resources/ICONS/rules.md +0 -7
- package/modules/resources/README.md +0 -9
- package/modules/resources/UI/ANTI-PATTERNS.md +0 -6
- package/modules/resources/UI/TONE.md +0 -6
- package/scripts/chat-app-smoke.js +0 -30
- package/scripts/global-chat-switch-benchmark.js +0 -406
- package/scripts/ink-demo.js +0 -23
- package/scripts/ink-smoke.js +0 -30
- package/scripts/ucode-app-smoke.js +0 -36
- /package/{modules/bus/SKILLS → SKILLS}/ubus/SKILL.md +0 -0
- /package/{modules/context/SKILLS → SKILLS}/uctx/SKILL.md +0 -0
- /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
|
|
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(`
|
|
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
|
-
|
|
37
|
-
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
|
package/src/app/cli/run.js
CHANGED
|
@@ -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
|
|
1080
|
-
.option("--
|
|
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 [--
|
|
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
|
-
|
|
2066
|
+
targets: getOpt("--targets", getOpt("--modules", "context")),
|
|
2062
2067
|
project: getOpt("--project", process.cwd()),
|
|
2063
2068
|
};
|
|
2064
2069
|
|
package/src/code/README.md
CHANGED
|
@@ -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
|
-
- `
|
|
20
|
-
- `
|
|
21
|
-
- `
|
|
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
|
|
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
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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
|
-
|
|
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:
|
|
333
|
-
args: [
|
|
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
|
|
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
|
|
86
|
+
* Lint bundled context skill.
|
|
87
87
|
*/
|
|
88
88
|
lintProtocol() {
|
|
89
|
-
const
|
|
89
|
+
const repoSkill = path.join(this.projectRoot, "SKILLS", "uctx", "SKILL.md");
|
|
90
90
|
|
|
91
|
-
if (!fs.existsSync(
|
|
92
|
-
console.log("No
|
|
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
|
|
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");
|
package/src/online/server.js
CHANGED
|
@@ -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
|
|
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({
|
|
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
|
-
|
|
403
|
+
targets: "context,bus",
|
|
404
404
|
project: root,
|
|
405
405
|
controllerMode: true,
|
|
406
406
|
}));
|