agenticros 0.2.4 → 0.3.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.
- package/README.md +4 -0
- package/dist/__tests__/skill-scaffold.test.d.ts +2 -0
- package/dist/__tests__/skill-scaffold.test.d.ts.map +1 -0
- package/dist/__tests__/skill-scaffold.test.js +80 -0
- package/dist/__tests__/skill-scaffold.test.js.map +1 -0
- package/dist/commands/create-skill.d.ts +9 -0
- package/dist/commands/create-skill.d.ts.map +1 -0
- package/dist/commands/create-skill.js +41 -0
- package/dist/commands/create-skill.js.map +1 -0
- package/dist/commands/publish-skill.d.ts +10 -0
- package/dist/commands/publish-skill.d.ts.map +1 -0
- package/dist/commands/publish-skill.js +222 -0
- package/dist/commands/publish-skill.js.map +1 -0
- package/dist/commands/skills-dev.d.ts +11 -0
- package/dist/commands/skills-dev.d.ts.map +1 -0
- package/dist/commands/skills-dev.js +154 -0
- package/dist/commands/skills-dev.js.map +1 -0
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +21 -11
- package/dist/commands/skills.js.map +1 -1
- package/dist/index.js +37 -2
- package/dist/index.js.map +1 -1
- package/dist/menu.d.ts.map +1 -1
- package/dist/menu.js +28 -2
- package/dist/menu.js.map +1 -1
- package/dist/util/marketplace.d.ts +26 -2
- package/dist/util/marketplace.d.ts.map +1 -1
- package/dist/util/marketplace.js +56 -4
- package/dist/util/marketplace.js.map +1 -1
- package/dist/util/skill-manifest.d.ts +58 -0
- package/dist/util/skill-manifest.d.ts.map +1 -0
- package/dist/util/skill-manifest.js +81 -0
- package/dist/util/skill-manifest.js.map +1 -0
- package/dist/util/skill-scaffold.d.ts +26 -0
- package/dist/util/skill-scaffold.d.ts.map +1 -0
- package/dist/util/skill-scaffold.js +153 -0
- package/dist/util/skill-scaffold.js.map +1 -0
- package/package.json +2 -1
- package/runtime/BUNDLE.json +1 -1
- package/runtime/README.md +2 -0
- package/runtime/docs/cli.md +12 -0
- package/templates/skills/camera/README.md +16 -0
- package/templates/skills/camera/demo.md +5 -0
- package/templates/skills/camera/package.json +38 -0
- package/templates/skills/camera/src/index.ts +68 -0
- package/templates/skills/camera/tsconfig.json +15 -0
- package/templates/skills/depth/README.md +16 -0
- package/templates/skills/depth/demo.md +5 -0
- package/templates/skills/depth/package.json +38 -0
- package/templates/skills/depth/src/index.ts +69 -0
- package/templates/skills/depth/tsconfig.json +15 -0
- package/templates/skills/hello/README.md +32 -0
- package/templates/skills/hello/demo.md +5 -0
- package/templates/skills/hello/package.json +37 -0
- package/templates/skills/hello/src/index.ts +37 -0
- package/templates/skills/hello/tsconfig.json +15 -0
- package/templates/skills/robot/README.md +18 -0
- package/templates/skills/robot/demo.md +5 -0
- package/templates/skills/robot/package.json +40 -0
- package/templates/skills/robot/src/index.ts +69 -0
- package/templates/skills/robot/tsconfig.json +15 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local validation of skill package.json manifests.
|
|
3
|
+
* Keep in sync with agenticros-skills/functions/src/util/manifest.ts
|
|
4
|
+
*/
|
|
5
|
+
export class ManifestError extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "ManifestError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$/;
|
|
12
|
+
export function isValidSlug(slug) {
|
|
13
|
+
return SLUG_RE.test(slug);
|
|
14
|
+
}
|
|
15
|
+
export function validateManifest(raw) {
|
|
16
|
+
if (!raw || typeof raw !== "object") {
|
|
17
|
+
throw new ManifestError("package.json is missing or empty");
|
|
18
|
+
}
|
|
19
|
+
const m = raw;
|
|
20
|
+
if (!m.name || typeof m.name !== "string") {
|
|
21
|
+
throw new ManifestError("package.json must declare a `name`");
|
|
22
|
+
}
|
|
23
|
+
if (!m.version || typeof m.version !== "string") {
|
|
24
|
+
throw new ManifestError("package.json must declare a `version`");
|
|
25
|
+
}
|
|
26
|
+
if (!m.main || typeof m.main !== "string") {
|
|
27
|
+
throw new ManifestError("package.json must declare a `main` entry (e.g. `dist/index.js`).");
|
|
28
|
+
}
|
|
29
|
+
if (!m.agenticros || typeof m.agenticros !== "object") {
|
|
30
|
+
throw new ManifestError("package.json must declare an `agenticros` block. See https://skills.agenticros.com");
|
|
31
|
+
}
|
|
32
|
+
const block = m.agenticros;
|
|
33
|
+
if (!block.id || typeof block.id !== "string" || !isValidSlug(block.id)) {
|
|
34
|
+
throw new ManifestError("`agenticros.id` is required and must be a kebab-case slug (2-64 chars, [a-z0-9-]).");
|
|
35
|
+
}
|
|
36
|
+
const warnings = [];
|
|
37
|
+
if (m.agenticrosSkill !== undefined) {
|
|
38
|
+
warnings.push("The legacy `agenticrosSkill` field is deprecated. Move metadata into the `agenticros` block.");
|
|
39
|
+
}
|
|
40
|
+
const coreDep = m.dependencies?.["@agenticros/core"];
|
|
41
|
+
if (coreDep?.startsWith("file:")) {
|
|
42
|
+
warnings.push("`@agenticros/core` is declared as a `file:` path. Publish a version from npm (e.g. `^0.5.0`) before others can install your skill.");
|
|
43
|
+
}
|
|
44
|
+
if (!block.description && !m.description) {
|
|
45
|
+
warnings.push("Add a one-sentence `description` (top-level or in `agenticros`).");
|
|
46
|
+
}
|
|
47
|
+
if (!block.capabilities || block.capabilities.length === 0) {
|
|
48
|
+
warnings.push("Declare at least one capability in `agenticros.capabilities` so the agent planner can reason about your skill.");
|
|
49
|
+
}
|
|
50
|
+
if (!block.screenshots || block.screenshots.length === 0) {
|
|
51
|
+
warnings.push("Add at least one entry to `agenticros.screenshots` so the marketplace card has a preview image.");
|
|
52
|
+
}
|
|
53
|
+
return { manifest: m, block, warnings };
|
|
54
|
+
}
|
|
55
|
+
export function manifestRepoUrl(m) {
|
|
56
|
+
if (!m.repository)
|
|
57
|
+
return null;
|
|
58
|
+
if (typeof m.repository === "string")
|
|
59
|
+
return m.repository;
|
|
60
|
+
return m.repository.url ?? null;
|
|
61
|
+
}
|
|
62
|
+
export function firestoreDocId(ownerLogin, skillSlug) {
|
|
63
|
+
return `${ownerLogin.toLowerCase()}__${skillSlug}`;
|
|
64
|
+
}
|
|
65
|
+
export function marketplaceRef(ownerLogin, skillSlug) {
|
|
66
|
+
return `${ownerLogin.toLowerCase()}/${skillSlug}`;
|
|
67
|
+
}
|
|
68
|
+
export function parseMarketplaceRef(ref) {
|
|
69
|
+
const trimmed = ref.trim();
|
|
70
|
+
const slash = trimmed.indexOf("/");
|
|
71
|
+
if (slash <= 0 || slash === trimmed.length - 1)
|
|
72
|
+
return null;
|
|
73
|
+
const owner = trimmed.slice(0, slash).toLowerCase();
|
|
74
|
+
const skill = trimmed.slice(slash + 1);
|
|
75
|
+
if (!/^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?$/.test(owner))
|
|
76
|
+
return null;
|
|
77
|
+
if (!isValidSlug(skill))
|
|
78
|
+
return null;
|
|
79
|
+
return { owner, skill };
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=skill-manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-manifest.js","sourceRoot":"","sources":["../../src/util/skill-manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill scaffolding — copy embedded templates into cwd/agenticros-skill-<slug>/.
|
|
3
|
+
*/
|
|
4
|
+
export type SkillTemplate = "hello" | "robot" | "camera" | "depth";
|
|
5
|
+
export declare function normalizeTemplate(input: string | undefined): SkillTemplate;
|
|
6
|
+
export declare function normalizeSkillSlug(input: string): string;
|
|
7
|
+
export declare function slugToToolName(slug: string): string;
|
|
8
|
+
export declare function slugToDisplayName(slug: string): string;
|
|
9
|
+
export interface ScaffoldOptions {
|
|
10
|
+
slug: string;
|
|
11
|
+
template?: string;
|
|
12
|
+
cwd?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ScaffoldResult {
|
|
15
|
+
dir: string;
|
|
16
|
+
slug: string;
|
|
17
|
+
template: SkillTemplate;
|
|
18
|
+
toolName: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function scaffoldSkill(opts: ScaffoldOptions): ScaffoldResult;
|
|
21
|
+
/** SHA-256 of normalized template source (for tutorial graduation checks). */
|
|
22
|
+
export declare function hashSkillSource(source: string): string;
|
|
23
|
+
export declare function getTemplateFingerprints(): Record<SkillTemplate, string>;
|
|
24
|
+
export declare function isUnmodifiedTemplate(source: string, template: SkillTemplate): boolean;
|
|
25
|
+
export declare function readSkillIndexSource(skillDir: string): string | null;
|
|
26
|
+
//# sourceMappingURL=skill-scaffold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-scaffold.d.ts","sourceRoot":"","sources":["../../src/util/skill-scaffold.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AA2CnE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAS1E;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAcxD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMtD;AAkCD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,aAAa,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,eAAe,GAAG,cAAc,CAiCnE;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAUvE;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,aAAa,GACtB,OAAO,CAKT;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIpE"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill scaffolding — copy embedded templates into cwd/agenticros-skill-<slug>/.
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync, } from "node:fs";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$/;
|
|
9
|
+
const TEMPLATE_ALIASES = {
|
|
10
|
+
hello: "hello",
|
|
11
|
+
h: "hello",
|
|
12
|
+
robot: "robot",
|
|
13
|
+
r: "robot",
|
|
14
|
+
camera: "camera",
|
|
15
|
+
c: "camera",
|
|
16
|
+
depth: "depth",
|
|
17
|
+
d: "depth",
|
|
18
|
+
};
|
|
19
|
+
const TEMPLATE_DEFAULTS = {
|
|
20
|
+
hello: {
|
|
21
|
+
displayName: "Hello World",
|
|
22
|
+
description: "My first AgenticROS skill — returns a friendly greeting.",
|
|
23
|
+
},
|
|
24
|
+
robot: {
|
|
25
|
+
displayName: "Wave Hand",
|
|
26
|
+
description: "Wave the robot base with a brief cmd_vel gesture.",
|
|
27
|
+
},
|
|
28
|
+
camera: {
|
|
29
|
+
displayName: "Describe Scene",
|
|
30
|
+
description: "Capture one frame from the robot camera.",
|
|
31
|
+
},
|
|
32
|
+
depth: {
|
|
33
|
+
displayName: "Measure Distance",
|
|
34
|
+
description: "Sample depth at the center of the depth image.",
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
/** Minimal 1×1 PNG (valid placeholder for docs/icon.png). */
|
|
38
|
+
const PLACEHOLDER_PNG = Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==", "base64");
|
|
39
|
+
export function normalizeTemplate(input) {
|
|
40
|
+
const key = (input ?? "hello").toLowerCase().trim();
|
|
41
|
+
const t = TEMPLATE_ALIASES[key];
|
|
42
|
+
if (!t) {
|
|
43
|
+
throw new Error(`Unknown template "${input}". Use: hello, robot, camera, or depth.`);
|
|
44
|
+
}
|
|
45
|
+
return t;
|
|
46
|
+
}
|
|
47
|
+
export function normalizeSkillSlug(input) {
|
|
48
|
+
const slug = input
|
|
49
|
+
.trim()
|
|
50
|
+
.toLowerCase()
|
|
51
|
+
.replace(/^@[^/]+\//, "")
|
|
52
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
53
|
+
.replace(/-+/g, "-")
|
|
54
|
+
.replace(/^-|-$/g, "");
|
|
55
|
+
if (!slug || !SLUG_RE.test(slug)) {
|
|
56
|
+
throw new Error("Skill slug must be kebab-case (2–64 chars, [a-z0-9-]), e.g. hello-world or follow-me.");
|
|
57
|
+
}
|
|
58
|
+
return slug;
|
|
59
|
+
}
|
|
60
|
+
export function slugToToolName(slug) {
|
|
61
|
+
return slug.replace(/-/g, "_");
|
|
62
|
+
}
|
|
63
|
+
export function slugToDisplayName(slug) {
|
|
64
|
+
return slug
|
|
65
|
+
.split("-")
|
|
66
|
+
.filter(Boolean)
|
|
67
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
68
|
+
.join(" ");
|
|
69
|
+
}
|
|
70
|
+
function templatesRoot() {
|
|
71
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
72
|
+
return join(here, "..", "..", "templates", "skills");
|
|
73
|
+
}
|
|
74
|
+
function substituteVars(content, vars) {
|
|
75
|
+
let out = content;
|
|
76
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
77
|
+
out = out.replaceAll(`{{${key}}}`, value);
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
function copyTemplateTree(srcDir, destDir, vars) {
|
|
82
|
+
for (const name of readdirSync(srcDir)) {
|
|
83
|
+
const src = join(srcDir, name);
|
|
84
|
+
const dest = join(destDir, name);
|
|
85
|
+
const st = statSync(src);
|
|
86
|
+
if (st.isDirectory()) {
|
|
87
|
+
mkdirSync(dest, { recursive: true });
|
|
88
|
+
copyTemplateTree(src, dest, vars);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const raw = readFileSync(src, "utf8");
|
|
92
|
+
writeFileSync(dest, substituteVars(raw, vars), "utf8");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export function scaffoldSkill(opts) {
|
|
97
|
+
const slug = normalizeSkillSlug(opts.slug);
|
|
98
|
+
const template = normalizeTemplate(opts.template);
|
|
99
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
100
|
+
const dir = resolve(cwd, `agenticros-skill-${slug}`);
|
|
101
|
+
if (existsSync(dir)) {
|
|
102
|
+
throw new Error(`Directory already exists: ${dir}`);
|
|
103
|
+
}
|
|
104
|
+
const defaults = TEMPLATE_DEFAULTS[template];
|
|
105
|
+
const displayName = slugToDisplayName(slug);
|
|
106
|
+
const toolName = slugToToolName(slug);
|
|
107
|
+
const vars = {
|
|
108
|
+
slug,
|
|
109
|
+
displayName,
|
|
110
|
+
toolName,
|
|
111
|
+
description: defaults.description,
|
|
112
|
+
};
|
|
113
|
+
const srcTemplate = join(templatesRoot(), template);
|
|
114
|
+
if (!existsSync(srcTemplate)) {
|
|
115
|
+
throw new Error(`Template not found on disk: ${srcTemplate}`);
|
|
116
|
+
}
|
|
117
|
+
mkdirSync(dir, { recursive: true });
|
|
118
|
+
copyTemplateTree(srcTemplate, dir, vars);
|
|
119
|
+
const docsDir = join(dir, "docs");
|
|
120
|
+
mkdirSync(docsDir, { recursive: true });
|
|
121
|
+
writeFileSync(join(docsDir, "icon.png"), PLACEHOLDER_PNG);
|
|
122
|
+
return { dir, slug, template, toolName };
|
|
123
|
+
}
|
|
124
|
+
/** SHA-256 of normalized template source (for tutorial graduation checks). */
|
|
125
|
+
export function hashSkillSource(source) {
|
|
126
|
+
const normalized = source.replace(/\s+/g, " ").trim();
|
|
127
|
+
return createHash("sha256").update(normalized).digest("hex");
|
|
128
|
+
}
|
|
129
|
+
export function getTemplateFingerprints() {
|
|
130
|
+
const root = templatesRoot();
|
|
131
|
+
const out = {};
|
|
132
|
+
for (const t of ["hello", "robot", "camera", "depth"]) {
|
|
133
|
+
const indexPath = join(root, t, "src", "index.ts");
|
|
134
|
+
if (existsSync(indexPath)) {
|
|
135
|
+
out[t] = hashSkillSource(readFileSync(indexPath, "utf8"));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
export function isUnmodifiedTemplate(source, template) {
|
|
141
|
+
const fps = getTemplateFingerprints();
|
|
142
|
+
const fp = fps[template];
|
|
143
|
+
if (!fp)
|
|
144
|
+
return false;
|
|
145
|
+
return hashSkillSource(source) === fp;
|
|
146
|
+
}
|
|
147
|
+
export function readSkillIndexSource(skillDir) {
|
|
148
|
+
const path = join(skillDir, "src", "index.ts");
|
|
149
|
+
if (!existsSync(path))
|
|
150
|
+
return null;
|
|
151
|
+
return readFileSync(path, "utf8");
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=skill-scaffold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-scaffold.js","sourceRoot":"","sources":["../../src/util/skill-scaffold.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agenticros",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgenticROS - agentic AI for ROS-powered robots. Single CLI to launch real-robot or simulated demos, manage configuration, and inspect status.",
|
|
6
6
|
"keywords": [
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
23
|
"dist",
|
|
24
|
+
"templates",
|
|
24
25
|
"runtime",
|
|
25
26
|
"README.md",
|
|
26
27
|
"LICENSE"
|
package/runtime/BUNDLE.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"packedAt": "2026-06-
|
|
2
|
+
"packedAt": "2026-06-30T01:58:21.409Z",
|
|
3
3
|
"repo": "https://github.com/PlaiPin/agenticros",
|
|
4
4
|
"note": "This directory is a snapshot of the agenticros monorepo source. `agenticros init` will copy it to ~/agenticros and run pnpm install + colcon build there.",
|
|
5
5
|
"layout": {
|
package/runtime/README.md
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
**Physical AI Agents for ROS Robots**
|
|
14
14
|
|
|
15
|
+

|
|
16
|
+
|
|
15
17
|
[](https://www.youtube.com/watch?v=_fbWhYcPj0M)
|
|
16
18
|
|
|
17
19
|
> ▶ [Watch the AgenticROS intro on YouTube](https://www.youtube.com/watch?v=_fbWhYcPj0M)
|
package/runtime/docs/cli.md
CHANGED
|
@@ -124,6 +124,18 @@ Read or edit `~/.agenticros/config.json`. Actions:
|
|
|
124
124
|
| `AGENTICROS_CONFIG_PATH` | (auto) | Override the path to `~/.agenticros/config.json`. |
|
|
125
125
|
| `AGENTICROS_ROBOT_NAMESPACE` | (from config) | Force a robot namespace at runtime. |
|
|
126
126
|
| `OPENAI_API_KEY` | (none) | If set, doctor reports green without requiring OpenClaw profile config. |
|
|
127
|
+
| `AGENTICROS_SKILLS_API` | `https://skills.agenticros.com/api` | Override marketplace API base URL. |
|
|
128
|
+
| `GH_TOKEN` / `GITHUB_TOKEN` | (none) | GitHub PAT for `agenticros publish`. |
|
|
129
|
+
|
|
130
|
+
### Skill authoring
|
|
131
|
+
|
|
132
|
+
| Command | Purpose |
|
|
133
|
+
|---|---|
|
|
134
|
+
| `agenticros create-skill <slug> [--template hello\|robot\|camera\|depth]` | Scaffold `./agenticros-skill-<slug>/` in cwd. |
|
|
135
|
+
| `agenticros skills dev [--invoke <tool>] [--live]` | Load the skill locally without OpenClaw. |
|
|
136
|
+
| `agenticros publish [--graduate]` | Validate, push to GitHub, submit to skills.agenticros.com. |
|
|
137
|
+
| `agenticros skills install <owner/skill>` | Install from marketplace (e.g. `agenticros/followme`). |
|
|
138
|
+
| `agenticros skills search <q>` | Search the marketplace. |
|
|
127
139
|
|
|
128
140
|
## Troubleshooting
|
|
129
141
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agenticros-skill-{{slug}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "{{description}}",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"typecheck": "tsc --noEmit",
|
|
11
|
+
"dev": "npx agenticros skills dev"
|
|
12
|
+
},
|
|
13
|
+
"agenticros": {
|
|
14
|
+
"id": "{{slug}}",
|
|
15
|
+
"displayName": "{{displayName}}",
|
|
16
|
+
"description": "{{description}}",
|
|
17
|
+
"tutorial": false,
|
|
18
|
+
"categories": ["vision"],
|
|
19
|
+
"screenshots": ["docs/icon.png"],
|
|
20
|
+
"capabilities": [
|
|
21
|
+
{
|
|
22
|
+
"id": "{{toolName}}",
|
|
23
|
+
"verb": "capture",
|
|
24
|
+
"description": "{{description}}"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@agenticros/core": "^0.5.0",
|
|
30
|
+
"@sinclair/typebox": "^0.34.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^20.17.0",
|
|
34
|
+
"typescript": "^5.7.0"
|
|
35
|
+
},
|
|
36
|
+
"keywords": ["agenticros", "camera", "vision"],
|
|
37
|
+
"license": "Apache-2.0"
|
|
38
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {{displayName}} — capture one frame from the robot camera.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Type } from "@sinclair/typebox";
|
|
6
|
+
import type { RosTransport } from "@agenticros/core";
|
|
7
|
+
|
|
8
|
+
const TOOL_NAME = "{{toolName}}";
|
|
9
|
+
|
|
10
|
+
interface SkillContext {
|
|
11
|
+
getTransport(): RosTransport;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface SkillPluginApi {
|
|
15
|
+
registerTool(tool: {
|
|
16
|
+
name: string;
|
|
17
|
+
label: string;
|
|
18
|
+
description: string;
|
|
19
|
+
parameters: unknown;
|
|
20
|
+
execute: (
|
|
21
|
+
toolCallId: string,
|
|
22
|
+
params: Record<string, unknown>,
|
|
23
|
+
signal?: AbortSignal,
|
|
24
|
+
) => Promise<{ content: { type: string; text: string }[]; details?: unknown }>;
|
|
25
|
+
}): void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function registerSkill(
|
|
29
|
+
api: SkillPluginApi,
|
|
30
|
+
config: { robot?: { cameraTopic?: string } },
|
|
31
|
+
context: SkillContext,
|
|
32
|
+
): void {
|
|
33
|
+
api.registerTool({
|
|
34
|
+
name: TOOL_NAME,
|
|
35
|
+
label: "{{displayName}}",
|
|
36
|
+
description: "{{description}}",
|
|
37
|
+
parameters: Type.Object({
|
|
38
|
+
topic: Type.Optional(
|
|
39
|
+
Type.String({ description: "Camera topic override (default from robot config)." }),
|
|
40
|
+
),
|
|
41
|
+
}),
|
|
42
|
+
async execute(_id, params) {
|
|
43
|
+
const transport = context.getTransport();
|
|
44
|
+
const topic =
|
|
45
|
+
(typeof params.topic === "string" && params.topic) ||
|
|
46
|
+
config.robot?.cameraTopic ||
|
|
47
|
+
"camera/color/image_raw";
|
|
48
|
+
const msg = await transport.subscribeOnce(topic, 5000);
|
|
49
|
+
const encoding =
|
|
50
|
+
msg && typeof msg === "object" && "encoding" in msg
|
|
51
|
+
? String((msg as { encoding?: string }).encoding ?? "unknown")
|
|
52
|
+
: "unknown";
|
|
53
|
+
const width =
|
|
54
|
+
msg && typeof msg === "object" && "width" in msg
|
|
55
|
+
? Number((msg as { width?: number }).width ?? 0)
|
|
56
|
+
: 0;
|
|
57
|
+
const height =
|
|
58
|
+
msg && typeof msg === "object" && "height" in msg
|
|
59
|
+
? Number((msg as { height?: number }).height ?? 0)
|
|
60
|
+
: 0;
|
|
61
|
+
const summary = `Captured ${width}x${height} frame (${encoding}) from ${topic}.`;
|
|
62
|
+
return {
|
|
63
|
+
content: [{ type: "text", text: summary }],
|
|
64
|
+
details: { topic, width, height, encoding, captured: Boolean(msg) },
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"rootDir": "src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"declarationMap": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"skipLibCheck": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agenticros-skill-{{slug}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "{{description}}",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"typecheck": "tsc --noEmit",
|
|
11
|
+
"dev": "npx agenticros skills dev"
|
|
12
|
+
},
|
|
13
|
+
"agenticros": {
|
|
14
|
+
"id": "{{slug}}",
|
|
15
|
+
"displayName": "{{displayName}}",
|
|
16
|
+
"description": "{{description}}",
|
|
17
|
+
"tutorial": false,
|
|
18
|
+
"categories": ["vision", "telemetry"],
|
|
19
|
+
"screenshots": ["docs/icon.png"],
|
|
20
|
+
"capabilities": [
|
|
21
|
+
{
|
|
22
|
+
"id": "{{toolName}}",
|
|
23
|
+
"verb": "measure",
|
|
24
|
+
"description": "{{description}}"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@agenticros/core": "^0.5.0",
|
|
30
|
+
"@sinclair/typebox": "^0.34.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^20.17.0",
|
|
34
|
+
"typescript": "^5.7.0"
|
|
35
|
+
},
|
|
36
|
+
"keywords": ["agenticros", "depth", "realsense"],
|
|
37
|
+
"license": "Apache-2.0"
|
|
38
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {{displayName}} — sample depth at image center (RealSense / depth camera).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Type } from "@sinclair/typebox";
|
|
6
|
+
import type { RosTransport } from "@agenticros/core";
|
|
7
|
+
|
|
8
|
+
const TOOL_NAME = "{{toolName}}";
|
|
9
|
+
|
|
10
|
+
interface DepthSampleResult {
|
|
11
|
+
distance_m: number;
|
|
12
|
+
valid: boolean;
|
|
13
|
+
topic: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface SkillContext {
|
|
17
|
+
getTransport(): RosTransport;
|
|
18
|
+
getDepthDistance(
|
|
19
|
+
transport: RosTransport,
|
|
20
|
+
topic: string,
|
|
21
|
+
timeoutMs?: number,
|
|
22
|
+
): Promise<DepthSampleResult>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface SkillPluginApi {
|
|
26
|
+
registerTool(tool: {
|
|
27
|
+
name: string;
|
|
28
|
+
label: string;
|
|
29
|
+
description: string;
|
|
30
|
+
parameters: unknown;
|
|
31
|
+
execute: (
|
|
32
|
+
toolCallId: string,
|
|
33
|
+
params: Record<string, unknown>,
|
|
34
|
+
signal?: AbortSignal,
|
|
35
|
+
) => Promise<{ content: { type: string; text: string }[]; details?: unknown }>;
|
|
36
|
+
}): void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function registerSkill(
|
|
40
|
+
api: SkillPluginApi,
|
|
41
|
+
config: { robot?: { depthTopic?: string } },
|
|
42
|
+
context: SkillContext,
|
|
43
|
+
): void {
|
|
44
|
+
api.registerTool({
|
|
45
|
+
name: TOOL_NAME,
|
|
46
|
+
label: "{{displayName}}",
|
|
47
|
+
description: "{{description}}",
|
|
48
|
+
parameters: Type.Object({
|
|
49
|
+
topic: Type.Optional(
|
|
50
|
+
Type.String({ description: "Depth topic override (default: depth/image_rect_raw)." }),
|
|
51
|
+
),
|
|
52
|
+
}),
|
|
53
|
+
async execute(_id, params) {
|
|
54
|
+
const transport = context.getTransport();
|
|
55
|
+
const topic =
|
|
56
|
+
(typeof params.topic === "string" && params.topic) ||
|
|
57
|
+
config.robot?.depthTopic ||
|
|
58
|
+
"depth/image_rect_raw";
|
|
59
|
+
const sample = await context.getDepthDistance(transport, topic, 5000);
|
|
60
|
+
const text = sample.valid
|
|
61
|
+
? `Object is ${sample.distance_m.toFixed(1)} meters away.`
|
|
62
|
+
: `No valid depth reading on ${topic}.`;
|
|
63
|
+
return {
|
|
64
|
+
content: [{ type: "text", text }],
|
|
65
|
+
details: sample,
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"rootDir": "src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"declarationMap": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"skipLibCheck": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# {{displayName}}
|
|
2
|
+
|
|
3
|
+
{{description}}
|
|
4
|
+
|
|
5
|
+
> **Tutorial skill** — meant for local learning with `npm run dev`. Customize the code or scaffold with `--template robot` before publishing to the marketplace.
|
|
6
|
+
|
|
7
|
+
## Local dev
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install
|
|
11
|
+
npm run dev
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Invoke (OpenClaw / Claude / Gemini)
|
|
15
|
+
|
|
16
|
+
After registering with your gateway:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
agenticros skills add .
|
|
20
|
+
agenticros skills sync
|
|
21
|
+
# restart gateway
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Try prompts from [demo.md](./demo.md).
|
|
25
|
+
|
|
26
|
+
## Publish
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx agenticros publish
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Tutorial skills stay unlisted on [skills.agenticros.com](https://skills.agenticros.com) unless you customize and use `--graduate`.
|