agenticros 0.1.19 → 0.2.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.
Files changed (83) hide show
  1. package/dist/commands/skills.d.ts.map +1 -1
  2. package/dist/commands/skills.js +125 -2
  3. package/dist/commands/skills.js.map +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/menu.js +22 -4
  7. package/dist/menu.js.map +1 -1
  8. package/dist/util/marketplace.d.ts +57 -0
  9. package/dist/util/marketplace.d.ts.map +1 -0
  10. package/dist/util/marketplace.js +144 -0
  11. package/dist/util/marketplace.js.map +1 -0
  12. package/dist/util/skills.d.ts +6 -6
  13. package/dist/util/skills.d.ts.map +1 -1
  14. package/dist/util/skills.js +14 -9
  15. package/dist/util/skills.js.map +1 -1
  16. package/package.json +12 -11
  17. package/runtime/BUNDLE.json +1 -1
  18. package/runtime/README.md +59 -2
  19. package/runtime/packages/agenticros/openclaw.plugin.json +1 -1
  20. package/runtime/packages/agenticros/src/config-page.ts +1 -1
  21. package/runtime/packages/agenticros/src/skill-loader.ts +109 -38
  22. package/runtime/packages/agenticros-claude-code/README.md +52 -9
  23. package/runtime/packages/agenticros-claude-code/dist/__tests__/capabilities-mcp.test.d.ts +2 -0
  24. package/runtime/packages/agenticros-claude-code/dist/__tests__/capabilities-mcp.test.d.ts.map +1 -0
  25. package/runtime/packages/agenticros-claude-code/dist/__tests__/capabilities-mcp.test.js +773 -0
  26. package/runtime/packages/agenticros-claude-code/dist/__tests__/capabilities-mcp.test.js.map +1 -0
  27. package/runtime/packages/agenticros-claude-code/dist/__tests__/follow-me-registry.test.d.ts +2 -0
  28. package/runtime/packages/agenticros-claude-code/dist/__tests__/follow-me-registry.test.d.ts.map +1 -0
  29. package/runtime/packages/agenticros-claude-code/dist/__tests__/follow-me-registry.test.js +97 -0
  30. package/runtime/packages/agenticros-claude-code/dist/__tests__/follow-me-registry.test.js.map +1 -0
  31. package/runtime/packages/agenticros-claude-code/dist/find-object/find-object.d.ts +2 -2
  32. package/runtime/packages/agenticros-claude-code/dist/find-object/find-object.d.ts.map +1 -1
  33. package/runtime/packages/agenticros-claude-code/dist/find-object/find-object.js +5 -5
  34. package/runtime/packages/agenticros-claude-code/dist/find-object/find-object.js.map +1 -1
  35. package/runtime/packages/agenticros-claude-code/dist/follow-me/depth-loop.d.ts +109 -0
  36. package/runtime/packages/agenticros-claude-code/dist/follow-me/depth-loop.d.ts.map +1 -0
  37. package/runtime/packages/agenticros-claude-code/dist/follow-me/depth-loop.js +392 -0
  38. package/runtime/packages/agenticros-claude-code/dist/follow-me/depth-loop.js.map +1 -0
  39. package/runtime/packages/agenticros-claude-code/dist/follow-me/loop.d.ts +8 -3
  40. package/runtime/packages/agenticros-claude-code/dist/follow-me/loop.d.ts.map +1 -1
  41. package/runtime/packages/agenticros-claude-code/dist/follow-me/loop.js +30 -12
  42. package/runtime/packages/agenticros-claude-code/dist/follow-me/loop.js.map +1 -1
  43. package/runtime/packages/agenticros-claude-code/dist/index.js +5 -5
  44. package/runtime/packages/agenticros-claude-code/dist/index.js.map +1 -1
  45. package/runtime/packages/agenticros-claude-code/dist/mission-registry.d.ts +16 -0
  46. package/runtime/packages/agenticros-claude-code/dist/mission-registry.d.ts.map +1 -0
  47. package/runtime/packages/agenticros-claude-code/dist/mission-registry.js +19 -0
  48. package/runtime/packages/agenticros-claude-code/dist/mission-registry.js.map +1 -0
  49. package/runtime/packages/agenticros-claude-code/dist/tools.d.ts +9 -0
  50. package/runtime/packages/agenticros-claude-code/dist/tools.d.ts.map +1 -1
  51. package/runtime/packages/agenticros-claude-code/dist/tools.js +700 -54
  52. package/runtime/packages/agenticros-claude-code/dist/tools.js.map +1 -1
  53. package/runtime/packages/agenticros-claude-code/dist/transport.d.ts +28 -8
  54. package/runtime/packages/agenticros-claude-code/dist/transport.d.ts.map +1 -1
  55. package/runtime/packages/agenticros-claude-code/dist/transport.js +37 -34
  56. package/runtime/packages/agenticros-claude-code/dist/transport.js.map +1 -1
  57. package/runtime/packages/agenticros-claude-code/src/__tests__/capabilities-mcp.test.ts +2 -1
  58. package/runtime/packages/core/LICENSE +192 -0
  59. package/runtime/packages/core/README.md +88 -0
  60. package/runtime/packages/core/package.json +36 -3
  61. package/runtime/packages/core/src/__tests__/capabilities.test.ts +49 -44
  62. package/runtime/packages/core/src/capabilities.ts +19 -45
  63. package/runtime/packages/core/src/config.ts +1 -1
  64. package/runtime/scripts/configure_agenticros.sh +0 -0
  65. package/runtime/scripts/configure_for_sim.sh +0 -0
  66. package/runtime/scripts/fix-openclaw-control-ui-path.sh +0 -0
  67. package/runtime/scripts/install_cli.sh +0 -0
  68. package/runtime/scripts/install_rosbridge_from_source.sh +0 -0
  69. package/runtime/scripts/onboard_robot.sh +0 -0
  70. package/runtime/scripts/pack-runtime.mjs +0 -0
  71. package/runtime/scripts/refresh-skill-deps.mjs +0 -0
  72. package/runtime/scripts/run_demo_native.sh +0 -0
  73. package/runtime/scripts/run_nemoclaw_host_stack.sh +0 -0
  74. package/runtime/scripts/run_robot_rosbridge.sh +0 -0
  75. package/runtime/scripts/setup_gateway_plugin.sh +0 -0
  76. package/runtime/scripts/setup_robot.sh +0 -0
  77. package/runtime/scripts/setup_workspace.sh +0 -0
  78. package/runtime/scripts/sim/run_sim.sh +0 -0
  79. package/runtime/scripts/smoke_test_nemoclaw.sh +0 -0
  80. package/runtime/scripts/start_demo.sh +0 -0
  81. package/runtime/scripts/sync-skill-tools.mjs +2 -2
  82. package/runtime/scripts/use-openclaw-2026.2.26.sh +0 -0
  83. package/runtime/scripts/use-openclaw-2026.3.11.sh +0 -0
