@fdcn/sourcefed 0.2.1 → 0.2.3

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 (38) hide show
  1. package/README.md +2 -2
  2. package/dist/chunk-7KHZCWGQ.js +5174 -0
  3. package/dist/chunk-EVSHVYPF.js +5167 -0
  4. package/dist/chunk-UOTCX4ME.js +3963 -0
  5. package/dist/cli.js +494 -362
  6. package/dist/core.js +5 -0
  7. package/dist/daemon.js +20 -1
  8. package/dist/data/core/SKILL.md +10 -0
  9. package/dist/data/core/references/commands.md +1 -0
  10. package/dist/mcp.js +1 -1
  11. package/dist/opencode.js +1 -1
  12. package/dist/pi.js +22 -3
  13. package/dist/tui-compiled.mjs +146 -101
  14. package/dist.dts/packages/cli/src/commands/daemon.d.ts +1 -0
  15. package/dist.dts/packages/cli/src/commands/mcp.d.ts +1 -0
  16. package/dist.dts/packages/cli/src/commands/monitor/ack.d.ts +2 -0
  17. package/dist.dts/packages/cli/src/commands/monitor/create.d.ts +2 -0
  18. package/dist.dts/packages/cli/src/commands/monitor/events.d.ts +2 -0
  19. package/dist.dts/packages/cli/src/commands/monitor/follow.d.ts +2 -0
  20. package/dist.dts/packages/cli/src/commands/monitor/index.d.ts +10 -0
  21. package/dist.dts/packages/cli/src/commands/monitor/list.d.ts +2 -0
  22. package/dist.dts/packages/cli/src/commands/monitor/logs.d.ts +2 -0
  23. package/dist.dts/packages/cli/src/commands/monitor/remove.d.ts +2 -0
  24. package/dist.dts/packages/cli/src/commands/monitor/sources.d.ts +2 -0
  25. package/dist.dts/packages/cli/src/commands/monitor/start.d.ts +2 -0
  26. package/dist.dts/packages/cli/src/commands/monitor/status.d.ts +2 -0
  27. package/dist.dts/packages/cli/src/commands/monitor/stop.d.ts +2 -0
  28. package/dist.dts/packages/cli/src/commands/monitor.d.ts +1 -0
  29. package/dist.dts/packages/cli/src/commands/setup.d.ts +1 -0
  30. package/dist.dts/packages/cli/src/follow.test.d.ts +1 -0
  31. package/dist.dts/packages/cli/src/utils/daemon.d.ts +2 -0
  32. package/dist.dts/packages/cli/src/utils/flags.d.ts +1 -0
  33. package/dist.dts/packages/cli/src/utils/format.d.ts +8 -0
  34. package/dist.dts/packages/cli/src/utils/net.d.ts +1 -0
  35. package/dist.dts/packages/cli/src/utils/setup.d.ts +2 -0
  36. package/dist.dts/packages/cli/src/utils/webhooks.d.ts +2 -0
  37. package/dist.dts/packages/daemon/src/types/daemon.d.ts +2 -0
  38. package/package.json +1 -1
