u-foo 2.4.6 → 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 (42) hide show
  1. package/README.md +5 -5
  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 +1 -2
  6. package/src/agents/launch/launcher.js +1 -13
  7. package/src/app/chat/commandExecutor.js +3 -3
  8. package/src/app/chat/commands.js +2 -2
  9. package/src/app/cli/features/doctor.js +11 -18
  10. package/src/app/cli/features/init.js +12 -191
  11. package/src/app/cli/run.js +11 -6
  12. package/src/coordination/context/doctor.js +4 -22
  13. package/src/runtime/daemon/index.js +1 -1
  14. package/src/runtime/daemon/mcpServer.js +1 -1
  15. package/src/runtime/terminal/index.js +1 -1
  16. package/src/ui/ink/ChatApp.js +1 -1
  17. package/modules/AGENTS.template.md +0 -8
  18. package/modules/bus/README.md +0 -140
  19. package/modules/context/README.md +0 -60
  20. package/modules/online/README.md +0 -92
  21. package/modules/resources/ICONS/README.md +0 -12
  22. package/modules/resources/ICONS/libraries/README.md +0 -17
  23. package/modules/resources/ICONS/libraries/heroicons/LICENSE +0 -22
  24. package/modules/resources/ICONS/libraries/heroicons/README.md +0 -15
  25. package/modules/resources/ICONS/libraries/heroicons/arrow-right.svg +0 -4
  26. package/modules/resources/ICONS/libraries/heroicons/check.svg +0 -4
  27. package/modules/resources/ICONS/libraries/heroicons/chevron-down.svg +0 -4
  28. package/modules/resources/ICONS/libraries/heroicons/cog-6-tooth.svg +0 -5
  29. package/modules/resources/ICONS/libraries/heroicons/magnifying-glass.svg +0 -4
  30. package/modules/resources/ICONS/libraries/heroicons/x-mark.svg +0 -4
  31. package/modules/resources/ICONS/libraries/lucide/LICENSE +0 -40
  32. package/modules/resources/ICONS/libraries/lucide/README.md +0 -15
  33. package/modules/resources/ICONS/libraries/lucide/arrow-right.svg +0 -15
  34. package/modules/resources/ICONS/libraries/lucide/check.svg +0 -14
  35. package/modules/resources/ICONS/libraries/lucide/chevron-down.svg +0 -14
  36. package/modules/resources/ICONS/libraries/lucide/search.svg +0 -15
  37. package/modules/resources/ICONS/libraries/lucide/settings.svg +0 -15
  38. package/modules/resources/ICONS/libraries/lucide/x.svg +0 -15
  39. package/modules/resources/ICONS/rules.md +0 -7
  40. package/modules/resources/README.md +0 -9
  41. package/modules/resources/UI/ANTI-PATTERNS.md +0 -6
  42. package/modules/resources/UI/TONE.md +0 -6
package/README.md CHANGED
@@ -69,7 +69,7 @@ Initialize a project and open the chat dashboard:
69
69
 
70
70
  ```bash
71
71
  cd your-project
72
- ufoo init --modules context,bus
72
+ ufoo init --targets context,bus
73
73
  ufoo
74
74
  ```
75
75
 
@@ -167,7 +167,7 @@ still available, but the normal ufoo workflow is to work from chat.
167
167
  These are setup or troubleshooting commands. In chat, use slash commands:
168
168
 
169
169
  ```text
170
- /init context bus resources
170
+ /init context bus
171
171
  /doctor
172
172
  /status
173
173
  /daemon status
@@ -177,11 +177,11 @@ These are setup or troubleshooting commands. In chat, use slash commands:
177
177
  ```
178
178
 
179
179
  `ufoo init` creates `.ufoo/`, ensures `AGENTS.md` and `CLAUDE.md`, initializes
180
- selected modules, and prepares shared storage. `CLAUDE.md` may be a symlink;
181
- edit project instructions in `AGENTS.md`.
180
+ selected workspace state, and prepares shared storage. `CLAUDE.md` may be a
181
+ symlink; edit project instructions in `AGENTS.md`.
182
182
 
183
183
  Before a project has been initialized, the equivalent CLI form is also useful:
184
- `ufoo init --modules context,bus`.
184
+ `ufoo init --targets context,bus`.
185
185
 
186
186
  ### Event Bus
187
187
 
package/README.zh-CN.md CHANGED
@@ -67,7 +67,7 @@ npm link
67
67
 
68
68
  ```bash
69
69
  cd your-project
70
- ufoo init --modules context,bus
70
+ ufoo init --targets context,bus
71
71
  ufoo
72
72
  ```
73
73
 
