@pellux/goodvibes-sdk 0.25.1 → 0.25.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 (76) hide show
  1. package/dist/_internal/daemon/otlp-protobuf.d.ts +3 -0
  2. package/dist/_internal/daemon/otlp-protobuf.d.ts.map +1 -0
  3. package/dist/_internal/daemon/otlp-protobuf.js +968 -0
  4. package/dist/_internal/daemon/telemetry-routes.d.ts.map +1 -1
  5. package/dist/_internal/daemon/telemetry-routes.js +22 -13
  6. package/dist/_internal/platform/adapters/ntfy/index.d.ts.map +1 -1
  7. package/dist/_internal/platform/adapters/ntfy/index.js +93 -0
  8. package/dist/_internal/platform/adapters/types.d.ts +21 -0
  9. package/dist/_internal/platform/adapters/types.d.ts.map +1 -1
  10. package/dist/_internal/platform/channels/builtin/setup-schema.d.ts.map +1 -1
  11. package/dist/_internal/platform/channels/builtin/setup-schema.js +4 -3
  12. package/dist/_internal/platform/channels/delivery/strategies-core.d.ts.map +1 -1
  13. package/dist/_internal/platform/channels/delivery/strategies-core.js +1 -0
  14. package/dist/_internal/platform/channels/provider-runtime.d.ts +1 -1
  15. package/dist/_internal/platform/channels/provider-runtime.d.ts.map +1 -1
  16. package/dist/_internal/platform/channels/provider-runtime.js +14 -9
  17. package/dist/_internal/platform/channels/reply-pipeline.d.ts +1 -0
  18. package/dist/_internal/platform/channels/reply-pipeline.d.ts.map +1 -1
  19. package/dist/_internal/platform/channels/reply-pipeline.js +32 -1
  20. package/dist/_internal/platform/companion/companion-chat-manager.d.ts +12 -0
  21. package/dist/_internal/platform/companion/companion-chat-manager.d.ts.map +1 -1
  22. package/dist/_internal/platform/companion/companion-chat-manager.js +41 -0
  23. package/dist/_internal/platform/config/schema-domain-surfaces.js +1 -1
  24. package/dist/_internal/platform/control-plane/conversation-message.d.ts +1 -1
  25. package/dist/_internal/platform/control-plane/conversation-message.d.ts.map +1 -1
  26. package/dist/_internal/platform/daemon/facade-composition.d.ts.map +1 -1
  27. package/dist/_internal/platform/daemon/facade-composition.js +3 -0
  28. package/dist/_internal/platform/daemon/surface-actions.d.ts +21 -1
  29. package/dist/_internal/platform/daemon/surface-actions.d.ts.map +1 -1
  30. package/dist/_internal/platform/daemon/surface-actions.js +184 -0
  31. package/dist/_internal/platform/daemon/surface-delivery.d.ts.map +1 -1
  32. package/dist/_internal/platform/daemon/surface-delivery.js +2 -0
  33. package/dist/_internal/platform/integrations/index.d.ts +1 -1
  34. package/dist/_internal/platform/integrations/index.d.ts.map +1 -1
  35. package/dist/_internal/platform/integrations/index.js +1 -1
  36. package/dist/_internal/platform/integrations/ntfy.d.ts +11 -0
  37. package/dist/_internal/platform/integrations/ntfy.d.ts.map +1 -1
  38. package/dist/_internal/platform/integrations/ntfy.js +266 -30
  39. package/dist/_internal/platform/providers/registry.d.ts +1 -0
  40. package/dist/_internal/platform/providers/registry.d.ts.map +1 -1
  41. package/dist/_internal/platform/providers/registry.js +15 -5
  42. package/dist/_internal/platform/runtime/emitters/agents.d.ts +3 -0
  43. package/dist/_internal/platform/runtime/emitters/agents.d.ts.map +1 -1
  44. package/dist/_internal/platform/runtime/events/agents.d.ts +3 -0
  45. package/dist/_internal/platform/runtime/events/agents.d.ts.map +1 -1
  46. package/dist/_internal/platform/tools/agent/manager.d.ts.map +1 -1
  47. package/dist/_internal/platform/tools/agent/manager.js +3 -0
  48. package/dist/_internal/platform/version.js +1 -1
  49. package/package.json +1 -1
  50. package/dist/_internal/platform/runtime/contracts/index.d.ts +0 -40
  51. package/dist/_internal/platform/runtime/contracts/index.d.ts.map +0 -1
  52. package/dist/_internal/platform/runtime/contracts/index.js +0 -133
  53. package/dist/_internal/platform/runtime/contracts/migrations/index.d.ts +0 -75
  54. package/dist/_internal/platform/runtime/contracts/migrations/index.d.ts.map +0 -1
  55. package/dist/_internal/platform/runtime/contracts/migrations/index.js +0 -158
  56. package/dist/_internal/platform/runtime/contracts/migrations/schemas.d.ts +0 -57
  57. package/dist/_internal/platform/runtime/contracts/migrations/schemas.d.ts.map +0 -1
  58. package/dist/_internal/platform/runtime/contracts/migrations/schemas.js +0 -157
  59. package/dist/_internal/platform/runtime/contracts/types.d.ts +0 -123
  60. package/dist/_internal/platform/runtime/contracts/types.d.ts.map +0 -1
  61. package/dist/_internal/platform/runtime/contracts/types.js +0 -41
  62. package/dist/_internal/platform/runtime/contracts/validators/event-envelope.d.ts +0 -24
  63. package/dist/_internal/platform/runtime/contracts/validators/event-envelope.d.ts.map +0 -1
  64. package/dist/_internal/platform/runtime/contracts/validators/event-envelope.js +0 -104
  65. package/dist/_internal/platform/runtime/contracts/validators/index.d.ts +0 -11
  66. package/dist/_internal/platform/runtime/contracts/validators/index.d.ts.map +0 -1
  67. package/dist/_internal/platform/runtime/contracts/validators/index.js +0 -10
  68. package/dist/_internal/platform/runtime/contracts/validators/runtime-state.d.ts +0 -23
  69. package/dist/_internal/platform/runtime/contracts/validators/runtime-state.d.ts.map +0 -1
  70. package/dist/_internal/platform/runtime/contracts/validators/runtime-state.js +0 -101
  71. package/dist/_internal/platform/runtime/contracts/validators/session.d.ts +0 -24
  72. package/dist/_internal/platform/runtime/contracts/validators/session.d.ts.map +0 -1
  73. package/dist/_internal/platform/runtime/contracts/validators/session.js +0 -103
  74. package/dist/_internal/platform/runtime/contracts/version.d.ts +0 -84
  75. package/dist/_internal/platform/runtime/contracts/version.d.ts.map +0 -1
  76. package/dist/_internal/platform/runtime/contracts/version.js +0 -41