package/dist/core.js CHANGED
@@ -168,6 +168,11 @@ var MonitorService = class {
168
168
  return this.transact((registry) => {
169
169
  const monitor = registry.monitors.find((entry) => entry.id === id);
170
170
  if (!monitor) return { error: `monitor ${id} was not found` };
171
+ const identity = monitorIdentity(monitor.target, monitor.source);
172
+ const duplicate = registry.monitors.find(
173
+ (entry) => entry.id !== id && entry.enabled && monitorIdentity(entry.target, entry.source) === identity
174
+ );
175
+ if (duplicate) return { error: `monitor ${id} duplicates active monitor ${duplicate.id} for the same source` };
171
176
  monitor.enabled = true;
172
177
  monitor.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
173
178
  return monitor;
package/dist/daemon.js CHANGED
@@ -541,6 +541,11 @@ var MonitorService = class {
541
541
  return this.transact((registry) => {
542
542
  const monitor = registry.monitors.find((entry) => entry.id === id);
543
543
  if (!monitor) return { error: `monitor ${id} was not found` };
544
+ const identity = monitorIdentity(monitor.target, monitor.source);
545
+ const duplicate = registry.monitors.find(
546
+ (entry) => entry.id !== id && entry.enabled && monitorIdentity(entry.target, entry.source) === identity
547
+ );
548
+ if (duplicate) return { error: `monitor ${id} duplicates active monitor ${duplicate.id} for the same source` };
544
549
  monitor.enabled = true;
545
550
  monitor.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
546
551
  return monitor;
@@ -4392,7 +4397,10 @@ function daemonEnvironment(host) {
4392
4397
  import { createServer } from "node:http";
4393
4398
  import { Readable } from "node:stream";
4394
4399
  async function serveHttp(options) {
4400
+ const active = /* @__PURE__ */ new Set();
4395
4401
  const server = createServer((incoming, outgoing) => {
4402
+ active.add(outgoing);
4403
+ outgoing.on("close", () => active.delete(outgoing));
4396
4404
  void handle(incoming, outgoing, options.handler);
4397
4405
  });
4398
4406
  server.requestTimeout = 0;
@@ -4411,6 +4419,10 @@ async function serveHttp(options) {
4411
4419
  return {
4412
4420
  port,
4413
4421
  async stop() {
4422
+ for (const outgoing of active) {
4423
+ outgoing.destroy();
4424
+ }
4425
+ active.clear();
4414
4426
  server.closeIdleConnections?.();
4415
4427
  await new Promise((resolve) => {
4416
4428
  server.close(() => resolve());
@@ -4822,9 +4834,16 @@ function monitorView(monitor) {
4822
4834
  label: definition.label(monitor.source),
4823
4835
  detail: definition.detail(monitor.source),
4824
4836
  describe: definition.describe(monitor.source),
4825
- unresponsive: definition.unresponsive(monitor)
4837
+ unresponsive: definition.unresponsive(monitor),
4838
+ lastPolledAt: cursorTime(monitor.cursors.__lastPolledAt ?? monitor.cursors.__lastAttemptAt),
4839
+ webhookHeartbeatAt: cursorTime(monitor.cursors.__webhookHeartbeatAt)
4826
4840
  };
4827
4841
  }
4842
+ function cursorTime(value) {
4843
+ const numeric = Number(value);
4844
+ if (!Number.isFinite(numeric) || numeric <= 0) return void 0;
4845
+ return new Date(numeric).toISOString();
4846
+ }
4828
4847
  function logEntryView(queued) {
4829
4848
  const definition = sourceDefinition(queued.event.source);
4830
4849
  return {
@@ -63,6 +63,16 @@ adapters (OpenCode, Pi) are all consumers of the daemon.
63
63
  - `sourcefed daemon [--port 18787]` — run the shared daemon (rpc, events, webhooks).
64
64
  - `sourcefed mcp --stdio|--http` — expose the daemon through MCP.
65
65
  - `sourcefed monitor create|list|status|stop` — drive a running daemon from the shell.
66
+ - `sourcefed monitor follow` — tail new events live over SSE (drains queued events first);
67
+ use `sourcefed monitor events` for a one-shot snapshot and `monitor ack` to consume them.
68
+
69
+ Without MCP, read events from the CLI:
70
+
71
+ ```bash
72
+ sourcefed monitor follow & # stream events in the background
73
+ sourcefed monitor events # or take a snapshot of what's queued
74
+ sourcefed monitor ack --event-id $ID # acknowledge what you consumed
75
+ ```
66
76
 
67
77
  When `SOURCEFED_DAEMON_URL` is unset, the OpenCode and Pi adapters spawn one
68
78
  local HTTP daemon automatically (if none is running) and connect to it, so
@@ -13,6 +13,7 @@ sourcefed monitor stop --id ID [--target-kind KIND] [--target-id ID]
13
13
  sourcefed monitor start --id ID [--target-kind KIND] [--target-id ID]
14
14
  sourcefed monitor remove --id ID --yes [--target-kind KIND] [--target-id ID]
15
15
  sourcefed monitor events [--target-kind KIND] [--target-id ID]
16
+ sourcefed monitor follow [--target-kind KIND] [--target-id ID]
16
17
  sourcefed monitor ack --event-id ID[,ID...] [--target-kind KIND] [--target-id ID]
17
18
  sourcefed monitor sources
18
19
  sourcefed skills [list] List bundled skills
package/dist/mcp.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  decodeTarget,
3
3
  encodeTarget
4
- } from "./chunk-B7T6IZYS.js";
4
+ } from "./chunk-7KHZCWGQ.js";
5
5
  import {
6
6
  __export
7
7
  } from "./chunk-MLKGABMK.js";
package/dist/opencode.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  daemonCommand,
5
5
  daemonEnvironment,
6
6
  spawnLocalDaemon
7
- } from "./chunk-B7T6IZYS.js";
7
+ } from "./chunk-7KHZCWGQ.js";
8
8
  import {
9
9
  __export
10
10
  } from "./chunk-MLKGABMK.js";
package/dist/pi.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  daemonCommand,
4
4
  daemonEnvironment,
5
5
  spawnLocalDaemon
6
- } from "./chunk-B7T6IZYS.js";
6
+ } from "./chunk-7KHZCWGQ.js";
7
7
  import "./chunk-MLKGABMK.js";
8
8
 
9
9
  // adapters/pi/src/index.ts
@@ -39,13 +39,32 @@ function showSourcefedDialog(_tui, theme, done, title, lines) {
39
39
  function monitorLines(monitors, theme) {
40
40
  const active = monitors.filter((monitor) => monitor.enabled);
41
41
  if (active.length === 0) return [{ text: theme.fg("dim", "No active monitors") }];
42
- return active.map((monitor) => {
42
+ return active.flatMap((monitor) => {
43
43
  const status = monitor.unresponsive ? theme.fg("error", "\u25CF") : theme.fg("success", "\u25CF");
44
44
  const describe = theme.fg("text", monitor.describe);
45
45
  const detail = monitor.detail ? theme.fg("muted", monitor.detail) : "";
46
- return { text: `${status} ${monitor.icon} ${describe}${detail}` };
46
+ const statusLabel = monitor.unresponsive ? "recovering connection" : "healthy";
47
+ const rows = [
48
+ ["Name", monitor.name],
49
+ ["Delivery", monitor.delivery],
50
+ ["Poll interval", `${monitor.pollIntervalSec}s`],
51
+ ["Created", formatTime(monitor.createdAt)],
52
+ ["Updated", formatTime(monitor.updatedAt)],
53
+ ["Last poll", formatTime(monitor.lastPolledAt)],
54
+ ["Webhook heartbeat", formatTime(monitor.webhookHeartbeatAt)]
55
+ ];
56
+ return [
57
+ { text: `${status} ${monitor.icon} ${describe}${detail} [${statusLabel}]` },
58
+ ...rows.map(([label, value]) => ({ text: theme.fg("muted", ` ${label}: ${value}`) }))
59
+ ];
47
60
  });
48
61
  }
62
+ function formatTime(value) {
63
+ if (!value) return "never";
64
+ const date = new Date(value);
65
+ if (Number.isNaN(date.getTime())) return value;
66
+ return date.toLocaleString();
67
+ }
49
68
  function logLines(logs, theme) {
50
69
  if (logs.length === 0) return [{ text: theme.fg("dim", "No notifications sent yet") }];
51
70
  return logs.flatMap((entry) => {
@@ -3927,36 +3927,12 @@ function MonitorDialog(props) {
3927
3927
  _$setProp2(_el$1, "scrollY", true);
3928
3928
  _$setProp2(_el$10, "flexDirection", "column");
3929
3929
  _$setProp2(_el$10, "width", "100%");
3930
- _$insert2(_el$10, () => active.map((monitor) => (() => {
3931
- var _el$11 = _$createElement2("box"), _el$12 = _$createElement2("text"), _el$14 = _$createElement2("text"), _el$15 = _$createTextNode2(` `), _el$16 = _$createTextNode2(` `), _el$17 = _$createElement2("text");
3932
- _$insertNode2(_el$11, _el$12);
3933
- _$insertNode2(_el$11, _el$14);
3934
- _$insertNode2(_el$11, _el$17);
3935
- _$setProp2(_el$11, "flexDirection", "row");
3936
- _$setProp2(_el$11, "width", "100%");
3937
- _$setProp2(_el$11, "minWidth", 0);
3938
- _$insertNode2(_el$12, _$createTextNode2(`\u25CF`));
3939
- _$insertNode2(_el$14, _el$15);
3940
- _$insertNode2(_el$14, _el$16);
3941
- _$insert2(_el$14, () => monitor.icon, _el$16);
3942
- _$setProp2(_el$17, "flexGrow", 1);
3943
- _$setProp2(_el$17, "flexShrink", 1);
3944
- _$setProp2(_el$17, "minWidth", 0);
3945
- _$setProp2(_el$17, "truncate", true);
3946
- _$insert2(_el$17, () => monitor.describe);
3947
- _$effect2((_p$) => {
3948
- var _v$3 = monitor.unresponsive ? theme().error : theme().success, _v$4 = theme().text, _v$5 = theme().text;
3949
- _v$3 !== _p$.e && (_p$.e = _$setProp2(_el$12, "fg", _v$3, _p$.e));
3950
- _v$4 !== _p$.t && (_p$.t = _$setProp2(_el$14, "fg", _v$4, _p$.t));
3951
- _v$5 !== _p$.a && (_p$.a = _$setProp2(_el$17, "fg", _v$5, _p$.a));
3952
- return _p$;
3953
- }, {
3954
- e: void 0,
3955
- t: void 0,
3956
- a: void 0
3957
- });
3958
- return _el$11;
3959
- })()));
3930
+ _$insert2(_el$10, () => active.map((monitor) => _$createComponent2(MonitorCard, {
3931
+ monitor,
3932
+ get theme() {
3933
+ return theme();
3934
+ }
3935
+ })));
3960
3936
  return _el$1;
3961
3937
  })();
3962
3938
  },
@@ -3979,111 +3955,180 @@ function MonitorDialog(props) {
3979
3955
  return _el$;
3980
3956
  })();
3981
3957
  }
3958
+ function MonitorCard(props) {
3959
+ const monitor = props.monitor;
3960
+ const theme = props.theme;
3961
+ const status = monitor.unresponsive ? theme.error : monitor.enabled ? theme.success : theme.textMuted;
3962
+ const statusLabel = !monitor.enabled ? "stopped" : monitor.unresponsive ? "recovering connection" : "healthy";
3963
+ const rows = [["Delivery", monitor.delivery], ["Poll interval", `${monitor.pollIntervalSec}s`], ["Created", formatTime(monitor.createdAt)], ["Updated", formatTime(monitor.updatedAt)], ["Last poll", formatTime(monitor.lastPolledAt)], ["Webhook heartbeat", formatTime(monitor.webhookHeartbeatAt)]];
3964
+ return (() => {
3965
+ var _el$11 = _$createElement2("box"), _el$12 = _$createElement2("box"), _el$13 = _$createElement2("text"), _el$15 = _$createElement2("text"), _el$16 = _$createTextNode2(` `), _el$17 = _$createTextNode2(` `), _el$18 = _$createElement2("text"), _el$19 = _$createTextNode2(` [`), _el$20 = _$createTextNode2(`]`);
3966
+ _$insertNode2(_el$11, _el$12);
3967
+ _$setProp2(_el$11, "flexDirection", "column");
3968
+ _$setProp2(_el$11, "width", "100%");
3969
+ _$setProp2(_el$11, "minWidth", 0);
3970
+ _$setProp2(_el$11, "marginBottom", 1);
3971
+ _$insertNode2(_el$12, _el$13);
3972
+ _$insertNode2(_el$12, _el$15);
3973
+ _$insertNode2(_el$12, _el$18);
3974
+ _$setProp2(_el$12, "flexDirection", "row");
3975
+ _$setProp2(_el$12, "width", "100%");
3976
+ _$setProp2(_el$12, "minWidth", 0);
3977
+ _$insertNode2(_el$13, _$createTextNode2(`\u25CF`));
3978
+ _$setProp2(_el$13, "fg", status);
3979
+ _$insertNode2(_el$15, _el$16);
3980
+ _$insertNode2(_el$15, _el$17);
3981
+ _$insert2(_el$15, () => monitor.icon, _el$17);
3982
+ _$insert2(_el$15, () => monitor.describe, null);
3983
+ _$insertNode2(_el$18, _el$19);
3984
+ _$insertNode2(_el$18, _el$20);
3985
+ _$setProp2(_el$18, "fg", status);
3986
+ _$setProp2(_el$18, "flexGrow", 1);
3987
+ _$setProp2(_el$18, "flexShrink", 1);
3988
+ _$setProp2(_el$18, "minWidth", 0);
3989
+ _$setProp2(_el$18, "truncate", true);
3990
+ _$insert2(_el$18, statusLabel, _el$20);
3991
+ _$insert2(_el$11, () => rows.map(([label, value]) => (() => {
3992
+ var _el$21 = _$createElement2("box"), _el$22 = _$createElement2("text"), _el$23 = _$createTextNode2(`: `), _el$24 = _$createElement2("text");
3993
+ _$insertNode2(_el$21, _el$22);
3994
+ _$insertNode2(_el$21, _el$24);
3995
+ _$setProp2(_el$21, "flexDirection", "row");
3996
+ _$setProp2(_el$21, "width", "100%");
3997
+ _$setProp2(_el$21, "minWidth", 0);
3998
+ _$insertNode2(_el$22, _el$23);
3999
+ _$setProp2(_el$22, "flexShrink", 0);
4000
+ _$insert2(_el$22, label, _el$23);
4001
+ _$setProp2(_el$24, "flexGrow", 1);
4002
+ _$setProp2(_el$24, "flexShrink", 1);
4003
+ _$setProp2(_el$24, "minWidth", 0);
4004
+ _$setProp2(_el$24, "truncate", true);
4005
+ _$insert2(_el$24, value);
4006
+ _$effect2((_p$) => {
4007
+ var _v$3 = theme.textMuted, _v$4 = theme.text;
4008
+ _v$3 !== _p$.e && (_p$.e = _$setProp2(_el$22, "fg", _v$3, _p$.e));
4009
+ _v$4 !== _p$.t && (_p$.t = _$setProp2(_el$24, "fg", _v$4, _p$.t));
4010
+ return _p$;
4011
+ }, {
4012
+ e: void 0,
4013
+ t: void 0
4014
+ });
4015
+ return _el$21;
4016
+ })()), null);
4017
+ _$effect2((_$p) => _$setProp2(_el$15, "fg", theme.text, _$p));
4018
+ return _el$11;
4019
+ })();
4020
+ }
4021
+ function formatTime(value) {
4022
+ if (!value) return "never";
4023
+ const date = new Date(value);
4024
+ if (Number.isNaN(date.getTime())) return value;
4025
+ return date.toLocaleString();
4026
+ }
3982
4027
  function LogsDialog(props) {
3983
4028
  const theme = createMemo2(() => props.api.theme.current);
3984
4029
  const maxListRows = Math.max(6, Math.floor(props.api.renderer.height * 0.45));
3985
4030
  return (() => {
3986
- var _el$18 = _$createElement2("box"), _el$19 = _$createElement2("box"), _el$20 = _$createElement2("text"), _el$21 = _$createTextNode2(`Sourcefed notifications (`), _el$22 = _$createTextNode2(`)`), _el$23 = _$createElement2("box"), _el$24 = _$createElement2("text");
3987
- _$insertNode2(_el$18, _el$19);
3988
- _$setProp2(_el$18, "flexDirection", "column");
3989
- _$setProp2(_el$18, "width", "100%");
3990
- _$setProp2(_el$18, "paddingX", 2);
3991
- _$setProp2(_el$18, "paddingY", 1);
3992
- _$insertNode2(_el$19, _el$20);
3993
- _$insertNode2(_el$19, _el$23);
3994
- _$insertNode2(_el$19, _el$24);
3995
- _$setProp2(_el$19, "flexDirection", "row");
3996
- _$setProp2(_el$19, "width", "100%");
3997
- _$setProp2(_el$19, "minWidth", 0);
3998
- _$insertNode2(_el$20, _el$21);
3999
- _$insertNode2(_el$20, _el$22);
4000
- _$setProp2(_el$20, "attributes", 1);
4001
- _$insert2(_el$20, () => props.logs.length, _el$22);
4002
- _$setProp2(_el$23, "flexGrow", 1);
4003
- _$insertNode2(_el$24, _$createTextNode2(`esc`));
4004
- _$insert2(_el$18, _$createComponent2(Show2, {
4031
+ var _el$25 = _$createElement2("box"), _el$26 = _$createElement2("box"), _el$27 = _$createElement2("text"), _el$28 = _$createTextNode2(`Sourcefed notifications (`), _el$29 = _$createTextNode2(`)`), _el$30 = _$createElement2("box"), _el$31 = _$createElement2("text");
4032
+ _$insertNode2(_el$25, _el$26);
4033
+ _$setProp2(_el$25, "flexDirection", "column");
4034
+ _$setProp2(_el$25, "width", "100%");
4035
+ _$setProp2(_el$25, "paddingX", 2);
4036
+ _$setProp2(_el$25, "paddingY", 1);
4037
+ _$insertNode2(_el$26, _el$27);
4038
+ _$insertNode2(_el$26, _el$30);
4039
+ _$insertNode2(_el$26, _el$31);
4040
+ _$setProp2(_el$26, "flexDirection", "row");
4041
+ _$setProp2(_el$26, "width", "100%");
4042
+ _$setProp2(_el$26, "minWidth", 0);
4043
+ _$insertNode2(_el$27, _el$28);
4044
+ _$insertNode2(_el$27, _el$29);
4045
+ _$setProp2(_el$27, "attributes", 1);
4046
+ _$insert2(_el$27, () => props.logs.length, _el$29);
4047
+ _$setProp2(_el$30, "flexGrow", 1);
4048
+ _$insertNode2(_el$31, _$createTextNode2(`esc`));
4049
+ _$insert2(_el$25, _$createComponent2(Show2, {
4005
4050
  get when() {
4006
4051
  return props.logs.length > 0;
4007
4052
  },
4008
4053
  get fallback() {
4009
4054
  return (() => {
4010
- var _el$28 = _$createElement2("text");
4011
- _$insertNode2(_el$28, _$createTextNode2(`No notifications sent yet`));
4012
- _$effect2((_$p) => _$setProp2(_el$28, "fg", theme().textMuted, _$p));
4013
- return _el$28;
4055
+ var _el$35 = _$createElement2("text");
4056
+ _$insertNode2(_el$35, _$createTextNode2(`No notifications sent yet`));
4057
+ _$effect2((_$p) => _$setProp2(_el$35, "fg", theme().textMuted, _$p));
4058
+ return _el$35;
4014
4059
  })();
4015
4060
  },
4016
4061
  get children() {
4017
- var _el$26 = _$createElement2("scrollbox"), _el$27 = _$createElement2("box");
4018
- _$insertNode2(_el$26, _el$27);
4019
- _$setProp2(_el$26, "maxHeight", maxListRows);
4020
- _$setProp2(_el$26, "scrollY", true);
4021
- _$setProp2(_el$26, "stickyScroll", true);
4022
- _$setProp2(_el$26, "stickyStart", "bottom");
4023
- _$setProp2(_el$27, "flexDirection", "column");
4024
- _$setProp2(_el$27, "width", "100%");
4025
- _$insert2(_el$27, () => props.logs.map((entry) => (() => {
4026
- var _el$30 = _$createElement2("box"), _el$31 = _$createElement2("box"), _el$32 = _$createElement2("text"), _el$33 = _$createElement2("text"), _el$34 = _$createTextNode2(` `), _el$35 = _$createElement2("text"), _el$36 = _$createTextNode2(` `), _el$37 = _$createTextNode2(` `);
4027
- _$insertNode2(_el$30, _el$31);
4028
- _$setProp2(_el$30, "flexDirection", "column");
4029
- _$setProp2(_el$30, "width", "100%");
4030
- _$insertNode2(_el$31, _el$32);
4031
- _$insertNode2(_el$31, _el$33);
4032
- _$insertNode2(_el$31, _el$35);
4033
- _$setProp2(_el$31, "flexDirection", "row");
4034
- _$setProp2(_el$31, "width", "100%");
4035
- _$setProp2(_el$31, "minWidth", 0);
4036
- _$insert2(_el$32, () => entry.actionable ? "\u25B6" : "\xB7");
4037
- _$insertNode2(_el$33, _el$34);
4038
- _$setProp2(_el$33, "flexShrink", 0);
4039
- _$setProp2(_el$33, "minWidth", 0);
4040
- _$insert2(_el$33, () => entry.icon, null);
4041
- _$insertNode2(_el$35, _el$36);
4042
- _$insertNode2(_el$35, _el$37);
4043
- _$setProp2(_el$35, "flexGrow", 1);
4044
- _$setProp2(_el$35, "flexShrink", 1);
4045
- _$setProp2(_el$35, "minWidth", 0);
4046
- _$setProp2(_el$35, "truncate", true);
4047
- _$insert2(_el$35, () => new Date(entry.at).toLocaleString(), _el$37);
4048
- _$insert2(_el$35, () => entry.summary, null);
4049
- _$insert2(_el$30, _$createComponent2(Show2, {
4062
+ var _el$33 = _$createElement2("scrollbox"), _el$34 = _$createElement2("box");
4063
+ _$insertNode2(_el$33, _el$34);
4064
+ _$setProp2(_el$33, "maxHeight", maxListRows);
4065
+ _$setProp2(_el$33, "scrollY", true);
4066
+ _$setProp2(_el$33, "stickyScroll", true);
4067
+ _$setProp2(_el$33, "stickyStart", "bottom");
4068
+ _$setProp2(_el$34, "flexDirection", "column");
4069
+ _$setProp2(_el$34, "width", "100%");
4070
+ _$insert2(_el$34, () => props.logs.map((entry) => (() => {
4071
+ var _el$37 = _$createElement2("box"), _el$38 = _$createElement2("box"), _el$39 = _$createElement2("text"), _el$40 = _$createElement2("text"), _el$41 = _$createTextNode2(` `), _el$42 = _$createElement2("text"), _el$43 = _$createTextNode2(` `), _el$44 = _$createTextNode2(` `);
4072
+ _$insertNode2(_el$37, _el$38);
4073
+ _$setProp2(_el$37, "flexDirection", "column");
4074
+ _$setProp2(_el$37, "width", "100%");
4075
+ _$insertNode2(_el$38, _el$39);
4076
+ _$insertNode2(_el$38, _el$40);
4077
+ _$insertNode2(_el$38, _el$42);
4078
+ _$setProp2(_el$38, "flexDirection", "row");
4079
+ _$setProp2(_el$38, "width", "100%");
4080
+ _$setProp2(_el$38, "minWidth", 0);
4081
+ _$insert2(_el$39, () => entry.actionable ? "\u25B6" : "\xB7");
4082
+ _$insertNode2(_el$40, _el$41);
4083
+ _$setProp2(_el$40, "flexShrink", 0);
4084
+ _$setProp2(_el$40, "minWidth", 0);
4085
+ _$insert2(_el$40, () => entry.icon, null);
4086
+ _$insertNode2(_el$42, _el$43);
4087
+ _$insertNode2(_el$42, _el$44);
4088
+ _$setProp2(_el$42, "flexGrow", 1);
4089
+ _$setProp2(_el$42, "flexShrink", 1);
4090
+ _$setProp2(_el$42, "minWidth", 0);
4091
+ _$setProp2(_el$42, "truncate", true);
4092
+ _$insert2(_el$42, () => new Date(entry.at).toLocaleString(), _el$44);
4093
+ _$insert2(_el$42, () => entry.summary, null);
4094
+ _$insert2(_el$37, _$createComponent2(Show2, {
4050
4095
  get when() {
4051
4096
  return entry.body;
4052
4097
  },
4053
4098
  get children() {
4054
- var _el$38 = _$createElement2("text"), _el$39 = _$createTextNode2(` `);
4055
- _$insertNode2(_el$38, _el$39);
4056
- _$insert2(_el$38, () => entry.body, null);
4057
- _$effect2((_$p) => _$setProp2(_el$38, "fg", theme().textMuted, _$p));
4058
- return _el$38;
4099
+ var _el$45 = _$createElement2("text"), _el$46 = _$createTextNode2(` `);
4100
+ _$insertNode2(_el$45, _el$46);
4101
+ _$insert2(_el$45, () => entry.body, null);
4102
+ _$effect2((_$p) => _$setProp2(_el$45, "fg", theme().textMuted, _$p));
4103
+ return _el$45;
4059
4104
  }
4060
4105
  }), null);
4061
4106
  _$effect2((_p$) => {
4062
- var _v$8 = entry.actionable ? theme().warning : theme().textMuted, _v$9 = theme().text, _v$0 = theme().text;
4063
- _v$8 !== _p$.e && (_p$.e = _$setProp2(_el$32, "fg", _v$8, _p$.e));
4064
- _v$9 !== _p$.t && (_p$.t = _$setProp2(_el$33, "fg", _v$9, _p$.t));
4065
- _v$0 !== _p$.a && (_p$.a = _$setProp2(_el$35, "fg", _v$0, _p$.a));
4107
+ var _v$7 = entry.actionable ? theme().warning : theme().textMuted, _v$8 = theme().text, _v$9 = theme().text;
4108
+ _v$7 !== _p$.e && (_p$.e = _$setProp2(_el$39, "fg", _v$7, _p$.e));
4109
+ _v$8 !== _p$.t && (_p$.t = _$setProp2(_el$40, "fg", _v$8, _p$.t));
4110
+ _v$9 !== _p$.a && (_p$.a = _$setProp2(_el$42, "fg", _v$9, _p$.a));
4066
4111
  return _p$;
4067
4112
  }, {
4068
4113
  e: void 0,
4069
4114
  t: void 0,
4070
4115
  a: void 0
4071
4116
  });
4072
- return _el$30;
4117
+ return _el$37;
4073
4118
  })()));
4074
- return _el$26;
4119
+ return _el$33;
4075
4120
  }
4076
4121
  }), null);
4077
4122
  _$effect2((_p$) => {
4078
- var _v$6 = theme().text, _v$7 = theme().textMuted;
4079
- _v$6 !== _p$.e && (_p$.e = _$setProp2(_el$20, "fg", _v$6, _p$.e));
4080
- _v$7 !== _p$.t && (_p$.t = _$setProp2(_el$24, "fg", _v$7, _p$.t));
4123
+ var _v$5 = theme().text, _v$6 = theme().textMuted;
4124
+ _v$5 !== _p$.e && (_p$.e = _$setProp2(_el$27, "fg", _v$5, _p$.e));
4125
+ _v$6 !== _p$.t && (_p$.t = _$setProp2(_el$31, "fg", _v$6, _p$.t));
4081
4126
  return _p$;
4082
4127
  }, {
4083
4128
  e: void 0,
4084
4129
  t: void 0
4085
4130
  });
4086
- return _el$18;
4131
+ return _el$25;
4087
4132
  })();
4088
4133
  }
4089
4134
 
@@ -0,0 +1 @@
1
+ export declare function runDaemon(args: string[]): Promise<void>;
@@ -0,0 +1 @@
1
+ export declare function runMcp(args: string[]): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { MonitorContext } from "./index.js";
2
+ export declare function ack(context: MonitorContext): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { MonitorContext } from "./index.js";
2
+ export declare function create(context: MonitorContext): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { MonitorContext } from "./index.js";
2
+ export declare function events(context: MonitorContext): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { MonitorContext } from "./index.js";
2
+ export declare function follow(context: MonitorContext): Promise<void>;
@@ -0,0 +1,10 @@
1
+ import type { DaemonClient } from "@fdcn/sourcefed/daemon";
2
+ export declare function runMonitor(argv: string[]): Promise<void>;
3
+ export type MonitorContext = {
4
+ client: DaemonClient;
5
+ target: {
6
+ kind: string;
7
+ id: string;
8
+ };
9
+ args: string[];
10
+ };
@@ -0,0 +1,2 @@
1
+ import type { MonitorContext } from "./index.js";
2
+ export declare function list(context: MonitorContext): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { MonitorContext } from "./index.js";
2
+ export declare function logs(context: MonitorContext): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { MonitorContext } from "./index.js";
2
+ export declare function remove(context: MonitorContext): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { MonitorContext } from "./index.js";
2
+ export declare function sources(context: MonitorContext): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { MonitorContext } from "./index.js";
2
+ export declare function start(context: MonitorContext): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { MonitorContext } from "./index.js";
2
+ export declare function status(context: MonitorContext): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { MonitorContext } from "./index.js";
2
+ export declare function stop(context: MonitorContext): Promise<void>;
@@ -0,0 +1 @@
1
+ export declare function runMonitor(argv: string[]): Promise<void>;
@@ -0,0 +1 @@
1
+ export declare function runSetup(args: string[]): Promise<void>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import { SourcefedDaemon } from "@fdcn/sourcefed/daemon";
2
+ export declare function createDaemon(): SourcefedDaemon;
@@ -0,0 +1 @@
1
+ export declare function flag(args: string[], name: string): string | undefined;
@@ -0,0 +1,8 @@
1
+ import type { LogEntryView, MonitorView } from "@fdcn/sourcefed/daemon";
2
+ export declare function printMonitors(monitors: MonitorView[]): void;
3
+ export declare function printLogs(logs: LogEntryView[]): void;
4
+ export declare function printResult(result: unknown): void;
5
+ export declare function green(text: string): string;
6
+ export declare function red(text: string): string;
7
+ export declare function yellow(text: string): string;
8
+ export declare function dim(text: string): string;
@@ -0,0 +1 @@
1
+ export declare function isLoopback(hostname: string): boolean;
@@ -0,0 +1,2 @@
1
+ export declare function setupSpec(): string;
2
+ export declare function setupHost(name: string, args: string[], spec: string): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { HttpServer, SourcefedDaemon } from "@fdcn/sourcefed/daemon";
2
+ export declare function startWebhookServer(runtime: SourcefedDaemon["runtime"]): Promise<HttpServer | undefined>;
@@ -31,6 +31,8 @@ export type MonitorView = {
31
31
  detail: string;
32
32
  describe: string;
33
33
  unresponsive: boolean;
34
+ lastPolledAt?: string;
35
+ webhookHeartbeatAt?: string;
34
36
  };
35
37
  export type LogEntryView = {
36
38
  id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fdcn/sourcefed",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Live Jira, GitHub, and Slack monitoring for agent hosts: CLI, daemon, MCP server, and host plugins.",
5
5
  "license": "MIT",
6
6
  "type": "module",