@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 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
+ ![AgentInbox Event Flow](./docs/site/assets/agentinbox-event-flow-v1.png)
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.13.3 or newer if you want to use GitHub or Feishu adapters
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 <agent_id> <source_id>
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 <agent_id>
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: [`docs/site/skills/README.md`](./docs/site/skills/README.md)
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
- ## Release
152
-
153
- `AgentInbox` releases are tag-driven.
215
+ Generate new SQLite migrations after schema changes:
154
216
 
155
- - update [package.json](./package.json) and [CHANGELOG.md](./CHANGELOG.md) in a PR before release
156
- - merge to `main`
157
- - run the manual terminal smoke matrix in [testcases/manual/manual-terminal-qa.md](./testcases/manual/manual-terminal-qa.md)
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
- The operational checklist lives in
164
- [testcases/manual/release-checklist.md](./testcases/manual/release-checklist.md).
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
 
@@ -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 github_ci_1 = require("./sources/github_ci");
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 = new NoopSourceAdapter("remote_source");
35
- feishuSource;
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.feishuSource = new feishu_1.FeishuSourceRuntime(store, appendSourceEvent);
43
- this.githubSource = new github_1.GithubSourceRuntime(store, appendSourceEvent);
44
- this.githubCiSource = new github_ci_1.GithubCiSourceRuntime(store, appendSourceEvent);
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.githubSource;
55
+ return this.remoteSource;
58
56
  }
59
57
  if (type === "github_repo_ci") {
60
- return this.githubCiSource;
58
+ return this.remoteSource;
61
59
  }
62
60
  if (type === "feishu_bot") {
63
- return this.feishuSource;
61
+ return this.remoteSource;
64
62
  }
65
- return this.fixtureSource;
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.fixtureDelivery;
72
+ return this.defaultDelivery;
78
73
  }
79
74
  async start() {
80
- await this.feishuSource.start?.();
81
- await this.githubSource.start?.();
82
- await this.githubCiSource.start?.();
75
+ await this.remoteSource.start?.();
83
76
  }
84
77
  async stop() {
85
- await this.feishuSource.stop?.();
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
- feishu: this.feishuSource.status?.() ?? {},
106
- github: this.githubSource.status?.() ?? {},
107
- githubCi: this.githubCiSource.status?.() ?? {},
114
+ remote: this.remoteSource.status?.() ?? {},
108
115
  };
109
116
  }
110
117
  }