@openscout/scout 0.2.48 → 0.2.49

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.
@@ -14109,12 +14109,38 @@ function compact(p) {
14109
14109
  return null;
14110
14110
  return p.startsWith(HOME) ? `~${p.slice(HOME.length)}` : p;
14111
14111
  }
14112
+ var LATEST_AGENT_ENDPOINT_JOIN = `LEFT JOIN agent_endpoints ep ON ep.id = (
14113
+ SELECT ep2.id
14114
+ FROM agent_endpoints ep2
14115
+ WHERE ep2.agent_id = a.id
14116
+ ORDER BY ep2.updated_at DESC
14117
+ LIMIT 1
14118
+ )`;
14119
+ function queryExecutingAgentIds() {
14120
+ return new Set(db().prepare(`SELECT DISTINCT target_agent_id FROM flights
14121
+ WHERE state = 'running'`).all().map((row) => row.target_agent_id));
14122
+ }
14123
+ function summarizeAgentState(rawState, isWorking) {
14124
+ if (isWorking) {
14125
+ return "working";
14126
+ }
14127
+ return rawState && rawState !== "offline" ? "available" : "offline";
14128
+ }
14129
+ function summarizeAgentStatusLabel(rawState, isWorking) {
14130
+ switch (summarizeAgentState(rawState, isWorking)) {
14131
+ case "working":
14132
+ return "Working";
14133
+ case "available":
14134
+ return "Available";
14135
+ default:
14136
+ return "Offline";
14137
+ }
14138
+ }
14112
14139
  function conversationIdForAgent(agentId) {
14113
14140
  return `dm.operator.${agentId}`;
14114
14141
  }
