@agentprojectcontext/apx 1.68.0 → 1.69.0

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": "@agentprojectcontext/apx",
3
- "version": "1.68.0",
3
+ "version": "1.69.0",
4
4
  "description": "APX — unified CLI + daemon for the Agent Project Context (APC) standard.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,6 +25,40 @@ import {
25
25
  import { agentToResponse } from "./shared.js";
26
26
  import { normalizeVaultPatch } from "#core/apc/agents-vault.js";
27
27
  import { PERMISSION_MODES } from "#core/constants/permissions.js";
28
+ import { listConversations } from "#core/stores/conversations.js";
29
+ import { listTasks } from "#core/stores/tasks.js";
30
+ import { listRoutines } from "#core/stores/routines.js";
31
+ import { readProjectMessages } from "#core/stores/messages.js";
32
+
33
+ // Attach a per-agent activity summary ({ threads, records, tasks, heartbeats })
34
+ // to a list of agent responses. Reads each store once and tallies by agent, so
35
+ // the whole list costs O(stores) rather than O(agents × stores). Gated behind
36
+ // `?stats=1` on the list endpoint since it touches the message ledger.
37
+ function attachAgentStats(p, agents) {
38
+ const store = p.storagePath || p.path;
39
+ const tally = (rows, key) => {
40
+ const m = Object.create(null);
41
+ for (const r of rows) {
42
+ const a = typeof key === "function" ? key(r) : r?.[key];
43
+ if (a) m[a] = (m[a] || 0) + 1;
44
+ }
45
+ return m;
46
+ };
47
+ let tasksByAgent = {}, hbByAgent = {}, recByAgent = {};
48
+ try { tasksByAgent = tally(listTasks(store, { state: "all" }), "agent"); } catch { /* no task store */ }
49
+ try { hbByAgent = tally(listRoutines(store), (r) => r?.spec?.agent); } catch { /* no routines */ }
50
+ try { recByAgent = tally(readProjectMessages(store, { limit: 1000 }), "agent_slug"); } catch { /* no ledger */ }
51
+ for (const a of agents) {
52
+ let threads = 0;
53
+ try { threads = listConversations(store, a.slug).length; } catch { /* none */ }
54
+ a.stats = {
55
+ threads,
56
+ records: recByAgent[a.slug] || 0,
57
+ tasks: tasksByAgent[a.slug] || 0,
58
+ heartbeats: hbByAgent[a.slug] || 0,
59
+ };
60
+ }
61
+ }
28
62
 
29
63
  // Autonomy mirrors the super-agent permission modes (total/automatico/permiso).
30
64
  // An invalid value is dropped rather than persisted so a typo can't silently
@@ -123,7 +157,9 @@ export function register(app, { projects, project }) {
123
157
  app.get("/projects/:pid/agents", (req, res) => {
124
158
  const p = project(req, res);
125
159
  if (!p) return;
126
- res.json(readAgents(p.path).map(agentToResponse));
160
+ const agents = readAgents(p.path).map(agentToResponse);
161
+ if (req.query.stats === "1") attachAgentStats(p, agents);
162
+ res.json(agents);
127
163
  });
128
164
 
129
165
  app.get("/projects/:pid/agents/:slug", (req, res) => {