@sechroom/cli 2026.7.6 → 2026.7.8

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 +89 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1544,12 +1544,16 @@ function registerChannel(program2) {
1544
1544
  const cfg = resolveConfig(cmd.optsWithGlobals());
1545
1545
  const filter = readFilter(opts);
1546
1546
  const sub = await ensureSubscription(cfg, opts.name, filter);
1547
- const conn = await openConnection(cfg, (payload) => {
1548
- if (!shouldDeliver(payload, filter)) return;
1549
- process.stdout.write(
1547
+ const seen = /* @__PURE__ */ new Set();
1548
+ const deliver = makeDeliver(
1549
+ filter,
1550
+ seen,
1551
+ (payload) => process.stdout.write(
1550
1552
  (typeof payload === "string" ? payload : JSON.stringify(payload)) + "\n"
1551
- );
1552
- });
1553
+ )
1554
+ );
1555
+ const conn = await openConnection(cfg, deliver);
1556
+ await reconcile(cfg, filter, deliver);
1553
1557
  if (json) {
1554
1558
  emit(
1555
1559
  {
@@ -1586,8 +1590,8 @@ function registerChannel(program2) {
1586
1590
  );
1587
1591
  await mcp.connect(new StdioServerTransport());
1588
1592
  await ensureSubscription(cfg, opts.name, filter);
1589
- const conn = await openConnection(cfg, (payload) => {
1590
- if (!shouldDeliver(payload, filter)) return;
1593
+ const seen = /* @__PURE__ */ new Set();
1594
+ const deliver = makeDeliver(filter, seen, (payload) => {
1591
1595
  const { content, meta } = summarizeEvent(payload);
1592
1596
  void mcp.notification({
1593
1597
  method: "notifications/claude/channel",
@@ -1597,6 +1601,8 @@ function registerChannel(program2) {
1597
1601
  `))
1598
1602
  );
1599
1603
  });
1604
+ const conn = await openConnection(cfg, deliver);
1605
+ await reconcile(cfg, filter, deliver);
1600
1606
  process.stderr.write(
1601
1607
  style.dim(
1602
1608
  `sechroom channel (mcp) \u2014 tenant ${cfg.tenant}, tags [${filter.tags.join(", ")}]
@@ -1760,6 +1766,82 @@ function shouldDeliver(payload, filter) {
1760
1766
  }
1761
1767
  return true;
1762
1768
  }
1769
+ function makeDeliver(filter, seen, forward) {
1770
+ return (payload) => {
1771
+ if (!shouldDeliver(payload, filter)) return;
1772
+ const { memoryId } = parseEvent(payload);
1773
+ if (memoryId) {
1774
+ if (seen.has(memoryId)) return;
1775
+ seen.add(memoryId);
1776
+ }
1777
+ forward(payload);
1778
+ };
1779
+ }
1780
+ async function reconcile(cfg, filter, deliver) {
1781
+ if (filter.workspaceScope.length === 0) {
1782
+ process.stderr.write(
1783
+ style.dim(
1784
+ "channel: no --workspace to reconcile against; live feed only (a dropped dispatch won't be recovered).\n"
1785
+ )
1786
+ );
1787
+ return;
1788
+ }
1789
+ if (filter.tags.length === 0) return;
1790
+ let token;
1791
+ try {
1792
+ token = await requireToken(cfg);
1793
+ } catch {
1794
+ return;
1795
+ }
1796
+ const qs = `filterTags=${encodeURIComponent(filter.tags.join(","))}&limit=100`;
1797
+ let recovered = 0;
1798
+ for (const ws of filter.workspaceScope) {
1799
+ try {
1800
+ const resp = await fetch(
1801
+ `${cfg.baseUrl}/workspaces/${encodeURIComponent(ws)}/memories/feed?${qs}`,
1802
+ {
1803
+ headers: {
1804
+ authorization: `Bearer ${token}`,
1805
+ tenant: cfg.tenant,
1806
+ "x-sechroom-surface": "cli"
1807
+ }
1808
+ }
1809
+ );
1810
+ if (!resp.ok) {
1811
+ process.stderr.write(
1812
+ err(
1813
+ `channel: reconcile query for ${ws} failed (HTTP ${resp.status})
1814
+ `
1815
+ )
1816
+ );
1817
+ continue;
1818
+ }
1819
+ const data = await resp.json();
1820
+ for (const m of data.results ?? []) {
1821
+ if (!m.id) continue;
1822
+ deliver({
1823
+ eventType: "reconcile",
1824
+ memoryId: m.id,
1825
+ workspaceId: ws,
1826
+ tags: m.tags ?? []
1827
+ });
1828
+ recovered++;
1829
+ }
1830
+ } catch (e) {
1831
+ process.stderr.write(
1832
+ err(`channel: reconcile error for ${ws}: ${String(e)}
1833
+ `)
1834
+ );
1835
+ }
1836
+ }
1837
+ if (recovered > 0)
1838
+ process.stderr.write(
1839
+ style.dim(
1840
+ `channel: reconciled ${recovered} already-queued event(s) on connect.
1841
+ `
1842
+ )
1843
+ );
1844
+ }
1763
1845
  function facetedTagMatch(eventTags, filterTags) {
1764
1846
  const have = new Set(eventTags);
1765
1847
  const groups = /* @__PURE__ */ new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sechroom/cli",
3
- "version": "2026.7.6",
3
+ "version": "2026.7.8",
4
4
  "description": "Sechroom CLI — a thin, generated client over the Sechroom HTTP API. An agent/human surface alongside MCP.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",