14115
14142
  function queryMobileAgents(limit = 50) {
14116
- const workingAgentIds = new Set(db().prepare(`SELECT DISTINCT target_agent_id FROM flights
14117
- WHERE state NOT IN ('completed','failed','cancelled')`).all().map((r) => r.target_agent_id));
14143
+ const executingAgentIds = queryExecutingAgentIds();
14118
14144
  const lastMessageAt = new Map(db().prepare(`SELECT actor_id, MAX(created_at) AS last_at FROM messages GROUP BY actor_id`).all().map((r) => [r.actor_id, r.last_at]));
14119
14145
  const rows = db().prepare(`SELECT
14120
14146
  a.id,
@@ -14129,17 +14155,17 @@ function queryMobileAgents(limit = 50) {
14129
14155
  ep.updated_at
14130
14156
  FROM agents a
14131
14157
  JOIN actors ac ON ac.id = a.id
14132
- LEFT JOIN agent_endpoints ep ON ep.agent_id = a.id
14133
- ORDER BY ep.updated_at DESC NULLS LAST
14158
+ ${LATEST_AGENT_ENDPOINT_JOIN}
14159
+ ORDER BY COALESCE(ep.updated_at, 0) DESC, ac.display_name ASC
14134
14160
  LIMIT ?`).all(limit);
14135
14161
  return rows.map((r) => {
14136
14162
  let meta = {};
14137
14163
  try {
14138
14164
  meta = r.metadata_json ? JSON.parse(r.metadata_json) : {};
14139
14165
  } catch {}
14140
- const isWorking = workingAgentIds.has(r.id);
14141
- const state = isWorking ? "working" : r.state && r.state !== "offline" ? "available" : "offline";
14142
- const statusLabel = isWorking ? "Working" : r.state === "active" ? "Available" : r.state ?? "Offline";
14166
+ const isWorking = executingAgentIds.has(r.id);
14167
+ const state = summarizeAgentState(r.state, isWorking);
14168
+ const statusLabel = summarizeAgentStatusLabel(r.state, isWorking);
14143
14169
  return {
14144
14170
  id: r.id,
14145
14171
  title: r.display_name,
@@ -14149,7 +14175,7 @@ function queryMobileAgents(limit = 50) {
14149
14175
  harness: r.harness,
14150
14176
  transport: r.transport,
14151
14177
  state,
14152
- statusLabel: statusLabel.charAt(0).toUpperCase() + statusLabel.slice(1),
14178
+ statusLabel,
14153
14179
  sessionId: conversationIdForAgent(r.id),
14154
14180
  lastActiveAt: lastMessageAt.get(r.id) ?? null
14155
14181
  };
@@ -14271,7 +14297,7 @@ function queryMobileAgentDetail(agentId) {
14271
14297
  ep.updated_at
14272
14298
  FROM agents a
14273
14299
  JOIN actors ac ON ac.id = a.id
14274
- LEFT JOIN agent_endpoints ep ON ep.agent_id = a.id
14300
+ ${LATEST_AGENT_ENDPOINT_JOIN}
14275
14301
  WHERE a.id = ?`).get(agentId);
14276
14302
  if (!row)
14277
14303
  return null;
@@ -14283,8 +14309,7 @@ function queryMobileAgentDetail(agentId) {
14283
14309
  try {
14284
14310
  capabilities = row.capabilities_json ? JSON.parse(row.capabilities_json) : [];
14285
14311
  } catch {}
14286
- const workingAgentIds = new Set(db().prepare(`SELECT DISTINCT target_agent_id FROM flights
14287
- WHERE state NOT IN ('completed','failed','cancelled')`).all().map((r) => r.target_agent_id));
14312
+ const executingAgentIds = queryExecutingAgentIds();
14288
14313
  const activeFlights = db().prepare(`SELECT id, state, summary, started_at
14289
14314
  FROM flights
14290
14315
  WHERE target_agent_id = ? AND state NOT IN ('completed','failed','cancelled')
@@ -14308,9 +14333,9 @@ function queryMobileAgentDetail(agentId) {
14308
14333
  const msgRow = db().prepare(`SELECT COUNT(*) AS cnt FROM messages WHERE conversation_id = ?`).get(conversationIdForAgent(agentId));
14309
14334
  const messageCount = msgRow?.cnt ?? 0;
14310
14335
  const lastMessageAt = db().prepare(`SELECT MAX(created_at) AS last_at FROM messages WHERE actor_id = ?`).get(agentId)?.last_at ?? null;
14311
- const isWorking = workingAgentIds.has(row.id);
14312
- const state = isWorking ? "working" : row.state && row.state !== "offline" ? "available" : "offline";
14313
- const statusLabel = isWorking ? "Working" : row.state === "active" ? "Available" : row.state ?? "Offline";
14336
+ const isWorking = executingAgentIds.has(row.id);
14337
+ const state = summarizeAgentState(row.state, isWorking);
14338
+ const statusLabel = summarizeAgentStatusLabel(row.state, isWorking);
14314
14339
  return {
14315
14340
  id: row.id,
14316
14341
  title: row.display_name,
@@ -14320,7 +14345,7 @@ function queryMobileAgentDetail(agentId) {
14320
14345
  harness: row.harness,
14321
14346
  transport: row.transport,
14322
14347
  state,
14323
- statusLabel: statusLabel.charAt(0).toUpperCase() + statusLabel.slice(1),
14348
+ statusLabel,
14324
14349
  sessionId: conversationIdForAgent(row.id),
14325
14350
  lastActiveAt: lastMessageAt,
14326
14351
  cwd: compact(row.cwd),
@@ -14429,7 +14454,7 @@ function endpointForAgent(snapshot, agentId) {
14429
14454
  function buildMobileAgentSummary(snapshot, agent) {
14430
14455
  const endpoint = endpointForAgent(snapshot, agent.id);
14431
14456
  const flights = Object.values(snapshot.flights).filter((flight) => flight.targetAgentId === agent.id);
14432
- const hasWorkingFlight = flights.some((flight) => !["completed", "failed", "cancelled"].includes(flight.state));
14457
+ const hasWorkingFlight = flights.some((flight) => flight.state === "running");
14433
14458
  const lastAuthoredMessageAt = Object.values(snapshot.messages).filter((message) => message.actorId === agent.id).reduce((latest, message) => {
14434
14459
  const createdAt = normalizeTimestamp(message.createdAt);
14435
14460
  return typeof createdAt === "number" && (!latest || createdAt > latest) ? createdAt : latest;
@@ -14444,7 +14469,7 @@ function buildMobileAgentSummary(snapshot, agent) {
14444
14469
  harness: endpoint?.harness ?? null,
14445
14470
  transport: endpoint?.transport ?? null,
14446
14471
  state,
14447
- statusLabel: hasWorkingFlight ? "Working" : endpoint?.state === "active" ? "Available" : endpoint?.state ?? "Offline",
14472
+ statusLabel: state === "working" ? "Working" : state === "available" ? "Available" : "Offline",
14448
14473
  sessionId: endpoint?.sessionId ?? null,
14449
14474
  lastActiveAt: lastAuthoredMessageAt
14450
14475
  };
@@ -13863,6 +13863,32 @@ function coerceNumber(value) {
13863
13863
  }
13864
13864
  return null;
13865
13865
  }
13866
+ function isExecutingFlightState(state2) {
13867
+ return state2 === "running";
13868
+ }
13869
+ var LATEST_AGENT_ENDPOINT_JOIN = `LEFT JOIN agent_endpoints ep ON ep.id = (
13870
+ SELECT ep2.id
13871
+ FROM agent_endpoints ep2
13872
+ WHERE ep2.agent_id = a.id
13873
+ ORDER BY ep2.updated_at DESC
13874
+ LIMIT 1
13875
+ )`;
13876
+ function queryExecutingAgentIds() {
13877
+ return new Set(db().prepare(`SELECT DISTINCT target_agent_id FROM flights
13878
+ WHERE state = 'running'`).all().map((row) => row.target_agent_id));
13879
+ }
13880
+ function summarizeAgentState(rawState, isWorking) {
13881
+ if (isWorking) {
13882
+ return "working";
13883
+ }
13884
+ return rawState && rawState !== "offline" ? "available" : "offline";
13885
+ }
13886
+ function isDuplicateActivityFeedItem(previous, next) {
13887
+ if (!previous) {
13888
+ return false;
13889
+ }
13890
+ return previous.kind === next.kind && previous.title === next.title && previous.summary === next.summary && previous.conversationId === next.conversationId && Math.abs(previous.ts - next.ts) <= 5000;
13891
+ }
13866
13892
  function workPhaseFromFlightState(state2) {
13867
13893
  switch (state2) {
13868
13894
  case "queued":
@@ -13953,6 +13979,7 @@ function projectWorkItemRow(row) {
13953
13979
  };
13954
13980
  }
13955
13981
  function queryAgents(limit = 50) {
13982
+ const executingAgentIds = queryExecutingAgentIds();
13956
13983
  const rows = db().prepare(`SELECT
13957
13984
  a.id,
13958
13985
  ac.display_name AS name,
@@ -13970,9 +13997,9 @@ function queryAgents(limit = 50) {
13970
13997
  ep.updated_at
13971
13998
  FROM agents a
13972
13999
  JOIN actors ac ON ac.id = a.id
13973
- LEFT JOIN agent_endpoints ep ON ep.agent_id = a.id
14000
+ ${LATEST_AGENT_ENDPOINT_JOIN}
13974
14001
  WHERE COALESCE(json_extract(a.metadata_json, '$.retiredFromFleet'), 0) != 1
13975
- ORDER BY ep.updated_at DESC NULLS LAST
14002
+ ORDER BY COALESCE(ep.updated_at, 0) DESC, ac.display_name ASC
13976
14003
  LIMIT ?`).all(limit);
13977
14004
  return rows.map((r) => {
13978
14005
  let capabilities = [];
@@ -13989,7 +14016,7 @@ function queryAgents(limit = 50) {
13989
14016
  handle: r.handle,
13990
14017
  agentClass: r.agent_class,
13991
14018
  harness: r.harness,
13992
- state: r.state,
14019
+ state: summarizeAgentState(r.state, executingAgentIds.has(r.id)),
13993
14020
  projectRoot: compact(r.project_root),
13994
14021
  cwd: compact(r.cwd),
13995
14022
  updatedAt: r.updated_at,
@@ -14015,9 +14042,14 @@ function queryActivity(limit = 60) {
14015
14042
  ai.workspace_root
14016
14043
  FROM activity_items ai
14017
14044
  LEFT JOIN actors ac ON ac.id = ai.actor_id
14045
+ WHERE ai.kind != 'ask_replied'
14046
+ AND NOT (
14047
+ ai.kind = 'flight_updated'
14048
+ AND COALESCE(ai.summary, '') LIKE 'Stale running flight reconciled:%'
14049
+ )
14018
14050
  ORDER BY ai.ts DESC
14019
14051
  LIMIT ?`).all(limit);
14020
- return rows.map((r) => ({
14052
+ const items = rows.map((r) => ({
14021
14053
  id: r.id,
14022
14054
  kind: r.kind,
14023
14055
  ts: r.ts,
@@ -14027,6 +14059,7 @@ function queryActivity(limit = 60) {
14027
14059
  conversationId: r.conversation_id,
14028
14060
  workspaceRoot: compact(r.workspace_root)
14029
14061
  }));
14062
+ return items.filter((item, index) => !isDuplicateActivityFeedItem(items[index - 1] ?? null, item));
14030
14063
  }
14031
14064
  function queryRecentMessages(limit = 80) {
14032
14065
  const rows = db().prepare(`SELECT
@@ -14175,6 +14208,7 @@ function queryFleetObservable(agentRow) {
14175
14208
  });
14176
14209
  const flightRows = queryFleetFlightRows(agentRow.id);
14177
14210
  const latestFlight = flightRows[0] ?? null;
14211
+ const isWorking = activeFlights.some((flight) => isExecutingFlightState(flight.state));
14178
14212
  const workStats = db().prepare(`SELECT
14179
14213
  COUNT(*) AS active_work_count,
14180
14214
  MAX(CASE WHEN state IN ('waiting','review') OR acceptance_state = 'pending' THEN 1 ELSE 0 END) AS attention_work_count,
@@ -14222,7 +14256,7 @@ function queryFleetObservable(agentRow) {
14222
14256
  role,
14223
14257
  harness: agentRow.harness,
14224
14258
  transport: agentRow.transport,
14225
- state: agentRow.state,
14259
+ state: summarizeAgentState(agentRow.state, isWorking),
14226
14260
  attention,
14227
14261
  conversationId,
14228
14262
  sessionId: agentRow.session_id,
@@ -19390,6 +19390,15 @@ function coerceNumber(value) {
19390
19390
  }
19391
19391
  return null;
19392
19392
  }
19393
+ function isExecutingFlightState(state4) {
19394
+ return state4 === "running";
19395
+ }
19396
+ function summarizeAgentState(rawState, isWorking) {
19397
+ if (isWorking) {
19398
+ return "working";
19399
+ }
19400
+ return rawState && rawState !== "offline" ? "available" : "offline";
19401
+ }
19393
19402
  function parseFleetCapabilities(value) {
19394
19403
  if (!value)
19395
19404
  return [];
@@ -19516,6 +19525,7 @@ function queryFleetObservable(agentRow) {
19516
19525
  });
19517
19526
  const flightRows = queryFleetFlightRows(agentRow.id);
19518
19527
  const latestFlight = flightRows[0] ?? null;
19528
+ const isWorking = activeFlights.some((flight) => isExecutingFlightState(flight.state));
19519
19529
  const workStats = db().prepare(`SELECT
19520
19530
  COUNT(*) AS active_work_count,
19521
19531
  MAX(CASE WHEN state IN ('waiting','review') OR acceptance_state = 'pending' THEN 1 ELSE 0 END) AS attention_work_count,
@@ -19563,7 +19573,7 @@ function queryFleetObservable(agentRow) {
19563
19573
  role,
19564
19574
  harness: agentRow.harness,
19565
19575
  transport: agentRow.transport,
19566
- state: agentRow.state,
19576
+ state: summarizeAgentState(agentRow.state, isWorking),
19567
19577
  attention,
19568
19578
  conversationId,
19569
19579
  sessionId: agentRow.session_id,
@@ -19803,7 +19813,7 @@ function endpointForAgent(snapshot, agentId) {
19803
19813
  function buildMobileAgentSummary(snapshot, agent) {
19804
19814
  const endpoint = endpointForAgent(snapshot, agent.id);
19805
19815
  const flights = Object.values(snapshot.flights).filter((flight) => flight.targetAgentId === agent.id);
19806
- const hasWorkingFlight = flights.some((flight) => !["completed", "failed", "cancelled"].includes(flight.state));
19816
+ const hasWorkingFlight = flights.some((flight) => flight.state === "running");
19807
19817
  const lastAuthoredMessageAt = Object.values(snapshot.messages).filter((message) => message.actorId === agent.id).reduce((latest, message) => {
19808
19818
  const createdAt = normalizeTimestamp5(message.createdAt);
19809
19819
  return typeof createdAt === "number" && (!latest || createdAt > latest) ? createdAt : latest;
@@ -19818,7 +19828,7 @@ function buildMobileAgentSummary(snapshot, agent) {
19818
19828
  harness: endpoint?.harness ?? null,
19819
19829
  transport: endpoint?.transport ?? null,
19820
19830
  state: state4,
19821
- statusLabel: hasWorkingFlight ? "Working" : endpoint?.state === "active" ? "Available" : endpoint?.state ?? "Offline",
19831
+ statusLabel: state4 === "working" ? "Working" : state4 === "available" ? "Available" : "Offline",
19822
19832
  sessionId: endpoint?.sessionId ?? null,
19823
19833
  lastActiveAt: lastAuthoredMessageAt
19824
19834
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openscout/scout",
3
- "version": "0.2.48",
3
+ "version": "0.2.49",
4
4
  "description": "Published Scout package that installs the `scout` command",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -23,6 +23,6 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
- "@openscout/runtime": "0.2.48"
26
+ "@openscout/runtime": "0.2.49"
27
27
  }
28
28
  }