@holon-run/agentinbox 0.1.0 → 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/README.md +76 -16
- package/dist/src/adapters.js +38 -31
- package/dist/src/cli.js +279 -66
- package/dist/src/current_agent.js +126 -0
- package/dist/src/http.js +962 -354
- package/dist/src/service.js +94 -10
- package/dist/src/source_schema.js +2 -10
- package/dist/src/sources/feishu.js +14 -237
- package/dist/src/sources/github.js +10 -244
- package/dist/src/sources/github_ci.js +13 -12
- package/dist/src/sources/remote.js +362 -0
- package/dist/src/sources/remote_profiles.js +254 -0
- package/dist/src/store.js +119 -248
- package/dist/src/util.js +19 -3
- package/drizzle/migrations/0000_initial.sql +206 -0
- package/drizzle/migrations/0001_inbox_items_source_occurred_at_idx.sql +3 -0
- package/drizzle/migrations/meta/0001_snapshot.json +1181 -0
- package/drizzle/migrations/meta/_journal.json +20 -0
- package/drizzle/schema.ts +196 -0
- package/package.json +8 -2
- package/dist/src/matcher.js +0 -47
package/README.md
CHANGED
|
@@ -16,6 +16,43 @@ In practice, that means `AgentInbox` can:
|
|
|
16
16
|
- wake or drive agent sessions running in `tmux` or `iTerm2`, even when the
|
|
17
17
|
agent runtime does not expose a notification API
|
|
18
18
|
|
|
19
|
+
## Event Flow
|
|
20
|
+
|
|
21
|
+
At a high level, `AgentInbox` sits between external events and the current
|
|
22
|
+
agent session:
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
## Review Workflow
|
|
27
|
+
|
|
28
|
+
One concrete workflow is reviewer / developer collaboration around a PR:
|
|
29
|
+
|
|
30
|
+
```mermaid
|
|
31
|
+
sequenceDiagram
|
|
32
|
+
participant D as Developer Agent
|
|
33
|
+
participant G as GitHub / CI
|
|
34
|
+
participant A as AgentInbox
|
|
35
|
+
participant R as Reviewer Agent
|
|
36
|
+
|
|
37
|
+
D->>G: Open PR / Push fix
|
|
38
|
+
G->>A: PR opened / CI started
|
|
39
|
+
A->>R: Wake reviewer
|
|
40
|
+
|
|
41
|
+
R->>G: Leave review comment
|
|
42
|
+
G->>A: Review comment created
|
|
43
|
+
A->>D: Wake developer
|
|
44
|
+
|
|
45
|
+
D->>G: Push fix
|
|
46
|
+
G->>A: CI completed
|
|
47
|
+
A->>D: Wake developer
|
|
48
|
+
A->>R: Wake reviewer
|
|
49
|
+
|
|
50
|
+
R->>G: Approve / Merge
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`AgentInbox` is what lets both agents stay in the loop without polling GitHub
|
|
54
|
+
manually or relying on the agent runtime to expose its own notification API.
|
|
55
|
+
|
|
19
56
|
## Status
|
|
20
57
|
|
|
21
58
|
`AgentInbox` is public beta software.
|
|
@@ -32,7 +69,8 @@ In practice, that means `AgentInbox` can:
|
|
|
32
69
|
Requires:
|
|
33
70
|
|
|
34
71
|
- Node.js 20 or newer
|
|
35
|
-
- `uxc` 0.
|
|
72
|
+
- `uxc` 0.15.0 or newer if you want to use GitHub or Feishu adapters:
|
|
73
|
+
https://github.com/holon-run/uxc
|
|
36
74
|
|
|
37
75
|
Install globally:
|
|
38
76
|
|
|
@@ -61,6 +99,13 @@ If you are using Codex or Claude Code, start with the bundled AgentInbox skill:
|
|
|
61
99
|
- repo copy: [`skills/agentinbox/SKILL.md`](./skills/agentinbox/SKILL.md)
|
|
62
100
|
- docs site copy: `https://agentinbox.holon.run/skills/agentinbox/SKILL`
|
|
63
101
|
|
|
102
|
+
If you use the community `skills` installer, you can install the bundled skill
|
|
103
|
+
directly:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npx skills add holon-run/agentinbox --skill agentinbox -a codex -a claude-code
|
|
107
|
+
```
|
|
108
|
+
|
|
64
109
|
That skill is the recommended onboarding path. It can guide the agent through:
|
|
65
110
|
|
|
66
111
|
- checking or installing `agentinbox`
|
|
@@ -82,15 +127,34 @@ Register the current terminal session:
|
|
|
82
127
|
```bash
|
|
83
128
|
agentinbox agent register
|
|
84
129
|
agentinbox agent register --agent-id agent-alpha
|
|
130
|
+
agentinbox agent current
|
|
85
131
|
```
|
|
86
132
|
|
|
87
133
|
Create a local source and publish an event:
|
|
88
134
|
|
|
89
135
|
```bash
|
|
90
136
|
agentinbox source add local_event local-demo
|
|
91
|
-
agentinbox subscription add <
|
|
137
|
+
agentinbox subscription add <source_id>
|
|
138
|
+
agentinbox subscription add <source_id> --agent-id <agent_id>
|
|
139
|
+
agentinbox subscription add <source_id> --filter-file ./filter.json
|
|
140
|
+
cat filter.json | agentinbox subscription add <source_id> --filter-stdin
|
|
92
141
|
agentinbox source event <source_id> --native-id demo-1 --event local.demo
|
|
93
|
-
agentinbox inbox read
|
|
142
|
+
agentinbox inbox read
|
|
143
|
+
agentinbox inbox read --agent-id <agent_id>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Update an existing source in place:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
agentinbox source update <source_id> --config-json '{"channel":"infra"}'
|
|
150
|
+
agentinbox source update <source_id> --clear-config-ref
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Pause and resume a managed remote source:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
agentinbox source pause <remote_source_id>
|
|
157
|
+
agentinbox source resume <remote_source_id>
|
|
94
158
|
```
|
|
95
159
|
|
|
96
160
|
Remove a task-specific subscription without deleting the whole agent:
|
|
@@ -108,7 +172,7 @@ Public docs live in the mdorigin site under [`docs/site`](./docs/site).
|
|
|
108
172
|
- onboarding with the agent skill: [`docs/site/guides/onboarding-with-agent-skill.md`](./docs/site/guides/onboarding-with-agent-skill.md)
|
|
109
173
|
- getting started: [`docs/site/guides/getting-started.md`](./docs/site/guides/getting-started.md)
|
|
110
174
|
- review workflows: [`docs/site/guides/review-workflows.md`](./docs/site/guides/review-workflows.md)
|
|
111
|
-
- skill docs: [`
|
|
175
|
+
- skill docs: [`skills/README.md`](./skills/README.md)
|
|
112
176
|
- CLI reference: [`docs/site/reference/cli.md`](./docs/site/reference/cli.md)
|
|
113
177
|
- source types: [`docs/site/reference/source-types.md`](./docs/site/reference/source-types.md)
|
|
114
178
|
- architecture: [`docs/site/concepts/architecture.md`](./docs/site/concepts/architecture.md)
|
|
@@ -148,20 +212,16 @@ Build docs directory indexes:
|
|
|
148
212
|
npm run docs:index
|
|
149
213
|
```
|
|
150
214
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
`AgentInbox` releases are tag-driven.
|
|
215
|
+
Generate new SQLite migrations after schema changes:
|
|
154
216
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
- push a tag in the form `v<package.json version>`
|
|
159
|
-
|
|
160
|
-
Public beta tags such as `v0.1.0-beta.1` publish to npm with the `beta`
|
|
161
|
-
dist-tag. Stable tags such as `v0.1.0` publish with the `latest` dist-tag.
|
|
217
|
+
```bash
|
|
218
|
+
npm run db:migrations:generate
|
|
219
|
+
```
|
|
162
220
|
|
|
163
|
-
|
|
164
|
-
|
|
221
|
+
`AgentInbox` now upgrades SQLite state with versioned SQL migrations in
|
|
222
|
+
`drizzle/migrations`. On upgrade with pending migrations, the daemon creates a
|
|
223
|
+
local backup next to the DB file (for example,
|
|
224
|
+
`~/.agentinbox/agentinbox.sqlite.backup-<timestamp>`).
|
|
165
225
|
|
|
166
226
|
## License
|
|
167
227
|
|
package/dist/src/adapters.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.AdapterRegistry = void 0;
|
|
4
4
|
const feishu_1 = require("./sources/feishu");
|
|
5
5
|
const github_1 = require("./sources/github");
|
|
6
|
-
const
|
|
6
|
+
const remote_1 = require("./sources/remote");
|
|
7
7
|
class NoopSourceAdapter {
|
|
8
8
|
sourceType;
|
|
9
9
|
constructor(sourceType) {
|
|
@@ -12,6 +12,9 @@ class NoopSourceAdapter {
|
|
|
12
12
|
async ensureSource(_source) {
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
|
+
async validateSource(_source) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
15
18
|
async pollSource(sourceId) {
|
|
16
19
|
return {
|
|
17
20
|
sourceId,
|
|
@@ -29,24 +32,19 @@ class NoopDeliveryAdapter {
|
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
34
|
class AdapterRegistry {
|
|
32
|
-
fixtureSource = new NoopSourceAdapter("fixture");
|
|
33
35
|
localEventSource = new NoopSourceAdapter("local_event");
|
|
34
|
-
remoteSource
|
|
35
|
-
|
|
36
|
-
githubSource;
|
|
37
|
-
githubCiSource;
|
|
38
|
-
fixtureDelivery = new NoopDeliveryAdapter();
|
|
36
|
+
remoteSource;
|
|
37
|
+
defaultDelivery = new NoopDeliveryAdapter();
|
|
39
38
|
feishuDelivery = new feishu_1.FeishuDeliveryAdapter();
|
|
40
39
|
githubDelivery = new github_1.GithubDeliveryAdapter();
|
|
41
|
-
constructor(store, appendSourceEvent) {
|
|
42
|
-
this.
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
constructor(store, appendSourceEvent, options) {
|
|
41
|
+
this.remoteSource = new remote_1.RemoteSourceRuntime(store, appendSourceEvent, {
|
|
42
|
+
homeDir: options?.homeDir,
|
|
43
|
+
client: options?.remoteSourceClient,
|
|
44
|
+
profileRegistry: options?.remoteProfileRegistry,
|
|
45
|
+
});
|
|
45
46
|
}
|
|
46
47
|
sourceAdapterFor(type) {
|
|
47
|
-
if (type === "fixture") {
|
|
48
|
-
return this.fixtureSource;
|
|
49
|
-
}
|
|
50
48
|
if (type === "local_event") {
|
|
51
49
|
return this.localEventSource;
|
|
52
50
|
}
|
|
@@ -54,37 +52,30 @@ class AdapterRegistry {
|
|
|
54
52
|
return this.remoteSource;
|
|
55
53
|
}
|
|
56
54
|
if (type === "github_repo") {
|
|
57
|
-
return this.
|
|
55
|
+
return this.remoteSource;
|
|
58
56
|
}
|
|
59
57
|
if (type === "github_repo_ci") {
|
|
60
|
-
return this.
|
|
58
|
+
return this.remoteSource;
|
|
61
59
|
}
|
|
62
60
|
if (type === "feishu_bot") {
|
|
63
|
-
return this.
|
|
61
|
+
return this.remoteSource;
|
|
64
62
|
}
|
|
65
|
-
return this.
|
|
63
|
+
return this.localEventSource;
|
|
66
64
|
}
|
|
67
65
|
deliveryAdapterFor(provider) {
|
|
68
|
-
if (provider === "fixture") {
|
|
69
|
-
return this.fixtureDelivery;
|
|
70
|
-
}
|
|
71
66
|
if (provider === "feishu") {
|
|
72
67
|
return this.feishuDelivery;
|
|
73
68
|
}
|
|
74
69
|
if (provider === "github") {
|
|
75
70
|
return this.githubDelivery;
|
|
76
71
|
}
|
|
77
|
-
return this.
|
|
72
|
+
return this.defaultDelivery;
|
|
78
73
|
}
|
|
79
74
|
async start() {
|
|
80
|
-
await this.
|
|
81
|
-
await this.githubSource.start?.();
|
|
82
|
-
await this.githubCiSource.start?.();
|
|
75
|
+
await this.remoteSource.start?.();
|
|
83
76
|
}
|
|
84
77
|
async stop() {
|
|
85
|
-
await this.
|
|
86
|
-
await this.githubSource.stop?.();
|
|
87
|
-
await this.githubCiSource.stop?.();
|
|
78
|
+
await this.remoteSource.stop?.();
|
|
88
79
|
}
|
|
89
80
|
async pollSource(source) {
|
|
90
81
|
const adapter = this.sourceAdapterFor(source.sourceType);
|
|
@@ -100,11 +91,27 @@ class AdapterRegistry {
|
|
|
100
91
|
}
|
|
101
92
|
return adapter.pollSource(source.sourceId);
|
|
102
93
|
}
|
|
94
|
+
async pauseSource(source) {
|
|
95
|
+
const adapter = this.sourceAdapterFor(source.sourceType);
|
|
96
|
+
if (!adapter.pauseSource) {
|
|
97
|
+
throw new Error(`source type ${source.sourceType} does not support pause`);
|
|
98
|
+
}
|
|
99
|
+
await adapter.pauseSource?.(source.sourceId);
|
|
100
|
+
}
|
|
101
|
+
async resumeSource(source) {
|
|
102
|
+
const adapter = this.sourceAdapterFor(source.sourceType);
|
|
103
|
+
if (!adapter.resumeSource) {
|
|
104
|
+
throw new Error(`source type ${source.sourceType} does not support resume`);
|
|
105
|
+
}
|
|
106
|
+
await adapter.resumeSource?.(source.sourceId);
|
|
107
|
+
}
|
|
108
|
+
async removeSource(source) {
|
|
109
|
+
const adapter = this.sourceAdapterFor(source.sourceType);
|
|
110
|
+
await adapter.removeSource?.(source.sourceId);
|
|
111
|
+
}
|
|
103
112
|
status() {
|
|
104
113
|
return {
|
|
105
|
-
|
|
106
|
-
github: this.githubSource.status?.() ?? {},
|
|
107
|
-
githubCi: this.githubCiSource.status?.() ?? {},
|
|
114
|
+
remote: this.remoteSource.status?.() ?? {},
|
|
108
115
|
};
|
|
109
116
|
}
|
|
110
117
|
}
|