@sechroom/cli 2026.8.1 → 2026.8.3-rc.fc3795ae7

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.
Files changed (2) hide show
  1. package/dist/index.js +114 -52
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -8975,7 +8975,7 @@ function herdrRequest(socketPath, method, params, timeoutMs = 1e4) {
8975
8975
  });
8976
8976
  }
8977
8977
  function herdrStream(socketPath, subscriptions, onEvent, options = {}) {
8978
- const { signal, onWarning, subscribeTimeoutMs = 1e4 } = options;
8978
+ const { signal, onWarning, onReady, subscribeTimeoutMs = 1e4 } = options;
8979
8979
  return new Promise((resolvePromise, rejectPromise) => {
8980
8980
  if (signal?.aborted) {
8981
8981
  resolvePromise();
@@ -9017,6 +9017,7 @@ function herdrStream(socketPath, subscriptions, onEvent, options = {}) {
9017
9017
  if (!acked) {
9018
9018
  acked = true;
9019
9019
  clearTimeout(ackTimer);
9020
+ onReady?.();
9020
9021
  }
9021
9022
  const classified = classifyStreamLine(line, id);
9022
9023
  if (classified.kind === "ack") continue;
@@ -9191,9 +9192,12 @@ function indexAgents(agents) {
9191
9192
  return new Map(agents.map((agent) => [agent.pane_id, agent]));
9192
9193
  }
9193
9194
  function buildWatchSubscriptions(agents) {
9194
- return agents.flatMap((agent) => [
9195
- { type: "pane.agent_status_changed", pane_id: agent.pane_id },
9196
- { type: "pane.exited", pane_id: agent.pane_id }
9195
+ return buildPaneSubscriptions(agents.map((agent) => agent.pane_id));
9196
+ }
9197
+ function buildPaneSubscriptions(paneIds) {
9198
+ return [...new Set(paneIds)].flatMap((pane_id) => [
9199
+ { type: "pane.agent_status_changed", pane_id },
9200
+ { type: "pane.exited", pane_id }
9197
9201
  ]);
9198
9202
  }
9199
9203
  function normalizeWatchEvent(raw) {
@@ -9385,6 +9389,7 @@ async function runWait(ports, targets, options) {
9385
9389
  const remaining = new Set(targetIds);
9386
9390
  let seed = /* @__PURE__ */ new Map();
9387
9391
  let attempt = 0;
9392
+ const subscriptions = buildPaneSubscriptions(targetIds);
9388
9393
  const settle = (agent, paneId, status) => {
9389
9394
  if (!remaining.has(paneId)) return;
9390
9395
  const record = {
@@ -9403,67 +9408,124 @@ async function runWait(ports, targets, options) {
9403
9408
  try {
9404
9409
  while (!controller.signal.aborted) {
9405
9410
  try {
9406
- const listed = await raceAbort(
9407
- ports.request("agent.list", {})
9408
- );
9409
- if (listed === aborted) break;
9410
- const current = listed.agents ?? [];
9411
- const fresh = indexAgents(current);
9412
- for (const paneId of [...remaining]) {
9413
- const currentAgent = fresh.get(paneId);
9414
- if (currentAgent === void 0) {
9415
- settle(seed.get(paneId), paneId, "exited");
9416
- continue;
9417
- }
9418
- const status = currentAgent.agent_status?.trim().toLowerCase();
9419
- if (status !== void 0 && statuses.has(status)) {
9420
- settle(currentAgent, paneId, currentAgent.agent_status ?? status);
9421
- }
9422
- }
9423
- seed = fresh;
9424
- if (completed || remaining.size === 0) return;
9425
- const subscriptions = buildWatchSubscriptions(
9426
- current.filter((agent) => remaining.has(agent.pane_id))
9427
- );
9428
9411
  let carriedTraffic = false;
9429
9412
  let relistNeeded = false;
9413
+ let reconciled = false;
9414
+ const bufferedEvents = [];
9430
9415
  const startedAt = now();
9431
9416
  const cycle = new AbortController();
9432
9417
  const stopCycle = () => cycle.abort();
9433
9418
  controller.signal.addEventListener("abort", stopCycle, { once: true });
9419
+ let streamReady = false;
9420
+ let streamFailed = false;
9421
+ let streamFailure;
9422
+ let resolveReady;
9423
+ let rejectReady;
9424
+ const ready = new Promise((resolve9, reject) => {
9425
+ resolveReady = resolve9;
9426
+ rejectReady = reject;
9427
+ });
9428
+ const handleEvent = (event) => {
9429
+ if (!remaining.has(event.paneId)) return;
9430
+ const known = seed.get(event.paneId);
9431
+ if (event.type === "pane.exited") {
9432
+ settle(known, event.paneId, "exited");
9433
+ return;
9434
+ }
9435
+ const status = event.to?.trim().toLowerCase();
9436
+ if (known && event.to) known.agent_status = event.to;
9437
+ if (status !== void 0 && statuses.has(status)) {
9438
+ settle(known, event.paneId, event.to ?? status);
9439
+ }
9440
+ };
9441
+ let streamFinished;
9434
9442
  try {
9435
- const streamed = await raceAbort(
9436
- ports.stream(
9437
- subscriptions,
9438
- (raw) => {
9439
- carriedTraffic = true;
9440
- const event = normalizeWatchEvent(raw);
9441
- if (event === null || needsRelistFallback(event)) {
9442
- relistNeeded = true;
9443
- cycle.abort();
9444
- return;
9445
- }
9446
- if (!remaining.has(event.paneId)) return;
9447
- const known = seed.get(event.paneId);
9448
- if (event.type === "pane.exited") {
9449
- settle(known, event.paneId, "exited");
9450
- return;
9451
- }
9452
- const status = event.to?.trim().toLowerCase();
9453
- if (known && event.to) known.agent_status = event.to;
9454
- if (status !== void 0 && statuses.has(status)) {
9455
- settle(known, event.paneId, event.to ?? status);
9456
- }
9443
+ const stream = ports.stream(
9444
+ subscriptions,
9445
+ (raw) => {
9446
+ carriedTraffic = true;
9447
+ if (!streamReady) {
9448
+ streamReady = true;
9449
+ resolveReady();
9450
+ }
9451
+ const event = normalizeWatchEvent(raw);
9452
+ if (event === null || needsRelistFallback(event)) {
9453
+ relistNeeded = true;
9454
+ cycle.abort();
9455
+ return;
9456
+ }
9457
+ if (!reconciled) {
9458
+ bufferedEvents.push(event);
9459
+ return;
9460
+ }
9461
+ handleEvent(event);
9462
+ },
9463
+ {
9464
+ signal: cycle.signal,
9465
+ onReady: () => {
9466
+ streamReady = true;
9467
+ resolveReady();
9457
9468
  },
9458
- {
9459
- signal: cycle.signal,
9460
- onWarning: (message) => warn2(`herdr wait: ${message}`)
9469
+ onWarning: (message) => warn2(`herdr wait: ${message}`)
9470
+ }
9471
+ );
9472
+ streamFinished = stream.then(
9473
+ () => {
9474
+ if (!streamReady) {
9475
+ rejectReady(
9476
+ new Error("Herdr subscription closed before it was ready")
9477
+ );
9461
9478
  }
9462
- )
9479
+ },
9480
+ (error) => {
9481
+ streamFailed = true;
9482
+ streamFailure = error;
9483
+ if (!streamReady) rejectReady(error);
9484
+ }
9463
9485
  );
9486
+ } catch (error) {
9487
+ streamFailed = true;
9488
+ streamFailure = error;
9489
+ rejectReady(error);
9490
+ streamFinished = Promise.resolve();
9491
+ }
9492
+ try {
9493
+ const readyResult = await raceAbort(ready);
9494
+ if (readyResult === aborted) break;
9495
+ const listed = await raceAbort(
9496
+ ports.request("agent.list", {})
9497
+ );
9498
+ if (listed === aborted) break;
9499
+ const current = listed.agents ?? [];
9500
+ const fresh = indexAgents(current);
9501
+ for (const paneId of [...remaining]) {
9502
+ const currentAgent = fresh.get(paneId);
9503
+ if (currentAgent === void 0) {
9504
+ settle(seed.get(paneId), paneId, "exited");
9505
+ }
9506
+ }
9507
+ seed = fresh;
9508
+ reconciled = true;
9509
+ for (const paneId of [...remaining]) {
9510
+ const currentAgent = fresh.get(paneId);
9511
+ if (currentAgent === void 0) continue;
9512
+ for (const event of bufferedEvents) {
9513
+ if (event.paneId === paneId) handleEvent(event);
9514
+ }
9515
+ if (!remaining.has(paneId)) continue;
9516
+ const status = currentAgent.agent_status?.trim().toLowerCase();
9517
+ if (status !== void 0 && statuses.has(status)) {
9518
+ settle(currentAgent, paneId, currentAgent.agent_status ?? status);
9519
+ }
9520
+ }
9521
+ if (completed || remaining.size === 0) return;
9522
+ if (relistNeeded) continue;
9523
+ const streamed = await raceAbort(streamFinished);
9464
9524
  if (streamed === aborted) break;
9525
+ if (streamFailed) throw streamFailure;
9465
9526
  } finally {
9466
9527
  controller.signal.removeEventListener("abort", stopCycle);
9528
+ cycle.abort();
9467
9529
  }
9468
9530
  if (completed) return;
9469
9531
  if (relistNeeded) continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sechroom/cli",
3
- "version": "2026.8.1",
3
+ "version": "2026.8.3-rc.fc3795ae7",
4
4
  "description": "Command-line interface for Sechroom — sign in, wire your AI tools, and work with your sechroom from the terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",