shraga 0.1.102 → 0.1.104
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/dist/client/index.html
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
14
14
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
15
15
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet" />
|
|
16
|
-
<script type="module" crossorigin src="/assets/index-
|
|
16
|
+
<script type="module" crossorigin src="/assets/index-DSNBsFVU.js"></script>
|
|
17
17
|
<link rel="stylesheet" crossorigin href="/assets/index-CibL2gLy.css">
|
|
18
18
|
</head>
|
|
19
19
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shraga",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.104",
|
|
4
4
|
"description": "The teammate you delegate coding to — a self-hostable, multi-user AI coding agent web UI (Claude Code, with a pluggable engine seam).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
package/src/client/App.tsx
CHANGED
|
@@ -169,6 +169,7 @@ function AppInner() {
|
|
|
169
169
|
}
|
|
170
170
|
}, [bumpSidebar]);
|
|
171
171
|
|
|
172
|
+
const workspaceRefreshTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
172
173
|
const markReadRef = useRef<((sid: string) => void) | null>(null);
|
|
173
174
|
const unreadEventRef = useRef<((event: ServerEvent) => void) | null>(null);
|
|
174
175
|
const activeSessionRef = useRef(activeSessionId);
|
|
@@ -186,7 +187,13 @@ function AppInner() {
|
|
|
186
187
|
if (event.type === 'permission_request') requestDesktopAttention(true);
|
|
187
188
|
switch (event.type) {
|
|
188
189
|
case 'workspace_change':
|
|
189
|
-
|
|
190
|
+
// A burst of changes (one event per path) collapses into a single tree refetch.
|
|
191
|
+
if (!workspaceRefreshTimer.current) {
|
|
192
|
+
workspaceRefreshTimer.current = setTimeout(() => {
|
|
193
|
+
workspaceRefreshTimer.current = null;
|
|
194
|
+
refreshWorkspace();
|
|
195
|
+
}, 1000);
|
|
196
|
+
}
|
|
190
197
|
break;
|
|
191
198
|
case 'session_title_updated':
|
|
192
199
|
bumpSidebar();
|
|
@@ -365,7 +365,9 @@ export class WebhookStreamer {
|
|
|
365
365
|
}
|
|
366
366
|
|
|
367
367
|
/** PROACTIVE post — a scheduled run, a deploy notice, a downtime report. No preceding user turn,
|
|
368
|
-
* so there is no row to patch: the receiver mints one. Same signed transport, same fence.
|
|
369
|
-
|
|
370
|
-
|
|
368
|
+
* so there is no row to patch: the receiver mints one. Same signed transport, same fence.
|
|
369
|
+
* `notify` is OPT-IN: it asks the receiver to also push to the owner's device. Omitted (not
|
|
370
|
+
* `false`) when unset, so a plain notice's wire body is byte-identical to before. */
|
|
371
|
+
export function postNotice(cb: WebhookTarget, convId: string, text: string, opts?: { notify?: boolean }): Promise<boolean> {
|
|
372
|
+
return postDelivery(cb, { type: 'post', convId, text, ...(opts?.notify ? { notify: true } : {}) });
|
|
371
373
|
}
|
package/src/server/workspace.ts
CHANGED
|
@@ -227,6 +227,9 @@ export function watchWorkspace(cb: (event: { action: 'created' | 'modified' | 'd
|
|
|
227
227
|
pending.clear();
|
|
228
228
|
timer = null;
|
|
229
229
|
};
|
|
230
|
+
// Last seen mtime:size per path. Bun's recursive watcher can get stuck re-emitting an event for an
|
|
231
|
+
// unchanged file (observed: ~14/s for hours) — each one fans out to a full tree refetch per client.
|
|
232
|
+
const seen = new Map<string, string>();
|
|
230
233
|
let watcher: import('node:fs').FSWatcher;
|
|
231
234
|
try {
|
|
232
235
|
watcher = watch(WORKSPACE_DIR, { recursive: true }, (eventType, filename) => {
|
|
@@ -234,7 +237,11 @@ export function watchWorkspace(cb: (event: { action: 'created' | 'modified' | 'd
|
|
|
234
237
|
const rel = String(filename).split(path.sep).join('/');
|
|
235
238
|
if (rel.split('/').some((seg) => seg.startsWith('.'))) return;
|
|
236
239
|
const full = path.join(WORKSPACE_DIR, rel);
|
|
237
|
-
|
|
240
|
+
let sig: string | undefined;
|
|
241
|
+
try { const st = statSync(full); sig = `${st.mtimeMs}:${st.size}`; } catch {}
|
|
242
|
+
if (sig !== undefined && seen.get(rel) === sig) return;
|
|
243
|
+
if (sig === undefined) seen.delete(rel); else seen.set(rel, sig);
|
|
244
|
+
const action: 'created' | 'modified' | 'deleted' = sig !== undefined
|
|
238
245
|
? (eventType === 'rename' ? 'created' : 'modified')
|
|
239
246
|
: 'deleted';
|
|
240
247
|
pending.set(rel, action);
|