@@ -1,8 +1,24 @@
1
1
  {
2
2
  "name": "@agenticros/core",
3
- "version": "0.0.1",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
- "description": "AgenticROS core — platform-agnostic ROS2 transport, types, and config",
5
+ "description": "AgenticROS core — platform-agnostic ROS2 transport, types, and config (the dep every AgenticROS skill imports).",
6
+ "keywords": [
7
+ "agenticros",
8
+ "ros2",
9
+ "robotics",
10
+ "zenoh",
11
+ "rosbridge",
12
+ "webrtc",
13
+ "skill-sdk"
14
+ ],
15
+ "homepage": "https://github.com/agenticros/agenticros#readme",
16
+ "bugs": "https://github.com/agenticros/agenticros/issues",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/agenticros/agenticros.git",
20
+ "directory": "packages/core"
21
+ },
6
22
  "main": "./dist/index.js",
7
23
  "types": "./dist/index.d.ts",
8
24
  "exports": {
@@ -12,10 +28,27 @@
12
28
  "default": "./dist/index.js"
13
29
  }
14
30
  },
31
+ "files": [
32
+ "dist/**/*.js",
33
+ "dist/**/*.d.ts",
34
+ "dist/**/*.js.map",
35
+ "dist/**/*.d.ts.map",
36
+ "!dist/**/__tests__/**",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "engines": {
44
+ "node": ">=20"
45
+ },
15
46
  "scripts": {
16
47
  "build": "tsc",
17
48
  "typecheck": "tsc --noEmit",
18
- "test": "node --test \"dist/memory/__tests__/*.test.js\" \"dist/__tests__/*.test.js\""
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"
19
52
  },
20
53
  "dependencies": {
21
54
  "@eclipse-zenoh/zenoh-ts": "^1.9.0",
@@ -11,12 +11,12 @@
11
11
  * The most upstream of those is "the reader produces what we promised";
12
12
  * everything else depends on that contract holding. So this file pins down:
13
13
  * - BUILTIN_CAPABILITIES has the 6 intrinsic verbs we ship.
14
- * - readSkillCapabilities() picks up package.json's agenticrosSkill object form.
15
- * - It also reads sibling capabilities.json files.
14
+ * - readSkillCapabilities() picks up the `agenticros` block from package.json.
15
+ * - It uses `agenticros.id` (not the package name) as the skill id.
16
16
  * - It tags every capability with a source so dispatchers can filter.
17
17
  * - It deduplicates within a skill so a malformed manifest can't blow up.
18
18
  * - listAllCapabilities() merges intrinsic + skill in that order.
19
- * - It tolerates non-skill packages (no agenticrosSkill key) silently.
19
+ * - It tolerates non-skill packages (no `agenticros` key) silently.
20
20
  */
21
21
  import { test } from "node:test";
22
22
  import assert from "node:assert/strict";
@@ -40,12 +40,10 @@ async function makeSkillDir(
40
40
  root: string,
41
41
  name: string,
42
42
  pkg: Record<string, unknown>,
43
- sidecar?: Record<string, unknown>,
44
43
  ): Promise<string> {
45
44
  const dir = path.join(root, name);
46
45
  await mkdir(dir, { recursive: true });
47
46
  await writeJson(path.join(dir, "package.json"), pkg);
48
- if (sidecar) await writeJson(path.join(dir, "capabilities.json"), sidecar);
49
47
  return dir;
50
48
  }
51
49
 
@@ -66,14 +64,16 @@ test("BUILTIN_CAPABILITIES exposes the six intrinsic robot verbs", () => {
66
64
  }
67
65
  });
68
66
 
69
- test("readSkillCapabilities: reads package.json agenticrosSkill object form", async () => {
67
+ test("readSkillCapabilities: reads capabilities from the `agenticros` block", async () => {
70
68
  const root = await mkdtemp(path.join(tmpdir(), "agenticros-caps-"));
71
69
  try {
72
70
  const skillDir = await makeSkillDir(root, "skill-alpha", {
73
71
  name: "agenticros-skill-alpha",
74
72
  version: "0.0.1",
75
73
  main: "dist/index.js",
76
- agenticrosSkill: {
74
+ agenticros: {
75
+ id: "alpha",
76
+ displayName: "Alpha",
77
77
  capabilities: [
78
78
  {
79
79
  id: "wave_hello",
@@ -114,30 +114,23 @@ test("readSkillCapabilities: reads package.json agenticrosSkill object form", as
114
114
  }
115
115
  });
116
116
 
117
- test("readSkillCapabilities: also reads sibling capabilities.json", async () => {
117
+ test("readSkillCapabilities: uses agenticros.id (not the package name) for the skill id", async () => {
118
118
  const root = await mkdtemp(path.join(tmpdir(), "agenticros-caps-"));
119
119
  try {
120
- const skillDir = await makeSkillDir(
121
- root,
122
- "skill-beta",
123
- {
124
- name: "agenticros-skill-beta",
125
- version: "0.0.1",
126
- agenticrosSkill: true,
127
- },
128
- {
129
- capabilities: [
130
- { id: "sidecar_only", verb: "demo", description: "From sibling." },
131
- ],
120
+ const skillDir = await makeSkillDir(root, "weird-named-repo", {
121
+ name: "@some-org/totally-different-name",
122
+ version: "0.0.1",
123
+ agenticros: {
124
+ id: "explicit-id",
125
+ capabilities: [{ id: "do_thing", verb: "do", description: "Do." }],
132
126
  },
133
- );
134
-
127
+ });
135
128
  const caps = readSkillCapabilities(parseConfig({ skillPaths: [skillDir] }));
136
129
  assert.equal(caps.length, 1);
137
- assert.equal(caps[0].id, "sidecar_only");
138
130
  assert.equal(caps[0].source?.kind, "skill");
139
131
  if (caps[0].source?.kind === "skill") {
140
- assert.equal(caps[0].source.skillId, "beta");
132
+ assert.equal(caps[0].source.skillId, "explicit-id");
133
+ assert.equal(caps[0].source.package, "@some-org/totally-different-name");
141
134
  }
142
135
  } finally {
143
136
  await rm(root, { recursive: true, force: true });
@@ -158,33 +151,26 @@ test("readSkillCapabilities: silently ignores non-skill packages", async () => {
158
151
  }
159
152
  });
160
153
 
161
- test("readSkillCapabilities: dedupes when an id appears in both package.json and sibling", async () => {
154
+ test("readSkillCapabilities: dedupes within a skill when an id appears twice in the array", async () => {
162
155
  const root = await mkdtemp(path.join(tmpdir(), "agenticros-caps-"));
163
156
  try {
164
- const skillDir = await makeSkillDir(
165
- root,
166
- "skill-dupe",
167
- {
168
- name: "agenticros-skill-dupe",
169
- version: "0.0.1",
170
- agenticrosSkill: {
171
- capabilities: [
172
- { id: "shared_id", verb: "first", description: "From package.json." },
173
- ],
174
- },
175
- },
176
- {
157
+ const skillDir = await makeSkillDir(root, "skill-dupe", {
158
+ name: "agenticros-skill-dupe",
159
+ version: "0.0.1",
160
+ agenticros: {
161
+ id: "dupe",
177
162
  capabilities: [
178
- { id: "shared_id", verb: "second", description: "From sidecar (ignored)." },
179
- { id: "extra", verb: "demo", description: "Unique to sidecar." },
163
+ { id: "shared_id", verb: "first", description: "First." },
164
+ { id: "shared_id", verb: "second", description: "Duplicate (ignored)." },
165
+ { id: "extra", verb: "demo", description: "Unique." },
180
166
  ],
181
167
  },
182
- );
168
+ });
183
169
  const caps = readSkillCapabilities(parseConfig({ skillPaths: [skillDir] }));
184
170
  const ids = caps.map((c) => c.id).sort();
185
171
  assert.deepEqual(ids, ["extra", "shared_id"]);
186
172
  const shared = caps.find((c) => c.id === "shared_id");
187
- assert.equal(shared?.verb, "first", "package.json should win over sidecar");
173
+ assert.equal(shared?.verb, "first", "first entry should win on duplicate id");
188
174
  } finally {
189
175
  await rm(root, { recursive: true, force: true });
190
176
  }
@@ -196,7 +182,8 @@ test("readSkillCapabilities: drops entries without a valid id", async () => {
196
182
  const skillDir = await makeSkillDir(root, "skill-bad", {
197
183
  name: "agenticros-skill-bad",
198
184
  version: "0.0.1",
199
- agenticrosSkill: {
185
+ agenticros: {
186
+ id: "bad",
200
187
  capabilities: [
201
188
  { verb: "noid", description: "Missing id." },
202
189
  { id: "", verb: "empty", description: "Empty id." },
@@ -214,13 +201,31 @@ test("readSkillCapabilities: drops entries without a valid id", async () => {
214
201
  }
215
202
  });
216
203
 
204
+ test("readSkillCapabilities: skips packages with an `agenticros` block that lacks an `id`", async () => {
205
+ const root = await mkdtemp(path.join(tmpdir(), "agenticros-caps-"));
206
+ try {
207
+ const skillDir = await makeSkillDir(root, "skill-noid", {
208
+ name: "agenticros-skill-noid",
209
+ version: "0.0.1",
210
+ agenticros: {
211
+ capabilities: [{ id: "do_thing", verb: "do", description: "Do." }],
212
+ },
213
+ });
214
+ const caps = readSkillCapabilities(parseConfig({ skillPaths: [skillDir] }));
215
+ assert.equal(caps.length, 0);
216
+ } finally {
217
+ await rm(root, { recursive: true, force: true });
218
+ }
219
+ });
220
+
217
221
  test("listAllCapabilities: built-ins first, then skill caps; counts add up", async () => {
218
222
  const root = await mkdtemp(path.join(tmpdir(), "agenticros-caps-"));
219
223
  try {
220
224
  const skillDir = await makeSkillDir(root, "skill-extra", {
221
225
  name: "agenticros-skill-extra",
222
226
  version: "0.0.1",
223
- agenticrosSkill: {
227
+ agenticros: {
228
+ id: "extra",
224
229
  capabilities: [
225
230
  { id: "extra_one", verb: "demo", description: "One." },
226
231
  { id: "extra_two", verb: "demo", description: "Two." },
@@ -169,16 +169,6 @@ export const BUILTIN_CAPABILITIES: readonly Capability[] = [
169
169
  },
170
170
  ];
171
171
 
172
- const SKILL_PACKAGE_PREFIX = "agenticros-skill-";
173
-
174
- function deriveSkillId(packageName: string): string {
175
- const lower = packageName.toLowerCase();
176
- if (lower.startsWith(SKILL_PACKAGE_PREFIX)) {
177
- return lower.slice(SKILL_PACKAGE_PREFIX.length);
178
- }
179
- return lower.replace(/^@[^/]+\//, "").replace(/[^a-z0-9]/g, "");
180
- }
181
-
182
172
  function isCapabilityLike(value: unknown): value is Partial<Capability> & { id: string } {
183
173
  if (!value || typeof value !== "object") return false;
184
174
  const v = value as Record<string, unknown>;
@@ -204,53 +194,39 @@ function normalizeCapability(
204
194
  }
205
195
 
206
196
  /**
207
- * Parse the `agenticrosSkill` field from a package.json + a sibling
208
- * `capabilities.json` (if present). Returns the raw capability array or `null`
209
- * if the package isn't an AgenticROS skill.
197
+ * Read the `agenticros.capabilities[]` array from a skill's package.json.
198
+ * Returns `null` if the package doesn't declare a valid `agenticros` block.
199
+ *
200
+ * The legacy `agenticrosSkill: true | { capabilities }` form is NOT supported
201
+ * — every skill must use the single `agenticros` block as its source of truth.
210
202
  */
211
203
  function readSkillManifestFromDir(
212
204
  packageDir: string,
213
- ): { packageName: string; rawCaps: Array<Partial<Capability> & { id: string }> } | null {
205
+ ): { packageName: string; skillId: string; rawCaps: Array<Partial<Capability> & { id: string }> } | null {
214
206
  const pkgJsonPath = join(packageDir, "package.json");
215
207
  if (!existsSync(pkgJsonPath)) return null;
216
208
  let pkg: {
217
209
  name?: string;
218
- agenticrosSkill?: boolean | { capabilities?: unknown };
210
+ agenticros?: { id?: unknown; capabilities?: unknown };
219
211
  };
220
212
  try {
221
213
  pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
222
214
  } catch {
223
215
  return null;
224
216
  }
225
- if (pkg.agenticrosSkill !== true && (typeof pkg.agenticrosSkill !== "object" || pkg.agenticrosSkill === null)) {
226
- return null;
227
- }
228
- const packageName = pkg.name ?? "unknown";
217
+ if (!pkg.agenticros || typeof pkg.agenticros !== "object") return null;
218
+ if (typeof pkg.agenticros.id !== "string") return null;
229
219
 
220
+ const packageName = pkg.name ?? "unknown";
221
+ const skillId = pkg.agenticros.id;
230
222
  const rawCaps: Array<Partial<Capability> & { id: string }> = [];
231
223
 
232
- if (typeof pkg.agenticrosSkill === "object" && pkg.agenticrosSkill !== null) {
233
- const caps = (pkg.agenticrosSkill as { capabilities?: unknown }).capabilities;
234
- if (Array.isArray(caps)) {
235
- for (const c of caps) if (isCapabilityLike(c)) rawCaps.push(c);
236
- }
237
- }
238
-
239
- const sidecarPath = join(packageDir, "capabilities.json");
240
- if (existsSync(sidecarPath)) {
241
- try {
242
- const parsed = JSON.parse(readFileSync(sidecarPath, "utf-8"));
243
- const arr = Array.isArray(parsed)
244
- ? parsed
245
- : Array.isArray((parsed as { capabilities?: unknown }).capabilities)
246
- ? (parsed as { capabilities: unknown[] }).capabilities
247
- : [];
248
- for (const c of arr) if (isCapabilityLike(c)) rawCaps.push(c);
249
- } catch {
250
- }
224
+ const caps = pkg.agenticros.capabilities;
225
+ if (Array.isArray(caps)) {
226
+ for (const c of caps) if (isCapabilityLike(c)) rawCaps.push(c);
251
227
  }
252
228
 
253
- return { packageName, rawCaps };
229
+ return { packageName, skillId, rawCaps };
254
230
  }
255
231
 
256
232
  function resolvePackageDir(packageName: string, searchPaths: string[]): string | null {
@@ -290,15 +266,14 @@ export function readSkillCapabilities(config: AgenticROSConfig): Capability[] {
290
266
  const absDir = resolvePath(dir);
291
267
  const manifest = readSkillManifestFromDir(absDir);
292
268
  if (!manifest) continue;
293
- const skillId = deriveSkillId(manifest.packageName);
294
269
  for (const raw of manifest.rawCaps) {
295
- const key = `${skillId}:${raw.id}`;
270
+ const key = `${manifest.skillId}:${raw.id}`;
296
271
  if (seen.has(key)) continue;
297
272
  seen.add(key);
298
273
  out.push(
299
274
  normalizeCapability(raw, {
300
275
  kind: "skill",
301
- skillId,
276
+ skillId: manifest.skillId,
302
277
  package: manifest.packageName,
303
278
  path: absDir,
304
279
  }),
@@ -311,15 +286,14 @@ export function readSkillCapabilities(config: AgenticROSConfig): Capability[] {
311
286
  if (!packageDir) continue;
312
287
  const manifest = readSkillManifestFromDir(packageDir);
313
288
  if (!manifest) continue;
314
- const skillId = deriveSkillId(manifest.packageName);
315
289
  for (const raw of manifest.rawCaps) {
316
- const key = `${skillId}:${raw.id}`;
290
+ const key = `${manifest.skillId}:${raw.id}`;
317
291
  if (seen.has(key)) continue;
318
292
  seen.add(key);
319
293
  out.push(
320
294
  normalizeCapability(raw, {
321
295
  kind: "skill",
322
- skillId,
296
+ skillId: manifest.skillId,
323
297
  package: manifest.packageName,
324
298
  path: packageDir,
325
299
  }),
@@ -413,7 +413,7 @@ export const AgenticROSConfigSchema = z.object({
413
413
  /** Per-skill config. Keys are skill ids (e.g. followme). Each skill validates its own slice. */
414
414
  skills: z.record(z.string(), z.unknown()).default({}),
415
415
 
416
- /** Directories to scan for skill packages (package.json with "agenticrosSkill": true). Resolved at gateway start. */
416
+ /** Directories to scan for skill packages (package.json with an `agenticros` block). Resolved at gateway start. */
417
417
  skillPaths: z.array(z.string()).default([]),
418
418
 
419
419
  /** Npm (or local) package names to load as skills. Resolved via require.resolve from plugin context. */
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -130,8 +130,8 @@ function findSkillEntryFromPath(dirPath) {
130
130
  warn(`Invalid package.json in ${dirPath}: ${e?.message ?? e}`);
131
131
  return null;
132
132
  }
133
- if (!pkg.agenticrosSkill) {
134
- warn(`Not an AgenticROS skill (missing agenticrosSkill flag): ${dirPath}`);
133
+ if (!pkg.agenticros || typeof pkg.agenticros !== "object" || typeof pkg.agenticros.id !== "string") {
134
+ warn(`Not an AgenticROS skill (missing "agenticros": { "id": "..." } block): ${dirPath}`);
135
135
  return null;
136
136
  }
137
137
  const main = pkg.main ?? "index.js";
File without changes
File without changes