@amalgm/channels 0.1.1 → 0.1.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.
- package/PURPOSE.md +48 -13
- package/README.md +64 -6
- package/dist/host/auth.js +7 -3
- package/dist/host/auth.js.map +1 -1
- package/dist/host/config.d.ts +3 -1
- package/dist/host/config.js +3 -1
- package/dist/host/config.js.map +1 -1
- package/dist/host/inbox-repository.d.ts +10 -0
- package/dist/host/inbox-repository.js +57 -0
- package/dist/host/inbox-repository.js.map +1 -0
- package/dist/host/index.d.ts +4 -0
- package/dist/host/index.js +4 -0
- package/dist/host/index.js.map +1 -1
- package/dist/host/ingress-repository.d.ts +10 -0
- package/dist/host/ingress-repository.js +61 -0
- package/dist/host/ingress-repository.js.map +1 -0
- package/dist/host/main.js +32 -3
- package/dist/host/main.js.map +1 -1
- package/dist/host/repository.d.ts +4 -3
- package/dist/host/repository.js +23 -3
- package/dist/host/repository.js.map +1 -1
- package/dist/host/resend-webhook.d.ts +14 -0
- package/dist/host/resend-webhook.js +172 -0
- package/dist/host/resend-webhook.js.map +1 -0
- package/dist/host/resend.js +4 -0
- package/dist/host/resend.js.map +1 -1
- package/dist/host/server.d.ts +2 -1
- package/dist/host/server.js +85 -17
- package/dist/host/server.js.map +1 -1
- package/dist/host/wakeups.d.ts +22 -0
- package/dist/host/wakeups.js +30 -0
- package/dist/host/wakeups.js.map +1 -0
- package/dist/src/api-error.d.ts +2 -0
- package/dist/src/api-error.js +13 -0
- package/dist/src/api-error.js.map +1 -0
- package/dist/src/cli/arguments.d.ts +20 -0
- package/dist/src/cli/arguments.js +46 -0
- package/dist/src/cli/arguments.js.map +1 -0
- package/dist/src/cli/input.d.ts +6 -0
- package/dist/src/cli/input.js +38 -0
- package/dist/src/cli/input.js.map +1 -0
- package/dist/src/cli/main.d.ts +7 -0
- package/dist/src/cli/main.js +27 -0
- package/dist/src/cli/main.js.map +1 -0
- package/dist/src/cli/run.d.ts +13 -0
- package/dist/src/cli/run.js +47 -0
- package/dist/src/cli/run.js.map +1 -0
- package/dist/src/cli/shell-runtime.d.ts +9 -0
- package/dist/src/cli/shell-runtime.js +106 -0
- package/dist/src/cli/shell-runtime.js.map +1 -0
- package/dist/src/cli-main.d.ts +2 -0
- package/dist/src/cli-main.js +4 -0
- package/dist/src/cli-main.js.map +1 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.js +4 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/client.js +5 -4
- package/dist/src/client.js.map +1 -1
- package/dist/src/command-surface.d.ts +23 -0
- package/dist/src/command-surface.js +53 -0
- package/dist/src/command-surface.js.map +1 -0
- package/dist/src/contract.d.ts +33 -7
- package/dist/src/email/blocks.d.ts +7 -0
- package/dist/src/email/blocks.js +43 -0
- package/dist/src/email/blocks.js.map +1 -0
- package/dist/src/email/escape.d.ts +3 -0
- package/dist/src/email/escape.js +19 -0
- package/dist/src/email/escape.js.map +1 -0
- package/dist/src/email/inbound.d.ts +83 -0
- package/dist/src/email/inbound.js +162 -0
- package/dist/src/email/inbound.js.map +1 -0
- package/dist/src/email/inline.d.ts +1 -0
- package/dist/src/email/inline.js +31 -0
- package/dist/src/email/inline.js.map +1 -0
- package/dist/src/email/markdown.d.ts +1 -0
- package/dist/src/email/markdown.js +117 -0
- package/dist/src/email/markdown.js.map +1 -0
- package/dist/src/email/notification.d.ts +2 -0
- package/dist/src/email/notification.js +18 -0
- package/dist/src/email/notification.js.map +1 -0
- package/dist/src/email/styles.d.ts +33 -0
- package/dist/src/email/styles.js +34 -0
- package/dist/src/email/styles.js.map +1 -0
- package/dist/src/email/system.d.ts +13 -0
- package/dist/src/email/system.js +31 -0
- package/dist/src/email/system.js.map +1 -0
- package/dist/src/email/thread-token.d.ts +8 -0
- package/dist/src/email/thread-token.js +70 -0
- package/dist/src/email/thread-token.js.map +1 -0
- package/dist/src/errors.d.ts +3 -2
- package/dist/src/errors.js +3 -1
- package/dist/src/errors.js.map +1 -1
- package/dist/src/http.d.ts +2 -0
- package/dist/src/http.js +84 -3
- package/dist/src/http.js.map +1 -1
- package/dist/src/inbox/client.d.ts +7 -0
- package/dist/src/inbox/client.js +79 -0
- package/dist/src/inbox/client.js.map +1 -0
- package/dist/src/inbox/contract.d.ts +37 -0
- package/dist/src/inbox/contract.js +2 -0
- package/dist/src/inbox/contract.js.map +1 -0
- package/dist/src/inbox/events.d.ts +7 -0
- package/dist/src/inbox/events.js +46 -0
- package/dist/src/inbox/events.js.map +1 -0
- package/dist/src/inbox/runner.d.ts +14 -0
- package/dist/src/inbox/runner.js +93 -0
- package/dist/src/inbox/runner.js.map +1 -0
- package/dist/src/inbox/service.d.ts +9 -0
- package/dist/src/inbox/service.js +56 -0
- package/dist/src/inbox/service.js.map +1 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp.js +20 -52
- package/dist/src/mcp.js.map +1 -1
- package/dist/src/service.js +7 -3
- package/dist/src/service.js.map +1 -1
- package/dist/src/validation.d.ts +2 -2
- package/dist/src/validation.js +2 -2
- package/dist/src/validation.js.map +1 -1
- package/dist/src/worker.d.ts +4 -1
- package/dist/src/worker.js +27 -5
- package/dist/src/worker.js.map +1 -1
- package/package.json +12 -5
- package/skills/channels/SKILL.md +14 -14
- package/supabase/migrations/20260903000000_bidirectional_email.sql +630 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ChannelsError } from '../errors.js';
|
|
2
|
+
import { identifier } from '../validation.js';
|
|
3
|
+
export function createMachineInboxService(repository, events, options = {}) {
|
|
4
|
+
const now = options.now ?? (() => new Date());
|
|
5
|
+
return Object.freeze({
|
|
6
|
+
for(principal) {
|
|
7
|
+
const scopes = new Set(principal.scopes);
|
|
8
|
+
if (!scopes.has('channels:receive')) {
|
|
9
|
+
throw new ChannelsError('forbidden', 'Missing scope: channels:receive');
|
|
10
|
+
}
|
|
11
|
+
const userId = identifier(principal.userId, 'principal.userId');
|
|
12
|
+
const computerId = principal.computerId
|
|
13
|
+
? identifier(principal.computerId, 'principal.computerId')
|
|
14
|
+
: null;
|
|
15
|
+
if (!computerId)
|
|
16
|
+
throw new ChannelsError('forbidden', 'Machine identity is required');
|
|
17
|
+
return Object.freeze({
|
|
18
|
+
claim(input = {}) {
|
|
19
|
+
const leaseSeconds = integer(input.leaseSeconds ?? 60, 30, 900, 'leaseSeconds');
|
|
20
|
+
return repository.claim(userId, computerId, 1, leaseSeconds);
|
|
21
|
+
},
|
|
22
|
+
accept(message) {
|
|
23
|
+
return repository.accept(userId, computerId, lease(message), now());
|
|
24
|
+
},
|
|
25
|
+
release(message, error) {
|
|
26
|
+
return repository.release(userId, computerId, lease(message), bounded(error, 'error', 1, 500), now());
|
|
27
|
+
},
|
|
28
|
+
events(signal) {
|
|
29
|
+
return events(userId, computerId, signal);
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function lease(value) {
|
|
36
|
+
return Object.freeze({
|
|
37
|
+
id: identifier(value.id, 'message.id'),
|
|
38
|
+
leaseToken: identifier(value.leaseToken, 'message.leaseToken'),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function integer(value, minimum, maximum, name) {
|
|
42
|
+
if (!Number.isInteger(value) || value < minimum || value > maximum) {
|
|
43
|
+
throw new ChannelsError('validation', `${name} must be an integer from ${minimum} to ${maximum}`);
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
function bounded(value, name, minimum, maximum) {
|
|
48
|
+
if (typeof value !== 'string')
|
|
49
|
+
throw new ChannelsError('validation', `${name} must be a string`);
|
|
50
|
+
const clean = value.replace(/[\r\n]+/g, ' ').trim();
|
|
51
|
+
if (clean.length < minimum || clean.length > maximum) {
|
|
52
|
+
throw new ChannelsError('validation', `${name} must be ${minimum}-${maximum} characters`);
|
|
53
|
+
}
|
|
54
|
+
return clean;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/inbox/service.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
export * from './contract.js';
|
|
2
2
|
export * from './errors.js';
|
|
3
|
+
export * from './api-error.js';
|
|
3
4
|
export * from './validation.js';
|
|
4
5
|
export * from './service.js';
|
|
5
6
|
export * from './worker.js';
|
|
6
7
|
export * from './http.js';
|
|
7
8
|
export * from './client.js';
|
|
9
|
+
export * from './command-surface.js';
|
|
10
|
+
export * from './email/notification.js';
|
|
11
|
+
export * from './email/thread-token.js';
|
|
12
|
+
export * from './email/inbound.js';
|
|
13
|
+
export * from './email/system.js';
|
|
14
|
+
export * from './inbox/contract.js';
|
|
15
|
+
export * from './inbox/service.js';
|
|
16
|
+
export * from './inbox/client.js';
|
|
17
|
+
export * from './inbox/runner.js';
|
|
18
|
+
export * from './inbox/events.js';
|
package/dist/src/index.js
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
export * from './contract.js';
|
|
2
2
|
export * from './errors.js';
|
|
3
|
+
export * from './api-error.js';
|
|
3
4
|
export * from './validation.js';
|
|
4
5
|
export * from './service.js';
|
|
5
6
|
export * from './worker.js';
|
|
6
7
|
export * from './http.js';
|
|
7
8
|
export * from './client.js';
|
|
9
|
+
export * from './command-surface.js';
|
|
10
|
+
export * from './email/notification.js';
|
|
11
|
+
export * from './email/thread-token.js';
|
|
12
|
+
export * from './email/inbound.js';
|
|
13
|
+
export * from './email/system.js';
|
|
14
|
+
export * from './inbox/contract.js';
|
|
15
|
+
export * from './inbox/service.js';
|
|
16
|
+
export * from './inbox/client.js';
|
|
17
|
+
export * from './inbox/runner.js';
|
|
18
|
+
export * from './inbox/events.js';
|
|
8
19
|
//# sourceMappingURL=index.js.map
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
|
package/dist/src/mcp.js
CHANGED
|
@@ -1,66 +1,34 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { z } from 'zod/v3';
|
|
3
|
+
import { channelsCommandDefinitions, createChannelsCommands } from './command-surface.js';
|
|
3
4
|
const outputSchema = { result: z.unknown() };
|
|
4
5
|
export function createChannelsMcpServer(channels) {
|
|
5
6
|
const server = new McpServer({ name: 'amalgm-channels-mcp-server', version: '0.1.0' });
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
idempotentHint: true,
|
|
20
|
-
openWorldHint: true,
|
|
21
|
-
},
|
|
22
|
-
}, async ({ message, title, channel, idempotency_key }) => result(await channels.notify({
|
|
23
|
-
message,
|
|
24
|
-
...(title === undefined ? {} : { title }),
|
|
25
|
-
...(channel === undefined ? {} : { channel }),
|
|
26
|
-
...(idempotency_key === undefined ? {} : { idempotencyKey: idempotency_key }),
|
|
27
|
-
})));
|
|
28
|
-
server.registerTool('amalgm_channels_list_deliveries', {
|
|
29
|
-
title: 'List notification deliveries',
|
|
30
|
-
description: 'List the authenticated user\'s durable notification delivery history.',
|
|
31
|
-
inputSchema: {
|
|
32
|
-
status: z.enum(['pending', 'sending', 'delivered', 'failed']).optional(),
|
|
33
|
-
limit: z.number().int().min(1).max(100).optional(),
|
|
34
|
-
offset: z.number().int().min(0).optional(),
|
|
35
|
-
},
|
|
36
|
-
outputSchema,
|
|
37
|
-
annotations: readOnly(),
|
|
38
|
-
}, async ({ status, limit, offset }) => result(await channels.list({
|
|
39
|
-
...(status === undefined ? {} : { status }),
|
|
40
|
-
...(limit === undefined ? {} : { limit }),
|
|
41
|
-
...(offset === undefined ? {} : { offset }),
|
|
42
|
-
})));
|
|
43
|
-
server.registerTool('amalgm_channels_get_delivery', {
|
|
44
|
-
title: 'Get notification delivery',
|
|
45
|
-
description: 'Get one durable notification delivery by id for the authenticated user.',
|
|
46
|
-
inputSchema: { delivery_id: z.string().min(1).max(200) },
|
|
47
|
-
outputSchema,
|
|
48
|
-
annotations: readOnly(),
|
|
49
|
-
}, async ({ delivery_id }) => result(await channels.get(delivery_id)));
|
|
7
|
+
const commands = createChannelsCommands(channels);
|
|
8
|
+
for (const definition of channelsCommandDefinitions) {
|
|
9
|
+
server.registerTool(definition.mcpName, {
|
|
10
|
+
title: definition.title,
|
|
11
|
+
description: definition.description,
|
|
12
|
+
inputSchema: definition.inputShape,
|
|
13
|
+
outputSchema,
|
|
14
|
+
annotations: definition.annotations,
|
|
15
|
+
}, async (input, extra) => {
|
|
16
|
+
const trustedSessionId = sessionId(extra._meta);
|
|
17
|
+
return result(await commands.execute(definition.name, input, trustedSessionId ? { sessionId: trustedSessionId } : {}));
|
|
18
|
+
});
|
|
19
|
+
}
|
|
50
20
|
return server;
|
|
51
21
|
}
|
|
22
|
+
function sessionId(meta) {
|
|
23
|
+
if (!meta || typeof meta !== 'object' || Array.isArray(meta))
|
|
24
|
+
return undefined;
|
|
25
|
+
const value = meta['amalgm/sessionId'];
|
|
26
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
27
|
+
}
|
|
52
28
|
function result(value) {
|
|
53
29
|
return {
|
|
54
30
|
content: [{ type: 'text', text: JSON.stringify(value) }],
|
|
55
31
|
structuredContent: { result: value },
|
|
56
32
|
};
|
|
57
33
|
}
|
|
58
|
-
function readOnly() {
|
|
59
|
-
return {
|
|
60
|
-
readOnlyHint: true,
|
|
61
|
-
destructiveHint: false,
|
|
62
|
-
idempotentHint: true,
|
|
63
|
-
openWorldHint: false,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
34
|
//# sourceMappingURL=mcp.js.map
|
package/dist/src/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B,OAAO,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE1F,MAAM,YAAY,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;AAE7C,MAAM,UAAU,uBAAuB,CAAC,QAAkB;IACxD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,4BAA4B,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACvF,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IAElD,KAAK,MAAM,UAAU,IAAI,0BAA0B,EAAE,CAAC;QACpD,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,OAAO,EAAE;YACtC,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,WAAW,EAAE,UAAU,CAAC,WAAW;YACnC,WAAW,EAAE,UAAU,CAAC,UAAU;YAClC,YAAY;YACZ,WAAW,EAAE,UAAU,CAAC,WAAW;SACpC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACxB,MAAM,gBAAgB,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAChD,OAAO,MAAM,CAAC,MAAM,QAAQ,CAAC,OAAO,CAClC,UAAU,CAAC,IAAI,EACf,KAAK,EACL,gBAAgB,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CACxD,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,SAAS,CAAC,IAAa;IAC9B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/E,MAAM,KAAK,GAAI,IAAgC,CAAC,kBAAkB,CAAC,CAAC;IACpE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9E,CAAC;AAED,SAAS,MAAM,CAAC,KAAc;IAC5B,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QACxD,iBAAiB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;KACrC,CAAC;AACJ,CAAC"}
|
package/dist/src/service.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { ChannelsError } from './errors.js';
|
|
2
|
-
import { deliveryQuery, identifier,
|
|
2
|
+
import { deliveryQuery, identifier, sendMessage } from './validation.js';
|
|
3
3
|
export function createChannelsService(repository) {
|
|
4
4
|
return Object.freeze({
|
|
5
5
|
for(principal) {
|
|
6
6
|
const userId = identifier(principal.userId, 'principal.userId');
|
|
7
7
|
const scopes = new Set(principal.scopes);
|
|
8
8
|
return Object.freeze({
|
|
9
|
-
async
|
|
9
|
+
async send(input, context = {}) {
|
|
10
10
|
requireScope(scopes, 'channels:send');
|
|
11
|
-
return repository.enqueue(userId,
|
|
11
|
+
return repository.enqueue(userId, principal.computerId, sendMessage(input), Object.freeze({
|
|
12
|
+
...(context.sessionId === undefined
|
|
13
|
+
? {}
|
|
14
|
+
: { sessionId: identifier(context.sessionId, 'context.sessionId') }),
|
|
15
|
+
}));
|
|
12
16
|
},
|
|
13
17
|
async list(query) {
|
|
14
18
|
requireScope(scopes, 'channels:read');
|
package/dist/src/service.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEzE,MAAM,UAAU,qBAAqB,CAAC,UAA8B;IAClE,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,GAAG,CAAC,SAA2B;YAC7B,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YAChE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAS,SAAS,CAAC,MAAM,CAAC,CAAC;YACjD,OAAO,MAAM,CAAC,MAAM,CAAC;gBACnB,KAAK,CAAC,IAAI,CAAC,KAAsC,EAAE,UAA8B,EAAE;oBACjF,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;oBACtC,OAAO,UAAU,CAAC,OAAO,CACvB,MAAM,EACN,SAAS,CAAC,UAAU,EACpB,WAAW,CAAC,KAAK,CAAC,EAClB,MAAM,CAAC,MAAM,CAAC;wBACZ,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS;4BACjC,CAAC,CAAC,EAAE;4BACJ,CAAC,CAAC,EAAE,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC,SAAS,EAAE,mBAAmB,CAAC,EAAE,CAAC;qBACvE,CAAC,CACH,CAAC;gBACJ,CAAC;gBACD,KAAK,CAAC,IAAI,CAAC,KAAuC;oBAChD,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;oBACtC,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;gBACvD,CAAC;gBACD,KAAK,CAAC,GAAG,CAAC,UAAkB;oBAC1B,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;oBACtC,OAAO,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;gBACtE,CAAC;aACF,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,MAA2B,EAAE,QAAgB;IACjE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,aAAa,CAAC,WAAW,EAAE,kBAAkB,QAAQ,EAAE,CAAC,CAAC;AAChG,CAAC"}
|
package/dist/src/validation.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ListDeliveries, NormalizedListDeliveries,
|
|
2
|
-
export declare function
|
|
1
|
+
import type { ListDeliveries, NormalizedListDeliveries, NormalizedSendMessage, SendMessageInput } from './contract.js';
|
|
2
|
+
export declare function sendMessage(input: SendMessageInput): NormalizedSendMessage;
|
|
3
3
|
export declare function deliveryQuery(input?: ListDeliveries): NormalizedListDeliveries;
|
|
4
4
|
export declare function identifier(value: string, name: string): string;
|
package/dist/src/validation.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { ChannelsError } from './errors.js';
|
|
3
|
-
const statuses = new Set(['pending', 'sending', 'delivered', 'failed']);
|
|
4
|
-
export function
|
|
3
|
+
const statuses = new Set(['pending', 'sending', 'sent', 'delivered', 'failed']);
|
|
4
|
+
export function sendMessage(input) {
|
|
5
5
|
const message = bounded(input.message, 'message', 1, 4_000);
|
|
6
6
|
const title = input.title === undefined
|
|
7
7
|
? 'Amalgm reminder'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/validation.ts"],"names":[],"mappings":"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"}
|
package/dist/src/worker.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DeliveryRepository, EmailProvider, RecipientDirectory } from './contract.js';
|
|
2
|
+
import type { EmailThreadAddressing } from './email/thread-token.js';
|
|
2
3
|
export interface ChannelsWorkerOptions {
|
|
3
4
|
readonly batchSize?: number;
|
|
4
5
|
readonly leaseSeconds?: number;
|
|
@@ -10,6 +11,8 @@ export declare class ChannelsWorker {
|
|
|
10
11
|
private readonly repository;
|
|
11
12
|
private readonly directory;
|
|
12
13
|
private readonly email;
|
|
13
|
-
|
|
14
|
+
private readonly addressing;
|
|
15
|
+
constructor(repository: DeliveryRepository, directory: RecipientDirectory, email: EmailProvider, addressing: EmailThreadAddressing, options?: ChannelsWorkerOptions);
|
|
14
16
|
drainOnce(): Promise<number>;
|
|
17
|
+
nextWakeAt(): Promise<Date | null>;
|
|
15
18
|
}
|
package/dist/src/worker.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
import { renderNotificationEmail } from './email/notification.js';
|
|
1
2
|
export class ChannelsWorker {
|
|
2
3
|
repository;
|
|
3
4
|
directory;
|
|
4
5
|
email;
|
|
6
|
+
addressing;
|
|
5
7
|
#batchSize;
|
|
6
8
|
#leaseSeconds;
|
|
7
9
|
#now;
|
|
8
10
|
#log;
|
|
9
|
-
constructor(repository, directory, email, options = {}) {
|
|
11
|
+
constructor(repository, directory, email, addressing, options = {}) {
|
|
10
12
|
this.repository = repository;
|
|
11
13
|
this.directory = directory;
|
|
12
14
|
this.email = email;
|
|
15
|
+
this.addressing = addressing;
|
|
13
16
|
this.#batchSize = options.batchSize ?? 20;
|
|
14
17
|
this.#leaseSeconds = options.leaseSeconds ?? 60;
|
|
15
18
|
this.#now = options.now ?? (() => new Date());
|
|
@@ -23,14 +26,30 @@ export class ChannelsWorker {
|
|
|
23
26
|
async #deliver(delivery) {
|
|
24
27
|
try {
|
|
25
28
|
const to = await this.directory.emailForUser(delivery.userId);
|
|
29
|
+
const replyTo = await this.addressing.replyAddress(delivery.thread.id);
|
|
30
|
+
const references = [...delivery.thread.references];
|
|
31
|
+
if (delivery.thread.replyToMessageId && !references.includes(delivery.thread.replyToMessageId)) {
|
|
32
|
+
references.push(delivery.thread.replyToMessageId);
|
|
33
|
+
}
|
|
26
34
|
const result = await this.email.send({
|
|
27
35
|
to,
|
|
28
|
-
subject: delivery.
|
|
36
|
+
subject: delivery.thread.subject,
|
|
29
37
|
text: delivery.message,
|
|
30
|
-
|
|
38
|
+
html: renderNotificationEmail(delivery.message),
|
|
39
|
+
idempotencyKey: `channel-delivery:${delivery.id}`,
|
|
40
|
+
replyTo,
|
|
41
|
+
headers: {
|
|
42
|
+
'Message-ID': delivery.thread.messageId,
|
|
43
|
+
...(delivery.thread.replyToMessageId
|
|
44
|
+
? { 'In-Reply-To': delivery.thread.replyToMessageId }
|
|
45
|
+
: {}),
|
|
46
|
+
...(references.length ? { References: references.join(' ') } : {}),
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
const marked = await this.repository.markSent(delivery, result.providerId, this.#now());
|
|
50
|
+
this.#log(marked ? 'delivery.sent' : 'delivery.lease_lost', {
|
|
51
|
+
deliveryId: delivery.id, attempts: delivery.attempts,
|
|
31
52
|
});
|
|
32
|
-
await this.repository.complete(delivery, result.providerId, this.#now());
|
|
33
|
-
this.#log('delivery.completed', { deliveryId: delivery.id, attempts: delivery.attempts });
|
|
34
53
|
}
|
|
35
54
|
catch (error) {
|
|
36
55
|
const message = safeError(error);
|
|
@@ -38,6 +57,9 @@ export class ChannelsWorker {
|
|
|
38
57
|
this.#log('delivery.failed', { deliveryId: delivery.id, error: message });
|
|
39
58
|
}
|
|
40
59
|
}
|
|
60
|
+
nextWakeAt() {
|
|
61
|
+
return this.repository.nextWorkAt();
|
|
62
|
+
}
|
|
41
63
|
}
|
|
42
64
|
function safeError(error) {
|
|
43
65
|
const message = error instanceof Error ? error.message : 'Provider delivery failed';
|
package/dist/src/worker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/worker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/worker.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amalgm/channels",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Amalgm's SDK and hosted service for durable user
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "Amalgm's SDK and hosted service for durable bidirectional user channels.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"repository": {
|
|
@@ -20,11 +20,18 @@
|
|
|
20
20
|
"types": "./dist/src/mcp.d.ts",
|
|
21
21
|
"import": "./dist/src/mcp.js"
|
|
22
22
|
},
|
|
23
|
+
"./cli": {
|
|
24
|
+
"types": "./dist/src/cli.d.ts",
|
|
25
|
+
"import": "./dist/src/cli.js"
|
|
26
|
+
},
|
|
23
27
|
"./host": {
|
|
24
28
|
"types": "./dist/host/index.d.ts",
|
|
25
29
|
"import": "./dist/host/index.js"
|
|
26
30
|
}
|
|
27
31
|
},
|
|
32
|
+
"bin": {
|
|
33
|
+
"amalgm-channels": "dist/src/cli-main.js"
|
|
34
|
+
},
|
|
28
35
|
"files": [
|
|
29
36
|
"dist",
|
|
30
37
|
"supabase",
|
|
@@ -34,10 +41,10 @@
|
|
|
34
41
|
],
|
|
35
42
|
"scripts": {
|
|
36
43
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
37
|
-
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
44
|
+
"build": "npm run clean && tsc -p tsconfig.build.json && tsx scripts/mark-executables.ts",
|
|
38
45
|
"check": "tsx scripts/check-tree.ts && tsc -p tsconfig.json --noEmit",
|
|
39
46
|
"test": "tsx --test test/*.test.ts",
|
|
40
|
-
"verify": "npm run check && npm test && npm run build",
|
|
47
|
+
"verify": "npm run check && npm test && npm run build && tsx scripts/check-cli-artifact.ts",
|
|
41
48
|
"prepack": "npm run build",
|
|
42
49
|
"start": "node dist/host/main.js"
|
|
43
50
|
},
|
|
@@ -45,7 +52,7 @@
|
|
|
45
52
|
"node": ">=20"
|
|
46
53
|
},
|
|
47
54
|
"dependencies": {
|
|
48
|
-
"@amalgm/core": "0.4.
|
|
55
|
+
"@amalgm/core": "0.4.6",
|
|
49
56
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
50
57
|
"@supabase/supabase-js": "2.57.4",
|
|
51
58
|
"jose": "^6.1.0",
|
package/skills/channels/SKILL.md
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: amalgm-channels
|
|
3
|
-
description:
|
|
3
|
+
description: Deliberately send one discrete message to the current Amalgm user over a selected external channel.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Amalgm Channels
|
|
7
7
|
|
|
8
|
-
Use Channels when the user asks to be notified, reminded, emailed, or contacted
|
|
9
|
-
|
|
10
|
-
not ask for or pass their email
|
|
8
|
+
Use Channels when the user asks to be notified, reminded, emailed, or contacted,
|
|
9
|
+
or when an inbound channel message requires a deliberate reply. Channels always
|
|
10
|
+
addresses the authenticated current user. Do not ask for or pass their email
|
|
11
|
+
address.
|
|
11
12
|
|
|
12
13
|
## Send
|
|
13
14
|
|
|
14
|
-
Call `
|
|
15
|
-
`
|
|
16
|
-
|
|
15
|
+
Call the one tool, `amalgm_channels_send`, with concise `message` text and the
|
|
16
|
+
selected `channel`. Email is currently the supported channel. Add a short
|
|
17
|
+
`title` when it improves recognition.
|
|
18
|
+
|
|
19
|
+
Ordinary assistant output is local and is never delivered through Channels.
|
|
20
|
+
After finishing inbound work, explicitly call the send tool for each complete
|
|
21
|
+
message that should reach the user. Never use it to stream progress fragments.
|
|
17
22
|
|
|
18
23
|
When the notification belongs to an automation run, always pass that durable
|
|
19
24
|
run id as `idempotency_key`. Retrying the same run will then return the original
|
|
20
25
|
delivery instead of sending twice.
|
|
21
26
|
|
|
22
27
|
The returned `pending` state means the message is durably queued, not yet
|
|
23
|
-
delivered.
|
|
24
|
-
|
|
25
|
-
## Inspect
|
|
26
|
-
|
|
27
|
-
Use `amalgm_channels_list_deliveries` for history and status filtering. Delivery
|
|
28
|
-
records expose content, attempts, safe provider status, and timestamps; they do
|
|
29
|
-
not expose recipient coordinates or provider credentials.
|
|
28
|
+
delivered. The tool cannot select another recipient, session, or provider
|
|
29
|
+
credential.
|