@holon-run/agentinbox 0.1.1 → 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.14.0 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`
package/dist/src/cli.js CHANGED
@@ -310,7 +310,8 @@ async function main() {
310
310
  }
311
311
  if (command === "inbox" && normalized[1] === "read") {
312
312
  const args = normalized.slice(2);
313
- if (positionalArgs(args, ["--agent-id", "--after-item"]).length > 0) {
313
+ const allowedFlags = ["--agent-id", "--after-item", "--include-acked"];
314
+ if (positionalArgs(args, ["--agent-id", "--after-item"]).length > 0 || unexpectedFlags(args, allowedFlags).length > 0) {
314
315
  throw new Error("usage: agentinbox inbox read [--agent-id ID] [--after-item ID] [--include-acked]");
315
316
  }
316
317
  const selection = await selectAgentForCommand(client, {
@@ -693,6 +694,10 @@ function positionalArgs(args, flagsWithValues) {
693
694
  }
694
695
  return positionals;
695
696
  }
697
+ function unexpectedFlags(args, allowedFlags) {
698
+ const allowed = new Set(allowedFlags);
699
+ return args.filter((token) => token.startsWith("--") && !allowed.has(token));
700
+ }
696
701
  function printHelp(path = []) {
697
702
  const key = path[0] ?? "root";
698
703
  const helpByKey = {
@@ -1,60 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FeishuDeliveryAdapter = exports.FeishuSourceRuntime = exports.FeishuUxcClient = exports.DEFAULT_FEISHU_EVENT_TYPES = exports.FEISHU_IM_SCHEMA_URL = exports.FEISHU_OPENAPI_ENDPOINT = void 0;
3
+ exports.FeishuDeliveryAdapter = exports.FeishuUxcClient = exports.DEFAULT_FEISHU_EVENT_TYPES = exports.FEISHU_IM_SCHEMA_URL = exports.FEISHU_OPENAPI_ENDPOINT = void 0;
4
4
  exports.normalizeFeishuBotEvent = normalizeFeishuBotEvent;
5
5
  exports.parseFeishuSourceConfig = parseFeishuSourceConfig;
6
6
  const uxc_daemon_client_1 = require("@holon-run/uxc-daemon-client");
7
7
  exports.FEISHU_OPENAPI_ENDPOINT = "https://open.feishu.cn/open-apis";
8
8
  exports.FEISHU_IM_SCHEMA_URL = "https://raw.githubusercontent.com/holon-run/uxc/main/skills/feishu-openapi-skill/references/feishu-im.openapi.json";
9
9
  exports.DEFAULT_FEISHU_EVENT_TYPES = ["im.message.receive_v1"];
10
- const DEFAULT_SYNC_INTERVAL_SECS = 2;
11
- const MAX_ERROR_BACKOFF_MULTIPLIER = 8;
12
10
  class FeishuUxcClient {
13
11
  client;
14
12
  constructor(client = new uxc_daemon_client_1.UxcDaemonClient({ env: process.env })) {
15
13
  this.client = client;
16
14
  }
17
- async ensureLongConnectionSubscription(config, checkpoint) {
18
- if (checkpoint.uxcJobId) {
19
- try {
20
- const status = await this.client.subscribeStatus(checkpoint.uxcJobId);
21
- if (status.status === "running" || status.status === "reconnecting") {
22
- return {
23
- job_id: checkpoint.uxcJobId,
24
- mode: "stream",
25
- protocol: "feishu_long_connection",
26
- endpoint: config.endpoint ?? exports.FEISHU_OPENAPI_ENDPOINT,
27
- sink: "memory:",
28
- status: status.status,
29
- };
30
- }
31
- }
32
- catch {
33
- // Recreate the job below.
34
- }
35
- }
36
- return this.client.subscribeStart({
37
- endpoint: config.endpoint ?? exports.FEISHU_OPENAPI_ENDPOINT,
38
- mode: "stream",
39
- options: { auth: config.uxcAuth },
40
- sink: "memory:",
41
- ephemeral: false,
42
- transportHint: "feishu_long_connection",
43
- });
44
- }
45
- async readSubscriptionEvents(jobId, afterSeq) {
46
- const response = await this.client.subscriptionEvents({
47
- jobId,
48
- afterSeq,
49
- limit: 100,
50
- waitMs: 10,
51
- });
52
- return {
53
- events: response.events,
54
- nextAfterSeq: response.next_after_seq,
55
- status: response.status,
56
- };
57
- }
58
15
  async sendChatMessage(input) {
59
16
  await this.client.call({
60
17
  endpoint: input.endpoint ?? exports.FEISHU_OPENAPI_ENDPOINT,
@@ -91,176 +48,6 @@ class FeishuUxcClient {
91
48
  }
92
49
  }
93
50
  exports.FeishuUxcClient = FeishuUxcClient;
94
- class FeishuSourceRuntime {
95
- store;
96
- appendSourceEvent;
97
- client;
98
- interval = null;
99
- inFlight = new Set();
100
- errorCounts = new Map();
101
- nextRetryAt = new Map();
102
- constructor(store, appendSourceEvent, client) {
103
- this.store = store;
104
- this.appendSourceEvent = appendSourceEvent;
105
- this.client = client ?? new FeishuUxcClient();
106
- }
107
- async ensureSource(source) {
108
- if (source.sourceType !== "feishu_bot") {
109
- return;
110
- }
111
- const config = parseFeishuSourceConfig(source);
112
- const checkpoint = parseFeishuCheckpoint(source.checkpoint);
113
- const started = await this.client.ensureLongConnectionSubscription(config, checkpoint);
114
- this.store.updateSourceRuntime(source.sourceId, {
115
- status: "active",
116
- checkpoint: JSON.stringify({
117
- ...checkpoint,
118
- uxcJobId: started.job_id,
119
- }),
120
- });
121
- }
122
- async start() {
123
- if (this.interval) {
124
- return;
125
- }
126
- this.interval = setInterval(() => {
127
- void this.syncAll();
128
- }, 2_000);
129
- try {
130
- await this.syncAll();
131
- }
132
- catch (error) {
133
- console.warn("feishu_bot initial sync failed:", error);
134
- }
135
- }
136
- async stop() {
137
- if (this.interval) {
138
- clearInterval(this.interval);
139
- this.interval = null;
140
- }
141
- }
142
- async pollSource(sourceId) {
143
- return this.syncSource(sourceId);
144
- }
145
- status() {
146
- return {
147
- activeSourceIds: Array.from(this.inFlight.values()).sort(),
148
- erroredSourceIds: Array.from(this.errorCounts.keys()).sort(),
149
- };
150
- }
151
- async syncAll() {
152
- const sources = this.store
153
- .listSources()
154
- .filter((source) => source.sourceType === "feishu_bot" && source.status !== "paused");
155
- for (const source of sources) {
156
- try {
157
- await this.syncSource(source.sourceId);
158
- }
159
- catch (error) {
160
- console.warn(`feishu_bot sync failed for ${source.sourceId}:`, error);
161
- }
162
- }
163
- }
164
- async syncSource(sourceId) {
165
- if (this.inFlight.has(sourceId)) {
166
- return {
167
- sourceId,
168
- sourceType: "feishu_bot",
169
- appended: 0,
170
- deduped: 0,
171
- eventsRead: 0,
172
- note: "source sync already in flight",
173
- };
174
- }
175
- this.inFlight.add(sourceId);
176
- try {
177
- const source = this.store.getSource(sourceId);
178
- if (!source) {
179
- throw new Error(`unknown source: ${sourceId}`);
180
- }
181
- const config = parseFeishuSourceConfig(source);
182
- if (source.status === "error") {
183
- const retryAt = this.nextRetryAt.get(sourceId) ?? 0;
184
- if (Date.now() < retryAt) {
185
- return {
186
- sourceId,
187
- sourceType: "feishu_bot",
188
- appended: 0,
189
- deduped: 0,
190
- eventsRead: 0,
191
- note: "error backoff not elapsed",
192
- };
193
- }
194
- }
195
- let checkpoint = parseFeishuCheckpoint(source.checkpoint);
196
- const subscription = await this.client.ensureLongConnectionSubscription(config, checkpoint);
197
- if (subscription.job_id !== checkpoint.uxcJobId) {
198
- checkpoint = { ...checkpoint, uxcJobId: subscription.job_id };
199
- }
200
- const batch = await this.client.readSubscriptionEvents(checkpoint.uxcJobId, checkpoint.afterSeq ?? 0);
201
- let appended = 0;
202
- let deduped = 0;
203
- for (const event of batch.events) {
204
- if (event.event_kind !== "data") {
205
- continue;
206
- }
207
- const normalized = normalizeFeishuBotEvent(source, config, event.data);
208
- if (!normalized) {
209
- continue;
210
- }
211
- const result = await this.appendSourceEvent(normalized);
212
- appended += result.appended;
213
- deduped += result.deduped;
214
- }
215
- this.store.updateSourceRuntime(sourceId, {
216
- status: "active",
217
- checkpoint: JSON.stringify({
218
- ...checkpoint,
219
- uxcJobId: checkpoint.uxcJobId,
220
- afterSeq: batch.nextAfterSeq,
221
- lastEventAt: new Date().toISOString(),
222
- lastError: null,
223
- }),
224
- });
225
- this.errorCounts.delete(sourceId);
226
- this.nextRetryAt.delete(sourceId);
227
- return {
228
- sourceId,
229
- sourceType: "feishu_bot",
230
- appended,
231
- deduped,
232
- eventsRead: batch.events.length,
233
- note: `subscription status=${batch.status}`,
234
- };
235
- }
236
- catch (error) {
237
- const source = this.store.getSource(sourceId);
238
- if (source) {
239
- const checkpoint = parseFeishuCheckpoint(source.checkpoint);
240
- const nextErrorCount = (this.errorCounts.get(sourceId) ?? 0) + 1;
241
- this.errorCounts.set(sourceId, nextErrorCount);
242
- this.nextRetryAt.set(sourceId, Date.now() + computeErrorBackoffMs(DEFAULT_SYNC_INTERVAL_SECS, nextErrorCount));
243
- this.store.updateSourceRuntime(sourceId, {
244
- status: "error",
245
- checkpoint: JSON.stringify({
246
- ...checkpoint,
247
- lastError: error instanceof Error ? error.message : String(error),
248
- }),
249
- });
250
- }
251
- throw error;
252
- }
253
- finally {
254
- this.inFlight.delete(sourceId);
255
- }
256
- }
257
- }
258
- exports.FeishuSourceRuntime = FeishuSourceRuntime;
259
- function computeErrorBackoffMs(syncIntervalSecs, errorCount) {
260
- const baseMs = Math.max(1, syncIntervalSecs) * 1000;
261
- const multiplier = Math.min(2 ** Math.max(0, errorCount - 1), MAX_ERROR_BACKOFF_MULTIPLIER);
262
- return baseMs * multiplier;
263
- }
264
51
  class FeishuDeliveryAdapter {
265
52
  client;
266
53
  constructor(client) {
@@ -376,17 +163,6 @@ function parseFeishuSourceConfig(source) {
376
163
  chatIds: asStringArray(config.chatIds) ?? undefined,
377
164
  };
378
165
  }
379
- function parseFeishuCheckpoint(checkpoint) {
380
- if (!checkpoint) {
381
- return {};
382
- }
383
- try {
384
- return JSON.parse(checkpoint);
385
- }
386
- catch {
387
- return {};
388
- }
389
- }
390
166
  function parseDeliveryConfig(payload) {
391
167
  return {
392
168
  endpoint: asString(payload.endpoint) ?? undefined,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GithubDeliveryAdapter = exports.GithubSourceRuntime = exports.GithubUxcClient = exports.DEFAULT_GITHUB_EVENT_TYPES = exports.GITHUB_ENDPOINT = void 0;
3
+ exports.GithubDeliveryAdapter = exports.GithubUxcClient = exports.DEFAULT_GITHUB_EVENT_TYPES = exports.GITHUB_ENDPOINT = void 0;
4
4
  exports.normalizeGithubRepoEvent = normalizeGithubRepoEvent;
5
5
  exports.parseGithubSourceConfig = parseGithubSourceConfig;
6
6
  const uxc_daemon_client_1 = require("@holon-run/uxc-daemon-client");
@@ -11,64 +11,11 @@ exports.DEFAULT_GITHUB_EVENT_TYPES = [
11
11
  "PullRequestEvent",
12
12
  "PullRequestReviewCommentEvent",
13
13
  ];
14
- const MAX_ERROR_BACKOFF_MULTIPLIER = 8;
15
14
  class GithubUxcClient {
16
15
  client;
17
16
  constructor(client = new uxc_daemon_client_1.UxcDaemonClient({ env: process.env })) {
18
17
  this.client = client;
19
18
  }
20
- async ensureRepoEventsSubscription(config, checkpoint) {
21
- if (checkpoint.uxcJobId) {
22
- try {
23
- const status = await this.client.subscribeStatus(checkpoint.uxcJobId);
24
- if (status.status === "running" || status.status === "reconnecting") {
25
- return {
26
- job_id: checkpoint.uxcJobId,
27
- mode: "poll",
28
- protocol: "openapi",
29
- endpoint: exports.GITHUB_ENDPOINT,
30
- sink: "memory:",
31
- status: status.status,
32
- };
33
- }
34
- }
35
- catch {
36
- // Recreate the job below.
37
- }
38
- }
39
- const started = await this.client.subscribeStart({
40
- endpoint: exports.GITHUB_ENDPOINT,
41
- operationId: "get:/repos/{owner}/{repo}/events",
42
- args: { owner: config.owner, repo: config.repo, per_page: config.perPage ?? 10 },
43
- mode: "poll",
44
- pollConfig: {
45
- interval_secs: config.pollIntervalSecs ?? 30,
46
- extract_items_pointer: "",
47
- checkpoint_strategy: {
48
- type: "item_key",
49
- item_key_pointer: "/id",
50
- seen_window: 1024,
51
- },
52
- },
53
- options: { auth: config.uxcAuth },
54
- sink: "memory:",
55
- ephemeral: false,
56
- });
57
- return started;
58
- }
59
- async readSubscriptionEvents(jobId, afterSeq) {
60
- const response = await this.client.subscriptionEvents({
61
- jobId,
62
- afterSeq,
63
- limit: 100,
64
- waitMs: 10,
65
- });
66
- return {
67
- events: response.events,
68
- nextAfterSeq: response.next_after_seq,
69
- status: response.status,
70
- };
71
- }
72
19
  async createIssueComment(input) {
73
20
  await this.client.call({
74
21
  endpoint: exports.GITHUB_ENDPOINT,
@@ -98,177 +45,6 @@ class GithubUxcClient {
98
45
  }
99
46
  }
100
47
  exports.GithubUxcClient = GithubUxcClient;
101
- class GithubSourceRuntime {
102
- store;
103
- appendSourceEvent;
104
- client;
105
- interval = null;
106
- inFlight = new Set();
107
- errorCounts = new Map();
108
- nextRetryAt = new Map();
109
- constructor(store, appendSourceEvent, client) {
110
- this.store = store;
111
- this.appendSourceEvent = appendSourceEvent;
112
- this.client = client ?? new GithubUxcClient();
113
- }
114
- async ensureSource(source) {
115
- if (source.sourceType !== "github_repo") {
116
- return;
117
- }
118
- const config = parseGithubSourceConfig(source);
119
- const checkpoint = parseGithubCheckpoint(source.checkpoint);
120
- const started = await this.client.ensureRepoEventsSubscription(config, checkpoint);
121
- this.store.updateSourceRuntime(source.sourceId, {
122
- status: "active",
123
- checkpoint: JSON.stringify({
124
- ...checkpoint,
125
- uxcJobId: started.job_id,
126
- }),
127
- });
128
- }
129
- async start() {
130
- if (this.interval) {
131
- return;
132
- }
133
- this.interval = setInterval(() => {
134
- void this.syncAll();
135
- }, 2_000);
136
- try {
137
- await this.syncAll();
138
- }
139
- catch (error) {
140
- console.warn("github_repo initial sync failed:", error);
141
- }
142
- }
143
- async stop() {
144
- if (this.interval) {
145
- clearInterval(this.interval);
146
- this.interval = null;
147
- }
148
- }
149
- async pollSource(sourceId) {
150
- return this.syncSource(sourceId);
151
- }
152
- status() {
153
- return {
154
- activeSourceIds: Array.from(this.inFlight.values()).sort(),
155
- erroredSourceIds: Array.from(this.errorCounts.keys()).sort(),
156
- };
157
- }
158
- async syncAll() {
159
- const sources = this.store
160
- .listSources()
161
- .filter((source) => source.sourceType === "github_repo" && source.status !== "paused");
162
- for (const source of sources) {
163
- try {
164
- await this.syncSource(source.sourceId);
165
- }
166
- catch (error) {
167
- console.warn(`github_repo sync failed for ${source.sourceId}:`, error);
168
- }
169
- }
170
- }
171
- async syncSource(sourceId) {
172
- if (this.inFlight.has(sourceId)) {
173
- return {
174
- sourceId,
175
- sourceType: "github_repo",
176
- appended: 0,
177
- deduped: 0,
178
- eventsRead: 0,
179
- note: "source sync already in flight",
180
- };
181
- }
182
- this.inFlight.add(sourceId);
183
- try {
184
- const source = this.store.getSource(sourceId);
185
- if (!source) {
186
- throw new Error(`unknown source: ${sourceId}`);
187
- }
188
- const config = parseGithubSourceConfig(source);
189
- if (source.status === "error") {
190
- const retryAt = this.nextRetryAt.get(sourceId) ?? 0;
191
- if (Date.now() < retryAt) {
192
- return {
193
- sourceId,
194
- sourceType: "github_repo",
195
- appended: 0,
196
- deduped: 0,
197
- eventsRead: 0,
198
- note: "error backoff not elapsed",
199
- };
200
- }
201
- }
202
- let checkpoint = parseGithubCheckpoint(source.checkpoint);
203
- const subscription = await this.client.ensureRepoEventsSubscription(config, checkpoint);
204
- if (subscription.job_id !== checkpoint.uxcJobId) {
205
- checkpoint = { ...checkpoint, uxcJobId: subscription.job_id };
206
- }
207
- const batch = await this.client.readSubscriptionEvents(checkpoint.uxcJobId, checkpoint.afterSeq ?? 0);
208
- let appended = 0;
209
- let deduped = 0;
210
- for (const event of batch.events) {
211
- if (event.event_kind !== "data") {
212
- continue;
213
- }
214
- const normalized = normalizeGithubRepoEvent(source, config, event.data);
215
- if (!normalized) {
216
- continue;
217
- }
218
- const result = await this.appendSourceEvent(normalized);
219
- appended += result.appended;
220
- deduped += result.deduped;
221
- }
222
- this.store.updateSourceRuntime(sourceId, {
223
- status: "active",
224
- checkpoint: JSON.stringify({
225
- ...checkpoint,
226
- uxcJobId: checkpoint.uxcJobId,
227
- afterSeq: batch.nextAfterSeq,
228
- lastEventAt: new Date().toISOString(),
229
- lastError: null,
230
- }),
231
- });
232
- this.errorCounts.delete(sourceId);
233
- this.nextRetryAt.delete(sourceId);
234
- return {
235
- sourceId,
236
- sourceType: "github_repo",
237
- appended,
238
- deduped,
239
- eventsRead: batch.events.length,
240
- note: `subscription status=${batch.status}`,
241
- };
242
- }
243
- catch (error) {
244
- const source = this.store.getSource(sourceId);
245
- if (source) {
246
- const checkpoint = parseGithubCheckpoint(source.checkpoint);
247
- const config = parseGithubSourceConfig(source);
248
- const nextErrorCount = (this.errorCounts.get(sourceId) ?? 0) + 1;
249
- this.errorCounts.set(sourceId, nextErrorCount);
250
- this.nextRetryAt.set(sourceId, Date.now() + computeErrorBackoffMs(config.pollIntervalSecs ?? 30, nextErrorCount));
251
- this.store.updateSourceRuntime(sourceId, {
252
- status: "error",
253
- checkpoint: JSON.stringify({
254
- ...checkpoint,
255
- lastError: error instanceof Error ? error.message : String(error),
256
- }),
257
- });
258
- }
259
- throw error;
260
- }
261
- finally {
262
- this.inFlight.delete(sourceId);
263
- }
264
- }
265
- }
266
- exports.GithubSourceRuntime = GithubSourceRuntime;
267
- function computeErrorBackoffMs(pollIntervalSecs, errorCount) {
268
- const baseMs = Math.max(1, pollIntervalSecs) * 1000;
269
- const multiplier = Math.min(2 ** Math.max(0, errorCount - 1), MAX_ERROR_BACKOFF_MULTIPLIER);
270
- return baseMs * multiplier;
271
- }
272
48
  class GithubDeliveryAdapter {
273
49
  client;
274
50
  constructor(client) {
@@ -332,7 +108,7 @@ function normalizeGithubRepoEvent(source, config, raw) {
332
108
  const url = asString(comment.html_url) ??
333
109
  asString(issue.html_url) ??
334
110
  asString(pullRequest.html_url) ??
335
- asString(event["url"]);
111
+ asString(event.url);
336
112
  const deliveryHandle = buildGithubDeliveryHandle(config, eventType, number, comment);
337
113
  return {
338
114
  sourceId: source.sourceId,
@@ -416,17 +192,6 @@ function parseGithubSourceConfig(source) {
416
192
  eventTypes: asStringArray(config.eventTypes) ?? exports.DEFAULT_GITHUB_EVENT_TYPES,
417
193
  };
418
194
  }
419
- function parseGithubCheckpoint(checkpoint) {
420
- if (!checkpoint) {
421
- return {};
422
- }
423
- try {
424
- return JSON.parse(checkpoint);
425
- }
426
- catch {
427
- return {};
428
- }
429
- }
430
195
  function extractLabels(raw) {
431
196
  if (!Array.isArray(raw)) {
432
197
  return [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holon-run/agentinbox",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Local event subscription and delivery service for agents.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@fastify/swagger": "^9.5.2",
44
- "@holon-run/uxc-daemon-client": "^0.14.0",
44
+ "@holon-run/uxc-daemon-client": "^0.15.0",
45
45
  "fastify": "^5.6.1",
46
46
  "jexl": "^2.3.0",
47
47
  "sql.js": "^1.13.0"