@holon-run/agentinbox 0.7.0 → 1.0.0-beta.1

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 (33) hide show
  1. package/README.md +36 -7
  2. package/dist/src/adapters.js +55 -0
  3. package/dist/src/backend.js +4 -16
  4. package/dist/src/cli.js +329 -52
  5. package/dist/src/client.js +2 -2
  6. package/dist/src/http.js +479 -55
  7. package/dist/src/runtime_gate.js +49 -41
  8. package/dist/src/service.js +922 -200
  9. package/dist/src/source_hosts.js +75 -0
  10. package/dist/src/source_resolution.js +2 -2
  11. package/dist/src/source_schema.js +2 -2
  12. package/dist/src/sources/feishu.js +66 -28
  13. package/dist/src/sources/github.js +222 -36
  14. package/dist/src/sources/remote.js +50 -3
  15. package/dist/src/sources/remote_modules.js +100 -15
  16. package/dist/src/store.js +875 -110
  17. package/dist/src/terminal.js +33 -7
  18. package/dist/src/util.js +46 -1
  19. package/drizzle/migrations/{0000_initial.sql → 0000_v1_initial.sql} +182 -6
  20. package/drizzle/migrations/0002_host_scoped_lifecycle_retirements.sql +42 -0
  21. package/drizzle/migrations/0003_subscription_tracked_resource_indexes.sql +5 -0
  22. package/drizzle/schema.ts +98 -3
  23. package/package.json +2 -1
  24. package/scripts/release_smoke.sh +123 -0
  25. package/dist/src/sources/remote_profiles.js +0 -13
  26. package/drizzle/migrations/0001_inbox_items_source_occurred_at_idx.sql +0 -3
  27. package/drizzle/migrations/0002_subscription_cleanup_policy.sql +0 -45
  28. package/drizzle/migrations/0003_subscription_lifecycle_retirements.sql +0 -14
  29. package/drizzle/migrations/0004_source_idle_states.sql +0 -10
  30. package/drizzle/migrations/0005_timers.sql +0 -22
  31. package/drizzle/migrations/0006_terminal_runtime_pid.sql +0 -1
  32. package/drizzle/migrations/0007_activation_dispatch_last_notified_fingerprint.sql +0 -2
  33. package/drizzle/migrations/0008_inbox_item_sequence.sql +0 -21
@@ -12,7 +12,7 @@ const node_url_1 = require("node:url");
12
12
  const github_1 = require("./github");
13
13
  const github_ci_1 = require("./github_ci");
14
14
  const feishu_1 = require("./feishu");
15
- const REMOTE_USER_MODULE_ROOT_DIR = "source-profiles";
15
+ const REMOTE_USER_MODULE_ROOT_DIR = "source-modules";
16
16
  const BUILTIN_MODULE_IDS = new Set(["builtin.github_repo", "builtin.github_repo_ci", "builtin.feishu_bot"]);
