@myagentroam/node 0.11.72 → 0.11.73

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/dist/database.js CHANGED
@@ -392,13 +392,40 @@ export class NodeDatabase {
392
392
  }
393
393
  /** Resolve the complete registered tree, independently of display pagination. */
394
394
  sessionTreeRecords(workspaceId, sessionId) {
395
- const root = this.getSessionRecord(sessionId);
396
- if (root === undefined || root.workspaceId !== workspaceId)
395
+ // UNION bounds corrupt cycles; the in-memory traversal still reports them.
396
+ // Keep the frontier outermost so SQLite uses both columns of the parent index.
397
+ const rows = this.raw
398
+ .prepare(`
399
+ WITH RECURSIVE tree(id) AS (
400
+ SELECT id FROM agent_sessions WHERE workspace_id = ? AND id = ?
401
+ UNION
402
+ SELECT child.id FROM tree CROSS JOIN agent_sessions child ON child.parent_session_id = tree.id
403
+ WHERE child.workspace_id = ?
404
+ )
405
+ SELECT session.id, session.workspace_id, session.runner, session.pin_order,
406
+ session.metadata, session.parent_session_id
407
+ FROM tree CROSS JOIN agent_sessions session ON session.id = tree.id ORDER BY session.id
408
+ `)
409
+ .all(workspaceId, sessionId, workspaceId);
410
+ const children = new Map();
411
+ let root;
412
+ for (const row of rows) {
413
+ const record = sessionRecord(row);
414
+ if (record.id === sessionId)
415
+ root = record;
416
+ const parent = record.metadata.parentSessionId ?? null;
417
+ if (parent === null)
418
+ continue;
419
+ const siblings = children.get(parent) ?? [];
420
+ siblings.push(record);
421
+ children.set(parent, siblings);
422
+ }
423
+ if (root === undefined)
397
424
  throw new Error('SESSION_NOT_FOUND');
398
425
  const records = [root];
399
426
  const seen = new Set([root.id]);
400
427
  for (let index = 0; index < records.length; index++) {
401
- for (const child of this.listChildSessionRecords(workspaceId, records[index].id)) {
428
+ for (const child of children.get(records[index].id) ?? []) {
402
429
  if (seen.has(child.id))
403
430
  throw new Error('SESSION_RELATION_INVALID');
404
431
  seen.add(child.id);
@@ -113,6 +113,15 @@ export class SessionCatalogService {
113
113
  return record === undefined ? [] : [project(record)];
114
114
  });
115
115
  const descendantsByAnchor = new Map();
116
+ const statuses = new Map();
117
+ const status = (id) => {
118
+ const cached = statuses.get(id);
119
+ if (cached !== undefined)
120
+ return cached;
121
+ const value = sessionActivityStatus(this.options.runtime, id);
122
+ statuses.set(id, value);
123
+ return value;
124
+ };
116
125
  const descendants = (anchor) => {
117
126
  let records = descendantsByAnchor.get(anchor);
118
127
  if (records === undefined) {
@@ -128,10 +137,10 @@ export class SessionCatalogService {
128
137
  let sleepingCount = 0;
129
138
  const records = descendants(anchorSessionId);
130
139
  for (const record of records) {
131
- const status = sessionActivityStatus(this.options.runtime, record.id);
132
- if (status === 'RUNNING')
140
+ const activity = status(record.id);
141
+ if (activity === 'RUNNING')
133
142
  runningCount++;
134
- else if (status === 'SLEEPING')
143
+ else if (activity === 'SLEEPING')
135
144
  sleepingCount++;
136
145
  }
137
146
  return [
@@ -147,6 +156,22 @@ export class SessionCatalogService {
147
156
  });
148
157
  const anchor = query.treeAnchor === undefined ? undefined : get(query.treeAnchor);
149
158
  const records = anchor === undefined ? [] : descendants(anchor.id);
159
+ const activePaths = new Set();
160
+ // Records are breadth-first: propagate activity to ancestors in one reverse pass.
161
+ for (let index = records.length - 1; index >= 0; index--) {
162
+ const record = records[index];
163
+ if (status(record.id) !== 'IDLE' || activePaths.has(record.id)) {
164
+ activePaths.add(record.id);
165
+ if (typeof record.metadata.parentSessionId === 'string')
166
+ activePaths.add(record.metadata.parentSessionId);
167
+ }
168
+ }
169
+ // Select active paths before idle filler, not after truncating arbitrary records.
170
+ // Stable breadth-first order keeps selected children connected to their ancestors.
171
+ const prioritized = [
172
+ ...records.filter((record) => activePaths.has(record.id)),
173
+ ...records.filter((record) => !activePaths.has(record.id))
174
+ ];
150
175
  const parent = anchor?.metadata.parentSessionId
151
176
  ? get(anchor.metadata.parentSessionId)
152
177
  : undefined;
@@ -155,7 +180,7 @@ export class SessionCatalogService {
155
180
  : {
156
181
  anchorSessionId: anchor.id,
157
182
  parent: parent === undefined ? null : project(parent),
158
- nodes: records.slice(0, query.limit).map(project),
183
+ nodes: prioritized.slice(0, query.limit).map(project),
159
184
  truncated: records.length > query.limit
160
185
  };
161
186
  return { sessions, summaries, tree, missingSessionIds };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/node",
3
- "version": "0.11.72",
3
+ "version": "0.11.73",
4
4
  "description": "MyAgentRoam Node runtime CLI.",
5
5
  "license": "Apache-2.0 AND GPL-2.0-or-later",
6
6
  "type": "module",
@@ -40,9 +40,9 @@
40
40
  "turndown-plugin-gfm": "^1.0.2",
41
41
  "ws": "^8.21.3",
42
42
  "zod": "4.4.3",
43
- "@myagentroam/agent": "0.11.72",
43
+ "@myagentroam/agent": "0.11.73",
44
44
  "@myagentroam/code-navigation": "0.11.1",
45
- "@myagentroam/protocol": "0.11.72",
45
+ "@myagentroam/protocol": "0.11.73",
46
46
  "@myagentroam/marctl": "0.11.12"
47
47
  },
48
48
  "devDependencies": {