@@ -1 +1 @@
1
- {"version":3,"file":"telemetry-routes.d.ts","sourceRoot":"","sources":["../../../src/_internal/daemon/telemetry-routes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"telemetry-routes.d.ts","sourceRoot":"","sources":["../../../src/_internal/daemon/telemetry-routes.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { buildMissingScopeBody } from './http-policy.js';
2
+ import { decodeOtlpProtobuf } from './otlp-protobuf.js';
2
3
  import { DaemonErrorCategory } from '../errors/index.js';
3
4
  function parseNumber(value) {
4
5
  if (value === null || value.trim().length === 0)
@@ -45,10 +46,9 @@ function buildFilter(url) {
45
46
  // ---------------------------------------------------------------------------
46
47
  /** Max ingest payload (4 MiB) — reject larger bodies with 413 */
47
48
  const OTLP_INGEST_MAX_BODY_BYTES = 4 * 1024 * 1024;
48
- /** Accepted content-types for OTLP/HTTP JSON only; protobuf returns 415 */
49
- const OTLP_ACCEPTED_CONTENT_TYPES = [
50
- 'application/json',
51
- ];
49
+ /** Accepted content-types for OTLP/HTTP ingest. */
50
+ const OTLP_JSON_CONTENT_TYPE = 'application/json';
51
+ const OTLP_PROTOBUF_CONTENT_TYPES = new Set(['application/x-protobuf', 'application/protobuf']);
52
52
  const OTLP_PARTIAL_SUCCESS_KEYS = {
53
53
  logs: 'partialSuccess',
54
54
  traces: 'partialSuccess',
@@ -58,18 +58,19 @@ const OTLP_PARTIAL_SUCCESS_KEYS = {
58
58
  * Validate and parse an OTLP HTTP ingest request body.
59
59
  * Returns a parsed JSON Record on success, or a Response (error) on failure.
60
60
  *
61
- * Protocol: OTLP/HTTP spec §4.2 — only application/json is accepted in this
62
- * release. application/x-protobuf returns 415; protobuf decoding is planned
63
- * for a future release.
61
+ * Protocol: OTLP/HTTP spec §4.2 — supports JSON and binary protobuf service
62
+ * requests for logs, traces, and metrics.
64
63
  */
65
- async function parseOtlpBody(req) {
64
+ async function parseOtlpBody(req, kind) {
66
65
  const contentType = (req.headers.get('content-type') ?? '').toLowerCase().split(';')[0].trim();
67
- if (!OTLP_ACCEPTED_CONTENT_TYPES.some((ct) => contentType === ct)) {
66
+ const acceptsJson = contentType === OTLP_JSON_CONTENT_TYPE;
67
+ const acceptsProtobuf = OTLP_PROTOBUF_CONTENT_TYPES.has(contentType);
68
+ if (!acceptsJson && !acceptsProtobuf) {
68
69
  return Response.json({
69
70
  error: `Unsupported Content-Type '${contentType}' for OTLP ingest`,
70
71
  code: 'UNSUPPORTED_MEDIA_TYPE',
71
72
  category: DaemonErrorCategory.BAD_REQUEST,
72
- hint: `Use 'application/json'. Protobuf decoding is not implemented in this release — planned for a future release.`,
73
+ hint: `Use '${OTLP_JSON_CONTENT_TYPE}' or 'application/x-protobuf'.`,
73
74
  }, { status: 415 });
74
75
  }
75
76
  const raw = await req.arrayBuffer();
@@ -80,6 +81,14 @@ async function parseOtlpBody(req) {
80
81
  category: DaemonErrorCategory.BAD_REQUEST,
81
82
  }, { status: 413 });
82
83
  }
84
+ if (acceptsProtobuf) {
85
+ try {
86
+ return decodeOtlpProtobuf(kind, new Uint8Array(raw));
87
+ }
88
+ catch {
89
+ return Response.json({ error: 'OTLP ingest body is not valid protobuf', code: 'INVALID_PAYLOAD', category: DaemonErrorCategory.BAD_REQUEST }, { status: 400 });
90
+ }
91
+ }
83
92
  try {
84
93
  const text = new TextDecoder().decode(raw);
85
94
  const parsed = JSON.parse(text);
@@ -289,7 +298,7 @@ export function createDaemonTelemetryRouteHandlers(context) {
289
298
  if (!auth) {
290
299
  return Response.json({ error: 'Authentication required for OTLP ingest', code: 'AUTH_REQUIRED', category: DaemonErrorCategory.AUTHENTICATION, status: 401 }, { status: 401 });
291
300
  }
292
- const bodyOrErr = await parseOtlpBody(req);
301
+ const bodyOrErr = await parseOtlpBody(req, 'logs');
293
302
  if (bodyOrErr instanceof Response)
294
303
  return bodyOrErr;
295
304
  context.ingestSink?.ingestLogs(bodyOrErr);
@@ -300,7 +309,7 @@ export function createDaemonTelemetryRouteHandlers(context) {
300
309
  if (!auth) {
301
310
  return Response.json({ error: 'Authentication required for OTLP ingest', code: 'AUTH_REQUIRED', category: DaemonErrorCategory.AUTHENTICATION, status: 401 }, { status: 401 });
302
311
  }
303
- const bodyOrErr = await parseOtlpBody(req);
312
+ const bodyOrErr = await parseOtlpBody(req, 'traces');
304
313
  if (bodyOrErr instanceof Response)
305
314
  return bodyOrErr;
306
315
  context.ingestSink?.ingestTraces(bodyOrErr);
@@ -311,7 +320,7 @@ export function createDaemonTelemetryRouteHandlers(context) {
311
320
  if (!auth) {
312
321
  return Response.json({ error: 'Authentication required for OTLP ingest', code: 'AUTH_REQUIRED', category: DaemonErrorCategory.AUTHENTICATION, status: 401 }, { status: 401 });
313
322
  }
314
- const bodyOrErr = await parseOtlpBody(req);
323
+ const bodyOrErr = await parseOtlpBody(req, 'metrics');
315
324
  if (bodyOrErr instanceof Response)
316
325
  return bodyOrErr;
317
326
  context.ingestSink?.ingestMetrics(bodyOrErr);
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/adapters/ntfy/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4B9G;AAED,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,qBAAqB,EAC9B,GAAG,CAAC,EAAE,GAAG,GACR,OAAO,CAAC,QAAQ,CAAC,CAgFnB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/adapters/ntfy/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAQzD,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4B9G;AAED,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,qBAAqB,EAC9B,GAAG,CAAC,EAAE,GAAG,GACR,OAAO,CAAC,QAAQ,CAAC,CAyBnB"}
@@ -1,4 +1,6 @@
1
+ import { randomUUID } from 'node:crypto';
1
2
  import { parseJsonRecord, readBearerOrHeaderToken, readTextBodyWithinLimit } from '../helpers.js';
3
+ import { GOODVIBES_NTFY_AGENT_TOPIC, GOODVIBES_NTFY_CHAT_TOPIC, GOODVIBES_NTFY_REMOTE_TOPIC, isGoodVibesNtfyDeliveryEcho, } from '../../integrations/ntfy.js';
2
4
  export async function handleNtfySurfaceWebhook(req, context) {
3
5
  const enabled = Boolean(context.configManager.get('surfaces.ntfy.enabled'));
4
6
  const configuredToken = String(context.configManager.get('surfaces.ntfy.token') ?? '')
@@ -30,6 +32,9 @@ export async function handleNtfySurfaceWebhook(req, context) {
30
32
  return handleNtfySurfacePayload(body, context, new URL(req.url));
31
33
  }
32
34
  export async function handleNtfySurfacePayload(body, context, url) {
35
+ if (isGoodVibesNtfyDeliveryEcho(body)) {
36
+ return Response.json({ acknowledged: true, queued: false, ignored: 'goodvibes-self-echo' });
37
+ }
33
38
  const topic = typeof body.topic === 'string'
34
39
  ? body.topic
35
40
  : url?.searchParams.get('topic') ?? '';
@@ -41,6 +46,18 @@ export async function handleNtfySurfacePayload(body, context, url) {
41
46
  if (!topic) {
42
47
  return Response.json({ error: 'Missing ntfy topic' }, { status: 400 });
43
48
  }
49
+ if (topic === GOODVIBES_NTFY_CHAT_TOPIC) {
50
+ return handleNtfyChatPayload(body, context, topic, message);
51
+ }
52
+ if (topic === GOODVIBES_NTFY_REMOTE_TOPIC) {
53
+ return handleNtfyRemoteChatPayload(body, context, topic, message);
54
+ }
55
+ if (topic !== GOODVIBES_NTFY_AGENT_TOPIC) {
56
+ return Response.json({ acknowledged: true, queued: false, ignored: 'unknown-ntfy-topic', topic });
57
+ }
58
+ return handleNtfyAgentPayload(body, context, topic, message);
59
+ }
60
+ async function authorizeNtfyPayload(body, context, topic, message) {
44
61
  const policy = await context.authorizeSurfaceIngress({
45
62
  surface: 'ntfy',
46
63
  channelId: topic,
@@ -53,6 +70,81 @@ export async function handleNtfySurfacePayload(body, context, url) {
53
70
  if (!policy.allowed) {
54
71
  return Response.json({ error: `Blocked by channel policy: ${policy.reason}` }, { status: 403 });
55
72
  }
73
+ return null;
74
+ }
75
+ async function handleNtfyChatPayload(body, context, topic, message) {
76
+ const denied = await authorizeNtfyPayload(body, context, topic, message);
77
+ if (denied)
78
+ return denied;
79
+ if (!message) {
80
+ return Response.json({ acknowledged: true, queued: false, topic });
81
+ }
82
+ if (!context.publishConversationFollowup) {
83
+ return Response.json({ error: 'ntfy chat routing is unavailable in this runtime' }, { status: 503 });
84
+ }
85
+ const session = await context.sessionBroker.findPreferredSession({ surfaceKind: 'tui' });
86
+ if (!session) {
87
+ return Response.json({ error: 'No active terminal TUI session is available for ntfy chat' }, { status: 409 });
88
+ }
89
+ const messageId = randomUUID();
90
+ const timestamp = Date.now();
91
+ await context.sessionBroker.appendCompanionMessage(session.id, {
92
+ messageId,
93
+ body: message,
94
+ source: 'ntfy-chat',
95
+ timestamp,
96
+ });
97
+ context.queueNtfyChatReply?.({
98
+ sessionId: session.id,
99
+ topic,
100
+ body: message,
101
+ title: typeof body.title === 'string' ? body.title : 'GoodVibes chat',
102
+ messageId,
103
+ });
104
+ context.publishConversationFollowup(session.id, {
105
+ messageId,
106
+ body: message,
107
+ source: 'ntfy-chat',
108
+ timestamp,
109
+ metadata: { surface: 'ntfy', topic },
110
+ });
111
+ return Response.json({
112
+ acknowledged: true,
113
+ queued: false,
114
+ routedTo: 'tui-chat',
115
+ sessionId: session.id,
116
+ messageId,
117
+ topic,
118
+ }, { status: 202 });
119
+ }
120
+ async function handleNtfyRemoteChatPayload(body, context, topic, message) {
121
+ const denied = await authorizeNtfyPayload(body, context, topic, message);
122
+ if (denied)
123
+ return denied;
124
+ if (!message) {
125
+ return Response.json({ acknowledged: true, queued: false, topic });
126
+ }
127
+ if (!context.postNtfyRemoteChatMessage) {
128
+ return Response.json({ error: 'ntfy remote chat is unavailable in this runtime' }, { status: 503 });
129
+ }
130
+ const result = await context.postNtfyRemoteChatMessage({
131
+ topic,
132
+ body: message,
133
+ title: typeof body.title === 'string' ? body.title : 'GoodVibes ntfy',
134
+ });
135
+ return Response.json({
136
+ acknowledged: true,
137
+ queued: false,
138
+ routedTo: 'ntfy-remote-chat',
139
+ ...result,
140
+ topic,
141
+ }, { status: result.error ? 502 : 202 });
142
+ }
143
+ async function handleNtfyAgentPayload(body, context, topic, message) {
144
+ const denied = await authorizeNtfyPayload(body, context, topic, message);
145
+ if (denied)
146
+ return denied;
147
+ const preferredTuiSession = await context.sessionBroker.findPreferredSession({ surfaceKind: 'tui' });
56
148
  const binding = await context.routeBindings.upsertBinding({
57
149
  kind: 'channel',
58
150
  surfaceKind: 'ntfy',
@@ -66,6 +158,7 @@ export async function handleNtfySurfacePayload(body, context, url) {
66
158
  return Response.json({ acknowledged: true, queued: false, bindingId: binding.id });
67
159
  }
68
160
  const submission = await context.sessionBroker.submitMessage({
161
+ ...(preferredTuiSession ? { sessionId: preferredTuiSession.id } : {}),
69
162
  routeId: binding.id,
70
163
  surfaceKind: 'ntfy',
71
164
  surfaceId: binding.surfaceId,
@@ -4,6 +4,7 @@ import type { AutomationRouteBinding } from '../automation/routes.js';
4
4
  import type { AutomationSurfaceKind } from '../automation/types.js';
5
5
  import type { ChannelConversationKind, ChannelPolicyDecision, RouteBindingManager } from '../channels/index.js';
6
6
  import type { SharedSessionBroker } from '../control-plane/index.js';
7
+ import type { ConversationMessageEnvelope } from '../control-plane/conversation-message.js';
7
8
  import type { ServiceRegistry } from '../config/service-registry.js';
8
9
  export interface SurfaceControlCommand {
9
10
  readonly action: 'status' | 'cancel' | 'retry';
@@ -14,6 +15,19 @@ export interface QueueSurfaceReplyInput {
14
15
  readonly task: string;
15
16
  readonly sessionId?: string;
16
17
  }
18
+ export interface QueueNtfyChatReplyInput {
19
+ readonly sessionId: string;
20
+ readonly topic: string;
21
+ readonly body: string;
22
+ readonly title?: string;
23
+ readonly messageId: string;
24
+ }
25
+ export interface NtfyRemoteChatResult {
26
+ readonly sessionId: string;
27
+ readonly messageId: string;
28
+ readonly delivered: boolean;
29
+ readonly error?: string;
30
+ }
17
31
  export type TrySpawnAgentInput = Parameters<AgentManager['spawn']>[0];
18
32
  export type TrySpawnAgentResult = AgentRecord | Response;
19
33
  export type TrySpawnAgentFn = (input: TrySpawnAgentInput, logLabel: string, sessionId?: string) => TrySpawnAgentResult;
@@ -43,6 +57,13 @@ export interface SurfaceAdapterContext {
43
57
  readonly performInteractiveSurfaceAction: (actionId: string, surface: 'slack' | 'discord', req: Request) => Promise<string>;
44
58
  readonly trySpawnAgent: TrySpawnAgentFn;
45
59
  readonly queueSurfaceReplyFromBinding: (binding: AutomationRouteBinding | undefined, input: QueueSurfaceReplyInput) => void;
60
+ readonly publishConversationFollowup?: (sessionId: string, envelope: Omit<ConversationMessageEnvelope, 'sessionId'>) => void;
61
+ readonly queueNtfyChatReply?: (input: QueueNtfyChatReplyInput) => void;
62
+ readonly postNtfyRemoteChatMessage?: (input: {
63
+ readonly topic: string;
64
+ readonly body: string;
65
+ readonly title?: string;
66
+ }) => Promise<NtfyRemoteChatResult>;
46
67
  }
47
68
  export interface GenericWebhookReplyInput {
48
69
  readonly agentId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/adapters/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAErE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC/C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG,QAAQ,CAAC;AACzD,MAAM,MAAM,eAAe,GAAG,CAC5B,KAAK,EAAE,kBAAkB,EACzB,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,KACf,mBAAmB,CAAC;AAEzB,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,aAAa,EAAE;QACtB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KAC3B,CAAC;IACF,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAC5C,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAC5C,QAAQ,CAAC,uBAAuB,EAAE,CAAC,KAAK,EAAE;QACxC,OAAO,EAAE,OAAO,CAAC,qBAAqB,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,aAAa,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,YAAY,GAAG,QAAQ,CAAC,CAAC;QAC9L,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,gBAAgB,CAAC,EAAE,uBAAuB,CAAC;QAC3C,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACrC,QAAQ,CAAC,0BAA0B,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,qBAAqB,GAAG,IAAI,CAAC;IACpF,QAAQ,CAAC,4BAA4B,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3F,QAAQ,CAAC,+BAA+B,EAAE,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,GAAG,EAAE,OAAO,KACT,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;IACxC,QAAQ,CAAC,4BAA4B,EAAE,CACrC,OAAO,EAAE,sBAAsB,GAAG,SAAS,EAC3C,KAAK,EAAE,sBAAsB,KAC1B,IAAI,CAAC;CACX;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,eAAe,GAAG,aAAa,CAAC;CAC9D;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,aAAa,EAAE;QACtB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KAC3B,CAAC;IACF,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAC5C,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAC5C,QAAQ,CAAC,uBAAuB,EAAE,CAAC,KAAK,EAAE;QACxC,OAAO,EAAE,OAAO,CAAC,qBAAqB,EAAE,SAAS,CAAC,CAAC;QACnD,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,gBAAgB,CAAC,EAAE,uBAAuB,CAAC;QAC3C,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC;IACxC,QAAQ,CAAC,sBAAsB,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,qBAAqB,EAAE,SAAS,CAAC,KAAK,OAAO,CAAC;IACjG,QAAQ,CAAC,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACtE,QAAQ,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACvE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/adapters/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"setup-schema.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/channels/builtin/setup-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EAClB,cAAc,EACf,MAAM,aAAa,CAAC;AAMrB,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,GAAG,kBAAkB,CAucjF"}
1
+ {"version":3,"file":"setup-schema.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/channels/builtin/setup-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EAClB,cAAc,EACf,MAAM,aAAa,CAAC;AAMrB,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,GAAG,kBAAkB,CAwcjF"}
@@ -116,11 +116,11 @@ export function getBuiltinSetupSchema(surface) {
116
116
  version: CHANNEL_SETUP_VERSION,
117
117
  label: 'ntfy',
118
118
  setupMode: 'webhook',
119
- description: 'ntfy is a notification surface backed by a topic, optional token, and subscription URLs.',
119
+ description: 'ntfy is a notification and remote-control surface backed by SDK-owned inbound topics, optional delivery topics, and optional authentication.',
120
120
  fields: [
121
121
  setupField('enabled', 'Enabled', 'boolean', false, { configKey: 'surfaces.ntfy.enabled', defaultValue: false }),
122
122
  setupField('baseUrl', 'Base URL', 'url', false, { configKey: 'surfaces.ntfy.baseUrl', placeholder: 'https://ntfy.sh' }),
123
- setupField('topic', 'Topic', 'string', true, { configKey: 'surfaces.ntfy.topic' }),
123
+ setupField('topic', 'Default delivery topic', 'string', false, { configKey: 'surfaces.ntfy.topic' }),
124
124
  setupField('token', 'Access token', 'secret', false, { configKey: 'surfaces.ntfy.token', secretTargetId: 'primary' }),
125
125
  ],
126
126
  secretTargets: [
@@ -132,7 +132,8 @@ export function getBuiltinSetupSchema(surface) {
132
132
  }),
133
133
  ],
134
134
  externalSteps: [
135
- 'Choose or create an ntfy topic.',
135
+ 'Subscribe the daemon to the SDK-owned goodvibes-chat, goodvibes-agent, and goodvibes-ntfy topics.',
136
+ 'Optionally configure a default delivery topic for outbound notifications.',
136
137
  'Optionally configure an authenticated ntfy token.',
137
138
  'Use provider actions to inspect subscribe and poll URLs.',
138
139
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"strategies-core.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/channels/delivery/strategies-core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAGrE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAc1D,wBAAgB,6BAA6B,CAAC,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,GAAG,uBAAuB,CAsCjI;AAED,wBAAgB,2BAA2B,CACzC,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CA0CzB;AAED,wBAAgB,6BAA6B,CAC3C,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CA2CzB;AAED,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CAuBzB;AAED,wBAAgB,qCAAqC,CACnD,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,MAAM,mBAAmB,GAAG,IAAI,GAC3C,uBAAuB,CA6BzB;AAED,wBAAgB,8BAA8B,CAC5C,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CAqCzB;AAED,wBAAgB,gCAAgC,CAC9C,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CA+BzB"}
1
+ {"version":3,"file":"strategies-core.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/channels/delivery/strategies-core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAGrE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAc1D,wBAAgB,6BAA6B,CAAC,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,GAAG,uBAAuB,CAsCjI;AAED,wBAAgB,2BAA2B,CACzC,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CA0CzB;AAED,wBAAgB,6BAA6B,CAC3C,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CA2CzB;AAED,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CAwBzB;AAED,wBAAgB,qCAAqC,CACnD,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,MAAM,mBAAmB,GAAG,IAAI,GAC3C,uBAAuB,CA6BzB;AAED,wBAAgB,8BAA8B,CAC5C,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CAqCzB;AAED,wBAAgB,gCAAgC,CAC9C,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CA+BzB"}
@@ -145,6 +145,7 @@ export function createNtfyDeliveryStrategy(configManager, serviceRegistry, artif
145
145
  title: request.target.label ?? titleFromBody(request.body),
146
146
  ...(request.includeLinks && baseUrlHint ? { click: `${baseUrlHint.replace(/\/+$/, '')}/api/control-plane/web` } : {}),
147
147
  ...(primaryAttachment?.contentUrl ? { attach: primaryAttachment.contentUrl } : {}),
148
+ markGoodVibesOrigin: true,
148
149
  });
149
150
  return success(topic);
150
151
  },
@@ -45,7 +45,7 @@ export declare class ChannelProviderRuntimeManager {
45
45
  private resolveSlackAppToken;
46
46
  private resolveDiscordBotToken;
47
47
  private resolveNtfyToken;
48
- private resolveNtfyTopic;
48
+ private resolveNtfyTopics;
49
49
  private isConfigured;
50
50
  private markStarted;
51
51
  private markStopped;
@@ -1 +1 @@
1
- {"version":3,"file":"provider-runtime.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/channels/provider-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAWrE,OAAO,EACL,KAAK,qBAAqB,EAI3B,MAAM,sBAAsB,CAAC;AAI9B,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC;IAC9D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,UAAU,0BAA0B;IAClC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;CAClE;AAeD,qBAAa,6BAA6B;IAU5B,OAAO,CAAC,QAAQ,CAAC,IAAI;IATjC,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAIpB;gBAE2B,IAAI,EAAE,0BAA0B;IAEvD,eAAe,IAAI,OAAO,CAAC,2BAA2B,EAAE,CAAC;IAczD,KAAK,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAMlF,IAAI,CAAC,OAAO,EAAE,sBAAsB,GAAG,2BAA2B;IAmBlE,OAAO,IAAI,IAAI;IAMf,MAAM,CAAC,OAAO,EAAE,sBAAsB,GAAG,qBAAqB;YAchD,UAAU;YAoCV,YAAY;YA8BZ,SAAS;YA6BT,mBAAmB;YASnB,qBAAqB;YASrB,iBAAiB;YASjB,oBAAoB;YAQpB,oBAAoB;YAMpB,sBAAsB;YAQtB,gBAAgB;IAQ9B,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,MAAM;CAQf"}
1
+ {"version":3,"file":"provider-runtime.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/channels/provider-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAYrE,OAAO,EACL,KAAK,qBAAqB,EAI3B,MAAM,sBAAsB,CAAC;AAI9B,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC;IAC9D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,UAAU,0BAA0B;IAClC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;CAClE;AAeD,qBAAa,6BAA6B;IAU5B,OAAO,CAAC,QAAQ,CAAC,IAAI;IATjC,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAIpB;gBAE2B,IAAI,EAAE,0BAA0B;IAEvD,eAAe,IAAI,OAAO,CAAC,2BAA2B,EAAE,CAAC;IAczD,KAAK,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAMlF,IAAI,CAAC,OAAO,EAAE,sBAAsB,GAAG,2BAA2B;IAmBlE,OAAO,IAAI,IAAI;IAMf,MAAM,CAAC,OAAO,EAAE,sBAAsB,GAAG,qBAAqB;YAchD,UAAU;YAoCV,YAAY;YA8BZ,SAAS;YA8BT,mBAAmB;YASnB,qBAAqB;YASrB,iBAAiB;YASjB,oBAAoB;YAQpB,oBAAoB;YAMpB,sBAAsB;YAQtB,gBAAgB;IAQ9B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,MAAM;CAQf"}
@@ -1,4 +1,4 @@
1
- import { DiscordGatewayClient, DiscordIntegration, NtfyIntegration, SlackIntegration, SlackSocketModeClient, } from '../integrations/index.js';
1
+ import { DiscordGatewayClient, DiscordIntegration, GOODVIBES_NTFY_DEFAULT_TOPICS, NtfyIntegration, SlackIntegration, SlackSocketModeClient, } from '../integrations/index.js';
2
2
  import { handleDiscordGatewayDispatchPayload, handleNtfySurfacePayload, handleSlackSurfacePayload, } from '../adapters/index.js';
3
3
  import { logger } from '../utils/logger.js';
4
4
  import { summarizeError } from '../utils/error-display.js';
@@ -27,7 +27,7 @@ export class ChannelProviderRuntimeManager {
27
27
  if (this.deps.configManager.get('surfaces.discord.enabled') && await this.resolveDiscordBotToken()) {
28
28
  results.push(await this.start('discord'));
29
29
  }
30
- if (this.deps.configManager.get('surfaces.ntfy.enabled') && this.resolveNtfyTopic()) {
30
+ if (this.deps.configManager.get('surfaces.ntfy.enabled') && this.resolveNtfyTopics().length > 0) {
31
31
  results.push(await this.start('ntfy'));
32
32
  }
33
33
  return results;
@@ -139,16 +139,17 @@ export class ChannelProviderRuntimeManager {
139
139
  if (this.ntfyAbort) {
140
140
  return this.result('ntfy', true, 'ntfy JSON stream runtime is already running.');
141
141
  }
142
- const topic = this.resolveNtfyTopic();
143
- if (!topic) {
142
+ const topics = this.resolveNtfyTopics();
143
+ if (topics.length === 0) {
144
144
  this.markError('ntfy', 'ntfy topic is required for subscription runtime.');
145
145
  return this.result('ntfy', false, 'ntfy topic is required for subscription runtime.');
146
146
  }
147
147
  const abort = new AbortController();
148
148
  this.ntfyAbort = abort;
149
149
  const ntfy = new NtfyIntegration(String(this.deps.configManager.get('surfaces.ntfy.baseUrl') || 'https://ntfy.sh'), await this.resolveNtfyToken() ?? undefined);
150
- this.markStarted('ntfy', { topic });
151
- void ntfy.subscribeJsonStream(topic, (message) => this.handleNtfyMessage(message), {
150
+ const topicList = topics.join(',');
151
+ this.markStarted('ntfy', { topics });
152
+ void ntfy.subscribeJsonStream(topicList, (message) => this.handleNtfyMessage(message), {
152
153
  since: 'latest',
153
154
  signal: abort.signal,
154
155
  }).catch((error) => {
@@ -213,8 +214,12 @@ export class ChannelProviderRuntimeManager {
213
214
  || process.env.NTFY_ACCESS_TOKEN
214
215
  || null;
215
216
  }
216
- resolveNtfyTopic() {
217
- return String(this.deps.configManager.get('surfaces.ntfy.topic') || '').trim();
217
+ resolveNtfyTopics() {
218
+ const configured = String(this.deps.configManager.get('surfaces.ntfy.topic') || '')
219
+ .split(',')
220
+ .map((topic) => topic.trim())
221
+ .filter((topic) => topic.length > 0);
222
+ return [...new Set([...GOODVIBES_NTFY_DEFAULT_TOPICS, ...configured])];
218
223
  }
219
224
  isConfigured(surface) {
220
225
  if (surface === 'slack') {
@@ -223,7 +228,7 @@ export class ChannelProviderRuntimeManager {
223
228
  if (surface === 'discord') {
224
229
  return Boolean(this.deps.configManager.get('surfaces.discord.botToken') || process.env.DISCORD_BOT_TOKEN);
225
230
  }
226
- return Boolean(this.resolveNtfyTopic());
231
+ return this.resolveNtfyTopics().length > 0;
227
232
  }
228
233
  markStarted(surface, metadata) {
229
234
  this.state[surface] = {
@@ -34,6 +34,7 @@ export declare class ChannelReplyPipeline {
34
34
  deliverProgress(agentId: string, explicitText?: string, force?: boolean): Promise<ChannelRenderResult | null>;
35
35
  deliverFinal(agentId: string, explicitText: string): Promise<ChannelRenderResult | null>;
36
36
  private handleEnvelope;
37
+ private trackChildPendingReply;
37
38
  private resolvePolicy;
38
39
  private dispatch;
39
40
  private disposeSubscriptions;
@@ -1 +1 @@
1
- {"version":3,"file":"reply-pipeline.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/channels/reply-pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACzG,OAAO,KAAK,EACV,kBAAkB,EAIlB,mBAAmB,EAEnB,cAAc,EACf,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAK9D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,UAAU,iBAAiB;IACzB,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC;IAC/C,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAyOD,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,oBAAoB,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC,GACvE,kBAAkB,EAAE,CAyFtB;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;IACvD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IACpD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyB;gBAE3C,IAAI,EAAE,iBAAiB;IAOnC,gBAAgB,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI;IAmB1D,OAAO,IAAI,IAAI;IAKf,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAOhD,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI9B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI7B,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI;IAIjD,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAe3G,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;YAwBhF,cAAc;YA2Bd,aAAa;YAIb,QAAQ;IAgCtB,OAAO,CAAC,oBAAoB;CAK7B"}
1
+ {"version":3,"file":"reply-pipeline.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/channels/reply-pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACzG,OAAO,KAAK,EACV,kBAAkB,EAIlB,mBAAmB,EAEnB,cAAc,EACf,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAK9D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,UAAU,iBAAiB;IACzB,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC;IAC/C,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AA+OD,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,oBAAoB,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC,GACvE,kBAAkB,EAAE,CAyFtB;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;IACvD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IACpD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyB;gBAE3C,IAAI,EAAE,iBAAiB;IAOnC,gBAAgB,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI;IAmB1D,OAAO,IAAI,IAAI;IAKf,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAOhD,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI9B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI7B,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI;IAIjD,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAe3G,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;YAwBhF,cAAc;IAsC5B,OAAO,CAAC,sBAAsB;YAmBhB,aAAa;YAIb,QAAQ;IAgCtB,OAAO,CAAC,oBAAoB;CAK7B"}
@@ -211,6 +211,12 @@ function renderEvent(kind, phase, envelope, extras = {}) {
211
211
  ...extras,
212
212
  };
213
213
  }
214
+ function resolveEnvelopeAgentId(envelope) {
215
+ if (envelope.agentId)
216
+ return envelope.agentId;
217
+ const payload = envelope.payload;
218
+ return typeof payload.agentId === 'string' ? payload.agentId : null;
219
+ }
214
220
  export function normalizeChannelRenderEventFromRuntime(envelope) {
215
221
  const payload = envelope.payload;
216
222
  switch (payload.type) {
@@ -386,7 +392,12 @@ export class ChannelReplyPipeline {
386
392
  return result;
387
393
  }
388
394
  async handleEnvelope(envelope) {
389
- const agentId = envelope.agentId;
395
+ if (envelope.payload.type === 'AGENT_SPAWNING'
396
+ && typeof envelope.payload.parentAgentId === 'string'
397
+ && envelope.payload.parentAgentId.length > 0) {
398
+ this.trackChildPendingReply(envelope.payload.agentId, envelope.payload.parentAgentId, envelope.payload.task);
399
+ }
400
+ const agentId = resolveEnvelopeAgentId(envelope);
390
401
  if (!agentId)
391
402
  return;
392
403
  const state = this.buffers.get(agentId);
@@ -412,6 +423,26 @@ export class ChannelReplyPipeline {
412
423
  }
413
424
  await this.deliverProgress(agentId);
414
425
  }
426
+ trackChildPendingReply(agentId, parentAgentId, task) {
427
+ if (this.buffers.has(agentId))
428
+ return;
429
+ const parentState = this.buffers.get(parentAgentId);
430
+ if (!parentState)
431
+ return;
432
+ const rootAgentId = typeof parentState.pending.rootAgentId === 'string'
433
+ ? parentState.pending.rootAgentId
434
+ : parentAgentId;
435
+ this.buffers.set(agentId, {
436
+ pending: {
437
+ ...parentState.pending,
438
+ agentId,
439
+ task,
440
+ parentAgentId,
441
+ rootAgentId,
442
+ },
443
+ events: [],
444
+ });
445
+ }
415
446
  async resolvePolicy(surface) {
416
447
  return await this.channelPlugins.getRenderPolicy(surface) ?? DEFAULT_POLICY[surface];
417
448
  }
@@ -50,6 +50,12 @@ export interface CompanionChatEventPublisher {
50
50
  clientId?: string;
51
51
  }): void;
52
52
  }
53
+ export interface CompanionChatReplyResult {
54
+ readonly messageId: string;
55
+ readonly assistantMessageId?: string;
56
+ readonly response?: string;
57
+ readonly error?: string;
58
+ }
53
59
  export interface CompanionChatManagerConfig {
54
60
  readonly provider: CompanionLLMProvider;
55
61
  readonly eventPublisher: CompanionChatEventPublisher;
@@ -90,6 +96,7 @@ export declare class CompanionChatManager {
90
96
  private gcTimer;
91
97
  /** Tracks whether the async init() has completed. */
92
98
  private initCompleted;
99
+ private readonly pendingReplies;
93
100
  /**
94
101
  * Serializes persistence writes per session to prevent write-after-write
95
102
  * races where two concurrent saves could result in an older snapshot
@@ -131,6 +138,10 @@ export declare class CompanionChatManager {
131
138
  * Pass '' to skip client-level rate limiting.
132
139
  */
133
140
  postMessage(sessionId: string, content: string, clientId?: string): Promise<string>;
141
+ postMessageAndWaitForReply(sessionId: string, content: string, clientId?: string, options?: {
142
+ readonly timeoutMs?: number;
143
+ }): Promise<CompanionChatReplyResult>;
144
+ private _postMessageInternal;
134
145
  dispose(): void;
135
146
  private _runTurn;
136
147
  _gcSweep(): void;
@@ -143,5 +154,6 @@ export declare class CompanionChatManager {
143
154
  */
144
155
  private _persist;
145
156
  private _doSave;
157
+ private resolvePendingReply;
146
158
  }
147
159
  //# sourceMappingURL=companion-chat-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"companion-chat-manager.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/companion/companion-chat-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"companion-chat-manager.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/companion/companion-chat-manager.ts"],"names":[],"mappings":"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"}
@@ -41,6 +41,7 @@ export class CompanionChatManager {
41
41
  gcTimer = null;
42
42
  /** Tracks whether the async init() has completed. */
43
43
  initCompleted = false;
44
+ pendingReplies = new Map();
44
45
  /**
45
46
  * Serializes persistence writes per session to prevent write-after-write
46
47
  * races where two concurrent saves could result in an older snapshot
@@ -195,6 +196,30 @@ export class CompanionChatManager {
195
196
  * Pass '' to skip client-level rate limiting.
196
197
  */
197
198
  async postMessage(sessionId, content, clientId = '') {
199
+ return await this._postMessageInternal(sessionId, content, clientId);
200
+ }
201
+ async postMessageAndWaitForReply(sessionId, content, clientId = '', options = {}) {
202
+ let messageId = '';
203
+ const result = new Promise((resolve) => {
204
+ const timeout = setTimeout(() => {
205
+ if (messageId)
206
+ this.pendingReplies.delete(messageId);
207
+ resolve({ messageId, error: 'Timed out waiting for companion chat reply' });
208
+ }, options.timeoutMs ?? 120_000);
209
+ timeout.unref?.();
210
+ void this._postMessageInternal(sessionId, content, clientId, { resolve, timeout })
211
+ .then((id) => { messageId = id; })
212
+ .catch((error) => {
213
+ clearTimeout(timeout);
214
+ resolve({
215
+ messageId,
216
+ error: error instanceof Error ? error.message : String(error),
217
+ });
218
+ });
219
+ });
220
+ return result;
221
+ }
222
+ async _postMessageInternal(sessionId, content, clientId, pendingReply) {
198
223
  const session = this.sessions.get(sessionId);
199
224
  if (!session) {
200
225
  throw Object.assign(new Error(`Session not found: ${sessionId}`), { code: 'SESSION_NOT_FOUND', status: 404 });
@@ -222,6 +247,9 @@ export class CompanionChatManager {
222
247
  });
223
248
  // Persist async (non-blocking)
224
249
  void this._persist(sessionId);
250
+ if (pendingReply) {
251
+ this.pendingReplies.set(messageId, pendingReply);
252
+ }
225
253
  // Fire-and-forget: run the turn without blocking the HTTP response
226
254
  void this._runTurn(session, messageId);
227
255
  return messageId;
@@ -367,11 +395,16 @@ export class CompanionChatManager {
367
395
  timestamp: now,
368
396
  };
369
397
  publish({ type: 'turn.completed', sessionId, turnId, assistantMessageId, envelope: completedEnvelope });
398
+ this.resolvePendingReply(userMessageId, { messageId: userMessageId, assistantMessageId, response: assistantContent });
370
399
  }
371
400
  catch (err) {
372
401
  if (!abortSignal.aborted) {
373
402
  const errorMessage = err instanceof Error ? err.message : String(err);
374
403
  publish({ type: 'turn.error', sessionId, turnId, error: errorMessage });
404
+ this.resolvePendingReply(userMessageId, { messageId: userMessageId, error: errorMessage });
405
+ }
406
+ else {
407
+ this.resolvePendingReply(userMessageId, { messageId: userMessageId, error: 'Turn cancelled' });
375
408
  }
376
409
  }
377
410
  }
@@ -434,4 +467,12 @@ export class CompanionChatManager {
434
467
  return;
435
468
  await this.persistence.save({ meta: session.meta, messages: session.messages });
436
469
  }
470
+ resolvePendingReply(messageId, result) {
471
+ const pending = this.pendingReplies.get(messageId);
472
+ if (!pending)
473
+ return;
474
+ this.pendingReplies.delete(messageId);
475
+ clearTimeout(pending.timeout);
476
+ pending.resolve(result);
477
+ }
437
478
  }