mixdog 0.9.119 → 0.9.120

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": "mixdog",
3
- "version": "0.9.119",
3
+ "version": "0.9.120",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Standalone mixdog coding-agent CLI/TUI workspace.",
@@ -241,6 +241,17 @@ export function getBackgroundTask(taskId, options = {}) {
241
241
  return task;
242
242
  }
243
243
 
244
+ /** CC-parity lifetime signal: a session-owned background task remains live
245
+ * work even while the interactive turn is idle and every view is detached. */
246
+ export function hasActiveBackgroundTasks(options = {}) {
247
+ pruneTasks(options);
248
+ const wanted = clean(options.surface);
249
+ return [...tasks.values()].some((task) =>
250
+ task.status === 'running'
251
+ && (!wanted || task.surface === wanted)
252
+ && taskMatchesScope(task, options, { includeUnattributed: false }));
253
+ }
254
+
244
255
  export function listBackgroundTasks(options = {}) {
245
256
  const { surface } = options;
246
257
  pruneTasks(options);
@@ -457,6 +468,7 @@ export function taskSummary(task) {
457
468
  operation: task.operation,
458
469
  label: task.label,
459
470
  status: task.status,
471
+ notified: task.notified === true,
460
472
  startedAt: task.startedAt,
461
473
  finishedAt: task.finishedAt,
462
474
  error: task.error,
@@ -20,6 +20,7 @@ import {
20
20
  materializePromptSubmission,
21
21
  preparePromptSubmissionForProvider,
22
22
  } from '../runtime/attachments/store.mjs';
23
+ import { hasActiveBackgroundTasks } from '../runtime/shared/background-tasks.mjs';
23
24
 
24
25
  const MAX_CLONE_DEPTH = 24;
25
26
  const requireDesktopService = createRequire(import.meta.url);
@@ -246,6 +247,12 @@ export function createSessionService({
246
247
  }
247
248
 
248
249
  function sessionBusy(entry) {
250
+ const sessionId = currentSessionId(entry);
251
+ // CC parity: detached views do not make their background commands
252
+ // disposable. Keep the owner runtime (and daemon self-shutdown guard) live
253
+ // until the task reaches a terminal state and its completion can be
254
+ // delivered back into this session.
255
+ if (sessionId && hasActiveBackgroundTasks({ callerSessionId: sessionId })) return true;
249
256
  if (typeof entry?.busy === 'boolean') return entry.busy;
250
257
  try {
251
258
  return updateEntryBusy(entry, entry.runtime.getState?.() || {});
@@ -256,6 +263,14 @@ export function createSessionService({
256
263
  }
257
264
  }
258
265
 
266
+ function liveBusyCount() {
267
+ let count = 0;
268
+ for (const entry of sessions) {
269
+ if (sessionBusy(entry)) count += 1;
270
+ }
271
+ return count;
272
+ }
273
+
259
274
  function startEvictionSweep() {
260
275
  if (evictTimer || closed) return;
261
276
  evictTimer = setInterval(() => {
@@ -1241,8 +1256,9 @@ export function createSessionService({
1241
1256
  configureSession, stop, releaseClient,
1242
1257
  get size() { return sessions.size; },
1243
1258
  /** Live work the daemon must not abandon (self-shutdown guard). */
1244
- get busyCount() { return busyEntries; },
1259
+ get busyCount() { return liveBusyCount(); },
1245
1260
  get status() {
1261
+ const busy = liveBusyCount();
1246
1262
  let watched = 0;
1247
1263
  let retained = 0;
1248
1264
  let projected = 0;
@@ -1253,7 +1269,7 @@ export function createSessionService({
1253
1269
  }
1254
1270
  return {
1255
1271
  live: sessions.size,
1256
- busy: busyEntries,
1272
+ busy,
1257
1273
  watched,
1258
1274
  retained,
1259
1275
  projected,