17
17
  class RemoteSourceModuleRegistry {
18
18
  moduleCache = new Map();
@@ -33,12 +33,12 @@ class RemoteSourceModuleRegistry {
33
33
  }
34
34
  async loadUserModule(source, homeDir) {
35
35
  const config = source.config ?? {};
36
- const profilePath = asNonEmptyString(config.profilePath);
37
- if (!profilePath) {
38
- throw new Error("remote_source requires config.profilePath (module path)");
36
+ const modulePath = asNonEmptyString(config.modulePath);
37
+ if (!modulePath) {
38
+ throw new Error("remote_source requires config.modulePath (module path)");
39
39
  }
40
40
  const moduleRoot = node_path_1.default.resolve(homeDir, REMOTE_USER_MODULE_ROOT_DIR);
41
- const resolvedPath = resolveAndValidateModulePath(moduleRoot, profilePath);
41
+ const resolvedPath = resolveAndValidateModulePath(moduleRoot, modulePath);
42
42
  const cacheKey = `${resolvedPath}:${source.sourceKey}`;
43
43
  const cached = this.moduleCache.get(cacheKey);
44
44
  if (cached) {
@@ -96,20 +96,24 @@ function validateModuleContract(module, sourcePath) {
96
96
  validateOptionalHook(module.deriveTrackedResource, "deriveTrackedResource", sourcePath);
97
97
  validateOptionalHook(module.projectLifecycleSignal, "projectLifecycleSignal", sourcePath);
98
98
  validateOptionalHook(module.deriveInlinePreview, "deriveInlinePreview", sourcePath);
99
+ validateOptionalHook(module.deriveNotificationGrouping, "deriveNotificationGrouping", sourcePath);
100
+ validateOptionalHook(module.listDeliveryOperations, "listDeliveryOperations", sourcePath);
101
+ validateOptionalHook(module.invokeDeliveryOperation, "invokeDeliveryOperation", sourcePath);
102
+ validateOptionalHook(module.summarizeDigestThread, "summarizeDigestThread", sourcePath);
99
103
  }
100
104
  function validateOptionalHook(value, name, sourcePath) {
101
105
  if (value !== undefined && typeof value !== "function") {
102
106
  throw new Error(`remote_source module ${name} must be a function when provided: ${sourcePath}`);
103
107
  }
104
108
  }
105
- function resolveAndValidateModulePath(moduleRoot, profilePath) {
106
- const resolved = node_path_1.default.isAbsolute(profilePath)
107
- ? node_path_1.default.resolve(profilePath)
108
- : node_path_1.default.resolve(moduleRoot, profilePath);
109
+ function resolveAndValidateModulePath(moduleRoot, modulePath) {
110
+ const resolved = node_path_1.default.isAbsolute(modulePath)
111
+ ? node_path_1.default.resolve(modulePath)
112
+ : node_path_1.default.resolve(moduleRoot, modulePath);
109
113
  const normalizedRoot = ensureTrailingSep(node_path_1.default.resolve(moduleRoot));
110
114
  const normalizedResolved = node_path_1.default.resolve(resolved);
111
115
  if (!normalizedResolved.startsWith(normalizedRoot) && normalizedResolved !== node_path_1.default.resolve(moduleRoot)) {
112
- throw new Error(`remote_source profilePath must stay under ${moduleRoot}`);
116
+ throw new Error(`remote_source modulePath must stay under ${moduleRoot}`);
113
117
  }
114
118
  return normalizedResolved;
115
119
  }
@@ -131,6 +135,12 @@ function asNonEmptyString(value) {
131
135
  }
132
136
  const GITHUB_REPO_MODULE = {
133
137
  id: "builtin.github_repo",
138
+ listDeliveryOperations(input) {
139
+ return (0, github_1.githubDeliveryOperationsForHandle)(input.handle);
140
+ },
141
+ async invokeDeliveryOperation(input) {
142
+ return (0, github_1.invokeGithubDeliveryOperation)(input.handle, input.operation, input.input);
143
+ },
134
144
  describeCapabilities(source) {
135
145
  const config = (0, github_1.parseGithubSourceConfig)(source);
136
146
  return {
@@ -190,11 +200,59 @@ const GITHUB_REPO_MODULE = {
190
200
  expandSubscriptionShortcut(input) {
191
201
  return (0, github_1.expandGithubSubscriptionShortcut)(input);
192
202
  },
193
- deriveTrackedResource(filter) {
194
- return (0, github_1.deriveGithubTrackedResource)(filter);
203
+ deriveTrackedResource(filter, source) {
204
+ return (0, github_1.deriveGithubTrackedResource)(filter, source);
205
+ },
206
+ deriveNotificationGrouping(item) {
207
+ const number = typeof item.metadata.number === "number" ? item.metadata.number : null;
208
+ if (!number) {
209
+ return null;
210
+ }
211
+ const variant = item.eventVariant;
212
+ if (variant.startsWith("PullRequestReviewCommentEvent.")) {
213
+ return {
214
+ groupable: true,
215
+ resourceRef: `pr:${number}`,
216
+ eventFamily: "review_comments",
217
+ summaryHint: `review comments on PR #${number}`,
218
+ };
219
+ }
220
+ if (variant.startsWith("PullRequestReviewEvent.")) {
221
+ return {
222
+ groupable: true,
223
+ resourceRef: `pr:${number}`,
224
+ eventFamily: "reviews",
225
+ summaryHint: `reviews on PR #${number}`,
226
+ };
227
+ }
228
+ if (variant.startsWith("IssueCommentEvent.")) {
229
+ return {
230
+ groupable: true,
231
+ resourceRef: item.metadata.isPullRequest === true ? `pr:${number}` : `issue:${number}`,
232
+ eventFamily: "comments",
233
+ summaryHint: item.metadata.isPullRequest === true ? `comments on PR #${number}` : `comments on issue #${number}`,
234
+ };
235
+ }
236
+ if (variant.startsWith("PullRequestEvent.closed")) {
237
+ return {
238
+ groupable: true,
239
+ resourceRef: `pr:${number}`,
240
+ eventFamily: "lifecycle",
241
+ summaryHint: `PR #${number} lifecycle updates`,
242
+ flushClass: "immediate",
243
+ };
244
+ }
245
+ return null;
195
246
  },
196
- projectLifecycleSignal(rawPayload) {
197
- return (0, github_1.projectGithubLifecycleSignal)(rawPayload);
247
+ summarizeDigestThread(items, _source, grouping) {
248
+ if (!grouping.summaryHint || items.length === 0) {
249
+ return null;
250
+ }
251
+ const count = items.length;
252
+ return `${count} ${grouping.summaryHint}`;
253
+ },
254
+ projectLifecycleSignal(rawPayload, source) {
255
+ return (0, github_1.projectGithubLifecycleSignal)(rawPayload, source);
198
256
  },
199
257
  validateConfig(source) {
200
258
  (0, github_1.parseGithubSourceConfig)(source);
@@ -298,6 +356,27 @@ const GITHUB_REPO_CI_MODULE = {
298
356
  }
299
357
  return parts.join(" ");
300
358
  },
359
+ deriveNotificationGrouping(item) {
360
+ const workflowRunId = typeof item.metadata.workflowRunId === "number" ? item.metadata.workflowRunId : null;
361
+ if (!workflowRunId) {
362
+ return null;
363
+ }
364
+ const conclusion = asNonEmptyString(item.metadata.conclusion);
365
+ const status = asNonEmptyString(item.metadata.status);
366
+ return {
367
+ groupable: true,
368
+ resourceRef: `workflow_run:${workflowRunId}`,
369
+ eventFamily: "ci_updates",
370
+ summaryHint: `CI updates for run #${workflowRunId}`,
371
+ flushClass: conclusion || status === "completed" ? "immediate" : "normal",
372
+ };
373
+ },
374
+ summarizeDigestThread(items, _source, grouping) {
375
+ if (!grouping.summaryHint || items.length === 0) {
376
+ return null;
377
+ }
378
+ return `${items.length} ${grouping.summaryHint}`;
379
+ },
301
380
  validateConfig(source) {
302
381
  (0, github_ci_1.parseGithubCiSourceConfig)(source);
303
382
  },
@@ -351,6 +430,12 @@ const GITHUB_REPO_CI_MODULE = {
351
430
  };
352
431
  const FEISHU_BOT_MODULE = {
353
432
  id: "builtin.feishu_bot",
433
+ listDeliveryOperations(input) {
434
+ return (0, feishu_1.feishuDeliveryOperationsForHandle)(input.handle);
435
+ },
436
+ async invokeDeliveryOperation(input) {
437
+ return (0, feishu_1.invokeFeishuDeliveryOperation)(input.handle, input.operation, input.input);
438
+ },
354
439
  describeCapabilities() {
355
440
  return {
356
441
  sourceKind: "feishu_bot",
@@ -412,7 +497,7 @@ const FEISHU_BOT_MODULE = {
412
497
  function moduleConfigForSource(source) {
413
498
  const config = asRecord(source.config);
414
499
  if (source.sourceType === "remote_source") {
415
- return asRecord(config.profileConfig);
500
+ return asRecord(config.moduleConfig);
416
501
  }
417
502
  return config;
418
503
  }