sentinelayer-cli 0.36.3 → 0.36.5

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": "sentinelayer-cli",
3
- "version": "0.36.3",
3
+ "version": "0.36.5",
4
4
  "description": "Scaffold Sentinelayer spec/prompt/guide artifacts with secure browser auth and token bootstrap.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -54,7 +54,7 @@
54
54
  "cli-highlight": "2.1.11",
55
55
  "commander": "14.0.1",
56
56
  "ignore": "7.0.5",
57
- "lighthouse": "12.8.2",
57
+ "lighthouse": "12.6.1",
58
58
  "mp4-muxer": "5.2.2",
59
59
  "open": "10.1.2",
60
60
  "picocolors": "1.1.1",
@@ -66,5 +66,13 @@
66
66
  "devDependencies": {
67
67
  "c8": "10.1.3",
68
68
  "license-checker-rseidelsohn": "4.4.2"
69
+ },
70
+ "overrides": {
71
+ "lighthouse": {
72
+ "ws": "7.5.11"
73
+ },
74
+ "puppeteer-core": {
75
+ "ws": "8.21.0"
76
+ }
69
77
  }
70
78
  }
@@ -69,6 +69,7 @@ import {
69
69
  getListenerProcessStatus,
70
70
  removeListenerPidRecord,
71
71
  requestListenerProcessStop,
72
+ summarizeLocalListenerProcesses,
72
73
  stopMatchingListenerProcesses,
73
74
  writeListenerPidRecord,
74
75
  } from "../session/listener-process.js";
@@ -4466,7 +4467,47 @@ export function registerSessionCommand(program) {
4466
4467
  limit,
4467
4468
  maxPages,
4468
4469
  });
4469
- const listeners = Array.isArray(result.listeners) ? result.listeners : [];
4470
+ let listeners = Array.isArray(result.listeners) ? result.listeners : [];
4471
+ let localProcessScan = {
4472
+ ok: false,
4473
+ reason: listeners.length > 0 ? "not_scanned" : "no_listener_rows",
4474
+ processCount: 0,
4475
+ duplicateProcessCount: 0,
4476
+ agents: [],
4477
+ };
4478
+ if (listeners.length > 0) {
4479
+ try {
4480
+ const summary = await summarizeLocalListenerProcesses(
4481
+ normalizedSessionId,
4482
+ listeners.map((row) => row.agentId),
4483
+ );
4484
+ const byAgent = new Map(summary.agents.map((entry) => [entry.agentId, entry]));
4485
+ listeners = listeners.map((row) => {
4486
+ const local = byAgent.get(row.agentId) || {};
4487
+ const pids = Array.isArray(local.pids) ? local.pids : [];
4488
+ return {
4489
+ ...row,
4490
+ localProcessCount: Number(local.processCount || 0),
4491
+ localDuplicateProcessCount: Number(local.duplicateProcessCount || 0),
4492
+ localProcessPids: pids,
4493
+ };
4494
+ });
4495
+ localProcessScan = {
4496
+ ok: true,
4497
+ processCount: Number(summary.processCount || 0),
4498
+ duplicateProcessCount: Number(summary.duplicateProcessCount || 0),
4499
+ agents: summary.agents,
4500
+ };
4501
+ } catch (error) {
4502
+ localProcessScan = {
4503
+ ok: false,
4504
+ reason: normalizeString(error?.message) || "process_scan_failed",
4505
+ processCount: 0,
4506
+ duplicateProcessCount: 0,
4507
+ agents: [],
4508
+ };
4509
+ }
4510
+ }
4470
4511
  const live = listeners.filter((row) => row.status === "active" || row.status === "idle").length;
