u-foo 1.7.4 → 1.8.0

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 (45) hide show
  1. package/README.md +9 -1
  2. package/README.zh-CN.md +9 -1
  3. package/bin/ufoo.js +4 -2
  4. package/package.json +1 -1
  5. package/src/agent/cliRunner.js +3 -2
  6. package/src/agent/ucodeBootstrap.js +5 -3
  7. package/src/agent/ufooAgent.js +185 -6
  8. package/src/assistant/constants.js +1 -1
  9. package/src/assistant/engine.js +1 -6
  10. package/src/chat/commandExecutor.js +116 -19
  11. package/src/chat/commands.js +8 -1
  12. package/src/chat/completionController.js +40 -0
  13. package/src/chat/cronScheduler.js +37 -6
  14. package/src/chat/daemonMessageRouter.js +23 -3
  15. package/src/chat/dashboardKeyController.js +48 -59
  16. package/src/chat/dashboardView.js +31 -39
  17. package/src/chat/index.js +154 -77
  18. package/src/chat/inputListenerController.js +14 -0
  19. package/src/chat/inputSubmitHandler.js +9 -5
  20. package/src/chat/settingsController.js +0 -28
  21. package/src/chat/transientAgentState.js +64 -0
  22. package/src/cli/groupCoreCommands.js +21 -12
  23. package/src/cli.js +23 -1
  24. package/src/daemon/cronOps.js +48 -11
  25. package/src/daemon/groupOrchestrator.js +581 -97
  26. package/src/daemon/index.js +420 -5
  27. package/src/daemon/ops.js +25 -7
  28. package/src/daemon/promptLoop.js +16 -0
  29. package/src/daemon/promptRequest.js +126 -2
  30. package/src/daemon/reporting.js +18 -0
  31. package/src/daemon/soloBootstrap.js +435 -0
  32. package/src/daemon/status.js +7 -1
  33. package/src/globalMode.js +33 -0
  34. package/src/group/bootstrap.js +157 -0
  35. package/src/group/promptProfiles.js +646 -0
  36. package/src/group/templateValidation.js +99 -0
  37. package/src/group/validateTemplate.js +36 -5
  38. package/src/init/index.js +13 -7
  39. package/src/report/store.js +6 -0
  40. package/src/shared/eventContract.js +1 -0
  41. package/templates/groups/{dev-basic.json → build-lane.json} +38 -34
  42. package/templates/groups/product-discovery.json +79 -0
  43. package/templates/groups/ui-polish.json +87 -0
  44. package/templates/groups/verify-ship.json +79 -0
  45. package/templates/groups/research-quick.json +0 -49
