shraga 0.1.15 → 0.1.16
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shraga",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
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/server/boot.ts
CHANGED
|
@@ -26,7 +26,7 @@ import { mountFeatures, registerFeature, resumeFeatureSession, collectFeatureFla
|
|
|
26
26
|
import { registerSpaCatchAll } from './spa-catchall.ts';
|
|
27
27
|
import { slackFeature } from './slack/feature.ts';
|
|
28
28
|
import { dataPath } from './paths.ts';
|
|
29
|
-
import { getAllSessions, getSession, getSessionHistory, upsertSession, appendMessage, saveConversation, loadConversation, setSessionDirectives, getAutoApprove, setAutoApprove, getSessionsByScheduleId, getSessionsVisibleTo, isSessionVisibleTo, setRunStatus, incrementRetryCount, resetRetryCount, getRunningSessions, updateScheduledSessionStatus, setShuttingDown, backfillSessionVisibility, writePartial, readPartial, clearPartial, registerLivePartial, unregisterLivePartial, readLivePartial, acquireSessionLock, releaseSessionLock, replaceSessionLock, isSessionLocked, getSessionAbortController, forkSession, generateSessionTitle, type ConvBlock, type ConvMessage, type SessionMeta } from './sessions.ts';
|
|
29
|
+
import { getAllSessions, getSession, getSessionHistory, upsertSession, appendMessage, saveConversation, loadConversation, setSessionDirectives, getAutoApprove, setAutoApprove, getSessionsByScheduleId, getSessionsVisibleTo, isSessionVisibleTo, setRunStatus, incrementRetryCount, resetRetryCount, getRunningSessions, getActiveLockCount, updateScheduledSessionStatus, setShuttingDown, backfillSessionVisibility, writePartial, readPartial, clearPartial, registerLivePartial, unregisterLivePartial, readLivePartial, acquireSessionLock, releaseSessionLock, replaceSessionLock, isSessionLocked, getSessionAbortController, forkSession, generateSessionTitle, type ConvBlock, type ConvMessage, type SessionMeta } from './sessions.ts';
|
|
30
30
|
import { setBroadcaster } from './session-bus.ts';
|
|
31
31
|
import * as scheduler from './scheduler/index.ts';
|
|
32
32
|
import { initPolls } from './polls.ts';
|
|
@@ -1808,16 +1808,19 @@ async function gracefulShutdown(signal: string, opts: { exit?: boolean } = {}) {
|
|
|
1808
1808
|
// Agent turns routinely run for minutes; give in-flight streams time to finish before we force-kill
|
|
1809
1809
|
// their Claude Code child processes (which would otherwise surface as `exited with code 143`).
|
|
1810
1810
|
// Keep this under the service manager's stop timeout (e.g. systemd TimeoutStopSec) so the drain wins, not SIGKILL.
|
|
1811
|
+
// Drain on the LIVE lock count, not the persisted index: setRunStatus freezes `running` in the
|
|
1812
|
+
// index at shutdown (the crash-recovery marker), so index entries can never go idle mid-drain —
|
|
1813
|
+
// polling the index made every restart with an active session (or a stale marker from a prior
|
|
1814
|
+
// crash) sit out the full 90s.
|
|
1811
1815
|
const deadline = Date.now() + 90_000;
|
|
1812
1816
|
while (Date.now() < deadline) {
|
|
1813
|
-
const running =
|
|
1814
|
-
if (running
|
|
1815
|
-
console.log(`[server] waiting for ${running
|
|
1817
|
+
const running = getActiveLockCount();
|
|
1818
|
+
if (running === 0) break;
|
|
1819
|
+
console.log(`[server] waiting for ${running} active stream(s)…`);
|
|
1816
1820
|
await new Promise((r) => setTimeout(r, 2000));
|
|
1817
1821
|
}
|
|
1818
1822
|
|
|
1819
|
-
|
|
1820
|
-
console.log(`[server] drain complete — ${remaining.length} stream(s) still active, closing`);
|
|
1823
|
+
console.log(`[server] drain complete — ${getActiveLockCount()} stream(s) still active, closing`);
|
|
1821
1824
|
|
|
1822
1825
|
for (const [ws, session] of activeConnections) {
|
|
1823
1826
|
for (const ac of session.abortControllers.values()) ac.abort();
|
|
@@ -140,6 +140,10 @@ export async function runSchedule(
|
|
|
140
140
|
if (eventCtx) base = `${base}\n\n---\n${formatEventBlock(eventCtx)}`;
|
|
141
141
|
prompt = base;
|
|
142
142
|
}
|
|
143
|
+
// task.model rides the same [model] prompt-directive channel users type by hand — parseDirectives
|
|
144
|
+
// strips it and resolves aliases. Prepending (vs new plumbing) also persists the choice into the
|
|
145
|
+
// saved prompt, so the session UI shows which model the schedule actually requested.
|
|
146
|
+
if (!resume && task.model) prompt = `[${task.model}] ${prompt}`;
|
|
143
147
|
|
|
144
148
|
// Save the synthesized user prompt to the conversation (skip on resume — task prompt already persisted).
|
|
145
149
|
if (!resume) {
|
package/src/server/sessions.ts
CHANGED
|
@@ -326,6 +326,14 @@ export function isSessionLocked(sessionId: string): boolean {
|
|
|
326
326
|
return globalSessionLocks.has(sessionId);
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
+
/** Count of queries streaming in THIS process right now. The drain loop must use this, not the
|
|
330
|
+
* persisted index: setRunStatus freezes `running` at shutdown as the crash-recovery marker, so
|
|
331
|
+
* index entries can't go idle mid-drain (and stale entries from a prior crash would stall the
|
|
332
|
+
* drain for sessions that aren't streaming at all). */
|
|
333
|
+
export function getActiveLockCount(): number {
|
|
334
|
+
return globalSessionLocks.size;
|
|
335
|
+
}
|
|
336
|
+
|
|
329
337
|
export function replaceSessionLock(sessionId: string, origin: SessionLock['origin'], abortController: AbortController): void {
|
|
330
338
|
globalSessionLocks.set(sessionId, { origin, abortController, startedAt: Date.now() });
|
|
331
339
|
}
|