code-squad-cli 1.2.17 → 1.2.19

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.
@@ -47,7 +47,6 @@ export function createSessionRouter(sessionManager) {
47
47
  res.json({
48
48
  session_id: session.id,
49
49
  cwd: session.cwd,
50
- lastActivity: session.lastActivity,
51
50
  });
52
51
  });
53
52
  return router;
@@ -6,10 +6,10 @@ export interface Session {
6
6
  cwd: string;
7
7
  /** FileWatcher instance for this session */
8
8
  watcher: FileWatcher;
9
- /** Last activity timestamp (ms since epoch) */
10
- lastActivity: number;
11
9
  /** Changed files since last poll (for polling-based sync) */
12
10
  pendingChanges: PendingChanges;
11
+ /** Timeout timer for session expiration */
12
+ timeoutTimer: ReturnType<typeof setTimeout> | null;
13
13
  }
14
14
  export interface PendingChanges {
15
15
  filesChanged: boolean;
@@ -25,10 +25,9 @@ export interface SessionManagerOptions {
25
25
  export declare class SessionManager {
26
26
  private sessions;
27
27
  private options;
28
- private cleanupInterval;
29
28
  constructor(options: SessionManagerOptions);
30
29
  /**
31
- * Start the session cleanup timer
30
+ * Start the session manager (no-op, kept for API compatibility)
32
31
  */
33
32
  start(): void;
34
33
  /**
@@ -40,15 +39,15 @@ export declare class SessionManager {
40
39
  */
41
40
  registerSession(sessionId: string, cwd: string): Session;
42
41
  /**
43
- * Get a session by ID and update activity
42
+ * Get a session by ID and reset timeout
44
43
  */
45
44
  getSession(sessionId: string): Session | undefined;
46
45
  /**
47
- * Touch session to update activity timestamp (called on every API request)
46
+ * Touch session to reset timeout (called on every API request)
48
47
  */
49
48
  touchSession(sessionId: string): void;
50
49
  /**
51
- * Unregister a session (e.g., on cancel/submit)
50
+ * Unregister a session (e.g., on cancel/submit/timeout)
52
51
  */
53
52
  unregisterSession(sessionId: string): Promise<void>;
54
53
  /**
@@ -65,5 +64,9 @@ export declare class SessionManager {
65
64
  get hasSessions(): boolean;
66
65
  private createWatcher;
67
66
  private createEmptyPendingChanges;
68
- private cleanupTimedOutSessions;
67
+ /**
68
+ * Reset the timeout timer for a session.
69
+ * Called on every activity (register, poll, etc.)
70
+ */
71
+ private resetSessionTimeout;
69
72
  }
@@ -3,29 +3,26 @@ const log = (...args) => console.error(...args);
3
3
  export class SessionManager {
4
4
  sessions = new Map();
5
5
  options;
6
- cleanupInterval = null;
7
6
  constructor(options) {
8
7
  this.options = options;
9
8
  }
10
9
  /**
11
- * Start the session cleanup timer
10
+ * Start the session manager (no-op, kept for API compatibility)
12
11
  */
13
12
  start() {
14
- // Check for timed out sessions every 5 seconds
15
- this.cleanupInterval = setInterval(() => {
16
- this.cleanupTimedOutSessions();
17
- }, 5000);
13
+ // No longer uses periodic cleanup - each session has its own timeout
18
14
  }
19
15
  /**
20
16
  * Stop the session manager and clean up all sessions
21
17
  */
22
18
  async stop() {
23
- if (this.cleanupInterval) {
24
- clearInterval(this.cleanupInterval);
25
- this.cleanupInterval = null;
26
- }
27
- // Stop all watchers
28
- const stopPromises = Array.from(this.sessions.values()).map(session => session.watcher.stop());
19
+ // Clear all session timeouts and stop watchers
20
+ const stopPromises = Array.from(this.sessions.values()).map(session => {
21
+ if (session.timeoutTimer) {
22
+ clearTimeout(session.timeoutTimer);
23
+ }
24
+ return session.watcher.stop();
25
+ });
29
26
  await Promise.all(stopPromises);
30
27
  this.sessions.clear();
31
28
  }
@@ -35,8 +32,8 @@ export class SessionManager {
35
32
  registerSession(sessionId, cwd) {
36
33
  const existing = this.sessions.get(sessionId);
37
34
  if (existing) {
38
- // Update activity timestamp
39
- existing.lastActivity = Date.now();
35
+ // Reset timeout on activity
36
+ this.resetSessionTimeout(sessionId);
40
37
  // If cwd changed, need to restart watcher
41
38
  if (existing.cwd !== cwd) {
42
39
  existing.watcher.stop();
@@ -52,38 +49,40 @@ export class SessionManager {
52
49
  id: sessionId,
53
50
  cwd,
54
51
  watcher,
55
- lastActivity: Date.now(),
56
52
  pendingChanges: this.createEmptyPendingChanges(),
53
+ timeoutTimer: null,
57
54
  };
58
55
  this.sessions.set(sessionId, session);
56
+ this.resetSessionTimeout(sessionId);
59
57
  log(`[SessionManager] Session registered: ${sessionId} (cwd: ${cwd})`);
60
58
  return session;
61
59
  }
62
60
  /**
63
- * Get a session by ID and update activity
61
+ * Get a session by ID and reset timeout
64
62
  */
65
63
  getSession(sessionId) {
66
64
  const session = this.sessions.get(sessionId);
67
65
  if (session) {
68
- session.lastActivity = Date.now();
66
+ this.resetSessionTimeout(sessionId);
69
67
  }
70
68
  return session;
71
69
  }
72
70
  /**
73
- * Touch session to update activity timestamp (called on every API request)
71
+ * Touch session to reset timeout (called on every API request)
74
72
  */
75
73
  touchSession(sessionId) {
76
- const session = this.sessions.get(sessionId);
77
- if (session) {
78
- session.lastActivity = Date.now();
79
- }
74
+ this.resetSessionTimeout(sessionId);
80
75
  }
81
76
  /**
82
- * Unregister a session (e.g., on cancel/submit)
77
+ * Unregister a session (e.g., on cancel/submit/timeout)
83
78
  */
84
79
  async unregisterSession(sessionId) {
85
80
  const session = this.sessions.get(sessionId);
86
81
  if (session) {
82
+ // Clear timeout timer
83
+ if (session.timeoutTimer) {
84
+ clearTimeout(session.timeoutTimer);
85
+ }
87
86
  await session.watcher.stop();
88
87
  this.sessions.delete(sessionId);
89
88
  log(`[SessionManager] Session unregistered: ${sessionId}`);
@@ -147,17 +146,24 @@ export class SessionManager {
147
146
  changedFiles: new Set(),
148
147
  };
149
148
  }
150
- cleanupTimedOutSessions() {
151
- const now = Date.now();
152
- const timedOut = [];
153
- for (const [sessionId, session] of this.sessions) {
154
- if (now - session.lastActivity > this.options.sessionTimeoutMs) {
155
- timedOut.push(sessionId);
156
- }
149
+ /**
150
+ * Reset the timeout timer for a session.
151
+ * Called on every activity (register, poll, etc.)
152
+ */
153
+ resetSessionTimeout(sessionId) {
154
+ const session = this.sessions.get(sessionId);
155
+ if (!session)
156
+ return;
157
+ // Clear existing timeout
158
+ if (session.timeoutTimer) {
159
+ clearTimeout(session.timeoutTimer);
157
160
  }
158
- for (const sessionId of timedOut) {
161
+ // Set new timeout
162
+ session.timeoutTimer = setTimeout(() => {
159
163
  log(`[SessionManager] Session timed out: ${sessionId}`);
160
- this.unregisterSession(sessionId);
161
- }
164
+ this.unregisterSession(sessionId).catch(error => {
165
+ log(`[SessionManager] Error during session unregister for ${sessionId}:`, error);
166
+ });
167
+ }, this.options.sessionTimeoutMs);
162
168
  }
163
169
  }
package/dist/index.js CHANGED
@@ -1265,8 +1265,7 @@ function createSessionRouter(sessionManager) {
1265
1265
  }
1266
1266
  res.json({
1267
1267
  session_id: session.id,
1268
- cwd: session.cwd,
1269
- lastActivity: session.lastActivity
1268
+ cwd: session.cwd
1270
1269
  });
1271
1270
  });
1272
1271
  return router6;
@@ -1426,27 +1425,24 @@ var log = (...args) => console.error(...args);
1426
1425
  var SessionManager = class {
1427
1426
  sessions = /* @__PURE__ */ new Map();
1428
1427
  options;
1429
- cleanupInterval = null;
1430
1428
  constructor(options) {
1431
1429
  this.options = options;
1432
1430
  }
1433
1431
  /**
1434
- * Start the session cleanup timer
1432
+ * Start the session manager (no-op, kept for API compatibility)
1435
1433
  */
1436
1434
  start() {
1437
- this.cleanupInterval = setInterval(() => {
1438
- this.cleanupTimedOutSessions();
1439
- }, 5e3);
1440
1435
  }
1441
1436
  /**
1442
1437
  * Stop the session manager and clean up all sessions
1443
1438
  */
1444
1439
  async stop() {
1445
- if (this.cleanupInterval) {
1446
- clearInterval(this.cleanupInterval);
1447
- this.cleanupInterval = null;
1448
- }
1449
- const stopPromises = Array.from(this.sessions.values()).map((session) => session.watcher.stop());
1440
+ const stopPromises = Array.from(this.sessions.values()).map((session) => {
1441
+ if (session.timeoutTimer) {
1442
+ clearTimeout(session.timeoutTimer);
1443
+ }
1444
+ return session.watcher.stop();
1445
+ });
1450
1446
  await Promise.all(stopPromises);
1451
1447
  this.sessions.clear();
1452
1448
  }
@@ -1456,7 +1452,7 @@ var SessionManager = class {
1456
1452
  registerSession(sessionId, cwd) {
1457
1453
  const existing = this.sessions.get(sessionId);
1458
1454
  if (existing) {
1459
- existing.lastActivity = Date.now();
1455
+ this.resetSessionTimeout(sessionId);
1460
1456
  if (existing.cwd !== cwd) {
1461
1457
  existing.watcher.stop();
1462
1458
  existing.cwd = cwd;
@@ -1470,38 +1466,39 @@ var SessionManager = class {
1470
1466
  id: sessionId,
1471
1467
  cwd,
1472
1468
  watcher,
1473
- lastActivity: Date.now(),
1474
- pendingChanges: this.createEmptyPendingChanges()
1469
+ pendingChanges: this.createEmptyPendingChanges(),
1470
+ timeoutTimer: null
1475
1471
  };
1476
1472
  this.sessions.set(sessionId, session);
1473
+ this.resetSessionTimeout(sessionId);
1477
1474
  log(`[SessionManager] Session registered: ${sessionId} (cwd: ${cwd})`);
1478
1475
  return session;
1479
1476
  }
1480
1477
  /**
1481
- * Get a session by ID and update activity
1478
+ * Get a session by ID and reset timeout
1482
1479
  */
1483
1480
  getSession(sessionId) {
1484
1481
  const session = this.sessions.get(sessionId);
1485
1482
  if (session) {
1486
- session.lastActivity = Date.now();
1483
+ this.resetSessionTimeout(sessionId);
1487
1484
  }
1488
1485
  return session;
1489
1486
  }
1490
1487
  /**
1491
- * Touch session to update activity timestamp (called on every API request)
1488
+ * Touch session to reset timeout (called on every API request)
1492
1489
  */
1493
1490
  touchSession(sessionId) {
1494
- const session = this.sessions.get(sessionId);
1495
- if (session) {
1496
- session.lastActivity = Date.now();
1497
- }
1491
+ this.resetSessionTimeout(sessionId);
1498
1492
  }
1499
1493
  /**
1500
- * Unregister a session (e.g., on cancel/submit)
1494
+ * Unregister a session (e.g., on cancel/submit/timeout)
1501
1495
  */
1502
1496
  async unregisterSession(sessionId) {
1503
1497
  const session = this.sessions.get(sessionId);
1504
1498
  if (session) {
1499
+ if (session.timeoutTimer) {
1500
+ clearTimeout(session.timeoutTimer);
1501
+ }
1505
1502
  await session.watcher.stop();
1506
1503
  this.sessions.delete(sessionId);
1507
1504
  log(`[SessionManager] Session unregistered: ${sessionId}`);
@@ -1564,18 +1561,23 @@ var SessionManager = class {
1564
1561
  changedFiles: /* @__PURE__ */ new Set()
1565
1562
  };
1566
1563
  }
1567
- cleanupTimedOutSessions() {
1568
- const now = Date.now();
1569
- const timedOut = [];
1570
- for (const [sessionId, session] of this.sessions) {
1571
- if (now - session.lastActivity > this.options.sessionTimeoutMs) {
1572
- timedOut.push(sessionId);
1573
- }
1564
+ /**
1565
+ * Reset the timeout timer for a session.
1566
+ * Called on every activity (register, poll, etc.)
1567
+ */
1568
+ resetSessionTimeout(sessionId) {
1569
+ const session = this.sessions.get(sessionId);
1570
+ if (!session)
1571
+ return;
1572
+ if (session.timeoutTimer) {
1573
+ clearTimeout(session.timeoutTimer);
1574
1574
  }
1575
- for (const sessionId of timedOut) {
1575
+ session.timeoutTimer = setTimeout(() => {
1576
1576
  log(`[SessionManager] Session timed out: ${sessionId}`);
1577
- this.unregisterSession(sessionId);
1578
- }
1577
+ this.unregisterSession(sessionId).catch((error) => {
1578
+ log(`[SessionManager] Error during session unregister for ${sessionId}:`, error);
1579
+ });
1580
+ }, this.options.sessionTimeoutMs);
1579
1581
  }
1580
1582
  };
1581
1583
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-squad-cli",
3
- "version": "1.2.17",
3
+ "version": "1.2.19",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "csq": "./dist/index.js"