u-foo 2.5.5 → 2.5.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/bin/ucode.js CHANGED
@@ -106,6 +106,11 @@ const resolved = resolveUcodeLaunch({
106
106
  cwd: process.cwd(),
107
107
  });
108
108
 
109
+ // Capture before resolved.env (which may carry project-config values) is
110
+ // merged into process.env — the user's own env var is trusted, a path from
111
+ // the project config must stay inside the project root.
112
+ const userBootstrapFile = String(process.env.UFOO_UCODE_BOOTSTRAP_FILE || "").trim();
113
+
109
114
  if (resolved && resolved.env && typeof resolved.env === "object") {
110
115
  for (const [key, value] of Object.entries(resolved.env)) {
111
116
  if (!key) continue;
@@ -133,6 +138,10 @@ try {
133
138
  projectRoot: process.cwd(),
134
139
  promptFile: process.env.UFOO_UCODE_PROMPT_FILE || "",
135
140
  targetFile: process.env.UFOO_UCODE_BOOTSTRAP_FILE || "",
141
+ allowOutsideProjectRoot: Boolean(userBootstrapFile),
142
+ // The native core already injects the ufoo protocol via its modular
143
+ // prompt; inlining it here would append the same text a second time.
144
+ includeDefaultProtocol: false,
136
145
  });
137
146
  } catch (err) {
138
147
  const mode = String(process.env.UFOO_UCODE_APPEND_SYSTEM_PROMPT_MODE || "auto").trim().toLowerCase();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u-foo",
3
- "version": "2.5.5",
3
+ "version": "2.5.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",
@@ -114,6 +114,12 @@ class AgentNotifier {
114
114
  * 更新心跳时间戳(last_seen)
115
115
  */
116
116
  updateHeartbeat() {
117
+ // TODO(race, needs evidence): this read-modify-write of all-agents.json
118
+ // has no file lock and races with the daemon, the launcher, and other
119
+ // agents' notifiers writing the same file — a lost update could roll
120
+ // back activity_state/last_seen (suspected amplifier of delivery
121
+ // stalls, not yet confirmed). If evidence shows lost updates, serialize
122
+ // writes (lockfile or single-writer daemon IPC) instead of JSON RMW.
117
123
  try {
118
124
  if (!this.agentsFile || !fs.existsSync(this.agentsFile)) return;
119
125
  const data = readJSON(this.agentsFile, null);
@@ -61,8 +61,8 @@ function stripAnsi(text) {
61
61
  function rewriteTitleOscPrefix(text, prefix) {
62
62
  if (!prefix || !text) return text;
63
63
  return String(text).replace(/\x1b\]([012]);([^\x07\x1b]*)(\x07|\x1b\\)/g, (match, code, title, terminator) => {
64
- if (!title || title.startsWith(`${prefix}:`)) return match;
65
- return `\x1b]${code};${prefix}:${title}${terminator}`;
64
+ if (!title || title.startsWith(`${prefix}: `)) return match;
65
+ return `\x1b]${code};${prefix}: ${title}${terminator}`;
66
66
  });
67
67
  }
68
68
 
@@ -211,8 +211,8 @@ class PtyWrapper {
211
211
  if (!this.titlePrefix || !text) return text;
212
212
  const prefix = this.titlePrefix;
213
213
  return text.replace(/\x1b\]([012]);([^\x07\x1b]*)(\x07|\x1b\\)/g, (match, code, title, terminator) => {
214
- if (!title || title.startsWith(`${prefix}:`)) return match;
215
- return `\x1b]${code};${prefix}:${title}${terminator}`;
214
+ if (!title || title.startsWith(`${prefix}: `)) return match;
215
+ return `\x1b]${code};${prefix}: ${title}${terminator}`;
216
216
  });
217
217
  }
218
218
 
@@ -54,7 +54,7 @@ function getSystemPrompt({
54
54
  return [overrideSystemPrompt];
55
55
  }
56
56
 
57
- // --- Static sections (cacheable, computed once per session) ---
57
+ // --- Static sections (session-independent content, recomputed on every call) ---
58
58
  const staticSections = [
59
59
  getIdentitySection(),
60
60
  getSystemSection(),
@@ -70,7 +70,7 @@ function getSystemPrompt({
70
70
  // --- Dynamic sections (may change per session/turn) ---
71
71
  const dynamicSectionDefs = [
72
72
  systemPromptSection("ufoo", () => getUfooIntegrationSection()),
73
- systemPromptSection("environment", () =>
73
+ uncachedSection("environment", () =>
74
74
  getEnvironmentSection({ workspaceRoot, model, provider }),
75
75
  ),
76
76
  uncachedSection("skills", () => {
@@ -6,7 +6,7 @@ function getBashToolDescription() {
6
6
  return `Run a single shell command in the workspace directory.
7
7
 
8
8
  Usage notes:
9
- - Default timeout is 60 seconds. Use timeoutMs to adjust for longer operations.
9
+ - Default timeout is 60 seconds. Use timeoutMs to adjust for longer operations (maximum 600 seconds; larger values are clamped).
10
10
  - Do NOT use bash for file operations when a dedicated tool exists:
11
11
  - Use read instead of cat/head/tail.
12
12
  - Use write instead of echo/cat heredoc.
@@ -9,6 +9,7 @@ Usage notes:
9
9
  - You must read the file first before editing. This tool will produce incorrect results if you guess at file contents.
10
10
  - The find string must match exactly — including whitespace and indentation. Copy it precisely from the read output.
11
11
  - The find string should be unique in the file. If it's not unique, provide more surrounding context to make it unique, or use all: true to replace every occurrence.
12
+ - If the find string does not match anything, the tool fails with a "not found" error — no partial edit is applied. Re-read the file and adjust the find string instead of assuming the edit succeeded.
12
13
  - Use all: true for bulk replacements like renaming a variable across the file.
13
14
  - Preserve the exact indentation of the original code when specifying the replacement.`;
14
15
  }
@@ -7,11 +7,12 @@ function getReadToolDescription() {
7
7
 
8
8
  Usage notes:
9
9
  - The path parameter is relative to the workspace root.
10
- - By default reads the entire file. For large files, use startLine and endLine to read specific ranges.
10
+ - By default reads the entire file. Files larger than ~4MB are only partially read from the start; in that case truncated is true.
11
+ - Use startLine and endLine to read specific line ranges.
11
12
  - Use maxBytes to limit the amount of data returned (default ~200KB).
12
13
  - Cannot read directories — use bash with \`ls\` for that.
13
14
  - Always read a file before editing it to understand its current content and structure.
14
- - Results are returned with line numbers for easy reference.`;
15
+ - The content field contains the raw file text without line numbers. The result also includes totalLines (lines in the portion that was read) and truncated (true when the content was cut short by maxBytes or the large-file limit).`;
15
16
  }
16
17
 
17
18
  module.exports = { READ_TOOL_NAME, getReadToolDescription };