agentboss 0.1.0 → 0.1.1

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.
@@ -25,7 +25,7 @@
25
25
  } catch (e) {}
26
26
  })();
27
27
  </script>
28
- <script type="module" crossorigin src="/assets/index-DBj1Ujlx.js"></script>
28
+ <script type="module" crossorigin src="/assets/index-CsVml4AS.js"></script>
29
29
  <link rel="stylesheet" crossorigin href="/assets/index-C1wFD_Vo.css">
30
30
  </head>
31
31
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentboss",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "AI Agent collaboration analytics - become your AI agent's boss, not its babysitter",
5
5
  "main": "server/index.js",
6
6
  "bin": {
@@ -40,14 +40,51 @@ function buildDateList(days) {
40
40
  for (let i = 0; i <= days; i++) {
41
41
  const d = new Date(now);
42
42
  d.setDate(d.getDate() - i);
43
- const yyyy = d.getFullYear();
44
- const mm = String(d.getMonth() + 1).padStart(2, '0');
45
- const dd = String(d.getDate()).padStart(2, '0');
46
- dates.push(`${yyyy}-${mm}-${dd}`);
43
+ dates.push(formatDate(d));
47
44
  }
48
45
  return dates; // already most-recent first
49
46
  }
50
47
 
48
+ /**
49
+ * Local-time YYYY-MM-DD for a Date. Must match buildDateList so the
50
+ * "today" string we compute lines up with the date strings we iterate.
51
+ */
52
+ function formatDate(d) {
53
+ const yyyy = d.getFullYear();
54
+ const mm = String(d.getMonth() + 1).padStart(2, '0');
55
+ const dd = String(d.getDate()).padStart(2, '0');
56
+ return `${yyyy}-${mm}-${dd}`;
57
+ }
58
+
59
+ /**
60
+ * Pick the id of the "currently active" session for `date` — defined
61
+ * (per user spec) as the today-bucket session with the largest
62
+ * ended_at. Returns null if `date` isn't today or the bucket is empty.
63
+ * We skip this session in the job so we don't analyze a still-growing
64
+ * conversation; the next job pass will pick it up once it settles.
65
+ *
66
+ * @param {object} db
67
+ * @param {string} date YYYY-MM-DD
68
+ * @param {object[]} sessions candidate session rows for that date
69
+ * @returns {string|null} session_id to skip, or null
70
+ */
71
+ function pickCurrentSessionId(db, date, sessions) {
72
+ const today = formatDate(new Date());
73
+ if (date !== today) return null;
74
+ // Compare against ALL today's sessions (not just unanalyzed) so a
75
+ // fully-analyzed but freshly-touched session still counts as "current"
76
+ // and shields a slightly older still-running session from being
77
+ // wrongly considered the active one.
78
+ const allToday = getSessionsByDate(db, today);
79
+ const pool = allToday.length > 0 ? allToday : sessions;
80
+ let best = null;
81
+ for (const s of pool) {
82
+ if (!s.ended_at) continue;
83
+ if (!best || s.ended_at > best.ended_at) best = s;
84
+ }
85
+ return best ? best.id : null;
86
+ }
87
+
51
88
  // ---------------------------------------------------------------------------
52
89
  // Per-session analyze + persist (shared by the job loop and the
53
90
  // per-session reanalyze endpoint)
@@ -154,13 +191,15 @@ async function runAnalysisJob(db, options = {}) {
154
191
  : buildDateList(days);
155
192
 
156
193
  try {
157
- // Pre-calculate total count for progress reporting
194
+ // Pre-calculate total count for progress reporting. Subtract the
195
+ // "current" (still-running) session if it falls in the candidate set.
158
196
  let totalSessions = 0;
159
197
  for (const date of dates) {
160
198
  const sessions = forceReanalyze
161
199
  ? getSessionsByDate(db, date)
162
200
  : getUnanalyzedSessions(db, date);
163
- totalSessions += sessions.length;
201
+ const skipId = pickCurrentSessionId(db, date, sessions);
202
+ totalSessions += sessions.filter((s) => s.id !== skipId).length;
164
203
  }
165
204
 
166
205
  updateAnalysisState(db, {
@@ -181,10 +220,17 @@ async function runAnalysisJob(db, options = {}) {
181
220
  last_analyzed_at: null,
182
221
  });
183
222
 
184
- // 2a. Get unanalyzed sessions for this date
185
- const sessions = forceReanalyze
223
+ // 2a. Get unanalyzed sessions for this date, minus the currently-
224
+ // active session (today's session with the largest ended_at). We
225
+ // skip it so the job doesn't score a conversation that's still
226
+ // being written to — the next pass will catch it.
227
+ const rawSessions = forceReanalyze
186
228
  ? getSessionsByDate(db, date)
187
229
  : getUnanalyzedSessions(db, date);
230
+ const skipId = pickCurrentSessionId(db, date, rawSessions);
231
+ const sessions = skipId
232
+ ? rawSessions.filter((s) => s.id !== skipId)
233
+ : rawSessions;
188
234
 
189
235
  if (sessions.length === 0) {
190
236
  result.skipped++;