4471
4512
  const payload = {
4472
4513
  command: "session listeners",
@@ -4480,6 +4521,7 @@ export function registerSessionCommand(program) {
4480
4521
  listenerEventCount: Number(result.listenerEventCount || 0),
4481
4522
  partial: Boolean(result.partial),
4482
4523
  beforeSequence: result.beforeSequence || null,
4524
+ localProcessScan,
4483
4525
  listeners,
4484
4526
  };
4485
4527
  if (shouldEmitJson(options, command)) {
@@ -4501,6 +4543,16 @@ export function registerSessionCommand(program) {
4501
4543
  else if (row.status === "idle") console.log(pc.cyan(` ${line}`));
4502
4544
  else console.log(pc.gray(` ${line}`));
4503
4545
  }
4546
+ const duplicateLocalRows = listeners.filter((row) => Number(row.localDuplicateProcessCount || 0) > 0);
4547
+ if (duplicateLocalRows.length > 0) {
4548
+ const summary = duplicateLocalRows
4549
+ .map((row) => `${row.agentId}:${row.localProcessCount}`)
4550
+ .join(", ");
4551
+ console.log(pc.yellow(`Local process warning: multiple matching listener processes detected (${summary}).`));
4552
+ console.log(pc.gray(
4553
+ `Use "sl session listen --session ${normalizedSessionId} --agent <your-agent> --force --from-now" to replace your own duplicate listener; coordinate before touching another agent.`,
4554
+ ));
4555
+ }
4504
4556
  return payload;
4505
4557
  });
4506
4558
 
@@ -147,6 +147,44 @@ export async function listMatchingListenerProcesses(
147
147
  );
148
148
  }
149
149
 
150
+ export async function summarizeLocalListenerProcesses(
151
+ sessionId,
152
+ agentIds = [],
153
+ {
154
+ excludePid = process.pid,
155
+ _listProcesses = listProcessTable,
156
+ } = {},
157
+ ) {
158
+ const normalizedSessionId = normalizeString(sessionId);
159
+ const uniqueAgentIds = [...new Set((Array.isArray(agentIds) ? agentIds : [])
160
+ .map((agentId) => normalizeString(agentId))
161
+ .filter(Boolean))];
162
+ const rows = normalizeProcessRows(await _listProcesses());
163
+ const excluded = Number(excludePid);
164
+ const candidates = rows.filter((row) => row.pid !== excluded);
165
+ const agents = uniqueAgentIds.map((agentId) => {
166
+ const matches = candidates
167
+ .filter((row) => listenerCommandLineMatches(row.commandLine, {
168
+ sessionId: normalizedSessionId,
169
+ agentId,
170
+ }))
171
+ .sort((a, b) => a.pid - b.pid);
172
+ const pids = matches.map((match) => match.pid);
173
+ return {
174
+ agentId,
175
+ processCount: pids.length,
176
+ duplicateProcessCount: Math.max(0, pids.length - 1),
177
+ pids,
178
+ };
179
+ });
180
+ return {
181
+ sessionId: normalizedSessionId,
182
+ processCount: agents.reduce((sum, agent) => sum + agent.processCount, 0),
183
+ duplicateProcessCount: agents.reduce((sum, agent) => sum + agent.duplicateProcessCount, 0),
184
+ agents,
185
+ };
186
+ }
187
+
150
188
  async function readWindowsCommandLine(pid) {
151
189
  const command = [
152
190
  "$ErrorActionPreference = 'Stop';",
@@ -246,5 +246,13 @@ export function formatListenerLine(row) {
246
246
  : row.status === "stale"
247
247
  ? "◌ stale"
248
248
  : "× stopped";
249
- return `${statusLabel.padEnd(10)} ${row.agentId.padEnd(24)} cadence=${cadence.padEnd(6)} last_seen=${seen}`;
249
+ const localProcessCount = Number(row.localProcessCount || 0);
250
+ const localPids = Array.isArray(row.localProcessPids)
251
+ ? row.localProcessPids.filter((pid) => Number.isInteger(Number(pid)) && Number(pid) > 0)
252
+ : [];
253
+ const local =
254
+ localProcessCount > 1 && localPids.length > 0
255
+ ? ` local_pids=${localPids.join(",")}`
256
+ : "";
257
+ return `${statusLabel.padEnd(10)} ${row.agentId.padEnd(24)} cadence=${cadence.padEnd(6)} last_seen=${seen}${local}`;
250
258
  }