clay-server 2.19.0 → 2.20.0-beta.1

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/lib/notes.js CHANGED
@@ -109,12 +109,32 @@ function createNotesManager(opts) {
109
109
  return update(id, { zIndex: maxZ + 1 });
110
110
  }
111
111
 
112
+ /**
113
+ * Return formatted text of all active (non-hidden) notes.
114
+ * Used to inject into mate CLAUDE.md so the mate can read them.
115
+ */
116
+ function getActiveNotesText() {
117
+ var active = [];
118
+ for (var i = 0; i < notes.length; i++) {
119
+ if (!notes[i].hidden && notes[i].text) active.push(notes[i]);
120
+ }
121
+ if (active.length === 0) return "";
122
+ var lines = [];
123
+ for (var j = 0; j < active.length; j++) {
124
+ var n = active[j];
125
+ var label = n.color ? "[" + n.color + "]" : "";
126
+ lines.push("- " + label + " " + n.text.trim());
127
+ }
128
+ return lines.join("\n");
129
+ }
130
+
112
131
  return {
113
132
  list: list,
114
133
  create: create,
115
134
  update: update,
116
135
  remove: remove,
117
136
  bringToFront: bringToFront,
137
+ getActiveNotesText: getActiveNotesText,
118
138
  };
119
139
  }
120
140
 
package/lib/os-users.js CHANGED
@@ -103,6 +103,60 @@ function fsAsUser(op, args, osUserInfo) {
103
103
  return JSON.parse(output.trim());
104
104
  }
105
105
 
106
+ /**
107
+ * Detect the Linux distribution family for package manager guidance.
108
+ * Returns "debian", "rhel", "alpine", "suse", "arch", or "unknown".
109
+ */
110
+ function detectDistroFamily() {
111
+ try {
112
+ var release = fs.readFileSync("/etc/os-release", "utf8");
113
+ var idLike = "";
114
+ var id = "";
115
+ var lines = release.split("\n");
116
+ for (var i = 0; i < lines.length; i++) {
117
+ if (lines[i].indexOf("ID_LIKE=") === 0) idLike = lines[i].substring(8).replace(/"/g, "").toLowerCase();
118
+ if (lines[i].indexOf("ID=") === 0 && lines[i].indexOf("ID_LIKE=") !== 0) id = lines[i].substring(3).replace(/"/g, "").toLowerCase();
119
+ }
120
+ var all = id + " " + idLike;
121
+ if (all.indexOf("debian") !== -1 || all.indexOf("ubuntu") !== -1) return "debian";
122
+ if (all.indexOf("rhel") !== -1 || all.indexOf("centos") !== -1 || all.indexOf("fedora") !== -1 || all.indexOf("amzn") !== -1 || all.indexOf("amazon") !== -1) return "rhel";
123
+ if (all.indexOf("alpine") !== -1) return "alpine";
124
+ if (all.indexOf("suse") !== -1 || all.indexOf("opensuse") !== -1) return "suse";
125
+ if (all.indexOf("arch") !== -1 || all.indexOf("manjaro") !== -1) return "arch";
126
+ return "unknown";
127
+ } catch (e) {
128
+ return "unknown";
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Build a user-friendly install command for the ACL package based on distro.
134
+ */
135
+ function getAclInstallCommand() {
136
+ var distro = detectDistroFamily();
137
+ switch (distro) {
138
+ case "debian": return "sudo apt install -y acl";
139
+ case "rhel": return "sudo yum install -y acl";
140
+ case "alpine": return "sudo apk add acl";
141
+ case "suse": return "sudo zypper install -y acl";
142
+ case "arch": return "sudo pacman -S --noconfirm acl";
143
+ default: return "Install the 'acl' package using your distribution's package manager (apt, yum, apk, etc.)";
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Check if setfacl is available on the system.
149
+ * Returns { available: true } or { available: false, installCmd: "..." }.
150
+ */
151
+ function checkAclSupport() {
152
+ try {
153
+ execSync("which setfacl", { encoding: "utf8", timeout: 5000, stdio: "pipe" });
154
+ return { available: true };
155
+ } catch (e) {
156
+ return { available: false, installCmd: getAclInstallCommand() };
157
+ }
158
+ }
159
+
106
160
  /**
107
161
  * Grant a Linux user ACL access (rwX) to a project directory.
108
162
  * Uses setfacl to add recursive + default ACL entries.
@@ -121,7 +175,14 @@ function grantProjectAccess(projectPath, linuxUser) {
121
175
  });
122
176
  console.log("[os-users] Granted ACL access for " + linuxUser + " on " + projectPath);
123
177
  } catch (e) {
124
- console.error("[os-users] Failed to grant ACL access for " + linuxUser + " on " + projectPath + ": " + (e.message || e));
178
+ var errMsg = (e.stderr || e.message || "").toString();
179
+ if (errMsg.indexOf("not found") !== -1 || errMsg.indexOf("ENOENT") !== -1) {
180
+ var cmd = getAclInstallCommand();
181
+ console.error("[os-users] setfacl is not installed. ACL support is required for OS user isolation.");
182
+ console.error("[os-users] Install it with: " + cmd);
183
+ } else {
184
+ console.error("[os-users] Failed to grant ACL access for " + linuxUser + " on " + projectPath + ": " + errMsg);
185
+ }
125
186
  }
126
187
  }
127
188
 
@@ -140,7 +201,14 @@ function revokeProjectAccess(projectPath, linuxUser) {
140
201
  });
141
202
  console.log("[os-users] Revoked ACL access for " + linuxUser + " on " + projectPath);
142
203
  } catch (e) {
143
- console.error("[os-users] Failed to revoke ACL access for " + linuxUser + " on " + projectPath + ": " + (e.message || e));
204
+ var errMsg = (e.stderr || e.message || "").toString();
205
+ if (errMsg.indexOf("not found") !== -1 || errMsg.indexOf("ENOENT") !== -1) {
206
+ var cmd = getAclInstallCommand();
207
+ console.error("[os-users] setfacl is not installed. ACL support is required for OS user isolation.");
208
+ console.error("[os-users] Install it with: " + cmd);
209
+ } else {
210
+ console.error("[os-users] Failed to revoke ACL access for " + linuxUser + " on " + projectPath + ": " + errMsg);
211
+ }
144
212
  }
145
213
  }
146
214
 
@@ -343,6 +411,7 @@ function ensureProjectsDir() {
343
411
  }
344
412
 
345
413
  module.exports = {
414
+ checkAclSupport: checkAclSupport,
346
415
  resolveOsUserInfo: resolveOsUserInfo,
347
416
  fsAsUser: fsAsUser,
348
417
  grantProjectAccess: grantProjectAccess,