@fdcn/sourcefed 0.3.6 → 0.3.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 (52) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-X3BZSHKZ.js → chunk-5JL3UV72.js} +1328 -399
  3. package/dist/cli.js +9888 -8063
  4. package/dist/daemon.js +1194 -263
  5. package/dist/data/core/SKILL.md +9 -4
  6. package/dist/data/core/references/commands.md +6 -1
  7. package/dist/data/sourcefed/SKILL.md +3 -2
  8. package/dist/guidance.md +6 -2
  9. package/dist/mcp.js +6 -2
  10. package/dist/opencode.js +263 -122
  11. package/dist/pi.js +161 -39
  12. package/dist/tui-compiled.mjs +306 -166
  13. package/dist.dts/adapters/opencode/bridge.d.ts +66 -22
  14. package/dist.dts/adapters/opencode/subscriptions.d.ts +46 -0
  15. package/dist.dts/adapters/opencode/tool-result.d.ts +2 -1
  16. package/dist.dts/adapters/opencode/tools/monitor_create.d.ts +19 -2
  17. package/dist.dts/adapters/opencode/tools/monitor_list.d.ts +3 -2
  18. package/dist.dts/adapters/opencode/tools/monitor_start.d.ts +3 -2
  19. package/dist.dts/adapters/opencode/tools/monitor_status.d.ts +3 -2
  20. package/dist.dts/adapters/opencode/tools/monitor_stop.d.ts +3 -2
  21. package/dist.dts/adapters/pi/src/dialog.d.ts +1 -2
  22. package/dist.dts/adapters/pi/src/monitors-dialog.d.ts +32 -0
  23. package/dist.dts/packages/core/src/types/monitor-create-input.d.ts +4 -0
  24. package/dist.dts/packages/daemon/src/event-stream.d.ts +26 -0
  25. package/dist.dts/packages/daemon/src/registry.d.ts +2 -0
  26. package/dist.dts/packages/daemon/src/stream-lifecycle.test.d.ts +1 -0
  27. package/dist.dts/packages/daemon/src/types/client.d.ts +3 -1
  28. package/dist.dts/packages/daemon/src/types/daemon.d.ts +4 -0
  29. package/dist.dts/packages/daemon/src/utils/index.d.ts +0 -1
  30. package/dist.dts/providers/yab/src/index.d.ts +2 -0
  31. package/dist.dts/providers/yab/src/monitor.d.ts +14 -0
  32. package/dist.dts/providers/yab/src/poll/index.d.ts +2 -0
  33. package/dist.dts/providers/yab/src/poll/monitor.d.ts +3 -0
  34. package/dist.dts/providers/yab/src/poll/utils/feed-events.d.ts +5 -0
  35. package/dist.dts/providers/yab/src/poll/utils/index.d.ts +4 -0
  36. package/dist.dts/providers/yab/src/poll/utils/parse-feed.d.ts +3 -0
  37. package/dist.dts/providers/yab/src/poll/utils/poll-yab.d.ts +7 -0
  38. package/dist.dts/providers/yab/src/poll/utils/yab-mcp.d.ts +10 -0
  39. package/dist.dts/providers/yab/src/schema.d.ts +12 -0
  40. package/dist.dts/providers/yab/src/types/cursor.d.ts +4 -0
  41. package/dist.dts/providers/yab/src/types/event.d.ts +8 -0
  42. package/dist.dts/providers/yab/src/types/feed-entry.d.ts +8 -0
  43. package/dist.dts/providers/yab/src/types/index.d.ts +5 -0
  44. package/dist.dts/providers/yab/src/types/page.d.ts +6 -0
  45. package/dist.dts/providers/yab/src/types/source-record.d.ts +7 -0
  46. package/dist.dts/providers/yab/src/yab.test.d.ts +1 -0
  47. package/package.json +1 -1
  48. package/dist.dts/packages/daemon/src/utils/forward.d.ts +0 -32
  49. package/dist.dts/packages/daemon/src/utils/gate.d.ts +0 -33
  50. package/dist.dts/packages/daemon/src/utils/request-router.d.ts +0 -11
  51. /package/dist.dts/{packages/daemon/src/forward.test.d.ts → adapters/opencode/lifecycle.test.d.ts} +0 -0
  52. /package/dist.dts/{packages/daemon/src/gate.test.d.ts → adapters/pi/src/monitors-dialog.test.d.ts} +0 -0