@@ -0,0 +1,33 @@
1
+ const os = require("os");
2
+ const path = require("path");
3
+ const { canonicalProjectRoot, trimTrailingSlashes } = require("./projects/projectId");
4
+
5
+ function normalizeProjectRoot(projectRoot) {
6
+ const input = String(projectRoot || "").trim();
7
+ if (!input) return "";
8
+ try {
9
+ return canonicalProjectRoot(input);
10
+ } catch {
11
+ return trimTrailingSlashes(path.resolve(input));
12
+ }
13
+ }
14
+
15
+ function resolveGlobalControllerProjectRoot() {
16
+ return trimTrailingSlashes(path.resolve(os.homedir()));
17
+ }
18
+
19
+ function resolveGlobalControllerUfooDir() {
20
+ return path.join(resolveGlobalControllerProjectRoot(), ".ufoo");
21
+ }
22
+
23
+ function isGlobalControllerProjectRoot(projectRoot) {
24
+ const normalized = normalizeProjectRoot(projectRoot);
25
+ return Boolean(normalized) && normalized === resolveGlobalControllerProjectRoot();
26
+ }
27
+
28
+ module.exports = {
29
+ normalizeProjectRoot,
30
+ resolveGlobalControllerProjectRoot,
31
+ resolveGlobalControllerUfooDir,
32
+ isGlobalControllerProjectRoot,
33
+ };
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+
3
+ const crypto = require("crypto");
4
+
5
+ const SHARED_GROUP_PREFIX = [
6
+ "You are part of a ufoo multi-agent group.",
7
+ "",
8
+ "Shared rules:",
9
+ "- Stay within your role.",
10
+ "- Prefer concise handoffs over long essays.",
11
+ "- Surface uncertainty explicitly.",
12
+ "- If another agent owns the next step, hand off instead of doing their job for them.",
13
+ "- When reporting, separate facts, inferences, and recommendations.",
14
+ "- Preserve continuity with the group's current task rather than restarting analysis from scratch.",
15
+ "",
16
+ "Coordination protocol:",
17
+ "- Use direct handoff for worker-to-worker delivery.",
18
+ "- Use private `ufoo report` updates for ufoo-agent control-plane reporting.",
19
+ "- Do not ask ufoo-agent to forward a handoff that you already delivered directly unless you explicitly need controller dispatch help.",
20
+ ].join("\n");
21
+
22
+ const SOLO_AGENT_PREFIX = [
23
+ "You are operating as a role-specialized ufoo agent.",
24
+ "",
25
+ "Shared rules:",
26
+ "- Stay within your assigned role.",
27
+ "- Prefer direct, concrete output over generic commentary.",
28
+ "- Surface uncertainty explicitly.",
29
+ "- Preserve continuity with the current task instead of restarting from scratch.",
30
+ "- Use ufoo-agent for control-plane coordination, not as a substitute for doing your role.",
31
+ ].join("\n");
32
+
33
+ function asTrimmedString(value) {
34
+ if (typeof value !== "string") return "";
35
+ return value.trim();
36
+ }
37
+
38
+ function stableHash(value) {
39
+ return crypto.createHash("sha256").update(String(value || ""), "utf8").digest("hex");
40
+ }
41
+
42
+ function buildGroupPromptMetadata({
43
+ groupId = "",
44
+ templateAlias = "",
45
+ templateName = "",
46
+ rosterVersion = "",
47
+ member = {},
48
+ groupMembers = [],
49
+ upstream = [],
50
+ downstream = [],
51
+ } = {}) {
52
+ return {
53
+ group_id: asTrimmedString(groupId),
54
+ group_name: asTrimmedString(templateName) || asTrimmedString(templateAlias),
55
+ template_alias: asTrimmedString(templateAlias),
56
+ roster_version: asTrimmedString(rosterVersion),
57
+ controller_id: "ufoo-agent",
58
+ self_nickname: asTrimmedString(member.nickname),
59
+ self_role: asTrimmedString(member.role),
60
+ prompt_profile: asTrimmedString(member.prompt_profile),
61
+ resolved_profile: asTrimmedString(member.resolved_profile),
62
+ depends_on: Array.isArray(member.depends_on) ? member.depends_on.slice() : [],
63
+ accept_from: Array.isArray(member.accept_from) ? member.accept_from.slice() : [],
64
+ report_to: Array.isArray(member.report_to) ? member.report_to.slice() : [],
65
+ member_count: Array.isArray(groupMembers) ? groupMembers.length : 0,
66
+ group_members: Array.isArray(groupMembers) ? groupMembers.slice() : [],
67
+ upstream: Array.isArray(upstream) ? upstream.slice() : [],
68
+ downstream: Array.isArray(downstream) ? downstream.slice() : [],
69
+ };
70
+ }
71
+
72
+ function buildRuntimeMetadataBlock(metadata = {}) {
73
+ return `Runtime metadata:\n${JSON.stringify(metadata, null, 2)}`;
74
+ }
75
+
76
+ function buildSoloPromptMetadata({
77
+ nickname = "",
78
+ agentType = "",
79
+ requestedProfile = "",
80
+ resolvedProfile = "",
81
+ displayName = "",
82
+ shortName = "",
83
+ summary = "",
84
+ source = "",
85
+ } = {}) {
86
+ return {
87
+ controller_id: "ufoo-agent",
88
+ self_nickname: asTrimmedString(nickname),
89
+ self_agent_type: asTrimmedString(agentType),
90
+ prompt_profile: asTrimmedString(requestedProfile),
91
+ resolved_profile: asTrimmedString(resolvedProfile),
92
+ display_name: asTrimmedString(displayName),
93
+ short_name: asTrimmedString(shortName),
94
+ profile_summary: asTrimmedString(summary),
95
+ profile_source: asTrimmedString(source),
96
+ };
97
+ }
98
+
99
+ function composeGroupBootstrapPrompt({
100
+ sharedPrefix = SHARED_GROUP_PREFIX,
101
+ profilePrompt = "",
102
+ metadata = {},
103
+ } = {}) {
104
+ const segments = [];
105
+ if (asTrimmedString(sharedPrefix)) segments.push(asTrimmedString(sharedPrefix));
106
+ if (asTrimmedString(profilePrompt)) segments.push(asTrimmedString(profilePrompt));
107
+ segments.push(buildRuntimeMetadataBlock(metadata));
108
+ return `${segments.join("\n\n")}\n`;
109
+ }
110
+
111
+ function composeSoloBootstrapPrompt({
112
+ sharedPrefix = SOLO_AGENT_PREFIX,
113
+ profilePrompt = "",
114
+ metadata = {},
115
+ } = {}) {
116
+ const segments = [];
117
+ if (asTrimmedString(sharedPrefix)) segments.push(asTrimmedString(sharedPrefix));
118
+ if (asTrimmedString(profilePrompt)) segments.push(asTrimmedString(profilePrompt));
119
+ segments.push(buildRuntimeMetadataBlock(metadata));
120
+ return `${segments.join("\n\n")}\n`;
121
+ }
122
+
123
+ function computeRosterVersion(groupMembers = []) {
124
+ return stableHash(JSON.stringify(groupMembers || [])).slice(0, 16);
125
+ }
126
+
127
+ function computeBootstrapFingerprint({
128
+ groupId = "",
129
+ nickname = "",
130
+ resolvedProfile = "",
131
+ rosterVersion = "",
132
+ promptText = "",
133
+ metadata = {},
134
+ } = {}) {
135
+ return stableHash(
136
+ JSON.stringify({
137
+ group_id: asTrimmedString(groupId),
138
+ nickname: asTrimmedString(nickname),
139
+ resolved_profile: asTrimmedString(resolvedProfile),
140
+ roster_version: asTrimmedString(rosterVersion),
141
+ metadata,
142
+ prompt: String(promptText || ""),
143
+ })
144
+ );
145
+ }
146
+
147
+ module.exports = {
148
+ SHARED_GROUP_PREFIX,
149
+ SOLO_AGENT_PREFIX,
150
+ buildGroupPromptMetadata,
151
+ buildSoloPromptMetadata,
152
+ buildRuntimeMetadataBlock,
153
+ composeGroupBootstrapPrompt,
154
+ composeSoloBootstrapPrompt,
155
+ computeRosterVersion,
156
+ computeBootstrapFingerprint,
157
+ };