@a5c-ai/channels-adapter 5.1.1-staging.0007199a1cb2

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 (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +661 -0
  3. package/dist/backend.d.ts +7 -0
  4. package/dist/backend.d.ts.map +1 -0
  5. package/dist/backend.js +22 -0
  6. package/dist/backend.js.map +1 -0
  7. package/dist/backends/github.d.ts +16 -0
  8. package/dist/backends/github.d.ts.map +1 -0
  9. package/dist/backends/github.js +357 -0
  10. package/dist/backends/github.js.map +1 -0
  11. package/dist/backends/jira.d.ts +18 -0
  12. package/dist/backends/jira.d.ts.map +1 -0
  13. package/dist/backends/jira.js +256 -0
  14. package/dist/backends/jira.js.map +1 -0
  15. package/dist/backends/webhook.d.ts +25 -0
  16. package/dist/backends/webhook.d.ts.map +1 -0
  17. package/dist/backends/webhook.js +206 -0
  18. package/dist/backends/webhook.js.map +1 -0
  19. package/dist/cli.d.ts +2 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +28 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/config.d.ts +10 -0
  24. package/dist/config.d.ts.map +1 -0
  25. package/dist/config.js +323 -0
  26. package/dist/config.js.map +1 -0
  27. package/dist/dedup.d.ts +26 -0
  28. package/dist/dedup.d.ts.map +1 -0
  29. package/dist/dedup.js +68 -0
  30. package/dist/dedup.js.map +1 -0
  31. package/dist/filter.d.ts +9 -0
  32. package/dist/filter.d.ts.map +1 -0
  33. package/dist/filter.js +115 -0
  34. package/dist/filter.js.map +1 -0
  35. package/dist/index.d.ts +14 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +21 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/poller.d.ts +63 -0
  40. package/dist/poller.d.ts.map +1 -0
  41. package/dist/poller.js +195 -0
  42. package/dist/poller.js.map +1 -0
  43. package/dist/registry.d.ts +22 -0
  44. package/dist/registry.d.ts.map +1 -0
  45. package/dist/registry.js +59 -0
  46. package/dist/registry.js.map +1 -0
  47. package/dist/relay.d.ts +58 -0
  48. package/dist/relay.d.ts.map +1 -0
  49. package/dist/relay.js +172 -0
  50. package/dist/relay.js.map +1 -0
  51. package/dist/runtime.d.ts +27 -0
  52. package/dist/runtime.d.ts.map +1 -0
  53. package/dist/runtime.js +198 -0
  54. package/dist/runtime.js.map +1 -0
  55. package/dist/server.d.ts +64 -0
  56. package/dist/server.d.ts.map +1 -0
  57. package/dist/server.js +217 -0
  58. package/dist/server.js.map +1 -0
  59. package/dist/spawner.d.ts +96 -0
  60. package/dist/spawner.d.ts.map +1 -0
  61. package/dist/spawner.js +368 -0
  62. package/dist/spawner.js.map +1 -0
  63. package/dist/state.d.ts +43 -0
  64. package/dist/state.d.ts.map +1 -0
  65. package/dist/state.js +92 -0
  66. package/dist/state.js.map +1 -0
  67. package/dist/types.d.ts +140 -0
  68. package/dist/types.d.ts.map +1 -0
  69. package/dist/types.js +10 -0
  70. package/dist/types.js.map +1 -0
  71. package/package.json +78 -0
package/dist/config.js ADDED
@@ -0,0 +1,323 @@
1
+ // Config loading + validation (SPEC §5, DESIGN §1).
2
+ //
3
+ // `loadConfig(yamlStringOrPath, { env })` -> { config, errors }. It NEVER throws:
4
+ // malformed YAML, an unresolved ${ENV}, an unknown backend type, a malformed
5
+ // filter, or a backend.validateConfig failure are all collected into
6
+ // `errors: string[]` so misconfiguration surfaces as actionable diagnostics
7
+ // rather than a crash at poll time.
8
+ import { readFileSync, existsSync, statSync } from 'node:fs';
9
+ import { dirname, resolve } from 'node:path';
10
+ import yaml from 'js-yaml';
11
+ import { registry } from './registry.js';
12
+ const KNOWN_OPS = new Set([
13
+ 'eq', 'ne', 'in', 'nin', 'includes', 'contains', 'regex', 'exists', 'gt', 'gte', 'lt', 'lte'
14
+ ]);
15
+ const DEFAULT_POLL_INTERVAL = 60;
16
+ // SPEC §5: default `state.maxSeenPerSource` when the YAML omits it. A finite
17
+ // default keeps the FIFO seen-bound from silently becoming UNBOUNDED (which would
18
+ // let state files grow without limit); an explicit YAML value still wins.
19
+ const DEFAULT_MAX_SEEN_PER_SOURCE = 1000;
20
+ // SPEC §10 / DESIGN §7.5: the session-spawner config additions. All keys are
21
+ // OPTIONAL and additive — an absent key preserves today's behavior.
22
+ const SPAWN_MODES = new Set(['headless', 'interactive']);
23
+ const APPROVAL_MODES = new Set(['yolo', 'prompt', 'deny']);
24
+ const ON_EVENT_VALUES = new Set(['emit', 'spawn', 'both']);
25
+ // adapters McpServerConfig.name regex.
26
+ const MCP_NAME_RE = /^[a-zA-Z0-9_-]{1,64}$/;
27
+ /** Default global spawn block (DESIGN §7.5). `agent` defaults to the CANONICAL
28
+ * adapters key `'claude'`. An explicit YAML `agent` value is preserved verbatim
29
+ * here (normalization happens in the spawner, not at load). */
30
+ const SPAWN_DEFAULTS = {
31
+ agent: 'claude',
32
+ mode: 'headless',
33
+ approvalMode: 'yolo',
34
+ selfMcpName: 'mcp-channels',
35
+ maxConcurrent: 4
36
+ };
37
+ /**
38
+ * Interpolate `${NAME}` placeholders from `env` across the PARSED config tree.
39
+ * Walking the parsed structure (rather than the raw text) means YAML comments
40
+ * are already stripped, so a literal `${ENV}` inside a comment is never mistaken
41
+ * for a required variable. Records every unresolved name in `errors`.
42
+ */
43
+ function interpolateNode(node, env, missing) {
44
+ if (typeof node === 'string') {
45
+ return node.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_m, name) => {
46
+ const val = env[name];
47
+ if (val === undefined || val === null || val === '') {
48
+ missing.add(name);
49
+ return '';
50
+ }
51
+ return String(val);
52
+ });
53
+ }
54
+ if (Array.isArray(node)) {
55
+ return node.map((v) => interpolateNode(v, env, missing));
56
+ }
57
+ if (node && typeof node === 'object') {
58
+ const out = {};
59
+ for (const [k, v] of Object.entries(node)) {
60
+ out[k] = interpolateNode(v, env, missing);
61
+ }
62
+ return out;
63
+ }
64
+ return node;
65
+ }
66
+ /**
67
+ * Validate a filter spec recursively. Pushes human-readable problems into
68
+ * `errors`. Mirrors the engine in filter.js so a bad filter is caught at load
69
+ * time (rather than silently never matching at runtime).
70
+ */
71
+ function validateFilter(spec, sourceId, errors) {
72
+ if (spec == null)
73
+ return;
74
+ if (typeof spec !== 'object' || Array.isArray(spec)) {
75
+ errors.push(`Source "${sourceId}": filter must be an object`);
76
+ return;
77
+ }
78
+ const s = spec;
79
+ if (Array.isArray(s.all)) {
80
+ s.all.forEach((sub) => validateFilter(sub, sourceId, errors));
81
+ return;
82
+ }
83
+ if (Array.isArray(s.any)) {
84
+ s.any.forEach((sub) => validateFilter(sub, sourceId, errors));
85
+ return;
86
+ }
87
+ if ('not' in s) {
88
+ validateFilter(s.not, sourceId, errors);
89
+ return;
90
+ }
91
+ // An empty object is "no gate"; allow it.
92
+ if (!('field' in s) && !('op' in s))
93
+ return;
94
+ // Leaf clause.
95
+ if (typeof s.field !== 'string' || s.field.length === 0) {
96
+ errors.push(`Source "${sourceId}": filter clause is missing a "field"`);
97
+ }
98
+ if (typeof s.op !== 'string' || !KNOWN_OPS.has(s.op)) {
99
+ errors.push(`Source "${sourceId}": filter clause has an unknown op "${s.op}" ` +
100
+ `(valid: ${[...KNOWN_OPS].join(', ')})`);
101
+ }
102
+ }
103
+ /**
104
+ * Validate an EFFECTIVE spawn config block (DESIGN §7.5). `label` identifies the
105
+ * origin in error messages. Pushes human-readable problems into `errors`; never
106
+ * throws.
107
+ */
108
+ function validateSpawn(spawn, label, errors) {
109
+ if (spawn == null)
110
+ return;
111
+ if (typeof spawn !== 'object' || Array.isArray(spawn)) {
112
+ errors.push(`${label}: spawn must be a mapping`);
113
+ return;
114
+ }
115
+ const sp = spawn;
116
+ if (sp.mode != null && !SPAWN_MODES.has(sp.mode)) {
117
+ errors.push(`${label}: spawn.mode must be one of headless, interactive (got "${sp.mode}")`);
118
+ }
119
+ if (sp.approvalMode != null && !APPROVAL_MODES.has(sp.approvalMode)) {
120
+ errors.push(`${label}: spawn.approvalMode must be one of yolo, prompt, deny (got "${sp.approvalMode}")`);
121
+ }
122
+ if (sp.selfMcpName != null && !MCP_NAME_RE.test(String(sp.selfMcpName))) {
123
+ errors.push(`${label}: spawn.selfMcpName must match ^[a-zA-Z0-9_-]{1,64}$ (got "${sp.selfMcpName}")`);
124
+ }
125
+ if (sp.maxConcurrent != null) {
126
+ const n = sp.maxConcurrent;
127
+ if (typeof n !== 'number' || !Number.isInteger(n) || n < 1) {
128
+ errors.push(`${label}: spawn.maxConcurrent must be a positive integer (got "${n}")`);
129
+ }
130
+ }
131
+ if (sp.promptTemplate != null && typeof sp.promptTemplate !== 'string') {
132
+ errors.push(`${label}: spawn.promptTemplate must be a string`);
133
+ }
134
+ }
135
+ /** Shallow-merge a per-source spawn block OVER the global defaults (per-source
136
+ * wins). `env` is deep-merged so a source can add one variable without
137
+ * redefining the whole block (DESIGN §7.5). */
138
+ function mergeSpawn(global, perSource) {
139
+ const merged = { ...(global || {}) };
140
+ if (perSource && typeof perSource === 'object' && !Array.isArray(perSource)) {
141
+ for (const [k, v] of Object.entries(perSource)) {
142
+ if (v === undefined)
143
+ continue;
144
+ if (k === 'env' && v && typeof v === 'object' && !Array.isArray(v)) {
145
+ merged.env = { ...(merged.env || {}), ...v };
146
+ }
147
+ else {
148
+ merged[k] = v;
149
+ }
150
+ }
151
+ }
152
+ return merged;
153
+ }
154
+ /**
155
+ * Resolve the raw YAML text from either an inline string or a file path. An
156
+ * inline config always contains newlines; a bare path won't, so a single-line
157
+ * existing file is read from disk. Returns `{ text, baseDir }` where `baseDir`
158
+ * is the directory custom backends resolve against.
159
+ */
160
+ function resolveSource(input) {
161
+ if (typeof input === 'string' && !input.includes('\n')) {
162
+ try {
163
+ if (existsSync(input) && statSync(input).isFile()) {
164
+ return { text: readFileSync(input, 'utf8'), baseDir: dirname(resolve(input)) };
165
+ }
166
+ }
167
+ catch {
168
+ // fall through to treating it as inline YAML
169
+ }
170
+ }
171
+ return { text: String(input ?? ''), baseDir: process.cwd() };
172
+ }
173
+ /**
174
+ * Load and validate a channels config.
175
+ */
176
+ export function loadConfig(input, opts = {}) {
177
+ const env = opts.env || process.env;
178
+ const errors = [];
179
+ const { text, baseDir } = resolveSource(input);
180
+ let parsed;
181
+ try {
182
+ parsed = yaml.load(text);
183
+ }
184
+ catch (err) {
185
+ errors.push(`Failed to parse YAML: ${err?.message || String(err)}`);
186
+ return {
187
+ config: { server: { permissionRelay: false }, sources: [], state: { maxSeenPerSource: DEFAULT_MAX_SEEN_PER_SOURCE }, defaults: { pollIntervalSeconds: DEFAULT_POLL_INTERVAL }, spawn: {}, baseDir },
188
+ errors
189
+ };
190
+ }
191
+ // Interpolate ${ENV} on the parsed tree (comments already stripped), then
192
+ // surface any unresolved variables as actionable errors.
193
+ const missing = new Set();
194
+ let raw = interpolateNode(parsed, env, missing);
195
+ for (const name of missing) {
196
+ errors.push(`Missing required environment variable: \${${name}}`);
197
+ }
198
+ if (raw == null || typeof raw !== 'object') {
199
+ errors.push('Config must be a YAML mapping with `server` and `sources`.');
200
+ raw = {};
201
+ }
202
+ const server = raw.server && typeof raw.server === 'object' ? raw.server : {};
203
+ const state = raw.state && typeof raw.state === 'object' ? raw.state : {};
204
+ const defaults = raw.defaults && typeof raw.defaults === 'object' ? raw.defaults : {};
205
+ const defaultInterval = typeof defaults.pollIntervalSeconds === 'number'
206
+ ? defaults.pollIntervalSeconds
207
+ : DEFAULT_POLL_INTERVAL;
208
+ if (!server.name) {
209
+ errors.push('config.server.name is required.');
210
+ }
211
+ // server.replySecret (DESIGN §7.4): optional string (typically ${ENV}). An
212
+ // empty/unset value is omitted (per-process random key path).
213
+ let replySecret;
214
+ if (server.replySecret != null && server.replySecret !== '') {
215
+ if (typeof server.replySecret === 'string') {
216
+ replySecret = server.replySecret;
217
+ }
218
+ else {
219
+ errors.push('config.server.replySecret must be a string.');
220
+ }
221
+ }
222
+ // Global spawn defaults block (DESIGN §7.5). Validate the RAW block, then
223
+ // normalize it onto config.spawn with documented defaults applied.
224
+ const rawSpawn = raw.spawn && typeof raw.spawn === 'object' && !Array.isArray(raw.spawn) ? raw.spawn : null;
225
+ if (raw.spawn != null && !rawSpawn) {
226
+ errors.push('config.spawn must be a mapping.');
227
+ }
228
+ validateSpawn(rawSpawn, 'global spawn', errors);
229
+ const globalSpawn = mergeSpawn(SPAWN_DEFAULTS, rawSpawn);
230
+ const rawSources = Array.isArray(raw.sources) ? raw.sources : [];
231
+ if (!Array.isArray(raw.sources)) {
232
+ errors.push('config.sources must be an array.');
233
+ }
234
+ const sources = rawSources.map((s) => {
235
+ const src = s && typeof s === 'object' ? s : {};
236
+ const id = src.id;
237
+ if (!id)
238
+ errors.push('Each source requires an `id`.');
239
+ // onEvent routing (DESIGN §7.5): default 'emit' so existing configs (which
240
+ // have no onEvent) keep emitting and never spawn. An unknown value is an error.
241
+ let onEvent = 'emit';
242
+ if (src.onEvent != null) {
243
+ if (ON_EVENT_VALUES.has(src.onEvent)) {
244
+ onEvent = src.onEvent;
245
+ }
246
+ else {
247
+ errors.push(`Source "${id}": onEvent must be one of emit, spawn, both (got "${src.onEvent}")`);
248
+ }
249
+ }
250
+ // Per-source spawn merged OVER the global spawn (per-source wins). Validate
251
+ // the EFFECTIVE merged block so an invalid effective mode/name is caught.
252
+ const rawSrcSpawn = src.spawn && typeof src.spawn === 'object' && !Array.isArray(src.spawn) ? src.spawn : null;
253
+ if (src.spawn != null && !rawSrcSpawn) {
254
+ errors.push(`Source "${id}": spawn must be a mapping.`);
255
+ }
256
+ const effectiveSpawn = mergeSpawn(globalSpawn, rawSrcSpawn);
257
+ validateSpawn(effectiveSpawn, `Source "${id}"`, errors);
258
+ const normalized = {
259
+ id,
260
+ backend: src.backend,
261
+ pollIntervalSeconds: typeof src.pollIntervalSeconds === 'number'
262
+ ? src.pollIntervalSeconds
263
+ : defaultInterval,
264
+ auth: src.auth || {},
265
+ config: src.config || {},
266
+ filter: src.filter,
267
+ routing: src.routing || {},
268
+ onEvent,
269
+ spawn: effectiveSpawn,
270
+ baseDir
271
+ };
272
+ // Backend resolution: a built-in/registered type, OR a relative path to a
273
+ // custom JS module. We only deeply validate registered types here; a custom
274
+ // path is validated at load time by registry.load().
275
+ const backendType = normalized.backend;
276
+ const looksLikePath = typeof backendType === 'string' &&
277
+ (backendType.startsWith('.') ||
278
+ backendType.startsWith('/') ||
279
+ /\.[cm]?js$/.test(backendType) ||
280
+ /^[A-Za-z]:[\\/]/.test(backendType));
281
+ if (!backendType) {
282
+ errors.push(`Source "${id}": a \`backend\` is required.`);
283
+ }
284
+ else if (!looksLikePath) {
285
+ const backend = registry.get(backendType);
286
+ if (!backend) {
287
+ errors.push(`Source "${id}": unknown backend type "${backendType}".`);
288
+ }
289
+ else if (typeof backend.validateConfig === 'function') {
290
+ try {
291
+ const problems = backend.validateConfig(normalized) || [];
292
+ for (const p of problems)
293
+ errors.push(p);
294
+ }
295
+ catch (err) {
296
+ errors.push(`Source "${id}": backend.validateConfig threw: ${err?.message || err}`);
297
+ }
298
+ }
299
+ }
300
+ validateFilter(normalized.filter, id, errors);
301
+ return normalized;
302
+ });
303
+ const config = {
304
+ server: {
305
+ name: server.name,
306
+ instructions: server.instructions,
307
+ permissionRelay: !!server.permissionRelay,
308
+ replySecret
309
+ },
310
+ state: {
311
+ dir: state.dir,
312
+ maxSeenPerSource: typeof state.maxSeenPerSource === 'number'
313
+ ? state.maxSeenPerSource
314
+ : DEFAULT_MAX_SEEN_PER_SOURCE
315
+ },
316
+ defaults: { pollIntervalSeconds: defaultInterval },
317
+ spawn: globalSpawn,
318
+ sources,
319
+ baseDir
320
+ };
321
+ return { config, errors };
322
+ }
323
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * FIFO-prune a seen array to at most `max` entries (newest retained), but NEVER
3
+ * drop an id in `keep` — the boundary bucket. A naive count-based FIFO can evict
4
+ * an id whose timestamp still sits at/after the cursor (re-returned by the next
5
+ * inclusive `since`/`>=` query) → a duplicate emit. Retaining the boundary bucket
6
+ * makes the bound "soft": if `keep` alone exceeds `max`, all kept ids survive
7
+ * (the cursor guarantees the window stays small in practice) (SPEC §5.3,
8
+ * finding §3).
9
+ */
10
+ export declare function boundSeen(seen: string[], { max, keep }?: {
11
+ max?: number;
12
+ keep?: Iterable<string>;
13
+ }): string[];
14
+ /**
15
+ * `fresh`: items whose id is not already in `seen` (deduped within the batch);
16
+ * `seen`: the union (prior seen + fresh ids), bounded by `max` (boundary-safe).
17
+ */
18
+ export declare function deriveNew<T>(items: T[], { idOf, seen, max, keep }: {
19
+ idOf: (item: T) => string;
20
+ seen?: string[];
21
+ max?: number;
22
+ keep?: Iterable<string>;
23
+ }): {
24
+ fresh: T[];
25
+ seen: string[];
26
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedup.d.ts","sourceRoot":"","sources":["../src/dedup.ts"],"names":[],"mappings":"AAQA;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EAAE,EACd,EAAE,GAAG,EAAE,IAAI,EAAE,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;CAAO,GAC5D,MAAM,EAAE,CA6BV;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,CAAC,EACzB,KAAK,EAAE,CAAC,EAAE,EACV,EACE,IAAI,EACJ,IAAS,EACT,GAAG,EACH,IAAI,EACL,EAAE;IACD,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACzB,GACA;IAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAgBhC"}
package/dist/dedup.js ADDED
@@ -0,0 +1,68 @@
1
+ // Shared dedup helper (SPEC §5.3, DESIGN §5).
2
+ //
3
+ // `deriveNew` is the single chokepoint for "drop what we've already emitted".
4
+ // Backends and the core both lean on it so "at most once" holds even when a
5
+ // polling window overlaps the previous one (an inclusive `since`, a
6
+ // minute-granularity JQL `>=`, …). Backends only choose the id derivation
7
+ // (`idOf`) and any cursor post-filter; this function owns the seen-set logic.
8
+ /**
9
+ * FIFO-prune a seen array to at most `max` entries (newest retained), but NEVER
10
+ * drop an id in `keep` — the boundary bucket. A naive count-based FIFO can evict
11
+ * an id whose timestamp still sits at/after the cursor (re-returned by the next
12
+ * inclusive `since`/`>=` query) → a duplicate emit. Retaining the boundary bucket
13
+ * makes the bound "soft": if `keep` alone exceeds `max`, all kept ids survive
14
+ * (the cursor guarantees the window stays small in practice) (SPEC §5.3,
15
+ * finding §3).
16
+ */
17
+ export function boundSeen(seen, { max, keep } = {}) {
18
+ const arr = Array.isArray(seen) ? seen : [];
19
+ if (typeof max !== 'number' || !Number.isFinite(max) || arr.length <= max) {
20
+ return [...arr];
21
+ }
22
+ const keepSet = keep ? new Set(keep) : null;
23
+ if (!keepSet || keepSet.size === 0) {
24
+ // Plain FIFO: keep the most-recent `max` ids.
25
+ return arr.slice(arr.length - max);
26
+ }
27
+ // Walk newest→oldest, taking ids until we hit `max`, but ALWAYS taking a
28
+ // boundary id even past the budget. Preserve original order in the result.
29
+ const retainIdx = new Set();
30
+ let budget = max;
31
+ for (let i = arr.length - 1; i >= 0; i -= 1) {
32
+ const id = arr[i];
33
+ if (keepSet.has(id)) {
34
+ retainIdx.add(i); // boundary id: always retained
35
+ }
36
+ else if (budget > 0) {
37
+ retainIdx.add(i);
38
+ budget -= 1;
39
+ }
40
+ }
41
+ const out = [];
42
+ for (let i = 0; i < arr.length; i += 1) {
43
+ if (retainIdx.has(i))
44
+ out.push(arr[i]);
45
+ }
46
+ return out;
47
+ }
48
+ /**
49
+ * `fresh`: items whose id is not already in `seen` (deduped within the batch);
50
+ * `seen`: the union (prior seen + fresh ids), bounded by `max` (boundary-safe).
51
+ */
52
+ export function deriveNew(items, { idOf, seen = [], max, keep }) {
53
+ const known = new Set(seen);
54
+ const fresh = [];
55
+ const freshIds = [];
56
+ for (const item of Array.isArray(items) ? items : []) {
57
+ const id = idOf(item);
58
+ if (known.has(id))
59
+ continue;
60
+ // Mark immediately so a duplicate id within this same batch is fresh once.
61
+ known.add(id);
62
+ fresh.push(item);
63
+ freshIds.push(id);
64
+ }
65
+ const nextSeen = boundSeen([...seen, ...freshIds], { max, keep });
66
+ return { fresh, seen: nextSeen };
67
+ }
68
+ //# sourceMappingURL=dedup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedup.js","sourceRoot":"","sources":["../src/dedup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { FilterSpec } from './types.js';
2
+ /**
3
+ * Evaluate a filter spec (leaf or combinator) against a payload.
4
+ */
5
+ export declare function filterMatch(spec: unknown, payload: unknown): boolean;
6
+ /**
7
+ * Compile a filter spec into a reusable predicate `(payload) => boolean`.
8
+ */
9
+ export declare function compileFilter(spec: FilterSpec | null | undefined): (payload: unknown) => boolean;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAc,UAAU,EAAE,MAAM,YAAY,CAAC;AA+EzD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAqBpE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,GAClC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAE/B"}
package/dist/filter.js ADDED
@@ -0,0 +1,115 @@
1
+ // Declarative filter engine (SPEC §4, DESIGN §1).
2
+ //
3
+ // A filter `spec` is either a leaf clause `{ field, op, value, ignoreCase? }` or
4
+ // a combinator `{ all: [...] } | { any: [...] } | { not: clause }`. Matching is
5
+ // performed against a dot-path payload. The cardinal rule (AC-9/AC-10): an
6
+ // unknown op, a bad/missing dot-path, or a malformed regex yields NO MATCH and
7
+ // NEVER throws — a misconfigured filter must not be able to crash a poll.
8
+ /**
9
+ * Resolve a dot-path (e.g. "issue.assignee.login") against an object. Returns
10
+ * `undefined` for any missing segment or when traversing into a primitive.
11
+ */
12
+ function getPath(obj, path) {
13
+ if (obj == null || typeof path !== 'string')
14
+ return undefined;
15
+ let cur = obj;
16
+ for (const key of path.split('.')) {
17
+ if (cur == null || (typeof cur !== 'object' && typeof cur !== 'function')) {
18
+ return undefined;
19
+ }
20
+ cur = cur[key];
21
+ }
22
+ return cur;
23
+ }
24
+ /** Build a RegExp, returning `null` if the pattern is invalid. */
25
+ function safeRegExp(pattern, flags) {
26
+ try {
27
+ return new RegExp(pattern, flags);
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ /**
34
+ * Evaluate a single leaf clause.
35
+ */
36
+ function matchLeaf(clause, payload) {
37
+ const { field, op, value, ignoreCase } = clause;
38
+ if (typeof field !== 'string' || typeof op !== 'string')
39
+ return false;
40
+ const actual = getPath(payload, field);
41
+ switch (op) {
42
+ case 'eq':
43
+ return actual === value;
44
+ case 'ne':
45
+ return actual !== value;
46
+ case 'in':
47
+ return Array.isArray(value) && value.includes(actual);
48
+ case 'nin':
49
+ return Array.isArray(value) && !value.includes(actual);
50
+ case 'includes':
51
+ // The FIELD is an array that must contain `value`.
52
+ return Array.isArray(actual) && actual.includes(value);
53
+ case 'contains': {
54
+ // The FIELD is a string that must contain the substring `value`.
55
+ if (typeof actual !== 'string' || typeof value !== 'string')
56
+ return false;
57
+ return ignoreCase
58
+ ? actual.toLowerCase().includes(value.toLowerCase())
59
+ : actual.includes(value);
60
+ }
61
+ case 'regex': {
62
+ if (typeof actual !== 'string' || typeof value !== 'string')
63
+ return false;
64
+ const re = safeRegExp(value, ignoreCase ? 'i' : '');
65
+ return re ? re.test(actual) : false;
66
+ }
67
+ case 'exists': {
68
+ const present = actual !== undefined && actual !== null;
69
+ // value:true asserts presence; value:false asserts absence.
70
+ return value === false ? !present : present;
71
+ }
72
+ case 'gt':
73
+ return typeof actual === 'number' && typeof value === 'number' && actual > value;
74
+ case 'gte':
75
+ return typeof actual === 'number' && typeof value === 'number' && actual >= value;
76
+ case 'lt':
77
+ return typeof actual === 'number' && typeof value === 'number' && actual < value;
78
+ case 'lte':
79
+ return typeof actual === 'number' && typeof value === 'number' && actual <= value;
80
+ default:
81
+ // Unknown operator => no match (never throw).
82
+ return false;
83
+ }
84
+ }
85
+ /**
86
+ * Evaluate a filter spec (leaf or combinator) against a payload.
87
+ */
88
+ export function filterMatch(spec, payload) {
89
+ // An empty / missing filter matches everything (no gate configured).
90
+ if (spec == null)
91
+ return true;
92
+ if (typeof spec !== 'object')
93
+ return false;
94
+ const s = spec;
95
+ if (Array.isArray(s.all)) {
96
+ return s.all.every((sub) => filterMatch(sub, payload));
97
+ }
98
+ if (Array.isArray(s.any)) {
99
+ return s.any.some((sub) => filterMatch(sub, payload));
100
+ }
101
+ if ('not' in s) {
102
+ return !filterMatch(s.not, payload);
103
+ }
104
+ // Leaf clause. An object with no field/op (e.g. `{}`) is treated as "no gate".
105
+ if (!('field' in s) && !('op' in s))
106
+ return true;
107
+ return matchLeaf(s, payload);
108
+ }
109
+ /**
110
+ * Compile a filter spec into a reusable predicate `(payload) => boolean`.
111
+ */
112
+ export function compileFilter(spec) {
113
+ return (payload) => filterMatch(spec, payload);
114
+ }
115
+ //# sourceMappingURL=filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.js","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export { ChannelServer, DEFAULT_INSTRUCTIONS } from './server.js';
2
+ export { createRuntime } from './runtime.js';
3
+ export { Poller } from './poller.js';
4
+ export { defineBackend } from './backend.js';
5
+ export { registry, Registry } from './registry.js';
6
+ export { default as webhookBackend } from './backends/webhook.js';
7
+ export type { NormalizedTriggerEvent, TriggerBackend } from '@a5c-ai/triggers-adapter';
8
+ export { loadConfig } from './config.js';
9
+ export { compileFilter, filterMatch } from './filter.js';
10
+ export { StateStore, MemoryStateStore } from './state.js';
11
+ export { deriveNew, boundSeen } from './dedup.js';
12
+ export { encodeReplyTo, decodeReplyTo, dispatchReply, createRelay } from './relay.js';
13
+ export { SessionSpawner, buildSpawnRunOptions } from './spawner.js';
14
+ export type * from './types.js';
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAInD,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGlE,YAAY,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAEvF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGtF,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAGpE,mBAAmB,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ // Public package surface (SPEC §3, DESIGN §1).
2
+ //
3
+ // This is what library consumers import. It re-exports the channel server, the
4
+ // runtime bootstrap, the backend authoring helper + registry, and the filter,
5
+ // state, dedup, and relay primitives.
6
+ export { ChannelServer, DEFAULT_INSTRUCTIONS } from './server.js';
7
+ export { createRuntime } from './runtime.js';
8
+ export { Poller } from './poller.js';
9
+ export { defineBackend } from './backend.js';
10
+ export { registry, Registry } from './registry.js';
11
+ // SPEC §4 — the OPTIONAL additive webhook-ingest backend (built on
12
+ // `@a5c-ai/triggers-adapter`'s `normalizeEvent`). Alongside github/jira.
13
+ export { default as webhookBackend } from './backends/webhook.js';
14
+ export { loadConfig } from './config.js';
15
+ export { compileFilter, filterMatch } from './filter.js';
16
+ export { StateStore, MemoryStateStore } from './state.js';
17
+ export { deriveNew, boundSeen } from './dedup.js';
18
+ export { encodeReplyTo, decodeReplyTo, dispatchReply, createRelay } from './relay.js';
19
+ // SPEC §10 / DESIGN §7 — the event-triggered session spawner.
20
+ export { SessionSpawner, buildSpawnRunOptions } from './spawner.js';
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,sCAAsC;AAEtC,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEnD,mEAAmE;AACnE,yEAAyE;AACzE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAKlE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEtF,8DAA8D;AAC9D,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC"}