@agenticros/core 0.8.4 → 0.8.6

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/dist/safety.js ADDED
@@ -0,0 +1,365 @@
1
+ /**
2
+ * Shared safety gates: per-robot velocity limits, optional workspace
3
+ * geofence, and fail-safe zero-Twist on transport loss.
4
+ *
5
+ * Adapters (MCP, OpenClaw, Gemini, teleop, skills) must call these
6
+ * helpers rather than reading `config.safety` directly so a mixed
7
+ * fleet does not share one clamp.
8
+ */
9
+ import { resolveBinding } from "./robot-profile.js";
10
+ export const TWIST_MSG_TYPE = "geometry_msgs/msg/Twist";
11
+ export const ZERO_TWIST = {
12
+ linear: { x: 0, y: 0, z: 0 },
13
+ angular: { x: 0, y: 0, z: 0 },
14
+ };
15
+ const PASS = { block: false };
16
+ function overlayOf(robot) {
17
+ return robot?.safety;
18
+ }
19
+ /**
20
+ * Resolve velocity + workspace limits for a robot. Robot overlay fields
21
+ * win; unset fields inherit the gateway `config.safety` defaults.
22
+ */
23
+ export function resolveSafetyForRobot(config, robot) {
24
+ const gateway = config.safety ?? {
25
+ maxLinearVelocity: 1.0,
26
+ maxAngularVelocity: 1.5,
27
+ };
28
+ const overlay = overlayOf(robot);
29
+ return {
30
+ maxLinearVelocity: overlay?.maxLinearVelocity ?? gateway.maxLinearVelocity ?? 1.0,
31
+ maxAngularVelocity: overlay?.maxAngularVelocity ?? gateway.maxAngularVelocity ?? 1.5,
32
+ workspaceLimits: overlay?.workspaceLimits ?? gateway.workspaceLimits,
33
+ };
34
+ }
35
+ function asRecord(value) {
36
+ if (!value || typeof value !== "object" || Array.isArray(value))
37
+ return undefined;
38
+ return value;
39
+ }
40
+ function num(value, fallback = 0) {
41
+ const n = Number(value);
42
+ return Number.isFinite(n) ? n : fallback;
43
+ }
44
+ /** True when the payload looks like geometry_msgs/Twist. */
45
+ export function isTwistMessage(msg) {
46
+ const rec = asRecord(msg);
47
+ if (!rec)
48
+ return false;
49
+ return asRecord(rec["linear"]) !== undefined || asRecord(rec["angular"]) !== undefined;
50
+ }
51
+ export function checkTwistMessage(limits, msg) {
52
+ if (!isTwistMessage(msg))
53
+ return PASS;
54
+ const rec = asRecord(msg);
55
+ const linear = asRecord(rec["linear"]);
56
+ const angular = asRecord(rec["angular"]);
57
+ if (linear) {
58
+ const speed = Math.sqrt(num(linear["x"]) ** 2 + num(linear["y"]) ** 2 + num(linear["z"]) ** 2);
59
+ if (speed > limits.maxLinearVelocity) {
60
+ return {
61
+ block: true,
62
+ blockReason: `Linear velocity ${speed.toFixed(2)} m/s exceeds safety limit of ${limits.maxLinearVelocity} m/s`,
63
+ };
64
+ }
65
+ }
66
+ if (angular) {
67
+ const rate = Math.abs(num(angular["z"]));
68
+ if (rate > limits.maxAngularVelocity) {
69
+ return {
70
+ block: true,
71
+ blockReason: `Angular velocity ${rate.toFixed(2)} rad/s exceeds safety limit of ${limits.maxAngularVelocity} rad/s`,
72
+ };
73
+ }
74
+ }
75
+ return PASS;
76
+ }
77
+ /** Scale a Twist down to the velocity ceilings (teleop / skills). */
78
+ export function clampTwistToLimits(limits, linearX, linearY, linearZ, angularX, angularY, angularZ) {
79
+ const maxLin = limits.maxLinearVelocity;
80
+ const maxAng = limits.maxAngularVelocity;
81
+ const linMag = Math.sqrt(linearX * linearX + linearY * linearY + linearZ * linearZ);
82
+ const scaleLin = linMag > maxLin && linMag > 0 ? maxLin / linMag : 1;
83
+ const angMag = Math.abs(angularZ);
84
+ const scaleAng = angMag > maxAng && angMag > 0 ? maxAng / angMag : 1;
85
+ return {
86
+ linear: {
87
+ x: linearX * scaleLin,
88
+ y: linearY * scaleLin,
89
+ z: linearZ * scaleLin,
90
+ },
91
+ angular: {
92
+ x: angularX * scaleAng,
93
+ y: angularY * scaleAng,
94
+ z: Math.max(-maxAng, Math.min(maxAng, angularZ)),
95
+ },
96
+ };
97
+ }
98
+ function workspaceMalformed(bounds) {
99
+ if (bounds.xMin > bounds.xMax) {
100
+ return `Malformed workspaceLimits: xMin (${bounds.xMin}) > xMax (${bounds.xMax})`;
101
+ }
102
+ if (bounds.yMin > bounds.yMax) {
103
+ return `Malformed workspaceLimits: yMin (${bounds.yMin}) > yMax (${bounds.yMax})`;
104
+ }
105
+ return undefined;
106
+ }
107
+ export function checkWorkspacePosition(limits, x, y) {
108
+ const bounds = limits.workspaceLimits;
109
+ if (!bounds)
110
+ return PASS;
111
+ const malformed = workspaceMalformed(bounds);
112
+ if (malformed)
113
+ return { block: true, blockReason: malformed };
114
+ if (x < bounds.xMin || x > bounds.xMax || y < bounds.yMin || y > bounds.yMax) {
115
+ return {
116
+ block: true,
117
+ blockReason: `Position (${x.toFixed(2)}, ${y.toFixed(2)}) is outside workspaceLimits ` +
118
+ `[x ${bounds.xMin}..${bounds.xMax}, y ${bounds.yMin}..${bounds.yMax}]`,
119
+ };
120
+ }
121
+ return PASS;
122
+ }
123
+ function pushPosition(out, rec) {
124
+ if (!rec)
125
+ return;
126
+ if ("x" in rec && "y" in rec) {
127
+ out.push({ x: num(rec["x"]), y: num(rec["y"]) });
128
+ return;
129
+ }
130
+ const position = asRecord(rec["position"]);
131
+ if (position && "x" in position && "y" in position) {
132
+ out.push({ x: num(position["x"]), y: num(position["y"]) });
133
+ }
134
+ }
135
+ /**
136
+ * Pull map-frame (x, y) pairs from Twist-unrelated nav payloads:
137
+ * `{x,y}`, Pose, PoseStamped, NavigateToPose goal, NavigateThroughPoses.
138
+ */
139
+ export function extractWorkspacePositions(payload) {
140
+ const out = [];
141
+ const rec = asRecord(payload);
142
+ if (!rec)
143
+ return out;
144
+ if (Array.isArray(rec["poses"])) {
145
+ for (const p of rec["poses"]) {
146
+ out.push(...extractWorkspacePositions(p));
147
+ }
148
+ }
149
+ const nestedGoal = rec["goal"] ?? rec["request"] ?? rec["message"];
150
+ if (nestedGoal && nestedGoal !== payload) {
151
+ out.push(...extractWorkspacePositions(nestedGoal));
152
+ }
153
+ const pose = asRecord(rec["pose"]);
154
+ if (pose) {
155
+ const inner = asRecord(pose["pose"]);
156
+ if (inner) {
157
+ pushPosition(out, inner);
158
+ }
159
+ else {
160
+ pushPosition(out, pose);
161
+ }
162
+ }
163
+ if ("x" in rec && "y" in rec && !asRecord(rec["linear"]) && !asRecord(rec["angular"])) {
164
+ pushPosition(out, rec);
165
+ }
166
+ return out;
167
+ }
168
+ export function checkWorkspacePayload(limits, payload) {
169
+ if (!limits.workspaceLimits)
170
+ return PASS;
171
+ for (const pos of extractWorkspacePositions(payload)) {
172
+ const hit = checkWorkspacePosition(limits, pos.x, pos.y);
173
+ if (hit.block)
174
+ return hit;
175
+ }
176
+ return PASS;
177
+ }
178
+ export function checkPublishSafety(config, params, robot) {
179
+ const limits = resolveSafetyForRobot(config, robot);
180
+ const msg = params["message"];
181
+ const twist = checkTwistMessage(limits, msg);
182
+ if (twist.block)
183
+ return twist;
184
+ return checkWorkspacePayload(limits, msg);
185
+ }
186
+ export function checkActionGoalSafety(config, params, robot) {
187
+ const limits = resolveSafetyForRobot(config, robot);
188
+ const goal = params["goal"] ?? params["args"] ?? params["inputs"] ?? params;
189
+ return checkWorkspacePayload(limits, goal);
190
+ }
191
+ export function checkInputsWorkspace(config, inputs, robot) {
192
+ return checkWorkspacePayload(resolveSafetyForRobot(config, robot), inputs);
193
+ }
194
+ /**
195
+ * A body that accepts Twist. Profile `base` wins; with no profile,
196
+ * anything except an arm-only cell is treated as having a base
197
+ * (legacy configs default kind to "amr").
198
+ */
199
+ export function robotHasMobileBase(robot) {
200
+ if (robot.profile) {
201
+ return robot.profile.features.includes("base");
202
+ }
203
+ const kind = (robot.kind ?? "amr").trim().toLowerCase();
204
+ return kind !== "arm";
205
+ }
206
+ const STOP_PUBLISH_BUDGET_MS = 500;
207
+ /** Best-effort zero Twist on every mobile-base robot sharing this transport. */
208
+ export async function publishStopForBases(transport, robots) {
209
+ const pubs = [];
210
+ for (const robot of robots) {
211
+ if (!robotHasMobileBase(robot))
212
+ continue;
213
+ const topic = resolveBinding(robot, "cmd_vel");
214
+ if (!topic)
215
+ continue;
216
+ try {
217
+ transport.advertise?.({ topic, type: TWIST_MSG_TYPE });
218
+ }
219
+ catch {
220
+ /* rosbridge advertise is optional */
221
+ }
222
+ try {
223
+ const result = transport.publish({
224
+ topic,
225
+ type: TWIST_MSG_TYPE,
226
+ msg: {
227
+ linear: { ...ZERO_TWIST.linear },
228
+ angular: { ...ZERO_TWIST.angular },
229
+ },
230
+ });
231
+ if (result && typeof result.then === "function") {
232
+ pubs.push(Promise.resolve(result).catch(() => { }));
233
+ }
234
+ }
235
+ catch {
236
+ /* socket may already be half-closed */
237
+ }
238
+ }
239
+ if (pubs.length === 0)
240
+ return;
241
+ await Promise.race([
242
+ Promise.all(pubs),
243
+ new Promise((resolve) => setTimeout(resolve, STOP_PUBLISH_BUDGET_MS)),
244
+ ]);
245
+ }
246
+ /**
247
+ * Publish zero Twist when the transport drops (and again on reconnect
248
+ * so a stale last-command cannot resume). Returns an unsubscribe.
249
+ */
250
+ export function attachDisconnectFailSafe(transport, robots) {
251
+ if (typeof transport.onConnection !== "function")
252
+ return () => { };
253
+ let everConnected = transport.getStatus() === "connected";
254
+ return transport.onConnection((status) => {
255
+ if (status === "connected") {
256
+ if (everConnected) {
257
+ void publishStopForBases(transport, robots);
258
+ }
259
+ everConnected = true;
260
+ return;
261
+ }
262
+ if (status === "disconnected" && everConnected) {
263
+ void publishStopForBases(transport, robots);
264
+ }
265
+ });
266
+ }
267
+ const ACTION_BINDING_KEYS = new Set(["navigate_to_pose", "dock"]);
268
+ const EXPECTED_TYPE_FRAGMENT = {
269
+ cmd_vel: /Twist/i,
270
+ odom: /Odometry/i,
271
+ "camera.rgb": /Image/i,
272
+ "camera.depth": /Image/i,
273
+ lidar: /LaserScan|PointCloud/i,
274
+ joint_states: /JointState/i,
275
+ battery: /BatteryState/i,
276
+ };
277
+ function normalizeGraphName(name) {
278
+ const trimmed = name.trim();
279
+ if (!trimmed)
280
+ return trimmed;
281
+ const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
282
+ return withSlash.replace(/\/+$/, "") || "/";
283
+ }
284
+ function findGraphEntry(names, wanted) {
285
+ const target = normalizeGraphName(wanted);
286
+ return names.find((n) => normalizeGraphName(n.name) === target);
287
+ }
288
+ /**
289
+ * Compare declared profile bindings against a live topic/action list.
290
+ * Missing declared hardware is red; type mismatch is yellow.
291
+ */
292
+ export function checkLiveBindings(robots, graph) {
293
+ const checks = [];
294
+ for (const robot of robots) {
295
+ const profile = robot.profile;
296
+ if (!profile)
297
+ continue;
298
+ const entries = Object.entries(profile.bindings);
299
+ if (entries.length === 0) {
300
+ checks.push({
301
+ id: `live-${robot.id}-no-bindings`,
302
+ robotId: robot.id,
303
+ key: "",
304
+ name: "",
305
+ severity: "yellow",
306
+ reason: `Robot "${robot.id}" has a profile but no bindings to verify`,
307
+ });
308
+ continue;
309
+ }
310
+ for (const [key, raw] of entries) {
311
+ const resolved = resolveBinding(robot, key) ??
312
+ (typeof raw === "string" ? raw.trim() : "");
313
+ if (!resolved)
314
+ continue;
315
+ const isAction = ACTION_BINDING_KEYS.has(key);
316
+ const pool = isAction ? (graph.actions ?? []) : graph.topics;
317
+ const found = findGraphEntry(pool, resolved);
318
+ const checkId = `live-${robot.id}-${key}`;
319
+ if (!found) {
320
+ if (isAction && (graph.actions === undefined || graph.actions.length === 0)) {
321
+ checks.push({
322
+ id: checkId,
323
+ robotId: robot.id,
324
+ key,
325
+ name: resolved,
326
+ severity: "yellow",
327
+ reason: `Could not verify action ${key}=${resolved} (transport returned no action list)`,
328
+ });
329
+ continue;
330
+ }
331
+ checks.push({
332
+ id: checkId,
333
+ robotId: robot.id,
334
+ key,
335
+ name: resolved,
336
+ severity: "red",
337
+ reason: `Declared ${key}=${resolved} is not on the live graph`,
338
+ });
339
+ continue;
340
+ }
341
+ const expected = EXPECTED_TYPE_FRAGMENT[key];
342
+ if (expected && found.type && !expected.test(found.type)) {
343
+ checks.push({
344
+ id: checkId,
345
+ robotId: robot.id,
346
+ key,
347
+ name: resolved,
348
+ severity: "yellow",
349
+ reason: `${key}=${resolved} type is ${found.type} (expected ${expected})`,
350
+ });
351
+ continue;
352
+ }
353
+ checks.push({
354
+ id: checkId,
355
+ robotId: robot.id,
356
+ key,
357
+ name: resolved,
358
+ severity: "green",
359
+ reason: `${key}=${resolved} present`,
360
+ });
361
+ }
362
+ }
363
+ return checks;
364
+ }
365
+ //# sourceMappingURL=safety.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safety.js","sourceRoot":"","sources":["../src/safety.ts"],"names":[],"mappings":"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"}
@@ -48,6 +48,9 @@ export declare class TransportPool {
48
48
  private readonly entries;
49
49
  /** Promises kept while a connection is in flight, so concurrent acquires share the same connect. */
50
50
  private readonly inFlight;
51
+ private readonly failSafeUnsub;
52
+ /** Last config passed to acquire — used to resolve which robots share a transport on drain. */
53
+ private lastConfig;
51
54
  constructor(factory?: TransportFactory);
52
55
  /**
53
56
  * Acquire (lazy-connect on first call) the transport for this robot.
@@ -65,6 +68,7 @@ export declare class TransportPool {
65
68
  * times. Errors on individual disconnects are swallowed.
66
69
  */
67
70
  disconnectAll(): Promise<void>;
71
+ private clearFailSafe;
68
72
  /** Visible for tests: how many distinct transports are alive right now. */
69
73
  get size(): number;
70
74
  /** Visible for tests: list of pool keys currently cached. */
@@ -1 +1 @@
1
- {"version":3,"file":"transport-pool.d.ts","sourceRoot":"","sources":["../src/transport-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,eAAe,EAChB,MAAM,YAAY,CAAC;AAUpB,eAAO,MAAM,yBAAyB,eAAe,CAAC;AAEtD,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAE/E,qBAAa,aAAa;IAKZ,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,oGAAoG;IACpG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4C;gBAExC,OAAO,GAAE,gBAAkC;IAExE;;;OAGG;IACG,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAWpF;;;;OAIG;IACG,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAcpC,2EAA2E;IAC3E,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,6DAA6D;IAC7D,IAAI,IAAI,MAAM,EAAE;YAIF,YAAY;CAgC3B"}
1
+ {"version":3,"file":"transport-pool.d.ts","sourceRoot":"","sources":["../src/transport-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,eAAe,EAChB,MAAM,YAAY,CAAC;AAYpB,eAAO,MAAM,yBAAyB,eAAe,CAAC;AAEtD,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAE/E,qBAAa,aAAa;IAQZ,OAAO,CAAC,QAAQ,CAAC,OAAO;IAPpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,oGAAoG;IACpG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4C;IACrE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiC;IAC/D,+FAA+F;IAC/F,OAAO,CAAC,UAAU,CAA+B;gBAEpB,OAAO,GAAE,gBAAkC;IAExE;;;OAGG;IACG,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAYpF;;;;OAIG;IACG,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBpC,OAAO,CAAC,aAAa;IAYrB,2EAA2E;IAC3E,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,6DAA6D;IAC7D,IAAI,IAAI,MAAM,EAAE;YAIF,YAAY;CA2C3B"}
@@ -41,6 +41,8 @@
41
41
  * for the unit-test seam.
42
42
  */
43
43
  import { createTransport, getTransportConfig, getTransportConfigForRobot, hasRobotTransportOverride, resolveRobot, } from "./index.js";
44
+ import { listRobots } from "./robots.js";
45
+ import { attachDisconnectFailSafe, publishStopForBases } from "./safety.js";
44
46
  const CONNECT_TIMEOUT_MS = 15_000;
45
47
  export const TRANSPORT_POOL_GLOBAL_KEY = "__global__";
46
48
  export class TransportPool {
@@ -48,6 +50,9 @@ export class TransportPool {
48
50
  entries = new Map();
49
51
  /** Promises kept while a connection is in flight, so concurrent acquires share the same connect. */
50
52
  inFlight = new Map();
53
+ failSafeUnsub = new Map();
54
+ /** Last config passed to acquire — used to resolve which robots share a transport on drain. */
55
+ lastConfig;
51
56
  constructor(factory = createTransport) {
52
57
  this.factory = factory;
53
58
  }
@@ -56,6 +61,7 @@ export class TransportPool {
56
61
  * See the module docstring for the full key + caching contract.
57
62
  */
58
63
  async acquire(config, robot) {
64
+ this.lastConfig = config;
59
65
  const key = hasRobotTransportOverride(config, robot.id)
60
66
  ? robot.id
61
67
  : TRANSPORT_POOL_GLOBAL_KEY;
@@ -78,15 +84,33 @@ export class TransportPool {
78
84
  */
79
85
  async disconnectAll() {
80
86
  const pending = [];
81
- for (const t of this.entries.values()) {
82
- pending.push(t.disconnect().catch(() => {
83
- /* best-effort drain */
84
- }));
87
+ const cfg = this.lastConfig;
88
+ for (const [key, t] of this.entries) {
89
+ const robots = cfg ? robotsForPoolKey(cfg, key) : [];
90
+ pending.push((async () => {
91
+ await publishStopForBases(t, robots).catch(() => { });
92
+ this.clearFailSafe(key);
93
+ await t.disconnect().catch(() => {
94
+ /* best-effort drain */
95
+ });
96
+ })());
85
97
  }
86
98
  this.entries.clear();
87
99
  this.inFlight.clear();
88
100
  await Promise.all(pending);
89
101
  }
102
+ clearFailSafe(key) {
103
+ const unsub = this.failSafeUnsub.get(key);
104
+ if (unsub) {
105
+ try {
106
+ unsub();
107
+ }
108
+ catch {
109
+ /* ignore */
110
+ }
111
+ this.failSafeUnsub.delete(key);
112
+ }
113
+ }
90
114
  /** Visible for tests: how many distinct transports are alive right now. */
91
115
  get size() {
92
116
  return this.entries.size;
@@ -107,13 +131,24 @@ export class TransportPool {
107
131
  if (cached) {
108
132
  // Stale entry (e.g. router restarted under us). Drop it cleanly.
109
133
  this.entries.delete(key);
110
- cached.disconnect().catch(() => { });
134
+ this.clearFailSafe(key);
135
+ const staleRobots = this.lastConfig ? robotsForPoolKey(this.lastConfig, key) : [];
136
+ void publishStopForBases(cached, staleRobots)
137
+ .catch(() => { })
138
+ .finally(() => {
139
+ cached.disconnect().catch(() => { });
140
+ });
111
141
  }
112
142
  const connectFlight = (async () => {
113
143
  const cfg = resolveCfg();
114
144
  const t = await this.factory(cfg);
115
145
  await connectWithTimeout(t);
116
146
  this.entries.set(key, t);
147
+ if (this.lastConfig) {
148
+ this.clearFailSafe(key);
149
+ const unsub = attachDisconnectFailSafe(t, robotsForPoolKey(this.lastConfig, key));
150
+ this.failSafeUnsub.set(key, unsub);
151
+ }
117
152
  return t;
118
153
  })();
119
154
  this.inFlight.set(key, connectFlight);
@@ -132,4 +167,11 @@ async function connectWithTimeout(t) {
132
167
  });
133
168
  await Promise.race([t.connect(), timeout]);
134
169
  }
170
+ function robotsForPoolKey(config, key) {
171
+ const robots = listRobots(config);
172
+ if (key === TRANSPORT_POOL_GLOBAL_KEY) {
173
+ return robots.filter((r) => !hasRobotTransportOverride(config, r.id));
174
+ }
175
+ return robots.filter((r) => r.id === key);
176
+ }
135
177
  //# sourceMappingURL=transport-pool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transport-pool.js","sourceRoot":"","sources":["../src/transport-pool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transport-pool.js","sourceRoot":"","sources":["../src/transport-pool.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticros/core",
3
- "version": "0.8.4",
3
+ "version": "0.8.6",
4
4
  "type": "module",
5
5
  "description": "AgenticROS core — platform-agnostic ROS2 transport, types, and config (the dep every AgenticROS skill imports).",
6
6
  "keywords": [
@@ -43,13 +43,6 @@
43
43
  "engines": {
44
44
  "node": ">=20"
45
45
  },
46
- "scripts": {
47
- "build": "tsc",
48
- "typecheck": "tsc --noEmit",
49
- "test": "node --test \"dist/memory/__tests__/*.test.js\" \"dist/__tests__/*.test.js\"",
50
- "prepublishOnly": "npm run build",
51
- "pack:dry": "npm pack --dry-run"
52
- },
53
46
  "dependencies": {
54
47
  "@eclipse-zenoh/zenoh-ts": "^1.9.0",
55
48
  "@foxglove/cdr": "^3.5.0",
@@ -68,5 +61,11 @@
68
61
  "typescript": "^5.7.0"
69
62
  },
70
63
  "author": "PlaiPin",
71
- "license": "Apache-2.0"
72
- }
64
+ "license": "Apache-2.0",
65
+ "scripts": {
66
+ "build": "tsc",
67
+ "typecheck": "tsc --noEmit",
68
+ "test": "node --test \"dist/memory/__tests__/*.test.js\" \"dist/__tests__/*.test.js\"",
69
+ "pack:dry": "npm pack --dry-run"
70
+ }
71
+ }