@@ -163,7 +163,7 @@ ufoo -g
163
163
  这些是初始化或排障命令。进入 chat 后优先使用 slash command:
164
164
 
165
165
  ```text
166
- /init context bus resources
166
+ /init context bus
167
167
  /doctor
168
168
  /status
169
169
  /daemon status
@@ -173,10 +173,10 @@ ufoo -g
173
173
  ```
174
174
 
175
175
  `ufoo init` 会创建 `.ufoo/`,确保 `AGENTS.md` 和 `CLAUDE.md` 存在,
176
- 初始化选中的模块,并准备共享存储。`CLAUDE.md` 可以是 symlink;项目指令
177
- 优先编辑 `AGENTS.md`。
176
+ 初始化选中的工作区状态,并准备共享存储。`CLAUDE.md` 可以是 symlink
177
+ 项目指令优先编辑 `AGENTS.md`。
178
178
 
179
- 项目尚未初始化时,也可以先在外部执行等价 CLI:`ufoo init --modules context,bus`。
179
+ 项目尚未初始化时,也可以先在外部执行等价 CLI:`ufoo init --targets context,bus`。
180
180
 
181
181
  ### 事件总线
182
182
 
@@ -13,7 +13,7 @@ ufoo is the multi-agent coordination layer. It provides four capabilities:
13
13
  1. **Context Decisions** — Sparse log of major plan-level choices shared across agents
14
14
  2. **Shared Memory** — Durable, low-noise project facts shared across agents
15
15
  3. **Event Bus** — Inter-agent messaging
16
- 4. **Initialization** — Project setup for ufoo modules
16
+ 4. **Initialization** — Project setup for ufoo workspace state
17
17
 
18
18
  ## 1. Context Decisions (uctx)
19
19
 
@@ -199,7 +199,7 @@ ufoo history prompt [limit] # Render as injectable prompt block
199
199
  Trigger: `/uinit` or `/ufoo init`
200
200
 
201
201
  ```bash
202
- ufoo init --modules context,bus --project $(pwd)
202
+ ufoo init --targets context,bus --project $(pwd)
203
203
  ```
204
204
 
205
205
  After init, auto-join bus if enabled.
@@ -1,14 +1,14 @@
1
1
  ---
2
2
  name: uinit
3
3
  description: |
4
- Initialize ufoo modules in current project.
4
+ Initialize ufoo workspace state in current project.
5
5
  Use when: (1) new project needs context/bus enabled, (2) user inputs /uinit or /ufoo init.
6
- Provides interactive module selection, defaults to all selected.
6
+ Provides interactive target selection, defaults to all selected.
7
7
  ---
8
8
 
9
9
  # uinit
10
10
 
11
- Initialize ufoo modules in current project.
11
+ Initialize ufoo workspace state in current project.
12
12
 
13
13
  ## Trigger
14
14
 
@@ -16,22 +16,20 @@ User inputs `/uinit` or `/ufoo init`
16
16
 
17
17
  ## Execution Flow
18
18
 
19
- ### 1. Ask user to select modules
19
+ ### 1. Ask user to select init targets
20
20
 
21
21
  Use AskUserQuestion tool, provide multi-select, default all selected:
22
22
 
23
23
  ```
24
- Please select modules to enable:
24
+ Please select ufoo state to enable:
25
25
 
26
26
  ☑ context - Shared context protocol (.ufoo/context/)
27
27
  ☑ bus - Agent event bus (.ufoo/bus/ + .ufoo/agent/)
28
- ☐ resources - UI/Icons resources (optional)
29
28
  ```
30
29
 
31
30
  Options:
32
31
  - `context` (recommended) - Shared context, sparse decision log for major plan-level choices
33
32
  - `bus` (recommended) - Multi-agent communication, task delegation, message passing
34
- - `resources` (optional) - UI tone guide, icon library
35
33
 
36
34
  Default selected: context, bus
37
35
 
@@ -40,10 +38,10 @@ Default selected: context, bus
40
38
  Based on user selection, execute:
41
39
 
42
40
  ```bash
43
- ufoo init --modules <selected_modules> --project $(pwd)
41
+ ufoo init --targets <selected_targets> --project $(pwd)
44
42
  ```
45
43
 
46
- ### 3. If bus module selected, auto-join bus
44
+ ### 3. If bus target selected, auto-join bus
47
45
 
48
46
  ```bash
49
47
  SUBSCRIBER="${UFOO_SUBSCRIBER_ID:-$(ufoo bus whoami 2>/dev/null || true)}"
@@ -60,7 +58,7 @@ fi
60
58
  ```
61
59
  === ufoo initialization complete ===
