clay-server 3.2.1 → 3.2.2-beta.2
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/daemon-projects.js
CHANGED
|
@@ -6,12 +6,16 @@
|
|
|
6
6
|
|
|
7
7
|
var fs = require("fs");
|
|
8
8
|
var { scanWorktrees, isWorktree } = require("./worktree");
|
|
9
|
+
var { daemonSync } = require("./daemon-sync");
|
|
9
10
|
|
|
10
11
|
// --- Worktree tracking state ---
|
|
11
12
|
var worktreeRegistry = {}; // parentSlug -> [wtSlug, ...]
|
|
12
|
-
var worktreeTimers = {}; // parentSlug -> intervalId
|
|
13
13
|
var worktreeScanning = {}; // parentSlug -> boolean (mutex)
|
|
14
14
|
|
|
15
|
+
function getWorktreeSyncKey(parentSlug) {
|
|
16
|
+
return "worktrees:" + parentSlug;
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
function isWorktreeSlug(slug) {
|
|
16
20
|
return slug.indexOf("--") !== -1;
|
|
17
21
|
}
|
|
@@ -42,11 +46,9 @@ function scanAndRegisterWorktrees(relay, parentPath, parentSlug, parentIcon, par
|
|
|
42
46
|
worktreeRegistry[parentSlug].push(wtSlug);
|
|
43
47
|
console.log("[daemon] Registered worktree:", wtSlug, "->", wt.path, wt.accessible ? "(accessible)" : "(inaccessible)");
|
|
44
48
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}, 10000);
|
|
49
|
-
}
|
|
49
|
+
daemonSync.register(getWorktreeSyncKey(parentSlug), function () {
|
|
50
|
+
rescanWorktrees(relay, parentPath, parentSlug, parentIcon, parentOwnerId);
|
|
51
|
+
});
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
/**
|
|
@@ -114,10 +116,7 @@ function cleanupWorktreesForParent(relay, parentSlug) {
|
|
|
114
116
|
console.log("[daemon] Cascade removed worktree:", wtSlugs[i]);
|
|
115
117
|
}
|
|
116
118
|
delete worktreeRegistry[parentSlug];
|
|
117
|
-
|
|
118
|
-
clearInterval(worktreeTimers[parentSlug]);
|
|
119
|
-
delete worktreeTimers[parentSlug];
|
|
120
|
-
}
|
|
119
|
+
daemonSync.unregister(getWorktreeSyncKey(parentSlug));
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
/**
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared daemon synchronization loop.
|
|
3
|
+
*
|
|
4
|
+
* Periodic daemon work registers here so every project shares one timer.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
function attachDaemonSync(ctx) {
|
|
8
|
+
var intervalMs = ctx.intervalMs || 10000;
|
|
9
|
+
var scheduleInterval = ctx.setInterval || setInterval;
|
|
10
|
+
var cancelInterval = ctx.clearInterval || clearInterval;
|
|
11
|
+
var onError = ctx.onError || function (key, err) {
|
|
12
|
+
console.error("[daemon] Sync task failed:", key, err);
|
|
13
|
+
};
|
|
14
|
+
var tasks = {};
|
|
15
|
+
var timer = null;
|
|
16
|
+
|
|
17
|
+
function finishTask(task) {
|
|
18
|
+
task.running = false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function runTask(key, task) {
|
|
22
|
+
if (task.running) return;
|
|
23
|
+
task.running = true;
|
|
24
|
+
var result;
|
|
25
|
+
try {
|
|
26
|
+
result = task.run();
|
|
27
|
+
} catch (err) {
|
|
28
|
+
finishTask(task);
|
|
29
|
+
onError(key, err);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (result && typeof result.then === "function") {
|
|
33
|
+
Promise.resolve(result).then(function () {
|
|
34
|
+
finishTask(task);
|
|
35
|
+
}, function (err) {
|
|
36
|
+
finishTask(task);
|
|
37
|
+
onError(key, err);
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
finishTask(task);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function tick() {
|
|
45
|
+
var keys = Object.keys(tasks);
|
|
46
|
+
for (var i = 0; i < keys.length; i++) {
|
|
47
|
+
var key = keys[i];
|
|
48
|
+
var task = tasks[key];
|
|
49
|
+
if (task) runTask(key, task);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function start() {
|
|
54
|
+
if (timer || Object.keys(tasks).length === 0) return;
|
|
55
|
+
timer = scheduleInterval(tick, intervalMs);
|
|
56
|
+
if (timer && typeof timer.unref === "function") timer.unref();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function register(key, run) {
|
|
60
|
+
var current = tasks[key];
|
|
61
|
+
if (current) {
|
|
62
|
+
current.run = run;
|
|
63
|
+
} else {
|
|
64
|
+
tasks[key] = { run: run, running: false };
|
|
65
|
+
}
|
|
66
|
+
start();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function unregister(key) {
|
|
70
|
+
delete tasks[key];
|
|
71
|
+
if (Object.keys(tasks).length === 0 && timer) {
|
|
72
|
+
cancelInterval(timer);
|
|
73
|
+
timer = null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function stop() {
|
|
78
|
+
if (timer) cancelInterval(timer);
|
|
79
|
+
timer = null;
|
|
80
|
+
tasks = {};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getTaskCount() {
|
|
84
|
+
return Object.keys(tasks).length;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function isRunning() {
|
|
88
|
+
return !!timer;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
register: register,
|
|
93
|
+
unregister: unregister,
|
|
94
|
+
tick: tick,
|
|
95
|
+
stop: stop,
|
|
96
|
+
getTaskCount: getTaskCount,
|
|
97
|
+
isRunning: isRunning,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
var daemonSync = attachDaemonSync({});
|
|
102
|
+
|
|
103
|
+
module.exports = {
|
|
104
|
+
attachDaemonSync: attachDaemonSync,
|
|
105
|
+
daemonSync: daemonSync,
|
|
106
|
+
};
|
package/lib/public/css/pane.css
CHANGED
|
@@ -56,6 +56,11 @@ export function initAppNotifications() {
|
|
|
56
56
|
bellBtn = document.getElementById("notif-center-btn");
|
|
57
57
|
badgeEl = document.getElementById("notif-center-badge");
|
|
58
58
|
|
|
59
|
+
// Split panes are secondary clients inside the parent shell. They keep
|
|
60
|
+
// notification state in sync, but the parent owns the single visible
|
|
61
|
+
// banner surface for the whole split view.
|
|
62
|
+
if (store.get('paneMode')) return;
|
|
63
|
+
|
|
59
64
|
// Create banner container
|
|
60
65
|
bannerContainer = document.createElement("div");
|
|
61
66
|
bannerContainer.className = "notif-banner-container";
|
package/package.json
CHANGED