@holon-run/agentinbox 0.6.0 → 1.0.0-beta.0
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/README.md +32 -7
- package/dist/src/adapters.js +61 -6
- package/dist/src/backend.js +4 -16
- package/dist/src/cli.js +307 -53
- package/dist/src/client.js +2 -2
- package/dist/src/daemon.js +36 -2
- package/dist/src/http.js +467 -45
- package/dist/src/logging.js +112 -0
- package/dist/src/paths.js +1 -0
- package/dist/src/runtime_gate.js +394 -63
- package/dist/src/service.js +856 -154
- package/dist/src/source_hosts.js +75 -0
- package/dist/src/source_resolution.js +20 -20
- package/dist/src/source_schema.js +2 -2
- package/dist/src/sources/feishu.js +66 -28
- package/dist/src/sources/github.js +188 -24
- package/dist/src/sources/remote.js +44 -24
- package/dist/src/sources/{remote_profiles.js → remote_modules.js} +143 -58
- package/dist/src/store.js +861 -106
- package/dist/src/terminal.js +33 -7
- package/dist/src/util.js +46 -1
- package/drizzle/migrations/{0000_initial.sql → 0000_v1_initial.sql} +182 -6
- package/drizzle/schema.ts +93 -1
- package/package.json +2 -1
- package/scripts/iterm2_cursor_probe.py +8 -3
- package/scripts/release_smoke.sh +123 -0
- package/drizzle/migrations/0001_inbox_items_source_occurred_at_idx.sql +0 -3
- package/drizzle/migrations/0002_subscription_cleanup_policy.sql +0 -45
- package/drizzle/migrations/0003_subscription_lifecycle_retirements.sql +0 -14
- package/drizzle/migrations/0004_source_idle_states.sql +0 -10
- package/drizzle/migrations/0005_timers.sql +0 -22
- package/drizzle/migrations/0006_terminal_runtime_pid.sql +0 -1
- package/drizzle/migrations/0007_activation_dispatch_last_notified_fingerprint.sql +0 -2
- package/drizzle/migrations/0008_inbox_item_sequence.sql +0 -21
|
@@ -3,66 +3,66 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
exports.
|
|
8
|
-
exports.
|
|
6
|
+
exports.RemoteSourceModuleRegistry = void 0;
|
|
7
|
+
exports.builtInModuleIdForSourceType = builtInModuleIdForSourceType;
|
|
8
|
+
exports.moduleConfigForSource = moduleConfigForSource;
|
|
9
9
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
11
|
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
|
|
16
|
-
const
|
|
17
|
-
class
|
|
18
|
-
|
|
15
|
+
const REMOTE_USER_MODULE_ROOT_DIR = "source-modules";
|
|
16
|
+
const BUILTIN_MODULE_IDS = new Set(["builtin.github_repo", "builtin.github_repo_ci", "builtin.feishu_bot"]);
|
|
17
|
+
class RemoteSourceModuleRegistry {
|
|
18
|
+
moduleCache = new Map();
|
|
19
19
|
resolve(source, homeDir) {
|
|
20
20
|
if (source.sourceType === "github_repo") {
|
|
21
|
-
return Promise.resolve(
|
|
21
|
+
return Promise.resolve(GITHUB_REPO_MODULE);
|
|
22
22
|
}
|
|
23
23
|
if (source.sourceType === "github_repo_ci") {
|
|
24
|
-
return Promise.resolve(
|
|
24
|
+
return Promise.resolve(GITHUB_REPO_CI_MODULE);
|
|
25
25
|
}
|
|
26
26
|
if (source.sourceType === "feishu_bot") {
|
|
27
|
-
return Promise.resolve(
|
|
27
|
+
return Promise.resolve(FEISHU_BOT_MODULE);
|
|
28
28
|
}
|
|
29
29
|
if (source.sourceType !== "remote_source") {
|
|
30
|
-
throw new Error(`unsupported source type for remote
|
|
30
|
+
throw new Error(`unsupported source type for remote module: ${source.sourceType}`);
|
|
31
31
|
}
|
|
32
|
-
return this.
|
|
32
|
+
return this.loadUserModule(source, homeDir);
|
|
33
33
|
}
|
|
34
|
-
async
|
|
34
|
+
async loadUserModule(source, homeDir) {
|
|
35
35
|
const config = source.config ?? {};
|
|
36
|
-
const
|
|
37
|
-
if (!
|
|
38
|
-
throw new Error("remote_source requires config.
|
|
36
|
+
const modulePath = asNonEmptyString(config.modulePath);
|
|
37
|
+
if (!modulePath) {
|
|
38
|
+
throw new Error("remote_source requires config.modulePath (module path)");
|
|
39
39
|
}
|
|
40
|
-
const
|
|
41
|
-
const resolvedPath =
|
|
40
|
+
const moduleRoot = node_path_1.default.resolve(homeDir, REMOTE_USER_MODULE_ROOT_DIR);
|
|
41
|
+
const resolvedPath = resolveAndValidateModulePath(moduleRoot, modulePath);
|
|
42
42
|
const cacheKey = `${resolvedPath}:${source.sourceKey}`;
|
|
43
|
-
const cached = this.
|
|
43
|
+
const cached = this.moduleCache.get(cacheKey);
|
|
44
44
|
if (cached) {
|
|
45
45
|
return cached;
|
|
46
46
|
}
|
|
47
47
|
if (!node_fs_1.default.existsSync(resolvedPath)) {
|
|
48
|
-
throw new Error(`remote_source
|
|
48
|
+
throw new Error(`remote_source module not found: ${resolvedPath}`);
|
|
49
49
|
}
|
|
50
50
|
const imported = await dynamicImportModule((0, node_url_1.pathToFileURL)(resolvedPath).href);
|
|
51
|
-
const
|
|
52
|
-
if (!
|
|
53
|
-
throw new Error(`remote_source
|
|
51
|
+
const module = (imported.default ?? imported);
|
|
52
|
+
if (!module || typeof module !== "object") {
|
|
53
|
+
throw new Error(`remote_source module must export default object: ${resolvedPath}`);
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
this.
|
|
57
|
-
return
|
|
55
|
+
validateModuleContract(module, resolvedPath);
|
|
56
|
+
this.moduleCache.set(cacheKey, module);
|
|
57
|
+
return module;
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
exports.
|
|
60
|
+
exports.RemoteSourceModuleRegistry = RemoteSourceModuleRegistry;
|
|
61
61
|
async function dynamicImportModule(moduleUrl) {
|
|
62
62
|
const importer = new Function("url", "return import(url);");
|
|
63
63
|
return importer(moduleUrl);
|
|
64
64
|
}
|
|
65
|
-
function
|
|
65
|
+
function builtInModuleIdForSourceType(sourceType) {
|
|
66
66
|
if (sourceType === "github_repo") {
|
|
67
67
|
return "builtin.github_repo";
|
|
68
68
|
}
|
|
@@ -74,42 +74,46 @@ function builtInProfileIdForSourceType(sourceType) {
|
|
|
74
74
|
}
|
|
75
75
|
return null;
|
|
76
76
|
}
|
|
77
|
-
function
|
|
78
|
-
if (!
|
|
79
|
-
throw new Error(`remote_source
|
|
77
|
+
function validateModuleContract(module, sourcePath) {
|
|
78
|
+
if (!module.id || typeof module.id !== "string") {
|
|
79
|
+
throw new Error(`remote_source module id must be a non-empty string: ${sourcePath}`);
|
|
80
80
|
}
|
|
81
|
-
if (
|
|
82
|
-
throw new Error(`remote_source
|
|
81
|
+
if (BUILTIN_MODULE_IDS.has(module.id)) {
|
|
82
|
+
throw new Error(`remote_source module id is reserved: ${module.id}`);
|
|
83
83
|
}
|
|
84
|
-
if (typeof
|
|
85
|
-
throw new Error(`remote_source
|
|
84
|
+
if (typeof module.validateConfig !== "function") {
|
|
85
|
+
throw new Error(`remote_source module missing validateConfig(): ${sourcePath}`);
|
|
86
86
|
}
|
|
87
|
-
if (typeof
|
|
88
|
-
throw new Error(`remote_source
|
|
87
|
+
if (typeof module.buildManagedSourceSpec !== "function") {
|
|
88
|
+
throw new Error(`remote_source module missing buildManagedSourceSpec(): ${sourcePath}`);
|
|
89
89
|
}
|
|
90
|
-
if (typeof
|
|
91
|
-
throw new Error(`remote_source
|
|
90
|
+
if (typeof module.mapRawEvent !== "function") {
|
|
91
|
+
throw new Error(`remote_source module missing mapRawEvent(): ${sourcePath}`);
|
|
92
92
|
}
|
|
93
|
-
validateOptionalHook(
|
|
94
|
-
validateOptionalHook(
|
|
95
|
-
validateOptionalHook(
|
|
96
|
-
validateOptionalHook(
|
|
97
|
-
validateOptionalHook(
|
|
98
|
-
validateOptionalHook(
|
|
93
|
+
validateOptionalHook(module.describeCapabilities, "describeCapabilities", sourcePath);
|
|
94
|
+
validateOptionalHook(module.listSubscriptionShortcuts, "listSubscriptionShortcuts", sourcePath);
|
|
95
|
+
validateOptionalHook(module.expandSubscriptionShortcut, "expandSubscriptionShortcut", sourcePath);
|
|
96
|
+
validateOptionalHook(module.deriveTrackedResource, "deriveTrackedResource", sourcePath);
|
|
97
|
+
validateOptionalHook(module.projectLifecycleSignal, "projectLifecycleSignal", sourcePath);
|
|
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
|
-
throw new Error(`remote_source
|
|
106
|
+
throw new Error(`remote_source module ${name} must be a function when provided: ${sourcePath}`);
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
|
-
function
|
|
106
|
-
const resolved = node_path_1.default.isAbsolute(
|
|
107
|
-
? node_path_1.default.resolve(
|
|
108
|
-
: node_path_1.default.resolve(
|
|
109
|
-
const normalizedRoot = ensureTrailingSep(node_path_1.default.resolve(
|
|
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);
|
|
113
|
+
const normalizedRoot = ensureTrailingSep(node_path_1.default.resolve(moduleRoot));
|
|
110
114
|
const normalizedResolved = node_path_1.default.resolve(resolved);
|
|
111
|
-
if (!normalizedResolved.startsWith(normalizedRoot) && normalizedResolved !== node_path_1.default.resolve(
|
|
112
|
-
throw new Error(`remote_source
|
|
115
|
+
if (!normalizedResolved.startsWith(normalizedRoot) && normalizedResolved !== node_path_1.default.resolve(moduleRoot)) {
|
|
116
|
+
throw new Error(`remote_source modulePath must stay under ${moduleRoot}`);
|
|
113
117
|
}
|
|
114
118
|
return normalizedResolved;
|
|
115
119
|
}
|
|
@@ -129,8 +133,14 @@ function asNonEmptyString(value) {
|
|
|
129
133
|
const trimmed = value.trim();
|
|
130
134
|
return trimmed.length > 0 ? trimmed : null;
|
|
131
135
|
}
|
|
132
|
-
const
|
|
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 {
|
|
@@ -193,6 +203,54 @@ const GITHUB_REPO_PROFILE = {
|
|
|
193
203
|
deriveTrackedResource(filter) {
|
|
194
204
|
return (0, github_1.deriveGithubTrackedResource)(filter);
|
|
195
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;
|
|
246
|
+
},
|
|
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
|
+
},
|
|
196
254
|
projectLifecycleSignal(rawPayload) {
|
|
197
255
|
return (0, github_1.projectGithubLifecycleSignal)(rawPayload);
|
|
198
256
|
},
|
|
@@ -238,7 +296,7 @@ const GITHUB_REPO_PROFILE = {
|
|
|
238
296
|
};
|
|
239
297
|
},
|
|
240
298
|
};
|
|
241
|
-
const
|
|
299
|
+
const GITHUB_REPO_CI_MODULE = {
|
|
242
300
|
id: "builtin.github_repo_ci",
|
|
243
301
|
describeCapabilities() {
|
|
244
302
|
return {
|
|
@@ -298,6 +356,27 @@ const GITHUB_REPO_CI_PROFILE = {
|
|
|
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
|
},
|
|
@@ -349,8 +428,14 @@ const GITHUB_REPO_CI_PROFILE = {
|
|
|
349
428
|
};
|
|
350
429
|
},
|
|
351
430
|
};
|
|
352
|
-
const
|
|
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",
|
|
@@ -409,10 +494,10 @@ const FEISHU_BOT_PROFILE = {
|
|
|
409
494
|
};
|
|
410
495
|
},
|
|
411
496
|
};
|
|
412
|
-
function
|
|
497
|
+
function moduleConfigForSource(source) {
|
|
413
498
|
const config = asRecord(source.config);
|
|
414
499
|
if (source.sourceType === "remote_source") {
|
|
415
|
-
return asRecord(config.
|
|
500
|
+
return asRecord(config.moduleConfig);
|
|
416
501
|
}
|
|
417
502
|
return config;
|
|
418
503
|
}
|