diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 479b5560..582015c0 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -14,6 +14,7 @@ - Fixed AgentSession retry, compaction, and event settlement to use the awaited agent lifecycle instead of a separate event queue, and added `willRetry` to `agent_end` session events. - Fixed the subagent extension's parallel mode to return useful per-task output and failed-task diagnostics to the parent model instead of 100-character previews ([#4710](https://github.com/earendil-works/pi/issues/4710)). - Fixed Windows local bash execution to hide helper console windows when launched from background SDK processes ([#4699](https://github.com/earendil-works/pi/issues/4699)). +- Fixed managed npm extension folders to set cloud-sync ignore metadata where supported ([#4763](https://github.com/earendil-works/pi/issues/4763)). ## [0.75.3] - 2026-05-18 diff --git a/packages/coding-agent/src/core/package-manager.ts b/packages/coding-agent/src/core/package-manager.ts index 59d53427..90c41942 100644 --- a/packages/coding-agent/src/core/package-manager.ts +++ b/packages/coding-agent/src/core/package-manager.ts @@ -30,7 +30,7 @@ import { minimatch } from "minimatch"; import { CONFIG_DIR_NAME } from "../config.ts"; import { spawnProcess, spawnProcessSync } from "../utils/child-process.ts"; import { type GitSource, parseGitUrl } from "../utils/git.ts"; -import { canonicalizePath, isLocalPath } from "../utils/paths.ts"; +import { canonicalizePath, isLocalPath, markPathIgnoredByCloudSync } from "../utils/paths.ts"; import { isStdoutTakenOver } from "./output-guard.ts"; import type { PackageSource, SettingsManager } from "./settings-manager.ts"; @@ -1822,6 +1822,7 @@ export class DefaultPackageManager implements PackageManager { if (!existsSync(installRoot)) { mkdirSync(installRoot, { recursive: true }); } + markPathIgnoredByCloudSync(installRoot); this.ensureGitIgnore(installRoot); const packageJsonPath = join(installRoot, "package.json"); if (!existsSync(packageJsonPath)) { diff --git a/packages/coding-agent/src/utils/paths.ts b/packages/coding-agent/src/utils/paths.ts index ef36de7a..fd8d176e 100644 --- a/packages/coding-agent/src/utils/paths.ts +++ b/packages/coding-agent/src/utils/paths.ts @@ -1,5 +1,6 @@ import { realpathSync } from "node:fs"; import { isAbsolute, relative, resolve as resolvePath, sep } from "node:path"; +import { spawnProcessSync } from "./child-process.ts"; /** * Resolve a path to its canonical (real) form, following symlinks. @@ -55,3 +56,20 @@ export function formatPathRelativeToCwdOrAbsolute(filePath: string, cwd: string) const absolutePath = resolveAgainstCwd(filePath, cwd); return (getCwdRelativePath(absolutePath, cwd) ?? absolutePath).split(sep).join("/"); } + +export function markPathIgnoredByCloudSync(path: string): void { + const attrs = + process.platform === "darwin" + ? ["com.dropbox.ignored", "com.apple.fileprovider.ignore#P"] + : process.platform === "linux" + ? ["user.com.dropbox.ignored"] + : []; + + for (const attr of attrs) { + if (process.platform === "darwin") { + spawnProcessSync("xattr", ["-w", attr, "1", path], { encoding: "utf-8", stdio: "ignore" }); + } else { + spawnProcessSync("setfattr", ["-n", attr, "-v", "1", path], { encoding: "utf-8", stdio: "ignore" }); + } + } +}