package/dist/pi.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  daemonCommand,
7
7
  daemonEnvironment,
8
8
  spawnLocalDaemon
9
- } from "./chunk-X3BZSHKZ.js";
9
+ } from "./chunk-5JL3UV72.js";
10
10
  import "./chunk-MLKGABMK.js";
11
11
 
12
12
  // adapters/pi/src/index.ts
@@ -39,35 +39,6 @@ function showSourcefedDialog(_tui, theme, done, title, lines) {
39
39
  }
40
40
  };
41
41
  }
42
- function monitorLines(monitors, theme) {
43
- const active = monitors.filter((monitor) => monitor.enabled);
44
- if (active.length === 0) return [{ text: theme.fg("dim", "No active monitors") }];
45
- return active.flatMap((monitor) => {
46
- const status = monitor.unresponsive ? theme.fg("error", "\u25CF") : theme.fg("success", "\u25CF");
47
- const describe = theme.fg("text", monitor.describe);
48
- const detail = monitor.detail ? theme.fg("muted", monitor.detail) : "";
49
- const statusLabel = monitor.unresponsive ? "recovering connection" : "healthy";
50
- const rows = [
51
- ["Name", monitor.name],
52
- ["Delivery", monitor.delivery],
53
- ["Poll interval", `${monitor.pollIntervalSec}s`],
54
- ["Created", formatTime(monitor.createdAt)],
55
- ["Updated", formatTime(monitor.updatedAt)],
56
- ["Last poll", formatTime(monitor.lastPolledAt)],
57
- ["Webhook heartbeat", formatTime(monitor.webhookHeartbeatAt)]
58
- ];
59
- return [
60
- { text: `${status} ${monitor.icon} ${describe}${detail} [${statusLabel}]` },
61
- ...rows.map(([label, value]) => ({ text: theme.fg("muted", ` ${label}: ${value}`) }))
62
- ];
63
- });
64
- }
65
- function formatTime(value) {
66
- if (!value) return "never";
67
- const date = new Date(value);
68
- if (Number.isNaN(date.getTime())) return value;
69
- return date.toLocaleString();
70
- }
71
42
  function logLines(logs, theme) {
72
43
  if (logs.length === 0) return [{ text: theme.fg("dim", "No notifications sent yet") }];
73
44
  return logs.flatMap((entry) => {
@@ -80,12 +51,145 @@ function logLines(logs, theme) {
80
51
  });
81
52
  }
82
53
 
54
+ // adapters/pi/src/monitors-dialog.ts
55
+ import { truncateToWidth as truncateToWidth2 } from "@earendil-works/pi-tui";
56
+ var PROGRESS = { stop: "Stopping", start: "Starting", remove: "Deleting" };
57
+ var MonitorManager = class {
58
+ constructor(monitors, deps) {
59
+ this.deps = deps;
60
+ this.monitors = monitors;
61
+ }
62
+ monitors;
63
+ selected = 0;
64
+ mode = { kind: "browse" };
65
+ error;
66
+ handleInput(data) {
67
+ switch (this.mode.kind) {
68
+ case "busy":
69
+ return;
70
+ case "confirm-remove":
71
+ return this.handleConfirm(data, this.mode.monitor);
72
+ case "browse":
73
+ return this.handleBrowse(data);
74
+ }
75
+ }
76
+ render(width) {
77
+ const { theme } = this.deps;
78
+ const active = this.monitors.filter((monitor) => monitor.enabled).length;
79
+ const border = theme.fg("accent", "\u2500".repeat(Math.max(0, width)));
80
+ const lines = [
81
+ border,
82
+ ` ${theme.fg("accent", theme.bold(`Sourcefed monitors (${active} active)`))}`,
83
+ "",
84
+ ...this.listLines(),
85
+ "",
86
+ ...this.statusLines(),
87
+ border
88
+ ];
89
+ return lines.map((line) => truncateToWidth2(line, width));
90
+ }
91
+ invalidate() {
92
+ }
93
+ handleBrowse(data) {
94
+ if (this.matches(data, "tui.select.cancel") || this.matches(data, "tui.select.confirm")) return this.deps.close();
95
+ if (this.matches(data, "tui.select.up")) return this.select(this.selected - 1);
96
+ if (this.matches(data, "tui.select.down")) return this.select(this.selected + 1);
97
+ const monitor = this.monitors[this.selected];
98
+ if (!monitor) return;
99
+ if (data === "s") void this.perform(monitor.enabled ? "stop" : "start", monitor);
100
+ if (data === "d") this.setMode({ kind: "confirm-remove", monitor });
101
+ }
102
+ handleConfirm(data, monitor) {
103
+ if (data === "y") void this.perform("remove", monitor);
104
+ else if (data === "n" || this.matches(data, "tui.select.cancel")) this.setMode({ kind: "browse" });
105
+ }
106
+ async perform(action, monitor) {
107
+ this.error = void 0;
108
+ this.setMode({ kind: "busy", label: `${PROGRESS[action]} ${monitor.name}\u2026` });
109
+ try {
110
+ this.monitors = await this.deps.run(action, monitor.id);
111
+ const kept = this.monitors.findIndex((candidate) => candidate.id === monitor.id);
112
+ this.selected = clamp(kept >= 0 ? kept : this.selected, this.monitors.length);
113
+ } catch (error) {
114
+ this.error = error instanceof Error ? error.message : String(error);
115
+ }
116
+ this.setMode({ kind: "browse" });
117
+ }
118
+ select(index) {
119
+ this.selected = clamp(index, this.monitors.length);
120
+ this.deps.requestRender();
121
+ }
122
+ setMode(mode) {
123
+ this.mode = mode;
124
+ this.deps.requestRender();
125
+ }
126
+ matches(data, keybinding) {
127
+ return this.deps.keys.matches(data, keybinding);
128
+ }
129
+ listLines() {
130
+ const { theme } = this.deps;
131
+ if (this.monitors.length === 0) return [` ${theme.fg("dim", "No monitors")}`];
132
+ return this.monitors.flatMap((monitor, index) => {
133
+ const selected = index === this.selected;
134
+ const marker = selected ? theme.fg("accent", "\u203A") : " ";
135
+ const header = ` ${marker} ${statusDot(monitor, theme)} ${monitor.icon} ${theme.fg("text", monitor.describe)} [${statusLabel(monitor)}]`;
136
+ return selected ? [header, ...detailLines(monitor, theme)] : [header];
137
+ });
138
+ }
139
+ statusLines() {
140
+ const { theme } = this.deps;
141
+ const lines = [];
142
+ if (this.error) lines.push(` ${theme.fg("error", this.error)}`);
143
+ switch (this.mode.kind) {
144
+ case "busy":
145
+ lines.push(` ${theme.fg("muted", this.mode.label)}`);
146
+ break;
147
+ case "confirm-remove":
148
+ lines.push(` ${theme.fg("warning", `Delete ${this.mode.monitor.name}? It stops watching and its record is removed. y/n`)}`);
149
+ break;
150
+ case "browse":
151
+ lines.push(` ${theme.fg("dim", "\u2191\u2193 select \xB7 s stop/start \xB7 d delete \xB7 esc close")}`);
152
+ }
153
+ return lines;
154
+ }
155
+ };
156
+ function clamp(index, length) {
157
+ return Math.min(Math.max(index, 0), Math.max(length - 1, 0));
158
+ }
159
+ function statusLabel(monitor) {
160
+ if (!monitor.enabled) return "stopped";
161
+ return monitor.unresponsive ? "recovering connection" : "healthy";
162
+ }
163
+ function statusDot(monitor, theme) {
164
+ if (!monitor.enabled) return theme.fg("dim", "\u25CF");
165
+ return theme.fg(monitor.unresponsive ? "error" : "success", "\u25CF");
166
+ }
167
+ function detailLines(monitor, theme) {
168
+ const rows = [
169
+ ["Name", monitor.name],
170
+ ["Delivery", monitor.delivery],
171
+ ["Poll interval", `${monitor.pollIntervalSec}s`],
172
+ ["Created", formatTime(monitor.createdAt)],
173
+ ["Updated", formatTime(monitor.updatedAt)],
174
+ ["Last poll", formatTime(monitor.lastPolledAt)],
175
+ ["Webhook heartbeat", formatTime(monitor.webhookHeartbeatAt)]
176
+ ];
177
+ return rows.map(([label, value]) => theme.fg("muted", ` ${label}: ${value}`));
178
+ }
179
+ function formatTime(value) {
180
+ if (!value) return "never";
181
+ const date = new Date(value);
182
+ if (Number.isNaN(date.getTime())) return value;
183
+ return date.toLocaleString();
184
+ }
185
+
83
186
  // adapters/pi/src/index.ts
84
187
  var STATUS_REFRESH_MS = 3e3;
85
188
  var SOURCE_ICONS = {
86
189
  jira: "\u{F0303}",
87
190
  github: "\u{F02A4}",
88
- slack: "\u{F04B1}"
191
+ slack: "\u{F04B1}",
192
+ yab: "\u{F059F}"
89
193
  };
90
194
  async function sourcefedExtension(pi) {
91
195
  const listeners = /* @__PURE__ */ new Map();
@@ -113,16 +217,20 @@ async function sourcefedExtension(pi) {
113
217
  pi.registerTool({
114
218
  name: "sourcefed_monitor_create",
115
219
  label: "Sourcefed monitor create",
116
- description: "Create or reuse a Jira, GitHub PR, Slack thread, or Slack DM monitor for the current Pi session.",
220
+ description: "Create or reuse a Jira, GitHub PR, Slack thread, Slack DM, or Yab feed monitor for the current Pi session.",
117
221
  parameters: Type.Object({
118
222
  name: Type.String(),
119
- sourceType: Type.Unsafe({ type: "string", enum: ["jira", "github", "slack"] }),
223
+ sourceType: Type.Unsafe({ type: "string", enum: ["jira", "github", "slack", "yab"] }),
120
224
  issueKey: Type.Optional(Type.String()),
121
225
  repo: Type.Optional(Type.String()),
122
226
  prNumber: Type.Optional(Type.Number()),
123
227
  channelId: Type.Optional(Type.String()),
124
228
  threadTs: Type.Optional(Type.String()),
125
229
  threadUrl: Type.Optional(Type.String()),
230
+ url: Type.Optional(Type.String()),
231
+ space: Type.Optional(Type.String()),
232
+ match: Type.Optional(Type.String()),
233
+ exclude: Type.Optional(Type.String()),
126
234
  pollIntervalSec: Type.Optional(Type.Number())
127
235
  }),
128
236
  execute: async (_toolCallID, input, _signal, _onUpdate, ctx) => toolResult(await call(ctx, "monitor_create", input))
@@ -156,12 +264,23 @@ async function sourcefedExtension(pi) {
156
264
  execute: async (_toolCallID, input, _signal, _onUpdate, ctx) => toolResult(await call(ctx, "monitor_start", input))
157
265
  });
158
266
  pi.registerCommand("sourcefed", {
159
- description: "List Sourcefed monitors for the current Pi session",
267
+ description: "Show, stop, start, or delete Sourcefed monitors for the current Pi session",
160
268
  handler: async (_args, ctx) => {
161
- const result = await call(ctx, "monitor_list", {});
162
- const monitors = Array.isArray(result?.monitors) ? result.monitors : [];
269
+ const monitors = await listMonitors(ctx);
270
+ const run = async (action, id) => {
271
+ const result = await call(ctx, `monitor_${action}`, { id });
272
+ if (result?.ok === false) throw new Error(result.error ?? `monitor ${action} failed`);
273
+ void refreshStatus();
274
+ return listMonitors(ctx);
275
+ };
163
276
  await ctx.ui.custom(
164
- (tui, theme, _keybindings, done) => showSourcefedDialog(tui, theme, done, `Sourcefed monitors (${monitors.length})`, monitorLines(monitors, theme))
277
+ (tui, theme, keybindings, done) => new MonitorManager(monitors, {
278
+ theme,
279
+ keys: keybindings,
280
+ run,
281
+ requestRender: () => tui.requestRender(),
282
+ close: () => done(null)
283
+ })
165
284
  );
166
285
  }
167
286
  });
@@ -185,9 +304,12 @@ async function sourcefedExtension(pi) {
185
304
  statusTimer = void 0;
186
305
  }
187
306
  }
188
- async function updateStatus(ctx) {
307
+ async function listMonitors(ctx) {
189
308
  const result = await call(ctx, "monitor_list", {});
190
- const monitors = Array.isArray(result?.monitors) ? result.monitors : [];
309
+ return Array.isArray(result?.monitors) ? result.monitors : [];
310
+ }
311
+ async function updateStatus(ctx) {
312
+ const monitors = await listMonitors(ctx);
191
313
  const active = monitors.filter((monitor) => monitor.enabled);
192
314
  if (active.length === 0) {
193
315
  ctx.ui.setStatus("sourcefed", void 0);