62
60
 
63
- Enabled modules:
61
+ Enabled ufoo state:
64
62
  ✓ core memory → .ufoo/memory/
65
63
  ✓ context → .ufoo/context/
66
64
  ✓ bus → .ufoo/bus/ + .ufoo/agent/
@@ -76,4 +74,3 @@ Next steps:
76
74
 
77
75
  - If .ufoo/memory, .ufoo/context, .ufoo/bus, or .ufoo/agent already exists, skip creation
78
76
  - After initialization, reuse existing subscriber ID first, join only as fallback (if bus enabled)
79
- - AGENTS.md will have protocol description block injected
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u-foo",
3
- "version": "2.4.6",
3
+ "version": "2.4.7",
4
4
  "description": "Multi-Agent Workspace Protocol. Just add u. claude → uclaude, codex → ucodex.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://ufoo.dev",
@@ -29,7 +29,6 @@
29
29
  "online/",
30
30
  "scripts/",
31
31
  "SKILLS/",
32
- "modules/",
33
32
  "LICENSE",
34
33
  "README.md"
35
34
  ],
@@ -323,23 +323,11 @@ class AgentLauncher {
323
323
 
324
324
  if (!fs.existsSync(busDir)) {
325
325
  // 调用 ufoo init
326
- spawnSync("ufoo", ["init", "--modules", "context,bus"], {
326
+ spawnSync("ufoo", ["init", "--targets", "context,bus"], {
327
327
  cwd: this.cwd,
328
328
  stdio: "ignore",
329
329
  });
330
330
  }
331
-
332
- // 检查 AGENTS.md 是否有 ufoo template
333
- const agentsFile = path.join(this.cwd, "AGENTS.md");
334
- if (fs.existsSync(agentsFile)) {
335
- const content = fs.readFileSync(agentsFile, "utf8");
336
- if (!content.includes("<!-- ufoo -->")) {
337
- spawnSync("ufoo", ["init", "--modules", "context,bus"], {
338
- cwd: this.cwd,
339
- stdio: "ignore",
340
- });
341
- }
342
- }
343
331
  }
344
332
 
345
333
  /**
@@ -303,7 +303,7 @@ function createCommandExecutor(options = {}) {
303
303
  }
304
304
 
305
305
  async function handleInitCommand(args = []) {
306
- logMessage("system", "{white-fg}⚙{/white-fg} Initializing ufoo modules...");
306
+ logMessage("system", "{white-fg}⚙{/white-fg} Initializing ufoo workspace...");
307
307
 
308
308
  await withCapturedConsole(
309
309
  {
@@ -319,8 +319,8 @@ function createCommandExecutor(options = {}) {
319
319
  try {
320
320
  const repoRoot = path.join(__dirname, "..", "..");
321
321
  const init = createInit(repoRoot);
322
- const modules = args.length > 0 ? args.join(",") : "context,bus";
323
- await init.init({ modules, project: projectRoot });
322
+ const targets = args.length > 0 ? args.join(",") : "context,bus";
323
+ await init.init({ targets, project: projectRoot });
324
324
 
325
325
  logMessage("system", "{white-fg}✓{/white-fg} Initialization complete");
326
326
  renderScreen();
@@ -47,7 +47,7 @@ const COMMAND_TREE = {
47
47
  templates: { desc: "List available templates" },
48
48
  },
49
49
  },
50
- "/init": { desc: "Initialize modules" },
50
+ "/init": { desc: "Initialize workspace" },
51
51
  "/multi": { desc: "Toggle multi-window agent view" },
52
52
  "/open": { desc: "Open project path in global mode" },
53
53
  "/launch": {
@@ -305,7 +305,7 @@ function describeCommandForChat(text) {
305
305
  if (command === "multi") return "Toggling multi-pane view";
306
306
  if (command === "open") return `Opening project ${args[0] || ""}`.trim();
307
307
  if (command === "resume") return args[0] === "list" ? "Listing recoverable agents" : `Resuming ${args[0] || "agents"}`;
308
- if (command === "init") return "Initializing ufoo modules";
308
+ if (command === "init") return "Initializing ufoo workspace";
309
309
 
310
310
  return `Running /${command}`;
311
311
  }
@@ -14,29 +14,22 @@ class RepoDoctor {
14
14
  }
15
15
 
16
16
  run() {
17
- const contextMod = path.join(this.repoRoot, "modules", "context");
17
+ const skillsDir = path.join(this.repoRoot, "SKILLS");
18
+ const contextSkill = path.join(skillsDir, "uctx", "SKILL.md");
19
+ const busSkill = path.join(skillsDir, "ubus", "SKILL.md");
18
20
 
19
- const contextExists = fs.existsSync(contextMod);
20
- if (!contextExists) {
21
- this.fail(`missing ${contextMod}`);
22
- }
21
+ if (!fs.existsSync(contextSkill)) this.fail(`missing ${contextSkill}`);
22
+ if (!fs.existsSync(busSkill)) this.fail(`missing ${busSkill}`);
23
23
 
24
- if (contextExists) {
25
- const contextDoctor = new ContextDoctor(this.repoRoot);
26
- const ok = contextDoctor.lintProtocol();
27
- if (!ok) this.failed = true;
28
- }
24
+ const contextDoctor = new ContextDoctor(this.repoRoot);
25
+ const ok = contextDoctor.lintProtocol();
26
+ if (!ok) this.failed = true;
29
27
 
30
28
  console.log("=== ufoo doctor ===");
31
29
  console.log(`Monorepo: ${this.repoRoot}`);
32
- console.log("Modules:");
33
- if (contextExists) {
34
- console.log(`- context: ${contextMod}`);
35
- }
36
- const resources = path.join(this.repoRoot, "modules", "resources");
37
- if (fs.existsSync(resources)) {
38
- console.log(`- resources: ${resources}`);
39
- }
30
+ console.log("Skills:");
31
+ if (fs.existsSync(contextSkill)) console.log(`- uctx: ${contextSkill}`);
32
+ if (fs.existsSync(busSkill)) console.log(`- ubus: ${busSkill}`);
40
33
 
41
34
  if (this.failed) {
42
35
  console.log("Status: FAILED");
@@ -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;
@@ -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
@@ -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
 
@@ -83,21 +83,17 @@ 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");
90
89
  const repoSkill = path.join(this.projectRoot, "SKILLS", "uctx", "SKILL.md");
91
90
 
92
- if (!fs.existsSync(moduleRoot)) {
93
- 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)");
94
93
  return true;
95
94
  }
96
95
 
97
- console.log(`Linting protocol repo: ${moduleRoot}`);
98
-
99
- // Check minimal module files
100
- this.checkFile(path.join(moduleRoot, "README.md"), "README.md");
96
+ console.log(`Linting bundled context skill: ${repoSkill}`);
101
97
  this.checkFile(repoSkill, "SKILLS/uctx/SKILL.md");
102
98
 
103
99
  return !this.failed;
@@ -153,20 +149,6 @@ class ContextDoctor {
153
149
  }
154
150
  }
155
151
 
156
- // Check global modules
157
- const globalContext = path.join(
158
- process.env.HOME,
159
- ".ufoo",
160
- "modules",
161
- "context"
162
- );
163
- if (!fs.existsSync(globalContext)) {
164
- console.log("");
165
- console.log(
166
- `WARN: ${globalContext} not found (install via ufoo for best UX)`
167
- );
168
- }
169
-
170
152
  console.log("");
171
153
  if (this.failed) {
172
154
  console.log("Status: FAILED");
@@ -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
  }));
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Terminal detection and feature modules.
2
+ * Terminal detection and feature helpers.
3
3
  */
4
4
 
5
5
  const detect = require("./detect");
@@ -3549,7 +3549,7 @@ async function runChatInk(projectRoot, options = {}) {
3549
3549
  const repoRoot = path.join(__dirname, "..", "..", "..");
3550
3550
  const init = new env.UfooInit(repoRoot);
3551
3551
  await init.init({
3552
- modules: "context,bus",
3552
+ targets: "context,bus",
3553
3553
  project: projectRoot,
3554
3554
  controllerMode: env.globalMode,
3555
3555
  });
@@ -1,8 +0,0 @@
1
- <!-- ufoo -->
2
- ## ufoo Agent Protocol
3
-
4
- > **Default: do not write a decision.** Record one only for important, plan-level knowledge that should constrain future work: architectural choices, trade-off analysis, cross-agent coordination, or precedent-setting integration contracts. NOT for routine findings, simple fixes, or because the user asked for a plan/evaluation/recommendation. Durable project facts belong in shared memory, not decisions. → `ufoo ctx decisions new "Title"` BEFORE acting only when that high bar is met.
5
- > **Read shared memory before writing it.** Durable facts live in `.ufoo/memory/`; use `ufoo memory list/show`, `recall`, `search_memory`, or redacted `search_history` evidence before `remember` / `edit_memory`.
6
- > **Auto-execute bus messages.** On `ubus`: execute tasks immediately, then `ufoo bus ack`. Never ask the user.
7
- > **Full protocol**: `/ufoo` skill (auto-loaded on session start). Docs: `.ufoo/docs/`
8
- <!-- /ufoo -->
@@ -1,140 +0,0 @@
1
- # bus
2
-
3
- File-system based Agent event bus for async communication between multiple AI Coding Agents.
4
-
5
- ## Overview
6
-
7
- bus solves communication problems in multi-agent collaboration:
8
-
9
- - Multiple Claude Code instances collaborating on the same project
10
- - Communication between different AI tools (Claude Code, Cursor, Copilot)
11
- - Task delegation and response
12
- - Broadcast messages
13
-
14
- ## Installation
15
-
16
- Initialize via ufoo:
17
-
18
- ```bash
19
- ufoo init --modules context,bus
20
- ```
21
-
22
- ## Directory Structure
23
-
24
- ```
25
- .ufoo/
26
- ├── agent/
27
- │ └── all-agents.json # Agent metadata + agent status
28
- ├── daemon/
29
- │ ├── daemon.pid
30
- │ ├── daemon.log
31
- │ └── counts/
32
- └── bus/
33
- ├── events/ # Event stream (JSONL, sharded by date)
34
- ├── offsets/ # Each Agent's consumption progress
35
- └── queues/ # Targeted event queues
36
- ```
37
-
38
- ## Usage
39
-
40
- ### Join Bus
41
-
42
- ```bash
43
- SUBSCRIBER="${UFOO_SUBSCRIBER_ID:-$(ufoo bus whoami 2>/dev/null || true)}"
44
- [ -n "$SUBSCRIBER" ] || SUBSCRIBER=$(ufoo bus join | tail -n 1)
45
- # Output: claude-code:a1b2c3 (or codex:def456)
46
- ```
47
-
48
- ### Check Pending Messages
49
-
50
- ```bash
51
- ufoo bus check "$SUBSCRIBER"
52
- ```
53
-
54
- ### Send Messages
55
-
56
- ```bash
57
- # Send to specific instance
58
- ufoo bus send "claude-code:abc123" "Please help me review"
59
-
60
- # Send to all instances of same type
61
- ufoo bus send "claude-code" "Everyone please review"
62
-
63
- # Broadcast to all
64
- ufoo bus broadcast "I completed feature-x"
65
- ```
66
-
67
- ### View Status
68
-
69
- ```bash
70
- ufoo bus status
71
- ```
72
-
73
- ## Notifications/Alerts (no key injection, recommended)
74
-
75
- If you want to receive "new message alerts" while running Codex/Claude in another terminal, use **agent-side alert/listen** (avoids IME/accessibility permission/window positioning fragmentation issues):
76
-
77
- ```bash
78
- SUBSCRIBER="${UFOO_SUBSCRIBER_ID:-$(ufoo bus whoami 2>/dev/null || true)}"
79
- [ -n "$SUBSCRIBER" ] || SUBSCRIBER=$(ufoo bus join | tail -n 1)
80
-
81
- # Background alert: title badge + bell + optional macOS notification center
82
- ufoo bus alert "$SUBSCRIBER" 1 --notify --daemon
83
-
84
- # Or: foreground continuous print of new messages (suitable for a side terminal)
85
- ufoo bus listen "$SUBSCRIBER" --from-beginning
86
- ```
87
-
88
- ## Unattended Auto-Execute (recommended)
89
-
90
- If you need **Claude A to notify Claude B / Codex C and have the target auto-execute** (e.g., auto-trigger `/ubus`), use the bus daemon:
91
-
92
- 1) Resolve subscriber in each terminal session first (records `tty`, also records `TMUX_PANE` if in tmux). Join only as fallback:
93
-
94
- ```bash
95
- SUBSCRIBER="${UFOO_SUBSCRIBER_ID:-$(ufoo bus whoami 2>/dev/null || true)}"
96
- [ -n "$SUBSCRIBER" ] || SUBSCRIBER=$(ufoo bus join | tail -n 1)
97
- ```
98
-
99
- 2) Start the bus daemon in the project (runs as background daemon):
100
-
101
- ```bash
102
- ufoo bus daemon --interval 1 --daemon
103
- ```
104
-
105
- 3) After sending a message, the daemon injects `/ubus` into the target session and presses Enter:
106
- - tmux: `send-keys`
107
- - Terminal.app (pure Automation): `do script` (no Accessibility needed, but requires Automation authorization; compatibility depends on whether target program accepts input)
108
- - Terminal.app (Accessibility): System Events (needs Accessibility), injection sequence is Escape + paste + Return (avoids IME issues)
109
-
110
- Tips:
111
- - Terminal.app backend depends on `tty` in `.ufoo/agent/all-agents.json`. Execute `join` in the target terminal session (ensure `tty` is not `not a tty`).
112
- - Pure Automation backend needs one-time authorization: System Preferences → Privacy & Security → Automation (allow script to control Terminal).
113
- - Accessibility backend needs one-time authorization: System Preferences → Privacy & Security → Accessibility (for Terminal / script host).
114
-
115
- Stop/view status:
116
-
117
- ```bash
118
- ufoo bus daemon --status
119
- ufoo bus daemon --stop
120
- ```
121
-
122
- ## Subscriber ID Format
123
-
124
- ```
125
- {agent_type}:{instance_id}
126
-
127
- Examples:
128
- claude-code:a1b2c3
129
- cursor-ai:main
130
- copilot:session1
131
- ```
132
-
133
- ## Relationship with context
134
-
135
- | Module | Problem Solved |
136
- |--------|----------------|
137
- | context | Shared context, sparse decision log for major plan-level choices |
138
- | bus | Real-time communication, task delegation, message passing |
139
-
140
- Both are independent peer modules that can be used separately or together.
@@ -1,60 +0,0 @@
1
- # context
2
-
3
- Decision-only context module for ufoo.
4
-
5
- Purpose:
6
- - Persist decisions in project workspaces
7
- - Keep decision format canonical in `uctx` skill
8
-
9
- Bus handles communication; context handles durable decision truth.
10
-
11
- ## Quick Start
12
-
13
- ```bash
14
- # Install `ufoo` globally (once), then use it to install modules and init projects.
15
- ```
16
-
17
- This repository is the `context` module. The recommended entrypoint is `ufoo`.
18
-
19
- ## Architecture
20
-
21
- ### Global: `~/.ufoo/` (read-only for agents, managed by humans)
22
-
23
- Global modules live under `~/.ufoo/modules/`.
24
-
25
- ### Project: `<project>/.ufoo/context/` (writable)
26
-
27
- ```
28
- .ufoo/context/
29
- ├── decisions/ # Append-only decision log (decision-only mode)
30
- └── decisions.jsonl # Decision index (ts/type/file/author)
31
- ```
32
-
33
- Should be in the project workspace and writable by agents.
34
- Versioning is optional but recommended for auditability.
35
-
36
- ## Module Structure
37
-
38
- ```
39
- context/ # This repo
40
- ├── README.md # This file
41
- ├── ../../SKILLS/uctx/SKILL.md # Canonical decision format + workflow
42
- └── .ufoo/context/ # Local project context for this repo (ignored; not part of protocol distribution)
43
- ```
44
-
45
- ## For AI Agents
46
-
47
- 1. Read installed module from `~/.ufoo/modules/context/`
48
- 2. Read/write decisions in `<project>/.ufoo/context/decisions/`
49
- 3. **Never write to global** — only to project
50
- 4. Follow the decision format in the package-level `SKILLS/uctx/SKILL.md`
51
-
52
- ## Validate
53
-
54
- ```bash
55
- # protocol repo
56
- ufoo ctx lint
57
-
58
- # project-local context (in a real project repo)
59
- ufoo ctx lint --project <path-to-project-context>
60
- ```
@@ -1,92 +0,0 @@
1
- # online
2
-
3
- WebSocket relay module for cross-machine agent collaboration. Extends the local ufoo bus to work over the network.
4
-
5
- ## Overview
6
-
7
- online enables agents on different machines to collaborate:
8
-
9
- - Public channel chat (broadcast to all connected agents)
10
- - Private room collaboration (bus/decisions/wake sync)
11
- - Token-based authentication
12
- - Auto-reconnect with exponential backoff
13
-
14
- ## Quick Start
15
-
16
- ### 1. Start a relay server
17
-
18
- ```bash
19
- ufoo online server --port 8787
20
- ```
21
-
22
- ### 2. Connect an agent
23
-
24
- ```bash
25
- # Join a public channel
26
- ufoo online connect --nickname my-agent --join lobby
27
-
28
- # Join a private room
29
- ufoo online connect --nickname my-agent --room room_001 --room-password secret
30
- ```
31
-
32
- ### 3. Send messages
33
-
34
- ```bash
35
- # To a channel
36
- ufoo online send --nickname my-agent --channel lobby --text "hello everyone"
37
-
38
- # To a room
39
- ufoo online send --nickname my-agent --room room_001 --text "hello team"
40
- ```
41
-
42
- ### 4. Check inbox
43
-
44
- ```bash
45
- ufoo online inbox my-agent # All messages
46
- ufoo online inbox my-agent --unread # Unread only
47
- ufoo online inbox my-agent --clear # Clear inbox
48
- ```
49
-
50
- ## Private Room Sync
51
-
52
- In private room mode, agents automatically sync:
53
-
54
- - **Bus messages** — local bus ↔ online relay, bidirectional
55
- - **Decisions** — new `.md` files synced across team
56
- - **Wake events** — remote agent can wake local agent via bus
57
-
58
- ## HTTP APIs (for web preview)
59
-
60
- Auth-required management APIs:
61
-
62
- - `GET/POST /ufoo/online/channels`
63
- - `GET/POST /ufoo/online/rooms`
64
-
65
- Public read-only preview APIs (no bearer token required):
66
-
67
- - `GET /ufoo/online/public/channels`
68
- - `GET /ufoo/online/public/rooms?type=private`
69
- - `GET /ufoo/online/public/channels/:channel/messages?limit=120`
70
-
71
- Notes:
72
-
73
- - Channel history is in-memory (rolling buffer) on relay server.
74
- - Private room public API only exposes metadata (`room_id`, `name`, `created_by`, `password_required`).
75
-
76
- ## Storage
77
-
78
- ```
79
- ~/.ufoo/online/
80
- ├── tokens.json # Auth tokens
81
- ├── inbox/<nickname>.jsonl # Incoming messages
82
- └── outbox/<nickname>.jsonl # Queued outgoing messages
83
- ```
84
-
85
- ## Relationship with bus
86
-
87
- | Module | Scope |
88
- |--------|-------|
89
- | bus | Local file-system based messaging within a single machine |
90
- | online | Network relay extending bus across machines via WebSocket |
91
-
92
- online builds on top of bus — local agents still communicate via the file-system bus, while online bridges messages to remote agents.
@@ -1,12 +0,0 @@
1
- # Icon Context
2
-
3
- Icons here define visual grammar, not shippable assets.
4
-
5
- They are used as:
6
- - Reference bases
7
- - Modification sources
8
- - Style constraints
9
-
10
- Do not copy blindly into projects.
11
-
12
- `libraries/` contains minimal subsets of third-party icon libraries (with licenses) as reference material.
@@ -1,17 +0,0 @@
1
- # Icon Libraries (Minimal Subsets)
2
-
3
- This directory vendors **small, representative subsets** of third-party icon libraries.
4
-
5
- Purpose:
6
- - Provide strong, unambiguous signal that icons are **canonical protocol context**
7
- - Serve as reference bases and modification sources
8
-
9
- Non-goals:
10
- - Shipping assets for products
11
- - Full icon sets
12
-
13
- Each library subfolder contains:
14
- - A minimal set of SVGs
15
- - The upstream license text
16
- - A short README with source info
17
-
@@ -1,22 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) Tailwind Labs, Inc.
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
22
-
@@ -1,15 +0,0 @@
1
- # Heroicons (Minimal Subset)
2
-
3
- Source:
4
- - Repository: https://github.com/tailwindlabs/heroicons
5
- - Path: `optimized/24/outline/`
6
- - License: MIT (see `LICENSE`)
7
- - Fetched: 2026-01-27
8
-
9
- Included icons:
10
- - `arrow-right.svg`
11
- - `chevron-down.svg`
12
- - `magnifying-glass.svg`
13
- - `cog-6-tooth.svg`
14
- - `check.svg`
15
- - `x-mark.svg`
@@ -1,4 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
2
- <path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3"/>
3
- </svg>
4
-
@@ -1,4 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
2
- <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"/>
3
- </svg>
4
-
@@ -1,4 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
2
- <path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5"/>
3
- </svg>
4
-
@@ -1,5 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
2
- <path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z"/>
3
- <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
4
- </svg>
5
-
@@ -1,4 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
2
- <path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"/>
3
- </svg>
4
-
@@ -1,4 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
2
- <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/>
3
- </svg>
4
-
@@ -1,40 +0,0 @@
1
- ISC License
2
-
3
- Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2026 as part of Feather (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2026.
4
-
5
- Permission to use, copy, modify, and/or distribute this software for any
6
- purpose with or without fee is hereby granted, provided that the above
7
- copyright notice and this permission notice appear in all copies.
8
-
9
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
-
17
- ---
18
-
19
- The MIT License (MIT) (for portions derived from Feather)
20
-
21
- Copyright (c) 2013-2026 Cole Bemis
22
-
23
- Permission is hereby granted, free of charge, to any person obtaining a copy
24
- of this software and associated documentation files (the "Software"), to deal
25
- in the Software without restriction, including without limitation the rights
26
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27
- copies of the Software, and to permit persons to whom the Software is
28
- furnished to do so, subject to the following conditions:
29
-
30
- The above copyright notice and this permission notice shall be included in all
31
- copies or substantial portions of the Software.
32
-
33
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39
- SOFTWARE.
40
-
@@ -1,15 +0,0 @@
1
- # Lucide (Minimal Subset)
2
-
3
- Source:
4
- - Repository: https://github.com/lucide-icons/lucide
5
- - Path: `icons/`
6
- - License: ISC (see `LICENSE`)
7
- - Fetched: 2026-01-27
8
-
9
- Included icons:
10
- - `arrow-right.svg`
11
- - `chevron-down.svg`
12
- - `search.svg`
13
- - `settings.svg`
14
- - `check.svg`
15
- - `x.svg`
@@ -1,15 +0,0 @@
1
- <svg
2
- xmlns="http://www.w3.org/2000/svg"
3
- width="24"
4
- height="24"
5
- viewBox="0 0 24 24"
6
- fill="none"
7
- stroke="currentColor"
8
- stroke-width="2"
9
- stroke-linecap="round"
10
- stroke-linejoin="round"
11
- >
12
- <path d="M5 12h14" />
13
- <path d="m12 5 7 7-7 7" />
14
- </svg>
15
-
@@ -1,14 +0,0 @@
1
- <svg
2
- xmlns="http://www.w3.org/2000/svg"
3
- width="24"
4
- height="24"
5
- viewBox="0 0 24 24"
6
- fill="none"
7
- stroke="currentColor"
8
- stroke-width="2"
9
- stroke-linecap="round"
10
- stroke-linejoin="round"
11
- >
12
- <path d="M20 6 9 17l-5-5" />
13
- </svg>
14
-
@@ -1,14 +0,0 @@
1
- <svg
2
- xmlns="http://www.w3.org/2000/svg"
3
- width="24"
4
- height="24"
5
- viewBox="0 0 24 24"
6
- fill="none"
7
- stroke="currentColor"
8
- stroke-width="2"
9
- stroke-linecap="round"
10
- stroke-linejoin="round"
11
- >
12
- <path d="m6 9 6 6 6-6" />
13
- </svg>
14
-
@@ -1,15 +0,0 @@
1
- <svg
2
- xmlns="http://www.w3.org/2000/svg"
3
- width="24"
4
- height="24"
5
- viewBox="0 0 24 24"
6
- fill="none"
7
- stroke="currentColor"
8
- stroke-width="2"
9
- stroke-linecap="round"
10
- stroke-linejoin="round"
11
- >
12
- <path d="m21 21-4.34-4.34" />
13
- <circle cx="11" cy="11" r="8" />
14
- </svg>
15
-
@@ -1,15 +0,0 @@
1
- <svg
2
- xmlns="http://www.w3.org/2000/svg"
3
- width="24"
4
- height="24"
5
- viewBox="0 0 24 24"
6
- fill="none"
7
- stroke="currentColor"
8
- stroke-width="2"
9
- stroke-linecap="round"
10
- stroke-linejoin="round"
11
- >
12
- <path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915" />
13
- <circle cx="12" cy="12" r="3" />
14
- </svg>
15
-
@@ -1,15 +0,0 @@
1
- <svg
2
- xmlns="http://www.w3.org/2000/svg"
3
- width="24"
4
- height="24"
5
- viewBox="0 0 24 24"
6
- fill="none"
7
- stroke="currentColor"
8
- stroke-width="2"
9
- stroke-linecap="round"
10
- stroke-linejoin="round"
11
- >
12
- <path d="M18 6 6 18" />
13
- <path d="m6 6 12 12" />
14
- </svg>
15
-
@@ -1,7 +0,0 @@
1
- # Icon Rules
2
-
3
- - ViewBox: 0 0 24 24
4
- - Stroke-based icons preferred
5
- - No gradients or shadows
6
- - Avoid perfect symmetry
7
- - Optical balance > geometric balance
@@ -1,9 +0,0 @@
1
- # resources
2
-
3
- Optional resources for AI-assisted coding workflows.
4
-
5
- This repository intentionally contains non-core materials such as:
6
- - `UI/` tone + anti-pattern references
7
- - `ICONS/` reference icon subsets (with licenses)
8
-
9
- It is designed to be installed and managed by `ufoo` under `~/.ufoo/modules/resources`.
@@ -1,6 +0,0 @@
1
- # UI Anti-Patterns
2
-
3
- - Over-rounded corners
4
- - Decorative gradients
5
- - Unnecessary animations
6
- - Visual noise
@@ -1,6 +0,0 @@
1
- # UI Tone
2
-
3
- - Neutral
4
- - Restrained
5
- - Utility-focused
6
- - Avoid friendliness or decoration